Initial implementation of C-source-level &&-idiom recovery
[valgrind.git] / VEX / priv / guest_ppc_toIR.c
blob6e3fac74f824c6ad343997a4f65d3d6487cacbc4
2 /*--------------------------------------------------------------------*/
3 /*--- begin guest_ppc_toIR.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2004-2017 OpenWorks LLP
11 info@open-works.net
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, see <http://www.gnu.org/licenses/>.
26 The GNU General Public License is contained in the file COPYING.
28 Neither the names of the U.S. Department of Energy nor the
29 University of California nor the names of its contributors may be
30 used to endorse or promote products derived from this software
31 without prior written permission.
34 /* TODO 18/Nov/05:
36 Spot rld... cases which are simply left/right shifts and emit
37 Shl64/Shr64 accordingly.
39 Altivec
40 - datastream insns
41 - lvxl,stvxl: load/store with 'least recently used' hint
42 - vexptefp, vlogefp
44 LIMITATIONS:
46 Various, including:
48 - Some invalid forms of lswi and lswx are accepted when they should
49 not be.
51 - Floating Point:
52 - All exceptions disabled in FPSCR
53 - condition codes not set in FPSCR
55 - Altivec floating point:
56 - vmaddfp, vnmsubfp
57 Because we're using Java/IEEE mode (FPSCR[NJ]), rather than the
58 system default of Non-Java mode, we get some small errors
59 (lowest bit only).
60 This is because Non-Java mode brutally hacks denormalised results
61 to zero, whereas we keep maximum accuracy. However, using
62 Non-Java mode would give us more inaccuracy, as our intermediate
63 results would then be zeroed, too.
65 - AbiHints for the stack red zone are only emitted for
66 unconditional calls and returns (bl, blr). They should also be
67 emitted for conditional calls and returns, but we don't have a
68 way to express that right now. Ah well.
70 - Uses of Iop_{Add,Sub,Mul}32Fx4: the backend (host_ppc_isel.c)
71 ignores the rounding mode, and generates code that assumes
72 round-to-nearest. This means V will compute incorrect results
73 for uses of these IROps when the rounding mode (first) arg is
74 not mkU32(Irrm_NEAREST).
77 /* "Special" instructions.
79 This instruction decoder can decode four special instructions
80 which mean nothing natively (are no-ops as far as regs/mem are
81 concerned) but have meaning for supporting Valgrind. A special
82 instruction is flagged by a 16-byte preamble:
84 32-bit mode: 5400183E 5400683E 5400E83E 5400983E
85 (rlwinm 0,0,3,0,31; rlwinm 0,0,13,0,31;
86 rlwinm 0,0,29,0,31; rlwinm 0,0,19,0,31)
88 64-bit mode: 78001800 78006800 7800E802 78009802
89 (rotldi 0,0,3; rotldi 0,0,13;
90 rotldi 0,0,61; rotldi 0,0,51)
92 Following that, one of the following 3 are allowed
93 (standard interpretation in parentheses):
95 7C210B78 (or 1,1,1) %R3 = client_request ( %R4 )
96 7C421378 (or 2,2,2) %R3 = guest_NRADDR
97 7C631B78 (or 3,3,3) branch-and-link-to-noredir %R11 Big endian
98 7C631B78 (or 3,3,3) branch-and-link-to-noredir %R12 Little endian
99 7C842378 (or 4,4,4) %R3 = guest_NRADDR_GPR2
100 7CA52B78 (or 5,5,5) IR injection
102 Any other bytes following the 16-byte preamble are illegal and
103 constitute a failure in instruction decoding. This all assumes
104 that the preamble will never occur except in specific code
105 fragments designed for Valgrind to catch.
108 /* Little Endian notes */
110 * Vector operations in little Endian mode behave in non-obvious ways at times.
111 * Below is an attempt at explaining this.
113 * LE/BE vector example
114 * With a vector of unsigned ints declared as follows:
115 * vector unsigned int vec_inA =
116 { 0x11111111, 0x22222222, 0x33333333, 0x44444444 };
117 * The '0x11111111' word is word zero in both LE and BE format. But the
118 * loaded vector register will have word zero on the far left in BE mode and
119 * on the far right in LE mode. The lvx and stvx instructions work naturally
120 * for whatever endianness is in effect. For example, in LE mode, the stvx
121 * stores word zero (far right word) of the vector at the lowest memory
122 * address of the EA; in BE mode, stvx still stores word zero at the lowest
123 * memory address, but with word zero interpreted as the one at the far left
124 * of the register.
126 * The lxvd2x and stxvd2x instructions are not so well suited for LE mode.
127 * When the compiler generates an lxvd2x instruction to load the
128 * above-declared vector of unsigned integers, it loads the vector as two
129 * double words, but they are in BE word-wise format. To put the vector in
130 * the right order for LE, the compiler also generates an xxswapd after the
131 * load, which puts it in proper LE format. Similarly, the stxvd2x
132 * instruction has a BE bias, storing the vector in BE word-wise format. But
133 * the compiler also generates an xxswapd prior to the store, thus ensuring
134 * the vector is stored in memory in the correct LE order.
136 * Vector-flavored Iops, such Iop_V128Hito64, reference the hi and lo parts
137 * of a double words and words within a vector. Because of the reverse order
138 * of numbering for LE as described above, the high part refers to word 1 in
139 * LE format. When input data is saved to a guest state vector register
140 * (e.g., via Iop_64HLtoV128), it is first saved to memory and then the
141 * register is loaded via PPCInstr_AvLdSt, which does an lvx instruction.
142 * The saving of the data to memory must be done in proper LE order. For the
143 * inverse operation of extracting data from a vector register (e.g.,
144 * Iop_V128Hito64), the register is first saved (by PPCInstr_AvLdSt resulting
145 * in stvx), and then integer registers are loaded from the memory location
146 * from where the vector register was saved. Again, this must be done in
147 * proper LE order. So for these various vector Iops, we have LE-specific
148 * code in host_ppc_isel.c
150 * Another unique behavior of vectors in LE mode is with the vector scalar
151 * (VSX) operations that operate on "double word 0" of the source register,
152 * storing the result in "double word 0" of the output vector register. For
153 * these operations, "double word 0" is interpreted as "high half of the
154 * register" (i.e, the part on the left side).
158 /* Notes on handling subnormal results:
160 * The various vector floating point instructions:
161 * vmaddfp, vaddfp, vsubfp, vmaxfp, vminfp, vrefp, vexptefp,
162 * vlogefp, vcmpeqfp, vcmpgefp, vcmpgtfp, vcmpbfp, vrfin, vrfiz,
163 * vrfip, vrfim
164 * generate subnormal results that are controled by the VSCR[NJ] bit setting.
166 * The following describes how the host and guest is setup so that the function
167 * dnorm_adj_Vector() can properly handle the results of the Iops in the guest
168 * state.
170 * At startup, on all host variants, we set VSCR[NJ].host = 0 (don't flush to
171 * zero). It stays at 0 permanently.
173 * At startup, we set VSCR[NJ].guest = (if BE then 1 else 0)
175 * When running, guest insns can set/clear/query VSCR[NJ].guest as they
176 * like.
178 * When running, any (guest) insn whose result depends on VSCR[NJ] will query
179 * VSCR[NJ].guest and the results will be truncated accordingly, by
180 * dnorm_adj_Vector(). Because VSCR[NJ].host is always 0, we will always
181 * be able to provide correct guest results for either value of
182 * VSCR[NJ].guest.
186 /* Translates PPC32/64 code to IR. */
188 /* References
190 #define PPC32
191 "PowerPC Microprocessor Family:
192 The Programming Environments Manual for 32-Bit Microprocessors"
193 02/21/2000
194 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF778525699600719DF2
196 #define PPC64
197 "PowerPC Microprocessor Family:
198 Programming Environments Manual for 64-Bit Microprocessors"
199 06/10/2003
200 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/F7E732FF811F783187256FDD004D3797
202 #define AV
203 "PowerPC Microprocessor Family:
204 AltiVec(TM) Technology Programming Environments Manual"
205 07/10/2003
206 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/FBFA164F824370F987256D6A006F424D
209 #include "libvex_basictypes.h"
210 #include "libvex_ir.h"
211 #include "libvex.h"
212 #include "libvex_emnote.h"
213 #include "libvex_guest_ppc32.h"
214 #include "libvex_guest_ppc64.h"
216 #include "main_util.h"
217 #include "main_globals.h"
218 #include "guest_generic_bb_to_IR.h"
219 #include "guest_ppc_defs.h"
221 /*------------------------------------------------------------*/
222 /*--- Globals ---*/
223 /*------------------------------------------------------------*/
225 /* These are set at the start of the translation of an insn, right
226 down in disInstr_PPC, so that we don't have to pass them around
227 endlessly. They are all constant during the translation of any
228 given insn. */
230 /* We need to know this to do sub-register accesses correctly. */
231 static VexEndness host_endness;
233 /* Pointer to the guest code area. */
234 static const UChar* guest_code;
236 /* The guest address corresponding to guest_code[0]. */
237 static Addr64 guest_CIA_bbstart;
239 /* The guest address for the instruction currently being
240 translated. */
241 static Addr64 guest_CIA_curr_instr;
243 /* The IRSB* into which we're generating code. */
244 static IRSB* irsb;
246 /* Is our guest binary 32 or 64bit? Set at each call to
247 disInstr_PPC below. */
248 static Bool mode64 = False;
250 // Given a pointer to a function as obtained by "& functionname" in C,
251 // produce a pointer to the actual entry point for the function. For
252 // most platforms it's the identity function. Unfortunately, on
253 // ppc64-linux it isn't (sigh)
254 static void* fnptr_to_fnentry( const VexAbiInfo* vbi, void* f )
256 if (vbi->host_ppc_calls_use_fndescrs) {
257 /* f is a pointer to a 3-word function descriptor, of which the
258 first word is the entry address. */
259 /* note, this is correct even with cross-jitting, since this is
260 purely a host issue, not a guest one. */
261 HWord* fdescr = (HWord*)f;
262 return (void*)(fdescr[0]);
263 } else {
264 /* Simple; "& f" points directly at the code for f. */
265 return f;
269 /* The OV32 and CA32 bits were added with ISA3.0 */
270 static Bool OV32_CA32_supported = False;
272 #define SIGN_BIT 0x8000000000000000ULL
273 #define SIGN_MASK 0x7fffffffffffffffULL
274 #define SIGN_BIT32 0x80000000
275 #define SIGN_MASK32 0x7fffffff
278 /*------------------------------------------------------------*/
279 /*--- Debugging output ---*/
280 /*------------------------------------------------------------*/
282 #define DIP(format, args...) \
283 if (vex_traceflags & VEX_TRACE_FE) \
284 vex_printf(format, ## args)
286 #define DIS(buf, format, args...) \
287 if (vex_traceflags & VEX_TRACE_FE) \
288 vex_sprintf(buf, format, ## args)
291 /*------------------------------------------------------------*/
292 /*--- Offsets of various parts of the ppc32/64 guest state ---*/
293 /*------------------------------------------------------------*/
295 #define offsetofPPCGuestState(_x) \
296 (mode64 ? offsetof(VexGuestPPC64State, _x) : \
297 offsetof(VexGuestPPC32State, _x))
299 #define OFFB_CIA offsetofPPCGuestState(guest_CIA)
300 #define OFFB_IP_AT_SYSCALL offsetofPPCGuestState(guest_IP_AT_SYSCALL)
301 #define OFFB_SPRG3_RO offsetofPPCGuestState(guest_SPRG3_RO)
302 #define OFFB_LR offsetofPPCGuestState(guest_LR)
303 #define OFFB_CTR offsetofPPCGuestState(guest_CTR)
304 #define OFFB_XER_SO offsetofPPCGuestState(guest_XER_SO)
305 #define OFFB_XER_OV offsetofPPCGuestState(guest_XER_OV)
306 #define OFFB_XER_OV32 offsetofPPCGuestState(guest_XER_OV32)
307 #define OFFB_XER_CA offsetofPPCGuestState(guest_XER_CA)
308 #define OFFB_XER_CA32 offsetofPPCGuestState(guest_XER_CA32)
309 #define OFFB_XER_BC offsetofPPCGuestState(guest_XER_BC)
310 #define OFFB_FPROUND offsetofPPCGuestState(guest_FPROUND)
311 #define OFFB_DFPROUND offsetofPPCGuestState(guest_DFPROUND)
312 #define OFFB_C_FPCC offsetofPPCGuestState(guest_C_FPCC)
313 #define OFFB_VRSAVE offsetofPPCGuestState(guest_VRSAVE)
314 #define OFFB_VSCR offsetofPPCGuestState(guest_VSCR)
315 #define OFFB_EMNOTE offsetofPPCGuestState(guest_EMNOTE)
316 #define OFFB_CMSTART offsetofPPCGuestState(guest_CMSTART)
317 #define OFFB_CMLEN offsetofPPCGuestState(guest_CMLEN)
318 #define OFFB_NRADDR offsetofPPCGuestState(guest_NRADDR)
319 #define OFFB_NRADDR_GPR2 offsetofPPCGuestState(guest_NRADDR_GPR2)
320 #define OFFB_TFHAR offsetofPPCGuestState(guest_TFHAR)
321 #define OFFB_TEXASR offsetofPPCGuestState(guest_TEXASR)
322 #define OFFB_TEXASRU offsetofPPCGuestState(guest_TEXASRU)
323 #define OFFB_TFIAR offsetofPPCGuestState(guest_TFIAR)
324 #define OFFB_PPR offsetofPPCGuestState(guest_PPR)
325 #define OFFB_PSPB offsetofPPCGuestState(guest_PSPB)
326 #define OFFB_DSCR offsetofPPCGuestState(guest_DSCR)
329 /*------------------------------------------------------------*/
330 /*--- Extract instruction fields --- */
331 /*------------------------------------------------------------*/
333 /* Extract field from insn, given idx (zero = lsb) and field length */
334 #define IFIELD( insn, idx, len ) ((insn >> idx) & ((1<<len)-1))
336 /* Extract primary opcode, instr[31:26] */
337 static UChar ifieldOPC( UInt instr ) {
338 return toUChar( IFIELD( instr, 26, 6 ) );
341 /* Extract 10-bit secondary opcode, instr[10:1] */
342 static UInt ifieldOPClo10 ( UInt instr) {
343 return IFIELD( instr, 1, 10 );
346 /* Extract 9-bit secondary opcode, instr[9:1] */
347 static UInt ifieldOPClo9 ( UInt instr) {
348 return IFIELD( instr, 1, 9 );
351 /* Extract 8-bit secondary opcode, instr[8:1] */
352 static UInt ifieldOPClo8 ( UInt instr) {
353 return IFIELD( instr, 1, 8 );
356 /* Extract 5-bit secondary opcode, instr[5:1] */
357 static UInt ifieldOPClo5 ( UInt instr) {
358 return IFIELD( instr, 1, 5 );
361 /* Extract 2-bit secondary opcode, instr[1:0] */
362 static UInt ifieldOPC0o2 ( UInt instr) {
363 return IFIELD( instr, 0, 2 );
366 /* Extract RD (destination register) field, instr[25:21] */
367 static UChar ifieldRegDS( UInt instr ) {
368 return toUChar( IFIELD( instr, 21, 5 ) );
371 /* Extract XT (destination register) field, instr[0,25:21] */
372 static UChar ifieldRegXT ( UInt instr )
374 UChar upper_bit = toUChar (IFIELD (instr, 0, 1));
375 UChar lower_bits = toUChar (IFIELD (instr, 21, 5));
376 return (upper_bit << 5) | lower_bits;
379 /* Extract XS (store source register) field, instr[0,25:21] */
380 static inline UChar ifieldRegXS ( UInt instr )
382 return ifieldRegXT ( instr );
385 /* Extract RA (1st source register) field, instr[20:16] */
386 static UChar ifieldRegA ( UInt instr ) {
387 return toUChar( IFIELD( instr, 16, 5 ) );
390 /* Extract XA (1st source register) field, instr[2,20:16] */
391 static UChar ifieldRegXA ( UInt instr )
393 UChar upper_bit = toUChar (IFIELD (instr, 2, 1));
394 UChar lower_bits = toUChar (IFIELD (instr, 16, 5));
395 return (upper_bit << 5) | lower_bits;
398 /* Extract RB (2nd source register) field, instr[15:11] */
399 static UChar ifieldRegB ( UInt instr ) {
400 return toUChar( IFIELD( instr, 11, 5 ) );
403 /* Extract XB (2nd source register) field, instr[1,15:11] */
404 static UChar ifieldRegXB ( UInt instr )
406 UChar upper_bit = toUChar (IFIELD (instr, 1, 1));
407 UChar lower_bits = toUChar (IFIELD (instr, 11, 5));
408 return (upper_bit << 5) | lower_bits;
411 /* Extract RC (3rd source register) field, instr[10:6] */
412 static UChar ifieldRegC ( UInt instr ) {
413 return toUChar( IFIELD( instr, 6, 5 ) );
416 /* Extract XC (3rd source register) field, instr[3,10:6] */
417 static UChar ifieldRegXC ( UInt instr )
419 UChar upper_bit = toUChar (IFIELD (instr, 3, 1));
420 UChar lower_bits = toUChar (IFIELD (instr, 6, 5));
421 return (upper_bit << 5) | lower_bits;
424 /* Extract bit 10, instr[10] */
425 static UChar ifieldBIT10 ( UInt instr ) {
426 return toUChar( IFIELD( instr, 10, 1 ) );
429 /* Extract 2nd lowest bit, instr[1] */
430 static UChar ifieldBIT1 ( UInt instr ) {
431 return toUChar( IFIELD( instr, 1, 1 ) );
434 /* Extract lowest bit, instr[0] */
435 static UChar ifieldBIT0 ( UInt instr ) {
436 return toUChar( instr & 0x1 );
439 /* Extract unsigned bottom half, instr[15:0] */
440 static UInt ifieldUIMM16 ( UInt instr ) {
441 return instr & 0xFFFF;
444 /* Extract unsigned bottom 26 bits, instr[25:0] */
445 static UInt ifieldUIMM26 ( UInt instr ) {
446 return instr & 0x3FFFFFF;
449 /* Extract DM field, instr[9:8] */
450 static UChar ifieldDM ( UInt instr ) {
451 return toUChar( IFIELD( instr, 8, 2 ) );
454 /* Extract SHW field, instr[9:8] */
455 static inline UChar ifieldSHW ( UInt instr )
457 return ifieldDM ( instr );
460 /*------------------------------------------------------------*/
461 /*--- Guest-state identifiers ---*/
462 /*------------------------------------------------------------*/
464 typedef enum {
465 PPC_GST_CIA, // Current Instruction Address
466 PPC_GST_LR, // Link Register
467 PPC_GST_CTR, // Count Register
468 PPC_GST_XER, // Overflow, carry flags, byte count
469 PPC_GST_CR, // Condition Register
470 PPC_GST_FPSCR, // Floating Point Status/Control Register
471 PPC_GST_VRSAVE, // Vector Save/Restore Register
472 PPC_GST_VSCR, // Vector Status and Control Register
473 PPC_GST_EMWARN, // Emulation warnings
474 PPC_GST_CMSTART,// For icbi: start of area to invalidate
475 PPC_GST_CMLEN, // For icbi: length of area to invalidate
476 PPC_GST_IP_AT_SYSCALL, // the CIA of the most recently executed SC insn
477 PPC_GST_SPRG3_RO, // SPRG3
478 PPC_GST_TFHAR, // Transactional Failure Handler Address Register
479 PPC_GST_TFIAR, // Transactional Failure Instruction Address Register
480 PPC_GST_TEXASR, // Transactional EXception And Summary Register
481 PPC_GST_TEXASRU, // Transactional EXception And Summary Register Upper
482 PPC_GST_PPR, // Program Priority register
483 PPC_GST_PPR32, // Upper 32-bits of Program Priority register
484 PPC_GST_PSPB, /* Problem State Priority Boost register, Note, the
485 * register is initialized to a non-zero value. Currently
486 * Valgrind is not supporting the register value to
487 * automatically decrement. Could be added later if
488 * needed.
490 PPC_GST_DSCR, // Data Stream Control Register
491 PPC_GST_MAX
492 } PPC_GST;
494 #define MASK_FPSCR_RN 0x3ULL // Binary floating point rounding mode
495 #define MASK_FPSCR_DRN 0x700000000ULL // Decimal floating point rounding mode
496 #define MASK_FPSCR_C_FPCC 0x1F000ULL // Floating-Point Condition code FPCC
498 #define MASK_VSCR_VALID 0x00010001
501 /*------------------------------------------------------------*/
502 /*--- Misc Helpers ---*/
503 /*------------------------------------------------------------*/
505 /* Generate mask with 1's from 'begin' through 'end',
506 wrapping if begin > end.
507 begin->end works from right to left, 0=lsb
509 static UInt MASK32( UInt begin, UInt end )
511 UInt m1, m2, mask;
512 vassert(begin < 32);
513 vassert(end < 32);
514 m1 = ((UInt)(-1)) << begin;
515 m2 = ((UInt)(-1)) << end << 1;
516 mask = m1 ^ m2;
517 if (begin > end) mask = ~mask; // wrap mask
518 return mask;
521 static ULong MASK64( UInt begin, UInt end )
523 ULong m1, m2, mask;
524 vassert(begin < 64);
525 vassert(end < 64);
526 m1 = ((ULong)(-1)) << begin;
527 m2 = ((ULong)(-1)) << end << 1;
528 mask = m1 ^ m2;
529 if (begin > end) mask = ~mask; // wrap mask
530 return mask;
533 static Addr64 nextInsnAddr( void )
535 return guest_CIA_curr_instr + 4;
539 /*------------------------------------------------------------*/
540 /*--- Helper bits and pieces for deconstructing the ---*/
541 /*--- ppc32/64 insn stream. ---*/
542 /*------------------------------------------------------------*/
544 /* Add a statement to the list held by "irsb". */
545 static void stmt ( IRStmt* st )
547 addStmtToIRSB( irsb, st );
550 /* Generate a new temporary of the given type. */
551 static IRTemp newTemp ( IRType ty )
553 vassert(isPlausibleIRType(ty));
554 return newIRTemp( irsb->tyenv, ty );
557 /* Various simple conversions */
559 static UChar extend_s_5to8 ( UChar x )
561 return toUChar((((Int)x) << 27) >> 27);
564 static UInt extend_s_8to32( UChar x )
566 return (UInt)((((Int)x) << 24) >> 24);
569 static UInt extend_s_16to32 ( UInt x )
571 return (UInt)((((Int)x) << 16) >> 16);
574 static ULong extend_s_16to64 ( UInt x )
576 return (ULong)((((Long)x) << 48) >> 48);
579 static ULong extend_s_26to64 ( UInt x )
581 return (ULong)((((Long)x) << 38) >> 38);
584 static ULong extend_s_32to64 ( UInt x )
586 return (ULong)((((Long)x) << 32) >> 32);
589 /* Do a proper-endian load of a 32-bit word, regardless of the endianness
590 of the underlying host. */
591 static UInt getUIntPPCendianly ( const UChar* p )
593 UInt w = 0;
594 if (host_endness == VexEndnessBE) {
595 w = (w << 8) | p[0];
596 w = (w << 8) | p[1];
597 w = (w << 8) | p[2];
598 w = (w << 8) | p[3];
599 } else {
600 w = (w << 8) | p[3];
601 w = (w << 8) | p[2];
602 w = (w << 8) | p[1];
603 w = (w << 8) | p[0];
605 return w;
609 /*------------------------------------------------------------*/
610 /*--- Helpers for constructing IR. ---*/
611 /*------------------------------------------------------------*/
613 static void assign ( IRTemp dst, IRExpr* e )
615 stmt( IRStmt_WrTmp(dst, e) );
618 /* This generates a normal (non store-conditional) store. */
619 static void store ( IRExpr* addr, IRExpr* data )
621 IRType tyA = typeOfIRExpr(irsb->tyenv, addr);
622 vassert(tyA == Ity_I32 || tyA == Ity_I64);
624 if (host_endness == VexEndnessBE)
625 stmt( IRStmt_Store(Iend_BE, addr, data) );
626 else
627 stmt( IRStmt_Store(Iend_LE, addr, data) );
630 static IRExpr* unop ( IROp op, IRExpr* a )
632 return IRExpr_Unop(op, a);
635 static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
637 return IRExpr_Binop(op, a1, a2);
640 static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
642 return IRExpr_Triop(op, a1, a2, a3);
645 static IRExpr* qop ( IROp op, IRExpr* a1, IRExpr* a2,
646 IRExpr* a3, IRExpr* a4 )
648 return IRExpr_Qop(op, a1, a2, a3, a4);
651 static IRExpr* mkexpr ( IRTemp tmp )
653 return IRExpr_RdTmp(tmp);
656 #define mkU1(_n) IRExpr_Const(IRConst_U1(_n))
658 static IRExpr* mkU8 ( UChar i )
660 return IRExpr_Const(IRConst_U8(i));
663 static IRExpr* mkU16 ( UInt i )
665 return IRExpr_Const(IRConst_U16(i));
668 static IRExpr* mkU32 ( UInt i )
670 return IRExpr_Const(IRConst_U32(i));
673 static IRExpr* mkU64 ( ULong i )
675 return IRExpr_Const(IRConst_U64(i));
678 static IRExpr* mkV128 ( UShort i )
680 vassert(i == 0 || i == 0xffff);
681 return IRExpr_Const(IRConst_V128(i));
684 /* This generates a normal (non load-linked) load. */
685 static IRExpr* load ( IRType ty, IRExpr* addr )
687 if (host_endness == VexEndnessBE)
688 return IRExpr_Load(Iend_BE, ty, addr);
689 else
690 return IRExpr_Load(Iend_LE, ty, addr);
693 static IRStmt* stmt_load ( IRTemp result,
694 IRExpr* addr, IRExpr* storedata )
696 if (host_endness == VexEndnessBE)
697 return IRStmt_LLSC(Iend_BE, result, addr, storedata);
698 else
699 return IRStmt_LLSC(Iend_LE, result, addr, storedata);
702 static IRExpr* mkOR1 ( IRExpr* arg1, IRExpr* arg2 )
704 vassert(typeOfIRExpr(irsb->tyenv, arg1) == Ity_I1);
705 vassert(typeOfIRExpr(irsb->tyenv, arg2) == Ity_I1);
706 return unop(Iop_32to1, binop(Iop_Or32, unop(Iop_1Uto32, arg1),
707 unop(Iop_1Uto32, arg2)));
710 static IRExpr* mkAND1 ( IRExpr* arg1, IRExpr* arg2 )
712 vassert(typeOfIRExpr(irsb->tyenv, arg1) == Ity_I1);
713 vassert(typeOfIRExpr(irsb->tyenv, arg2) == Ity_I1);
714 return unop(Iop_32to1, binop(Iop_And32, unop(Iop_1Uto32, arg1),
715 unop(Iop_1Uto32, arg2)));
718 static inline IRExpr* mkXOr4_32( IRTemp t0, IRTemp t1, IRTemp t2,
719 IRTemp t3 )
721 return binop( Iop_Xor32,
722 binop( Iop_Xor32, mkexpr( t0 ), mkexpr( t1 ) ),
723 binop( Iop_Xor32, mkexpr( t2 ), mkexpr( t3 ) ) );
726 static inline IRExpr* mkOr3_V128( IRTemp t0, IRTemp t1, IRTemp t2 )
728 return binop( Iop_OrV128,
729 mkexpr( t0 ),
730 binop( Iop_OrV128, mkexpr( t1 ), mkexpr( t2 ) ) );
733 static inline IRExpr* mkOr4_V128( IRTemp t0, IRTemp t1, IRTemp t2,
734 IRTemp t3 )
736 return binop( Iop_OrV128,
737 binop( Iop_OrV128, mkexpr( t0 ), mkexpr( t1 ) ),
738 binop( Iop_OrV128, mkexpr( t2 ), mkexpr( t3 ) ) );
741 static inline IRExpr* mkOr4_V128_expr( IRExpr* t0, IRExpr* t1, IRExpr* t2,
742 IRExpr* t3 )
744 /* arguments are already expressions */
745 return binop( Iop_OrV128,
746 binop( Iop_OrV128, ( t0 ), ( t1 ) ),
747 binop( Iop_OrV128, ( t2 ), ( t3 ) ) );
750 static IRExpr* mkNOT1 ( IRExpr* arg1 )
752 vassert(typeOfIRExpr(irsb->tyenv, arg1) == Ity_I1);
753 return unop(Iop_32to1, unop(Iop_Not32, unop(Iop_1Uto32, arg1) ) );
756 /* expand V128_8Ux16 to 2x V128_16Ux8's */
757 static void expand8Ux16( IRExpr* vIn,
758 /*OUTs*/ IRTemp* vEvn, IRTemp* vOdd )
760 IRTemp ones8x16 = newTemp(Ity_V128);
762 vassert(typeOfIRExpr(irsb->tyenv, vIn) == Ity_V128);
763 vassert(vEvn && *vEvn == IRTemp_INVALID);
764 vassert(vOdd && *vOdd == IRTemp_INVALID);
765 *vEvn = newTemp(Ity_V128);
766 *vOdd = newTemp(Ity_V128);
768 assign( ones8x16, unop(Iop_Dup8x16, mkU8(0x1)) );
769 assign( *vOdd, binop(Iop_MullEven8Ux16, mkexpr(ones8x16), vIn) );
770 assign( *vEvn, binop(Iop_MullEven8Ux16, mkexpr(ones8x16),
771 binop(Iop_ShrV128, vIn, mkU8(8))) );
774 /* expand V128_8Sx16 to 2x V128_16Sx8's */
775 static void expand8Sx16( IRExpr* vIn,
776 /*OUTs*/ IRTemp* vEvn, IRTemp* vOdd )
778 IRTemp ones8x16 = newTemp(Ity_V128);
780 vassert(typeOfIRExpr(irsb->tyenv, vIn) == Ity_V128);
781 vassert(vEvn && *vEvn == IRTemp_INVALID);
782 vassert(vOdd && *vOdd == IRTemp_INVALID);
783 *vEvn = newTemp(Ity_V128);
784 *vOdd = newTemp(Ity_V128);
786 assign( ones8x16, unop(Iop_Dup8x16, mkU8(0x1)) );
787 assign( *vOdd, binop(Iop_MullEven8Sx16, mkexpr(ones8x16), vIn) );
788 assign( *vEvn, binop(Iop_MullEven8Sx16, mkexpr(ones8x16),
789 binop(Iop_ShrV128, vIn, mkU8(8))) );
792 /* expand V128_16Uto8 to 2x V128_32Ux4's */
793 static void expand16Ux8( IRExpr* vIn,
794 /*OUTs*/ IRTemp* vEvn, IRTemp* vOdd )
796 IRTemp ones16x8 = newTemp(Ity_V128);
798 vassert(typeOfIRExpr(irsb->tyenv, vIn) == Ity_V128);
799 vassert(vEvn && *vEvn == IRTemp_INVALID);
800 vassert(vOdd && *vOdd == IRTemp_INVALID);
801 *vEvn = newTemp(Ity_V128);
802 *vOdd = newTemp(Ity_V128);
804 assign( ones16x8, unop(Iop_Dup16x8, mkU16(0x1)) );
805 assign( *vOdd, binop(Iop_MullEven16Ux8, mkexpr(ones16x8), vIn) );
806 assign( *vEvn, binop(Iop_MullEven16Ux8, mkexpr(ones16x8),
807 binop(Iop_ShrV128, vIn, mkU8(16))) );
810 /* expand V128_16Sto8 to 2x V128_32Sx4's */
811 static void expand16Sx8( IRExpr* vIn,
812 /*OUTs*/ IRTemp* vEvn, IRTemp* vOdd )
814 IRTemp ones16x8 = newTemp(Ity_V128);
816 vassert(typeOfIRExpr(irsb->tyenv, vIn) == Ity_V128);
817 vassert(vEvn && *vEvn == IRTemp_INVALID);
818 vassert(vOdd && *vOdd == IRTemp_INVALID);
819 *vEvn = newTemp(Ity_V128);
820 *vOdd = newTemp(Ity_V128);
822 assign( ones16x8, unop(Iop_Dup16x8, mkU16(0x1)) );
823 assign( *vOdd, binop(Iop_MullEven16Sx8, mkexpr(ones16x8), vIn) );
824 assign( *vEvn, binop(Iop_MullEven16Sx8, mkexpr(ones16x8),
825 binop(Iop_ShrV128, vIn, mkU8(16))) );
828 /* break V128 to 4xF64's*/
829 static void breakV128to4xF64( IRExpr* t128,
830 /*OUTs*/
831 IRTemp* t3, IRTemp* t2,
832 IRTemp* t1, IRTemp* t0 )
834 IRTemp hi64 = newTemp(Ity_I64);
835 IRTemp lo64 = newTemp(Ity_I64);
837 vassert(typeOfIRExpr(irsb->tyenv, t128) == Ity_V128);
838 vassert(t0 && *t0 == IRTemp_INVALID);
839 vassert(t1 && *t1 == IRTemp_INVALID);
840 vassert(t2 && *t2 == IRTemp_INVALID);
841 vassert(t3 && *t3 == IRTemp_INVALID);
842 *t0 = newTemp(Ity_F64);
843 *t1 = newTemp(Ity_F64);
844 *t2 = newTemp(Ity_F64);
845 *t3 = newTemp(Ity_F64);
847 assign( hi64, unop(Iop_V128HIto64, t128) );
848 assign( lo64, unop(Iop_V128to64, t128) );
849 assign( *t3,
850 unop( Iop_F32toF64,
851 unop( Iop_ReinterpI32asF32,
852 unop( Iop_64HIto32, mkexpr( hi64 ) ) ) ) );
853 assign( *t2,
854 unop( Iop_F32toF64,
855 unop( Iop_ReinterpI32asF32, unop( Iop_64to32, mkexpr( hi64 ) ) ) ) );
856 assign( *t1,
857 unop( Iop_F32toF64,
858 unop( Iop_ReinterpI32asF32,
859 unop( Iop_64HIto32, mkexpr( lo64 ) ) ) ) );
860 assign( *t0,
861 unop( Iop_F32toF64,
862 unop( Iop_ReinterpI32asF32, unop( Iop_64to32, mkexpr( lo64 ) ) ) ) );
866 /* break V128 to 4xI32's, then sign-extend to I64's */
867 static void breakV128to4x64S( IRExpr* t128,
868 /*OUTs*/
869 IRTemp* t3, IRTemp* t2,
870 IRTemp* t1, IRTemp* t0 )
872 IRTemp hi64 = newTemp(Ity_I64);
873 IRTemp lo64 = newTemp(Ity_I64);
875 vassert(typeOfIRExpr(irsb->tyenv, t128) == Ity_V128);
876 vassert(t0 && *t0 == IRTemp_INVALID);
877 vassert(t1 && *t1 == IRTemp_INVALID);
878 vassert(t2 && *t2 == IRTemp_INVALID);
879 vassert(t3 && *t3 == IRTemp_INVALID);
880 *t0 = newTemp(Ity_I64);
881 *t1 = newTemp(Ity_I64);
882 *t2 = newTemp(Ity_I64);
883 *t3 = newTemp(Ity_I64);
885 assign( hi64, unop(Iop_V128HIto64, t128) );
886 assign( lo64, unop(Iop_V128to64, t128) );
887 assign( *t3, unop(Iop_32Sto64, unop(Iop_64HIto32, mkexpr(hi64))) );
888 assign( *t2, unop(Iop_32Sto64, unop(Iop_64to32, mkexpr(hi64))) );
889 assign( *t1, unop(Iop_32Sto64, unop(Iop_64HIto32, mkexpr(lo64))) );
890 assign( *t0, unop(Iop_32Sto64, unop(Iop_64to32, mkexpr(lo64))) );
893 /* break V128 to 4xI32's, then zero-extend to I64's */
894 static void breakV128to4x64U ( IRExpr* t128,
895 /*OUTs*/
896 IRTemp* t3, IRTemp* t2,
897 IRTemp* t1, IRTemp* t0 )
899 IRTemp hi64 = newTemp(Ity_I64);
900 IRTemp lo64 = newTemp(Ity_I64);
902 vassert(typeOfIRExpr(irsb->tyenv, t128) == Ity_V128);
903 vassert(t0 && *t0 == IRTemp_INVALID);
904 vassert(t1 && *t1 == IRTemp_INVALID);
905 vassert(t2 && *t2 == IRTemp_INVALID);
906 vassert(t3 && *t3 == IRTemp_INVALID);
907 *t0 = newTemp(Ity_I64);
908 *t1 = newTemp(Ity_I64);
909 *t2 = newTemp(Ity_I64);
910 *t3 = newTemp(Ity_I64);
912 assign( hi64, unop(Iop_V128HIto64, t128) );
913 assign( lo64, unop(Iop_V128to64, t128) );
914 assign( *t3, unop(Iop_32Uto64, unop(Iop_64HIto32, mkexpr(hi64))) );
915 assign( *t2, unop(Iop_32Uto64, unop(Iop_64to32, mkexpr(hi64))) );
916 assign( *t1, unop(Iop_32Uto64, unop(Iop_64HIto32, mkexpr(lo64))) );
917 assign( *t0, unop(Iop_32Uto64, unop(Iop_64to32, mkexpr(lo64))) );
920 static void breakV128to4x32( IRExpr* t128,
921 /*OUTs*/
922 IRTemp* t3, IRTemp* t2,
923 IRTemp* t1, IRTemp* t0 )
925 IRTemp hi64 = newTemp(Ity_I64);
926 IRTemp lo64 = newTemp(Ity_I64);
928 vassert(typeOfIRExpr(irsb->tyenv, t128) == Ity_V128);
929 vassert(t0 && *t0 == IRTemp_INVALID);
930 vassert(t1 && *t1 == IRTemp_INVALID);
931 vassert(t2 && *t2 == IRTemp_INVALID);
932 vassert(t3 && *t3 == IRTemp_INVALID);
933 *t0 = newTemp(Ity_I32);
934 *t1 = newTemp(Ity_I32);
935 *t2 = newTemp(Ity_I32);
936 *t3 = newTemp(Ity_I32);
938 assign( hi64, unop(Iop_V128HIto64, t128) );
939 assign( lo64, unop(Iop_V128to64, t128) );
940 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
941 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
942 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
943 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
946 static IRExpr* mkV128from32( IRTemp t3, IRTemp t2,
947 IRTemp t1, IRTemp t0 )
949 return
950 binop( Iop_64HLtoV128,
951 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
952 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
956 static IRExpr* extract_field_from_vector( IRTemp vB, IRExpr* index, UInt mask)
958 /* vB is a vector, extract bits starting at index to size of mask */
959 return unop( Iop_V128to64,
960 binop( Iop_AndV128,
961 binop( Iop_ShrV128,
962 mkexpr( vB ),
963 unop( Iop_64to8,
964 binop( Iop_Mul64, index,
965 mkU64( 8 ) ) ) ),
966 binop( Iop_64HLtoV128,
967 mkU64( 0x0 ),
968 mkU64( mask ) ) ) );
971 /* Signed saturating narrow 64S to 32 */
972 static IRExpr* mkQNarrow64Sto32 ( IRExpr* t64 )
974 IRTemp hi32 = newTemp(Ity_I32);
975 IRTemp lo32 = newTemp(Ity_I32);
977 vassert(typeOfIRExpr(irsb->tyenv, t64) == Ity_I64);
979 assign( hi32, unop(Iop_64HIto32, t64));
980 assign( lo32, unop(Iop_64to32, t64));
982 return IRExpr_ITE(
983 /* if (hi32 == (lo32 >>s 31)) */
984 binop(Iop_CmpEQ32, mkexpr(hi32),
985 binop( Iop_Sar32, mkexpr(lo32), mkU8(31))),
986 /* then: within signed-32 range: lo half good enough */
987 mkexpr(lo32),
988 /* else: sign dep saturate: 1->0x80000000, 0->0x7FFFFFFF */
989 binop(Iop_Add32, mkU32(0x7FFFFFFF),
990 binop(Iop_Shr32, mkexpr(hi32), mkU8(31))));
993 /* Unsigned saturating narrow 64S to 32 */
994 static IRExpr* mkQNarrow64Uto32 ( IRExpr* t64 )
996 IRTemp hi32 = newTemp(Ity_I32);
997 IRTemp lo32 = newTemp(Ity_I32);
999 vassert(typeOfIRExpr(irsb->tyenv, t64) == Ity_I64);
1001 assign( hi32, unop(Iop_64HIto32, t64));
1002 assign( lo32, unop(Iop_64to32, t64));
1004 return IRExpr_ITE(
1005 /* if (top 32 bits of t64 are 0) */
1006 binop(Iop_CmpEQ32, mkexpr(hi32), mkU32(0)),
1007 /* then: within unsigned-32 range: lo half good enough */
1008 mkexpr(lo32),
1009 /* else: positive saturate -> 0xFFFFFFFF */
1010 mkU32(0xFFFFFFFF));
1013 /* Signed saturate narrow 64->32, combining to V128 */
1014 static IRExpr* mkV128from4x64S ( IRExpr* t3, IRExpr* t2,
1015 IRExpr* t1, IRExpr* t0 )
1017 vassert(typeOfIRExpr(irsb->tyenv, t3) == Ity_I64);
1018 vassert(typeOfIRExpr(irsb->tyenv, t2) == Ity_I64);
1019 vassert(typeOfIRExpr(irsb->tyenv, t1) == Ity_I64);
1020 vassert(typeOfIRExpr(irsb->tyenv, t0) == Ity_I64);
1021 return binop(Iop_64HLtoV128,
1022 binop(Iop_32HLto64,
1023 mkQNarrow64Sto32( t3 ),
1024 mkQNarrow64Sto32( t2 )),
1025 binop(Iop_32HLto64,
1026 mkQNarrow64Sto32( t1 ),
1027 mkQNarrow64Sto32( t0 )));
1030 /* Unsigned saturate narrow 64->32, combining to V128 */
1031 static IRExpr* mkV128from4x64U ( IRExpr* t3, IRExpr* t2,
1032 IRExpr* t1, IRExpr* t0 )
1034 vassert(typeOfIRExpr(irsb->tyenv, t3) == Ity_I64);
1035 vassert(typeOfIRExpr(irsb->tyenv, t2) == Ity_I64);
1036 vassert(typeOfIRExpr(irsb->tyenv, t1) == Ity_I64);
1037 vassert(typeOfIRExpr(irsb->tyenv, t0) == Ity_I64);
1038 return binop(Iop_64HLtoV128,
1039 binop(Iop_32HLto64,
1040 mkQNarrow64Uto32( t3 ),
1041 mkQNarrow64Uto32( t2 )),
1042 binop(Iop_32HLto64,
1043 mkQNarrow64Uto32( t1 ),
1044 mkQNarrow64Uto32( t0 )));
1047 /* Simulate irops Iop_MullOdd*, since we don't have them */
1048 #define MK_Iop_MullOdd8Ux16( expr_vA, expr_vB ) \
1049 binop(Iop_MullEven8Ux16, \
1050 binop(Iop_ShrV128, expr_vA, mkU8(8)), \
1051 binop(Iop_ShrV128, expr_vB, mkU8(8)))
1053 #define MK_Iop_MullOdd8Sx16( expr_vA, expr_vB ) \
1054 binop(Iop_MullEven8Sx16, \
1055 binop(Iop_ShrV128, expr_vA, mkU8(8)), \
1056 binop(Iop_ShrV128, expr_vB, mkU8(8)))
1058 #define MK_Iop_MullOdd16Ux8( expr_vA, expr_vB ) \
1059 binop(Iop_MullEven16Ux8, \
1060 binop(Iop_ShrV128, expr_vA, mkU8(16)), \
1061 binop(Iop_ShrV128, expr_vB, mkU8(16)))
1063 #define MK_Iop_MullOdd32Ux4( expr_vA, expr_vB ) \
1064 binop(Iop_MullEven32Ux4, \
1065 binop(Iop_ShrV128, expr_vA, mkU8(32)), \
1066 binop(Iop_ShrV128, expr_vB, mkU8(32)))
1068 #define MK_Iop_MullOdd16Sx8( expr_vA, expr_vB ) \
1069 binop(Iop_MullEven16Sx8, \
1070 binop(Iop_ShrV128, expr_vA, mkU8(16)), \
1071 binop(Iop_ShrV128, expr_vB, mkU8(16)))
1073 #define MK_Iop_MullOdd32Sx4( expr_vA, expr_vB ) \
1074 binop(Iop_MullEven32Sx4, \
1075 binop(Iop_ShrV128, expr_vA, mkU8(32)), \
1076 binop(Iop_ShrV128, expr_vB, mkU8(32)))
1079 static IRExpr* /* :: Ity_I64 */ mk64lo32Sto64 ( IRExpr* src )
1081 vassert(typeOfIRExpr(irsb->tyenv, src) == Ity_I64);
1082 return unop(Iop_32Sto64, unop(Iop_64to32, src));
1085 static IRExpr* /* :: Ity_I64 */ mk64lo32Uto64 ( IRExpr* src )
1087 vassert(typeOfIRExpr(irsb->tyenv, src) == Ity_I64);
1088 return unop(Iop_32Uto64, unop(Iop_64to32, src));
1091 static IROp mkSzOp ( IRType ty, IROp op8 )
1093 Int adj;
1094 vassert(ty == Ity_I8 || ty == Ity_I16 ||
1095 ty == Ity_I32 || ty == Ity_I64);
1096 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8 || op8 == Iop_Mul8 ||
1097 op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8 ||
1098 op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8 ||
1099 op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8 ||
1100 op8 == Iop_Not8 );
1101 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : (ty==Ity_I32 ? 2 : 3));
1102 return adj + op8;
1105 /* Make sure we get valid 32 and 64bit addresses */
1106 static Addr64 mkSzAddr ( IRType ty, Addr64 addr )
1108 vassert(ty == Ity_I32 || ty == Ity_I64);
1109 return ( ty == Ity_I64 ?
1110 (Addr64)addr :
1111 (Addr64)extend_s_32to64( toUInt(addr) ) );
1114 /* sz, ULong -> IRExpr */
1115 static IRExpr* mkSzImm ( IRType ty, ULong imm64 )
1117 vassert(ty == Ity_I32 || ty == Ity_I64);
1118 return ty == Ity_I64 ? mkU64(imm64) : mkU32((UInt)imm64);
1121 /* sz, ULong -> IRConst */
1122 static IRConst* mkSzConst ( IRType ty, ULong imm64 )
1124 vassert(ty == Ity_I32 || ty == Ity_I64);
1125 return ( ty == Ity_I64 ?
1126 IRConst_U64(imm64) :
1127 IRConst_U32((UInt)imm64) );
1130 /* Sign extend imm16 -> IRExpr* */
1131 static IRExpr* mkSzExtendS16 ( IRType ty, UInt imm16 )
1133 vassert(ty == Ity_I32 || ty == Ity_I64);
1134 return ( ty == Ity_I64 ?
1135 mkU64(extend_s_16to64(imm16)) :
1136 mkU32(extend_s_16to32(imm16)) );
1139 /* Sign extend imm32 -> IRExpr* */
1140 static IRExpr* mkSzExtendS32 ( IRType ty, UInt imm32 )
1142 vassert(ty == Ity_I32 || ty == Ity_I64);
1143 return ( ty == Ity_I64 ?
1144 mkU64(extend_s_32to64(imm32)) :
1145 mkU32(imm32) );
1148 /* IR narrows I32/I64 -> I8/I16/I32 */
1149 static IRExpr* mkNarrowTo8 ( IRType ty, IRExpr* src )
1151 vassert(ty == Ity_I32 || ty == Ity_I64);
1152 return ty == Ity_I64 ? unop(Iop_64to8, src) : unop(Iop_32to8, src);
1155 static IRExpr* mkNarrowTo16 ( IRType ty, IRExpr* src )
1157 vassert(ty == Ity_I32 || ty == Ity_I64);
1158 return ty == Ity_I64 ? unop(Iop_64to16, src) : unop(Iop_32to16, src);
1161 static IRExpr* mkNarrowTo32 ( IRType ty, IRExpr* src )
1163 vassert(ty == Ity_I32 || ty == Ity_I64);
1164 return ty == Ity_I64 ? unop(Iop_64to32, src) : src;
1167 /* Signed/Unsigned IR widens I8/I16/I32 -> I32/I64 */
1168 static IRExpr* mkWidenFrom8 ( IRType ty, IRExpr* src, Bool sined )
1170 IROp op;
1171 vassert(ty == Ity_I32 || ty == Ity_I64);
1172 if (sined) op = (ty==Ity_I32) ? Iop_8Sto32 : Iop_8Sto64;
1173 else op = (ty==Ity_I32) ? Iop_8Uto32 : Iop_8Uto64;
1174 return unop(op, src);
1177 static IRExpr* mkWidenFrom16 ( IRType ty, IRExpr* src, Bool sined )
1179 IROp op;
1180 vassert(ty == Ity_I32 || ty == Ity_I64);
1181 if (sined) op = (ty==Ity_I32) ? Iop_16Sto32 : Iop_16Sto64;
1182 else op = (ty==Ity_I32) ? Iop_16Uto32 : Iop_16Uto64;
1183 return unop(op, src);
1186 static IRExpr* mkWidenFrom32 ( IRType ty, IRExpr* src, Bool sined )
1188 vassert(ty == Ity_I32 || ty == Ity_I64);
1189 if (ty == Ity_I32)
1190 return src;
1191 return (sined) ? unop(Iop_32Sto64, src) : unop(Iop_32Uto64, src);
1195 static Int integerGuestRegOffset ( UInt archreg )
1197 vassert(archreg < 32);
1199 // jrs: probably not necessary; only matters if we reference sub-parts
1200 // of the ppc registers, but that isn't the case
1201 // later: this might affect Altivec though?
1203 switch (archreg) {
1204 case 0: return offsetofPPCGuestState(guest_GPR0);
1205 case 1: return offsetofPPCGuestState(guest_GPR1);
1206 case 2: return offsetofPPCGuestState(guest_GPR2);
1207 case 3: return offsetofPPCGuestState(guest_GPR3);
1208 case 4: return offsetofPPCGuestState(guest_GPR4);
1209 case 5: return offsetofPPCGuestState(guest_GPR5);
1210 case 6: return offsetofPPCGuestState(guest_GPR6);
1211 case 7: return offsetofPPCGuestState(guest_GPR7);
1212 case 8: return offsetofPPCGuestState(guest_GPR8);
1213 case 9: return offsetofPPCGuestState(guest_GPR9);
1214 case 10: return offsetofPPCGuestState(guest_GPR10);
1215 case 11: return offsetofPPCGuestState(guest_GPR11);
1216 case 12: return offsetofPPCGuestState(guest_GPR12);
1217 case 13: return offsetofPPCGuestState(guest_GPR13);
1218 case 14: return offsetofPPCGuestState(guest_GPR14);
1219 case 15: return offsetofPPCGuestState(guest_GPR15);
1220 case 16: return offsetofPPCGuestState(guest_GPR16);
1221 case 17: return offsetofPPCGuestState(guest_GPR17);
1222 case 18: return offsetofPPCGuestState(guest_GPR18);
1223 case 19: return offsetofPPCGuestState(guest_GPR19);
1224 case 20: return offsetofPPCGuestState(guest_GPR20);
1225 case 21: return offsetofPPCGuestState(guest_GPR21);
1226 case 22: return offsetofPPCGuestState(guest_GPR22);
1227 case 23: return offsetofPPCGuestState(guest_GPR23);
1228 case 24: return offsetofPPCGuestState(guest_GPR24);
1229 case 25: return offsetofPPCGuestState(guest_GPR25);
1230 case 26: return offsetofPPCGuestState(guest_GPR26);
1231 case 27: return offsetofPPCGuestState(guest_GPR27);
1232 case 28: return offsetofPPCGuestState(guest_GPR28);
1233 case 29: return offsetofPPCGuestState(guest_GPR29);
1234 case 30: return offsetofPPCGuestState(guest_GPR30);
1235 case 31: return offsetofPPCGuestState(guest_GPR31);
1236 default: break;
1238 vpanic("integerGuestRegOffset(ppc,be)"); /*notreached*/
1241 static IRExpr* getIReg ( UInt archreg )
1243 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1244 vassert(archreg < 32);
1245 return IRExpr_Get( integerGuestRegOffset(archreg), ty );
1248 /* Ditto, but write to a reg instead. */
1249 static void putIReg ( UInt archreg, IRExpr* e )
1251 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1252 vassert(archreg < 32);
1253 vassert(typeOfIRExpr(irsb->tyenv, e) == ty );
1254 stmt( IRStmt_Put(integerGuestRegOffset(archreg), e) );
1258 /* Floating point egisters are mapped to VSX registers[0..31]. */
1259 static Int floatGuestRegOffset ( UInt archreg )
1261 vassert(archreg < 32);
1263 if (host_endness == VexEndnessLE) {
1264 switch (archreg) {
1265 case 0: return offsetofPPCGuestState(guest_VSR0) + 8;
1266 case 1: return offsetofPPCGuestState(guest_VSR1) + 8;
1267 case 2: return offsetofPPCGuestState(guest_VSR2) + 8;
1268 case 3: return offsetofPPCGuestState(guest_VSR3) + 8;
1269 case 4: return offsetofPPCGuestState(guest_VSR4) + 8;
1270 case 5: return offsetofPPCGuestState(guest_VSR5) + 8;
1271 case 6: return offsetofPPCGuestState(guest_VSR6) + 8;
1272 case 7: return offsetofPPCGuestState(guest_VSR7) + 8;
1273 case 8: return offsetofPPCGuestState(guest_VSR8) + 8;
1274 case 9: return offsetofPPCGuestState(guest_VSR9) + 8;
1275 case 10: return offsetofPPCGuestState(guest_VSR10) + 8;
1276 case 11: return offsetofPPCGuestState(guest_VSR11) + 8;
1277 case 12: return offsetofPPCGuestState(guest_VSR12) + 8;
1278 case 13: return offsetofPPCGuestState(guest_VSR13) + 8;
1279 case 14: return offsetofPPCGuestState(guest_VSR14) + 8;
1280 case 15: return offsetofPPCGuestState(guest_VSR15) + 8;
1281 case 16: return offsetofPPCGuestState(guest_VSR16) + 8;
1282 case 17: return offsetofPPCGuestState(guest_VSR17) + 8;
1283 case 18: return offsetofPPCGuestState(guest_VSR18) + 8;
1284 case 19: return offsetofPPCGuestState(guest_VSR19) + 8;
1285 case 20: return offsetofPPCGuestState(guest_VSR20) + 8;
1286 case 21: return offsetofPPCGuestState(guest_VSR21) + 8;
1287 case 22: return offsetofPPCGuestState(guest_VSR22) + 8;
1288 case 23: return offsetofPPCGuestState(guest_VSR23) + 8;
1289 case 24: return offsetofPPCGuestState(guest_VSR24) + 8;
1290 case 25: return offsetofPPCGuestState(guest_VSR25) + 8;
1291 case 26: return offsetofPPCGuestState(guest_VSR26) + 8;
1292 case 27: return offsetofPPCGuestState(guest_VSR27) + 8;
1293 case 28: return offsetofPPCGuestState(guest_VSR28) + 8;
1294 case 29: return offsetofPPCGuestState(guest_VSR29) + 8;
1295 case 30: return offsetofPPCGuestState(guest_VSR30) + 8;
1296 case 31: return offsetofPPCGuestState(guest_VSR31) + 8;
1297 default: break;
1299 } else {
1300 switch (archreg) {
1301 case 0: return offsetofPPCGuestState(guest_VSR0);
1302 case 1: return offsetofPPCGuestState(guest_VSR1);
1303 case 2: return offsetofPPCGuestState(guest_VSR2);
1304 case 3: return offsetofPPCGuestState(guest_VSR3);
1305 case 4: return offsetofPPCGuestState(guest_VSR4);
1306 case 5: return offsetofPPCGuestState(guest_VSR5);
1307 case 6: return offsetofPPCGuestState(guest_VSR6);
1308 case 7: return offsetofPPCGuestState(guest_VSR7);
1309 case 8: return offsetofPPCGuestState(guest_VSR8);
1310 case 9: return offsetofPPCGuestState(guest_VSR9);
1311 case 10: return offsetofPPCGuestState(guest_VSR10);
1312 case 11: return offsetofPPCGuestState(guest_VSR11);
1313 case 12: return offsetofPPCGuestState(guest_VSR12);
1314 case 13: return offsetofPPCGuestState(guest_VSR13);
1315 case 14: return offsetofPPCGuestState(guest_VSR14);
1316 case 15: return offsetofPPCGuestState(guest_VSR15);
1317 case 16: return offsetofPPCGuestState(guest_VSR16);
1318 case 17: return offsetofPPCGuestState(guest_VSR17);
1319 case 18: return offsetofPPCGuestState(guest_VSR18);
1320 case 19: return offsetofPPCGuestState(guest_VSR19);
1321 case 20: return offsetofPPCGuestState(guest_VSR20);
1322 case 21: return offsetofPPCGuestState(guest_VSR21);
1323 case 22: return offsetofPPCGuestState(guest_VSR22);
1324 case 23: return offsetofPPCGuestState(guest_VSR23);
1325 case 24: return offsetofPPCGuestState(guest_VSR24);
1326 case 25: return offsetofPPCGuestState(guest_VSR25);
1327 case 26: return offsetofPPCGuestState(guest_VSR26);
1328 case 27: return offsetofPPCGuestState(guest_VSR27);
1329 case 28: return offsetofPPCGuestState(guest_VSR28);
1330 case 29: return offsetofPPCGuestState(guest_VSR29);
1331 case 30: return offsetofPPCGuestState(guest_VSR30);
1332 case 31: return offsetofPPCGuestState(guest_VSR31);
1333 default: break;
1336 vpanic("floatGuestRegOffset(ppc)"); /*notreached*/
1339 static IRExpr* getFReg ( UInt archreg )
1341 vassert(archreg < 32);
1342 return IRExpr_Get( floatGuestRegOffset(archreg), Ity_F64 );
1345 /* Ditto, but write to a reg instead. */
1346 static void putFReg ( UInt archreg, IRExpr* e )
1348 vassert(archreg < 32);
1349 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64);
1350 stmt( IRStmt_Put(floatGuestRegOffset(archreg), e) );
1353 /* get Decimal float value. Note, they share floating point register file. */
1354 static IRExpr* getDReg(UInt archreg) {
1355 IRExpr *e;
1356 vassert( archreg < 32 );
1357 e = IRExpr_Get( floatGuestRegOffset( archreg ), Ity_D64 );
1358 return e;
1360 static IRExpr* getDReg32(UInt archreg) {
1361 IRExpr *e;
1362 vassert( archreg < 32 );
1363 e = IRExpr_Get( floatGuestRegOffset( archreg ), Ity_D32 );
1364 return e;
1367 /* Read a floating point register pair and combine their contents into a
1368 128-bit value */
1369 static IRExpr *getDReg_pair(UInt archreg) {
1370 IRExpr *high = getDReg( archreg );
1371 IRExpr *low = getDReg( archreg + 1 );
1373 return binop( Iop_D64HLtoD128, high, low );
1376 /* Ditto, but write to a reg instead. */
1377 static void putDReg32(UInt archreg, IRExpr* e) {
1378 vassert( archreg < 32 );
1379 vassert( typeOfIRExpr(irsb->tyenv, e) == Ity_D32 );
1380 stmt( IRStmt_Put( floatGuestRegOffset( archreg ), e ) );
1383 static void putDReg(UInt archreg, IRExpr* e) {
1384 vassert( archreg < 32 );
1385 vassert( typeOfIRExpr(irsb->tyenv, e) == Ity_D64 );
1386 stmt( IRStmt_Put( floatGuestRegOffset( archreg ), e ) );
1389 /* Write a 128-bit floating point value into a register pair. */
1390 static void putDReg_pair(UInt archreg, IRExpr *e) {
1391 IRTemp low = newTemp( Ity_D64 );
1392 IRTemp high = newTemp( Ity_D64 );
1394 vassert( archreg < 32 );
1395 vassert( typeOfIRExpr(irsb->tyenv, e) == Ity_D128 );
1397 assign( low, unop( Iop_D128LOtoD64, e ) );
1398 assign( high, unop( Iop_D128HItoD64, e ) );
1400 stmt( IRStmt_Put( floatGuestRegOffset( archreg ), mkexpr( high ) ) );
1401 stmt( IRStmt_Put( floatGuestRegOffset( archreg + 1 ), mkexpr( low ) ) );
1404 static Int vsxGuestRegOffset ( UInt archreg )
1406 vassert(archreg < 64);
1407 switch (archreg) {
1408 case 0: return offsetofPPCGuestState(guest_VSR0);
1409 case 1: return offsetofPPCGuestState(guest_VSR1);
1410 case 2: return offsetofPPCGuestState(guest_VSR2);
1411 case 3: return offsetofPPCGuestState(guest_VSR3);
1412 case 4: return offsetofPPCGuestState(guest_VSR4);
1413 case 5: return offsetofPPCGuestState(guest_VSR5);
1414 case 6: return offsetofPPCGuestState(guest_VSR6);
1415 case 7: return offsetofPPCGuestState(guest_VSR7);
1416 case 8: return offsetofPPCGuestState(guest_VSR8);
1417 case 9: return offsetofPPCGuestState(guest_VSR9);
1418 case 10: return offsetofPPCGuestState(guest_VSR10);
1419 case 11: return offsetofPPCGuestState(guest_VSR11);
1420 case 12: return offsetofPPCGuestState(guest_VSR12);
1421 case 13: return offsetofPPCGuestState(guest_VSR13);
1422 case 14: return offsetofPPCGuestState(guest_VSR14);
1423 case 15: return offsetofPPCGuestState(guest_VSR15);
1424 case 16: return offsetofPPCGuestState(guest_VSR16);
1425 case 17: return offsetofPPCGuestState(guest_VSR17);
1426 case 18: return offsetofPPCGuestState(guest_VSR18);
1427 case 19: return offsetofPPCGuestState(guest_VSR19);
1428 case 20: return offsetofPPCGuestState(guest_VSR20);
1429 case 21: return offsetofPPCGuestState(guest_VSR21);
1430 case 22: return offsetofPPCGuestState(guest_VSR22);
1431 case 23: return offsetofPPCGuestState(guest_VSR23);
1432 case 24: return offsetofPPCGuestState(guest_VSR24);
1433 case 25: return offsetofPPCGuestState(guest_VSR25);
1434 case 26: return offsetofPPCGuestState(guest_VSR26);
1435 case 27: return offsetofPPCGuestState(guest_VSR27);
1436 case 28: return offsetofPPCGuestState(guest_VSR28);
1437 case 29: return offsetofPPCGuestState(guest_VSR29);
1438 case 30: return offsetofPPCGuestState(guest_VSR30);
1439 case 31: return offsetofPPCGuestState(guest_VSR31);
1440 case 32: return offsetofPPCGuestState(guest_VSR32);
1441 case 33: return offsetofPPCGuestState(guest_VSR33);
1442 case 34: return offsetofPPCGuestState(guest_VSR34);
1443 case 35: return offsetofPPCGuestState(guest_VSR35);
1444 case 36: return offsetofPPCGuestState(guest_VSR36);
1445 case 37: return offsetofPPCGuestState(guest_VSR37);
1446 case 38: return offsetofPPCGuestState(guest_VSR38);
1447 case 39: return offsetofPPCGuestState(guest_VSR39);
1448 case 40: return offsetofPPCGuestState(guest_VSR40);
1449 case 41: return offsetofPPCGuestState(guest_VSR41);
1450 case 42: return offsetofPPCGuestState(guest_VSR42);
1451 case 43: return offsetofPPCGuestState(guest_VSR43);
1452 case 44: return offsetofPPCGuestState(guest_VSR44);
1453 case 45: return offsetofPPCGuestState(guest_VSR45);
1454 case 46: return offsetofPPCGuestState(guest_VSR46);
1455 case 47: return offsetofPPCGuestState(guest_VSR47);
1456 case 48: return offsetofPPCGuestState(guest_VSR48);
1457 case 49: return offsetofPPCGuestState(guest_VSR49);
1458 case 50: return offsetofPPCGuestState(guest_VSR50);
1459 case 51: return offsetofPPCGuestState(guest_VSR51);
1460 case 52: return offsetofPPCGuestState(guest_VSR52);
1461 case 53: return offsetofPPCGuestState(guest_VSR53);
1462 case 54: return offsetofPPCGuestState(guest_VSR54);
1463 case 55: return offsetofPPCGuestState(guest_VSR55);
1464 case 56: return offsetofPPCGuestState(guest_VSR56);
1465 case 57: return offsetofPPCGuestState(guest_VSR57);
1466 case 58: return offsetofPPCGuestState(guest_VSR58);
1467 case 59: return offsetofPPCGuestState(guest_VSR59);
1468 case 60: return offsetofPPCGuestState(guest_VSR60);
1469 case 61: return offsetofPPCGuestState(guest_VSR61);
1470 case 62: return offsetofPPCGuestState(guest_VSR62);
1471 case 63: return offsetofPPCGuestState(guest_VSR63);
1472 default: break;
1474 vpanic("vsxGuestRegOffset(ppc)"); /*notreached*/
1477 /* Vector registers are mapped to VSX registers[32..63]. */
1478 static Int vectorGuestRegOffset ( UInt archreg )
1480 vassert(archreg < 32);
1482 switch (archreg) {
1483 case 0: return offsetofPPCGuestState(guest_VSR32);
1484 case 1: return offsetofPPCGuestState(guest_VSR33);
1485 case 2: return offsetofPPCGuestState(guest_VSR34);
1486 case 3: return offsetofPPCGuestState(guest_VSR35);
1487 case 4: return offsetofPPCGuestState(guest_VSR36);
1488 case 5: return offsetofPPCGuestState(guest_VSR37);
1489 case 6: return offsetofPPCGuestState(guest_VSR38);
1490 case 7: return offsetofPPCGuestState(guest_VSR39);
1491 case 8: return offsetofPPCGuestState(guest_VSR40);
1492 case 9: return offsetofPPCGuestState(guest_VSR41);
1493 case 10: return offsetofPPCGuestState(guest_VSR42);
1494 case 11: return offsetofPPCGuestState(guest_VSR43);
1495 case 12: return offsetofPPCGuestState(guest_VSR44);
1496 case 13: return offsetofPPCGuestState(guest_VSR45);
1497 case 14: return offsetofPPCGuestState(guest_VSR46);
1498 case 15: return offsetofPPCGuestState(guest_VSR47);
1499 case 16: return offsetofPPCGuestState(guest_VSR48);
1500 case 17: return offsetofPPCGuestState(guest_VSR49);
1501 case 18: return offsetofPPCGuestState(guest_VSR50);
1502 case 19: return offsetofPPCGuestState(guest_VSR51);
1503 case 20: return offsetofPPCGuestState(guest_VSR52);
1504 case 21: return offsetofPPCGuestState(guest_VSR53);
1505 case 22: return offsetofPPCGuestState(guest_VSR54);
1506 case 23: return offsetofPPCGuestState(guest_VSR55);
1507 case 24: return offsetofPPCGuestState(guest_VSR56);
1508 case 25: return offsetofPPCGuestState(guest_VSR57);
1509 case 26: return offsetofPPCGuestState(guest_VSR58);
1510 case 27: return offsetofPPCGuestState(guest_VSR59);
1511 case 28: return offsetofPPCGuestState(guest_VSR60);
1512 case 29: return offsetofPPCGuestState(guest_VSR61);
1513 case 30: return offsetofPPCGuestState(guest_VSR62);
1514 case 31: return offsetofPPCGuestState(guest_VSR63);
1515 default: break;
1517 vpanic("vextorGuestRegOffset(ppc)"); /*notreached*/
1520 static IRExpr* getVReg ( UInt archreg )
1522 vassert(archreg < 32);
1523 return IRExpr_Get( vectorGuestRegOffset(archreg), Ity_V128 );
1526 /* Get contents of 128-bit reg guest register */
1527 static IRExpr* getF128Reg ( UInt archreg )
1529 vassert(archreg < 64);
1530 return IRExpr_Get( vectorGuestRegOffset(archreg), Ity_F128 );
1533 /* Ditto, but write to a reg instead. */
1534 static void putF128Reg ( UInt archreg, IRExpr* e )
1536 vassert(archreg < 64);
1537 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F128);
1538 stmt( IRStmt_Put(vectorGuestRegOffset(archreg), e) );
1541 /* Ditto, but write to a reg instead. */
1542 static void putVReg ( UInt archreg, IRExpr* e )
1544 vassert(archreg < 32);
1545 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
1546 stmt( IRStmt_Put(vectorGuestRegOffset(archreg), e) );
1549 /* Get contents of VSX guest register */
1550 static IRExpr* getVSReg ( UInt archreg )
1552 vassert(archreg < 64);
1553 return IRExpr_Get( vsxGuestRegOffset(archreg), Ity_V128 );
1556 /* Ditto, but write to a VSX reg instead. */
1557 static void putVSReg ( UInt archreg, IRExpr* e )
1559 vassert(archreg < 64);
1560 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
1561 stmt( IRStmt_Put(vsxGuestRegOffset(archreg), e) );
1565 static Int guestCR321offset ( UInt cr )
1567 switch (cr) {
1568 case 0: return offsetofPPCGuestState(guest_CR0_321 );
1569 case 1: return offsetofPPCGuestState(guest_CR1_321 );
1570 case 2: return offsetofPPCGuestState(guest_CR2_321 );
1571 case 3: return offsetofPPCGuestState(guest_CR3_321 );
1572 case 4: return offsetofPPCGuestState(guest_CR4_321 );
1573 case 5: return offsetofPPCGuestState(guest_CR5_321 );
1574 case 6: return offsetofPPCGuestState(guest_CR6_321 );
1575 case 7: return offsetofPPCGuestState(guest_CR7_321 );
1576 default: vpanic("guestCR321offset(ppc)");
1580 static Int guestCR0offset ( UInt cr )
1582 switch (cr) {
1583 case 0: return offsetofPPCGuestState(guest_CR0_0 );
1584 case 1: return offsetofPPCGuestState(guest_CR1_0 );
1585 case 2: return offsetofPPCGuestState(guest_CR2_0 );
1586 case 3: return offsetofPPCGuestState(guest_CR3_0 );
1587 case 4: return offsetofPPCGuestState(guest_CR4_0 );
1588 case 5: return offsetofPPCGuestState(guest_CR5_0 );
1589 case 6: return offsetofPPCGuestState(guest_CR6_0 );
1590 case 7: return offsetofPPCGuestState(guest_CR7_0 );
1591 default: vpanic("guestCR3offset(ppc)");
1595 typedef enum {
1596 _placeholder0,
1597 _placeholder1,
1598 _placeholder2,
1599 BYTE,
1600 HWORD,
1601 WORD,
1602 DWORD
1603 } _popcount_data_type;
1605 /* Generate an IR sequence to do a popcount operation on the supplied
1606 IRTemp, and return a new IRTemp holding the result. 'ty' may be
1607 Ity_I32 or Ity_I64 only. */
1608 static IRTemp gen_POPCOUNT ( IRType ty, IRTemp src,
1609 _popcount_data_type data_type )
1611 /* Do count across 2^data_type bits,
1612 byte: data_type = 3
1613 half word: data_type = 4
1614 word: data_type = 5
1615 double word: data_type = 6 (not supported for 32-bit type)
1617 Int shift[6];
1618 _popcount_data_type idx, i;
1619 IRTemp mask[6];
1620 IRTemp old = IRTemp_INVALID;
1621 IRTemp nyu = IRTemp_INVALID;
1623 vassert(ty == Ity_I64 || ty == Ity_I32);
1625 // Use a single IROp in cases where we can.
1627 if (ty == Ity_I64 && data_type == DWORD) {
1628 IRTemp res = newTemp(Ity_I64);
1629 assign(res, unop(Iop_PopCount64, mkexpr(src)));
1630 return res;
1633 if (ty == Ity_I32 && data_type == WORD) {
1634 IRTemp res = newTemp(Ity_I32);
1635 assign(res, unop(Iop_PopCount32, mkexpr(src)));
1636 return res;
1639 // For the rest, we have to do it the slow way.
1641 if (ty == Ity_I32) {
1643 for (idx = 0; idx < WORD; idx++) {
1644 mask[idx] = newTemp(ty);
1645 shift[idx] = 1 << idx;
1647 assign(mask[0], mkU32(0x55555555));
1648 assign(mask[1], mkU32(0x33333333));
1649 assign(mask[2], mkU32(0x0F0F0F0F));
1650 assign(mask[3], mkU32(0x00FF00FF));
1651 assign(mask[4], mkU32(0x0000FFFF));
1652 old = src;
1653 for (i = 0; i < data_type; i++) {
1654 nyu = newTemp(ty);
1655 assign(nyu,
1656 binop(Iop_Add32,
1657 binop(Iop_And32,
1658 mkexpr(old),
1659 mkexpr(mask[i])),
1660 binop(Iop_And32,
1661 binop(Iop_Shr32, mkexpr(old), mkU8(shift[i])),
1662 mkexpr(mask[i]))));
1663 old = nyu;
1665 return nyu;
1668 // else, ty == Ity_I64
1669 vassert(mode64);
1671 for (i = 0; i < DWORD; i++) {
1672 mask[i] = newTemp( Ity_I64 );
1673 shift[i] = 1 << i;
1675 assign( mask[0], mkU64( 0x5555555555555555ULL ) );
1676 assign( mask[1], mkU64( 0x3333333333333333ULL ) );
1677 assign( mask[2], mkU64( 0x0F0F0F0F0F0F0F0FULL ) );
1678 assign( mask[3], mkU64( 0x00FF00FF00FF00FFULL ) );
1679 assign( mask[4], mkU64( 0x0000FFFF0000FFFFULL ) );
1680 assign( mask[5], mkU64( 0x00000000FFFFFFFFULL ) );
1681 old = src;
1682 for (i = 0; i < data_type; i++) {
1683 nyu = newTemp( Ity_I64 );
1684 assign( nyu,
1685 binop( Iop_Add64,
1686 binop( Iop_And64, mkexpr( old ), mkexpr( mask[i] ) ),
1687 binop( Iop_And64,
1688 binop( Iop_Shr64, mkexpr( old ), mkU8( shift[i] ) ),
1689 mkexpr( mask[i] ) ) ) );
1690 old = nyu;
1692 return nyu;
1695 /* Special purpose population count function for
1696 * vpopcntd in 32-bit mode.
1698 static IRTemp gen_vpopcntd_mode32 ( IRTemp src1, IRTemp src2 )
1700 IRTemp retval = newTemp(Ity_I64);
1702 vassert(!mode64);
1704 assign(retval,
1705 unop(Iop_32Uto64,
1706 binop(Iop_Add32,
1707 unop(Iop_PopCount32, mkexpr(src1)),
1708 unop(Iop_PopCount32, mkexpr(src2)))));
1709 return retval;
1713 // ROTL(src32/64, rot_amt5/6)
1714 static IRExpr* /* :: Ity_I32/64 */ ROTL ( IRExpr* src,
1715 IRExpr* rot_amt )
1717 IRExpr *mask, *rot;
1718 vassert(typeOfIRExpr(irsb->tyenv,rot_amt) == Ity_I8);
1720 if (typeOfIRExpr(irsb->tyenv,src) == Ity_I64) {
1721 // rot = (src << rot_amt) | (src >> (64-rot_amt))
1722 mask = binop(Iop_And8, rot_amt, mkU8(63));
1723 rot = binop(Iop_Or64,
1724 binop(Iop_Shl64, src, mask),
1725 binop(Iop_Shr64, src, binop(Iop_Sub8, mkU8(64), mask)));
1726 } else {
1727 // rot = (src << rot_amt) | (src >> (32-rot_amt))
1728 mask = binop(Iop_And8, rot_amt, mkU8(31));
1729 rot = binop(Iop_Or32,
1730 binop(Iop_Shl32, src, mask),
1731 binop(Iop_Shr32, src, binop(Iop_Sub8, mkU8(32), mask)));
1733 /* Note: the ITE not merely an optimisation; it's needed
1734 because otherwise the Shr is a shift by the word size when
1735 mask denotes zero. For rotates by immediates, a lot of
1736 this junk gets folded out. */
1737 return IRExpr_ITE( binop(Iop_CmpNE8, mask, mkU8(0)),
1738 /* non-zero rotate */ rot,
1739 /* zero rotate */ src);
1742 /* Standard effective address calc: (rA + rB) */
1743 static IRExpr* ea_rA_idxd ( UInt rA, UInt rB )
1745 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1746 vassert(rA < 32);
1747 vassert(rB < 32);
1748 return binop(mkSzOp(ty, Iop_Add8), getIReg(rA), getIReg(rB));
1751 /* Standard effective address calc: (rA + simm) */
1752 static IRExpr* ea_rA_simm ( UInt rA, UInt simm16 )
1754 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1755 vassert(rA < 32);
1756 return binop(mkSzOp(ty, Iop_Add8), getIReg(rA),
1757 mkSzExtendS16(ty, simm16));
1760 /* Standard effective address calc: (rA|0) */
1761 static IRExpr* ea_rAor0 ( UInt rA )
1763 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1764 vassert(rA < 32);
1765 if (rA == 0) {
1766 return mkSzImm(ty, 0);
1767 } else {
1768 return getIReg(rA);
1772 /* Standard effective address calc: (rA|0) + rB */
1773 static IRExpr* ea_rAor0_idxd ( UInt rA, UInt rB )
1775 vassert(rA < 32);
1776 vassert(rB < 32);
1777 return (rA == 0) ? getIReg(rB) : ea_rA_idxd( rA, rB );
1780 /* Standard effective address calc: (rA|0) + simm16 */
1781 static IRExpr* ea_rAor0_simm ( UInt rA, UInt simm16 )
1783 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1784 vassert(rA < 32);
1785 if (rA == 0) {
1786 return mkSzExtendS16(ty, simm16);
1787 } else {
1788 return ea_rA_simm( rA, simm16 );
1793 /* Align effective address */
1794 static IRExpr* addr_align( IRExpr* addr, UChar align )
1796 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1797 ULong mask;
1798 switch (align) {
1799 case 1: return addr; // byte aligned
1800 case 2: mask = ~0ULL << 1; break; // half-word aligned
1801 case 4: mask = ~0ULL << 2; break; // word aligned
1802 case 16: mask = ~0ULL << 4; break; // quad-word aligned
1803 default:
1804 vex_printf("addr_align: align = %u\n", align);
1805 vpanic("addr_align(ppc)");
1808 vassert(typeOfIRExpr(irsb->tyenv,addr) == ty);
1809 return binop( mkSzOp(ty, Iop_And8), addr, mkSzImm(ty, mask) );
1813 /* Exit the trace if ADDR (intended to be a guest memory address) is
1814 not ALIGN-aligned, generating a request for a SIGBUS followed by a
1815 restart of the current insn. */
1816 static void gen_SIGBUS_if_misaligned ( IRTemp addr, UChar align )
1818 vassert(align == 2 || align == 4 || align == 8 || align == 16);
1819 if (mode64) {
1820 vassert(typeOfIRTemp(irsb->tyenv, addr) == Ity_I64);
1821 stmt(
1822 IRStmt_Exit(
1823 binop(Iop_CmpNE64,
1824 binop(Iop_And64, mkexpr(addr), mkU64(align-1)),
1825 mkU64(0)),
1826 Ijk_SigBUS,
1827 IRConst_U64( guest_CIA_curr_instr ), OFFB_CIA
1830 } else {
1831 vassert(typeOfIRTemp(irsb->tyenv, addr) == Ity_I32);
1832 stmt(
1833 IRStmt_Exit(
1834 binop(Iop_CmpNE32,
1835 binop(Iop_And32, mkexpr(addr), mkU32(align-1)),
1836 mkU32(0)),
1837 Ijk_SigBUS,
1838 IRConst_U32( guest_CIA_curr_instr ), OFFB_CIA
1845 /* Generate AbiHints which mark points at which the ELF or PowerOpen
1846 ABIs say that the stack red zone (viz, -N(r1) .. -1(r1), for some
1847 N) becomes undefined. That is at function calls and returns. ELF
1848 ppc32 doesn't have this "feature" (how fortunate for it). nia is
1849 the address of the next instruction to be executed.
1851 static void make_redzone_AbiHint ( const VexAbiInfo* vbi,
1852 IRTemp nia, const HChar* who )
1854 Int szB = vbi->guest_stack_redzone_size;
1855 if (0) vex_printf("AbiHint: %s\n", who);
1856 vassert(szB >= 0);
1857 if (szB > 0) {
1858 if (mode64) {
1859 vassert(typeOfIRTemp(irsb->tyenv, nia) == Ity_I64);
1860 stmt( IRStmt_AbiHint(
1861 binop(Iop_Sub64, getIReg(1), mkU64(szB)),
1862 szB,
1863 mkexpr(nia)
1865 } else {
1866 vassert(typeOfIRTemp(irsb->tyenv, nia) == Ity_I32);
1867 stmt( IRStmt_AbiHint(
1868 binop(Iop_Sub32, getIReg(1), mkU32(szB)),
1869 szB,
1870 mkexpr(nia)
1877 /*------------------------------------------------------------*/
1878 /*--- Helpers for condition codes. ---*/
1879 /*------------------------------------------------------------*/
1881 /* Condition register layout.
1883 In the hardware, CR is laid out like this. The leftmost end is the
1884 most significant bit in the register; however the IBM documentation
1885 numbers the bits backwards for some reason.
1887 CR0 CR1 .......... CR6 CR7
1888 0 .. 3 ....................... 28 .. 31 (IBM bit numbering)
1889 31 28 3 0 (normal bit numbering)
1891 Each CR field is 4 bits: [<,>,==,SO]
1893 Hence in IBM's notation, BI=0 is CR7[SO], BI=1 is CR7[==], etc.
1895 Indexing from BI to guest state:
1897 let n = BI / 4
1898 off = BI % 4
1899 this references CR n:
1901 off==0 -> guest_CRn_321 >> 3
1902 off==1 -> guest_CRn_321 >> 2
1903 off==2 -> guest_CRn_321 >> 1
1904 off==3 -> guest_CRn_SO
1906 Bear in mind the only significant bit in guest_CRn_SO is bit 0
1907 (normal notation) and in guest_CRn_321 the significant bits are
1908 3, 2 and 1 (normal notation).
1911 static void putCR321 ( UInt cr, IRExpr* e )
1913 vassert(cr < 8);
1914 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
1915 stmt( IRStmt_Put(guestCR321offset(cr), e) );
1918 static void putCR0 ( UInt cr, IRExpr* e )
1920 vassert(cr < 8);
1921 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
1922 stmt( IRStmt_Put(guestCR0offset(cr), e) );
1925 static void putC ( IRExpr* e )
1927 /* The assumption is that the value of the Floating-Point Result
1928 * Class Descriptor bit (C) is passed in the lower four bits of a
1929 * 32 bit value.
1931 * Note, the C and FPCC bits which are fields in the FPSCR
1932 * register are stored in their own memory location of
1933 * memory. The FPCC bits are in the lower 4 bits. The C bit needs
1934 * to be shifted to bit 4 in the memory location that holds C and FPCC.
1935 * Note not all of the FPSCR register bits are supported. We are
1936 * only writing C bit.
1938 IRExpr* tmp;
1940 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
1942 /* Get the FPCC bit field */
1943 tmp = binop( Iop_And32,
1944 mkU32( 0xF ),
1945 unop( Iop_8Uto32, IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ) );
1947 stmt( IRStmt_Put( OFFB_C_FPCC,
1948 unop( Iop_32to8,
1949 binop( Iop_Or32, tmp,
1950 binop( Iop_Shl32,
1951 binop( Iop_And32, mkU32( 0x1 ), e ),
1952 mkU8( 4 ) ) ) ) ) );
1955 static IRExpr* /* :: Ity_I8 */ getCR0 ( UInt cr )
1957 vassert(cr < 8);
1958 return IRExpr_Get(guestCR0offset(cr), Ity_I8);
1961 static IRExpr* /* :: Ity_I8 */ getCR321 ( UInt cr )
1963 vassert(cr < 8);
1964 return IRExpr_Get(guestCR321offset(cr), Ity_I8);
1967 /* Fetch the specified CR bit (as per IBM/hardware notation) and
1968 return it at the bottom of an I32; the top 31 bits are guaranteed
1969 to be zero. */
1970 static IRExpr* /* :: Ity_I32 */ getCRbit ( UInt bi )
1972 UInt n = bi / 4;
1973 UInt off = bi % 4;
1974 vassert(bi < 32);
1975 if (off == 3) {
1976 /* Fetch the SO bit for this CR field */
1977 /* Note: And32 is redundant paranoia iff guest state only has 0
1978 or 1 in that slot. */
1979 return binop(Iop_And32, unop(Iop_8Uto32, getCR0(n)), mkU32(1));
1980 } else {
1981 /* Fetch the <, > or == bit for this CR field */
1982 return binop( Iop_And32,
1983 binop( Iop_Shr32,
1984 unop(Iop_8Uto32, getCR321(n)),
1985 mkU8(toUChar(3-off)) ),
1986 mkU32(1) );
1990 /* Dually, write the least significant bit of BIT to the specified CR
1991 bit. Indexing as per getCRbit. */
1992 static void putCRbit ( UInt bi, IRExpr* bit )
1994 UInt n, off;
1995 IRExpr* safe;
1996 vassert(typeOfIRExpr(irsb->tyenv,bit) == Ity_I32);
1997 safe = binop(Iop_And32, bit, mkU32(1));
1998 n = bi / 4;
1999 off = bi % 4;
2000 vassert(bi < 32);
2001 if (off == 3) {
2002 /* This is the SO bit for this CR field */
2003 putCR0(n, unop(Iop_32to8, safe));
2004 } else {
2005 off = 3 - off;
2006 vassert(off == 1 || off == 2 || off == 3);
2007 putCR321(
2009 unop( Iop_32to8,
2010 binop( Iop_Or32,
2011 /* old value with field masked out */
2012 binop(Iop_And32, unop(Iop_8Uto32, getCR321(n)),
2013 mkU32(~(1 << off))),
2014 /* new value in the right place */
2015 binop(Iop_Shl32, safe, mkU8(toUChar(off)))
2022 /* Fetch the specified CR bit (as per IBM/hardware notation) and
2023 return it somewhere in an I32; it does not matter where, but
2024 whichever bit it is, all other bits are guaranteed to be zero. In
2025 other words, the I32-typed expression will be zero if the bit is
2026 zero and nonzero if the bit is 1. Write into *where the index
2027 of where the bit will be. */
2029 static
2030 IRExpr* /* :: Ity_I32 */ getCRbit_anywhere ( UInt bi, Int* where )
2032 UInt n = bi / 4;
2033 UInt off = bi % 4;
2034 vassert(bi < 32);
2035 if (off == 3) {
2036 /* Fetch the SO bit for this CR field */
2037 /* Note: And32 is redundant paranoia iff guest state only has 0
2038 or 1 in that slot. */
2039 *where = 0;
2040 return binop(Iop_And32, unop(Iop_8Uto32, getCR0(n)), mkU32(1));
2041 } else {
2042 /* Fetch the <, > or == bit for this CR field */
2043 *where = 3-off;
2044 return binop( Iop_And32,
2045 unop(Iop_8Uto32, getCR321(n)),
2046 mkU32(1 << (3-off)) );
2050 /* Set the CR0 flags following an arithmetic operation.
2051 (Condition Register CR0 Field Definition, PPC32 p60)
2053 static IRExpr* getXER_SO ( void );
2054 static void set_CR0 ( IRExpr* result )
2056 vassert(typeOfIRExpr(irsb->tyenv,result) == Ity_I32 ||
2057 typeOfIRExpr(irsb->tyenv,result) == Ity_I64);
2058 if (mode64) {
2059 putCR321( 0, unop(Iop_64to8,
2060 binop(Iop_CmpORD64S, result, mkU64(0))) );
2061 } else {
2062 putCR321( 0, unop(Iop_32to8,
2063 binop(Iop_CmpORD32S, result, mkU32(0))) );
2065 putCR0( 0, getXER_SO() );
2069 /* Set the CR6 flags following an AltiVec compare operation.
2070 * NOTE: This also works for VSX single-precision compares.
2071 * */
2072 static void set_AV_CR6 ( IRExpr* result, Bool test_all_ones )
2074 /* CR6[0:3] = {all_ones, 0, all_zeros, 0}
2075 32 bit: all_zeros = (v[0] || v[1] || v[2] || v[3]) == 0x0000'0000
2076 all_ones = ~(v[0] && v[1] && v[2] && v[3]) == 0x0000'0000
2077 where v[] denotes 32-bit lanes
2079 64 bit: all_zeros = (v[0] || v[1]) == 0x0000'0000'0000'0000
2080 all_ones = ~(v[0] && v[1]) == 0x0000'0000'0000'0000
2081 where v[] denotes 64-bit lanes
2083 The 32- and 64-bit versions compute the same thing, but the 64-bit one
2084 tries to be a bit more efficient.
2086 vassert(typeOfIRExpr(irsb->tyenv,result) == Ity_V128);
2088 IRTemp overlappedOred = newTemp(Ity_V128);
2089 IRTemp overlappedAnded = newTemp(Ity_V128);
2091 if (mode64) {
2092 IRTemp v0 = newTemp(Ity_V128);
2093 IRTemp v1 = newTemp(Ity_V128);
2094 assign( v0, result );
2095 assign( v1, binop(Iop_ShrV128, result, mkU8(64)) );
2096 assign(overlappedOred,
2097 binop(Iop_OrV128, mkexpr(v0), mkexpr(v1)));
2098 assign(overlappedAnded,
2099 binop(Iop_AndV128, mkexpr(v0), mkexpr(v1)));
2100 } else {
2101 IRTemp v0 = newTemp(Ity_V128);
2102 IRTemp v1 = newTemp(Ity_V128);
2103 IRTemp v2 = newTemp(Ity_V128);
2104 IRTemp v3 = newTemp(Ity_V128);
2105 assign( v0, result );
2106 assign( v1, binop(Iop_ShrV128, result, mkU8(32)) );
2107 assign( v2, binop(Iop_ShrV128, result, mkU8(64)) );
2108 assign( v3, binop(Iop_ShrV128, result, mkU8(96)) );
2109 assign(overlappedOred,
2110 binop(Iop_OrV128,
2111 binop(Iop_OrV128, mkexpr(v0), mkexpr(v1)),
2112 binop(Iop_OrV128, mkexpr(v2), mkexpr(v3))));
2113 assign(overlappedAnded,
2114 binop(Iop_AndV128,
2115 binop(Iop_AndV128, mkexpr(v0), mkexpr(v1)),
2116 binop(Iop_AndV128, mkexpr(v2), mkexpr(v3))));
2119 IRTemp rOnes = newTemp(Ity_I8);
2120 IRTemp rZeroes = newTemp(Ity_I8);
2122 if (mode64) {
2123 assign(rZeroes,
2124 unop(Iop_1Uto8,
2125 binop(Iop_CmpEQ64,
2126 mkU64(0),
2127 unop(Iop_V128to64, mkexpr(overlappedOred)))));
2128 assign(rOnes,
2129 unop(Iop_1Uto8,
2130 binop(Iop_CmpEQ64,
2131 mkU64(0),
2132 unop(Iop_Not64,
2133 unop(Iop_V128to64, mkexpr(overlappedAnded))))));
2134 } else {
2135 assign(rZeroes,
2136 unop(Iop_1Uto8,
2137 binop(Iop_CmpEQ32,
2138 mkU32(0),
2139 unop(Iop_V128to32, mkexpr(overlappedOred)))));
2140 assign(rOnes,
2141 unop(Iop_1Uto8,
2142 binop(Iop_CmpEQ32,
2143 mkU32(0),
2144 unop(Iop_Not32,
2145 unop(Iop_V128to32, mkexpr(overlappedAnded))))));
2148 // rOnes might not be used below. But iropt will remove it, so there's no
2149 // inefficiency as a result.
2151 if (test_all_ones) {
2152 putCR321( 6, binop(Iop_Or8,
2153 binop(Iop_Shl8, mkexpr(rOnes), mkU8(3)),
2154 binop(Iop_Shl8, mkexpr(rZeroes), mkU8(1))) );
2155 } else {
2156 putCR321( 6, binop(Iop_Shl8, mkexpr(rZeroes), mkU8(1)) );
2158 putCR0( 6, mkU8(0) );
2162 static IRExpr * create_DCM ( IRType size, IRTemp NaN, IRTemp inf, IRTemp zero,
2163 IRTemp dnorm, IRTemp pos)
2165 /* This is a general function for creating the DCM for a 32-bit or
2166 64-bit expression based on the passes size.
2168 IRTemp neg;
2169 IROp opAND, opOR, opSHL, opXto1, op1UtoX;
2171 vassert( ( size == Ity_I32 ) || ( size == Ity_I64 ) );
2173 if ( size == Ity_I32 ) {
2174 opSHL = Iop_Shl32;
2175 opAND = Iop_And32;
2176 opOR = Iop_Or32;
2177 opXto1 = Iop_32to1;
2178 op1UtoX = Iop_1Uto32;
2179 neg = newTemp( Ity_I32 );
2181 } else {
2182 opSHL = Iop_Shl64;
2183 opAND = Iop_And64;
2184 opOR = Iop_Or64;
2185 opXto1 = Iop_64to1;
2186 op1UtoX = Iop_1Uto64;
2187 neg = newTemp( Ity_I64 );
2190 assign( neg, unop( op1UtoX, mkNOT1( unop( opXto1,
2191 mkexpr ( pos ) ) ) ) );
2193 return binop( opOR,
2194 binop( opSHL, mkexpr( NaN ), mkU8( 6 ) ),
2195 binop( opOR,
2196 binop( opOR,
2197 binop( opOR,
2198 binop( opSHL,
2199 binop( opAND,
2200 mkexpr( pos ),
2201 mkexpr( inf ) ),
2202 mkU8( 5 ) ),
2203 binop( opSHL,
2204 binop( opAND,
2205 mkexpr( neg ),
2206 mkexpr( inf ) ),
2207 mkU8( 4 ) ) ),
2208 binop( opOR,
2209 binop( opSHL,
2210 binop( opAND,
2211 mkexpr( pos ),
2212 mkexpr( zero ) ),
2213 mkU8( 3 ) ),
2214 binop( opSHL,
2215 binop( opAND,
2216 mkexpr( neg ),
2217 mkexpr( zero ) ),
2218 mkU8( 2 ) ) ) ),
2219 binop( opOR,
2220 binop( opSHL,
2221 binop( opAND,
2222 mkexpr( pos ),
2223 mkexpr( dnorm ) ),
2224 mkU8( 1 ) ),
2225 binop( opAND,
2226 mkexpr( neg ),
2227 mkexpr( dnorm ) ) ) ) );
2230 /*------------------------------------------------------------*/
2231 /*--- Helpers for XER flags. ---*/
2232 /*------------------------------------------------------------*/
2234 static void putXER_SO ( IRExpr* e )
2236 IRExpr* so;
2237 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
2238 so = binop(Iop_And8, e, mkU8(1));
2239 stmt( IRStmt_Put( OFFB_XER_SO, so ) );
2242 static void putXER_OV ( IRExpr* e )
2244 /* Interface to write XER[OV] */
2245 IRExpr* ov;
2246 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
2247 ov = binop(Iop_And8, e, mkU8(1));
2248 stmt( IRStmt_Put( OFFB_XER_OV, ov ) );
2251 static void putXER_OV32 ( IRExpr* e )
2253 /*Interface to write XER[OV32] */
2254 IRExpr* ov;
2255 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
2256 ov = binop(Iop_And8, e, mkU8(1));
2258 /* The OV32 bit was added to XER in ISA 3.0. Do not write unless we
2259 * ISA 3.0 or beyond is supported. */
2260 if( OV32_CA32_supported )
2261 stmt( IRStmt_Put( OFFB_XER_OV32, ov ) );
2264 static void putXER_CA ( IRExpr* e )
2266 /* Interface to write XER[CA] */
2267 IRExpr* ca;
2268 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
2269 ca = binop(Iop_And8, e, mkU8(1));
2270 stmt( IRStmt_Put( OFFB_XER_CA, ca ) );
2273 static void putXER_CA32 ( IRExpr* e )
2275 /* Interface to write XER[CA32] */
2276 IRExpr* ca;
2277 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
2278 ca = binop(Iop_And8, e, mkU8(1));
2280 /* The CA32 bit was added to XER in ISA 3.0. Do not write unless we
2281 * ISA 3.0 or beyond is supported. */
2282 if( OV32_CA32_supported )
2283 stmt( IRStmt_Put( OFFB_XER_CA32, ca ) );
2286 static void putXER_BC ( IRExpr* e )
2288 IRExpr* bc;
2289 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
2290 bc = binop(Iop_And8, e, mkU8(0x7F));
2291 stmt( IRStmt_Put( OFFB_XER_BC, bc ) );
2294 static IRExpr* /* :: Ity_I8 */ getXER_SO ( void )
2296 return IRExpr_Get( OFFB_XER_SO, Ity_I8 );
2299 static IRExpr* /* :: Ity_I32 */ getXER_SO_32 ( void )
2301 return binop( Iop_And32, unop(Iop_8Uto32, getXER_SO()), mkU32(1) );
2304 static IRExpr* /* :: Ity_I8 */ getXER_OV ( void )
2306 return IRExpr_Get( OFFB_XER_OV, Ity_I8 );
2309 static IRExpr* /* :: Ity_I8 */ getXER_OV32 ( void )
2311 return IRExpr_Get( OFFB_XER_OV32, Ity_I8 );
2314 static IRExpr* /* :: Ity_I32 */ getXER_OV_32 ( void )
2316 /* get XER[OV], 32-bit interface */
2317 return binop( Iop_And32, unop(Iop_8Uto32, getXER_OV()), mkU32(1) );
2320 static IRExpr* /* :: Ity_I32 */ getXER_OV32_32 ( void )
2322 /* get XER[OV32], 32-bit interface */
2323 return binop( Iop_And32, unop(Iop_8Uto32, getXER_OV32()), mkU32(1) );
2326 static IRExpr* /* :: Ity_I32 */ getXER_CA_32 ( void )
2328 /* get XER[CA], 32-bit interface */
2329 IRExpr* ca = IRExpr_Get( OFFB_XER_CA, Ity_I8 );
2330 return binop( Iop_And32, unop(Iop_8Uto32, ca ), mkU32(1) );
2333 static IRExpr* /* :: Ity_I32 */ getXER_CA32_32 ( void )
2335 /* get XER[CA32], 32-bit interface */
2336 IRExpr* ca = IRExpr_Get( OFFB_XER_CA32, Ity_I8 );
2337 return binop( Iop_And32, unop(Iop_8Uto32, ca ), mkU32(1) );
2340 static IRExpr* /* :: Ity_I8 */ getXER_BC ( void )
2342 return IRExpr_Get( OFFB_XER_BC, Ity_I8 );
2345 static IRExpr* /* :: Ity_I32 */ getXER_BC_32 ( void )
2347 IRExpr* bc = IRExpr_Get( OFFB_XER_BC, Ity_I8 );
2348 return binop( Iop_And32, unop(Iop_8Uto32, bc), mkU32(0x7F) );
2352 /* RES is the result of doing OP on ARGL and ARGR. Set %XER.OV and
2353 %XER.SO accordingly. */
2355 static IRExpr* calculate_XER_OV_32( UInt op, IRExpr* res,
2356 IRExpr* argL, IRExpr* argR )
2358 IRTemp t64;
2359 IRExpr* xer_ov;
2361 # define INT32_MIN 0x80000000
2363 # define XOR2(_aa,_bb) \
2364 binop(Iop_Xor32,(_aa),(_bb))
2366 # define XOR3(_cc,_dd,_ee) \
2367 binop(Iop_Xor32,binop(Iop_Xor32,(_cc),(_dd)),(_ee))
2369 # define AND3(_ff,_gg,_hh) \
2370 binop(Iop_And32,binop(Iop_And32,(_ff),(_gg)),(_hh))
2372 #define NOT(_jj) \
2373 unop(Iop_Not32, (_jj))
2375 switch (op) {
2376 case /* 0 */ PPCG_FLAG_OP_ADD:
2377 case /* 1 */ PPCG_FLAG_OP_ADDE:
2378 /* (argL^argR^-1) & (argL^res) & (1<<31) ?1:0 */
2379 // i.e. ((both_same_sign) & (sign_changed) & (sign_mask))
2380 xer_ov
2381 = AND3( XOR3(argL,argR,mkU32(-1)),
2382 XOR2(argL,res),
2383 mkU32(INT32_MIN) );
2384 /* xer_ov can only be 0 or 1<<31 */
2385 xer_ov
2386 = binop(Iop_Shr32, xer_ov, mkU8(31) );
2387 break;
2389 case /* 2 */ PPCG_FLAG_OP_DIVW:
2390 /* (argL == INT32_MIN && argR == -1) || argR == 0 */
2391 xer_ov
2392 = mkOR1(
2393 mkAND1(
2394 binop(Iop_CmpEQ32, argL, mkU32(INT32_MIN)),
2395 binop(Iop_CmpEQ32, argR, mkU32(-1))
2397 binop(Iop_CmpEQ32, argR, mkU32(0) )
2399 xer_ov
2400 = unop(Iop_1Uto32, xer_ov);
2401 break;
2403 case /* 3 */ PPCG_FLAG_OP_DIVWU:
2404 /* argR == 0 */
2405 xer_ov
2406 = unop(Iop_1Uto32, binop(Iop_CmpEQ32, argR, mkU32(0)));
2407 break;
2409 case /* 4 */ PPCG_FLAG_OP_MULLW:
2410 /* OV true if result can't be represented in 32 bits
2411 i.e sHi != sign extension of sLo */
2412 t64 = newTemp(Ity_I64);
2413 assign( t64, binop(Iop_MullS32, argL, argR) );
2414 xer_ov
2415 = binop( Iop_CmpNE32,
2416 unop(Iop_64HIto32, mkexpr(t64)),
2417 binop( Iop_Sar32,
2418 unop(Iop_64to32, mkexpr(t64)),
2419 mkU8(31))
2421 xer_ov
2422 = unop(Iop_1Uto32, xer_ov);
2423 break;
2425 case /* 5 */ PPCG_FLAG_OP_NEG:
2426 /* argL == INT32_MIN */
2427 xer_ov
2428 = unop( Iop_1Uto32,
2429 binop(Iop_CmpEQ32, argL, mkU32(INT32_MIN)) );
2430 break;
2432 case /* 6 */ PPCG_FLAG_OP_SUBF:
2433 case /* 7 */ PPCG_FLAG_OP_SUBFC:
2434 case /* 8 */ PPCG_FLAG_OP_SUBFE:
2435 /* ((~argL)^argR^-1) & ((~argL)^res) & (1<<31) ?1:0; */
2436 xer_ov
2437 = AND3( XOR3(NOT(argL),argR,mkU32(-1)),
2438 XOR2(NOT(argL),res),
2439 mkU32(INT32_MIN) );
2440 /* xer_ov can only be 0 or 1<<31 */
2441 xer_ov
2442 = binop(Iop_Shr32, xer_ov, mkU8(31) );
2443 break;
2445 case PPCG_FLAG_OP_DIVWEU:
2446 xer_ov
2447 = binop( Iop_Or32,
2448 unop( Iop_1Uto32, binop( Iop_CmpEQ32, argR, mkU32( 0 ) ) ),
2449 unop( Iop_1Uto32, binop( Iop_CmpLT32U, argR, argL ) ) );
2450 break;
2452 case PPCG_FLAG_OP_DIVWE:
2454 /* If argR == 0 of if the result cannot fit in the 32-bit destination register,
2455 * then OV <- 1. If dest reg is 0 AND both dividend and divisor are non-zero,
2456 * an overflow is implied.
2458 xer_ov = binop( Iop_Or32,
2459 unop( Iop_1Uto32, binop( Iop_CmpEQ32, argR, mkU32( 0 ) ) ),
2460 unop( Iop_1Uto32, mkAND1( binop( Iop_CmpEQ32, res, mkU32( 0 ) ),
2461 mkAND1( binop( Iop_CmpNE32, argL, mkU32( 0 ) ),
2462 binop( Iop_CmpNE32, argR, mkU32( 0 ) ) ) ) ) );
2463 break;
2467 default:
2468 vex_printf("calculate_XER_OV_32: op = %u\n", op);
2469 vpanic("calculate_XER_OV_32(ppc)");
2472 return xer_ov;
2474 # undef INT32_MIN
2475 # undef AND3
2476 # undef XOR3
2477 # undef XOR2
2478 # undef NOT
2481 static void set_XER_OV_OV32_32( UInt op, IRExpr* res,
2482 IRExpr* argL, IRExpr* argR )
2484 IRExpr* xer_ov;
2486 vassert(op < PPCG_FLAG_OP_NUMBER);
2487 vassert(typeOfIRExpr(irsb->tyenv,res) == Ity_I32);
2488 vassert(typeOfIRExpr(irsb->tyenv,argL) == Ity_I32);
2489 vassert(typeOfIRExpr(irsb->tyenv,argR) == Ity_I32);
2491 xer_ov = calculate_XER_OV_32( op, res, argL, argR );
2493 /* xer_ov MUST denote either 0 or 1, no other value allowed */
2494 putXER_OV( unop(Iop_32to8, xer_ov) );
2495 putXER_OV32( unop(Iop_32to8, xer_ov) );
2498 static IRExpr* calculate_XER_OV_64( UInt op, IRExpr* res,
2499 IRExpr* argL, IRExpr* argR )
2501 IRExpr* xer_ov;
2503 # define INT64_MIN 0x8000000000000000ULL
2505 # define XOR2(_aa,_bb) \
2506 binop(Iop_Xor64,(_aa),(_bb))
2508 # define XOR3(_cc,_dd,_ee) \
2509 binop(Iop_Xor64,binop(Iop_Xor64,(_cc),(_dd)),(_ee))
2511 # define AND3(_ff,_gg,_hh) \
2512 binop(Iop_And64,binop(Iop_And64,(_ff),(_gg)),(_hh))
2514 #define NOT(_jj) \
2515 unop(Iop_Not64, (_jj))
2517 switch (op) {
2518 case /* 0 */ PPCG_FLAG_OP_ADD:
2519 case /* 1 */ PPCG_FLAG_OP_ADDE:
2520 /* (argL^argR^-1) & (argL^res) & (1<<63) ? 1:0 */
2521 // i.e. ((both_same_sign) & (sign_changed) & (sign_mask))
2522 xer_ov
2523 = AND3( XOR3(argL,argR,mkU64(-1)),
2524 XOR2(argL,res),
2525 mkU64(INT64_MIN) );
2526 /* xer_ov can only be 0 or 1<<63 */
2527 xer_ov
2528 = unop(Iop_64to1, binop(Iop_Shr64, xer_ov, mkU8(63)));
2529 break;
2531 case /* 2 */ PPCG_FLAG_OP_DIVW:
2532 /* (argL == INT64_MIN && argR == -1) || argR == 0 */
2533 xer_ov
2534 = mkOR1(
2535 mkAND1(
2536 binop(Iop_CmpEQ64, argL, mkU64(INT64_MIN)),
2537 binop(Iop_CmpEQ64, argR, mkU64(-1))
2539 binop(Iop_CmpEQ64, argR, mkU64(0) )
2541 break;
2543 case /* 3 */ PPCG_FLAG_OP_DIVWU:
2544 /* argR == 0 */
2545 xer_ov
2546 = binop(Iop_CmpEQ64, argR, mkU64(0));
2547 break;
2549 case /* 4 */ PPCG_FLAG_OP_MULLW: {
2550 /* OV true if result can't be represented in 64 bits
2551 i.e sHi != sign extension of sLo */
2552 xer_ov
2553 = binop( Iop_CmpNE32,
2554 unop(Iop_64HIto32, res),
2555 binop( Iop_Sar32,
2556 unop(Iop_64to32, res),
2557 mkU8(31))
2559 break;
2562 case /* 5 */ PPCG_FLAG_OP_NEG:
2563 /* argL == INT64_MIN */
2564 xer_ov
2565 = binop(Iop_CmpEQ64, argL, mkU64(INT64_MIN));
2566 break;
2568 case /* 6 */ PPCG_FLAG_OP_SUBF:
2569 case /* 7 */ PPCG_FLAG_OP_SUBFC:
2570 case /* 8 */ PPCG_FLAG_OP_SUBFE:
2571 /* ((~argL)^argR^-1) & ((~argL)^res) & (1<<63) ?1:0; */
2572 xer_ov
2573 = AND3( XOR3(NOT(argL),argR,mkU64(-1)),
2574 XOR2(NOT(argL),res),
2575 mkU64(INT64_MIN) );
2576 /* xer_ov can only be 0 or 1<<63 */
2577 xer_ov
2578 = unop(Iop_64to1, binop(Iop_Shr64, xer_ov, mkU8(63)));
2579 break;
2581 case /* 14 */ PPCG_FLAG_OP_DIVDE:
2583 /* If argR == 0, we must set the OV bit. But there's another condition
2584 * where we can get overflow set for divde . . . when the
2585 * result cannot fit in the 64-bit destination register. If dest reg is 0 AND
2586 * both dividend and divisor are non-zero, it implies an overflow.
2588 xer_ov
2589 = mkOR1( binop( Iop_CmpEQ64, argR, mkU64( 0 ) ),
2590 mkAND1( binop( Iop_CmpEQ64, res, mkU64( 0 ) ),
2591 mkAND1( binop( Iop_CmpNE64, argL, mkU64( 0 ) ),
2592 binop( Iop_CmpNE64, argR, mkU64( 0 ) ) ) ) );
2593 break;
2595 case /* 17 */ PPCG_FLAG_OP_DIVDEU:
2596 /* If argR == 0 or if argL >= argR, set OV. */
2597 xer_ov = mkOR1( binop( Iop_CmpEQ64, argR, mkU64( 0 ) ),
2598 binop( Iop_CmpLE64U, argR, argL ) );
2599 break;
2601 case /* 18 */ PPCG_FLAG_OP_MULLD: {
2602 IRTemp t128;
2603 /* OV true if result can't be represented in 64 bits
2604 i.e sHi != sign extension of sLo */
2605 t128 = newTemp(Ity_I128);
2606 assign( t128, binop(Iop_MullS64, argL, argR) );
2607 xer_ov
2608 = binop( Iop_CmpNE64,
2609 unop(Iop_128HIto64, mkexpr(t128)),
2610 binop( Iop_Sar64,
2611 unop(Iop_128to64, mkexpr(t128)),
2612 mkU8(63))
2614 break;
2617 default:
2618 vex_printf("calculate_XER_OV_64: op = %u\n", op);
2619 vpanic("calculate_XER_OV_64(ppc64)");
2622 return xer_ov;
2624 # undef INT64_MIN
2625 # undef AND3
2626 # undef XOR3
2627 # undef XOR2
2628 # undef NOT
2631 static void set_XER_OV_64( UInt op, IRExpr* res,
2632 IRExpr* argL, IRExpr* argR )
2634 IRExpr* xer_ov;
2635 vassert(op < PPCG_FLAG_OP_NUMBER);
2636 vassert(typeOfIRExpr(irsb->tyenv,res) == Ity_I64);
2637 vassert(typeOfIRExpr(irsb->tyenv,argL) == Ity_I64);
2638 vassert(typeOfIRExpr(irsb->tyenv,argR) == Ity_I64);
2640 /* xer_ov MUST denote either 0 or 1, no other value allowed */
2641 xer_ov = calculate_XER_OV_64( op, res, argL, argR);
2642 putXER_OV( unop(Iop_1Uto8, xer_ov) );
2644 /* Update the summary overflow */
2645 putXER_SO( binop(Iop_Or8, getXER_SO(), getXER_OV()) );
2648 static void update_SO( void ) {
2649 /* Update the summary overflow bit */
2650 putXER_SO( binop(Iop_Or8, getXER_SO(), getXER_OV()) );
2653 static void copy_OV_to_OV32( void ) {
2654 /* Update the OV32 to match OV */
2655 putXER_OV32( getXER_OV() );
2658 static void set_XER_OV_OV32_SO ( IRType ty, UInt op, IRExpr* res,
2659 IRExpr* argL, IRExpr* argR )
2661 if (ty == Ity_I32) {
2662 set_XER_OV_OV32_32( op, res, argL, argR );
2663 } else {
2664 IRExpr* xer_ov_32;
2665 set_XER_OV_64( op, res, argL, argR );
2666 xer_ov_32 = calculate_XER_OV_32( op, unop(Iop_64to32, res),
2667 unop(Iop_64to32, argL),
2668 unop(Iop_64to32, argR));
2669 putXER_OV32( unop(Iop_32to8, xer_ov_32) );
2671 update_SO();
2676 /* RES is the result of doing OP on ARGL and ARGR with the old %XER.CA
2677 value being OLDCA. Set %XER.CA accordingly. */
2679 static IRExpr* calculate_XER_CA_32 ( UInt op, IRExpr* res,
2680 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
2682 IRExpr* xer_ca;
2684 switch (op) {
2685 case /* 0 */ PPCG_FLAG_OP_ADD:
2686 /* res <u argL */
2687 xer_ca
2688 = unop(Iop_1Uto32, binop(Iop_CmpLT32U, res, argL));
2689 break;
2691 case /* 1 */ PPCG_FLAG_OP_ADDE:
2692 /* res <u argL || (old_ca==1 && res==argL) */
2693 xer_ca
2694 = mkOR1(
2695 binop(Iop_CmpLT32U, res, argL),
2696 mkAND1(
2697 binop(Iop_CmpEQ32, oldca, mkU32(1)),
2698 binop(Iop_CmpEQ32, res, argL)
2701 xer_ca
2702 = unop(Iop_1Uto32, xer_ca);
2703 break;
2705 case /* 8 */ PPCG_FLAG_OP_SUBFE:
2706 /* res <u argR || (old_ca==1 && res==argR) */
2707 xer_ca
2708 = mkOR1(
2709 binop(Iop_CmpLT32U, res, argR),
2710 mkAND1(
2711 binop(Iop_CmpEQ32, oldca, mkU32(1)),
2712 binop(Iop_CmpEQ32, res, argR)
2715 xer_ca
2716 = unop(Iop_1Uto32, xer_ca);
2717 break;
2719 case /* 7 */ PPCG_FLAG_OP_SUBFC:
2720 case /* 9 */ PPCG_FLAG_OP_SUBFI:
2721 /* res <=u argR */
2722 xer_ca
2723 = unop(Iop_1Uto32, binop(Iop_CmpLE32U, res, argR));
2724 break;
2726 case /* 10 */ PPCG_FLAG_OP_SRAW:
2727 /* The shift amount is guaranteed to be in 0 .. 63 inclusive.
2728 If it is <= 31, behave like SRAWI; else XER.CA is the sign
2729 bit of argL. */
2730 /* This term valid for shift amount < 32 only */
2731 xer_ca
2732 = binop(
2733 Iop_And32,
2734 binop(Iop_Sar32, argL, mkU8(31)),
2735 binop( Iop_And32,
2736 argL,
2737 binop( Iop_Sub32,
2738 binop(Iop_Shl32, mkU32(1),
2739 unop(Iop_32to8,argR)),
2740 mkU32(1) )
2743 xer_ca
2744 = IRExpr_ITE(
2745 /* shift amt > 31 ? */
2746 binop(Iop_CmpLT32U, mkU32(31), argR),
2747 /* yes -- get sign bit of argL */
2748 binop(Iop_Shr32, argL, mkU8(31)),
2749 /* no -- be like srawi */
2750 unop(Iop_1Uto32, binop(Iop_CmpNE32, xer_ca, mkU32(0)))
2752 break;
2754 case /* 11 */ PPCG_FLAG_OP_SRAWI:
2755 /* xer_ca is 1 iff src was negative and bits_shifted_out !=
2756 0. Since the shift amount is known to be in the range
2757 0 .. 31 inclusive the following seems viable:
2758 xer.ca == 1 iff the following is nonzero:
2759 (argL >>s 31) -- either all 0s or all 1s
2760 & (argL & (1<<argR)-1) -- the stuff shifted out */
2761 xer_ca
2762 = binop(
2763 Iop_And32,
2764 binop(Iop_Sar32, argL, mkU8(31)),
2765 binop( Iop_And32,
2766 argL,
2767 binop( Iop_Sub32,
2768 binop(Iop_Shl32, mkU32(1),
2769 unop(Iop_32to8,argR)),
2770 mkU32(1) )
2773 xer_ca
2774 = unop(Iop_1Uto32, binop(Iop_CmpNE32, xer_ca, mkU32(0)));
2775 break;
2777 default:
2778 vex_printf("set_XER_CA: op = %u\n", op);
2779 vpanic("set_XER_CA(ppc)");
2782 return xer_ca;
2785 static void set_XER_CA_32 ( UInt op, IRExpr* res,
2786 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
2788 IRExpr* xer_ca;
2789 vassert(op < PPCG_FLAG_OP_NUMBER);
2790 vassert(typeOfIRExpr(irsb->tyenv,res) == Ity_I32);
2791 vassert(typeOfIRExpr(irsb->tyenv,argL) == Ity_I32);
2792 vassert(typeOfIRExpr(irsb->tyenv,argR) == Ity_I32);
2793 vassert(typeOfIRExpr(irsb->tyenv,oldca) == Ity_I32);
2795 /* Incoming oldca is assumed to hold the values 0 or 1 only. This
2796 seems reasonable given that it's always generated by
2797 getXER_CA_32(), which masks it accordingly. In any case it being
2798 0 or 1 is an invariant of the ppc guest state representation;
2799 if it has any other value, that invariant has been violated. */
2801 xer_ca = calculate_XER_CA_32( op, res, argL, argR, oldca);
2803 /* xer_ca MUST denote either 0 or 1, no other value allowed */
2804 putXER_CA( unop(Iop_32to8, xer_ca) );
2807 static IRExpr* calculate_XER_CA_64 ( UInt op, IRExpr* res,
2808 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
2810 IRExpr* xer_ca;
2812 switch (op) {
2813 case /* 0 */ PPCG_FLAG_OP_ADD:
2814 /* res <u argL */
2815 xer_ca
2816 = unop(Iop_1Uto32, binop(Iop_CmpLT64U, res, argL));
2817 break;
2819 case /* 1 */ PPCG_FLAG_OP_ADDE:
2820 /* res <u argL || (old_ca==1 && res==argL) */
2821 xer_ca
2822 = mkOR1(
2823 binop(Iop_CmpLT64U, res, argL),
2824 mkAND1(
2825 binop(Iop_CmpEQ64, oldca, mkU64(1)),
2826 binop(Iop_CmpEQ64, res, argL)
2829 xer_ca
2830 = unop(Iop_1Uto32, xer_ca);
2831 break;
2833 case /* 8 */ PPCG_FLAG_OP_SUBFE:
2834 /* res <u argR || (old_ca==1 && res==argR) */
2835 xer_ca
2836 = mkOR1(
2837 binop(Iop_CmpLT64U, res, argR),
2838 mkAND1(
2839 binop(Iop_CmpEQ64, oldca, mkU64(1)),
2840 binop(Iop_CmpEQ64, res, argR)
2843 xer_ca
2844 = unop(Iop_1Uto32, xer_ca);
2845 break;
2847 case /* 7 */ PPCG_FLAG_OP_SUBFC:
2848 case /* 9 */ PPCG_FLAG_OP_SUBFI:
2849 /* res <=u argR */
2850 xer_ca
2851 = unop(Iop_1Uto32, binop(Iop_CmpLE64U, res, argR));
2852 break;
2855 case /* 10 */ PPCG_FLAG_OP_SRAW:
2856 /* The shift amount is guaranteed to be in 0 .. 31 inclusive.
2857 If it is <= 31, behave like SRAWI; else XER.CA is the sign
2858 bit of argL. */
2859 /* This term valid for shift amount < 31 only */
2861 xer_ca
2862 = binop(
2863 Iop_And64,
2864 binop(Iop_Sar64, argL, mkU8(31)),
2865 binop( Iop_And64,
2866 argL,
2867 binop( Iop_Sub64,
2868 binop(Iop_Shl64, mkU64(1),
2869 unop(Iop_64to8,argR)),
2870 mkU64(1) )
2873 xer_ca
2874 = IRExpr_ITE(
2875 /* shift amt > 31 ? */
2876 binop(Iop_CmpLT64U, mkU64(31), argR),
2877 /* yes -- get sign bit of argL */
2878 unop(Iop_64to32, binop(Iop_Shr64, argL, mkU8(63))),
2879 /* no -- be like srawi */
2880 unop(Iop_1Uto32, binop(Iop_CmpNE64, xer_ca, mkU64(0)))
2882 break;
2884 case /* 11 */ PPCG_FLAG_OP_SRAWI:
2885 /* xer_ca is 1 iff src was negative and bits_shifted_out != 0.
2886 Since the shift amount is known to be in the range 0 .. 31
2887 inclusive the following seems viable:
2888 xer.ca == 1 iff the following is nonzero:
2889 (argL >>s 31) -- either all 0s or all 1s
2890 & (argL & (1<<argR)-1) -- the stuff shifted out */
2892 xer_ca
2893 = binop(
2894 Iop_And64,
2895 binop(Iop_Sar64, argL, mkU8(31)),
2896 binop( Iop_And64,
2897 argL,
2898 binop( Iop_Sub64,
2899 binop(Iop_Shl64, mkU64(1),
2900 unop(Iop_64to8,argR)),
2901 mkU64(1) )
2904 xer_ca
2905 = unop(Iop_1Uto32, binop(Iop_CmpNE64, xer_ca, mkU64(0)));
2906 break;
2909 case /* 12 */ PPCG_FLAG_OP_SRAD:
2910 /* The shift amount is guaranteed to be in 0 .. 63 inclusive.
2911 If it is <= 63, behave like SRADI; else XER.CA is the sign
2912 bit of argL. */
2913 /* This term valid for shift amount < 63 only */
2915 xer_ca
2916 = binop(
2917 Iop_And64,
2918 binop(Iop_Sar64, argL, mkU8(63)),
2919 binop( Iop_And64,
2920 argL,
2921 binop( Iop_Sub64,
2922 binop(Iop_Shl64, mkU64(1),
2923 unop(Iop_64to8,argR)),
2924 mkU64(1) )
2927 xer_ca
2928 = IRExpr_ITE(
2929 /* shift amt > 63 ? */
2930 binop(Iop_CmpLT64U, mkU64(63), argR),
2931 /* yes -- get sign bit of argL */
2932 unop(Iop_64to32, binop(Iop_Shr64, argL, mkU8(63))),
2933 /* no -- be like sradi */
2934 unop(Iop_1Uto32, binop(Iop_CmpNE64, xer_ca, mkU64(0)))
2936 break;
2939 case /* 13 */ PPCG_FLAG_OP_SRADI:
2940 /* xer_ca is 1 iff src was negative and bits_shifted_out != 0.
2941 Since the shift amount is known to be in the range 0 .. 63
2942 inclusive, the following seems viable:
2943 xer.ca == 1 iff the following is nonzero:
2944 (argL >>s 63) -- either all 0s or all 1s
2945 & (argL & (1<<argR)-1) -- the stuff shifted out */
2947 xer_ca
2948 = binop(
2949 Iop_And64,
2950 binop(Iop_Sar64, argL, mkU8(63)),
2951 binop( Iop_And64,
2952 argL,
2953 binop( Iop_Sub64,
2954 binop(Iop_Shl64, mkU64(1),
2955 unop(Iop_64to8,argR)),
2956 mkU64(1) )
2959 xer_ca
2960 = unop(Iop_1Uto32, binop(Iop_CmpNE64, xer_ca, mkU64(0)));
2961 break;
2963 default:
2964 vex_printf("set_XER_CA: op = %u\n", op);
2965 vpanic("set_XER_CA(ppc64)");
2968 return xer_ca;
2971 static void set_XER_CA_64 ( UInt op, IRExpr* res,
2972 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
2974 IRExpr* xer_ca;
2975 vassert(op < PPCG_FLAG_OP_NUMBER);
2976 vassert(typeOfIRExpr(irsb->tyenv,res) == Ity_I64);
2977 vassert(typeOfIRExpr(irsb->tyenv,argL) == Ity_I64);
2978 vassert(typeOfIRExpr(irsb->tyenv,argR) == Ity_I64);
2979 vassert(typeOfIRExpr(irsb->tyenv,oldca) == Ity_I64);
2981 /* Incoming oldca is assumed to hold the values 0 or 1 only. This
2982 seems reasonable given that it's always generated by
2983 getXER_CA_32(), which masks it accordingly. In any case it being
2984 0 or 1 is an invariant of the ppc guest state representation;
2985 if it has any other value, that invariant has been violated. */
2987 xer_ca = calculate_XER_CA_64( op, res, argL, argR, oldca );
2989 /* xer_ca MUST denote either 0 or 1, no other value allowed */
2990 putXER_CA( unop(Iop_32to8, xer_ca) );
2993 static void set_XER_CA_CA32 ( IRType ty, UInt op, IRExpr* res,
2994 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
2996 if (ty == Ity_I32) {
2997 set_XER_CA_32( op, res, argL, argR, oldca );
2998 } else {
2999 set_XER_CA_64( op, res, argL, argR, oldca );
3003 /* Used only by addex instruction, which uses and sets OV as carry. */
3004 static void set_XER_OV_OV32_ADDEX ( IRType ty, IRExpr* res,
3005 IRExpr* argL, IRExpr* argR,
3006 IRExpr* old_ov )
3008 if (ty == Ity_I32) {
3009 IRTemp xer_ov = newTemp(Ity_I32);
3010 assign ( xer_ov, unop(Iop_32to8,
3011 calculate_XER_CA_32( PPCG_FLAG_OP_ADDE,
3012 res, argL, argR, old_ov ) ) );
3013 putXER_OV( mkexpr (xer_ov) );
3014 putXER_OV32( mkexpr (xer_ov) );
3015 } else {
3016 IRExpr *xer_ov;
3017 IRExpr* xer_ov_32;
3018 xer_ov = calculate_XER_CA_64( PPCG_FLAG_OP_ADDE,
3019 res, argL, argR, old_ov );
3020 putXER_OV( unop(Iop_32to8, xer_ov) );
3021 xer_ov_32 = calculate_XER_CA_32( PPCG_FLAG_OP_ADDE,
3022 unop(Iop_64to32, res),
3023 unop(Iop_64to32, argL),
3024 unop(Iop_64to32, argR),
3025 unop(Iop_64to32, old_ov) );
3026 putXER_OV32( unop(Iop_32to8, xer_ov_32) );
3032 /*------------------------------------------------------------*/
3033 /*--- Read/write to guest-state --- */
3034 /*------------------------------------------------------------*/
3036 static IRExpr* /* :: Ity_I32/64 */ getGST ( PPC_GST reg )
3038 IRType ty = mode64 ? Ity_I64 : Ity_I32;
3039 switch (reg) {
3040 case PPC_GST_SPRG3_RO:
3041 return IRExpr_Get( OFFB_SPRG3_RO, ty );
3043 case PPC_GST_CIA:
3044 return IRExpr_Get( OFFB_CIA, ty );
3046 case PPC_GST_LR:
3047 return IRExpr_Get( OFFB_LR, ty );
3049 case PPC_GST_CTR:
3050 return IRExpr_Get( OFFB_CTR, ty );
3052 case PPC_GST_VRSAVE:
3053 return IRExpr_Get( OFFB_VRSAVE, Ity_I32 );
3055 case PPC_GST_VSCR:
3056 return binop(Iop_And32, IRExpr_Get( OFFB_VSCR,Ity_I32 ),
3057 mkU32(MASK_VSCR_VALID));
3059 case PPC_GST_CR: {
3060 /* Synthesise the entire CR into a single word. Expensive. */
3061 # define FIELD(_n) \
3062 binop(Iop_Shl32, \
3063 unop(Iop_8Uto32, \
3064 binop(Iop_Or8, \
3065 binop(Iop_And8, getCR321(_n), mkU8(7<<1)), \
3066 binop(Iop_And8, getCR0(_n), mkU8(1)) \
3068 ), \
3069 mkU8(4 * (7-(_n))) \
3071 return binop(Iop_Or32,
3072 binop(Iop_Or32,
3073 binop(Iop_Or32, FIELD(0), FIELD(1)),
3074 binop(Iop_Or32, FIELD(2), FIELD(3))
3076 binop(Iop_Or32,
3077 binop(Iop_Or32, FIELD(4), FIELD(5)),
3078 binop(Iop_Or32, FIELD(6), FIELD(7))
3081 # undef FIELD
3084 case PPC_GST_XER:
3085 return binop(Iop_Or32,
3086 binop(Iop_Or32,
3087 binop(Iop_Or32,
3088 binop( Iop_Shl32, getXER_SO_32(), mkU8(31)),
3089 binop( Iop_Shl32, getXER_OV_32(), mkU8(30))),
3090 binop(Iop_Or32,
3091 binop( Iop_Shl32, getXER_CA_32(), mkU8(29)),
3092 getXER_BC_32())),
3093 binop(Iop_Or32,
3094 binop( Iop_Shl32, getXER_OV32_32(), mkU8(19)),
3095 binop( Iop_Shl32, getXER_CA32_32(), mkU8(18))));
3097 case PPC_GST_TFHAR:
3098 return IRExpr_Get( OFFB_TFHAR, ty );
3100 case PPC_GST_TEXASR:
3101 return IRExpr_Get( OFFB_TEXASR, ty );
3103 case PPC_GST_TEXASRU:
3104 return IRExpr_Get( OFFB_TEXASRU, ty );
3106 case PPC_GST_TFIAR:
3107 return IRExpr_Get( OFFB_TFIAR, ty );
3109 case PPC_GST_PPR:
3110 return IRExpr_Get( OFFB_PPR, ty );
3112 case PPC_GST_PPR32:
3113 return unop( Iop_64HIto32, IRExpr_Get( OFFB_PPR, ty ) );
3115 case PPC_GST_PSPB:
3116 return IRExpr_Get( OFFB_PSPB, ty );
3118 case PPC_GST_DSCR:
3119 return IRExpr_Get( OFFB_DSCR, ty );
3121 default:
3122 vex_printf("getGST(ppc): reg = %u", reg);
3123 vpanic("getGST(ppc)");
3127 /* Get a masked word from the given reg */
3128 static IRExpr* /* ::Ity_I32 */ getGST_masked ( PPC_GST reg, ULong mask )
3130 IRTemp val = newTemp(Ity_I32);
3131 vassert( reg < PPC_GST_MAX );
3133 switch (reg) {
3135 case PPC_GST_FPSCR: {
3136 /* Vex-generated code expects the FPSCR to be set as follows:
3137 all exceptions masked, round-to-nearest.
3138 This corresponds to a FPSCR value of 0x0. */
3140 /* In the lower 32 bits of FPSCR, we're keeping track of the binary
3141 * floating point rounding mode and Floating-point Condition code, so
3142 * if the mask isn't asking for either of these, just return 0x0.
3144 if ( mask & ( MASK_FPSCR_C_FPCC | MASK_FPSCR_RN ) ) {
3145 assign( val, binop( Iop_Or32,
3146 unop( Iop_8Uto32, IRExpr_Get( OFFB_FPROUND, Ity_I8 ) ),
3147 binop( Iop_Shl32,
3148 unop( Iop_8Uto32,
3149 IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ),
3150 mkU8( 12 ) ) ) );
3151 } else {
3152 assign( val, mkU32(0x0) );
3155 break;
3158 default:
3159 vex_printf("getGST_masked(ppc): reg = %u", reg);
3160 vpanic("getGST_masked(ppc)");
3163 if ( mask != 0xFFFFFFFF ) {
3164 return binop(Iop_And32, mkexpr(val), mkU32(mask));
3165 } else {
3166 return mkexpr(val);
3170 /* Get a masked word from the given reg */
3171 static IRExpr* /* ::Ity_I32 */getGST_masked_upper(PPC_GST reg, ULong mask) {
3172 IRExpr * val;
3173 vassert( reg < PPC_GST_MAX );
3175 switch (reg) {
3177 case PPC_GST_FPSCR: {
3178 /* In the upper 32 bits of FPSCR, we're only keeping track
3179 * of the decimal floating point rounding mode, so if the mask
3180 * isn't asking for this, just return 0x0.
3182 if (mask & MASK_FPSCR_DRN) {
3183 val = binop( Iop_And32,
3184 unop( Iop_8Uto32, IRExpr_Get( OFFB_DFPROUND, Ity_I8 ) ),
3185 unop( Iop_64HIto32, mkU64( mask ) ) );
3186 } else {
3187 val = mkU32( 0x0ULL );
3189 break;
3192 default:
3193 vex_printf( "getGST_masked_upper(ppc): reg = %u", reg );
3194 vpanic( "getGST_masked_upper(ppc)" );
3196 return val;
3200 /* Fetch the specified REG[FLD] nibble (as per IBM/hardware notation)
3201 and return it at the bottom of an I32; the top 27 bits are
3202 guaranteed to be zero. */
3203 static IRExpr* /* ::Ity_I32 */ getGST_field ( PPC_GST reg, UInt fld )
3205 UInt shft, mask;
3207 vassert( fld < 8 );
3208 vassert( reg < PPC_GST_MAX );
3210 shft = 4*(7-fld);
3211 mask = 0xF<<shft;
3213 switch (reg) {
3214 case PPC_GST_XER:
3215 vassert(fld ==7);
3216 return binop(Iop_Or32,
3217 binop(Iop_Or32,
3218 binop(Iop_Shl32, getXER_SO_32(), mkU8(3)),
3219 binop(Iop_Shl32, getXER_OV_32(), mkU8(2))),
3220 binop( Iop_Shl32, getXER_CA_32(), mkU8(1)));
3221 break;
3223 default:
3224 if (shft == 0)
3225 return getGST_masked( reg, mask );
3226 else
3227 return binop(Iop_Shr32,
3228 getGST_masked( reg, mask ),
3229 mkU8(toUChar( shft )));
3233 static void putGST ( PPC_GST reg, IRExpr* src )
3235 IRType ty = mode64 ? Ity_I64 : Ity_I32;
3236 IRType ty_src = typeOfIRExpr(irsb->tyenv,src );
3237 vassert( reg < PPC_GST_MAX );
3238 switch (reg) {
3239 case PPC_GST_IP_AT_SYSCALL:
3240 vassert( ty_src == ty );
3241 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL, src ) );
3242 break;
3243 case PPC_GST_CIA:
3244 vassert( ty_src == ty );
3245 stmt( IRStmt_Put( OFFB_CIA, src ) );
3246 break;
3247 case PPC_GST_LR:
3248 vassert( ty_src == ty );
3249 stmt( IRStmt_Put( OFFB_LR, src ) );
3250 break;
3251 case PPC_GST_CTR:
3252 vassert( ty_src == ty );
3253 stmt( IRStmt_Put( OFFB_CTR, src ) );
3254 break;
3255 case PPC_GST_VRSAVE:
3256 vassert( ty_src == Ity_I32 );
3257 stmt( IRStmt_Put( OFFB_VRSAVE,src));
3258 break;
3259 case PPC_GST_VSCR:
3260 vassert( ty_src == Ity_I32 );
3261 stmt( IRStmt_Put( OFFB_VSCR,
3262 binop(Iop_And32, src,
3263 mkU32(MASK_VSCR_VALID)) ) );
3264 break;
3265 case PPC_GST_XER:
3266 vassert( ty_src == Ity_I32 );
3267 putXER_SO( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(31))) );
3268 putXER_OV( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(30))) );
3269 putXER_CA( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(29))) );
3270 putXER_OV32( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(19))) );
3271 putXER_CA32( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(18))) );
3272 putXER_BC( unop(Iop_32to8, src) );
3273 break;
3275 case PPC_GST_EMWARN:
3276 vassert( ty_src == Ity_I32 );
3277 stmt( IRStmt_Put( OFFB_EMNOTE,src) );
3278 break;
3280 case PPC_GST_CMSTART:
3281 vassert( ty_src == ty );
3282 stmt( IRStmt_Put( OFFB_CMSTART, src) );
3283 break;
3285 case PPC_GST_CMLEN:
3286 vassert( ty_src == ty );
3287 stmt( IRStmt_Put( OFFB_CMLEN, src) );
3288 break;
3290 case PPC_GST_TEXASR:
3291 vassert( ty_src == Ity_I64 );
3292 stmt( IRStmt_Put( OFFB_TEXASR, src ) );
3293 break;
3295 case PPC_GST_TEXASRU:
3296 vassert( ty_src == Ity_I32 );
3297 stmt( IRStmt_Put( OFFB_TEXASRU, src ) );
3298 break;
3300 case PPC_GST_TFIAR:
3301 vassert( ty_src == Ity_I64 );
3302 stmt( IRStmt_Put( OFFB_TFIAR, src ) );
3303 break;
3304 case PPC_GST_TFHAR:
3305 vassert( ty_src == Ity_I64 );
3306 stmt( IRStmt_Put( OFFB_TFHAR, src ) );
3307 break;
3309 case PPC_GST_PPR32:
3310 case PPC_GST_PPR:
3312 /* The Program Priority Register (PPR) stores the priority in
3313 * bits [52:50]. The user setable priorities are:
3315 * 001 very low
3316 * 010 low
3317 * 011 medium low
3318 * 100 medium
3319 * 101 medium high
3321 * If the argument is not between 0b001 and 0b100 the priority is set
3322 * to 0b100. The priority can only be set to 0b101 if the the Problem
3323 * State Boost Register is non-zero. The value of the PPR is not
3324 * changed if the input is not valid.
3327 IRTemp not_valid = newTemp(Ity_I64);
3328 IRTemp has_perm = newTemp(Ity_I64);
3329 IRTemp new_src = newTemp(Ity_I64);
3330 IRTemp PSPB_val = newTemp(Ity_I64);
3331 IRTemp value = newTemp(Ity_I64);
3333 vassert(( ty_src == Ity_I64 ) || ( ty_src == Ity_I32 ));
3334 assign( PSPB_val, binop( Iop_32HLto64,
3335 mkU32( 0 ),
3336 IRExpr_Get( OFFB_PSPB, Ity_I32 ) ) );
3337 if( reg == PPC_GST_PPR32 ) {
3338 vassert( ty_src == Ity_I32 );
3339 assign( value, binop( Iop_32HLto64,
3340 mkU32(0),
3341 binop( Iop_And32,
3342 binop( Iop_Shr32, src, mkU8( 18 ) ),
3343 mkU32( 0x7 ) ) ) );
3344 } else {
3345 vassert( ty_src == Ity_I64 );
3346 assign( value, binop( Iop_And64,
3347 binop( Iop_Shr64, src, mkU8( 50 ) ),
3348 mkU64( 0x7 ) ) );
3350 assign( has_perm,
3351 binop( Iop_And64,
3352 unop( Iop_1Sto64,
3353 binop( Iop_CmpEQ64,
3354 mkexpr( PSPB_val ),
3355 mkU64( 0 ) ) ),
3356 unop( Iop_1Sto64,
3357 binop( Iop_CmpEQ64,
3358 mkU64( 0x5 ),
3359 mkexpr( value ) ) ) ) );
3360 assign( not_valid,
3361 binop( Iop_Or64,
3362 unop( Iop_1Sto64,
3363 binop( Iop_CmpEQ64,
3364 mkexpr( value ),
3365 mkU64( 0 ) ) ),
3366 unop( Iop_1Sto64,
3367 binop( Iop_CmpLT64U,
3368 mkU64( 0x5 ),
3369 mkexpr( value ) ) ) ) );
3370 assign( new_src,
3371 binop( Iop_Or64,
3372 binop( Iop_And64,
3373 unop( Iop_Not64,
3374 mkexpr( not_valid ) ),
3375 src ),
3376 binop( Iop_And64,
3377 mkexpr( not_valid ),
3378 binop( Iop_Or64,
3379 binop( Iop_And64,
3380 mkexpr( has_perm),
3381 binop( Iop_Shl64,
3382 mkexpr( value ),
3383 mkU8( 50 ) ) ),
3384 binop( Iop_And64,
3385 IRExpr_Get( OFFB_PPR, ty ),
3386 unop( Iop_Not64,
3387 mkexpr( has_perm )
3388 ) ) ) ) ) );
3390 /* make sure we only set the valid bit field [52:50] */
3391 stmt( IRStmt_Put( OFFB_PPR,
3392 binop( Iop_And64,
3393 mkexpr( new_src ),
3394 mkU64( 0x1C000000000000) ) ) );
3395 break;
3397 case PPC_GST_DSCR:
3398 vassert( ty_src == Ity_I64 );
3399 stmt( IRStmt_Put( OFFB_DSCR, src ) );
3400 break;
3402 default:
3403 vex_printf("putGST(ppc): reg = %u", reg);
3404 vpanic("putGST(ppc)");
3408 /* Write masked src to the given reg */
3409 static void putGST_masked ( PPC_GST reg, IRExpr* src, ULong mask )
3411 IRType ty = mode64 ? Ity_I64 : Ity_I32;
3412 vassert( reg < PPC_GST_MAX );
3413 vassert( typeOfIRExpr( irsb->tyenv,src ) == Ity_I64 );
3415 switch (reg) {
3416 case PPC_GST_FPSCR: {
3417 /* Allow writes to either binary or decimal floating point
3418 Rounding Mode.
3420 /* If any part of |mask| covers FPSCR.RN, update the bits of
3421 FPSCR.RN by copying in |src| for locations where the
3422 corresponding bit in |mask| is 1, and leaving it unchanged
3423 for corresponding |mask| zero bits. */
3424 if (mask & MASK_FPSCR_RN) {
3425 stmt(
3426 IRStmt_Put(
3427 OFFB_FPROUND,
3428 unop(
3429 Iop_32to8,
3430 binop(
3431 Iop_Or32,
3432 binop(
3433 Iop_And32,
3434 unop(Iop_64to32, src),
3435 mkU32(MASK_FPSCR_RN & mask)
3437 binop(
3438 Iop_And32,
3439 unop(Iop_8Uto32, IRExpr_Get(OFFB_FPROUND,Ity_I8)),
3440 mkU32(MASK_FPSCR_RN & ~mask)
3448 if (mask & MASK_FPSCR_C_FPCC) {
3449 /* FPCC bits are in [47:51] */
3450 stmt(
3451 IRStmt_Put(
3452 OFFB_C_FPCC,
3453 unop(
3454 Iop_32to8,
3455 binop(Iop_Shr32,
3456 binop(
3457 Iop_Or32,
3458 binop(
3459 Iop_And32,
3460 unop(Iop_64to32, src),
3461 mkU32(MASK_FPSCR_C_FPCC & mask) ),
3462 binop(
3463 Iop_And32,
3464 unop(Iop_8Uto32,
3465 IRExpr_Get(OFFB_C_FPCC,Ity_I8)),
3466 mkU32(MASK_FPSCR_C_FPCC & ~mask)
3467 ) ),
3468 mkU8( 12 ) )
3469 ) ) );
3472 /* Similarly, update FPSCR.DRN if any bits of |mask|
3473 corresponding to FPSCR.DRN are set. */
3474 if (mask & MASK_FPSCR_DRN) {
3475 stmt(
3476 IRStmt_Put(
3477 OFFB_DFPROUND,
3478 unop(
3479 Iop_32to8,
3480 binop(
3481 Iop_Or32,
3482 binop(
3483 Iop_And32,
3484 unop(Iop_64HIto32, src),
3485 mkU32((MASK_FPSCR_DRN & mask) >> 32)
3487 binop(
3488 Iop_And32,
3489 unop(Iop_8Uto32, IRExpr_Get(OFFB_DFPROUND,Ity_I8)),
3490 mkU32((MASK_FPSCR_DRN & ~mask) >> 32)
3498 /* Give EmNote for attempted writes to:
3499 - Exception Controls
3500 - Non-IEEE Mode
3502 if (mask & 0xFC) { // Exception Control, Non-IEE mode
3503 VexEmNote ew = EmWarn_PPCexns;
3505 /* If any of the src::exception_control bits are actually set,
3506 side-exit to the next insn, reporting the warning,
3507 so that Valgrind's dispatcher sees the warning. */
3508 putGST( PPC_GST_EMWARN, mkU32(ew) );
3509 stmt(
3510 IRStmt_Exit(
3511 binop(Iop_CmpNE32, mkU32(ew), mkU32(EmNote_NONE)),
3512 Ijk_EmWarn,
3513 mkSzConst( ty, nextInsnAddr()), OFFB_CIA ));
3516 /* Ignore all other writes */
3517 break;
3520 default:
3521 vex_printf("putGST_masked(ppc): reg = %u", reg);
3522 vpanic("putGST_masked(ppc)");
3526 /* Write the least significant nibble of src to the specified
3527 REG[FLD] (as per IBM/hardware notation). */
3528 static void putGST_field ( PPC_GST reg, IRExpr* src, UInt fld )
3530 UInt shft;
3531 ULong mask;
3533 vassert( typeOfIRExpr(irsb->tyenv,src ) == Ity_I32 );
3534 vassert( fld < 16 );
3535 vassert( reg < PPC_GST_MAX );
3537 if (fld < 8)
3538 shft = 4*(7-fld);
3539 else
3540 shft = 4*(15-fld);
3541 mask = 0xF;
3542 mask = mask << shft;
3544 switch (reg) {
3545 case PPC_GST_CR:
3546 putCR0 (fld, binop(Iop_And8, mkU8(1 ), unop(Iop_32to8, src)));
3547 putCR321(fld, binop(Iop_And8, mkU8(7<<1), unop(Iop_32to8, src)));
3548 break;
3550 default:
3552 IRExpr * src64 = unop( Iop_32Uto64, src );
3554 if (shft == 0) {
3555 putGST_masked( reg, src64, mask );
3556 } else {
3557 putGST_masked( reg,
3558 binop( Iop_Shl64, src64, mkU8( toUChar( shft ) ) ),
3559 mask );
3565 static void putFPCC ( IRExpr* e )
3567 /* The assumption is that the value of the FPCC are passed in the lower
3568 * four bits of a 32 bit value.
3570 * Note, the C and FPCC bits which are a field of the FPSCR
3571 * register are stored in their own "register" in
3572 * memory. The FPCC bits are in the lower 4 bits. We don't need to
3573 * shift it to the bits to their location in the FPSCR register. Note,
3574 * not all of the FPSCR register bits are supported. We are writing all
3575 * of the bits in the FPCC field but not the C field.
3577 IRExpr* tmp;
3579 vassert( typeOfIRExpr( irsb->tyenv, e ) == Ity_I32 );
3580 /* Get the C bit field */
3581 tmp = binop( Iop_And32,
3582 mkU32( 0x10 ),
3583 unop( Iop_8Uto32, IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ) );
3585 stmt( IRStmt_Put( OFFB_C_FPCC,
3586 unop( Iop_32to8,
3587 binop( Iop_Or32, tmp,
3588 binop( Iop_And32, mkU32( 0xF ), e ) ) ) ) );
3592 static IRExpr* /* ::Ity_I32 */ getC ( void )
3594 /* Note, the Floating-Point Result Class Descriptor (C) bit is a field of
3595 * the FPSCR registered are stored in its own "register" in guest state
3596 * with the FPCC bit field. C | FPCC
3598 IRTemp val = newTemp(Ity_I32);
3600 assign( val, binop( Iop_Shr32,
3601 unop( Iop_8Uto32, IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ),
3602 mkU8( 4 ) ) );
3603 return mkexpr(val);
3606 static IRExpr* /* ::Ity_I32 */ getFPCC ( void )
3608 /* Note, the FPCC bits are a field of the FPSCR
3609 * register are stored in their own "register" in
3610 * guest state with the C bit field. C | FPCC
3612 IRTemp val = newTemp( Ity_I32 );
3614 assign( val, binop( Iop_And32, unop( Iop_8Uto32,
3615 IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ),
3616 mkU32( 0xF ) ));
3617 return mkexpr(val);
3620 /*------------------------------------------------------------*/
3621 /* Helpers for VSX instructions that do floating point
3622 * operations and need to determine if a src contains a
3623 * special FP value.
3625 *------------------------------------------------------------*/
3627 #define NONZERO_FRAC_MASK 0x000fffffffffffffULL
3628 #define FP_FRAC_PART(x) binop( Iop_And64, \
3629 mkexpr( x ), \
3630 mkU64( NONZERO_FRAC_MASK ) )
3632 #define NONZERO_FRAC_MASK32 0x007fffffULL
3633 #define FP_FRAC_PART32(x) binop( Iop_And32, \
3634 mkexpr( x ), \
3635 mkU32( NONZERO_FRAC_MASK32 ) )
3637 // Returns exponent part of floating point src as I32
3638 static IRExpr * fp_exp_part( IRType size, IRTemp src )
3640 IRExpr *shift_by, *mask, *tsrc;
3642 vassert( ( size == Ity_I16 ) || ( size == Ity_I32 )
3643 || ( size == Ity_I64 ) );
3645 if( size == Ity_I16 ) {
3646 /* The 16-bit floating point value is in the lower 16-bits
3647 * of the 32-bit input value.
3649 tsrc = mkexpr( src );
3650 mask = mkU32( 0x1F );
3651 shift_by = mkU8( 10 );
3653 } else if( size == Ity_I32 ) {
3654 tsrc = mkexpr( src );
3655 mask = mkU32( 0xFF );
3656 shift_by = mkU8( 23 );
3658 } else if( size == Ity_I64 ) {
3659 tsrc = unop( Iop_64HIto32, mkexpr( src ) );
3660 mask = mkU32( 0x7FF );
3661 shift_by = mkU8( 52 - 32 );
3663 } else {
3664 /*NOTREACHED*/
3665 vassert(0); // Stops gcc complaining at "-Og"
3668 return binop( Iop_And32, binop( Iop_Shr32, tsrc, shift_by ), mask );
3671 /* The following functions check the floating point value to see if it
3672 is zero, infinity, NaN, Normalized, Denormalized.
3674 /* 16-bit floating point number is stored in the lower 16-bits of 32-bit value */
3675 #define I16_EXP_MASK 0x7C00
3676 #define I16_FRACTION_MASK 0x03FF
3677 #define I16_MSB_FRACTION_MASK 0x0200
3678 #define I32_EXP_MASK 0x7F800000
3679 #define I32_FRACTION_MASK 0x007FFFFF
3680 #define I32_MSB_FRACTION_MASK 0x00400000
3681 #define I32_SIGN_MASK 0x80000000
3682 #define I64_EXP_MASK 0x7FF0000000000000ULL
3683 #define I64_FRACTION_MASK 0x000FFFFFFFFFFFFFULL
3684 #define I64_MSB_FRACTION_MASK 0x0008000000000000ULL
3685 #define V128_EXP_MASK 0x7FFF000000000000ULL
3686 #define V128_FRACTION_MASK 0x0000FFFFFFFFFFFFULL /* upper 64-bit fractional mask */
3687 #define V128_MSB_FRACTION_MASK 0x0000800000000000ULL /* upper 64-bit fractional mask */
3689 void setup_value_check_args( IRType size, IRTemp *exp_mask, IRTemp *frac_mask,
3690 IRTemp *msb_frac_mask, IRTemp *zero );
3692 void setup_value_check_args( IRType size, IRTemp *exp_mask, IRTemp *frac_mask,
3693 IRTemp *msb_frac_mask, IRTemp *zero ) {
3695 vassert( ( size == Ity_I16 ) || ( size == Ity_I32 )
3696 || ( size == Ity_I64 ) || ( size == Ity_V128 ) );
3698 if( size == Ity_I16 ) {
3699 /* The 16-bit floating point value is in the lower 16-bits of
3700 the 32-bit input value */
3701 *frac_mask = newTemp( Ity_I32 );
3702 *msb_frac_mask = newTemp( Ity_I32 );
3703 *exp_mask = newTemp( Ity_I32 );
3704 *zero = newTemp( Ity_I32 );
3705 assign( *exp_mask, mkU32( I16_EXP_MASK ) );
3706 assign( *frac_mask, mkU32( I16_FRACTION_MASK ) );
3707 assign( *msb_frac_mask, mkU32( I16_MSB_FRACTION_MASK ) );
3708 assign( *zero, mkU32( 0 ) );
3710 } else if( size == Ity_I32 ) {
3711 *frac_mask = newTemp( Ity_I32 );
3712 *msb_frac_mask = newTemp( Ity_I32 );
3713 *exp_mask = newTemp( Ity_I32 );
3714 *zero = newTemp( Ity_I32 );
3715 assign( *exp_mask, mkU32( I32_EXP_MASK ) );
3716 assign( *frac_mask, mkU32( I32_FRACTION_MASK ) );
3717 assign( *msb_frac_mask, mkU32( I32_MSB_FRACTION_MASK ) );
3718 assign( *zero, mkU32( 0 ) );
3720 } else if( size == Ity_I64 ) {
3721 *frac_mask = newTemp( Ity_I64 );
3722 *msb_frac_mask = newTemp( Ity_I64 );
3723 *exp_mask = newTemp( Ity_I64 );
3724 *zero = newTemp( Ity_I64 );
3725 assign( *exp_mask, mkU64( I64_EXP_MASK ) );
3726 assign( *frac_mask, mkU64( I64_FRACTION_MASK ) );
3727 assign( *msb_frac_mask, mkU64( I64_MSB_FRACTION_MASK ) );
3728 assign( *zero, mkU64( 0 ) );
3730 } else {
3731 /* V128 is converted to upper and lower 64 bit values, */
3732 /* uses 64-bit operators and temps */
3733 *frac_mask = newTemp( Ity_I64 );
3734 *msb_frac_mask = newTemp( Ity_I64 );
3735 *exp_mask = newTemp( Ity_I64 );
3736 *zero = newTemp( Ity_I64 );
3737 assign( *exp_mask, mkU64( V128_EXP_MASK ) );
3738 /* upper 64-bit fractional mask */
3739 assign( *frac_mask, mkU64( V128_FRACTION_MASK ) );
3740 assign( *msb_frac_mask, mkU64( V128_MSB_FRACTION_MASK ) );
3741 assign( *zero, mkU64( 0 ) );
3745 /* Helper function for the various function which check the value of
3746 the floating point value.
3748 static IRExpr * exponent_compare( IRType size, IRTemp src,
3749 IRTemp exp_mask, IRExpr *exp_val )
3751 IROp opAND, opCmpEQ;
3753 if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
3754 /* The 16-bit floating point value is in the lower 16-bits of
3755 the 32-bit input value */
3756 opAND = Iop_And32;
3757 opCmpEQ = Iop_CmpEQ32;
3759 } else {
3760 opAND = Iop_And64;
3761 opCmpEQ = Iop_CmpEQ64;
3764 if( size == Ity_V128 ) {
3765 return binop( opCmpEQ,
3766 binop ( opAND,
3767 unop( Iop_V128HIto64, mkexpr( src ) ),
3768 mkexpr( exp_mask ) ),
3769 exp_val );
3771 } else if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
3772 return binop( opCmpEQ,
3773 binop ( opAND, mkexpr( src ), mkexpr( exp_mask ) ),
3774 exp_val );
3775 } else {
3776 /* 64-bit operands */
3778 if (mode64) {
3779 return binop( opCmpEQ,
3780 binop ( opAND, mkexpr( src ), mkexpr( exp_mask ) ),
3781 exp_val );
3782 } else {
3783 /* No support for 64-bit compares in 32-bit mode, need to do upper
3784 * and lower parts using 32-bit compare operators.
3786 return
3787 mkAND1( binop( Iop_CmpEQ32,
3788 binop ( Iop_And32,
3789 unop(Iop_64HIto32, mkexpr( src ) ),
3790 unop(Iop_64HIto32, mkexpr( exp_mask ) ) ),
3791 unop(Iop_64HIto32, exp_val ) ),
3792 binop( Iop_CmpEQ32,
3793 binop ( Iop_And32,
3794 unop(Iop_64to32, mkexpr( src ) ),
3795 unop(Iop_64to32, mkexpr( exp_mask ) ) ),
3796 unop(Iop_64to32, exp_val ) ) );
3801 static IRExpr *fractional_part_compare( IRType size, IRTemp src,
3802 IRTemp frac_mask, IRExpr *zero )
3804 IROp opAND, opCmpEQ;
3806 if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
3807 /*The 16-bit floating point value is in the lower 16-bits of
3808 the 32-bit input value */
3809 opAND = Iop_And32;
3810 opCmpEQ = Iop_CmpEQ32;
3812 } else {
3813 opAND = Iop_And64;
3814 opCmpEQ = Iop_CmpEQ64;
3817 if( size == Ity_V128 ) {
3818 /* 128-bit, note we only care if the fractional part is zero so take upper
3819 52-bits of fractional part and lower 64-bits and OR them together and test
3820 for zero. This keeps the temp variables and operators all 64-bit.
3822 return binop( opCmpEQ,
3823 binop( Iop_Or64,
3824 binop( opAND,
3825 unop( Iop_V128HIto64, mkexpr( src ) ),
3826 mkexpr( frac_mask ) ),
3827 unop( Iop_V128to64, mkexpr( src ) ) ),
3828 zero );
3830 } else if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
3831 return binop( opCmpEQ,
3832 binop( opAND, mkexpr( src ), mkexpr( frac_mask ) ),
3833 zero );
3834 } else {
3835 if (mode64) {
3836 return binop( opCmpEQ,
3837 binop( opAND, mkexpr( src ), mkexpr( frac_mask ) ),
3838 zero );
3839 } else {
3840 /* No support for 64-bit compares in 32-bit mode, need to do upper
3841 * and lower parts using 32-bit compare operators.
3843 return
3844 mkAND1( binop( Iop_CmpEQ32,
3845 binop ( Iop_And32,
3846 unop(Iop_64HIto32, mkexpr( src ) ),
3847 unop(Iop_64HIto32, mkexpr( frac_mask ) ) ),
3848 mkU32 ( 0 ) ),
3849 binop( Iop_CmpEQ32,
3850 binop ( Iop_And32,
3851 unop(Iop_64to32, mkexpr( src ) ),
3852 unop(Iop_64to32, mkexpr( frac_mask ) ) ),
3853 mkU32 ( 0 ) ) );
3858 // Infinity: exp has all bits set, and fraction is zero; s = 0/1
3859 static IRExpr * is_Inf( IRType size, IRTemp src )
3861 IRExpr *max_exp, *zero_frac;
3862 IRTemp exp_mask, frac_mask, msb_frac_mask, zero;
3864 setup_value_check_args( size, &exp_mask, &frac_mask, &msb_frac_mask,
3865 &zero );
3867 /* check exponent is all ones, i.e. (exp AND exp_mask) = exp_mask */
3868 max_exp = exponent_compare( size, src, exp_mask, mkexpr( exp_mask ) );
3870 /* check fractional part is all zeros */
3871 zero_frac = fractional_part_compare( size, src, frac_mask, mkexpr( zero ) );
3873 return mkAND1( max_exp, zero_frac );
3876 // Zero: exp is zero and fraction is zero; s = 0/1
3877 static IRExpr * is_Zero( IRType size, IRTemp src )
3879 IRExpr *zero_exp, *zero_frac;
3880 IRTemp exp_mask, frac_mask, msb_frac_mask, zero;
3882 setup_value_check_args( size, &exp_mask, &frac_mask, &msb_frac_mask,
3883 &zero );
3885 /* check the exponent is all zeros, i.e. (exp AND exp_mask) = zero */
3886 zero_exp = exponent_compare( size, src, exp_mask, mkexpr( zero ) );
3888 /* check fractional part is all zeros */
3889 zero_frac = fractional_part_compare( size, src, frac_mask, mkexpr( zero ) );
3891 return mkAND1( zero_exp, zero_frac );
3894 /* SNAN: s = 1/0; exp all 1's; fraction is nonzero, with highest bit '1'
3895 * QNAN: s = 1/0; exp all 1's; fraction is nonzero, with highest bit '0'
3897 static IRExpr * is_NaN( IRType size, IRTemp src )
3899 IRExpr *max_exp, *not_zero_frac;
3900 IRTemp exp_mask, frac_mask, msb_frac_mask, zero;
3902 setup_value_check_args( size, &exp_mask, &frac_mask, &msb_frac_mask,
3903 &zero );
3905 /* check exponent is all ones, i.e. (exp AND exp_mask) = exp_mask */
3906 max_exp = exponent_compare( size, src, exp_mask, mkexpr( exp_mask ) );
3908 /* check fractional part is not zero */
3909 not_zero_frac = unop( Iop_Not1,
3910 fractional_part_compare( size, src, frac_mask,
3911 mkexpr( zero ) ) );
3913 return mkAND1( max_exp, not_zero_frac );
3916 static IRExpr * is_sNaN( IRType size, IRTemp src )
3918 IRExpr *max_exp, *not_zero_frac, *msb_zero;
3919 IRTemp exp_mask, frac_mask, msb_frac_mask, zero;
3921 setup_value_check_args( size, &exp_mask, &frac_mask, &msb_frac_mask,
3922 &zero );
3924 /* check exponent is all ones, i.e. (exp AND exp_mask) = exp_mask */
3925 max_exp = exponent_compare( size, src, exp_mask, mkexpr( exp_mask ) );
3927 /* Most significant fractional bit is zero for sNaN */
3928 msb_zero = fractional_part_compare ( size, src, msb_frac_mask,
3929 mkexpr( zero ) );
3931 /* check fractional part is not zero */
3932 not_zero_frac = unop( Iop_Not1,
3933 fractional_part_compare( size, src, frac_mask,
3934 mkexpr( zero ) ) );
3936 return mkAND1( msb_zero, mkAND1( max_exp, not_zero_frac ) );
3939 /* Denormalized number has a zero exponent and non zero fraction. */
3940 static IRExpr * is_Denorm( IRType size, IRTemp src )
3942 IRExpr *zero_exp, *not_zero_frac;
3943 IRTemp exp_mask, frac_mask, msb_frac_mask, zero;
3945 setup_value_check_args( size, &exp_mask, &frac_mask, &msb_frac_mask,
3946 &zero );
3948 /* check exponent is all zeros */
3949 zero_exp = exponent_compare( size, src, exp_mask, mkexpr( zero ) );
3951 /* check fractional part is not zero */
3952 not_zero_frac = unop( Iop_Not1,
3953 fractional_part_compare( size, src, frac_mask,
3954 mkexpr( zero ) ) );
3956 return mkAND1( zero_exp, not_zero_frac );
3959 static IRExpr * is_Zero_Vector( IRType element_size, IRExpr *src )
3961 /* Check elements of a 128-bit floating point vector, with element size
3962 element_size, are zero. Return 1's in the elements of the vector
3963 which are values. */
3964 IRTemp exp_maskV128 = newTemp( Ity_V128 );
3965 IRTemp exp_zeroV128 = newTemp( Ity_V128 );
3966 IRTemp frac_maskV128 = newTemp( Ity_V128 );
3967 IRTemp frac_zeroV128 = newTemp( Ity_V128 );
3968 IRTemp zeroV128 = newTemp( Ity_V128 );
3970 assign( zeroV128, mkV128( 0 ) );
3972 if ( element_size == Ity_I32 ) {
3973 assign( exp_maskV128, unop( Iop_Dup32x4, mkU32( I32_EXP_MASK ) ) );
3974 assign( frac_maskV128, unop( Iop_Dup32x4, mkU32( I32_FRACTION_MASK ) ) );
3976 } else
3977 vex_printf("ERROR, is_Zero_Vector: Unknown input size\n");
3979 /* CmpEQ32x4 returns all 1's in elements where comparison is true */
3980 assign( exp_zeroV128,
3981 binop( Iop_CmpEQ32x4,
3982 binop( Iop_AndV128,
3983 mkexpr( exp_maskV128 ), src ),
3984 mkexpr( zeroV128 ) ) );
3986 assign( frac_zeroV128,
3987 binop( Iop_CmpEQ32x4,
3988 binop( Iop_AndV128,
3989 mkexpr( frac_maskV128 ), src ),
3990 mkexpr( zeroV128 ) ) );
3992 return binop( Iop_AndV128, mkexpr( exp_zeroV128 ),
3993 mkexpr( frac_zeroV128 ) );
3996 static IRExpr * is_Denorm_Vector( IRType element_size, IRExpr *src )
3998 /* Check elements of a 128-bit floating point vector, with element size
3999 element_size, are Denorm. Return 1's in the elements of the vector
4000 which are denormalized values. */
4001 IRTemp exp_maskV128 = newTemp( Ity_V128 );
4002 IRTemp exp_zeroV128 = newTemp( Ity_V128 );
4003 IRTemp frac_maskV128 = newTemp( Ity_V128 );
4004 IRTemp frac_nonzeroV128 = newTemp( Ity_V128 );
4005 IRTemp zeroV128 = newTemp( Ity_V128 );
4007 assign( zeroV128, mkV128(0 ) );
4009 if ( element_size == Ity_I32 ) {
4010 assign( exp_maskV128, unop( Iop_Dup32x4, mkU32( I32_EXP_MASK ) ) );
4011 assign( frac_maskV128, unop( Iop_Dup32x4, mkU32( I32_FRACTION_MASK ) ) );
4013 } else
4014 vex_printf("ERROR, is_Denorm_Vector: Unknown input size\n");
4016 /* CmpEQ32x4 returns all 1's in elements where comparison is true */
4017 assign( exp_zeroV128,
4018 binop( Iop_CmpEQ32x4,
4019 binop( Iop_AndV128,
4020 mkexpr( exp_maskV128 ), src ),
4021 mkexpr( zeroV128 ) ) );
4023 assign( frac_nonzeroV128,
4024 unop( Iop_NotV128,
4025 binop( Iop_CmpEQ32x4,
4026 binop( Iop_AndV128,
4027 mkexpr( frac_maskV128 ), src ),
4028 mkexpr( zeroV128 ) ) ) );
4030 return binop( Iop_AndV128, mkexpr( exp_zeroV128 ),
4031 mkexpr( frac_nonzeroV128 ) );
4034 static IRExpr * is_NaN_Vector( IRType element_size, IRExpr *src )
4036 IRTemp max_expV128 = newTemp( Ity_V128 );
4037 IRTemp not_zero_fracV128 = newTemp( Ity_V128 );
4038 IRTemp zeroV128 = newTemp( Ity_V128 );
4039 IRTemp exp_maskV128 = newTemp( Ity_V128 );
4040 IRTemp frac_maskV128 = newTemp( Ity_V128 );
4041 IROp opCmpEQ;
4043 assign( zeroV128, mkV128( 0 ) );
4045 if ( element_size == Ity_I32 ) {
4046 assign( exp_maskV128, unop( Iop_Dup32x4, mkU32( I32_EXP_MASK ) ) );
4047 assign( frac_maskV128, unop( Iop_Dup32x4, mkU32( I32_FRACTION_MASK ) ) );
4048 opCmpEQ = Iop_CmpEQ32x4;
4050 } else
4051 vex_printf("ERROR, is_NaN_Vector: Unknown input size\n");
4053 /* check exponent is all ones, i.e. (exp AND exp_mask) = exp_mask */
4054 assign( max_expV128,
4055 binop( opCmpEQ,
4056 binop( Iop_AndV128, src, mkexpr( exp_maskV128 ) ),
4057 mkexpr( exp_maskV128 ) ) );
4059 /* check fractional part is not zero */
4060 assign( not_zero_fracV128,
4061 unop( Iop_NotV128,
4062 binop( opCmpEQ,
4063 binop( Iop_AndV128, src, mkexpr( frac_maskV128 ) ),
4064 mkexpr( zeroV128 ) ) ) );
4066 return binop( Iop_AndV128, mkexpr( max_expV128 ),
4067 mkexpr( not_zero_fracV128 ) );
4070 #if 0
4071 /* Normalized number has exponent between 1 and max_exp -1, or in other words
4072 the exponent is not zero and not equal to the max exponent value. */
4073 Currently not needed since generate_C_FPCC is now done with a C helper.
4074 Keep it around, might be useful in the future.
4075 static IRExpr * is_Norm( IRType size, IRTemp src )
4077 IRExpr *not_zero_exp, *not_max_exp;
4078 IRTemp exp_mask, zero;
4080 vassert( ( size == Ity_I16 ) || ( size == Ity_I32 )
4081 || ( size == Ity_I64 ) || ( size == Ity_V128 ) );
4083 if( size == Ity_I16 ) {
4084 /* The 16-bit floating point value is in the lower 16-bits of
4085 the 32-bit input value */
4086 exp_mask = newTemp( Ity_I32 );
4087 zero = newTemp( Ity_I32 );
4088 assign( exp_mask, mkU32( I16_EXP_MASK ) );
4089 assign( zero, mkU32( 0 ) );
4091 } else if( size == Ity_I32 ) {
4092 exp_mask = newTemp( Ity_I32 );
4093 zero = newTemp( Ity_I32 );
4094 assign( exp_mask, mkU32( I32_EXP_MASK ) );
4095 assign( zero, mkU32( 0 ) );
4097 } else if( size == Ity_I64 ) {
4098 exp_mask = newTemp( Ity_I64 );
4099 zero = newTemp( Ity_I64 );
4100 assign( exp_mask, mkU64( I64_EXP_MASK ) );
4101 assign( zero, mkU64( 0 ) );
4103 } else {
4104 /* V128 is converted to upper and lower 64 bit values, */
4105 /* uses 64-bit operators and temps */
4106 exp_mask = newTemp( Ity_I64 );
4107 zero = newTemp( Ity_I64 );
4108 assign( exp_mask, mkU64( V128_EXP_MASK ) );
4109 assign( zero, mkU64( 0 ) );
4112 not_zero_exp = unop( Iop_Not1,
4113 exponent_compare( size, src,
4114 exp_mask, mkexpr( zero ) ) );
4115 not_max_exp = unop( Iop_Not1,
4116 exponent_compare( size, src,
4117 exp_mask, mkexpr( exp_mask ) ) );
4119 return mkAND1( not_zero_exp, not_max_exp );
4121 #endif
4123 static void generate_store_FPRF( IRType size, IRTemp src,
4124 const VexAbiInfo* vbi )
4127 /* This function was originally written using IR code. It has been
4128 * replaced with a clean helper due to the large amount of IR code
4129 * needed by this function.
4132 IRTemp tmp = newTemp( Ity_I64 );
4133 vassert( ( size == Ity_I16 ) || ( size == Ity_I32 )
4134 || ( size == Ity_I64 ) || ( size == Ity_F128 ) );
4136 vassert( ( typeOfIRExpr(irsb->tyenv, mkexpr( src ) ) == Ity_I32 )
4137 || ( typeOfIRExpr(irsb->tyenv, mkexpr( src ) ) == Ity_I64 )
4138 || ( typeOfIRExpr(irsb->tyenv, mkexpr( src ) ) == Ity_F128 ) );
4140 if( size == Ity_I16 ) {
4141 assign( tmp,
4142 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4143 "generate_store_C_FPCC_helper",
4144 fnptr_to_fnentry( vbi, &generate_C_FPCC_helper ),
4145 mkIRExprVec_3( mkU64( size ), mkU64( 0 ),
4146 mkexpr( src ) ) ) );
4147 } else if( size == Ity_I32 ) {
4148 assign( tmp,
4149 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4150 "generate_store_C_FPCC_helper",
4151 fnptr_to_fnentry( vbi, &generate_C_FPCC_helper ),
4152 mkIRExprVec_3( mkU64( size ), mkU64( 0 ),
4153 mkexpr( src ) ) ) );
4154 } else if( size == Ity_I64 ) {
4155 assign( tmp,
4156 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4157 "generate_store_C_FPCC_helper",
4158 fnptr_to_fnentry( vbi, &generate_C_FPCC_helper ),
4159 mkIRExprVec_3( mkU64( size ), mkU64( 0 ),
4160 mkexpr( src ) ) ) );
4161 } else if( size == Ity_F128 ) {
4162 assign( tmp,
4163 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4164 "generate_store_C_FPCC_helper",
4165 fnptr_to_fnentry( vbi, &generate_C_FPCC_helper ),
4166 mkIRExprVec_3( mkU64( size ),
4167 unop( Iop_ReinterpF64asI64,
4168 unop( Iop_F128HItoF64,
4169 mkexpr( src ) ) ),
4170 unop( Iop_ReinterpF64asI64,
4171 unop( Iop_F128LOtoF64,
4172 mkexpr( src ) ) ) ) ) );
4175 /* C is in the upper 32-bits, FPCC is in the lower 32-bits of the
4176 * value returned by the helper function
4178 putC( unop( Iop_64HIto32, mkexpr( tmp) ) );
4179 putFPCC( unop( Iop_64to32, mkexpr( tmp) ) );
4182 /* This function takes an Ity_I32 input argument interpreted
4183 as a single-precision floating point value. If src is a
4184 SNaN, it is changed to a QNaN and returned; otherwise,
4185 the original value is returned. */
4186 static IRExpr * handle_SNaN_to_QNaN_32(IRExpr * src)
4188 #define SNAN_MASK32 0x00400000
4189 IRTemp tmp = newTemp(Ity_I32);
4190 IRTemp mask = newTemp(Ity_I32);
4191 IRTemp is_SNAN = newTemp(Ity_I1);
4193 vassert( typeOfIRExpr(irsb->tyenv, src ) == Ity_I32 );
4194 assign(tmp, src);
4196 /* check if input is SNaN, if it is convert to QNaN */
4197 assign( is_SNAN,
4198 mkAND1( is_NaN( Ity_I32, tmp ),
4199 binop( Iop_CmpEQ32,
4200 binop( Iop_And32, mkexpr( tmp ),
4201 mkU32( SNAN_MASK32 ) ),
4202 mkU32( 0 ) ) ) );
4203 /* create mask with QNaN bit set to make it a QNaN if tmp is SNaN */
4204 assign ( mask, binop( Iop_And32,
4205 unop( Iop_1Sto32, mkexpr( is_SNAN ) ),
4206 mkU32( SNAN_MASK32 ) ) );
4207 return binop( Iop_Or32, mkexpr( mask ), mkexpr( tmp) );
4211 /* This helper function performs the negation part of operations of the form:
4212 * "Negate Multiply-<op>"
4213 * where "<op>" is either "Add" or "Sub".
4215 * This function takes one argument -- the floating point intermediate result (converted to
4216 * Ity_I64 via Iop_ReinterpF64asI64) that was obtained from the "Multip-<op>" part of
4217 * the operation described above.
4219 static IRTemp getNegatedResult(IRTemp intermediateResult)
4221 ULong signbit_mask = 0x8000000000000000ULL;
4222 IRTemp signbit_32 = newTemp(Ity_I32);
4223 IRTemp resultantSignbit = newTemp(Ity_I1);
4224 IRTemp negatedResult = newTemp(Ity_I64);
4225 assign( signbit_32, binop( Iop_Shr32,
4226 unop( Iop_64HIto32,
4227 binop( Iop_And64, mkexpr( intermediateResult ),
4228 mkU64( signbit_mask ) ) ),
4229 mkU8( 31 ) ) );
4230 /* We negate the signbit if and only if the intermediate result from the
4231 * multiply-<op> was NOT a NaN. This is an XNOR predicate.
4233 assign( resultantSignbit,
4234 unop( Iop_Not1,
4235 binop( Iop_CmpEQ32,
4236 binop( Iop_Xor32,
4237 mkexpr( signbit_32 ),
4238 unop( Iop_1Uto32, is_NaN( Ity_I64,
4239 intermediateResult ) ) ),
4240 mkU32( 1 ) ) ) );
4242 assign( negatedResult,
4243 binop( Iop_Or64,
4244 binop( Iop_And64,
4245 mkexpr( intermediateResult ),
4246 mkU64( ~signbit_mask ) ),
4247 binop( Iop_32HLto64,
4248 binop( Iop_Shl32,
4249 unop( Iop_1Uto32, mkexpr( resultantSignbit ) ),
4250 mkU8( 31 ) ),
4251 mkU32( 0 ) ) ) );
4253 return negatedResult;
4256 /* This helper function performs the negation part of operations of the form:
4257 * "Negate Multiply-<op>"
4258 * where "<op>" is either "Add" or "Sub".
4260 * This function takes one argument -- the floating point intermediate result (converted to
4261 * Ity_I32 via Iop_ReinterpF32asI32) that was obtained from the "Multip-<op>" part of
4262 * the operation described above.
4264 static IRTemp getNegatedResult_32(IRTemp intermediateResult)
4266 UInt signbit_mask = 0x80000000;
4267 IRTemp signbit_32 = newTemp(Ity_I32);
4268 IRTemp resultantSignbit = newTemp(Ity_I1);
4269 IRTemp negatedResult = newTemp(Ity_I32);
4270 assign( signbit_32, binop( Iop_Shr32,
4271 binop( Iop_And32, mkexpr( intermediateResult ),
4272 mkU32( signbit_mask ) ),
4273 mkU8( 31 ) ) );
4274 /* We negate the signbit if and only if the intermediate result from the
4275 * multiply-<op> was NOT a NaN. This is an XNOR predicate.
4277 assign( resultantSignbit,
4278 unop( Iop_Not1,
4279 binop( Iop_CmpEQ32,
4280 binop( Iop_Xor32,
4281 mkexpr( signbit_32 ),
4282 unop( Iop_1Uto32, is_NaN( Ity_I32,
4283 intermediateResult ) ) ),
4284 mkU32( 1 ) ) ) );
4286 assign( negatedResult,
4287 binop( Iop_Or32,
4288 binop( Iop_And32,
4289 mkexpr( intermediateResult ),
4290 mkU32( ~signbit_mask ) ),
4291 binop( Iop_Shl32,
4292 unop( Iop_1Uto32, mkexpr( resultantSignbit ) ),
4293 mkU8( 31 ) ) ) );
4295 return negatedResult;
4298 static IRExpr* negate_Vector ( IRType element_size, IRExpr* value )
4300 /* This function takes a vector of floats. If the value is
4301 not a NaN, the value is negated. */
4303 IRTemp not_nan_mask = newTemp( Ity_V128 );
4304 IRTemp sign_maskV128 = newTemp( Ity_V128 );
4306 if ( element_size == Ity_I32 ) {
4307 assign( sign_maskV128, unop( Iop_Dup32x4, mkU32( I32_SIGN_MASK ) ) );
4309 } else
4310 vex_printf("ERROR, negate_Vector: Unknown input size\n");
4312 /* Determine if vector elementes are not a NaN, negate sign bit
4313 for non NaN elements */
4314 assign ( not_nan_mask,
4315 unop( Iop_NotV128, is_NaN_Vector( element_size, value ) ) );
4317 return binop( Iop_XorV128,
4318 binop( Iop_AndV128,
4319 mkexpr( sign_maskV128 ), mkexpr( not_nan_mask ) ),
4320 value );
4323 /* This function takes two quad_precision floating point numbers of type
4324 V128 and return 1 if src_A > src_B, 0 otherwise. */
4325 static IRExpr * Quad_precision_gt ( IRTemp src_A, IRTemp src_B )
4327 #define FRAC_MASK64Hi 0x0000ffffffffffffULL
4328 #define MASK 0x7FFFFFFFFFFFFFFFULL /* exclude sign bit in upper 64 bits */
4329 #define EXP_MASK 0x7fff
4331 IRType ty = Ity_I64;
4332 IRTemp sign_A = newTemp( ty );
4333 IRTemp sign_B = newTemp( ty );
4334 IRTemp exp_A = newTemp( ty );
4335 IRTemp exp_B = newTemp( ty );
4336 IRTemp frac_A_hi = newTemp( ty );
4337 IRTemp frac_B_hi = newTemp( ty );
4338 IRTemp frac_A_lo = newTemp( ty );
4339 IRTemp frac_B_lo = newTemp( ty );
4342 /* extract exponents, and fractional parts so they can be compared */
4343 assign( sign_A, binop( Iop_Shr64,
4344 unop( Iop_V128HIto64, mkexpr( src_A ) ),
4345 mkU8( 63 ) ) );
4346 assign( sign_B, binop( Iop_Shr64,
4347 unop( Iop_V128HIto64, mkexpr( src_B ) ),
4348 mkU8( 63 ) ) );
4349 assign( exp_A, binop( Iop_And64,
4350 binop( Iop_Shr64,
4351 unop( Iop_V128HIto64, mkexpr( src_A ) ),
4352 mkU8( 48 ) ),
4353 mkU64( EXP_MASK ) ) );
4354 assign( exp_B, binop( Iop_And64,
4355 binop( Iop_Shr64,
4356 unop( Iop_V128HIto64, mkexpr( src_B ) ),
4357 mkU8( 48 ) ),
4358 mkU64( EXP_MASK ) ) );
4359 assign( frac_A_hi, binop( Iop_And64,
4360 unop( Iop_V128HIto64, mkexpr( src_A ) ),
4361 mkU64( FRAC_MASK64Hi ) ) );
4362 assign( frac_B_hi, binop( Iop_And64,
4363 unop( Iop_V128HIto64, mkexpr( src_B ) ),
4364 mkU64( FRAC_MASK64Hi ) ) );
4365 assign( frac_A_lo, unop( Iop_V128to64, mkexpr( src_A ) ) );
4366 assign( frac_B_lo, unop( Iop_V128to64, mkexpr( src_B ) ) );
4368 IRExpr * A_zero = mkAND1( binop( Iop_CmpEQ64,
4369 binop( Iop_And64,
4370 unop( Iop_V128HIto64,
4371 mkexpr( src_A ) ),
4372 mkU64( MASK ) ),
4373 mkU64( 0 ) ),
4374 binop( Iop_CmpEQ64,
4375 unop( Iop_V128to64, mkexpr( src_A ) ),
4376 mkU64( 0 ) ) );
4377 IRExpr * B_zero = mkAND1( binop( Iop_CmpEQ64,
4378 binop( Iop_And64,
4379 unop( Iop_V128HIto64,
4380 mkexpr( src_B ) ),
4381 mkU64( MASK ) ),
4382 mkU64( 0 ) ),
4383 binop( Iop_CmpEQ64,
4384 unop( Iop_V128to64, mkexpr( src_B ) ),
4385 mkU64( 0 ) ) );
4386 IRExpr * A_B_zero = mkAND1( A_zero, B_zero );
4388 /* Compare numbers */
4389 IRExpr * both_pos = mkAND1( binop( Iop_CmpEQ64, mkexpr( sign_A ),
4390 mkU64( 0 ) ),
4391 binop( Iop_CmpEQ64, mkexpr( sign_B ),
4392 mkU64( 0 ) ) );
4393 IRExpr * both_neg = mkAND1( binop( Iop_CmpEQ64, mkexpr( sign_A ),
4394 mkU64( 1 ) ),
4395 binop( Iop_CmpEQ64, mkexpr( sign_B ),
4396 mkU64( 1 ) ) );
4397 IRExpr * sign_eq = binop( Iop_CmpEQ64, mkexpr( sign_A ), mkexpr( sign_B ) );
4398 IRExpr * sign_gt = binop( Iop_CmpLT64U, mkexpr( sign_A ),
4399 mkexpr( sign_B ) ); /* A pos, B neg */
4401 IRExpr * exp_eq = binop( Iop_CmpEQ64, mkexpr( exp_A ), mkexpr( exp_B ) );
4402 IRExpr * exp_gt = binop( Iop_CmpLT64U, mkexpr( exp_B ), mkexpr( exp_A ) );
4403 IRExpr * exp_lt = binop( Iop_CmpLT64U, mkexpr( exp_A ), mkexpr( exp_B ) );
4405 IRExpr * frac_hi_eq = binop( Iop_CmpEQ64, mkexpr( frac_A_hi),
4406 mkexpr( frac_B_hi ) );
4407 IRExpr * frac_hi_gt = binop( Iop_CmpLT64U, mkexpr( frac_B_hi ),
4408 mkexpr( frac_A_hi ) );
4409 IRExpr * frac_hi_lt = binop( Iop_CmpLT64U, mkexpr( frac_A_hi ),
4410 mkexpr( frac_B_hi ) );
4412 IRExpr * frac_lo_gt = binop( Iop_CmpLT64U, mkexpr( frac_B_lo ),
4413 mkexpr( frac_A_lo ) );
4414 IRExpr * frac_lo_lt = binop( Iop_CmpLT64U, mkexpr( frac_A_lo ),
4415 mkexpr( frac_B_lo ) );
4417 /* src_A and src_B both positive */
4418 IRExpr *pos_cmp = mkOR1( exp_gt,
4419 mkAND1( exp_eq,
4420 mkOR1( frac_hi_gt,
4421 mkAND1( frac_hi_eq, frac_lo_gt ) )
4422 ) );
4424 /* src_A and src_B both negative */
4425 IRExpr *neg_cmp = mkOR1( exp_lt,
4426 mkAND1( exp_eq,
4427 mkOR1( frac_hi_lt,
4428 mkAND1( frac_hi_eq, frac_lo_lt ) )
4429 ) );
4431 /* Need to check the case where one value is a positive
4432 * zero and the other value is a negative zero
4434 return mkAND1( mkNOT1( A_B_zero ),
4435 mkOR1( sign_gt,
4436 mkAND1( sign_eq,
4437 mkOR1( mkAND1( both_pos, pos_cmp ),
4438 mkAND1( both_neg, neg_cmp ) ) ) ) );
4441 /*-----------------------------------------------------------
4442 * Helpers for VX instructions that work on National decimal values,
4443 * Zoned decimal values and BCD values.
4445 *------------------------------------------------------------*/
4446 static IRExpr * is_National_decimal (IRTemp src)
4448 /* The src is a 128-bit value containing a sign code in half word 7
4449 * and seven digits in halfwords 0 to 6 (IBM numbering). A valid
4450 * national decimal value has the following:
4451 * - the sign code must be 0x002B (positive) or 0x002D (negative)
4452 * - the digits must be in the range 0x0030 to 0x0039
4454 Int i;
4455 IRExpr * valid_pos_sign;
4456 IRExpr * valid_neg_sign;
4457 IRTemp valid_num[8];
4458 IRTemp digit[7];
4460 valid_pos_sign = binop( Iop_CmpEQ64,
4461 binop( Iop_And64,
4462 mkU64( 0xFFFF ),
4463 unop( Iop_V128to64, mkexpr( src ) ) ),
4464 mkU64( 0x002B ) );
4466 valid_neg_sign = binop( Iop_CmpEQ64,
4467 binop( Iop_And64,
4468 mkU64( 0xFFFF ),
4469 unop( Iop_V128to64, mkexpr( src ) ) ),
4470 mkU64( 0x002D ) );
4472 valid_num[0] = newTemp( Ity_I1 );
4473 digit[0] = newTemp( Ity_I64 );
4474 assign( valid_num[0], mkU1( 1 ) ); // Assume true to start
4476 for(i = 0; i < 7; i++) {
4477 valid_num[i+1] = newTemp( Ity_I1 );
4478 digit[i] = newTemp( Ity_I64 );
4479 assign( digit[i], binop( Iop_And64,
4480 unop( Iop_V128to64,
4481 binop( Iop_ShrV128,
4482 mkexpr( src ),
4483 mkU8( (7-i)*16 ) ) ),
4484 mkU64( 0xFFFF ) ) );
4486 assign( valid_num[i+1],
4487 mkAND1( mkexpr( valid_num[i] ),
4488 mkAND1( binop( Iop_CmpLE64U,
4489 mkexpr( digit[i] ),
4490 mkU64( 0x39 ) ),
4491 binop( Iop_CmpLE64U,
4492 mkU64( 0x30 ),
4493 mkexpr( digit[i] ) ) ) ) );
4496 return mkAND1( mkOR1( valid_pos_sign, valid_neg_sign),
4497 mkexpr( valid_num[7] ) );
4500 static IRExpr * is_Zoned_decimal (IRTemp src, UChar ps)
4502 /* The src is a 128-bit value containing a sign code the least significant
4503 * two bytes. The upper pairs of bytes contain digits. A valid Zoned
4504 * decimal value has the following:
4505 * - the sign code must be between 0x0X to 0xFX inclusive (X - don't care)
4506 * - bits [0:3] of each digit must be equal to 0x3
4507 * - bits [4:7] of each digit must be between 0x0 and 0x9
4509 * If ps = 0
4510 * Positive sign codes are: 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xA, 0xB
4511 * (note 0bX0XX XXXX is positive)
4513 * Negative sign codes are 0x4, 0x5, 0x6, 0x7, 0xC, 0xD, 0xE, 0xF
4514 * (note 0bX1XX XXXX is negative)
4516 * If ps = 1, then the sign code must be in the range 0xA to 0xF
4517 * Positive sign codes are: 0xA, 0xC, 0xE, 0xF
4519 * Negative sign codes are 0xB, 0xD
4521 Int i, mask_hi, mask_lo;
4522 IRExpr *valid_range;
4523 IRTemp valid_num[16];
4524 IRTemp digit[15];
4526 /* check the range of the sign value based on the value of ps */
4527 valid_range = mkOR1(
4528 mkAND1( binop( Iop_CmpEQ64,
4529 mkU64( 1 ),
4530 mkU64( ps ) ),
4531 mkAND1( binop( Iop_CmpLE64U,
4532 binop( Iop_And64,
4533 mkU64( 0xF0 ),
4534 unop( Iop_V128to64,
4535 mkexpr( src ) ) ),
4537 mkU64( 0xF0 ) ),
4538 binop( Iop_CmpLE64U,
4539 mkU64( 0xA0 ),
4540 binop( Iop_And64,
4541 mkU64( 0xF0 ),
4542 unop( Iop_V128to64,
4543 mkexpr( src ) ))))),
4544 binop( Iop_CmpEQ64,
4545 mkU64( 0 ),
4546 mkU64( ps ) ) );
4548 valid_num[0] = newTemp( Ity_I1 );
4549 assign( valid_num[0], mkU1( 1) ); // Assume true to start
4551 if (ps == 0) {
4552 mask_hi = 0x39;
4553 mask_lo = 0x30;
4554 } else {
4555 mask_hi = 0xF9;
4556 mask_lo = 0xF0;
4559 for(i = 0; i < 15; i++) {
4560 valid_num[i+1] = newTemp( Ity_I1 );
4561 digit[i] = newTemp( Ity_I64 );
4562 assign( digit[i], binop( Iop_And64,
4563 unop( Iop_V128to64,
4564 binop( Iop_ShrV128,
4565 mkexpr( src ),
4566 mkU8( (15-i)*8 ) ) ),
4567 mkU64( 0xFF ) ) );
4569 assign( valid_num[i+1],
4570 mkAND1( mkexpr( valid_num[i] ),
4571 mkAND1( binop( Iop_CmpLE64U,
4572 mkexpr( digit[i] ),
4573 mkU64( mask_hi ) ),
4574 binop( Iop_CmpLE64U,
4575 mkU64( mask_lo ),
4576 mkexpr( digit[i] ) ) ) ) );
4579 return mkAND1( valid_range, mkexpr( valid_num[15] ) );
4582 static IRExpr * CmpGT128U ( IRExpr *src1, IRExpr *src2 )
4584 /* Unsigend compare of two 128-bit values */
4585 IRExpr *pos_upper_gt, *pos_upper_eq, *pos_lower_gt;
4587 pos_upper_gt = binop( Iop_CmpLT64U,
4588 unop( Iop_V128HIto64, src2 ),
4589 unop( Iop_V128HIto64, src1 ) );
4590 pos_upper_eq = binop( Iop_CmpEQ64,
4591 unop( Iop_V128HIto64, src1 ),
4592 unop( Iop_V128HIto64, src2 ) );
4593 pos_lower_gt = binop( Iop_CmpLT64U,
4594 unop( Iop_V128to64, src2),
4595 unop( Iop_V128to64, src1) );
4596 return mkOR1( pos_upper_gt,
4597 mkAND1( pos_upper_eq,
4598 pos_lower_gt ) );
4602 static IRExpr * is_BCDstring128 ( const VexAbiInfo* vbi,
4603 UInt Signed, IRExpr *src )
4606 IRTemp valid = newTemp( Ity_I64 );
4608 /* The src is a 128-bit value containing a MAX_DIGITS BCD digits and
4609 * a sign. The upper bytes are BCD values between 0x0 and 0x9. The sign
4610 * byte is the least significant byte. This function returns 64-bit 1
4611 * value if sign and digits are valid, 0 otherwise.
4613 * This function was originally written using IR code. It has been
4614 * replaced with a clean helper due to the large amount of IR code
4615 * needed by this function.
4617 assign( valid,
4618 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4619 "is_BCDstring128_helper",
4620 fnptr_to_fnentry( vbi, &is_BCDstring128_helper ),
4621 mkIRExprVec_3( mkU64( Signed ),
4622 unop( Iop_V128HIto64, src ),
4623 unop( Iop_V128to64, src ) ) ) );
4624 return mkexpr( valid );
4627 static IRExpr * BCDstring_zero (IRExpr *src)
4629 /* The src is a 128-bit value containing a BCD string. The function
4630 * returns a 1 if the BCD string values are all zero, 0 otherwise.
4632 IRTemp tsrc = newTemp( Ity_V128 );
4633 assign( tsrc, src);
4635 if ( mode64 ) {
4636 return mkAND1( binop( Iop_CmpEQ64,
4637 mkU64( 0 ),
4638 unop( Iop_V128HIto64,
4639 mkexpr( tsrc ) ) ),
4640 binop( Iop_CmpEQ64,
4641 mkU64( 0 ),
4642 unop( Iop_V128to64,
4643 mkexpr( tsrc ) ) ) );
4644 } else {
4645 /* make this work in 32-bit mode */
4646 return mkAND1(
4647 mkAND1( binop( Iop_CmpEQ32,
4648 mkU32( 0 ),
4649 unop( Iop_64HIto32,
4650 unop( Iop_V128HIto64,
4651 mkexpr( tsrc ) ) ) ),
4652 binop( Iop_CmpEQ32,
4653 mkU32( 0 ),
4654 unop( Iop_64to32,
4655 unop( Iop_V128HIto64,
4656 mkexpr( tsrc ) ) ) ) ),
4657 mkAND1( binop( Iop_CmpEQ32,
4658 mkU32( 0 ),
4659 unop( Iop_64HIto32,
4660 unop( Iop_V128to64,
4661 mkexpr( tsrc ) ) ) ),
4662 binop( Iop_CmpEQ32,
4663 mkU32( 0 ),
4664 unop( Iop_64to32,
4665 unop( Iop_V128to64,
4666 mkexpr( tsrc ) ) ) ) ) );
4670 static IRExpr * check_BCD_round (IRExpr *src, IRTemp shift)
4672 /* The src is a 128-bit value containing 31 BCD digits with the sign in
4673 * the least significant byte. The bytes are BCD values between 0x0 and 0x9.
4674 * This routine checks the BCD digit in position shift (counting from
4675 * the least significant digit). If the digit is greater then five,
4676 * a 1 is returned indicating the string needs to be rounded up,
4677 * otherwise, 0 is returned. The value of shift (I64) is the index of
4678 * the BCD digit times four bits.
4680 return binop( Iop_CmpLE64U,
4681 mkU64( 6 ),
4682 binop( Iop_And64,
4683 unop( Iop_V128to64,
4684 binop( Iop_ShrV128,
4685 src,
4686 unop( Iop_64to8, mkexpr( shift ) ) ) ),
4687 mkU64( 0xF ) ) );
4690 static IRTemp increment_BCDstring ( const VexAbiInfo* vbi,
4691 IRExpr *src, IRExpr *carry_in )
4693 /* The src is a 128-bit value containing 31 BCD digits with the sign in
4694 * the least significant byte. The bytes are BCD values between 0x0 and 0x9.
4695 * This function returns the BCD string incremented by 1.
4697 * Call a clean helper to do the computation as it requires a lot of
4698 * IR code to do this.
4700 * The helper function takes a 32-bit BCD string, in a 64-bit value, and
4701 * increments the string by the 32-bi carry in value.
4703 * The incremented value is returned in the lower 32-bits of the result.
4704 * The carry out is returned in bits [35:32] of the result. The
4705 * helper function will be called for each of the four 32-bit strings
4706 * that make up the src string passing the returned carry out to the
4707 * next call.
4709 IRTemp bcd_result = newTemp( Ity_V128 );
4710 IRTemp bcd_result0 = newTemp( Ity_I64 );
4711 IRTemp bcd_result1 = newTemp( Ity_I64 );
4712 IRTemp bcd_result2 = newTemp( Ity_I64 );
4713 IRTemp bcd_result3 = newTemp( Ity_I64 );
4714 IRExpr *bcd_string0, *bcd_string1, *bcd_string2, *bcd_string3;
4716 bcd_string0 = binop( Iop_And64,
4717 mkU64( 0xFFFFFFFF ), unop( Iop_V128to64, src ) );
4718 bcd_string1 = binop( Iop_Shr64, unop( Iop_V128to64, src ), mkU8( 32 ) );
4719 bcd_string2 = binop( Iop_And64,
4720 mkU64( 0xFFFFFFFF ), unop( Iop_V128HIto64, src ) );
4721 bcd_string3 = binop( Iop_Shr64, unop( Iop_V128HIto64, src ), mkU8( 32 ) );
4723 assign( bcd_result0,
4724 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4725 "increment_BCDstring32_helper",
4726 fnptr_to_fnentry( vbi,
4727 &increment_BCDstring32_helper ),
4728 mkIRExprVec_3( mkU64( True /*Signed*/ ),
4729 bcd_string0,
4730 binop( Iop_32HLto64, mkU32( 0 ),
4731 carry_in ) ) ) );
4733 assign( bcd_result1,
4734 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4735 "increment_BCDstring32_helper",
4736 fnptr_to_fnentry( vbi,
4737 &increment_BCDstring32_helper ),
4738 mkIRExprVec_3( mkU64( False /*Unsigned*/ ),
4739 bcd_string1,
4740 binop( Iop_Shr64,
4741 mkexpr( bcd_result0 ),
4742 mkU8( 32 ) ) ) ) );
4743 assign( bcd_result2,
4744 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4745 "increment_BCDstring32_helper",
4746 fnptr_to_fnentry( vbi,
4747 &increment_BCDstring32_helper ),
4748 mkIRExprVec_3( mkU64( False /*Unsigned*/ ),
4749 bcd_string2,
4750 binop( Iop_Shr64,
4751 mkexpr( bcd_result1 ),
4752 mkU8( 32 ) ) ) ) );
4753 assign( bcd_result3,
4754 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4755 "increment_BCDstring32_helper",
4756 fnptr_to_fnentry( vbi,
4757 &increment_BCDstring32_helper ),
4758 mkIRExprVec_3( mkU64( False /*Unsigned*/ ),
4759 bcd_string3,
4760 binop( Iop_Shr64,
4761 mkexpr( bcd_result2 ),
4762 mkU8( 32 ) ) ) ) );
4764 /* Put the 128-bit result together from the intermediate results. Remember
4765 * to mask out the carry out from the upper 32 bits of the results.
4767 assign( bcd_result,
4768 binop( Iop_64HLtoV128,
4769 binop( Iop_Or64,
4770 binop( Iop_And64,
4771 mkU64( 0xFFFFFFFF ), mkexpr (bcd_result2 ) ),
4772 binop( Iop_Shl64,
4773 mkexpr (bcd_result3 ), mkU8( 32 ) ) ),
4774 binop( Iop_Or64,
4775 binop( Iop_And64,
4776 mkU64( 0xFFFFFFFF ), mkexpr (bcd_result0 ) ),
4777 binop( Iop_Shl64,
4778 mkexpr (bcd_result1 ), mkU8( 32 ) ) ) ) );
4779 return bcd_result;
4782 static IRExpr * convert_to_zoned ( const VexAbiInfo* vbi,
4783 IRExpr *src, IRExpr *upper_byte )
4785 /* The function takes a V128 packed decimal value and returns
4786 * the value in zoned format. Note, the sign of the value is ignored.
4788 IRTemp result_low = newTemp( Ity_I64 );
4789 IRTemp result_hi = newTemp( Ity_I64 );
4790 IRTemp result = newTemp( Ity_V128 );
4792 /* Since we can only return 64-bits from a clean helper, we will
4793 * have to get the lower and upper 64-bits separately.
4796 assign( result_low,
4797 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4798 "convert_to_zoned_helper",
4799 fnptr_to_fnentry( vbi, &convert_to_zoned_helper ),
4800 mkIRExprVec_4( unop( Iop_V128HIto64, src ),
4801 unop( Iop_V128to64, src ),
4802 upper_byte,
4803 mkU64( 0 ) ) ) );
4805 assign( result_hi,
4806 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4807 "convert_to_zoned_helper",
4808 fnptr_to_fnentry( vbi, &convert_to_zoned_helper ),
4809 mkIRExprVec_4( unop( Iop_V128HIto64, src ),
4810 unop( Iop_V128to64, src ),
4811 upper_byte,
4812 mkU64( 1 ) ) ) );
4815 assign( result,
4816 binop( Iop_64HLtoV128, mkexpr( result_hi ), mkexpr( result_low ) ) );
4818 return mkexpr( result );
4821 static IRExpr * convert_to_national ( const VexAbiInfo* vbi, IRExpr *src ) {
4822 /* The function takes 128-bit value which has a 64-bit packed decimal
4823 * value in the lower 64-bits of the source. The packed decimal is
4824 * converted to the national format via a clean helper. The clean
4825 * helper is used to to the large amount of IR code needed to do the
4826 * conversion. The helper returns the upper 64-bits of the 128-bit
4827 * result if return_upper != 0. Otherwise, the lower 64-bits of the
4828 * result is returned.
4830 IRTemp result_low = newTemp( Ity_I64 );
4831 IRTemp result_hi = newTemp( Ity_I64 );
4832 IRTemp result = newTemp( Ity_V128 );
4834 /* Since we can only return 64-bits from a clean helper, we will
4835 * have to get the lower and upper 64-bits separately.
4838 assign( result_low,
4839 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4840 "convert_to_national_helper",
4841 fnptr_to_fnentry( vbi, &convert_to_national_helper ),
4842 mkIRExprVec_2( unop( Iop_V128to64, src ),
4843 mkU64( 0 ) ) ) );
4845 assign( result_hi,
4846 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4847 "convert_to_national_helper",
4848 fnptr_to_fnentry( vbi, &convert_to_national_helper ),
4849 mkIRExprVec_2( unop( Iop_V128to64, src ),
4850 mkU64( 1 ) ) ) );
4852 assign( result,
4853 binop( Iop_64HLtoV128, mkexpr( result_hi ), mkexpr( result_low ) ) );
4855 return mkexpr( result );
4858 static IRExpr * convert_from_zoned ( const VexAbiInfo* vbi, IRExpr *src ) {
4859 /* The function takes 128-bit zoned value and returns a signless 64-bit
4860 * packed decimal value in the lower 64-bits of the 128-bit result.
4862 IRTemp result = newTemp( Ity_V128 );
4864 assign( result,
4865 binop( Iop_ShlV128,
4866 binop( Iop_64HLtoV128,
4867 mkU64( 0 ),
4868 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4869 "convert_from_zoned_helper",
4870 fnptr_to_fnentry( vbi,
4871 &convert_from_zoned_helper ),
4872 mkIRExprVec_2( unop( Iop_V128HIto64,
4873 src ),
4874 unop( Iop_V128to64,
4875 src ) ) ) ),
4876 mkU8( 4 ) ) );
4878 return mkexpr( result );
4881 static IRExpr * convert_from_national ( const VexAbiInfo* vbi, IRExpr *src ) {
4882 /* The function takes 128-bit national value and returns a 64-bit
4883 * packed decimal value.
4885 IRTemp result = newTemp( Ity_I64);
4887 assign( result,
4888 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4889 "convert_from_national_helper",
4890 fnptr_to_fnentry( vbi,
4891 &convert_from_national_helper ),
4892 mkIRExprVec_2( unop( Iop_V128HIto64,
4893 src ),
4894 unop( Iop_V128to64,
4895 src ) ) ) );
4897 return mkexpr( result );
4900 static IRExpr * UNSIGNED_CMP_GT_V128 ( IRExpr *vA, IRExpr *vB ) {
4901 /* This function does an unsigned compare of two V128 values. The
4902 * function is for use in 32-bit mode only as it is expensive. The
4903 * issue is that compares (GT, LT, EQ) are not supported for operands
4904 * larger then 32-bits when running in 32-bit mode. The function returns
4905 * a 1-bit expression, 1 for TRUE and 0 for FALSE.
4907 IRTemp vA_word0 = newTemp( Ity_I32);
4908 IRTemp vA_word1 = newTemp( Ity_I32);
4909 IRTemp vA_word2 = newTemp( Ity_I32);
4910 IRTemp vA_word3 = newTemp( Ity_I32);
4911 IRTemp vB_word0 = newTemp( Ity_I32);
4912 IRTemp vB_word1 = newTemp( Ity_I32);
4913 IRTemp vB_word2 = newTemp( Ity_I32);
4914 IRTemp vB_word3 = newTemp( Ity_I32);
4916 IRTemp eq_word1 = newTemp( Ity_I1);
4917 IRTemp eq_word2 = newTemp( Ity_I1);
4918 IRTemp eq_word3 = newTemp( Ity_I1);
4921 IRExpr *gt_word0, *gt_word1, *gt_word2, *gt_word3;
4922 IRExpr *eq_word3_2, *eq_word3_2_1;
4923 IRTemp result = newTemp( Ity_I1 );
4925 assign( vA_word0, unop( Iop_64to32, unop( Iop_V128to64, vA ) ) );
4926 assign( vA_word1, unop( Iop_64HIto32, unop( Iop_V128to64, vA ) ) );
4927 assign( vA_word2, unop( Iop_64to32, unop( Iop_V128HIto64, vA ) ) );
4928 assign( vA_word3, unop( Iop_64HIto32, unop( Iop_V128HIto64, vA ) ) );
4930 assign( vB_word0, unop( Iop_64to32, unop( Iop_V128to64, vB ) ) );
4931 assign( vB_word1, unop( Iop_64HIto32, unop( Iop_V128to64, vB ) ) );
4932 assign( vB_word2, unop( Iop_64to32, unop( Iop_V128HIto64, vB ) ) );
4933 assign( vB_word3, unop( Iop_64HIto32, unop( Iop_V128HIto64, vB ) ) );
4935 assign( eq_word3, binop( Iop_CmpEQ32, mkexpr( vA_word3 ),
4936 mkexpr( vB_word3 ) ) );
4937 assign( eq_word2, binop( Iop_CmpEQ32, mkexpr( vA_word2 ),
4938 mkexpr( vB_word2 ) ) );
4939 assign( eq_word1, binop( Iop_CmpEQ32, mkexpr( vA_word1 ),
4940 mkexpr( vB_word1 ) ) );
4942 gt_word3 = binop( Iop_CmpLT32U, mkexpr( vB_word3 ), mkexpr( vA_word3 ) );
4943 gt_word2 = binop( Iop_CmpLT32U, mkexpr( vB_word2 ), mkexpr( vA_word2 ) );
4944 gt_word1 = binop( Iop_CmpLT32U, mkexpr( vB_word1 ), mkexpr( vA_word1 ) );
4945 gt_word0 = binop( Iop_CmpLT32U, mkexpr( vB_word0 ), mkexpr( vA_word0 ) );
4947 eq_word3_2 = mkAND1( mkexpr( eq_word3 ), mkexpr( eq_word2 ) );
4948 eq_word3_2_1 = mkAND1( mkexpr( eq_word1 ), eq_word3_2 );
4950 assign( result, mkOR1(
4951 mkOR1( gt_word3,
4952 mkAND1( mkexpr( eq_word3 ), gt_word2 ) ),
4953 mkOR1( mkAND1( eq_word3_2, gt_word1 ),
4954 mkAND1( eq_word3_2_1, gt_word0 ) ) ) );
4955 return mkexpr( result );
4958 /*------------------------------------------------------------*/
4959 /*--- FP Helpers ---*/
4960 /*------------------------------------------------------------*/
4962 /* Produce the 32-bit pattern corresponding to the supplied
4963 float. */
4964 static UInt float_to_bits ( Float f )
4966 union { UInt i; Float f; } u;
4967 vassert(4 == sizeof(UInt));
4968 vassert(4 == sizeof(Float));
4969 vassert(4 == sizeof(u));
4970 u.f = f;
4971 return u.i;
4974 static IRExpr* dnorm_adj_Vector ( IRExpr* src )
4976 /* This function takes a vector of 32-bit floats. It does the required
4977 adjustment on denormalized values based on the setting of the
4978 VSCR[NJ] bit.
4980 The VSCR[NJ] bit controlls how subnormal (denormalized) results for
4981 vector floating point operations are handled. VSCR[NJ] is bit 17
4982 (bit 111 IBM numbering).
4984 VSCR[NJ] = 0 Denormalized values are handled as
4985 specified by Java and the IEEE standard.
4987 VSCR[NJ] = 1 If an element in a source VR contains a denormalized
4988 value, the value 0 is used instead. If an instruction
4989 causes an Underflow Exception, the corresponding element
4990 in the target VR is set to 0. In both cases the 0 has
4991 the same sign as the denormalized or underflowing value.
4992 Convert negative zero to positive zero.
4994 The ABI for LE requires VSCR[NJ] = 0. For BE mode, VSCR[NJ] = 1 by
4995 default. The PPC guest state is initialized to match the HW setup.
4997 IRTemp sign_bit_maskV128 = newTemp( Ity_V128 );
4998 IRTemp ones_maskV128 = newTemp( Ity_V128 );
4999 IRTemp clear_dnorm_maskV128 = newTemp( Ity_V128 );
5000 IRTemp adj_valueV128 = newTemp( Ity_V128 );
5001 IRTemp dnormV128 = newTemp( Ity_V128 );
5002 IRTemp zeroV128 = newTemp( Ity_V128 );
5003 IRTemp VSCR_NJ = newTemp( Ity_I64 );
5004 IRTemp VSCR_NJ_mask = newTemp( Ity_V128 );
5005 IRTemp resultV128 = newTemp( Ity_V128 );
5007 /* get the VSCR[NJ] bit */
5008 assign( VSCR_NJ,
5009 unop( Iop_1Sto64,
5010 unop( Iop_32to1,
5011 binop( Iop_Shr32,
5012 getGST( PPC_GST_VSCR ),
5013 mkU8( 16 ) ) ) ) );
5015 assign ( VSCR_NJ_mask, binop( Iop_64HLtoV128,
5016 mkexpr( VSCR_NJ ) ,
5017 mkexpr( VSCR_NJ ) ) );
5019 /* Create the masks to do the rounding of dnorm values and absolute
5020 value of zero. */
5021 assign( dnormV128, is_Denorm_Vector( Ity_I32, src ) );
5022 assign( zeroV128, is_Zero_Vector( Ity_I32, src ) );
5024 /* If the value is dnorm, then we need to clear the significand and
5025 exponent but leave the sign bit. Put 1'x in elements that are not
5026 denormalized values. */
5027 assign( sign_bit_maskV128, unop( Iop_Dup32x4, mkU32( 0x80000000 ) ) );
5029 assign( clear_dnorm_maskV128,
5030 binop( Iop_OrV128,
5031 binop( Iop_AndV128,
5032 mkexpr( dnormV128 ),
5033 mkexpr( sign_bit_maskV128 ) ),
5034 unop( Iop_NotV128, mkexpr( dnormV128 ) ) ) );
5036 assign( ones_maskV128, mkV128( 0xFFFF ) );
5038 assign( adj_valueV128, binop( Iop_AndV128,
5039 mkexpr( clear_dnorm_maskV128 ),
5040 binop( Iop_AndV128,
5041 src,
5042 mkexpr( ones_maskV128 ) ) ) );
5044 /* If the VSCR[NJ] bit is 1, then clear the denormalized values,
5045 otherwise just return the input unchanged. */
5046 assign( resultV128,
5047 binop( Iop_OrV128,
5048 binop( Iop_AndV128,
5049 mkexpr( VSCR_NJ_mask ),
5050 mkexpr( adj_valueV128 ) ),
5051 binop( Iop_AndV128,
5052 unop( Iop_NotV128, mkexpr( VSCR_NJ_mask ) ),
5053 src ) ) );
5055 return mkexpr(resultV128);
5058 /*------------------------------------------------------------*/
5059 /* Transactional memory helpers
5061 *------------------------------------------------------------*/
5063 static ULong generate_TMreason( UInt failure_code,
5064 UInt persistant,
5065 UInt nest_overflow,
5066 UInt tm_exact )
5068 ULong tm_err_code =
5069 ( (ULong) 0) << (63-6) /* Failure code */
5070 | ( (ULong) persistant) << (63-7) /* Failure persistant */
5071 | ( (ULong) 0) << (63-8) /* Disallowed */
5072 | ( (ULong) nest_overflow) << (63-9) /* Nesting Overflow */
5073 | ( (ULong) 0) << (63-10) /* Footprint Overflow */
5074 | ( (ULong) 0) << (63-11) /* Self-Induced Conflict */
5075 | ( (ULong) 0) << (63-12) /* Non-Transactional Conflict */
5076 | ( (ULong) 0) << (63-13) /* Transactional Conflict */
5077 | ( (ULong) 0) << (63-14) /* Translation Invalidation Conflict */
5078 | ( (ULong) 0) << (63-15) /* Implementation-specific */
5079 | ( (ULong) 0) << (63-16) /* Instruction Fetch Conflict */
5080 | ( (ULong) 0) << (63-30) /* Reserved */
5081 | ( (ULong) 0) << (63-31) /* Abort */
5082 | ( (ULong) 0) << (63-32) /* Suspend */
5083 | ( (ULong) 0) << (63-33) /* Reserved */
5084 | ( (ULong) 0) << (63-35) /* Privilege */
5085 | ( (ULong) 0) << (63-36) /* Failure Summary */
5086 | ( (ULong) tm_exact) << (63-37) /* TFIAR Exact */
5087 | ( (ULong) 0) << (63-38) /* ROT */
5088 | ( (ULong) 0) << (63-51) /* Reserved */
5089 | ( (ULong) 0) << (63-63); /* Transaction Level */
5091 return tm_err_code;
5094 static void storeTMfailure( Addr64 err_address, ULong tm_reason,
5095 Addr64 handler_address )
5097 putGST( PPC_GST_TFIAR, mkU64( err_address ) );
5098 putGST( PPC_GST_TEXASR, mkU64( tm_reason ) );
5099 putGST( PPC_GST_TEXASRU, mkU32( 0 ) );
5100 putGST( PPC_GST_TFHAR, mkU64( handler_address ) );
5103 /*------------------------------------------------------------*/
5104 /*--- Integer Instruction Translation --- */
5105 /*------------------------------------------------------------*/
5108 Integer Arithmetic Instructions
5110 static Bool dis_int_mult_add ( UInt theInstr )
5112 /* VA-Form */
5113 UChar rD_addr = ifieldRegDS( theInstr );
5114 UChar rA_addr = ifieldRegA( theInstr );
5115 UChar rB_addr = ifieldRegB( theInstr );
5116 UChar rC_addr = ifieldRegC( theInstr );
5117 UInt opc2 = IFIELD( theInstr, 0, 6 );
5118 IRType ty = Ity_I64;
5119 IRTemp rA = newTemp( ty );
5120 IRTemp rB = newTemp( ty );
5121 IRTemp rC = newTemp( ty );
5122 IRTemp rD = newTemp( ty );
5123 IRTemp tmpLo = newTemp( Ity_I64 );
5124 IRTemp tmpHi = newTemp( Ity_I64 );
5125 IRTemp tmp2Hi = newTemp( Ity_I64 );
5126 IRTemp result = newTemp( Ity_I128 );
5127 IRTemp resultLo = newTemp( Ity_I64 );
5128 IRExpr* carryout;
5130 assign( rA, getIReg( rA_addr ) );
5131 assign( rB, getIReg( rB_addr ) );
5132 assign( rC, getIReg( rC_addr ) );
5134 switch (opc2) {
5135 case 0x30: // maddhd multiply-add High doubleword signed
5136 DIP("maddhd r%u,r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr, rC_addr);
5138 assign( result, binop( Iop_MullS64, mkexpr( rA ), mkexpr( rB ) ) );
5139 assign( tmpLo, unop( Iop_128to64, mkexpr( result ) ) );
5140 assign( tmpHi, unop( Iop_128HIto64, mkexpr( result ) ) );
5142 /* Multiply rA and rB then add rC. If the lower 32-bits of the result
5143 * is less then rC and the result rA * rB, a carry out of the lower 32
5144 * bits occurred and the upper 32 bits must be incremented by 1. Sign
5145 * extend rC and do the add to the upper 64 bits to handle the
5146 * negative case for rC.
5148 assign( resultLo, binop( Iop_Add64, mkexpr( tmpLo ), mkexpr( rC ) ) );
5149 assign( tmp2Hi, binop( Iop_Add64,
5150 mkexpr( tmpHi ),
5151 unop( Iop_1Sto64,
5152 unop( Iop_64to1,
5153 binop( Iop_Shr64,
5154 mkexpr( rC ),
5155 mkU8( 63 ) ) ) ) ) );
5157 /* need to do calculation for the upper 32 bit result */
5158 carryout = mkAND1( binop( Iop_CmpLT64U,
5159 mkexpr( resultLo ), mkexpr( rC ) ),
5160 binop( Iop_CmpLT64U,
5161 mkexpr( resultLo ), mkexpr( tmpLo ) ) );
5162 assign( rD, binop( Iop_Add64,
5163 mkexpr( tmp2Hi ),
5164 unop( Iop_1Uto64, carryout ) ) );
5165 break;
5167 case 0x31: // maddhdu multiply-add High doubleword unsigned
5168 DIP("maddhdu r%u,r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr, rC_addr);
5170 assign( result, binop( Iop_MullU64, mkexpr( rA ), mkexpr( rB ) ) );
5171 assign( tmpLo, unop( Iop_128to64, mkexpr( result ) ) );
5172 assign( tmpHi, unop( Iop_128HIto64, mkexpr( result ) ) );
5174 /* Add rC, if the lower 32-bits of the result is less then rC and
5175 * tmpLo, a carry out of the lower 32 bits occurred. Upper 32 bits
5176 * must be incremented by 1.
5178 assign( resultLo, binop( Iop_Add64, mkexpr( tmpLo ), mkexpr( rC ) ) );
5180 /* need to do calculation for the upper 32 bit result */
5181 carryout = mkAND1( binop( Iop_CmpLT64U,
5182 mkexpr(resultLo), mkexpr( rC ) ),
5183 binop( Iop_CmpLT64U,
5184 mkexpr(resultLo), mkexpr( tmpLo ) ) );
5185 assign( rD, binop( Iop_Add64,
5186 mkexpr( tmpHi ),
5187 unop( Iop_1Uto64, carryout ) ) );
5188 break;
5190 case 0x33: // maddld multiply-add Low doubleword
5191 DIP("maddld r%u,r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr, rC_addr);
5193 assign( result, binop( Iop_MullS64, mkexpr( rA ), mkexpr( rB ) ) );
5194 assign( tmpLo, unop( Iop_128to64, mkexpr( result ) ) );
5195 assign( tmpHi, unop( Iop_128HIto64, mkexpr( result ) ) );
5197 assign( rD, binop( Iop_Add64, mkexpr( tmpLo ), mkexpr( rC ) ) );
5198 break;
5200 default:
5201 vex_printf("dis_int_mult(ppc): unrecognized instruction\n");
5202 return False;
5205 putIReg( rD_addr, mkexpr(rD) );
5207 return True;
5210 static Bool dis_int_arith ( UInt theInstr )
5212 /* D-Form, XO-Form */
5213 UChar opc1 = ifieldOPC(theInstr);
5214 UChar rD_addr = ifieldRegDS(theInstr);
5215 UChar rA_addr = ifieldRegA(theInstr);
5216 UInt uimm16 = ifieldUIMM16(theInstr);
5217 UChar rB_addr = ifieldRegB(theInstr);
5218 UChar flag_OE = ifieldBIT10(theInstr);
5219 UInt opc2 = ifieldOPClo9(theInstr);
5220 UChar flag_rC = ifieldBIT0(theInstr);
5222 Long simm16 = extend_s_16to64(uimm16);
5223 IRType ty = mode64 ? Ity_I64 : Ity_I32;
5224 IRTemp rA = newTemp(ty);
5225 IRTemp rB = newTemp(ty);
5226 IRTemp rD = newTemp(ty);
5228 Bool do_rc = False;
5230 assign( rA, getIReg(rA_addr) );
5231 assign( rB, getIReg(rB_addr) ); // XO-Form: rD, rA, rB
5233 switch (opc1) {
5234 /* D-Form */
5235 case 0x0C: // addic (Add Immediate Carrying, PPC32 p351
5236 DIP("addic r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
5237 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
5238 mkSzExtendS16(ty, uimm16) ) );
5239 set_XER_CA_CA32( ty, PPCG_FLAG_OP_ADD,
5240 mkexpr(rD), mkexpr(rA), mkSzExtendS16(ty, uimm16),
5241 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
5242 break;
5244 case 0x0D: // addic. (Add Immediate Carrying and Record, PPC32 p352)
5245 DIP("addic. r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
5246 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
5247 mkSzExtendS16(ty, uimm16) ) );
5248 set_XER_CA_CA32( ty, PPCG_FLAG_OP_ADD,
5249 mkexpr(rD), mkexpr(rA), mkSzExtendS16(ty, uimm16),
5250 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
5251 do_rc = True; // Always record to CR
5252 flag_rC = 1;
5253 break;
5255 case 0x0E: // addi (Add Immediate, PPC32 p350)
5256 // li rD,val == addi rD,0,val
5257 // la disp(rA) == addi rD,rA,disp
5258 if ( rA_addr == 0 ) {
5259 DIP("li r%u,%d\n", rD_addr, (Int)simm16);
5260 assign( rD, mkSzExtendS16(ty, uimm16) );
5261 } else {
5262 DIP("addi r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
5263 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
5264 mkSzExtendS16(ty, uimm16) ) );
5266 break;
5268 case 0x0F: // addis (Add Immediate Shifted, PPC32 p353)
5269 // lis rD,val == addis rD,0,val
5270 if ( rA_addr == 0 ) {
5271 DIP("lis r%u,%d\n", rD_addr, (Int)simm16);
5272 assign( rD, mkSzExtendS32(ty, uimm16 << 16) );
5273 } else {
5274 DIP("addis r%u,r%u,0x%x\n", rD_addr, rA_addr, (UInt)simm16);
5275 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
5276 mkSzExtendS32(ty, uimm16 << 16) ) );
5278 break;
5280 case 0x07: // mulli (Multiply Low Immediate, PPC32 p490)
5281 DIP("mulli r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
5282 if (mode64)
5283 assign( rD, unop(Iop_128to64,
5284 binop(Iop_MullS64, mkexpr(rA),
5285 mkSzExtendS16(ty, uimm16))) );
5286 else
5287 assign( rD, unop(Iop_64to32,
5288 binop(Iop_MullS32, mkexpr(rA),
5289 mkSzExtendS16(ty, uimm16))) );
5290 break;
5292 case 0x08: // subfic (Subtract from Immediate Carrying, PPC32 p540)
5293 DIP("subfic r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
5294 // rD = simm16 - rA
5295 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
5296 mkSzExtendS16(ty, uimm16),
5297 mkexpr(rA)) );
5298 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SUBFI,
5299 mkexpr(rD), mkexpr(rA), mkSzExtendS16(ty, uimm16),
5300 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
5301 break;
5303 /* XO-Form */
5304 case 0x1F:
5305 do_rc = True; // All below record to CR
5307 switch (opc2) {
5308 case 0x10A: // add (Add, PPC32 p347)
5309 DIP("add%s%s r%u,r%u,r%u\n",
5310 flag_OE ? "o" : "", flag_rC ? ".":"",
5311 rD_addr, rA_addr, rB_addr);
5312 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5313 mkexpr(rA), mkexpr(rB) ) );
5314 if (flag_OE) {
5315 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_ADD,
5316 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5318 break;
5320 case 0x00A: // addc (Add Carrying, PPC32 p348)
5321 DIP("addc%s%s r%u,r%u,r%u\n",
5322 flag_OE ? "o" : "", flag_rC ? ".":"",
5323 rD_addr, rA_addr, rB_addr);
5324 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5325 mkexpr(rA), mkexpr(rB)) );
5326 set_XER_CA_CA32( ty, PPCG_FLAG_OP_ADD,
5327 mkexpr(rD), mkexpr(rA), mkexpr(rB),
5328 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
5329 if (flag_OE) {
5330 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_ADD,
5331 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5333 break;
5335 case 0x08A: { // adde (Add Extended, PPC32 p349)
5336 IRTemp old_xer_ca = newTemp(ty);
5337 DIP("adde%s%s r%u,r%u,r%u\n",
5338 flag_OE ? "o" : "", flag_rC ? ".":"",
5339 rD_addr, rA_addr, rB_addr);
5340 // rD = rA + rB + XER[CA]
5341 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA_32(), False) );
5342 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
5343 binop( mkSzOp(ty, Iop_Add8),
5344 mkexpr(rB), mkexpr(old_xer_ca))) );
5345 set_XER_CA_CA32( ty, PPCG_FLAG_OP_ADDE,
5346 mkexpr(rD), mkexpr(rA), mkexpr(rB),
5347 mkexpr(old_xer_ca) );
5348 if (flag_OE) {
5349 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_ADDE,
5350 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5352 break;
5355 case 0xAA: {// addex (Add Extended alternate carry bit Z23-form)
5356 IRTemp old_xer_ov = newTemp(ty);
5357 DIP("addex r%u,r%u,r%u,%d\n", rD_addr, rA_addr, rB_addr, (Int)flag_OE);
5358 assign( old_xer_ov, mkWidenFrom32(ty, getXER_OV_32(), False) );
5359 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
5360 binop( mkSzOp(ty, Iop_Add8), mkexpr(rB),
5361 mkexpr(old_xer_ov) ) ) );
5363 /* CY bit is same as OE bit */
5364 if (flag_OE == 0) {
5365 /* Exception, do not set SO bit and set OV from carry. */
5366 set_XER_OV_OV32_ADDEX( ty, mkexpr(rD), mkexpr(rA), mkexpr(rB),
5367 mkexpr(old_xer_ov) );
5368 } else {
5369 /* CY=1, 2 and 3 (AKA flag_OE) are reserved */
5370 vex_printf("addex instruction, CY = %d is reserved.\n", flag_OE);
5371 vpanic("addex instruction\n");
5373 break;
5376 case 0x0EA: { // addme (Add to Minus One Extended, PPC32 p354)
5377 IRTemp old_xer_ca = newTemp(ty);
5378 IRExpr *min_one;
5379 if (rB_addr != 0) {
5380 vex_printf("dis_int_arith(ppc)(addme,rB_addr)\n");
5381 return False;
5383 DIP("addme%s%s r%u,r%u,r%u\n",
5384 flag_OE ? "o" : "", flag_rC ? ".":"",
5385 rD_addr, rA_addr, rB_addr);
5386 // rD = rA + (-1) + XER[CA]
5387 // => Just another form of adde
5388 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA_32(), False) );
5389 min_one = mkSzImm(ty, (Long)-1);
5390 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
5391 binop( mkSzOp(ty, Iop_Add8),
5392 min_one, mkexpr(old_xer_ca)) ));
5393 set_XER_CA_CA32( ty, PPCG_FLAG_OP_ADDE,
5394 mkexpr(rD), mkexpr(rA), min_one,
5395 mkexpr(old_xer_ca) );
5396 if (flag_OE) {
5397 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_ADDE,
5398 mkexpr(rD), mkexpr(rA), min_one );
5400 break;
5403 case 0x0CA: { // addze (Add to Zero Extended, PPC32 p355)
5404 IRTemp old_xer_ca = newTemp(ty);
5405 if (rB_addr != 0) {
5406 vex_printf("dis_int_arith(ppc)(addze,rB_addr)\n");
5407 return False;
5409 DIP("addze%s%s r%u,r%u,r%u\n",
5410 flag_OE ? "o" : "", flag_rC ? ".":"",
5411 rD_addr, rA_addr, rB_addr);
5412 // rD = rA + (0) + XER[CA]
5413 // => Just another form of adde
5414 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA_32(), False) );
5415 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5416 mkexpr(rA), mkexpr(old_xer_ca)) );
5417 set_XER_CA_CA32( ty, PPCG_FLAG_OP_ADDE,
5418 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0),
5419 mkexpr(old_xer_ca) );
5420 if (flag_OE) {
5421 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_ADDE,
5422 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0) );
5424 break;
5427 case 0x1EB: // divw (Divide Word, PPC32 p388)
5428 DIP("divw%s%s r%u,r%u,r%u\n",
5429 flag_OE ? "o" : "", flag_rC ? ".":"",
5430 rD_addr, rA_addr, rB_addr);
5431 if (mode64) {
5432 /* Note:
5433 XER settings are mode independent, and reflect the
5434 overflow of the low-order 32bit result
5435 CR0[LT|GT|EQ] are undefined if flag_rC && mode64
5437 /* rD[hi32] are undefined: setting them to sign of lo32
5438 - makes set_CR0 happy */
5439 IRExpr* dividend = mk64lo32Sto64( mkexpr(rA) );
5440 IRExpr* divisor = mk64lo32Sto64( mkexpr(rB) );
5441 assign( rD, mk64lo32Uto64( binop(Iop_DivS64, dividend,
5442 divisor) ) );
5443 if (flag_OE) {
5444 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_DIVW,
5445 mkexpr(rD), dividend, divisor );
5447 } else {
5448 assign( rD, binop(Iop_DivS32, mkexpr(rA), mkexpr(rB)) );
5449 if (flag_OE) {
5450 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_DIVW,
5451 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5454 /* Note:
5455 if (0x8000_0000 / -1) or (x / 0)
5456 => rD=undef, if(flag_rC) CR7=undef, if(flag_OE) XER_OV=1
5457 => But _no_ exception raised. */
5458 break;
5460 case 0x1CB: // divwu (Divide Word Unsigned, PPC32 p389)
5461 DIP("divwu%s%s r%u,r%u,r%u\n",
5462 flag_OE ? "o" : "", flag_rC ? ".":"",
5463 rD_addr, rA_addr, rB_addr);
5464 if (mode64) {
5465 /* Note:
5466 XER settings are mode independent, and reflect the
5467 overflow of the low-order 32bit result
5468 CR0[LT|GT|EQ] are undefined if flag_rC && mode64
5470 IRExpr* dividend = mk64lo32Uto64( mkexpr(rA) );
5471 IRExpr* divisor = mk64lo32Uto64( mkexpr(rB) );
5472 assign( rD, mk64lo32Uto64( binop(Iop_DivU64, dividend,
5473 divisor) ) );
5474 if (flag_OE) {
5475 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_DIVWU,
5476 mkexpr(rD), dividend, divisor );
5478 } else {
5479 assign( rD, binop(Iop_DivU32, mkexpr(rA), mkexpr(rB)) );
5480 if (flag_OE) {
5481 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_DIVWU,
5482 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5485 /* Note: ditto comment divw, for (x / 0) */
5486 break;
5488 case 0x04B: // mulhw (Multiply High Word, PPC32 p488)
5489 if (flag_OE != 0) {
5490 vex_printf("dis_int_arith(ppc)(mulhw,flag_OE)\n");
5491 return False;
5493 DIP("mulhw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
5494 rD_addr, rA_addr, rB_addr);
5495 if (mode64) {
5496 /* rD[hi32] are undefined: setting them to sign of lo32
5497 - makes set_CR0 happy */
5498 assign( rD, binop(Iop_Sar64,
5499 binop(Iop_Mul64,
5500 mk64lo32Sto64( mkexpr(rA) ),
5501 mk64lo32Sto64( mkexpr(rB) )),
5502 mkU8(32)) );
5503 } else {
5504 assign( rD, unop(Iop_64HIto32,
5505 binop(Iop_MullS32,
5506 mkexpr(rA), mkexpr(rB))) );
5508 break;
5510 case 0x00B: // mulhwu (Multiply High Word Unsigned, PPC32 p489)
5511 if (flag_OE != 0) {
5512 vex_printf("dis_int_arith(ppc)(mulhwu,flag_OE)\n");
5513 return False;
5515 DIP("mulhwu%s r%u,r%u,r%u\n", flag_rC ? ".":"",
5516 rD_addr, rA_addr, rB_addr);
5517 if (mode64) {
5518 /* rD[hi32] are undefined: setting them to sign of lo32
5519 - makes set_CR0 happy */
5520 assign( rD, binop(Iop_Sar64,
5521 binop(Iop_Mul64,
5522 mk64lo32Uto64( mkexpr(rA) ),
5523 mk64lo32Uto64( mkexpr(rB) ) ),
5524 mkU8(32)) );
5525 } else {
5526 assign( rD, unop(Iop_64HIto32,
5527 binop(Iop_MullU32,
5528 mkexpr(rA), mkexpr(rB))) );
5530 break;
5532 case 0x0EB: // mullw (Multiply Low Word, PPC32 p491)
5533 DIP("mullw%s%s r%u,r%u,r%u\n",
5534 flag_OE ? "o" : "", flag_rC ? ".":"",
5535 rD_addr, rA_addr, rB_addr);
5536 if (mode64) {
5537 /* rD[hi32] are undefined: setting them to sign of lo32
5538 - set_XER_OV() and set_CR0() depend on this */
5539 IRExpr *a = unop(Iop_64to32, mkexpr(rA) );
5540 IRExpr *b = unop(Iop_64to32, mkexpr(rB) );
5541 assign( rD, binop(Iop_MullS32, a, b) );
5542 if (flag_OE) {
5543 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_MULLW,
5544 mkexpr(rD),
5545 unop(Iop_32Uto64, a), unop(Iop_32Uto64, b) );
5547 } else {
5548 assign( rD, unop(Iop_64to32,
5549 binop(Iop_MullU32,
5550 mkexpr(rA), mkexpr(rB))) );
5551 if (flag_OE) {
5552 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_MULLW,
5553 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5556 break;
5558 case 0x068: // neg (Negate, PPC32 p493)
5559 if (rB_addr != 0) {
5560 vex_printf("dis_int_arith(ppc)(neg,rB_addr)\n");
5561 return False;
5563 DIP("neg%s%s r%u,r%u\n",
5564 flag_OE ? "o" : "", flag_rC ? ".":"",
5565 rD_addr, rA_addr);
5566 // rD = (~rA) + 1
5567 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5568 unop( mkSzOp(ty, Iop_Not8), mkexpr(rA) ),
5569 mkSzImm(ty, 1)) );
5570 if (flag_OE) {
5571 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_NEG,
5572 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5574 break;
5576 case 0x028: // subf (Subtract From, PPC32 p537)
5577 DIP("subf%s%s r%u,r%u,r%u\n",
5578 flag_OE ? "o" : "", flag_rC ? ".":"",
5579 rD_addr, rA_addr, rB_addr);
5580 // rD = rB - rA
5581 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
5582 mkexpr(rB), mkexpr(rA)) );
5583 if (flag_OE) {
5584 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_SUBF,
5585 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5587 break;
5589 case 0x008: // subfc (Subtract from Carrying, PPC32 p538)
5590 DIP("subfc%s%s r%u,r%u,r%u\n",
5591 flag_OE ? "o" : "", flag_rC ? ".":"",
5592 rD_addr, rA_addr, rB_addr);
5593 // rD = rB - rA
5594 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
5595 mkexpr(rB), mkexpr(rA)) );
5596 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SUBFC,
5597 mkexpr(rD), mkexpr(rA), mkexpr(rB),
5598 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
5599 if (flag_OE) {
5600 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_SUBFC,
5601 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5603 break;
5605 case 0x088: {// subfe (Subtract from Extended, PPC32 p539)
5606 IRTemp old_xer_ca = newTemp(ty);
5607 DIP("subfe%s%s r%u,r%u,r%u\n",
5608 flag_OE ? "o" : "", flag_rC ? ".":"",
5609 rD_addr, rA_addr, rB_addr);
5610 // rD = (log not)rA + rB + XER[CA]
5611 // ==>
5612 // rD = rB - rA - (XER[CA] ^ 1)
5613 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA_32(), False) );
5614 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
5615 binop( mkSzOp(ty, Iop_Sub8),
5616 mkexpr(rB), mkexpr(rA)),
5617 binop(mkSzOp(ty, Iop_Xor8),
5618 mkexpr(old_xer_ca),
5619 mkSzImm(ty, 1))) );
5620 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SUBFE,
5621 mkexpr(rD), mkexpr(rA), mkexpr(rB),
5622 mkexpr(old_xer_ca) );
5623 if (flag_OE) {
5624 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_SUBFE,
5625 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5627 break;
5630 case 0x0E8: { // subfme (Subtract from -1 Extended, PPC32 p541)
5631 IRTemp old_xer_ca = newTemp(ty);
5632 IRExpr *min_one;
5633 if (rB_addr != 0) {
5634 vex_printf("dis_int_arith(ppc)(subfme,rB_addr)\n");
5635 return False;
5637 DIP("subfme%s%s r%u,r%u\n",
5638 flag_OE ? "o" : "", flag_rC ? ".":"",
5639 rD_addr, rA_addr);
5640 // rD = (log not)rA + (-1) + XER[CA]
5641 // => Just another form of subfe
5642 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA_32(), False) );
5643 min_one = mkSzImm(ty, (Long)-1);
5644 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5645 unop( mkSzOp(ty, Iop_Not8), mkexpr(rA)),
5646 binop( mkSzOp(ty, Iop_Add8),
5647 min_one, mkexpr(old_xer_ca))) );
5648 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SUBFE,
5649 mkexpr(rD), mkexpr(rA), min_one,
5650 mkexpr(old_xer_ca) );
5651 if (flag_OE) {
5652 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_SUBFE,
5653 mkexpr(rD), mkexpr(rA), min_one );
5655 break;
5658 case 0x0C8: { // subfze (Subtract from Zero Extended, PPC32 p542)
5659 IRTemp old_xer_ca = newTemp(ty);
5660 if (rB_addr != 0) {
5661 vex_printf("dis_int_arith(ppc)(subfze,rB_addr)\n");
5662 return False;
5664 DIP("subfze%s%s r%u,r%u\n",
5665 flag_OE ? "o" : "", flag_rC ? ".":"",
5666 rD_addr, rA_addr);
5667 // rD = (log not)rA + (0) + XER[CA]
5668 // => Just another form of subfe
5669 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA_32(), False) );
5670 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5671 unop( mkSzOp(ty, Iop_Not8),
5672 mkexpr(rA)), mkexpr(old_xer_ca)) );
5673 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SUBFE,
5674 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0),
5675 mkexpr(old_xer_ca) );
5676 if (flag_OE) {
5677 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_SUBFE,
5678 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0) );
5680 break;
5684 /* 64bit Arithmetic */
5685 case 0x49: // mulhd (Multiply High DWord, PPC64 p539)
5686 if (flag_OE != 0) {
5687 vex_printf("dis_int_arith(ppc)(mulhd,flagOE)\n");
5688 return False;
5690 DIP("mulhd%s r%u,r%u,r%u\n", flag_rC ? ".":"",
5691 rD_addr, rA_addr, rB_addr);
5692 assign( rD, unop(Iop_128HIto64,
5693 binop(Iop_MullS64,
5694 mkexpr(rA), mkexpr(rB))) );
5696 break;
5698 case 0x9: // mulhdu (Multiply High DWord Unsigned, PPC64 p540)
5699 if (flag_OE != 0) {
5700 vex_printf("dis_int_arith(ppc)(mulhdu,flagOE)\n");
5701 return False;
5703 DIP("mulhdu%s r%u,r%u,r%u\n", flag_rC ? ".":"",
5704 rD_addr, rA_addr, rB_addr);
5705 assign( rD, unop(Iop_128HIto64,
5706 binop(Iop_MullU64,
5707 mkexpr(rA), mkexpr(rB))) );
5708 break;
5710 case 0xE9: // mulld (Multiply Low DWord, PPC64 p543)
5711 DIP("mulld%s%s r%u,r%u,r%u\n",
5712 flag_OE ? "o" : "", flag_rC ? ".":"",
5713 rD_addr, rA_addr, rB_addr);
5714 assign( rD, binop(Iop_Mul64, mkexpr(rA), mkexpr(rB)) );
5715 if (flag_OE) {
5716 set_XER_OV_64( PPCG_FLAG_OP_MULLD,
5717 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5718 /* OV is set to 1 if product isn't representable.
5719 * In this case also need to set OV32 and SO to 1,
5720 * i.e. copy OV to OV32 and SO.
5722 copy_OV_to_OV32();
5723 update_SO();
5725 break;
5727 case 0x1E9: // divd (Divide DWord, PPC64 p419)
5728 DIP("divd%s%s r%u,r%u,r%u\n",
5729 flag_OE ? "o" : "", flag_rC ? ".":"",
5730 rD_addr, rA_addr, rB_addr);
5731 assign( rD, binop(Iop_DivS64, mkexpr(rA), mkexpr(rB)) );
5732 if (flag_OE) {
5733 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_DIVW,
5734 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5736 break;
5737 /* Note:
5738 if (0x8000_0000_0000_0000 / -1) or (x / 0)
5739 => rD=undef, if(flag_rC) CR7=undef, if(flag_OE) XER_OV=1
5740 => But _no_ exception raised. */
5742 case 0x1C9: // divdu (Divide DWord Unsigned, PPC64 p420)
5743 DIP("divdu%s%s r%u,r%u,r%u\n",
5744 flag_OE ? "o" : "", flag_rC ? ".":"",
5745 rD_addr, rA_addr, rB_addr);
5746 assign( rD, binop(Iop_DivU64, mkexpr(rA), mkexpr(rB)) );
5747 if (flag_OE) {
5748 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_DIVWU,
5749 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5751 break;
5752 /* Note: ditto comment divd, for (x / 0) */
5754 case 0x18B: // divweu (Divide Word Extended Unsigned)
5757 * If (RA) >= (RB), or if an attempt is made to perform the division
5758 * <anything> / 0
5759 * then the contents of register RD are undefined as are (if Rc=1) the contents of
5760 * the LT, GT, and EQ bits of CR Field 0. In these cases, if OE=1 then OV is set
5761 * to 1.
5763 IRTemp res = newTemp(Ity_I32);
5764 IRExpr * dividend, * divisor;
5765 DIP("divweu%s%s r%u,r%u,r%u\n",
5766 flag_OE ? "o" : "", flag_rC ? ".":"",
5767 rD_addr, rA_addr, rB_addr);
5768 if (mode64) {
5769 dividend = unop( Iop_64to32, mkexpr( rA ) );
5770 divisor = unop( Iop_64to32, mkexpr( rB ) );
5771 assign( res, binop( Iop_DivU32E, dividend, divisor ) );
5772 assign( rD, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( res ) ) );
5773 } else {
5774 dividend = mkexpr( rA );
5775 divisor = mkexpr( rB );
5776 assign( res, binop( Iop_DivU32E, dividend, divisor ) );
5777 assign( rD, mkexpr( res) );
5780 if (flag_OE) {
5781 set_XER_OV_OV32_32( PPCG_FLAG_OP_DIVWEU,
5782 mkexpr(res), dividend, divisor );
5783 update_SO( );
5785 break;
5788 case 0x1AB: // divwe (Divide Word Extended)
5791 * If the quotient cannot be represented in 32 bits, or if an
5792 * attempt is made to perform the division
5793 * <anything> / 0
5794 * then the contents of register RD are undefined as are (if
5795 * Rc=1) the contents of the LT, GT, and EQ bits of CR
5796 * Field 0. In these cases, if OE=1 then OV is set to 1.
5799 IRTemp res = newTemp(Ity_I32);
5800 IRExpr * dividend, * divisor;
5801 DIP("divwe%s%s r%u,r%u,r%u\n",
5802 flag_OE ? "o" : "", flag_rC ? ".":"",
5803 rD_addr, rA_addr, rB_addr);
5804 if (mode64) {
5805 dividend = unop( Iop_64to32, mkexpr( rA ) );
5806 divisor = unop( Iop_64to32, mkexpr( rB ) );
5807 assign( res, binop( Iop_DivS32E, dividend, divisor ) );
5808 assign( rD, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( res ) ) );
5809 } else {
5810 dividend = mkexpr( rA );
5811 divisor = mkexpr( rB );
5812 assign( res, binop( Iop_DivS32E, dividend, divisor ) );
5813 assign( rD, mkexpr( res) );
5816 if (flag_OE) {
5817 set_XER_OV_OV32_32( PPCG_FLAG_OP_DIVWE,
5818 mkexpr(res), dividend, divisor );
5819 update_SO( );
5821 break;
5825 case 0x1A9: // divde (Divide Doubleword Extended)
5827 * If the quotient cannot be represented in 64 bits, or if an
5828 * attempt is made to perform the division
5829 * <anything> / 0
5830 * then the contents of register RD are undefined as are (if
5831 * Rc=1) the contents of the LT, GT, and EQ bits of CR
5832 * Field 0. In these cases, if OE=1 then OV is set to 1.
5834 DIP("divde%s%s r%u,r%u,r%u\n",
5835 flag_OE ? "o" : "", flag_rC ? ".":"",
5836 rD_addr, rA_addr, rB_addr);
5837 assign( rD, binop(Iop_DivS64E, mkexpr(rA), mkexpr(rB)) );
5838 if (flag_OE) {
5839 set_XER_OV_64( PPCG_FLAG_OP_DIVDE, mkexpr( rD ),
5840 mkexpr( rA ), mkexpr( rB ) );
5841 copy_OV_to_OV32();
5842 update_SO();
5844 break;
5846 case 0x189: // divdeuo (Divide Doubleword Extended Unsigned)
5847 // Same CR and OV rules as given for divweu above
5848 DIP("divdeu%s%s r%u,r%u,r%u\n",
5849 flag_OE ? "o" : "", flag_rC ? ".":"",
5850 rD_addr, rA_addr, rB_addr);
5851 assign( rD, binop(Iop_DivU64E, mkexpr(rA), mkexpr(rB)) );
5852 if (flag_OE) {
5853 set_XER_OV_64( PPCG_FLAG_OP_DIVDEU, mkexpr( rD ),
5854 mkexpr( rA ), mkexpr( rB ) );
5855 copy_OV_to_OV32();
5856 update_SO();
5858 break;
5860 default:
5861 vex_printf("dis_int_arith(ppc)(opc2)\n");
5862 return False;
5864 break;
5866 default:
5867 vex_printf("dis_int_arith(ppc)(opc1)\n");
5868 return False;
5871 putIReg( rD_addr, mkexpr(rD) );
5873 if (do_rc && flag_rC) {
5874 set_CR0( mkexpr(rD) );
5876 return True;
5879 static Bool dis_modulo_int ( UInt theInstr )
5881 /* X-Form */
5882 UChar opc1 = ifieldOPC( theInstr );
5883 UInt opc2 = ifieldOPClo10( theInstr );
5884 UChar rA_addr = ifieldRegA( theInstr );
5885 UChar rB_addr = ifieldRegB( theInstr );
5886 UChar rD_addr = ifieldRegDS( theInstr );
5887 IRType ty = mode64 ? Ity_I64 : Ity_I32;
5888 IRTemp rD = newTemp( ty );
5890 switch (opc1) {
5891 /* X-Form */
5892 case 0x1F:
5893 switch (opc2) {
5894 case 0x109: // modud Modulo Unsigned Double Word
5896 IRTemp rA = newTemp( Ity_I64 );
5897 IRTemp rB = newTemp( Ity_I64 );
5898 IRTemp quotient = newTemp( Ity_I64 );
5899 IRTemp quotientTimesDivisor = newTemp( Ity_I64 );
5900 IRTemp remainder = newTemp( Ity_I64 );
5901 IRTemp rB_0 = newTemp( Ity_I64 ); /* all 1's if rB = 0 */
5903 DIP("modud r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
5905 assign( rA, getIReg( rA_addr ) );
5906 assign( rB, getIReg( rB_addr ) );
5908 assign( quotient,
5909 binop( Iop_DivU64, mkexpr( rA ), mkexpr( rB ) ) );
5911 assign( quotientTimesDivisor,
5912 binop( Iop_Mul64,
5913 mkexpr( quotient ),
5914 mkexpr( rB ) ) );
5916 assign( remainder,
5917 binop( Iop_Sub64,
5918 mkexpr( rA ),
5919 mkexpr( quotientTimesDivisor ) ) );
5921 /* Need to match the HW for these special cases
5922 * rB = 0 result all zeros
5924 assign( rB_0, unop( Iop_1Sto64,
5925 binop( Iop_CmpEQ64,
5926 mkexpr( rB ),
5927 mkU64( 0x0 ) ) ) );
5929 assign (rD, binop( Iop_And64,
5930 unop( Iop_Not64, mkexpr( rB_0 ) ),
5931 mkexpr( remainder ) ) );
5932 break;
5935 case 0x10B: // moduw Modulo Unsigned Word
5937 IRTemp quotient = newTemp( Ity_I32 );
5938 IRTemp quotientTimesDivisor = newTemp( Ity_I32 );
5939 IRTemp remainder = newTemp( Ity_I32 );
5941 IRTemp rA = newTemp( Ity_I32 );
5942 IRTemp rB = newTemp( Ity_I32 );
5943 IRTemp rB_0 = newTemp( Ity_I32 ); /* all 1's if rB = 0 */
5945 DIP("moduw r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
5947 if ( ty == Ity_I64 ) {
5948 /* rA and rB are 32 bit values in bits 32:63 of the
5949 * 64-bit register.
5951 assign( rA, unop( Iop_64to32, getIReg( rA_addr ) ) );
5952 assign( rB, unop( Iop_64to32, getIReg( rB_addr ) ) );
5954 } else {
5955 assign( rA, getIReg( rA_addr ) );
5956 assign( rB, getIReg( rB_addr ) );
5959 assign( quotient,
5960 binop( Iop_DivU32, mkexpr( rA ), mkexpr( rB ) ) );
5962 assign( quotientTimesDivisor,
5963 unop( Iop_64to32,
5964 binop( Iop_MullU32,
5965 mkexpr( quotient ),
5966 mkexpr( rB ) ) ) );
5968 assign( remainder,
5969 binop( Iop_Sub32,
5970 mkexpr( rA ),
5971 mkexpr( quotientTimesDivisor ) ) );
5973 /* Need to match the HW for these special cases
5974 * rB = 0 result all zeros
5976 assign( rB_0, unop( Iop_1Sto32,
5977 binop( Iop_CmpEQ32,
5978 mkexpr( rB ),
5979 mkU32( 0x0 ) ) ) );
5981 assign (rD, binop( Iop_32HLto64,
5982 mkU32( 0 ),
5983 binop( Iop_And32,
5984 unop( Iop_Not32, mkexpr( rB_0 ) ),
5985 mkexpr( remainder ) ) ) );
5986 break;
5989 case 0x21A: // cnttzw, cnttzw. Count Trailing Zero Word
5991 /* Note cnttzw RA, RS - RA is dest, RS is source. But the
5992 * order of the operands in theInst is opc1 RS RA opc2 which has
5993 * the operand fields backwards to what the standard order.
5995 UChar rA_address = ifieldRegA(theInstr);
5996 UChar rS_address = ifieldRegDS(theInstr);
5997 IRTemp rA = newTemp(Ity_I64);
5998 IRTemp rS = newTemp(Ity_I64);
5999 UChar flag_rC = ifieldBIT0(theInstr);
6000 IRTemp result = newTemp(Ity_I32);
6002 DIP("cnttzw%s r%u,r%u\n", flag_rC ? "." : "",
6003 rA_address, rS_address);
6005 assign( rS, getIReg( rS_address ) );
6006 assign( result, unop( Iop_CtzNat32,
6007 unop( Iop_64to32, mkexpr( rS ) ) ) );
6008 assign( rA, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( result ) ) );
6010 if ( flag_rC )
6011 set_CR0( mkexpr( rA ) );
6013 putIReg( rA_address, mkexpr( rA ) );
6015 return True; /* Return here since this inst is not consistent
6016 * with the other instructions
6019 break;
6021 case 0x23A: // cnttzd, cnttzd. Count Trailing Zero Double word
6023 /* Note cnttzd RA, RS - RA is dest, RS is source. But the
6024 * order of the operands in theInst is opc1 RS RA opc2 which has
6025 * the operand order listed backwards to what is standard.
6027 UChar rA_address = ifieldRegA(theInstr);
6028 UChar rS_address = ifieldRegDS(theInstr);
6029 IRTemp rA = newTemp(Ity_I64);
6030 IRTemp rS = newTemp(Ity_I64);
6031 UChar flag_rC = ifieldBIT0(theInstr);
6033 DIP("cnttzd%s r%u,r%u\n", flag_rC ? "." : "",
6034 rA_address, rS_address);
6036 assign( rS, getIReg( rS_address ) );
6037 assign( rA, unop( Iop_CtzNat64, mkexpr( rS ) ) );
6039 if ( flag_rC == 1 )
6040 set_CR0( mkexpr( rA ) );
6042 putIReg( rA_address, mkexpr( rA ) );
6044 return True; /* Return here since this inst is not consistent
6045 * with the other instructions
6048 break;
6050 case 0x309: // modsd Modulo Signed Double Word
6052 IRTemp rA = newTemp( Ity_I64 );
6053 IRTemp rB = newTemp( Ity_I64 );
6054 IRTemp rA2_63 = newTemp( Ity_I64 ); /* all 1's if rA != -2^63 */
6055 IRTemp rB_0 = newTemp( Ity_I1 ); /* 1 if rB = 0 */
6056 IRTemp rB_1 = newTemp( Ity_I1 ); /* 1 if rB = -1 */
6057 IRTemp rA_1 = newTemp( Ity_I1 ); /* 1 if rA = -1 */
6058 IRTemp resultis0 = newTemp( Ity_I64 );
6059 IRTemp resultisF = newTemp( Ity_I64 );
6060 IRTemp quotient = newTemp( Ity_I64 );
6061 IRTemp quotientTimesDivisor = newTemp( Ity_I64 );
6062 IRTemp remainder = newTemp( Ity_I64 );
6063 IRTemp tmp = newTemp( Ity_I64 );
6065 DIP("modsd r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
6067 assign( rA, getIReg( rA_addr ) );
6068 assign( rB, getIReg( rB_addr ) );
6070 assign( rA2_63, unop ( Iop_1Sto64,
6071 binop( Iop_CmpNE64,
6072 mkexpr( rA ),
6073 mkU64( 0x8000000000000000 ) ) ) );
6074 assign( rB_0, binop( Iop_CmpEQ64,
6075 mkexpr( rB ),
6076 mkU64( 0x0 ) ) );
6078 assign( rB_1, binop( Iop_CmpEQ64,
6079 mkexpr( rB ),
6080 mkU64( 0xFFFFFFFFFFFFFFFF ) ) );
6082 assign( rA_1, binop( Iop_CmpEQ64,
6083 mkexpr( rA ),
6084 mkU64( 0xFFFFFFFFFFFFFFFF ) ) );
6086 /* Need to match the HW for these special cases
6087 * rA = -2^31 and rB = -1 result all zeros
6088 * rA = -1 and rB = -1 result all zeros
6089 * rA = -1 and (rB != -1 AND rB != 0) result all 1's
6091 assign( resultis0,
6092 binop( Iop_Or64,
6093 mkexpr( rA2_63 ),
6094 unop ( Iop_1Sto64, mkexpr( rB_1 ) ) ) );
6095 assign( resultisF,
6096 binop( Iop_And64,
6097 unop( Iop_1Sto64, mkexpr( rA_1 ) ),
6098 binop( Iop_And64,
6099 unop( Iop_Not64,
6100 unop( Iop_1Sto64, mkexpr( rB_0 ) ) ),
6101 unop( Iop_Not64,
6102 unop( Iop_1Sto64, mkexpr( rB_1 ) ) )
6103 ) ) );
6105 /* The following remainder computation works as long as
6106 * rA != -2^63 and rB != -1.
6108 assign( quotient,
6109 binop( Iop_DivS64, mkexpr( rA ), mkexpr( rB ) ) );
6111 assign( quotientTimesDivisor,
6112 binop( Iop_Mul64,
6113 mkexpr( quotient ),
6114 mkexpr( rB ) ) );
6116 assign( remainder,
6117 binop( Iop_Sub64,
6118 mkexpr( rA ),
6119 mkexpr( quotientTimesDivisor ) ) );
6121 assign( tmp, binop( Iop_And64,
6122 mkexpr( remainder ),
6123 unop( Iop_Not64,
6124 mkexpr( resultis0 ) ) ) );
6126 assign( rD, binop( Iop_Or64,
6127 binop( Iop_And64,
6128 unop (Iop_Not64,
6129 mkexpr( resultisF ) ),
6130 mkexpr( tmp ) ),
6131 mkexpr( resultisF ) ) );
6132 break;
6134 case 0x30B: // modsw Modulo Signed Word
6136 IRTemp rA = newTemp( Ity_I32 );
6137 IRTemp rB = newTemp( Ity_I32 );
6138 IRTemp rA2_32 = newTemp( Ity_I32 ); /* all 1's if rA = -2^32 */
6139 IRTemp rB_0 = newTemp( Ity_I1 ); /* 1 if rB = 0 */
6140 IRTemp rB_1 = newTemp( Ity_I1 ); /* 1 if rB = -1 */
6141 IRTemp rA_1 = newTemp( Ity_I1 ); /* 1 if rA = -1 */
6142 IRTemp resultis0 = newTemp( Ity_I32 );
6143 IRTemp resultisF = newTemp( Ity_I64 );
6144 IRTemp quotient = newTemp( Ity_I32 );
6145 IRTemp quotientTimesDivisor = newTemp( Ity_I32 );
6146 IRTemp remainder = newTemp( Ity_I32 );
6147 IRTemp tmp = newTemp( Ity_I64 );
6149 DIP("modsw r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
6151 if ( ty == Ity_I64 ) {
6152 /* rA and rB are 32 bit values in bits 32:63 of the
6153 * 64-bit register.
6155 assign( rA, unop(Iop_64to32, getIReg(rA_addr) ) );
6156 assign( rB, unop(Iop_64to32, getIReg(rB_addr) ) );
6158 } else {
6159 assign( rA, getIReg(rA_addr) );
6160 assign( rB, getIReg(rB_addr) );
6163 assign( rA2_32, unop( Iop_1Sto32,
6164 binop( Iop_CmpEQ32,
6165 mkexpr( rA ),
6166 mkU32( 0x80000000 ) ) ) );
6167 /* If the divisor is zero, then the result is undefined.
6168 * However, we will make the result be zero to match what
6169 * the hardware does.
6171 assign( rB_0, binop( Iop_CmpEQ32,
6172 mkexpr( rB ),
6173 mkU32( 0x0 ) ) );
6175 assign( rB_1, binop( Iop_CmpEQ32,
6176 mkexpr( rB ),
6177 mkU32( 0xFFFFFFFF ) ) );
6179 assign( rA_1, binop( Iop_CmpEQ32,
6180 mkexpr( rA ),
6181 mkU32( 0xFFFFFFFF ) ) );
6183 /* Need to match the HW for these special cases
6184 * rA = -2^31 and rB = -1 result all zeros
6185 * rA = -1 and rB = -1 result all zeros
6186 * rA = -1 and (rB != -1 AND rB != 0) result all 1's
6188 assign( resultis0,
6189 binop( Iop_Or32,
6190 unop( Iop_Not32,
6191 binop( Iop_And32,
6192 mkexpr( rA2_32 ),
6193 unop( Iop_1Sto32,
6194 mkexpr( rB_1 ) ) ) ),
6195 binop( Iop_And32,
6196 unop( Iop_1Sto32, mkexpr( rA_1 ) ),
6197 unop( Iop_1Sto32, mkexpr( rB_1 ) ) ) ) );
6198 assign( resultisF,
6199 binop( Iop_And64,
6200 unop( Iop_1Sto64, mkexpr( rA_1 ) ),
6201 binop( Iop_And64,
6202 unop( Iop_Not64,
6203 unop( Iop_1Sto64, mkexpr( rB_0 ) ) ),
6204 unop( Iop_Not64,
6205 unop( Iop_1Sto64, mkexpr( rB_1 ) ) )
6206 ) ) );
6208 /* The following remainder computation works as long as
6209 * rA != -2^31 and rB != -1.
6211 assign( quotient,
6212 binop( Iop_DivS32, mkexpr( rA ), mkexpr( rB ) ) );
6214 assign( quotientTimesDivisor,
6215 unop( Iop_64to32,
6216 binop( Iop_MullS32,
6217 mkexpr( quotient ),
6218 mkexpr( rB ) ) ) );
6220 assign( remainder,
6221 binop( Iop_Sub32,
6222 mkexpr( rA ),
6223 mkexpr( quotientTimesDivisor ) ) );
6225 assign( tmp, binop( Iop_32HLto64,
6226 mkU32( 0 ),
6227 binop( Iop_And32,
6228 mkexpr( remainder ),
6229 unop( Iop_Not32,
6230 mkexpr( resultis0 ) ) ) ) );
6232 assign( rD, binop( Iop_Or64,
6233 binop( Iop_And64,
6234 unop ( Iop_Not64,
6235 mkexpr( resultisF ) ),
6236 mkexpr( tmp ) ),
6237 mkexpr( resultisF ) ) );
6238 break;
6241 default:
6242 vex_printf("dis_modulo_int(ppc)(opc2)\n");
6243 return False;
6245 break;
6247 default:
6248 vex_printf("dis_modulo_int(ppc)(opc1)\n");
6249 return False;
6252 putIReg( rD_addr, mkexpr( rD ) );
6254 return True;
6259 Byte Compare Instructions
6261 static Bool dis_byte_cmp ( UInt theInstr )
6263 /* X-Form */
6264 UChar opc1 = ifieldOPC(theInstr);
6265 UInt opc2 = ifieldOPClo10(theInstr);
6266 UChar rA_addr = ifieldRegA(theInstr);
6267 UChar rB_addr = ifieldRegB(theInstr);
6268 IRTemp rA = newTemp(Ity_I64);
6269 IRTemp rB = newTemp(Ity_I64);
6270 UChar L = toUChar( IFIELD( theInstr, 21, 1 ) );
6271 UChar BF = toUChar( IFIELD( theInstr, 23, 3 ) );
6273 assign( rA, getIReg(rA_addr) );
6274 assign( rB, getIReg(rB_addr) );
6276 if (opc1 != 0x1F) {
6277 vex_printf("dis_byte_cmp(ppc)(opc1)\n");
6278 return False;
6281 switch (opc2) {
6282 case 0xc0: // cmprb (Compare Ranged Byte)
6284 IRExpr *value;
6285 IRExpr *hi_1, *lo_1, *hi_2, *lo_2;
6286 IRExpr *inrange_1, *inrange_2;
6288 DIP("cmprb %u,%u,r%u,r%u\n", BF, L, rA_addr, rB_addr);
6290 hi_1 = binop( Iop_Shr64,
6291 binop( Iop_And64,
6292 mkexpr( rB ),
6293 mkU64( 0xFF000000 ) ),
6294 mkU8( 24 ) );
6295 lo_1 = binop( Iop_Shr64,
6296 binop( Iop_And64,
6297 mkexpr( rB ),
6298 mkU64( 0xFF0000 ) ) ,
6299 mkU8( 16 ) );
6300 hi_2 = binop( Iop_Shr64,
6301 binop( Iop_And64,
6302 mkexpr( rB ),
6303 mkU64( 0xFF00 ) ),
6304 mkU8( 8 ) );
6305 lo_2 = binop( Iop_And64,
6306 mkexpr( rB ),
6307 mkU64( 0xFF ) );
6308 value = binop( Iop_And64,
6309 mkexpr( rA ),
6310 mkU64( 0xFF ) );
6312 inrange_1 = mkAND1( binop( Iop_CmpLE64U, value, hi_1 ),
6313 mkNOT1( binop( Iop_CmpLT64U, value, lo_1 ) ) );
6314 inrange_2 = mkAND1( binop( Iop_CmpLE64U, value, hi_2 ),
6315 mkNOT1( binop( Iop_CmpLT64U, value, lo_2 ) ) );
6317 putGST_field( PPC_GST_CR,
6318 binop( Iop_Shl32,
6319 binop( Iop_Or32,
6320 unop( Iop_1Uto32, inrange_2 ),
6321 binop( Iop_And32,
6322 mkU32 ( L ),
6323 unop( Iop_1Uto32, inrange_1 ) ) ),
6324 mkU8( 2 ) ),
6325 BF );
6327 break;
6329 case 0xE0: // cmpeqb (Compare Equal Byte)
6331 Int i;
6332 IRTemp tmp[9];
6333 IRExpr *value;
6335 DIP("cmpeqb %u,r%u,r%u\n", BF, rA_addr, rB_addr);
6337 value = binop( Iop_And64,
6338 mkexpr( rA ),
6339 mkU64( 0xFF ) );
6341 tmp[0] = newTemp(Ity_I32);
6342 assign( tmp[0], mkU32( 0 ) );
6344 for(i = 0; i < 8; i++) {
6345 tmp[i+1] = newTemp(Ity_I32);
6346 assign( tmp[i+1], binop( Iop_Or32,
6347 unop( Iop_1Uto32,
6348 binop( Iop_CmpEQ64,
6349 value,
6350 binop( Iop_And64,
6351 binop( Iop_Shr64,
6352 mkexpr( rB ),
6353 mkU8( i*8 ) ),
6354 mkU64( 0xFF ) ) ) ),
6355 mkexpr( tmp[i] ) ) );
6358 putGST_field( PPC_GST_CR,
6359 binop( Iop_Shl32,
6360 unop( Iop_1Uto32,
6361 mkNOT1( binop( Iop_CmpEQ32,
6362 mkexpr( tmp[8] ),
6363 mkU32( 0 ) ) ) ),
6364 mkU8( 2 ) ),
6365 BF );
6367 break;
6369 default:
6370 vex_printf("dis_byte_cmp(ppc)(opc2)\n");
6371 return False;
6373 return True;
6377 * Integer Miscellaneous instructions
6379 static Bool dis_int_misc ( UInt theInstr )
6381 Int wc = IFIELD(theInstr, 21, 2);
6382 UChar opc1 = ifieldOPC(theInstr);
6383 UInt opc2 = ifieldOPClo10(theInstr);
6385 if ( opc1 != 0x1F ) {
6386 vex_printf("dis_modulo_int(ppc)(opc1)\n");
6387 return False;
6390 switch (opc2) {
6391 case 0x01E: // wait, (X-from)
6392 DIP("wait %d\n", wc);
6394 /* The wait instruction causes instruction fetching and execution
6395 * to be suspended. Instruction fetching and execution are resumed
6396 * when the events specified by the WC field occur.
6398 * 0b00 Resume instruction fetching and execution when an
6399 * exception or an event-based branch exception occurs,
6400 * or a resume signal from the platform is recieved.
6402 * 0b01 Reserved.
6404 * For our purposes, we will just assume the contition is always
6405 * immediately satisfied.
6407 break;
6408 default:
6409 vex_printf("dis_int_misc(ppc)(opc2)\n");
6410 return False;
6413 return True;
6417 Integer Compare Instructions
6419 static Bool dis_int_cmp ( UInt theInstr )
6421 /* D-Form, X-Form */
6422 UChar opc1 = ifieldOPC(theInstr);
6423 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
6424 UChar b22 = toUChar( IFIELD( theInstr, 22, 1 ) );
6425 UChar flag_L = toUChar( IFIELD( theInstr, 21, 1 ) );
6426 UChar rA_addr = ifieldRegA(theInstr);
6427 UInt uimm16 = ifieldUIMM16(theInstr);
6428 UChar rB_addr = ifieldRegB(theInstr);
6429 UInt opc2 = ifieldOPClo10(theInstr);
6430 UChar b0 = ifieldBIT0(theInstr);
6432 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6433 IRExpr *a = getIReg(rA_addr);
6434 IRExpr *b;
6436 if (!mode64 && flag_L==1) { // L==1 invalid for 32 bit.
6437 vex_printf("dis_int_cmp(ppc)(flag_L)\n");
6438 return False;
6441 if (( b22 != 0 ) && ( opc2 != 0x080 ) ) { // setb case exception
6442 vex_printf("dis_int_cmp(ppc)(b22)\n");
6443 return False;
6446 switch (opc1) {
6447 case 0x0B: // cmpi (Compare Immediate, PPC32 p368)
6448 DIP("cmpi cr%u,%u,r%u,%d\n", crfD, flag_L, rA_addr,
6449 (Int)extend_s_16to32(uimm16));
6450 b = mkSzExtendS16( ty, uimm16 );
6451 if (flag_L == 1) {
6452 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64S, a, b)));
6453 } else {
6454 a = mkNarrowTo32( ty, a );
6455 b = mkNarrowTo32( ty, b );
6456 putCR321(crfD, unop(Iop_32to8, binop(Iop_CmpORD32S, a, b)));
6458 putCR0( crfD, getXER_SO() );
6459 break;
6461 case 0x0A: // cmpli (Compare Logical Immediate, PPC32 p370)
6462 DIP("cmpli cr%u,%u,r%u,0x%x\n", crfD, flag_L, rA_addr, uimm16);
6463 b = mkSzImm( ty, uimm16 );
6464 if (flag_L == 1) {
6465 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64U, a, b)));
6466 } else {
6467 a = mkNarrowTo32( ty, a );
6468 b = mkNarrowTo32( ty, b );
6469 putCR321(crfD, unop(Iop_32to8, binop(Iop_CmpORD32U, a, b)));
6471 putCR0( crfD, getXER_SO() );
6472 break;
6474 /* X Form */
6475 case 0x1F:
6476 if (b0 != 0) {
6477 vex_printf("dis_int_cmp(ppc)(0x1F,b0)\n");
6478 return False;
6480 b = getIReg(rB_addr);
6482 switch (opc2) {
6483 case 0x000: // cmp (Compare, PPC32 p367)
6484 DIP("cmp cr%u,%u,r%u,r%u\n", crfD, flag_L, rA_addr, rB_addr);
6485 /* Comparing a reg with itself produces a result which
6486 doesn't depend on the contents of the reg. Therefore
6487 remove the false dependency, which has been known to cause
6488 memcheck to produce false errors. */
6489 if (rA_addr == rB_addr)
6490 a = b = typeOfIRExpr(irsb->tyenv,a) == Ity_I64
6491 ? mkU64(0) : mkU32(0);
6492 if (flag_L == 1) {
6493 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64S, a, b)));
6494 } else {
6495 a = mkNarrowTo32( ty, a );
6496 b = mkNarrowTo32( ty, b );
6497 putCR321(crfD, unop(Iop_32to8,binop(Iop_CmpORD32S, a, b)));
6499 putCR0( crfD, getXER_SO() );
6500 break;
6502 case 0x020: // cmpl (Compare Logical, PPC32 p369)
6503 DIP("cmpl cr%u,%u,r%u,r%u\n", crfD, flag_L, rA_addr, rB_addr);
6504 /* Comparing a reg with itself produces a result which
6505 doesn't depend on the contents of the reg. Therefore
6506 remove the false dependency, which has been known to cause
6507 memcheck to produce false errors. */
6508 if (rA_addr == rB_addr)
6509 a = b = typeOfIRExpr(irsb->tyenv,a) == Ity_I64
6510 ? mkU64(0) : mkU32(0);
6511 if (flag_L == 1) {
6512 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64U, a, b)));
6513 } else {
6514 a = mkNarrowTo32( ty, a );
6515 b = mkNarrowTo32( ty, b );
6516 putCR321(crfD, unop(Iop_32to8, binop(Iop_CmpORD32U, a, b)));
6518 putCR0( crfD, getXER_SO() );
6519 break;
6521 case 0x080: // setb (Set Boolean)
6523 UChar rT_addr = ifieldRegDS(theInstr);
6524 Int bfa = IFIELD(theInstr, 18, 3);
6525 IRTemp cr = newTemp(Ity_I32);
6526 IRTemp cr0 = newTemp(Ity_I32);
6527 IRTemp cr1 = newTemp(Ity_I32);
6528 IRTemp result = newTemp(Ity_I64);
6530 DIP("setb r%u,%d\n", rT_addr, bfa);
6532 /* Fetch the entire condition code value */
6533 assign( cr, getGST( PPC_GST_CR ) );
6535 /* Get bit zero (IBM numbering) of the CR field specified
6536 * by bfa.
6538 assign( cr0, binop( Iop_And32,
6539 binop( Iop_Shr32,
6540 mkexpr( cr ),
6541 mkU8( (7-bfa)*4 ) ),
6542 mkU32( 0x8 ) ) );
6543 assign( cr1, binop( Iop_And32,
6544 binop( Iop_Shr32,
6545 mkexpr( cr ),
6546 mkU8( (7-bfa)*4 ) ),
6547 mkU32( 0x4 ) ) );
6548 assign( result, binop( Iop_Or64,
6549 unop( Iop_1Sto64,
6550 binop( Iop_CmpEQ32,
6551 mkexpr( cr0 ),
6552 mkU32( 0x8 ) ) ),
6553 binop( Iop_32HLto64,
6554 mkU32( 0 ),
6555 unop( Iop_1Uto32,
6556 binop( Iop_CmpEQ32,
6557 mkexpr( cr1 ),
6558 mkU32( 0x4 ) ) ) ) ) );
6559 if ( ty == Ity_I64 )
6560 putIReg( rT_addr, mkexpr( result ) );
6561 else
6562 putIReg( rT_addr, unop( Iop_64to32, mkexpr(result ) ) );
6564 break;
6565 default:
6566 vex_printf("dis_int_cmp(ppc)(opc2)\n");
6567 return False;
6569 break;
6571 default:
6572 vex_printf("dis_int_cmp(ppc)(opc1)\n");
6573 return False;
6576 return True;
6581 Integer Logical Instructions
6583 static Bool dis_int_logic ( UInt theInstr )
6585 /* D-Form, X-Form */
6586 UChar opc1 = ifieldOPC(theInstr);
6587 UChar rS_addr = ifieldRegDS(theInstr);
6588 UChar rA_addr = ifieldRegA(theInstr);
6589 UInt uimm16 = ifieldUIMM16(theInstr);
6590 UChar rB_addr = ifieldRegB(theInstr);
6591 UInt opc2 = ifieldOPClo10(theInstr);
6592 UChar flag_rC = ifieldBIT0(theInstr);
6594 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6595 IRTemp rS = newTemp(ty);
6596 IRTemp rA = newTemp(ty);
6597 IRTemp rB = newTemp(ty);
6598 Bool do_rc = False;
6600 assign( rS, getIReg(rS_addr) );
6601 assign( rB, getIReg(rB_addr) );
6603 switch (opc1) {
6604 case 0x1C: // andi. (AND Immediate, PPC32 p358)
6605 DIP("andi. r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
6606 assign( rA, binop( mkSzOp(ty, Iop_And8), mkexpr(rS),
6607 mkSzImm(ty, uimm16)) );
6608 do_rc = True; // Always record to CR
6609 flag_rC = 1;
6610 break;
6612 case 0x1D: // andis. (AND Immediate Shifted, PPC32 p359)
6613 DIP("andis r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
6614 assign( rA, binop( mkSzOp(ty, Iop_And8), mkexpr(rS),
6615 mkSzImm(ty, uimm16 << 16)) );
6616 do_rc = True; // Always record to CR
6617 flag_rC = 1;
6618 break;
6620 case 0x18: // ori (OR Immediate, PPC32 p497)
6621 DIP("ori r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
6622 assign( rA, binop( mkSzOp(ty, Iop_Or8), mkexpr(rS),
6623 mkSzImm(ty, uimm16)) );
6624 break;
6626 case 0x19: // oris (OR Immediate Shifted, PPC32 p498)
6627 DIP("oris r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
6628 assign( rA, binop( mkSzOp(ty, Iop_Or8), mkexpr(rS),
6629 mkSzImm(ty, uimm16 << 16)) );
6630 break;
6632 case 0x1A: // xori (XOR Immediate, PPC32 p550)
6633 DIP("xori r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
6634 assign( rA, binop( mkSzOp(ty, Iop_Xor8), mkexpr(rS),
6635 mkSzImm(ty, uimm16)) );
6636 break;
6638 case 0x1B: // xoris (XOR Immediate Shifted, PPC32 p551)
6639 DIP("xoris r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
6640 assign( rA, binop( mkSzOp(ty, Iop_Xor8), mkexpr(rS),
6641 mkSzImm(ty, uimm16 << 16)) );
6642 break;
6644 /* X Form */
6645 case 0x1F:
6647 opc2 = IFIELD( theInstr, 2, 9 );
6649 switch ( opc2 ) {
6650 case 0x1BD: // extswsli (Extend Sign Word shift left)
6652 /* sh[5] is in bit 1, sh[0:4] is in bits [14:10] of theInstr */
6653 UChar sh = IFIELD( theInstr, 11, 5 ) | (IFIELD(theInstr, 1, 1) << 5);
6654 IRTemp temp = newTemp( ty );
6656 DIP("extswsli%s r%u,r%u,%u\n", flag_rC ? ".":"",
6657 rA_addr, rS_addr, sh);
6659 assign( temp, unop( Iop_32Sto64,
6660 unop( Iop_64to32, mkexpr( rS ) ) ) );
6661 assign( rA, binop( Iop_Shl64, mkexpr( temp ), mkU8( sh ) ) );
6662 putIReg( rA_addr, mkexpr( rA ) );
6664 if ( flag_rC ) {
6665 set_CR0( mkexpr( rA ) );
6667 return True;
6669 default:
6670 break; // drop to next opc2 check
6673 do_rc = True; // All below record to CR, except for where we return at case end.
6675 opc2 = ifieldOPClo10( theInstr );
6677 switch (opc2) {
6678 case 0x01C: // and (AND, PPC32 p356)
6679 DIP("and%s r%u,r%u,r%u\n",
6680 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6681 assign(rA, binop( mkSzOp(ty, Iop_And8),
6682 mkexpr(rS), mkexpr(rB)));
6683 break;
6685 case 0x03C: // andc (AND with Complement, PPC32 p357)
6686 DIP("andc%s r%u,r%u,r%u\n",
6687 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6688 assign(rA, binop( mkSzOp(ty, Iop_And8), mkexpr(rS),
6689 unop( mkSzOp(ty, Iop_Not8),
6690 mkexpr(rB))));
6691 break;
6693 case 0x01A: { // cntlzw (Count Leading Zeros Word, PPC32 p371)
6694 if (rB_addr!=0) {
6695 vex_printf("dis_int_logic(ppc)(cntlzw,rB_addr)\n");
6696 return False;
6698 DIP("cntlzw%s r%u,r%u\n", flag_rC ? ".":"", rA_addr, rS_addr);
6700 // mode64: count in low word only
6701 IRExpr* lo32 = mode64 ? unop(Iop_64to32, mkexpr(rS)) : mkexpr(rS);
6702 IRExpr* res32 = unop(Iop_ClzNat32, lo32);
6703 assign(rA, mode64 ? unop(Iop_32Uto64, res32) : res32);
6704 break;
6707 case 0x11C: // eqv (Equivalent, PPC32 p396)
6708 DIP("eqv%s r%u,r%u,r%u\n",
6709 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6710 assign( rA, unop( mkSzOp(ty, Iop_Not8),
6711 binop( mkSzOp(ty, Iop_Xor8),
6712 mkexpr(rS), mkexpr(rB))) );
6713 break;
6715 case 0x3BA: // extsb (Extend Sign Byte, PPC32 p397
6716 if (rB_addr!=0) {
6717 vex_printf("dis_int_logic(ppc)(extsb,rB_addr)\n");
6718 return False;
6720 DIP("extsb%s r%u,r%u\n",
6721 flag_rC ? ".":"", rA_addr, rS_addr);
6722 if (mode64)
6723 assign( rA, unop(Iop_8Sto64, unop(Iop_64to8, mkexpr(rS))) );
6724 else
6725 assign( rA, unop(Iop_8Sto32, unop(Iop_32to8, mkexpr(rS))) );
6726 break;
6728 case 0x39A: // extsh (Extend Sign Half Word, PPC32 p398)
6729 if (rB_addr!=0) {
6730 vex_printf("dis_int_logic(ppc)(extsh,rB_addr)\n");
6731 return False;
6733 DIP("extsh%s r%u,r%u\n",
6734 flag_rC ? ".":"", rA_addr, rS_addr);
6735 if (mode64)
6736 assign( rA, unop(Iop_16Sto64,
6737 unop(Iop_64to16, mkexpr(rS))) );
6738 else
6739 assign( rA, unop(Iop_16Sto32,
6740 unop(Iop_32to16, mkexpr(rS))) );
6741 break;
6743 case 0x1DC: // nand (NAND, PPC32 p492)
6744 DIP("nand%s r%u,r%u,r%u\n",
6745 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6746 assign( rA, unop( mkSzOp(ty, Iop_Not8),
6747 binop( mkSzOp(ty, Iop_And8),
6748 mkexpr(rS), mkexpr(rB))) );
6749 break;
6751 case 0x07C: // nor (NOR, PPC32 p494)
6752 DIP("nor%s r%u,r%u,r%u\n",
6753 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6754 assign( rA, unop( mkSzOp(ty, Iop_Not8),
6755 binop( mkSzOp(ty, Iop_Or8),
6756 mkexpr(rS), mkexpr(rB))) );
6757 break;
6759 case 0x1BC: // or (OR, PPC32 p495)
6760 if ((!flag_rC) && rS_addr == rB_addr) {
6761 DIP("mr r%u,r%u\n", rA_addr, rS_addr);
6762 assign( rA, mkexpr(rS) );
6763 } else {
6764 DIP("or%s r%u,r%u,r%u\n",
6765 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6766 assign( rA, binop( mkSzOp(ty, Iop_Or8),
6767 mkexpr(rS), mkexpr(rB)) );
6769 break;
6771 case 0x19C: // orc (OR with Complement, PPC32 p496)
6772 DIP("orc%s r%u,r%u,r%u\n",
6773 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6774 assign( rA, binop( mkSzOp(ty, Iop_Or8), mkexpr(rS),
6775 unop(mkSzOp(ty, Iop_Not8), mkexpr(rB))));
6776 break;
6778 case 0x13C: // xor (XOR, PPC32 p549)
6779 DIP("xor%s r%u,r%u,r%u\n",
6780 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6781 assign( rA, binop( mkSzOp(ty, Iop_Xor8),
6782 mkexpr(rS), mkexpr(rB)) );
6783 break;
6786 /* 64bit Integer Logical Instructions */
6787 case 0x3DA: // extsw (Extend Sign Word, PPC64 p430)
6788 if (rB_addr!=0) {
6789 vex_printf("dis_int_logic(ppc)(extsw,rB_addr)\n");
6790 return False;
6792 DIP("extsw%s r%u,r%u\n", flag_rC ? ".":"", rA_addr, rS_addr);
6793 assign(rA, unop(Iop_32Sto64, unop(Iop_64to32, mkexpr(rS))));
6794 break;
6796 case 0x03A: // cntlzd (Count Leading Zeros DWord, PPC64 p401)
6797 if (rB_addr!=0) {
6798 vex_printf("dis_int_logic(ppc)(cntlzd,rB_addr)\n");
6799 return False;
6801 DIP("cntlzd%s r%u,r%u\n", flag_rC ? ".":"", rA_addr, rS_addr);
6802 assign(rA, unop(Iop_ClzNat64, mkexpr(rS)));
6803 break;
6805 case 0x1FC: // cmpb (Power6: compare bytes)
6806 DIP("cmpb r%u,r%u,r%u\n", rA_addr, rS_addr, rB_addr);
6808 if (mode64)
6809 assign( rA, unop( Iop_V128to64,
6810 binop( Iop_CmpEQ8x16,
6811 binop( Iop_64HLtoV128, mkU64(0), mkexpr(rS) ),
6812 binop( Iop_64HLtoV128, mkU64(0), mkexpr(rB) )
6813 )) );
6814 else
6815 assign( rA, unop( Iop_V128to32,
6816 binop( Iop_CmpEQ8x16,
6817 unop( Iop_32UtoV128, mkexpr(rS) ),
6818 unop( Iop_32UtoV128, mkexpr(rB) )
6819 )) );
6820 break;
6822 case 0x2DF: { // mftgpr (move floating-point to general purpose register)
6823 IRTemp frB = newTemp(Ity_F64);
6824 DIP("mftgpr r%u,fr%u\n", rS_addr, rB_addr);
6826 assign( frB, getFReg(rB_addr)); // always F64
6827 if (mode64)
6828 assign( rA, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
6829 else
6830 assign( rA, unop( Iop_64to32, unop( Iop_ReinterpF64asI64, mkexpr(frB))) );
6832 putIReg( rS_addr, mkexpr(rA));
6833 return True;
6836 case 0x25F: { // mffgpr (move floating-point from general purpose register)
6837 IRTemp frA = newTemp(Ity_F64);
6838 DIP("mffgpr fr%u,r%u\n", rS_addr, rB_addr);
6840 if (mode64)
6841 assign( frA, unop( Iop_ReinterpI64asF64, mkexpr(rB)) );
6842 else
6843 assign( frA, unop( Iop_ReinterpI64asF64, unop( Iop_32Uto64, mkexpr(rB))) );
6845 putFReg( rS_addr, mkexpr(frA));
6846 return True;
6848 case 0x1FA: // popcntd (population count doubleword)
6850 vassert(mode64);
6851 DIP("popcntd r%u,r%u\n", rA_addr, rS_addr);
6852 IRTemp result = gen_POPCOUNT(ty, rS, DWORD);
6853 putIReg( rA_addr, mkexpr(result) );
6854 return True;
6856 case 0x17A: // popcntw (Population Count Words)
6858 DIP("popcntw r%u,r%u\n", rA_addr, rS_addr);
6859 if (mode64) {
6860 IRTemp resultHi, resultLo;
6861 IRTemp argLo = newTemp(Ity_I32);
6862 IRTemp argHi = newTemp(Ity_I32);
6863 assign(argLo, unop(Iop_64to32, mkexpr(rS)));
6864 assign(argHi, unop(Iop_64HIto32, mkexpr(rS)));
6865 resultLo = gen_POPCOUNT(Ity_I32, argLo, WORD);
6866 resultHi = gen_POPCOUNT(Ity_I32, argHi, WORD);
6867 putIReg( rA_addr, binop(Iop_32HLto64, mkexpr(resultHi), mkexpr(resultLo)));
6868 } else {
6869 IRTemp result = gen_POPCOUNT(ty, rS, WORD);
6870 putIReg( rA_addr, mkexpr(result) );
6872 return True;
6874 case 0x7A: // popcntb (Population Count Byte)
6876 DIP("popcntb r%u,r%u\n", rA_addr, rS_addr);
6878 if (mode64) {
6879 IRTemp resultHi, resultLo;
6880 IRTemp argLo = newTemp(Ity_I32);
6881 IRTemp argHi = newTemp(Ity_I32);
6882 assign(argLo, unop(Iop_64to32, mkexpr(rS)));
6883 assign(argHi, unop(Iop_64HIto32, mkexpr(rS)));
6884 resultLo = gen_POPCOUNT(Ity_I32, argLo, BYTE);
6885 resultHi = gen_POPCOUNT(Ity_I32, argHi, BYTE);
6886 putIReg( rA_addr, binop(Iop_32HLto64, mkexpr(resultHi),
6887 mkexpr(resultLo)));
6888 } else {
6889 IRTemp result = gen_POPCOUNT(ty, rS, BYTE);
6890 putIReg( rA_addr, mkexpr(result) );
6892 return True;
6894 case 0x0FC: // bpermd (Bit Permute Doubleword)
6896 /* This is a lot of rigmarole to emulate bpermd like this, as it
6897 * could be done much faster by implementing a call to the native
6898 * instruction. However, where possible I want to avoid using new
6899 * native instructions so that we can use valgrind to emulate those
6900 * instructions on older PPC64 hardware.
6902 #define BPERMD_IDX_MASK 0x00000000000000FFULL
6903 #define BPERMD_BIT_MASK 0x8000000000000000ULL
6904 int i;
6905 IRExpr * rS_expr = mkexpr(rS);
6906 IRExpr * res = binop(Iop_And64, mkU64(0), mkU64(0));
6907 DIP("bpermd r%u,r%u,r%u\n", rA_addr, rS_addr, rB_addr);
6908 for (i = 0; i < 8; i++) {
6909 IRTemp idx_tmp = newTemp( Ity_I64 );
6910 IRTemp perm_bit = newTemp( Ity_I64 );
6911 IRTemp idx = newTemp( Ity_I8 );
6912 IRTemp idx_LT64 = newTemp( Ity_I1 );
6913 IRTemp idx_LT64_ity64 = newTemp( Ity_I64 );
6915 assign( idx_tmp,
6916 binop( Iop_And64, mkU64( BPERMD_IDX_MASK ), rS_expr ) );
6917 assign( idx_LT64,
6918 binop( Iop_CmpLT64U, mkexpr( idx_tmp ), mkU64( 64 ) ) );
6919 assign( idx,
6920 binop( Iop_And8,
6921 unop( Iop_1Sto8,
6922 mkexpr(idx_LT64) ),
6923 unop( Iop_64to8, mkexpr( idx_tmp ) ) ) );
6924 /* If idx_LT64 == 0, we must force the perm bit to '0'. Below, we se idx
6925 * to determine which bit of rB to use for the perm bit, and then we shift
6926 * that bit to the MSB position. We AND that with a 64-bit-ized idx_LT64
6927 * to set the final perm bit.
6929 assign( idx_LT64_ity64,
6930 unop( Iop_32Uto64, unop( Iop_1Uto32, mkexpr(idx_LT64 ) ) ) );
6931 assign( perm_bit,
6932 binop( Iop_And64,
6933 mkexpr( idx_LT64_ity64 ),
6934 binop( Iop_Shr64,
6935 binop( Iop_And64,
6936 mkU64( BPERMD_BIT_MASK ),
6937 binop( Iop_Shl64,
6938 mkexpr( rB ),
6939 mkexpr( idx ) ) ),
6940 mkU8( 63 ) ) ) );
6941 res = binop( Iop_Or64,
6942 res,
6943 binop( Iop_Shl64,
6944 mkexpr( perm_bit ),
6945 mkU8( i ) ) );
6946 rS_expr = binop( Iop_Shr64, rS_expr, mkU8( 8 ) );
6948 putIReg(rA_addr, res);
6949 return True;
6952 default:
6953 vex_printf("dis_int_logic(ppc)(opc2)\n");
6954 return False;
6956 break;
6958 default:
6959 vex_printf("dis_int_logic(ppc)(opc1)\n");
6960 return False;
6963 putIReg( rA_addr, mkexpr(rA) );
6965 if (do_rc && flag_rC) {
6966 set_CR0( mkexpr(rA) );
6968 return True;
6972 Integer Parity Instructions
6974 static Bool dis_int_parity ( UInt theInstr )
6976 /* X-Form */
6977 UChar opc1 = ifieldOPC(theInstr);
6978 UChar rS_addr = ifieldRegDS(theInstr);
6979 UChar rA_addr = ifieldRegA(theInstr);
6980 UChar rB_addr = ifieldRegB(theInstr);
6981 UInt opc2 = ifieldOPClo10(theInstr);
6982 UChar b0 = ifieldBIT0(theInstr);
6983 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6985 IRTemp rS = newTemp(ty);
6986 IRTemp rA = newTemp(ty);
6987 IRTemp iTot1 = newTemp(Ity_I32);
6988 IRTemp iTot2 = newTemp(Ity_I32);
6989 IRTemp iTot3 = newTemp(Ity_I32);
6990 IRTemp iTot4 = newTemp(Ity_I32);
6991 IRTemp iTot5 = newTemp(Ity_I32);
6992 IRTemp iTot6 = newTemp(Ity_I32);
6993 IRTemp iTot7 = newTemp(Ity_I32);
6994 IRTemp iTot8 = newTemp(Ity_I32);
6995 IRTemp rS1 = newTemp(ty);
6996 IRTemp rS2 = newTemp(ty);
6997 IRTemp rS3 = newTemp(ty);
6998 IRTemp rS4 = newTemp(ty);
6999 IRTemp rS5 = newTemp(ty);
7000 IRTemp rS6 = newTemp(ty);
7001 IRTemp rS7 = newTemp(ty);
7002 IRTemp iHi = newTemp(Ity_I32);
7003 IRTemp iLo = newTemp(Ity_I32);
7004 IROp to_bit = (mode64 ? Iop_64to1 : Iop_32to1);
7005 IROp shr_op = (mode64 ? Iop_Shr64 : Iop_Shr32);
7007 if (opc1 != 0x1f || rB_addr || b0) {
7008 vex_printf("dis_int_parity(ppc)(0x1F,opc1:rB|b0)\n");
7009 return False;
7012 assign( rS, getIReg(rS_addr) );
7014 switch (opc2) {
7015 case 0xba: // prtyd (Parity Doubleword, ISA 2.05 p320)
7016 DIP("prtyd r%u,r%u\n", rA_addr, rS_addr);
7017 assign( iTot1, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS))) );
7018 assign( rS1, binop(shr_op, mkexpr(rS), mkU8(8)) );
7019 assign( iTot2, binop(Iop_Add32,
7020 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS1))),
7021 mkexpr(iTot1)) );
7022 assign( rS2, binop(shr_op, mkexpr(rS1), mkU8(8)) );
7023 assign( iTot3, binop(Iop_Add32,
7024 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS2))),
7025 mkexpr(iTot2)) );
7026 assign( rS3, binop(shr_op, mkexpr(rS2), mkU8(8)) );
7027 assign( iTot4, binop(Iop_Add32,
7028 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS3))),
7029 mkexpr(iTot3)) );
7030 if (mode64) {
7031 assign( rS4, binop(shr_op, mkexpr(rS3), mkU8(8)) );
7032 assign( iTot5, binop(Iop_Add32,
7033 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS4))),
7034 mkexpr(iTot4)) );
7035 assign( rS5, binop(shr_op, mkexpr(rS4), mkU8(8)) );
7036 assign( iTot6, binop(Iop_Add32,
7037 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS5))),
7038 mkexpr(iTot5)) );
7039 assign( rS6, binop(shr_op, mkexpr(rS5), mkU8(8)) );
7040 assign( iTot7, binop(Iop_Add32,
7041 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS6))),
7042 mkexpr(iTot6)) );
7043 assign( rS7, binop(shr_op, mkexpr(rS6), mkU8(8)) );
7044 assign( iTot8, binop(Iop_Add32,
7045 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS7))),
7046 mkexpr(iTot7)) );
7047 assign( rA, unop(Iop_32Uto64,
7048 binop(Iop_And32, mkexpr(iTot8), mkU32(1))) );
7049 } else
7050 assign( rA, mkexpr(iTot4) );
7052 break;
7053 case 0x9a: // prtyw (Parity Word, ISA 2.05 p320)
7054 assign( iTot1, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS))) );
7055 assign( rS1, binop(shr_op, mkexpr(rS), mkU8(8)) );
7056 assign( iTot2, binop(Iop_Add32,
7057 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS1))),
7058 mkexpr(iTot1)) );
7059 assign( rS2, binop(shr_op, mkexpr(rS1), mkU8(8)) );
7060 assign( iTot3, binop(Iop_Add32,
7061 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS2))),
7062 mkexpr(iTot2)) );
7063 assign( rS3, binop(shr_op, mkexpr(rS2), mkU8(8)) );
7064 assign( iTot4, binop(Iop_Add32,
7065 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS3))),
7066 mkexpr(iTot3)) );
7067 assign( iLo, unop(Iop_1Uto32, unop(Iop_32to1, mkexpr(iTot4) )) );
7069 if (mode64) {
7070 assign( rS4, binop(shr_op, mkexpr(rS3), mkU8(8)) );
7071 assign( iTot5, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS4))) );
7072 assign( rS5, binop(shr_op, mkexpr(rS4), mkU8(8)) );
7073 assign( iTot6, binop(Iop_Add32,
7074 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS5))),
7075 mkexpr(iTot5)) );
7076 assign( rS6, binop(shr_op, mkexpr(rS5), mkU8(8)) );
7077 assign( iTot7, binop(Iop_Add32,
7078 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS6))),
7079 mkexpr(iTot6)) );
7080 assign( rS7, binop(shr_op, mkexpr(rS6), mkU8(8)));
7081 assign( iTot8, binop(Iop_Add32,
7082 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS7))),
7083 mkexpr(iTot7)) );
7084 assign( iHi, binop(Iop_And32, mkU32(1), mkexpr(iTot8)) ),
7085 assign( rA, binop(Iop_32HLto64, mkexpr(iHi), mkexpr(iLo)) );
7086 } else
7087 assign( rA, binop(Iop_Or32, mkU32(0), mkexpr(iLo)) );
7088 break;
7089 default:
7090 vex_printf("dis_int_parity(ppc)(opc2)\n");
7091 return False;
7094 putIReg( rA_addr, mkexpr(rA) );
7096 return True;
7101 Integer Rotate Instructions
7103 static Bool dis_int_rot ( UInt theInstr )
7105 /* M-Form, MDS-Form */
7106 UChar opc1 = ifieldOPC(theInstr);
7107 UChar rS_addr = ifieldRegDS(theInstr);
7108 UChar rA_addr = ifieldRegA(theInstr);
7109 UChar rB_addr = ifieldRegB(theInstr);
7110 UChar sh_imm = rB_addr;
7111 UChar MaskBeg = toUChar( IFIELD( theInstr, 6, 5 ) );
7112 UChar MaskEnd = toUChar( IFIELD( theInstr, 1, 5 ) );
7113 UChar msk_imm = toUChar( IFIELD( theInstr, 5, 6 ) );
7114 UChar opc2 = toUChar( IFIELD( theInstr, 2, 3 ) );
7115 UChar b1 = ifieldBIT1(theInstr);
7116 UChar flag_rC = ifieldBIT0(theInstr);
7118 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7119 IRTemp rS = newTemp(ty);
7120 IRTemp rA = newTemp(ty);
7121 IRTemp rB = newTemp(ty);
7122 IRTemp rot = newTemp(ty);
7123 IRExpr *r;
7124 UInt mask32;
7125 ULong mask64;
7127 assign( rS, getIReg(rS_addr) );
7128 assign( rB, getIReg(rB_addr) );
7130 switch (opc1) {
7131 case 0x14: {
7132 // rlwimi (Rotate Left Word Imm then Mask Insert, PPC32 p500)
7133 DIP("rlwimi%s r%u,r%u,%d,%d,%d\n", flag_rC ? ".":"",
7134 rA_addr, rS_addr, sh_imm, MaskBeg, MaskEnd);
7135 if (mode64) {
7136 // tmp32 = (ROTL(rS_Lo32, Imm)
7137 // rA = ((tmp32 || tmp32) & mask64) | (rA & ~mask64)
7138 mask64 = MASK64(31-MaskEnd, 31-MaskBeg);
7139 r = ROTL( unop(Iop_64to32, mkexpr(rS) ), mkU8(sh_imm) );
7140 r = unop(Iop_32Uto64, r);
7141 assign( rot, binop(Iop_Or64, r,
7142 binop(Iop_Shl64, r, mkU8(32))) );
7143 assign( rA,
7144 binop(Iop_Or64,
7145 binop(Iop_And64, mkexpr(rot), mkU64(mask64)),
7146 binop(Iop_And64, getIReg(rA_addr), mkU64(~mask64))) );
7148 else {
7149 // rA = (ROTL(rS, Imm) & mask) | (rA & ~mask);
7150 mask32 = MASK32(31-MaskEnd, 31-MaskBeg);
7151 r = ROTL(mkexpr(rS), mkU8(sh_imm));
7152 assign( rA,
7153 binop(Iop_Or32,
7154 binop(Iop_And32, mkU32(mask32), r),
7155 binop(Iop_And32, getIReg(rA_addr), mkU32(~mask32))) );
7157 break;
7160 case 0x15: {
7161 // rlwinm (Rotate Left Word Imm then AND with Mask, PPC32 p501)
7162 vassert(MaskBeg < 32);
7163 vassert(MaskEnd < 32);
7164 vassert(sh_imm < 32);
7166 if (mode64) {
7167 IRTemp rTmp = newTemp(Ity_I64);
7168 mask64 = MASK64(31-MaskEnd, 31-MaskBeg);
7169 DIP("rlwinm%s r%u,r%u,%d,%d,%d\n", flag_rC ? ".":"",
7170 rA_addr, rS_addr, sh_imm, MaskBeg, MaskEnd);
7171 // tmp32 = (ROTL(rS_Lo32, Imm)
7172 // rA = ((tmp32 || tmp32) & mask64)
7173 r = ROTL( unop(Iop_64to32, mkexpr(rS) ), mkU8(sh_imm) );
7174 r = unop(Iop_32Uto64, r);
7175 assign( rTmp, r );
7176 r = NULL;
7177 assign( rot, binop(Iop_Or64, mkexpr(rTmp),
7178 binop(Iop_Shl64, mkexpr(rTmp), mkU8(32))) );
7179 assign( rA, binop(Iop_And64, mkexpr(rot), mkU64(mask64)) );
7181 else {
7182 if (MaskBeg == 0 && sh_imm+MaskEnd == 31) {
7183 /* Special-case the ,n,0,31-n form as that is just n-bit
7184 shift left, PPC32 p501 */
7185 DIP("slwi%s r%u,r%u,%d\n", flag_rC ? ".":"",
7186 rA_addr, rS_addr, sh_imm);
7187 assign( rA, binop(Iop_Shl32, mkexpr(rS), mkU8(sh_imm)) );
7189 else if (MaskEnd == 31 && sh_imm+MaskBeg == 32) {
7190 /* Special-case the ,32-n,n,31 form as that is just n-bit
7191 unsigned shift right, PPC32 p501 */
7192 DIP("srwi%s r%u,r%u,%d\n", flag_rC ? ".":"",
7193 rA_addr, rS_addr, MaskBeg);
7194 assign( rA, binop(Iop_Shr32, mkexpr(rS), mkU8(MaskBeg)) );
7196 else {
7197 /* General case. */
7198 mask32 = MASK32(31-MaskEnd, 31-MaskBeg);
7199 DIP("rlwinm%s r%u,r%u,%d,%d,%d\n", flag_rC ? ".":"",
7200 rA_addr, rS_addr, sh_imm, MaskBeg, MaskEnd);
7201 // rA = ROTL(rS, Imm) & mask
7202 assign( rA, binop(Iop_And32,
7203 ROTL(mkexpr(rS), mkU8(sh_imm)),
7204 mkU32(mask32)) );
7207 break;
7210 case 0x17: {
7211 // rlwnm (Rotate Left Word then AND with Mask, PPC32 p503
7212 DIP("rlwnm%s r%u,r%u,r%u,%d,%d\n", flag_rC ? ".":"",
7213 rA_addr, rS_addr, rB_addr, MaskBeg, MaskEnd);
7214 if (mode64) {
7215 mask64 = MASK64(31-MaskEnd, 31-MaskBeg);
7216 /* weird insn alert!
7217 tmp32 = (ROTL(rS_Lo32, rB[0-4])
7218 rA = ((tmp32 || tmp32) & mask64)
7220 // note, ROTL does the masking, so we don't do it here
7221 r = ROTL( unop(Iop_64to32, mkexpr(rS)),
7222 unop(Iop_64to8, mkexpr(rB)) );
7223 r = unop(Iop_32Uto64, r);
7224 assign(rot, binop(Iop_Or64, r, binop(Iop_Shl64, r, mkU8(32))));
7225 assign( rA, binop(Iop_And64, mkexpr(rot), mkU64(mask64)) );
7226 } else {
7227 mask32 = MASK32(31-MaskEnd, 31-MaskBeg);
7228 // rA = ROTL(rS, rB[0-4]) & mask
7229 // note, ROTL does the masking, so we don't do it here
7230 assign( rA, binop(Iop_And32,
7231 ROTL(mkexpr(rS),
7232 unop(Iop_32to8, mkexpr(rB))),
7233 mkU32(mask32)) );
7235 break;
7238 /* 64bit Integer Rotates */
7239 case 0x1E: {
7240 msk_imm = ((msk_imm & 1) << 5) | (msk_imm >> 1);
7241 sh_imm |= b1 << 5;
7243 vassert( msk_imm < 64 );
7244 vassert( sh_imm < 64 );
7246 switch (opc2) {
7247 case 0x4: {
7248 /* r = ROTL64( rS, rB_lo6) */
7249 r = ROTL( mkexpr(rS), unop(Iop_64to8, mkexpr(rB)) );
7251 if (b1 == 0) { // rldcl (Rotl DWord, Clear Left, PPC64 p555)
7252 DIP("rldcl%s r%u,r%u,r%u,%u\n", flag_rC ? ".":"",
7253 rA_addr, rS_addr, rB_addr, msk_imm);
7254 // note, ROTL does the masking, so we don't do it here
7255 mask64 = MASK64(0, 63-msk_imm);
7256 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
7257 break;
7258 } else { // rldcr (Rotl DWord, Clear Right, PPC64 p556)
7259 DIP("rldcr%s r%u,r%u,r%u,%u\n", flag_rC ? ".":"",
7260 rA_addr, rS_addr, rB_addr, msk_imm);
7261 mask64 = MASK64(63-msk_imm, 63);
7262 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
7263 break;
7265 break;
7267 case 0x2: // rldic (Rotl DWord Imm, Clear, PPC64 p557)
7268 DIP("rldic%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
7269 rA_addr, rS_addr, sh_imm, msk_imm);
7270 r = ROTL(mkexpr(rS), mkU8(sh_imm));
7271 mask64 = MASK64(sh_imm, 63-msk_imm);
7272 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
7273 break;
7274 // later: deal with special case: (msk_imm==0) => SHL(sh_imm)
7276 Hmm... looks like this'll do the job more simply:
7277 r = SHL(rS, sh_imm)
7278 m = ~(1 << (63-msk_imm))
7279 assign(rA, r & m);
7282 case 0x0: // rldicl (Rotl DWord Imm, Clear Left, PPC64 p558)
7283 if (mode64
7284 && sh_imm + msk_imm == 64 && msk_imm >= 1 && msk_imm <= 63) {
7285 /* special-case the ,64-n,n form as that is just
7286 unsigned shift-right by n */
7287 DIP("srdi%s r%u,r%u,%u\n",
7288 flag_rC ? ".":"", rA_addr, rS_addr, msk_imm);
7289 assign( rA, binop(Iop_Shr64, mkexpr(rS), mkU8(msk_imm)) );
7290 } else {
7291 DIP("rldicl%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
7292 rA_addr, rS_addr, sh_imm, msk_imm);
7293 r = ROTL(mkexpr(rS), mkU8(sh_imm));
7294 mask64 = MASK64(0, 63-msk_imm);
7295 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
7297 break;
7299 case 0x1: // rldicr (Rotl DWord Imm, Clear Right, PPC64 p559)
7300 if (mode64
7301 && sh_imm + msk_imm == 63 && sh_imm >= 1 && sh_imm <= 63) {
7302 /* special-case the ,n,63-n form as that is just
7303 shift-left by n */
7304 DIP("sldi%s r%u,r%u,%u\n",
7305 flag_rC ? ".":"", rA_addr, rS_addr, sh_imm);
7306 assign( rA, binop(Iop_Shl64, mkexpr(rS), mkU8(sh_imm)) );
7307 } else {
7308 DIP("rldicr%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
7309 rA_addr, rS_addr, sh_imm, msk_imm);
7310 r = ROTL(mkexpr(rS), mkU8(sh_imm));
7311 mask64 = MASK64(63-msk_imm, 63);
7312 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
7314 break;
7316 case 0x3: { // rldimi (Rotl DWord Imm, Mask Insert, PPC64 p560)
7317 IRTemp rA_orig = newTemp(ty);
7318 DIP("rldimi%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
7319 rA_addr, rS_addr, sh_imm, msk_imm);
7320 r = ROTL(mkexpr(rS), mkU8(sh_imm));
7321 mask64 = MASK64(sh_imm, 63-msk_imm);
7322 assign( rA_orig, getIReg(rA_addr) );
7323 assign( rA, binop(Iop_Or64,
7324 binop(Iop_And64, mkU64(mask64), r),
7325 binop(Iop_And64, mkU64(~mask64),
7326 mkexpr(rA_orig))) );
7327 break;
7329 default:
7330 vex_printf("dis_int_rot(ppc)(opc2)\n");
7331 return False;
7333 break;
7336 default:
7337 vex_printf("dis_int_rot(ppc)(opc1)\n");
7338 return False;
7341 putIReg( rA_addr, mkexpr(rA) );
7343 if (flag_rC) {
7344 set_CR0( mkexpr(rA) );
7346 return True;
7351 Integer Load Instructions
7353 static Bool dis_int_load ( UInt theInstr )
7355 /* D-Form, X-Form, DS-Form */
7356 UChar opc1 = ifieldOPC(theInstr);
7357 UChar rD_addr = ifieldRegDS(theInstr);
7358 UChar rA_addr = ifieldRegA(theInstr);
7359 UInt uimm16 = ifieldUIMM16(theInstr);
7360 UChar rB_addr = ifieldRegB(theInstr);
7361 UInt opc2 = ifieldOPClo10(theInstr);
7362 UChar b1 = ifieldBIT1(theInstr);
7363 UChar b0 = ifieldBIT0(theInstr);
7365 Int simm16 = extend_s_16to32(uimm16);
7366 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7367 IRTemp EA = newTemp(ty);
7368 IRExpr* val;
7370 switch (opc1) {
7371 case 0x1F: // register offset
7372 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
7373 break;
7374 case 0x38: // immediate offset: 64bit: lq: maskoff
7375 // lowest 4 bits of immediate before forming EA
7376 simm16 = simm16 & 0xFFFFFFF0;
7377 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
7378 break;
7379 case 0x3A: // immediate offset: 64bit: ld/ldu/lwa: mask off
7380 // lowest 2 bits of immediate before forming EA
7381 simm16 = simm16 & 0xFFFFFFFC;
7382 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
7383 break;
7384 default: // immediate offset
7385 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
7386 break;
7389 switch (opc1) {
7390 case 0x22: // lbz (Load B & Zero, PPC32 p433)
7391 DIP("lbz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7392 val = load(Ity_I8, mkexpr(EA));
7393 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
7394 break;
7396 case 0x23: // lbzu (Load B & Zero, Update, PPC32 p434)
7397 if (rA_addr == 0 || rA_addr == rD_addr) {
7398 vex_printf("dis_int_load(ppc)(lbzu,rA_addr|rD_addr)\n");
7399 return False;
7401 DIP("lbzu r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7402 val = load(Ity_I8, mkexpr(EA));
7403 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
7404 putIReg( rA_addr, mkexpr(EA) );
7405 break;
7407 case 0x2A: // lha (Load HW Alg, PPC32 p445)
7408 DIP("lha r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7409 val = load(Ity_I16, mkexpr(EA));
7410 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
7411 break;
7413 case 0x2B: // lhau (Load HW Alg, Update, PPC32 p446)
7414 if (rA_addr == 0 || rA_addr == rD_addr) {
7415 vex_printf("dis_int_load(ppc)(lhau,rA_addr|rD_addr)\n");
7416 return False;
7418 DIP("lhau r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7419 val = load(Ity_I16, mkexpr(EA));
7420 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
7421 putIReg( rA_addr, mkexpr(EA) );
7422 break;
7424 case 0x28: // lhz (Load HW & Zero, PPC32 p450)
7425 DIP("lhz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7426 val = load(Ity_I16, mkexpr(EA));
7427 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
7428 break;
7430 case 0x29: // lhzu (Load HW & and Zero, Update, PPC32 p451)
7431 if (rA_addr == 0 || rA_addr == rD_addr) {
7432 vex_printf("dis_int_load(ppc)(lhzu,rA_addr|rD_addr)\n");
7433 return False;
7435 DIP("lhzu r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7436 val = load(Ity_I16, mkexpr(EA));
7437 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
7438 putIReg( rA_addr, mkexpr(EA) );
7439 break;
7441 case 0x20: // lwz (Load W & Zero, PPC32 p460)
7442 DIP("lwz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7443 val = load(Ity_I32, mkexpr(EA));
7444 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
7445 break;
7447 case 0x21: // lwzu (Load W & Zero, Update, PPC32 p461))
7448 if (rA_addr == 0 || rA_addr == rD_addr) {
7449 vex_printf("dis_int_load(ppc)(lwzu,rA_addr|rD_addr)\n");
7450 return False;
7452 DIP("lwzu r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7453 val = load(Ity_I32, mkexpr(EA));
7454 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
7455 putIReg( rA_addr, mkexpr(EA) );
7456 break;
7458 /* X Form */
7459 case 0x1F:
7460 if (b0 != 0) {
7461 vex_printf("dis_int_load(ppc)(Ox1F,b0)\n");
7462 return False;
7465 switch (opc2) {
7466 case 0x077: // lbzux (Load B & Zero, Update Indexed, PPC32 p435)
7467 DIP("lbzux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7468 if (rA_addr == 0 || rA_addr == rD_addr) {
7469 vex_printf("dis_int_load(ppc)(lwzux,rA_addr|rD_addr)\n");
7470 return False;
7472 val = load(Ity_I8, mkexpr(EA));
7473 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
7474 putIReg( rA_addr, mkexpr(EA) );
7475 break;
7477 case 0x057: // lbzx (Load B & Zero, Indexed, PPC32 p436)
7478 DIP("lbzx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7479 val = load(Ity_I8, mkexpr(EA));
7480 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
7481 break;
7483 case 0x177: // lhaux (Load HW Alg, Update Indexed, PPC32 p447)
7484 if (rA_addr == 0 || rA_addr == rD_addr) {
7485 vex_printf("dis_int_load(ppc)(lhaux,rA_addr|rD_addr)\n");
7486 return False;
7488 DIP("lhaux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7489 val = load(Ity_I16, mkexpr(EA));
7490 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
7491 putIReg( rA_addr, mkexpr(EA) );
7492 break;
7494 case 0x157: // lhax (Load HW Alg, Indexed, PPC32 p448)
7495 DIP("lhax r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7496 val = load(Ity_I16, mkexpr(EA));
7497 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
7498 break;
7500 case 0x137: // lhzux (Load HW & Zero, Update Indexed, PPC32 p452)
7501 if (rA_addr == 0 || rA_addr == rD_addr) {
7502 vex_printf("dis_int_load(ppc)(lhzux,rA_addr|rD_addr)\n");
7503 return False;
7505 DIP("lhzux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7506 val = load(Ity_I16, mkexpr(EA));
7507 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
7508 putIReg( rA_addr, mkexpr(EA) );
7509 break;
7511 case 0x117: // lhzx (Load HW & Zero, Indexed, PPC32 p453)
7512 DIP("lhzx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7513 val = load(Ity_I16, mkexpr(EA));
7514 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
7515 break;
7517 case 0x037: // lwzux (Load W & Zero, Update Indexed, PPC32 p462)
7518 if (rA_addr == 0 || rA_addr == rD_addr) {
7519 vex_printf("dis_int_load(ppc)(lwzux,rA_addr|rD_addr)\n");
7520 return False;
7522 DIP("lwzux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7523 val = load(Ity_I32, mkexpr(EA));
7524 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
7525 putIReg( rA_addr, mkexpr(EA) );
7526 break;
7528 case 0x017: // lwzx (Load W & Zero, Indexed, PPC32 p463)
7529 DIP("lwzx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7530 val = load(Ity_I32, mkexpr(EA));
7531 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
7532 break;
7535 /* 64bit Loads */
7536 case 0x035: // ldux (Load DWord, Update Indexed, PPC64 p475)
7537 if (rA_addr == 0 || rA_addr == rD_addr) {
7538 vex_printf("dis_int_load(ppc)(ldux,rA_addr|rD_addr)\n");
7539 return False;
7541 DIP("ldux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7542 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
7543 putIReg( rA_addr, mkexpr(EA) );
7544 break;
7546 case 0x015: // ldx (Load DWord, Indexed, PPC64 p476)
7547 DIP("ldx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7548 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
7549 break;
7551 case 0x175: // lwaux (Load W Alg, Update Indexed, PPC64 p501)
7552 if (rA_addr == 0 || rA_addr == rD_addr) {
7553 vex_printf("dis_int_load(ppc)(lwaux,rA_addr|rD_addr)\n");
7554 return False;
7556 DIP("lwaux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7557 putIReg( rD_addr,
7558 unop(Iop_32Sto64, load(Ity_I32, mkexpr(EA))) );
7559 putIReg( rA_addr, mkexpr(EA) );
7560 break;
7562 case 0x155: // lwax (Load W Alg, Indexed, PPC64 p502)
7563 DIP("lwax r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7564 putIReg( rD_addr,
7565 unop(Iop_32Sto64, load(Ity_I32, mkexpr(EA))) );
7566 break;
7568 default:
7569 vex_printf("dis_int_load(ppc)(opc2)\n");
7570 return False;
7572 break;
7574 /* DS Form - 64bit Loads. In each case EA will have been formed
7575 with the lowest 2 bits masked off the immediate offset. */
7576 case 0x3A:
7577 switch ((b1<<1) | b0) {
7578 case 0x0: // ld (Load DWord, PPC64 p472)
7579 DIP("ld r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
7580 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
7581 break;
7583 case 0x1: // ldu (Load DWord, Update, PPC64 p474)
7584 if (rA_addr == 0 || rA_addr == rD_addr) {
7585 vex_printf("dis_int_load(ppc)(ldu,rA_addr|rD_addr)\n");
7586 return False;
7588 DIP("ldu r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
7589 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
7590 putIReg( rA_addr, mkexpr(EA) );
7591 break;
7593 case 0x2: // lwa (Load Word Alg, PPC64 p499)
7594 DIP("lwa r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
7595 putIReg( rD_addr,
7596 unop(Iop_32Sto64, load(Ity_I32, mkexpr(EA))) );
7597 break;
7599 default:
7600 vex_printf("dis_int_load(ppc)(0x3A, opc2)\n");
7601 return False;
7603 break;
7605 case 0x38: {
7606 IRTemp high = newTemp(ty);
7607 IRTemp low = newTemp(ty);
7608 /* DQ Form - 128bit Loads. Lowest bits [1:0] are the PT field. */
7609 DIP("lq r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
7610 /* NOTE: there are some changes to XER[41:42] that have not been
7611 * implemented.
7613 // trap if EA misaligned on 16 byte address
7614 if (mode64) {
7615 if (host_endness == VexEndnessBE) {
7616 assign(high, load(ty, mkexpr( EA ) ) );
7617 assign(low, load(ty, binop( Iop_Add64,
7618 mkexpr( EA ),
7619 mkU64( 8 ) ) ) );
7620 } else {
7621 assign(low, load(ty, mkexpr( EA ) ) );
7622 assign(high, load(ty, binop( Iop_Add64,
7623 mkexpr( EA ),
7624 mkU64( 8 ) ) ) );
7626 } else {
7627 assign(high, load(ty, binop( Iop_Add32,
7628 mkexpr( EA ),
7629 mkU32( 4 ) ) ) );
7630 assign(low, load(ty, binop( Iop_Add32,
7631 mkexpr( EA ),
7632 mkU32( 12 ) ) ) );
7634 gen_SIGBUS_if_misaligned( EA, 16 );
7635 putIReg( rD_addr, mkexpr( high) );
7636 putIReg( rD_addr+1, mkexpr( low) );
7637 break;
7639 default:
7640 vex_printf("dis_int_load(ppc)(opc1)\n");
7641 return False;
7643 return True;
7649 Integer Store Instructions
7651 static Bool dis_int_store ( UInt theInstr, const VexAbiInfo* vbi )
7653 /* D-Form, X-Form, DS-Form */
7654 UChar opc1 = ifieldOPC(theInstr);
7655 UInt rS_addr = ifieldRegDS(theInstr);
7656 UInt rA_addr = ifieldRegA(theInstr);
7657 UInt uimm16 = ifieldUIMM16(theInstr);
7658 UInt rB_addr = ifieldRegB(theInstr);
7659 UInt opc2 = ifieldOPClo10(theInstr);
7660 UChar b1 = ifieldBIT1(theInstr);
7661 UChar b0 = ifieldBIT0(theInstr);
7663 Int simm16 = extend_s_16to32(uimm16);
7664 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7665 IRTemp rS = newTemp(ty);
7666 IRTemp rB = newTemp(ty);
7667 IRTemp EA = newTemp(ty);
7669 assign( rB, getIReg(rB_addr) );
7670 assign( rS, getIReg(rS_addr) );
7672 switch (opc1) {
7673 case 0x1F: // register offset
7674 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
7675 break;
7676 case 0x3E: // immediate offset: 64bit: std/stdu/stq: mask off
7677 // lowest 2 bits of immediate before forming EA
7678 simm16 = simm16 & 0xFFFFFFFC;
7679 /* fallthrough */
7680 default: // immediate offset
7681 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
7682 break;
7685 switch (opc1) {
7686 case 0x26: // stb (Store B, PPC32 p509)
7687 DIP("stb r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7688 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
7689 break;
7691 case 0x27: // stbu (Store B, Update, PPC32 p510)
7692 if (rA_addr == 0 ) {
7693 vex_printf("dis_int_store(ppc)(stbu,rA_addr)\n");
7694 return False;
7696 DIP("stbu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7697 putIReg( rA_addr, mkexpr(EA) );
7698 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
7699 break;
7701 case 0x2C: // sth (Store HW, PPC32 p522)
7702 DIP("sth r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7703 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
7704 break;
7706 case 0x2D: // sthu (Store HW, Update, PPC32 p524)
7707 if (rA_addr == 0) {
7708 vex_printf("dis_int_store(ppc)(sthu,rA_addr)\n");
7709 return False;
7711 DIP("sthu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7712 putIReg( rA_addr, mkexpr(EA) );
7713 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
7714 break;
7716 case 0x24: // stw (Store W, PPC32 p530)
7717 DIP("stw r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7718 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
7719 break;
7721 case 0x25: // stwu (Store W, Update, PPC32 p534)
7722 if (rA_addr == 0) {
7723 vex_printf("dis_int_store(ppc)(stwu,rA_addr)\n");
7724 return False;
7726 DIP("stwu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7727 putIReg( rA_addr, mkexpr(EA) );
7728 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
7729 break;
7731 /* X Form : all these use EA_indexed */
7732 case 0x1F:
7733 if (b0 != 0) {
7734 vex_printf("dis_int_store(ppc)(0x1F,b0)\n");
7735 return False;
7738 switch (opc2) {
7739 case 0x0F7: // stbux (Store B, Update Indexed, PPC32 p511)
7740 if (rA_addr == 0) {
7741 vex_printf("dis_int_store(ppc)(stbux,rA_addr)\n");
7742 return False;
7744 DIP("stbux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7745 putIReg( rA_addr, mkexpr(EA) );
7746 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
7747 break;
7749 case 0x0D7: // stbx (Store B Indexed, PPC32 p512)
7750 DIP("stbx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7751 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
7752 break;
7754 case 0x1B7: // sthux (Store HW, Update Indexed, PPC32 p525)
7755 if (rA_addr == 0) {
7756 vex_printf("dis_int_store(ppc)(sthux,rA_addr)\n");
7757 return False;
7759 DIP("sthux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7760 putIReg( rA_addr, mkexpr(EA) );
7761 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
7762 break;
7764 case 0x197: // sthx (Store HW Indexed, PPC32 p526)
7765 DIP("sthx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7766 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
7767 break;
7769 case 0x0B7: // stwux (Store W, Update Indexed, PPC32 p535)
7770 if (rA_addr == 0) {
7771 vex_printf("dis_int_store(ppc)(stwux,rA_addr)\n");
7772 return False;
7774 DIP("stwux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7775 putIReg( rA_addr, mkexpr(EA) );
7776 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
7777 break;
7779 case 0x097: // stwx (Store W Indexed, PPC32 p536)
7780 DIP("stwx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7781 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
7782 break;
7785 /* 64bit Stores */
7786 case 0x0B5: // stdux (Store DWord, Update Indexed, PPC64 p584)
7787 if (rA_addr == 0) {
7788 vex_printf("dis_int_store(ppc)(stdux,rA_addr)\n");
7789 return False;
7791 DIP("stdux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7792 putIReg( rA_addr, mkexpr(EA) );
7793 store( mkexpr(EA), mkexpr(rS) );
7794 break;
7796 case 0x095: // stdx (Store DWord Indexed, PPC64 p585)
7797 DIP("stdx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7798 store( mkexpr(EA), mkexpr(rS) );
7799 break;
7801 default:
7802 vex_printf("dis_int_store(ppc)(opc2)\n");
7803 return False;
7805 break;
7807 /* DS Form - 64bit Stores. In each case EA will have been formed
7808 with the lowest 2 bits masked off the immediate offset. */
7809 case 0x3E:
7810 switch ((b1<<1) | b0) {
7811 case 0x0: // std (Store DWord, PPC64 p580)
7812 if (!mode64)
7813 return False;
7815 DIP("std r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7816 store( mkexpr(EA), mkexpr(rS) );
7817 break;
7819 case 0x1: // stdu (Store DWord, Update, PPC64 p583)
7820 if (!mode64)
7821 return False;
7823 DIP("stdu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7824 putIReg( rA_addr, mkexpr(EA) );
7825 store( mkexpr(EA), mkexpr(rS) );
7826 break;
7828 case 0x2: { // stq (Store QuadWord, Update, PPC64 p583)
7829 IRTemp EA_hi = newTemp(ty);
7830 IRTemp EA_lo = newTemp(ty);
7831 DIP("stq r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7833 if (mode64) {
7834 if (host_endness == VexEndnessBE) {
7836 /* upper 64-bits */
7837 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
7839 /* lower 64-bits */
7840 assign( EA_lo, ea_rAor0_simm( rA_addr, simm16+8 ) );
7841 } else {
7842 /* upper 64-bits */
7843 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16+8 ) );
7845 /* lower 64-bits */
7846 assign( EA_lo, ea_rAor0_simm( rA_addr, simm16 ) );
7848 } else {
7849 /* upper half of upper 64-bits */
7850 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16+4 ) );
7852 /* lower half of upper 64-bits */
7853 assign( EA_lo, ea_rAor0_simm( rA_addr, simm16+12 ) );
7855 store( mkexpr(EA_hi), mkexpr(rS) );
7856 store( mkexpr(EA_lo), getIReg( rS_addr+1 ) );
7857 break;
7859 default:
7860 vex_printf("dis_int_load(ppc)(0x3A, opc2)\n");
7861 return False;
7863 break;
7865 default:
7866 vex_printf("dis_int_store(ppc)(opc1)\n");
7867 return False;
7869 return True;
7875 Integer Load/Store Multiple Instructions
7877 static Bool dis_int_ldst_mult ( UInt theInstr )
7879 /* D-Form */
7880 UChar opc1 = ifieldOPC(theInstr);
7881 UChar rD_addr = ifieldRegDS(theInstr);
7882 UChar rS_addr = rD_addr;
7883 UChar rA_addr = ifieldRegA(theInstr);
7884 UInt uimm16 = ifieldUIMM16(theInstr);
7886 Int simm16 = extend_s_16to32(uimm16);
7887 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7888 IROp mkAdd = mode64 ? Iop_Add64 : Iop_Add32;
7889 IRTemp EA = newTemp(ty);
7890 UInt r = 0;
7891 UInt ea_off = 0;
7892 IRExpr* irx_addr;
7894 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
7896 switch (opc1) {
7897 case 0x2E: // lmw (Load Multiple Word, PPC32 p454)
7898 if (rA_addr >= rD_addr) {
7899 vex_printf("dis_int_ldst_mult(ppc)(lmw,rA_addr)\n");
7900 return False;
7902 DIP("lmw r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
7903 for (r = rD_addr; r <= 31; r++) {
7904 irx_addr = binop(mkAdd, mkexpr(EA), mode64 ? mkU64(ea_off) : mkU32(ea_off));
7905 putIReg( r, mkWidenFrom32(ty, load(Ity_I32, irx_addr ),
7906 False) );
7907 ea_off += 4;
7909 break;
7911 case 0x2F: // stmw (Store Multiple Word, PPC32 p527)
7912 DIP("stmw r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7913 for (r = rS_addr; r <= 31; r++) {
7914 irx_addr = binop(mkAdd, mkexpr(EA), mode64 ? mkU64(ea_off) : mkU32(ea_off));
7915 store( irx_addr, mkNarrowTo32(ty, getIReg(r)) );
7916 ea_off += 4;
7918 break;
7920 default:
7921 vex_printf("dis_int_ldst_mult(ppc)(opc1)\n");
7922 return False;
7924 return True;
7930 Integer Load/Store String Instructions
7932 static
7933 void generate_lsw_sequence ( IRTemp tNBytes, // # bytes, :: Ity_I32
7934 IRTemp EA, // EA
7935 Int rD, // first dst register
7936 Int maxBytes ) // 32 or 128
7938 Int i, shift = 24;
7939 IRExpr* e_nbytes = mkexpr(tNBytes);
7940 IRExpr* e_EA = mkexpr(EA);
7941 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7943 vassert(rD >= 0 && rD < 32);
7944 rD--; if (rD < 0) rD = 31;
7946 for (i = 0; i < maxBytes; i++) {
7947 /* if (nBytes < (i+1)) goto NIA; */
7948 stmt( IRStmt_Exit( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
7949 Ijk_Boring,
7950 mkSzConst( ty, nextInsnAddr()), OFFB_CIA ));
7951 /* when crossing into a new dest register, set it to zero. */
7952 if ((i % 4) == 0) {
7953 rD++; if (rD == 32) rD = 0;
7954 putIReg(rD, mkSzImm(ty, 0));
7955 shift = 24;
7957 /* rD |= (8Uto32(*(EA+i))) << shift */
7958 vassert(shift == 0 || shift == 8 || shift == 16 || shift == 24);
7959 putIReg(
7960 rD,
7961 mkWidenFrom32(
7962 ty,
7963 binop(
7964 Iop_Or32,
7965 mkNarrowTo32(ty, getIReg(rD)),
7966 binop(
7967 Iop_Shl32,
7968 unop(
7969 Iop_8Uto32,
7970 load( Ity_I8,
7971 binop( mkSzOp(ty,Iop_Add8),
7972 e_EA, mkSzImm(ty,i)))
7974 mkU8(toUChar(shift))
7977 /*Signed*/False
7980 shift -= 8;
7984 static
7985 void generate_stsw_sequence ( IRTemp tNBytes, // # bytes, :: Ity_I32
7986 IRTemp EA, // EA
7987 Int rS, // first src register
7988 Int maxBytes ) // 32 or 128
7990 Int i, shift = 24;
7991 IRExpr* e_nbytes = mkexpr(tNBytes);
7992 IRExpr* e_EA = mkexpr(EA);
7993 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7995 vassert(rS >= 0 && rS < 32);
7996 rS--; if (rS < 0) rS = 31;
7998 for (i = 0; i < maxBytes; i++) {
7999 /* if (nBytes < (i+1)) goto NIA; */
8000 stmt( IRStmt_Exit( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
8001 Ijk_Boring,
8002 mkSzConst( ty, nextInsnAddr() ), OFFB_CIA ));
8003 /* check for crossing into a new src register. */
8004 if ((i % 4) == 0) {
8005 rS++; if (rS == 32) rS = 0;
8006 shift = 24;
8008 /* *(EA+i) = 32to8(rS >> shift) */
8009 vassert(shift == 0 || shift == 8 || shift == 16 || shift == 24);
8010 store(
8011 binop( mkSzOp(ty,Iop_Add8), e_EA, mkSzImm(ty,i)),
8012 unop( Iop_32to8,
8013 binop( Iop_Shr32,
8014 mkNarrowTo32( ty, getIReg(rS) ),
8015 mkU8( toUChar(shift) )))
8017 shift -= 8;
8021 static Bool dis_int_ldst_str ( UInt theInstr, /*OUT*/Bool* stopHere )
8023 /* X-Form */
8024 UChar opc1 = ifieldOPC(theInstr);
8025 UChar rD_addr = ifieldRegDS(theInstr);
8026 UChar rS_addr = rD_addr;
8027 UChar rA_addr = ifieldRegA(theInstr);
8028 UChar rB_addr = ifieldRegB(theInstr);
8029 UChar NumBytes = rB_addr;
8030 UInt opc2 = ifieldOPClo10(theInstr);
8031 UChar b0 = ifieldBIT0(theInstr);
8033 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8034 IRTemp t_EA = newTemp(ty);
8035 IRTemp t_nbytes = IRTemp_INVALID;
8037 *stopHere = False;
8039 if (opc1 != 0x1F || b0 != 0) {
8040 vex_printf("dis_int_ldst_str(ppc)(opc1)\n");
8041 return False;
8044 switch (opc2) {
8045 case 0x255: // lswi (Load String Word Immediate, PPC32 p455)
8046 /* NB: does not reject the case where RA is in the range of
8047 registers to be loaded. It should. */
8048 DIP("lswi r%u,r%u,%d\n", rD_addr, rA_addr, NumBytes);
8049 assign( t_EA, ea_rAor0(rA_addr) );
8050 if (NumBytes == 8 && !mode64) {
8051 /* Special case hack */
8052 /* rD = Mem[EA]; (rD+1)%32 = Mem[EA+4] */
8053 putIReg( rD_addr,
8054 load(Ity_I32, mkexpr(t_EA)) );
8055 putIReg( (rD_addr+1) % 32,
8056 load(Ity_I32,
8057 binop(Iop_Add32, mkexpr(t_EA), mkU32(4))) );
8058 } else {
8059 t_nbytes = newTemp(Ity_I32);
8060 assign( t_nbytes, mkU32(NumBytes==0 ? 32 : NumBytes) );
8061 generate_lsw_sequence( t_nbytes, t_EA, rD_addr, 32 );
8062 *stopHere = True;
8064 return True;
8066 case 0x215: // lswx (Load String Word Indexed, PPC32 p456)
8067 /* NB: does not reject the case where RA is in the range of
8068 registers to be loaded. It should. Although considering
8069 that that can only be detected at run time, it's not easy to
8070 do so. */
8071 if (rD_addr == rA_addr || rD_addr == rB_addr)
8072 return False;
8073 if (rD_addr == 0 && rA_addr == 0)
8074 return False;
8075 DIP("lswx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
8076 t_nbytes = newTemp(Ity_I32);
8077 assign( t_EA, ea_rAor0_idxd(rA_addr,rB_addr) );
8078 assign( t_nbytes, unop( Iop_8Uto32, getXER_BC() ) );
8079 generate_lsw_sequence( t_nbytes, t_EA, rD_addr, 128 );
8080 *stopHere = True;
8081 return True;
8083 case 0x2D5: // stswi (Store String Word Immediate, PPC32 p528)
8084 DIP("stswi r%u,r%u,%d\n", rS_addr, rA_addr, NumBytes);
8085 assign( t_EA, ea_rAor0(rA_addr) );
8086 if (NumBytes == 8 && !mode64) {
8087 /* Special case hack */
8088 /* Mem[EA] = rD; Mem[EA+4] = (rD+1)%32 */
8089 store( mkexpr(t_EA),
8090 getIReg(rD_addr) );
8091 store( binop(Iop_Add32, mkexpr(t_EA), mkU32(4)),
8092 getIReg((rD_addr+1) % 32) );
8093 } else {
8094 t_nbytes = newTemp(Ity_I32);
8095 assign( t_nbytes, mkU32(NumBytes==0 ? 32 : NumBytes) );
8096 generate_stsw_sequence( t_nbytes, t_EA, rD_addr, 32 );
8097 *stopHere = True;
8099 return True;
8101 case 0x295: // stswx (Store String Word Indexed, PPC32 p529)
8102 DIP("stswx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
8103 t_nbytes = newTemp(Ity_I32);
8104 assign( t_EA, ea_rAor0_idxd(rA_addr,rB_addr) );
8105 assign( t_nbytes, unop( Iop_8Uto32, getXER_BC() ) );
8106 generate_stsw_sequence( t_nbytes, t_EA, rS_addr, 128 );
8107 *stopHere = True;
8108 return True;
8110 default:
8111 vex_printf("dis_int_ldst_str(ppc)(opc2)\n");
8112 return False;
8114 return True;
8118 /* ------------------------------------------------------------------
8119 Integer Branch Instructions
8120 ------------------------------------------------------------------ */
8123 Branch helper function
8124 ok = BO[2] | ((CTR[0] != 0) ^ BO[1])
8125 Returns an I32 which is 0x00000000 if the ctr condition failed
8126 and 0xFFFFFFFF otherwise.
8128 static IRExpr* /* :: Ity_I32 */ branch_ctr_ok( UInt BO )
8130 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8131 IRTemp ok = newTemp(Ity_I32);
8133 if ((BO >> 2) & 1) { // independent of ctr
8134 assign( ok, mkU32(0xFFFFFFFF) );
8135 } else {
8136 if ((BO >> 1) & 1) { // ctr == 0 ?
8137 assign( ok, unop( Iop_1Sto32,
8138 binop( mkSzOp(ty, Iop_CmpEQ8),
8139 getGST( PPC_GST_CTR ),
8140 mkSzImm(ty,0))) );
8141 } else { // ctr != 0 ?
8142 assign( ok, unop( Iop_1Sto32,
8143 binop( mkSzOp(ty, Iop_CmpNE8),
8144 getGST( PPC_GST_CTR ),
8145 mkSzImm(ty,0))) );
8148 return mkexpr(ok);
8153 Branch helper function cond_ok = BO[4] | (CR[BI] == BO[3])
8154 Returns an I32 which is either 0 if the condition failed or
8155 some arbitrary nonzero value otherwise. */
8157 static IRExpr* /* :: Ity_I32 */ branch_cond_ok( UInt BO, UInt BI )
8159 Int where;
8160 IRTemp res = newTemp(Ity_I32);
8161 IRTemp cr_bi = newTemp(Ity_I32);
8163 if ((BO >> 4) & 1) {
8164 assign( res, mkU32(1) );
8165 } else {
8166 // ok = (CR[BI] == BO[3]) Note, the following relies on
8167 // getCRbit_anywhere returning a value which
8168 // is either zero or has exactly 1 bit set.
8169 assign( cr_bi, getCRbit_anywhere( BI, &where ) );
8171 if ((BO >> 3) & 1) {
8172 /* We can use cr_bi as-is. */
8173 assign( res, mkexpr(cr_bi) );
8174 } else {
8175 /* We have to invert the sense of the information held in
8176 cr_bi. For that we need to know which bit
8177 getCRbit_anywhere regards as significant. */
8178 assign( res, binop(Iop_Xor32, mkexpr(cr_bi),
8179 mkU32(1<<where)) );
8182 return mkexpr(res);
8187 Integer Branch Instructions
8189 static Bool dis_branch ( UInt theInstr,
8190 const VexAbiInfo* vbi,
8191 /*OUT*/DisResult* dres )
8193 UChar opc1 = ifieldOPC(theInstr);
8194 UChar BO = ifieldRegDS(theInstr);
8195 UChar BI = ifieldRegA(theInstr);
8196 UInt BD_u16 = ifieldUIMM16(theInstr) & 0xFFFFFFFC; /* mask off */
8197 UChar b11to15 = ifieldRegB(theInstr);
8198 UInt opc2 = ifieldOPClo10(theInstr);
8199 UInt LI_u26 = ifieldUIMM26(theInstr) & 0xFFFFFFFC; /* mask off */
8200 UChar flag_AA = ifieldBIT1(theInstr);
8201 UChar flag_LK = ifieldBIT0(theInstr);
8203 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8204 Addr64 tgt = 0;
8205 UInt BD = extend_s_16to32(BD_u16);
8206 IRTemp do_branch = newTemp(Ity_I32);
8207 IRTemp ctr_ok = newTemp(Ity_I32);
8208 IRTemp cond_ok = newTemp(Ity_I32);
8209 IRExpr* e_nia = mkSzImm(ty, nextInsnAddr());
8210 IRConst* c_nia = mkSzConst(ty, nextInsnAddr());
8211 IRTemp lr_old = newTemp(ty);
8213 /* Hack to pass through code that just wants to read the PC */
8214 if (theInstr == 0x429F0005) {
8215 DIP("bcl 0x%x, 0x%x (a.k.a mr lr,cia+4)\n", BO, BI);
8216 putGST( PPC_GST_LR, e_nia );
8217 return True;
8220 /* The default what-next. Individual cases can override it. */
8221 dres->whatNext = Dis_StopHere;
8222 vassert(dres->jk_StopHere == Ijk_INVALID);
8224 switch (opc1) {
8225 case 0x12: // b (Branch, PPC32 p360)
8226 if (flag_AA) {
8227 tgt = mkSzAddr( ty, extend_s_26to64(LI_u26) );
8228 } else {
8229 tgt = mkSzAddr( ty, guest_CIA_curr_instr +
8230 (Long)extend_s_26to64(LI_u26) );
8232 if (mode64) {
8233 DIP("b%s%s 0x%llx\n",
8234 flag_LK ? "l" : "", flag_AA ? "a" : "", tgt);
8235 } else {
8236 DIP("b%s%s 0x%x\n",
8237 flag_LK ? "l" : "", flag_AA ? "a" : "", (Addr32)tgt);
8240 if (flag_LK) {
8241 putGST( PPC_GST_LR, e_nia );
8242 if (vbi->guest_ppc_zap_RZ_at_bl
8243 && vbi->guest_ppc_zap_RZ_at_bl( (ULong)tgt) ) {
8244 IRTemp t_tgt = newTemp(ty);
8245 assign(t_tgt, mode64 ? mkU64(tgt) : mkU32(tgt) );
8246 make_redzone_AbiHint( vbi, t_tgt,
8247 "branch-and-link (unconditional call)" );
8251 dres->jk_StopHere = flag_LK ? Ijk_Call : Ijk_Boring; ;
8252 putGST( PPC_GST_CIA, mkSzImm(ty, tgt) );
8253 break;
8255 case 0x10: // bc (Branch Conditional, PPC32 p361)
8256 DIP("bc%s%s 0x%x, 0x%x, 0x%x\n",
8257 flag_LK ? "l" : "", flag_AA ? "a" : "", BO, BI, BD);
8259 if (!(BO & 0x4)) {
8260 putGST( PPC_GST_CTR,
8261 binop(mkSzOp(ty, Iop_Sub8),
8262 getGST( PPC_GST_CTR ), mkSzImm(ty, 1)) );
8265 /* This is a bit subtle. ctr_ok is either all 0s or all 1s.
8266 cond_ok is either zero or nonzero, since that's the cheapest
8267 way to compute it. Anding them together gives a value which
8268 is either zero or non zero and so that's what we must test
8269 for in the IRStmt_Exit. */
8270 assign( ctr_ok, branch_ctr_ok( BO ) );
8271 assign( cond_ok, branch_cond_ok( BO, BI ) );
8272 assign( do_branch,
8273 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
8275 if (flag_AA) {
8276 tgt = mkSzAddr(ty, extend_s_16to64(BD_u16));
8277 } else {
8278 tgt = mkSzAddr(ty, guest_CIA_curr_instr +
8279 (Long)extend_s_16to64(BD_u16));
8281 if (flag_LK)
8282 putGST( PPC_GST_LR, e_nia );
8284 stmt( IRStmt_Exit(
8285 binop(Iop_CmpNE32, mkexpr(do_branch), mkU32(0)),
8286 flag_LK ? Ijk_Call : Ijk_Boring,
8287 mkSzConst(ty, tgt), OFFB_CIA ) );
8289 dres->jk_StopHere = Ijk_Boring;
8290 putGST( PPC_GST_CIA, e_nia );
8291 break;
8293 case 0x13:
8294 /* For bclr and bcctr, it appears that the lowest two bits of
8295 b11to15 are a branch hint, and so we only need to ensure it's
8296 of the form 000XX. */
8297 if ((b11to15 & ~3) != 0) {
8298 vex_printf("dis_int_branch(ppc)(0x13,b11to15)(%d)\n", b11to15);
8299 return False;
8302 switch (opc2) {
8303 case 0x210: // bcctr (Branch Cond. to Count Register, PPC32 p363)
8304 if ((BO & 0x4) == 0) { // "decr and test CTR" option invalid
8305 vex_printf("dis_int_branch(ppc)(bcctr,BO)\n");
8306 return False;
8308 DIP("bcctr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
8310 assign( cond_ok, branch_cond_ok( BO, BI ) );
8312 /* FIXME: this is confusing. lr_old holds the old value
8313 of ctr, not lr :-) */
8314 assign( lr_old, addr_align( getGST( PPC_GST_CTR ), 4 ));
8316 if (flag_LK)
8317 putGST( PPC_GST_LR, e_nia );
8319 stmt( IRStmt_Exit(
8320 binop(Iop_CmpEQ32, mkexpr(cond_ok), mkU32(0)),
8321 Ijk_Boring,
8322 c_nia, OFFB_CIA ));
8324 if (flag_LK && vbi->guest_ppc_zap_RZ_at_bl) {
8325 make_redzone_AbiHint( vbi, lr_old,
8326 "b-ctr-l (indirect call)" );
8329 dres->jk_StopHere = flag_LK ? Ijk_Call : Ijk_Boring;;
8330 putGST( PPC_GST_CIA, mkexpr(lr_old) );
8331 break;
8333 case 0x010: { // bclr (Branch Cond. to Link Register, PPC32 p365)
8334 Bool vanilla_return = False;
8335 if ((BO & 0x14 /* 1z1zz */) == 0x14 && flag_LK == 0) {
8336 DIP("blr\n");
8337 vanilla_return = True;
8338 } else {
8339 DIP("bclr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
8342 if (!(BO & 0x4)) {
8343 putGST( PPC_GST_CTR,
8344 binop(mkSzOp(ty, Iop_Sub8),
8345 getGST( PPC_GST_CTR ), mkSzImm(ty, 1)) );
8348 /* See comments above for 'bc' about this */
8349 assign( ctr_ok, branch_ctr_ok( BO ) );
8350 assign( cond_ok, branch_cond_ok( BO, BI ) );
8351 assign( do_branch,
8352 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
8354 assign( lr_old, addr_align( getGST( PPC_GST_LR ), 4 ));
8356 if (flag_LK)
8357 putGST( PPC_GST_LR, e_nia );
8359 stmt( IRStmt_Exit(
8360 binop(Iop_CmpEQ32, mkexpr(do_branch), mkU32(0)),
8361 Ijk_Boring,
8362 c_nia, OFFB_CIA ));
8364 if (vanilla_return && vbi->guest_ppc_zap_RZ_at_blr) {
8365 make_redzone_AbiHint( vbi, lr_old,
8366 "branch-to-lr (unconditional return)" );
8369 /* blrl is pretty strange; it's like a return that sets the
8370 return address of its caller to the insn following this
8371 one. Mark it as a return. */
8372 dres->jk_StopHere = Ijk_Ret; /* was flag_LK ? Ijk_Call : Ijk_Ret; */
8373 putGST( PPC_GST_CIA, mkexpr(lr_old) );
8374 break;
8376 default:
8377 vex_printf("dis_int_branch(ppc)(opc2)\n");
8378 return False;
8380 break;
8382 default:
8383 vex_printf("dis_int_branch(ppc)(opc1)\n");
8384 return False;
8387 return True;
8391 * PC relative instruction
8393 static Bool dis_pc_relative ( UInt theInstr )
8395 /* DX-Form */
8396 UChar opc1 = ifieldOPC(theInstr);
8397 unsigned long long D;
8398 UInt d0 = IFIELD(theInstr, 6, 10);
8399 UInt d1 = IFIELD(theInstr, 16, 5);
8400 UInt d2 = IFIELD(theInstr, 0, 1);
8401 UChar rT_addr = ifieldRegDS(theInstr);
8402 UInt opc2 = ifieldOPClo5(theInstr);
8403 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8405 if ( opc1 != 0x13) {
8406 vex_printf("dis_pc_relative(ppc)(opc1)\n");
8407 return False;
8410 switch (opc2) {
8411 case 0x002: // addpcis (Add PC immediate Shifted DX-form)
8413 IRExpr* nia = mkSzImm(ty, nextInsnAddr());
8414 IRExpr* result;
8416 D = (d0 << 6) | (d1 << 1) | d2;
8417 DIP("addpcis %u,%llu\n", rT_addr, D);
8419 if ( (D & 0x8000) == 0x8000 )
8420 D = 0xFFFFFFFFFFFF0000UL | D; // sign extend
8422 if ( ty == Ity_I32 ) {
8423 result = binop( Iop_Add32, nia, mkU32( D << 16 ) );
8424 } else {
8425 vassert( ty == Ity_I64 );
8426 result = binop( Iop_Add64, nia, mkU64( D << 16 ) );
8429 putIReg( rT_addr, result);
8431 break;
8433 default:
8434 vex_printf("dis_pc_relative(ppc)(opc2)\n");
8435 return False;
8438 return True;
8442 Condition Register Logical Instructions
8444 static Bool dis_cond_logic ( UInt theInstr )
8446 /* XL-Form */
8447 UChar opc1 = ifieldOPC(theInstr);
8448 UChar crbD_addr = ifieldRegDS(theInstr);
8449 UChar crfD_addr = toUChar( IFIELD(theInstr, 23, 3) );
8450 UChar crbA_addr = ifieldRegA(theInstr);
8451 UChar crfS_addr = toUChar( IFIELD(theInstr, 18, 3) );
8452 UChar crbB_addr = ifieldRegB(theInstr);
8453 UInt opc2 = ifieldOPClo10(theInstr);
8454 UChar b0 = ifieldBIT0(theInstr);
8456 IRTemp crbD = newTemp(Ity_I32);
8457 IRTemp crbA = newTemp(Ity_I32);
8458 IRTemp crbB = newTemp(Ity_I32);
8460 if (opc1 != 19 || b0 != 0) {
8461 vex_printf("dis_cond_logic(ppc)(opc1)\n");
8462 return False;
8465 if (opc2 == 0) { // mcrf (Move Cond Reg Field, PPC32 p464)
8466 if (((crbD_addr & 0x3) != 0) ||
8467 ((crbA_addr & 0x3) != 0) || (crbB_addr != 0)) {
8468 vex_printf("dis_cond_logic(ppc)(crbD|crbA|crbB != 0)\n");
8469 return False;
8471 DIP("mcrf cr%u,cr%u\n", crfD_addr, crfS_addr);
8472 putCR0( crfD_addr, getCR0( crfS_addr) );
8473 putCR321( crfD_addr, getCR321(crfS_addr) );
8474 } else {
8475 assign( crbA, getCRbit(crbA_addr) );
8476 if (crbA_addr == crbB_addr)
8477 crbB = crbA;
8478 else
8479 assign( crbB, getCRbit(crbB_addr) );
8481 switch (opc2) {
8482 case 0x101: // crand (Cond Reg AND, PPC32 p372)
8483 DIP("crand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8484 assign( crbD, binop(Iop_And32, mkexpr(crbA), mkexpr(crbB)) );
8485 break;
8486 case 0x081: // crandc (Cond Reg AND w. Complement, PPC32 p373)
8487 DIP("crandc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8488 assign( crbD, binop(Iop_And32,
8489 mkexpr(crbA),
8490 unop(Iop_Not32, mkexpr(crbB))) );
8491 break;
8492 case 0x121: // creqv (Cond Reg Equivalent, PPC32 p374)
8493 DIP("creqv crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8494 assign( crbD, unop(Iop_Not32,
8495 binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB))) );
8496 break;
8497 case 0x0E1: // crnand (Cond Reg NAND, PPC32 p375)
8498 DIP("crnand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8499 assign( crbD, unop(Iop_Not32,
8500 binop(Iop_And32, mkexpr(crbA), mkexpr(crbB))) );
8501 break;
8502 case 0x021: // crnor (Cond Reg NOR, PPC32 p376)
8503 DIP("crnor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8504 assign( crbD, unop(Iop_Not32,
8505 binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB))) );
8506 break;
8507 case 0x1C1: // cror (Cond Reg OR, PPC32 p377)
8508 DIP("cror crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8509 assign( crbD, binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB)) );
8510 break;
8511 case 0x1A1: // crorc (Cond Reg OR w. Complement, PPC32 p378)
8512 DIP("crorc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8513 assign( crbD, binop(Iop_Or32,
8514 mkexpr(crbA),
8515 unop(Iop_Not32, mkexpr(crbB))) );
8516 break;
8517 case 0x0C1: // crxor (Cond Reg XOR, PPC32 p379)
8518 DIP("crxor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8519 assign( crbD, binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB)) );
8520 break;
8521 default:
8522 vex_printf("dis_cond_logic(ppc)(opc2)\n");
8523 return False;
8526 putCRbit( crbD_addr, mkexpr(crbD) );
8528 return True;
8533 Trap instructions
8536 /* Do the code generation for a trap. Returned Bool is true iff
8537 this is an unconditional trap. If the two arg IRExpr*s are
8538 Ity_I32s then the comparison is 32-bit. If they are Ity_I64s
8539 then they are 64-bit, and we must be disassembling 64-bit
8540 instructions. */
8541 static Bool do_trap ( UChar TO,
8542 IRExpr* argL0, IRExpr* argR0, Addr64 cia )
8544 IRTemp argL, argR;
8545 IRExpr *argLe, *argRe, *cond, *tmp;
8547 Bool is32bit = typeOfIRExpr(irsb->tyenv, argL0 ) == Ity_I32;
8549 IROp opAND = is32bit ? Iop_And32 : Iop_And64;
8550 IROp opOR = is32bit ? Iop_Or32 : Iop_Or64;
8551 IROp opCMPORDS = is32bit ? Iop_CmpORD32S : Iop_CmpORD64S;
8552 IROp opCMPORDU = is32bit ? Iop_CmpORD32U : Iop_CmpORD64U;
8553 IROp opCMPNE = is32bit ? Iop_CmpNE32 : Iop_CmpNE64;
8554 IROp opCMPEQ = is32bit ? Iop_CmpEQ32 : Iop_CmpEQ64;
8555 IRExpr* const0 = is32bit ? mkU32(0) : mkU64(0);
8556 IRExpr* const2 = is32bit ? mkU32(2) : mkU64(2);
8557 IRExpr* const4 = is32bit ? mkU32(4) : mkU64(4);
8558 IRExpr* const8 = is32bit ? mkU32(8) : mkU64(8);
8560 const UChar b11100 = 0x1C;
8561 const UChar b00111 = 0x07;
8563 if (is32bit) {
8564 vassert( typeOfIRExpr(irsb->tyenv, argL0) == Ity_I32 );
8565 vassert( typeOfIRExpr(irsb->tyenv, argR0) == Ity_I32 );
8566 } else {
8567 vassert( typeOfIRExpr(irsb->tyenv, argL0) == Ity_I64 );
8568 vassert( typeOfIRExpr(irsb->tyenv, argR0) == Ity_I64 );
8569 vassert( mode64 );
8572 if ((TO & b11100) == b11100 || (TO & b00111) == b00111) {
8573 /* Unconditional trap. Just do the exit without
8574 testing the arguments. */
8575 stmt( IRStmt_Exit(
8576 binop(opCMPEQ, const0, const0),
8577 Ijk_SigTRAP,
8578 mode64 ? IRConst_U64(cia) : IRConst_U32((UInt)cia),
8579 OFFB_CIA
8581 return True; /* unconditional trap */
8584 if (is32bit) {
8585 argL = newTemp(Ity_I32);
8586 argR = newTemp(Ity_I32);
8587 } else {
8588 argL = newTemp(Ity_I64);
8589 argR = newTemp(Ity_I64);
8592 assign( argL, argL0 );
8593 assign( argR, argR0 );
8595 argLe = mkexpr(argL);
8596 argRe = mkexpr(argR);
8598 cond = const0;
8599 if (TO & 16) { // L <s R
8600 tmp = binop(opAND, binop(opCMPORDS, argLe, argRe), const8);
8601 cond = binop(opOR, tmp, cond);
8603 if (TO & 8) { // L >s R
8604 tmp = binop(opAND, binop(opCMPORDS, argLe, argRe), const4);
8605 cond = binop(opOR, tmp, cond);
8607 if (TO & 4) { // L == R
8608 tmp = binop(opAND, binop(opCMPORDS, argLe, argRe), const2);
8609 cond = binop(opOR, tmp, cond);
8611 if (TO & 2) { // L <u R
8612 tmp = binop(opAND, binop(opCMPORDU, argLe, argRe), const8);
8613 cond = binop(opOR, tmp, cond);
8615 if (TO & 1) { // L >u R
8616 tmp = binop(opAND, binop(opCMPORDU, argLe, argRe), const4);
8617 cond = binop(opOR, tmp, cond);
8619 stmt( IRStmt_Exit(
8620 binop(opCMPNE, cond, const0),
8621 Ijk_SigTRAP,
8622 mode64 ? IRConst_U64(cia) : IRConst_U32((UInt)cia),
8623 OFFB_CIA
8625 return False; /* not an unconditional trap */
8628 static Bool dis_trapi ( UInt theInstr,
8629 /*OUT*/DisResult* dres )
8631 /* D-Form */
8632 UChar opc1 = ifieldOPC(theInstr);
8633 UChar TO = ifieldRegDS(theInstr);
8634 UChar rA_addr = ifieldRegA(theInstr);
8635 UInt uimm16 = ifieldUIMM16(theInstr);
8636 ULong simm16 = extend_s_16to64(uimm16);
8637 Addr64 cia = guest_CIA_curr_instr;
8638 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8639 Bool uncond = False;
8641 switch (opc1) {
8642 case 0x03: // twi (Trap Word Immediate, PPC32 p548)
8643 uncond = do_trap( TO,
8644 mode64 ? unop(Iop_64to32, getIReg(rA_addr))
8645 : getIReg(rA_addr),
8646 mkU32( (UInt)simm16 ),
8647 cia );
8648 if (TO == 4) {
8649 DIP("tweqi r%u,%d\n", rA_addr, (Int)simm16);
8650 } else {
8651 DIP("tw%di r%u,%d\n", TO, rA_addr, (Int)simm16);
8653 break;
8654 case 0x02: // tdi
8655 if (!mode64)
8656 return False;
8657 uncond = do_trap( TO, getIReg(rA_addr), mkU64( (ULong)simm16 ), cia );
8658 if (TO == 4) {
8659 DIP("tdeqi r%u,%d\n", rA_addr, (Int)simm16);
8660 } else {
8661 DIP("td%di r%u,%d\n", TO, rA_addr, (Int)simm16);
8663 break;
8664 default:
8665 return False;
8668 if (uncond) {
8669 /* If the trap shows signs of being unconditional, don't
8670 continue decoding past it. */
8671 putGST( PPC_GST_CIA, mkSzImm( ty, nextInsnAddr() ));
8672 dres->jk_StopHere = Ijk_Boring;
8673 dres->whatNext = Dis_StopHere;
8676 return True;
8679 static Bool dis_trap ( UInt theInstr,
8680 /*OUT*/DisResult* dres )
8682 /* X-Form */
8683 UInt opc2 = ifieldOPClo10(theInstr);
8684 UChar TO = ifieldRegDS(theInstr);
8685 UChar rA_addr = ifieldRegA(theInstr);
8686 UChar rB_addr = ifieldRegB(theInstr);
8687 Addr64 cia = guest_CIA_curr_instr;
8688 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8689 Bool uncond = False;
8691 if (ifieldBIT0(theInstr) != 0)
8692 return False;
8694 switch (opc2) {
8695 case 0x004: // tw (Trap Word, PPC64 p540)
8696 uncond = do_trap( TO,
8697 mode64 ? unop(Iop_64to32, getIReg(rA_addr))
8698 : getIReg(rA_addr),
8699 mode64 ? unop(Iop_64to32, getIReg(rB_addr))
8700 : getIReg(rB_addr),
8701 cia );
8702 if (TO == 4) {
8703 DIP("tweq r%u,r%u\n", rA_addr, rB_addr);
8704 } else {
8705 DIP("tw%d r%u,r%u\n", TO, rA_addr, rB_addr);
8707 break;
8708 case 0x044: // td (Trap Doubleword, PPC64 p534)
8709 if (!mode64)
8710 return False;
8711 uncond = do_trap( TO, getIReg(rA_addr), getIReg(rB_addr), cia );
8712 if (TO == 4) {
8713 DIP("tdeq r%u,r%u\n", rA_addr, rB_addr);
8714 } else {
8715 DIP("td%d r%u,r%u\n", TO, rA_addr, rB_addr);
8717 break;
8718 default:
8719 return False;
8722 if (uncond) {
8723 /* If the trap shows signs of being unconditional, don't
8724 continue decoding past it. */
8725 putGST( PPC_GST_CIA, mkSzImm( ty, nextInsnAddr() ));
8726 dres->jk_StopHere = Ijk_Boring;
8727 dres->whatNext = Dis_StopHere;
8730 return True;
8735 System Linkage Instructions
8737 static Bool dis_syslink ( UInt theInstr,
8738 const VexAbiInfo* abiinfo, DisResult* dres )
8740 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8742 if (theInstr != 0x44000002) {
8743 vex_printf("dis_syslink(ppc)(theInstr)\n");
8744 return False;
8747 // sc (System Call, PPC32 p504)
8748 DIP("sc\n");
8750 /* Copy CIA into the IP_AT_SYSCALL pseudo-register, so that on Darwin
8751 Valgrind can back the guest up to this instruction if it needs
8752 to restart the syscall. */
8753 putGST( PPC_GST_IP_AT_SYSCALL, getGST( PPC_GST_CIA ) );
8755 /* It's important that all ArchRegs carry their up-to-date value
8756 at this point. So we declare an end-of-block here, which
8757 forces any TempRegs caching ArchRegs to be flushed. */
8758 putGST( PPC_GST_CIA, mkSzImm( ty, nextInsnAddr() ));
8760 dres->whatNext = Dis_StopHere;
8761 dres->jk_StopHere = Ijk_Sys_syscall;
8762 return True;
8767 Memory Synchronization Instructions
8769 Note on Reservations:
8770 We rely on the assumption that V will in fact only allow one thread at
8771 once to run. In effect, a thread can make a reservation, but we don't
8772 check any stores it does. Instead, the reservation is cancelled when
8773 the scheduler switches to another thread (run_thread_for_a_while()).
8775 static Bool dis_memsync ( UInt theInstr )
8777 /* X-Form, XL-Form */
8778 UChar opc1 = ifieldOPC(theInstr);
8779 UInt b11to25 = IFIELD(theInstr, 11, 15);
8780 UChar flag_L = ifieldRegDS(theInstr);
8781 UInt b11to20 = IFIELD(theInstr, 11, 10);
8782 UInt M0 = IFIELD(theInstr, 11, 5);
8783 UChar rD_addr = ifieldRegDS(theInstr);
8784 UChar rS_addr = rD_addr;
8785 UChar rA_addr = ifieldRegA(theInstr);
8786 UChar rB_addr = ifieldRegB(theInstr);
8787 UInt opc2 = ifieldOPClo10(theInstr);
8788 UChar b0 = ifieldBIT0(theInstr);
8790 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8791 IRTemp EA = newTemp(ty);
8793 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
8795 switch (opc1) {
8796 /* XL-Form */
8797 case 0x13: // isync (Instruction Synchronize, PPC32 p432)
8798 if (opc2 != 0x096) {
8799 vex_printf("dis_memsync(ppc)(0x13,opc2)\n");
8800 return False;
8802 if (b11to25 != 0 || b0 != 0) {
8803 vex_printf("dis_memsync(ppc)(0x13,b11to25|b0)\n");
8804 return False;
8806 DIP("isync\n");
8807 stmt( IRStmt_MBE(Imbe_Fence) );
8808 break;
8810 /* X-Form */
8811 case 0x1F:
8812 switch (opc2) {
8813 case 0x356: // eieio or mbar (Enforce In-Order Exec of I/O, PPC32 p394)
8814 if (M0 == 0) {
8815 if (b11to20 != 0 || b0 != 0) {
8816 vex_printf("dis_memsync(ppc)(eieio,b11to20|b0)\n");
8817 return False;
8819 DIP("eieio\n");
8820 } else {
8821 if (b11to20 != 0 || b0 != 0) {
8822 vex_printf("dis_memsync(ppc)(mbar,b11to20|b0)\n");
8823 return False;
8825 DIP("mbar %u\n", M0);
8827 /* Insert a memory fence, just to be on the safe side. */
8828 stmt( IRStmt_MBE(Imbe_Fence) );
8829 break;
8831 case 0x014: { // lwarx (Load Word and Reserve Indexed, PPC32 p458)
8832 IRTemp res;
8833 /* According to the PowerPC ISA version 2.05, b0 (called EH
8834 in the documentation) is merely a hint bit to the
8835 hardware, I think as to whether or not contention is
8836 likely. So we can just ignore it. */
8837 DIP("lwarx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, b0);
8839 // trap if misaligned
8840 gen_SIGBUS_if_misaligned( EA, 4 );
8842 // and actually do the load
8843 res = newTemp(Ity_I32);
8844 stmt( stmt_load(res, mkexpr(EA), NULL/*this is a load*/) );
8846 putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(res), False) );
8847 break;
8850 case 0x034: { // lbarx (Load Word and Reserve Indexed)
8851 IRTemp res;
8852 /* According to the PowerPC ISA version 2.05, b0 (called EH
8853 in the documentation) is merely a hint bit to the
8854 hardware, I think as to whether or not contention is
8855 likely. So we can just ignore it. */
8856 DIP("lbarx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, b0);
8858 // and actually do the load
8859 res = newTemp(Ity_I8);
8860 stmt( stmt_load(res, mkexpr(EA), NULL/*this is a load*/) );
8862 putIReg( rD_addr, mkWidenFrom8(ty, mkexpr(res), False) );
8863 break;
8866 case 0x074: { // lharx (Load Word and Reserve Indexed)
8867 IRTemp res;
8868 /* According to the PowerPC ISA version 2.05, b0 (called EH
8869 in the documentation) is merely a hint bit to the
8870 hardware, I think as to whether or not contention is
8871 likely. So we can just ignore it. */
8872 DIP("lharx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, b0);
8874 // trap if misaligned
8875 gen_SIGBUS_if_misaligned( EA, 2 );
8877 // and actually do the load
8878 res = newTemp(Ity_I16);
8879 stmt( stmt_load(res, mkexpr(EA), NULL/*this is a load*/) );
8881 putIReg( rD_addr, mkWidenFrom16(ty, mkexpr(res), False) );
8882 break;
8885 case 0x096: {
8886 // stwcx. (Store Word Conditional Indexed, PPC32 p532)
8887 // Note this has to handle stwcx. in both 32- and 64-bit modes,
8888 // so isn't quite as straightforward as it might otherwise be.
8889 IRTemp rS = newTemp(Ity_I32);
8890 IRTemp resSC;
8891 if (b0 != 1) {
8892 vex_printf("dis_memsync(ppc)(stwcx.,b0)\n");
8893 return False;
8895 DIP("stwcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
8897 // trap if misaligned
8898 gen_SIGBUS_if_misaligned( EA, 4 );
8900 // Get the data to be stored, and narrow to 32 bits if necessary
8901 assign( rS, mkNarrowTo32(ty, getIReg(rS_addr)) );
8903 // Do the store, and get success/failure bit into resSC
8904 resSC = newTemp(Ity_I1);
8905 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS)) );
8907 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
8908 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
8909 putCR321(0, binop(Iop_Shl8, unop(Iop_1Uto8, mkexpr(resSC)), mkU8(1)));
8910 putCR0(0, getXER_SO());
8912 /* Note:
8913 If resaddr != lwarx_resaddr, CR0[EQ] is undefined, and
8914 whether rS is stored is dependent on that value. */
8915 /* So I guess we can just ignore this case? */
8916 break;
8919 case 0x2B6: {
8920 // stbcx. (Store Byte Conditional Indexed)
8921 // Note this has to handle stbcx. in both 32- and 64-bit modes,
8922 // so isn't quite as straightforward as it might otherwise be.
8923 IRTemp rS = newTemp(Ity_I8);
8924 IRTemp resSC;
8925 if (b0 != 1) {
8926 vex_printf("dis_memsync(ppc)(stbcx.,b0)\n");
8927 return False;
8929 DIP("stbcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
8931 // Get the data to be stored, and narrow to 32 bits if necessary
8932 assign( rS, mkNarrowTo8(ty, getIReg(rS_addr)) );
8934 // Do the store, and get success/failure bit into resSC
8935 resSC = newTemp(Ity_I1);
8936 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS)) );
8938 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
8939 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
8940 putCR321(0, binop(Iop_Shl8, unop(Iop_1Uto8, mkexpr(resSC)), mkU8(1)));
8941 putCR0(0, getXER_SO());
8943 /* Note:
8944 If resaddr != lbarx_resaddr, CR0[EQ] is undefined, and
8945 whether rS is stored is dependent on that value. */
8946 /* So I guess we can just ignore this case? */
8947 break;
8950 case 0x2D6: {
8951 // sthcx. (Store Word Conditional Indexed, PPC32 p532)
8952 // Note this has to handle sthcx. in both 32- and 64-bit modes,
8953 // so isn't quite as straightforward as it might otherwise be.
8954 IRTemp rS = newTemp(Ity_I16);
8955 IRTemp resSC;
8956 if (b0 != 1) {
8957 vex_printf("dis_memsync(ppc)(stwcx.,b0)\n");
8958 return False;
8960 DIP("sthcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
8962 // trap if misaligned
8963 gen_SIGBUS_if_misaligned( EA, 2 );
8965 // Get the data to be stored, and narrow to 16 bits if necessary
8966 assign( rS, mkNarrowTo16(ty, getIReg(rS_addr)) );
8968 // Do the store, and get success/failure bit into resSC
8969 resSC = newTemp(Ity_I1);
8970 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS)) );
8972 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
8973 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
8974 putCR321(0, binop(Iop_Shl8, unop(Iop_1Uto8, mkexpr(resSC)), mkU8(1)));
8975 putCR0(0, getXER_SO());
8977 /* Note:
8978 If resaddr != lharx_resaddr, CR0[EQ] is undefined, and
8979 whether rS is stored is dependent on that value. */
8980 /* So I guess we can just ignore this case? */
8981 break;
8984 case 0x256: // sync (Synchronize, PPC32 p543),
8985 // also lwsync (L==1), ptesync (L==2)
8986 /* http://sources.redhat.com/ml/binutils/2000-12/msg00311.html
8988 The PowerPC architecture used in IBM chips has expanded
8989 the sync instruction into two variants: lightweight sync
8990 and heavyweight sync. The original sync instruction is
8991 the new heavyweight sync and lightweight sync is a strict
8992 subset of the heavyweight sync functionality. This allows
8993 the programmer to specify a less expensive operation on
8994 high-end systems when the full sync functionality is not
8995 necessary.
8997 The basic "sync" mnemonic now utilizes an operand. "sync"
8998 without an operand now becomes a extended mnemonic for
8999 heavyweight sync. Processors without the lwsync
9000 instruction will not decode the L field and will perform a
9001 heavyweight sync. Everything is backward compatible.
9003 sync = sync 0
9004 lwsync = sync 1
9005 ptesync = sync 2 *** TODO - not implemented ***
9007 if (b11to20 != 0 || b0 != 0) {
9008 vex_printf("dis_memsync(ppc)(sync/lwsync,b11to20|b0)\n");
9009 return False;
9011 if (flag_L != 0/*sync*/ && flag_L != 1/*lwsync*/) {
9012 vex_printf("dis_memsync(ppc)(sync/lwsync,flag_L)\n");
9013 return False;
9015 DIP("%ssync\n", flag_L == 1 ? "lw" : "");
9016 /* Insert a memory fence. It's sometimes important that these
9017 are carried through to the generated code. */
9018 stmt( IRStmt_MBE(Imbe_Fence) );
9019 break;
9021 /* 64bit Memsync */
9022 case 0x054: { // ldarx (Load DWord and Reserve Indexed, PPC64 p473)
9023 IRTemp res;
9024 /* According to the PowerPC ISA version 2.05, b0 (called EH
9025 in the documentation) is merely a hint bit to the
9026 hardware, I think as to whether or not contention is
9027 likely. So we can just ignore it. */
9028 if (!mode64)
9029 return False;
9030 DIP("ldarx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, b0);
9032 // trap if misaligned
9033 gen_SIGBUS_if_misaligned( EA, 8 );
9035 // and actually do the load
9036 res = newTemp(Ity_I64);
9037 stmt( stmt_load( res, mkexpr(EA), NULL/*this is a load*/) );
9039 putIReg( rD_addr, mkexpr(res) );
9040 break;
9043 case 0x0D6: { // stdcx. (Store DWord Condition Indexd, PPC64 p581)
9044 // A marginally simplified version of the stwcx. case
9045 IRTemp rS = newTemp(Ity_I64);
9046 IRTemp resSC;
9047 if (b0 != 1) {
9048 vex_printf("dis_memsync(ppc)(stdcx.,b0)\n");
9049 return False;
9051 if (!mode64)
9052 return False;
9053 DIP("stdcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
9055 // trap if misaligned
9056 gen_SIGBUS_if_misaligned( EA, 8 );
9058 // Get the data to be stored
9059 assign( rS, getIReg(rS_addr) );
9061 // Do the store, and get success/failure bit into resSC
9062 resSC = newTemp(Ity_I1);
9063 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS)) );
9065 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
9066 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
9067 putCR321(0, binop(Iop_Shl8, unop(Iop_1Uto8, mkexpr(resSC)), mkU8(1)));
9068 putCR0(0, getXER_SO());
9070 /* Note:
9071 If resaddr != lwarx_resaddr, CR0[EQ] is undefined, and
9072 whether rS is stored is dependent on that value. */
9073 /* So I guess we can just ignore this case? */
9074 break;
9077 /* 128bit Memsync */
9078 case 0x114: { // lqarx (Load QuadWord and Reserve Indexed)
9079 IRTemp res_hi = newTemp(ty);
9080 IRTemp res_lo = newTemp(ty);
9082 /* According to the PowerPC ISA version 2.07, b0 (called EH
9083 in the documentation) is merely a hint bit to the
9084 hardware, I think as to whether or not contention is
9085 likely. So we can just ignore it. */
9086 DIP("lqarx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, b0);
9088 // trap if misaligned
9089 gen_SIGBUS_if_misaligned( EA, 16 );
9091 // and actually do the load
9092 if (mode64) {
9093 if (host_endness == VexEndnessBE) {
9094 stmt( stmt_load( res_hi,
9095 mkexpr(EA), NULL/*this is a load*/) );
9096 stmt( stmt_load( res_lo,
9097 binop(Iop_Add64, mkexpr(EA), mkU64(8) ),
9098 NULL/*this is a load*/) );
9099 } else {
9100 stmt( stmt_load( res_lo,
9101 mkexpr(EA), NULL/*this is a load*/) );
9102 stmt( stmt_load( res_hi,
9103 binop(Iop_Add64, mkexpr(EA), mkU64(8) ),
9104 NULL/*this is a load*/) );
9106 } else {
9107 stmt( stmt_load( res_hi,
9108 binop( Iop_Add32, mkexpr(EA), mkU32(4) ),
9109 NULL/*this is a load*/) );
9110 stmt( stmt_load( res_lo,
9111 binop( Iop_Add32, mkexpr(EA), mkU32(12) ),
9112 NULL/*this is a load*/) );
9114 putIReg( rD_addr, mkexpr(res_hi) );
9115 putIReg( rD_addr+1, mkexpr(res_lo) );
9116 break;
9119 case 0x0B6: { // stqcx. (Store QuadWord Condition Indexd, PPC64)
9120 // A marginally simplified version of the stwcx. case
9121 IRTemp rS_hi = newTemp(ty);
9122 IRTemp rS_lo = newTemp(ty);
9123 IRTemp resSC;
9124 if (b0 != 1) {
9125 vex_printf("dis_memsync(ppc)(stqcx.,b0)\n");
9126 return False;
9129 DIP("stqcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
9131 // trap if misaligned
9132 gen_SIGBUS_if_misaligned( EA, 16 );
9133 // Get the data to be stored
9134 assign( rS_hi, getIReg(rS_addr) );
9135 assign( rS_lo, getIReg(rS_addr+1) );
9137 // Do the store, and get success/failure bit into resSC
9138 resSC = newTemp(Ity_I1);
9140 if (mode64) {
9141 if (host_endness == VexEndnessBE) {
9142 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS_hi) ) );
9143 store( binop( Iop_Add64, mkexpr(EA), mkU64(8) ),
9144 mkexpr(rS_lo) );
9145 } else {
9146 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS_lo) ) );
9147 store( binop( Iop_Add64, mkexpr(EA), mkU64(8) ),
9148 mkexpr(rS_hi) );
9150 } else {
9151 stmt( stmt_load( resSC, binop( Iop_Add32,
9152 mkexpr(EA),
9153 mkU32(4) ),
9154 mkexpr(rS_hi) ) );
9155 store( binop(Iop_Add32, mkexpr(EA), mkU32(12) ), mkexpr(rS_lo) );
9158 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
9159 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
9160 putCR321(0, binop( Iop_Shl8,
9161 unop(Iop_1Uto8, mkexpr(resSC) ),
9162 mkU8(1)));
9163 putCR0(0, getXER_SO());
9164 break;
9167 default:
9168 vex_printf("dis_memsync(ppc)(opc2)\n");
9169 return False;
9171 break;
9173 default:
9174 vex_printf("dis_memsync(ppc)(opc1)\n");
9175 return False;
9177 return True;
9183 Integer Shift Instructions
9185 static Bool dis_int_shift ( UInt theInstr )
9187 /* X-Form, XS-Form */
9188 UChar opc1 = ifieldOPC(theInstr);
9189 UChar rS_addr = ifieldRegDS(theInstr);
9190 UChar rA_addr = ifieldRegA(theInstr);
9191 UChar rB_addr = ifieldRegB(theInstr);
9192 UChar sh_imm = rB_addr;
9193 UInt opc2 = ifieldOPClo10(theInstr);
9194 UChar b1 = ifieldBIT1(theInstr);
9195 UChar flag_rC = ifieldBIT0(theInstr);
9197 IRType ty = mode64 ? Ity_I64 : Ity_I32;
9198 IRTemp rA = newTemp(ty);
9199 IRTemp rS = newTemp(ty);
9200 IRTemp rB = newTemp(ty);
9201 IRTemp outofrange = newTemp(Ity_I1);
9202 IRTemp rS_lo32 = newTemp(Ity_I32);
9203 IRTemp rB_lo32 = newTemp(Ity_I32);
9204 IRExpr* e_tmp;
9206 assign( rS, getIReg(rS_addr) );
9207 assign( rB, getIReg(rB_addr) );
9208 assign( rS_lo32, mkNarrowTo32(ty, mkexpr(rS)) );
9209 assign( rB_lo32, mkNarrowTo32(ty, mkexpr(rB)) );
9211 if (opc1 == 0x1F) {
9212 switch (opc2) {
9213 case 0x018: { // slw (Shift Left Word, PPC32 p505)
9214 DIP("slw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
9215 rA_addr, rS_addr, rB_addr);
9216 /* rA = rS << rB */
9217 /* ppc32 semantics are:
9218 slw(x,y) = (x << (y & 31)) -- primary result
9219 & ~((y << 26) >>s 31) -- make result 0
9220 for y in 32 .. 63
9222 e_tmp =
9223 binop( Iop_And32,
9224 binop( Iop_Shl32,
9225 mkexpr(rS_lo32),
9226 unop( Iop_32to8,
9227 binop(Iop_And32,
9228 mkexpr(rB_lo32), mkU32(31)))),
9229 unop( Iop_Not32,
9230 binop( Iop_Sar32,
9231 binop(Iop_Shl32, mkexpr(rB_lo32), mkU8(26)),
9232 mkU8(31))) );
9233 assign( rA, mkWidenFrom32(ty, e_tmp, /* Signed */False) );
9234 break;
9237 case 0x318: { // sraw (Shift Right Alg Word, PPC32 p506)
9238 IRTemp sh_amt = newTemp(Ity_I32);
9239 DIP("sraw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
9240 rA_addr, rS_addr, rB_addr);
9241 /* JRS: my reading of the (poorly worded) PPC32 doc p506 is:
9242 amt = rB & 63
9243 rA = Sar32( rS, amt > 31 ? 31 : amt )
9244 XER.CA = amt > 31 ? sign-of-rS : (computation as per srawi)
9246 assign( sh_amt, binop(Iop_And32, mkU32(0x3F),
9247 mkexpr(rB_lo32)) );
9248 assign( outofrange,
9249 binop(Iop_CmpLT32U, mkU32(31), mkexpr(sh_amt)) );
9250 e_tmp = binop( Iop_Sar32,
9251 mkexpr(rS_lo32),
9252 unop( Iop_32to8,
9253 IRExpr_ITE( mkexpr(outofrange),
9254 mkU32(31),
9255 mkexpr(sh_amt)) ) );
9256 assign( rA, mkWidenFrom32(ty, e_tmp, /* Signed */True) );
9258 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SRAW,
9259 mkexpr(rA),
9260 mkWidenFrom32(ty, mkexpr(rS_lo32), True),
9261 mkWidenFrom32(ty, mkexpr(sh_amt), True ),
9262 mkWidenFrom32(ty, getXER_CA_32(), True) );
9263 break;
9266 case 0x338: // srawi (Shift Right Alg Word Immediate, PPC32 p507)
9267 DIP("srawi%s r%u,r%u,%d\n", flag_rC ? ".":"",
9268 rA_addr, rS_addr, sh_imm);
9269 vassert(sh_imm < 32);
9270 if (mode64) {
9271 assign( rA, binop(Iop_Sar64,
9272 binop(Iop_Shl64, getIReg(rS_addr),
9273 mkU8(32)),
9274 mkU8(32 + sh_imm)) );
9275 } else {
9276 assign( rA, binop(Iop_Sar32, mkexpr(rS_lo32),
9277 mkU8(sh_imm)) );
9280 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SRAWI,
9281 mkexpr(rA),
9282 mkWidenFrom32(ty, mkexpr(rS_lo32), /* Syned */True),
9283 mkSzImm(ty, sh_imm),
9284 mkWidenFrom32(ty, getXER_CA_32(), /* Syned */False) );
9285 break;
9287 case 0x218: // srw (Shift Right Word, PPC32 p508)
9288 DIP("srw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
9289 rA_addr, rS_addr, rB_addr);
9290 /* rA = rS >>u rB */
9291 /* ppc32 semantics are:
9292 srw(x,y) = (x >>u (y & 31)) -- primary result
9293 & ~((y << 26) >>s 31) -- make result 0
9294 for y in 32 .. 63
9296 e_tmp =
9297 binop(
9298 Iop_And32,
9299 binop( Iop_Shr32,
9300 mkexpr(rS_lo32),
9301 unop( Iop_32to8,
9302 binop(Iop_And32, mkexpr(rB_lo32),
9303 mkU32(31)))),
9304 unop( Iop_Not32,
9305 binop( Iop_Sar32,
9306 binop(Iop_Shl32, mkexpr(rB_lo32),
9307 mkU8(26)),
9308 mkU8(31))));
9309 assign( rA, mkWidenFrom32(ty, e_tmp, /* Signed */False) );
9310 break;
9313 /* 64bit Shifts */
9314 case 0x01B: // sld (Shift Left DWord, PPC64 p568)
9315 DIP("sld%s r%u,r%u,r%u\n",
9316 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
9317 /* rA = rS << rB */
9318 /* ppc64 semantics are:
9319 slw(x,y) = (x << (y & 63)) -- primary result
9320 & ~((y << 57) >>s 63) -- make result 0
9321 for y in 64 ..
9323 assign( rA,
9324 binop(
9325 Iop_And64,
9326 binop( Iop_Shl64,
9327 mkexpr(rS),
9328 unop( Iop_64to8,
9329 binop(Iop_And64, mkexpr(rB), mkU64(63)))),
9330 unop( Iop_Not64,
9331 binop( Iop_Sar64,
9332 binop(Iop_Shl64, mkexpr(rB), mkU8(57)),
9333 mkU8(63)))) );
9334 break;
9336 case 0x31A: { // srad (Shift Right Alg DWord, PPC64 p570)
9337 IRTemp sh_amt = newTemp(Ity_I64);
9338 DIP("srad%s r%u,r%u,r%u\n",
9339 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
9340 /* amt = rB & 127
9341 rA = Sar64( rS, amt > 63 ? 63 : amt )
9342 XER.CA = amt > 63 ? sign-of-rS : (computation as per srawi)
9344 assign( sh_amt, binop(Iop_And64, mkU64(0x7F), mkexpr(rB)) );
9345 assign( outofrange,
9346 binop(Iop_CmpLT64U, mkU64(63), mkexpr(sh_amt)) );
9347 assign( rA,
9348 binop( Iop_Sar64,
9349 mkexpr(rS),
9350 unop( Iop_64to8,
9351 IRExpr_ITE( mkexpr(outofrange),
9352 mkU64(63),
9353 mkexpr(sh_amt)) ))
9355 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SRAD,
9356 mkexpr(rA), mkexpr(rS), mkexpr(sh_amt),
9357 mkWidenFrom32(ty, getXER_CA_32(), /* Syned */False) );
9358 break;
9361 case 0x33A: case 0x33B: // sradi (Shr Alg DWord Imm, PPC64 p571)
9362 sh_imm |= b1<<5;
9363 vassert(sh_imm < 64);
9364 DIP("sradi%s r%u,r%u,%u\n",
9365 flag_rC ? ".":"", rA_addr, rS_addr, sh_imm);
9366 assign( rA, binop(Iop_Sar64, getIReg(rS_addr), mkU8(sh_imm)) );
9368 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SRADI,
9369 mkexpr(rA),
9370 getIReg(rS_addr),
9371 mkU64(sh_imm),
9372 mkWidenFrom32(ty, getXER_CA_32(), /* Syned */False) );
9373 break;
9375 case 0x21B: // srd (Shift Right DWord, PPC64 p574)
9376 DIP("srd%s r%u,r%u,r%u\n",
9377 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
9378 /* rA = rS >>u rB */
9379 /* ppc semantics are:
9380 srw(x,y) = (x >>u (y & 63)) -- primary result
9381 & ~((y << 57) >>s 63) -- make result 0
9382 for y in 64 .. 127
9384 assign( rA,
9385 binop(
9386 Iop_And64,
9387 binop( Iop_Shr64,
9388 mkexpr(rS),
9389 unop( Iop_64to8,
9390 binop(Iop_And64, mkexpr(rB), mkU64(63)))),
9391 unop( Iop_Not64,
9392 binop( Iop_Sar64,
9393 binop(Iop_Shl64, mkexpr(rB), mkU8(57)),
9394 mkU8(63)))) );
9395 break;
9397 default:
9398 vex_printf("dis_int_shift(ppc)(opc2)\n");
9399 return False;
9401 } else {
9402 vex_printf("dis_int_shift(ppc)(opc1)\n");
9403 return False;
9406 putIReg( rA_addr, mkexpr(rA) );
9408 if (flag_rC) {
9409 set_CR0( mkexpr(rA) );
9411 return True;
9417 Integer Load/Store Reverse Instructions
9419 /* Generates code to swap the byte order in an Ity_I32. */
9420 static IRExpr* /* :: Ity_I32 */ gen_byterev32 ( IRTemp t )
9422 vassert(typeOfIRTemp(irsb->tyenv, t) == Ity_I32);
9423 return unop(Iop_Reverse8sIn32_x1, mkexpr(t));
9426 /* Generates code to swap the byte order in the lower half of an Ity_I32,
9427 and zeroes the upper half. */
9428 static IRExpr* /* :: Ity_I32 */ gen_byterev16 ( IRTemp t )
9430 vassert(typeOfIRTemp(irsb->tyenv, t) == Ity_I32);
9431 return
9432 binop(Iop_Or32,
9433 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t), mkU8(8)),
9434 mkU32(0x0000FF00)),
9435 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t), mkU8(8)),
9436 mkU32(0x000000FF))
9440 static Bool dis_int_ldst_rev ( UInt theInstr )
9442 /* X-Form */
9443 UChar opc1 = ifieldOPC(theInstr);
9444 UChar rD_addr = ifieldRegDS(theInstr);
9445 UChar rS_addr = rD_addr;
9446 UChar rA_addr = ifieldRegA(theInstr);
9447 UChar rB_addr = ifieldRegB(theInstr);
9448 UInt opc2 = ifieldOPClo10(theInstr);
9449 UChar b0 = ifieldBIT0(theInstr);
9451 IRType ty = mode64 ? Ity_I64 : Ity_I32;
9452 IRTemp EA = newTemp(ty);
9453 IRTemp w1 = newTemp(Ity_I32);
9454 IRTemp w2 = newTemp(Ity_I32);
9456 if (opc1 != 0x1F || b0 != 0) {
9457 vex_printf("dis_int_ldst_rev(ppc)(opc1|b0)\n");
9458 return False;
9461 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
9463 switch (opc2) {
9465 case 0x316: // lhbrx (Load Halfword Byte-Reverse Indexed, PPC32 p449)
9466 DIP("lhbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
9467 assign( w1, unop(Iop_16Uto32, load(Ity_I16, mkexpr(EA))) );
9468 assign( w2, gen_byterev16(w1) );
9469 putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(w2),
9470 /* Signed */False) );
9471 break;
9473 case 0x216: // lwbrx (Load Word Byte-Reverse Indexed, PPC32 p459)
9474 DIP("lwbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
9475 assign( w1, load(Ity_I32, mkexpr(EA)) );
9476 assign( w2, gen_byterev32(w1) );
9477 putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(w2),
9478 /* Signed */False) );
9479 break;
9481 case 0x214: // ldbrx (Load Doubleword Byte-Reverse Indexed)
9483 /* Caller makes sure we are only called in mode64. */
9485 /* If we supported swapping LE/BE loads in the backend then we could
9486 just load the value with the bytes reversed by doing a BE load
9487 on an LE machine and a LE load on a BE machine.
9489 IRTemp dw1 = newTemp(Ity_I64);
9490 if (host_endness == VexEndnessBE)
9491 assign( dw1, IRExpr_Load(Iend_LE, Ity_I64, mkexpr(EA)));
9492 else
9493 assign( dw1, IRExpr_Load(Iend_BE, Ity_I64, mkexpr(EA)));
9494 putIReg( rD_addr, mkexpr(dw1) );
9496 But since we currently don't we load the value as is and then
9497 switch it around with Iop_Reverse8sIn64_x1. */
9499 IRTemp dw1 = newTemp(Ity_I64);
9500 IRTemp dw2 = newTemp(Ity_I64);
9501 DIP("ldbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
9502 assign( dw1, load(Ity_I64, mkexpr(EA)) );
9503 assign( dw2, unop(Iop_Reverse8sIn64_x1, mkexpr(dw1)) );
9504 putIReg( rD_addr, mkexpr(dw2) );
9505 break;
9508 case 0x396: // sthbrx (Store Half Word Byte-Reverse Indexed, PPC32 p523)
9509 DIP("sthbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
9510 assign( w1, mkNarrowTo32(ty, getIReg(rS_addr)) );
9511 store( mkexpr(EA), unop(Iop_32to16, gen_byterev16(w1)) );
9512 break;
9514 case 0x296: // stwbrx (Store Word Byte-Reverse Indxd, PPC32 p531)
9515 DIP("stwbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
9516 assign( w1, mkNarrowTo32(ty, getIReg(rS_addr)) );
9517 store( mkexpr(EA), gen_byterev32(w1) );
9518 break;
9520 case 0x294: // stdbrx (Store Doubleword Byte-Reverse Indexed)
9522 IRTemp lo = newTemp(Ity_I32);
9523 IRTemp hi = newTemp(Ity_I32);
9524 IRTemp rS = newTemp(Ity_I64);
9525 assign( rS, getIReg( rS_addr ) );
9526 DIP("stdbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
9527 assign(lo, unop(Iop_64HIto32, mkexpr(rS)));
9528 assign(hi, unop(Iop_64to32, mkexpr(rS)));
9529 store( mkexpr( EA ),
9530 binop( Iop_32HLto64, gen_byterev32( hi ),
9531 gen_byterev32( lo ) ) );
9532 break;
9535 default:
9536 vex_printf("dis_int_ldst_rev(ppc)(opc2)\n");
9537 return False;
9539 return True;
9545 Processor Control Instructions
9547 static Bool dis_proc_ctl ( const VexAbiInfo* vbi, UInt theInstr )
9549 UChar opc1 = ifieldOPC(theInstr);
9551 /* X-Form */
9552 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
9553 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
9554 UChar rD_addr = ifieldRegDS(theInstr);
9555 UInt b11to20 = IFIELD( theInstr, 11, 10 );
9557 /* XFX-Form */
9558 UChar rS_addr = rD_addr;
9559 UInt SPR = b11to20;
9560 UInt TBR = b11to20;
9561 UChar b20 = toUChar( IFIELD( theInstr, 20, 1 ) );
9562 UInt CRM = IFIELD( theInstr, 12, 8 );
9563 UChar b11 = toUChar( IFIELD( theInstr, 11, 1 ) );
9565 UInt opc2 = ifieldOPClo10(theInstr);
9566 UChar b0 = ifieldBIT0(theInstr);
9568 IRType ty = mode64 ? Ity_I64 : Ity_I32;
9569 IRTemp rS = newTemp(ty);
9570 assign( rS, getIReg(rS_addr) );
9572 /* Reorder SPR field as per PPC32 p470 */
9573 SPR = ((SPR & 0x1F) << 5) | ((SPR >> 5) & 0x1F);
9574 /* Reorder TBR field as per PPC32 p475 */
9575 TBR = ((TBR & 31) << 5) | ((TBR >> 5) & 31);
9577 /* b0 = 0, inst is treated as floating point inst for reservation purposes
9578 * b0 = 1, inst is treated as vector inst for reservation purposes
9580 if (opc1 != 0x1F) {
9581 vex_printf("dis_proc_ctl(ppc)(opc1|b%d)\n", b0);
9582 return False;
9585 switch (opc2) {
9586 /* X-Form */
9587 case 0x200: { // mcrxr (Move to Cond Register from XER, PPC32 p466)
9588 if (b21to22 != 0 || b11to20 != 0) {
9589 vex_printf("dis_proc_ctl(ppc)(mcrxr,b21to22|b11to20)\n");
9590 return False;
9592 DIP("mcrxr crf%d\n", crfD);
9593 /* Move XER[0-3] (the top 4 bits of XER) to CR[crfD] */
9594 putGST_field( PPC_GST_CR,
9595 getGST_field( PPC_GST_XER, 7 ),
9596 crfD );
9598 // Clear XER[0-3]
9599 putXER_SO( mkU8(0) );
9600 putXER_OV( mkU8(0) );
9601 putXER_CA( mkU8(0) );
9602 break;
9605 case 0x013:
9606 // b11to20==0: mfcr (Move from Cond Register, PPC32 p467)
9607 // b20==1 & b11==0: mfocrf (Move from One CR Field)
9608 // However it seems that the 'mfcr' behaviour is an acceptable
9609 // implementation of mfocr (from the 2.02 arch spec)
9610 if (b11to20 == 0) {
9611 DIP("mfcr r%u\n", rD_addr);
9612 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_CR ),
9613 /* Signed */False) );
9614 break;
9616 if (b20 == 1 && b11 == 0) {
9617 DIP("mfocrf r%u,%u\n", rD_addr, CRM);
9618 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_CR ),
9619 /* Signed */False) );
9620 break;
9622 /* not decodable */
9623 return False;
9625 /* XFX-Form */
9626 case 0x153: // mfspr (Move from Special-Purpose Register, PPC32 p470)
9628 switch (SPR) { // Choose a register...
9629 case 0x1:
9630 DIP("mfxer r%u\n", rD_addr);
9631 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_XER ),
9632 /* Signed */False) );
9633 break;
9634 case 0x3: // 131
9635 DIP("mfspr r%u (DSCR)\n", rD_addr);
9636 putIReg( rD_addr, getGST( PPC_GST_DSCR) );
9637 break;
9638 case 0x8:
9639 DIP("mflr r%u\n", rD_addr);
9640 putIReg( rD_addr, getGST( PPC_GST_LR ) );
9641 break;
9642 case 0x9:
9643 DIP("mfctr r%u\n", rD_addr);
9644 putIReg( rD_addr, getGST( PPC_GST_CTR ) );
9645 break;
9646 case 0x80: // 128
9647 DIP("mfspr r%u (TFHAR)\n", rD_addr);
9648 putIReg( rD_addr, getGST( PPC_GST_TFHAR) );
9649 break;
9650 case 0x81: // 129
9651 DIP("mfspr r%u (TFIAR)\n", rD_addr);
9652 putIReg( rD_addr, getGST( PPC_GST_TFIAR) );
9653 break;
9654 case 0x82: // 130
9655 DIP("mfspr r%u (TEXASR)\n", rD_addr);
9656 putIReg( rD_addr, getGST( PPC_GST_TEXASR) );
9657 break;
9658 case 0x83: // 131
9659 DIP("mfspr r%u (TEXASRU)\n", rD_addr);
9660 putIReg( rD_addr, getGST( PPC_GST_TEXASRU) );
9661 break;
9662 case 0x9F: // 159
9663 DIP("mfspr r%u (PSPB)\n", rD_addr);
9664 putIReg( rD_addr, getGST( PPC_GST_PSPB) );
9665 break;
9666 case 0x380: // 896
9667 DIP("mfspr r%u (PPR)\n", rD_addr);
9668 putIReg( rD_addr, getGST( PPC_GST_PPR) );
9669 break;
9670 case 0x382: // 898
9671 DIP("mfspr r%u (PPR)32\n", rD_addr);
9672 putIReg( rD_addr, getGST( PPC_GST_PPR32) );
9673 break;
9674 case 0x100:
9675 DIP("mfvrsave r%u\n", rD_addr);
9676 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_VRSAVE ),
9677 /* Signed */False) );
9678 break;
9680 case 0x103:
9681 DIP("mfspr r%u, SPRG3(readonly)\n", rD_addr);
9682 putIReg( rD_addr, getGST( PPC_GST_SPRG3_RO ) );
9683 break;
9685 case 268 /* 0x10C TB - 64 bit time base register */:
9687 IRTemp val = newTemp(Ity_I64);
9688 IRExpr** args = mkIRExprVec_0();
9689 IRDirty* d = unsafeIRDirty_1_N(
9690 val,
9691 0/*regparms*/,
9692 "ppcg_dirtyhelper_MFTB",
9693 fnptr_to_fnentry(vbi,
9694 &ppcg_dirtyhelper_MFTB),
9695 args );
9696 /* execute the dirty call, dumping the result in val. */
9697 stmt( IRStmt_Dirty(d) );
9698 putIReg( rD_addr, (mode64) ? mkexpr(val) :
9699 unop(Iop_64to32, mkexpr(val)) );
9701 break;
9703 case 269 /* 0x10D TBU - upper 32-bits of time base register */:
9705 DIP("mfspr r%u,%u", rD_addr, SPR);
9706 IRTemp val = newTemp(Ity_I64);
9707 IRExpr** args = mkIRExprVec_0();
9708 IRDirty* d = unsafeIRDirty_1_N(
9709 val,
9710 0/*regparms*/,
9711 "ppcg_dirtyhelper_MFTB",
9712 fnptr_to_fnentry(vbi,
9713 &ppcg_dirtyhelper_MFTB),
9714 args );
9715 /* execute the dirty call, dumping the result in val. */
9716 stmt( IRStmt_Dirty(d) );
9717 putIReg( rD_addr,
9718 mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(val)),
9719 /* Signed */False) );
9720 break;
9722 case 284 /* 0x1 TBL - lower 32-bits of time base register */:
9724 DIP("mfspr r%u,%u", rD_addr, SPR);
9725 IRTemp val = newTemp(Ity_I64);
9726 IRExpr** args = mkIRExprVec_0();
9727 IRDirty* d = unsafeIRDirty_1_N(
9728 val,
9729 0/*regparms*/,
9730 "ppcg_dirtyhelper_MFTB",
9731 fnptr_to_fnentry(vbi,
9732 &ppcg_dirtyhelper_MFTB),
9733 args );
9734 /* execute the dirty call, dumping the result in val. */
9735 stmt( IRStmt_Dirty(d) );
9736 putIReg( rD_addr,
9737 mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(val)),
9738 /* Signed */False) );
9739 break;
9742 /* Again, runs natively on PPC7400 (7447, really). Not
9743 bothering with a feature test. */
9744 case 287: /* 0x11F */ {
9745 IRTemp val = newTemp(Ity_I32);
9746 IRExpr** args = mkIRExprVec_0();
9747 IRDirty* d = unsafeIRDirty_1_N(
9748 val,
9749 0/*regparms*/,
9750 "ppc32g_dirtyhelper_MFSPR_287",
9751 fnptr_to_fnentry
9752 (vbi, &ppc32g_dirtyhelper_MFSPR_287),
9753 args
9755 /* execute the dirty call, dumping the result in val. */
9756 stmt( IRStmt_Dirty(d) );
9757 putIReg( rD_addr,
9758 mkWidenFrom32(ty, mkexpr(val), False/*unsigned*/) );
9759 DIP("mfspr r%u,%u", rD_addr, SPR);
9760 break;
9763 default:
9764 vex_printf("dis_proc_ctl(ppc)(mfspr,SPR)(0x%x)\n", SPR);
9765 return False;
9767 break;
9769 case 0x173: { // mftb (Move from Time Base, PPC32 p475)
9770 IRTemp val = newTemp(Ity_I64);
9771 IRExpr** args = mkIRExprVec_0();
9772 IRDirty* d = unsafeIRDirty_1_N(
9773 val,
9774 0/*regparms*/,
9775 "ppcg_dirtyhelper_MFTB",
9776 fnptr_to_fnentry(vbi, &ppcg_dirtyhelper_MFTB),
9777 args );
9778 /* execute the dirty call, dumping the result in val. */
9779 stmt( IRStmt_Dirty(d) );
9781 switch (TBR) {
9782 case 269:
9783 DIP("mftbu r%u", rD_addr);
9784 putIReg( rD_addr,
9785 mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(val)),
9786 /* Signed */False) );
9787 break;
9788 case 268:
9789 DIP("mftb r%u", rD_addr);
9790 putIReg( rD_addr, (mode64) ? mkexpr(val) :
9791 unop(Iop_64to32, mkexpr(val)) );
9792 break;
9793 case 284:
9794 DIP("mftbl r%u", rD_addr);
9795 putIReg( rD_addr,
9796 mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(val)),
9797 /* Signed */False) );
9798 break;
9799 default:
9800 return False; /* illegal instruction */
9802 break;
9805 case 0x090: {
9806 // b20==0: mtcrf (Move to Cond Register Fields, PPC32 p477)
9807 // b20==1: mtocrf (Move to One Cond Reg Field)
9808 Int cr;
9809 UChar shft;
9810 if (b11 != 0)
9811 return False;
9812 if (b20 == 1) {
9813 /* ppc64 v2.02 spec says mtocrf gives undefined outcome if >
9814 1 field is written. It seems more robust to decline to
9815 decode the insn if so. */
9816 switch (CRM) {
9817 case 0x01: case 0x02: case 0x04: case 0x08:
9818 case 0x10: case 0x20: case 0x40: case 0x80:
9819 break;
9820 default:
9821 return False;
9824 DIP("%s 0x%x,r%u\n", b20==1 ? "mtocrf" : "mtcrf",
9825 CRM, rS_addr);
9826 /* Write to each field specified by CRM */
9827 for (cr = 0; cr < 8; cr++) {
9828 if ((CRM & (1 << (7-cr))) == 0)
9829 continue;
9830 shft = 4*(7-cr);
9831 putGST_field( PPC_GST_CR,
9832 binop(Iop_Shr32,
9833 mkNarrowTo32(ty, mkexpr(rS)),
9834 mkU8(shft)), cr );
9836 break;
9839 case 0x1D3: // mtspr (Move to Special-Purpose Register, PPC32 p483)
9841 switch (SPR) { // Choose a register...
9842 case 0x1:
9843 DIP("mtxer r%u\n", rS_addr);
9844 putGST( PPC_GST_XER, mkNarrowTo32(ty, mkexpr(rS)) );
9845 break;
9846 case 0x3:
9847 DIP("mtspr r%u (DSCR)\n", rS_addr);
9848 putGST( PPC_GST_DSCR, mkexpr(rS) );
9849 break;
9850 case 0x8:
9851 DIP("mtlr r%u\n", rS_addr);
9852 putGST( PPC_GST_LR, mkexpr(rS) );
9853 break;
9854 case 0x9:
9855 DIP("mtctr r%u\n", rS_addr);
9856 putGST( PPC_GST_CTR, mkexpr(rS) );
9857 break;
9858 case 0x100:
9859 DIP("mtvrsave r%u\n", rS_addr);
9860 putGST( PPC_GST_VRSAVE, mkNarrowTo32(ty, mkexpr(rS)) );
9861 break;
9862 case 0x80: // 128
9863 DIP("mtspr r%u (TFHAR)\n", rS_addr);
9864 putGST( PPC_GST_TFHAR, mkexpr(rS) );
9865 break;
9866 case 0x81: // 129
9867 DIP("mtspr r%u (TFIAR)\n", rS_addr);
9868 putGST( PPC_GST_TFIAR, mkexpr(rS) );
9869 break;
9870 case 0x82: // 130
9871 DIP("mtspr r%u (TEXASR)\n", rS_addr);
9872 putGST( PPC_GST_TEXASR, mkexpr(rS) );
9873 break;
9874 case 0x9F: // 159
9875 DIP("mtspr r%u (PSPB)\n", rS_addr);
9876 putGST( PPC_GST_PSPB, mkexpr(rS) );
9877 break;
9878 case 0x380: // 896
9879 DIP("mtspr r%u (PPR)\n", rS_addr);
9880 putGST( PPC_GST_PPR, mkexpr(rS) );
9881 break;
9882 case 0x382: // 898
9883 DIP("mtspr r%u (PPR32)\n", rS_addr);
9884 putGST( PPC_GST_PPR32, mkexpr(rS) );
9885 break;
9886 default:
9887 vex_printf("dis_proc_ctl(ppc)(mtspr,SPR)(%u)\n", SPR);
9888 return False;
9890 break;
9892 case 0x33: // mfvsrd
9894 UChar XS = ifieldRegXS( theInstr );
9895 UChar rA_addr = ifieldRegA(theInstr);
9896 IRExpr * high64;
9897 IRTemp vS = newTemp( Ity_V128 );
9898 DIP("mfvsrd r%u,vsr%d\n", rA_addr, XS);
9900 /* XS = SX || S
9901 * For SX=0, mfvsrd is treated as a Floating-Point
9902 * instruction in terms of resource availability.
9903 * For SX=1, mfvsrd is treated as a Vector instruction in
9904 * terms of resource availability.
9905 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
9907 assign( vS, getVSReg( XS ) );
9908 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
9909 putIReg( rA_addr, (mode64) ? high64 :
9910 unop( Iop_64to32, high64 ) );
9911 break;
9914 case 0x73: // mfvsrwz
9916 UChar XS = ifieldRegXS( theInstr );
9917 UChar rA_addr = ifieldRegA(theInstr);
9918 IRExpr * high64;
9919 IRTemp vS = newTemp( Ity_V128 );
9920 DIP("mfvsrwz r%u,vsr%d\n", rA_addr, XS);
9921 /* XS = SX || S
9922 * For SX=0, mfvsrwz is treated as a Floating-Point
9923 * instruction in terms of resource availability.
9924 * For SX=1, mfvsrwz is treated as a Vector instruction in
9925 * terms of resource availability.
9926 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
9929 assign( vS, getVSReg( XS ) );
9930 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
9931 /* move value to the destination setting the upper 32-bits to zero */
9932 putIReg( rA_addr, (mode64) ?
9933 binop( Iop_And64, high64, mkU64( 0xFFFFFFFF ) ) :
9934 unop( Iop_64to32,
9935 binop( Iop_And64, high64, mkU64( 0xFFFFFFFF ) ) ) );
9936 break;
9939 case 0xB3: // mtvsrd
9941 UChar XT = ifieldRegXT( theInstr );
9942 UChar rA_addr = ifieldRegA(theInstr);
9943 IRTemp rA = newTemp(ty);
9944 DIP("mtvsrd vsr%d,r%u\n", XT, rA_addr);
9945 /* XS = SX || S
9946 * For SX=0, mfvsrd is treated as a Floating-Point
9947 * instruction in terms of resource availability.
9948 * For SX=1, mfvsrd is treated as a Vector instruction in
9949 * terms of resource availability.
9950 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
9952 assign( rA, getIReg(rA_addr) );
9954 if (mode64)
9955 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( rA ), mkU64( 0 ) ) );
9956 else
9957 putVSReg( XT, binop( Iop_64HLtoV128,
9958 binop( Iop_32HLto64,
9959 mkU32( 0 ),
9960 mkexpr( rA ) ),
9961 mkU64( 0 ) ) );
9962 break;
9965 case 0xD3: // mtvsrwa
9967 UChar XT = ifieldRegXT( theInstr );
9968 UChar rA_addr = ifieldRegA(theInstr);
9969 IRTemp rA = newTemp( Ity_I32 );
9970 DIP("mtvsrwa vsr%d,r%u\n", XT, rA_addr);
9971 /* XS = SX || S
9972 * For SX=0, mtvsrwa is treated as a Floating-Point
9973 * instruction in terms of resource availability.
9974 * For SX=1, mtvsrwa is treated as a Vector instruction in
9975 * terms of resource availability.
9976 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
9978 if (mode64)
9979 assign( rA, unop( Iop_64to32, getIReg( rA_addr ) ) );
9980 else
9981 assign( rA, getIReg(rA_addr) );
9983 putVSReg( XT, binop( Iop_64HLtoV128,
9984 unop( Iop_32Sto64, mkexpr( rA ) ),
9985 mkU64( 0 ) ) );
9986 break;
9989 case 0xF3: // mtvsrwz
9991 UChar XT = ifieldRegXT( theInstr );
9992 UChar rA_addr = ifieldRegA(theInstr);
9993 IRTemp rA = newTemp( Ity_I32 );
9994 DIP("mtvsrwz vsr%d,r%u\n", rA_addr, XT);
9995 /* XS = SX || S
9996 * For SX=0, mtvsrwz is treated as a Floating-Point
9997 * instruction in terms of resource availability.
9998 * For SX=1, mtvsrwz is treated as a Vector instruction in
9999 * terms of resource availability.
10000 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
10002 if (mode64)
10003 assign( rA, unop( Iop_64to32, getIReg( rA_addr ) ) );
10004 else
10005 assign( rA, getIReg(rA_addr) );
10007 putVSReg( XT, binop( Iop_64HLtoV128,
10008 binop( Iop_32HLto64, mkU32( 0 ), mkexpr ( rA ) ),
10009 mkU64( 0 ) ) );
10010 break;
10013 default:
10014 vex_printf("dis_proc_ctl(ppc)(opc2)\n");
10015 return False;
10017 return True;
10022 Cache Management Instructions
10024 static Bool dis_cache_manage ( UInt theInstr,
10025 DisResult* dres,
10026 const VexArchInfo* guest_archinfo )
10028 /* X-Form */
10029 UChar opc1 = ifieldOPC(theInstr);
10030 UChar b21to25 = ifieldRegDS(theInstr);
10031 UChar rA_addr = ifieldRegA(theInstr);
10032 UChar rB_addr = ifieldRegB(theInstr);
10033 UInt opc2 = ifieldOPClo10(theInstr);
10034 UChar b0 = ifieldBIT0(theInstr);
10035 UInt lineszB = guest_archinfo->ppc_icache_line_szB;
10036 Bool is_dcbzl = False;
10038 IRType ty = mode64 ? Ity_I64 : Ity_I32;
10040 // Check for valid hint values for dcbt and dcbtst as currently described in
10041 // ISA 2.07. If valid, then we simply set b21to25 to zero since we have no
10042 // means of modeling the hint anyway.
10043 if (opc1 == 0x1F && ((opc2 == 0x116) || (opc2 == 0xF6))) {
10044 if (b21to25 == 0x10 || b21to25 < 0x10)
10045 b21to25 = 0;
10047 if (opc1 == 0x1F && opc2 == 0x116 && b21to25 == 0x11)
10048 b21to25 = 0;
10050 if (opc1 == 0x1F && opc2 == 0x3F6) { // dcbz
10051 if (b21to25 == 1) {
10052 is_dcbzl = True;
10053 b21to25 = 0;
10054 if (!(guest_archinfo->ppc_dcbzl_szB)) {
10055 vex_printf("dis_cache_manage(ppc)(dcbzl not supported by host)\n");
10056 return False;
10061 if (opc1 != 0x1F || b0 != 0) {
10062 if (0) vex_printf("dis_cache_manage %d %d\n",
10063 opc1, b0);
10064 vex_printf("dis_cache_manage(ppc)(opc1|b0)\n");
10065 return False;
10068 /* stay sane .. */
10069 vassert(lineszB == 16 || lineszB == 32 || lineszB == 64 || lineszB == 128);
10071 switch (opc2) {
10072 //zz case 0x2F6: // dcba (Data Cache Block Allocate, PPC32 p380)
10073 //zz vassert(0); /* AWAITING TEST CASE */
10074 //zz DIP("dcba r%u,r%u\n", rA_addr, rB_addr);
10075 //zz if (0) vex_printf("vex ppc->IR: kludged dcba\n");
10076 //zz break;
10078 case 0x056: // dcbf (Data Cache Block Flush, PPC32 p382)
10079 DIP("dcbf r%u,r%u\n", rA_addr, rB_addr);
10080 /* nop as far as vex is concerned */
10081 break;
10083 case 0x036: // dcbst (Data Cache Block Store, PPC32 p384)
10084 DIP("dcbst r%u,r%u\n", rA_addr, rB_addr);
10085 /* nop as far as vex is concerned */
10086 break;
10088 case 0x116: // dcbt (Data Cache Block Touch, PPC32 p385)
10089 DIP("dcbt r%u,r%u\n", rA_addr, rB_addr);
10090 /* nop as far as vex is concerned */
10091 break;
10093 case 0x0F6: // dcbtst (Data Cache Block Touch for Store, PPC32 p386)
10094 DIP("dcbtst r%u,r%u\n", rA_addr, rB_addr);
10095 /* nop as far as vex is concerned */
10096 break;
10098 case 0x3F6: { // dcbz (Data Cache Block Clear to Zero, PPC32 p387)
10099 // dcbzl (Data Cache Block Clear to Zero Long, bug#135264)
10100 /* Clear all bytes in cache block at (rA|0) + rB. */
10101 IRTemp EA = newTemp(ty);
10102 IRTemp addr = newTemp(ty);
10103 IRExpr* irx_addr;
10104 UInt i;
10105 UInt clearszB;
10106 if (is_dcbzl) {
10107 clearszB = guest_archinfo->ppc_dcbzl_szB;
10108 DIP("dcbzl r%u,r%u\n", rA_addr, rB_addr);
10110 else {
10111 clearszB = guest_archinfo->ppc_dcbz_szB;
10112 DIP("dcbz r%u,r%u\n", rA_addr, rB_addr);
10115 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
10117 if (mode64) {
10118 /* Round EA down to the start of the containing block. */
10119 assign( addr, binop( Iop_And64,
10120 mkexpr(EA),
10121 mkU64( ~((ULong)clearszB-1) )) );
10123 for (i = 0; i < clearszB / 8; i++) {
10124 irx_addr = binop( Iop_Add64, mkexpr(addr), mkU64(i*8) );
10125 store( irx_addr, mkU64(0) );
10127 } else {
10128 /* Round EA down to the start of the containing block. */
10129 assign( addr, binop( Iop_And32,
10130 mkexpr(EA),
10131 mkU32( ~(clearszB-1) )) );
10133 for (i = 0; i < clearszB / 4; i++) {
10134 irx_addr = binop( Iop_Add32, mkexpr(addr), mkU32(i*4) );
10135 store( irx_addr, mkU32(0) );
10138 break;
10141 case 0x3D6: {
10142 // icbi (Instruction Cache Block Invalidate, PPC32 p431)
10143 /* Invalidate all translations containing code from the cache
10144 block at (rA|0) + rB. */
10145 IRTemp EA = newTemp(ty);
10146 IRTemp addr = newTemp(ty);
10147 DIP("icbi r%u,r%u\n", rA_addr, rB_addr);
10148 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
10150 /* Round EA down to the start of the containing block. */
10151 assign( addr, binop( mkSzOp(ty, Iop_And8),
10152 mkexpr(EA),
10153 mkSzImm(ty, ~(((ULong)lineszB)-1) )) );
10154 putGST( PPC_GST_CMSTART, mkexpr(addr) );
10155 putGST( PPC_GST_CMLEN, mkSzImm(ty, lineszB) );
10157 /* be paranoid ... */
10158 stmt( IRStmt_MBE(Imbe_Fence) );
10160 putGST( PPC_GST_CIA, mkSzImm(ty, nextInsnAddr()));
10161 dres->jk_StopHere = Ijk_InvalICache;
10162 dres->whatNext = Dis_StopHere;
10163 break;
10166 default:
10167 vex_printf("dis_cache_manage(ppc)(opc2)\n");
10168 return False;
10170 return True;
10174 /*------------------------------------------------------------*/
10175 /*--- Floating Point Helpers ---*/
10176 /*------------------------------------------------------------*/
10178 /* --------- Synthesise a 2-bit FPU rounding mode. --------- */
10179 /* Produces a value in 0 .. 3, which is encoded as per the type
10180 IRRoundingMode. PPCRoundingMode encoding is different to
10181 IRRoundingMode, so need to map it.
10184 static IRExpr* /* :: Ity_I32 */ set_round_to_Oddmode ( void )
10186 /* PPC/ valgrind have two-bits to designate the rounding mode.
10187 ISA 3.0 adds instructions than can use a round to odd mode
10188 but did not change the number of bits for the rm. Basically,
10189 they added two instructions that only differ by the rounding
10190 mode the operation uses. In essesce, they encoded the rm
10191 in the name. In order to avoid having to create Iops, that
10192 encode the rm in th name, we will "expand" the definition of
10193 the rounding mode bits. We will just pass the rm and then
10194 map the to odd mode to the appropriate PPCFpOp name that
10195 will tell us which instruction to map to.
10197 rounding mode | PPC | IR
10198 ------------------------
10199 to nearest | 000 | 00
10200 to zero | 001 | 11
10201 to +infinity | 010 | 10
10202 to -infinity | 011 | 01
10203 to odd | 1xx | xx
10205 return mkU32(8);
10208 static IRExpr* /* :: Ity_I32 */ get_IR_roundingmode ( void )
10211 rounding mode | PPC | IR
10212 ------------------------
10213 to nearest | 00 | 00
10214 to zero | 01 | 11
10215 to +infinity | 10 | 10
10216 to -infinity | 11 | 01
10218 IRTemp rm_PPC32 = newTemp(Ity_I32);
10219 assign( rm_PPC32, getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN ) );
10221 // rm_IR = XOR( rm_PPC32, (rm_PPC32 << 1) & 2)
10222 return binop( Iop_Xor32,
10223 mkexpr(rm_PPC32),
10224 binop( Iop_And32,
10225 binop(Iop_Shl32, mkexpr(rm_PPC32), mkU8(1)),
10226 mkU32(2) ));
10229 /* The DFP IR rounding modes were chosen such that the existing PPC to IR
10230 * mapping would still work with the extended three bit DFP rounding
10231 * mode designator.
10233 * rounding mode | PPC | IR
10234 * -----------------------------------------------
10235 * to nearest, ties to even | 000 | 000
10236 * to zero | 001 | 011
10237 * to +infinity | 010 | 010
10238 * to -infinity | 011 | 001
10239 * to nearest, ties away from 0 | 100 | 100
10240 * to nearest, ties toward 0 | 101 | 111
10241 * to away from 0 | 110 | 110
10242 * to prepare for shorter precision | 111 | 101
10244 static IRExpr* /* :: Ity_I32 */ get_IR_roundingmode_DFP( void )
10246 IRTemp rm_PPC32 = newTemp( Ity_I32 );
10247 assign( rm_PPC32, getGST_masked_upper( PPC_GST_FPSCR, MASK_FPSCR_DRN ) );
10249 // rm_IR = XOR( rm_PPC32, (rm_PPC32 << 1) & 2)
10250 return binop( Iop_Xor32,
10251 mkexpr( rm_PPC32 ),
10252 binop( Iop_And32,
10253 binop( Iop_Shl32, mkexpr( rm_PPC32 ), mkU8( 1 ) ),
10254 mkU32( 2 ) ) );
10257 #define NANmaskSingle 0x7F800000
10258 #define NANmaskDouble 0x7FF00000
10260 static IRExpr * Check_NaN( IRExpr * value, IRExpr * Hi32Mask )
10262 IRTemp exp_zero = newTemp(Ity_I8);
10263 IRTemp frac_mask = newTemp(Ity_I32);
10264 IRTemp frac_not_zero = newTemp(Ity_I8);
10266 /* Check if the result is QNAN or SNAN and not +infinity or -infinity.
10267 * The input value is always 64-bits, for single precision values, the
10268 * lower 32 bits must be zero.
10270 * Single Pricision
10271 * [62:54] exponent field is equal to 0xFF for NAN and Infinity.
10272 * [53:32] fraction field is zero for Infinity and non-zero for NAN
10273 * [31:0] unused for single precision representation
10275 * Double Pricision
10276 * [62:51] exponent field is equal to 0xFF for NAN and Infinity.
10277 * [50:0] fraction field is zero for Infinity and non-zero for NAN
10279 * Returned result is a U32 value of 0xFFFFFFFF for NaN and 0 otherwise.
10281 assign( frac_mask, unop( Iop_Not32,
10282 binop( Iop_Or32,
10283 mkU32( 0x80000000ULL ), Hi32Mask) ) );
10285 assign( exp_zero,
10286 unop( Iop_1Sto8,
10287 binop( Iop_CmpEQ32,
10288 binop( Iop_And32,
10289 unop( Iop_64HIto32,
10290 unop( Iop_ReinterpF64asI64,
10291 value ) ),
10292 Hi32Mask ),
10293 Hi32Mask ) ) );
10294 assign( frac_not_zero,
10295 binop( Iop_Or8,
10296 unop( Iop_1Sto8,
10297 binop( Iop_CmpNE32,
10298 binop( Iop_And32,
10299 unop( Iop_64HIto32,
10300 unop( Iop_ReinterpF64asI64,
10301 value ) ),
10302 mkexpr( frac_mask ) ),
10303 mkU32( 0x0 ) ) ),
10304 unop( Iop_1Sto8,
10305 binop( Iop_CmpNE32,
10306 binop( Iop_And32,
10307 unop( Iop_64to32,
10308 unop( Iop_ReinterpF64asI64,
10309 value ) ),
10310 mkU32( 0xFFFFFFFF ) ),
10311 mkU32( 0x0 ) ) ) ) );
10312 return unop( Iop_8Sto32,
10313 binop( Iop_And8,
10314 mkexpr( exp_zero ),
10315 mkexpr( frac_not_zero ) ) );
10318 static IRExpr * Complement_non_NaN( IRExpr * value, IRExpr * nan_mask )
10320 /* This function will only complement the 64-bit floating point value if it
10321 * is not Nan. NaN is not a signed value. Need to do computations using
10322 * 32-bit operands to ensure it will run in 32-bit mode.
10324 return binop( Iop_32HLto64,
10325 binop( Iop_Or32,
10326 binop( Iop_And32,
10327 nan_mask,
10328 unop( Iop_64HIto32,
10329 unop( Iop_ReinterpF64asI64,
10330 value ) ) ),
10331 binop( Iop_And32,
10332 unop( Iop_Not32,
10333 nan_mask ),
10334 unop( Iop_64HIto32,
10335 unop( Iop_ReinterpF64asI64,
10336 unop( Iop_NegF64,
10337 value ) ) ) ) ),
10338 unop( Iop_64to32,
10339 unop( Iop_ReinterpF64asI64, value ) ) );
10342 /*------------------------------------------------------------*/
10343 /*--- Floating Point Instruction Translation ---*/
10344 /*------------------------------------------------------------*/
10347 Floating Point Load Instructions
10349 static Bool dis_fp_load ( UInt theInstr )
10351 /* X-Form, D-Form */
10352 UChar opc1 = ifieldOPC(theInstr);
10353 UChar frD_addr = ifieldRegDS(theInstr);
10354 UChar rA_addr = ifieldRegA(theInstr);
10355 UChar rB_addr = ifieldRegB(theInstr);
10356 UInt opc2 = ifieldOPClo10(theInstr);
10357 UChar b0 = ifieldBIT0(theInstr);
10358 UInt uimm16 = ifieldUIMM16(theInstr);
10360 Int simm16 = extend_s_16to32(uimm16);
10361 IRType ty = mode64 ? Ity_I64 : Ity_I32;
10362 IRTemp EA = newTemp(ty);
10363 IRTemp rA = newTemp(ty);
10364 IRTemp rB = newTemp(ty);
10365 IRTemp iHi = newTemp(Ity_I32);
10366 IRTemp iLo = newTemp(Ity_I32);
10368 assign( rA, getIReg(rA_addr) );
10369 assign( rB, getIReg(rB_addr) );
10371 /* These are completely straightforward from a rounding and status
10372 bits perspective: no rounding involved and no funny status or CR
10373 bits affected. */
10375 switch (opc1) {
10376 case 0x30: // lfs (Load Float Single, PPC32 p441)
10377 DIP("lfs fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
10378 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
10379 putFReg( frD_addr,
10380 unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
10381 break;
10383 case 0x31: // lfsu (Load Float Single, Update, PPC32 p442)
10384 if (rA_addr == 0)
10385 return False;
10386 DIP("lfsu fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
10387 assign( EA, ea_rA_simm(rA_addr, simm16) );
10388 putFReg( frD_addr,
10389 unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
10390 putIReg( rA_addr, mkexpr(EA) );
10391 break;
10393 case 0x32: // lfd (Load Float Double, PPC32 p437)
10394 DIP("lfd fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
10395 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
10396 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
10397 break;
10399 case 0x33: // lfdu (Load Float Double, Update, PPC32 p438)
10400 if (rA_addr == 0)
10401 return False;
10402 DIP("lfdu fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
10403 assign( EA, ea_rA_simm(rA_addr, simm16) );
10404 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
10405 putIReg( rA_addr, mkexpr(EA) );
10406 break;
10408 case 0x1F:
10409 if (b0 != 0) {
10410 vex_printf("dis_fp_load(ppc)(instr,b0)\n");
10411 return False;
10414 switch(opc2) {
10415 case 0x217: // lfsx (Load Float Single Indexed, PPC32 p444)
10416 DIP("lfsx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
10417 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
10418 putFReg( frD_addr, unop( Iop_F32toF64,
10419 load(Ity_F32, mkexpr(EA))) );
10420 break;
10422 case 0x237: // lfsux (Load Float Single, Update Indxd, PPC32 p443)
10423 if (rA_addr == 0)
10424 return False;
10425 DIP("lfsux fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
10426 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
10427 putFReg( frD_addr,
10428 unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
10429 putIReg( rA_addr, mkexpr(EA) );
10430 break;
10432 case 0x257: // lfdx (Load Float Double Indexed, PPC32 p440)
10433 DIP("lfdx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
10434 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
10435 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
10436 break;
10438 case 0x277: // lfdux (Load Float Double, Update Indxd, PPC32 p439)
10439 if (rA_addr == 0)
10440 return False;
10441 DIP("lfdux fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
10442 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
10443 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
10444 putIReg( rA_addr, mkexpr(EA) );
10445 break;
10447 case 0x357: // lfiwax (Load Float As Integer, Indxd, ISA 2.05 p120)
10448 DIP("lfiwax fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
10449 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
10450 assign( iLo, load(Ity_I32, mkexpr(EA)) );
10451 assign( iHi, binop(Iop_Sub32,
10452 mkU32(0),
10453 binop(Iop_Shr32, mkexpr(iLo), mkU8(31))) );
10454 putFReg( frD_addr, unop(Iop_ReinterpI64asF64,
10455 binop(Iop_32HLto64, mkexpr(iHi), mkexpr(iLo))) );
10456 break;
10458 case 0x377: // lfiwzx (Load floating-point as integer word, zero indexed
10460 IRTemp dw = newTemp( Ity_I64 );
10461 DIP("lfiwzx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
10462 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
10463 assign( iLo, load(Ity_I32, mkexpr(EA)) );
10464 assign( dw, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( iLo ) ) );
10465 putFReg( frD_addr, unop( Iop_ReinterpI64asF64, mkexpr( dw ) ) );
10466 break;
10469 default:
10470 vex_printf("dis_fp_load(ppc)(opc2)\n");
10471 return False;
10473 break;
10475 default:
10476 vex_printf("dis_fp_load(ppc)(opc1)\n");
10477 return False;
10479 return True;
10485 Floating Point Store Instructions
10487 static Bool dis_fp_store ( UInt theInstr )
10489 /* X-Form, D-Form */
10490 UChar opc1 = ifieldOPC(theInstr);
10491 UChar frS_addr = ifieldRegDS(theInstr);
10492 UChar rA_addr = ifieldRegA(theInstr);
10493 UChar rB_addr = ifieldRegB(theInstr);
10494 UInt opc2 = ifieldOPClo10(theInstr);
10495 UChar b0 = ifieldBIT0(theInstr);
10496 Int uimm16 = ifieldUIMM16(theInstr);
10498 Int simm16 = extend_s_16to32(uimm16);
10499 IRTemp frS = newTemp(Ity_F64);
10500 IRType ty = mode64 ? Ity_I64 : Ity_I32;
10501 IRTemp EA = newTemp(ty);
10502 IRTemp rA = newTemp(ty);
10503 IRTemp rB = newTemp(ty);
10505 assign( frS, getFReg(frS_addr) );
10506 assign( rA, getIReg(rA_addr) );
10507 assign( rB, getIReg(rB_addr) );
10509 /* These are straightforward from a status bits perspective: no
10510 funny status or CR bits affected. For single precision stores,
10511 the values are truncated and denormalised (not rounded) to turn
10512 them into single precision values. */
10514 switch (opc1) {
10516 case 0x34: // stfs (Store Float Single, PPC32 p518)
10517 DIP("stfs fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
10518 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
10519 /* Use Iop_TruncF64asF32 to truncate and possible denormalise
10520 the value to be stored in the correct way, without any
10521 rounding. */
10522 store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
10523 break;
10525 case 0x35: // stfsu (Store Float Single, Update, PPC32 p519)
10526 if (rA_addr == 0)
10527 return False;
10528 DIP("stfsu fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
10529 assign( EA, ea_rA_simm(rA_addr, simm16) );
10530 /* See comment for stfs */
10531 store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
10532 putIReg( rA_addr, mkexpr(EA) );
10533 break;
10535 case 0x36: // stfd (Store Float Double, PPC32 p513)
10536 DIP("stfd fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
10537 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
10538 store( mkexpr(EA), mkexpr(frS) );
10539 break;
10541 case 0x37: // stfdu (Store Float Double, Update, PPC32 p514)
10542 if (rA_addr == 0)
10543 return False;
10544 DIP("stfdu fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
10545 assign( EA, ea_rA_simm(rA_addr, simm16) );
10546 store( mkexpr(EA), mkexpr(frS) );
10547 putIReg( rA_addr, mkexpr(EA) );
10548 break;
10550 case 0x1F:
10551 if (b0 != 0) {
10552 vex_printf("dis_fp_store(ppc)(instr,b0)\n");
10553 return False;
10555 switch(opc2) {
10556 case 0x297: // stfsx (Store Float Single Indexed, PPC32 p521)
10557 DIP("stfsx fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
10558 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
10559 /* See note for stfs */
10560 store( mkexpr(EA),
10561 unop(Iop_TruncF64asF32, mkexpr(frS)) );
10562 break;
10564 case 0x2B7: // stfsux (Store Float Sgl, Update Indxd, PPC32 p520)
10565 if (rA_addr == 0)
10566 return False;
10567 DIP("stfsux fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
10568 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
10569 /* See note for stfs */
10570 store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
10571 putIReg( rA_addr, mkexpr(EA) );
10572 break;
10574 case 0x2D7: // stfdx (Store Float Double Indexed, PPC32 p516)
10575 DIP("stfdx fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
10576 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
10577 store( mkexpr(EA), mkexpr(frS) );
10578 break;
10580 case 0x2F7: // stfdux (Store Float Dbl, Update Indxd, PPC32 p515)
10581 if (rA_addr == 0)
10582 return False;
10583 DIP("stfdux fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
10584 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
10585 store( mkexpr(EA), mkexpr(frS) );
10586 putIReg( rA_addr, mkexpr(EA) );
10587 break;
10589 case 0x3D7: // stfiwx (Store Float as Int, Indexed, PPC32 p517)
10590 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
10591 DIP("stfiwx fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
10592 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
10593 store( mkexpr(EA),
10594 unop(Iop_64to32, unop(Iop_ReinterpF64asI64, mkexpr(frS))) );
10595 break;
10597 default:
10598 vex_printf("dis_fp_store(ppc)(opc2)\n");
10599 return False;
10601 break;
10603 default:
10604 vex_printf("dis_fp_store(ppc)(opc1)\n");
10605 return False;
10607 return True;
10613 Floating Point Arith Instructions
10615 static Bool dis_fp_arith ( UInt theInstr )
10617 /* A-Form */
10618 UChar opc1 = ifieldOPC(theInstr);
10619 UChar frD_addr = ifieldRegDS(theInstr);
10620 UChar frA_addr = ifieldRegA(theInstr);
10621 UChar frB_addr = ifieldRegB(theInstr);
10622 UChar frC_addr = ifieldRegC(theInstr);
10623 UChar opc2 = ifieldOPClo5(theInstr);
10624 UChar flag_rC = ifieldBIT0(theInstr);
10626 IRTemp frD = newTemp(Ity_F64);
10627 IRTemp frA = newTemp(Ity_F64);
10628 IRTemp frB = newTemp(Ity_F64);
10629 IRTemp frC = newTemp(Ity_F64);
10630 IRExpr* rm = get_IR_roundingmode();
10632 /* By default, we will examine the results of the operation and set
10633 fpscr[FPRF] accordingly. */
10634 Bool set_FPRF = True;
10636 /* By default, if flag_RC is set, we will clear cr1 after the
10637 operation. In reality we should set cr1 to indicate the
10638 exception status of the operation, but since we're not
10639 simulating exceptions, the exception status will appear to be
10640 zero. Hence cr1 should be cleared if this is a . form insn. */
10641 Bool clear_CR1 = True;
10643 assign( frA, getFReg(frA_addr));
10644 assign( frB, getFReg(frB_addr));
10645 assign( frC, getFReg(frC_addr));
10647 switch (opc1) {
10648 case 0x3B:
10649 switch (opc2) {
10650 case 0x12: // fdivs (Floating Divide Single, PPC32 p407)
10651 if (frC_addr != 0)
10652 return False;
10653 DIP("fdivs%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10654 frD_addr, frA_addr, frB_addr);
10655 assign( frD, triop( Iop_DivF64r32,
10656 rm, mkexpr(frA), mkexpr(frB) ));
10657 break;
10659 case 0x14: // fsubs (Floating Subtract Single, PPC32 p430)
10660 if (frC_addr != 0)
10661 return False;
10662 DIP("fsubs%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10663 frD_addr, frA_addr, frB_addr);
10664 assign( frD, triop( Iop_SubF64r32,
10665 rm, mkexpr(frA), mkexpr(frB) ));
10666 break;
10668 case 0x15: // fadds (Floating Add Single, PPC32 p401)
10669 if (frC_addr != 0)
10670 return False;
10671 DIP("fadds%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10672 frD_addr, frA_addr, frB_addr);
10673 assign( frD, triop( Iop_AddF64r32,
10674 rm, mkexpr(frA), mkexpr(frB) ));
10675 break;
10677 case 0x16: // fsqrts (Floating SqRt (Single-Precision), PPC32 p428)
10678 // NOTE: POWERPC OPTIONAL, "General-Purpose Group" (PPC32_FX)
10679 if (frA_addr != 0 || frC_addr != 0)
10680 return False;
10681 DIP("fsqrts%s fr%u,fr%u\n", flag_rC ? ".":"",
10682 frD_addr, frB_addr);
10683 // however illogically, on ppc970 this insn behaves identically
10684 // to fsqrt (double-precision). So use SqrtF64, not SqrtF64r32.
10685 assign( frD, binop( Iop_SqrtF64, rm, mkexpr(frB) ));
10686 break;
10688 case 0x18: // fres (Floating Reciprocal Estimate Single, PPC32 p421)
10689 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
10690 if (frA_addr != 0 || frC_addr != 0)
10691 return False;
10692 DIP("fres%s fr%u,fr%u\n", flag_rC ? ".":"",
10693 frD_addr, frB_addr);
10694 { IRExpr* ieee_one
10695 = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
10696 assign( frD, triop( Iop_DivF64r32,
10698 ieee_one, mkexpr(frB) ));
10700 break;
10702 case 0x19: // fmuls (Floating Multiply Single, PPC32 p414)
10703 if (frB_addr != 0)
10704 return False;
10705 DIP("fmuls%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10706 frD_addr, frA_addr, frC_addr);
10707 assign( frD, triop( Iop_MulF64r32,
10708 rm, mkexpr(frA), mkexpr(frC) ));
10709 break;
10711 case 0x1A: // frsqrtes (Floating Recip SqRt Est Single)
10712 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
10713 // Undocumented instruction?
10714 if (frA_addr != 0 || frC_addr != 0)
10715 return False;
10716 DIP("frsqrtes%s fr%u,fr%u\n", flag_rC ? ".":"",
10717 frD_addr, frB_addr);
10718 assign( frD, unop(Iop_RSqrtEst5GoodF64, mkexpr(frB)) );
10719 break;
10721 default:
10722 vex_printf("dis_fp_arith(ppc)(3B: opc2)\n");
10723 return False;
10725 break;
10727 case 0x3F:
10728 switch (opc2) {
10729 case 0x12: // fdiv (Floating Div (Double-Precision), PPC32 p406)
10730 if (frC_addr != 0)
10731 return False;
10732 DIP("fdiv%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10733 frD_addr, frA_addr, frB_addr);
10734 assign( frD, triop(Iop_DivF64, rm, mkexpr(frA), mkexpr(frB)) );
10735 break;
10737 case 0x14: // fsub (Floating Sub (Double-Precision), PPC32 p429)
10738 if (frC_addr != 0)
10739 return False;
10740 DIP("fsub%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10741 frD_addr, frA_addr, frB_addr);
10742 assign( frD, triop(Iop_SubF64, rm, mkexpr(frA), mkexpr(frB)) );
10743 break;
10745 case 0x15: // fadd (Floating Add (Double-Precision), PPC32 p400)
10746 if (frC_addr != 0)
10747 return False;
10748 DIP("fadd%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10749 frD_addr, frA_addr, frB_addr);
10750 assign( frD, triop(Iop_AddF64, rm, mkexpr(frA), mkexpr(frB)) );
10751 break;
10753 case 0x16: // fsqrt (Floating SqRt (Double-Precision), PPC32 p427)
10754 // NOTE: POWERPC OPTIONAL, "General-Purpose Group" (PPC32_FX)
10755 if (frA_addr != 0 || frC_addr != 0)
10756 return False;
10757 DIP("fsqrt%s fr%u,fr%u\n", flag_rC ? ".":"",
10758 frD_addr, frB_addr);
10759 assign( frD, binop(Iop_SqrtF64, rm, mkexpr(frB)) );
10760 break;
10762 case 0x17: { // fsel (Floating Select, PPC32 p426)
10763 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
10764 IRTemp cc = newTemp(Ity_I32);
10765 IRTemp cc_b0 = newTemp(Ity_I32);
10767 DIP("fsel%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10768 frD_addr, frA_addr, frC_addr, frB_addr);
10770 // cc: UN == 0x41, LT == 0x01, GT == 0x00, EQ == 0x40
10771 // => GT|EQ == (cc & 0x1 == 0)
10772 assign( cc, binop(Iop_CmpF64, mkexpr(frA),
10773 IRExpr_Const(IRConst_F64(0))) );
10774 assign( cc_b0, binop(Iop_And32, mkexpr(cc), mkU32(1)) );
10776 // frD = (frA >= 0.0) ? frC : frB
10777 // = (cc_b0 == 0) ? frC : frB
10778 assign( frD,
10779 IRExpr_ITE(
10780 binop(Iop_CmpEQ32, mkexpr(cc_b0), mkU32(0)),
10781 mkexpr(frC),
10782 mkexpr(frB) ));
10784 /* One of the rare ones which don't mess with FPRF */
10785 set_FPRF = False;
10786 break;
10789 case 0x18: // fre (Floating Reciprocal Estimate)
10790 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
10791 // Note: unclear whether this insn really exists or not
10792 // ppc970 doesn't have it, but POWER5 does
10793 if (frA_addr != 0 || frC_addr != 0)
10794 return False;
10795 DIP("fre%s fr%u,fr%u\n", flag_rC ? ".":"",
10796 frD_addr, frB_addr);
10797 { IRExpr* ieee_one
10798 = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
10799 assign( frD, triop( Iop_DivF64,
10801 ieee_one, mkexpr(frB) ));
10803 break;
10805 case 0x19: // fmul (Floating Mult (Double Precision), PPC32 p413)
10806 if (frB_addr != 0)
10807 vex_printf("dis_fp_arith(ppc)(instr,fmul)\n");
10808 DIP("fmul%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10809 frD_addr, frA_addr, frC_addr);
10810 assign( frD, triop(Iop_MulF64, rm, mkexpr(frA), mkexpr(frC)) );
10811 break;
10813 case 0x1A: // frsqrte (Floating Recip SqRt Est., PPC32 p424)
10814 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
10815 if (frA_addr != 0 || frC_addr != 0)
10816 return False;
10817 DIP("frsqrte%s fr%u,fr%u\n", flag_rC ? ".":"",
10818 frD_addr, frB_addr);
10819 assign( frD, unop(Iop_RSqrtEst5GoodF64, mkexpr(frB)) );
10820 break;
10822 default:
10823 vex_printf("dis_fp_arith(ppc)(3F: opc2)\n");
10824 return False;
10826 break;
10828 default:
10829 vex_printf("dis_fp_arith(ppc)(opc1)\n");
10830 return False;
10833 putFReg( frD_addr, mkexpr(frD) );
10835 if (set_FPRF) {
10836 // XXX XXX XXX FIXME
10837 // set FPRF from frD
10840 if (flag_rC && clear_CR1) {
10841 putCR321( 1, mkU8(0) );
10842 putCR0( 1, mkU8(0) );
10845 return True;
10851 Floating Point Mult-Add Instructions
10853 static Bool dis_fp_multadd ( UInt theInstr )
10855 /* A-Form */
10856 UChar opc1 = ifieldOPC(theInstr);
10857 UChar frD_addr = ifieldRegDS(theInstr);
10858 UChar frA_addr = ifieldRegA(theInstr);
10859 UChar frB_addr = ifieldRegB(theInstr);
10860 UChar frC_addr = ifieldRegC(theInstr);
10861 UChar opc2 = ifieldOPClo5(theInstr);
10862 UChar flag_rC = ifieldBIT0(theInstr);
10864 IRTemp frD = newTemp(Ity_F64);
10865 IRTemp frA = newTemp(Ity_F64);
10866 IRTemp frB = newTemp(Ity_F64);
10867 IRTemp frC = newTemp(Ity_F64);
10868 IRTemp rmt = newTemp(Ity_I32);
10869 IRTemp tmp = newTemp(Ity_F64);
10870 IRTemp sign_tmp = newTemp(Ity_I64);
10871 IRTemp nan_mask = newTemp(Ity_I32);
10872 IRExpr* rm;
10874 /* By default, we will examine the results of the operation and set
10875 fpscr[FPRF] accordingly. */
10876 Bool set_FPRF = True;
10878 /* By default, if flag_RC is set, we will clear cr1 after the
10879 operation. In reality we should set cr1 to indicate the
10880 exception status of the operation, but since we're not
10881 simulating exceptions, the exception status will appear to be
10882 zero. Hence cr1 should be cleared if this is a . form insn. */
10883 Bool clear_CR1 = True;
10885 /* Bind the rounding mode expression to a temp; there's no
10886 point in creating gratuitous CSEs, as we know we'll need
10887 to use it twice. */
10888 assign( rmt, get_IR_roundingmode() );
10889 rm = mkexpr(rmt);
10891 assign( frA, getFReg(frA_addr));
10892 assign( frB, getFReg(frB_addr));
10893 assign( frC, getFReg(frC_addr));
10895 /* The rounding in this is all a bit dodgy. The idea is to only do
10896 one rounding. That clearly isn't achieveable without dedicated
10897 four-input IR primops, although in the single precision case we
10898 can sort-of simulate it by doing the inner multiply in double
10899 precision.
10901 In the negated cases, the negation happens after rounding. */
10903 switch (opc1) {
10904 case 0x3B:
10905 switch (opc2) {
10906 case 0x1C: // fmsubs (Floating Mult-Subtr Single, PPC32 p412)
10907 DIP("fmsubs%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10908 frD_addr, frA_addr, frC_addr, frB_addr);
10909 assign( frD, qop( Iop_MSubF64r32, rm,
10910 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
10911 break;
10913 case 0x1D: // fmadds (Floating Mult-Add Single, PPC32 p409)
10914 DIP("fmadds%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10915 frD_addr, frA_addr, frC_addr, frB_addr);
10916 assign( frD, qop( Iop_MAddF64r32, rm,
10917 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
10918 break;
10920 case 0x1E: // fnmsubs (Float Neg Mult-Subtr Single, PPC32 p420)
10921 case 0x1F: // fnmadds (Floating Negative Multiply-Add Single, PPC32 p418)
10923 if (opc2 == 0x1E) {
10924 DIP("fnmsubs%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10925 frD_addr, frA_addr, frC_addr, frB_addr);
10926 assign( tmp, qop( Iop_MSubF64r32, rm,
10927 mkexpr(frA), mkexpr(frC), mkexpr(frB) ) );
10928 } else {
10929 DIP("fnmadds%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10930 frD_addr, frA_addr, frC_addr, frB_addr);
10931 assign( tmp, qop( Iop_MAddF64r32, rm,
10932 mkexpr(frA), mkexpr(frC), mkexpr(frB) ) );
10935 assign( nan_mask, Check_NaN( mkexpr( tmp ),
10936 mkU32( NANmaskSingle ) ) );
10937 assign( sign_tmp, Complement_non_NaN( mkexpr( tmp ),
10938 mkexpr( nan_mask ) ) );
10939 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr( sign_tmp ) ) );
10940 break;
10942 default:
10943 vex_printf("dis_fp_multadd(ppc)(3B: opc2)\n");
10944 return False;
10946 break;
10948 case 0x3F:
10949 switch (opc2) {
10950 case 0x1C: // fmsub (Float Mult-Sub (Dbl Precision), PPC32 p411)
10951 DIP("fmsub%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10952 frD_addr, frA_addr, frC_addr, frB_addr);
10953 assign( frD, qop( Iop_MSubF64, rm,
10954 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
10955 break;
10957 case 0x1D: // fmadd (Float Mult-Add (Dbl Precision), PPC32 p408)
10958 DIP("fmadd%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10959 frD_addr, frA_addr, frC_addr, frB_addr);
10960 assign( frD, qop( Iop_MAddF64, rm,
10961 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
10962 break;
10964 case 0x1E: // fnmsub (Float Neg Mult-Subtr (Dbl Precision), PPC32 p419)
10965 case 0x1F: // fnmadd (Float Neg Mult-Add (Dbl Precision), PPC32 p417)
10967 if (opc2 == 0x1E) {
10968 DIP("fnmsub%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10969 frD_addr, frA_addr, frC_addr, frB_addr);
10970 assign( tmp, qop( Iop_MSubF64, rm,
10971 mkexpr(frA), mkexpr(frC), mkexpr(frB) ) );
10972 } else {
10973 DIP("fnmadd%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10974 frD_addr, frA_addr, frC_addr, frB_addr);
10975 assign( tmp, qop( Iop_MAddF64, rm,
10976 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
10979 assign( nan_mask, Check_NaN( mkexpr( tmp ),
10980 mkU32( NANmaskDouble ) ) );
10981 assign( sign_tmp, Complement_non_NaN( mkexpr( tmp ),
10982 mkexpr( nan_mask ) ) );
10983 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr( sign_tmp ) ) );
10984 break;
10986 default:
10987 vex_printf("dis_fp_multadd(ppc)(3F: opc2)\n");
10988 return False;
10990 break;
10992 default:
10993 vex_printf("dis_fp_multadd(ppc)(opc1)\n");
10994 return False;
10997 putFReg( frD_addr, mkexpr(frD) );
10999 if (set_FPRF) {
11000 // XXX XXX XXX FIXME
11001 // set FPRF from frD
11004 if (flag_rC && clear_CR1) {
11005 putCR321( 1, mkU8(0) );
11006 putCR0( 1, mkU8(0) );
11009 return True;
11013 * fe_flag is set to 1 if any of the following conditions occurs:
11014 * - The floating-point operand in register FRB is a Zero, a
11015 * NaN, an Infinity, or a negative value.
11016 * - e_b is less than or equal to: -970 for double precision; -103 for single precision
11017 * Otherwise fe_flag is set to 0.
11019 * fg_flag is set to 1 if either of the following conditions occurs.
11020 * - The floating-point operand in register FRB is a Zero, an
11021 * Infinity, or a denormalized value.
11022 * Otherwise fg_flag is set to 0.
11026 static void do_fp_tsqrt(IRTemp frB_Int, Bool sp, IRTemp * fe_flag_tmp, IRTemp * fg_flag_tmp)
11028 // The following temps are for holding intermediate results
11029 IRTemp e_b = newTemp(Ity_I32);
11030 IRExpr * fe_flag, * fg_flag;
11031 IRTemp frB_exp_shR = newTemp(Ity_I32);
11032 UInt bias = sp? 127 : 1023;
11033 IRExpr * frbNaN, * frbDenorm, * frBNeg;
11034 IRExpr * eb_LTE;
11035 IRTemp frbZero_tmp = newTemp(Ity_I1);
11036 IRTemp frbInf_tmp = newTemp(Ity_I1);
11037 *fe_flag_tmp = newTemp(Ity_I32);
11038 *fg_flag_tmp = newTemp(Ity_I32);
11040 if ( sp )
11041 assign( frB_exp_shR, fp_exp_part( Ity_I32, frB_Int ) );
11042 else
11043 assign( frB_exp_shR, fp_exp_part( Ity_I64, frB_Int ) );
11045 assign(e_b, binop( Iop_Sub32, mkexpr(frB_exp_shR), mkU32( bias ) ));
11047 ////////////////// fe_flag tests BEGIN //////////////////////
11048 /* We first do all tests that may result in setting fe_flag to '1'.
11049 * (NOTE: These tests are similar to those used for ftdiv. See do_fp_tdiv()
11050 * for details.)
11052 if ( sp ) {
11053 frbNaN = is_NaN( Ity_I32, frB_Int );
11054 assign( frbInf_tmp, is_Inf( Ity_I32, frB_Int ) );
11055 assign( frbZero_tmp, is_Zero( Ity_I32, frB_Int ) );
11057 } else {
11058 frbNaN = is_NaN( Ity_I64, frB_Int );
11059 assign( frbInf_tmp, is_Inf( Ity_I64, frB_Int ) );
11060 assign( frbZero_tmp, is_Zero( Ity_I64, frB_Int ) );
11064 // Test_value = -970 for double precision
11065 UInt test_value = sp ? 0xffffff99 : 0xfffffc36;
11066 eb_LTE = binop( Iop_CmpLE32S, mkexpr( e_b ), mkU32( test_value ) );
11068 frBNeg = binop( Iop_CmpEQ32,
11069 binop( Iop_Shr32,
11070 sp ? mkexpr( frB_Int ) : unop( Iop_64HIto32, mkexpr( frB_Int ) ),
11071 mkU8( 31 ) ),
11072 mkU32( 1 ) );
11073 ////////////////// fe_flag tests END //////////////////////
11075 ////////////////// fg_flag tests BEGIN //////////////////////
11077 * The following tests were already performed above in the fe_flag
11078 * tests. So these conditions will result in both fe_ and fg_ flags
11079 * being set.
11080 * - Test if FRB is Zero
11081 * - Test if FRB is an Infinity
11085 * Test if FRB holds a denormalized value. A denormalized value is one where
11086 * the exp is 0 and the fraction is non-zero.
11088 if (sp) {
11089 IRTemp frac_part = newTemp(Ity_I32);
11090 assign( frac_part, binop( Iop_And32, mkexpr(frB_Int), mkU32(0x007fffff)) );
11091 frbDenorm
11092 = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ), mkU32( 0 ) ),
11093 binop( Iop_CmpNE32, mkexpr( frac_part ), mkU32( 0 ) ) );
11094 } else {
11095 IRExpr * hi32, * low32, * fraction_is_nonzero;
11096 IRTemp frac_part = newTemp(Ity_I64);
11098 assign( frac_part, FP_FRAC_PART(frB_Int) );
11099 hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
11100 low32 = unop( Iop_64to32, mkexpr( frac_part ) );
11101 fraction_is_nonzero = binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
11102 mkU32( 0 ) );
11103 frbDenorm
11104 = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ), mkU32( 0 ) ),
11105 fraction_is_nonzero );
11107 ////////////////// fg_flag tests END //////////////////////
11109 /////////////////////////
11110 fe_flag = mkOR1( mkexpr( frbZero_tmp ),
11111 mkOR1( frbNaN,
11112 mkOR1( mkexpr( frbInf_tmp ),
11113 mkOR1( frBNeg, eb_LTE ) ) ) );
11115 fe_flag = unop(Iop_1Uto32, fe_flag);
11117 fg_flag = mkOR1( mkexpr( frbZero_tmp ),
11118 mkOR1( mkexpr( frbInf_tmp ), frbDenorm ) );
11119 fg_flag = unop(Iop_1Uto32, fg_flag);
11120 assign (*fg_flag_tmp, fg_flag);
11121 assign (*fe_flag_tmp, fe_flag);
11124 * fe_flag is set to 1 if any of the following conditions occurs:
11125 * - The double-precision floating-point operand in register FRA is a NaN or an
11126 * Infinity.
11127 * - The double-precision floating-point operand in register FRB is a Zero, a
11128 * NaN, or an Infinity.
11129 * - e_b is less than or equal to -1022.
11130 * - e_b is greater than or equal to 1021.
11131 * - The double-precision floating-point operand in register FRA is not a zero
11132 * and the difference, e_a - e_b, is greater than or equal to 1023.
11133 * - The double-precision floating-point operand in register FRA is not a zero
11134 * and the difference, e_a - e_b, is less than or equal to -1021.
11135 * - The double-precision floating-point operand in register FRA is not a zero
11136 * and e_a is less than or equal to -970
11137 * Otherwise fe_flag is set to 0.
11139 * fg_flag is set to 1 if either of the following conditions occurs.
11140 * - The double-precision floating-point operand in register FRA is an Infinity.
11141 * - The double-precision floating-point operand in register FRB is a Zero, an
11142 * Infinity, or a denormalized value.
11143 * Otherwise fg_flag is set to 0.
11146 static void _do_fp_tdiv(IRTemp frA_int, IRTemp frB_int, Bool sp, IRTemp * fe_flag_tmp, IRTemp * fg_flag_tmp)
11148 // The following temps are for holding intermediate results
11149 IRTemp e_a = newTemp(Ity_I32);
11150 IRTemp e_b = newTemp(Ity_I32);
11151 IRTemp frA_exp_shR = newTemp(Ity_I32);
11152 IRTemp frB_exp_shR = newTemp(Ity_I32);
11154 UInt bias = sp? 127 : 1023;
11155 *fe_flag_tmp = newTemp(Ity_I32);
11156 *fg_flag_tmp = newTemp(Ity_I32);
11158 /* The following variables hold boolean results from tests
11159 * that are OR'ed together for setting the fe_ and fg_ flags.
11160 * For some cases, the booleans are used more than once, so
11161 * I make those IRTemp's instead of IRExpr's.
11163 IRExpr * fraNaN, * frbNaN, * frbDenorm;
11164 IRExpr * eb_LTE, * eb_GTE, * ea_eb_GTE, * ea_eb_LTE, * ea_LTE;
11165 IRTemp fraInf_tmp = newTemp(Ity_I1);
11166 IRTemp frbZero_tmp = newTemp(Ity_I1);
11167 IRTemp frbInf_tmp = newTemp(Ity_I1);
11168 IRTemp fraNotZero_tmp = newTemp(Ity_I1);
11170 /* The following are the flags that are set by OR'ing the results of
11171 * all the tests done for tdiv. These flags are the input to the specified CR.
11173 IRExpr * fe_flag, * fg_flag;
11175 // Create temps that will be used throughout the following tests.
11176 if ( sp ) {
11177 assign( frA_exp_shR, fp_exp_part( Ity_I32, frA_int ) );
11178 assign( frB_exp_shR, fp_exp_part( Ity_I32, frB_int ) );
11179 } else{
11180 assign( frA_exp_shR, fp_exp_part( Ity_I64, frA_int ) );
11181 assign( frB_exp_shR, fp_exp_part( Ity_I64, frB_int ) );
11184 /* Let e_[a|b] be the unbiased exponent: i.e. exp - 1023. */
11185 assign(e_a, binop( Iop_Sub32, mkexpr(frA_exp_shR), mkU32( bias ) ));
11186 assign(e_b, binop( Iop_Sub32, mkexpr(frB_exp_shR), mkU32( bias ) ));
11189 ////////////////// fe_flag tests BEGIN //////////////////////
11190 /* We first do all tests that may result in setting fe_flag to '1'. */
11193 * Test if the double-precision floating-point operand in register FRA is
11194 * a NaN:
11196 fraNaN = sp ? is_NaN( Ity_I32, frA_int ) : is_NaN( Ity_I64, frA_int );
11198 * Test if the double-precision floating-point operands in register FRA
11199 * and FRB is an Infinity. Test if FRB is zero.
11201 if ( sp ) {
11202 assign(fraInf_tmp, is_Inf( Ity_I32, frA_int ) );
11203 assign( frbInf_tmp, is_Inf( Ity_I32, frB_int ) );
11204 assign( frbZero_tmp, is_Zero( Ity_I32, frB_int ) );
11206 } else {
11207 assign(fraInf_tmp, is_Inf( Ity_I64, frA_int ) );
11208 assign( frbInf_tmp, is_Inf( Ity_I64, frB_int ) );
11209 assign( frbZero_tmp, is_Zero( Ity_I64, frB_int ) );
11212 * Test if the double-precision floating-point operand in register FRB is
11213 * a NaN:
11215 frbNaN = sp ? is_NaN( Ity_I32, frB_int ) : is_NaN( Ity_I64, frB_int );
11218 * Test if e_b <= -1022 for double precision;
11219 * or e_b <= -126 for single precision
11222 UInt test_value = sp ? 0xffffff82 : 0xfffffc02;
11223 eb_LTE = binop(Iop_CmpLE32S, mkexpr(e_b), mkU32(test_value));
11227 * Test if e_b >= 1021 (i.e., 1021 < e_b) for double precision;
11228 * or e_b >= -125 (125 < e_b) for single precision
11231 Int test_value = sp ? 125 : 1021;
11232 eb_GTE = binop(Iop_CmpLT32S, mkU32(test_value), mkexpr(e_b));
11236 * Test if FRA != Zero and (e_a - e_b) >= bias
11238 if ( sp )
11239 assign( fraNotZero_tmp, unop( Iop_Not1, is_Zero( Ity_I32, frA_int ) ) );
11240 else
11241 assign( fraNotZero_tmp, unop( Iop_Not1, is_Zero( Ity_I64, frA_int ) ) );
11243 ea_eb_GTE = mkAND1( mkexpr( fraNotZero_tmp ),
11244 binop( Iop_CmpLT32S, mkU32( bias ),
11245 binop( Iop_Sub32, mkexpr( e_a ),
11246 mkexpr( e_b ) ) ) );
11249 * Test if FRA != Zero and (e_a - e_b) <= [-1021 (double precision) or -125 (single precision)]
11252 UInt test_value = sp ? 0xffffff83 : 0xfffffc03;
11254 ea_eb_LTE = mkAND1( mkexpr( fraNotZero_tmp ),
11255 binop( Iop_CmpLE32S,
11256 binop( Iop_Sub32,
11257 mkexpr( e_a ),
11258 mkexpr( e_b ) ),
11259 mkU32( test_value ) ) );
11263 * Test if FRA != Zero and e_a <= [-970 (double precision) or -103 (single precision)]
11266 UInt test_value = 0xfffffc36; //Int test_value = -970;
11268 ea_LTE = mkAND1( mkexpr( fraNotZero_tmp ), binop( Iop_CmpLE32S,
11269 mkexpr( e_a ),
11270 mkU32( test_value ) ) );
11272 ////////////////// fe_flag tests END //////////////////////
11274 ////////////////// fg_flag tests BEGIN //////////////////////
11276 * The following tests were already performed above in the fe_flag
11277 * tests. So these conditions will result in both fe_ and fg_ flags
11278 * being set.
11279 * - Test if FRA is an Infinity
11280 * - Test if FRB ix Zero
11281 * - Test if FRB is an Infinity
11285 * Test if FRB holds a denormalized value. A denormalized value is one where
11286 * the exp is 0 and the fraction is non-zero.
11289 IRExpr * fraction_is_nonzero;
11291 if (sp) {
11292 fraction_is_nonzero = binop( Iop_CmpNE32, FP_FRAC_PART32(frB_int),
11293 mkU32( 0 ) );
11294 } else {
11295 IRExpr * hi32, * low32;
11296 IRTemp frac_part = newTemp(Ity_I64);
11297 assign( frac_part, FP_FRAC_PART(frB_int) );
11299 hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
11300 low32 = unop( Iop_64to32, mkexpr( frac_part ) );
11301 fraction_is_nonzero = binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
11302 mkU32( 0 ) );
11304 frbDenorm = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ),
11305 mkU32( 0x0 ) ), fraction_is_nonzero );
11308 ////////////////// fg_flag tests END //////////////////////
11310 fe_flag
11311 = mkOR1(
11312 fraNaN,
11313 mkOR1(
11314 mkexpr( fraInf_tmp ),
11315 mkOR1(
11316 mkexpr( frbZero_tmp ),
11317 mkOR1(
11318 frbNaN,
11319 mkOR1(
11320 mkexpr( frbInf_tmp ),
11321 mkOR1( eb_LTE,
11322 mkOR1( eb_GTE,
11323 mkOR1( ea_eb_GTE,
11324 mkOR1( ea_eb_LTE,
11325 ea_LTE ) ) ) ) ) ) ) ) );
11327 fe_flag = unop(Iop_1Uto32, fe_flag);
11329 fg_flag = mkOR1( mkexpr( fraInf_tmp ), mkOR1( mkexpr( frbZero_tmp ),
11330 mkOR1( mkexpr( frbInf_tmp ),
11331 frbDenorm ) ) );
11332 fg_flag = unop(Iop_1Uto32, fg_flag);
11333 assign(*fe_flag_tmp, fe_flag);
11334 assign(*fg_flag_tmp, fg_flag);
11337 /* See description for _do_fp_tdiv() above. */
11338 static IRExpr * do_fp_tdiv(IRTemp frA_int, IRTemp frB_int)
11340 IRTemp fe_flag, fg_flag;
11341 /////////////////////////
11342 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
11343 * where fl_flag == 1 on ppc64.
11345 IRExpr * fl_flag = unop(Iop_Not32, mkU32(0xFFFFFE));
11346 fe_flag = fg_flag = IRTemp_INVALID;
11347 _do_fp_tdiv(frA_int, frB_int, False/*not single precision*/, &fe_flag, &fg_flag);
11348 return binop( Iop_Or32,
11349 binop( Iop_Or32,
11350 binop( Iop_Shl32, fl_flag, mkU8( 3 ) ),
11351 binop( Iop_Shl32, mkexpr(fg_flag), mkU8( 2 ) ) ),
11352 binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) );
11355 static Bool dis_fp_tests ( UInt theInstr )
11357 UChar opc1 = ifieldOPC(theInstr);
11358 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
11359 UChar frB_addr = ifieldRegB(theInstr);
11360 UChar b0 = ifieldBIT0(theInstr);
11361 UInt opc2 = ifieldOPClo10(theInstr);
11362 IRTemp frB_I64 = newTemp(Ity_I64);
11364 if (opc1 != 0x3F || b0 != 0 ){
11365 vex_printf("dis_fp_tests(ppc)(ftdiv)\n");
11366 return False;
11368 assign( frB_I64, unop( Iop_ReinterpF64asI64, getFReg( frB_addr ) ) );
11370 switch (opc2) {
11371 case 0x080: // ftdiv
11373 UChar frA_addr = ifieldRegA(theInstr);
11374 IRTemp frA_I64 = newTemp(Ity_I64);
11375 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
11376 if (b21to22 != 0 ) {
11377 vex_printf("dis_fp_tests(ppc)(ftdiv)\n");
11378 return False;
11381 assign( frA_I64, unop( Iop_ReinterpF64asI64, getFReg( frA_addr ) ) );
11382 putGST_field( PPC_GST_CR, do_fp_tdiv(frA_I64, frB_I64), crfD );
11384 DIP("ftdiv crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
11385 break;
11387 case 0x0A0: // ftsqrt
11389 IRTemp flags = newTemp(Ity_I32);
11390 IRTemp fe_flag, fg_flag;
11391 fe_flag = fg_flag = IRTemp_INVALID;
11392 UChar b18to22 = toUChar( IFIELD( theInstr, 18, 5 ) );
11393 if ( b18to22 != 0) {
11394 vex_printf("dis_fp_tests(ppc)(ftsqrt)\n");
11395 return False;
11397 DIP("ftsqrt crf%d,fr%u\n", crfD, frB_addr);
11398 do_fp_tsqrt(frB_I64, False /* not single precision*/, &fe_flag, &fg_flag);
11399 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
11400 * where fl_flag == 1 on ppc64.
11402 assign( flags,
11403 binop( Iop_Or32,
11404 binop( Iop_Or32, mkU32( 8 ), // fl_flag
11405 binop( Iop_Shl32, mkexpr(fg_flag), mkU8( 2 ) ) ),
11406 binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) ) );
11407 putGST_field( PPC_GST_CR, mkexpr(flags), crfD );
11408 break;
11411 default:
11412 vex_printf("dis_fp_tests(ppc)(opc2)\n");
11413 return False;
11416 return True;
11420 Floating Point Compare Instructions
11422 static Bool dis_fp_cmp ( UInt theInstr )
11424 /* X-Form */
11425 UChar opc1 = ifieldOPC(theInstr);
11426 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
11427 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
11428 UChar frA_addr = ifieldRegA(theInstr);
11429 UChar frB_addr = ifieldRegB(theInstr);
11430 UInt opc2 = ifieldOPClo10(theInstr);
11431 UChar b0 = ifieldBIT0(theInstr);
11433 IRTemp ccIR = newTemp(Ity_I32);
11434 IRTemp ccPPC32 = newTemp(Ity_I32);
11436 IRTemp frA = newTemp(Ity_F64);
11437 IRTemp frB = newTemp(Ity_F64);
11439 if (opc1 != 0x3F || b21to22 != 0 || b0 != 0) {
11440 vex_printf("dis_fp_cmp(ppc)(instr)\n");
11441 return False;
11444 assign( frA, getFReg(frA_addr));
11445 assign( frB, getFReg(frB_addr));
11447 assign( ccIR, binop(Iop_CmpF64, mkexpr(frA), mkexpr(frB)) );
11449 /* Map compare result from IR to PPC32 */
11451 FP cmp result | PPC | IR
11452 --------------------------
11453 UN | 0x1 | 0x45
11454 EQ | 0x2 | 0x40
11455 GT | 0x4 | 0x00
11456 LT | 0x8 | 0x01
11459 // ccPPC32 = Shl(1, (~(ccIR>>5) & 2)
11460 // | ((ccIR ^ (ccIR>>6)) & 1)
11461 assign(
11462 ccPPC32,
11463 binop(
11464 Iop_Shl32,
11465 mkU32(1),
11466 unop(
11467 Iop_32to8,
11468 binop(
11469 Iop_Or32,
11470 binop(
11471 Iop_And32,
11472 unop(
11473 Iop_Not32,
11474 binop(Iop_Shr32, mkexpr(ccIR), mkU8(5))
11476 mkU32(2)
11478 binop(
11479 Iop_And32,
11480 binop(
11481 Iop_Xor32,
11482 mkexpr(ccIR),
11483 binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))
11485 mkU32(1)
11492 putGST_field( PPC_GST_CR, mkexpr(ccPPC32), crfD );
11493 putFPCC( mkexpr( ccPPC32 ) );
11495 // XXX XXX XXX FIXME
11496 // Also write the result into FPRF (it's not entirely clear how)
11498 /* Note: Differences between fcmpu and fcmpo are only in exception
11499 flag settings, which aren't supported anyway. */
11500 switch (opc2) {
11501 case 0x000: // fcmpu (Floating Compare Unordered, PPC32 p403)
11502 DIP("fcmpu crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
11503 break;
11504 case 0x020: // fcmpo (Floating Compare Ordered, PPC32 p402)
11505 DIP("fcmpo crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
11506 break;
11507 default:
11508 vex_printf("dis_fp_cmp(ppc)(opc2)\n");
11509 return False;
11511 return True;
11517 Floating Point Rounding/Conversion Instructions
11519 static Bool dis_fp_round ( UInt theInstr )
11521 /* X-Form */
11522 UChar opc1 = ifieldOPC(theInstr);
11523 UChar b16to20 = ifieldRegA(theInstr);
11524 UChar frD_addr = ifieldRegDS(theInstr);
11525 UChar frB_addr = ifieldRegB(theInstr);
11526 UInt opc2 = ifieldOPClo10(theInstr);
11527 UChar flag_rC = ifieldBIT0(theInstr);
11529 IRTemp frD = newTemp(Ity_F64);
11530 IRTemp frB = newTemp(Ity_F64);
11531 IRTemp r_tmp32 = newTemp(Ity_I32);
11532 IRTemp r_tmp64 = newTemp(Ity_I64);
11533 IRExpr* rm = get_IR_roundingmode();
11535 /* By default, we will examine the results of the operation and set
11536 fpscr[FPRF] accordingly. */
11537 Bool set_FPRF = True;
11539 /* By default, if flag_RC is set, we will clear cr1 after the
11540 operation. In reality we should set cr1 to indicate the
11541 exception status of the operation, but since we're not
11542 simulating exceptions, the exception status will appear to be
11543 zero. Hence cr1 should be cleared if this is a . form insn. */
11544 Bool clear_CR1 = True;
11545 if ((!(opc1 == 0x3F || opc1 == 0x3B)) || b16to20 != 0) {
11546 vex_printf("dis_fp_round(ppc)(instr)\n");
11547 return False;
11550 assign( frB, getFReg(frB_addr));
11551 if (opc1 == 0x3B) {
11552 /* The fcfid[u]s instructions (from ISA 2.06) are a bit odd because
11553 * they're very similar to the other instructions handled here, but have
11554 * a different primary opcode.
11556 switch (opc2) {
11557 case 0x34E: // fcfids (Float convert from signed DWord to single precision)
11558 DIP("fcfids%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11559 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
11560 assign( frD, binop( Iop_RoundF64toF32, rm, binop( Iop_I64StoF64, rm,
11561 mkexpr( r_tmp64 ) ) ) );
11562 goto putFR;
11564 case 0x3Ce: // fcfidus (Float convert from unsigned DWord to single precision)
11565 DIP("fcfidus%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11566 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
11567 assign( frD, unop( Iop_F32toF64, binop( Iop_I64UtoF32, rm, mkexpr( r_tmp64 ) ) ) );
11568 goto putFR;
11573 switch (opc2) {
11574 case 0x00C: // frsp (Float Round to Single, PPC32 p423)
11575 DIP("frsp%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11576 assign( frD, binop( Iop_RoundF64toF32, rm, mkexpr(frB) ));
11577 break;
11579 case 0x00E: // fctiw (Float Conv to Int, PPC32 p404)
11580 DIP("fctiw%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11581 assign( r_tmp32,
11582 binop(Iop_F64toI32S, rm, mkexpr(frB)) );
11583 assign( frD, unop( Iop_ReinterpI64asF64,
11584 unop( Iop_32Uto64, mkexpr(r_tmp32))));
11585 /* FPRF is undefined after fctiw. Leave unchanged. */
11586 set_FPRF = False;
11587 break;
11589 case 0x00F: // fctiwz (Float Conv to Int, Round to Zero, PPC32 p405)
11590 DIP("fctiwz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11591 assign( r_tmp32,
11592 binop(Iop_F64toI32S, mkU32(Irrm_ZERO), mkexpr(frB) ));
11593 assign( frD, unop( Iop_ReinterpI64asF64,
11594 unop( Iop_32Uto64, mkexpr(r_tmp32))));
11595 /* FPRF is undefined after fctiwz. Leave unchanged. */
11596 set_FPRF = False;
11597 break;
11599 case 0x08F: case 0x08E: // fctiwu[z]
11600 DIP("fctiwu%s%s fr%u,fr%u\n", opc2 == 0x08F ? "z" : "",
11601 flag_rC ? ".":"", frD_addr, frB_addr);
11602 assign( r_tmp32,
11603 binop( Iop_F64toI32U,
11604 opc2 == 0x08F ? mkU32( Irrm_ZERO ) : rm,
11605 mkexpr( frB ) ) );
11606 assign( frD, unop( Iop_ReinterpI64asF64,
11607 unop( Iop_32Uto64, mkexpr(r_tmp32))));
11608 /* FPRF is undefined after fctiwz. Leave unchanged. */
11609 set_FPRF = False;
11610 break;
11613 case 0x32E: // fctid (Float Conv to Int DWord, PPC64 p437)
11614 DIP("fctid%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11615 assign( r_tmp64,
11616 binop(Iop_F64toI64S, rm, mkexpr(frB)) );
11617 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
11618 /* FPRF is undefined after fctid. Leave unchanged. */
11619 set_FPRF = False;
11620 break;
11622 case 0x32F: // fctidz (Float Conv to Int DWord, Round to Zero, PPC64 p437)
11623 DIP("fctidz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11624 assign( r_tmp64,
11625 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), mkexpr(frB)) );
11626 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
11627 /* FPRF is undefined after fctidz. Leave unchanged. */
11628 set_FPRF = False;
11629 break;
11631 case 0x3AE: case 0x3AF: // fctidu[z] (Float Conv to Int DWord Unsigned [Round to Zero])
11633 DIP("fctidu%s%s fr%u,fr%u\n", opc2 == 0x3AE ? "" : "z",
11634 flag_rC ? ".":"", frD_addr, frB_addr);
11635 assign( r_tmp64,
11636 binop(Iop_F64toI64U, opc2 == 0x3AE ? rm : mkU32(Irrm_ZERO), mkexpr(frB)) );
11637 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
11638 /* FPRF is undefined after fctidz. Leave unchanged. */
11639 set_FPRF = False;
11640 break;
11642 case 0x34E: // fcfid (Float Conv from Int DWord, PPC64 p434)
11643 DIP("fcfid%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11644 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
11645 assign( frD,
11646 binop(Iop_I64StoF64, rm, mkexpr(r_tmp64)) );
11647 break;
11649 case 0x3CE: // fcfidu (Float convert from unsigned DWord)
11650 DIP("fcfidu%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11651 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
11652 assign( frD, binop( Iop_I64UtoF64, rm, mkexpr( r_tmp64 ) ) );
11653 break;
11655 case 0x188: case 0x1A8: case 0x1C8: case 0x1E8: // frin, friz, frip, frim
11656 switch(opc2) {
11657 case 0x188: // frin (Floating Round to Integer Nearest)
11658 DIP("frin%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11659 assign( r_tmp64,
11660 binop(Iop_F64toI64S, mkU32(Irrm_NEAREST), mkexpr(frB)) );
11661 break;
11662 case 0x1A8: // friz (Floating Round to Integer Toward Zero)
11663 DIP("friz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11664 assign( r_tmp64,
11665 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), mkexpr(frB)) );
11666 break;
11667 case 0x1C8: // frip (Floating Round to Integer Plus)
11668 DIP("frip%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11669 assign( r_tmp64,
11670 binop(Iop_F64toI64S, mkU32(Irrm_PosINF), mkexpr(frB)) );
11671 break;
11672 case 0x1E8: // frim (Floating Round to Integer Minus)
11673 DIP("frim%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11674 assign( r_tmp64,
11675 binop(Iop_F64toI64S, mkU32(Irrm_NegINF), mkexpr(frB)) );
11676 break;
11679 /* don't use the rounded integer if frB is outside -9e18..9e18 */
11680 /* F64 has only log10(2**52) significant digits anyway */
11681 /* need to preserve sign of zero */
11682 /* frD = (fabs(frB) > 9e18) ? frB :
11683 (sign(frB)) ? -fabs((double)r_tmp64) : (double)r_tmp64 */
11684 assign(frD, IRExpr_ITE(
11685 binop(Iop_CmpNE8,
11686 unop(Iop_32to8,
11687 binop(Iop_CmpF64,
11688 IRExpr_Const(IRConst_F64(9e18)),
11689 unop(Iop_AbsF64, mkexpr(frB)))),
11690 mkU8(0)),
11691 mkexpr(frB),
11692 IRExpr_ITE(
11693 binop(Iop_CmpNE32,
11694 binop(Iop_Shr32,
11695 unop(Iop_64HIto32,
11696 unop(Iop_ReinterpF64asI64,
11697 mkexpr(frB))),
11698 mkU8(31)),
11699 mkU32(0)),
11700 unop(Iop_NegF64,
11701 unop( Iop_AbsF64,
11702 binop(Iop_I64StoF64, mkU32(0),
11703 mkexpr(r_tmp64)) )),
11704 binop(Iop_I64StoF64, mkU32(0), mkexpr(r_tmp64) )
11707 break;
11709 default:
11710 vex_printf("dis_fp_round(ppc)(opc2)\n");
11711 return False;
11713 putFR:
11714 putFReg( frD_addr, mkexpr(frD) );
11716 if (set_FPRF) {
11717 // XXX XXX XXX FIXME
11718 // set FPRF from frD
11721 if (flag_rC && clear_CR1) {
11722 putCR321( 1, mkU8(0) );
11723 putCR0( 1, mkU8(0) );
11726 return True;
11730 Floating Point Pair Instructions
11732 static Bool dis_fp_pair ( UInt theInstr )
11734 /* X-Form/DS-Form */
11735 UChar opc1 = ifieldOPC(theInstr);
11736 UChar frT_hi_addr = ifieldRegDS(theInstr);
11737 UChar frT_lo_addr = frT_hi_addr + 1;
11738 UChar rA_addr = ifieldRegA(theInstr);
11739 UChar rB_addr = ifieldRegB(theInstr);
11740 UInt uimm16 = ifieldUIMM16(theInstr);
11741 Int simm16 = extend_s_16to32(uimm16);
11742 UInt opc2 = ifieldOPClo10(theInstr);
11743 IRType ty = mode64 ? Ity_I64 : Ity_I32;
11744 IRTemp EA_hi = newTemp(ty);
11745 IRTemp EA_lo = newTemp(ty);
11746 IRTemp frT_hi = newTemp(Ity_F64);
11747 IRTemp frT_lo = newTemp(Ity_F64);
11748 UChar b0 = ifieldBIT0(theInstr);
11749 Bool is_load = 0;
11751 switch (opc1) {
11752 case 0x1F: // register offset
11753 /* These instructions work on a pair of registers. The specified
11754 * register must be even.
11756 if ((frT_hi_addr %2) != 0) {
11757 vex_printf("dis_fp_pair(ppc) ldpx or stdpx: odd frT register\n");
11758 return False;
11761 switch(opc2) {
11762 case 0x317: // lfdpx (FP Load Double Pair X-form, ISA 2.05 p125)
11763 DIP("ldpx fr%u,r%u,r%u\n", frT_hi_addr, rA_addr, rB_addr);
11764 is_load = 1;
11765 break;
11766 case 0x397: // stfdpx (FP STORE Double Pair X-form, ISA 2.05 p125)
11767 DIP("stdpx fr%u,r%u,r%u\n", frT_hi_addr, rA_addr, rB_addr);
11768 break;
11769 default:
11770 vex_printf("dis_fp_pair(ppc) : X-form wrong opc2\n");
11771 return False;
11774 if (b0 != 0) {
11775 vex_printf("dis_fp_pair(ppc)(0x1F,b0)\n");
11776 return False;
11778 assign( EA_hi, ea_rAor0_idxd( rA_addr, rB_addr ) );
11779 break;
11780 case 0x39:
11782 UInt DS = IFIELD( theInstr, 2, 14);
11783 UChar vRT = ifieldRegDS(theInstr);
11784 IRTemp EA = newTemp( ty );
11786 opc2 = ifieldOPC0o2(theInstr);
11788 switch(opc2) {
11789 case 0x0: // lfdp (FP Load Double Pair DS-form, ISA 2.05 p125)
11790 /* This instruction works on a pair of registers. The specified
11791 * register must be even.
11793 if ((frT_hi_addr %2) != 0) {
11794 vex_printf("dis_fp_pair(ppc) lfdp : odd frT register\n");
11795 return False;
11798 DIP("lfdp fr%u,%d(r%u)\n", frT_hi_addr, simm16, rA_addr);
11799 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
11800 is_load = 1;
11801 break;
11803 case 0x2: // lxsd (Load VSX Scalar Doubleword)
11804 DIP("lxsd v%u,%u(r%u)\n", vRT, DS, rA_addr);
11806 assign( EA, ea_rAor0_simm( rA_addr, DS<<2 ) );
11808 putVSReg( vRT+32, binop( Iop_64HLtoV128,
11809 load( Ity_I64, mkexpr( EA ) ),
11810 mkU64( 0 ) ) );
11811 return True;
11813 case 0x3: // lxssp (Load VSX Scalar Single from memory,
11814 // store as double in register)
11815 DIP("lxssp v%u,%u(r%u)\n", vRT, DS, rA_addr);
11817 assign( EA, ea_rAor0_simm( rA_addr, DS<<2 ) );
11819 putVSReg( vRT+32,
11820 binop( Iop_64HLtoV128,
11821 unop( Iop_ReinterpF64asI64,
11822 unop( Iop_F32toF64,
11823 unop( Iop_ReinterpI32asF32,
11824 load( Ity_I32, mkexpr( EA ) ) ) ) ),
11825 mkU64( 0 ) ) );
11826 return True;
11828 default:
11829 vex_printf("dis_fp_pair(ppc) : DS-form wrong opc2\n");
11830 return False;
11832 break;
11834 case 0x3d:
11836 UInt DS = IFIELD( theInstr, 2, 14);
11837 UChar vRS = ifieldRegDS(theInstr);
11838 IRTemp EA = newTemp( ty );
11840 opc2 = ifieldOPC0o2(theInstr);
11842 switch(opc2) {
11843 case 0x0:
11844 // stfdp (FP Store Double Pair DS-form, ISA 2.05 p125)
11845 /* This instruction works on a pair of registers. The specified
11846 * register must be even.
11848 if ((frT_hi_addr %2) != 0) {
11849 vex_printf("dis_fp_pair(ppc) stfdp : odd frT register\n");
11850 return False;
11853 DIP("stfdp fr%u,%d(r%u)\n", frT_hi_addr, simm16, rA_addr);
11854 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
11855 break;
11857 case 0x1:
11859 UInt ea_off = 8;
11860 IRTemp word[2];
11861 IRExpr* irx_addr;
11862 UInt T = IFIELD( theInstr, 21, 5); // T or S depending on inst
11863 UInt TX = IFIELD( theInstr, 3, 1); // TX or SX field
11865 word[0] = newTemp(Ity_I64);
11866 word[1] = newTemp(Ity_I64);
11867 DS = IFIELD( theInstr, 4, 12); // DQ in the instruction definition
11868 assign( EA, ea_rAor0_simm( rA_addr, DS<<4 ) );
11870 if ( IFIELD( theInstr, 0, 3) == 1) {
11871 // lxv (Load VSX Vector)
11872 DIP("lxv v%u,%u(r%u)\n", vRS, DS, rA_addr);
11874 assign( word[0], load( Ity_I64, mkexpr( EA ) ) );
11876 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
11877 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
11879 assign( word[1], load( Ity_I64, irx_addr ) );
11881 if (host_endness == VexEndnessBE)
11882 putVSReg( TX*32+T, binop( Iop_64HLtoV128,
11883 mkexpr( word[0] ),
11884 mkexpr( word[1] ) ) );
11885 else
11886 putVSReg( TX*32+T, binop( Iop_64HLtoV128,
11887 mkexpr( word[1] ),
11888 mkexpr( word[0] ) ) );
11889 return True;
11891 } else if ( IFIELD( theInstr, 0, 3) == 5) {
11892 // stxv (Store VSX Vector)
11893 DIP("stxv v%u,%u(r%u)\n", vRS, DS, rA_addr);
11895 if (host_endness == VexEndnessBE) {
11896 store( mkexpr(EA), unop( Iop_V128HIto64,
11897 getVSReg( TX*32+T ) ) );
11898 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
11899 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
11900 store( irx_addr, unop( Iop_V128to64,
11901 getVSReg( TX*32+T ) ) );
11902 } else {
11903 store( mkexpr(EA), unop( Iop_V128to64,
11904 getVSReg( TX*32+T ) ) );
11905 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
11906 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
11907 store( irx_addr, unop( Iop_V128HIto64,
11908 getVSReg( TX*32+T ) ) );
11910 return True;
11912 } else {
11913 vex_printf("dis_fp_pair vector load/store (ppc) : DS-form wrong opc2\n");
11914 return False;
11916 break;
11918 case 0x2:
11919 // stxsd (Store VSX Scalar Doubleword)
11920 DIP("stxsd v%u,%u(r%u)\n", vRS, DS, rA_addr);
11922 assign( EA, ea_rAor0_simm( rA_addr, DS<<2 ) );
11924 store( mkexpr(EA), unop( Iop_V128HIto64,
11925 getVSReg( vRS+32 ) ) );
11926 /* HW is clearing vector element 1. Don't see that in the ISA but
11927 * matching the HW.
11929 putVSReg( vRS+32, binop( Iop_64HLtoV128,
11930 unop( Iop_V128HIto64,
11931 getVSReg( vRS+32 ) ),
11932 mkU64( 0 ) ) );
11933 return True;
11935 case 0x3:
11937 // stxssp (Store VSX Scalar Single - store double precision
11938 // value from register into memory in single precision format)
11939 IRTemp high64 = newTemp(Ity_F64);
11940 IRTemp val32 = newTemp(Ity_I32);
11942 DIP("stxssp v%u,%u(r%u)\n", vRS, DS, rA_addr);
11944 assign( EA, ea_rAor0_simm( rA_addr, DS<<2 ) );
11945 assign(high64, unop( Iop_ReinterpI64asF64,
11946 unop( Iop_V128HIto64, getVSReg( vRS+32 ) ) ) );
11948 assign(val32, unop( Iop_ReinterpF32asI32,
11949 unop( Iop_TruncF64asF32,
11950 mkexpr(high64) ) ) );
11951 store( mkexpr(EA), mkexpr( val32 ) );
11953 return True;
11955 default:
11956 vex_printf("dis_fp_pair(ppc) : DS-form wrong opc2\n");
11957 return False;
11959 break;
11961 default: // immediate offset
11962 vex_printf("dis_fp_pair(ppc)(instr)\n");
11963 return False;
11966 if (mode64)
11967 assign( EA_lo, binop(Iop_Add64, mkexpr(EA_hi), mkU64(8)) );
11968 else
11969 assign( EA_lo, binop(Iop_Add32, mkexpr(EA_hi), mkU32(8)) );
11971 assign( frT_hi, getFReg(frT_hi_addr) );
11972 assign( frT_lo, getFReg(frT_lo_addr) );
11974 if (is_load) {
11975 putFReg( frT_hi_addr, load(Ity_F64, mkexpr(EA_hi)) );
11976 putFReg( frT_lo_addr, load(Ity_F64, mkexpr(EA_lo)) );
11977 } else {
11978 store( mkexpr(EA_hi), mkexpr(frT_hi) );
11979 store( mkexpr(EA_lo), mkexpr(frT_lo) );
11982 return True;
11987 Floating Point Merge Instructions
11989 static Bool dis_fp_merge ( UInt theInstr )
11991 /* X-Form */
11992 UInt opc2 = ifieldOPClo10(theInstr);
11993 UChar frD_addr = ifieldRegDS(theInstr);
11994 UChar frA_addr = ifieldRegA(theInstr);
11995 UChar frB_addr = ifieldRegB(theInstr);
11997 IRTemp frD = newTemp(Ity_F64);
11998 IRTemp frA = newTemp(Ity_F64);
11999 IRTemp frB = newTemp(Ity_F64);
12001 assign( frA, getFReg(frA_addr));
12002 assign( frB, getFReg(frB_addr));
12004 switch (opc2) {
12005 case 0x3c6: // fmrgew floating merge even word
12006 DIP("fmrgew fr%u,fr%u,fr%u\n", frD_addr, frA_addr, frB_addr);
12008 assign( frD, unop( Iop_ReinterpI64asF64,
12009 binop( Iop_32HLto64,
12010 unop( Iop_64HIto32,
12011 unop( Iop_ReinterpF64asI64,
12012 mkexpr(frA) ) ),
12013 unop( Iop_64HIto32,
12014 unop( Iop_ReinterpF64asI64,
12015 mkexpr(frB) ) ) ) ) );
12016 break;
12018 case 0x346: // fmrgow floating merge odd word
12019 DIP("fmrgow fr%u,fr%u,fr%u\n", frD_addr, frA_addr, frB_addr);
12021 assign( frD, unop( Iop_ReinterpI64asF64,
12022 binop( Iop_32HLto64,
12023 unop( Iop_64to32,
12024 unop( Iop_ReinterpF64asI64,
12025 mkexpr(frA) ) ),
12026 unop( Iop_64to32,
12027 unop( Iop_ReinterpF64asI64,
12028 mkexpr(frB) ) ) ) ) );
12029 break;
12031 default:
12032 vex_printf("dis_fp_merge(ppc)(opc2)\n");
12033 return False;
12036 putFReg( frD_addr, mkexpr(frD) );
12037 return True;
12041 Floating Point Move Instructions
12043 static Bool dis_fp_move ( UInt theInstr )
12045 /* X-Form */
12046 UChar opc1 = ifieldOPC(theInstr);
12047 UChar frD_addr = ifieldRegDS(theInstr);
12048 UChar frA_addr = ifieldRegA(theInstr);
12049 UChar frB_addr = ifieldRegB(theInstr);
12050 UInt opc2 = ifieldOPClo10(theInstr);
12051 UChar flag_rC = ifieldBIT0(theInstr);
12053 IRTemp frD = newTemp(Ity_F64);
12054 IRTemp frB = newTemp(Ity_F64);
12055 IRTemp itmpB = newTemp(Ity_F64);
12056 IRTemp frA;
12057 IRTemp signA;
12058 IRTemp hiD;
12060 if (opc1 != 0x3F || (frA_addr != 0 && opc2 != 0x008)) {
12061 vex_printf("dis_fp_move(ppc)(instr)\n");
12062 return False;
12065 assign( frB, getFReg(frB_addr));
12067 switch (opc2) {
12068 case 0x008: // fcpsgn (Floating Copy Sign, ISA_V2.05 p126)
12069 DIP("fcpsgn%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frA_addr,
12070 frB_addr);
12071 signA = newTemp(Ity_I32);
12072 hiD = newTemp(Ity_I32);
12073 itmpB = newTemp(Ity_I64);
12074 frA = newTemp(Ity_F64);
12075 assign( frA, getFReg(frA_addr) );
12077 /* get A's sign bit */
12078 assign(signA, binop(Iop_And32,
12079 unop(Iop_64HIto32, unop(Iop_ReinterpF64asI64,
12080 mkexpr(frA))),
12081 mkU32(0x80000000)) );
12083 assign( itmpB, unop(Iop_ReinterpF64asI64, mkexpr(frB)) );
12085 /* mask off B's sign bit and or in A's sign bit */
12086 assign(hiD, binop(Iop_Or32,
12087 binop(Iop_And32,
12088 unop(Iop_64HIto32,
12089 mkexpr(itmpB)), /* frB's high 32 bits */
12090 mkU32(0x7fffffff)),
12091 mkexpr(signA)) );
12093 /* combine hiD/loB into frD */
12094 assign( frD, unop(Iop_ReinterpI64asF64,
12095 binop(Iop_32HLto64,
12096 mkexpr(hiD),
12097 unop(Iop_64to32,
12098 mkexpr(itmpB)))) ); /* frB's low 32 bits */
12099 break;
12101 case 0x028: // fneg (Floating Negate, PPC32 p416)
12102 DIP("fneg%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
12103 assign( frD, unop( Iop_NegF64, mkexpr(frB) ));
12104 break;
12106 case 0x048: // fmr (Floating Move Register, PPC32 p410)
12107 DIP("fmr%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
12108 assign( frD, mkexpr(frB) );
12109 break;
12111 case 0x088: // fnabs (Floating Negative Absolute Value, PPC32 p415)
12112 DIP("fnabs%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
12113 assign( frD, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr(frB) )));
12114 break;
12116 case 0x108: // fabs (Floating Absolute Value, PPC32 p399)
12117 DIP("fabs%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
12118 assign( frD, unop( Iop_AbsF64, mkexpr(frB) ));
12119 break;
12121 default:
12122 vex_printf("dis_fp_move(ppc)(opc2)\n");
12123 return False;
12126 putFReg( frD_addr, mkexpr(frD) );
12128 /* None of these change FPRF. cr1 is set in the usual way though,
12129 if flag_rC is set. */
12131 if (flag_rC) {
12132 putCR321( 1, mkU8(0) );
12133 putCR0( 1, mkU8(0) );
12136 return True;
12142 Floating Point Status/Control Register Instructions
12144 static Bool dis_fp_scr ( UInt theInstr, Bool GX_level )
12146 /* Many forms - see each switch case */
12147 UChar opc1 = ifieldOPC(theInstr);
12148 UInt opc2 = ifieldOPClo10(theInstr);
12149 UChar flag_rC = ifieldBIT0(theInstr);
12151 if (opc1 != 0x3F) {
12152 vex_printf("dis_fp_scr(ppc)(instr)\n");
12153 return False;
12156 switch (opc2) {
12157 case 0x026: { // mtfsb1 (Move to FPSCR Bit 1, PPC32 p479)
12158 // Bit crbD of the FPSCR is set.
12159 UChar crbD = ifieldRegDS(theInstr);
12160 UInt b11to20 = IFIELD(theInstr, 11, 10);
12162 if (b11to20 != 0) {
12163 vex_printf("dis_fp_scr(ppc)(instr,mtfsb1)\n");
12164 return False;
12166 DIP("mtfsb1%s crb%d \n", flag_rC ? ".":"", crbD);
12167 putGST_masked( PPC_GST_FPSCR, mkU64( 1 <<( 31 - crbD ) ),
12168 1ULL << ( 31 - crbD ) );
12169 break;
12172 case 0x040: { // mcrfs (Move to Condition Register from FPSCR, PPC32 p465)
12173 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
12174 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
12175 UChar crfS = toUChar( IFIELD( theInstr, 18, 3 ) );
12176 UChar b11to17 = toUChar( IFIELD( theInstr, 11, 7 ) );
12177 IRTemp tmp = newTemp(Ity_I32);
12178 IRExpr* fpscr_all;
12179 if (b21to22 != 0 || b11to17 != 0 || flag_rC != 0) {
12180 vex_printf("dis_fp_scr(ppc)(instr,mcrfs)\n");
12181 return False;
12183 DIP("mcrfs crf%d,crf%d\n", crfD, crfS);
12184 vassert(crfD < 8);
12185 vassert(crfS < 8);
12186 fpscr_all = getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN );
12187 assign( tmp, binop(Iop_And32,
12188 binop(Iop_Shr32,fpscr_all,mkU8(4 * (7-crfS))),
12189 mkU32(0xF)) );
12190 putGST_field( PPC_GST_CR, mkexpr(tmp), crfD );
12191 break;
12194 case 0x046: { // mtfsb0 (Move to FPSCR Bit 0, PPC32 p478)
12195 // Bit crbD of the FPSCR is cleared.
12196 UChar crbD = ifieldRegDS(theInstr);
12197 UInt b11to20 = IFIELD(theInstr, 11, 10);
12199 if (b11to20 != 0) {
12200 vex_printf("dis_fp_scr(ppc)(instr,mtfsb0)\n");
12201 return False;
12203 DIP("mtfsb0%s crb%d\n", flag_rC ? ".":"", crbD);
12204 putGST_masked( PPC_GST_FPSCR, mkU64( 0 ), 1ULL << ( 31 - crbD ) );
12205 break;
12208 case 0x086: { // mtfsfi (Move to FPSCR Field Immediate, PPC32 p481)
12209 UInt crfD = IFIELD( theInstr, 23, 3 );
12210 UChar b17to22 = toUChar( IFIELD( theInstr, 17, 6 ) );
12211 UChar IMM = toUChar( IFIELD( theInstr, 12, 4 ) );
12212 UChar b11 = toUChar( IFIELD( theInstr, 11, 1 ) );
12213 UChar Wbit = toUChar( IFIELD( theInstr, 16, 1 ) );
12215 if (b17to22 != 0 || b11 != 0 || (Wbit && !GX_level)) {
12216 vex_printf("dis_fp_scr(ppc)(instr,mtfsfi)\n");
12217 return False;
12219 DIP("mtfsfi%s crf%u,%d%s\n", flag_rC ? ".":"", crfD, IMM, Wbit ? ",1":"");
12220 crfD = crfD + (8 * (1 - Wbit) );
12221 putGST_field( PPC_GST_FPSCR, mkU32( IMM ), crfD );
12222 break;
12225 case 0x247: { // mffs (Move from FPSCR, PPC32 p468)
12226 UChar frD_addr = ifieldRegDS(theInstr);
12227 UChar frB_addr = ifieldRegB(theInstr);
12228 IRTemp frB = newTemp(Ity_F64);
12229 UInt b11to12 = IFIELD(theInstr, 19, 2);
12230 UInt b13to15 = IFIELD(theInstr, 16, 3);
12231 UInt RN = IFIELD(theInstr, 11, 2);
12232 UInt DRN = IFIELD(theInstr, 11, 3);
12234 /* The FPSCR_DRN, FPSCR_RN and FPSCR_FPCC are all stored in
12235 * their own 8-bit entries with distinct offsets. The FPSCR
12236 * register is handled as two 32-bit values. We need to
12237 * assemble the pieces into the single 64-bit value to return.
12239 IRExpr* fpscr_lower
12240 = binop( Iop_Or32,
12241 getGST_masked( PPC_GST_FPSCR, (MASK_FPSCR_RN | MASK_FPSCR_C_FPCC) ),
12242 binop( Iop_Or32,
12243 binop( Iop_Shl32,
12244 getC(),
12245 mkU8(63-47) ) ,
12246 binop( Iop_Shl32,
12247 getFPCC(),
12248 mkU8(63-51) ) ) );
12249 IRExpr* fpscr_upper = getGST_masked_upper( PPC_GST_FPSCR, MASK_FPSCR_DRN );
12251 if ((b11to12 == 0) && (b13to15 == 0)) {
12252 DIP("mffs%s fr%u\n", flag_rC ? ".":"", frD_addr);
12253 putFReg( frD_addr,
12254 unop( Iop_ReinterpI64asF64,
12255 binop( Iop_32HLto64, fpscr_upper, fpscr_lower ) ) );
12257 } else if ((b11to12 == 0) && (b13to15 == 1)) {
12258 DIP("mffsce fr%u\n", frD_addr);
12259 /* Technically as of 4/5/2017 we are not tracking VE, OE, UE, ZE,
12260 or XE but in case that changes in the future, do the masking. */
12261 putFReg( frD_addr,
12262 unop( Iop_ReinterpI64asF64,
12263 binop( Iop_32HLto64, fpscr_upper,
12264 binop( Iop_And32, fpscr_lower,
12265 mkU32( 0xFFFFFF07 ) ) ) ) );
12267 } else if ((b11to12 == 2) && (b13to15 == 4)) {
12268 IRTemp frB_int = newTemp(Ity_I64);
12270 DIP("mffscdrn fr%u,fr%u\n", frD_addr, frB_addr);
12272 assign( frB, getFReg(frB_addr));
12273 assign( frB_int, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
12275 /* Clear all of the FPSCR bits except for the DRN field, VE,
12276 OE, UE, ZE and XE bits and write the result to the frD
12277 register. Note, currently the exception bits are not tracked but
12278 will mask anyway in case that changes in the future. */
12279 putFReg( frD_addr,
12280 unop( Iop_ReinterpI64asF64,
12281 binop( Iop_32HLto64,
12282 binop( Iop_And32, mkU32(0x7), fpscr_upper ),
12283 binop( Iop_And32, mkU32(0xFF), fpscr_lower ) ) ) );
12285 /* Put new_DRN bits into the FPSCR register */
12286 putGST_masked( PPC_GST_FPSCR, mkexpr( frB_int ), MASK_FPSCR_DRN );
12288 } else if ((b11to12 == 2) && (b13to15 == 5)) {
12289 DIP("mffscdrni fr%u,%u\n", frD_addr, DRN);
12291 /* Clear all of the FPSCR bits except for the DRN field, VE,
12292 OE, UE, ZE and XE bits and write the result to the frD
12293 register. Note, currently the exception bits are not tracked but
12294 will mask anyway in case that changes in the future. */
12295 putFReg( frD_addr,
12296 unop( Iop_ReinterpI64asF64,
12297 binop( Iop_32HLto64,
12298 binop( Iop_And32, mkU32(0x7), fpscr_upper ),
12299 binop( Iop_And32, mkU32(0xFF), fpscr_lower ) ) ) );
12301 /* Put new_DRN bits into the FPSCR register */
12302 putGST_masked( PPC_GST_FPSCR, binop( Iop_32HLto64, mkU32( DRN ),
12303 mkU32( 0 ) ), MASK_FPSCR_DRN );
12305 } else if ((b11to12 == 2) && (b13to15 == 6)) {
12306 IRTemp frB_int = newTemp(Ity_I64);
12308 DIP("mffscrn fr%u,fr%u\n", frD_addr,frB_addr);
12310 assign( frB, getFReg(frB_addr));
12311 assign( frB_int, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
12313 /* Clear all of the FPSCR bits except for the DRN field, VE,
12314 OE, UE, ZE and XE bits and write the result to the frD
12315 register. Note, currently the exception bits are not tracked but
12316 will mask anyway in case that changes in the future. */
12317 putFReg( frD_addr,
12318 unop( Iop_ReinterpI64asF64,
12319 binop( Iop_32HLto64,
12320 binop( Iop_And32, mkU32(0x7), fpscr_upper ),
12321 binop( Iop_And32, mkU32(0xFF), fpscr_lower ) ) ) );
12323 /* Put new_CRN bits into the FPSCR register */
12324 putGST_masked( PPC_GST_FPSCR, mkexpr( frB_int ), MASK_FPSCR_RN );
12326 } else if ((b11to12 == 2) && (b13to15 == 7)) {
12327 DIP("mffscrni fr%u,%u\n", frD_addr, RN);
12329 /* Clear all of the FPSCR bits except for the DRN field, VE,
12330 OE, UE, ZE and XE bits and write the result to the frD
12331 register. Note, currently the exception bits are not tracked but
12332 will mask anyway in case that changes in the future. */
12333 putFReg( frD_addr,
12334 unop( Iop_ReinterpI64asF64,
12335 binop( Iop_32HLto64,
12336 binop( Iop_And32, mkU32(0x7), fpscr_upper ),
12337 binop( Iop_And32, mkU32(0xFF), fpscr_lower ) ) ) );
12339 /* Put new_RN bits into the FPSCR register */
12340 putGST_masked( PPC_GST_FPSCR, binop( Iop_32HLto64, mkU32( 0 ),
12341 mkU32( RN ) ), MASK_FPSCR_RN );
12343 } else if ((b11to12 == 3) && (b13to15 == 0)) {
12344 DIP("mffsl fr%u\n", frD_addr);
12345 /* Technically as of 4/5/2017 we are not tracking VE, OE, UE, ZE,
12346 XE, FR, FI, C, FL, FG, FE, FU. Also only track DRN in the upper
12347 bits but in case that changes in the future we will do the
12348 masking. */
12349 putFReg( frD_addr,
12350 unop( Iop_ReinterpI64asF64,
12351 binop( Iop_32HLto64,
12352 binop( Iop_And32, fpscr_upper,
12353 mkU32( 0x7 ) ),
12354 binop( Iop_And32, fpscr_lower,
12355 mkU32( 0x7F0FF ) ) ) ) );
12356 } else {
12357 vex_printf("dis_fp_scr(ppc)(mff**) Unrecognized instruction.\n");
12358 return False;
12360 break;
12363 case 0x2C7: { // mtfsf (Move to FPSCR Fields, PPC32 p480)
12364 UChar b25 = toUChar( IFIELD(theInstr, 25, 1) );
12365 UChar FM = toUChar( IFIELD(theInstr, 17, 8) );
12366 UChar frB_addr = ifieldRegB(theInstr);
12367 IRTemp frB = newTemp(Ity_F64);
12368 IRTemp rB_64 = newTemp( Ity_I64 );
12369 Int i;
12370 ULong mask;
12371 UChar Wbit;
12372 #define BFP_MASK_SEED 0x3000000000000000ULL
12373 #define DFP_MASK_SEED 0x7000000000000000ULL
12375 if (GX_level) {
12376 /* This implies that Decimal Floating Point is supported, and the
12377 * FPSCR must be managed as a 64-bit register.
12379 Wbit = toUChar( IFIELD(theInstr, 16, 1) );
12380 } else {
12381 Wbit = 0;
12384 if (b25 == 1) {
12385 /* new 64 bit move variant for power 6. If L field (bit 25) is
12386 * a one do a full 64 bit move. Note, the FPSCR is not really
12387 * properly modeled. This instruciton only changes the value of
12388 * the rounding mode bit fields RN, FPCC and DRN. The HW exception bits
12389 * do not get set in the simulator. 1/12/09
12391 DIP("mtfsf%s %d,fr%u (L=1)\n", flag_rC ? ".":"", FM, frB_addr);
12392 mask = 0x1F0001F003;
12394 } else {
12395 DIP("mtfsf%s %d,fr%u\n", flag_rC ? ".":"", FM, frB_addr);
12396 // Build 32bit mask from FM:
12397 mask = 0;
12398 for (i=0; i<8; i++) {
12399 if ((FM & (1<<(7-i))) == 1) {
12400 /* FPSCR field k is set to the contents of the corresponding
12401 * field of register FRB, where k = i+8x(1-W). In the Power
12402 * ISA, register field numbering is from left to right, so field
12403 * 15 is the least significant field in a 64-bit register. To
12404 * generate the mask, we set all the appropriate rounding mode
12405 * bits in the highest order nibble (field 0) and shift right
12406 * 'k x nibble length'.
12408 if (Wbit)
12409 mask |= DFP_MASK_SEED >> ( 4 * ( i + 8 * ( 1 - Wbit ) ) );
12410 else
12411 mask |= BFP_MASK_SEED >> ( 4 * ( i + 8 * ( 1 - Wbit ) ) );
12413 if ((FM & (1<<(7-i))) == 0x2) { //set the FPCC bits
12414 mask |= 0xF000;
12416 if ((FM & (1<<(7-i))) == 0x4) { //set the Floating-Point Class Descriptor (C) bit
12417 mask |= 0x10000;
12421 assign( frB, getFReg(frB_addr));
12422 assign( rB_64, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
12423 putGST_masked( PPC_GST_FPSCR, mkexpr( rB_64 ), mask );
12424 break;
12427 default:
12428 vex_printf("dis_fp_scr(ppc)(opc2)\n");
12429 return False;
12431 return True;
12434 /*------------------------------------------------------------*/
12435 /*--- Decimal Floating Point (DFP) Helper functions ---*/
12436 /*------------------------------------------------------------*/
12437 #define DFP_LONG 1
12438 #define DFP_EXTND 2
12439 #define DFP_LONG_BIAS 398
12440 #define DFP_LONG_ENCODED_FIELD_MASK 0x1F00
12441 #define DFP_EXTND_BIAS 6176
12442 #define DFP_EXTND_ENCODED_FIELD_MASK 0x1F000
12443 #define DFP_LONG_EXP_MSK 0XFF
12444 #define DFP_EXTND_EXP_MSK 0XFFF
12446 #define DFP_G_FIELD_LONG_MASK 0x7FFC0000 // upper 32-bits only
12447 #define DFP_LONG_GFIELD_RT_SHIFT (63 - 13 - 32) // adj for upper 32-bits
12448 #define DFP_G_FIELD_EXTND_MASK 0x7FFFC000 // upper 32-bits only
12449 #define DFP_EXTND_GFIELD_RT_SHIFT (63 - 17 - 32) //adj for upper 32 bits
12450 #define DFP_T_FIELD_LONG_MASK 0x3FFFF // mask for upper 32-bits
12451 #define DFP_T_FIELD_EXTND_MASK 0x03FFFF // mask for upper 32-bits
12452 #define DFP_LONG_EXP_MAX 369 // biased max
12453 #define DFP_LONG_EXP_MIN 0 // biased min
12454 #define DFP_EXTND_EXP_MAX 6111 // biased max
12455 #define DFP_EXTND_EXP_MIN 0 // biased min
12456 #define DFP_LONG_MAX_SIG_DIGITS 16
12457 #define DFP_EXTND_MAX_SIG_DIGITS 34
12458 #define MAX_DIGITS_IN_STRING 8
12461 #define AND(x, y) binop( Iop_And32, x, y )
12462 #define AND4(w, x, y, z) AND( AND( w, x ), AND( y, z ) )
12463 #define OR(x, y) binop( Iop_Or32, x, y )
12464 #define OR3(x, y, z) OR( x, OR( y, z ) )
12465 #define OR4(w, x, y, z) OR( OR( w, x ), OR( y, z ) )
12466 #define NOT(x) unop( Iop_1Uto32, unop( Iop_Not1, unop( Iop_32to1, mkexpr( x ) ) ) )
12468 #define SHL(value, by) binop( Iop_Shl32, value, mkU8( by ) )
12469 #define SHR(value, by) binop( Iop_Shr32, value, mkU8( by ) )
12471 #define BITS5(_b4,_b3,_b2,_b1,_b0) \
12472 (((_b4) << 4) | ((_b3) << 3) | ((_b2) << 2) | \
12473 ((_b1) << 1) | ((_b0) << 0))
12475 static IRExpr * Gfield_encoding( IRExpr * lmexp, IRExpr * lmd32 )
12477 IRTemp lmd_07_mask = newTemp( Ity_I32 );
12478 IRTemp lmd_8_mask = newTemp( Ity_I32 );
12479 IRTemp lmd_9_mask = newTemp( Ity_I32 );
12480 IRTemp lmexp_00_mask = newTemp( Ity_I32 );
12481 IRTemp lmexp_01_mask = newTemp( Ity_I32 );
12482 IRTemp lmexp_10_mask = newTemp( Ity_I32 );
12483 IRTemp lmd_07_val = newTemp( Ity_I32 );
12484 IRTemp lmd_8_val = newTemp( Ity_I32 );
12485 IRTemp lmd_9_val = newTemp( Ity_I32 );
12487 /* The encodig is as follows:
12488 * lmd - left most digit
12489 * lme - left most 2-bits of the exponent
12491 * lmd
12492 * 0 - 7 (lmexp << 3) | lmd
12493 * 8 0b11000 (24 decimal) if lme=0b00;
12494 * 0b11010 (26 decimal) if lme=0b01;
12495 * 0b11100 (28 decimal) if lme=0b10;
12496 * 9 0b11001 (25 decimal) if lme=0b00;
12497 * 0b11011 (27 decimal) if lme=0b01;
12498 * 0b11101 (29 decimal) if lme=0b10;
12501 /* Generate the masks for each condition */
12502 assign( lmd_07_mask,
12503 unop( Iop_1Sto32, binop( Iop_CmpLE32U, lmd32, mkU32( 7 ) ) ) );
12504 assign( lmd_8_mask,
12505 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmd32, mkU32( 8 ) ) ) );
12506 assign( lmd_9_mask,
12507 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmd32, mkU32( 9 ) ) ) );
12508 assign( lmexp_00_mask,
12509 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 0 ) ) ) );
12510 assign( lmexp_01_mask,
12511 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 1 ) ) ) );
12512 assign( lmexp_10_mask,
12513 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 2 ) ) ) );
12515 /* Generate the values for each LMD condition, assuming the condition
12516 * is TRUE.
12518 assign( lmd_07_val,
12519 binop( Iop_Or32, binop( Iop_Shl32, lmexp, mkU8( 3 ) ), lmd32 ) );
12520 assign( lmd_8_val,
12521 binop( Iop_Or32,
12522 binop( Iop_Or32,
12523 binop( Iop_And32,
12524 mkexpr( lmexp_00_mask ),
12525 mkU32( 24 ) ),
12526 binop( Iop_And32,
12527 mkexpr( lmexp_01_mask ),
12528 mkU32( 26 ) ) ),
12529 binop( Iop_And32, mkexpr( lmexp_10_mask ), mkU32( 28 ) ) ) );
12530 assign( lmd_9_val,
12531 binop( Iop_Or32,
12532 binop( Iop_Or32,
12533 binop( Iop_And32,
12534 mkexpr( lmexp_00_mask ),
12535 mkU32( 25 ) ),
12536 binop( Iop_And32,
12537 mkexpr( lmexp_01_mask ),
12538 mkU32( 27 ) ) ),
12539 binop( Iop_And32, mkexpr( lmexp_10_mask ), mkU32( 29 ) ) ) );
12541 /* generate the result from the possible LMD values */
12542 return binop( Iop_Or32,
12543 binop( Iop_Or32,
12544 binop( Iop_And32,
12545 mkexpr( lmd_07_mask ),
12546 mkexpr( lmd_07_val ) ),
12547 binop( Iop_And32,
12548 mkexpr( lmd_8_mask ),
12549 mkexpr( lmd_8_val ) ) ),
12550 binop( Iop_And32, mkexpr( lmd_9_mask ), mkexpr( lmd_9_val ) ) );
12553 static void Get_lmd( IRTemp * lmd, IRExpr * gfield_0_4 )
12555 /* Extract the exponent and the left most digit of the mantissa
12556 * from the G field bits [0:4].
12558 IRTemp lmd_07_mask = newTemp( Ity_I32 );
12559 IRTemp lmd_8_00_mask = newTemp( Ity_I32 );
12560 IRTemp lmd_8_01_mask = newTemp( Ity_I32 );
12561 IRTemp lmd_8_10_mask = newTemp( Ity_I32 );
12562 IRTemp lmd_9_00_mask = newTemp( Ity_I32 );
12563 IRTemp lmd_9_01_mask = newTemp( Ity_I32 );
12564 IRTemp lmd_9_10_mask = newTemp( Ity_I32 );
12566 IRTemp lmd_07_val = newTemp( Ity_I32 );
12567 IRTemp lmd_8_val = newTemp( Ity_I32 );
12568 IRTemp lmd_9_val = newTemp( Ity_I32 );
12570 /* The left most digit (LMD) encoding is as follows:
12571 * lmd
12572 * 0 - 7 (lmexp << 3) | lmd
12573 * 8 0b11000 (24 decimal) if lme=0b00;
12574 * 0b11010 (26 decimal) if lme=0b01;
12575 * 0b11100 (28 decimal) if lme=0b10
12576 * 9 0b11001 (25 decimal) if lme=0b00;
12577 * 0b11011 (27 decimal) if lme=0b01;
12578 * 0b11101 (29 decimal) if lme=0b10;
12581 /* Generate the masks for each condition of LMD and exponent bits */
12582 assign( lmd_07_mask,
12583 unop( Iop_1Sto32, binop( Iop_CmpLE32U,
12584 gfield_0_4,
12585 mkU32( BITS5(1,0,1,1,1) ) ) ) );
12586 assign( lmd_8_00_mask,
12587 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
12588 gfield_0_4,
12589 mkU32( BITS5(1,1,0,0,0) ) ) ) );
12590 assign( lmd_8_01_mask,
12591 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
12592 gfield_0_4,
12593 mkU32( BITS5(1,1,0,1,0) ) ) ) );
12594 assign( lmd_8_10_mask,
12595 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
12596 gfield_0_4,
12597 mkU32( BITS5(1,1,1,0,0) ) ) ) );
12598 assign( lmd_9_00_mask,
12599 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
12600 gfield_0_4,
12601 mkU32( BITS5(1,1,0,0,1) ) ) ) );
12602 assign( lmd_9_01_mask,
12603 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
12604 gfield_0_4,
12605 mkU32( BITS5(1,1,0,1,1) ) ) ) );
12606 assign( lmd_9_10_mask,
12607 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
12608 gfield_0_4,
12609 mkU32( BITS5(1,1,1,0,1) ) ) ) );
12611 /* Generate the values for each LMD condition, assuming the condition
12612 * is TRUE.
12614 assign( lmd_07_val, binop( Iop_And32, gfield_0_4, mkU32( 0x7 ) ) );
12615 assign( lmd_8_val, mkU32( 0x8 ) );
12616 assign( lmd_9_val, mkU32( 0x9 ) );
12618 assign( *lmd,
12619 OR( OR3 ( AND( mkexpr( lmd_07_mask ), mkexpr( lmd_07_val ) ),
12620 AND( mkexpr( lmd_8_00_mask ), mkexpr( lmd_8_val ) ),
12621 AND( mkexpr( lmd_8_01_mask ), mkexpr( lmd_8_val ) )),
12622 OR4( AND( mkexpr( lmd_8_10_mask ), mkexpr( lmd_8_val ) ),
12623 AND( mkexpr( lmd_9_00_mask ), mkexpr( lmd_9_val ) ),
12624 AND( mkexpr( lmd_9_01_mask ), mkexpr( lmd_9_val ) ),
12625 AND( mkexpr( lmd_9_10_mask ), mkexpr( lmd_9_val ) )
12626 ) ) );
12629 #define DIGIT1_SHR 4 // shift digit 1 to bottom 4 bits
12630 #define DIGIT2_SHR 8 // shift digit 2 to bottom 4 bits
12631 #define DIGIT3_SHR 12
12632 #define DIGIT4_SHR 16
12633 #define DIGIT5_SHR 20
12634 #define DIGIT6_SHR 24
12635 #define DIGIT7_SHR 28
12637 static IRExpr * bcd_digit_inval( IRExpr * bcd_u, IRExpr * bcd_l )
12639 /* 60-bit BCD string stored in two 32-bit values. Check that each,
12640 * digit is a valid BCD number, i.e. less then 9.
12642 IRTemp valid = newTemp( Ity_I32 );
12644 assign( valid,
12645 AND4( AND4 ( unop( Iop_1Sto32,
12646 binop( Iop_CmpLE32U,
12647 binop( Iop_And32,
12648 bcd_l,
12649 mkU32 ( 0xF ) ),
12650 mkU32( 0x9 ) ) ),
12651 unop( Iop_1Sto32,
12652 binop( Iop_CmpLE32U,
12653 binop( Iop_And32,
12654 binop( Iop_Shr32,
12655 bcd_l,
12656 mkU8 ( DIGIT1_SHR ) ),
12657 mkU32 ( 0xF ) ),
12658 mkU32( 0x9 ) ) ),
12659 unop( Iop_1Sto32,
12660 binop( Iop_CmpLE32U,
12661 binop( Iop_And32,
12662 binop( Iop_Shr32,
12663 bcd_l,
12664 mkU8 ( DIGIT2_SHR ) ),
12665 mkU32 ( 0xF ) ),
12666 mkU32( 0x9 ) ) ),
12667 unop( Iop_1Sto32,
12668 binop( Iop_CmpLE32U,
12669 binop( Iop_And32,
12670 binop( Iop_Shr32,
12671 bcd_l,
12672 mkU8 ( DIGIT3_SHR ) ),
12673 mkU32 ( 0xF ) ),
12674 mkU32( 0x9 ) ) ) ),
12675 AND4 ( unop( Iop_1Sto32,
12676 binop( Iop_CmpLE32U,
12677 binop( Iop_And32,
12678 binop( Iop_Shr32,
12679 bcd_l,
12680 mkU8 ( DIGIT4_SHR ) ),
12681 mkU32 ( 0xF ) ),
12682 mkU32( 0x9 ) ) ),
12683 unop( Iop_1Sto32,
12684 binop( Iop_CmpLE32U,
12685 binop( Iop_And32,
12686 binop( Iop_Shr32,
12687 bcd_l,
12688 mkU8 ( DIGIT5_SHR ) ),
12689 mkU32 ( 0xF ) ),
12690 mkU32( 0x9 ) ) ),
12691 unop( Iop_1Sto32,
12692 binop( Iop_CmpLE32U,
12693 binop( Iop_And32,
12694 binop( Iop_Shr32,
12695 bcd_l,
12696 mkU8 ( DIGIT6_SHR ) ),
12697 mkU32 ( 0xF ) ),
12698 mkU32( 0x9 ) ) ),
12699 unop( Iop_1Sto32,
12700 binop( Iop_CmpLE32U,
12701 binop( Iop_And32,
12702 binop( Iop_Shr32,
12703 bcd_l,
12704 mkU8 ( DIGIT7_SHR ) ),
12705 mkU32 ( 0xF ) ),
12706 mkU32( 0x9 ) ) ) ),
12707 AND4( unop( Iop_1Sto32,
12708 binop( Iop_CmpLE32U,
12709 binop( Iop_And32,
12710 bcd_u,
12711 mkU32 ( 0xF ) ),
12712 mkU32( 0x9 ) ) ),
12713 unop( Iop_1Sto32,
12714 binop( Iop_CmpLE32U,
12715 binop( Iop_And32,
12716 binop( Iop_Shr32,
12717 bcd_u,
12718 mkU8 ( DIGIT1_SHR ) ),
12719 mkU32 ( 0xF ) ),
12720 mkU32( 0x9 ) ) ),
12721 unop( Iop_1Sto32,
12722 binop( Iop_CmpLE32U,
12723 binop( Iop_And32,
12724 binop( Iop_Shr32,
12725 bcd_u,
12726 mkU8 ( DIGIT2_SHR ) ),
12727 mkU32 ( 0xF ) ),
12728 mkU32( 0x9 ) ) ),
12729 unop( Iop_1Sto32,
12730 binop( Iop_CmpLE32U,
12731 binop( Iop_And32,
12732 binop( Iop_Shr32,
12733 bcd_u,
12734 mkU8 ( DIGIT3_SHR ) ),
12735 mkU32 ( 0xF ) ),
12736 mkU32( 0x9 ) ) ) ),
12737 AND4( unop( Iop_1Sto32,
12738 binop( Iop_CmpLE32U,
12739 binop( Iop_And32,
12740 binop( Iop_Shr32,
12741 bcd_u,
12742 mkU8 ( DIGIT4_SHR ) ),
12743 mkU32 ( 0xF ) ),
12744 mkU32( 0x9 ) ) ),
12745 unop( Iop_1Sto32,
12746 binop( Iop_CmpLE32U,
12747 binop( Iop_And32,
12748 binop( Iop_Shr32,
12749 bcd_u,
12750 mkU8 ( DIGIT5_SHR ) ),
12751 mkU32 ( 0xF ) ),
12752 mkU32( 0x9 ) ) ),
12753 unop( Iop_1Sto32,
12754 binop( Iop_CmpLE32U,
12755 binop( Iop_And32,
12756 binop( Iop_Shr32,
12757 bcd_u,
12758 mkU8 ( DIGIT6_SHR ) ),
12759 mkU32 ( 0xF ) ),
12760 mkU32( 0x9 ) ) ),
12761 unop( Iop_1Sto32,
12762 binop( Iop_CmpLE32U,
12763 binop( Iop_And32,
12764 binop( Iop_Shr32,
12765 bcd_u,
12766 mkU8 ( DIGIT7_SHR ) ),
12767 mkU32 ( 0xF ) ),
12768 mkU32( 0x9 ) ) ) ) ) );
12770 return unop( Iop_Not32, mkexpr( valid ) );
12772 #undef DIGIT1_SHR
12773 #undef DIGIT2_SHR
12774 #undef DIGIT3_SHR
12775 #undef DIGIT4_SHR
12776 #undef DIGIT5_SHR
12777 #undef DIGIT6_SHR
12778 #undef DIGIT7_SHR
12780 static IRExpr * Generate_neg_sign_mask( IRExpr * sign )
12782 return binop( Iop_Or32,
12783 unop( Iop_1Sto32, binop( Iop_CmpEQ32, sign, mkU32( 0xB ) ) ),
12784 unop( Iop_1Sto32, binop( Iop_CmpEQ32, sign, mkU32( 0xD ) ) )
12788 static IRExpr * Generate_pos_sign_mask( IRExpr * sign )
12790 return binop( Iop_Or32,
12791 binop( Iop_Or32,
12792 unop( Iop_1Sto32,
12793 binop( Iop_CmpEQ32, sign, mkU32( 0xA ) ) ),
12794 unop( Iop_1Sto32,
12795 binop( Iop_CmpEQ32, sign, mkU32( 0xC ) ) ) ),
12796 binop( Iop_Or32,
12797 unop( Iop_1Sto32,
12798 binop( Iop_CmpEQ32, sign, mkU32( 0xE ) ) ),
12799 unop( Iop_1Sto32,
12800 binop( Iop_CmpEQ32, sign, mkU32( 0xF ) ) ) ) );
12803 static IRExpr * Generate_sign_bit( IRExpr * pos_sign_mask,
12804 IRExpr * neg_sign_mask )
12806 return binop( Iop_Or32,
12807 binop( Iop_And32, neg_sign_mask, mkU32( 0x80000000 ) ),
12808 binop( Iop_And32, pos_sign_mask, mkU32( 0x00000000 ) ) );
12811 static IRExpr * Generate_inv_mask( IRExpr * invalid_bcd_mask,
12812 IRExpr * pos_sign_mask,
12813 IRExpr * neg_sign_mask )
12814 /* first argument is all 1's if the BCD string had an invalid digit in it. */
12816 return binop( Iop_Or32,
12817 invalid_bcd_mask,
12818 unop( Iop_1Sto32,
12819 binop( Iop_CmpEQ32,
12820 binop( Iop_Or32, pos_sign_mask, neg_sign_mask ),
12821 mkU32( 0x0 ) ) ) );
12824 static void Generate_132_bit_bcd_string( IRExpr * frBI64_hi, IRExpr * frBI64_lo,
12825 IRTemp * top_12_l, IRTemp * mid_60_u,
12826 IRTemp * mid_60_l, IRTemp * low_60_u,
12827 IRTemp * low_60_l)
12829 IRTemp tmplow60 = newTemp( Ity_I64 );
12830 IRTemp tmpmid60 = newTemp( Ity_I64 );
12831 IRTemp tmptop12 = newTemp( Ity_I64 );
12832 IRTemp low_50 = newTemp( Ity_I64 );
12833 IRTemp mid_50 = newTemp( Ity_I64 );
12834 IRTemp top_10 = newTemp( Ity_I64 );
12835 IRTemp top_12_u = newTemp( Ity_I32 ); // only needed for a dummy arg
12837 /* Convert the 110-bit densely packed BCD string to a 128-bit BCD string */
12839 /* low_50[49:0] = ((frBI64_lo[49:32] << 14) | frBI64_lo[31:0]) */
12840 assign( low_50,
12841 binop( Iop_32HLto64,
12842 binop( Iop_And32,
12843 unop( Iop_64HIto32, frBI64_lo ),
12844 mkU32( 0x3FFFF ) ),
12845 unop( Iop_64to32, frBI64_lo ) ) );
12847 /* Convert the 50 bit densely packed BCD string to a 60 bit
12848 * BCD string.
12850 assign( tmplow60, unop( Iop_DPBtoBCD, mkexpr( low_50 ) ) );
12851 assign( *low_60_u, unop( Iop_64HIto32, mkexpr( tmplow60 ) ) );
12852 assign( *low_60_l, unop( Iop_64to32, mkexpr( tmplow60 ) ) );
12854 /* mid_50[49:0] = ((frBI64_hi[35:32] << 14) | frBI64_hi[31:18]) |
12855 * ((frBI64_hi[17:0] << 14) | frBI64_lo[63:50])
12857 assign( mid_50,
12858 binop( Iop_32HLto64,
12859 binop( Iop_Or32,
12860 binop( Iop_Shl32,
12861 binop( Iop_And32,
12862 unop( Iop_64HIto32, frBI64_hi ),
12863 mkU32( 0xF ) ),
12864 mkU8( 14 ) ),
12865 binop( Iop_Shr32,
12866 unop( Iop_64to32, frBI64_hi ),
12867 mkU8( 18 ) ) ),
12868 binop( Iop_Or32,
12869 binop( Iop_Shl32,
12870 unop( Iop_64to32, frBI64_hi ),
12871 mkU8( 14 ) ),
12872 binop( Iop_Shr32,
12873 unop( Iop_64HIto32, frBI64_lo ),
12874 mkU8( 18 ) ) ) ) );
12876 /* Convert the 50 bit densely packed BCD string to a 60 bit
12877 * BCD string.
12879 assign( tmpmid60, unop( Iop_DPBtoBCD, mkexpr( mid_50 ) ) );
12880 assign( *mid_60_u, unop( Iop_64HIto32, mkexpr( tmpmid60 ) ) );
12881 assign( *mid_60_l, unop( Iop_64to32, mkexpr( tmpmid60 ) ) );
12883 /* top_10[49:0] = frBI64_hi[45:36]) | */
12884 assign( top_10,
12885 binop( Iop_32HLto64,
12886 mkU32( 0 ),
12887 binop( Iop_And32,
12888 binop( Iop_Shr32,
12889 unop( Iop_64HIto32, frBI64_hi ),
12890 mkU8( 4 ) ),
12891 mkU32( 0x3FF ) ) ) );
12893 /* Convert the 10 bit densely packed BCD string to a 12 bit
12894 * BCD string.
12896 assign( tmptop12, unop( Iop_DPBtoBCD, mkexpr( top_10 ) ) );
12897 assign( top_12_u, unop( Iop_64HIto32, mkexpr( tmptop12 ) ) );
12898 assign( *top_12_l, unop( Iop_64to32, mkexpr( tmptop12 ) ) );
12901 static void Count_zeros( int start, IRExpr * init_cnt, IRExpr * init_flag,
12902 IRTemp * final_cnt, IRTemp * final_flag,
12903 IRExpr * string )
12905 IRTemp cnt[MAX_DIGITS_IN_STRING + 1];IRTemp flag[MAX_DIGITS_IN_STRING+1];
12906 int digits = MAX_DIGITS_IN_STRING;
12907 int i;
12909 cnt[start-1] = newTemp( Ity_I8 );
12910 flag[start-1] = newTemp( Ity_I8 );
12911 assign( cnt[start-1], init_cnt);
12912 assign( flag[start-1], init_flag);
12914 for ( i = start; i <= digits; i++) {
12915 cnt[i] = newTemp( Ity_I8 );
12916 flag[i] = newTemp( Ity_I8 );
12917 assign( cnt[i],
12918 binop( Iop_Add8,
12919 mkexpr( cnt[i-1] ),
12920 binop(Iop_And8,
12921 unop( Iop_1Uto8,
12922 binop(Iop_CmpEQ32,
12923 binop(Iop_And32,
12924 string,
12925 mkU32( 0xF <<
12926 ( ( digits - i ) * 4) ) ),
12927 mkU32( 0 ) ) ),
12928 binop( Iop_Xor8, /* complement flag */
12929 mkexpr( flag[i - 1] ),
12930 mkU8( 0xFF ) ) ) ) );
12932 /* set flag to 1 if digit was not a zero */
12933 assign( flag[i],
12934 binop(Iop_Or8,
12935 unop( Iop_1Sto8,
12936 binop(Iop_CmpNE32,
12937 binop(Iop_And32,
12938 string,
12939 mkU32( 0xF <<
12940 ( (digits - i) * 4) ) ),
12941 mkU32( 0 ) ) ),
12942 mkexpr( flag[i - 1] ) ) );
12945 *final_cnt = cnt[digits];
12946 *final_flag = flag[digits];
12949 static IRExpr * Count_leading_zeros_60( IRExpr * lmd, IRExpr * upper_28,
12950 IRExpr * low_32 )
12952 IRTemp num_lmd = newTemp( Ity_I8 );
12953 IRTemp num_upper = newTemp( Ity_I8 );
12954 IRTemp num_low = newTemp( Ity_I8 );
12955 IRTemp lmd_flag = newTemp( Ity_I8 );
12956 IRTemp upper_flag = newTemp( Ity_I8 );
12957 IRTemp low_flag = newTemp( Ity_I8 );
12959 assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
12960 assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
12962 Count_zeros( 2,
12963 mkexpr( num_lmd ),
12964 mkexpr( lmd_flag ),
12965 &num_upper,
12966 &upper_flag,
12967 upper_28 );
12969 Count_zeros( 1,
12970 mkexpr( num_upper ),
12971 mkexpr( upper_flag ),
12972 &num_low,
12973 &low_flag,
12974 low_32 );
12976 return mkexpr( num_low );
12979 static IRExpr * Count_leading_zeros_128( IRExpr * lmd, IRExpr * top_12_l,
12980 IRExpr * mid_60_u, IRExpr * mid_60_l,
12981 IRExpr * low_60_u, IRExpr * low_60_l)
12983 IRTemp num_lmd = newTemp( Ity_I8 );
12984 IRTemp num_top = newTemp( Ity_I8 );
12985 IRTemp num_mid_u = newTemp( Ity_I8 );
12986 IRTemp num_mid_l = newTemp( Ity_I8 );
12987 IRTemp num_low_u = newTemp( Ity_I8 );
12988 IRTemp num_low_l = newTemp( Ity_I8 );
12990 IRTemp lmd_flag = newTemp( Ity_I8 );
12991 IRTemp top_flag = newTemp( Ity_I8 );
12992 IRTemp mid_u_flag = newTemp( Ity_I8 );
12993 IRTemp mid_l_flag = newTemp( Ity_I8 );
12994 IRTemp low_u_flag = newTemp( Ity_I8 );
12995 IRTemp low_l_flag = newTemp( Ity_I8 );
12997 /* Check the LMD, digit 34, to see if it is zero. */
12998 assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
13000 assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
13002 Count_zeros( 6,
13003 mkexpr( num_lmd ),
13004 mkexpr( lmd_flag ),
13005 &num_top,
13006 &top_flag,
13007 top_12_l );
13009 Count_zeros( 2,
13010 mkexpr( num_top ),
13011 mkexpr( top_flag ),
13012 &num_mid_u,
13013 &mid_u_flag,
13014 binop( Iop_Or32,
13015 binop( Iop_Shl32, mid_60_u, mkU8( 2 ) ),
13016 binop( Iop_Shr32, mid_60_l, mkU8( 30 ) ) ) );
13018 Count_zeros( 1,
13019 mkexpr( num_mid_u ),
13020 mkexpr( mid_u_flag ),
13021 &num_mid_l,
13022 &mid_l_flag,
13023 mid_60_l );
13025 Count_zeros( 2,
13026 mkexpr( num_mid_l ),
13027 mkexpr( mid_l_flag ),
13028 &num_low_u,
13029 &low_u_flag,
13030 binop( Iop_Or32,
13031 binop( Iop_Shl32, low_60_u, mkU8( 2 ) ),
13032 binop( Iop_Shr32, low_60_l, mkU8( 30 ) ) ) );
13034 Count_zeros( 1,
13035 mkexpr( num_low_u ),
13036 mkexpr( low_u_flag ),
13037 &num_low_l,
13038 &low_l_flag,
13039 low_60_l );
13041 return mkexpr( num_low_l );
13044 static IRExpr * Check_unordered(IRExpr * val)
13046 IRTemp gfield0to5 = newTemp( Ity_I32 );
13048 /* Extract G[0:4] */
13049 assign( gfield0to5,
13050 binop( Iop_And32,
13051 binop( Iop_Shr32, unop( Iop_64HIto32, val ), mkU8( 26 ) ),
13052 mkU32( 0x1F ) ) );
13054 /* Check for unordered, return all 1'x if true */
13055 return binop( Iop_Or32, /* QNaN check */
13056 unop( Iop_1Sto32,
13057 binop( Iop_CmpEQ32,
13058 mkexpr( gfield0to5 ),
13059 mkU32( 0x1E ) ) ),
13060 unop( Iop_1Sto32, /* SNaN check */
13061 binop( Iop_CmpEQ32,
13062 mkexpr( gfield0to5 ),
13063 mkU32( 0x1F ) ) ) );
13066 #undef AND
13067 #undef AND4
13068 #undef OR
13069 #undef OR3
13070 #undef OR4
13071 #undef NOT
13072 #undef SHR
13073 #undef SHL
13074 #undef BITS5
13076 /*------------------------------------------------------------*/
13077 /*--- Decimal Floating Point (DFP) instruction translation ---*/
13078 /*------------------------------------------------------------*/
13080 /* DFP Arithmetic instructions */
13081 static Bool dis_dfp_arith(UInt theInstr)
13083 UInt opc2 = ifieldOPClo10( theInstr );
13084 UChar frS_addr = ifieldRegDS( theInstr );
13085 UChar frA_addr = ifieldRegA( theInstr );
13086 UChar frB_addr = ifieldRegB( theInstr );
13087 UChar flag_rC = ifieldBIT0( theInstr );
13089 IRTemp frA = newTemp( Ity_D64 );
13090 IRTemp frB = newTemp( Ity_D64 );
13091 IRTemp frS = newTemp( Ity_D64 );
13092 IRExpr* round = get_IR_roundingmode_DFP();
13094 /* By default, if flag_RC is set, we will clear cr1 after the
13095 * operation. In reality we should set cr1 to indicate the
13096 * exception status of the operation, but since we're not
13097 * simulating exceptions, the exception status will appear to be
13098 * zero. Hence cr1 should be cleared if this is a . form insn.
13100 Bool clear_CR1 = True;
13102 assign( frA, getDReg( frA_addr ) );
13103 assign( frB, getDReg( frB_addr ) );
13105 switch (opc2) {
13106 case 0x2: // dadd
13107 DIP( "dadd%s fr%u,fr%u,fr%u\n",
13108 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13109 assign( frS, triop( Iop_AddD64, round, mkexpr( frA ), mkexpr( frB ) ) );
13110 break;
13111 case 0x202: // dsub
13112 DIP( "dsub%s fr%u,fr%u,fr%u\n",
13113 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13114 assign( frS, triop( Iop_SubD64, round, mkexpr( frA ), mkexpr( frB ) ) );
13115 break;
13116 case 0x22: // dmul
13117 DIP( "dmul%s fr%u,fr%u,fr%u\n",
13118 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13119 assign( frS, triop( Iop_MulD64, round, mkexpr( frA ), mkexpr( frB ) ) );
13120 break;
13121 case 0x222: // ddiv
13122 DIP( "ddiv%s fr%u,fr%u,fr%u\n",
13123 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13124 assign( frS, triop( Iop_DivD64, round, mkexpr( frA ), mkexpr( frB ) ) );
13125 break;
13128 putDReg( frS_addr, mkexpr( frS ) );
13130 if (flag_rC && clear_CR1) {
13131 putCR321( 1, mkU8( 0 ) );
13132 putCR0( 1, mkU8( 0 ) );
13135 return True;
13138 /* Quad DFP Arithmetic instructions */
13139 static Bool dis_dfp_arithq(UInt theInstr)
13141 UInt opc2 = ifieldOPClo10( theInstr );
13142 UChar frS_addr = ifieldRegDS( theInstr );
13143 UChar frA_addr = ifieldRegA( theInstr );
13144 UChar frB_addr = ifieldRegB( theInstr );
13145 UChar flag_rC = ifieldBIT0( theInstr );
13147 IRTemp frA = newTemp( Ity_D128 );
13148 IRTemp frB = newTemp( Ity_D128 );
13149 IRTemp frS = newTemp( Ity_D128 );
13150 IRExpr* round = get_IR_roundingmode_DFP();
13152 /* By default, if flag_RC is set, we will clear cr1 after the
13153 * operation. In reality we should set cr1 to indicate the
13154 * exception status of the operation, but since we're not
13155 * simulating exceptions, the exception status will appear to be
13156 * zero. Hence cr1 should be cleared if this is a . form insn.
13158 Bool clear_CR1 = True;
13160 assign( frA, getDReg_pair( frA_addr ) );
13161 assign( frB, getDReg_pair( frB_addr ) );
13163 switch (opc2) {
13164 case 0x2: // daddq
13165 DIP( "daddq%s fr%u,fr%u,fr%u\n",
13166 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13167 assign( frS, triop( Iop_AddD128, round, mkexpr( frA ), mkexpr( frB ) ) );
13168 break;
13169 case 0x202: // dsubq
13170 DIP( "dsubq%s fr%u,fr%u,fr%u\n",
13171 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13172 assign( frS, triop( Iop_SubD128, round, mkexpr( frA ), mkexpr( frB ) ) );
13173 break;
13174 case 0x22: // dmulq
13175 DIP( "dmulq%s fr%u,fr%u,fr%u\n",
13176 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13177 assign( frS, triop( Iop_MulD128, round, mkexpr( frA ), mkexpr( frB ) ) );
13178 break;
13179 case 0x222: // ddivq
13180 DIP( "ddivq%s fr%u,fr%u,fr%u\n",
13181 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13182 assign( frS, triop( Iop_DivD128, round, mkexpr( frA ), mkexpr( frB ) ) );
13183 break;
13186 putDReg_pair( frS_addr, mkexpr( frS ) );
13188 if (flag_rC && clear_CR1) {
13189 putCR321( 1, mkU8( 0 ) );
13190 putCR0( 1, mkU8( 0 ) );
13193 return True;
13196 /* DFP 64-bit logical shift instructions */
13197 static Bool dis_dfp_shift(UInt theInstr) {
13198 UInt opc2 = ifieldOPClo9( theInstr );
13199 UChar frS_addr = ifieldRegDS( theInstr );
13200 UChar frA_addr = ifieldRegA( theInstr );
13201 UChar shift_val = IFIELD(theInstr, 10, 6);
13202 UChar flag_rC = ifieldBIT0( theInstr );
13204 IRTemp frA = newTemp( Ity_D64 );
13205 IRTemp frS = newTemp( Ity_D64 );
13206 Bool clear_CR1 = True;
13208 assign( frA, getDReg( frA_addr ) );
13210 switch (opc2) {
13211 case 0x42: // dscli
13212 DIP( "dscli%s fr%u,fr%u,%u\n",
13213 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
13214 assign( frS, binop( Iop_ShlD64, mkexpr( frA ), mkU8( shift_val ) ) );
13215 break;
13216 case 0x62: // dscri
13217 DIP( "dscri%s fr%u,fr%u,%u\n",
13218 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
13219 assign( frS, binop( Iop_ShrD64, mkexpr( frA ), mkU8( shift_val ) ) );
13220 break;
13223 putDReg( frS_addr, mkexpr( frS ) );
13225 if (flag_rC && clear_CR1) {
13226 putCR321( 1, mkU8( 0 ) );
13227 putCR0( 1, mkU8( 0 ) );
13230 return True;
13233 /* Quad DFP logical shift instructions */
13234 static Bool dis_dfp_shiftq(UInt theInstr) {
13235 UInt opc2 = ifieldOPClo9( theInstr );
13236 UChar frS_addr = ifieldRegDS( theInstr );
13237 UChar frA_addr = ifieldRegA( theInstr );
13238 UChar shift_val = IFIELD(theInstr, 10, 6);
13239 UChar flag_rC = ifieldBIT0( theInstr );
13241 IRTemp frA = newTemp( Ity_D128 );
13242 IRTemp frS = newTemp( Ity_D128 );
13243 Bool clear_CR1 = True;
13245 assign( frA, getDReg_pair( frA_addr ) );
13247 switch (opc2) {
13248 case 0x42: // dscliq
13249 DIP( "dscliq%s fr%u,fr%u,%u\n",
13250 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
13251 assign( frS, binop( Iop_ShlD128, mkexpr( frA ), mkU8( shift_val ) ) );
13252 break;
13253 case 0x62: // dscriq
13254 DIP( "dscriq%s fr%u,fr%u,%u\n",
13255 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
13256 assign( frS, binop( Iop_ShrD128, mkexpr( frA ), mkU8( shift_val ) ) );
13257 break;
13260 putDReg_pair( frS_addr, mkexpr( frS ) );
13262 if (flag_rC && clear_CR1) {
13263 putCR321( 1, mkU8( 0 ) );
13264 putCR0( 1, mkU8( 0 ) );
13267 return True;
13270 /* DFP 64-bit format conversion instructions */
13271 static Bool dis_dfp_fmt_conv(UInt theInstr) {
13272 UInt opc2 = ifieldOPClo10( theInstr );
13273 UChar frS_addr = ifieldRegDS( theInstr );
13274 UChar frB_addr = ifieldRegB( theInstr );
13275 IRExpr* round = get_IR_roundingmode_DFP();
13276 UChar flag_rC = ifieldBIT0( theInstr );
13277 IRTemp frB;
13278 IRTemp frS;
13279 Bool clear_CR1 = True;
13281 switch (opc2) {
13282 case 0x102: //dctdp
13283 DIP( "dctdp%s fr%u,fr%u\n",
13284 flag_rC ? ".":"", frS_addr, frB_addr );
13286 frB = newTemp( Ity_D32 );
13287 frS = newTemp( Ity_D64 );
13288 assign( frB, getDReg32( frB_addr ) );
13289 assign( frS, unop( Iop_D32toD64, mkexpr( frB ) ) );
13290 putDReg( frS_addr, mkexpr( frS ) );
13291 break;
13292 case 0x302: // drsp
13293 DIP( "drsp%s fr%u,fr%u\n",
13294 flag_rC ? ".":"", frS_addr, frB_addr );
13295 frB = newTemp( Ity_D64 );
13296 frS = newTemp( Ity_D32 );
13297 assign( frB, getDReg( frB_addr ) );
13298 assign( frS, binop( Iop_D64toD32, round, mkexpr( frB ) ) );
13299 putDReg32( frS_addr, mkexpr( frS ) );
13300 break;
13301 case 0x122: // dctfix
13303 IRTemp tmp = newTemp( Ity_I64 );
13305 DIP( "dctfix%s fr%u,fr%u\n",
13306 flag_rC ? ".":"", frS_addr, frB_addr );
13307 frB = newTemp( Ity_D64 );
13308 frS = newTemp( Ity_D64 );
13309 assign( frB, getDReg( frB_addr ) );
13310 assign( tmp, binop( Iop_D64toI64S, round, mkexpr( frB ) ) );
13311 assign( frS, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
13312 putDReg( frS_addr, mkexpr( frS ) );
13314 break;
13315 case 0x322: // dcffix
13316 DIP( "dcffix%s fr%u,fr%u\n",
13317 flag_rC ? ".":"", frS_addr, frB_addr );
13318 frB = newTemp( Ity_D64 );
13319 frS = newTemp( Ity_D64 );
13320 assign( frB, getDReg( frB_addr ) );
13321 assign( frS, binop( Iop_I64StoD64,
13322 round,
13323 unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) ) );
13324 putDReg( frS_addr, mkexpr( frS ) );
13325 break;
13328 if (flag_rC && clear_CR1) {
13329 putCR321( 1, mkU8( 0 ) );
13330 putCR0( 1, mkU8( 0 ) );
13333 return True;
13336 /* Quad DFP format conversion instructions */
13337 static Bool dis_dfp_fmt_convq(UInt theInstr) {
13338 UInt opc2 = ifieldOPClo10( theInstr );
13339 UChar frS_addr = ifieldRegDS( theInstr );
13340 UChar frB_addr = ifieldRegB( theInstr );
13341 IRExpr* round = get_IR_roundingmode_DFP();
13342 IRTemp frB64 = newTemp( Ity_D64 );
13343 IRTemp frB128 = newTemp( Ity_D128 );
13344 IRTemp frS64 = newTemp( Ity_D64 );
13345 IRTemp frS128 = newTemp( Ity_D128 );
13346 UChar flag_rC = ifieldBIT0( theInstr );
13347 Bool clear_CR1 = True;
13349 switch (opc2) {
13350 case 0x102: // dctqpq
13351 DIP( "dctqpq%s fr%u,fr%u\n",
13352 flag_rC ? ".":"", frS_addr, frB_addr );
13353 assign( frB64, getDReg( frB_addr ) );
13354 assign( frS128, unop( Iop_D64toD128, mkexpr( frB64 ) ) );
13355 putDReg_pair( frS_addr, mkexpr( frS128 ) );
13356 break;
13357 case 0x122: // dctfixq
13359 IRTemp tmp = newTemp( Ity_I64 );
13361 DIP( "dctfixq%s fr%u,fr%u\n",
13362 flag_rC ? ".":"", frS_addr, frB_addr );
13363 assign( frB128, getDReg_pair( frB_addr ) );
13364 assign( tmp, binop( Iop_D128toI64S, round, mkexpr( frB128 ) ) );
13365 assign( frS64, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
13366 putDReg( frS_addr, mkexpr( frS64 ) );
13368 break;
13369 case 0x302: //drdpq
13370 DIP( "drdpq%s fr%u,fr%u\n",
13371 flag_rC ? ".":"", frS_addr, frB_addr );
13372 assign( frB128, getDReg_pair( frB_addr ) );
13373 assign( frS64, binop( Iop_D128toD64, round, mkexpr( frB128 ) ) );
13374 putDReg( frS_addr, mkexpr( frS64 ) );
13375 break;
13376 case 0x322: // dcffixq
13378 /* Have to introduce an IOP for this instruction so it will work
13379 * on POWER 6 because emulating the instruction requires a POWER 7
13380 * DFP instruction in the emulation code.
13382 DIP( "dcffixq%s fr%u,fr%u\n",
13383 flag_rC ? ".":"", frS_addr, frB_addr );
13384 assign( frB64, getDReg( frB_addr ) );
13385 assign( frS128, unop( Iop_I64StoD128,
13386 unop( Iop_ReinterpD64asI64,
13387 mkexpr( frB64 ) ) ) );
13388 putDReg_pair( frS_addr, mkexpr( frS128 ) );
13389 break;
13393 if (flag_rC && clear_CR1) {
13394 putCR321( 1, mkU8( 0 ) );
13395 putCR0( 1, mkU8( 0 ) );
13398 return True;
13401 static Bool dis_dfp_round( UInt theInstr ) {
13402 UChar frS_addr = ifieldRegDS(theInstr);
13403 UChar R = IFIELD(theInstr, 16, 1);
13404 UChar RMC = IFIELD(theInstr, 9, 2);
13405 UChar frB_addr = ifieldRegB( theInstr );
13406 UChar flag_rC = ifieldBIT0( theInstr );
13407 IRTemp frB = newTemp( Ity_D64 );
13408 IRTemp frS = newTemp( Ity_D64 );
13409 UInt opc2 = ifieldOPClo8( theInstr );
13410 Bool clear_CR1 = True;
13412 switch (opc2) {
13413 /* drintn, is the same as drintx. The only difference is this
13414 * instruction does not generate an exception for an inexact operation.
13415 * Currently not supporting inexact exceptions.
13417 case 0x63: // drintx
13418 case 0xE3: // drintn
13419 DIP( "drintx/drintn%s fr%u,fr%u\n",
13420 flag_rC ? ".":"", frS_addr, frB_addr );
13422 /* NOTE, this instruction takes a DFP value and rounds to the
13423 * neares floating point integer value, i.e. fractional part
13424 * is zero. The result is a floating point number.
13426 /* pass the value of R and RMC in the same field */
13427 assign( frB, getDReg( frB_addr ) );
13428 assign( frS, binop( Iop_RoundD64toInt,
13429 mkU32( ( R << 3 ) | RMC ),
13430 mkexpr( frB ) ) );
13431 putDReg( frS_addr, mkexpr( frS ) );
13432 break;
13433 default:
13434 vex_printf("dis_dfp_round(ppc)(opc2)\n");
13435 return False;
13438 if (flag_rC && clear_CR1) {
13439 putCR321( 1, mkU8( 0 ) );
13440 putCR0( 1, mkU8( 0 ) );
13443 return True;
13446 static Bool dis_dfp_roundq(UInt theInstr) {
13447 UChar frS_addr = ifieldRegDS( theInstr );
13448 UChar frB_addr = ifieldRegB( theInstr );
13449 UChar R = IFIELD(theInstr, 16, 1);
13450 UChar RMC = IFIELD(theInstr, 9, 2);
13451 UChar flag_rC = ifieldBIT0( theInstr );
13452 IRTemp frB = newTemp( Ity_D128 );
13453 IRTemp frS = newTemp( Ity_D128 );
13454 Bool clear_CR1 = True;
13455 UInt opc2 = ifieldOPClo8( theInstr );
13457 switch (opc2) {
13458 /* drintnq, is the same as drintxq. The only difference is this
13459 * instruction does not generate an exception for an inexact operation.
13460 * Currently not supporting inexact exceptions.
13462 case 0x63: // drintxq
13463 case 0xE3: // drintnq
13464 DIP( "drintxq/drintnq%s fr%u,fr%u\n",
13465 flag_rC ? ".":"", frS_addr, frB_addr );
13467 /* pass the value of R and RMC in the same field */
13468 assign( frB, getDReg_pair( frB_addr ) );
13469 assign( frS, binop( Iop_RoundD128toInt,
13470 mkU32( ( R << 3 ) | RMC ),
13471 mkexpr( frB ) ) );
13472 putDReg_pair( frS_addr, mkexpr( frS ) );
13473 break;
13474 default:
13475 vex_printf("dis_dfp_roundq(ppc)(opc2)\n");
13476 return False;
13479 if (flag_rC && clear_CR1) {
13480 putCR321( 1, mkU8( 0 ) );
13481 putCR0( 1, mkU8( 0 ) );
13484 return True;
13487 static Bool dis_dfp_quantize_sig_rrnd(UInt theInstr) {
13488 UInt opc2 = ifieldOPClo8( theInstr );
13489 UChar frS_addr = ifieldRegDS( theInstr );
13490 UChar frA_addr = ifieldRegA( theInstr );
13491 UChar frB_addr = ifieldRegB( theInstr );
13492 UChar flag_rC = ifieldBIT0( theInstr );
13493 UInt TE_value = IFIELD(theInstr, 16, 4);
13494 UInt TE_sign = IFIELD(theInstr, 20, 1);
13495 UInt RMC = IFIELD(theInstr, 9, 2);
13496 IRTemp frA = newTemp( Ity_D64 );
13497 IRTemp frB = newTemp( Ity_D64 );
13498 IRTemp frS = newTemp( Ity_D64 );
13499 Bool clear_CR1 = True;
13501 assign( frB, getDReg( frB_addr ) );
13503 switch (opc2) {
13504 case 0x43: // dquai
13505 DIP( "dquai%s fr%u,fr%u,fr%u\n",
13506 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13507 IRTemp TE_I64 = newTemp( Ity_I64 );
13509 /* Generate a reference DFP value frA with the desired exponent
13510 * given by TE using significand from frB. Need to add the bias
13511 * 398 to TE. TE is stored as a 2's complement number.
13513 if (TE_sign == 1) {
13514 /* Take 2's complement of the 5-bit value and subtract from bias.
13515 * Bias is adjusted for the +1 required when taking 2's complement.
13517 assign( TE_I64,
13518 unop( Iop_32Uto64,
13519 binop( Iop_Sub32, mkU32( 397 ),
13520 binop( Iop_And32, mkU32( 0xF ),
13521 unop( Iop_Not32, mkU32( TE_value ) )
13522 ) ) ) );
13524 } else {
13525 assign( TE_I64,
13526 unop( Iop_32Uto64,
13527 binop( Iop_Add32, mkU32( 398 ), mkU32( TE_value ) )
13528 ) );
13531 assign( frA, binop( Iop_InsertExpD64, mkexpr( TE_I64 ),
13532 unop( Iop_ReinterpI64asD64, mkU64( 1 ) ) ) );
13534 assign( frS, triop( Iop_QuantizeD64,
13535 mkU32( RMC ),
13536 mkexpr( frA ),
13537 mkexpr( frB ) ) );
13538 break;
13540 case 0x3: // dqua
13541 DIP( "dqua%s fr%u,fr%u,fr%u\n",
13542 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13543 assign( frA, getDReg( frA_addr ) );
13544 assign( frS, triop( Iop_QuantizeD64,
13545 mkU32( RMC ),
13546 mkexpr( frA ),
13547 mkexpr( frB ) ) );
13548 break;
13549 case 0x23: // drrnd
13551 IRTemp tmp = newTemp( Ity_I8 );
13553 DIP( "drrnd%s fr%u,fr%u,fr%u\n",
13554 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13555 assign( frA, getDReg( frA_addr ) );
13556 /* Iop_64to8 not supported in 32 bit mode, do it in two steps. */
13557 assign( tmp, unop( Iop_32to8,
13558 unop( Iop_64to32,
13559 unop( Iop_ReinterpD64asI64,
13560 mkexpr( frA ) ) ) ) );
13561 assign( frS, triop( Iop_SignificanceRoundD64,
13562 mkU32( RMC ),
13563 mkexpr( tmp ),
13564 mkexpr( frB ) ) );
13566 break;
13567 default:
13568 vex_printf("dis_dfp_quantize_sig_rrnd(ppc)(opc2)\n");
13569 return False;
13571 putDReg( frS_addr, mkexpr( frS ) );
13573 if (flag_rC && clear_CR1) {
13574 putCR321( 1, mkU8( 0 ) );
13575 putCR0( 1, mkU8( 0 ) );
13578 return True;
13581 static Bool dis_dfp_quantize_sig_rrndq(UInt theInstr) {
13582 UInt opc2 = ifieldOPClo8( theInstr );
13583 UChar frS_addr = ifieldRegDS( theInstr );
13584 UChar frA_addr = ifieldRegA( theInstr );
13585 UChar frB_addr = ifieldRegB( theInstr );
13586 UChar flag_rC = ifieldBIT0( theInstr );
13587 UInt TE_value = IFIELD(theInstr, 16, 4);
13588 UInt TE_sign = IFIELD(theInstr, 20, 1);
13589 UInt RMC = IFIELD(theInstr, 9, 2);
13590 IRTemp frA = newTemp( Ity_D128 );
13591 IRTemp frB = newTemp( Ity_D128 );
13592 IRTemp frS = newTemp( Ity_D128 );
13593 Bool clear_CR1 = True;
13595 assign( frB, getDReg_pair( frB_addr ) );
13597 switch (opc2) {
13598 case 0x43: // dquaiq
13599 DIP( "dquaiq%s fr%u,fr%u,fr%u\n",
13600 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13601 IRTemp TE_I64 = newTemp( Ity_I64 );
13603 /* Generate a reference DFP value frA with the desired exponent
13604 * given by TE using significand of 1. Need to add the bias
13605 * 6176 to TE.
13607 if (TE_sign == 1) {
13608 /* Take 2's complement of the 5-bit value and subtract from bias.
13609 * Bias adjusted for the +1 required when taking 2's complement.
13611 assign( TE_I64,
13612 unop( Iop_32Uto64,
13613 binop( Iop_Sub32, mkU32( 6175 ),
13614 binop( Iop_And32, mkU32( 0xF ),
13615 unop( Iop_Not32, mkU32( TE_value ) )
13616 ) ) ) );
13618 } else {
13619 assign( TE_I64,
13620 unop( Iop_32Uto64,
13621 binop( Iop_Add32,
13622 mkU32( 6176 ),
13623 mkU32( TE_value ) ) ) );
13626 assign( frA,
13627 binop( Iop_InsertExpD128, mkexpr( TE_I64 ),
13628 unop( Iop_D64toD128,
13629 unop( Iop_ReinterpI64asD64, mkU64( 1 ) ) ) ) );
13630 assign( frS, triop( Iop_QuantizeD128,
13631 mkU32( RMC ),
13632 mkexpr( frA ),
13633 mkexpr( frB ) ) );
13634 break;
13635 case 0x3: // dquaq
13636 DIP( "dquaiq%s fr%u,fr%u,fr%u\n",
13637 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13638 assign( frA, getDReg_pair( frA_addr ) );
13639 assign( frS, triop( Iop_QuantizeD128,
13640 mkU32( RMC ),
13641 mkexpr( frA ),
13642 mkexpr( frB ) ) );
13643 break;
13644 case 0x23: // drrndq
13646 IRTemp tmp = newTemp( Ity_I8 );
13648 DIP( "drrndq%s fr%u,fr%u,fr%u\n",
13649 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13650 assign( frA, getDReg_pair( frA_addr ) );
13651 assign( tmp, unop( Iop_32to8,
13652 unop( Iop_64to32,
13653 unop( Iop_ReinterpD64asI64,
13654 unop( Iop_D128HItoD64,
13655 mkexpr( frA ) ) ) ) ) );
13656 assign( frS, triop( Iop_SignificanceRoundD128,
13657 mkU32( RMC ),
13658 mkexpr( tmp ),
13659 mkexpr( frB ) ) );
13661 break;
13662 default:
13663 vex_printf("dis_dfp_quantize_sig_rrndq(ppc)(opc2)\n");
13664 return False;
13666 putDReg_pair( frS_addr, mkexpr( frS ) );
13668 if (flag_rC && clear_CR1) {
13669 putCR321( 1, mkU8( 0 ) );
13670 putCR0( 1, mkU8( 0 ) );
13673 return True;
13676 static Bool dis_dfp_extract_insert(UInt theInstr) {
13677 UInt opc2 = ifieldOPClo10( theInstr );
13678 UChar frS_addr = ifieldRegDS( theInstr );
13679 UChar frA_addr = ifieldRegA( theInstr );
13680 UChar frB_addr = ifieldRegB( theInstr );
13681 UChar flag_rC = ifieldBIT0( theInstr );
13682 Bool clear_CR1 = True;
13684 IRTemp frA = newTemp( Ity_D64 );
13685 IRTemp frB = newTemp( Ity_D64 );
13686 IRTemp frS = newTemp( Ity_D64 );
13687 IRTemp tmp = newTemp( Ity_I64 );
13689 assign( frA, getDReg( frA_addr ) );
13690 assign( frB, getDReg( frB_addr ) );
13692 switch (opc2) {
13693 case 0x162: // dxex
13694 DIP( "dxex%s fr%u,fr%u,fr%u\n",
13695 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13696 assign( tmp, unop( Iop_ExtractExpD64, mkexpr( frB ) ) );
13697 assign( frS, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
13698 break;
13699 case 0x362: // diex
13700 DIP( "diex%s fr%u,fr%u,fr%u\n",
13701 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13702 assign( frS, binop( Iop_InsertExpD64,
13703 unop( Iop_ReinterpD64asI64,
13704 mkexpr( frA ) ),
13705 mkexpr( frB ) ) );
13706 break;
13707 default:
13708 vex_printf("dis_dfp_extract_insert(ppc)(opc2)\n");
13709 return False;
13712 putDReg( frS_addr, mkexpr( frS ) );
13714 if (flag_rC && clear_CR1) {
13715 putCR321( 1, mkU8( 0 ) );
13716 putCR0( 1, mkU8( 0 ) );
13719 return True;
13722 static Bool dis_dfp_extract_insertq(UInt theInstr) {
13723 UInt opc2 = ifieldOPClo10( theInstr );
13724 UChar frS_addr = ifieldRegDS( theInstr );
13725 UChar frA_addr = ifieldRegA( theInstr );
13726 UChar frB_addr = ifieldRegB( theInstr );
13727 UChar flag_rC = ifieldBIT0( theInstr );
13729 IRTemp frA = newTemp( Ity_D64 );
13730 IRTemp frB = newTemp( Ity_D128 );
13731 IRTemp frS64 = newTemp( Ity_D64 );
13732 IRTemp frS = newTemp( Ity_D128 );
13733 IRTemp tmp = newTemp( Ity_I64 );
13734 Bool clear_CR1 = True;
13736 assign( frB, getDReg_pair( frB_addr ) );
13738 switch (opc2) {
13739 case 0x162: // dxexq
13740 DIP( "dxexq%s fr%u,fr%u\n",
13741 flag_rC ? ".":"", frS_addr, frB_addr );
13742 /* Instruction actually returns a 64-bit result. So as to be
13743 * consistent and not have to add a new struct, the emulation returns
13744 * the 64-bit result in the upper and lower register.
13746 assign( tmp, unop( Iop_ExtractExpD128, mkexpr( frB ) ) );
13747 assign( frS64, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
13748 putDReg( frS_addr, mkexpr( frS64 ) );
13749 break;
13750 case 0x362: // diexq
13751 DIP( "diexq%s fr%u,fr%u,fr%u\n",
13752 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13753 assign( frA, getDReg( frA_addr ) );
13754 assign( frS, binop( Iop_InsertExpD128,
13755 unop( Iop_ReinterpD64asI64, mkexpr( frA ) ),
13756 mkexpr( frB ) ) );
13757 putDReg_pair( frS_addr, mkexpr( frS ) );
13758 break;
13759 default:
13760 vex_printf("dis_dfp_extract_insertq(ppc)(opc2)\n");
13761 return False;
13764 if (flag_rC && clear_CR1) {
13765 putCR321( 1, mkU8( 0 ) );
13766 putCR0( 1, mkU8( 0 ) );
13769 return True;
13772 /* DFP 64-bit comparison instructions */
13773 static Bool dis_dfp_compare(UInt theInstr) {
13774 /* X-Form */
13775 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
13776 UChar frA_addr = ifieldRegA( theInstr );
13777 UChar frB_addr = ifieldRegB( theInstr );
13778 UInt opc1 = ifieldOPC( theInstr );
13779 IRTemp frA;
13780 IRTemp frB;
13782 IRTemp ccIR = newTemp( Ity_I32 );
13783 IRTemp ccPPC32 = newTemp( Ity_I32 );
13786 /* Note: Differences between dcmpu and dcmpo are only in exception
13787 flag settings, which aren't supported anyway. */
13788 switch (opc1) {
13789 case 0x3B: /* dcmpo and dcmpu, DFP 64-bit */
13790 DIP( "dcmpo %u,fr%u,fr%u\n", crfD, frA_addr, frB_addr );
13791 frA = newTemp( Ity_D64 );
13792 frB = newTemp( Ity_D64 );
13794 assign( frA, getDReg( frA_addr ) );
13795 assign( frB, getDReg( frB_addr ) );
13797 assign( ccIR, binop( Iop_CmpD64, mkexpr( frA ), mkexpr( frB ) ) );
13798 break;
13799 case 0x3F: /* dcmpoq and dcmpuq,DFP 128-bit */
13800 DIP( "dcmpoq %u,fr%u,fr%u\n", crfD, frA_addr, frB_addr );
13801 frA = newTemp( Ity_D128 );
13802 frB = newTemp( Ity_D128 );
13804 assign( frA, getDReg_pair( frA_addr ) );
13805 assign( frB, getDReg_pair( frB_addr ) );
13806 assign( ccIR, binop( Iop_CmpD128, mkexpr( frA ), mkexpr( frB ) ) );
13807 break;
13808 default:
13809 vex_printf("dis_dfp_compare(ppc)(opc2)\n");
13810 return False;
13813 /* Map compare result from IR to PPC32 */
13815 FP cmp result | PPC | IR
13816 --------------------------
13817 UN | 0x1 | 0x45
13818 EQ | 0x2 | 0x40
13819 GT | 0x4 | 0x00
13820 LT | 0x8 | 0x01
13823 assign( ccPPC32,
13824 binop( Iop_Shl32,
13825 mkU32( 1 ),
13826 unop( Iop_32to8,
13827 binop( Iop_Or32,
13828 binop( Iop_And32,
13829 unop( Iop_Not32,
13830 binop( Iop_Shr32,
13831 mkexpr( ccIR ),
13832 mkU8( 5 ) ) ),
13833 mkU32( 2 ) ),
13834 binop( Iop_And32,
13835 binop( Iop_Xor32,
13836 mkexpr( ccIR ),
13837 binop( Iop_Shr32,
13838 mkexpr( ccIR ),
13839 mkU8( 6 ) ) ),
13840 mkU32( 1 ) ) ) ) ) );
13842 putGST_field( PPC_GST_CR, mkexpr( ccPPC32 ), crfD );
13843 putFPCC( mkexpr( ccPPC32 ) );
13844 return True;
13847 /* Test class/group/exponent/significance instructions. */
13848 static Bool dis_dfp_exponent_test ( UInt theInstr )
13850 UChar frA_addr = ifieldRegA( theInstr );
13851 UChar frB_addr = ifieldRegB( theInstr );
13852 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
13853 IRTemp frA = newTemp( Ity_D64 );
13854 IRTemp frB = newTemp( Ity_D64 );
13855 IRTemp frA128 = newTemp( Ity_D128 );
13856 IRTemp frB128 = newTemp( Ity_D128 );
13857 UInt opc1 = ifieldOPC( theInstr );
13858 IRTemp gfield_A = newTemp( Ity_I32 );
13859 IRTemp gfield_B = newTemp( Ity_I32 );
13860 IRTemp gfield_mask = newTemp( Ity_I32 );
13861 IRTemp exponent_A = newTemp( Ity_I32 );
13862 IRTemp exponent_B = newTemp( Ity_I32 );
13863 IRTemp A_NaN_true = newTemp( Ity_I32 );
13864 IRTemp B_NaN_true = newTemp( Ity_I32 );
13865 IRTemp A_inf_true = newTemp( Ity_I32 );
13866 IRTemp B_inf_true = newTemp( Ity_I32 );
13867 IRTemp A_equals_B = newTemp( Ity_I32 );
13868 IRTemp finite_number = newTemp( Ity_I32 );
13869 IRTemp cc0 = newTemp( Ity_I32 );
13870 IRTemp cc1 = newTemp( Ity_I32 );
13871 IRTemp cc2 = newTemp( Ity_I32 );
13872 IRTemp cc3 = newTemp( Ity_I32 );
13873 IRTemp cc = newTemp( Ity_I32 );
13875 /* The dtstex and dtstexg instructions only differ in the size of the
13876 * exponent field. The following switch statement takes care of the size
13877 * specific setup. Once the value of the exponents, the G-field shift
13878 * and mask is setup the remaining code is identical.
13880 switch (opc1) {
13881 case 0x3b: // dtstex Extended instruction setup
13882 DIP("dtstex %u,r%u,r%d\n", crfD, frA_addr, frB_addr);
13883 assign( frA, getDReg( frA_addr ) );
13884 assign( frB, getDReg( frB_addr ) );
13885 assign( gfield_mask, mkU32( DFP_G_FIELD_LONG_MASK ) );
13886 assign(exponent_A, unop( Iop_64to32,
13887 unop( Iop_ExtractExpD64,
13888 mkexpr( frA ) ) ) );
13889 assign(exponent_B, unop( Iop_64to32,
13890 unop( Iop_ExtractExpD64,
13891 mkexpr( frB ) ) ) );
13892 break;
13894 case 0x3F: // dtstexq Quad instruction setup
13895 DIP("dtstexq %u,r%u,r%d\n", crfD, frA_addr, frB_addr);
13896 assign( frA128, getDReg_pair( frA_addr ) );
13897 assign( frB128, getDReg_pair( frB_addr ) );
13898 assign( frA, unop( Iop_D128HItoD64, mkexpr( frA128 ) ) );
13899 assign( frB, unop( Iop_D128HItoD64, mkexpr( frB128 ) ) );
13900 assign( gfield_mask, mkU32( DFP_G_FIELD_EXTND_MASK ) );
13901 assign( exponent_A, unop( Iop_64to32,
13902 unop( Iop_ExtractExpD128,
13903 mkexpr( frA128 ) ) ) );
13904 assign( exponent_B, unop( Iop_64to32,
13905 unop( Iop_ExtractExpD128,
13906 mkexpr( frB128 ) ) ) );
13907 break;
13908 default:
13909 vex_printf("dis_dfp_exponent_test(ppc)(opc2)\n");
13910 return False;
13913 /* Extract the Gfield */
13914 assign( gfield_A, binop( Iop_And32,
13915 mkexpr( gfield_mask ),
13916 unop( Iop_64HIto32,
13917 unop( Iop_ReinterpD64asI64,
13918 mkexpr(frA) ) ) ) );
13920 assign( gfield_B, binop( Iop_And32,
13921 mkexpr( gfield_mask ),
13922 unop( Iop_64HIto32,
13923 unop( Iop_ReinterpD64asI64,
13924 mkexpr(frB) ) ) ) );
13926 /* check for NAN */
13927 assign( A_NaN_true, binop(Iop_Or32,
13928 unop( Iop_1Sto32,
13929 binop( Iop_CmpEQ32,
13930 mkexpr( gfield_A ),
13931 mkU32( 0x7C000000 ) ) ),
13932 unop( Iop_1Sto32,
13933 binop( Iop_CmpEQ32,
13934 mkexpr( gfield_A ),
13935 mkU32( 0x7E000000 ) )
13936 ) ) );
13937 assign( B_NaN_true, binop(Iop_Or32,
13938 unop( Iop_1Sto32,
13939 binop( Iop_CmpEQ32,
13940 mkexpr( gfield_B ),
13941 mkU32( 0x7C000000 ) ) ),
13942 unop( Iop_1Sto32,
13943 binop( Iop_CmpEQ32,
13944 mkexpr( gfield_B ),
13945 mkU32( 0x7E000000 ) )
13946 ) ) );
13948 /* check for infinity */
13949 assign( A_inf_true,
13950 unop( Iop_1Sto32,
13951 binop( Iop_CmpEQ32,
13952 mkexpr( gfield_A ),
13953 mkU32( 0x78000000 ) ) ) );
13955 assign( B_inf_true,
13956 unop( Iop_1Sto32,
13957 binop( Iop_CmpEQ32,
13958 mkexpr( gfield_B ),
13959 mkU32( 0x78000000 ) ) ) );
13961 assign( finite_number,
13962 unop( Iop_Not32,
13963 binop( Iop_Or32,
13964 binop( Iop_Or32,
13965 mkexpr( A_NaN_true ),
13966 mkexpr( B_NaN_true ) ),
13967 binop( Iop_Or32,
13968 mkexpr( A_inf_true ),
13969 mkexpr( B_inf_true ) ) ) ) );
13971 /* Calculate the condition code bits
13972 * If QNaN,SNaN, +infinity, -infinity then cc0, cc1 and cc2 are zero
13973 * regardless of the value of the comparisons and cc3 is 1. Otherwise,
13974 * cc0, cc1 and cc0 reflect the results of the comparisons.
13976 assign( A_equals_B,
13977 binop( Iop_Or32,
13978 unop( Iop_1Uto32,
13979 binop( Iop_CmpEQ32,
13980 mkexpr( exponent_A ),
13981 mkexpr( exponent_B ) ) ),
13982 binop( Iop_Or32,
13983 binop( Iop_And32,
13984 mkexpr( A_inf_true ),
13985 mkexpr( B_inf_true ) ),
13986 binop( Iop_And32,
13987 mkexpr( A_NaN_true ),
13988 mkexpr( B_NaN_true ) ) ) ) );
13990 assign( cc0, binop( Iop_And32,
13991 mkexpr( finite_number ),
13992 binop( Iop_Shl32,
13993 unop( Iop_1Uto32,
13994 binop( Iop_CmpLT32U,
13995 mkexpr( exponent_A ),
13996 mkexpr( exponent_B ) ) ),
13997 mkU8( 3 ) ) ) );
13999 assign( cc1, binop( Iop_And32,
14000 mkexpr( finite_number ),
14001 binop( Iop_Shl32,
14002 unop( Iop_1Uto32,
14003 binop( Iop_CmpLT32U,
14004 mkexpr( exponent_B ),
14005 mkexpr( exponent_A ) ) ),
14006 mkU8( 2 ) ) ) );
14008 assign( cc2, binop( Iop_Shl32,
14009 binop( Iop_And32,
14010 mkexpr( A_equals_B ),
14011 mkU32( 1 ) ),
14012 mkU8( 1 ) ) );
14014 assign( cc3, binop( Iop_And32,
14015 unop( Iop_Not32, mkexpr( A_equals_B ) ),
14016 binop( Iop_And32,
14017 mkU32( 0x1 ),
14018 binop( Iop_Or32,
14019 binop( Iop_Or32,
14020 mkexpr ( A_inf_true ),
14021 mkexpr ( B_inf_true ) ),
14022 binop( Iop_Or32,
14023 mkexpr ( A_NaN_true ),
14024 mkexpr ( B_NaN_true ) ) )
14025 ) ) );
14027 /* store the condition code */
14028 assign( cc, binop( Iop_Or32,
14029 mkexpr( cc0 ),
14030 binop( Iop_Or32,
14031 mkexpr( cc1 ),
14032 binop( Iop_Or32,
14033 mkexpr( cc2 ),
14034 mkexpr( cc3 ) ) ) ) );
14035 putGST_field( PPC_GST_CR, mkexpr( cc ), crfD );
14036 putFPCC( mkexpr( cc ) );
14037 return True;
14040 /* Test class/group/exponent/significance instructions. */
14041 static Bool dis_dfp_class_test ( UInt theInstr )
14043 UChar frA_addr = ifieldRegA( theInstr );
14044 IRTemp frA = newTemp( Ity_D64 );
14045 IRTemp abs_frA = newTemp( Ity_D64 );
14046 IRTemp frAI64_hi = newTemp( Ity_I64 );
14047 IRTemp frAI64_lo = newTemp( Ity_I64 );
14048 UInt opc1 = ifieldOPC( theInstr );
14049 UInt opc2 = ifieldOPClo9( theInstr );
14050 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
14051 UInt DCM = IFIELD( theInstr, 10, 6 );
14052 IRTemp DCM_calc = newTemp( Ity_I32 );
14053 UInt max_exp = 0;
14054 UInt min_exp = 0;
14055 IRTemp min_subnormalD64 = newTemp( Ity_D64 );
14056 IRTemp min_subnormalD128 = newTemp( Ity_D128 );
14057 IRTemp significand64 = newTemp( Ity_D64 );
14058 IRTemp significand128 = newTemp( Ity_D128 );
14059 IRTemp exp_min_normal = newTemp( Ity_I64 );
14060 IRTemp exponent = newTemp( Ity_I32 );
14062 IRTemp infinity_true = newTemp( Ity_I32 );
14063 IRTemp SNaN_true = newTemp( Ity_I32 );
14064 IRTemp QNaN_true = newTemp( Ity_I32 );
14065 IRTemp subnormal_true = newTemp( Ity_I32 );
14066 IRTemp normal_true = newTemp( Ity_I32 );
14067 IRTemp extreme_true = newTemp( Ity_I32 );
14068 IRTemp lmd = newTemp( Ity_I32 );
14069 IRTemp lmd_zero_true = newTemp( Ity_I32 );
14070 IRTemp zero_true = newTemp( Ity_I32 );
14071 IRTemp sign = newTemp( Ity_I32 );
14072 IRTemp field = newTemp( Ity_I32 );
14073 IRTemp ccIR_zero = newTemp( Ity_I32 );
14074 IRTemp ccIR_subnormal = newTemp( Ity_I32 );
14076 /* UInt size = DFP_LONG; JRS:unused */
14077 IRTemp gfield = newTemp( Ity_I32 );
14078 IRTemp gfield_0_4_shift = newTemp( Ity_I8 );
14079 IRTemp gfield_mask = newTemp( Ity_I32 );
14080 IRTemp dcm0 = newTemp( Ity_I32 );
14081 IRTemp dcm1 = newTemp( Ity_I32 );
14082 IRTemp dcm2 = newTemp( Ity_I32 );
14083 IRTemp dcm3 = newTemp( Ity_I32 );
14084 IRTemp dcm4 = newTemp( Ity_I32 );
14085 IRTemp dcm5 = newTemp( Ity_I32 );
14087 /* The only difference between the dtstdc and dtstdcq instructions is
14088 * size of the T and G fields. The calculation of the 4 bit field
14089 * is the same. Setup the parameters and values that are DFP size
14090 * specific. The rest of the code is independent of the DFP size.
14092 * The Io_CmpD64 is used below. The instruction sets the ccIR values.
14093 * The interpretation of the ccIR values is as follows:
14095 * DFP cmp result | IR
14096 * --------------------------
14097 * UN | 0x45
14098 * EQ | 0x40
14099 * GT | 0x00
14100 * LT | 0x01
14103 assign( frA, getDReg( frA_addr ) );
14104 assign( frAI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frA ) ) );
14106 assign( abs_frA, unop( Iop_ReinterpI64asD64,
14107 binop( Iop_And64,
14108 unop( Iop_ReinterpD64asI64,
14109 mkexpr( frA ) ),
14110 mkU64( 0x7FFFFFFFFFFFFFFFULL ) ) ) );
14111 assign( gfield_0_4_shift, mkU8( 31 - 5 ) ); // G-field[0:4]
14112 switch (opc1) {
14113 case 0x3b: // dtstdc, dtstdg
14114 DIP("dtstd%s %u,r%u,%u\n", opc2 == 0xc2 ? "c" : "g",
14115 crfD, frA_addr, DCM);
14116 /* setup the parameters for the long format of the two instructions */
14117 assign( frAI64_lo, mkU64( 0 ) );
14118 assign( gfield_mask, mkU32( DFP_G_FIELD_LONG_MASK ) );
14119 max_exp = DFP_LONG_EXP_MAX;
14120 min_exp = DFP_LONG_EXP_MIN;
14122 assign( exponent, unop( Iop_64to32,
14123 unop( Iop_ExtractExpD64,
14124 mkexpr( frA ) ) ) );
14125 assign( significand64,
14126 unop( Iop_ReinterpI64asD64,
14127 mkU64( 0x2234000000000001ULL ) ) ); // dfp 1.0
14128 assign( exp_min_normal,mkU64( 398 - 383 ) );
14129 assign( min_subnormalD64,
14130 binop( Iop_InsertExpD64,
14131 mkexpr( exp_min_normal ),
14132 mkexpr( significand64 ) ) );
14134 assign( ccIR_subnormal,
14135 binop( Iop_CmpD64,
14136 mkexpr( abs_frA ),
14137 mkexpr( min_subnormalD64 ) ) );
14139 /* compare absolute value of frA with zero */
14140 assign( ccIR_zero,
14141 binop( Iop_CmpD64,
14142 mkexpr( abs_frA ),
14143 unop( Iop_ReinterpI64asD64,
14144 mkU64( 0x2238000000000000ULL ) ) ) );
14146 /* size = DFP_LONG; JRS: unused */
14147 break;
14149 case 0x3F: // dtstdcq, dtstdgq
14150 DIP("dtstd%sq %u,r%u,%u\n", opc2 == 0xc2 ? "c" : "g",
14151 crfD, frA_addr, DCM);
14152 /* setup the parameters for the extended format of the
14153 * two instructions
14155 assign( frAI64_lo, unop( Iop_ReinterpD64asI64,
14156 getDReg( frA_addr+1 ) ) );
14158 assign( gfield_mask, mkU32( DFP_G_FIELD_EXTND_MASK ) );
14159 max_exp = DFP_EXTND_EXP_MAX;
14160 min_exp = DFP_EXTND_EXP_MIN;
14161 assign( exponent, unop( Iop_64to32,
14162 unop( Iop_ExtractExpD128,
14163 getDReg_pair( frA_addr) ) ) );
14165 /* create quand exponent for minimum normal number */
14166 assign( exp_min_normal, mkU64( 6176 - 6143 ) );
14167 assign( significand128,
14168 unop( Iop_D64toD128,
14169 unop( Iop_ReinterpI64asD64,
14170 mkU64( 0x2234000000000001ULL ) ) ) ); // dfp 1.0
14172 assign( min_subnormalD128,
14173 binop( Iop_InsertExpD128,
14174 mkexpr( exp_min_normal ),
14175 mkexpr( significand128 ) ) );
14177 assign( ccIR_subnormal,
14178 binop( Iop_CmpD128,
14179 binop( Iop_D64HLtoD128,
14180 unop( Iop_ReinterpI64asD64,
14181 binop( Iop_And64,
14182 unop( Iop_ReinterpD64asI64,
14183 mkexpr( frA ) ),
14184 mkU64( 0x7FFFFFFFFFFFFFFFULL ) ) ),
14185 getDReg( frA_addr+1 ) ),
14186 mkexpr( min_subnormalD128 ) ) );
14187 assign( ccIR_zero,
14188 binop( Iop_CmpD128,
14189 binop( Iop_D64HLtoD128,
14190 mkexpr( abs_frA ),
14191 getDReg( frA_addr+1 ) ),
14192 unop( Iop_D64toD128,
14193 unop( Iop_ReinterpI64asD64,
14194 mkU64( 0x0ULL ) ) ) ) );
14196 /* size = DFP_EXTND; JRS:unused */
14197 break;
14198 default:
14199 vex_printf("dis_dfp_class_test(ppc)(opc2)\n");
14200 return False;
14203 /* The G-field is in the upper 32-bits. The I64 logical operations
14204 * do not seem to be supported in 32-bit mode so keep things as 32-bit
14205 * operations.
14207 assign( gfield, binop( Iop_And32,
14208 mkexpr( gfield_mask ),
14209 unop( Iop_64HIto32,
14210 mkexpr(frAI64_hi) ) ) );
14212 /* There is a lot of code that is the same to do the class and group
14213 * instructions. Later there is an if statement to handle the specific
14214 * instruction.
14216 * Will be using I32 values, compares, shifts and logical operations for
14217 * this code as the 64-bit compare, shifts, logical operations are not
14218 * supported in 32-bit mode.
14221 /* Check the bits for Infinity, QNaN or Signaling NaN */
14222 assign( infinity_true,
14223 unop( Iop_1Sto32,
14224 binop( Iop_CmpEQ32,
14225 binop( Iop_And32,
14226 mkU32( 0x7C000000 ),
14227 mkexpr( gfield ) ),
14228 mkU32( 0x78000000 ) ) ) );
14230 assign( SNaN_true,
14231 unop( Iop_1Sto32,
14232 binop( Iop_CmpEQ32,
14233 binop( Iop_And32,
14234 mkU32( 0x7E000000 ),
14235 mkexpr( gfield ) ),
14236 mkU32( 0x7E000000 ) ) ) );
14238 assign( QNaN_true,
14239 binop( Iop_And32,
14240 unop( Iop_1Sto32,
14241 binop( Iop_CmpEQ32,
14242 binop( Iop_And32,
14243 mkU32( 0x7E000000 ),
14244 mkexpr( gfield ) ),
14245 mkU32( 0x7C000000 ) ) ),
14246 unop( Iop_Not32,
14247 mkexpr( SNaN_true ) ) ) );
14249 assign( zero_true,
14250 binop( Iop_And32,
14251 unop(Iop_1Sto32,
14252 binop( Iop_CmpEQ32,
14253 mkexpr( ccIR_zero ),
14254 mkU32( 0x40 ) ) ), // ccIR code for Equal
14255 unop( Iop_Not32,
14256 binop( Iop_Or32,
14257 mkexpr( infinity_true ),
14258 binop( Iop_Or32,
14259 mkexpr( QNaN_true ),
14260 mkexpr( SNaN_true ) ) ) ) ) );
14262 /* Do compare of frA the minimum normal value. Comparison is size
14263 * depenent and was done above to get the ccIR value.
14265 assign( subnormal_true,
14266 binop( Iop_And32,
14267 binop( Iop_Or32,
14268 unop( Iop_1Sto32,
14269 binop( Iop_CmpEQ32,
14270 mkexpr( ccIR_subnormal ),
14271 mkU32( 0x40 ) ) ), // ccIR code for Equal
14272 unop( Iop_1Sto32,
14273 binop( Iop_CmpEQ32,
14274 mkexpr( ccIR_subnormal ),
14275 mkU32( 0x1 ) ) ) ), // ccIR code for LT
14276 unop( Iop_Not32,
14277 binop( Iop_Or32,
14278 binop( Iop_Or32,
14279 mkexpr( infinity_true ),
14280 mkexpr( zero_true) ),
14281 binop( Iop_Or32,
14282 mkexpr( QNaN_true ),
14283 mkexpr( SNaN_true ) ) ) ) ) );
14285 /* Normal number is not subnormal, infinity, NaN or Zero */
14286 assign( normal_true,
14287 unop( Iop_Not32,
14288 binop( Iop_Or32,
14289 binop( Iop_Or32,
14290 mkexpr( infinity_true ),
14291 mkexpr( zero_true ) ),
14292 binop( Iop_Or32,
14293 mkexpr( subnormal_true ),
14294 binop( Iop_Or32,
14295 mkexpr( QNaN_true ),
14296 mkexpr( SNaN_true ) ) ) ) ) );
14298 /* Calculate the DCM bit field based on the tests for the specific
14299 * instruction
14301 if (opc2 == 0xC2) { // dtstdc, dtstdcq
14302 /* DCM[0:5] Bit Data Class definition
14303 * 0 Zero
14304 * 1 Subnormal
14305 * 2 Normal
14306 * 3 Infinity
14307 * 4 Quiet NaN
14308 * 5 Signaling NaN
14311 assign( dcm0, binop( Iop_Shl32,
14312 mkexpr( zero_true ),
14313 mkU8( 5 ) ) );
14314 assign( dcm1, binop( Iop_Shl32,
14315 binop( Iop_And32,
14316 mkexpr( subnormal_true ),
14317 mkU32( 1 ) ),
14318 mkU8( 4 ) ) );
14319 assign( dcm2, binop( Iop_Shl32,
14320 binop( Iop_And32,
14321 mkexpr( normal_true ),
14322 mkU32( 1 ) ),
14323 mkU8( 3 ) ) );
14324 assign( dcm3, binop( Iop_Shl32,
14325 binop( Iop_And32,
14326 mkexpr( infinity_true),
14327 mkU32( 1 ) ),
14328 mkU8( 2 ) ) );
14329 assign( dcm4, binop( Iop_Shl32,
14330 binop( Iop_And32,
14331 mkexpr( QNaN_true ),
14332 mkU32( 1 ) ),
14333 mkU8( 1 ) ) );
14334 assign( dcm5, binop( Iop_And32, mkexpr( SNaN_true), mkU32( 1 ) ) );
14336 } else if (opc2 == 0xE2) { // dtstdg, dtstdgq
14337 /* check if the exponent is extreme */
14338 assign( extreme_true, binop( Iop_Or32,
14339 unop( Iop_1Sto32,
14340 binop( Iop_CmpEQ32,
14341 mkexpr( exponent ),
14342 mkU32( max_exp ) ) ),
14343 unop( Iop_1Sto32,
14344 binop( Iop_CmpEQ32,
14345 mkexpr( exponent ),
14346 mkU32( min_exp ) ) ) ) );
14348 /* Check if LMD is zero */
14349 Get_lmd( &lmd, binop( Iop_Shr32,
14350 mkexpr( gfield ), mkU8( 31 - 5 ) ) );
14352 assign( lmd_zero_true, unop( Iop_1Sto32,
14353 binop( Iop_CmpEQ32,
14354 mkexpr( lmd ),
14355 mkU32( 0 ) ) ) );
14357 /* DCM[0:5] Bit Data Class definition
14358 * 0 Zero with non-extreme exponent
14359 * 1 Zero with extreme exponent
14360 * 2 Subnormal or (Normal with extreme exponent)
14361 * 3 Normal with non-extreme exponent and
14362 * leftmost zero digit in significand
14363 * 4 Normal with non-extreme exponent and
14364 * leftmost nonzero digit in significand
14365 * 5 Special symbol (Infinity, QNaN, or SNaN)
14367 assign( dcm0, binop( Iop_Shl32,
14368 binop( Iop_And32,
14369 binop( Iop_And32,
14370 unop( Iop_Not32,
14371 mkexpr( extreme_true ) ),
14372 mkexpr( zero_true ) ),
14373 mkU32( 0x1 ) ),
14374 mkU8( 5 ) ) );
14376 assign( dcm1, binop( Iop_Shl32,
14377 binop( Iop_And32,
14378 binop( Iop_And32,
14379 mkexpr( extreme_true ),
14380 mkexpr( zero_true ) ),
14381 mkU32( 0x1 ) ),
14382 mkU8( 4 ) ) );
14384 assign( dcm2, binop( Iop_Shl32,
14385 binop( Iop_And32,
14386 binop( Iop_Or32,
14387 binop( Iop_And32,
14388 mkexpr( extreme_true ),
14389 mkexpr( normal_true ) ),
14390 mkexpr( subnormal_true ) ),
14391 mkU32( 0x1 ) ),
14392 mkU8( 3 ) ) );
14394 assign( dcm3, binop( Iop_Shl32,
14395 binop( Iop_And32,
14396 binop( Iop_And32,
14397 binop( Iop_And32,
14398 unop( Iop_Not32,
14399 mkexpr( extreme_true ) ),
14400 mkexpr( normal_true ) ),
14401 unop( Iop_1Sto32,
14402 binop( Iop_CmpEQ32,
14403 mkexpr( lmd ),
14404 mkU32( 0 ) ) ) ),
14405 mkU32( 0x1 ) ),
14406 mkU8( 2 ) ) );
14408 assign( dcm4, binop( Iop_Shl32,
14409 binop( Iop_And32,
14410 binop( Iop_And32,
14411 binop( Iop_And32,
14412 unop( Iop_Not32,
14413 mkexpr( extreme_true ) ),
14414 mkexpr( normal_true ) ),
14415 unop( Iop_1Sto32,
14416 binop( Iop_CmpNE32,
14417 mkexpr( lmd ),
14418 mkU32( 0 ) ) ) ),
14419 mkU32( 0x1 ) ),
14420 mkU8( 1 ) ) );
14422 assign( dcm5, binop( Iop_And32,
14423 binop( Iop_Or32,
14424 mkexpr( SNaN_true),
14425 binop( Iop_Or32,
14426 mkexpr( QNaN_true),
14427 mkexpr( infinity_true) ) ),
14428 mkU32( 0x1 ) ) );
14431 /* create DCM field */
14432 assign( DCM_calc,
14433 binop( Iop_Or32,
14434 mkexpr( dcm0 ),
14435 binop( Iop_Or32,
14436 mkexpr( dcm1 ),
14437 binop( Iop_Or32,
14438 mkexpr( dcm2 ),
14439 binop( Iop_Or32,
14440 mkexpr( dcm3 ),
14441 binop( Iop_Or32,
14442 mkexpr( dcm4 ),
14443 mkexpr( dcm5 ) ) ) ) ) ) );
14445 /* Get the sign of the DFP number, ignore sign for QNaN */
14446 assign( sign,
14447 unop( Iop_1Uto32,
14448 binop( Iop_CmpEQ32,
14449 binop( Iop_Shr32,
14450 unop( Iop_64HIto32, mkexpr( frAI64_hi ) ),
14451 mkU8( 63 - 32 ) ),
14452 mkU32( 1 ) ) ) );
14454 /* This instruction generates a four bit field to be stored in the
14455 * condition code register. The condition code register consists of 7
14456 * fields. The field to be written to is specified by the BF (AKA crfD)
14457 * field.
14459 * The field layout is as follows:
14461 * Field Meaning
14462 * 0000 Operand positive with no match
14463 * 0100 Operand positive with at least one match
14464 * 0001 Operand negative with no match
14465 * 0101 Operand negative with at least one match
14467 assign( field, binop( Iop_Or32,
14468 binop( Iop_Shl32,
14469 mkexpr( sign ),
14470 mkU8( 3 ) ),
14471 binop( Iop_Shl32,
14472 unop( Iop_1Uto32,
14473 binop( Iop_CmpNE32,
14474 binop( Iop_And32,
14475 mkU32( DCM ),
14476 mkexpr( DCM_calc ) ),
14477 mkU32( 0 ) ) ),
14478 mkU8( 1 ) ) ) );
14480 putGST_field( PPC_GST_CR, mkexpr( field ), crfD );
14481 putFPCC( mkexpr( field ) );
14482 return True;
14485 static Bool dis_dfp_bcd(UInt theInstr) {
14486 UInt opc2 = ifieldOPClo10( theInstr );
14487 ULong sp = IFIELD(theInstr, 19, 2);
14488 ULong s = IFIELD(theInstr, 20, 1);
14489 UChar frT_addr = ifieldRegDS( theInstr );
14490 UChar frB_addr = ifieldRegB( theInstr );
14491 IRTemp frB = newTemp( Ity_D64 );
14492 IRTemp frBI64 = newTemp( Ity_I64 );
14493 IRTemp result = newTemp( Ity_I64 );
14494 IRTemp resultD64 = newTemp( Ity_D64 );
14495 IRTemp bcd64 = newTemp( Ity_I64 );
14496 IRTemp bcd_u = newTemp( Ity_I32 );
14497 IRTemp bcd_l = newTemp( Ity_I32 );
14498 IRTemp dbcd_u = newTemp( Ity_I32 );
14499 IRTemp dbcd_l = newTemp( Ity_I32 );
14500 IRTemp lmd = newTemp( Ity_I32 );
14502 assign( frB, getDReg( frB_addr ) );
14503 assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
14505 switch ( opc2 ) {
14506 case 0x142: // ddedpd DFP Decode DPD to BCD
14507 DIP( "ddedpd %llu,r%u,r%u\n", sp, frT_addr, frB_addr );
14509 assign( bcd64, unop( Iop_DPBtoBCD, mkexpr( frBI64 ) ) );
14510 assign( bcd_u, unop( Iop_64HIto32, mkexpr( bcd64 ) ) );
14511 assign( bcd_l, unop( Iop_64to32, mkexpr( bcd64 ) ) );
14513 if ( ( sp == 0 ) || ( sp == 1 ) ) {
14514 /* Unsigned BCD string */
14515 Get_lmd( &lmd,
14516 binop( Iop_Shr32,
14517 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
14518 mkU8( 31 - 5 ) ) ); // G-field[0:4]
14520 assign( result,
14521 binop( Iop_32HLto64,
14522 binop( Iop_Or32,
14523 binop( Iop_Shl32, mkexpr( lmd ), mkU8( 28 ) ),
14524 mkexpr( bcd_u ) ),
14525 mkexpr( bcd_l ) ) );
14527 } else {
14528 /* Signed BCD string, the cases for sp 2 and 3 only differ in how
14529 * the positive and negative values are encoded in the least
14530 * significant bits.
14532 IRTemp sign = newTemp( Ity_I32 );
14534 if (sp == 2) {
14535 /* Positive sign = 0xC, negative sign = 0xD */
14537 assign( sign,
14538 binop( Iop_Or32,
14539 binop( Iop_Shr32,
14540 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
14541 mkU8( 31 ) ),
14542 mkU32( 0xC ) ) );
14544 } else if ( sp == 3 ) {
14545 /* Positive sign = 0xF, negative sign = 0xD */
14546 IRTemp tmp32 = newTemp( Ity_I32 );
14548 /* Complement sign bit then OR into bit position 1 */
14549 assign( tmp32,
14550 binop( Iop_Xor32,
14551 binop( Iop_Shr32,
14552 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
14553 mkU8( 30 ) ),
14554 mkU32( 0x2 ) ) );
14556 assign( sign, binop( Iop_Or32, mkexpr( tmp32 ), mkU32( 0xD ) ) );
14558 } else {
14559 vpanic( "The impossible happened: dis_dfp_bcd(ppc), undefined SP field" );
14562 /* Put sign in bottom 4 bits, move most significant 4-bits from
14563 * bcd_l to bcd_u.
14565 assign( result,
14566 binop( Iop_32HLto64,
14567 binop( Iop_Or32,
14568 binop( Iop_Shr32,
14569 mkexpr( bcd_l ),
14570 mkU8( 28 ) ),
14571 binop( Iop_Shl32,
14572 mkexpr( bcd_u ),
14573 mkU8( 4 ) ) ),
14574 binop( Iop_Or32,
14575 mkexpr( sign ),
14576 binop( Iop_Shl32,
14577 mkexpr( bcd_l ),
14578 mkU8( 4 ) ) ) ) );
14581 putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result ) ) );
14582 break;
14584 case 0x342: // denbcd DFP Encode BCD to DPD
14586 IRTemp valid_mask = newTemp( Ity_I32 );
14587 IRTemp invalid_mask = newTemp( Ity_I32 );
14588 IRTemp without_lmd = newTemp( Ity_I64 );
14589 IRTemp tmp64 = newTemp( Ity_I64 );
14590 IRTemp dbcd64 = newTemp( Ity_I64 );
14591 IRTemp left_exp = newTemp( Ity_I32 );
14592 IRTemp g0_4 = newTemp( Ity_I32 );
14594 DIP( "denbcd %llu,r%u,r%u\n", s, frT_addr, frB_addr );
14596 if ( s == 0 ) {
14597 /* Unsigned BCD string */
14598 assign( dbcd64, unop( Iop_BCDtoDPB, mkexpr(frBI64 ) ) );
14599 assign( dbcd_u, unop( Iop_64HIto32, mkexpr( dbcd64 ) ) );
14600 assign( dbcd_l, unop( Iop_64to32, mkexpr( dbcd64 ) ) );
14602 assign( lmd,
14603 binop( Iop_Shr32,
14604 binop( Iop_And32,
14605 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
14606 mkU32( 0xF0000000 ) ),
14607 mkU8( 28 ) ) );
14609 assign( invalid_mask,
14610 bcd_digit_inval( unop( Iop_64HIto32, mkexpr( frBI64 ) ),
14611 unop( Iop_64to32, mkexpr( frBI64 ) ) ) );
14612 assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
14614 assign( without_lmd,
14615 unop( Iop_ReinterpD64asI64,
14616 binop( Iop_InsertExpD64,
14617 mkU64( DFP_LONG_BIAS ),
14618 unop( Iop_ReinterpI64asD64,
14619 binop( Iop_32HLto64,
14620 mkexpr( dbcd_u ),
14621 mkexpr( dbcd_l ) ) ) ) ) );
14622 assign( left_exp,
14623 binop( Iop_Shr32,
14624 binop( Iop_And32,
14625 unop( Iop_64HIto32, mkexpr( without_lmd ) ),
14626 mkU32( 0x60000000 ) ),
14627 mkU8( 29 ) ) );
14629 assign( g0_4,
14630 binop( Iop_Shl32,
14631 Gfield_encoding( mkexpr( left_exp ), mkexpr( lmd ) ),
14632 mkU8( 26 ) ) );
14634 assign( tmp64,
14635 binop( Iop_32HLto64,
14636 binop( Iop_Or32,
14637 binop( Iop_And32,
14638 unop( Iop_64HIto32,
14639 mkexpr( without_lmd ) ),
14640 mkU32( 0x83FFFFFF ) ),
14641 mkexpr( g0_4 ) ),
14642 unop( Iop_64to32, mkexpr( without_lmd ) ) ) );
14644 } else if ( s == 1 ) {
14645 IRTemp sign = newTemp( Ity_I32 );
14646 IRTemp sign_bit = newTemp( Ity_I32 );
14647 IRTemp pos_sign_mask = newTemp( Ity_I32 );
14648 IRTemp neg_sign_mask = newTemp( Ity_I32 );
14649 IRTemp tmp = newTemp( Ity_I64 );
14651 /* Signed BCD string, least significant 4 bits are sign bits
14652 * positive sign = 0xC, negative sign = 0xD
14654 assign( tmp, unop( Iop_BCDtoDPB,
14655 binop( Iop_32HLto64,
14656 binop( Iop_Shr32,
14657 unop( Iop_64HIto32,
14658 mkexpr( frBI64 ) ),
14659 mkU8( 4 ) ),
14660 binop( Iop_Or32,
14661 binop( Iop_Shr32,
14662 unop( Iop_64to32,
14663 mkexpr( frBI64 ) ),
14664 mkU8( 4 ) ),
14665 binop( Iop_Shl32,
14666 unop( Iop_64HIto32,
14667 mkexpr( frBI64 ) ),
14668 mkU8( 28 ) ) ) ) ) );
14670 assign( dbcd_u, unop( Iop_64HIto32, mkexpr( tmp ) ) );
14671 assign( dbcd_l, unop( Iop_64to32, mkexpr( tmp ) ) );
14673 /* Get the sign of the BCD string. */
14674 assign( sign,
14675 binop( Iop_And32,
14676 unop( Iop_64to32, mkexpr( frBI64 ) ),
14677 mkU32( 0xF ) ) );
14679 assign( neg_sign_mask, Generate_neg_sign_mask( mkexpr( sign ) ) );
14680 assign( pos_sign_mask, Generate_pos_sign_mask( mkexpr( sign ) ) );
14681 assign( sign_bit,
14682 Generate_sign_bit( mkexpr( pos_sign_mask ),
14683 mkexpr( neg_sign_mask ) ) );
14685 /* Check for invalid sign and BCD digit. Don't check the bottom
14686 * four bits of bcd_l as that is the sign value.
14688 assign( invalid_mask,
14689 Generate_inv_mask(
14690 bcd_digit_inval( unop( Iop_64HIto32,
14691 mkexpr( frBI64 ) ),
14692 binop( Iop_Shr32,
14693 unop( Iop_64to32,
14694 mkexpr( frBI64 ) ),
14695 mkU8( 4 ) ) ),
14696 mkexpr( pos_sign_mask ),
14697 mkexpr( neg_sign_mask ) ) );
14699 assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
14701 /* Generate the result assuming the sign value was valid. */
14702 assign( tmp64,
14703 unop( Iop_ReinterpD64asI64,
14704 binop( Iop_InsertExpD64,
14705 mkU64( DFP_LONG_BIAS ),
14706 unop( Iop_ReinterpI64asD64,
14707 binop( Iop_32HLto64,
14708 binop( Iop_Or32,
14709 mkexpr( dbcd_u ),
14710 mkexpr( sign_bit ) ),
14711 mkexpr( dbcd_l ) ) ) ) ) );
14714 /* Generate the value to store depending on the validity of the
14715 * sign value and the validity of the BCD digits.
14717 assign( resultD64,
14718 unop( Iop_ReinterpI64asD64,
14719 binop( Iop_32HLto64,
14720 binop( Iop_Or32,
14721 binop( Iop_And32,
14722 mkexpr( valid_mask ),
14723 unop( Iop_64HIto32,
14724 mkexpr( tmp64 ) ) ),
14725 binop( Iop_And32,
14726 mkU32( 0x7C000000 ),
14727 mkexpr( invalid_mask ) ) ),
14728 binop( Iop_Or32,
14729 binop( Iop_And32,
14730 mkexpr( valid_mask ),
14731 unop( Iop_64to32, mkexpr( tmp64 ) ) ),
14732 binop( Iop_And32,
14733 mkU32( 0x0 ),
14734 mkexpr( invalid_mask ) ) ) ) ) );
14735 putDReg( frT_addr, mkexpr( resultD64 ) );
14737 break;
14738 default:
14739 vpanic( "ERROR: dis_dfp_bcd(ppc), undefined opc2 case " );
14740 return False;
14742 return True;
14745 static Bool dis_dfp_bcdq( UInt theInstr )
14747 UInt opc2 = ifieldOPClo10( theInstr );
14748 ULong sp = IFIELD(theInstr, 19, 2);
14749 ULong s = IFIELD(theInstr, 20, 1);
14750 IRTemp frB_hi = newTemp( Ity_D64 );
14751 IRTemp frB_lo = newTemp( Ity_D64 );
14752 IRTemp frBI64_hi = newTemp( Ity_I64 );
14753 IRTemp frBI64_lo = newTemp( Ity_I64 );
14754 UChar frT_addr = ifieldRegDS( theInstr );
14755 UChar frB_addr = ifieldRegB( theInstr );
14757 IRTemp lmd = newTemp( Ity_I32 );
14758 IRTemp result_hi = newTemp( Ity_I64 );
14759 IRTemp result_lo = newTemp( Ity_I64 );
14761 assign( frB_hi, getDReg( frB_addr ) );
14762 assign( frB_lo, getDReg( frB_addr + 1 ) );
14763 assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
14764 assign( frBI64_lo, unop( Iop_ReinterpD64asI64, mkexpr( frB_lo ) ) );
14766 switch ( opc2 ) {
14767 case 0x142: // ddedpdq DFP Decode DPD to BCD
14769 IRTemp low_60_u = newTemp( Ity_I32 );
14770 IRTemp low_60_l = newTemp( Ity_I32 );
14771 IRTemp mid_60_u = newTemp( Ity_I32 );
14772 IRTemp mid_60_l = newTemp( Ity_I32 );
14773 IRTemp top_12_l = newTemp( Ity_I32 );
14775 DIP( "ddedpdq %llu,r%u,r%u\n", sp, frT_addr, frB_addr );
14777 /* Note, instruction only stores the lower 32 BCD digits in
14778 * the result
14780 Generate_132_bit_bcd_string( mkexpr( frBI64_hi ),
14781 mkexpr( frBI64_lo ),
14782 &top_12_l,
14783 &mid_60_u,
14784 &mid_60_l,
14785 &low_60_u,
14786 &low_60_l );
14788 if ( ( sp == 0 ) || ( sp == 1 ) ) {
14789 /* Unsigned BCD string */
14790 assign( result_hi,
14791 binop( Iop_32HLto64,
14792 binop( Iop_Or32,
14793 binop( Iop_Shl32,
14794 mkexpr( top_12_l ),
14795 mkU8( 24 ) ),
14796 binop( Iop_Shr32,
14797 mkexpr( mid_60_u ),
14798 mkU8( 4 ) ) ),
14799 binop( Iop_Or32,
14800 binop( Iop_Shl32,
14801 mkexpr( mid_60_u ),
14802 mkU8( 28 ) ),
14803 binop( Iop_Shr32,
14804 mkexpr( mid_60_l ),
14805 mkU8( 4 ) ) ) ) );
14807 assign( result_lo,
14808 binop( Iop_32HLto64,
14809 binop( Iop_Or32,
14810 binop( Iop_Shl32,
14811 mkexpr( mid_60_l ),
14812 mkU8( 28 ) ),
14813 mkexpr( low_60_u ) ),
14814 mkexpr( low_60_l ) ) );
14816 } else {
14817 /* Signed BCD string, the cases for sp 2 and 3 only differ in how
14818 * the positive and negative values are encoded in the least
14819 * significant bits.
14821 IRTemp sign = newTemp( Ity_I32 );
14823 if ( sp == 2 ) {
14824 /* Positive sign = 0xC, negative sign = 0xD */
14825 assign( sign,
14826 binop( Iop_Or32,
14827 binop( Iop_Shr32,
14828 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
14829 mkU8( 31 ) ),
14830 mkU32( 0xC ) ) );
14832 } else if ( sp == 3 ) {
14833 IRTemp tmp32 = newTemp( Ity_I32 );
14835 /* Positive sign = 0xF, negative sign = 0xD.
14836 * Need to complement sign bit then OR into bit position 1.
14838 assign( tmp32,
14839 binop( Iop_Xor32,
14840 binop( Iop_Shr32,
14841 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
14842 mkU8( 30 ) ),
14843 mkU32( 0x2 ) ) );
14845 assign( sign, binop( Iop_Or32, mkexpr( tmp32 ), mkU32( 0xD ) ) );
14847 } else {
14848 vpanic( "The impossible happened: dis_dfp_bcd(ppc), undefined SP field" );
14851 assign( result_hi,
14852 binop( Iop_32HLto64,
14853 binop( Iop_Or32,
14854 binop( Iop_Shl32,
14855 mkexpr( top_12_l ),
14856 mkU8( 28 ) ),
14857 mkexpr( mid_60_u ) ),
14858 mkexpr( mid_60_l ) ) );
14860 assign( result_lo,
14861 binop( Iop_32HLto64,
14862 binop( Iop_Or32,
14863 binop( Iop_Shl32,
14864 mkexpr( low_60_u ),
14865 mkU8( 4 ) ),
14866 binop( Iop_Shr32,
14867 mkexpr( low_60_l ),
14868 mkU8( 28 ) ) ),
14869 binop( Iop_Or32,
14870 binop( Iop_Shl32,
14871 mkexpr( low_60_l ),
14872 mkU8( 4 ) ),
14873 mkexpr( sign ) ) ) );
14876 putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result_hi ) ) );
14877 putDReg( frT_addr + 1,
14878 unop( Iop_ReinterpI64asD64, mkexpr( result_lo ) ) );
14880 break;
14881 case 0x342: // denbcdq DFP Encode BCD to DPD
14883 IRTemp valid_mask = newTemp( Ity_I32 );
14884 IRTemp invalid_mask = newTemp( Ity_I32 );
14885 IRTemp result128 = newTemp( Ity_D128 );
14886 IRTemp dfp_significand = newTemp( Ity_D128 );
14887 IRTemp tmp_hi = newTemp( Ity_I64 );
14888 IRTemp tmp_lo = newTemp( Ity_I64 );
14889 IRTemp dbcd_top_l = newTemp( Ity_I32 );
14890 IRTemp dbcd_mid_u = newTemp( Ity_I32 );
14891 IRTemp dbcd_mid_l = newTemp( Ity_I32 );
14892 IRTemp dbcd_low_u = newTemp( Ity_I32 );
14893 IRTemp dbcd_low_l = newTemp( Ity_I32 );
14894 IRTemp bcd_top_8 = newTemp( Ity_I64 );
14895 IRTemp bcd_mid_60 = newTemp( Ity_I64 );
14896 IRTemp bcd_low_60 = newTemp( Ity_I64 );
14897 IRTemp sign_bit = newTemp( Ity_I32 );
14898 IRTemp tmptop10 = newTemp( Ity_I64 );
14899 IRTemp tmpmid50 = newTemp( Ity_I64 );
14900 IRTemp tmplow50 = newTemp( Ity_I64 );
14901 IRTemp inval_bcd_digit_mask = newTemp( Ity_I32 );
14903 DIP( "denbcd %llu,r%u,r%u\n", s, frT_addr, frB_addr );
14905 if ( s == 0 ) {
14906 /* Unsigned BCD string */
14907 assign( sign_bit, mkU32( 0 ) ); // set to zero for unsigned string
14909 assign( bcd_top_8,
14910 binop( Iop_32HLto64,
14911 mkU32( 0 ),
14912 binop( Iop_And32,
14913 binop( Iop_Shr32,
14914 unop( Iop_64HIto32,
14915 mkexpr( frBI64_hi ) ),
14916 mkU8( 24 ) ),
14917 mkU32( 0xFF ) ) ) );
14918 assign( bcd_mid_60,
14919 binop( Iop_32HLto64,
14920 binop( Iop_Or32,
14921 binop( Iop_Shr32,
14922 unop( Iop_64to32,
14923 mkexpr( frBI64_hi ) ),
14924 mkU8( 28 ) ),
14925 binop( Iop_Shl32,
14926 unop( Iop_64HIto32,
14927 mkexpr( frBI64_hi ) ),
14928 mkU8( 4 ) ) ),
14929 binop( Iop_Or32,
14930 binop( Iop_Shl32,
14931 unop( Iop_64to32,
14932 mkexpr( frBI64_hi ) ),
14933 mkU8( 4 ) ),
14934 binop( Iop_Shr32,
14935 unop( Iop_64HIto32,
14936 mkexpr( frBI64_lo ) ),
14937 mkU8( 28 ) ) ) ) );
14939 /* Note, the various helper functions ignores top 4-bits */
14940 assign( bcd_low_60, mkexpr( frBI64_lo ) );
14942 assign( tmptop10, unop( Iop_BCDtoDPB, mkexpr( bcd_top_8 ) ) );
14943 assign( dbcd_top_l, unop( Iop_64to32, mkexpr( tmptop10 ) ) );
14945 assign( tmpmid50, unop( Iop_BCDtoDPB, mkexpr( bcd_mid_60 ) ) );
14946 assign( dbcd_mid_u, unop( Iop_64HIto32, mkexpr( tmpmid50 ) ) );
14947 assign( dbcd_mid_l, unop( Iop_64to32, mkexpr( tmpmid50 ) ) );
14949 assign( tmplow50, unop( Iop_BCDtoDPB, mkexpr( bcd_low_60 ) ) );
14950 assign( dbcd_low_u, unop( Iop_64HIto32, mkexpr( tmplow50 ) ) );
14951 assign( dbcd_low_l, unop( Iop_64to32, mkexpr( tmplow50 ) ) );
14953 /* The entire BCD string fits in lower 110-bits. The LMD = 0,
14954 * value is not part of the final result. Only the right most
14955 * BCD digits are stored.
14957 assign( lmd, mkU32( 0 ) );
14959 assign( invalid_mask,
14960 binop( Iop_Or32,
14961 bcd_digit_inval( mkU32( 0 ),
14962 unop( Iop_64to32,
14963 mkexpr( bcd_top_8 ) ) ),
14964 binop( Iop_Or32,
14965 bcd_digit_inval( unop( Iop_64HIto32,
14966 mkexpr( bcd_mid_60 ) ),
14967 unop( Iop_64to32,
14968 mkexpr( bcd_mid_60 ) ) ),
14969 bcd_digit_inval( unop( Iop_64HIto32,
14970 mkexpr( bcd_low_60 ) ),
14971 unop( Iop_64to32,
14972 mkexpr( bcd_low_60 ) )
14973 ) ) ) );
14975 } else if ( s == 1 ) {
14976 IRTemp sign = newTemp( Ity_I32 );
14977 IRTemp zero = newTemp( Ity_I32 );
14978 IRTemp pos_sign_mask = newTemp( Ity_I32 );
14979 IRTemp neg_sign_mask = newTemp( Ity_I32 );
14981 /* The sign of the BCD string is stored in lower 4 bits */
14982 assign( sign,
14983 binop( Iop_And32,
14984 unop( Iop_64to32, mkexpr( frBI64_lo ) ),
14985 mkU32( 0xF ) ) );
14986 assign( neg_sign_mask, Generate_neg_sign_mask( mkexpr( sign ) ) );
14987 assign( pos_sign_mask, Generate_pos_sign_mask( mkexpr( sign ) ) );
14988 assign( sign_bit,
14989 Generate_sign_bit( mkexpr( pos_sign_mask ),
14990 mkexpr( neg_sign_mask ) ) );
14992 /* Generate the value assuminig the sign and BCD digits are vaild */
14993 assign( bcd_top_8,
14994 binop( Iop_32HLto64,
14995 mkU32( 0x0 ),
14996 binop( Iop_Shr32,
14997 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
14998 mkU8( 28 ) ) ) );
15000 /* The various helper routines ignore the upper 4-bits */
15001 assign( bcd_mid_60, mkexpr( frBI64_hi ) );
15003 /* Remove bottom four sign bits */
15004 assign( bcd_low_60,
15005 binop( Iop_32HLto64,
15006 binop( Iop_Shr32,
15007 unop( Iop_64HIto32,
15008 mkexpr( frBI64_lo ) ),
15009 mkU8( 4 ) ),
15010 binop( Iop_Or32,
15011 binop( Iop_Shl32,
15012 unop( Iop_64HIto32,
15013 mkexpr( frBI64_lo ) ),
15014 mkU8( 28 ) ),
15015 binop( Iop_Shr32,
15016 unop( Iop_64to32,
15017 mkexpr( frBI64_lo ) ),
15018 mkU8( 4 ) ) ) ) );
15019 assign( tmptop10, unop( Iop_BCDtoDPB, mkexpr(bcd_top_8 ) ) );
15020 assign( dbcd_top_l, unop( Iop_64to32, mkexpr( tmptop10 ) ) );
15022 assign( tmpmid50, unop( Iop_BCDtoDPB, mkexpr(bcd_mid_60 ) ) );
15023 assign( dbcd_mid_u, unop( Iop_64HIto32, mkexpr( tmpmid50 ) ) );
15024 assign( dbcd_mid_l, unop( Iop_64to32, mkexpr( tmpmid50 ) ) );
15026 assign( tmplow50, unop( Iop_BCDtoDPB, mkexpr( bcd_low_60 ) ) );
15027 assign( dbcd_low_u, unop( Iop_64HIto32, mkexpr( tmplow50 ) ) );
15028 assign( dbcd_low_l, unop( Iop_64to32, mkexpr( tmplow50 ) ) );
15030 /* The entire BCD string fits in lower 110-bits. The LMD value
15031 * is not stored in the final result for the DFP Long instruction.
15033 assign( lmd, mkU32( 0 ) );
15035 /* Check for invalid sign and invalid BCD digit. Don't check the
15036 * bottom four bits of frBI64_lo as that is the sign value.
15038 assign( zero, mkU32( 0 ) );
15039 assign( inval_bcd_digit_mask,
15040 binop( Iop_Or32,
15041 bcd_digit_inval( mkexpr( zero ),
15042 unop( Iop_64to32,
15043 mkexpr( bcd_top_8 ) ) ),
15044 binop( Iop_Or32,
15045 bcd_digit_inval( unop( Iop_64HIto32,
15046 mkexpr( bcd_mid_60 ) ),
15047 unop( Iop_64to32,
15048 mkexpr( bcd_mid_60 ) ) ),
15049 bcd_digit_inval( unop( Iop_64HIto32,
15050 mkexpr( frBI64_lo ) ),
15051 binop( Iop_Shr32,
15052 unop( Iop_64to32,
15053 mkexpr( frBI64_lo ) ),
15054 mkU8( 4 ) ) ) ) ) );
15055 assign( invalid_mask,
15056 Generate_inv_mask( mkexpr( inval_bcd_digit_mask ),
15057 mkexpr( pos_sign_mask ),
15058 mkexpr( neg_sign_mask ) ) );
15062 assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
15064 /* Calculate the value of the result assuming sign and BCD digits
15065 * are all valid.
15067 assign( dfp_significand,
15068 binop( Iop_D64HLtoD128,
15069 unop( Iop_ReinterpI64asD64,
15070 binop( Iop_32HLto64,
15071 binop( Iop_Or32,
15072 mkexpr( sign_bit ),
15073 mkexpr( dbcd_top_l ) ),
15074 binop( Iop_Or32,
15075 binop( Iop_Shl32,
15076 mkexpr( dbcd_mid_u ),
15077 mkU8( 18 ) ),
15078 binop( Iop_Shr32,
15079 mkexpr( dbcd_mid_l ),
15080 mkU8( 14 ) ) ) ) ),
15081 unop( Iop_ReinterpI64asD64,
15082 binop( Iop_32HLto64,
15083 binop( Iop_Or32,
15084 mkexpr( dbcd_low_u ),
15085 binop( Iop_Shl32,
15086 mkexpr( dbcd_mid_l ),
15087 mkU8( 18 ) ) ),
15088 mkexpr( dbcd_low_l ) ) ) ) );
15090 /* Break the result back down to 32-bit chunks and replace chunks.
15091 * If there was an invalid BCD digit or invalid sign value, replace
15092 * the calculated result with the invalid bit string.
15094 assign( result128,
15095 binop( Iop_InsertExpD128,
15096 mkU64( DFP_EXTND_BIAS ),
15097 mkexpr( dfp_significand ) ) );
15099 assign( tmp_hi,
15100 unop( Iop_ReinterpD64asI64,
15101 unop( Iop_D128HItoD64, mkexpr( result128 ) ) ) );
15103 assign( tmp_lo,
15104 unop( Iop_ReinterpD64asI64,
15105 unop( Iop_D128LOtoD64, mkexpr( result128 ) ) ) );
15107 assign( result_hi,
15108 binop( Iop_32HLto64,
15109 binop( Iop_Or32,
15110 binop( Iop_And32,
15111 mkexpr( valid_mask ),
15112 unop( Iop_64HIto32, mkexpr( tmp_hi ) ) ),
15113 binop( Iop_And32,
15114 mkU32( 0x7C000000 ),
15115 mkexpr( invalid_mask ) ) ),
15116 binop( Iop_Or32,
15117 binop( Iop_And32,
15118 mkexpr( valid_mask ),
15119 unop( Iop_64to32, mkexpr( tmp_hi ) ) ),
15120 binop( Iop_And32,
15121 mkU32( 0x0 ),
15122 mkexpr( invalid_mask ) ) ) ) );
15124 assign( result_lo,
15125 binop( Iop_32HLto64,
15126 binop( Iop_Or32,
15127 binop( Iop_And32,
15128 mkexpr( valid_mask ),
15129 unop( Iop_64HIto32, mkexpr( tmp_lo ) ) ),
15130 binop( Iop_And32,
15131 mkU32( 0x0 ),
15132 mkexpr( invalid_mask ) ) ),
15133 binop( Iop_Or32,
15134 binop( Iop_And32,
15135 mkexpr( valid_mask ),
15136 unop( Iop_64to32, mkexpr( tmp_lo ) ) ),
15137 binop( Iop_And32,
15138 mkU32( 0x0 ),
15139 mkexpr( invalid_mask ) ) ) ) );
15141 putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result_hi ) ) );
15142 putDReg( frT_addr + 1,
15143 unop( Iop_ReinterpI64asD64, mkexpr( result_lo ) ) );
15146 break;
15147 default:
15148 vpanic( "ERROR: dis_dfp_bcdq(ppc), undefined opc2 case " );
15149 break;
15151 return True;
15154 static Bool dis_dfp_significant_digits( UInt theInstr )
15156 UInt opc1 = ifieldOPC( theInstr );
15157 UInt opc2 = ifieldOPClo10(theInstr);
15158 UChar frA_addr = ifieldRegA( theInstr );
15159 UChar frB_addr = ifieldRegB( theInstr );
15160 IRTemp frA = newTemp( Ity_D64 );
15161 IRTemp B_sig = newTemp( Ity_I8 );
15162 IRTemp K = newTemp( Ity_I8 );
15163 IRTemp lmd_B = newTemp( Ity_I32 );
15164 IRTemp field = newTemp( Ity_I32 );
15165 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
15166 IRTemp Unordered_true = newTemp( Ity_I32 );
15167 IRTemp Eq_true_mask = newTemp( Ity_I32 );
15168 IRTemp Lt_true_mask = newTemp( Ity_I32 );
15169 IRTemp Gt_true_mask = newTemp( Ity_I32 );
15170 IRTemp KisZero_true_mask = newTemp( Ity_I32 );
15171 IRTemp KisZero_false_mask = newTemp( Ity_I32 );
15172 IRTemp cc = newTemp( Ity_I32 );
15173 UChar UIM = toUChar( IFIELD( theInstr, 16, 6 ) );
15174 IRTemp BCD_valid = newTemp( Ity_I32 );
15176 if (opc2 == 0x2A2) { // dtstsf DFP Test Significance
15177 // dtstsfq DFP Test Significance Quad
15178 /* Get the reference singificance stored in frA */
15179 assign( frA, getDReg( frA_addr ) );
15181 /* Convert from 64 bit to 8 bits in two steps. The Iop_64to8 is not
15182 * supported in 32-bit mode.
15184 assign( K, unop( Iop_32to8,
15185 binop( Iop_And32,
15186 unop( Iop_64to32,
15187 unop( Iop_ReinterpD64asI64,
15188 mkexpr( frA ) ) ),
15189 mkU32( 0x3F ) ) ) );
15191 } else if (opc2 == 0x2A3) { // dtstsfi DFP Test Significance Immediate
15192 // dtstsfiq DFP Test Significance Quad Immediate
15193 /* get the significane from the immediate field */
15194 assign( K, mkU8( UIM) );
15196 } else {
15197 vex_printf("dis_dfp_significant_digits(ppc)(opc2) wrong\n");
15198 return False;
15201 switch ( opc1 ) {
15202 case 0x3b: // dtstsf DFP Test Significance
15203 // dtstsfi DFP Test Significance Immediate
15205 IRTemp frB = newTemp( Ity_D64 );
15206 IRTemp frBI64 = newTemp( Ity_I64 );
15207 IRTemp B_bcd_u = newTemp( Ity_I32 );
15208 IRTemp B_bcd_l = newTemp( Ity_I32 );
15209 IRTemp tmp64 = newTemp( Ity_I64 );
15211 if (opc2 == 0x2A2) {
15212 DIP( "dtstsf %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
15213 } else {
15214 DIP( "dtstsfi %u,%u,r%u\n", crfD, UIM, frB_addr );
15217 assign( frB, getDReg( frB_addr ) );
15218 assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
15220 /* Get the BCD string for the value stored in a series of I32 values.
15221 * Count the number of leading zeros. Subtract the number of leading
15222 * zeros from 16 (maximum number of significant digits in DFP
15223 * Long).
15225 Get_lmd( &lmd_B,
15226 binop( Iop_Shr32,
15227 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
15228 mkU8( 31 - 5 ) ) ); // G-field[0:4]
15230 assign( tmp64, unop( Iop_DPBtoBCD, mkexpr( frBI64 ) ) );
15231 assign( B_bcd_u, unop( Iop_64HIto32, mkexpr( tmp64 ) ) );
15232 assign( B_bcd_l, unop( Iop_64to32, mkexpr( tmp64 ) ) );
15234 assign( B_sig,
15235 binop( Iop_Sub8,
15236 mkU8( DFP_LONG_MAX_SIG_DIGITS ),
15237 Count_leading_zeros_60( mkexpr( lmd_B ),
15238 mkexpr( B_bcd_u ),
15239 mkexpr( B_bcd_l ) ) ) );
15241 assign( BCD_valid,
15242 binop( Iop_Or32,
15243 bcd_digit_inval( mkexpr( B_bcd_u), mkexpr( B_bcd_l) ),
15244 bcd_digit_inval( mkexpr( lmd_B), mkU32( 0 ) ) ) );
15246 /* Set unordered to True if the number is NaN, Inf or an invalid
15247 * digit.
15249 assign( Unordered_true,
15250 binop( Iop_Or32,
15251 Check_unordered( mkexpr( frBI64 ) ),
15252 mkexpr( BCD_valid) ) );
15254 break;
15255 case 0x3F: // dtstsfq DFP Test Significance
15256 // dtstsfqi DFP Test Significance Immediate
15258 IRTemp frB_hi = newTemp( Ity_D64 );
15259 IRTemp frB_lo = newTemp( Ity_D64 );
15260 IRTemp frBI64_hi = newTemp( Ity_I64 );
15261 IRTemp frBI64_lo = newTemp( Ity_I64 );
15262 IRTemp B_low_60_u = newTemp( Ity_I32 );
15263 IRTemp B_low_60_l = newTemp( Ity_I32 );
15264 IRTemp B_mid_60_u = newTemp( Ity_I32 );
15265 IRTemp B_mid_60_l = newTemp( Ity_I32 );
15266 IRTemp B_top_12_l = newTemp( Ity_I32 );
15268 if (opc2 == 0x2A2) {
15269 DIP( "dtstsfq %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
15270 } else {
15271 DIP( "dtstsfiq %u,%u,r%u\n", crfD, UIM, frB_addr );
15274 assign( frB_hi, getDReg( frB_addr ) );
15275 assign( frB_lo, getDReg( frB_addr + 1 ) );
15277 assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
15278 assign( frBI64_lo, unop( Iop_ReinterpD64asI64, mkexpr( frB_lo ) ) );
15280 /* Get the BCD string for the value stored in a series of I32 values.
15281 * Count the number of leading zeros. Subtract the number of leading
15282 * zeros from 32 (maximum number of significant digits in DFP
15283 * extended).
15285 Get_lmd( &lmd_B,
15286 binop( Iop_Shr32,
15287 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
15288 mkU8( 31 - 5 ) ) ); // G-field[0:4]
15290 Generate_132_bit_bcd_string( mkexpr( frBI64_hi ),
15291 mkexpr( frBI64_lo ),
15292 &B_top_12_l,
15293 &B_mid_60_u,
15294 &B_mid_60_l,
15295 &B_low_60_u,
15296 &B_low_60_l );
15298 assign( BCD_valid,
15299 binop( Iop_Or32,
15300 binop( Iop_Or32,
15301 bcd_digit_inval( mkexpr( lmd_B ),
15302 mkexpr( B_top_12_l ) ),
15303 bcd_digit_inval( mkexpr( B_mid_60_u ),
15304 mkexpr( B_mid_60_l ) ) ),
15305 bcd_digit_inval( mkexpr( B_low_60_u ),
15306 mkexpr( B_low_60_l ) ) ) );
15308 assign( B_sig,
15309 binop( Iop_Sub8,
15310 mkU8( DFP_EXTND_MAX_SIG_DIGITS ),
15311 Count_leading_zeros_128( mkexpr( lmd_B ),
15312 mkexpr( B_top_12_l ),
15313 mkexpr( B_mid_60_u ),
15314 mkexpr( B_mid_60_l ),
15315 mkexpr( B_low_60_u ),
15316 mkexpr( B_low_60_l ) ) ) );
15318 /* Set unordered to True if the number is NaN, Inf or an invalid
15319 * digit.
15321 assign( Unordered_true,
15322 binop( Iop_Or32,
15323 Check_unordered( mkexpr( frBI64_hi ) ),
15324 mkexpr( BCD_valid) ) );
15326 break;
15329 /* Compare (16 - cnt[0]) against K and set the condition code field
15330 * accordingly.
15332 * The field layout is as follows:
15334 * bit[3:0] Description
15335 * 3 K != 0 and K < Number of significant digits if FRB
15336 * 2 K != 0 and K > Number of significant digits if FRB OR K = 0
15337 * 1 K != 0 and K = Number of significant digits if FRB
15338 * 0 K ? Number of significant digits if FRB
15340 assign( Eq_true_mask,
15341 unop( Iop_1Sto32,
15342 binop( Iop_CmpEQ32,
15343 unop( Iop_8Uto32, mkexpr( K ) ),
15344 unop( Iop_8Uto32, mkexpr( B_sig ) ) ) ) );
15345 assign( Lt_true_mask,
15346 unop( Iop_1Sto32,
15347 binop( Iop_CmpLT32U,
15348 unop( Iop_8Uto32, mkexpr( K ) ),
15349 unop( Iop_8Uto32, mkexpr( B_sig ) ) ) ) );
15350 assign( Gt_true_mask,
15351 unop( Iop_1Sto32,
15352 binop( Iop_CmpLT32U,
15353 unop( Iop_8Uto32, mkexpr( B_sig ) ),
15354 unop( Iop_8Uto32, mkexpr( K ) ) ) ) );
15356 assign( KisZero_true_mask,
15357 unop( Iop_1Sto32,
15358 binop( Iop_CmpEQ32,
15359 unop( Iop_8Uto32, mkexpr( K ) ),
15360 mkU32( 0 ) ) ) );
15361 assign( KisZero_false_mask,
15362 unop( Iop_1Sto32,
15363 binop( Iop_CmpNE32,
15364 unop( Iop_8Uto32, mkexpr( K ) ),
15365 mkU32( 0 ) ) ) );
15367 assign( field,
15368 binop( Iop_Or32,
15369 binop( Iop_And32,
15370 mkexpr( KisZero_false_mask ),
15371 binop( Iop_Or32,
15372 binop( Iop_And32,
15373 mkexpr( Lt_true_mask ),
15374 mkU32( 0x8 ) ),
15375 binop( Iop_Or32,
15376 binop( Iop_And32,
15377 mkexpr( Gt_true_mask ),
15378 mkU32( 0x4 ) ),
15379 binop( Iop_And32,
15380 mkexpr( Eq_true_mask ),
15381 mkU32( 0x2 ) ) ) ) ),
15382 binop( Iop_And32,
15383 mkexpr( KisZero_true_mask ),
15384 mkU32( 0x4 ) ) ) );
15386 assign( cc, binop( Iop_Or32,
15387 binop( Iop_And32,
15388 mkexpr( Unordered_true ),
15389 mkU32( 0x1 ) ),
15390 binop( Iop_And32,
15391 unop( Iop_Not32, mkexpr( Unordered_true ) ),
15392 mkexpr( field ) ) ) );
15394 putGST_field( PPC_GST_CR, mkexpr( cc ), crfD );
15395 putFPCC( mkexpr( cc ) );
15397 return True;
15399 /*------------------------------------------------------------*/
15400 /*--- AltiVec Instruction Translation ---*/
15401 /*------------------------------------------------------------*/
15404 Altivec Cache Control Instructions (Data Streams)
15406 static Bool dis_av_datastream ( UInt theInstr )
15408 /* X-Form */
15409 UChar opc1 = ifieldOPC(theInstr);
15410 UChar flag_T = toUChar( IFIELD( theInstr, 25, 1 ) );
15411 UChar flag_A = flag_T;
15412 UChar b23to24 = toUChar( IFIELD( theInstr, 23, 2 ) );
15413 UChar STRM = toUChar( IFIELD( theInstr, 21, 2 ) );
15414 UChar rA_addr = ifieldRegA(theInstr);
15415 UChar rB_addr = ifieldRegB(theInstr);
15416 UInt opc2 = ifieldOPClo10(theInstr);
15417 UChar b0 = ifieldBIT0(theInstr);
15419 if (opc1 != 0x1F || b23to24 != 0 || b0 != 0) {
15420 vex_printf("dis_av_datastream(ppc)(instr)\n");
15421 return False;
15424 switch (opc2) {
15425 case 0x156: // dst (Data Stream Touch, AV p115)
15426 DIP("dst%s r%u,r%u,%d\n", flag_T ? "t" : "",
15427 rA_addr, rB_addr, STRM);
15428 break;
15430 case 0x176: // dstst (Data Stream Touch for Store, AV p117)
15431 DIP("dstst%s r%u,r%u,%d\n", flag_T ? "t" : "",
15432 rA_addr, rB_addr, STRM);
15433 break;
15435 case 0x336: // dss (Data Stream Stop, AV p114)
15436 if (rA_addr != 0 || rB_addr != 0) {
15437 vex_printf("dis_av_datastream(ppc)(opc2,dst)\n");
15438 return False;
15440 if (flag_A == 0) {
15441 DIP("dss %d\n", STRM);
15442 } else {
15443 DIP("dssall\n");
15445 break;
15447 default:
15448 vex_printf("dis_av_datastream(ppc)(opc2)\n");
15449 return False;
15451 return True;
15455 AltiVec Processor Control Instructions
15457 static Bool dis_av_procctl ( UInt theInstr )
15459 /* VX-Form */
15460 UChar opc1 = ifieldOPC(theInstr);
15461 UChar vD_addr = ifieldRegDS(theInstr);
15462 UChar vA_addr = ifieldRegA(theInstr);
15463 UChar vB_addr = ifieldRegB(theInstr);
15464 UInt opc2 = IFIELD( theInstr, 0, 11 );
15466 if (opc1 != 0x4) {
15467 vex_printf("dis_av_procctl(ppc)(instr)\n");
15468 return False;
15471 switch (opc2) {
15472 case 0x604: // mfvscr (Move from VSCR, AV p129)
15473 if (vA_addr != 0 || vB_addr != 0) {
15474 vex_printf("dis_av_procctl(ppc)(opc2,dst)\n");
15475 return False;
15477 DIP("mfvscr v%d\n", vD_addr);
15478 putVReg( vD_addr, unop(Iop_32UtoV128, getGST( PPC_GST_VSCR )) );
15479 break;
15481 case 0x644: { // mtvscr (Move to VSCR, AV p130)
15482 IRTemp vB = newTemp(Ity_V128);
15483 if (vD_addr != 0 || vA_addr != 0) {
15484 vex_printf("dis_av_procctl(ppc)(opc2,dst)\n");
15485 return False;
15487 DIP("mtvscr v%d\n", vB_addr);
15488 assign( vB, getVReg(vB_addr));
15489 putGST( PPC_GST_VSCR, unop(Iop_V128to32, mkexpr(vB)) );
15490 break;
15492 default:
15493 vex_printf("dis_av_procctl(ppc)(opc2)\n");
15494 return False;
15496 return True;
15500 Vector Extend Sign Instructions
15502 static Bool dis_av_extend_sign_count_zero ( UInt theInstr, UInt allow_isa_3_0 )
15504 /* VX-Form, sort of, the A register field is used to select the specific
15505 * sign extension instruction or count leading/trailing zero LSB
15506 * instruction.
15509 UChar opc1 = ifieldOPC( theInstr );
15510 UChar rT_addr = ifieldRegDS (theInstr );
15511 UChar rA_addr = ifieldRegA( theInstr );
15512 UChar vB_addr = ifieldRegB( theInstr );
15513 UInt opc2 = IFIELD( theInstr, 0, 11 );
15515 IRTemp vB = newTemp( Ity_V128 );
15516 IRTemp vT = newTemp( Ity_V128 );
15518 assign( vB, getVReg ( vB_addr ) );
15520 if ( ( opc1 != 0x4 ) && ( opc2 != 0x602 ) ) {
15521 vex_printf("dis_av_extend_sign(ppc)(instr)\n");
15522 return False;
15525 switch ( rA_addr ) {
15526 case 0:
15527 case 1:
15529 UInt i;
15530 IRTemp count[17];
15531 IRTemp bit_zero[16];
15532 IRTemp byte_mask[17];
15534 /* These instructions store the result in the general purpose
15535 * register in the rT_addr field.
15538 byte_mask[0] = newTemp( Ity_I32 );
15539 count[0] = newTemp( Ity_I32 );
15540 assign( count[0], mkU32( 0 ) );
15541 assign( byte_mask[0], mkU32( 0x1 ) );
15543 if ( rA_addr == 0 ) {
15544 // vclzlsbb (Vector Count Leading Zero Least-Significant Bits Byte)
15545 DIP("vclzlsbb %d,v%d\n", rT_addr, vB_addr);
15547 } else {
15548 // vctzlsbb (Vector Count Trailing Zero Least-Significant Bits Byte)
15549 DIP("vctzlsbb %d,v%d\n", rT_addr, vB_addr);
15552 for( i = 0; i < 16; i++ ) {
15553 byte_mask[i+1] = newTemp( Ity_I32 );
15554 count[i+1] = newTemp( Ity_I32 );
15555 bit_zero[i] = newTemp( Ity_I1 );
15557 /* bit_zero[i] = 0x0 until the first 1 bit is found in lsb of
15558 * byte. When the first 1 bit is found it causes the byte_mask
15559 * to change from 0x1 to 0x0. Thus the AND of the lsb and byte_mask
15560 * will be zero which will be equal to the zero byte_mask causing
15561 * the value of bit_zero[i] to be equal to 0x1 for all remaining bits.
15564 if ( rA_addr == 0 )
15565 /* leading zero bit in byte count,
15566 work bytes from left to right
15568 assign( bit_zero[i],
15569 binop( Iop_CmpEQ32,
15570 binop( Iop_And32,
15571 unop( Iop_V128to32,
15572 binop( Iop_ShrV128,
15573 mkexpr( vB ),
15574 mkU8( ( 15 - i) * 8 ) ) ),
15575 mkexpr( byte_mask[i] ) ),
15576 mkexpr( byte_mask[i] ) ) );
15578 else if ( rA_addr == 1 )
15579 /* trailing zero bit in byte count,
15580 * work bytes from right to left
15582 assign( bit_zero[i],
15583 binop( Iop_CmpEQ32,
15584 binop( Iop_And32,
15585 unop( Iop_V128to32,
15586 binop( Iop_ShrV128,
15587 mkexpr( vB ),
15588 mkU8( i * 8 ) ) ),
15589 mkexpr( byte_mask[i] ) ),
15590 mkexpr( byte_mask[i] ) ) );
15592 /* Increment count as long as bit_zero = 0 */
15593 assign( count[i+1], binop( Iop_Add32,
15594 mkexpr( count[i] ),
15595 unop( Iop_1Uto32,
15596 unop( Iop_Not1,
15597 mkexpr( bit_zero[i] ) ) ) ) );
15599 /* If comparison fails to find a zero bit, set the byte_mask to zero
15600 * for all future comparisons so there will be no more matches.
15602 assign( byte_mask[i+1],
15603 binop( Iop_And32,
15604 unop( Iop_1Uto32,
15605 unop( Iop_Not1,
15606 mkexpr( bit_zero[i] ) ) ),
15607 mkexpr( byte_mask[i] ) ) );
15609 putIReg( rT_addr, unop( Iop_32Uto64, mkexpr( count[16] ) ) );
15610 return True;
15613 case 6: // vnegw, Vector Negate Word
15614 DIP("vnegw v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15616 /* multiply each word by -1 */
15617 assign( vT, binop( Iop_Mul32x4, mkexpr( vB ), mkV128( 0xFFFF ) ) );
15618 break;
15620 case 7: // vnegd, Vector Negate Doubleword
15621 DIP("vnegd v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15623 /* multiply each word by -1 */
15624 assign( vT, binop( Iop_64HLtoV128,
15625 binop( Iop_Mul64,
15626 unop( Iop_V128HIto64,
15627 mkexpr( vB ) ),
15628 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
15629 binop( Iop_Mul64,
15630 unop( Iop_V128to64,
15631 mkexpr( vB ) ),
15632 mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) );
15633 break;
15635 case 8: // vprtybw, Vector Parity Byte Word
15636 case 9: // vprtybd, Vector Parity Byte Doubleword
15637 case 10: // vprtybq, Vector Parity Byte Quadword
15639 UInt i;
15640 IRTemp bit_in_byte[16];
15641 IRTemp word_parity[4];
15643 for( i = 0; i < 16; i++ ) {
15644 bit_in_byte[i] = newTemp( Ity_I32 );
15645 assign( bit_in_byte[i],
15646 binop( Iop_And32,
15647 unop( Iop_V128to32,
15648 binop( Iop_ShrV128,
15649 mkexpr( vB ),
15650 mkU8( ( 15 - i ) * 8 ) ) ),
15651 mkU32( 0x1 ) ) );
15654 for( i = 0; i < 4; i++ ) {
15655 word_parity[i] = newTemp(Ity_I32);
15656 assign( word_parity[i],
15657 mkXOr4_32( bit_in_byte[0 + i * 4],
15658 bit_in_byte[1 + i * 4],
15659 bit_in_byte[2 + i * 4],
15660 bit_in_byte[3 + i * 4] ) );
15663 if ( rA_addr == 8 ) {
15664 DIP("vprtybw v%d,v%d", rT_addr, vB_addr);
15666 assign( vT, mkV128from32( word_parity[0], word_parity[1],
15667 word_parity[2], word_parity[3] ) );
15669 } else if ( rA_addr == 9 ) {
15670 DIP("vprtybd v%d,v%d", rT_addr, vB_addr);
15672 assign( vT,
15673 binop( Iop_64HLtoV128,
15674 binop( Iop_32HLto64,
15675 mkU32( 0 ),
15676 binop( Iop_Xor32,
15677 mkexpr( word_parity[0] ),
15678 mkexpr( word_parity[1] ) ) ),
15679 binop( Iop_32HLto64,
15680 mkU32( 0 ),
15681 binop( Iop_Xor32,
15682 mkexpr( word_parity[2] ),
15683 mkexpr( word_parity[3] ) ) ) ) );
15685 } else if ( rA_addr == 10 ) {
15686 DIP("vprtybq v%d,v%d", rT_addr, vB_addr);
15688 assign( vT,
15689 binop( Iop_64HLtoV128,
15690 mkU64( 0 ),
15691 unop( Iop_32Uto64,
15692 mkXOr4_32( word_parity[0],
15693 word_parity[1],
15694 word_parity[2],
15695 word_parity[3] ) ) ) );
15698 break;
15700 case 16: // vextsb2w, Vector Extend Sign Byte to Word
15701 DIP("vextsb2w v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15703 /* Iop_MullEven8Sx16 does a signed widening multiplication of byte to
15704 * two byte sign extended result. Then do a two byte to four byte sign
15705 * extended multiply. Note contents of upper three bytes in word are
15706 * "over written". So just take source and multiply by 1.
15708 assign( vT, binop( Iop_MullEven16Sx8,
15709 binop( Iop_64HLtoV128,
15710 mkU64( 0x0000000100000001 ),
15711 mkU64( 0x0000000100000001 ) ),
15712 binop( Iop_MullEven8Sx16,
15713 mkexpr( vB ),
15714 binop( Iop_64HLtoV128,
15715 mkU64( 0x0001000100010001 ),
15716 mkU64( 0x0001000100010001 ) ) ) ) );
15717 break;
15719 case 17: // vextsh2w, Vector Extend Sign Halfword to Word
15720 DIP("vextsh2w v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15722 /* Iop_MullEven16Sx8 does a signed widening multiply of four byte
15723 * 8 bytes. Note contents of upper two bytes in word are
15724 * "over written". So just take source and multiply by 1.
15726 assign( vT, binop( Iop_MullEven16Sx8,
15727 binop( Iop_64HLtoV128,
15728 mkU64( 0x0000000100000001 ),
15729 mkU64( 0x0000000100000001 ) ),
15730 mkexpr( vB ) ) );
15732 break;
15734 case 24: // vextsb2d, Vector Extend Sign Byte to Doubleword
15735 DIP("vextsb2d v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15737 /* Iop_MullEven8Sx16 does a signed widening multiplication of byte to
15738 * two byte sign extended result. Then do a two byte to four byte sign
15739 * extended multiply. Then do four byte to eight byte multiply.
15741 assign( vT, binop( Iop_MullEven32Sx4,
15742 binop( Iop_64HLtoV128,
15743 mkU64( 0x0000000000000001 ),
15744 mkU64( 0x0000000000000001 ) ),
15745 binop( Iop_MullEven16Sx8,
15746 binop( Iop_64HLtoV128,
15747 mkU64( 0x0000000100000001 ),
15748 mkU64( 0x0000000100000001 ) ),
15749 binop( Iop_MullEven8Sx16,
15750 binop( Iop_64HLtoV128,
15751 mkU64( 0x0001000100010001 ),
15752 mkU64( 0x0001000100010001 ) ),
15753 mkexpr( vB ) ) ) ) );
15754 break;
15756 case 25: // vextsh2d, Vector Extend Sign Halfword to Doubleword
15757 DIP("vextsh2d v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15759 assign( vT, binop( Iop_MullEven32Sx4,
15760 binop( Iop_64HLtoV128,
15761 mkU64( 0x0000000000000001 ),
15762 mkU64( 0x0000000000000001 ) ),
15763 binop( Iop_MullEven16Sx8,
15764 binop( Iop_64HLtoV128,
15765 mkU64( 0x0000000100000001 ),
15766 mkU64( 0x0000000100000001 ) ),
15767 mkexpr( vB ) ) ) );
15768 break;
15770 case 26: // vextsw2d, Vector Extend Sign Word to Doubleword
15771 DIP("vextsw2d v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15773 assign( vT, binop( Iop_MullEven32Sx4,
15774 binop( Iop_64HLtoV128,
15775 mkU64( 0x0000000000000001 ),
15776 mkU64( 0x0000000000000001 ) ),
15777 mkexpr( vB ) ) );
15778 break;
15780 case 28: // vctzb, Vector Count Trailing Zeros Byte
15782 DIP("vctzb v%d,v%d", rT_addr, vB_addr);
15784 /* This instruction is only available in the ISA 3.0 */
15785 if ( !mode64 || !allow_isa_3_0 ) {
15786 vex_printf("\n vctzb instruction not supported on non ISA 3.0 platform\n\n");
15787 return False;
15789 assign( vT, unop( Iop_Ctz8x16, mkexpr( vB ) ) );
15791 break;
15793 case 29: // vctzh, Vector Count Trailing Zeros Halfword
15795 DIP("vctzh v%d,v%d", rT_addr, vB_addr);
15797 /* This instruction is only available in the ISA 3.0 */
15798 if ( !mode64 || !allow_isa_3_0 ) {
15799 vex_printf("\n vctzh instruction not supported on non ISA 3.0 platform\n\n");
15800 return False;
15802 assign( vT, unop( Iop_Ctz16x8, mkexpr( vB ) ) );
15804 break;
15806 case 30: // vctzw, Vector Count Trailing Zeros Word
15808 DIP("vctzw v%d,v%d", rT_addr, vB_addr);
15810 /* This instruction is only available in the ISA 3.0 */
15811 if ( !mode64 || !allow_isa_3_0 ) {
15812 vex_printf("\n vctzw instruction not supported on non ISA 3.0 platform\n\n");
15813 return False;
15815 assign( vT, unop( Iop_Ctz32x4, mkexpr( vB ) ) );
15817 break;
15819 case 31: // vctzd, Vector Count Trailing Zeros Double word
15821 DIP("vctzd v%d,v%d", rT_addr, vB_addr);
15823 /* This instruction is only available in the ISA 3.0 */
15824 if ( !mode64 || !allow_isa_3_0 ) {
15825 vex_printf("\n vctzd instruction not supported on non ISA 3.0 platform\n\n");
15826 return False;
15828 assign( vT, unop( Iop_Ctz64x2, mkexpr( vB ) ) );
15830 break;
15832 default:
15833 vex_printf("dis_av_extend_sign(ppc)(Unsupported vector extend sign instruction)\n");
15834 return False;
15837 putVReg( rT_addr, mkexpr( vT ) );
15838 return True;
15842 Vector Rotate Instructions
15844 static Bool dis_av_rotate ( UInt theInstr )
15846 /* VX-Form */
15848 UChar opc1 = ifieldOPC( theInstr );
15849 UChar vT_addr = ifieldRegDS( theInstr );
15850 UChar vA_addr = ifieldRegA( theInstr );
15851 UChar vB_addr = ifieldRegB( theInstr );
15852 UInt opc2 = IFIELD( theInstr, 0, 11 );
15854 IRTemp vA = newTemp( Ity_V128 );
15855 IRTemp vB = newTemp( Ity_V128 );
15856 IRTemp src3 = newTemp( Ity_V128 );
15857 IRTemp vT = newTemp( Ity_V128 );
15858 IRTemp field_mask = newTemp( Ity_V128 );
15859 IRTemp mask128 = newTemp( Ity_V128 );
15860 IRTemp vA_word[4];
15861 IRTemp left_bits[4];
15862 IRTemp right_bits[4];
15863 IRTemp mb[4];
15864 IRTemp me[4];
15865 IRTemp shift[4];
15866 IRTemp mask[4];
15867 IRTemp tmp_mask[4];
15868 IRTemp invert_mask[4];
15869 IRTemp tmp128[4];
15870 UInt i;
15871 UInt num_words;
15872 UInt word_size;
15873 unsigned long long word_mask;
15875 if ( opc1 != 0x4 ) {
15876 vex_printf("dis_av_rotate(ppc)(instr)\n");
15877 return False;
15880 assign( vA, getVReg( vA_addr ) );
15881 assign( vB, getVReg( vB_addr ) );
15883 switch (opc2) {
15884 case 0x85: // vrlwmi, Vector Rotate Left Word then Mask Insert
15885 case 0x185: // vrlwnm, Vector Rotate Left Word then AND with Mask
15886 num_words = 4;
15887 word_size = 32;
15888 assign( field_mask, binop( Iop_64HLtoV128,
15889 mkU64( 0 ),
15890 mkU64( 0x1F ) ) );
15891 word_mask = 0xFFFFFFFF;
15892 break;
15894 case 0x0C5: // vrldmi, Vector Rotate Left Doubleword then Mask Insert
15895 case 0x1C5: // vrldnm, Vector Rotate Left Doubleword then AND with Mask
15896 num_words = 2;
15897 word_size = 64;
15898 assign( field_mask, binop( Iop_64HLtoV128,
15899 mkU64( 0 ),
15900 mkU64( 0x3F ) ) );
15901 word_mask = 0xFFFFFFFFFFFFFFFFULL;
15902 break;
15903 default:
15904 vex_printf("dis_av_rotate(ppc)(opc2)\n");
15905 return False;
15908 for( i = 0; i < num_words; i++ ) {
15909 left_bits[i] = newTemp( Ity_I8 );
15910 right_bits[i] = newTemp( Ity_I8 );
15911 shift[i] = newTemp( Ity_I8 );
15912 mb[i] = newTemp( Ity_I64 );
15913 me[i] = newTemp( Ity_I64 );
15914 tmp_mask[i] = newTemp( Ity_I64 );
15915 invert_mask[i] = newTemp( Ity_I64 );
15916 mask[i] = newTemp( Ity_V128 );
15917 tmp128[i] = newTemp( Ity_V128 );
15918 vA_word[i] = newTemp( Ity_V128 );
15920 assign( shift[i],
15921 unop( Iop_64to8,
15922 unop( Iop_V128to64,
15923 binop( Iop_AndV128,
15924 binop( Iop_ShrV128,
15925 mkexpr( vB ),
15926 mkU8( (num_words - 1 - i )
15927 * word_size ) ),
15928 mkexpr( field_mask ) ) ) ) );
15930 assign( mb[i], unop( Iop_V128to64,
15931 binop( Iop_AndV128,
15932 binop( Iop_ShrV128,
15933 mkexpr( vB ),
15934 mkU8( ( num_words - 1 - i )
15935 * word_size + 16 ) ),
15936 mkexpr( field_mask ) ) ) );
15938 assign( me[i], unop( Iop_V128to64,
15939 binop( Iop_AndV128,
15940 binop( Iop_ShrV128,
15941 mkexpr( vB ),
15942 mkU8( ( num_words - 1 - i )
15943 * word_size + 8 ) ),
15944 mkexpr( field_mask ) ) ) );
15946 /* If me < mb, we have to flip things around and invert the mask */
15947 assign( invert_mask[i],
15948 unop( Iop_1Sto64, binop( Iop_CmpLT64U,
15949 mkexpr( me[i] ), mkexpr( mb[i] ) ) ) );
15951 /* left_bits = 63 - mb. Tells us how many bits to the left
15952 * of mb to clear. Note for a word left_bits = 32+mb, for a double
15953 * word left_bits = mb
15955 assign( left_bits[i],
15956 unop( Iop_64to8,
15957 binop( Iop_Or64,
15958 binop( Iop_And64, // mb < me
15959 unop( Iop_Not64, mkexpr( invert_mask[i] ) ),
15960 binop( Iop_Add64,
15961 mkU64( 64 - word_size ),
15962 mkexpr( mb[i] ) ) ),
15963 binop( Iop_And64, // me < mb
15964 mkexpr( invert_mask[i] ),
15965 binop( Iop_Add64,
15966 mkU64( 64 + 1 - word_size ),
15967 mkexpr( me[i] ) ) ) ) ) );
15969 /* right_bits = 63 - me. Tells us how many bits to the right
15970 * of me to clear. Note for a word, left_bits = me+32, for a double
15971 * word left_bits = me
15973 assign( right_bits[i],
15974 unop( Iop_64to8,
15975 binop( Iop_Or64,
15976 binop( Iop_And64, // mb < me
15977 unop( Iop_Not64, mkexpr( invert_mask[i] ) ),
15978 binop( Iop_Sub64,
15979 mkU64( word_size - 1 ),
15980 mkexpr( me[i] ) ) ),
15981 binop( Iop_And64, // me < mb
15982 mkexpr( invert_mask[i] ),
15983 binop( Iop_Sub64,
15984 mkU64( word_size - 1 + 1),
15985 mkexpr( mb[i] ) ) ) ) ) );
15987 /* create mask for 32-bit word or 64-bit word */
15988 assign( tmp_mask[i],
15989 binop( Iop_Shl64,
15990 binop( Iop_Shr64,
15991 binop( Iop_Shr64,
15992 binop( Iop_Shl64,
15993 mkU64( 0xFFFFFFFFFFFFFFFF ),
15994 mkexpr( left_bits[i] ) ),
15995 mkexpr( left_bits[i] ) ),
15996 mkexpr( right_bits[i] ) ),
15997 mkexpr( right_bits[i] ) ) );
15999 assign( mask[i],
16000 binop( Iop_64HLtoV128,
16001 mkU64( 0 ),
16002 binop( Iop_Or64,
16003 binop( Iop_And64,
16004 unop( Iop_Not64, mkexpr( invert_mask[i] ) ),
16005 mkexpr( tmp_mask[i] ) ),
16006 binop( Iop_And64,
16007 mkexpr( invert_mask[i] ),
16008 /* Need to make sure mask is only the size
16009 desired word.*/
16010 binop( Iop_And64,
16011 mkU64( word_mask ),
16012 unop( Iop_Not64,
16013 mkexpr( tmp_mask[i] ) ) ) ))));
16015 /* Need to rotate vA using a left and right shift of vA OR'd together
16016 * then ANDed with the mask.
16018 assign( vA_word[i], binop( Iop_AndV128,
16019 mkexpr( vA ),
16020 binop( Iop_ShlV128,
16021 binop( Iop_64HLtoV128,
16022 mkU64( 0 ),
16023 mkU64( word_mask ) ),
16024 mkU8( ( num_words - 1 - i )
16025 * word_size ) ) ) );
16026 assign( tmp128[i],
16027 binop( Iop_AndV128,
16028 binop( Iop_ShlV128,
16029 mkexpr( mask[i] ),
16030 mkU8( ( num_words - 1 - i) * word_size ) ),
16031 binop( Iop_OrV128,
16032 binop( Iop_ShlV128,
16033 mkexpr( vA_word[i] ),
16034 mkexpr( shift[i] ) ),
16035 binop( Iop_ShrV128,
16036 mkexpr( vA_word[i] ),
16037 unop( Iop_32to8,
16038 binop(Iop_Sub32,
16039 mkU32( word_size ),
16040 unop( Iop_8Uto32,
16041 mkexpr( shift[i] ) ) )
16042 ) ) ) ) );
16045 switch (opc2) {
16046 case 0x85: // vrlwmi, Vector Rotate Left Word then Mask Insert
16047 DIP("vrlwmi %d,%d,v%d", vT_addr, vA_addr, vB_addr);
16049 assign( src3, getVReg( vT_addr ) );
16050 assign( mask128, unop( Iop_NotV128,
16051 mkOr4_V128_expr( binop( Iop_ShlV128,
16052 mkexpr( mask[0] ),
16053 mkU8( 96 ) ),
16054 binop( Iop_ShlV128,
16055 mkexpr( mask[1] ),
16056 mkU8( 64 ) ),
16057 binop( Iop_ShlV128,
16058 mkexpr( mask[2] ),
16059 mkU8( 32 ) ),
16060 mkexpr( mask[3] ) ) ) );
16061 assign( vT, binop( Iop_OrV128,
16062 binop( Iop_AndV128,
16063 mkexpr( src3 ),
16064 mkexpr( mask128 ) ),
16065 mkOr4_V128( tmp128[0], tmp128[1],
16066 tmp128[2], tmp128[3] ) ) );
16067 break;
16069 case 0xC5: // vrldmi, Vector Rotate Left Double word then Mask Insert
16070 DIP("vrldmi %d,%d,v%d", vT_addr, vA_addr, vB_addr);
16072 assign( src3, getVReg( vT_addr ) );
16073 assign( mask128, unop( Iop_NotV128,
16074 binop( Iop_OrV128,
16075 binop( Iop_ShlV128,
16076 mkexpr( mask[0] ),
16077 mkU8( 64 ) ),
16078 mkexpr( mask[1] ) ) ) );
16080 assign( vT, binop( Iop_OrV128,
16081 binop( Iop_AndV128,
16082 mkexpr( src3 ),
16083 mkexpr( mask128 ) ),
16084 binop( Iop_OrV128,
16085 mkexpr( tmp128[0] ),
16086 mkexpr( tmp128[1] ) ) ) );
16087 break;
16089 case 0x185: // vrlwnm, Vector Rotate Left Word then AND with Mask
16090 DIP("vrlwnm %d,%d,v%d", vT_addr, vA_addr, vB_addr);
16091 assign( vT, mkOr4_V128( tmp128[0], tmp128[1], tmp128[2], tmp128[3] ) );
16092 break;
16094 case 0x1C5: // vrldnm, Vector Rotate Left Doubleword then AND with Mask
16095 DIP("vrldnm %d,%d,v%d", vT_addr, vA_addr, vB_addr);
16096 assign( vT, binop( Iop_OrV128,
16097 mkexpr( tmp128[0] ),
16098 mkexpr( tmp128[1] ) ) );
16099 break;
16102 putVReg( vT_addr, mkexpr( vT ) );
16103 return True;
16107 AltiVec Vector Extract Element Instructions
16109 static Bool dis_av_extract_element ( UInt theInstr )
16111 /* VX-Form,
16112 * sorta destination and first source are GPR not vector registers
16115 UChar opc1 = ifieldOPC( theInstr );
16116 UChar rT_addr = ifieldRegDS( theInstr );
16117 UChar rA_addr = ifieldRegA( theInstr );
16118 UChar vB_addr = ifieldRegB( theInstr );
16119 UInt opc2 = IFIELD( theInstr, 0, 11 );
16121 IRTemp vB = newTemp( Ity_V128 );
16122 IRTemp rA = newTemp( Ity_I64 );
16123 IRTemp rT = newTemp( Ity_I64 );
16125 assign( vB, getVReg( vB_addr ) );
16126 assign( rA, getIReg( rA_addr ) );
16128 if ( opc1 != 0x4 ) {
16129 vex_printf("dis_av_extract_element(ppc)(instr)\n");
16130 return False;
16133 switch ( opc2 ) {
16134 case 0x60D: // vextublx, vector extract unsigned Byte Left-indexed
16135 DIP("vextublx %d,%d,v%d", rT_addr, rA_addr, vB_addr);
16137 assign( rT, extract_field_from_vector( vB,
16138 binop( Iop_Sub64,
16139 mkU64( 15 ),
16140 mkexpr( rA ) ),
16141 0xFF ) );
16143 break;
16145 case 0x64D: // vextuhlx, vector extract unsigned Halfword Left-indexed
16146 DIP("vextuhlx %d,%d,v%d", rT_addr, rA_addr, vB_addr);
16148 assign( rT, extract_field_from_vector( vB,
16149 binop( Iop_Sub64,
16150 mkU64( 14 ),
16151 mkexpr( rA ) ),
16152 0xFFFF ) );
16153 break;
16155 case 0x68D: // vextuwlx, vector extract unsigned Word Left-indexed
16156 DIP("vextuwlx %d,%d,v%d", rT_addr, rA_addr, vB_addr);
16158 assign( rT, extract_field_from_vector( vB,
16159 binop( Iop_Sub64,
16160 mkU64( 12 ),
16161 mkexpr( rA ) ),
16162 0xFFFFFFFF ) );
16163 break;
16165 case 0x70D: // vextubrx, vector extract unsigned Byte Right-indexed
16166 DIP("vextubrx %d,%d,v%d", rT_addr, rA_addr, vB_addr);
16168 assign( rT, extract_field_from_vector( vB, mkexpr( rA ), 0xFF ) );
16169 break;
16171 case 0x74D: // vextuhrx, vector extract unsigned Halfword Right-indexed
16172 DIP("vextuhrx %d,%d,v%d", rT_addr, rA_addr, vB_addr);
16174 assign( rT, extract_field_from_vector( vB, mkexpr( rA ), 0xFFFF ) );
16175 break;
16177 case 0x78D: // vextuwrx, vector extract unsigned Word Right-indexed
16178 DIP("vextuwrx %d,%d,v%d", rT_addr, rA_addr, vB_addr);
16180 assign( rT, extract_field_from_vector( vB, mkexpr( rA ), 0xFFFFFFFF ) );
16181 break;
16183 default:
16184 vex_printf("dis_av_extract_element(ppc)(opc2)\n");
16185 return False;
16187 putIReg( rT_addr, mkexpr( rT ) );
16188 return True;
16192 * VSX scalar and vector convert instructions
16194 static Bool
16195 dis_vx_conv ( UInt theInstr, UInt opc2 )
16197 /* XX2-Form */
16198 UChar opc1 = ifieldOPC( theInstr );
16199 UChar XT = ifieldRegXT( theInstr );
16200 UChar XB = ifieldRegXB( theInstr );
16201 IRTemp xB, xB2;
16202 IRTemp b3, b2, b1, b0;
16203 xB = xB2 = IRTemp_INVALID;
16205 if (opc1 != 0x3C) {
16206 vex_printf( "dis_vx_conv(ppc)(instr)\n" );
16207 return False;
16210 /* Create and assign temps only as needed for the given instruction. */
16211 switch (opc2) {
16212 // scalar double-precision floating point argument
16213 case 0x2B0: case 0x0b0: case 0x290: case 0x212: case 0x216: case 0x090:
16214 xB = newTemp(Ity_F64);
16215 assign( xB,
16216 unop( Iop_ReinterpI64asF64,
16217 unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
16218 break;
16219 // vector double-precision floating point arguments
16220 case 0x1b0: case 0x312: case 0x390: case 0x190: case 0x3B0:
16222 xB = newTemp(Ity_F64);
16223 xB2 = newTemp(Ity_F64);
16224 assign( xB,
16225 unop( Iop_ReinterpI64asF64,
16226 unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
16227 assign( xB2,
16228 unop( Iop_ReinterpI64asF64,
16229 unop( Iop_V128to64, getVSReg( XB ) ) ) );
16230 break;
16231 // vector single precision or [un]signed integer word arguments
16232 case 0x130: case 0x392: case 0x330: case 0x310: case 0x110:
16233 case 0x1f0: case 0x1d0:
16234 b3 = b2 = b1 = b0 = IRTemp_INVALID;
16235 breakV128to4x32(getVSReg(XB), &b3, &b2, &b1, &b0);
16236 break;
16237 // vector [un]signed integer doubleword argument
16238 case 0x3f0: case 0x370: case 0x3d0: case 0x350:
16239 xB = newTemp(Ity_I64);
16240 assign( xB, unop( Iop_V128HIto64, getVSReg( XB ) ) );
16241 xB2 = newTemp(Ity_I64);
16242 assign( xB2, unop( Iop_V128to64, getVSReg( XB ) ) );
16243 break;
16244 // scalar [un]signed integer doubleword argument
16245 case 0x250: case 0x270: case 0x2D0: case 0x2F0:
16246 xB = newTemp(Ity_I64);
16247 assign( xB, unop( Iop_V128HIto64, getVSReg( XB ) ) );
16248 break;
16249 // scalar single precision argument
16250 case 0x292: // xscvspdp
16251 xB = newTemp(Ity_I32);
16253 assign( xB, handle_SNaN_to_QNaN_32(unop( Iop_64HIto32,
16254 unop( Iop_V128HIto64,
16255 getVSReg( XB ) ) ) ) );
16256 break;
16257 case 0x296: // xscvspdpn (non signaling version of xscvpdp)
16258 xB = newTemp(Ity_I32);
16259 assign( xB,
16260 unop( Iop_64HIto32, unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
16261 break;
16263 /* Certain instructions have their complete implementation in the main switch statement
16264 * that follows this one; thus we have a "do nothing" case for those instructions here.
16266 case 0x170: case 0x150:
16267 break; // do nothing
16269 default:
16270 vex_printf( "dis_vx_conv(ppc)(opc2)\n" );
16271 return False;
16275 switch (opc2) {
16276 case 0x2B0:
16277 // xscvdpsxds (VSX Scalar truncate Double-Precision to integer and Convert
16278 // to Signed Integer Doubleword format with Saturate)
16279 DIP("xscvdpsxds v%u,v%u\n", XT, XB);
16280 putVSReg( XT,
16281 binop( Iop_64HLtoV128, binop( Iop_F64toI64S,
16282 mkU32( Irrm_ZERO ),
16283 mkexpr( xB ) ), mkU64( 0 ) ) );
16284 break;
16285 case 0x0b0: // xscvdpsxws (VSX Scalar truncate Double-Precision to integer and
16286 // Convert to Signed Integer Word format with Saturate)
16287 DIP("xscvdpsxws v%u,v%u\n", XT, XB);
16288 putVSReg( XT,
16289 binop( Iop_64HLtoV128,
16290 unop( Iop_32Sto64,
16291 binop( Iop_F64toI32S,
16292 mkU32( Irrm_ZERO ),
16293 mkexpr( xB ) ) ),
16294 mkU64( 0ULL ) ) );
16295 break;
16296 case 0x290: // xscvdpuxds (VSX Scalar truncate Double-Precision integer and Convert
16297 // to Unsigned Integer Doubleword format with Saturate)
16298 DIP("xscvdpuxds v%u,v%u\n", XT, XB);
16299 putVSReg( XT,
16300 binop( Iop_64HLtoV128,
16301 binop( Iop_F64toI64U,
16302 mkU32( Irrm_ZERO ),
16303 mkexpr( xB ) ),
16304 mkU64( 0ULL ) ) );
16305 break;
16306 case 0x270:
16307 // xscvsxdsp (VSX Scalar Convert and round Signed Integer Doubleword
16308 // to Single-Precision format)
16309 DIP("xscvsxdsp v%u,v%u\n", XT, XB);
16310 putVSReg( XT,
16311 binop( Iop_64HLtoV128,
16312 unop( Iop_ReinterpF64asI64,
16313 binop( Iop_RoundF64toF32,
16314 get_IR_roundingmode(),
16315 binop( Iop_I64StoF64,
16316 get_IR_roundingmode(),
16317 mkexpr( xB ) ) ) ),
16318 mkU64( 0 ) ) );
16319 break;
16320 case 0x2F0:
16321 // xscvsxddp (VSX Scalar Convert and round Signed Integer Doubleword to
16322 // Double-Precision format)
16323 DIP("xscvsxddp v%u,v%u\n", XT, XB);
16324 putVSReg( XT,
16325 binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
16326 binop( Iop_I64StoF64, get_IR_roundingmode(),
16327 mkexpr( xB ) ) ),
16328 mkU64( 0 ) ) );
16329 break;
16330 case 0x250:
16331 // xscvuxdsp (VSX Scalar Convert and round Unsigned Integer
16332 // Doubleword to Singel-Precision format)
16333 DIP("xscvuxdsp v%u,v%u\n", XT, XB);
16334 putVSReg( XT,
16335 binop( Iop_64HLtoV128,
16336 unop( Iop_ReinterpF64asI64,
16337 binop( Iop_RoundF64toF32,
16338 get_IR_roundingmode(),
16339 binop( Iop_I64UtoF64,
16340 get_IR_roundingmode(),
16341 mkexpr( xB ) ) ) ),
16342 mkU64( 0 ) ) );
16343 break;
16344 case 0x2D0:
16345 // xscvuxddp (VSX Scalar Convert and round Unsigned Integer Doubleword to
16346 // Double-Precision format)
16347 DIP("xscvuxddp v%u,v%u\n", XT, XB);
16348 putVSReg( XT,
16349 binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
16350 binop( Iop_I64UtoF64, get_IR_roundingmode(),
16351 mkexpr( xB ) ) ),
16352 mkU64( 0 ) ) );
16353 break;
16354 case 0x1b0: // xvcvdpsxws (VSX Vector truncate Double-Precision to integer and Convert
16355 // to Signed Integer Word format with Saturate)
16356 case 0x190: // xvcvdpuxws (VSX Vector truncate Double-Precision to integer and
16357 // Convert to Unsigned Integer Word format with Saturate)
16359 IRTemp value_f64[2];
16360 IRTemp Result_32[2];
16361 IRTemp Result_32_tmp[2];
16362 IRTemp nan_mask[2];
16363 IRTemp underflow_mask[2];
16364 IRTemp overflow_mask[2];
16365 IRTemp error_mask[2];
16366 IRTemp error_value[2];
16367 IRTemp tmp_64[2];
16369 Int i;
16370 Int underflow_value;
16371 Int overflow_value;
16372 IRExpr* rmZero = mkU32(Irrm_ZERO);
16374 value_f64[0] = newTemp(Ity_F64);
16375 assign( value_f64[0], mkexpr( xB ) );
16377 value_f64[1] = newTemp(Ity_F64);
16378 assign( value_f64[1], mkexpr( xB2 ) );
16380 for ( i = 0; i < 2; i++) {
16381 Result_32[i] = newTemp(Ity_I32);
16382 Result_32_tmp[i] = newTemp(Ity_I32);
16383 nan_mask[i] = newTemp(Ity_I32);
16384 underflow_mask[i] = newTemp(Ity_I32);
16385 overflow_mask[i] = newTemp(Ity_I32);
16386 error_mask[i] = newTemp(Ity_I32);
16387 error_value[i] = newTemp(Ity_I32);
16388 tmp_64[i] = newTemp(Ity_I64);
16390 if ( opc2 == 0x1b0 ) { // xvcvdpsxws
16391 assign(Result_32_tmp[i], binop(Iop_F64toI32S,
16392 rmZero, mkexpr( value_f64[i] ) ) );
16394 /* result of Iop_CmpF64 is 0x01 if A < -2^31. */
16395 assign( underflow_mask[i],
16396 unop( Iop_1Sto32,
16397 unop( Iop_32to1,
16398 binop( Iop_CmpF64,
16399 mkexpr( value_f64[i] ),
16400 unop( Iop_ReinterpI64asF64,
16401 mkU64( 0xC1E0000000000000 ))))));
16402 overflow_value = 0x7FFFFFFF;
16403 underflow_value = 0x80000000;
16405 } else { // xvcvdpuxws
16406 assign( Result_32_tmp[i],
16407 binop( Iop_F64toI32U,
16408 mkU32( Irrm_ZERO ),
16409 mkexpr( value_f64[i] ) ) );
16411 /* result of Iop_CmpF64 is 0x01 if A < 0. */
16412 assign( underflow_mask[i],
16413 unop( Iop_1Sto32,
16414 unop( Iop_32to1,
16415 binop( Iop_CmpF64,
16416 mkexpr( value_f64[i] ),
16417 unop( Iop_ReinterpI64asF64,
16418 mkU64( 0x0 ) ) ) ) ) );
16419 overflow_value = 0xFFFFFFFF;
16420 underflow_value = 0;
16423 /* Check if input is NaN, output is 0x80000000.
16424 if input < -2^31, output is 0x80000000.
16425 if input > 2^31 - 1, output is 0x7FFFFFFF */
16426 assign( tmp_64[i], unop (Iop_ReinterpF64asI64,
16427 mkexpr( value_f64[i] ) ) );
16429 assign( nan_mask[i], unop( Iop_1Sto32,
16430 is_NaN( Ity_I64, tmp_64[i] ) ) );
16432 /* result of Iop_CmpF64 is 0x00 if A > 2^31 - 1. */
16433 assign( overflow_mask[i],
16434 unop( Iop_1Sto32,
16435 binop( Iop_CmpEQ32,
16436 mkU32( 0 ),
16437 binop( Iop_CmpF64,
16438 mkexpr( value_f64[i] ),
16439 unop( Iop_ReinterpI64asF64,
16440 mkU64( 0x41DFFFFFFFC00000 ))))));
16442 assign( error_mask[i], binop( Iop_Or32, mkexpr( overflow_mask[i] ),
16443 binop( Iop_Or32,
16444 mkexpr( underflow_mask[i] ),
16445 mkexpr( nan_mask[i] ) ) ) );
16447 if ( opc2 == 0x1b0 ) { // xvcvdpsxws
16448 /* NaN takes precedence over underflow/overflow for vxcvdpsxws */
16449 assign( error_value[i],
16450 binop( Iop_Or32,
16451 binop( Iop_And32,
16452 unop( Iop_Not32, mkexpr( nan_mask[i] ) ),
16453 binop( Iop_Or32,
16454 binop( Iop_And32,
16455 mkexpr( overflow_mask[i] ),
16456 mkU32( overflow_value ) ),
16457 binop( Iop_And32,
16458 mkexpr( underflow_mask[i] ),
16459 mkU32( underflow_value ) ) ) ),
16460 binop( Iop_And32,
16461 mkexpr( nan_mask[i] ),
16462 mkU32( 0x80000000 ) ) ) );
16463 } else {
16464 /* Less then zeo takes precedence over NaN/overflow
16465 for vxcvdpuxws in the hardware. Matching the HW here
16466 but it does not appear to match ISA. */
16467 assign( error_value[i],
16468 binop( Iop_Or32,
16469 binop( Iop_And32,
16470 unop( Iop_Not32,
16471 mkexpr( underflow_mask[i] ) ),
16472 binop( Iop_Or32,
16473 binop( Iop_And32,
16474 mkexpr( overflow_mask[i] ),
16475 mkU32( overflow_value ) ),
16476 binop( Iop_And32,
16477 mkexpr( nan_mask[i] ),
16478 mkU32( 0x80000000 ) ) ) ),
16479 binop( Iop_And32,
16480 mkexpr( underflow_mask[i] ),
16481 mkU32( underflow_value ) ) ) );
16484 assign( Result_32[i], binop( Iop_Or32,
16485 binop( Iop_And32,
16486 mkexpr( Result_32_tmp[i] ),
16487 unop( Iop_Not32,
16488 mkexpr( error_mask[i] ) ) ),
16489 binop( Iop_And32,
16490 mkexpr( error_value[i] ),
16491 mkexpr( error_mask[i] ) ) ) );
16494 if ( opc2 == 0x1b0 ) {
16495 DIP("xvcvdpsxws v%u,v%u\n", XT, XB);
16497 } else {
16498 DIP("xvcvdpuxws v%u,v%u", XT, XB);
16501 /* Result is put in the hi and low 32-bits of the double word result. */
16502 putVSReg( XT,
16503 binop( Iop_64HLtoV128,
16504 binop( Iop_32HLto64,
16505 mkexpr( Result_32[0] ),
16506 mkexpr( Result_32[0] ) ),
16507 binop( Iop_32HLto64,
16508 mkexpr( Result_32[1] ),
16509 mkexpr( Result_32[1] ) ) ) );
16510 break;
16512 case 0x130: case 0x110: // xvcvspsxws, xvcvspuxws
16513 // (VSX Vector truncate Single-Precision to integer and
16514 // Convert to [Un]signed Integer Word format with Saturate)
16516 IRExpr * b0_result, * b1_result, * b2_result, * b3_result;
16517 IRTemp tempResult = newTemp(Ity_V128);
16518 IRTemp res0 = newTemp(Ity_I32);
16519 IRTemp res1 = newTemp(Ity_I32);
16520 IRTemp res2 = newTemp(Ity_I32);
16521 IRTemp res3 = newTemp(Ity_I32);
16522 IRTemp hi64 = newTemp(Ity_I64);
16523 IRTemp lo64 = newTemp(Ity_I64);
16524 Bool un_signed = (opc2 == 0x110);
16525 IROp op = un_signed ? Iop_QF32toI32Ux4_RZ : Iop_QF32toI32Sx4_RZ;
16527 DIP("xvcvsp%sxws v%u,v%u\n", un_signed ? "u" : "s", XT, XB);
16528 /* The xvcvsp{s|u}xws instruction is similar to vct{s|u}xs, except if src is a NaN,
16529 * then result is set to 0x80000000. */
16530 assign(tempResult, unop(op, getVSReg(XB)));
16531 assign( hi64, unop(Iop_V128HIto64, mkexpr(tempResult)) );
16532 assign( lo64, unop(Iop_V128to64, mkexpr(tempResult)) );
16533 assign( res3, unop(Iop_64HIto32, mkexpr(hi64)) );
16534 assign( res2, unop(Iop_64to32, mkexpr(hi64)) );
16535 assign( res1, unop(Iop_64HIto32, mkexpr(lo64)) );
16536 assign( res0, unop(Iop_64to32, mkexpr(lo64)) );
16538 b3_result = IRExpr_ITE(is_NaN(Ity_I32, b3),
16539 // then: result is 0x{8|0}80000000
16540 mkU32(un_signed ? 0x00000000 : 0x80000000),
16541 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
16542 mkexpr(res3));
16543 b2_result = IRExpr_ITE(is_NaN(Ity_I32, b2),
16544 // then: result is 0x{8|0}80000000
16545 mkU32(un_signed ? 0x00000000 : 0x80000000),
16546 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
16547 mkexpr(res2));
16548 b1_result = IRExpr_ITE(is_NaN(Ity_I32, b1),
16549 // then: result is 0x{8|0}80000000
16550 mkU32(un_signed ? 0x00000000 : 0x80000000),
16551 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
16552 mkexpr(res1));
16553 b0_result = IRExpr_ITE(is_NaN(Ity_I32, b0),
16554 // then: result is 0x{8|0}80000000
16555 mkU32(un_signed ? 0x00000000 : 0x80000000),
16556 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
16557 mkexpr(res0));
16559 putVSReg( XT,
16560 binop( Iop_64HLtoV128,
16561 binop( Iop_32HLto64, b3_result, b2_result ),
16562 binop( Iop_32HLto64, b1_result, b0_result ) ) );
16563 break;
16565 case 0x212: // xscvdpsp (VSX Scalar round Double-Precision to single-precision and
16566 // Convert to Single-Precision format
16567 // Apr 2019 update - write the result to both halves of the
16568 // target VSR. (see bug 401827,401828).
16569 DIP("xscvdpsp v%u,v%u\n", XT, XB);
16570 IRTemp ResultI32a = newTemp(Ity_I32);
16571 assign(ResultI32a, unop( Iop_ReinterpF32asI32,
16572 unop( Iop_TruncF64asF32,
16573 binop( Iop_RoundF64toF32,
16574 get_IR_roundingmode(),
16575 mkexpr( xB ) ) ) ) );
16576 putVSReg( XT,
16577 binop( Iop_64HLtoV128,
16578 binop( Iop_32HLto64,
16579 mkexpr(ResultI32a ),
16580 mkexpr(ResultI32a ) ),
16581 mkU64( 0ULL ) ) );
16582 break;
16583 case 0x216: /* xscvdpspn (VSX Scalar convert scalar Single-Precision to
16584 vector Single-Precision non-signalling */
16585 // Apr 2019 update - write the result to both halves of the
16586 // target VSR. (see bug 401827,401828).
16587 DIP("xscvdpspn v%u,v%u\n", XT, XB);
16588 IRTemp ResultI32b = newTemp(Ity_I32);
16589 assign(ResultI32b, unop( Iop_ReinterpF32asI32,
16590 unop( Iop_TruncF64asF32,
16591 mkexpr( xB ) ) ) );
16592 putVSReg( XT,
16593 binop( Iop_64HLtoV128,
16594 binop( Iop_32HLto64,
16595 mkexpr(ResultI32b ),
16596 mkexpr(ResultI32b ) ),
16597 mkU64( 0ULL ) ) );
16598 break;
16599 case 0x090: // xscvdpuxws (VSX Scalar truncate Double-Precision to integer
16600 // and Convert to Unsigned Integer Word format with Saturate)
16601 DIP("xscvdpuxws v%u,v%u\n", XT, XB);
16602 putVSReg( XT,
16603 binop( Iop_64HLtoV128,
16604 binop( Iop_32HLto64,
16605 mkU32( 0 ),
16606 binop( Iop_F64toI32U,
16607 mkU32( Irrm_ZERO ),
16608 mkexpr( xB ) ) ),
16609 mkU64( 0ULL ) ) );
16610 break;
16611 case 0x292: // xscvspdp (VSX Scalar Convert Single-Precision to Double-Precision format, signaling)
16612 DIP("xscvspdp v%u,v%u\n", XT, XB);
16613 putVSReg( XT,
16614 binop( Iop_64HLtoV128,
16615 unop( Iop_ReinterpF64asI64,
16616 unop( Iop_F32toF64,
16617 unop( Iop_ReinterpI32asF32, mkexpr( xB ) ) ) ),
16618 mkU64( 0ULL ) ) );
16619 break;
16620 case 0x296: // xscvspdpn (VSX Scalar Convert Single-Precision to Double-Precision format Non signaling)
16621 DIP("xscvspdpn v%u,v%u\n", XT, XB);
16622 putVSReg( XT,
16623 binop( Iop_64HLtoV128,
16624 unop( Iop_ReinterpF64asI64,
16625 unop( Iop_F32toF64,
16626 unop( Iop_ReinterpI32asF32, mkexpr( xB ) ) ) ),
16627 mkU64( 0ULL ) ) );
16628 break;
16629 case 0x312: // xvcvdpsp (VSX Vector round Double-Precision to single-precision
16630 // and Convert to Single-Precision format)
16631 DIP("xvcvdpsp v%u,v%u\n", XT, XB);
16633 /* Note, the 32-bit result is put into the upper and lower bits of the
16634 doubleword result. */
16635 putVSReg( XT,
16636 binop( Iop_64HLtoV128,
16637 binop( Iop_32HLto64,
16638 unop( Iop_ReinterpF32asI32,
16639 unop( Iop_TruncF64asF32,
16640 binop( Iop_RoundF64toF32,
16641 get_IR_roundingmode(),
16642 mkexpr( xB ) ) ) ),
16643 unop( Iop_ReinterpF32asI32,
16644 unop( Iop_TruncF64asF32,
16645 binop( Iop_RoundF64toF32,
16646 get_IR_roundingmode(),
16647 mkexpr( xB ) ) ) ) ),
16648 binop( Iop_32HLto64,
16649 unop( Iop_ReinterpF32asI32,
16650 unop( Iop_TruncF64asF32,
16651 binop( Iop_RoundF64toF32,
16652 get_IR_roundingmode(),
16653 mkexpr( xB2 ) ) ) ),
16654 unop( Iop_ReinterpF32asI32,
16655 unop( Iop_TruncF64asF32,
16656 binop( Iop_RoundF64toF32,
16657 get_IR_roundingmode(),
16658 mkexpr( xB2 ) ) ) ) ) ) );
16659 break;
16660 case 0x390: // xvcvdpuxds (VSX Vector truncate Double-Precision to integer
16661 // and Convert to Unsigned Integer Doubleword format
16662 // with Saturate)
16663 DIP("xvcvdpuxds v%u,v%u\n", XT, XB);
16664 putVSReg( XT,
16665 binop( Iop_64HLtoV128,
16666 binop( Iop_F64toI64U, mkU32( Irrm_ZERO ), mkexpr( xB ) ),
16667 binop( Iop_F64toI64U, mkU32( Irrm_ZERO ), mkexpr( xB2 ) ) ) );
16668 break;
16669 case 0x392: // xvcvspdp (VSX Vector Convert Single-Precision to Double-Precision format)
16670 DIP("xvcvspdp v%u,v%u\n", XT, XB);
16671 putVSReg( XT,
16672 binop( Iop_64HLtoV128,
16673 unop( Iop_ReinterpF64asI64,
16674 unop( Iop_F32toF64,
16675 unop( Iop_ReinterpI32asF32,
16676 handle_SNaN_to_QNaN_32( mkexpr( b3 ) ) ) ) ),
16677 unop( Iop_ReinterpF64asI64,
16678 unop( Iop_F32toF64,
16679 unop( Iop_ReinterpI32asF32,
16680 handle_SNaN_to_QNaN_32( mkexpr( b1 ) ) ) ) ) ) );
16681 break;
16682 case 0x330: // xvcvspsxds (VSX Vector truncate Single-Precision to integer and
16683 // Convert to Signed Integer Doubleword format with Saturate)
16684 DIP("xvcvspsxds v%u,v%u\n", XT, XB);
16685 putVSReg( XT,
16686 binop( Iop_64HLtoV128,
16687 binop( Iop_F64toI64S,
16688 mkU32( Irrm_ZERO ),
16689 unop( Iop_F32toF64,
16690 unop( Iop_ReinterpI32asF32, mkexpr( b3 ) ) ) ),
16691 binop( Iop_F64toI64S,
16692 mkU32( Irrm_ZERO ),
16693 unop( Iop_F32toF64,
16694 unop( Iop_ReinterpI32asF32, mkexpr( b1 ) ) ) ) ) );
16695 break;
16696 case 0x310: // xvcvspuxds (VSX Vector truncate Single-Precision to integer and
16697 // Convert to Unsigned Integer Doubleword format with Saturate)
16698 DIP("xvcvspuxds v%u,v%u\n", XT, XB);
16699 putVSReg( XT,
16700 binop( Iop_64HLtoV128,
16701 binop( Iop_F64toI64U,
16702 mkU32( Irrm_ZERO ),
16703 unop( Iop_F32toF64,
16704 unop( Iop_ReinterpI32asF32, mkexpr( b3 ) ) ) ),
16705 binop( Iop_F64toI64U,
16706 mkU32( Irrm_ZERO ),
16707 unop( Iop_F32toF64,
16708 unop( Iop_ReinterpI32asF32, mkexpr( b1 ) ) ) ) ) );
16709 break;
16710 case 0x3B0: // xvcvdpsxds (VSX Vector truncate Double-Precision to integer and
16711 // Convert to Signed Integer Doubleword format with Saturate)
16712 DIP("xvcvdpsxds v%u,v%u\n", XT, XB);
16713 putVSReg( XT,
16714 binop( Iop_64HLtoV128,
16715 binop( Iop_F64toI64S, mkU32( Irrm_ZERO ), mkexpr( xB ) ),
16716 binop( Iop_F64toI64S, mkU32( Irrm_ZERO ), mkexpr( xB2 ) ) ) );
16717 break;
16718 case 0x3f0: // xvcvsxddp (VSX Vector Convert and round Signed Integer Doubleword
16719 // to Double-Precision format)
16720 DIP("xvcvsxddp v%u,v%u\n", XT, XB);
16721 putVSReg( XT,
16722 binop( Iop_64HLtoV128,
16723 unop( Iop_ReinterpF64asI64,
16724 binop( Iop_I64StoF64,
16725 get_IR_roundingmode(),
16726 mkexpr( xB ) ) ),
16727 unop( Iop_ReinterpF64asI64,
16728 binop( Iop_I64StoF64,
16729 get_IR_roundingmode(),
16730 mkexpr( xB2 ) ) ) ) );
16731 break;
16732 case 0x3d0: // xvcvuxddp (VSX Vector Convert and round Unsigned Integer Doubleword
16733 // to Double-Precision format)
16734 DIP("xvcvuxddp v%u,v%u\n", XT, XB);
16735 putVSReg( XT,
16736 binop( Iop_64HLtoV128,
16737 unop( Iop_ReinterpF64asI64,
16738 binop( Iop_I64UtoF64,
16739 get_IR_roundingmode(),
16740 mkexpr( xB ) ) ),
16741 unop( Iop_ReinterpF64asI64,
16742 binop( Iop_I64UtoF64,
16743 get_IR_roundingmode(),
16744 mkexpr( xB2 ) ) ) ) );
16746 break;
16747 case 0x370: // xvcvsxdsp (VSX Vector Convert and round Signed Integer Doubleword
16748 // to Single-Precision format)
16750 IRTemp result32hi = newTemp(Ity_I32);
16751 IRTemp result32lo = newTemp(Ity_I32);
16753 DIP("xvcvsxdsp v%u,v%u\n", XT, XB);
16754 assign( result32hi,
16755 unop( Iop_ReinterpF32asI32,
16756 unop( Iop_TruncF64asF32,
16757 binop( Iop_RoundF64toF32,
16758 get_IR_roundingmode(),
16759 binop( Iop_I64StoF64,
16760 get_IR_roundingmode(),
16761 mkexpr( xB ) ) ) ) ) );
16762 assign( result32lo,
16763 unop( Iop_ReinterpF32asI32,
16764 unop( Iop_TruncF64asF32,
16765 binop( Iop_RoundF64toF32,
16766 get_IR_roundingmode(),
16767 binop( Iop_I64StoF64,
16768 get_IR_roundingmode(),
16769 mkexpr( xB2 ) ) ) ) ) );
16771 putVSReg( XT,
16772 binop( Iop_64HLtoV128,
16773 binop( Iop_32HLto64,
16774 mkexpr( result32hi ),
16775 mkexpr( result32hi ) ),
16776 binop( Iop_32HLto64,
16777 mkexpr( result32lo ),
16778 mkexpr( result32lo ) ) ) );
16780 break;
16781 case 0x350: // xvcvuxdsp (VSX Vector Convert and round Unsigned Integer Doubleword
16782 // to Single-Precision format)
16784 IRTemp result32hi = newTemp(Ity_I32);
16785 IRTemp result32lo = newTemp(Ity_I32);
16787 DIP("xvcvuxdsp v%u,v%u\n", XT, XB);
16788 assign( result32hi,
16789 unop( Iop_ReinterpF32asI32,
16790 unop( Iop_TruncF64asF32,
16791 binop( Iop_RoundF64toF32,
16792 get_IR_roundingmode(),
16793 binop( Iop_I64UtoF64,
16794 get_IR_roundingmode(),
16795 mkexpr( xB ) ) ) ) ) );
16796 assign( result32lo,
16797 unop( Iop_ReinterpF32asI32,
16798 unop( Iop_TruncF64asF32,
16799 binop( Iop_RoundF64toF32,
16800 get_IR_roundingmode(),
16801 binop( Iop_I64UtoF64,
16802 get_IR_roundingmode(),
16803 mkexpr( xB2 ) ) ) ) ) );
16804 putVSReg( XT,
16805 binop( Iop_64HLtoV128,
16806 binop( Iop_32HLto64,
16807 mkexpr( result32hi ),
16808 mkexpr( result32hi ) ),
16809 binop( Iop_32HLto64,
16810 mkexpr( result32lo ),
16811 mkexpr( result32lo ) ) ) );
16813 break;
16815 case 0x1f0: // xvcvsxwdp (VSX Vector Convert Signed Integer Word to Double-Precision format)
16816 DIP("xvcvsxwdp v%u,v%u\n", XT, XB);
16817 putVSReg( XT,
16818 binop( Iop_64HLtoV128,
16819 unop( Iop_ReinterpF64asI64,
16820 binop( Iop_I64StoF64, get_IR_roundingmode(),
16821 unop( Iop_32Sto64, mkexpr( b3 ) ) ) ),
16822 unop( Iop_ReinterpF64asI64,
16823 binop( Iop_I64StoF64, get_IR_roundingmode(),
16824 unop( Iop_32Sto64, mkexpr( b1 ) ) ) ) ) );
16825 break;
16826 case 0x1d0: // xvcvuxwdp (VSX Vector Convert Unsigned Integer Word to Double-Precision format)
16827 DIP("xvcvuxwdp v%u,v%u\n", XT, XB);
16828 putVSReg( XT,
16829 binop( Iop_64HLtoV128,
16830 unop( Iop_ReinterpF64asI64,
16831 binop( Iop_I64UtoF64, get_IR_roundingmode(),
16832 unop( Iop_32Uto64, mkexpr( b3 ) ) ) ),
16833 unop( Iop_ReinterpF64asI64,
16834 binop( Iop_I64UtoF64, get_IR_roundingmode(),
16835 unop( Iop_32Uto64, mkexpr( b1 ) ) ) ) ) );
16836 break;
16837 case 0x170: // xvcvsxwsp (VSX Vector Convert Signed Integer Word to Single-Precision format)
16838 DIP("xvcvsxwsp v%u,v%u\n", XT, XB);
16839 putVSReg( XT, unop( Iop_I32StoF32x4_DEP, getVSReg( XB ) ) );
16840 break;
16841 case 0x150: // xvcvuxwsp (VSX Vector Convert Unsigned Integer Word to Single-Precision format)
16842 DIP("xvcvuxwsp v%u,v%u\n", XT, XB);
16843 putVSReg( XT, unop( Iop_I32UtoF32x4_DEP, getVSReg( XB ) ) );
16844 break;
16846 default:
16847 vex_printf( "dis_vx_conv(ppc)(opc2)\n" );
16848 return False;
16850 return True;
16854 * VSX vector Double Precision Floating Point Arithmetic Instructions
16856 static Bool
16857 dis_vxv_dp_arith ( UInt theInstr, UInt opc2 )
16859 /* XX3-Form */
16860 UChar opc1 = ifieldOPC( theInstr );
16861 UChar XT = ifieldRegXT( theInstr );
16862 UChar XA = ifieldRegXA( theInstr );
16863 UChar XB = ifieldRegXB( theInstr );
16864 IRExpr* rm = get_IR_roundingmode();
16865 IRTemp frA = newTemp(Ity_F64);
16866 IRTemp frB = newTemp(Ity_F64);
16867 IRTemp frA2 = newTemp(Ity_F64);
16868 IRTemp frB2 = newTemp(Ity_F64);
16870 if (opc1 != 0x3C) {
16871 vex_printf( "dis_vxv_dp_arith(ppc)(instr)\n" );
16872 return False;
16875 assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
16876 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
16877 assign(frA2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg( XA ))));
16878 assign(frB2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg( XB ))));
16880 switch (opc2) {
16881 case 0x1E0: // xvdivdp (VSX Vector Divide Double-Precision)
16882 case 0x1C0: // xvmuldp (VSX Vector Multiply Double-Precision)
16883 case 0x180: // xvadddp (VSX Vector Add Double-Precision)
16884 case 0x1A0: // xvsubdp (VSX Vector Subtract Double-Precision)
16886 IROp mOp;
16887 const HChar * oper_name;
16888 switch (opc2) {
16889 case 0x1E0:
16890 mOp = Iop_DivF64;
16891 oper_name = "div";
16892 break;
16893 case 0x1C0:
16894 mOp = Iop_MulF64;
16895 oper_name = "mul";
16896 break;
16897 case 0x180:
16898 mOp = Iop_AddF64;
16899 oper_name = "add";
16900 break;
16901 case 0x1A0:
16902 mOp = Iop_SubF64;
16903 oper_name = "sub";
16904 break;
16906 default:
16907 vpanic("The impossible happened: dis_vxv_dp_arith(ppc)");
16909 IRTemp hiResult = newTemp(Ity_I64);
16910 IRTemp loResult = newTemp(Ity_I64);
16911 DIP("xv%sdp v%d,v%d,v%d\n", oper_name, XT, XA, XB);
16913 assign( hiResult,
16914 unop( Iop_ReinterpF64asI64,
16915 triop( mOp, rm, mkexpr( frA ), mkexpr( frB ) ) ) );
16916 assign( loResult,
16917 unop( Iop_ReinterpF64asI64,
16918 triop( mOp, rm, mkexpr( frA2 ), mkexpr( frB2 ) ) ) );
16919 putVSReg( XT,
16920 binop( Iop_64HLtoV128, mkexpr( hiResult ), mkexpr( loResult ) ) );
16921 break;
16923 case 0x196: // xvsqrtdp
16925 IRTemp hiResult = newTemp(Ity_I64);
16926 IRTemp loResult = newTemp(Ity_I64);
16927 DIP("xvsqrtdp v%d,v%d\n", XT, XB);
16929 assign( hiResult,
16930 unop( Iop_ReinterpF64asI64,
16931 binop( Iop_SqrtF64, rm, mkexpr( frB ) ) ) );
16932 assign( loResult,
16933 unop( Iop_ReinterpF64asI64,
16934 binop( Iop_SqrtF64, rm, mkexpr( frB2 ) ) ) );
16935 putVSReg( XT,
16936 binop( Iop_64HLtoV128, mkexpr( hiResult ), mkexpr( loResult ) ) );
16937 break;
16939 case 0x184: case 0x1A4: // xvmaddadp, xvmaddmdp (VSX Vector Multiply-Add Double-Precision)
16940 case 0x1C4: case 0x1E4: // xvmsubadp, xvmsubmdp (VSX Vector Multiply-Subtract Double-Precision)
16941 case 0x384: case 0x3A4: // xvnmaddadp, xvnmaddmdp (VSX Vector Negate Multiply-Add Double-Precision)
16942 case 0x3C4: case 0x3E4: // xvnmsubadp, xvnmsubmdp (VSX Vector Negate Multiply-Subtract Double-Precision)
16944 /* xvm{add|sub}mdp XT,XA,XB is element-wise equivalent to fm{add|sub} FRT,FRA,FRC,FRB with . . .
16945 * XT == FRC
16946 * XA == FRA
16947 * XB == FRB
16949 * and for xvm{add|sub}adp . . .
16950 * XT == FRB
16951 * XA == FRA
16952 * XB == FRC
16954 Bool negate;
16955 IROp mOp = Iop_INVALID;
16956 const HChar * oper_name = NULL;
16957 Bool mdp = False;
16959 switch (opc2) {
16960 case 0x184: case 0x1A4:
16961 case 0x384: case 0x3A4:
16962 mOp = Iop_MAddF64;
16963 oper_name = "add";
16964 mdp = (opc2 & 0x0FF) == 0x0A4;
16965 break;
16967 case 0x1C4: case 0x1E4:
16968 case 0x3C4: case 0x3E4:
16969 mOp = Iop_MSubF64;
16970 oper_name = "sub";
16971 mdp = (opc2 & 0x0FF) == 0x0E4;
16972 break;
16974 default:
16975 vpanic("The impossible happened: dis_vxv_sp_arith(ppc)");
16978 switch (opc2) {
16979 case 0x384: case 0x3A4:
16980 case 0x3C4: case 0x3E4:
16981 negate = True;
16982 break;
16983 default:
16984 negate = False;
16986 IRTemp hiResult = newTemp(Ity_I64);
16987 IRTemp loResult = newTemp(Ity_I64);
16988 IRTemp frT = newTemp(Ity_F64);
16989 IRTemp frT2 = newTemp(Ity_F64);
16990 DIP("xv%sm%s%s v%d,v%d,v%d\n", negate ? "n" : "", oper_name, mdp ? "mdp" : "adp",
16991 XT, XA, XB);
16992 assign(frT, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XT ) ) ) );
16993 assign(frT2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg( XT ) ) ) );
16995 assign( hiResult,
16996 unop( Iop_ReinterpF64asI64,
16997 qop( mOp,
16999 mkexpr( frA ),
17000 mkexpr( mdp ? frT : frB ),
17001 mkexpr( mdp ? frB : frT ) ) ) );
17002 assign( loResult,
17003 unop( Iop_ReinterpF64asI64,
17004 qop( mOp,
17006 mkexpr( frA2 ),
17007 mkexpr( mdp ? frT2 : frB2 ),
17008 mkexpr( mdp ? frB2 : frT2 ) ) ) );
17009 putVSReg( XT,
17010 binop( Iop_64HLtoV128,
17011 mkexpr( negate ? getNegatedResult( hiResult )
17012 : hiResult ),
17013 mkexpr( negate ? getNegatedResult( loResult )
17014 : loResult ) ) );
17015 break;
17017 case 0x1D4: // xvtsqrtdp (VSX Vector Test for software Square Root Double-Precision)
17019 IRTemp frBHi_I64 = newTemp(Ity_I64);
17020 IRTemp frBLo_I64 = newTemp(Ity_I64);
17021 IRTemp flagsHi = newTemp(Ity_I32);
17022 IRTemp flagsLo = newTemp(Ity_I32);
17023 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
17024 IRTemp fe_flagHi, fg_flagHi, fe_flagLo, fg_flagLo;
17025 fe_flagHi = fg_flagHi = fe_flagLo = fg_flagLo = IRTemp_INVALID;
17027 DIP("xvtsqrtdp cr%d,v%d\n", crfD, XB);
17028 assign( frBHi_I64, unop(Iop_V128HIto64, getVSReg( XB )) );
17029 assign( frBLo_I64, unop(Iop_V128to64, getVSReg( XB )) );
17030 do_fp_tsqrt(frBHi_I64, False /*not single precision*/, &fe_flagHi, &fg_flagHi);
17031 do_fp_tsqrt(frBLo_I64, False /*not single precision*/, &fe_flagLo, &fg_flagLo);
17032 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
17033 * where fl_flag == 1 on ppc64.
17035 assign( flagsHi,
17036 binop( Iop_Or32,
17037 binop( Iop_Or32, mkU32( 8 ), // fl_flag
17038 binop( Iop_Shl32, mkexpr(fg_flagHi), mkU8( 2 ) ) ),
17039 binop( Iop_Shl32, mkexpr(fe_flagHi), mkU8( 1 ) ) ) );
17040 assign( flagsLo,
17041 binop( Iop_Or32,
17042 binop( Iop_Or32, mkU32( 8 ), // fl_flag
17043 binop( Iop_Shl32, mkexpr(fg_flagLo), mkU8( 2 ) ) ),
17044 binop( Iop_Shl32, mkexpr(fe_flagLo), mkU8( 1 ) ) ) );
17045 putGST_field( PPC_GST_CR,
17046 binop( Iop_Or32, mkexpr( flagsHi ), mkexpr( flagsLo ) ),
17047 crfD );
17048 break;
17050 case 0x1F4: // xvtdivdp (VSX Vector Test for software Divide Double-Precision)
17052 IRTemp frBHi_I64 = newTemp(Ity_I64);
17053 IRTemp frBLo_I64 = newTemp(Ity_I64);
17054 IRTemp frAHi_I64 = newTemp(Ity_I64);
17055 IRTemp frALo_I64 = newTemp(Ity_I64);
17056 IRTemp flagsHi = newTemp(Ity_I32);
17057 IRTemp flagsLo = newTemp(Ity_I32);
17058 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
17059 IRTemp fe_flagHi, fg_flagHi, fe_flagLo, fg_flagLo;
17060 fe_flagHi = fg_flagHi = fe_flagLo = fg_flagLo = IRTemp_INVALID;
17062 DIP("xvtdivdp cr%d,v%d,v%d\n", crfD, XA, XB);
17063 assign( frAHi_I64, unop(Iop_V128HIto64, getVSReg( XA )) );
17064 assign( frALo_I64, unop(Iop_V128to64, getVSReg( XA )) );
17065 assign( frBHi_I64, unop(Iop_V128HIto64, getVSReg( XB )) );
17066 assign( frBLo_I64, unop(Iop_V128to64, getVSReg( XB )) );
17068 _do_fp_tdiv(frAHi_I64, frBHi_I64, False/*dp*/, &fe_flagHi, &fg_flagHi);
17069 _do_fp_tdiv(frALo_I64, frBLo_I64, False/*dp*/, &fe_flagLo, &fg_flagLo);
17070 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
17071 * where fl_flag == 1 on ppc64.
17073 assign( flagsHi,
17074 binop( Iop_Or32,
17075 binop( Iop_Or32, mkU32( 8 ), // fl_flag
17076 binop( Iop_Shl32, mkexpr(fg_flagHi), mkU8( 2 ) ) ),
17077 binop( Iop_Shl32, mkexpr(fe_flagHi), mkU8( 1 ) ) ) );
17078 assign( flagsLo,
17079 binop( Iop_Or32,
17080 binop( Iop_Or32, mkU32( 8 ), // fl_flag
17081 binop( Iop_Shl32, mkexpr(fg_flagLo), mkU8( 2 ) ) ),
17082 binop( Iop_Shl32, mkexpr(fe_flagLo), mkU8( 1 ) ) ) );
17083 putGST_field( PPC_GST_CR,
17084 binop( Iop_Or32, mkexpr( flagsHi ), mkexpr( flagsLo ) ),
17085 crfD );
17086 break;
17089 default:
17090 vex_printf( "dis_vxv_dp_arith(ppc)(opc2)\n" );
17091 return False;
17093 return True;
17097 * VSX vector Single Precision Floating Point Arithmetic Instructions
17099 static Bool
17100 dis_vxv_sp_arith ( UInt theInstr, UInt opc2 )
17102 /* XX3-Form */
17103 UChar opc1 = ifieldOPC( theInstr );
17104 UChar XT = ifieldRegXT( theInstr );
17105 UChar XA = ifieldRegXA( theInstr );
17106 UChar XB = ifieldRegXB( theInstr );
17107 IRExpr* rm = get_IR_roundingmode();
17108 IRTemp a3, a2, a1, a0;
17109 IRTemp b3, b2, b1, b0;
17110 IRTemp res0 = newTemp(Ity_I32);
17111 IRTemp res1 = newTemp(Ity_I32);
17112 IRTemp res2 = newTemp(Ity_I32);
17113 IRTemp res3 = newTemp(Ity_I32);
17115 a3 = a2 = a1 = a0 = IRTemp_INVALID;
17116 b3 = b2 = b1 = b0 = IRTemp_INVALID;
17118 if (opc1 != 0x3C) {
17119 vex_printf( "dis_vxv_sp_arith(ppc)(instr)\n" );
17120 return False;
17123 switch (opc2) {
17124 case 0x100: // xvaddsp (VSX Vector Add Single-Precision)
17125 DIP("xvaddsp v%d,v%d,v%d\n", XT, XA, XB);
17126 // WARNING: BOGUS! The backend ignores rm on Iop_Add32Fx4
17127 putVSReg( XT, triop(Iop_Add32Fx4, rm,
17128 getVSReg( XA ), getVSReg( XB )) );
17129 break;
17131 case 0x140: // xvmulsp (VSX Vector Multiply Single-Precision)
17132 DIP("xvmulsp v%d,v%d,v%d\n", XT, XA, XB);
17133 // WARNING: BOGUS! The backend ignores rm on Iop_Mul32Fx4
17134 putVSReg( XT, triop(Iop_Mul32Fx4, rm,
17135 getVSReg( XA ), getVSReg( XB )) );
17136 break;
17138 case 0x120: // xvsubsp (VSX Vector Subtract Single-Precision)
17139 DIP("xvsubsp v%d,v%d,v%d\n", XT, XA, XB);
17140 // WARNING: BOGUS! The backend ignores rm on Iop_Sub32Fx4
17141 putVSReg( XT, triop(Iop_Sub32Fx4, rm,
17142 getVSReg( XA ), getVSReg( XB )) );
17143 break;
17145 case 0x160: // xvdivsp (VSX Vector Divide Single-Precision)
17147 /* Iop_Div32Fx4 is not implemented for ppc64 (in host_ppc_{isel|defs}.c.
17148 * So there are two choices:
17149 * 1. Implement the xvdivsp with a native insn; or
17150 * 2. Extract the 4 single precision floats from each vector
17151 * register inputs and perform fdivs on each pair
17152 * I will do the latter, due to the general philosophy of
17153 * reusing existing implementations when practical.
17155 DIP("xvdivsp v%d,v%d,v%d\n", XT, XA, XB);
17156 breakV128to4xF64( getVSReg( XA ), &a3, &a2, &a1, &a0 );
17157 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
17159 assign( res0,
17160 unop( Iop_ReinterpF32asI32,
17161 unop( Iop_TruncF64asF32,
17162 triop( Iop_DivF64r32, rm, mkexpr( a0 ), mkexpr( b0 ) ) ) ) );
17163 assign( res1,
17164 unop( Iop_ReinterpF32asI32,
17165 unop( Iop_TruncF64asF32,
17166 triop( Iop_DivF64r32, rm, mkexpr( a1 ), mkexpr( b1 ) ) ) ) );
17167 assign( res2,
17168 unop( Iop_ReinterpF32asI32,
17169 unop( Iop_TruncF64asF32,
17170 triop( Iop_DivF64r32, rm, mkexpr( a2 ), mkexpr( b2 ) ) ) ) );
17171 assign( res3,
17172 unop( Iop_ReinterpF32asI32,
17173 unop( Iop_TruncF64asF32,
17174 triop( Iop_DivF64r32, rm, mkexpr( a3 ), mkexpr( b3 ) ) ) ) );
17176 putVSReg( XT,
17177 binop( Iop_64HLtoV128,
17178 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
17179 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
17180 break;
17182 case 0x116: // xvsqrtsp (VSX Vector Square Root Single-Precision)
17184 DIP("xvsqrtsp v%d,v%d\n", XT, XB);
17185 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
17186 /* Note: The native xvsqrtsp insruction does not always give the same precision
17187 * as what we get with Iop_SqrtF64. But it doesn't seem worthwhile to implement
17188 * an Iop_SqrtF32 that would give us a lower precision result, albeit more true
17189 * to the actual instruction.
17192 assign( res0,
17193 unop( Iop_ReinterpF32asI32,
17194 unop( Iop_TruncF64asF32,
17195 binop(Iop_SqrtF64, rm, mkexpr( b0 ) ) ) ) );
17196 assign( res1,
17197 unop( Iop_ReinterpF32asI32,
17198 unop( Iop_TruncF64asF32,
17199 binop(Iop_SqrtF64, rm, mkexpr( b1 ) ) ) ) );
17200 assign( res2,
17201 unop( Iop_ReinterpF32asI32,
17202 unop( Iop_TruncF64asF32,
17203 binop(Iop_SqrtF64, rm, mkexpr( b2) ) ) ) );
17204 assign( res3,
17205 unop( Iop_ReinterpF32asI32,
17206 unop( Iop_TruncF64asF32,
17207 binop(Iop_SqrtF64, rm, mkexpr( b3 ) ) ) ) );
17209 putVSReg( XT,
17210 binop( Iop_64HLtoV128,
17211 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
17212 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
17213 break;
17216 case 0x104: case 0x124: // xvmaddasp, xvmaddmsp (VSX Vector Multiply-Add Single-Precision)
17217 case 0x144: case 0x164: // xvmsubasp, xvmsubmsp (VSX Vector Multiply-Subtract Single-Precision)
17218 case 0x304: case 0x324: // xvnmaddasp, xvnmaddmsp (VSX Vector Negate Multiply-Add Single-Precision)
17219 case 0x344: case 0x364: // xvnmsubasp, xvnmsubmsp (VSX Vector Negate Multiply-Subtract Single-Precision)
17221 IRTemp t3, t2, t1, t0;
17222 Bool msp = False;
17223 Bool negate;
17224 const HChar * oper_name = NULL;
17225 IROp mOp = Iop_INVALID;
17226 switch (opc2) {
17227 case 0x104: case 0x124:
17228 case 0x304: case 0x324:
17229 msp = (opc2 & 0x0FF) == 0x024;
17230 mOp = Iop_MAddF64r32;
17231 oper_name = "madd";
17232 break;
17234 case 0x144: case 0x164:
17235 case 0x344: case 0x364:
17236 msp = (opc2 & 0x0FF) == 0x064;
17237 mOp = Iop_MSubF64r32;
17238 oper_name = "sub";
17239 break;
17241 default:
17242 vpanic("The impossible happened: dis_vxv_sp_arith(ppc)");
17245 switch (opc2) {
17246 case 0x304: case 0x324:
17247 case 0x344: case 0x364:
17248 negate = True;
17249 break;
17251 default:
17252 negate = False;
17255 DIP("xv%sm%s%s v%d,v%d,v%d\n", negate ? "n" : "", oper_name,
17256 msp ? "msp" : "asp", XT, XA, XB);
17258 t3 = t2 = t1 = t0 = IRTemp_INVALID;
17259 breakV128to4xF64( getVSReg( XA ), &a3, &a2, &a1, &a0 );
17260 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
17261 breakV128to4xF64( getVSReg( XT ), &t3, &t2, &t1, &t0 );
17263 assign( res0,
17264 unop( Iop_ReinterpF32asI32,
17265 unop( Iop_TruncF64asF32,
17266 qop( mOp,
17268 mkexpr( a0 ),
17269 mkexpr( msp ? t0 : b0 ),
17270 mkexpr( msp ? b0 : t0 ) ) ) ) );
17271 assign( res1,
17272 unop( Iop_ReinterpF32asI32,
17273 unop( Iop_TruncF64asF32,
17274 qop( mOp,
17276 mkexpr( a1 ),
17277 mkexpr( msp ? t1 : b1 ),
17278 mkexpr( msp ? b1 : t1 ) ) ) ) );
17279 assign( res2,
17280 unop( Iop_ReinterpF32asI32,
17281 unop( Iop_TruncF64asF32,
17282 qop( mOp,
17284 mkexpr( a2 ),
17285 mkexpr( msp ? t2 : b2 ),
17286 mkexpr( msp ? b2 : t2 ) ) ) ) );
17287 assign( res3,
17288 unop( Iop_ReinterpF32asI32,
17289 unop( Iop_TruncF64asF32,
17290 qop( mOp,
17292 mkexpr( a3 ),
17293 mkexpr( msp ? t3 : b3 ),
17294 mkexpr( msp ? b3 : t3 ) ) ) ) );
17296 putVSReg( XT,
17297 binop( Iop_64HLtoV128,
17298 binop( Iop_32HLto64, mkexpr( negate ? getNegatedResult_32( res3 ) : res3 ),
17299 mkexpr( negate ? getNegatedResult_32( res2 ) : res2 ) ),
17300 binop( Iop_32HLto64, mkexpr( negate ? getNegatedResult_32( res1 ) : res1 ),
17301 mkexpr( negate ? getNegatedResult_32( res0 ) : res0 ) ) ) );
17303 break;
17305 case 0x154: // xvtsqrtsp (VSX Vector Test for software Square Root Single-Precision)
17307 IRTemp flags0 = newTemp(Ity_I32);
17308 IRTemp flags1 = newTemp(Ity_I32);
17309 IRTemp flags2 = newTemp(Ity_I32);
17310 IRTemp flags3 = newTemp(Ity_I32);
17311 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
17312 IRTemp fe_flag0, fg_flag0, fe_flag1, fg_flag1;
17313 IRTemp fe_flag2, fg_flag2, fe_flag3, fg_flag3;
17314 fe_flag0 = fg_flag0 = fe_flag1 = fg_flag1 = IRTemp_INVALID;
17315 fe_flag2 = fg_flag2 = fe_flag3 = fg_flag3 = IRTemp_INVALID;
17316 DIP("xvtsqrtsp cr%d,v%d\n", crfD, XB);
17318 breakV128to4x32( getVSReg( XB ), &b3, &b2, &b1, &b0 );
17319 do_fp_tsqrt(b0, True /* single precision*/, &fe_flag0, &fg_flag0);
17320 do_fp_tsqrt(b1, True /* single precision*/, &fe_flag1, &fg_flag1);
17321 do_fp_tsqrt(b2, True /* single precision*/, &fe_flag2, &fg_flag2);
17322 do_fp_tsqrt(b3, True /* single precision*/, &fe_flag3, &fg_flag3);
17324 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
17325 * where fl_flag == 1 on ppc64.
17327 assign( flags0,
17328 binop( Iop_Or32,
17329 binop( Iop_Or32, mkU32( 8 ), // fl_flag
17330 binop( Iop_Shl32, mkexpr(fg_flag0), mkU8( 2 ) ) ),
17331 binop( Iop_Shl32, mkexpr(fe_flag0), mkU8( 1 ) ) ) );
17332 assign( flags1,
17333 binop( Iop_Or32,
17334 binop( Iop_Or32, mkU32( 8 ), // fl_flag
17335 binop( Iop_Shl32, mkexpr(fg_flag1), mkU8( 2 ) ) ),
17336 binop( Iop_Shl32, mkexpr(fe_flag1), mkU8( 1 ) ) ) );
17337 assign( flags2,
17338 binop( Iop_Or32,
17339 binop( Iop_Or32, mkU32( 8 ), // fl_flag
17340 binop( Iop_Shl32, mkexpr(fg_flag2), mkU8( 2 ) ) ),
17341 binop( Iop_Shl32, mkexpr(fe_flag2), mkU8( 1 ) ) ) );
17342 assign( flags3,
17343 binop( Iop_Or32,
17344 binop( Iop_Or32, mkU32( 8 ), // fl_flag
17345 binop( Iop_Shl32, mkexpr(fg_flag3), mkU8( 2 ) ) ),
17346 binop( Iop_Shl32, mkexpr(fe_flag3), mkU8( 1 ) ) ) );
17347 putGST_field( PPC_GST_CR,
17348 binop( Iop_Or32,
17349 mkexpr( flags0 ),
17350 binop( Iop_Or32,
17351 mkexpr( flags1 ),
17352 binop( Iop_Or32,
17353 mkexpr( flags2 ),
17354 mkexpr( flags3 ) ) ) ),
17355 crfD );
17357 break;
17359 case 0x174: // xvtdivsp (VSX Vector Test for software Divide Single-Precision)
17361 IRTemp flags0 = newTemp(Ity_I32);
17362 IRTemp flags1 = newTemp(Ity_I32);
17363 IRTemp flags2 = newTemp(Ity_I32);
17364 IRTemp flags3 = newTemp(Ity_I32);
17365 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
17366 IRTemp fe_flag0, fg_flag0, fe_flag1, fg_flag1;
17367 IRTemp fe_flag2, fg_flag2, fe_flag3, fg_flag3;
17368 fe_flag0 = fg_flag0 = fe_flag1 = fg_flag1 = IRTemp_INVALID;
17369 fe_flag2 = fg_flag2 = fe_flag3 = fg_flag3 = IRTemp_INVALID;
17370 DIP("xvtdivsp cr%d,v%d,v%d\n", crfD, XA, XB);
17372 breakV128to4x32( getVSReg( XA ), &a3, &a2, &a1, &a0 );
17373 breakV128to4x32( getVSReg( XB ), &b3, &b2, &b1, &b0 );
17374 _do_fp_tdiv(a0, b0, True /* single precision*/, &fe_flag0, &fg_flag0);
17375 _do_fp_tdiv(a1, b1, True /* single precision*/, &fe_flag1, &fg_flag1);
17376 _do_fp_tdiv(a2, b2, True /* single precision*/, &fe_flag2, &fg_flag2);
17377 _do_fp_tdiv(a3, b3, True /* single precision*/, &fe_flag3, &fg_flag3);
17379 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
17380 * where fl_flag == 1 on ppc64.
17382 assign( flags0,
17383 binop( Iop_Or32,
17384 binop( Iop_Or32, mkU32( 8 ), // fl_flag
17385 binop( Iop_Shl32, mkexpr(fg_flag0), mkU8( 2 ) ) ),
17386 binop( Iop_Shl32, mkexpr(fe_flag0), mkU8( 1 ) ) ) );
17387 assign( flags1,
17388 binop( Iop_Or32,
17389 binop( Iop_Or32, mkU32( 8 ), // fl_flag
17390 binop( Iop_Shl32, mkexpr(fg_flag1), mkU8( 2 ) ) ),
17391 binop( Iop_Shl32, mkexpr(fe_flag1), mkU8( 1 ) ) ) );
17392 assign( flags2,
17393 binop( Iop_Or32,
17394 binop( Iop_Or32, mkU32( 8 ), // fl_flag
17395 binop( Iop_Shl32, mkexpr(fg_flag2), mkU8( 2 ) ) ),
17396 binop( Iop_Shl32, mkexpr(fe_flag2), mkU8( 1 ) ) ) );
17397 assign( flags3,
17398 binop( Iop_Or32,
17399 binop( Iop_Or32, mkU32( 8 ), // fl_flag
17400 binop( Iop_Shl32, mkexpr(fg_flag3), mkU8( 2 ) ) ),
17401 binop( Iop_Shl32, mkexpr(fe_flag3), mkU8( 1 ) ) ) );
17402 putGST_field( PPC_GST_CR,
17403 binop( Iop_Or32,
17404 mkexpr( flags0 ),
17405 binop( Iop_Or32,
17406 mkexpr( flags1 ),
17407 binop( Iop_Or32,
17408 mkexpr( flags2 ),
17409 mkexpr( flags3 ) ) ) ),
17410 crfD );
17412 break;
17415 default:
17416 vex_printf( "dis_vxv_sp_arith(ppc)(opc2)\n" );
17417 return False;
17419 return True;
17423 * Vector Population Count/bit matrix transpose
17425 static Bool
17426 dis_av_count_bitTranspose ( UInt theInstr, UInt opc2 )
17428 UChar vRB_addr = ifieldRegB(theInstr);
17429 UChar vRT_addr = ifieldRegDS(theInstr);
17430 UChar opc1 = ifieldOPC( theInstr );
17431 IRTemp vB = newTemp(Ity_V128);
17432 assign( vB, getVReg(vRB_addr));
17434 if (opc1 != 0x4) {
17435 vex_printf( "dis_av_count_bitTranspose(ppc)(instr)\n" );
17436 return False;
17439 switch (opc2) {
17440 case 0x702: // vclzb
17441 DIP("vclzb v%d,v%d\n", vRT_addr, vRB_addr);
17442 putVReg( vRT_addr, unop(Iop_Clz8x16, mkexpr( vB ) ) );
17443 break;
17445 case 0x742: // vclzh
17446 DIP("vclzh v%d,v%d\n", vRT_addr, vRB_addr);
17447 putVReg( vRT_addr, unop(Iop_Clz16x8, mkexpr( vB ) ) );
17448 break;
17450 case 0x782: // vclzw
17451 DIP("vclzw v%d,v%d\n", vRT_addr, vRB_addr);
17452 putVReg( vRT_addr, unop(Iop_Clz32x4, mkexpr( vB ) ) );
17453 break;
17455 case 0x7C2: // vclzd
17456 DIP("vclzd v%d,v%d\n", vRT_addr, vRB_addr);
17457 putVReg( vRT_addr, unop(Iop_Clz64x2, mkexpr( vB ) ) );
17458 break;
17460 case 0x703: // vpopcntb
17462 /* Break vector into 32-bit words and do the population count
17463 * on byte in the words
17465 IRType ty = Ity_I32;
17466 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
17467 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
17468 IRTemp cnt_bits0_31, cnt_bits32_63, cnt_bits64_95, cnt_bits96_127;
17469 cnt_bits0_31 = cnt_bits32_63 = cnt_bits64_95 = cnt_bits96_127 = IRTemp_INVALID;
17471 DIP("vpopcntb v%d,v%d\n", vRT_addr, vRB_addr);
17472 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
17473 cnt_bits0_31 = gen_POPCOUNT(ty, bits0_31, BYTE);
17474 cnt_bits32_63 = gen_POPCOUNT(ty, bits32_63, BYTE);
17475 cnt_bits64_95 = gen_POPCOUNT(ty, bits64_95, BYTE);
17476 cnt_bits96_127 = gen_POPCOUNT(ty, bits96_127, BYTE);
17478 putVReg( vRT_addr, mkV128from32(cnt_bits96_127, cnt_bits64_95,
17479 cnt_bits32_63, cnt_bits0_31) );
17480 break;
17483 case 0x743: // vpopcnth
17485 /* Break vector into 32-bit words and do the population count
17486 * for each half word
17488 IRType ty = Ity_I32;
17489 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
17490 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
17491 IRTemp cnt_bits0_31, cnt_bits32_63, cnt_bits64_95, cnt_bits96_127;
17492 cnt_bits0_31 = cnt_bits32_63 = cnt_bits64_95 = cnt_bits96_127 = IRTemp_INVALID;
17494 DIP("vpopcnth v%d,v%d\n", vRT_addr, vRB_addr);
17495 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
17497 cnt_bits0_31 = gen_POPCOUNT(ty, bits0_31, HWORD);
17498 cnt_bits32_63 = gen_POPCOUNT(ty, bits32_63, HWORD);
17499 cnt_bits64_95 = gen_POPCOUNT(ty, bits64_95, HWORD);
17500 cnt_bits96_127 = gen_POPCOUNT(ty, bits96_127, HWORD);
17502 putVReg( vRT_addr, mkV128from32(cnt_bits96_127, cnt_bits64_95,
17503 cnt_bits32_63, cnt_bits0_31) );
17504 break;
17507 case 0x783: // vpopcntw
17509 /* Break vector into 32-bit words and do the population count
17510 * on each word.
17512 IRType ty = Ity_I32;
17513 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
17514 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
17515 IRTemp cnt_bits0_31, cnt_bits32_63, cnt_bits64_95, cnt_bits96_127;
17516 cnt_bits0_31 = cnt_bits32_63 = cnt_bits64_95 = cnt_bits96_127 = IRTemp_INVALID;
17518 DIP("vpopcntw v%d,v%d\n", vRT_addr, vRB_addr);
17519 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
17521 cnt_bits0_31 = gen_POPCOUNT(ty, bits0_31, WORD);
17522 cnt_bits32_63 = gen_POPCOUNT(ty, bits32_63, WORD);
17523 cnt_bits64_95 = gen_POPCOUNT(ty, bits64_95, WORD);
17524 cnt_bits96_127 = gen_POPCOUNT(ty, bits96_127, WORD);
17526 putVReg( vRT_addr, mkV128from32(cnt_bits96_127, cnt_bits64_95,
17527 cnt_bits32_63, cnt_bits0_31) );
17528 break;
17531 case 0x7C3: // vpopcntd
17533 if (mode64) {
17534 /* Break vector into 64-bit double words and do the population
17535 count on each double word.
17537 IRType ty = Ity_I64;
17538 IRTemp bits0_63 = newTemp(Ity_I64);
17539 IRTemp bits64_127 = newTemp(Ity_I64);
17540 IRTemp cnt_bits0_63 = newTemp(Ity_I64);
17541 IRTemp cnt_bits64_127 = newTemp(Ity_I64);
17543 DIP("vpopcntd v%d,v%d\n", vRT_addr, vRB_addr);
17545 assign(bits0_63, unop( Iop_V128to64, mkexpr( vB ) ) );
17546 assign(bits64_127, unop( Iop_V128HIto64, mkexpr( vB ) ) );
17547 cnt_bits0_63 = gen_POPCOUNT(ty, bits0_63, DWORD);
17548 cnt_bits64_127 = gen_POPCOUNT(ty, bits64_127, DWORD);
17550 putVReg( vRT_addr, binop( Iop_64HLtoV128,
17551 mkexpr( cnt_bits64_127 ),
17552 mkexpr( cnt_bits0_63 ) ) );
17553 } else {
17554 /* Break vector into 32-bit words and do the population count
17555 on each 32-bit word.
17557 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
17558 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
17559 IRTemp cnt_bits0_63 = newTemp(Ity_I64);
17560 IRTemp cnt_bits64_127 = newTemp(Ity_I64);
17562 DIP("vpopcntd v%d,v%d\n", vRT_addr, vRB_addr);
17563 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95,
17564 &bits32_63, &bits0_31 );
17566 cnt_bits0_63 = gen_vpopcntd_mode32(bits0_31, bits32_63);
17567 cnt_bits64_127 = gen_vpopcntd_mode32(bits64_95, bits96_127);
17569 putVReg( vRT_addr, binop( Iop_64HLtoV128,
17570 mkexpr( cnt_bits64_127 ),
17571 mkexpr( cnt_bits0_63 ) ) );
17573 break;
17576 case 0x50C: // vgbbd Vector Gather Bits by Bytes by Doubleword
17577 DIP("vgbbd v%d,v%d\n", vRT_addr, vRB_addr);
17578 putVReg( vRT_addr, unop( Iop_PwBitMtxXpose64x2, mkexpr( vB ) ) );
17579 break;
17581 case 0x5CC: // vbpermd Vector Bit Permute Doubleword
17583 UChar vRA_addr = ifieldRegA( theInstr );
17584 IRTemp vA = newTemp( Ity_V128 );
17585 UInt j;
17586 IRTemp index_dword_hi[8]; // index in double word
17587 IRTemp index_dword_lo[8];
17588 IRTemp index_dword_hi_valid[8];
17589 IRTemp index_dword_lo_valid[8];
17590 IRTemp pb_dword_hi[8]; // permute bit
17591 IRTemp pb_dword_lo[8];
17592 IRTemp tmp_hi[9];
17593 IRTemp tmp_lo[9];
17595 DIP("vbpermd v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
17597 tmp_hi[0] = newTemp( Ity_I64 );
17598 tmp_lo[0] = newTemp( Ity_I64 );
17600 assign( vA, getVReg(vRA_addr) );
17601 assign( tmp_hi[0], mkU64( 0 ) );
17602 assign( tmp_lo[0], mkU64( 0 ) );
17604 for (j=0; j<8; j++) {
17605 index_dword_hi[j] = newTemp( Ity_I64 );
17606 index_dword_lo[j] = newTemp( Ity_I64 );
17607 index_dword_hi_valid[j] = newTemp( Ity_I64 );
17608 index_dword_lo_valid[j] = newTemp( Ity_I64 );
17609 pb_dword_hi[j] = newTemp( Ity_I64 );
17610 pb_dword_lo[j] = newTemp( Ity_I64 );
17611 tmp_hi[j+1] = newTemp( Ity_I64 );
17612 tmp_lo[j+1] = newTemp( Ity_I64 );
17614 assign( index_dword_hi[j],
17615 binop( Iop_And64,
17616 binop( Iop_Shr64,
17617 unop( Iop_V128HIto64,
17618 mkexpr( vB ) ),
17619 mkU8( ( 7 - j ) * 8 ) ),
17620 mkU64( 0xFF ) ) );
17622 assign( index_dword_lo[j],
17623 binop( Iop_And64,
17624 binop( Iop_Shr64,
17625 unop( Iop_V128to64,
17626 mkexpr( vB ) ),
17627 mkU8( ( 7 - j ) * 8 ) ),
17628 mkU64( 0xFF ) ) );
17630 assign( index_dword_hi_valid[j],
17631 unop( Iop_1Sto64,
17632 binop( Iop_CmpLT64U,
17633 mkexpr( index_dword_hi[j] ),
17634 mkU64( 64 ) ) ) );
17636 assign( index_dword_lo_valid[j],
17637 unop( Iop_1Sto64,
17638 binop( Iop_CmpLT64U,
17639 mkexpr( index_dword_lo[j] ),
17640 mkU64( 64 ) ) ) );
17641 assign( pb_dword_hi[j],
17642 binop( Iop_And64,
17643 binop( Iop_Shr64,
17644 unop( Iop_V128HIto64,
17645 mkexpr( vA ) ),
17646 unop( Iop_64to8,
17647 binop( Iop_Sub64,
17648 mkU64( 63 ),
17649 mkexpr( index_dword_hi[j] )
17650 ) ) ),
17651 mkU64( 0x1 ) ) );
17653 assign( pb_dword_lo[j],
17654 binop( Iop_And64,
17655 binop( Iop_Shr64,
17656 unop( Iop_V128to64,
17657 mkexpr( vA ) ),
17658 unop( Iop_64to8,
17659 binop( Iop_Sub64,
17660 mkU64( 63 ),
17661 mkexpr( index_dword_lo[j] )
17662 ) ) ),
17663 mkU64( 0x1 ) ) );
17665 assign( tmp_hi[j+1],
17666 binop( Iop_Or64,
17667 binop( Iop_And64,
17668 mkexpr( index_dword_hi_valid[j] ),
17669 binop( Iop_Shl64,
17670 mkexpr( pb_dword_hi[j] ),
17671 mkU8( 7 - j ) ) ),
17672 mkexpr( tmp_hi[j] ) ) );
17674 assign( tmp_lo[j+1],
17675 binop( Iop_Or64,
17676 binop( Iop_And64,
17677 mkexpr( index_dword_lo_valid[j] ),
17678 binop( Iop_Shl64,
17679 mkexpr( pb_dword_lo[j] ),
17680 mkU8( 7 - j ) ) ),
17681 mkexpr( tmp_lo[j] ) ) );
17684 putVReg( vRT_addr,
17685 binop( Iop_64HLtoV128,
17686 mkexpr( tmp_hi[8] ),
17687 mkexpr( tmp_lo[8] ) ) );
17689 break;
17691 default:
17692 vex_printf("dis_av_count_bitTranspose(ppc)(opc2)\n");
17693 return False;
17694 break;
17696 return True;
17699 typedef enum {
17700 PPC_CMP_EQ = 2,
17701 PPC_CMP_GT = 4,
17702 PPC_CMP_GE = 6,
17703 PPC_CMP_LT = 8
17704 } ppc_cmp_t;
17708 This helper function takes as input the IRExpr returned
17709 from a binop( Iop_CmpF64, fpA, fpB), whose result is returned
17710 in IR form. This helper function converts it to PPC form.
17712 Map compare result from IR to PPC
17714 FP cmp result | PPC | IR
17715 --------------------------
17716 UN | 0x1 | 0x45
17717 EQ | 0x2 | 0x40
17718 GT | 0x4 | 0x00
17719 LT | 0x8 | 0x01
17721 condcode = Shl(1, (~(ccIR>>5) & 2)
17722 | ((ccIR ^ (ccIR>>6)) & 1)
17724 static IRTemp
17725 get_fp_cmp_CR_val (IRExpr * ccIR_expr)
17727 IRTemp condcode = newTemp( Ity_I32 );
17728 IRTemp ccIR = newTemp( Ity_I32 );
17730 assign(ccIR, ccIR_expr);
17731 assign( condcode,
17732 binop( Iop_Shl32,
17733 mkU32( 1 ),
17734 unop( Iop_32to8,
17735 binop( Iop_Or32,
17736 binop( Iop_And32,
17737 unop( Iop_Not32,
17738 binop( Iop_Shr32,
17739 mkexpr( ccIR ),
17740 mkU8( 5 ) ) ),
17741 mkU32( 2 ) ),
17742 binop( Iop_And32,
17743 binop( Iop_Xor32,
17744 mkexpr( ccIR ),
17745 binop( Iop_Shr32,
17746 mkexpr( ccIR ),
17747 mkU8( 6 ) ) ),
17748 mkU32( 1 ) ) ) ) ) );
17749 return condcode;
17753 * Helper function for get_max_min_fp for ascertaining the max or min between two doubles
17754 * following these special rules:
17755 * - The max/min of a QNaN and any value is that value
17756 * (When two QNaNs are being compared, the frA QNaN is the return value.)
17757 * - The max/min of any value and an SNaN is that SNaN converted to a QNaN
17758 * (When two SNaNs are being compared, the frA SNaN is converted to a QNaN.)
17760 static IRExpr * _get_maxmin_fp_NaN(IRTemp frA_I64, IRTemp frB_I64)
17762 IRTemp frA_isNaN = newTemp(Ity_I1);
17763 IRTemp frB_isNaN = newTemp(Ity_I1);
17764 IRTemp frA_isSNaN = newTemp(Ity_I1);
17765 IRTemp frB_isSNaN = newTemp(Ity_I1);
17766 IRTemp frA_isQNaN = newTemp(Ity_I1);
17767 IRTemp frB_isQNaN = newTemp(Ity_I1);
17769 assign( frA_isNaN, is_NaN( Ity_I64, frA_I64 ) );
17770 assign( frB_isNaN, is_NaN( Ity_I64, frB_I64 ) );
17771 // If operand is a NAN and bit 12 is '0', then it's an SNaN
17772 assign( frA_isSNaN,
17773 mkAND1( mkexpr(frA_isNaN),
17774 binop( Iop_CmpEQ32,
17775 binop( Iop_And32,
17776 unop( Iop_64HIto32, mkexpr( frA_I64 ) ),
17777 mkU32( 0x00080000 ) ),
17778 mkU32( 0 ) ) ) );
17779 assign( frB_isSNaN,
17780 mkAND1( mkexpr(frB_isNaN),
17781 binop( Iop_CmpEQ32,
17782 binop( Iop_And32,
17783 unop( Iop_64HIto32, mkexpr( frB_I64 ) ),
17784 mkU32( 0x00080000 ) ),
17785 mkU32( 0 ) ) ) );
17786 assign( frA_isQNaN,
17787 mkAND1( mkexpr( frA_isNaN ), unop( Iop_Not1, mkexpr( frA_isSNaN ) ) ) );
17788 assign( frB_isQNaN,
17789 mkAND1( mkexpr( frB_isNaN ), unop( Iop_Not1, mkexpr( frB_isSNaN ) ) ) );
17791 /* Based on the rules specified in the function prologue, the algorithm is as follows:
17792 * <<<<<<<<<>>>>>>>>>>>>>>>>>>
17793 * if frA is a SNaN
17794 * result = frA converted to QNaN
17795 * else if frB is a SNaN
17796 * if (frA is QNan)
17797 * result = frA
17798 * else
17799 * result = frB converted to QNaN
17800 * else if frB is a QNaN
17801 * result = frA
17802 * // One of frA or frB was a NaN in order for this function to be called, so
17803 * // if we get to this point, we KNOW that frA must be a QNaN.
17804 * else // frA is a QNaN
17805 * result = frB
17806 * <<<<<<<<<>>>>>>>>>>>>>>>>>>
17809 #define SNAN_MASK 0x0008000000000000ULL
17811 return
17812 IRExpr_ITE(mkexpr(frA_isSNaN),
17813 /* then: result = frA converted to QNaN */
17814 binop(Iop_Or64, mkexpr(frA_I64), mkU64(SNAN_MASK)),
17815 /* else: if frB is a SNaN */
17816 IRExpr_ITE(mkexpr(frB_isSNaN),
17817 IRExpr_ITE(mkexpr(frA_isQNaN),
17818 /* then: result = frA */
17819 mkexpr(frA_I64),
17820 /* else: result = frB converted to QNaN */
17821 binop(Iop_Or64, mkexpr(frB_I64),
17822 mkU64(SNAN_MASK))),
17823 /* else: if frB is a QNaN */
17824 IRExpr_ITE(mkexpr(frB_isQNaN),
17825 /* then: result = frA */
17826 mkexpr(frA_I64),
17827 /* else: frA is a QNaN, so result = frB */
17828 mkexpr(frB_I64))));
17832 * Helper function for get_max_min_fp.
17834 static IRExpr * _get_maxmin_fp_cmp(IRTemp src1, IRTemp src2, Bool isMin)
17836 IRTemp src1cmpsrc2 = get_fp_cmp_CR_val( binop( Iop_CmpF64,
17837 unop( Iop_ReinterpI64asF64,
17838 mkexpr( src1 ) ),
17839 unop( Iop_ReinterpI64asF64,
17840 mkexpr( src2 ) ) ) );
17842 return IRExpr_ITE( binop( Iop_CmpEQ32,
17843 mkexpr( src1cmpsrc2 ),
17844 mkU32( isMin ? PPC_CMP_LT : PPC_CMP_GT ) ),
17845 /* then: use src1 */
17846 mkexpr( src1 ),
17847 /* else: use src2 */
17848 mkexpr( src2 ) );
17852 * Helper function for "Maximum/Minimum Double Precision" operations.
17853 * Arguments: frA and frb are Ity_I64
17854 * Returns Ity_I64 IRExpr that answers the "which is Maxiumum/Minimum" question
17856 static IRExpr * get_max_min_fp(IRTemp frA_I64, IRTemp frB_I64, Bool isMin)
17858 /* There are three special cases where get_fp_cmp_CR_val is not helpful
17859 * for ascertaining the maximum between two doubles:
17860 * 1. The max/min of +0 and -0 is +0.
17861 * 2. The max/min of a QNaN and any value is that value.
17862 * 3. The max/min of any value and an SNaN is that SNaN converted to a QNaN.
17863 * We perform the check for [+/-]0 here in this function and use the
17864 * _get_maxmin_fp_NaN helper for the two NaN cases; otherwise we call _get_maxmin_fp_cmp
17865 * to do the standard comparison function.
17867 IRTemp anyNaN = newTemp(Ity_I1);
17868 IRTemp frA_isZero = newTemp(Ity_I1);
17869 IRTemp frB_isZero = newTemp(Ity_I1);
17870 assign( frA_isZero, is_Zero( Ity_I64, frA_I64 ) );
17871 assign( frB_isZero, is_Zero( Ity_I64, frB_I64 ) );
17872 assign( anyNaN, mkOR1( is_NaN( Ity_I64, frA_I64 ),
17873 is_NaN(Ity_I64, frB_I64 ) ) );
17874 #define MINUS_ZERO 0x8000000000000000ULL
17876 return IRExpr_ITE( /* If both arguments are zero . . . */
17877 mkAND1( mkexpr( frA_isZero ), mkexpr( frB_isZero ) ),
17878 /* then: if frA is -0 and isMin==True, return -0;
17879 * else if frA is +0 and isMin==False; return +0;
17880 * otherwise, simply return frB. */
17881 IRExpr_ITE( binop( Iop_CmpEQ32,
17882 unop( Iop_64HIto32,
17883 mkexpr( frA_I64 ) ),
17884 mkU32( isMin ? 0x80000000 : 0 ) ),
17885 mkU64( isMin ? MINUS_ZERO : 0ULL ),
17886 mkexpr( frB_I64 ) ),
17887 /* else: check if either input is a NaN*/
17888 IRExpr_ITE( mkexpr( anyNaN ),
17889 /* then: use "NaN helper" */
17890 _get_maxmin_fp_NaN( frA_I64, frB_I64 ),
17891 /* else: use "comparison helper" */
17892 _get_maxmin_fp_cmp( frB_I64, frA_I64, isMin ) ));
17895 static const HChar * _get_vsx_rdpi_suffix(UInt opc2)
17897 switch (opc2 & 0x7F) {
17898 case 0x72:
17899 return "m";
17900 case 0x52:
17901 return "p";
17902 case 0x56:
17903 return "c";
17904 case 0x32:
17905 return "z";
17906 case 0x12:
17907 return "";
17909 default: // Impossible to get here
17910 vex_printf("Unrecognized opcode %x\n", opc2);
17911 vpanic("_get_vsx_rdpi_suffix(ppc)(opc2)");
17916 * Helper function for vector/scalar double precision fp round to integer instructions.
17918 static IRExpr * _do_vsx_fp_roundToInt(IRTemp frB_I64, UInt opc2)
17921 /* The same rules apply for x{s|v}rdpi{m|p|c|z} as for floating point round operations (fri{m|n|p|z}). */
17922 IRTemp frB = newTemp(Ity_F64);
17923 IRTemp frD = newTemp(Ity_F64);
17924 IRTemp intermediateResult = newTemp(Ity_I64);
17925 IRTemp is_SNAN = newTemp(Ity_I1);
17926 IRExpr * hi32;
17927 IRExpr * rxpi_rm;
17928 switch (opc2 & 0x7F) {
17929 case 0x72:
17930 rxpi_rm = mkU32(Irrm_NegINF);
17931 break;
17932 case 0x52:
17933 rxpi_rm = mkU32(Irrm_PosINF);
17934 break;
17935 case 0x56:
17936 rxpi_rm = get_IR_roundingmode();
17937 break;
17938 case 0x32:
17939 rxpi_rm = mkU32(Irrm_ZERO);
17940 break;
17941 case 0x12:
17942 rxpi_rm = mkU32(Irrm_NEAREST);
17943 break;
17945 default: // Impossible to get here
17946 vex_printf("Unrecognized opcode %x\n", opc2);
17947 vpanic("_do_vsx_fp_roundToInt(ppc)(opc2)");
17949 assign(frB, unop(Iop_ReinterpI64asF64, mkexpr(frB_I64)));
17950 assign( intermediateResult,
17951 binop( Iop_F64toI64S, rxpi_rm,
17952 mkexpr( frB ) ) );
17954 /* don't use the rounded integer if frB is outside -9e18..9e18 */
17955 /* F64 has only log10(2**52) significant digits anyway */
17956 /* need to preserve sign of zero */
17957 /* frD = (fabs(frB) > 9e18) ? frB :
17958 (sign(frB)) ? -fabs((double)intermediateResult) : (double)intermediateResult */
17959 assign( frD,
17960 IRExpr_ITE(
17961 binop( Iop_CmpNE8,
17962 unop( Iop_32to8,
17963 binop( Iop_CmpF64,
17964 IRExpr_Const( IRConst_F64( 9e18 ) ),
17965 unop( Iop_AbsF64, mkexpr( frB ) ) ) ),
17966 mkU8(0) ),
17967 mkexpr( frB ),
17968 IRExpr_ITE(
17969 binop( Iop_CmpNE32,
17970 binop( Iop_Shr32,
17971 unop( Iop_64HIto32,
17972 mkexpr( frB_I64 ) ),
17973 mkU8( 31 ) ),
17974 mkU32(0) ),
17975 unop( Iop_NegF64,
17976 unop( Iop_AbsF64,
17977 binop( Iop_I64StoF64,
17978 mkU32( 0 ),
17979 mkexpr( intermediateResult ) ) ) ),
17980 binop( Iop_I64StoF64,
17981 mkU32( 0 ),
17982 mkexpr( intermediateResult ) )
17987 /* See Appendix "Floating-Point Round to Integer Model" in ISA doc.
17988 * If frB is a SNAN, then frD <- frB, with bit 12 set to '1'.
17990 #define SNAN_MASK 0x0008000000000000ULL
17991 hi32 = unop( Iop_64HIto32, mkexpr(frB_I64) );
17992 assign( is_SNAN,
17993 mkAND1( is_NaN( Ity_I64, frB_I64 ),
17994 binop( Iop_CmpEQ32,
17995 binop( Iop_And32, hi32, mkU32( 0x00080000 ) ),
17996 mkU32( 0 ) ) ) );
17998 return IRExpr_ITE( mkexpr( is_SNAN ),
17999 unop( Iop_ReinterpI64asF64,
18000 binop( Iop_Xor64,
18001 mkU64( SNAN_MASK ),
18002 mkexpr( frB_I64 ) ) ),
18003 mkexpr( frD ));
18007 * Miscellaneous VSX vector instructions
18009 static Bool
18010 dis_vxv_misc ( UInt theInstr, UInt opc2 )
18012 /* XX3-Form */
18013 UChar opc1 = ifieldOPC( theInstr );
18014 UChar XT = ifieldRegXT( theInstr );
18015 UChar XB = ifieldRegXB( theInstr );
18017 if (opc1 != 0x3C) {
18018 vex_printf( "dis_vxv_misc(ppc)(instr)\n" );
18019 return False;
18022 switch (opc2) {
18023 case 0x1B4: // xvredp (VSX Vector Reciprocal Estimate Double-Precision)
18024 case 0x194: // xvrsqrtedp (VSX Vector Reciprocal Square Root Estimate
18025 // Double-Precision)
18027 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
18028 IRExpr* rm = get_IR_roundingmode();
18029 IRTemp frB = newTemp(Ity_I64);
18030 IRTemp frB2 = newTemp(Ity_I64);
18031 Bool redp = opc2 == 0x1B4;
18032 IRTemp sqrtHi = newTemp(Ity_F64);
18033 IRTemp sqrtLo = newTemp(Ity_F64);
18034 assign(frB, unop(Iop_V128HIto64, getVSReg( XB )));
18035 assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
18037 DIP("%s v%d,v%d\n", redp ? "xvredp" : "xvrsqrtedp", XT, XB);
18039 if (!redp) {
18040 assign( sqrtHi,
18041 binop( Iop_SqrtF64,
18043 unop( Iop_ReinterpI64asF64, mkexpr( frB ) ) ) );
18044 assign( sqrtLo,
18045 binop( Iop_SqrtF64,
18047 unop( Iop_ReinterpI64asF64, mkexpr( frB2 ) ) ) );
18049 putVSReg( XT,
18050 binop( Iop_64HLtoV128,
18051 unop( Iop_ReinterpF64asI64,
18052 triop( Iop_DivF64,
18054 ieee_one,
18055 redp ? unop( Iop_ReinterpI64asF64,
18056 mkexpr( frB ) )
18057 : mkexpr( sqrtHi ) ) ),
18058 unop( Iop_ReinterpF64asI64,
18059 triop( Iop_DivF64,
18061 ieee_one,
18062 redp ? unop( Iop_ReinterpI64asF64,
18063 mkexpr( frB2 ) )
18064 : mkexpr( sqrtLo ) ) ) ) );
18065 break;
18068 case 0x134: // xvresp (VSX Vector Reciprocal Estimate Single-Precision)
18069 case 0x114: // xvrsqrtesp (VSX Vector Reciprocal Square Root Estimate Single-Precision)
18071 IRTemp b3, b2, b1, b0;
18072 IRTemp res0 = newTemp(Ity_I32);
18073 IRTemp res1 = newTemp(Ity_I32);
18074 IRTemp res2 = newTemp(Ity_I32);
18075 IRTemp res3 = newTemp(Ity_I32);
18076 IRTemp sqrt3 = newTemp(Ity_F64);
18077 IRTemp sqrt2 = newTemp(Ity_F64);
18078 IRTemp sqrt1 = newTemp(Ity_F64);
18079 IRTemp sqrt0 = newTemp(Ity_F64);
18080 IRExpr* rm = get_IR_roundingmode();
18081 Bool resp = opc2 == 0x134;
18083 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
18085 b3 = b2 = b1 = b0 = IRTemp_INVALID;
18086 DIP("%s v%d,v%d\n", resp ? "xvresp" : "xvrsqrtesp", XT, XB);
18087 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
18089 if (!resp) {
18090 assign( sqrt3, binop( Iop_SqrtF64, rm, mkexpr( b3 ) ) );
18091 assign( sqrt2, binop( Iop_SqrtF64, rm, mkexpr( b2 ) ) );
18092 assign( sqrt1, binop( Iop_SqrtF64, rm, mkexpr( b1 ) ) );
18093 assign( sqrt0, binop( Iop_SqrtF64, rm, mkexpr( b0 ) ) );
18096 assign( res0,
18097 unop( Iop_ReinterpF32asI32,
18098 unop( Iop_TruncF64asF32,
18099 triop( Iop_DivF64r32,
18101 ieee_one,
18102 resp ? mkexpr( b0 ) : mkexpr( sqrt0 ) ) ) ) );
18103 assign( res1,
18104 unop( Iop_ReinterpF32asI32,
18105 unop( Iop_TruncF64asF32,
18106 triop( Iop_DivF64r32,
18108 ieee_one,
18109 resp ? mkexpr( b1 ) : mkexpr( sqrt1 ) ) ) ) );
18110 assign( res2,
18111 unop( Iop_ReinterpF32asI32,
18112 unop( Iop_TruncF64asF32,
18113 triop( Iop_DivF64r32,
18115 ieee_one,
18116 resp ? mkexpr( b2 ) : mkexpr( sqrt2 ) ) ) ) );
18117 assign( res3,
18118 unop( Iop_ReinterpF32asI32,
18119 unop( Iop_TruncF64asF32,
18120 triop( Iop_DivF64r32,
18122 ieee_one,
18123 resp ? mkexpr( b3 ) : mkexpr( sqrt3 ) ) ) ) );
18124 putVSReg( XT,
18125 binop( Iop_64HLtoV128,
18126 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
18127 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
18128 break;
18130 case 0x300: // xvmaxsp (VSX Vector Maximum Single-Precision)
18131 case 0x320: // xvminsp (VSX Vector Minimum Single-Precision)
18133 UChar XA = ifieldRegXA( theInstr );
18134 IRTemp a3, a2, a1, a0;
18135 IRTemp b3, b2, b1, b0;
18136 IRTemp res0 = newTemp( Ity_I32 );
18137 IRTemp res1 = newTemp( Ity_I32 );
18138 IRTemp res2 = newTemp( Ity_I32 );
18139 IRTemp res3 = newTemp( Ity_I32 );
18140 IRTemp a0_I64 = newTemp( Ity_I64 );
18141 IRTemp a1_I64 = newTemp( Ity_I64 );
18142 IRTemp a2_I64 = newTemp( Ity_I64 );
18143 IRTemp a3_I64 = newTemp( Ity_I64 );
18144 IRTemp b0_I64 = newTemp( Ity_I64 );
18145 IRTemp b1_I64 = newTemp( Ity_I64 );
18146 IRTemp b2_I64 = newTemp( Ity_I64 );
18147 IRTemp b3_I64 = newTemp( Ity_I64 );
18149 Bool isMin = opc2 == 0x320 ? True : False;
18151 a3 = a2 = a1 = a0 = IRTemp_INVALID;
18152 b3 = b2 = b1 = b0 = IRTemp_INVALID;
18153 DIP("%s v%d,v%d v%d\n", isMin ? "xvminsp" : "xvmaxsp", XT, XA, XB);
18154 breakV128to4xF64( getVSReg( XA ), &a3, &a2, &a1, &a0 );
18155 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
18156 assign( a0_I64, unop( Iop_ReinterpF64asI64, mkexpr( a0 ) ) );
18157 assign( b0_I64, unop( Iop_ReinterpF64asI64, mkexpr( b0 ) ) );
18158 assign( a1_I64, unop( Iop_ReinterpF64asI64, mkexpr( a1 ) ) );
18159 assign( b1_I64, unop( Iop_ReinterpF64asI64, mkexpr( b1 ) ) );
18160 assign( a2_I64, unop( Iop_ReinterpF64asI64, mkexpr( a2 ) ) );
18161 assign( b2_I64, unop( Iop_ReinterpF64asI64, mkexpr( b2 ) ) );
18162 assign( a3_I64, unop( Iop_ReinterpF64asI64, mkexpr( a3 ) ) );
18163 assign( b3_I64, unop( Iop_ReinterpF64asI64, mkexpr( b3 ) ) );
18164 assign( res0,
18165 unop( Iop_ReinterpF32asI32,
18166 unop( Iop_TruncF64asF32,
18167 unop( Iop_ReinterpI64asF64,
18168 get_max_min_fp( a0_I64, b0_I64, isMin ) ) ) ) );
18169 assign( res1,
18170 unop( Iop_ReinterpF32asI32,
18171 unop( Iop_TruncF64asF32,
18172 unop( Iop_ReinterpI64asF64,
18173 get_max_min_fp( a1_I64, b1_I64, isMin ) ) ) ) );
18174 assign( res2,
18175 unop( Iop_ReinterpF32asI32,
18176 unop( Iop_TruncF64asF32,
18177 unop( Iop_ReinterpI64asF64,
18178 get_max_min_fp( a2_I64, b2_I64, isMin ) ) ) ) );
18179 assign( res3,
18180 unop( Iop_ReinterpF32asI32,
18181 unop( Iop_TruncF64asF32,
18182 unop( Iop_ReinterpI64asF64,
18183 get_max_min_fp( a3_I64, b3_I64, isMin ) ) ) ) );
18184 putVSReg( XT,
18185 binop( Iop_64HLtoV128,
18186 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
18187 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
18188 break;
18190 case 0x380: // xvmaxdp (VSX Vector Maximum Double-Precision)
18191 case 0x3A0: // xvmindp (VSX Vector Minimum Double-Precision)
18193 UChar XA = ifieldRegXA( theInstr );
18194 IRTemp frA = newTemp(Ity_I64);
18195 IRTemp frB = newTemp(Ity_I64);
18196 IRTemp frA2 = newTemp(Ity_I64);
18197 IRTemp frB2 = newTemp(Ity_I64);
18198 Bool isMin = opc2 == 0x3A0 ? True : False;
18200 assign(frA, unop(Iop_V128HIto64, getVSReg( XA )));
18201 assign(frB, unop(Iop_V128HIto64, getVSReg( XB )));
18202 assign(frA2, unop(Iop_V128to64, getVSReg( XA )));
18203 assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
18204 DIP("%s v%d,v%d v%d\n", isMin ? "xvmindp" : "xvmaxdp", XT, XA, XB);
18205 putVSReg( XT, binop( Iop_64HLtoV128, get_max_min_fp(frA, frB, isMin), get_max_min_fp(frA2, frB2, isMin) ) );
18207 break;
18209 case 0x3c0: // xvcpsgndp (VSX Vector Copy Sign Double-Precision)
18211 UChar XA = ifieldRegXA( theInstr );
18212 IRTemp frA = newTemp(Ity_I64);
18213 IRTemp frB = newTemp(Ity_I64);
18214 IRTemp frA2 = newTemp(Ity_I64);
18215 IRTemp frB2 = newTemp(Ity_I64);
18216 assign(frA, unop(Iop_V128HIto64, getVSReg( XA )));
18217 assign(frB, unop(Iop_V128HIto64, getVSReg( XB )));
18218 assign(frA2, unop(Iop_V128to64, getVSReg( XA )));
18219 assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
18221 DIP("xvcpsgndp v%d,v%d,v%d\n", XT, XA, XB);
18222 putVSReg( XT,
18223 binop( Iop_64HLtoV128,
18224 binop( Iop_Or64,
18225 binop( Iop_And64,
18226 mkexpr( frA ),
18227 mkU64( SIGN_BIT ) ),
18228 binop( Iop_And64,
18229 mkexpr( frB ),
18230 mkU64( SIGN_MASK ) ) ),
18231 binop( Iop_Or64,
18232 binop( Iop_And64,
18233 mkexpr( frA2 ),
18234 mkU64( SIGN_BIT ) ),
18235 binop( Iop_And64,
18236 mkexpr( frB2 ),
18237 mkU64( SIGN_MASK ) ) ) ) );
18238 break;
18240 case 0x340: // xvcpsgnsp
18242 UChar XA = ifieldRegXA( theInstr );
18243 IRTemp a3_I64, a2_I64, a1_I64, a0_I64;
18244 IRTemp b3_I64, b2_I64, b1_I64, b0_I64;
18245 IRTemp resHi = newTemp(Ity_I64);
18246 IRTemp resLo = newTemp(Ity_I64);
18248 a3_I64 = a2_I64 = a1_I64 = a0_I64 = IRTemp_INVALID;
18249 b3_I64 = b2_I64 = b1_I64 = b0_I64 = IRTemp_INVALID;
18250 DIP("xvcpsgnsp v%d,v%d v%d\n",XT, XA, XB);
18251 breakV128to4x64U( getVSReg( XA ), &a3_I64, &a2_I64, &a1_I64, &a0_I64 );
18252 breakV128to4x64U( getVSReg( XB ), &b3_I64, &b2_I64, &b1_I64, &b0_I64 );
18254 assign( resHi,
18255 binop( Iop_32HLto64,
18256 binop( Iop_Or32,
18257 binop( Iop_And32,
18258 unop(Iop_64to32, mkexpr( a3_I64 ) ),
18259 mkU32( SIGN_BIT32 ) ),
18260 binop( Iop_And32,
18261 unop(Iop_64to32, mkexpr( b3_I64 ) ),
18262 mkU32( SIGN_MASK32) ) ),
18264 binop( Iop_Or32,
18265 binop( Iop_And32,
18266 unop(Iop_64to32, mkexpr( a2_I64 ) ),
18267 mkU32( SIGN_BIT32 ) ),
18268 binop( Iop_And32,
18269 unop(Iop_64to32, mkexpr( b2_I64 ) ),
18270 mkU32( SIGN_MASK32 ) ) ) ) );
18271 assign( resLo,
18272 binop( Iop_32HLto64,
18273 binop( Iop_Or32,
18274 binop( Iop_And32,
18275 unop(Iop_64to32, mkexpr( a1_I64 ) ),
18276 mkU32( SIGN_BIT32 ) ),
18277 binop( Iop_And32,
18278 unop(Iop_64to32, mkexpr( b1_I64 ) ),
18279 mkU32( SIGN_MASK32 ) ) ),
18281 binop( Iop_Or32,
18282 binop( Iop_And32,
18283 unop(Iop_64to32, mkexpr( a0_I64 ) ),
18284 mkU32( SIGN_BIT32 ) ),
18285 binop( Iop_And32,
18286 unop(Iop_64to32, mkexpr( b0_I64 ) ),
18287 mkU32( SIGN_MASK32 ) ) ) ) );
18288 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( resHi ), mkexpr( resLo ) ) );
18289 break;
18291 case 0x3B2: // xvabsdp (VSX Vector Absolute Value Double-Precision)
18292 case 0x3D2: // xvnabsdp VSX Vector Negative Absolute Value Double-Precision)
18294 IRTemp frB = newTemp(Ity_F64);
18295 IRTemp frB2 = newTemp(Ity_F64);
18296 IRTemp abs_resultHi = newTemp(Ity_F64);
18297 IRTemp abs_resultLo = newTemp(Ity_F64);
18298 Bool make_negative = (opc2 == 0x3D2) ? True : False;
18299 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
18300 assign(frB2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg(XB))));
18302 DIP("xv%sabsdp v%d,v%d\n", make_negative ? "n" : "", XT, XB);
18303 if (make_negative) {
18304 assign(abs_resultHi, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr( frB ) ) ) );
18305 assign(abs_resultLo, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr( frB2 ) ) ) );
18307 } else {
18308 assign(abs_resultHi, unop( Iop_AbsF64, mkexpr( frB ) ) );
18309 assign(abs_resultLo, unop( Iop_AbsF64, mkexpr( frB2 ) ) );
18311 putVSReg( XT, binop( Iop_64HLtoV128,
18312 unop( Iop_ReinterpF64asI64, mkexpr( abs_resultHi ) ),
18313 unop( Iop_ReinterpF64asI64, mkexpr( abs_resultLo ) ) ) );
18314 break;
18316 case 0x332: // xvabssp (VSX Vector Absolute Value Single-Precision)
18317 case 0x352: // xvnabssp (VSX Vector Negative Absolute Value Single-Precision)
18320 * The Iop_AbsF32 IRop is not implemented for ppc64 since, up until introduction
18321 * of xvabssp, there has not been an abs(sp) type of instruction. But since emulation
18322 * of this function is so easy using shifts, I choose to emulate this instruction that
18323 * way versus a native instruction method of implementation.
18325 Bool make_negative = (opc2 == 0x352) ? True : False;
18326 IRTemp shiftVector = newTemp(Ity_V128);
18327 IRTemp absVal_vector = newTemp(Ity_V128);
18328 assign( shiftVector,
18329 binop( Iop_64HLtoV128,
18330 binop( Iop_32HLto64, mkU32( 1 ), mkU32( 1 ) ),
18331 binop( Iop_32HLto64, mkU32( 1 ), mkU32( 1 ) ) ) );
18332 assign( absVal_vector,
18333 binop( Iop_Shr32x4,
18334 binop( Iop_Shl32x4,
18335 getVSReg( XB ),
18336 mkexpr( shiftVector ) ),
18337 mkexpr( shiftVector ) ) );
18338 if (make_negative) {
18339 IRTemp signBit_vector = newTemp(Ity_V128);
18340 assign( signBit_vector,
18341 binop( Iop_64HLtoV128,
18342 binop( Iop_32HLto64,
18343 mkU32( 0x80000000 ),
18344 mkU32( 0x80000000 ) ),
18345 binop( Iop_32HLto64,
18346 mkU32( 0x80000000 ),
18347 mkU32( 0x80000000 ) ) ) );
18348 putVSReg( XT,
18349 binop( Iop_OrV128,
18350 mkexpr( absVal_vector ),
18351 mkexpr( signBit_vector ) ) );
18352 } else {
18353 putVSReg( XT, mkexpr( absVal_vector ) );
18355 break;
18357 case 0x372: // xvnegsp (VSX Vector Negate Single-Precision)
18359 IRTemp B0 = newTemp(Ity_I32);
18360 IRTemp B1 = newTemp(Ity_I32);
18361 IRTemp B2 = newTemp(Ity_I32);
18362 IRTemp B3 = newTemp(Ity_I32);
18364 DIP("xvnegsp v%d,v%d\n", XT, XB);
18366 /* Don't support NegF32, so just XOR the sign bit in the int value */
18367 assign(B0, unop( Iop_64HIto32,
18368 unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
18369 assign(B1, unop( Iop_64to32,
18370 unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
18371 assign(B2, unop( Iop_64HIto32,
18372 unop( Iop_V128to64, getVSReg( XB ) ) ) );
18373 assign(B3, unop( Iop_64to32,
18374 unop( Iop_V128to64, getVSReg( XB ) ) ) );
18376 putVSReg( XT,
18377 binop( Iop_64HLtoV128,
18378 binop( Iop_32HLto64,
18379 binop( Iop_Xor32, mkexpr( B0 ), mkU32( 0x80000000 ) ),
18380 binop( Iop_Xor32, mkexpr( B1 ), mkU32( 0x80000000 ) ) ),
18381 binop( Iop_32HLto64,
18382 binop( Iop_Xor32, mkexpr( B2 ), mkU32( 0x80000000 ) ),
18383 binop( Iop_Xor32, mkexpr( B3 ), mkU32( 0x80000000 ) ) ) ) );
18384 break;
18386 case 0x3F2: // xvnegdp (VSX Vector Negate Double-Precision)
18388 IRTemp frB = newTemp(Ity_F64);
18389 IRTemp frB2 = newTemp(Ity_F64);
18390 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
18391 assign(frB2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg(XB))));
18392 DIP("xvnegdp v%d,v%d\n", XT, XB);
18393 putVSReg( XT,
18394 binop( Iop_64HLtoV128,
18395 unop( Iop_ReinterpF64asI64,
18396 unop( Iop_NegF64, mkexpr( frB ) ) ),
18397 unop( Iop_ReinterpF64asI64,
18398 unop( Iop_NegF64, mkexpr( frB2 ) ) ) ) );
18399 break;
18401 case 0x192: // xvrdpi (VSX Vector Round to Double-Precision Integer using round toward Nearest Away)
18402 case 0x1D6: // xvrdpic (VSX Vector Round to Double-Precision Integer using Current rounding mode)
18403 case 0x1F2: // xvrdpim (VSX Vector Round to Double-Precision Integer using round toward -Infinity)
18404 case 0x1D2: // xvrdpip (VSX Vector Round to Double-Precision Integer using round toward +Infinity)
18405 case 0x1B2: // xvrdpiz (VSX Vector Round to Double-Precision Integer using round toward Zero)
18407 IRTemp frBHi_I64 = newTemp(Ity_I64);
18408 IRTemp frBLo_I64 = newTemp(Ity_I64);
18409 IRExpr * frD_fp_roundHi = NULL;
18410 IRExpr * frD_fp_roundLo = NULL;
18412 assign( frBHi_I64, unop( Iop_V128HIto64, getVSReg( XB ) ) );
18413 frD_fp_roundHi = _do_vsx_fp_roundToInt(frBHi_I64, opc2);
18414 assign( frBLo_I64, unop( Iop_V128to64, getVSReg( XB ) ) );
18415 frD_fp_roundLo = _do_vsx_fp_roundToInt(frBLo_I64, opc2);
18417 DIP("xvrdpi%s v%d,v%d\n", _get_vsx_rdpi_suffix(opc2), XT, XB);
18418 putVSReg( XT,
18419 binop( Iop_64HLtoV128,
18420 unop( Iop_ReinterpF64asI64, frD_fp_roundHi ),
18421 unop( Iop_ReinterpF64asI64, frD_fp_roundLo ) ) );
18422 break;
18424 case 0x112: // xvrspi (VSX Vector Round to Single-Precision Integer using round toward Nearest Away)
18425 case 0x156: // xvrspic (VSX Vector Round to SinglePrecision Integer using Current rounding mode)
18426 case 0x172: // xvrspim (VSX Vector Round to SinglePrecision Integer using round toward -Infinity)
18427 case 0x152: // xvrspip (VSX Vector Round to SinglePrecision Integer using round toward +Infinity)
18428 case 0x132: // xvrspiz (VSX Vector Round to SinglePrecision Integer using round toward Zero)
18430 const HChar * insn_suffix = NULL;
18431 IROp op;
18432 if (opc2 != 0x156) {
18433 // Use pre-defined IRop's for vrfi{m|n|p|z}
18434 switch (opc2) {
18435 case 0x112:
18436 insn_suffix = "";
18437 op = Iop_RoundF32x4_RN;
18438 break;
18439 case 0x172:
18440 insn_suffix = "m";
18441 op = Iop_RoundF32x4_RM;
18442 break;
18443 case 0x152:
18444 insn_suffix = "p";
18445 op = Iop_RoundF32x4_RP;
18446 break;
18447 case 0x132:
18448 insn_suffix = "z";
18449 op = Iop_RoundF32x4_RZ;
18450 break;
18452 default:
18453 vex_printf("Unrecognized opcode %x\n", opc2);
18454 vpanic("dis_vxv_misc(ppc)(vrspi<x>)(opc2)\n");
18456 DIP("xvrspi%s v%d,v%d\n", insn_suffix, XT, XB);
18457 putVSReg( XT, unop( op, getVSReg(XB) ) );
18458 } else {
18459 // Handle xvrspic. Unfortunately there is no corresponding "vfric" instruction.
18460 IRExpr * frD_fp_roundb3, * frD_fp_roundb2, * frD_fp_roundb1, * frD_fp_roundb0;
18461 IRTemp b3_F64, b2_F64, b1_F64, b0_F64;
18462 IRTemp b3_I64 = newTemp(Ity_I64);
18463 IRTemp b2_I64 = newTemp(Ity_I64);
18464 IRTemp b1_I64 = newTemp(Ity_I64);
18465 IRTemp b0_I64 = newTemp(Ity_I64);
18467 b3_F64 = b2_F64 = b1_F64 = b0_F64 = IRTemp_INVALID;
18468 frD_fp_roundb3 = frD_fp_roundb2 = frD_fp_roundb1 = frD_fp_roundb0 = NULL;
18469 breakV128to4xF64( getVSReg(XB), &b3_F64, &b2_F64, &b1_F64, &b0_F64);
18470 assign(b3_I64, unop(Iop_ReinterpF64asI64, mkexpr(b3_F64)));
18471 assign(b2_I64, unop(Iop_ReinterpF64asI64, mkexpr(b2_F64)));
18472 assign(b1_I64, unop(Iop_ReinterpF64asI64, mkexpr(b1_F64)));
18473 assign(b0_I64, unop(Iop_ReinterpF64asI64, mkexpr(b0_F64)));
18474 frD_fp_roundb3 = unop(Iop_TruncF64asF32,
18475 _do_vsx_fp_roundToInt(b3_I64, opc2));
18476 frD_fp_roundb2 = unop(Iop_TruncF64asF32,
18477 _do_vsx_fp_roundToInt(b2_I64, opc2));
18478 frD_fp_roundb1 = unop(Iop_TruncF64asF32,
18479 _do_vsx_fp_roundToInt(b1_I64, opc2));
18480 frD_fp_roundb0 = unop(Iop_TruncF64asF32,
18481 _do_vsx_fp_roundToInt(b0_I64, opc2));
18482 DIP("xvrspic v%d,v%d\n", XT, XB);
18483 putVSReg( XT,
18484 binop( Iop_64HLtoV128,
18485 binop( Iop_32HLto64,
18486 unop( Iop_ReinterpF32asI32, frD_fp_roundb3 ),
18487 unop( Iop_ReinterpF32asI32, frD_fp_roundb2 ) ),
18488 binop( Iop_32HLto64,
18489 unop( Iop_ReinterpF32asI32, frD_fp_roundb1 ),
18490 unop( Iop_ReinterpF32asI32, frD_fp_roundb0 ) ) ) );
18492 break;
18495 default:
18496 vex_printf( "dis_vxv_misc(ppc)(opc2)\n" );
18497 return False;
18499 return True;
18504 * VSX Scalar Floating Point Arithmetic Instructions
18506 static Bool
18507 dis_vxs_arith ( UInt theInstr, UInt opc2 )
18509 /* XX3-Form */
18510 UChar opc1 = ifieldOPC( theInstr );
18511 UChar XT = ifieldRegXT( theInstr );
18512 UChar XA = ifieldRegXA( theInstr );
18513 UChar XB = ifieldRegXB( theInstr );
18514 IRExpr* rm = get_IR_roundingmode();
18515 IRTemp frA = newTemp(Ity_F64);
18516 IRTemp frB = newTemp(Ity_F64);
18518 if (opc1 != 0x3C) {
18519 vex_printf( "dis_vxs_arith(ppc)(instr)\n" );
18520 return False;
18523 assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
18524 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
18526 /* For all the VSX sclar arithmetic instructions, the contents of doubleword element 1
18527 * of VSX[XT] are undefined after the operation; therefore, we can simply set
18528 * element to zero where it makes sense to do so.
18530 switch (opc2) {
18531 case 0x000: // xsaddsp (VSX Scalar Add Single-Precision)
18532 DIP("xsaddsp v%d,v%d,v%d\n", XT, XA, XB);
18533 putVSReg( XT, binop( Iop_64HLtoV128,
18534 unop( Iop_ReinterpF64asI64,
18535 binop( Iop_RoundF64toF32, rm,
18536 triop( Iop_AddF64, rm,
18537 mkexpr( frA ),
18538 mkexpr( frB ) ) ) ),
18539 mkU64( 0 ) ) );
18540 break;
18541 case 0x020: // xssubsp (VSX Scalar Subtract Single-Precision)
18542 DIP("xssubsp v%d,v%d,v%d\n", XT, XA, XB);
18543 putVSReg( XT, binop( Iop_64HLtoV128,
18544 unop( Iop_ReinterpF64asI64,
18545 binop( Iop_RoundF64toF32, rm,
18546 triop( Iop_SubF64, rm,
18547 mkexpr( frA ),
18548 mkexpr( frB ) ) ) ),
18549 mkU64( 0 ) ) );
18550 break;
18551 case 0x080: // xsadddp (VSX scalar add double-precision)
18552 DIP("xsadddp v%d,v%d,v%d\n", XT, XA, XB);
18553 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18554 triop( Iop_AddF64, rm,
18555 mkexpr( frA ),
18556 mkexpr( frB ) ) ),
18557 mkU64( 0 ) ) );
18558 break;
18559 case 0x060: // xsdivsp (VSX scalar divide single-precision)
18560 DIP("xsdivsp v%d,v%d,v%d\n", XT, XA, XB);
18561 putVSReg( XT, binop( Iop_64HLtoV128,
18562 unop( Iop_ReinterpF64asI64,
18563 binop( Iop_RoundF64toF32, rm,
18564 triop( Iop_DivF64, rm,
18565 mkexpr( frA ),
18566 mkexpr( frB ) ) ) ),
18567 mkU64( 0 ) ) );
18568 break;
18569 case 0x0E0: // xsdivdp (VSX scalar divide double-precision)
18570 DIP("xsdivdp v%d,v%d,v%d\n", XT, XA, XB);
18571 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18572 triop( Iop_DivF64, rm,
18573 mkexpr( frA ),
18574 mkexpr( frB ) ) ),
18575 mkU64( 0 ) ) );
18576 break;
18577 case 0x004: case 0x024: /* xsmaddasp, xsmaddmsp (VSX scalar multiply-add
18578 * single-precision)
18581 IRTemp frT = newTemp(Ity_F64);
18582 Bool mdp = opc2 == 0x024;
18583 DIP("xsmadd%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18584 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18585 getVSReg( XT ) ) ) );
18586 putVSReg( XT,
18587 binop( Iop_64HLtoV128,
18588 unop( Iop_ReinterpF64asI64,
18589 binop( Iop_RoundF64toF32, rm,
18590 qop( Iop_MAddF64, rm,
18591 mkexpr( frA ),
18592 mkexpr( mdp ? frT : frB ),
18593 mkexpr( mdp ? frB : frT ) ) ) ),
18594 mkU64( 0 ) ) );
18595 break;
18597 case 0x084: case 0x0A4: // xsmaddadp, xsmaddmdp (VSX scalar multiply-add double-precision)
18599 IRTemp frT = newTemp(Ity_F64);
18600 Bool mdp = opc2 == 0x0A4;
18601 DIP("xsmadd%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18602 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18603 getVSReg( XT ) ) ) );
18604 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18605 qop( Iop_MAddF64, rm,
18606 mkexpr( frA ),
18607 mkexpr( mdp ? frT : frB ),
18608 mkexpr( mdp ? frB : frT ) ) ),
18609 mkU64( 0 ) ) );
18610 break;
18612 case 0x044: case 0x064: /* xsmsubasp, xsmsubmsp (VSX scalar
18613 * multiply-subtract single-precision)
18616 IRTemp frT = newTemp(Ity_F64);
18617 Bool mdp = opc2 == 0x064;
18618 DIP("xsmsub%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18619 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18620 getVSReg( XT ) ) ) );
18621 putVSReg( XT,
18622 binop( Iop_64HLtoV128,
18623 unop( Iop_ReinterpF64asI64,
18624 binop( Iop_RoundF64toF32, rm,
18625 qop( Iop_MSubF64, rm,
18626 mkexpr( frA ),
18627 mkexpr( mdp ? frT : frB ),
18628 mkexpr( mdp ? frB : frT ) ) ) ),
18629 mkU64( 0 ) ) );
18630 break;
18632 case 0x0C4: case 0x0E4: // xsmsubadp, xsmsubmdp (VSX scalar multiply-subtract double-precision)
18634 IRTemp frT = newTemp(Ity_F64);
18635 Bool mdp = opc2 == 0x0E4;
18636 DIP("xsmsub%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18637 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18638 getVSReg( XT ) ) ) );
18639 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18640 qop( Iop_MSubF64, rm,
18641 mkexpr( frA ),
18642 mkexpr( mdp ? frT : frB ),
18643 mkexpr( mdp ? frB : frT ) ) ),
18644 mkU64( 0 ) ) );
18645 break;
18647 case 0x284: case 0x2A4: // xsnmaddadp, xsnmaddmdp (VSX scalar multiply-add double-precision)
18649 /* TODO: mpj -- Naturally, I expected to be able to leverage the implementation
18650 * of fnmadd and use pretty much the same code. However, that code has a bug in the
18651 * way it blindly negates the signbit, even if the floating point result is a NaN.
18652 * So, the TODO is to fix fnmadd (which I'll do in a different patch).
18653 * FIXED 7/1/2012: carll fnmadd and fnmsubs fixed to not negate sign
18654 * bit for NaN result.
18656 Bool mdp = opc2 == 0x2A4;
18657 IRTemp frT = newTemp(Ity_F64);
18658 IRTemp maddResult = newTemp(Ity_I64);
18660 DIP("xsnmadd%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18661 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18662 getVSReg( XT ) ) ) );
18663 assign( maddResult, unop( Iop_ReinterpF64asI64, qop( Iop_MAddF64, rm,
18664 mkexpr( frA ),
18665 mkexpr( mdp ? frT : frB ),
18666 mkexpr( mdp ? frB : frT ) ) ) );
18668 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( getNegatedResult(maddResult) ),
18669 mkU64( 0 ) ) );
18670 break;
18672 case 0x204: case 0x224: /* xsnmaddasp, xsnmaddmsp (VSX scalar
18673 * multiply-add single-precision)
18676 Bool mdp = opc2 == 0x224;
18677 IRTemp frT = newTemp(Ity_F64);
18678 IRTemp maddResult = newTemp(Ity_I64);
18680 DIP("xsnmadd%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18681 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18682 getVSReg( XT ) ) ) );
18683 assign( maddResult,
18684 unop( Iop_ReinterpF64asI64,
18685 binop( Iop_RoundF64toF32, rm,
18686 qop( Iop_MAddF64, rm,
18687 mkexpr( frA ),
18688 mkexpr( mdp ? frT : frB ),
18689 mkexpr( mdp ? frB : frT ) ) ) ) );
18691 putVSReg( XT, binop( Iop_64HLtoV128,
18692 mkexpr( getNegatedResult(maddResult) ),
18693 mkU64( 0 ) ) );
18694 break;
18696 case 0x244: case 0x264: /* xsnmsubasp, xsnmsubmsp (VSX Scalar Negative
18697 * Multiply-Subtract Single-Precision)
18700 IRTemp frT = newTemp(Ity_F64);
18701 Bool mdp = opc2 == 0x264;
18702 IRTemp msubResult = newTemp(Ity_I64);
18704 DIP("xsnmsub%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18705 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18706 getVSReg( XT ) ) ) );
18707 assign( msubResult,
18708 unop( Iop_ReinterpF64asI64,
18709 binop( Iop_RoundF64toF32, rm,
18710 qop( Iop_MSubF64, rm,
18711 mkexpr( frA ),
18712 mkexpr( mdp ? frT : frB ),
18713 mkexpr( mdp ? frB : frT ) ) ) ) );
18715 putVSReg( XT, binop( Iop_64HLtoV128,
18716 mkexpr( getNegatedResult(msubResult) ),
18717 mkU64( 0 ) ) );
18719 break;
18722 case 0x2C4: case 0x2E4: // xsnmsubadp, xsnmsubmdp (VSX Scalar Negative Multiply-Subtract Double-Precision)
18724 IRTemp frT = newTemp(Ity_F64);
18725 Bool mdp = opc2 == 0x2E4;
18726 IRTemp msubResult = newTemp(Ity_I64);
18728 DIP("xsnmsub%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18729 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18730 getVSReg( XT ) ) ) );
18731 assign(msubResult, unop( Iop_ReinterpF64asI64,
18732 qop( Iop_MSubF64,
18734 mkexpr( frA ),
18735 mkexpr( mdp ? frT : frB ),
18736 mkexpr( mdp ? frB : frT ) ) ));
18738 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( getNegatedResult(msubResult) ), mkU64( 0 ) ) );
18740 break;
18743 case 0x040: // xsmulsp (VSX Scalar Multiply Single-Precision)
18744 DIP("xsmulsp v%d,v%d,v%d\n", XT, XA, XB);
18745 putVSReg( XT, binop( Iop_64HLtoV128,
18746 unop( Iop_ReinterpF64asI64,
18747 binop( Iop_RoundF64toF32, rm,
18748 triop( Iop_MulF64, rm,
18749 mkexpr( frA ),
18750 mkexpr( frB ) ) ) ),
18751 mkU64( 0 ) ) );
18752 break;
18754 case 0x0C0: // xsmuldp (VSX Scalar Multiply Double-Precision)
18755 DIP("xsmuldp v%d,v%d,v%d\n", XT, XA, XB);
18756 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18757 triop( Iop_MulF64, rm,
18758 mkexpr( frA ),
18759 mkexpr( frB ) ) ),
18760 mkU64( 0 ) ) );
18761 break;
18762 case 0x0A0: // xssubdp (VSX Scalar Subtract Double-Precision)
18763 DIP("xssubdp v%d,v%d,v%d\n", XT, XA, XB);
18764 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18765 triop( Iop_SubF64, rm,
18766 mkexpr( frA ),
18767 mkexpr( frB ) ) ),
18768 mkU64( 0 ) ) );
18769 break;
18771 case 0x016: // xssqrtsp (VSX Scalar Square Root Single-Precision)
18772 DIP("xssqrtsp v%d,v%d\n", XT, XB);
18773 putVSReg( XT,
18774 binop( Iop_64HLtoV128,
18775 unop( Iop_ReinterpF64asI64,
18776 binop( Iop_RoundF64toF32, rm,
18777 binop( Iop_SqrtF64, rm,
18778 mkexpr( frB ) ) ) ),
18779 mkU64( 0 ) ) );
18780 break;
18782 case 0x096: // xssqrtdp (VSX Scalar Square Root Double-Precision)
18783 DIP("xssqrtdp v%d,v%d\n", XT, XB);
18784 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18785 binop( Iop_SqrtF64, rm,
18786 mkexpr( frB ) ) ),
18787 mkU64( 0 ) ) );
18788 break;
18790 case 0x0F4: // xstdivdp (VSX Scalar Test for software Divide Double-Precision)
18792 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
18793 IRTemp frA_I64 = newTemp(Ity_I64);
18794 IRTemp frB_I64 = newTemp(Ity_I64);
18795 DIP("xstdivdp crf%d,v%d,v%d\n", crfD, XA, XB);
18796 assign( frA_I64, unop( Iop_ReinterpF64asI64, mkexpr( frA ) ) );
18797 assign( frB_I64, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
18798 putGST_field( PPC_GST_CR, do_fp_tdiv(frA_I64, frB_I64), crfD );
18799 break;
18801 case 0x0D4: // xstsqrtdp (VSX Vector Test for software Square Root Double-Precision)
18803 IRTemp frB_I64 = newTemp(Ity_I64);
18804 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
18805 IRTemp flags = newTemp(Ity_I32);
18806 IRTemp fe_flag, fg_flag;
18807 fe_flag = fg_flag = IRTemp_INVALID;
18808 DIP("xstsqrtdp v%d,v%d\n", XT, XB);
18809 assign( frB_I64, unop(Iop_V128HIto64, getVSReg( XB )) );
18810 do_fp_tsqrt(frB_I64, False /*not single precision*/, &fe_flag, &fg_flag);
18811 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
18812 * where fl_flag == 1 on ppc64.
18814 assign( flags,
18815 binop( Iop_Or32,
18816 binop( Iop_Or32, mkU32( 8 ), // fl_flag
18817 binop( Iop_Shl32, mkexpr(fg_flag), mkU8( 2 ) ) ),
18818 binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) ) );
18819 putGST_field( PPC_GST_CR, mkexpr(flags), crfD );
18820 break;
18823 default:
18824 vex_printf( "dis_vxs_arith(ppc)(opc2)\n" );
18825 return False;
18828 return True;
18833 * VSX Floating Point Compare Instructions
18835 static Bool
18836 dis_vx_cmp( UInt theInstr, UInt opc2 )
18838 /* XX3-Form and XX2-Form */
18839 UChar opc1 = ifieldOPC( theInstr );
18840 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
18841 IRTemp ccPPC32;
18842 UChar XA = ifieldRegXA ( theInstr );
18843 UChar XB = ifieldRegXB ( theInstr );
18844 IRTemp frA = newTemp(Ity_F64);
18845 IRTemp frB = newTemp(Ity_F64);
18847 if (opc1 != 0x3C) {
18848 vex_printf( "dis_vx_cmp(ppc)(instr)\n" );
18849 return False;
18852 assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
18853 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
18854 switch (opc2) {
18855 case 0x08C: case 0x0AC: // xscmpudp, xscmpodp
18856 /* Note: Differences between xscmpudp and xscmpodp are only in
18857 * exception flag settings, which aren't supported anyway. */
18858 DIP("xscmp%sdp crf%d,fr%u,fr%u\n", opc2 == 0x08c ? "u" : "o",
18859 crfD, XA, XB);
18860 ccPPC32 = get_fp_cmp_CR_val( binop(Iop_CmpF64, mkexpr(frA), mkexpr(frB)));
18861 putGST_field( PPC_GST_CR, mkexpr(ccPPC32), crfD );
18862 putFPCC( mkexpr( ccPPC32 ) );
18863 break;
18865 default:
18866 vex_printf( "dis_vx_cmp(ppc)(opc2)\n" );
18867 return False;
18869 return True;
18872 static void
18873 do_vvec_fp_cmp ( IRTemp vA, IRTemp vB, UChar XT, UChar flag_rC,
18874 ppc_cmp_t cmp_type )
18876 IRTemp frA_hi = newTemp(Ity_F64);
18877 IRTemp frB_hi = newTemp(Ity_F64);
18878 IRTemp frA_lo = newTemp(Ity_F64);
18879 IRTemp frB_lo = newTemp(Ity_F64);
18880 IRTemp ccPPC32 = newTemp(Ity_I32);
18881 IRTemp ccIR_hi;
18882 IRTemp ccIR_lo;
18884 IRTemp hiResult = newTemp(Ity_I64);
18885 IRTemp loResult = newTemp(Ity_I64);
18886 IRTemp hiEQlo = newTemp(Ity_I1);
18887 IRTemp all_elem_true = newTemp(Ity_I32);
18888 IRTemp all_elem_false = newTemp(Ity_I32);
18890 assign(frA_hi, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, mkexpr( vA ))));
18891 assign(frB_hi, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, mkexpr( vB ))));
18892 assign(frA_lo, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, mkexpr( vA ))));
18893 assign(frB_lo, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, mkexpr( vB ))));
18895 ccIR_hi = get_fp_cmp_CR_val( binop( Iop_CmpF64,
18896 mkexpr( frA_hi ),
18897 mkexpr( frB_hi ) ) );
18898 ccIR_lo = get_fp_cmp_CR_val( binop( Iop_CmpF64,
18899 mkexpr( frA_lo ),
18900 mkexpr( frB_lo ) ) );
18902 if (cmp_type != PPC_CMP_GE) {
18903 assign( hiResult,
18904 unop( Iop_1Sto64,
18905 binop( Iop_CmpEQ32, mkexpr( ccIR_hi ), mkU32( cmp_type ) ) ) );
18906 assign( loResult,
18907 unop( Iop_1Sto64,
18908 binop( Iop_CmpEQ32, mkexpr( ccIR_lo ), mkU32( cmp_type ) ) ) );
18909 } else {
18910 // For PPC_CMP_GE, one element compare may return "4" (for "greater than") and
18911 // the other element compare may return "2" (for "equal to").
18912 IRTemp lo_GE = newTemp(Ity_I1);
18913 IRTemp hi_GE = newTemp(Ity_I1);
18915 assign(hi_GE, mkOR1( binop( Iop_CmpEQ32, mkexpr( ccIR_hi ), mkU32( 2 ) ),
18916 binop( Iop_CmpEQ32, mkexpr( ccIR_hi ), mkU32( 4 ) ) ) );
18917 assign( hiResult,unop( Iop_1Sto64, mkexpr( hi_GE ) ) );
18919 assign(lo_GE, mkOR1( binop( Iop_CmpEQ32, mkexpr( ccIR_lo ), mkU32( 2 ) ),
18920 binop( Iop_CmpEQ32, mkexpr( ccIR_lo ), mkU32( 4 ) ) ) );
18921 assign( loResult, unop( Iop_1Sto64, mkexpr( lo_GE ) ) );
18924 // The [hi/lo]Result will be all 1's or all 0's. We just look at the lower word.
18925 assign( hiEQlo,
18926 binop( Iop_CmpEQ32,
18927 unop( Iop_64to32, mkexpr( hiResult ) ),
18928 unop( Iop_64to32, mkexpr( loResult ) ) ) );
18929 putVSReg( XT,
18930 binop( Iop_64HLtoV128, mkexpr( hiResult ), mkexpr( loResult ) ) );
18932 assign( all_elem_true,
18933 unop( Iop_1Uto32,
18934 mkAND1( mkexpr( hiEQlo ),
18935 binop( Iop_CmpEQ32,
18936 mkU32( 0xffffffff ),
18937 unop( Iop_64to32,
18938 mkexpr( hiResult ) ) ) ) ) );
18940 assign( all_elem_false,
18941 unop( Iop_1Uto32,
18942 mkAND1( mkexpr( hiEQlo ),
18943 binop( Iop_CmpEQ32,
18944 mkU32( 0 ),
18945 unop( Iop_64to32,
18946 mkexpr( hiResult ) ) ) ) ) );
18947 assign( ccPPC32,
18948 binop( Iop_Or32,
18949 binop( Iop_Shl32, mkexpr( all_elem_false ), mkU8( 1 ) ),
18950 binop( Iop_Shl32, mkexpr( all_elem_true ), mkU8( 3 ) ) ) );
18952 if (flag_rC) {
18953 putGST_field( PPC_GST_CR, mkexpr(ccPPC32), 6 );
18958 * VSX Vector Compare Instructions
18960 static Bool
18961 dis_vvec_cmp( UInt theInstr, UInt opc2 )
18963 /* XX3-Form */
18964 UChar opc1 = ifieldOPC( theInstr );
18965 UChar XT = ifieldRegXT ( theInstr );
18966 UChar XA = ifieldRegXA ( theInstr );
18967 UChar XB = ifieldRegXB ( theInstr );
18968 UChar flag_rC = ifieldBIT10(theInstr);
18969 IRTemp vA = newTemp( Ity_V128 );
18970 IRTemp vB = newTemp( Ity_V128 );
18972 if (opc1 != 0x3C) {
18973 vex_printf( "dis_vvec_cmp(ppc)(instr)\n" );
18974 return False;
18977 assign( vA, getVSReg( XA ) );
18978 assign( vB, getVSReg( XB ) );
18980 switch (opc2) {
18981 case 0x18C: // xvcmpeqdp[.] (VSX Vector Compare Equal To Double-Precision [ & Record ])
18983 DIP("xvcmpeqdp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
18984 XT, XA, XB);
18985 do_vvec_fp_cmp(vA, vB, XT, flag_rC, PPC_CMP_EQ);
18986 break;
18989 case 0x1CC: // xvcmpgedp[.] (VSX Vector Compare Greater Than or Equal To Double-Precision [ & Record ])
18991 DIP("xvcmpgedp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
18992 XT, XA, XB);
18993 do_vvec_fp_cmp(vA, vB, XT, flag_rC, PPC_CMP_GE);
18994 break;
18997 case 0x1AC: // xvcmpgtdp[.] (VSX Vector Compare Greater Than Double-Precision [ & Record ])
18999 DIP("xvcmpgtdp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
19000 XT, XA, XB);
19001 do_vvec_fp_cmp(vA, vB, XT, flag_rC, PPC_CMP_GT);
19002 break;
19005 case 0x10C: // xvcmpeqsp[.] (VSX Vector Compare Equal To Single-Precision [ & Record ])
19007 IRTemp vD = newTemp(Ity_V128);
19009 DIP("xvcmpeqsp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
19010 XT, XA, XB);
19011 assign( vD, binop(Iop_CmpEQ32Fx4, mkexpr(vA), mkexpr(vB)) );
19012 putVSReg( XT, mkexpr(vD) );
19013 if (flag_rC) {
19014 set_AV_CR6( mkexpr(vD), True );
19016 break;
19019 case 0x14C: // xvcmpgesp[.] (VSX Vector Compare Greater Than or Equal To Single-Precision [ & Record ])
19021 IRTemp vD = newTemp(Ity_V128);
19023 DIP("xvcmpgesp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
19024 XT, XA, XB);
19025 assign( vD, binop(Iop_CmpGE32Fx4, mkexpr(vA), mkexpr(vB)) );
19026 putVSReg( XT, mkexpr(vD) );
19027 if (flag_rC) {
19028 set_AV_CR6( mkexpr(vD), True );
19030 break;
19033 case 0x12C: //xvcmpgtsp[.] (VSX Vector Compare Greater Than Single-Precision [ & Record ])
19035 IRTemp vD = newTemp(Ity_V128);
19037 DIP("xvcmpgtsp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
19038 XT, XA, XB);
19039 assign( vD, binop(Iop_CmpGT32Fx4, mkexpr(vA), mkexpr(vB)) );
19040 putVSReg( XT, mkexpr(vD) );
19041 if (flag_rC) {
19042 set_AV_CR6( mkexpr(vD), True );
19044 break;
19047 default:
19048 vex_printf( "dis_vvec_cmp(ppc)(opc2)\n" );
19049 return False;
19051 return True;
19054 * Miscellaneous VSX Scalar Instructions
19056 static Bool
19057 dis_vxs_misc( UInt theInstr, const VexAbiInfo* vbi, UInt opc2,
19058 int allow_isa_3_0 )
19060 #define VG_PPC_SIGN_MASK 0x7fffffffffffffffULL
19061 /* XX3-Form and XX2-Form */
19062 UChar opc1 = ifieldOPC( theInstr );
19063 UChar XT = ifieldRegXT ( theInstr );
19064 UChar XA = ifieldRegXA ( theInstr );
19065 UChar XB = ifieldRegXB ( theInstr );
19066 IRTemp vA = newTemp( Ity_V128 );
19067 IRTemp vB = newTemp( Ity_V128 );
19069 if (opc1 != 0x3C) {
19070 vex_printf( "dis_vxs_misc(ppc)(instr)\n" );
19071 return False;
19074 assign( vA, getVSReg( XA ) );
19075 assign( vB, getVSReg( XB ) );
19077 /* For all the VSX move instructions, the contents of doubleword element 1
19078 * of VSX[XT] are undefined after the operation; therefore, we can simply
19079 * move the entire array element where it makes sense to do so.
19081 if (( opc2 == 0x168 ) && ( IFIELD( theInstr, 19, 2 ) == 0 ) )
19083 /* Special case of XX1-Form with immediate value
19084 * xxspltib (VSX Vector Splat Immediate Byte)
19086 UInt uim = IFIELD( theInstr, 11, 8 );
19087 UInt word_value = ( uim << 24 ) | ( uim << 16 ) | ( uim << 8 ) | uim;
19089 DIP("xxspltib v%u,%u\n", (UInt)XT, uim);
19090 putVSReg(XT, binop( Iop_64HLtoV128,
19091 binop( Iop_32HLto64,
19092 mkU32( word_value ),
19093 mkU32( word_value ) ),
19094 binop( Iop_32HLto64,
19095 mkU32( word_value ),
19096 mkU32( word_value ) ) ) );
19097 return True;
19100 switch ( opc2 ) {
19101 case 0x0ec: // xscmpexpdp (VSX Scalar Compare Exponents Double-Precision)
19103 /* Compare 64-bit data, 128-bit layout:
19104 src1[0:63] is double word, src1[64:127] is unused
19105 src2[0:63] is double word, src2[64:127] is unused
19107 IRExpr *bit4, *bit5, *bit6, *bit7;
19108 UInt BF = IFIELD( theInstr, 23, 3 );
19109 IRTemp eq_lt_gt = newTemp( Ity_I32 );
19110 IRTemp CC = newTemp( Ity_I32 );
19111 IRTemp vA_hi = newTemp( Ity_I64 );
19112 IRTemp vB_hi = newTemp( Ity_I64 );
19113 IRExpr *mask = mkU64( 0x7FF0000000000000 );
19115 DIP("xscmpexpdp %u,v%u,v%u\n", BF, XA, XB);
19117 assign( vA_hi, unop( Iop_V128HIto64, mkexpr( vA ) ) );
19118 assign( vB_hi, unop( Iop_V128HIto64, mkexpr( vB ) ) );
19120 /* A exp < B exp */
19121 bit4 = binop( Iop_CmpLT64U,
19122 binop( Iop_And64,
19123 mkexpr( vA_hi ),
19124 mask ),
19125 binop( Iop_And64,
19126 mkexpr( vB_hi ),
19127 mask ) );
19128 /* A exp > B exp */
19129 bit5 = binop( Iop_CmpLT64U,
19130 binop( Iop_And64,
19131 mkexpr( vB_hi ),
19132 mask ),
19133 binop( Iop_And64,
19134 mkexpr( vA_hi ),
19135 mask ) );
19136 /* test equal */
19137 bit6 = binop( Iop_CmpEQ64,
19138 binop( Iop_And64,
19139 mkexpr( vA_hi ),
19140 mask ),
19141 binop( Iop_And64,
19142 mkexpr( vB_hi ),
19143 mask ) );
19145 /* exp A or exp B is NaN */
19146 bit7 = mkOR1( is_NaN( Ity_I64, vA_hi ),
19147 is_NaN( Ity_I64, vB_hi ) );
19149 assign( eq_lt_gt, binop( Iop_Or32,
19150 binop( Iop_Shl32,
19151 unop( Iop_1Uto32, bit4 ),
19152 mkU8( 3) ),
19153 binop( Iop_Or32,
19154 binop( Iop_Shl32,
19155 unop( Iop_1Uto32, bit5 ),
19156 mkU8( 2) ),
19157 binop( Iop_Shl32,
19158 unop( Iop_1Uto32, bit6 ),
19159 mkU8( 1 ) ) ) ) );
19160 assign(CC, binop( Iop_Or32,
19161 binop( Iop_And32,
19162 mkexpr( eq_lt_gt ) ,
19163 unop( Iop_Not32, unop( Iop_1Sto32, bit7 ) ) ),
19164 unop( Iop_1Uto32, bit7 ) ) );
19166 putGST_field( PPC_GST_CR, mkexpr( CC ), BF );
19167 putFPCC( mkexpr( CC ) );
19168 return True;
19170 break;
19172 case 0x14A: // xxextractuw (VSX Vector Extract Unsigned Word)
19174 UInt uim = IFIELD( theInstr, 16, 4 );
19176 DIP("xxextractuw v%u,v%u,%u\n", (UInt)XT, (UInt)XB, uim);
19178 putVSReg( XT,
19179 binop( Iop_ShlV128,
19180 binop( Iop_AndV128,
19181 binop( Iop_ShrV128,
19182 mkexpr( vB ),
19183 mkU8( ( 12 - uim ) * 8 ) ),
19184 binop(Iop_64HLtoV128,
19185 mkU64( 0 ),
19186 mkU64( 0xFFFFFFFF ) ) ),
19187 mkU8( ( 32*2 ) ) ) );
19188 break;
19190 case 0x16A: // xxinsertw (VSX Vector insert Word)
19192 UInt uim = IFIELD( theInstr, 16, 4 );
19193 IRTemp vT = newTemp( Ity_V128 );
19194 IRTemp tmp = newTemp( Ity_V128 );
19196 DIP("xxinsertw v%u,v%u,%u\n", (UInt)XT, (UInt)XB, uim);
19198 assign( vT, getVSReg( XT ) );
19199 assign( tmp, binop( Iop_AndV128,
19200 mkexpr( vT ),
19201 unop( Iop_NotV128,
19202 binop( Iop_ShlV128,
19203 binop( Iop_64HLtoV128,
19204 mkU64( 0x0 ),
19205 mkU64( 0xFFFFFFFF) ),
19206 mkU8( ( 12 - uim ) * 8 ) ) ) ) );
19208 putVSReg( XT,
19209 binop( Iop_OrV128,
19210 binop( Iop_ShlV128,
19211 binop( Iop_AndV128,
19212 binop( Iop_ShrV128,
19213 mkexpr( vB ),
19214 mkU8( 32 * 2 ) ),
19215 binop( Iop_64HLtoV128,
19216 mkU64( 0 ),
19217 mkU64( 0xFFFFFFFF ) ) ),
19218 mkU8( ( 12 - uim ) * 8 ) ),
19219 mkexpr( tmp ) ) );
19220 break;
19223 case 0x2B2: // xsabsdp (VSX scalar absolute value double-precision
19225 /* Move abs val of dw 0 of VSX[XB] to dw 0 of VSX[XT]. */
19226 IRTemp absVal = newTemp(Ity_V128);
19227 if (host_endness == VexEndnessLE) {
19228 IRTemp hi64 = newTemp(Ity_I64);
19229 IRTemp lo64 = newTemp(Ity_I64);
19230 assign( hi64, unop( Iop_V128HIto64, mkexpr(vB) ) );
19231 assign( lo64, unop( Iop_V128to64, mkexpr(vB) ) );
19232 assign( absVal, binop( Iop_64HLtoV128,
19233 binop( Iop_And64, mkexpr(hi64),
19234 mkU64(VG_PPC_SIGN_MASK) ),
19235 mkexpr(lo64) ) );
19236 } else {
19237 assign(absVal, binop(Iop_ShrV128,
19238 binop(Iop_ShlV128, mkexpr(vB),
19239 mkU8(1)), mkU8(1)));
19241 DIP("xsabsdp v%u,v%u\n", XT, XB);
19242 putVSReg(XT, mkexpr(absVal));
19243 break;
19246 case 0x2b6: // xsxexpdp (VSX Scalar Extract Exponent Double-Precision)
19247 // xsxsigdp (VSX Scalar Extract Significand Doulbe-Precision)
19248 // xsvhpdp (VSX Scalar Convert Half-Precision format
19249 // to Double-Precision format)
19250 // xscvdphp (VSX Scalar round & convert Double-precision
19251 // format to Half-precision format)
19253 IRTemp rT = newTemp( Ity_I64 );
19254 UInt inst_select = IFIELD( theInstr, 16, 5);
19256 if (inst_select == 0) {
19257 DIP("xsxexpd %u,v%u\n", (UInt)XT, (UInt)XB);
19259 assign( rT, binop( Iop_Shr64,
19260 binop( Iop_And64,
19261 unop( Iop_V128HIto64, mkexpr( vB ) ),
19262 mkU64( 0x7FF0000000000000 ) ),
19263 mkU8 ( 52 ) ) );
19264 } else if (inst_select == 1) {
19265 IRExpr *normal;
19266 IRTemp tmp = newTemp(Ity_I64);
19268 DIP("xsxsigdp v%u,v%u\n", (UInt)XT, (UInt)XB);
19270 assign( tmp, unop( Iop_V128HIto64, mkexpr( vB ) ) );
19272 /* Value is normal if it isn't infinite, zero or denormalized */
19273 normal = mkNOT1( mkOR1(
19274 mkOR1( is_NaN( Ity_I64, tmp ),
19275 is_Inf( Ity_I64, tmp ) ),
19276 mkOR1( is_Zero( Ity_I64, tmp ),
19277 is_Denorm( Ity_I64, tmp ) ) ) );
19279 assign( rT, binop( Iop_Or64,
19280 binop( Iop_And64,
19281 mkexpr( tmp ),
19282 mkU64( 0xFFFFFFFFFFFFF ) ),
19283 binop( Iop_Shl64,
19284 unop( Iop_1Uto64, normal),
19285 mkU8( 52 ) ) ) );
19286 putIReg( XT, mkexpr( rT ) );
19288 } else if (inst_select == 16) {
19289 IRTemp result = newTemp( Ity_V128 );
19290 IRTemp value = newTemp( Ity_I64 );
19291 /* Note: PPC only coverts the 16-bit value in the upper 64-bits
19292 * of the source V128 to a 64-bit value stored in the upper
19293 * 64-bits of the V128 result. The contents of the lower 64-bits
19294 * is undefined.
19297 DIP("xscvhpdp v%u, v%u\n", (UInt)XT, (UInt)XB);
19298 assign( result, unop( Iop_F16toF64x2, mkexpr( vB ) ) );
19300 putVSReg( XT, mkexpr( result ) );
19302 assign( value, unop( Iop_V128HIto64, mkexpr( result ) ) );
19303 generate_store_FPRF( Ity_I64, value, vbi );
19304 return True;
19306 } else if (inst_select == 17) { // xscvdphp
19307 IRTemp value = newTemp( Ity_I32 );
19308 IRTemp result = newTemp( Ity_V128 );
19309 /* Note: PPC only coverts the 64-bit value in the upper 64-bits of
19310 * the V128 and stores the 16-bit result in the upper word of the
19311 * V128 result. The contents of the lower 64-bits is undefined.
19313 DIP("xscvdphp v%u, v%u\n", (UInt)XT, (UInt)XB);
19314 assign( result, unop( Iop_F64toF16x2_DEP, mkexpr( vB ) ) );
19315 assign( value, unop( Iop_64to32, unop( Iop_V128HIto64,
19316 mkexpr( result ) ) ) );
19317 putVSReg( XT, mkexpr( result ) );
19318 generate_store_FPRF( Ity_I16, value, vbi );
19319 return True;
19321 } else {
19322 vex_printf( "dis_vxv_scalar_extract_exp_sig invalid inst_select (ppc)(opc2)\n" );
19323 vex_printf("inst_select = %u\n", inst_select);
19324 return False;
19327 break;
19329 case 0x254: // xststdcsp (VSX Scalar Test Data Class Single-Precision)
19330 case 0x2D4: // xststdcdp (VSX Scalar Test Data Class Double-Precision)
19332 /* These instructions only differ in that the single precision
19333 instruction, xststdcsp, has the additional constraint on the
19334 denormal test that the exponent be greater then zero and
19335 less then 0x381. */
19336 IRTemp vB_hi = newTemp( Ity_I64 );
19337 UInt BF = IFIELD( theInstr, 23, 3 );
19338 UInt DCMX_mask = IFIELD( theInstr, 16, 7 );
19339 IRTemp NaN = newTemp( Ity_I64 );
19340 IRTemp inf = newTemp( Ity_I64 );
19341 IRTemp zero = newTemp( Ity_I64 );
19342 IRTemp dnorm = newTemp( Ity_I64 );
19343 IRTemp pos = newTemp( Ity_I64 );
19344 IRTemp not_sp = newTemp( Ity_I64 );
19345 IRTemp DCM = newTemp( Ity_I64 );
19346 IRTemp CC = newTemp( Ity_I64 );
19347 IRTemp exponent = newTemp( Ity_I64 );
19348 IRTemp tmp = newTemp( Ity_I64 );
19350 assign( vB_hi, unop( Iop_V128HIto64, mkexpr( vB ) ) );
19352 assign( pos, unop( Iop_1Uto64,
19353 binop( Iop_CmpEQ64,
19354 binop( Iop_Shr64,
19355 mkexpr( vB_hi ),
19356 mkU8( 63 ) ),
19357 mkU64( 0 ) ) ) );
19359 assign( NaN, unop( Iop_1Uto64, is_NaN( Ity_I64, vB_hi ) ) );
19360 assign( inf, unop( Iop_1Uto64, is_Inf( Ity_I64, vB_hi ) ) );
19361 assign( zero, unop( Iop_1Uto64, is_Zero( Ity_I64, vB_hi ) ) );
19363 if (opc2 == 0x254) {
19364 DIP("xststdcsp %u,v%u,%u\n", BF, (UInt)XB, DCMX_mask);
19366 /* The least significant bit of the CC is set to 1 if the double
19367 precision value is not representable as a single precision
19368 value. The spec says the bit is set if:
19369 src != convert_SPtoDP(convert_DPtoSP(src))
19371 assign( tmp,
19372 unop( Iop_ReinterpF64asI64,
19373 unop( Iop_F32toF64,
19374 unop( Iop_TruncF64asF32,
19375 unop( Iop_ReinterpI64asF64,
19376 mkexpr( vB_hi ) ) ) ) ) );
19377 assign( not_sp, unop( Iop_1Uto64,
19378 mkNOT1( binop( Iop_CmpEQ64,
19379 mkexpr( vB_hi ),
19380 mkexpr( tmp ) ) ) ) );
19381 assign( exponent,
19382 binop( Iop_Shr64,
19383 binop( Iop_And64,
19384 mkexpr( vB_hi ),
19385 mkU64( 0x7ff0000000000000 ) ),
19386 mkU8( 52 ) ) );
19387 assign( dnorm, unop( Iop_1Uto64,
19388 mkOR1( is_Denorm( Ity_I64, vB_hi ),
19389 mkAND1( binop( Iop_CmpLT64U,
19390 mkexpr( exponent ),
19391 mkU64( 0x381 ) ),
19392 binop( Iop_CmpNE64,
19393 mkexpr( exponent ),
19394 mkU64( 0x0 ) ) ) ) ) );
19396 } else {
19397 DIP("xststdcdp %u,v%u,%u\n", BF, (UInt)XB, DCMX_mask);
19398 assign( not_sp, mkU64( 0 ) );
19399 assign( dnorm, unop( Iop_1Uto64, is_Denorm( Ity_I64, vB_hi ) ) );
19402 assign( DCM, create_DCM( Ity_I64, NaN, inf, zero, dnorm, pos ) );
19403 assign( CC,
19404 binop( Iop_Or64,
19405 binop( Iop_And64, /* vB sign bit */
19406 binop( Iop_Shr64,
19407 mkexpr( vB_hi ),
19408 mkU8( 60 ) ),
19409 mkU64( 0x8 ) ),
19410 binop( Iop_Or64,
19411 binop( Iop_Shl64,
19412 unop( Iop_1Uto64,
19413 binop( Iop_CmpNE64,
19414 binop( Iop_And64,
19415 mkexpr( DCM ),
19416 mkU64( DCMX_mask ) ),
19417 mkU64( 0 ) ) ),
19418 mkU8( 1 ) ),
19419 mkexpr( not_sp ) ) ) );
19420 putGST_field( PPC_GST_CR, unop( Iop_64to32, mkexpr( CC ) ), BF );
19421 putFPCC( unop( Iop_64to32, mkexpr( CC ) ) );
19423 return True;
19425 case 0x2C0: // xscpsgndp
19427 /* Scalar copy sign double-precision */
19428 IRTemp vecA_signed = newTemp(Ity_I64);
19429 IRTemp vecB_unsigned = newTemp(Ity_I64);
19430 IRTemp vec_result = newTemp(Ity_V128);
19431 DIP("xscpsgndp v%d,v%d v%d\n", XT, XA, XB);
19432 assign( vecA_signed, binop( Iop_And64,
19433 unop( Iop_V128HIto64,
19434 mkexpr(vA)),
19435 mkU64(~VG_PPC_SIGN_MASK) ) );
19436 assign( vecB_unsigned, binop( Iop_And64,
19437 unop( Iop_V128HIto64,
19438 mkexpr(vB) ),
19439 mkU64(VG_PPC_SIGN_MASK) ) );
19440 assign( vec_result, binop( Iop_64HLtoV128,
19441 binop( Iop_Or64,
19442 mkexpr(vecA_signed),
19443 mkexpr(vecB_unsigned) ),
19444 mkU64(0x0ULL)));
19445 putVSReg(XT, mkexpr(vec_result));
19446 break;
19448 case 0x2D2: // xsnabsdp
19450 /* Scalar negative absolute value double-precision */
19451 IRTemp BHi_signed = newTemp(Ity_I64);
19452 DIP("xsnabsdp v%d,v%d\n", XT, XB);
19453 assign( BHi_signed, binop( Iop_Or64,
19454 unop( Iop_V128HIto64,
19455 mkexpr(vB) ),
19456 mkU64(~VG_PPC_SIGN_MASK) ) );
19457 putVSReg(XT, binop( Iop_64HLtoV128,
19458 mkexpr(BHi_signed), mkU64(0x0ULL) ) );
19459 break;
19461 case 0x2F2: // xsnegdp
19463 /* Scalar negate double-precision */
19464 IRTemp BHi_signed = newTemp(Ity_I64);
19465 IRTemp BHi_unsigned = newTemp(Ity_I64);
19466 IRTemp BHi_negated = newTemp(Ity_I64);
19467 IRTemp BHi_negated_signbit = newTemp(Ity_I1);
19468 IRTemp vec_result = newTemp(Ity_V128);
19469 DIP("xsnabsdp v%d,v%d\n", XT, XB);
19470 assign( BHi_signed, unop( Iop_V128HIto64, mkexpr(vB) ) );
19471 assign( BHi_unsigned, binop( Iop_And64, mkexpr(BHi_signed),
19472 mkU64(VG_PPC_SIGN_MASK) ) );
19473 assign( BHi_negated_signbit,
19474 unop( Iop_Not1,
19475 unop( Iop_32to1,
19476 binop( Iop_Shr32,
19477 unop( Iop_64HIto32,
19478 binop( Iop_And64,
19479 mkexpr(BHi_signed),
19480 mkU64(~VG_PPC_SIGN_MASK) )
19482 mkU8(31) ) ) ) );
19483 assign( BHi_negated,
19484 binop( Iop_Or64,
19485 binop( Iop_32HLto64,
19486 binop( Iop_Shl32,
19487 unop( Iop_1Uto32,
19488 mkexpr(BHi_negated_signbit) ),
19489 mkU8(31) ),
19490 mkU32(0) ),
19491 mkexpr(BHi_unsigned) ) );
19492 assign( vec_result, binop( Iop_64HLtoV128, mkexpr(BHi_negated),
19493 mkU64(0x0ULL)));
19494 putVSReg( XT, mkexpr(vec_result));
19495 break;
19497 case 0x280: // xsmaxdp (VSX Scalar Maximum Double-Precision)
19498 case 0x2A0: // xsmindp (VSX Scalar Minimum Double-Precision)
19500 IRTemp frA = newTemp(Ity_I64);
19501 IRTemp frB = newTemp(Ity_I64);
19502 Bool isMin = opc2 == 0x2A0 ? True : False;
19503 DIP("%s v%d,v%d v%d\n", isMin ? "xsmaxdp" : "xsmindp", XT, XA, XB);
19505 assign(frA, unop(Iop_V128HIto64, mkexpr( vA )));
19506 assign(frB, unop(Iop_V128HIto64, mkexpr( vB )));
19507 putVSReg( XT, binop( Iop_64HLtoV128, get_max_min_fp(frA, frB, isMin), mkU64( 0 ) ) );
19509 break;
19511 case 0x0F2: // xsrdpim (VSX Scalar Round to Double-Precision Integer using round toward -Infinity)
19512 case 0x0D2: // xsrdpip (VSX Scalar Round to Double-Precision Integer using round toward +Infinity)
19513 case 0x0D6: // xsrdpic (VSX Scalar Round to Double-Precision Integer using Current rounding mode)
19514 case 0x0B2: // xsrdpiz (VSX Scalar Round to Double-Precision Integer using round toward Zero)
19515 case 0x092: // xsrdpi (VSX Scalar Round to Double-Precision Integer using round toward Nearest Away)
19517 IRTemp frB_I64 = newTemp(Ity_I64);
19518 IRExpr * frD_fp_round = NULL;
19520 assign(frB_I64, unop(Iop_V128HIto64, mkexpr( vB )));
19521 frD_fp_round = _do_vsx_fp_roundToInt(frB_I64, opc2);
19523 DIP("xsrdpi%s v%d,v%d\n", _get_vsx_rdpi_suffix(opc2), XT, XB);
19524 putVSReg( XT,
19525 binop( Iop_64HLtoV128,
19526 unop( Iop_ReinterpF64asI64, frD_fp_round),
19527 mkU64( 0 ) ) );
19528 break;
19530 case 0x034: // xsresp (VSX Scalar Reciprocal Estimate single-Precision)
19531 case 0x014: /* xsrsqrtesp (VSX Scalar Reciprocal Square Root Estimate
19532 * single-Precision)
19535 IRTemp frB = newTemp(Ity_F64);
19536 IRTemp sqrt = newTemp(Ity_F64);
19537 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
19538 IRExpr* rm = get_IR_roundingmode();
19539 Bool redp = opc2 == 0x034;
19540 DIP("%s v%d,v%d\n", redp ? "xsresp" : "xsrsqrtesp", XT,
19541 XB);
19543 assign( frB,
19544 unop( Iop_ReinterpI64asF64,
19545 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
19547 if (!redp)
19548 assign( sqrt,
19549 binop( Iop_SqrtF64,
19551 mkexpr(frB) ) );
19552 putVSReg( XT,
19553 binop( Iop_64HLtoV128,
19554 unop( Iop_ReinterpF64asI64,
19555 binop( Iop_RoundF64toF32, rm,
19556 triop( Iop_DivF64,
19558 ieee_one,
19559 redp ? mkexpr( frB ) :
19560 mkexpr( sqrt ) ) ) ),
19561 mkU64( 0 ) ) );
19562 break;
19565 case 0x0B4: // xsredp (VSX Scalar Reciprocal Estimate Double-Precision)
19566 case 0x094: // xsrsqrtedp (VSX Scalar Reciprocal Square Root Estimate Double-Precision)
19569 IRTemp frB = newTemp(Ity_F64);
19570 IRTemp sqrt = newTemp(Ity_F64);
19571 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
19572 IRExpr* rm = get_IR_roundingmode();
19573 Bool redp = opc2 == 0x0B4;
19574 DIP("%s v%d,v%d\n", redp ? "xsredp" : "xsrsqrtedp", XT, XB);
19575 assign( frB,
19576 unop( Iop_ReinterpI64asF64,
19577 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
19579 if (!redp)
19580 assign( sqrt,
19581 binop( Iop_SqrtF64,
19583 mkexpr(frB) ) );
19584 putVSReg( XT,
19585 binop( Iop_64HLtoV128,
19586 unop( Iop_ReinterpF64asI64,
19587 triop( Iop_DivF64,
19589 ieee_one,
19590 redp ? mkexpr( frB ) : mkexpr( sqrt ) ) ),
19591 mkU64( 0 ) ) );
19592 break;
19595 case 0x232: // xsrsp (VSX Scalar Round to Single-Precision)
19597 IRTemp frB = newTemp(Ity_F64);
19598 IRExpr* rm = get_IR_roundingmode();
19599 DIP("xsrsp v%d, v%d\n", XT, XB);
19600 assign( frB,
19601 unop( Iop_ReinterpI64asF64,
19602 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
19604 putVSReg( XT, binop( Iop_64HLtoV128,
19605 unop( Iop_ReinterpF64asI64,
19606 binop( Iop_RoundF64toF32,
19608 mkexpr( frB ) ) ),
19609 mkU64( 0 ) ) );
19610 break;
19613 case 0x354: // xvtstdcsp (VSX Test Data Class Single-Precision)
19615 UInt DX_mask = IFIELD( theInstr, 16, 5 );
19616 UInt DC_mask = IFIELD( theInstr, 6, 1 );
19617 UInt DM_mask = IFIELD( theInstr, 2, 1 );
19618 UInt DCMX_mask = (DC_mask << 6) | (DM_mask << 5) | DX_mask;
19620 IRTemp match_value[4];
19621 IRTemp value[4];
19622 IRTemp NaN[4];
19623 IRTemp inf[4];
19624 IRTemp pos[4];
19625 IRTemp DCM[4];
19626 IRTemp zero[4];
19627 IRTemp dnorm[4];
19628 Int i;
19630 DIP("xvtstdcsp v%u,v%u,%u\n", (UInt)XT, (UInt)XB, DCMX_mask);
19632 for (i = 0; i < 4; i++) {
19633 NaN[i] = newTemp(Ity_I32);
19634 inf[i] = newTemp(Ity_I32);
19635 pos[i] = newTemp(Ity_I32);
19636 DCM[i] = newTemp(Ity_I32);
19637 zero[i] = newTemp(Ity_I32);
19638 dnorm[i] = newTemp(Ity_I32);
19640 value[i] = newTemp(Ity_I32);
19641 match_value[i] = newTemp(Ity_I32);
19643 assign( value[i],
19644 unop( Iop_64to32,
19645 unop( Iop_V128to64,
19646 binop( Iop_AndV128,
19647 binop( Iop_ShrV128,
19648 mkexpr( vB ),
19649 mkU8( (3-i)*32 ) ),
19650 binop( Iop_64HLtoV128,
19651 mkU64( 0x0 ),
19652 mkU64( 0xFFFFFFFF ) ) ) ) ) );
19654 assign( pos[i], unop( Iop_1Uto32,
19655 binop( Iop_CmpEQ32,
19656 binop( Iop_Shr32,
19657 mkexpr( value[i] ),
19658 mkU8( 31 ) ),
19659 mkU32( 0 ) ) ) );
19661 assign( NaN[i], unop( Iop_1Uto32, is_NaN( Ity_I32, value[i] ) ));
19662 assign( inf[i], unop( Iop_1Uto32, is_Inf( Ity_I32, value[i] ) ) );
19663 assign( zero[i], unop( Iop_1Uto32, is_Zero( Ity_I32, value[i] ) ) );
19665 assign( dnorm[i], unop( Iop_1Uto32, is_Denorm( Ity_I32,
19666 value[i] ) ) );
19667 assign( DCM[i], create_DCM( Ity_I32, NaN[i], inf[i], zero[i],
19668 dnorm[i], pos[i] ) );
19670 assign( match_value[i],
19671 unop( Iop_1Sto32,
19672 binop( Iop_CmpNE32,
19673 binop( Iop_And32,
19674 mkU32( DCMX_mask ),
19675 mkexpr( DCM[i] ) ),
19676 mkU32( 0 ) ) ) );
19679 putVSReg( XT, binop( Iop_64HLtoV128,
19680 binop( Iop_32HLto64,
19681 mkexpr( match_value[0] ),
19682 mkexpr( match_value[1] ) ),
19683 binop( Iop_32HLto64,
19684 mkexpr( match_value[2] ),
19685 mkexpr( match_value[3] ) ) ) );
19687 break;
19689 case 0x360: // xviexpsp (VSX Vector Insert Exponent Single-Precision)
19691 Int i;
19692 IRTemp new_XT[5];
19693 IRTemp A_value[4];
19694 IRTemp B_value[4];
19695 IRExpr *sign[4], *expr[4], *fract[4];
19697 DIP("xviexpsp v%d,v%d\n", XT, XB);
19698 new_XT[0] = newTemp(Ity_V128);
19699 assign( new_XT[0], binop( Iop_64HLtoV128,
19700 mkU64( 0x0 ),
19701 mkU64( 0x0 ) ) );
19703 for (i = 0; i < 4; i++) {
19704 A_value[i] = newTemp(Ity_I32);
19705 B_value[i] = newTemp(Ity_I32);
19707 assign( A_value[i],
19708 unop( Iop_64to32,
19709 unop( Iop_V128to64,
19710 binop( Iop_AndV128,
19711 binop( Iop_ShrV128,
19712 mkexpr( vA ),
19713 mkU8( (3-i)*32 ) ),
19714 binop( Iop_64HLtoV128,
19715 mkU64( 0x0 ),
19716 mkU64( 0xFFFFFFFF ) ) ) ) ) );
19717 assign( B_value[i],
19718 unop( Iop_64to32,
19719 unop( Iop_V128to64,
19720 binop( Iop_AndV128,
19721 binop( Iop_ShrV128,
19722 mkexpr( vB ),
19723 mkU8( (3-i)*32 ) ),
19724 binop( Iop_64HLtoV128,
19725 mkU64( 0x0 ),
19726 mkU64( 0xFFFFFFFF ) ) ) ) ) );
19728 sign[i] = binop( Iop_And32, mkexpr( A_value[i] ),
19729 mkU32( 0x80000000 ) );
19730 expr[i] = binop( Iop_Shl32,
19731 binop( Iop_And32, mkexpr( B_value[i] ),
19732 mkU32( 0xFF ) ),
19733 mkU8( 23 ) );
19734 fract[i] = binop( Iop_And32, mkexpr( A_value[i] ),
19735 mkU32( 0x007FFFFF ) );
19737 new_XT[i+1] = newTemp(Ity_V128);
19738 assign( new_XT[i+1],
19739 binop( Iop_OrV128,
19740 binop( Iop_ShlV128,
19741 binop( Iop_64HLtoV128,
19742 mkU64( 0 ),
19743 binop( Iop_32HLto64,
19744 mkU32( 0 ),
19745 binop( Iop_Or32,
19746 binop( Iop_Or32,
19747 sign[i],
19748 expr[i] ),
19749 fract[i] ) ) ),
19750 mkU8( (3-i)*32 ) ),
19751 mkexpr( new_XT[i] ) ) );
19753 putVSReg( XT, mkexpr( new_XT[4] ) );
19755 break;
19757 case 0x396: // xsiexpdp (VSX Scalar Insert Exponent Double-Precision)
19759 IRExpr *sign, *expr, *fract;
19760 UChar rA_addr = ifieldRegA(theInstr);
19761 UChar rB_addr = ifieldRegB(theInstr);
19762 IRTemp rA = newTemp( Ity_I64 );
19763 IRTemp rB = newTemp( Ity_I64 );
19765 DIP("xsiexpdp v%u,%u,%u\n", (UInt)XT, (UInt)rA_addr, (UInt)rB_addr);
19766 assign( rA, getIReg(rA_addr));
19767 assign( rB, getIReg(rB_addr));
19769 sign = binop( Iop_And64, mkexpr( rA ), mkU64( 0x8000000000000000 ) );
19770 expr = binop( Iop_Shl64,
19771 binop( Iop_And64, mkexpr( rB ), mkU64( 0x7FF ) ),
19772 mkU8( 52 ) );
19773 fract = binop( Iop_And64, mkexpr( rA ), mkU64( 0x000FFFFFFFFFFFFF ) );
19775 putVSReg( XT, binop( Iop_64HLtoV128,
19776 binop( Iop_Or64,
19777 binop( Iop_Or64, sign, expr ),
19778 fract ),
19779 mkU64( 0 ) ) );
19781 break;
19783 case 0x3B6: // xvxexpdp (VSX Vector Extract Exponent Double-Precision)
19784 // xvxsigdp (VSX Vector Extract Significand Double-Precision)
19785 // xxbrh
19786 // xvxexpsp (VSX Vector Extract Exponent Single-Precision)
19787 // xvxsigsp (VSX Vector Extract Significand Single-Precision)
19788 // xxbrw
19789 // xxbrd
19790 // xxbrq
19791 // xvcvhpsp (VSX Vector Convert Half-Precision format to Single-Precision format)
19792 // xvcvsphp (VSX Vector round and convert Single-Precision format to Half-Precision format)
19794 UInt inst_select = IFIELD( theInstr, 16, 5);
19796 if (inst_select == 0) {
19797 DIP("xvxexpdp v%d,v%d\n", XT, XB);
19799 putVSReg( XT, binop( Iop_ShrV128,
19800 binop( Iop_AndV128,
19801 mkexpr( vB ),
19802 binop( Iop_64HLtoV128,
19803 mkU64( 0x7FF0000000000000 ),
19804 mkU64( 0x7FF0000000000000 ) ) ),
19805 mkU8( 52 ) ) );
19807 } else if (inst_select == 1) {
19808 Int i;
19809 IRExpr *normal[2];
19810 IRTemp value[2];
19811 IRTemp new_XT[3];
19813 DIP("xvxsigdp v%d,v%d\n", XT, XB);
19814 new_XT[0] = newTemp(Ity_V128);
19815 assign( new_XT[0], binop( Iop_64HLtoV128,
19816 mkU64( 0x0 ),
19817 mkU64( 0x0 ) ) );
19819 for (i = 0; i < 2; i++) {
19820 value[i] = newTemp(Ity_I64);
19821 assign( value[i],
19822 unop( Iop_V128to64,
19823 binop( Iop_AndV128,
19824 binop( Iop_ShrV128,
19825 mkexpr( vB ),
19826 mkU8( (1-i)*64 ) ),
19827 binop( Iop_64HLtoV128,
19828 mkU64( 0x0 ),
19829 mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) ) );
19831 /* Value is normal if it isn't infinite, zero or denormalized */
19832 normal[i] = mkNOT1( mkOR1(
19833 mkOR1( is_NaN( Ity_I64, value[i] ),
19834 is_Inf( Ity_I64, value[i] ) ),
19835 mkOR1( is_Zero( Ity_I64, value[i] ),
19836 is_Denorm( Ity_I64,
19837 value[i] ) ) ) );
19838 new_XT[i+1] = newTemp(Ity_V128);
19840 assign( new_XT[i+1],
19841 binop( Iop_OrV128,
19842 binop( Iop_ShlV128,
19843 binop( Iop_64HLtoV128,
19844 mkU64( 0x0 ),
19845 binop( Iop_Or64,
19846 binop( Iop_And64,
19847 mkexpr( value[i] ),
19848 mkU64( 0xFFFFFFFFFFFFF ) ),
19849 binop( Iop_Shl64,
19850 unop( Iop_1Uto64,
19851 normal[i]),
19852 mkU8( 52 ) ) ) ),
19853 mkU8( (1-i)*64 ) ),
19854 mkexpr( new_XT[i] ) ) );
19856 putVSReg( XT, mkexpr( new_XT[2] ) );
19858 } else if (inst_select == 7) {
19859 IRTemp sub_element0 = newTemp( Ity_V128 );
19860 IRTemp sub_element1 = newTemp( Ity_V128 );
19862 DIP("xxbrh v%u, v%u\n", (UInt)XT, (UInt)XB);
19864 assign( sub_element0,
19865 binop( Iop_ShrV128,
19866 binop( Iop_AndV128,
19867 binop(Iop_64HLtoV128,
19868 mkU64( 0xFF00FF00FF00FF00 ),
19869 mkU64( 0xFF00FF00FF00FF00 ) ),
19870 mkexpr( vB ) ),
19871 mkU8( 8 ) ) );
19872 assign( sub_element1,
19873 binop( Iop_ShlV128,
19874 binop( Iop_AndV128,
19875 binop(Iop_64HLtoV128,
19876 mkU64( 0x00FF00FF00FF00FF ),
19877 mkU64( 0x00FF00FF00FF00FF ) ),
19878 mkexpr( vB ) ),
19879 mkU8( 8 ) ) );
19881 putVSReg(XT, binop( Iop_OrV128,
19882 mkexpr( sub_element1 ),
19883 mkexpr( sub_element0 ) ) );
19885 } else if (inst_select == 8) {
19886 DIP("xvxexpsp v%d,v%d\n", XT, XB);
19888 putVSReg( XT, binop( Iop_ShrV128,
19889 binop( Iop_AndV128,
19890 mkexpr( vB ),
19891 binop( Iop_64HLtoV128,
19892 mkU64( 0x7F8000007F800000 ),
19893 mkU64( 0x7F8000007F800000 ) ) ),
19894 mkU8( 23 ) ) );
19895 } else if (inst_select == 9) {
19896 Int i;
19897 IRExpr *normal[4];
19898 IRTemp value[4];
19899 IRTemp new_value[4];
19900 IRTemp new_XT[5];
19902 DIP("xvxsigsp v%d,v%d\n", XT, XB);
19903 new_XT[0] = newTemp(Ity_V128);
19904 assign( new_XT[0], binop( Iop_64HLtoV128,
19905 mkU64( 0x0 ),
19906 mkU64( 0x0 ) ) );
19908 for (i = 0; i < 4; i++) {
19909 value[i] = newTemp(Ity_I32);
19910 assign( value[i],
19911 unop( Iop_64to32,
19912 unop( Iop_V128to64,
19913 binop( Iop_AndV128,
19914 binop( Iop_ShrV128,
19915 mkexpr( vB ),
19916 mkU8( (3-i)*32 ) ),
19917 binop( Iop_64HLtoV128,
19918 mkU64( 0x0 ),
19919 mkU64( 0xFFFFFFFF ) ) ) ) ) );
19921 new_XT[i+1] = newTemp(Ity_V128);
19923 /* Value is normal if it isn't infinite, zero or denormalized */
19924 normal[i] = mkNOT1( mkOR1(
19925 mkOR1( is_NaN( Ity_I32, value[i] ),
19926 is_Inf( Ity_I32, value[i] ) ),
19927 mkOR1( is_Zero( Ity_I32, value[i] ),
19928 is_Denorm( Ity_I32,
19929 value[i] ) ) ) );
19930 new_value[i] = newTemp(Ity_I32);
19931 assign( new_value[i],
19932 binop( Iop_Or32,
19933 binop( Iop_And32,
19934 mkexpr( value[i] ),
19935 mkU32( 0x7FFFFF ) ),
19936 binop( Iop_Shl32,
19937 unop( Iop_1Uto32,
19938 normal[i]),
19939 mkU8( 23 ) ) ) );
19941 assign( new_XT[i+1],
19942 binop( Iop_OrV128,
19943 binop( Iop_ShlV128,
19944 binop( Iop_64HLtoV128,
19945 mkU64( 0x0 ),
19946 binop( Iop_32HLto64,
19947 mkU32( 0x0 ),
19948 mkexpr( new_value[i] ) ) ),
19949 mkU8( (3-i)*32 ) ),
19950 mkexpr( new_XT[i] ) ) );
19952 putVSReg( XT, mkexpr( new_XT[4] ) );
19954 } else if (inst_select == 15) {
19955 IRTemp sub_element0 = newTemp( Ity_V128 );
19956 IRTemp sub_element1 = newTemp( Ity_V128 );
19957 IRTemp sub_element2 = newTemp( Ity_V128 );
19958 IRTemp sub_element3 = newTemp( Ity_V128 );
19960 DIP("xxbrw v%u, v%u\n", (UInt)XT, (UInt)XB);
19962 assign( sub_element0,
19963 binop( Iop_ShrV128,
19964 binop( Iop_AndV128,
19965 binop(Iop_64HLtoV128,
19966 mkU64( 0xFF000000FF000000 ),
19967 mkU64( 0xFF000000FF000000 ) ),
19968 mkexpr( vB ) ),
19969 mkU8( 24 ) ) );
19970 assign( sub_element1,
19971 binop( Iop_ShrV128,
19972 binop( Iop_AndV128,
19973 binop(Iop_64HLtoV128,
19974 mkU64( 0x00FF000000FF0000 ),
19975 mkU64( 0x00FF000000FF0000 ) ),
19976 mkexpr( vB ) ),
19977 mkU8( 8 ) ) );
19978 assign( sub_element2,
19979 binop( Iop_ShlV128,
19980 binop( Iop_AndV128,
19981 binop(Iop_64HLtoV128,
19982 mkU64( 0x0000FF000000FF00 ),
19983 mkU64( 0x0000FF000000FF00 ) ),
19984 mkexpr( vB ) ),
19985 mkU8( 8 ) ) );
19986 assign( sub_element3,
19987 binop( Iop_ShlV128,
19988 binop( Iop_AndV128,
19989 binop(Iop_64HLtoV128,
19990 mkU64( 0x00000000FF000000FF ),
19991 mkU64( 0x00000000FF000000FF ) ),
19992 mkexpr( vB ) ),
19993 mkU8( 24 ) ) );
19995 putVSReg( XT,
19996 binop( Iop_OrV128,
19997 binop( Iop_OrV128,
19998 mkexpr( sub_element3 ),
19999 mkexpr( sub_element2 ) ),
20000 binop( Iop_OrV128,
20001 mkexpr( sub_element1 ),
20002 mkexpr( sub_element0 ) ) ) );
20004 } else if (inst_select == 23) {
20005 DIP("xxbrd v%u, v%u\n", (UInt)XT, (UInt)XB);
20007 int i;
20008 int shift = 56;
20009 IRTemp sub_element[16];
20010 IRTemp new_xT[17];
20012 new_xT[0] = newTemp( Ity_V128 );
20013 assign( new_xT[0], binop( Iop_64HLtoV128,
20014 mkU64( 0 ),
20015 mkU64( 0 ) ) );
20017 for ( i = 0; i < 4; i++ ) {
20018 new_xT[i+1] = newTemp( Ity_V128 );
20019 sub_element[i] = newTemp( Ity_V128 );
20020 sub_element[i+4] = newTemp( Ity_V128 );
20022 assign( sub_element[i],
20023 binop( Iop_ShrV128,
20024 binop( Iop_AndV128,
20025 binop( Iop_64HLtoV128,
20026 mkU64( (0xFFULL << (7 - i) * 8) ),
20027 mkU64( (0xFFULL << (7 - i) * 8) ) ),
20028 mkexpr( vB ) ),
20029 mkU8( shift ) ) );
20031 assign( sub_element[i+4],
20032 binop( Iop_ShlV128,
20033 binop( Iop_AndV128,
20034 binop( Iop_64HLtoV128,
20035 mkU64( (0xFFULL << i*8) ),
20036 mkU64( (0xFFULL << i*8) ) ),
20037 mkexpr( vB ) ),
20038 mkU8( shift ) ) );
20039 shift = shift - 16;
20041 assign( new_xT[i+1],
20042 binop( Iop_OrV128,
20043 mkexpr( new_xT[i] ),
20044 binop( Iop_OrV128,
20045 mkexpr ( sub_element[i] ),
20046 mkexpr ( sub_element[i+4] ) ) ) );
20049 putVSReg( XT, mkexpr( new_xT[4] ) );
20051 } else if (inst_select == 24) {
20052 // xvcvhpsp, (VSX Vector Convert half-precision format to
20053 // Single-precision format)
20054 /* only supported on ISA 3.0 and newer */
20055 IRTemp result = newTemp( Ity_V128 );
20056 IRTemp src = newTemp( Ity_I64 );
20058 if (!allow_isa_3_0) return False;
20060 DIP("xvcvhpsp v%d,v%d\n", XT,XB);
20061 /* The instruction does not set the C or FPCC fields. The
20062 * instruction takes four 16-bit values stored in a 128-bit value
20063 * as follows: x V | x V | x V | x V where V is a 16-bit
20064 * value and x is an unused 16-bit value. To use Iop_F16toF32x4
20065 * the four 16-bit values will be gathered into a single 64 bit
20066 * value. The backend will scatter the four 16-bit values back
20067 * into a 128-bit operand before issuing the instruction.
20069 /* Gather 16-bit float values from V128 source into new 64-bit
20070 * source value for the Iop.
20072 assign( src,
20073 unop( Iop_V128to64,
20074 binop( Iop_Perm8x16,
20075 mkexpr( vB ),
20076 binop ( Iop_64HLtoV128,
20077 mkU64( 0 ),
20078 mkU64( 0x020306070A0B0E0F) ) ) ) );
20080 assign( result, unop( Iop_F16toF32x4, mkexpr( src ) ) );
20082 putVSReg( XT, mkexpr( result ) );
20084 } else if (inst_select == 25) {
20085 // xvcvsphp, (VSX Vector round and Convert single-precision
20086 // format to half-precision format)
20087 /* only supported on ISA 3.0 and newer */
20088 IRTemp result = newTemp( Ity_V128 );
20089 IRTemp tmp64 = newTemp( Ity_I64 );
20091 if (!allow_isa_3_0) return False;
20092 DIP("xvcvsphp v%d,v%d\n", XT,XB);
20094 /* Iop_F32toF16x4 is V128 -> I64, scatter the 16-bit floats in the
20095 * I64 result to the V128 register to store.
20097 assign( tmp64, unop( Iop_F32toF16x4_DEP, mkexpr( vB ) ) );
20099 /* Scatter 16-bit float values from returned 64-bit value
20100 * of V128 result.
20102 if (host_endness == VexEndnessLE)
20103 /* Note location 0 may have a valid number in it. Location
20104 * 15 should always be zero. Use 0xF to put zeros in the
20105 * desired bytes.
20107 assign( result,
20108 binop( Iop_Perm8x16,
20109 binop( Iop_64HLtoV128,
20110 mkexpr( tmp64 ),
20111 mkU64( 0 ) ),
20112 binop ( Iop_64HLtoV128,
20113 mkU64( 0x0F0F00010F0F0203 ),
20114 mkU64( 0x0F0F04050F0F0607 ) ) ) );
20115 else
20116 assign( result,
20117 binop( Iop_Perm8x16,
20118 binop( Iop_64HLtoV128,
20119 mkexpr( tmp64 ),
20120 mkU64( 0 ) ),
20121 binop ( Iop_64HLtoV128,
20122 mkU64( 0x0F0F06070F0F0405 ),
20123 mkU64( 0x0F0F02030F0F0001 ) ) ) );
20124 putVSReg( XT, mkexpr( result ) );
20126 } else if ( inst_select == 31 ) {
20127 int i;
20128 int shift_left = 8;
20129 int shift_right = 120;
20130 IRTemp sub_element[16];
20131 IRTemp new_xT[9];
20133 DIP("xxbrq v%u, v%u\n", (UInt) XT, (UInt) XB);
20135 new_xT[0] = newTemp( Ity_V128 );
20136 assign( new_xT[0], binop( Iop_64HLtoV128,
20137 mkU64( 0 ),
20138 mkU64( 0 ) ) );
20140 for ( i = 0; i < 8; i++ ) {
20141 new_xT[i+1] = newTemp( Ity_V128 );
20142 sub_element[i] = newTemp( Ity_V128 );
20143 sub_element[i+8] = newTemp( Ity_V128 );
20145 assign( sub_element[i],
20146 binop( Iop_ShrV128,
20147 binop( Iop_AndV128,
20148 binop( Iop_64HLtoV128,
20149 mkU64( ( 0xFFULL << (7 - i) * 8 ) ),
20150 mkU64( 0x0ULL ) ),
20151 mkexpr( vB ) ),
20152 mkU8( shift_right ) ) );
20153 shift_right = shift_right - 16;
20155 assign( sub_element[i+8],
20156 binop( Iop_ShlV128,
20157 binop( Iop_AndV128,
20158 binop( Iop_64HLtoV128,
20159 mkU64( 0x0ULL ),
20160 mkU64( ( 0xFFULL << (7 - i) * 8 ) ) ),
20161 mkexpr( vB ) ),
20162 mkU8( shift_left ) ) );
20163 shift_left = shift_left + 16;
20165 assign( new_xT[i+1],
20166 binop( Iop_OrV128,
20167 mkexpr( new_xT[i] ),
20168 binop( Iop_OrV128,
20169 mkexpr ( sub_element[i] ),
20170 mkexpr ( sub_element[i+8] ) ) ) );
20173 putVSReg( XT, mkexpr( new_xT[8] ) );
20175 } else {
20176 vex_printf("dis_vxs_misc(ppc) Invalid instruction selection\n");
20177 return False;
20179 break;
20182 case 0x3D4: // xvtstdcdp (VSX Test Data Class Double-Precision)
20184 UInt DX_mask = IFIELD( theInstr, 16, 5 );
20185 UInt DC_mask = IFIELD( theInstr, 6, 1 );
20186 UInt DM_mask = IFIELD( theInstr, 2, 1 );
20187 UInt DCMX_mask = (DC_mask << 6) | (DM_mask << 5) | DX_mask;
20189 IRTemp NaN[2], inf[2], zero[2], dnorm[2], pos[2], DCM[2];
20190 IRTemp match_value[2];
20191 IRTemp value[2];
20192 Int i;
20194 DIP("xvtstdcdp v%u,v%u,%u\n", (UInt)XT, (UInt)XB, DCMX_mask);
20196 for (i = 0; i < 2; i++) {
20197 NaN[i] = newTemp(Ity_I64);
20198 inf[i] = newTemp(Ity_I64);
20199 pos[i] = newTemp(Ity_I64);
20200 DCM[i] = newTemp(Ity_I64);
20201 zero[i] = newTemp(Ity_I64);
20202 dnorm[i] = newTemp(Ity_I64);
20204 value[i] = newTemp(Ity_I64);
20205 match_value[i] = newTemp(Ity_I64);
20207 assign( value[i],
20208 unop( Iop_V128to64,
20209 binop( Iop_AndV128,
20210 binop( Iop_ShrV128,
20211 mkexpr( vB ),
20212 mkU8( (1-i)*64 ) ),
20213 binop( Iop_64HLtoV128,
20214 mkU64( 0x0 ),
20215 mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) ) );
20217 assign( pos[i], unop( Iop_1Uto64,
20218 binop( Iop_CmpEQ64,
20219 binop( Iop_Shr64,
20220 mkexpr( value[i] ),
20221 mkU8( 63 ) ),
20222 mkU64( 0 ) ) ) );
20224 assign( NaN[i], unop( Iop_1Uto64, is_NaN( Ity_I64, value[i] ) ) );
20225 assign( inf[i], unop( Iop_1Uto64, is_Inf( Ity_I64, value[i] ) ) );
20226 assign( zero[i], unop( Iop_1Uto64, is_Zero( Ity_I64, value[i] ) ) );
20227 assign( dnorm[i], unop( Iop_1Uto64, is_Denorm( Ity_I64,
20228 value[i] ) ) );
20230 assign( DCM[i], create_DCM( Ity_I64, NaN[i], inf[i], zero[i],
20231 dnorm[i], pos[i] ) );
20233 assign( match_value[i],
20234 unop( Iop_1Sto64,
20235 binop( Iop_CmpNE64,
20236 binop( Iop_And64,
20237 mkU64( DCMX_mask ),
20238 mkexpr( DCM[i] ) ),
20239 mkU64( 0 ) ) ) );
20241 putVSReg( XT, binop( Iop_64HLtoV128,
20242 mkexpr( match_value[0] ),
20243 mkexpr( match_value[1] ) ) );
20245 break;
20247 case 0x3E0: // xviexpdp (VSX Vector Insert Exponent Double-Precision)
20249 Int i;
20250 IRTemp new_XT[3];
20251 IRTemp A_value[2];
20252 IRTemp B_value[2];
20253 IRExpr *sign[2], *expr[2], *fract[2];
20255 DIP("xviexpdp v%d,v%d\n", XT, XB);
20256 new_XT[0] = newTemp(Ity_V128);
20257 assign( new_XT[0], binop( Iop_64HLtoV128,
20258 mkU64( 0x0 ),
20259 mkU64( 0x0 ) ) );
20261 for (i = 0; i < 2; i++) {
20262 A_value[i] = newTemp(Ity_I64);
20263 B_value[i] = newTemp(Ity_I64);
20265 assign( A_value[i],
20266 unop( Iop_V128to64,
20267 binop( Iop_AndV128,
20268 binop( Iop_ShrV128,
20269 mkexpr( vA ),
20270 mkU8( (1-i)*64 ) ),
20271 binop( Iop_64HLtoV128,
20272 mkU64( 0x0 ),
20273 mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) ) );
20274 assign( B_value[i],
20275 unop( Iop_V128to64,
20276 binop( Iop_AndV128,
20277 binop( Iop_ShrV128,
20278 mkexpr( vB ),
20279 mkU8( (1-i)*64 ) ),
20280 binop( Iop_64HLtoV128,
20281 mkU64( 0x0 ),
20282 mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) ) );
20284 sign[i] = binop( Iop_And64, mkexpr( A_value[i] ),
20285 mkU64( 0x8000000000000000 ) );
20286 expr[i] = binop( Iop_Shl64,
20287 binop( Iop_And64, mkexpr( B_value[i] ),
20288 mkU64( 0x7FF ) ),
20289 mkU8( 52 ) );
20290 fract[i] = binop( Iop_And64, mkexpr( A_value[i] ),
20291 mkU64( 0x000FFFFFFFFFFFFF ) );
20293 new_XT[i+1] = newTemp(Ity_V128);
20294 assign( new_XT[i+1],
20295 binop( Iop_OrV128,
20296 binop( Iop_ShlV128,
20297 binop( Iop_64HLtoV128,
20298 mkU64( 0 ),
20299 binop( Iop_Or64,
20300 binop( Iop_Or64,
20301 sign[i],
20302 expr[i] ),
20303 fract[i] ) ),
20304 mkU8( (1-i)*64 ) ),
20305 mkexpr( new_XT[i] ) ) );
20307 putVSReg( XT, mkexpr( new_XT[2] ) );
20309 break;
20311 default:
20312 vex_printf( "dis_vxs_misc(ppc)(opc2)\n" );
20313 return False;
20315 return True;
20319 * VSX vector miscellaneous instructions
20322 static Bool
20323 dis_vx_misc ( UInt theInstr, UInt opc2 )
20325 /* XX3-Form */
20326 UChar XT = ifieldRegXT ( theInstr );
20327 UChar XA = ifieldRegXA ( theInstr );
20328 UChar XB = ifieldRegXB ( theInstr );
20329 IRTemp vA = newTemp( Ity_V128 );
20330 IRTemp vB = newTemp( Ity_V128 );
20331 IRTemp src1 = newTemp(Ity_I64);
20332 IRTemp src2 = newTemp(Ity_I64);
20333 IRTemp result_mask = newTemp(Ity_I64);
20334 IRTemp cmp_mask = newTemp(Ity_I64);
20335 IRTemp nan_mask = newTemp(Ity_I64);
20336 IRTemp snan_mask = newTemp(Ity_I64);
20337 IRTemp word_result = newTemp(Ity_I64);
20338 IRTemp check_result = newTemp(Ity_I64);
20339 IRTemp xT = newTemp( Ity_V128 );
20340 IRTemp nan_cmp_value = newTemp(Ity_I64);
20341 UInt trap_enabled = 0; /* 0 - trap enabled is False */
20343 assign( vA, getVSReg( XA ) );
20344 assign( vB, getVSReg( XB ) );
20345 assign( xT, getVSReg( XT ) );
20347 assign(src1, unop( Iop_V128HIto64, mkexpr( vA ) ) );
20348 assign(src2, unop( Iop_V128HIto64, mkexpr( vB ) ) );
20350 assign( nan_mask,
20351 binop( Iop_Or64,
20352 unop( Iop_1Sto64, is_NaN( Ity_I64, src1 ) ),
20353 unop( Iop_1Sto64, is_NaN( Ity_I64, src2 ) ) ) );
20355 if ( trap_enabled == 0 )
20356 /* Traps on invalid operation are assumed not enabled, assign
20357 result of comparison to xT.
20359 assign( snan_mask, mkU64( 0 ) );
20361 else
20362 assign( snan_mask,
20363 binop( Iop_Or64,
20364 unop( Iop_1Sto64, is_sNaN( Ity_I64, src1 ) ),
20365 unop( Iop_1Sto64, is_sNaN( Ity_I64, src2 ) ) ) );
20367 assign (result_mask, binop( Iop_Or64,
20368 mkexpr( snan_mask ),
20369 mkexpr( nan_mask ) ) );
20371 switch (opc2) {
20372 case 0xC: //xscmpeqdp
20374 DIP("xscmpeqdp v%d,v%d,v%d\n", XT, XA, XB);
20375 /* extract double-precision floating point source values from
20376 double word 0 */
20378 /* result of Iop_CmpF64 is 0x40 if operands are equal,
20379 mask is all 1's if equal. */
20381 assign( cmp_mask,
20382 unop( Iop_1Sto64,
20383 unop(Iop_32to1,
20384 binop(Iop_Shr32,
20385 binop( Iop_CmpF64,
20386 unop( Iop_ReinterpI64asF64,
20387 mkexpr( src1 ) ),
20388 unop( Iop_ReinterpI64asF64,
20389 mkexpr( src2 ) ) ),
20390 mkU8( 6 ) ) ) ) );
20392 assign( word_result,
20393 binop( Iop_Or64,
20394 binop( Iop_And64, mkexpr( cmp_mask ),
20395 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
20396 binop( Iop_And64,
20397 unop( Iop_Not64, mkexpr( cmp_mask ) ),
20398 mkU64( 0x0 ) ) ) );
20399 assign( nan_cmp_value, mkU64( 0 ) );
20400 break;
20403 case 0x2C: //xscmpgtdp
20405 DIP("xscmpgtdp v%d,v%d,v%d\n", XT, XA, XB);
20406 /* Test for src1 > src2 */
20408 /* Result of Iop_CmpF64 is 0x1 if op1 < op2, set mask to all 1's. */
20409 assign( cmp_mask,
20410 unop( Iop_1Sto64,
20411 unop(Iop_32to1,
20412 binop(Iop_CmpF64,
20413 unop( Iop_ReinterpI64asF64,
20414 mkexpr( src2 ) ),
20415 unop( Iop_ReinterpI64asF64,
20416 mkexpr( src1 ) ) ) ) ) );
20417 assign( word_result,
20418 binop( Iop_Or64,
20419 binop( Iop_And64, mkexpr( cmp_mask ),
20420 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
20421 binop( Iop_And64,
20422 unop( Iop_Not64, mkexpr( cmp_mask ) ),
20423 mkU64( 0x0 ) ) ) );
20424 assign( nan_cmp_value, mkU64( 0 ) );
20425 break;
20428 case 0x4C: //xscmpgedp
20430 DIP("xscmpeqdp v%d,v%d,v%d\n", XT, XA, XB);
20431 /* compare src 1 >= src 2 */
20432 /* result of Iop_CmpF64 is 0x40 if operands are equal,
20433 mask is all 1's if equal. */
20434 assign( cmp_mask,
20435 unop( Iop_1Sto64,
20436 unop(Iop_32to1,
20437 binop( Iop_Or32,
20438 binop( Iop_Shr32,
20439 binop(Iop_CmpF64, /* EQ test */
20440 unop( Iop_ReinterpI64asF64,
20441 mkexpr( src1 ) ),
20442 unop( Iop_ReinterpI64asF64,
20443 mkexpr( src2 ) ) ),
20444 mkU8( 6 ) ),
20445 binop(Iop_CmpF64, /* src2 < src 1 test */
20446 unop( Iop_ReinterpI64asF64,
20447 mkexpr( src2 ) ),
20448 unop( Iop_ReinterpI64asF64,
20449 mkexpr( src1 ) ) ) ) ) ) );
20450 assign( word_result,
20451 binop( Iop_Or64,
20452 binop( Iop_And64, mkexpr( cmp_mask ),
20453 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
20454 binop( Iop_And64,
20455 unop( Iop_Not64, mkexpr( cmp_mask ) ),
20456 mkU64( 0x0 ) ) ) );
20457 assign( nan_cmp_value, mkU64( 0 ) );
20458 break;
20461 case 0x200: //xsmaxcdp
20463 DIP("xsmaxcdp v%d,v%d,v%d\n", XT, XA, XB);
20464 /* extract double-precision floating point source values from
20465 double word 0 */
20467 /* result of Iop_CmpF64 is 0x1 if arg1 LT then arg2, */
20468 assign( cmp_mask,
20469 unop( Iop_1Sto64,
20470 unop( Iop_32to1,
20471 binop(Iop_CmpF64,
20472 unop( Iop_ReinterpI64asF64,
20473 mkexpr( src2 ) ),
20474 unop( Iop_ReinterpI64asF64,
20475 mkexpr( src1 ) ) ) ) ) );
20476 assign( word_result,
20477 binop( Iop_Or64,
20478 binop( Iop_And64, mkexpr( cmp_mask ), mkexpr( src1 ) ),
20479 binop( Iop_And64,
20480 unop( Iop_Not64, mkexpr( cmp_mask ) ),
20481 mkexpr( src2 ) ) ) );
20482 assign( nan_cmp_value, mkexpr( src2 ) );
20483 break;
20486 case 0x220: //xsmincdp
20488 DIP("xsmincdp v%d,v%d,v%d\n", XT, XA, XB);
20489 /* extract double-precision floating point source values from
20490 double word 0 */
20492 /* result of Iop_CmpF64 is 0x1 if arg1 less then arg2, */
20493 assign( cmp_mask,
20494 unop( Iop_1Sto64,
20495 unop( Iop_32to1,
20496 binop(Iop_CmpF64,
20497 unop( Iop_ReinterpI64asF64,
20498 mkexpr( src1 ) ),
20499 unop( Iop_ReinterpI64asF64,
20500 mkexpr( src2 ) ) ) ) ) );
20501 assign( word_result,
20502 binop( Iop_Or64,
20503 binop( Iop_And64, mkexpr( cmp_mask ), mkexpr( src1 ) ),
20504 binop( Iop_And64,
20505 unop( Iop_Not64, mkexpr( cmp_mask ) ),
20506 mkexpr( src2 ) ) ) );
20507 assign( nan_cmp_value, mkexpr( src2 ) );
20508 break;
20511 default:
20512 vex_printf( "dis_vx_misc(ppc)(opc2)\n" );
20513 return False;
20516 /* If either argument is NaN, result is src2. If either argument is
20517 SNaN, we are supposed to generate invalid operation exception.
20518 Currently don't support generating exceptions. In case of an
20519 trap enabled invalid operation (SNaN) XT is not changed. The
20520 snan_mask is setup appropriately for trap enabled or not.
20522 assign( check_result,
20523 binop( Iop_Or64,
20524 binop( Iop_And64, mkexpr( snan_mask ),
20525 unop( Iop_V128HIto64, mkexpr( xT ) ) ),
20526 binop( Iop_And64, unop( Iop_Not64,
20527 mkexpr( snan_mask ) ),
20528 binop( Iop_Or64,
20529 binop( Iop_And64, mkexpr( nan_mask ),
20530 mkexpr( nan_cmp_value ) ),
20531 binop( Iop_And64,
20532 unop( Iop_Not64,
20533 mkexpr( nan_mask ) ),
20534 mkU64( 0 ) ) ) ) ) );
20536 /* If SNaN is true, then the result is unchanged if a trap-enabled
20537 Invalid Operation occurs. Result mask already setup for trap-enabled
20538 case.
20540 putVSReg( XT,
20541 binop( Iop_64HLtoV128,
20542 binop( Iop_Or64,
20543 binop( Iop_And64,
20544 unop( Iop_Not64, mkexpr( result_mask ) ),
20545 mkexpr( word_result ) ),
20546 binop( Iop_And64,
20547 mkexpr( result_mask ),
20548 mkexpr( check_result ) ) ),
20549 mkU64( 0 ) ) );
20550 return True;
20554 * VSX Logical Instructions
20556 static Bool
20557 dis_vx_logic ( UInt theInstr, UInt opc2 )
20559 /* XX3-Form */
20560 UChar opc1 = ifieldOPC( theInstr );
20561 UChar XT = ifieldRegXT ( theInstr );
20562 UChar XA = ifieldRegXA ( theInstr );
20563 UChar XB = ifieldRegXB ( theInstr );
20564 IRTemp vA = newTemp( Ity_V128 );
20565 IRTemp vB = newTemp( Ity_V128 );
20567 if (opc1 != 0x3C) {
20568 vex_printf( "dis_vx_logic(ppc)(instr)\n" );
20569 return False;
20572 assign( vA, getVSReg( XA ) );
20573 assign( vB, getVSReg( XB ) );
20575 switch (opc2) {
20576 case 0x268: // xxlxor
20577 DIP("xxlxor v%d,v%d,v%d\n", XT, XA, XB);
20578 putVSReg( XT, binop( Iop_XorV128, mkexpr( vA ), mkexpr( vB ) ) );
20579 break;
20580 case 0x248: // xxlor
20581 DIP("xxlor v%d,v%d,v%d\n", XT, XA, XB);
20582 putVSReg( XT, binop( Iop_OrV128, mkexpr( vA ), mkexpr( vB ) ) );
20583 break;
20584 case 0x288: // xxlnor
20585 DIP("xxlnor v%d,v%d,v%d\n", XT, XA, XB);
20586 putVSReg( XT, unop( Iop_NotV128, binop( Iop_OrV128, mkexpr( vA ),
20587 mkexpr( vB ) ) ) );
20588 break;
20589 case 0x208: // xxland
20590 DIP("xxland v%d,v%d,v%d\n", XT, XA, XB);
20591 putVSReg( XT, binop( Iop_AndV128, mkexpr( vA ), mkexpr( vB ) ) );
20592 break;
20593 case 0x228: //xxlandc
20594 DIP("xxlandc v%d,v%d,v%d\n", XT, XA, XB);
20595 putVSReg( XT, binop( Iop_AndV128, mkexpr( vA ), unop( Iop_NotV128,
20596 mkexpr( vB ) ) ) );
20597 break;
20598 case 0x2A8: // xxlorc (VSX Logical OR with complement)
20599 DIP("xxlorc v%d,v%d,v%d\n", XT, XA, XB);
20600 putVSReg( XT, binop( Iop_OrV128,
20601 mkexpr( vA ),
20602 unop( Iop_NotV128, mkexpr( vB ) ) ) );
20603 break;
20604 case 0x2C8: // xxlnand (VSX Logical NAND)
20605 DIP("xxlnand v%d,v%d,v%d\n", XT, XA, XB);
20606 putVSReg( XT, unop( Iop_NotV128,
20607 binop( Iop_AndV128, mkexpr( vA ),
20608 mkexpr( vB ) ) ) );
20609 break;
20610 case 0x2E8: // xxleqv (VSX Logical Equivalence)
20611 DIP("xxleqv v%d,v%d,v%d\n", XT, XA, XB);
20612 putVSReg( XT, unop( Iop_NotV128,
20613 binop( Iop_XorV128,
20614 mkexpr( vA ), mkexpr( vB ) ) ) );
20615 break;
20616 default:
20617 vex_printf( "dis_vx_logic(ppc)(opc2)\n" );
20618 return False;
20620 return True;
20624 * VSX Load Instructions
20625 * NOTE: VSX supports word-aligned storage access.
20627 static Bool
20628 dis_vx_load ( UInt theInstr )
20630 /* XX1-Form */
20631 UChar opc1 = ifieldOPC( theInstr );
20632 UChar XT = ifieldRegXT ( theInstr );
20633 UChar rA_addr = ifieldRegA( theInstr );
20634 UChar rB_addr = ifieldRegB( theInstr );
20635 UInt opc2 = ifieldOPClo10( theInstr );
20637 IRType ty = mode64 ? Ity_I64 : Ity_I32;
20638 IRTemp EA = newTemp( ty );
20640 if (opc1 != 0x1F) {
20641 vex_printf( "dis_vx_load(ppc)(instr)\n" );
20642 return False;
20645 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
20647 switch (opc2) {
20648 case 0x00C: // lxsiwzx (Load VSX Scalar as Integer Word and Zero Indexed)
20650 IRExpr * exp;
20651 DIP("lxsiwzx %d,r%u,r%u\n", XT, rA_addr, rB_addr);
20653 if (host_endness == VexEndnessLE)
20654 exp = unop( Iop_64to32, load( Ity_I64, mkexpr( EA ) ) );
20655 else
20656 exp = unop( Iop_64HIto32, load( Ity_I64, mkexpr( EA ) ) );
20658 putVSReg( XT, binop( Iop_64HLtoV128,
20659 unop( Iop_32Uto64, exp),
20660 mkU64(0) ) );
20661 break;
20663 case 0x04C: // lxsiwax (Load VSX Scalar as Integer Word Algebraic Indexed)
20665 IRExpr * exp;
20666 DIP("lxsiwax %d,r%u,r%u\n", XT, rA_addr, rB_addr);
20668 if (host_endness == VexEndnessLE)
20669 exp = unop( Iop_64to32, load( Ity_I64, mkexpr( EA ) ) );
20670 else
20671 exp = unop( Iop_64HIto32, load( Ity_I64, mkexpr( EA ) ) );
20673 putVSReg( XT, binop( Iop_64HLtoV128,
20674 unop( Iop_32Sto64, exp),
20675 mkU64(0) ) );
20676 break;
20678 case 0x10C: // lxvx
20680 UInt ea_off = 0;
20681 IRExpr* irx_addr;
20682 IRTemp word[4];
20683 int i;
20685 DIP("lxvx %u,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
20687 if ( host_endness == VexEndnessBE ) {
20688 for ( i = 3; i>= 0; i-- ) {
20689 word[i] = newTemp( Ity_I64 );
20691 irx_addr =
20692 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20693 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20695 assign( word[i], unop( Iop_32Uto64,
20696 load( Ity_I32, irx_addr ) ) );
20697 ea_off += 4;
20700 putVSReg( XT, binop( Iop_64HLtoV128,
20701 binop( Iop_Or64,
20702 mkexpr( word[2] ),
20703 binop( Iop_Shl64,
20704 mkexpr( word[3] ),
20705 mkU8( 32 ) ) ),
20706 binop( Iop_Or64,
20707 mkexpr( word[0] ),
20708 binop( Iop_Shl64,
20709 mkexpr( word[1] ),
20710 mkU8( 32 ) ) ) ) );
20711 } else {
20712 for ( i = 0; i< 4; i++ ) {
20713 word[i] = newTemp( Ity_I64 );
20715 irx_addr =
20716 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20717 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20719 assign( word[i], unop( Iop_32Uto64,
20720 load( Ity_I32, irx_addr ) ) );
20721 ea_off += 4;
20724 putVSReg( XT, binop( Iop_64HLtoV128,
20725 binop( Iop_Or64,
20726 mkexpr( word[2] ),
20727 binop( Iop_Shl64,
20728 mkexpr( word[3] ),
20729 mkU8( 32 ) ) ),
20730 binop( Iop_Or64,
20731 mkexpr( word[0] ),
20732 binop( Iop_Shl64,
20733 mkexpr( word[1] ),
20734 mkU8( 32 ) ) ) ) );
20736 break;
20739 case 0x10D: // lxvl
20741 DIP("lxvl %u,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
20743 IRTemp byte[16];
20744 UInt i;
20745 UInt ea_off = 0;
20746 IRExpr* irx_addr;
20747 IRTemp tmp_low[9];
20748 IRTemp tmp_hi[9];
20749 IRTemp shift = newTemp( Ity_I8 );
20750 IRTemp nb_gt16 = newTemp( Ity_I8 );
20751 IRTemp ld_result = newTemp( Ity_V128 );
20752 IRTemp nb_not_zero = newTemp( Ity_I64 );
20754 IRTemp base_addr = newTemp( ty );
20756 tmp_low[0] = newTemp( Ity_I64 );
20757 tmp_hi[0] = newTemp( Ity_I64 );
20759 assign( base_addr, ea_rAor0( rA_addr ) );
20760 assign( tmp_low[0], mkU64( 0 ) );
20761 assign( tmp_hi[0], mkU64( 0 ) );
20763 /* shift is 15 - nb, where nb = rB[0:7], used to zero out upper bytes */
20764 assign( nb_not_zero, unop( Iop_1Sto64,
20765 binop( Iop_CmpNE64,
20766 mkU64( 0 ),
20767 binop( Iop_Shr64,
20768 getIReg( rB_addr ),
20769 mkU8( 56 ) ) ) ) );
20771 assign( nb_gt16, unop( Iop_1Sto8,
20772 binop( Iop_CmpLT64U,
20773 binop( Iop_Shr64,
20774 getIReg( rB_addr ),
20775 mkU8( 60 ) ),
20776 mkU64( 1 ) ) ) );
20778 /* Set the shift to 0, by ANDing with nb_gt16. nb_gt16 will be all
20779 * zeros if nb > 16. This will result in quad word load being stored.
20781 assign( shift,
20782 binop( Iop_And8,
20783 unop( Iop_64to8,
20784 binop( Iop_Mul64,
20785 binop( Iop_Sub64,
20786 mkU64 ( 16 ),
20787 binop( Iop_Shr64,
20788 getIReg( rB_addr ),
20789 mkU8( 56 ) ) ),
20790 mkU64( 8 ) ) ),
20791 mkexpr( nb_gt16 ) ) );
20793 /* fetch all 16 bytes, we will remove what we don't want later */
20794 if ( host_endness == VexEndnessBE ) {
20795 for ( i = 0; i < 8; i++ ) {
20796 byte[i] = newTemp( Ity_I64 );
20797 tmp_hi[i+1] = newTemp( Ity_I64 );
20799 irx_addr =
20800 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
20801 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20802 ea_off += 1;
20804 assign( byte[i], binop( Iop_Shl64,
20805 unop( Iop_8Uto64,
20806 load( Ity_I8, irx_addr ) ),
20807 mkU8( 8 * ( 7 - i ) ) ) );
20809 assign( tmp_hi[i+1], binop( Iop_Or64,
20810 mkexpr( byte[i] ),
20811 mkexpr( tmp_hi[i] ) ) );
20814 for ( i = 0; i < 8; i++ ) {
20815 byte[i+8] = newTemp( Ity_I64 );
20816 tmp_low[i+1] = newTemp( Ity_I64 );
20818 irx_addr =
20819 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
20820 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20821 ea_off += 1;
20823 assign( byte[i+8], binop( Iop_Shl64,
20824 unop( Iop_8Uto64,
20825 load( Ity_I8, irx_addr ) ),
20826 mkU8( 8 * ( 7 - i ) ) ) );
20828 assign( tmp_low[i+1], binop( Iop_Or64,
20829 mkexpr( byte[i+8] ),
20830 mkexpr( tmp_low[i] ) ) );
20832 assign( ld_result, binop( Iop_ShlV128,
20833 binop( Iop_ShrV128,
20834 binop( Iop_64HLtoV128,
20835 mkexpr( tmp_hi[8] ),
20836 mkexpr( tmp_low[8] ) ),
20837 mkexpr( shift ) ),
20838 mkexpr( shift ) ) );
20839 } else {
20840 for ( i = 0; i < 8; i++ ) {
20841 byte[i] = newTemp( Ity_I64 );
20842 tmp_low[i+1] = newTemp( Ity_I64 );
20844 irx_addr =
20845 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
20846 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20847 ea_off += 1;
20849 assign( byte[i], binop( Iop_Shl64,
20850 unop( Iop_8Uto64,
20851 load( Ity_I8, irx_addr ) ),
20852 mkU8( 8 * i ) ) );
20854 assign( tmp_low[i+1],
20855 binop( Iop_Or64,
20856 mkexpr( byte[i] ), mkexpr( tmp_low[i] ) ) );
20859 for ( i = 0; i < 8; i++ ) {
20860 byte[i + 8] = newTemp( Ity_I64 );
20861 tmp_hi[i+1] = newTemp( Ity_I64 );
20863 irx_addr =
20864 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
20865 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20866 ea_off += 1;
20868 assign( byte[i+8], binop( Iop_Shl64,
20869 unop( Iop_8Uto64,
20870 load( Ity_I8, irx_addr ) ),
20871 mkU8( 8 * i ) ) );
20873 assign( tmp_hi[i+1], binop( Iop_Or64,
20874 mkexpr( byte[i+8] ),
20875 mkexpr( tmp_hi[i] ) ) );
20877 assign( ld_result, binop( Iop_ShrV128,
20878 binop( Iop_ShlV128,
20879 binop( Iop_64HLtoV128,
20880 mkexpr( tmp_hi[8] ),
20881 mkexpr( tmp_low[8] ) ),
20882 mkexpr( shift ) ),
20883 mkexpr( shift ) ) );
20887 /* If nb = 0, mask out the calculated load result so the stored
20888 * value is zero.
20891 putVSReg( XT, binop( Iop_AndV128,
20892 mkexpr( ld_result ),
20893 binop( Iop_64HLtoV128,
20894 mkexpr( nb_not_zero ),
20895 mkexpr( nb_not_zero ) ) ) );
20896 break;
20899 case 0x12D: // lxvll (Load VSX Vector Left-Justified with Length XX1 form)
20901 IRTemp byte[16];
20902 IRTemp tmp_low[9];
20903 IRTemp tmp_hi[9];
20904 IRTemp mask = newTemp(Ity_V128);
20905 IRTemp rB = newTemp( Ity_I64 );
20906 IRTemp nb = newTemp( Ity_I64 );
20907 IRTemp nb_zero = newTemp(Ity_V128);
20908 IRTemp mask_shift = newTemp(Ity_I64);
20909 Int i;
20910 UInt ea_off = 0;
20911 IRExpr* irx_addr;
20912 IRTemp base_addr = newTemp( ty );
20913 IRTemp nb_compare_zero = newTemp( Ity_I64 );
20915 DIP("lxvll %u,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
20917 tmp_low[0] = newTemp(Ity_I64);
20918 tmp_hi[0] = newTemp(Ity_I64);
20920 assign( rB, getIReg(rB_addr));
20921 assign( base_addr, ea_rAor0( rA_addr ) );
20922 assign( tmp_low[0], mkU64( 0 ) );
20923 assign( tmp_hi[0], mkU64( 0 ) );
20925 /* mask_shift is number of 16 bytes minus (nb times 8-bits per byte) */
20926 assign( nb, binop( Iop_Shr64, mkexpr( rB ), mkU8( 56 ) ) );
20928 assign( nb_compare_zero, unop( Iop_1Sto64,
20929 binop( Iop_CmpEQ64,
20930 mkexpr( nb ),
20931 mkU64( 0 ) ) ) );
20933 /* nb_zero is 0xFF..FF if the nb_field = 0 */
20934 assign( nb_zero, binop( Iop_64HLtoV128,
20935 mkexpr( nb_compare_zero ),
20936 mkexpr( nb_compare_zero ) ) );
20938 assign( mask_shift, binop( Iop_Sub64,
20939 mkU64( 16*8 ),
20940 binop( Iop_Mul64,
20941 mkexpr( nb ),
20942 mkU64( 8 ) ) ) );
20944 /* fetch all 16 bytes, we will remove what we don't want later */
20945 for (i = 0; i < 8; i++) {
20946 byte[i] = newTemp(Ity_I64);
20947 tmp_hi[i+1] = newTemp(Ity_I64);
20949 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
20950 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20951 ea_off += 1;
20953 /* Instruction always loads in Big Endian format */
20954 assign( byte[i], binop( Iop_Shl64,
20955 unop( Iop_8Uto64,
20956 load( Ity_I8, irx_addr ) ),
20957 mkU8( 8 * (7 - i) ) ) );
20958 assign( tmp_hi[i+1],
20959 binop( Iop_Or64,
20960 mkexpr( byte[i] ), mkexpr( tmp_hi[i] ) ) );
20963 for (i = 0; i < 8; i++) {
20964 byte[i + 8] = newTemp(Ity_I64);
20965 tmp_low[i+1] = newTemp(Ity_I64);
20967 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
20968 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20969 ea_off += 1;
20971 /* Instruction always loads in Big Endian format */
20972 assign( byte[i+8], binop( Iop_Shl64,
20973 unop( Iop_8Uto64,
20974 load( Ity_I8, irx_addr ) ),
20975 mkU8( 8 * (7 - i) ) ) );
20976 assign( tmp_low[i+1], binop( Iop_Or64,
20977 mkexpr( byte[i+8] ),
20978 mkexpr( tmp_low[i] ) ) );
20981 /* Create mask to clear the right most 16 - nb bytes, set to zero
20982 * if nb= 0.
20984 assign( mask, binop( Iop_AndV128,
20985 binop( Iop_ShlV128,
20986 binop( Iop_ShrV128,
20987 mkV128( 0xFFFF ),
20988 unop( Iop_64to8, mkexpr( mask_shift ) ) ),
20989 unop( Iop_64to8, mkexpr( mask_shift ) ) ),
20990 unop( Iop_NotV128, mkexpr( nb_zero ) ) ) );
20992 putVSReg( XT, binop( Iop_AndV128,
20993 mkexpr( mask ),
20994 binop( Iop_64HLtoV128,
20995 mkexpr( tmp_hi[8] ),
20996 mkexpr( tmp_low[8] ) ) ) );
20997 break;
21000 case 0x16C: // lxvwsx
21002 IRTemp data = newTemp( Ity_I64 );
21004 DIP("lxvwsx %u,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
21006 /* The load is a 64-bit fetch that is Endian aware, just want
21007 * the lower 32 bits. */
21008 if ( host_endness == VexEndnessBE ) {
21009 UInt ea_off = 4;
21010 IRExpr* irx_addr;
21012 irx_addr =
21013 binop( mkSzOp( ty, Iop_Sub8 ), mkexpr( EA ),
21014 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21016 assign( data, binop( Iop_And64,
21017 load( Ity_I64, irx_addr ),
21018 mkU64( 0xFFFFFFFF ) ) );
21020 } else {
21021 assign( data, binop( Iop_And64,
21022 load( Ity_I64, mkexpr( EA ) ),
21023 mkU64( 0xFFFFFFFF ) ) );
21026 /* Take lower 32-bits and spat across the four word positions */
21027 putVSReg( XT,
21028 binop( Iop_64HLtoV128,
21029 binop( Iop_Or64,
21030 mkexpr( data ),
21031 binop( Iop_Shl64,
21032 mkexpr( data ),
21033 mkU8( 32 ) ) ),
21034 binop( Iop_Or64,
21035 mkexpr( data ),
21036 binop( Iop_Shl64,
21037 mkexpr( data ),
21038 mkU8( 32 ) ) ) ) );
21039 break;
21042 case 0x20C: // lxsspx (Load VSX Scalar Single-Precision Indexed)
21044 IRExpr * exp;
21045 DIP("lxsspx %d,r%u,r%u\n", XT, rA_addr, rB_addr);
21046 /* Take 32-bit floating point value in the upper half of the fetched
21047 * 64-bit value, convert to 64-bit floating point value and load into
21048 * top word of V128.
21050 exp = unop( Iop_ReinterpF64asI64,
21051 unop( Iop_F32toF64,
21052 unop( Iop_ReinterpI32asF32,
21053 load( Ity_I32, mkexpr( EA ) ) ) ) );
21055 putVSReg( XT, binop( Iop_64HLtoV128, exp, mkU64( 0 ) ) );
21056 break;
21058 case 0x24C: // lxsdx
21060 IRExpr * exp;
21061 DIP("lxsdx %d,r%u,r%u\n", XT, rA_addr, rB_addr);
21062 exp = load( Ity_I64, mkexpr( EA ) );
21063 // We need to pass an expression of type Ity_V128 with putVSReg, but the load
21064 // we just performed is only a DW. But since the contents of VSR[XT] element 1
21065 // are undefined after this operation, we can just do a splat op.
21066 putVSReg( XT, binop( Iop_64HLtoV128, exp, exp ) );
21067 break;
21070 case 0x30D: // lxsibzx
21072 IRExpr *byte;
21073 IRExpr* irx_addr;
21075 DIP("lxsibzx %u,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
21077 if ( host_endness == VexEndnessBE )
21078 irx_addr = binop( Iop_Sub64, mkexpr( EA ), mkU64( 7 ) );
21080 else
21081 irx_addr = mkexpr( EA );
21083 byte = load( Ity_I64, irx_addr );
21084 putVSReg( XT, binop( Iop_64HLtoV128,
21085 binop( Iop_And64,
21086 byte,
21087 mkU64( 0xFF ) ),
21088 mkU64( 0 ) ) );
21089 break;
21092 case 0x32D: // lxsihzx
21094 IRExpr *byte;
21095 IRExpr* irx_addr;
21097 DIP("lxsihzx %u,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
21099 if ( host_endness == VexEndnessBE )
21100 irx_addr = binop( Iop_Sub64, mkexpr( EA ), mkU64( 6 ) );
21102 else
21103 irx_addr = mkexpr( EA );
21105 byte = load( Ity_I64, irx_addr );
21106 putVSReg( XT, binop( Iop_64HLtoV128,
21107 binop( Iop_And64,
21108 byte,
21109 mkU64( 0xFFFF ) ),
21110 mkU64( 0 ) ) );
21111 break;
21113 case 0x34C: // lxvd2x
21115 IRExpr *t128;
21116 DIP("lxvd2x %d,r%u,r%u\n", XT, rA_addr, rB_addr);
21117 t128 = load( Ity_V128, mkexpr( EA ) );
21119 /* The data in the vec register should be in big endian order.
21120 So if we just did a little endian load then swap around the
21121 high and low double words. */
21122 if (host_endness == VexEndnessLE) {
21123 IRTemp high = newTemp(Ity_I64);
21124 IRTemp low = newTemp(Ity_I64);
21125 assign( high, unop(Iop_V128HIto64, t128) );
21126 assign( low, unop(Iop_V128to64, t128) );
21127 t128 = binop( Iop_64HLtoV128, mkexpr (low), mkexpr (high) );
21130 putVSReg( XT, t128 );
21131 break;
21133 case 0x14C: // lxvdsx
21135 IRTemp data = newTemp(Ity_I64);
21136 DIP("lxvdsx %d,r%u,r%u\n", XT, rA_addr, rB_addr);
21137 assign( data, load( Ity_I64, mkexpr( EA ) ) );
21138 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( data ), mkexpr( data ) ) );
21139 break;
21141 case 0x30C:
21143 IRExpr *t0;
21145 DIP("lxvw4x %u,r%u,r%u\n", XT, rA_addr, rB_addr);
21147 /* The load will result in the data being in BE order. */
21148 if (host_endness == VexEndnessLE) {
21149 IRExpr *t0_BE;
21150 IRTemp perm_LE = newTemp(Ity_V128);
21152 t0_BE = load( Ity_V128, mkexpr( EA ) );
21154 /* Permute the data to LE format */
21155 assign( perm_LE, binop( Iop_64HLtoV128, mkU64(0x0c0d0e0f08090a0bULL),
21156 mkU64(0x0405060700010203ULL)));
21158 t0 = binop( Iop_Perm8x16, t0_BE, mkexpr(perm_LE) );
21159 } else {
21160 t0 = load( Ity_V128, mkexpr( EA ) );
21163 putVSReg( XT, t0 );
21164 break;
21167 case 0x32C: // lxvh8x
21169 DIP("lxvh8x %u,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
21171 IRTemp h_word[8];
21172 int i;
21173 UInt ea_off = 0;
21174 IRExpr* irx_addr;
21175 IRTemp tmp_low[5];
21176 IRTemp tmp_hi[5];
21178 tmp_low[0] = newTemp( Ity_I64 );
21179 tmp_hi[0] = newTemp( Ity_I64 );
21180 assign( tmp_low[0], mkU64( 0 ) );
21181 assign( tmp_hi[0], mkU64( 0 ) );
21183 for ( i = 0; i < 4; i++ ) {
21184 h_word[i] = newTemp(Ity_I64);
21185 tmp_low[i+1] = newTemp(Ity_I64);
21187 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21188 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21189 ea_off += 2;
21191 assign( h_word[i], binop( Iop_Shl64,
21192 unop( Iop_16Uto64,
21193 load( Ity_I16, irx_addr ) ),
21194 mkU8( 16 * ( 3 - i ) ) ) );
21196 assign( tmp_low[i+1],
21197 binop( Iop_Or64,
21198 mkexpr( h_word[i] ), mkexpr( tmp_low[i] ) ) );
21201 for ( i = 0; i < 4; i++ ) {
21202 h_word[i+4] = newTemp( Ity_I64 );
21203 tmp_hi[i+1] = newTemp( Ity_I64 );
21205 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21206 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21207 ea_off += 2;
21209 assign( h_word[i+4], binop( Iop_Shl64,
21210 unop( Iop_16Uto64,
21211 load( Ity_I16, irx_addr ) ),
21212 mkU8( 16 * ( 3 - i ) ) ) );
21214 assign( tmp_hi[i+1], binop( Iop_Or64,
21215 mkexpr( h_word[i+4] ),
21216 mkexpr( tmp_hi[i] ) ) );
21218 putVSReg( XT, binop( Iop_64HLtoV128,
21219 mkexpr( tmp_low[4] ), mkexpr( tmp_hi[4] ) ) );
21220 break;
21223 case 0x36C: // lxvb16x
21225 DIP("lxvb16x %u,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
21227 /* The result of lxvb16x should be the same on big and little
21228 endian systems. We do a host load, then reverse the bytes in
21229 the double words. If the host load was little endian we swap
21230 them around again. */
21232 IRTemp high = newTemp(Ity_I64);
21233 IRTemp high_rev = newTemp(Ity_I64);
21234 IRTemp low = newTemp(Ity_I64);
21235 IRTemp low_rev = newTemp(Ity_I64);
21237 IRExpr *t128 = load( Ity_V128, mkexpr( EA ) );
21239 assign( high, unop(Iop_V128HIto64, t128) );
21240 assign( high_rev, unop(Iop_Reverse8sIn64_x1, mkexpr(high)) );
21241 assign( low, unop(Iop_V128to64, t128) );
21242 assign( low_rev, unop(Iop_Reverse8sIn64_x1, mkexpr(low)) );
21244 if (host_endness == VexEndnessLE)
21245 t128 = binop( Iop_64HLtoV128, mkexpr (low_rev), mkexpr (high_rev) );
21246 else
21247 t128 = binop( Iop_64HLtoV128, mkexpr (high_rev), mkexpr (low_rev) );
21249 putVSReg( XT, t128 );
21250 break;
21253 default:
21254 vex_printf( "dis_vx_load(ppc)(opc2)\n" );
21255 return False;
21257 return True;
21261 * VSX Move Instructions
21263 static Bool
21264 dis_vx_move ( UInt theInstr )
21266 /* XX1-Form */
21267 UChar opc1 = ifieldOPC( theInstr );
21268 UChar XS = ifieldRegXS( theInstr );
21269 UChar rA_addr = ifieldRegA( theInstr );
21270 UChar rB_addr = ifieldRegB( theInstr );
21271 IRTemp vS = newTemp( Ity_V128 );
21272 UInt opc2 = ifieldOPClo10( theInstr );
21273 IRType ty = Ity_I64;
21275 if ( opc1 != 0x1F ) {
21276 vex_printf( "dis_vx_move(ppc)(instr)\n" );
21277 return False;
21280 switch (opc2) {
21281 case 0x133: // mfvsrld RA,XS Move From VSR Lower Doubleword
21282 DIP("mfvsrld %u,r%u\n", (UInt)XS, rA_addr);
21284 assign( vS, getVSReg( XS ) );
21285 putIReg( rA_addr, unop(Iop_V128to64, mkexpr( vS) ) );
21287 break;
21289 case 0x193: // mfvsrdd XT,RA,RB Move to VSR Double Doubleword
21291 IRTemp tmp = newTemp( Ity_I32 );
21293 DIP("mfvsrdd %u,r%u\n", (UInt)XS, rA_addr);
21295 assign( tmp, unop( Iop_64to32, getIReg(rA_addr) ) );
21296 assign( vS, binop( Iop_64HLtoV128,
21297 binop( Iop_32HLto64,
21298 mkexpr( tmp ),
21299 mkexpr( tmp ) ),
21300 binop( Iop_32HLto64,
21301 mkexpr( tmp ),
21302 mkexpr( tmp ) ) ) );
21303 putVSReg( XS, mkexpr( vS ) );
21305 break;
21307 case 0x1B3: // mtvsrws XT,RA Move to VSR word & Splat
21309 IRTemp rA = newTemp( ty );
21310 IRTemp rB = newTemp( ty );
21312 DIP("mfvsrws %u,r%u\n", (UInt)XS, rA_addr);
21314 if ( rA_addr == 0 )
21315 assign( rA, mkU64 ( 0 ) );
21316 else
21317 assign( rA, getIReg(rA_addr) );
21319 assign( rB, getIReg(rB_addr) );
21320 assign( vS, binop( Iop_64HLtoV128, mkexpr( rA ), mkexpr( rB ) ) );
21321 putVSReg( XS, mkexpr( vS ) );
21323 break;
21325 default:
21326 vex_printf( "dis_vx_move(ppc)(opc2)\n" );
21327 return False;
21329 return True;
21333 * VSX Store Instructions
21334 * NOTE: VSX supports word-aligned storage access.
21336 static Bool
21337 dis_vx_store ( UInt theInstr )
21339 /* XX1-Form */
21340 UChar opc1 = ifieldOPC( theInstr );
21341 UChar XS = ifieldRegXS( theInstr );
21342 UChar rA_addr = ifieldRegA( theInstr );
21343 UChar rB_addr = ifieldRegB( theInstr );
21344 IRTemp vS = newTemp( Ity_V128 );
21345 UInt opc2 = ifieldOPClo10( theInstr );
21347 IRType ty = mode64 ? Ity_I64 : Ity_I32;
21348 IRTemp EA = newTemp( ty );
21350 if (opc1 != 0x1F) {
21351 vex_printf( "dis_vx_store(ppc)(instr)\n" );
21352 return False;
21355 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
21356 assign( vS, getVSReg( XS ) );
21358 switch (opc2) {
21359 case 0x08C:
21361 /* Need the next to the most significant 32-bit word from
21362 * the 128-bit vector.
21364 IRExpr * high64, * low32;
21365 DIP("stxsiwx %d,r%u,r%u\n", XS, rA_addr, rB_addr);
21366 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
21367 low32 = unop( Iop_64to32, high64 );
21368 store( mkexpr( EA ), low32 );
21369 break;
21372 case 0x18C: // stxvx Store VSX Vector Indexed
21374 UInt ea_off = 0;
21375 IRExpr* irx_addr;
21376 IRTemp word0 = newTemp( Ity_I64 );
21377 IRTemp word1 = newTemp( Ity_I64 );
21378 IRTemp word2 = newTemp( Ity_I64 );
21379 IRTemp word3 = newTemp( Ity_I64 );
21380 DIP("stxvx %u,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21382 assign( word0, binop( Iop_Shr64,
21383 unop( Iop_V128HIto64, mkexpr( vS ) ),
21384 mkU8( 32 ) ) );
21386 assign( word1, binop( Iop_And64,
21387 unop( Iop_V128HIto64, mkexpr( vS ) ),
21388 mkU64( 0xFFFFFFFF ) ) );
21390 assign( word2, binop( Iop_Shr64,
21391 unop( Iop_V128to64, mkexpr( vS ) ),
21392 mkU8( 32 ) ) );
21394 assign( word3, binop( Iop_And64,
21395 unop( Iop_V128to64, mkexpr( vS ) ),
21396 mkU64( 0xFFFFFFFF ) ) );
21398 if (host_endness == VexEndnessBE) {
21399 store( mkexpr( EA ), unop( Iop_64to32, mkexpr( word0 ) ) );
21401 ea_off += 4;
21402 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21403 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21405 store( irx_addr, unop( Iop_64to32, mkexpr( word1 ) ) );
21407 ea_off += 4;
21408 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21409 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21411 store( irx_addr, unop( Iop_64to32, mkexpr( word2 ) ) );
21412 ea_off += 4;
21413 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21414 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21416 store( irx_addr, unop( Iop_64to32, mkexpr( word3 ) ) );
21417 } else {
21418 store( mkexpr( EA ), unop( Iop_64to32, mkexpr( word3 ) ) );
21420 ea_off += 4;
21421 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21422 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21424 store( irx_addr, unop( Iop_64to32, mkexpr( word2 ) ) );
21426 ea_off += 4;
21427 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21428 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21430 store( irx_addr, unop( Iop_64to32, mkexpr( word1 ) ) );
21431 ea_off += 4;
21432 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21433 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21435 store( irx_addr, unop( Iop_64to32, mkexpr( word0 ) ) );
21437 break;
21440 case 0x18D: // stxvl Store VSX Vector Indexed
21442 UInt ea_off = 0;
21443 IRExpr* irx_addr;
21444 IRTemp word0 = newTemp( Ity_I64 );
21445 IRTemp word1 = newTemp( Ity_I64 );
21446 IRTemp word2 = newTemp( Ity_I64 );
21447 IRTemp word3 = newTemp( Ity_I64 );
21448 IRTemp shift = newTemp( Ity_I8 );
21449 IRTemp nb_gt16 = newTemp( Ity_I8 );
21450 IRTemp nb_zero = newTemp( Ity_V128 );
21451 IRTemp nb = newTemp( Ity_I8 );
21452 IRTemp nb_field = newTemp( Ity_I64 );
21453 IRTemp n_bytes = newTemp( Ity_I8 );
21454 IRTemp base_addr = newTemp( ty );
21455 IRTemp current_mem = newTemp( Ity_V128 );
21456 IRTemp store_val = newTemp( Ity_V128 );
21457 IRTemp nb_mask = newTemp( Ity_V128 );
21459 DIP("stxvl %u,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21461 assign( nb_field, binop( Iop_Shr64,
21462 getIReg(rB_addr),
21463 mkU8( 56 ) ) );
21465 assign( nb, unop( Iop_64to8, mkexpr( nb_field ) ) );
21467 /* nb_gt16 will be all zeros if nb > 16 */
21468 assign( nb_gt16, unop( Iop_1Sto8,
21469 binop( Iop_CmpLT64U,
21470 binop( Iop_Shr64,
21471 mkexpr( nb_field ),
21472 mkU8( 4 ) ),
21473 mkU64( 1 ) ) ) );
21475 /* nb_zero is 0xFF..FF if the nb_field = 0 */
21476 assign( nb_zero, binop( Iop_64HLtoV128,
21477 unop( Iop_1Sto64,
21478 binop( Iop_CmpEQ64,
21479 mkexpr( nb_field ),
21480 mkU64( 0 ) ) ),
21481 unop( Iop_1Sto64,
21482 binop( Iop_CmpEQ64,
21483 mkexpr( nb_field ),
21484 mkU64( 0 ) ) ) ) );
21486 /* set n_bytes to 0 if nb >= 16. Otherwise, set to nb. */
21487 assign( n_bytes, binop( Iop_And8, mkexpr( nb ), mkexpr( nb_gt16 ) ) );
21488 assign( shift, unop( Iop_64to8,
21489 binop( Iop_Mul64,
21490 binop( Iop_Sub64,
21491 mkU64( 16 ),
21492 unop( Iop_8Uto64,
21493 mkexpr( n_bytes ) ) ),
21494 mkU64( 8 ) ) ) );
21496 /* We only have a 32-bit store function. So, need to fetch the
21497 * contents of memory merge with the store value and do two
21498 * 32-byte stores so we preserve the contents of memory not
21499 * addressed by nb.
21501 assign( base_addr, ea_rAor0( rA_addr ) );
21503 assign( current_mem,
21504 binop( Iop_64HLtoV128,
21505 load( Ity_I64,
21506 binop( mkSzOp( ty, Iop_Add8 ),
21507 mkexpr( base_addr ),
21508 ty == Ity_I64 ? mkU64( 8 ) : mkU32( 8 )
21509 ) ),
21510 load( Ity_I64, mkexpr( base_addr ) ) ) );
21512 /* Set the nb_mask to all zeros if nb = 0 so the current contents
21513 * of memory get written back without modifications.
21515 * The store_val is a combination of the current memory value
21516 * and the bytes you want to store. The nb_mask selects the
21517 * bytes you want stored from Vs.
21519 assign( nb_mask,
21520 binop( Iop_OrV128,
21521 binop( Iop_AndV128,
21522 mkexpr( nb_zero ),
21523 mkV128( 0 ) ),
21524 binop( Iop_AndV128,
21525 binop( Iop_ShrV128,
21526 mkV128( 0xFFFF ),
21527 mkexpr( shift ) ),
21528 unop( Iop_NotV128, mkexpr( nb_zero ) ) ) ) );
21530 assign( store_val,
21531 binop( Iop_OrV128,
21532 binop( Iop_AndV128,
21533 mkexpr( vS ),
21534 mkexpr( nb_mask ) ),
21535 binop( Iop_AndV128,
21536 unop( Iop_NotV128, mkexpr( nb_mask ) ),
21537 mkexpr( current_mem) ) ) );
21539 /* Store the value in 32-byte chunks */
21540 assign( word0, binop( Iop_Shr64,
21541 unop( Iop_V128HIto64, mkexpr( store_val ) ),
21542 mkU8( 32 ) ) );
21544 assign( word1, binop( Iop_And64,
21545 unop( Iop_V128HIto64, mkexpr( store_val ) ),
21546 mkU64( 0xFFFFFFFF ) ) );
21548 assign( word2, binop( Iop_Shr64,
21549 unop( Iop_V128to64, mkexpr( store_val ) ),
21550 mkU8( 32 ) ) );
21552 assign( word3, binop( Iop_And64,
21553 unop( Iop_V128to64, mkexpr( store_val ) ),
21554 mkU64( 0xFFFFFFFF ) ) );
21556 ea_off = 0;
21557 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21558 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21560 store( irx_addr, unop( Iop_64to32, mkexpr( word3 ) ) );
21562 ea_off += 4;
21563 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21564 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21566 store( irx_addr, unop( Iop_64to32, mkexpr( word2 ) ) );
21568 ea_off += 4;
21569 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21570 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21572 store( irx_addr, unop( Iop_64to32, mkexpr( word1 ) ) );
21574 ea_off += 4;
21575 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21576 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21578 store( irx_addr, unop( Iop_64to32, mkexpr( word0 ) ) );
21579 break;
21582 case 0x1AD: // stxvll (Store VSX Vector Left-justified with length XX1-form)
21584 UInt ea_off = 0;
21585 IRExpr* irx_addr;
21586 IRTemp word0[5];
21587 IRTemp word1[5];
21588 IRTemp word2[5];
21589 IRTemp word3[5];
21590 IRTemp shift = newTemp(Ity_I8);
21591 IRTemp nb_gt16 = newTemp(Ity_I8);
21592 IRTemp nb_zero = newTemp(Ity_V128);
21593 IRTemp nb = newTemp(Ity_I8);
21594 IRTemp nb_field = newTemp(Ity_I64);
21595 IRTemp n_bytes = newTemp(Ity_I8);
21596 IRTemp base_addr = newTemp( ty );
21597 IRTemp current_mem = newTemp(Ity_V128);
21598 IRTemp store_val = newTemp(Ity_V128);
21599 IRTemp nb_mask = newTemp(Ity_V128);
21600 IRTemp mask = newTemp( Ity_I64 );
21601 IRTemp byte[16];
21602 IRTemp tmp_low[9];
21603 IRTemp tmp_hi[9];
21604 IRTemp nb_field_compare_zero = newTemp( Ity_I64 );
21605 Int i;
21607 DIP("stxvll %u,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21609 assign( nb_field, binop( Iop_Shr64,
21610 getIReg(rB_addr),
21611 mkU8( 56 ) ) );
21612 assign( nb, unop( Iop_64to8, mkexpr( nb_field ) ) );
21613 assign( mask, mkU64( 0xFFFFFFFFFFFFFFFFULL ) );
21615 /* nb_gt16 will be all zeros if nb > 16 */
21616 assign( nb_gt16, unop( Iop_1Sto8,
21617 binop( Iop_CmpLT64U,
21618 binop( Iop_Shr64,
21619 mkexpr( nb_field ),
21620 mkU8( 4 ) ),
21621 mkU64( 1 ) ) ) );
21623 assign( nb_field_compare_zero, unop( Iop_1Sto64,
21624 binop( Iop_CmpEQ64,
21625 mkexpr( nb_field ),
21626 mkU64( 0 ) ) ) );
21628 /* nb_zero is 0xFF..FF if the nb_field = 0 */
21629 assign( nb_zero, binop( Iop_64HLtoV128,
21630 mkexpr( nb_field_compare_zero ),
21631 mkexpr( nb_field_compare_zero ) ) );
21634 /* set n_bytes to 0 if nb >= 16. Otherwise, set to nb. */
21635 assign( n_bytes, binop( Iop_And8, mkexpr( nb ), mkexpr( nb_gt16 ) ) );
21636 assign( shift,
21637 unop( Iop_64to8,
21638 binop( Iop_Mul64,
21639 binop( Iop_Sub64,
21640 mkU64( 16 ),
21641 unop( Iop_8Uto64, mkexpr( n_bytes ) )),
21642 mkU64( 8 ) ) ) );
21644 /* We only have a 32-bit store function. So, need to fetch the
21645 * contents of memory merge with the store value and do two
21646 * 32-byte stores so we preserve the contents of memory not
21647 * addressed by nb.
21649 assign( base_addr, ea_rAor0( rA_addr ) );
21650 /* fetch all 16 bytes and store in Big Endian format */
21651 word0[0] = newTemp(Ity_I64);
21652 assign( word0[0], mkU64( 0 ) );
21654 word1[0] = newTemp(Ity_I64);
21655 assign( word1[0], mkU64( 0 ) );
21657 word2[0] = newTemp(Ity_I64);
21658 assign( word2[0], mkU64( 0 ) );
21660 word3[0] = newTemp(Ity_I64);
21661 assign( word3[0], mkU64( 0 ) );
21663 for (i = 0; i < 4; i++) {
21664 word0[i+1] = newTemp(Ity_I64);
21666 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21667 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21668 ea_off += 1;
21670 /* Instruction always loads in Big Endian format */
21671 assign( word0[i+1],
21672 binop( Iop_Or64,
21673 binop( Iop_Shl64,
21674 unop( Iop_8Uto64,
21675 load( Ity_I8,
21676 irx_addr ) ),
21677 mkU8( (3-i)*8 ) ),
21678 mkexpr( word0[i] ) ) );
21681 for (i = 0; i < 4; i++) {
21682 word1[i+1] = newTemp(Ity_I64);
21684 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21685 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21686 ea_off += 1;
21688 /* Instruction always loads in Big Endian format */
21689 assign( word1[i+1],
21690 binop( Iop_Or64,
21691 binop( Iop_Shl64,
21692 unop( Iop_8Uto64,
21693 load( Ity_I8,
21694 irx_addr ) ),
21695 mkU8( (3-i)*8 ) ),
21696 mkexpr( word1[i] ) ) );
21698 for (i = 0; i < 4; i++) {
21699 word2[i+1] = newTemp(Ity_I64);
21701 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21702 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21703 ea_off += 1;
21705 /* Instruction always loads in Big Endian format */
21706 assign( word2[i+1],
21707 binop( Iop_Or64,
21708 binop( Iop_Shl64,
21709 unop( Iop_8Uto64,
21710 load( Ity_I8,
21711 irx_addr ) ),
21712 mkU8( (3-i)*8 ) ),
21713 mkexpr( word2[i] ) ) );
21715 for (i = 0; i < 4; i++) {
21716 word3[i+1] = newTemp(Ity_I64);
21718 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21719 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21720 ea_off += 1;
21722 /* Instruction always loads in Big Endian format */
21723 assign( word3[i+1],
21724 binop( Iop_Or64,
21725 binop( Iop_Shl64,
21726 unop( Iop_8Uto64,
21727 load( Ity_I8,
21728 irx_addr ) ),
21729 mkU8( (3-i)*8 ) ),
21730 mkexpr( word3[i] ) ) );
21734 assign( current_mem,
21735 binop( Iop_64HLtoV128,
21736 binop( Iop_Or64,
21737 binop( Iop_Shl64,
21738 mkexpr( word0[4] ),
21739 mkU8( 32 ) ),
21740 mkexpr( word1[4] ) ),
21741 binop( Iop_Or64,
21742 binop( Iop_Shl64,
21743 mkexpr( word2[4] ),
21744 mkU8( 32 ) ),
21745 mkexpr( word3[4] ) ) ) );
21747 /* Set the nb_mask to all zeros if nb = 0 so the current contents
21748 * of memory get written back without modifications.
21750 * The store_val is a combination of the current memory value
21751 * and the bytes you want to store. The nb_mask selects the
21752 * bytes you want stored from Vs.
21754 /* The instruction always uses Big Endian order */
21755 assign( nb_mask,
21756 binop( Iop_OrV128,
21757 binop( Iop_AndV128,
21758 binop( Iop_ShlV128,
21759 binop( Iop_ShrV128,
21760 binop( Iop_64HLtoV128,
21761 mkexpr( mask ),
21762 mkexpr( mask ) ),
21763 mkexpr( shift ) ),
21764 mkexpr( shift ) ),
21765 unop( Iop_NotV128, mkexpr( nb_zero ) ) ),
21766 binop( Iop_AndV128,
21767 mkexpr( nb_zero ),
21768 binop( Iop_64HLtoV128,
21769 mkU64( 0x0 ),
21770 mkU64( 0x0 ) ) ) ) );
21772 assign( store_val,
21773 binop( Iop_OrV128,
21774 binop( Iop_AndV128,
21775 mkexpr( vS ),
21776 mkexpr( nb_mask ) ),
21777 binop( Iop_AndV128,
21778 unop( Iop_NotV128, mkexpr( nb_mask ) ),
21779 mkexpr( current_mem) ) ) );
21781 /* store the merged value in Big Endian format */
21782 tmp_low[0] = newTemp(Ity_I64);
21783 tmp_hi[0] = newTemp(Ity_I64);
21784 assign( tmp_low[0], mkU64( 0 ) );
21785 assign( tmp_hi[0], mkU64( 0 ) );
21787 for (i = 0; i < 8; i++) {
21788 byte[i] = newTemp(Ity_I64);
21789 byte[i+8] = newTemp(Ity_I64);
21790 tmp_low[i+1] = newTemp(Ity_I64);
21791 tmp_hi[i+1] = newTemp(Ity_I64);
21793 assign( byte[i], binop( Iop_And64,
21794 binop( Iop_Shr64,
21795 unop( Iop_V128HIto64,
21796 mkexpr( store_val ) ),
21797 mkU8( (7-i)*8 ) ),
21798 mkU64( 0xFF ) ) );
21799 assign( byte[i+8], binop( Iop_And64,
21800 binop( Iop_Shr64,
21801 unop( Iop_V128to64,
21802 mkexpr( store_val ) ),
21803 mkU8( (7-i)*8 ) ),
21804 mkU64( 0xFF ) ) );
21806 assign( tmp_low[i+1],
21807 binop( Iop_Or64,
21808 mkexpr( tmp_low[i] ),
21809 binop( Iop_Shl64, mkexpr( byte[i] ), mkU8( i*8 ) ) ) );
21810 assign( tmp_hi[i+1],
21811 binop( Iop_Or64,
21812 mkexpr( tmp_hi[i] ),
21813 binop( Iop_Shl64, mkexpr( byte[i+8] ),
21814 mkU8( i*8 ) ) ) );
21817 /* Store the value in 32-byte chunks */
21818 ea_off = 0;
21819 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21820 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21822 store( irx_addr, unop( Iop_64to32, mkexpr( tmp_low[8] ) ) );
21824 ea_off += 4;
21825 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21826 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21828 store( irx_addr, unop( Iop_64HIto32, mkexpr( tmp_low[8] ) ) );
21830 ea_off += 4;
21831 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21832 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21834 store( irx_addr, unop( Iop_64to32, mkexpr( tmp_hi[8] ) ) );
21836 ea_off += 4;
21837 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21838 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21840 store( irx_addr, unop( Iop_64HIto32, mkexpr( tmp_hi[8] ) ) );
21842 break;
21845 case 0x28C:
21847 IRTemp high64 = newTemp(Ity_F64);
21848 IRTemp val32 = newTemp(Ity_I32);
21849 DIP("stxsspx %u,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21850 assign(high64, unop( Iop_ReinterpI64asF64,
21851 unop( Iop_V128HIto64, mkexpr( vS ) ) ) );
21852 assign(val32, unop( Iop_ReinterpF32asI32,
21853 unop( Iop_TruncF64asF32,
21854 mkexpr(high64) ) ) );
21855 store( mkexpr( EA ), mkexpr( val32 ) );
21856 break;
21858 case 0x2CC:
21860 IRExpr * high64;
21861 DIP("stxsdx %u,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21862 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
21863 store( mkexpr( EA ), high64 );
21864 break;
21867 case 0x38D: // stxsibx
21869 IRExpr *stored_word;
21870 IRTemp byte_to_store = newTemp( Ity_I64 );
21872 DIP("stxsibx %u,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21874 /* Can't store just a byte, need to fetch the word at EA merge data
21875 * and store.
21877 stored_word = load( Ity_I64, mkexpr( EA ) );
21878 assign( byte_to_store, binop( Iop_And64,
21879 unop( Iop_V128HIto64,
21880 mkexpr( vS ) ),
21881 mkU64( 0xFF ) ) );
21883 store( mkexpr( EA ), binop( Iop_Or64,
21884 binop( Iop_And64,
21885 stored_word,
21886 mkU64( 0xFFFFFFFFFFFFFF00 ) ),
21887 mkexpr( byte_to_store ) ) );
21888 break;
21891 case 0x3AD: // stxsihx
21893 IRExpr *stored_word;
21894 IRTemp byte_to_store = newTemp( Ity_I64 );
21896 DIP("stxsihx %u,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21898 /* Can't store just a halfword, need to fetch the word at EA merge data
21899 * and store.
21901 stored_word = load( Ity_I64, mkexpr( EA ) );
21902 assign( byte_to_store, binop( Iop_And64,
21903 unop( Iop_V128HIto64,
21904 mkexpr( vS ) ),
21905 mkU64( 0xFFFF ) ) );
21907 store( mkexpr( EA ), binop( Iop_Or64,
21908 binop( Iop_And64,
21909 stored_word,
21910 mkU64( 0xFFFFFFFFFFFF0000 ) ),
21911 mkexpr( byte_to_store ) ) );
21912 break;
21915 case 0x3CC:
21917 IRExpr * high64, *low64;
21918 DIP("stxvd2x %u,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21919 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
21920 low64 = unop( Iop_V128to64, mkexpr( vS ) );
21921 store( mkexpr( EA ), high64 );
21922 store( binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21923 ty == Ity_I64 ? mkU64( 8 ) : mkU32( 8 ) ), low64 );
21924 break;
21926 case 0x38C:
21928 UInt ea_off = 0;
21929 IRExpr* irx_addr;
21930 IRTemp hi64 = newTemp( Ity_I64 );
21931 IRTemp lo64 = newTemp( Ity_I64 );
21933 DIP("stxvw4x %u,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21935 // This instruction supports word-aligned stores, so EA may not be
21936 // quad-word aligned. Therefore, do 4 individual word-size stores.
21937 assign( hi64, unop( Iop_V128HIto64, mkexpr( vS ) ) );
21938 assign( lo64, unop( Iop_V128to64, mkexpr( vS ) ) );
21939 store( mkexpr( EA ), unop( Iop_64HIto32, mkexpr( hi64 ) ) );
21940 ea_off += 4;
21941 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21942 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21943 store( irx_addr, unop( Iop_64to32, mkexpr( hi64 ) ) );
21944 ea_off += 4;
21945 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21946 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21947 store( irx_addr, unop( Iop_64HIto32, mkexpr( lo64 ) ) );
21948 ea_off += 4;
21949 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21950 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21951 store( irx_addr, unop( Iop_64to32, mkexpr( lo64 ) ) );
21953 break;
21955 case 0x3AC: // stxvh8x Store VSX Vector Halfword*8 Indexed
21957 UInt ea_off = 0;
21958 IRExpr* irx_addr;
21959 IRTemp half_word0 = newTemp( Ity_I64 );
21960 IRTemp half_word1 = newTemp( Ity_I64 );
21961 IRTemp half_word2 = newTemp( Ity_I64 );
21962 IRTemp half_word3 = newTemp( Ity_I64 );
21963 IRTemp half_word4 = newTemp( Ity_I64 );
21964 IRTemp half_word5 = newTemp( Ity_I64 );
21965 IRTemp half_word6 = newTemp( Ity_I64 );
21966 IRTemp half_word7 = newTemp( Ity_I64 );
21968 DIP("stxvb8x %u,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21970 assign( half_word0, binop( Iop_Shr64,
21971 unop( Iop_V128HIto64, mkexpr( vS ) ),
21972 mkU8( 48 ) ) );
21974 assign( half_word1, binop( Iop_And64,
21975 binop( Iop_Shr64,
21976 unop( Iop_V128HIto64, mkexpr( vS ) ),
21977 mkU8( 32 ) ),
21978 mkU64( 0xFFFF ) ) );
21980 assign( half_word2, binop( Iop_And64,
21981 binop( Iop_Shr64,
21982 unop( Iop_V128HIto64, mkexpr( vS ) ),
21983 mkU8( 16 ) ),
21984 mkU64( 0xFFFF ) ) );
21986 assign( half_word3, binop( Iop_And64,
21987 unop( Iop_V128HIto64, mkexpr( vS ) ),
21988 mkU64( 0xFFFF ) ) );
21990 assign( half_word4, binop( Iop_Shr64,
21991 unop( Iop_V128to64, mkexpr( vS ) ),
21992 mkU8( 48 ) ) );
21994 assign( half_word5, binop( Iop_And64,
21995 binop( Iop_Shr64,
21996 unop( Iop_V128to64, mkexpr( vS ) ),
21997 mkU8( 32 ) ),
21998 mkU64( 0xFFFF ) ) );
22000 assign( half_word6, binop( Iop_And64,
22001 binop( Iop_Shr64,
22002 unop( Iop_V128to64, mkexpr( vS ) ),
22003 mkU8( 16 ) ),
22004 mkU64( 0xFFFF ) ) );
22006 assign( half_word7, binop( Iop_And64,
22007 unop( Iop_V128to64, mkexpr( vS ) ),
22008 mkU64( 0xFFFF ) ) );
22010 /* Do the 32-bit stores. The store() does an Endian aware store. */
22011 if ( host_endness == VexEndnessBE ) {
22012 store( mkexpr( EA ), unop( Iop_64to32,
22013 binop( Iop_Or64,
22014 mkexpr( half_word1 ),
22015 binop( Iop_Shl64,
22016 mkexpr( half_word0 ),
22017 mkU8( 16 ) ) ) ) );
22019 ea_off += 4;
22020 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
22021 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
22024 store( irx_addr, unop( Iop_64to32,
22025 binop( Iop_Or64,
22026 mkexpr( half_word3 ),
22027 binop( Iop_Shl64,
22028 mkexpr( half_word2 ),
22029 mkU8( 16 ) ) ) ) );
22031 ea_off += 4;
22032 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
22033 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
22035 store( irx_addr, unop( Iop_64to32,
22036 binop( Iop_Or64,
22037 mkexpr( half_word5 ),
22038 binop( Iop_Shl64,
22039 mkexpr( half_word4 ),
22040 mkU8( 16 ) ) ) ) );
22041 ea_off += 4;
22042 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
22043 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
22045 store( irx_addr, unop( Iop_64to32,
22046 binop( Iop_Or64,
22047 mkexpr( half_word7 ),
22048 binop( Iop_Shl64,
22049 mkexpr( half_word6 ),
22050 mkU8( 16 ) ) ) ) );
22052 } else {
22053 store( mkexpr( EA ), unop( Iop_64to32,
22054 binop( Iop_Or64,
22055 mkexpr( half_word0 ),
22056 binop( Iop_Shl64,
22057 mkexpr( half_word1 ),
22058 mkU8( 16 ) ) ) ) );
22060 ea_off += 4;
22061 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
22062 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
22064 store( irx_addr, unop( Iop_64to32,
22065 binop( Iop_Or64,
22066 mkexpr( half_word2 ),
22067 binop( Iop_Shl64,
22068 mkexpr( half_word3 ),
22069 mkU8( 16 ) ) ) ) );
22070 ea_off += 4;
22071 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
22072 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
22074 store( irx_addr, unop( Iop_64to32,
22075 binop( Iop_Or64,
22076 mkexpr( half_word4 ),
22077 binop( Iop_Shl64,
22078 mkexpr( half_word5 ),
22079 mkU8( 16 ) ) ) ) );
22080 ea_off += 4;
22081 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
22082 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
22084 store( irx_addr, unop( Iop_64to32,
22085 binop( Iop_Or64,
22086 mkexpr( half_word6 ),
22087 binop( Iop_Shl64,
22088 mkexpr( half_word7 ),
22089 mkU8( 16 ) ) ) ) );
22091 break;
22094 case 0x3EC: // stxvb16x Store VSX Vector Byte*16 Indexed
22096 UInt ea_off = 0;
22097 int i;
22098 IRExpr* irx_addr;
22099 IRTemp byte[16];
22101 DIP("stxvb16x %u,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
22103 for ( i = 0; i < 8; i++ ) {
22104 byte[i] = newTemp( Ity_I64 );
22105 byte[i+8] = newTemp( Ity_I64 );
22107 assign( byte[i], binop( Iop_And64,
22108 binop( Iop_Shr64,
22109 unop( Iop_V128HIto64, mkexpr( vS ) ),
22110 mkU8( 56 - i*8 ) ),
22111 mkU64( 0xFF ) ) );
22113 assign( byte[i+8], binop( Iop_And64,
22114 binop( Iop_Shr64,
22115 unop( Iop_V128to64, mkexpr( vS ) ),
22116 mkU8( 56 - i*8) ),
22117 mkU64( 0xFF ) ) );
22120 if ( host_endness == VexEndnessBE ) {
22121 for ( i = 0; i < 16; i = i + 4) {
22122 irx_addr =
22123 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
22124 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
22126 store( irx_addr,
22127 unop( Iop_64to32,
22128 binop( Iop_Or64,
22129 binop( Iop_Or64,
22130 mkexpr( byte[i+3] ),
22131 binop( Iop_Shl64,
22132 mkexpr( byte[i+2] ),
22133 mkU8( 8 ) ) ),
22134 binop( Iop_Or64,
22135 binop( Iop_Shl64,
22136 mkexpr( byte[i+1] ),
22137 mkU8( 16 ) ),
22138 binop( Iop_Shl64,
22139 mkexpr( byte[i] ),
22140 mkU8( 24 ) ) ) ) ) );
22141 ea_off += 4;
22144 } else {
22145 for ( i = 0; i < 16; i = i + 4) {
22146 irx_addr =
22147 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
22148 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
22150 store( irx_addr,
22151 unop( Iop_64to32,
22152 binop( Iop_Or64,
22153 binop( Iop_Or64,
22154 mkexpr( byte[i] ),
22155 binop( Iop_Shl64,
22156 mkexpr( byte[i+1] ),
22157 mkU8( 8 ) ) ),
22158 binop( Iop_Or64,
22159 binop( Iop_Shl64,
22160 mkexpr( byte[i+2] ),
22161 mkU8( 16 ) ),
22162 binop( Iop_Shl64,
22163 mkexpr( byte[i+3] ),
22164 mkU8( 24 ) ) ) ) ) );
22166 ea_off += 4;
22169 break;
22172 default:
22173 vex_printf( "dis_vx_store(ppc)(opc2)\n" );
22174 return False;
22176 return True;
22179 static Bool
22180 dis_vx_Scalar_Round_to_quad_integer( UInt theInstr, const VexAbiInfo* vbi )
22182 /* The ISA 3.0 instructions supported in this function require
22183 * the underlying hardware platform that supports the ISA3.0
22184 * instruction set.
22186 /* XX1-Form */
22187 UChar opc1 = ifieldOPC( theInstr );
22188 UInt opc2 = IFIELD( theInstr, 1, 8 );
22189 UChar vT_addr = ifieldRegDS( theInstr );
22190 UChar vB_addr = ifieldRegB( theInstr );
22191 IRTemp vB = newTemp( Ity_F128 );
22192 IRTemp vT = newTemp( Ity_F128 );
22193 UChar EX = IFIELD( theInstr, 0, 1 );
22195 assign( vB, getF128Reg( vB_addr ) );
22196 if (opc1 != 0x3F) {
22197 vex_printf( "dis_vx_Scalar_Round_to_quad_integer(ppc)(instr)\n" );
22198 return False;
22200 switch (opc2) {
22201 case 0x005: // VSX Scalar Round to Quad-Precision Integer [with Inexact]
22203 UChar R = IFIELD( theInstr, 16, 1 );
22204 UChar RMC = IFIELD( theInstr, 9, 2 );
22206 /* Store the rm specification bits. Will extract them later when
22207 * the isntruction is issued.
22209 IRExpr* rm = mkU32( R << 3 | RMC << 1 | EX);
22211 if ( EX == 0 ) { // xsrqpi
22212 DIP("xsrqpi %d,v%d,v%d,%d\n", R, vT_addr, vB_addr, RMC);
22213 assign( vT, binop( Iop_F128toI128S, rm, mkexpr( vB ) ) );
22215 } else { // xsrqpix
22216 DIP("xsrqpix %d,v%d,v%d,%d\n", R, vT_addr, vB_addr, RMC);
22217 assign( vT, binop( Iop_F128toI128S, rm, mkexpr( vB ) ) );
22219 generate_store_FPRF( Ity_F128, vT, vbi );
22220 } /* case 0x005 */
22221 break;
22222 case 0x025: // xsrqpxp VSX Scalar Round Quad-Precision to
22223 // Double-Extended Precision
22225 UChar R = IFIELD( theInstr, 16, 1 );
22226 UChar RMC = IFIELD( theInstr, 9, 2 );
22228 /* Store the rm specification bits. Will extract them later when
22229 * the isntruction is issued.
22231 IRExpr* rm = mkU32( R << 3 | RMC << 1 );
22233 DIP("xsrqpxp %d,v%d,v%d,%d\n", R, vT_addr, vB_addr, RMC);
22234 assign( vT, binop( Iop_RndF128, rm, mkexpr( vB ) ) );
22235 generate_store_FPRF( Ity_F128, vT, vbi );
22236 } /* case 0x025 */
22237 break;
22238 default:
22239 vex_printf( "dis_vx_Scalar_Round_to_quad_integer(ppc)(opc2)\n" );
22240 return False;
22241 } /* switch opc2 */
22242 putF128Reg( vT_addr, mkexpr( vT ) );
22243 return True;
22246 static Bool
22247 dis_vx_Floating_Point_Arithmetic_quad_precision( UInt theInstr,
22248 const VexAbiInfo* vbi )
22250 /* The ISA 3.0 instructions supported in this function require
22251 * the underlying hardware platform that supports the ISA 3.0
22252 * instruction set.
22254 /* XX1-Form */
22255 UChar opc1 = ifieldOPC( theInstr );
22256 UInt opc2 = ifieldOPClo10( theInstr );
22257 UChar vT_addr = ifieldRegDS( theInstr );
22258 UChar vA_addr = ifieldRegA( theInstr );
22259 UChar vB_addr = ifieldRegB( theInstr );
22260 IRTemp vA = newTemp( Ity_F128 );
22261 IRTemp vB = newTemp( Ity_F128 );
22262 IRTemp vT = newTemp( Ity_F128 );
22263 IRExpr* rm = get_IR_roundingmode();
22264 UChar R0 = IFIELD( theInstr, 0, 1 );
22266 assign( vB, getF128Reg( vB_addr ) );
22268 if ( opc1 != 0x3F ) {
22269 vex_printf( "Erorr, dis_vx_Floating_Point_Arithmetic_quad_precision(ppc)(instr)\n" );
22270 return False;
22272 switch ( opc2 ) {
22273 case 0x004: // xsaddqp (VSX Scalar Add Quad-Precision[using round to Odd])
22275 assign( vA, getF128Reg( vA_addr ) );
22277 if ( R0 == 0 ) {
22278 /* rounding mode specified by RN. Issue inst with R0 = 0 */
22279 DIP("xsaddqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22280 assign( vT, triop( Iop_AddF128, rm, mkexpr( vA ), mkexpr( vB ) ) );
22282 } else {
22283 /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
22284 DIP("xsaddqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22285 assign( vT, triop( Iop_AddF128, set_round_to_Oddmode(),
22286 mkexpr( vA ), mkexpr( vB ) ) );
22288 generate_store_FPRF( Ity_F128, vT, vbi );
22289 break;
22291 case 0x024: // xsmulqp (VSX Scalar Multiply Quad-Precision[using round to Odd])
22293 assign( vA, getF128Reg( vA_addr ) );
22295 if ( R0 == 0 ) {
22296 /* rounding mode specified by RN. Issue inst with R0 = 0 */
22297 DIP("xsmulqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22298 assign( vT, triop( Iop_MulF128, rm, mkexpr( vA ), mkexpr( vB ) ) );
22300 } else {
22301 /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
22302 DIP("xsmulqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22303 assign( vT, triop( Iop_MulF128, set_round_to_Oddmode(), mkexpr( vA ),
22304 mkexpr( vB ) ) );
22306 generate_store_FPRF( Ity_F128, vT, vbi );
22307 break;
22309 case 0x184: // xsmaddqp (VSX Scalar Multiply add Quad-Precision[using round to Odd])
22311 /* instruction computes (vA * vB) + vC */
22312 IRTemp vC = newTemp( Ity_F128 );
22314 assign( vA, getF128Reg( vA_addr ) );
22315 assign( vC, getF128Reg( vT_addr ) );
22317 if ( R0 == 0 ) {
22318 /* rounding mode specified by RN. Issue inst with R0 = 0 */
22319 DIP("xsmaddqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22320 assign( vT,
22321 qop( Iop_MAddF128, rm, mkexpr( vA ),
22322 mkexpr( vC ), mkexpr( vB ) ) );
22324 } else {
22325 /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
22326 DIP("xsmaddqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22327 assign( vT,
22328 qop( Iop_MAddF128, set_round_to_Oddmode(), mkexpr( vA ),
22329 mkexpr( vC ), mkexpr( vB ) ) );
22331 generate_store_FPRF( Ity_F128, vT, vbi );
22332 break;
22334 case 0x1A4: // xsmsubqp (VSX Scalar Multiply Subtract Quad-Precision[using round to Odd])
22336 IRTemp vC = newTemp( Ity_F128 );
22338 assign( vA, getF128Reg( vA_addr ) );
22339 assign( vC, getF128Reg( vT_addr ) );
22341 if ( R0 == 0 ) {
22342 /* rounding mode specified by RN. Issue inst with R0 = 0 */
22343 DIP("xsmsubqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22344 assign( vT,
22345 qop( Iop_MSubF128, rm, mkexpr( vA ),
22346 mkexpr( vC ), mkexpr( vB ) ) );
22348 } else {
22349 /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
22350 DIP("xsmsubqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22351 assign( vT,
22352 qop( Iop_MSubF128, set_round_to_Oddmode(),
22353 mkexpr( vA ), mkexpr( vC ), mkexpr( vB ) ) );
22355 generate_store_FPRF( Ity_F128, vT, vbi );
22356 break;
22358 case 0x1C4: // xsnmaddqp (VSX Scalar Negative Multiply Add Quad-Precision[using round to Odd])
22360 IRTemp vC = newTemp( Ity_F128 );
22362 assign( vA, getF128Reg( vA_addr ) );
22363 assign( vC, getF128Reg( vT_addr ) );
22365 if ( R0 == 0 ) {
22366 /* rounding mode specified by RN. Issue inst with R0 = 0 */
22367 DIP("xsnmaddqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22368 assign( vT,
22369 qop( Iop_NegMAddF128, rm, mkexpr( vA ),
22370 mkexpr( vC ), mkexpr( vB ) ) );
22372 } else {
22373 /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
22374 DIP("xsnmaddqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22375 assign( vT,
22376 qop( Iop_NegMAddF128, set_round_to_Oddmode(),
22377 mkexpr( vA ), mkexpr( vC ), mkexpr( vB ) ) );
22379 generate_store_FPRF( Ity_F128, vT, vbi );
22380 break;
22382 case 0x1E4: // xsmsubqp (VSX Scalar Negatve Multiply Subtract Quad-Precision[using round to Odd])
22384 IRTemp vC = newTemp( Ity_F128 );
22386 assign( vA, getF128Reg( vA_addr ) );
22387 assign( vC, getF128Reg( vT_addr ) );
22389 if ( R0 == 0 ) {
22390 /* rounding mode specified by RN. Issue inst with R0 = 0 */
22391 DIP("xsnmsubqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22392 assign( vT,
22393 qop( Iop_NegMSubF128, rm, mkexpr( vA ),
22394 mkexpr( vC ), mkexpr( vB ) ) );
22396 } else {
22397 /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
22398 DIP("xsnmsubqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22399 assign( vT,
22400 qop( Iop_NegMSubF128, set_round_to_Oddmode(),
22401 mkexpr( vA ), mkexpr( vC ), mkexpr( vB ) ) );
22403 generate_store_FPRF( Ity_F128, vT, vbi );
22404 break;
22406 case 0x204: // xssubqp (VSX Scalar Subtract Quad-Precision[using round to Odd])
22408 assign( vA, getF128Reg( vA_addr ) );
22409 if ( R0 == 0 ) {
22410 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
22411 DIP("xssubqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22412 assign( vT, triop( Iop_SubF128, rm, mkexpr( vA ), mkexpr( vB ) ) );
22414 } else {
22415 /* use rounding mode specified by Round to odd. Issue inst with R0 = 1 */
22416 DIP("xssubqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22417 assign( vT, triop( Iop_SubF128, set_round_to_Oddmode(), mkexpr( vA ),
22418 mkexpr( vB ) ) );
22420 generate_store_FPRF( Ity_F128, vT, vbi );
22421 break;
22423 case 0x224: // xsdivqp (VSX Scalar Divide Quad-Precision[using round to Odd])
22425 assign( vA, getF128Reg( vA_addr ) );
22426 if ( R0 == 0 ) {
22427 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
22428 DIP("xsdivqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22429 assign( vT, triop( Iop_DivF128, rm, mkexpr( vA ), mkexpr( vB ) ) );
22431 } else {
22432 /* use rounding mode specified by Round to odd. Issue inst with R0 = 1 */
22433 DIP("xsdivqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22434 assign( vT, triop( Iop_DivF128, set_round_to_Oddmode(), mkexpr( vA ),
22435 mkexpr( vB ) ) );
22437 generate_store_FPRF( Ity_F128, vT, vbi );
22438 break;
22440 case 0x324: // xssqrtqp (VSX Scalar Square root Quad-Precision[using round to Odd])
22442 UInt inst_select = IFIELD( theInstr, 16, 5 );
22444 switch (inst_select) {
22445 case 27:
22447 if ( R0 == 0 ) { // xssqrtqp
22448 /* rounding mode specified by RN. Issue inst with R0 = 0 */
22449 DIP("xssqrtqp v%d,v%d\n", vT_addr, vB_addr);
22450 assign( vT, binop( Iop_SqrtF128, rm, mkexpr( vB ) ) );
22452 } else { // xssqrtqpo
22453 /* rounding mode is Round to odd. Issue inst with R0 = 1 */
22454 DIP("xssqrtqpo v%d,v%d\n", vT_addr, vB_addr);
22455 assign( vT, binop( Iop_SqrtF128, set_round_to_Oddmode(),
22456 mkexpr( vB ) ) );
22458 generate_store_FPRF( Ity_F128, vT, vbi );
22459 break;
22460 } /* end case 27 */
22461 default:
22462 vex_printf("dis_vx_Floating_Point_Arithmetic_quad_precision(0x324 unknown inst_select)\n");
22463 return False;
22464 } /* end switch inst_select */
22465 break;
22466 } /* end case 0x324 */
22468 case 0x344:
22470 UInt inst_select = IFIELD( theInstr, 16, 5);
22472 switch (inst_select) {
22473 case 1: // xscvqpuwz VSX Scalar Truncate & Convert Quad-Precision
22474 // format to Unsigned Word format
22476 DIP("xscvqpuwz v%d,v%d\n", vT_addr, vB_addr);
22477 assign( vT, unop( Iop_TruncF128toI32U, mkexpr( vB ) ) );
22478 break;
22480 case 2: // xscvudqp VSX Scalar Convert from Unsigned Doubleword
22481 // format to Quad-Precision format
22483 IRTemp tmp = newTemp( Ity_I64 );
22485 DIP("xscvudqp v%d,v%d\n", vT_addr, vB_addr);
22486 assign( tmp, unop( Iop_ReinterpF64asI64,
22487 unop( Iop_F128HItoF64, mkexpr( vB ) ) ) );
22488 assign( vT, unop( Iop_I64UtoF128, mkexpr( tmp ) ) );
22489 generate_store_FPRF( Ity_F128, vT, vbi );
22490 break;
22492 case 9: // xsvqpswz VSX Scalar Truncate & Convert Quad-Precision
22493 // format to Signed Word format
22495 DIP("xscvqpswz v%d,v%d\n", vT_addr, vB_addr);
22496 assign( vT, unop( Iop_TruncF128toI32S, mkexpr( vB ) ) );
22497 break;
22499 case 10: // xscvsdqp VSX Scalar from Signed Doubleword format
22500 // Quad-Precision format
22502 IRTemp tmp = newTemp( Ity_I64 );
22504 DIP("xscvsdqp v%d,v%d\n", vT_addr, vB_addr);
22506 assign( tmp, unop( Iop_ReinterpF64asI64,
22507 unop( Iop_F128HItoF64, mkexpr( vB ) ) ) );
22508 assign( vT, unop( Iop_I64StoF128, mkexpr( tmp ) ) );
22509 generate_store_FPRF( Ity_F128, vT, vbi );
22510 break;
22512 case 17: // xsvqpudz VSX Scalar Truncate & Convert Quad-Precision
22513 // format to Unigned Doubleword format
22515 DIP("xscvqpudz v%d,v%d\n", vT_addr, vB_addr);
22516 assign( vT, unop( Iop_TruncF128toI64U, mkexpr( vB ) ) );
22517 break;
22519 case 20: // xscvqpdp Scalar round & Conver Quad-Precision
22520 // format to Double-Precision format [using round to Odd]
22522 IRTemp ftmp = newTemp( Ity_F64 );
22523 IRTemp tmp = newTemp( Ity_I64 );
22525 /* This instruction takes a 128-bit floating point value and
22526 * converts it to a 64-bit floating point value. The 64-bit
22527 * result is stored in the upper 64-bit of the 128-bit result
22528 * register. The lower 64-bit are undefined.
22530 if (R0 == 0) { // xscvqpdp
22531 /* rounding mode specified by RN. Issue inst with R0 = 0 */
22532 DIP("xscvqpdp v%d,v%d\n", vT_addr, vB_addr);
22534 assign( ftmp, binop( Iop_F128toF64, rm, mkexpr( vB ) ) );
22536 } else { // xscvqpdpo
22537 /* rounding mode is Round to odd. Issue inst with R0 = 1 */
22538 DIP("xscvqpdpo v%d,v%d\n", vT_addr, vB_addr);
22539 assign( ftmp,
22540 binop( Iop_F128toF64,
22541 set_round_to_Oddmode(), mkexpr( vB ) ) );
22544 /* store 64-bit float in upper 64-bits of 128-bit register,
22545 * lower 64-bits are zero.
22547 if (host_endness == VexEndnessLE)
22548 assign( vT,
22549 binop( Iop_F64HLtoF128,
22550 mkexpr( ftmp ),
22551 unop( Iop_ReinterpI64asF64, mkU64( 0 ) ) ) );
22552 else
22553 assign( vT,
22554 binop( Iop_F64HLtoF128,
22555 unop( Iop_ReinterpI64asF64, mkU64( 0 ) ),
22556 mkexpr( ftmp ) ) );
22558 assign( tmp, unop( Iop_ReinterpF64asI64,
22559 unop( Iop_F128HItoF64, mkexpr( vT ) ) ) );
22561 generate_store_FPRF( Ity_I64, tmp, vbi );
22562 break;
22564 case 22: // xscvdpqp VSX Scalar Convert from Double-Precision
22565 // format to Quad-Precision format
22567 DIP("xscvdpqp v%d,v%d\n", vT_addr, vB_addr);
22568 /* The 64-bit value is in the upper 64 bit of the src */
22569 assign( vT, unop( Iop_F64toF128,
22570 unop( Iop_F128HItoF64, mkexpr( vB ) ) ) );
22572 generate_store_FPRF( Ity_F128, vT, vbi );
22573 break;
22575 case 25: // xsvqpsdz VSX Scalar Truncate & Convert Quad-Precision
22576 // format to Signed Doubleword format
22578 DIP("xscvqpsdz v%d,v%d\n", vT_addr, vB_addr);
22579 assign( vT, unop( Iop_TruncF128toI64S, mkexpr( vB ) ) );
22580 break;
22582 default:
22583 vex_printf( "dis_vx_Floating_Point_Arithmetic_quad_precision invalid inst_select (ppc)(opc2)\n" );
22584 return False;
22585 } /* switch inst_select */
22586 } /* end case 0x344 */
22587 break;
22588 default: /* switch opc2 */
22589 vex_printf( "dis_vx_Floating_Point_Arithmetic_quad_precision(ppc)(opc2)\n" );
22590 return False;
22592 putF128Reg( vT_addr, mkexpr( vT ) );
22593 return True;
22597 /* VSX Scalar Quad-Precision instructions */
22598 static Bool
22599 dis_vx_scalar_quad_precision ( UInt theInstr )
22601 /* This function emulates the 128-bit floating point instructions
22602 * using existing 128-bit vector instructions (Iops). The 128-bit
22603 * floating point instructions use the same 128-bit vector register
22604 * set.
22606 /* XX1-Form */
22607 UChar opc1 = ifieldOPC( theInstr );
22608 UInt opc2 = ifieldOPClo10( theInstr );
22609 UChar vT_addr = ifieldRegDS( theInstr ) + 32;
22610 UChar vA_addr = ifieldRegA( theInstr ) + 32;
22611 UChar vB_addr = ifieldRegB( theInstr ) + 32;
22612 IRTemp vA = newTemp( Ity_V128 );
22613 IRTemp vB = newTemp( Ity_V128 );
22614 IRTemp vT = newTemp( Ity_V128 );
22616 assign( vB, getVSReg( vB_addr ) );
22618 if (opc1 != 0x3F) {
22619 vex_printf( "dis_vx_scalar_quad_precision(ppc)(instr)\n" );
22620 return False;
22623 switch (opc2) {
22625 case 0x064: // xscpsgnqp (VSX Scalar Copy Sign Quad-Precision)
22627 IRTemp sign_vA = newTemp( Ity_I64 );
22628 IRTemp vB_hi = newTemp( Ity_I64 );
22630 DIP("xscpsgnqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22632 assign( vA, getVSReg(vA_addr) );
22634 assign( sign_vA, binop( Iop_And64,
22635 unop( Iop_V128HIto64,
22636 mkexpr( vA ) ),
22637 mkU64( 0x8000000000000000ULL ) ) );
22638 assign( vB_hi, binop( Iop_Or64,
22639 binop( Iop_And64,
22640 unop( Iop_V128HIto64,
22641 mkexpr( vB ) ),
22642 mkU64( 0x7FFFFFFFFFFFFFFFULL ) ),
22643 mkexpr( sign_vA ) ) );
22644 assign( vT, binop( Iop_64HLtoV128,
22645 mkexpr( vB_hi ),
22646 unop( Iop_V128to64, mkexpr( vB ) ) ) );
22647 break;
22650 case 0x084: // xscmpoqp (VSX Scalar Compare Ordered Quad-Precision)
22651 case 0x284: // xscmpuqp (VSX Scalar Compare Unrdered Quad-Precision)
22653 /* Note, only differece between xscmoqp and xscmpuqp is the
22654 exception flag settings which are not supported anyway. */
22655 IRExpr *bit4, *bit5, *bit6, *bit7;
22656 IRExpr *bit_zero, *bit_inf, *same_sign;
22657 UInt BF = IFIELD( theInstr, 23, 3 );
22658 IRTemp eq_lt_gt = newTemp( Ity_I32 );
22659 IRTemp CC = newTemp( Ity_I32 );
22661 if (opc2 == 0x084) {
22662 DIP("xscmpoqp %u,v%d,v%u\n", BF, vA_addr, vB_addr);
22663 } else {
22664 DIP("xscmpuqp %u,v%d,v%u\n", BF, vA_addr, vB_addr);
22667 assign( vA, getVSReg(vA_addr));
22669 /* A and B have the same sign */
22670 same_sign = binop( Iop_CmpEQ64,
22671 binop( Iop_Shr64,
22672 unop( Iop_V128HIto64,
22673 mkexpr( vA ) ),
22674 mkU8( 63 ) ),
22675 binop( Iop_Shr64,
22676 unop( Iop_V128HIto64,
22677 mkexpr( vB ) ),
22678 mkU8( 63 ) ) );
22680 /* A < B */
22681 bit4 = Quad_precision_gt( vB, vA );
22683 /* A > B */
22684 bit5 = Quad_precision_gt( vA, vB );
22686 /* A equal B */
22687 bit6 = mkAND1( binop( Iop_CmpEQ64,
22688 unop( Iop_V128HIto64,
22689 mkexpr( vA ) ),
22690 unop( Iop_V128HIto64,
22691 mkexpr( vB ) ) ),
22692 binop( Iop_CmpEQ64,
22693 unop( Iop_V128to64,
22694 mkexpr( vA ) ),
22695 unop( Iop_V128to64,
22696 mkexpr( vB ) ) ) );
22698 /* test both zero don't care about sign */
22699 bit_zero = mkAND1( is_Zero( Ity_V128, vA ), is_Zero( Ity_V128, vB ) );
22701 /* test both for infinity, don't care about sign */
22702 bit_inf = mkAND1(
22703 mkAND1( is_Inf( Ity_V128, vA ), is_Inf( Ity_V128, vB ) ),
22704 binop( Iop_CmpEQ64,
22705 binop( Iop_And64,
22706 unop( Iop_V128to64,
22707 mkexpr( vA ) ),
22708 mkU64( 0x80000000) ),
22709 binop( Iop_And64,
22710 unop( Iop_V128to64,
22711 mkexpr( vB ) ),
22712 mkU64( 0x80000000) ) ) );
22714 /* exp A or exp B is NaN */
22715 bit7 = mkOR1( is_NaN( Ity_V128, vA ),
22716 is_NaN( Ity_V128, vB ) );
22718 assign( eq_lt_gt,
22719 binop( Iop_Or32,
22720 binop( Iop_Or32,
22721 binop( Iop_Shl32,
22722 unop( Iop_1Uto32, bit4 ),
22723 mkU8( 3 ) ),
22724 binop( Iop_Shl32,
22725 unop( Iop_1Uto32, bit5 ),
22726 mkU8( 2 ) ) ),
22727 binop( Iop_Or32,
22728 binop( Iop_Shl32,
22729 unop( Iop_1Uto32, bit6 ),
22730 mkU8( 1 ) ),
22731 binop( Iop_Or32,
22732 binop( Iop_Shl32,
22733 unop( Iop_1Uto32,
22734 bit_zero ),
22735 mkU8( 1 ) ),
22736 binop( Iop_Shl32,
22737 unop( Iop_1Uto32,
22738 mkAND1( bit_inf, same_sign ) ),
22739 mkU8( 1 ) ) ) ) ) );
22741 assign(CC, binop( Iop_Or32,
22742 binop( Iop_And32,
22743 unop( Iop_Not32,
22744 unop( Iop_1Sto32, bit7 ) ),
22745 mkexpr( eq_lt_gt ) ),
22746 unop( Iop_1Uto32, bit7 ) ) );
22748 /* put result of the comparison into CC and FPCC */
22749 putGST_field( PPC_GST_CR, mkexpr( CC ), BF );
22750 putFPCC( mkexpr( CC ) );
22751 return True;
22753 break;
22755 case 0xA4: // xscmpexpqp (VSX Scalar Compare Exponents Double-Precision)
22757 IRExpr *bit4, *bit5, *bit6, *bit7;
22758 UInt BF = IFIELD( theInstr, 23, 3 );
22760 IRTemp eq_lt_gt = newTemp( Ity_I32 );
22761 IRTemp CC = newTemp( Ity_I32 );
22763 DIP("xscmpexpqp %u,v%d,v%u\n", BF, vA_addr, vB_addr);
22765 assign( vA, getVSReg(vA_addr));
22767 /* A exp < B exp */
22768 bit4 = binop( Iop_CmpLT64U,
22769 binop( Iop_And64,
22770 unop( Iop_V128HIto64,
22771 mkexpr( vA ) ),
22772 mkU64( 0x7FFF000000000000 ) ),
22773 binop( Iop_And64,
22774 unop( Iop_V128HIto64,
22775 mkexpr( vB ) ),
22776 mkU64( 0x7FFF000000000000 ) ) );
22777 /* exp > B exp */
22778 bit5 = binop( Iop_CmpLT64U,
22779 binop( Iop_And64,
22780 unop( Iop_V128HIto64,
22781 mkexpr( vB ) ),
22782 mkU64( 0x7FFF000000000000 ) ),
22783 binop( Iop_And64,
22784 unop( Iop_V128HIto64,
22785 mkexpr( vA ) ),
22786 mkU64( 0x7FFF000000000000 ) ) );
22787 /* test equal */
22788 bit6 = binop( Iop_CmpEQ64,
22789 binop( Iop_And64,
22790 unop( Iop_V128HIto64,
22791 mkexpr( vA ) ),
22792 mkU64( 0x7FFF000000000000 ) ),
22793 binop( Iop_And64,
22794 unop( Iop_V128HIto64,
22795 mkexpr( vB ) ),
22796 mkU64( 0x7FFF000000000000 ) ) );
22798 /* exp A or exp B is NaN */
22799 bit7 = mkOR1( is_NaN( Ity_V128, vA ),
22800 is_NaN( Ity_V128, vB ) );
22802 /* NaN over rules the other comparisons */
22803 assign( eq_lt_gt, binop( Iop_Or32,
22804 binop( Iop_Shl32,
22805 unop( Iop_1Uto32, bit4 ),
22806 mkU8( 3) ),
22807 binop( Iop_Or32,
22808 binop( Iop_Shl32,
22809 unop( Iop_1Uto32, bit5 ),
22810 mkU8( 2) ),
22811 binop( Iop_Shl32,
22812 unop( Iop_1Uto32, bit6 ),
22813 mkU8( 1 ) ) ) ) );
22814 assign(CC, binop( Iop_Or32,
22815 binop( Iop_And32,
22816 unop( Iop_Not32,
22817 unop( Iop_1Sto32, bit7 ) ),
22818 mkexpr( eq_lt_gt ) ),
22819 unop( Iop_1Uto32, bit7 ) ) );
22821 /* put result of the comparison into CC and FPCC */
22822 putGST_field( PPC_GST_CR, mkexpr( CC ), BF );
22823 putFPCC( mkexpr( CC ) );
22824 return True;
22826 break;
22828 case 0x2C4: // xststdcqp (VSX Scalar Quad-Precision Test Data Class)
22830 UInt BF = IFIELD( theInstr, 23, 3 );
22831 UInt DCMX_mask = IFIELD( theInstr, 16, 7 );
22832 IRTemp CC = newTemp( Ity_I64 );
22833 IRTemp NaN = newTemp( Ity_I64 );
22834 IRTemp inf = newTemp( Ity_I64 );
22835 IRTemp pos = newTemp( Ity_I64 );
22836 IRTemp DCM = newTemp( Ity_I64 );
22837 IRTemp zero = newTemp( Ity_I64 );
22838 IRTemp dnorm = newTemp( Ity_I64 );
22840 DIP("xststdcqp %u,v%d,%u\n", BF, vB_addr, DCMX_mask);
22842 assign( zero, unop( Iop_1Uto64, is_Zero( Ity_V128, vB ) ) );
22843 assign( pos, unop( Iop_1Uto64,
22844 binop( Iop_CmpEQ64,
22845 binop( Iop_Shr64,
22846 unop( Iop_V128HIto64,
22847 mkexpr( vB ) ),
22848 mkU8( 63 ) ),
22849 mkU64( 0 ) ) ) );
22851 assign( NaN, unop( Iop_1Uto64, is_NaN( Ity_V128, vB ) ) );
22852 assign( inf, unop( Iop_1Uto64, is_Inf( Ity_V128, vB ) ) );
22854 assign( dnorm, unop( Iop_1Uto64, is_Denorm( Ity_V128, vB ) ) );
22855 assign( DCM, create_DCM( Ity_I64, NaN, inf, zero, dnorm, pos ) );
22856 assign( CC, binop( Iop_Or64,
22857 binop( Iop_And64, /* vB sign bit */
22858 binop( Iop_Shr64,
22859 unop( Iop_V128HIto64, mkexpr( vB ) ),
22860 mkU8( 60 ) ),
22861 mkU64( 0x8 ) ),
22862 binop( Iop_Shl64,
22863 unop( Iop_1Uto64,
22864 binop( Iop_CmpNE64,
22865 binop( Iop_And64,
22866 mkexpr( DCM ),
22867 mkU64( DCMX_mask ) ),
22868 mkU64( 0 ) ) ),
22869 mkU8( 1 ) ) ) );
22871 putGST_field( PPC_GST_CR, unop(Iop_64to32, mkexpr( CC ) ), BF );
22872 putFPCC( unop(Iop_64to32, mkexpr( CC ) ) );
22873 return True;
22875 break;
22877 case 0x324: // xsabsqp (VSX Scalar Absolute Quad-Precision)
22878 // xsxexpqp (VSX Scalaar Extract Exponent Quad-Precision)
22879 // xsnabsqp (VSX Scalar Negative Absolute Quad-Precision)
22880 // xsnegqp (VSX Scalar Negate Quad-Precision)
22881 // xsxsigqp (VSX Scalar Extract Significand Quad-Precision)
22883 UInt inst_select = IFIELD( theInstr, 16, 5);
22885 switch (inst_select) {
22886 case 0:
22887 DIP("xsabsqp v%d,v%d\n", vT_addr, vB_addr);
22888 assign( vT, binop( Iop_AndV128, mkexpr( vB ),
22889 binop( Iop_64HLtoV128,
22890 mkU64( 0x7FFFFFFFFFFFFFFF ),
22891 mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) );
22892 break;
22894 case 2:
22895 DIP("xsxexpqp v%d,v%d\n", vT_addr, vB_addr);
22896 assign( vT, binop( Iop_ShrV128,
22897 binop( Iop_AndV128, mkexpr( vB ),
22898 binop( Iop_64HLtoV128,
22899 mkU64( 0x7FFF000000000000 ),
22900 mkU64( 0x0000000000000000 ) ) ),
22901 mkU8( 48 ) ) );
22902 break;
22904 case 8:
22905 DIP("xsnabsqp v%d,v%d\n", vT_addr, vB_addr);
22906 assign( vT, binop( Iop_OrV128, mkexpr( vB ),
22907 binop( Iop_64HLtoV128,
22908 mkU64( 0x8000000000000000 ),
22909 mkU64( 0x0000000000000000 ) ) ) );
22910 break;
22912 case 16:
22913 DIP("xsnegqp v%d,v%d\n", vT_addr, vB_addr);
22914 assign( vT, binop( Iop_XorV128, mkexpr( vB ),
22915 binop( Iop_64HLtoV128,
22916 mkU64( 0x8000000000000000 ),
22917 mkU64( 0x0000000000000000 ) ) ) );
22918 break;
22920 case 18:
22922 IRTemp expZero = newTemp( Ity_I64 );
22923 IRTemp expInfinity = newTemp( Ity_I64 );
22925 DIP("xsxsigqp v%d,v%d\n", vT_addr, vB_addr);
22927 assign( expZero, unop( Iop_1Uto64,
22928 binop( Iop_CmpNE64,
22929 binop( Iop_And64,
22930 unop( Iop_V128HIto64,
22931 mkexpr( vB ) ),
22932 mkU64( 0x7FFF000000000000 ) ),
22933 mkU64( 0x0 ) ) ) );
22935 assign( expInfinity,
22936 unop( Iop_1Uto64,
22937 binop( Iop_CmpNE64,
22938 binop( Iop_And64,
22939 unop( Iop_V128HIto64,
22940 mkexpr( vB ) ),
22941 mkU64( 0x7FFF000000000000 ) ),
22942 mkU64( 0x7FFF000000000000 ) ) ) );
22944 /* Clear upper 16 bits to 0x0000. If the exp was zero or infinity
22945 * set bit 48 (lsb = 0) to 0, otherwise set bit 48 to 1.
22947 assign( vT,
22948 binop( Iop_OrV128,
22949 binop( Iop_ShrV128,
22950 binop( Iop_ShlV128,
22951 mkexpr( vB ),
22952 mkU8( 16 ) ),
22953 mkU8( 16 ) ),
22954 binop( Iop_64HLtoV128,
22955 binop( Iop_Shl64,
22956 binop( Iop_And64,
22957 mkexpr( expZero ),
22958 mkexpr( expInfinity ) ),
22959 mkU8( 48 ) ),
22960 mkU64( 0 ) ) ) );
22962 break;
22964 default:
22965 vex_printf( "dis_vx_scalar_quad_precision invalid inst_select (ppc)(opc2)\n" );
22966 return False;
22969 break;
22970 case 0x364: // xsiexpqp (VST Scalar Insert Exponent Quad-Precision)
22972 IRTemp exp = newTemp( Ity_I64 );
22974 DIP("xsiexpqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22976 assign( vA, getVSReg( vA_addr ) );
22977 assign( exp, binop( Iop_And64,
22978 unop( Iop_V128HIto64,
22979 mkexpr( vB ) ),
22980 mkU64( 0x7FFFULL ) ) );
22981 assign( vT, binop( Iop_64HLtoV128,
22982 binop( Iop_Or64,
22983 binop( Iop_And64,
22984 unop( Iop_V128HIto64,
22985 mkexpr( vA ) ),
22986 mkU64( 0x8000FFFFFFFFFFFFULL ) ),
22987 binop( Iop_Shl64,
22988 mkexpr( exp ),
22989 mkU8( 48 ) ) ),
22990 unop( Iop_V128to64,
22991 mkexpr( vA ) ) ) );
22993 break;
22995 default:
22996 vex_printf( "dis_vx_scalar_quad_precision(ppc)(opc2)\n" );
22998 return False;
23001 putVSReg( vT_addr, mkexpr( vT ) );
23002 return True;
23006 * VSX permute and other miscealleous instructions
23008 static Bool
23009 dis_vx_permute_misc( UInt theInstr, UInt opc2 )
23011 /* XX3-Form */
23012 UChar opc1 = ifieldOPC( theInstr );
23013 UChar XT = ifieldRegXT ( theInstr );
23014 UChar XA = ifieldRegXA ( theInstr );
23015 UChar XB = ifieldRegXB ( theInstr );
23016 IRTemp vT = newTemp( Ity_V128 );
23017 IRTemp vA = newTemp( Ity_V128 );
23018 IRTemp vB = newTemp( Ity_V128 );
23020 if (opc1 != 0x3C) {
23021 vex_printf( "dis_vx_permute_misc(ppc)(instr)\n" );
23022 return False;
23025 assign( vA, getVSReg( XA ) );
23026 assign( vB, getVSReg( XB ) );
23028 switch (opc2) {
23029 case 0x8: // xxsldwi (VSX Shift Left Double by Word Immediate)
23031 UChar SHW = ifieldSHW ( theInstr );
23032 IRTemp result = newTemp(Ity_V128);
23033 if ( SHW != 0 ) {
23034 IRTemp hi = newTemp(Ity_V128);
23035 IRTemp lo = newTemp(Ity_V128);
23036 assign( hi, binop(Iop_ShlV128, mkexpr(vA), mkU8(SHW*32)) );
23037 assign( lo, binop(Iop_ShrV128, mkexpr(vB), mkU8(128-SHW*32)) );
23038 assign ( result, binop(Iop_OrV128, mkexpr(hi), mkexpr(lo)) );
23039 } else
23040 assign ( result, mkexpr(vA) );
23041 DIP("xxsldwi v%d,v%d,v%d,%d\n", XT, XA, XB, SHW);
23042 putVSReg( XT, mkexpr(result) );
23043 break;
23045 case 0x28: // xpermdi (VSX Permute Doubleword Immediate)
23047 UChar DM = ifieldDM ( theInstr );
23048 IRTemp hi = newTemp(Ity_I64);
23049 IRTemp lo = newTemp(Ity_I64);
23051 if (DM & 0x2)
23052 assign( hi, unop(Iop_V128to64, mkexpr(vA)) );
23053 else
23054 assign( hi, unop(Iop_V128HIto64, mkexpr(vA)) );
23056 if (DM & 0x1)
23057 assign( lo, unop(Iop_V128to64, mkexpr(vB)) );
23058 else
23059 assign( lo, unop(Iop_V128HIto64, mkexpr(vB)) );
23061 assign( vT, binop(Iop_64HLtoV128, mkexpr(hi), mkexpr(lo)) );
23063 DIP("xxpermdi v%d,v%d,v%d,0x%x\n", XT, XA, XB, DM);
23064 putVSReg( XT, mkexpr( vT ) );
23065 break;
23067 case 0x48: // xxmrghw (VSX Merge High Word)
23068 case 0xc8: // xxmrglw (VSX Merge Low Word)
23070 const HChar type = (opc2 == 0x48) ? 'h' : 'l';
23071 IROp word_op = (opc2 == 0x48) ? Iop_V128HIto64 : Iop_V128to64;
23072 IRTemp a64 = newTemp(Ity_I64);
23073 IRTemp ahi32 = newTemp(Ity_I32);
23074 IRTemp alo32 = newTemp(Ity_I32);
23075 IRTemp b64 = newTemp(Ity_I64);
23076 IRTemp bhi32 = newTemp(Ity_I32);
23077 IRTemp blo32 = newTemp(Ity_I32);
23079 assign( a64, unop(word_op, mkexpr(vA)) );
23080 assign( ahi32, unop(Iop_64HIto32, mkexpr(a64)) );
23081 assign( alo32, unop(Iop_64to32, mkexpr(a64)) );
23083 assign( b64, unop(word_op, mkexpr(vB)) );
23084 assign( bhi32, unop(Iop_64HIto32, mkexpr(b64)) );
23085 assign( blo32, unop(Iop_64to32, mkexpr(b64)) );
23087 assign( vT, binop(Iop_64HLtoV128,
23088 binop(Iop_32HLto64, mkexpr(ahi32), mkexpr(bhi32)),
23089 binop(Iop_32HLto64, mkexpr(alo32), mkexpr(blo32))) );
23091 DIP("xxmrg%cw v%d,v%d,v%d\n", type, XT, XA, XB);
23092 putVSReg( XT, mkexpr( vT ) );
23093 break;
23095 case 0x018: // xxsel (VSX Select)
23097 UChar XC = ifieldRegXC(theInstr);
23098 IRTemp vC = newTemp( Ity_V128 );
23099 assign( vC, getVSReg( XC ) );
23100 DIP("xxsel v%d,v%d,v%d,v%d\n", XT, XA, XB, XC);
23101 /* vD = (vA & ~vC) | (vB & vC) */
23102 putVSReg( XT, binop(Iop_OrV128,
23103 binop(Iop_AndV128, mkexpr(vA), unop(Iop_NotV128, mkexpr(vC))),
23104 binop(Iop_AndV128, mkexpr(vB), mkexpr(vC))) );
23105 break;
23108 case 0x68: // xxperm (VSX Permute )
23109 case 0xE8: // xxpermr (VSX Permute right-index )
23112 /* The xxperm instruction performs the same operation as
23113 the vperm except the xxperm operates on the VSR register
23114 file. while vperm operates on the VR register file.
23115 Lets borrow some code here from vperm. The mapping of
23116 the source registers is also a little different.
23118 IRTemp a_perm = newTemp(Ity_V128);
23119 IRTemp b_perm = newTemp(Ity_V128);
23120 IRTemp mask = newTemp(Ity_V128);
23121 IRTemp perm_val = newTemp(Ity_V128);
23122 IRTemp vB_adj = newTemp( Ity_V128 );
23124 if ( opc2 == 0x68 ) {
23125 DIP("xxperm v%u,v%u,v%u\n", (UInt)XT, (UInt)XA, (UInt)XB);
23127 } else {
23128 /* Same as xperm just the index is 31 - idx */
23129 DIP("xxpermr v%u,v%u,v%u\n", (UInt)XT, (UInt)XA, (UInt)XB);
23132 assign( vT, getVSReg( XT ) );
23134 if ( opc2 == 0x68 ) // xxperm
23135 assign( vB_adj, mkexpr( vB ) );
23137 else // xxpermr
23138 assign( vB_adj,
23139 binop( Iop_Sub16x8,
23140 unop( Iop_Dup8x16, mkU8( 0x1F ) ),
23141 mkexpr( vB ) ) );
23143 /* Limit the Perm8x16 steering values to 0 .. 15 as that is what
23144 IR specifies, and also to hide irrelevant bits from
23145 memcheck.
23147 assign( perm_val,
23148 binop( Iop_AndV128, mkexpr( vB_adj ),
23149 unop( Iop_Dup8x16, mkU8( 0xF ) ) ) );
23150 assign( a_perm,
23151 binop( Iop_Perm8x16, mkexpr( vA ), mkexpr( perm_val ) ) );
23152 assign( b_perm,
23153 binop( Iop_Perm8x16, mkexpr( vT ), mkexpr( perm_val ) ) );
23154 assign( mask, binop( Iop_SarN8x16,
23155 binop( Iop_ShlN8x16, mkexpr( vB_adj ),
23156 mkU8( 3 ) ),
23157 mkU8( 7 ) ) );
23158 // dst = (a & ~mask) | (b & mask)
23159 putVSReg( XT, binop( Iop_OrV128,
23160 binop( Iop_AndV128, mkexpr( a_perm ),
23161 unop( Iop_NotV128, mkexpr( mask ) ) ),
23162 binop( Iop_AndV128, mkexpr( b_perm ),
23163 mkexpr( mask ) ) ) );
23164 break;
23167 case 0x148: // xxspltw (VSX Splat Word)
23169 UChar UIM = ifieldRegA(theInstr) & 3;
23170 UChar sh_uim = (3 - (UIM)) * 32;
23171 DIP("xxspltw v%d,v%d,%d\n", XT, XB, UIM);
23172 putVSReg( XT,
23173 unop( Iop_Dup32x4,
23174 unop( Iop_V128to32,
23175 binop( Iop_ShrV128, mkexpr( vB ), mkU8( sh_uim ) ) ) ) );
23176 break;
23179 default:
23180 vex_printf( "dis_vx_permute_misc(ppc)(opc2)\n" );
23181 return False;
23183 return True;
23187 AltiVec Load Instructions
23189 static Bool dis_av_load ( const VexAbiInfo* vbi, UInt theInstr )
23191 /* X-Form */
23192 UChar opc1 = ifieldOPC(theInstr);
23193 UChar vD_addr = ifieldRegDS(theInstr);
23194 UChar rA_addr = ifieldRegA(theInstr);
23195 UChar rB_addr = ifieldRegB(theInstr);
23196 UInt opc2 = ifieldOPClo10(theInstr);
23197 UChar b0 = ifieldBIT0(theInstr);
23199 IRType ty = mode64 ? Ity_I64 : Ity_I32;
23200 IRTemp EA = newTemp(ty);
23201 IRTemp EA_align16 = newTemp(ty);
23203 if (opc1 != 0x1F || b0 != 0) {
23204 vex_printf("dis_av_load(ppc)(instr)\n");
23205 return False;
23208 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
23209 assign( EA_align16, addr_align( mkexpr(EA), 16 ) );
23211 switch (opc2) {
23213 case 0x006: { // lvsl (Load Vector for Shift Left, AV p123)
23214 IRDirty* d;
23215 UInt vD_off = vectorGuestRegOffset(vD_addr);
23216 IRExpr** args_be = mkIRExprVec_5(
23217 IRExpr_GSPTR(),
23218 mkU32(vD_off),
23219 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
23220 mkU32(0xF)),
23221 mkU32(0)/*left*/,
23222 mkU32(1)/*Big Endian*/);
23223 IRExpr** args_le = mkIRExprVec_5(
23224 IRExpr_GSPTR(),
23225 mkU32(vD_off),
23226 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
23227 mkU32(0xF)),
23228 mkU32(0)/*left*/,
23229 mkU32(0)/*Little Endian*/);
23230 if (!mode64) {
23231 d = unsafeIRDirty_0_N (
23232 0/*regparms*/,
23233 "ppc32g_dirtyhelper_LVS",
23234 fnptr_to_fnentry(vbi, &ppc32g_dirtyhelper_LVS),
23235 args_be );
23236 } else {
23237 if (host_endness == VexEndnessBE)
23238 d = unsafeIRDirty_0_N (
23239 0/*regparms*/,
23240 "ppc64g_dirtyhelper_LVS",
23241 fnptr_to_fnentry(vbi, &ppc64g_dirtyhelper_LVS),
23242 args_be );
23243 else
23244 d = unsafeIRDirty_0_N (
23245 0/*regparms*/,
23246 "ppc64g_dirtyhelper_LVS",
23247 fnptr_to_fnentry( vbi, &ppc64g_dirtyhelper_LVS ),
23248 args_le );
23250 DIP("lvsl v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
23251 /* declare guest state effects */
23252 d->nFxState = 1;
23253 vex_bzero(&d->fxState, sizeof(d->fxState));
23254 d->fxState[0].fx = Ifx_Write;
23255 d->fxState[0].offset = vD_off;
23256 d->fxState[0].size = sizeof(U128);
23258 /* execute the dirty call, side-effecting guest state */
23259 stmt( IRStmt_Dirty(d) );
23260 break;
23262 case 0x026: { // lvsr (Load Vector for Shift Right, AV p125)
23263 IRDirty* d;
23264 UInt vD_off = vectorGuestRegOffset(vD_addr);
23265 IRExpr** args_be = mkIRExprVec_5(
23266 IRExpr_GSPTR(),
23267 mkU32(vD_off),
23268 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
23269 mkU32(0xF)),
23270 mkU32(1)/*right*/,
23271 mkU32(1)/*Big Endian*/);
23272 IRExpr** args_le = mkIRExprVec_5(
23273 IRExpr_GSPTR(),
23274 mkU32(vD_off),
23275 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
23276 mkU32(0xF)),
23277 mkU32(1)/*right*/,
23278 mkU32(0)/*Little Endian*/);
23280 if (!mode64) {
23281 d = unsafeIRDirty_0_N (
23282 0/*regparms*/,
23283 "ppc32g_dirtyhelper_LVS",
23284 fnptr_to_fnentry(vbi, &ppc32g_dirtyhelper_LVS),
23285 args_be );
23286 } else {
23287 if (host_endness == VexEndnessBE)
23288 d = unsafeIRDirty_0_N (
23289 0/*regparms*/,
23290 "ppc64g_dirtyhelper_LVS",
23291 fnptr_to_fnentry(vbi, &ppc64g_dirtyhelper_LVS),
23292 args_be );
23293 else
23294 d = unsafeIRDirty_0_N (
23295 0/*regparms*/,
23296 "ppc64g_dirtyhelper_LVS",
23297 fnptr_to_fnentry( vbi, &ppc64g_dirtyhelper_LVS ),
23298 args_le );
23300 DIP("lvsr v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
23301 /* declare guest state effects */
23302 d->nFxState = 1;
23303 vex_bzero(&d->fxState, sizeof(d->fxState));
23304 d->fxState[0].fx = Ifx_Write;
23305 d->fxState[0].offset = vD_off;
23306 d->fxState[0].size = sizeof(U128);
23308 /* execute the dirty call, side-effecting guest state */
23309 stmt( IRStmt_Dirty(d) );
23310 break;
23312 case 0x007: // lvebx (Load Vector Element Byte Indexed, AV p119)
23313 DIP("lvebx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
23314 /* loads addressed byte into vector[EA[0:3]
23315 since all other destination bytes are undefined,
23316 can simply load entire vector from 16-aligned EA */
23317 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
23318 break;
23320 case 0x027: // lvehx (Load Vector Element Half Word Indexed, AV p121)
23321 DIP("lvehx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
23322 /* see note for lvebx */
23323 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
23324 break;
23326 case 0x047: // lvewx (Load Vector Element Word Indexed, AV p122)
23327 DIP("lvewx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
23328 /* see note for lvebx */
23329 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
23330 break;
23332 case 0x067: // lvx (Load Vector Indexed, AV p127)
23333 DIP("lvx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
23334 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
23335 break;
23337 case 0x167: // lvxl (Load Vector Indexed LRU, AV p128)
23338 DIP("lvxl v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
23339 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
23340 break;
23342 default:
23343 vex_printf("dis_av_load(ppc)(opc2)\n");
23344 return False;
23346 return True;
23350 AltiVec Store Instructions
23352 static Bool dis_av_store ( UInt theInstr )
23354 /* X-Form */
23355 UChar opc1 = ifieldOPC(theInstr);
23356 UChar vS_addr = ifieldRegDS(theInstr);
23357 UChar rA_addr = ifieldRegA(theInstr);
23358 UChar rB_addr = ifieldRegB(theInstr);
23359 UInt opc2 = ifieldOPClo10(theInstr);
23360 UChar b0 = ifieldBIT0(theInstr);
23362 IRType ty = mode64 ? Ity_I64 : Ity_I32;
23363 IRTemp EA = newTemp(ty);
23364 IRTemp addr_aligned = newTemp(ty);
23365 IRTemp vS = newTemp(Ity_V128);
23366 IRTemp eb = newTemp(Ity_I8);
23367 IRTemp idx = newTemp(Ity_I8);
23369 if (opc1 != 0x1F || b0 != 0) {
23370 vex_printf("dis_av_store(ppc)(instr)\n");
23371 return False;
23374 assign( vS, getVReg(vS_addr));
23375 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
23377 switch (opc2) {
23378 case 0x087: { // stvebx (Store Vector Byte Indexed, AV p131)
23379 DIP("stvebx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
23380 assign( eb, binop(Iop_And8, mkU8(0xF),
23381 unop(Iop_32to8,
23382 mkNarrowTo32(ty, mkexpr(EA)) )) );
23383 if (host_endness == VexEndnessLE) {
23384 assign( idx, binop(Iop_Shl8, mkexpr(eb), mkU8(3)) );
23385 } else {
23386 assign( idx, binop(Iop_Shl8,
23387 binop(Iop_Sub8, mkU8(15), mkexpr(eb)),
23388 mkU8(3)) );
23390 store( mkexpr(EA),
23391 unop( Iop_32to8, unop(Iop_V128to32,
23392 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx)))) );
23393 break;
23395 case 0x0A7: { // stvehx (Store Vector Half Word Indexed, AV p132)
23396 DIP("stvehx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
23397 assign( addr_aligned, addr_align(mkexpr(EA), 2) );
23398 assign( eb, binop(Iop_And8, mkU8(0xF),
23399 mkNarrowTo8(ty, mkexpr(addr_aligned) )) );
23400 if (host_endness == VexEndnessLE) {
23401 assign( idx, binop(Iop_Shl8, mkexpr(eb), mkU8(3)) );
23402 } else {
23403 assign( idx, binop(Iop_Shl8,
23404 binop(Iop_Sub8, mkU8(14), mkexpr(eb)),
23405 mkU8(3)) );
23407 store( mkexpr(addr_aligned),
23408 unop( Iop_32to16, unop(Iop_V128to32,
23409 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx)))) );
23410 break;
23412 case 0x0C7: { // stvewx (Store Vector Word Indexed, AV p133)
23413 DIP("stvewx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
23414 assign( addr_aligned, addr_align(mkexpr(EA), 4) );
23415 assign( eb, binop(Iop_And8, mkU8(0xF),
23416 mkNarrowTo8(ty, mkexpr(addr_aligned) )) );
23417 if (host_endness == VexEndnessLE) {
23418 assign( idx, binop(Iop_Shl8, mkexpr(eb), mkU8(3)) );
23419 } else {
23420 assign( idx, binop(Iop_Shl8,
23421 binop(Iop_Sub8, mkU8(12), mkexpr(eb)),
23422 mkU8(3)) );
23424 store( mkexpr( addr_aligned),
23425 unop( Iop_V128to32,
23426 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx))) );
23427 break;
23430 case 0x0E7: // stvx (Store Vector Indexed, AV p134)
23431 DIP("stvx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
23432 store( addr_align( mkexpr(EA), 16 ), mkexpr(vS) );
23433 break;
23435 case 0x1E7: // stvxl (Store Vector Indexed LRU, AV p135)
23436 DIP("stvxl v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
23437 store( addr_align( mkexpr(EA), 16 ), mkexpr(vS) );
23438 break;
23440 default:
23441 vex_printf("dis_av_store(ppc)(opc2)\n");
23442 return False;
23444 return True;
23448 AltiVec Arithmetic Instructions
23450 static Bool dis_av_arith ( UInt theInstr )
23452 /* VX-Form */
23453 UChar opc1 = ifieldOPC(theInstr);
23454 UChar vD_addr = ifieldRegDS(theInstr);
23455 UChar vA_addr = ifieldRegA(theInstr);
23456 UChar vB_addr = ifieldRegB(theInstr);
23457 UInt opc2 = IFIELD( theInstr, 0, 11 );
23459 IRTemp vA = newTemp(Ity_V128);
23460 IRTemp vB = newTemp(Ity_V128);
23461 IRTemp z3 = newTemp(Ity_I64);
23462 IRTemp z2 = newTemp(Ity_I64);
23463 IRTemp z1 = newTemp(Ity_I64);
23464 IRTemp z0 = newTemp(Ity_I64);
23465 IRTemp aEvn, aOdd;
23466 IRTemp a15, a14, a13, a12, a11, a10, a9, a8;
23467 IRTemp a7, a6, a5, a4, a3, a2, a1, a0;
23468 IRTemp b3, b2, b1, b0;
23470 aEvn = aOdd = IRTemp_INVALID;
23471 a15 = a14 = a13 = a12 = a11 = a10 = a9 = a8 = IRTemp_INVALID;
23472 a7 = a6 = a5 = a4 = a3 = a2 = a1 = a0 = IRTemp_INVALID;
23473 b3 = b2 = b1 = b0 = IRTemp_INVALID;
23475 assign( vA, getVReg( vA_addr ) );
23476 assign( vB, getVReg( vB_addr ) );
23478 if (opc1 != 0x4) {
23479 vex_printf("dis_av_arith(ppc)(opc1 != 0x4)\n");
23480 return False;
23483 switch (opc2) {
23484 /* Add */
23485 case 0x180: { // vaddcuw (Add Carryout Unsigned Word, AV p136)
23486 DIP("vaddcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23487 /* unsigned_ov(x+y) = (y >u not(x)) */
23488 putVReg( vD_addr, binop( Iop_ShrN32x4,
23489 binop( Iop_CmpGT32Ux4, mkexpr( vB ),
23490 unop( Iop_NotV128, mkexpr( vA ) ) ),
23491 mkU8( 31 ) ) );
23492 break;
23494 case 0x000: // vaddubm (Add Unsigned Byte Modulo, AV p141)
23495 DIP("vaddubm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23496 putVReg( vD_addr, binop(Iop_Add8x16, mkexpr(vA), mkexpr(vB)) );
23497 break;
23499 case 0x040: // vadduhm (Add Unsigned Half Word Modulo, AV p143)
23500 DIP("vadduhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23501 putVReg( vD_addr, binop(Iop_Add16x8, mkexpr(vA), mkexpr(vB)) );
23502 break;
23504 case 0x080: // vadduwm (Add Unsigned Word Modulo, AV p145)
23505 DIP("vadduwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23506 putVReg( vD_addr, binop(Iop_Add32x4, mkexpr(vA), mkexpr(vB)) );
23507 break;
23509 case 0x0C0: // vaddudm (Add Unsigned Double Word Modulo)
23510 DIP("vaddudm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23511 putVReg( vD_addr, binop(Iop_Add64x2, mkexpr(vA), mkexpr(vB)) );
23512 break;
23514 case 0x200: // vaddubs (Add Unsigned Byte Saturate, AV p142)
23515 DIP("vaddubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23516 putVReg( vD_addr, binop(Iop_QAdd8Ux16, mkexpr(vA), mkexpr(vB)) );
23517 // TODO: set VSCR[SAT], perhaps via new primop: Iop_SatOfQAdd8Ux16
23518 break;
23520 case 0x240: // vadduhs (Add Unsigned Half Word Saturate, AV p144)
23521 DIP("vadduhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23522 putVReg( vD_addr, binop(Iop_QAdd16Ux8, mkexpr(vA), mkexpr(vB)) );
23523 // TODO: set VSCR[SAT]
23524 break;
23526 case 0x280: // vadduws (Add Unsigned Word Saturate, AV p146)
23527 DIP("vadduws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23528 putVReg( vD_addr, binop(Iop_QAdd32Ux4, mkexpr(vA), mkexpr(vB)) );
23529 // TODO: set VSCR[SAT]
23530 break;
23532 case 0x300: // vaddsbs (Add Signed Byte Saturate, AV p138)
23533 DIP("vaddsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23534 putVReg( vD_addr, binop(Iop_QAdd8Sx16, mkexpr(vA), mkexpr(vB)) );
23535 // TODO: set VSCR[SAT]
23536 break;
23538 case 0x340: // vaddshs (Add Signed Half Word Saturate, AV p139)
23539 DIP("vaddshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23540 putVReg( vD_addr, binop(Iop_QAdd16Sx8, mkexpr(vA), mkexpr(vB)) );
23541 // TODO: set VSCR[SAT]
23542 break;
23544 case 0x380: // vaddsws (Add Signed Word Saturate, AV p140)
23545 DIP("vaddsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23546 putVReg( vD_addr, binop(Iop_QAdd32Sx4, mkexpr(vA), mkexpr(vB)) );
23547 // TODO: set VSCR[SAT]
23548 break;
23551 /* Subtract */
23552 case 0x580: { // vsubcuw (Subtract Carryout Unsigned Word, AV p260)
23553 DIP("vsubcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23554 /* unsigned_ov(x-y) = (y >u x) */
23555 putVReg( vD_addr, binop(Iop_ShrN32x4,
23556 unop(Iop_NotV128,
23557 binop(Iop_CmpGT32Ux4, mkexpr(vB),
23558 mkexpr(vA))),
23559 mkU8(31)) );
23560 break;
23562 case 0x400: // vsububm (Subtract Unsigned Byte Modulo, AV p265)
23563 DIP("vsububm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23564 putVReg( vD_addr, binop(Iop_Sub8x16, mkexpr(vA), mkexpr(vB)) );
23565 break;
23567 case 0x440: // vsubuhm (Subtract Unsigned Half Word Modulo, AV p267)
23568 DIP("vsubuhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23569 putVReg( vD_addr, binop(Iop_Sub16x8, mkexpr(vA), mkexpr(vB)) );
23570 break;
23572 case 0x480: // vsubuwm (Subtract Unsigned Word Modulo, AV p269)
23573 DIP("vsubuwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23574 putVReg( vD_addr, binop(Iop_Sub32x4, mkexpr(vA), mkexpr(vB)) );
23575 break;
23577 case 0x4C0: // vsubudm (Subtract Unsigned Double Word Modulo)
23578 DIP("vsubudm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23579 putVReg( vD_addr, binop(Iop_Sub64x2, mkexpr(vA), mkexpr(vB)) );
23580 break;
23582 case 0x600: // vsububs (Subtract Unsigned Byte Saturate, AV p266)
23583 DIP("vsububs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23584 putVReg( vD_addr, binop(Iop_QSub8Ux16, mkexpr(vA), mkexpr(vB)) );
23585 // TODO: set VSCR[SAT]
23586 break;
23588 case 0x640: // vsubuhs (Subtract Unsigned HWord Saturate, AV p268)
23589 DIP("vsubuhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23590 putVReg( vD_addr, binop(Iop_QSub16Ux8, mkexpr(vA), mkexpr(vB)) );
23591 // TODO: set VSCR[SAT]
23592 break;
23594 case 0x680: // vsubuws (Subtract Unsigned Word Saturate, AV p270)
23595 DIP("vsubuws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23596 putVReg( vD_addr, binop(Iop_QSub32Ux4, mkexpr(vA), mkexpr(vB)) );
23597 // TODO: set VSCR[SAT]
23598 break;
23600 case 0x700: // vsubsbs (Subtract Signed Byte Saturate, AV p262)
23601 DIP("vsubsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23602 putVReg( vD_addr, binop(Iop_QSub8Sx16, mkexpr(vA), mkexpr(vB)) );
23603 // TODO: set VSCR[SAT]
23604 break;
23606 case 0x740: // vsubshs (Subtract Signed Half Word Saturate, AV p263)
23607 DIP("vsubshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23608 putVReg( vD_addr, binop(Iop_QSub16Sx8, mkexpr(vA), mkexpr(vB)) );
23609 // TODO: set VSCR[SAT]
23610 break;
23612 case 0x780: // vsubsws (Subtract Signed Word Saturate, AV p264)
23613 DIP("vsubsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23614 putVReg( vD_addr, binop(Iop_QSub32Sx4, mkexpr(vA), mkexpr(vB)) );
23615 // TODO: set VSCR[SAT]
23616 break;
23619 /* Maximum */
23620 case 0x002: // vmaxub (Maximum Unsigned Byte, AV p182)
23621 DIP("vmaxub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23622 putVReg( vD_addr, binop(Iop_Max8Ux16, mkexpr(vA), mkexpr(vB)) );
23623 break;
23625 case 0x042: // vmaxuh (Maximum Unsigned Half Word, AV p183)
23626 DIP("vmaxuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23627 putVReg( vD_addr, binop(Iop_Max16Ux8, mkexpr(vA), mkexpr(vB)) );
23628 break;
23630 case 0x082: // vmaxuw (Maximum Unsigned Word, AV p184)
23631 DIP("vmaxuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23632 putVReg( vD_addr, binop(Iop_Max32Ux4, mkexpr(vA), mkexpr(vB)) );
23633 break;
23635 case 0x0C2: // vmaxud (Maximum Unsigned Double word)
23636 DIP("vmaxud v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23637 putVReg( vD_addr, binop(Iop_Max64Ux2, mkexpr(vA), mkexpr(vB)) );
23638 break;
23640 case 0x102: // vmaxsb (Maximum Signed Byte, AV p179)
23641 DIP("vmaxsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23642 putVReg( vD_addr, binop(Iop_Max8Sx16, mkexpr(vA), mkexpr(vB)) );
23643 break;
23645 case 0x142: // vmaxsh (Maximum Signed Half Word, AV p180)
23646 DIP("vmaxsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23647 putVReg( vD_addr, binop(Iop_Max16Sx8, mkexpr(vA), mkexpr(vB)) );
23648 break;
23650 case 0x182: // vmaxsw (Maximum Signed Word, AV p181)
23651 DIP("vmaxsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23652 putVReg( vD_addr, binop(Iop_Max32Sx4, mkexpr(vA), mkexpr(vB)) );
23653 break;
23655 case 0x1C2: // vmaxsd (Maximum Signed Double word)
23656 DIP("vmaxsd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23657 putVReg( vD_addr, binop(Iop_Max64Sx2, mkexpr(vA), mkexpr(vB)) );
23658 break;
23660 /* Minimum */
23661 case 0x202: // vminub (Minimum Unsigned Byte, AV p191)
23662 DIP("vminub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23663 putVReg( vD_addr, binop(Iop_Min8Ux16, mkexpr(vA), mkexpr(vB)) );
23664 break;
23666 case 0x242: // vminuh (Minimum Unsigned Half Word, AV p192)
23667 DIP("vminuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23668 putVReg( vD_addr, binop(Iop_Min16Ux8, mkexpr(vA), mkexpr(vB)) );
23669 break;
23671 case 0x282: // vminuw (Minimum Unsigned Word, AV p193)
23672 DIP("vminuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23673 putVReg( vD_addr, binop(Iop_Min32Ux4, mkexpr(vA), mkexpr(vB)) );
23674 break;
23676 case 0x2C2: // vminud (Minimum Unsigned Double Word)
23677 DIP("vminud v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23678 putVReg( vD_addr, binop(Iop_Min64Ux2, mkexpr(vA), mkexpr(vB)) );
23679 break;
23681 case 0x302: // vminsb (Minimum Signed Byte, AV p188)
23682 DIP("vminsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23683 putVReg( vD_addr, binop(Iop_Min8Sx16, mkexpr(vA), mkexpr(vB)) );
23684 break;
23686 case 0x342: // vminsh (Minimum Signed Half Word, AV p189)
23687 DIP("vminsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23688 putVReg( vD_addr, binop(Iop_Min16Sx8, mkexpr(vA), mkexpr(vB)) );
23689 break;
23691 case 0x382: // vminsw (Minimum Signed Word, AV p190)
23692 DIP("vminsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23693 putVReg( vD_addr, binop(Iop_Min32Sx4, mkexpr(vA), mkexpr(vB)) );
23694 break;
23696 case 0x3C2: // vminsd (Minimum Signed Double Word)
23697 DIP("vminsd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23698 putVReg( vD_addr, binop(Iop_Min64Sx2, mkexpr(vA), mkexpr(vB)) );
23699 break;
23702 /* Average */
23703 case 0x402: // vavgub (Average Unsigned Byte, AV p152)
23704 DIP("vavgub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23705 putVReg( vD_addr, binop(Iop_Avg8Ux16, mkexpr(vA), mkexpr(vB)) );
23706 break;
23708 case 0x442: // vavguh (Average Unsigned Half Word, AV p153)
23709 DIP("vavguh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23710 putVReg( vD_addr, binop(Iop_Avg16Ux8, mkexpr(vA), mkexpr(vB)) );
23711 break;
23713 case 0x482: // vavguw (Average Unsigned Word, AV p154)
23714 DIP("vavguw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23715 putVReg( vD_addr, binop(Iop_Avg32Ux4, mkexpr(vA), mkexpr(vB)) );
23716 break;
23718 case 0x502: // vavgsb (Average Signed Byte, AV p149)
23719 DIP("vavgsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23720 putVReg( vD_addr, binop(Iop_Avg8Sx16, mkexpr(vA), mkexpr(vB)) );
23721 break;
23723 case 0x542: // vavgsh (Average Signed Half Word, AV p150)
23724 DIP("vavgsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23725 putVReg( vD_addr, binop(Iop_Avg16Sx8, mkexpr(vA), mkexpr(vB)) );
23726 break;
23728 case 0x582: // vavgsw (Average Signed Word, AV p151)
23729 DIP("vavgsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23730 putVReg( vD_addr, binop(Iop_Avg32Sx4, mkexpr(vA), mkexpr(vB)) );
23731 break;
23734 /* Multiply */
23735 case 0x008: // vmuloub (Multiply Odd Unsigned Byte, AV p213)
23736 DIP("vmuloub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23737 putVReg( vD_addr,
23738 binop(Iop_MullEven8Ux16, mkexpr(vA), mkexpr(vB)));
23739 break;
23741 case 0x048: // vmulouh (Multiply Odd Unsigned Half Word, AV p214)
23742 DIP("vmulouh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23743 putVReg( vD_addr,
23744 binop(Iop_MullEven16Ux8, mkexpr(vA), mkexpr(vB)));
23745 break;
23747 case 0x088: // vmulouw (Multiply Odd Unsigned Word)
23748 DIP("vmulouw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23749 putVReg( vD_addr, binop( Iop_MullEven32Ux4, mkexpr(vA), mkexpr(vB) ) );
23750 break;
23752 case 0x089: // vmuluwm (Multiply Unsigned Word Modulo)
23753 DIP("vmuluwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23754 putVReg( vD_addr, binop( Iop_Mul32x4, mkexpr(vA), mkexpr(vB) ) );
23755 break;
23757 case 0x108: // vmulosb (Multiply Odd Signed Byte, AV p211)
23758 DIP("vmulosb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23759 putVReg( vD_addr,
23760 binop(Iop_MullEven8Sx16, mkexpr(vA), mkexpr(vB)));
23761 break;
23763 case 0x148: // vmulosh (Multiply Odd Signed Half Word, AV p212)
23764 DIP("vmulosh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23765 putVReg( vD_addr,
23766 binop(Iop_MullEven16Sx8, mkexpr(vA), mkexpr(vB)));
23767 break;
23769 case 0x188: // vmulosw (Multiply Odd Signed Word)
23770 DIP("vmulosw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23771 putVReg( vD_addr, binop( Iop_MullEven32Sx4, mkexpr(vA), mkexpr(vB) ) );
23772 break;
23774 case 0x208: // vmuleub (Multiply Even Unsigned Byte, AV p209)
23775 DIP("vmuleub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23776 putVReg( vD_addr, MK_Iop_MullOdd8Ux16( mkexpr(vA), mkexpr(vB) ));
23777 break;
23779 case 0x248: // vmuleuh (Multiply Even Unsigned Half Word, AV p210)
23780 DIP("vmuleuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23781 putVReg( vD_addr, MK_Iop_MullOdd16Ux8( mkexpr(vA), mkexpr(vB) ));
23782 break;
23784 case 0x288: // vmuleuw (Multiply Even Unsigned Word)
23785 DIP("vmuleuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23786 putVReg( vD_addr, MK_Iop_MullOdd32Ux4( mkexpr(vA), mkexpr(vB) ) );
23787 break;
23789 case 0x308: // vmulesb (Multiply Even Signed Byte, AV p207)
23790 DIP("vmulesb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23791 putVReg( vD_addr, MK_Iop_MullOdd8Sx16( mkexpr(vA), mkexpr(vB) ));
23792 break;
23794 case 0x348: // vmulesh (Multiply Even Signed Half Word, AV p208)
23795 DIP("vmulesh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23796 putVReg( vD_addr, MK_Iop_MullOdd16Sx8( mkexpr(vA), mkexpr(vB) ));
23797 break;
23799 case 0x388: // vmulesw (Multiply Even Signed Word)
23800 DIP("vmulesw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23801 putVReg( vD_addr, MK_Iop_MullOdd32Sx4( mkexpr(vA), mkexpr(vB) ) );
23802 break;
23804 /* Sum Across Partial */
23805 case 0x608: { // vsum4ubs (Sum Partial (1/4) UB Saturate, AV p275)
23806 IRTemp aEE, aEO, aOE, aOO;
23807 aEE = aEO = aOE = aOO = IRTemp_INVALID;
23808 DIP("vsum4ubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23810 /* vA: V128_8Ux16 -> 4 x V128_32Ux4, sign-extended */
23811 expand8Ux16( mkexpr(vA), &aEvn, &aOdd ); // (15,13...),(14,12...)
23812 expand16Ux8( mkexpr(aEvn), &aEE, &aEO ); // (15,11...),(13, 9...)
23813 expand16Ux8( mkexpr(aOdd), &aOE, &aOO ); // (14,10...),(12, 8...)
23815 /* break V128 to 4xI32's, zero-extending to I64's */
23816 breakV128to4x64U( mkexpr(aEE), &a15, &a11, &a7, &a3 );
23817 breakV128to4x64U( mkexpr(aOE), &a14, &a10, &a6, &a2 );
23818 breakV128to4x64U( mkexpr(aEO), &a13, &a9, &a5, &a1 );
23819 breakV128to4x64U( mkexpr(aOO), &a12, &a8, &a4, &a0 );
23820 breakV128to4x64U( mkexpr(vB), &b3, &b2, &b1, &b0 );
23822 /* add lanes */
23823 assign( z3, binop(Iop_Add64, mkexpr(b3),
23824 binop(Iop_Add64,
23825 binop(Iop_Add64, mkexpr(a15), mkexpr(a14)),
23826 binop(Iop_Add64, mkexpr(a13), mkexpr(a12)))) );
23827 assign( z2, binop(Iop_Add64, mkexpr(b2),
23828 binop(Iop_Add64,
23829 binop(Iop_Add64, mkexpr(a11), mkexpr(a10)),
23830 binop(Iop_Add64, mkexpr(a9), mkexpr(a8)))) );
23831 assign( z1, binop(Iop_Add64, mkexpr(b1),
23832 binop(Iop_Add64,
23833 binop(Iop_Add64, mkexpr(a7), mkexpr(a6)),
23834 binop(Iop_Add64, mkexpr(a5), mkexpr(a4)))) );
23835 assign( z0, binop(Iop_Add64, mkexpr(b0),
23836 binop(Iop_Add64,
23837 binop(Iop_Add64, mkexpr(a3), mkexpr(a2)),
23838 binop(Iop_Add64, mkexpr(a1), mkexpr(a0)))) );
23840 /* saturate-narrow to 32bit, and combine to V128 */
23841 putVReg( vD_addr, mkV128from4x64U( mkexpr(z3), mkexpr(z2),
23842 mkexpr(z1), mkexpr(z0)) );
23843 break;
23845 case 0x708: { // vsum4sbs (Sum Partial (1/4) SB Saturate, AV p273)
23846 IRTemp aEE, aEO, aOE, aOO;
23847 aEE = aEO = aOE = aOO = IRTemp_INVALID;
23848 DIP("vsum4sbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23850 /* vA: V128_8Sx16 -> 4 x V128_32Sx4, sign-extended */
23851 expand8Sx16( mkexpr(vA), &aEvn, &aOdd ); // (15,13...),(14,12...)
23852 expand16Sx8( mkexpr(aEvn), &aEE, &aEO ); // (15,11...),(13, 9...)
23853 expand16Sx8( mkexpr(aOdd), &aOE, &aOO ); // (14,10...),(12, 8...)
23855 /* break V128 to 4xI32's, sign-extending to I64's */
23856 breakV128to4x64S( mkexpr(aEE), &a15, &a11, &a7, &a3 );
23857 breakV128to4x64S( mkexpr(aOE), &a14, &a10, &a6, &a2 );
23858 breakV128to4x64S( mkexpr(aEO), &a13, &a9, &a5, &a1 );
23859 breakV128to4x64S( mkexpr(aOO), &a12, &a8, &a4, &a0 );
23860 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
23862 /* add lanes */
23863 assign( z3, binop(Iop_Add64, mkexpr(b3),
23864 binop(Iop_Add64,
23865 binop(Iop_Add64, mkexpr(a15), mkexpr(a14)),
23866 binop(Iop_Add64, mkexpr(a13), mkexpr(a12)))) );
23867 assign( z2, binop(Iop_Add64, mkexpr(b2),
23868 binop(Iop_Add64,
23869 binop(Iop_Add64, mkexpr(a11), mkexpr(a10)),
23870 binop(Iop_Add64, mkexpr(a9), mkexpr(a8)))) );
23871 assign( z1, binop(Iop_Add64, mkexpr(b1),
23872 binop(Iop_Add64,
23873 binop(Iop_Add64, mkexpr(a7), mkexpr(a6)),
23874 binop(Iop_Add64, mkexpr(a5), mkexpr(a4)))) );
23875 assign( z0, binop(Iop_Add64, mkexpr(b0),
23876 binop(Iop_Add64,
23877 binop(Iop_Add64, mkexpr(a3), mkexpr(a2)),
23878 binop(Iop_Add64, mkexpr(a1), mkexpr(a0)))) );
23880 /* saturate-narrow to 32bit, and combine to V128 */
23881 putVReg( vD_addr, mkV128from4x64S( mkexpr(z3), mkexpr(z2),
23882 mkexpr(z1), mkexpr(z0)) );
23883 break;
23885 case 0x648: { // vsum4shs (Sum Partial (1/4) SHW Saturate, AV p274)
23886 DIP("vsum4shs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23888 /* vA: V128_16Sx8 -> 2 x V128_32Sx4, sign-extended */
23889 expand16Sx8( mkexpr(vA), &aEvn, &aOdd ); // (7,5...),(6,4...)
23891 /* break V128 to 4xI32's, sign-extending to I64's */
23892 breakV128to4x64S( mkexpr(aEvn), &a7, &a5, &a3, &a1 );
23893 breakV128to4x64S( mkexpr(aOdd), &a6, &a4, &a2, &a0 );
23894 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
23896 /* add lanes */
23897 assign( z3, binop(Iop_Add64, mkexpr(b3),
23898 binop(Iop_Add64, mkexpr(a7), mkexpr(a6))));
23899 assign( z2, binop(Iop_Add64, mkexpr(b2),
23900 binop(Iop_Add64, mkexpr(a5), mkexpr(a4))));
23901 assign( z1, binop(Iop_Add64, mkexpr(b1),
23902 binop(Iop_Add64, mkexpr(a3), mkexpr(a2))));
23903 assign( z0, binop(Iop_Add64, mkexpr(b0),
23904 binop(Iop_Add64, mkexpr(a1), mkexpr(a0))));
23906 /* saturate-narrow to 32bit, and combine to V128 */
23907 putVReg( vD_addr, mkV128from4x64S( mkexpr(z3), mkexpr(z2),
23908 mkexpr(z1), mkexpr(z0)) );
23909 break;
23911 case 0x688: { // vsum2sws (Sum Partial (1/2) SW Saturate, AV p272)
23912 DIP("vsum2sws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23914 /* break V128 to 4xI32's, sign-extending to I64's */
23915 breakV128to4x64S( mkexpr(vA), &a3, &a2, &a1, &a0 );
23916 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
23918 /* add lanes */
23919 assign( z2, binop(Iop_Add64, mkexpr(b2),
23920 binop(Iop_Add64, mkexpr(a3), mkexpr(a2))) );
23921 assign( z0, binop(Iop_Add64, mkexpr(b0),
23922 binop(Iop_Add64, mkexpr(a1), mkexpr(a0))) );
23924 /* saturate-narrow to 32bit, and combine to V128 */
23925 putVReg( vD_addr, mkV128from4x64S( mkU64(0), mkexpr(z2),
23926 mkU64(0), mkexpr(z0)) );
23927 break;
23929 case 0x788: { // vsumsws (Sum SW Saturate, AV p271)
23930 DIP("vsumsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23932 /* break V128 to 4xI32's, sign-extending to I64's */
23933 breakV128to4x64S( mkexpr(vA), &a3, &a2, &a1, &a0 );
23934 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
23936 /* add lanes */
23937 assign( z0, binop(Iop_Add64, mkexpr(b0),
23938 binop(Iop_Add64,
23939 binop(Iop_Add64, mkexpr(a3), mkexpr(a2)),
23940 binop(Iop_Add64, mkexpr(a1), mkexpr(a0)))) );
23942 /* saturate-narrow to 32bit, and combine to V128 */
23943 putVReg( vD_addr, mkV128from4x64S( mkU64(0), mkU64(0),
23944 mkU64(0), mkexpr(z0)) );
23945 break;
23947 default:
23948 vex_printf("dis_av_arith(ppc)(opc2=0x%x)\n", opc2);
23949 return False;
23951 return True;
23955 AltiVec Logic Instructions
23957 static Bool dis_av_logic ( UInt theInstr )
23959 /* VX-Form */
23960 UChar opc1 = ifieldOPC(theInstr);
23961 UChar vD_addr = ifieldRegDS(theInstr);
23962 UChar vA_addr = ifieldRegA(theInstr);
23963 UChar vB_addr = ifieldRegB(theInstr);
23964 UInt opc2 = IFIELD( theInstr, 0, 11 );
23966 IRTemp vA = newTemp(Ity_V128);
23967 IRTemp vB = newTemp(Ity_V128);
23968 assign( vA, getVReg(vA_addr));
23969 assign( vB, getVReg(vB_addr));
23971 if (opc1 != 0x4) {
23972 vex_printf("dis_av_logic(ppc)(opc1 != 0x4)\n");
23973 return False;
23976 switch (opc2) {
23977 case 0x404: // vand (And, AV p147)
23978 DIP("vand v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23979 putVReg( vD_addr, binop(Iop_AndV128, mkexpr(vA), mkexpr(vB)) );
23980 break;
23982 case 0x444: // vandc (And, AV p148)
23983 DIP("vandc v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23984 putVReg( vD_addr, binop(Iop_AndV128, mkexpr(vA),
23985 unop(Iop_NotV128, mkexpr(vB))) );
23986 break;
23988 case 0x484: // vor (Or, AV p217)
23989 DIP("vor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23990 putVReg( vD_addr, binop(Iop_OrV128, mkexpr(vA), mkexpr(vB)) );
23991 break;
23993 case 0x4C4: // vxor (Xor, AV p282)
23994 DIP("vxor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23995 putVReg( vD_addr, binop(Iop_XorV128, mkexpr(vA), mkexpr(vB)) );
23996 break;
23998 case 0x504: // vnor (Nor, AV p216)
23999 DIP("vnor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24000 putVReg( vD_addr,
24001 unop(Iop_NotV128, binop(Iop_OrV128, mkexpr(vA), mkexpr(vB))) );
24002 break;
24004 case 0x544: // vorc (vA Or'd with complement of vb)
24005 DIP("vorc v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24006 putVReg( vD_addr, binop( Iop_OrV128,
24007 mkexpr( vA ),
24008 unop( Iop_NotV128, mkexpr( vB ) ) ) );
24009 break;
24011 case 0x584: // vnand (Nand)
24012 DIP("vnand v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24013 putVReg( vD_addr, unop( Iop_NotV128,
24014 binop(Iop_AndV128, mkexpr( vA ),
24015 mkexpr( vB ) ) ) );
24016 break;
24018 case 0x684: // veqv (complemented XOr)
24019 DIP("veqv v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24020 putVReg( vD_addr, unop( Iop_NotV128,
24021 binop( Iop_XorV128, mkexpr( vA ),
24022 mkexpr( vB ) ) ) );
24023 break;
24025 default:
24026 vex_printf("dis_av_logic(ppc)(opc2=0x%x)\n", opc2);
24027 return False;
24029 return True;
24033 AltiVec Compare Instructions
24035 static Bool dis_av_cmp ( UInt theInstr )
24037 /* VXR-Form */
24038 UChar opc1 = ifieldOPC(theInstr);
24039 UChar vD_addr = ifieldRegDS(theInstr);
24040 UChar vA_addr = ifieldRegA(theInstr);
24041 UChar vB_addr = ifieldRegB(theInstr);
24042 UChar flag_rC = ifieldBIT10(theInstr);
24043 UInt opc2 = IFIELD( theInstr, 0, 10 );
24045 IRTemp vA = newTemp(Ity_V128);
24046 IRTemp vB = newTemp(Ity_V128);
24047 IRTemp vD = newTemp(Ity_V128);
24048 assign( vA, getVReg(vA_addr));
24049 assign( vB, getVReg(vB_addr));
24051 if (opc1 != 0x4) {
24052 vex_printf("dis_av_cmp(ppc)(instr)\n");
24053 return False;
24056 switch (opc2) {
24057 case 0x006: // vcmpequb (Compare Equal-to Unsigned B, AV p160)
24058 DIP("vcmpequb%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24059 vD_addr, vA_addr, vB_addr);
24060 assign( vD, binop(Iop_CmpEQ8x16, mkexpr(vA), mkexpr(vB)) );
24061 break;
24063 case 0x007: // vcmpneb (Compare Not Equal byte)
24064 DIP("vcmpneb%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24065 vD_addr, vA_addr, vB_addr);
24066 assign( vD, unop( Iop_NotV128,
24067 binop( Iop_CmpEQ8x16, mkexpr( vA ), mkexpr( vB ) ) ) );
24068 break;
24070 case 0x046: // vcmpequh (Compare Equal-to Unsigned HW, AV p161)
24071 DIP("vcmpequh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24072 vD_addr, vA_addr, vB_addr);
24073 assign( vD, binop(Iop_CmpEQ16x8, mkexpr(vA), mkexpr(vB)) );
24074 break;
24076 case 0x047: // vcmpneh (Compare Not Equal-to Halfword)
24077 DIP("vcmpneh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24078 vD_addr, vA_addr, vB_addr);
24079 assign( vD, unop( Iop_NotV128,
24080 binop( Iop_CmpEQ16x8, mkexpr( vA ), mkexpr( vB ) ) ) );
24081 break;
24083 case 0x086: // vcmpequw (Compare Equal-to Unsigned W, AV p162)
24084 DIP("vcmpequw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24085 vD_addr, vA_addr, vB_addr);
24086 assign( vD, binop(Iop_CmpEQ32x4, mkexpr(vA), mkexpr(vB)) );
24087 break;
24089 case 0x087: // vcmpnew (Compare Not Equal-to Word)
24090 DIP("vcmpnew%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24091 vD_addr, vA_addr, vB_addr);
24092 assign( vD, unop( Iop_NotV128,
24093 binop( Iop_CmpEQ32x4, mkexpr( vA ), mkexpr( vB ) ) ) );
24094 break;
24096 case 0x107: // vcmpnezb (Compare Not Equal or Zero byte)
24098 IRTemp vAeqvB = newTemp( Ity_V128 );
24099 IRTemp vAeq0 = newTemp( Ity_V128 );
24100 IRTemp vBeq0 = newTemp( Ity_V128 );
24101 IRTemp zero = newTemp( Ity_V128 );
24103 DIP("vcmpnezb%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24104 vD_addr, vA_addr, vB_addr);
24106 assign( zero, binop( Iop_64HLtoV128, mkU64( 0 ), mkU64( 0 ) ) );
24107 assign( vAeq0, binop( Iop_CmpEQ8x16, mkexpr( vA ), mkexpr( zero ) ) );
24108 assign( vBeq0, binop( Iop_CmpEQ8x16, mkexpr( vB ), mkexpr( zero ) ) );
24109 assign( vAeqvB, unop( Iop_NotV128,
24110 binop( Iop_CmpEQ8x16, mkexpr( vA ),
24111 mkexpr( vB ) ) ) );
24113 assign( vD, mkOr3_V128( vAeqvB, vAeq0, vBeq0 ) );
24115 break;
24117 case 0x147: // vcmpnezh (Compare Not Equal or Zero Halfword)
24119 IRTemp vAeqvB = newTemp( Ity_V128 );
24120 IRTemp vAeq0 = newTemp( Ity_V128 );
24121 IRTemp vBeq0 = newTemp( Ity_V128 );
24122 IRTemp zero = newTemp( Ity_V128 );
24124 DIP("vcmpnezh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24125 vD_addr, vA_addr, vB_addr);
24127 assign( zero, binop( Iop_64HLtoV128, mkU64( 0 ), mkU64( 0 ) ) );
24128 assign( vAeq0, binop( Iop_CmpEQ16x8, mkexpr( vA ), mkexpr( zero ) ) );
24129 assign( vBeq0, binop( Iop_CmpEQ16x8, mkexpr( vB ), mkexpr( zero ) ) );
24130 assign( vAeqvB, unop( Iop_NotV128,
24131 binop(Iop_CmpEQ16x8, mkexpr( vA ),
24132 mkexpr( vB ) ) ) );
24134 assign( vD, binop( Iop_OrV128,
24135 binop( Iop_OrV128,
24136 mkexpr( vAeq0 ),
24137 mkexpr( vBeq0 ) ),
24138 mkexpr( vAeqvB ) ) );
24140 break;
24142 case 0x187: // vcmpnezw (Compare Not Equal or Zero Word)
24144 IRTemp vAeqvB = newTemp( Ity_V128 );
24145 IRTemp vAeq0 = newTemp( Ity_V128 );
24146 IRTemp vBeq0 = newTemp( Ity_V128 );
24147 IRTemp zero = newTemp( Ity_V128 );
24149 DIP("vcmpnezw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24150 vD_addr, vA_addr, vB_addr);
24152 assign( zero, binop( Iop_64HLtoV128, mkU64( 0 ), mkU64( 0 ) ) );
24153 assign( vAeq0, binop( Iop_CmpEQ32x4, mkexpr( vA ), mkexpr( zero ) ) );
24154 assign( vBeq0, binop( Iop_CmpEQ32x4, mkexpr( vB ), mkexpr( zero ) ) );
24155 assign( vAeqvB, unop( Iop_NotV128,
24156 binop(Iop_CmpEQ32x4, mkexpr( vA ),
24157 mkexpr( vB ) ) ) );
24159 assign( vD, binop( Iop_OrV128,
24160 binop( Iop_OrV128,
24161 mkexpr( vAeq0 ),
24162 mkexpr( vBeq0 ) ),
24163 mkexpr( vAeqvB ) ) );
24165 break;
24167 case 0x0C7: // vcmpequd (Compare Equal-to Unsigned Doubleword)
24168 DIP("vcmpequd%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24169 vD_addr, vA_addr, vB_addr);
24170 assign( vD, binop(Iop_CmpEQ64x2, mkexpr(vA), mkexpr(vB)) );
24171 break;
24173 case 0x206: // vcmpgtub (Compare Greater-than Unsigned B, AV p168)
24174 DIP("vcmpgtub%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24175 vD_addr, vA_addr, vB_addr);
24176 assign( vD, binop(Iop_CmpGT8Ux16, mkexpr(vA), mkexpr(vB)) );
24177 break;
24179 case 0x246: // vcmpgtuh (Compare Greater-than Unsigned HW, AV p169)
24180 DIP("vcmpgtuh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24181 vD_addr, vA_addr, vB_addr);
24182 assign( vD, binop(Iop_CmpGT16Ux8, mkexpr(vA), mkexpr(vB)) );
24183 break;
24185 case 0x286: // vcmpgtuw (Compare Greater-than Unsigned W, AV p170)
24186 DIP("vcmpgtuw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24187 vD_addr, vA_addr, vB_addr);
24188 assign( vD, binop(Iop_CmpGT32Ux4, mkexpr(vA), mkexpr(vB)) );
24189 break;
24191 case 0x2C7: // vcmpgtud (Compare Greater-than Unsigned double)
24192 DIP("vcmpgtud%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24193 vD_addr, vA_addr, vB_addr);
24194 assign( vD, binop(Iop_CmpGT64Ux2, mkexpr(vA), mkexpr(vB)) );
24195 break;
24197 case 0x306: // vcmpgtsb (Compare Greater-than Signed B, AV p165)
24198 DIP("vcmpgtsb%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24199 vD_addr, vA_addr, vB_addr);
24200 assign( vD, binop(Iop_CmpGT8Sx16, mkexpr(vA), mkexpr(vB)) );
24201 break;
24203 case 0x346: // vcmpgtsh (Compare Greater-than Signed HW, AV p166)
24204 DIP("vcmpgtsh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24205 vD_addr, vA_addr, vB_addr);
24206 assign( vD, binop(Iop_CmpGT16Sx8, mkexpr(vA), mkexpr(vB)) );
24207 break;
24209 case 0x386: // vcmpgtsw (Compare Greater-than Signed W, AV p167)
24210 DIP("vcmpgtsw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24211 vD_addr, vA_addr, vB_addr);
24212 assign( vD, binop(Iop_CmpGT32Sx4, mkexpr(vA), mkexpr(vB)) );
24213 break;
24215 case 0x3C7: // vcmpgtsd (Compare Greater-than Signed double)
24216 DIP("vcmpgtsd%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
24217 vD_addr, vA_addr, vB_addr);
24218 assign( vD, binop(Iop_CmpGT64Sx2, mkexpr(vA), mkexpr(vB)) );
24219 break;
24221 default:
24222 vex_printf("dis_av_cmp(ppc)(opc2)\n");
24223 return False;
24226 putVReg( vD_addr, mkexpr(vD) );
24228 if (flag_rC) {
24229 set_AV_CR6( mkexpr(vD), True );
24231 return True;
24235 AltiVec Multiply-Sum Instructions
24237 static Bool dis_av_multarith ( UInt theInstr )
24239 /* VA-Form */
24240 UChar opc1 = ifieldOPC(theInstr);
24241 UChar vD_addr = ifieldRegDS(theInstr);
24242 UChar vA_addr = ifieldRegA(theInstr);
24243 UChar vB_addr = ifieldRegB(theInstr);
24244 UChar vC_addr = ifieldRegC(theInstr);
24245 UChar opc2 = toUChar( IFIELD( theInstr, 0, 6 ) );
24247 IRTemp vA = newTemp(Ity_V128);
24248 IRTemp vB = newTemp(Ity_V128);
24249 IRTemp vC = newTemp(Ity_V128);
24250 IRTemp zeros = newTemp(Ity_V128);
24251 IRTemp aLo = newTemp(Ity_V128);
24252 IRTemp bLo = newTemp(Ity_V128);
24253 IRTemp cLo = newTemp(Ity_V128);
24254 IRTemp zLo = newTemp(Ity_V128);
24255 IRTemp aHi = newTemp(Ity_V128);
24256 IRTemp bHi = newTemp(Ity_V128);
24257 IRTemp cHi = newTemp(Ity_V128);
24258 IRTemp zHi = newTemp(Ity_V128);
24259 IRTemp abEvn = newTemp(Ity_V128);
24260 IRTemp abOdd = newTemp(Ity_V128);
24261 IRTemp z3 = newTemp(Ity_I64);
24262 IRTemp z2 = newTemp(Ity_I64);
24263 IRTemp z1 = newTemp(Ity_I64);
24264 IRTemp z0 = newTemp(Ity_I64);
24265 IRTemp ab7, ab6, ab5, ab4, ab3, ab2, ab1, ab0;
24266 IRTemp c3, c2, c1, c0;
24268 ab7 = ab6 = ab5 = ab4 = ab3 = ab2 = ab1 = ab0 = IRTemp_INVALID;
24269 c3 = c2 = c1 = c0 = IRTemp_INVALID;
24271 assign( vA, getVReg(vA_addr));
24272 assign( vB, getVReg(vB_addr));
24273 assign( vC, getVReg(vC_addr));
24274 assign( zeros, unop(Iop_Dup32x4, mkU32(0)) );
24276 if (opc1 != 0x4) {
24277 vex_printf("dis_av_multarith(ppc)(instr)\n");
24278 return False;
24281 switch (opc2) {
24282 /* Multiply-Add */
24283 case 0x20: { // vmhaddshs (Mult Hi, Add Signed HW Saturate, AV p185)
24284 IRTemp cSigns = newTemp(Ity_V128);
24285 DIP("vmhaddshs v%d,v%d,v%d,v%d\n",
24286 vD_addr, vA_addr, vB_addr, vC_addr);
24287 assign(cSigns, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vC)));
24288 assign(aLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vA)));
24289 assign(bLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vB)));
24290 assign(cLo, binop(Iop_InterleaveLO16x8, mkexpr(cSigns),mkexpr(vC)));
24291 assign(aHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vA)));
24292 assign(bHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vB)));
24293 assign(cHi, binop(Iop_InterleaveHI16x8, mkexpr(cSigns),mkexpr(vC)));
24295 assign( zLo, binop(Iop_Add32x4, mkexpr(cLo),
24296 binop(Iop_SarN32x4,
24297 binop(Iop_MullEven16Sx8,
24298 mkexpr(aLo), mkexpr(bLo)),
24299 mkU8(15))) );
24301 assign( zHi, binop(Iop_Add32x4, mkexpr(cHi),
24302 binop(Iop_SarN32x4,
24303 binop(Iop_MullEven16Sx8,
24304 mkexpr(aHi), mkexpr(bHi)),
24305 mkU8(15))) );
24307 putVReg( vD_addr,
24308 binop(Iop_QNarrowBin32Sto16Sx8, mkexpr(zHi), mkexpr(zLo)) );
24309 break;
24311 case 0x21: { // vmhraddshs (Mult High Round, Add Signed HW Saturate, AV p186)
24312 IRTemp zKonst = newTemp(Ity_V128);
24313 IRTemp cSigns = newTemp(Ity_V128);
24314 DIP("vmhraddshs v%d,v%d,v%d,v%d\n",
24315 vD_addr, vA_addr, vB_addr, vC_addr);
24316 assign(cSigns, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vC)) );
24317 assign(aLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vA)));
24318 assign(bLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vB)));
24319 assign(cLo, binop(Iop_InterleaveLO16x8, mkexpr(cSigns),mkexpr(vC)));
24320 assign(aHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vA)));
24321 assign(bHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vB)));
24322 assign(cHi, binop(Iop_InterleaveHI16x8, mkexpr(cSigns),mkexpr(vC)));
24324 /* shifting our const avoids store/load version of Dup */
24325 assign( zKonst, binop(Iop_ShlN32x4, unop(Iop_Dup32x4, mkU32(0x1)),
24326 mkU8(14)) );
24328 assign( zLo, binop(Iop_Add32x4, mkexpr(cLo),
24329 binop(Iop_SarN32x4,
24330 binop(Iop_Add32x4, mkexpr(zKonst),
24331 binop(Iop_MullEven16Sx8,
24332 mkexpr(aLo), mkexpr(bLo))),
24333 mkU8(15))) );
24335 assign( zHi, binop(Iop_Add32x4, mkexpr(cHi),
24336 binop(Iop_SarN32x4,
24337 binop(Iop_Add32x4, mkexpr(zKonst),
24338 binop(Iop_MullEven16Sx8,
24339 mkexpr(aHi), mkexpr(bHi))),
24340 mkU8(15))) );
24342 putVReg( vD_addr,
24343 binop(Iop_QNarrowBin32Sto16Sx8, mkexpr(zHi), mkexpr(zLo)) );
24344 break;
24346 case 0x22: { // vmladduhm (Mult Low, Add Unsigned HW Modulo, AV p194)
24347 DIP("vmladduhm v%d,v%d,v%d,v%d\n",
24348 vD_addr, vA_addr, vB_addr, vC_addr);
24349 assign(aLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vA)));
24350 assign(bLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vB)));
24351 assign(cLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vC)));
24352 assign(aHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vA)));
24353 assign(bHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vB)));
24354 assign(cHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vC)));
24355 assign(zLo, binop(Iop_Add32x4,
24356 binop(Iop_MullEven16Ux8, mkexpr(aLo), mkexpr(bLo)),
24357 mkexpr(cLo)) );
24358 assign(zHi, binop(Iop_Add32x4,
24359 binop(Iop_MullEven16Ux8, mkexpr(aHi), mkexpr(bHi)),
24360 mkexpr(cHi)));
24361 putVReg( vD_addr,
24362 binop(Iop_NarrowBin32to16x8, mkexpr(zHi), mkexpr(zLo)) );
24363 break;
24366 case 0x23: { // vmsumudm
24367 DIP("vmsumudm v%d,v%d,v%d,v%d\n",
24368 vD_addr, vA_addr, vB_addr, vC_addr);
24369 /* This instruction takes input vectors VA, VB consisting of 2 usigned
24370 64-bit integer elements and a 128 bit unsigned input U128_C. The
24371 instruction performs the following operation:
24373 VA[0] * VB[0] -> U128_mul_result0;
24374 VA[1] * VB[1] -> U128_mul_result1;
24375 U128_C + U128_mul_result0 + U128_mul_result1 -> U128_partial_sum;
24376 carry out and overflow is discarded.
24379 /* The Iop_MulI128low assumes the upper 64-bits in the two input operands
24380 are zero. */
24381 IRTemp mul_result0 = newTemp( Ity_I128 );
24382 IRTemp mul_result1 = newTemp( Ity_I128 );
24383 IRTemp partial_sum_hi = newTemp( Ity_I64 );
24384 IRTemp partial_sum_low = newTemp( Ity_I64 );
24385 IRTemp result_hi = newTemp( Ity_I64 );
24386 IRTemp result_low = newTemp( Ity_I64 );
24387 IRExpr *ca_sum, *ca_result;
24390 /* Do multiplications */
24391 assign ( mul_result0, binop( Iop_MullU64,
24392 unop( Iop_V128to64, mkexpr( vA ) ),
24393 unop( Iop_V128to64, mkexpr( vB) ) ) );
24395 assign ( mul_result1, binop( Iop_MullU64,
24396 unop( Iop_V128HIto64, mkexpr( vA ) ),
24397 unop( Iop_V128HIto64, mkexpr( vB) ) ) );
24399 /* Add the two 128-bit results using 64-bit unsigned adds, calculate carry
24400 from low 64-bits add into sum of upper 64-bits. Throw away carry out
24401 of the upper 64-bit sum. */
24402 assign ( partial_sum_low, binop( Iop_Add64,
24403 unop( Iop_128to64, mkexpr( mul_result0 ) ),
24404 unop( Iop_128to64, mkexpr( mul_result1 ) )
24405 ) );
24407 /* ca_sum is type U32 */
24408 ca_sum = calculate_XER_CA_64 ( PPCG_FLAG_OP_ADD,
24409 mkexpr(partial_sum_low ),
24410 unop( Iop_128to64, mkexpr( mul_result0 ) ),
24411 unop( Iop_128to64, mkexpr( mul_result1 ) ),
24412 mkU64( 0 ) );
24414 assign ( partial_sum_hi,
24415 binop( Iop_Add64,
24416 binop( Iop_Add64,
24417 unop( Iop_128HIto64, mkexpr( mul_result0 ) ),
24418 unop( Iop_128HIto64, mkexpr( mul_result1 ) ) ),
24419 binop( Iop_32HLto64, mkU32( 0 ), ca_sum ) ) );
24421 /* Now add in the value of C */
24422 assign ( result_low, binop( Iop_Add64,
24423 mkexpr( partial_sum_low ),
24424 unop( Iop_V128to64, mkexpr( vC ) ) ) );
24426 /* ca_result is type U32 */
24427 ca_result = calculate_XER_CA_64( PPCG_FLAG_OP_ADD,
24428 mkexpr( result_low ),
24429 mkexpr( partial_sum_low ),
24430 unop( Iop_V128to64,
24431 mkexpr( vC ) ),
24432 mkU64( 0 ) );
24434 assign ( result_hi,
24435 binop( Iop_Add64,
24436 binop( Iop_Add64,
24437 mkexpr( partial_sum_hi ),
24438 unop( Iop_V128HIto64, mkexpr( vC ) ) ),
24439 binop( Iop_32HLto64, mkU32( 0 ), ca_result ) ) );
24441 putVReg( vD_addr, binop( Iop_64HLtoV128,
24442 mkexpr( result_hi ), mkexpr ( result_low ) ) );
24443 break;
24446 /* Multiply-Sum */
24447 case 0x24: { // vmsumubm (Multiply Sum Unsigned B Modulo, AV p204)
24448 IRTemp abEE, abEO, abOE, abOO;
24449 abEE = abEO = abOE = abOO = IRTemp_INVALID;
24450 DIP("vmsumubm v%d,v%d,v%d,v%d\n",
24451 vD_addr, vA_addr, vB_addr, vC_addr);
24453 /* multiply vA,vB (unsigned, widening) */
24454 assign( abEvn, MK_Iop_MullOdd8Ux16( mkexpr(vA), mkexpr(vB) ));
24455 assign( abOdd, binop(Iop_MullEven8Ux16, mkexpr(vA), mkexpr(vB)) );
24457 /* evn,odd: V128_16Ux8 -> 2 x V128_32Ux4, zero-extended */
24458 expand16Ux8( mkexpr(abEvn), &abEE, &abEO );
24459 expand16Ux8( mkexpr(abOdd), &abOE, &abOO );
24461 putVReg( vD_addr,
24462 binop(Iop_Add32x4, mkexpr(vC),
24463 binop(Iop_Add32x4,
24464 binop(Iop_Add32x4, mkexpr(abEE), mkexpr(abEO)),
24465 binop(Iop_Add32x4, mkexpr(abOE), mkexpr(abOO)))) );
24466 break;
24468 case 0x25: { // vmsummbm (Multiply Sum Mixed-Sign B Modulo, AV p201)
24469 IRTemp aEvn, aOdd, bEvn, bOdd;
24470 IRTemp abEE = newTemp(Ity_V128);
24471 IRTemp abEO = newTemp(Ity_V128);
24472 IRTemp abOE = newTemp(Ity_V128);
24473 IRTemp abOO = newTemp(Ity_V128);
24474 IRTemp prod = newTemp(Ity_V128);
24475 IRTemp sum0 = newTemp(Ity_I32);
24476 IRTemp sum1 = newTemp(Ity_I32);
24477 IRTemp sum2 = newTemp(Ity_I32);
24478 IRTemp sum3 = newTemp(Ity_I32);
24480 aEvn = aOdd = bEvn = bOdd = IRTemp_INVALID;
24481 DIP("vmsummbm v%d,v%d,v%d,v%d\n",
24482 vD_addr, vA_addr, vB_addr, vC_addr);
24484 /* sign-extend vA, zero-extend vB, for mixed-sign multiply
24485 (separating out adjacent lanes to different vectors) */
24486 expand8Sx16( mkexpr(vA), &aEvn, &aOdd );
24487 expand8Ux16( mkexpr(vB), &bEvn, &bOdd );
24489 /* multiply vA, vB, again separating adjacent lanes */
24490 assign( abEE, MK_Iop_MullOdd16Sx8( mkexpr(aEvn), mkexpr(bEvn) ));
24491 assign( abEO, binop(Iop_MullEven16Sx8, mkexpr(aEvn), mkexpr(bEvn)) );
24492 assign( abOE, MK_Iop_MullOdd16Sx8( mkexpr(aOdd), mkexpr(bOdd) ));
24493 assign( abOO, binop(Iop_MullEven16Sx8, mkexpr(aOdd), mkexpr(bOdd)) );
24495 /* add results together, + vC */
24496 /* Unfortunately, we need to chop the results of the adds to 32-bits. The
24497 following lane based calculations don't handle the overflow correctly. Need
24498 to explicitly do the adds and 32-bit chops.
24500 putVReg( vD_addr,
24501 binop(Iop_QAdd32Sx4, mkexpr(vC),
24502 binop(Iop_QAdd32Sx4,
24503 binop(Iop_QAdd32Sx4, mkexpr(abEE), mkexpr(abEO)),
24504 binop(Iop_QAdd32Sx4, mkexpr(abOE), mkexpr(abOO)))) );
24507 assign(prod,
24508 binop(Iop_QAdd32Sx4,
24509 binop(Iop_QAdd32Sx4, mkexpr(abEE), mkexpr(abEO)),
24510 binop(Iop_QAdd32Sx4, mkexpr(abOE), mkexpr(abOO))));
24511 assign( sum0,
24512 unop(Iop_64to32,
24513 binop(Iop_Add64,
24514 unop(Iop_32Sto64,
24515 unop(Iop_64HIto32, unop(Iop_V128HIto64, mkexpr(prod)))),
24516 unop(Iop_32Sto64,
24517 unop(Iop_64HIto32, unop(Iop_V128HIto64, mkexpr(vC)))))));
24518 assign( sum1,
24519 unop(Iop_64to32,
24520 binop(Iop_Add64,
24521 unop(Iop_32Sto64,
24522 unop(Iop_64to32, unop(Iop_V128HIto64, mkexpr(prod)))),
24523 unop(Iop_32Sto64,
24524 unop(Iop_64to32, unop(Iop_V128HIto64, mkexpr(vC)))))));
24525 assign( sum2,
24526 unop(Iop_64to32,
24527 binop(Iop_Add64,
24528 unop(Iop_32Sto64,
24529 unop(Iop_64HIto32, unop(Iop_V128to64, mkexpr(prod)))),
24530 unop(Iop_32Sto64,
24531 unop(Iop_64HIto32, unop(Iop_V128to64, mkexpr(vC)))))));
24532 assign( sum3,
24533 unop(Iop_64to32,
24534 binop(Iop_Add64,
24535 unop(Iop_32Sto64,
24536 unop(Iop_64to32, unop(Iop_V128to64, mkexpr(prod)))),
24537 unop(Iop_32Sto64,
24538 unop(Iop_64to32, unop(Iop_V128to64, mkexpr(vC)))))));
24539 putVReg( vD_addr, binop(Iop_64HLtoV128,
24540 binop(Iop_32HLto64, mkexpr(sum0), mkexpr(sum1)),
24541 binop(Iop_32HLto64, mkexpr(sum2), mkexpr(sum3))));
24543 break;
24545 case 0x26: { // vmsumuhm (Multiply Sum Unsigned HW Modulo, AV p205)
24546 DIP("vmsumuhm v%d,v%d,v%d,v%d\n",
24547 vD_addr, vA_addr, vB_addr, vC_addr);
24548 assign( abEvn, MK_Iop_MullOdd16Ux8( mkexpr(vA), mkexpr(vB) ));
24549 assign( abOdd, binop(Iop_MullEven16Ux8, mkexpr(vA), mkexpr(vB)) );
24550 putVReg( vD_addr,
24551 binop(Iop_Add32x4, mkexpr(vC),
24552 binop(Iop_Add32x4, mkexpr(abEvn), mkexpr(abOdd))) );
24553 break;
24555 case 0x27: { // vmsumuhs (Multiply Sum Unsigned HW Saturate, AV p206)
24556 DIP("vmsumuhs v%d,v%d,v%d,v%d\n",
24557 vD_addr, vA_addr, vB_addr, vC_addr);
24558 /* widening multiply, separating lanes */
24559 assign( abEvn, MK_Iop_MullOdd16Ux8(mkexpr(vA), mkexpr(vB) ));
24560 assign( abOdd, binop(Iop_MullEven16Ux8, mkexpr(vA), mkexpr(vB)) );
24562 /* break V128 to 4xI32's, zero-extending to I64's */
24563 breakV128to4x64U( mkexpr(abEvn), &ab7, &ab5, &ab3, &ab1 );
24564 breakV128to4x64U( mkexpr(abOdd), &ab6, &ab4, &ab2, &ab0 );
24565 breakV128to4x64U( mkexpr(vC), &c3, &c2, &c1, &c0 );
24567 /* add lanes */
24568 assign( z3, binop(Iop_Add64, mkexpr(c3),
24569 binop(Iop_Add64, mkexpr(ab7), mkexpr(ab6))));
24570 assign( z2, binop(Iop_Add64, mkexpr(c2),
24571 binop(Iop_Add64, mkexpr(ab5), mkexpr(ab4))));
24572 assign( z1, binop(Iop_Add64, mkexpr(c1),
24573 binop(Iop_Add64, mkexpr(ab3), mkexpr(ab2))));
24574 assign( z0, binop(Iop_Add64, mkexpr(c0),
24575 binop(Iop_Add64, mkexpr(ab1), mkexpr(ab0))));
24577 /* saturate-narrow to 32bit, and combine to V128 */
24578 putVReg( vD_addr, mkV128from4x64U( mkexpr(z3), mkexpr(z2),
24579 mkexpr(z1), mkexpr(z0)) );
24581 break;
24583 case 0x28: { // vmsumshm (Multiply Sum Signed HW Modulo, AV p202)
24584 DIP("vmsumshm v%d,v%d,v%d,v%d\n",
24585 vD_addr, vA_addr, vB_addr, vC_addr);
24586 assign( abEvn, MK_Iop_MullOdd16Sx8( mkexpr(vA), mkexpr(vB) ));
24587 assign( abOdd, binop(Iop_MullEven16Sx8, mkexpr(vA), mkexpr(vB)) );
24588 putVReg( vD_addr,
24589 binop(Iop_Add32x4, mkexpr(vC),
24590 binop(Iop_Add32x4, mkexpr(abOdd), mkexpr(abEvn))) );
24591 break;
24593 case 0x29: { // vmsumshs (Multiply Sum Signed HW Saturate, AV p203)
24594 DIP("vmsumshs v%d,v%d,v%d,v%d\n",
24595 vD_addr, vA_addr, vB_addr, vC_addr);
24596 /* widening multiply, separating lanes */
24597 assign( abEvn, MK_Iop_MullOdd16Sx8( mkexpr(vA), mkexpr(vB) ));
24598 assign( abOdd, binop(Iop_MullEven16Sx8, mkexpr(vA), mkexpr(vB)) );
24600 /* break V128 to 4xI32's, sign-extending to I64's */
24601 breakV128to4x64S( mkexpr(abEvn), &ab7, &ab5, &ab3, &ab1 );
24602 breakV128to4x64S( mkexpr(abOdd), &ab6, &ab4, &ab2, &ab0 );
24603 breakV128to4x64S( mkexpr(vC), &c3, &c2, &c1, &c0 );
24605 /* add lanes */
24606 assign( z3, binop(Iop_Add64, mkexpr(c3),
24607 binop(Iop_Add64, mkexpr(ab7), mkexpr(ab6))));
24608 assign( z2, binop(Iop_Add64, mkexpr(c2),
24609 binop(Iop_Add64, mkexpr(ab5), mkexpr(ab4))));
24610 assign( z1, binop(Iop_Add64, mkexpr(c1),
24611 binop(Iop_Add64, mkexpr(ab3), mkexpr(ab2))));
24612 assign( z0, binop(Iop_Add64, mkexpr(c0),
24613 binop(Iop_Add64, mkexpr(ab1), mkexpr(ab0))));
24615 /* saturate-narrow to 32bit, and combine to V128 */
24616 putVReg( vD_addr, mkV128from4x64S( mkexpr(z3), mkexpr(z2),
24617 mkexpr(z1), mkexpr(z0)) );
24618 break;
24620 default:
24621 vex_printf("dis_av_multarith(ppc)(opc2)\n");
24622 return False;
24624 return True;
24628 AltiVec Polynomial Multiply-Sum Instructions
24630 static Bool dis_av_polymultarith ( UInt theInstr )
24632 /* VA-Form */
24633 UChar opc1 = ifieldOPC(theInstr);
24634 UChar vD_addr = ifieldRegDS(theInstr);
24635 UChar vA_addr = ifieldRegA(theInstr);
24636 UChar vB_addr = ifieldRegB(theInstr);
24637 UChar vC_addr = ifieldRegC(theInstr);
24638 UInt opc2 = IFIELD(theInstr, 0, 11);
24639 IRTemp vA = newTemp(Ity_V128);
24640 IRTemp vB = newTemp(Ity_V128);
24641 IRTemp vC = newTemp(Ity_V128);
24643 assign( vA, getVReg(vA_addr));
24644 assign( vB, getVReg(vB_addr));
24645 assign( vC, getVReg(vC_addr));
24647 if (opc1 != 0x4) {
24648 vex_printf("dis_av_polymultarith(ppc)(instr)\n");
24649 return False;
24652 switch (opc2) {
24653 /* Polynomial Multiply-Add */
24654 case 0x408: // vpmsumb Vector Polynomial Multiply-sum Byte
24655 DIP("vpmsumb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24656 putVReg( vD_addr, binop(Iop_PolynomialMulAdd8x16,
24657 mkexpr(vA), mkexpr(vB)) );
24658 break;
24659 case 0x448: // vpmsumd Vector Polynomial Multiply-sum Double Word
24660 DIP("vpmsumd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24661 putVReg( vD_addr, binop(Iop_PolynomialMulAdd64x2,
24662 mkexpr(vA), mkexpr(vB)) );
24663 break;
24664 case 0x488: // vpmsumw Vector Polynomial Multiply-sum Word
24665 DIP("vpmsumw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24666 putVReg( vD_addr, binop(Iop_PolynomialMulAdd32x4,
24667 mkexpr(vA), mkexpr(vB)) );
24668 break;
24669 case 0x4C8: // vpmsumh Vector Polynomial Multiply-sum Half Word
24670 DIP("vpmsumh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24671 putVReg( vD_addr, binop(Iop_PolynomialMulAdd16x8,
24672 mkexpr(vA), mkexpr(vB)) );
24673 break;
24674 default:
24675 vex_printf("dis_av_polymultarith(ppc)(opc2=0x%x)\n", opc2);
24676 return False;
24678 return True;
24682 AltiVec Shift/Rotate Instructions
24684 static Bool dis_av_shift ( UInt theInstr )
24686 /* VX-Form */
24687 UChar opc1 = ifieldOPC(theInstr);
24688 UChar vD_addr = ifieldRegDS(theInstr);
24689 UChar vA_addr = ifieldRegA(theInstr);
24690 UChar vB_addr = ifieldRegB(theInstr);
24691 UInt opc2 = IFIELD( theInstr, 0, 11 );
24693 IRTemp vA = newTemp(Ity_V128);
24694 IRTemp vB = newTemp(Ity_V128);
24695 assign( vA, getVReg(vA_addr));
24696 assign( vB, getVReg(vB_addr));
24698 if (opc1 != 0x4){
24699 vex_printf("dis_av_shift(ppc)(instr)\n");
24700 return False;
24703 switch (opc2) {
24704 /* Rotate */
24705 case 0x004: // vrlb (Rotate Left Integer B, AV p234)
24706 DIP("vrlb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24707 putVReg( vD_addr, binop(Iop_Rol8x16, mkexpr(vA), mkexpr(vB)) );
24708 break;
24710 case 0x044: // vrlh (Rotate Left Integer HW, AV p235)
24711 DIP("vrlh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24712 putVReg( vD_addr, binop(Iop_Rol16x8, mkexpr(vA), mkexpr(vB)) );
24713 break;
24715 case 0x084: // vrlw (Rotate Left Integer W, AV p236)
24716 DIP("vrlw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24717 putVReg( vD_addr, binop(Iop_Rol32x4, mkexpr(vA), mkexpr(vB)) );
24718 break;
24720 case 0x0C4: // vrld (Rotate Left Integer Double Word)
24721 DIP("vrld v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24722 putVReg( vD_addr, binop(Iop_Rol64x2, mkexpr(vA), mkexpr(vB)) );
24723 break;
24726 /* Shift Left */
24727 case 0x104: // vslb (Shift Left Integer B, AV p240)
24728 DIP("vslb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24729 putVReg( vD_addr, binop(Iop_Shl8x16, mkexpr(vA), mkexpr(vB)) );
24730 break;
24732 case 0x144: // vslh (Shift Left Integer HW, AV p242)
24733 DIP("vslh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24734 putVReg( vD_addr, binop(Iop_Shl16x8, mkexpr(vA), mkexpr(vB)) );
24735 break;
24737 case 0x184: // vslw (Shift Left Integer W, AV p244)
24738 DIP("vslw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24739 putVReg( vD_addr, binop(Iop_Shl32x4, mkexpr(vA), mkexpr(vB)) );
24740 break;
24742 case 0x5C4: // vsld (Shift Left Integer Double Word)
24743 DIP("vsld v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24744 putVReg( vD_addr, binop(Iop_Shl64x2, mkexpr(vA), mkexpr(vB)) );
24745 break;
24747 case 0x1C4: { // vsl (Shift Left, AV p239)
24748 IRTemp sh = newTemp(Ity_I8);
24749 DIP("vsl v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24750 assign( sh, binop(Iop_And8, mkU8(0x7),
24751 unop(Iop_32to8,
24752 unop(Iop_V128to32, mkexpr(vB)))) );
24753 putVReg( vD_addr,
24754 binop(Iop_ShlV128, mkexpr(vA), mkexpr(sh)) );
24755 break;
24757 case 0x40C: { // vslo (Shift Left by Octet, AV p243)
24758 IRTemp sh = newTemp(Ity_I8);
24759 DIP("vslo v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24760 assign( sh, binop(Iop_And8, mkU8(0x78),
24761 unop(Iop_32to8,
24762 unop(Iop_V128to32, mkexpr(vB)))) );
24763 putVReg( vD_addr,
24764 binop(Iop_ShlV128, mkexpr(vA), mkexpr(sh)) );
24765 break;
24769 /* Shift Right */
24770 case 0x204: // vsrb (Shift Right B, AV p256)
24771 DIP("vsrb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24772 putVReg( vD_addr, binop(Iop_Shr8x16, mkexpr(vA), mkexpr(vB)) );
24773 break;
24775 case 0x244: // vsrh (Shift Right HW, AV p257)
24776 DIP("vsrh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24777 putVReg( vD_addr, binop(Iop_Shr16x8, mkexpr(vA), mkexpr(vB)) );
24778 break;
24780 case 0x284: // vsrw (Shift Right W, AV p259)
24781 DIP("vsrw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24782 putVReg( vD_addr, binop(Iop_Shr32x4, mkexpr(vA), mkexpr(vB)) );
24783 break;
24785 case 0x2C4: { // vsr (Shift Right, AV p251)
24786 IRTemp sh = newTemp(Ity_I8);
24787 DIP("vsr v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24788 assign( sh, binop(Iop_And8, mkU8(0x7),
24789 unop(Iop_32to8,
24790 unop(Iop_V128to32, mkexpr(vB)))) );
24791 putVReg( vD_addr,
24792 binop(Iop_ShrV128, mkexpr(vA), mkexpr(sh)) );
24793 break;
24795 case 0x304: // vsrab (Shift Right Alg B, AV p253)
24796 DIP("vsrab v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24797 putVReg( vD_addr, binop(Iop_Sar8x16, mkexpr(vA), mkexpr(vB)) );
24798 break;
24800 case 0x344: // vsrah (Shift Right Alg HW, AV p254)
24801 DIP("vsrah v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24802 putVReg( vD_addr, binop(Iop_Sar16x8, mkexpr(vA), mkexpr(vB)) );
24803 break;
24805 case 0x384: // vsraw (Shift Right Alg W, AV p255)
24806 DIP("vsraw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24807 putVReg( vD_addr, binop(Iop_Sar32x4, mkexpr(vA), mkexpr(vB)) );
24808 break;
24810 case 0x3C4: // vsrad (Shift Right Alg Double Word)
24811 DIP("vsrad v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24812 putVReg( vD_addr, binop(Iop_Sar64x2, mkexpr(vA), mkexpr(vB)) );
24813 break;
24815 case 0x44C: { // vsro (Shift Right by Octet, AV p258)
24816 IRTemp sh = newTemp(Ity_I8);
24817 DIP("vsro v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24818 assign( sh, binop(Iop_And8, mkU8(0x78),
24819 unop(Iop_32to8,
24820 unop(Iop_V128to32, mkexpr(vB)))) );
24821 putVReg( vD_addr,
24822 binop(Iop_ShrV128, mkexpr(vA), mkexpr(sh)) );
24823 break;
24826 case 0x6C4: // vsrd (Shift Right Double Word)
24827 DIP("vsrd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24828 putVReg( vD_addr, binop(Iop_Shr64x2, mkexpr(vA), mkexpr(vB)) );
24829 break;
24832 default:
24833 vex_printf("dis_av_shift(ppc)(opc2)\n");
24834 return False;
24836 return True;
24840 AltiVec Permute Instructions
24842 static Bool dis_av_permute ( UInt theInstr )
24844 /* VA-Form, VX-Form */
24845 UChar opc1 = ifieldOPC(theInstr);
24846 UChar vD_addr = ifieldRegDS(theInstr);
24847 UChar vA_addr = ifieldRegA(theInstr);
24848 UChar UIMM_5 = vA_addr;
24849 UChar vB_addr = ifieldRegB(theInstr);
24850 UChar vC_addr = ifieldRegC(theInstr);
24851 UChar b10 = ifieldBIT10(theInstr);
24852 UChar SHB_uimm4 = toUChar( IFIELD( theInstr, 6, 4 ) );
24853 UInt opc2 = toUChar( IFIELD( theInstr, 0, 6 ) );
24855 UChar SIMM_8 = extend_s_5to8(UIMM_5);
24857 IRTemp vA = newTemp(Ity_V128);
24858 IRTemp vB = newTemp(Ity_V128);
24859 IRTemp vC = newTemp(Ity_V128);
24860 assign( vA, getVReg(vA_addr));
24861 assign( vB, getVReg(vB_addr));
24862 assign( vC, getVReg(vC_addr));
24864 if (opc1 != 0x4) {
24865 vex_printf("dis_av_permute(ppc)(instr)\n");
24866 return False;
24869 switch (opc2) {
24870 case 0x2A: // vsel (Conditional Select, AV p238)
24871 DIP("vsel v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
24872 /* vD = (vA & ~vC) | (vB & vC) */
24873 putVReg( vD_addr, binop(Iop_OrV128,
24874 binop(Iop_AndV128, mkexpr(vA), unop(Iop_NotV128, mkexpr(vC))),
24875 binop(Iop_AndV128, mkexpr(vB), mkexpr(vC))) );
24876 return True;
24878 case 0x2B: { // vperm (Permute, AV p218)
24879 /* limited to two args for IR, so have to play games... */
24880 IRTemp a_perm = newTemp(Ity_V128);
24881 IRTemp b_perm = newTemp(Ity_V128);
24882 IRTemp mask = newTemp(Ity_V128);
24883 IRTemp vC_andF = newTemp(Ity_V128);
24884 DIP("vperm v%d,v%d,v%d,v%d\n",
24885 vD_addr, vA_addr, vB_addr, vC_addr);
24886 /* Limit the Perm8x16 steering values to 0 .. 15 as that is what
24887 IR specifies, and also to hide irrelevant bits from
24888 memcheck */
24889 assign( vC_andF,
24890 binop(Iop_AndV128, mkexpr(vC),
24891 unop(Iop_Dup8x16, mkU8(0xF))) );
24892 assign( a_perm,
24893 binop(Iop_Perm8x16, mkexpr(vA), mkexpr(vC_andF)) );
24894 assign( b_perm,
24895 binop(Iop_Perm8x16, mkexpr(vB), mkexpr(vC_andF)) );
24896 // mask[i8] = (vC[i8]_4 == 1) ? 0xFF : 0x0
24897 assign( mask, binop(Iop_SarN8x16,
24898 binop(Iop_ShlN8x16, mkexpr(vC), mkU8(3)),
24899 mkU8(7)) );
24900 // dst = (a & ~mask) | (b & mask)
24901 putVReg( vD_addr, binop(Iop_OrV128,
24902 binop(Iop_AndV128, mkexpr(a_perm),
24903 unop(Iop_NotV128, mkexpr(mask))),
24904 binop(Iop_AndV128, mkexpr(b_perm),
24905 mkexpr(mask))) );
24906 return True;
24908 case 0x2C: // vsldoi (Shift Left Double by Octet Imm, AV p241)
24909 if (b10 != 0) {
24910 vex_printf("dis_av_permute(ppc)(vsldoi)\n");
24911 return False;
24913 DIP("vsldoi v%d,v%d,v%d,%d\n",
24914 vD_addr, vA_addr, vB_addr, SHB_uimm4);
24915 if (SHB_uimm4 == 0)
24916 putVReg( vD_addr, mkexpr(vA) );
24917 else
24918 putVReg( vD_addr,
24919 binop(Iop_OrV128,
24920 binop(Iop_ShlV128, mkexpr(vA), mkU8(SHB_uimm4*8)),
24921 binop(Iop_ShrV128, mkexpr(vB), mkU8((16-SHB_uimm4)*8))) );
24922 return True;
24923 case 0x2D: { // vpermxor (Vector Permute and Exclusive-OR)
24924 IRTemp a_perm = newTemp(Ity_V128);
24925 IRTemp b_perm = newTemp(Ity_V128);
24926 IRTemp vrc_a = newTemp(Ity_V128);
24927 IRTemp vrc_b = newTemp(Ity_V128);
24929 DIP("vpermxor v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
24931 /* IBM index is 0:7, Change index value to index 7:0 */
24932 assign( vrc_b, binop( Iop_AndV128, mkexpr( vC ),
24933 unop( Iop_Dup8x16, mkU8( 0xF ) ) ) );
24934 assign( vrc_a, binop( Iop_ShrV128,
24935 binop( Iop_AndV128, mkexpr( vC ),
24936 unop( Iop_Dup8x16, mkU8( 0xF0 ) ) ),
24937 mkU8 ( 4 ) ) );
24938 assign( a_perm, binop( Iop_Perm8x16, mkexpr( vA ), mkexpr( vrc_a ) ) );
24939 assign( b_perm, binop( Iop_Perm8x16, mkexpr( vB ), mkexpr( vrc_b ) ) );
24940 putVReg( vD_addr, binop( Iop_XorV128,
24941 mkexpr( a_perm ), mkexpr( b_perm) ) );
24942 return True;
24945 case 0x3B: { // vpermr (Vector Permute Right-indexed)
24946 /* limited to two args for IR, so have to play games... */
24947 IRTemp a_perm = newTemp( Ity_V128 );
24948 IRTemp b_perm = newTemp( Ity_V128 );
24949 IRTemp mask = newTemp( Ity_V128 );
24950 IRTemp vC_andF = newTemp( Ity_V128 );
24951 IRTemp vC_adj = newTemp( Ity_V128 );
24953 DIP( "vpermr v%d,v%d,v%d,v%d\n",
24954 vD_addr, vA_addr, vB_addr, vC_addr);
24955 /* Limit the Perm8x16 steering values to 0 .. 15 as that is what
24956 IR specifies, and also to hide irrelevant bits from
24957 memcheck.
24960 assign( vC_adj,
24961 binop( Iop_Sub16x8,
24962 unop( Iop_Dup8x16, mkU8( 0x1F ) ),
24963 mkexpr( vC ) ) );
24964 assign( vC_andF,
24965 binop( Iop_AndV128, mkexpr( vC_adj),
24966 unop( Iop_Dup8x16, mkU8( 0xF ) ) ) );
24967 assign( a_perm,
24968 binop( Iop_Perm8x16, mkexpr( vA ), mkexpr( vC_andF ) ) );
24969 assign( b_perm,
24970 binop( Iop_Perm8x16, mkexpr( vB ), mkexpr( vC_andF ) ) );
24971 // mask[i8] = (vC[i8]_4 == 1) ? 0xFF : 0x0
24972 assign( mask, binop(Iop_SarN8x16,
24973 binop( Iop_ShlN8x16, mkexpr( vC_adj ),
24974 mkU8( 3 ) ), mkU8( 7 ) ) );
24975 // dst = (a & ~mask) | (b & mask)
24976 putVReg( vD_addr, binop( Iop_OrV128,
24977 binop( Iop_AndV128, mkexpr( a_perm ),
24978 unop( Iop_NotV128, mkexpr( mask ) ) ),
24979 binop( Iop_AndV128, mkexpr( b_perm ),
24980 mkexpr( mask ) ) ) );
24981 return True;
24984 default:
24985 break; // Fall through...
24988 opc2 = IFIELD( theInstr, 0, 11 );
24989 switch (opc2) {
24991 /* Merge */
24992 case 0x00C: // vmrghb (Merge High B, AV p195)
24993 DIP("vmrghb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24994 putVReg( vD_addr,
24995 binop(Iop_InterleaveHI8x16, mkexpr(vA), mkexpr(vB)) );
24996 break;
24998 case 0x04C: // vmrghh (Merge High HW, AV p196)
24999 DIP("vmrghh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25000 putVReg( vD_addr,
25001 binop(Iop_InterleaveHI16x8, mkexpr(vA), mkexpr(vB)) );
25002 break;
25004 case 0x08C: // vmrghw (Merge High W, AV p197)
25005 DIP("vmrghw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25006 putVReg( vD_addr,
25007 binop(Iop_InterleaveHI32x4, mkexpr(vA), mkexpr(vB)) );
25008 break;
25010 case 0x10C: // vmrglb (Merge Low B, AV p198)
25011 DIP("vmrglb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25012 putVReg( vD_addr,
25013 binop(Iop_InterleaveLO8x16, mkexpr(vA), mkexpr(vB)) );
25014 break;
25016 case 0x14C: // vmrglh (Merge Low HW, AV p199)
25017 DIP("vmrglh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25018 putVReg( vD_addr,
25019 binop(Iop_InterleaveLO16x8, mkexpr(vA), mkexpr(vB)) );
25020 break;
25022 case 0x18C: // vmrglw (Merge Low W, AV p200)
25023 DIP("vmrglw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25024 putVReg( vD_addr,
25025 binop(Iop_InterleaveLO32x4, mkexpr(vA), mkexpr(vB)) );
25026 break;
25028 /* Extract instructions */
25029 case 0x20D: // vextractub (Vector Extract Unsigned Byte)
25031 UChar uim = IFIELD( theInstr, 16, 4 );
25033 DIP("vextractub v%d,v%d,%d\n", vD_addr, vB_addr, uim);
25035 putVReg( vD_addr, binop( Iop_ShlV128,
25036 binop( Iop_AndV128,
25037 binop( Iop_ShrV128,
25038 mkexpr( vB ),
25039 unop( Iop_32to8,
25040 binop( Iop_Mul32,
25041 mkU32( 8 ),
25042 mkU32( 31 - uim ) ) ) ),
25043 binop( Iop_64HLtoV128,
25044 mkU64( 0x0ULL ),
25045 mkU64( 0xFFULL ) ) ),
25046 mkU8( 64 ) ) );
25048 break;
25050 case 0x24D: // vextractuh (Vector Extract Unsigned Halfword)
25052 UChar uim = IFIELD( theInstr, 16, 4 );
25054 DIP("vextractuh v%d,v%d,%d\n", vD_addr, vB_addr, uim);
25056 putVReg( vD_addr, binop( Iop_ShlV128,
25057 binop( Iop_AndV128,
25058 binop( Iop_ShrV128,
25059 mkexpr( vB ),
25060 unop( Iop_32to8,
25061 binop( Iop_Mul32,
25062 mkU32( 8 ),
25063 mkU32( 30 - uim ) ) ) ),
25064 binop( Iop_64HLtoV128,
25065 mkU64( 0x0ULL ),
25066 mkU64( 0xFFFFULL ) ) ),
25067 mkU8( 64 ) ) );
25069 break;
25071 case 0x28D: // vextractuw (Vector Extract Unsigned Word)
25073 UChar uim = IFIELD( theInstr, 16, 4 );
25075 DIP("vextractuw v%d,v%d,%d\n", vD_addr, vB_addr, uim);
25077 putVReg( vD_addr,
25078 binop( Iop_ShlV128,
25079 binop( Iop_AndV128,
25080 binop( Iop_ShrV128,
25081 mkexpr( vB ),
25082 unop( Iop_32to8,
25083 binop( Iop_Mul32,
25084 mkU32( 8 ),
25085 mkU32( 28 - uim ) ) ) ),
25086 binop( Iop_64HLtoV128,
25087 mkU64( 0x0ULL ),
25088 mkU64( 0xFFFFFFFFULL ) ) ),
25089 mkU8( 64 ) ) );
25091 break;
25093 case 0x2CD: // vextractd (Vector Extract Double Word)
25095 UChar uim = IFIELD( theInstr, 16, 4 );
25097 DIP("vextractd v%d,v%d,%d\n", vD_addr, vB_addr, uim);
25099 putVReg( vD_addr,
25100 binop( Iop_ShlV128,
25101 binop( Iop_AndV128,
25102 binop( Iop_ShrV128,
25103 mkexpr( vB ),
25104 unop( Iop_32to8,
25105 binop( Iop_Mul32,
25106 mkU32( 8 ),
25107 mkU32( 24 - uim ) ) ) ),
25108 binop( Iop_64HLtoV128,
25109 mkU64( 0x0ULL ),
25110 mkU64( 0xFFFFFFFFFFFFFFFFULL ) ) ),
25111 mkU8( 64 ) ) );
25113 break;
25115 /* Insert instructions */
25116 case 0x30D: // vinsertb (Vector insert Unsigned Byte)
25118 UChar uim = IFIELD( theInstr, 16, 4 );
25119 IRTemp shift = newTemp( Ity_I8 );
25120 IRTemp vD = newTemp( Ity_V128 );
25122 DIP("vinsertb v%d,v%d,%d\n", vD_addr, vB_addr, uim);
25124 assign( vD, getVReg( vD_addr ) );
25126 assign( shift, unop( Iop_32to8,
25127 binop( Iop_Mul32,
25128 mkU32( 8 ),
25129 mkU32( 15 - ( uim + 0 ) ) ) ) );
25131 putVReg( vD_addr,
25132 binop( Iop_OrV128,
25133 binop( Iop_ShlV128,
25134 binop( Iop_AndV128,
25135 binop( Iop_ShrV128,
25136 mkexpr( vB ),
25137 mkU8( ( 15 - 7 )*8 ) ),
25138 binop( Iop_64HLtoV128,
25139 mkU64( 0x0ULL ),
25140 mkU64( 0xFFULL ) ) ),
25141 mkexpr( shift ) ),
25142 binop( Iop_AndV128,
25143 unop( Iop_NotV128,
25144 binop( Iop_ShlV128,
25145 binop( Iop_64HLtoV128,
25146 mkU64( 0x0ULL ),
25147 mkU64( 0xFFULL ) ),
25148 mkexpr( shift ) ) ),
25149 mkexpr( vD ) ) ) );
25151 break;
25153 case 0x34D: // vinserth (Vector insert Halfword)
25155 UChar uim = IFIELD( theInstr, 16, 4 );
25156 IRTemp shift = newTemp( Ity_I8 );
25157 IRTemp vD = newTemp( Ity_V128 );
25159 DIP("vinserth v%d,v%d,%d\n", vD_addr, vB_addr, uim);
25161 assign( vD, getVReg( vD_addr ) );
25163 assign( shift, unop( Iop_32to8,
25164 binop( Iop_Mul32,
25165 mkU32( 8 ),
25166 mkU32( 15 - ( uim + 1 ) ) ) ) );
25168 putVReg( vD_addr,
25169 binop( Iop_OrV128,
25170 binop( Iop_ShlV128,
25171 binop( Iop_AndV128,
25172 binop( Iop_ShrV128,
25173 mkexpr( vB ),
25174 mkU8( (7 - 3)*16 ) ),
25175 binop( Iop_64HLtoV128,
25176 mkU64( 0x0ULL ),
25177 mkU64( 0xFFFFULL ) ) ),
25178 mkexpr( shift ) ),
25179 binop( Iop_AndV128,
25180 unop( Iop_NotV128,
25181 binop( Iop_ShlV128,
25182 binop( Iop_64HLtoV128,
25183 mkU64( 0x0ULL ),
25184 mkU64( 0xFFFFULL ) ),
25185 mkexpr( shift ) ) ),
25186 mkexpr( vD ) ) ) );
25188 break;
25190 case 0x38D: // vinsertw (Vector insert Word)
25192 UChar uim = IFIELD( theInstr, 16, 4 );
25193 IRTemp shift = newTemp( Ity_I8 );
25194 IRTemp vD = newTemp( Ity_V128 );
25196 DIP("vinsertw v%d,v%d,%d\n", vD_addr, vB_addr, uim);
25198 assign( vD, getVReg( vD_addr ) );
25200 assign( shift, unop( Iop_32to8,
25201 binop( Iop_Mul32,
25202 mkU32( 8 ),
25203 mkU32( 15 - ( uim + 3 ) ) ) ) );
25205 putVReg( vD_addr,
25206 binop( Iop_OrV128,
25207 binop( Iop_ShlV128,
25208 binop( Iop_AndV128,
25209 binop( Iop_ShrV128,
25210 mkexpr( vB ),
25211 mkU8( (3 - 1) * 32 ) ),
25212 binop( Iop_64HLtoV128,
25213 mkU64( 0x0ULL ),
25214 mkU64( 0xFFFFFFFFULL ) ) ),
25215 mkexpr( shift ) ),
25216 binop( Iop_AndV128,
25217 unop( Iop_NotV128,
25218 binop( Iop_ShlV128,
25219 binop( Iop_64HLtoV128,
25220 mkU64( 0x0ULL ),
25221 mkU64( 0xFFFFFFFFULL ) ),
25222 mkexpr( shift ) ) ),
25223 mkexpr( vD ) ) ) );
25225 break;
25227 case 0x3CD: // vinsertd (Vector insert Doubleword)
25229 UChar uim = IFIELD( theInstr, 16, 4 );
25230 IRTemp shift = newTemp( Ity_I8 );
25231 IRTemp vD = newTemp( Ity_V128 );
25233 DIP("vinsertd v%d,v%d,%d\n", vD_addr, vB_addr, uim);
25235 assign( vD, getVReg( vD_addr ) );
25237 assign( shift, unop( Iop_32to8,
25238 binop( Iop_Mul32,
25239 mkU32( 8 ),
25240 mkU32( 15 - ( uim + 7 ) ) ) ) );
25242 putVReg( vD_addr,
25243 binop( Iop_OrV128,
25244 binop( Iop_ShlV128,
25245 binop( Iop_AndV128,
25246 binop( Iop_ShrV128,
25247 mkexpr( vB ),
25248 mkU8( ( 1 - 0 ) * 64 ) ),
25249 binop( Iop_64HLtoV128,
25250 mkU64( 0x0ULL ),
25251 mkU64( 0xFFFFFFFFFFFFFFFFULL ) ) ),
25252 mkexpr( shift ) ),
25253 binop( Iop_AndV128,
25254 unop( Iop_NotV128,
25255 binop( Iop_ShlV128,
25256 binop( Iop_64HLtoV128,
25257 mkU64( 0x0ULL ),
25258 mkU64( 0xFFFFFFFFFFFFFFFFULL ) ),
25259 mkexpr( shift ) ) ),
25260 mkexpr( vD ) ) ) );
25262 break;
25264 /* Splat */
25265 case 0x20C: { // vspltb (Splat Byte, AV p245)
25266 /* vD = Dup8x16( vB[UIMM_5] ) */
25267 UChar sh_uimm = (15 - (UIMM_5 & 15)) * 8;
25268 DIP("vspltb v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
25269 putVReg( vD_addr, unop(Iop_Dup8x16,
25270 unop(Iop_32to8, unop(Iop_V128to32,
25271 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm))))) );
25272 break;
25274 case 0x24C: { // vsplth (Splat Half Word, AV p246)
25275 UChar sh_uimm = (7 - (UIMM_5 & 7)) * 16;
25276 DIP("vsplth v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
25277 putVReg( vD_addr, unop(Iop_Dup16x8,
25278 unop(Iop_32to16, unop(Iop_V128to32,
25279 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm))))) );
25280 break;
25282 case 0x28C: { // vspltw (Splat Word, AV p250)
25283 /* vD = Dup32x4( vB[UIMM_5] ) */
25284 UChar sh_uimm = (3 - (UIMM_5 & 3)) * 32;
25285 DIP("vspltw v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
25286 putVReg( vD_addr, unop(Iop_Dup32x4,
25287 unop(Iop_V128to32,
25288 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm)))) );
25289 break;
25291 case 0x30C: // vspltisb (Splat Immediate Signed B, AV p247)
25292 DIP("vspltisb v%d,%d\n", vD_addr, (Char)SIMM_8);
25293 putVReg( vD_addr, unop(Iop_Dup8x16, mkU8(SIMM_8)) );
25294 break;
25296 case 0x34C: // vspltish (Splat Immediate Signed HW, AV p248)
25297 DIP("vspltish v%d,%d\n", vD_addr, (Char)SIMM_8);
25298 putVReg( vD_addr,
25299 unop(Iop_Dup16x8, mkU16(extend_s_8to32(SIMM_8))) );
25300 break;
25302 case 0x38C: // vspltisw (Splat Immediate Signed W, AV p249)
25303 DIP("vspltisw v%d,%d\n", vD_addr, (Char)SIMM_8);
25304 putVReg( vD_addr,
25305 unop(Iop_Dup32x4, mkU32(extend_s_8to32(SIMM_8))) );
25306 break;
25308 case 0x68C: // vmrgow (Merge Odd Word)
25309 DIP("vmrgow v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25310 /* VD[0] <- VA[1]
25311 VD[1] <- VB[1]
25312 VD[2] <- VA[3]
25313 VD[3] <- VB[3]
25315 putVReg( vD_addr,
25316 binop(Iop_CatOddLanes32x4, mkexpr(vA), mkexpr(vB) ) );
25317 break;
25319 case 0x78C: // vmrgew (Merge Even Word)
25320 DIP("vmrgew v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25321 /* VD[0] <- VA[0]
25322 VD[1] <- VB[0]
25323 VD[2] <- VA[2]
25324 VD[3] <- VB[2]
25326 putVReg( vD_addr,
25327 binop(Iop_CatEvenLanes32x4, mkexpr(vA), mkexpr(vB) ) );
25328 break;
25330 default:
25331 vex_printf("dis_av_permute(ppc)(opc2)\n");
25332 return False;
25334 return True;
25338 Vector Integer Absolute Difference
25340 static Bool dis_abs_diff ( UInt theInstr )
25342 /* VX-Form */
25343 UChar opc1 = ifieldOPC( theInstr );
25344 UChar vT_addr = ifieldRegDS( theInstr );
25345 UChar vA_addr = ifieldRegA( theInstr );
25346 UChar vB_addr = ifieldRegB( theInstr );
25347 UInt opc2 = IFIELD( theInstr, 0, 11 );
25349 IRTemp vA = newTemp( Ity_V128 );
25350 IRTemp vB = newTemp( Ity_V128 );
25351 IRTemp vT = newTemp( Ity_V128 );
25353 IRTemp vAminusB = newTemp( Ity_V128 );
25354 IRTemp vBminusA = newTemp( Ity_V128 );
25355 IRTemp vMask = newTemp( Ity_V128 );
25357 assign( vA, getVReg( vA_addr ) );
25358 assign( vB, getVReg( vB_addr ) );
25360 if ( opc1 != 0x4 ) {
25361 vex_printf("dis_abs_diff(ppc)(instr)\n");
25362 return False;
25365 switch ( opc2 ) {
25366 case 0x403: // vabsdub Vector absolute difference Unsigned Byte
25368 DIP("vabsdub v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
25370 /* Determine which of the corresponding bytes is larger,
25371 * create mask with 1's in byte positions where vA[i] > vB[i]
25373 assign( vMask, binop( Iop_CmpGT8Ux16, mkexpr( vA ), mkexpr( vB ) ) );
25375 assign( vAminusB,
25376 binop( Iop_AndV128,
25377 binop( Iop_Sub8x16, mkexpr( vA ), mkexpr( vB ) ),
25378 mkexpr( vMask ) ) );
25380 assign( vBminusA,
25381 binop( Iop_AndV128,
25382 binop( Iop_Sub8x16, mkexpr( vB ), mkexpr( vA ) ),
25383 unop ( Iop_NotV128, mkexpr( vMask ) ) ) );
25385 assign( vT, binop( Iop_OrV128,
25386 mkexpr( vAminusB ),
25387 mkexpr( vBminusA ) ) );
25389 break;
25391 case 0x443: // vabsduh Vector absolute difference Unsigned Halfword
25393 DIP("vabsduh v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
25395 /* Determine which of the corresponding halfwords is larger,
25396 * create mask with 1's in halfword positions where vA[i] > vB[i]
25398 assign( vMask, binop( Iop_CmpGT16Ux8, mkexpr( vA ), mkexpr( vB ) ) );
25400 assign( vAminusB,
25401 binop( Iop_AndV128,
25402 binop( Iop_Sub16x8, mkexpr( vA ), mkexpr( vB ) ),
25403 mkexpr( vMask ) ) );
25405 assign( vBminusA,
25406 binop( Iop_AndV128,
25407 binop( Iop_Sub16x8, mkexpr( vB ), mkexpr( vA ) ),
25408 unop ( Iop_NotV128, mkexpr( vMask ) ) ) );
25410 assign( vT, binop( Iop_OrV128,
25411 mkexpr( vAminusB ),
25412 mkexpr( vBminusA ) ) );
25414 break;
25416 case 0x483: // vabsduw Vector absolute difference Unsigned Word
25418 DIP("vabsduw v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
25420 /* Determine which of the corresponding words is larger,
25421 * create mask with 1's in word positions where vA[i] > vB[i]
25423 assign( vMask, binop( Iop_CmpGT32Ux4, mkexpr( vA ), mkexpr( vB ) ) );
25425 assign( vAminusB,
25426 binop( Iop_AndV128,
25427 binop( Iop_Sub32x4, mkexpr( vA ), mkexpr( vB ) ),
25428 mkexpr( vMask ) ) );
25430 assign( vBminusA,
25431 binop( Iop_AndV128,
25432 binop( Iop_Sub32x4, mkexpr( vB ), mkexpr( vA ) ),
25433 unop ( Iop_NotV128, mkexpr( vMask ) ) ) );
25435 assign( vT, binop( Iop_OrV128,
25436 mkexpr( vAminusB ),
25437 mkexpr( vBminusA ) ) );
25439 break;
25441 default:
25442 return False;
25445 putVReg( vT_addr, mkexpr( vT ) );
25447 return True;
25451 AltiVec 128 bit integer multiply by 10 Instructions
25453 static Bool dis_av_mult10 ( UInt theInstr )
25455 /* VX-Form */
25456 UChar opc1 = ifieldOPC(theInstr);
25457 UChar vT_addr = ifieldRegDS(theInstr);
25458 UChar vA_addr = ifieldRegA(theInstr);
25459 UChar vB_addr = ifieldRegB(theInstr);
25460 UInt opc2 = IFIELD( theInstr, 0, 11 );
25462 IRTemp vA = newTemp(Ity_V128);
25463 assign( vA, getVReg(vA_addr));
25465 if (opc1 != 0x4) {
25466 vex_printf("dis_av_mult10(ppc)(instr)\n");
25467 return False;
25469 switch (opc2) {
25470 case 0x001: { // vmul10cuq (Vector Multiply-by-10 and write carry
25471 DIP("vmul10cuq v%d,v%d\n", vT_addr, vA_addr);
25472 putVReg( vT_addr,
25473 unop( Iop_MulI128by10Carry, mkexpr( vA ) ) );
25474 break;
25476 case 0x041: { // vmul10uq (Vector Multiply-by-10 Extended and write carry
25477 // Unsigned Quadword VX form)
25478 IRTemp vB = newTemp(Ity_V128);
25479 assign( vB, getVReg(vB_addr));
25480 DIP("vmul10ecuq v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
25481 putVReg( vT_addr,
25482 binop( Iop_MulI128by10ECarry, mkexpr( vA ), mkexpr( vB ) ) );
25483 break;
25485 case 0x201: { // vmul10uq (Vector Multiply-by-10 Unsigned Quadword VX form)
25486 DIP("vmul10uq v%d,v%d\n", vT_addr, vA_addr);
25487 putVReg( vT_addr,
25488 unop( Iop_MulI128by10, mkexpr( vA ) ) );
25489 break;
25491 case 0x241: { // vmul10uq (Vector Multiply-by-10 Extended
25492 // Unsigned Quadword VX form)
25493 IRTemp vB = newTemp(Ity_V128);
25494 assign( vB, getVReg(vB_addr));
25495 DIP("vmul10euq v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
25496 putVReg( vT_addr,
25497 binop( Iop_MulI128by10E, mkexpr( vA ), mkexpr( vB ) ) );
25498 break;
25500 default:
25501 vex_printf("dis_av_mult10(ppc)(opc2)\n");
25502 return False;
25504 return True;
25508 AltiVec Pack/Unpack Instructions
25510 static Bool dis_av_pack ( UInt theInstr )
25512 /* VX-Form */
25513 UChar opc1 = ifieldOPC(theInstr);
25514 UChar vD_addr = ifieldRegDS(theInstr);
25515 UChar vA_addr = ifieldRegA(theInstr);
25516 UChar vB_addr = ifieldRegB(theInstr);
25517 UInt opc2 = IFIELD( theInstr, 0, 11 );
25519 IRTemp signs = IRTemp_INVALID;
25520 IRTemp zeros = IRTemp_INVALID;
25521 IRTemp vA = newTemp(Ity_V128);
25522 IRTemp vB = newTemp(Ity_V128);
25523 assign( vA, getVReg(vA_addr));
25524 assign( vB, getVReg(vB_addr));
25526 if (opc1 != 0x4) {
25527 vex_printf("dis_av_pack(ppc)(instr)\n");
25528 return False;
25530 switch (opc2) {
25531 /* Packing */
25532 case 0x00E: // vpkuhum (Pack Unsigned HW Unsigned Modulo, AV p224)
25533 DIP("vpkuhum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25534 putVReg( vD_addr,
25535 binop(Iop_NarrowBin16to8x16, mkexpr(vA), mkexpr(vB)) );
25536 return True;
25538 case 0x04E: // vpkuwum (Pack Unsigned W Unsigned Modulo, AV p226)
25539 DIP("vpkuwum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25540 putVReg( vD_addr,
25541 binop(Iop_NarrowBin32to16x8, mkexpr(vA), mkexpr(vB)) );
25542 return True;
25544 case 0x08E: // vpkuhus (Pack Unsigned HW Unsigned Saturate, AV p225)
25545 DIP("vpkuhus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25546 putVReg( vD_addr,
25547 binop(Iop_QNarrowBin16Uto8Ux16, mkexpr(vA), mkexpr(vB)) );
25548 // TODO: set VSCR[SAT]
25549 return True;
25551 case 0x0CE: // vpkuwus (Pack Unsigned W Unsigned Saturate, AV p227)
25552 DIP("vpkuwus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25553 putVReg( vD_addr,
25554 binop(Iop_QNarrowBin32Uto16Ux8, mkexpr(vA), mkexpr(vB)) );
25555 // TODO: set VSCR[SAT]
25556 return True;
25558 case 0x10E: { // vpkshus (Pack Signed HW Unsigned Saturate, AV p221)
25559 // This insn does a signed->unsigned saturating conversion.
25560 // Conversion done here, then uses unsigned->unsigned vpk insn:
25561 // => UnsignedSaturatingNarrow( x & ~ (x >>s 15) )
25562 IRTemp vA_tmp = newTemp(Ity_V128);
25563 IRTemp vB_tmp = newTemp(Ity_V128);
25564 DIP("vpkshus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25565 assign( vA_tmp, binop(Iop_AndV128, mkexpr(vA),
25566 unop(Iop_NotV128,
25567 binop(Iop_SarN16x8,
25568 mkexpr(vA), mkU8(15)))) );
25569 assign( vB_tmp, binop(Iop_AndV128, mkexpr(vB),
25570 unop(Iop_NotV128,
25571 binop(Iop_SarN16x8,
25572 mkexpr(vB), mkU8(15)))) );
25573 putVReg( vD_addr, binop(Iop_QNarrowBin16Uto8Ux16,
25574 mkexpr(vA_tmp), mkexpr(vB_tmp)) );
25575 // TODO: set VSCR[SAT]
25576 return True;
25578 case 0x14E: { // vpkswus (Pack Signed W Unsigned Saturate, AV p223)
25579 // This insn does a signed->unsigned saturating conversion.
25580 // Conversion done here, then uses unsigned->unsigned vpk insn:
25581 // => UnsignedSaturatingNarrow( x & ~ (x >>s 31) )
25582 IRTemp vA_tmp = newTemp(Ity_V128);
25583 IRTemp vB_tmp = newTemp(Ity_V128);
25584 DIP("vpkswus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25585 assign( vA_tmp, binop(Iop_AndV128, mkexpr(vA),
25586 unop(Iop_NotV128,
25587 binop(Iop_SarN32x4,
25588 mkexpr(vA), mkU8(31)))) );
25589 assign( vB_tmp, binop(Iop_AndV128, mkexpr(vB),
25590 unop(Iop_NotV128,
25591 binop(Iop_SarN32x4,
25592 mkexpr(vB), mkU8(31)))) );
25593 putVReg( vD_addr, binop(Iop_QNarrowBin32Uto16Ux8,
25594 mkexpr(vA_tmp), mkexpr(vB_tmp)) );
25595 // TODO: set VSCR[SAT]
25596 return True;
25598 case 0x18E: // vpkshss (Pack Signed HW Signed Saturate, AV p220)
25599 DIP("vpkshss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25600 putVReg( vD_addr,
25601 binop(Iop_QNarrowBin16Sto8Sx16, mkexpr(vA), mkexpr(vB)) );
25602 // TODO: set VSCR[SAT]
25603 return True;
25605 case 0x1CE: // vpkswss (Pack Signed W Signed Saturate, AV p222)
25606 DIP("vpkswss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25607 putVReg( vD_addr,
25608 binop(Iop_QNarrowBin32Sto16Sx8, mkexpr(vA), mkexpr(vB)) );
25609 // TODO: set VSCR[SAT]
25610 return True;
25612 case 0x30E: { // vpkpx (Pack Pixel, AV p219)
25613 /* CAB: Worth a new primop? */
25614 /* Using shifts to compact pixel elements, then packing them */
25615 IRTemp a1 = newTemp(Ity_V128);
25616 IRTemp a2 = newTemp(Ity_V128);
25617 IRTemp a3 = newTemp(Ity_V128);
25618 IRTemp a_tmp = newTemp(Ity_V128);
25619 IRTemp b1 = newTemp(Ity_V128);
25620 IRTemp b2 = newTemp(Ity_V128);
25621 IRTemp b3 = newTemp(Ity_V128);
25622 IRTemp b_tmp = newTemp(Ity_V128);
25623 DIP("vpkpx v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25624 assign( a1, binop(Iop_ShlN16x8,
25625 binop(Iop_ShrN32x4, mkexpr(vA), mkU8(19)),
25626 mkU8(10)) );
25627 assign( a2, binop(Iop_ShlN16x8,
25628 binop(Iop_ShrN16x8, mkexpr(vA), mkU8(11)),
25629 mkU8(5)) );
25630 assign( a3, binop(Iop_ShrN16x8,
25631 binop(Iop_ShlN16x8, mkexpr(vA), mkU8(8)),
25632 mkU8(11)) );
25633 assign( a_tmp, binop(Iop_OrV128, mkexpr(a1),
25634 binop(Iop_OrV128, mkexpr(a2), mkexpr(a3))) );
25636 assign( b1, binop(Iop_ShlN16x8,
25637 binop(Iop_ShrN32x4, mkexpr(vB), mkU8(19)),
25638 mkU8(10)) );
25639 assign( b2, binop(Iop_ShlN16x8,
25640 binop(Iop_ShrN16x8, mkexpr(vB), mkU8(11)),
25641 mkU8(5)) );
25642 assign( b3, binop(Iop_ShrN16x8,
25643 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(8)),
25644 mkU8(11)) );
25645 assign( b_tmp, binop(Iop_OrV128, mkexpr(b1),
25646 binop(Iop_OrV128, mkexpr(b2), mkexpr(b3))) );
25648 putVReg( vD_addr, binop(Iop_NarrowBin32to16x8,
25649 mkexpr(a_tmp), mkexpr(b_tmp)) );
25650 return True;
25653 case 0x44E: // vpkudum (Pack Unsigned Double Word Unsigned Modulo)
25654 DIP("vpkudum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25655 putVReg( vD_addr,
25656 binop(Iop_NarrowBin64to32x4, mkexpr(vA), mkexpr(vB)) );
25657 return True;
25659 case 0x4CE: // vpkudus (Pack Unsigned Double Word Unsigned Saturate)
25660 DIP("vpkudus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25661 putVReg( vD_addr,
25662 binop(Iop_QNarrowBin64Uto32Ux4, mkexpr(vA), mkexpr(vB)) );
25663 // TODO: set VSCR[SAT]
25664 return True;
25666 case 0x54E: { // vpksdus (Pack Signed Double Word Unsigned Saturate)
25667 // This insn does a doubled signed->double unsigned saturating conversion
25668 // Conversion done here, then uses unsigned->unsigned vpk insn:
25669 // => UnsignedSaturatingNarrow( x & ~ (x >>s 31) )
25670 // This is similar to the technique used for vpkswus, except done
25671 // with double word integers versus word integers.
25672 IRTemp vA_tmp = newTemp(Ity_V128);
25673 IRTemp vB_tmp = newTemp(Ity_V128);
25674 DIP("vpksdus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25675 assign( vA_tmp, binop(Iop_AndV128, mkexpr(vA),
25676 unop(Iop_NotV128,
25677 binop(Iop_SarN64x2,
25678 mkexpr(vA), mkU8(63)))) );
25679 assign( vB_tmp, binop(Iop_AndV128, mkexpr(vB),
25680 unop(Iop_NotV128,
25681 binop(Iop_SarN64x2,
25682 mkexpr(vB), mkU8(63)))) );
25683 putVReg( vD_addr, binop(Iop_QNarrowBin64Uto32Ux4,
25684 mkexpr(vA_tmp), mkexpr(vB_tmp)) );
25685 // TODO: set VSCR[SAT]
25686 return True;
25689 case 0x5CE: // vpksdss (Pack Signed double word Signed Saturate)
25690 DIP("vpksdss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25691 putVReg( vD_addr,
25692 binop(Iop_QNarrowBin64Sto32Sx4, mkexpr(vA), mkexpr(vB)) );
25693 // TODO: set VSCR[SAT]
25694 return True;
25695 default:
25696 break; // Fall through...
25700 if (vA_addr != 0) {
25701 vex_printf("dis_av_pack(ppc)(vA_addr)\n");
25702 return False;
25705 signs = newTemp(Ity_V128);
25706 zeros = newTemp(Ity_V128);
25707 assign( zeros, unop(Iop_Dup32x4, mkU32(0)) );
25709 switch (opc2) {
25710 /* Unpacking */
25711 case 0x20E: { // vupkhsb (Unpack High Signed B, AV p277)
25712 DIP("vupkhsb v%d,v%d\n", vD_addr, vB_addr);
25713 assign( signs, binop(Iop_CmpGT8Sx16, mkexpr(zeros), mkexpr(vB)) );
25714 putVReg( vD_addr,
25715 binop(Iop_InterleaveHI8x16, mkexpr(signs), mkexpr(vB)) );
25716 break;
25718 case 0x24E: { // vupkhsh (Unpack High Signed HW, AV p278)
25719 DIP("vupkhsh v%d,v%d\n", vD_addr, vB_addr);
25720 assign( signs, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vB)) );
25721 putVReg( vD_addr,
25722 binop(Iop_InterleaveHI16x8, mkexpr(signs), mkexpr(vB)) );
25723 break;
25725 case 0x28E: { // vupklsb (Unpack Low Signed B, AV p280)
25726 DIP("vupklsb v%d,v%d\n", vD_addr, vB_addr);
25727 assign( signs, binop(Iop_CmpGT8Sx16, mkexpr(zeros), mkexpr(vB)) );
25728 putVReg( vD_addr,
25729 binop(Iop_InterleaveLO8x16, mkexpr(signs), mkexpr(vB)) );
25730 break;
25732 case 0x2CE: { // vupklsh (Unpack Low Signed HW, AV p281)
25733 DIP("vupklsh v%d,v%d\n", vD_addr, vB_addr);
25734 assign( signs, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vB)) );
25735 putVReg( vD_addr,
25736 binop(Iop_InterleaveLO16x8, mkexpr(signs), mkexpr(vB)) );
25737 break;
25739 case 0x34E: { // vupkhpx (Unpack High Pixel16, AV p276)
25740 /* CAB: Worth a new primop? */
25741 /* Using shifts to isolate pixel elements, then expanding them */
25742 IRTemp z0 = newTemp(Ity_V128);
25743 IRTemp z1 = newTemp(Ity_V128);
25744 IRTemp z01 = newTemp(Ity_V128);
25745 IRTemp z2 = newTemp(Ity_V128);
25746 IRTemp z3 = newTemp(Ity_V128);
25747 IRTemp z23 = newTemp(Ity_V128);
25748 DIP("vupkhpx v%d,v%d\n", vD_addr, vB_addr);
25749 assign( z0, binop(Iop_ShlN16x8,
25750 binop(Iop_SarN16x8, mkexpr(vB), mkU8(15)),
25751 mkU8(8)) );
25752 assign( z1, binop(Iop_ShrN16x8,
25753 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(1)),
25754 mkU8(11)) );
25755 assign( z01, binop(Iop_InterleaveHI16x8, mkexpr(zeros),
25756 binop(Iop_OrV128, mkexpr(z0), mkexpr(z1))) );
25757 assign( z2, binop(Iop_ShrN16x8,
25758 binop(Iop_ShlN16x8,
25759 binop(Iop_ShrN16x8, mkexpr(vB), mkU8(5)),
25760 mkU8(11)),
25761 mkU8(3)) );
25762 assign( z3, binop(Iop_ShrN16x8,
25763 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(11)),
25764 mkU8(11)) );
25765 assign( z23, binop(Iop_InterleaveHI16x8, mkexpr(zeros),
25766 binop(Iop_OrV128, mkexpr(z2), mkexpr(z3))) );
25767 putVReg( vD_addr,
25768 binop(Iop_OrV128,
25769 binop(Iop_ShlN32x4, mkexpr(z01), mkU8(16)),
25770 mkexpr(z23)) );
25771 break;
25773 case 0x3CE: { // vupklpx (Unpack Low Pixel16, AV p279)
25774 /* identical to vupkhpx, except interleaving LO */
25775 IRTemp z0 = newTemp(Ity_V128);
25776 IRTemp z1 = newTemp(Ity_V128);
25777 IRTemp z01 = newTemp(Ity_V128);
25778 IRTemp z2 = newTemp(Ity_V128);
25779 IRTemp z3 = newTemp(Ity_V128);
25780 IRTemp z23 = newTemp(Ity_V128);
25781 DIP("vupklpx v%d,v%d\n", vD_addr, vB_addr);
25782 assign( z0, binop(Iop_ShlN16x8,
25783 binop(Iop_SarN16x8, mkexpr(vB), mkU8(15)),
25784 mkU8(8)) );
25785 assign( z1, binop(Iop_ShrN16x8,
25786 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(1)),
25787 mkU8(11)) );
25788 assign( z01, binop(Iop_InterleaveLO16x8, mkexpr(zeros),
25789 binop(Iop_OrV128, mkexpr(z0), mkexpr(z1))) );
25790 assign( z2, binop(Iop_ShrN16x8,
25791 binop(Iop_ShlN16x8,
25792 binop(Iop_ShrN16x8, mkexpr(vB), mkU8(5)),
25793 mkU8(11)),
25794 mkU8(3)) );
25795 assign( z3, binop(Iop_ShrN16x8,
25796 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(11)),
25797 mkU8(11)) );
25798 assign( z23, binop(Iop_InterleaveLO16x8, mkexpr(zeros),
25799 binop(Iop_OrV128, mkexpr(z2), mkexpr(z3))) );
25800 putVReg( vD_addr,
25801 binop(Iop_OrV128,
25802 binop(Iop_ShlN32x4, mkexpr(z01), mkU8(16)),
25803 mkexpr(z23)) );
25804 break;
25806 case 0x64E: { // vupkhsw (Unpack High Signed Word)
25807 DIP("vupkhsw v%d,v%d\n", vD_addr, vB_addr);
25808 assign( signs, binop(Iop_CmpGT32Sx4, mkexpr(zeros), mkexpr(vB)) );
25809 putVReg( vD_addr,
25810 binop(Iop_InterleaveHI32x4, mkexpr(signs), mkexpr(vB)) );
25811 break;
25813 case 0x6CE: { // vupklsw (Unpack Low Signed Word)
25814 DIP("vupklsw v%d,v%d\n", vD_addr, vB_addr);
25815 assign( signs, binop(Iop_CmpGT32Sx4, mkexpr(zeros), mkexpr(vB)) );
25816 putVReg( vD_addr,
25817 binop(Iop_InterleaveLO32x4, mkexpr(signs), mkexpr(vB)) );
25818 break;
25820 default:
25821 vex_printf("dis_av_pack(ppc)(opc2)\n");
25822 return False;
25824 return True;
25828 AltiVec Cipher Instructions
25830 static Bool dis_av_cipher ( UInt theInstr )
25832 /* VX-Form */
25833 UChar opc1 = ifieldOPC(theInstr);
25834 UChar vD_addr = ifieldRegDS(theInstr);
25835 UChar vA_addr = ifieldRegA(theInstr);
25836 UChar vB_addr = ifieldRegB(theInstr);
25837 UInt opc2 = IFIELD( theInstr, 0, 11 );
25839 IRTemp vA = newTemp(Ity_V128);
25840 IRTemp vB = newTemp(Ity_V128);
25841 assign( vA, getVReg(vA_addr));
25842 assign( vB, getVReg(vB_addr));
25844 if (opc1 != 0x4) {
25845 vex_printf("dis_av_cipher(ppc)(instr)\n");
25846 return False;
25848 switch (opc2) {
25849 case 0x508: // vcipher (Vector Inverser Cipher)
25850 DIP("vcipher v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25851 putVReg( vD_addr,
25852 binop(Iop_CipherV128, mkexpr(vA), mkexpr(vB)) );
25853 return True;
25855 case 0x509: // vcipherlast (Vector Inverser Cipher Last)
25856 DIP("vcipherlast v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25857 putVReg( vD_addr,
25858 binop(Iop_CipherLV128, mkexpr(vA), mkexpr(vB)) );
25859 return True;
25861 case 0x548: // vncipher (Vector Inverser Cipher)
25862 DIP("vncipher v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25863 putVReg( vD_addr,
25864 binop(Iop_NCipherV128, mkexpr(vA), mkexpr(vB)) );
25865 return True;
25867 case 0x549: // vncipherlast (Vector Inverser Cipher Last)
25868 DIP("vncipherlast v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25869 putVReg( vD_addr,
25870 binop(Iop_NCipherLV128, mkexpr(vA), mkexpr(vB)) );
25871 return True;
25873 case 0x5C8: /* vsbox (Vector SubBytes, this does the cipher
25874 * subBytes transform)
25876 DIP("vsbox v%d,v%d\n", vD_addr, vA_addr);
25877 putVReg( vD_addr,
25878 unop(Iop_CipherSV128, mkexpr(vA) ) );
25879 return True;
25881 default:
25882 vex_printf("dis_av_cipher(ppc)(opc2)\n");
25883 return False;
25885 return True;
25889 AltiVec Secure Hash Instructions
25891 static Bool dis_av_hash ( UInt theInstr )
25893 /* VX-Form */
25894 UChar opc1 = ifieldOPC(theInstr);
25895 UChar vRT_addr = ifieldRegDS(theInstr);
25896 UChar vRA_addr = ifieldRegA(theInstr);
25897 UChar s_field = IFIELD( theInstr, 11, 5 ); // st and six field
25898 UChar st = IFIELD( theInstr, 15, 1 ); // st
25899 UChar six = IFIELD( theInstr, 11, 4 ); // six field
25900 UInt opc2 = IFIELD( theInstr, 0, 11 );
25902 IRTemp vA = newTemp(Ity_V128);
25903 IRTemp dst = newTemp(Ity_V128);
25904 assign( vA, getVReg(vRA_addr));
25906 if (opc1 != 0x4) {
25907 vex_printf("dis_av_hash(ppc)(instr)\n");
25908 return False;
25911 switch (opc2) {
25912 case 0x682: // vshasigmaw
25913 DIP("vshasigmaw v%d,v%d,%u,%u\n", vRT_addr, vRA_addr, st, six);
25914 assign( dst, binop( Iop_SHA256, mkexpr( vA ), mkU8( s_field) ) );
25915 putVReg( vRT_addr, mkexpr(dst));
25916 return True;
25918 case 0x6C2: // vshasigmad,
25919 DIP("vshasigmad v%d,v%d,%u,%u\n", vRT_addr, vRA_addr, st, six);
25920 putVReg( vRT_addr, binop( Iop_SHA512, mkexpr( vA ), mkU8( s_field) ) );
25921 return True;
25923 default:
25924 vex_printf("dis_av_hash(ppc)(opc2)\n");
25925 return False;
25927 return True;
25931 * This function is used by the Vector add/subtract [extended] modulo/carry
25932 * instructions.
25933 * - For the non-extended add instructions, the cin arg is set to zero.
25934 * - For the extended add instructions, cin is the integer value of
25935 * src3.bit[127].
25936 * - For the non-extended subtract instructions, src1 is added to the one's
25937 * complement of src2 + 1. We re-use the cin argument to hold the '1'
25938 * value for this operation.
25939 * - For the extended subtract instructions, cin is the integer value of src3.bit[127].
25941 static IRTemp _get_quad_modulo_or_carry(IRExpr * vecA, IRExpr * vecB,
25942 IRExpr * cin, Bool modulo)
25944 IRTemp _vecA_32 = IRTemp_INVALID;
25945 IRTemp _vecB_32 = IRTemp_INVALID;
25946 IRTemp res_32 = IRTemp_INVALID;
25947 IRTemp res_64 = IRTemp_INVALID;
25948 IRTemp result = IRTemp_INVALID;
25949 IRTemp tmp_result = IRTemp_INVALID;
25950 IRTemp carry = IRTemp_INVALID;
25951 Int i;
25952 IRExpr * _vecA_low64 = unop( Iop_V128to64, vecA );
25953 IRExpr * _vecB_low64 = unop( Iop_V128to64, vecB );
25954 IRExpr * _vecA_high64 = unop( Iop_V128HIto64, vecA );
25955 IRExpr * _vecB_high64 = unop( Iop_V128HIto64, vecB );
25957 carry = newTemp(Ity_I32);
25958 assign( carry, cin );
25960 for (i = 0; i < 4; i++) {
25961 _vecA_32 = newTemp(Ity_I32);
25962 _vecB_32 = newTemp(Ity_I32);
25963 res_32 = newTemp(Ity_I32);
25964 res_64 = newTemp(Ity_I64);
25966 switch (i) {
25967 case 0:
25968 assign(_vecA_32, unop( Iop_64to32, _vecA_low64 ) );
25969 assign(_vecB_32, unop( Iop_64to32, _vecB_low64 ) );
25970 break;
25971 case 1:
25972 assign(_vecA_32, unop( Iop_64HIto32, _vecA_low64 ) );
25973 assign(_vecB_32, unop( Iop_64HIto32, _vecB_low64 ) );
25974 break;
25975 case 2:
25976 assign(_vecA_32, unop( Iop_64to32, _vecA_high64 ) );
25977 assign(_vecB_32, unop( Iop_64to32, _vecB_high64 ) );
25978 break;
25979 case 3:
25980 assign(_vecA_32, unop( Iop_64HIto32, _vecA_high64 ) );
25981 assign(_vecB_32, unop( Iop_64HIto32, _vecB_high64 ) );
25982 break;
25985 assign( res_64, binop( Iop_Add64,
25986 binop ( Iop_Add64,
25987 binop( Iop_32HLto64,
25988 mkU32( 0 ),
25989 mkexpr(_vecA_32) ),
25990 binop( Iop_32HLto64,
25991 mkU32( 0 ),
25992 mkexpr(_vecB_32) ) ),
25993 binop( Iop_32HLto64,
25994 mkU32( 0 ),
25995 mkexpr( carry ) ) ) );
25997 /* Calculate the carry to the next higher 32 bits. */
25998 carry = newTemp(Ity_I32);
25999 assign(carry, unop( Iop_64HIto32, mkexpr( res_64 ) ) );
26001 /* result is the lower 32-bits */
26002 assign(res_32, unop( Iop_64to32, mkexpr( res_64 ) ) );
26004 if (modulo) {
26005 result = newTemp(Ity_V128);
26006 assign(result, binop( Iop_OrV128,
26007 (i == 0) ? binop( Iop_64HLtoV128,
26008 mkU64(0),
26009 mkU64(0) ) : mkexpr(tmp_result),
26010 binop( Iop_ShlV128,
26011 binop( Iop_64HLtoV128,
26012 mkU64(0),
26013 binop( Iop_32HLto64,
26014 mkU32(0),
26015 mkexpr(res_32) ) ),
26016 mkU8(i * 32) ) ) );
26017 tmp_result = newTemp(Ity_V128);
26018 assign(tmp_result, mkexpr(result));
26021 if (modulo)
26022 return result;
26023 else
26024 return carry;
26028 static Bool dis_av_quad ( UInt theInstr )
26030 /* VX-Form */
26031 UChar opc1 = ifieldOPC(theInstr);
26032 UChar vRT_addr = ifieldRegDS(theInstr);
26033 UChar vRA_addr = ifieldRegA(theInstr);
26034 UChar vRB_addr = ifieldRegB(theInstr);
26035 UChar vRC_addr;
26036 UInt opc2 = IFIELD( theInstr, 0, 11 );
26038 IRTemp vA = newTemp(Ity_V128);
26039 IRTemp vB = newTemp(Ity_V128);
26040 IRTemp vC = IRTemp_INVALID;
26041 IRTemp cin = IRTemp_INVALID;
26042 assign( vA, getVReg(vRA_addr));
26043 assign( vB, getVReg(vRB_addr));
26045 if (opc1 != 0x4) {
26046 vex_printf("dis_av_quad(ppc)(instr)\n");
26047 return False;
26050 switch (opc2) {
26051 case 0x140: // vaddcuq
26052 DIP("vaddcuq v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
26053 putVReg( vRT_addr, unop( Iop_32UtoV128,
26054 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
26055 mkexpr(vB),
26056 mkU32(0), False) ) ) );
26057 return True;
26058 case 0x100: // vadduqm
26059 DIP("vadduqm v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
26060 putVReg( vRT_addr, mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
26061 mkexpr(vB), mkU32(0), True) ) );
26062 return True;
26063 case 0x540: // vsubcuq
26064 DIP("vsubcuq v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
26065 putVReg( vRT_addr,
26066 unop( Iop_32UtoV128,
26067 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
26068 unop( Iop_NotV128,
26069 mkexpr(vB) ),
26070 mkU32(1), False) ) ) );
26071 return True;
26072 case 0x500: // vsubuqm
26073 DIP("vsubuqm v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
26074 putVReg( vRT_addr,
26075 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
26076 unop( Iop_NotV128, mkexpr(vB) ),
26077 mkU32(1), True) ) );
26078 return True;
26079 case 0x054C: // vbpermq
26081 #define BPERMD_IDX_MASK 0x00000000000000FFULL
26082 #define BPERMD_BIT_MASK 0x8000000000000000ULL
26083 int i;
26084 IRExpr * vB_expr = mkexpr(vB);
26085 IRExpr * res = binop(Iop_AndV128, mkV128(0), mkV128(0));
26086 DIP("vbpermq v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
26087 for (i = 0; i < 16; i++) {
26088 IRTemp idx_tmp = newTemp( Ity_V128 );
26089 IRTemp perm_bit = newTemp( Ity_V128 );
26090 IRTemp idx = newTemp( Ity_I8 );
26091 IRTemp idx_LT127 = newTemp( Ity_I1 );
26092 IRTemp idx_LT127_ity128 = newTemp( Ity_V128 );
26094 assign( idx_tmp,
26095 binop( Iop_AndV128,
26096 binop( Iop_64HLtoV128,
26097 mkU64(0),
26098 mkU64(BPERMD_IDX_MASK) ),
26099 vB_expr ) );
26100 assign( idx_LT127,
26101 binop( Iop_CmpEQ32,
26102 unop ( Iop_64to32,
26103 unop( Iop_V128to64, binop( Iop_ShrV128,
26104 mkexpr(idx_tmp),
26105 mkU8(7) ) ) ),
26106 mkU32(0) ) );
26108 /* Below, we set idx to determine which bit of vA to use for the
26109 * perm bit. If idx_LT127 is 0, the perm bit is forced to '0'.
26111 assign( idx,
26112 binop( Iop_And8,
26113 unop( Iop_1Sto8,
26114 mkexpr(idx_LT127) ),
26115 unop( Iop_32to8,
26116 unop( Iop_V128to32, mkexpr( idx_tmp ) ) ) ) );
26118 assign( idx_LT127_ity128,
26119 binop( Iop_64HLtoV128,
26120 mkU64(0),
26121 unop( Iop_32Uto64,
26122 unop( Iop_1Uto32, mkexpr(idx_LT127 ) ) ) ) );
26123 assign( perm_bit,
26124 binop( Iop_AndV128,
26125 mkexpr( idx_LT127_ity128 ),
26126 binop( Iop_ShrV128,
26127 binop( Iop_AndV128,
26128 binop (Iop_64HLtoV128,
26129 mkU64( BPERMD_BIT_MASK ),
26130 mkU64(0)),
26131 binop( Iop_ShlV128,
26132 mkexpr( vA ),
26133 mkexpr( idx ) ) ),
26134 mkU8( 127 ) ) ) );
26135 res = binop( Iop_OrV128,
26136 res,
26137 binop( Iop_ShlV128,
26138 mkexpr( perm_bit ),
26139 mkU8( i + 64 ) ) );
26140 vB_expr = binop( Iop_ShrV128, vB_expr, mkU8( 8 ) );
26142 putVReg( vRT_addr, res);
26143 return True;
26144 #undef BPERMD_IDX_MASK
26145 #undef BPERMD_BIT_MASK
26148 default:
26149 break; // fall through
26152 opc2 = IFIELD( theInstr, 0, 6 );
26153 vRC_addr = ifieldRegC(theInstr);
26154 vC = newTemp(Ity_V128);
26155 cin = newTemp(Ity_I32);
26156 switch (opc2) {
26157 case 0x3D: // vaddecuq
26158 assign( vC, getVReg(vRC_addr));
26159 DIP("vaddecuq v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
26160 vRC_addr);
26161 assign(cin, binop( Iop_And32,
26162 unop( Iop_64to32,
26163 unop( Iop_V128to64, mkexpr(vC) ) ),
26164 mkU32(1) ) );
26165 putVReg( vRT_addr,
26166 unop( Iop_32UtoV128,
26167 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA), mkexpr(vB),
26168 mkexpr(cin),
26169 False) ) ) );
26170 return True;
26171 case 0x3C: // vaddeuqm
26172 assign( vC, getVReg(vRC_addr));
26173 DIP("vaddeuqm v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
26174 vRC_addr);
26175 assign(cin, binop( Iop_And32,
26176 unop( Iop_64to32,
26177 unop( Iop_V128to64, mkexpr(vC) ) ),
26178 mkU32(1) ) );
26179 putVReg( vRT_addr,
26180 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA), mkexpr(vB),
26181 mkexpr(cin),
26182 True) ) );
26183 return True;
26184 case 0x3F: // vsubecuq
26185 assign( vC, getVReg(vRC_addr));
26186 DIP("vsubecuq v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
26187 vRC_addr);
26188 assign(cin, binop( Iop_And32,
26189 unop( Iop_64to32,
26190 unop( Iop_V128to64, mkexpr(vC) ) ),
26191 mkU32(1) ) );
26192 putVReg( vRT_addr,
26193 unop( Iop_32UtoV128,
26194 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
26195 unop( Iop_NotV128,
26196 mkexpr(vB) ),
26197 mkexpr(cin),
26198 False) ) ) );
26199 return True;
26200 case 0x3E: // vsubeuqm
26201 assign( vC, getVReg(vRC_addr));
26202 DIP("vsubeuqm v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
26203 vRC_addr);
26204 assign(cin, binop( Iop_And32,
26205 unop( Iop_64to32,
26206 unop( Iop_V128to64, mkexpr(vC) ) ),
26207 mkU32(1) ) );
26208 putVReg( vRT_addr,
26209 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
26210 unop( Iop_NotV128, mkexpr(vB) ),
26211 mkexpr(cin),
26212 True) ) );
26213 return True;
26214 default:
26215 vex_printf("dis_av_quad(ppc)(opc2.2)\n");
26216 return False;
26219 return True;
26222 static IRExpr * bcd_sign_code_adjust( UInt ps, IRExpr * tmp)
26224 /* The Iop_BCDAdd and Iop_BCDSub will result in the corresponding Power PC
26225 * instruction being issued with ps = 0. If ps = 1, the sign code, which
26226 * is in the least significant four bits of the result, needs to be updated
26227 * per the ISA:
26229 * If PS=0, the sign code of the result is set to 0b1100.
26230 * If PS=1, the sign code of the result is set to 0b1111.
26232 * Note, the ps value is NOT being passed down to the instruction issue
26233 * because passing a constant via triop() breaks the vbit-test test. The
26234 * vbit-tester assumes it can set non-zero shadow bits for the triop()
26235 * arguments. Thus they have to be expressions not a constant.
26236 * Use 32-bit compare instructiions as 64-bit compares are not supported
26237 * in 32-bit mode.
26239 IRTemp mask = newTemp(Ity_I64);
26240 IRExpr *rtn;
26242 if ( ps == 0 ) {
26243 /* sign code is correct, just return it. */
26244 rtn = tmp;
26246 } else {
26247 /* Check if lower four bits are 0b1100, if so, change to 0b1111 */
26248 /* Make this work in 32-bit mode using only 32-bit compares */
26249 assign( mask, unop( Iop_1Sto64,
26250 binop( Iop_CmpEQ32, mkU32( 0xC ),
26251 binop( Iop_And32, mkU32( 0xF ),
26252 unop( Iop_64to32,
26253 unop( Iop_V128to64, tmp )
26254 ) ) ) ) );
26255 rtn = binop( Iop_64HLtoV128,
26256 unop( Iop_V128HIto64, tmp ),
26257 binop( Iop_Or64,
26258 binop( Iop_And64, mkU64( 0xF ), mkexpr( mask ) ),
26259 unop( Iop_V128to64, tmp ) ) );
26262 return rtn;
26266 AltiVec BCD Arithmetic instructions.
26267 These instructions modify CR6 for various conditions in the result,
26268 including when an overflow occurs. We could easily detect all conditions
26269 except when an overflow occurs. But since we can't be 100% accurate
26270 in our emulation of CR6, it seems best to just not support it all.
26272 static Bool dis_av_bcd_misc ( UInt theInstr, const VexAbiInfo* vbi )
26274 UChar opc1 = ifieldOPC(theInstr);
26275 UChar vRT_addr = ifieldRegDS(theInstr);
26276 UChar vRA_addr = ifieldRegA(theInstr);
26277 UChar vRB_addr = ifieldRegB(theInstr);
26278 IRTemp vA = newTemp(Ity_V128);
26279 IRTemp vB = newTemp(Ity_V128);
26280 UInt opc2 = IFIELD( theInstr, 0, 11 );
26281 IRExpr *pos, *neg, *valid, *zero, *sign;
26282 IRTemp eq_lt_gt = newTemp( Ity_I32 );
26284 assign( vA, getVReg(vRA_addr));
26285 assign( vB, getVReg(vRB_addr));
26287 if (opc1 != 0x4) {
26288 vex_printf("dis_av_bcd_misc(ppc)(instr)\n");
26289 return False;
26292 switch (opc2) {
26293 case 0x341: // bcdcpsgn. Decimal Copy Sign VX-form
26295 IRExpr *sign_vb, *value_va;
26296 DIP("bcdcpsgn. v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
26298 zero =
26299 BCDstring_zero( binop( Iop_AndV128,
26300 binop( Iop_64HLtoV128,
26301 mkU64( 0xFFFFFFFFFFFFFFFF ),
26302 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
26303 mkexpr( vA ) ) );
26305 /* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
26306 * codes 0xB and 0xD are negative.
26308 sign = binop( Iop_And64, mkU64( 0xF ),
26309 unop( Iop_V128to64, mkexpr( vB ) ) );
26311 neg = mkOR1( binop( Iop_CmpEQ64,
26312 sign,
26313 mkU64 ( 0xB ) ),
26314 binop( Iop_CmpEQ64,
26315 sign,
26316 mkU64 ( 0xD ) ) );
26318 pos = mkNOT1( neg );
26320 /* invalid if vA or vB is not valid */
26321 valid =
26322 unop( Iop_64to32,
26323 binop( Iop_And64,
26324 is_BCDstring128( vbi,
26325 /*Signed*/True, mkexpr( vA ) ),
26326 is_BCDstring128( vbi,
26327 /*Signed*/True, mkexpr( vB ) ) ) );
26329 sign_vb = binop( Iop_AndV128,
26330 binop( Iop_64HLtoV128,
26331 mkU64( 0 ),
26332 mkU64( 0xF ) ),
26333 mkexpr( vB ) );
26335 value_va = binop( Iop_AndV128,
26336 binop( Iop_64HLtoV128,
26337 mkU64( 0xFFFFFFFFFFFFFFFF ),
26338 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
26339 mkexpr( vA ) );
26340 putVReg( vRT_addr, binop( Iop_OrV128, sign_vb, value_va ) );
26342 break;
26344 default:
26345 vex_printf("dis_av_bcd_misc(ppc)(opc2)\n");
26346 return False;
26349 /* set CR field 6 to:
26350 * 0b1000 if vB less then 0, i.e. vB is neg and not zero,
26351 * 0b0100 if vB greter then 0, i.e. vB is pos and not zero,
26352 * 0b1000 if vB equals 0,
26353 * 0b0001 if vB is invalid over rules lt, gt, eq
26355 assign( eq_lt_gt,
26356 binop( Iop_Or32,
26357 binop( Iop_Shl32,
26358 unop( Iop_1Uto32,
26359 mkAND1( neg,
26360 mkNOT1( zero ) ) ),
26361 mkU8( 3 ) ),
26362 binop( Iop_Or32,
26363 binop( Iop_Shl32,
26364 unop( Iop_1Uto32,
26365 mkAND1( pos,
26366 mkNOT1( zero ) ) ),
26367 mkU8( 2 ) ),
26368 binop( Iop_Shl32,
26369 unop( Iop_1Uto32, zero ),
26370 mkU8( 1 ) ) ) ) );
26372 IRTemp valid_mask = newTemp( Ity_I32 );
26374 assign( valid_mask, unop( Iop_1Sto32, unop( Iop_32to1, valid ) ) );
26376 putGST_field( PPC_GST_CR,
26377 binop( Iop_Or32,
26378 binop( Iop_And32,
26379 mkexpr( valid_mask ),
26380 mkexpr( eq_lt_gt ) ),
26381 binop( Iop_And32,
26382 unop( Iop_Not32, mkexpr( valid_mask ) ),
26383 mkU32( 1 ) ) ),
26384 6 );
26385 return True;
26388 static Bool dis_av_bcd ( UInt theInstr, const VexAbiInfo* vbi )
26390 /* VX-Form */
26391 UChar opc1 = ifieldOPC(theInstr);
26392 UChar vRT_addr = ifieldRegDS(theInstr);
26393 UChar vRA_addr = ifieldRegA(theInstr);
26394 UChar vRB_addr = ifieldRegB(theInstr);
26395 UChar ps = IFIELD( theInstr, 9, 1 );
26396 UInt opc2 = IFIELD( theInstr, 0, 9 );
26397 IRTemp vA = newTemp(Ity_V128);
26398 IRTemp vB = newTemp(Ity_V128);
26399 IRTemp dst = newTemp(Ity_V128);
26400 IRExpr *pos, *neg, *valid, *zero, *sign_digit, *in_range;
26401 IRTemp eq_lt_gt = newTemp( Ity_I32 );
26402 IRExpr *overflow, *value;
26404 assign( vA, getVReg(vRA_addr));
26405 assign( vB, getVReg(vRB_addr));
26407 if (opc1 != 0x4) {
26408 vex_printf("dis_av_bcd(ppc)(instr)\n");
26409 return False;
26412 switch (opc2) {
26413 case 0x1: // bcdadd.
26414 case 0x41: // bcdsub.
26416 /* NOTE 64 bit compares are not supported in 32-bit mode. Use
26417 * 32-bit compares only.
26420 IRExpr *sign, *res_smaller;
26421 IRExpr *signA, *signB, *sign_digitA, *sign_digitB;
26422 IRExpr *zeroA, *zeroB, *posA, *posB, *negA, *negB;
26424 if ( opc2 == 0x1 ) {
26425 DIP("bcdadd. v%d,v%d,v%d,%u\n", vRT_addr, vRA_addr, vRB_addr, ps);
26426 assign( dst, bcd_sign_code_adjust( ps,
26427 binop( Iop_BCDAdd,
26428 mkexpr( vA ),
26429 mkexpr( vB ) ) ) );
26430 } else {
26431 DIP("bcdsub. v%d,v%d,v%d,%u\n", vRT_addr, vRA_addr, vRB_addr, ps);
26432 assign( dst, bcd_sign_code_adjust( ps,
26433 binop( Iop_BCDSub,
26434 mkexpr( vA ),
26435 mkexpr( vB ) ) ) );
26438 putVReg( vRT_addr, mkexpr( dst ) );
26439 /* set CR field 6 */
26440 /* result */
26441 zero = BCDstring_zero( binop( Iop_AndV128,
26442 binop( Iop_64HLtoV128,
26443 mkU64( 0xFFFFFFFFFFFFFFFF ),
26444 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
26445 mkexpr(dst) ) ); // ignore sign
26447 sign_digit = binop( Iop_And32, mkU32( 0xF ),
26448 unop( Iop_64to32,
26449 unop( Iop_V128to64, mkexpr( dst ) ) ) );
26451 sign = mkOR1( binop( Iop_CmpEQ32,
26452 sign_digit,
26453 mkU32 ( 0xB ) ),
26454 binop( Iop_CmpEQ32,
26455 sign_digit,
26456 mkU32 ( 0xD ) ) );
26457 neg = mkAND1( sign, mkNOT1( zero ) );
26459 /* Pos position AKA gt = 1 if ((not neg) & (not eq zero)) */
26460 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
26461 valid = unop( Iop_64to32,
26462 binop( Iop_And64,
26463 is_BCDstring128( vbi,
26464 /*Signed*/True, mkexpr( vA ) ),
26465 is_BCDstring128( vbi,
26466 /*Signed*/True, mkexpr( vB ) )
26467 ) );
26469 /* src A */
26470 zeroA = BCDstring_zero( binop( Iop_AndV128,
26471 binop( Iop_64HLtoV128,
26472 mkU64( 0xFFFFFFFFFFFFFFFF ),
26473 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
26474 mkexpr( vA ) ) ); // ignore sign
26475 sign_digitA = binop( Iop_And32, mkU32( 0xF ),
26476 unop( Iop_64to32,
26477 unop( Iop_V128to64, mkexpr( vA ) ) ) );
26479 signA = mkOR1( binop( Iop_CmpEQ32,
26480 sign_digitA,
26481 mkU32 ( 0xB ) ),
26482 binop( Iop_CmpEQ32,
26483 sign_digitA,
26484 mkU32 ( 0xD ) ) );
26485 negA = mkAND1( signA, mkNOT1( zeroA ) );
26486 /* Pos position AKA gt = 1 if ((not neg) & (not eq zero)) */
26487 posA = mkAND1( mkNOT1( signA ), mkNOT1( zeroA ) );
26489 /* src B */
26490 zeroB = BCDstring_zero( binop( Iop_AndV128,
26491 binop( Iop_64HLtoV128,
26492 mkU64( 0xFFFFFFFFFFFFFFFF ),
26493 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
26494 mkexpr( vB ) ) ); // ignore sign
26495 sign_digitB = binop( Iop_And32, mkU32( 0xF ),
26496 unop( Iop_64to32,
26497 unop( Iop_V128to64, mkexpr( vB ) ) ) );
26499 signB = mkOR1( binop( Iop_CmpEQ32,
26500 sign_digitB,
26501 mkU32 ( 0xB ) ),
26502 binop( Iop_CmpEQ32,
26503 sign_digitB,
26504 mkU32 ( 0xD ) ) );
26505 negB = mkAND1( signB, mkNOT1( zeroB ) );
26508 /* Pos position AKA gt = 1 if ((not neg) & (not eq zero)) */
26509 posB = mkAND1( mkNOT1( signB ), mkNOT1( zeroB ) );
26512 if (mode64) {
26513 res_smaller = mkAND1( CmpGT128U( mkexpr( vA ), mkexpr( dst ) ),
26514 CmpGT128U( mkexpr( vB ), mkexpr( dst ) ) );
26516 } else {
26517 /* Have to do this with 32-bit compares, expensive */
26518 res_smaller = mkAND1( UNSIGNED_CMP_GT_V128( mkexpr( vA ),
26519 mkexpr( dst ) ),
26520 UNSIGNED_CMP_GT_V128( mkexpr( vB ),
26521 mkexpr( dst ) ) );
26524 if ( opc2 == 0x1) {
26525 /* Overflow for Add can only occur if the signs of the operands
26526 * are the same and the two operands are non-zero. On overflow,
26527 * the PPC hardware produces a result consisting of just the lower
26528 * digits of the result. So, if the result is less then both
26529 * operands and the sign of the operands are the same overflow
26530 * occured.
26532 overflow = mkOR1( mkAND1( res_smaller, mkAND1( negA, negB ) ),
26533 mkAND1( res_smaller, mkAND1( posA, posB ) ) );
26534 } else {
26535 /* Overflow for Add can only occur if the signs of the operands
26536 * are the different and the two operands are non-zero. On overflow,
26537 * the PPC hardware produces a result consisting of just the lower
26538 * digits of the result. So, if the result is less then both
26539 * operands and the sign of the operands are different overflow
26540 * occured.
26542 overflow = mkOR1( mkAND1( res_smaller, mkAND1( negA, posB ) ),
26543 mkAND1( res_smaller, mkAND1( posA, negB ) ) );
26546 break;
26548 case 0x081: // bcdus. Decimal Unsigned Shift VX-form
26549 case 0x0C1: // bcds. Decimal Shift VX-form
26550 case 0x1C1: // bcdsr. Decimal Shift and Round VX-form
26552 IRExpr *shift_dir;
26553 IRExpr *shift_mask, *result, *new_sign_val, *sign;
26554 IRExpr *not_excess_shift, *not_excess_shift_mask;
26555 IRTemp shift_dir_mask = newTemp( Ity_I64 );
26556 IRTemp shift_by = newTemp( Ity_I64 );
26557 IRTemp shift_field = newTemp( Ity_I64 );
26558 IRTemp shifted_out = newTemp( Ity_V128 );
26559 IRTemp value_shl = newTemp( Ity_V128 );
26560 IRTemp value_shr = newTemp( Ity_V128 );
26561 IRTemp round = newTemp( Ity_I32);
26563 ULong value_mask_low = 0;
26564 UInt max_shift = 0;
26566 if (opc2 == 0x0C1) {
26567 DIP("bcds. v%d,v%d,v%d,%d\n", vRT_addr, vRA_addr, vRB_addr, ps);
26568 value_mask_low = 0xFFFFFFFFFFFFFFF0;
26569 max_shift = 30 * 4; /* maximum without shifting all digits out */
26571 } else if (opc2 == 0x1C1) {
26572 DIP("bcdsr. v%d,v%d,v%d,%d\n", vRT_addr, vRA_addr, vRB_addr, ps);
26574 value_mask_low = 0xFFFFFFFFFFFFFFF0;
26575 max_shift = 30 * 4; /* maximum without shifting all digits out */
26577 } else {
26578 DIP("bcdus. v%d,v%d,v%d,%d\n", vRT_addr, vRA_addr,
26579 vRB_addr, ps);
26580 value_mask_low = 0xFFFFFFFFFFFFFFFF;
26581 max_shift = 31 * 4; /* maximum without shifting all digits out */
26584 value = binop( Iop_AndV128,
26585 binop( Iop_64HLtoV128,
26586 mkU64( 0xFFFFFFFFFFFFFFFF ),
26587 mkU64( value_mask_low ) ),
26588 mkexpr( vB ) );
26590 zero = BCDstring_zero( value );
26592 /* Shift field is 2's complement value */
26593 assign( shift_field, unop( Iop_V128to64,
26594 binop( Iop_ShrV128,
26595 binop( Iop_AndV128,
26596 binop( Iop_64HLtoV128,
26597 mkU64( 0xFF ),
26598 mkU64( 0x0) ),
26599 mkexpr( vA ) ),
26600 mkU8( 64 ) ) ) );
26602 /* if shift_dir = 0 shift left, otherwise shift right */
26603 shift_dir = binop( Iop_CmpEQ64,
26604 binop( Iop_Shr64,
26605 mkexpr( shift_field ),
26606 mkU8( 7 ) ),
26607 mkU64( 1 ) );
26609 assign( shift_dir_mask, unop( Iop_1Sto64, shift_dir ) );
26611 /* Shift field is stored in 2's complement form */
26612 assign(shift_by,
26613 binop( Iop_Mul64,
26614 binop( Iop_Or64,
26615 binop( Iop_And64,
26616 unop( Iop_Not64,
26617 mkexpr( shift_dir_mask ) ),
26618 mkexpr( shift_field ) ),
26619 binop( Iop_And64,
26620 mkexpr( shift_dir_mask ),
26621 binop( Iop_And64,
26622 binop( Iop_Add64,
26623 mkU64( 1 ),
26624 unop( Iop_Not64,
26625 mkexpr( shift_field ) ) ),
26626 mkU64( 0xFF ) ) ) ),
26627 mkU64( 4 ) ) );
26629 /* If the shift exceeds 128 bits, we need to force the result
26630 * to zero because Valgrind shift amount is only 7-bits. Otherwise,
26631 * we get a shift amount of mod(shift_by, 127)
26633 not_excess_shift = unop( Iop_1Sto64,
26634 binop( Iop_CmpLE64U,
26635 mkexpr( shift_by ),
26636 mkU64( max_shift ) ) );
26638 not_excess_shift_mask = binop( Iop_64HLtoV128,
26639 not_excess_shift,
26640 not_excess_shift );
26642 assign( value_shl,
26643 binop( Iop_ShlV128, value, unop( Iop_64to8,
26644 mkexpr( shift_by) ) ) );
26645 assign( value_shr,
26646 binop( Iop_AndV128,
26647 binop( Iop_64HLtoV128,
26648 mkU64( 0xFFFFFFFFFFFFFFFF ),
26649 mkU64( value_mask_low) ),
26650 binop( Iop_ShrV128,
26651 value,
26652 unop( Iop_64to8,
26653 mkexpr( shift_by ) ) ) ) );
26655 /* Overflow occurs if the shift amount is greater than zero, the
26656 * operation is a left shift and any non-zero digits are left
26657 * shifted out.
26659 assign( shifted_out,
26660 binop( Iop_OrV128,
26661 binop( Iop_ShrV128,
26662 value,
26663 unop( Iop_64to8,
26664 binop( Iop_Sub64,
26665 mkU64( 32*4 ),
26666 mkexpr( shift_by ) ) ) ),
26667 binop( Iop_AndV128,
26668 unop( Iop_NotV128,
26669 not_excess_shift_mask ),
26670 value ) ) );
26672 overflow = mkAND1( mkNOT1( BCDstring_zero( mkexpr( shifted_out ) ) ),
26673 mkAND1( mkNOT1( shift_dir ),
26674 binop( Iop_CmpNE64,
26675 mkexpr( shift_by ),
26676 mkU64( 0 ) ) ) );
26678 if ((opc2 == 0xC1) || (opc2 == 0x1C1)) {
26679 /* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
26680 * codes 0xB and 0xD are negative.
26682 sign_digit = binop( Iop_And64, mkU64( 0xF ),
26683 unop( Iop_V128to64, mkexpr( vB ) ) );
26685 sign = mkOR1( binop( Iop_CmpEQ64,
26686 sign_digit,
26687 mkU64 ( 0xB ) ),
26688 binop( Iop_CmpEQ64,
26689 sign_digit,
26690 mkU64 ( 0xD ) ) );
26691 neg = mkAND1( sign, mkNOT1( zero ) );
26693 /* Pos position AKA gt = 1 if ((not neg) & (not eq zero)) */
26694 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
26696 valid =
26697 unop( Iop_64to32,
26698 is_BCDstring128( vbi, /* Signed */True, mkexpr( vB ) ) );
26700 } else {
26701 /* string is an unsigned BCD value */
26702 pos = mkU1( 1 );
26703 neg = mkU1( 0 );
26704 sign = mkU1( 0 );
26706 valid =
26707 unop( Iop_64to32,
26708 is_BCDstring128( vbi, /* Unsigned */False,
26709 mkexpr( vB ) ) );
26712 /* if PS = 0
26713 vB positive, sign is C
26714 vB negative, sign is D
26715 if PS = 1
26716 vB positive, sign is F
26717 vB negative, sign is D
26718 Note can't use pos or neg here since they are ANDed with zero,
26719 use sign instead.
26721 if (ps == 0) {
26722 new_sign_val = binop( Iop_Or64,
26723 unop( Iop_1Uto64, sign ),
26724 mkU64( 0xC ) );
26726 } else {
26727 new_sign_val = binop( Iop_Xor64,
26728 binop( Iop_Shl64,
26729 unop( Iop_1Uto64, sign ),
26730 mkU8( 1 ) ),
26731 mkU64( 0xF ) );
26734 shift_mask = binop( Iop_64HLtoV128,
26735 unop( Iop_1Sto64, shift_dir ),
26736 unop( Iop_1Sto64, shift_dir ) );
26738 result = binop( Iop_OrV128,
26739 binop( Iop_AndV128, mkexpr( value_shr ), shift_mask ),
26740 binop( Iop_AndV128,
26741 mkexpr( value_shl ),
26742 unop( Iop_NotV128, shift_mask ) ) );
26744 if (opc2 == 0xC1) { // bcds.
26745 putVReg( vRT_addr, binop( Iop_OrV128,
26746 binop( Iop_64HLtoV128,
26747 mkU64( 0 ),
26748 new_sign_val ),
26749 binop( Iop_AndV128,
26750 not_excess_shift_mask,
26751 result ) ) );
26752 } else if (opc2 == 0x1C1) { //bcdsr.
26753 /* If shifting right, need to round up if needed */
26754 assign( round, unop( Iop_1Uto32,
26755 mkAND1( shift_dir,
26756 check_BCD_round( value,
26757 shift_by ) ) ) );
26759 putVReg( vRT_addr,
26760 binop( Iop_OrV128,
26761 binop( Iop_64HLtoV128,
26762 mkU64( 0 ),
26763 new_sign_val ),
26764 binop( Iop_AndV128,
26765 not_excess_shift_mask,
26766 mkexpr( increment_BCDstring( vbi, result,
26767 mkexpr( round)
26768 ) ) ) ) );
26769 } else { // bcdus.
26770 putVReg( vRT_addr, binop( Iop_AndV128,
26771 not_excess_shift_mask,
26772 result ) );
26775 break;
26777 case 0x101: // bcdtrunc. Decimal Truncate VX-form
26778 case 0x141: // bcdutrunc. Decimal Unsigned Truncate VX-form
26780 IRTemp length = newTemp( Ity_I64 );
26781 IRTemp masked_out = newTemp( Ity_V128 );
26782 IRExpr *new_sign_val, *result, *shift;
26783 IRExpr *length_neq_128, *sign;
26784 ULong value_mask_low;
26785 Int max_digits;
26787 if ( opc2 == 0x101) { // bcdtrunc.
26788 value_mask_low = 0xFFFFFFFFFFFFFFF0;
26789 max_digits = 31;
26790 } else {
26791 value_mask_low = 0xFFFFFFFFFFFFFFFF;
26792 max_digits = 32;
26795 assign( length, binop( Iop_And64,
26796 unop( Iop_V128HIto64,
26797 mkexpr( vA ) ),
26798 mkU64( 0xFFFF ) ) );
26799 shift = unop( Iop_64to8,
26800 binop( Iop_Mul64,
26801 binop( Iop_Sub64,
26802 mkU64( max_digits ),
26803 mkexpr( length ) ),
26804 mkU64( 4 ) ) );
26806 /* Note ShrV128 gets masked by 127 so a shift of 128 results in
26807 * the value not being shifted. A shift of 128 sets the register
26808 * zero. So if length+1 = 128, just set the value to 0.
26810 length_neq_128 = mkNOT1( binop( Iop_CmpEQ64,
26811 mkexpr( length),
26812 mkU64( 0x1F ) ) );
26814 assign( masked_out,
26815 binop( Iop_AndV128,
26816 binop( Iop_64HLtoV128,
26817 unop( Iop_1Sto64, length_neq_128 ),
26818 unop( Iop_1Sto64, length_neq_128 ) ),
26819 binop( Iop_ShrV128,
26820 mkexpr( vB ),
26821 unop( Iop_64to8,
26822 binop( Iop_Mul64,
26823 mkU64( 4 ),
26824 binop( Iop_Add64,
26825 mkU64( 1 ),
26826 mkexpr( length ) ) ) ) )
26827 ) );
26829 /* Overflow occurs if any of the left most 31-length digits of vB
26830 * are non-zero.
26832 overflow = mkNOT1( BCDstring_zero( mkexpr( masked_out ) ) );
26834 value = binop( Iop_AndV128,
26835 binop( Iop_64HLtoV128,
26836 mkU64( 0xFFFFFFFFFFFFFFFF ),
26837 mkU64( value_mask_low ) ),
26838 mkexpr( vB ) );
26841 if ( opc2 == 0x101 ) { // bcdtrunc.
26842 /* Check if all of the non-sign digits are zero */
26843 zero = BCDstring_zero( binop( Iop_AndV128,
26844 binop( Iop_64HLtoV128,
26845 mkU64( 0xFFFFFFFFFFFFFFFF ),
26846 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
26847 value ) );
26849 /* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
26850 * codes 0xB and 0xD are negative.
26852 sign_digit = binop( Iop_And64, mkU64( 0xF ),
26853 unop( Iop_V128to64, mkexpr( vB ) ) );
26855 sign = mkOR1( binop( Iop_CmpEQ64,
26856 sign_digit,
26857 mkU64 ( 0xB ) ),
26858 binop( Iop_CmpEQ64,
26859 sign_digit,
26860 mkU64 ( 0xD ) ) );
26861 neg = mkAND1( sign, mkNOT1( zero ) );
26863 /* Pos position AKA gt = 1 if ((not neg) & (not eq zero)) */
26864 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
26866 /* Note can't use pos or neg here since they are ANDed with zero,
26867 use sign instead.
26869 if (ps == 0) {
26870 new_sign_val = binop( Iop_Or64,
26871 unop( Iop_1Uto64, sign ),
26872 mkU64( 0xC ) );
26873 } else {
26874 new_sign_val = binop( Iop_Xor64,
26875 binop( Iop_Shl64,
26876 unop( Iop_1Uto64, sign ),
26877 mkU8 ( 1 ) ),
26878 mkU64( 0xF ) );
26880 valid =
26881 unop( Iop_64to32,
26882 is_BCDstring128( vbi, /* Signed */True, mkexpr( vB ) ) );
26884 } else { // bcdutrunc.
26885 /* Check if all of the digits are zero */
26886 zero = BCDstring_zero( value );
26888 /* unsigned value, need to make CC code happy */
26889 neg = mkU1( 0 );
26891 /* Pos position AKA gt = 1 if (not eq zero) */
26892 pos = mkNOT1( zero );
26893 valid =
26894 unop( Iop_64to32,
26895 is_BCDstring128( vbi, /* Unsigned */False,
26896 mkexpr( vB ) ) );
26899 /* If vB is not valid, the result is undefined, but we need to
26900 * match the hardware so the output of the test suite will match.
26901 * Hardware sets result to 0x0.
26903 result = binop( Iop_AndV128,
26904 mkV128( 0xFFFF ),
26905 binop( Iop_ShrV128,
26906 binop( Iop_ShlV128, value, shift ),
26907 shift ) );
26909 if ( opc2 == 0x101) { // bcdtrunc.
26910 putVReg( vRT_addr, binop( Iop_OrV128,
26911 binop( Iop_64HLtoV128,
26912 mkU64( 0 ),
26913 new_sign_val ),
26914 result ) );
26915 } else {
26916 putVReg( vRT_addr, result );
26919 break;
26921 case 0x181: // bcdctz., bcdctn., bcdcfz., bcdcfn., bcdsetsgn.,
26922 // bcdcfsq., bcdctsq.
26924 UInt inst_select = IFIELD( theInstr, 16, 5);
26926 switch (inst_select) {
26927 case 0: // bcdctsq. (Decimal Convert to Signed Quadword VX-form)
26929 IRExpr *sign;
26931 /* The instruction takes a 32-bit integer in a vector source
26932 * register and returns the signed packed decimal number
26933 * in a vector register. The source integer needs to be moved
26934 * from the V128 to an I32 for the Iop.
26937 DIP("bcdctsq v%d, v%d\n", vRT_addr, vRB_addr);
26939 putVReg( vRT_addr, unop( Iop_BCD128toI128S, mkexpr( vB ) ) );
26941 sign = binop( Iop_And64,
26942 unop( Iop_V128to64, mkexpr( vB ) ),
26943 mkU64( 0xF ) );
26944 zero = mkAND1( binop( Iop_CmpEQ64,
26945 unop( Iop_V128HIto64, mkexpr( vB ) ),
26946 mkU64( 0x0 ) ),
26947 binop( Iop_CmpEQ64,
26948 binop( Iop_And64,
26949 unop( Iop_V128to64, mkexpr( vB ) ),
26950 mkU64( 0xFFFFFFF0 ) ),
26951 mkU64( 0x0 ) ) );
26952 pos = mkAND1( mkNOT1( zero ),
26953 mkOR1( mkOR1( binop( Iop_CmpEQ64,
26954 sign, mkU64( 0xA ) ),
26955 binop( Iop_CmpEQ64,
26956 sign, mkU64( 0xC ) ) ),
26957 mkOR1( binop( Iop_CmpEQ64,
26958 sign, mkU64( 0xE ) ),
26959 binop( Iop_CmpEQ64,
26960 sign, mkU64( 0xF ) ) ) ) );
26961 neg = mkAND1( mkNOT1( zero ),
26962 mkOR1( binop( Iop_CmpEQ64, sign, mkU64( 0xB ) ),
26963 binop( Iop_CmpEQ64, sign, mkU64( 0xD ) ) ) );
26965 /* Check each of the nibbles for a valid digit 0 to 9 */
26966 valid =
26967 unop( Iop_64to32,
26968 is_BCDstring128( vbi, /* Signed */True,
26969 mkexpr( vB ) ) );
26970 overflow = mkU1( 0 ); // not used
26972 break;
26974 case 2: // bcdcfsq. (Decimal Convert from Signed Quadword VX-form)
26976 IRExpr *pos_upper_gt, *pos_upper_eq, *pos_lower_gt;
26977 IRExpr *neg_upper_lt, *neg_upper_eq, *neg_lower_lt;
26979 DIP("bcdcfsq v%d, v%d, %d\n", vRT_addr, vRB_addr, ps);
26981 /* The instruction takes a signed packed decimal number and
26982 * returns the integer value in the vector register. The Iop
26983 * returns an I32 which needs to be moved to the destination
26984 * vector register.
26986 putVReg( vRT_addr,
26987 binop( Iop_I128StoBCD128, mkexpr( vB ), mkU8( ps ) ) );
26989 zero = mkAND1( binop( Iop_CmpEQ64, mkU64( 0 ),
26990 unop( Iop_V128to64, mkexpr( vB ) ) ),
26991 binop( Iop_CmpEQ64, mkU64( 0 ),
26992 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
26993 pos = mkAND1( mkNOT1 ( zero ),
26994 binop( Iop_CmpEQ64, mkU64( 0 ),
26995 binop( Iop_And64,
26996 unop( Iop_V128HIto64,
26997 mkexpr( vB ) ),
26998 mkU64( 0x8000000000000000UL ) ) ) );
26999 neg = mkAND1( mkNOT1 ( zero ),
27000 binop( Iop_CmpEQ64, mkU64( 0x8000000000000000UL ),
27001 binop( Iop_And64,
27002 unop( Iop_V128HIto64,
27003 mkexpr( vB ) ),
27004 mkU64( 0x8000000000000000UL ) ) ) );
27006 /* Overflow occurs if: vB > 10^31-1 OR vB < -10^31-1
27007 * do not have a 128 bit compare. Will have to compare the
27008 * upper 64 bit and athe lower 64 bits. If the upper 64-bits
27009 * are equal then overflow if the lower 64 bits of vB is greater
27010 * otherwise if the upper bits of vB is greater then the max
27011 * for the upper 64-bits then overflow
27013 * 10^31-1 = 0x7E37BE2022C0914B267FFFFFFF
27015 pos_upper_gt = binop( Iop_CmpLT64U,
27016 mkU64( 0x7E37BE2022 ),
27017 unop( Iop_V128HIto64, mkexpr( vB ) ) );
27018 pos_upper_eq = binop( Iop_CmpEQ64,
27019 unop( Iop_V128HIto64, mkexpr( vB ) ),
27020 mkU64( 0x7E37BE2022 ) );
27021 pos_lower_gt = binop( Iop_CmpLT64U,
27022 mkU64( 0x0914B267FFFFFFF ),
27023 unop( Iop_V128to64, mkexpr( vB ) ) );
27024 /* -10^31-1 = 0X81C841DFDD3F6EB4D97FFFFFFF */
27025 neg_upper_lt = binop( Iop_CmpLT64U,
27026 mkU64( 0X81C841DFDD ),
27027 unop( Iop_V128HIto64, mkexpr( vB ) ) );
27028 neg_upper_eq = binop( Iop_CmpEQ64,
27029 unop( Iop_V128HIto64, mkexpr( vB ) ),
27030 mkU64( 0X81C841DFDD ) );
27031 neg_lower_lt = binop( Iop_CmpLT64U,
27032 mkU64( 0x3F6EB4D97FFFFFFF ),
27033 unop( Iop_V128to64, mkexpr( vB ) ) );
27035 /* calculate overflow, masking for positive and negative */
27036 overflow = mkOR1( mkAND1( pos,
27037 mkOR1( pos_upper_gt,
27038 mkAND1( pos_upper_eq,
27039 pos_lower_gt ) ) ),
27040 mkAND1( neg,
27041 mkOR1( neg_upper_lt,
27042 mkAND1( neg_upper_eq,
27043 neg_lower_lt )
27044 ) ) );
27045 valid = mkU32( 1 );
27047 break;
27049 case 4: // bcdctz. (Decimal Convert to Zoned VX-form)
27051 IRExpr *ox_flag, *sign, *vrb_nibble30;
27052 int neg_bit_shift;
27053 unsigned int upper_byte, sign_byte;
27054 IRTemp tmp = newTemp( Ity_V128 );
27056 DIP("bcdctz. v%d,v%d,%d\n", vRT_addr, vRB_addr, ps);
27058 if (ps == 0) {
27059 upper_byte = 0x30;
27060 sign_byte = 0x30;
27061 neg_bit_shift = 4+2; /* sign byte is in bits [7:4] */
27062 } else {
27063 upper_byte = 0xF0;
27064 sign_byte = 0xC0;
27065 neg_bit_shift = 4+0;
27068 /* Grab vB bits[7:4]. It goes into bits [3:0] of the
27069 * result.
27071 vrb_nibble30 = binop( Iop_Shr64,
27072 binop( Iop_And64,
27073 unop( Iop_V128to64, mkexpr( vB ) ),
27074 mkU64( 0xF0 ) ),
27075 mkU8( 4 ) );
27077 /* Upper 24 hex digits of VB, i.e. hex digits vB[0:23],
27078 * must be zero for the value to be zero. This goes
27079 * in the overflow position of the condition code register.
27081 ox_flag = binop( Iop_CmpEQ64,
27082 binop( Iop_And64,
27083 unop( Iop_V128to64, mkexpr( vB ) ),
27084 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
27085 mkU64( 0 ) );
27087 /* zero is the same as eq_flag */
27088 zero = mkAND1( binop( Iop_CmpEQ64,
27089 binop( Iop_And64,
27090 unop( Iop_V128HIto64, mkexpr( vB ) ),
27091 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
27092 mkU64( 0 ) ),
27093 binop( Iop_CmpEQ64,
27094 binop( Iop_And64,
27095 unop( Iop_V128to64, mkexpr( vB ) ),
27096 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
27097 mkU64( 0 ) ) );
27099 /* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
27100 * codes 0xB and 0xD are negative.
27102 sign_digit = binop( Iop_And64, mkU64( 0xF ),
27103 unop( Iop_V128to64, mkexpr( vB ) ) );
27105 /* The negative value goes in the LT bit position of the
27106 * condition code register. Set neg if the sign of vB
27107 * is negative and zero is true.
27109 sign = mkOR1( binop( Iop_CmpEQ64,
27110 sign_digit,
27111 mkU64 ( 0xB ) ),
27112 binop( Iop_CmpEQ64,
27113 sign_digit,
27114 mkU64 ( 0xD ) ) );
27115 neg = mkAND1( sign, mkNOT1( zero ) );
27117 /* The positive value goes in the LT bit position of the
27118 * condition code register. Set positive if the sign of the
27119 * value is not negative.
27121 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
27123 assign( tmp,
27124 convert_to_zoned( vbi, mkexpr( vB ),
27125 mkU64( upper_byte ) ) );
27127 /* Insert the sign based on ps and sign of vB
27128 * in the lower byte.
27130 putVReg( vRT_addr,
27131 binop( Iop_OrV128,
27132 binop( Iop_64HLtoV128,
27133 mkU64( 0 ),
27134 vrb_nibble30 ),
27135 binop( Iop_OrV128,
27136 mkexpr( tmp ),
27137 binop( Iop_64HLtoV128,
27138 mkU64( 0 ),
27139 binop( Iop_Or64,
27140 mkU64( sign_byte ),
27141 binop( Iop_Shl64,
27142 unop( Iop_1Uto64,
27143 sign ),
27144 mkU8( neg_bit_shift)
27145 ) ) ) ) ) );
27147 /* A valid number must have a value that is less then or
27148 * equal to 10^16 - 1. This is checked by making sure
27149 * bytes [31:16] of vB are zero.
27151 in_range = binop( Iop_CmpEQ64,
27152 binop( Iop_And64,
27153 mkU64( 0xFFFFFFFFFFFFFFF0 ),
27154 unop( Iop_V128HIto64, mkexpr( vB ) ) ),
27155 mkU64( 0 ) );
27157 /* overflow is set if ox_flag or not in_inrange. Setting is
27158 * ORed with the other condition code values.
27160 overflow = mkOR1( ox_flag, mkNOT1( in_range ) );
27162 /* The sign code must be between 0xA and 0xF and all digits are
27163 * between 0x0 and 0x9. The vB must be in range to be valid.
27164 * If not valid, condition code set to 0x0001.
27166 valid =
27167 unop( Iop_64to32,
27168 is_BCDstring128( vbi, /* Signed */True,
27169 mkexpr( vB ) ) );
27171 break;
27173 case 5: // bcdctn. (Decimal Convert to National VX-form)
27175 IRExpr *ox_flag, *sign;
27176 IRTemp tmp = newTemp( Ity_V128 );;
27178 DIP("bcdctn. v%d,v%d\n", vRT_addr, vRB_addr);
27180 value = binop( Iop_And64,
27181 mkU64( 0xFFFFFFFF ),
27182 unop( Iop_V128to64, mkexpr( vB ) ) );
27184 /* A valid number must have a value that is less then or
27185 * equal to 10^7 - 1. This is checked by making sure
27186 * bytes [31:8] of vB are zero.
27188 in_range = mkAND1( binop( Iop_CmpEQ64,
27189 unop( Iop_V128HIto64, mkexpr( vB ) ),
27190 mkU64( 0 ) ),
27191 binop( Iop_CmpEQ64,
27192 binop( Iop_Shr64,
27193 unop( Iop_V128to64,
27194 mkexpr( vB ) ),
27195 mkU8( 32 ) ),
27196 mkU64( 0 ) ) );
27198 /* The sign code must be between 0xA and 0xF and all digits are
27199 * between 0x0 and 0x9.
27201 valid =
27202 unop( Iop_64to32,
27203 is_BCDstring128( vbi, /* Signed */True,
27204 mkexpr( vB ) ) );
27206 /* Upper 24 hex digits of VB, i.e. hex ditgits vB[0:23],
27207 * must be zero for the ox_flag to be zero. This goes
27208 * in the LSB position (variable overflow) of the
27209 * condition code register.
27211 ox_flag =
27212 mkNOT1( mkAND1( binop( Iop_CmpEQ64,
27213 binop( Iop_And64,
27214 unop( Iop_V128HIto64,
27215 mkexpr( vB ) ),
27216 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
27217 mkU64( 0 ) ),
27218 binop( Iop_CmpEQ64,
27219 binop( Iop_And64,
27220 unop( Iop_V128to64,
27221 mkexpr( vB ) ),
27222 mkU64( 0xFFFFFFFF00000000 ) ),
27223 mkU64( 0 ) ) ) );
27225 /* Set zero to 1 if all of the bytes in vB are zero. This is
27226 * used when setting the lt_flag (variable neg) and the gt_flag
27227 * (variable pos).
27229 zero = mkAND1( binop( Iop_CmpEQ64,
27230 binop( Iop_And64,
27231 unop( Iop_V128HIto64,
27232 mkexpr( vB ) ),
27233 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
27234 mkU64( 0 ) ),
27235 binop( Iop_CmpEQ64,
27236 binop( Iop_And64,
27237 unop( Iop_V128to64, mkexpr( vB ) ),
27238 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
27239 mkU64( 0 ) ) );
27241 /* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
27242 * codes 0xB and 0xD are negative.
27244 sign_digit = binop( Iop_And64, mkU64( 0xF ), value );
27246 /* The negative value goes in the LT bit position of the
27247 * condition code register. Set neg if the sign of the
27248 * value is negative and the value is zero.
27250 sign = mkOR1( binop( Iop_CmpEQ64,
27251 sign_digit,
27252 mkU64 ( 0xB ) ),
27253 binop( Iop_CmpEQ64,
27254 sign_digit,
27255 mkU64 ( 0xD ) ) );
27256 neg = mkAND1( sign, mkNOT1( zero ) );
27258 /* The positive value goes in the LT bit position of the
27259 * condition code register. Set neg if the sign of the
27260 * value is not negative and the value is zero.
27262 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
27264 assign( tmp,
27265 convert_to_national( vbi, mkexpr( vB ) ) );
27267 /* If vB is positive insert sign value 0x002B, otherwise
27268 * insert 0x002D for negative. Have to use sign not neg
27269 * because neg has been ANDed with zero. This is 0x29
27270 * OR'd with (sign << 1 | NOT sign) << 1.
27271 * sign = 1 if vB is negative.
27273 putVReg( vRT_addr,
27274 binop( Iop_OrV128,
27275 mkexpr( tmp ),
27276 binop( Iop_64HLtoV128,
27277 mkU64( 0 ),
27278 binop( Iop_Or64,
27279 mkU64( 0x29 ),
27280 binop( Iop_Or64,
27281 binop( Iop_Shl64,
27282 unop( Iop_1Uto64,
27283 sign ),
27284 mkU8( 2 ) ),
27285 binop( Iop_Shl64,
27286 unop( Iop_1Uto64,
27287 mkNOT1(sign)),
27288 mkU8( 1 ) )
27289 ) ) ) ) );
27292 /* The sign code must be between 0xA and 0xF and all digits are
27293 * between 0x0 and 0x9. The vB must be in range to be valid.
27295 valid =
27296 unop( Iop_64to32,
27297 is_BCDstring128( vbi, /* Signed */True,
27298 mkexpr( vB ) ) );
27300 overflow = ox_flag;
27302 break;
27304 case 6: // bcdcfz. (Decimal Convert From Zoned VX-form)
27306 IRExpr *sign;
27307 IRTemp tmp = newTemp( Ity_V128 );;
27309 DIP("bcdcfz. v%d,v%d,%d\n", vRT_addr, vRB_addr, ps);
27311 valid = unop( Iop_1Uto32, is_Zoned_decimal( vB, ps ) );
27313 assign( tmp,
27314 convert_from_zoned( vbi, mkexpr( vB ) ) );
27316 /* If the result of checking the lower 4 bits of each 8-bit
27317 * value is zero, then the "number" was zero.
27319 zero =
27320 binop( Iop_CmpEQ64,
27321 binop( Iop_Or64,
27322 binop( Iop_And64,
27323 unop( Iop_V128to64, mkexpr( vB ) ),
27324 mkU64( 0x0F0F0F0F0F0F0F0FULL ) ),
27325 binop( Iop_And64,
27326 unop( Iop_V128to64, mkexpr( vB ) ),
27327 mkU64( 0x0F0F0F0F0F0F0F0FULL ) ) ),
27328 mkU64( 0 ) );
27330 /* Sign bit is in bit 6 of vB. */
27331 sign_digit = binop( Iop_And64, mkU64( 0xF0 ),
27332 unop( Iop_V128to64, mkexpr( vB ) ) );
27334 if ( ps == 0 ) {
27335 /* sign will be equal to 0 for positive number */
27336 sign = binop( Iop_CmpEQ64,
27337 binop( Iop_And64,
27338 sign_digit,
27339 mkU64( 0x40 ) ),
27340 mkU64( 0x40 ) );
27341 } else {
27342 sign = mkOR1(
27343 binop( Iop_CmpEQ64, sign_digit, mkU64( 0xB0 ) ),
27344 binop( Iop_CmpEQ64, sign_digit, mkU64( 0xD0 ) ) );
27347 /* The negative value goes in the LT bit position of the
27348 * condition code register. Set neg if the sign of the
27349 * value is negative and the value is zero.
27351 neg = mkAND1( sign, mkNOT1( zero ) );
27353 /* The positive value goes in the GT bit position of the
27354 * condition code register. Set neg if the sign of the
27355 * value is not negative and the value is zero.
27357 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
27359 /* sign of the result is 0xC for positive, 0xD for negative */
27360 putVReg( vRT_addr,
27361 binop( Iop_OrV128,
27362 mkexpr( tmp ),
27363 binop( Iop_64HLtoV128,
27364 mkU64( 0 ),
27365 binop( Iop_Or64,
27366 mkU64( 0xC ),
27367 unop( Iop_1Uto64, sign )
27368 ) ) ) );
27369 /* For this instructions the LSB position in the CC
27370 * field, the overflow position in the other instructions,
27371 * is given by 0. There is nothing to or with LT, EQ or GT.
27373 overflow = mkU1( 0 );
27375 break;
27377 case 7: // bcdcfn. (Decimal Convert From National VX-form)
27379 IRTemp hword_7 = newTemp( Ity_I64 );
27380 IRExpr *sign;
27381 IRTemp tmp = newTemp( Ity_I64 );;
27383 DIP("bcdcfn. v%d,v%d,%d\n", vRT_addr, vRB_addr, ps);
27385 /* check that the value is valid */
27386 valid = unop( Iop_1Uto32, is_National_decimal( vB ) );
27388 assign( hword_7, binop( Iop_And64,
27389 unop( Iop_V128to64, mkexpr( vB ) ),
27390 mkU64( 0xFFF ) ) );
27391 /* sign = 1 if vB is negative */
27392 sign = binop( Iop_CmpEQ64, mkexpr( hword_7 ), mkU64( 0x002D ) );
27394 assign( tmp, convert_from_national( vbi, mkexpr( vB ) ) );
27396 /* If the result of checking the lower 4 bits of each 16-bit
27397 * value is zero, then the "number" was zero.
27399 zero =
27400 binop( Iop_CmpEQ64,
27401 binop( Iop_Or64,
27402 binop( Iop_And64,
27403 unop( Iop_V128HIto64, mkexpr( vB ) ),
27404 mkU64( 0x000F000F000F000FULL ) ),
27405 binop( Iop_And64,
27406 unop( Iop_V128to64, mkexpr( vB ) ),
27407 mkU64( 0x000F000F000F0000ULL ) ) ),
27408 mkU64( 0 ) );
27411 /* The negative value goes in the LT bit position of the
27412 * condition code register. Set neg if the sign of the
27413 * value is negative and the value is zero.
27415 neg = mkAND1( sign, mkNOT1( zero ) );
27417 /* The positive value goes in the GT bit position of the
27418 * condition code register. Set neg if the sign of the
27419 * value is not negative and the value is zero.
27421 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
27423 /* For this instructions the LSB position in the CC
27424 * field, the overflow position in the other instructions,
27425 * is given by invalid. There is nothing to OR with the valid
27426 * flag.
27428 overflow = mkU1( 0 );
27430 /* sign of the result is:
27431 ( 0b1100 OR neg) OR (ps OR (ps AND pos) << 1 )
27434 putVReg( vRT_addr,
27435 binop( Iop_64HLtoV128,
27436 mkU64( 0 ),
27437 binop( Iop_Or64,
27438 binop( Iop_Or64,
27439 binop( Iop_Shl64,
27440 binop( Iop_And64,
27441 mkU64( ps ),
27442 unop( Iop_1Uto64,
27443 mkNOT1(sign))),
27444 mkU8( 1 ) ),
27445 mkU64( ps ) ),
27446 binop( Iop_Or64,
27447 binop( Iop_Or64,
27448 mkU64( 0xC ),
27449 unop( Iop_1Uto64, sign ) ),
27450 mkexpr( tmp ) ) ) ) );
27453 break;
27455 case 31: // bcdsetsgn. (BCD set sign)
27457 IRExpr *new_sign_val, *sign;
27459 DIP("bcdsetsgn. v%d,v%d,%d\n", vRT_addr, vRB_addr, ps);
27461 value = binop( Iop_AndV128,
27462 binop( Iop_64HLtoV128,
27463 mkU64( 0xFFFFFFFFFFFFFFFF ),
27464 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
27465 mkexpr( vB ) );
27466 zero = BCDstring_zero( value );
27468 /* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
27469 * codes 0xB and 0xD are negative.
27471 sign_digit = binop( Iop_And64, mkU64( 0xF ),
27472 unop( Iop_V128to64, mkexpr( vB ) ) );
27474 sign = mkOR1( binop( Iop_CmpEQ64,
27475 sign_digit,
27476 mkU64 ( 0xB ) ),
27477 binop( Iop_CmpEQ64,
27478 sign_digit,
27479 mkU64 ( 0xD ) ) );
27480 neg = mkAND1( sign, mkNOT1( zero ) );
27482 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
27484 valid =
27485 unop( Iop_64to32,
27486 is_BCDstring128( vbi, /* Signed */True,
27487 mkexpr( vB ) ) );
27489 /* if PS = 0
27490 vB positive, sign is C
27491 vB negative, sign is D
27492 if PS = 1
27493 vB positive, sign is F
27494 vB negative, sign is D
27495 Note can't use pos or neg here since they are ANDed with
27496 zero, use sign instead.
27498 if (ps == 0) {
27499 new_sign_val = binop( Iop_Or64,
27500 unop( Iop_1Uto64, sign ),
27501 mkU64( 0xC ) );
27503 } else {
27504 new_sign_val = binop( Iop_Xor64,
27505 binop( Iop_Shl64,
27506 unop( Iop_1Uto64, sign ),
27507 mkU8( 1 ) ),
27508 mkU64( 0xF ) );
27511 putVReg( vRT_addr, binop( Iop_OrV128,
27512 binop( Iop_64HLtoV128,
27513 mkU64( 0 ),
27514 new_sign_val ),
27515 value ) );
27516 /* For this instructions the LSB position in the CC
27517 * field, the overflow position in the other instructions,
27518 * is given by invalid.
27520 overflow = unop( Iop_32to1, unop( Iop_Not32, valid ) );
27522 break;
27524 default:
27525 vex_printf("dis_av_bcd(ppc)(invalid inst_select)\n");
27526 return False;
27529 break;
27531 default:
27532 vex_printf("dis_av_bcd(ppc)(opc2)\n");
27533 return False;
27536 IRTemp valid_mask = newTemp( Ity_I32 );
27538 assign( valid_mask, unop( Iop_1Sto32, unop( Iop_32to1, valid ) ) );
27540 /* set CR field 6 to:
27541 * 0b1000 if vB less then 0, i.e. vB is neg and not zero,
27542 * 0b0100 if vB greter then 0, i.e. vB is pos and not zero,
27543 * 0b0010 if vB equals 0,
27544 * 0b0001 if vB is invalid over rules lt, gt, eq
27546 assign( eq_lt_gt,
27547 binop( Iop_Or32,
27548 binop( Iop_Shl32,
27549 unop( Iop_1Uto32, neg ),
27550 mkU8( 3 ) ),
27551 binop( Iop_Or32,
27552 binop( Iop_Shl32,
27553 unop( Iop_1Uto32, pos ),
27554 mkU8( 2 ) ),
27555 binop( Iop_Shl32,
27556 unop( Iop_1Uto32, zero ),
27557 mkU8( 1 ) ) ) ) );
27558 /* valid is 1 if it is a valid number, complement and put in the
27559 * invalid bit location, overriding ls, eq, gt, overflow.
27561 putGST_field( PPC_GST_CR,
27562 binop( Iop_Or32,
27563 binop( Iop_And32,
27564 mkexpr( valid_mask ),
27565 binop( Iop_Or32,
27566 mkexpr( eq_lt_gt ),
27567 unop( Iop_1Uto32, overflow ) ) ),
27568 binop( Iop_And32,
27569 unop( Iop_Not32, mkexpr( valid_mask ) ),
27570 mkU32( 1 ) ) ),
27571 6 );
27572 return True;
27576 AltiVec Floating Point Arithmetic Instructions
27578 static Bool dis_av_fp_arith ( UInt theInstr )
27580 /* VA-Form */
27581 UChar opc1 = ifieldOPC(theInstr);
27582 UChar vD_addr = ifieldRegDS(theInstr);
27583 UChar vA_addr = ifieldRegA(theInstr);
27584 UChar vB_addr = ifieldRegB(theInstr);
27585 UChar vC_addr = ifieldRegC(theInstr);
27586 UInt opc2=0;
27588 IRTemp vA = newTemp(Ity_V128);
27589 IRTemp vB = newTemp(Ity_V128);
27590 IRTemp vC = newTemp(Ity_V128);
27591 assign( vA, getVReg(vA_addr));
27592 assign( vB, getVReg(vB_addr));
27593 assign( vC, getVReg(vC_addr));
27595 if (opc1 != 0x4) {
27596 vex_printf("dis_av_fp_arith(ppc)(instr)\n");
27597 return False;
27600 IRTemp rm = newTemp(Ity_I32);
27601 assign(rm, get_IR_roundingmode());
27603 opc2 = IFIELD( theInstr, 0, 6 );
27604 switch (opc2) {
27605 case 0x2E: // vmaddfp (Multiply Add FP, AV p177)
27606 DIP("vmaddfp v%d,v%d,v%d,v%d\n",
27607 vD_addr, vA_addr, vC_addr, vB_addr);
27608 putVReg( vD_addr,
27609 dnorm_adj_Vector(
27610 triop( Iop_Add32Fx4,
27611 mkU32( Irrm_NEAREST ),
27612 dnorm_adj_Vector( mkexpr( vB ) ),
27613 dnorm_adj_Vector( triop( Iop_Mul32Fx4,
27614 mkU32( Irrm_NEAREST ),
27615 dnorm_adj_Vector( mkexpr( vA ) ),
27616 dnorm_adj_Vector( mkexpr( vC ) ) )
27617 ) ) ) );
27618 return True;
27620 case 0x2F: { // vnmsubfp (Negative Multiply-Subtract FP, AV p215)
27621 DIP("vnmsubfp v%d,v%d,v%d,v%d\n",
27622 vD_addr, vA_addr, vC_addr, vB_addr);
27623 putVReg( vD_addr,
27624 negate_Vector( Ity_I32,
27625 dnorm_adj_Vector(
27626 triop( Iop_Sub32Fx4,
27627 mkU32( Irrm_NEAREST ),
27628 dnorm_adj_Vector(
27629 triop( Iop_Mul32Fx4,
27630 mkU32( Irrm_NEAREST ),
27631 dnorm_adj_Vector( mkexpr( vA ) ),
27632 dnorm_adj_Vector( mkexpr( vC ) ) ) ),
27633 dnorm_adj_Vector( mkexpr( vB ) ) ) ) ) );
27634 return True;
27637 default:
27638 break; // Fall through...
27641 opc2 = IFIELD( theInstr, 0, 11 );
27642 switch (opc2) {
27643 case 0x00A: // vaddfp (Add FP, AV p137)
27644 DIP("vaddfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
27645 putVReg( vD_addr,
27646 dnorm_adj_Vector( triop( Iop_Add32Fx4, mkU32( Irrm_NEAREST ),
27647 dnorm_adj_Vector( mkexpr( vA ) ),
27648 dnorm_adj_Vector( mkexpr( vB ) ) ) ) );
27649 return True;
27651 case 0x04A: // vsubfp (Subtract FP, AV p261)
27652 DIP("vsubfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
27653 putVReg( vD_addr,
27654 dnorm_adj_Vector( triop( Iop_Sub32Fx4, mkU32( Irrm_NEAREST ),
27655 dnorm_adj_Vector( mkexpr( vA ) ),
27656 dnorm_adj_Vector( mkexpr( vB ) ) ) ) );
27657 return True;
27659 case 0x40A: // vmaxfp (Maximum FP, AV p178)
27660 DIP("vmaxfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
27661 putVReg( vD_addr,
27662 dnorm_adj_Vector( binop( Iop_Max32Fx4,
27663 mkexpr( vA ), mkexpr( vB ) ) ) );
27664 return True;
27666 case 0x44A: // vminfp (Minimum FP, AV p187)
27667 DIP("vminfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
27668 putVReg( vD_addr,
27669 dnorm_adj_Vector( binop( Iop_Min32Fx4,
27670 mkexpr( vA ), mkexpr( vB ) ) ) );
27671 return True;
27673 default:
27674 break; // Fall through...
27678 if (vA_addr != 0) {
27679 vex_printf("dis_av_fp_arith(ppc)(vA_addr)\n");
27680 return False;
27683 switch (opc2) {
27684 case 0x10A: // vrefp (Reciprocal Esimate FP, AV p228)
27685 DIP("vrefp v%d,v%d\n", vD_addr, vB_addr);
27686 putVReg( vD_addr, dnorm_adj_Vector( unop( Iop_RecipEst32Fx4,
27687 dnorm_adj_Vector( mkexpr( vB ) ) ) ) );
27688 return True;
27690 case 0x14A: // vrsqrtefp (Reciprocal Sqrt Estimate FP, AV p237)
27691 DIP("vrsqrtefp v%d,v%d\n", vD_addr, vB_addr);
27692 putVReg( vD_addr, dnorm_adj_Vector( unop( Iop_RSqrtEst32Fx4,
27693 dnorm_adj_Vector( mkexpr( vB ) ) ) ) );
27694 return True;
27696 case 0x18A: // vexptefp (2 Raised to the Exp Est FP, AV p173)
27697 DIP("vexptefp v%d,v%d\n", vD_addr, vB_addr);
27698 /* NOTE, need to address dnormalized value handling when this is
27699 implemented. */
27700 putVReg( vD_addr,
27701 dnorm_adj_Vector( unop( Iop_Exp2_32Fx4,
27702 dnorm_adj_Vector( mkexpr( vB ) ) ) ) );
27703 return True;
27705 case 0x1CA: // vlogefp (Log2 Estimate FP, AV p175)
27706 DIP("vlogefp v%d,v%d\n", vD_addr, vB_addr);
27707 /* NOTE, need to address dnormalized value handling when this is
27708 implemented. */
27709 putVReg( vD_addr,
27710 dnorm_adj_Vector( unop( Iop_Log2_32Fx4,
27711 dnorm_adj_Vector( mkexpr( vB ) ) ) ) );
27712 return True;
27714 default:
27715 vex_printf("dis_av_fp_arith(ppc)(opc2=0x%x)\n",opc2);
27716 return False;
27718 return True;
27722 AltiVec Floating Point Compare Instructions
27724 static Bool dis_av_fp_cmp ( UInt theInstr )
27726 /* VXR-Form */
27727 UChar opc1 = ifieldOPC(theInstr);
27728 UChar vD_addr = ifieldRegDS(theInstr);
27729 UChar vA_addr = ifieldRegA(theInstr);
27730 UChar vB_addr = ifieldRegB(theInstr);
27731 UChar flag_rC = ifieldBIT10(theInstr);
27732 UInt opc2 = IFIELD( theInstr, 0, 10 );
27734 Bool cmp_bounds = False;
27736 IRTemp vA = newTemp(Ity_V128);
27737 IRTemp vB = newTemp(Ity_V128);
27738 IRTemp vD = newTemp(Ity_V128);
27739 assign( vA, getVReg(vA_addr));
27740 assign( vB, getVReg(vB_addr));
27742 if (opc1 != 0x4) {
27743 vex_printf("dis_av_fp_cmp(ppc)(instr)\n");
27744 return False;
27747 switch (opc2) {
27748 case 0x0C6: // vcmpeqfp (Compare Equal-to FP, AV p159)
27749 DIP("vcmpeqfp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
27750 vD_addr, vA_addr, vB_addr);
27751 assign( vD, binop( Iop_CmpEQ32Fx4,
27752 dnorm_adj_Vector( mkexpr( vA ) ),
27753 dnorm_adj_Vector( mkexpr( vB ) ) ) );
27754 break;
27756 case 0x1C6: // vcmpgefp (Compare Greater-than-or-Equal-to, AV p163)
27757 DIP("vcmpgefp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
27758 vD_addr, vA_addr, vB_addr);
27759 assign( vD, binop( Iop_CmpGE32Fx4,
27760 dnorm_adj_Vector( mkexpr( vA ) ),
27761 dnorm_adj_Vector( mkexpr( vB ) ) ) );
27762 break;
27764 case 0x2C6: // vcmpgtfp (Compare Greater-than FP, AV p164)
27765 DIP("vcmpgtfp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
27766 vD_addr, vA_addr, vB_addr);
27767 assign( vD, binop( Iop_CmpGT32Fx4,
27768 dnorm_adj_Vector( mkexpr( vA ) ),
27769 dnorm_adj_Vector( mkexpr( vB ) ) ) );
27770 break;
27772 case 0x3C6: { // vcmpbfp (Compare Bounds FP, AV p157)
27773 IRTemp gt = newTemp(Ity_V128);
27774 IRTemp lt = newTemp(Ity_V128);
27775 IRTemp zeros = newTemp(Ity_V128);
27776 IRTemp srcA = newTemp(Ity_V128);
27777 IRTemp srcB = newTemp(Ity_V128);
27779 DIP("vcmpbfp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
27780 vD_addr, vA_addr, vB_addr);
27781 cmp_bounds = True;
27782 assign( zeros, unop(Iop_Dup32x4, mkU32(0)) );
27784 /* Note: making use of fact that the ppc backend for compare insns
27785 return zero'd lanes if either of the corresponding arg lanes is
27786 a nan.
27788 Perhaps better to have an irop Iop_isNan32Fx4, but then we'd
27789 need this for the other compares too (vcmpeqfp etc)...
27790 Better still, tighten down the spec for compare irops.
27792 assign ( srcA, dnorm_adj_Vector( mkexpr( vA ) ) );
27793 assign ( srcB, dnorm_adj_Vector( mkexpr( vB ) ) );
27795 assign( gt, unop( Iop_NotV128,
27796 binop( Iop_CmpLE32Fx4, mkexpr( srcA ),
27797 mkexpr( srcB ) ) ) );
27798 assign( lt, unop( Iop_NotV128,
27799 binop( Iop_CmpGE32Fx4, mkexpr( srcA ),
27800 triop( Iop_Sub32Fx4, mkU32( Irrm_NEAREST ),
27801 mkexpr( zeros ),
27802 mkexpr( srcB ) ) ) ) );
27804 // finally, just shift gt,lt to correct position
27805 assign( vD, binop(Iop_ShlN32x4,
27806 binop(Iop_OrV128,
27807 binop(Iop_AndV128, mkexpr(gt),
27808 unop(Iop_Dup32x4, mkU32(0x2))),
27809 binop(Iop_AndV128, mkexpr(lt),
27810 unop(Iop_Dup32x4, mkU32(0x1)))),
27811 mkU8(30)) );
27812 break;
27815 default:
27816 vex_printf("dis_av_fp_cmp(ppc)(opc2)\n");
27817 return False;
27820 putVReg( vD_addr, mkexpr(vD) );
27822 if (flag_rC) {
27823 set_AV_CR6( mkexpr(vD), !cmp_bounds );
27825 return True;
27829 AltiVec Floating Point Convert/Round Instructions
27831 static Bool dis_av_fp_convert ( UInt theInstr )
27833 /* VX-Form */
27834 UChar opc1 = ifieldOPC(theInstr);
27835 UChar vD_addr = ifieldRegDS(theInstr);
27836 UChar UIMM_5 = ifieldRegA(theInstr);
27837 UChar vB_addr = ifieldRegB(theInstr);
27838 UInt opc2 = IFIELD( theInstr, 0, 11 );
27840 IRTemp vB = newTemp(Ity_V128);
27841 IRTemp vScale = newTemp(Ity_V128);
27842 IRTemp vInvScale = newTemp(Ity_V128);
27844 float scale, inv_scale;
27846 assign( vB, getVReg(vB_addr));
27848 /* scale = 2^UIMM, cast to float, reinterpreted as uint */
27849 scale = (float)( (unsigned int) 1<<UIMM_5 );
27850 assign( vScale, unop(Iop_Dup32x4, mkU32( float_to_bits(scale) )) );
27851 inv_scale = 1/scale;
27852 assign( vInvScale,
27853 unop(Iop_Dup32x4, mkU32( float_to_bits(inv_scale) )) );
27855 if (opc1 != 0x4) {
27856 vex_printf("dis_av_fp_convert(ppc)(instr)\n");
27857 return False;
27860 switch (opc2) {
27861 case 0x30A: // vcfux (Convert from Unsigned Fixed-Point W, AV p156)
27862 DIP("vcfux v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
27863 putVReg( vD_addr, triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
27864 unop(Iop_I32UtoF32x4_DEP, mkexpr(vB)),
27865 mkexpr(vInvScale)) );
27866 return True;
27868 case 0x34A: // vcfsx (Convert from Signed Fixed-Point W, AV p155)
27869 DIP("vcfsx v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
27871 putVReg( vD_addr, triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
27872 unop(Iop_I32StoF32x4_DEP, mkexpr(vB)),
27873 mkexpr(vInvScale)) );
27874 return True;
27876 case 0x38A: // vctuxs (Convert to Unsigned Fixed-Point W Saturate, AV p172)
27877 DIP("vctuxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
27878 putVReg( vD_addr,
27879 unop(Iop_QF32toI32Ux4_RZ,
27880 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
27881 mkexpr(vB), mkexpr(vScale))) );
27882 return True;
27884 case 0x3CA: // vctsxs (Convert to Signed Fixed-Point W Saturate, AV p171)
27885 DIP("vctsxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
27886 putVReg( vD_addr,
27887 unop(Iop_QF32toI32Sx4_RZ,
27888 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
27889 mkexpr(vB), mkexpr(vScale))) );
27890 return True;
27892 default:
27893 break; // Fall through...
27896 if (UIMM_5 != 0) {
27897 vex_printf("dis_av_fp_convert(ppc)(UIMM_5)\n");
27898 return False;
27901 switch (opc2) {
27902 case 0x20A: // vrfin (Round to FP Integer Nearest, AV p231)
27903 DIP("vrfin v%d,v%d\n", vD_addr, vB_addr);
27904 putVReg( vD_addr, unop(Iop_RoundF32x4_RN,
27905 dnorm_adj_Vector( mkexpr( vB ) ) ) );
27906 break;
27908 case 0x24A: // vrfiz (Round to FP Integer toward zero, AV p233)
27909 DIP("vrfiz v%d,v%d\n", vD_addr, vB_addr);
27910 putVReg( vD_addr, unop(Iop_RoundF32x4_RZ,
27911 dnorm_adj_Vector( mkexpr( vB ) ) ) );
27912 break;
27914 case 0x28A: // vrfip (Round to FP Integer toward +inf, AV p232)
27915 DIP("vrfip v%d,v%d\n", vD_addr, vB_addr);
27916 putVReg( vD_addr, unop(Iop_RoundF32x4_RP,
27917 dnorm_adj_Vector( mkexpr( vB ) ) ) );
27918 break;
27920 case 0x2CA: // vrfim (Round to FP Integer toward -inf, AV p230)
27921 DIP("vrfim v%d,v%d\n", vD_addr, vB_addr);
27922 putVReg( vD_addr, unop(Iop_RoundF32x4_RM,
27923 dnorm_adj_Vector( mkexpr(vB ) ) ) );
27924 break;
27926 default:
27927 vex_printf("dis_av_fp_convert(ppc)(opc2)\n");
27928 return False;
27930 return True;
27933 static Bool dis_transactional_memory ( UInt theInstr, UInt nextInstr,
27934 const VexAbiInfo* vbi,
27935 /*OUT*/DisResult* dres )
27937 UInt opc2 = IFIELD( theInstr, 1, 10 );
27939 switch (opc2) {
27940 case 0x28E: { //tbegin.
27941 /* The current implementation is to just fail the tbegin and execute
27942 * the failure path. The failure path is assumed to be functionaly
27943 * equivalent to the transactional path with the needed data locking
27944 * to ensure correctness. The tend is just a noop and shouldn't
27945 * actually get executed.
27946 * 1) set cr0 to 0x2
27947 * 2) Initialize TFHAR to CIA+4
27948 * 3) Initialize TEXASR
27949 * 4) Initialize TFIAR (probably to CIA, ie, the address of tbegin.)
27950 * 5) Continue executing at the next instruction.
27952 UInt R = IFIELD( theInstr, 21, 1 );
27954 ULong tm_reason;
27955 UInt failure_code = 0; /* Forcing failure, will not be due to tabort
27956 * or treclaim.
27958 UInt persistant = 1; /* set persistant since we are always failing
27959 * the tbegin.
27961 UInt nest_overflow = 1; /* Alowed nesting depth overflow, we use this
27962 as the reason for failing the trasaction */
27963 UInt tm_exact = 1; /* have exact address for failure */
27965 DIP("tbegin. %u\n", R);
27967 /* Set the CR0 field to indicate the tbegin failed. Then let
27968 * the code do the branch to the failure path.
27970 * 000 || 0 Transaction initiation successful,
27971 * unnested (Transaction state of
27972 * Non-transactional prior to tbegin.)
27973 * 010 || 0 Transaction initiation successful, nested
27974 * (Transaction state of Transactional
27975 * prior to tbegin.)
27976 * 001 || 0 Transaction initiation unsuccessful,
27977 * (Transaction state of Suspended prior
27978 * to tbegin.)
27980 putCR321( 0, mkU8( 0x2 ) );
27982 tm_reason = generate_TMreason( failure_code, persistant,
27983 nest_overflow, tm_exact );
27985 storeTMfailure( guest_CIA_curr_instr, tm_reason,
27986 guest_CIA_curr_instr+4 );
27988 return True;
27990 break;
27993 case 0x2AE: { //tend.
27994 /* The tend. is just a noop. Do nothing */
27995 UInt A = IFIELD( theInstr, 25, 1 );
27997 DIP("tend. %u\n", A);
27998 break;
28001 case 0x2EE: { //tsr.
28002 /* The tsr. is just a noop. Do nothing */
28003 UInt L = IFIELD( theInstr, 21, 1 );
28005 DIP("tsr. %u\n", L);
28006 break;
28009 case 0x2CE: { //tcheck.
28010 /* The tcheck. is just a noop. Do nothing */
28011 UInt BF = IFIELD( theInstr, 25, 1 );
28013 DIP("tcheck. %u\n", BF);
28014 break;
28017 case 0x30E: { //tbortwc.
28018 /* The tabortwc. is just a noop. Do nothing */
28019 UInt TO = IFIELD( theInstr, 25, 1 );
28020 UInt RA = IFIELD( theInstr, 16, 5 );
28021 UInt RB = IFIELD( theInstr, 11, 5 );
28023 DIP("tabortwc. %u,%u,%u\n", TO, RA, RB);
28024 break;
28027 case 0x32E: { //tbortdc.
28028 /* The tabortdc. is just a noop. Do nothing */
28029 UInt TO = IFIELD( theInstr, 25, 1 );
28030 UInt RA = IFIELD( theInstr, 16, 5 );
28031 UInt RB = IFIELD( theInstr, 11, 5 );
28033 DIP("tabortdc. %u,%u,%u\n", TO, RA, RB);
28034 break;
28037 case 0x34E: { //tbortwci.
28038 /* The tabortwci. is just a noop. Do nothing */
28039 UInt TO = IFIELD( theInstr, 25, 1 );
28040 UInt RA = IFIELD( theInstr, 16, 5 );
28041 UInt SI = IFIELD( theInstr, 11, 5 );
28043 DIP("tabortwci. %u,%u,%u\n", TO, RA, SI);
28044 break;
28047 case 0x36E: { //tbortdci.
28048 /* The tabortdci. is just a noop. Do nothing */
28049 UInt TO = IFIELD( theInstr, 25, 1 );
28050 UInt RA = IFIELD( theInstr, 16, 5 );
28051 UInt SI = IFIELD( theInstr, 11, 5 );
28053 DIP("tabortdci. %u,%u,%u\n", TO, RA, SI);
28054 break;
28057 case 0x38E: { //tbort.
28058 /* The tabort. is just a noop. Do nothing */
28059 UInt RA = IFIELD( theInstr, 16, 5 );
28061 DIP("tabort. %u\n", RA);
28062 break;
28065 case 0x3AE: { //treclaim.
28066 /* The treclaim. is just a noop. Do nothing */
28067 UInt RA = IFIELD( theInstr, 16, 5 );
28069 DIP("treclaim. %u\n", RA);
28070 break;
28073 case 0x3EE: { //trechkpt.
28074 /* The trechkpt. is just a noop. Do nothing */
28075 DIP("trechkpt.\n");
28076 break;
28079 default:
28080 vex_printf("dis_transactional_memory(ppc): unrecognized instruction\n");
28081 return False;
28084 return True;
28088 /* The 0x3C primary opcode (VSX category) uses several different forms of
28089 * extended opcodes:
28090 * o XX2-form:
28091 * - [10:2] (IBM notation [21:29])
28092 * o XX3-form variants:
28093 * - variant 1: [10:3] (IBM notation [21:28])
28094 * - variant 2: [9:3] (IBM notation [22:28])
28095 * - variant 3: [7:3] (IBM notation [24:28])
28096 * o XX-4 form:
28097 * - [10:6] (IBM notation [21:25])
28099 * The XX2-form needs bit 0 masked from the standard extended opcode
28100 * as returned by ifieldOPClo10; the XX3-form needs bits 0 and 1 masked;
28101 * and the XX4-form needs bits 0, 1, and 2 masked. Additionally, the
28102 * XX4 and XX3 (variants 2 and 3) forms need certain bits masked on the
28103 * front end since their encoding does not begin at bit 21 like the standard
28104 * format.
28106 * The get_VSX60_opc2() function uses the vsx_insn array below to obtain the
28107 * secondary opcode for such VSX instructions.
28112 struct vsx_insn {
28113 UInt opcode;
28114 const HChar * name;
28117 // ATTENTION: Keep this array sorted on the opcocde!!!
28118 static struct vsx_insn vsx_xx2[] = {
28119 { 0x14, "xsrsqrtesp" },
28120 { 0x16, "xssqrtsp" },
28121 { 0x18, "xxsel" },
28122 { 0x34, "xsresp" },
28123 { 0x90, "xscvdpuxws" },
28124 { 0x92, "xsrdpi" },
28125 { 0x94, "xsrsqrtedp" },
28126 { 0x96, "xssqrtdp" },
28127 { 0xb0, "xscvdpsxws" },
28128 { 0xb2, "xsrdpiz" },
28129 { 0xb4, "xsredp" },
28130 { 0xd2, "xsrdpip" },
28131 { 0xd4, "xstsqrtdp" },
28132 { 0xd6, "xsrdpic" },
28133 { 0xf2, "xsrdpim" },
28134 { 0x112, "xvrspi" },
28135 { 0x116, "xvsqrtsp" },
28136 { 0x130, "xvcvspsxws" },
28137 { 0x132, "xvrspiz" },
28138 { 0x134, "xvresp" },
28139 { 0x148, "xxspltw" },
28140 { 0x14A, "xxextractuw" },
28141 { 0x150, "xvcvuxwsp" },
28142 { 0x152, "xvrspip" },
28143 { 0x154, "xvtsqrtsp" },
28144 { 0x156, "xvrspic" },
28145 { 0x16A, "xxinsertw" },
28146 { 0x170, "xvcvsxwsp" },
28147 { 0x172, "xvrspim" },
28148 { 0x190, "xvcvdpuxws" },
28149 { 0x192, "xvrdpi" },
28150 { 0x194, "xvrsqrtedp" },
28151 { 0x196, "xvsqrtdp" },
28152 { 0x1b0, "xvcvdpsxws" },
28153 { 0x1b2, "xvrdpiz" },
28154 { 0x1b4, "xvredp" },
28155 { 0x1d0, "xvcvuxwdp" },
28156 { 0x1d2, "xvrdpip" },
28157 { 0x1d4, "xvtsqrtdp" },
28158 { 0x1d6, "xvrdpic" },
28159 { 0x1f0, "xvcvsxwdp" },
28160 { 0x1f2, "xvrdpim" },
28161 { 0x212, "xscvdpsp" },
28162 { 0x216, "xscvdpspn" },
28163 { 0x232, "xxrsp" },
28164 { 0x250, "xscvuxdsp" },
28165 { 0x254, "xststdcsp" },
28166 { 0x270, "xscvsxdsp" },
28167 { 0x290, "xscvdpuxds" },
28168 { 0x292, "xscvspdp" },
28169 { 0x296, "xscvspdpn" },
28170 { 0x2b0, "xscvdpsxds" },
28171 { 0x2b2, "xsabsdp" },
28172 { 0x2b6, "xsxexpdp_xsxigdp" },
28173 { 0x2d0, "xscvuxddp" },
28174 { 0x2d2, "xsnabsdp" },
28175 { 0x2d4, "xststdcdp" },
28176 { 0x2e4, "xsnmsubmdp" },
28177 { 0x2f0, "xscvsxddp" },
28178 { 0x2f2, "xsnegdp" },
28179 { 0x310, "xvcvspuxds" },
28180 { 0x312, "xvcvdpsp" },
28181 { 0x330, "xvcvspsxds" },
28182 { 0x332, "xvabssp" },
28183 { 0x350, "xvcvuxdsp" },
28184 { 0x352, "xvnabssp" },
28185 { 0x370, "xvcvsxdsp" },
28186 { 0x372, "xvnegsp" },
28187 { 0x390, "xvcvdpuxds" },
28188 { 0x392, "xvcvspdp" },
28189 { 0x3b0, "xvcvdpsxds" },
28190 { 0x3b2, "xvabsdp" },
28191 { 0x3b6, "xxbr[h|w|d|q]|xvxexpdp|xvxexpsp|xvxsigdp|xvxsigsp|xvcvhpsp|xvcvsphp|xscvdphp|xscvhpdp" },
28192 { 0x3d0, "xvcvuxddp" },
28193 { 0x3d2, "xvnabsdp" },
28194 { 0x3f2, "xvnegdp" }
28196 #define VSX_XX2_LEN (sizeof vsx_xx2 / sizeof *vsx_xx2)
28198 // ATTENTION: Keep this array sorted on the opcocde!!!
28199 static struct vsx_insn vsx_xx3[] = {
28200 { 0x0, "xsaddsp" },
28201 { 0x4, "xsmaddasp" },
28202 { 0x9, "xsmaddmsp" },
28203 { 0xC, "xscmpeqdp" },
28204 { 0x20, "xssubsp" },
28205 { 0x24, "xsmaddmsp" },
28206 { 0x2C, "xscmpgtdp" },
28207 { 0x3A, "xxpermr" },
28208 { 0x40, "xsmulsp" },
28209 { 0x44, "xsmsubasp" },
28210 { 0x48, "xxmrghw" },
28211 { 0x4C, "xscmpgedp" },
28212 { 0x60, "xsdivsp" },
28213 { 0x64, "xsmsubmsp" },
28214 { 0x68, "xxperm" },
28215 { 0x80, "xsadddp" },
28216 { 0x84, "xsmaddadp" },
28217 { 0x8c, "xscmpudp" },
28218 { 0xa0, "xssubdp" },
28219 { 0xa4, "xsmaddmdp" },
28220 { 0xac, "xscmpodp" },
28221 { 0xc0, "xsmuldp" },
28222 { 0xc4, "xsmsubadp" },
28223 { 0xc8, "xxmrglw" },
28224 { 0xd4, "xstsqrtdp" },
28225 { 0xe0, "xsdivdp" },
28226 { 0xe4, "xsmsubmdp" },
28227 { 0xe8, "xxpermr" },
28228 { 0xeC, "xscmpexpdp" },
28229 { 0xf4, "xstdivdp" },
28230 { 0x100, "xvaddsp" },
28231 { 0x104, "xvmaddasp" },
28232 { 0x10C, "xvcmpeqsp" },
28233 { 0x110, "xvcvspuxws" },
28234 { 0x114, "xvrsqrtesp" },
28235 { 0x120, "xvsubsp" },
28236 { 0x124, "xvmaddmsp" },
28237 { 0x130, "xvcvspsxws" },
28238 { 0x140, "xvmulsp" },
28239 { 0x144, "xvmsubasp" },
28240 { 0x14C, "xvcmpgesp", },
28241 { 0x160, "xvdivsp" },
28242 { 0x164, "xvmsubmsp" },
28243 { 0x174, "xvtdivsp" },
28244 { 0x180, "xvadddp" },
28245 { 0x184, "xvmaddadp" },
28246 { 0x18C, "xvcmpeqdp" },
28247 { 0x1a0, "xvsubdp" },
28248 { 0x1a4, "xvmaddmdp" },
28249 { 0x1aC, "xvcmpgtdp" },
28250 { 0x1c0, "xvmuldp" },
28251 { 0x1c4, "xvmsubadp" },
28252 { 0x1cc, "xvcmpgedp" },
28253 { 0x1e0, "xvdivdp" },
28254 { 0x1e4, "xvmsubmdp" },
28255 { 0x1f4, "xvtdivdp" },
28256 { 0x200, "xsmaxcdp" },
28257 { 0x204, "xsnmaddasp" },
28258 { 0x208, "xxland" },
28259 { 0x220, "xsmincdp" },
28260 { 0x224, "xsnmaddmsp" },
28261 { 0x228, "xxlandc" },
28262 { 0x244, "xsnmsubasp" },
28263 { 0x248, "xxlor" },
28264 { 0x264, "xsnmsubmsp" },
28265 { 0x268, "xxlxor" },
28266 { 0x280, "xsmaxdp" },
28267 { 0x284, "xsnmaddadp" },
28268 { 0x288, "xxlnor" },
28269 { 0x2a0, "xsmindp" },
28270 { 0x2a4, "xsnmaddmdp" },
28271 { 0x2a8, "xxlorc" },
28272 { 0x2c0, "xscpsgndp" },
28273 { 0x2c4, "xsnmsubadp" },
28274 { 0x2c8, "xxlnand" },
28275 { 0x2e4, "xsnmsubmdp" },
28276 { 0x2e8, "xxleqv" },
28277 { 0x300, "xvmaxsp" },
28278 { 0x304, "xvnmaddasp" },
28279 { 0x320, "xvminsp" },
28280 { 0x324, "xvnmaddmsp" },
28281 { 0x340, "xvcpsgnsp" },
28282 { 0x344, "xvnmsubasp" },
28283 { 0x360, "xviexpsp" },
28284 { 0x364, "xvnmsubmsp" },
28285 { 0x380, "xvmaxdp" },
28286 { 0x384, "xvnmaddadp" },
28287 { 0x3a0, "xvmindp" },
28288 { 0x3a4, "xvnmaddmdp" },
28289 { 0x3c0, "xvcpsgndp" },
28290 { 0x3c4, "xvnmsubadp" },
28291 { 0x3e0, "xviexpdp" },
28292 { 0x3e4, "xvnmsubmdp" },
28293 { 0x3f0, "xvcvsxddp" },
28295 #define VSX_XX3_LEN (sizeof vsx_xx3 / sizeof *vsx_xx3)
28298 /* ATTENTION: These search functions assumes vsx_xx2 and vsx_xx3 arrays
28299 * are sorted.
28301 static Int findVSXextOpCode_xx2(UInt opcode)
28303 Int low, mid, high;
28304 low = 0;
28305 high = VSX_XX2_LEN - 1;
28306 while (low <= high) {
28307 mid = (low + high)/2;
28308 if (opcode < vsx_xx2[mid].opcode)
28309 high = mid - 1;
28310 else if (opcode > vsx_xx2[mid].opcode)
28311 low = mid + 1;
28312 else
28313 return mid;
28315 return -1;
28318 static Int findVSXextOpCode_xx3(UInt opcode)
28320 Int low, mid, high;
28321 low = 0;
28322 high = VSX_XX3_LEN - 1;
28323 while (low <= high) {
28324 mid = (low + high)/2;
28325 if (opcode < vsx_xx3[mid].opcode)
28326 high = mid - 1;
28327 else if (opcode > vsx_xx3[mid].opcode)
28328 low = mid + 1;
28329 else
28330 return mid;
28332 return -1;
28336 /* The full 10-bit extended opcode retrieved via ifieldOPClo10 is
28337 * passed, and we then try to match it up with one of the VSX forms
28338 * below.
28340 static UInt get_VSX60_opc2(UInt opc2_full, UInt theInstr)
28342 #define XX2_1_MASK 0x000003FF // xsiexpdp specific
28343 #define XX2_2_MASK 0x000003FE
28344 #define XX3_1_MASK 0x000003FC
28345 #define XX3_2_MASK 0x000001FC
28346 #define XX3_4_MASK 0x0000027C
28347 #define XX3_5_MASK 0x000003DC
28348 #define XX4_MASK 0x00000018
28350 Int ret;
28351 UInt vsxExtOpcode = 0;
28353 if (( ret = findVSXextOpCode_xx2(opc2_full & XX2_2_MASK)) >= 0)
28354 return vsx_xx2[ret].opcode;
28355 else if ((opc2_full & XX2_1_MASK) == 0x396 ) // xsiexpdp
28356 return 0x396;
28357 else if (( ret = findVSXextOpCode_xx3(opc2_full & XX3_1_MASK)) >= 0)
28358 return vsx_xx3[ret].opcode;
28359 else {
28361 /* There are only a few codes in each of these cases it is
28362 * probably faster to check for the codes then do the array lookups.
28364 vsxExtOpcode = opc2_full & XX3_2_MASK;
28366 switch (vsxExtOpcode) {
28367 case 0x10C: return vsxExtOpcode; // xvcmpeqsp
28368 case 0x12C: return vsxExtOpcode; // xvcmpgtsp, xvcmpgtsp.
28369 case 0x14C: return vsxExtOpcode; // xvcmpgesp, xvcmpgesp.
28370 case 0x18C: return vsxExtOpcode; // xvcmpeqdp, xvcmpeqdp.
28371 case 0x1AC: return vsxExtOpcode; // xvcmpgtdp, xvcmpgtdp.
28372 case 0x1CC: return vsxExtOpcode; // xvcmpgedp, xvcmpgedp.
28373 default: break;
28376 vsxExtOpcode = opc2_full & XX3_4_MASK;
28378 switch (vsxExtOpcode) {
28379 case 0x8: return vsxExtOpcode; // xxsldwi
28380 case 0x28: return vsxExtOpcode; // xxpermdi
28381 default: break;
28384 vsxExtOpcode = opc2_full & XX3_5_MASK;
28386 switch (vsxExtOpcode) {
28387 case 0x354: return vsxExtOpcode; // xvtstdcsp
28388 case 0x3D4: return vsxExtOpcode; // xvtstdcdp
28389 default: break;
28392 if (( opc2_full & XX4_MASK ) == XX4_MASK ) { // xxsel
28393 vsxExtOpcode = 0x18;
28394 return vsxExtOpcode;
28398 vex_printf( "Error: undefined opcode 0x %x, the instruction = 0x %x\n",
28399 opc2_full, theInstr );
28400 vpanic( "ERROR: get_VSX60_opc2()\n" );
28401 return 0;
28404 /*------------------------------------------------------------*/
28405 /*--- Disassemble a single instruction ---*/
28406 /*------------------------------------------------------------*/
28408 /* Disassemble a single instruction into IR. The instruction
28409 is located in host memory at &guest_code[delta]. */
28411 static
28412 DisResult disInstr_PPC_WRK (
28413 Long delta64,
28414 const VexArchInfo* archinfo,
28415 const VexAbiInfo* abiinfo,
28416 Bool sigill_diag
28419 UChar opc1;
28420 UInt opc2;
28421 DisResult dres;
28422 UInt theInstr;
28423 IRType ty = mode64 ? Ity_I64 : Ity_I32;
28424 UInt hwcaps = archinfo->hwcaps;
28425 Long delta;
28426 Bool allow_F = False;
28427 Bool allow_V = False;
28428 Bool allow_FX = False;
28429 Bool allow_GX = False;
28430 Bool allow_VX = False; // Equates to "supports Power ISA 2.06
28431 Bool allow_DFP = False;
28432 Bool allow_isa_2_07 = False;
28433 Bool allow_isa_3_0 = False;
28435 /* What insn variants are we supporting today? */
28436 if (mode64) {
28437 allow_F = True;
28438 allow_V = (0 != (hwcaps & VEX_HWCAPS_PPC64_V));
28439 allow_FX = (0 != (hwcaps & VEX_HWCAPS_PPC64_FX));
28440 allow_GX = (0 != (hwcaps & VEX_HWCAPS_PPC64_GX));
28441 allow_VX = (0 != (hwcaps & VEX_HWCAPS_PPC64_VX));
28442 allow_DFP = (0 != (hwcaps & VEX_HWCAPS_PPC64_DFP));
28443 allow_isa_2_07 = (0 != (hwcaps & VEX_HWCAPS_PPC64_ISA2_07));
28444 allow_isa_3_0 = (0 != (hwcaps & VEX_HWCAPS_PPC64_ISA3_0));
28445 } else {
28446 allow_F = (0 != (hwcaps & VEX_HWCAPS_PPC32_F));
28447 allow_V = (0 != (hwcaps & VEX_HWCAPS_PPC32_V));
28448 allow_FX = (0 != (hwcaps & VEX_HWCAPS_PPC32_FX));
28449 allow_GX = (0 != (hwcaps & VEX_HWCAPS_PPC32_GX));
28450 allow_VX = (0 != (hwcaps & VEX_HWCAPS_PPC32_VX));
28451 allow_DFP = (0 != (hwcaps & VEX_HWCAPS_PPC32_DFP));
28452 allow_isa_2_07 = (0 != (hwcaps & VEX_HWCAPS_PPC32_ISA2_07));
28453 allow_isa_3_0 = (0 != (hwcaps & VEX_HWCAPS_PPC32_ISA3_0));
28456 /* Enable writting the OV32 and CA32 bits added with ISA3.0 */
28457 OV32_CA32_supported = allow_isa_3_0;
28459 /* The running delta */
28460 delta = (Long)mkSzAddr(ty, (ULong)delta64);
28462 /* Set result defaults. */
28463 dres.whatNext = Dis_Continue;
28464 dres.len = 0;
28465 dres.jk_StopHere = Ijk_INVALID;
28466 dres.hint = Dis_HintNone;
28468 /* At least this is simple on PPC32: insns are all 4 bytes long, and
28469 4-aligned. So just fish the whole thing out of memory right now
28470 and have done. */
28471 theInstr = getUIntPPCendianly( &guest_code[delta] );
28473 if (0) vex_printf("insn: 0x%x\n", theInstr);
28475 DIP("\t0x%llx: ", (ULong)guest_CIA_curr_instr);
28477 /* Spot "Special" instructions (see comment at top of file). */
28479 const UChar* code = guest_code + delta;
28480 /* Spot the 16-byte preamble:
28481 32-bit mode:
28482 5400183E rlwinm 0,0,3,0,31
28483 5400683E rlwinm 0,0,13,0,31
28484 5400E83E rlwinm 0,0,29,0,31
28485 5400983E rlwinm 0,0,19,0,31
28486 64-bit mode:
28487 78001800 rotldi 0,0,3
28488 78006800 rotldi 0,0,13
28489 7800E802 rotldi 0,0,61
28490 78009802 rotldi 0,0,51
28492 UInt word1 = mode64 ? 0x78001800 : 0x5400183E;
28493 UInt word2 = mode64 ? 0x78006800 : 0x5400683E;
28494 UInt word3 = mode64 ? 0x7800E802 : 0x5400E83E;
28495 UInt word4 = mode64 ? 0x78009802 : 0x5400983E;
28496 Bool is_special_preamble = False;
28497 if (getUIntPPCendianly(code+ 0) == word1 &&
28498 getUIntPPCendianly(code+ 4) == word2 &&
28499 getUIntPPCendianly(code+ 8) == word3 &&
28500 getUIntPPCendianly(code+12) == word4) {
28501 is_special_preamble = True;
28502 } else if (! mode64 &&
28503 getUIntPPCendianly(code+ 0) == 0x54001800 &&
28504 getUIntPPCendianly(code+ 4) == 0x54006800 &&
28505 getUIntPPCendianly(code+ 8) == 0x5400E800 &&
28506 getUIntPPCendianly(code+12) == 0x54009800) {
28507 static Bool reported = False;
28508 if (!reported) {
28509 vex_printf("disInstr(ppc): old ppc32 instruction magic detected. Code might clobber r0.\n");
28510 vex_printf("disInstr(ppc): source needs to be recompiled against latest valgrind.h.\n");
28511 reported = True;
28513 is_special_preamble = True;
28515 if (is_special_preamble) {
28516 /* Got a "Special" instruction preamble. Which one is it? */
28517 if (getUIntPPCendianly(code+16) == 0x7C210B78 /* or 1,1,1 */) {
28518 /* %R3 = client_request ( %R4 ) */
28519 DIP("r3 = client_request ( %%r4 )\n");
28520 delta += 20;
28521 putGST( PPC_GST_CIA, mkSzImm( ty, guest_CIA_bbstart + delta ));
28522 dres.jk_StopHere = Ijk_ClientReq;
28523 dres.whatNext = Dis_StopHere;
28524 goto decode_success;
28526 else
28527 if (getUIntPPCendianly(code+16) == 0x7C421378 /* or 2,2,2 */) {
28528 /* %R3 = guest_NRADDR */
28529 DIP("r3 = guest_NRADDR\n");
28530 delta += 20;
28531 dres.len = 20;
28532 putIReg(3, IRExpr_Get( OFFB_NRADDR, ty ));
28533 goto decode_success;
28535 else
28536 if (getUIntPPCendianly(code+16) == 0x7C631B78 /* or 3,3,3 */) {
28537 delta += 20;
28538 if (host_endness == VexEndnessLE) {
28539 /* branch-and-link-to-noredir %R12 */
28540 DIP("branch-and-link-to-noredir r12\n");
28541 putGST( PPC_GST_LR,
28542 mkSzImm(ty, guest_CIA_bbstart + (Long)delta) );
28543 putGST( PPC_GST_CIA, getIReg(12));
28544 } else {
28545 /* branch-and-link-to-noredir %R11 */
28546 DIP("branch-and-link-to-noredir r11\n");
28547 putGST( PPC_GST_LR,
28548 mkSzImm(ty, guest_CIA_bbstart + (Long)delta) );
28549 putGST( PPC_GST_CIA, getIReg(11));
28551 dres.jk_StopHere = Ijk_NoRedir;
28552 dres.whatNext = Dis_StopHere;
28553 goto decode_success;
28555 else
28556 if (getUIntPPCendianly(code+16) == 0x7C842378 /* or 4,4,4 */) {
28557 /* %R3 = guest_NRADDR_GPR2 */
28558 DIP("r3 = guest_NRADDR_GPR2\n");
28559 delta += 20;
28560 dres.len = 20;
28561 putIReg(3, IRExpr_Get( OFFB_NRADDR_GPR2, ty ));
28562 goto decode_success;
28564 else
28565 if (getUIntPPCendianly(code+16) == 0x7CA52B78 /* or 5,5,5 */) {
28566 DIP("IR injection\n");
28567 if (host_endness == VexEndnessBE)
28568 vex_inject_ir(irsb, Iend_BE);
28569 else
28570 vex_inject_ir(irsb, Iend_LE);
28572 delta += 20;
28573 dres.len = 20;
28575 // Invalidate the current insn. The reason is that the IRop we're
28576 // injecting here can change. In which case the translation has to
28577 // be redone. For ease of handling, we simply invalidate all the
28578 // time.
28580 stmt(IRStmt_Put(OFFB_CMSTART, mkSzImm(ty, guest_CIA_curr_instr)));
28581 stmt(IRStmt_Put(OFFB_CMLEN, mkSzImm(ty, 20)));
28583 putGST( PPC_GST_CIA, mkSzImm( ty, guest_CIA_bbstart + delta ));
28584 dres.whatNext = Dis_StopHere;
28585 dres.jk_StopHere = Ijk_InvalICache;
28586 goto decode_success;
28588 /* We don't know what it is. Set opc1/opc2 so decode_failure
28589 can print the insn following the Special-insn preamble. */
28590 theInstr = getUIntPPCendianly(code+16);
28591 opc1 = ifieldOPC(theInstr);
28592 opc2 = ifieldOPClo10(theInstr);
28593 goto decode_failure;
28594 /*NOTREACHED*/
28598 opc1 = ifieldOPC(theInstr);
28599 opc2 = ifieldOPClo10(theInstr);
28601 // Note: all 'reserved' bits must be cleared, else invalid
28602 switch (opc1) {
28604 /* Integer Arithmetic Instructions */
28605 case 0x0C: case 0x0D: case 0x0E: // addic, addic., addi
28606 case 0x0F: case 0x07: case 0x08: // addis, mulli, subfic
28607 if (dis_int_arith( theInstr )) goto decode_success;
28608 goto decode_failure;
28610 /* Integer Compare Instructions */
28611 case 0x0B: case 0x0A: // cmpi, cmpli
28612 if (dis_int_cmp( theInstr )) goto decode_success;
28613 goto decode_failure;
28615 /* Integer Logical Instructions */
28616 case 0x1C: case 0x1D: case 0x18: // andi., andis., ori
28617 case 0x19: case 0x1A: case 0x1B: // oris, xori, xoris
28618 if (dis_int_logic( theInstr )) goto decode_success;
28619 goto decode_failure;
28621 /* Integer Rotate Instructions */
28622 case 0x14: case 0x15: case 0x17: // rlwimi, rlwinm, rlwnm
28623 if (dis_int_rot( theInstr )) goto decode_success;
28624 goto decode_failure;
28626 /* 64bit Integer Rotate Instructions */
28627 case 0x1E: // rldcl, rldcr, rldic, rldicl, rldicr, rldimi
28628 if (!mode64) goto decode_failure;
28629 if (dis_int_rot( theInstr )) goto decode_success;
28630 goto decode_failure;
28632 /* Integer Load Instructions */
28633 case 0x22: case 0x23: case 0x2A: // lbz, lbzu, lha
28634 case 0x2B: case 0x28: case 0x29: // lhau, lhz, lhzu
28635 case 0x20: case 0x21: // lwz, lwzu
28636 if (dis_int_load( theInstr )) goto decode_success;
28637 goto decode_failure;
28639 /* Integer Store Instructions */
28640 case 0x26: case 0x27: case 0x2C: // stb, stbu, sth
28641 case 0x2D: case 0x24: case 0x25: // sthu, stw, stwu
28642 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
28643 goto decode_failure;
28645 /* Integer Load and Store Multiple Instructions */
28646 case 0x2E: case 0x2F: // lmw, stmw
28647 if (dis_int_ldst_mult( theInstr )) goto decode_success;
28648 goto decode_failure;
28650 /* Branch Instructions */
28651 case 0x12: case 0x10: // b, bc
28652 if (dis_branch(theInstr, abiinfo, &dres))
28653 goto decode_success;
28654 goto decode_failure;
28656 /* System Linkage Instructions */
28657 case 0x11: // sc
28658 if (dis_syslink(theInstr, abiinfo, &dres)) goto decode_success;
28659 goto decode_failure;
28661 /* Trap Instructions */
28662 case 0x02: // tdi
28663 if (!mode64) goto decode_failure;
28664 if (dis_trapi(theInstr, &dres)) goto decode_success;
28665 goto decode_failure;
28667 case 0x03: // twi
28668 if (dis_trapi(theInstr, &dres)) goto decode_success;
28669 goto decode_failure;
28671 /* Floating Point Load Instructions */
28672 case 0x30: case 0x31: case 0x32: // lfs, lfsu, lfd
28673 case 0x33: // lfdu
28674 if (!allow_F) goto decode_noF;
28675 if (dis_fp_load( theInstr )) goto decode_success;
28676 goto decode_failure;
28678 /* Floating Point Store Instructions */
28679 case 0x34: case 0x35: case 0x36: // stfsx, stfsux, stfdx
28680 case 0x37: // stfdux
28681 if (!allow_F) goto decode_noF;
28682 if (dis_fp_store( theInstr )) goto decode_success;
28683 goto decode_failure;
28685 /* Floating Point Load Double Pair Instructions */
28686 case 0x39: case 0x3D: // lfdp, lxsd, lxssp, lxv
28687 // stfdp, stxsd, stxssp, stxv
28688 if (!allow_F) goto decode_noF;
28689 if (dis_fp_pair( theInstr )) goto decode_success;
28690 goto decode_failure;
28692 /* 128-bit Integer Load */
28693 case 0x38: // lq
28694 if (dis_int_load( theInstr )) goto decode_success;
28695 goto decode_failure;
28697 /* 64bit Integer Loads */
28698 case 0x3A: // ld, ldu, lwa
28699 if (!mode64) goto decode_failure;
28700 if (dis_int_load( theInstr )) goto decode_success;
28701 goto decode_failure;
28703 case 0x3B:
28704 if (!allow_F) goto decode_noF;
28705 opc2 = ifieldOPClo10(theInstr);
28707 switch (opc2) {
28708 case 0x2: // dadd - DFP Add
28709 case 0x202: // dsub - DFP Subtract
28710 case 0x22: // dmul - DFP Mult
28711 case 0x222: // ddiv - DFP Divide
28712 if (!allow_DFP) goto decode_noDFP;
28713 if (dis_dfp_arith( theInstr ))
28714 goto decode_success;
28715 goto decode_failure;
28716 case 0x82: // dcmpo, DFP comparison ordered instruction
28717 case 0x282: // dcmpu, DFP comparison unordered instruction
28718 if (!allow_DFP) goto decode_noDFP;
28719 if (dis_dfp_compare( theInstr ) )
28720 goto decode_success;
28721 goto decode_failure;
28722 case 0x102: // dctdp - DFP convert to DFP long
28723 case 0x302: // drsp - DFP round to dfp short
28724 case 0x122: // dctfix - DFP convert to fixed
28725 if (!allow_DFP) goto decode_noDFP;
28726 if (dis_dfp_fmt_conv( theInstr ))
28727 goto decode_success;
28728 goto decode_failure;
28729 case 0x322: // POWER 7 inst, dcffix - DFP convert from fixed
28730 if (!allow_VX)
28731 goto decode_failure;
28732 if (!allow_DFP) goto decode_noDFP;
28733 if (dis_dfp_fmt_conv( theInstr ))
28734 goto decode_success;
28735 goto decode_failure;
28736 case 0x2A2: // dtstsf - DFP number of significant digits
28737 case 0x2A3: // dtstsfi - DFP number of significant digits Immediate
28738 if (!allow_DFP) goto decode_noDFP;
28739 if (dis_dfp_significant_digits(theInstr))
28740 goto decode_success;
28741 goto decode_failure;
28742 case 0x142: // ddedpd DFP Decode DPD to BCD
28743 case 0x342: // denbcd DFP Encode BCD to DPD
28744 if (!allow_DFP) goto decode_noDFP;
28745 if (dis_dfp_bcd(theInstr))
28746 goto decode_success;
28747 goto decode_failure;
28748 case 0x162: // dxex - Extract exponent
28749 case 0x362: // diex - Insert exponent
28750 if (!allow_DFP) goto decode_noDFP;
28751 if (dis_dfp_extract_insert( theInstr ) )
28752 goto decode_success;
28753 goto decode_failure;
28754 case 0x3CE: // fcfidus (implemented as native insn)
28755 if (!allow_VX)
28756 goto decode_noVX;
28757 if (dis_fp_round( theInstr ))
28758 goto decode_success;
28759 goto decode_failure;
28760 case 0x34E: // fcfids
28761 if (dis_fp_round( theInstr ))
28762 goto decode_success;
28763 goto decode_failure;
28766 opc2 = ifieldOPClo9( theInstr );
28767 switch (opc2) {
28768 case 0x42: // dscli, DFP shift left
28769 case 0x62: // dscri, DFP shift right
28770 if (!allow_DFP) goto decode_noDFP;
28771 if (dis_dfp_shift( theInstr ))
28772 goto decode_success;
28773 goto decode_failure;
28774 case 0xc2: // dtstdc, DFP test data class
28775 case 0xe2: // dtstdg, DFP test data group
28776 if (!allow_DFP) goto decode_noDFP;
28777 if (dis_dfp_class_test( theInstr ))
28778 goto decode_success;
28779 goto decode_failure;
28782 opc2 = ifieldOPClo8( theInstr );
28783 switch (opc2) {
28784 case 0x3: // dqua - DFP Quantize
28785 case 0x23: // drrnd - DFP Reround
28786 case 0x43: // dquai - DFP Quantize immediate
28787 if (!allow_DFP) goto decode_noDFP;
28788 if (dis_dfp_quantize_sig_rrnd( theInstr ) )
28789 goto decode_success;
28790 goto decode_failure;
28791 case 0xA2: // dtstex - DFP Test exponent
28792 if (!allow_DFP) goto decode_noDFP;
28793 if (dis_dfp_exponent_test( theInstr ) )
28794 goto decode_success;
28795 goto decode_failure;
28796 case 0x63: // drintx - Round to an integer value
28797 case 0xE3: // drintn - Round to an integer value
28798 if (!allow_DFP) goto decode_noDFP;
28799 if (dis_dfp_round( theInstr ) ) {
28800 goto decode_success;
28802 goto decode_failure;
28803 default:
28804 break; /* fall through to next opc2 check */
28807 opc2 = IFIELD(theInstr, 1, 5);
28808 switch (opc2) {
28809 /* Floating Point Arith Instructions */
28810 case 0x12: case 0x14: case 0x15: // fdivs, fsubs, fadds
28811 case 0x19: // fmuls
28812 if (dis_fp_arith(theInstr)) goto decode_success;
28813 goto decode_failure;
28814 case 0x16: // fsqrts
28815 if (!allow_FX) goto decode_noFX;
28816 if (dis_fp_arith(theInstr)) goto decode_success;
28817 goto decode_failure;
28818 case 0x18: // fres
28819 if (!allow_GX) goto decode_noGX;
28820 if (dis_fp_arith(theInstr)) goto decode_success;
28821 goto decode_failure;
28823 /* Floating Point Mult-Add Instructions */
28824 case 0x1C: case 0x1D: case 0x1E: // fmsubs, fmadds, fnmsubs
28825 case 0x1F: // fnmadds
28826 if (dis_fp_multadd(theInstr)) goto decode_success;
28827 goto decode_failure;
28829 case 0x1A: // frsqrtes
28830 if (!allow_GX) goto decode_noGX;
28831 if (dis_fp_arith(theInstr)) goto decode_success;
28832 goto decode_failure;
28834 default:
28835 goto decode_failure;
28837 break;
28839 case 0x3C: // VSX instructions (except load/store)
28841 // All of these VSX instructions use some VMX facilities, so
28842 // if allow_V is not set, we'll skip trying to decode.
28843 if (!allow_V) goto decode_noVX;
28844 /* The xvtstdcdp and xvtstdcsp instructions do not have a
28845 contiguous opc2 field. The following vsxOpc2 = get_VSX60_opc2()
28846 doesn't correctly match these instructions for dc != 0. So,
28847 we will explicitly look for the two instructions. */
28848 opc2 = ifieldOPClo10(theInstr);
28849 UInt opc2hi = IFIELD(theInstr, 7, 4);
28850 UInt opc2lo = IFIELD(theInstr, 3, 3);
28851 UInt vsxOpc2;
28853 if (( opc2hi == 13 ) && ( opc2lo == 5)) { //xvtstdcsp
28854 if (dis_vxs_misc(theInstr, abiinfo, 0x354, allow_isa_3_0))
28855 goto decode_success;
28856 goto decode_failure;
28859 if (( opc2hi == 15 ) && ( opc2lo == 5)) { //xvtstdcdp
28860 if (dis_vxs_misc(theInstr, abiinfo, 0x3D4, allow_isa_3_0))
28861 goto decode_success;
28862 goto decode_failure;
28865 /* The vsxOpc2 returned is the "normalized" value, representing the
28866 * instructions secondary opcode as taken from the standard secondary
28867 * opcode field [21:30] (IBM notatition), even if the actual field
28868 * is non-standard. These normalized values are given in the opcode
28869 * appendices of the ISA 2.06 document.
28871 if ( ( opc2 == 0x168 ) && ( IFIELD( theInstr, 19, 2 ) == 0 ) )// xxspltib
28873 /* This is a special case of the XX1 form where the RA, RB
28874 * fields hold an immediate value.
28876 if (dis_vxs_misc(theInstr, abiinfo, opc2, allow_isa_3_0)) goto decode_success;
28877 goto decode_failure;
28880 vsxOpc2 = get_VSX60_opc2(opc2, theInstr);
28882 switch (vsxOpc2) {
28883 case 0x8: case 0x28: case 0x48: case 0xc8: // xxsldwi, xxpermdi, xxmrghw, xxmrglw
28884 case 0x068: case 0xE8: // xxperm, xxpermr
28885 case 0x018: case 0x148: // xxsel, xxspltw
28886 if (dis_vx_permute_misc(theInstr, vsxOpc2 ))
28887 goto decode_success;
28888 goto decode_failure;
28889 case 0xC: case 0x2C: case 0x4C: // xscmpeqdp, xscmpgtdp, xscmpgedp
28890 case 0x200: case 0x220: //xsmaxcdp, xsmincdp
28891 if (dis_vx_misc(theInstr, vsxOpc2)) goto decode_success;
28892 goto decode_failure;
28893 case 0x268: case 0x248: case 0x288: // xxlxor, xxlor, xxlnor,
28894 case 0x208: case 0x228: // xxland, xxlandc
28895 case 0x2A8: case 0x2C8: case 0x2E8: // xxlorc, xxlnand, xxleqv
28896 if (dis_vx_logic(theInstr, vsxOpc2)) goto decode_success;
28897 goto decode_failure;
28898 case 0x0ec: // xscmpexpdp
28899 case 0x14A: case 0x16A: // xxextractuw, xxinsertw
28900 case 0x2B2: case 0x2C0: // xsabsdp, xscpsgndp
28901 case 0x2D2: case 0x2F2: // xsnabsdp, xsnegdp
28902 case 0x280: case 0x2A0: // xsmaxdp, xsmindp
28903 case 0x0F2: case 0x0D2: // xsrdpim, xsrdpip
28904 case 0x034: case 0x014: // xsresp, xsrsqrtesp
28905 case 0x0B4: case 0x094: // xsredp, xsrsqrtedp
28906 case 0x0D6: case 0x0B2: // xsrdpic, xsrdpiz
28907 case 0x092: case 0x232: // xsrdpi, xsrsp
28908 case 0x3B6: // xxbrh, xvxexpdp, xvxexpsp, xvxsigdp
28909 // xvxsigsp, xvcvhpsp
28910 case 0x2b6: // xsxexpdp, xsxsigdp
28911 case 0x254: case 0x2d4: // xststdcsp, xststdcdp
28912 case 0x354: // xvtstdcsp
28913 case 0x360:case 0x396: // xviexpsp, xsiexpdp
28914 case 0x3D4: case 0x3E0: // xvtstdcdp, xviexpdp
28915 if (dis_vxs_misc(theInstr, abiinfo, vsxOpc2, allow_isa_3_0))
28916 goto decode_success;
28917 goto decode_failure;
28918 case 0x08C: case 0x0AC: // xscmpudp, xscmpodp
28919 if (dis_vx_cmp(theInstr, vsxOpc2)) goto decode_success;
28920 goto decode_failure;
28921 case 0x0: case 0x020: // xsaddsp, xssubsp
28922 case 0x080: // xsadddp
28923 case 0x060: case 0x0E0: // xsdivsp, xsdivdp
28924 case 0x004: case 0x024: // xsmaddasp, xsmaddmsp
28925 case 0x084: case 0x0A4: // xsmaddadp, xsmaddmdp
28926 case 0x044: case 0x064: // xsmsubasp, xsmsubmsp
28927 case 0x0C4: case 0x0E4: // xsmsubadp, xsmsubmdp
28928 case 0x204: case 0x224: // xsnmaddasp, xsnmaddmsp
28929 case 0x284: case 0x2A4: // xsnmaddadp, xsnmaddmdp
28930 case 0x244: case 0x264: // xsnmsubasp, xsnmsubmsp
28931 case 0x2C4: case 0x2E4: // xsnmsubadp, xsnmsubmdp
28932 case 0x040: case 0x0C0: // xsmulsp, xsmuldp
28933 case 0x0A0: // xssubdp
28934 case 0x016: case 0x096: // xssqrtsp,xssqrtdp
28935 case 0x0F4: case 0x0D4: // xstdivdp, xstsqrtdp
28936 if (dis_vxs_arith(theInstr, vsxOpc2)) goto decode_success;
28937 goto decode_failure;
28938 case 0x180: // xvadddp
28939 case 0x1E0: // xvdivdp
28940 case 0x1C0: // xvmuldp
28941 case 0x1A0: // xvsubdp
28942 case 0x184: case 0x1A4: // xvmaddadp, xvmaddmdp
28943 case 0x1C4: case 0x1E4: // xvmsubadp, xvmsubmdp
28944 case 0x384: case 0x3A4: // xvnmaddadp, xvnmaddmdp
28945 case 0x3C4: case 0x3E4: // xvnmsubadp, xvnmsubmdp
28946 case 0x1D4: case 0x1F4: // xvtsqrtdp, xvtdivdp
28947 case 0x196: // xvsqrtdp
28948 if (dis_vxv_dp_arith(theInstr, vsxOpc2)) goto decode_success;
28949 goto decode_failure;
28950 case 0x100: // xvaddsp
28951 case 0x160: // xvdivsp
28952 case 0x140: // xvmulsp
28953 case 0x120: // xvsubsp
28954 case 0x104: case 0x124: // xvmaddasp, xvmaddmsp
28955 case 0x144: case 0x164: // xvmsubasp, xvmsubmsp
28956 case 0x304: case 0x324: // xvnmaddasp, xvnmaddmsp
28957 case 0x344: case 0x364: // xvnmsubasp, xvnmsubmsp
28958 case 0x154: case 0x174: // xvtsqrtsp, xvtdivsp
28959 case 0x116: // xvsqrtsp
28960 if (dis_vxv_sp_arith(theInstr, vsxOpc2)) goto decode_success;
28961 goto decode_failure;
28963 case 0x250: // xscvuxdsp
28964 case 0x2D0: case 0x3d0: // xscvuxddp, xvcvuxddp
28965 case 0x350: case 0x1d0: // xvcvuxdsp, xvcvuxwdp
28966 case 0x090: // xscvdpuxws
28967 // The above VSX conversion instructions employ some ISA 2.06
28968 // floating point conversion instructions under the covers,
28969 // so if allow_VX (which means "supports ISA 2.06") is not set,
28970 // we'll skip the decode.
28971 if (!allow_VX) goto decode_noVX;
28972 if (dis_vx_conv(theInstr, vsxOpc2)) goto decode_success;
28973 goto decode_failure;
28975 case 0x2B0: // xscvdpsxds
28976 case 0x270: case 0x2F0: // xscvsxdsp, xscvsxddp
28977 case 0x1b0: case 0x130: // xvcvdpsxws, xvcvspsxws
28978 case 0x0b0: case 0x290: // xscvdpsxws, xscvdpuxds
28979 case 0x212: case 0x216: // xscvdpsp, xscvdpspn
28980 case 0x292: case 0x296: // xscvspdp, xscvspdpn
28981 case 0x312: // xvcvdpsp
28982 case 0x390: case 0x190: // xvcvdpuxds, xvcvdpuxws
28983 case 0x3B0: case 0x310: // xvcvdpsxds, xvcvspuxds
28984 case 0x392: case 0x330: // xvcvspdp, xvcvspsxds
28985 case 0x110: case 0x3f0: // xvcvspuxws, xvcvsxddp
28986 case 0x370: case 0x1f0: // xvcvsxdsp, xvcvsxwdp
28987 case 0x170: case 0x150: // xvcvsxwsp, xvcvuxwsp
28988 if (dis_vx_conv(theInstr, vsxOpc2)) goto decode_success;
28989 goto decode_failure;
28991 case 0x18C: // xvcmpeqdp[.]
28992 case 0x10C: // xvcmpeqsp[.]
28993 case 0x14C: // xvcmpgesp[.]
28994 case 0x12C: // xvcmpgtsp[.]
28995 case 0x1CC: // xvcmpgedp[.]
28996 case 0x1AC: // xvcmpgtdp[.]
28997 if (dis_vvec_cmp(theInstr, vsxOpc2)) goto decode_success;
28998 goto decode_failure;
29000 case 0x134: // xvresp
29001 case 0x1B4: // xvredp
29002 case 0x194: case 0x114: // xvrsqrtedp, xvrsqrtesp
29003 case 0x372: // xvnegsp
29004 case 0x380: case 0x3A0: // xvmaxdp, xvmindp
29005 case 0x300: case 0x320: // xvmaxsp, xvminsp
29006 case 0x3C0: case 0x340: // xvcpsgndp, xvcpsgnsp
29007 case 0x3B2: case 0x332: // xvabsdp, xvabssp
29008 case 0x3D2: case 0x352: // xvnabsdp, xvnabssp
29009 case 0x192: case 0x1D6: // xvrdpi, xvrdpic
29010 case 0x1F2: case 0x1D2: // xvrdpim, xvrdpip
29011 case 0x1B2: case 0x3F2: // xvrdpiz, xvnegdp
29012 case 0x112: case 0x156: // xvrspi, xvrspic
29013 case 0x172: case 0x152: // xvrspim, xvrspip
29014 case 0x132: // xvrspiz
29015 if (dis_vxv_misc(theInstr, vsxOpc2)) goto decode_success;
29016 goto decode_failure;
29018 default:
29019 goto decode_failure;
29021 break;
29024 /* 64bit Integer Stores */
29025 case 0x3E: // std, stdu, stq
29026 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
29027 goto decode_failure;
29029 case 0x3F:
29030 if (!allow_F) goto decode_noF;
29031 /* Instrs using opc[1:5] never overlap instrs using opc[1:10],
29032 so we can simply fall through the first switch statement */
29034 opc2 = IFIELD(theInstr, 1, 5);
29035 switch (opc2) {
29036 /* Floating Point Arith Instructions */
29037 case 0x12: case 0x14: case 0x15: // fdiv, fsub, fadd
29038 case 0x19: // fmul
29039 if (dis_fp_arith(theInstr)) goto decode_success;
29040 goto decode_failure;
29041 case 0x16: // fsqrt
29042 if (!allow_FX) goto decode_noFX;
29043 if (dis_fp_arith(theInstr)) goto decode_success;
29044 goto decode_failure;
29045 case 0x17: case 0x1A: // fsel, frsqrte
29046 if (!allow_GX) goto decode_noGX;
29047 if (dis_fp_arith(theInstr)) goto decode_success;
29048 goto decode_failure;
29050 /* Floating Point Mult-Add Instructions */
29051 case 0x1C: case 0x1D: case 0x1E: // fmsub, fmadd, fnmsub
29052 case 0x1F: // fnmadd
29053 if (dis_fp_multadd(theInstr)) goto decode_success;
29054 goto decode_failure;
29056 case 0x18: // fre
29057 if (!allow_GX) goto decode_noGX;
29058 if (dis_fp_arith(theInstr)) goto decode_success;
29059 goto decode_failure;
29061 default:
29062 break; // Fall through
29065 opc2 = IFIELD(theInstr, 1, 8);
29066 switch (opc2) {
29067 case 0x5: // xsrqpi, xsrqpix
29068 case 0x25: // xsrqpxp
29069 if ( !mode64 || !allow_isa_3_0 ) goto decode_failure;
29070 if ( dis_vx_Scalar_Round_to_quad_integer( theInstr, abiinfo ) )
29071 goto decode_success;
29072 goto decode_failure;
29073 default:
29074 break; // Fall through
29077 opc2 = IFIELD(theInstr, 1, 10);
29078 UInt inst_select = IFIELD( theInstr, 16, 5 );
29080 switch (opc2) {
29081 /* 128-bit DFP instructions */
29082 case 0x2: // daddq - DFP Add
29083 case 0x202: // dsubq - DFP Subtract
29084 case 0x22: // dmulq - DFP Mult
29085 case 0x222: // ddivq - DFP Divide
29086 if (!allow_DFP) goto decode_noDFP;
29087 if (dis_dfp_arithq( theInstr ))
29088 goto decode_success;
29089 goto decode_failure;
29090 case 0x162: // dxexq - DFP Extract exponent
29091 case 0x362: // diexq - DFP Insert exponent
29092 if (!allow_DFP) goto decode_noDFP;
29093 if (dis_dfp_extract_insertq( theInstr ))
29094 goto decode_success;
29095 goto decode_failure;
29097 case 0x82: // dcmpoq, DFP comparison ordered instruction
29098 case 0x282: // dcmpuq, DFP comparison unordered instruction
29099 if (!allow_DFP) goto decode_noDFP;
29100 if (dis_dfp_compare( theInstr ) )
29101 goto decode_success;
29102 goto decode_failure;
29104 case 0x102: // dctqpq - DFP convert to DFP extended
29105 case 0x302: // drdpq - DFP round to dfp Long
29106 case 0x122: // dctfixq - DFP convert to fixed quad
29107 case 0x322: // dcffixq - DFP convert from fixed quad
29108 if (!allow_DFP) goto decode_noDFP;
29109 if (dis_dfp_fmt_convq( theInstr ))
29110 goto decode_success;
29111 goto decode_failure;
29113 case 0x2A2: // dtstsfq - DFP number of significant digits
29114 case 0x2A3: // dtstsfiq - DFP number of significant digits Immediate
29115 if (!allow_DFP) goto decode_noDFP;
29116 if (dis_dfp_significant_digits(theInstr))
29117 goto decode_success;
29118 goto decode_failure;
29120 case 0x142: // ddedpdq DFP Decode DPD to BCD
29121 case 0x342: // denbcdq DFP Encode BCD to DPD
29122 if (!allow_DFP) goto decode_noDFP;
29123 if (dis_dfp_bcdq(theInstr))
29124 goto decode_success;
29125 goto decode_failure;
29127 /* Floating Point Compare Instructions */
29128 case 0x000: // fcmpu
29129 case 0x020: // fcmpo
29130 if (dis_fp_cmp(theInstr)) goto decode_success;
29131 goto decode_failure;
29133 case 0x080: // ftdiv
29134 case 0x0A0: // ftsqrt
29135 if (dis_fp_tests(theInstr)) goto decode_success;
29136 goto decode_failure;
29138 /* Floating Point Rounding/Conversion Instructions */
29139 case 0x00C: // frsp
29140 case 0x00E: // fctiw
29141 case 0x00F: // fctiwz
29142 case 0x32E: // fctid
29143 case 0x32F: // fctidz
29144 case 0x34E: // fcfid
29145 if (dis_fp_round(theInstr)) goto decode_success;
29146 goto decode_failure;
29147 case 0x3CE: case 0x3AE: case 0x3AF: // fcfidu, fctidu[z] (implemented as native insns)
29148 case 0x08F: case 0x08E: // fctiwu[z] (implemented as native insns)
29149 if (!allow_VX) goto decode_noVX;
29150 if (dis_fp_round(theInstr)) goto decode_success;
29151 goto decode_failure;
29153 /* Power6 rounding stuff */
29154 case 0x1E8: // frim
29155 case 0x1C8: // frip
29156 case 0x188: // frin
29157 case 0x1A8: // friz
29158 /* A hack to check for P6 capability . . . */
29159 if ((allow_F && allow_V && allow_FX && allow_GX) &&
29160 (dis_fp_round(theInstr)))
29161 goto decode_success;
29162 goto decode_failure;
29164 /* Floating Point Move Instructions */
29165 case 0x008: // fcpsgn
29166 case 0x028: // fneg
29167 case 0x048: // fmr
29168 case 0x088: // fnabs
29169 case 0x108: // fabs
29170 if (dis_fp_move( theInstr )) goto decode_success;
29171 goto decode_failure;
29173 case 0x3c6: case 0x346: // fmrgew, fmrgow
29174 if (dis_fp_merge( theInstr )) goto decode_success;
29175 goto decode_failure;
29177 /* Floating Point Status/Control Register Instructions */
29178 case 0x026: // mtfsb1
29179 case 0x040: // mcrfs
29180 case 0x046: // mtfsb0
29181 case 0x086: // mtfsfi
29182 case 0x247: // mffs, mmfs., mffsce, mffscdrn, mffscdrni,
29183 // mffscrn, mffscrn, mffscri, mffsl
29184 case 0x2C7: // mtfsf
29185 // Some of the above instructions need to know more about the
29186 // ISA level supported by the host.
29187 if (dis_fp_scr( theInstr, allow_GX )) goto decode_success;
29188 goto decode_failure;
29190 case 0x324: // xsabsqp, xsxexpqp,xsnabsqp, xsnegqp, xsxsigqp
29191 if ( inst_select == 27 ) { // xssqrtqp
29192 if ( dis_vx_Floating_Point_Arithmetic_quad_precision( theInstr,
29193 abiinfo ) )
29194 goto decode_success;
29196 /* fallthrough to dis_vx_scalar_quad_precision */
29198 /* Instructions implemented with Pre ISA 3.0 Iops */
29199 /* VSX Scalar Quad-Precision instructions */
29200 case 0x064: // xscpsgnqp
29201 case 0x0A4: // xscmpexpqp
29202 case 0x084: // xscmpoqp
29203 case 0x284: // xscmpuqp
29204 case 0x2C4: // xststdcqp
29205 case 0x364: // xsiexpqp
29206 if (dis_vx_scalar_quad_precision( theInstr )) goto decode_success;
29207 goto decode_failure;
29209 /* Instructions implemented using ISA 3.0 instructions */
29210 // xsaddqpo (VSX Scalar Add Quad-Precision [using round to ODD]
29211 case 0x004: // xsaddqp (VSX Scalar Add Quad-Precision [using RN mode]
29212 // xsmulqpo (VSX Scalar Multiply Quad-Precision [using round to ODD]
29213 case 0x024: // xsmulqp (VSX Scalar Multiply Quad-Precision [using RN mode]
29214 // xsmaddqpo (VSX Scalar Multiply Add Quad-Precision [using round to ODD]
29215 case 0x184: // xsmaddqp (VSX Scalar Multiply Add Quad-Precision [using RN mode]
29216 // xsmsubqpo (VSX Scalar Multiply Sub Quad-Precision [using round to ODD]
29217 case 0x1A4: // xsmsubqp (VSX Scalar Multiply Sub Quad-Precision [using RN mode]
29218 // xsnmaddqpo (VSX Scalar Negative Multiply Add Quad-Precision [using round to ODD]
29219 case 0x1C4: // xsnmaddqp (VSX Scalar Negative Multiply Add Quad-Precision [using RN mode]
29220 // xsnmsubqpo (VSX Scalar Negative Multiply Sub Quad-Precision [using round to ODD]
29221 case 0x1E4: // xsnmsubqp (VSX Scalar Negative Multiply Sub Quad-Precision [usin RN mode]
29222 // xssubqpo (VSX Scalar Subrtact Quad-Precision [using round to ODD]
29223 case 0x204: // xssubqp (VSX Scalar Subrtact Quad-Precision [using RN mode]
29224 // xsdivqpo (VSX Scalar Divde Quad-Precision [using round to ODD]
29225 case 0x224: // xsdivqp (VSX Scalar Divde Quad-Precision [using RN mode]
29226 case 0x344: // xscvudqp, xscvsdqp, xscvqpdp, xscvqpdpo, xsvqpdp
29227 // xscvqpswz, xscvqpuwz, xscvqpudz, xscvqpsdz
29228 if ( !mode64 || !allow_isa_3_0 ) goto decode_failure;
29229 if ( dis_vx_Floating_Point_Arithmetic_quad_precision( theInstr,
29230 abiinfo ) )
29231 goto decode_success;
29232 goto decode_failure;
29234 default:
29235 break; // Fall through...
29238 opc2 = ifieldOPClo9( theInstr );
29239 switch (opc2) {
29240 case 0x42: // dscli, DFP shift left
29241 case 0x62: // dscri, DFP shift right
29242 if (!allow_DFP) goto decode_noDFP;
29243 if (dis_dfp_shiftq( theInstr ))
29244 goto decode_success;
29245 goto decode_failure;
29246 case 0xc2: // dtstdc, DFP test data class
29247 case 0xe2: // dtstdg, DFP test data group
29248 if (!allow_DFP) goto decode_noDFP;
29249 if (dis_dfp_class_test( theInstr ))
29250 goto decode_success;
29251 goto decode_failure;
29252 default:
29253 break;
29256 opc2 = ifieldOPClo8( theInstr );
29257 switch (opc2) {
29258 case 0x3: // dquaq - DFP Quantize Quad
29259 case 0x23: // drrndq - DFP Reround Quad
29260 case 0x43: // dquaiq - DFP Quantize immediate Quad
29261 if (!allow_DFP) goto decode_noDFP;
29262 if (dis_dfp_quantize_sig_rrndq( theInstr ))
29263 goto decode_success;
29264 goto decode_failure;
29265 case 0xA2: // dtstexq - DFP Test exponent Quad
29266 if (!allow_DFP) goto decode_noDFP;
29267 if (dis_dfp_exponent_test( theInstr ) )
29268 goto decode_success;
29269 goto decode_failure;
29270 case 0x63: // drintxq - DFP Round to an integer value
29271 case 0xE3: // drintnq - DFP Round to an integer value
29272 if (!allow_DFP) goto decode_noDFP;
29273 if (dis_dfp_roundq( theInstr ))
29274 goto decode_success;
29275 goto decode_failure;
29277 default:
29278 goto decode_failure;
29280 break;
29282 case 0x13:
29284 opc2 = ifieldOPClo5(theInstr);
29285 switch (opc2) {
29287 /* PC relative load/store */
29288 case 0x002: // addpcis
29289 if (dis_pc_relative(theInstr)) goto decode_success;
29290 goto decode_failure;
29292 /* fall through to the next opc2 field size */
29295 opc2 = ifieldOPClo10(theInstr);
29296 switch (opc2) {
29298 /* Condition Register Logical Instructions */
29299 case 0x101: case 0x081: case 0x121: // crand, crandc, creqv
29300 case 0x0E1: case 0x021: case 0x1C1: // crnand, crnor, cror
29301 case 0x1A1: case 0x0C1: case 0x000: // crorc, crxor, mcrf
29302 if (dis_cond_logic( theInstr )) goto decode_success;
29303 goto decode_failure;
29305 /* Branch Instructions */
29306 case 0x210: case 0x010: // bcctr, bclr
29307 if (dis_branch(theInstr, abiinfo, &dres))
29308 goto decode_success;
29309 goto decode_failure;
29311 /* Memory Synchronization Instructions */
29312 case 0x096: // isync
29313 if (dis_memsync( theInstr )) goto decode_success;
29314 goto decode_failure;
29316 default:
29317 goto decode_failure;
29319 break;
29322 case 0x1F:
29324 /* For arith instns, bit10 is the OE flag (overflow enable) */
29326 opc2 = IFIELD(theInstr, 1, 9);
29327 switch (opc2) {
29328 /* Integer Arithmetic Instructions */
29329 case 0x10A: case 0x00A: case 0x08A: // add, addc, adde
29330 case 0x0AA: // addex
29331 case 0x0EA: case 0x0CA: case 0x1EB: // addme, addze, divw
29332 case 0x1CB: case 0x04B: case 0x00B: // divwu, mulhw, mulhwu
29333 case 0x0EB: case 0x068: case 0x028: // mullw, neg, subf
29334 case 0x008: case 0x088: case 0x0E8: // subfc, subfe, subfme
29335 case 0x0C8: // subfze
29336 if (dis_int_arith( theInstr )) goto decode_success;
29337 goto decode_failure;
29339 case 0x18B: // divweu (implemented as native insn)
29340 case 0x1AB: // divwe (implemented as native insn)
29341 if (!allow_VX) goto decode_noVX;
29342 if (dis_int_arith( theInstr )) goto decode_success;
29343 goto decode_failure;
29345 /* 64bit Integer Arithmetic */
29346 case 0x009: case 0x049: case 0x0E9: // mulhdu, mulhd, mulld
29347 case 0x1C9: case 0x1E9: // divdu, divd
29348 if (!mode64) goto decode_failure;
29349 if (dis_int_arith( theInstr )) goto decode_success;
29350 goto decode_failure;
29352 case 0x1A9: // divde (implemented as native insn)
29353 case 0x189: // divdeuo (implemented as native insn)
29354 if (!allow_VX) goto decode_noVX;
29355 if (!mode64) goto decode_failure;
29356 if (dis_int_arith( theInstr )) goto decode_success;
29357 goto decode_failure;
29359 case 0x1FC: // cmpb
29360 if (dis_int_logic( theInstr )) goto decode_success;
29361 goto decode_failure;
29363 default:
29364 break; // Fall through...
29367 /* All remaining opcodes use full 10 bits. */
29369 opc2 = IFIELD(theInstr, 1, 10);
29370 switch (opc2) {
29372 /* Integer miscellaneous instructions */
29373 case 0x01E: // wait RFC 2500
29374 if (dis_int_misc( theInstr )) goto decode_success;
29375 goto decode_failure;
29378 /* Integer Compare Instructions */
29379 case 0x000: case 0x020: case 0x080: // cmp, cmpl, setb
29380 if (dis_int_cmp( theInstr )) goto decode_success;
29381 goto decode_failure;
29383 case 0x0C0: case 0x0E0: // cmprb, cmpeqb
29384 if (dis_byte_cmp( theInstr )) goto decode_success;
29385 goto decode_failure;
29387 case 0x10B: case 0x30B: // moduw, modsw
29388 case 0x109: case 0x309: // modsd, modud
29389 case 0x21A: case 0x23A: // cnttzw, cnttzd
29390 if (dis_modulo_int( theInstr )) goto decode_success;
29391 goto decode_failure;
29393 /* Integer Logical Instructions */
29394 case 0x01C: case 0x03C: case 0x01A: // and, andc, cntlzw
29395 case 0x11C: case 0x3BA: case 0x39A: // eqv, extsb, extsh
29396 case 0x1DC: case 0x07C: case 0x1BC: // nand, nor, or
29397 case 0x19C: case 0x13C: // orc, xor
29398 case 0x2DF: case 0x25F: // mftgpr, mffgpr
29399 if (dis_int_logic( theInstr )) goto decode_success;
29400 goto decode_failure;
29402 case 0x28E: case 0x2AE: // tbegin., tend.
29403 case 0x2EE: case 0x2CE: case 0x30E: // tsr., tcheck., tabortwc.
29404 case 0x32E: case 0x34E: case 0x36E: // tabortdc., tabortwci., tabortdci.
29405 case 0x38E: case 0x3AE: case 0x3EE: // tabort., treclaim., trechkpt.
29406 if (dis_transactional_memory( theInstr,
29407 getUIntPPCendianly( &guest_code[delta + 4]),
29408 abiinfo, &dres))
29409 goto decode_success;
29410 goto decode_failure;
29412 /* 64bit Integer Logical Instructions */
29413 case 0x3DA: case 0x03A: // extsw, cntlzd
29414 if (!mode64) goto decode_failure;
29415 if (dis_int_logic( theInstr )) goto decode_success;
29416 goto decode_failure;
29418 /* 64bit Integer Parity Instructions */
29419 case 0xba: // prtyd
29420 if (!mode64) goto decode_failure;
29421 if (dis_int_parity( theInstr )) goto decode_success;
29422 goto decode_failure;
29424 case 0x9a: // prtyw
29425 if (dis_int_parity( theInstr )) goto decode_success;
29426 goto decode_failure;
29428 /* Integer Shift Instructions */
29429 case 0x018: case 0x318: case 0x338: // slw, sraw, srawi
29430 case 0x218: // srw
29431 if (dis_int_shift( theInstr )) goto decode_success;
29432 goto decode_failure;
29434 /* 64bit Integer Shift Instructions */
29435 case 0x01B: case 0x31A: // sld, srad
29436 case 0x33A: case 0x33B: // sradi
29437 case 0x21B: // srd
29438 if (!mode64) goto decode_failure;
29439 if (dis_int_shift( theInstr )) goto decode_success;
29440 goto decode_failure;
29442 /* Integer Load Instructions */
29443 case 0x057: case 0x077: case 0x157: // lbzx, lbzux, lhax
29444 case 0x177: case 0x117: case 0x137: // lhaux, lhzx, lhzux
29445 case 0x017: case 0x037: // lwzx, lwzux
29446 if (dis_int_load( theInstr )) goto decode_success;
29447 goto decode_failure;
29449 /* 64bit Integer Load Instructions */
29450 case 0x035: case 0x015: // ldux, ldx
29451 case 0x175: case 0x155: // lwaux, lwax
29452 if (!mode64) goto decode_failure;
29453 if (dis_int_load( theInstr )) goto decode_success;
29454 goto decode_failure;
29456 /* Integer Store Instructions */
29457 case 0x0F7: case 0x0D7: case 0x1B7: // stbux, stbx, sthux
29458 case 0x197: case 0x0B7: case 0x097: // sthx, stwux, stwx
29459 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
29460 goto decode_failure;
29462 /* 64bit Integer Store Instructions */
29463 case 0x0B5: case 0x095: // stdux, stdx
29464 if (!mode64) goto decode_failure;
29465 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
29466 goto decode_failure;
29468 /* Integer Load and Store with Byte Reverse Instructions */
29469 case 0x214: case 0x294: // ldbrx, stdbrx
29470 if (!mode64) goto decode_failure;
29471 if (dis_int_ldst_rev( theInstr )) goto decode_success;
29472 goto decode_failure;
29474 case 0x216: case 0x316: case 0x296: // lwbrx, lhbrx, stwbrx
29475 case 0x396: // sthbrx
29476 if (dis_int_ldst_rev( theInstr )) goto decode_success;
29477 goto decode_failure;
29479 /* Integer Load and Store String Instructions */
29480 case 0x255: case 0x215: case 0x2D5: // lswi, lswx, stswi
29481 case 0x295: { // stswx
29482 Bool stopHere = False;
29483 Bool ok = dis_int_ldst_str( theInstr, &stopHere );
29484 if (!ok) goto decode_failure;
29485 if (stopHere) {
29486 putGST( PPC_GST_CIA, mkSzImm(ty, nextInsnAddr()) );
29487 dres.jk_StopHere = Ijk_Boring;
29488 dres.whatNext = Dis_StopHere;
29490 goto decode_success;
29493 /* Memory Synchronization Instructions */
29494 case 0x034: case 0x074: // lbarx, lharx
29495 case 0x2B6: case 0x2D6: // stbcx, sthcx
29496 if (!allow_isa_2_07) goto decode_noP8;
29497 if (dis_memsync( theInstr )) goto decode_success;
29498 goto decode_failure;
29500 case 0x356: case 0x014: case 0x096: // eieio, lwarx, stwcx.
29501 case 0x256: // sync
29502 if (dis_memsync( theInstr )) goto decode_success;
29503 goto decode_failure;
29505 /* 64bit Memory Synchronization Instructions */
29506 case 0x054: case 0x0D6: // ldarx, stdcx.
29507 if (!mode64) goto decode_failure;
29508 if (dis_memsync( theInstr )) goto decode_success;
29509 goto decode_failure;
29511 case 0x114: case 0x0B6: // lqarx, stqcx.
29512 if (dis_memsync( theInstr )) goto decode_success;
29513 goto decode_failure;
29515 /* Processor Control Instructions */
29516 case 0x33: case 0x73: // mfvsrd, mfvsrwz
29517 case 0xB3: case 0xD3: case 0xF3: // mtvsrd, mtvsrwa, mtvsrwz
29518 case 0x200: case 0x013: case 0x153: // mcrxr, mfcr, mfspr
29519 case 0x173: case 0x090: case 0x1D3: // mftb, mtcrf, mtspr
29520 case 0x220: // mcrxrt
29521 if (dis_proc_ctl( abiinfo, theInstr )) goto decode_success;
29522 goto decode_failure;
29524 /* Cache Management Instructions */
29525 case 0x2F6: case 0x056: case 0x036: // dcba, dcbf, dcbst
29526 case 0x116: case 0x0F6: case 0x3F6: // dcbt, dcbtst, dcbz
29527 case 0x3D6: // icbi
29528 if (dis_cache_manage( theInstr, &dres, archinfo ))
29529 goto decode_success;
29530 goto decode_failure;
29532 //zz /* External Control Instructions */
29533 //zz case 0x136: case 0x1B6: // eciwx, ecowx
29534 //zz DIP("external control op => not implemented\n");
29535 //zz goto decode_failure;
29537 /* Trap Instructions */
29538 case 0x004: // tw
29539 if (dis_trap(theInstr, &dres)) goto decode_success;
29540 goto decode_failure;
29542 case 0x044: // td
29543 if (!mode64) goto decode_failure;
29544 if (dis_trap(theInstr, &dres)) goto decode_success;
29545 goto decode_failure;
29547 /* Floating Point Load Instructions */
29548 case 0x217: case 0x237: case 0x257: // lfsx, lfsux, lfdx
29549 case 0x277: // lfdux
29550 if (!allow_F) goto decode_noF;
29551 if (dis_fp_load( theInstr )) goto decode_success;
29552 goto decode_failure;
29554 /* Floating Point Store Instructions */
29555 case 0x297: case 0x2B7: case 0x2D7: // stfs, stfsu, stfd
29556 case 0x2F7: // stfdu, stfiwx
29557 if (!allow_F) goto decode_noF;
29558 if (dis_fp_store( theInstr )) goto decode_success;
29559 goto decode_failure;
29560 case 0x3D7: // stfiwx
29561 if (!allow_F) goto decode_noF;
29562 if (!allow_GX) goto decode_noGX;
29563 if (dis_fp_store( theInstr )) goto decode_success;
29564 goto decode_failure;
29566 /* Floating Point Double Pair Indexed Instructions */
29567 case 0x317: // lfdpx (Power6)
29568 case 0x397: // stfdpx (Power6)
29569 if (!allow_F) goto decode_noF;
29570 if (dis_fp_pair(theInstr)) goto decode_success;
29571 goto decode_failure;
29573 case 0x357: // lfiwax
29574 if (!allow_F) goto decode_noF;
29575 if (dis_fp_load( theInstr )) goto decode_success;
29576 goto decode_failure;
29578 case 0x377: // lfiwzx
29579 if (!allow_F) goto decode_noF;
29580 if (dis_fp_load( theInstr )) goto decode_success;
29581 goto decode_failure;
29583 /* AltiVec instructions */
29585 /* AV Cache Control - Data streams */
29586 case 0x156: case 0x176: case 0x336: // dst, dstst, dss
29587 if (!allow_V) goto decode_noV;
29588 if (dis_av_datastream( theInstr )) goto decode_success;
29589 goto decode_failure;
29591 /* AV Load */
29592 case 0x006: case 0x026: // lvsl, lvsr
29593 case 0x007: case 0x027: case 0x047: // lvebx, lvehx, lvewx
29594 case 0x067: case 0x167: // lvx, lvxl
29595 if (!allow_V) goto decode_noV;
29596 if (dis_av_load( abiinfo, theInstr )) goto decode_success;
29597 goto decode_failure;
29599 /* AV Store */
29600 case 0x087: case 0x0A7: case 0x0C7: // stvebx, stvehx, stvewx
29601 case 0x0E7: case 0x1E7: // stvx, stvxl
29602 if (!allow_V) goto decode_noV;
29603 if (dis_av_store( theInstr )) goto decode_success;
29604 goto decode_failure;
29606 /* VSX Load */
29607 case 0x00C: // lxsiwzx
29608 case 0x04C: // lxsiwax
29609 case 0x10C: // lxvx
29610 case 0x10D: // lxvl
29611 case 0x12D: // lxvll
29612 case 0x16C: // lxvwsx
29613 case 0x20C: // lxsspx
29614 case 0x24C: // lxsdx
29615 case 0x32C: // lxvh8x
29616 case 0x30D: // lxsibzx
29617 case 0x32D: // lxsihzx
29618 case 0x34C: // lxvd2x
29619 case 0x36C: // lxvb16x
29620 case 0x14C: // lxvdsx
29621 case 0x30C: // lxvw4x
29622 // All of these VSX load instructions use some VMX facilities, so
29623 // if allow_V is not set, we'll skip trying to decode.
29624 if (!allow_V) goto decode_noV;
29626 if (dis_vx_load( theInstr )) goto decode_success;
29627 goto decode_failure;
29629 /* VSX Store */
29630 case 0x08C: // stxsiwx
29631 case 0x18C: // stxvx
29632 case 0x18D: // stxvl
29633 case 0x1AD: // stxvll
29634 case 0x28C: // stxsspx
29635 case 0x2CC: // stxsdx
29636 case 0x38C: // stxvw4x
29637 case 0x3CC: // stxvd2x
29638 case 0x38D: // stxsibx
29639 case 0x3AD: // stxsihx
29640 case 0x3AC: // stxvh8x
29641 case 0x3EC: // stxvb16x
29642 // All of these VSX store instructions use some VMX facilities, so
29643 // if allow_V is not set, we'll skip trying to decode.
29644 if (!allow_V) goto decode_noV;
29646 if (dis_vx_store( theInstr )) goto decode_success;
29647 goto decode_failure;
29649 case 0x133: case 0x193: case 0x1B3: // mfvsrld, mfvsrdd, mtvsrws
29650 // The move from/to VSX instructions use some VMX facilities, so
29651 // if allow_V is not set, we'll skip trying to decode.
29652 if (!allow_V) goto decode_noV;
29653 if (dis_vx_move( theInstr )) goto decode_success;
29654 goto decode_failure;
29656 /* Miscellaneous ISA 2.06 instructions */
29657 case 0x1FA: // popcntd
29658 if (!mode64) goto decode_failure;
29659 /* else fallthru */
29660 case 0x17A: // popcntw
29661 case 0x7A: // popcntb
29662 if (dis_int_logic( theInstr )) goto decode_success;
29663 goto decode_failure;
29665 case 0x0FC: // bpermd
29666 if (!mode64) goto decode_failure;
29667 if (dis_int_logic( theInstr )) goto decode_success;
29668 goto decode_failure;
29670 default:
29671 /* Deal with some other cases that we would otherwise have
29672 punted on. */
29673 /* --- ISEL (PowerISA_V2.05.pdf, p74) --- */
29674 /* only decode this insn when reserved bit 0 (31 in IBM's
29675 notation) is zero */
29676 if (IFIELD(theInstr, 0, 6) == (15<<1)) {
29677 UInt rT = ifieldRegDS( theInstr );
29678 UInt rA = ifieldRegA( theInstr );
29679 UInt rB = ifieldRegB( theInstr );
29680 UInt bi = ifieldRegC( theInstr );
29681 putIReg(
29683 IRExpr_ITE( binop(Iop_CmpNE32, getCRbit( bi ), mkU32(0)),
29684 rA == 0 ? (mode64 ? mkU64(0) : mkU32(0))
29685 : getIReg(rA),
29686 getIReg(rB))
29689 DIP("isel r%u,r%u,r%u,crb%u\n", rT,rA,rB,bi);
29690 goto decode_success;
29694 opc2 = IFIELD(theInstr, 2, 9);
29695 switch (opc2) {
29696 case 0x1BD:
29697 if (!mode64) goto decode_failure;
29698 if (dis_int_logic( theInstr )) goto decode_success;
29699 goto decode_failure;
29701 default:
29702 goto decode_failure;
29704 break;
29707 case 0x04:
29708 /* AltiVec instructions */
29710 opc2 = IFIELD(theInstr, 0, 6);
29711 switch (opc2) {
29712 /* AV Mult-Add, Mult-Sum */
29713 case 0x20: case 0x21: case 0x22: // vmhaddshs, vmhraddshs, vmladduhm
29714 case 0x23: // vmsumudm
29715 case 0x24: case 0x25: case 0x26: // vmsumubm, vmsummbm, vmsumuhm
29716 case 0x27: case 0x28: case 0x29: // vmsumuhs, vmsumshm, vmsumshs
29717 if (!allow_V) goto decode_noV;
29718 if (dis_av_multarith( theInstr )) goto decode_success;
29719 goto decode_failure;
29721 case 0x30: case 0x31: case 0x33: // maddhd, madhdu, maddld
29722 if (!mode64) goto decode_failure;
29723 if (dis_int_mult_add( theInstr )) goto decode_success;
29724 goto decode_failure;
29726 /* AV Permutations */
29727 case 0x2A: // vsel
29728 case 0x2B: // vperm
29729 case 0x2C: // vsldoi
29730 if (!allow_V) goto decode_noV;
29731 if (dis_av_permute( theInstr )) goto decode_success;
29732 goto decode_failure;
29734 case 0x2D: // vpermxor
29735 case 0x3B: // vpermr
29736 if (!allow_isa_2_07) goto decode_noP8;
29737 if (dis_av_permute( theInstr )) goto decode_success;
29738 goto decode_failure;
29740 /* AV Floating Point Mult-Add/Sub */
29741 case 0x2E: case 0x2F: // vmaddfp, vnmsubfp
29742 if (!allow_V) goto decode_noV;
29743 if (dis_av_fp_arith( theInstr )) goto decode_success;
29744 goto decode_failure;
29746 case 0x3D: case 0x3C: // vaddecuq, vaddeuqm
29747 case 0x3F: case 0x3E: // vsubecuq, vsubeuqm
29748 if (!allow_V) goto decode_noV;
29749 if (dis_av_quad( theInstr)) goto decode_success;
29750 goto decode_failure;
29752 default:
29753 break; // Fall through...
29756 opc2 = IFIELD(theInstr, 0, 9);
29757 if (IFIELD(theInstr, 10, 1) == 1) {
29758 /* The following instructions have bit 21 set and a PS bit (bit 22)
29759 * Bit 21 distinquishes them from instructions with an 11 bit opc2
29760 * field.
29762 switch (opc2) {
29763 /* BCD arithmetic */
29764 case 0x001: case 0x041: // bcdadd, bcdsub
29765 case 0x101: case 0x141: // bcdtrunc., bcdutrunc.
29766 case 0x081: case 0x0C1: case 0x1C1: // bcdus., bcds., bcdsr.
29767 case 0x181: // bcdcfn., bcdcfz.
29768 // bcdctz., bcdcfsq., bcdctsq.
29769 if (!allow_isa_2_07) goto decode_noP8;
29770 if (dis_av_bcd( theInstr, abiinfo )) goto decode_success;
29771 goto decode_failure;
29772 default:
29773 break; // Fall through...
29777 opc2 = IFIELD(theInstr, 0, 11);
29778 switch (opc2) {
29779 /* BCD manipulation */
29780 case 0x341: // bcdcpsgn
29782 if (!allow_isa_2_07) goto decode_noP8;
29783 if (dis_av_bcd_misc( theInstr, abiinfo )) goto decode_success;
29784 goto decode_failure;
29787 /* AV Arithmetic */
29788 case 0x180: // vaddcuw
29789 case 0x000: case 0x040: case 0x080: // vaddubm, vadduhm, vadduwm
29790 case 0x200: case 0x240: case 0x280: // vaddubs, vadduhs, vadduws
29791 case 0x300: case 0x340: case 0x380: // vaddsbs, vaddshs, vaddsws
29792 case 0x580: // vsubcuw
29793 case 0x400: case 0x440: case 0x480: // vsububm, vsubuhm, vsubuwm
29794 case 0x600: case 0x640: case 0x680: // vsububs, vsubuhs, vsubuws
29795 case 0x700: case 0x740: case 0x780: // vsubsbs, vsubshs, vsubsws
29796 case 0x402: case 0x442: case 0x482: // vavgub, vavguh, vavguw
29797 case 0x502: case 0x542: case 0x582: // vavgsb, vavgsh, vavgsw
29798 case 0x002: case 0x042: case 0x082: // vmaxub, vmaxuh, vmaxuw
29799 case 0x102: case 0x142: case 0x182: // vmaxsb, vmaxsh, vmaxsw
29800 case 0x202: case 0x242: case 0x282: // vminub, vminuh, vminuw
29801 case 0x302: case 0x342: case 0x382: // vminsb, vminsh, vminsw
29802 case 0x008: case 0x048: // vmuloub, vmulouh
29803 case 0x108: case 0x148: // vmulosb, vmulosh
29804 case 0x208: case 0x248: // vmuleub, vmuleuh
29805 case 0x308: case 0x348: // vmulesb, vmulesh
29806 case 0x608: case 0x708: case 0x648: // vsum4ubs, vsum4sbs, vsum4shs
29807 case 0x688: case 0x788: // vsum2sws, vsumsws
29808 if (!allow_V) goto decode_noV;
29809 if (dis_av_arith( theInstr )) goto decode_success;
29810 goto decode_failure;
29812 case 0x088: case 0x089: // vmulouw, vmuluwm
29813 case 0x0C0: case 0x0C2: // vaddudm, vmaxud
29814 case 0x1C2: case 0x2C2: case 0x3C2: // vnaxsd, vminud, vminsd
29815 case 0x188: case 0x288: case 0x388: // vmulosw, vmuleuw, vmulesw
29816 case 0x4C0: // vsubudm
29817 if (!allow_isa_2_07) goto decode_noP8;
29818 if (dis_av_arith( theInstr )) goto decode_success;
29819 goto decode_failure;
29821 /* AV Polynomial Vector Multiply Add */
29822 case 0x408: case 0x448: // vpmsumb, vpmsumd
29823 case 0x488: case 0x4C8: // vpmsumw, vpmsumh
29824 if (!allow_isa_2_07) goto decode_noP8;
29825 if (dis_av_polymultarith( theInstr )) goto decode_success;
29826 goto decode_failure;
29828 /* AV Rotate, Shift */
29829 case 0x004: case 0x044: case 0x084: // vrlb, vrlh, vrlw
29830 case 0x104: case 0x144: case 0x184: // vslb, vslh, vslw
29831 case 0x204: case 0x244: case 0x284: // vsrb, vsrh, vsrw
29832 case 0x304: case 0x344: case 0x384: // vsrab, vsrah, vsraw
29833 case 0x1C4: case 0x2C4: // vsl, vsr
29834 case 0x40C: case 0x44C: // vslo, vsro
29835 if (!allow_V) goto decode_noV;
29836 if (dis_av_shift( theInstr )) goto decode_success;
29837 goto decode_failure;
29839 case 0x0C4: // vrld
29840 case 0x3C4: case 0x5C4: case 0x6C4: // vsrad, vsld, vsrd
29841 if (!allow_isa_2_07) goto decode_noP8;
29842 if (dis_av_shift( theInstr )) goto decode_success;
29843 goto decode_failure;
29845 /* AV Logic */
29846 case 0x404: case 0x444: case 0x484: // vand, vandc, vor
29847 case 0x4C4: case 0x504: // vxor, vnor
29848 if (!allow_V) goto decode_noV;
29849 if (dis_av_logic( theInstr )) goto decode_success;
29850 goto decode_failure;
29852 case 0x544: // vorc
29853 case 0x584: case 0x684: // vnand, veqv
29854 if (!allow_isa_2_07) goto decode_noP8;
29855 if (dis_av_logic( theInstr )) goto decode_success;
29856 goto decode_failure;
29858 /* AV Rotate */
29859 case 0x085: case 0x185: // vrlwmi, vrlwnm
29860 case 0x0C5: case 0x1C5: // vrldmi, vrldnm
29861 if (!allow_V) goto decode_noV;
29862 if (dis_av_rotate( theInstr )) goto decode_success;
29863 goto decode_failure;
29865 /* AV Processor Control */
29866 case 0x604: case 0x644: // mfvscr, mtvscr
29867 if (!allow_V) goto decode_noV;
29868 if (dis_av_procctl( theInstr )) goto decode_success;
29869 goto decode_failure;
29871 /* AV Vector Extract Element instructions */
29872 case 0x60D: case 0x64D: case 0x68D: // vextublx, vextuhlx, vextuwlx
29873 case 0x70D: case 0x74D: case 0x78D: // vextubrx, vextuhrx, vextuwrx
29874 if (!allow_V) goto decode_noV;
29875 if (dis_av_extract_element( theInstr )) goto decode_success;
29876 goto decode_failure;
29879 /* AV Floating Point Arithmetic */
29880 case 0x00A: case 0x04A: // vaddfp, vsubfp
29881 case 0x10A: case 0x14A: case 0x18A: // vrefp, vrsqrtefp, vexptefp
29882 case 0x1CA: // vlogefp
29883 case 0x40A: case 0x44A: // vmaxfp, vminfp
29884 if (!allow_V) goto decode_noV;
29885 if (dis_av_fp_arith( theInstr )) goto decode_success;
29886 goto decode_failure;
29888 /* AV Floating Point Round/Convert */
29889 case 0x20A: case 0x24A: case 0x28A: // vrfin, vrfiz, vrfip
29890 case 0x2CA: // vrfim
29891 case 0x30A: case 0x34A: case 0x38A: // vcfux, vcfsx, vctuxs
29892 case 0x3CA: // vctsxs
29893 if (!allow_V) goto decode_noV;
29894 if (dis_av_fp_convert( theInstr )) goto decode_success;
29895 goto decode_failure;
29897 /* AV Merge, Splat, Extract, Insert */
29898 case 0x00C: case 0x04C: case 0x08C: // vmrghb, vmrghh, vmrghw
29899 case 0x10C: case 0x14C: case 0x18C: // vmrglb, vmrglh, vmrglw
29900 case 0x20C: case 0x24C: case 0x28C: // vspltb, vsplth, vspltw
29901 case 0x20D: case 0x24D: // vextractub, vextractuh,
29902 case 0x28D: case 0x2CD: // vextractuw, vextractd,
29903 case 0x30D: case 0x34D: // vinsertb, vinserth
29904 case 0x38D: case 0x3CD: // vinsertw, vinsertd
29905 case 0x30C: case 0x34C: case 0x38C: // vspltisb, vspltish, vspltisw
29906 if (!allow_V) goto decode_noV;
29907 if (dis_av_permute( theInstr )) goto decode_success;
29908 goto decode_failure;
29910 case 0x68C: case 0x78C: // vmrgow, vmrgew
29911 if (!allow_isa_2_07) goto decode_noP8;
29912 if (dis_av_permute( theInstr )) goto decode_success;
29913 goto decode_failure;
29915 /* AltiVec 128 bit integer multiply by 10 Instructions */
29916 case 0x201: case 0x001: //vmul10uq, vmul10cuq
29917 case 0x241: case 0x041: //vmul10euq, vmul10ceuq
29918 if (!allow_V) goto decode_noV;
29919 if (!allow_isa_3_0) goto decode_noP9;
29920 if (dis_av_mult10( theInstr )) goto decode_success;
29921 goto decode_failure;
29923 /* AV Pack, Unpack */
29924 case 0x00E: case 0x04E: case 0x08E: // vpkuhum, vpkuwum, vpkuhus
29925 case 0x0CE: // vpkuwus
29926 case 0x10E: case 0x14E: case 0x18E: // vpkshus, vpkswus, vpkshss
29927 case 0x1CE: // vpkswss
29928 case 0x20E: case 0x24E: case 0x28E: // vupkhsb, vupkhsh, vupklsb
29929 case 0x2CE: // vupklsh
29930 case 0x30E: case 0x34E: case 0x3CE: // vpkpx, vupkhpx, vupklpx
29931 if (!allow_V) goto decode_noV;
29932 if (dis_av_pack( theInstr )) goto decode_success;
29933 goto decode_failure;
29935 case 0x403: case 0x443: case 0x483: // vabsdub, vabsduh, vabsduw
29936 if (!allow_V) goto decode_noV;
29937 if (dis_abs_diff( theInstr )) goto decode_success;
29938 goto decode_failure;
29940 case 0x44E: case 0x4CE: case 0x54E: // vpkudum, vpkudus, vpksdus
29941 case 0x5CE: case 0x64E: case 0x6cE: // vpksdss, vupkhsw, vupklsw
29942 if (!allow_isa_2_07) goto decode_noP8;
29943 if (dis_av_pack( theInstr )) goto decode_success;
29944 goto decode_failure;
29946 case 0x508: case 0x509: // vcipher, vcipherlast
29947 case 0x548: case 0x549: // vncipher, vncipherlast
29948 case 0x5C8: // vsbox
29949 if (!allow_isa_2_07) goto decode_noP8;
29950 if (dis_av_cipher( theInstr )) goto decode_success;
29951 goto decode_failure;
29953 /* AV Vector Extend Sign Instructions and
29954 * Vector Count Leading/Trailing zero Least-Significant bits Byte.
29955 * Vector Integer Negate Instructions
29957 case 0x602: // vextsb2w, vextsh2w, vextsb2d, vextsh2d, vextsw2d
29958 // vclzlsbb and vctzlsbb
29959 // vnegw, vnegd
29960 // vprtybw, vprtybd, vprtybq
29961 // vctzb, vctzh, vctzw, vctzd
29962 if (!allow_V) goto decode_noV;
29963 if (dis_av_extend_sign_count_zero( theInstr, allow_isa_3_0 ))
29964 goto decode_success;
29965 goto decode_failure;
29967 case 0x6C2: case 0x682: // vshasigmaw, vshasigmad
29968 if (!allow_isa_2_07) goto decode_noP8;
29969 if (dis_av_hash( theInstr )) goto decode_success;
29970 goto decode_failure;
29972 case 0x702: case 0x742: // vclzb, vclzh
29973 case 0x782: case 0x7c2: // vclzw, vclzd
29974 if (!allow_isa_2_07) goto decode_noP8;
29975 if (dis_av_count_bitTranspose( theInstr, opc2 )) goto decode_success;
29976 goto decode_failure;
29978 case 0x703: case 0x743: // vpopcntb, vpopcnth
29979 case 0x783: case 0x7c3: // vpopcntw, vpopcntd
29980 if (!allow_isa_2_07) goto decode_noP8;
29981 if (dis_av_count_bitTranspose( theInstr, opc2 )) goto decode_success;
29982 goto decode_failure;
29984 case 0x50c: // vgbbd
29985 case 0x5cc: // vbpermd
29986 if (!allow_isa_2_07) goto decode_noP8;
29987 if (dis_av_count_bitTranspose( theInstr, opc2 )) goto decode_success;
29988 goto decode_failure;
29990 case 0x140: case 0x100: // vaddcuq, vadduqm
29991 case 0x540: case 0x500: // vsubcuq, vsubuqm
29992 case 0x54C: // vbpermq
29993 if (!allow_V) goto decode_noV;
29994 if (dis_av_quad( theInstr)) goto decode_success;
29995 goto decode_failure;
29997 default:
29998 break; // Fall through...
30001 opc2 = IFIELD(theInstr, 0, 10);
30002 switch (opc2) {
30004 /* AV Compare */
30005 case 0x006: case 0x007: case 0x107: // vcmpequb, vcmpneb, vcmpnezb
30006 case 0x046: case 0x047: case 0x147: // vcmpequh, vcmpneh, vcmpnezh
30007 case 0x086: case 0x087: case 0x187: // vcmpequw, vcmpnew, vcmpnezw
30008 case 0x206: case 0x246: case 0x286: // vcmpgtub, vcmpgtuh, vcmpgtuw
30009 case 0x306: case 0x346: case 0x386: // vcmpgtsb, vcmpgtsh, vcmpgtsw
30010 if (!allow_V) goto decode_noV;
30011 if (dis_av_cmp( theInstr )) goto decode_success;
30012 goto decode_failure;
30014 case 0x0C7: // vcmpequd
30015 case 0x2C7: // vcmpgtud
30016 case 0x3C7: // vcmpgtsd
30017 if (!allow_isa_2_07) goto decode_noP8;
30018 if (dis_av_cmp( theInstr )) goto decode_success;
30019 goto decode_failure;
30021 /* AV Floating Point Compare */
30022 case 0x0C6: case 0x1C6: case 0x2C6: // vcmpeqfp, vcmpgefp, vcmpgtfp
30023 case 0x3C6: // vcmpbfp
30024 if (!allow_V) goto decode_noV;
30025 if (dis_av_fp_cmp( theInstr )) goto decode_success;
30026 goto decode_failure;
30028 default:
30029 goto decode_failure;
30031 break;
30033 default:
30034 goto decode_failure;
30036 decode_noF:
30037 vassert(!allow_F);
30038 if (sigill_diag)
30039 vex_printf("disInstr(ppc): found the Floating Point instruction 0x%x that\n"
30040 "can't be handled by Valgrind on this host. This instruction\n"
30041 "requires a host that supports Floating Point instructions.\n",
30042 theInstr);
30043 goto not_supported;
30044 decode_noV:
30045 vassert(!allow_V);
30046 if (sigill_diag)
30047 vex_printf("disInstr(ppc): found an AltiVec or an e500 instruction 0x%x\n"
30048 "that can't be handled by Valgrind. If this instruction is an\n"
30049 "Altivec instruction, Valgrind must be run on a host that supports"
30050 "AltiVec instructions. If the application was compiled for e500, then\n"
30051 "unfortunately Valgrind does not yet support e500 instructions.\n",
30052 theInstr);
30053 goto not_supported;
30054 decode_noVX:
30055 vassert(!allow_VX);
30056 if (sigill_diag)
30057 vex_printf("disInstr(ppc): found the instruction 0x%x that is defined in the\n"
30058 "Power ISA 2.06 ABI but can't be handled by Valgrind on this host.\n"
30059 "This instruction \nrequires a host that supports the ISA 2.06 ABI.\n",
30060 theInstr);
30061 goto not_supported;
30062 decode_noFX:
30063 vassert(!allow_FX);
30064 if (sigill_diag)
30065 vex_printf("disInstr(ppc): found the General Purpose-Optional instruction 0x%x\n"
30066 "that can't be handled by Valgrind on this host. This instruction\n"
30067 "requires a host that supports the General Purpose-Optional instructions.\n",
30068 theInstr);
30069 goto not_supported;
30070 decode_noGX:
30071 vassert(!allow_GX);
30072 if (sigill_diag)
30073 vex_printf("disInstr(ppc): found the Graphics-Optional instruction 0x%x\n"
30074 "that can't be handled by Valgrind on this host. This instruction\n"
30075 "requires a host that supports the Graphic-Optional instructions.\n",
30076 theInstr);
30077 goto not_supported;
30078 decode_noDFP:
30079 vassert(!allow_DFP);
30080 if (sigill_diag)
30081 vex_printf("disInstr(ppc): found the decimal floating point (DFP) instruction 0x%x\n"
30082 "that can't be handled by Valgrind on this host. This instruction\n"
30083 "requires a host that supports DFP instructions.\n",
30084 theInstr);
30085 goto not_supported;
30086 decode_noP8:
30087 vassert(!allow_isa_2_07);
30088 if (sigill_diag)
30089 vex_printf("disInstr(ppc): found the Power 8 instruction 0x%x that can't be handled\n"
30090 "by Valgrind on this host. This instruction requires a host that\n"
30091 "supports Power 8 instructions.\n",
30092 theInstr);
30093 goto not_supported;
30095 decode_noP9:
30096 vassert(!allow_isa_3_0);
30097 if (sigill_diag)
30098 vex_printf("disInstr(ppc): found the Power 9 instruction 0x%x that can't be handled\n"
30099 "by Valgrind on this host. This instruction requires a host that\n"
30100 "supports Power 9 instructions.\n",
30101 theInstr);
30102 goto not_supported;
30104 decode_failure:
30105 /* All decode failures end up here. */
30106 opc2 = (theInstr) & 0x7FF;
30107 if (sigill_diag) {
30108 vex_printf("disInstr(ppc): unhandled instruction: "
30109 "0x%x\n", theInstr);
30110 vex_printf(" primary %d(0x%x), secondary %u(0x%x)\n",
30111 opc1, opc1, opc2, opc2);
30114 not_supported:
30115 /* Tell the dispatcher that this insn cannot be decoded, and so has
30116 not been executed, and (is currently) the next to be executed.
30117 CIA should be up-to-date since it made so at the start of each
30118 insn, but nevertheless be paranoid and update it again right
30119 now. */
30120 putGST( PPC_GST_CIA, mkSzImm(ty, guest_CIA_curr_instr) );
30121 dres.len = 0;
30122 dres.whatNext = Dis_StopHere;
30123 dres.jk_StopHere = Ijk_NoDecode;
30124 return dres;
30125 } /* switch (opc) for the main (primary) opcode switch. */
30127 decode_success:
30128 /* All decode successes end up here. */
30129 switch (dres.whatNext) {
30130 case Dis_Continue:
30131 putGST( PPC_GST_CIA, mkSzImm(ty, guest_CIA_curr_instr + 4));
30132 break;
30133 case Dis_StopHere:
30134 break;
30135 default:
30136 vassert(0);
30138 DIP("\n");
30140 if (dres.len == 0) {
30141 dres.len = 4;
30142 } else {
30143 vassert(dres.len == 20);
30145 return dres;
30148 #undef DIP
30149 #undef DIS
30152 /*------------------------------------------------------------*/
30153 /*--- Top-level fn ---*/
30154 /*------------------------------------------------------------*/
30156 /* Disassemble a single instruction into IR. The instruction
30157 is located in host memory at &guest_code[delta]. */
30159 DisResult disInstr_PPC ( IRSB* irsb_IN,
30160 const UChar* guest_code_IN,
30161 Long delta,
30162 Addr guest_IP,
30163 VexArch guest_arch,
30164 const VexArchInfo* archinfo,
30165 const VexAbiInfo* abiinfo,
30166 VexEndness host_endness_IN,
30167 Bool sigill_diag_IN )
30169 IRType ty;
30170 DisResult dres;
30171 UInt mask32, mask64;
30172 UInt hwcaps_guest = archinfo->hwcaps;
30174 vassert(guest_arch == VexArchPPC32 || guest_arch == VexArchPPC64);
30176 /* global -- ick */
30177 mode64 = guest_arch == VexArchPPC64;
30178 ty = mode64 ? Ity_I64 : Ity_I32;
30179 if (!mode64 && (host_endness_IN == VexEndnessLE)) {
30180 vex_printf("disInstr(ppc): Little Endian 32-bit mode is not supported\n");
30181 dres.len = 0;
30182 dres.whatNext = Dis_StopHere;
30183 dres.jk_StopHere = Ijk_NoDecode;
30184 dres.hint = Dis_HintNone;
30185 return dres;
30188 /* do some sanity checks */
30189 mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
30190 | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX
30191 | VEX_HWCAPS_PPC32_DFP | VEX_HWCAPS_PPC32_ISA2_07;
30193 mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
30194 | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP
30195 | VEX_HWCAPS_PPC64_ISA2_07 | VEX_HWCAPS_PPC64_ISA3_0;
30197 if (mode64) {
30198 vassert((hwcaps_guest & mask32) == 0);
30199 } else {
30200 vassert((hwcaps_guest & mask64) == 0);
30203 /* Set globals (see top of this file) */
30204 guest_code = guest_code_IN;
30205 irsb = irsb_IN;
30206 host_endness = host_endness_IN;
30208 guest_CIA_curr_instr = mkSzAddr(ty, guest_IP);
30209 guest_CIA_bbstart = mkSzAddr(ty, guest_IP - delta);
30211 dres = disInstr_PPC_WRK ( delta, archinfo, abiinfo, sigill_diag_IN );
30213 return dres;
30216 /*--------------------------------------------------------------------*/
30217 /*--- end guest_ppc_toIR.c ---*/
30218 /*--------------------------------------------------------------------*/