blob: ee11473adb25f7ed4571a8258a6f8219ca0fe68c [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. */
cerion896a1372005-01-25 12:24:25 +0000208static UChar* guest_code;
209
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. */
carll1f5fe1f2014-08-07 23:25:23 +0000556static UInt getUIntPPCendianly ( 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
2936 * Rounding Mode
2937 */
2938 if (mask & MASK_FPSCR_RN) {
2939 stmt( IRStmt_Put( OFFB_FPROUND,
2940 unop( Iop_32to8,
2941 binop( Iop_And32,
2942 unop( Iop_64to32, src ),
2943 mkU32( MASK_FPSCR_RN & mask ) ) ) ) );
2944 } else if (mask & MASK_FPSCR_DRN) {
2945 stmt( IRStmt_Put( OFFB_DFPROUND,
2946 unop( Iop_32to8,
2947 binop( Iop_And32,
2948 unop( Iop_64HIto32, src ),
2949 mkU32( ( MASK_FPSCR_DRN & mask )
2950 >> 32 ) ) ) ) );
sewardje14bb9f2005-07-22 09:39:02 +00002951 }
2952
florian6ef84be2012-08-26 03:20:07 +00002953 /* Give EmNote for attempted writes to:
sewardje14bb9f2005-07-22 09:39:02 +00002954 - Exception Controls
2955 - Non-IEEE Mode
2956 */
2957 if (mask & 0xFC) { // Exception Control, Non-IEE mode
florian6ef84be2012-08-26 03:20:07 +00002958 VexEmNote ew = EmWarn_PPCexns;
sewardje14bb9f2005-07-22 09:39:02 +00002959
2960 /* If any of the src::exception_control bits are actually set,
2961 side-exit to the next insn, reporting the warning,
2962 so that Valgrind's dispatcher sees the warning. */
ceriond953ebb2005-11-29 13:27:20 +00002963 putGST( PPC_GST_EMWARN, mkU32(ew) );
sewardje14bb9f2005-07-22 09:39:02 +00002964 stmt(
2965 IRStmt_Exit(
florian6ef84be2012-08-26 03:20:07 +00002966 binop(Iop_CmpNE32, mkU32(ew), mkU32(EmNote_NONE)),
sewardje14bb9f2005-07-22 09:39:02 +00002967 Ijk_EmWarn,
sewardj3dee8492012-04-20 00:13:28 +00002968 mkSzConst( ty, nextInsnAddr()), OFFB_CIA ));
sewardje14bb9f2005-07-22 09:39:02 +00002969 }
2970
cerionedf7fc52005-11-18 20:57:41 +00002971 /* Ignore all other writes */
sewardje14bb9f2005-07-22 09:39:02 +00002972 break;
cerionedf7fc52005-11-18 20:57:41 +00002973 }
sewardje14bb9f2005-07-22 09:39:02 +00002974
2975 default:
cerion5b2325f2005-12-23 00:55:09 +00002976 vex_printf("putGST_masked(ppc): reg = %u", reg);
2977 vpanic("putGST_masked(ppc)");
sewardje14bb9f2005-07-22 09:39:02 +00002978 }
2979}
2980
cerionedf7fc52005-11-18 20:57:41 +00002981/* Write the least significant nibble of src to the specified
2982 REG[FLD] (as per IBM/hardware notation). */
ceriond953ebb2005-11-29 13:27:20 +00002983static void putGST_field ( PPC_GST reg, IRExpr* src, UInt fld )
cerionedf7fc52005-11-18 20:57:41 +00002984{
sewardjc6bbd472012-04-02 10:20:48 +00002985 UInt shft;
2986 ULong mask;
sewardj41a7b702005-11-18 22:18:23 +00002987
sewardjdd40fdf2006-12-24 02:20:24 +00002988 vassert( typeOfIRExpr(irsb->tyenv,src ) == Ity_I32 );
sewardjc6bbd472012-04-02 10:20:48 +00002989 vassert( fld < 16 );
ceriond953ebb2005-11-29 13:27:20 +00002990 vassert( reg < PPC_GST_MAX );
cerionedf7fc52005-11-18 20:57:41 +00002991
sewardjc6bbd472012-04-02 10:20:48 +00002992 if (fld < 8)
2993 shft = 4*(7-fld);
2994 else
2995 shft = 4*(15-fld);
florian654b7f92013-02-02 00:10:36 +00002996 mask = 0xF;
2997 mask = mask << shft;
cerionedf7fc52005-11-18 20:57:41 +00002998
2999 switch (reg) {
ceriond953ebb2005-11-29 13:27:20 +00003000 case PPC_GST_CR:
cerionedf7fc52005-11-18 20:57:41 +00003001 putCR0 (fld, binop(Iop_And8, mkU8(1 ), unop(Iop_32to8, src)));
3002 putCR321(fld, binop(Iop_And8, mkU8(7<<1), unop(Iop_32to8, src)));
3003 break;
3004
3005 default:
sewardjc6bbd472012-04-02 10:20:48 +00003006 {
3007 IRExpr * src64 = unop( Iop_32Uto64, src );
3008
3009 if (shft == 0) {
3010 putGST_masked( reg, src64, mask );
3011 } else {
3012 putGST_masked( reg,
3013 binop( Iop_Shl64, src64, mkU8( toUChar( shft ) ) ),
3014 mask );
3015 }
cerionedf7fc52005-11-18 20:57:41 +00003016 }
3017 }
3018}
cerion62bec572005-02-01 21:29:39 +00003019
sewardj66d5ef22011-04-15 11:55:00 +00003020/*------------------------------------------------------------*/
3021/* Helpers for VSX instructions that do floating point
3022 * operations and need to determine if a src contains a
3023 * special FP value.
3024 *
3025 *------------------------------------------------------------*/
3026
3027#define NONZERO_FRAC_MASK 0x000fffffffffffffULL
3028#define FP_FRAC_PART(x) binop( Iop_And64, \
3029 mkexpr( x ), \
3030 mkU64( NONZERO_FRAC_MASK ) )
3031
sewardje71e56a2011-09-05 12:11:06 +00003032// Returns exponent part of a single precision floating point as I32
3033static IRExpr * fp_exp_part_sp(IRTemp src)
3034{
3035 return binop( Iop_And32,
3036 binop( Iop_Shr32, mkexpr( src ), mkU8( 23 ) ),
3037 mkU32( 0xff ) );
3038}
3039
sewardj66d5ef22011-04-15 11:55:00 +00003040// Returns exponent part of floating point as I32
sewardje71e56a2011-09-05 12:11:06 +00003041static IRExpr * fp_exp_part(IRTemp src, Bool sp)
sewardj66d5ef22011-04-15 11:55:00 +00003042{
3043 IRExpr * exp;
sewardje71e56a2011-09-05 12:11:06 +00003044 if (sp)
3045 return fp_exp_part_sp(src);
3046
sewardj66d5ef22011-04-15 11:55:00 +00003047 if (!mode64)
3048 exp = binop( Iop_And32, binop( Iop_Shr32, unop( Iop_64HIto32,
3049 mkexpr( src ) ),
3050 mkU8( 20 ) ), mkU32( 0x7ff ) );
3051 else
3052 exp = unop( Iop_64to32,
3053 binop( Iop_And64,
3054 binop( Iop_Shr64, mkexpr( src ), mkU8( 52 ) ),
3055 mkU64( 0x7ff ) ) );
3056 return exp;
3057}
3058
sewardje71e56a2011-09-05 12:11:06 +00003059static IRExpr * is_Inf_sp(IRTemp src)
3060{
3061 IRTemp frac_part = newTemp(Ity_I32);
3062 IRExpr * Inf_exp;
3063
3064 assign( frac_part, binop( Iop_And32, mkexpr(src), mkU32(0x007fffff)) );
3065 Inf_exp = binop( Iop_CmpEQ32, fp_exp_part( src, True /*single precision*/ ), mkU32( 0xff ) );
3066 return mkAND1( Inf_exp, binop( Iop_CmpEQ32, mkexpr( frac_part ), mkU32( 0 ) ) );
3067}
3068
sewardj66d5ef22011-04-15 11:55:00 +00003069
3070// Infinity: exp = 7ff and fraction is zero; s = 0/1
sewardje71e56a2011-09-05 12:11:06 +00003071static IRExpr * is_Inf(IRTemp src, Bool sp)
sewardj66d5ef22011-04-15 11:55:00 +00003072{
3073 IRExpr * Inf_exp, * hi32, * low32;
sewardje71e56a2011-09-05 12:11:06 +00003074 IRTemp frac_part;
sewardj66d5ef22011-04-15 11:55:00 +00003075
sewardje71e56a2011-09-05 12:11:06 +00003076 if (sp)
3077 return is_Inf_sp(src);
3078
3079 frac_part = newTemp(Ity_I64);
sewardj66d5ef22011-04-15 11:55:00 +00003080 assign( frac_part, FP_FRAC_PART(src) );
sewardje71e56a2011-09-05 12:11:06 +00003081 Inf_exp = binop( Iop_CmpEQ32, fp_exp_part( src, False /*not single precision*/ ), mkU32( 0x7ff ) );
sewardj66d5ef22011-04-15 11:55:00 +00003082 hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
3083 low32 = unop( Iop_64to32, mkexpr( frac_part ) );
3084 return mkAND1( Inf_exp, binop( Iop_CmpEQ32, binop( Iop_Or32, low32, hi32 ),
3085 mkU32( 0 ) ) );
3086}
3087
sewardje71e56a2011-09-05 12:11:06 +00003088static IRExpr * is_Zero_sp(IRTemp src)
3089{
3090 IRTemp sign_less_part = newTemp(Ity_I32);
3091 assign( sign_less_part, binop( Iop_And32, mkexpr( src ), mkU32( SIGN_MASK32 ) ) );
3092 return binop( Iop_CmpEQ32, mkexpr( sign_less_part ), mkU32( 0 ) );
3093}
3094
sewardj66d5ef22011-04-15 11:55:00 +00003095// Zero: exp is zero and fraction is zero; s = 0/1
sewardje71e56a2011-09-05 12:11:06 +00003096static IRExpr * is_Zero(IRTemp src, Bool sp)
sewardj66d5ef22011-04-15 11:55:00 +00003097{
sewardj66d5ef22011-04-15 11:55:00 +00003098 IRExpr * hi32, * low32;
sewardje71e56a2011-09-05 12:11:06 +00003099 IRTemp sign_less_part;
3100 if (sp)
3101 return is_Zero_sp(src);
3102
3103 sign_less_part = newTemp(Ity_I64);
sewardj66d5ef22011-04-15 11:55:00 +00003104
3105 assign( sign_less_part, binop( Iop_And64, mkexpr( src ), mkU64( SIGN_MASK ) ) );
3106 hi32 = unop( Iop_64HIto32, mkexpr( sign_less_part ) );
3107 low32 = unop( Iop_64to32, mkexpr( sign_less_part ) );
3108 return binop( Iop_CmpEQ32, binop( Iop_Or32, low32, hi32 ),
3109 mkU32( 0 ) );
3110}
3111
3112/* SNAN: s = 1/0; exp = 0x7ff; fraction is nonzero, with highest bit '1'
3113 * QNAN: s = 1/0; exp = 0x7ff; fraction is nonzero, with highest bit '0'
3114 * This function returns an IRExpr value of '1' for any type of NaN.
3115 */
3116static IRExpr * is_NaN(IRTemp src)
3117{
3118 IRExpr * NaN_exp, * hi32, * low32;
3119 IRTemp frac_part = newTemp(Ity_I64);
3120
3121 assign( frac_part, FP_FRAC_PART(src) );
3122 hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
3123 low32 = unop( Iop_64to32, mkexpr( frac_part ) );
sewardje71e56a2011-09-05 12:11:06 +00003124 NaN_exp = binop( Iop_CmpEQ32, fp_exp_part( src, False /*not single precision*/ ),
3125 mkU32( 0x7ff ) );
sewardj66d5ef22011-04-15 11:55:00 +00003126
3127 return mkAND1( NaN_exp, binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
3128 mkU32( 0 ) ) );
3129}
cerion76222262005-02-05 13:45:57 +00003130
sewardj4aa412a2011-07-24 14:13:21 +00003131/* This function returns an IRExpr value of '1' for any type of NaN.
3132 * The passed 'src' argument is assumed to be Ity_I32.
3133 */
3134static IRExpr * is_NaN_32(IRTemp src)
3135{
3136#define NONZERO_FRAC_MASK32 0x007fffffULL
3137#define FP_FRAC_PART32(x) binop( Iop_And32, \
3138 mkexpr( x ), \
3139 mkU32( NONZERO_FRAC_MASK32 ) )
3140
3141 IRExpr * frac_part = FP_FRAC_PART32(src);
3142 IRExpr * exp_part = binop( Iop_And32,
3143 binop( Iop_Shr32, mkexpr( src ), mkU8( 23 ) ),
3144 mkU32( 0x0ff ) );
3145 IRExpr * NaN_exp = binop( Iop_CmpEQ32, exp_part, mkU32( 0xff ) );
3146
3147 return mkAND1( NaN_exp, binop( Iop_CmpNE32, frac_part, mkU32( 0 ) ) );
3148}
3149
carll6fef87a2013-09-12 17:26:42 +00003150/* This function takes an Ity_I32 input argument interpreted
3151 * as a single-precision floating point value. If src is a
3152 * SNaN, it is changed to a QNaN and returned; otherwise,
3153 * the original value is returned.
3154 */
3155static IRExpr * handle_SNaN_to_QNaN_32(IRExpr * src)
3156{
3157#define SNAN_MASK32 0x00400000
3158 IRTemp tmp = newTemp(Ity_I32);
3159 IRTemp mask = newTemp(Ity_I32);
3160 IRTemp is_SNAN = newTemp(Ity_I1);
3161
3162 vassert( typeOfIRExpr(irsb->tyenv, src ) == Ity_I32 );
3163 assign(tmp, src);
3164
3165 /* check if input is SNaN, if it is convert to QNaN */
3166 assign( is_SNAN,
3167 mkAND1( is_NaN_32( tmp ),
3168 binop( Iop_CmpEQ32,
3169 binop( Iop_And32, mkexpr( tmp ),
3170 mkU32( SNAN_MASK32 ) ),
3171 mkU32( 0 ) ) ) );
3172 /* create mask with QNaN bit set to make it a QNaN if tmp is SNaN */
3173 assign ( mask, binop( Iop_And32,
3174 unop( Iop_1Sto32, mkexpr( is_SNAN ) ),
3175 mkU32( SNAN_MASK32 ) ) );
3176 return binop( Iop_Or32, mkexpr( mask ), mkexpr( tmp) );
3177}
3178
3179
sewardj4aa412a2011-07-24 14:13:21 +00003180/* This helper function performs the negation part of operations of the form:
3181 * "Negate Multiply-<op>"
3182 * where "<op>" is either "Add" or "Sub".
3183 *
3184 * This function takes one argument -- the floating point intermediate result (converted to
3185 * Ity_I64 via Iop_ReinterpF64asI64) that was obtained from the "Multip-<op>" part of
3186 * the operation described above.
3187 */
3188static IRTemp getNegatedResult(IRTemp intermediateResult)
3189{
3190 ULong signbit_mask = 0x8000000000000000ULL;
3191 IRTemp signbit_32 = newTemp(Ity_I32);
3192 IRTemp resultantSignbit = newTemp(Ity_I1);
3193 IRTemp negatedResult = newTemp(Ity_I64);
3194 assign( signbit_32, binop( Iop_Shr32,
3195 unop( Iop_64HIto32,
3196 binop( Iop_And64, mkexpr( intermediateResult ),
3197 mkU64( signbit_mask ) ) ),
3198 mkU8( 31 ) ) );
3199 /* We negate the signbit if and only if the intermediate result from the
3200 * multiply-<op> was NOT a NaN. This is an XNOR predicate.
3201 */
3202 assign( resultantSignbit,
3203 unop( Iop_Not1,
3204 binop( Iop_CmpEQ32,
3205 binop( Iop_Xor32,
3206 mkexpr( signbit_32 ),
3207 unop( Iop_1Uto32, is_NaN( intermediateResult ) ) ),
3208 mkU32( 1 ) ) ) );
3209
3210 assign( negatedResult,
3211 binop( Iop_Or64,
3212 binop( Iop_And64,
3213 mkexpr( intermediateResult ),
3214 mkU64( ~signbit_mask ) ),
3215 binop( Iop_32HLto64,
3216 binop( Iop_Shl32,
3217 unop( Iop_1Uto32, mkexpr( resultantSignbit ) ),
3218 mkU8( 31 ) ),
3219 mkU32( 0 ) ) ) );
3220
3221 return negatedResult;
3222}
3223
3224/* This helper function performs the negation part of operations of the form:
3225 * "Negate Multiply-<op>"
3226 * where "<op>" is either "Add" or "Sub".
3227 *
3228 * This function takes one argument -- the floating point intermediate result (converted to
3229 * Ity_I32 via Iop_ReinterpF32asI32) that was obtained from the "Multip-<op>" part of
3230 * the operation described above.
3231 */
3232static IRTemp getNegatedResult_32(IRTemp intermediateResult)
3233{
3234 UInt signbit_mask = 0x80000000;
3235 IRTemp signbit_32 = newTemp(Ity_I32);
3236 IRTemp resultantSignbit = newTemp(Ity_I1);
3237 IRTemp negatedResult = newTemp(Ity_I32);
3238 assign( signbit_32, binop( Iop_Shr32,
3239 binop( Iop_And32, mkexpr( intermediateResult ),
3240 mkU32( signbit_mask ) ),
3241 mkU8( 31 ) ) );
3242 /* We negate the signbit if and only if the intermediate result from the
3243 * multiply-<op> was NOT a NaN. This is an XNOR predicate.
3244 */
3245 assign( resultantSignbit,
3246 unop( Iop_Not1,
3247 binop( Iop_CmpEQ32,
3248 binop( Iop_Xor32,
3249 mkexpr( signbit_32 ),
3250 unop( Iop_1Uto32, is_NaN_32( intermediateResult ) ) ),
3251 mkU32( 1 ) ) ) );
3252
3253 assign( negatedResult,
3254 binop( Iop_Or32,
3255 binop( Iop_And32,
3256 mkexpr( intermediateResult ),
3257 mkU32( ~signbit_mask ) ),
3258 binop( Iop_Shl32,
3259 unop( Iop_1Uto32, mkexpr( resultantSignbit ) ),
3260 mkU8( 31 ) ) ) );
3261
3262 return negatedResult;
3263}
cerion76222262005-02-05 13:45:57 +00003264
cerione9d361a2005-03-04 17:35:29 +00003265/*------------------------------------------------------------*/
carll8943d022013-10-02 16:25:57 +00003266/* Transactional memory helpers
3267 *
3268 *------------------------------------------------------------*/
3269
3270static ULong generate_TMreason( UInt failure_code,
3271 UInt persistant,
3272 UInt nest_overflow,
3273 UInt tm_exact )
3274{
3275 ULong tm_err_code =
3276 ( (ULong) 0) << (63-6) /* Failure code */
3277 | ( (ULong) persistant) << (63-7) /* Failure persistant */
3278 | ( (ULong) 0) << (63-8) /* Disallowed */
3279 | ( (ULong) nest_overflow) << (63-9) /* Nesting Overflow */
3280 | ( (ULong) 0) << (63-10) /* Footprint Overflow */
3281 | ( (ULong) 0) << (63-11) /* Self-Induced Conflict */
3282 | ( (ULong) 0) << (63-12) /* Non-Transactional Conflict */
3283 | ( (ULong) 0) << (63-13) /* Transactional Conflict */
3284 | ( (ULong) 0) << (63-14) /* Translation Invalidation Conflict */
3285 | ( (ULong) 0) << (63-15) /* Implementation-specific */
3286 | ( (ULong) 0) << (63-16) /* Instruction Fetch Conflict */
3287 | ( (ULong) 0) << (63-30) /* Reserved */
3288 | ( (ULong) 0) << (63-31) /* Abort */
3289 | ( (ULong) 0) << (63-32) /* Suspend */
3290 | ( (ULong) 0) << (63-33) /* Reserved */
3291 | ( (ULong) 0) << (63-35) /* Privilege */
3292 | ( (ULong) 0) << (63-36) /* Failure Summary */
3293 | ( (ULong) tm_exact) << (63-37) /* TFIAR Exact */
3294 | ( (ULong) 0) << (63-38) /* ROT */
3295 | ( (ULong) 0) << (63-51) /* Reserved */
3296 | ( (ULong) 0) << (63-63); /* Transaction Level */
3297
3298 return tm_err_code;
3299}
3300
3301static void storeTMfailure( Addr64 err_address, ULong tm_reason,
3302 Addr64 handler_address )
3303{
3304 putGST( PPC_GST_TFIAR, mkU64( err_address ) );
3305 putGST( PPC_GST_TEXASR, mkU64( tm_reason ) );
3306 putGST( PPC_GST_TFHAR, mkU64( handler_address ) );
3307}
3308
3309/*------------------------------------------------------------*/
cerion3d870a32005-03-18 12:23:33 +00003310/*--- Integer Instruction Translation --- */
cerione9d361a2005-03-04 17:35:29 +00003311/*------------------------------------------------------------*/
cerion896a1372005-01-25 12:24:25 +00003312
cerion91ad5362005-01-27 23:02:41 +00003313/*
3314 Integer Arithmetic Instructions
3315*/
cerion645c9302005-01-31 10:09:59 +00003316static Bool dis_int_arith ( UInt theInstr )
cerion91ad5362005-01-27 23:02:41 +00003317{
cerion76de5cf2005-11-18 18:25:12 +00003318 /* D-Form, XO-Form */
3319 UChar opc1 = ifieldOPC(theInstr);
3320 UChar rD_addr = ifieldRegDS(theInstr);
3321 UChar rA_addr = ifieldRegA(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00003322 UInt uimm16 = ifieldUIMM16(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00003323 UChar rB_addr = ifieldRegB(theInstr);
3324 UChar flag_OE = ifieldBIT10(theInstr);
3325 UInt opc2 = ifieldOPClo9(theInstr);
3326 UChar flag_rC = ifieldBIT0(theInstr);
3327
ceriond953ebb2005-11-29 13:27:20 +00003328 Long simm16 = extend_s_16to64(uimm16);
3329 IRType ty = mode64 ? Ity_I64 : Ity_I32;
3330 IRTemp rA = newTemp(ty);
3331 IRTemp rB = newTemp(ty);
3332 IRTemp rD = newTemp(ty);
cerion70e24122005-03-16 00:27:37 +00003333
cerionb85e8bb2005-02-16 08:54:33 +00003334 Bool do_rc = False;
cerion91ad5362005-01-27 23:02:41 +00003335
cerion76de5cf2005-11-18 18:25:12 +00003336 assign( rA, getIReg(rA_addr) );
3337 assign( rB, getIReg(rB_addr) ); // XO-Form: rD, rA, rB
sewardjb51f0f42005-07-18 11:38:02 +00003338
cerionb85e8bb2005-02-16 08:54:33 +00003339 switch (opc1) {
cerionb85e8bb2005-02-16 08:54:33 +00003340 /* D-Form */
cerione9d361a2005-03-04 17:35:29 +00003341 case 0x0C: // addic (Add Immediate Carrying, PPC32 p351
ceriond953ebb2005-11-29 13:27:20 +00003342 DIP("addic r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
cerion2831b002005-11-30 19:55:22 +00003343 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
3344 mkSzExtendS16(ty, uimm16) ) );
cerion5b2325f2005-12-23 00:55:09 +00003345 set_XER_CA( ty, PPCG_FLAG_OP_ADD,
cerion2831b002005-11-30 19:55:22 +00003346 mkexpr(rD), mkexpr(rA), mkSzExtendS16(ty, uimm16),
3347 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
cerion4561acb2005-02-21 14:07:48 +00003348 break;
sewardjb51f0f42005-07-18 11:38:02 +00003349
cerione9d361a2005-03-04 17:35:29 +00003350 case 0x0D: // addic. (Add Immediate Carrying and Record, PPC32 p352)
ceriond953ebb2005-11-29 13:27:20 +00003351 DIP("addic. r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
cerion2831b002005-11-30 19:55:22 +00003352 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
3353 mkSzExtendS16(ty, uimm16) ) );
cerion5b2325f2005-12-23 00:55:09 +00003354 set_XER_CA( ty, PPCG_FLAG_OP_ADD,
cerion2831b002005-11-30 19:55:22 +00003355 mkexpr(rD), mkexpr(rA), mkSzExtendS16(ty, uimm16),
3356 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00003357 do_rc = True; // Always record to CR
cerion76de5cf2005-11-18 18:25:12 +00003358 flag_rC = 1;
cerion4561acb2005-02-21 14:07:48 +00003359 break;
3360
cerione9d361a2005-03-04 17:35:29 +00003361 case 0x0E: // addi (Add Immediate, PPC32 p350)
cerionb85e8bb2005-02-16 08:54:33 +00003362 // li rD,val == addi rD,0,val
3363 // la disp(rA) == addi rD,rA,disp
cerion76de5cf2005-11-18 18:25:12 +00003364 if ( rA_addr == 0 ) {
ceriond953ebb2005-11-29 13:27:20 +00003365 DIP("li r%u,%d\n", rD_addr, (Int)simm16);
cerion2831b002005-11-30 19:55:22 +00003366 assign( rD, mkSzExtendS16(ty, uimm16) );
cerionb85e8bb2005-02-16 08:54:33 +00003367 } else {
ceriond953ebb2005-11-29 13:27:20 +00003368 DIP("addi r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
cerion2831b002005-11-30 19:55:22 +00003369 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
3370 mkSzExtendS16(ty, uimm16) ) );
cerionb85e8bb2005-02-16 08:54:33 +00003371 }
3372 break;
cerion91ad5362005-01-27 23:02:41 +00003373
cerione9d361a2005-03-04 17:35:29 +00003374 case 0x0F: // addis (Add Immediate Shifted, PPC32 p353)
cerionb85e8bb2005-02-16 08:54:33 +00003375 // lis rD,val == addis rD,0,val
cerion76de5cf2005-11-18 18:25:12 +00003376 if ( rA_addr == 0 ) {
ceriond953ebb2005-11-29 13:27:20 +00003377 DIP("lis r%u,%d\n", rD_addr, (Int)simm16);
cerion2831b002005-11-30 19:55:22 +00003378 assign( rD, mkSzExtendS32(ty, uimm16 << 16) );
cerionb85e8bb2005-02-16 08:54:33 +00003379 } else {
ceriond953ebb2005-11-29 13:27:20 +00003380 DIP("addis r%u,r%u,0x%x\n", rD_addr, rA_addr, (Int)simm16);
cerion2831b002005-11-30 19:55:22 +00003381 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
3382 mkSzExtendS32(ty, uimm16 << 16) ) );
cerionb85e8bb2005-02-16 08:54:33 +00003383 }
3384 break;
cerion91ad5362005-01-27 23:02:41 +00003385
cerione9d361a2005-03-04 17:35:29 +00003386 case 0x07: // mulli (Multiply Low Immediate, PPC32 p490)
ceriond953ebb2005-11-29 13:27:20 +00003387 DIP("mulli r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
3388 if (mode64)
3389 assign( rD, unop(Iop_128to64,
3390 binop(Iop_MullS64, mkexpr(rA),
cerion2831b002005-11-30 19:55:22 +00003391 mkSzExtendS16(ty, uimm16))) );
ceriond953ebb2005-11-29 13:27:20 +00003392 else
3393 assign( rD, unop(Iop_64to32,
3394 binop(Iop_MullS32, mkexpr(rA),
cerion2831b002005-11-30 19:55:22 +00003395 mkSzExtendS16(ty, uimm16))) );
cerionb85e8bb2005-02-16 08:54:33 +00003396 break;
cerion38674602005-02-08 02:19:25 +00003397
cerione9d361a2005-03-04 17:35:29 +00003398 case 0x08: // subfic (Subtract from Immediate Carrying, PPC32 p540)
ceriond953ebb2005-11-29 13:27:20 +00003399 DIP("subfic r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
cerion76de5cf2005-11-18 18:25:12 +00003400 // rD = simm16 - rA
cerion2831b002005-11-30 19:55:22 +00003401 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
3402 mkSzExtendS16(ty, uimm16),
ceriond953ebb2005-11-29 13:27:20 +00003403 mkexpr(rA)) );
cerion5b2325f2005-12-23 00:55:09 +00003404 set_XER_CA( ty, PPCG_FLAG_OP_SUBFI,
cerion2831b002005-11-30 19:55:22 +00003405 mkexpr(rD), mkexpr(rA), mkSzExtendS16(ty, uimm16),
3406 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
cerionb85e8bb2005-02-16 08:54:33 +00003407 break;
cerion38674602005-02-08 02:19:25 +00003408
cerionb85e8bb2005-02-16 08:54:33 +00003409 /* XO-Form */
3410 case 0x1F:
cerionb85e8bb2005-02-16 08:54:33 +00003411 do_rc = True; // All below record to CR
3412
3413 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00003414 case 0x10A: // add (Add, PPC32 p347)
ceriond953ebb2005-11-29 13:27:20 +00003415 DIP("add%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003416 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003417 rD_addr, rA_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00003418 assign( rD, binop( mkSzOp(ty, Iop_Add8),
ceriond953ebb2005-11-29 13:27:20 +00003419 mkexpr(rA), mkexpr(rB) ) );
cerion70e24122005-03-16 00:27:37 +00003420 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003421 set_XER_OV( ty, PPCG_FLAG_OP_ADD,
cerion76de5cf2005-11-18 18:25:12 +00003422 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003423 }
cerionb85e8bb2005-02-16 08:54:33 +00003424 break;
cerion91ad5362005-01-27 23:02:41 +00003425
cerione9d361a2005-03-04 17:35:29 +00003426 case 0x00A: // addc (Add Carrying, PPC32 p348)
ceriond953ebb2005-11-29 13:27:20 +00003427 DIP("addc%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003428 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003429 rD_addr, rA_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00003430 assign( rD, binop( mkSzOp(ty, Iop_Add8),
ceriond953ebb2005-11-29 13:27:20 +00003431 mkexpr(rA), mkexpr(rB)) );
cerion5b2325f2005-12-23 00:55:09 +00003432 set_XER_CA( ty, PPCG_FLAG_OP_ADD,
cerion76de5cf2005-11-18 18:25:12 +00003433 mkexpr(rD), mkexpr(rA), mkexpr(rB),
cerion2831b002005-11-30 19:55:22 +00003434 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00003435 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003436 set_XER_OV( ty, PPCG_FLAG_OP_ADD,
cerion76de5cf2005-11-18 18:25:12 +00003437 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003438 }
cerionb85e8bb2005-02-16 08:54:33 +00003439 break;
3440
sewardjb51f0f42005-07-18 11:38:02 +00003441 case 0x08A: { // adde (Add Extended, PPC32 p349)
cerion2831b002005-11-30 19:55:22 +00003442 IRTemp old_xer_ca = newTemp(ty);
ceriond953ebb2005-11-29 13:27:20 +00003443 DIP("adde%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003444 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003445 rD_addr, rA_addr, rB_addr);
cerionb85e8bb2005-02-16 08:54:33 +00003446 // rD = rA + rB + XER[CA]
sewardje9d8a262009-07-01 08:06:34 +00003447 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA32(), False) );
cerion2831b002005-11-30 19:55:22 +00003448 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
3449 binop( mkSzOp(ty, Iop_Add8),
3450 mkexpr(rB), mkexpr(old_xer_ca))) );
cerion5b2325f2005-12-23 00:55:09 +00003451 set_XER_CA( ty, PPCG_FLAG_OP_ADDE,
cerion76de5cf2005-11-18 18:25:12 +00003452 mkexpr(rD), mkexpr(rA), mkexpr(rB),
cerion2831b002005-11-30 19:55:22 +00003453 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00003454 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003455 set_XER_OV( ty, PPCG_FLAG_OP_ADDE,
cerion76de5cf2005-11-18 18:25:12 +00003456 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003457 }
cerionb85e8bb2005-02-16 08:54:33 +00003458 break;
sewardjb51f0f42005-07-18 11:38:02 +00003459 }
3460
cerion5b2325f2005-12-23 00:55:09 +00003461 case 0x0EA: { // addme (Add to Minus One Extended, PPC32 p354)
cerion2831b002005-11-30 19:55:22 +00003462 IRTemp old_xer_ca = newTemp(ty);
3463 IRExpr *min_one;
cerion76de5cf2005-11-18 18:25:12 +00003464 if (rB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003465 vex_printf("dis_int_arith(ppc)(addme,rB_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003466 return False;
3467 }
ceriond953ebb2005-11-29 13:27:20 +00003468 DIP("addme%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003469 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003470 rD_addr, rA_addr, rB_addr);
cerion70e24122005-03-16 00:27:37 +00003471 // rD = rA + (-1) + XER[CA]
3472 // => Just another form of adde
sewardje9d8a262009-07-01 08:06:34 +00003473 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA32(), False) );
cerion2831b002005-11-30 19:55:22 +00003474 min_one = mkSzImm(ty, (Long)-1);
3475 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
3476 binop( mkSzOp(ty, Iop_Add8),
3477 min_one, mkexpr(old_xer_ca)) ));
cerion5b2325f2005-12-23 00:55:09 +00003478 set_XER_CA( ty, PPCG_FLAG_OP_ADDE,
ceriond953ebb2005-11-29 13:27:20 +00003479 mkexpr(rD), mkexpr(rA), min_one,
cerion2831b002005-11-30 19:55:22 +00003480 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00003481 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003482 set_XER_OV( ty, PPCG_FLAG_OP_ADDE,
ceriond953ebb2005-11-29 13:27:20 +00003483 mkexpr(rD), mkexpr(rA), min_one );
cerion70e24122005-03-16 00:27:37 +00003484 }
cerionb85e8bb2005-02-16 08:54:33 +00003485 break;
sewardjb51f0f42005-07-18 11:38:02 +00003486 }
3487
3488 case 0x0CA: { // addze (Add to Zero Extended, PPC32 p355)
cerion2831b002005-11-30 19:55:22 +00003489 IRTemp old_xer_ca = newTemp(ty);
cerion76de5cf2005-11-18 18:25:12 +00003490 if (rB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003491 vex_printf("dis_int_arith(ppc)(addze,rB_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003492 return False;
3493 }
ceriond953ebb2005-11-29 13:27:20 +00003494 DIP("addze%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003495 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003496 rD_addr, rA_addr, rB_addr);
cerion70e24122005-03-16 00:27:37 +00003497 // rD = rA + (0) + XER[CA]
3498 // => Just another form of adde
sewardje9d8a262009-07-01 08:06:34 +00003499 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA32(), False) );
cerion2831b002005-11-30 19:55:22 +00003500 assign( rD, binop( mkSzOp(ty, Iop_Add8),
3501 mkexpr(rA), mkexpr(old_xer_ca)) );
cerion5b2325f2005-12-23 00:55:09 +00003502 set_XER_CA( ty, PPCG_FLAG_OP_ADDE,
cerion2831b002005-11-30 19:55:22 +00003503 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0),
3504 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00003505 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003506 set_XER_OV( ty, PPCG_FLAG_OP_ADDE,
cerion2831b002005-11-30 19:55:22 +00003507 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0) );
cerion70e24122005-03-16 00:27:37 +00003508 }
cerionb85e8bb2005-02-16 08:54:33 +00003509 break;
sewardjb51f0f42005-07-18 11:38:02 +00003510 }
cerion91ad5362005-01-27 23:02:41 +00003511
cerione9d361a2005-03-04 17:35:29 +00003512 case 0x1EB: // divw (Divide Word, PPC32 p388)
ceriond953ebb2005-11-29 13:27:20 +00003513 DIP("divw%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003514 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003515 rD_addr, rA_addr, rB_addr);
ceriond953ebb2005-11-29 13:27:20 +00003516 if (mode64) {
cerion2831b002005-11-30 19:55:22 +00003517 /* Note:
3518 XER settings are mode independent, and reflect the
3519 overflow of the low-order 32bit result
3520 CR0[LT|GT|EQ] are undefined if flag_rC && mode64
3521 */
cerionbb01b7c2005-12-16 13:40:18 +00003522 /* rD[hi32] are undefined: setting them to sign of lo32
3523 - makes set_CR0 happy */
3524 IRExpr* dividend = mk64lo32Sto64( mkexpr(rA) );
3525 IRExpr* divisor = mk64lo32Sto64( mkexpr(rB) );
cerion5b2325f2005-12-23 00:55:09 +00003526 assign( rD, mk64lo32Uto64( binop(Iop_DivS64, dividend,
3527 divisor) ) );
ceriond953ebb2005-11-29 13:27:20 +00003528 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003529 set_XER_OV( ty, PPCG_FLAG_OP_DIVW,
cerionf0de28c2005-12-13 20:21:11 +00003530 mkexpr(rD), dividend, divisor );
ceriond953ebb2005-11-29 13:27:20 +00003531 }
3532 } else {
3533 assign( rD, binop(Iop_DivS32, mkexpr(rA), mkexpr(rB)) );
3534 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003535 set_XER_OV( ty, PPCG_FLAG_OP_DIVW,
ceriond953ebb2005-11-29 13:27:20 +00003536 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
3537 }
cerion70e24122005-03-16 00:27:37 +00003538 }
cerionb85e8bb2005-02-16 08:54:33 +00003539 /* Note:
3540 if (0x8000_0000 / -1) or (x / 0)
cerion76de5cf2005-11-18 18:25:12 +00003541 => rD=undef, if(flag_rC) CR7=undef, if(flag_OE) XER_OV=1
cerionb85e8bb2005-02-16 08:54:33 +00003542 => But _no_ exception raised. */
3543 break;
cerion91ad5362005-01-27 23:02:41 +00003544
cerione9d361a2005-03-04 17:35:29 +00003545 case 0x1CB: // divwu (Divide Word Unsigned, PPC32 p389)
ceriond953ebb2005-11-29 13:27:20 +00003546 DIP("divwu%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003547 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003548 rD_addr, rA_addr, rB_addr);
ceriond953ebb2005-11-29 13:27:20 +00003549 if (mode64) {
cerion2831b002005-11-30 19:55:22 +00003550 /* Note:
3551 XER settings are mode independent, and reflect the
3552 overflow of the low-order 32bit result
3553 CR0[LT|GT|EQ] are undefined if flag_rC && mode64
3554 */
cerionbb01b7c2005-12-16 13:40:18 +00003555 IRExpr* dividend = mk64lo32Uto64( mkexpr(rA) );
3556 IRExpr* divisor = mk64lo32Uto64( mkexpr(rB) );
cerion5b2325f2005-12-23 00:55:09 +00003557 assign( rD, mk64lo32Uto64( binop(Iop_DivU64, dividend,
3558 divisor) ) );
ceriond953ebb2005-11-29 13:27:20 +00003559 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003560 set_XER_OV( ty, PPCG_FLAG_OP_DIVWU,
cerionf0de28c2005-12-13 20:21:11 +00003561 mkexpr(rD), dividend, divisor );
ceriond953ebb2005-11-29 13:27:20 +00003562 }
cerion2831b002005-11-30 19:55:22 +00003563 } else {
ceriond953ebb2005-11-29 13:27:20 +00003564 assign( rD, binop(Iop_DivU32, mkexpr(rA), mkexpr(rB)) );
3565 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003566 set_XER_OV( ty, PPCG_FLAG_OP_DIVWU,
ceriond953ebb2005-11-29 13:27:20 +00003567 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
3568 }
cerion70e24122005-03-16 00:27:37 +00003569 }
cerionb85e8bb2005-02-16 08:54:33 +00003570 /* Note: ditto comment divw, for (x / 0) */
3571 break;
cerion91ad5362005-01-27 23:02:41 +00003572
cerione9d361a2005-03-04 17:35:29 +00003573 case 0x04B: // mulhw (Multiply High Word, PPC32 p488)
cerionb85e8bb2005-02-16 08:54:33 +00003574 if (flag_OE != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003575 vex_printf("dis_int_arith(ppc)(mulhw,flag_OE)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003576 return False;
3577 }
cerion5b2325f2005-12-23 00:55:09 +00003578 DIP("mulhw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003579 rD_addr, rA_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00003580 if (mode64) {
cerionbb01b7c2005-12-16 13:40:18 +00003581 /* rD[hi32] are undefined: setting them to sign of lo32
3582 - makes set_CR0 happy */
3583 assign( rD, binop(Iop_Sar64,
3584 binop(Iop_Mul64,
3585 mk64lo32Sto64( mkexpr(rA) ),
3586 mk64lo32Sto64( mkexpr(rB) )),
3587 mkU8(32)) );
cerion2831b002005-11-30 19:55:22 +00003588 } else {
ceriond953ebb2005-11-29 13:27:20 +00003589 assign( rD, unop(Iop_64HIto32,
3590 binop(Iop_MullS32,
3591 mkexpr(rA), mkexpr(rB))) );
cerion2831b002005-11-30 19:55:22 +00003592 }
cerionb85e8bb2005-02-16 08:54:33 +00003593 break;
cerionc19d5e12005-02-01 15:56:25 +00003594
cerion5b2325f2005-12-23 00:55:09 +00003595 case 0x00B: // mulhwu (Multiply High Word Unsigned, PPC32 p489)
cerionb85e8bb2005-02-16 08:54:33 +00003596 if (flag_OE != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003597 vex_printf("dis_int_arith(ppc)(mulhwu,flag_OE)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003598 return False;
3599 }
cerion5b2325f2005-12-23 00:55:09 +00003600 DIP("mulhwu%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003601 rD_addr, rA_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00003602 if (mode64) {
cerionbb01b7c2005-12-16 13:40:18 +00003603 /* rD[hi32] are undefined: setting them to sign of lo32
3604 - makes set_CR0 happy */
3605 assign( rD, binop(Iop_Sar64,
3606 binop(Iop_Mul64,
3607 mk64lo32Uto64( mkexpr(rA) ),
3608 mk64lo32Uto64( mkexpr(rB) ) ),
3609 mkU8(32)) );
cerion2831b002005-11-30 19:55:22 +00003610 } else {
ceriond953ebb2005-11-29 13:27:20 +00003611 assign( rD, unop(Iop_64HIto32,
3612 binop(Iop_MullU32,
3613 mkexpr(rA), mkexpr(rB))) );
cerion2831b002005-11-30 19:55:22 +00003614 }
cerionb85e8bb2005-02-16 08:54:33 +00003615 break;
3616
cerione9d361a2005-03-04 17:35:29 +00003617 case 0x0EB: // mullw (Multiply Low Word, PPC32 p491)
ceriond953ebb2005-11-29 13:27:20 +00003618 DIP("mullw%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003619 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003620 rD_addr, rA_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00003621 if (mode64) {
cerionbb01b7c2005-12-16 13:40:18 +00003622 /* rD[hi32] are undefined: setting them to sign of lo32
3623 - set_XER_OV() and set_CR0() depend on this */
3624 IRExpr *a = unop(Iop_64to32, mkexpr(rA) );
3625 IRExpr *b = unop(Iop_64to32, mkexpr(rB) );
3626 assign( rD, binop(Iop_MullS32, a, b) );
3627 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003628 set_XER_OV( ty, PPCG_FLAG_OP_MULLW,
cerionbb01b7c2005-12-16 13:40:18 +00003629 mkexpr(rD),
3630 unop(Iop_32Uto64, a), unop(Iop_32Uto64, b) );
3631 }
cerion2831b002005-11-30 19:55:22 +00003632 } else {
ceriond953ebb2005-11-29 13:27:20 +00003633 assign( rD, unop(Iop_64to32,
3634 binop(Iop_MullU32,
3635 mkexpr(rA), mkexpr(rB))) );
cerionbb01b7c2005-12-16 13:40:18 +00003636 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003637 set_XER_OV( ty, PPCG_FLAG_OP_MULLW,
cerionbb01b7c2005-12-16 13:40:18 +00003638 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
3639 }
cerion70e24122005-03-16 00:27:37 +00003640 }
cerionb85e8bb2005-02-16 08:54:33 +00003641 break;
cerionc19d5e12005-02-01 15:56:25 +00003642
cerione9d361a2005-03-04 17:35:29 +00003643 case 0x068: // neg (Negate, PPC32 p493)
cerion76de5cf2005-11-18 18:25:12 +00003644 if (rB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003645 vex_printf("dis_int_arith(ppc)(neg,rB_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003646 return False;
3647 }
ceriond953ebb2005-11-29 13:27:20 +00003648 DIP("neg%s%s r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003649 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003650 rD_addr, rA_addr);
ceriond953ebb2005-11-29 13:27:20 +00003651 // rD = (~rA) + 1
cerion2831b002005-11-30 19:55:22 +00003652 assign( rD, binop( mkSzOp(ty, Iop_Add8),
3653 unop( mkSzOp(ty, Iop_Not8), mkexpr(rA) ),
3654 mkSzImm(ty, 1)) );
cerion70e24122005-03-16 00:27:37 +00003655 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003656 set_XER_OV( ty, PPCG_FLAG_OP_NEG,
cerion76de5cf2005-11-18 18:25:12 +00003657 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003658 }
cerionb85e8bb2005-02-16 08:54:33 +00003659 break;
cerion91ad5362005-01-27 23:02:41 +00003660
cerione9d361a2005-03-04 17:35:29 +00003661 case 0x028: // subf (Subtract From, PPC32 p537)
ceriond953ebb2005-11-29 13:27:20 +00003662 DIP("subf%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003663 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003664 rD_addr, rA_addr, rB_addr);
cerion01908472005-02-25 16:43:08 +00003665 // rD = rB - rA
cerion2831b002005-11-30 19:55:22 +00003666 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
ceriond953ebb2005-11-29 13:27:20 +00003667 mkexpr(rB), mkexpr(rA)) );
cerion70e24122005-03-16 00:27:37 +00003668 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003669 set_XER_OV( ty, PPCG_FLAG_OP_SUBF,
cerion76de5cf2005-11-18 18:25:12 +00003670 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003671 }
cerionb85e8bb2005-02-16 08:54:33 +00003672 break;
cerion38674602005-02-08 02:19:25 +00003673
cerione9d361a2005-03-04 17:35:29 +00003674 case 0x008: // subfc (Subtract from Carrying, PPC32 p538)
ceriond953ebb2005-11-29 13:27:20 +00003675 DIP("subfc%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003676 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003677 rD_addr, rA_addr, rB_addr);
cerion01908472005-02-25 16:43:08 +00003678 // rD = rB - rA
cerion2831b002005-11-30 19:55:22 +00003679 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
ceriond953ebb2005-11-29 13:27:20 +00003680 mkexpr(rB), mkexpr(rA)) );
cerion5b2325f2005-12-23 00:55:09 +00003681 set_XER_CA( ty, PPCG_FLAG_OP_SUBFC,
cerion76de5cf2005-11-18 18:25:12 +00003682 mkexpr(rD), mkexpr(rA), mkexpr(rB),
cerion2831b002005-11-30 19:55:22 +00003683 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00003684 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003685 set_XER_OV( ty, PPCG_FLAG_OP_SUBFC,
cerion76de5cf2005-11-18 18:25:12 +00003686 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003687 }
cerionb85e8bb2005-02-16 08:54:33 +00003688 break;
3689
sewardjb51f0f42005-07-18 11:38:02 +00003690 case 0x088: {// subfe (Subtract from Extended, PPC32 p539)
cerion2831b002005-11-30 19:55:22 +00003691 IRTemp old_xer_ca = newTemp(ty);
ceriond953ebb2005-11-29 13:27:20 +00003692 DIP("subfe%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003693 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003694 rD_addr, rA_addr, rB_addr);
cerionb85e8bb2005-02-16 08:54:33 +00003695 // rD = (log not)rA + rB + XER[CA]
sewardje9d8a262009-07-01 08:06:34 +00003696 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA32(), False) );
cerion2831b002005-11-30 19:55:22 +00003697 assign( rD, binop( mkSzOp(ty, Iop_Add8),
3698 unop( mkSzOp(ty, Iop_Not8), mkexpr(rA)),
3699 binop( mkSzOp(ty, Iop_Add8),
3700 mkexpr(rB), mkexpr(old_xer_ca))) );
cerion5b2325f2005-12-23 00:55:09 +00003701 set_XER_CA( ty, PPCG_FLAG_OP_SUBFE,
cerion76de5cf2005-11-18 18:25:12 +00003702 mkexpr(rD), mkexpr(rA), mkexpr(rB),
cerion2831b002005-11-30 19:55:22 +00003703 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00003704 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003705 set_XER_OV( ty, PPCG_FLAG_OP_SUBFE,
cerion76de5cf2005-11-18 18:25:12 +00003706 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003707 }
cerionb85e8bb2005-02-16 08:54:33 +00003708 break;
sewardjb51f0f42005-07-18 11:38:02 +00003709 }
3710
cerion5b2325f2005-12-23 00:55:09 +00003711 case 0x0E8: { // subfme (Subtract from -1 Extended, PPC32 p541)
cerion2831b002005-11-30 19:55:22 +00003712 IRTemp old_xer_ca = newTemp(ty);
3713 IRExpr *min_one;
cerion76de5cf2005-11-18 18:25:12 +00003714 if (rB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003715 vex_printf("dis_int_arith(ppc)(subfme,rB_addr)\n");
sewardj20ef5472005-07-21 14:48:31 +00003716 return False;
3717 }
ceriond953ebb2005-11-29 13:27:20 +00003718 DIP("subfme%s%s r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003719 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003720 rD_addr, rA_addr);
sewardj20ef5472005-07-21 14:48:31 +00003721 // rD = (log not)rA + (-1) + XER[CA]
3722 // => Just another form of subfe
sewardje9d8a262009-07-01 08:06:34 +00003723 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA32(), False) );
cerion2831b002005-11-30 19:55:22 +00003724 min_one = mkSzImm(ty, (Long)-1);
3725 assign( rD, binop( mkSzOp(ty, Iop_Add8),
3726 unop( mkSzOp(ty, Iop_Not8), mkexpr(rA)),
3727 binop( mkSzOp(ty, Iop_Add8),
3728 min_one, mkexpr(old_xer_ca))) );
cerion5b2325f2005-12-23 00:55:09 +00003729 set_XER_CA( ty, PPCG_FLAG_OP_SUBFE,
ceriond953ebb2005-11-29 13:27:20 +00003730 mkexpr(rD), mkexpr(rA), min_one,
cerion2831b002005-11-30 19:55:22 +00003731 mkexpr(old_xer_ca) );
sewardj20ef5472005-07-21 14:48:31 +00003732 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003733 set_XER_OV( ty, PPCG_FLAG_OP_SUBFE,
ceriond953ebb2005-11-29 13:27:20 +00003734 mkexpr(rD), mkexpr(rA), min_one );
sewardj20ef5472005-07-21 14:48:31 +00003735 }
3736 break;
3737 }
3738
cerion5b2325f2005-12-23 00:55:09 +00003739 case 0x0C8: { // subfze (Subtract from Zero Extended, PPC32 p542)
cerion2831b002005-11-30 19:55:22 +00003740 IRTemp old_xer_ca = newTemp(ty);
cerion76de5cf2005-11-18 18:25:12 +00003741 if (rB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003742 vex_printf("dis_int_arith(ppc)(subfze,rB_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003743 return False;
3744 }
ceriond953ebb2005-11-29 13:27:20 +00003745 DIP("subfze%s%s r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003746 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003747 rD_addr, rA_addr);
cerion70e24122005-03-16 00:27:37 +00003748 // rD = (log not)rA + (0) + XER[CA]
3749 // => Just another form of subfe
sewardje9d8a262009-07-01 08:06:34 +00003750 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA32(), False) );
cerion2831b002005-11-30 19:55:22 +00003751 assign( rD, binop( mkSzOp(ty, Iop_Add8),
3752 unop( mkSzOp(ty, Iop_Not8),
3753 mkexpr(rA)), mkexpr(old_xer_ca)) );
cerion5b2325f2005-12-23 00:55:09 +00003754 set_XER_CA( ty, PPCG_FLAG_OP_SUBFE,
cerion2831b002005-11-30 19:55:22 +00003755 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0),
3756 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00003757 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003758 set_XER_OV( ty, PPCG_FLAG_OP_SUBFE,
cerion2831b002005-11-30 19:55:22 +00003759 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0) );
cerion70e24122005-03-16 00:27:37 +00003760 }
cerionb85e8bb2005-02-16 08:54:33 +00003761 break;
sewardjb51f0f42005-07-18 11:38:02 +00003762 }
cerionae694622005-01-28 17:52:47 +00003763
cerionf0de28c2005-12-13 20:21:11 +00003764
3765 /* 64bit Arithmetic */
cerion5b2325f2005-12-23 00:55:09 +00003766 case 0x49: // mulhd (Multiply High DWord, PPC64 p539)
cerionf0de28c2005-12-13 20:21:11 +00003767 if (flag_OE != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003768 vex_printf("dis_int_arith(ppc)(mulhd,flagOE)\n");
cerionf0de28c2005-12-13 20:21:11 +00003769 return False;
3770 }
cerion5b2325f2005-12-23 00:55:09 +00003771 DIP("mulhd%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00003772 rD_addr, rA_addr, rB_addr);
cerionf0de28c2005-12-13 20:21:11 +00003773 assign( rD, unop(Iop_128HIto64,
cerion07b07a92005-12-22 14:32:35 +00003774 binop(Iop_MullS64,
cerionf0de28c2005-12-13 20:21:11 +00003775 mkexpr(rA), mkexpr(rB))) );
cerion07b07a92005-12-22 14:32:35 +00003776
3777 break;
cerionf0de28c2005-12-13 20:21:11 +00003778
cerion5b2325f2005-12-23 00:55:09 +00003779 case 0x9: // mulhdu (Multiply High DWord Unsigned, PPC64 p540)
cerionf0de28c2005-12-13 20:21:11 +00003780 if (flag_OE != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003781 vex_printf("dis_int_arith(ppc)(mulhdu,flagOE)\n");
cerionf0de28c2005-12-13 20:21:11 +00003782 return False;
3783 }
cerion5b2325f2005-12-23 00:55:09 +00003784 DIP("mulhdu%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00003785 rD_addr, rA_addr, rB_addr);
cerion07b07a92005-12-22 14:32:35 +00003786 assign( rD, unop(Iop_128HIto64,
3787 binop(Iop_MullU64,
3788 mkexpr(rA), mkexpr(rB))) );
3789 break;
cerionf0de28c2005-12-13 20:21:11 +00003790
cerion5b2325f2005-12-23 00:55:09 +00003791 case 0xE9: // mulld (Multiply Low DWord, PPC64 p543)
cerionf0de28c2005-12-13 20:21:11 +00003792 DIP("mulld%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003793 flag_OE ? "o" : "", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00003794 rD_addr, rA_addr, rB_addr);
3795 assign( rD, binop(Iop_Mul64, mkexpr(rA), mkexpr(rB)) );
3796 if (flag_OE) {
carll38b79ac2013-09-06 22:27:34 +00003797 set_XER_OV( ty, PPCG_FLAG_OP_MULLD,
cerionf0de28c2005-12-13 20:21:11 +00003798 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
3799 }
3800 break;
3801
cerion5b2325f2005-12-23 00:55:09 +00003802 case 0x1E9: // divd (Divide DWord, PPC64 p419)
cerionf0de28c2005-12-13 20:21:11 +00003803 DIP("divd%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003804 flag_OE ? "o" : "", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00003805 rD_addr, rA_addr, rB_addr);
cerion07b07a92005-12-22 14:32:35 +00003806 assign( rD, binop(Iop_DivS64, mkexpr(rA), mkexpr(rB)) );
3807 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003808 set_XER_OV( ty, PPCG_FLAG_OP_DIVW,
cerion07b07a92005-12-22 14:32:35 +00003809 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
3810 }
3811 break;
cerionf0de28c2005-12-13 20:21:11 +00003812 /* Note:
cerion07b07a92005-12-22 14:32:35 +00003813 if (0x8000_0000_0000_0000 / -1) or (x / 0)
cerionf0de28c2005-12-13 20:21:11 +00003814 => rD=undef, if(flag_rC) CR7=undef, if(flag_OE) XER_OV=1
3815 => But _no_ exception raised. */
3816
cerion5b2325f2005-12-23 00:55:09 +00003817 case 0x1C9: // divdu (Divide DWord Unsigned, PPC64 p420)
cerionf0de28c2005-12-13 20:21:11 +00003818 DIP("divdu%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003819 flag_OE ? "o" : "", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00003820 rD_addr, rA_addr, rB_addr);
cerion07b07a92005-12-22 14:32:35 +00003821 assign( rD, binop(Iop_DivU64, mkexpr(rA), mkexpr(rB)) );
3822 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003823 set_XER_OV( ty, PPCG_FLAG_OP_DIVWU,
cerion07b07a92005-12-22 14:32:35 +00003824 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
3825 }
3826 break;
cerionf0de28c2005-12-13 20:21:11 +00003827 /* Note: ditto comment divd, for (x / 0) */
3828
sewardj4aa412a2011-07-24 14:13:21 +00003829 case 0x18B: // divweu (Divide Word Extended Unsigned)
3830 {
3831 /*
3832 * If (RA) >= (RB), or if an attempt is made to perform the division
3833 * <anything> / 0
3834 * then the contents of register RD are undefined as are (if Rc=1) the contents of
3835 * the LT, GT, and EQ bits of CR Field 0. In these cases, if OE=1 then OV is set
3836 * to 1.
3837 */
3838 IRTemp res = newTemp(Ity_I32);
3839 IRExpr * dividend, * divisor;
3840 DIP("divweu%s%s r%u,r%u,r%u\n",
3841 flag_OE ? "o" : "", flag_rC ? ".":"",
3842 rD_addr, rA_addr, rB_addr);
3843 if (mode64) {
3844 dividend = unop( Iop_64to32, mkexpr( rA ) );
3845 divisor = unop( Iop_64to32, mkexpr( rB ) );
3846 assign( res, binop( Iop_DivU32E, dividend, divisor ) );
3847 assign( rD, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( res ) ) );
3848 } else {
3849 dividend = mkexpr( rA );
3850 divisor = mkexpr( rB );
3851 assign( res, binop( Iop_DivU32E, dividend, divisor ) );
3852 assign( rD, mkexpr( res) );
3853 }
3854
3855 if (flag_OE) {
3856 set_XER_OV_32( PPCG_FLAG_OP_DIVWEU,
3857 mkexpr(res), dividend, divisor );
3858 }
3859 break;
3860 }
3861
sewardje71e56a2011-09-05 12:11:06 +00003862 case 0x1AB: // divwe (Divide Word Extended)
3863 {
3864 /*
3865 * If the quotient cannot be represented in 32 bits, or if an
3866 * attempt is made to perform the division
3867 * <anything> / 0
3868 * then the contents of register RD are undefined as are (if
3869 * Rc=1) the contents of the LT, GT, and EQ bits of CR
3870 * Field 0. In these cases, if OE=1 then OV is set to 1.
3871 */
3872
3873 IRTemp res = newTemp(Ity_I32);
3874 IRExpr * dividend, * divisor;
3875 DIP("divwe%s%s r%u,r%u,r%u\n",
3876 flag_OE ? "o" : "", flag_rC ? ".":"",
3877 rD_addr, rA_addr, rB_addr);
3878 if (mode64) {
3879 dividend = unop( Iop_64to32, mkexpr( rA ) );
3880 divisor = unop( Iop_64to32, mkexpr( rB ) );
3881 assign( res, binop( Iop_DivS32E, dividend, divisor ) );
3882 assign( rD, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( res ) ) );
3883 } else {
3884 dividend = mkexpr( rA );
3885 divisor = mkexpr( rB );
3886 assign( res, binop( Iop_DivS32E, dividend, divisor ) );
3887 assign( rD, mkexpr( res) );
3888 }
3889
3890 if (flag_OE) {
3891 set_XER_OV_32( PPCG_FLAG_OP_DIVWE,
3892 mkexpr(res), dividend, divisor );
3893 }
3894 break;
3895 }
3896
3897
sewardj4aa412a2011-07-24 14:13:21 +00003898 case 0x1A9: // divde (Divide Doubleword Extended)
3899 /*
3900 * If the quotient cannot be represented in 64 bits, or if an
3901 * attempt is made to perform the division
3902 * <anything> / 0
3903 * then the contents of register RD are undefined as are (if
3904 * Rc=1) the contents of the LT, GT, and EQ bits of CR
3905 * Field 0. In these cases, if OE=1 then OV is set to 1.
3906 */
3907 DIP("divde%s%s r%u,r%u,r%u\n",
3908 flag_OE ? "o" : "", flag_rC ? ".":"",
3909 rD_addr, rA_addr, rB_addr);
3910 assign( rD, binop(Iop_DivS64E, mkexpr(rA), mkexpr(rB)) );
3911 if (flag_OE) {
3912 set_XER_OV_64( PPCG_FLAG_OP_DIVDE, mkexpr( rD ),
3913 mkexpr( rA ), mkexpr( rB ) );
3914 }
3915 break;
3916
sewardje71e56a2011-09-05 12:11:06 +00003917 case 0x189: // divdeuo (Divide Doubleword Extended Unsigned)
3918 // Same CR and OV rules as given for divweu above
3919 DIP("divdeu%s%s r%u,r%u,r%u\n",
3920 flag_OE ? "o" : "", flag_rC ? ".":"",
3921 rD_addr, rA_addr, rB_addr);
3922 assign( rD, binop(Iop_DivU64E, mkexpr(rA), mkexpr(rB)) );
3923 if (flag_OE) {
3924 set_XER_OV_64( PPCG_FLAG_OP_DIVDEU, mkexpr( rD ),
3925 mkexpr( rA ), mkexpr( rB ) );
3926 }
3927 break;
3928
cerionb85e8bb2005-02-16 08:54:33 +00003929 default:
cerion5b2325f2005-12-23 00:55:09 +00003930 vex_printf("dis_int_arith(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003931 return False;
3932 }
3933 break;
cerionf0de28c2005-12-13 20:21:11 +00003934
cerionb85e8bb2005-02-16 08:54:33 +00003935 default:
cerion5b2325f2005-12-23 00:55:09 +00003936 vex_printf("dis_int_arith(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003937 return False;
3938 }
cerion91ad5362005-01-27 23:02:41 +00003939
cerion76de5cf2005-11-18 18:25:12 +00003940 putIReg( rD_addr, mkexpr(rD) );
3941
3942 if (do_rc && flag_rC) {
3943 set_CR0( mkexpr(rD) );
cerionb85e8bb2005-02-16 08:54:33 +00003944 }
3945 return True;
cerion91ad5362005-01-27 23:02:41 +00003946}
3947
3948
3949
cerion3d870a32005-03-18 12:23:33 +00003950/*
3951 Integer Compare Instructions
3952*/
cerion7aa4bbc2005-01-29 09:32:07 +00003953static Bool dis_int_cmp ( UInt theInstr )
3954{
cerion76de5cf2005-11-18 18:25:12 +00003955 /* D-Form, X-Form */
3956 UChar opc1 = ifieldOPC(theInstr);
3957 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
3958 UChar b22 = toUChar( IFIELD( theInstr, 22, 1 ) );
3959 UChar flag_L = toUChar( IFIELD( theInstr, 21, 1 ) );
3960 UChar rA_addr = ifieldRegA(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00003961 UInt uimm16 = ifieldUIMM16(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00003962 UChar rB_addr = ifieldRegB(theInstr);
3963 UInt opc2 = ifieldOPClo10(theInstr);
3964 UChar b0 = ifieldBIT0(theInstr);
cerion7aa4bbc2005-01-29 09:32:07 +00003965
cerionbb01b7c2005-12-16 13:40:18 +00003966 IRType ty = mode64 ? Ity_I64 : Ity_I32;
3967 IRExpr *a = getIReg(rA_addr);
3968 IRExpr *b;
cerion76de5cf2005-11-18 18:25:12 +00003969
ceriond953ebb2005-11-29 13:27:20 +00003970 if (!mode64 && flag_L==1) { // L==1 invalid for 32 bit.
cerion5b2325f2005-12-23 00:55:09 +00003971 vex_printf("dis_int_cmp(ppc)(flag_L)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003972 return False;
3973 }
3974
cerion76de5cf2005-11-18 18:25:12 +00003975 if (b22 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003976 vex_printf("dis_int_cmp(ppc)(b22)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003977 return False;
3978 }
3979
3980 switch (opc1) {
ceriond953ebb2005-11-29 13:27:20 +00003981 case 0x0B: // cmpi (Compare Immediate, PPC32 p368)
3982 DIP("cmpi cr%u,%u,r%u,%d\n", crfD, flag_L, rA_addr,
3983 (Int)extend_s_16to32(uimm16));
cerion2831b002005-11-30 19:55:22 +00003984 b = mkSzExtendS16( ty, uimm16 );
cerionbb01b7c2005-12-16 13:40:18 +00003985 if (flag_L == 1) {
cerion2831b002005-11-30 19:55:22 +00003986 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64S, a, b)));
ceriond953ebb2005-11-29 13:27:20 +00003987 } else {
sewardje9d8a262009-07-01 08:06:34 +00003988 a = mkNarrowTo32( ty, a );
3989 b = mkNarrowTo32( ty, b );
ceriond953ebb2005-11-29 13:27:20 +00003990 putCR321(crfD, unop(Iop_32to8, binop(Iop_CmpORD32S, a, b)));
3991 }
3992 putCR0( crfD, getXER_SO() );
3993 break;
3994
3995 case 0x0A: // cmpli (Compare Logical Immediate, PPC32 p370)
3996 DIP("cmpli cr%u,%u,r%u,0x%x\n", crfD, flag_L, rA_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00003997 b = mkSzImm( ty, uimm16 );
cerionbb01b7c2005-12-16 13:40:18 +00003998 if (flag_L == 1) {
cerion2831b002005-11-30 19:55:22 +00003999 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64U, a, b)));
ceriond953ebb2005-11-29 13:27:20 +00004000 } else {
sewardje9d8a262009-07-01 08:06:34 +00004001 a = mkNarrowTo32( ty, a );
4002 b = mkNarrowTo32( ty, b );
ceriond953ebb2005-11-29 13:27:20 +00004003 putCR321(crfD, unop(Iop_32to8, binop(Iop_CmpORD32U, a, b)));
4004 }
4005 putCR0( crfD, getXER_SO() );
4006 break;
cerionb85e8bb2005-02-16 08:54:33 +00004007
4008 /* X Form */
4009 case 0x1F:
4010 if (b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00004011 vex_printf("dis_int_cmp(ppc)(0x1F,b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004012 return False;
4013 }
cerionbb01b7c2005-12-16 13:40:18 +00004014 b = getIReg(rB_addr);
cerion7aa4bbc2005-01-29 09:32:07 +00004015
cerionb85e8bb2005-02-16 08:54:33 +00004016 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +00004017 case 0x000: // cmp (Compare, PPC32 p367)
4018 DIP("cmp cr%u,%u,r%u,r%u\n", crfD, flag_L, rA_addr, rB_addr);
sewardja9cb67b2006-08-19 18:31:53 +00004019 /* Comparing a reg with itself produces a result which
4020 doesn't depend on the contents of the reg. Therefore
4021 remove the false dependency, which has been known to cause
4022 memcheck to produce false errors. */
sewardj9195aa12006-08-19 22:18:53 +00004023 if (rA_addr == rB_addr)
sewardjdd40fdf2006-12-24 02:20:24 +00004024 a = b = typeOfIRExpr(irsb->tyenv,a) == Ity_I64
sewardj9195aa12006-08-19 22:18:53 +00004025 ? mkU64(0) : mkU32(0);
cerionbb01b7c2005-12-16 13:40:18 +00004026 if (flag_L == 1) {
4027 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64S, a, b)));
ceriond953ebb2005-11-29 13:27:20 +00004028 } else {
sewardje9d8a262009-07-01 08:06:34 +00004029 a = mkNarrowTo32( ty, a );
4030 b = mkNarrowTo32( ty, b );
cerionbb01b7c2005-12-16 13:40:18 +00004031 putCR321(crfD, unop(Iop_32to8,binop(Iop_CmpORD32S, a, b)));
ceriond953ebb2005-11-29 13:27:20 +00004032 }
4033 putCR0( crfD, getXER_SO() );
4034 break;
cerionb85e8bb2005-02-16 08:54:33 +00004035
ceriond953ebb2005-11-29 13:27:20 +00004036 case 0x020: // cmpl (Compare Logical, PPC32 p369)
4037 DIP("cmpl cr%u,%u,r%u,r%u\n", crfD, flag_L, rA_addr, rB_addr);
sewardja9cb67b2006-08-19 18:31:53 +00004038 /* Comparing a reg with itself produces a result which
4039 doesn't depend on the contents of the reg. Therefore
4040 remove the false dependency, which has been known to cause
4041 memcheck to produce false errors. */
sewardj9195aa12006-08-19 22:18:53 +00004042 if (rA_addr == rB_addr)
sewardjdd40fdf2006-12-24 02:20:24 +00004043 a = b = typeOfIRExpr(irsb->tyenv,a) == Ity_I64
sewardj9195aa12006-08-19 22:18:53 +00004044 ? mkU64(0) : mkU32(0);
cerionbb01b7c2005-12-16 13:40:18 +00004045 if (flag_L == 1) {
4046 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64U, a, b)));
ceriond953ebb2005-11-29 13:27:20 +00004047 } else {
sewardje9d8a262009-07-01 08:06:34 +00004048 a = mkNarrowTo32( ty, a );
4049 b = mkNarrowTo32( ty, b );
cerionbb01b7c2005-12-16 13:40:18 +00004050 putCR321(crfD, unop(Iop_32to8, binop(Iop_CmpORD32U, a, b)));
ceriond953ebb2005-11-29 13:27:20 +00004051 }
4052 putCR0( crfD, getXER_SO() );
4053 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004054
ceriond953ebb2005-11-29 13:27:20 +00004055 default:
cerion5b2325f2005-12-23 00:55:09 +00004056 vex_printf("dis_int_cmp(ppc)(opc2)\n");
ceriond953ebb2005-11-29 13:27:20 +00004057 return False;
cerionb85e8bb2005-02-16 08:54:33 +00004058 }
4059 break;
ceriond953ebb2005-11-29 13:27:20 +00004060
cerionb85e8bb2005-02-16 08:54:33 +00004061 default:
cerion5b2325f2005-12-23 00:55:09 +00004062 vex_printf("dis_int_cmp(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004063 return False;
4064 }
4065
cerionb85e8bb2005-02-16 08:54:33 +00004066 return True;
cerion7aa4bbc2005-01-29 09:32:07 +00004067}
4068
4069
cerion3d870a32005-03-18 12:23:33 +00004070/*
4071 Integer Logical Instructions
4072*/
cerion7aa4bbc2005-01-29 09:32:07 +00004073static Bool dis_int_logic ( UInt theInstr )
4074{
cerion76de5cf2005-11-18 18:25:12 +00004075 /* D-Form, X-Form */
4076 UChar opc1 = ifieldOPC(theInstr);
4077 UChar rS_addr = ifieldRegDS(theInstr);
4078 UChar rA_addr = ifieldRegA(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00004079 UInt uimm16 = ifieldUIMM16(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00004080 UChar rB_addr = ifieldRegB(theInstr);
4081 UInt opc2 = ifieldOPClo10(theInstr);
4082 UChar flag_rC = ifieldBIT0(theInstr);
cerionb85e8bb2005-02-16 08:54:33 +00004083
ceriond953ebb2005-11-29 13:27:20 +00004084 IRType ty = mode64 ? Ity_I64 : Ity_I32;
4085 IRTemp rS = newTemp(ty);
4086 IRTemp rA = newTemp(ty);
4087 IRTemp rB = newTemp(ty);
cerione9d361a2005-03-04 17:35:29 +00004088 IRExpr* irx;
ceriond953ebb2005-11-29 13:27:20 +00004089 Bool do_rc = False;
4090
cerion76de5cf2005-11-18 18:25:12 +00004091 assign( rS, getIReg(rS_addr) );
4092 assign( rB, getIReg(rB_addr) );
cerionb85e8bb2005-02-16 08:54:33 +00004093
4094 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00004095 case 0x1C: // andi. (AND Immediate, PPC32 p358)
ceriond953ebb2005-11-29 13:27:20 +00004096 DIP("andi. r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004097 assign( rA, binop( mkSzOp(ty, Iop_And8), mkexpr(rS),
4098 mkSzImm(ty, uimm16)) );
cerion70e24122005-03-16 00:27:37 +00004099 do_rc = True; // Always record to CR
cerion76de5cf2005-11-18 18:25:12 +00004100 flag_rC = 1;
cerionb85e8bb2005-02-16 08:54:33 +00004101 break;
4102
cerione9d361a2005-03-04 17:35:29 +00004103 case 0x1D: // andis. (AND Immediate Shifted, PPC32 p359)
ceriond953ebb2005-11-29 13:27:20 +00004104 DIP("andis r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004105 assign( rA, binop( mkSzOp(ty, Iop_And8), mkexpr(rS),
4106 mkSzImm(ty, uimm16 << 16)) );
cerion70e24122005-03-16 00:27:37 +00004107 do_rc = True; // Always record to CR
cerion76de5cf2005-11-18 18:25:12 +00004108 flag_rC = 1;
cerionb85e8bb2005-02-16 08:54:33 +00004109 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004110
cerione9d361a2005-03-04 17:35:29 +00004111 case 0x18: // ori (OR Immediate, PPC32 p497)
ceriond953ebb2005-11-29 13:27:20 +00004112 DIP("ori r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004113 assign( rA, binop( mkSzOp(ty, Iop_Or8), mkexpr(rS),
4114 mkSzImm(ty, uimm16)) );
cerionb85e8bb2005-02-16 08:54:33 +00004115 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004116
cerione9d361a2005-03-04 17:35:29 +00004117 case 0x19: // oris (OR Immediate Shifted, PPC32 p498)
ceriond953ebb2005-11-29 13:27:20 +00004118 DIP("oris r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004119 assign( rA, binop( mkSzOp(ty, Iop_Or8), mkexpr(rS),
4120 mkSzImm(ty, uimm16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00004121 break;
cerionaabdfbf2005-01-29 12:56:15 +00004122
cerione9d361a2005-03-04 17:35:29 +00004123 case 0x1A: // xori (XOR Immediate, PPC32 p550)
ceriond953ebb2005-11-29 13:27:20 +00004124 DIP("xori r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004125 assign( rA, binop( mkSzOp(ty, Iop_Xor8), mkexpr(rS),
4126 mkSzImm(ty, uimm16)) );
cerionb85e8bb2005-02-16 08:54:33 +00004127 break;
cerion38674602005-02-08 02:19:25 +00004128
cerione9d361a2005-03-04 17:35:29 +00004129 case 0x1B: // xoris (XOR Immediate Shifted, PPC32 p551)
ceriond953ebb2005-11-29 13:27:20 +00004130 DIP("xoris r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004131 assign( rA, binop( mkSzOp(ty, Iop_Xor8), mkexpr(rS),
4132 mkSzImm(ty, uimm16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00004133 break;
cerionaabdfbf2005-01-29 12:56:15 +00004134
cerionb85e8bb2005-02-16 08:54:33 +00004135 /* X Form */
4136 case 0x1F:
sewardj4aa412a2011-07-24 14:13:21 +00004137 do_rc = True; // All below record to CR, except for where we return at case end.
cerion70e24122005-03-16 00:27:37 +00004138
cerionb85e8bb2005-02-16 08:54:33 +00004139 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +00004140 case 0x01C: // and (AND, PPC32 p356)
4141 DIP("and%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004142 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004143 assign(rA, binop( mkSzOp(ty, Iop_And8),
ceriond953ebb2005-11-29 13:27:20 +00004144 mkexpr(rS), mkexpr(rB)));
4145 break;
4146
4147 case 0x03C: // andc (AND with Complement, PPC32 p357)
4148 DIP("andc%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004149 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004150 assign(rA, binop( mkSzOp(ty, Iop_And8), mkexpr(rS),
4151 unop( mkSzOp(ty, Iop_Not8),
ceriond953ebb2005-11-29 13:27:20 +00004152 mkexpr(rB))));
4153 break;
4154
4155 case 0x01A: { // cntlzw (Count Leading Zeros Word, PPC32 p371)
4156 IRExpr* lo32;
4157 if (rB_addr!=0) {
cerion5b2325f2005-12-23 00:55:09 +00004158 vex_printf("dis_int_logic(ppc)(cntlzw,rB_addr)\n");
ceriond953ebb2005-11-29 13:27:20 +00004159 return False;
4160 }
4161 DIP("cntlzw%s r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004162 flag_rC ? ".":"", rA_addr, rS_addr);
ceriond953ebb2005-11-29 13:27:20 +00004163
4164 // mode64: count in low word only
4165 lo32 = mode64 ? unop(Iop_64to32, mkexpr(rS)) : mkexpr(rS);
4166
4167 // Iop_Clz32 undefined for arg==0, so deal with that case:
4168 irx = binop(Iop_CmpNE32, lo32, mkU32(0));
sewardje9d8a262009-07-01 08:06:34 +00004169 assign(rA, mkWidenFrom32(ty,
florian99dd03e2013-01-29 03:56:06 +00004170 IRExpr_ITE( irx,
4171 unop(Iop_Clz32, lo32),
4172 mkU32(32)),
cerion5b2325f2005-12-23 00:55:09 +00004173 False));
4174
ceriond953ebb2005-11-29 13:27:20 +00004175 // TODO: alternatively: assign(rA, verbose_Clz32(rS));
4176 break;
4177 }
4178
4179 case 0x11C: // eqv (Equivalent, PPC32 p396)
4180 DIP("eqv%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004181 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004182 assign( rA, unop( mkSzOp(ty, Iop_Not8),
4183 binop( mkSzOp(ty, Iop_Xor8),
ceriond953ebb2005-11-29 13:27:20 +00004184 mkexpr(rS), mkexpr(rB))) );
sewardj20ef5472005-07-21 14:48:31 +00004185 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004186
cerione9d361a2005-03-04 17:35:29 +00004187 case 0x3BA: // extsb (Extend Sign Byte, PPC32 p397
cerion76de5cf2005-11-18 18:25:12 +00004188 if (rB_addr!=0) {
cerion5b2325f2005-12-23 00:55:09 +00004189 vex_printf("dis_int_logic(ppc)(extsb,rB_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004190 return False;
4191 }
ceriond953ebb2005-11-29 13:27:20 +00004192 DIP("extsb%s r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004193 flag_rC ? ".":"", rA_addr, rS_addr);
ceriond953ebb2005-11-29 13:27:20 +00004194 if (mode64)
4195 assign( rA, unop(Iop_8Sto64, unop(Iop_64to8, mkexpr(rS))) );
4196 else
4197 assign( rA, unop(Iop_8Sto32, unop(Iop_32to8, mkexpr(rS))) );
cerionb85e8bb2005-02-16 08:54:33 +00004198 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004199
cerione9d361a2005-03-04 17:35:29 +00004200 case 0x39A: // extsh (Extend Sign Half Word, PPC32 p398)
cerion76de5cf2005-11-18 18:25:12 +00004201 if (rB_addr!=0) {
cerion5b2325f2005-12-23 00:55:09 +00004202 vex_printf("dis_int_logic(ppc)(extsh,rB_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004203 return False;
4204 }
ceriond953ebb2005-11-29 13:27:20 +00004205 DIP("extsh%s r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004206 flag_rC ? ".":"", rA_addr, rS_addr);
ceriond953ebb2005-11-29 13:27:20 +00004207 if (mode64)
cerion5b2325f2005-12-23 00:55:09 +00004208 assign( rA, unop(Iop_16Sto64,
4209 unop(Iop_64to16, mkexpr(rS))) );
ceriond953ebb2005-11-29 13:27:20 +00004210 else
cerion5b2325f2005-12-23 00:55:09 +00004211 assign( rA, unop(Iop_16Sto32,
4212 unop(Iop_32to16, mkexpr(rS))) );
cerionb85e8bb2005-02-16 08:54:33 +00004213 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004214
cerione9d361a2005-03-04 17:35:29 +00004215 case 0x1DC: // nand (NAND, PPC32 p492)
ceriond953ebb2005-11-29 13:27:20 +00004216 DIP("nand%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004217 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004218 assign( rA, unop( mkSzOp(ty, Iop_Not8),
4219 binop( mkSzOp(ty, Iop_And8),
ceriond953ebb2005-11-29 13:27:20 +00004220 mkexpr(rS), mkexpr(rB))) );
cerionb85e8bb2005-02-16 08:54:33 +00004221 break;
4222
cerione9d361a2005-03-04 17:35:29 +00004223 case 0x07C: // nor (NOR, PPC32 p494)
ceriond953ebb2005-11-29 13:27:20 +00004224 DIP("nor%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004225 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004226 assign( rA, unop( mkSzOp(ty, Iop_Not8),
4227 binop( mkSzOp(ty, Iop_Or8),
ceriond953ebb2005-11-29 13:27:20 +00004228 mkexpr(rS), mkexpr(rB))) );
cerionb85e8bb2005-02-16 08:54:33 +00004229 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004230
cerione9d361a2005-03-04 17:35:29 +00004231 case 0x1BC: // or (OR, PPC32 p495)
cerion76de5cf2005-11-18 18:25:12 +00004232 if ((!flag_rC) && rS_addr == rB_addr) {
ceriond953ebb2005-11-29 13:27:20 +00004233 DIP("mr r%u,r%u\n", rA_addr, rS_addr);
cerion76de5cf2005-11-18 18:25:12 +00004234 assign( rA, mkexpr(rS) );
sewardjb51f0f42005-07-18 11:38:02 +00004235 } else {
ceriond953ebb2005-11-29 13:27:20 +00004236 DIP("or%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004237 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004238 assign( rA, binop( mkSzOp(ty, Iop_Or8),
ceriond953ebb2005-11-29 13:27:20 +00004239 mkexpr(rS), mkexpr(rB)) );
sewardjb51f0f42005-07-18 11:38:02 +00004240 }
cerionb85e8bb2005-02-16 08:54:33 +00004241 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004242
cerione9d361a2005-03-04 17:35:29 +00004243 case 0x19C: // orc (OR with Complement, PPC32 p496)
ceriond953ebb2005-11-29 13:27:20 +00004244 DIP("orc%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004245 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004246 assign( rA, binop( mkSzOp(ty, Iop_Or8), mkexpr(rS),
4247 unop(mkSzOp(ty, Iop_Not8), mkexpr(rB))));
cerionb85e8bb2005-02-16 08:54:33 +00004248 break;
4249
cerione9d361a2005-03-04 17:35:29 +00004250 case 0x13C: // xor (XOR, PPC32 p549)
ceriond953ebb2005-11-29 13:27:20 +00004251 DIP("xor%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004252 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004253 assign( rA, binop( mkSzOp(ty, Iop_Xor8),
ceriond953ebb2005-11-29 13:27:20 +00004254 mkexpr(rS), mkexpr(rB)) );
cerionb85e8bb2005-02-16 08:54:33 +00004255 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004256
cerionf0de28c2005-12-13 20:21:11 +00004257
4258 /* 64bit Integer Logical Instructions */
4259 case 0x3DA: // extsw (Extend Sign Word, PPC64 p430)
4260 if (rB_addr!=0) {
cerion5b2325f2005-12-23 00:55:09 +00004261 vex_printf("dis_int_logic(ppc)(extsw,rB_addr)\n");
cerionf0de28c2005-12-13 20:21:11 +00004262 return False;
4263 }
cerion5b2325f2005-12-23 00:55:09 +00004264 DIP("extsw%s r%u,r%u\n", flag_rC ? ".":"", rA_addr, rS_addr);
cerionf0de28c2005-12-13 20:21:11 +00004265 assign(rA, unop(Iop_32Sto64, unop(Iop_64to32, mkexpr(rS))));
4266 break;
4267
cerion5b2325f2005-12-23 00:55:09 +00004268 case 0x03A: // cntlzd (Count Leading Zeros DWord, PPC64 p401)
cerionf0de28c2005-12-13 20:21:11 +00004269 if (rB_addr!=0) {
cerion5b2325f2005-12-23 00:55:09 +00004270 vex_printf("dis_int_logic(ppc)(cntlzd,rB_addr)\n");
cerionf0de28c2005-12-13 20:21:11 +00004271 return False;
4272 }
cerion5b2325f2005-12-23 00:55:09 +00004273 DIP("cntlzd%s r%u,r%u\n",
4274 flag_rC ? ".":"", rA_addr, rS_addr);
cerion07b07a92005-12-22 14:32:35 +00004275 // Iop_Clz64 undefined for arg==0, so deal with that case:
4276 irx = binop(Iop_CmpNE64, mkexpr(rS), mkU64(0));
florian99dd03e2013-01-29 03:56:06 +00004277 assign(rA, IRExpr_ITE( irx,
4278 unop(Iop_Clz64, mkexpr(rS)),
4279 mkU64(64) ));
cerion5b2325f2005-12-23 00:55:09 +00004280 // TODO: alternatively: assign(rA, verbose_Clz64(rS));
cerion07b07a92005-12-22 14:32:35 +00004281 break;
cerionf0de28c2005-12-13 20:21:11 +00004282
sewardj7e846302010-09-03 23:37:02 +00004283 case 0x1FC: // cmpb (Power6: compare bytes)
4284 DIP("cmpb r%u,r%u,r%u\n", rA_addr, rS_addr, rB_addr);
4285
4286 if (mode64)
4287 assign( rA, unop( Iop_V128to64,
4288 binop( Iop_CmpEQ8x16,
4289 binop( Iop_64HLtoV128, mkU64(0), mkexpr(rS) ),
4290 binop( Iop_64HLtoV128, mkU64(0), mkexpr(rB) )
4291 )) );
4292 else
4293 assign( rA, unop( Iop_V128to32,
4294 binop( Iop_CmpEQ8x16,
4295 unop( Iop_32UtoV128, mkexpr(rS) ),
4296 unop( Iop_32UtoV128, mkexpr(rB) )
4297 )) );
4298 break;
4299
4300 case 0x2DF: { // mftgpr (move floating-point to general purpose register)
4301 IRTemp frB = newTemp(Ity_F64);
4302 DIP("mftgpr r%u,fr%u\n", rS_addr, rB_addr);
4303
4304 assign( frB, getFReg(rB_addr)); // always F64
4305 if (mode64)
4306 assign( rA, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
4307 else
4308 assign( rA, unop( Iop_64to32, unop( Iop_ReinterpF64asI64, mkexpr(frB))) );
4309
4310 putIReg( rS_addr, mkexpr(rA));
4311 return True;
4312 }
4313
4314 case 0x25F: { // mffgpr (move floating-point from general purpose register)
4315 IRTemp frA = newTemp(Ity_F64);
4316 DIP("mffgpr fr%u,r%u\n", rS_addr, rB_addr);
4317
4318 if (mode64)
4319 assign( frA, unop( Iop_ReinterpI64asF64, mkexpr(rB)) );
4320 else
4321 assign( frA, unop( Iop_ReinterpI64asF64, unop( Iop_32Uto64, mkexpr(rB))) );
4322
4323 putFReg( rS_addr, mkexpr(frA));
4324 return True;
4325 }
sewardj66d5ef22011-04-15 11:55:00 +00004326 case 0x1FA: // popcntd (population count doubleword
4327 {
4328 DIP("popcntd r%u,r%u\n", rA_addr, rS_addr);
carll7deaf952013-10-15 18:11:20 +00004329 IRTemp result = gen_POPCOUNT(ty, rS, DWORD);
sewardj66d5ef22011-04-15 11:55:00 +00004330 putIReg( rA_addr, mkexpr(result) );
4331 return True;
4332 }
sewardje71e56a2011-09-05 12:11:06 +00004333 case 0x17A: // popcntw (Population Count Words)
4334 {
4335 DIP("popcntw r%u,r%u\n", rA_addr, rS_addr);
4336 if (mode64) {
4337 IRTemp resultHi, resultLo;
4338 IRTemp argLo = newTemp(Ity_I32);
4339 IRTemp argHi = newTemp(Ity_I32);
4340 assign(argLo, unop(Iop_64to32, mkexpr(rS)));
4341 assign(argHi, unop(Iop_64HIto32, mkexpr(rS)));
carll7deaf952013-10-15 18:11:20 +00004342 resultLo = gen_POPCOUNT(Ity_I32, argLo, WORD);
4343 resultHi = gen_POPCOUNT(Ity_I32, argHi, WORD);
sewardje71e56a2011-09-05 12:11:06 +00004344 putIReg( rA_addr, binop(Iop_32HLto64, mkexpr(resultHi), mkexpr(resultLo)));
4345 } else {
carll7deaf952013-10-15 18:11:20 +00004346 IRTemp result = gen_POPCOUNT(ty, rS, WORD);
philippe738d9dd2012-07-06 21:56:53 +00004347 putIReg( rA_addr, mkexpr(result) );
4348 }
4349 return True;
4350 }
4351 case 0x7A: // popcntb (Population Count Byte)
4352 {
4353 DIP("popcntb r%u,r%u\n", rA_addr, rS_addr);
4354
4355 if (mode64) {
4356 IRTemp resultHi, resultLo;
4357 IRTemp argLo = newTemp(Ity_I32);
4358 IRTemp argHi = newTemp(Ity_I32);
4359 assign(argLo, unop(Iop_64to32, mkexpr(rS)));
4360 assign(argHi, unop(Iop_64HIto32, mkexpr(rS)));
carll7deaf952013-10-15 18:11:20 +00004361 resultLo = gen_POPCOUNT(Ity_I32, argLo, BYTE);
4362 resultHi = gen_POPCOUNT(Ity_I32, argHi, BYTE);
philippe738d9dd2012-07-06 21:56:53 +00004363 putIReg( rA_addr, binop(Iop_32HLto64, mkexpr(resultHi),
4364 mkexpr(resultLo)));
4365 } else {
carll7deaf952013-10-15 18:11:20 +00004366 IRTemp result = gen_POPCOUNT(ty, rS, BYTE);
sewardje71e56a2011-09-05 12:11:06 +00004367 putIReg( rA_addr, mkexpr(result) );
4368 }
4369 return True;
4370 }
sewardj4aa412a2011-07-24 14:13:21 +00004371 case 0x0FC: // bpermd (Bit Permute Doubleword)
4372 {
4373 /* This is a lot of rigmarole to emulate bpermd like this, as it
4374 * could be done much faster by implementing a call to the native
4375 * instruction. However, where possible I want to avoid using new
4376 * native instructions so that we can use valgrind to emulate those
4377 * instructions on older PPC64 hardware.
4378 */
4379 #define BPERMD_IDX_MASK 0x00000000000000FFULL
4380 #define BPERMD_BIT_MASK 0x8000000000000000ULL
4381 int i;
4382 IRExpr * rS_expr = mkexpr(rS);
4383 IRExpr * res = binop(Iop_And64, mkU64(0), mkU64(0));
4384 DIP("bpermd r%u,r%u,r%u\n", rA_addr, rS_addr, rB_addr);
4385 for (i = 0; i < 8; i++) {
4386 IRTemp idx_tmp = newTemp( Ity_I64 );
4387 IRTemp perm_bit = newTemp( Ity_I64 );
4388 IRTemp idx = newTemp( Ity_I8 );
4389 IRTemp idx_LT64 = newTemp( Ity_I1 );
4390 IRTemp idx_LT64_ity64 = newTemp( Ity_I64 );
4391
4392 assign( idx_tmp,
4393 binop( Iop_And64, mkU64( BPERMD_IDX_MASK ), rS_expr ) );
4394 assign( idx_LT64,
4395 binop( Iop_CmpLT64U, mkexpr( idx_tmp ), mkU64( 64 ) ) );
4396 assign( idx,
4397 binop( Iop_And8,
4398 unop( Iop_1Sto8,
4399 mkexpr(idx_LT64) ),
4400 unop( Iop_64to8, mkexpr( idx_tmp ) ) ) );
4401 /* If idx_LT64 == 0, we must force the perm bit to '0'. Below, we se idx
4402 * to determine which bit of rB to use for the perm bit, and then we shift
4403 * that bit to the MSB position. We AND that with a 64-bit-ized idx_LT64
4404 * to set the final perm bit.
4405 */
4406 assign( idx_LT64_ity64,
4407 unop( Iop_32Uto64, unop( Iop_1Uto32, mkexpr(idx_LT64 ) ) ) );
4408 assign( perm_bit,
4409 binop( Iop_And64,
4410 mkexpr( idx_LT64_ity64 ),
4411 binop( Iop_Shr64,
4412 binop( Iop_And64,
4413 mkU64( BPERMD_BIT_MASK ),
4414 binop( Iop_Shl64,
4415 mkexpr( rB ),
4416 mkexpr( idx ) ) ),
4417 mkU8( 63 ) ) ) );
4418 res = binop( Iop_Or64,
4419 res,
4420 binop( Iop_Shl64,
4421 mkexpr( perm_bit ),
4422 mkU8( i ) ) );
4423 rS_expr = binop( Iop_Shr64, rS_expr, mkU8( 8 ) );
4424 }
4425 putIReg(rA_addr, res);
4426 return True;
4427 }
4428
cerionb85e8bb2005-02-16 08:54:33 +00004429 default:
cerion5b2325f2005-12-23 00:55:09 +00004430 vex_printf("dis_int_logic(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004431 return False;
4432 }
cerionb85e8bb2005-02-16 08:54:33 +00004433 break;
4434
4435 default:
cerion5b2325f2005-12-23 00:55:09 +00004436 vex_printf("dis_int_logic(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004437 return False;
4438 }
cerion70e24122005-03-16 00:27:37 +00004439
cerion76de5cf2005-11-18 18:25:12 +00004440 putIReg( rA_addr, mkexpr(rA) );
4441
4442 if (do_rc && flag_rC) {
4443 set_CR0( mkexpr(rA) );
cerionb85e8bb2005-02-16 08:54:33 +00004444 }
4445 return True;
cerion645c9302005-01-31 10:09:59 +00004446}
4447
sewardj7e846302010-09-03 23:37:02 +00004448/*
4449 Integer Parity Instructions
4450*/
4451static Bool dis_int_parity ( UInt theInstr )
4452{
4453 /* X-Form */
4454 UChar opc1 = ifieldOPC(theInstr);
4455 UChar rS_addr = ifieldRegDS(theInstr);
4456 UChar rA_addr = ifieldRegA(theInstr);
4457 UChar rB_addr = ifieldRegB(theInstr);
4458 UInt opc2 = ifieldOPClo10(theInstr);
4459 UChar b0 = ifieldBIT0(theInstr);
4460 IRType ty = mode64 ? Ity_I64 : Ity_I32;
4461
4462 IRTemp rS = newTemp(ty);
4463 IRTemp rA = newTemp(ty);
4464 IRTemp iTot1 = newTemp(Ity_I32);
4465 IRTemp iTot2 = newTemp(Ity_I32);
4466 IRTemp iTot3 = newTemp(Ity_I32);
4467 IRTemp iTot4 = newTemp(Ity_I32);
4468 IRTemp iTot5 = newTemp(Ity_I32);
4469 IRTemp iTot6 = newTemp(Ity_I32);
4470 IRTemp iTot7 = newTemp(Ity_I32);
4471 IRTemp iTot8 = newTemp(Ity_I32);
4472 IRTemp rS1 = newTemp(ty);
4473 IRTemp rS2 = newTemp(ty);
4474 IRTemp rS3 = newTemp(ty);
4475 IRTemp rS4 = newTemp(ty);
4476 IRTemp rS5 = newTemp(ty);
4477 IRTemp rS6 = newTemp(ty);
4478 IRTemp rS7 = newTemp(ty);
4479 IRTemp iHi = newTemp(Ity_I32);
4480 IRTemp iLo = newTemp(Ity_I32);
4481 IROp to_bit = (mode64 ? Iop_64to1 : Iop_32to1);
4482 IROp shr_op = (mode64 ? Iop_Shr64 : Iop_Shr32);
4483
4484 if (opc1 != 0x1f || rB_addr || b0) {
4485 vex_printf("dis_int_parity(ppc)(0x1F,opc1:rB|b0)\n");
4486 return False;
4487 }
4488
4489 assign( rS, getIReg(rS_addr) );
4490
4491 switch (opc2) {
4492 case 0xba: // prtyd (Parity Doubleword, ISA 2.05 p320)
4493 DIP("prtyd r%u,r%u\n", rA_addr, rS_addr);
4494 assign( iTot1, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS))) );
4495 assign( rS1, binop(shr_op, mkexpr(rS), mkU8(8)) );
4496 assign( iTot2, binop(Iop_Add32,
4497 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS1))),
4498 mkexpr(iTot1)) );
4499 assign( rS2, binop(shr_op, mkexpr(rS1), mkU8(8)) );
4500 assign( iTot3, binop(Iop_Add32,
4501 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS2))),
4502 mkexpr(iTot2)) );
4503 assign( rS3, binop(shr_op, mkexpr(rS2), mkU8(8)) );
4504 assign( iTot4, binop(Iop_Add32,
4505 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS3))),
4506 mkexpr(iTot3)) );
4507 if (mode64) {
4508 assign( rS4, binop(shr_op, mkexpr(rS3), mkU8(8)) );
4509 assign( iTot5, binop(Iop_Add32,
4510 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS4))),
4511 mkexpr(iTot4)) );
4512 assign( rS5, binop(shr_op, mkexpr(rS4), mkU8(8)) );
4513 assign( iTot6, binop(Iop_Add32,
4514 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS5))),
4515 mkexpr(iTot5)) );
4516 assign( rS6, binop(shr_op, mkexpr(rS5), mkU8(8)) );
4517 assign( iTot7, binop(Iop_Add32,
4518 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS6))),
4519 mkexpr(iTot6)) );
4520 assign( rS7, binop(shr_op, mkexpr(rS6), mkU8(8)) );
4521 assign( iTot8, binop(Iop_Add32,
4522 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS7))),
4523 mkexpr(iTot7)) );
4524 assign( rA, unop(Iop_32Uto64,
4525 binop(Iop_And32, mkexpr(iTot8), mkU32(1))) );
4526 } else
4527 assign( rA, mkexpr(iTot4) );
4528
4529 break;
4530 case 0x9a: // prtyw (Parity Word, ISA 2.05 p320)
4531 assign( iTot1, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS))) );
4532 assign( rS1, binop(shr_op, mkexpr(rS), mkU8(8)) );
4533 assign( iTot2, binop(Iop_Add32,
4534 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS1))),
4535 mkexpr(iTot1)) );
4536 assign( rS2, binop(shr_op, mkexpr(rS1), mkU8(8)) );
4537 assign( iTot3, binop(Iop_Add32,
4538 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS2))),
4539 mkexpr(iTot2)) );
4540 assign( rS3, binop(shr_op, mkexpr(rS2), mkU8(8)) );
4541 assign( iTot4, binop(Iop_Add32,
4542 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS3))),
4543 mkexpr(iTot3)) );
4544 assign( iLo, unop(Iop_1Uto32, unop(Iop_32to1, mkexpr(iTot4) )) );
4545
4546 if (mode64) {
4547 assign( rS4, binop(shr_op, mkexpr(rS3), mkU8(8)) );
4548 assign( iTot5, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS4))) );
4549 assign( rS5, binop(shr_op, mkexpr(rS4), mkU8(8)) );
4550 assign( iTot6, binop(Iop_Add32,
4551 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS5))),
4552 mkexpr(iTot5)) );
4553 assign( rS6, binop(shr_op, mkexpr(rS5), mkU8(8)) );
4554 assign( iTot7, binop(Iop_Add32,
4555 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS6))),
4556 mkexpr(iTot6)) );
4557 assign( rS7, binop(shr_op, mkexpr(rS6), mkU8(8)));
4558 assign( iTot8, binop(Iop_Add32,
4559 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS7))),
4560 mkexpr(iTot7)) );
4561 assign( iHi, binop(Iop_And32, mkU32(1), mkexpr(iTot8)) ),
4562 assign( rA, binop(Iop_32HLto64, mkexpr(iHi), mkexpr(iLo)) );
4563 } else
4564 assign( rA, binop(Iop_Or32, mkU32(0), mkexpr(iLo)) );
4565 break;
4566 default:
4567 vex_printf("dis_int_parity(ppc)(opc2)\n");
4568 return False;
4569 }
4570
4571 putIReg( rA_addr, mkexpr(rA) );
4572
4573 return True;
4574}
cerion645c9302005-01-31 10:09:59 +00004575
4576
cerion3d870a32005-03-18 12:23:33 +00004577/*
4578 Integer Rotate Instructions
4579*/
cerion645c9302005-01-31 10:09:59 +00004580static Bool dis_int_rot ( UInt theInstr )
4581{
cerionf0de28c2005-12-13 20:21:11 +00004582 /* M-Form, MDS-Form */
ceriond953ebb2005-11-29 13:27:20 +00004583 UChar opc1 = ifieldOPC(theInstr);
4584 UChar rS_addr = ifieldRegDS(theInstr);
4585 UChar rA_addr = ifieldRegA(theInstr);
4586 UChar rB_addr = ifieldRegB(theInstr);
4587 UChar sh_imm = rB_addr;
4588 UChar MaskBeg = toUChar( IFIELD( theInstr, 6, 5 ) );
4589 UChar MaskEnd = toUChar( IFIELD( theInstr, 1, 5 ) );
cerionf0de28c2005-12-13 20:21:11 +00004590 UChar msk_imm = toUChar( IFIELD( theInstr, 5, 6 ) );
4591 UChar opc2 = toUChar( IFIELD( theInstr, 2, 3 ) );
4592 UChar b1 = ifieldBIT1(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00004593 UChar flag_rC = ifieldBIT0(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00004594
ceriond953ebb2005-11-29 13:27:20 +00004595 IRType ty = mode64 ? Ity_I64 : Ity_I32;
4596 IRTemp rS = newTemp(ty);
4597 IRTemp rA = newTemp(ty);
4598 IRTemp rB = newTemp(ty);
cerionbb01b7c2005-12-16 13:40:18 +00004599 IRTemp rot = newTemp(ty);
ceriond953ebb2005-11-29 13:27:20 +00004600 IRExpr *r;
cerionf0de28c2005-12-13 20:21:11 +00004601 UInt mask32;
4602 ULong mask64;
ceriond953ebb2005-11-29 13:27:20 +00004603
cerion76de5cf2005-11-18 18:25:12 +00004604 assign( rS, getIReg(rS_addr) );
4605 assign( rB, getIReg(rB_addr) );
ceriond953ebb2005-11-29 13:27:20 +00004606
cerionb85e8bb2005-02-16 08:54:33 +00004607 switch (opc1) {
ceriond953ebb2005-11-29 13:27:20 +00004608 case 0x14: {
cerion5b2325f2005-12-23 00:55:09 +00004609 // rlwimi (Rotate Left Word Imm then Mask Insert, PPC32 p500)
4610 DIP("rlwimi%s r%u,r%u,%d,%d,%d\n", flag_rC ? ".":"",
ceriond953ebb2005-11-29 13:27:20 +00004611 rA_addr, rS_addr, sh_imm, MaskBeg, MaskEnd);
4612 if (mode64) {
4613 // tmp32 = (ROTL(rS_Lo32, Imm)
4614 // rA = ((tmp32 || tmp32) & mask64) | (rA & ~mask64)
cerionf0de28c2005-12-13 20:21:11 +00004615 mask64 = MASK64(31-MaskEnd, 31-MaskBeg);
ceriond953ebb2005-11-29 13:27:20 +00004616 r = ROTL( unop(Iop_64to32, mkexpr(rS) ), mkU8(sh_imm) );
4617 r = unop(Iop_32Uto64, r);
cerion5b2325f2005-12-23 00:55:09 +00004618 assign( rot, binop(Iop_Or64, r,
4619 binop(Iop_Shl64, r, mkU8(32))) );
ceriond953ebb2005-11-29 13:27:20 +00004620 assign( rA,
4621 binop(Iop_Or64,
cerionbb01b7c2005-12-16 13:40:18 +00004622 binop(Iop_And64, mkexpr(rot), mkU64(mask64)),
cerionf0de28c2005-12-13 20:21:11 +00004623 binop(Iop_And64, getIReg(rA_addr), mkU64(~mask64))) );
sewardj26b33202005-10-07 09:45:16 +00004624 }
4625 else {
ceriond953ebb2005-11-29 13:27:20 +00004626 // rA = (ROTL(rS, Imm) & mask) | (rA & ~mask);
cerionf0de28c2005-12-13 20:21:11 +00004627 mask32 = MASK32(31-MaskEnd, 31-MaskBeg);
4628 r = ROTL(mkexpr(rS), mkU8(sh_imm));
ceriond953ebb2005-11-29 13:27:20 +00004629 assign( rA,
4630 binop(Iop_Or32,
cerionf0de28c2005-12-13 20:21:11 +00004631 binop(Iop_And32, mkU32(mask32), r),
4632 binop(Iop_And32, getIReg(rA_addr), mkU32(~mask32))) );
sewardj26b33202005-10-07 09:45:16 +00004633 }
cerionb85e8bb2005-02-16 08:54:33 +00004634 break;
ceriond953ebb2005-11-29 13:27:20 +00004635 }
cerion45b70ff2005-01-31 17:03:25 +00004636
ceriond953ebb2005-11-29 13:27:20 +00004637 case 0x15: {
cerion5b2325f2005-12-23 00:55:09 +00004638 // rlwinm (Rotate Left Word Imm then AND with Mask, PPC32 p501)
ceriond953ebb2005-11-29 13:27:20 +00004639 vassert(MaskBeg < 32);
4640 vassert(MaskEnd < 32);
4641 vassert(sh_imm < 32);
4642
4643 if (mode64) {
sewardjef4433b2006-10-19 03:01:09 +00004644 IRTemp rTmp = newTemp(Ity_I64);
cerionf0de28c2005-12-13 20:21:11 +00004645 mask64 = MASK64(31-MaskEnd, 31-MaskBeg);
cerion5b2325f2005-12-23 00:55:09 +00004646 DIP("rlwinm%s r%u,r%u,%d,%d,%d\n", flag_rC ? ".":"",
ceriond953ebb2005-11-29 13:27:20 +00004647 rA_addr, rS_addr, sh_imm, MaskBeg, MaskEnd);
4648 // tmp32 = (ROTL(rS_Lo32, Imm)
4649 // rA = ((tmp32 || tmp32) & mask64)
4650 r = ROTL( unop(Iop_64to32, mkexpr(rS) ), mkU8(sh_imm) );
4651 r = unop(Iop_32Uto64, r);
sewardjef4433b2006-10-19 03:01:09 +00004652 assign( rTmp, r );
4653 r = NULL;
4654 assign( rot, binop(Iop_Or64, mkexpr(rTmp),
4655 binop(Iop_Shl64, mkexpr(rTmp), mkU8(32))) );
cerionbb01b7c2005-12-16 13:40:18 +00004656 assign( rA, binop(Iop_And64, mkexpr(rot), mkU64(mask64)) );
ceriond953ebb2005-11-29 13:27:20 +00004657 }
4658 else {
4659 if (MaskBeg == 0 && sh_imm+MaskEnd == 31) {
4660 /* Special-case the ,n,0,31-n form as that is just n-bit
cerion5b2325f2005-12-23 00:55:09 +00004661 shift left, PPC32 p501 */
4662 DIP("slwi%s r%u,r%u,%d\n", flag_rC ? ".":"",
ceriond953ebb2005-11-29 13:27:20 +00004663 rA_addr, rS_addr, sh_imm);
4664 assign( rA, binop(Iop_Shl32, mkexpr(rS), mkU8(sh_imm)) );
4665 }
cerion2831b002005-11-30 19:55:22 +00004666 else if (MaskEnd == 31 && sh_imm+MaskBeg == 32) {
4667 /* Special-case the ,32-n,n,31 form as that is just n-bit
cerion5b2325f2005-12-23 00:55:09 +00004668 unsigned shift right, PPC32 p501 */
4669 DIP("srwi%s r%u,r%u,%d\n", flag_rC ? ".":"",
sewardjee4a8592006-10-19 00:15:25 +00004670 rA_addr, rS_addr, MaskBeg);
cerion2831b002005-11-30 19:55:22 +00004671 assign( rA, binop(Iop_Shr32, mkexpr(rS), mkU8(MaskBeg)) );
4672 }
4673 else {
4674 /* General case. */
cerionf0de28c2005-12-13 20:21:11 +00004675 mask32 = MASK32(31-MaskEnd, 31-MaskBeg);
cerion5b2325f2005-12-23 00:55:09 +00004676 DIP("rlwinm%s r%u,r%u,%d,%d,%d\n", flag_rC ? ".":"",
cerion2831b002005-11-30 19:55:22 +00004677 rA_addr, rS_addr, sh_imm, MaskBeg, MaskEnd);
4678 // rA = ROTL(rS, Imm) & mask
cerion5b2325f2005-12-23 00:55:09 +00004679 assign( rA, binop(Iop_And32,
4680 ROTL(mkexpr(rS), mkU8(sh_imm)),
cerionf0de28c2005-12-13 20:21:11 +00004681 mkU32(mask32)) );
cerion2831b002005-11-30 19:55:22 +00004682 }
ceriond953ebb2005-11-29 13:27:20 +00004683 }
sewardjc9659532005-07-21 21:33:57 +00004684 break;
ceriond953ebb2005-11-29 13:27:20 +00004685 }
4686
4687 case 0x17: {
4688 // rlwnm (Rotate Left Word then AND with Mask, PPC32 p503
cerion5b2325f2005-12-23 00:55:09 +00004689 DIP("rlwnm%s r%u,r%u,r%u,%d,%d\n", flag_rC ? ".":"",
ceriond953ebb2005-11-29 13:27:20 +00004690 rA_addr, rS_addr, rB_addr, MaskBeg, MaskEnd);
4691 if (mode64) {
cerionf0de28c2005-12-13 20:21:11 +00004692 mask64 = MASK64(31-MaskEnd, 31-MaskBeg);
cerionbb01b7c2005-12-16 13:40:18 +00004693 /* weird insn alert!
4694 tmp32 = (ROTL(rS_Lo32, rB[0-4])
4695 rA = ((tmp32 || tmp32) & mask64)
4696 */
ceriond953ebb2005-11-29 13:27:20 +00004697 // note, ROTL does the masking, so we don't do it here
4698 r = ROTL( unop(Iop_64to32, mkexpr(rS)),
cerionbb01b7c2005-12-16 13:40:18 +00004699 unop(Iop_64to8, mkexpr(rB)) );
ceriond953ebb2005-11-29 13:27:20 +00004700 r = unop(Iop_32Uto64, r);
cerionbb01b7c2005-12-16 13:40:18 +00004701 assign(rot, binop(Iop_Or64, r, binop(Iop_Shl64, r, mkU8(32))));
4702 assign( rA, binop(Iop_And64, mkexpr(rot), mkU64(mask64)) );
ceriond953ebb2005-11-29 13:27:20 +00004703 } else {
cerionf0de28c2005-12-13 20:21:11 +00004704 mask32 = MASK32(31-MaskEnd, 31-MaskBeg);
ceriond953ebb2005-11-29 13:27:20 +00004705 // rA = ROTL(rS, rB[0-4]) & mask
4706 // note, ROTL does the masking, so we don't do it here
4707 assign( rA, binop(Iop_And32,
cerion5b2325f2005-12-23 00:55:09 +00004708 ROTL(mkexpr(rS),
4709 unop(Iop_32to8, mkexpr(rB))),
cerionf0de28c2005-12-13 20:21:11 +00004710 mkU32(mask32)) );
ceriond953ebb2005-11-29 13:27:20 +00004711 }
4712 break;
4713 }
cerion45b70ff2005-01-31 17:03:25 +00004714
cerionf0de28c2005-12-13 20:21:11 +00004715 /* 64bit Integer Rotates */
4716 case 0x1E: {
4717 msk_imm = ((msk_imm & 1) << 5) | (msk_imm >> 1);
4718 sh_imm |= b1 << 5;
4719
4720 vassert( msk_imm < 64 );
4721 vassert( sh_imm < 64 );
4722
4723 switch (opc2) {
cerion07b07a92005-12-22 14:32:35 +00004724 case 0x4: {
4725 /* r = ROTL64( rS, rB_lo6) */
4726 r = ROTL( mkexpr(rS), unop(Iop_64to8, mkexpr(rB)) );
4727
cerion5b2325f2005-12-23 00:55:09 +00004728 if (b1 == 0) { // rldcl (Rotl DWord, Clear Left, PPC64 p555)
4729 DIP("rldcl%s r%u,r%u,r%u,%u\n", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00004730 rA_addr, rS_addr, rB_addr, msk_imm);
cerion07b07a92005-12-22 14:32:35 +00004731 // note, ROTL does the masking, so we don't do it here
cerionf0de28c2005-12-13 20:21:11 +00004732 mask64 = MASK64(0, 63-msk_imm);
4733 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
4734 break;
cerion5b2325f2005-12-23 00:55:09 +00004735 } else { // rldcr (Rotl DWord, Clear Right, PPC64 p556)
4736 DIP("rldcr%s r%u,r%u,r%u,%u\n", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00004737 rA_addr, rS_addr, rB_addr, msk_imm);
cerionf0de28c2005-12-13 20:21:11 +00004738 mask64 = MASK64(63-msk_imm, 63);
4739 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
4740 break;
4741 }
4742 break;
cerion07b07a92005-12-22 14:32:35 +00004743 }
cerion5b2325f2005-12-23 00:55:09 +00004744 case 0x2: // rldic (Rotl DWord Imm, Clear, PPC64 p557)
4745 DIP("rldic%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00004746 rA_addr, rS_addr, sh_imm, msk_imm);
4747 r = ROTL(mkexpr(rS), mkU8(sh_imm));
4748 mask64 = MASK64(sh_imm, 63-msk_imm);
4749 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
4750 break;
4751 // later: deal with special case: (msk_imm==0) => SHL(sh_imm)
4752 /*
4753 Hmm... looks like this'll do the job more simply:
4754 r = SHL(rS, sh_imm)
4755 m = ~(1 << (63-msk_imm))
4756 assign(rA, r & m);
4757 */
4758
cerion5b2325f2005-12-23 00:55:09 +00004759 case 0x0: // rldicl (Rotl DWord Imm, Clear Left, PPC64 p558)
sewardjee4a8592006-10-19 00:15:25 +00004760 if (mode64
4761 && sh_imm + msk_imm == 64 && msk_imm >= 1 && msk_imm <= 63) {
4762 /* special-case the ,64-n,n form as that is just
4763 unsigned shift-right by n */
4764 DIP("srdi%s r%u,r%u,%u\n",
4765 flag_rC ? ".":"", rA_addr, rS_addr, msk_imm);
4766 assign( rA, binop(Iop_Shr64, mkexpr(rS), mkU8(msk_imm)) );
4767 } else {
4768 DIP("rldicl%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
4769 rA_addr, rS_addr, sh_imm, msk_imm);
4770 r = ROTL(mkexpr(rS), mkU8(sh_imm));
4771 mask64 = MASK64(0, 63-msk_imm);
4772 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
4773 }
cerionf0de28c2005-12-13 20:21:11 +00004774 break;
cerionf0de28c2005-12-13 20:21:11 +00004775
cerion5b2325f2005-12-23 00:55:09 +00004776 case 0x1: // rldicr (Rotl DWord Imm, Clear Right, PPC64 p559)
sewardjee4a8592006-10-19 00:15:25 +00004777 if (mode64
4778 && sh_imm + msk_imm == 63 && sh_imm >= 1 && sh_imm <= 63) {
4779 /* special-case the ,n,63-n form as that is just
4780 shift-left by n */
4781 DIP("sldi%s r%u,r%u,%u\n",
4782 flag_rC ? ".":"", rA_addr, rS_addr, sh_imm);
4783 assign( rA, binop(Iop_Shl64, mkexpr(rS), mkU8(sh_imm)) );
4784 } else {
4785 DIP("rldicr%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
4786 rA_addr, rS_addr, sh_imm, msk_imm);
4787 r = ROTL(mkexpr(rS), mkU8(sh_imm));
4788 mask64 = MASK64(63-msk_imm, 63);
4789 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
4790 }
cerionf0de28c2005-12-13 20:21:11 +00004791 break;
cerionf0de28c2005-12-13 20:21:11 +00004792
cerion5b2325f2005-12-23 00:55:09 +00004793 case 0x3: { // rldimi (Rotl DWord Imm, Mask Insert, PPC64 p560)
cerion07b07a92005-12-22 14:32:35 +00004794 IRTemp rA_orig = newTemp(ty);
cerion5b2325f2005-12-23 00:55:09 +00004795 DIP("rldimi%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00004796 rA_addr, rS_addr, sh_imm, msk_imm);
4797 r = ROTL(mkexpr(rS), mkU8(sh_imm));
4798 mask64 = MASK64(sh_imm, 63-msk_imm);
cerion07b07a92005-12-22 14:32:35 +00004799 assign( rA_orig, getIReg(rA_addr) );
cerionf0de28c2005-12-13 20:21:11 +00004800 assign( rA, binop(Iop_Or64,
4801 binop(Iop_And64, mkU64(mask64), r),
cerion5b2325f2005-12-23 00:55:09 +00004802 binop(Iop_And64, mkU64(~mask64),
4803 mkexpr(rA_orig))) );
cerionf0de28c2005-12-13 20:21:11 +00004804 break;
cerion07b07a92005-12-22 14:32:35 +00004805 }
cerionf0de28c2005-12-13 20:21:11 +00004806 default:
cerion5b2325f2005-12-23 00:55:09 +00004807 vex_printf("dis_int_rot(ppc)(opc2)\n");
cerionf0de28c2005-12-13 20:21:11 +00004808 return False;
4809 }
4810 break;
4811 }
4812
cerionb85e8bb2005-02-16 08:54:33 +00004813 default:
cerion5b2325f2005-12-23 00:55:09 +00004814 vex_printf("dis_int_rot(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004815 return False;
4816 }
cerion645c9302005-01-31 10:09:59 +00004817
cerion76de5cf2005-11-18 18:25:12 +00004818 putIReg( rA_addr, mkexpr(rA) );
4819
4820 if (flag_rC) {
4821 set_CR0( mkexpr(rA) );
cerionb85e8bb2005-02-16 08:54:33 +00004822 }
4823 return True;
cerion645c9302005-01-31 10:09:59 +00004824}
4825
4826
cerion3d870a32005-03-18 12:23:33 +00004827/*
4828 Integer Load Instructions
4829*/
cerion645c9302005-01-31 10:09:59 +00004830static Bool dis_int_load ( UInt theInstr )
4831{
cerionf0de28c2005-12-13 20:21:11 +00004832 /* D-Form, X-Form, DS-Form */
cerion76de5cf2005-11-18 18:25:12 +00004833 UChar opc1 = ifieldOPC(theInstr);
4834 UChar rD_addr = ifieldRegDS(theInstr);
4835 UChar rA_addr = ifieldRegA(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00004836 UInt uimm16 = ifieldUIMM16(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00004837 UChar rB_addr = ifieldRegB(theInstr);
4838 UInt opc2 = ifieldOPClo10(theInstr);
cerionf0de28c2005-12-13 20:21:11 +00004839 UChar b1 = ifieldBIT1(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00004840 UChar b0 = ifieldBIT0(theInstr);
4841
ceriond953ebb2005-11-29 13:27:20 +00004842 Int simm16 = extend_s_16to32(uimm16);
4843 IRType ty = mode64 ? Ity_I64 : Ity_I32;
ceriond953ebb2005-11-29 13:27:20 +00004844 IRTemp EA = newTemp(ty);
4845 IRExpr* val;
cerionedf7fc52005-11-18 20:57:41 +00004846
cerionf0de28c2005-12-13 20:21:11 +00004847 switch (opc1) {
4848 case 0x1F: // register offset
ceriond953ebb2005-11-29 13:27:20 +00004849 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
cerionf0de28c2005-12-13 20:21:11 +00004850 break;
carll78850ae2013-09-10 18:46:40 +00004851 case 0x38: // immediate offset: 64bit: lq: maskoff
4852 // lowest 4 bits of immediate before forming EA
4853 simm16 = simm16 & 0xFFFFFFF0;
4854 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
4855 break;
sewardj6d834222007-03-09 14:24:38 +00004856 case 0x3A: // immediate offset: 64bit: ld/ldu/lwa: mask off
4857 // lowest 2 bits of immediate before forming EA
cerionf0de28c2005-12-13 20:21:11 +00004858 simm16 = simm16 & 0xFFFFFFFC;
carll78850ae2013-09-10 18:46:40 +00004859 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
4860 break;
cerionf0de28c2005-12-13 20:21:11 +00004861 default: // immediate offset
4862 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
4863 break;
ceriond953ebb2005-11-29 13:27:20 +00004864 }
cerione9d361a2005-03-04 17:35:29 +00004865
cerionb85e8bb2005-02-16 08:54:33 +00004866 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00004867 case 0x22: // lbz (Load B & Zero, PPC32 p433)
ceriond953ebb2005-11-29 13:27:20 +00004868 DIP("lbz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004869 val = load(Ity_I8, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004870 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
cerionb85e8bb2005-02-16 08:54:33 +00004871 break;
4872
cerion5b2325f2005-12-23 00:55:09 +00004873 case 0x23: // lbzu (Load B & Zero, Update, PPC32 p434)
cerion76de5cf2005-11-18 18:25:12 +00004874 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004875 vex_printf("dis_int_load(ppc)(lbzu,rA_addr|rD_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004876 return False;
4877 }
ceriond953ebb2005-11-29 13:27:20 +00004878 DIP("lbzu r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004879 val = load(Ity_I8, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004880 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
ceriond953ebb2005-11-29 13:27:20 +00004881 putIReg( rA_addr, mkexpr(EA) );
cerionb85e8bb2005-02-16 08:54:33 +00004882 break;
4883
cerion5b2325f2005-12-23 00:55:09 +00004884 case 0x2A: // lha (Load HW Alg, PPC32 p445)
ceriond953ebb2005-11-29 13:27:20 +00004885 DIP("lha r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004886 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004887 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
cerionb85e8bb2005-02-16 08:54:33 +00004888 break;
cerion645c9302005-01-31 10:09:59 +00004889
cerion5b2325f2005-12-23 00:55:09 +00004890 case 0x2B: // lhau (Load HW Alg, Update, PPC32 p446)
cerion76de5cf2005-11-18 18:25:12 +00004891 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004892 vex_printf("dis_int_load(ppc)(lhau,rA_addr|rD_addr)\n");
cerioncb14e732005-09-09 16:38:19 +00004893 return False;
4894 }
ceriond953ebb2005-11-29 13:27:20 +00004895 DIP("lhau r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004896 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004897 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
ceriond953ebb2005-11-29 13:27:20 +00004898 putIReg( rA_addr, mkexpr(EA) );
cerioncb14e732005-09-09 16:38:19 +00004899 break;
cerionb85e8bb2005-02-16 08:54:33 +00004900
cerione9d361a2005-03-04 17:35:29 +00004901 case 0x28: // lhz (Load HW & Zero, PPC32 p450)
ceriond953ebb2005-11-29 13:27:20 +00004902 DIP("lhz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004903 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004904 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
cerionb85e8bb2005-02-16 08:54:33 +00004905 break;
4906
cerion5b2325f2005-12-23 00:55:09 +00004907 case 0x29: // lhzu (Load HW & and Zero, Update, PPC32 p451)
cerion76de5cf2005-11-18 18:25:12 +00004908 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004909 vex_printf("dis_int_load(ppc)(lhzu,rA_addr|rD_addr)\n");
sewardj0e2cc672005-07-29 21:58:51 +00004910 return False;
4911 }
ceriond953ebb2005-11-29 13:27:20 +00004912 DIP("lhzu r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004913 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004914 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
ceriond953ebb2005-11-29 13:27:20 +00004915 putIReg( rA_addr, mkexpr(EA) );
sewardj0e2cc672005-07-29 21:58:51 +00004916 break;
cerion645c9302005-01-31 10:09:59 +00004917
cerione9d361a2005-03-04 17:35:29 +00004918 case 0x20: // lwz (Load W & Zero, PPC32 p460)
ceriond953ebb2005-11-29 13:27:20 +00004919 DIP("lwz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004920 val = load(Ity_I32, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004921 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
cerionb85e8bb2005-02-16 08:54:33 +00004922 break;
4923
cerion5b2325f2005-12-23 00:55:09 +00004924 case 0x21: // lwzu (Load W & Zero, Update, PPC32 p461))
cerion76de5cf2005-11-18 18:25:12 +00004925 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004926 vex_printf("dis_int_load(ppc)(lwzu,rA_addr|rD_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004927 return False;
4928 }
ceriond953ebb2005-11-29 13:27:20 +00004929 DIP("lwzu r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004930 val = load(Ity_I32, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004931 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
ceriond953ebb2005-11-29 13:27:20 +00004932 putIReg( rA_addr, mkexpr(EA) );
cerionb85e8bb2005-02-16 08:54:33 +00004933 break;
4934
4935 /* X Form */
4936 case 0x1F:
4937 if (b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00004938 vex_printf("dis_int_load(ppc)(Ox1F,b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004939 return False;
4940 }
cerion645c9302005-01-31 10:09:59 +00004941
cerionb85e8bb2005-02-16 08:54:33 +00004942 switch (opc2) {
cerion5b2325f2005-12-23 00:55:09 +00004943 case 0x077: // lbzux (Load B & Zero, Update Indexed, PPC32 p435)
ceriond953ebb2005-11-29 13:27:20 +00004944 DIP("lbzux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
cerion76de5cf2005-11-18 18:25:12 +00004945 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004946 vex_printf("dis_int_load(ppc)(lwzux,rA_addr|rD_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004947 return False;
4948 }
carll1f5fe1f2014-08-07 23:25:23 +00004949 val = load(Ity_I8, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004950 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
ceriond953ebb2005-11-29 13:27:20 +00004951 putIReg( rA_addr, mkexpr(EA) );
cerionb85e8bb2005-02-16 08:54:33 +00004952 break;
4953
cerion5b2325f2005-12-23 00:55:09 +00004954 case 0x057: // lbzx (Load B & Zero, Indexed, PPC32 p436)
ceriond953ebb2005-11-29 13:27:20 +00004955 DIP("lbzx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004956 val = load(Ity_I8, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004957 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
cerionb85e8bb2005-02-16 08:54:33 +00004958 break;
4959
cerion5b2325f2005-12-23 00:55:09 +00004960 case 0x177: // lhaux (Load HW Alg, Update Indexed, PPC32 p447)
cerion76de5cf2005-11-18 18:25:12 +00004961 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004962 vex_printf("dis_int_load(ppc)(lhaux,rA_addr|rD_addr)\n");
cerioncb14e732005-09-09 16:38:19 +00004963 return False;
4964 }
ceriond953ebb2005-11-29 13:27:20 +00004965 DIP("lhaux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004966 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004967 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
ceriond953ebb2005-11-29 13:27:20 +00004968 putIReg( rA_addr, mkexpr(EA) );
cerioncb14e732005-09-09 16:38:19 +00004969 break;
cerionb85e8bb2005-02-16 08:54:33 +00004970
cerion5b2325f2005-12-23 00:55:09 +00004971 case 0x157: // lhax (Load HW Alg, Indexed, PPC32 p448)
ceriond953ebb2005-11-29 13:27:20 +00004972 DIP("lhax r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004973 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004974 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
cerionb85e8bb2005-02-16 08:54:33 +00004975 break;
4976
cerion5b2325f2005-12-23 00:55:09 +00004977 case 0x137: // lhzux (Load HW & Zero, Update Indexed, PPC32 p452)
cerion76de5cf2005-11-18 18:25:12 +00004978 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004979 vex_printf("dis_int_load(ppc)(lhzux,rA_addr|rD_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004980 return False;
4981 }
ceriond953ebb2005-11-29 13:27:20 +00004982 DIP("lhzux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004983 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004984 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
ceriond953ebb2005-11-29 13:27:20 +00004985 putIReg( rA_addr, mkexpr(EA) );
cerionb85e8bb2005-02-16 08:54:33 +00004986 break;
4987
cerion5b2325f2005-12-23 00:55:09 +00004988 case 0x117: // lhzx (Load HW & Zero, Indexed, PPC32 p453)
ceriond953ebb2005-11-29 13:27:20 +00004989 DIP("lhzx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004990 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004991 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
cerionb85e8bb2005-02-16 08:54:33 +00004992 break;
cerion44997f22005-01-31 18:45:59 +00004993
cerion5b2325f2005-12-23 00:55:09 +00004994 case 0x037: // lwzux (Load W & Zero, Update Indexed, PPC32 p462)
cerion76de5cf2005-11-18 18:25:12 +00004995 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004996 vex_printf("dis_int_load(ppc)(lwzux,rA_addr|rD_addr)\n");
sewardj7787af42005-08-04 18:32:19 +00004997 return False;
4998 }
ceriond953ebb2005-11-29 13:27:20 +00004999 DIP("lwzux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005000 val = load(Ity_I32, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00005001 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
ceriond953ebb2005-11-29 13:27:20 +00005002 putIReg( rA_addr, mkexpr(EA) );
sewardj7787af42005-08-04 18:32:19 +00005003 break;
cerionb85e8bb2005-02-16 08:54:33 +00005004
cerion5b2325f2005-12-23 00:55:09 +00005005 case 0x017: // lwzx (Load W & Zero, Indexed, PPC32 p463)
ceriond953ebb2005-11-29 13:27:20 +00005006 DIP("lwzx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005007 val = load(Ity_I32, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00005008 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
cerionb85e8bb2005-02-16 08:54:33 +00005009 break;
cerion44997f22005-01-31 18:45:59 +00005010
cerionf0de28c2005-12-13 20:21:11 +00005011
5012 /* 64bit Loads */
cerion5b2325f2005-12-23 00:55:09 +00005013 case 0x035: // ldux (Load DWord, Update Indexed, PPC64 p475)
cerionf0de28c2005-12-13 20:21:11 +00005014 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00005015 vex_printf("dis_int_load(ppc)(ldux,rA_addr|rD_addr)\n");
cerionf0de28c2005-12-13 20:21:11 +00005016 return False;
5017 }
5018 DIP("ldux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005019 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
cerionf0de28c2005-12-13 20:21:11 +00005020 putIReg( rA_addr, mkexpr(EA) );
5021 break;
5022
cerion5b2325f2005-12-23 00:55:09 +00005023 case 0x015: // ldx (Load DWord, Indexed, PPC64 p476)
cerionf0de28c2005-12-13 20:21:11 +00005024 DIP("ldx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005025 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
cerionf0de28c2005-12-13 20:21:11 +00005026 break;
5027
cerion5b2325f2005-12-23 00:55:09 +00005028 case 0x175: // lwaux (Load W Alg, Update Indexed, PPC64 p501)
cerionf0de28c2005-12-13 20:21:11 +00005029 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00005030 vex_printf("dis_int_load(ppc)(lwaux,rA_addr|rD_addr)\n");
cerionf0de28c2005-12-13 20:21:11 +00005031 return False;
5032 }
5033 DIP("lwaux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
cerion5b2325f2005-12-23 00:55:09 +00005034 putIReg( rD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00005035 unop(Iop_32Sto64, load(Ity_I32, mkexpr(EA))) );
cerionf0de28c2005-12-13 20:21:11 +00005036 putIReg( rA_addr, mkexpr(EA) );
5037 break;
5038
cerion5b2325f2005-12-23 00:55:09 +00005039 case 0x155: // lwax (Load W Alg, Indexed, PPC64 p502)
cerionf0de28c2005-12-13 20:21:11 +00005040 DIP("lwax r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
cerion5b2325f2005-12-23 00:55:09 +00005041 putIReg( rD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00005042 unop(Iop_32Sto64, load(Ity_I32, mkexpr(EA))) );
cerionf0de28c2005-12-13 20:21:11 +00005043 break;
5044
cerionb85e8bb2005-02-16 08:54:33 +00005045 default:
cerion5b2325f2005-12-23 00:55:09 +00005046 vex_printf("dis_int_load(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005047 return False;
5048 }
5049 break;
cerionf0de28c2005-12-13 20:21:11 +00005050
sewardj6d834222007-03-09 14:24:38 +00005051 /* DS Form - 64bit Loads. In each case EA will have been formed
5052 with the lowest 2 bits masked off the immediate offset. */
cerionf0de28c2005-12-13 20:21:11 +00005053 case 0x3A:
sewardj6d834222007-03-09 14:24:38 +00005054 switch ((b1<<1) | b0) {
cerion5b2325f2005-12-23 00:55:09 +00005055 case 0x0: // ld (Load DWord, PPC64 p472)
cerionf0de28c2005-12-13 20:21:11 +00005056 DIP("ld r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005057 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
cerionf0de28c2005-12-13 20:21:11 +00005058 break;
5059
cerion5b2325f2005-12-23 00:55:09 +00005060 case 0x1: // ldu (Load DWord, Update, PPC64 p474)
cerionf0de28c2005-12-13 20:21:11 +00005061 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00005062 vex_printf("dis_int_load(ppc)(ldu,rA_addr|rD_addr)\n");
cerionf0de28c2005-12-13 20:21:11 +00005063 return False;
5064 }
5065 DIP("ldu r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005066 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
cerionf0de28c2005-12-13 20:21:11 +00005067 putIReg( rA_addr, mkexpr(EA) );
5068 break;
5069
cerion5b2325f2005-12-23 00:55:09 +00005070 case 0x2: // lwa (Load Word Alg, PPC64 p499)
cerionf0de28c2005-12-13 20:21:11 +00005071 DIP("lwa r%u,%d(r%u)\n", rD_addr, simm16, rA_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 break;
5075
5076 default:
cerion5b2325f2005-12-23 00:55:09 +00005077 vex_printf("dis_int_load(ppc)(0x3A, opc2)\n");
cerionf0de28c2005-12-13 20:21:11 +00005078 return False;
5079 }
5080 break;
5081
carll78850ae2013-09-10 18:46:40 +00005082 case 0x38: {
5083 IRTemp high = newTemp(ty);
5084 IRTemp low = newTemp(ty);
5085 /* DQ Form - 128bit Loads. Lowest bits [1:0] are the PT field. */
5086 DIP("lq r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
5087 /* NOTE: there are some changes to XER[41:42] that have not been
5088 * implemented.
5089 */
5090 // trap if EA misaligned on 16 byte address
5091 if (mode64) {
carll1f5fe1f2014-08-07 23:25:23 +00005092 assign(high, load(ty, mkexpr( EA ) ) );
5093 assign(low, load(ty, binop( Iop_Add64,
5094 mkexpr( EA ),
5095 mkU64( 8 ) ) ) );
carll78850ae2013-09-10 18:46:40 +00005096 } else {
carll1f5fe1f2014-08-07 23:25:23 +00005097 assign(high, load(ty, binop( Iop_Add32,
5098 mkexpr( EA ),
5099 mkU32( 4 ) ) ) );
5100 assign(low, load(ty, binop( Iop_Add32,
5101 mkexpr( EA ),
5102 mkU32( 12 ) ) ) );
carll78850ae2013-09-10 18:46:40 +00005103 }
5104 gen_SIGBUS_if_misaligned( EA, 16 );
5105 putIReg( rD_addr, mkexpr( high) );
5106 putIReg( rD_addr+1, mkexpr( low) );
5107 break;
5108 }
cerionb85e8bb2005-02-16 08:54:33 +00005109 default:
cerion5b2325f2005-12-23 00:55:09 +00005110 vex_printf("dis_int_load(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005111 return False;
5112 }
5113 return True;
cerion7aa4bbc2005-01-29 09:32:07 +00005114}
5115
5116
5117
cerion3d870a32005-03-18 12:23:33 +00005118/*
5119 Integer Store Instructions
5120*/
sewardjdd40fdf2006-12-24 02:20:24 +00005121static Bool dis_int_store ( UInt theInstr, VexAbiInfo* vbi )
ceriond23be4e2005-01-31 07:23:07 +00005122{
cerionf0de28c2005-12-13 20:21:11 +00005123 /* D-Form, X-Form, DS-Form */
cerionedf7fc52005-11-18 20:57:41 +00005124 UChar opc1 = ifieldOPC(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00005125 UInt rS_addr = ifieldRegDS(theInstr);
5126 UInt rA_addr = ifieldRegA(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00005127 UInt uimm16 = ifieldUIMM16(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00005128 UInt rB_addr = ifieldRegB(theInstr);
5129 UInt opc2 = ifieldOPClo10(theInstr);
cerionf0de28c2005-12-13 20:21:11 +00005130 UChar b1 = ifieldBIT1(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00005131 UChar b0 = ifieldBIT0(theInstr);
5132
ceriond953ebb2005-11-29 13:27:20 +00005133 Int simm16 = extend_s_16to32(uimm16);
5134 IRType ty = mode64 ? Ity_I64 : Ity_I32;
5135 IRTemp rS = newTemp(ty);
5136 IRTemp rB = newTemp(ty);
5137 IRTemp EA = newTemp(ty);
cerionb85e8bb2005-02-16 08:54:33 +00005138
cerion76de5cf2005-11-18 18:25:12 +00005139 assign( rB, getIReg(rB_addr) );
5140 assign( rS, getIReg(rS_addr) );
cerionb85e8bb2005-02-16 08:54:33 +00005141
cerionf0de28c2005-12-13 20:21:11 +00005142 switch (opc1) {
5143 case 0x1F: // register offset
ceriond953ebb2005-11-29 13:27:20 +00005144 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
cerionf0de28c2005-12-13 20:21:11 +00005145 break;
carll78850ae2013-09-10 18:46:40 +00005146 case 0x3E: // immediate offset: 64bit: std/stdu/stq: mask off
sewardj6d834222007-03-09 14:24:38 +00005147 // lowest 2 bits of immediate before forming EA
cerionf0de28c2005-12-13 20:21:11 +00005148 simm16 = simm16 & 0xFFFFFFFC;
5149 default: // immediate offset
5150 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
5151 break;
ceriond953ebb2005-11-29 13:27:20 +00005152 }
5153
cerionb85e8bb2005-02-16 08:54:33 +00005154 switch (opc1) {
sewardjafe85832005-09-09 10:25:39 +00005155 case 0x26: // stb (Store B, PPC32 p509)
cerion76de5cf2005-11-18 18:25:12 +00005156 DIP("stb r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005157 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
sewardjafe85832005-09-09 10:25:39 +00005158 break;
sewardjb51f0f42005-07-18 11:38:02 +00005159
cerion5b2325f2005-12-23 00:55:09 +00005160 case 0x27: // stbu (Store B, Update, PPC32 p510)
cerion76de5cf2005-11-18 18:25:12 +00005161 if (rA_addr == 0 ) {
cerion5b2325f2005-12-23 00:55:09 +00005162 vex_printf("dis_int_store(ppc)(stbu,rA_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005163 return False;
5164 }
cerion76de5cf2005-11-18 18:25:12 +00005165 DIP("stbu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
ceriond953ebb2005-11-29 13:27:20 +00005166 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005167 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005168 break;
ceriond23be4e2005-01-31 07:23:07 +00005169
cerione9d361a2005-03-04 17:35:29 +00005170 case 0x2C: // sth (Store HW, PPC32 p522)
cerion76de5cf2005-11-18 18:25:12 +00005171 DIP("sth r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005172 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005173 break;
5174
cerion5b2325f2005-12-23 00:55:09 +00005175 case 0x2D: // sthu (Store HW, Update, PPC32 p524)
cerion76de5cf2005-11-18 18:25:12 +00005176 if (rA_addr == 0) {
cerion5b2325f2005-12-23 00:55:09 +00005177 vex_printf("dis_int_store(ppc)(sthu,rA_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005178 return False;
5179 }
cerion76de5cf2005-11-18 18:25:12 +00005180 DIP("sthu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
ceriond953ebb2005-11-29 13:27:20 +00005181 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005182 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005183 break;
ceriond23be4e2005-01-31 07:23:07 +00005184
cerione9d361a2005-03-04 17:35:29 +00005185 case 0x24: // stw (Store W, PPC32 p530)
cerion76de5cf2005-11-18 18:25:12 +00005186 DIP("stw r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005187 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005188 break;
ceriond23be4e2005-01-31 07:23:07 +00005189
cerion5b2325f2005-12-23 00:55:09 +00005190 case 0x25: // stwu (Store W, Update, PPC32 p534)
cerion76de5cf2005-11-18 18:25:12 +00005191 if (rA_addr == 0) {
cerion5b2325f2005-12-23 00:55:09 +00005192 vex_printf("dis_int_store(ppc)(stwu,rA_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005193 return False;
5194 }
cerion76de5cf2005-11-18 18:25:12 +00005195 DIP("stwu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
ceriond953ebb2005-11-29 13:27:20 +00005196 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005197 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005198 break;
5199
cerionf0de28c2005-12-13 20:21:11 +00005200 /* X Form : all these use EA_indexed */
cerionb85e8bb2005-02-16 08:54:33 +00005201 case 0x1F:
5202 if (b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00005203 vex_printf("dis_int_store(ppc)(0x1F,b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005204 return False;
5205 }
cerion44997f22005-01-31 18:45:59 +00005206
cerionb85e8bb2005-02-16 08:54:33 +00005207 switch (opc2) {
cerion5b2325f2005-12-23 00:55:09 +00005208 case 0x0F7: // stbux (Store B, Update Indexed, PPC32 p511)
cerion76de5cf2005-11-18 18:25:12 +00005209 if (rA_addr == 0) {
cerion5b2325f2005-12-23 00:55:09 +00005210 vex_printf("dis_int_store(ppc)(stbux,rA_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005211 return False;
5212 }
cerion76de5cf2005-11-18 18:25:12 +00005213 DIP("stbux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
ceriond953ebb2005-11-29 13:27:20 +00005214 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005215 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005216 break;
5217
cerione9d361a2005-03-04 17:35:29 +00005218 case 0x0D7: // stbx (Store B Indexed, PPC32 p512)
cerion76de5cf2005-11-18 18:25:12 +00005219 DIP("stbx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005220 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005221 break;
5222
cerion5b2325f2005-12-23 00:55:09 +00005223 case 0x1B7: // sthux (Store HW, Update Indexed, PPC32 p525)
cerion76de5cf2005-11-18 18:25:12 +00005224 if (rA_addr == 0) {
cerion5b2325f2005-12-23 00:55:09 +00005225 vex_printf("dis_int_store(ppc)(sthux,rA_addr)\n");
cerioncb14e732005-09-09 16:38:19 +00005226 return False;
5227 }
cerion76de5cf2005-11-18 18:25:12 +00005228 DIP("sthux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
ceriond953ebb2005-11-29 13:27:20 +00005229 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005230 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
cerioncb14e732005-09-09 16:38:19 +00005231 break;
cerionb85e8bb2005-02-16 08:54:33 +00005232
cerione9d361a2005-03-04 17:35:29 +00005233 case 0x197: // sthx (Store HW Indexed, PPC32 p526)
cerion76de5cf2005-11-18 18:25:12 +00005234 DIP("sthx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005235 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005236 break;
5237
cerion5b2325f2005-12-23 00:55:09 +00005238 case 0x0B7: // stwux (Store W, Update Indexed, PPC32 p535)
cerion76de5cf2005-11-18 18:25:12 +00005239 if (rA_addr == 0) {
cerion5b2325f2005-12-23 00:55:09 +00005240 vex_printf("dis_int_store(ppc)(stwux,rA_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005241 return False;
5242 }
cerion76de5cf2005-11-18 18:25:12 +00005243 DIP("stwux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
ceriond953ebb2005-11-29 13:27:20 +00005244 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005245 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005246 break;
cerion44997f22005-01-31 18:45:59 +00005247
cerione9d361a2005-03-04 17:35:29 +00005248 case 0x097: // stwx (Store W Indexed, PPC32 p536)
cerion76de5cf2005-11-18 18:25:12 +00005249 DIP("stwx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005250 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005251 break;
5252
cerionf0de28c2005-12-13 20:21:11 +00005253
5254 /* 64bit Stores */
cerion5b2325f2005-12-23 00:55:09 +00005255 case 0x0B5: // stdux (Store DWord, Update Indexed, PPC64 p584)
cerionf0de28c2005-12-13 20:21:11 +00005256 if (rA_addr == 0) {
cerion5b2325f2005-12-23 00:55:09 +00005257 vex_printf("dis_int_store(ppc)(stdux,rA_addr)\n");
cerionf0de28c2005-12-13 20:21:11 +00005258 return False;
5259 }
5260 DIP("stdux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
5261 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005262 store( mkexpr(EA), mkexpr(rS) );
cerionf0de28c2005-12-13 20:21:11 +00005263 break;
5264
cerion5b2325f2005-12-23 00:55:09 +00005265 case 0x095: // stdx (Store DWord Indexed, PPC64 p585)
cerionf0de28c2005-12-13 20:21:11 +00005266 DIP("stdx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005267 store( mkexpr(EA), mkexpr(rS) );
cerionf0de28c2005-12-13 20:21:11 +00005268 break;
5269
cerionb85e8bb2005-02-16 08:54:33 +00005270 default:
cerion5b2325f2005-12-23 00:55:09 +00005271 vex_printf("dis_int_store(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005272 return False;
5273 }
5274 break;
cerionf0de28c2005-12-13 20:21:11 +00005275
sewardj6d834222007-03-09 14:24:38 +00005276 /* DS Form - 64bit Stores. In each case EA will have been formed
5277 with the lowest 2 bits masked off the immediate offset. */
cerionf0de28c2005-12-13 20:21:11 +00005278 case 0x3E:
sewardj6d834222007-03-09 14:24:38 +00005279 switch ((b1<<1) | b0) {
cerion5b2325f2005-12-23 00:55:09 +00005280 case 0x0: // std (Store DWord, PPC64 p580)
carll0c74bb52013-08-12 18:01:40 +00005281 if (!mode64)
5282 return False;
5283
cerionf0de28c2005-12-13 20:21:11 +00005284 DIP("std r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005285 store( mkexpr(EA), mkexpr(rS) );
cerionf0de28c2005-12-13 20:21:11 +00005286 break;
5287
cerion5b2325f2005-12-23 00:55:09 +00005288 case 0x1: // stdu (Store DWord, Update, PPC64 p583)
carll0c74bb52013-08-12 18:01:40 +00005289 if (!mode64)
5290 return False;
5291
cerionf0de28c2005-12-13 20:21:11 +00005292 DIP("stdu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
5293 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005294 store( mkexpr(EA), mkexpr(rS) );
cerionf0de28c2005-12-13 20:21:11 +00005295 break;
5296
carll78850ae2013-09-10 18:46:40 +00005297 case 0x2: { // stq (Store QuadWord, Update, PPC64 p583)
5298 IRTemp EA_hi = newTemp(ty);
5299 IRTemp EA_lo = newTemp(ty);
5300 DIP("stq r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
5301
5302 if (mode64) {
5303 /* upper 64-bits */
5304 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
5305
5306 /* lower 64-bits */
5307 assign( EA_lo, ea_rAor0_simm( rA_addr, simm16+8 ) );
5308 } else {
5309 /* upper half of upper 64-bits */
5310 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16+4 ) );
5311
5312 /* lower half of upper 64-bits */
5313 assign( EA_lo, ea_rAor0_simm( rA_addr, simm16+12 ) );
5314 }
5315 putIReg( rA_addr, mkexpr(EA_hi) );
carll1f5fe1f2014-08-07 23:25:23 +00005316 store( mkexpr(EA_hi), mkexpr(rS) );
carll78850ae2013-09-10 18:46:40 +00005317 putIReg( rA_addr, mkexpr( EA_lo) );
carll1f5fe1f2014-08-07 23:25:23 +00005318 store( mkexpr(EA_lo), getIReg( rS_addr+1 ) );
carll78850ae2013-09-10 18:46:40 +00005319 break;
5320 }
cerionf0de28c2005-12-13 20:21:11 +00005321 default:
cerion5b2325f2005-12-23 00:55:09 +00005322 vex_printf("dis_int_load(ppc)(0x3A, opc2)\n");
cerionf0de28c2005-12-13 20:21:11 +00005323 return False;
5324 }
5325 break;
5326
cerionb85e8bb2005-02-16 08:54:33 +00005327 default:
cerion5b2325f2005-12-23 00:55:09 +00005328 vex_printf("dis_int_store(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005329 return False;
5330 }
5331 return True;
ceriond23be4e2005-01-31 07:23:07 +00005332}
5333
5334
5335
sewardj7787af42005-08-04 18:32:19 +00005336/*
5337 Integer Load/Store Multiple Instructions
5338*/
5339static Bool dis_int_ldst_mult ( UInt theInstr )
5340{
5341 /* D-Form */
cerion76de5cf2005-11-18 18:25:12 +00005342 UChar opc1 = ifieldOPC(theInstr);
5343 UChar rD_addr = ifieldRegDS(theInstr);
5344 UChar rS_addr = rD_addr;
5345 UChar rA_addr = ifieldRegA(theInstr);
cerion2831b002005-11-30 19:55:22 +00005346 UInt uimm16 = ifieldUIMM16(theInstr);
cerionedf7fc52005-11-18 20:57:41 +00005347
ceriond953ebb2005-11-29 13:27:20 +00005348 Int simm16 = extend_s_16to32(uimm16);
5349 IRType ty = mode64 ? Ity_I64 : Ity_I32;
carll9fcbb9a2014-01-24 16:42:26 +00005350 IROp mkAdd = mode64 ? Iop_Add64 : Iop_Add32;
ceriond953ebb2005-11-29 13:27:20 +00005351 IRTemp EA = newTemp(ty);
5352 UInt r = 0;
5353 UInt ea_off = 0;
sewardj7787af42005-08-04 18:32:19 +00005354 IRExpr* irx_addr;
cerionedf7fc52005-11-18 20:57:41 +00005355
ceriond953ebb2005-11-29 13:27:20 +00005356 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
5357
sewardj7787af42005-08-04 18:32:19 +00005358 switch (opc1) {
ceriond953ebb2005-11-29 13:27:20 +00005359 case 0x2E: // lmw (Load Multiple Word, PPC32 p454)
5360 if (rA_addr >= rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00005361 vex_printf("dis_int_ldst_mult(ppc)(lmw,rA_addr)\n");
sewardj7787af42005-08-04 18:32:19 +00005362 return False;
ceriond953ebb2005-11-29 13:27:20 +00005363 }
5364 DIP("lmw r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
5365 for (r = rD_addr; r <= 31; r++) {
carll9fcbb9a2014-01-24 16:42:26 +00005366 irx_addr = binop(mkAdd, mkexpr(EA), mode64 ? mkU64(ea_off) : mkU32(ea_off));
carll1f5fe1f2014-08-07 23:25:23 +00005367 putIReg( r, mkWidenFrom32(ty, load(Ity_I32, irx_addr ),
sewardje9d8a262009-07-01 08:06:34 +00005368 False) );
ceriond953ebb2005-11-29 13:27:20 +00005369 ea_off += 4;
5370 }
5371 break;
5372
5373 case 0x2F: // stmw (Store Multiple Word, PPC32 p527)
5374 DIP("stmw r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
5375 for (r = rS_addr; r <= 31; r++) {
carll9fcbb9a2014-01-24 16:42:26 +00005376 irx_addr = binop(mkAdd, mkexpr(EA), mode64 ? mkU64(ea_off) : mkU32(ea_off));
carll1f5fe1f2014-08-07 23:25:23 +00005377 store( irx_addr, mkNarrowTo32(ty, getIReg(r)) );
ceriond953ebb2005-11-29 13:27:20 +00005378 ea_off += 4;
5379 }
5380 break;
5381
5382 default:
cerion5b2325f2005-12-23 00:55:09 +00005383 vex_printf("dis_int_ldst_mult(ppc)(opc1)\n");
ceriond953ebb2005-11-29 13:27:20 +00005384 return False;
sewardj7787af42005-08-04 18:32:19 +00005385 }
5386 return True;
5387}
5388
5389
5390
sewardj87e651f2005-09-09 08:31:18 +00005391/*
5392 Integer Load/Store String Instructions
5393*/
5394static
5395void generate_lsw_sequence ( IRTemp tNBytes, // # bytes, :: Ity_I32
5396 IRTemp EA, // EA
5397 Int rD, // first dst register
ceriond953ebb2005-11-29 13:27:20 +00005398 Int maxBytes ) // 32 or 128
sewardj87e651f2005-09-09 08:31:18 +00005399{
5400 Int i, shift = 24;
5401 IRExpr* e_nbytes = mkexpr(tNBytes);
ceriond953ebb2005-11-29 13:27:20 +00005402 IRExpr* e_EA = mkexpr(EA);
5403 IRType ty = mode64 ? Ity_I64 : Ity_I32;
sewardj87e651f2005-09-09 08:31:18 +00005404
sewardj5876fa12005-09-09 09:35:29 +00005405 vassert(rD >= 0 && rD < 32);
sewardj87e651f2005-09-09 08:31:18 +00005406 rD--; if (rD < 0) rD = 31;
5407
5408 for (i = 0; i < maxBytes; i++) {
sewardj87e651f2005-09-09 08:31:18 +00005409 /* if (nBytes < (i+1)) goto NIA; */
5410 stmt( IRStmt_Exit( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
5411 Ijk_Boring,
sewardj3dee8492012-04-20 00:13:28 +00005412 mkSzConst( ty, nextInsnAddr()), OFFB_CIA ));
sewardj87e651f2005-09-09 08:31:18 +00005413 /* when crossing into a new dest register, set it to zero. */
5414 if ((i % 4) == 0) {
5415 rD++; if (rD == 32) rD = 0;
cerion2831b002005-11-30 19:55:22 +00005416 putIReg(rD, mkSzImm(ty, 0));
sewardj87e651f2005-09-09 08:31:18 +00005417 shift = 24;
5418 }
5419 /* rD |= (8Uto32(*(EA+i))) << shift */
5420 vassert(shift == 0 || shift == 8 || shift == 16 || shift == 24);
sewardj2ef8a372006-01-28 17:07:19 +00005421 putIReg(
5422 rD,
sewardje9d8a262009-07-01 08:06:34 +00005423 mkWidenFrom32(
sewardj2ef8a372006-01-28 17:07:19 +00005424 ty,
5425 binop(
5426 Iop_Or32,
sewardje9d8a262009-07-01 08:06:34 +00005427 mkNarrowTo32(ty, getIReg(rD)),
sewardj2ef8a372006-01-28 17:07:19 +00005428 binop(
5429 Iop_Shl32,
5430 unop(
5431 Iop_8Uto32,
carll1f5fe1f2014-08-07 23:25:23 +00005432 load( Ity_I8,
5433 binop( mkSzOp(ty,Iop_Add8),
5434 e_EA, mkSzImm(ty,i)))
sewardj2ef8a372006-01-28 17:07:19 +00005435 ),
5436 mkU8(toUChar(shift))
5437 )
5438 ),
5439 /*Signed*/False
5440 )
5441 );
sewardj87e651f2005-09-09 08:31:18 +00005442 shift -= 8;
5443 }
5444}
5445
sewardj5876fa12005-09-09 09:35:29 +00005446static
5447void generate_stsw_sequence ( IRTemp tNBytes, // # bytes, :: Ity_I32
5448 IRTemp EA, // EA
5449 Int rS, // first src register
ceriond953ebb2005-11-29 13:27:20 +00005450 Int maxBytes ) // 32 or 128
sewardj5876fa12005-09-09 09:35:29 +00005451{
5452 Int i, shift = 24;
5453 IRExpr* e_nbytes = mkexpr(tNBytes);
ceriond953ebb2005-11-29 13:27:20 +00005454 IRExpr* e_EA = mkexpr(EA);
5455 IRType ty = mode64 ? Ity_I64 : Ity_I32;
sewardj5876fa12005-09-09 09:35:29 +00005456
5457 vassert(rS >= 0 && rS < 32);
5458 rS--; if (rS < 0) rS = 31;
5459
5460 for (i = 0; i < maxBytes; i++) {
5461 /* if (nBytes < (i+1)) goto NIA; */
5462 stmt( IRStmt_Exit( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
5463 Ijk_Boring,
sewardj3dee8492012-04-20 00:13:28 +00005464 mkSzConst( ty, nextInsnAddr() ), OFFB_CIA ));
sewardj5876fa12005-09-09 09:35:29 +00005465 /* check for crossing into a new src register. */
5466 if ((i % 4) == 0) {
5467 rS++; if (rS == 32) rS = 0;
5468 shift = 24;
5469 }
5470 /* *(EA+i) = 32to8(rS >> shift) */
5471 vassert(shift == 0 || shift == 8 || shift == 16 || shift == 24);
carll1f5fe1f2014-08-07 23:25:23 +00005472 store(
5473 binop( mkSzOp(ty,Iop_Add8), e_EA, mkSzImm(ty,i)),
5474 unop( Iop_32to8,
5475 binop( Iop_Shr32,
5476 mkNarrowTo32( ty, getIReg(rS) ),
5477 mkU8( toUChar(shift) )))
sewardj5876fa12005-09-09 09:35:29 +00005478 );
5479 shift -= 8;
5480 }
5481}
5482
sewardj87e651f2005-09-09 08:31:18 +00005483static Bool dis_int_ldst_str ( UInt theInstr, /*OUT*/Bool* stopHere )
5484{
5485 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00005486 UChar opc1 = ifieldOPC(theInstr);
5487 UChar rD_addr = ifieldRegDS(theInstr);
5488 UChar rS_addr = rD_addr;
5489 UChar rA_addr = ifieldRegA(theInstr);
5490 UChar rB_addr = ifieldRegB(theInstr);
5491 UChar NumBytes = rB_addr;
5492 UInt opc2 = ifieldOPClo10(theInstr);
5493 UChar b0 = ifieldBIT0(theInstr);
cerionedf7fc52005-11-18 20:57:41 +00005494
ceriond953ebb2005-11-29 13:27:20 +00005495 IRType ty = mode64 ? Ity_I64 : Ity_I32;
5496 IRTemp t_EA = newTemp(ty);
sewardj87e651f2005-09-09 08:31:18 +00005497 IRTemp t_nbytes = IRTemp_INVALID;
cerionedf7fc52005-11-18 20:57:41 +00005498
sewardj87e651f2005-09-09 08:31:18 +00005499 *stopHere = False;
cerionedf7fc52005-11-18 20:57:41 +00005500
sewardj87e651f2005-09-09 08:31:18 +00005501 if (opc1 != 0x1F || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00005502 vex_printf("dis_int_ldst_str(ppc)(opc1)\n");
sewardj87e651f2005-09-09 08:31:18 +00005503 return False;
5504 }
5505
5506 switch (opc2) {
5507 case 0x255: // lswi (Load String Word Immediate, PPC32 p455)
5508 /* NB: does not reject the case where RA is in the range of
5509 registers to be loaded. It should. */
ceriond953ebb2005-11-29 13:27:20 +00005510 DIP("lswi r%u,r%u,%d\n", rD_addr, rA_addr, NumBytes);
5511 assign( t_EA, ea_rAor0(rA_addr) );
sewardj2ef8a372006-01-28 17:07:19 +00005512 if (NumBytes == 8 && !mode64) {
sewardj87e651f2005-09-09 08:31:18 +00005513 /* Special case hack */
cerion76de5cf2005-11-18 18:25:12 +00005514 /* rD = Mem[EA]; (rD+1)%32 = Mem[EA+4] */
5515 putIReg( rD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00005516 load(Ity_I32, mkexpr(t_EA)) );
cerion76de5cf2005-11-18 18:25:12 +00005517 putIReg( (rD_addr+1) % 32,
carll1f5fe1f2014-08-07 23:25:23 +00005518 load(Ity_I32,
5519 binop(Iop_Add32, mkexpr(t_EA), mkU32(4))) );
sewardj87e651f2005-09-09 08:31:18 +00005520 } else {
5521 t_nbytes = newTemp(Ity_I32);
cerion76de5cf2005-11-18 18:25:12 +00005522 assign( t_nbytes, mkU32(NumBytes==0 ? 32 : NumBytes) );
ceriond953ebb2005-11-29 13:27:20 +00005523 generate_lsw_sequence( t_nbytes, t_EA, rD_addr, 32 );
sewardj87e651f2005-09-09 08:31:18 +00005524 *stopHere = True;
5525 }
5526 return True;
5527
5528 case 0x215: // lswx (Load String Word Indexed, PPC32 p456)
5529 /* NB: does not reject the case where RA is in the range of
5530 registers to be loaded. It should. Although considering
5531 that that can only be detected at run time, it's not easy to
5532 do so. */
cerion76de5cf2005-11-18 18:25:12 +00005533 if (rD_addr == rA_addr || rD_addr == rB_addr)
sewardj87e651f2005-09-09 08:31:18 +00005534 return False;
cerion76de5cf2005-11-18 18:25:12 +00005535 if (rD_addr == 0 && rA_addr == 0)
sewardj87e651f2005-09-09 08:31:18 +00005536 return False;
ceriond953ebb2005-11-29 13:27:20 +00005537 DIP("lswx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
sewardj87e651f2005-09-09 08:31:18 +00005538 t_nbytes = newTemp(Ity_I32);
ceriond953ebb2005-11-29 13:27:20 +00005539 assign( t_EA, ea_rAor0_idxd(rA_addr,rB_addr) );
cerionedf7fc52005-11-18 20:57:41 +00005540 assign( t_nbytes, unop( Iop_8Uto32, getXER_BC() ) );
ceriond953ebb2005-11-29 13:27:20 +00005541 generate_lsw_sequence( t_nbytes, t_EA, rD_addr, 128 );
sewardj87e651f2005-09-09 08:31:18 +00005542 *stopHere = True;
5543 return True;
5544
sewardj5876fa12005-09-09 09:35:29 +00005545 case 0x2D5: // stswi (Store String Word Immediate, PPC32 p528)
ceriond953ebb2005-11-29 13:27:20 +00005546 DIP("stswi r%u,r%u,%d\n", rS_addr, rA_addr, NumBytes);
5547 assign( t_EA, ea_rAor0(rA_addr) );
sewardj2ef8a372006-01-28 17:07:19 +00005548 if (NumBytes == 8 && !mode64) {
sewardj5876fa12005-09-09 09:35:29 +00005549 /* Special case hack */
cerion76de5cf2005-11-18 18:25:12 +00005550 /* Mem[EA] = rD; Mem[EA+4] = (rD+1)%32 */
carll1f5fe1f2014-08-07 23:25:23 +00005551 store( mkexpr(t_EA),
5552 getIReg(rD_addr) );
5553 store( binop(Iop_Add32, mkexpr(t_EA), mkU32(4)),
5554 getIReg((rD_addr+1) % 32) );
sewardj5876fa12005-09-09 09:35:29 +00005555 } else {
5556 t_nbytes = newTemp(Ity_I32);
cerion76de5cf2005-11-18 18:25:12 +00005557 assign( t_nbytes, mkU32(NumBytes==0 ? 32 : NumBytes) );
ceriond953ebb2005-11-29 13:27:20 +00005558 generate_stsw_sequence( t_nbytes, t_EA, rD_addr, 32 );
sewardj5876fa12005-09-09 09:35:29 +00005559 *stopHere = True;
5560 }
5561 return True;
5562
sewardj5876fa12005-09-09 09:35:29 +00005563 case 0x295: // stswx (Store String Word Indexed, PPC32 p529)
ceriond953ebb2005-11-29 13:27:20 +00005564 DIP("stswx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
sewardj5876fa12005-09-09 09:35:29 +00005565 t_nbytes = newTemp(Ity_I32);
ceriond953ebb2005-11-29 13:27:20 +00005566 assign( t_EA, ea_rAor0_idxd(rA_addr,rB_addr) );
cerionedf7fc52005-11-18 20:57:41 +00005567 assign( t_nbytes, unop( Iop_8Uto32, getXER_BC() ) );
ceriond953ebb2005-11-29 13:27:20 +00005568 generate_stsw_sequence( t_nbytes, t_EA, rS_addr, 128 );
sewardj5876fa12005-09-09 09:35:29 +00005569 *stopHere = True;
5570 return True;
sewardj87e651f2005-09-09 08:31:18 +00005571
5572 default:
cerion5b2325f2005-12-23 00:55:09 +00005573 vex_printf("dis_int_ldst_str(ppc)(opc2)\n");
sewardj87e651f2005-09-09 08:31:18 +00005574 return False;
5575 }
5576 return True;
5577}
5578
cerion094d1392005-06-20 13:45:57 +00005579
sewardjb51f0f42005-07-18 11:38:02 +00005580/* ------------------------------------------------------------------
5581 Integer Branch Instructions
5582 ------------------------------------------------------------------ */
cerion645c9302005-01-31 10:09:59 +00005583
cerion45552a92005-02-03 18:20:22 +00005584/*
5585 Branch helper function
5586 ok = BO[2] | ((CTR[0] != 0) ^ BO[1])
sewardjb51f0f42005-07-18 11:38:02 +00005587 Returns an I32 which is 0x00000000 if the ctr condition failed
5588 and 0xFFFFFFFF otherwise.
cerion45552a92005-02-03 18:20:22 +00005589*/
sewardjb51f0f42005-07-18 11:38:02 +00005590static IRExpr* /* :: Ity_I32 */ branch_ctr_ok( UInt BO )
cerion45552a92005-02-03 18:20:22 +00005591{
ceriond953ebb2005-11-29 13:27:20 +00005592 IRType ty = mode64 ? Ity_I64 : Ity_I32;
sewardjb51f0f42005-07-18 11:38:02 +00005593 IRTemp ok = newTemp(Ity_I32);
cerioned623db2005-06-20 12:42:04 +00005594
cerionf0de28c2005-12-13 20:21:11 +00005595 if ((BO >> 2) & 1) { // independent of ctr
sewardjb51f0f42005-07-18 11:38:02 +00005596 assign( ok, mkU32(0xFFFFFFFF) );
cerionb85e8bb2005-02-16 08:54:33 +00005597 } else {
cerionf0de28c2005-12-13 20:21:11 +00005598 if ((BO >> 1) & 1) { // ctr == 0 ?
ceriond953ebb2005-11-29 13:27:20 +00005599 assign( ok, unop( Iop_1Sto32,
cerion4e2c2b32006-01-02 13:35:51 +00005600 binop( mkSzOp(ty, Iop_CmpEQ8),
5601 getGST( PPC_GST_CTR ),
5602 mkSzImm(ty,0))) );
cerionf0de28c2005-12-13 20:21:11 +00005603 } else { // ctr != 0 ?
sewardjb51f0f42005-07-18 11:38:02 +00005604 assign( ok, unop( Iop_1Sto32,
cerion4e2c2b32006-01-02 13:35:51 +00005605 binop( mkSzOp(ty, Iop_CmpNE8),
5606 getGST( PPC_GST_CTR ),
5607 mkSzImm(ty,0))) );
cerionb85e8bb2005-02-16 08:54:33 +00005608 }
5609 }
5610 return mkexpr(ok);
cerion45552a92005-02-03 18:20:22 +00005611}
5612
sewardjb51f0f42005-07-18 11:38:02 +00005613
cerion45552a92005-02-03 18:20:22 +00005614/*
sewardjb51f0f42005-07-18 11:38:02 +00005615 Branch helper function cond_ok = BO[4] | (CR[BI] == BO[3])
5616 Returns an I32 which is either 0 if the condition failed or
5617 some arbitrary nonzero value otherwise. */
5618
5619static IRExpr* /* :: Ity_I32 */ branch_cond_ok( UInt BO, UInt BI )
cerion45552a92005-02-03 18:20:22 +00005620{
sewardjb51f0f42005-07-18 11:38:02 +00005621 Int where;
5622 IRTemp res = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00005623 IRTemp cr_bi = newTemp(Ity_I32);
5624
sewardjb51f0f42005-07-18 11:38:02 +00005625 if ((BO >> 4) & 1) {
5626 assign( res, mkU32(1) );
cerionb85e8bb2005-02-16 08:54:33 +00005627 } else {
sewardjb51f0f42005-07-18 11:38:02 +00005628 // ok = (CR[BI] == BO[3]) Note, the following relies on
5629 // getCRbit_anywhere returning a value which
5630 // is either zero or has exactly 1 bit set.
5631 assign( cr_bi, getCRbit_anywhere( BI, &where ) );
cerione9d361a2005-03-04 17:35:29 +00005632
5633 if ((BO >> 3) & 1) {
sewardjb51f0f42005-07-18 11:38:02 +00005634 /* We can use cr_bi as-is. */
5635 assign( res, mkexpr(cr_bi) );
cerione9d361a2005-03-04 17:35:29 +00005636 } else {
sewardjb51f0f42005-07-18 11:38:02 +00005637 /* We have to invert the sense of the information held in
5638 cr_bi. For that we need to know which bit
cerion76de5cf2005-11-18 18:25:12 +00005639 getCRbit_anywhere regards as significant. */
cerion5b2325f2005-12-23 00:55:09 +00005640 assign( res, binop(Iop_Xor32, mkexpr(cr_bi),
5641 mkU32(1<<where)) );
cerionb85e8bb2005-02-16 08:54:33 +00005642 }
5643 }
sewardjb51f0f42005-07-18 11:38:02 +00005644 return mkexpr(res);
cerion45552a92005-02-03 18:20:22 +00005645}
5646
5647
cerion3d870a32005-03-18 12:23:33 +00005648/*
5649 Integer Branch Instructions
5650*/
sewardj9d540e52005-10-08 11:28:16 +00005651static Bool dis_branch ( UInt theInstr,
sewardjdd40fdf2006-12-24 02:20:24 +00005652 VexAbiInfo* vbi,
sewardj9d540e52005-10-08 11:28:16 +00005653 /*OUT*/DisResult* dres,
sewardjc716aea2006-01-17 01:48:46 +00005654 Bool (*resteerOkFn)(void*,Addr64),
5655 void* callback_opaque )
cerion91ad5362005-01-27 23:02:41 +00005656{
ceriond953ebb2005-11-29 13:27:20 +00005657 UChar opc1 = ifieldOPC(theInstr);
5658 UChar BO = ifieldRegDS(theInstr);
5659 UChar BI = ifieldRegA(theInstr);
5660 UInt BD_u16 = ifieldUIMM16(theInstr) & 0xFFFFFFFC; /* mask off */
5661 UChar b11to15 = ifieldRegB(theInstr);
5662 UInt opc2 = ifieldOPClo10(theInstr);
5663 UInt LI_u26 = ifieldUIMM26(theInstr) & 0xFFFFFFFC; /* mask off */
5664 UChar flag_AA = ifieldBIT1(theInstr);
5665 UChar flag_LK = ifieldBIT0(theInstr);
5666
cerion2831b002005-11-30 19:55:22 +00005667 IRType ty = mode64 ? Ity_I64 : Ity_I32;
ceriond953ebb2005-11-29 13:27:20 +00005668 Addr64 tgt = 0;
5669 Int BD = extend_s_16to32(BD_u16);
cerion2831b002005-11-30 19:55:22 +00005670 IRTemp do_branch = newTemp(Ity_I32);
5671 IRTemp ctr_ok = newTemp(Ity_I32);
5672 IRTemp cond_ok = newTemp(Ity_I32);
5673 IRExpr* e_nia = mkSzImm(ty, nextInsnAddr());
5674 IRConst* c_nia = mkSzConst(ty, nextInsnAddr());
sewardjdf07b882005-11-29 18:19:11 +00005675 IRTemp lr_old = newTemp(ty);
ceriond953ebb2005-11-29 13:27:20 +00005676
cerionb85e8bb2005-02-16 08:54:33 +00005677 /* Hack to pass through code that just wants to read the PC */
5678 if (theInstr == 0x429F0005) {
sewardjb51f0f42005-07-18 11:38:02 +00005679 DIP("bcl 0x%x, 0x%x (a.k.a mr lr,cia+4)\n", BO, BI);
ceriond953ebb2005-11-29 13:27:20 +00005680 putGST( PPC_GST_LR, e_nia );
cerionb85e8bb2005-02-16 08:54:33 +00005681 return True;
sewardjb51f0f42005-07-18 11:38:02 +00005682 }
sewardj9d540e52005-10-08 11:28:16 +00005683
5684 /* The default what-next. Individual cases can override it. */
5685 dres->whatNext = Dis_StopHere;
sewardj3dee8492012-04-20 00:13:28 +00005686 vassert(dres->jk_StopHere == Ijk_INVALID);
sewardj9d540e52005-10-08 11:28:16 +00005687
cerionb85e8bb2005-02-16 08:54:33 +00005688 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00005689 case 0x12: // b (Branch, PPC32 p360)
cerion4561acb2005-02-21 14:07:48 +00005690 if (flag_AA) {
cerion2831b002005-11-30 19:55:22 +00005691 tgt = mkSzAddr( ty, extend_s_26to64(LI_u26) );
cerion4561acb2005-02-21 14:07:48 +00005692 } else {
cerion2831b002005-11-30 19:55:22 +00005693 tgt = mkSzAddr( ty, guest_CIA_curr_instr +
5694 (Long)extend_s_26to64(LI_u26) );
cerionb85e8bb2005-02-16 08:54:33 +00005695 }
ceriond953ebb2005-11-29 13:27:20 +00005696 if (mode64) {
5697 DIP("b%s%s 0x%llx\n",
5698 flag_LK ? "l" : "", flag_AA ? "a" : "", tgt);
5699 } else {
5700 DIP("b%s%s 0x%x\n",
5701 flag_LK ? "l" : "", flag_AA ? "a" : "", (Addr32)tgt);
sewardj9d540e52005-10-08 11:28:16 +00005702 }
5703
sewardjcf8986c2006-01-18 04:14:52 +00005704 if (flag_LK) {
ceriond953ebb2005-11-29 13:27:20 +00005705 putGST( PPC_GST_LR, e_nia );
sewardjdd40fdf2006-12-24 02:20:24 +00005706 if (vbi->guest_ppc_zap_RZ_at_bl
sewardj478646f2008-05-01 20:13:04 +00005707 && vbi->guest_ppc_zap_RZ_at_bl( (ULong)tgt) ) {
5708 IRTemp t_tgt = newTemp(ty);
5709 assign(t_tgt, mode64 ? mkU64(tgt) : mkU32(tgt) );
5710 make_redzone_AbiHint( vbi, t_tgt,
sewardjaca070a2006-10-17 00:28:22 +00005711 "branch-and-link (unconditional call)" );
sewardj478646f2008-05-01 20:13:04 +00005712 }
sewardjcf8986c2006-01-18 04:14:52 +00005713 }
ceriond953ebb2005-11-29 13:27:20 +00005714
sewardjc716aea2006-01-17 01:48:46 +00005715 if (resteerOkFn( callback_opaque, tgt )) {
sewardj984d9b12010-01-15 10:53:21 +00005716 dres->whatNext = Dis_ResteerU;
ceriond953ebb2005-11-29 13:27:20 +00005717 dres->continueAt = tgt;
sewardj9d540e52005-10-08 11:28:16 +00005718 } else {
sewardj3dee8492012-04-20 00:13:28 +00005719 dres->jk_StopHere = flag_LK ? Ijk_Call : Ijk_Boring; ;
5720 putGST( PPC_GST_CIA, mkSzImm(ty, tgt) );
sewardj9d540e52005-10-08 11:28:16 +00005721 }
cerionb85e8bb2005-02-16 08:54:33 +00005722 break;
5723
cerione9d361a2005-03-04 17:35:29 +00005724 case 0x10: // bc (Branch Conditional, PPC32 p361)
cerionb85e8bb2005-02-16 08:54:33 +00005725 DIP("bc%s%s 0x%x, 0x%x, 0x%x\n",
ceriond953ebb2005-11-29 13:27:20 +00005726 flag_LK ? "l" : "", flag_AA ? "a" : "", BO, BI, BD);
cerionb85e8bb2005-02-16 08:54:33 +00005727
5728 if (!(BO & 0x4)) {
ceriond953ebb2005-11-29 13:27:20 +00005729 putGST( PPC_GST_CTR,
cerion2831b002005-11-30 19:55:22 +00005730 binop(mkSzOp(ty, Iop_Sub8),
5731 getGST( PPC_GST_CTR ), mkSzImm(ty, 1)) );
cerionb85e8bb2005-02-16 08:54:33 +00005732 }
sewardjb51f0f42005-07-18 11:38:02 +00005733
5734 /* This is a bit subtle. ctr_ok is either all 0s or all 1s.
cerion76de5cf2005-11-18 18:25:12 +00005735 cond_ok is either zero or nonzero, since that's the cheapest
5736 way to compute it. Anding them together gives a value which
5737 is either zero or non zero and so that's what we must test
5738 for in the IRStmt_Exit. */
sewardjb51f0f42005-07-18 11:38:02 +00005739 assign( ctr_ok, branch_ctr_ok( BO ) );
cerionb85e8bb2005-02-16 08:54:33 +00005740 assign( cond_ok, branch_cond_ok( BO, BI ) );
sewardjb51f0f42005-07-18 11:38:02 +00005741 assign( do_branch,
5742 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
5743
cerion4561acb2005-02-21 14:07:48 +00005744 if (flag_AA) {
cerion2831b002005-11-30 19:55:22 +00005745 tgt = mkSzAddr(ty, extend_s_16to64(BD_u16));
cerion4561acb2005-02-21 14:07:48 +00005746 } else {
cerion2831b002005-11-30 19:55:22 +00005747 tgt = mkSzAddr(ty, guest_CIA_curr_instr +
5748 (Long)extend_s_16to64(BD_u16));
cerionb85e8bb2005-02-16 08:54:33 +00005749 }
ceriond953ebb2005-11-29 13:27:20 +00005750 if (flag_LK)
5751 putGST( PPC_GST_LR, e_nia );
cerionb85e8bb2005-02-16 08:54:33 +00005752
ceriond953ebb2005-11-29 13:27:20 +00005753 stmt( IRStmt_Exit(
5754 binop(Iop_CmpNE32, mkexpr(do_branch), mkU32(0)),
5755 flag_LK ? Ijk_Call : Ijk_Boring,
sewardj3dee8492012-04-20 00:13:28 +00005756 mkSzConst(ty, tgt), OFFB_CIA ) );
5757
5758 dres->jk_StopHere = Ijk_Boring;
5759 putGST( PPC_GST_CIA, e_nia );
cerionb85e8bb2005-02-16 08:54:33 +00005760 break;
5761
5762 case 0x13:
sewardj6be67232006-01-24 19:00:05 +00005763 /* For bclr and bcctr, it appears that the lowest two bits of
5764 b11to15 are a branch hint, and so we only need to ensure it's
5765 of the form 000XX. */
5766 if ((b11to15 & ~3) != 0) {
5767 vex_printf("dis_int_branch(ppc)(0x13,b11to15)(%d)\n", (Int)b11to15);
cerionb85e8bb2005-02-16 08:54:33 +00005768 return False;
5769 }
cerion91ad5362005-01-27 23:02:41 +00005770
cerionb85e8bb2005-02-16 08:54:33 +00005771 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00005772 case 0x210: // bcctr (Branch Cond. to Count Register, PPC32 p363)
cerion5b2325f2005-12-23 00:55:09 +00005773 if ((BO & 0x4) == 0) { // "decr and test CTR" option invalid
5774 vex_printf("dis_int_branch(ppc)(bcctr,BO)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005775 return False;
5776 }
ceriona31e8b52005-02-21 16:30:45 +00005777 DIP("bcctr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
cerionb85e8bb2005-02-16 08:54:33 +00005778
5779 assign( cond_ok, branch_cond_ok( BO, BI ) );
ceriond953ebb2005-11-29 13:27:20 +00005780
sewardj478646f2008-05-01 20:13:04 +00005781 /* FIXME: this is confusing. lr_old holds the old value
5782 of ctr, not lr :-) */
cerion2831b002005-11-30 19:55:22 +00005783 assign( lr_old, addr_align( getGST( PPC_GST_CTR ), 4 ));
sewardjdf07b882005-11-29 18:19:11 +00005784
ceriond953ebb2005-11-29 13:27:20 +00005785 if (flag_LK)
5786 putGST( PPC_GST_LR, e_nia );
cerionb85e8bb2005-02-16 08:54:33 +00005787
sewardjb51f0f42005-07-18 11:38:02 +00005788 stmt( IRStmt_Exit(
5789 binop(Iop_CmpEQ32, mkexpr(cond_ok), mkU32(0)),
5790 Ijk_Boring,
sewardj3dee8492012-04-20 00:13:28 +00005791 c_nia, OFFB_CIA ));
sewardj478646f2008-05-01 20:13:04 +00005792
5793 if (flag_LK && vbi->guest_ppc_zap_RZ_at_bl) {
5794 make_redzone_AbiHint( vbi, lr_old,
5795 "b-ctr-l (indirect call)" );
5796 }
5797
sewardj3dee8492012-04-20 00:13:28 +00005798 dres->jk_StopHere = flag_LK ? Ijk_Call : Ijk_Boring;;
5799 putGST( PPC_GST_CIA, mkexpr(lr_old) );
cerionb85e8bb2005-02-16 08:54:33 +00005800 break;
5801
sewardjcf8986c2006-01-18 04:14:52 +00005802 case 0x010: { // bclr (Branch Cond. to Link Register, PPC32 p365)
5803 Bool vanilla_return = False;
sewardjb51f0f42005-07-18 11:38:02 +00005804 if ((BO & 0x14 /* 1z1zz */) == 0x14 && flag_LK == 0) {
cerion225a0342005-09-12 20:49:09 +00005805 DIP("blr\n");
sewardjcf8986c2006-01-18 04:14:52 +00005806 vanilla_return = True;
sewardjb51f0f42005-07-18 11:38:02 +00005807 } else {
5808 DIP("bclr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
5809 }
cerion91ad5362005-01-27 23:02:41 +00005810
cerionb85e8bb2005-02-16 08:54:33 +00005811 if (!(BO & 0x4)) {
ceriond953ebb2005-11-29 13:27:20 +00005812 putGST( PPC_GST_CTR,
cerion2831b002005-11-30 19:55:22 +00005813 binop(mkSzOp(ty, Iop_Sub8),
5814 getGST( PPC_GST_CTR ), mkSzImm(ty, 1)) );
cerionb85e8bb2005-02-16 08:54:33 +00005815 }
5816
sewardjb51f0f42005-07-18 11:38:02 +00005817 /* See comments above for 'bc' about this */
5818 assign( ctr_ok, branch_ctr_ok( BO ) );
5819 assign( cond_ok, branch_cond_ok( BO, BI ) );
5820 assign( do_branch,
5821 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
cerion2831b002005-11-30 19:55:22 +00005822
sewardjdf07b882005-11-29 18:19:11 +00005823 assign( lr_old, addr_align( getGST( PPC_GST_LR ), 4 ));
5824
ceriond953ebb2005-11-29 13:27:20 +00005825 if (flag_LK)
5826 putGST( PPC_GST_LR, e_nia );
sewardjb51f0f42005-07-18 11:38:02 +00005827
5828 stmt( IRStmt_Exit(
5829 binop(Iop_CmpEQ32, mkexpr(do_branch), mkU32(0)),
5830 Ijk_Boring,
sewardj3dee8492012-04-20 00:13:28 +00005831 c_nia, OFFB_CIA ));
sewardjb51f0f42005-07-18 11:38:02 +00005832
sewardj478646f2008-05-01 20:13:04 +00005833 if (vanilla_return && vbi->guest_ppc_zap_RZ_at_blr) {
5834 make_redzone_AbiHint( vbi, lr_old,
5835 "branch-to-lr (unconditional return)" );
5836 }
sewardjcf8986c2006-01-18 04:14:52 +00005837
sewardjd37be032005-11-12 12:56:31 +00005838 /* blrl is pretty strange; it's like a return that sets the
5839 return address of its caller to the insn following this
5840 one. Mark it as a return. */
sewardj3dee8492012-04-20 00:13:28 +00005841 dres->jk_StopHere = Ijk_Ret; /* was flag_LK ? Ijk_Call : Ijk_Ret; */
5842 putGST( PPC_GST_CIA, mkexpr(lr_old) );
cerionb85e8bb2005-02-16 08:54:33 +00005843 break;
sewardjcf8986c2006-01-18 04:14:52 +00005844 }
cerionb85e8bb2005-02-16 08:54:33 +00005845 default:
cerion5b2325f2005-12-23 00:55:09 +00005846 vex_printf("dis_int_branch(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005847 return False;
5848 }
5849 break;
cerion2831b002005-11-30 19:55:22 +00005850
cerionb85e8bb2005-02-16 08:54:33 +00005851 default:
cerion5b2325f2005-12-23 00:55:09 +00005852 vex_printf("dis_int_branch(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005853 return False;
5854 }
cerion2831b002005-11-30 19:55:22 +00005855
cerionb85e8bb2005-02-16 08:54:33 +00005856 return True;
cerion91ad5362005-01-27 23:02:41 +00005857}
5858
5859
5860
cerion3d870a32005-03-18 12:23:33 +00005861/*
5862 Condition Register Logical Instructions
5863*/
cerion3007c7f2005-02-23 23:13:29 +00005864static Bool dis_cond_logic ( UInt theInstr )
5865{
5866 /* XL-Form */
cerion76de5cf2005-11-18 18:25:12 +00005867 UChar opc1 = ifieldOPC(theInstr);
5868 UChar crbD_addr = ifieldRegDS(theInstr);
5869 UChar crfD_addr = toUChar( IFIELD(theInstr, 23, 3) );
5870 UChar crbA_addr = ifieldRegA(theInstr);
5871 UChar crfS_addr = toUChar( IFIELD(theInstr, 18, 3) );
5872 UChar crbB_addr = ifieldRegB(theInstr);
5873 UInt opc2 = ifieldOPClo10(theInstr);
5874 UChar b0 = ifieldBIT0(theInstr);
cerion3007c7f2005-02-23 23:13:29 +00005875
cerionf0de28c2005-12-13 20:21:11 +00005876 IRTemp crbD = newTemp(Ity_I32);
5877 IRTemp crbA = newTemp(Ity_I32);
5878 IRTemp crbB = newTemp(Ity_I32);
cerion3007c7f2005-02-23 23:13:29 +00005879
5880 if (opc1 != 19 || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00005881 vex_printf("dis_cond_logic(ppc)(opc1)\n");
cerion3007c7f2005-02-23 23:13:29 +00005882 return False;
5883 }
5884
cerione9d361a2005-03-04 17:35:29 +00005885 if (opc2 == 0) { // mcrf (Move Cond Reg Field, PPC32 p464)
cerion3007c7f2005-02-23 23:13:29 +00005886 if (((crbD_addr & 0x3) != 0) ||
cerion76de5cf2005-11-18 18:25:12 +00005887 ((crbA_addr & 0x3) != 0) || (crbB_addr != 0)) {
cerion5b2325f2005-12-23 00:55:09 +00005888 vex_printf("dis_cond_logic(ppc)(crbD|crbA|crbB != 0)\n");
cerion3007c7f2005-02-23 23:13:29 +00005889 return False;
cerion76de5cf2005-11-18 18:25:12 +00005890 }
ceriond953ebb2005-11-29 13:27:20 +00005891 DIP("mcrf cr%u,cr%u\n", crfD_addr, crfS_addr);
sewardjb51f0f42005-07-18 11:38:02 +00005892 putCR0( crfD_addr, getCR0( crfS_addr) );
5893 putCR321( crfD_addr, getCR321(crfS_addr) );
cerion3007c7f2005-02-23 23:13:29 +00005894 } else {
sewardjb51f0f42005-07-18 11:38:02 +00005895 assign( crbA, getCRbit(crbA_addr) );
ceriona50fde52005-07-01 21:16:10 +00005896 if (crbA_addr == crbB_addr)
sewardjb51f0f42005-07-18 11:38:02 +00005897 crbB = crbA;
ceriona50fde52005-07-01 21:16:10 +00005898 else
sewardjb51f0f42005-07-18 11:38:02 +00005899 assign( crbB, getCRbit(crbB_addr) );
cerion3007c7f2005-02-23 23:13:29 +00005900
5901 switch (opc2) {
sewardj7c2dc712005-09-08 17:33:27 +00005902 case 0x101: // crand (Cond Reg AND, PPC32 p372)
5903 DIP("crand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5904 assign( crbD, binop(Iop_And32, mkexpr(crbA), mkexpr(crbB)) );
5905 break;
sewardj7787af42005-08-04 18:32:19 +00005906 case 0x081: // crandc (Cond Reg AND w. Complement, PPC32 p373)
5907 DIP("crandc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5908 assign( crbD, binop(Iop_And32,
5909 mkexpr(crbA),
5910 unop(Iop_Not32, mkexpr(crbB))) );
5911 break;
sewardje14bb9f2005-07-22 09:39:02 +00005912 case 0x121: // creqv (Cond Reg Equivalent, PPC32 p374)
5913 DIP("creqv crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5914 assign( crbD, unop(Iop_Not32,
5915 binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB))) );
5916 break;
sewardj7c2dc712005-09-08 17:33:27 +00005917 case 0x0E1: // crnand (Cond Reg NAND, PPC32 p375)
5918 DIP("crnand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5919 assign( crbD, unop(Iop_Not32,
5920 binop(Iop_And32, mkexpr(crbA), mkexpr(crbB))) );
5921 break;
cerione9d361a2005-03-04 17:35:29 +00005922 case 0x021: // crnor (Cond Reg NOR, PPC32 p376)
cerion3007c7f2005-02-23 23:13:29 +00005923 DIP("crnor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5924 assign( crbD, unop(Iop_Not32,
5925 binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB))) );
5926 break;
cerione9d361a2005-03-04 17:35:29 +00005927 case 0x1C1: // cror (Cond Reg OR, PPC32 p377)
cerion3007c7f2005-02-23 23:13:29 +00005928 DIP("cror crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5929 assign( crbD, binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB)) );
5930 break;
sewardj7c2dc712005-09-08 17:33:27 +00005931 case 0x1A1: // crorc (Cond Reg OR w. Complement, PPC32 p378)
5932 DIP("crorc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5933 assign( crbD, binop(Iop_Or32,
5934 mkexpr(crbA),
5935 unop(Iop_Not32, mkexpr(crbB))) );
5936 break;
cerione9d361a2005-03-04 17:35:29 +00005937 case 0x0C1: // crxor (Cond Reg XOR, PPC32 p379)
cerion3007c7f2005-02-23 23:13:29 +00005938 DIP("crxor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5939 assign( crbD, binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB)) );
5940 break;
cerion3007c7f2005-02-23 23:13:29 +00005941 default:
cerion5b2325f2005-12-23 00:55:09 +00005942 vex_printf("dis_cond_logic(ppc)(opc2)\n");
cerion3007c7f2005-02-23 23:13:29 +00005943 return False;
5944 }
5945
sewardjb51f0f42005-07-18 11:38:02 +00005946 putCRbit( crbD_addr, mkexpr(crbD) );
cerion3007c7f2005-02-23 23:13:29 +00005947 }
5948 return True;
5949}
5950
5951
sewardj334870d2006-02-07 16:42:39 +00005952/*
5953 Trap instructions
5954*/
5955
5956/* Do the code generation for a trap. Returned Bool is true iff
sewardj59c0d8f2007-08-28 14:48:35 +00005957 this is an unconditional trap. If the two arg IRExpr*s are
5958 Ity_I32s then the comparison is 32-bit. If they are Ity_I64s
5959 then they are 64-bit, and we must be disassembling 64-bit
5960 instructions. */
5961static Bool do_trap ( UChar TO,
5962 IRExpr* argL0, IRExpr* argR0, Addr64 cia )
sewardj334870d2006-02-07 16:42:39 +00005963{
5964 IRTemp argL, argR;
5965 IRExpr *argLe, *argRe, *cond, *tmp;
5966
sewardj59c0d8f2007-08-28 14:48:35 +00005967 Bool is32bit = typeOfIRExpr(irsb->tyenv, argL0 ) == Ity_I32;
5968
5969 IROp opAND = is32bit ? Iop_And32 : Iop_And64;
5970 IROp opOR = is32bit ? Iop_Or32 : Iop_Or64;
5971 IROp opCMPORDS = is32bit ? Iop_CmpORD32S : Iop_CmpORD64S;
5972 IROp opCMPORDU = is32bit ? Iop_CmpORD32U : Iop_CmpORD64U;
5973 IROp opCMPNE = is32bit ? Iop_CmpNE32 : Iop_CmpNE64;
5974 IROp opCMPEQ = is32bit ? Iop_CmpEQ32 : Iop_CmpEQ64;
5975 IRExpr* const0 = is32bit ? mkU32(0) : mkU64(0);
5976 IRExpr* const2 = is32bit ? mkU32(2) : mkU64(2);
5977 IRExpr* const4 = is32bit ? mkU32(4) : mkU64(4);
5978 IRExpr* const8 = is32bit ? mkU32(8) : mkU64(8);
sewardj334870d2006-02-07 16:42:39 +00005979
5980 const UChar b11100 = 0x1C;
5981 const UChar b00111 = 0x07;
5982
sewardj59c0d8f2007-08-28 14:48:35 +00005983 if (is32bit) {
5984 vassert( typeOfIRExpr(irsb->tyenv, argL0) == Ity_I32 );
5985 vassert( typeOfIRExpr(irsb->tyenv, argR0) == Ity_I32 );
5986 } else {
5987 vassert( typeOfIRExpr(irsb->tyenv, argL0) == Ity_I64 );
5988 vassert( typeOfIRExpr(irsb->tyenv, argR0) == Ity_I64 );
5989 vassert( mode64 );
5990 }
5991
sewardj334870d2006-02-07 16:42:39 +00005992 if ((TO & b11100) == b11100 || (TO & b00111) == b00111) {
5993 /* Unconditional trap. Just do the exit without
5994 testing the arguments. */
5995 stmt( IRStmt_Exit(
5996 binop(opCMPEQ, const0, const0),
sewardj0f500042007-08-29 09:09:17 +00005997 Ijk_SigTRAP,
sewardj3dee8492012-04-20 00:13:28 +00005998 mode64 ? IRConst_U64(cia) : IRConst_U32((UInt)cia),
5999 OFFB_CIA
sewardj334870d2006-02-07 16:42:39 +00006000 ));
6001 return True; /* unconditional trap */
6002 }
6003
sewardj59c0d8f2007-08-28 14:48:35 +00006004 if (is32bit) {
sewardj2d19fe32006-02-07 20:55:08 +00006005 argL = newTemp(Ity_I32);
6006 argR = newTemp(Ity_I32);
sewardj334870d2006-02-07 16:42:39 +00006007 } else {
sewardj2d19fe32006-02-07 20:55:08 +00006008 argL = newTemp(Ity_I64);
6009 argR = newTemp(Ity_I64);
sewardj334870d2006-02-07 16:42:39 +00006010 }
sewardj59c0d8f2007-08-28 14:48:35 +00006011
6012 assign( argL, argL0 );
6013 assign( argR, argR0 );
6014
sewardj334870d2006-02-07 16:42:39 +00006015 argLe = mkexpr(argL);
6016 argRe = mkexpr(argR);
sewardj59c0d8f2007-08-28 14:48:35 +00006017
sewardj334870d2006-02-07 16:42:39 +00006018 cond = const0;
6019 if (TO & 16) { // L <s R
6020 tmp = binop(opAND, binop(opCMPORDS, argLe, argRe), const8);
6021 cond = binop(opOR, tmp, cond);
6022 }
6023 if (TO & 8) { // L >s R
6024 tmp = binop(opAND, binop(opCMPORDS, argLe, argRe), const4);
6025 cond = binop(opOR, tmp, cond);
6026 }
6027 if (TO & 4) { // L == R
6028 tmp = binop(opAND, binop(opCMPORDS, argLe, argRe), const2);
6029 cond = binop(opOR, tmp, cond);
6030 }
6031 if (TO & 2) { // L <u R
6032 tmp = binop(opAND, binop(opCMPORDU, argLe, argRe), const8);
6033 cond = binop(opOR, tmp, cond);
6034 }
6035 if (TO & 1) { // L >u R
6036 tmp = binop(opAND, binop(opCMPORDU, argLe, argRe), const4);
6037 cond = binop(opOR, tmp, cond);
6038 }
6039 stmt( IRStmt_Exit(
6040 binop(opCMPNE, cond, const0),
sewardj0f500042007-08-29 09:09:17 +00006041 Ijk_SigTRAP,
sewardj3dee8492012-04-20 00:13:28 +00006042 mode64 ? IRConst_U64(cia) : IRConst_U32((UInt)cia),
6043 OFFB_CIA
sewardj334870d2006-02-07 16:42:39 +00006044 ));
6045 return False; /* not an unconditional trap */
6046}
6047
6048static Bool dis_trapi ( UInt theInstr,
6049 /*OUT*/DisResult* dres )
6050{
6051 /* D-Form */
6052 UChar opc1 = ifieldOPC(theInstr);
6053 UChar TO = ifieldRegDS(theInstr);
6054 UChar rA_addr = ifieldRegA(theInstr);
6055 UInt uimm16 = ifieldUIMM16(theInstr);
6056 ULong simm16 = extend_s_16to64(uimm16);
6057 Addr64 cia = guest_CIA_curr_instr;
6058 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6059 Bool uncond = False;
6060
6061 switch (opc1) {
6062 case 0x03: // twi (Trap Word Immediate, PPC32 p548)
sewardj59c0d8f2007-08-28 14:48:35 +00006063 uncond = do_trap( TO,
6064 mode64 ? unop(Iop_64to32, getIReg(rA_addr))
6065 : getIReg(rA_addr),
sewardjb4f6d6b2007-08-28 16:39:52 +00006066 mkU32( (UInt)simm16 ),
sewardj59c0d8f2007-08-28 14:48:35 +00006067 cia );
sewardj334870d2006-02-07 16:42:39 +00006068 if (TO == 4) {
6069 DIP("tweqi r%u,%d\n", (UInt)rA_addr, (Int)simm16);
6070 } else {
6071 DIP("tw%di r%u,%d\n", (Int)TO, (UInt)rA_addr, (Int)simm16);
6072 }
6073 break;
6074 case 0x02: // tdi
6075 if (!mode64)
6076 return False;
sewardj59c0d8f2007-08-28 14:48:35 +00006077 uncond = do_trap( TO, getIReg(rA_addr), mkU64( (ULong)simm16 ), cia );
sewardj2d19fe32006-02-07 20:55:08 +00006078 if (TO == 4) {
6079 DIP("tdeqi r%u,%d\n", (UInt)rA_addr, (Int)simm16);
6080 } else {
6081 DIP("td%di r%u,%d\n", (Int)TO, (UInt)rA_addr, (Int)simm16);
6082 }
sewardj334870d2006-02-07 16:42:39 +00006083 break;
6084 default:
6085 return False;
6086 }
6087
6088 if (uncond) {
6089 /* If the trap shows signs of being unconditional, don't
6090 continue decoding past it. */
sewardj3dee8492012-04-20 00:13:28 +00006091 putGST( PPC_GST_CIA, mkSzImm( ty, nextInsnAddr() ));
6092 dres->jk_StopHere = Ijk_Boring;
6093 dres->whatNext = Dis_StopHere;
sewardj334870d2006-02-07 16:42:39 +00006094 }
6095
6096 return True;
6097}
6098
sewardj59c0d8f2007-08-28 14:48:35 +00006099static Bool dis_trap ( UInt theInstr,
6100 /*OUT*/DisResult* dres )
6101{
6102 /* X-Form */
6103 UInt opc2 = ifieldOPClo10(theInstr);
6104 UChar TO = ifieldRegDS(theInstr);
6105 UChar rA_addr = ifieldRegA(theInstr);
6106 UChar rB_addr = ifieldRegB(theInstr);
6107 Addr64 cia = guest_CIA_curr_instr;
6108 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6109 Bool uncond = False;
6110
6111 if (ifieldBIT0(theInstr) != 0)
6112 return False;
6113
6114 switch (opc2) {
6115 case 0x004: // tw (Trap Word, PPC64 p540)
6116 uncond = do_trap( TO,
6117 mode64 ? unop(Iop_64to32, getIReg(rA_addr))
6118 : getIReg(rA_addr),
6119 mode64 ? unop(Iop_64to32, getIReg(rB_addr))
6120 : getIReg(rB_addr),
6121 cia );
6122 if (TO == 4) {
6123 DIP("tweq r%u,r%u\n", (UInt)rA_addr, (UInt)rB_addr);
6124 } else {
6125 DIP("tw%d r%u,r%u\n", (Int)TO, (UInt)rA_addr, (UInt)rB_addr);
6126 }
6127 break;
sewardjb4f6d6b2007-08-28 16:39:52 +00006128 case 0x044: // td (Trap Doubleword, PPC64 p534)
6129 if (!mode64)
6130 return False;
6131 uncond = do_trap( TO, getIReg(rA_addr), getIReg(rB_addr), cia );
6132 if (TO == 4) {
6133 DIP("tdeq r%u,r%u\n", (UInt)rA_addr, (UInt)rB_addr);
6134 } else {
6135 DIP("td%d r%u,r%u\n", (Int)TO, (UInt)rA_addr, (UInt)rB_addr);
6136 }
6137 break;
sewardj59c0d8f2007-08-28 14:48:35 +00006138 default:
6139 return False;
6140 }
6141
6142 if (uncond) {
6143 /* If the trap shows signs of being unconditional, don't
6144 continue decoding past it. */
sewardj3dee8492012-04-20 00:13:28 +00006145 putGST( PPC_GST_CIA, mkSzImm( ty, nextInsnAddr() ));
6146 dres->jk_StopHere = Ijk_Boring;
6147 dres->whatNext = Dis_StopHere;
sewardj59c0d8f2007-08-28 14:48:35 +00006148 }
6149
6150 return True;
6151}
6152
sewardj334870d2006-02-07 16:42:39 +00006153
cerion3d870a32005-03-18 12:23:33 +00006154/*
6155 System Linkage Instructions
6156*/
sewardjaca070a2006-10-17 00:28:22 +00006157static Bool dis_syslink ( UInt theInstr,
sewardjdd40fdf2006-12-24 02:20:24 +00006158 VexAbiInfo* abiinfo, DisResult* dres )
cerion8c3adda2005-01-31 11:54:05 +00006159{
ceriond953ebb2005-11-29 13:27:20 +00006160 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6161
cerionb85e8bb2005-02-16 08:54:33 +00006162 if (theInstr != 0x44000002) {
cerion5b2325f2005-12-23 00:55:09 +00006163 vex_printf("dis_syslink(ppc)(theInstr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006164 return False;
6165 }
cerione1d857b2005-02-04 18:29:05 +00006166
cerione9d361a2005-03-04 17:35:29 +00006167 // sc (System Call, PPC32 p504)
cerionb85e8bb2005-02-16 08:54:33 +00006168 DIP("sc\n");
sewardjaca070a2006-10-17 00:28:22 +00006169
sewardje86310f2009-03-19 22:21:40 +00006170 /* Copy CIA into the IP_AT_SYSCALL pseudo-register, so that on AIX
sewardjaca070a2006-10-17 00:28:22 +00006171 Valgrind can back the guest up to this instruction if it needs
6172 to restart the syscall. */
sewardje86310f2009-03-19 22:21:40 +00006173 putGST( PPC_GST_IP_AT_SYSCALL, getGST( PPC_GST_CIA ) );
sewardjaca070a2006-10-17 00:28:22 +00006174
cerionb85e8bb2005-02-16 08:54:33 +00006175 /* It's important that all ArchRegs carry their up-to-date value
6176 at this point. So we declare an end-of-block here, which
6177 forces any TempRegs caching ArchRegs to be flushed. */
sewardjd1526f22014-07-16 23:14:33 +00006178 putGST( PPC_GST_CIA, mkSzImm( ty, nextInsnAddr() ));
ceriond953ebb2005-11-29 13:27:20 +00006179
sewardj3dee8492012-04-20 00:13:28 +00006180 dres->whatNext = Dis_StopHere;
6181 dres->jk_StopHere = Ijk_Sys_syscall;
cerionb85e8bb2005-02-16 08:54:33 +00006182 return True;
cerion8c3adda2005-01-31 11:54:05 +00006183}
6184
cerion3d870a32005-03-18 12:23:33 +00006185
6186/*
6187 Memory Synchronization Instructions
cerion07b07a92005-12-22 14:32:35 +00006188
6189 Note on Reservations:
6190 We rely on the assumption that V will in fact only allow one thread at
6191 once to run. In effect, a thread can make a reservation, but we don't
6192 check any stores it does. Instead, the reservation is cancelled when
6193 the scheduler switches to another thread (run_thread_for_a_while()).
cerion3d870a32005-03-18 12:23:33 +00006194*/
cerion8c3adda2005-01-31 11:54:05 +00006195static Bool dis_memsync ( UInt theInstr )
6196{
cerionb85e8bb2005-02-16 08:54:33 +00006197 /* X-Form, XL-Form */
ceriond953ebb2005-11-29 13:27:20 +00006198 UChar opc1 = ifieldOPC(theInstr);
6199 UInt b11to25 = IFIELD(theInstr, 11, 15);
cerione43bc882006-01-05 13:11:59 +00006200 UChar flag_L = ifieldRegDS(theInstr);
6201 UInt b11to20 = IFIELD(theInstr, 11, 10);
ceriond953ebb2005-11-29 13:27:20 +00006202 UChar rD_addr = ifieldRegDS(theInstr);
6203 UChar rS_addr = rD_addr;
6204 UChar rA_addr = ifieldRegA(theInstr);
6205 UChar rB_addr = ifieldRegB(theInstr);
6206 UInt opc2 = ifieldOPClo10(theInstr);
6207 UChar b0 = ifieldBIT0(theInstr);
cerionedf7fc52005-11-18 20:57:41 +00006208
ceriond953ebb2005-11-29 13:27:20 +00006209 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6210 IRTemp EA = newTemp(ty);
ceriond953ebb2005-11-29 13:27:20 +00006211
6212 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
6213
cerionb85e8bb2005-02-16 08:54:33 +00006214 switch (opc1) {
sewardjafe85832005-09-09 10:25:39 +00006215 /* XL-Form */
cerione9d361a2005-03-04 17:35:29 +00006216 case 0x13: // isync (Instruction Synchronize, PPC32 p432)
cerionb85e8bb2005-02-16 08:54:33 +00006217 if (opc2 != 0x096) {
cerion5b2325f2005-12-23 00:55:09 +00006218 vex_printf("dis_memsync(ppc)(0x13,opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006219 return False;
6220 }
6221 if (b11to25 != 0 || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00006222 vex_printf("dis_memsync(ppc)(0x13,b11to25|b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006223 return False;
6224 }
6225 DIP("isync\n");
sewardjc4356f02007-11-09 21:15:04 +00006226 stmt( IRStmt_MBE(Imbe_Fence) );
cerionb85e8bb2005-02-16 08:54:33 +00006227 break;
cerion8c3adda2005-01-31 11:54:05 +00006228
cerionb85e8bb2005-02-16 08:54:33 +00006229 /* X-Form */
6230 case 0x1F:
6231 switch (opc2) {
cerion5b2325f2005-12-23 00:55:09 +00006232 case 0x356: // eieio (Enforce In-Order Exec of I/O, PPC32 p394)
sewardj7787af42005-08-04 18:32:19 +00006233 if (b11to25 != 0 || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00006234 vex_printf("dis_memsync(ppc)(eiei0,b11to25|b0)\n");
sewardj7787af42005-08-04 18:32:19 +00006235 return False;
6236 }
6237 DIP("eieio\n");
6238 /* Insert a memory fence, just to be on the safe side. */
sewardjc4356f02007-11-09 21:15:04 +00006239 stmt( IRStmt_MBE(Imbe_Fence) );
sewardj7787af42005-08-04 18:32:19 +00006240 break;
cerion8c3adda2005-01-31 11:54:05 +00006241
sewardje768e922009-11-26 17:17:37 +00006242 case 0x014: { // lwarx (Load Word and Reserve Indexed, PPC32 p458)
6243 IRTemp res;
sewardjfe397a22008-08-06 19:13:42 +00006244 /* According to the PowerPC ISA version 2.05, b0 (called EH
6245 in the documentation) is merely a hint bit to the
6246 hardware, I think as to whether or not contention is
6247 likely. So we can just ignore it. */
6248 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 +00006249
6250 // trap if misaligned
6251 gen_SIGBUS_if_misaligned( EA, 4 );
6252
6253 // and actually do the load
sewardje768e922009-11-26 17:17:37 +00006254 res = newTemp(Ity_I32);
carll1f5fe1f2014-08-07 23:25:23 +00006255 stmt( stmt_load(res, mkexpr(EA), NULL/*this is a load*/) );
sewardje768e922009-11-26 17:17:37 +00006256
6257 putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(res), False) );
cerionb85e8bb2005-02-16 08:54:33 +00006258 break;
sewardje768e922009-11-26 17:17:37 +00006259 }
6260
sewardj7787af42005-08-04 18:32:19 +00006261 case 0x096: {
6262 // stwcx. (Store Word Conditional Indexed, PPC32 p532)
sewardje9d8a262009-07-01 08:06:34 +00006263 // Note this has to handle stwcx. in both 32- and 64-bit modes,
6264 // so isn't quite as straightforward as it might otherwise be.
6265 IRTemp rS = newTemp(Ity_I32);
6266 IRTemp resSC;
cerionb85e8bb2005-02-16 08:54:33 +00006267 if (b0 != 1) {
cerion5b2325f2005-12-23 00:55:09 +00006268 vex_printf("dis_memsync(ppc)(stwcx.,b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006269 return False;
6270 }
ceriond953ebb2005-11-29 13:27:20 +00006271 DIP("stwcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
sewardjafe85832005-09-09 10:25:39 +00006272
sewardje9d8a262009-07-01 08:06:34 +00006273 // trap if misaligned
6274 gen_SIGBUS_if_misaligned( EA, 4 );
6275
6276 // Get the data to be stored, and narrow to 32 bits if necessary
6277 assign( rS, mkNarrowTo32(ty, getIReg(rS_addr)) );
6278
6279 // Do the store, and get success/failure bit into resSC
6280 resSC = newTemp(Ity_I1);
carll1f5fe1f2014-08-07 23:25:23 +00006281 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS)) );
sewardje9d8a262009-07-01 08:06:34 +00006282
6283 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
6284 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
6285 putCR321(0, binop(Iop_Shl8, unop(Iop_1Uto8, mkexpr(resSC)), mkU8(1)));
sewardj7787af42005-08-04 18:32:19 +00006286 putCR0(0, getXER_SO());
6287
sewardje9d8a262009-07-01 08:06:34 +00006288 /* Note:
ceriond953ebb2005-11-29 13:27:20 +00006289 If resaddr != lwarx_resaddr, CR0[EQ] is undefined, and
6290 whether rS is stored is dependent on that value. */
sewardje9d8a262009-07-01 08:06:34 +00006291 /* So I guess we can just ignore this case? */
cerionb85e8bb2005-02-16 08:54:33 +00006292 break;
sewardj7787af42005-08-04 18:32:19 +00006293 }
6294
sewardjb029a612005-12-30 15:04:29 +00006295 case 0x256: // sync (Synchronize, PPC32 p543),
cerione43bc882006-01-05 13:11:59 +00006296 // also lwsync (L==1), ptesync (L==2)
sewardjb029a612005-12-30 15:04:29 +00006297 /* http://sources.redhat.com/ml/binutils/2000-12/msg00311.html
6298
6299 The PowerPC architecture used in IBM chips has expanded
6300 the sync instruction into two variants: lightweight sync
6301 and heavyweight sync. The original sync instruction is
6302 the new heavyweight sync and lightweight sync is a strict
6303 subset of the heavyweight sync functionality. This allows
6304 the programmer to specify a less expensive operation on
6305 high-end systems when the full sync functionality is not
6306 necessary.
6307
6308 The basic "sync" mnemonic now utilizes an operand. "sync"
6309 without an operand now becomes a extended mnemonic for
6310 heavyweight sync. Processors without the lwsync
6311 instruction will not decode the L field and will perform a
6312 heavyweight sync. Everything is backward compatible.
6313
6314 sync = sync 0
6315 lwsync = sync 1
cerione43bc882006-01-05 13:11:59 +00006316 ptesync = sync 2 *** TODO - not implemented ***
cerion4e2c2b32006-01-02 13:35:51 +00006317 */
cerione43bc882006-01-05 13:11:59 +00006318 if (b11to20 != 0 || b0 != 0) {
6319 vex_printf("dis_memsync(ppc)(sync/lwsync,b11to20|b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006320 return False;
6321 }
cerione43bc882006-01-05 13:11:59 +00006322 if (flag_L != 0/*sync*/ && flag_L != 1/*lwsync*/) {
6323 vex_printf("dis_memsync(ppc)(sync/lwsync,flag_L)\n");
6324 return False;
6325 }
6326 DIP("%ssync\n", flag_L == 1 ? "lw" : "");
cerionb85e8bb2005-02-16 08:54:33 +00006327 /* Insert a memory fence. It's sometimes important that these
6328 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +00006329 stmt( IRStmt_MBE(Imbe_Fence) );
cerionb85e8bb2005-02-16 08:54:33 +00006330 break;
cerionf0de28c2005-12-13 20:21:11 +00006331
cerionf0de28c2005-12-13 20:21:11 +00006332 /* 64bit Memsync */
sewardje768e922009-11-26 17:17:37 +00006333 case 0x054: { // ldarx (Load DWord and Reserve Indexed, PPC64 p473)
6334 IRTemp res;
sewardjfe397a22008-08-06 19:13:42 +00006335 /* According to the PowerPC ISA version 2.05, b0 (called EH
6336 in the documentation) is merely a hint bit to the
6337 hardware, I think as to whether or not contention is
6338 likely. So we can just ignore it. */
sewardje9d8a262009-07-01 08:06:34 +00006339 if (!mode64)
6340 return False;
sewardjfe397a22008-08-06 19:13:42 +00006341 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 +00006342
6343 // trap if misaligned
6344 gen_SIGBUS_if_misaligned( EA, 8 );
6345
6346 // and actually do the load
sewardje768e922009-11-26 17:17:37 +00006347 res = newTemp(Ity_I64);
carll1f5fe1f2014-08-07 23:25:23 +00006348 stmt( stmt_load( res, mkexpr(EA), NULL/*this is a load*/) );
sewardje768e922009-11-26 17:17:37 +00006349
6350 putIReg( rD_addr, mkexpr(res) );
cerion07b07a92005-12-22 14:32:35 +00006351 break;
sewardje768e922009-11-26 17:17:37 +00006352 }
6353
cerion5b2325f2005-12-23 00:55:09 +00006354 case 0x0D6: { // stdcx. (Store DWord Condition Indexd, PPC64 p581)
sewardje9d8a262009-07-01 08:06:34 +00006355 // A marginally simplified version of the stwcx. case
6356 IRTemp rS = newTemp(Ity_I64);
6357 IRTemp resSC;
cerionf0de28c2005-12-13 20:21:11 +00006358 if (b0 != 1) {
cerion5b2325f2005-12-23 00:55:09 +00006359 vex_printf("dis_memsync(ppc)(stdcx.,b0)\n");
cerionf0de28c2005-12-13 20:21:11 +00006360 return False;
6361 }
sewardje9d8a262009-07-01 08:06:34 +00006362 if (!mode64)
6363 return False;
cerionf0de28c2005-12-13 20:21:11 +00006364 DIP("stdcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
sewardje9d8a262009-07-01 08:06:34 +00006365
6366 // trap if misaligned
6367 gen_SIGBUS_if_misaligned( EA, 8 );
6368
6369 // Get the data to be stored
cerion07b07a92005-12-22 14:32:35 +00006370 assign( rS, getIReg(rS_addr) );
cerionf0de28c2005-12-13 20:21:11 +00006371
sewardje9d8a262009-07-01 08:06:34 +00006372 // Do the store, and get success/failure bit into resSC
6373 resSC = newTemp(Ity_I1);
carll1f5fe1f2014-08-07 23:25:23 +00006374 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS)) );
sewardje9d8a262009-07-01 08:06:34 +00006375
6376 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
6377 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
6378 putCR321(0, binop(Iop_Shl8, unop(Iop_1Uto8, mkexpr(resSC)), mkU8(1)));
cerion07b07a92005-12-22 14:32:35 +00006379 putCR0(0, getXER_SO());
cerionf0de28c2005-12-13 20:21:11 +00006380
sewardje9d8a262009-07-01 08:06:34 +00006381 /* Note:
6382 If resaddr != lwarx_resaddr, CR0[EQ] is undefined, and
6383 whether rS is stored is dependent on that value. */
6384 /* So I guess we can just ignore this case? */
cerion07b07a92005-12-22 14:32:35 +00006385 break;
6386 }
6387
carll78850ae2013-09-10 18:46:40 +00006388 /* 128bit Memsync */
6389 case 0x114: { // lqarx (Load QuadWord and Reserve Indexed)
6390 IRTemp res_hi = newTemp(ty);
6391 IRTemp res_lo = newTemp(ty);
6392
6393 /* According to the PowerPC ISA version 2.07, b0 (called EH
6394 in the documentation) is merely a hint bit to the
6395 hardware, I think as to whether or not contention is
6396 likely. So we can just ignore it. */
6397 DIP("lqarx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, (UInt)b0);
6398
6399 // trap if misaligned
6400 gen_SIGBUS_if_misaligned( EA, 16 );
6401
6402 // and actually do the load
6403 if (mode64) {
carll1f5fe1f2014-08-07 23:25:23 +00006404 stmt( stmt_load( res_hi,
6405 mkexpr(EA), NULL/*this is a load*/) );
6406 stmt( stmt_load( res_lo,
6407 binop(Iop_Add64, mkexpr(EA), mkU64(8) ),
6408 NULL/*this is a load*/) );
carll78850ae2013-09-10 18:46:40 +00006409 } else {
carll1f5fe1f2014-08-07 23:25:23 +00006410 stmt( stmt_load( res_hi,
6411 binop( Iop_Add32, mkexpr(EA), mkU32(4) ),
6412 NULL/*this is a load*/) );
6413 stmt( stmt_load( res_lo,
6414 binop( Iop_Add32, mkexpr(EA), mkU32(12) ),
6415 NULL/*this is a load*/) );
carll78850ae2013-09-10 18:46:40 +00006416 }
6417 putIReg( rD_addr, mkexpr(res_hi) );
6418 putIReg( rD_addr+1, mkexpr(res_lo) );
6419 break;
6420 }
6421
6422 case 0x0B6: { // stqcx. (Store QuadWord Condition Indexd, PPC64)
6423 // A marginally simplified version of the stwcx. case
6424 IRTemp rS_hi = newTemp(ty);
6425 IRTemp rS_lo = newTemp(ty);
6426 IRTemp resSC;
6427 if (b0 != 1) {
6428 vex_printf("dis_memsync(ppc)(stqcx.,b0)\n");
6429 return False;
6430 }
6431
6432 DIP("stqcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
6433
6434 // trap if misaligned
6435 gen_SIGBUS_if_misaligned( EA, 16 );
6436 // Get the data to be stored
6437 assign( rS_hi, getIReg(rS_addr) );
6438 assign( rS_lo, getIReg(rS_addr+1) );
6439
6440 // Do the store, and get success/failure bit into resSC
6441 resSC = newTemp(Ity_I1);
6442
6443 if (mode64) {
carll1f5fe1f2014-08-07 23:25:23 +00006444 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS_hi) ) );
6445 store( binop( Iop_Add64, mkexpr(EA), mkU64(8) ), mkexpr(rS_lo) );
carll78850ae2013-09-10 18:46:40 +00006446 } else {
carll1f5fe1f2014-08-07 23:25:23 +00006447 stmt( stmt_load( resSC, binop( Iop_Add32,
6448 mkexpr(EA),
6449 mkU32(4) ),
6450 mkexpr(rS_hi) ) );
6451 store( binop(Iop_Add32, mkexpr(EA), mkU32(12) ), mkexpr(rS_lo) );
carll78850ae2013-09-10 18:46:40 +00006452 }
6453
6454 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
6455 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
6456 putCR321(0, binop( Iop_Shl8,
6457 unop(Iop_1Uto8, mkexpr(resSC) ),
6458 mkU8(1)));
6459 putCR0(0, getXER_SO());
6460 break;
6461 }
6462
cerionb85e8bb2005-02-16 08:54:33 +00006463 default:
cerion5b2325f2005-12-23 00:55:09 +00006464 vex_printf("dis_memsync(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006465 return False;
6466 }
6467 break;
cerion8c3adda2005-01-31 11:54:05 +00006468
cerionb85e8bb2005-02-16 08:54:33 +00006469 default:
cerion5b2325f2005-12-23 00:55:09 +00006470 vex_printf("dis_memsync(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006471 return False;
6472 }
6473 return True;
cerion8c3adda2005-01-31 11:54:05 +00006474}
6475
6476
6477
cerion3d870a32005-03-18 12:23:33 +00006478/*
6479 Integer Shift Instructions
6480*/
cerion645c9302005-01-31 10:09:59 +00006481static Bool dis_int_shift ( UInt theInstr )
6482{
cerionf0de28c2005-12-13 20:21:11 +00006483 /* X-Form, XS-Form */
cerion76de5cf2005-11-18 18:25:12 +00006484 UChar opc1 = ifieldOPC(theInstr);
6485 UChar rS_addr = ifieldRegDS(theInstr);
6486 UChar rA_addr = ifieldRegA(theInstr);
6487 UChar rB_addr = ifieldRegB(theInstr);
6488 UChar sh_imm = rB_addr;
6489 UInt opc2 = ifieldOPClo10(theInstr);
cerionf0de28c2005-12-13 20:21:11 +00006490 UChar b1 = ifieldBIT1(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00006491 UChar flag_rC = ifieldBIT0(theInstr);
6492
ceriond953ebb2005-11-29 13:27:20 +00006493 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6494 IRTemp rA = newTemp(ty);
cerion07b07a92005-12-22 14:32:35 +00006495 IRTemp rS = newTemp(ty);
6496 IRTemp rB = newTemp(ty);
sewardj009230b2013-01-26 11:47:55 +00006497 IRTemp outofrange = newTemp(Ity_I1);
ceriond953ebb2005-11-29 13:27:20 +00006498 IRTemp rS_lo32 = newTemp(Ity_I32);
6499 IRTemp rB_lo32 = newTemp(Ity_I32);
6500 IRExpr* e_tmp;
6501
cerion07b07a92005-12-22 14:32:35 +00006502 assign( rS, getIReg(rS_addr) );
6503 assign( rB, getIReg(rB_addr) );
sewardje9d8a262009-07-01 08:06:34 +00006504 assign( rS_lo32, mkNarrowTo32(ty, mkexpr(rS)) );
6505 assign( rB_lo32, mkNarrowTo32(ty, mkexpr(rB)) );
cerionb85e8bb2005-02-16 08:54:33 +00006506
6507 if (opc1 == 0x1F) {
6508 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +00006509 case 0x018: { // slw (Shift Left Word, PPC32 p505)
cerion5b2325f2005-12-23 00:55:09 +00006510 DIP("slw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00006511 rA_addr, rS_addr, rB_addr);
6512 /* rA = rS << rB */
6513 /* ppc32 semantics are:
sewardjdfb11442005-10-08 19:58:48 +00006514 slw(x,y) = (x << (y & 31)) -- primary result
6515 & ~((y << 26) >>s 31) -- make result 0
6516 for y in 32 .. 63
6517 */
ceriond953ebb2005-11-29 13:27:20 +00006518 e_tmp =
6519 binop( Iop_And32,
6520 binop( Iop_Shl32,
6521 mkexpr(rS_lo32),
6522 unop( Iop_32to8,
6523 binop(Iop_And32,
6524 mkexpr(rB_lo32), mkU32(31)))),
6525 unop( Iop_Not32,
6526 binop( Iop_Sar32,
6527 binop(Iop_Shl32, mkexpr(rB_lo32), mkU8(26)),
6528 mkU8(31))) );
sewardje9d8a262009-07-01 08:06:34 +00006529 assign( rA, mkWidenFrom32(ty, e_tmp, /* Signed */False) );
cerionb85e8bb2005-02-16 08:54:33 +00006530 break;
ceriond953ebb2005-11-29 13:27:20 +00006531 }
6532
cerion5b2325f2005-12-23 00:55:09 +00006533 case 0x318: { // sraw (Shift Right Alg Word, PPC32 p506)
cerion07b07a92005-12-22 14:32:35 +00006534 IRTemp sh_amt = newTemp(Ity_I32);
cerion5b2325f2005-12-23 00:55:09 +00006535 DIP("sraw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00006536 rA_addr, rS_addr, rB_addr);
cerion76de5cf2005-11-18 18:25:12 +00006537 /* JRS: my reading of the (poorly worded) PPC32 doc p506 is:
6538 amt = rB & 63
6539 rA = Sar32( rS, amt > 31 ? 31 : amt )
6540 XER.CA = amt > 31 ? sign-of-rS : (computation as per srawi)
6541 */
cerion5b2325f2005-12-23 00:55:09 +00006542 assign( sh_amt, binop(Iop_And32, mkU32(0x3F),
6543 mkexpr(rB_lo32)) );
cerion76de5cf2005-11-18 18:25:12 +00006544 assign( outofrange,
sewardj009230b2013-01-26 11:47:55 +00006545 binop(Iop_CmpLT32U, mkU32(31), mkexpr(sh_amt)) );
ceriond953ebb2005-11-29 13:27:20 +00006546 e_tmp = binop( Iop_Sar32,
6547 mkexpr(rS_lo32),
sewardj20ef5472005-07-21 14:48:31 +00006548 unop( Iop_32to8,
florian99dd03e2013-01-29 03:56:06 +00006549 IRExpr_ITE( mkexpr(outofrange),
6550 mkU32(31),
6551 mkexpr(sh_amt)) ) );
sewardje9d8a262009-07-01 08:06:34 +00006552 assign( rA, mkWidenFrom32(ty, e_tmp, /* Signed */True) );
cerion2831b002005-11-30 19:55:22 +00006553
cerion5b2325f2005-12-23 00:55:09 +00006554 set_XER_CA( ty, PPCG_FLAG_OP_SRAW,
cerionf0de28c2005-12-13 20:21:11 +00006555 mkexpr(rA),
sewardje9d8a262009-07-01 08:06:34 +00006556 mkWidenFrom32(ty, mkexpr(rS_lo32), True),
6557 mkWidenFrom32(ty, mkexpr(sh_amt), True ),
6558 mkWidenFrom32(ty, getXER_CA32(), True) );
cerionb85e8bb2005-02-16 08:54:33 +00006559 break;
cerion07b07a92005-12-22 14:32:35 +00006560 }
cerionb85e8bb2005-02-16 08:54:33 +00006561
cerion5b2325f2005-12-23 00:55:09 +00006562 case 0x338: // srawi (Shift Right Alg Word Immediate, PPC32 p507)
6563 DIP("srawi%s r%u,r%u,%d\n", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00006564 rA_addr, rS_addr, sh_imm);
6565 vassert(sh_imm < 32);
cerionf0de28c2005-12-13 20:21:11 +00006566 if (mode64) {
6567 assign( rA, binop(Iop_Sar64,
cerion5b2325f2005-12-23 00:55:09 +00006568 binop(Iop_Shl64, getIReg(rS_addr),
6569 mkU8(32)),
cerionf0de28c2005-12-13 20:21:11 +00006570 mkU8(32 + sh_imm)) );
6571 } else {
cerion5b2325f2005-12-23 00:55:09 +00006572 assign( rA, binop(Iop_Sar32, mkexpr(rS_lo32),
6573 mkU8(sh_imm)) );
cerionf0de28c2005-12-13 20:21:11 +00006574 }
cerion2831b002005-11-30 19:55:22 +00006575
cerion5b2325f2005-12-23 00:55:09 +00006576 set_XER_CA( ty, PPCG_FLAG_OP_SRAWI,
cerionf0de28c2005-12-13 20:21:11 +00006577 mkexpr(rA),
sewardje9d8a262009-07-01 08:06:34 +00006578 mkWidenFrom32(ty, mkexpr(rS_lo32), /* Syned */True),
cerionf0de28c2005-12-13 20:21:11 +00006579 mkSzImm(ty, sh_imm),
sewardje9d8a262009-07-01 08:06:34 +00006580 mkWidenFrom32(ty, getXER_CA32(), /* Syned */False) );
cerionb85e8bb2005-02-16 08:54:33 +00006581 break;
6582
cerione9d361a2005-03-04 17:35:29 +00006583 case 0x218: // srw (Shift Right Word, PPC32 p508)
cerion5b2325f2005-12-23 00:55:09 +00006584 DIP("srw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00006585 rA_addr, rS_addr, rB_addr);
6586 /* rA = rS >>u rB */
6587 /* ppc32 semantics are:
cerionf0de28c2005-12-13 20:21:11 +00006588 srw(x,y) = (x >>u (y & 31)) -- primary result
sewardjdfb11442005-10-08 19:58:48 +00006589 & ~((y << 26) >>s 31) -- make result 0
6590 for y in 32 .. 63
6591 */
ceriond953ebb2005-11-29 13:27:20 +00006592 e_tmp =
sewardjdfb11442005-10-08 19:58:48 +00006593 binop(
6594 Iop_And32,
6595 binop( Iop_Shr32,
ceriond953ebb2005-11-29 13:27:20 +00006596 mkexpr(rS_lo32),
sewardjdfb11442005-10-08 19:58:48 +00006597 unop( Iop_32to8,
cerion5b2325f2005-12-23 00:55:09 +00006598 binop(Iop_And32, mkexpr(rB_lo32),
6599 mkU32(31)))),
sewardjdfb11442005-10-08 19:58:48 +00006600 unop( Iop_Not32,
6601 binop( Iop_Sar32,
cerion5b2325f2005-12-23 00:55:09 +00006602 binop(Iop_Shl32, mkexpr(rB_lo32),
6603 mkU8(26)),
ceriond953ebb2005-11-29 13:27:20 +00006604 mkU8(31))));
sewardje9d8a262009-07-01 08:06:34 +00006605 assign( rA, mkWidenFrom32(ty, e_tmp, /* Signed */False) );
cerionb85e8bb2005-02-16 08:54:33 +00006606 break;
cerionf0de28c2005-12-13 20:21:11 +00006607
6608
6609 /* 64bit Shifts */
cerion5b2325f2005-12-23 00:55:09 +00006610 case 0x01B: // sld (Shift Left DWord, PPC64 p568)
6611 DIP("sld%s r%u,r%u,r%u\n",
6612 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerionf0de28c2005-12-13 20:21:11 +00006613 /* rA = rS << rB */
cerion07b07a92005-12-22 14:32:35 +00006614 /* ppc64 semantics are:
cerionf0de28c2005-12-13 20:21:11 +00006615 slw(x,y) = (x << (y & 63)) -- primary result
6616 & ~((y << 57) >>s 63) -- make result 0
6617 for y in 64 ..
6618 */
cerionf0de28c2005-12-13 20:21:11 +00006619 assign( rA,
6620 binop(
6621 Iop_And64,
6622 binop( Iop_Shl64,
6623 mkexpr(rS),
6624 unop( Iop_64to8,
6625 binop(Iop_And64, mkexpr(rB), mkU64(63)))),
6626 unop( Iop_Not64,
6627 binop( Iop_Sar64,
6628 binop(Iop_Shl64, mkexpr(rB), mkU8(57)),
6629 mkU8(63)))) );
cerion07b07a92005-12-22 14:32:35 +00006630 break;
cerionf0de28c2005-12-13 20:21:11 +00006631
cerion5b2325f2005-12-23 00:55:09 +00006632 case 0x31A: { // srad (Shift Right Alg DWord, PPC64 p570)
cerion07b07a92005-12-22 14:32:35 +00006633 IRTemp sh_amt = newTemp(Ity_I64);
cerion5b2325f2005-12-23 00:55:09 +00006634 DIP("srad%s r%u,r%u,r%u\n",
6635 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerionf0de28c2005-12-13 20:21:11 +00006636 /* amt = rB & 127
6637 rA = Sar64( rS, amt > 63 ? 63 : amt )
6638 XER.CA = amt > 63 ? sign-of-rS : (computation as per srawi)
6639 */
cerion07b07a92005-12-22 14:32:35 +00006640 assign( sh_amt, binop(Iop_And64, mkU64(0x7F), mkexpr(rB)) );
cerionf0de28c2005-12-13 20:21:11 +00006641 assign( outofrange,
sewardj009230b2013-01-26 11:47:55 +00006642 binop(Iop_CmpLT64U, mkU64(63), mkexpr(sh_amt)) );
cerionf0de28c2005-12-13 20:21:11 +00006643 assign( rA,
6644 binop( Iop_Sar64,
6645 mkexpr(rS),
6646 unop( Iop_64to8,
florian99dd03e2013-01-29 03:56:06 +00006647 IRExpr_ITE( mkexpr(outofrange),
6648 mkU64(63),
6649 mkexpr(sh_amt)) ))
cerionf0de28c2005-12-13 20:21:11 +00006650 );
cerion5b2325f2005-12-23 00:55:09 +00006651 set_XER_CA( ty, PPCG_FLAG_OP_SRAD,
cerion07b07a92005-12-22 14:32:35 +00006652 mkexpr(rA), mkexpr(rS), mkexpr(sh_amt),
sewardje9d8a262009-07-01 08:06:34 +00006653 mkWidenFrom32(ty, getXER_CA32(), /* Syned */False) );
cerion07b07a92005-12-22 14:32:35 +00006654 break;
6655 }
6656
cerion5b2325f2005-12-23 00:55:09 +00006657 case 0x33A: case 0x33B: // sradi (Shr Alg DWord Imm, PPC64 p571)
cerionf0de28c2005-12-13 20:21:11 +00006658 sh_imm |= b1<<5;
6659 vassert(sh_imm < 64);
cerion5b2325f2005-12-23 00:55:09 +00006660 DIP("sradi%s r%u,r%u,%u\n",
6661 flag_rC ? ".":"", rA_addr, rS_addr, sh_imm);
cerionf0de28c2005-12-13 20:21:11 +00006662 assign( rA, binop(Iop_Sar64, getIReg(rS_addr), mkU8(sh_imm)) );
6663
cerion5b2325f2005-12-23 00:55:09 +00006664 set_XER_CA( ty, PPCG_FLAG_OP_SRADI,
cerionf0de28c2005-12-13 20:21:11 +00006665 mkexpr(rA),
6666 getIReg(rS_addr),
6667 mkU64(sh_imm),
sewardje9d8a262009-07-01 08:06:34 +00006668 mkWidenFrom32(ty, getXER_CA32(), /* Syned */False) );
cerionf0de28c2005-12-13 20:21:11 +00006669 break;
6670
cerion5b2325f2005-12-23 00:55:09 +00006671 case 0x21B: // srd (Shift Right DWord, PPC64 p574)
6672 DIP("srd%s r%u,r%u,r%u\n",
6673 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerionf0de28c2005-12-13 20:21:11 +00006674 /* rA = rS >>u rB */
cerion07b07a92005-12-22 14:32:35 +00006675 /* ppc semantics are:
cerionf0de28c2005-12-13 20:21:11 +00006676 srw(x,y) = (x >>u (y & 63)) -- primary result
6677 & ~((y << 57) >>s 63) -- make result 0
6678 for y in 64 .. 127
6679 */
cerionf0de28c2005-12-13 20:21:11 +00006680 assign( rA,
6681 binop(
6682 Iop_And64,
6683 binop( Iop_Shr64,
6684 mkexpr(rS),
6685 unop( Iop_64to8,
6686 binop(Iop_And64, mkexpr(rB), mkU64(63)))),
6687 unop( Iop_Not64,
6688 binop( Iop_Sar64,
6689 binop(Iop_Shl64, mkexpr(rB), mkU8(57)),
6690 mkU8(63)))) );
cerion07b07a92005-12-22 14:32:35 +00006691 break;
cerionf0de28c2005-12-13 20:21:11 +00006692
cerionb85e8bb2005-02-16 08:54:33 +00006693 default:
cerion5b2325f2005-12-23 00:55:09 +00006694 vex_printf("dis_int_shift(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006695 return False;
6696 }
6697 } else {
cerion5b2325f2005-12-23 00:55:09 +00006698 vex_printf("dis_int_shift(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006699 return False;
6700 }
cerion0d330c52005-02-28 16:43:16 +00006701
cerion76de5cf2005-11-18 18:25:12 +00006702 putIReg( rA_addr, mkexpr(rA) );
cerionb85e8bb2005-02-16 08:54:33 +00006703
cerion76de5cf2005-11-18 18:25:12 +00006704 if (flag_rC) {
6705 set_CR0( mkexpr(rA) );
cerionb85e8bb2005-02-16 08:54:33 +00006706 }
6707 return True;
cerion645c9302005-01-31 10:09:59 +00006708}
6709
6710
6711
sewardj602857d2005-09-06 09:10:09 +00006712/*
6713 Integer Load/Store Reverse Instructions
6714*/
sewardj40d8c092006-05-05 13:26:14 +00006715/* Generates code to swap the byte order in an Ity_I32. */
sewardjfb957972005-09-08 17:53:03 +00006716static IRExpr* /* :: Ity_I32 */ gen_byterev32 ( IRTemp t )
6717{
sewardjdd40fdf2006-12-24 02:20:24 +00006718 vassert(typeOfIRTemp(irsb->tyenv, t) == Ity_I32);
sewardjfb957972005-09-08 17:53:03 +00006719 return
6720 binop(Iop_Or32,
6721 binop(Iop_Shl32, mkexpr(t), mkU8(24)),
6722 binop(Iop_Or32,
6723 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t), mkU8(8)),
6724 mkU32(0x00FF0000)),
6725 binop(Iop_Or32,
6726 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t), mkU8(8)),
6727 mkU32(0x0000FF00)),
6728 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t), mkU8(24)),
6729 mkU32(0x000000FF) )
6730 )));
6731}
6732
sewardj40d8c092006-05-05 13:26:14 +00006733/* Generates code to swap the byte order in the lower half of an Ity_I32,
6734 and zeroes the upper half. */
6735static IRExpr* /* :: Ity_I32 */ gen_byterev16 ( IRTemp t )
6736{
sewardjdd40fdf2006-12-24 02:20:24 +00006737 vassert(typeOfIRTemp(irsb->tyenv, t) == Ity_I32);
sewardj40d8c092006-05-05 13:26:14 +00006738 return
6739 binop(Iop_Or32,
6740 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t), mkU8(8)),
6741 mkU32(0x0000FF00)),
6742 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t), mkU8(8)),
6743 mkU32(0x000000FF))
6744 );
6745}
6746
sewardj602857d2005-09-06 09:10:09 +00006747static Bool dis_int_ldst_rev ( UInt theInstr )
6748{
6749 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00006750 UChar opc1 = ifieldOPC(theInstr);
6751 UChar rD_addr = ifieldRegDS(theInstr);
6752 UChar rS_addr = rD_addr;
6753 UChar rA_addr = ifieldRegA(theInstr);
6754 UChar rB_addr = ifieldRegB(theInstr);
6755 UInt opc2 = ifieldOPClo10(theInstr);
6756 UChar b0 = ifieldBIT0(theInstr);
cerionedf7fc52005-11-18 20:57:41 +00006757
ceriond953ebb2005-11-29 13:27:20 +00006758 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6759 IRTemp EA = newTemp(ty);
cerionedf7fc52005-11-18 20:57:41 +00006760 IRTemp w1 = newTemp(Ity_I32);
6761 IRTemp w2 = newTemp(Ity_I32);
sewardj602857d2005-09-06 09:10:09 +00006762
6763 if (opc1 != 0x1F || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00006764 vex_printf("dis_int_ldst_rev(ppc)(opc1|b0)\n");
sewardj602857d2005-09-06 09:10:09 +00006765 return False;
6766 }
sewardjafe85832005-09-09 10:25:39 +00006767
ceriond953ebb2005-11-29 13:27:20 +00006768 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
sewardj602857d2005-09-06 09:10:09 +00006769
6770 switch (opc2) {
sewardj40d8c092006-05-05 13:26:14 +00006771
6772 case 0x316: // lhbrx (Load Halfword Byte-Reverse Indexed, PPC32 p449)
6773 DIP("lhbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00006774 assign( w1, unop(Iop_16Uto32, load(Ity_I16, mkexpr(EA))) );
sewardj40d8c092006-05-05 13:26:14 +00006775 assign( w2, gen_byterev16(w1) );
sewardje9d8a262009-07-01 08:06:34 +00006776 putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(w2),
6777 /* Signed */False) );
sewardj40d8c092006-05-05 13:26:14 +00006778 break;
6779
sewardjfb957972005-09-08 17:53:03 +00006780 case 0x216: // lwbrx (Load Word Byte-Reverse Indexed, PPC32 p459)
ceriond953ebb2005-11-29 13:27:20 +00006781 DIP("lwbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00006782 assign( w1, load(Ity_I32, mkexpr(EA)) );
sewardjfb957972005-09-08 17:53:03 +00006783 assign( w2, gen_byterev32(w1) );
sewardje9d8a262009-07-01 08:06:34 +00006784 putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(w2),
6785 /* Signed */False) );
sewardjfb957972005-09-08 17:53:03 +00006786 break;
sewardj66d5ef22011-04-15 11:55:00 +00006787
6788 case 0x214: // ldbrx (Load Doubleword Byte-Reverse Indexed)
6789 {
6790 IRExpr * nextAddr;
6791 IRTemp w3 = newTemp( Ity_I32 );
6792 IRTemp w4 = newTemp( Ity_I32 );
6793 DIP("ldbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00006794 assign( w1, load( Ity_I32, mkexpr( EA ) ) );
sewardj66d5ef22011-04-15 11:55:00 +00006795 assign( w2, gen_byterev32( w1 ) );
6796 nextAddr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
6797 ty == Ity_I64 ? mkU64( 4 ) : mkU32( 4 ) );
carll1f5fe1f2014-08-07 23:25:23 +00006798 assign( w3, load( Ity_I32, nextAddr ) );
sewardj66d5ef22011-04-15 11:55:00 +00006799 assign( w4, gen_byterev32( w3 ) );
carll1f5fe1f2014-08-07 23:25:23 +00006800 if (host_endness == VexEndnessLE)
6801 putIReg( rD_addr, binop( Iop_32HLto64, mkexpr( w2 ), mkexpr( w4 ) ) );
6802 else
6803 putIReg( rD_addr, binop( Iop_32HLto64, mkexpr( w4 ), mkexpr( w2 ) ) );
sewardj66d5ef22011-04-15 11:55:00 +00006804 break;
6805 }
6806
sewardj413a4682006-05-05 13:44:17 +00006807 case 0x396: // sthbrx (Store Half Word Byte-Reverse Indexed, PPC32 p523)
6808 DIP("sthbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
sewardje9d8a262009-07-01 08:06:34 +00006809 assign( w1, mkNarrowTo32(ty, getIReg(rS_addr)) );
carll1f5fe1f2014-08-07 23:25:23 +00006810 store( mkexpr(EA), unop(Iop_32to16, gen_byterev16(w1)) );
sewardj413a4682006-05-05 13:44:17 +00006811 break;
sewardj602857d2005-09-06 09:10:09 +00006812
cerion5b2325f2005-12-23 00:55:09 +00006813 case 0x296: // stwbrx (Store Word Byte-Reverse Indxd, PPC32 p531)
ceriond953ebb2005-11-29 13:27:20 +00006814 DIP("stwbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
sewardje9d8a262009-07-01 08:06:34 +00006815 assign( w1, mkNarrowTo32(ty, getIReg(rS_addr)) );
carll1f5fe1f2014-08-07 23:25:23 +00006816 store( mkexpr(EA), gen_byterev32(w1) );
sewardjfb957972005-09-08 17:53:03 +00006817 break;
sewardj4aa412a2011-07-24 14:13:21 +00006818
6819 case 0x294: // stdbrx (Store Doubleword Byte-Reverse Indexed)
6820 {
6821 IRTemp lo = newTemp(Ity_I32);
6822 IRTemp hi = newTemp(Ity_I32);
6823 IRTemp rS = newTemp(Ity_I64);
6824 assign( rS, getIReg( rS_addr ) );
6825 DIP("stdbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
6826 assign(lo, unop(Iop_64HIto32, mkexpr(rS)));
6827 assign(hi, unop(Iop_64to32, mkexpr(rS)));
carll1f5fe1f2014-08-07 23:25:23 +00006828 store( mkexpr( EA ),
6829 binop( Iop_32HLto64, gen_byterev32( hi ),
6830 gen_byterev32( lo ) ) );
sewardj4aa412a2011-07-24 14:13:21 +00006831 break;
6832 }
6833
sewardjfb957972005-09-08 17:53:03 +00006834 default:
cerion5b2325f2005-12-23 00:55:09 +00006835 vex_printf("dis_int_ldst_rev(ppc)(opc2)\n");
sewardjfb957972005-09-08 17:53:03 +00006836 return False;
sewardj602857d2005-09-06 09:10:09 +00006837 }
6838 return True;
6839}
cerion645c9302005-01-31 10:09:59 +00006840
6841
6842
cerion3d870a32005-03-18 12:23:33 +00006843/*
6844 Processor Control Instructions
6845*/
sewardjdd40fdf2006-12-24 02:20:24 +00006846static Bool dis_proc_ctl ( VexAbiInfo* vbi, UInt theInstr )
cerion8c3adda2005-01-31 11:54:05 +00006847{
cerion76de5cf2005-11-18 18:25:12 +00006848 UChar opc1 = ifieldOPC(theInstr);
cerionb85e8bb2005-02-16 08:54:33 +00006849
6850 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00006851 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
6852 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
6853 UChar rD_addr = ifieldRegDS(theInstr);
6854 UInt b11to20 = IFIELD( theInstr, 11, 10 );
cerione9d361a2005-03-04 17:35:29 +00006855
cerion76de5cf2005-11-18 18:25:12 +00006856 /* XFX-Form */
6857 UChar rS_addr = rD_addr;
6858 UInt SPR = b11to20;
cerionedf7fc52005-11-18 20:57:41 +00006859 UInt TBR = b11to20;
cerion76de5cf2005-11-18 18:25:12 +00006860 UChar b20 = toUChar( IFIELD( theInstr, 20, 1 ) );
6861 UInt CRM = IFIELD( theInstr, 12, 8 );
6862 UChar b11 = toUChar( IFIELD( theInstr, 11, 1 ) );
6863
6864 UInt opc2 = ifieldOPClo10(theInstr);
6865 UChar b0 = ifieldBIT0(theInstr);
6866
cerion2831b002005-11-30 19:55:22 +00006867 IRType ty = mode64 ? Ity_I64 : Ity_I32;
cerionf0de28c2005-12-13 20:21:11 +00006868 IRTemp rS = newTemp(ty);
ceriond953ebb2005-11-29 13:27:20 +00006869 assign( rS, getIReg(rS_addr) );
sewardj41a7b702005-11-18 22:18:23 +00006870
cerion76de5cf2005-11-18 18:25:12 +00006871 /* Reorder SPR field as per PPC32 p470 */
6872 SPR = ((SPR & 0x1F) << 5) | ((SPR >> 5) & 0x1F);
sewardj73a91972005-09-06 10:25:46 +00006873 /* Reorder TBR field as per PPC32 p475 */
6874 TBR = ((TBR & 31) << 5) | ((TBR >> 5) & 31);
cerionb85e8bb2005-02-16 08:54:33 +00006875
carll48ae46b2013-10-01 15:45:54 +00006876 /* b0 = 0, inst is treated as floating point inst for reservation purposes
6877 * b0 = 1, inst is treated as vector inst for reservation purposes
6878 */
6879 if (opc1 != 0x1F) {
6880 vex_printf("dis_proc_ctl(ppc)(opc1|b%d)\n", b0);
cerionb85e8bb2005-02-16 08:54:33 +00006881 return False;
6882 }
6883
6884 switch (opc2) {
cerioncb14e732005-09-09 16:38:19 +00006885 /* X-Form */
cerion5b2325f2005-12-23 00:55:09 +00006886 case 0x200: { // mcrxr (Move to Cond Register from XER, PPC32 p466)
cerioncb14e732005-09-09 16:38:19 +00006887 if (b21to22 != 0 || b11to20 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00006888 vex_printf("dis_proc_ctl(ppc)(mcrxr,b21to22|b11to20)\n");
cerioncb14e732005-09-09 16:38:19 +00006889 return False;
6890 }
6891 DIP("mcrxr crf%d\n", crfD);
cerionedf7fc52005-11-18 20:57:41 +00006892 /* Move XER[0-3] (the top 4 bits of XER) to CR[crfD] */
ceriond953ebb2005-11-29 13:27:20 +00006893 putGST_field( PPC_GST_CR,
6894 getGST_field( PPC_GST_XER, 7 ),
cerionedf7fc52005-11-18 20:57:41 +00006895 crfD );
sewardj55ccc3e2005-09-09 19:45:02 +00006896
6897 // Clear XER[0-3]
cerionedf7fc52005-11-18 20:57:41 +00006898 putXER_SO( mkU8(0) );
6899 putXER_OV( mkU8(0) );
6900 putXER_CA( mkU8(0) );
cerioncb14e732005-09-09 16:38:19 +00006901 break;
sewardj55ccc3e2005-09-09 19:45:02 +00006902 }
cerionb85e8bb2005-02-16 08:54:33 +00006903
sewardj72aefb22006-03-01 18:58:39 +00006904 case 0x013:
6905 // b11to20==0: mfcr (Move from Cond Register, PPC32 p467)
6906 // b20==1 & b11==0: mfocrf (Move from One CR Field)
6907 // However it seems that the 'mfcr' behaviour is an acceptable
6908 // implementation of mfocr (from the 2.02 arch spec)
6909 if (b11to20 == 0) {
6910 DIP("mfcr r%u\n", rD_addr);
sewardje9d8a262009-07-01 08:06:34 +00006911 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_CR ),
6912 /* Signed */False) );
sewardj72aefb22006-03-01 18:58:39 +00006913 break;
cerionb85e8bb2005-02-16 08:54:33 +00006914 }
sewardj72aefb22006-03-01 18:58:39 +00006915 if (b20 == 1 && b11 == 0) {
6916 DIP("mfocrf r%u,%u\n", rD_addr, CRM);
sewardje9d8a262009-07-01 08:06:34 +00006917 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_CR ),
6918 /* Signed */False) );
sewardj72aefb22006-03-01 18:58:39 +00006919 break;
6920 }
6921 /* not decodable */
6922 return False;
carll0c74bb52013-08-12 18:01:40 +00006923
cerionb85e8bb2005-02-16 08:54:33 +00006924 /* XFX-Form */
cerione9d361a2005-03-04 17:35:29 +00006925 case 0x153: // mfspr (Move from Special-Purpose Register, PPC32 p470)
cerionb85e8bb2005-02-16 08:54:33 +00006926
cerion76de5cf2005-11-18 18:25:12 +00006927 switch (SPR) { // Choose a register...
ceriond953ebb2005-11-29 13:27:20 +00006928 case 0x1:
6929 DIP("mfxer r%u\n", rD_addr);
sewardje9d8a262009-07-01 08:06:34 +00006930 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_XER ),
6931 /* Signed */False) );
ceriond953ebb2005-11-29 13:27:20 +00006932 break;
6933 case 0x8:
6934 DIP("mflr r%u\n", rD_addr);
6935 putIReg( rD_addr, getGST( PPC_GST_LR ) );
6936 break;
6937 case 0x9:
6938 DIP("mfctr r%u\n", rD_addr);
6939 putIReg( rD_addr, getGST( PPC_GST_CTR ) );
6940 break;
carll8943d022013-10-02 16:25:57 +00006941 case 0x80: // 128
6942 DIP("mfspr r%u (TFHAR)\n", rD_addr);
6943 putIReg( rD_addr, getGST( PPC_GST_TFHAR) );
6944 break;
6945 case 0x81: // 129
6946 DIP("mfspr r%u (TFIAR)\n", rD_addr);
6947 putIReg( rD_addr, getGST( PPC_GST_TFIAR) );
6948 break;
6949 case 0x82: // 130
6950 DIP("mfspr r%u (TEXASR)\n", rD_addr);
6951 putIReg( rD_addr, getGST( PPC_GST_TEXASR) );
6952 break;
ceriond953ebb2005-11-29 13:27:20 +00006953 case 0x100:
6954 DIP("mfvrsave r%u\n", rD_addr);
sewardje9d8a262009-07-01 08:06:34 +00006955 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_VRSAVE ),
6956 /* Signed */False) );
ceriond953ebb2005-11-29 13:27:20 +00006957 break;
sewardjaca070a2006-10-17 00:28:22 +00006958
6959 case 0x103:
6960 DIP("mfspr r%u, SPRG3(readonly)\n", rD_addr);
6961 putIReg( rD_addr, getGST( PPC_GST_SPRG3_RO ) );
6962 break;
6963
sewardjabb321c2006-12-27 18:39:46 +00006964 /* Even a lowly PPC7400 can run the associated helper, so no
6965 obvious need for feature testing at this point. */
6966 case 268 /* 0x10C */:
6967 case 269 /* 0x10D */: {
6968 UInt arg = SPR==268 ? 0 : 1;
6969 IRTemp val = newTemp(Ity_I32);
6970 IRExpr** args = mkIRExprVec_1( mkU32(arg) );
6971 IRDirty* d = unsafeIRDirty_1_N(
6972 val,
6973 0/*regparms*/,
6974 "ppc32g_dirtyhelper_MFSPR_268_269",
6975 fnptr_to_fnentry
6976 (vbi, &ppc32g_dirtyhelper_MFSPR_268_269),
6977 args
6978 );
6979 /* execute the dirty call, dumping the result in val. */
6980 stmt( IRStmt_Dirty(d) );
sewardj37b2ee82009-08-02 14:35:45 +00006981 putIReg( rD_addr,
6982 mkWidenFrom32(ty, mkexpr(val), False/*unsigned*/) );
6983 DIP("mfspr r%u,%u", rD_addr, (UInt)SPR);
6984 break;
6985 }
6986
6987 /* Again, runs natively on PPC7400 (7447, really). Not
6988 bothering with a feature test. */
6989 case 287: /* 0x11F */ {
6990 IRTemp val = newTemp(Ity_I32);
6991 IRExpr** args = mkIRExprVec_0();
6992 IRDirty* d = unsafeIRDirty_1_N(
6993 val,
6994 0/*regparms*/,
6995 "ppc32g_dirtyhelper_MFSPR_287",
6996 fnptr_to_fnentry
6997 (vbi, &ppc32g_dirtyhelper_MFSPR_287),
6998 args
6999 );
7000 /* execute the dirty call, dumping the result in val. */
7001 stmt( IRStmt_Dirty(d) );
7002 putIReg( rD_addr,
7003 mkWidenFrom32(ty, mkexpr(val), False/*unsigned*/) );
sewardjabb321c2006-12-27 18:39:46 +00007004 DIP("mfspr r%u,%u", rD_addr, (UInt)SPR);
7005 break;
7006 }
7007
ceriond953ebb2005-11-29 13:27:20 +00007008 default:
cerion5b2325f2005-12-23 00:55:09 +00007009 vex_printf("dis_proc_ctl(ppc)(mfspr,SPR)(0x%x)\n", SPR);
ceriond953ebb2005-11-29 13:27:20 +00007010 return False;
cerionb85e8bb2005-02-16 08:54:33 +00007011 }
7012 break;
7013
sewardj73a91972005-09-06 10:25:46 +00007014 case 0x173: { // mftb (Move from Time Base, PPC32 p475)
7015 IRTemp val = newTemp(Ity_I64);
7016 IRExpr** args = mkIRExprVec_0();
cerion4c4f5ef2006-01-02 14:41:50 +00007017 IRDirty* d = unsafeIRDirty_1_N(
7018 val,
7019 0/*regparms*/,
7020 "ppcg_dirtyhelper_MFTB",
sewardjdd40fdf2006-12-24 02:20:24 +00007021 fnptr_to_fnentry(vbi, &ppcg_dirtyhelper_MFTB),
cerion4c4f5ef2006-01-02 14:41:50 +00007022 args );
sewardj73a91972005-09-06 10:25:46 +00007023 /* execute the dirty call, dumping the result in val. */
7024 stmt( IRStmt_Dirty(d) );
7025
7026 switch (TBR) {
ceriond953ebb2005-11-29 13:27:20 +00007027 case 269:
ceriond953ebb2005-11-29 13:27:20 +00007028 DIP("mftbu r%u", rD_addr);
cerion2831b002005-11-30 19:55:22 +00007029 putIReg( rD_addr,
sewardje9d8a262009-07-01 08:06:34 +00007030 mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(val)),
7031 /* Signed */False) );
ceriond953ebb2005-11-29 13:27:20 +00007032 break;
7033 case 268:
ceriond953ebb2005-11-29 13:27:20 +00007034 DIP("mftb r%u", rD_addr);
cerion2831b002005-11-30 19:55:22 +00007035 putIReg( rD_addr, (mode64) ? mkexpr(val) :
7036 unop(Iop_64to32, mkexpr(val)) );
ceriond953ebb2005-11-29 13:27:20 +00007037 break;
7038 default:
7039 return False; /* illegal instruction */
sewardj73a91972005-09-06 10:25:46 +00007040 }
7041 break;
7042 }
7043
sewardj72aefb22006-03-01 18:58:39 +00007044 case 0x090: {
7045 // b20==0: mtcrf (Move to Cond Register Fields, PPC32 p477)
7046 // b20==1: mtocrf (Move to One Cond Reg Field)
cerionedf7fc52005-11-18 20:57:41 +00007047 Int cr;
7048 UChar shft;
sewardj72aefb22006-03-01 18:58:39 +00007049 if (b11 != 0)
cerionb85e8bb2005-02-16 08:54:33 +00007050 return False;
sewardj72aefb22006-03-01 18:58:39 +00007051 if (b20 == 1) {
7052 /* ppc64 v2.02 spec says mtocrf gives undefined outcome if >
7053 1 field is written. It seems more robust to decline to
7054 decode the insn if so. */
7055 switch (CRM) {
7056 case 0x01: case 0x02: case 0x04: case 0x08:
7057 case 0x10: case 0x20: case 0x40: case 0x80:
7058 break;
7059 default:
7060 return False;
7061 }
cerionb85e8bb2005-02-16 08:54:33 +00007062 }
sewardj72aefb22006-03-01 18:58:39 +00007063 DIP("%s 0x%x,r%u\n", b20==1 ? "mtocrf" : "mtcrf",
7064 CRM, rS_addr);
cerionedf7fc52005-11-18 20:57:41 +00007065 /* Write to each field specified by CRM */
7066 for (cr = 0; cr < 8; cr++) {
7067 if ((CRM & (1 << (7-cr))) == 0)
7068 continue;
7069 shft = 4*(7-cr);
ceriond953ebb2005-11-29 13:27:20 +00007070 putGST_field( PPC_GST_CR,
cerion2831b002005-11-30 19:55:22 +00007071 binop(Iop_Shr32,
sewardje9d8a262009-07-01 08:06:34 +00007072 mkNarrowTo32(ty, mkexpr(rS)),
cerion2831b002005-11-30 19:55:22 +00007073 mkU8(shft)), cr );
cerionedf7fc52005-11-18 20:57:41 +00007074 }
cerionb85e8bb2005-02-16 08:54:33 +00007075 break;
cerionedf7fc52005-11-18 20:57:41 +00007076 }
cerione9d361a2005-03-04 17:35:29 +00007077
7078 case 0x1D3: // mtspr (Move to Special-Purpose Register, PPC32 p483)
cerionb85e8bb2005-02-16 08:54:33 +00007079
cerion76de5cf2005-11-18 18:25:12 +00007080 switch (SPR) { // Choose a register...
ceriond953ebb2005-11-29 13:27:20 +00007081 case 0x1:
7082 DIP("mtxer r%u\n", rS_addr);
sewardje9d8a262009-07-01 08:06:34 +00007083 putGST( PPC_GST_XER, mkNarrowTo32(ty, mkexpr(rS)) );
ceriond953ebb2005-11-29 13:27:20 +00007084 break;
7085 case 0x8:
7086 DIP("mtlr r%u\n", rS_addr);
7087 putGST( PPC_GST_LR, mkexpr(rS) );
7088 break;
7089 case 0x9:
7090 DIP("mtctr r%u\n", rS_addr);
7091 putGST( PPC_GST_CTR, mkexpr(rS) );
7092 break;
7093 case 0x100:
7094 DIP("mtvrsave r%u\n", rS_addr);
sewardje9d8a262009-07-01 08:06:34 +00007095 putGST( PPC_GST_VRSAVE, mkNarrowTo32(ty, mkexpr(rS)) );
ceriond953ebb2005-11-29 13:27:20 +00007096 break;
carll8943d022013-10-02 16:25:57 +00007097 case 0x80: // 128
7098 DIP("mtspr r%u (TFHAR)\n", rS_addr);
7099 putGST( PPC_GST_TFHAR, mkexpr(rS) );
7100 break;
7101 case 0x81: // 129
7102 DIP("mtspr r%u (TFIAR)\n", rS_addr);
7103 putGST( PPC_GST_TFIAR, mkexpr(rS) );
7104 break;
7105 case 0x82: // 130
7106 DIP("mtspr r%u (TEXASR)\n", rS_addr);
7107 putGST( PPC_GST_TEXASR, mkexpr(rS) );
7108 break;
ceriond953ebb2005-11-29 13:27:20 +00007109 default:
cerion5b2325f2005-12-23 00:55:09 +00007110 vex_printf("dis_proc_ctl(ppc)(mtspr,SPR)(%u)\n", SPR);
ceriond953ebb2005-11-29 13:27:20 +00007111 return False;
cerionb85e8bb2005-02-16 08:54:33 +00007112 }
7113 break;
carll0c74bb52013-08-12 18:01:40 +00007114
7115 case 0x33: // mfvsrd
7116 {
7117 UChar XS = ifieldRegXS( theInstr );
7118 UChar rA_addr = ifieldRegA(theInstr);
7119 IRExpr * high64;
7120 IRTemp vS = newTemp( Ity_V128 );
7121 DIP("mfvsrd r%u,vsr%d\n", rA_addr, (UInt)XS);
7122
7123 /* XS = SX || S
7124 * For SX=0, mfvsrd is treated as a Floating-Point
7125 * instruction in terms of resource availability.
7126 * For SX=1, mfvsrd is treated as a Vector instruction in
7127 * terms of resource availability.
carll78850ae2013-09-10 18:46:40 +00007128 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
carll0c74bb52013-08-12 18:01:40 +00007129 */
7130 assign( vS, getVSReg( XS ) );
7131 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
7132 putIReg( rA_addr, (mode64) ? high64 :
7133 unop( Iop_64to32, high64 ) );
7134 break;
7135 }
7136
carll78850ae2013-09-10 18:46:40 +00007137 case 0x73: // mfvsrwz
7138 {
7139 UChar XS = ifieldRegXS( theInstr );
7140 UChar rA_addr = ifieldRegA(theInstr);
7141 IRExpr * high64;
7142 IRTemp vS = newTemp( Ity_V128 );
7143 DIP("mfvsrwz r%u,vsr%d\n", rA_addr, (UInt)XS);
7144 /* XS = SX || S
7145 * For SX=0, mfvsrwz is treated as a Floating-Point
7146 * instruction in terms of resource availability.
7147 * For SX=1, mfvsrwz is treated as a Vector instruction in
7148 * terms of resource availability.
7149 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
7150 */
7151
7152 assign( vS, getVSReg( XS ) );
7153 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
7154 /* move value to the destination setting the upper 32-bits to zero */
7155 putIReg( rA_addr, (mode64) ?
7156 binop( Iop_And64, high64, mkU64( 0xFFFFFFFF ) ) :
7157 unop( Iop_64to32,
7158 binop( Iop_And64, high64, mkU64( 0xFFFFFFFF ) ) ) );
7159 break;
7160 }
7161
carll0c74bb52013-08-12 18:01:40 +00007162 case 0xB3: // mtvsrd
7163 {
7164 UChar XT = ifieldRegXT( theInstr );
7165 UChar rA_addr = ifieldRegA(theInstr);
7166 IRTemp rA = newTemp(ty);
7167 DIP("mtvsrd vsr%d,r%u\n", (UInt)XT, rA_addr);
7168 /* XS = SX || S
7169 * For SX=0, mfvsrd is treated as a Floating-Point
7170 * instruction in terms of resource availability.
7171 * For SX=1, mfvsrd is treated as a Vector instruction in
7172 * terms of resource availability.
carll78850ae2013-09-10 18:46:40 +00007173 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
carll0c74bb52013-08-12 18:01:40 +00007174 */
7175 assign( rA, getIReg(rA_addr) );
7176
7177 if (mode64)
7178 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( rA ), mkU64( 0 ) ) );
7179 else
7180 putVSReg( XT, binop( Iop_64HLtoV128,
7181 binop( Iop_32HLto64,
7182 mkU32( 0 ),
7183 mkexpr( rA ) ),
7184 mkU64( 0 ) ) );
7185 break;
7186 }
7187
7188 case 0xD3: // mtvsrwa
7189 {
7190 UChar XT = ifieldRegXT( theInstr );
7191 UChar rA_addr = ifieldRegA(theInstr);
7192 IRTemp rA = newTemp( Ity_I32 );
7193 DIP("mtvsrwa vsr%d,r%u\n", (UInt)XT, rA_addr);
7194 /* XS = SX || S
7195 * For SX=0, mtvsrwa is treated as a Floating-Point
7196 * instruction in terms of resource availability.
7197 * For SX=1, mtvsrwa is treated as a Vector instruction in
7198 * terms of resource availability.
carll78850ae2013-09-10 18:46:40 +00007199 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
carll0c74bb52013-08-12 18:01:40 +00007200 */
7201 if (mode64)
7202 assign( rA, unop( Iop_64to32, getIReg( rA_addr ) ) );
7203 else
7204 assign( rA, getIReg(rA_addr) );
7205
7206 putVSReg( XT, binop( Iop_64HLtoV128,
7207 unop( Iop_32Sto64, mkexpr( rA ) ),
7208 mkU64( 0 ) ) );
7209 break;
7210 }
7211
carll78850ae2013-09-10 18:46:40 +00007212 case 0xF3: // mtvsrwz
7213 {
7214 UChar XT = ifieldRegXT( theInstr );
7215 UChar rA_addr = ifieldRegA(theInstr);
7216 IRTemp rA = newTemp( Ity_I32 );
7217 DIP("mtvsrwz vsr%d,r%u\n", rA_addr, (UInt)XT);
7218 /* XS = SX || S
7219 * For SX=0, mtvsrwz is treated as a Floating-Point
7220 * instruction in terms of resource availability.
7221 * For SX=1, mtvsrwz is treated as a Vector instruction in
7222 * terms of resource availability.
7223 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
7224 */
7225 if (mode64)
7226 assign( rA, unop( Iop_64to32, getIReg( rA_addr ) ) );
7227 else
7228 assign( rA, getIReg(rA_addr) );
7229
7230 putVSReg( XT, binop( Iop_64HLtoV128,
7231 binop( Iop_32HLto64, mkU32( 0 ), mkexpr ( rA ) ),
7232 mkU64( 0 ) ) );
7233 break;
7234 }
7235
cerionb85e8bb2005-02-16 08:54:33 +00007236 default:
cerion5b2325f2005-12-23 00:55:09 +00007237 vex_printf("dis_proc_ctl(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00007238 return False;
7239 }
7240 return True;
cerion8c3adda2005-01-31 11:54:05 +00007241}
7242
7243
cerion3d870a32005-03-18 12:23:33 +00007244/*
7245 Cache Management Instructions
7246*/
sewardjd94b73a2005-06-30 12:08:48 +00007247static Bool dis_cache_manage ( UInt theInstr,
sewardj9e6491a2005-07-02 19:24:10 +00007248 DisResult* dres,
sewardjd94b73a2005-06-30 12:08:48 +00007249 VexArchInfo* guest_archinfo )
cerion8c3adda2005-01-31 11:54:05 +00007250{
cerionb85e8bb2005-02-16 08:54:33 +00007251 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00007252 UChar opc1 = ifieldOPC(theInstr);
7253 UChar b21to25 = ifieldRegDS(theInstr);
7254 UChar rA_addr = ifieldRegA(theInstr);
7255 UChar rB_addr = ifieldRegB(theInstr);
7256 UInt opc2 = ifieldOPClo10(theInstr);
7257 UChar b0 = ifieldBIT0(theInstr);
florian9138b172013-08-03 19:36:55 +00007258 UInt lineszB = guest_archinfo->ppc_icache_line_szB;
sewardje971c6a2010-09-03 15:49:57 +00007259 Bool is_dcbzl = False;
ceriond953ebb2005-11-29 13:27:20 +00007260
7261 IRType ty = mode64 ? Ity_I64 : Ity_I32;
cerion094d1392005-06-20 13:45:57 +00007262
carllb77db0e2013-09-05 19:47:40 +00007263 // Check for valid hint values for dcbt and dcbtst as currently described in
7264 // ISA 2.07. If valid, then we simply set b21to25 to zero since we have no
7265 // means of modeling the hint anyway.
7266 if (opc1 == 0x1F && ((opc2 == 0x116) || (opc2 == 0xF6))) {
carll9708b6a2013-09-06 16:49:42 +00007267 if (b21to25 == 0x10 || b21to25 < 0x10)
carllb77db0e2013-09-05 19:47:40 +00007268 b21to25 = 0;
sewardj6be67232006-01-24 19:00:05 +00007269 }
carll9708b6a2013-09-06 16:49:42 +00007270 if (opc1 == 0x1F && opc2 == 0x116 && b21to25 == 0x11)
carllb77db0e2013-09-05 19:47:40 +00007271 b21to25 = 0;
7272
sewardje971c6a2010-09-03 15:49:57 +00007273 if (opc1 == 0x1F && opc2 == 0x3F6) { // dcbz
7274 if (b21to25 == 1) {
7275 is_dcbzl = True;
7276 b21to25 = 0;
7277 if (!(guest_archinfo->ppc_dcbzl_szB)) {
7278 vex_printf("dis_cache_manage(ppc)(dcbzl not supported by host)\n");
7279 return False;
7280 }
7281 }
7282 }
sewardj6be67232006-01-24 19:00:05 +00007283
cerionb85e8bb2005-02-16 08:54:33 +00007284 if (opc1 != 0x1F || b21to25 != 0 || b0 != 0) {
sewardj6be67232006-01-24 19:00:05 +00007285 if (0) vex_printf("dis_cache_manage %d %d %d\n",
7286 (Int)opc1, (Int)b21to25, (Int)b0);
cerion5b2325f2005-12-23 00:55:09 +00007287 vex_printf("dis_cache_manage(ppc)(opc1|b21to25|b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00007288 return False;
7289 }
sewardjd94b73a2005-06-30 12:08:48 +00007290
7291 /* stay sane .. */
sewardj2691a612013-10-14 11:40:24 +00007292 vassert(lineszB == 16 || lineszB == 32 || lineszB == 64 || lineszB == 128);
cerionb85e8bb2005-02-16 08:54:33 +00007293
7294 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00007295//zz case 0x2F6: // dcba (Data Cache Block Allocate, PPC32 p380)
7296//zz vassert(0); /* AWAITING TEST CASE */
ceriond953ebb2005-11-29 13:27:20 +00007297//zz DIP("dcba r%u,r%u\n", rA_addr, rB_addr);
cerion5b2325f2005-12-23 00:55:09 +00007298//zz if (0) vex_printf("vex ppc->IR: kludged dcba\n");
sewardjb51f0f42005-07-18 11:38:02 +00007299//zz break;
sewardj20ef5472005-07-21 14:48:31 +00007300
7301 case 0x056: // dcbf (Data Cache Block Flush, PPC32 p382)
ceriond953ebb2005-11-29 13:27:20 +00007302 DIP("dcbf r%u,r%u\n", rA_addr, rB_addr);
sewardj20ef5472005-07-21 14:48:31 +00007303 /* nop as far as vex is concerned */
sewardj20ef5472005-07-21 14:48:31 +00007304 break;
cerionb85e8bb2005-02-16 08:54:33 +00007305
cerione9d361a2005-03-04 17:35:29 +00007306 case 0x036: // dcbst (Data Cache Block Store, PPC32 p384)
ceriond953ebb2005-11-29 13:27:20 +00007307 DIP("dcbst r%u,r%u\n", rA_addr, rB_addr);
sewardjb51f0f42005-07-18 11:38:02 +00007308 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00007309 break;
cerion8c3adda2005-01-31 11:54:05 +00007310
cerione9d361a2005-03-04 17:35:29 +00007311 case 0x116: // dcbt (Data Cache Block Touch, PPC32 p385)
ceriond953ebb2005-11-29 13:27:20 +00007312 DIP("dcbt r%u,r%u\n", rA_addr, rB_addr);
sewardjb51f0f42005-07-18 11:38:02 +00007313 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00007314 break;
7315
cerione9d361a2005-03-04 17:35:29 +00007316 case 0x0F6: // dcbtst (Data Cache Block Touch for Store, PPC32 p386)
ceriond953ebb2005-11-29 13:27:20 +00007317 DIP("dcbtst r%u,r%u\n", rA_addr, rB_addr);
sewardjb51f0f42005-07-18 11:38:02 +00007318 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00007319 break;
7320
cerion094d1392005-06-20 13:45:57 +00007321 case 0x3F6: { // dcbz (Data Cache Block Clear to Zero, PPC32 p387)
sewardje971c6a2010-09-03 15:49:57 +00007322 // dcbzl (Data Cache Block Clear to Zero Long, bug#135264)
sewardjd94b73a2005-06-30 12:08:48 +00007323 /* Clear all bytes in cache block at (rA|0) + rB. */
cerion2831b002005-11-30 19:55:22 +00007324 IRTemp EA = newTemp(ty);
7325 IRTemp addr = newTemp(ty);
cerion094d1392005-06-20 13:45:57 +00007326 IRExpr* irx_addr;
cerion094d1392005-06-20 13:45:57 +00007327 UInt i;
sewardje971c6a2010-09-03 15:49:57 +00007328 UInt clearszB;
7329 if (is_dcbzl) {
7330 clearszB = guest_archinfo->ppc_dcbzl_szB;
7331 DIP("dcbzl r%u,r%u\n", rA_addr, rB_addr);
7332 }
7333 else {
7334 clearszB = guest_archinfo->ppc_dcbz_szB;
7335 DIP("dcbz r%u,r%u\n", rA_addr, rB_addr);
7336 }
sewardjcb1f68e2005-12-30 03:39:14 +00007337
ceriond953ebb2005-11-29 13:27:20 +00007338 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
cerion094d1392005-06-20 13:45:57 +00007339
cerion2831b002005-11-30 19:55:22 +00007340 if (mode64) {
7341 /* Round EA down to the start of the containing block. */
7342 assign( addr, binop( Iop_And64,
7343 mkexpr(EA),
sewardje971c6a2010-09-03 15:49:57 +00007344 mkU64( ~((ULong)clearszB-1) )) );
cerion2831b002005-11-30 19:55:22 +00007345
sewardje971c6a2010-09-03 15:49:57 +00007346 for (i = 0; i < clearszB / 8; i++) {
cerion2831b002005-11-30 19:55:22 +00007347 irx_addr = binop( Iop_Add64, mkexpr(addr), mkU64(i*8) );
carll1f5fe1f2014-08-07 23:25:23 +00007348 store( irx_addr, mkU64(0) );
cerion2831b002005-11-30 19:55:22 +00007349 }
7350 } else {
7351 /* Round EA down to the start of the containing block. */
7352 assign( addr, binop( Iop_And32,
7353 mkexpr(EA),
sewardje971c6a2010-09-03 15:49:57 +00007354 mkU32( ~(clearszB-1) )) );
cerion2831b002005-11-30 19:55:22 +00007355
sewardje971c6a2010-09-03 15:49:57 +00007356 for (i = 0; i < clearszB / 4; i++) {
cerion2831b002005-11-30 19:55:22 +00007357 irx_addr = binop( Iop_Add32, mkexpr(addr), mkU32(i*4) );
carll1f5fe1f2014-08-07 23:25:23 +00007358 store( irx_addr, mkU32(0) );
cerion2831b002005-11-30 19:55:22 +00007359 }
cerion094d1392005-06-20 13:45:57 +00007360 }
cerionb85e8bb2005-02-16 08:54:33 +00007361 break;
cerion094d1392005-06-20 13:45:57 +00007362 }
cerion8c3adda2005-01-31 11:54:05 +00007363
sewardj7ce9d152005-03-15 16:54:13 +00007364 case 0x3D6: {
7365 // icbi (Instruction Cache Block Invalidate, PPC32 p431)
7366 /* Invalidate all translations containing code from the cache
sewardjd94b73a2005-06-30 12:08:48 +00007367 block at (rA|0) + rB. */
ceriond953ebb2005-11-29 13:27:20 +00007368 IRTemp EA = newTemp(ty);
7369 IRTemp addr = newTemp(ty);
7370 DIP("icbi r%u,r%u\n", rA_addr, rB_addr);
7371 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
sewardj7ce9d152005-03-15 16:54:13 +00007372
cerion2831b002005-11-30 19:55:22 +00007373 /* Round EA down to the start of the containing block. */
7374 assign( addr, binop( mkSzOp(ty, Iop_And8),
ceriond953ebb2005-11-29 13:27:20 +00007375 mkexpr(EA),
cerion2831b002005-11-30 19:55:22 +00007376 mkSzImm(ty, ~(((ULong)lineszB)-1) )) );
sewardj05f5e012014-05-04 10:52:11 +00007377 putGST( PPC_GST_CMSTART, mkexpr(addr) );
7378 putGST( PPC_GST_CMLEN, mkSzImm(ty, lineszB) );
sewardj7ce9d152005-03-15 16:54:13 +00007379
sewardja8078f62005-03-15 18:27:40 +00007380 /* be paranoid ... */
sewardjc4356f02007-11-09 21:15:04 +00007381 stmt( IRStmt_MBE(Imbe_Fence) );
sewardja8078f62005-03-15 18:27:40 +00007382
sewardj3dee8492012-04-20 00:13:28 +00007383 putGST( PPC_GST_CIA, mkSzImm(ty, nextInsnAddr()));
sewardj05f5e012014-05-04 10:52:11 +00007384 dres->jk_StopHere = Ijk_InvalICache;
sewardj3dee8492012-04-20 00:13:28 +00007385 dres->whatNext = Dis_StopHere;
cerionb85e8bb2005-02-16 08:54:33 +00007386 break;
sewardj7ce9d152005-03-15 16:54:13 +00007387 }
cerion8c3adda2005-01-31 11:54:05 +00007388
cerionb85e8bb2005-02-16 08:54:33 +00007389 default:
cerion5b2325f2005-12-23 00:55:09 +00007390 vex_printf("dis_cache_manage(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00007391 return False;
7392 }
7393 return True;
cerion8c3adda2005-01-31 11:54:05 +00007394}
7395
7396
sewardje14bb9f2005-07-22 09:39:02 +00007397/*------------------------------------------------------------*/
7398/*--- Floating Point Helpers ---*/
7399/*------------------------------------------------------------*/
7400
sewardje14bb9f2005-07-22 09:39:02 +00007401/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
7402/* Produces a value in 0 .. 3, which is encoded as per the type
cerion5b2325f2005-12-23 00:55:09 +00007403 IRRoundingMode. PPCRoundingMode encoding is different to
sewardje14bb9f2005-07-22 09:39:02 +00007404 IRRoundingMode, so need to map it.
7405*/
sewardjb183b852006-02-03 16:08:03 +00007406static IRExpr* /* :: Ity_I32 */ get_IR_roundingmode ( void )
sewardje14bb9f2005-07-22 09:39:02 +00007407{
7408/*
7409 rounding mode | PPC | IR
7410 ------------------------
7411 to nearest | 00 | 00
7412 to zero | 01 | 11
7413 to +infinity | 10 | 10
7414 to -infinity | 11 | 01
7415*/
7416 IRTemp rm_PPC32 = newTemp(Ity_I32);
ceriond953ebb2005-11-29 13:27:20 +00007417 assign( rm_PPC32, getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN ) );
sewardje14bb9f2005-07-22 09:39:02 +00007418
7419 // rm_IR = XOR( rm_PPC32, (rm_PPC32 << 1) & 2)
sewardjb183b852006-02-03 16:08:03 +00007420 return binop( Iop_Xor32,
7421 mkexpr(rm_PPC32),
7422 binop( Iop_And32,
7423 binop(Iop_Shl32, mkexpr(rm_PPC32), mkU8(1)),
7424 mkU32(2) ));
sewardje14bb9f2005-07-22 09:39:02 +00007425}
cerion094d1392005-06-20 13:45:57 +00007426
sewardjc6bbd472012-04-02 10:20:48 +00007427/* The DFP IR rounding modes were chosen such that the existing PPC to IR
7428 * mapping would still work with the extended three bit DFP rounding
7429 * mode designator.
7430
7431 * rounding mode | PPC | IR
7432 * -----------------------------------------------
7433 * to nearest, ties to even | 000 | 000
7434 * to zero | 001 | 011
7435 * to +infinity | 010 | 010
7436 * to -infinity | 011 | 001
7437 * to nearest, ties away from 0 | 100 | 100
7438 * to nearest, ties toward 0 | 101 | 111
7439 * to away from 0 | 110 | 110
7440 * to prepare for shorter precision | 111 | 101
7441 */
7442static IRExpr* /* :: Ity_I32 */ get_IR_roundingmode_DFP( void )
7443{
7444 IRTemp rm_PPC32 = newTemp( Ity_I32 );
7445 assign( rm_PPC32, getGST_masked_upper( PPC_GST_FPSCR, MASK_FPSCR_DRN ) );
7446
7447 // rm_IR = XOR( rm_PPC32, (rm_PPC32 << 1) & 2)
7448 return binop( Iop_Xor32,
7449 mkexpr( rm_PPC32 ),
7450 binop( Iop_And32,
7451 binop( Iop_Shl32, mkexpr( rm_PPC32 ), mkU8( 1 ) ),
7452 mkU32( 2 ) ) );
7453}
cerion094d1392005-06-20 13:45:57 +00007454
sewardj2bcdd652012-07-14 08:22:13 +00007455#define NANmaskSingle 0x7F800000
7456#define NANmaskDouble 0x7FF00000
7457
7458static IRExpr * Check_NaN( IRExpr * value, IRExpr * Hi32Mask )
7459{
7460 IRTemp exp_zero = newTemp(Ity_I8);
7461 IRTemp frac_mask = newTemp(Ity_I32);
7462 IRTemp frac_not_zero = newTemp(Ity_I8);
7463
7464 /* Check if the result is QNAN or SNAN and not +infinity or -infinity.
7465 * The input value is always 64-bits, for single precision values, the
7466 * lower 32 bits must be zero.
7467 *
7468 * Single Pricision
7469 * [62:54] exponent field is equal to 0xFF for NAN and Infinity.
7470 * [53:32] fraction field is zero for Infinity and non-zero for NAN
7471 * [31:0] unused for single precision representation
7472 *
7473 * Double Pricision
7474 * [62:51] exponent field is equal to 0xFF for NAN and Infinity.
7475 * [50:0] fraction field is zero for Infinity and non-zero for NAN
7476 *
7477 * Returned result is a U32 value of 0xFFFFFFFF for NaN and 0 otherwise.
7478 */
7479 assign( frac_mask, unop( Iop_Not32,
7480 binop( Iop_Or32,
7481 mkU32( 0x80000000ULL ), Hi32Mask) ) );
7482
7483 assign( exp_zero,
7484 unop( Iop_1Sto8,
7485 binop( Iop_CmpEQ32,
7486 binop( Iop_And32,
7487 unop( Iop_64HIto32,
7488 unop( Iop_ReinterpF64asI64,
7489 value ) ),
7490 Hi32Mask ),
7491 Hi32Mask ) ) );
7492 assign( frac_not_zero,
7493 binop( Iop_Or8,
7494 unop( Iop_1Sto8,
7495 binop( Iop_CmpNE32,
7496 binop( Iop_And32,
7497 unop( Iop_64HIto32,
7498 unop( Iop_ReinterpF64asI64,
7499 value ) ),
7500 mkexpr( frac_mask ) ),
7501 mkU32( 0x0 ) ) ),
7502 unop( Iop_1Sto8,
7503 binop( Iop_CmpNE32,
7504 binop( Iop_And32,
7505 unop( Iop_64to32,
7506 unop( Iop_ReinterpF64asI64,
7507 value ) ),
7508 mkU32( 0xFFFFFFFF ) ),
7509 mkU32( 0x0 ) ) ) ) );
7510 return unop( Iop_8Sto32,
7511 binop( Iop_And8,
7512 mkexpr( exp_zero ),
7513 mkexpr( frac_not_zero ) ) );
7514}
7515
7516static IRExpr * Complement_non_NaN( IRExpr * value, IRExpr * nan_mask )
7517{
7518 /* This function will only complement the 64-bit floating point value if it
7519 * is not Nan. NaN is not a signed value. Need to do computations using
7520 * 32-bit operands to ensure it will run in 32-bit mode.
7521 */
7522 return binop( Iop_32HLto64,
7523 binop( Iop_Or32,
7524 binop( Iop_And32,
7525 nan_mask,
7526 unop( Iop_64HIto32,
7527 unop( Iop_ReinterpF64asI64,
7528 value ) ) ),
7529 binop( Iop_And32,
7530 unop( Iop_Not32,
7531 nan_mask ),
7532 unop( Iop_64HIto32,
7533 unop( Iop_ReinterpF64asI64,
7534 unop( Iop_NegF64,
7535 value ) ) ) ) ),
7536 unop( Iop_64to32,
7537 unop( Iop_ReinterpF64asI64, value ) ) );
7538}
7539
cerion3d870a32005-03-18 12:23:33 +00007540/*------------------------------------------------------------*/
7541/*--- Floating Point Instruction Translation ---*/
7542/*------------------------------------------------------------*/
7543
7544/*
7545 Floating Point Load Instructions
7546*/
7547static Bool dis_fp_load ( UInt theInstr )
7548{
cerion76de5cf2005-11-18 18:25:12 +00007549 /* X-Form, D-Form */
7550 UChar opc1 = ifieldOPC(theInstr);
7551 UChar frD_addr = ifieldRegDS(theInstr);
7552 UChar rA_addr = ifieldRegA(theInstr);
7553 UChar rB_addr = ifieldRegB(theInstr);
7554 UInt opc2 = ifieldOPClo10(theInstr);
7555 UChar b0 = ifieldBIT0(theInstr);
cerion2831b002005-11-30 19:55:22 +00007556 UInt uimm16 = ifieldUIMM16(theInstr);
cerion094d1392005-06-20 13:45:57 +00007557
cerion2831b002005-11-30 19:55:22 +00007558 Int simm16 = extend_s_16to32(uimm16);
7559 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7560 IRTemp EA = newTemp(ty);
7561 IRTemp rA = newTemp(ty);
7562 IRTemp rB = newTemp(ty);
sewardj7e846302010-09-03 23:37:02 +00007563 IRTemp iHi = newTemp(Ity_I32);
7564 IRTemp iLo = newTemp(Ity_I32);
cerion094d1392005-06-20 13:45:57 +00007565
7566 assign( rA, getIReg(rA_addr) );
7567 assign( rB, getIReg(rB_addr) );
ceriond953ebb2005-11-29 13:27:20 +00007568
sewardjb183b852006-02-03 16:08:03 +00007569 /* These are completely straightforward from a rounding and status
7570 bits perspective: no rounding involved and no funny status or CR
7571 bits affected. */
cerion3d870a32005-03-18 12:23:33 +00007572
sewardjb183b852006-02-03 16:08:03 +00007573 switch (opc1) {
sewardje14bb9f2005-07-22 09:39:02 +00007574 case 0x30: // lfs (Load Float Single, PPC32 p441)
ceriond953ebb2005-11-29 13:27:20 +00007575 DIP("lfs fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
7576 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
cerion5b2325f2005-12-23 00:55:09 +00007577 putFReg( frD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00007578 unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
sewardje14bb9f2005-07-22 09:39:02 +00007579 break;
7580
cerion5b2325f2005-12-23 00:55:09 +00007581 case 0x31: // lfsu (Load Float Single, Update, PPC32 p442)
sewardjb183b852006-02-03 16:08:03 +00007582 if (rA_addr == 0)
cerion729edb72005-12-02 16:03:46 +00007583 return False;
cerion729edb72005-12-02 16:03:46 +00007584 DIP("lfsu fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
7585 assign( EA, ea_rA_simm(rA_addr, simm16) );
cerion5b2325f2005-12-23 00:55:09 +00007586 putFReg( frD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00007587 unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
cerion729edb72005-12-02 16:03:46 +00007588 putIReg( rA_addr, mkexpr(EA) );
7589 break;
cerion094d1392005-06-20 13:45:57 +00007590
7591 case 0x32: // lfd (Load Float Double, PPC32 p437)
ceriond953ebb2005-11-29 13:27:20 +00007592 DIP("lfd fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
7593 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
carll1f5fe1f2014-08-07 23:25:23 +00007594 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
cerion094d1392005-06-20 13:45:57 +00007595 break;
cerion3d870a32005-03-18 12:23:33 +00007596
cerion5b2325f2005-12-23 00:55:09 +00007597 case 0x33: // lfdu (Load Float Double, Update, PPC32 p438)
sewardjb183b852006-02-03 16:08:03 +00007598 if (rA_addr == 0)
sewardj0e2cc672005-07-29 21:58:51 +00007599 return False;
ceriond953ebb2005-11-29 13:27:20 +00007600 DIP("lfdu fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
7601 assign( EA, ea_rA_simm(rA_addr, simm16) );
carll1f5fe1f2014-08-07 23:25:23 +00007602 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
sewardj0e2cc672005-07-29 21:58:51 +00007603 putIReg( rA_addr, mkexpr(EA) );
7604 break;
sewardje14bb9f2005-07-22 09:39:02 +00007605
7606 case 0x1F:
7607 if (b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00007608 vex_printf("dis_fp_load(ppc)(instr,b0)\n");
sewardje14bb9f2005-07-22 09:39:02 +00007609 return False;
7610 }
7611
7612 switch(opc2) {
ceriond953ebb2005-11-29 13:27:20 +00007613 case 0x217: // lfsx (Load Float Single Indexed, PPC32 p444)
7614 DIP("lfsx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
7615 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
7616 putFReg( frD_addr, unop( Iop_F32toF64,
carll1f5fe1f2014-08-07 23:25:23 +00007617 load(Ity_F32, mkexpr(EA))) );
ceriond953ebb2005-11-29 13:27:20 +00007618 break;
7619
cerion5b2325f2005-12-23 00:55:09 +00007620 case 0x237: // lfsux (Load Float Single, Update Indxd, PPC32 p443)
sewardjb183b852006-02-03 16:08:03 +00007621 if (rA_addr == 0)
sewardje14bb9f2005-07-22 09:39:02 +00007622 return False;
ceriond953ebb2005-11-29 13:27:20 +00007623 DIP("lfsux fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
7624 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
cerion5b2325f2005-12-23 00:55:09 +00007625 putFReg( frD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00007626 unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
ceriond953ebb2005-11-29 13:27:20 +00007627 putIReg( rA_addr, mkexpr(EA) );
7628 break;
7629
7630 case 0x257: // lfdx (Load Float Double Indexed, PPC32 p440)
7631 DIP("lfdx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
7632 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
carll1f5fe1f2014-08-07 23:25:23 +00007633 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
ceriond953ebb2005-11-29 13:27:20 +00007634 break;
7635
cerion5b2325f2005-12-23 00:55:09 +00007636 case 0x277: // lfdux (Load Float Double, Update Indxd, PPC32 p439)
sewardjb183b852006-02-03 16:08:03 +00007637 if (rA_addr == 0)
ceriond953ebb2005-11-29 13:27:20 +00007638 return False;
ceriond953ebb2005-11-29 13:27:20 +00007639 DIP("lfdux fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
7640 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
carll1f5fe1f2014-08-07 23:25:23 +00007641 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
ceriond953ebb2005-11-29 13:27:20 +00007642 putIReg( rA_addr, mkexpr(EA) );
7643 break;
7644
sewardj7e846302010-09-03 23:37:02 +00007645 case 0x357: // lfiwax (Load Float As Integer, Indxd, ISA 2.05 p120)
7646 DIP("lfiwax fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
7647 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
carll1f5fe1f2014-08-07 23:25:23 +00007648 assign( iLo, load(Ity_I32, mkexpr(EA)) );
sewardj7e846302010-09-03 23:37:02 +00007649 assign( iHi, binop(Iop_Sub32,
7650 mkU32(0),
7651 binop(Iop_Shr32, mkexpr(iLo), mkU8(31))) );
7652 putFReg( frD_addr, unop(Iop_ReinterpI64asF64,
7653 binop(Iop_32HLto64, mkexpr(iHi), mkexpr(iLo))) );
7654 break;
7655
sewardj66d5ef22011-04-15 11:55:00 +00007656 case 0x377: // lfiwzx (Load floating-point as integer word, zero indexed
7657 {
7658 IRTemp dw = newTemp( Ity_I64 );
7659 DIP("lfiwzx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
7660 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
carll1f5fe1f2014-08-07 23:25:23 +00007661 assign( iLo, load(Ity_I32, mkexpr(EA)) );
sewardj66d5ef22011-04-15 11:55:00 +00007662 assign( dw, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( iLo ) ) );
7663 putFReg( frD_addr, unop( Iop_ReinterpI64asF64, mkexpr( dw ) ) );
7664 break;
7665 }
7666
ceriond953ebb2005-11-29 13:27:20 +00007667 default:
cerion5b2325f2005-12-23 00:55:09 +00007668 vex_printf("dis_fp_load(ppc)(opc2)\n");
ceriond953ebb2005-11-29 13:27:20 +00007669 return False;
sewardje14bb9f2005-07-22 09:39:02 +00007670 }
7671 break;
cerion3d870a32005-03-18 12:23:33 +00007672
7673 default:
cerion5b2325f2005-12-23 00:55:09 +00007674 vex_printf("dis_fp_load(ppc)(opc1)\n");
cerion3d870a32005-03-18 12:23:33 +00007675 return False;
7676 }
7677 return True;
7678}
7679
7680
7681
7682/*
7683 Floating Point Store Instructions
7684*/
7685static Bool dis_fp_store ( UInt theInstr )
7686{
cerion76de5cf2005-11-18 18:25:12 +00007687 /* X-Form, D-Form */
7688 UChar opc1 = ifieldOPC(theInstr);
7689 UChar frS_addr = ifieldRegDS(theInstr);
7690 UChar rA_addr = ifieldRegA(theInstr);
7691 UChar rB_addr = ifieldRegB(theInstr);
7692 UInt opc2 = ifieldOPClo10(theInstr);
7693 UChar b0 = ifieldBIT0(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00007694 Int uimm16 = ifieldUIMM16(theInstr);
cerion094d1392005-06-20 13:45:57 +00007695
cerion2831b002005-11-30 19:55:22 +00007696 Int simm16 = extend_s_16to32(uimm16);
7697 IRTemp frS = newTemp(Ity_F64);
7698 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7699 IRTemp EA = newTemp(ty);
7700 IRTemp rA = newTemp(ty);
7701 IRTemp rB = newTemp(ty);
cerion094d1392005-06-20 13:45:57 +00007702
7703 assign( frS, getFReg(frS_addr) );
cerionedf7fc52005-11-18 20:57:41 +00007704 assign( rA, getIReg(rA_addr) );
7705 assign( rB, getIReg(rB_addr) );
cerion3d870a32005-03-18 12:23:33 +00007706
sewardjb183b852006-02-03 16:08:03 +00007707 /* These are straightforward from a status bits perspective: no
7708 funny status or CR bits affected. For single precision stores,
7709 the values are truncated and denormalised (not rounded) to turn
7710 them into single precision values. */
7711
7712 switch (opc1) {
sewardje14bb9f2005-07-22 09:39:02 +00007713
7714 case 0x34: // stfs (Store Float Single, PPC32 p518)
ceriond953ebb2005-11-29 13:27:20 +00007715 DIP("stfs fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
7716 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
sewardjb183b852006-02-03 16:08:03 +00007717 /* Use Iop_TruncF64asF32 to truncate and possible denormalise
7718 the value to be stored in the correct way, without any
7719 rounding. */
carll1f5fe1f2014-08-07 23:25:23 +00007720 store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
sewardje14bb9f2005-07-22 09:39:02 +00007721 break;
7722
cerion5b2325f2005-12-23 00:55:09 +00007723 case 0x35: // stfsu (Store Float Single, Update, PPC32 p519)
sewardjb183b852006-02-03 16:08:03 +00007724 if (rA_addr == 0)
cerion729edb72005-12-02 16:03:46 +00007725 return False;
cerion729edb72005-12-02 16:03:46 +00007726 DIP("stfsu fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
7727 assign( EA, ea_rA_simm(rA_addr, simm16) );
sewardjb183b852006-02-03 16:08:03 +00007728 /* See comment for stfs */
carll1f5fe1f2014-08-07 23:25:23 +00007729 store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
cerion729edb72005-12-02 16:03:46 +00007730 putIReg( rA_addr, mkexpr(EA) );
7731 break;
cerion3d870a32005-03-18 12:23:33 +00007732
cerion094d1392005-06-20 13:45:57 +00007733 case 0x36: // stfd (Store Float Double, PPC32 p513)
ceriond953ebb2005-11-29 13:27:20 +00007734 DIP("stfd fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
7735 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
carll1f5fe1f2014-08-07 23:25:23 +00007736 store( mkexpr(EA), mkexpr(frS) );
cerion094d1392005-06-20 13:45:57 +00007737 break;
cerion3d870a32005-03-18 12:23:33 +00007738
cerion5b2325f2005-12-23 00:55:09 +00007739 case 0x37: // stfdu (Store Float Double, Update, PPC32 p514)
sewardjb183b852006-02-03 16:08:03 +00007740 if (rA_addr == 0)
sewardje14bb9f2005-07-22 09:39:02 +00007741 return False;
ceriond953ebb2005-11-29 13:27:20 +00007742 DIP("stfdu fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
7743 assign( EA, ea_rA_simm(rA_addr, simm16) );
carll1f5fe1f2014-08-07 23:25:23 +00007744 store( mkexpr(EA), mkexpr(frS) );
sewardje14bb9f2005-07-22 09:39:02 +00007745 putIReg( rA_addr, mkexpr(EA) );
7746 break;
7747
7748 case 0x1F:
7749 if (b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00007750 vex_printf("dis_fp_store(ppc)(instr,b0)\n");
sewardje14bb9f2005-07-22 09:39:02 +00007751 return False;
7752 }
sewardje14bb9f2005-07-22 09:39:02 +00007753 switch(opc2) {
ceriond953ebb2005-11-29 13:27:20 +00007754 case 0x297: // stfsx (Store Float Single Indexed, PPC32 p521)
7755 DIP("stfsx fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
7756 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
sewardjb183b852006-02-03 16:08:03 +00007757 /* See note for stfs */
carll1f5fe1f2014-08-07 23:25:23 +00007758 store( mkexpr(EA),
7759 unop(Iop_TruncF64asF32, mkexpr(frS)) );
ceriond953ebb2005-11-29 13:27:20 +00007760 break;
7761
cerion5b2325f2005-12-23 00:55:09 +00007762 case 0x2B7: // stfsux (Store Float Sgl, Update Indxd, PPC32 p520)
sewardjb183b852006-02-03 16:08:03 +00007763 if (rA_addr == 0)
cerion729edb72005-12-02 16:03:46 +00007764 return False;
cerion729edb72005-12-02 16:03:46 +00007765 DIP("stfsux fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
7766 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
sewardjb183b852006-02-03 16:08:03 +00007767 /* See note for stfs */
carll1f5fe1f2014-08-07 23:25:23 +00007768 store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
cerion729edb72005-12-02 16:03:46 +00007769 putIReg( rA_addr, mkexpr(EA) );
7770 break;
sewardje14bb9f2005-07-22 09:39:02 +00007771
ceriond953ebb2005-11-29 13:27:20 +00007772 case 0x2D7: // stfdx (Store Float Double Indexed, PPC32 p516)
7773 DIP("stfdx fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
7774 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
carll1f5fe1f2014-08-07 23:25:23 +00007775 store( mkexpr(EA), mkexpr(frS) );
ceriond953ebb2005-11-29 13:27:20 +00007776 break;
sewardje14bb9f2005-07-22 09:39:02 +00007777
cerion5b2325f2005-12-23 00:55:09 +00007778 case 0x2F7: // stfdux (Store Float Dbl, Update Indxd, PPC32 p515)
sewardjb183b852006-02-03 16:08:03 +00007779 if (rA_addr == 0)
ceriond953ebb2005-11-29 13:27:20 +00007780 return False;
ceriond953ebb2005-11-29 13:27:20 +00007781 DIP("stfdux fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
7782 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
carll1f5fe1f2014-08-07 23:25:23 +00007783 store( mkexpr(EA), mkexpr(frS) );
ceriond953ebb2005-11-29 13:27:20 +00007784 putIReg( rA_addr, mkexpr(EA) );
7785 break;
sewardj5f63c0c2005-09-09 10:36:55 +00007786
sewardj09e88d12006-01-27 16:05:49 +00007787 case 0x3D7: // stfiwx (Store Float as Int, Indexed, PPC32 p517)
sewardj5117ce12006-01-27 21:20:15 +00007788 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
sewardj09e88d12006-01-27 16:05:49 +00007789 DIP("stfiwx fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
7790 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
carll1f5fe1f2014-08-07 23:25:23 +00007791 store( mkexpr(EA),
7792 unop(Iop_64to32, unop(Iop_ReinterpF64asI64, mkexpr(frS))) );
sewardj09e88d12006-01-27 16:05:49 +00007793 break;
sewardje14bb9f2005-07-22 09:39:02 +00007794
ceriond953ebb2005-11-29 13:27:20 +00007795 default:
cerion5b2325f2005-12-23 00:55:09 +00007796 vex_printf("dis_fp_store(ppc)(opc2)\n");
ceriond953ebb2005-11-29 13:27:20 +00007797 return False;
sewardje14bb9f2005-07-22 09:39:02 +00007798 }
7799 break;
cerion3d870a32005-03-18 12:23:33 +00007800
7801 default:
cerion5b2325f2005-12-23 00:55:09 +00007802 vex_printf("dis_fp_store(ppc)(opc1)\n");
cerion3d870a32005-03-18 12:23:33 +00007803 return False;
7804 }
7805 return True;
7806}
7807
7808
7809
7810/*
7811 Floating Point Arith Instructions
7812*/
7813static Bool dis_fp_arith ( UInt theInstr )
7814{
7815 /* A-Form */
cerion76de5cf2005-11-18 18:25:12 +00007816 UChar opc1 = ifieldOPC(theInstr);
7817 UChar frD_addr = ifieldRegDS(theInstr);
7818 UChar frA_addr = ifieldRegA(theInstr);
7819 UChar frB_addr = ifieldRegB(theInstr);
7820 UChar frC_addr = ifieldRegC(theInstr);
7821 UChar opc2 = ifieldOPClo5(theInstr);
7822 UChar flag_rC = ifieldBIT0(theInstr);
cerion094d1392005-06-20 13:45:57 +00007823
sewardjb183b852006-02-03 16:08:03 +00007824 IRTemp frD = newTemp(Ity_F64);
7825 IRTemp frA = newTemp(Ity_F64);
7826 IRTemp frB = newTemp(Ity_F64);
7827 IRTemp frC = newTemp(Ity_F64);
7828 IRExpr* rm = get_IR_roundingmode();
7829
7830 /* By default, we will examine the results of the operation and set
7831 fpscr[FPRF] accordingly. */
7832 Bool set_FPRF = True;
7833
7834 /* By default, if flag_RC is set, we will clear cr1 after the
7835 operation. In reality we should set cr1 to indicate the
7836 exception status of the operation, but since we're not
7837 simulating exceptions, the exception status will appear to be
7838 zero. Hence cr1 should be cleared if this is a . form insn. */
7839 Bool clear_CR1 = True;
cerion094d1392005-06-20 13:45:57 +00007840
7841 assign( frA, getFReg(frA_addr));
7842 assign( frB, getFReg(frB_addr));
7843 assign( frC, getFReg(frC_addr));
cerion3d870a32005-03-18 12:23:33 +00007844
7845 switch (opc1) {
sewardje14bb9f2005-07-22 09:39:02 +00007846 case 0x3B:
7847 switch (opc2) {
7848 case 0x12: // fdivs (Floating Divide Single, PPC32 p407)
sewardjb183b852006-02-03 16:08:03 +00007849 if (frC_addr != 0)
sewardje14bb9f2005-07-22 09:39:02 +00007850 return False;
cerion5b2325f2005-12-23 00:55:09 +00007851 DIP("fdivs%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007852 frD_addr, frA_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007853 assign( frD, triop( Iop_DivF64r32,
7854 rm, mkexpr(frA), mkexpr(frB) ));
sewardje14bb9f2005-07-22 09:39:02 +00007855 break;
7856
7857 case 0x14: // fsubs (Floating Subtract Single, PPC32 p430)
sewardjb183b852006-02-03 16:08:03 +00007858 if (frC_addr != 0)
sewardje14bb9f2005-07-22 09:39:02 +00007859 return False;
cerion5b2325f2005-12-23 00:55:09 +00007860 DIP("fsubs%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007861 frD_addr, frA_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007862 assign( frD, triop( Iop_SubF64r32,
7863 rm, mkexpr(frA), mkexpr(frB) ));
sewardje14bb9f2005-07-22 09:39:02 +00007864 break;
7865
7866 case 0x15: // fadds (Floating Add Single, PPC32 p401)
sewardjb183b852006-02-03 16:08:03 +00007867 if (frC_addr != 0)
sewardje14bb9f2005-07-22 09:39:02 +00007868 return False;
cerion5b2325f2005-12-23 00:55:09 +00007869 DIP("fadds%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007870 frD_addr, frA_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007871 assign( frD, triop( Iop_AddF64r32,
7872 rm, mkexpr(frA), mkexpr(frB) ));
sewardje14bb9f2005-07-22 09:39:02 +00007873 break;
7874
sewardj870c84b2006-01-24 03:33:43 +00007875 case 0x16: // fsqrts (Floating SqRt (Single-Precision), PPC32 p428)
sewardj5117ce12006-01-27 21:20:15 +00007876 // NOTE: POWERPC OPTIONAL, "General-Purpose Group" (PPC32_FX)
sewardjb183b852006-02-03 16:08:03 +00007877 if (frA_addr != 0 || frC_addr != 0)
sewardj870c84b2006-01-24 03:33:43 +00007878 return False;
sewardj870c84b2006-01-24 03:33:43 +00007879 DIP("fsqrts%s fr%u,fr%u\n", flag_rC ? ".":"",
7880 frD_addr, frB_addr);
sewardj79fd33f2006-01-29 17:07:57 +00007881 // however illogically, on ppc970 this insn behaves identically
sewardjb183b852006-02-03 16:08:03 +00007882 // to fsqrt (double-precision). So use SqrtF64, not SqrtF64r32.
7883 assign( frD, binop( Iop_SqrtF64, rm, mkexpr(frB) ));
sewardj870c84b2006-01-24 03:33:43 +00007884 break;
sewardje14bb9f2005-07-22 09:39:02 +00007885
sewardjbaf971a2006-01-27 15:09:35 +00007886 case 0x18: // fres (Floating Reciprocal Estimate Single, PPC32 p421)
sewardj5117ce12006-01-27 21:20:15 +00007887 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
sewardjb183b852006-02-03 16:08:03 +00007888 if (frA_addr != 0 || frC_addr != 0)
sewardjbaf971a2006-01-27 15:09:35 +00007889 return False;
sewardjbaf971a2006-01-27 15:09:35 +00007890 DIP("fres%s fr%u,fr%u\n", flag_rC ? ".":"",
7891 frD_addr, frB_addr);
sewardj157b19b2006-01-31 16:32:25 +00007892 { IRExpr* ieee_one
7893 = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
sewardjb183b852006-02-03 16:08:03 +00007894 assign( frD, triop( Iop_DivF64r32,
7895 rm,
7896 ieee_one, mkexpr(frB) ));
sewardj157b19b2006-01-31 16:32:25 +00007897 }
sewardjbaf971a2006-01-27 15:09:35 +00007898 break;
sewardje14bb9f2005-07-22 09:39:02 +00007899
7900 case 0x19: // fmuls (Floating Multiply Single, PPC32 p414)
sewardjb183b852006-02-03 16:08:03 +00007901 if (frB_addr != 0)
sewardje14bb9f2005-07-22 09:39:02 +00007902 return False;
cerion5b2325f2005-12-23 00:55:09 +00007903 DIP("fmuls%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007904 frD_addr, frA_addr, frC_addr);
sewardjb183b852006-02-03 16:08:03 +00007905 assign( frD, triop( Iop_MulF64r32,
7906 rm, mkexpr(frA), mkexpr(frC) ));
sewardje14bb9f2005-07-22 09:39:02 +00007907 break;
7908
sewardj79fd33f2006-01-29 17:07:57 +00007909 case 0x1A: // frsqrtes (Floating Recip SqRt Est Single)
7910 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
7911 // Undocumented instruction?
sewardjb183b852006-02-03 16:08:03 +00007912 if (frA_addr != 0 || frC_addr != 0)
sewardj79fd33f2006-01-29 17:07:57 +00007913 return False;
sewardj79fd33f2006-01-29 17:07:57 +00007914 DIP("frsqrtes%s fr%u,fr%u\n", flag_rC ? ".":"",
7915 frD_addr, frB_addr);
7916 assign( frD, unop(Iop_Est5FRSqrt, mkexpr(frB)) );
7917 break;
7918
sewardje14bb9f2005-07-22 09:39:02 +00007919 default:
cerion5b2325f2005-12-23 00:55:09 +00007920 vex_printf("dis_fp_arith(ppc)(3B: opc2)\n");
sewardje14bb9f2005-07-22 09:39:02 +00007921 return False;
7922 }
7923 break;
cerion094d1392005-06-20 13:45:57 +00007924
cerion3d870a32005-03-18 12:23:33 +00007925 case 0x3F:
7926 switch (opc2) {
cerion5b2325f2005-12-23 00:55:09 +00007927 case 0x12: // fdiv (Floating Div (Double-Precision), PPC32 p406)
sewardjb183b852006-02-03 16:08:03 +00007928 if (frC_addr != 0)
sewardje14bb9f2005-07-22 09:39:02 +00007929 return False;
cerion5b2325f2005-12-23 00:55:09 +00007930 DIP("fdiv%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007931 frD_addr, frA_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007932 assign( frD, triop(Iop_DivF64, rm, mkexpr(frA), mkexpr(frB)) );
sewardje14bb9f2005-07-22 09:39:02 +00007933 break;
7934
cerion5b2325f2005-12-23 00:55:09 +00007935 case 0x14: // fsub (Floating Sub (Double-Precision), PPC32 p429)
sewardjb183b852006-02-03 16:08:03 +00007936 if (frC_addr != 0)
sewardje14bb9f2005-07-22 09:39:02 +00007937 return False;
cerion5b2325f2005-12-23 00:55:09 +00007938 DIP("fsub%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007939 frD_addr, frA_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007940 assign( frD, triop(Iop_SubF64, rm, mkexpr(frA), mkexpr(frB)) );
sewardje14bb9f2005-07-22 09:39:02 +00007941 break;
cerion3d870a32005-03-18 12:23:33 +00007942
7943 case 0x15: // fadd (Floating Add (Double-Precision), PPC32 p400)
sewardjb183b852006-02-03 16:08:03 +00007944 if (frC_addr != 0)
cerion3d870a32005-03-18 12:23:33 +00007945 return False;
cerion5b2325f2005-12-23 00:55:09 +00007946 DIP("fadd%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
cerion3d870a32005-03-18 12:23:33 +00007947 frD_addr, frA_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007948 assign( frD, triop(Iop_AddF64, rm, mkexpr(frA), mkexpr(frB)) );
cerion094d1392005-06-20 13:45:57 +00007949 break;
cerion3d870a32005-03-18 12:23:33 +00007950
cerion876ef412005-12-14 22:00:53 +00007951 case 0x16: // fsqrt (Floating SqRt (Double-Precision), PPC32 p427)
sewardj5117ce12006-01-27 21:20:15 +00007952 // NOTE: POWERPC OPTIONAL, "General-Purpose Group" (PPC32_FX)
sewardjb183b852006-02-03 16:08:03 +00007953 if (frA_addr != 0 || frC_addr != 0)
cerion876ef412005-12-14 22:00:53 +00007954 return False;
cerion5b2325f2005-12-23 00:55:09 +00007955 DIP("fsqrt%s fr%u,fr%u\n", flag_rC ? ".":"",
cerion876ef412005-12-14 22:00:53 +00007956 frD_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007957 assign( frD, binop(Iop_SqrtF64, rm, mkexpr(frB)) );
cerion876ef412005-12-14 22:00:53 +00007958 break;
sewardje14bb9f2005-07-22 09:39:02 +00007959
7960 case 0x17: { // fsel (Floating Select, PPC32 p426)
sewardj5117ce12006-01-27 21:20:15 +00007961 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
sewardje14bb9f2005-07-22 09:39:02 +00007962 IRTemp cc = newTemp(Ity_I32);
7963 IRTemp cc_b0 = newTemp(Ity_I32);
7964
cerion5b2325f2005-12-23 00:55:09 +00007965 DIP("fsel%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007966 frD_addr, frA_addr, frC_addr, frB_addr);
7967
7968 // cc: UN == 0x41, LT == 0x01, GT == 0x00, EQ == 0x40
7969 // => GT|EQ == (cc & 0x1 == 0)
cerion5b2325f2005-12-23 00:55:09 +00007970 assign( cc, binop(Iop_CmpF64, mkexpr(frA),
7971 IRExpr_Const(IRConst_F64(0))) );
sewardje14bb9f2005-07-22 09:39:02 +00007972 assign( cc_b0, binop(Iop_And32, mkexpr(cc), mkU32(1)) );
7973
7974 // frD = (frA >= 0.0) ? frC : frB
7975 // = (cc_b0 == 0) ? frC : frB
7976 assign( frD,
florian99dd03e2013-01-29 03:56:06 +00007977 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00007978 binop(Iop_CmpEQ32, mkexpr(cc_b0), mkU32(0)),
florian99dd03e2013-01-29 03:56:06 +00007979 mkexpr(frC),
7980 mkexpr(frB) ));
sewardjb183b852006-02-03 16:08:03 +00007981
7982 /* One of the rare ones which don't mess with FPRF */
7983 set_FPRF = False;
sewardje14bb9f2005-07-22 09:39:02 +00007984 break;
7985 }
7986
sewardj79fd33f2006-01-29 17:07:57 +00007987 case 0x18: // fre (Floating Reciprocal Estimate)
7988 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
7989 // Note: unclear whether this insn really exists or not
7990 // ppc970 doesn't have it, but POWER5 does
sewardjb183b852006-02-03 16:08:03 +00007991 if (frA_addr != 0 || frC_addr != 0)
sewardj79fd33f2006-01-29 17:07:57 +00007992 return False;
sewardj79fd33f2006-01-29 17:07:57 +00007993 DIP("fre%s fr%u,fr%u\n", flag_rC ? ".":"",
7994 frD_addr, frB_addr);
sewardj157b19b2006-01-31 16:32:25 +00007995 { IRExpr* ieee_one
7996 = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
sewardjb183b852006-02-03 16:08:03 +00007997 assign( frD, triop( Iop_DivF64,
sewardj56de4212006-02-06 22:19:17 +00007998 rm,
sewardjb183b852006-02-03 16:08:03 +00007999 ieee_one, mkexpr(frB) ));
sewardj157b19b2006-01-31 16:32:25 +00008000 }
sewardj79fd33f2006-01-29 17:07:57 +00008001 break;
8002
cerion5b2325f2005-12-23 00:55:09 +00008003 case 0x19: // fmul (Floating Mult (Double Precision), PPC32 p413)
sewardjb183b852006-02-03 16:08:03 +00008004 if (frB_addr != 0)
cerion5b2325f2005-12-23 00:55:09 +00008005 vex_printf("dis_fp_arith(ppc)(instr,fmul)\n");
cerion5b2325f2005-12-23 00:55:09 +00008006 DIP("fmul%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00008007 frD_addr, frA_addr, frC_addr);
sewardjb183b852006-02-03 16:08:03 +00008008 assign( frD, triop(Iop_MulF64, rm, mkexpr(frA), mkexpr(frC)) );
sewardje14bb9f2005-07-22 09:39:02 +00008009 break;
8010
sewardjbaf971a2006-01-27 15:09:35 +00008011 case 0x1A: // frsqrte (Floating Recip SqRt Est., PPC32 p424)
sewardj5117ce12006-01-27 21:20:15 +00008012 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
sewardjb183b852006-02-03 16:08:03 +00008013 if (frA_addr != 0 || frC_addr != 0)
sewardjbaf971a2006-01-27 15:09:35 +00008014 return False;
sewardjbaf971a2006-01-27 15:09:35 +00008015 DIP("frsqrte%s fr%u,fr%u\n", flag_rC ? ".":"",
8016 frD_addr, frB_addr);
8017 assign( frD, unop(Iop_Est5FRSqrt, mkexpr(frB)) );
8018 break;
cerion3d870a32005-03-18 12:23:33 +00008019
8020 default:
cerion5b2325f2005-12-23 00:55:09 +00008021 vex_printf("dis_fp_arith(ppc)(3F: opc2)\n");
cerion3d870a32005-03-18 12:23:33 +00008022 return False;
8023 }
cerion094d1392005-06-20 13:45:57 +00008024 break;
8025
cerion3d870a32005-03-18 12:23:33 +00008026 default:
cerion5b2325f2005-12-23 00:55:09 +00008027 vex_printf("dis_fp_arith(ppc)(opc1)\n");
cerion3d870a32005-03-18 12:23:33 +00008028 return False;
8029 }
cerion094d1392005-06-20 13:45:57 +00008030
8031 putFReg( frD_addr, mkexpr(frD) );
sewardjb183b852006-02-03 16:08:03 +00008032
8033 if (set_FPRF) {
8034 // XXX XXX XXX FIXME
8035 // set FPRF from frD
8036 }
8037
8038 if (flag_rC && clear_CR1) {
8039 putCR321( 1, mkU8(0) );
8040 putCR0( 1, mkU8(0) );
8041 }
8042
cerion3d870a32005-03-18 12:23:33 +00008043 return True;
8044}
8045
8046
8047
sewardje14bb9f2005-07-22 09:39:02 +00008048/*
8049 Floating Point Mult-Add Instructions
8050*/
8051static Bool dis_fp_multadd ( UInt theInstr )
8052{
8053 /* A-Form */
cerion76de5cf2005-11-18 18:25:12 +00008054 UChar opc1 = ifieldOPC(theInstr);
8055 UChar frD_addr = ifieldRegDS(theInstr);
8056 UChar frA_addr = ifieldRegA(theInstr);
8057 UChar frB_addr = ifieldRegB(theInstr);
8058 UChar frC_addr = ifieldRegC(theInstr);
8059 UChar opc2 = ifieldOPClo5(theInstr);
8060 UChar flag_rC = ifieldBIT0(theInstr);
sewardje14bb9f2005-07-22 09:39:02 +00008061
sewardjb183b852006-02-03 16:08:03 +00008062 IRTemp frD = newTemp(Ity_F64);
8063 IRTemp frA = newTemp(Ity_F64);
8064 IRTemp frB = newTemp(Ity_F64);
8065 IRTemp frC = newTemp(Ity_F64);
8066 IRTemp rmt = newTemp(Ity_I32);
sewardj2bcdd652012-07-14 08:22:13 +00008067 IRTemp tmp = newTemp(Ity_F64);
8068 IRTemp sign_tmp = newTemp(Ity_I64);
8069 IRTemp nan_mask = newTemp(Ity_I32);
sewardjb183b852006-02-03 16:08:03 +00008070 IRExpr* rm;
8071
8072 /* By default, we will examine the results of the operation and set
8073 fpscr[FPRF] accordingly. */
8074 Bool set_FPRF = True;
8075
8076 /* By default, if flag_RC is set, we will clear cr1 after the
8077 operation. In reality we should set cr1 to indicate the
8078 exception status of the operation, but since we're not
8079 simulating exceptions, the exception status will appear to be
8080 zero. Hence cr1 should be cleared if this is a . form insn. */
8081 Bool clear_CR1 = True;
8082
8083 /* Bind the rounding mode expression to a temp; there's no
8084 point in creating gratuitous CSEs, as we know we'll need
8085 to use it twice. */
8086 assign( rmt, get_IR_roundingmode() );
8087 rm = mkexpr(rmt);
sewardje14bb9f2005-07-22 09:39:02 +00008088
8089 assign( frA, getFReg(frA_addr));
8090 assign( frB, getFReg(frB_addr));
8091 assign( frC, getFReg(frC_addr));
8092
sewardjb183b852006-02-03 16:08:03 +00008093 /* The rounding in this is all a bit dodgy. The idea is to only do
8094 one rounding. That clearly isn't achieveable without dedicated
8095 four-input IR primops, although in the single precision case we
8096 can sort-of simulate it by doing the inner multiply in double
8097 precision.
8098
8099 In the negated cases, the negation happens after rounding. */
8100
sewardje14bb9f2005-07-22 09:39:02 +00008101 switch (opc1) {
8102 case 0x3B:
8103 switch (opc2) {
8104 case 0x1C: // fmsubs (Floating Mult-Subtr Single, PPC32 p412)
cerion5b2325f2005-12-23 00:55:09 +00008105 DIP("fmsubs%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00008106 frD_addr, frA_addr, frC_addr, frB_addr);
sewardj40c80262006-02-08 19:30:46 +00008107 assign( frD, qop( Iop_MSubF64r32, rm,
8108 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
sewardjb183b852006-02-03 16:08:03 +00008109 break;
sewardje14bb9f2005-07-22 09:39:02 +00008110
8111 case 0x1D: // fmadds (Floating Mult-Add Single, PPC32 p409)
cerion5b2325f2005-12-23 00:55:09 +00008112 DIP("fmadds%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00008113 frD_addr, frA_addr, frC_addr, frB_addr);
sewardj40c80262006-02-08 19:30:46 +00008114 assign( frD, qop( Iop_MAddF64r32, rm,
8115 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
sewardje14bb9f2005-07-22 09:39:02 +00008116 break;
8117
8118 case 0x1E: // fnmsubs (Float Neg Mult-Subtr Single, PPC32 p420)
sewardje14bb9f2005-07-22 09:39:02 +00008119 case 0x1F: // fnmadds (Floating Negative Multiply-Add Single, PPC32 p418)
sewardj2bcdd652012-07-14 08:22:13 +00008120
8121 if (opc2 == 0x1E) {
8122 DIP("fnmsubs%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
8123 frD_addr, frA_addr, frC_addr, frB_addr);
8124 assign( tmp, qop( Iop_MSubF64r32, rm,
8125 mkexpr(frA), mkexpr(frC), mkexpr(frB) ) );
8126 } else {
8127 DIP("fnmadds%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
8128 frD_addr, frA_addr, frC_addr, frB_addr);
8129 assign( tmp, qop( Iop_MAddF64r32, rm,
8130 mkexpr(frA), mkexpr(frC), mkexpr(frB) ) );
8131 }
8132
8133 assign( nan_mask, Check_NaN( mkexpr( tmp ),
8134 mkU32( NANmaskSingle ) ) );
8135 assign( sign_tmp, Complement_non_NaN( mkexpr( tmp ),
8136 mkexpr( nan_mask ) ) );
8137 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr( sign_tmp ) ) );
sewardje14bb9f2005-07-22 09:39:02 +00008138 break;
8139
8140 default:
cerion5b2325f2005-12-23 00:55:09 +00008141 vex_printf("dis_fp_multadd(ppc)(3B: opc2)\n");
sewardje14bb9f2005-07-22 09:39:02 +00008142 return False;
8143 }
8144 break;
8145
8146 case 0x3F:
8147 switch (opc2) {
cerion5b2325f2005-12-23 00:55:09 +00008148 case 0x1C: // fmsub (Float Mult-Sub (Dbl Precision), PPC32 p411)
8149 DIP("fmsub%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00008150 frD_addr, frA_addr, frC_addr, frB_addr);
sewardj40c80262006-02-08 19:30:46 +00008151 assign( frD, qop( Iop_MSubF64, rm,
8152 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
sewardje14bb9f2005-07-22 09:39:02 +00008153 break;
8154
cerion5b2325f2005-12-23 00:55:09 +00008155 case 0x1D: // fmadd (Float Mult-Add (Dbl Precision), PPC32 p408)
8156 DIP("fmadd%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00008157 frD_addr, frA_addr, frC_addr, frB_addr);
sewardj40c80262006-02-08 19:30:46 +00008158 assign( frD, qop( Iop_MAddF64, rm,
8159 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
sewardje14bb9f2005-07-22 09:39:02 +00008160 break;
8161
cerion5b2325f2005-12-23 00:55:09 +00008162 case 0x1E: // fnmsub (Float Neg Mult-Subtr (Dbl Precision), PPC32 p419)
cerion5b2325f2005-12-23 00:55:09 +00008163 case 0x1F: // fnmadd (Float Neg Mult-Add (Dbl Precision), PPC32 p417)
sewardj2bcdd652012-07-14 08:22:13 +00008164
8165 if (opc2 == 0x1E) {
8166 DIP("fnmsub%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
8167 frD_addr, frA_addr, frC_addr, frB_addr);
8168 assign( tmp, qop( Iop_MSubF64, rm,
8169 mkexpr(frA), mkexpr(frC), mkexpr(frB) ) );
8170 } else {
8171 DIP("fnmadd%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
8172 frD_addr, frA_addr, frC_addr, frB_addr);
8173 assign( tmp, qop( Iop_MAddF64, rm,
8174 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
8175 }
8176
8177 assign( nan_mask, Check_NaN( mkexpr( tmp ),
8178 mkU32( NANmaskDouble ) ) );
8179 assign( sign_tmp, Complement_non_NaN( mkexpr( tmp ),
8180 mkexpr( nan_mask ) ) );
8181 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr( sign_tmp ) ) );
sewardj0e2cc672005-07-29 21:58:51 +00008182 break;
sewardje14bb9f2005-07-22 09:39:02 +00008183
8184 default:
cerion5b2325f2005-12-23 00:55:09 +00008185 vex_printf("dis_fp_multadd(ppc)(3F: opc2)\n");
sewardje14bb9f2005-07-22 09:39:02 +00008186 return False;
8187 }
8188 break;
8189
8190 default:
cerion5b2325f2005-12-23 00:55:09 +00008191 vex_printf("dis_fp_multadd(ppc)(opc1)\n");
sewardje14bb9f2005-07-22 09:39:02 +00008192 return False;
8193 }
8194
8195 putFReg( frD_addr, mkexpr(frD) );
sewardjb183b852006-02-03 16:08:03 +00008196
8197 if (set_FPRF) {
8198 // XXX XXX XXX FIXME
8199 // set FPRF from frD
8200 }
8201
8202 if (flag_rC && clear_CR1) {
8203 putCR321( 1, mkU8(0) );
8204 putCR0( 1, mkU8(0) );
8205 }
8206
sewardje14bb9f2005-07-22 09:39:02 +00008207 return True;
8208}
8209
sewardj66d5ef22011-04-15 11:55:00 +00008210/*
8211 * fe_flag is set to 1 if any of the following conditions occurs:
sewardje71e56a2011-09-05 12:11:06 +00008212 * - The floating-point operand in register FRB is a Zero, a
8213 * NaN, an Infinity, or a negative value.
8214 * - e_b is less than or equal to: -970 for double precision; -103 for single precision
8215 * Otherwise fe_flag is set to 0.
8216 *
8217 * fg_flag is set to 1 if either of the following conditions occurs.
8218 * - The floating-point operand in register FRB is a Zero, an
8219 * Infinity, or a denormalized value.
8220 * Otherwise fg_flag is set to 0.
8221 *
8222 */
8223static void do_fp_tsqrt(IRTemp frB_Int, Bool sp, IRTemp * fe_flag_tmp, IRTemp * fg_flag_tmp)
8224{
8225 // The following temps are for holding intermediate results
8226 IRTemp e_b = newTemp(Ity_I32);
8227 IRExpr * fe_flag, * fg_flag;
8228 IRTemp frB_exp_shR = newTemp(Ity_I32);
8229 UInt bias = sp? 127 : 1023;
8230 IRExpr * frbNaN, * frbDenorm, * frBNeg;
8231 IRExpr * eb_LTE;
8232 IRTemp frbZero_tmp = newTemp(Ity_I1);
8233 IRTemp frbInf_tmp = newTemp(Ity_I1);
8234 *fe_flag_tmp = newTemp(Ity_I32);
8235 *fg_flag_tmp = newTemp(Ity_I32);
8236 assign( frB_exp_shR, fp_exp_part( frB_Int, sp ) );
8237 assign(e_b, binop( Iop_Sub32, mkexpr(frB_exp_shR), mkU32( bias ) ));
8238
8239 ////////////////// fe_flag tests BEGIN //////////////////////
8240 /* We first do all tests that may result in setting fe_flag to '1'.
8241 * (NOTE: These tests are similar to those used for ftdiv. See do_fp_tdiv()
8242 * for details.)
8243 */
8244 frbNaN = sp ? is_NaN_32(frB_Int) : is_NaN(frB_Int);
8245 assign( frbInf_tmp, is_Inf(frB_Int, sp) );
8246 assign( frbZero_tmp, is_Zero(frB_Int, sp ) );
8247 {
8248 // Test_value = -970 for double precision
8249 UInt test_value = sp ? 0xffffff99 : 0xfffffc36;
8250 eb_LTE = binop( Iop_CmpLE32S, mkexpr( e_b ), mkU32( test_value ) );
8251 }
8252 frBNeg = binop( Iop_CmpEQ32,
8253 binop( Iop_Shr32,
8254 sp ? mkexpr( frB_Int ) : unop( Iop_64HIto32, mkexpr( frB_Int ) ),
8255 mkU8( 31 ) ),
8256 mkU32( 1 ) );
8257 ////////////////// fe_flag tests END //////////////////////
8258
8259 ////////////////// fg_flag tests BEGIN //////////////////////
8260 /*
8261 * The following tests were already performed above in the fe_flag
8262 * tests. So these conditions will result in both fe_ and fg_ flags
8263 * being set.
8264 * - Test if FRB is Zero
8265 * - Test if FRB is an Infinity
8266 */
8267
8268 /*
8269 * Test if FRB holds a denormalized value. A denormalized value is one where
8270 * the exp is 0 and the fraction is non-zero.
8271 */
8272 if (sp) {
8273 IRTemp frac_part = newTemp(Ity_I32);
8274 assign( frac_part, binop( Iop_And32, mkexpr(frB_Int), mkU32(0x007fffff)) );
8275 frbDenorm
8276 = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ), mkU32( 0 ) ),
8277 binop( Iop_CmpNE32, mkexpr( frac_part ), mkU32( 0 ) ) );
8278 } else {
8279 IRExpr * hi32, * low32, * fraction_is_nonzero;
8280 IRTemp frac_part = newTemp(Ity_I64);
8281
8282 assign( frac_part, FP_FRAC_PART(frB_Int) );
8283 hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
8284 low32 = unop( Iop_64to32, mkexpr( frac_part ) );
8285 fraction_is_nonzero = binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
8286 mkU32( 0 ) );
8287 frbDenorm
8288 = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ), mkU32( 0 ) ),
8289 fraction_is_nonzero );
8290 }
8291 ////////////////// fg_flag tests END //////////////////////
8292
8293 /////////////////////////
8294 fe_flag = mkOR1( mkexpr( frbZero_tmp ),
8295 mkOR1( frbNaN,
8296 mkOR1( mkexpr( frbInf_tmp ),
8297 mkOR1( frBNeg, eb_LTE ) ) ) );
8298
8299 fe_flag = unop(Iop_1Uto32, fe_flag);
8300
8301 fg_flag = mkOR1( mkexpr( frbZero_tmp ),
8302 mkOR1( mkexpr( frbInf_tmp ), frbDenorm ) );
8303 fg_flag = unop(Iop_1Uto32, fg_flag);
8304 assign (*fg_flag_tmp, fg_flag);
8305 assign (*fe_flag_tmp, fe_flag);
8306}
8307/*
8308 * fe_flag is set to 1 if any of the following conditions occurs:
sewardj66d5ef22011-04-15 11:55:00 +00008309 * - The double-precision floating-point operand in register FRA is a NaN or an
8310 * Infinity.
8311 * - The double-precision floating-point operand in register FRB is a Zero, a
8312 * NaN, or an Infinity.
8313 * - e_b is less than or equal to -1022.
8314 * - e_b is greater than or equal to 1021.
8315 * - The double-precision floating-point operand in register FRA is not a zero
8316 * and the difference, e_a - e_b, is greater than or equal to 1023.
8317 * - The double-precision floating-point operand in register FRA is not a zero
8318 * and the difference, e_a - e_b, is less than or equal to -1021.
8319 * - The double-precision floating-point operand in register FRA is not a zero
8320 * and e_a is less than or equal to -970
8321 * Otherwise fe_flag is set to 0.
8322 *
8323 * fg_flag is set to 1 if either of the following conditions occurs.
8324 * - The double-precision floating-point operand in register FRA is an Infinity.
8325 * - The double-precision floating-point operand in register FRB is a Zero, an
8326 * Infinity, or a denormalized value.
8327 * Otherwise fg_flag is set to 0.
8328 *
8329 */
sewardje71e56a2011-09-05 12:11:06 +00008330static 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 +00008331{
sewardj66d5ef22011-04-15 11:55:00 +00008332 // The following temps are for holding intermediate results
sewardj66d5ef22011-04-15 11:55:00 +00008333 IRTemp e_a = newTemp(Ity_I32);
8334 IRTemp e_b = newTemp(Ity_I32);
8335 IRTemp frA_exp_shR = newTemp(Ity_I32);
8336 IRTemp frB_exp_shR = newTemp(Ity_I32);
8337
sewardje71e56a2011-09-05 12:11:06 +00008338 UInt bias = sp? 127 : 1023;
8339 *fe_flag_tmp = newTemp(Ity_I32);
8340 *fg_flag_tmp = newTemp(Ity_I32);
sewardj66d5ef22011-04-15 11:55:00 +00008341
8342 /* The following variables hold boolean results from tests
8343 * that are OR'ed together for setting the fe_ and fg_ flags.
8344 * For some cases, the booleans are used more than once, so
8345 * I make those IRTemp's instead of IRExpr's.
8346 */
8347 IRExpr * fraNaN, * frbNaN, * frbDenorm;
8348 IRExpr * eb_LTE, * eb_GTE, * ea_eb_GTE, * ea_eb_LTE, * ea_LTE;
8349 IRTemp fraInf_tmp = newTemp(Ity_I1);
8350 IRTemp frbZero_tmp = newTemp(Ity_I1);
8351 IRTemp frbInf_tmp = newTemp(Ity_I1);
8352 IRTemp fraNotZero_tmp = newTemp(Ity_I1);
8353
8354/* The following are the flags that are set by OR'ing the results of
sewardj4aa412a2011-07-24 14:13:21 +00008355 * all the tests done for tdiv. These flags are the input to the specified CR.
sewardj66d5ef22011-04-15 11:55:00 +00008356 */
sewardje71e56a2011-09-05 12:11:06 +00008357 IRExpr * fe_flag, * fg_flag;
sewardj66d5ef22011-04-15 11:55:00 +00008358
sewardj66d5ef22011-04-15 11:55:00 +00008359 // Create temps that will be used throughout the following tests.
sewardje71e56a2011-09-05 12:11:06 +00008360 assign( frA_exp_shR, fp_exp_part( frA_int, sp ) );
8361 assign( frB_exp_shR, fp_exp_part( frB_int, sp ) );
sewardj66d5ef22011-04-15 11:55:00 +00008362 /* Let e_[a|b] be the unbiased exponent: i.e. exp - 1023. */
8363 assign(e_a, binop( Iop_Sub32, mkexpr(frA_exp_shR), mkU32( bias ) ));
8364 assign(e_b, binop( Iop_Sub32, mkexpr(frB_exp_shR), mkU32( bias ) ));
8365
8366
8367 ////////////////// fe_flag tests BEGIN //////////////////////
8368 /* We first do all tests that may result in setting fe_flag to '1'. */
8369
8370 /*
8371 * Test if the double-precision floating-point operand in register FRA is
8372 * a NaN:
sewardj66d5ef22011-04-15 11:55:00 +00008373 */
sewardje71e56a2011-09-05 12:11:06 +00008374 fraNaN = sp ? is_NaN_32(frA_int) : is_NaN(frA_int);
sewardj66d5ef22011-04-15 11:55:00 +00008375 /*
8376 * Test if the double-precision floating-point operand in register FRA is
8377 * an Infinity.
sewardj66d5ef22011-04-15 11:55:00 +00008378 */
sewardje71e56a2011-09-05 12:11:06 +00008379 assign(fraInf_tmp, is_Inf(frA_int, sp));
sewardj66d5ef22011-04-15 11:55:00 +00008380
8381 /*
8382 * Test if the double-precision floating-point operand in register FRB is
8383 * a NaN:
sewardj66d5ef22011-04-15 11:55:00 +00008384 */
sewardje71e56a2011-09-05 12:11:06 +00008385 frbNaN = sp ? is_NaN_32(frB_int) : is_NaN(frB_int);
sewardj66d5ef22011-04-15 11:55:00 +00008386 /*
8387 * Test if the double-precision floating-point operand in register FRB is
8388 * an Infinity.
sewardj66d5ef22011-04-15 11:55:00 +00008389 */
sewardje71e56a2011-09-05 12:11:06 +00008390 assign( frbInf_tmp, is_Inf(frB_int, sp) );
sewardj66d5ef22011-04-15 11:55:00 +00008391 /*
8392 * Test if the double-precision floating-point operand in register FRB is
8393 * a Zero.
sewardj66d5ef22011-04-15 11:55:00 +00008394 */
sewardje71e56a2011-09-05 12:11:06 +00008395 assign( frbZero_tmp, is_Zero(frB_int, sp) );
sewardj66d5ef22011-04-15 11:55:00 +00008396
8397 /*
sewardje71e56a2011-09-05 12:11:06 +00008398 * Test if e_b <= -1022 for double precision;
8399 * or e_b <= -126 for single precision
sewardj66d5ef22011-04-15 11:55:00 +00008400 */
8401 {
sewardje71e56a2011-09-05 12:11:06 +00008402 UInt test_value = sp ? 0xffffff82 : 0xfffffc02;
sewardj66d5ef22011-04-15 11:55:00 +00008403 eb_LTE = binop(Iop_CmpLE32S, mkexpr(e_b), mkU32(test_value));
8404 }
8405
8406 /*
sewardje71e56a2011-09-05 12:11:06 +00008407 * Test if e_b >= 1021 (i.e., 1021 < e_b) for double precision;
8408 * or e_b >= -125 (125 < e_b) for single precision
sewardj66d5ef22011-04-15 11:55:00 +00008409 */
8410 {
sewardje71e56a2011-09-05 12:11:06 +00008411 Int test_value = sp ? 125 : 1021;
sewardj66d5ef22011-04-15 11:55:00 +00008412 eb_GTE = binop(Iop_CmpLT32S, mkU32(test_value), mkexpr(e_b));
8413 }
8414
8415 /*
sewardje71e56a2011-09-05 12:11:06 +00008416 * Test if FRA != Zero and (e_a - e_b) >= bias
sewardj66d5ef22011-04-15 11:55:00 +00008417 */
sewardje71e56a2011-09-05 12:11:06 +00008418 assign( fraNotZero_tmp, unop( Iop_Not1, is_Zero( frA_int, sp ) ) );
sewardj66d5ef22011-04-15 11:55:00 +00008419 ea_eb_GTE = mkAND1( mkexpr( fraNotZero_tmp ),
8420 binop( Iop_CmpLT32S, mkU32( bias ),
8421 binop( Iop_Sub32, mkexpr( e_a ),
8422 mkexpr( e_b ) ) ) );
8423
8424 /*
sewardje71e56a2011-09-05 12:11:06 +00008425 * Test if FRA != Zero and (e_a - e_b) <= [-1021 (double precision) or -125 (single precision)]
sewardj66d5ef22011-04-15 11:55:00 +00008426 */
8427 {
sewardje71e56a2011-09-05 12:11:06 +00008428 UInt test_value = sp ? 0xffffff83 : 0xfffffc03;
sewardj66d5ef22011-04-15 11:55:00 +00008429
8430 ea_eb_LTE = mkAND1( mkexpr( fraNotZero_tmp ),
8431 binop( Iop_CmpLE32S,
8432 binop( Iop_Sub32,
8433 mkexpr( e_a ),
8434 mkexpr( e_b ) ),
8435 mkU32( test_value ) ) );
8436 }
8437
8438 /*
sewardje71e56a2011-09-05 12:11:06 +00008439 * Test if FRA != Zero and e_a <= [-970 (double precision) or -103 (single precision)]
sewardj66d5ef22011-04-15 11:55:00 +00008440 */
8441 {
8442 UInt test_value = 0xfffffc36; //Int test_value = -970;
8443
8444 ea_LTE = mkAND1( mkexpr( fraNotZero_tmp ), binop( Iop_CmpLE32S,
8445 mkexpr( e_a ),
8446 mkU32( test_value ) ) );
8447 }
8448 ////////////////// fe_flag tests END //////////////////////
8449
8450 ////////////////// fg_flag tests BEGIN //////////////////////
8451 /*
8452 * The following tests were already performed above in the fe_flag
8453 * tests. So these conditions will result in both fe_ and fg_ flags
8454 * being set.
8455 * - Test if FRA is an Infinity
8456 * - Test if FRB ix Zero
8457 * - Test if FRB is an Infinity
8458 */
8459
8460 /*
8461 * Test if FRB holds a denormalized value. A denormalized value is one where
8462 * the exp is 0 and the fraction is non-zero.
8463 */
8464 {
sewardje71e56a2011-09-05 12:11:06 +00008465 IRExpr * fraction_is_nonzero;
sewardj66d5ef22011-04-15 11:55:00 +00008466
sewardje71e56a2011-09-05 12:11:06 +00008467 if (sp) {
8468 fraction_is_nonzero = binop( Iop_CmpNE32, FP_FRAC_PART32(frB_int),
8469 mkU32( 0 ) );
8470 } else {
8471 IRExpr * hi32, * low32;
8472 IRTemp frac_part = newTemp(Ity_I64);
8473 assign( frac_part, FP_FRAC_PART(frB_int) );
8474
8475 hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
8476 low32 = unop( Iop_64to32, mkexpr( frac_part ) );
8477 fraction_is_nonzero = binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
8478 mkU32( 0 ) );
8479 }
sewardj66d5ef22011-04-15 11:55:00 +00008480 frbDenorm = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ),
sewardje71e56a2011-09-05 12:11:06 +00008481 mkU32( 0x0 ) ), fraction_is_nonzero );
sewardj66d5ef22011-04-15 11:55:00 +00008482
8483 }
8484 ////////////////// fg_flag tests END //////////////////////
8485
sewardj66d5ef22011-04-15 11:55:00 +00008486 fe_flag
8487 = mkOR1(
8488 fraNaN,
8489 mkOR1(
8490 mkexpr( fraInf_tmp ),
8491 mkOR1(
8492 mkexpr( frbZero_tmp ),
8493 mkOR1(
8494 frbNaN,
8495 mkOR1(
8496 mkexpr( frbInf_tmp ),
8497 mkOR1( eb_LTE,
8498 mkOR1( eb_GTE,
8499 mkOR1( ea_eb_GTE,
8500 mkOR1( ea_eb_LTE,
8501 ea_LTE ) ) ) ) ) ) ) ) );
8502
8503 fe_flag = unop(Iop_1Uto32, fe_flag);
8504
8505 fg_flag = mkOR1( mkexpr( fraInf_tmp ), mkOR1( mkexpr( frbZero_tmp ),
8506 mkOR1( mkexpr( frbInf_tmp ),
8507 frbDenorm ) ) );
8508 fg_flag = unop(Iop_1Uto32, fg_flag);
sewardje71e56a2011-09-05 12:11:06 +00008509 assign(*fe_flag_tmp, fe_flag);
8510 assign(*fg_flag_tmp, fg_flag);
8511}
sewardj66d5ef22011-04-15 11:55:00 +00008512
sewardje71e56a2011-09-05 12:11:06 +00008513/* See description for _do_fp_tdiv() above. */
8514static IRExpr * do_fp_tdiv(IRTemp frA_int, IRTemp frB_int)
8515{
8516 IRTemp fe_flag, fg_flag;
8517 /////////////////////////
8518 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
8519 * where fl_flag == 1 on ppc64.
8520 */
8521 IRExpr * fl_flag = unop(Iop_Not32, mkU32(0xFFFFFE));
8522 fe_flag = fg_flag = IRTemp_INVALID;
8523 _do_fp_tdiv(frA_int, frB_int, False/*not single precision*/, &fe_flag, &fg_flag);
sewardj4aa412a2011-07-24 14:13:21 +00008524 return binop( Iop_Or32,
8525 binop( Iop_Or32,
8526 binop( Iop_Shl32, fl_flag, mkU8( 3 ) ),
sewardje71e56a2011-09-05 12:11:06 +00008527 binop( Iop_Shl32, mkexpr(fg_flag), mkU8( 2 ) ) ),
8528 binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) );
sewardj4aa412a2011-07-24 14:13:21 +00008529}
8530
sewardje71e56a2011-09-05 12:11:06 +00008531static Bool dis_fp_tests ( UInt theInstr )
sewardj4aa412a2011-07-24 14:13:21 +00008532{
8533 UChar opc1 = ifieldOPC(theInstr);
8534 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
sewardj4aa412a2011-07-24 14:13:21 +00008535 UChar frB_addr = ifieldRegB(theInstr);
8536 UChar b0 = ifieldBIT0(theInstr);
sewardje71e56a2011-09-05 12:11:06 +00008537 UInt opc2 = ifieldOPClo10(theInstr);
sewardj4aa412a2011-07-24 14:13:21 +00008538 IRTemp frB_I64 = newTemp(Ity_I64);
8539
sewardje71e56a2011-09-05 12:11:06 +00008540 if (opc1 != 0x3F || b0 != 0 ){
8541 vex_printf("dis_fp_tests(ppc)(ftdiv)\n");
sewardj4aa412a2011-07-24 14:13:21 +00008542 return False;
8543 }
sewardj4aa412a2011-07-24 14:13:21 +00008544 assign( frB_I64, unop( Iop_ReinterpF64asI64, getFReg( frB_addr ) ) );
8545
sewardje71e56a2011-09-05 12:11:06 +00008546 switch (opc2) {
8547 case 0x080: // ftdiv
8548 {
8549 UChar frA_addr = ifieldRegA(theInstr);
8550 IRTemp frA_I64 = newTemp(Ity_I64);
8551 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
8552 if (b21to22 != 0 ) {
8553 vex_printf("dis_fp_tests(ppc)(ftdiv)\n");
8554 return False;
8555 }
sewardj66d5ef22011-04-15 11:55:00 +00008556
sewardje71e56a2011-09-05 12:11:06 +00008557 assign( frA_I64, unop( Iop_ReinterpF64asI64, getFReg( frA_addr ) ) );
8558 putGST_field( PPC_GST_CR, do_fp_tdiv(frA_I64, frB_I64), crfD );
8559
8560 DIP("ftdiv crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
8561 break;
8562 }
8563 case 0x0A0: // ftsqrt
8564 {
8565 IRTemp flags = newTemp(Ity_I32);
8566 IRTemp fe_flag, fg_flag;
8567 fe_flag = fg_flag = IRTemp_INVALID;
8568 UChar b18to22 = toUChar( IFIELD( theInstr, 18, 5 ) );
8569 if ( b18to22 != 0) {
8570 vex_printf("dis_fp_tests(ppc)(ftsqrt)\n");
8571 return False;
8572 }
8573 DIP("ftsqrt crf%d,fr%u\n", crfD, frB_addr);
8574 do_fp_tsqrt(frB_I64, False /* not single precision*/, &fe_flag, &fg_flag);
8575 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
8576 * where fl_flag == 1 on ppc64.
8577 */
8578 assign( flags,
8579 binop( Iop_Or32,
8580 binop( Iop_Or32, mkU32( 8 ), // fl_flag
8581 binop( Iop_Shl32, mkexpr(fg_flag), mkU8( 2 ) ) ),
8582 binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) ) );
8583 putGST_field( PPC_GST_CR, mkexpr(flags), crfD );
8584 break;
8585 }
8586
8587 default:
8588 vex_printf("dis_fp_tests(ppc)(opc2)\n");
8589 return False;
8590
8591 }
sewardj66d5ef22011-04-15 11:55:00 +00008592 return True;
8593}
sewardje14bb9f2005-07-22 09:39:02 +00008594
8595/*
8596 Floating Point Compare Instructions
8597*/
8598static Bool dis_fp_cmp ( UInt theInstr )
8599{
8600 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00008601 UChar opc1 = ifieldOPC(theInstr);
8602 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
8603 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
8604 UChar frA_addr = ifieldRegA(theInstr);
8605 UChar frB_addr = ifieldRegB(theInstr);
8606 UInt opc2 = ifieldOPClo10(theInstr);
8607 UChar b0 = ifieldBIT0(theInstr);
sewardje14bb9f2005-07-22 09:39:02 +00008608
8609 IRTemp ccIR = newTemp(Ity_I32);
8610 IRTemp ccPPC32 = newTemp(Ity_I32);
8611
sewardje14bb9f2005-07-22 09:39:02 +00008612 IRTemp frA = newTemp(Ity_F64);
8613 IRTemp frB = newTemp(Ity_F64);
sewardje14bb9f2005-07-22 09:39:02 +00008614
8615 if (opc1 != 0x3F || b21to22 != 0 || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00008616 vex_printf("dis_fp_cmp(ppc)(instr)\n");
sewardje14bb9f2005-07-22 09:39:02 +00008617 return False;
8618 }
8619
8620 assign( frA, getFReg(frA_addr));
8621 assign( frB, getFReg(frB_addr));
8622
8623 assign( ccIR, binop(Iop_CmpF64, mkexpr(frA), mkexpr(frB)) );
8624
8625 /* Map compare result from IR to PPC32 */
8626 /*
8627 FP cmp result | PPC | IR
8628 --------------------------
8629 UN | 0x1 | 0x45
8630 EQ | 0x2 | 0x40
8631 GT | 0x4 | 0x00
8632 LT | 0x8 | 0x01
8633 */
8634
sewardjb183b852006-02-03 16:08:03 +00008635 // ccPPC32 = Shl(1, (~(ccIR>>5) & 2)
8636 // | ((ccIR ^ (ccIR>>6)) & 1)
sewardje14bb9f2005-07-22 09:39:02 +00008637 assign(
8638 ccPPC32,
sewardjb183b852006-02-03 16:08:03 +00008639 binop(
8640 Iop_Shl32,
8641 mkU32(1),
8642 unop(
8643 Iop_32to8,
8644 binop(
8645 Iop_Or32,
8646 binop(
8647 Iop_And32,
8648 unop(
8649 Iop_Not32,
8650 binop(Iop_Shr32, mkexpr(ccIR), mkU8(5))
8651 ),
8652 mkU32(2)
8653 ),
8654 binop(
8655 Iop_And32,
8656 binop(
8657 Iop_Xor32,
8658 mkexpr(ccIR),
8659 binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))
8660 ),
8661 mkU32(1)
8662 )
8663 )
8664 )
8665 )
sewardje14bb9f2005-07-22 09:39:02 +00008666 );
8667
ceriond953ebb2005-11-29 13:27:20 +00008668 putGST_field( PPC_GST_CR, mkexpr(ccPPC32), crfD );
sewardje14bb9f2005-07-22 09:39:02 +00008669
cerionedf7fc52005-11-18 20:57:41 +00008670 /* CAB: TODO?: Support writing cc to FPSCR->FPCC ?
ceriond953ebb2005-11-29 13:27:20 +00008671 putGST_field( PPC_GST_FPSCR, mkexpr(ccPPC32), 4 );
cerionedf7fc52005-11-18 20:57:41 +00008672 */
sewardjb183b852006-02-03 16:08:03 +00008673 // XXX XXX XXX FIXME
8674 // Also write the result into FPRF (it's not entirely clear how)
sewardje14bb9f2005-07-22 09:39:02 +00008675
cerionedf7fc52005-11-18 20:57:41 +00008676 /* Note: Differences between fcmpu and fcmpo are only in exception
8677 flag settings, which aren't supported anyway. */
sewardje14bb9f2005-07-22 09:39:02 +00008678 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +00008679 case 0x000: // fcmpu (Floating Compare Unordered, PPC32 p403)
8680 DIP("fcmpu crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
8681 break;
8682 case 0x020: // fcmpo (Floating Compare Ordered, PPC32 p402)
8683 DIP("fcmpo crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
8684 break;
8685 default:
cerion5b2325f2005-12-23 00:55:09 +00008686 vex_printf("dis_fp_cmp(ppc)(opc2)\n");
ceriond953ebb2005-11-29 13:27:20 +00008687 return False;
sewardje14bb9f2005-07-22 09:39:02 +00008688 }
8689 return True;
8690}
8691
8692
8693
8694/*
8695 Floating Point Rounding/Conversion Instructions
8696*/
8697static Bool dis_fp_round ( UInt theInstr )
8698{
8699 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00008700 UChar opc1 = ifieldOPC(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00008701 UChar b16to20 = ifieldRegA(theInstr);
sewardj7e846302010-09-03 23:37:02 +00008702 UChar frD_addr = ifieldRegDS(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00008703 UChar frB_addr = ifieldRegB(theInstr);
8704 UInt opc2 = ifieldOPClo10(theInstr);
8705 UChar flag_rC = ifieldBIT0(theInstr);
sewardje14bb9f2005-07-22 09:39:02 +00008706
sewardjb183b852006-02-03 16:08:03 +00008707 IRTemp frD = newTemp(Ity_F64);
8708 IRTemp frB = newTemp(Ity_F64);
8709 IRTemp r_tmp32 = newTemp(Ity_I32);
8710 IRTemp r_tmp64 = newTemp(Ity_I64);
8711 IRExpr* rm = get_IR_roundingmode();
sewardje14bb9f2005-07-22 09:39:02 +00008712
sewardjb183b852006-02-03 16:08:03 +00008713 /* By default, we will examine the results of the operation and set
8714 fpscr[FPRF] accordingly. */
8715 Bool set_FPRF = True;
8716
8717 /* By default, if flag_RC is set, we will clear cr1 after the
8718 operation. In reality we should set cr1 to indicate the
8719 exception status of the operation, but since we're not
8720 simulating exceptions, the exception status will appear to be
8721 zero. Hence cr1 should be cleared if this is a . form insn. */
8722 Bool clear_CR1 = True;
sewardj66d5ef22011-04-15 11:55:00 +00008723 if ((!(opc1 == 0x3F || opc1 == 0x3B)) || b16to20 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00008724 vex_printf("dis_fp_round(ppc)(instr)\n");
sewardje14bb9f2005-07-22 09:39:02 +00008725 return False;
8726 }
8727
8728 assign( frB, getFReg(frB_addr));
sewardj66d5ef22011-04-15 11:55:00 +00008729 if (opc1 == 0x3B) {
8730 /* The fcfid[u]s instructions (from ISA 2.06) are a bit odd because
8731 * they're very similar to the other instructions handled here, but have
8732 * a different primary opcode.
8733 */
8734 switch (opc2) {
8735 case 0x34E: // fcfids (Float convert from signed DWord to single precision)
8736 DIP("fcfids%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8737 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
8738 assign( frD, binop( Iop_RoundF64toF32, rm, binop( Iop_I64StoF64, rm,
8739 mkexpr( r_tmp64 ) ) ) );
8740 goto putFR;
8741
8742 case 0x3Ce: // fcfidus (Float convert from unsigned DWord to single precision)
8743 DIP("fcfidus%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8744 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
sewardj95d6f3a2011-04-27 10:07:42 +00008745 assign( frD, unop( Iop_F32toF64, binop( Iop_I64UtoF32, rm, mkexpr( r_tmp64 ) ) ) );
sewardj66d5ef22011-04-15 11:55:00 +00008746 goto putFR;
8747 }
8748 }
8749
sewardje14bb9f2005-07-22 09:39:02 +00008750
sewardje14bb9f2005-07-22 09:39:02 +00008751 switch (opc2) {
cerionf0de28c2005-12-13 20:21:11 +00008752 case 0x00C: // frsp (Float Round to Single, PPC32 p423)
cerion5b2325f2005-12-23 00:55:09 +00008753 DIP("frsp%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00008754 assign( frD, binop( Iop_RoundF64toF32, rm, mkexpr(frB) ));
ceriond953ebb2005-11-29 13:27:20 +00008755 break;
8756
cerionf0de28c2005-12-13 20:21:11 +00008757 case 0x00E: // fctiw (Float Conv to Int, PPC32 p404)
cerion5b2325f2005-12-23 00:55:09 +00008758 DIP("fctiw%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8759 assign( r_tmp32,
sewardj6c299f32009-12-31 18:00:12 +00008760 binop(Iop_F64toI32S, rm, mkexpr(frB)) );
ceriond953ebb2005-11-29 13:27:20 +00008761 assign( frD, unop( Iop_ReinterpI64asF64,
cerion07b07a92005-12-22 14:32:35 +00008762 unop( Iop_32Uto64, mkexpr(r_tmp32))));
sewardjb183b852006-02-03 16:08:03 +00008763 /* FPRF is undefined after fctiw. Leave unchanged. */
8764 set_FPRF = False;
ceriond953ebb2005-11-29 13:27:20 +00008765 break;
8766
cerionf0de28c2005-12-13 20:21:11 +00008767 case 0x00F: // fctiwz (Float Conv to Int, Round to Zero, PPC32 p405)
cerion5b2325f2005-12-23 00:55:09 +00008768 DIP("fctiwz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00008769 assign( r_tmp32,
sewardj6c299f32009-12-31 18:00:12 +00008770 binop(Iop_F64toI32S, mkU32(Irrm_ZERO), mkexpr(frB) ));
ceriond953ebb2005-11-29 13:27:20 +00008771 assign( frD, unop( Iop_ReinterpI64asF64,
cerion07b07a92005-12-22 14:32:35 +00008772 unop( Iop_32Uto64, mkexpr(r_tmp32))));
sewardjb183b852006-02-03 16:08:03 +00008773 /* FPRF is undefined after fctiwz. Leave unchanged. */
8774 set_FPRF = False;
ceriond953ebb2005-11-29 13:27:20 +00008775 break;
cerionf0de28c2005-12-13 20:21:11 +00008776
sewardj4aa412a2011-07-24 14:13:21 +00008777 case 0x08F: case 0x08E: // fctiwu[z]
8778 DIP("fctiwu%s%s fr%u,fr%u\n", opc2 == 0x08F ? "z" : "",
8779 flag_rC ? ".":"", frD_addr, frB_addr);
8780 assign( r_tmp32,
8781 binop( Iop_F64toI32U,
8782 opc2 == 0x08F ? mkU32( Irrm_ZERO ) : rm,
8783 mkexpr( frB ) ) );
8784 assign( frD, unop( Iop_ReinterpI64asF64,
8785 unop( Iop_32Uto64, mkexpr(r_tmp32))));
8786 /* FPRF is undefined after fctiwz. Leave unchanged. */
8787 set_FPRF = False;
8788 break;
8789
8790
cerion5b2325f2005-12-23 00:55:09 +00008791 case 0x32E: // fctid (Float Conv to Int DWord, PPC64 p437)
8792 DIP("fctid%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8793 assign( r_tmp64,
sewardj6c299f32009-12-31 18:00:12 +00008794 binop(Iop_F64toI64S, rm, mkexpr(frB)) );
cerion07b07a92005-12-22 14:32:35 +00008795 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
sewardjb183b852006-02-03 16:08:03 +00008796 /* FPRF is undefined after fctid. Leave unchanged. */
8797 set_FPRF = False;
cerion07b07a92005-12-22 14:32:35 +00008798 break;
cerionf0de28c2005-12-13 20:21:11 +00008799
cerion5b2325f2005-12-23 00:55:09 +00008800 case 0x32F: // fctidz (Float Conv to Int DWord, Round to Zero, PPC64 p437)
8801 DIP("fctidz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00008802 assign( r_tmp64,
sewardj6c299f32009-12-31 18:00:12 +00008803 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), mkexpr(frB)) );
cerion07b07a92005-12-22 14:32:35 +00008804 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
sewardjb183b852006-02-03 16:08:03 +00008805 /* FPRF is undefined after fctidz. Leave unchanged. */
8806 set_FPRF = False;
cerion07b07a92005-12-22 14:32:35 +00008807 break;
cerionf0de28c2005-12-13 20:21:11 +00008808
sewardj4aa412a2011-07-24 14:13:21 +00008809 case 0x3AE: case 0x3AF: // fctidu[z] (Float Conv to Int DWord Unsigned [Round to Zero])
8810 {
8811 DIP("fctidu%s%s fr%u,fr%u\n", opc2 == 0x3AE ? "" : "z",
8812 flag_rC ? ".":"", frD_addr, frB_addr);
8813 assign( r_tmp64,
8814 binop(Iop_F64toI64U, opc2 == 0x3AE ? rm : mkU32(Irrm_ZERO), mkexpr(frB)) );
8815 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
8816 /* FPRF is undefined after fctidz. Leave unchanged. */
8817 set_FPRF = False;
8818 break;
8819 }
cerion5b2325f2005-12-23 00:55:09 +00008820 case 0x34E: // fcfid (Float Conv from Int DWord, PPC64 p434)
8821 DIP("fcfid%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
cerion07b07a92005-12-22 14:32:35 +00008822 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
sewardjb183b852006-02-03 16:08:03 +00008823 assign( frD,
sewardj6c299f32009-12-31 18:00:12 +00008824 binop(Iop_I64StoF64, rm, mkexpr(r_tmp64)) );
cerion07b07a92005-12-22 14:32:35 +00008825 break;
cerionf0de28c2005-12-13 20:21:11 +00008826
sewardj66d5ef22011-04-15 11:55:00 +00008827 case 0x3CE: // fcfidu (Float convert from unsigned DWord)
8828 DIP("fcfidu%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8829 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
8830 assign( frD, binop( Iop_I64UtoF64, rm, mkexpr( r_tmp64 ) ) );
8831 break;
8832
sewardj7e846302010-09-03 23:37:02 +00008833 case 0x188: case 0x1A8: case 0x1C8: case 0x1E8: // frin, friz, frip, frim
8834 switch(opc2) {
8835 case 0x188: // frin (Floating Round to Integer Nearest)
8836 DIP("frin%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8837 assign( r_tmp64,
8838 binop(Iop_F64toI64S, mkU32(Irrm_NEAREST), mkexpr(frB)) );
8839 break;
8840 case 0x1A8: // friz (Floating Round to Integer Toward Zero)
8841 DIP("friz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8842 assign( r_tmp64,
8843 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), mkexpr(frB)) );
8844 break;
8845 case 0x1C8: // frip (Floating Round to Integer Plus)
8846 DIP("frip%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8847 assign( r_tmp64,
8848 binop(Iop_F64toI64S, mkU32(Irrm_PosINF), mkexpr(frB)) );
8849 break;
8850 case 0x1E8: // frim (Floating Round to Integer Minus)
8851 DIP("frim%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8852 assign( r_tmp64,
8853 binop(Iop_F64toI64S, mkU32(Irrm_NegINF), mkexpr(frB)) );
8854 break;
8855 }
8856
8857 /* don't use the rounded integer if frB is outside -9e18..9e18 */
8858 /* F64 has only log10(2**52) significant digits anyway */
8859 /* need to preserve sign of zero */
8860 /* frD = (fabs(frB) > 9e18) ? frB :
8861 (sign(frB)) ? -fabs((double)r_tmp64) : (double)r_tmp64 */
florian99dd03e2013-01-29 03:56:06 +00008862 assign(frD, IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00008863 binop(Iop_CmpNE8,
8864 unop(Iop_32to8,
8865 binop(Iop_CmpF64,
8866 IRExpr_Const(IRConst_F64(9e18)),
8867 unop(Iop_AbsF64, mkexpr(frB)))),
8868 mkU8(0)),
florian99dd03e2013-01-29 03:56:06 +00008869 mkexpr(frB),
8870 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00008871 binop(Iop_CmpNE32,
8872 binop(Iop_Shr32,
8873 unop(Iop_64HIto32,
8874 unop(Iop_ReinterpF64asI64,
8875 mkexpr(frB))),
8876 mkU8(31)),
8877 mkU32(0)),
sewardj009230b2013-01-26 11:47:55 +00008878 unop(Iop_NegF64,
8879 unop( Iop_AbsF64,
8880 binop(Iop_I64StoF64, mkU32(0),
florian99dd03e2013-01-29 03:56:06 +00008881 mkexpr(r_tmp64)) )),
8882 binop(Iop_I64StoF64, mkU32(0), mkexpr(r_tmp64) )
8883 )
sewardj009230b2013-01-26 11:47:55 +00008884 ));
sewardj7e846302010-09-03 23:37:02 +00008885 break;
8886
ceriond953ebb2005-11-29 13:27:20 +00008887 default:
cerion5b2325f2005-12-23 00:55:09 +00008888 vex_printf("dis_fp_round(ppc)(opc2)\n");
ceriond953ebb2005-11-29 13:27:20 +00008889 return False;
sewardje14bb9f2005-07-22 09:39:02 +00008890 }
sewardj66d5ef22011-04-15 11:55:00 +00008891putFR:
sewardje14bb9f2005-07-22 09:39:02 +00008892 putFReg( frD_addr, mkexpr(frD) );
sewardjb183b852006-02-03 16:08:03 +00008893
8894 if (set_FPRF) {
8895 // XXX XXX XXX FIXME
8896 // set FPRF from frD
8897 }
8898
8899 if (flag_rC && clear_CR1) {
8900 putCR321( 1, mkU8(0) );
8901 putCR0( 1, mkU8(0) );
8902 }
8903
sewardje14bb9f2005-07-22 09:39:02 +00008904 return True;
8905}
8906
sewardj7e846302010-09-03 23:37:02 +00008907/*
8908 Floating Point Pair Instructions
8909*/
8910static Bool dis_fp_pair ( UInt theInstr )
8911{
8912 /* X-Form/DS-Form */
8913 UChar opc1 = ifieldOPC(theInstr);
8914 UChar frT_hi_addr = ifieldRegDS(theInstr);
8915 UChar frT_lo_addr = frT_hi_addr + 1;
8916 UChar rA_addr = ifieldRegA(theInstr);
8917 UChar rB_addr = ifieldRegB(theInstr);
8918 UInt uimm16 = ifieldUIMM16(theInstr);
8919 Int simm16 = extend_s_16to32(uimm16);
8920 UInt opc2 = ifieldOPClo10(theInstr);
8921 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8922 IRTemp EA_hi = newTemp(ty);
8923 IRTemp EA_lo = newTemp(ty);
8924 IRTemp frT_hi = newTemp(Ity_F64);
8925 IRTemp frT_lo = newTemp(Ity_F64);
8926 UChar b0 = ifieldBIT0(theInstr);
8927 Bool is_load = 0;
8928
8929 if ((frT_hi_addr %2) != 0) {
8930 vex_printf("dis_fp_pair(ppc) : odd frT register\n");
8931 return False;
8932 }
8933
8934 switch (opc1) {
8935 case 0x1F: // register offset
8936 switch(opc2) {
8937 case 0x317: // lfdpx (FP Load Double Pair X-form, ISA 2.05 p125)
8938 DIP("ldpx fr%u,r%u,r%u\n", frT_hi_addr, rA_addr, rB_addr);
8939 is_load = 1;
8940 break;
8941 case 0x397: // stfdpx (FP STORE Double Pair X-form, ISA 2.05 p125)
8942 DIP("stdpx fr%u,r%u,r%u\n", frT_hi_addr, rA_addr, rB_addr);
8943 break;
8944 default:
8945 vex_printf("dis_fp_pair(ppc) : X-form wrong opc2\n");
8946 return False;
8947 }
8948
8949 if (b0 != 0) {
8950 vex_printf("dis_fp_pair(ppc)(0x1F,b0)\n");
8951 return False;
8952 }
8953 assign( EA_hi, ea_rAor0_idxd( rA_addr, rB_addr ) );
8954 break;
8955 case 0x39: // lfdp (FP Load Double Pair DS-form, ISA 2.05 p125)
8956 DIP("lfdp fr%u,%d(r%u)\n", frT_hi_addr, simm16, rA_addr);
8957 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
8958 is_load = 1;
8959 break;
8960 case 0x3d: // stfdp (FP Store Double Pair DS-form, ISA 2.05 p125)
8961 DIP("stfdp fr%u,%d(r%u)\n", frT_hi_addr, simm16, rA_addr);
8962 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
8963 break;
8964 default: // immediate offset
8965 vex_printf("dis_fp_pair(ppc)(instr)\n");
8966 return False;
8967 }
8968
8969 if (mode64)
8970 assign( EA_lo, binop(Iop_Add64, mkexpr(EA_hi), mkU64(8)) );
8971 else
8972 assign( EA_lo, binop(Iop_Add32, mkexpr(EA_hi), mkU32(8)) );
8973
8974 assign( frT_hi, getFReg(frT_hi_addr) );
8975 assign( frT_lo, getFReg(frT_lo_addr) );
8976
8977 if (is_load) {
carll1f5fe1f2014-08-07 23:25:23 +00008978 putFReg( frT_hi_addr, load(Ity_F64, mkexpr(EA_hi)) );
8979 putFReg( frT_lo_addr, load(Ity_F64, mkexpr(EA_lo)) );
sewardj7e846302010-09-03 23:37:02 +00008980 } else {
carll1f5fe1f2014-08-07 23:25:23 +00008981 store( mkexpr(EA_hi), mkexpr(frT_hi) );
8982 store( mkexpr(EA_lo), mkexpr(frT_lo) );
sewardj7e846302010-09-03 23:37:02 +00008983 }
8984
8985 return True;
8986}
sewardje14bb9f2005-07-22 09:39:02 +00008987
8988
8989/*
carll78850ae2013-09-10 18:46:40 +00008990 Floating Point Merge Instructions
8991*/
8992static Bool dis_fp_merge ( UInt theInstr )
8993{
8994 /* X-Form */
8995 UInt opc2 = ifieldOPClo10(theInstr);
8996 UChar frD_addr = ifieldRegDS(theInstr);
8997 UChar frA_addr = ifieldRegA(theInstr);
8998 UChar frB_addr = ifieldRegB(theInstr);
8999
9000 IRTemp frD = newTemp(Ity_F64);
9001 IRTemp frA = newTemp(Ity_F64);
9002 IRTemp frB = newTemp(Ity_F64);
9003
9004 assign( frA, getFReg(frA_addr));
9005 assign( frB, getFReg(frB_addr));
9006
9007 switch (opc2) {
9008 case 0x3c6: // fmrgew floating merge even word
9009 DIP("fmrgew fr%u,fr%u,fr%u\n", frD_addr, frA_addr, frB_addr);
9010
9011 assign( frD, unop( Iop_ReinterpI64asF64,
9012 binop( Iop_32HLto64,
9013 unop( Iop_64HIto32,
9014 unop( Iop_ReinterpF64asI64,
9015 mkexpr(frA) ) ),
9016 unop( Iop_64HIto32,
9017 unop( Iop_ReinterpF64asI64,
9018 mkexpr(frB) ) ) ) ) );
9019 break;
9020
9021 case 0x346: // fmrgow floating merge odd word
9022 DIP("fmrgow fr%u,fr%u,fr%u\n", frD_addr, frA_addr, frB_addr);
9023
9024 assign( frD, unop( Iop_ReinterpI64asF64,
9025 binop( Iop_32HLto64,
9026 unop( Iop_64to32,
9027 unop( Iop_ReinterpF64asI64,
9028 mkexpr(frA) ) ),
9029 unop( Iop_64to32,
9030 unop( Iop_ReinterpF64asI64,
9031 mkexpr(frB) ) ) ) ) );
9032 break;
9033
9034 default:
9035 vex_printf("dis_fp_merge(ppc)(opc2)\n");
9036 return False;
9037 }
9038
9039 putFReg( frD_addr, mkexpr(frD) );
9040 return True;
9041}
9042
9043/*
sewardje14bb9f2005-07-22 09:39:02 +00009044 Floating Point Move Instructions
9045*/
9046static Bool dis_fp_move ( UInt theInstr )
9047{
9048 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00009049 UChar opc1 = ifieldOPC(theInstr);
9050 UChar frD_addr = ifieldRegDS(theInstr);
sewardj7e846302010-09-03 23:37:02 +00009051 UChar frA_addr = ifieldRegA(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00009052 UChar frB_addr = ifieldRegB(theInstr);
9053 UInt opc2 = ifieldOPClo10(theInstr);
9054 UChar flag_rC = ifieldBIT0(theInstr);
sewardje14bb9f2005-07-22 09:39:02 +00009055
9056 IRTemp frD = newTemp(Ity_F64);
9057 IRTemp frB = newTemp(Ity_F64);
sewardj7e846302010-09-03 23:37:02 +00009058 IRTemp itmpB = newTemp(Ity_F64);
9059 IRTemp frA;
9060 IRTemp signA;
9061 IRTemp hiD;
sewardje14bb9f2005-07-22 09:39:02 +00009062
sewardj7e846302010-09-03 23:37:02 +00009063 if (opc1 != 0x3F || (frA_addr != 0 && opc2 != 0x008)) {
cerion5b2325f2005-12-23 00:55:09 +00009064 vex_printf("dis_fp_move(ppc)(instr)\n");
sewardje14bb9f2005-07-22 09:39:02 +00009065 return False;
9066 }
9067
9068 assign( frB, getFReg(frB_addr));
9069
sewardje14bb9f2005-07-22 09:39:02 +00009070 switch (opc2) {
sewardj7e846302010-09-03 23:37:02 +00009071 case 0x008: // fcpsgn (Floating Copy Sign, ISA_V2.05 p126)
9072 DIP("fcpsgn%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frA_addr,
9073 frB_addr);
9074 signA = newTemp(Ity_I32);
9075 hiD = newTemp(Ity_I32);
9076 itmpB = newTemp(Ity_I64);
9077 frA = newTemp(Ity_F64);
9078 assign( frA, getFReg(frA_addr) );
9079
9080 /* get A's sign bit */
9081 assign(signA, binop(Iop_And32,
9082 unop(Iop_64HIto32, unop(Iop_ReinterpF64asI64,
9083 mkexpr(frA))),
9084 mkU32(0x80000000)) );
9085
9086 assign( itmpB, unop(Iop_ReinterpF64asI64, mkexpr(frB)) );
9087
9088 /* mask off B's sign bit and or in A's sign bit */
9089 assign(hiD, binop(Iop_Or32,
9090 binop(Iop_And32,
9091 unop(Iop_64HIto32,
9092 mkexpr(itmpB)), /* frB's high 32 bits */
9093 mkU32(0x7fffffff)),
9094 mkexpr(signA)) );
9095
9096 /* combine hiD/loB into frD */
9097 assign( frD, unop(Iop_ReinterpI64asF64,
9098 binop(Iop_32HLto64,
9099 mkexpr(hiD),
9100 unop(Iop_64to32,
9101 mkexpr(itmpB)))) ); /* frB's low 32 bits */
9102 break;
9103
ceriond953ebb2005-11-29 13:27:20 +00009104 case 0x028: // fneg (Floating Negate, PPC32 p416)
cerion5b2325f2005-12-23 00:55:09 +00009105 DIP("fneg%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
ceriond953ebb2005-11-29 13:27:20 +00009106 assign( frD, unop( Iop_NegF64, mkexpr(frB) ));
9107 break;
9108
9109 case 0x048: // fmr (Floating Move Register, PPC32 p410)
cerion5b2325f2005-12-23 00:55:09 +00009110 DIP("fmr%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
ceriond953ebb2005-11-29 13:27:20 +00009111 assign( frD, mkexpr(frB) );
9112 break;
9113
9114 case 0x088: // fnabs (Floating Negative Absolute Value, PPC32 p415)
cerion5b2325f2005-12-23 00:55:09 +00009115 DIP("fnabs%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
ceriond953ebb2005-11-29 13:27:20 +00009116 assign( frD, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr(frB) )));
9117 break;
9118
9119 case 0x108: // fabs (Floating Absolute Value, PPC32 p399)
cerion5b2325f2005-12-23 00:55:09 +00009120 DIP("fabs%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
ceriond953ebb2005-11-29 13:27:20 +00009121 assign( frD, unop( Iop_AbsF64, mkexpr(frB) ));
9122 break;
9123
9124 default:
cerion5b2325f2005-12-23 00:55:09 +00009125 vex_printf("dis_fp_move(ppc)(opc2)\n");
ceriond953ebb2005-11-29 13:27:20 +00009126 return False;
sewardje14bb9f2005-07-22 09:39:02 +00009127 }
9128
9129 putFReg( frD_addr, mkexpr(frD) );
sewardjb183b852006-02-03 16:08:03 +00009130
9131 /* None of these change FPRF. cr1 is set in the usual way though,
9132 if flag_rC is set. */
9133
9134 if (flag_rC) {
9135 putCR321( 1, mkU8(0) );
9136 putCR0( 1, mkU8(0) );
9137 }
9138
sewardje14bb9f2005-07-22 09:39:02 +00009139 return True;
9140}
9141
9142
9143
9144/*
9145 Floating Point Status/Control Register Instructions
9146*/
sewardjc6bbd472012-04-02 10:20:48 +00009147static Bool dis_fp_scr ( UInt theInstr, Bool GX_level )
sewardje14bb9f2005-07-22 09:39:02 +00009148{
cerion76de5cf2005-11-18 18:25:12 +00009149 /* Many forms - see each switch case */
9150 UChar opc1 = ifieldOPC(theInstr);
9151 UInt opc2 = ifieldOPClo10(theInstr);
9152 UChar flag_rC = ifieldBIT0(theInstr);
sewardje14bb9f2005-07-22 09:39:02 +00009153
9154 if (opc1 != 0x3F) {
cerion5b2325f2005-12-23 00:55:09 +00009155 vex_printf("dis_fp_scr(ppc)(instr)\n");
sewardje14bb9f2005-07-22 09:39:02 +00009156 return False;
9157 }
9158
9159 switch (opc2) {
cerion3ea49ee2006-01-04 10:53:00 +00009160 case 0x026: { // mtfsb1 (Move to FPSCR Bit 1, PPC32 p479)
9161 // Bit crbD of the FPSCR is set.
9162 UChar crbD = ifieldRegDS(theInstr);
9163 UInt b11to20 = IFIELD(theInstr, 11, 10);
9164
9165 if (b11to20 != 0) {
9166 vex_printf("dis_fp_scr(ppc)(instr,mtfsb1)\n");
9167 return False;
9168 }
9169 DIP("mtfsb1%s crb%d \n", flag_rC ? ".":"", crbD);
sewardjc6bbd472012-04-02 10:20:48 +00009170 putGST_masked( PPC_GST_FPSCR, mkU64( 1 <<( 31 - crbD ) ),
9171 1ULL << ( 31 - crbD ) );
cerion3ea49ee2006-01-04 10:53:00 +00009172 break;
9173 }
9174
sewardj496b88f2006-10-04 17:46:11 +00009175 case 0x040: { // mcrfs (Move to Condition Register from FPSCR, PPC32 p465)
9176 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
9177 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
9178 UChar crfS = toUChar( IFIELD( theInstr, 18, 3 ) );
9179 UChar b11to17 = toUChar( IFIELD( theInstr, 11, 7 ) );
9180 IRTemp tmp = newTemp(Ity_I32);
9181 IRExpr* fpscr_all;
9182 if (b21to22 != 0 || b11to17 != 0 || flag_rC != 0) {
9183 vex_printf("dis_fp_scr(ppc)(instr,mcrfs)\n");
9184 return False;
9185 }
9186 DIP("mcrfs crf%d,crf%d\n", crfD, crfS);
9187 vassert(crfD < 8);
9188 vassert(crfS < 8);
9189 fpscr_all = getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN );
9190 assign( tmp, binop(Iop_And32,
9191 binop(Iop_Shr32,fpscr_all,mkU8(4 * (7-crfS))),
9192 mkU32(0xF)) );
9193 putGST_field( PPC_GST_CR, mkexpr(tmp), crfD );
9194 break;
9195 }
sewardj0e2cc672005-07-29 21:58:51 +00009196
9197 case 0x046: { // mtfsb0 (Move to FPSCR Bit 0, PPC32 p478)
9198 // Bit crbD of the FPSCR is cleared.
cerion76de5cf2005-11-18 18:25:12 +00009199 UChar crbD = ifieldRegDS(theInstr);
9200 UInt b11to20 = IFIELD(theInstr, 11, 10);
sewardj0e2cc672005-07-29 21:58:51 +00009201
9202 if (b11to20 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00009203 vex_printf("dis_fp_scr(ppc)(instr,mtfsb0)\n");
sewardj0e2cc672005-07-29 21:58:51 +00009204 return False;
9205 }
cerion5b2325f2005-12-23 00:55:09 +00009206 DIP("mtfsb0%s crb%d\n", flag_rC ? ".":"", crbD);
sewardjc6bbd472012-04-02 10:20:48 +00009207 putGST_masked( PPC_GST_FPSCR, mkU64( 0 ), 1ULL << ( 31 - crbD ) );
sewardj0e2cc672005-07-29 21:58:51 +00009208 break;
9209 }
9210
9211 case 0x086: { // mtfsfi (Move to FPSCR Field Immediate, PPC32 p481)
sewardjc6bbd472012-04-02 10:20:48 +00009212 UInt crfD = IFIELD( theInstr, 23, 3 );
cerion76de5cf2005-11-18 18:25:12 +00009213 UChar b16to22 = toUChar( IFIELD( theInstr, 16, 7 ) );
9214 UChar IMM = toUChar( IFIELD( theInstr, 12, 4 ) );
9215 UChar b11 = toUChar( IFIELD( theInstr, 11, 1 ) );
sewardjc6bbd472012-04-02 10:20:48 +00009216 UChar Wbit;
sewardj0e2cc672005-07-29 21:58:51 +00009217
9218 if (b16to22 != 0 || b11 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00009219 vex_printf("dis_fp_scr(ppc)(instr,mtfsfi)\n");
sewardj0e2cc672005-07-29 21:58:51 +00009220 return False;
9221 }
cerion5b2325f2005-12-23 00:55:09 +00009222 DIP("mtfsfi%s crf%d,%d\n", flag_rC ? ".":"", crfD, IMM);
sewardjc6bbd472012-04-02 10:20:48 +00009223 if (GX_level) {
9224 /* This implies that Decimal Floating Point is supported, and the
9225 * FPSCR must be managed as a 64-bit register.
9226 */
9227 Wbit = toUChar( IFIELD(theInstr, 16, 1) );
9228 } else {
9229 Wbit = 0;
9230 }
9231 crfD = crfD + (8 * (1 - Wbit) );
9232 putGST_field( PPC_GST_FPSCR, mkU32( IMM ), crfD );
sewardj0e2cc672005-07-29 21:58:51 +00009233 break;
9234 }
sewardje14bb9f2005-07-22 09:39:02 +00009235
9236 case 0x247: { // mffs (Move from FPSCR, PPC32 p468)
sewardj496b88f2006-10-04 17:46:11 +00009237 UChar frD_addr = ifieldRegDS(theInstr);
9238 UInt b11to20 = IFIELD(theInstr, 11, 10);
sewardjc6bbd472012-04-02 10:20:48 +00009239 IRExpr* fpscr_lower = getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN );
9240 IRExpr* fpscr_upper = getGST_masked_upper( PPC_GST_FPSCR,
9241 MASK_FPSCR_DRN );
sewardje14bb9f2005-07-22 09:39:02 +00009242
9243 if (b11to20 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00009244 vex_printf("dis_fp_scr(ppc)(instr,mffs)\n");
sewardje14bb9f2005-07-22 09:39:02 +00009245 return False;
9246 }
cerion5b2325f2005-12-23 00:55:09 +00009247 DIP("mffs%s fr%u\n", flag_rC ? ".":"", frD_addr);
9248 putFReg( frD_addr,
9249 unop( Iop_ReinterpI64asF64,
sewardjc6bbd472012-04-02 10:20:48 +00009250 binop( Iop_32HLto64, fpscr_upper, fpscr_lower ) ) );
sewardje14bb9f2005-07-22 09:39:02 +00009251 break;
9252 }
9253
9254 case 0x2C7: { // mtfsf (Move to FPSCR Fields, PPC32 p480)
cerion76de5cf2005-11-18 18:25:12 +00009255 UChar b25 = toUChar( IFIELD(theInstr, 25, 1) );
9256 UChar FM = toUChar( IFIELD(theInstr, 17, 8) );
cerion76de5cf2005-11-18 18:25:12 +00009257 UChar frB_addr = ifieldRegB(theInstr);
9258 IRTemp frB = newTemp(Ity_F64);
sewardjc6bbd472012-04-02 10:20:48 +00009259 IRTemp rB_64 = newTemp( Ity_I64 );
9260 Int i;
9261 ULong mask;
9262 UChar Wbit;
9263#define BFP_MASK_SEED 0x3000000000000000ULL
9264#define DFP_MASK_SEED 0x7000000000000000ULL
9265
9266 if (GX_level) {
9267 /* This implies that Decimal Floating Point is supported, and the
9268 * FPSCR must be managed as a 64-bit register.
9269 */
9270 Wbit = toUChar( IFIELD(theInstr, 16, 1) );
9271 } else {
9272 Wbit = 0;
9273 }
sewardje14bb9f2005-07-22 09:39:02 +00009274
sewardj7e846302010-09-03 23:37:02 +00009275 if (b25 == 1) {
9276 /* new 64 bit move variant for power 6. If L field (bit 25) is
9277 * a one do a full 64 bit move. Note, the FPSCR is not really
9278 * properly modeled. This instruciton only changes the value of
9279 * the rounding mode. The HW exception bits do not get set in
9280 * the simulator. 1/12/09
9281 */
9282 DIP("mtfsf%s %d,fr%u (L=1)\n", flag_rC ? ".":"", FM, frB_addr);
9283 mask = 0xFF;
9284
9285 } else {
9286 DIP("mtfsf%s %d,fr%u\n", flag_rC ? ".":"", FM, frB_addr);
9287 // Build 32bit mask from FM:
9288 mask = 0;
9289 for (i=0; i<8; i++) {
9290 if ((FM & (1<<(7-i))) == 1) {
sewardjc6bbd472012-04-02 10:20:48 +00009291 /* FPSCR field k is set to the contents of the corresponding
9292 * field of register FRB, where k = i+8x(1-W). In the Power
9293 * ISA, register field numbering is from left to right, so field
9294 * 15 is the least significant field in a 64-bit register. To
9295 * generate the mask, we set all the appropriate rounding mode
9296 * bits in the highest order nibble (field 0) and shift right
9297 * 'k x nibble length'.
9298 */
9299 if (Wbit)
9300 mask |= DFP_MASK_SEED >> ( 4 * ( i + 8 * ( 1 - Wbit ) ) );
9301 else
9302 mask |= BFP_MASK_SEED >> ( 4 * ( i + 8 * ( 1 - Wbit ) ) );
sewardj7e846302010-09-03 23:37:02 +00009303 }
9304 }
9305 }
sewardje14bb9f2005-07-22 09:39:02 +00009306 assign( frB, getFReg(frB_addr));
sewardjc6bbd472012-04-02 10:20:48 +00009307 assign( rB_64, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
9308 putGST_masked( PPC_GST_FPSCR, mkexpr( rB_64 ), mask );
sewardje14bb9f2005-07-22 09:39:02 +00009309 break;
9310 }
9311
9312 default:
cerion5b2325f2005-12-23 00:55:09 +00009313 vex_printf("dis_fp_scr(ppc)(opc2)\n");
sewardje14bb9f2005-07-22 09:39:02 +00009314 return False;
9315 }
9316 return True;
9317}
9318
sewardjc6bbd472012-04-02 10:20:48 +00009319/*------------------------------------------------------------*/
sewardj5eff1c52012-04-29 20:19:17 +00009320/*--- Decimal Floating Point (DFP) Helper functions ---*/
9321/*------------------------------------------------------------*/
9322#define DFP_LONG 1
9323#define DFP_EXTND 2
sewardj4c96e612012-06-02 23:47:02 +00009324#define DFP_LONG_BIAS 398
sewardj5eff1c52012-04-29 20:19:17 +00009325#define DFP_LONG_ENCODED_FIELD_MASK 0x1F00
sewardj4c96e612012-06-02 23:47:02 +00009326#define DFP_EXTND_BIAS 6176
sewardj5eff1c52012-04-29 20:19:17 +00009327#define DFP_EXTND_ENCODED_FIELD_MASK 0x1F000
9328#define DFP_LONG_EXP_MSK 0XFF
9329#define DFP_EXTND_EXP_MSK 0XFFF
9330
9331#define DFP_G_FIELD_LONG_MASK 0x7FFC0000 // upper 32-bits only
9332#define DFP_LONG_GFIELD_RT_SHIFT (63 - 13 - 32) // adj for upper 32-bits
9333#define DFP_G_FIELD_EXTND_MASK 0x7FFFC000 // upper 32-bits only
9334#define DFP_EXTND_GFIELD_RT_SHIFT (63 - 17 - 32) //adj for upper 32 bits
sewardj5eff1c52012-04-29 20:19:17 +00009335#define DFP_T_FIELD_LONG_MASK 0x3FFFF // mask for upper 32-bits
9336#define DFP_T_FIELD_EXTND_MASK 0x03FFFF // mask for upper 32-bits
sewardj5eff1c52012-04-29 20:19:17 +00009337#define DFP_LONG_EXP_MAX 369 // biased max
9338#define DFP_LONG_EXP_MIN 0 // biased min
9339#define DFP_EXTND_EXP_MAX 6111 // biased max
9340#define DFP_EXTND_EXP_MIN 0 // biased min
sewardj4c96e612012-06-02 23:47:02 +00009341#define DFP_LONG_MAX_SIG_DIGITS 16
9342#define DFP_EXTND_MAX_SIG_DIGITS 34
9343#define MAX_DIGITS_IN_STRING 8
9344
sewardj5eff1c52012-04-29 20:19:17 +00009345
9346#define AND(x, y) binop( Iop_And32, x, y )
sewardj5eff1c52012-04-29 20:19:17 +00009347#define AND4(w, x, y, z) AND( AND( w, x ), AND( y, z ) )
sewardj4c96e612012-06-02 23:47:02 +00009348#define OR(x, y) binop( Iop_Or32, x, y )
sewardj5eff1c52012-04-29 20:19:17 +00009349#define OR3(x, y, z) OR( x, OR( y, z ) )
9350#define OR4(w, x, y, z) OR( OR( w, x ), OR( y, z ) )
sewardj4c96e612012-06-02 23:47:02 +00009351#define NOT(x) unop( Iop_1Uto32, unop( Iop_Not1, unop( Iop_32to1, mkexpr( x ) ) ) )
9352
sewardj5eff1c52012-04-29 20:19:17 +00009353#define SHL(value, by) binop( Iop_Shl32, value, mkU8( by ) )
sewardj4c96e612012-06-02 23:47:02 +00009354#define SHR(value, by) binop( Iop_Shr32, value, mkU8( by ) )
9355
sewardjcb06d5e2012-04-30 08:10:11 +00009356#define BITS5(_b4,_b3,_b2,_b1,_b0) \
9357 (((_b4) << 4) | ((_b3) << 3) | ((_b2) << 2) | \
9358 ((_b1) << 1) | ((_b0) << 0))
sewardj5eff1c52012-04-29 20:19:17 +00009359
sewardj4c96e612012-06-02 23:47:02 +00009360static IRExpr * Gfield_encoding( IRExpr * lmexp, IRExpr * lmd32 )
sewardj5eff1c52012-04-29 20:19:17 +00009361{
sewardj4c96e612012-06-02 23:47:02 +00009362 IRTemp lmd_07_mask = newTemp( Ity_I32 );
9363 IRTemp lmd_8_mask = newTemp( Ity_I32 );
9364 IRTemp lmd_9_mask = newTemp( Ity_I32 );
9365 IRTemp lmexp_00_mask = newTemp( Ity_I32 );
9366 IRTemp lmexp_01_mask = newTemp( Ity_I32 );
9367 IRTemp lmexp_10_mask = newTemp( Ity_I32 );
9368 IRTemp lmd_07_val = newTemp( Ity_I32 );
9369 IRTemp lmd_8_val = newTemp( Ity_I32 );
9370 IRTemp lmd_9_val = newTemp( Ity_I32 );
sewardj5eff1c52012-04-29 20:19:17 +00009371
sewardj4c96e612012-06-02 23:47:02 +00009372 /* The encodig is as follows:
9373 * lmd - left most digit
9374 * lme - left most 2-bits of the exponent
9375 *
9376 * lmd
9377 * 0 - 7 (lmexp << 3) | lmd
9378 * 8 0b11000 (24 decimal) if lme=0b00;
9379 * 0b11010 (26 decimal) if lme=0b01;
9380 * 0b11100 (28 decimal) if lme=0b10;
9381 * 9 0b11001 (25 decimal) if lme=0b00;
9382 * 0b11011 (27 decimal) if lme=0b01;
9383 * 0b11101 (29 decimal) if lme=0b10;
9384 */
9385
9386 /* Generate the masks for each condition */
9387 assign( lmd_07_mask,
9388 unop( Iop_1Sto32, binop( Iop_CmpLE32U, lmd32, mkU32( 7 ) ) ) );
9389 assign( lmd_8_mask,
9390 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmd32, mkU32( 8 ) ) ) );
9391 assign( lmd_9_mask,
9392 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmd32, mkU32( 9 ) ) ) );
9393 assign( lmexp_00_mask,
9394 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 0 ) ) ) );
9395 assign( lmexp_01_mask,
9396 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 1 ) ) ) );
9397 assign( lmexp_10_mask,
9398 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 2 ) ) ) );
9399
9400 /* Generate the values for each LMD condition, assuming the condition
9401 * is TRUE.
9402 */
9403 assign( lmd_07_val,
9404 binop( Iop_Or32, binop( Iop_Shl32, lmexp, mkU8( 3 ) ), lmd32 ) );
9405 assign( lmd_8_val,
9406 binop( Iop_Or32,
9407 binop( Iop_Or32,
9408 binop( Iop_And32,
9409 mkexpr( lmexp_00_mask ),
9410 mkU32( 24 ) ),
9411 binop( Iop_And32,
9412 mkexpr( lmexp_01_mask ),
9413 mkU32( 26 ) ) ),
9414 binop( Iop_And32, mkexpr( lmexp_10_mask ), mkU32( 28 ) ) ) );
9415 assign( lmd_9_val,
9416 binop( Iop_Or32,
9417 binop( Iop_Or32,
9418 binop( Iop_And32,
9419 mkexpr( lmexp_00_mask ),
9420 mkU32( 25 ) ),
9421 binop( Iop_And32,
9422 mkexpr( lmexp_01_mask ),
9423 mkU32( 27 ) ) ),
9424 binop( Iop_And32, mkexpr( lmexp_10_mask ), mkU32( 29 ) ) ) );
9425
9426 /* generate the result from the possible LMD values */
9427 return binop( Iop_Or32,
9428 binop( Iop_Or32,
9429 binop( Iop_And32,
9430 mkexpr( lmd_07_mask ),
9431 mkexpr( lmd_07_val ) ),
9432 binop( Iop_And32,
9433 mkexpr( lmd_8_mask ),
9434 mkexpr( lmd_8_val ) ) ),
9435 binop( Iop_And32, mkexpr( lmd_9_mask ), mkexpr( lmd_9_val ) ) );
9436}
9437
9438static void Get_lmd( IRTemp * lmd, IRExpr * gfield_0_4 )
9439{
sewardj5eff1c52012-04-29 20:19:17 +00009440 /* Extract the exponent and the left most digit of the mantissa
9441 * from the G field bits [0:4].
9442 */
9443 IRTemp lmd_07_mask = newTemp( Ity_I32 );
9444 IRTemp lmd_8_00_mask = newTemp( Ity_I32 );
9445 IRTemp lmd_8_01_mask = newTemp( Ity_I32 );
9446 IRTemp lmd_8_10_mask = newTemp( Ity_I32 );
9447 IRTemp lmd_9_00_mask = newTemp( Ity_I32 );
9448 IRTemp lmd_9_01_mask = newTemp( Ity_I32 );
9449 IRTemp lmd_9_10_mask = newTemp( Ity_I32 );
9450
9451 IRTemp lmd_07_val = newTemp( Ity_I32 );
9452 IRTemp lmd_8_val = newTemp( Ity_I32 );
9453 IRTemp lmd_9_val = newTemp( Ity_I32 );
9454
9455 /* The left most digit (LMD) encoding is as follows:
9456 * lmd
9457 * 0 - 7 (lmexp << 3) | lmd
9458 * 8 0b11000 (24 decimal) if lme=0b00;
9459 * 0b11010 (26 decimal) if lme=0b01;
9460 * 0b11100 (28 decimal) if lme=0b10
9461 * 9 0b11001 (25 decimal) if lme=0b00;
9462 * 0b11011 (27 decimal) if lme=0b01;
9463 * 0b11101 (29 decimal) if lme=0b10;
9464 */
9465
9466 /* Generate the masks for each condition of LMD and exponent bits */
sewardjcb06d5e2012-04-30 08:10:11 +00009467 assign( lmd_07_mask,
9468 unop( Iop_1Sto32, binop( Iop_CmpLE32U,
9469 gfield_0_4,
9470 mkU32( BITS5(1,0,1,1,1) ) ) ) );
9471 assign( lmd_8_00_mask,
9472 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
9473 gfield_0_4,
9474 mkU32( BITS5(1,1,0,0,0) ) ) ) );
9475 assign( lmd_8_01_mask,
9476 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
9477 gfield_0_4,
9478 mkU32( BITS5(1,1,0,1,0) ) ) ) );
9479 assign( lmd_8_10_mask,
9480 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
9481 gfield_0_4,
9482 mkU32( BITS5(1,1,1,0,0) ) ) ) );
9483 assign( lmd_9_00_mask,
9484 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
9485 gfield_0_4,
9486 mkU32( BITS5(1,1,0,0,1) ) ) ) );
9487 assign( lmd_9_01_mask,
9488 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
9489 gfield_0_4,
9490 mkU32( BITS5(1,1,0,1,1) ) ) ) );
9491 assign( lmd_9_10_mask,
9492 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
9493 gfield_0_4,
9494 mkU32( BITS5(1,1,1,0,1) ) ) ) );
sewardj5eff1c52012-04-29 20:19:17 +00009495
9496 /* Generate the values for each LMD condition, assuming the condition
9497 * is TRUE.
9498 */
9499 assign( lmd_07_val, binop( Iop_And32, gfield_0_4, mkU32( 0x7 ) ) );
9500 assign( lmd_8_val, mkU32( 0x8 ) );
9501 assign( lmd_9_val, mkU32( 0x9 ) );
9502
9503 assign( *lmd,
9504 OR( OR3 ( AND( mkexpr( lmd_07_mask ), mkexpr( lmd_07_val ) ),
9505 AND( mkexpr( lmd_8_00_mask ), mkexpr( lmd_8_val ) ),
9506 AND( mkexpr( lmd_8_01_mask ), mkexpr( lmd_8_val ) )),
9507 OR4( AND( mkexpr( lmd_8_10_mask ), mkexpr( lmd_8_val ) ),
9508 AND( mkexpr( lmd_9_00_mask ), mkexpr( lmd_9_val ) ),
9509 AND( mkexpr( lmd_9_01_mask ), mkexpr( lmd_9_val ) ),
9510 AND( mkexpr( lmd_9_10_mask ), mkexpr( lmd_9_val ) )
9511 ) ) );
9512}
9513
sewardj4c96e612012-06-02 23:47:02 +00009514#define DIGIT1_SHR 4 // shift digit 1 to bottom 4 bits
9515#define DIGIT2_SHR 8 // shift digit 2 to bottom 4 bits
9516#define DIGIT3_SHR 12
9517#define DIGIT4_SHR 16
9518#define DIGIT5_SHR 20
9519#define DIGIT6_SHR 24
9520#define DIGIT7_SHR 28
9521
9522static IRExpr * bcd_digit_inval( IRExpr * bcd_u, IRExpr * bcd_l )
9523{
9524 /* 60-bit BCD string stored in two 32-bit values. Check that each,
9525 * digit is a valid BCD number, i.e. less then 9.
9526 */
9527 IRTemp valid = newTemp( Ity_I32 );
9528
9529 assign( valid,
9530 AND4( AND4 ( unop( Iop_1Sto32,
9531 binop( Iop_CmpLE32U,
9532 binop( Iop_And32,
9533 bcd_l,
9534 mkU32 ( 0xF ) ),
9535 mkU32( 0x9 ) ) ),
9536 unop( Iop_1Sto32,
9537 binop( Iop_CmpLE32U,
9538 binop( Iop_And32,
9539 binop( Iop_Shr32,
9540 bcd_l,
9541 mkU8 ( DIGIT1_SHR ) ),
9542 mkU32 ( 0xF ) ),
9543 mkU32( 0x9 ) ) ),
9544 unop( Iop_1Sto32,
9545 binop( Iop_CmpLE32U,
9546 binop( Iop_And32,
9547 binop( Iop_Shr32,
9548 bcd_l,
9549 mkU8 ( DIGIT2_SHR ) ),
9550 mkU32 ( 0xF ) ),
9551 mkU32( 0x9 ) ) ),
9552 unop( Iop_1Sto32,
9553 binop( Iop_CmpLE32U,
9554 binop( Iop_And32,
9555 binop( Iop_Shr32,
9556 bcd_l,
9557 mkU8 ( DIGIT3_SHR ) ),
9558 mkU32 ( 0xF ) ),
9559 mkU32( 0x9 ) ) ) ),
9560 AND4 ( unop( Iop_1Sto32,
9561 binop( Iop_CmpLE32U,
9562 binop( Iop_And32,
9563 binop( Iop_Shr32,
9564 bcd_l,
9565 mkU8 ( DIGIT4_SHR ) ),
9566 mkU32 ( 0xF ) ),
9567 mkU32( 0x9 ) ) ),
9568 unop( Iop_1Sto32,
9569 binop( Iop_CmpLE32U,
9570 binop( Iop_And32,
9571 binop( Iop_Shr32,
9572 bcd_l,
9573 mkU8 ( DIGIT5_SHR ) ),
9574 mkU32 ( 0xF ) ),
9575 mkU32( 0x9 ) ) ),
9576 unop( Iop_1Sto32,
9577 binop( Iop_CmpLE32U,
9578 binop( Iop_And32,
9579 binop( Iop_Shr32,
9580 bcd_l,
9581 mkU8 ( DIGIT6_SHR ) ),
9582 mkU32 ( 0xF ) ),
9583 mkU32( 0x9 ) ) ),
9584 unop( Iop_1Sto32,
9585 binop( Iop_CmpLE32U,
9586 binop( Iop_And32,
9587 binop( Iop_Shr32,
9588 bcd_l,
9589 mkU8 ( DIGIT7_SHR ) ),
9590 mkU32 ( 0xF ) ),
9591 mkU32( 0x9 ) ) ) ),
9592 AND4( unop( Iop_1Sto32,
9593 binop( Iop_CmpLE32U,
9594 binop( Iop_And32,
9595 bcd_u,
9596 mkU32 ( 0xF ) ),
9597 mkU32( 0x9 ) ) ),
9598 unop( Iop_1Sto32,
9599 binop( Iop_CmpLE32U,
9600 binop( Iop_And32,
9601 binop( Iop_Shr32,
9602 bcd_u,
9603 mkU8 ( DIGIT1_SHR ) ),
9604 mkU32 ( 0xF ) ),
9605 mkU32( 0x9 ) ) ),
9606 unop( Iop_1Sto32,
9607 binop( Iop_CmpLE32U,
9608 binop( Iop_And32,
9609 binop( Iop_Shr32,
9610 bcd_u,
9611 mkU8 ( DIGIT2_SHR ) ),
9612 mkU32 ( 0xF ) ),
9613 mkU32( 0x9 ) ) ),
9614 unop( Iop_1Sto32,
9615 binop( Iop_CmpLE32U,
9616 binop( Iop_And32,
9617 binop( Iop_Shr32,
9618 bcd_u,
9619 mkU8 ( DIGIT3_SHR ) ),
9620 mkU32 ( 0xF ) ),
9621 mkU32( 0x9 ) ) ) ),
9622 AND4( unop( Iop_1Sto32,
9623 binop( Iop_CmpLE32U,
9624 binop( Iop_And32,
9625 binop( Iop_Shr32,
9626 bcd_u,
9627 mkU8 ( DIGIT4_SHR ) ),
9628 mkU32 ( 0xF ) ),
9629 mkU32( 0x9 ) ) ),
9630 unop( Iop_1Sto32,
9631 binop( Iop_CmpLE32U,
9632 binop( Iop_And32,
9633 binop( Iop_Shr32,
9634 bcd_u,
9635 mkU8 ( DIGIT5_SHR ) ),
9636 mkU32 ( 0xF ) ),
9637 mkU32( 0x9 ) ) ),
9638 unop( Iop_1Sto32,
9639 binop( Iop_CmpLE32U,
9640 binop( Iop_And32,
9641 binop( Iop_Shr32,
9642 bcd_u,
9643 mkU8 ( DIGIT6_SHR ) ),
9644 mkU32 ( 0xF ) ),
9645 mkU32( 0x9 ) ) ),
9646 unop( Iop_1Sto32,
9647 binop( Iop_CmpLE32U,
9648 binop( Iop_And32,
9649 binop( Iop_Shr32,
9650 bcd_u,
9651 mkU8 ( DIGIT7_SHR ) ),
9652 mkU32 ( 0xF ) ),
9653 mkU32( 0x9 ) ) ) ) ) );
9654
9655 return unop( Iop_Not32, mkexpr( valid ) );
9656}
9657#undef DIGIT1_SHR
9658#undef DIGIT2_SHR
9659#undef DIGIT3_SHR
9660#undef DIGIT4_SHR
9661#undef DIGIT5_SHR
9662#undef DIGIT6_SHR
9663#undef DIGIT7_SHR
9664
9665static IRExpr * Generate_neg_sign_mask( IRExpr * sign )
9666{
9667 return binop( Iop_Or32,
9668 unop( Iop_1Sto32, binop( Iop_CmpEQ32, sign, mkU32( 0xB ) ) ),
9669 unop( Iop_1Sto32, binop( Iop_CmpEQ32, sign, mkU32( 0xD ) ) )
9670 );
9671}
9672
9673static IRExpr * Generate_pos_sign_mask( IRExpr * sign )
9674{
9675 return binop( Iop_Or32,
9676 binop( Iop_Or32,
9677 unop( Iop_1Sto32,
9678 binop( Iop_CmpEQ32, sign, mkU32( 0xA ) ) ),
9679 unop( Iop_1Sto32,
9680 binop( Iop_CmpEQ32, sign, mkU32( 0xC ) ) ) ),
9681 binop( Iop_Or32,
9682 unop( Iop_1Sto32,
9683 binop( Iop_CmpEQ32, sign, mkU32( 0xE ) ) ),
9684 unop( Iop_1Sto32,
9685 binop( Iop_CmpEQ32, sign, mkU32( 0xF ) ) ) ) );
9686}
9687
9688static IRExpr * Generate_sign_bit( IRExpr * pos_sign_mask,
9689 IRExpr * neg_sign_mask )
9690{
9691 return binop( Iop_Or32,
9692 binop( Iop_And32, neg_sign_mask, mkU32( 0x80000000 ) ),
9693 binop( Iop_And32, pos_sign_mask, mkU32( 0x00000000 ) ) );
9694}
9695
9696static IRExpr * Generate_inv_mask( IRExpr * invalid_bcd_mask,
9697 IRExpr * pos_sign_mask,
9698 IRExpr * neg_sign_mask )
9699/* first argument is all 1's if the BCD string had an invalid digit in it. */
9700{
9701 return binop( Iop_Or32,
9702 invalid_bcd_mask,
9703 unop( Iop_1Sto32,
9704 binop( Iop_CmpEQ32,
9705 binop( Iop_Or32, pos_sign_mask, neg_sign_mask ),
9706 mkU32( 0x0 ) ) ) );
9707}
9708
9709static void Generate_132_bit_bcd_string( IRExpr * frBI64_hi, IRExpr * frBI64_lo,
9710 IRTemp * top_12_l, IRTemp * mid_60_u,
9711 IRTemp * mid_60_l, IRTemp * low_60_u,
9712 IRTemp * low_60_l)
9713{
9714 IRTemp tmplow60 = newTemp( Ity_I64 );
9715 IRTemp tmpmid60 = newTemp( Ity_I64 );
9716 IRTemp tmptop12 = newTemp( Ity_I64 );
9717 IRTemp low_50 = newTemp( Ity_I64 );
9718 IRTemp mid_50 = newTemp( Ity_I64 );
9719 IRTemp top_10 = newTemp( Ity_I64 );
9720 IRTemp top_12_u = newTemp( Ity_I32 ); // only needed for a dummy arg
9721
9722 /* Convert the 110-bit densely packed BCD string to a 128-bit BCD string */
9723
9724 /* low_50[49:0] = ((frBI64_lo[49:32] << 14) | frBI64_lo[31:0]) */
9725 assign( low_50,
9726 binop( Iop_32HLto64,
9727 binop( Iop_And32,
9728 unop( Iop_64HIto32, frBI64_lo ),
9729 mkU32( 0x3FFFF ) ),
9730 unop( Iop_64to32, frBI64_lo ) ) );
9731
9732 /* Convert the 50 bit densely packed BCD string to a 60 bit
9733 * BCD string.
9734 */
9735 assign( tmplow60, unop( Iop_DPBtoBCD, mkexpr( low_50 ) ) );
9736 assign( *low_60_u, unop( Iop_64HIto32, mkexpr( tmplow60 ) ) );
9737 assign( *low_60_l, unop( Iop_64to32, mkexpr( tmplow60 ) ) );
9738
9739 /* mid_50[49:0] = ((frBI64_hi[35:32] << 14) | frBI64_hi[31:18]) |
9740 * ((frBI64_hi[17:0] << 14) | frBI64_lo[63:50])
9741 */
9742 assign( mid_50,
9743 binop( Iop_32HLto64,
9744 binop( Iop_Or32,
9745 binop( Iop_Shl32,
9746 binop( Iop_And32,
9747 unop( Iop_64HIto32, frBI64_hi ),
9748 mkU32( 0xF ) ),
9749 mkU8( 14 ) ),
9750 binop( Iop_Shr32,
9751 unop( Iop_64to32, frBI64_hi ),
9752 mkU8( 18 ) ) ),
9753 binop( Iop_Or32,
9754 binop( Iop_Shl32,
9755 unop( Iop_64to32, frBI64_hi ),
9756 mkU8( 14 ) ),
9757 binop( Iop_Shr32,
9758 unop( Iop_64HIto32, frBI64_lo ),
9759 mkU8( 18 ) ) ) ) );
9760
9761 /* Convert the 50 bit densely packed BCD string to a 60 bit
9762 * BCD string.
9763 */
9764 assign( tmpmid60, unop( Iop_DPBtoBCD, mkexpr( mid_50 ) ) );
9765 assign( *mid_60_u, unop( Iop_64HIto32, mkexpr( tmpmid60 ) ) );
9766 assign( *mid_60_l, unop( Iop_64to32, mkexpr( tmpmid60 ) ) );
9767
9768 /* top_10[49:0] = frBI64_hi[45:36]) | */
9769 assign( top_10,
9770 binop( Iop_32HLto64,
9771 mkU32( 0 ),
9772 binop( Iop_And32,
9773 binop( Iop_Shr32,
9774 unop( Iop_64HIto32, frBI64_hi ),
9775 mkU8( 4 ) ),
9776 mkU32( 0x3FF ) ) ) );
9777
9778 /* Convert the 10 bit densely packed BCD string to a 12 bit
9779 * BCD string.
9780 */
9781 assign( tmptop12, unop( Iop_DPBtoBCD, mkexpr( top_10 ) ) );
9782 assign( top_12_u, unop( Iop_64HIto32, mkexpr( tmptop12 ) ) );
9783 assign( *top_12_l, unop( Iop_64to32, mkexpr( tmptop12 ) ) );
9784}
9785
9786static void Count_zeros( int start, IRExpr * init_cnt, IRExpr * init_flag,
9787 IRTemp * final_cnt, IRTemp * final_flag,
9788 IRExpr * string )
9789{
9790 IRTemp cnt[MAX_DIGITS_IN_STRING + 1];IRTemp flag[MAX_DIGITS_IN_STRING+1];
9791 int digits = MAX_DIGITS_IN_STRING;
9792 int i;
9793
9794 cnt[start-1] = newTemp( Ity_I8 );
9795 flag[start-1] = newTemp( Ity_I8 );
9796 assign( cnt[start-1], init_cnt);
9797 assign( flag[start-1], init_flag);
9798
9799 for ( i = start; i <= digits; i++) {
9800 cnt[i] = newTemp( Ity_I8 );
9801 flag[i] = newTemp( Ity_I8 );
9802 assign( cnt[i],
9803 binop( Iop_Add8,
9804 mkexpr( cnt[i-1] ),
9805 binop(Iop_And8,
9806 unop( Iop_1Uto8,
9807 binop(Iop_CmpEQ32,
9808 binop(Iop_And32,
9809 string,
9810 mkU32( 0xF <<
9811 ( ( digits - i ) * 4) ) ),
9812 mkU32( 0 ) ) ),
9813 binop( Iop_Xor8, /* complement flag */
9814 mkexpr( flag[i - 1] ),
9815 mkU8( 0xFF ) ) ) ) );
9816
9817 /* set flag to 1 if digit was not a zero */
9818 assign( flag[i],
9819 binop(Iop_Or8,
9820 unop( Iop_1Sto8,
9821 binop(Iop_CmpNE32,
9822 binop(Iop_And32,
9823 string,
9824 mkU32( 0xF <<
9825 ( (digits - i) * 4) ) ),
9826 mkU32( 0 ) ) ),
9827 mkexpr( flag[i - 1] ) ) );
9828 }
9829
9830 *final_cnt = cnt[digits];
9831 *final_flag = flag[digits];
9832}
9833
9834static IRExpr * Count_leading_zeros_60( IRExpr * lmd, IRExpr * upper_28,
9835 IRExpr * low_32 )
9836{
9837 IRTemp num_lmd = newTemp( Ity_I8 );
9838 IRTemp num_upper = newTemp( Ity_I8 );
9839 IRTemp num_low = newTemp( Ity_I8 );
9840 IRTemp lmd_flag = newTemp( Ity_I8 );
9841 IRTemp upper_flag = newTemp( Ity_I8 );
9842 IRTemp low_flag = newTemp( Ity_I8 );
9843
9844 assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
9845 assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
9846
9847 Count_zeros( 2,
9848 mkexpr( num_lmd ),
9849 mkexpr( lmd_flag ),
9850 &num_upper,
9851 &upper_flag,
9852 upper_28 );
9853
9854 Count_zeros( 1,
9855 mkexpr( num_upper ),
9856 mkexpr( upper_flag ),
9857 &num_low,
9858 &low_flag,
9859 low_32 );
9860
9861 return mkexpr( num_low );
9862}
9863
9864static IRExpr * Count_leading_zeros_128( IRExpr * lmd, IRExpr * top_12_l,
9865 IRExpr * mid_60_u, IRExpr * mid_60_l,
9866 IRExpr * low_60_u, IRExpr * low_60_l)
9867{
9868 IRTemp num_lmd = newTemp( Ity_I8 );
9869 IRTemp num_top = newTemp( Ity_I8 );
9870 IRTemp num_mid_u = newTemp( Ity_I8 );
9871 IRTemp num_mid_l = newTemp( Ity_I8 );
9872 IRTemp num_low_u = newTemp( Ity_I8 );
9873 IRTemp num_low_l = newTemp( Ity_I8 );
9874
9875 IRTemp lmd_flag = newTemp( Ity_I8 );
9876 IRTemp top_flag = newTemp( Ity_I8 );
9877 IRTemp mid_u_flag = newTemp( Ity_I8 );
9878 IRTemp mid_l_flag = newTemp( Ity_I8 );
9879 IRTemp low_u_flag = newTemp( Ity_I8 );
9880 IRTemp low_l_flag = newTemp( Ity_I8 );
9881
9882 /* Check the LMD, digit 16, to see if it is zero. */
9883 assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
9884
9885 assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
9886
9887 Count_zeros( 6,
9888 mkexpr( num_lmd ),
9889 mkexpr( lmd_flag ),
9890 &num_top,
9891 &top_flag,
9892 top_12_l );
9893
9894 Count_zeros( 1,
9895 mkexpr( num_top ),
9896 mkexpr( top_flag ),
9897 &num_mid_u,
9898 &mid_u_flag,
9899 binop( Iop_Or32,
9900 binop( Iop_Shl32, mid_60_u, mkU8( 2 ) ),
9901 binop( Iop_Shr32, mid_60_l, mkU8( 30 ) ) ) );
9902
9903 Count_zeros( 2,
9904 mkexpr( num_mid_u ),
9905 mkexpr( mid_u_flag ),
9906 &num_mid_l,
9907 &mid_l_flag,
9908 mid_60_l );
9909
9910 Count_zeros( 1,
9911 mkexpr( num_mid_l ),
9912 mkexpr( mid_l_flag ),
9913 &num_low_u,
9914 &low_u_flag,
9915 binop( Iop_Or32,
9916 binop( Iop_Shl32, low_60_u, mkU8( 2 ) ),
9917 binop( Iop_Shr32, low_60_l, mkU8( 30 ) ) ) );
9918
9919 Count_zeros( 2,
9920 mkexpr( num_low_u ),
9921 mkexpr( low_u_flag ),
9922 &num_low_l,
9923 &low_l_flag,
9924 low_60_l );
9925
9926 return mkexpr( num_low_l );
9927}
9928
9929static IRExpr * Check_unordered(IRExpr * val)
9930{
9931 IRTemp gfield0to5 = newTemp( Ity_I32 );
9932
9933 /* Extract G[0:4] */
9934 assign( gfield0to5,
9935 binop( Iop_And32,
9936 binop( Iop_Shr32, unop( Iop_64HIto32, val ), mkU8( 26 ) ),
9937 mkU32( 0x1F ) ) );
9938
9939 /* Check for unordered, return all 1'x if true */
9940 return binop( Iop_Or32, /* QNaN check */
9941 unop( Iop_1Sto32,
9942 binop( Iop_CmpEQ32,
9943 mkexpr( gfield0to5 ),
9944 mkU32( 0x1E ) ) ),
9945 unop( Iop_1Sto32, /* SNaN check */
9946 binop( Iop_CmpEQ32,
9947 mkexpr( gfield0to5 ),
9948 mkU32( 0x1F ) ) ) );
9949}
9950
sewardj5eff1c52012-04-29 20:19:17 +00009951#undef AND
sewardj5eff1c52012-04-29 20:19:17 +00009952#undef AND4
sewardj4c96e612012-06-02 23:47:02 +00009953#undef OR
sewardj5eff1c52012-04-29 20:19:17 +00009954#undef OR3
9955#undef OR4
sewardj4c96e612012-06-02 23:47:02 +00009956#undef NOT
9957#undef SHR
sewardj5eff1c52012-04-29 20:19:17 +00009958#undef SHL
sewardjcb06d5e2012-04-30 08:10:11 +00009959#undef BITS5
sewardj5eff1c52012-04-29 20:19:17 +00009960
9961/*------------------------------------------------------------*/
sewardjc6bbd472012-04-02 10:20:48 +00009962/*--- Decimal Floating Point (DFP) instruction translation ---*/
9963/*------------------------------------------------------------*/
sewardj5eff1c52012-04-29 20:19:17 +00009964
sewardjc6bbd472012-04-02 10:20:48 +00009965/* DFP Arithmetic instructions */
9966static Bool dis_dfp_arith(UInt theInstr)
9967{
9968 UInt opc2 = ifieldOPClo10( theInstr );
9969 UChar frS_addr = ifieldRegDS( theInstr );
9970 UChar frA_addr = ifieldRegA( theInstr );
9971 UChar frB_addr = ifieldRegB( theInstr );
9972 UChar flag_rC = ifieldBIT0( theInstr );
sewardje14bb9f2005-07-22 09:39:02 +00009973
sewardjc6bbd472012-04-02 10:20:48 +00009974 IRTemp frA = newTemp( Ity_D64 );
9975 IRTemp frB = newTemp( Ity_D64 );
9976 IRTemp frS = newTemp( Ity_D64 );
9977 IRExpr* round = get_IR_roundingmode_DFP();
9978
9979 /* By default, if flag_RC is set, we will clear cr1 after the
9980 * operation. In reality we should set cr1 to indicate the
9981 * exception status of the operation, but since we're not
9982 * simulating exceptions, the exception status will appear to be
9983 * zero. Hence cr1 should be cleared if this is a . form insn.
9984 */
9985 Bool clear_CR1 = True;
9986
9987 assign( frA, getDReg( frA_addr ) );
9988 assign( frB, getDReg( frB_addr ) );
9989
9990 switch (opc2) {
9991 case 0x2: // dadd
9992 DIP( "dadd%s fr%u,fr%u,fr%u\n",
9993 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
9994 assign( frS, triop( Iop_AddD64, round, mkexpr( frA ), mkexpr( frB ) ) );
9995 break;
9996 case 0x202: // dsub
9997 DIP( "dsub%s fr%u,fr%u,fr%u\n",
9998 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
9999 assign( frS, triop( Iop_SubD64, round, mkexpr( frA ), mkexpr( frB ) ) );
10000 break;
10001 case 0x22: // dmul
10002 DIP( "dmul%s fr%u,fr%u,fr%u\n",
10003 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10004 assign( frS, triop( Iop_MulD64, round, mkexpr( frA ), mkexpr( frB ) ) );
10005 break;
10006 case 0x222: // ddiv
10007 DIP( "ddiv%s fr%u,fr%u,fr%u\n",
10008 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10009 assign( frS, triop( Iop_DivD64, round, mkexpr( frA ), mkexpr( frB ) ) );
10010 break;
10011 }
10012
10013 putDReg( frS_addr, mkexpr( frS ) );
10014
10015 if (flag_rC && clear_CR1) {
10016 putCR321( 1, mkU8( 0 ) );
10017 putCR0( 1, mkU8( 0 ) );
10018 }
10019
10020 return True;
10021}
10022
10023/* Quad DFP Arithmetic instructions */
10024static Bool dis_dfp_arithq(UInt theInstr)
10025{
10026 UInt opc2 = ifieldOPClo10( theInstr );
10027 UChar frS_addr = ifieldRegDS( theInstr );
10028 UChar frA_addr = ifieldRegA( theInstr );
10029 UChar frB_addr = ifieldRegB( theInstr );
10030 UChar flag_rC = ifieldBIT0( theInstr );
10031
10032 IRTemp frA = newTemp( Ity_D128 );
10033 IRTemp frB = newTemp( Ity_D128 );
10034 IRTemp frS = newTemp( Ity_D128 );
10035 IRExpr* round = get_IR_roundingmode_DFP();
10036
10037 /* By default, if flag_RC is set, we will clear cr1 after the
10038 * operation. In reality we should set cr1 to indicate the
10039 * exception status of the operation, but since we're not
10040 * simulating exceptions, the exception status will appear to be
10041 * zero. Hence cr1 should be cleared if this is a . form insn.
10042 */
10043 Bool clear_CR1 = True;
10044
10045 assign( frA, getDReg_pair( frA_addr ) );
10046 assign( frB, getDReg_pair( frB_addr ) );
10047
10048 switch (opc2) {
10049 case 0x2: // daddq
10050 DIP( "daddq%s fr%u,fr%u,fr%u\n",
10051 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10052 assign( frS, triop( Iop_AddD128, round, mkexpr( frA ), mkexpr( frB ) ) );
10053 break;
10054 case 0x202: // dsubq
10055 DIP( "dsubq%s fr%u,fr%u,fr%u\n",
10056 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10057 assign( frS, triop( Iop_SubD128, round, mkexpr( frA ), mkexpr( frB ) ) );
10058 break;
10059 case 0x22: // dmulq
10060 DIP( "dmulq%s fr%u,fr%u,fr%u\n",
10061 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10062 assign( frS, triop( Iop_MulD128, round, mkexpr( frA ), mkexpr( frB ) ) );
10063 break;
10064 case 0x222: // ddivq
10065 DIP( "ddivq%s fr%u,fr%u,fr%u\n",
10066 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10067 assign( frS, triop( Iop_DivD128, round, mkexpr( frA ), mkexpr( frB ) ) );
10068 break;
10069 }
10070
10071 putDReg_pair( frS_addr, mkexpr( frS ) );
10072
10073 if (flag_rC && clear_CR1) {
10074 putCR321( 1, mkU8( 0 ) );
10075 putCR0( 1, mkU8( 0 ) );
10076 }
10077
10078 return True;
10079}
sewardje14bb9f2005-07-22 09:39:02 +000010080
sewardj26217b02012-04-12 17:19:48 +000010081/* DFP 64-bit logical shift instructions */
10082static Bool dis_dfp_shift(UInt theInstr) {
10083 UInt opc2 = ifieldOPClo9( theInstr );
10084 UChar frS_addr = ifieldRegDS( theInstr );
10085 UChar frA_addr = ifieldRegA( theInstr );
10086 UChar shift_val = IFIELD(theInstr, 10, 6);
10087 UChar flag_rC = ifieldBIT0( theInstr );
10088
10089 IRTemp frA = newTemp( Ity_D64 );
10090 IRTemp frS = newTemp( Ity_D64 );
10091 Bool clear_CR1 = True;
10092
10093 assign( frA, getDReg( frA_addr ) );
10094
10095 switch (opc2) {
10096 case 0x42: // dscli
10097 DIP( "dscli%s fr%u,fr%u,%u\n",
10098 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
10099 assign( frS, binop( Iop_ShlD64, mkexpr( frA ), mkU8( shift_val ) ) );
10100 break;
10101 case 0x62: // dscri
10102 DIP( "dscri%s fr%u,fr%u,%u\n",
10103 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
10104 assign( frS, binop( Iop_ShrD64, mkexpr( frA ), mkU8( shift_val ) ) );
10105 break;
10106 }
10107
10108 putDReg( frS_addr, mkexpr( frS ) );
10109
10110 if (flag_rC && clear_CR1) {
10111 putCR321( 1, mkU8( 0 ) );
10112 putCR0( 1, mkU8( 0 ) );
10113 }
10114
10115 return True;
10116}
10117
10118/* Quad DFP logical shift instructions */
10119static Bool dis_dfp_shiftq(UInt theInstr) {
10120 UInt opc2 = ifieldOPClo9( theInstr );
10121 UChar frS_addr = ifieldRegDS( theInstr );
10122 UChar frA_addr = ifieldRegA( theInstr );
10123 UChar shift_val = IFIELD(theInstr, 10, 6);
10124 UChar flag_rC = ifieldBIT0( theInstr );
10125
10126 IRTemp frA = newTemp( Ity_D128 );
10127 IRTemp frS = newTemp( Ity_D128 );
10128 Bool clear_CR1 = True;
10129
10130 assign( frA, getDReg_pair( frA_addr ) );
10131
10132 switch (opc2) {
10133 case 0x42: // dscliq
10134 DIP( "dscliq%s fr%u,fr%u,%u\n",
10135 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
10136 assign( frS, binop( Iop_ShlD128, mkexpr( frA ), mkU8( shift_val ) ) );
10137 break;
10138 case 0x62: // dscriq
10139 DIP( "dscriq%s fr%u,fr%u,%u\n",
10140 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
10141 assign( frS, binop( Iop_ShrD128, mkexpr( frA ), mkU8( shift_val ) ) );
10142 break;
10143 }
10144
10145 putDReg_pair( frS_addr, mkexpr( frS ) );
10146
10147 if (flag_rC && clear_CR1) {
10148 putCR321( 1, mkU8( 0 ) );
10149 putCR0( 1, mkU8( 0 ) );
10150 }
10151
10152 return True;
10153}
10154
10155/* DFP 64-bit format conversion instructions */
10156static Bool dis_dfp_fmt_conv(UInt theInstr) {
10157 UInt opc2 = ifieldOPClo10( theInstr );
10158 UChar frS_addr = ifieldRegDS( theInstr );
10159 UChar frB_addr = ifieldRegB( theInstr );
10160 IRExpr* round = get_IR_roundingmode_DFP();
10161 UChar flag_rC = ifieldBIT0( theInstr );
10162 IRTemp frB;
10163 IRTemp frS;
10164 Bool clear_CR1 = True;
10165
10166 switch (opc2) {
10167 case 0x102: //dctdp
10168 DIP( "dctdp%s fr%u,fr%u\n",
10169 flag_rC ? ".":"", frS_addr, frB_addr );
10170
carllf704eb22013-01-21 18:12:31 +000010171 frB = newTemp( Ity_D32 );
sewardj26217b02012-04-12 17:19:48 +000010172 frS = newTemp( Ity_D64 );
carllf704eb22013-01-21 18:12:31 +000010173 assign( frB, getDReg32( frB_addr ) );
sewardj26217b02012-04-12 17:19:48 +000010174 assign( frS, unop( Iop_D32toD64, mkexpr( frB ) ) );
10175 putDReg( frS_addr, mkexpr( frS ) );
10176 break;
10177 case 0x302: // drsp
10178 DIP( "drsp%s fr%u,fr%u\n",
10179 flag_rC ? ".":"", frS_addr, frB_addr );
10180 frB = newTemp( Ity_D64 );
carllf704eb22013-01-21 18:12:31 +000010181 frS = newTemp( Ity_D32 );
sewardj26217b02012-04-12 17:19:48 +000010182 assign( frB, getDReg( frB_addr ) );
10183 assign( frS, binop( Iop_D64toD32, round, mkexpr( frB ) ) );
carllf704eb22013-01-21 18:12:31 +000010184 putDReg32( frS_addr, mkexpr( frS ) );
sewardj26217b02012-04-12 17:19:48 +000010185 break;
10186 case 0x122: // dctfix
carllcea07cc2013-01-22 20:25:31 +000010187 {
10188 IRTemp tmp = newTemp( Ity_I64 );
10189
10190 DIP( "dctfix%s fr%u,fr%u\n",
10191 flag_rC ? ".":"", frS_addr, frB_addr );
10192 frB = newTemp( Ity_D64 );
10193 frS = newTemp( Ity_D64 );
10194 assign( frB, getDReg( frB_addr ) );
10195 assign( tmp, binop( Iop_D64toI64S, round, mkexpr( frB ) ) );
10196 assign( frS, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
10197 putDReg( frS_addr, mkexpr( frS ) );
10198 }
sewardj26217b02012-04-12 17:19:48 +000010199 break;
10200 case 0x322: // dcffix
10201 DIP( "dcffix%s fr%u,fr%u\n",
10202 flag_rC ? ".":"", frS_addr, frB_addr );
10203 frB = newTemp( Ity_D64 );
10204 frS = newTemp( Ity_D64 );
10205 assign( frB, getDReg( frB_addr ) );
carllcea07cc2013-01-22 20:25:31 +000010206 assign( frS, binop( Iop_I64StoD64,
10207 round,
10208 unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) ) );
sewardj26217b02012-04-12 17:19:48 +000010209 putDReg( frS_addr, mkexpr( frS ) );
10210 break;
10211 }
10212
10213 if (flag_rC && clear_CR1) {
10214 putCR321( 1, mkU8( 0 ) );
10215 putCR0( 1, mkU8( 0 ) );
10216 }
10217
10218 return True;
10219}
10220
10221/* Quad DFP format conversion instructions */
10222static Bool dis_dfp_fmt_convq(UInt theInstr) {
10223 UInt opc2 = ifieldOPClo10( theInstr );
10224 UChar frS_addr = ifieldRegDS( theInstr );
10225 UChar frB_addr = ifieldRegB( theInstr );
10226 IRExpr* round = get_IR_roundingmode_DFP();
10227 IRTemp frB64 = newTemp( Ity_D64 );
10228 IRTemp frB128 = newTemp( Ity_D128 );
10229 IRTemp frS64 = newTemp( Ity_D64 );
10230 IRTemp frS128 = newTemp( Ity_D128 );
10231 UChar flag_rC = ifieldBIT0( theInstr );
10232 Bool clear_CR1 = True;
10233
10234 switch (opc2) {
10235 case 0x102: // dctqpq
10236 DIP( "dctqpq%s fr%u,fr%u\n",
10237 flag_rC ? ".":"", frS_addr, frB_addr );
10238 assign( frB64, getDReg( frB_addr ) );
10239 assign( frS128, unop( Iop_D64toD128, mkexpr( frB64 ) ) );
10240 putDReg_pair( frS_addr, mkexpr( frS128 ) );
10241 break;
10242 case 0x122: // dctfixq
carllcea07cc2013-01-22 20:25:31 +000010243 {
10244 IRTemp tmp = newTemp( Ity_I64 );
10245
10246 DIP( "dctfixq%s fr%u,fr%u\n",
10247 flag_rC ? ".":"", frS_addr, frB_addr );
10248 assign( frB128, getDReg_pair( frB_addr ) );
10249 assign( tmp, binop( Iop_D128toI64S, round, mkexpr( frB128 ) ) );
10250 assign( frS64, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
10251 putDReg( frS_addr, mkexpr( frS64 ) );
10252 }
sewardj26217b02012-04-12 17:19:48 +000010253 break;
10254 case 0x302: //drdpq
10255 DIP( "drdpq%s fr%u,fr%u\n",
10256 flag_rC ? ".":"", frS_addr, frB_addr );
10257 assign( frB128, getDReg_pair( frB_addr ) );
10258 assign( frS64, binop( Iop_D128toD64, round, mkexpr( frB128 ) ) );
10259 putDReg( frS_addr, mkexpr( frS64 ) );
10260 break;
10261 case 0x322: // dcffixq
carllcea07cc2013-01-22 20:25:31 +000010262 {
sewardj26217b02012-04-12 17:19:48 +000010263 /* Have to introduce an IOP for this instruction so it will work
10264 * on POWER 6 because emulating the instruction requires a POWER 7
10265 * DFP instruction in the emulation code.
10266 */
10267 DIP( "dcffixq%s fr%u,fr%u\n",
10268 flag_rC ? ".":"", frS_addr, frB_addr );
10269 assign( frB64, getDReg( frB_addr ) );
carllcea07cc2013-01-22 20:25:31 +000010270 assign( frS128, unop( Iop_I64StoD128,
10271 unop( Iop_ReinterpD64asI64,
10272 mkexpr( frB64 ) ) ) );
sewardj26217b02012-04-12 17:19:48 +000010273 putDReg_pair( frS_addr, mkexpr( frS128 ) );
10274 break;
carllcea07cc2013-01-22 20:25:31 +000010275 }
sewardj26217b02012-04-12 17:19:48 +000010276 }
10277
10278 if (flag_rC && clear_CR1) {
10279 putCR321( 1, mkU8( 0 ) );
10280 putCR0( 1, mkU8( 0 ) );
10281 }
10282
10283 return True;
10284}
10285
sewardjcdc376d2012-04-23 11:21:12 +000010286static Bool dis_dfp_round( UInt theInstr ) {
10287 UChar frS_addr = ifieldRegDS(theInstr);
10288 UChar R = IFIELD(theInstr, 16, 1);
10289 UChar RMC = IFIELD(theInstr, 9, 2);
10290 UChar frB_addr = ifieldRegB( theInstr );
10291 UChar flag_rC = ifieldBIT0( theInstr );
10292 IRTemp frB = newTemp( Ity_D64 );
10293 IRTemp frS = newTemp( Ity_D64 );
10294 UInt opc2 = ifieldOPClo8( theInstr );
10295 Bool clear_CR1 = True;
10296
10297 switch (opc2) {
10298 /* drintn, is the same as drintx. The only difference is this
10299 * instruction does not generate an exception for an inexact operation.
10300 * Currently not supporting inexact exceptions.
10301 */
10302 case 0x63: // drintx
10303 case 0xE3: // drintn
10304 DIP( "drintx/drintn%s fr%u,fr%u\n",
10305 flag_rC ? ".":"", frS_addr, frB_addr );
10306
carllcea07cc2013-01-22 20:25:31 +000010307 /* NOTE, this instruction takes a DFP value and rounds to the
10308 * neares floating point integer value, i.e. fractional part
10309 * is zero. The result is a floating point number.
10310 */
sewardjcdc376d2012-04-23 11:21:12 +000010311 /* pass the value of R and RMC in the same field */
10312 assign( frB, getDReg( frB_addr ) );
10313 assign( frS, binop( Iop_RoundD64toInt,
10314 mkU32( ( R << 3 ) | RMC ),
10315 mkexpr( frB ) ) );
10316 putDReg( frS_addr, mkexpr( frS ) );
10317 break;
10318 default:
10319 vex_printf("dis_dfp_round(ppc)(opc2)\n");
10320 return False;
10321 }
10322
10323 if (flag_rC && clear_CR1) {
10324 putCR321( 1, mkU8( 0 ) );
10325 putCR0( 1, mkU8( 0 ) );
10326 }
10327
10328 return True;
10329}
10330
10331static Bool dis_dfp_roundq(UInt theInstr) {
10332 UChar frS_addr = ifieldRegDS( theInstr );
10333 UChar frB_addr = ifieldRegB( theInstr );
10334 UChar R = IFIELD(theInstr, 16, 1);
10335 UChar RMC = IFIELD(theInstr, 9, 2);
10336 UChar flag_rC = ifieldBIT0( theInstr );
10337 IRTemp frB = newTemp( Ity_D128 );
10338 IRTemp frS = newTemp( Ity_D128 );
10339 Bool clear_CR1 = True;
10340 UInt opc2 = ifieldOPClo8( theInstr );
10341
10342 switch (opc2) {
10343 /* drintnq, is the same as drintxq. The only difference is this
10344 * instruction does not generate an exception for an inexact operation.
10345 * Currently not supporting inexact exceptions.
10346 */
10347 case 0x63: // drintxq
10348 case 0xE3: // drintnq
10349 DIP( "drintxq/drintnq%s fr%u,fr%u\n",
10350 flag_rC ? ".":"", frS_addr, frB_addr );
10351
10352 /* pass the value of R and RMC in the same field */
10353 assign( frB, getDReg_pair( frB_addr ) );
10354 assign( frS, binop( Iop_RoundD128toInt,
10355 mkU32( ( R << 3 ) | RMC ),
10356 mkexpr( frB ) ) );
10357 putDReg_pair( frS_addr, mkexpr( frS ) );
10358 break;
10359 default:
10360 vex_printf("dis_dfp_roundq(ppc)(opc2)\n");
10361 return False;
10362 }
10363
10364 if (flag_rC && clear_CR1) {
10365 putCR321( 1, mkU8( 0 ) );
10366 putCR0( 1, mkU8( 0 ) );
10367 }
10368
10369 return True;
10370}
10371
10372static Bool dis_dfp_quantize_sig_rrnd(UInt theInstr) {
10373 UInt opc2 = ifieldOPClo8( theInstr );
10374 UChar frS_addr = ifieldRegDS( theInstr );
10375 UChar frA_addr = ifieldRegA( theInstr );
10376 UChar frB_addr = ifieldRegB( theInstr );
10377 UChar flag_rC = ifieldBIT0( theInstr );
10378 UInt TE_value = IFIELD(theInstr, 16, 4);
10379 UInt TE_sign = IFIELD(theInstr, 20, 1);
10380 UInt RMC = IFIELD(theInstr, 9, 2);
10381 IRTemp frA = newTemp( Ity_D64 );
10382 IRTemp frB = newTemp( Ity_D64 );
10383 IRTemp frS = newTemp( Ity_D64 );
10384 Bool clear_CR1 = True;
10385
10386 assign( frB, getDReg( frB_addr ) );
10387
10388 switch (opc2) {
10389 case 0x43: // dquai
10390 DIP( "dquai%s fr%u,fr%u,fr%u\n",
10391 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
carllcea07cc2013-01-22 20:25:31 +000010392 IRTemp TE_I64 = newTemp( Ity_I64 );
sewardjcdc376d2012-04-23 11:21:12 +000010393
10394 /* Generate a reference DFP value frA with the desired exponent
10395 * given by TE using significand from frB. Need to add the bias
10396 * 398 to TE. TE is stored as a 2's complement number.
10397 */
10398 if (TE_sign == 1) {
10399 /* Take 2's complement of the 5-bit value and subtract from bias.
10400 * Bias is adjusted for the +1 required when taking 2's complement.
10401 */
carllcea07cc2013-01-22 20:25:31 +000010402 assign( TE_I64,
10403 unop( Iop_32Uto64,
10404 binop( Iop_Sub32, mkU32( 397 ),
10405 binop( Iop_And32, mkU32( 0xF ),
10406 unop( Iop_Not32, mkU32( TE_value ) )
10407 ) ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010408
10409 } else {
carllcea07cc2013-01-22 20:25:31 +000010410 assign( TE_I64,
10411 unop( Iop_32Uto64,
10412 binop( Iop_Add32, mkU32( 398 ), mkU32( TE_value ) )
10413 ) );
sewardjcdc376d2012-04-23 11:21:12 +000010414 }
10415
carllcea07cc2013-01-22 20:25:31 +000010416 assign( frA, binop( Iop_InsertExpD64, mkexpr( TE_I64 ),
sewardjcdc376d2012-04-23 11:21:12 +000010417 unop( Iop_ReinterpI64asD64, mkU64( 1 ) ) ) );
10418
10419 assign( frS, triop( Iop_QuantizeD64,
10420 mkU32( RMC ),
10421 mkexpr( frA ),
10422 mkexpr( frB ) ) );
10423 break;
10424
10425 case 0x3: // dqua
10426 DIP( "dqua%s fr%u,fr%u,fr%u\n",
10427 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10428 assign( frA, getDReg( frA_addr ) );
10429 assign( frS, triop( Iop_QuantizeD64,
10430 mkU32( RMC ),
10431 mkexpr( frA ),
10432 mkexpr( frB ) ) );
10433 break;
10434 case 0x23: // drrnd
carllcea07cc2013-01-22 20:25:31 +000010435 {
10436 IRTemp tmp = newTemp( Ity_I8 );
10437
10438 DIP( "drrnd%s fr%u,fr%u,fr%u\n",
10439 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10440 assign( frA, getDReg( frA_addr ) );
10441 /* Iop_64to8 not supported in 32 bit mode, do it in two steps. */
10442 assign( tmp, unop( Iop_32to8,
10443 unop( Iop_64to32,
10444 unop( Iop_ReinterpD64asI64,
10445 mkexpr( frA ) ) ) ) );
10446 assign( frS, triop( Iop_SignificanceRoundD64,
10447 mkU32( RMC ),
10448 mkexpr( tmp ),
10449 mkexpr( frB ) ) );
10450 }
sewardjcdc376d2012-04-23 11:21:12 +000010451 break;
10452 default:
10453 vex_printf("dis_dfp_quantize_sig_rrnd(ppc)(opc2)\n");
10454 return False;
10455 }
10456 putDReg( frS_addr, mkexpr( frS ) );
10457
10458 if (flag_rC && clear_CR1) {
10459 putCR321( 1, mkU8( 0 ) );
10460 putCR0( 1, mkU8( 0 ) );
10461 }
10462
10463 return True;
10464}
10465
10466static Bool dis_dfp_quantize_sig_rrndq(UInt theInstr) {
10467 UInt opc2 = ifieldOPClo8( theInstr );
10468 UChar frS_addr = ifieldRegDS( theInstr );
10469 UChar frA_addr = ifieldRegA( theInstr );
10470 UChar frB_addr = ifieldRegB( theInstr );
10471 UChar flag_rC = ifieldBIT0( theInstr );
10472 UInt TE_value = IFIELD(theInstr, 16, 4);
10473 UInt TE_sign = IFIELD(theInstr, 20, 1);
10474 UInt RMC = IFIELD(theInstr, 9, 2);
10475 IRTemp frA = newTemp( Ity_D128 );
10476 IRTemp frB = newTemp( Ity_D128 );
10477 IRTemp frS = newTemp( Ity_D128 );
10478 Bool clear_CR1 = True;
10479
10480 assign( frB, getDReg_pair( frB_addr ) );
10481
10482 switch (opc2) {
10483 case 0x43: // dquaiq
10484 DIP( "dquaiq%s fr%u,fr%u,fr%u\n",
10485 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
carllcea07cc2013-01-22 20:25:31 +000010486 IRTemp TE_I64 = newTemp( Ity_I64 );
sewardjcdc376d2012-04-23 11:21:12 +000010487
10488 /* Generate a reference DFP value frA with the desired exponent
10489 * given by TE using significand of 1. Need to add the bias
10490 * 6176 to TE.
10491 */
10492 if (TE_sign == 1) {
10493 /* Take 2's complement of the 5-bit value and subtract from bias.
10494 * Bias adjusted for the +1 required when taking 2's complement.
10495 */
carllcea07cc2013-01-22 20:25:31 +000010496 assign( TE_I64,
10497 unop( Iop_32Uto64,
10498 binop( Iop_Sub32, mkU32( 6175 ),
10499 binop( Iop_And32, mkU32( 0xF ),
10500 unop( Iop_Not32, mkU32( TE_value ) )
10501 ) ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010502
10503 } else {
carllcea07cc2013-01-22 20:25:31 +000010504 assign( TE_I64,
10505 unop( Iop_32Uto64,
10506 binop( Iop_Add32,
10507 mkU32( 6176 ),
10508 mkU32( TE_value ) ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010509 }
10510
10511 assign( frA,
carllcea07cc2013-01-22 20:25:31 +000010512 binop( Iop_InsertExpD128, mkexpr( TE_I64 ),
10513 unop( Iop_D64toD128,
sewardjcdc376d2012-04-23 11:21:12 +000010514 unop( Iop_ReinterpI64asD64, mkU64( 1 ) ) ) ) );
10515 assign( frS, triop( Iop_QuantizeD128,
10516 mkU32( RMC ),
10517 mkexpr( frA ),
10518 mkexpr( frB ) ) );
10519 break;
10520 case 0x3: // dquaq
10521 DIP( "dquaiq%s fr%u,fr%u,fr%u\n",
10522 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10523 assign( frA, getDReg_pair( frA_addr ) );
10524 assign( frS, triop( Iop_QuantizeD128,
10525 mkU32( RMC ),
10526 mkexpr( frA ),
10527 mkexpr( frB ) ) );
10528 break;
10529 case 0x23: // drrndq
carllcea07cc2013-01-22 20:25:31 +000010530 {
10531 IRTemp tmp = newTemp( Ity_I8 );
10532
10533 DIP( "drrndq%s fr%u,fr%u,fr%u\n",
10534 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10535 assign( frA, getDReg_pair( frA_addr ) );
10536 assign( tmp, unop( Iop_32to8,
10537 unop( Iop_64to32,
10538 unop( Iop_ReinterpD64asI64,
10539 unop( Iop_D128HItoD64,
10540 mkexpr( frA ) ) ) ) ) );
10541 assign( frS, triop( Iop_SignificanceRoundD128,
10542 mkU32( RMC ),
10543 mkexpr( tmp ),
10544 mkexpr( frB ) ) );
10545 }
sewardjcdc376d2012-04-23 11:21:12 +000010546 break;
10547 default:
10548 vex_printf("dis_dfp_quantize_sig_rrndq(ppc)(opc2)\n");
10549 return False;
10550 }
10551 putDReg_pair( frS_addr, mkexpr( frS ) );
10552
10553 if (flag_rC && clear_CR1) {
10554 putCR321( 1, mkU8( 0 ) );
10555 putCR0( 1, mkU8( 0 ) );
10556 }
10557
10558 return True;
10559}
10560
10561static Bool dis_dfp_extract_insert(UInt theInstr) {
10562 UInt opc2 = ifieldOPClo10( theInstr );
10563 UChar frS_addr = ifieldRegDS( theInstr );
10564 UChar frA_addr = ifieldRegA( theInstr );
10565 UChar frB_addr = ifieldRegB( theInstr );
10566 UChar flag_rC = ifieldBIT0( theInstr );
10567 Bool clear_CR1 = True;
10568
10569 IRTemp frA = newTemp( Ity_D64 );
10570 IRTemp frB = newTemp( Ity_D64 );
10571 IRTemp frS = newTemp( Ity_D64 );
carllcea07cc2013-01-22 20:25:31 +000010572 IRTemp tmp = newTemp( Ity_I64 );
sewardjcdc376d2012-04-23 11:21:12 +000010573
10574 assign( frA, getDReg( frA_addr ) );
10575 assign( frB, getDReg( frB_addr ) );
10576
10577 switch (opc2) {
10578 case 0x162: // dxex
10579 DIP( "dxex%s fr%u,fr%u,fr%u\n",
10580 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
carllcea07cc2013-01-22 20:25:31 +000010581 assign( tmp, unop( Iop_ExtractExpD64, mkexpr( frB ) ) );
10582 assign( frS, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010583 break;
10584 case 0x362: // diex
10585 DIP( "diex%s fr%u,fr%u,fr%u\n",
10586 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
carllcea07cc2013-01-22 20:25:31 +000010587 assign( frS, binop( Iop_InsertExpD64,
10588 unop( Iop_ReinterpD64asI64,
10589 mkexpr( frA ) ),
10590 mkexpr( frB ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010591 break;
10592 default:
10593 vex_printf("dis_dfp_extract_insert(ppc)(opc2)\n");
10594 return False;
10595 }
10596
10597 putDReg( frS_addr, mkexpr( frS ) );
10598
10599 if (flag_rC && clear_CR1) {
10600 putCR321( 1, mkU8( 0 ) );
10601 putCR0( 1, mkU8( 0 ) );
10602 }
10603
10604 return True;
10605}
10606
10607static Bool dis_dfp_extract_insertq(UInt theInstr) {
10608 UInt opc2 = ifieldOPClo10( theInstr );
10609 UChar frS_addr = ifieldRegDS( theInstr );
10610 UChar frA_addr = ifieldRegA( theInstr );
10611 UChar frB_addr = ifieldRegB( theInstr );
10612 UChar flag_rC = ifieldBIT0( theInstr );
10613
10614 IRTemp frA = newTemp( Ity_D64 );
10615 IRTemp frB = newTemp( Ity_D128 );
10616 IRTemp frS64 = newTemp( Ity_D64 );
10617 IRTemp frS = newTemp( Ity_D128 );
carllcea07cc2013-01-22 20:25:31 +000010618 IRTemp tmp = newTemp( Ity_I64 );
sewardjcdc376d2012-04-23 11:21:12 +000010619 Bool clear_CR1 = True;
10620
10621 assign( frB, getDReg_pair( frB_addr ) );
10622
10623 switch (opc2) {
10624 case 0x162: // dxexq
10625 DIP( "dxexq%s fr%u,fr%u\n",
10626 flag_rC ? ".":"", frS_addr, frB_addr );
10627 /* Instruction actually returns a 64-bit result. So as to be
10628 * consistent and not have to add a new struct, the emulation returns
10629 * the 64-bit result in the upper and lower register.
10630 */
carllcea07cc2013-01-22 20:25:31 +000010631 assign( tmp, unop( Iop_ExtractExpD128, mkexpr( frB ) ) );
10632 assign( frS64, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010633 putDReg( frS_addr, mkexpr( frS64 ) );
10634 break;
10635 case 0x362: // diexq
10636 DIP( "diexq%s fr%u,fr%u,fr%u\n",
10637 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10638 assign( frA, getDReg( frA_addr ) );
carllcea07cc2013-01-22 20:25:31 +000010639 assign( frS, binop( Iop_InsertExpD128,
10640 unop( Iop_ReinterpD64asI64, mkexpr( frA ) ),
10641 mkexpr( frB ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010642 putDReg_pair( frS_addr, mkexpr( frS ) );
10643 break;
10644 default:
10645 vex_printf("dis_dfp_extract_insertq(ppc)(opc2)\n");
10646 return False;
10647 }
10648
10649 if (flag_rC && clear_CR1) {
10650 putCR321( 1, mkU8( 0 ) );
10651 putCR0( 1, mkU8( 0 ) );
10652 }
10653
10654 return True;
10655}
10656
10657/* DFP 64-bit comparison instructions */
10658static Bool dis_dfp_compare(UInt theInstr) {
10659 /* X-Form */
10660 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
10661 UChar frA_addr = ifieldRegA( theInstr );
10662 UChar frB_addr = ifieldRegB( theInstr );
10663 UInt opc1 = ifieldOPC( theInstr );
10664 IRTemp frA;
10665 IRTemp frB;
10666
10667 IRTemp ccIR = newTemp( Ity_I32 );
10668 IRTemp ccPPC32 = newTemp( Ity_I32 );
10669
10670
10671 /* Note: Differences between dcmpu and dcmpo are only in exception
10672 flag settings, which aren't supported anyway. */
10673 switch (opc1) {
10674 case 0x3B: /* dcmpo and dcmpu, DFP 64-bit */
10675 DIP( "dcmpo %u,fr%u,fr%u\n", crfD, frA_addr, frB_addr );
10676 frA = newTemp( Ity_D64 );
10677 frB = newTemp( Ity_D64 );
10678
10679 assign( frA, getDReg( frA_addr ) );
10680 assign( frB, getDReg( frB_addr ) );
10681
10682 assign( ccIR, binop( Iop_CmpD64, mkexpr( frA ), mkexpr( frB ) ) );
10683 break;
10684 case 0x3F: /* dcmpoq and dcmpuq,DFP 128-bit */
10685 DIP( "dcmpoq %u,fr%u,fr%u\n", crfD, frA_addr, frB_addr );
10686 frA = newTemp( Ity_D128 );
10687 frB = newTemp( Ity_D128 );
10688
10689 assign( frA, getDReg_pair( frA_addr ) );
10690 assign( frB, getDReg_pair( frB_addr ) );
10691 assign( ccIR, binop( Iop_CmpD128, mkexpr( frA ), mkexpr( frB ) ) );
10692 break;
10693 default:
10694 vex_printf("dis_dfp_compare(ppc)(opc2)\n");
10695 return False;
10696 }
10697
10698 /* Map compare result from IR to PPC32 */
10699 /*
10700 FP cmp result | PPC | IR
10701 --------------------------
10702 UN | 0x1 | 0x45
10703 EQ | 0x2 | 0x40
10704 GT | 0x4 | 0x00
10705 LT | 0x8 | 0x01
10706 */
10707
10708 assign( ccPPC32,
10709 binop( Iop_Shl32,
10710 mkU32( 1 ),
10711 unop( Iop_32to8,
10712 binop( Iop_Or32,
10713 binop( Iop_And32,
10714 unop( Iop_Not32,
10715 binop( Iop_Shr32,
10716 mkexpr( ccIR ),
10717 mkU8( 5 ) ) ),
10718 mkU32( 2 ) ),
10719 binop( Iop_And32,
10720 binop( Iop_Xor32,
10721 mkexpr( ccIR ),
10722 binop( Iop_Shr32,
10723 mkexpr( ccIR ),
10724 mkU8( 6 ) ) ),
10725 mkU32( 1 ) ) ) ) ) );
10726
10727 putGST_field( PPC_GST_CR, mkexpr( ccPPC32 ), crfD );
10728 return True;
10729}
10730
sewardj5eff1c52012-04-29 20:19:17 +000010731/* Test class/group/exponent/significance instructions. */
10732static Bool dis_dfp_exponent_test ( UInt theInstr )
10733{
10734 UChar frA_addr = ifieldRegA( theInstr );
10735 UChar frB_addr = ifieldRegB( theInstr );
10736 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
10737 IRTemp frA = newTemp( Ity_D64 );
10738 IRTemp frB = newTemp( Ity_D64 );
10739 IRTemp frA128 = newTemp( Ity_D128 );
10740 IRTemp frB128 = newTemp( Ity_D128 );
10741 UInt opc1 = ifieldOPC( theInstr );
10742 IRTemp gfield_A = newTemp( Ity_I32 );
10743 IRTemp gfield_B = newTemp( Ity_I32 );
10744 IRTemp gfield_mask = newTemp( Ity_I32 );
10745 IRTemp exponent_A = newTemp( Ity_I32 );
10746 IRTemp exponent_B = newTemp( Ity_I32 );
10747 IRTemp A_NaN_true = newTemp( Ity_I32 );
10748 IRTemp B_NaN_true = newTemp( Ity_I32 );
10749 IRTemp A_inf_true = newTemp( Ity_I32 );
10750 IRTemp B_inf_true = newTemp( Ity_I32 );
10751 IRTemp A_equals_B = newTemp( Ity_I32 );
10752 IRTemp finite_number = newTemp( Ity_I32 );
10753 IRTemp cc0 = newTemp( Ity_I32 );
10754 IRTemp cc1 = newTemp( Ity_I32 );
10755 IRTemp cc2 = newTemp( Ity_I32 );
10756 IRTemp cc3 = newTemp( Ity_I32 );
10757
10758 /* The dtstex and dtstexg instructions only differ in the size of the
10759 * exponent field. The following switch statement takes care of the size
10760 * specific setup. Once the value of the exponents, the G-field shift
10761 * and mask is setup the remaining code is identical.
10762 */
10763 switch (opc1) {
10764 case 0x3b: // dtstex Extended instruction setup
10765 DIP("dtstex %u,r%u,r%d\n", crfD, frA_addr, frB_addr);
10766 assign( frA, getDReg( frA_addr ) );
10767 assign( frB, getDReg( frB_addr ) );
10768 assign( gfield_mask, mkU32( DFP_G_FIELD_LONG_MASK ) );
carllcea07cc2013-01-22 20:25:31 +000010769 assign(exponent_A, unop( Iop_64to32,
10770 unop( Iop_ExtractExpD64,
10771 mkexpr( frA ) ) ) );
10772 assign(exponent_B, unop( Iop_64to32,
10773 unop( Iop_ExtractExpD64,
10774 mkexpr( frB ) ) ) );
sewardj5eff1c52012-04-29 20:19:17 +000010775 break;
10776
10777 case 0x3F: // dtstexq Quad instruction setup
10778 DIP("dtstexq %u,r%u,r%d\n", crfD, frA_addr, frB_addr);
10779 assign( frA128, getDReg_pair( frA_addr ) );
10780 assign( frB128, getDReg_pair( frB_addr ) );
10781 assign( frA, unop( Iop_D128HItoD64, mkexpr( frA128 ) ) );
10782 assign( frB, unop( Iop_D128HItoD64, mkexpr( frB128 ) ) );
10783 assign( gfield_mask, mkU32( DFP_G_FIELD_EXTND_MASK ) );
carllcea07cc2013-01-22 20:25:31 +000010784 assign( exponent_A, unop( Iop_64to32,
10785 unop( Iop_ExtractExpD128,
10786 mkexpr( frA128 ) ) ) );
10787 assign( exponent_B, unop( Iop_64to32,
10788 unop( Iop_ExtractExpD128,
10789 mkexpr( frB128 ) ) ) );
sewardj5eff1c52012-04-29 20:19:17 +000010790 break;
10791 default:
10792 vex_printf("dis_dfp_exponent_test(ppc)(opc2)\n");
10793 return False;
10794 }
10795
10796 /* Extract the Gfield */
10797 assign( gfield_A, binop( Iop_And32,
10798 mkexpr( gfield_mask ),
10799 unop( Iop_64HIto32,
10800 unop( Iop_ReinterpD64asI64,
10801 mkexpr(frA) ) ) ) );
10802
10803 assign( gfield_B, binop( Iop_And32,
10804 mkexpr( gfield_mask ),
10805 unop( Iop_64HIto32,
10806 unop( Iop_ReinterpD64asI64,
10807 mkexpr(frB) ) ) ) );
10808
10809 /* check for NAN */
10810 assign( A_NaN_true, binop(Iop_Or32,
10811 unop( Iop_1Sto32,
10812 binop( Iop_CmpEQ32,
10813 mkexpr( gfield_A ),
10814 mkU32( 0x7C000000 ) ) ),
10815 unop( Iop_1Sto32,
10816 binop( Iop_CmpEQ32,
10817 mkexpr( gfield_A ),
10818 mkU32( 0x7E000000 ) )
10819 ) ) );
10820 assign( B_NaN_true, binop(Iop_Or32,
10821 unop( Iop_1Sto32,
10822 binop( Iop_CmpEQ32,
10823 mkexpr( gfield_B ),
10824 mkU32( 0x7C000000 ) ) ),
10825 unop( Iop_1Sto32,
10826 binop( Iop_CmpEQ32,
10827 mkexpr( gfield_B ),
10828 mkU32( 0x7E000000 ) )
10829 ) ) );
10830
10831 /* check for infinity */
10832 assign( A_inf_true,
10833 unop( Iop_1Sto32,
10834 binop( Iop_CmpEQ32,
10835 mkexpr( gfield_A ),
10836 mkU32( 0x78000000 ) ) ) );
10837
10838 assign( B_inf_true,
10839 unop( Iop_1Sto32,
10840 binop( Iop_CmpEQ32,
10841 mkexpr( gfield_B ),
10842 mkU32( 0x78000000 ) ) ) );
10843
10844 assign( finite_number,
10845 unop( Iop_Not32,
10846 binop( Iop_Or32,
10847 binop( Iop_Or32,
10848 mkexpr( A_NaN_true ),
10849 mkexpr( B_NaN_true ) ),
10850 binop( Iop_Or32,
10851 mkexpr( A_inf_true ),
10852 mkexpr( B_inf_true ) ) ) ) );
10853
10854 /* Calculate the condition code bits
10855 * If QNaN,SNaN, +infinity, -infinity then cc0, cc1 and cc2 are zero
10856 * regardless of the value of the comparisons and cc3 is 1. Otherwise,
10857 * cc0, cc1 and cc0 reflect the results of the comparisons.
10858 */
10859 assign( A_equals_B,
10860 binop( Iop_Or32,
10861 unop( Iop_1Uto32,
10862 binop( Iop_CmpEQ32,
10863 mkexpr( exponent_A ),
10864 mkexpr( exponent_B ) ) ),
10865 binop( Iop_Or32,
10866 binop( Iop_And32,
10867 mkexpr( A_inf_true ),
10868 mkexpr( B_inf_true ) ),
10869 binop( Iop_And32,
10870 mkexpr( A_NaN_true ),
10871 mkexpr( B_NaN_true ) ) ) ) );
10872
10873 assign( cc0, binop( Iop_And32,
10874 mkexpr( finite_number ),
10875 binop( Iop_Shl32,
10876 unop( Iop_1Uto32,
10877 binop( Iop_CmpLT32U,
10878 mkexpr( exponent_A ),
10879 mkexpr( exponent_B ) ) ),
10880 mkU8( 3 ) ) ) );
10881
10882 assign( cc1, binop( Iop_And32,
10883 mkexpr( finite_number ),
10884 binop( Iop_Shl32,
10885 unop( Iop_1Uto32,
10886 binop( Iop_CmpLT32U,
10887 mkexpr( exponent_B ),
10888 mkexpr( exponent_A ) ) ),
10889 mkU8( 2 ) ) ) );
10890
10891 assign( cc2, binop( Iop_Shl32,
10892 binop( Iop_And32,
10893 mkexpr( A_equals_B ),
10894 mkU32( 1 ) ),
10895 mkU8( 1 ) ) );
10896
10897 assign( cc3, binop( Iop_And32,
10898 unop( Iop_Not32, mkexpr( A_equals_B ) ),
10899 binop( Iop_And32,
10900 mkU32( 0x1 ),
10901 binop( Iop_Or32,
10902 binop( Iop_Or32,
10903 mkexpr ( A_inf_true ),
10904 mkexpr ( B_inf_true ) ),
10905 binop( Iop_Or32,
10906 mkexpr ( A_NaN_true ),
10907 mkexpr ( B_NaN_true ) ) )
10908 ) ) );
10909
10910 /* store the condition code */
10911 putGST_field( PPC_GST_CR,
10912 binop( Iop_Or32,
10913 mkexpr( cc0 ),
10914 binop( Iop_Or32,
10915 mkexpr( cc1 ),
10916 binop( Iop_Or32,
10917 mkexpr( cc2 ),
10918 mkexpr( cc3 ) ) ) ),
10919 crfD );
10920 return True;
10921}
10922
10923/* Test class/group/exponent/significance instructions. */
10924static Bool dis_dfp_class_test ( UInt theInstr )
10925{
10926 UChar frA_addr = ifieldRegA( theInstr );
10927 IRTemp frA = newTemp( Ity_D64 );
10928 IRTemp abs_frA = newTemp( Ity_D64 );
10929 IRTemp frAI64_hi = newTemp( Ity_I64 );
10930 IRTemp frAI64_lo = newTemp( Ity_I64 );
10931 UInt opc1 = ifieldOPC( theInstr );
10932 UInt opc2 = ifieldOPClo9( theInstr );
10933 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
10934 UInt DCM = IFIELD( theInstr, 10, 6 );
10935 IRTemp DCM_calc = newTemp( Ity_I32 );
10936 UInt max_exp = 0;
10937 UInt min_exp = 0;
10938 IRTemp min_subnormalD64 = newTemp( Ity_D64 );
10939 IRTemp min_subnormalD128 = newTemp( Ity_D128 );
10940 IRTemp significand64 = newTemp( Ity_D64 );
10941 IRTemp significand128 = newTemp( Ity_D128 );
carllcea07cc2013-01-22 20:25:31 +000010942 IRTemp exp_min_normal = newTemp( Ity_I64 );
sewardj5eff1c52012-04-29 20:19:17 +000010943 IRTemp exponent = newTemp( Ity_I32 );
10944
10945 IRTemp infinity_true = newTemp( Ity_I32 );
10946 IRTemp SNaN_true = newTemp( Ity_I32 );
10947 IRTemp QNaN_true = newTemp( Ity_I32 );
10948 IRTemp subnormal_true = newTemp( Ity_I32 );
10949 IRTemp normal_true = newTemp( Ity_I32 );
10950 IRTemp extreme_true = newTemp( Ity_I32 );
10951 IRTemp lmd = newTemp( Ity_I32 );
10952 IRTemp lmd_zero_true = newTemp( Ity_I32 );
10953 IRTemp zero_true = newTemp( Ity_I32 );
10954 IRTemp sign = newTemp( Ity_I32 );
10955 IRTemp field = newTemp( Ity_I32 );
10956 IRTemp ccIR_zero = newTemp( Ity_I32 );
10957 IRTemp ccIR_subnormal = newTemp( Ity_I32 );
10958
10959 /* UInt size = DFP_LONG; JRS:unused */
10960 IRTemp gfield = newTemp( Ity_I32 );
10961 IRTemp gfield_0_4_shift = newTemp( Ity_I8 );
10962 IRTemp gfield_mask = newTemp( Ity_I32 );
10963 IRTemp dcm0 = newTemp( Ity_I32 );
10964 IRTemp dcm1 = newTemp( Ity_I32 );
10965 IRTemp dcm2 = newTemp( Ity_I32 );
10966 IRTemp dcm3 = newTemp( Ity_I32 );
10967 IRTemp dcm4 = newTemp( Ity_I32 );
10968 IRTemp dcm5 = newTemp( Ity_I32 );
10969
10970 /* The only difference between the dtstdc and dtstdcq instructions is
10971 * size of the T and G fields. The calculation of the 4 bit field
10972 * is the same. Setup the parameters and values that are DFP size
10973 * specific. The rest of the code is independent of the DFP size.
10974 *
10975 * The Io_CmpD64 is used below. The instruction sets the ccIR values.
10976 * The interpretation of the ccIR values is as follows:
10977 *
10978 * DFP cmp result | IR
10979 * --------------------------
10980 * UN | 0x45
10981 * EQ | 0x40
10982 * GT | 0x00
10983 * LT | 0x01
10984 */
10985
10986 assign( frA, getDReg( frA_addr ) );
10987 assign( frAI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frA ) ) );
10988
10989 assign( abs_frA, unop( Iop_ReinterpI64asD64,
10990 binop( Iop_And64,
10991 unop( Iop_ReinterpD64asI64,
10992 mkexpr( frA ) ),
10993 mkU64( 0x7FFFFFFFFFFFFFFFULL ) ) ) );
10994 assign( gfield_0_4_shift, mkU8( 31 - 5 ) ); // G-field[0:4]
10995 switch (opc1) {
10996 case 0x3b: // dtstdc, dtstdg
10997 DIP("dtstd%s %u,r%u,%d\n", opc2 == 0xc2 ? "c" : "g",
10998 crfD, frA_addr, DCM);
10999 /* setup the parameters for the long format of the two instructions */
11000 assign( frAI64_lo, mkU64( 0 ) );
11001 assign( gfield_mask, mkU32( DFP_G_FIELD_LONG_MASK ) );
11002 max_exp = DFP_LONG_EXP_MAX;
11003 min_exp = DFP_LONG_EXP_MIN;
11004
carllcea07cc2013-01-22 20:25:31 +000011005 assign( exponent, unop( Iop_64to32,
11006 unop( Iop_ExtractExpD64,
11007 mkexpr( frA ) ) ) );
sewardj5eff1c52012-04-29 20:19:17 +000011008 assign( significand64,
11009 unop( Iop_ReinterpI64asD64,
11010 mkU64( 0x2234000000000001ULL ) ) ); // dfp 1.0
carllcea07cc2013-01-22 20:25:31 +000011011 assign( exp_min_normal,mkU64( 398 - 383 ) );
sewardj5eff1c52012-04-29 20:19:17 +000011012 assign( min_subnormalD64,
11013 binop( Iop_InsertExpD64,
11014 mkexpr( exp_min_normal ),
11015 mkexpr( significand64 ) ) );
11016
11017 assign( ccIR_subnormal,
11018 binop( Iop_CmpD64,
11019 mkexpr( abs_frA ),
11020 mkexpr( min_subnormalD64 ) ) );
11021
11022 /* compare absolute value of frA with zero */
11023 assign( ccIR_zero,
11024 binop( Iop_CmpD64,
11025 mkexpr( abs_frA ),
11026 unop( Iop_ReinterpI64asD64,
11027 mkU64( 0x2238000000000000ULL ) ) ) );
11028
11029 /* size = DFP_LONG; JRS: unused */
11030 break;
11031
11032 case 0x3F: // dtstdcq, dtstdgq
11033 DIP("dtstd%sq %u,r%u,%d\n", opc2 == 0xc2 ? "c" : "g",
11034 crfD, frA_addr, DCM);
11035 /* setup the parameters for the extended format of the
11036 * two instructions
11037 */
11038 assign( frAI64_lo, unop( Iop_ReinterpD64asI64,
11039 getDReg( frA_addr+1 ) ) );
11040
11041 assign( gfield_mask, mkU32( DFP_G_FIELD_EXTND_MASK ) );
11042 max_exp = DFP_EXTND_EXP_MAX;
11043 min_exp = DFP_EXTND_EXP_MIN;
11044 assign( exponent, unop( Iop_64to32,
carllcea07cc2013-01-22 20:25:31 +000011045 unop( Iop_ExtractExpD128,
11046 getDReg_pair( frA_addr) ) ) );
sewardj5eff1c52012-04-29 20:19:17 +000011047
11048 /* create quand exponent for minimum normal number */
carllcea07cc2013-01-22 20:25:31 +000011049 assign( exp_min_normal, mkU64( 6176 - 6143 ) );
sewardj5eff1c52012-04-29 20:19:17 +000011050 assign( significand128,
11051 unop( Iop_D64toD128,
11052 unop( Iop_ReinterpI64asD64,
11053 mkU64( 0x2234000000000001ULL ) ) ) ); // dfp 1.0
11054
11055 assign( min_subnormalD128,
11056 binop( Iop_InsertExpD128,
11057 mkexpr( exp_min_normal ),
11058 mkexpr( significand128 ) ) );
11059
11060 assign( ccIR_subnormal,
11061 binop( Iop_CmpD128,
11062 binop( Iop_D64HLtoD128,
11063 unop( Iop_ReinterpI64asD64,
11064 binop( Iop_And64,
11065 unop( Iop_ReinterpD64asI64,
11066 mkexpr( frA ) ),
11067 mkU64( 0x7FFFFFFFFFFFFFFFULL ) ) ),
11068 getDReg( frA_addr+1 ) ),
11069 mkexpr( min_subnormalD128 ) ) );
11070 assign( ccIR_zero,
11071 binop( Iop_CmpD128,
11072 binop( Iop_D64HLtoD128,
11073 mkexpr( abs_frA ),
11074 getDReg( frA_addr+1 ) ),
11075 unop( Iop_D64toD128,
11076 unop( Iop_ReinterpI64asD64,
11077 mkU64( 0x0ULL ) ) ) ) );
11078
11079 /* size = DFP_EXTND; JRS:unused */
11080 break;
11081 default:
11082 vex_printf("dis_dfp_class_test(ppc)(opc2)\n");
11083 return False;
11084 }
11085
11086 /* The G-field is in the upper 32-bits. The I64 logical operations
11087 * do not seem to be supported in 32-bit mode so keep things as 32-bit
11088 * operations.
11089 */
11090 assign( gfield, binop( Iop_And32,
11091 mkexpr( gfield_mask ),
11092 unop( Iop_64HIto32,
11093 mkexpr(frAI64_hi) ) ) );
11094
11095 /* There is a lot of code that is the same to do the class and group
11096 * instructions. Later there is an if statement to handle the specific
11097 * instruction.
11098 *
11099 * Will be using I32 values, compares, shifts and logical operations for
11100 * this code as the 64-bit compare, shifts, logical operations are not
11101 * supported in 32-bit mode.
11102 */
11103
11104 /* Check the bits for Infinity, QNaN or Signaling NaN */
11105 assign( infinity_true,
11106 unop( Iop_1Sto32,
11107 binop( Iop_CmpEQ32,
11108 binop( Iop_And32,
11109 mkU32( 0x7C000000 ),
11110 mkexpr( gfield ) ),
11111 mkU32( 0x78000000 ) ) ) );
11112
11113 assign( SNaN_true,
11114 unop( Iop_1Sto32,
11115 binop( Iop_CmpEQ32,
11116 binop( Iop_And32,
11117 mkU32( 0x7E000000 ),
11118 mkexpr( gfield ) ),
11119 mkU32( 0x7E000000 ) ) ) );
11120
11121 assign( QNaN_true,
11122 binop( Iop_And32,
11123 unop( Iop_1Sto32,
11124 binop( Iop_CmpEQ32,
11125 binop( Iop_And32,
11126 mkU32( 0x7E000000 ),
11127 mkexpr( gfield ) ),
11128 mkU32( 0x7C000000 ) ) ),
11129 unop( Iop_Not32,
11130 mkexpr( SNaN_true ) ) ) );
11131
11132 assign( zero_true,
11133 binop( Iop_And32,
11134 unop(Iop_1Sto32,
11135 binop( Iop_CmpEQ32,
11136 mkexpr( ccIR_zero ),
11137 mkU32( 0x40 ) ) ), // ccIR code for Equal
11138 unop( Iop_Not32,
11139 binop( Iop_Or32,
11140 mkexpr( infinity_true ),
11141 binop( Iop_Or32,
11142 mkexpr( QNaN_true ),
11143 mkexpr( SNaN_true ) ) ) ) ) );
11144
11145 /* Do compare of frA the minimum normal value. Comparison is size
11146 * depenent and was done above to get the ccIR value.
11147 */
11148 assign( subnormal_true,
11149 binop( Iop_And32,
11150 binop( Iop_Or32,
11151 unop( Iop_1Sto32,
11152 binop( Iop_CmpEQ32,
11153 mkexpr( ccIR_subnormal ),
11154 mkU32( 0x40 ) ) ), // ccIR code for Equal
11155 unop( Iop_1Sto32,
11156 binop( Iop_CmpEQ32,
11157 mkexpr( ccIR_subnormal ),
11158 mkU32( 0x1 ) ) ) ), // ccIR code for LT
11159 unop( Iop_Not32,
11160 binop( Iop_Or32,
11161 binop( Iop_Or32,
11162 mkexpr( infinity_true ),
11163 mkexpr( zero_true) ),
11164 binop( Iop_Or32,
11165 mkexpr( QNaN_true ),
11166 mkexpr( SNaN_true ) ) ) ) ) );
11167
11168 /* Normal number is not subnormal, infinity, NaN or Zero */
11169 assign( normal_true,
11170 unop( Iop_Not32,
11171 binop( Iop_Or32,
11172 binop( Iop_Or32,
11173 mkexpr( infinity_true ),
11174 mkexpr( zero_true ) ),
11175 binop( Iop_Or32,
11176 mkexpr( subnormal_true ),
11177 binop( Iop_Or32,
11178 mkexpr( QNaN_true ),
11179 mkexpr( SNaN_true ) ) ) ) ) );
11180
11181 /* Calculate the DCM bit field based on the tests for the specific
11182 * instruction
11183 */
11184 if (opc2 == 0xC2) { // dtstdc, dtstdcq
11185 /* DCM[0:5] Bit Data Class definition
11186 * 0 Zero
11187 * 1 Subnormal
11188 * 2 Normal
11189 * 3 Infinity
11190 * 4 Quiet NaN
11191 * 5 Signaling NaN
11192 */
11193
11194 assign( dcm0, binop( Iop_Shl32,
11195 mkexpr( zero_true ),
11196 mkU8( 5 ) ) );
11197 assign( dcm1, binop( Iop_Shl32,
11198 binop( Iop_And32,
11199 mkexpr( subnormal_true ),
11200 mkU32( 1 ) ),
11201 mkU8( 4 ) ) );
11202 assign( dcm2, binop( Iop_Shl32,
11203 binop( Iop_And32,
11204 mkexpr( normal_true ),
11205 mkU32( 1 ) ),
11206 mkU8( 3 ) ) );
11207 assign( dcm3, binop( Iop_Shl32,
11208 binop( Iop_And32,
11209 mkexpr( infinity_true),
11210 mkU32( 1 ) ),
11211 mkU8( 2 ) ) );
11212 assign( dcm4, binop( Iop_Shl32,
11213 binop( Iop_And32,
11214 mkexpr( QNaN_true ),
11215 mkU32( 1 ) ),
11216 mkU8( 1 ) ) );
11217 assign( dcm5, binop( Iop_And32, mkexpr( SNaN_true), mkU32( 1 ) ) );
11218
11219 } else if (opc2 == 0xE2) { // dtstdg, dtstdgq
11220 /* check if the exponent is extreme */
11221 assign( extreme_true, binop( Iop_Or32,
11222 unop( Iop_1Sto32,
11223 binop( Iop_CmpEQ32,
11224 mkexpr( exponent ),
11225 mkU32( max_exp ) ) ),
11226 unop( Iop_1Sto32,
11227 binop( Iop_CmpEQ32,
11228 mkexpr( exponent ),
11229 mkU32( min_exp ) ) ) ) );
11230
11231 /* Check if LMD is zero */
11232 Get_lmd( &lmd, binop( Iop_Shr32,
11233 mkexpr( gfield ), mkU8( 31 - 5 ) ) );
11234
11235 assign( lmd_zero_true, unop( Iop_1Sto32,
11236 binop( Iop_CmpEQ32,
11237 mkexpr( lmd ),
11238 mkU32( 0 ) ) ) );
11239
11240 /* DCM[0:5] Bit Data Class definition
11241 * 0 Zero with non-extreme exponent
11242 * 1 Zero with extreme exponent
11243 * 2 Subnormal or (Normal with extreme exponent)
11244 * 3 Normal with non-extreme exponent and
11245 * leftmost zero digit in significand
11246 * 4 Normal with non-extreme exponent and
11247 * leftmost nonzero digit in significand
11248 * 5 Special symbol (Infinity, QNaN, or SNaN)
11249 */
11250 assign( dcm0, binop( Iop_Shl32,
11251 binop( Iop_And32,
11252 binop( Iop_And32,
11253 unop( Iop_Not32,
11254 mkexpr( extreme_true ) ),
11255 mkexpr( zero_true ) ),
11256 mkU32( 0x1 ) ),
11257 mkU8( 5 ) ) );
11258
11259 assign( dcm1, binop( Iop_Shl32,
11260 binop( Iop_And32,
11261 binop( Iop_And32,
11262 mkexpr( extreme_true ),
11263 mkexpr( zero_true ) ),
11264 mkU32( 0x1 ) ),
11265 mkU8( 4 ) ) );
11266
11267 assign( dcm2, binop( Iop_Shl32,
11268 binop( Iop_And32,
11269 binop( Iop_Or32,
11270 binop( Iop_And32,
11271 mkexpr( extreme_true ),
11272 mkexpr( normal_true ) ),
11273 mkexpr( subnormal_true ) ),
11274 mkU32( 0x1 ) ),
11275 mkU8( 3 ) ) );
11276
11277 assign( dcm3, binop( Iop_Shl32,
11278 binop( Iop_And32,
11279 binop( Iop_And32,
11280 binop( Iop_And32,
11281 unop( Iop_Not32,
11282 mkexpr( extreme_true ) ),
11283 mkexpr( normal_true ) ),
11284 unop( Iop_1Sto32,
11285 binop( Iop_CmpEQ32,
11286 mkexpr( lmd ),
11287 mkU32( 0 ) ) ) ),
11288 mkU32( 0x1 ) ),
11289 mkU8( 2 ) ) );
11290
11291 assign( dcm4, binop( Iop_Shl32,
11292 binop( Iop_And32,
11293 binop( Iop_And32,
11294 binop( Iop_And32,
11295 unop( Iop_Not32,
11296 mkexpr( extreme_true ) ),
11297 mkexpr( normal_true ) ),
11298 unop( Iop_1Sto32,
11299 binop( Iop_CmpNE32,
11300 mkexpr( lmd ),
sewardj4c96e612012-06-02 23:47:02 +000011301 mkU32( 0 ) ) ) ),
sewardj5eff1c52012-04-29 20:19:17 +000011302 mkU32( 0x1 ) ),
11303 mkU8( 1 ) ) );
11304
11305 assign( dcm5, binop( Iop_And32,
11306 binop( Iop_Or32,
11307 mkexpr( SNaN_true),
11308 binop( Iop_Or32,
11309 mkexpr( QNaN_true),
11310 mkexpr( infinity_true) ) ),
11311 mkU32( 0x1 ) ) );
11312 }
11313
11314 /* create DCM field */
11315 assign( DCM_calc,
11316 binop( Iop_Or32,
11317 mkexpr( dcm0 ),
11318 binop( Iop_Or32,
11319 mkexpr( dcm1 ),
11320 binop( Iop_Or32,
11321 mkexpr( dcm2 ),
11322 binop( Iop_Or32,
11323 mkexpr( dcm3 ),
11324 binop( Iop_Or32,
11325 mkexpr( dcm4 ),
11326 mkexpr( dcm5 ) ) ) ) ) ) );
11327
11328 /* Get the sign of the DFP number, ignore sign for QNaN */
11329 assign( sign,
11330 unop( Iop_1Uto32,
11331 binop( Iop_CmpEQ32,
11332 binop( Iop_Shr32,
11333 unop( Iop_64HIto32, mkexpr( frAI64_hi ) ),
11334 mkU8( 63 - 32 ) ),
11335 mkU32( 1 ) ) ) );
11336
11337 /* This instruction generates a four bit field to be stored in the
11338 * condition code register. The condition code register consists of 7
11339 * fields. The field to be written to is specified by the BF (AKA crfD)
11340 * field.
11341 *
11342 * The field layout is as follows:
11343 *
11344 * Field Meaning
11345 * 0000 Operand positive with no match
11346 * 0100 Operand positive with at least one match
11347 * 0001 Operand negative with no match
11348 * 0101 Operand negative with at least one match
11349 */
11350 assign( field, binop( Iop_Or32,
11351 binop( Iop_Shl32,
11352 mkexpr( sign ),
11353 mkU8( 3 ) ),
11354 binop( Iop_Shl32,
11355 unop( Iop_1Uto32,
11356 binop( Iop_CmpNE32,
11357 binop( Iop_And32,
11358 mkU32( DCM ),
11359 mkexpr( DCM_calc ) ),
11360 mkU32( 0 ) ) ),
11361 mkU8( 1 ) ) ) );
11362
11363 putGST_field( PPC_GST_CR, mkexpr( field ), crfD );
11364 return True;
11365}
11366
sewardj4c96e612012-06-02 23:47:02 +000011367static Bool dis_dfp_bcd(UInt theInstr) {
11368 UInt opc2 = ifieldOPClo10( theInstr );
11369 ULong sp = IFIELD(theInstr, 19, 2);
11370 ULong s = IFIELD(theInstr, 20, 1);
11371 UChar frT_addr = ifieldRegDS( theInstr );
11372 UChar frB_addr = ifieldRegB( theInstr );
11373 IRTemp frB = newTemp( Ity_D64 );
11374 IRTemp frBI64 = newTemp( Ity_I64 );
11375 IRTemp result = newTemp( Ity_I64 );
11376 IRTemp resultD64 = newTemp( Ity_D64 );
11377 IRTemp bcd64 = newTemp( Ity_I64 );
11378 IRTemp bcd_u = newTemp( Ity_I32 );
11379 IRTemp bcd_l = newTemp( Ity_I32 );
11380 IRTemp dbcd_u = newTemp( Ity_I32 );
11381 IRTemp dbcd_l = newTemp( Ity_I32 );
11382 IRTemp lmd = newTemp( Ity_I32 );
11383
11384 assign( frB, getDReg( frB_addr ) );
11385 assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
11386
11387 switch ( opc2 ) {
11388 case 0x142: // ddedpd DFP Decode DPD to BCD
11389 DIP( "ddedpd %llu,r%u,r%u\n", sp, frT_addr, frB_addr );
11390
11391 assign( bcd64, unop( Iop_DPBtoBCD, mkexpr( frBI64 ) ) );
11392 assign( bcd_u, unop( Iop_64HIto32, mkexpr( bcd64 ) ) );
11393 assign( bcd_l, unop( Iop_64to32, mkexpr( bcd64 ) ) );
11394
11395 if ( ( sp == 0 ) || ( sp == 1 ) ) {
11396 /* Unsigned BCD string */
11397 Get_lmd( &lmd,
11398 binop( Iop_Shr32,
11399 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
11400 mkU8( 31 - 5 ) ) ); // G-field[0:4]
11401
11402 assign( result,
11403 binop( Iop_32HLto64,
11404 binop( Iop_Or32,
11405 binop( Iop_Shl32, mkexpr( lmd ), mkU8( 28 ) ),
11406 mkexpr( bcd_u ) ),
11407 mkexpr( bcd_l ) ) );
11408
11409 } else {
11410 /* Signed BCD string, the cases for sp 2 and 3 only differ in how
11411 * the positive and negative values are encoded in the least
11412 * significant bits.
11413 */
11414 IRTemp sign = newTemp( Ity_I32 );
11415
11416 if (sp == 2) {
11417 /* Positive sign = 0xC, negative sign = 0xD */
11418
11419 assign( sign,
11420 binop( Iop_Or32,
11421 binop( Iop_Shr32,
11422 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
11423 mkU8( 31 ) ),
11424 mkU32( 0xC ) ) );
11425
11426 } else if ( sp == 3 ) {
11427 /* Positive sign = 0xF, negative sign = 0xD */
11428 IRTemp tmp32 = newTemp( Ity_I32 );
11429
11430 /* Complement sign bit then OR into bit position 1 */
11431 assign( tmp32,
11432 binop( Iop_Xor32,
11433 binop( Iop_Shr32,
11434 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
11435 mkU8( 30 ) ),
11436 mkU32( 0x2 ) ) );
11437
11438 assign( sign, binop( Iop_Or32, mkexpr( tmp32 ), mkU32( 0xD ) ) );
11439
11440 } else {
11441 vpanic( "The impossible happened: dis_dfp_bcd(ppc), undefined SP field" );
11442 }
11443
11444 /* Put sign in bottom 4 bits, move most significant 4-bits from
11445 * bcd_l to bcd_u.
11446 */
11447 assign( result,
11448 binop( Iop_32HLto64,
11449 binop( Iop_Or32,
11450 binop( Iop_Shr32,
11451 mkexpr( bcd_l ),
11452 mkU8( 28 ) ),
11453 binop( Iop_Shl32,
11454 mkexpr( bcd_u ),
11455 mkU8( 4 ) ) ),
11456 binop( Iop_Or32,
11457 mkexpr( sign ),
11458 binop( Iop_Shl32,
11459 mkexpr( bcd_l ),
11460 mkU8( 4 ) ) ) ) );
11461 }
11462
11463 putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result ) ) );
11464 break;
11465
11466 case 0x342: // denbcd DFP Encode BCD to DPD
11467 {
11468 IRTemp valid_mask = newTemp( Ity_I32 );
11469 IRTemp invalid_mask = newTemp( Ity_I32 );
11470 IRTemp without_lmd = newTemp( Ity_I64 );
11471 IRTemp tmp64 = newTemp( Ity_I64 );
11472 IRTemp dbcd64 = newTemp( Ity_I64 );
11473 IRTemp left_exp = newTemp( Ity_I32 );
11474 IRTemp g0_4 = newTemp( Ity_I32 );
11475
11476 DIP( "denbcd %llu,r%u,r%u\n", s, frT_addr, frB_addr );
11477
11478 if ( s == 0 ) {
11479 /* Unsigned BCD string */
11480 assign( dbcd64, unop( Iop_BCDtoDPB, mkexpr(frBI64 ) ) );
11481 assign( dbcd_u, unop( Iop_64HIto32, mkexpr( dbcd64 ) ) );
11482 assign( dbcd_l, unop( Iop_64to32, mkexpr( dbcd64 ) ) );
11483
11484 assign( lmd,
11485 binop( Iop_Shr32,
11486 binop( Iop_And32,
11487 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
11488 mkU32( 0xF0000000 ) ),
11489 mkU8( 28 ) ) );
11490
11491 assign( invalid_mask,
11492 bcd_digit_inval( unop( Iop_64HIto32, mkexpr( frBI64 ) ),
11493 unop( Iop_64to32, mkexpr( frBI64 ) ) ) );
11494 assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
11495
11496 assign( without_lmd,
11497 unop( Iop_ReinterpD64asI64,
11498 binop( Iop_InsertExpD64,
carllcea07cc2013-01-22 20:25:31 +000011499 mkU64( DFP_LONG_BIAS ),
sewardj4c96e612012-06-02 23:47:02 +000011500 unop( Iop_ReinterpI64asD64,
11501 binop( Iop_32HLto64,
11502 mkexpr( dbcd_u ),
11503 mkexpr( dbcd_l ) ) ) ) ) );
11504 assign( left_exp,
11505 binop( Iop_Shr32,
11506 binop( Iop_And32,
11507 unop( Iop_64HIto32, mkexpr( without_lmd ) ),
11508 mkU32( 0x60000000 ) ),
11509 mkU8( 29 ) ) );
11510
11511 assign( g0_4,
11512 binop( Iop_Shl32,
11513 Gfield_encoding( mkexpr( left_exp ), mkexpr( lmd ) ),
11514 mkU8( 26 ) ) );
11515
11516 assign( tmp64,
11517 binop( Iop_32HLto64,
11518 binop( Iop_Or32,
11519 binop( Iop_And32,
11520 unop( Iop_64HIto32,
11521 mkexpr( without_lmd ) ),
11522 mkU32( 0x83FFFFFF ) ),
11523 mkexpr( g0_4 ) ),
11524 unop( Iop_64to32, mkexpr( without_lmd ) ) ) );
11525
11526 } else if ( s == 1 ) {
11527 IRTemp sign = newTemp( Ity_I32 );
11528 IRTemp sign_bit = newTemp( Ity_I32 );
11529 IRTemp pos_sign_mask = newTemp( Ity_I32 );
11530 IRTemp neg_sign_mask = newTemp( Ity_I32 );
11531 IRTemp tmp = newTemp( Ity_I64 );
11532
11533 /* Signed BCD string, least significant 4 bits are sign bits
11534 * positive sign = 0xC, negative sign = 0xD
11535 */
11536 assign( tmp, unop( Iop_BCDtoDPB,
11537 binop( Iop_32HLto64,
11538 binop( Iop_Shr32,
11539 unop( Iop_64HIto32,
11540 mkexpr( frBI64 ) ),
11541 mkU8( 4 ) ),
11542 binop( Iop_Or32,
11543 binop( Iop_Shr32,
11544 unop( Iop_64to32,
11545 mkexpr( frBI64 ) ),
11546 mkU8( 4 ) ),
11547 binop( Iop_Shl32,
11548 unop( Iop_64HIto32,
11549 mkexpr( frBI64 ) ),
11550 mkU8( 28 ) ) ) ) ) );
11551
11552 assign( dbcd_u, unop( Iop_64HIto32, mkexpr( tmp ) ) );
11553 assign( dbcd_l, unop( Iop_64to32, mkexpr( tmp ) ) );
11554
11555 /* Get the sign of the BCD string. */
11556 assign( sign,
11557 binop( Iop_And32,
11558 unop( Iop_64to32, mkexpr( frBI64 ) ),
11559 mkU32( 0xF ) ) );
11560
11561 assign( neg_sign_mask, Generate_neg_sign_mask( mkexpr( sign ) ) );
11562 assign( pos_sign_mask, Generate_pos_sign_mask( mkexpr( sign ) ) );
11563 assign( sign_bit,
11564 Generate_sign_bit( mkexpr( pos_sign_mask ),
11565 mkexpr( neg_sign_mask ) ) );
11566
11567 /* Check for invalid sign and BCD digit. Don't check the bottom
11568 * four bits of bcd_l as that is the sign value.
11569 */
11570 assign( invalid_mask,
11571 Generate_inv_mask(
11572 bcd_digit_inval( unop( Iop_64HIto32,
11573 mkexpr( frBI64 ) ),
11574 binop( Iop_Shr32,
11575 unop( Iop_64to32,
11576 mkexpr( frBI64 ) ),
11577 mkU8( 4 ) ) ),
11578 mkexpr( pos_sign_mask ),
11579 mkexpr( neg_sign_mask ) ) );
11580
11581 assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
11582
11583 /* Generate the result assuming the sign value was valid. */
11584 assign( tmp64,
11585 unop( Iop_ReinterpD64asI64,
11586 binop( Iop_InsertExpD64,
carllcea07cc2013-01-22 20:25:31 +000011587 mkU64( DFP_LONG_BIAS ),
sewardj4c96e612012-06-02 23:47:02 +000011588 unop( Iop_ReinterpI64asD64,
11589 binop( Iop_32HLto64,
11590 binop( Iop_Or32,
11591 mkexpr( dbcd_u ),
11592 mkexpr( sign_bit ) ),
11593 mkexpr( dbcd_l ) ) ) ) ) );
11594 }
11595
11596 /* Generate the value to store depending on the validity of the
11597 * sign value and the validity of the BCD digits.
11598 */
11599 assign( resultD64,
11600 unop( Iop_ReinterpI64asD64,
11601 binop( Iop_32HLto64,
11602 binop( Iop_Or32,
11603 binop( Iop_And32,
11604 mkexpr( valid_mask ),
11605 unop( Iop_64HIto32,
11606 mkexpr( tmp64 ) ) ),
11607 binop( Iop_And32,
11608 mkU32( 0x7C000000 ),
11609 mkexpr( invalid_mask ) ) ),
11610 binop( Iop_Or32,
11611 binop( Iop_And32,
11612 mkexpr( valid_mask ),
11613 unop( Iop_64to32, mkexpr( tmp64 ) ) ),
11614 binop( Iop_And32,
11615 mkU32( 0x0 ),
11616 mkexpr( invalid_mask ) ) ) ) ) );
11617 putDReg( frT_addr, mkexpr( resultD64 ) );
11618 }
11619 break;
11620 default:
11621 vpanic( "ERROR: dis_dfp_bcd(ppc), undefined opc2 case " );
11622 return False;
11623 }
11624 return True;
11625}
11626
11627static Bool dis_dfp_bcdq( UInt theInstr )
11628{
11629 UInt opc2 = ifieldOPClo10( theInstr );
11630 ULong sp = IFIELD(theInstr, 19, 2);
11631 ULong s = IFIELD(theInstr, 20, 1);
11632 IRTemp frB_hi = newTemp( Ity_D64 );
11633 IRTemp frB_lo = newTemp( Ity_D64 );
11634 IRTemp frBI64_hi = newTemp( Ity_I64 );
11635 IRTemp frBI64_lo = newTemp( Ity_I64 );
11636 UChar frT_addr = ifieldRegDS( theInstr );
11637 UChar frB_addr = ifieldRegB( theInstr );
11638
11639 IRTemp lmd = newTemp( Ity_I32 );
11640 IRTemp result_hi = newTemp( Ity_I64 );
11641 IRTemp result_lo = newTemp( Ity_I64 );
11642
11643 assign( frB_hi, getDReg( frB_addr ) );
11644 assign( frB_lo, getDReg( frB_addr + 1 ) );
11645 assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
11646 assign( frBI64_lo, unop( Iop_ReinterpD64asI64, mkexpr( frB_lo ) ) );
11647
11648 switch ( opc2 ) {
11649 case 0x142: // ddedpdq DFP Decode DPD to BCD
11650 {
11651 IRTemp low_60_u = newTemp( Ity_I32 );
11652 IRTemp low_60_l = newTemp( Ity_I32 );
11653 IRTemp mid_60_u = newTemp( Ity_I32 );
11654 IRTemp mid_60_l = newTemp( Ity_I32 );
11655 IRTemp top_12_l = newTemp( Ity_I32 );
11656
11657 DIP( "ddedpdq %llu,r%u,r%u\n", sp, frT_addr, frB_addr );
11658
11659 /* Note, instruction only stores the lower 32 BCD digits in
11660 * the result
11661 */
11662 Generate_132_bit_bcd_string( mkexpr( frBI64_hi ),
11663 mkexpr( frBI64_lo ),
11664 &top_12_l,
11665 &mid_60_u,
11666 &mid_60_l,
11667 &low_60_u,
11668 &low_60_l );
11669
11670 if ( ( sp == 0 ) || ( sp == 1 ) ) {
11671 /* Unsigned BCD string */
11672 assign( result_hi,
11673 binop( Iop_32HLto64,
11674 binop( Iop_Or32,
11675 binop( Iop_Shl32,
11676 mkexpr( top_12_l ),
11677 mkU8( 24 ) ),
11678 binop( Iop_Shr32,
11679 mkexpr( mid_60_u ),
11680 mkU8( 4 ) ) ),
11681 binop( Iop_Or32,
11682 binop( Iop_Shl32,
11683 mkexpr( mid_60_u ),
11684 mkU8( 28 ) ),
11685 binop( Iop_Shr32,
11686 mkexpr( mid_60_l ),
11687 mkU8( 4 ) ) ) ) );
11688
11689 assign( result_lo,
11690 binop( Iop_32HLto64,
11691 binop( Iop_Or32,
11692 binop( Iop_Shl32,
11693 mkexpr( mid_60_l ),
11694 mkU8( 28 ) ),
11695 mkexpr( low_60_u ) ),
11696 mkexpr( low_60_l ) ) );
11697
11698 } else {
11699 /* Signed BCD string, the cases for sp 2 and 3 only differ in how
11700 * the positive and negative values are encoded in the least
11701 * significant bits.
11702 */
11703 IRTemp sign = newTemp( Ity_I32 );
11704
11705 if ( sp == 2 ) {
11706 /* Positive sign = 0xC, negative sign = 0xD */
11707 assign( sign,
11708 binop( Iop_Or32,
11709 binop( Iop_Shr32,
11710 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
11711 mkU8( 31 ) ),
11712 mkU32( 0xC ) ) );
11713
11714 } else if ( sp == 3 ) {
11715 IRTemp tmp32 = newTemp( Ity_I32 );
11716
11717 /* Positive sign = 0xF, negative sign = 0xD.
11718 * Need to complement sign bit then OR into bit position 1.
11719 */
11720 assign( tmp32,
11721 binop( Iop_Xor32,
11722 binop( Iop_Shr32,
11723 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
11724 mkU8( 30 ) ),
11725 mkU32( 0x2 ) ) );
11726
11727 assign( sign, binop( Iop_Or32, mkexpr( tmp32 ), mkU32( 0xD ) ) );
11728
11729 } else {
11730 vpanic( "The impossible happened: dis_dfp_bcd(ppc), undefined SP field" );
11731 }
11732
11733 assign( result_hi,
11734 binop( Iop_32HLto64,
11735 binop( Iop_Or32,
11736 binop( Iop_Shl32,
11737 mkexpr( top_12_l ),
11738 mkU8( 28 ) ),
11739 mkexpr( mid_60_u ) ),
11740 mkexpr( mid_60_l ) ) );
11741
11742 assign( result_lo,
11743 binop( Iop_32HLto64,
11744 binop( Iop_Or32,
11745 binop( Iop_Shl32,
11746 mkexpr( low_60_u ),
11747 mkU8( 4 ) ),
11748 binop( Iop_Shr32,
11749 mkexpr( low_60_l ),
11750 mkU8( 28 ) ) ),
11751 binop( Iop_Or32,
11752 binop( Iop_Shl32,
11753 mkexpr( low_60_l ),
11754 mkU8( 4 ) ),
11755 mkexpr( sign ) ) ) );
11756 }
11757
11758 putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result_hi ) ) );
11759 putDReg( frT_addr + 1,
11760 unop( Iop_ReinterpI64asD64, mkexpr( result_lo ) ) );
11761 }
11762 break;
11763 case 0x342: // denbcdq DFP Encode BCD to DPD
11764 {
11765 IRTemp valid_mask = newTemp( Ity_I32 );
11766 IRTemp invalid_mask = newTemp( Ity_I32 );
11767 IRTemp result128 = newTemp( Ity_D128 );
11768 IRTemp dfp_significand = newTemp( Ity_D128 );
11769 IRTemp tmp_hi = newTemp( Ity_I64 );
11770 IRTemp tmp_lo = newTemp( Ity_I64 );
11771 IRTemp dbcd_top_l = newTemp( Ity_I32 );
11772 IRTemp dbcd_mid_u = newTemp( Ity_I32 );
11773 IRTemp dbcd_mid_l = newTemp( Ity_I32 );
11774 IRTemp dbcd_low_u = newTemp( Ity_I32 );
11775 IRTemp dbcd_low_l = newTemp( Ity_I32 );
11776 IRTemp bcd_top_8 = newTemp( Ity_I64 );
11777 IRTemp bcd_mid_60 = newTemp( Ity_I64 );
11778 IRTemp bcd_low_60 = newTemp( Ity_I64 );
11779 IRTemp sign_bit = newTemp( Ity_I32 );
11780 IRTemp tmptop10 = newTemp( Ity_I64 );
11781 IRTemp tmpmid50 = newTemp( Ity_I64 );
11782 IRTemp tmplow50 = newTemp( Ity_I64 );
11783 IRTemp inval_bcd_digit_mask = newTemp( Ity_I32 );
11784
11785 DIP( "denbcd %llu,r%u,r%u\n", s, frT_addr, frB_addr );
11786
11787 if ( s == 0 ) {
11788 /* Unsigned BCD string */
11789 assign( sign_bit, mkU32( 0 ) ); // set to zero for unsigned string
11790
11791 assign( bcd_top_8,
11792 binop( Iop_32HLto64,
11793 mkU32( 0 ),
11794 binop( Iop_And32,
11795 binop( Iop_Shr32,
11796 unop( Iop_64HIto32,
11797 mkexpr( frBI64_hi ) ),
11798 mkU8( 24 ) ),
11799 mkU32( 0xFF ) ) ) );
11800 assign( bcd_mid_60,
11801 binop( Iop_32HLto64,
11802 binop( Iop_Or32,
11803 binop( Iop_Shr32,
11804 unop( Iop_64to32,
11805 mkexpr( frBI64_hi ) ),
11806 mkU8( 28 ) ),
11807 binop( Iop_Shl32,
11808 unop( Iop_64HIto32,
11809 mkexpr( frBI64_hi ) ),
11810 mkU8( 4 ) ) ),
11811 binop( Iop_Or32,
11812 binop( Iop_Shl32,
11813 unop( Iop_64to32,
11814 mkexpr( frBI64_hi ) ),
11815 mkU8( 4 ) ),
11816 binop( Iop_Shr32,
11817 unop( Iop_64HIto32,
11818 mkexpr( frBI64_lo ) ),
11819 mkU8( 28 ) ) ) ) );
11820
11821 /* Note, the various helper functions ignores top 4-bits */
11822 assign( bcd_low_60, mkexpr( frBI64_lo ) );
11823
11824 assign( tmptop10, unop( Iop_BCDtoDPB, mkexpr( bcd_top_8 ) ) );
11825 assign( dbcd_top_l, unop( Iop_64to32, mkexpr( tmptop10 ) ) );
11826
11827 assign( tmpmid50, unop( Iop_BCDtoDPB, mkexpr( bcd_mid_60 ) ) );
11828 assign( dbcd_mid_u, unop( Iop_64HIto32, mkexpr( tmpmid50 ) ) );
11829 assign( dbcd_mid_l, unop( Iop_64to32, mkexpr( tmpmid50 ) ) );
11830
11831 assign( tmplow50, unop( Iop_BCDtoDPB, mkexpr( bcd_low_60 ) ) );
11832 assign( dbcd_low_u, unop( Iop_64HIto32, mkexpr( tmplow50 ) ) );
11833 assign( dbcd_low_l, unop( Iop_64to32, mkexpr( tmplow50 ) ) );
11834
11835 /* The entire BCD string fits in lower 110-bits. The LMD = 0,
11836 * value is not part of the final result. Only the right most
11837 * BCD digits are stored.
11838 */
11839 assign( lmd, mkU32( 0 ) );
11840
11841 assign( invalid_mask,
11842 binop( Iop_Or32,
11843 bcd_digit_inval( mkU32( 0 ),
11844 unop( Iop_64to32,
11845 mkexpr( bcd_top_8 ) ) ),
11846 binop( Iop_Or32,
11847 bcd_digit_inval( unop( Iop_64HIto32,
11848 mkexpr( bcd_mid_60 ) ),
11849 unop( Iop_64to32,
11850 mkexpr( bcd_mid_60 ) ) ),
11851 bcd_digit_inval( unop( Iop_64HIto32,
11852 mkexpr( bcd_low_60 ) ),
11853 unop( Iop_64to32,
11854 mkexpr( bcd_low_60 ) )
11855 ) ) ) );
11856
11857 } else if ( s == 1 ) {
11858 IRTemp sign = newTemp( Ity_I32 );
11859 IRTemp zero = newTemp( Ity_I32 );
11860 IRTemp pos_sign_mask = newTemp( Ity_I32 );
11861 IRTemp neg_sign_mask = newTemp( Ity_I32 );
11862
11863 /* The sign of the BCD string is stored in lower 4 bits */
11864 assign( sign,
11865 binop( Iop_And32,
11866 unop( Iop_64to32, mkexpr( frBI64_lo ) ),
11867 mkU32( 0xF ) ) );
11868 assign( neg_sign_mask, Generate_neg_sign_mask( mkexpr( sign ) ) );
11869 assign( pos_sign_mask, Generate_pos_sign_mask( mkexpr( sign ) ) );
11870 assign( sign_bit,
11871 Generate_sign_bit( mkexpr( pos_sign_mask ),
11872 mkexpr( neg_sign_mask ) ) );
11873
11874 /* Generate the value assuminig the sign and BCD digits are vaild */
11875 assign( bcd_top_8,
11876 binop( Iop_32HLto64,
11877 mkU32( 0x0 ),
11878 binop( Iop_Shr32,
11879 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
11880 mkU8( 28 ) ) ) );
11881
11882 /* The various helper routines ignore the upper 4-bits */
11883 assign( bcd_mid_60, mkexpr( frBI64_hi ) );
11884
11885 /* Remove bottom four sign bits */
11886 assign( bcd_low_60,
11887 binop( Iop_32HLto64,
11888 binop( Iop_Shr32,
11889 unop( Iop_64HIto32,
11890 mkexpr( frBI64_lo ) ),
11891 mkU8( 4 ) ),
11892 binop( Iop_Or32,
11893 binop( Iop_Shl32,
11894 unop( Iop_64HIto32,
11895 mkexpr( frBI64_lo ) ),
11896 mkU8( 28 ) ),
11897 binop( Iop_Shr32,
11898 unop( Iop_64to32,
11899 mkexpr( frBI64_lo ) ),
11900 mkU8( 4 ) ) ) ) );
11901 assign( tmptop10, unop( Iop_BCDtoDPB, mkexpr(bcd_top_8 ) ) );
11902 assign( dbcd_top_l, unop( Iop_64to32, mkexpr( tmptop10 ) ) );
11903
11904 assign( tmpmid50, unop( Iop_BCDtoDPB, mkexpr(bcd_mid_60 ) ) );
11905 assign( dbcd_mid_u, unop( Iop_64HIto32, mkexpr( tmpmid50 ) ) );
11906 assign( dbcd_mid_l, unop( Iop_64to32, mkexpr( tmpmid50 ) ) );
11907
11908 assign( tmplow50, unop( Iop_BCDtoDPB, mkexpr( bcd_low_60 ) ) );
11909 assign( dbcd_low_u, unop( Iop_64HIto32, mkexpr( tmplow50 ) ) );
11910 assign( dbcd_low_l, unop( Iop_64to32, mkexpr( tmplow50 ) ) );
11911
11912 /* The entire BCD string fits in lower 110-bits. The LMD value
11913 * is not stored in the final result for the DFP Long instruction.
11914 */
11915 assign( lmd, mkU32( 0 ) );
11916
11917 /* Check for invalid sign and invalid BCD digit. Don't check the
11918 * bottom four bits of frBI64_lo as that is the sign value.
11919 */
11920 assign( zero, mkU32( 0 ) );
11921 assign( inval_bcd_digit_mask,
11922 binop( Iop_Or32,
11923 bcd_digit_inval( mkexpr( zero ),
11924 unop( Iop_64to32,
11925 mkexpr( bcd_top_8 ) ) ),
11926 binop( Iop_Or32,
11927 bcd_digit_inval( unop( Iop_64HIto32,
11928 mkexpr( bcd_mid_60 ) ),
11929 unop( Iop_64to32,
11930 mkexpr( bcd_mid_60 ) ) ),
11931 bcd_digit_inval( unop( Iop_64HIto32,
11932 mkexpr( frBI64_lo ) ),
11933 binop( Iop_Shr32,
11934 unop( Iop_64to32,
11935 mkexpr( frBI64_lo ) ),
11936 mkU8( 4 ) ) ) ) ) );
11937 assign( invalid_mask,
11938 Generate_inv_mask( mkexpr( inval_bcd_digit_mask ),
11939 mkexpr( pos_sign_mask ),
11940 mkexpr( neg_sign_mask ) ) );
11941
11942 }
11943
11944 assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
11945
11946 /* Calculate the value of the result assuming sign and BCD digits
11947 * are all valid.
11948 */
11949 assign( dfp_significand,
11950 binop( Iop_D64HLtoD128,
11951 unop( Iop_ReinterpI64asD64,
11952 binop( Iop_32HLto64,
11953 binop( Iop_Or32,
11954 mkexpr( sign_bit ),
11955 mkexpr( dbcd_top_l ) ),
11956 binop( Iop_Or32,
11957 binop( Iop_Shl32,
11958 mkexpr( dbcd_mid_u ),
11959 mkU8( 18 ) ),
11960 binop( Iop_Shr32,
11961 mkexpr( dbcd_mid_l ),
11962 mkU8( 14 ) ) ) ) ),
11963 unop( Iop_ReinterpI64asD64,
11964 binop( Iop_32HLto64,
11965 binop( Iop_Or32,
11966 mkexpr( dbcd_low_u ),
11967 binop( Iop_Shl32,
11968 mkexpr( dbcd_mid_l ),
11969 mkU8( 18 ) ) ),
11970 mkexpr( dbcd_low_l ) ) ) ) );
11971
11972 /* Break the result back down to 32-bit chunks and replace chunks.
11973 * If there was an invalid BCD digit or invalid sign value, replace
11974 * the calculated result with the invalid bit string.
11975 */
11976 assign( result128,
11977 binop( Iop_InsertExpD128,
carllcea07cc2013-01-22 20:25:31 +000011978 mkU64( DFP_EXTND_BIAS ),
sewardj4c96e612012-06-02 23:47:02 +000011979 mkexpr( dfp_significand ) ) );
11980
11981 assign( tmp_hi,
11982 unop( Iop_ReinterpD64asI64,
11983 unop( Iop_D128HItoD64, mkexpr( result128 ) ) ) );
11984
11985 assign( tmp_lo,
11986 unop( Iop_ReinterpD64asI64,
11987 unop( Iop_D128LOtoD64, mkexpr( result128 ) ) ) );
11988
11989 assign( result_hi,
11990 binop( Iop_32HLto64,
11991 binop( Iop_Or32,
11992 binop( Iop_And32,
11993 mkexpr( valid_mask ),
11994 unop( Iop_64HIto32, mkexpr( tmp_hi ) ) ),
11995 binop( Iop_And32,
11996 mkU32( 0x7C000000 ),
11997 mkexpr( invalid_mask ) ) ),
11998 binop( Iop_Or32,
11999 binop( Iop_And32,
12000 mkexpr( valid_mask ),
12001 unop( Iop_64to32, mkexpr( tmp_hi ) ) ),
12002 binop( Iop_And32,
12003 mkU32( 0x0 ),
12004 mkexpr( invalid_mask ) ) ) ) );
12005
12006 assign( result_lo,
12007 binop( Iop_32HLto64,
12008 binop( Iop_Or32,
12009 binop( Iop_And32,
12010 mkexpr( valid_mask ),
12011 unop( Iop_64HIto32, mkexpr( tmp_lo ) ) ),
12012 binop( Iop_And32,
12013 mkU32( 0x0 ),
12014 mkexpr( invalid_mask ) ) ),
12015 binop( Iop_Or32,
12016 binop( Iop_And32,
12017 mkexpr( valid_mask ),
12018 unop( Iop_64to32, mkexpr( tmp_lo ) ) ),
12019 binop( Iop_And32,
12020 mkU32( 0x0 ),
12021 mkexpr( invalid_mask ) ) ) ) );
12022
12023 putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result_hi ) ) );
12024 putDReg( frT_addr + 1,
12025 unop( Iop_ReinterpI64asD64, mkexpr( result_lo ) ) );
12026
12027 }
12028 break;
12029 default:
12030 vpanic( "ERROR: dis_dfp_bcdq(ppc), undefined opc2 case " );
12031 break;
12032 }
12033 return True;
12034}
12035
12036static Bool dis_dfp_significant_digits( UInt theInstr )
12037{
12038 UChar frA_addr = ifieldRegA( theInstr );
12039 UChar frB_addr = ifieldRegB( theInstr );
12040 IRTemp frA = newTemp( Ity_D64 );
12041 UInt opc1 = ifieldOPC( theInstr );
12042 IRTemp B_sig = newTemp( Ity_I8 );
12043 IRTemp K = newTemp( Ity_I8 );
12044 IRTemp lmd_B = newTemp( Ity_I32 );
12045 IRTemp field = newTemp( Ity_I32 );
12046 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
12047 IRTemp Unordered_true = newTemp( Ity_I32 );
12048 IRTemp Eq_true_mask = newTemp( Ity_I32 );
12049 IRTemp Lt_true_mask = newTemp( Ity_I32 );
12050 IRTemp Gt_true_mask = newTemp( Ity_I32 );
12051 IRTemp KisZero_true_mask = newTemp( Ity_I32 );
12052 IRTemp KisZero_false_mask = newTemp( Ity_I32 );
12053
12054 /* Get the reference singificance stored in frA */
12055 assign( frA, getDReg( frA_addr ) );
12056
12057 /* Convert from 64 bit to 8 bits in two steps. The Iop_64to8 is not
12058 * supported in 32-bit mode.
12059 */
12060 assign( K, unop( Iop_32to8,
12061 binop( Iop_And32,
12062 unop( Iop_64to32,
12063 unop( Iop_ReinterpD64asI64,
12064 mkexpr( frA ) ) ),
12065 mkU32( 0x3F ) ) ) );
12066
12067 switch ( opc1 ) {
12068 case 0x3b: // dtstsf DFP Test Significance
12069 {
12070 IRTemp frB = newTemp( Ity_D64 );
12071 IRTemp frBI64 = newTemp( Ity_I64 );
12072 IRTemp B_bcd_u = newTemp( Ity_I32 );
12073 IRTemp B_bcd_l = newTemp( Ity_I32 );
12074 IRTemp tmp64 = newTemp( Ity_I64 );
12075
12076 DIP( "dtstsf %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
12077
12078 assign( frB, getDReg( frB_addr ) );
12079 assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
12080
12081 /* Get the BCD string for the value stored in a series of I32 values.
12082 * Count the number of leading zeros. Subtract the number of leading
12083 * zeros from 16 (maximum number of significant digits in DFP
12084 * Long).
12085 */
12086 Get_lmd( &lmd_B,
12087 binop( Iop_Shr32,
12088 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
12089 mkU8( 31 - 5 ) ) ); // G-field[0:4]
12090
12091 assign( tmp64, unop( Iop_DPBtoBCD, mkexpr( frBI64 ) ) );
12092 assign( B_bcd_u, unop( Iop_64HIto32, mkexpr( tmp64 ) ) );
12093 assign( B_bcd_l, unop( Iop_64to32, mkexpr( tmp64 ) ) );
12094
12095 assign( B_sig,
12096 binop( Iop_Sub8,
12097 mkU8( DFP_LONG_MAX_SIG_DIGITS ),
12098 Count_leading_zeros_60( mkexpr( lmd_B ),
12099 mkexpr( B_bcd_u ),
12100 mkexpr( B_bcd_l ) ) ) );
12101 assign( Unordered_true, Check_unordered( mkexpr( frBI64 ) ) );
12102 }
12103 break;
12104 case 0x3F: // dtstsfq DFP Test Significance
12105 {
12106 IRTemp frB_hi = newTemp( Ity_D64 );
12107 IRTemp frB_lo = newTemp( Ity_D64 );
12108 IRTemp frBI64_hi = newTemp( Ity_I64 );
12109 IRTemp frBI64_lo = newTemp( Ity_I64 );
12110 IRTemp B_low_60_u = newTemp( Ity_I32 );
12111 IRTemp B_low_60_l = newTemp( Ity_I32 );
12112 IRTemp B_mid_60_u = newTemp( Ity_I32 );
12113 IRTemp B_mid_60_l = newTemp( Ity_I32 );
12114 IRTemp B_top_12_l = newTemp( Ity_I32 );
12115
12116 DIP( "dtstsfq %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
12117
12118 assign( frB_hi, getDReg( frB_addr ) );
12119 assign( frB_lo, getDReg( frB_addr + 1 ) );
12120
12121 assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
12122 assign( frBI64_lo, unop( Iop_ReinterpD64asI64, mkexpr( frB_lo ) ) );
12123
12124 /* Get the BCD string for the value stored in a series of I32 values.
12125 * Count the number of leading zeros. Subtract the number of leading
12126 * zeros from 32 (maximum number of significant digits in DFP
12127 * extended).
12128 */
12129 Get_lmd( &lmd_B,
12130 binop( Iop_Shr32,
12131 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
12132 mkU8( 31 - 5 ) ) ); // G-field[0:4]
12133
12134 Generate_132_bit_bcd_string( mkexpr( frBI64_hi ),
12135 mkexpr( frBI64_lo ),
12136 &B_top_12_l,
12137 &B_mid_60_u,
12138 &B_mid_60_l,
12139 &B_low_60_u,
12140 &B_low_60_l );
12141
12142 assign( B_sig,
12143 binop( Iop_Sub8,
12144 mkU8( DFP_EXTND_MAX_SIG_DIGITS ),
12145 Count_leading_zeros_128( mkexpr( lmd_B ),
12146 mkexpr( B_top_12_l ),
12147 mkexpr( B_mid_60_u ),
12148 mkexpr( B_mid_60_l ),
12149 mkexpr( B_low_60_u ),
12150 mkexpr( B_low_60_l ) ) ) );
12151
12152 assign( Unordered_true, Check_unordered( mkexpr( frBI64_hi ) ) );
12153 }
12154 break;
12155 }
12156
12157 /* Compare (16 - cnt[0]) against K and set the condition code field
12158 * accordingly.
12159 *
12160 * The field layout is as follows:
12161 *
12162 * bit[3:0] Description
12163 * 3 K != 0 and K < Number of significant digits if FRB
12164 * 2 K != 0 and K > Number of significant digits if FRB OR K = 0
12165 * 1 K != 0 and K = Number of significant digits if FRB
12166 * 0 K ? Number of significant digits if FRB
12167 */
12168 assign( Eq_true_mask,
12169 unop( Iop_1Sto32,
12170 binop( Iop_CmpEQ32,
12171 unop( Iop_8Uto32, mkexpr( K ) ),
12172 unop( Iop_8Uto32, mkexpr( B_sig ) ) ) ) );
12173 assign( Lt_true_mask,
12174 unop( Iop_1Sto32,
12175 binop( Iop_CmpLT32U,
12176 unop( Iop_8Uto32, mkexpr( K ) ),
12177 unop( Iop_8Uto32, mkexpr( B_sig ) ) ) ) );
12178 assign( Gt_true_mask,
12179 unop( Iop_1Sto32,
12180 binop( Iop_CmpLT32U,
12181 unop( Iop_8Uto32, mkexpr( B_sig ) ),
12182 unop( Iop_8Uto32, mkexpr( K ) ) ) ) );
12183
12184 assign( KisZero_true_mask,
12185 unop( Iop_1Sto32,
12186 binop( Iop_CmpEQ32,
12187 unop( Iop_8Uto32, mkexpr( K ) ),
12188 mkU32( 0 ) ) ) );
12189 assign( KisZero_false_mask,
12190 unop( Iop_1Sto32,
12191 binop( Iop_CmpNE32,
12192 unop( Iop_8Uto32, mkexpr( K ) ),
12193 mkU32( 0 ) ) ) );
12194
12195 assign( field,
12196 binop( Iop_Or32,
12197 binop( Iop_And32,
12198 mkexpr( KisZero_false_mask ),
12199 binop( Iop_Or32,
12200 binop( Iop_And32,
12201 mkexpr( Lt_true_mask ),
12202 mkU32( 0x8 ) ),
12203 binop( Iop_Or32,
12204 binop( Iop_And32,
12205 mkexpr( Gt_true_mask ),
12206 mkU32( 0x4 ) ),
12207 binop( Iop_And32,
12208 mkexpr( Eq_true_mask ),
12209 mkU32( 0x2 ) ) ) ) ),
12210 binop( Iop_And32,
12211 mkexpr( KisZero_true_mask ),
12212 mkU32( 0x4 ) ) ) );
12213
12214 putGST_field( PPC_GST_CR,
12215 binop( Iop_Or32,
12216 binop( Iop_And32,
12217 mkexpr( Unordered_true ),
12218 mkU32( 0x1 ) ),
12219 binop( Iop_And32,
12220 unop( Iop_Not32, mkexpr( Unordered_true ) ),
12221 mkexpr( field ) ) ),
12222 crfD );
12223
12224 return True;
12225}
sewardj5eff1c52012-04-29 20:19:17 +000012226
cerion32aad402005-09-10 12:02:24 +000012227/*------------------------------------------------------------*/
12228/*--- AltiVec Instruction Translation ---*/
12229/*------------------------------------------------------------*/
12230
12231/*
12232 Altivec Cache Control Instructions (Data Streams)
12233*/
12234static Bool dis_av_datastream ( UInt theInstr )
12235{
cerion76de5cf2005-11-18 18:25:12 +000012236 /* X-Form */
12237 UChar opc1 = ifieldOPC(theInstr);
12238 UChar flag_T = toUChar( IFIELD( theInstr, 25, 1 ) );
12239 UChar flag_A = flag_T;
12240 UChar b23to24 = toUChar( IFIELD( theInstr, 23, 2 ) );
12241 UChar STRM = toUChar( IFIELD( theInstr, 21, 2 ) );
12242 UChar rA_addr = ifieldRegA(theInstr);
12243 UChar rB_addr = ifieldRegB(theInstr);
12244 UInt opc2 = ifieldOPClo10(theInstr);
12245 UChar b0 = ifieldBIT0(theInstr);
cerion32aad402005-09-10 12:02:24 +000012246
12247 if (opc1 != 0x1F || b23to24 != 0 || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +000012248 vex_printf("dis_av_datastream(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000012249 return False;
12250 }
12251
12252 switch (opc2) {
12253 case 0x156: // dst (Data Stream Touch, AV p115)
cerion5b2325f2005-12-23 00:55:09 +000012254 DIP("dst%s r%u,r%u,%d\n", flag_T ? "t" : "",
12255 rA_addr, rB_addr, STRM);
sewardj923c65b2006-12-27 23:59:31 +000012256 break;
cerion32aad402005-09-10 12:02:24 +000012257
12258 case 0x176: // dstst (Data Stream Touch for Store, AV p117)
cerion5b2325f2005-12-23 00:55:09 +000012259 DIP("dstst%s r%u,r%u,%d\n", flag_T ? "t" : "",
12260 rA_addr, rB_addr, STRM);
sewardj923c65b2006-12-27 23:59:31 +000012261 break;
cerion32aad402005-09-10 12:02:24 +000012262
12263 case 0x336: // dss (Data Stream Stop, AV p114)
12264 if (rA_addr != 0 || rB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +000012265 vex_printf("dis_av_datastream(ppc)(opc2,dst)\n");
cerion32aad402005-09-10 12:02:24 +000012266 return False;
12267 }
12268 if (flag_A == 0) {
12269 DIP("dss %d\n", STRM);
cerion32aad402005-09-10 12:02:24 +000012270 } else {
12271 DIP("dssall\n");
cerion32aad402005-09-10 12:02:24 +000012272 }
sewardj923c65b2006-12-27 23:59:31 +000012273 break;
cerion32aad402005-09-10 12:02:24 +000012274
12275 default:
cerion5b2325f2005-12-23 00:55:09 +000012276 vex_printf("dis_av_datastream(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000012277 return False;
12278 }
12279 return True;
12280}
12281
12282/*
12283 AltiVec Processor Control Instructions
12284*/
12285static Bool dis_av_procctl ( UInt theInstr )
12286{
cerion76de5cf2005-11-18 18:25:12 +000012287 /* VX-Form */
12288 UChar opc1 = ifieldOPC(theInstr);
12289 UChar vD_addr = ifieldRegDS(theInstr);
12290 UChar vA_addr = ifieldRegA(theInstr);
12291 UChar vB_addr = ifieldRegB(theInstr);
12292 UInt opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000012293
12294 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000012295 vex_printf("dis_av_procctl(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000012296 return False;
12297 }
12298
12299 switch (opc2) {
12300 case 0x604: // mfvscr (Move from VSCR, AV p129)
12301 if (vA_addr != 0 || vB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +000012302 vex_printf("dis_av_procctl(ppc)(opc2,dst)\n");
cerion32aad402005-09-10 12:02:24 +000012303 return False;
12304 }
12305 DIP("mfvscr v%d\n", vD_addr);
ceriond953ebb2005-11-29 13:27:20 +000012306 putVReg( vD_addr, unop(Iop_32UtoV128, getGST( PPC_GST_VSCR )) );
cerion225a0342005-09-12 20:49:09 +000012307 break;
cerion32aad402005-09-10 12:02:24 +000012308
cerion225a0342005-09-12 20:49:09 +000012309 case 0x644: { // mtvscr (Move to VSCR, AV p130)
sewardj197bd172005-10-12 11:34:33 +000012310 IRTemp vB = newTemp(Ity_V128);
cerion32aad402005-09-10 12:02:24 +000012311 if (vD_addr != 0 || vA_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +000012312 vex_printf("dis_av_procctl(ppc)(opc2,dst)\n");
cerion32aad402005-09-10 12:02:24 +000012313 return False;
12314 }
12315 DIP("mtvscr v%d\n", vB_addr);
cerion225a0342005-09-12 20:49:09 +000012316 assign( vB, getVReg(vB_addr));
ceriond953ebb2005-11-29 13:27:20 +000012317 putGST( PPC_GST_VSCR, unop(Iop_V128to32, mkexpr(vB)) );
cerion225a0342005-09-12 20:49:09 +000012318 break;
12319 }
cerion32aad402005-09-10 12:02:24 +000012320 default:
cerion5b2325f2005-12-23 00:55:09 +000012321 vex_printf("dis_av_procctl(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000012322 return False;
12323 }
12324 return True;
12325}
ceriona982c052005-06-28 17:23:09 +000012326
12327/*
sewardj4aa412a2011-07-24 14:13:21 +000012328 * VSX scalar and vector convert instructions
sewardj66d5ef22011-04-15 11:55:00 +000012329 */
12330static Bool
12331dis_vx_conv ( UInt theInstr, UInt opc2 )
12332{
12333 /* XX2-Form */
12334 UChar opc1 = ifieldOPC( theInstr );
12335 UChar XT = ifieldRegXT( theInstr );
12336 UChar XB = ifieldRegXB( theInstr );
sewardje71e56a2011-09-05 12:11:06 +000012337 IRTemp xB, xB2;
12338 IRTemp b3, b2, b1, b0;
12339 xB = xB2 = IRTemp_INVALID;
sewardj66d5ef22011-04-15 11:55:00 +000012340
12341 if (opc1 != 0x3C) {
12342 vex_printf( "dis_vx_conv(ppc)(instr)\n" );
12343 return False;
12344 }
12345
sewardje71e56a2011-09-05 12:11:06 +000012346 /* Create and assign temps only as needed for the given instruction. */
12347 switch (opc2) {
12348 // scalar double-precision floating point argument
carll0c74bb52013-08-12 18:01:40 +000012349 case 0x2B0: case 0x0b0: case 0x290: case 0x212: case 0x216: case 0x090:
sewardje71e56a2011-09-05 12:11:06 +000012350 xB = newTemp(Ity_F64);
12351 assign( xB,
12352 unop( Iop_ReinterpI64asF64,
12353 unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
12354 break;
12355 // vector double-precision floating point arguments
12356 case 0x1b0: case 0x312: case 0x390: case 0x190: case 0x3B0:
12357
12358 xB = newTemp(Ity_F64);
12359 xB2 = newTemp(Ity_F64);
12360 assign( xB,
12361 unop( Iop_ReinterpI64asF64,
12362 unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
12363 assign( xB2,
12364 unop( Iop_ReinterpI64asF64,
12365 unop( Iop_V128to64, getVSReg( XB ) ) ) );
12366 break;
12367 // vector single precision or [un]signed integer word arguments
12368 case 0x130: case 0x392: case 0x330: case 0x310: case 0x110:
12369 case 0x1f0: case 0x1d0:
12370 b3 = b2 = b1 = b0 = IRTemp_INVALID;
12371 breakV128to4x32(getVSReg(XB), &b3, &b2, &b1, &b0);
12372 break;
12373 // vector [un]signed integer doubleword argument
12374 case 0x3f0: case 0x370: case 0x3d0: case 0x350:
12375 xB = newTemp(Ity_I64);
12376 assign( xB, unop( Iop_V128HIto64, getVSReg( XB ) ) );
12377 xB2 = newTemp(Ity_I64);
12378 assign( xB2, unop( Iop_V128to64, getVSReg( XB ) ) );
12379 break;
12380 // scalar [un]signed integer doubleword argument
carll6c758b62013-10-03 21:38:45 +000012381 case 0x250: case 0x270: case 0x2D0: case 0x2F0:
sewardje71e56a2011-09-05 12:11:06 +000012382 xB = newTemp(Ity_I64);
12383 assign( xB, unop( Iop_V128HIto64, getVSReg( XB ) ) );
12384 break;
12385 // scalar single precision argument
12386 case 0x292: // xscvspdp
carll6fef87a2013-09-12 17:26:42 +000012387 xB = newTemp(Ity_I32);
12388
12389 assign( xB, handle_SNaN_to_QNaN_32(unop( Iop_64HIto32,
12390 unop( Iop_V128HIto64,
12391 getVSReg( XB ) ) ) ) );
sewardje71e56a2011-09-05 12:11:06 +000012392 break;
carll0c74bb52013-08-12 18:01:40 +000012393 case 0x296: // xscvspdpn (non signaling version of xscvpdp)
12394 xB = newTemp(Ity_I32);
12395 assign( xB,
12396 unop( Iop_64HIto32, unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
12397 break;
sewardje71e56a2011-09-05 12:11:06 +000012398
12399 /* Certain instructions have their complete implementation in the main switch statement
12400 * that follows this one; thus we have a "do nothing" case for those instructions here.
12401 */
12402 case 0x170: case 0x150:
12403 break; // do nothing
12404
12405 default:
12406 vex_printf( "dis_vx_conv(ppc)(opc2)\n" );
12407 return False;
12408 }
12409
sewardj66d5ef22011-04-15 11:55:00 +000012410
12411 switch (opc2) {
sewardje71e56a2011-09-05 12:11:06 +000012412 case 0x2B0:
12413 // xscvdpsxds (VSX Scalar truncate Double-Precision to integer and Convert
12414 // to Signed Integer Doubleword format with Saturate)
12415 DIP("xscvdpsxds v%u,v%u\n", (UInt)XT, (UInt)XB);
12416 putVSReg( XT,
sewardj66d5ef22011-04-15 11:55:00 +000012417 binop( Iop_64HLtoV128, binop( Iop_F64toI64S,
12418 mkU32( Irrm_ZERO ),
sewardje71e56a2011-09-05 12:11:06 +000012419 mkexpr( xB ) ), mkU64( 0 ) ) );
12420 break;
12421 case 0x0b0: // xscvdpsxws (VSX Scalar truncate Double-Precision to integer and
12422 // Convert to Signed Integer Word format with Saturate)
12423 DIP("xscvdpsxws v%u,v%u\n", (UInt)XT, (UInt)XB);
12424 putVSReg( XT,
sewardj4aa412a2011-07-24 14:13:21 +000012425 binop( Iop_64HLtoV128,
12426 unop( Iop_32Sto64,
12427 binop( Iop_F64toI32S,
12428 mkU32( Irrm_ZERO ),
sewardje71e56a2011-09-05 12:11:06 +000012429 mkexpr( xB ) ) ),
12430 mkU64( 0ULL ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000012431 break;
sewardje71e56a2011-09-05 12:11:06 +000012432 case 0x290: // xscvdpuxds (VSX Scalar truncate Double-Precision integer and Convert
12433 // to Unsigned Integer Doubleword format with Saturate)
12434 DIP("xscvdpuxds v%u,v%u\n", (UInt)XT, (UInt)XB);
12435 putVSReg( XT,
sewardj4aa412a2011-07-24 14:13:21 +000012436 binop( Iop_64HLtoV128,
12437 binop( Iop_F64toI64U,
12438 mkU32( Irrm_ZERO ),
sewardje71e56a2011-09-05 12:11:06 +000012439 mkexpr( xB ) ),
12440 mkU64( 0ULL ) ) );
12441 break;
carll6c758b62013-10-03 21:38:45 +000012442 case 0x270:
12443 // xscvsxdsp (VSX Scalar Convert and round Signed Integer Doubleword
12444 // to Single-Precision format)
12445 DIP("xscvsxdsp v%u,v%u\n", (UInt)XT, (UInt)XB);
12446 putVSReg( XT,
12447 binop( Iop_64HLtoV128,
12448 unop( Iop_ReinterpF64asI64,
12449 binop( Iop_RoundF64toF32,
12450 get_IR_roundingmode(),
12451 binop( Iop_I64StoF64,
12452 get_IR_roundingmode(),
12453 mkexpr( xB ) ) ) ),
12454 mkU64( 0 ) ) );
12455 break;
sewardje71e56a2011-09-05 12:11:06 +000012456 case 0x2F0:
12457 // xscvsxddp (VSX Scalar Convert and round Signed Integer Doubleword to
12458 // Double-Precision format)
12459 DIP("xscvsxddp v%u,v%u\n", (UInt)XT, (UInt)XB);
12460 putVSReg( XT,
sewardj66d5ef22011-04-15 11:55:00 +000012461 binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
sewardj4aa412a2011-07-24 14:13:21 +000012462 binop( Iop_I64StoF64, get_IR_roundingmode(),
sewardje71e56a2011-09-05 12:11:06 +000012463 mkexpr( xB ) ) ),
12464 mkU64( 0 ) ) );
12465 break;
carll6c758b62013-10-03 21:38:45 +000012466 case 0x250:
12467 // xscvuxdsp (VSX Scalar Convert and round Unsigned Integer
12468 // Doubleword to Singel-Precision format)
12469 DIP("xscvuxdsp v%u,v%u\n", (UInt)XT, (UInt)XB);
12470 putVSReg( XT,
12471 binop( Iop_64HLtoV128,
12472 unop( Iop_ReinterpF64asI64,
12473 binop( Iop_RoundF64toF32,
12474 get_IR_roundingmode(),
12475 binop( Iop_I64UtoF64,
12476 get_IR_roundingmode(),
12477 mkexpr( xB ) ) ) ),
12478 mkU64( 0 ) ) );
12479 break;
sewardje71e56a2011-09-05 12:11:06 +000012480 case 0x2D0:
12481 // xscvuxddp (VSX Scalar Convert and round Unsigned Integer Doubleword to
12482 // Double-Precision format)
12483 DIP("xscvuxddp v%u,v%u\n", (UInt)XT, (UInt)XB);
12484 putVSReg( XT,
sewardj66d5ef22011-04-15 11:55:00 +000012485 binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
sewardj4aa412a2011-07-24 14:13:21 +000012486 binop( Iop_I64UtoF64, get_IR_roundingmode(),
sewardje71e56a2011-09-05 12:11:06 +000012487 mkexpr( xB ) ) ),
12488 mkU64( 0 ) ) );
12489 break;
12490 case 0x1b0: // xvcvdpsxws (VSX Vector truncate Double-Precision to integer and Convert
12491 // to Signed Integer Word format with Saturate)
12492 {
12493 IRTemp hiResult_32 = newTemp(Ity_I32);
12494 IRTemp loResult_32 = newTemp(Ity_I32);
12495 IRExpr* rmZero = mkU32(Irrm_ZERO);
sewardj66d5ef22011-04-15 11:55:00 +000012496
sewardje71e56a2011-09-05 12:11:06 +000012497 DIP("xvcvdpsxws v%u,v%u\n", (UInt)XT, (UInt)XB);
12498 assign(hiResult_32, binop(Iop_F64toI32S, rmZero, mkexpr(xB)));
12499 assign(loResult_32, binop(Iop_F64toI32S, rmZero, mkexpr(xB2)));
12500 putVSReg( XT,
sewardj4aa412a2011-07-24 14:13:21 +000012501 binop( Iop_64HLtoV128,
12502 unop( Iop_32Sto64, mkexpr( hiResult_32 ) ),
12503 unop( Iop_32Sto64, mkexpr( loResult_32 ) ) ) );
sewardje71e56a2011-09-05 12:11:06 +000012504 break;
12505 }
12506 case 0x130: case 0x110: // xvcvspsxws, xvcvspuxws
12507 // (VSX Vector truncate Single-Precision to integer and
12508 // Convert to [Un]signed Integer Word format with Saturate)
12509 {
12510 IRExpr * b0_result, * b1_result, * b2_result, * b3_result;
12511 IRTemp tempResult = newTemp(Ity_V128);
12512 IRTemp res0 = newTemp(Ity_I32);
12513 IRTemp res1 = newTemp(Ity_I32);
12514 IRTemp res2 = newTemp(Ity_I32);
12515 IRTemp res3 = newTemp(Ity_I32);
12516 IRTemp hi64 = newTemp(Ity_I64);
12517 IRTemp lo64 = newTemp(Ity_I64);
12518 Bool un_signed = (opc2 == 0x110);
12519 IROp op = un_signed ? Iop_QFtoI32Ux4_RZ : Iop_QFtoI32Sx4_RZ;
sewardj4aa412a2011-07-24 14:13:21 +000012520
sewardje71e56a2011-09-05 12:11:06 +000012521 DIP("xvcvsp%sxws v%u,v%u\n", un_signed ? "u" : "s", (UInt)XT, (UInt)XB);
12522 /* The xvcvsp{s|u}xws instruction is similar to vct{s|u}xs, except if src is a NaN,
12523 * then result is set to 0x80000000. */
12524 assign(tempResult, unop(op, getVSReg(XB)));
12525 assign( hi64, unop(Iop_V128HIto64, mkexpr(tempResult)) );
12526 assign( lo64, unop(Iop_V128to64, mkexpr(tempResult)) );
12527 assign( res3, unop(Iop_64HIto32, mkexpr(hi64)) );
12528 assign( res2, unop(Iop_64to32, mkexpr(hi64)) );
12529 assign( res1, unop(Iop_64HIto32, mkexpr(lo64)) );
12530 assign( res0, unop(Iop_64to32, mkexpr(lo64)) );
sewardj4aa412a2011-07-24 14:13:21 +000012531
florian99dd03e2013-01-29 03:56:06 +000012532 b3_result = IRExpr_ITE(is_NaN_32(b3),
12533 // then: result is 0x{8|0}80000000
12534 mkU32(un_signed ? 0x00000000 : 0x80000000),
12535 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
12536 mkexpr(res3));
12537 b2_result = IRExpr_ITE(is_NaN_32(b2),
12538 // then: result is 0x{8|0}80000000
12539 mkU32(un_signed ? 0x00000000 : 0x80000000),
12540 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
12541 mkexpr(res2));
12542 b1_result = IRExpr_ITE(is_NaN_32(b1),
12543 // then: result is 0x{8|0}80000000
12544 mkU32(un_signed ? 0x00000000 : 0x80000000),
12545 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
12546 mkexpr(res1));
12547 b0_result = IRExpr_ITE(is_NaN_32(b0),
12548 // then: result is 0x{8|0}80000000
12549 mkU32(un_signed ? 0x00000000 : 0x80000000),
12550 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
12551 mkexpr(res0));
sewardj4aa412a2011-07-24 14:13:21 +000012552
sewardje71e56a2011-09-05 12:11:06 +000012553 putVSReg( XT,
sewardj4aa412a2011-07-24 14:13:21 +000012554 binop( Iop_64HLtoV128,
12555 binop( Iop_32HLto64, b3_result, b2_result ),
12556 binop( Iop_32HLto64, b1_result, b0_result ) ) );
sewardje71e56a2011-09-05 12:11:06 +000012557 break;
12558 }
12559 case 0x212: // xscvdpsp (VSX Scalar round Double-Precision to single-precision and
12560 // Convert to Single-Precision format
12561 DIP("xscvdpsp v%u,v%u\n", (UInt)XT, (UInt)XB);
12562 putVSReg( XT,
12563 binop( Iop_64HLtoV128,
12564 binop( Iop_32HLto64,
12565 unop( Iop_ReinterpF32asI32,
12566 unop( Iop_TruncF64asF32,
12567 binop( Iop_RoundF64toF32,
12568 get_IR_roundingmode(),
12569 mkexpr( xB ) ) ) ),
12570 mkU32( 0 ) ),
12571 mkU64( 0ULL ) ) );
12572 break;
carll0c74bb52013-08-12 18:01:40 +000012573 case 0x216: /* xscvdpspn (VSX Scalar convert scalar Single-Precision to
carll6c758b62013-10-03 21:38:45 +000012574 vector Single-Precision non-signalling */
carll0c74bb52013-08-12 18:01:40 +000012575 DIP("xscvdpspn v%u,v%u\n", (UInt)XT, (UInt)XB);
12576 putVSReg( XT,
12577 binop( Iop_64HLtoV128,
12578 binop( Iop_32HLto64,
12579 unop( Iop_ReinterpF32asI32,
12580 unop( Iop_TruncF64asF32,
12581 mkexpr( xB ) ) ),
carll6c758b62013-10-03 21:38:45 +000012582 mkU32( 0 ) ),
12583 mkU64( 0ULL ) ) );
carll0c74bb52013-08-12 18:01:40 +000012584 break;
sewardje71e56a2011-09-05 12:11:06 +000012585 case 0x090: // xscvdpuxws (VSX Scalar truncate Double-Precision to integer
12586 // and Convert to Unsigned Integer Word format with Saturate)
12587 DIP("xscvdpuxws v%u,v%u\n", (UInt)XT, (UInt)XB);
12588 putVSReg( XT,
12589 binop( Iop_64HLtoV128,
12590 binop( Iop_32HLto64,
12591 mkU32( 0 ),
12592 binop( Iop_F64toI32U,
12593 mkU32( Irrm_ZERO ),
12594 mkexpr( xB ) ) ),
12595 mkU64( 0ULL ) ) );
12596 break;
carll6c758b62013-10-03 21:38:45 +000012597 case 0x292: // xscvspdp (VSX Scalar Convert Single-Precision to Double-Precision format, signaling)
sewardje71e56a2011-09-05 12:11:06 +000012598 DIP("xscvspdp v%u,v%u\n", (UInt)XT, (UInt)XB);
12599 putVSReg( XT,
12600 binop( Iop_64HLtoV128,
12601 unop( Iop_ReinterpF64asI64,
12602 unop( Iop_F32toF64,
12603 unop( Iop_ReinterpI32asF32, mkexpr( xB ) ) ) ),
12604 mkU64( 0ULL ) ) );
12605 break;
carll0c74bb52013-08-12 18:01:40 +000012606 case 0x296: // xscvspdpn (VSX Scalar Convert Single-Precision to Double-Precision format Non signaling)
12607 DIP("xscvspdpn v%u,v%u\n", (UInt)XT, (UInt)XB);
12608 putVSReg( XT,
12609 binop( Iop_64HLtoV128,
12610 unop( Iop_ReinterpF64asI64,
12611 unop( Iop_F32toF64,
12612 unop( Iop_ReinterpI32asF32, mkexpr( xB ) ) ) ),
12613 mkU64( 0ULL ) ) );
12614 break;
sewardje71e56a2011-09-05 12:11:06 +000012615 case 0x312: // xvcvdpsp (VSX Vector round Double-Precision to single-precision
12616 // and Convert to Single-Precision format)
12617 DIP("xvcvdpsp v%u,v%u\n", (UInt)XT, (UInt)XB);
12618 putVSReg( XT,
12619 binop( Iop_64HLtoV128,
12620 binop( Iop_32HLto64,
12621 unop( Iop_ReinterpF32asI32,
12622 unop( Iop_TruncF64asF32,
12623 binop( Iop_RoundF64toF32,
12624 get_IR_roundingmode(),
12625 mkexpr( xB ) ) ) ),
12626 mkU32( 0 ) ),
12627 binop( Iop_32HLto64,
12628 unop( Iop_ReinterpF32asI32,
12629 unop( Iop_TruncF64asF32,
12630 binop( Iop_RoundF64toF32,
12631 get_IR_roundingmode(),
12632 mkexpr( xB2 ) ) ) ),
12633 mkU32( 0 ) ) ) );
12634 break;
12635 case 0x390: // xvcvdpuxds (VSX Vector truncate Double-Precision to integer
12636 // and Convert to Unsigned Integer Doubleword format
12637 // with Saturate)
12638 DIP("xvcvdpuxds v%u,v%u\n", (UInt)XT, (UInt)XB);
12639 putVSReg( XT,
12640 binop( Iop_64HLtoV128,
12641 binop( Iop_F64toI64U, mkU32( Irrm_ZERO ), mkexpr( xB ) ),
12642 binop( Iop_F64toI64U, mkU32( Irrm_ZERO ), mkexpr( xB2 ) ) ) );
12643 break;
12644 case 0x190: // xvcvdpuxws (VSX Vector truncate Double-Precision to integer and
12645 // Convert to Unsigned Integer Word format with Saturate)
12646 DIP("xvcvdpuxws v%u,v%u\n", (UInt)XT, (UInt)XB);
12647 putVSReg( XT,
12648 binop( Iop_64HLtoV128,
12649 binop( Iop_32HLto64,
12650 binop( Iop_F64toI32U,
12651 mkU32( Irrm_ZERO ),
12652 mkexpr( xB ) ),
12653 mkU32( 0 ) ),
12654 binop( Iop_32HLto64,
12655 binop( Iop_F64toI32U,
12656 mkU32( Irrm_ZERO ),
12657 mkexpr( xB2 ) ),
12658 mkU32( 0 ) ) ) );
12659 break;
12660 case 0x392: // xvcvspdp (VSX Vector Convert Single-Precision to Double-Precision format)
12661 DIP("xvcvspdp v%u,v%u\n", (UInt)XT, (UInt)XB);
12662 putVSReg( XT,
12663 binop( Iop_64HLtoV128,
12664 unop( Iop_ReinterpF64asI64,
12665 unop( Iop_F32toF64,
carll6fef87a2013-09-12 17:26:42 +000012666 unop( Iop_ReinterpI32asF32,
12667 handle_SNaN_to_QNaN_32( mkexpr( b3 ) ) ) ) ),
sewardje71e56a2011-09-05 12:11:06 +000012668 unop( Iop_ReinterpF64asI64,
12669 unop( Iop_F32toF64,
carll6fef87a2013-09-12 17:26:42 +000012670 unop( Iop_ReinterpI32asF32,
12671 handle_SNaN_to_QNaN_32( mkexpr( b1 ) ) ) ) ) ) );
sewardje71e56a2011-09-05 12:11:06 +000012672 break;
12673 case 0x330: // xvcvspsxds (VSX Vector truncate Single-Precision to integer and
12674 // Convert to Signed Integer Doubleword format with Saturate)
12675 DIP("xvcvspsxds v%u,v%u\n", (UInt)XT, (UInt)XB);
12676 putVSReg( XT,
12677 binop( Iop_64HLtoV128,
12678 binop( Iop_F64toI64S,
12679 mkU32( Irrm_ZERO ),
12680 unop( Iop_F32toF64,
12681 unop( Iop_ReinterpI32asF32, mkexpr( b3 ) ) ) ),
12682 binop( Iop_F64toI64S,
12683 mkU32( Irrm_ZERO ),
12684 unop( Iop_F32toF64,
12685 unop( Iop_ReinterpI32asF32, mkexpr( b1 ) ) ) ) ) );
12686 break;
12687 case 0x310: // xvcvspuxds (VSX Vector truncate Single-Precision to integer and
12688 // Convert to Unsigned Integer Doubleword format with Saturate)
12689 DIP("xvcvspuxds v%u,v%u\n", (UInt)XT, (UInt)XB);
12690 putVSReg( XT,
12691 binop( Iop_64HLtoV128,
12692 binop( Iop_F64toI64U,
12693 mkU32( Irrm_ZERO ),
12694 unop( Iop_F32toF64,
12695 unop( Iop_ReinterpI32asF32, mkexpr( b3 ) ) ) ),
12696 binop( Iop_F64toI64U,
12697 mkU32( Irrm_ZERO ),
12698 unop( Iop_F32toF64,
12699 unop( Iop_ReinterpI32asF32, mkexpr( b1 ) ) ) ) ) );
12700 break;
12701 case 0x3B0: // xvcvdpsxds (VSX Vector truncate Double-Precision to integer and
12702 // Convert to Signed Integer Doubleword format with Saturate)
12703 DIP("xvcvdpsxds v%u,v%u\n", (UInt)XT, (UInt)XB);
12704 putVSReg( XT,
12705 binop( Iop_64HLtoV128,
12706 binop( Iop_F64toI64S, mkU32( Irrm_ZERO ), mkexpr( xB ) ),
12707 binop( Iop_F64toI64S, mkU32( Irrm_ZERO ), mkexpr( xB2 ) ) ) );
12708 break;
12709 case 0x3f0: // xvcvsxddp (VSX Vector Convert and round Signed Integer Doubleword
12710 // to Double-Precision format)
12711 DIP("xvcvsxddp v%u,v%u\n", (UInt)XT, (UInt)XB);
12712 putVSReg( XT,
12713 binop( Iop_64HLtoV128,
12714 unop( Iop_ReinterpF64asI64,
12715 binop( Iop_I64StoF64,
12716 get_IR_roundingmode(),
12717 mkexpr( xB ) ) ),
12718 unop( Iop_ReinterpF64asI64,
12719 binop( Iop_I64StoF64,
12720 get_IR_roundingmode(),
12721 mkexpr( xB2 ) ) ) ) );
12722 break;
12723 case 0x3d0: // xvcvuxddp (VSX Vector Convert and round Unsigned Integer Doubleword
12724 // to Double-Precision format)
12725 DIP("xvcvuxddp v%u,v%u\n", (UInt)XT, (UInt)XB);
12726 putVSReg( XT,
12727 binop( Iop_64HLtoV128,
12728 unop( Iop_ReinterpF64asI64,
12729 binop( Iop_I64UtoF64,
12730 get_IR_roundingmode(),
12731 mkexpr( xB ) ) ),
12732 unop( Iop_ReinterpF64asI64,
12733 binop( Iop_I64UtoF64,
12734 get_IR_roundingmode(),
12735 mkexpr( xB2 ) ) ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000012736
sewardje71e56a2011-09-05 12:11:06 +000012737 break;
12738 case 0x370: // xvcvsxdsp (VSX Vector Convert and round Signed Integer Doubleword
12739 // to Single-Precision format)
12740 DIP("xvcvsxddp v%u,v%u\n", (UInt)XT, (UInt)XB);
12741 putVSReg( XT,
12742 binop( Iop_64HLtoV128,
12743 binop( Iop_32HLto64,
12744 unop( Iop_ReinterpF32asI32,
12745 unop( Iop_TruncF64asF32,
12746 binop( Iop_RoundF64toF32,
12747 get_IR_roundingmode(),
12748 binop( Iop_I64StoF64,
12749 get_IR_roundingmode(),
12750 mkexpr( xB ) ) ) ) ),
12751 mkU32( 0 ) ),
12752 binop( Iop_32HLto64,
12753 unop( Iop_ReinterpF32asI32,
12754 unop( Iop_TruncF64asF32,
12755 binop( Iop_RoundF64toF32,
12756 get_IR_roundingmode(),
12757 binop( Iop_I64StoF64,
12758 get_IR_roundingmode(),
12759 mkexpr( xB2 ) ) ) ) ),
12760 mkU32( 0 ) ) ) );
12761 break;
12762 case 0x350: // xvcvuxdsp (VSX Vector Convert and round Unsigned Integer Doubleword
12763 // to Single-Precision format)
12764 DIP("xvcvuxddp v%u,v%u\n", (UInt)XT, (UInt)XB);
12765 putVSReg( XT,
12766 binop( Iop_64HLtoV128,
12767 binop( Iop_32HLto64,
12768 unop( Iop_ReinterpF32asI32,
12769 unop( Iop_TruncF64asF32,
12770 binop( Iop_RoundF64toF32,
12771 get_IR_roundingmode(),
12772 binop( Iop_I64UtoF64,
12773 get_IR_roundingmode(),
12774 mkexpr( xB ) ) ) ) ),
12775 mkU32( 0 ) ),
12776 binop( Iop_32HLto64,
12777 unop( Iop_ReinterpF32asI32,
12778 unop( Iop_TruncF64asF32,
12779 binop( Iop_RoundF64toF32,
12780 get_IR_roundingmode(),
12781 binop( Iop_I64UtoF64,
12782 get_IR_roundingmode(),
12783 mkexpr( xB2 ) ) ) ) ),
12784 mkU32( 0 ) ) ) );
12785 break;
12786
12787 case 0x1f0: // xvcvsxwdp (VSX Vector Convert Signed Integer Word to Double-Precision format)
12788 DIP("xvcvsxwdp v%u,v%u\n", (UInt)XT, (UInt)XB);
12789 putVSReg( XT,
12790 binop( Iop_64HLtoV128,
12791 unop( Iop_ReinterpF64asI64,
12792 binop( Iop_I64StoF64, get_IR_roundingmode(),
12793 unop( Iop_32Sto64, mkexpr( b3 ) ) ) ),
12794 unop( Iop_ReinterpF64asI64,
12795 binop( Iop_I64StoF64, get_IR_roundingmode(),
12796 unop( Iop_32Sto64, mkexpr( b1 ) ) ) ) ) );
12797 break;
12798 case 0x1d0: // xvcvuxwdp (VSX Vector Convert Unsigned Integer Word to Double-Precision format)
12799 DIP("xvcvuxwdp v%u,v%u\n", (UInt)XT, (UInt)XB);
12800 putVSReg( XT,
12801 binop( Iop_64HLtoV128,
12802 unop( Iop_ReinterpF64asI64,
12803 binop( Iop_I64UtoF64, get_IR_roundingmode(),
12804 unop( Iop_32Uto64, mkexpr( b3 ) ) ) ),
12805 unop( Iop_ReinterpF64asI64,
12806 binop( Iop_I64UtoF64, get_IR_roundingmode(),
12807 unop( Iop_32Uto64, mkexpr( b1 ) ) ) ) ) );
12808 break;
12809 case 0x170: // xvcvsxwsp (VSX Vector Convert Signed Integer Word to Single-Precision format)
12810 DIP("xvcvsxwsp v%u,v%u\n", (UInt)XT, (UInt)XB);
12811 putVSReg( XT, unop( Iop_I32StoFx4, getVSReg( XB ) ) );
12812 break;
12813 case 0x150: // xvcvuxwsp (VSX Vector Convert Unsigned Integer Word to Single-Precision format)
12814 DIP("xvcvuxwsp v%u,v%u\n", (UInt)XT, (UInt)XB);
12815 putVSReg( XT, unop( Iop_I32UtoFx4, getVSReg( XB ) ) );
12816 break;
12817
12818 default:
12819 vex_printf( "dis_vx_conv(ppc)(opc2)\n" );
12820 return False;
sewardj66d5ef22011-04-15 11:55:00 +000012821 }
12822 return True;
12823}
12824
12825/*
sewardj4aa412a2011-07-24 14:13:21 +000012826 * VSX vector Double Precision Floating Point Arithmetic Instructions
12827 */
12828static Bool
12829dis_vxv_dp_arith ( UInt theInstr, UInt opc2 )
12830{
12831 /* XX3-Form */
12832 UChar opc1 = ifieldOPC( theInstr );
12833 UChar XT = ifieldRegXT( theInstr );
12834 UChar XA = ifieldRegXA( theInstr );
12835 UChar XB = ifieldRegXB( theInstr );
12836 IRExpr* rm = get_IR_roundingmode();
12837 IRTemp frA = newTemp(Ity_F64);
12838 IRTemp frB = newTemp(Ity_F64);
12839 IRTemp frA2 = newTemp(Ity_F64);
12840 IRTemp frB2 = newTemp(Ity_F64);
12841
12842 if (opc1 != 0x3C) {
12843 vex_printf( "dis_vxv_dp_arith(ppc)(instr)\n" );
12844 return False;
12845 }
12846
12847 assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
12848 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
12849 assign(frA2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg( XA ))));
12850 assign(frB2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg( XB ))));
12851
12852 switch (opc2) {
12853 case 0x1E0: // xvdivdp (VSX Vector Divide Double-Precision)
12854 case 0x1C0: // xvmuldp (VSX Vector Multiply Double-Precision)
12855 case 0x180: // xvadddp (VSX Vector Add Double-Precision)
12856 case 0x1A0: // xvsubdp (VSX Vector Subtract Double-Precision)
12857 {
12858 IROp mOp;
florian55085f82012-11-21 00:36:55 +000012859 const HChar * oper_name;
sewardj4aa412a2011-07-24 14:13:21 +000012860 switch (opc2) {
12861 case 0x1E0:
12862 mOp = Iop_DivF64;
12863 oper_name = "div";
12864 break;
12865 case 0x1C0:
12866 mOp = Iop_MulF64;
12867 oper_name = "mul";
12868 break;
12869 case 0x180:
12870 mOp = Iop_AddF64;
12871 oper_name = "add";
12872 break;
12873 case 0x1A0:
12874 mOp = Iop_SubF64;
12875 oper_name = "sub";
12876 break;
12877
12878 default:
12879 vpanic("The impossible happened: dis_vxv_dp_arith(ppc)");
12880 }
12881 IRTemp hiResult = newTemp(Ity_I64);
12882 IRTemp loResult = newTemp(Ity_I64);
12883 DIP("xv%sdp v%d,v%d,v%d\n", oper_name, (UInt)XT, (UInt)XA, (UInt)XB);
12884
12885 assign( hiResult,
12886 unop( Iop_ReinterpF64asI64,
12887 triop( mOp, rm, mkexpr( frA ), mkexpr( frB ) ) ) );
12888 assign( loResult,
12889 unop( Iop_ReinterpF64asI64,
12890 triop( mOp, rm, mkexpr( frA2 ), mkexpr( frB2 ) ) ) );
12891 putVSReg( XT,
12892 binop( Iop_64HLtoV128, mkexpr( hiResult ), mkexpr( loResult ) ) );
12893 break;
12894 }
sewardje71e56a2011-09-05 12:11:06 +000012895 case 0x196: // xvsqrtdp
12896 {
12897 IRTemp hiResult = newTemp(Ity_I64);
12898 IRTemp loResult = newTemp(Ity_I64);
12899 DIP("xvsqrtdp v%d,v%d\n", (UInt)XT, (UInt)XB);
sewardj4aa412a2011-07-24 14:13:21 +000012900
sewardje71e56a2011-09-05 12:11:06 +000012901 assign( hiResult,
12902 unop( Iop_ReinterpF64asI64,
12903 binop( Iop_SqrtF64, rm, mkexpr( frB ) ) ) );
12904 assign( loResult,
12905 unop( Iop_ReinterpF64asI64,
12906 binop( Iop_SqrtF64, rm, mkexpr( frB2 ) ) ) );
12907 putVSReg( XT,
12908 binop( Iop_64HLtoV128, mkexpr( hiResult ), mkexpr( loResult ) ) );
12909 break;
12910 }
sewardj4aa412a2011-07-24 14:13:21 +000012911 case 0x184: case 0x1A4: // xvmaddadp, xvmaddmdp (VSX Vector Multiply-Add Double-Precision)
12912 case 0x1C4: case 0x1E4: // xvmsubadp, xvmsubmdp (VSX Vector Multiply-Subtract Double-Precision)
12913 case 0x384: case 0x3A4: // xvnmaddadp, xvnmaddmdp (VSX Vector Negate Multiply-Add Double-Precision)
12914 case 0x3C4: case 0x3E4: // xvnmsubadp, xvnmsubmdp (VSX Vector Negate Multiply-Subtract Double-Precision)
12915 {
12916 /* xvm{add|sub}mdp XT,XA,XB is element-wise equivalent to fm{add|sub} FRT,FRA,FRC,FRB with . . .
12917 * XT == FRC
12918 * XA == FRA
12919 * XB == FRB
12920 *
12921 * and for xvm{add|sub}adp . . .
12922 * XT == FRB
12923 * XA == FRA
12924 * XB == FRC
12925 */
12926 Bool negate;
12927 IROp mOp = Iop_INVALID;
florian55085f82012-11-21 00:36:55 +000012928 const HChar * oper_name = NULL;
sewardj4aa412a2011-07-24 14:13:21 +000012929 Bool mdp = False;
12930
12931 switch (opc2) {
12932 case 0x184: case 0x1A4:
12933 case 0x384: case 0x3A4:
12934 mOp = Iop_MAddF64;
12935 oper_name = "add";
12936 mdp = (opc2 & 0x0FF) == 0x0A4;
12937 break;
12938
12939 case 0x1C4: case 0x1E4:
12940 case 0x3C4: case 0x3E4:
12941 mOp = Iop_MSubF64;
12942 oper_name = "sub";
12943 mdp = (opc2 & 0x0FF) == 0x0E4;
12944 break;
12945
12946 default:
12947 vpanic("The impossible happened: dis_vxv_sp_arith(ppc)");
12948 }
12949
12950 switch (opc2) {
12951 case 0x384: case 0x3A4:
12952 case 0x3C4: case 0x3E4:
12953 negate = True;
12954 break;
12955 default:
12956 negate = False;
12957 }
12958 IRTemp hiResult = newTemp(Ity_I64);
12959 IRTemp loResult = newTemp(Ity_I64);
12960 IRTemp frT = newTemp(Ity_F64);
12961 IRTemp frT2 = newTemp(Ity_F64);
12962 DIP("xv%sm%s%s v%d,v%d,v%d\n", negate ? "n" : "", oper_name, mdp ? "mdp" : "adp",
12963 (UInt)XT, (UInt)XA, (UInt)XB);
12964 assign(frT, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XT ) ) ) );
12965 assign(frT2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg( XT ) ) ) );
12966
12967 assign( hiResult,
12968 unop( Iop_ReinterpF64asI64,
12969 qop( mOp,
12970 rm,
12971 mkexpr( frA ),
12972 mkexpr( mdp ? frT : frB ),
12973 mkexpr( mdp ? frB : frT ) ) ) );
12974 assign( loResult,
12975 unop( Iop_ReinterpF64asI64,
12976 qop( mOp,
12977 rm,
12978 mkexpr( frA2 ),
12979 mkexpr( mdp ? frT2 : frB2 ),
12980 mkexpr( mdp ? frB2 : frT2 ) ) ) );
12981 putVSReg( XT,
12982 binop( Iop_64HLtoV128,
12983 mkexpr( negate ? getNegatedResult( hiResult )
12984 : hiResult ),
12985 mkexpr( negate ? getNegatedResult( loResult )
12986 : loResult ) ) );
12987 break;
12988 }
sewardje71e56a2011-09-05 12:11:06 +000012989 case 0x1D4: // xvtsqrtdp (VSX Vector Test for software Square Root Double-Precision)
12990 {
12991 IRTemp frBHi_I64 = newTemp(Ity_I64);
12992 IRTemp frBLo_I64 = newTemp(Ity_I64);
12993 IRTemp flagsHi = newTemp(Ity_I32);
12994 IRTemp flagsLo = newTemp(Ity_I32);
12995 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
12996 IRTemp fe_flagHi, fg_flagHi, fe_flagLo, fg_flagLo;
12997 fe_flagHi = fg_flagHi = fe_flagLo = fg_flagLo = IRTemp_INVALID;
12998
12999 DIP("xvtsqrtdp cr%d,v%d\n", (UInt)crfD, (UInt)XB);
13000 assign( frBHi_I64, unop(Iop_V128HIto64, getVSReg( XB )) );
13001 assign( frBLo_I64, unop(Iop_V128to64, getVSReg( XB )) );
13002 do_fp_tsqrt(frBHi_I64, False /*not single precision*/, &fe_flagHi, &fg_flagHi);
13003 do_fp_tsqrt(frBLo_I64, False /*not single precision*/, &fe_flagLo, &fg_flagLo);
13004 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
13005 * where fl_flag == 1 on ppc64.
13006 */
13007 assign( flagsHi,
13008 binop( Iop_Or32,
13009 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13010 binop( Iop_Shl32, mkexpr(fg_flagHi), mkU8( 2 ) ) ),
13011 binop( Iop_Shl32, mkexpr(fe_flagHi), mkU8( 1 ) ) ) );
13012 assign( flagsLo,
13013 binop( Iop_Or32,
13014 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13015 binop( Iop_Shl32, mkexpr(fg_flagLo), mkU8( 2 ) ) ),
13016 binop( Iop_Shl32, mkexpr(fe_flagLo), mkU8( 1 ) ) ) );
13017 putGST_field( PPC_GST_CR,
13018 binop( Iop_Or32, mkexpr( flagsHi ), mkexpr( flagsLo ) ),
13019 crfD );
13020 break;
13021 }
13022 case 0x1F4: // xvtdivdp (VSX Vector Test for software Divide Double-Precision)
13023 {
13024 IRTemp frBHi_I64 = newTemp(Ity_I64);
13025 IRTemp frBLo_I64 = newTemp(Ity_I64);
13026 IRTemp frAHi_I64 = newTemp(Ity_I64);
13027 IRTemp frALo_I64 = newTemp(Ity_I64);
13028 IRTemp flagsHi = newTemp(Ity_I32);
13029 IRTemp flagsLo = newTemp(Ity_I32);
13030 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
13031 IRTemp fe_flagHi, fg_flagHi, fe_flagLo, fg_flagLo;
13032 fe_flagHi = fg_flagHi = fe_flagLo = fg_flagLo = IRTemp_INVALID;
13033
13034 DIP("xvtdivdp cr%d,v%d,v%d\n", (UInt)crfD, (UInt)XA, (UInt)XB);
13035 assign( frAHi_I64, unop(Iop_V128HIto64, getVSReg( XA )) );
13036 assign( frALo_I64, unop(Iop_V128to64, getVSReg( XA )) );
13037 assign( frBHi_I64, unop(Iop_V128HIto64, getVSReg( XB )) );
13038 assign( frBLo_I64, unop(Iop_V128to64, getVSReg( XB )) );
13039
13040 _do_fp_tdiv(frAHi_I64, frBHi_I64, False/*dp*/, &fe_flagHi, &fg_flagHi);
13041 _do_fp_tdiv(frALo_I64, frBLo_I64, False/*dp*/, &fe_flagLo, &fg_flagLo);
13042 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
13043 * where fl_flag == 1 on ppc64.
13044 */
13045 assign( flagsHi,
13046 binop( Iop_Or32,
13047 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13048 binop( Iop_Shl32, mkexpr(fg_flagHi), mkU8( 2 ) ) ),
13049 binop( Iop_Shl32, mkexpr(fe_flagHi), mkU8( 1 ) ) ) );
13050 assign( flagsLo,
13051 binop( Iop_Or32,
13052 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13053 binop( Iop_Shl32, mkexpr(fg_flagLo), mkU8( 2 ) ) ),
13054 binop( Iop_Shl32, mkexpr(fe_flagLo), mkU8( 1 ) ) ) );
13055 putGST_field( PPC_GST_CR,
13056 binop( Iop_Or32, mkexpr( flagsHi ), mkexpr( flagsLo ) ),
13057 crfD );
13058 break;
13059 }
sewardj4aa412a2011-07-24 14:13:21 +000013060
13061 default:
13062 vex_printf( "dis_vxv_dp_arith(ppc)(opc2)\n" );
13063 return False;
13064 }
13065 return True;
13066}
13067
13068/*
13069 * VSX vector Single Precision Floating Point Arithmetic Instructions
13070 */
13071static Bool
13072dis_vxv_sp_arith ( UInt theInstr, UInt opc2 )
13073{
13074 /* XX3-Form */
13075 UChar opc1 = ifieldOPC( theInstr );
13076 UChar XT = ifieldRegXT( theInstr );
13077 UChar XA = ifieldRegXA( theInstr );
13078 UChar XB = ifieldRegXB( theInstr );
13079 IRExpr* rm = get_IR_roundingmode();
13080 IRTemp a3, a2, a1, a0;
13081 IRTemp b3, b2, b1, b0;
13082 IRTemp res0 = newTemp(Ity_I32);
13083 IRTemp res1 = newTemp(Ity_I32);
13084 IRTemp res2 = newTemp(Ity_I32);
13085 IRTemp res3 = newTemp(Ity_I32);
13086
13087 a3 = a2 = a1 = a0 = IRTemp_INVALID;
13088 b3 = b2 = b1 = b0 = IRTemp_INVALID;
13089
13090 if (opc1 != 0x3C) {
13091 vex_printf( "dis_vxv_sp_arith(ppc)(instr)\n" );
13092 return False;
13093 }
13094
13095 switch (opc2) {
13096 case 0x100: // xvaddsp (VSX Vector Add Single-Precision)
13097 DIP("xvaddsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
sewardj20a760e2014-05-05 10:03:56 +000013098 // WARNING: BOGUS! The backend ignores rm on Iop_Add32Fx4
13099 putVSReg( XT, triop(Iop_Add32Fx4, rm,
13100 getVSReg( XA ), getVSReg( XB )) );
sewardj4aa412a2011-07-24 14:13:21 +000013101 break;
13102
13103 case 0x140: // xvmulsp (VSX Vector Multiply Single-Precision)
13104 DIP("xvmulsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
sewardj20a760e2014-05-05 10:03:56 +000013105 // WARNING: BOGUS! The backend ignores rm on Iop_Mul32Fx4
13106 putVSReg( XT, triop(Iop_Mul32Fx4, rm,
13107 getVSReg( XA ), getVSReg( XB )) );
sewardj4aa412a2011-07-24 14:13:21 +000013108 break;
13109
13110 case 0x120: // xvsubsp (VSX Vector Subtract Single-Precision)
13111 DIP("xvsubsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
sewardj20a760e2014-05-05 10:03:56 +000013112 // WARNING: BOGUS! The backend ignores rm on Iop_Sub32Fx4
13113 putVSReg( XT, triop(Iop_Sub32Fx4, rm,
13114 getVSReg( XA ), getVSReg( XB )) );
sewardj4aa412a2011-07-24 14:13:21 +000013115 break;
13116
13117 case 0x160: // xvdivsp (VSX Vector Divide Single-Precision)
13118 {
13119 /* Iop_Div32Fx4 is not implemented for ppc64 (in host_ppc_{isel|defs}.c.
13120 * So there are two choices:
13121 * 1. Implement the xvdivsp with a native insn; or
13122 * 2. Extract the 4 single precision floats from each vector
13123 * register inputs and perform fdivs on each pair
13124 * I will do the latter, due to the general philosophy of
13125 * reusing existing implementations when practical.
13126 */
13127 DIP("xvdivsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
13128 breakV128to4xF64( getVSReg( XA ), &a3, &a2, &a1, &a0 );
13129 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
13130
13131 assign( res0,
13132 unop( Iop_ReinterpF32asI32,
13133 unop( Iop_TruncF64asF32,
13134 triop( Iop_DivF64r32, rm, mkexpr( a0 ), mkexpr( b0 ) ) ) ) );
13135 assign( res1,
13136 unop( Iop_ReinterpF32asI32,
13137 unop( Iop_TruncF64asF32,
13138 triop( Iop_DivF64r32, rm, mkexpr( a1 ), mkexpr( b1 ) ) ) ) );
13139 assign( res2,
13140 unop( Iop_ReinterpF32asI32,
13141 unop( Iop_TruncF64asF32,
13142 triop( Iop_DivF64r32, rm, mkexpr( a2 ), mkexpr( b2 ) ) ) ) );
13143 assign( res3,
13144 unop( Iop_ReinterpF32asI32,
13145 unop( Iop_TruncF64asF32,
13146 triop( Iop_DivF64r32, rm, mkexpr( a3 ), mkexpr( b3 ) ) ) ) );
13147
13148 putVSReg( XT,
13149 binop( Iop_64HLtoV128,
13150 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
13151 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
13152 break;
13153 }
sewardje71e56a2011-09-05 12:11:06 +000013154 case 0x116: // xvsqrtsp (VSX Vector Square Root Single-Precision)
13155 {
13156 DIP("xvsqrtsp v%d,v%d\n", (UInt)XT, (UInt)XB);
13157 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
13158 /* Note: The native xvsqrtsp insruction does not always give the same precision
13159 * as what we get with Iop_SqrtF64. But it doesn't seem worthwhile to implement
13160 * an Iop_SqrtF32 that would give us a lower precision result, albeit more true
13161 * to the actual instruction.
13162 */
13163
13164 assign( res0,
13165 unop( Iop_ReinterpF32asI32,
13166 unop( Iop_TruncF64asF32,
13167 binop(Iop_SqrtF64, rm, mkexpr( b0 ) ) ) ) );
13168 assign( res1,
13169 unop( Iop_ReinterpF32asI32,
13170 unop( Iop_TruncF64asF32,
13171 binop(Iop_SqrtF64, rm, mkexpr( b1 ) ) ) ) );
13172 assign( res2,
13173 unop( Iop_ReinterpF32asI32,
13174 unop( Iop_TruncF64asF32,
13175 binop(Iop_SqrtF64, rm, mkexpr( b2) ) ) ) );
13176 assign( res3,
13177 unop( Iop_ReinterpF32asI32,
13178 unop( Iop_TruncF64asF32,
13179 binop(Iop_SqrtF64, rm, mkexpr( b3 ) ) ) ) );
13180
13181 putVSReg( XT,
13182 binop( Iop_64HLtoV128,
13183 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
13184 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
13185 break;
13186 }
sewardj4aa412a2011-07-24 14:13:21 +000013187
13188 case 0x104: case 0x124: // xvmaddasp, xvmaddmsp (VSX Vector Multiply-Add Single-Precision)
13189 case 0x144: case 0x164: // xvmsubasp, xvmsubmsp (VSX Vector Multiply-Subtract Single-Precision)
13190 case 0x304: case 0x324: // xvnmaddasp, xvnmaddmsp (VSX Vector Negate Multiply-Add Single-Precision)
13191 case 0x344: case 0x364: // xvnmsubasp, xvnmsubmsp (VSX Vector Negate Multiply-Subtract Single-Precision)
13192 {
13193 IRTemp t3, t2, t1, t0;
13194 Bool msp = False;
13195 Bool negate;
florian55085f82012-11-21 00:36:55 +000013196 const HChar * oper_name = NULL;
sewardj4aa412a2011-07-24 14:13:21 +000013197 IROp mOp = Iop_INVALID;
13198 switch (opc2) {
13199 case 0x104: case 0x124:
13200 case 0x304: case 0x324:
13201 msp = (opc2 & 0x0FF) == 0x024;
13202 mOp = Iop_MAddF64r32;
13203 oper_name = "madd";
13204 break;
13205
13206 case 0x144: case 0x164:
13207 case 0x344: case 0x364:
13208 msp = (opc2 & 0x0FF) == 0x064;
13209 mOp = Iop_MSubF64r32;
13210 oper_name = "sub";
13211 break;
13212
13213 default:
13214 vpanic("The impossible happened: dis_vxv_sp_arith(ppc)");
13215 }
13216
13217 switch (opc2) {
13218 case 0x304: case 0x324:
13219 case 0x344: case 0x364:
13220 negate = True;
13221 break;
13222
13223 default:
13224 negate = False;
13225 }
13226
13227 DIP("xv%sm%s%s v%d,v%d,v%d\n", negate ? "n" : "", oper_name, msp ? "msp" : "asp",
13228 (UInt)XT, (UInt)XA, (UInt)XB);
13229
13230 t3 = t2 = t1 = t0 = IRTemp_INVALID;
13231 breakV128to4xF64( getVSReg( XA ), &a3, &a2, &a1, &a0 );
13232 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
13233 breakV128to4xF64( getVSReg( XT ), &t3, &t2, &t1, &t0 );
13234
13235 assign( res0,
13236 unop( Iop_ReinterpF32asI32,
13237 unop( Iop_TruncF64asF32,
13238 qop( mOp,
13239 rm,
13240 mkexpr( a0 ),
13241 mkexpr( msp ? t0 : b0 ),
13242 mkexpr( msp ? b0 : t0 ) ) ) ) );
13243 assign( res1,
13244 unop( Iop_ReinterpF32asI32,
13245 unop( Iop_TruncF64asF32,
13246 qop( mOp,
13247 rm,
13248 mkexpr( a1 ),
13249 mkexpr( msp ? t1 : b1 ),
13250 mkexpr( msp ? b1 : t1 ) ) ) ) );
13251 assign( res2,
13252 unop( Iop_ReinterpF32asI32,
13253 unop( Iop_TruncF64asF32,
13254 qop( mOp,
13255 rm,
13256 mkexpr( a2 ),
13257 mkexpr( msp ? t2 : b2 ),
13258 mkexpr( msp ? b2 : t2 ) ) ) ) );
13259 assign( res3,
13260 unop( Iop_ReinterpF32asI32,
13261 unop( Iop_TruncF64asF32,
13262 qop( mOp,
13263 rm,
13264 mkexpr( a3 ),
13265 mkexpr( msp ? t3 : b3 ),
13266 mkexpr( msp ? b3 : t3 ) ) ) ) );
13267
13268 putVSReg( XT,
13269 binop( Iop_64HLtoV128,
13270 binop( Iop_32HLto64, mkexpr( negate ? getNegatedResult_32( res3 ) : res3 ),
13271 mkexpr( negate ? getNegatedResult_32( res2 ) : res2 ) ),
13272 binop( Iop_32HLto64, mkexpr( negate ? getNegatedResult_32( res1 ) : res1 ),
13273 mkexpr( negate ? getNegatedResult_32( res0 ) : res0 ) ) ) );
13274
13275 break;
13276 }
sewardje71e56a2011-09-05 12:11:06 +000013277 case 0x154: // xvtsqrtsp (VSX Vector Test for software Square Root Single-Precision)
13278 {
13279 IRTemp flags0 = newTemp(Ity_I32);
13280 IRTemp flags1 = newTemp(Ity_I32);
13281 IRTemp flags2 = newTemp(Ity_I32);
13282 IRTemp flags3 = newTemp(Ity_I32);
13283 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
13284 IRTemp fe_flag0, fg_flag0, fe_flag1, fg_flag1;
13285 IRTemp fe_flag2, fg_flag2, fe_flag3, fg_flag3;
13286 fe_flag0 = fg_flag0 = fe_flag1 = fg_flag1 = IRTemp_INVALID;
13287 fe_flag2 = fg_flag2 = fe_flag3 = fg_flag3 = IRTemp_INVALID;
13288 DIP("xvtsqrtsp cr%d,v%d\n", (UInt)crfD, (UInt)XB);
13289
13290 breakV128to4x32( getVSReg( XB ), &b3, &b2, &b1, &b0 );
13291 do_fp_tsqrt(b0, True /* single precision*/, &fe_flag0, &fg_flag0);
13292 do_fp_tsqrt(b1, True /* single precision*/, &fe_flag1, &fg_flag1);
13293 do_fp_tsqrt(b2, True /* single precision*/, &fe_flag2, &fg_flag2);
13294 do_fp_tsqrt(b3, True /* single precision*/, &fe_flag3, &fg_flag3);
13295
13296 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
13297 * where fl_flag == 1 on ppc64.
13298 */
13299 assign( flags0,
13300 binop( Iop_Or32,
13301 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13302 binop( Iop_Shl32, mkexpr(fg_flag0), mkU8( 2 ) ) ),
13303 binop( Iop_Shl32, mkexpr(fe_flag0), mkU8( 1 ) ) ) );
13304 assign( flags1,
13305 binop( Iop_Or32,
13306 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13307 binop( Iop_Shl32, mkexpr(fg_flag1), mkU8( 2 ) ) ),
13308 binop( Iop_Shl32, mkexpr(fe_flag1), mkU8( 1 ) ) ) );
13309 assign( flags2,
13310 binop( Iop_Or32,
13311 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13312 binop( Iop_Shl32, mkexpr(fg_flag2), mkU8( 2 ) ) ),
13313 binop( Iop_Shl32, mkexpr(fe_flag2), mkU8( 1 ) ) ) );
13314 assign( flags3,
13315 binop( Iop_Or32,
13316 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13317 binop( Iop_Shl32, mkexpr(fg_flag3), mkU8( 2 ) ) ),
13318 binop( Iop_Shl32, mkexpr(fe_flag3), mkU8( 1 ) ) ) );
13319 putGST_field( PPC_GST_CR,
13320 binop( Iop_Or32,
13321 mkexpr( flags0 ),
13322 binop( Iop_Or32,
13323 mkexpr( flags1 ),
13324 binop( Iop_Or32,
13325 mkexpr( flags2 ),
13326 mkexpr( flags3 ) ) ) ),
13327 crfD );
13328
13329 break;
13330 }
13331 case 0x174: // xvtdivsp (VSX Vector Test for software Divide Single-Precision)
13332 {
13333 IRTemp flags0 = newTemp(Ity_I32);
13334 IRTemp flags1 = newTemp(Ity_I32);
13335 IRTemp flags2 = newTemp(Ity_I32);
13336 IRTemp flags3 = newTemp(Ity_I32);
13337 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
13338 IRTemp fe_flag0, fg_flag0, fe_flag1, fg_flag1;
13339 IRTemp fe_flag2, fg_flag2, fe_flag3, fg_flag3;
13340 fe_flag0 = fg_flag0 = fe_flag1 = fg_flag1 = IRTemp_INVALID;
13341 fe_flag2 = fg_flag2 = fe_flag3 = fg_flag3 = IRTemp_INVALID;
13342 DIP("xvtdivsp cr%d,v%d,v%d\n", (UInt)crfD, (UInt)XA, (UInt)XB);
13343
13344 breakV128to4x32( getVSReg( XA ), &a3, &a2, &a1, &a0 );
13345 breakV128to4x32( getVSReg( XB ), &b3, &b2, &b1, &b0 );
13346 _do_fp_tdiv(a0, b0, True /* single precision*/, &fe_flag0, &fg_flag0);
13347 _do_fp_tdiv(a1, b1, True /* single precision*/, &fe_flag1, &fg_flag1);
13348 _do_fp_tdiv(a2, b2, True /* single precision*/, &fe_flag2, &fg_flag2);
13349 _do_fp_tdiv(a3, b3, True /* single precision*/, &fe_flag3, &fg_flag3);
13350
13351 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
13352 * where fl_flag == 1 on ppc64.
13353 */
13354 assign( flags0,
13355 binop( Iop_Or32,
13356 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13357 binop( Iop_Shl32, mkexpr(fg_flag0), mkU8( 2 ) ) ),
13358 binop( Iop_Shl32, mkexpr(fe_flag0), mkU8( 1 ) ) ) );
13359 assign( flags1,
13360 binop( Iop_Or32,
13361 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13362 binop( Iop_Shl32, mkexpr(fg_flag1), mkU8( 2 ) ) ),
13363 binop( Iop_Shl32, mkexpr(fe_flag1), mkU8( 1 ) ) ) );
13364 assign( flags2,
13365 binop( Iop_Or32,
13366 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13367 binop( Iop_Shl32, mkexpr(fg_flag2), mkU8( 2 ) ) ),
13368 binop( Iop_Shl32, mkexpr(fe_flag2), mkU8( 1 ) ) ) );
13369 assign( flags3,
13370 binop( Iop_Or32,
13371 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13372 binop( Iop_Shl32, mkexpr(fg_flag3), mkU8( 2 ) ) ),
13373 binop( Iop_Shl32, mkexpr(fe_flag3), mkU8( 1 ) ) ) );
13374 putGST_field( PPC_GST_CR,
13375 binop( Iop_Or32,
13376 mkexpr( flags0 ),
13377 binop( Iop_Or32,
13378 mkexpr( flags1 ),
13379 binop( Iop_Or32,
13380 mkexpr( flags2 ),
13381 mkexpr( flags3 ) ) ) ),
13382 crfD );
13383
13384 break;
13385 }
sewardj4aa412a2011-07-24 14:13:21 +000013386
13387 default:
13388 vex_printf( "dis_vxv_sp_arith(ppc)(opc2)\n" );
13389 return False;
13390 }
13391 return True;
13392}
13393
carll7deaf952013-10-15 18:11:20 +000013394/*
carll60c6bac2013-10-18 01:19:06 +000013395 * Vector Population Count/bit matrix transpose
carll7deaf952013-10-15 18:11:20 +000013396 */
13397static Bool
carll60c6bac2013-10-18 01:19:06 +000013398dis_av_count_bitTranspose ( UInt theInstr, UInt opc2 )
carll7deaf952013-10-15 18:11:20 +000013399{
13400 UChar vRB_addr = ifieldRegB(theInstr);
13401 UChar vRT_addr = ifieldRegDS(theInstr);
13402 UChar opc1 = ifieldOPC( theInstr );
13403 IRTemp vB = newTemp(Ity_V128);
13404 assign( vB, getVReg(vRB_addr));
13405
13406 if (opc1 != 0x4) {
carll60c6bac2013-10-18 01:19:06 +000013407 vex_printf( "dis_av_count_bitTranspose(ppc)(instr)\n" );
carll7deaf952013-10-15 18:11:20 +000013408 return False;
13409 }
13410
13411 switch (opc2) {
13412 case 0x702: // vclzb
13413 DIP("vclzb v%d,v%d\n", vRT_addr, vRB_addr);
sewardja8c7b0f2014-06-26 08:18:08 +000013414 putVReg( vRT_addr, unop(Iop_Clz8x16, mkexpr( vB ) ) );
carll7deaf952013-10-15 18:11:20 +000013415 break;
13416
13417 case 0x742: // vclzh
13418 DIP("vclzh v%d,v%d\n", vRT_addr, vRB_addr);
sewardja8c7b0f2014-06-26 08:18:08 +000013419 putVReg( vRT_addr, unop(Iop_Clz16x8, mkexpr( vB ) ) );
carll7deaf952013-10-15 18:11:20 +000013420 break;
13421
13422 case 0x782: // vclzw
13423 DIP("vclzw v%d,v%d\n", vRT_addr, vRB_addr);
sewardja8c7b0f2014-06-26 08:18:08 +000013424 putVReg( vRT_addr, unop(Iop_Clz32x4, mkexpr( vB ) ) );
carll7deaf952013-10-15 18:11:20 +000013425 break;
13426
13427 case 0x7C2: // vclzd
13428 DIP("vclzd v%d,v%d\n", vRT_addr, vRB_addr);
13429 putVReg( vRT_addr, unop(Iop_Clz64x2, mkexpr( vB ) ) );
13430 break;
13431
13432 case 0x703: // vpopcntb
13433 {
13434 /* Break vector into 32-bit words and do the population count
13435 * on byte in the words
13436 */
13437 IRType ty = Ity_I32;
13438 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
13439 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
13440 IRTemp cnt_bits0_31, cnt_bits32_63, cnt_bits64_95, cnt_bits96_127;
13441 cnt_bits0_31 = cnt_bits32_63 = cnt_bits64_95 = cnt_bits96_127 = IRTemp_INVALID;
13442
13443 DIP("vpopcntb v%d,v%d\n", vRT_addr, vRB_addr);
13444 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
13445 cnt_bits0_31 = gen_POPCOUNT(ty, bits0_31, BYTE);
13446 cnt_bits32_63 = gen_POPCOUNT(ty, bits32_63, BYTE);
13447 cnt_bits64_95 = gen_POPCOUNT(ty, bits64_95, BYTE);
13448 cnt_bits96_127 = gen_POPCOUNT(ty, bits96_127, BYTE);
13449
13450 putVReg( vRT_addr, mkV128from32(cnt_bits96_127, cnt_bits64_95,
13451 cnt_bits32_63, cnt_bits0_31) );
13452 break;
13453 }
13454
13455 case 0x743: // vpopcnth
13456 {
13457 /* Break vector into 32-bit words and do the population count
13458 * for each half word
13459 */
13460 IRType ty = Ity_I32;
13461 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
13462 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
13463 IRTemp cnt_bits0_31, cnt_bits32_63, cnt_bits64_95, cnt_bits96_127;
13464 cnt_bits0_31 = cnt_bits32_63 = cnt_bits64_95 = cnt_bits96_127 = IRTemp_INVALID;
13465
13466 DIP("vpopcnth v%d,v%d\n", vRT_addr, vRB_addr);
13467 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
13468
13469 cnt_bits0_31 = gen_POPCOUNT(ty, bits0_31, HWORD);
13470 cnt_bits32_63 = gen_POPCOUNT(ty, bits32_63, HWORD);
13471 cnt_bits64_95 = gen_POPCOUNT(ty, bits64_95, HWORD);
13472 cnt_bits96_127 = gen_POPCOUNT(ty, bits96_127, HWORD);
13473
13474 putVReg( vRT_addr, mkV128from32(cnt_bits96_127, cnt_bits64_95,
13475 cnt_bits32_63, cnt_bits0_31) );
13476 break;
13477 }
13478
13479 case 0x783: // vpopcntw
13480 {
13481 /* Break vector into 32-bit words and do the population count
13482 * on each word.
13483 */
13484 IRType ty = Ity_I32;
13485 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
13486 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
13487 IRTemp cnt_bits0_31, cnt_bits32_63, cnt_bits64_95, cnt_bits96_127;
13488 cnt_bits0_31 = cnt_bits32_63 = cnt_bits64_95 = cnt_bits96_127 = IRTemp_INVALID;
13489
13490 DIP("vpopcntw v%d,v%d\n", vRT_addr, vRB_addr);
13491 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
13492
13493 cnt_bits0_31 = gen_POPCOUNT(ty, bits0_31, WORD);
13494 cnt_bits32_63 = gen_POPCOUNT(ty, bits32_63, WORD);
13495 cnt_bits64_95 = gen_POPCOUNT(ty, bits64_95, WORD);
13496 cnt_bits96_127 = gen_POPCOUNT(ty, bits96_127, WORD);
13497
13498 putVReg( vRT_addr, mkV128from32(cnt_bits96_127, cnt_bits64_95,
13499 cnt_bits32_63, cnt_bits0_31) );
13500 break;
13501 }
13502
13503 case 0x7C3: // vpopcntd
13504 {
13505 if (mode64) {
13506 /* Break vector into 64-bit double words and do the population count
13507 * on each double word.
13508 */
13509 IRType ty = Ity_I64;
13510 IRTemp bits0_63 = newTemp(Ity_I64);
13511 IRTemp bits64_127 = newTemp(Ity_I64);
13512 IRTemp cnt_bits0_63 = newTemp(Ity_I64);
13513 IRTemp cnt_bits64_127 = newTemp(Ity_I64);
13514
13515 DIP("vpopcntd v%d,v%d\n", vRT_addr, vRB_addr);
13516
13517 assign(bits0_63, unop( Iop_V128to64, mkexpr( vB ) ) );
13518 assign(bits64_127, unop( Iop_V128HIto64, mkexpr( vB ) ) );
13519 cnt_bits0_63 = gen_POPCOUNT(ty, bits0_63, DWORD);
13520 cnt_bits64_127 = gen_POPCOUNT(ty, bits64_127, DWORD);
13521
13522 putVReg( vRT_addr, binop( Iop_64HLtoV128,
13523 mkexpr( cnt_bits64_127 ),
13524 mkexpr( cnt_bits0_63 ) ) );
13525 } else {
13526 /* Break vector into 32-bit words and do the population count
13527 * on each doubleword.
13528 */
13529 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
13530 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
13531 IRTemp cnt_bits0_63 = newTemp(Ity_I64);
13532 IRTemp cnt_bits64_127 = newTemp(Ity_I64);
13533
13534 DIP("vpopcntd v%d,v%d\n", vRT_addr, vRB_addr);
13535 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
13536
13537 cnt_bits0_63 = gen_vpopcntd_mode32(bits0_31, bits32_63);
13538 cnt_bits64_127 = gen_vpopcntd_mode32(bits64_95, bits96_127);
13539
13540 putVReg( vRT_addr, binop( Iop_64HLtoV128,
13541 mkexpr( cnt_bits64_127 ),
13542 mkexpr( cnt_bits0_63 ) ) );
13543 }
13544 break;
13545 }
13546
carll60c6bac2013-10-18 01:19:06 +000013547 case 0x50C: // vgbbd Vector Gather Bits by Bytes by Doubleword
13548 DIP("vgbbd v%d,v%d\n", vRT_addr, vRB_addr);
13549 putVReg( vRT_addr, unop( Iop_PwBitMtxXpose64x2, mkexpr( vB ) ) );
13550 break;
13551
carll7deaf952013-10-15 18:11:20 +000013552 default:
carll60c6bac2013-10-18 01:19:06 +000013553 vex_printf("dis_av_count_bitTranspose(ppc)(opc2)\n");
carll7deaf952013-10-15 18:11:20 +000013554 return False;
13555 break;
13556 }
13557 return True;
13558}
13559
sewardj4aa412a2011-07-24 14:13:21 +000013560typedef enum {
13561 PPC_CMP_EQ = 2,
13562 PPC_CMP_GT = 4,
13563 PPC_CMP_GE = 6,
13564 PPC_CMP_LT = 8
13565} ppc_cmp_t;
13566
13567
13568/*
13569 This helper function takes as input the IRExpr returned
13570 from a binop( Iop_CmpF64, fpA, fpB), whose result is returned
13571 in IR form. This helper function converts it to PPC form.
13572
13573 Map compare result from IR to PPC
13574
13575 FP cmp result | PPC | IR
13576 --------------------------
13577 UN | 0x1 | 0x45
13578 EQ | 0x2 | 0x40
13579 GT | 0x4 | 0x00
13580 LT | 0x8 | 0x01
13581
13582 condcode = Shl(1, (~(ccIR>>5) & 2)
13583 | ((ccIR ^ (ccIR>>6)) & 1)
13584*/
13585static IRTemp
13586get_fp_cmp_CR_val (IRExpr * ccIR_expr)
13587{
13588 IRTemp condcode = newTemp( Ity_I32 );
13589 IRTemp ccIR = newTemp( Ity_I32 );
13590
13591 assign(ccIR, ccIR_expr);
13592 assign( condcode,
13593 binop( Iop_Shl32,
13594 mkU32( 1 ),
13595 unop( Iop_32to8,
13596 binop( Iop_Or32,
13597 binop( Iop_And32,
13598 unop( Iop_Not32,
13599 binop( Iop_Shr32,
13600 mkexpr( ccIR ),
13601 mkU8( 5 ) ) ),
13602 mkU32( 2 ) ),
13603 binop( Iop_And32,
13604 binop( Iop_Xor32,
13605 mkexpr( ccIR ),
13606 binop( Iop_Shr32,
13607 mkexpr( ccIR ),
13608 mkU8( 6 ) ) ),
13609 mkU32( 1 ) ) ) ) ) );
13610 return condcode;
13611}
13612
13613/*
13614 * Helper function for get_max_min_fp for ascertaining the max or min between two doubles
13615 * following these special rules:
13616 * - The max/min of a QNaN and any value is that value
13617 * (When two QNaNs are being compared, the frA QNaN is the return value.)
13618 * - The max/min of any value and an SNaN is that SNaN converted to a QNaN
13619 * (When two SNaNs are being compared, the frA SNaN is converted to a QNaN.)
13620 */
13621static IRExpr * _get_maxmin_fp_NaN(IRTemp frA_I64, IRTemp frB_I64)
13622{
13623 IRTemp frA_isNaN = newTemp(Ity_I1);
13624 IRTemp frB_isNaN = newTemp(Ity_I1);
13625 IRTemp frA_isSNaN = newTemp(Ity_I1);
13626 IRTemp frB_isSNaN = newTemp(Ity_I1);
13627 IRTemp frA_isQNaN = newTemp(Ity_I1);
13628 IRTemp frB_isQNaN = newTemp(Ity_I1);
13629
13630 assign( frA_isNaN, is_NaN( frA_I64 ) );
13631 assign( frB_isNaN, is_NaN( frB_I64 ) );
13632 // If operand is a NAN and bit 12 is '0', then it's an SNaN
13633 assign( frA_isSNaN,
13634 mkAND1( mkexpr(frA_isNaN),
13635 binop( Iop_CmpEQ32,
13636 binop( Iop_And32,
13637 unop( Iop_64HIto32, mkexpr( frA_I64 ) ),
13638 mkU32( 0x00080000 ) ),
13639 mkU32( 0 ) ) ) );
13640 assign( frB_isSNaN,
13641 mkAND1( mkexpr(frB_isNaN),
13642 binop( Iop_CmpEQ32,
13643 binop( Iop_And32,
13644 unop( Iop_64HIto32, mkexpr( frB_I64 ) ),
13645 mkU32( 0x00080000 ) ),
13646 mkU32( 0 ) ) ) );
13647 assign( frA_isQNaN,
13648 mkAND1( mkexpr( frA_isNaN ), unop( Iop_Not1, mkexpr( frA_isSNaN ) ) ) );
13649 assign( frB_isQNaN,
13650 mkAND1( mkexpr( frB_isNaN ), unop( Iop_Not1, mkexpr( frB_isSNaN ) ) ) );
13651
13652 /* Based on the rules specified in the function prologue, the algorithm is as follows:
13653 * <<<<<<<<<>>>>>>>>>>>>>>>>>>
13654 * if frA is a SNaN
13655 * result = frA converted to QNaN
13656 * else if frB is a SNaN
13657 * result = frB converted to QNaN
13658 * else if frB is a QNaN
13659 * result = frA
13660 * // One of frA or frB was a NaN in order for this function to be called, so
13661 * // if we get to this point, we KNOW that frA must be a QNaN.
13662 * else // frA is a QNaN
13663 * result = frB
13664 * <<<<<<<<<>>>>>>>>>>>>>>>>>>
13665 */
13666
13667#define SNAN_MASK 0x0008000000000000ULL
13668 return
florian99dd03e2013-01-29 03:56:06 +000013669 IRExpr_ITE(mkexpr(frA_isSNaN),
13670 /* then: result = frA converted to QNaN */
13671 binop(Iop_Or64, mkexpr(frA_I64), mkU64(SNAN_MASK)),
13672 /* else: if frB is a SNaN */
13673 IRExpr_ITE(mkexpr(frB_isSNaN),
13674 /* then: result = frB converted to QNaN */
13675 binop(Iop_Or64, mkexpr(frB_I64), mkU64(SNAN_MASK)),
13676 /* else: if frB is a QNaN */
13677 IRExpr_ITE(mkexpr(frB_isQNaN),
13678 /* then: result = frA */
13679 mkexpr(frA_I64),
13680 /* else: frA is a QNaN, so result = frB */
13681 mkexpr(frB_I64))));
sewardj4aa412a2011-07-24 14:13:21 +000013682}
13683
13684/*
13685 * Helper function for get_max_min_fp.
13686 */
13687static IRExpr * _get_maxmin_fp_cmp(IRTemp src1, IRTemp src2, Bool isMin)
13688{
13689 IRTemp src1cmpsrc2 = get_fp_cmp_CR_val( binop( Iop_CmpF64,
13690 unop( Iop_ReinterpI64asF64,
13691 mkexpr( src1 ) ),
13692 unop( Iop_ReinterpI64asF64,
13693 mkexpr( src2 ) ) ) );
13694
florian99dd03e2013-01-29 03:56:06 +000013695 return IRExpr_ITE( binop( Iop_CmpEQ32,
sewardj009230b2013-01-26 11:47:55 +000013696 mkexpr( src1cmpsrc2 ),
13697 mkU32( isMin ? PPC_CMP_LT : PPC_CMP_GT ) ),
florian99dd03e2013-01-29 03:56:06 +000013698 /* then: use src1 */
13699 mkexpr( src1 ),
13700 /* else: use src2 */
13701 mkexpr( src2 ) );
sewardj4aa412a2011-07-24 14:13:21 +000013702}
13703
13704/*
13705 * Helper function for "Maximum/Minimum Double Precision" operations.
13706 * Arguments: frA and frb are Ity_I64
13707 * Returns Ity_I64 IRExpr that answers the "which is Maxiumum/Minimum" question
13708 */
13709static IRExpr * get_max_min_fp(IRTemp frA_I64, IRTemp frB_I64, Bool isMin)
13710{
13711 /* There are three special cases where get_fp_cmp_CR_val is not helpful
13712 * for ascertaining the maximum between two doubles:
13713 * 1. The max/min of +0 and -0 is +0.
13714 * 2. The max/min of a QNaN and any value is that value.
13715 * 3. The max/min of any value and an SNaN is that SNaN converted to a QNaN.
13716 * We perform the check for [+/-]0 here in this function and use the
13717 * _get_maxmin_fp_NaN helper for the two NaN cases; otherwise we call _get_maxmin_fp_cmp
13718 * to do the standard comparison function.
13719 */
13720 IRTemp anyNaN = newTemp(Ity_I1);
13721 IRTemp frA_isZero = newTemp(Ity_I1);
13722 IRTemp frB_isZero = newTemp(Ity_I1);
sewardje71e56a2011-09-05 12:11:06 +000013723 assign(frA_isZero, is_Zero(frA_I64, False /*not single precision*/ ));
13724 assign(frB_isZero, is_Zero(frB_I64, False /*not single precision*/ ));
sewardj4aa412a2011-07-24 14:13:21 +000013725 assign(anyNaN, mkOR1(is_NaN(frA_I64), is_NaN(frB_I64)));
13726#define MINUS_ZERO 0x8000000000000000ULL
13727
florian99dd03e2013-01-29 03:56:06 +000013728 return IRExpr_ITE( /* If both arguments are zero . . . */
13729 mkAND1( mkexpr( frA_isZero ), mkexpr( frB_isZero ) ),
13730 /* then: if frA is -0 and isMin==True, return -0;
13731 * else if frA is +0 and isMin==False; return +0;
13732 * otherwise, simply return frB. */
13733 IRExpr_ITE( binop( Iop_CmpEQ32,
13734 unop( Iop_64HIto32,
13735 mkexpr( frA_I64 ) ),
13736 mkU32( isMin ? 0x80000000 : 0 ) ),
13737 mkU64( isMin ? MINUS_ZERO : 0ULL ),
13738 mkexpr( frB_I64 ) ),
13739 /* else: check if either input is a NaN*/
13740 IRExpr_ITE( mkexpr( anyNaN ),
13741 /* then: use "NaN helper" */
13742 _get_maxmin_fp_NaN( frA_I64, frB_I64 ),
13743 /* else: use "comparison helper" */
13744 _get_maxmin_fp_cmp( frB_I64, frA_I64, isMin ) ));
sewardj4aa412a2011-07-24 14:13:21 +000013745}
sewardje71e56a2011-09-05 12:11:06 +000013746
carll9884af02013-01-30 18:39:57 +000013747static const HChar * _get_vsx_rdpi_suffix(UInt opc2)
13748{
13749 switch (opc2 & 0x7F) {
13750 case 0x72:
13751 return "m";
13752 case 0x52:
13753 return "p";
13754 case 0x56:
13755 return "c";
13756 case 0x32:
13757 return "z";
13758 case 0x12:
13759 return "";
13760
13761 default: // Impossible to get here
13762 vex_printf("Unrecognized opcode %x\n", opc2);
13763 vpanic("_get_vsx_rdpi_suffix(ppc)(opc2)");
13764 }
13765}
13766
sewardje71e56a2011-09-05 12:11:06 +000013767/*
13768 * Helper function for vector/scalar double precision fp round to integer instructions.
13769 */
carll9884af02013-01-30 18:39:57 +000013770static IRExpr * _do_vsx_fp_roundToInt(IRTemp frB_I64, UInt opc2)
sewardje71e56a2011-09-05 12:11:06 +000013771{
13772
13773 /* The same rules apply for x{s|v}rdpi{m|p|c|z} as for floating point round operations (fri{m|n|p|z}). */
13774 IRTemp frB = newTemp(Ity_F64);
13775 IRTemp frD = newTemp(Ity_F64);
13776 IRTemp intermediateResult = newTemp(Ity_I64);
13777 IRTemp is_SNAN = newTemp(Ity_I1);
13778 IRExpr * hi32;
13779 IRExpr * rxpi_rm;
13780 switch (opc2 & 0x7F) {
13781 case 0x72:
sewardje71e56a2011-09-05 12:11:06 +000013782 rxpi_rm = mkU32(Irrm_NegINF);
13783 break;
13784 case 0x52:
sewardje71e56a2011-09-05 12:11:06 +000013785 rxpi_rm = mkU32(Irrm_PosINF);
13786 break;
13787 case 0x56:
sewardje71e56a2011-09-05 12:11:06 +000013788 rxpi_rm = get_IR_roundingmode();
13789 break;
13790 case 0x32:
sewardje71e56a2011-09-05 12:11:06 +000013791 rxpi_rm = mkU32(Irrm_ZERO);
13792 break;
13793 case 0x12:
sewardje71e56a2011-09-05 12:11:06 +000013794 rxpi_rm = mkU32(Irrm_NEAREST);
13795 break;
13796
13797 default: // Impossible to get here
carll9884af02013-01-30 18:39:57 +000013798 vex_printf("Unrecognized opcode %x\n", opc2);
13799 vpanic("_do_vsx_fp_roundToInt(ppc)(opc2)");
sewardje71e56a2011-09-05 12:11:06 +000013800 }
13801 assign(frB, unop(Iop_ReinterpI64asF64, mkexpr(frB_I64)));
13802 assign( intermediateResult,
13803 binop( Iop_F64toI64S, rxpi_rm,
13804 mkexpr( frB ) ) );
13805
13806 /* don't use the rounded integer if frB is outside -9e18..9e18 */
13807 /* F64 has only log10(2**52) significant digits anyway */
13808 /* need to preserve sign of zero */
13809 /* frD = (fabs(frB) > 9e18) ? frB :
13810 (sign(frB)) ? -fabs((double)intermediateResult) : (double)intermediateResult */
13811 assign( frD,
florian99dd03e2013-01-29 03:56:06 +000013812 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +000013813 binop( Iop_CmpNE8,
13814 unop( Iop_32to8,
13815 binop( Iop_CmpF64,
13816 IRExpr_Const( IRConst_F64( 9e18 ) ),
13817 unop( Iop_AbsF64, mkexpr( frB ) ) ) ),
13818 mkU8(0) ),
florian99dd03e2013-01-29 03:56:06 +000013819 mkexpr( frB ),
13820 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +000013821 binop( Iop_CmpNE32,
13822 binop( Iop_Shr32,
13823 unop( Iop_64HIto32,
13824 mkexpr( frB_I64 ) ),
13825 mkU8( 31 ) ),
13826 mkU32(0) ),
sewardj009230b2013-01-26 11:47:55 +000013827 unop( Iop_NegF64,
13828 unop( Iop_AbsF64,
13829 binop( Iop_I64StoF64,
13830 mkU32( 0 ),
florian99dd03e2013-01-29 03:56:06 +000013831 mkexpr( intermediateResult ) ) ) ),
13832 binop( Iop_I64StoF64,
13833 mkU32( 0 ),
13834 mkexpr( intermediateResult ) )
13835 )
sewardj009230b2013-01-26 11:47:55 +000013836 )
13837 );
sewardje71e56a2011-09-05 12:11:06 +000013838
13839 /* See Appendix "Floating-Point Round to Integer Model" in ISA doc.
13840 * If frB is a SNAN, then frD <- frB, with bit 12 set to '1'.
13841 */
13842#define SNAN_MASK 0x0008000000000000ULL
13843 hi32 = unop( Iop_64HIto32, mkexpr(frB_I64) );
13844 assign( is_SNAN,
13845 mkAND1( is_NaN( frB_I64 ),
13846 binop( Iop_CmpEQ32,
13847 binop( Iop_And32, hi32, mkU32( 0x00080000 ) ),
13848 mkU32( 0 ) ) ) );
13849
florian99dd03e2013-01-29 03:56:06 +000013850 return IRExpr_ITE( mkexpr( is_SNAN ),
sewardje71e56a2011-09-05 12:11:06 +000013851 unop( Iop_ReinterpI64asF64,
13852 binop( Iop_Xor64,
13853 mkU64( SNAN_MASK ),
florian99dd03e2013-01-29 03:56:06 +000013854 mkexpr( frB_I64 ) ) ),
13855 mkexpr( frD ));
sewardje71e56a2011-09-05 12:11:06 +000013856}
13857
sewardj4aa412a2011-07-24 14:13:21 +000013858/*
13859 * Miscellaneous VSX vector instructions
13860 */
13861static Bool
13862dis_vxv_misc ( UInt theInstr, UInt opc2 )
13863{
13864 /* XX3-Form */
13865 UChar opc1 = ifieldOPC( theInstr );
13866 UChar XT = ifieldRegXT( theInstr );
13867 UChar XB = ifieldRegXB( theInstr );
13868
13869 if (opc1 != 0x3C) {
13870 vex_printf( "dis_vxv_misc(ppc)(instr)\n" );
13871 return False;
13872 }
13873
13874 switch (opc2) {
sewardje71e56a2011-09-05 12:11:06 +000013875 case 0x1B4: // xvredp (VSX Vector Reciprocal Estimate Double-Precision)
13876 case 0x194: // xvrsqrtedp (VSX Vector Reciprocal Square Root Estimate
13877 // Double-Precision)
13878 {
13879 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
13880 IRExpr* rm = get_IR_roundingmode();
13881 IRTemp frB = newTemp(Ity_I64);
13882 IRTemp frB2 = newTemp(Ity_I64);
13883 Bool redp = opc2 == 0x1B4;
13884 IRTemp sqrtHi = newTemp(Ity_F64);
13885 IRTemp sqrtLo = newTemp(Ity_F64);
13886 assign(frB, unop(Iop_V128HIto64, getVSReg( XB )));
13887 assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
13888
13889 DIP("%s v%d,v%d\n", redp ? "xvredp" : "xvrsqrtedp", (UInt)XT, (UInt)XB);
13890 if (!redp) {
13891 assign( sqrtHi,
13892 binop( Iop_SqrtF64,
13893 rm,
13894 unop( Iop_ReinterpI64asF64, mkexpr( frB ) ) ) );
13895 assign( sqrtLo,
13896 binop( Iop_SqrtF64,
13897 rm,
13898 unop( Iop_ReinterpI64asF64, mkexpr( frB2 ) ) ) );
13899 }
13900 putVSReg( XT,
13901 binop( Iop_64HLtoV128,
13902 unop( Iop_ReinterpF64asI64,
13903 triop( Iop_DivF64,
13904 rm,
13905 ieee_one,
13906 redp ? unop( Iop_ReinterpI64asF64,
13907 mkexpr( frB ) )
13908 : mkexpr( sqrtHi ) ) ),
13909 unop( Iop_ReinterpF64asI64,
13910 triop( Iop_DivF64,
13911 rm,
13912 ieee_one,
13913 redp ? unop( Iop_ReinterpI64asF64,
13914 mkexpr( frB2 ) )
13915 : mkexpr( sqrtLo ) ) ) ) );
13916 break;
13917
13918 }
sewardj4aa412a2011-07-24 14:13:21 +000013919 case 0x134: // xvresp (VSX Vector Reciprocal Estimate Single-Precision)
sewardje71e56a2011-09-05 12:11:06 +000013920 case 0x114: // xvrsqrtesp (VSX Vector Reciprocal Square Root Estimate Single-Precision)
sewardj4aa412a2011-07-24 14:13:21 +000013921 {
13922 IRTemp b3, b2, b1, b0;
13923 IRTemp res0 = newTemp(Ity_I32);
13924 IRTemp res1 = newTemp(Ity_I32);
13925 IRTemp res2 = newTemp(Ity_I32);
13926 IRTemp res3 = newTemp(Ity_I32);
sewardje71e56a2011-09-05 12:11:06 +000013927 IRTemp sqrt3 = newTemp(Ity_F64);
13928 IRTemp sqrt2 = newTemp(Ity_F64);
13929 IRTemp sqrt1 = newTemp(Ity_F64);
13930 IRTemp sqrt0 = newTemp(Ity_F64);
sewardj4aa412a2011-07-24 14:13:21 +000013931 IRExpr* rm = get_IR_roundingmode();
sewardje71e56a2011-09-05 12:11:06 +000013932 Bool resp = opc2 == 0x134;
13933
sewardj4aa412a2011-07-24 14:13:21 +000013934 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
13935
13936 b3 = b2 = b1 = b0 = IRTemp_INVALID;
sewardje71e56a2011-09-05 12:11:06 +000013937 DIP("%s v%d,v%d\n", resp ? "xvresp" : "xvrsqrtesp", (UInt)XT, (UInt)XB);
sewardj4aa412a2011-07-24 14:13:21 +000013938 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
sewardje71e56a2011-09-05 12:11:06 +000013939
13940 if (!resp) {
13941 assign( sqrt3, binop( Iop_SqrtF64, rm, mkexpr( b3 ) ) );
13942 assign( sqrt2, binop( Iop_SqrtF64, rm, mkexpr( b2 ) ) );
13943 assign( sqrt1, binop( Iop_SqrtF64, rm, mkexpr( b1 ) ) );
13944 assign( sqrt0, binop( Iop_SqrtF64, rm, mkexpr( b0 ) ) );
13945 }
13946
sewardj4aa412a2011-07-24 14:13:21 +000013947 assign( res0,
13948 unop( Iop_ReinterpF32asI32,
13949 unop( Iop_TruncF64asF32,
sewardje71e56a2011-09-05 12:11:06 +000013950 triop( Iop_DivF64r32,
13951 rm,
13952 ieee_one,
13953 resp ? mkexpr( b0 ) : mkexpr( sqrt0 ) ) ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000013954 assign( res1,
13955 unop( Iop_ReinterpF32asI32,
13956 unop( Iop_TruncF64asF32,
sewardje71e56a2011-09-05 12:11:06 +000013957 triop( Iop_DivF64r32,
13958 rm,
13959 ieee_one,
13960 resp ? mkexpr( b1 ) : mkexpr( sqrt1 ) ) ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000013961 assign( res2,
13962 unop( Iop_ReinterpF32asI32,
13963 unop( Iop_TruncF64asF32,
sewardje71e56a2011-09-05 12:11:06 +000013964 triop( Iop_DivF64r32,
13965 rm,
13966 ieee_one,
13967 resp ? mkexpr( b2 ) : mkexpr( sqrt2 ) ) ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000013968 assign( res3,
13969 unop( Iop_ReinterpF32asI32,
13970 unop( Iop_TruncF64asF32,
sewardje71e56a2011-09-05 12:11:06 +000013971 triop( Iop_DivF64r32,
13972 rm,
13973 ieee_one,
13974 resp ? mkexpr( b3 ) : mkexpr( sqrt3 ) ) ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000013975 putVSReg( XT,
13976 binop( Iop_64HLtoV128,
13977 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
13978 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
13979 break;
13980 }
13981 case 0x300: // xvmaxsp (VSX Vector Maximum Single-Precision)
13982 case 0x320: // xvminsp (VSX Vector Minimum Single-Precision)
13983 {
13984 UChar XA = ifieldRegXA( theInstr );
13985 IRTemp a3, a2, a1, a0;
13986 IRTemp b3, b2, b1, b0;
13987 IRTemp res0 = newTemp( Ity_I32 );
13988 IRTemp res1 = newTemp( Ity_I32 );
13989 IRTemp res2 = newTemp( Ity_I32 );
13990 IRTemp res3 = newTemp( Ity_I32 );
13991 IRTemp a0_I64 = newTemp( Ity_I64 );
13992 IRTemp a1_I64 = newTemp( Ity_I64 );
13993 IRTemp a2_I64 = newTemp( Ity_I64 );
13994 IRTemp a3_I64 = newTemp( Ity_I64 );
13995 IRTemp b0_I64 = newTemp( Ity_I64 );
13996 IRTemp b1_I64 = newTemp( Ity_I64 );
13997 IRTemp b2_I64 = newTemp( Ity_I64 );
13998 IRTemp b3_I64 = newTemp( Ity_I64 );
13999
14000 Bool isMin = opc2 == 0x320 ? True : False;
14001
14002 a3 = a2 = a1 = a0 = IRTemp_INVALID;
14003 b3 = b2 = b1 = b0 = IRTemp_INVALID;
14004 DIP("%s v%d,v%d v%d\n", isMin ? "xvminsp" : "xvmaxsp", (UInt)XT, (UInt)XA, (UInt)XB);
14005 breakV128to4xF64( getVSReg( XA ), &a3, &a2, &a1, &a0 );
14006 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
14007 assign( a0_I64, unop( Iop_ReinterpF64asI64, mkexpr( a0 ) ) );
14008 assign( b0_I64, unop( Iop_ReinterpF64asI64, mkexpr( b0 ) ) );
14009 assign( a1_I64, unop( Iop_ReinterpF64asI64, mkexpr( a1 ) ) );
14010 assign( b1_I64, unop( Iop_ReinterpF64asI64, mkexpr( b1 ) ) );
14011 assign( a2_I64, unop( Iop_ReinterpF64asI64, mkexpr( a2 ) ) );
14012 assign( b2_I64, unop( Iop_ReinterpF64asI64, mkexpr( b2 ) ) );
14013 assign( a3_I64, unop( Iop_ReinterpF64asI64, mkexpr( a3 ) ) );
14014 assign( b3_I64, unop( Iop_ReinterpF64asI64, mkexpr( b3 ) ) );
14015 assign( res0,
14016 unop( Iop_ReinterpF32asI32,
14017 unop( Iop_TruncF64asF32,
14018 unop( Iop_ReinterpI64asF64,
14019 get_max_min_fp( a0_I64, b0_I64, isMin ) ) ) ) );
14020 assign( res1,
14021 unop( Iop_ReinterpF32asI32,
14022 unop( Iop_TruncF64asF32,
14023 unop( Iop_ReinterpI64asF64,
14024 get_max_min_fp( a1_I64, b1_I64, isMin ) ) ) ) );
14025 assign( res2,
14026 unop( Iop_ReinterpF32asI32,
14027 unop( Iop_TruncF64asF32,
14028 unop( Iop_ReinterpI64asF64,
14029 get_max_min_fp( a2_I64, b2_I64, isMin ) ) ) ) );
14030 assign( res3,
14031 unop( Iop_ReinterpF32asI32,
14032 unop( Iop_TruncF64asF32,
14033 unop( Iop_ReinterpI64asF64,
14034 get_max_min_fp( a3_I64, b3_I64, isMin ) ) ) ) );
14035 putVSReg( XT,
14036 binop( Iop_64HLtoV128,
14037 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
14038 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
14039 break;
14040 }
14041 case 0x380: // xvmaxdp (VSX Vector Maximum Double-Precision)
14042 case 0x3A0: // xvmindp (VSX Vector Minimum Double-Precision)
14043 {
14044 UChar XA = ifieldRegXA( theInstr );
14045 IRTemp frA = newTemp(Ity_I64);
14046 IRTemp frB = newTemp(Ity_I64);
14047 IRTemp frA2 = newTemp(Ity_I64);
14048 IRTemp frB2 = newTemp(Ity_I64);
14049 Bool isMin = opc2 == 0x3A0 ? True : False;
14050
14051 assign(frA, unop(Iop_V128HIto64, getVSReg( XA )));
14052 assign(frB, unop(Iop_V128HIto64, getVSReg( XB )));
14053 assign(frA2, unop(Iop_V128to64, getVSReg( XA )));
14054 assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
14055 DIP("%s v%d,v%d v%d\n", isMin ? "xvmindp" : "xvmaxdp", (UInt)XT, (UInt)XA, (UInt)XB);
14056 putVSReg( XT, binop( Iop_64HLtoV128, get_max_min_fp(frA, frB, isMin), get_max_min_fp(frA2, frB2, isMin) ) );
14057
14058 break;
14059 }
14060 case 0x3c0: // xvcpsgndp (VSX Vector Copy Sign Double-Precision)
14061 {
14062 UChar XA = ifieldRegXA( theInstr );
14063 IRTemp frA = newTemp(Ity_I64);
14064 IRTemp frB = newTemp(Ity_I64);
14065 IRTemp frA2 = newTemp(Ity_I64);
14066 IRTemp frB2 = newTemp(Ity_I64);
14067 assign(frA, unop(Iop_V128HIto64, getVSReg( XA )));
14068 assign(frB, unop(Iop_V128HIto64, getVSReg( XB )));
14069 assign(frA2, unop(Iop_V128to64, getVSReg( XA )));
14070 assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
14071
14072 DIP("xvcpsgndp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14073 putVSReg( XT,
14074 binop( Iop_64HLtoV128,
14075 binop( Iop_Or64,
14076 binop( Iop_And64,
14077 mkexpr( frA ),
14078 mkU64( SIGN_BIT ) ),
14079 binop( Iop_And64,
14080 mkexpr( frB ),
14081 mkU64( SIGN_MASK ) ) ),
14082 binop( Iop_Or64,
14083 binop( Iop_And64,
14084 mkexpr( frA2 ),
14085 mkU64( SIGN_BIT ) ),
14086 binop( Iop_And64,
14087 mkexpr( frB2 ),
14088 mkU64( SIGN_MASK ) ) ) ) );
14089 break;
14090 }
14091 case 0x340: // xvcpsgnsp
14092 {
14093 UChar XA = ifieldRegXA( theInstr );
14094 IRTemp a3_I64, a2_I64, a1_I64, a0_I64;
14095 IRTemp b3_I64, b2_I64, b1_I64, b0_I64;
14096 IRTemp resHi = newTemp(Ity_I64);
14097 IRTemp resLo = newTemp(Ity_I64);
14098
14099 a3_I64 = a2_I64 = a1_I64 = a0_I64 = IRTemp_INVALID;
14100 b3_I64 = b2_I64 = b1_I64 = b0_I64 = IRTemp_INVALID;
14101 DIP("xvcpsgnsp v%d,v%d v%d\n",(UInt)XT, (UInt)XA, (UInt)XB);
14102 breakV128to4x64U( getVSReg( XA ), &a3_I64, &a2_I64, &a1_I64, &a0_I64 );
14103 breakV128to4x64U( getVSReg( XB ), &b3_I64, &b2_I64, &b1_I64, &b0_I64 );
14104
14105 assign( resHi,
14106 binop( Iop_32HLto64,
14107 binop( Iop_Or32,
14108 binop( Iop_And32,
14109 unop(Iop_64to32, mkexpr( a3_I64 ) ),
14110 mkU32( SIGN_BIT32 ) ),
14111 binop( Iop_And32,
14112 unop(Iop_64to32, mkexpr( b3_I64 ) ),
14113 mkU32( SIGN_MASK32) ) ),
14114
14115 binop( Iop_Or32,
14116 binop( Iop_And32,
14117 unop(Iop_64to32, mkexpr( a2_I64 ) ),
14118 mkU32( SIGN_BIT32 ) ),
14119 binop( Iop_And32,
14120 unop(Iop_64to32, mkexpr( b2_I64 ) ),
14121 mkU32( SIGN_MASK32 ) ) ) ) );
14122 assign( resLo,
14123 binop( Iop_32HLto64,
14124 binop( Iop_Or32,
14125 binop( Iop_And32,
14126 unop(Iop_64to32, mkexpr( a1_I64 ) ),
14127 mkU32( SIGN_BIT32 ) ),
14128 binop( Iop_And32,
14129 unop(Iop_64to32, mkexpr( b1_I64 ) ),
14130 mkU32( SIGN_MASK32 ) ) ),
14131
14132 binop( Iop_Or32,
14133 binop( Iop_And32,
14134 unop(Iop_64to32, mkexpr( a0_I64 ) ),
14135 mkU32( SIGN_BIT32 ) ),
14136 binop( Iop_And32,
14137 unop(Iop_64to32, mkexpr( b0_I64 ) ),
14138 mkU32( SIGN_MASK32 ) ) ) ) );
14139 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( resHi ), mkexpr( resLo ) ) );
14140 break;
14141 }
sewardje71e56a2011-09-05 12:11:06 +000014142 case 0x3B2: // xvabsdp (VSX Vector Absolute Value Double-Precision)
14143 case 0x3D2: // xvnabsdp VSX Vector Negative Absolute Value Double-Precision)
14144 {
14145 IRTemp frB = newTemp(Ity_F64);
14146 IRTemp frB2 = newTemp(Ity_F64);
14147 IRTemp abs_resultHi = newTemp(Ity_F64);
14148 IRTemp abs_resultLo = newTemp(Ity_F64);
14149 Bool make_negative = (opc2 == 0x3D2) ? True : False;
14150 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
14151 assign(frB2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg(XB))));
14152
14153 DIP("xv%sabsdp v%d,v%d\n", make_negative ? "n" : "", (UInt)XT, (UInt)XB);
14154 if (make_negative) {
14155 assign(abs_resultHi, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr( frB ) ) ) );
14156 assign(abs_resultLo, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr( frB2 ) ) ) );
14157
14158 } else {
14159 assign(abs_resultHi, unop( Iop_AbsF64, mkexpr( frB ) ) );
14160 assign(abs_resultLo, unop( Iop_AbsF64, mkexpr( frB2 ) ) );
14161 }
14162 putVSReg( XT, binop( Iop_64HLtoV128,
14163 unop( Iop_ReinterpF64asI64, mkexpr( abs_resultHi ) ),
14164 unop( Iop_ReinterpF64asI64, mkexpr( abs_resultLo ) ) ) );
14165 break;
14166 }
14167 case 0x332: // xvabssp (VSX Vector Absolute Value Single-Precision)
14168 case 0x352: // xvnabssp (VSX Vector Negative Absolute Value Single-Precision)
14169 {
14170 /*
14171 * The Iop_AbsF32 IRop is not implemented for ppc64 since, up until introduction
14172 * of xvabssp, there has not been an abs(sp) type of instruction. But since emulation
14173 * of this function is so easy using shifts, I choose to emulate this instruction that
14174 * way versus a native instruction method of implementation.
14175 */
14176 Bool make_negative = (opc2 == 0x352) ? True : False;
14177 IRTemp shiftVector = newTemp(Ity_V128);
14178 IRTemp absVal_vector = newTemp(Ity_V128);
14179 assign( shiftVector,
14180 binop( Iop_64HLtoV128,
14181 binop( Iop_32HLto64, mkU32( 1 ), mkU32( 1 ) ),
14182 binop( Iop_32HLto64, mkU32( 1 ), mkU32( 1 ) ) ) );
14183 assign( absVal_vector,
14184 binop( Iop_Shr32x4,
14185 binop( Iop_Shl32x4,
14186 getVSReg( XB ),
14187 mkexpr( shiftVector ) ),
14188 mkexpr( shiftVector ) ) );
14189 if (make_negative) {
14190 IRTemp signBit_vector = newTemp(Ity_V128);
14191 assign( signBit_vector,
14192 binop( Iop_64HLtoV128,
14193 binop( Iop_32HLto64,
14194 mkU32( 0x80000000 ),
14195 mkU32( 0x80000000 ) ),
14196 binop( Iop_32HLto64,
14197 mkU32( 0x80000000 ),
14198 mkU32( 0x80000000 ) ) ) );
14199 putVSReg( XT,
14200 binop( Iop_OrV128,
14201 mkexpr( absVal_vector ),
14202 mkexpr( signBit_vector ) ) );
14203 } else {
14204 putVSReg( XT, mkexpr( absVal_vector ) );
14205 }
14206 break;
14207 }
14208 case 0x3F2: // xvnegdp (VSX Vector Negate Double-Precision)
14209 {
14210 IRTemp frB = newTemp(Ity_F64);
14211 IRTemp frB2 = newTemp(Ity_F64);
14212 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
14213 assign(frB2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg(XB))));
14214 DIP("xvnegdp v%d,v%d\n", (UInt)XT, (UInt)XB);
14215 putVSReg( XT,
14216 binop( Iop_64HLtoV128,
14217 unop( Iop_ReinterpF64asI64,
14218 unop( Iop_NegF64, mkexpr( frB ) ) ),
14219 unop( Iop_ReinterpF64asI64,
14220 unop( Iop_NegF64, mkexpr( frB2 ) ) ) ) );
14221 break;
14222 }
14223 case 0x192: // xvrdpi (VSX Vector Round to Double-Precision Integer using round toward Nearest Away)
14224 case 0x1D6: // xvrdpic (VSX Vector Round to Double-Precision Integer using Current rounding mode)
14225 case 0x1F2: // xvrdpim (VSX Vector Round to Double-Precision Integer using round toward -Infinity)
14226 case 0x1D2: // xvrdpip (VSX Vector Round to Double-Precision Integer using round toward +Infinity)
14227 case 0x1B2: // xvrdpiz (VSX Vector Round to Double-Precision Integer using round toward Zero)
14228 {
14229 IRTemp frBHi_I64 = newTemp(Ity_I64);
14230 IRTemp frBLo_I64 = newTemp(Ity_I64);
14231 IRExpr * frD_fp_roundHi = NULL;
14232 IRExpr * frD_fp_roundLo = NULL;
sewardje71e56a2011-09-05 12:11:06 +000014233
14234 assign( frBHi_I64, unop( Iop_V128HIto64, getVSReg( XB ) ) );
carll9884af02013-01-30 18:39:57 +000014235 frD_fp_roundHi = _do_vsx_fp_roundToInt(frBHi_I64, opc2);
sewardje71e56a2011-09-05 12:11:06 +000014236 assign( frBLo_I64, unop( Iop_V128to64, getVSReg( XB ) ) );
carll9884af02013-01-30 18:39:57 +000014237 frD_fp_roundLo = _do_vsx_fp_roundToInt(frBLo_I64, opc2);
sewardje71e56a2011-09-05 12:11:06 +000014238
carll9884af02013-01-30 18:39:57 +000014239 DIP("xvrdpi%s v%d,v%d\n", _get_vsx_rdpi_suffix(opc2), (UInt)XT, (UInt)XB);
sewardje71e56a2011-09-05 12:11:06 +000014240 putVSReg( XT,
14241 binop( Iop_64HLtoV128,
14242 unop( Iop_ReinterpF64asI64, frD_fp_roundHi ),
14243 unop( Iop_ReinterpF64asI64, frD_fp_roundLo ) ) );
14244 break;
14245 }
14246 case 0x112: // xvrspi (VSX Vector Round to Single-Precision Integer using round toward Nearest Away)
14247 case 0x156: // xvrspic (VSX Vector Round to SinglePrecision Integer using Current rounding mode)
14248 case 0x172: // xvrspim (VSX Vector Round to SinglePrecision Integer using round toward -Infinity)
14249 case 0x152: // xvrspip (VSX Vector Round to SinglePrecision Integer using round toward +Infinity)
14250 case 0x132: // xvrspiz (VSX Vector Round to SinglePrecision Integer using round toward Zero)
14251 {
florian55085f82012-11-21 00:36:55 +000014252 const HChar * insn_suffix = NULL;
sewardje71e56a2011-09-05 12:11:06 +000014253 IROp op;
14254 if (opc2 != 0x156) {
14255 // Use pre-defined IRop's for vrfi{m|n|p|z}
14256 switch (opc2) {
14257 case 0x112:
14258 insn_suffix = "";
14259 op = Iop_RoundF32x4_RN;
14260 break;
14261 case 0x172:
14262 insn_suffix = "m";
14263 op = Iop_RoundF32x4_RM;
14264 break;
14265 case 0x152:
14266 insn_suffix = "p";
14267 op = Iop_RoundF32x4_RP;
14268 break;
14269 case 0x132:
14270 insn_suffix = "z";
14271 op = Iop_RoundF32x4_RZ;
14272 break;
14273
14274 default:
carll9884af02013-01-30 18:39:57 +000014275 vex_printf("Unrecognized opcode %x\n", opc2);
14276 vpanic("dis_vxv_misc(ppc)(vrspi<x>)(opc2)\n");
sewardje71e56a2011-09-05 12:11:06 +000014277 }
14278 DIP("xvrspi%s v%d,v%d\n", insn_suffix, (UInt)XT, (UInt)XB);
14279 putVSReg( XT, unop( op, getVSReg(XB) ) );
14280 } else {
14281 // Handle xvrspic. Unfortunately there is no corresponding "vfric" instruction.
14282 IRExpr * frD_fp_roundb3, * frD_fp_roundb2, * frD_fp_roundb1, * frD_fp_roundb0;
14283 IRTemp b3_F64, b2_F64, b1_F64, b0_F64;
14284 IRTemp b3_I64 = newTemp(Ity_I64);
14285 IRTemp b2_I64 = newTemp(Ity_I64);
14286 IRTemp b1_I64 = newTemp(Ity_I64);
14287 IRTemp b0_I64 = newTemp(Ity_I64);
14288
14289 b3_F64 = b2_F64 = b1_F64 = b0_F64 = IRTemp_INVALID;
14290 frD_fp_roundb3 = frD_fp_roundb2 = frD_fp_roundb1 = frD_fp_roundb0 = NULL;
14291 breakV128to4xF64( getVSReg(XB), &b3_F64, &b2_F64, &b1_F64, &b0_F64);
14292 assign(b3_I64, unop(Iop_ReinterpF64asI64, mkexpr(b3_F64)));
14293 assign(b2_I64, unop(Iop_ReinterpF64asI64, mkexpr(b2_F64)));
14294 assign(b1_I64, unop(Iop_ReinterpF64asI64, mkexpr(b1_F64)));
14295 assign(b0_I64, unop(Iop_ReinterpF64asI64, mkexpr(b0_F64)));
14296 frD_fp_roundb3 = unop(Iop_TruncF64asF32,
carll9884af02013-01-30 18:39:57 +000014297 _do_vsx_fp_roundToInt(b3_I64, opc2));
sewardje71e56a2011-09-05 12:11:06 +000014298 frD_fp_roundb2 = unop(Iop_TruncF64asF32,
carll9884af02013-01-30 18:39:57 +000014299 _do_vsx_fp_roundToInt(b2_I64, opc2));
sewardje71e56a2011-09-05 12:11:06 +000014300 frD_fp_roundb1 = unop(Iop_TruncF64asF32,
carll9884af02013-01-30 18:39:57 +000014301 _do_vsx_fp_roundToInt(b1_I64, opc2));
sewardje71e56a2011-09-05 12:11:06 +000014302 frD_fp_roundb0 = unop(Iop_TruncF64asF32,
carll9884af02013-01-30 18:39:57 +000014303 _do_vsx_fp_roundToInt(b0_I64, opc2));
sewardje71e56a2011-09-05 12:11:06 +000014304 DIP("xvrspic v%d,v%d\n", (UInt)XT, (UInt)XB);
14305 putVSReg( XT,
14306 binop( Iop_64HLtoV128,
14307 binop( Iop_32HLto64,
14308 unop( Iop_ReinterpF32asI32, frD_fp_roundb3 ),
14309 unop( Iop_ReinterpF32asI32, frD_fp_roundb2 ) ),
14310 binop( Iop_32HLto64,
14311 unop( Iop_ReinterpF32asI32, frD_fp_roundb1 ),
14312 unop( Iop_ReinterpF32asI32, frD_fp_roundb0 ) ) ) );
14313 }
14314 break;
14315 }
sewardj4aa412a2011-07-24 14:13:21 +000014316
14317 default:
14318 vex_printf( "dis_vxv_misc(ppc)(opc2)\n" );
14319 return False;
14320 }
14321 return True;
14322}
14323
14324
14325/*
sewardj66d5ef22011-04-15 11:55:00 +000014326 * VSX Scalar Floating Point Arithmetic Instructions
14327 */
14328static Bool
sewardj4aa412a2011-07-24 14:13:21 +000014329dis_vxs_arith ( UInt theInstr, UInt opc2 )
sewardj66d5ef22011-04-15 11:55:00 +000014330{
14331 /* XX3-Form */
14332 UChar opc1 = ifieldOPC( theInstr );
14333 UChar XT = ifieldRegXT( theInstr );
14334 UChar XA = ifieldRegXA( theInstr );
14335 UChar XB = ifieldRegXB( theInstr );
14336 IRExpr* rm = get_IR_roundingmode();
14337 IRTemp frA = newTemp(Ity_F64);
14338 IRTemp frB = newTemp(Ity_F64);
14339
14340 if (opc1 != 0x3C) {
sewardj4aa412a2011-07-24 14:13:21 +000014341 vex_printf( "dis_vxs_arith(ppc)(instr)\n" );
sewardj66d5ef22011-04-15 11:55:00 +000014342 return False;
14343 }
14344
14345 assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
14346 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
14347
14348 /* For all the VSX sclar arithmetic instructions, the contents of doubleword element 1
14349 * of VSX[XT] are undefined after the operation; therefore, we can simply set
14350 * element to zero where it makes sense to do so.
14351 */
14352 switch (opc2) {
carll6c758b62013-10-03 21:38:45 +000014353 case 0x000: // xsaddsp (VSX Scalar Add Single-Precision)
14354 DIP("xsaddsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14355 putVSReg( XT, binop( Iop_64HLtoV128,
14356 unop( Iop_ReinterpF64asI64,
14357 binop( Iop_RoundF64toF32, rm,
14358 triop( Iop_AddF64, rm,
14359 mkexpr( frA ),
14360 mkexpr( frB ) ) ) ),
14361 mkU64( 0 ) ) );
14362 break;
14363 case 0x020: // xssubsp (VSX Scalar Subtract Single-Precision)
14364 DIP("xssubsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14365 putVSReg( XT, binop( Iop_64HLtoV128,
14366 unop( Iop_ReinterpF64asI64,
14367 binop( Iop_RoundF64toF32, rm,
14368 triop( Iop_SubF64, rm,
14369 mkexpr( frA ),
14370 mkexpr( frB ) ) ) ),
14371 mkU64( 0 ) ) );
14372 break;
sewardj66d5ef22011-04-15 11:55:00 +000014373 case 0x080: // xsadddp (VSX scalar add double-precision)
14374 DIP("xsadddp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14375 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14376 triop( Iop_AddF64, rm,
14377 mkexpr( frA ),
14378 mkexpr( frB ) ) ),
14379 mkU64( 0 ) ) );
14380 break;
carll6c758b62013-10-03 21:38:45 +000014381 case 0x060: // xsdivsp (VSX scalar divide single-precision)
14382 DIP("xsdivsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14383 putVSReg( XT, binop( Iop_64HLtoV128,
14384 unop( Iop_ReinterpF64asI64,
14385 binop( Iop_RoundF64toF32, rm,
14386 triop( Iop_DivF64, rm,
14387 mkexpr( frA ),
14388 mkexpr( frB ) ) ) ),
14389 mkU64( 0 ) ) );
14390 break;
sewardj66d5ef22011-04-15 11:55:00 +000014391 case 0x0E0: // xsdivdp (VSX scalar divide double-precision)
14392 DIP("xsdivdp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14393 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14394 triop( Iop_DivF64, rm,
14395 mkexpr( frA ),
14396 mkexpr( frB ) ) ),
14397 mkU64( 0 ) ) );
14398 break;
carll6c758b62013-10-03 21:38:45 +000014399 case 0x004: case 0x024: /* xsmaddasp, xsmaddmsp (VSX scalar multiply-add
14400 * single-precision)
14401 */
14402 {
14403 IRTemp frT = newTemp(Ity_F64);
14404 Bool mdp = opc2 == 0x024;
14405 DIP("xsmadd%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14406 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14407 getVSReg( XT ) ) ) );
14408 putVSReg( XT,
14409 binop( Iop_64HLtoV128,
14410 unop( Iop_ReinterpF64asI64,
14411 binop( Iop_RoundF64toF32, rm,
14412 qop( Iop_MAddF64, rm,
14413 mkexpr( frA ),
14414 mkexpr( mdp ? frT : frB ),
14415 mkexpr( mdp ? frB : frT ) ) ) ),
14416 mkU64( 0 ) ) );
14417 break;
14418 }
sewardj66d5ef22011-04-15 11:55:00 +000014419 case 0x084: case 0x0A4: // xsmaddadp, xsmaddmdp (VSX scalar multiply-add double-precision)
14420 {
14421 IRTemp frT = newTemp(Ity_F64);
14422 Bool mdp = opc2 == 0x0A4;
14423 DIP("xsmadd%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14424 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14425 getVSReg( XT ) ) ) );
14426 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14427 qop( Iop_MAddF64, rm,
14428 mkexpr( frA ),
14429 mkexpr( mdp ? frT : frB ),
14430 mkexpr( mdp ? frB : frT ) ) ),
14431 mkU64( 0 ) ) );
14432 break;
14433 }
carll6c758b62013-10-03 21:38:45 +000014434 case 0x044: case 0x064: /* xsmsubasp, xsmsubmsp (VSX scalar
14435 * multiply-subtract single-precision)
14436 */
14437 {
14438 IRTemp frT = newTemp(Ity_F64);
14439 Bool mdp = opc2 == 0x064;
14440 DIP("xsmsub%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14441 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14442 getVSReg( XT ) ) ) );
14443 putVSReg( XT,
14444 binop( Iop_64HLtoV128,
14445 unop( Iop_ReinterpF64asI64,
14446 binop( Iop_RoundF64toF32, rm,
14447 qop( Iop_MSubF64, rm,
14448 mkexpr( frA ),
14449 mkexpr( mdp ? frT : frB ),
14450 mkexpr( mdp ? frB : frT ) ) ) ),
14451 mkU64( 0 ) ) );
14452 break;
14453 }
sewardj66d5ef22011-04-15 11:55:00 +000014454 case 0x0C4: case 0x0E4: // xsmsubadp, xsmsubmdp (VSX scalar multiply-subtract double-precision)
14455 {
14456 IRTemp frT = newTemp(Ity_F64);
14457 Bool mdp = opc2 == 0x0E4;
14458 DIP("xsmsub%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14459 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14460 getVSReg( XT ) ) ) );
14461 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14462 qop( Iop_MSubF64, rm,
14463 mkexpr( frA ),
14464 mkexpr( mdp ? frT : frB ),
14465 mkexpr( mdp ? frB : frT ) ) ),
14466 mkU64( 0 ) ) );
14467 break;
14468 }
14469 case 0x284: case 0x2A4: // xsnmaddadp, xsnmaddmdp (VSX scalar multiply-add double-precision)
14470 {
14471 /* TODO: mpj -- Naturally, I expected to be able to leverage the implementation
14472 * of fnmadd and use pretty much the same code. However, that code has a bug in the
14473 * way it blindly negates the signbit, even if the floating point result is a NaN.
14474 * So, the TODO is to fix fnmadd (which I'll do in a different patch).
sewardj2bcdd652012-07-14 08:22:13 +000014475 * FIXED 7/1/2012: carll fnmadd and fnmsubs fixed to not negate sign
14476 * bit for NaN result.
sewardj66d5ef22011-04-15 11:55:00 +000014477 */
sewardj66d5ef22011-04-15 11:55:00 +000014478 Bool mdp = opc2 == 0x2A4;
14479 IRTemp frT = newTemp(Ity_F64);
14480 IRTemp maddResult = newTemp(Ity_I64);
sewardj66d5ef22011-04-15 11:55:00 +000014481
14482 DIP("xsnmadd%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14483 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14484 getVSReg( XT ) ) ) );
14485 assign( maddResult, unop( Iop_ReinterpF64asI64, qop( Iop_MAddF64, rm,
14486 mkexpr( frA ),
14487 mkexpr( mdp ? frT : frB ),
14488 mkexpr( mdp ? frB : frT ) ) ) );
sewardj66d5ef22011-04-15 11:55:00 +000014489
sewardj4aa412a2011-07-24 14:13:21 +000014490 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( getNegatedResult(maddResult) ),
sewardj66d5ef22011-04-15 11:55:00 +000014491 mkU64( 0 ) ) );
14492 break;
14493 }
carll6c758b62013-10-03 21:38:45 +000014494 case 0x204: case 0x224: /* xsnmaddasp, xsnmaddmsp (VSX scalar
14495 * multiply-add single-precision)
14496 */
14497 {
14498 Bool mdp = opc2 == 0x224;
14499 IRTemp frT = newTemp(Ity_F64);
14500 IRTemp maddResult = newTemp(Ity_I64);
14501
14502 DIP("xsnmadd%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14503 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14504 getVSReg( XT ) ) ) );
14505 assign( maddResult,
14506 unop( Iop_ReinterpF64asI64,
14507 binop( Iop_RoundF64toF32, rm,
14508 qop( Iop_MAddF64, rm,
14509 mkexpr( frA ),
14510 mkexpr( mdp ? frT : frB ),
14511 mkexpr( mdp ? frB : frT ) ) ) ) );
14512
14513 putVSReg( XT, binop( Iop_64HLtoV128,
14514 mkexpr( getNegatedResult(maddResult) ),
14515 mkU64( 0 ) ) );
14516 break;
14517 }
14518 case 0x244: case 0x264: /* xsnmsubasp, xsnmsubmsp (VSX Scalar Negative
14519 * Multiply-Subtract Single-Precision)
14520 */
14521 {
14522 IRTemp frT = newTemp(Ity_F64);
14523 Bool mdp = opc2 == 0x264;
14524 IRTemp msubResult = newTemp(Ity_I64);
14525
14526 DIP("xsnmsub%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14527 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14528 getVSReg( XT ) ) ) );
14529 assign( msubResult,
14530 unop( Iop_ReinterpF64asI64,
14531 binop( Iop_RoundF64toF32, rm,
14532 qop( Iop_MSubF64, rm,
14533 mkexpr( frA ),
14534 mkexpr( mdp ? frT : frB ),
14535 mkexpr( mdp ? frB : frT ) ) ) ) );
14536
14537 putVSReg( XT, binop( Iop_64HLtoV128,
14538 mkexpr( getNegatedResult(msubResult) ),
14539 mkU64( 0 ) ) );
14540
14541 break;
14542 }
14543
sewardj4aa412a2011-07-24 14:13:21 +000014544 case 0x2C4: case 0x2E4: // xsnmsubadp, xsnmsubmdp (VSX Scalar Negative Multiply-Subtract Double-Precision)
14545 {
14546 IRTemp frT = newTemp(Ity_F64);
14547 Bool mdp = opc2 == 0x2E4;
14548 IRTemp msubResult = newTemp(Ity_I64);
14549
14550 DIP("xsnmsub%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14551 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14552 getVSReg( XT ) ) ) );
14553 assign(msubResult, unop( Iop_ReinterpF64asI64,
14554 qop( Iop_MSubF64,
14555 rm,
14556 mkexpr( frA ),
14557 mkexpr( mdp ? frT : frB ),
14558 mkexpr( mdp ? frB : frT ) ) ));
14559
14560 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( getNegatedResult(msubResult) ), mkU64( 0 ) ) );
14561
14562 break;
14563 }
14564
carll6c758b62013-10-03 21:38:45 +000014565 case 0x040: // xsmulsp (VSX Scalar Multiply Single-Precision)
14566 DIP("xsmulsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14567 putVSReg( XT, binop( Iop_64HLtoV128,
14568 unop( Iop_ReinterpF64asI64,
14569 binop( Iop_RoundF64toF32, rm,
14570 triop( Iop_MulF64, rm,
14571 mkexpr( frA ),
14572 mkexpr( frB ) ) ) ),
14573 mkU64( 0 ) ) );
14574 break;
14575
sewardj66d5ef22011-04-15 11:55:00 +000014576 case 0x0C0: // xsmuldp (VSX Scalar Multiply Double-Precision)
14577 DIP("xsmuldp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14578 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14579 triop( Iop_MulF64, rm,
14580 mkexpr( frA ),
14581 mkexpr( frB ) ) ),
14582 mkU64( 0 ) ) );
14583 break;
14584 case 0x0A0: // xssubdp (VSX Scalar Subtract Double-Precision)
14585 DIP("xssubdp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14586 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14587 triop( Iop_SubF64, rm,
14588 mkexpr( frA ),
14589 mkexpr( frB ) ) ),
14590 mkU64( 0 ) ) );
14591 break;
14592
carll6c758b62013-10-03 21:38:45 +000014593 case 0x016: // xssqrtsp (VSX Scalar Square Root Single-Precision)
14594 DIP("xssqrtsp v%d,v%d\n", (UInt)XT, (UInt)XB);
14595 putVSReg( XT,
14596 binop( Iop_64HLtoV128,
14597 unop( Iop_ReinterpF64asI64,
14598 binop( Iop_RoundF64toF32, rm,
14599 binop( Iop_SqrtF64, rm,
14600 mkexpr( frB ) ) ) ),
14601 mkU64( 0 ) ) );
14602 break;
14603
sewardj4aa412a2011-07-24 14:13:21 +000014604 case 0x096: // xssqrtdp (VSX Scalar Square Root Double-Precision)
14605 DIP("xssqrtdp v%d,v%d\n", (UInt)XT, (UInt)XB);
14606 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14607 binop( Iop_SqrtF64, rm,
14608 mkexpr( frB ) ) ),
14609 mkU64( 0 ) ) );
14610 break;
14611
14612 case 0x0F4: // xstdivdp (VSX Scalar Test for software Divide Double-Precision)
14613 {
14614 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
14615 IRTemp frA_I64 = newTemp(Ity_I64);
14616 IRTemp frB_I64 = newTemp(Ity_I64);
14617 DIP("xstdivdp crf%d,v%d,v%d\n", crfD, (UInt)XA, (UInt)XB);
14618 assign( frA_I64, unop( Iop_ReinterpF64asI64, mkexpr( frA ) ) );
14619 assign( frB_I64, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
14620 putGST_field( PPC_GST_CR, do_fp_tdiv(frA_I64, frB_I64), crfD );
14621 break;
14622 }
sewardje71e56a2011-09-05 12:11:06 +000014623 case 0x0D4: // xstsqrtdp (VSX Vector Test for software Square Root Double-Precision)
14624 {
14625 IRTemp frB_I64 = newTemp(Ity_I64);
14626 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
14627 IRTemp flags = newTemp(Ity_I32);
14628 IRTemp fe_flag, fg_flag;
14629 fe_flag = fg_flag = IRTemp_INVALID;
14630 DIP("xstsqrtdp v%d,v%d\n", (UInt)XT, (UInt)XB);
14631 assign( frB_I64, unop(Iop_V128HIto64, getVSReg( XB )) );
14632 do_fp_tsqrt(frB_I64, False /*not single precision*/, &fe_flag, &fg_flag);
14633 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
14634 * where fl_flag == 1 on ppc64.
14635 */
14636 assign( flags,
14637 binop( Iop_Or32,
14638 binop( Iop_Or32, mkU32( 8 ), // fl_flag
14639 binop( Iop_Shl32, mkexpr(fg_flag), mkU8( 2 ) ) ),
14640 binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) ) );
14641 putGST_field( PPC_GST_CR, mkexpr(flags), crfD );
14642 break;
14643 }
sewardj4aa412a2011-07-24 14:13:21 +000014644
sewardj66d5ef22011-04-15 11:55:00 +000014645 default:
sewardj4aa412a2011-07-24 14:13:21 +000014646 vex_printf( "dis_vxs_arith(ppc)(opc2)\n" );
sewardj66d5ef22011-04-15 11:55:00 +000014647 return False;
14648 }
sewardj4aa412a2011-07-24 14:13:21 +000014649
sewardj66d5ef22011-04-15 11:55:00 +000014650 return True;
14651}
14652
sewardj4aa412a2011-07-24 14:13:21 +000014653
sewardj66d5ef22011-04-15 11:55:00 +000014654/*
14655 * VSX Floating Point Compare Instructions
14656 */
14657static Bool
14658dis_vx_cmp( UInt theInstr, UInt opc2 )
14659{
14660 /* XX3-Form and XX2-Form */
14661 UChar opc1 = ifieldOPC( theInstr );
14662 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
sewardj4aa412a2011-07-24 14:13:21 +000014663 IRTemp ccPPC32;
sewardj66d5ef22011-04-15 11:55:00 +000014664 UChar XA = ifieldRegXA ( theInstr );
14665 UChar XB = ifieldRegXB ( theInstr );
14666 IRTemp frA = newTemp(Ity_F64);
14667 IRTemp frB = newTemp(Ity_F64);
14668
14669 if (opc1 != 0x3C) {
14670 vex_printf( "dis_vx_cmp(ppc)(instr)\n" );
14671 return False;
14672 }
14673
14674 assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
14675 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
14676 switch (opc2) {
14677 case 0x08C: case 0x0AC: // xscmpudp, xscmpodp
14678 /* Note: Differences between xscmpudp and xscmpodp are only in
14679 * exception flag settings, which aren't supported anyway. */
14680 DIP("xscmp%sdp crf%d,fr%u,fr%u\n", opc2 == 0x08c ? "u" : "o",
14681 crfD, (UInt)XA, (UInt)XB);
sewardj4aa412a2011-07-24 14:13:21 +000014682 ccPPC32 = get_fp_cmp_CR_val( binop(Iop_CmpF64, mkexpr(frA), mkexpr(frB)));
sewardj66d5ef22011-04-15 11:55:00 +000014683 putGST_field( PPC_GST_CR, mkexpr(ccPPC32), crfD );
sewardj66d5ef22011-04-15 11:55:00 +000014684 break;
sewardj4aa412a2011-07-24 14:13:21 +000014685
sewardj66d5ef22011-04-15 11:55:00 +000014686 default:
14687 vex_printf( "dis_vx_cmp(ppc)(opc2)\n" );
14688 return False;
14689 }
14690 return True;
14691}
sewardj4aa412a2011-07-24 14:13:21 +000014692
14693static void
14694do_vvec_fp_cmp ( IRTemp vA, IRTemp vB, UChar XT, UChar flag_rC,
14695 ppc_cmp_t cmp_type )
14696{
14697 IRTemp frA_hi = newTemp(Ity_F64);
14698 IRTemp frB_hi = newTemp(Ity_F64);
14699 IRTemp frA_lo = newTemp(Ity_F64);
14700 IRTemp frB_lo = newTemp(Ity_F64);
14701 IRTemp ccPPC32 = newTemp(Ity_I32);
14702 IRTemp ccIR_hi;
14703 IRTemp ccIR_lo;
14704
14705 IRTemp hiResult = newTemp(Ity_I64);
14706 IRTemp loResult = newTemp(Ity_I64);
14707 IRTemp hiEQlo = newTemp(Ity_I1);
14708 IRTemp all_elem_true = newTemp(Ity_I32);
14709 IRTemp all_elem_false = newTemp(Ity_I32);
14710
14711 assign(frA_hi, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, mkexpr( vA ))));
14712 assign(frB_hi, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, mkexpr( vB ))));
14713 assign(frA_lo, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, mkexpr( vA ))));
14714 assign(frB_lo, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, mkexpr( vB ))));
14715
14716 ccIR_hi = get_fp_cmp_CR_val( binop( Iop_CmpF64,
14717 mkexpr( frA_hi ),
14718 mkexpr( frB_hi ) ) );
14719 ccIR_lo = get_fp_cmp_CR_val( binop( Iop_CmpF64,
14720 mkexpr( frA_lo ),
14721 mkexpr( frB_lo ) ) );
14722
14723 if (cmp_type != PPC_CMP_GE) {
14724 assign( hiResult,
14725 unop( Iop_1Sto64,
14726 binop( Iop_CmpEQ32, mkexpr( ccIR_hi ), mkU32( cmp_type ) ) ) );
14727 assign( loResult,
14728 unop( Iop_1Sto64,
14729 binop( Iop_CmpEQ32, mkexpr( ccIR_lo ), mkU32( cmp_type ) ) ) );
14730 } else {
14731 // For PPC_CMP_GE, one element compare may return "4" (for "greater than") and
14732 // the other element compare may return "2" (for "equal to").
14733 IRTemp lo_GE = newTemp(Ity_I1);
14734 IRTemp hi_GE = newTemp(Ity_I1);
14735
14736 assign(hi_GE, mkOR1( binop( Iop_CmpEQ32, mkexpr( ccIR_hi ), mkU32( 2 ) ),
14737 binop( Iop_CmpEQ32, mkexpr( ccIR_hi ), mkU32( 4 ) ) ) );
14738 assign( hiResult,unop( Iop_1Sto64, mkexpr( hi_GE ) ) );
14739
14740 assign(lo_GE, mkOR1( binop( Iop_CmpEQ32, mkexpr( ccIR_lo ), mkU32( 2 ) ),
14741 binop( Iop_CmpEQ32, mkexpr( ccIR_lo ), mkU32( 4 ) ) ) );
14742 assign( loResult, unop( Iop_1Sto64, mkexpr( lo_GE ) ) );
14743 }
14744
14745 // The [hi/lo]Result will be all 1's or all 0's. We just look at the lower word.
14746 assign( hiEQlo,
14747 binop( Iop_CmpEQ32,
14748 unop( Iop_64to32, mkexpr( hiResult ) ),
14749 unop( Iop_64to32, mkexpr( loResult ) ) ) );
14750 putVSReg( XT,
14751 binop( Iop_64HLtoV128, mkexpr( hiResult ), mkexpr( loResult ) ) );
14752
14753 assign( all_elem_true,
14754 unop( Iop_1Uto32,
14755 mkAND1( mkexpr( hiEQlo ),
14756 binop( Iop_CmpEQ32,
14757 mkU32( 0xffffffff ),
14758 unop( Iop_64to32,
14759 mkexpr( hiResult ) ) ) ) ) );
14760
14761 assign( all_elem_false,
14762 unop( Iop_1Uto32,
14763 mkAND1( mkexpr( hiEQlo ),
14764 binop( Iop_CmpEQ32,
14765 mkU32( 0 ),
14766 unop( Iop_64to32,
14767 mkexpr( hiResult ) ) ) ) ) );
14768 assign( ccPPC32,
14769 binop( Iop_Or32,
14770 binop( Iop_Shl32, mkexpr( all_elem_false ), mkU8( 1 ) ),
14771 binop( Iop_Shl32, mkexpr( all_elem_true ), mkU8( 3 ) ) ) );
14772
14773 if (flag_rC) {
14774 putGST_field( PPC_GST_CR, mkexpr(ccPPC32), 6 );
14775 }
14776}
14777
sewardj66d5ef22011-04-15 11:55:00 +000014778/*
sewardj4aa412a2011-07-24 14:13:21 +000014779 * VSX Vector Compare Instructions
sewardj66d5ef22011-04-15 11:55:00 +000014780 */
14781static Bool
sewardj4aa412a2011-07-24 14:13:21 +000014782dis_vvec_cmp( UInt theInstr, UInt opc2 )
14783{
14784 /* XX3-Form */
14785 UChar opc1 = ifieldOPC( theInstr );
14786 UChar XT = ifieldRegXT ( theInstr );
14787 UChar XA = ifieldRegXA ( theInstr );
14788 UChar XB = ifieldRegXB ( theInstr );
14789 UChar flag_rC = ifieldBIT10(theInstr);
14790 IRTemp vA = newTemp( Ity_V128 );
14791 IRTemp vB = newTemp( Ity_V128 );
14792
14793 if (opc1 != 0x3C) {
14794 vex_printf( "dis_vvec_cmp(ppc)(instr)\n" );
14795 return False;
14796 }
14797
14798 assign( vA, getVSReg( XA ) );
14799 assign( vB, getVSReg( XB ) );
14800
14801 switch (opc2) {
14802 case 0x18C: case 0x38C: // xvcmpeqdp[.] (VSX Vector Compare Equal To Double-Precision [ & Record ])
14803 {
14804 DIP("xvcmpeqdp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
14805 (UInt)XT, (UInt)XA, (UInt)XB);
14806 do_vvec_fp_cmp(vA, vB, XT, flag_rC, PPC_CMP_EQ);
14807 break;
14808 }
14809
14810 case 0x1CC: case 0x3CC: // xvcmpgedp[.] (VSX Vector Compare Greater Than or Equal To Double-Precision [ & Record ])
14811 {
14812 DIP("xvcmpgedp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
14813 (UInt)XT, (UInt)XA, (UInt)XB);
14814 do_vvec_fp_cmp(vA, vB, XT, flag_rC, PPC_CMP_GE);
14815 break;
14816 }
14817
14818 case 0x1AC: case 0x3AC: // xvcmpgtdp[.] (VSX Vector Compare Greater Than Double-Precision [ & Record ])
14819 {
14820 DIP("xvcmpgtdp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
14821 (UInt)XT, (UInt)XA, (UInt)XB);
14822 do_vvec_fp_cmp(vA, vB, XT, flag_rC, PPC_CMP_GT);
14823 break;
14824 }
14825
14826 case 0x10C: case 0x30C: // xvcmpeqsp[.] (VSX Vector Compare Equal To Single-Precision [ & Record ])
14827 {
14828 IRTemp vD = newTemp(Ity_V128);
14829
14830 DIP("xvcmpeqsp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
14831 (UInt)XT, (UInt)XA, (UInt)XB);
14832 assign( vD, binop(Iop_CmpEQ32Fx4, mkexpr(vA), mkexpr(vB)) );
14833 putVSReg( XT, mkexpr(vD) );
14834 if (flag_rC) {
14835 set_AV_CR6( mkexpr(vD), True );
14836 }
14837 break;
14838 }
14839
14840 case 0x14C: case 0x34C: // xvcmpgesp[.] (VSX Vector Compare Greater Than or Equal To Single-Precision [ & Record ])
14841 {
14842 IRTemp vD = newTemp(Ity_V128);
14843
14844 DIP("xvcmpgesp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
14845 (UInt)XT, (UInt)XA, (UInt)XB);
14846 assign( vD, binop(Iop_CmpGE32Fx4, mkexpr(vA), mkexpr(vB)) );
14847 putVSReg( XT, mkexpr(vD) );
14848 if (flag_rC) {
14849 set_AV_CR6( mkexpr(vD), True );
14850 }
14851 break;
14852 }
14853
14854 case 0x12C: case 0x32C: //xvcmpgtsp[.] (VSX Vector Compare Greater Than Single-Precision [ & Record ])
14855 {
14856 IRTemp vD = newTemp(Ity_V128);
14857
14858 DIP("xvcmpgtsp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
14859 (UInt)XT, (UInt)XA, (UInt)XB);
14860 assign( vD, binop(Iop_CmpGT32Fx4, mkexpr(vA), mkexpr(vB)) );
14861 putVSReg( XT, mkexpr(vD) );
14862 if (flag_rC) {
14863 set_AV_CR6( mkexpr(vD), True );
14864 }
14865 break;
14866 }
14867
14868 default:
14869 vex_printf( "dis_vvec_cmp(ppc)(opc2)\n" );
14870 return False;
14871 }
14872 return True;
14873}
14874/*
14875 * Miscellaneous VSX Scalar Instructions
14876 */
14877static Bool
14878dis_vxs_misc( UInt theInstr, UInt opc2 )
sewardj66d5ef22011-04-15 11:55:00 +000014879{
carll1f5fe1f2014-08-07 23:25:23 +000014880#define VG_PPC_SIGN_MASK 0x7fffffffffffffffULL
sewardj66d5ef22011-04-15 11:55:00 +000014881 /* XX3-Form and XX2-Form */
14882 UChar opc1 = ifieldOPC( theInstr );
14883 UChar XT = ifieldRegXT ( theInstr );
14884 UChar XA = ifieldRegXA ( theInstr );
14885 UChar XB = ifieldRegXB ( theInstr );
14886 IRTemp vA = newTemp( Ity_V128 );
14887 IRTemp vB = newTemp( Ity_V128 );
14888
14889 if (opc1 != 0x3C) {
sewardj4aa412a2011-07-24 14:13:21 +000014890 vex_printf( "dis_vxs_misc(ppc)(instr)\n" );
sewardj66d5ef22011-04-15 11:55:00 +000014891 return False;
14892 }
14893
14894 assign( vA, getVSReg( XA ) );
14895 assign( vB, getVSReg( XB ) );
14896
14897 /* For all the VSX move instructions, the contents of doubleword element 1
14898 * of VSX[XT] are undefined after the operation; therefore, we can simply
14899 * move the entire array element where it makes sense to do so.
14900 */
14901
14902 switch (opc2) {
14903 case 0x2B2: // xsabsdp (VSX scalar absolute value double-precision
14904 {
14905 /* Move abs val of dw 0 of VSX[XB] to dw 0 of VSX[XT]. */
14906 IRTemp absVal = newTemp(Ity_V128);
carll1f5fe1f2014-08-07 23:25:23 +000014907 if (host_endness == VexEndnessLE) {
14908 IRTemp hi64 = newTemp(Ity_I64);
14909 IRTemp lo64 = newTemp(Ity_I64);
14910 assign( hi64, unop( Iop_V128HIto64, mkexpr(vB) ) );
14911 assign( lo64, unop( Iop_V128to64, mkexpr(vB) ) );
14912 assign( absVal, binop( Iop_64HLtoV128,
14913 binop( Iop_And64, mkexpr(hi64),
14914 mkU64(VG_PPC_SIGN_MASK) ),
14915 mkexpr(lo64) ) );
14916 } else {
14917 assign(absVal, binop(Iop_ShrV128,
14918 binop(Iop_ShlV128, mkexpr(vB),
14919 mkU8(1)), mkU8(1)));
14920 }
sewardj66d5ef22011-04-15 11:55:00 +000014921 DIP("xsabsdp v%d,v%d\n", (UInt)XT, (UInt)XB);
14922 putVSReg(XT, mkexpr(absVal));
14923 break;
14924 }
14925 case 0x2C0: // xscpsgndp
14926 {
14927 /* Scalar copy sign double-precision */
carll1f5fe1f2014-08-07 23:25:23 +000014928 IRTemp vecA_signed = newTemp(Ity_I64);
14929 IRTemp vecB_unsigned = newTemp(Ity_I64);
sewardj66d5ef22011-04-15 11:55:00 +000014930 IRTemp vec_result = newTemp(Ity_V128);
14931 DIP("xscpsgndp v%d,v%d v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
carll1f5fe1f2014-08-07 23:25:23 +000014932 assign( vecA_signed, binop( Iop_And64,
14933 unop( Iop_V128HIto64,
14934 mkexpr(vA)),
14935 mkU64(~VG_PPC_SIGN_MASK) ) );
14936 assign( vecB_unsigned, binop( Iop_And64,
14937 unop( Iop_V128HIto64,
14938 mkexpr(vB) ),
14939 mkU64(VG_PPC_SIGN_MASK) ) );
14940 assign( vec_result, binop( Iop_64HLtoV128,
14941 binop( Iop_Or64,
14942 mkexpr(vecA_signed),
14943 mkexpr(vecB_unsigned) ),
14944 mkU64(0x0ULL)));
sewardj66d5ef22011-04-15 11:55:00 +000014945 putVSReg(XT, mkexpr(vec_result));
14946 break;
14947 }
14948 case 0x2D2: // xsnabsdp
14949 {
14950 /* Scalar negative absolute value double-precision */
carll1f5fe1f2014-08-07 23:25:23 +000014951 IRTemp BHi_signed = newTemp(Ity_I64);
sewardj66d5ef22011-04-15 11:55:00 +000014952 DIP("xsnabsdp v%d,v%d\n", (UInt)XT, (UInt)XB);
carll1f5fe1f2014-08-07 23:25:23 +000014953 assign( BHi_signed, binop( Iop_Or64,
14954 unop( Iop_V128HIto64,
14955 mkexpr(vB) ),
14956 mkU64(~VG_PPC_SIGN_MASK) ) );
14957 putVSReg(XT, binop( Iop_64HLtoV128,
14958 mkexpr(BHi_signed), mkU64(0x0ULL) ) );
sewardj66d5ef22011-04-15 11:55:00 +000014959 break;
14960 }
14961 case 0x2F2: // xsnegdp
14962 {
14963 /* Scalar negate double-precision */
carll1f5fe1f2014-08-07 23:25:23 +000014964 IRTemp BHi_signed = newTemp(Ity_I64);
14965 IRTemp BHi_unsigned = newTemp(Ity_I64);
14966 IRTemp BHi_negated = newTemp(Ity_I64);
14967 IRTemp BHi_negated_signbit = newTemp(Ity_I1);
14968 IRTemp vec_result = newTemp(Ity_V128);
sewardj66d5ef22011-04-15 11:55:00 +000014969 DIP("xsnabsdp v%d,v%d\n", (UInt)XT, (UInt)XB);
carll1f5fe1f2014-08-07 23:25:23 +000014970 assign( BHi_signed, unop( Iop_V128HIto64, mkexpr(vB) ) );
14971 assign( BHi_unsigned, binop( Iop_And64, mkexpr(BHi_signed),
14972 mkU64(VG_PPC_SIGN_MASK) ) );
14973 assign( BHi_negated_signbit,
14974 unop( Iop_Not1,
14975 unop( Iop_32to1,
14976 binop( Iop_Shr32,
14977 unop( Iop_64HIto32,
14978 binop( Iop_And64,
14979 mkexpr(BHi_signed),
14980 mkU64(~VG_PPC_SIGN_MASK) )
14981 ),
14982 mkU8(31) ) ) ) );
14983 assign( BHi_negated,
14984 binop( Iop_Or64,
14985 binop( Iop_32HLto64,
14986 binop( Iop_Shl32,
14987 unop( Iop_1Uto32,
14988 mkexpr(BHi_negated_signbit) ),
14989 mkU8(31) ),
14990 mkU32(0) ),
14991 mkexpr(BHi_unsigned) ) );
14992 assign( vec_result, binop( Iop_64HLtoV128, mkexpr(BHi_negated),
14993 mkU64(0x0ULL)));
14994 putVSReg( XT, mkexpr(vec_result));
sewardj66d5ef22011-04-15 11:55:00 +000014995 break;
14996 }
sewardj4aa412a2011-07-24 14:13:21 +000014997 case 0x280: // xsmaxdp (VSX Scalar Maximum Double-Precision)
14998 case 0x2A0: // xsmindp (VSX Scalar Minimum Double-Precision)
14999 {
15000 IRTemp frA = newTemp(Ity_I64);
15001 IRTemp frB = newTemp(Ity_I64);
15002 Bool isMin = opc2 == 0x2A0 ? True : False;
15003 DIP("%s v%d,v%d v%d\n", isMin ? "xsmaxdp" : "xsmindp", (UInt)XT, (UInt)XA, (UInt)XB);
15004
15005 assign(frA, unop(Iop_V128HIto64, mkexpr( vA )));
15006 assign(frB, unop(Iop_V128HIto64, mkexpr( vB )));
15007 putVSReg( XT, binop( Iop_64HLtoV128, get_max_min_fp(frA, frB, isMin), mkU64( 0 ) ) );
15008
15009 break;
15010 }
15011 case 0x0F2: // xsrdpim (VSX Scalar Round to Double-Precision Integer using round toward -Infinity)
sewardje71e56a2011-09-05 12:11:06 +000015012 case 0x0D2: // xsrdpip (VSX Scalar Round to Double-Precision Integer using round toward +Infinity)
15013 case 0x0D6: // xsrdpic (VSX Scalar Round to Double-Precision Integer using Current rounding mode)
15014 case 0x0B2: // xsrdpiz (VSX Scalar Round to Double-Precision Integer using round toward Zero)
15015 case 0x092: // xsrdpi (VSX Scalar Round to Double-Precision Integer using round toward Nearest Away)
sewardj4aa412a2011-07-24 14:13:21 +000015016 {
sewardj4aa412a2011-07-24 14:13:21 +000015017 IRTemp frB_I64 = newTemp(Ity_I64);
sewardje71e56a2011-09-05 12:11:06 +000015018 IRExpr * frD_fp_round = NULL;
sewardje71e56a2011-09-05 12:11:06 +000015019
sewardj4aa412a2011-07-24 14:13:21 +000015020 assign(frB_I64, unop(Iop_V128HIto64, mkexpr( vB )));
carll9884af02013-01-30 18:39:57 +000015021 frD_fp_round = _do_vsx_fp_roundToInt(frB_I64, opc2);
sewardj4aa412a2011-07-24 14:13:21 +000015022
carll9884af02013-01-30 18:39:57 +000015023 DIP("xsrdpi%s v%d,v%d\n", _get_vsx_rdpi_suffix(opc2), (UInt)XT, (UInt)XB);
sewardj4aa412a2011-07-24 14:13:21 +000015024 putVSReg( XT,
15025 binop( Iop_64HLtoV128,
sewardje71e56a2011-09-05 12:11:06 +000015026 unop( Iop_ReinterpF64asI64, frD_fp_round),
sewardj4aa412a2011-07-24 14:13:21 +000015027 mkU64( 0 ) ) );
sewardje71e56a2011-09-05 12:11:06 +000015028 break;
15029 }
carll6c758b62013-10-03 21:38:45 +000015030 case 0x034: // xsresp (VSX Scalar Reciprocal Estimate single-Precision)
15031 case 0x014: /* xsrsqrtesp (VSX Scalar Reciprocal Square Root Estimate
15032 * single-Precision)
15033 */
15034 {
15035 IRTemp frB = newTemp(Ity_F64);
15036 IRTemp sqrt = newTemp(Ity_F64);
15037 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
15038 IRExpr* rm = get_IR_roundingmode();
15039 Bool redp = opc2 == 0x034;
15040 DIP("%s v%d,v%d\n", redp ? "xsresp" : "xsrsqrtesp", (UInt)XT,
15041 (UInt)XB);
15042
15043 assign( frB,
15044 unop( Iop_ReinterpI64asF64,
15045 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
15046
15047 if (!redp)
15048 assign( sqrt,
15049 binop( Iop_SqrtF64,
15050 rm,
15051 mkexpr(frB) ) );
15052 putVSReg( XT,
15053 binop( Iop_64HLtoV128,
15054 unop( Iop_ReinterpF64asI64,
15055 binop( Iop_RoundF64toF32, rm,
15056 triop( Iop_DivF64,
15057 rm,
15058 ieee_one,
15059 redp ? mkexpr( frB ) :
15060 mkexpr( sqrt ) ) ) ),
15061 mkU64( 0 ) ) );
15062 break;
15063 }
15064
sewardje71e56a2011-09-05 12:11:06 +000015065 case 0x0B4: // xsredp (VSX Scalar Reciprocal Estimate Double-Precision)
15066 case 0x094: // xsrsqrtedp (VSX Scalar Reciprocal Square Root Estimate Double-Precision)
sewardj4aa412a2011-07-24 14:13:21 +000015067
sewardje71e56a2011-09-05 12:11:06 +000015068 {
15069 IRTemp frB = newTemp(Ity_F64);
15070 IRTemp sqrt = newTemp(Ity_F64);
15071 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
15072 IRExpr* rm = get_IR_roundingmode();
15073 Bool redp = opc2 == 0x0B4;
15074 DIP("%s v%d,v%d\n", redp ? "xsredp" : "xsrsqrtedp", (UInt)XT, (UInt)XB);
15075 assign( frB,
15076 unop( Iop_ReinterpI64asF64,
15077 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
15078
15079 if (!redp)
15080 assign( sqrt,
15081 binop( Iop_SqrtF64,
15082 rm,
15083 mkexpr(frB) ) );
15084 putVSReg( XT,
15085 binop( Iop_64HLtoV128,
15086 unop( Iop_ReinterpF64asI64,
15087 triop( Iop_DivF64,
15088 rm,
15089 ieee_one,
15090 redp ? mkexpr( frB ) : mkexpr( sqrt ) ) ),
15091 mkU64( 0 ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000015092 break;
15093 }
sewardj66d5ef22011-04-15 11:55:00 +000015094
carll6c758b62013-10-03 21:38:45 +000015095 case 0x232: // xsrsp (VSX Scalar Round to Single-Precision)
15096 {
15097 IRTemp frB = newTemp(Ity_F64);
15098 IRExpr* rm = get_IR_roundingmode();
15099 DIP("xsrsp v%d, v%d\n", (UInt)XT, (UInt)XB);
15100 assign( frB,
15101 unop( Iop_ReinterpI64asF64,
15102 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
15103
15104 putVSReg( XT, binop( Iop_64HLtoV128,
15105 unop( Iop_ReinterpF64asI64,
15106 binop( Iop_RoundF64toF32,
15107 rm,
15108 mkexpr( frB ) ) ),
15109 mkU64( 0 ) ) );
15110 break;
15111 }
15112
sewardj66d5ef22011-04-15 11:55:00 +000015113 default:
sewardj4aa412a2011-07-24 14:13:21 +000015114 vex_printf( "dis_vxs_misc(ppc)(opc2)\n" );
sewardj66d5ef22011-04-15 11:55:00 +000015115 return False;
15116 }
15117 return True;
15118}
15119
15120/*
15121 * VSX Logical Instructions
15122 */
15123static Bool
15124dis_vx_logic ( UInt theInstr, UInt opc2 )
15125{
15126 /* XX3-Form */
15127 UChar opc1 = ifieldOPC( theInstr );
15128 UChar XT = ifieldRegXT ( theInstr );
15129 UChar XA = ifieldRegXA ( theInstr );
15130 UChar XB = ifieldRegXB ( theInstr );
15131 IRTemp vA = newTemp( Ity_V128 );
15132 IRTemp vB = newTemp( Ity_V128 );
15133
15134 if (opc1 != 0x3C) {
15135 vex_printf( "dis_vx_logic(ppc)(instr)\n" );
15136 return False;
15137 }
15138
15139 assign( vA, getVSReg( XA ) );
15140 assign( vB, getVSReg( XB ) );
15141
15142 switch (opc2) {
15143 case 0x268: // xxlxor
15144 DIP("xxlxor v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15145 putVSReg( XT, binop( Iop_XorV128, mkexpr( vA ), mkexpr( vB ) ) );
15146 break;
15147 case 0x248: // xxlor
15148 DIP("xxlor v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15149 putVSReg( XT, binop( Iop_OrV128, mkexpr( vA ), mkexpr( vB ) ) );
15150 break;
15151 case 0x288: // xxlnor
15152 DIP("xxlnor v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15153 putVSReg( XT, unop( Iop_NotV128, binop( Iop_OrV128, mkexpr( vA ),
15154 mkexpr( vB ) ) ) );
15155 break;
15156 case 0x208: // xxland
15157 DIP("xxland v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15158 putVSReg( XT, binop( Iop_AndV128, mkexpr( vA ), mkexpr( vB ) ) );
15159 break;
15160 case 0x228: //xxlandc
15161 DIP("xxlandc v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15162 putVSReg( XT, binop( Iop_AndV128, mkexpr( vA ), unop( Iop_NotV128,
15163 mkexpr( vB ) ) ) );
15164 break;
carll6c758b62013-10-03 21:38:45 +000015165 case 0x2A8: // xxlorc (VSX Logical OR with complement)
15166 DIP("xxlorc v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15167 putVSReg( XT, binop( Iop_OrV128,
15168 mkexpr( vA ),
15169 unop( Iop_NotV128, mkexpr( vB ) ) ) );
15170 break;
15171 case 0x2C8: // xxlnand (VSX Logical NAND)
15172 DIP("xxlnand v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15173 putVSReg( XT, unop( Iop_NotV128,
15174 binop( Iop_AndV128, mkexpr( vA ),
15175 mkexpr( vB ) ) ) );
15176 break;
15177 case 0x2E8: // xxleqv (VSX Logical Equivalence)
15178 DIP("xxleqv v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15179 putVSReg( XT, unop( Iop_NotV128,
15180 binop( Iop_XorV128,
15181 mkexpr( vA ), mkexpr( vB ) ) ) );
15182 break;
sewardj66d5ef22011-04-15 11:55:00 +000015183 default:
15184 vex_printf( "dis_vx_logic(ppc)(opc2)\n" );
15185 return False;
15186 }
15187 return True;
15188}
15189
15190/*
15191 * VSX Load Instructions
15192 * NOTE: VSX supports word-aligned storage access.
15193 */
15194static Bool
15195dis_vx_load ( UInt theInstr )
15196{
15197 /* XX1-Form */
15198 UChar opc1 = ifieldOPC( theInstr );
15199 UChar XT = ifieldRegXT ( theInstr );
15200 UChar rA_addr = ifieldRegA( theInstr );
15201 UChar rB_addr = ifieldRegB( theInstr );
15202 UInt opc2 = ifieldOPClo10( theInstr );
15203
15204 IRType ty = mode64 ? Ity_I64 : Ity_I32;
15205 IRTemp EA = newTemp( ty );
15206
15207 if (opc1 != 0x1F) {
15208 vex_printf( "dis_vx_load(ppc)(instr)\n" );
15209 return False;
15210 }
15211
15212 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
15213
15214 switch (opc2) {
carll6c758b62013-10-03 21:38:45 +000015215 case 0x00C: // lxsiwzx (Load VSX Scalar as Integer Word and Zero Indexed)
15216 {
15217 IRExpr * exp;
15218 DIP("lxsiwzx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015219 exp = unop( Iop_64HIto32, load( Ity_I64, mkexpr( EA ) ) );
carll6c758b62013-10-03 21:38:45 +000015220 putVSReg( XT, binop( Iop_64HLtoV128,
15221 unop( Iop_32Uto64, exp),
15222 mkU64(0) ) );
15223 break;
15224 }
15225 case 0x04C: // lxsiwax (Load VSX Scalar as Integer Word Algebraic Indexed)
15226 {
15227 IRExpr * exp;
15228 DIP("lxsiwax %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015229 exp = unop( Iop_64HIto32, load( Ity_I64, mkexpr( EA ) ) );
carll6c758b62013-10-03 21:38:45 +000015230 putVSReg( XT, binop( Iop_64HLtoV128,
15231 unop( Iop_32Sto64, exp),
15232 mkU64(0) ) );
15233 break;
15234 }
15235 case 0x20C: // lxsspx (Load VSX Scalar Single-Precision Indexed)
15236 {
15237 IRExpr * exp;
15238 DIP("lxsspx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
15239 /* Take 32-bit floating point value in the upper half of the fetched
15240 * 64-bit value, convert to 64-bit floating point value and load into
15241 * top word of V128.
15242 */
15243 exp = unop( Iop_ReinterpF64asI64,
15244 unop( Iop_F32toF64,
15245 unop( Iop_ReinterpI32asF32,
carll1f5fe1f2014-08-07 23:25:23 +000015246 load( Ity_I32, mkexpr( EA ) ) ) ) );
carll6c758b62013-10-03 21:38:45 +000015247
15248 putVSReg( XT, binop( Iop_64HLtoV128, exp, mkU64( 0 ) ) );
15249 break;
15250 }
sewardj66d5ef22011-04-15 11:55:00 +000015251 case 0x24C: // lxsdx
15252 {
15253 IRExpr * exp;
15254 DIP("lxsdx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015255 exp = load( Ity_I64, mkexpr( EA ) );
sewardj66d5ef22011-04-15 11:55:00 +000015256 // We need to pass an expression of type Ity_V128 with putVSReg, but the load
15257 // we just performed is only a DW. But since the contents of VSR[XT] element 1
15258 // are undefined after this operation, we can just do a splat op.
15259 putVSReg( XT, binop( Iop_64HLtoV128, exp, exp ) );
15260 break;
15261 }
15262 case 0x34C: // lxvd2x
15263 {
15264 IROp addOp = ty == Ity_I64 ? Iop_Add64 : Iop_Add32;
15265 IRExpr * high, *low;
15266 ULong ea_off = 8;
15267 IRExpr* high_addr;
15268 DIP("lxvd2x %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015269 high = load( Ity_I64, mkexpr( EA ) );
sewardj66d5ef22011-04-15 11:55:00 +000015270 high_addr = binop( addOp, mkexpr( EA ), ty == Ity_I64 ? mkU64( ea_off )
15271 : mkU32( ea_off ) );
carll1f5fe1f2014-08-07 23:25:23 +000015272 low = load( Ity_I64, high_addr );
sewardj66d5ef22011-04-15 11:55:00 +000015273 putVSReg( XT, binop( Iop_64HLtoV128, high, low ) );
15274 break;
15275 }
15276 case 0x14C: // lxvdsx
15277 {
15278 IRTemp data = newTemp(Ity_I64);
15279 DIP("lxvdsx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015280 assign( data, load( Ity_I64, mkexpr( EA ) ) );
sewardj66d5ef22011-04-15 11:55:00 +000015281 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( data ), mkexpr( data ) ) );
15282 break;
15283 }
15284 case 0x30C:
15285 {
15286 IRExpr * t3, *t2, *t1, *t0;
15287 UInt ea_off = 0;
15288 IRExpr* irx_addr;
15289
15290 DIP("lxvw4x %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015291 t3 = load( Ity_I32, mkexpr( EA ) );
sewardj66d5ef22011-04-15 11:55:00 +000015292 ea_off += 4;
15293 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
15294 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
carll1f5fe1f2014-08-07 23:25:23 +000015295 t2 = load( Ity_I32, irx_addr );
sewardj66d5ef22011-04-15 11:55:00 +000015296 ea_off += 4;
15297 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
15298 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
carll1f5fe1f2014-08-07 23:25:23 +000015299 t1 = load( Ity_I32, irx_addr );
sewardj66d5ef22011-04-15 11:55:00 +000015300 ea_off += 4;
15301 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
15302 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
carll1f5fe1f2014-08-07 23:25:23 +000015303 t0 = load( Ity_I32, irx_addr );
sewardj66d5ef22011-04-15 11:55:00 +000015304 putVSReg( XT, binop( Iop_64HLtoV128, binop( Iop_32HLto64, t3, t2 ),
15305 binop( Iop_32HLto64, t1, t0 ) ) );
15306 break;
15307 }
15308 default:
15309 vex_printf( "dis_vx_load(ppc)(opc2)\n" );
15310 return False;
15311 }
15312 return True;
15313}
15314
15315/*
15316 * VSX Store Instructions
15317 * NOTE: VSX supports word-aligned storage access.
15318 */
15319static Bool
15320dis_vx_store ( UInt theInstr )
15321{
15322 /* XX1-Form */
15323 UChar opc1 = ifieldOPC( theInstr );
15324 UChar XS = ifieldRegXS( theInstr );
15325 UChar rA_addr = ifieldRegA( theInstr );
15326 UChar rB_addr = ifieldRegB( theInstr );
15327 IRTemp vS = newTemp( Ity_V128 );
15328 UInt opc2 = ifieldOPClo10( theInstr );
15329
15330 IRType ty = mode64 ? Ity_I64 : Ity_I32;
15331 IRTemp EA = newTemp( ty );
15332
15333 if (opc1 != 0x1F) {
15334 vex_printf( "dis_vx_store(ppc)(instr)\n" );
15335 return False;
15336 }
15337
15338 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
15339 assign( vS, getVSReg( XS ) );
15340
15341 switch (opc2) {
carll6c758b62013-10-03 21:38:45 +000015342 case 0x08C:
15343 {
15344 /* Need the next to the most significant 32-bit word from
15345 * the 128-bit vector.
15346 */
15347 IRExpr * high64, * low32;
15348 DIP("stxsiwx %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
15349 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
15350 low32 = unop( Iop_64to32, high64 );
carll1f5fe1f2014-08-07 23:25:23 +000015351 store( mkexpr( EA ), low32 );
carll6c758b62013-10-03 21:38:45 +000015352 break;
15353 }
15354 case 0x28C:
15355 {
15356 IRTemp high64 = newTemp(Ity_F64);
15357 IRTemp val32 = newTemp(Ity_I32);
15358 DIP("stxsspx %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
15359 assign(high64, unop( Iop_ReinterpI64asF64,
15360 unop( Iop_V128HIto64, mkexpr( vS ) ) ) );
15361 assign(val32, unop( Iop_ReinterpF32asI32,
15362 unop( Iop_TruncF64asF32,
15363 mkexpr(high64) ) ) );
carll1f5fe1f2014-08-07 23:25:23 +000015364 store( mkexpr( EA ), mkexpr( val32 ) );
carll6c758b62013-10-03 21:38:45 +000015365 break;
15366 }
sewardj66d5ef22011-04-15 11:55:00 +000015367 case 0x2CC:
15368 {
15369 IRExpr * high64;
15370 DIP("stxsdx %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
15371 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
carll1f5fe1f2014-08-07 23:25:23 +000015372 store( mkexpr( EA ), high64 );
sewardj66d5ef22011-04-15 11:55:00 +000015373 break;
15374 }
15375 case 0x3CC:
15376 {
15377 IRExpr * high64, *low64;
15378 DIP("stxvd2x %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
15379 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
15380 low64 = unop( Iop_V128to64, mkexpr( vS ) );
carll1f5fe1f2014-08-07 23:25:23 +000015381 store( mkexpr( EA ), high64 );
15382 store( binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
15383 ty == Ity_I64 ? mkU64( 8 ) : mkU32( 8 ) ), low64 );
sewardj66d5ef22011-04-15 11:55:00 +000015384 break;
15385 }
15386 case 0x38C:
15387 {
15388 UInt ea_off = 0;
15389 IRExpr* irx_addr;
15390 IRTemp hi64 = newTemp( Ity_I64 );
15391 IRTemp lo64 = newTemp( Ity_I64 );
15392
15393 DIP("stxvw4x %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
15394
15395 // This instruction supports word-aligned stores, so EA may not be
15396 // quad-word aligned. Therefore, do 4 individual word-size stores.
15397 assign( hi64, unop( Iop_V128HIto64, mkexpr( vS ) ) );
15398 assign( lo64, unop( Iop_V128to64, mkexpr( vS ) ) );
carll1f5fe1f2014-08-07 23:25:23 +000015399 store( mkexpr( EA ), unop( Iop_64HIto32, mkexpr( hi64 ) ) );
sewardj66d5ef22011-04-15 11:55:00 +000015400 ea_off += 4;
15401 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
15402 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
carll1f5fe1f2014-08-07 23:25:23 +000015403 store( irx_addr, unop( Iop_64to32, mkexpr( hi64 ) ) );
sewardj66d5ef22011-04-15 11:55:00 +000015404 ea_off += 4;
15405 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
15406 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
carll1f5fe1f2014-08-07 23:25:23 +000015407 store( irx_addr, unop( Iop_64HIto32, mkexpr( lo64 ) ) );
sewardj66d5ef22011-04-15 11:55:00 +000015408 ea_off += 4;
15409 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
15410 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
carll1f5fe1f2014-08-07 23:25:23 +000015411 store( irx_addr, unop( Iop_64to32, mkexpr( lo64 ) ) );
sewardj66d5ef22011-04-15 11:55:00 +000015412
15413 break;
15414 }
15415 default:
15416 vex_printf( "dis_vx_store(ppc)(opc2)\n" );
15417 return False;
15418 }
15419 return True;
15420}
15421
15422/*
sewardj4aa412a2011-07-24 14:13:21 +000015423 * VSX permute and other miscealleous instructions
sewardj66d5ef22011-04-15 11:55:00 +000015424 */
15425static Bool
sewardj4aa412a2011-07-24 14:13:21 +000015426dis_vx_permute_misc( UInt theInstr, UInt opc2 )
sewardj66d5ef22011-04-15 11:55:00 +000015427{
15428 /* XX3-Form */
15429 UChar opc1 = ifieldOPC( theInstr );
15430 UChar XT = ifieldRegXT ( theInstr );
15431 UChar XA = ifieldRegXA ( theInstr );
15432 UChar XB = ifieldRegXB ( theInstr );
15433 IRTemp vT = newTemp( Ity_V128 );
15434 IRTemp vA = newTemp( Ity_V128 );
15435 IRTemp vB = newTemp( Ity_V128 );
15436
15437 if (opc1 != 0x3C) {
sewardj4aa412a2011-07-24 14:13:21 +000015438 vex_printf( "dis_vx_permute_misc(ppc)(instr)\n" );
sewardj66d5ef22011-04-15 11:55:00 +000015439 return False;
15440 }
15441
15442 assign( vA, getVSReg( XA ) );
15443 assign( vB, getVSReg( XB ) );
15444
15445 switch (opc2) {
15446 case 0x8: // xxsldwi (VSX Shift Left Double by Word Immediate)
15447 {
15448 UChar SHW = ifieldSHW ( theInstr );
15449 IRTemp result = newTemp(Ity_V128);
15450 if ( SHW != 0 ) {
15451 IRTemp hi = newTemp(Ity_V128);
15452 IRTemp lo = newTemp(Ity_V128);
15453 assign( hi, binop(Iop_ShlV128, mkexpr(vA), mkU8(SHW*32)) );
15454 assign( lo, binop(Iop_ShrV128, mkexpr(vB), mkU8(128-SHW*32)) );
15455 assign ( result, binop(Iop_OrV128, mkexpr(hi), mkexpr(lo)) );
15456 } else
15457 assign ( result, mkexpr(vA) );
15458 DIP("xxsldwi v%d,v%d,v%d,%d\n", (UInt)XT, (UInt)XA, (UInt)XB, (UInt)SHW);
15459 putVSReg( XT, mkexpr(result) );
15460 break;
15461 }
15462 case 0x28: // xpermdi (VSX Permute Doubleword Immediate)
15463 {
15464 UChar DM = ifieldDM ( theInstr );
15465 IRTemp hi = newTemp(Ity_I64);
15466 IRTemp lo = newTemp(Ity_I64);
15467
15468 if (DM & 0x2)
15469 assign( hi, unop(Iop_V128to64, mkexpr(vA)) );
15470 else
15471 assign( hi, unop(Iop_V128HIto64, mkexpr(vA)) );
15472
15473 if (DM & 0x1)
15474 assign( lo, unop(Iop_V128to64, mkexpr(vB)) );
15475 else
15476 assign( lo, unop(Iop_V128HIto64, mkexpr(vB)) );
15477
15478 assign( vT, binop(Iop_64HLtoV128, mkexpr(hi), mkexpr(lo)) );
15479
15480 DIP("xxpermdi v%d,v%d,v%d,0x%x\n", (UInt)XT, (UInt)XA, (UInt)XB, (UInt)DM);
15481 putVSReg( XT, mkexpr( vT ) );
15482 break;
15483 }
15484 case 0x48: // xxmrghw (VSX Merge High Word)
15485 case 0xc8: // xxmrglw (VSX Merge Low Word)
15486 {
florian55085f82012-11-21 00:36:55 +000015487 const HChar type = (opc2 == 0x48) ? 'h' : 'l';
sewardj66d5ef22011-04-15 11:55:00 +000015488 IROp word_op = (opc2 == 0x48) ? Iop_V128HIto64 : Iop_V128to64;
15489 IRTemp a64 = newTemp(Ity_I64);
15490 IRTemp ahi32 = newTemp(Ity_I32);
15491 IRTemp alo32 = newTemp(Ity_I32);
15492 IRTemp b64 = newTemp(Ity_I64);
15493 IRTemp bhi32 = newTemp(Ity_I32);
15494 IRTemp blo32 = newTemp(Ity_I32);
15495
15496 assign( a64, unop(word_op, mkexpr(vA)) );
15497 assign( ahi32, unop(Iop_64HIto32, mkexpr(a64)) );
15498 assign( alo32, unop(Iop_64to32, mkexpr(a64)) );
15499
15500 assign( b64, unop(word_op, mkexpr(vB)) );
15501 assign( bhi32, unop(Iop_64HIto32, mkexpr(b64)) );
15502 assign( blo32, unop(Iop_64to32, mkexpr(b64)) );
15503
15504 assign( vT, binop(Iop_64HLtoV128,
15505 binop(Iop_32HLto64, mkexpr(ahi32), mkexpr(bhi32)),
15506 binop(Iop_32HLto64, mkexpr(alo32), mkexpr(blo32))) );
15507
15508 DIP("xxmrg%cw v%d,v%d,v%d\n", type, (UInt)XT, (UInt)XA, (UInt)XB);
15509 putVSReg( XT, mkexpr( vT ) );
15510 break;
15511 }
sewardj4aa412a2011-07-24 14:13:21 +000015512 case 0x018: // xxsel (VSX Select)
15513 {
15514 UChar XC = ifieldRegXC(theInstr);
15515 IRTemp vC = newTemp( Ity_V128 );
15516 assign( vC, getVSReg( XC ) );
15517 DIP("xxsel v%d,v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB, (UInt)XC);
15518 /* vD = (vA & ~vC) | (vB & vC) */
15519 putVSReg( XT, binop(Iop_OrV128,
15520 binop(Iop_AndV128, mkexpr(vA), unop(Iop_NotV128, mkexpr(vC))),
15521 binop(Iop_AndV128, mkexpr(vB), mkexpr(vC))) );
15522 break;
15523 }
15524 case 0x148: // xxspltw (VSX Splat Word)
15525 {
15526 UChar UIM = ifieldRegA(theInstr) & 3;
15527 UChar sh_uim = (3 - (UIM)) * 32;
15528 DIP("xxspltw v%d,v%d,%d\n", (UInt)XT, (UInt)XB, UIM);
15529 putVSReg( XT,
15530 unop( Iop_Dup32x4,
15531 unop( Iop_V128to32,
15532 binop( Iop_ShrV128, mkexpr( vB ), mkU8( sh_uim ) ) ) ) );
15533 break;
15534 }
sewardj66d5ef22011-04-15 11:55:00 +000015535
15536 default:
sewardj4aa412a2011-07-24 14:13:21 +000015537 vex_printf( "dis_vx_permute_misc(ppc)(opc2)\n" );
sewardj66d5ef22011-04-15 11:55:00 +000015538 return False;
15539 }
15540 return True;
15541}
15542
15543/*
ceriona982c052005-06-28 17:23:09 +000015544 AltiVec Load Instructions
15545*/
sewardjdd40fdf2006-12-24 02:20:24 +000015546static Bool dis_av_load ( VexAbiInfo* vbi, UInt theInstr )
ceriona982c052005-06-28 17:23:09 +000015547{
cerion76de5cf2005-11-18 18:25:12 +000015548 /* X-Form */
15549 UChar opc1 = ifieldOPC(theInstr);
15550 UChar vD_addr = ifieldRegDS(theInstr);
15551 UChar rA_addr = ifieldRegA(theInstr);
15552 UChar rB_addr = ifieldRegB(theInstr);
15553 UInt opc2 = ifieldOPClo10(theInstr);
15554 UChar b0 = ifieldBIT0(theInstr);
ceriona982c052005-06-28 17:23:09 +000015555
cerionfb197c42005-12-24 12:32:10 +000015556 IRType ty = mode64 ? Ity_I64 : Ity_I32;
15557 IRTemp EA = newTemp(ty);
15558 IRTemp EA_align16 = newTemp(ty);
cerion2831b002005-11-30 19:55:22 +000015559
ceriona982c052005-06-28 17:23:09 +000015560 if (opc1 != 0x1F || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +000015561 vex_printf("dis_av_load(ppc)(instr)\n");
ceriona982c052005-06-28 17:23:09 +000015562 return False;
15563 }
15564
cerionfb197c42005-12-24 12:32:10 +000015565 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
15566 assign( EA_align16, addr_align( mkexpr(EA), 16 ) );
ceriona50fde52005-07-01 21:16:10 +000015567
ceriona982c052005-06-28 17:23:09 +000015568 switch (opc2) {
15569
cerion6f6c6a02005-09-13 18:41:09 +000015570 case 0x006: { // lvsl (Load Vector for Shift Left, AV p123)
cerionfb197c42005-12-24 12:32:10 +000015571 IRDirty* d;
sewardjd1470942005-10-22 02:01:16 +000015572 UInt vD_off = vectorGuestRegOffset(vD_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015573 IRExpr** args_be = mkIRExprVec_5(
florian90419562013-08-15 20:54:52 +000015574 IRExpr_BBPTR(),
carll1f5fe1f2014-08-07 23:25:23 +000015575 mkU32(vD_off),
sewardje9d8a262009-07-01 08:06:34 +000015576 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
cerionfb197c42005-12-24 12:32:10 +000015577 mkU32(0xF)),
carll1f5fe1f2014-08-07 23:25:23 +000015578 mkU32(0)/*left*/,
15579 mkU32(1)/*Big Endian*/);
15580 IRExpr** args_le = mkIRExprVec_5(
15581 IRExpr_BBPTR(),
15582 mkU32(vD_off),
15583 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
15584 mkU32(0xF)),
15585 mkU32(0)/*left*/,
15586 mkU32(0)/*Little Endian*/);
cerion5b2325f2005-12-23 00:55:09 +000015587 if (!mode64) {
cerion4c4f5ef2006-01-02 14:41:50 +000015588 d = unsafeIRDirty_0_N (
15589 0/*regparms*/,
15590 "ppc32g_dirtyhelper_LVS",
sewardjdd40fdf2006-12-24 02:20:24 +000015591 fnptr_to_fnentry(vbi, &ppc32g_dirtyhelper_LVS),
carll1f5fe1f2014-08-07 23:25:23 +000015592 args_be );
cerion5b2325f2005-12-23 00:55:09 +000015593 } else {
carll1f5fe1f2014-08-07 23:25:23 +000015594 if (host_endness == VexEndnessBE)
15595 d = unsafeIRDirty_0_N (
15596 0/*regparms*/,
15597 "ppc64g_dirtyhelper_LVS",
15598 fnptr_to_fnentry(vbi, &ppc64g_dirtyhelper_LVS),
15599 args_be );
15600 else
15601 d = unsafeIRDirty_0_N (
15602 0/*regparms*/,
15603 "ppc64g_dirtyhelper_LVS",
15604 &ppc64g_dirtyhelper_LVS,
15605 args_le );
cerion5b2325f2005-12-23 00:55:09 +000015606 }
ceriond953ebb2005-11-29 13:27:20 +000015607 DIP("lvsl v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
cerion6f6c6a02005-09-13 18:41:09 +000015608 /* declare guest state effects */
cerion6f6c6a02005-09-13 18:41:09 +000015609 d->nFxState = 1;
sewardjc9069f22012-06-01 16:09:50 +000015610 vex_bzero(&d->fxState, sizeof(d->fxState));
cerion6f6c6a02005-09-13 18:41:09 +000015611 d->fxState[0].fx = Ifx_Write;
sewardjd1470942005-10-22 02:01:16 +000015612 d->fxState[0].offset = vD_off;
cerion6f6c6a02005-09-13 18:41:09 +000015613 d->fxState[0].size = sizeof(U128);
cerion32aad402005-09-10 12:02:24 +000015614
cerion6f6c6a02005-09-13 18:41:09 +000015615 /* execute the dirty call, side-effecting guest state */
15616 stmt( IRStmt_Dirty(d) );
15617 break;
15618 }
15619 case 0x026: { // lvsr (Load Vector for Shift Right, AV p125)
cerionfb197c42005-12-24 12:32:10 +000015620 IRDirty* d;
sewardjd1470942005-10-22 02:01:16 +000015621 UInt vD_off = vectorGuestRegOffset(vD_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015622 IRExpr** args_be = mkIRExprVec_5(
15623 IRExpr_BBPTR(),
15624 mkU32(vD_off),
15625 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
15626 mkU32(0xF)),
15627 mkU32(1)/*right*/,
15628 mkU32(1)/*Big Endian*/);
15629 IRExpr** args_le = mkIRExprVec_5(
15630 IRExpr_BBPTR(),
15631 mkU32(vD_off),
15632 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
15633 mkU32(0xF)),
15634 mkU32(1)/*right*/,
15635 mkU32(0)/*Little Endian*/);
15636
cerion5b2325f2005-12-23 00:55:09 +000015637 if (!mode64) {
cerion4c4f5ef2006-01-02 14:41:50 +000015638 d = unsafeIRDirty_0_N (
carll1f5fe1f2014-08-07 23:25:23 +000015639 0/*regparms*/,
cerion4c4f5ef2006-01-02 14:41:50 +000015640 "ppc32g_dirtyhelper_LVS",
sewardjdd40fdf2006-12-24 02:20:24 +000015641 fnptr_to_fnentry(vbi, &ppc32g_dirtyhelper_LVS),
carll1f5fe1f2014-08-07 23:25:23 +000015642 args_be );
cerion5b2325f2005-12-23 00:55:09 +000015643 } else {
carll1f5fe1f2014-08-07 23:25:23 +000015644 if (host_endness == VexEndnessBE)
15645 d = unsafeIRDirty_0_N (
15646 0/*regparms*/,
15647 "ppc64g_dirtyhelper_LVS",
15648 fnptr_to_fnentry(vbi, &ppc64g_dirtyhelper_LVS),
15649 args_be );
15650 else
15651 d = unsafeIRDirty_0_N (
15652 0/*regparms*/,
15653 "ppc64g_dirtyhelper_LVS",
15654 &ppc64g_dirtyhelper_LVS,
15655 args_le );
cerion5b2325f2005-12-23 00:55:09 +000015656 }
ceriond953ebb2005-11-29 13:27:20 +000015657 DIP("lvsr v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
cerion6f6c6a02005-09-13 18:41:09 +000015658 /* declare guest state effects */
cerion6f6c6a02005-09-13 18:41:09 +000015659 d->nFxState = 1;
sewardjc9069f22012-06-01 16:09:50 +000015660 vex_bzero(&d->fxState, sizeof(d->fxState));
cerion6f6c6a02005-09-13 18:41:09 +000015661 d->fxState[0].fx = Ifx_Write;
sewardjd1470942005-10-22 02:01:16 +000015662 d->fxState[0].offset = vD_off;
cerion6f6c6a02005-09-13 18:41:09 +000015663 d->fxState[0].size = sizeof(U128);
cerion32aad402005-09-10 12:02:24 +000015664
cerion6f6c6a02005-09-13 18:41:09 +000015665 /* execute the dirty call, side-effecting guest state */
15666 stmt( IRStmt_Dirty(d) );
15667 break;
15668 }
cerion32aad402005-09-10 12:02:24 +000015669 case 0x007: // lvebx (Load Vector Element Byte Indexed, AV p119)
ceriond953ebb2005-11-29 13:27:20 +000015670 DIP("lvebx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +000015671 /* loads addressed byte into vector[EA[0:3]
15672 since all other destination bytes are undefined,
15673 can simply load entire vector from 16-aligned EA */
carll1f5fe1f2014-08-07 23:25:23 +000015674 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
cerion61c92742005-09-14 22:59:26 +000015675 break;
cerion32aad402005-09-10 12:02:24 +000015676
15677 case 0x027: // lvehx (Load Vector Element Half Word Indexed, AV p121)
ceriond953ebb2005-11-29 13:27:20 +000015678 DIP("lvehx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +000015679 /* see note for lvebx */
carll1f5fe1f2014-08-07 23:25:23 +000015680 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
cerion61c92742005-09-14 22:59:26 +000015681 break;
cerion32aad402005-09-10 12:02:24 +000015682
15683 case 0x047: // lvewx (Load Vector Element Word Indexed, AV p122)
ceriond953ebb2005-11-29 13:27:20 +000015684 DIP("lvewx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +000015685 /* see note for lvebx */
carll1f5fe1f2014-08-07 23:25:23 +000015686 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
cerion61c92742005-09-14 22:59:26 +000015687 break;
ceriona982c052005-06-28 17:23:09 +000015688
15689 case 0x067: // lvx (Load Vector Indexed, AV p127)
ceriond953ebb2005-11-29 13:27:20 +000015690 DIP("lvx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015691 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
ceriona50fde52005-07-01 21:16:10 +000015692 break;
ceriona982c052005-06-28 17:23:09 +000015693
cerion32aad402005-09-10 12:02:24 +000015694 case 0x167: // lvxl (Load Vector Indexed LRU, AV p128)
ceriond953ebb2005-11-29 13:27:20 +000015695 DIP("lvxl v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015696 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
sewardjd2fd8642006-12-27 21:21:14 +000015697 break;
ceriona982c052005-06-28 17:23:09 +000015698
15699 default:
cerion5b2325f2005-12-23 00:55:09 +000015700 vex_printf("dis_av_load(ppc)(opc2)\n");
ceriona982c052005-06-28 17:23:09 +000015701 return False;
15702 }
15703 return True;
15704}
15705
15706/*
15707 AltiVec Store Instructions
15708*/
15709static Bool dis_av_store ( UInt theInstr )
15710{
cerion76de5cf2005-11-18 18:25:12 +000015711 /* X-Form */
15712 UChar opc1 = ifieldOPC(theInstr);
15713 UChar vS_addr = ifieldRegDS(theInstr);
15714 UChar rA_addr = ifieldRegA(theInstr);
15715 UChar rB_addr = ifieldRegB(theInstr);
15716 UInt opc2 = ifieldOPClo10(theInstr);
15717 UChar b0 = ifieldBIT0(theInstr);
ceriona982c052005-06-28 17:23:09 +000015718
cerion2831b002005-11-30 19:55:22 +000015719 IRType ty = mode64 ? Ity_I64 : Ity_I32;
15720 IRTemp EA = newTemp(ty);
ceriondba87e22006-01-02 15:15:45 +000015721 IRTemp addr_aligned = newTemp(ty);
cerion2831b002005-11-30 19:55:22 +000015722 IRTemp vS = newTemp(Ity_V128);
15723 IRTemp eb = newTemp(Ity_I8);
15724 IRTemp idx = newTemp(Ity_I8);
ceriona982c052005-06-28 17:23:09 +000015725
15726 if (opc1 != 0x1F || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +000015727 vex_printf("dis_av_store(ppc)(instr)\n");
ceriona982c052005-06-28 17:23:09 +000015728 return False;
15729 }
15730
ceriond953ebb2005-11-29 13:27:20 +000015731 assign( vS, getVReg(vS_addr));
cerion2831b002005-11-30 19:55:22 +000015732 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
ceriond953ebb2005-11-29 13:27:20 +000015733
ceriona982c052005-06-28 17:23:09 +000015734 switch (opc2) {
cerion61c92742005-09-14 22:59:26 +000015735 case 0x087: { // stvebx (Store Vector Byte Indexed, AV p131)
ceriond953ebb2005-11-29 13:27:20 +000015736 DIP("stvebx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +000015737 assign( eb, binop(Iop_And8, mkU8(0xF),
cerion2831b002005-11-30 19:55:22 +000015738 unop(Iop_32to8,
sewardje9d8a262009-07-01 08:06:34 +000015739 mkNarrowTo32(ty, mkexpr(EA)) )) );
carll1f5fe1f2014-08-07 23:25:23 +000015740 if (host_endness == VexEndnessLE) {
15741 assign( idx, binop(Iop_Shl8, mkexpr(eb), mkU8(3)) );
15742 } else {
15743 assign( idx, binop(Iop_Shl8,
15744 binop(Iop_Sub8, mkU8(15), mkexpr(eb)),
15745 mkU8(3)) );
15746 }
15747 store( mkexpr(EA),
15748 unop( Iop_32to8, unop(Iop_V128to32,
15749 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx)))) );
cerion61c92742005-09-14 22:59:26 +000015750 break;
15751 }
15752 case 0x0A7: { // stvehx (Store Vector Half Word Indexed, AV p132)
ceriond953ebb2005-11-29 13:27:20 +000015753 DIP("stvehx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
ceriondba87e22006-01-02 15:15:45 +000015754 assign( addr_aligned, addr_align(mkexpr(EA), 2) );
cerion61c92742005-09-14 22:59:26 +000015755 assign( eb, binop(Iop_And8, mkU8(0xF),
sewardje9d8a262009-07-01 08:06:34 +000015756 mkNarrowTo8(ty, mkexpr(addr_aligned) )) );
carll1f5fe1f2014-08-07 23:25:23 +000015757 if (host_endness == VexEndnessLE) {
15758 assign( idx, binop(Iop_Shl8, mkexpr(eb), mkU8(3)) );
15759 } else {
15760 assign( idx, binop(Iop_Shl8,
15761 binop(Iop_Sub8, mkU8(14), mkexpr(eb)),
15762 mkU8(3)) );
15763 }
15764 store( mkexpr(addr_aligned),
15765 unop( Iop_32to16, unop(Iop_V128to32,
15766 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx)))) );
cerion61c92742005-09-14 22:59:26 +000015767 break;
15768 }
15769 case 0x0C7: { // stvewx (Store Vector Word Indexed, AV p133)
ceriond953ebb2005-11-29 13:27:20 +000015770 DIP("stvewx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
ceriondba87e22006-01-02 15:15:45 +000015771 assign( addr_aligned, addr_align(mkexpr(EA), 4) );
cerion61c92742005-09-14 22:59:26 +000015772 assign( eb, binop(Iop_And8, mkU8(0xF),
sewardje9d8a262009-07-01 08:06:34 +000015773 mkNarrowTo8(ty, mkexpr(addr_aligned) )) );
carll1f5fe1f2014-08-07 23:25:23 +000015774 if (host_endness == VexEndnessLE) {
15775 assign( idx, binop(Iop_Shl8, mkexpr(eb), mkU8(3)) );
15776 } else {
15777 assign( idx, binop(Iop_Shl8,
15778 binop(Iop_Sub8, mkU8(12), mkexpr(eb)),
15779 mkU8(3)) );
15780 }
15781 store( mkexpr( addr_aligned),
15782 unop( Iop_V128to32,
15783 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx))) );
cerion61c92742005-09-14 22:59:26 +000015784 break;
15785 }
cerion32aad402005-09-10 12:02:24 +000015786
ceriona982c052005-06-28 17:23:09 +000015787 case 0x0E7: // stvx (Store Vector Indexed, AV p134)
ceriond953ebb2005-11-29 13:27:20 +000015788 DIP("stvx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015789 store( addr_align( mkexpr(EA), 16 ), mkexpr(vS) );
ceriona982c052005-06-28 17:23:09 +000015790 break;
15791
cerion32aad402005-09-10 12:02:24 +000015792 case 0x1E7: // stvxl (Store Vector Indexed LRU, AV p135)
ceriond953ebb2005-11-29 13:27:20 +000015793 DIP("stvxl v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015794 store( addr_align( mkexpr(EA), 16 ), mkexpr(vS) );
sewardjd2fd8642006-12-27 21:21:14 +000015795 break;
ceriona982c052005-06-28 17:23:09 +000015796
15797 default:
cerion5b2325f2005-12-23 00:55:09 +000015798 vex_printf("dis_av_store(ppc)(opc2)\n");
ceriona982c052005-06-28 17:23:09 +000015799 return False;
15800 }
15801 return True;
15802}
15803
cerion32aad402005-09-10 12:02:24 +000015804/*
15805 AltiVec Arithmetic Instructions
15806*/
15807static Bool dis_av_arith ( UInt theInstr )
15808{
cerion76de5cf2005-11-18 18:25:12 +000015809 /* VX-Form */
15810 UChar opc1 = ifieldOPC(theInstr);
15811 UChar vD_addr = ifieldRegDS(theInstr);
15812 UChar vA_addr = ifieldRegA(theInstr);
15813 UChar vB_addr = ifieldRegB(theInstr);
15814 UInt opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000015815
ceriond3e52412005-09-14 21:15:40 +000015816 IRTemp vA = newTemp(Ity_V128);
15817 IRTemp vB = newTemp(Ity_V128);
cerion4a49b032005-11-08 16:23:07 +000015818 IRTemp z3 = newTemp(Ity_I64);
15819 IRTemp z2 = newTemp(Ity_I64);
15820 IRTemp z1 = newTemp(Ity_I64);
15821 IRTemp z0 = newTemp(Ity_I64);
15822 IRTemp aEvn, aOdd;
15823 IRTemp a15, a14, a13, a12, a11, a10, a9, a8;
15824 IRTemp a7, a6, a5, a4, a3, a2, a1, a0;
15825 IRTemp b3, b2, b1, b0;
15826
15827 aEvn = aOdd = IRTemp_INVALID;
15828 a15 = a14 = a13 = a12 = a11 = a10 = a9 = a8 = IRTemp_INVALID;
15829 a7 = a6 = a5 = a4 = a3 = a2 = a1 = a0 = IRTemp_INVALID;
15830 b3 = b2 = b1 = b0 = IRTemp_INVALID;
15831
ceriond3e52412005-09-14 21:15:40 +000015832 assign( vA, getVReg(vA_addr));
15833 assign( vB, getVReg(vB_addr));
15834
cerion32aad402005-09-10 12:02:24 +000015835 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000015836 vex_printf("dis_av_arith(ppc)(opc1 != 0x4)\n");
cerion32aad402005-09-10 12:02:24 +000015837 return False;
15838 }
15839
15840 switch (opc2) {
15841 /* Add */
ceriond3e52412005-09-14 21:15:40 +000015842 case 0x180: { // vaddcuw (Add Carryout Unsigned Word, AV p136)
cerion32aad402005-09-10 12:02:24 +000015843 DIP("vaddcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015844 /* unsigned_ov(x+y) = (y >u not(x)) */
ceriond3e52412005-09-14 21:15:40 +000015845 putVReg( vD_addr, binop(Iop_ShrN32x4,
cerion36991ef2005-09-15 12:42:16 +000015846 binop(Iop_CmpGT32Ux4, mkexpr(vB),
15847 unop(Iop_NotV128, mkexpr(vA))),
ceriond3e52412005-09-14 21:15:40 +000015848 mkU8(31)) );
15849 break;
15850 }
cerion32aad402005-09-10 12:02:24 +000015851 case 0x000: // vaddubm (Add Unsigned Byte Modulo, AV p141)
15852 DIP("vaddubm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015853 putVReg( vD_addr, binop(Iop_Add8x16, mkexpr(vA), mkexpr(vB)) );
15854 break;
15855
cerion32aad402005-09-10 12:02:24 +000015856 case 0x040: // vadduhm (Add Unsigned Half Word Modulo, AV p143)
15857 DIP("vadduhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015858 putVReg( vD_addr, binop(Iop_Add16x8, mkexpr(vA), mkexpr(vB)) );
15859 break;
15860
cerion32aad402005-09-10 12:02:24 +000015861 case 0x080: // vadduwm (Add Unsigned Word Modulo, AV p145)
15862 DIP("vadduwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015863 putVReg( vD_addr, binop(Iop_Add32x4, mkexpr(vA), mkexpr(vB)) );
15864 break;
15865
carll0c74bb52013-08-12 18:01:40 +000015866 case 0x0C0: // vaddudm (Add Unsigned Double Word Modulo)
15867 DIP("vaddudm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
15868 putVReg( vD_addr, binop(Iop_Add64x2, mkexpr(vA), mkexpr(vB)) );
15869 break;
15870
cerion32aad402005-09-10 12:02:24 +000015871 case 0x200: // vaddubs (Add Unsigned Byte Saturate, AV p142)
15872 DIP("vaddubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015873 putVReg( vD_addr, binop(Iop_QAdd8Ux16, mkexpr(vA), mkexpr(vB)) );
15874 // TODO: set VSCR[SAT], perhaps via new primop: Iop_SatOfQAdd8Ux16
15875 break;
15876
cerion32aad402005-09-10 12:02:24 +000015877 case 0x240: // vadduhs (Add Unsigned Half Word Saturate, AV p144)
15878 DIP("vadduhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015879 putVReg( vD_addr, binop(Iop_QAdd16Ux8, mkexpr(vA), mkexpr(vB)) );
15880 // TODO: set VSCR[SAT]
15881 break;
15882
cerion32aad402005-09-10 12:02:24 +000015883 case 0x280: // vadduws (Add Unsigned Word Saturate, AV p146)
15884 DIP("vadduws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015885 putVReg( vD_addr, binop(Iop_QAdd32Ux4, mkexpr(vA), mkexpr(vB)) );
15886 // TODO: set VSCR[SAT]
15887 break;
15888
cerion32aad402005-09-10 12:02:24 +000015889 case 0x300: // vaddsbs (Add Signed Byte Saturate, AV p138)
15890 DIP("vaddsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015891 putVReg( vD_addr, binop(Iop_QAdd8Sx16, mkexpr(vA), mkexpr(vB)) );
15892 // TODO: set VSCR[SAT]
15893 break;
15894
cerion32aad402005-09-10 12:02:24 +000015895 case 0x340: // vaddshs (Add Signed Half Word Saturate, AV p139)
15896 DIP("vaddshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015897 putVReg( vD_addr, binop(Iop_QAdd16Sx8, mkexpr(vA), mkexpr(vB)) );
15898 // TODO: set VSCR[SAT]
15899 break;
15900
cerion32aad402005-09-10 12:02:24 +000015901 case 0x380: // vaddsws (Add Signed Word Saturate, AV p140)
15902 DIP("vaddsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015903 putVReg( vD_addr, binop(Iop_QAdd32Sx4, mkexpr(vA), mkexpr(vB)) );
15904 // TODO: set VSCR[SAT]
15905 break;
15906
15907
cerion32aad402005-09-10 12:02:24 +000015908 /* Subtract */
cerion36991ef2005-09-15 12:42:16 +000015909 case 0x580: { // vsubcuw (Subtract Carryout Unsigned Word, AV p260)
cerion32aad402005-09-10 12:02:24 +000015910 DIP("vsubcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015911 /* unsigned_ov(x-y) = (y >u x) */
15912 putVReg( vD_addr, binop(Iop_ShrN32x4,
15913 unop(Iop_NotV128,
15914 binop(Iop_CmpGT32Ux4, mkexpr(vB),
15915 mkexpr(vA))),
15916 mkU8(31)) );
15917 break;
15918 }
cerion32aad402005-09-10 12:02:24 +000015919 case 0x400: // vsububm (Subtract Unsigned Byte Modulo, AV p265)
15920 DIP("vsububm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015921 putVReg( vD_addr, binop(Iop_Sub8x16, mkexpr(vA), mkexpr(vB)) );
15922 break;
15923
cerion32aad402005-09-10 12:02:24 +000015924 case 0x440: // vsubuhm (Subtract Unsigned Half Word Modulo, AV p267)
15925 DIP("vsubuhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015926 putVReg( vD_addr, binop(Iop_Sub16x8, mkexpr(vA), mkexpr(vB)) );
15927 break;
15928
cerion32aad402005-09-10 12:02:24 +000015929 case 0x480: // vsubuwm (Subtract Unsigned Word Modulo, AV p269)
15930 DIP("vsubuwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015931 putVReg( vD_addr, binop(Iop_Sub32x4, mkexpr(vA), mkexpr(vB)) );
15932 break;
15933
carll48ae46b2013-10-01 15:45:54 +000015934 case 0x4C0: // vsubudm (Subtract Unsigned Double Word Modulo)
15935 DIP("vsubudm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
15936 putVReg( vD_addr, binop(Iop_Sub64x2, mkexpr(vA), mkexpr(vB)) );
15937 break;
15938
cerion32aad402005-09-10 12:02:24 +000015939 case 0x600: // vsububs (Subtract Unsigned Byte Saturate, AV p266)
15940 DIP("vsububs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015941 putVReg( vD_addr, binop(Iop_QSub8Ux16, mkexpr(vA), mkexpr(vB)) );
15942 // TODO: set VSCR[SAT]
15943 break;
15944
cerion5b2325f2005-12-23 00:55:09 +000015945 case 0x640: // vsubuhs (Subtract Unsigned HWord Saturate, AV p268)
cerion32aad402005-09-10 12:02:24 +000015946 DIP("vsubuhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015947 putVReg( vD_addr, binop(Iop_QSub16Ux8, mkexpr(vA), mkexpr(vB)) );
15948 // TODO: set VSCR[SAT]
15949 break;
15950
cerion32aad402005-09-10 12:02:24 +000015951 case 0x680: // vsubuws (Subtract Unsigned Word Saturate, AV p270)
15952 DIP("vsubuws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015953 putVReg( vD_addr, binop(Iop_QSub32Ux4, mkexpr(vA), mkexpr(vB)) );
15954 // TODO: set VSCR[SAT]
15955 break;
15956
cerion32aad402005-09-10 12:02:24 +000015957 case 0x700: // vsubsbs (Subtract Signed Byte Saturate, AV p262)
15958 DIP("vsubsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015959 putVReg( vD_addr, binop(Iop_QSub8Sx16, mkexpr(vA), mkexpr(vB)) );
15960 // TODO: set VSCR[SAT]
15961 break;
15962
cerion32aad402005-09-10 12:02:24 +000015963 case 0x740: // vsubshs (Subtract Signed Half Word Saturate, AV p263)
15964 DIP("vsubshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015965 putVReg( vD_addr, binop(Iop_QSub16Sx8, mkexpr(vA), mkexpr(vB)) );
15966 // TODO: set VSCR[SAT]
15967 break;
15968
cerion32aad402005-09-10 12:02:24 +000015969 case 0x780: // vsubsws (Subtract Signed Word Saturate, AV p264)
15970 DIP("vsubsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015971 putVReg( vD_addr, binop(Iop_QSub32Sx4, mkexpr(vA), mkexpr(vB)) );
15972 // TODO: set VSCR[SAT]
15973 break;
cerion32aad402005-09-10 12:02:24 +000015974
15975
15976 /* Maximum */
15977 case 0x002: // vmaxub (Maximum Unsigned Byte, AV p182)
15978 DIP("vmaxub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015979 putVReg( vD_addr, binop(Iop_Max8Ux16, mkexpr(vA), mkexpr(vB)) );
15980 break;
cerion32aad402005-09-10 12:02:24 +000015981
15982 case 0x042: // vmaxuh (Maximum Unsigned Half Word, AV p183)
15983 DIP("vmaxuh 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_Max16Ux8, mkexpr(vA), mkexpr(vB)) );
15985 break;
cerion32aad402005-09-10 12:02:24 +000015986
15987 case 0x082: // vmaxuw (Maximum Unsigned Word, AV p184)
15988 DIP("vmaxuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015989 putVReg( vD_addr, binop(Iop_Max32Ux4, mkexpr(vA), mkexpr(vB)) );
15990 break;
cerion32aad402005-09-10 12:02:24 +000015991
carll48ae46b2013-10-01 15:45:54 +000015992 case 0x0C2: // vmaxud (Maximum Unsigned Double word)
15993 DIP("vmaxud v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
15994 putVReg( vD_addr, binop(Iop_Max64Ux2, mkexpr(vA), mkexpr(vB)) );
15995 break;
15996
cerion32aad402005-09-10 12:02:24 +000015997 case 0x102: // vmaxsb (Maximum Signed Byte, AV p179)
15998 DIP("vmaxsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015999 putVReg( vD_addr, binop(Iop_Max8Sx16, mkexpr(vA), mkexpr(vB)) );
16000 break;
cerion32aad402005-09-10 12:02:24 +000016001
16002 case 0x142: // vmaxsh (Maximum Signed Half Word, AV p180)
16003 DIP("vmaxsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016004 putVReg( vD_addr, binop(Iop_Max16Sx8, mkexpr(vA), mkexpr(vB)) );
16005 break;
cerion32aad402005-09-10 12:02:24 +000016006
16007 case 0x182: // vmaxsw (Maximum Signed Word, AV p181)
16008 DIP("vmaxsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016009 putVReg( vD_addr, binop(Iop_Max32Sx4, mkexpr(vA), mkexpr(vB)) );
16010 break;
cerion32aad402005-09-10 12:02:24 +000016011
carll48ae46b2013-10-01 15:45:54 +000016012 case 0x1C2: // vmaxsd (Maximum Signed Double word)
16013 DIP("vmaxsd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16014 putVReg( vD_addr, binop(Iop_Max64Sx2, mkexpr(vA), mkexpr(vB)) );
16015 break;
cerion32aad402005-09-10 12:02:24 +000016016
16017 /* Minimum */
16018 case 0x202: // vminub (Minimum Unsigned Byte, AV p191)
16019 DIP("vminub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016020 putVReg( vD_addr, binop(Iop_Min8Ux16, mkexpr(vA), mkexpr(vB)) );
16021 break;
cerion32aad402005-09-10 12:02:24 +000016022
16023 case 0x242: // vminuh (Minimum Unsigned Half Word, AV p192)
16024 DIP("vminuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016025 putVReg( vD_addr, binop(Iop_Min16Ux8, mkexpr(vA), mkexpr(vB)) );
16026 break;
cerion32aad402005-09-10 12:02:24 +000016027
16028 case 0x282: // vminuw (Minimum Unsigned Word, AV p193)
16029 DIP("vminuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016030 putVReg( vD_addr, binop(Iop_Min32Ux4, mkexpr(vA), mkexpr(vB)) );
16031 break;
cerion32aad402005-09-10 12:02:24 +000016032
carll48ae46b2013-10-01 15:45:54 +000016033 case 0x2C2: // vminud (Minimum Unsigned Double Word)
16034 DIP("vminud v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16035 putVReg( vD_addr, binop(Iop_Min64Ux2, mkexpr(vA), mkexpr(vB)) );
16036 break;
16037
cerion32aad402005-09-10 12:02:24 +000016038 case 0x302: // vminsb (Minimum Signed Byte, AV p188)
16039 DIP("vminsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016040 putVReg( vD_addr, binop(Iop_Min8Sx16, mkexpr(vA), mkexpr(vB)) );
16041 break;
cerion32aad402005-09-10 12:02:24 +000016042
16043 case 0x342: // vminsh (Minimum Signed Half Word, AV p189)
16044 DIP("vminsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016045 putVReg( vD_addr, binop(Iop_Min16Sx8, mkexpr(vA), mkexpr(vB)) );
16046 break;
cerion32aad402005-09-10 12:02:24 +000016047
16048 case 0x382: // vminsw (Minimum Signed Word, AV p190)
16049 DIP("vminsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016050 putVReg( vD_addr, binop(Iop_Min32Sx4, mkexpr(vA), mkexpr(vB)) );
16051 break;
16052
carll48ae46b2013-10-01 15:45:54 +000016053 case 0x3C2: // vminsd (Minimum Signed Double Word)
16054 DIP("vminsd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16055 putVReg( vD_addr, binop(Iop_Min64Sx2, mkexpr(vA), mkexpr(vB)) );
16056 break;
16057
cerion32aad402005-09-10 12:02:24 +000016058
16059 /* Average */
16060 case 0x402: // vavgub (Average Unsigned Byte, AV p152)
16061 DIP("vavgub 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_Avg8Ux16, mkexpr(vA), mkexpr(vB)) );
16063 break;
cerion32aad402005-09-10 12:02:24 +000016064
16065 case 0x442: // vavguh (Average Unsigned Half Word, AV p153)
16066 DIP("vavguh 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_Avg16Ux8, mkexpr(vA), mkexpr(vB)) );
16068 break;
cerion32aad402005-09-10 12:02:24 +000016069
16070 case 0x482: // vavguw (Average Unsigned Word, AV p154)
16071 DIP("vavguw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016072 putVReg( vD_addr, binop(Iop_Avg32Ux4, mkexpr(vA), mkexpr(vB)) );
16073 break;
cerion32aad402005-09-10 12:02:24 +000016074
16075 case 0x502: // vavgsb (Average Signed Byte, AV p149)
16076 DIP("vavgsb 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_Avg8Sx16, mkexpr(vA), mkexpr(vB)) );
16078 break;
cerion32aad402005-09-10 12:02:24 +000016079
16080 case 0x542: // vavgsh (Average Signed Half Word, AV p150)
16081 DIP("vavgsh 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_Avg16Sx8, mkexpr(vA), mkexpr(vB)) );
16083 break;
cerion32aad402005-09-10 12:02:24 +000016084
16085 case 0x582: // vavgsw (Average Signed Word, AV p151)
16086 DIP("vavgsw 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_Avg32Sx4, mkexpr(vA), mkexpr(vB)) );
16088 break;
cerion32aad402005-09-10 12:02:24 +000016089
16090
16091 /* Multiply */
16092 case 0x008: // vmuloub (Multiply Odd Unsigned Byte, AV p213)
16093 DIP("vmuloub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000016094 putVReg( vD_addr,
16095 binop(Iop_MullEven8Ux16, mkexpr(vA), mkexpr(vB)));
cerion36991ef2005-09-15 12:42:16 +000016096 break;
cerion32aad402005-09-10 12:02:24 +000016097
16098 case 0x048: // vmulouh (Multiply Odd Unsigned Half Word, AV p214)
16099 DIP("vmulouh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000016100 putVReg( vD_addr,
16101 binop(Iop_MullEven16Ux8, mkexpr(vA), mkexpr(vB)));
cerion36991ef2005-09-15 12:42:16 +000016102 break;
cerion32aad402005-09-10 12:02:24 +000016103
carll48ae46b2013-10-01 15:45:54 +000016104 case 0x088: // vmulouw (Multiply Odd Unsigned Word)
16105 DIP("vmulouw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16106 putVReg( vD_addr, binop( Iop_MullEven32Ux4, mkexpr(vA), mkexpr(vB) ) );
16107 break;
16108
16109 case 0x089: // vmuluwm (Multiply Unsigned Word Modulo)
16110 DIP("vmuluwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16111 putVReg( vD_addr, binop( Iop_Mul32x4, mkexpr(vA), mkexpr(vB) ) );
16112 break;
16113
cerion32aad402005-09-10 12:02:24 +000016114 case 0x108: // vmulosb (Multiply Odd Signed Byte, AV p211)
16115 DIP("vmulosb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000016116 putVReg( vD_addr,
16117 binop(Iop_MullEven8Sx16, mkexpr(vA), mkexpr(vB)));
cerion36991ef2005-09-15 12:42:16 +000016118 break;
cerion32aad402005-09-10 12:02:24 +000016119
16120 case 0x148: // vmulosh (Multiply Odd Signed Half Word, AV p212)
16121 DIP("vmulosh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000016122 putVReg( vD_addr,
16123 binop(Iop_MullEven16Sx8, mkexpr(vA), mkexpr(vB)));
cerion36991ef2005-09-15 12:42:16 +000016124 break;
cerion32aad402005-09-10 12:02:24 +000016125
carll48ae46b2013-10-01 15:45:54 +000016126 case 0x188: // vmulosw (Multiply Odd Signed Word)
16127 DIP("vmulosw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16128 putVReg( vD_addr, binop( Iop_MullEven32Sx4, mkexpr(vA), mkexpr(vB) ) );
16129 break;
16130
cerion32aad402005-09-10 12:02:24 +000016131 case 0x208: // vmuleub (Multiply Even Unsigned Byte, AV p209)
16132 DIP("vmuleub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion24d06f12005-11-09 21:34:20 +000016133 putVReg( vD_addr, MK_Iop_MullOdd8Ux16( mkexpr(vA), mkexpr(vB) ));
cerion36991ef2005-09-15 12:42:16 +000016134 break;
cerion32aad402005-09-10 12:02:24 +000016135
16136 case 0x248: // vmuleuh (Multiply Even Unsigned Half Word, AV p210)
16137 DIP("vmuleuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion24d06f12005-11-09 21:34:20 +000016138 putVReg( vD_addr, MK_Iop_MullOdd16Ux8( 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 0x288: // vmuleuw (Multiply Even Unsigned Word)
16142 DIP("vmuleuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16143 putVReg( vD_addr, MK_Iop_MullOdd32Ux4( mkexpr(vA), mkexpr(vB) ) );
16144 break;
16145
cerion32aad402005-09-10 12:02:24 +000016146 case 0x308: // vmulesb (Multiply Even Signed Byte, AV p207)
16147 DIP("vmulesb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion24d06f12005-11-09 21:34:20 +000016148 putVReg( vD_addr, MK_Iop_MullOdd8Sx16( mkexpr(vA), mkexpr(vB) ));
cerion36991ef2005-09-15 12:42:16 +000016149 break;
cerion32aad402005-09-10 12:02:24 +000016150
16151 case 0x348: // vmulesh (Multiply Even Signed Half Word, AV p208)
16152 DIP("vmulesh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion24d06f12005-11-09 21:34:20 +000016153 putVReg( vD_addr, MK_Iop_MullOdd16Sx8( mkexpr(vA), mkexpr(vB) ));
cerion36991ef2005-09-15 12:42:16 +000016154 break;
cerion32aad402005-09-10 12:02:24 +000016155
carll48ae46b2013-10-01 15:45:54 +000016156 case 0x388: // vmulesw (Multiply Even Signed Word)
16157 DIP("vmulesw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16158 putVReg( vD_addr, MK_Iop_MullOdd32Sx4( mkexpr(vA), mkexpr(vB) ) );
16159 break;
cerion32aad402005-09-10 12:02:24 +000016160
16161 /* Sum Across Partial */
cerion4a49b032005-11-08 16:23:07 +000016162 case 0x608: { // vsum4ubs (Sum Partial (1/4) UB Saturate, AV p275)
16163 IRTemp aEE, aEO, aOE, aOO;
16164 aEE = aEO = aOE = aOO = IRTemp_INVALID;
cerion32aad402005-09-10 12:02:24 +000016165 DIP("vsum4ubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion32aad402005-09-10 12:02:24 +000016166
cerion4a49b032005-11-08 16:23:07 +000016167 /* vA: V128_8Ux16 -> 4 x V128_32Ux4, sign-extended */
16168 expand8Ux16( mkexpr(vA), &aEvn, &aOdd ); // (15,13...),(14,12...)
16169 expand16Ux8( mkexpr(aEvn), &aEE, &aEO ); // (15,11...),(13, 9...)
16170 expand16Ux8( mkexpr(aOdd), &aOE, &aOO ); // (14,10...),(12, 8...)
16171
16172 /* break V128 to 4xI32's, zero-extending to I64's */
16173 breakV128to4x64U( mkexpr(aEE), &a15, &a11, &a7, &a3 );
16174 breakV128to4x64U( mkexpr(aOE), &a14, &a10, &a6, &a2 );
16175 breakV128to4x64U( mkexpr(aEO), &a13, &a9, &a5, &a1 );
16176 breakV128to4x64U( mkexpr(aOO), &a12, &a8, &a4, &a0 );
16177 breakV128to4x64U( mkexpr(vB), &b3, &b2, &b1, &b0 );
16178
16179 /* add lanes */
16180 assign( z3, binop(Iop_Add64, mkexpr(b3),
cerion5b2325f2005-12-23 00:55:09 +000016181 binop(Iop_Add64,
16182 binop(Iop_Add64, mkexpr(a15), mkexpr(a14)),
16183 binop(Iop_Add64, mkexpr(a13), mkexpr(a12)))) );
cerion4a49b032005-11-08 16:23:07 +000016184 assign( z2, binop(Iop_Add64, mkexpr(b2),
cerion5b2325f2005-12-23 00:55:09 +000016185 binop(Iop_Add64,
16186 binop(Iop_Add64, mkexpr(a11), mkexpr(a10)),
16187 binop(Iop_Add64, mkexpr(a9), mkexpr(a8)))) );
cerion4a49b032005-11-08 16:23:07 +000016188 assign( z1, binop(Iop_Add64, mkexpr(b1),
cerion5b2325f2005-12-23 00:55:09 +000016189 binop(Iop_Add64,
16190 binop(Iop_Add64, mkexpr(a7), mkexpr(a6)),
16191 binop(Iop_Add64, mkexpr(a5), mkexpr(a4)))) );
cerion4a49b032005-11-08 16:23:07 +000016192 assign( z0, binop(Iop_Add64, mkexpr(b0),
cerion5b2325f2005-12-23 00:55:09 +000016193 binop(Iop_Add64,
16194 binop(Iop_Add64, mkexpr(a3), mkexpr(a2)),
16195 binop(Iop_Add64, mkexpr(a1), mkexpr(a0)))) );
cerion4a49b032005-11-08 16:23:07 +000016196
16197 /* saturate-narrow to 32bit, and combine to V128 */
16198 putVReg( vD_addr, mkV128from4x64U( mkexpr(z3), mkexpr(z2),
16199 mkexpr(z1), mkexpr(z0)) );
16200 break;
16201 }
16202 case 0x708: { // vsum4sbs (Sum Partial (1/4) SB Saturate, AV p273)
16203 IRTemp aEE, aEO, aOE, aOO;
16204 aEE = aEO = aOE = aOO = IRTemp_INVALID;
cerion32aad402005-09-10 12:02:24 +000016205 DIP("vsum4sbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion32aad402005-09-10 12:02:24 +000016206
cerion4a49b032005-11-08 16:23:07 +000016207 /* vA: V128_8Sx16 -> 4 x V128_32Sx4, sign-extended */
16208 expand8Sx16( mkexpr(vA), &aEvn, &aOdd ); // (15,13...),(14,12...)
16209 expand16Sx8( mkexpr(aEvn), &aEE, &aEO ); // (15,11...),(13, 9...)
16210 expand16Sx8( mkexpr(aOdd), &aOE, &aOO ); // (14,10...),(12, 8...)
16211
16212 /* break V128 to 4xI32's, sign-extending to I64's */
16213 breakV128to4x64S( mkexpr(aEE), &a15, &a11, &a7, &a3 );
16214 breakV128to4x64S( mkexpr(aOE), &a14, &a10, &a6, &a2 );
16215 breakV128to4x64S( mkexpr(aEO), &a13, &a9, &a5, &a1 );
16216 breakV128to4x64S( mkexpr(aOO), &a12, &a8, &a4, &a0 );
16217 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
16218
16219 /* add lanes */
16220 assign( z3, binop(Iop_Add64, mkexpr(b3),
cerion5b2325f2005-12-23 00:55:09 +000016221 binop(Iop_Add64,
16222 binop(Iop_Add64, mkexpr(a15), mkexpr(a14)),
16223 binop(Iop_Add64, mkexpr(a13), mkexpr(a12)))) );
cerion4a49b032005-11-08 16:23:07 +000016224 assign( z2, binop(Iop_Add64, mkexpr(b2),
cerion5b2325f2005-12-23 00:55:09 +000016225 binop(Iop_Add64,
16226 binop(Iop_Add64, mkexpr(a11), mkexpr(a10)),
16227 binop(Iop_Add64, mkexpr(a9), mkexpr(a8)))) );
cerion4a49b032005-11-08 16:23:07 +000016228 assign( z1, binop(Iop_Add64, mkexpr(b1),
cerion5b2325f2005-12-23 00:55:09 +000016229 binop(Iop_Add64,
16230 binop(Iop_Add64, mkexpr(a7), mkexpr(a6)),
16231 binop(Iop_Add64, mkexpr(a5), mkexpr(a4)))) );
cerion4a49b032005-11-08 16:23:07 +000016232 assign( z0, binop(Iop_Add64, mkexpr(b0),
cerion5b2325f2005-12-23 00:55:09 +000016233 binop(Iop_Add64,
16234 binop(Iop_Add64, mkexpr(a3), mkexpr(a2)),
16235 binop(Iop_Add64, mkexpr(a1), mkexpr(a0)))) );
cerion4a49b032005-11-08 16:23:07 +000016236
16237 /* saturate-narrow to 32bit, and combine to V128 */
16238 putVReg( vD_addr, mkV128from4x64S( mkexpr(z3), mkexpr(z2),
16239 mkexpr(z1), mkexpr(z0)) );
16240 break;
16241 }
16242 case 0x648: { // vsum4shs (Sum Partial (1/4) SHW Saturate, AV p274)
cerion32aad402005-09-10 12:02:24 +000016243 DIP("vsum4shs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion32aad402005-09-10 12:02:24 +000016244
cerion4a49b032005-11-08 16:23:07 +000016245 /* vA: V128_16Sx8 -> 2 x V128_32Sx4, sign-extended */
16246 expand16Sx8( mkexpr(vA), &aEvn, &aOdd ); // (7,5...),(6,4...)
16247
16248 /* break V128 to 4xI32's, sign-extending to I64's */
16249 breakV128to4x64S( mkexpr(aEvn), &a7, &a5, &a3, &a1 );
16250 breakV128to4x64S( mkexpr(aOdd), &a6, &a4, &a2, &a0 );
16251 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
16252
16253 /* add lanes */
16254 assign( z3, binop(Iop_Add64, mkexpr(b3),
16255 binop(Iop_Add64, mkexpr(a7), mkexpr(a6))));
16256 assign( z2, binop(Iop_Add64, mkexpr(b2),
16257 binop(Iop_Add64, mkexpr(a5), mkexpr(a4))));
16258 assign( z1, binop(Iop_Add64, mkexpr(b1),
16259 binop(Iop_Add64, mkexpr(a3), mkexpr(a2))));
16260 assign( z0, binop(Iop_Add64, mkexpr(b0),
16261 binop(Iop_Add64, mkexpr(a1), mkexpr(a0))));
16262
16263 /* saturate-narrow to 32bit, and combine to V128 */
16264 putVReg( vD_addr, mkV128from4x64S( mkexpr(z3), mkexpr(z2),
16265 mkexpr(z1), mkexpr(z0)) );
16266 break;
16267 }
16268 case 0x688: { // vsum2sws (Sum Partial (1/2) SW Saturate, AV p272)
cerion32aad402005-09-10 12:02:24 +000016269 DIP("vsum2sws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion32aad402005-09-10 12:02:24 +000016270
cerion4a49b032005-11-08 16:23:07 +000016271 /* break V128 to 4xI32's, sign-extending to I64's */
16272 breakV128to4x64S( mkexpr(vA), &a3, &a2, &a1, &a0 );
16273 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
16274
16275 /* add lanes */
16276 assign( z2, binop(Iop_Add64, mkexpr(b2),
16277 binop(Iop_Add64, mkexpr(a3), mkexpr(a2))) );
16278 assign( z0, binop(Iop_Add64, mkexpr(b0),
16279 binop(Iop_Add64, mkexpr(a1), mkexpr(a0))) );
16280
16281 /* saturate-narrow to 32bit, and combine to V128 */
16282 putVReg( vD_addr, mkV128from4x64S( mkU64(0), mkexpr(z2),
16283 mkU64(0), mkexpr(z0)) );
16284 break;
16285 }
16286 case 0x788: { // vsumsws (Sum SW Saturate, AV p271)
cerion32aad402005-09-10 12:02:24 +000016287 DIP("vsumsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion32aad402005-09-10 12:02:24 +000016288
cerion4a49b032005-11-08 16:23:07 +000016289 /* break V128 to 4xI32's, sign-extending to I64's */
16290 breakV128to4x64S( mkexpr(vA), &a3, &a2, &a1, &a0 );
16291 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
16292
16293 /* add lanes */
16294 assign( z0, binop(Iop_Add64, mkexpr(b0),
cerion5b2325f2005-12-23 00:55:09 +000016295 binop(Iop_Add64,
16296 binop(Iop_Add64, mkexpr(a3), mkexpr(a2)),
16297 binop(Iop_Add64, mkexpr(a1), mkexpr(a0)))) );
cerion4a49b032005-11-08 16:23:07 +000016298
16299 /* saturate-narrow to 32bit, and combine to V128 */
16300 putVReg( vD_addr, mkV128from4x64S( mkU64(0), mkU64(0),
16301 mkU64(0), mkexpr(z0)) );
16302 break;
16303 }
cerion32aad402005-09-10 12:02:24 +000016304 default:
cerion5b2325f2005-12-23 00:55:09 +000016305 vex_printf("dis_av_arith(ppc)(opc2=0x%x)\n", opc2);
cerion32aad402005-09-10 12:02:24 +000016306 return False;
16307 }
16308 return True;
16309}
16310
16311/*
16312 AltiVec Logic Instructions
16313*/
16314static Bool dis_av_logic ( UInt theInstr )
16315{
cerion76de5cf2005-11-18 18:25:12 +000016316 /* VX-Form */
16317 UChar opc1 = ifieldOPC(theInstr);
16318 UChar vD_addr = ifieldRegDS(theInstr);
16319 UChar vA_addr = ifieldRegA(theInstr);
16320 UChar vB_addr = ifieldRegB(theInstr);
16321 UInt opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000016322
cerion225a0342005-09-12 20:49:09 +000016323 IRTemp vA = newTemp(Ity_V128);
16324 IRTemp vB = newTemp(Ity_V128);
16325 assign( vA, getVReg(vA_addr));
16326 assign( vB, getVReg(vB_addr));
16327
cerion32aad402005-09-10 12:02:24 +000016328 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000016329 vex_printf("dis_av_logic(ppc)(opc1 != 0x4)\n");
cerion32aad402005-09-10 12:02:24 +000016330 return False;
16331 }
16332
16333 switch (opc2) {
16334 case 0x404: // vand (And, AV p147)
16335 DIP("vand v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion225a0342005-09-12 20:49:09 +000016336 putVReg( vD_addr, binop(Iop_AndV128, mkexpr(vA), mkexpr(vB)) );
16337 break;
cerion32aad402005-09-10 12:02:24 +000016338
16339 case 0x444: // vandc (And, AV p148)
16340 DIP("vandc v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion6e7a0ea2005-09-13 13:34:09 +000016341 putVReg( vD_addr, binop(Iop_AndV128, mkexpr(vA),
cerion76de5cf2005-11-18 18:25:12 +000016342 unop(Iop_NotV128, mkexpr(vB))) );
cerion6e7a0ea2005-09-13 13:34:09 +000016343 break;
cerion32aad402005-09-10 12:02:24 +000016344
16345 case 0x484: // vor (Or, AV p217)
16346 DIP("vor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion225a0342005-09-12 20:49:09 +000016347 putVReg( vD_addr, binop(Iop_OrV128, mkexpr(vA), mkexpr(vB)) );
16348 break;
cerion32aad402005-09-10 12:02:24 +000016349
16350 case 0x4C4: // vxor (Xor, AV p282)
16351 DIP("vxor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion225a0342005-09-12 20:49:09 +000016352 putVReg( vD_addr, binop(Iop_XorV128, mkexpr(vA), mkexpr(vB)) );
16353 break;
cerion32aad402005-09-10 12:02:24 +000016354
16355 case 0x504: // vnor (Nor, AV p216)
16356 DIP("vnor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion6e7a0ea2005-09-13 13:34:09 +000016357 putVReg( vD_addr,
16358 unop(Iop_NotV128, binop(Iop_OrV128, mkexpr(vA), mkexpr(vB))) );
16359 break;
cerion32aad402005-09-10 12:02:24 +000016360
carll7deaf952013-10-15 18:11:20 +000016361 case 0x544: // vorc (vA Or'd with complement of vb)
16362 DIP("vorc v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16363 putVReg( vD_addr, binop( Iop_OrV128,
16364 mkexpr( vA ),
16365 unop( Iop_NotV128, mkexpr( vB ) ) ) );
16366 break;
16367
16368 case 0x584: // vnand (Nand)
16369 DIP("vnand v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16370 putVReg( vD_addr, unop( Iop_NotV128,
16371 binop(Iop_AndV128, mkexpr( vA ),
16372 mkexpr( vB ) ) ) );
16373 break;
16374
16375 case 0x684: // veqv (complemented XOr)
16376 DIP("veqv v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16377 putVReg( vD_addr, unop( Iop_NotV128,
16378 binop( Iop_XorV128, mkexpr( vA ),
16379 mkexpr( vB ) ) ) );
16380 break;
16381
cerion32aad402005-09-10 12:02:24 +000016382 default:
cerion5b2325f2005-12-23 00:55:09 +000016383 vex_printf("dis_av_logic(ppc)(opc2=0x%x)\n", opc2);
cerion32aad402005-09-10 12:02:24 +000016384 return False;
16385 }
16386 return True;
16387}
16388
16389/*
16390 AltiVec Compare Instructions
16391*/
16392static Bool dis_av_cmp ( UInt theInstr )
16393{
cerion76de5cf2005-11-18 18:25:12 +000016394 /* VXR-Form */
16395 UChar opc1 = ifieldOPC(theInstr);
16396 UChar vD_addr = ifieldRegDS(theInstr);
16397 UChar vA_addr = ifieldRegA(theInstr);
16398 UChar vB_addr = ifieldRegB(theInstr);
16399 UChar flag_rC = ifieldBIT10(theInstr);
16400 UInt opc2 = IFIELD( theInstr, 0, 10 );
cerion32aad402005-09-10 12:02:24 +000016401
cerion0c439222005-09-15 14:22:58 +000016402 IRTemp vA = newTemp(Ity_V128);
16403 IRTemp vB = newTemp(Ity_V128);
16404 IRTemp vD = newTemp(Ity_V128);
16405 assign( vA, getVReg(vA_addr));
16406 assign( vB, getVReg(vB_addr));
16407
cerion32aad402005-09-10 12:02:24 +000016408 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000016409 vex_printf("dis_av_cmp(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000016410 return False;
16411 }
16412
16413 switch (opc2) {
16414 case 0x006: // vcmpequb (Compare Equal-to Unsigned B, AV p160)
cerion5b2325f2005-12-23 00:55:09 +000016415 DIP("vcmpequb%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16416 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016417 assign( vD, binop(Iop_CmpEQ8x16, mkexpr(vA), mkexpr(vB)) );
16418 break;
cerion32aad402005-09-10 12:02:24 +000016419
16420 case 0x046: // vcmpequh (Compare Equal-to Unsigned HW, AV p161)
cerion5b2325f2005-12-23 00:55:09 +000016421 DIP("vcmpequh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16422 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016423 assign( vD, binop(Iop_CmpEQ16x8, mkexpr(vA), mkexpr(vB)) );
16424 break;
cerion32aad402005-09-10 12:02:24 +000016425
16426 case 0x086: // vcmpequw (Compare Equal-to Unsigned W, AV p162)
cerion5b2325f2005-12-23 00:55:09 +000016427 DIP("vcmpequw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16428 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016429 assign( vD, binop(Iop_CmpEQ32x4, mkexpr(vA), mkexpr(vB)) );
16430 break;
cerion32aad402005-09-10 12:02:24 +000016431
carll48ae46b2013-10-01 15:45:54 +000016432 case 0x0C7: // vcmpequd (Compare Equal-to Unsigned Doubleword)
16433 DIP("vcmpequd%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16434 vD_addr, vA_addr, vB_addr);
16435 assign( vD, binop(Iop_CmpEQ64x2, mkexpr(vA), mkexpr(vB)) );
16436 break;
16437
cerion32aad402005-09-10 12:02:24 +000016438 case 0x206: // vcmpgtub (Compare Greater-than Unsigned B, AV p168)
cerion5b2325f2005-12-23 00:55:09 +000016439 DIP("vcmpgtub%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16440 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016441 assign( vD, binop(Iop_CmpGT8Ux16, mkexpr(vA), mkexpr(vB)) );
16442 break;
cerion32aad402005-09-10 12:02:24 +000016443
16444 case 0x246: // vcmpgtuh (Compare Greater-than Unsigned HW, AV p169)
cerion5b2325f2005-12-23 00:55:09 +000016445 DIP("vcmpgtuh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16446 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016447 assign( vD, binop(Iop_CmpGT16Ux8, mkexpr(vA), mkexpr(vB)) );
16448 break;
cerion32aad402005-09-10 12:02:24 +000016449
16450 case 0x286: // vcmpgtuw (Compare Greater-than Unsigned W, AV p170)
cerion5b2325f2005-12-23 00:55:09 +000016451 DIP("vcmpgtuw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16452 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016453 assign( vD, binop(Iop_CmpGT32Ux4, mkexpr(vA), mkexpr(vB)) );
16454 break;
cerion32aad402005-09-10 12:02:24 +000016455
carll48ae46b2013-10-01 15:45:54 +000016456 case 0x2C7: // vcmpgtud (Compare Greater-than Unsigned double)
16457 DIP("vcmpgtud%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16458 vD_addr, vA_addr, vB_addr);
16459 assign( vD, binop(Iop_CmpGT64Ux2, mkexpr(vA), mkexpr(vB)) );
16460 break;
16461
cerion32aad402005-09-10 12:02:24 +000016462 case 0x306: // vcmpgtsb (Compare Greater-than Signed B, AV p165)
cerion5b2325f2005-12-23 00:55:09 +000016463 DIP("vcmpgtsb%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16464 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016465 assign( vD, binop(Iop_CmpGT8Sx16, mkexpr(vA), mkexpr(vB)) );
16466 break;
cerion32aad402005-09-10 12:02:24 +000016467
16468 case 0x346: // vcmpgtsh (Compare Greater-than Signed HW, AV p166)
cerion5b2325f2005-12-23 00:55:09 +000016469 DIP("vcmpgtsh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16470 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016471 assign( vD, binop(Iop_CmpGT16Sx8, mkexpr(vA), mkexpr(vB)) );
16472 break;
cerion32aad402005-09-10 12:02:24 +000016473
16474 case 0x386: // vcmpgtsw (Compare Greater-than Signed W, AV p167)
cerion5b2325f2005-12-23 00:55:09 +000016475 DIP("vcmpgtsw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16476 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016477 assign( vD, binop(Iop_CmpGT32Sx4, mkexpr(vA), mkexpr(vB)) );
16478 break;
cerion32aad402005-09-10 12:02:24 +000016479
carll48ae46b2013-10-01 15:45:54 +000016480 case 0x3C7: // vcmpgtsd (Compare Greater-than Signed double)
16481 DIP("vcmpgtsd%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16482 vD_addr, vA_addr, vB_addr);
16483 assign( vD, binop(Iop_CmpGT64Sx2, mkexpr(vA), mkexpr(vB)) );
16484 break;
16485
cerion32aad402005-09-10 12:02:24 +000016486 default:
cerion5b2325f2005-12-23 00:55:09 +000016487 vex_printf("dis_av_cmp(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000016488 return False;
16489 }
cerion0c439222005-09-15 14:22:58 +000016490
16491 putVReg( vD_addr, mkexpr(vD) );
16492
cerion76de5cf2005-11-18 18:25:12 +000016493 if (flag_rC) {
cerion8ea0d3e2005-11-14 00:44:47 +000016494 set_AV_CR6( mkexpr(vD), True );
cerion0c439222005-09-15 14:22:58 +000016495 }
cerion32aad402005-09-10 12:02:24 +000016496 return True;
16497}
16498
16499/*
16500 AltiVec Multiply-Sum Instructions
16501*/
16502static Bool dis_av_multarith ( UInt theInstr )
16503{
cerion76de5cf2005-11-18 18:25:12 +000016504 /* VA-Form */
16505 UChar opc1 = ifieldOPC(theInstr);
16506 UChar vD_addr = ifieldRegDS(theInstr);
16507 UChar vA_addr = ifieldRegA(theInstr);
16508 UChar vB_addr = ifieldRegB(theInstr);
16509 UChar vC_addr = ifieldRegC(theInstr);
16510 UChar opc2 = toUChar( IFIELD( theInstr, 0, 6 ) );
cerion32aad402005-09-10 12:02:24 +000016511
cerion4a49b032005-11-08 16:23:07 +000016512 IRTemp vA = newTemp(Ity_V128);
16513 IRTemp vB = newTemp(Ity_V128);
16514 IRTemp vC = newTemp(Ity_V128);
sewardj197bd172005-10-12 11:34:33 +000016515 IRTemp zeros = newTemp(Ity_V128);
cerion4a49b032005-11-08 16:23:07 +000016516 IRTemp aLo = newTemp(Ity_V128);
16517 IRTemp bLo = newTemp(Ity_V128);
16518 IRTemp cLo = newTemp(Ity_V128);
16519 IRTemp zLo = newTemp(Ity_V128);
16520 IRTemp aHi = newTemp(Ity_V128);
16521 IRTemp bHi = newTemp(Ity_V128);
16522 IRTemp cHi = newTemp(Ity_V128);
16523 IRTemp zHi = newTemp(Ity_V128);
16524 IRTemp abEvn = newTemp(Ity_V128);
16525 IRTemp abOdd = newTemp(Ity_V128);
16526 IRTemp z3 = newTemp(Ity_I64);
16527 IRTemp z2 = newTemp(Ity_I64);
16528 IRTemp z1 = newTemp(Ity_I64);
16529 IRTemp z0 = newTemp(Ity_I64);
16530 IRTemp ab7, ab6, ab5, ab4, ab3, ab2, ab1, ab0;
16531 IRTemp c3, c2, c1, c0;
16532
16533 ab7 = ab6 = ab5 = ab4 = ab3 = ab2 = ab1 = ab0 = IRTemp_INVALID;
16534 c3 = c2 = c1 = c0 = IRTemp_INVALID;
16535
cerion6f1cc0f2005-09-16 16:02:11 +000016536 assign( vA, getVReg(vA_addr));
16537 assign( vB, getVReg(vB_addr));
16538 assign( vC, getVReg(vC_addr));
cerion4a49b032005-11-08 16:23:07 +000016539 assign( zeros, unop(Iop_Dup32x4, mkU32(0)) );
cerion6f1cc0f2005-09-16 16:02:11 +000016540
cerion32aad402005-09-10 12:02:24 +000016541 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000016542 vex_printf("dis_av_multarith(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000016543 return False;
16544 }
16545
16546 switch (opc2) {
cerion32aad402005-09-10 12:02:24 +000016547 /* Multiply-Add */
cerion5b2325f2005-12-23 00:55:09 +000016548 case 0x20: { // vmhaddshs (Mult Hi, Add Signed HW Saturate, AV p185)
cerion6f1cc0f2005-09-16 16:02:11 +000016549 IRTemp cSigns = newTemp(Ity_V128);
cerion5b2325f2005-12-23 00:55:09 +000016550 DIP("vmhaddshs v%d,v%d,v%d,v%d\n",
16551 vD_addr, vA_addr, vB_addr, vC_addr);
16552 assign(cSigns, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vC)));
16553 assign(aLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vA)));
16554 assign(bLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vB)));
16555 assign(cLo, binop(Iop_InterleaveLO16x8, mkexpr(cSigns),mkexpr(vC)));
16556 assign(aHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vA)));
16557 assign(bHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vB)));
16558 assign(cHi, binop(Iop_InterleaveHI16x8, mkexpr(cSigns),mkexpr(vC)));
cerion32aad402005-09-10 12:02:24 +000016559
cerion24d06f12005-11-09 21:34:20 +000016560 assign( zLo, binop(Iop_Add32x4, mkexpr(cLo),
cerion6f1cc0f2005-09-16 16:02:11 +000016561 binop(Iop_SarN32x4,
cerion1ac656a2005-11-04 19:44:48 +000016562 binop(Iop_MullEven16Sx8,
cerion24d06f12005-11-09 21:34:20 +000016563 mkexpr(aLo), mkexpr(bLo)),
16564 mkU8(15))) );
cerion6f1cc0f2005-09-16 16:02:11 +000016565
cerion24d06f12005-11-09 21:34:20 +000016566 assign( zHi, binop(Iop_Add32x4, mkexpr(cHi),
cerion6f1cc0f2005-09-16 16:02:11 +000016567 binop(Iop_SarN32x4,
cerion1ac656a2005-11-04 19:44:48 +000016568 binop(Iop_MullEven16Sx8,
cerion24d06f12005-11-09 21:34:20 +000016569 mkexpr(aHi), mkexpr(bHi)),
16570 mkU8(15))) );
cerion6f1cc0f2005-09-16 16:02:11 +000016571
cerion5b2325f2005-12-23 00:55:09 +000016572 putVReg( vD_addr,
sewardj5f438dd2011-06-16 11:36:23 +000016573 binop(Iop_QNarrowBin32Sto16Sx8, mkexpr(zHi), mkexpr(zLo)) );
cerion6f1cc0f2005-09-16 16:02:11 +000016574 break;
16575 }
cerion5b2325f2005-12-23 00:55:09 +000016576 case 0x21: { // vmhraddshs (Mult High Round, Add Signed HW Saturate, AV p186)
cerion6f1cc0f2005-09-16 16:02:11 +000016577 IRTemp zKonst = newTemp(Ity_V128);
cerion6f1cc0f2005-09-16 16:02:11 +000016578 IRTemp cSigns = newTemp(Ity_V128);
cerion5b2325f2005-12-23 00:55:09 +000016579 DIP("vmhraddshs v%d,v%d,v%d,v%d\n",
16580 vD_addr, vA_addr, vB_addr, vC_addr);
16581 assign(cSigns, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vC)) );
16582 assign(aLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vA)));
16583 assign(bLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vB)));
16584 assign(cLo, binop(Iop_InterleaveLO16x8, mkexpr(cSigns),mkexpr(vC)));
16585 assign(aHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vA)));
16586 assign(bHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vB)));
16587 assign(cHi, binop(Iop_InterleaveHI16x8, mkexpr(cSigns),mkexpr(vC)));
cerion32aad402005-09-10 12:02:24 +000016588
cerion6f1cc0f2005-09-16 16:02:11 +000016589 /* shifting our const avoids store/load version of Dup */
cerion4a49b032005-11-08 16:23:07 +000016590 assign( zKonst, binop(Iop_ShlN32x4, unop(Iop_Dup32x4, mkU32(0x1)),
16591 mkU8(14)) );
cerion6f1cc0f2005-09-16 16:02:11 +000016592
cerion24d06f12005-11-09 21:34:20 +000016593 assign( zLo, binop(Iop_Add32x4, mkexpr(cLo),
cerion6f1cc0f2005-09-16 16:02:11 +000016594 binop(Iop_SarN32x4,
16595 binop(Iop_Add32x4, mkexpr(zKonst),
cerion1ac656a2005-11-04 19:44:48 +000016596 binop(Iop_MullEven16Sx8,
cerion24d06f12005-11-09 21:34:20 +000016597 mkexpr(aLo), mkexpr(bLo))),
16598 mkU8(15))) );
cerion6f1cc0f2005-09-16 16:02:11 +000016599
cerion24d06f12005-11-09 21:34:20 +000016600 assign( zHi, binop(Iop_Add32x4, mkexpr(cHi),
cerion6f1cc0f2005-09-16 16:02:11 +000016601 binop(Iop_SarN32x4,
16602 binop(Iop_Add32x4, mkexpr(zKonst),
cerion1ac656a2005-11-04 19:44:48 +000016603 binop(Iop_MullEven16Sx8,
cerion24d06f12005-11-09 21:34:20 +000016604 mkexpr(aHi), mkexpr(bHi))),
16605 mkU8(15))) );
cerion6f1cc0f2005-09-16 16:02:11 +000016606
sewardjc9bff7d2011-06-15 15:09:37 +000016607 putVReg( vD_addr,
sewardj5f438dd2011-06-16 11:36:23 +000016608 binop(Iop_QNarrowBin32Sto16Sx8, mkexpr(zHi), mkexpr(zLo)) );
cerion6f1cc0f2005-09-16 16:02:11 +000016609 break;
16610 }
cerion5b2325f2005-12-23 00:55:09 +000016611 case 0x22: { // vmladduhm (Mult Low, Add Unsigned HW Modulo, AV p194)
16612 DIP("vmladduhm v%d,v%d,v%d,v%d\n",
16613 vD_addr, vA_addr, vB_addr, vC_addr);
16614 assign(aLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vA)));
16615 assign(bLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vB)));
16616 assign(cLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vC)));
16617 assign(aHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vA)));
16618 assign(bHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vB)));
16619 assign(cHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vC)));
16620 assign(zLo, binop(Iop_Add32x4,
16621 binop(Iop_MullEven16Ux8, mkexpr(aLo), mkexpr(bLo)),
16622 mkexpr(cLo)) );
16623 assign(zHi, binop(Iop_Add32x4,
16624 binop(Iop_MullEven16Ux8, mkexpr(aHi), mkexpr(bHi)),
16625 mkexpr(cHi)));
sewardj5f438dd2011-06-16 11:36:23 +000016626 putVReg( vD_addr,
16627 binop(Iop_NarrowBin32to16x8, mkexpr(zHi), mkexpr(zLo)) );
cerion6f1cc0f2005-09-16 16:02:11 +000016628 break;
16629 }
cerion32aad402005-09-10 12:02:24 +000016630
16631
16632 /* Multiply-Sum */
cerion6f1cc0f2005-09-16 16:02:11 +000016633 case 0x24: { // vmsumubm (Multiply Sum Unsigned B Modulo, AV p204)
cerion4a49b032005-11-08 16:23:07 +000016634 IRTemp abEE, abEO, abOE, abOO;
16635 abEE = abEO = abOE = abOO = IRTemp_INVALID;
cerion5b2325f2005-12-23 00:55:09 +000016636 DIP("vmsumubm v%d,v%d,v%d,v%d\n",
16637 vD_addr, vA_addr, vB_addr, vC_addr);
cerion32aad402005-09-10 12:02:24 +000016638
cerion4a49b032005-11-08 16:23:07 +000016639 /* multiply vA,vB (unsigned, widening) */
cerion24d06f12005-11-09 21:34:20 +000016640 assign( abEvn, MK_Iop_MullOdd8Ux16( mkexpr(vA), mkexpr(vB) ));
16641 assign( abOdd, binop(Iop_MullEven8Ux16, mkexpr(vA), mkexpr(vB)) );
cerion4a49b032005-11-08 16:23:07 +000016642
16643 /* evn,odd: V128_16Ux8 -> 2 x V128_32Ux4, zero-extended */
16644 expand16Ux8( mkexpr(abEvn), &abEE, &abEO );
16645 expand16Ux8( mkexpr(abOdd), &abOE, &abOO );
16646
cerion6f1cc0f2005-09-16 16:02:11 +000016647 putVReg( vD_addr,
cerion5b2325f2005-12-23 00:55:09 +000016648 binop(Iop_Add32x4, mkexpr(vC),
16649 binop(Iop_Add32x4,
16650 binop(Iop_Add32x4, mkexpr(abEE), mkexpr(abEO)),
16651 binop(Iop_Add32x4, mkexpr(abOE), mkexpr(abOO)))) );
cerion6f1cc0f2005-09-16 16:02:11 +000016652 break;
16653 }
cerion4a49b032005-11-08 16:23:07 +000016654 case 0x25: { // vmsummbm (Multiply Sum Mixed-Sign B Modulo, AV p201)
16655 IRTemp aEvn, aOdd, bEvn, bOdd;
16656 IRTemp abEE = newTemp(Ity_V128);
16657 IRTemp abEO = newTemp(Ity_V128);
16658 IRTemp abOE = newTemp(Ity_V128);
16659 IRTemp abOO = newTemp(Ity_V128);
16660 aEvn = aOdd = bEvn = bOdd = IRTemp_INVALID;
cerion5b2325f2005-12-23 00:55:09 +000016661 DIP("vmsummbm v%d,v%d,v%d,v%d\n",
16662 vD_addr, vA_addr, vB_addr, vC_addr);
cerion32aad402005-09-10 12:02:24 +000016663
cerion4a49b032005-11-08 16:23:07 +000016664 /* sign-extend vA, zero-extend vB, for mixed-sign multiply
16665 (separating out adjacent lanes to different vectors) */
16666 expand8Sx16( mkexpr(vA), &aEvn, &aOdd );
16667 expand8Ux16( mkexpr(vB), &bEvn, &bOdd );
16668
16669 /* multiply vA, vB, again separating adjacent lanes */
cerion24d06f12005-11-09 21:34:20 +000016670 assign( abEE, MK_Iop_MullOdd16Sx8( mkexpr(aEvn), mkexpr(bEvn) ));
16671 assign( abEO, binop(Iop_MullEven16Sx8, mkexpr(aEvn), mkexpr(bEvn)) );
16672 assign( abOE, MK_Iop_MullOdd16Sx8( mkexpr(aOdd), mkexpr(bOdd) ));
16673 assign( abOO, binop(Iop_MullEven16Sx8, mkexpr(aOdd), mkexpr(bOdd)) );
cerion4a49b032005-11-08 16:23:07 +000016674
16675 /* add results together, + vC */
16676 putVReg( vD_addr,
cerion5b2325f2005-12-23 00:55:09 +000016677 binop(Iop_QAdd32Sx4, mkexpr(vC),
16678 binop(Iop_QAdd32Sx4,
16679 binop(Iop_QAdd32Sx4, mkexpr(abEE), mkexpr(abEO)),
16680 binop(Iop_QAdd32Sx4, mkexpr(abOE), mkexpr(abOO)))) );
cerion4a49b032005-11-08 16:23:07 +000016681 break;
16682 }
cerion6f1cc0f2005-09-16 16:02:11 +000016683 case 0x26: { // vmsumuhm (Multiply Sum Unsigned HW Modulo, AV p205)
cerion5b2325f2005-12-23 00:55:09 +000016684 DIP("vmsumuhm v%d,v%d,v%d,v%d\n",
16685 vD_addr, vA_addr, vB_addr, vC_addr);
cerion24d06f12005-11-09 21:34:20 +000016686 assign( abEvn, MK_Iop_MullOdd16Ux8( mkexpr(vA), mkexpr(vB) ));
16687 assign( abOdd, binop(Iop_MullEven16Ux8, mkexpr(vA), mkexpr(vB)) );
cerion6f1cc0f2005-09-16 16:02:11 +000016688 putVReg( vD_addr,
cerion5b2325f2005-12-23 00:55:09 +000016689 binop(Iop_Add32x4, mkexpr(vC),
16690 binop(Iop_Add32x4, mkexpr(abEvn), mkexpr(abOdd))) );
cerion6f1cc0f2005-09-16 16:02:11 +000016691 break;
16692 }
cerion4a49b032005-11-08 16:23:07 +000016693 case 0x27: { // vmsumuhs (Multiply Sum Unsigned HW Saturate, AV p206)
cerion5b2325f2005-12-23 00:55:09 +000016694 DIP("vmsumuhs v%d,v%d,v%d,v%d\n",
16695 vD_addr, vA_addr, vB_addr, vC_addr);
cerion4a49b032005-11-08 16:23:07 +000016696 /* widening multiply, separating lanes */
cerion24d06f12005-11-09 21:34:20 +000016697 assign( abEvn, MK_Iop_MullOdd16Ux8(mkexpr(vA), mkexpr(vB) ));
16698 assign( abOdd, binop(Iop_MullEven16Ux8, mkexpr(vA), mkexpr(vB)) );
cerion32aad402005-09-10 12:02:24 +000016699
cerion4a49b032005-11-08 16:23:07 +000016700 /* break V128 to 4xI32's, zero-extending to I64's */
16701 breakV128to4x64U( mkexpr(abEvn), &ab7, &ab5, &ab3, &ab1 );
16702 breakV128to4x64U( mkexpr(abOdd), &ab6, &ab4, &ab2, &ab0 );
16703 breakV128to4x64U( mkexpr(vC), &c3, &c2, &c1, &c0 );
16704
16705 /* add lanes */
16706 assign( z3, binop(Iop_Add64, mkexpr(c3),
16707 binop(Iop_Add64, mkexpr(ab7), mkexpr(ab6))));
16708 assign( z2, binop(Iop_Add64, mkexpr(c2),
16709 binop(Iop_Add64, mkexpr(ab5), mkexpr(ab4))));
16710 assign( z1, binop(Iop_Add64, mkexpr(c1),
16711 binop(Iop_Add64, mkexpr(ab3), mkexpr(ab2))));
16712 assign( z0, binop(Iop_Add64, mkexpr(c0),
16713 binop(Iop_Add64, mkexpr(ab1), mkexpr(ab0))));
16714
16715 /* saturate-narrow to 32bit, and combine to V128 */
16716 putVReg( vD_addr, mkV128from4x64U( mkexpr(z3), mkexpr(z2),
16717 mkexpr(z1), mkexpr(z0)) );
16718
cerion6f1cc0f2005-09-16 16:02:11 +000016719 break;
16720 }
cerion4a49b032005-11-08 16:23:07 +000016721 case 0x28: { // vmsumshm (Multiply Sum Signed HW Modulo, AV p202)
cerion5b2325f2005-12-23 00:55:09 +000016722 DIP("vmsumshm v%d,v%d,v%d,v%d\n",
16723 vD_addr, vA_addr, vB_addr, vC_addr);
cerion24d06f12005-11-09 21:34:20 +000016724 assign( abEvn, MK_Iop_MullOdd16Sx8( mkexpr(vA), mkexpr(vB) ));
16725 assign( abOdd, binop(Iop_MullEven16Sx8, mkexpr(vA), mkexpr(vB)) );
cerion4a49b032005-11-08 16:23:07 +000016726 putVReg( vD_addr,
cerion5b2325f2005-12-23 00:55:09 +000016727 binop(Iop_Add32x4, mkexpr(vC),
16728 binop(Iop_Add32x4, mkexpr(abOdd), mkexpr(abEvn))) );
cerion4a49b032005-11-08 16:23:07 +000016729 break;
16730 }
16731 case 0x29: { // vmsumshs (Multiply Sum Signed HW Saturate, AV p203)
cerion5b2325f2005-12-23 00:55:09 +000016732 DIP("vmsumshs v%d,v%d,v%d,v%d\n",
16733 vD_addr, vA_addr, vB_addr, vC_addr);
cerion4a49b032005-11-08 16:23:07 +000016734 /* widening multiply, separating lanes */
cerion24d06f12005-11-09 21:34:20 +000016735 assign( abEvn, MK_Iop_MullOdd16Sx8( mkexpr(vA), mkexpr(vB) ));
16736 assign( abOdd, binop(Iop_MullEven16Sx8, mkexpr(vA), mkexpr(vB)) );
cerion32aad402005-09-10 12:02:24 +000016737
cerion4a49b032005-11-08 16:23:07 +000016738 /* break V128 to 4xI32's, sign-extending to I64's */
16739 breakV128to4x64S( mkexpr(abEvn), &ab7, &ab5, &ab3, &ab1 );
16740 breakV128to4x64S( mkexpr(abOdd), &ab6, &ab4, &ab2, &ab0 );
16741 breakV128to4x64S( mkexpr(vC), &c3, &c2, &c1, &c0 );
16742
16743 /* add lanes */
16744 assign( z3, binop(Iop_Add64, mkexpr(c3),
16745 binop(Iop_Add64, mkexpr(ab7), mkexpr(ab6))));
16746 assign( z2, binop(Iop_Add64, mkexpr(c2),
16747 binop(Iop_Add64, mkexpr(ab5), mkexpr(ab4))));
16748 assign( z1, binop(Iop_Add64, mkexpr(c1),
16749 binop(Iop_Add64, mkexpr(ab3), mkexpr(ab2))));
16750 assign( z0, binop(Iop_Add64, mkexpr(c0),
16751 binop(Iop_Add64, mkexpr(ab1), mkexpr(ab0))));
16752
16753 /* saturate-narrow to 32bit, and combine to V128 */
16754 putVReg( vD_addr, mkV128from4x64S( mkexpr(z3), mkexpr(z2),
16755 mkexpr(z1), mkexpr(z0)) );
16756 break;
16757 }
cerion32aad402005-09-10 12:02:24 +000016758 default:
cerion5b2325f2005-12-23 00:55:09 +000016759 vex_printf("dis_av_multarith(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000016760 return False;
16761 }
16762 return True;
16763}
16764
16765/*
carll7deaf952013-10-15 18:11:20 +000016766 AltiVec Polynomial Multiply-Sum Instructions
16767*/
16768static Bool dis_av_polymultarith ( UInt theInstr )
16769{
16770 /* VA-Form */
16771 UChar opc1 = ifieldOPC(theInstr);
16772 UChar vD_addr = ifieldRegDS(theInstr);
16773 UChar vA_addr = ifieldRegA(theInstr);
16774 UChar vB_addr = ifieldRegB(theInstr);
16775 UChar vC_addr = ifieldRegC(theInstr);
16776 UInt opc2 = IFIELD(theInstr, 0, 11);
16777 IRTemp vA = newTemp(Ity_V128);
16778 IRTemp vB = newTemp(Ity_V128);
16779 IRTemp vC = newTemp(Ity_V128);
16780
16781 assign( vA, getVReg(vA_addr));
16782 assign( vB, getVReg(vB_addr));
16783 assign( vC, getVReg(vC_addr));
16784
16785 if (opc1 != 0x4) {
16786 vex_printf("dis_av_polymultarith(ppc)(instr)\n");
16787 return False;
16788 }
16789
16790 switch (opc2) {
16791 /* Polynomial Multiply-Add */
16792 case 0x408: // vpmsumb Vector Polynomial Multipy-sum Byte
16793 DIP("vpmsumb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16794 putVReg( vD_addr, binop(Iop_PolynomialMulAdd8x16,
16795 mkexpr(vA), mkexpr(vB)) );
16796 break;
16797 case 0x448: // vpmsumd Vector Polynomial Multipy-sum Double Word
16798 DIP("vpmsumd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16799 putVReg( vD_addr, binop(Iop_PolynomialMulAdd64x2,
16800 mkexpr(vA), mkexpr(vB)) );
16801 break;
16802 case 0x488: // vpmsumw Vector Polynomial Multipy-sum Word
16803 DIP("vpmsumw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16804 putVReg( vD_addr, binop(Iop_PolynomialMulAdd32x4,
16805 mkexpr(vA), mkexpr(vB)) );
16806 break;
16807 case 0x4C8: // vpmsumh Vector Polynomial Multipy-sum Half Word
16808 DIP("vpmsumh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16809 putVReg( vD_addr, binop(Iop_PolynomialMulAdd16x8,
16810 mkexpr(vA), mkexpr(vB)) );
16811 break;
16812 default:
16813 vex_printf("dis_av_polymultarith(ppc)(opc2=0x%x)\n", opc2);
16814 return False;
16815 }
16816 return True;
16817}
16818
16819/*
cerion32aad402005-09-10 12:02:24 +000016820 AltiVec Shift/Rotate Instructions
16821*/
16822static Bool dis_av_shift ( UInt theInstr )
16823{
cerion76de5cf2005-11-18 18:25:12 +000016824 /* VX-Form */
16825 UChar opc1 = ifieldOPC(theInstr);
16826 UChar vD_addr = ifieldRegDS(theInstr);
16827 UChar vA_addr = ifieldRegA(theInstr);
16828 UChar vB_addr = ifieldRegB(theInstr);
16829 UInt opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000016830
cerion27b3d7e2005-09-14 20:35:47 +000016831 IRTemp vA = newTemp(Ity_V128);
16832 IRTemp vB = newTemp(Ity_V128);
16833 assign( vA, getVReg(vA_addr));
16834 assign( vB, getVReg(vB_addr));
16835
cerion32aad402005-09-10 12:02:24 +000016836 if (opc1 != 0x4){
cerion5b2325f2005-12-23 00:55:09 +000016837 vex_printf("dis_av_shift(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000016838 return False;
16839 }
16840
16841 switch (opc2) {
16842 /* Rotate */
16843 case 0x004: // vrlb (Rotate Left Integer B, AV p234)
16844 DIP("vrlb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj1bee5612005-11-10 18:10:58 +000016845 putVReg( vD_addr, binop(Iop_Rol8x16, mkexpr(vA), mkexpr(vB)) );
cerion0a7b4f42005-09-16 07:54:40 +000016846 break;
cerion32aad402005-09-10 12:02:24 +000016847
16848 case 0x044: // vrlh (Rotate Left Integer HW, AV p235)
16849 DIP("vrlh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj1bee5612005-11-10 18:10:58 +000016850 putVReg( vD_addr, binop(Iop_Rol16x8, mkexpr(vA), mkexpr(vB)) );
cerion0a7b4f42005-09-16 07:54:40 +000016851 break;
cerion32aad402005-09-10 12:02:24 +000016852
16853 case 0x084: // vrlw (Rotate Left Integer W, AV p236)
16854 DIP("vrlw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj1bee5612005-11-10 18:10:58 +000016855 putVReg( vD_addr, binop(Iop_Rol32x4, mkexpr(vA), mkexpr(vB)) );
cerion0a7b4f42005-09-16 07:54:40 +000016856 break;
cerion32aad402005-09-10 12:02:24 +000016857
carll48ae46b2013-10-01 15:45:54 +000016858 case 0x0C4: // vrld (Rotate Left Integer Double Word)
16859 DIP("vrld v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16860 putVReg( vD_addr, binop(Iop_Rol64x2, mkexpr(vA), mkexpr(vB)) );
16861 break;
16862
cerion32aad402005-09-10 12:02:24 +000016863
16864 /* Shift Left */
16865 case 0x104: // vslb (Shift Left Integer B, AV p240)
16866 DIP("vslb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016867 putVReg( vD_addr, binop(Iop_Shl8x16, mkexpr(vA), mkexpr(vB)) );
16868 break;
cerion32aad402005-09-10 12:02:24 +000016869
16870 case 0x144: // vslh (Shift Left Integer HW, AV p242)
16871 DIP("vslh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016872 putVReg( vD_addr, binop(Iop_Shl16x8, mkexpr(vA), mkexpr(vB)) );
16873 break;
cerion32aad402005-09-10 12:02:24 +000016874
16875 case 0x184: // vslw (Shift Left Integer W, AV p244)
16876 DIP("vslw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016877 putVReg( vD_addr, binop(Iop_Shl32x4, mkexpr(vA), mkexpr(vB)) );
16878 break;
cerion32aad402005-09-10 12:02:24 +000016879
carll48ae46b2013-10-01 15:45:54 +000016880 case 0x5C4: // vsld (Shift Left Integer Double Word)
16881 DIP("vsld v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16882 putVReg( vD_addr, binop(Iop_Shl64x2, mkexpr(vA), mkexpr(vB)) );
16883 break;
16884
cerion0a7b4f42005-09-16 07:54:40 +000016885 case 0x1C4: { // vsl (Shift Left, AV p239)
cerion0a7b4f42005-09-16 07:54:40 +000016886 IRTemp sh = newTemp(Ity_I8);
sewardj197bd172005-10-12 11:34:33 +000016887 DIP("vsl v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016888 assign( sh, binop(Iop_And8, mkU8(0x7),
16889 unop(Iop_32to8,
16890 unop(Iop_V128to32, mkexpr(vB)))) );
16891 putVReg( vD_addr,
16892 binop(Iop_ShlV128, mkexpr(vA), mkexpr(sh)) );
16893 break;
16894 }
16895 case 0x40C: { // vslo (Shift Left by Octet, AV p243)
cerion0a7b4f42005-09-16 07:54:40 +000016896 IRTemp sh = newTemp(Ity_I8);
sewardj197bd172005-10-12 11:34:33 +000016897 DIP("vslo v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016898 assign( sh, binop(Iop_And8, mkU8(0x78),
16899 unop(Iop_32to8,
16900 unop(Iop_V128to32, mkexpr(vB)))) );
16901 putVReg( vD_addr,
16902 binop(Iop_ShlV128, mkexpr(vA), mkexpr(sh)) );
16903 break;
16904 }
16905
cerion32aad402005-09-10 12:02:24 +000016906
16907 /* Shift Right */
16908 case 0x204: // vsrb (Shift Right B, AV p256)
16909 DIP("vsrb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016910 putVReg( vD_addr, binop(Iop_Shr8x16, mkexpr(vA), mkexpr(vB)) );
16911 break;
cerion32aad402005-09-10 12:02:24 +000016912
16913 case 0x244: // vsrh (Shift Right HW, AV p257)
16914 DIP("vsrh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016915 putVReg( vD_addr, binop(Iop_Shr16x8, mkexpr(vA), mkexpr(vB)) );
16916 break;
cerion32aad402005-09-10 12:02:24 +000016917
16918 case 0x284: // vsrw (Shift Right W, AV p259)
16919 DIP("vsrw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016920 putVReg( vD_addr, binop(Iop_Shr32x4, mkexpr(vA), mkexpr(vB)) );
16921 break;
cerion32aad402005-09-10 12:02:24 +000016922
cerion27b3d7e2005-09-14 20:35:47 +000016923 case 0x2C4: { // vsr (Shift Right, AV p251)
cerion27b3d7e2005-09-14 20:35:47 +000016924 IRTemp sh = newTemp(Ity_I8);
sewardj197bd172005-10-12 11:34:33 +000016925 DIP("vsr v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion27b3d7e2005-09-14 20:35:47 +000016926 assign( sh, binop(Iop_And8, mkU8(0x7),
16927 unop(Iop_32to8,
16928 unop(Iop_V128to32, mkexpr(vB)))) );
16929 putVReg( vD_addr,
16930 binop(Iop_ShrV128, mkexpr(vA), mkexpr(sh)) );
16931 break;
16932 }
cerion5b2325f2005-12-23 00:55:09 +000016933 case 0x304: // vsrab (Shift Right Alg B, AV p253)
cerion32aad402005-09-10 12:02:24 +000016934 DIP("vsrab v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016935 putVReg( vD_addr, binop(Iop_Sar8x16, mkexpr(vA), mkexpr(vB)) );
16936 break;
cerion32aad402005-09-10 12:02:24 +000016937
cerion5b2325f2005-12-23 00:55:09 +000016938 case 0x344: // vsrah (Shift Right Alg HW, AV p254)
cerion32aad402005-09-10 12:02:24 +000016939 DIP("vsrah v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016940 putVReg( vD_addr, binop(Iop_Sar16x8, mkexpr(vA), mkexpr(vB)) );
16941 break;
cerion32aad402005-09-10 12:02:24 +000016942
cerion5b2325f2005-12-23 00:55:09 +000016943 case 0x384: // vsraw (Shift Right Alg W, AV p255)
cerion32aad402005-09-10 12:02:24 +000016944 DIP("vsraw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016945 putVReg( vD_addr, binop(Iop_Sar32x4, mkexpr(vA), mkexpr(vB)) );
16946 break;
cerion32aad402005-09-10 12:02:24 +000016947
carll48ae46b2013-10-01 15:45:54 +000016948 case 0x3C4: // vsrad (Shift Right Alg Double Word)
16949 DIP("vsrad v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16950 putVReg( vD_addr, binop(Iop_Sar64x2, mkexpr(vA), mkexpr(vB)) );
16951 break;
16952
cerion0a7b4f42005-09-16 07:54:40 +000016953 case 0x44C: { // vsro (Shift Right by Octet, AV p258)
cerion0a7b4f42005-09-16 07:54:40 +000016954 IRTemp sh = newTemp(Ity_I8);
sewardj197bd172005-10-12 11:34:33 +000016955 DIP("vsro v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016956 assign( sh, binop(Iop_And8, mkU8(0x78),
16957 unop(Iop_32to8,
16958 unop(Iop_V128to32, mkexpr(vB)))) );
16959 putVReg( vD_addr,
16960 binop(Iop_ShrV128, mkexpr(vA), mkexpr(sh)) );
16961 break;
16962 }
cerion32aad402005-09-10 12:02:24 +000016963
carll48ae46b2013-10-01 15:45:54 +000016964 case 0x6C4: // vsrd (Shift Right Double Word)
16965 DIP("vsrd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16966 putVReg( vD_addr, binop(Iop_Shr64x2, mkexpr(vA), mkexpr(vB)) );
16967 break;
16968
16969
cerion32aad402005-09-10 12:02:24 +000016970 default:
cerion5b2325f2005-12-23 00:55:09 +000016971 vex_printf("dis_av_shift(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000016972 return False;
16973 }
16974 return True;
16975}
16976
16977/*
16978 AltiVec Permute Instructions
16979*/
16980static Bool dis_av_permute ( UInt theInstr )
16981{
cerion76de5cf2005-11-18 18:25:12 +000016982 /* VA-Form, VX-Form */
16983 UChar opc1 = ifieldOPC(theInstr);
16984 UChar vD_addr = ifieldRegDS(theInstr);
16985 UChar vA_addr = ifieldRegA(theInstr);
16986 UChar UIMM_5 = vA_addr;
16987 UChar vB_addr = ifieldRegB(theInstr);
16988 UChar vC_addr = ifieldRegC(theInstr);
16989 UChar b10 = ifieldBIT10(theInstr);
16990 UChar SHB_uimm4 = toUChar( IFIELD( theInstr, 6, 4 ) );
16991 UInt opc2 = toUChar( IFIELD( theInstr, 0, 6 ) );
cerion32aad402005-09-10 12:02:24 +000016992
cerion76de5cf2005-11-18 18:25:12 +000016993 UChar SIMM_8 = extend_s_5to8(UIMM_5);
cerion32aad402005-09-10 12:02:24 +000016994
cerion6e7a0ea2005-09-13 13:34:09 +000016995 IRTemp vA = newTemp(Ity_V128);
16996 IRTemp vB = newTemp(Ity_V128);
16997 IRTemp vC = newTemp(Ity_V128);
16998 assign( vA, getVReg(vA_addr));
16999 assign( vB, getVReg(vB_addr));
17000 assign( vC, getVReg(vC_addr));
17001
cerion32aad402005-09-10 12:02:24 +000017002 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000017003 vex_printf("dis_av_permute(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000017004 return False;
17005 }
17006
17007 switch (opc2) {
17008 case 0x2A: // vsel (Conditional Select, AV p238)
17009 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 +000017010 /* vD = (vA & ~vC) | (vB & vC) */
17011 putVReg( vD_addr, binop(Iop_OrV128,
17012 binop(Iop_AndV128, mkexpr(vA), unop(Iop_NotV128, mkexpr(vC))),
17013 binop(Iop_AndV128, mkexpr(vB), mkexpr(vC))) );
17014 return True;
cerion32aad402005-09-10 12:02:24 +000017015
cerion92d9d872005-09-15 21:58:50 +000017016 case 0x2B: { // vperm (Permute, AV p218)
cerion92d9d872005-09-15 21:58:50 +000017017 /* limited to two args for IR, so have to play games... */
sewardjdc1f9132005-10-22 12:49:49 +000017018 IRTemp a_perm = newTemp(Ity_V128);
17019 IRTemp b_perm = newTemp(Ity_V128);
17020 IRTemp mask = newTemp(Ity_V128);
17021 IRTemp vC_andF = newTemp(Ity_V128);
cerion5b2325f2005-12-23 00:55:09 +000017022 DIP("vperm v%d,v%d,v%d,v%d\n",
17023 vD_addr, vA_addr, vB_addr, vC_addr);
sewardjdc1f9132005-10-22 12:49:49 +000017024 /* Limit the Perm8x16 steering values to 0 .. 15 as that is what
17025 IR specifies, and also to hide irrelevant bits from
17026 memcheck */
cerion5b2325f2005-12-23 00:55:09 +000017027 assign( vC_andF,
17028 binop(Iop_AndV128, mkexpr(vC),
17029 unop(Iop_Dup8x16, mkU8(0xF))) );
17030 assign( a_perm,
17031 binop(Iop_Perm8x16, mkexpr(vA), mkexpr(vC_andF)) );
17032 assign( b_perm,
17033 binop(Iop_Perm8x16, mkexpr(vB), mkexpr(vC_andF)) );
cerion92d9d872005-09-15 21:58:50 +000017034 // mask[i8] = (vC[i8]_4 == 1) ? 0xFF : 0x0
17035 assign( mask, binop(Iop_SarN8x16,
17036 binop(Iop_ShlN8x16, mkexpr(vC), mkU8(3)),
17037 mkU8(7)) );
17038 // dst = (a & ~mask) | (b & mask)
17039 putVReg( vD_addr, binop(Iop_OrV128,
17040 binop(Iop_AndV128, mkexpr(a_perm),
17041 unop(Iop_NotV128, mkexpr(mask))),
17042 binop(Iop_AndV128, mkexpr(b_perm),
17043 mkexpr(mask))) );
17044 return True;
17045 }
cerion32aad402005-09-10 12:02:24 +000017046 case 0x2C: // vsldoi (Shift Left Double by Octet Imm, AV p241)
17047 if (b10 != 0) {
cerion5b2325f2005-12-23 00:55:09 +000017048 vex_printf("dis_av_permute(ppc)(vsldoi)\n");
cerion32aad402005-09-10 12:02:24 +000017049 return False;
17050 }
cerion5b2325f2005-12-23 00:55:09 +000017051 DIP("vsldoi v%d,v%d,v%d,%d\n",
17052 vD_addr, vA_addr, vB_addr, SHB_uimm4);
cerion92d9d872005-09-15 21:58:50 +000017053 if (SHB_uimm4 == 0)
17054 putVReg( vD_addr, mkexpr(vA) );
17055 else
17056 putVReg( vD_addr,
cerion5b2325f2005-12-23 00:55:09 +000017057 binop(Iop_OrV128,
17058 binop(Iop_ShlV128, mkexpr(vA), mkU8(SHB_uimm4*8)),
17059 binop(Iop_ShrV128, mkexpr(vB), mkU8((16-SHB_uimm4)*8))) );
cerion92d9d872005-09-15 21:58:50 +000017060 return True;
carll7deaf952013-10-15 18:11:20 +000017061 case 0x2D: { // vpermxor (Vector Permute and Exclusive-OR)
17062 IRTemp a_perm = newTemp(Ity_V128);
17063 IRTemp b_perm = newTemp(Ity_V128);
17064 IRTemp vrc_a = newTemp(Ity_V128);
17065 IRTemp vrc_b = newTemp(Ity_V128);
cerion32aad402005-09-10 12:02:24 +000017066
carll7deaf952013-10-15 18:11:20 +000017067 /* IBM index is 0:7, Change index value to index 7:0 */
17068 assign( vrc_b, binop( Iop_AndV128, mkexpr( vC ),
17069 unop( Iop_Dup8x16, mkU8( 0xF ) ) ) );
17070 assign( vrc_a, binop( Iop_ShrV128,
17071 binop( Iop_AndV128, mkexpr( vC ),
17072 unop( Iop_Dup8x16, mkU8( 0xF0 ) ) ),
17073 mkU8 ( 4 ) ) );
17074 assign( a_perm, binop( Iop_Perm8x16, mkexpr( vA ), mkexpr( vrc_a ) ) );
17075 assign( b_perm, binop( Iop_Perm8x16, mkexpr( vB ), mkexpr( vrc_b ) ) );
17076 putVReg( vD_addr, binop( Iop_XorV128,
17077 mkexpr( a_perm ), mkexpr( b_perm) ) );
17078 return True;
17079 }
cerion32aad402005-09-10 12:02:24 +000017080 default:
17081 break; // Fall through...
17082 }
17083
cerion76de5cf2005-11-18 18:25:12 +000017084 opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000017085 switch (opc2) {
17086
17087 /* Merge */
17088 case 0x00C: // vmrghb (Merge High B, AV p195)
17089 DIP("vmrghb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion92d9d872005-09-15 21:58:50 +000017090 putVReg( vD_addr,
17091 binop(Iop_InterleaveHI8x16, mkexpr(vA), mkexpr(vB)) );
17092 break;
cerion32aad402005-09-10 12:02:24 +000017093
17094 case 0x04C: // vmrghh (Merge High HW, AV p196)
17095 DIP("vmrghh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion92d9d872005-09-15 21:58:50 +000017096 putVReg( vD_addr,
17097 binop(Iop_InterleaveHI16x8, mkexpr(vA), mkexpr(vB)) );
17098 break;
cerion32aad402005-09-10 12:02:24 +000017099
17100 case 0x08C: // vmrghw (Merge High W, AV p197)
17101 DIP("vmrghw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion92d9d872005-09-15 21:58:50 +000017102 putVReg( vD_addr,
17103 binop(Iop_InterleaveHI32x4, mkexpr(vA), mkexpr(vB)) );
17104 break;
cerion32aad402005-09-10 12:02:24 +000017105
17106 case 0x10C: // vmrglb (Merge Low B, AV p198)
17107 DIP("vmrglb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion92d9d872005-09-15 21:58:50 +000017108 putVReg( vD_addr,
17109 binop(Iop_InterleaveLO8x16, mkexpr(vA), mkexpr(vB)) );
17110 break;
cerion32aad402005-09-10 12:02:24 +000017111
17112 case 0x14C: // vmrglh (Merge Low HW, AV p199)
17113 DIP("vmrglh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion92d9d872005-09-15 21:58:50 +000017114 putVReg( vD_addr,
17115 binop(Iop_InterleaveLO16x8, mkexpr(vA), mkexpr(vB)) );
17116 break;
cerion32aad402005-09-10 12:02:24 +000017117
17118 case 0x18C: // vmrglw (Merge Low W, AV p200)
17119 DIP("vmrglw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion92d9d872005-09-15 21:58:50 +000017120 putVReg( vD_addr,
17121 binop(Iop_InterleaveLO32x4, mkexpr(vA), mkexpr(vB)) );
17122 break;
17123
cerion32aad402005-09-10 12:02:24 +000017124
17125 /* Splat */
cerion92d9d872005-09-15 21:58:50 +000017126 case 0x20C: { // vspltb (Splat Byte, AV p245)
cerion92d9d872005-09-15 21:58:50 +000017127 /* vD = Dup8x16( vB[UIMM_5] ) */
sewardjd1470942005-10-22 02:01:16 +000017128 UChar sh_uimm = (15 - (UIMM_5 & 15)) * 8;
sewardj197bd172005-10-12 11:34:33 +000017129 DIP("vspltb v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
cerion92d9d872005-09-15 21:58:50 +000017130 putVReg( vD_addr, unop(Iop_Dup8x16,
17131 unop(Iop_32to8, unop(Iop_V128to32,
17132 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm))))) );
17133 break;
17134 }
17135 case 0x24C: { // vsplth (Splat Half Word, AV p246)
sewardjd1470942005-10-22 02:01:16 +000017136 UChar sh_uimm = (7 - (UIMM_5 & 7)) * 16;
sewardj197bd172005-10-12 11:34:33 +000017137 DIP("vsplth v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
cerion92d9d872005-09-15 21:58:50 +000017138 putVReg( vD_addr, unop(Iop_Dup16x8,
17139 unop(Iop_32to16, unop(Iop_V128to32,
17140 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm))))) );
17141 break;
17142 }
cerion27b3d7e2005-09-14 20:35:47 +000017143 case 0x28C: { // vspltw (Splat Word, AV p250)
cerion27b3d7e2005-09-14 20:35:47 +000017144 /* vD = Dup32x4( vB[UIMM_5] ) */
sewardjd1470942005-10-22 02:01:16 +000017145 UChar sh_uimm = (3 - (UIMM_5 & 3)) * 32;
sewardj197bd172005-10-12 11:34:33 +000017146 DIP("vspltw v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
cerion27b3d7e2005-09-14 20:35:47 +000017147 putVReg( vD_addr, unop(Iop_Dup32x4,
17148 unop(Iop_V128to32,
17149 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm)))) );
17150 break;
17151 }
cerion32aad402005-09-10 12:02:24 +000017152 case 0x30C: // vspltisb (Splat Immediate Signed B, AV p247)
17153 DIP("vspltisb v%d,%d\n", vD_addr, (Char)SIMM_8);
cerion92d9d872005-09-15 21:58:50 +000017154 putVReg( vD_addr, unop(Iop_Dup8x16, mkU8(SIMM_8)) );
17155 break;
cerion32aad402005-09-10 12:02:24 +000017156
17157 case 0x34C: // vspltish (Splat Immediate Signed HW, AV p248)
17158 DIP("vspltish v%d,%d\n", vD_addr, (Char)SIMM_8);
cerion5b2325f2005-12-23 00:55:09 +000017159 putVReg( vD_addr,
17160 unop(Iop_Dup16x8, mkU16(extend_s_8to32(SIMM_8))) );
cerion92d9d872005-09-15 21:58:50 +000017161 break;
cerion32aad402005-09-10 12:02:24 +000017162
17163 case 0x38C: // vspltisw (Splat Immediate Signed W, AV p249)
17164 DIP("vspltisw v%d,%d\n", vD_addr, (Char)SIMM_8);
cerion5b2325f2005-12-23 00:55:09 +000017165 putVReg( vD_addr,
17166 unop(Iop_Dup32x4, mkU32(extend_s_8to32(SIMM_8))) );
cerion92d9d872005-09-15 21:58:50 +000017167 break;
cerion32aad402005-09-10 12:02:24 +000017168
carll48ae46b2013-10-01 15:45:54 +000017169 case 0x68C: // vmrgow (Merge Odd Word)
17170 DIP("vmrgow v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17171 /* VD[0] <- VA[1]
17172 VD[1] <- VB[1]
17173 VD[2] <- VA[3]
17174 VD[3] <- VB[3]
17175 */
17176 putVReg( vD_addr,
17177 binop(Iop_CatOddLanes32x4, mkexpr(vA), mkexpr(vB) ) );
17178 break;
17179
17180 case 0x78C: // vmrgew (Merge Even Word)
17181 DIP("vmrgew v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17182 /* VD[0] <- VA[0]
17183 VD[1] <- VB[0]
17184 VD[2] <- VA[2]
17185 VD[3] <- VB[2]
17186 */
17187 putVReg( vD_addr,
17188 binop(Iop_CatEvenLanes32x4, mkexpr(vA), mkexpr(vB) ) );
17189 break;
17190
cerion32aad402005-09-10 12:02:24 +000017191 default:
cerion5b2325f2005-12-23 00:55:09 +000017192 vex_printf("dis_av_permute(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000017193 return False;
17194 }
17195 return True;
17196}
17197
17198/*
17199 AltiVec Pack/Unpack Instructions
17200*/
17201static Bool dis_av_pack ( UInt theInstr )
17202{
cerion76de5cf2005-11-18 18:25:12 +000017203 /* VX-Form */
17204 UChar opc1 = ifieldOPC(theInstr);
17205 UChar vD_addr = ifieldRegDS(theInstr);
17206 UChar vA_addr = ifieldRegA(theInstr);
17207 UChar vB_addr = ifieldRegB(theInstr);
17208 UInt opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000017209
sewardj197bd172005-10-12 11:34:33 +000017210 IRTemp signs = IRTemp_INVALID;
17211 IRTemp zeros = IRTemp_INVALID;
cerion76de5cf2005-11-18 18:25:12 +000017212 IRTemp vA = newTemp(Ity_V128);
17213 IRTemp vB = newTemp(Ity_V128);
cerion3c052792005-09-16 07:13:44 +000017214 assign( vA, getVReg(vA_addr));
17215 assign( vB, getVReg(vB_addr));
17216
cerion32aad402005-09-10 12:02:24 +000017217 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000017218 vex_printf("dis_av_pack(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000017219 return False;
17220 }
cerion32aad402005-09-10 12:02:24 +000017221 switch (opc2) {
17222 /* Packing */
17223 case 0x00E: // vpkuhum (Pack Unsigned HW Unsigned Modulo, AV p224)
17224 DIP("vpkuhum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj5f438dd2011-06-16 11:36:23 +000017225 putVReg( vD_addr,
17226 binop(Iop_NarrowBin16to8x16, mkexpr(vA), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017227 return True;
cerion32aad402005-09-10 12:02:24 +000017228
17229 case 0x04E: // vpkuwum (Pack Unsigned W Unsigned Modulo, AV p226)
17230 DIP("vpkuwum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj5f438dd2011-06-16 11:36:23 +000017231 putVReg( vD_addr,
17232 binop(Iop_NarrowBin32to16x8, mkexpr(vA), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017233 return True;
cerion32aad402005-09-10 12:02:24 +000017234
17235 case 0x08E: // vpkuhus (Pack Unsigned HW Unsigned Saturate, AV p225)
17236 DIP("vpkuhus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000017237 putVReg( vD_addr,
sewardj5f438dd2011-06-16 11:36:23 +000017238 binop(Iop_QNarrowBin16Uto8Ux16, mkexpr(vA), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017239 // TODO: set VSCR[SAT]
17240 return True;
cerion32aad402005-09-10 12:02:24 +000017241
17242 case 0x0CE: // vpkuwus (Pack Unsigned W Unsigned Saturate, AV p227)
17243 DIP("vpkuwus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000017244 putVReg( vD_addr,
sewardj5f438dd2011-06-16 11:36:23 +000017245 binop(Iop_QNarrowBin32Uto16Ux8, mkexpr(vA), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017246 // TODO: set VSCR[SAT]
17247 return True;
cerion32aad402005-09-10 12:02:24 +000017248
cerion3c052792005-09-16 07:13:44 +000017249 case 0x10E: { // vpkshus (Pack Signed HW Unsigned Saturate, AV p221)
cerion3c052792005-09-16 07:13:44 +000017250 // This insn does a signed->unsigned saturating conversion.
17251 // Conversion done here, then uses unsigned->unsigned vpk insn:
17252 // => UnsignedSaturatingNarrow( x & ~ (x >>s 15) )
17253 IRTemp vA_tmp = newTemp(Ity_V128);
17254 IRTemp vB_tmp = newTemp(Ity_V128);
sewardj197bd172005-10-12 11:34:33 +000017255 DIP("vpkshus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017256 assign( vA_tmp, binop(Iop_AndV128, mkexpr(vA),
17257 unop(Iop_NotV128,
17258 binop(Iop_SarN16x8,
17259 mkexpr(vA), mkU8(15)))) );
17260 assign( vB_tmp, binop(Iop_AndV128, mkexpr(vB),
17261 unop(Iop_NotV128,
17262 binop(Iop_SarN16x8,
17263 mkexpr(vB), mkU8(15)))) );
sewardj5f438dd2011-06-16 11:36:23 +000017264 putVReg( vD_addr, binop(Iop_QNarrowBin16Uto8Ux16,
cerion3c052792005-09-16 07:13:44 +000017265 mkexpr(vA_tmp), mkexpr(vB_tmp)) );
17266 // TODO: set VSCR[SAT]
17267 return True;
17268 }
17269 case 0x14E: { // vpkswus (Pack Signed W Unsigned Saturate, AV p223)
cerion3c052792005-09-16 07:13:44 +000017270 // This insn does a signed->unsigned saturating conversion.
17271 // Conversion done here, then uses unsigned->unsigned vpk insn:
17272 // => UnsignedSaturatingNarrow( x & ~ (x >>s 31) )
17273 IRTemp vA_tmp = newTemp(Ity_V128);
17274 IRTemp vB_tmp = newTemp(Ity_V128);
sewardj197bd172005-10-12 11:34:33 +000017275 DIP("vpkswus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017276 assign( vA_tmp, binop(Iop_AndV128, mkexpr(vA),
17277 unop(Iop_NotV128,
17278 binop(Iop_SarN32x4,
17279 mkexpr(vA), mkU8(31)))) );
17280 assign( vB_tmp, binop(Iop_AndV128, mkexpr(vB),
17281 unop(Iop_NotV128,
17282 binop(Iop_SarN32x4,
17283 mkexpr(vB), mkU8(31)))) );
sewardj5f438dd2011-06-16 11:36:23 +000017284 putVReg( vD_addr, binop(Iop_QNarrowBin32Uto16Ux8,
cerion3c052792005-09-16 07:13:44 +000017285 mkexpr(vA_tmp), mkexpr(vB_tmp)) );
17286 // TODO: set VSCR[SAT]
17287 return True;
17288 }
cerion32aad402005-09-10 12:02:24 +000017289 case 0x18E: // vpkshss (Pack Signed HW Signed Saturate, AV p220)
17290 DIP("vpkshss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000017291 putVReg( vD_addr,
sewardj5f438dd2011-06-16 11:36:23 +000017292 binop(Iop_QNarrowBin16Sto8Sx16, mkexpr(vA), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017293 // TODO: set VSCR[SAT]
17294 return True;
cerion32aad402005-09-10 12:02:24 +000017295
17296 case 0x1CE: // vpkswss (Pack Signed W Signed Saturate, AV p222)
17297 DIP("vpkswss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000017298 putVReg( vD_addr,
sewardj5f438dd2011-06-16 11:36:23 +000017299 binop(Iop_QNarrowBin32Sto16Sx8, mkexpr(vA), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017300 // TODO: set VSCR[SAT]
17301 return True;
cerion32aad402005-09-10 12:02:24 +000017302
cerion3c052792005-09-16 07:13:44 +000017303 case 0x30E: { // vpkpx (Pack Pixel, AV p219)
cerion3c052792005-09-16 07:13:44 +000017304 /* CAB: Worth a new primop? */
cerion5b2325f2005-12-23 00:55:09 +000017305 /* Using shifts to compact pixel elements, then packing them */
cerion3c052792005-09-16 07:13:44 +000017306 IRTemp a1 = newTemp(Ity_V128);
17307 IRTemp a2 = newTemp(Ity_V128);
17308 IRTemp a3 = newTemp(Ity_V128);
17309 IRTemp a_tmp = newTemp(Ity_V128);
17310 IRTemp b1 = newTemp(Ity_V128);
17311 IRTemp b2 = newTemp(Ity_V128);
17312 IRTemp b3 = newTemp(Ity_V128);
17313 IRTemp b_tmp = newTemp(Ity_V128);
sewardj197bd172005-10-12 11:34:33 +000017314 DIP("vpkpx v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017315 assign( a1, binop(Iop_ShlN16x8,
17316 binop(Iop_ShrN32x4, mkexpr(vA), mkU8(19)),
17317 mkU8(10)) );
17318 assign( a2, binop(Iop_ShlN16x8,
17319 binop(Iop_ShrN16x8, mkexpr(vA), mkU8(11)),
17320 mkU8(5)) );
17321 assign( a3, binop(Iop_ShrN16x8,
17322 binop(Iop_ShlN16x8, mkexpr(vA), mkU8(8)),
17323 mkU8(11)) );
17324 assign( a_tmp, binop(Iop_OrV128, mkexpr(a1),
17325 binop(Iop_OrV128, mkexpr(a2), mkexpr(a3))) );
17326
17327 assign( b1, binop(Iop_ShlN16x8,
17328 binop(Iop_ShrN32x4, mkexpr(vB), mkU8(19)),
17329 mkU8(10)) );
17330 assign( b2, binop(Iop_ShlN16x8,
17331 binop(Iop_ShrN16x8, mkexpr(vB), mkU8(11)),
17332 mkU8(5)) );
17333 assign( b3, binop(Iop_ShrN16x8,
17334 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(8)),
17335 mkU8(11)) );
17336 assign( b_tmp, binop(Iop_OrV128, mkexpr(b1),
17337 binop(Iop_OrV128, mkexpr(b2), mkexpr(b3))) );
17338
sewardj5f438dd2011-06-16 11:36:23 +000017339 putVReg( vD_addr, binop(Iop_NarrowBin32to16x8,
cerion3c052792005-09-16 07:13:44 +000017340 mkexpr(a_tmp), mkexpr(b_tmp)) );
17341 return True;
17342 }
cerion32aad402005-09-10 12:02:24 +000017343
carll0c74bb52013-08-12 18:01:40 +000017344 case 0x44E: // vpkudum (Pack Unsigned Double Word Unsigned Modulo)
17345 DIP("vpkudum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17346 putVReg( vD_addr,
17347 binop(Iop_NarrowBin64to32x4, mkexpr(vA), mkexpr(vB)) );
17348 return True;
17349
carll48ae46b2013-10-01 15:45:54 +000017350 case 0x4CE: // vpkudus (Pack Unsigned Double Word Unsigned Saturate)
17351 DIP("vpkudus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17352 putVReg( vD_addr,
17353 binop(Iop_QNarrowBin64Uto32Ux4, mkexpr(vA), mkexpr(vB)) );
17354 // TODO: set VSCR[SAT]
17355 return True;
17356
17357 case 0x54E: { // vpksdus (Pack Signed Double Word Unsigned Saturate)
17358 // This insn does a doubled signed->double unsigned saturating conversion
17359 // Conversion done here, then uses unsigned->unsigned vpk insn:
17360 // => UnsignedSaturatingNarrow( x & ~ (x >>s 31) )
17361 // This is similar to the technique used for vpkswus, except done
17362 // with double word integers versus word integers.
17363 IRTemp vA_tmp = newTemp(Ity_V128);
17364 IRTemp vB_tmp = newTemp(Ity_V128);
17365 DIP("vpksdus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17366 assign( vA_tmp, binop(Iop_AndV128, mkexpr(vA),
17367 unop(Iop_NotV128,
17368 binop(Iop_SarN64x2,
17369 mkexpr(vA), mkU8(63)))) );
17370 assign( vB_tmp, binop(Iop_AndV128, mkexpr(vB),
17371 unop(Iop_NotV128,
17372 binop(Iop_SarN64x2,
17373 mkexpr(vB), mkU8(63)))) );
17374 putVReg( vD_addr, binop(Iop_QNarrowBin64Uto32Ux4,
17375 mkexpr(vA_tmp), mkexpr(vB_tmp)) );
17376 // TODO: set VSCR[SAT]
17377 return True;
17378 }
17379
17380 case 0x5CE: // vpksdss (Pack Signed double word Signed Saturate)
17381 DIP("vpksdss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17382 putVReg( vD_addr,
17383 binop(Iop_QNarrowBin64Sto32Sx4, mkexpr(vA), mkexpr(vB)) );
17384 // TODO: set VSCR[SAT]
17385 return True;
cerion32aad402005-09-10 12:02:24 +000017386 default:
17387 break; // Fall through...
17388 }
17389
17390
17391 if (vA_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +000017392 vex_printf("dis_av_pack(ppc)(vA_addr)\n");
cerion32aad402005-09-10 12:02:24 +000017393 return False;
17394 }
17395
sewardj197bd172005-10-12 11:34:33 +000017396 signs = newTemp(Ity_V128);
17397 zeros = newTemp(Ity_V128);
cerion3c052792005-09-16 07:13:44 +000017398 assign( zeros, unop(Iop_Dup32x4, mkU32(0)) );
17399
cerion32aad402005-09-10 12:02:24 +000017400 switch (opc2) {
17401 /* Unpacking */
cerion3c052792005-09-16 07:13:44 +000017402 case 0x20E: { // vupkhsb (Unpack High Signed B, AV p277)
cerion32aad402005-09-10 12:02:24 +000017403 DIP("vupkhsb v%d,v%d\n", vD_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017404 assign( signs, binop(Iop_CmpGT8Sx16, mkexpr(zeros), mkexpr(vB)) );
cerion5b2325f2005-12-23 00:55:09 +000017405 putVReg( vD_addr,
17406 binop(Iop_InterleaveHI8x16, mkexpr(signs), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017407 break;
17408 }
17409 case 0x24E: { // vupkhsh (Unpack High Signed HW, AV p278)
cerion32aad402005-09-10 12:02:24 +000017410 DIP("vupkhsh v%d,v%d\n", vD_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017411 assign( signs, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vB)) );
cerion5b2325f2005-12-23 00:55:09 +000017412 putVReg( vD_addr,
17413 binop(Iop_InterleaveHI16x8, mkexpr(signs), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017414 break;
17415 }
17416 case 0x28E: { // vupklsb (Unpack Low Signed B, AV p280)
cerion32aad402005-09-10 12:02:24 +000017417 DIP("vupklsb v%d,v%d\n", vD_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017418 assign( signs, binop(Iop_CmpGT8Sx16, mkexpr(zeros), mkexpr(vB)) );
cerion5b2325f2005-12-23 00:55:09 +000017419 putVReg( vD_addr,
17420 binop(Iop_InterleaveLO8x16, mkexpr(signs), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017421 break;
17422 }
17423 case 0x2CE: { // vupklsh (Unpack Low Signed HW, AV p281)
cerion32aad402005-09-10 12:02:24 +000017424 DIP("vupklsh v%d,v%d\n", vD_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017425 assign( signs, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vB)) );
cerion5b2325f2005-12-23 00:55:09 +000017426 putVReg( vD_addr,
17427 binop(Iop_InterleaveLO16x8, mkexpr(signs), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017428 break;
17429 }
17430 case 0x34E: { // vupkhpx (Unpack High Pixel16, AV p276)
cerion3c052792005-09-16 07:13:44 +000017431 /* CAB: Worth a new primop? */
17432 /* Using shifts to isolate pixel elements, then expanding them */
17433 IRTemp z0 = newTemp(Ity_V128);
17434 IRTemp z1 = newTemp(Ity_V128);
17435 IRTemp z01 = newTemp(Ity_V128);
17436 IRTemp z2 = newTemp(Ity_V128);
17437 IRTemp z3 = newTemp(Ity_V128);
17438 IRTemp z23 = newTemp(Ity_V128);
sewardj197bd172005-10-12 11:34:33 +000017439 DIP("vupkhpx v%d,v%d\n", vD_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017440 assign( z0, binop(Iop_ShlN16x8,
17441 binop(Iop_SarN16x8, mkexpr(vB), mkU8(15)),
17442 mkU8(8)) );
17443 assign( z1, binop(Iop_ShrN16x8,
17444 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(1)),
17445 mkU8(11)) );
17446 assign( z01, binop(Iop_InterleaveHI16x8, mkexpr(zeros),
17447 binop(Iop_OrV128, mkexpr(z0), mkexpr(z1))) );
17448 assign( z2, binop(Iop_ShrN16x8,
17449 binop(Iop_ShlN16x8,
17450 binop(Iop_ShrN16x8, mkexpr(vB), mkU8(5)),
17451 mkU8(11)),
17452 mkU8(3)) );
17453 assign( z3, binop(Iop_ShrN16x8,
17454 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(11)),
17455 mkU8(11)) );
17456 assign( z23, binop(Iop_InterleaveHI16x8, mkexpr(zeros),
17457 binop(Iop_OrV128, mkexpr(z2), mkexpr(z3))) );
cerion5b2325f2005-12-23 00:55:09 +000017458 putVReg( vD_addr,
17459 binop(Iop_OrV128,
17460 binop(Iop_ShlN32x4, mkexpr(z01), mkU8(16)),
17461 mkexpr(z23)) );
cerion3c052792005-09-16 07:13:44 +000017462 break;
17463 }
17464 case 0x3CE: { // vupklpx (Unpack Low Pixel16, AV p279)
cerion3c052792005-09-16 07:13:44 +000017465 /* identical to vupkhpx, except interleaving LO */
17466 IRTemp z0 = newTemp(Ity_V128);
17467 IRTemp z1 = newTemp(Ity_V128);
17468 IRTemp z01 = newTemp(Ity_V128);
17469 IRTemp z2 = newTemp(Ity_V128);
17470 IRTemp z3 = newTemp(Ity_V128);
17471 IRTemp z23 = newTemp(Ity_V128);
sewardj197bd172005-10-12 11:34:33 +000017472 DIP("vupklpx v%d,v%d\n", vD_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017473 assign( z0, binop(Iop_ShlN16x8,
17474 binop(Iop_SarN16x8, mkexpr(vB), mkU8(15)),
17475 mkU8(8)) );
17476 assign( z1, binop(Iop_ShrN16x8,
17477 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(1)),
17478 mkU8(11)) );
17479 assign( z01, binop(Iop_InterleaveLO16x8, mkexpr(zeros),
17480 binop(Iop_OrV128, mkexpr(z0), mkexpr(z1))) );
17481 assign( z2, binop(Iop_ShrN16x8,
17482 binop(Iop_ShlN16x8,
17483 binop(Iop_ShrN16x8, mkexpr(vB), mkU8(5)),
17484 mkU8(11)),
17485 mkU8(3)) );
17486 assign( z3, binop(Iop_ShrN16x8,
17487 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(11)),
17488 mkU8(11)) );
17489 assign( z23, binop(Iop_InterleaveLO16x8, mkexpr(zeros),
17490 binop(Iop_OrV128, mkexpr(z2), mkexpr(z3))) );
cerion5b2325f2005-12-23 00:55:09 +000017491 putVReg( vD_addr,
17492 binop(Iop_OrV128,
17493 binop(Iop_ShlN32x4, mkexpr(z01), mkU8(16)),
17494 mkexpr(z23)) );
cerion3c052792005-09-16 07:13:44 +000017495 break;
17496 }
carll48ae46b2013-10-01 15:45:54 +000017497 case 0x64E: { // vupkhsw (Unpack High Signed Word)
17498 DIP("vupkhsw v%d,v%d\n", vD_addr, vB_addr);
17499 assign( signs, binop(Iop_CmpGT32Sx4, mkexpr(zeros), mkexpr(vB)) );
17500 putVReg( vD_addr,
17501 binop(Iop_InterleaveHI32x4, mkexpr(signs), mkexpr(vB)) );
17502 break;
17503 }
17504 case 0x6CE: { // vupklsw (Unpack Low Signed Word)
17505 DIP("vupklsw v%d,v%d\n", vD_addr, vB_addr);
17506 assign( signs, binop(Iop_CmpGT32Sx4, mkexpr(zeros), mkexpr(vB)) );
17507 putVReg( vD_addr,
17508 binop(Iop_InterleaveLO32x4, mkexpr(signs), mkexpr(vB)) );
17509 break;
17510 }
cerion32aad402005-09-10 12:02:24 +000017511 default:
cerion5b2325f2005-12-23 00:55:09 +000017512 vex_printf("dis_av_pack(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000017513 return False;
17514 }
17515 return True;
17516}
17517
carll7deaf952013-10-15 18:11:20 +000017518/*
17519 AltiVec Cipher Instructions
17520*/
17521static Bool dis_av_cipher ( UInt theInstr )
17522{
17523 /* VX-Form */
17524 UChar opc1 = ifieldOPC(theInstr);
17525 UChar vD_addr = ifieldRegDS(theInstr);
17526 UChar vA_addr = ifieldRegA(theInstr);
17527 UChar vB_addr = ifieldRegB(theInstr);
17528 UInt opc2 = IFIELD( theInstr, 0, 11 );
17529
17530 IRTemp vA = newTemp(Ity_V128);
17531 IRTemp vB = newTemp(Ity_V128);
17532 assign( vA, getVReg(vA_addr));
17533 assign( vB, getVReg(vB_addr));
17534
17535 if (opc1 != 0x4) {
17536 vex_printf("dis_av_cipher(ppc)(instr)\n");
17537 return False;
17538 }
17539 switch (opc2) {
17540 case 0x508: // vcipher (Vector Inverser Cipher)
17541 DIP("vcipher v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17542 putVReg( vD_addr,
17543 binop(Iop_CipherV128, mkexpr(vA), mkexpr(vB)) );
17544 return True;
17545
17546 case 0x509: // vcipherlast (Vector Inverser Cipher Last)
17547 DIP("vcipherlast v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17548 putVReg( vD_addr,
17549 binop(Iop_CipherLV128, mkexpr(vA), mkexpr(vB)) );
17550 return True;
17551
17552 case 0x548: // vncipher (Vector Inverser Cipher)
17553 DIP("vncipher v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17554 putVReg( vD_addr,
17555 binop(Iop_NCipherV128, mkexpr(vA), mkexpr(vB)) );
17556 return True;
17557
17558 case 0x549: // vncipherlast (Vector Inverser Cipher Last)
17559 DIP("vncipherlast v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17560 putVReg( vD_addr,
17561 binop(Iop_NCipherLV128, mkexpr(vA), mkexpr(vB)) );
17562 return True;
17563
17564 case 0x5C8: /* vsbox (Vector SubBytes, this does the cipher
17565 * subBytes transform)
17566 */
17567 DIP("vsbox v%d,v%d\n", vD_addr, vA_addr);
17568 putVReg( vD_addr,
17569 unop(Iop_CipherSV128, mkexpr(vA) ) );
17570 return True;
17571
17572 default:
17573 vex_printf("dis_av_cipher(ppc)(opc2)\n");
17574 return False;
17575 }
17576 return True;
17577}
17578
17579/*
17580 AltiVec Secure Hash Instructions
17581*/
17582static Bool dis_av_hash ( UInt theInstr )
17583{
17584 /* VX-Form */
17585 UChar opc1 = ifieldOPC(theInstr);
17586 UChar vRT_addr = ifieldRegDS(theInstr);
17587 UChar vRA_addr = ifieldRegA(theInstr);
17588 UChar s_field = IFIELD( theInstr, 11, 5 ); // st and six field
17589 UChar st = IFIELD( theInstr, 15, 1 ); // st
17590 UChar six = IFIELD( theInstr, 11, 4 ); // six field
17591 UInt opc2 = IFIELD( theInstr, 0, 11 );
17592
17593 IRTemp vA = newTemp(Ity_V128);
17594 IRTemp dst = newTemp(Ity_V128);
17595 assign( vA, getVReg(vRA_addr));
17596
17597 if (opc1 != 0x4) {
17598 vex_printf("dis_av_hash(ppc)(instr)\n");
17599 return False;
17600 }
17601
17602 switch (opc2) {
17603 case 0x682: // vshasigmaw
17604 DIP("vshasigmaw v%d,v%d,%u,%u\n", vRT_addr, vRA_addr, st, six);
17605 assign( dst, binop( Iop_SHA256, mkexpr( vA ), mkU8( s_field) ) );
17606 putVReg( vRT_addr, mkexpr(dst));
17607 return True;
17608
17609 case 0x6C2: // vshasigmad,
17610 DIP("vshasigmad v%d,v%d,%u,%u\n", vRT_addr, vRA_addr, st, six);
17611 putVReg( vRT_addr, binop( Iop_SHA512, mkexpr( vA ), mkU8( s_field) ) );
17612 return True;
17613
17614 default:
17615 vex_printf("dis_av_hash(ppc)(opc2)\n");
17616 return False;
17617 }
17618 return True;
17619}
17620
17621/*
carll60c6bac2013-10-18 01:19:06 +000017622 * This function is used by the Vector add/subtract [extended] modulo/carry
17623 * instructions.
17624 * - For the non-extended add instructions, the cin arg is set to zero.
17625 * - For the extended add instructions, cin is the integer value of
17626 * src3.bit[127].
17627 * - For the non-extended subtract instructions, src1 is added to the one's
17628 * complement of src2 + 1. We re-use the cin argument to hold the '1'
17629 * value for this operation.
17630 * - For the extended subtract instructions, cin is the integer value of src3.bit[127].
17631 */
17632static IRTemp _get_quad_modulo_or_carry(IRExpr * vecA, IRExpr * vecB,
17633 IRExpr * cin, Bool modulo)
17634{
17635 IRTemp _vecA_32 = IRTemp_INVALID;
17636 IRTemp _vecB_32 = IRTemp_INVALID;
17637 IRTemp res_32 = IRTemp_INVALID;
17638 IRTemp result = IRTemp_INVALID;
17639 IRTemp tmp_result = IRTemp_INVALID;
17640 IRTemp carry = IRTemp_INVALID;
17641 Int i;
17642 IRExpr * _vecA_low64 = unop( Iop_V128to64, vecA );
17643 IRExpr * _vecB_low64 = unop( Iop_V128to64, vecB );
17644 IRExpr * _vecA_high64 = unop( Iop_V128HIto64, vecA );
17645 IRExpr * _vecB_high64 = unop( Iop_V128HIto64, vecB );
17646
17647 for (i = 0; i < 4; i++) {
17648 _vecA_32 = newTemp(Ity_I32);
17649 _vecB_32 = newTemp(Ity_I32);
17650 res_32 = newTemp(Ity_I32);
17651 switch (i) {
17652 case 0:
17653 assign(_vecA_32, unop( Iop_64to32, _vecA_low64 ) );
17654 assign(_vecB_32, unop( Iop_64to32, _vecB_low64 ) );
17655 break;
17656 case 1:
17657 assign(_vecA_32, unop( Iop_64HIto32, _vecA_low64 ) );
17658 assign(_vecB_32, unop( Iop_64HIto32, _vecB_low64 ) );
17659 break;
17660 case 2:
17661 assign(_vecA_32, unop( Iop_64to32, _vecA_high64 ) );
17662 assign(_vecB_32, unop( Iop_64to32, _vecB_high64 ) );
17663 break;
17664 case 3:
17665 assign(_vecA_32, unop( Iop_64HIto32, _vecA_high64 ) );
17666 assign(_vecB_32, unop( Iop_64HIto32, _vecB_high64 ) );
17667 break;
17668 }
17669
17670 assign(res_32, binop( Iop_Add32,
17671 binop( Iop_Add32,
17672 binop ( Iop_Add32,
17673 mkexpr(_vecA_32),
17674 mkexpr(_vecB_32) ),
17675 (i == 0) ? mkU32(0) : mkexpr(carry) ),
17676 (i == 0) ? cin : mkU32(0) ) );
17677 if (modulo) {
17678 result = newTemp(Ity_V128);
17679 assign(result, binop( Iop_OrV128,
17680 (i == 0) ? binop( Iop_64HLtoV128,
17681 mkU64(0),
17682 mkU64(0) ) : mkexpr(tmp_result),
17683 binop( Iop_ShlV128,
17684 binop( Iop_64HLtoV128,
17685 mkU64(0),
17686 binop( Iop_32HLto64,
17687 mkU32(0),
17688 mkexpr(res_32) ) ),
17689 mkU8(i * 32) ) ) );
17690 tmp_result = newTemp(Ity_V128);
17691 assign(tmp_result, mkexpr(result));
17692 }
17693 carry = newTemp(Ity_I32);
17694 assign(carry, unop(Iop_1Uto32, binop( Iop_CmpLT32U,
17695 mkexpr(res_32),
17696 mkexpr(_vecA_32 ) ) ) );
17697 }
17698 if (modulo)
17699 return result;
17700 else
17701 return carry;
17702}
17703
17704
17705static Bool dis_av_quad ( UInt theInstr )
17706{
17707 /* VX-Form */
17708 UChar opc1 = ifieldOPC(theInstr);
17709 UChar vRT_addr = ifieldRegDS(theInstr);
17710 UChar vRA_addr = ifieldRegA(theInstr);
17711 UChar vRB_addr = ifieldRegB(theInstr);
17712 UChar vRC_addr;
17713 UInt opc2 = IFIELD( theInstr, 0, 11 );
17714
17715 IRTemp vA = newTemp(Ity_V128);
17716 IRTemp vB = newTemp(Ity_V128);
17717 IRTemp vC = IRTemp_INVALID;
17718 IRTemp cin = IRTemp_INVALID;
17719 assign( vA, getVReg(vRA_addr));
17720 assign( vB, getVReg(vRB_addr));
17721
17722 if (opc1 != 0x4) {
17723 vex_printf("dis_av_quad(ppc)(instr)\n");
17724 return False;
17725 }
17726
17727 switch (opc2) {
17728 case 0x140: // vaddcuq
17729 DIP("vaddcuq v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
17730 putVReg( vRT_addr, unop( Iop_32UtoV128,
17731 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
17732 mkexpr(vB),
17733 mkU32(0), False) ) ) );
17734 return True;
17735 case 0x100: // vadduqm
17736 DIP("vadduqm v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
17737 putVReg( vRT_addr, mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
17738 mkexpr(vB), mkU32(0), True) ) );
17739 return True;
17740 case 0x540: // vsubcuq
17741 DIP("vsubcuq v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
17742 putVReg( vRT_addr,
17743 unop( Iop_32UtoV128,
17744 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
17745 unop( Iop_NotV128,
17746 mkexpr(vB) ),
17747 mkU32(1), False) ) ) );
17748 return True;
17749 case 0x500: // vsubuqm
17750 DIP("vsubuqm v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
17751 putVReg( vRT_addr,
17752 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
17753 unop( Iop_NotV128, mkexpr(vB) ),
17754 mkU32(1), True) ) );
17755 return True;
17756 case 0x054C: // vbpermq
17757 {
17758#define BPERMD_IDX_MASK 0x00000000000000FFULL
17759#define BPERMD_BIT_MASK 0x8000000000000000ULL
17760 int i;
17761 IRExpr * vB_expr = mkexpr(vB);
17762 IRExpr * res = binop(Iop_AndV128, mkV128(0), mkV128(0));
17763 DIP("vbpermq v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
17764 for (i = 0; i < 16; i++) {
17765 IRTemp idx_tmp = newTemp( Ity_V128 );
17766 IRTemp perm_bit = newTemp( Ity_V128 );
17767 IRTemp idx = newTemp( Ity_I8 );
17768 IRTemp idx_LT127 = newTemp( Ity_I1 );
17769 IRTemp idx_LT127_ity128 = newTemp( Ity_V128 );
17770
17771 assign( idx_tmp,
17772 binop( Iop_AndV128,
17773 binop( Iop_64HLtoV128,
17774 mkU64(0),
17775 mkU64(BPERMD_IDX_MASK) ),
17776 vB_expr ) );
17777 assign( idx_LT127,
17778 binop( Iop_CmpEQ32,
17779 unop ( Iop_64to32,
17780 unop( Iop_V128to64, binop( Iop_ShrV128,
17781 mkexpr(idx_tmp),
17782 mkU8(7) ) ) ),
17783 mkU32(0) ) );
17784
17785 /* Below, we set idx to determine which bit of vA to use for the
17786 * perm bit. If idx_LT127 is 0, the perm bit is forced to '0'.
17787 */
17788 assign( idx,
17789 binop( Iop_And8,
17790 unop( Iop_1Sto8,
17791 mkexpr(idx_LT127) ),
17792 unop( Iop_32to8,
17793 unop( Iop_V128to32, mkexpr( idx_tmp ) ) ) ) );
17794
17795 assign( idx_LT127_ity128,
17796 binop( Iop_64HLtoV128,
17797 mkU64(0),
17798 unop( Iop_32Uto64,
17799 unop( Iop_1Uto32, mkexpr(idx_LT127 ) ) ) ) );
17800 assign( perm_bit,
17801 binop( Iop_AndV128,
17802 mkexpr( idx_LT127_ity128 ),
17803 binop( Iop_ShrV128,
17804 binop( Iop_AndV128,
17805 binop (Iop_64HLtoV128,
17806 mkU64( BPERMD_BIT_MASK ),
17807 mkU64(0)),
17808 binop( Iop_ShlV128,
17809 mkexpr( vA ),
17810 mkexpr( idx ) ) ),
17811 mkU8( 127 ) ) ) );
17812 res = binop( Iop_OrV128,
17813 res,
17814 binop( Iop_ShlV128,
17815 mkexpr( perm_bit ),
17816 mkU8( i ) ) );
17817 vB_expr = binop( Iop_ShrV128, vB_expr, mkU8( 8 ) );
17818 }
17819 putVReg( vRT_addr, res);
17820 return True;
17821#undef BPERMD_IDX_MASK
17822#undef BPERMD_BIT_MASK
17823 }
17824
17825 default:
17826 break; // fall through
17827 }
17828
17829 opc2 = IFIELD( theInstr, 0, 6 );
17830 vRC_addr = ifieldRegC(theInstr);
17831 vC = newTemp(Ity_V128);
17832 cin = newTemp(Ity_I32);
17833 switch (opc2) {
17834 case 0x3D: // vaddecuq
17835 assign( vC, getVReg(vRC_addr));
17836 DIP("vaddecuq v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
17837 vRC_addr);
17838 assign(cin, binop( Iop_And32,
17839 unop( Iop_64to32,
17840 unop( Iop_V128to64, mkexpr(vC) ) ),
17841 mkU32(1) ) );
17842 putVReg( vRT_addr,
17843 unop( Iop_32UtoV128,
17844 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA), mkexpr(vB),
17845 mkexpr(cin),
17846 False) ) ) );
17847 return True;
17848 case 0x3C: // vaddeuqm
17849 assign( vC, getVReg(vRC_addr));
17850 DIP("vaddeuqm v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
17851 vRC_addr);
17852 assign(cin, binop( Iop_And32,
17853 unop( Iop_64to32,
17854 unop( Iop_V128to64, mkexpr(vC) ) ),
17855 mkU32(1) ) );
17856 putVReg( vRT_addr,
17857 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA), mkexpr(vB),
17858 mkexpr(cin),
17859 True) ) );
17860 return True;
17861 case 0x3F: // vsubecuq
17862 assign( vC, getVReg(vRC_addr));
17863 DIP("vsubecuq v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
17864 vRC_addr);
17865 assign(cin, binop( Iop_And32,
17866 unop( Iop_64to32,
17867 unop( Iop_V128to64, mkexpr(vC) ) ),
17868 mkU32(1) ) );
17869 putVReg( vRT_addr,
17870 unop( Iop_32UtoV128,
17871 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
17872 unop( Iop_NotV128,
17873 mkexpr(vB) ),
17874 mkexpr(cin),
17875 False) ) ) );
17876 return True;
17877 case 0x3E: // vsubeuqm
17878 assign( vC, getVReg(vRC_addr));
17879 DIP("vsubeuqm v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
17880 vRC_addr);
17881 assign(cin, binop( Iop_And32,
17882 unop( Iop_64to32,
17883 unop( Iop_V128to64, mkexpr(vC) ) ),
17884 mkU32(1) ) );
17885 putVReg( vRT_addr,
17886 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
17887 unop( Iop_NotV128, mkexpr(vB) ),
17888 mkexpr(cin),
17889 True) ) );
17890 return True;
17891 default:
17892 vex_printf("dis_av_quad(ppc)(opc2.2)\n");
17893 return False;
17894 }
17895
17896 return True;
17897}
17898
17899
17900/*
carll7deaf952013-10-15 18:11:20 +000017901 AltiVec BCD Arithmetic instructions.
17902 These instructions modify CR6 for various conditions in the result,
17903 including when an overflow occurs. We could easily detect all conditions
17904 except when an overflow occurs. But since we can't be 100% accurate
17905 in our emulation of CR6, it seems best to just not support it all.
17906*/
17907static Bool dis_av_bcd ( UInt theInstr )
17908{
17909 /* VX-Form */
17910 UChar opc1 = ifieldOPC(theInstr);
17911 UChar vRT_addr = ifieldRegDS(theInstr);
17912 UChar vRA_addr = ifieldRegA(theInstr);
17913 UChar vRB_addr = ifieldRegB(theInstr);
17914 UChar ps = IFIELD( theInstr, 9, 1 );
17915 UInt opc2 = IFIELD( theInstr, 0, 9 );
17916
17917 IRTemp vA = newTemp(Ity_V128);
17918 IRTemp vB = newTemp(Ity_V128);
17919 IRTemp dst = newTemp(Ity_V128);
17920 assign( vA, getVReg(vRA_addr));
17921 assign( vB, getVReg(vRB_addr));
17922
17923 if (opc1 != 0x4) {
17924 vex_printf("dis_av_bcd(ppc)(instr)\n");
17925 return False;
17926 }
17927
17928 switch (opc2) {
17929 case 0x1: // bcdadd
17930 DIP("bcdadd. v%d,v%d,v%d,%u\n", vRT_addr, vRA_addr, vRB_addr, ps);
17931 assign( dst, triop( Iop_BCDAdd, mkexpr( vA ),
17932 mkexpr( vB ), mkU8( ps ) ) );
17933 putVReg( vRT_addr, mkexpr(dst));
17934 return True;
17935
17936 case 0x41: // bcdsub
17937 DIP("bcdsub. v%d,v%d,v%d,%u\n", vRT_addr, vRA_addr, vRB_addr, ps);
17938 assign( dst, triop( Iop_BCDSub, mkexpr( vA ),
17939 mkexpr( vB ), mkU8( ps ) ) );
17940 putVReg( vRT_addr, mkexpr(dst));
17941 return True;
17942
17943 default:
17944 vex_printf("dis_av_bcd(ppc)(opc2)\n");
17945 return False;
17946 }
17947 return True;
17948}
cerion32aad402005-09-10 12:02:24 +000017949
17950/*
17951 AltiVec Floating Point Arithmetic Instructions
17952*/
17953static Bool dis_av_fp_arith ( UInt theInstr )
17954{
cerion76de5cf2005-11-18 18:25:12 +000017955 /* VA-Form */
17956 UChar opc1 = ifieldOPC(theInstr);
17957 UChar vD_addr = ifieldRegDS(theInstr);
17958 UChar vA_addr = ifieldRegA(theInstr);
17959 UChar vB_addr = ifieldRegB(theInstr);
17960 UChar vC_addr = ifieldRegC(theInstr);
cerion32aad402005-09-10 12:02:24 +000017961 UInt opc2=0;
17962
cerion8ea0d3e2005-11-14 00:44:47 +000017963 IRTemp vA = newTemp(Ity_V128);
17964 IRTemp vB = newTemp(Ity_V128);
17965 IRTemp vC = newTemp(Ity_V128);
17966 assign( vA, getVReg(vA_addr));
17967 assign( vB, getVReg(vB_addr));
17968 assign( vC, getVReg(vC_addr));
17969
cerion32aad402005-09-10 12:02:24 +000017970 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000017971 vex_printf("dis_av_fp_arith(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000017972 return False;
17973 }
17974
sewardj20a760e2014-05-05 10:03:56 +000017975 IRTemp rm = newTemp(Ity_I32);
17976 assign(rm, get_IR_roundingmode());
17977
cerion76de5cf2005-11-18 18:25:12 +000017978 opc2 = IFIELD( theInstr, 0, 6 );
cerion32aad402005-09-10 12:02:24 +000017979 switch (opc2) {
17980 case 0x2E: // vmaddfp (Multiply Add FP, AV p177)
cerion5b2325f2005-12-23 00:55:09 +000017981 DIP("vmaddfp v%d,v%d,v%d,v%d\n",
17982 vD_addr, vA_addr, vC_addr, vB_addr);
17983 putVReg( vD_addr,
sewardj20a760e2014-05-05 10:03:56 +000017984 triop(Iop_Add32Fx4, mkU32(Irrm_NEAREST),
17985 mkexpr(vB),
17986 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
17987 mkexpr(vA), mkexpr(vC))) );
cerionf3f173c2005-11-14 02:37:44 +000017988 return True;
cerion32aad402005-09-10 12:02:24 +000017989
cerionf3f173c2005-11-14 02:37:44 +000017990 case 0x2F: { // vnmsubfp (Negative Multiply-Subtract FP, AV p215)
cerion5b2325f2005-12-23 00:55:09 +000017991 DIP("vnmsubfp v%d,v%d,v%d,v%d\n",
17992 vD_addr, vA_addr, vC_addr, vB_addr);
17993 putVReg( vD_addr,
sewardj20a760e2014-05-05 10:03:56 +000017994 triop(Iop_Sub32Fx4, mkU32(Irrm_NEAREST),
cerion5b2325f2005-12-23 00:55:09 +000017995 mkexpr(vB),
sewardj20a760e2014-05-05 10:03:56 +000017996 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
17997 mkexpr(vA), mkexpr(vC))) );
cerionf3f173c2005-11-14 02:37:44 +000017998 return True;
17999 }
cerion32aad402005-09-10 12:02:24 +000018000
18001 default:
18002 break; // Fall through...
18003 }
18004
cerion76de5cf2005-11-18 18:25:12 +000018005 opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000018006 switch (opc2) {
18007 case 0x00A: // vaddfp (Add FP, AV p137)
18008 DIP("vaddfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj20a760e2014-05-05 10:03:56 +000018009 putVReg( vD_addr, triop(Iop_Add32Fx4,
18010 mkU32(Irrm_NEAREST), mkexpr(vA), mkexpr(vB)) );
cerion8ea0d3e2005-11-14 00:44:47 +000018011 return True;
cerion32aad402005-09-10 12:02:24 +000018012
18013 case 0x04A: // vsubfp (Subtract FP, AV p261)
18014 DIP("vsubfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj20a760e2014-05-05 10:03:56 +000018015 putVReg( vD_addr, triop(Iop_Sub32Fx4,
18016 mkU32(Irrm_NEAREST), mkexpr(vA), mkexpr(vB)) );
cerion8ea0d3e2005-11-14 00:44:47 +000018017 return True;
cerion32aad402005-09-10 12:02:24 +000018018
18019 case 0x40A: // vmaxfp (Maximum FP, AV p178)
18020 DIP("vmaxfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018021 putVReg( vD_addr, binop(Iop_Max32Fx4, mkexpr(vA), mkexpr(vB)) );
18022 return True;
cerion32aad402005-09-10 12:02:24 +000018023
18024 case 0x44A: // vminfp (Minimum FP, AV p187)
18025 DIP("vminfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018026 putVReg( vD_addr, binop(Iop_Min32Fx4, mkexpr(vA), mkexpr(vB)) );
18027 return True;
cerion32aad402005-09-10 12:02:24 +000018028
18029 default:
18030 break; // Fall through...
18031 }
18032
18033
18034 if (vA_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +000018035 vex_printf("dis_av_fp_arith(ppc)(vA_addr)\n");
cerion32aad402005-09-10 12:02:24 +000018036 return False;
18037 }
18038
18039 switch (opc2) {
18040 case 0x10A: // vrefp (Reciprocal Esimate FP, AV p228)
18041 DIP("vrefp v%d,v%d\n", vD_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018042 putVReg( vD_addr, unop(Iop_Recip32Fx4, mkexpr(vB)) );
18043 return True;
cerion32aad402005-09-10 12:02:24 +000018044
cerion5b2325f2005-12-23 00:55:09 +000018045 case 0x14A: // vrsqrtefp (Reciprocal Sqrt Estimate FP, AV p237)
cerion32aad402005-09-10 12:02:24 +000018046 DIP("vrsqrtefp v%d,v%d\n", vD_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018047 putVReg( vD_addr, unop(Iop_RSqrt32Fx4, mkexpr(vB)) );
18048 return True;
cerion32aad402005-09-10 12:02:24 +000018049
18050 case 0x18A: // vexptefp (2 Raised to the Exp Est FP, AV p173)
18051 DIP("vexptefp v%d,v%d\n", vD_addr, vB_addr);
18052 DIP(" => not implemented\n");
18053 return False;
18054
18055 case 0x1CA: // vlogefp (Log2 Estimate FP, AV p175)
18056 DIP("vlogefp v%d,v%d\n", vD_addr, vB_addr);
18057 DIP(" => not implemented\n");
18058 return False;
18059
18060 default:
cerion5b2325f2005-12-23 00:55:09 +000018061 vex_printf("dis_av_fp_arith(ppc)(opc2=0x%x)\n",opc2);
cerion32aad402005-09-10 12:02:24 +000018062 return False;
18063 }
18064 return True;
18065}
18066
18067/*
18068 AltiVec Floating Point Compare Instructions
18069*/
18070static Bool dis_av_fp_cmp ( UInt theInstr )
18071{
cerion76de5cf2005-11-18 18:25:12 +000018072 /* VXR-Form */
18073 UChar opc1 = ifieldOPC(theInstr);
18074 UChar vD_addr = ifieldRegDS(theInstr);
18075 UChar vA_addr = ifieldRegA(theInstr);
18076 UChar vB_addr = ifieldRegB(theInstr);
18077 UChar flag_rC = ifieldBIT10(theInstr);
18078 UInt opc2 = IFIELD( theInstr, 0, 10 );
cerion32aad402005-09-10 12:02:24 +000018079
cerion8ea0d3e2005-11-14 00:44:47 +000018080 Bool cmp_bounds = False;
18081
18082 IRTemp vA = newTemp(Ity_V128);
18083 IRTemp vB = newTemp(Ity_V128);
18084 IRTemp vD = newTemp(Ity_V128);
18085 assign( vA, getVReg(vA_addr));
18086 assign( vB, getVReg(vB_addr));
18087
cerion32aad402005-09-10 12:02:24 +000018088 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000018089 vex_printf("dis_av_fp_cmp(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000018090 return False;
18091 }
18092
18093 switch (opc2) {
18094 case 0x0C6: // vcmpeqfp (Compare Equal-to FP, AV p159)
cerion5b2325f2005-12-23 00:55:09 +000018095 DIP("vcmpeqfp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
18096 vD_addr, vA_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018097 assign( vD, binop(Iop_CmpEQ32Fx4, mkexpr(vA), mkexpr(vB)) );
18098 break;
cerion32aad402005-09-10 12:02:24 +000018099
cerion5b2325f2005-12-23 00:55:09 +000018100 case 0x1C6: // vcmpgefp (Compare Greater-than-or-Equal-to, AV p163)
18101 DIP("vcmpgefp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
18102 vD_addr, vA_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018103 assign( vD, binop(Iop_CmpGE32Fx4, mkexpr(vA), mkexpr(vB)) );
18104 break;
cerion32aad402005-09-10 12:02:24 +000018105
18106 case 0x2C6: // vcmpgtfp (Compare Greater-than FP, AV p164)
cerion5b2325f2005-12-23 00:55:09 +000018107 DIP("vcmpgtfp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
18108 vD_addr, vA_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018109 assign( vD, binop(Iop_CmpGT32Fx4, mkexpr(vA), mkexpr(vB)) );
18110 break;
cerion32aad402005-09-10 12:02:24 +000018111
cerion8ea0d3e2005-11-14 00:44:47 +000018112 case 0x3C6: { // vcmpbfp (Compare Bounds FP, AV p157)
18113 IRTemp gt = newTemp(Ity_V128);
18114 IRTemp lt = newTemp(Ity_V128);
18115 IRTemp zeros = newTemp(Ity_V128);
cerion5b2325f2005-12-23 00:55:09 +000018116 DIP("vcmpbfp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
18117 vD_addr, vA_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018118 cmp_bounds = True;
18119 assign( zeros, unop(Iop_Dup32x4, mkU32(0)) );
18120
18121 /* Note: making use of fact that the ppc backend for compare insns
cerion5b2325f2005-12-23 00:55:09 +000018122 return zero'd lanes if either of the corresponding arg lanes is
18123 a nan.
cerion8ea0d3e2005-11-14 00:44:47 +000018124
18125 Perhaps better to have an irop Iop_isNan32Fx4, but then we'd
18126 need this for the other compares too (vcmpeqfp etc)...
18127 Better still, tighten down the spec for compare irops.
18128 */
18129 assign( gt, unop(Iop_NotV128,
18130 binop(Iop_CmpLE32Fx4, mkexpr(vA), mkexpr(vB))) );
18131 assign( lt, unop(Iop_NotV128,
18132 binop(Iop_CmpGE32Fx4, mkexpr(vA),
sewardj20a760e2014-05-05 10:03:56 +000018133 triop(Iop_Sub32Fx4, mkU32(Irrm_NEAREST),
18134 mkexpr(zeros),
18135 mkexpr(vB)))) );
cerion8ea0d3e2005-11-14 00:44:47 +000018136
18137 // finally, just shift gt,lt to correct position
18138 assign( vD, binop(Iop_ShlN32x4,
18139 binop(Iop_OrV128,
18140 binop(Iop_AndV128, mkexpr(gt),
18141 unop(Iop_Dup32x4, mkU32(0x2))),
18142 binop(Iop_AndV128, mkexpr(lt),
18143 unop(Iop_Dup32x4, mkU32(0x1)))),
18144 mkU8(30)) );
18145 break;
18146 }
cerion32aad402005-09-10 12:02:24 +000018147
18148 default:
cerion5b2325f2005-12-23 00:55:09 +000018149 vex_printf("dis_av_fp_cmp(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000018150 return False;
18151 }
cerion8ea0d3e2005-11-14 00:44:47 +000018152
18153 putVReg( vD_addr, mkexpr(vD) );
18154
cerion76de5cf2005-11-18 18:25:12 +000018155 if (flag_rC) {
cerion8ea0d3e2005-11-14 00:44:47 +000018156 set_AV_CR6( mkexpr(vD), !cmp_bounds );
18157 }
cerion32aad402005-09-10 12:02:24 +000018158 return True;
18159}
18160
18161/*
18162 AltiVec Floating Point Convert/Round Instructions
18163*/
18164static Bool dis_av_fp_convert ( UInt theInstr )
18165{
cerion76de5cf2005-11-18 18:25:12 +000018166 /* VX-Form */
18167 UChar opc1 = ifieldOPC(theInstr);
18168 UChar vD_addr = ifieldRegDS(theInstr);
18169 UChar UIMM_5 = ifieldRegA(theInstr);
18170 UChar vB_addr = ifieldRegB(theInstr);
18171 UInt opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000018172
cerion76de5cf2005-11-18 18:25:12 +000018173 IRTemp vB = newTemp(Ity_V128);
18174 IRTemp vScale = newTemp(Ity_V128);
ceriond963eb42005-11-16 18:02:58 +000018175 IRTemp vInvScale = newTemp(Ity_V128);
sewardj41a7b702005-11-18 22:18:23 +000018176
18177 float scale, inv_scale;
18178
ceriond963eb42005-11-16 18:02:58 +000018179 assign( vB, getVReg(vB_addr));
18180
18181 /* scale = 2^UIMM, cast to float, reinterpreted as uint */
sewardj41a7b702005-11-18 22:18:23 +000018182 scale = (float)( (unsigned int) 1<<UIMM_5 );
sewardj2ead5222005-11-23 03:53:45 +000018183 assign( vScale, unop(Iop_Dup32x4, mkU32( float_to_bits(scale) )) );
sewardj41a7b702005-11-18 22:18:23 +000018184 inv_scale = 1/scale;
cerion5b2325f2005-12-23 00:55:09 +000018185 assign( vInvScale,
18186 unop(Iop_Dup32x4, mkU32( float_to_bits(inv_scale) )) );
ceriond963eb42005-11-16 18:02:58 +000018187
cerion32aad402005-09-10 12:02:24 +000018188 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000018189 vex_printf("dis_av_fp_convert(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000018190 return False;
18191 }
18192
18193 switch (opc2) {
18194 case 0x30A: // vcfux (Convert from Unsigned Fixed-Point W, AV p156)
18195 DIP("vcfux v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
sewardj20a760e2014-05-05 10:03:56 +000018196 putVReg( vD_addr, triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
ceriond963eb42005-11-16 18:02:58 +000018197 unop(Iop_I32UtoFx4, mkexpr(vB)),
18198 mkexpr(vInvScale)) );
18199 return True;
cerion32aad402005-09-10 12:02:24 +000018200
18201 case 0x34A: // vcfsx (Convert from Signed Fixed-Point W, AV p155)
18202 DIP("vcfsx v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
ceriond963eb42005-11-16 18:02:58 +000018203
sewardj20a760e2014-05-05 10:03:56 +000018204 putVReg( vD_addr, triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
ceriond963eb42005-11-16 18:02:58 +000018205 unop(Iop_I32StoFx4, mkexpr(vB)),
18206 mkexpr(vInvScale)) );
18207 return True;
cerion32aad402005-09-10 12:02:24 +000018208
18209 case 0x38A: // vctuxs (Convert to Unsigned Fixed-Point W Saturate, AV p172)
18210 DIP("vctuxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
ceriond963eb42005-11-16 18:02:58 +000018211 putVReg( vD_addr,
18212 unop(Iop_QFtoI32Ux4_RZ,
sewardj20a760e2014-05-05 10:03:56 +000018213 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
18214 mkexpr(vB), mkexpr(vScale))) );
ceriond963eb42005-11-16 18:02:58 +000018215 return True;
cerion32aad402005-09-10 12:02:24 +000018216
18217 case 0x3CA: // vctsxs (Convert to Signed Fixed-Point W Saturate, AV p171)
18218 DIP("vctsxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
ceriond963eb42005-11-16 18:02:58 +000018219 putVReg( vD_addr,
18220 unop(Iop_QFtoI32Sx4_RZ,
sewardj20a760e2014-05-05 10:03:56 +000018221 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
18222 mkexpr(vB), mkexpr(vScale))) );
ceriond963eb42005-11-16 18:02:58 +000018223 return True;
cerion32aad402005-09-10 12:02:24 +000018224
18225 default:
18226 break; // Fall through...
18227 }
18228
18229 if (UIMM_5 != 0) {
cerion5b2325f2005-12-23 00:55:09 +000018230 vex_printf("dis_av_fp_convert(ppc)(UIMM_5)\n");
cerion32aad402005-09-10 12:02:24 +000018231 return False;
18232 }
18233
18234 switch (opc2) {
18235 case 0x20A: // vrfin (Round to FP Integer Nearest, AV p231)
18236 DIP("vrfin v%d,v%d\n", vD_addr, vB_addr);
ceriond963eb42005-11-16 18:02:58 +000018237 putVReg( vD_addr, unop(Iop_RoundF32x4_RN, mkexpr(vB)) );
18238 break;
cerion32aad402005-09-10 12:02:24 +000018239
18240 case 0x24A: // vrfiz (Round to FP Integer toward zero, AV p233)
18241 DIP("vrfiz v%d,v%d\n", vD_addr, vB_addr);
ceriond963eb42005-11-16 18:02:58 +000018242 putVReg( vD_addr, unop(Iop_RoundF32x4_RZ, mkexpr(vB)) );
18243 break;
cerion32aad402005-09-10 12:02:24 +000018244
18245 case 0x28A: // vrfip (Round to FP Integer toward +inf, AV p232)
18246 DIP("vrfip v%d,v%d\n", vD_addr, vB_addr);
ceriond963eb42005-11-16 18:02:58 +000018247 putVReg( vD_addr, unop(Iop_RoundF32x4_RP, mkexpr(vB)) );
18248 break;
cerion32aad402005-09-10 12:02:24 +000018249
18250 case 0x2CA: // vrfim (Round to FP Integer toward -inf, AV p230)
18251 DIP("vrfim v%d,v%d\n", vD_addr, vB_addr);
ceriond963eb42005-11-16 18:02:58 +000018252 putVReg( vD_addr, unop(Iop_RoundF32x4_RM, mkexpr(vB)) );
18253 break;
cerion32aad402005-09-10 12:02:24 +000018254
18255 default:
cerion5b2325f2005-12-23 00:55:09 +000018256 vex_printf("dis_av_fp_convert(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000018257 return False;
18258 }
18259 return True;
18260}
cerion3d870a32005-03-18 12:23:33 +000018261
carll8943d022013-10-02 16:25:57 +000018262static Bool dis_transactional_memory ( UInt theInstr, UInt nextInstr,
18263 VexAbiInfo* vbi,
18264 /*OUT*/DisResult* dres,
18265 Bool (*resteerOkFn)(void*,Addr64),
18266 void* callback_opaque )
18267{
18268 UInt opc2 = IFIELD( theInstr, 1, 10 );
18269
18270 switch (opc2) {
18271 case 0x28E: { //tbegin.
18272 /* The current implementation is to just fail the tbegin and execute
18273 * the failure path. The failure path is assumed to be functionaly
18274 * equivalent to the transactional path with the needed data locking
18275 * to ensure correctness. The tend is just a noop and shouldn't
18276 * actually get executed.
18277 * 1) set cr0 to 0x2
18278 * 2) Initialize TFHAR to CIA+4
18279 * 3) Initialize TEXASR
18280 * 4) Initialize TFIAR (probably to CIA, ie, the address of tbegin.)
18281 * 5) Continue executing at the next instruction.
18282 */
18283 UInt R = IFIELD( theInstr, 21, 1 );
18284
18285 ULong tm_reason;
18286 UInt failure_code = 0; /* Forcing failure, will not be due to tabort
18287 * or treclaim.
18288 */
18289 UInt persistant = 1; /* set persistant since we are always failing
18290 * the tbegin.
18291 */
18292 UInt nest_overflow = 1; /* Alowed nesting depth overflow, we use this
18293 as the reason for failing the trasaction */
18294 UInt tm_exact = 1; /* have exact address for failure */
18295
18296 DIP("tbegin. %d\n", R);
18297
18298 /* Set the CR0 field to indicate the tbegin failed. Then let
18299 * the code do the branch to the failure path.
18300 *
18301 * 000 || 0 Transaction initiation successful,
18302 * unnested (Transaction state of
18303 * Non-transactional prior to tbegin.)
18304 * 010 || 0 Transaction initiation successful, nested
18305 * (Transaction state of Transactional
18306 * prior to tbegin.)
18307 * 001 || 0 Transaction initiation unsuccessful,
18308 * (Transaction state of Suspended prior
18309 * to tbegin.)
18310 */
18311 putCR321( 0, mkU8( 0x2 ) );
18312
18313 tm_reason = generate_TMreason( failure_code, persistant,
18314 nest_overflow, tm_exact );
18315
18316 storeTMfailure( guest_CIA_curr_instr, tm_reason,
18317 guest_CIA_curr_instr+4 );
18318
18319 return True;
18320
18321 break;
18322 }
18323
18324 case 0x2AE: { //tend.
18325 /* The tend. is just a noop. Do nothing */
18326 UInt A = IFIELD( theInstr, 25, 1 );
18327
18328 DIP("tend. %d\n", A);
18329 break;
18330 }
18331
18332 case 0x2EE: { //tsr.
18333 /* The tsr. is just a noop. Do nothing */
18334 UInt L = IFIELD( theInstr, 21, 1 );
18335
18336 DIP("tsr. %d\n", L);
18337 break;
18338 }
18339
18340 case 0x2CE: { //tcheck.
18341 /* The tcheck. is just a noop. Do nothing */
18342 UInt BF = IFIELD( theInstr, 25, 1 );
18343
18344 DIP("tcheck. %d\n", BF);
18345 break;
18346 }
18347
18348 case 0x30E: { //tbortwc.
18349 /* The tabortwc. is just a noop. Do nothing */
18350 UInt TO = IFIELD( theInstr, 25, 1 );
18351 UInt RA = IFIELD( theInstr, 16, 5 );
18352 UInt RB = IFIELD( theInstr, 11, 5 );
18353
18354 DIP("tabortwc. %d,%d,%d\n", TO, RA, RB);
18355 break;
18356 }
18357
18358 case 0x32E: { //tbortdc.
18359 /* The tabortdc. is just a noop. Do nothing */
18360 UInt TO = IFIELD( theInstr, 25, 1 );
18361 UInt RA = IFIELD( theInstr, 16, 5 );
18362 UInt RB = IFIELD( theInstr, 11, 5 );
18363
18364 DIP("tabortdc. %d,%d,%d\n", TO, RA, RB);
18365 break;
18366 }
18367
18368 case 0x34E: { //tbortwci.
18369 /* The tabortwci. is just a noop. Do nothing */
18370 UInt TO = IFIELD( theInstr, 25, 1 );
18371 UInt RA = IFIELD( theInstr, 16, 5 );
18372 UInt SI = IFIELD( theInstr, 11, 5 );
18373
18374 DIP("tabortwci. %d,%d,%d\n", TO, RA, SI);
18375 break;
18376 }
18377
18378 case 0x36E: { //tbortdci.
18379 /* The tabortdci. is just a noop. Do nothing */
18380 UInt TO = IFIELD( theInstr, 25, 1 );
18381 UInt RA = IFIELD( theInstr, 16, 5 );
18382 UInt SI = IFIELD( theInstr, 11, 5 );
18383
18384 DIP("tabortdci. %d,%d,%d\n", TO, RA, SI);
18385 break;
18386 }
18387
18388 case 0x38E: { //tbort.
18389 /* The tabort. is just a noop. Do nothing */
18390 UInt RA = IFIELD( theInstr, 16, 5 );
18391
18392 DIP("tabort. %d\n", RA);
18393 break;
18394 }
18395
carllfcce5f82013-10-09 17:52:01 +000018396 case 0x3AE: { //treclaim.
18397 /* The treclaim. is just a noop. Do nothing */
18398 UInt RA = IFIELD( theInstr, 16, 5 );
18399
18400 DIP("treclaim. %d\n", RA);
18401 break;
18402 }
18403
18404 case 0x3EE: { //trechkpt.
18405 /* The trechkpt. is just a noop. Do nothing */
18406 DIP("trechkpt.\n");
18407 break;
18408 }
18409
carll8943d022013-10-02 16:25:57 +000018410 default:
18411 vex_printf("dis_transactional_memory(ppc): unrecognized instruction\n");
18412 return False;
18413 }
18414
18415 return True;
18416}
18417
cerion3d870a32005-03-18 12:23:33 +000018418
sewardj66d5ef22011-04-15 11:55:00 +000018419/* The 0x3C primary opcode (VSX category) uses several different forms of
18420 * extended opcodes:
18421 * o XX2-form:
18422 * - [10:2] (IBM notation [21:29])
18423 * o XX3-form variants:
18424 * - variant 1: [10:3] (IBM notation [21:28])
18425 * - variant 2: [9:3] (IBM notation [22:28])
18426 * - variant 3: [7:3] (IBM notation [24:28])
18427 * o XX-4 form:
18428 * - [10:6] (IBM notation [21:25])
18429 *
18430 * The XX2-form needs bit 0 masked from the standard extended opcode
18431 * as returned by ifieldOPClo10; the XX3-form needs bits 0 and 1 masked;
18432 * and the XX4-form needs bits 0, 1, and 2 masked. Additionally, the
18433 * XX4 and XX3 (variants 2 and 3) forms need certain bits masked on the
18434 * front end since their encoding does not begin at bit 21 like the standard
18435 * format.
18436 *
18437 * The get_VSX60_opc2() function uses the vsx_insn array below to obtain the
18438 * secondary opcode for such VSX instructions.
18439 *
18440*/
cerion91ad5362005-01-27 23:02:41 +000018441
cerion91ad5362005-01-27 23:02:41 +000018442
sewardj66d5ef22011-04-15 11:55:00 +000018443struct vsx_insn {
18444 UInt opcode;
florian55085f82012-11-21 00:36:55 +000018445 const HChar * name;
sewardj66d5ef22011-04-15 11:55:00 +000018446};
18447
18448// ATTENTION: Keep this array sorted on the opcocde!!!
18449static struct vsx_insn vsx_all[] = {
carll6c758b62013-10-03 21:38:45 +000018450 { 0x0, "xsaddsp" },
18451 { 0x4, "xsmaddasp" },
sewardj66d5ef22011-04-15 11:55:00 +000018452 { 0x8, "xxsldwi" },
carll6c758b62013-10-03 21:38:45 +000018453 { 0x14, "xsrsqrtesp" },
18454 { 0x16, "xssqrtsp" },
sewardj66d5ef22011-04-15 11:55:00 +000018455 { 0x18, "xxsel" },
carll6c758b62013-10-03 21:38:45 +000018456 { 0x20, "xssubsp" },
18457 { 0x24, "xsmaddmsp" },
sewardj66d5ef22011-04-15 11:55:00 +000018458 { 0x28, "xxpermdi" },
carll6c758b62013-10-03 21:38:45 +000018459 { 0x34, "xsresp" },
18460 { 0x40, "xsmulsp" },
18461 { 0x44, "xsmsubasp" },
sewardj66d5ef22011-04-15 11:55:00 +000018462 { 0x48, "xxmrghw" },
carll6c758b62013-10-03 21:38:45 +000018463 { 0x60, "xsdivsp" },
18464 { 0x64, "xsmsubmsp" },
sewardj66d5ef22011-04-15 11:55:00 +000018465 { 0x80, "xsadddp" },
18466 { 0x84, "xsmaddadp" },
18467 { 0x8c, "xscmpudp" },
18468 { 0x90, "xscvdpuxws" },
18469 { 0x92, "xsrdpi" },
18470 { 0x94, "xsrsqrtedp" },
18471 { 0x96, "xssqrtdp" },
18472 { 0xa0, "xssubdp" },
18473 { 0xa4, "xsmaddmdp" },
18474 { 0xac, "xscmpodp" },
18475 { 0xb0, "xscvdpsxws" },
18476 { 0xb2, "xsrdpiz" },
18477 { 0xb4, "xsredp" },
18478 { 0xc0, "xsmuldp" },
18479 { 0xc4, "xsmsubadp" },
18480 { 0xc8, "xxmrglw" },
18481 { 0xd2, "xsrdpip" },
18482 { 0xd4, "xstsqrtdp" },
18483 { 0xd6, "xsrdpic" },
18484 { 0xe0, "xsdivdp" },
18485 { 0xe4, "xsmsubmdp" },
18486 { 0xf2, "xsrdpim" },
18487 { 0xf4, "xstdivdp" },
18488 { 0x100, "xvaddsp" },
18489 { 0x104, "xvmaddasp" },
18490 { 0x10c, "xvcmpeqsp" },
18491 { 0x110, "xvcvspuxws" },
18492 { 0x112, "xvrspi" },
18493 { 0x114, "xvrsqrtesp" },
18494 { 0x116, "xvsqrtsp" },
18495 { 0x120, "xvsubsp" },
18496 { 0x124, "xvmaddmsp" },
18497 { 0x12c, "xvcmpgtsp" },
18498 { 0x130, "xvcvspsxws" },
18499 { 0x132, "xvrspiz" },
18500 { 0x134, "xvresp" },
18501 { 0x140, "xvmulsp" },
18502 { 0x144, "xvmsubasp" },
18503 { 0x148, "xxspltw" },
18504 { 0x14c, "xvcmpgesp" },
18505 { 0x150, "xvcvuxwsp" },
18506 { 0x152, "xvrspip" },
18507 { 0x154, "xvtsqrtsp" },
18508 { 0x156, "xvrspic" },
18509 { 0x160, "xvdivsp" },
18510 { 0x164, "xvmsubmsp" },
18511 { 0x170, "xvcvsxwsp" },
18512 { 0x172, "xvrspim" },
18513 { 0x174, "xvtdivsp" },
18514 { 0x180, "xvadddp" },
18515 { 0x184, "xvmaddadp" },
18516 { 0x18c, "xvcmpeqdp" },
18517 { 0x190, "xvcvdpuxws" },
18518 { 0x192, "xvrdpi" },
18519 { 0x194, "xvrsqrtedp" },
18520 { 0x196, "xvsqrtdp" },
18521 { 0x1a0, "xvsubdp" },
18522 { 0x1a4, "xvmaddmdp" },
18523 { 0x1ac, "xvcmpgtdp" },
18524 { 0x1b0, "xvcvdpsxws" },
18525 { 0x1b2, "xvrdpiz" },
18526 { 0x1b4, "xvredp" },
18527 { 0x1c0, "xvmuldp" },
18528 { 0x1c4, "xvmsubadp" },
18529 { 0x1cc, "xvcmpgedp" },
18530 { 0x1d0, "xvcvuxwdp" },
18531 { 0x1d2, "xvrdpip" },
18532 { 0x1d4, "xvtsqrtdp" },
18533 { 0x1d6, "xvrdpic" },
18534 { 0x1e0, "xvdivdp" },
18535 { 0x1e4, "xvmsubmdp" },
18536 { 0x1f0, "xvcvsxwdp" },
18537 { 0x1f2, "xvrdpim" },
18538 { 0x1f4, "xvtdivdp" },
carll6c758b62013-10-03 21:38:45 +000018539 { 0x204, "xsnmaddasp" },
sewardj66d5ef22011-04-15 11:55:00 +000018540 { 0x208, "xxland" },
18541 { 0x212, "xscvdpsp" },
carll0c74bb52013-08-12 18:01:40 +000018542 { 0x216, "xscvdpspn" },
carll6c758b62013-10-03 21:38:45 +000018543 { 0x224, "xsnmaddmsp" },
sewardj66d5ef22011-04-15 11:55:00 +000018544 { 0x228, "xxlandc" },
carll6c758b62013-10-03 21:38:45 +000018545 { 0x232, "xxrsp" },
18546 { 0x244, "xsnmsubasp" },
18547 { 0x248, "xxlor" },
18548 { 0x250, "xscvuxdsp" },
18549 { 0x264, "xsnmsubmsp" },
sewardj66d5ef22011-04-15 11:55:00 +000018550 { 0x268, "xxlxor" },
carll6c758b62013-10-03 21:38:45 +000018551 { 0x270, "xscvsxdsp" },
sewardj66d5ef22011-04-15 11:55:00 +000018552 { 0x280, "xsmaxdp" },
18553 { 0x284, "xsnmaddadp" },
18554 { 0x288, "xxlnor" },
18555 { 0x290, "xscvdpuxds" },
18556 { 0x292, "xscvspdp" },
carll0c74bb52013-08-12 18:01:40 +000018557 { 0x296, "xscvspdpn" },
sewardj66d5ef22011-04-15 11:55:00 +000018558 { 0x2a0, "xsmindp" },
18559 { 0x2a4, "xsnmaddmdp" },
carll6c758b62013-10-03 21:38:45 +000018560 { 0x2a8, "xxlorc" },
sewardj66d5ef22011-04-15 11:55:00 +000018561 { 0x2b0, "xscvdpsxds" },
18562 { 0x2b2, "xsabsdp" },
18563 { 0x2c0, "xscpsgndp" },
18564 { 0x2c4, "xsnmsubadp" },
carll6c758b62013-10-03 21:38:45 +000018565 { 0x2c8, "xxlnand" },
sewardj66d5ef22011-04-15 11:55:00 +000018566 { 0x2d0, "xscvuxddp" },
18567 { 0x2d2, "xsnabsdp" },
18568 { 0x2e4, "xsnmsubmdp" },
carll6c758b62013-10-03 21:38:45 +000018569 { 0x2e8, "xxleqv" },
sewardj66d5ef22011-04-15 11:55:00 +000018570 { 0x2f0, "xscvsxddp" },
18571 { 0x2f2, "xsnegdp" },
18572 { 0x300, "xvmaxsp" },
18573 { 0x304, "xvnmaddasp" },
18574 { 0x30c, "xvcmpeqsp." },
18575 { 0x310, "xvcvspuxds" },
18576 { 0x312, "xvcvdpsp" },
18577 { 0x320, "xvminsp" },
18578 { 0x324, "xvnmaddmsp" },
18579 { 0x32c, "xvcmpgtsp." },
18580 { 0x330, "xvcvspsxds" },
18581 { 0x332, "xvabssp" },
18582 { 0x340, "xvcpsgnsp" },
18583 { 0x344, "xvnmsubasp" },
18584 { 0x34c, "xvcmpgesp." },
18585 { 0x350, "xvcvuxdsp" },
18586 { 0x352, "xvnabssp" },
18587 { 0x364, "xvnmsubmsp" },
18588 { 0x370, "xvcvsxdsp" },
18589 { 0x372, "xvnegsp" },
18590 { 0x380, "xvmaxdp" },
18591 { 0x384, "xvnmaddadp" },
18592 { 0x38c, "xvcmpeqdp." },
18593 { 0x390, "xvcvdpuxds" },
18594 { 0x392, "xvcvspdp" },
18595 { 0x3a0, "xvmindp" },
18596 { 0x3a4, "xvnmaddmdp" },
18597 { 0x3ac, "xvcmpgtdp." },
18598 { 0x3b0, "xvcvdpsxds" },
18599 { 0x3b2, "xvabsdp" },
18600 { 0x3c0, "xvcpsgndp" },
18601 { 0x3c4, "xvnmsubadp" },
18602 { 0x3cc, "xvcmpgedp." },
18603 { 0x3d0, "xvcvuxddp" },
18604 { 0x3d2, "xvnabsdp" },
18605 { 0x3e4, "xvnmsubmdp" },
18606 { 0x3f0, "xvcvsxddp" },
18607 { 0x3f2, "xvnegdp" }
18608};
carll0c74bb52013-08-12 18:01:40 +000018609#define VSX_ALL_LEN (sizeof vsx_all / sizeof *vsx_all)
18610
sewardj66d5ef22011-04-15 11:55:00 +000018611
18612// ATTENTION: This search function assumes vsx_all array is sorted.
18613static Int findVSXextOpCode(UInt opcode)
18614{
18615 Int low, mid, high;
18616 low = 0;
18617 high = VSX_ALL_LEN - 1;
18618 while (low <= high) {
18619 mid = (low + high)/2;
18620 if (opcode < vsx_all[mid].opcode)
18621 high = mid - 1;
18622 else if (opcode > vsx_all[mid].opcode)
18623 low = mid + 1;
18624 else
18625 return mid;
18626 }
18627 return -1;
18628}
18629
18630
18631/* The full 10-bit extended opcode retrieved via ifieldOPClo10 is
sewardj4aa412a2011-07-24 14:13:21 +000018632 * passed, and we then try to match it up with one of the VSX forms
18633 * below.
sewardj66d5ef22011-04-15 11:55:00 +000018634 */
18635static UInt get_VSX60_opc2(UInt opc2_full)
18636{
18637#define XX2_MASK 0x000003FE
18638#define XX3_1_MASK 0x000003FC
18639#define XX3_2_MASK 0x000001FC
18640#define XX3_3_MASK 0x0000007C
sewardj4aa412a2011-07-24 14:13:21 +000018641#define XX4_MASK 0x00000018
sewardj66d5ef22011-04-15 11:55:00 +000018642 Int ret;
18643 UInt vsxExtOpcode = 0;
18644
18645 if (( ret = findVSXextOpCode(opc2_full & XX2_MASK)) >= 0)
18646 vsxExtOpcode = vsx_all[ret].opcode;
18647 else if (( ret = findVSXextOpCode(opc2_full & XX3_1_MASK)) >= 0)
18648 vsxExtOpcode = vsx_all[ret].opcode;
18649 else if (( ret = findVSXextOpCode(opc2_full & XX3_2_MASK)) >= 0)
18650 vsxExtOpcode = vsx_all[ret].opcode;
18651 else if (( ret = findVSXextOpCode(opc2_full & XX3_3_MASK)) >= 0)
18652 vsxExtOpcode = vsx_all[ret].opcode;
18653 else if (( ret = findVSXextOpCode(opc2_full & XX4_MASK)) >= 0)
18654 vsxExtOpcode = vsx_all[ret].opcode;
18655
18656 return vsxExtOpcode;
18657}
cerion91ad5362005-01-27 23:02:41 +000018658
cerion896a1372005-01-25 12:24:25 +000018659/*------------------------------------------------------------*/
18660/*--- Disassemble a single instruction ---*/
18661/*------------------------------------------------------------*/
18662
18663/* Disassemble a single instruction into IR. The instruction
sewardj9e6491a2005-07-02 19:24:10 +000018664 is located in host memory at &guest_code[delta]. */
18665
18666static
cerion5b2325f2005-12-23 00:55:09 +000018667DisResult disInstr_PPC_WRK (
sewardjc716aea2006-01-17 01:48:46 +000018668 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +000018669 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +000018670 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000018671 Long delta64,
sewardjaca070a2006-10-17 00:28:22 +000018672 VexArchInfo* archinfo,
sewardj442e51a2012-12-06 18:08:04 +000018673 VexAbiInfo* abiinfo,
18674 Bool sigill_diag
sewardj9e6491a2005-07-02 19:24:10 +000018675 )
cerion896a1372005-01-25 12:24:25 +000018676{
sewardj9e6491a2005-07-02 19:24:10 +000018677 UChar opc1;
18678 UInt opc2;
18679 DisResult dres;
cerion896a1372005-01-25 12:24:25 +000018680 UInt theInstr;
ceriond953ebb2005-11-29 13:27:20 +000018681 IRType ty = mode64 ? Ity_I64 : Ity_I32;
sewardj5117ce12006-01-27 21:20:15 +000018682 Bool allow_F = False;
18683 Bool allow_V = False;
18684 Bool allow_FX = False;
18685 Bool allow_GX = False;
sewardj4aa412a2011-07-24 14:13:21 +000018686 Bool allow_VX = False; // Equates to "supports Power ISA 2.06
sewardjc66d6fa2012-04-02 21:24:12 +000018687 Bool allow_DFP = False;
carll0c74bb52013-08-12 18:01:40 +000018688 Bool allow_isa_2_07 = False;
sewardj5117ce12006-01-27 21:20:15 +000018689 UInt hwcaps = archinfo->hwcaps;
18690 Long delta;
cerion896a1372005-01-25 12:24:25 +000018691
sewardj059601a2005-11-13 00:53:05 +000018692 /* What insn variants are we supporting today? */
sewardj5117ce12006-01-27 21:20:15 +000018693 if (mode64) {
18694 allow_F = True;
18695 allow_V = (0 != (hwcaps & VEX_HWCAPS_PPC64_V));
18696 allow_FX = (0 != (hwcaps & VEX_HWCAPS_PPC64_FX));
18697 allow_GX = (0 != (hwcaps & VEX_HWCAPS_PPC64_GX));
sewardj66d5ef22011-04-15 11:55:00 +000018698 allow_VX = (0 != (hwcaps & VEX_HWCAPS_PPC64_VX));
sewardjc66d6fa2012-04-02 21:24:12 +000018699 allow_DFP = (0 != (hwcaps & VEX_HWCAPS_PPC64_DFP));
carll0c74bb52013-08-12 18:01:40 +000018700 allow_isa_2_07 = (0 != (hwcaps & VEX_HWCAPS_PPC64_ISA2_07));
sewardj5117ce12006-01-27 21:20:15 +000018701 } else {
18702 allow_F = (0 != (hwcaps & VEX_HWCAPS_PPC32_F));
18703 allow_V = (0 != (hwcaps & VEX_HWCAPS_PPC32_V));
18704 allow_FX = (0 != (hwcaps & VEX_HWCAPS_PPC32_FX));
18705 allow_GX = (0 != (hwcaps & VEX_HWCAPS_PPC32_GX));
sewardj66d5ef22011-04-15 11:55:00 +000018706 allow_VX = (0 != (hwcaps & VEX_HWCAPS_PPC32_VX));
sewardjc66d6fa2012-04-02 21:24:12 +000018707 allow_DFP = (0 != (hwcaps & VEX_HWCAPS_PPC32_DFP));
carll0c74bb52013-08-12 18:01:40 +000018708 allow_isa_2_07 = (0 != (hwcaps & VEX_HWCAPS_PPC32_ISA2_07));
sewardj5117ce12006-01-27 21:20:15 +000018709 }
sewardj059601a2005-11-13 00:53:05 +000018710
sewardj9e6491a2005-07-02 19:24:10 +000018711 /* The running delta */
sewardj5117ce12006-01-27 21:20:15 +000018712 delta = (Long)mkSzAddr(ty, (ULong)delta64);
sewardj9e6491a2005-07-02 19:24:10 +000018713
18714 /* Set result defaults. */
sewardj3dee8492012-04-20 00:13:28 +000018715 dres.whatNext = Dis_Continue;
18716 dres.len = 0;
18717 dres.continueAt = 0;
18718 dres.jk_StopHere = Ijk_INVALID;
cerion896a1372005-01-25 12:24:25 +000018719
cerion1515db92005-01-25 17:21:23 +000018720 /* At least this is simple on PPC32: insns are all 4 bytes long, and
cerion896a1372005-01-25 12:24:25 +000018721 4-aligned. So just fish the whole thing out of memory right now
18722 and have done. */
carll1f5fe1f2014-08-07 23:25:23 +000018723 theInstr = getUIntPPCendianly( (UChar*)(&guest_code[delta]) );
cerion896a1372005-01-25 12:24:25 +000018724
sewardj5117ce12006-01-27 21:20:15 +000018725 if (0) vex_printf("insn: 0x%x\n", theInstr);
cerionf0de28c2005-12-13 20:21:11 +000018726
sewardj1eb7e6b2006-01-12 21:13:14 +000018727 DIP("\t0x%llx: ", (ULong)guest_CIA_curr_instr);
sewardjb51f0f42005-07-18 11:38:02 +000018728
sewardjce02aa72006-01-12 12:27:58 +000018729 /* Spot "Special" instructions (see comment at top of file). */
sewardj1eb7e6b2006-01-12 21:13:14 +000018730 {
sewardjce02aa72006-01-12 12:27:58 +000018731 UChar* code = (UChar*)(guest_code + delta);
sewardj1eb7e6b2006-01-12 21:13:14 +000018732 /* Spot the 16-byte preamble:
18733 32-bit mode:
sewardj2171afd2014-02-10 12:27:29 +000018734 5400183E rlwinm 0,0,3,0,31
18735 5400683E rlwinm 0,0,13,0,31
18736 5400E83E rlwinm 0,0,29,0,31
18737 5400983E rlwinm 0,0,19,0,31
sewardj1eb7e6b2006-01-12 21:13:14 +000018738 64-bit mode:
18739 78001800 rotldi 0,0,3
18740 78006800 rotldi 0,0,13
18741 7800E802 rotldi 0,0,61
18742 78009802 rotldi 0,0,51
cerion896a1372005-01-25 12:24:25 +000018743 */
sewardj2171afd2014-02-10 12:27:29 +000018744 UInt word1 = mode64 ? 0x78001800 : 0x5400183E;
18745 UInt word2 = mode64 ? 0x78006800 : 0x5400683E;
18746 UInt word3 = mode64 ? 0x7800E802 : 0x5400E83E;
18747 UInt word4 = mode64 ? 0x78009802 : 0x5400983E;
carll1f5fe1f2014-08-07 23:25:23 +000018748 if (getUIntPPCendianly(code+ 0) == word1 &&
18749 getUIntPPCendianly(code+ 4) == word2 &&
18750 getUIntPPCendianly(code+ 8) == word3 &&
18751 getUIntPPCendianly(code+12) == word4) {
sewardjce02aa72006-01-12 12:27:58 +000018752 /* Got a "Special" instruction preamble. Which one is it? */
carll1f5fe1f2014-08-07 23:25:23 +000018753 if (getUIntPPCendianly(code+16) == 0x7C210B78 /* or 1,1,1 */) {
sewardjce02aa72006-01-12 12:27:58 +000018754 /* %R3 = client_request ( %R4 ) */
18755 DIP("r3 = client_request ( %%r4 )\n");
18756 delta += 20;
sewardj3dee8492012-04-20 00:13:28 +000018757 putGST( PPC_GST_CIA, mkSzImm( ty, guest_CIA_bbstart + delta ));
18758 dres.jk_StopHere = Ijk_ClientReq;
18759 dres.whatNext = Dis_StopHere;
sewardjce02aa72006-01-12 12:27:58 +000018760 goto decode_success;
18761 }
18762 else
carll1f5fe1f2014-08-07 23:25:23 +000018763 if (getUIntPPCendianly(code+16) == 0x7C421378 /* or 2,2,2 */) {
sewardjce02aa72006-01-12 12:27:58 +000018764 /* %R3 = guest_NRADDR */
18765 DIP("r3 = guest_NRADDR\n");
18766 delta += 20;
18767 dres.len = 20;
18768 putIReg(3, IRExpr_Get( OFFB_NRADDR, ty ));
18769 goto decode_success;
18770 }
18771 else
carll1f5fe1f2014-08-07 23:25:23 +000018772 if (getUIntPPCendianly(code+16) == 0x7C631B78 /* or 3,3,3 */) {
sewardjce02aa72006-01-12 12:27:58 +000018773 delta += 20;
carll1f5fe1f2014-08-07 23:25:23 +000018774 if (host_endness == VexEndnessLE) {
18775 /* branch-and-link-to-noredir %R12 */
18776 DIP("branch-and-link-to-noredir r12\n");
18777 putGST( PPC_GST_LR,
18778 mkSzImm(ty, guest_CIA_bbstart + (Long)delta) );
18779 putGST( PPC_GST_CIA, getIReg(12));
18780 } else {
18781 /* branch-and-link-to-noredir %R11 */
18782 DIP("branch-and-link-to-noredir r11\n");
18783 putGST( PPC_GST_LR,
18784 mkSzImm(ty, guest_CIA_bbstart + (Long)delta) );
18785 putGST( PPC_GST_CIA, getIReg(11));
18786 }
sewardj3dee8492012-04-20 00:13:28 +000018787 dres.jk_StopHere = Ijk_NoRedir;
18788 dres.whatNext = Dis_StopHere;
sewardjce02aa72006-01-12 12:27:58 +000018789 goto decode_success;
18790 }
sewardj5ff11dd2006-01-20 14:19:25 +000018791 else
carll1f5fe1f2014-08-07 23:25:23 +000018792 if (getUIntPPCendianly(code+16) == 0x7C842378 /* or 4,4,4 */) {
sewardj5ff11dd2006-01-20 14:19:25 +000018793 /* %R3 = guest_NRADDR_GPR2 */
18794 DIP("r3 = guest_NRADDR_GPR2\n");
18795 delta += 20;
18796 dres.len = 20;
sewardjaca070a2006-10-17 00:28:22 +000018797 putIReg(3, IRExpr_Get( OFFB_NRADDR_GPR2, ty ));
sewardj5ff11dd2006-01-20 14:19:25 +000018798 goto decode_success;
18799 }
florian2245ce92012-08-28 16:49:30 +000018800 else
carll1f5fe1f2014-08-07 23:25:23 +000018801 if (getUIntPPCendianly(code+16) == 0x7CA52B78 /* or 5,5,5 */) {
florian2245ce92012-08-28 16:49:30 +000018802 DIP("IR injection\n");
carll1f5fe1f2014-08-07 23:25:23 +000018803 if (host_endness == VexEndnessBE)
18804 vex_inject_ir(irsb, Iend_BE);
18805 else
18806 vex_inject_ir(irsb, Iend_LE);
florian2245ce92012-08-28 16:49:30 +000018807
18808 delta += 20;
18809 dres.len = 20;
18810
18811 // Invalidate the current insn. The reason is that the IRop we're
18812 // injecting here can change. In which case the translation has to
18813 // be redone. For ease of handling, we simply invalidate all the
18814 // time.
florian9e238732012-08-29 15:00:13 +000018815
sewardj05f5e012014-05-04 10:52:11 +000018816 stmt(IRStmt_Put(OFFB_CMSTART, mkSzImm(ty, guest_CIA_curr_instr)));
18817 stmt(IRStmt_Put(OFFB_CMLEN, mkSzImm(ty, 20)));
florian2245ce92012-08-28 16:49:30 +000018818
18819 putGST( PPC_GST_CIA, mkSzImm( ty, guest_CIA_bbstart + delta ));
18820 dres.whatNext = Dis_StopHere;
sewardj05f5e012014-05-04 10:52:11 +000018821 dres.jk_StopHere = Ijk_InvalICache;
florian2245ce92012-08-28 16:49:30 +000018822 goto decode_success;
18823 }
sewardjce02aa72006-01-12 12:27:58 +000018824 /* We don't know what it is. Set opc1/opc2 so decode_failure
18825 can print the insn following the Special-insn preamble. */
carll1f5fe1f2014-08-07 23:25:23 +000018826 theInstr = getUIntPPCendianly(code+16);
sewardjce02aa72006-01-12 12:27:58 +000018827 opc1 = ifieldOPC(theInstr);
18828 opc2 = ifieldOPClo10(theInstr);
18829 goto decode_failure;
18830 /*NOTREACHED*/
cerion896a1372005-01-25 12:24:25 +000018831 }
18832 }
18833
cerion76de5cf2005-11-18 18:25:12 +000018834 opc1 = ifieldOPC(theInstr);
sewardjb51f0f42005-07-18 11:38:02 +000018835 opc2 = ifieldOPClo10(theInstr);
cerion932ad942005-01-30 10:18:50 +000018836
cerion91ad5362005-01-27 23:02:41 +000018837 // Note: all 'reserved' bits must be cleared, else invalid
18838 switch (opc1) {
cerion896a1372005-01-25 12:24:25 +000018839
cerione9d361a2005-03-04 17:35:29 +000018840 /* Integer Arithmetic Instructions */
18841 case 0x0C: case 0x0D: case 0x0E: // addic, addic., addi
18842 case 0x0F: case 0x07: case 0x08: // addis, mulli, subfic
18843 if (dis_int_arith( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018844 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +000018845
cerione9d361a2005-03-04 17:35:29 +000018846 /* Integer Compare Instructions */
18847 case 0x0B: case 0x0A: // cmpi, cmpli
18848 if (dis_int_cmp( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018849 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +000018850
cerione9d361a2005-03-04 17:35:29 +000018851 /* Integer Logical Instructions */
18852 case 0x1C: case 0x1D: case 0x18: // andi., andis., ori
18853 case 0x19: case 0x1A: case 0x1B: // oris, xori, xoris
18854 if (dis_int_logic( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018855 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +000018856
cerione9d361a2005-03-04 17:35:29 +000018857 /* Integer Rotate Instructions */
18858 case 0x14: case 0x15: case 0x17: // rlwimi, rlwinm, rlwnm
18859 if (dis_int_rot( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018860 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +000018861
cerionf0de28c2005-12-13 20:21:11 +000018862 /* 64bit Integer Rotate Instructions */
18863 case 0x1E: // rldcl, rldcr, rldic, rldicl, rldicr, rldimi
carllbb3f4012012-10-29 20:23:41 +000018864 if (!mode64) goto decode_failure;
cerionf0de28c2005-12-13 20:21:11 +000018865 if (dis_int_rot( theInstr )) goto decode_success;
18866 goto decode_failure;
18867
cerione9d361a2005-03-04 17:35:29 +000018868 /* Integer Load Instructions */
18869 case 0x22: case 0x23: case 0x2A: // lbz, lbzu, lha
18870 case 0x2B: case 0x28: case 0x29: // lhau, lhz, lhzu
18871 case 0x20: case 0x21: // lwz, lwzu
18872 if (dis_int_load( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018873 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +000018874
cerione9d361a2005-03-04 17:35:29 +000018875 /* Integer Store Instructions */
18876 case 0x26: case 0x27: case 0x2C: // stb, stbu, sth
18877 case 0x2D: case 0x24: case 0x25: // sthu, stw, stwu
sewardjdd40fdf2006-12-24 02:20:24 +000018878 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018879 goto decode_failure;
ceriond23be4e2005-01-31 07:23:07 +000018880
sewardj7787af42005-08-04 18:32:19 +000018881 /* Integer Load and Store Multiple Instructions */
18882 case 0x2E: case 0x2F: // lmw, stmw
18883 if (dis_int_ldst_mult( theInstr )) goto decode_success;
18884 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +000018885
cerione9d361a2005-03-04 17:35:29 +000018886 /* Branch Instructions */
18887 case 0x12: case 0x10: // b, bc
sewardjdd40fdf2006-12-24 02:20:24 +000018888 if (dis_branch(theInstr, abiinfo, &dres,
sewardjaca070a2006-10-17 00:28:22 +000018889 resteerOkFn, callback_opaque))
sewardjc716aea2006-01-17 01:48:46 +000018890 goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018891 goto decode_failure;
cerion896a1372005-01-25 12:24:25 +000018892
cerione9d361a2005-03-04 17:35:29 +000018893 /* System Linkage Instructions */
cerion8c3adda2005-01-31 11:54:05 +000018894 case 0x11: // sc
sewardjdd40fdf2006-12-24 02:20:24 +000018895 if (dis_syslink(theInstr, abiinfo, &dres)) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018896 goto decode_failure;
cerion26d07b22005-02-02 17:13:28 +000018897
sewardj334870d2006-02-07 16:42:39 +000018898 /* Trap Instructions */
carllbb3f4012012-10-29 20:23:41 +000018899 case 0x02: // tdi
18900 if (!mode64) goto decode_failure;
18901 if (dis_trapi(theInstr, &dres)) goto decode_success;
18902 goto decode_failure;
18903
18904 case 0x03: // twi
sewardj334870d2006-02-07 16:42:39 +000018905 if (dis_trapi(theInstr, &dres)) goto decode_success;
18906 goto decode_failure;
cerion8c3adda2005-01-31 11:54:05 +000018907
cerion3d870a32005-03-18 12:23:33 +000018908 /* Floating Point Load Instructions */
cerion094d1392005-06-20 13:45:57 +000018909 case 0x30: case 0x31: case 0x32: // lfs, lfsu, lfd
18910 case 0x33: // lfdu
sewardj5117ce12006-01-27 21:20:15 +000018911 if (!allow_F) goto decode_noF;
cerion3d870a32005-03-18 12:23:33 +000018912 if (dis_fp_load( theInstr )) goto decode_success;
cerione9d361a2005-03-04 17:35:29 +000018913 goto decode_failure;
cerion995bc362005-02-03 11:03:31 +000018914
cerion3d870a32005-03-18 12:23:33 +000018915 /* Floating Point Store Instructions */
18916 case 0x34: case 0x35: case 0x36: // stfsx, stfsux, stfdx
18917 case 0x37: // stfdux
sewardj5117ce12006-01-27 21:20:15 +000018918 if (!allow_F) goto decode_noF;
cerion3d870a32005-03-18 12:23:33 +000018919 if (dis_fp_store( theInstr )) goto decode_success;
18920 goto decode_failure;
18921
sewardj7e846302010-09-03 23:37:02 +000018922 /* Floating Point Load Double Pair Instructions */
18923 case 0x39: case 0x3D:
18924 if (!allow_F) goto decode_noF;
18925 if (dis_fp_pair( theInstr )) goto decode_success;
18926 goto decode_failure;
18927
carll78850ae2013-09-10 18:46:40 +000018928 /* 128-bit Integer Load */
18929 case 0x38: // lq
18930 if (dis_int_load( theInstr )) goto decode_success;
18931 goto decode_failure;
18932
cerionf0de28c2005-12-13 20:21:11 +000018933 /* 64bit Integer Loads */
18934 case 0x3A: // ld, ldu, lwa
18935 if (!mode64) goto decode_failure;
18936 if (dis_int_load( theInstr )) goto decode_success;
18937 goto decode_failure;
18938
sewardje14bb9f2005-07-22 09:39:02 +000018939 case 0x3B:
sewardj5117ce12006-01-27 21:20:15 +000018940 if (!allow_F) goto decode_noF;
sewardj66d5ef22011-04-15 11:55:00 +000018941 opc2 = ifieldOPClo10(theInstr);
sewardjc6bbd472012-04-02 10:20:48 +000018942
sewardj66d5ef22011-04-15 11:55:00 +000018943 switch (opc2) {
sewardjc6bbd472012-04-02 10:20:48 +000018944 case 0x2: // dadd - DFP Add
18945 case 0x202: // dsub - DFP Subtract
18946 case 0x22: // dmul - DFP Mult
18947 case 0x222: // ddiv - DFP Divide
sewardjc66d6fa2012-04-02 21:24:12 +000018948 if (!allow_DFP) goto decode_noDFP;
sewardjc6bbd472012-04-02 10:20:48 +000018949 if (dis_dfp_arith( theInstr ))
18950 goto decode_success;
sewardjcdc376d2012-04-23 11:21:12 +000018951 case 0x82: // dcmpo, DFP comparison ordered instruction
18952 case 0x282: // dcmpu, DFP comparison unordered instruction
18953 if (!allow_DFP)
18954 goto decode_failure;
18955 if (dis_dfp_compare( theInstr ) )
18956 goto decode_success;
18957 goto decode_failure;
sewardj26217b02012-04-12 17:19:48 +000018958 case 0x102: // dctdp - DFP convert to DFP long
18959 case 0x302: // drsp - DFP round to dfp short
18960 case 0x122: // dctfix - DFP convert to fixed
18961 if (!allow_DFP)
18962 goto decode_failure;
18963 if (dis_dfp_fmt_conv( theInstr ))
18964 goto decode_success;
18965 goto decode_failure;
18966 case 0x322: // POWER 7 inst, dcffix - DFP convert from fixed
18967 if (!allow_VX)
18968 goto decode_failure;
18969 if (dis_dfp_fmt_conv( theInstr ))
18970 goto decode_success;
18971 goto decode_failure;
sewardj4c96e612012-06-02 23:47:02 +000018972 case 0x2A2: // dtstsf - DFP number of significant digits
18973 if (!allow_DFP)
18974 goto decode_failure;
18975 if (dis_dfp_significant_digits(theInstr))
18976 goto decode_success;
18977 goto decode_failure;
18978 case 0x142: // ddedpd DFP Decode DPD to BCD
18979 case 0x342: // denbcd DFP Encode BCD to DPD
18980 if (!allow_DFP)
18981 goto decode_failure;
18982 if (dis_dfp_bcd(theInstr))
18983 goto decode_success;
18984 goto decode_failure;
sewardjcdc376d2012-04-23 11:21:12 +000018985 case 0x162: // dxex - Extract exponent
18986 case 0x362: // diex - Insert exponent
18987 if (!allow_DFP)
18988 goto decode_failure;
18989 if (dis_dfp_extract_insert( theInstr ) )
18990 goto decode_success;
18991 goto decode_failure;
sewardj4aa412a2011-07-24 14:13:21 +000018992 case 0x3CE: // fcfidus (implemented as native insn)
sewardj66d5ef22011-04-15 11:55:00 +000018993 if (!allow_VX)
18994 goto decode_noVX;
18995 if (dis_fp_round( theInstr ))
18996 goto decode_success;
18997 goto decode_failure;
18998 case 0x34E: // fcfids
18999 if (dis_fp_round( theInstr ))
19000 goto decode_success;
19001 goto decode_failure;
19002 }
19003
sewardj26217b02012-04-12 17:19:48 +000019004 opc2 = ifieldOPClo9( theInstr );
19005 switch (opc2) {
19006 case 0x42: // dscli, DFP shift left
19007 case 0x62: // dscri, DFP shift right
19008 if (!allow_DFP)
19009 goto decode_failure;
19010 if (dis_dfp_shift( theInstr ))
19011 goto decode_success;
19012 goto decode_failure;
sewardj5eff1c52012-04-29 20:19:17 +000019013 case 0xc2: // dtstdc, DFP test data class
19014 case 0xe2: // dtstdg, DFP test data group
19015 if (!allow_DFP)
19016 goto decode_failure;
19017 if (dis_dfp_class_test( theInstr ))
19018 goto decode_success;
19019 goto decode_failure;
sewardj26217b02012-04-12 17:19:48 +000019020 }
19021
sewardjcdc376d2012-04-23 11:21:12 +000019022 opc2 = ifieldOPClo8( theInstr );
19023 switch (opc2) {
19024 case 0x3: // dqua - DFP Quantize
19025 case 0x23: // drrnd - DFP Reround
19026 case 0x43: // dquai - DFP Quantize immediate
19027 if (!allow_DFP)
19028 goto decode_failure;
19029 if (dis_dfp_quantize_sig_rrnd( theInstr ) )
19030 goto decode_success;
19031 goto decode_failure;
sewardj5eff1c52012-04-29 20:19:17 +000019032 case 0xA2: // dtstex - DFP Test exponent
19033 if (!allow_DFP)
19034 goto decode_failure;
19035 if (dis_dfp_exponent_test( theInstr ) )
19036 goto decode_success;
19037 goto decode_failure;
sewardjcdc376d2012-04-23 11:21:12 +000019038 case 0x63: // drintx - Round to an integer value
19039 case 0xE3: // drintn - Round to an integer value
19040 if (!allow_DFP)
19041 goto decode_failure;
19042 if (dis_dfp_round( theInstr ) ) {
19043 goto decode_success;
19044 }
19045 goto decode_failure;
19046 default:
19047 break; /* fall through to next opc2 check */
19048 }
19049
cerion76de5cf2005-11-18 18:25:12 +000019050 opc2 = IFIELD(theInstr, 1, 5);
sewardje14bb9f2005-07-22 09:39:02 +000019051 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +000019052 /* Floating Point Arith Instructions */
19053 case 0x12: case 0x14: case 0x15: // fdivs, fsubs, fadds
sewardj5117ce12006-01-27 21:20:15 +000019054 case 0x19: // fmuls
ceriond953ebb2005-11-29 13:27:20 +000019055 if (dis_fp_arith(theInstr)) goto decode_success;
19056 goto decode_failure;
sewardj5117ce12006-01-27 21:20:15 +000019057 case 0x16: // fsqrts
19058 if (!allow_FX) goto decode_noFX;
19059 if (dis_fp_arith(theInstr)) goto decode_success;
19060 goto decode_failure;
19061 case 0x18: // fres
19062 if (!allow_GX) goto decode_noGX;
19063 if (dis_fp_arith(theInstr)) goto decode_success;
19064 goto decode_failure;
19065
ceriond953ebb2005-11-29 13:27:20 +000019066 /* Floating Point Mult-Add Instructions */
19067 case 0x1C: case 0x1D: case 0x1E: // fmsubs, fmadds, fnmsubs
19068 case 0x1F: // fnmadds
19069 if (dis_fp_multadd(theInstr)) goto decode_success;
19070 goto decode_failure;
sewardj79fd33f2006-01-29 17:07:57 +000019071
19072 case 0x1A: // frsqrtes
19073 if (!allow_GX) goto decode_noGX;
19074 if (dis_fp_arith(theInstr)) goto decode_success;
19075 goto decode_failure;
sewardj66d5ef22011-04-15 11:55:00 +000019076
ceriond953ebb2005-11-29 13:27:20 +000019077 default:
19078 goto decode_failure;
sewardje14bb9f2005-07-22 09:39:02 +000019079 }
19080 break;
cerion3d870a32005-03-18 12:23:33 +000019081
sewardj66d5ef22011-04-15 11:55:00 +000019082 case 0x3C: // VSX instructions (except load/store)
19083 {
floriandc7948f2012-02-15 04:05:05 +000019084 // All of these VSX instructions use some VMX facilities, so
19085 // if allow_V is not set, we'll skip trying to decode.
19086 if (!allow_V) goto decode_noVX;
19087
sewardj66d5ef22011-04-15 11:55:00 +000019088 UInt vsxOpc2 = get_VSX60_opc2(opc2);
19089 /* The vsxOpc2 returned is the "normalized" value, representing the
19090 * instructions secondary opcode as taken from the standard secondary
19091 * opcode field [21:30] (IBM notatition), even if the actual field
19092 * is non-standard. These normalized values are given in the opcode
19093 * appendices of the ISA 2.06 document.
19094 */
sewardj66d5ef22011-04-15 11:55:00 +000019095
19096 switch (vsxOpc2) {
19097 case 0x8: case 0x28: case 0x48: case 0xc8: // xxsldwi, xxpermdi, xxmrghw, xxmrglw
sewardj4aa412a2011-07-24 14:13:21 +000019098 case 0x018: case 0x148: // xxsel, xxspltw
19099 if (dis_vx_permute_misc(theInstr, vsxOpc2)) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019100 goto decode_failure;
carll6c758b62013-10-03 21:38:45 +000019101 case 0x268: case 0x248: case 0x288: // xxlxor, xxlor, xxlnor,
19102 case 0x208: case 0x228: case 0x2A8: // xxland, xxlandc, xxlorc
19103 case 0x2C8: case 0x2E8: // xxlnand, xxleqv
sewardj66d5ef22011-04-15 11:55:00 +000019104 if (dis_vx_logic(theInstr, vsxOpc2)) goto decode_success;
19105 goto decode_failure;
sewardj4aa412a2011-07-24 14:13:21 +000019106 case 0x2B2: case 0x2C0: // xsabsdp, xscpsgndp
19107 case 0x2D2: case 0x2F2: // xsnabsdp, xsnegdp
19108 case 0x280: case 0x2A0: // xsmaxdp, xsmindp
19109 case 0x0F2: case 0x0D2: // xsrdpim, xsrdpip
carll6c758b62013-10-03 21:38:45 +000019110 case 0x034: case 0x014: // xsresp, xsrsqrtesp
sewardje71e56a2011-09-05 12:11:06 +000019111 case 0x0B4: case 0x094: // xsredp, xsrsqrtedp
19112 case 0x0D6: case 0x0B2: // xsrdpic, xsrdpiz
carll6c758b62013-10-03 21:38:45 +000019113 case 0x092: case 0x232: // xsrdpi, xsrsp
sewardj4aa412a2011-07-24 14:13:21 +000019114 if (dis_vxs_misc(theInstr, vsxOpc2)) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019115 goto decode_failure;
19116 case 0x08C: case 0x0AC: // xscmpudp, xscmpodp
19117 if (dis_vx_cmp(theInstr, vsxOpc2)) goto decode_success;
19118 goto decode_failure;
carll6c758b62013-10-03 21:38:45 +000019119 case 0x0: case 0x020: // xsaddsp, xssubsp
19120 case 0x080: // xsadddp
19121 case 0x060: case 0x0E0: // xsdivsp, xsdivdp
19122 case 0x004: case 0x024: // xsmaddasp, xsmaddmsp
sewardj66d5ef22011-04-15 11:55:00 +000019123 case 0x084: case 0x0A4: // xsmaddadp, xsmaddmdp
carll6c758b62013-10-03 21:38:45 +000019124 case 0x044: case 0x064: // xsmsubasp, xsmsubmsp
sewardj66d5ef22011-04-15 11:55:00 +000019125 case 0x0C4: case 0x0E4: // xsmsubadp, xsmsubmdp
carll6c758b62013-10-03 21:38:45 +000019126 case 0x204: case 0x224: // xsnmaddasp, xsnmaddmsp
sewardj66d5ef22011-04-15 11:55:00 +000019127 case 0x284: case 0x2A4: // xsnmaddadp, xsnmaddmdp
carll6c758b62013-10-03 21:38:45 +000019128 case 0x244: case 0x264: // xsnmsubasp, xsnmsubmsp
sewardj4aa412a2011-07-24 14:13:21 +000019129 case 0x2C4: case 0x2E4: // xsnmsubadp, xsnmsubmdp
carll6c758b62013-10-03 21:38:45 +000019130 case 0x040: case 0x0C0: // xsmulsp, xsmuldp
19131 case 0x0A0: // xssubdp
19132 case 0x016: case 0x096: // xssqrtsp,xssqrtdp
19133 case 0x0F4: case 0x0D4: // xstdivdp, xstsqrtdp
sewardj4aa412a2011-07-24 14:13:21 +000019134 if (dis_vxs_arith(theInstr, vsxOpc2)) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019135 goto decode_failure;
sewardj4aa412a2011-07-24 14:13:21 +000019136 case 0x180: // xvadddp
19137 case 0x1E0: // xvdivdp
19138 case 0x1C0: // xvmuldp
19139 case 0x1A0: // xvsubdp
19140 case 0x184: case 0x1A4: // xvmaddadp, xvmaddmdp
19141 case 0x1C4: case 0x1E4: // xvmsubadp, xvmsubmdp
19142 case 0x384: case 0x3A4: // xvnmaddadp, xvnmaddmdp
19143 case 0x3C4: case 0x3E4: // xvnmsubadp, xvnmsubmdp
sewardje71e56a2011-09-05 12:11:06 +000019144 case 0x1D4: case 0x1F4: // xvtsqrtdp, xvtdivdp
19145 case 0x196: // xvsqrtdp
sewardj4aa412a2011-07-24 14:13:21 +000019146 if (dis_vxv_dp_arith(theInstr, vsxOpc2)) goto decode_success;
19147 goto decode_failure;
19148 case 0x100: // xvaddsp
19149 case 0x160: // xvdivsp
19150 case 0x140: // xvmulsp
19151 case 0x120: // xvsubsp
19152 case 0x104: case 0x124: // xvmaddasp, xvmaddmsp
19153 case 0x144: case 0x164: // xvmsubasp, xvmsubmsp
19154 case 0x304: case 0x324: // xvnmaddasp, xvnmaddmsp
19155 case 0x344: case 0x364: // xvnmsubasp, xvnmsubmsp
sewardje71e56a2011-09-05 12:11:06 +000019156 case 0x154: case 0x174: // xvtsqrtsp, xvtdivsp
19157 case 0x116: // xvsqrtsp
sewardj4aa412a2011-07-24 14:13:21 +000019158 if (dis_vxv_sp_arith(theInstr, vsxOpc2)) goto decode_success;
19159 goto decode_failure;
19160
carll6c758b62013-10-03 21:38:45 +000019161 case 0x250: // xscvuxdsp
floriandc7948f2012-02-15 04:05:05 +000019162 case 0x2D0: case 0x3d0: // xscvuxddp, xvcvuxddp
19163 case 0x350: case 0x1d0: // xvcvuxdsp, xvcvuxwdp
19164 case 0x090: // xscvdpuxws
19165 // The above VSX conversion instructions employ some ISA 2.06
19166 // floating point conversion instructions under the covers,
19167 // so if allow_VX (which means "supports ISA 2.06") is not set,
19168 // we'll skip the decode.
19169 if (!allow_VX) goto decode_noVX;
19170 if (dis_vx_conv(theInstr, vsxOpc2)) goto decode_success;
19171 goto decode_failure;
19172
carll6c758b62013-10-03 21:38:45 +000019173 case 0x2B0: // xscvdpsxds
19174 case 0x270: case 0x2F0: // xscvsxdsp, xscvsxddp
sewardj4aa412a2011-07-24 14:13:21 +000019175 case 0x1b0: case 0x130: // xvcvdpsxws, xvcvspsxws
19176 case 0x0b0: case 0x290: // xscvdpsxws, xscvdpuxds
carll0c74bb52013-08-12 18:01:40 +000019177 case 0x212: case 0x216: // xscvdpsp, xscvdpspn
19178 case 0x292: case 0x296: // xscvspdp, xscvspdpn
19179 case 0x312: // xvcvdpsp
sewardje71e56a2011-09-05 12:11:06 +000019180 case 0x390: case 0x190: // xvcvdpuxds, xvcvdpuxws
19181 case 0x3B0: case 0x310: // xvcvdpsxds, xvcvspuxds
19182 case 0x392: case 0x330: // xvcvspdp, xvcvspsxds
19183 case 0x110: case 0x3f0: // xvcvspuxws, xvcvsxddp
19184 case 0x370: case 0x1f0: // xvcvsxdsp, xvcvsxwdp
19185 case 0x170: case 0x150: // xvcvsxwsp, xvcvuxwsp
sewardj66d5ef22011-04-15 11:55:00 +000019186 if (dis_vx_conv(theInstr, vsxOpc2)) goto decode_success;
19187 goto decode_failure;
19188
sewardj4aa412a2011-07-24 14:13:21 +000019189 case 0x18C: case 0x38C: // xvcmpeqdp[.]
19190 case 0x10C: case 0x30C: // xvcmpeqsp[.]
19191 case 0x14C: case 0x34C: // xvcmpgesp[.]
19192 case 0x12C: case 0x32C: // xvcmpgtsp[.]
19193 case 0x1CC: case 0x3CC: // xvcmpgedp[.]
19194 case 0x1AC: case 0x3AC: // xvcmpgtdp[.]
19195 if (dis_vvec_cmp(theInstr, vsxOpc2)) goto decode_success;
19196 goto decode_failure;
19197
19198 case 0x134: // xvresp
sewardje71e56a2011-09-05 12:11:06 +000019199 case 0x1B4: // xvredp
19200 case 0x194: case 0x114: // xvrsqrtedp, xvrsqrtesp
19201 case 0x380: case 0x3A0: // xvmaxdp, xvmindp
sewardj4aa412a2011-07-24 14:13:21 +000019202 case 0x300: case 0x320: // xvmaxsp, xvminsp
sewardje71e56a2011-09-05 12:11:06 +000019203 case 0x3C0: case 0x340: // xvcpsgndp, xvcpsgnsp
19204 case 0x3B2: case 0x332: // xvabsdp, xvabssp
19205 case 0x3D2: case 0x352: // xvnabsdp, xvnabssp
19206 case 0x192: case 0x1D6: // xvrdpi, xvrdpic
19207 case 0x1F2: case 0x1D2: // xvrdpim, xvrdpip
19208 case 0x1B2: case 0x3F2: // xvrdpiz, xvnegdp
19209 case 0x112: case 0x156: // xvrspi, xvrspic
19210 case 0x172: case 0x152: // xvrspim, xvrspip
19211 case 0x132: // xvrspiz
sewardj4aa412a2011-07-24 14:13:21 +000019212 if (dis_vxv_misc(theInstr, vsxOpc2)) goto decode_success;
19213 goto decode_failure;
19214
sewardj66d5ef22011-04-15 11:55:00 +000019215 default:
19216 goto decode_failure;
19217 }
19218 break;
19219 }
19220
cerionf0de28c2005-12-13 20:21:11 +000019221 /* 64bit Integer Stores */
carll78850ae2013-09-10 18:46:40 +000019222 case 0x3E: // std, stdu, stq
sewardjdd40fdf2006-12-24 02:20:24 +000019223 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
cerionf0de28c2005-12-13 20:21:11 +000019224 goto decode_failure;
19225
cerion3d870a32005-03-18 12:23:33 +000019226 case 0x3F:
sewardj5117ce12006-01-27 21:20:15 +000019227 if (!allow_F) goto decode_noF;
cerion5b2325f2005-12-23 00:55:09 +000019228 /* Instrs using opc[1:5] never overlap instrs using opc[1:10],
cerion3d870a32005-03-18 12:23:33 +000019229 so we can simply fall through the first switch statement */
19230
cerion76de5cf2005-11-18 18:25:12 +000019231 opc2 = IFIELD(theInstr, 1, 5);
cerion3d870a32005-03-18 12:23:33 +000019232 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +000019233 /* Floating Point Arith Instructions */
sewardj5117ce12006-01-27 21:20:15 +000019234 case 0x12: case 0x14: case 0x15: // fdiv, fsub, fadd
19235 case 0x19: // fmul
19236 if (dis_fp_arith(theInstr)) goto decode_success;
19237 goto decode_failure;
19238 case 0x16: // fsqrt
19239 if (!allow_FX) goto decode_noFX;
19240 if (dis_fp_arith(theInstr)) goto decode_success;
19241 goto decode_failure;
19242 case 0x17: case 0x1A: // fsel, frsqrte
19243 if (!allow_GX) goto decode_noGX;
ceriond953ebb2005-11-29 13:27:20 +000019244 if (dis_fp_arith(theInstr)) goto decode_success;
19245 goto decode_failure;
sewardje14bb9f2005-07-22 09:39:02 +000019246
ceriond953ebb2005-11-29 13:27:20 +000019247 /* Floating Point Mult-Add Instructions */
19248 case 0x1C: case 0x1D: case 0x1E: // fmsub, fmadd, fnmsub
19249 case 0x1F: // fnmadd
19250 if (dis_fp_multadd(theInstr)) goto decode_success;
19251 goto decode_failure;
sewardj79fd33f2006-01-29 17:07:57 +000019252
19253 case 0x18: // fre
19254 if (!allow_GX) goto decode_noGX;
19255 if (dis_fp_arith(theInstr)) goto decode_success;
19256 goto decode_failure;
carll0c74bb52013-08-12 18:01:40 +000019257
ceriond953ebb2005-11-29 13:27:20 +000019258 default:
19259 break; // Fall through
cerion3d870a32005-03-18 12:23:33 +000019260 }
19261
cerion76de5cf2005-11-18 18:25:12 +000019262 opc2 = IFIELD(theInstr, 1, 10);
sewardje14bb9f2005-07-22 09:39:02 +000019263 switch (opc2) {
sewardjc6bbd472012-04-02 10:20:48 +000019264 /* 128-bit DFP instructions */
19265 case 0x2: // daddq - DFP Add
19266 case 0x202: // dsubq - DFP Subtract
19267 case 0x22: // dmulq - DFP Mult
19268 case 0x222: // ddivq - DFP Divide
sewardjc66d6fa2012-04-02 21:24:12 +000019269 if (!allow_DFP) goto decode_noDFP;
sewardjc6bbd472012-04-02 10:20:48 +000019270 if (dis_dfp_arithq( theInstr ))
19271 goto decode_success;
19272 goto decode_failure;
sewardjcdc376d2012-04-23 11:21:12 +000019273 case 0x162: // dxexq - DFP Extract exponent
19274 case 0x362: // diexq - DFP Insert exponent
19275 if (!allow_DFP)
19276 goto decode_failure;
19277 if (dis_dfp_extract_insertq( theInstr ))
19278 goto decode_success;
19279 goto decode_failure;
19280
19281 case 0x82: // dcmpoq, DFP comparison ordered instruction
19282 case 0x282: // dcmpuq, DFP comparison unordered instruction
19283 if (!allow_DFP)
19284 goto decode_failure;
19285 if (dis_dfp_compare( theInstr ) )
19286 goto decode_success;
19287 goto decode_failure;
sewardjc6bbd472012-04-02 10:20:48 +000019288
sewardj26217b02012-04-12 17:19:48 +000019289 case 0x102: // dctqpq - DFP convert to DFP extended
19290 case 0x302: // drdpq - DFP round to dfp Long
19291 case 0x122: // dctfixq - DFP convert to fixed quad
19292 case 0x322: // dcffixq - DFP convert from fixed quad
19293 if (!allow_DFP)
19294 goto decode_failure;
19295 if (dis_dfp_fmt_convq( theInstr ))
19296 goto decode_success;
19297 goto decode_failure;
19298
sewardj4c96e612012-06-02 23:47:02 +000019299 case 0x2A2: // dtstsfq - DFP number of significant digits
19300 if (!allow_DFP)
19301 goto decode_failure;
19302 if (dis_dfp_significant_digits(theInstr))
19303 goto decode_success;
19304 goto decode_failure;
19305
19306 case 0x142: // ddedpdq DFP Decode DPD to BCD
19307 case 0x342: // denbcdq DFP Encode BCD to DPD
19308 if (!allow_DFP)
19309 goto decode_failure;
19310 if (dis_dfp_bcdq(theInstr))
19311 goto decode_success;
19312 goto decode_failure;
19313
ceriond953ebb2005-11-29 13:27:20 +000019314 /* Floating Point Compare Instructions */
19315 case 0x000: // fcmpu
19316 case 0x020: // fcmpo
19317 if (dis_fp_cmp(theInstr)) goto decode_success;
19318 goto decode_failure;
cerion2831b002005-11-30 19:55:22 +000019319
sewardj66d5ef22011-04-15 11:55:00 +000019320 case 0x080: // ftdiv
sewardje71e56a2011-09-05 12:11:06 +000019321 case 0x0A0: // ftsqrt
19322 if (dis_fp_tests(theInstr)) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019323 goto decode_failure;
19324
ceriond953ebb2005-11-29 13:27:20 +000019325 /* Floating Point Rounding/Conversion Instructions */
19326 case 0x00C: // frsp
19327 case 0x00E: // fctiw
19328 case 0x00F: // fctiwz
sewardj6be67232006-01-24 19:00:05 +000019329 case 0x32E: // fctid
19330 case 0x32F: // fctidz
19331 case 0x34E: // fcfid
ceriond953ebb2005-11-29 13:27:20 +000019332 if (dis_fp_round(theInstr)) goto decode_success;
19333 goto decode_failure;
sewardj4aa412a2011-07-24 14:13:21 +000019334 case 0x3CE: case 0x3AE: case 0x3AF: // fcfidu, fctidu[z] (implemented as native insns)
19335 case 0x08F: case 0x08E: // fctiwu[z] (implemented as native insns)
sewardj66d5ef22011-04-15 11:55:00 +000019336 if (!allow_VX) goto decode_noVX;
19337 if (dis_fp_round(theInstr)) goto decode_success;
19338 goto decode_failure;
19339
sewardj0f1ef862008-08-08 08:37:06 +000019340 /* Power6 rounding stuff */
19341 case 0x1E8: // frim
19342 case 0x1C8: // frip
19343 case 0x188: // frin
19344 case 0x1A8: // friz
sewardj7e846302010-09-03 23:37:02 +000019345 /* A hack to check for P6 capability . . . */
19346 if ((allow_F && allow_V && allow_FX && allow_GX) &&
19347 (dis_fp_round(theInstr)))
sewardj0f1ef862008-08-08 08:37:06 +000019348 goto decode_success;
19349 goto decode_failure;
ceriond953ebb2005-11-29 13:27:20 +000019350
19351 /* Floating Point Move Instructions */
sewardj7e846302010-09-03 23:37:02 +000019352 case 0x008: // fcpsgn
ceriond953ebb2005-11-29 13:27:20 +000019353 case 0x028: // fneg
19354 case 0x048: // fmr
19355 case 0x088: // fnabs
19356 case 0x108: // fabs
19357 if (dis_fp_move( theInstr )) goto decode_success;
19358 goto decode_failure;
sewardje14bb9f2005-07-22 09:39:02 +000019359
carll78850ae2013-09-10 18:46:40 +000019360 case 0x3c6: case 0x346: // fmrgew, fmrgow
19361 if (dis_fp_merge( theInstr )) goto decode_success;
19362 goto decode_failure;
19363
ceriond953ebb2005-11-29 13:27:20 +000019364 /* Floating Point Status/Control Register Instructions */
cerion3ea49ee2006-01-04 10:53:00 +000019365 case 0x026: // mtfsb1
sewardj496b88f2006-10-04 17:46:11 +000019366 case 0x040: // mcrfs
ceriond953ebb2005-11-29 13:27:20 +000019367 case 0x046: // mtfsb0
19368 case 0x086: // mtfsfi
19369 case 0x247: // mffs
19370 case 0x2C7: // mtfsf
sewardjc6bbd472012-04-02 10:20:48 +000019371 // Some of the above instructions need to know more about the
19372 // ISA level supported by the host.
19373 if (dis_fp_scr( theInstr, allow_GX )) goto decode_success;
ceriond953ebb2005-11-29 13:27:20 +000019374 goto decode_failure;
cerionf0de28c2005-12-13 20:21:11 +000019375
ceriond953ebb2005-11-29 13:27:20 +000019376 default:
sewardj26217b02012-04-12 17:19:48 +000019377 break; // Fall through...
19378 }
19379
19380 opc2 = ifieldOPClo9( theInstr );
19381 switch (opc2) {
19382 case 0x42: // dscli, DFP shift left
19383 case 0x62: // dscri, DFP shift right
19384 if (!allow_DFP)
19385 goto decode_failure;
19386 if (dis_dfp_shiftq( theInstr ))
19387 goto decode_success;
ceriond953ebb2005-11-29 13:27:20 +000019388 goto decode_failure;
sewardj5eff1c52012-04-29 20:19:17 +000019389 case 0xc2: // dtstdc, DFP test data class
19390 case 0xe2: // dtstdg, DFP test data group
19391 if (!allow_DFP)
19392 goto decode_failure;
19393 if (dis_dfp_class_test( theInstr ))
19394 goto decode_success;
19395 goto decode_failure;
sewardj26217b02012-04-12 17:19:48 +000019396 default:
sewardj26217b02012-04-12 17:19:48 +000019397 break;
sewardje14bb9f2005-07-22 09:39:02 +000019398 }
sewardjcdc376d2012-04-23 11:21:12 +000019399
19400 opc2 = ifieldOPClo8( theInstr );
19401 switch (opc2) {
19402 case 0x3: // dquaq - DFP Quantize Quad
19403 case 0x23: // drrndq - DFP Reround Quad
19404 case 0x43: // dquaiq - DFP Quantize immediate Quad
19405 if (!allow_DFP)
19406 goto decode_failure;
19407 if (dis_dfp_quantize_sig_rrndq( theInstr ))
19408 goto decode_success;
19409 goto decode_failure;
sewardj5eff1c52012-04-29 20:19:17 +000019410 case 0xA2: // dtstexq - DFP Test exponent Quad
19411 if (dis_dfp_exponent_test( theInstr ) )
19412 goto decode_success;
19413 goto decode_failure;
sewardjcdc376d2012-04-23 11:21:12 +000019414 case 0x63: // drintxq - DFP Round to an integer value
19415 case 0xE3: // drintnq - DFP Round to an integer value
19416 if (!allow_DFP)
19417 goto decode_failure;
19418 if (dis_dfp_roundq( theInstr ))
19419 goto decode_success;
19420 goto decode_failure;
19421
19422 default:
19423 goto decode_failure;
19424 }
cerion3d870a32005-03-18 12:23:33 +000019425 break;
sewardj26217b02012-04-12 17:19:48 +000019426
cerion91ad5362005-01-27 23:02:41 +000019427 case 0x13:
cerionb85e8bb2005-02-16 08:54:33 +000019428 switch (opc2) {
cerion91ad5362005-01-27 23:02:41 +000019429
ceriond953ebb2005-11-29 13:27:20 +000019430 /* Condition Register Logical Instructions */
19431 case 0x101: case 0x081: case 0x121: // crand, crandc, creqv
19432 case 0x0E1: case 0x021: case 0x1C1: // crnand, crnor, cror
19433 case 0x1A1: case 0x0C1: case 0x000: // crorc, crxor, mcrf
19434 if (dis_cond_logic( theInstr )) goto decode_success;
19435 goto decode_failure;
cerionb85e8bb2005-02-16 08:54:33 +000019436
ceriond953ebb2005-11-29 13:27:20 +000019437 /* Branch Instructions */
19438 case 0x210: case 0x010: // bcctr, bclr
sewardjdd40fdf2006-12-24 02:20:24 +000019439 if (dis_branch(theInstr, abiinfo, &dres,
sewardjaca070a2006-10-17 00:28:22 +000019440 resteerOkFn, callback_opaque))
sewardjc716aea2006-01-17 01:48:46 +000019441 goto decode_success;
ceriond953ebb2005-11-29 13:27:20 +000019442 goto decode_failure;
19443
19444 /* Memory Synchronization Instructions */
19445 case 0x096: // isync
19446 if (dis_memsync( theInstr )) goto decode_success;
19447 goto decode_failure;
carll78850ae2013-09-10 18:46:40 +000019448
ceriond953ebb2005-11-29 13:27:20 +000019449 default:
19450 goto decode_failure;
cerionb85e8bb2005-02-16 08:54:33 +000019451 }
19452 break;
cerion91ad5362005-01-27 23:02:41 +000019453
19454
cerionb85e8bb2005-02-16 08:54:33 +000019455 case 0x1F:
cerione9d361a2005-03-04 17:35:29 +000019456
19457 /* For arith instns, bit10 is the OE flag (overflow enable) */
19458
cerion76de5cf2005-11-18 18:25:12 +000019459 opc2 = IFIELD(theInstr, 1, 9);
cerionb85e8bb2005-02-16 08:54:33 +000019460 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +000019461 /* Integer Arithmetic Instructions */
19462 case 0x10A: case 0x00A: case 0x08A: // add, addc, adde
19463 case 0x0EA: case 0x0CA: case 0x1EB: // addme, addze, divw
19464 case 0x1CB: case 0x04B: case 0x00B: // divwu, mulhw, mulhwu
19465 case 0x0EB: case 0x068: case 0x028: // mullw, neg, subf
19466 case 0x008: case 0x088: case 0x0E8: // subfc, subfe, subfme
sewardj4aa412a2011-07-24 14:13:21 +000019467 case 0x0C8: // subfze
19468 if (dis_int_arith( theInstr )) goto decode_success;
19469 goto decode_failure;
19470
19471 case 0x18B: // divweu (implemented as native insn)
sewardje71e56a2011-09-05 12:11:06 +000019472 case 0x1AB: // divwe (implemented as native insn)
sewardj4aa412a2011-07-24 14:13:21 +000019473 if (!allow_VX) goto decode_noVX;
ceriond953ebb2005-11-29 13:27:20 +000019474 if (dis_int_arith( theInstr )) goto decode_success;
19475 goto decode_failure;
cerionf0de28c2005-12-13 20:21:11 +000019476
19477 /* 64bit Integer Arithmetic */
19478 case 0x009: case 0x049: case 0x0E9: // mulhdu, mulhd, mulld
sewardj4aa412a2011-07-24 14:13:21 +000019479 case 0x1C9: case 0x1E9: // divdu, divd
19480 if (!mode64) goto decode_failure;
19481 if (dis_int_arith( theInstr )) goto decode_success;
19482 goto decode_failure;
19483
19484 case 0x1A9: // divde (implemented as native insn)
sewardje71e56a2011-09-05 12:11:06 +000019485 case 0x189: // divdeuo (implemented as native insn)
sewardj4aa412a2011-07-24 14:13:21 +000019486 if (!allow_VX) goto decode_noVX;
cerionf0de28c2005-12-13 20:21:11 +000019487 if (!mode64) goto decode_failure;
19488 if (dis_int_arith( theInstr )) goto decode_success;
19489 goto decode_failure;
19490
sewardj7e846302010-09-03 23:37:02 +000019491 case 0x1FC: // cmpb
19492 if (dis_int_logic( theInstr )) goto decode_success;
19493 goto decode_failure;
19494
ceriond953ebb2005-11-29 13:27:20 +000019495 default:
19496 break; // Fall through...
cerionb85e8bb2005-02-16 08:54:33 +000019497 }
cerion91ad5362005-01-27 23:02:41 +000019498
cerione9d361a2005-03-04 17:35:29 +000019499 /* All remaining opcodes use full 10 bits. */
19500
cerion76de5cf2005-11-18 18:25:12 +000019501 opc2 = IFIELD(theInstr, 1, 10);
cerionb85e8bb2005-02-16 08:54:33 +000019502 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +000019503 /* Integer Compare Instructions */
19504 case 0x000: case 0x020: // cmp, cmpl
19505 if (dis_int_cmp( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019506 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +000019507
cerione9d361a2005-03-04 17:35:29 +000019508 /* Integer Logical Instructions */
19509 case 0x01C: case 0x03C: case 0x01A: // and, andc, cntlzw
19510 case 0x11C: case 0x3BA: case 0x39A: // eqv, extsb, extsh
19511 case 0x1DC: case 0x07C: case 0x1BC: // nand, nor, or
19512 case 0x19C: case 0x13C: // orc, xor
sewardj7e846302010-09-03 23:37:02 +000019513 case 0x2DF: case 0x25F: // mftgpr, mffgpr
cerione9d361a2005-03-04 17:35:29 +000019514 if (dis_int_logic( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019515 goto decode_failure;
cerion932ad942005-01-30 10:18:50 +000019516
carll8943d022013-10-02 16:25:57 +000019517 case 0x28E: case 0x2AE: // tbegin., tend.
19518 case 0x2EE: case 0x2CE: case 0x30E: // tsr., tcheck., tabortwc.
19519 case 0x32E: case 0x34E: case 0x36E: // tabortdc., tabortwci., tabortdci.
carllfcce5f82013-10-09 17:52:01 +000019520 case 0x38E: case 0x3AE: case 0x3EE: // tabort., treclaim., trechkpt.
carll8943d022013-10-02 16:25:57 +000019521 if (dis_transactional_memory( theInstr,
carll1f5fe1f2014-08-07 23:25:23 +000019522 getUIntPPCendianly( (UChar*)(&guest_code[delta + 4])),
carll8943d022013-10-02 16:25:57 +000019523 abiinfo, &dres,
19524 resteerOkFn, callback_opaque))
19525 goto decode_success;
19526 goto decode_failure;
19527
cerionf0de28c2005-12-13 20:21:11 +000019528 /* 64bit Integer Logical Instructions */
cerion07b07a92005-12-22 14:32:35 +000019529 case 0x3DA: case 0x03A: // extsw, cntlzd
cerionf0de28c2005-12-13 20:21:11 +000019530 if (!mode64) goto decode_failure;
19531 if (dis_int_logic( theInstr )) goto decode_success;
19532 goto decode_failure;
19533
sewardj7e846302010-09-03 23:37:02 +000019534 /* 64bit Integer Parity Instructions */
carllbb3f4012012-10-29 20:23:41 +000019535 case 0xba: // prtyd
19536 if (!mode64) goto decode_failure;
19537 if (dis_int_parity( theInstr )) goto decode_success;
19538 goto decode_failure;
19539
19540 case 0x9a: // prtyw
sewardj7e846302010-09-03 23:37:02 +000019541 if (dis_int_parity( theInstr )) goto decode_success;
19542 goto decode_failure;
19543
cerione9d361a2005-03-04 17:35:29 +000019544 /* Integer Shift Instructions */
19545 case 0x018: case 0x318: case 0x338: // slw, sraw, srawi
19546 case 0x218: // srw
19547 if (dis_int_shift( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019548 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +000019549
cerionf0de28c2005-12-13 20:21:11 +000019550 /* 64bit Integer Shift Instructions */
19551 case 0x01B: case 0x31A: // sld, srad
cerion07b07a92005-12-22 14:32:35 +000019552 case 0x33A: case 0x33B: // sradi
cerionf0de28c2005-12-13 20:21:11 +000019553 case 0x21B: // srd
19554 if (!mode64) goto decode_failure;
19555 if (dis_int_shift( theInstr )) goto decode_success;
19556 goto decode_failure;
19557
cerione9d361a2005-03-04 17:35:29 +000019558 /* Integer Load Instructions */
19559 case 0x057: case 0x077: case 0x157: // lbzx, lbzux, lhax
19560 case 0x177: case 0x117: case 0x137: // lhaux, lhzx, lhzux
19561 case 0x017: case 0x037: // lwzx, lwzux
19562 if (dis_int_load( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019563 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +000019564
cerionf0de28c2005-12-13 20:21:11 +000019565 /* 64bit Integer Load Instructions */
19566 case 0x035: case 0x015: // ldux, ldx
19567 case 0x175: case 0x155: // lwaux, lwax
19568 if (!mode64) goto decode_failure;
19569 if (dis_int_load( theInstr )) goto decode_success;
19570 goto decode_failure;
19571
sewardjb51f0f42005-07-18 11:38:02 +000019572 /* Integer Store Instructions */
cerione9d361a2005-03-04 17:35:29 +000019573 case 0x0F7: case 0x0D7: case 0x1B7: // stbux, stbx, sthux
19574 case 0x197: case 0x0B7: case 0x097: // sthx, stwux, stwx
sewardjdd40fdf2006-12-24 02:20:24 +000019575 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019576 goto decode_failure;
cerion91ad5362005-01-27 23:02:41 +000019577
cerionf0de28c2005-12-13 20:21:11 +000019578 /* 64bit Integer Store Instructions */
19579 case 0x0B5: case 0x095: // stdux, stdx
19580 if (!mode64) goto decode_failure;
sewardjdd40fdf2006-12-24 02:20:24 +000019581 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
cerionf0de28c2005-12-13 20:21:11 +000019582 goto decode_failure;
19583
sewardj602857d2005-09-06 09:10:09 +000019584 /* Integer Load and Store with Byte Reverse Instructions */
carllbb3f4012012-10-29 20:23:41 +000019585 case 0x214: case 0x294: // ldbrx, stdbrx
19586 if (!mode64) goto decode_failure;
19587 if (dis_int_ldst_rev( theInstr )) goto decode_success;
19588 goto decode_failure;
19589
19590 case 0x216: case 0x316: case 0x296: // lwbrx, lhbrx, stwbrx
19591 case 0x396: // sthbrx
sewardj602857d2005-09-06 09:10:09 +000019592 if (dis_int_ldst_rev( theInstr )) goto decode_success;
19593 goto decode_failure;
19594
sewardj87e651f2005-09-09 08:31:18 +000019595 /* Integer Load and Store String Instructions */
19596 case 0x255: case 0x215: case 0x2D5: // lswi, lswx, stswi
19597 case 0x295: { // stswx
19598 Bool stopHere = False;
19599 Bool ok = dis_int_ldst_str( theInstr, &stopHere );
19600 if (!ok) goto decode_failure;
19601 if (stopHere) {
sewardj3dee8492012-04-20 00:13:28 +000019602 putGST( PPC_GST_CIA, mkSzImm(ty, nextInsnAddr()) );
19603 dres.jk_StopHere = Ijk_Boring;
19604 dres.whatNext = Dis_StopHere;
sewardj87e651f2005-09-09 08:31:18 +000019605 }
19606 goto decode_success;
19607 }
cerion645c9302005-01-31 10:09:59 +000019608
cerione9d361a2005-03-04 17:35:29 +000019609 /* Memory Synchronization Instructions */
19610 case 0x356: case 0x014: case 0x096: // eieio, lwarx, stwcx.
19611 case 0x256: // sync
19612 if (dis_memsync( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019613 goto decode_failure;
19614
cerionf0de28c2005-12-13 20:21:11 +000019615 /* 64bit Memory Synchronization Instructions */
19616 case 0x054: case 0x0D6: // ldarx, stdcx.
19617 if (!mode64) goto decode_failure;
19618 if (dis_memsync( theInstr )) goto decode_success;
19619 goto decode_failure;
19620
carll78850ae2013-09-10 18:46:40 +000019621 case 0x114: case 0x0B6: // lqarx, stqcx.
19622 if (dis_memsync( theInstr )) goto decode_success;
19623 goto decode_failure;
19624
cerione9d361a2005-03-04 17:35:29 +000019625 /* Processor Control Instructions */
carll78850ae2013-09-10 18:46:40 +000019626 case 0x33: case 0x73: // mfvsrd, mfvsrwz
19627 case 0xB3: case 0xD3: case 0xF3: // mtvsrd, mtvsrwa, mtvsrwz
cerione9d361a2005-03-04 17:35:29 +000019628 case 0x200: case 0x013: case 0x153: // mcrxr, mfcr, mfspr
19629 case 0x173: case 0x090: case 0x1D3: // mftb, mtcrf, mtspr
carll78850ae2013-09-10 18:46:40 +000019630 case 0x220: // mcrxrt
sewardjdd40fdf2006-12-24 02:20:24 +000019631 if (dis_proc_ctl( abiinfo, theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019632 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +000019633
cerione9d361a2005-03-04 17:35:29 +000019634 /* Cache Management Instructions */
19635 case 0x2F6: case 0x056: case 0x036: // dcba, dcbf, dcbst
19636 case 0x116: case 0x0F6: case 0x3F6: // dcbt, dcbtst, dcbz
19637 case 0x3D6: // icbi
carll1f5fe1f2014-08-07 23:25:23 +000019638 if (dis_cache_manage( theInstr, &dres, archinfo ))
sewardjd94b73a2005-06-30 12:08:48 +000019639 goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019640 goto decode_failure;
ceriond23be4e2005-01-31 07:23:07 +000019641
sewardjb51f0f42005-07-18 11:38:02 +000019642//zz /* External Control Instructions */
19643//zz case 0x136: case 0x1B6: // eciwx, ecowx
19644//zz DIP("external control op => not implemented\n");
19645//zz goto decode_failure;
sewardj59c0d8f2007-08-28 14:48:35 +000019646
19647 /* Trap Instructions */
carllbb3f4012012-10-29 20:23:41 +000019648 case 0x004: // tw
19649 if (dis_trap(theInstr, &dres)) goto decode_success;
19650 goto decode_failure;
19651
19652 case 0x044: // td
19653 if (!mode64) goto decode_failure;
sewardj59c0d8f2007-08-28 14:48:35 +000019654 if (dis_trap(theInstr, &dres)) goto decode_success;
19655 goto decode_failure;
sewardje14bb9f2005-07-22 09:39:02 +000019656
19657 /* Floating Point Load Instructions */
19658 case 0x217: case 0x237: case 0x257: // lfsx, lfsux, lfdx
19659 case 0x277: // lfdux
sewardj5117ce12006-01-27 21:20:15 +000019660 if (!allow_F) goto decode_noF;
sewardje14bb9f2005-07-22 09:39:02 +000019661 if (dis_fp_load( theInstr )) goto decode_success;
19662 goto decode_failure;
19663
19664 /* Floating Point Store Instructions */
19665 case 0x297: case 0x2B7: case 0x2D7: // stfs, stfsu, stfd
sewardj5117ce12006-01-27 21:20:15 +000019666 case 0x2F7: // stfdu, stfiwx
19667 if (!allow_F) goto decode_noF;
sewardje14bb9f2005-07-22 09:39:02 +000019668 if (dis_fp_store( theInstr )) goto decode_success;
19669 goto decode_failure;
sewardj5117ce12006-01-27 21:20:15 +000019670 case 0x3D7: // stfiwx
19671 if (!allow_F) goto decode_noF;
19672 if (!allow_GX) goto decode_noGX;
19673 if (dis_fp_store( theInstr )) goto decode_success;
19674 goto decode_failure;
sewardje14bb9f2005-07-22 09:39:02 +000019675
sewardj7e846302010-09-03 23:37:02 +000019676 /* Floating Point Double Pair Indexed Instructions */
19677 case 0x317: // lfdpx (Power6)
19678 case 0x397: // stfdpx (Power6)
19679 if (!allow_F) goto decode_noF;
19680 if (dis_fp_pair(theInstr)) goto decode_success;
19681 goto decode_failure;
19682
19683 case 0x357: // lfiwax
19684 if (!allow_F) goto decode_noF;
19685 if (dis_fp_load( theInstr )) goto decode_success;
19686 goto decode_failure;
19687
sewardj66d5ef22011-04-15 11:55:00 +000019688 case 0x377: // lfiwzx
19689 if (!allow_F) goto decode_noF;
19690 if (dis_fp_load( theInstr )) goto decode_success;
19691 goto decode_failure;
19692
cerion32aad402005-09-10 12:02:24 +000019693 /* AltiVec instructions */
19694
19695 /* AV Cache Control - Data streams */
19696 case 0x156: case 0x176: case 0x336: // dst, dstst, dss
sewardj5117ce12006-01-27 21:20:15 +000019697 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019698 if (dis_av_datastream( theInstr )) goto decode_success;
19699 goto decode_failure;
ceriona982c052005-06-28 17:23:09 +000019700
19701 /* AV Load */
19702 case 0x006: case 0x026: // lvsl, lvsr
19703 case 0x007: case 0x027: case 0x047: // lvebx, lvehx, lvewx
19704 case 0x067: case 0x167: // lvx, lvxl
sewardj5117ce12006-01-27 21:20:15 +000019705 if (!allow_V) goto decode_noV;
sewardjdd40fdf2006-12-24 02:20:24 +000019706 if (dis_av_load( abiinfo, theInstr )) goto decode_success;
ceriona982c052005-06-28 17:23:09 +000019707 goto decode_failure;
19708
19709 /* AV Store */
19710 case 0x087: case 0x0A7: case 0x0C7: // stvebx, stvehx, stvewx
19711 case 0x0E7: case 0x1E7: // stvx, stvxl
sewardj5117ce12006-01-27 21:20:15 +000019712 if (!allow_V) goto decode_noV;
ceriona982c052005-06-28 17:23:09 +000019713 if (dis_av_store( theInstr )) goto decode_success;
19714 goto decode_failure;
19715
sewardj66d5ef22011-04-15 11:55:00 +000019716 /* VSX Load */
carll6c758b62013-10-03 21:38:45 +000019717 case 0x00C: // lxsiwzx
19718 case 0x04C: // lxsiwax
19719 case 0x20C: // lxsspx
sewardj66d5ef22011-04-15 11:55:00 +000019720 case 0x24C: // lxsdx
19721 case 0x34C: // lxvd2x
19722 case 0x14C: // lxvdsx
19723 case 0x30C: // lxvw4x
floriandc7948f2012-02-15 04:05:05 +000019724 // All of these VSX load instructions use some VMX facilities, so
19725 // if allow_V is not set, we'll skip trying to decode.
19726 if (!allow_V) goto decode_noV;
19727
carll1f5fe1f2014-08-07 23:25:23 +000019728 if (dis_vx_load( theInstr )) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019729 goto decode_failure;
19730
19731 /* VSX Store */
carll6c758b62013-10-03 21:38:45 +000019732 case 0x08C: // stxsiwx
19733 case 0x28C: // stxsspx
sewardj66d5ef22011-04-15 11:55:00 +000019734 case 0x2CC: // stxsdx
19735 case 0x3CC: // stxvd2x
19736 case 0x38C: // stxvw4x
floriandc7948f2012-02-15 04:05:05 +000019737 // All of these VSX store instructions use some VMX facilities, so
19738 // if allow_V is not set, we'll skip trying to decode.
19739 if (!allow_V) goto decode_noV;
19740
carll1f5fe1f2014-08-07 23:25:23 +000019741 if (dis_vx_store( theInstr )) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019742 goto decode_failure;
19743
19744 /* Miscellaneous ISA 2.06 instructions */
19745 case 0x1FA: // popcntd
sewardje71e56a2011-09-05 12:11:06 +000019746 case 0x17A: // popcntw
philippe738d9dd2012-07-06 21:56:53 +000019747 case 0x7A: // popcntb
carll1f5fe1f2014-08-07 23:25:23 +000019748 if (dis_int_logic( theInstr )) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019749 goto decode_failure;
19750
sewardj4aa412a2011-07-24 14:13:21 +000019751 case 0x0FC: // bpermd
carllbb3f4012012-10-29 20:23:41 +000019752 if (!mode64) goto decode_failure;
sewardj4aa412a2011-07-24 14:13:21 +000019753 if (dis_int_logic( theInstr )) goto decode_success;
19754 goto decode_failure;
19755
ceriona982c052005-06-28 17:23:09 +000019756 default:
sewardjcb07be22008-11-06 09:02:34 +000019757 /* Deal with some other cases that we would otherwise have
19758 punted on. */
19759 /* --- ISEL (PowerISA_V2.05.pdf, p74) --- */
sewardj1685c282008-11-06 09:22:05 +000019760 /* only decode this insn when reserved bit 0 (31 in IBM's
19761 notation) is zero */
19762 if (IFIELD(theInstr, 0, 6) == (15<<1)) {
sewardjcb07be22008-11-06 09:02:34 +000019763 UInt rT = ifieldRegDS( theInstr );
19764 UInt rA = ifieldRegA( theInstr );
19765 UInt rB = ifieldRegB( theInstr );
19766 UInt bi = ifieldRegC( theInstr );
19767 putIReg(
19768 rT,
florian99dd03e2013-01-29 03:56:06 +000019769 IRExpr_ITE( binop(Iop_CmpNE32, getCRbit( bi ), mkU32(0)),
19770 rA == 0 ? (mode64 ? mkU64(0) : mkU32(0))
19771 : getIReg(rA),
19772 getIReg(rB))
19773
sewardjcb07be22008-11-06 09:02:34 +000019774 );
19775 DIP("isel r%u,r%u,r%u,crb%u\n", rT,rA,rB,bi);
19776 goto decode_success;
19777 }
ceriona982c052005-06-28 17:23:09 +000019778 goto decode_failure;
19779 }
19780 break;
19781
19782
cerion32aad402005-09-10 12:02:24 +000019783 case 0x04:
19784 /* AltiVec instructions */
19785
cerion76de5cf2005-11-18 18:25:12 +000019786 opc2 = IFIELD(theInstr, 0, 6);
cerion32aad402005-09-10 12:02:24 +000019787 switch (opc2) {
19788 /* AV Mult-Add, Mult-Sum */
19789 case 0x20: case 0x21: case 0x22: // vmhaddshs, vmhraddshs, vmladduhm
19790 case 0x24: case 0x25: case 0x26: // vmsumubm, vmsummbm, vmsumuhm
19791 case 0x27: case 0x28: case 0x29: // vmsumuhs, vmsumshm, vmsumshs
sewardj5117ce12006-01-27 21:20:15 +000019792 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019793 if (dis_av_multarith( theInstr )) goto decode_success;
19794 goto decode_failure;
19795
19796 /* AV Permutations */
19797 case 0x2A: // vsel
19798 case 0x2B: // vperm
cerion32aad402005-09-10 12:02:24 +000019799 case 0x2C: // vsldoi
sewardj5117ce12006-01-27 21:20:15 +000019800 if (!allow_V) goto decode_noV;
cerion92d9d872005-09-15 21:58:50 +000019801 if (dis_av_permute( theInstr )) goto decode_success;
cerion32aad402005-09-10 12:02:24 +000019802 goto decode_failure;
19803
carll7deaf952013-10-15 18:11:20 +000019804 case 0x2D: // vpermxor
19805 if (!allow_isa_2_07) goto decode_noP8;
19806 if (dis_av_permute( theInstr )) goto decode_success;
19807 goto decode_failure;
19808
cerion32aad402005-09-10 12:02:24 +000019809 /* AV Floating Point Mult-Add/Sub */
19810 case 0x2E: case 0x2F: // vmaddfp, vnmsubfp
sewardj5117ce12006-01-27 21:20:15 +000019811 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019812 if (dis_av_fp_arith( theInstr )) goto decode_success;
19813 goto decode_failure;
19814
carll60c6bac2013-10-18 01:19:06 +000019815 case 0x3D: case 0x3C: // vaddecuq, vaddeuqm
19816 case 0x3F: case 0x3E: // vsubecuq, vsubeuqm
19817 if (!allow_V) goto decode_noV;
19818 if (dis_av_quad( theInstr)) goto decode_success;
19819 goto decode_failure;
19820
cerion32aad402005-09-10 12:02:24 +000019821 default:
19822 break; // Fall through...
19823 }
19824
carll7deaf952013-10-15 18:11:20 +000019825 opc2 = IFIELD(theInstr, 0, 9);
19826 switch (opc2) {
19827 /* BCD arithmetic */
19828 case 0x1: case 0x41: // bcdadd, bcdsub
19829 if (!allow_isa_2_07) goto decode_noP8;
19830 if (dis_av_bcd( theInstr )) goto decode_success;
19831 goto decode_failure;
19832
19833 default:
19834 break; // Fall through...
19835 }
19836
cerion76de5cf2005-11-18 18:25:12 +000019837 opc2 = IFIELD(theInstr, 0, 11);
cerion32aad402005-09-10 12:02:24 +000019838 switch (opc2) {
19839 /* AV Arithmetic */
19840 case 0x180: // vaddcuw
19841 case 0x000: case 0x040: case 0x080: // vaddubm, vadduhm, vadduwm
19842 case 0x200: case 0x240: case 0x280: // vaddubs, vadduhs, vadduws
19843 case 0x300: case 0x340: case 0x380: // vaddsbs, vaddshs, vaddsws
19844 case 0x580: // vsubcuw
19845 case 0x400: case 0x440: case 0x480: // vsububm, vsubuhm, vsubuwm
19846 case 0x600: case 0x640: case 0x680: // vsububs, vsubuhs, vsubuws
19847 case 0x700: case 0x740: case 0x780: // vsubsbs, vsubshs, vsubsws
19848 case 0x402: case 0x442: case 0x482: // vavgub, vavguh, vavguw
19849 case 0x502: case 0x542: case 0x582: // vavgsb, vavgsh, vavgsw
19850 case 0x002: case 0x042: case 0x082: // vmaxub, vmaxuh, vmaxuw
19851 case 0x102: case 0x142: case 0x182: // vmaxsb, vmaxsh, vmaxsw
19852 case 0x202: case 0x242: case 0x282: // vminub, vminuh, vminuw
19853 case 0x302: case 0x342: case 0x382: // vminsb, vminsh, vminsw
19854 case 0x008: case 0x048: // vmuloub, vmulouh
19855 case 0x108: case 0x148: // vmulosb, vmulosh
19856 case 0x208: case 0x248: // vmuleub, vmuleuh
19857 case 0x308: case 0x348: // vmulesb, vmulesh
19858 case 0x608: case 0x708: case 0x648: // vsum4ubs, vsum4sbs, vsum4shs
19859 case 0x688: case 0x788: // vsum2sws, vsumsws
sewardj5117ce12006-01-27 21:20:15 +000019860 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019861 if (dis_av_arith( theInstr )) goto decode_success;
19862 goto decode_failure;
19863
carll48ae46b2013-10-01 15:45:54 +000019864 case 0x088: case 0x089: // vmulouw, vmuluwm
19865 case 0x0C0: case 0x0C2: // vaddudm, vmaxud
19866 case 0x1C2: case 0x2C2: case 0x3C2: // vnaxsd, vminud, vminsd
19867 case 0x188: case 0x288: case 0x388: // vmulosw, vmuleuw, vmulesw
19868 case 0x4C0: // vsubudm
carll0c74bb52013-08-12 18:01:40 +000019869 if (!allow_isa_2_07) goto decode_noP8;
19870 if (dis_av_arith( theInstr )) goto decode_success;
19871 goto decode_failure;
19872
carll7deaf952013-10-15 18:11:20 +000019873 /* AV Polynomial Vector Multiply Add */
19874 case 0x408: case 0x448: // vpmsumb, vpmsumd
19875 case 0x488: case 0x4C8: // vpmsumw, vpmsumh
19876 if (!allow_isa_2_07) goto decode_noP8;
19877 if (dis_av_polymultarith( theInstr )) goto decode_success;
19878 goto decode_failure;
19879
cerion32aad402005-09-10 12:02:24 +000019880 /* AV Rotate, Shift */
19881 case 0x004: case 0x044: case 0x084: // vrlb, vrlh, vrlw
19882 case 0x104: case 0x144: case 0x184: // vslb, vslh, vslw
19883 case 0x204: case 0x244: case 0x284: // vsrb, vsrh, vsrw
19884 case 0x304: case 0x344: case 0x384: // vsrab, vsrah, vsraw
19885 case 0x1C4: case 0x2C4: // vsl, vsr
19886 case 0x40C: case 0x44C: // vslo, vsro
sewardj5117ce12006-01-27 21:20:15 +000019887 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019888 if (dis_av_shift( theInstr )) goto decode_success;
19889 goto decode_failure;
19890
carll48ae46b2013-10-01 15:45:54 +000019891 case 0x0C4: // vrld
19892 case 0x3C4: case 0x5C4: case 0x6C4: // vsrad, vsld, vsrd
19893 if (!allow_isa_2_07) goto decode_noP8;
19894 if (dis_av_shift( theInstr )) goto decode_success;
19895 goto decode_failure;
19896
cerion32aad402005-09-10 12:02:24 +000019897 /* AV Logic */
19898 case 0x404: case 0x444: case 0x484: // vand, vandc, vor
19899 case 0x4C4: case 0x504: // vxor, vnor
sewardj5117ce12006-01-27 21:20:15 +000019900 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019901 if (dis_av_logic( theInstr )) goto decode_success;
19902 goto decode_failure;
19903
carll7deaf952013-10-15 18:11:20 +000019904 case 0x544: // vorc
19905 case 0x584: case 0x684: // vnand, veqv
19906 if (!allow_isa_2_07) goto decode_noP8;
19907 if (dis_av_logic( theInstr )) goto decode_success;
19908 goto decode_failure;
19909
cerion32aad402005-09-10 12:02:24 +000019910 /* AV Processor Control */
19911 case 0x604: case 0x644: // mfvscr, mtvscr
sewardj5117ce12006-01-27 21:20:15 +000019912 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019913 if (dis_av_procctl( theInstr )) goto decode_success;
19914 goto decode_failure;
19915
19916 /* AV Floating Point Arithmetic */
19917 case 0x00A: case 0x04A: // vaddfp, vsubfp
19918 case 0x10A: case 0x14A: case 0x18A: // vrefp, vrsqrtefp, vexptefp
19919 case 0x1CA: // vlogefp
19920 case 0x40A: case 0x44A: // vmaxfp, vminfp
sewardj5117ce12006-01-27 21:20:15 +000019921 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019922 if (dis_av_fp_arith( theInstr )) goto decode_success;
19923 goto decode_failure;
19924
19925 /* AV Floating Point Round/Convert */
19926 case 0x20A: case 0x24A: case 0x28A: // vrfin, vrfiz, vrfip
19927 case 0x2CA: // vrfim
19928 case 0x30A: case 0x34A: case 0x38A: // vcfux, vcfsx, vctuxs
19929 case 0x3CA: // vctsxs
sewardj5117ce12006-01-27 21:20:15 +000019930 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019931 if (dis_av_fp_convert( theInstr )) goto decode_success;
19932 goto decode_failure;
19933
19934 /* AV Merge, Splat */
19935 case 0x00C: case 0x04C: case 0x08C: // vmrghb, vmrghh, vmrghw
19936 case 0x10C: case 0x14C: case 0x18C: // vmrglb, vmrglh, vmrglw
19937 case 0x20C: case 0x24C: case 0x28C: // vspltb, vsplth, vspltw
19938 case 0x30C: case 0x34C: case 0x38C: // vspltisb, vspltish, vspltisw
sewardj5117ce12006-01-27 21:20:15 +000019939 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019940 if (dis_av_permute( theInstr )) goto decode_success;
19941 goto decode_failure;
19942
carll48ae46b2013-10-01 15:45:54 +000019943 case 0x68C: case 0x78C: // vmrgow, vmrgew
19944 if (!allow_isa_2_07) goto decode_noP8;
19945 if (dis_av_permute( theInstr )) goto decode_success;
19946 goto decode_failure;
19947
cerion32aad402005-09-10 12:02:24 +000019948 /* AV Pack, Unpack */
19949 case 0x00E: case 0x04E: case 0x08E: // vpkuhum, vpkuwum, vpkuhus
19950 case 0x0CE: // vpkuwus
19951 case 0x10E: case 0x14E: case 0x18E: // vpkshus, vpkswus, vpkshss
19952 case 0x1CE: // vpkswss
19953 case 0x20E: case 0x24E: case 0x28E: // vupkhsb, vupkhsh, vupklsb
19954 case 0x2CE: // vupklsh
19955 case 0x30E: case 0x34E: case 0x3CE: // vpkpx, vupkhpx, vupklpx
carll48ae46b2013-10-01 15:45:54 +000019956 if (!allow_V) goto decode_noV;
19957 if (dis_av_pack( theInstr )) goto decode_success;
19958 goto decode_failure;
cerion32aad402005-09-10 12:02:24 +000019959
carll48ae46b2013-10-01 15:45:54 +000019960 case 0x44E: case 0x4CE: case 0x54E: // vpkudum, vpkudus, vpksdus
19961 case 0x5CE: case 0x64E: case 0x6cE: // vpksdss, vupkhsw, vupklsw
carll0c74bb52013-08-12 18:01:40 +000019962 if (!allow_isa_2_07) goto decode_noP8;
19963 if (dis_av_pack( theInstr )) goto decode_success;
19964 goto decode_failure;
19965
carll7deaf952013-10-15 18:11:20 +000019966 case 0x508: case 0x509: // vcipher, vcipherlast
19967 case 0x548: case 0x549: // vncipher, vncipherlast
19968 case 0x5C8: // vsbox
19969 if (!allow_isa_2_07) goto decode_noP8;
19970 if (dis_av_cipher( theInstr )) goto decode_success;
19971 goto decode_failure;
19972
19973 case 0x6C2: case 0x682: // vshasigmaw, vshasigmad
19974 if (!allow_isa_2_07) goto decode_noP8;
19975 if (dis_av_hash( theInstr )) goto decode_success;
19976 goto decode_failure;
19977
19978 case 0x702: case 0x742: // vclzb, vclzh
19979 case 0x782: case 0x7c2: // vclzw, vclzd
19980 if (!allow_isa_2_07) goto decode_noP8;
carll60c6bac2013-10-18 01:19:06 +000019981 if (dis_av_count_bitTranspose( theInstr, opc2 )) goto decode_success;
carll7deaf952013-10-15 18:11:20 +000019982 goto decode_failure;
19983
19984 case 0x703: case 0x743: // vpopcntb, vpopcnth
19985 case 0x783: case 0x7c3: // vpopcntw, vpopcntd
19986 if (!allow_isa_2_07) goto decode_noP8;
carll60c6bac2013-10-18 01:19:06 +000019987 if (dis_av_count_bitTranspose( theInstr, opc2 )) goto decode_success;
19988 goto decode_failure;
19989
19990 case 0x50c: // vgbbd
19991 if (!allow_isa_2_07) goto decode_noP8;
19992 if (dis_av_count_bitTranspose( theInstr, opc2 )) goto decode_success;
19993 goto decode_failure;
19994
19995 case 0x140: case 0x100: // vaddcuq, vadduqm
19996 case 0x540: case 0x500: // vsubcuq, vsubuqm
19997 case 0x54C: // vbpermq
19998 if (!allow_V) goto decode_noV;
19999 if (dis_av_quad( theInstr)) goto decode_success;
carll7deaf952013-10-15 18:11:20 +000020000 goto decode_failure;
20001
cerion32aad402005-09-10 12:02:24 +000020002 default:
20003 break; // Fall through...
20004 }
20005
cerion76de5cf2005-11-18 18:25:12 +000020006 opc2 = IFIELD(theInstr, 0, 10);
cerion32aad402005-09-10 12:02:24 +000020007 switch (opc2) {
20008
20009 /* AV Compare */
20010 case 0x006: case 0x046: case 0x086: // vcmpequb, vcmpequh, vcmpequw
20011 case 0x206: case 0x246: case 0x286: // vcmpgtub, vcmpgtuh, vcmpgtuw
20012 case 0x306: case 0x346: case 0x386: // vcmpgtsb, vcmpgtsh, vcmpgtsw
sewardj5117ce12006-01-27 21:20:15 +000020013 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000020014 if (dis_av_cmp( theInstr )) goto decode_success;
20015 goto decode_failure;
20016
carll48ae46b2013-10-01 15:45:54 +000020017 case 0x0C7: // vcmpequd
20018 case 0x2C7: // vcmpgtud
20019 case 0x3C7: // vcmpgtsd
20020 if (!allow_isa_2_07) goto decode_noP8;
20021 if (dis_av_cmp( theInstr )) goto decode_success;
20022 goto decode_failure;
20023
cerion32aad402005-09-10 12:02:24 +000020024 /* AV Floating Point Compare */
20025 case 0x0C6: case 0x1C6: case 0x2C6: // vcmpeqfp, vcmpgefp, vcmpgtfp
20026 case 0x3C6: // vcmpbfp
sewardj5117ce12006-01-27 21:20:15 +000020027 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000020028 if (dis_av_fp_cmp( theInstr )) goto decode_success;
20029 goto decode_failure;
20030
20031 default:
20032 goto decode_failure;
20033 }
20034 break;
cerion7aa4bbc2005-01-29 09:32:07 +000020035
cerion896a1372005-01-25 12:24:25 +000020036 default:
cerion5b2325f2005-12-23 00:55:09 +000020037 goto decode_failure;
20038
sewardj5117ce12006-01-27 21:20:15 +000020039 decode_noF:
20040 vassert(!allow_F);
20041 vex_printf("disInstr(ppc): declined to decode an FP insn.\n");
20042 goto decode_failure;
20043 decode_noV:
20044 vassert(!allow_V);
20045 vex_printf("disInstr(ppc): declined to decode an AltiVec insn.\n");
20046 goto decode_failure;
sewardj66d5ef22011-04-15 11:55:00 +000020047 decode_noVX:
20048 vassert(!allow_VX);
sewardj4aa412a2011-07-24 14:13:21 +000020049 vex_printf("disInstr(ppc): declined to decode a Power ISA 2.06 insn.\n");
sewardj66d5ef22011-04-15 11:55:00 +000020050 goto decode_failure;
sewardj5117ce12006-01-27 21:20:15 +000020051 decode_noFX:
sewardj7c545862006-01-27 21:52:19 +000020052 vassert(!allow_FX);
sewardj5117ce12006-01-27 21:20:15 +000020053 vex_printf("disInstr(ppc): "
sewardjb183b852006-02-03 16:08:03 +000020054 "declined to decode a GeneralPurpose-Optional insn.\n");
sewardj5117ce12006-01-27 21:20:15 +000020055 goto decode_failure;
20056 decode_noGX:
sewardj7c545862006-01-27 21:52:19 +000020057 vassert(!allow_GX);
sewardj5117ce12006-01-27 21:20:15 +000020058 vex_printf("disInstr(ppc): "
20059 "declined to decode a Graphics-Optional insn.\n");
cerion5b2325f2005-12-23 00:55:09 +000020060 goto decode_failure;
sewardjc66d6fa2012-04-02 21:24:12 +000020061 decode_noDFP:
20062 vassert(!allow_DFP);
20063 vex_printf("disInstr(ppc): "
20064 "declined to decode a Decimal Floating Point insn.\n");
20065 goto decode_failure;
carll0c74bb52013-08-12 18:01:40 +000020066 decode_noP8:
20067 vassert(!allow_isa_2_07);
20068 vex_printf("disInstr(ppc): "
20069 "declined to decode a Power 8 insn.\n");
20070 goto decode_failure;
sewardjc66d6fa2012-04-02 21:24:12 +000020071
cerion5b2325f2005-12-23 00:55:09 +000020072
cerion896a1372005-01-25 12:24:25 +000020073 decode_failure:
20074 /* All decode failures end up here. */
cerion225a0342005-09-12 20:49:09 +000020075 opc2 = (theInstr) & 0x7FF;
sewardj442e51a2012-12-06 18:08:04 +000020076 if (sigill_diag) {
20077 vex_printf("disInstr(ppc): unhandled instruction: "
20078 "0x%x\n", theInstr);
20079 vex_printf(" primary %d(0x%x), secondary %u(0x%x)\n",
20080 opc1, opc1, opc2, opc2);
20081 }
cerion995bc362005-02-03 11:03:31 +000020082
sewardj01a9e802005-02-01 20:46:00 +000020083 /* Tell the dispatcher that this insn cannot be decoded, and so has
20084 not been executed, and (is currently) the next to be executed.
20085 CIA should be up-to-date since it made so at the start of each
20086 insn, but nevertheless be paranoid and update it again right
20087 now. */
cerion2831b002005-11-30 19:55:22 +000020088 putGST( PPC_GST_CIA, mkSzImm(ty, guest_CIA_curr_instr) );
sewardj3dee8492012-04-20 00:13:28 +000020089 dres.whatNext = Dis_StopHere;
20090 dres.jk_StopHere = Ijk_NoDecode;
20091 dres.len = 0;
sewardj9e6491a2005-07-02 19:24:10 +000020092 return dres;
cerion896a1372005-01-25 12:24:25 +000020093
20094 } /* switch (opc) for the main (primary) opcode switch. */
20095
20096 decode_success:
20097 /* All decode successes end up here. */
sewardj3dee8492012-04-20 00:13:28 +000020098 switch (dres.whatNext) {
20099 case Dis_Continue:
20100 putGST( PPC_GST_CIA, mkSzImm(ty, guest_CIA_curr_instr + 4));
20101 break;
20102 case Dis_ResteerU:
20103 case Dis_ResteerC:
20104 putGST( PPC_GST_CIA, mkSzImm(ty, dres.continueAt));
20105 break;
20106 case Dis_StopHere:
20107 break;
20108 default:
20109 vassert(0);
20110 }
cerion896a1372005-01-25 12:24:25 +000020111 DIP("\n");
20112
sewardjce02aa72006-01-12 12:27:58 +000020113 if (dres.len == 0) {
20114 dres.len = 4;
20115 } else {
20116 vassert(dres.len == 20);
20117 }
sewardj9e6491a2005-07-02 19:24:10 +000020118 return dres;
cerion896a1372005-01-25 12:24:25 +000020119}
20120
20121#undef DIP
20122#undef DIS
20123
sewardj9e6491a2005-07-02 19:24:10 +000020124
20125/*------------------------------------------------------------*/
20126/*--- Top-level fn ---*/
20127/*------------------------------------------------------------*/
20128
20129/* Disassemble a single instruction into IR. The instruction
20130 is located in host memory at &guest_code[delta]. */
20131
sewardjdd40fdf2006-12-24 02:20:24 +000020132DisResult disInstr_PPC ( IRSB* irsb_IN,
sewardjc716aea2006-01-17 01:48:46 +000020133 Bool (*resteerOkFn) ( void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +000020134 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +000020135 void* callback_opaque,
cerion5b2325f2005-12-23 00:55:09 +000020136 UChar* guest_code_IN,
20137 Long delta,
20138 Addr64 guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000020139 VexArch guest_arch,
cerion5b2325f2005-12-23 00:55:09 +000020140 VexArchInfo* archinfo,
sewardjdd40fdf2006-12-24 02:20:24 +000020141 VexAbiInfo* abiinfo,
sewardj9b769162014-07-24 12:42:03 +000020142 VexEndness host_endness_IN,
sewardj442e51a2012-12-06 18:08:04 +000020143 Bool sigill_diag_IN )
sewardj9e6491a2005-07-02 19:24:10 +000020144{
sewardj5df65bb2005-11-29 14:47:04 +000020145 IRType ty;
20146 DisResult dres;
sewardj5117ce12006-01-27 21:20:15 +000020147 UInt mask32, mask64;
20148 UInt hwcaps_guest = archinfo->hwcaps;
20149
sewardja5f55da2006-04-30 23:37:32 +000020150 vassert(guest_arch == VexArchPPC32 || guest_arch == VexArchPPC64);
sewardj5df65bb2005-11-29 14:47:04 +000020151
sewardja5f55da2006-04-30 23:37:32 +000020152 /* global -- ick */
20153 mode64 = guest_arch == VexArchPPC64;
20154 ty = mode64 ? Ity_I64 : Ity_I32;
carll1f5fe1f2014-08-07 23:25:23 +000020155 if (!mode64 && (host_endness_IN == VexEndnessLE)) {
20156 vex_printf("disInstr(ppc): Little Endian 32-bit mode is not supported\n");
20157 dres.whatNext = Dis_StopHere;
20158 dres.jk_StopHere = Ijk_NoDecode;
20159 dres.len = 0;
20160 return dres;
20161 }
sewardja5f55da2006-04-30 23:37:32 +000020162
20163 /* do some sanity checks */
sewardj5117ce12006-01-27 21:20:15 +000020164 mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
sewardjc66d6fa2012-04-02 21:24:12 +000020165 | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX
carll0c74bb52013-08-12 18:01:40 +000020166 | VEX_HWCAPS_PPC32_DFP | VEX_HWCAPS_PPC32_ISA2_07;
sewardj5117ce12006-01-27 21:20:15 +000020167
sewardj66d5ef22011-04-15 11:55:00 +000020168 mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
carll0c74bb52013-08-12 18:01:40 +000020169 | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP
20170 | VEX_HWCAPS_PPC64_ISA2_07;
sewardj5117ce12006-01-27 21:20:15 +000020171
sewardja5f55da2006-04-30 23:37:32 +000020172 if (mode64) {
20173 vassert((hwcaps_guest & mask32) == 0);
20174 } else {
20175 vassert((hwcaps_guest & mask64) == 0);
20176 }
sewardj9e6491a2005-07-02 19:24:10 +000020177
20178 /* Set globals (see top of this file) */
20179 guest_code = guest_code_IN;
sewardjdd40fdf2006-12-24 02:20:24 +000020180 irsb = irsb_IN;
sewardj9b769162014-07-24 12:42:03 +000020181 host_endness = host_endness_IN;
ceriond953ebb2005-11-29 13:27:20 +000020182
cerion2831b002005-11-30 19:55:22 +000020183 guest_CIA_curr_instr = mkSzAddr(ty, guest_IP);
20184 guest_CIA_bbstart = mkSzAddr(ty, guest_IP - delta);
sewardj9e6491a2005-07-02 19:24:10 +000020185
sewardj3dee8492012-04-20 00:13:28 +000020186 dres = disInstr_PPC_WRK ( resteerOkFn, resteerCisOk, callback_opaque,
carll1f5fe1f2014-08-07 23:25:23 +000020187 delta, archinfo, abiinfo, sigill_diag_IN);
sewardj9e6491a2005-07-02 19:24:10 +000020188
20189 return dres;
20190}
20191
20192
sewardjc808ef72005-08-18 11:50:43 +000020193/*------------------------------------------------------------*/
20194/*--- Unused stuff ---*/
20195/*------------------------------------------------------------*/
20196
20197///* A potentially more memcheck-friendly implementation of Clz32, with
20198// the boundary case Clz32(0) = 32, which is what ppc requires. */
20199//
20200//static IRExpr* /* :: Ity_I32 */ verbose_Clz32 ( IRTemp arg )
20201//{
20202// /* Welcome ... to SSA R Us. */
20203// IRTemp n1 = newTemp(Ity_I32);
20204// IRTemp n2 = newTemp(Ity_I32);
20205// IRTemp n3 = newTemp(Ity_I32);
20206// IRTemp n4 = newTemp(Ity_I32);
20207// IRTemp n5 = newTemp(Ity_I32);
20208// IRTemp n6 = newTemp(Ity_I32);
20209// IRTemp n7 = newTemp(Ity_I32);
20210// IRTemp n8 = newTemp(Ity_I32);
20211// IRTemp n9 = newTemp(Ity_I32);
20212// IRTemp n10 = newTemp(Ity_I32);
20213// IRTemp n11 = newTemp(Ity_I32);
20214// IRTemp n12 = newTemp(Ity_I32);
20215//
20216// /* First, propagate the most significant 1-bit into all lower
20217// positions in the word. */
20218// /* unsigned int clz ( unsigned int n )
20219// {
20220// n |= (n >> 1);
20221// n |= (n >> 2);
20222// n |= (n >> 4);
20223// n |= (n >> 8);
20224// n |= (n >> 16);
20225// return bitcount(~n);
20226// }
20227// */
20228// assign(n1, mkexpr(arg));
20229// assign(n2, binop(Iop_Or32, mkexpr(n1), binop(Iop_Shr32, mkexpr(n1), mkU8(1))));
20230// assign(n3, binop(Iop_Or32, mkexpr(n2), binop(Iop_Shr32, mkexpr(n2), mkU8(2))));
20231// assign(n4, binop(Iop_Or32, mkexpr(n3), binop(Iop_Shr32, mkexpr(n3), mkU8(4))));
20232// assign(n5, binop(Iop_Or32, mkexpr(n4), binop(Iop_Shr32, mkexpr(n4), mkU8(8))));
20233// assign(n6, binop(Iop_Or32, mkexpr(n5), binop(Iop_Shr32, mkexpr(n5), mkU8(16))));
20234// /* This gives a word of the form 0---01---1. Now invert it, giving
20235// a word of the form 1---10---0, then do a population-count idiom
20236// (to count the 1s, which is the number of leading zeroes, or 32
20237// if the original word was 0. */
20238// assign(n7, unop(Iop_Not32, mkexpr(n6)));
20239//
20240// /* unsigned int bitcount ( unsigned int n )
20241// {
20242// n = n - ((n >> 1) & 0x55555555);
20243// n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
20244// n = (n + (n >> 4)) & 0x0F0F0F0F;
20245// n = n + (n >> 8);
20246// n = (n + (n >> 16)) & 0x3F;
20247// return n;
20248// }
20249// */
20250// assign(n8,
20251// binop(Iop_Sub32,
20252// mkexpr(n7),
20253// binop(Iop_And32,
20254// binop(Iop_Shr32, mkexpr(n7), mkU8(1)),
20255// mkU32(0x55555555))));
20256// assign(n9,
20257// binop(Iop_Add32,
20258// binop(Iop_And32, mkexpr(n8), mkU32(0x33333333)),
20259// binop(Iop_And32,
20260// binop(Iop_Shr32, mkexpr(n8), mkU8(2)),
20261// mkU32(0x33333333))));
20262// assign(n10,
20263// binop(Iop_And32,
20264// binop(Iop_Add32,
20265// mkexpr(n9),
20266// binop(Iop_Shr32, mkexpr(n9), mkU8(4))),
20267// mkU32(0x0F0F0F0F)));
20268// assign(n11,
20269// binop(Iop_Add32,
20270// mkexpr(n10),
20271// binop(Iop_Shr32, mkexpr(n10), mkU8(8))));
20272// assign(n12,
20273// binop(Iop_Add32,
20274// mkexpr(n11),
20275// binop(Iop_Shr32, mkexpr(n11), mkU8(16))));
20276// return
20277// binop(Iop_And32, mkexpr(n12), mkU32(0x3F));
20278//}
20279
cerion896a1372005-01-25 12:24:25 +000020280/*--------------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +000020281/*--- end guest_ppc_toIR.c ---*/
cerion896a1372005-01-25 12:24:25 +000020282/*--------------------------------------------------------------------*/