Add a test program for the membarrier() system call
[valgrind.git] / VEX / priv / guest_ppc_toIR.c
blob7fd7780bbf29463b6c43ed6b6d60c05c4a3ca584
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, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 02110-1301, USA.
28 The GNU General Public License is contained in the file COPYING.
30 Neither the names of the U.S. Department of Energy nor the
31 University of California nor the names of its contributors may be
32 used to endorse or promote products derived from this software
33 without prior written permission.
36 /* TODO 18/Nov/05:
38 Spot rld... cases which are simply left/right shifts and emit
39 Shl64/Shr64 accordingly.
41 Altivec
42 - datastream insns
43 - lvxl,stvxl: load/store with 'least recently used' hint
44 - vexptefp, vlogefp
46 LIMITATIONS:
48 Various, including:
50 - Some invalid forms of lswi and lswx are accepted when they should
51 not be.
53 - Floating Point:
54 - All exceptions disabled in FPSCR
55 - condition codes not set in FPSCR
57 - Altivec floating point:
58 - vmaddfp, vnmsubfp
59 Because we're using Java/IEEE mode (FPSCR[NJ]), rather than the
60 system default of Non-Java mode, we get some small errors
61 (lowest bit only).
62 This is because Non-Java mode brutally hacks denormalised results
63 to zero, whereas we keep maximum accuracy. However, using
64 Non-Java mode would give us more inaccuracy, as our intermediate
65 results would then be zeroed, too.
67 - AbiHints for the stack red zone are only emitted for
68 unconditional calls and returns (bl, blr). They should also be
69 emitted for conditional calls and returns, but we don't have a
70 way to express that right now. Ah well.
72 - Uses of Iop_{Add,Sub,Mul}32Fx4: the backend (host_ppc_isel.c)
73 ignores the rounding mode, and generates code that assumes
74 round-to-nearest. This means V will compute incorrect results
75 for uses of these IROps when the rounding mode (first) arg is
76 not mkU32(Irrm_NEAREST).
79 /* "Special" instructions.
81 This instruction decoder can decode four special instructions
82 which mean nothing natively (are no-ops as far as regs/mem are
83 concerned) but have meaning for supporting Valgrind. A special
84 instruction is flagged by a 16-byte preamble:
86 32-bit mode: 5400183E 5400683E 5400E83E 5400983E
87 (rlwinm 0,0,3,0,31; rlwinm 0,0,13,0,31;
88 rlwinm 0,0,29,0,31; rlwinm 0,0,19,0,31)
90 64-bit mode: 78001800 78006800 7800E802 78009802
91 (rotldi 0,0,3; rotldi 0,0,13;
92 rotldi 0,0,61; rotldi 0,0,51)
94 Following that, one of the following 3 are allowed
95 (standard interpretation in parentheses):
97 7C210B78 (or 1,1,1) %R3 = client_request ( %R4 )
98 7C421378 (or 2,2,2) %R3 = guest_NRADDR
99 7C631B78 (or 3,3,3) branch-and-link-to-noredir %R11 Big endian
100 7C631B78 (or 3,3,3) branch-and-link-to-noredir %R12 Little endian
101 7C842378 (or 4,4,4) %R3 = guest_NRADDR_GPR2
102 7CA52B78 (or 5,5,5) IR injection
104 Any other bytes following the 16-byte preamble are illegal and
105 constitute a failure in instruction decoding. This all assumes
106 that the preamble will never occur except in specific code
107 fragments designed for Valgrind to catch.
110 /* Little Endian notes */
112 * Vector operations in little Endian mode behave in non-obvious ways at times.
113 * Below is an attempt at explaining this.
115 * LE/BE vector example
116 * With a vector of unsigned ints declared as follows:
117 * vector unsigned int vec_inA =
118 { 0x11111111, 0x22222222, 0x33333333, 0x44444444 };
119 * The '0x11111111' word is word zero in both LE and BE format. But the
120 * loaded vector register will have word zero on the far left in BE mode and
121 * on the far right in LE mode. The lvx and stvx instructions work naturally
122 * for whatever endianness is in effect. For example, in LE mode, the stvx
123 * stores word zero (far right word) of the vector at the lowest memory
124 * address of the EA; in BE mode, stvx still stores word zero at the lowest
125 * memory address, but with word zero interpreted as the one at the far left
126 * of the register.
128 * The lxvd2x and stxvd2x instructions are not so well suited for LE mode.
129 * When the compiler generates an lxvd2x instruction to load the
130 * above-declared vector of unsigned integers, it loads the vector as two
131 * double words, but they are in BE word-wise format. To put the vector in
132 * the right order for LE, the compiler also generates an xxswapd after the
133 * load, which puts it in proper LE format. Similarly, the stxvd2x
134 * instruction has a BE bias, storing the vector in BE word-wise format. But
135 * the compiler also generates an xxswapd prior to the store, thus ensuring
136 * the vector is stored in memory in the correct LE order.
138 * Vector-flavored Iops, such Iop_V128Hito64, reference the hi and lo parts
139 * of a double words and words within a vector. Because of the reverse order
140 * of numbering for LE as described above, the high part refers to word 1 in
141 * LE format. When input data is saved to a guest state vector register
142 * (e.g., via Iop_64HLtoV128), it is first saved to memory and then the
143 * register is loaded via PPCInstr_AvLdSt, which does an lvx instruction.
144 * The saving of the data to memory must be done in proper LE order. For the
145 * inverse operation of extracting data from a vector register (e.g.,
146 * Iop_V128Hito64), the register is first saved (by PPCInstr_AvLdSt resulting
147 * in stvx), and then integer registers are loaded from the memory location
148 * from where the vector register was saved. Again, this must be done in
149 * proper LE order. So for these various vector Iops, we have LE-specific
150 * code in host_ppc_isel.c
152 * Another unique behavior of vectors in LE mode is with the vector scalar
153 * (VSX) operations that operate on "double word 0" of the source register,
154 * storing the result in "double word 0" of the output vector register. For
155 * these operations, "double word 0" is interpreted as "high half of the
156 * register" (i.e, the part on the left side).
159 /* Translates PPC32/64 code to IR. */
161 /* References
163 #define PPC32
164 "PowerPC Microprocessor Family:
165 The Programming Environments Manual for 32-Bit Microprocessors"
166 02/21/2000
167 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF778525699600719DF2
169 #define PPC64
170 "PowerPC Microprocessor Family:
171 Programming Environments Manual for 64-Bit Microprocessors"
172 06/10/2003
173 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/F7E732FF811F783187256FDD004D3797
175 #define AV
176 "PowerPC Microprocessor Family:
177 AltiVec(TM) Technology Programming Environments Manual"
178 07/10/2003
179 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/FBFA164F824370F987256D6A006F424D
182 #include "libvex_basictypes.h"
183 #include "libvex_ir.h"
184 #include "libvex.h"
185 #include "libvex_emnote.h"
186 #include "libvex_guest_ppc32.h"
187 #include "libvex_guest_ppc64.h"
189 #include "main_util.h"
190 #include "main_globals.h"
191 #include "guest_generic_bb_to_IR.h"
192 #include "guest_ppc_defs.h"
194 /*------------------------------------------------------------*/
195 /*--- Globals ---*/
196 /*------------------------------------------------------------*/
198 /* These are set at the start of the translation of an insn, right
199 down in disInstr_PPC, so that we don't have to pass them around
200 endlessly. They are all constant during the translation of any
201 given insn. */
203 /* We need to know this to do sub-register accesses correctly. */
204 static VexEndness host_endness;
206 /* Pointer to the guest code area. */
207 static const UChar* guest_code;
209 /* The guest address corresponding to guest_code[0]. */
210 static Addr64 guest_CIA_bbstart;
212 /* The guest address for the instruction currently being
213 translated. */
214 static Addr64 guest_CIA_curr_instr;
216 /* The IRSB* into which we're generating code. */
217 static IRSB* irsb;
219 /* Is our guest binary 32 or 64bit? Set at each call to
220 disInstr_PPC below. */
221 static Bool mode64 = False;
223 // Given a pointer to a function as obtained by "& functionname" in C,
224 // produce a pointer to the actual entry point for the function. For
225 // most platforms it's the identity function. Unfortunately, on
226 // ppc64-linux it isn't (sigh)
227 static void* fnptr_to_fnentry( const VexAbiInfo* vbi, void* f )
229 if (vbi->host_ppc_calls_use_fndescrs) {
230 /* f is a pointer to a 3-word function descriptor, of which the
231 first word is the entry address. */
232 /* note, this is correct even with cross-jitting, since this is
233 purely a host issue, not a guest one. */
234 HWord* fdescr = (HWord*)f;
235 return (void*)(fdescr[0]);
236 } else {
237 /* Simple; "& f" points directly at the code for f. */
238 return f;
242 /* The OV32 and CA32 bits were added with ISA3.0 */
243 static Bool OV32_CA32_supported = False;
245 #define SIGN_BIT 0x8000000000000000ULL
246 #define SIGN_MASK 0x7fffffffffffffffULL
247 #define SIGN_BIT32 0x80000000
248 #define SIGN_MASK32 0x7fffffff
251 /*------------------------------------------------------------*/
252 /*--- Debugging output ---*/
253 /*------------------------------------------------------------*/
255 #define DIP(format, args...) \
256 if (vex_traceflags & VEX_TRACE_FE) \
257 vex_printf(format, ## args)
259 #define DIS(buf, format, args...) \
260 if (vex_traceflags & VEX_TRACE_FE) \
261 vex_sprintf(buf, format, ## args)
264 /*------------------------------------------------------------*/
265 /*--- Offsets of various parts of the ppc32/64 guest state ---*/
266 /*------------------------------------------------------------*/
268 #define offsetofPPCGuestState(_x) \
269 (mode64 ? offsetof(VexGuestPPC64State, _x) : \
270 offsetof(VexGuestPPC32State, _x))
272 #define OFFB_CIA offsetofPPCGuestState(guest_CIA)
273 #define OFFB_IP_AT_SYSCALL offsetofPPCGuestState(guest_IP_AT_SYSCALL)
274 #define OFFB_SPRG3_RO offsetofPPCGuestState(guest_SPRG3_RO)
275 #define OFFB_LR offsetofPPCGuestState(guest_LR)
276 #define OFFB_CTR offsetofPPCGuestState(guest_CTR)
277 #define OFFB_XER_SO offsetofPPCGuestState(guest_XER_SO)
278 #define OFFB_XER_OV offsetofPPCGuestState(guest_XER_OV)
279 #define OFFB_XER_OV32 offsetofPPCGuestState(guest_XER_OV32)
280 #define OFFB_XER_CA offsetofPPCGuestState(guest_XER_CA)
281 #define OFFB_XER_CA32 offsetofPPCGuestState(guest_XER_CA32)
282 #define OFFB_XER_BC offsetofPPCGuestState(guest_XER_BC)
283 #define OFFB_FPROUND offsetofPPCGuestState(guest_FPROUND)
284 #define OFFB_DFPROUND offsetofPPCGuestState(guest_DFPROUND)
285 #define OFFB_C_FPCC offsetofPPCGuestState(guest_C_FPCC)
286 #define OFFB_VRSAVE offsetofPPCGuestState(guest_VRSAVE)
287 #define OFFB_VSCR offsetofPPCGuestState(guest_VSCR)
288 #define OFFB_EMNOTE offsetofPPCGuestState(guest_EMNOTE)
289 #define OFFB_CMSTART offsetofPPCGuestState(guest_CMSTART)
290 #define OFFB_CMLEN offsetofPPCGuestState(guest_CMLEN)
291 #define OFFB_NRADDR offsetofPPCGuestState(guest_NRADDR)
292 #define OFFB_NRADDR_GPR2 offsetofPPCGuestState(guest_NRADDR_GPR2)
293 #define OFFB_TFHAR offsetofPPCGuestState(guest_TFHAR)
294 #define OFFB_TEXASR offsetofPPCGuestState(guest_TEXASR)
295 #define OFFB_TEXASRU offsetofPPCGuestState(guest_TEXASRU)
296 #define OFFB_TFIAR offsetofPPCGuestState(guest_TFIAR)
297 #define OFFB_PPR offsetofPPCGuestState(guest_PPR)
298 #define OFFB_PSPB offsetofPPCGuestState(guest_PSPB)
299 #define OFFB_DSCR offsetofPPCGuestState(guest_DSCR)
302 /*------------------------------------------------------------*/
303 /*--- Extract instruction fields --- */
304 /*------------------------------------------------------------*/
306 /* Extract field from insn, given idx (zero = lsb) and field length */
307 #define IFIELD( insn, idx, len ) ((insn >> idx) & ((1<<len)-1))
309 /* Extract primary opcode, instr[31:26] */
310 static UChar ifieldOPC( UInt instr ) {
311 return toUChar( IFIELD( instr, 26, 6 ) );
314 /* Extract 10-bit secondary opcode, instr[10:1] */
315 static UInt ifieldOPClo10 ( UInt instr) {
316 return IFIELD( instr, 1, 10 );
319 /* Extract 9-bit secondary opcode, instr[9:1] */
320 static UInt ifieldOPClo9 ( UInt instr) {
321 return IFIELD( instr, 1, 9 );
324 /* Extract 8-bit secondary opcode, instr[8:1] */
325 static UInt ifieldOPClo8 ( UInt instr) {
326 return IFIELD( instr, 1, 8 );
329 /* Extract 5-bit secondary opcode, instr[5:1] */
330 static UInt ifieldOPClo5 ( UInt instr) {
331 return IFIELD( instr, 1, 5 );
334 /* Extract 2-bit secondary opcode, instr[1:0] */
335 static UInt ifieldOPC0o2 ( UInt instr) {
336 return IFIELD( instr, 0, 2 );
339 /* Extract RD (destination register) field, instr[25:21] */
340 static UChar ifieldRegDS( UInt instr ) {
341 return toUChar( IFIELD( instr, 21, 5 ) );
344 /* Extract XT (destination register) field, instr[0,25:21] */
345 static UChar ifieldRegXT ( UInt instr )
347 UChar upper_bit = toUChar (IFIELD (instr, 0, 1));
348 UChar lower_bits = toUChar (IFIELD (instr, 21, 5));
349 return (upper_bit << 5) | lower_bits;
352 /* Extract XS (store source register) field, instr[0,25:21] */
353 static inline UChar ifieldRegXS ( UInt instr )
355 return ifieldRegXT ( instr );
358 /* Extract RA (1st source register) field, instr[20:16] */
359 static UChar ifieldRegA ( UInt instr ) {
360 return toUChar( IFIELD( instr, 16, 5 ) );
363 /* Extract XA (1st source register) field, instr[2,20:16] */
364 static UChar ifieldRegXA ( UInt instr )
366 UChar upper_bit = toUChar (IFIELD (instr, 2, 1));
367 UChar lower_bits = toUChar (IFIELD (instr, 16, 5));
368 return (upper_bit << 5) | lower_bits;
371 /* Extract RB (2nd source register) field, instr[15:11] */
372 static UChar ifieldRegB ( UInt instr ) {
373 return toUChar( IFIELD( instr, 11, 5 ) );
376 /* Extract XB (2nd source register) field, instr[1,15:11] */
377 static UChar ifieldRegXB ( UInt instr )
379 UChar upper_bit = toUChar (IFIELD (instr, 1, 1));
380 UChar lower_bits = toUChar (IFIELD (instr, 11, 5));
381 return (upper_bit << 5) | lower_bits;
384 /* Extract RC (3rd source register) field, instr[10:6] */
385 static UChar ifieldRegC ( UInt instr ) {
386 return toUChar( IFIELD( instr, 6, 5 ) );
389 /* Extract XC (3rd source register) field, instr[3,10:6] */
390 static UChar ifieldRegXC ( UInt instr )
392 UChar upper_bit = toUChar (IFIELD (instr, 3, 1));
393 UChar lower_bits = toUChar (IFIELD (instr, 6, 5));
394 return (upper_bit << 5) | lower_bits;
397 /* Extract bit 10, instr[10] */
398 static UChar ifieldBIT10 ( UInt instr ) {
399 return toUChar( IFIELD( instr, 10, 1 ) );
402 /* Extract 2nd lowest bit, instr[1] */
403 static UChar ifieldBIT1 ( UInt instr ) {
404 return toUChar( IFIELD( instr, 1, 1 ) );
407 /* Extract lowest bit, instr[0] */
408 static UChar ifieldBIT0 ( UInt instr ) {
409 return toUChar( instr & 0x1 );
412 /* Extract unsigned bottom half, instr[15:0] */
413 static UInt ifieldUIMM16 ( UInt instr ) {
414 return instr & 0xFFFF;
417 /* Extract unsigned bottom 26 bits, instr[25:0] */
418 static UInt ifieldUIMM26 ( UInt instr ) {
419 return instr & 0x3FFFFFF;
422 /* Extract DM field, instr[9:8] */
423 static UChar ifieldDM ( UInt instr ) {
424 return toUChar( IFIELD( instr, 8, 2 ) );
427 /* Extract SHW field, instr[9:8] */
428 static inline UChar ifieldSHW ( UInt instr )
430 return ifieldDM ( instr );
433 /*------------------------------------------------------------*/
434 /*--- Guest-state identifiers ---*/
435 /*------------------------------------------------------------*/
437 typedef enum {
438 PPC_GST_CIA, // Current Instruction Address
439 PPC_GST_LR, // Link Register
440 PPC_GST_CTR, // Count Register
441 PPC_GST_XER, // Overflow, carry flags, byte count
442 PPC_GST_CR, // Condition Register
443 PPC_GST_FPSCR, // Floating Point Status/Control Register
444 PPC_GST_VRSAVE, // Vector Save/Restore Register
445 PPC_GST_VSCR, // Vector Status and Control Register
446 PPC_GST_EMWARN, // Emulation warnings
447 PPC_GST_CMSTART,// For icbi: start of area to invalidate
448 PPC_GST_CMLEN, // For icbi: length of area to invalidate
449 PPC_GST_IP_AT_SYSCALL, // the CIA of the most recently executed SC insn
450 PPC_GST_SPRG3_RO, // SPRG3
451 PPC_GST_TFHAR, // Transactional Failure Handler Address Register
452 PPC_GST_TFIAR, // Transactional Failure Instruction Address Register
453 PPC_GST_TEXASR, // Transactional EXception And Summary Register
454 PPC_GST_TEXASRU, // Transactional EXception And Summary Register Upper
455 PPC_GST_PPR, // Program Priority register
456 PPC_GST_PPR32, // Upper 32-bits of Program Priority register
457 PPC_GST_PSPB, /* Problem State Priority Boost register, Note, the
458 * register is initialized to a non-zero value. Currently
459 * Valgrind is not supporting the register value to
460 * automatically decrement. Could be added later if
461 * needed.
463 PPC_GST_DSCR, // Data Stream Control Register
464 PPC_GST_MAX
465 } PPC_GST;
467 #define MASK_FPSCR_RN 0x3ULL // Binary floating point rounding mode
468 #define MASK_FPSCR_DRN 0x700000000ULL // Decimal floating point rounding mode
469 #define MASK_FPSCR_C_FPCC 0x1F000ULL // Floating-Point Condition code FPCC
471 #define MASK_VSCR_VALID 0x00010001
474 /*------------------------------------------------------------*/
475 /*--- FP Helpers ---*/
476 /*------------------------------------------------------------*/
478 /* Produce the 32-bit pattern corresponding to the supplied
479 float. */
480 static UInt float_to_bits ( Float f )
482 union { UInt i; Float f; } u;
483 vassert(4 == sizeof(UInt));
484 vassert(4 == sizeof(Float));
485 vassert(4 == sizeof(u));
486 u.f = f;
487 return u.i;
491 /*------------------------------------------------------------*/
492 /*--- Misc Helpers ---*/
493 /*------------------------------------------------------------*/
495 /* Generate mask with 1's from 'begin' through 'end',
496 wrapping if begin > end.
497 begin->end works from right to left, 0=lsb
499 static UInt MASK32( UInt begin, UInt end )
501 UInt m1, m2, mask;
502 vassert(begin < 32);
503 vassert(end < 32);
504 m1 = ((UInt)(-1)) << begin;
505 m2 = ((UInt)(-1)) << end << 1;
506 mask = m1 ^ m2;
507 if (begin > end) mask = ~mask; // wrap mask
508 return mask;
511 static ULong MASK64( UInt begin, UInt end )
513 ULong m1, m2, mask;
514 vassert(begin < 64);
515 vassert(end < 64);
516 m1 = ((ULong)(-1)) << begin;
517 m2 = ((ULong)(-1)) << end << 1;
518 mask = m1 ^ m2;
519 if (begin > end) mask = ~mask; // wrap mask
520 return mask;
523 static Addr64 nextInsnAddr( void )
525 return guest_CIA_curr_instr + 4;
529 /*------------------------------------------------------------*/
530 /*--- Helper bits and pieces for deconstructing the ---*/
531 /*--- ppc32/64 insn stream. ---*/
532 /*------------------------------------------------------------*/
534 /* Add a statement to the list held by "irsb". */
535 static void stmt ( IRStmt* st )
537 addStmtToIRSB( irsb, st );
540 /* Generate a new temporary of the given type. */
541 static IRTemp newTemp ( IRType ty )
543 vassert(isPlausibleIRType(ty));
544 return newIRTemp( irsb->tyenv, ty );
547 /* Various simple conversions */
549 static UChar extend_s_5to8 ( UChar x )
551 return toUChar((((Int)x) << 27) >> 27);
554 static UInt extend_s_8to32( UChar x )
556 return (UInt)((((Int)x) << 24) >> 24);
559 static UInt extend_s_16to32 ( UInt x )
561 return (UInt)((((Int)x) << 16) >> 16);
564 static ULong extend_s_16to64 ( UInt x )
566 return (ULong)((((Long)x) << 48) >> 48);
569 static ULong extend_s_26to64 ( UInt x )
571 return (ULong)((((Long)x) << 38) >> 38);
574 static ULong extend_s_32to64 ( UInt x )
576 return (ULong)((((Long)x) << 32) >> 32);
579 /* Do a proper-endian load of a 32-bit word, regardless of the endianness
580 of the underlying host. */
581 static UInt getUIntPPCendianly ( const UChar* p )
583 UInt w = 0;
584 if (host_endness == VexEndnessBE) {
585 w = (w << 8) | p[0];
586 w = (w << 8) | p[1];
587 w = (w << 8) | p[2];
588 w = (w << 8) | p[3];
589 } else {
590 w = (w << 8) | p[3];
591 w = (w << 8) | p[2];
592 w = (w << 8) | p[1];
593 w = (w << 8) | p[0];
595 return w;
599 /*------------------------------------------------------------*/
600 /*--- Helpers for constructing IR. ---*/
601 /*------------------------------------------------------------*/
603 static void assign ( IRTemp dst, IRExpr* e )
605 stmt( IRStmt_WrTmp(dst, e) );
608 /* This generates a normal (non store-conditional) store. */
609 static void store ( IRExpr* addr, IRExpr* data )
611 IRType tyA = typeOfIRExpr(irsb->tyenv, addr);
612 vassert(tyA == Ity_I32 || tyA == Ity_I64);
614 if (host_endness == VexEndnessBE)
615 stmt( IRStmt_Store(Iend_BE, addr, data) );
616 else
617 stmt( IRStmt_Store(Iend_LE, addr, data) );
620 static IRExpr* unop ( IROp op, IRExpr* a )
622 return IRExpr_Unop(op, a);
625 static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
627 return IRExpr_Binop(op, a1, a2);
630 static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
632 return IRExpr_Triop(op, a1, a2, a3);
635 static IRExpr* qop ( IROp op, IRExpr* a1, IRExpr* a2,
636 IRExpr* a3, IRExpr* a4 )
638 return IRExpr_Qop(op, a1, a2, a3, a4);
641 static IRExpr* mkexpr ( IRTemp tmp )
643 return IRExpr_RdTmp(tmp);
646 #define mkU1(_n) IRExpr_Const(IRConst_U1(_n))
648 static IRExpr* mkU8 ( UChar i )
650 return IRExpr_Const(IRConst_U8(i));
653 static IRExpr* mkU16 ( UInt i )
655 return IRExpr_Const(IRConst_U16(i));
658 static IRExpr* mkU32 ( UInt i )
660 return IRExpr_Const(IRConst_U32(i));
663 static IRExpr* mkU64 ( ULong i )
665 return IRExpr_Const(IRConst_U64(i));
668 static IRExpr* mkV128 ( UShort i )
670 vassert(i == 0 || i == 0xffff);
671 return IRExpr_Const(IRConst_V128(i));
674 /* This generates a normal (non load-linked) load. */
675 static IRExpr* load ( IRType ty, IRExpr* addr )
677 if (host_endness == VexEndnessBE)
678 return IRExpr_Load(Iend_BE, ty, addr);
679 else
680 return IRExpr_Load(Iend_LE, ty, addr);
683 static IRStmt* stmt_load ( IRTemp result,
684 IRExpr* addr, IRExpr* storedata )
686 if (host_endness == VexEndnessBE)
687 return IRStmt_LLSC(Iend_BE, result, addr, storedata);
688 else
689 return IRStmt_LLSC(Iend_LE, result, addr, storedata);
692 static IRExpr* mkOR1 ( IRExpr* arg1, IRExpr* arg2 )
694 vassert(typeOfIRExpr(irsb->tyenv, arg1) == Ity_I1);
695 vassert(typeOfIRExpr(irsb->tyenv, arg2) == Ity_I1);
696 return unop(Iop_32to1, binop(Iop_Or32, unop(Iop_1Uto32, arg1),
697 unop(Iop_1Uto32, arg2)));
700 static IRExpr* mkAND1 ( IRExpr* arg1, IRExpr* arg2 )
702 vassert(typeOfIRExpr(irsb->tyenv, arg1) == Ity_I1);
703 vassert(typeOfIRExpr(irsb->tyenv, arg2) == Ity_I1);
704 return unop(Iop_32to1, binop(Iop_And32, unop(Iop_1Uto32, arg1),
705 unop(Iop_1Uto32, arg2)));
708 static inline IRExpr* mkXOr4_32( IRTemp t0, IRTemp t1, IRTemp t2,
709 IRTemp t3 )
711 return binop( Iop_Xor32,
712 binop( Iop_Xor32, mkexpr( t0 ), mkexpr( t1 ) ),
713 binop( Iop_Xor32, mkexpr( t2 ), mkexpr( t3 ) ) );
716 static inline IRExpr* mkOr3_V128( IRTemp t0, IRTemp t1, IRTemp t2 )
718 return binop( Iop_OrV128,
719 mkexpr( t0 ),
720 binop( Iop_OrV128, mkexpr( t1 ), mkexpr( t2 ) ) );
723 static inline IRExpr* mkOr4_V128( IRTemp t0, IRTemp t1, IRTemp t2,
724 IRTemp t3 )
726 return binop( Iop_OrV128,
727 binop( Iop_OrV128, mkexpr( t0 ), mkexpr( t1 ) ),
728 binop( Iop_OrV128, mkexpr( t2 ), mkexpr( t3 ) ) );
731 static inline IRExpr* mkOr4_V128_expr( IRExpr* t0, IRExpr* t1, IRExpr* t2,
732 IRExpr* t3 )
734 /* arguments are already expressions */
735 return binop( Iop_OrV128,
736 binop( Iop_OrV128, ( t0 ), ( t1 ) ),
737 binop( Iop_OrV128, ( t2 ), ( t3 ) ) );
740 static IRExpr* mkNOT1 ( IRExpr* arg1 )
742 vassert(typeOfIRExpr(irsb->tyenv, arg1) == Ity_I1);
743 return unop(Iop_32to1, unop(Iop_Not32, unop(Iop_1Uto32, arg1) ) );
746 /* expand V128_8Ux16 to 2x V128_16Ux8's */
747 static void expand8Ux16( IRExpr* vIn,
748 /*OUTs*/ IRTemp* vEvn, IRTemp* vOdd )
750 IRTemp ones8x16 = newTemp(Ity_V128);
752 vassert(typeOfIRExpr(irsb->tyenv, vIn) == Ity_V128);
753 vassert(vEvn && *vEvn == IRTemp_INVALID);
754 vassert(vOdd && *vOdd == IRTemp_INVALID);
755 *vEvn = newTemp(Ity_V128);
756 *vOdd = newTemp(Ity_V128);
758 assign( ones8x16, unop(Iop_Dup8x16, mkU8(0x1)) );
759 assign( *vOdd, binop(Iop_MullEven8Ux16, mkexpr(ones8x16), vIn) );
760 assign( *vEvn, binop(Iop_MullEven8Ux16, mkexpr(ones8x16),
761 binop(Iop_ShrV128, vIn, mkU8(8))) );
764 /* expand V128_8Sx16 to 2x V128_16Sx8's */
765 static void expand8Sx16( IRExpr* vIn,
766 /*OUTs*/ IRTemp* vEvn, IRTemp* vOdd )
768 IRTemp ones8x16 = newTemp(Ity_V128);
770 vassert(typeOfIRExpr(irsb->tyenv, vIn) == Ity_V128);
771 vassert(vEvn && *vEvn == IRTemp_INVALID);
772 vassert(vOdd && *vOdd == IRTemp_INVALID);
773 *vEvn = newTemp(Ity_V128);
774 *vOdd = newTemp(Ity_V128);
776 assign( ones8x16, unop(Iop_Dup8x16, mkU8(0x1)) );
777 assign( *vOdd, binop(Iop_MullEven8Sx16, mkexpr(ones8x16), vIn) );
778 assign( *vEvn, binop(Iop_MullEven8Sx16, mkexpr(ones8x16),
779 binop(Iop_ShrV128, vIn, mkU8(8))) );
782 /* expand V128_16Uto8 to 2x V128_32Ux4's */
783 static void expand16Ux8( IRExpr* vIn,
784 /*OUTs*/ IRTemp* vEvn, IRTemp* vOdd )
786 IRTemp ones16x8 = newTemp(Ity_V128);
788 vassert(typeOfIRExpr(irsb->tyenv, vIn) == Ity_V128);
789 vassert(vEvn && *vEvn == IRTemp_INVALID);
790 vassert(vOdd && *vOdd == IRTemp_INVALID);
791 *vEvn = newTemp(Ity_V128);
792 *vOdd = newTemp(Ity_V128);
794 assign( ones16x8, unop(Iop_Dup16x8, mkU16(0x1)) );
795 assign( *vOdd, binop(Iop_MullEven16Ux8, mkexpr(ones16x8), vIn) );
796 assign( *vEvn, binop(Iop_MullEven16Ux8, mkexpr(ones16x8),
797 binop(Iop_ShrV128, vIn, mkU8(16))) );
800 /* expand V128_16Sto8 to 2x V128_32Sx4's */
801 static void expand16Sx8( IRExpr* vIn,
802 /*OUTs*/ IRTemp* vEvn, IRTemp* vOdd )
804 IRTemp ones16x8 = newTemp(Ity_V128);
806 vassert(typeOfIRExpr(irsb->tyenv, vIn) == Ity_V128);
807 vassert(vEvn && *vEvn == IRTemp_INVALID);
808 vassert(vOdd && *vOdd == IRTemp_INVALID);
809 *vEvn = newTemp(Ity_V128);
810 *vOdd = newTemp(Ity_V128);
812 assign( ones16x8, unop(Iop_Dup16x8, mkU16(0x1)) );
813 assign( *vOdd, binop(Iop_MullEven16Sx8, mkexpr(ones16x8), vIn) );
814 assign( *vEvn, binop(Iop_MullEven16Sx8, mkexpr(ones16x8),
815 binop(Iop_ShrV128, vIn, mkU8(16))) );
818 /* break V128 to 4xF64's*/
819 static void breakV128to4xF64( IRExpr* t128,
820 /*OUTs*/
821 IRTemp* t3, IRTemp* t2,
822 IRTemp* t1, IRTemp* t0 )
824 IRTemp hi64 = newTemp(Ity_I64);
825 IRTemp lo64 = newTemp(Ity_I64);
827 vassert(typeOfIRExpr(irsb->tyenv, t128) == Ity_V128);
828 vassert(t0 && *t0 == IRTemp_INVALID);
829 vassert(t1 && *t1 == IRTemp_INVALID);
830 vassert(t2 && *t2 == IRTemp_INVALID);
831 vassert(t3 && *t3 == IRTemp_INVALID);
832 *t0 = newTemp(Ity_F64);
833 *t1 = newTemp(Ity_F64);
834 *t2 = newTemp(Ity_F64);
835 *t3 = newTemp(Ity_F64);
837 assign( hi64, unop(Iop_V128HIto64, t128) );
838 assign( lo64, unop(Iop_V128to64, t128) );
839 assign( *t3,
840 unop( Iop_F32toF64,
841 unop( Iop_ReinterpI32asF32,
842 unop( Iop_64HIto32, mkexpr( hi64 ) ) ) ) );
843 assign( *t2,
844 unop( Iop_F32toF64,
845 unop( Iop_ReinterpI32asF32, unop( Iop_64to32, mkexpr( hi64 ) ) ) ) );
846 assign( *t1,
847 unop( Iop_F32toF64,
848 unop( Iop_ReinterpI32asF32,
849 unop( Iop_64HIto32, mkexpr( lo64 ) ) ) ) );
850 assign( *t0,
851 unop( Iop_F32toF64,
852 unop( Iop_ReinterpI32asF32, unop( Iop_64to32, mkexpr( lo64 ) ) ) ) );
856 /* break V128 to 4xI32's, then sign-extend to I64's */
857 static void breakV128to4x64S( IRExpr* t128,
858 /*OUTs*/
859 IRTemp* t3, IRTemp* t2,
860 IRTemp* t1, IRTemp* t0 )
862 IRTemp hi64 = newTemp(Ity_I64);
863 IRTemp lo64 = newTemp(Ity_I64);
865 vassert(typeOfIRExpr(irsb->tyenv, t128) == Ity_V128);
866 vassert(t0 && *t0 == IRTemp_INVALID);
867 vassert(t1 && *t1 == IRTemp_INVALID);
868 vassert(t2 && *t2 == IRTemp_INVALID);
869 vassert(t3 && *t3 == IRTemp_INVALID);
870 *t0 = newTemp(Ity_I64);
871 *t1 = newTemp(Ity_I64);
872 *t2 = newTemp(Ity_I64);
873 *t3 = newTemp(Ity_I64);
875 assign( hi64, unop(Iop_V128HIto64, t128) );
876 assign( lo64, unop(Iop_V128to64, t128) );
877 assign( *t3, unop(Iop_32Sto64, unop(Iop_64HIto32, mkexpr(hi64))) );
878 assign( *t2, unop(Iop_32Sto64, unop(Iop_64to32, mkexpr(hi64))) );
879 assign( *t1, unop(Iop_32Sto64, unop(Iop_64HIto32, mkexpr(lo64))) );
880 assign( *t0, unop(Iop_32Sto64, unop(Iop_64to32, mkexpr(lo64))) );
883 /* break V128 to 4xI32's, then zero-extend to I64's */
884 static void breakV128to4x64U ( IRExpr* t128,
885 /*OUTs*/
886 IRTemp* t3, IRTemp* t2,
887 IRTemp* t1, IRTemp* t0 )
889 IRTemp hi64 = newTemp(Ity_I64);
890 IRTemp lo64 = newTemp(Ity_I64);
892 vassert(typeOfIRExpr(irsb->tyenv, t128) == Ity_V128);
893 vassert(t0 && *t0 == IRTemp_INVALID);
894 vassert(t1 && *t1 == IRTemp_INVALID);
895 vassert(t2 && *t2 == IRTemp_INVALID);
896 vassert(t3 && *t3 == IRTemp_INVALID);
897 *t0 = newTemp(Ity_I64);
898 *t1 = newTemp(Ity_I64);
899 *t2 = newTemp(Ity_I64);
900 *t3 = newTemp(Ity_I64);
902 assign( hi64, unop(Iop_V128HIto64, t128) );
903 assign( lo64, unop(Iop_V128to64, t128) );
904 assign( *t3, unop(Iop_32Uto64, unop(Iop_64HIto32, mkexpr(hi64))) );
905 assign( *t2, unop(Iop_32Uto64, unop(Iop_64to32, mkexpr(hi64))) );
906 assign( *t1, unop(Iop_32Uto64, unop(Iop_64HIto32, mkexpr(lo64))) );
907 assign( *t0, unop(Iop_32Uto64, unop(Iop_64to32, mkexpr(lo64))) );
910 static void breakV128to4x32( IRExpr* t128,
911 /*OUTs*/
912 IRTemp* t3, IRTemp* t2,
913 IRTemp* t1, IRTemp* t0 )
915 IRTemp hi64 = newTemp(Ity_I64);
916 IRTemp lo64 = newTemp(Ity_I64);
918 vassert(typeOfIRExpr(irsb->tyenv, t128) == Ity_V128);
919 vassert(t0 && *t0 == IRTemp_INVALID);
920 vassert(t1 && *t1 == IRTemp_INVALID);
921 vassert(t2 && *t2 == IRTemp_INVALID);
922 vassert(t3 && *t3 == IRTemp_INVALID);
923 *t0 = newTemp(Ity_I32);
924 *t1 = newTemp(Ity_I32);
925 *t2 = newTemp(Ity_I32);
926 *t3 = newTemp(Ity_I32);
928 assign( hi64, unop(Iop_V128HIto64, t128) );
929 assign( lo64, unop(Iop_V128to64, t128) );
930 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
931 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
932 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
933 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
936 static IRExpr* mkV128from32( IRTemp t3, IRTemp t2,
937 IRTemp t1, IRTemp t0 )
939 return
940 binop( Iop_64HLtoV128,
941 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
942 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
946 static IRExpr* extract_field_from_vector( IRTemp vB, IRExpr* index, UInt mask)
948 /* vB is a vector, extract bits starting at index to size of mask */
949 return unop( Iop_V128to64,
950 binop( Iop_AndV128,
951 binop( Iop_ShrV128,
952 mkexpr( vB ),
953 unop( Iop_64to8,
954 binop( Iop_Mul64, index,
955 mkU64( 8 ) ) ) ),
956 binop( Iop_64HLtoV128,
957 mkU64( 0x0 ),
958 mkU64( mask ) ) ) );
961 /* Signed saturating narrow 64S to 32 */
962 static IRExpr* mkQNarrow64Sto32 ( IRExpr* t64 )
964 IRTemp hi32 = newTemp(Ity_I32);
965 IRTemp lo32 = newTemp(Ity_I32);
967 vassert(typeOfIRExpr(irsb->tyenv, t64) == Ity_I64);
969 assign( hi32, unop(Iop_64HIto32, t64));
970 assign( lo32, unop(Iop_64to32, t64));
972 return IRExpr_ITE(
973 /* if (hi32 == (lo32 >>s 31)) */
974 binop(Iop_CmpEQ32, mkexpr(hi32),
975 binop( Iop_Sar32, mkexpr(lo32), mkU8(31))),
976 /* then: within signed-32 range: lo half good enough */
977 mkexpr(lo32),
978 /* else: sign dep saturate: 1->0x80000000, 0->0x7FFFFFFF */
979 binop(Iop_Add32, mkU32(0x7FFFFFFF),
980 binop(Iop_Shr32, mkexpr(hi32), mkU8(31))));
983 /* Unsigned saturating narrow 64S to 32 */
984 static IRExpr* mkQNarrow64Uto32 ( IRExpr* t64 )
986 IRTemp hi32 = newTemp(Ity_I32);
987 IRTemp lo32 = newTemp(Ity_I32);
989 vassert(typeOfIRExpr(irsb->tyenv, t64) == Ity_I64);
991 assign( hi32, unop(Iop_64HIto32, t64));
992 assign( lo32, unop(Iop_64to32, t64));
994 return IRExpr_ITE(
995 /* if (top 32 bits of t64 are 0) */
996 binop(Iop_CmpEQ32, mkexpr(hi32), mkU32(0)),
997 /* then: within unsigned-32 range: lo half good enough */
998 mkexpr(lo32),
999 /* else: positive saturate -> 0xFFFFFFFF */
1000 mkU32(0xFFFFFFFF));
1003 /* Signed saturate narrow 64->32, combining to V128 */
1004 static IRExpr* mkV128from4x64S ( IRExpr* t3, IRExpr* t2,
1005 IRExpr* t1, IRExpr* t0 )
1007 vassert(typeOfIRExpr(irsb->tyenv, t3) == Ity_I64);
1008 vassert(typeOfIRExpr(irsb->tyenv, t2) == Ity_I64);
1009 vassert(typeOfIRExpr(irsb->tyenv, t1) == Ity_I64);
1010 vassert(typeOfIRExpr(irsb->tyenv, t0) == Ity_I64);
1011 return binop(Iop_64HLtoV128,
1012 binop(Iop_32HLto64,
1013 mkQNarrow64Sto32( t3 ),
1014 mkQNarrow64Sto32( t2 )),
1015 binop(Iop_32HLto64,
1016 mkQNarrow64Sto32( t1 ),
1017 mkQNarrow64Sto32( t0 )));
1020 /* Unsigned saturate narrow 64->32, combining to V128 */
1021 static IRExpr* mkV128from4x64U ( IRExpr* t3, IRExpr* t2,
1022 IRExpr* t1, IRExpr* t0 )
1024 vassert(typeOfIRExpr(irsb->tyenv, t3) == Ity_I64);
1025 vassert(typeOfIRExpr(irsb->tyenv, t2) == Ity_I64);
1026 vassert(typeOfIRExpr(irsb->tyenv, t1) == Ity_I64);
1027 vassert(typeOfIRExpr(irsb->tyenv, t0) == Ity_I64);
1028 return binop(Iop_64HLtoV128,
1029 binop(Iop_32HLto64,
1030 mkQNarrow64Uto32( t3 ),
1031 mkQNarrow64Uto32( t2 )),
1032 binop(Iop_32HLto64,
1033 mkQNarrow64Uto32( t1 ),
1034 mkQNarrow64Uto32( t0 )));
1037 /* Simulate irops Iop_MullOdd*, since we don't have them */
1038 #define MK_Iop_MullOdd8Ux16( expr_vA, expr_vB ) \
1039 binop(Iop_MullEven8Ux16, \
1040 binop(Iop_ShrV128, expr_vA, mkU8(8)), \
1041 binop(Iop_ShrV128, expr_vB, mkU8(8)))
1043 #define MK_Iop_MullOdd8Sx16( expr_vA, expr_vB ) \
1044 binop(Iop_MullEven8Sx16, \
1045 binop(Iop_ShrV128, expr_vA, mkU8(8)), \
1046 binop(Iop_ShrV128, expr_vB, mkU8(8)))
1048 #define MK_Iop_MullOdd16Ux8( expr_vA, expr_vB ) \
1049 binop(Iop_MullEven16Ux8, \
1050 binop(Iop_ShrV128, expr_vA, mkU8(16)), \
1051 binop(Iop_ShrV128, expr_vB, mkU8(16)))
1053 #define MK_Iop_MullOdd32Ux4( expr_vA, expr_vB ) \
1054 binop(Iop_MullEven32Ux4, \
1055 binop(Iop_ShrV128, expr_vA, mkU8(32)), \
1056 binop(Iop_ShrV128, expr_vB, mkU8(32)))
1058 #define MK_Iop_MullOdd16Sx8( expr_vA, expr_vB ) \
1059 binop(Iop_MullEven16Sx8, \
1060 binop(Iop_ShrV128, expr_vA, mkU8(16)), \
1061 binop(Iop_ShrV128, expr_vB, mkU8(16)))
1063 #define MK_Iop_MullOdd32Sx4( expr_vA, expr_vB ) \
1064 binop(Iop_MullEven32Sx4, \
1065 binop(Iop_ShrV128, expr_vA, mkU8(32)), \
1066 binop(Iop_ShrV128, expr_vB, mkU8(32)))
1069 static IRExpr* /* :: Ity_I64 */ mk64lo32Sto64 ( IRExpr* src )
1071 vassert(typeOfIRExpr(irsb->tyenv, src) == Ity_I64);
1072 return unop(Iop_32Sto64, unop(Iop_64to32, src));
1075 static IRExpr* /* :: Ity_I64 */ mk64lo32Uto64 ( IRExpr* src )
1077 vassert(typeOfIRExpr(irsb->tyenv, src) == Ity_I64);
1078 return unop(Iop_32Uto64, unop(Iop_64to32, src));
1081 static IROp mkSzOp ( IRType ty, IROp op8 )
1083 Int adj;
1084 vassert(ty == Ity_I8 || ty == Ity_I16 ||
1085 ty == Ity_I32 || ty == Ity_I64);
1086 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8 || op8 == Iop_Mul8 ||
1087 op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8 ||
1088 op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8 ||
1089 op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8 ||
1090 op8 == Iop_Not8 );
1091 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : (ty==Ity_I32 ? 2 : 3));
1092 return adj + op8;
1095 /* Make sure we get valid 32 and 64bit addresses */
1096 static Addr64 mkSzAddr ( IRType ty, Addr64 addr )
1098 vassert(ty == Ity_I32 || ty == Ity_I64);
1099 return ( ty == Ity_I64 ?
1100 (Addr64)addr :
1101 (Addr64)extend_s_32to64( toUInt(addr) ) );
1104 /* sz, ULong -> IRExpr */
1105 static IRExpr* mkSzImm ( IRType ty, ULong imm64 )
1107 vassert(ty == Ity_I32 || ty == Ity_I64);
1108 return ty == Ity_I64 ? mkU64(imm64) : mkU32((UInt)imm64);
1111 /* sz, ULong -> IRConst */
1112 static IRConst* mkSzConst ( IRType ty, ULong imm64 )
1114 vassert(ty == Ity_I32 || ty == Ity_I64);
1115 return ( ty == Ity_I64 ?
1116 IRConst_U64(imm64) :
1117 IRConst_U32((UInt)imm64) );
1120 /* Sign extend imm16 -> IRExpr* */
1121 static IRExpr* mkSzExtendS16 ( IRType ty, UInt imm16 )
1123 vassert(ty == Ity_I32 || ty == Ity_I64);
1124 return ( ty == Ity_I64 ?
1125 mkU64(extend_s_16to64(imm16)) :
1126 mkU32(extend_s_16to32(imm16)) );
1129 /* Sign extend imm32 -> IRExpr* */
1130 static IRExpr* mkSzExtendS32 ( IRType ty, UInt imm32 )
1132 vassert(ty == Ity_I32 || ty == Ity_I64);
1133 return ( ty == Ity_I64 ?
1134 mkU64(extend_s_32to64(imm32)) :
1135 mkU32(imm32) );
1138 /* IR narrows I32/I64 -> I8/I16/I32 */
1139 static IRExpr* mkNarrowTo8 ( IRType ty, IRExpr* src )
1141 vassert(ty == Ity_I32 || ty == Ity_I64);
1142 return ty == Ity_I64 ? unop(Iop_64to8, src) : unop(Iop_32to8, src);
1145 static IRExpr* mkNarrowTo16 ( IRType ty, IRExpr* src )
1147 vassert(ty == Ity_I32 || ty == Ity_I64);
1148 return ty == Ity_I64 ? unop(Iop_64to16, src) : unop(Iop_32to16, src);
1151 static IRExpr* mkNarrowTo32 ( IRType ty, IRExpr* src )
1153 vassert(ty == Ity_I32 || ty == Ity_I64);
1154 return ty == Ity_I64 ? unop(Iop_64to32, src) : src;
1157 /* Signed/Unsigned IR widens I8/I16/I32 -> I32/I64 */
1158 static IRExpr* mkWidenFrom8 ( IRType ty, IRExpr* src, Bool sined )
1160 IROp op;
1161 vassert(ty == Ity_I32 || ty == Ity_I64);
1162 if (sined) op = (ty==Ity_I32) ? Iop_8Sto32 : Iop_8Sto64;
1163 else op = (ty==Ity_I32) ? Iop_8Uto32 : Iop_8Uto64;
1164 return unop(op, src);
1167 static IRExpr* mkWidenFrom16 ( IRType ty, IRExpr* src, Bool sined )
1169 IROp op;
1170 vassert(ty == Ity_I32 || ty == Ity_I64);
1171 if (sined) op = (ty==Ity_I32) ? Iop_16Sto32 : Iop_16Sto64;
1172 else op = (ty==Ity_I32) ? Iop_16Uto32 : Iop_16Uto64;
1173 return unop(op, src);
1176 static IRExpr* mkWidenFrom32 ( IRType ty, IRExpr* src, Bool sined )
1178 vassert(ty == Ity_I32 || ty == Ity_I64);
1179 if (ty == Ity_I32)
1180 return src;
1181 return (sined) ? unop(Iop_32Sto64, src) : unop(Iop_32Uto64, src);
1185 static Int integerGuestRegOffset ( UInt archreg )
1187 vassert(archreg < 32);
1189 // jrs: probably not necessary; only matters if we reference sub-parts
1190 // of the ppc registers, but that isn't the case
1191 // later: this might affect Altivec though?
1193 switch (archreg) {
1194 case 0: return offsetofPPCGuestState(guest_GPR0);
1195 case 1: return offsetofPPCGuestState(guest_GPR1);
1196 case 2: return offsetofPPCGuestState(guest_GPR2);
1197 case 3: return offsetofPPCGuestState(guest_GPR3);
1198 case 4: return offsetofPPCGuestState(guest_GPR4);
1199 case 5: return offsetofPPCGuestState(guest_GPR5);
1200 case 6: return offsetofPPCGuestState(guest_GPR6);
1201 case 7: return offsetofPPCGuestState(guest_GPR7);
1202 case 8: return offsetofPPCGuestState(guest_GPR8);
1203 case 9: return offsetofPPCGuestState(guest_GPR9);
1204 case 10: return offsetofPPCGuestState(guest_GPR10);
1205 case 11: return offsetofPPCGuestState(guest_GPR11);
1206 case 12: return offsetofPPCGuestState(guest_GPR12);
1207 case 13: return offsetofPPCGuestState(guest_GPR13);
1208 case 14: return offsetofPPCGuestState(guest_GPR14);
1209 case 15: return offsetofPPCGuestState(guest_GPR15);
1210 case 16: return offsetofPPCGuestState(guest_GPR16);
1211 case 17: return offsetofPPCGuestState(guest_GPR17);
1212 case 18: return offsetofPPCGuestState(guest_GPR18);
1213 case 19: return offsetofPPCGuestState(guest_GPR19);
1214 case 20: return offsetofPPCGuestState(guest_GPR20);
1215 case 21: return offsetofPPCGuestState(guest_GPR21);
1216 case 22: return offsetofPPCGuestState(guest_GPR22);
1217 case 23: return offsetofPPCGuestState(guest_GPR23);
1218 case 24: return offsetofPPCGuestState(guest_GPR24);
1219 case 25: return offsetofPPCGuestState(guest_GPR25);
1220 case 26: return offsetofPPCGuestState(guest_GPR26);
1221 case 27: return offsetofPPCGuestState(guest_GPR27);
1222 case 28: return offsetofPPCGuestState(guest_GPR28);
1223 case 29: return offsetofPPCGuestState(guest_GPR29);
1224 case 30: return offsetofPPCGuestState(guest_GPR30);
1225 case 31: return offsetofPPCGuestState(guest_GPR31);
1226 default: break;
1228 vpanic("integerGuestRegOffset(ppc,be)"); /*notreached*/
1231 static IRExpr* getIReg ( UInt archreg )
1233 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1234 vassert(archreg < 32);
1235 return IRExpr_Get( integerGuestRegOffset(archreg), ty );
1238 /* Ditto, but write to a reg instead. */
1239 static void putIReg ( UInt archreg, IRExpr* e )
1241 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1242 vassert(archreg < 32);
1243 vassert(typeOfIRExpr(irsb->tyenv, e) == ty );
1244 stmt( IRStmt_Put(integerGuestRegOffset(archreg), e) );
1248 /* Floating point egisters are mapped to VSX registers[0..31]. */
1249 static Int floatGuestRegOffset ( UInt archreg )
1251 vassert(archreg < 32);
1253 if (host_endness == VexEndnessLE) {
1254 switch (archreg) {
1255 case 0: return offsetofPPCGuestState(guest_VSR0) + 8;
1256 case 1: return offsetofPPCGuestState(guest_VSR1) + 8;
1257 case 2: return offsetofPPCGuestState(guest_VSR2) + 8;
1258 case 3: return offsetofPPCGuestState(guest_VSR3) + 8;
1259 case 4: return offsetofPPCGuestState(guest_VSR4) + 8;
1260 case 5: return offsetofPPCGuestState(guest_VSR5) + 8;
1261 case 6: return offsetofPPCGuestState(guest_VSR6) + 8;
1262 case 7: return offsetofPPCGuestState(guest_VSR7) + 8;
1263 case 8: return offsetofPPCGuestState(guest_VSR8) + 8;
1264 case 9: return offsetofPPCGuestState(guest_VSR9) + 8;
1265 case 10: return offsetofPPCGuestState(guest_VSR10) + 8;
1266 case 11: return offsetofPPCGuestState(guest_VSR11) + 8;
1267 case 12: return offsetofPPCGuestState(guest_VSR12) + 8;
1268 case 13: return offsetofPPCGuestState(guest_VSR13) + 8;
1269 case 14: return offsetofPPCGuestState(guest_VSR14) + 8;
1270 case 15: return offsetofPPCGuestState(guest_VSR15) + 8;
1271 case 16: return offsetofPPCGuestState(guest_VSR16) + 8;
1272 case 17: return offsetofPPCGuestState(guest_VSR17) + 8;
1273 case 18: return offsetofPPCGuestState(guest_VSR18) + 8;
1274 case 19: return offsetofPPCGuestState(guest_VSR19) + 8;
1275 case 20: return offsetofPPCGuestState(guest_VSR20) + 8;
1276 case 21: return offsetofPPCGuestState(guest_VSR21) + 8;
1277 case 22: return offsetofPPCGuestState(guest_VSR22) + 8;
1278 case 23: return offsetofPPCGuestState(guest_VSR23) + 8;
1279 case 24: return offsetofPPCGuestState(guest_VSR24) + 8;
1280 case 25: return offsetofPPCGuestState(guest_VSR25) + 8;
1281 case 26: return offsetofPPCGuestState(guest_VSR26) + 8;
1282 case 27: return offsetofPPCGuestState(guest_VSR27) + 8;
1283 case 28: return offsetofPPCGuestState(guest_VSR28) + 8;
1284 case 29: return offsetofPPCGuestState(guest_VSR29) + 8;
1285 case 30: return offsetofPPCGuestState(guest_VSR30) + 8;
1286 case 31: return offsetofPPCGuestState(guest_VSR31) + 8;
1287 default: break;
1289 } else {
1290 switch (archreg) {
1291 case 0: return offsetofPPCGuestState(guest_VSR0);
1292 case 1: return offsetofPPCGuestState(guest_VSR1);
1293 case 2: return offsetofPPCGuestState(guest_VSR2);
1294 case 3: return offsetofPPCGuestState(guest_VSR3);
1295 case 4: return offsetofPPCGuestState(guest_VSR4);
1296 case 5: return offsetofPPCGuestState(guest_VSR5);
1297 case 6: return offsetofPPCGuestState(guest_VSR6);
1298 case 7: return offsetofPPCGuestState(guest_VSR7);
1299 case 8: return offsetofPPCGuestState(guest_VSR8);
1300 case 9: return offsetofPPCGuestState(guest_VSR9);
1301 case 10: return offsetofPPCGuestState(guest_VSR10);
1302 case 11: return offsetofPPCGuestState(guest_VSR11);
1303 case 12: return offsetofPPCGuestState(guest_VSR12);
1304 case 13: return offsetofPPCGuestState(guest_VSR13);
1305 case 14: return offsetofPPCGuestState(guest_VSR14);
1306 case 15: return offsetofPPCGuestState(guest_VSR15);
1307 case 16: return offsetofPPCGuestState(guest_VSR16);
1308 case 17: return offsetofPPCGuestState(guest_VSR17);
1309 case 18: return offsetofPPCGuestState(guest_VSR18);
1310 case 19: return offsetofPPCGuestState(guest_VSR19);
1311 case 20: return offsetofPPCGuestState(guest_VSR20);
1312 case 21: return offsetofPPCGuestState(guest_VSR21);
1313 case 22: return offsetofPPCGuestState(guest_VSR22);
1314 case 23: return offsetofPPCGuestState(guest_VSR23);
1315 case 24: return offsetofPPCGuestState(guest_VSR24);
1316 case 25: return offsetofPPCGuestState(guest_VSR25);
1317 case 26: return offsetofPPCGuestState(guest_VSR26);
1318 case 27: return offsetofPPCGuestState(guest_VSR27);
1319 case 28: return offsetofPPCGuestState(guest_VSR28);
1320 case 29: return offsetofPPCGuestState(guest_VSR29);
1321 case 30: return offsetofPPCGuestState(guest_VSR30);
1322 case 31: return offsetofPPCGuestState(guest_VSR31);
1323 default: break;
1326 vpanic("floatGuestRegOffset(ppc)"); /*notreached*/
1329 static IRExpr* getFReg ( UInt archreg )
1331 vassert(archreg < 32);
1332 return IRExpr_Get( floatGuestRegOffset(archreg), Ity_F64 );
1335 /* Ditto, but write to a reg instead. */
1336 static void putFReg ( UInt archreg, IRExpr* e )
1338 vassert(archreg < 32);
1339 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64);
1340 stmt( IRStmt_Put(floatGuestRegOffset(archreg), e) );
1343 /* get Decimal float value. Note, they share floating point register file. */
1344 static IRExpr* getDReg(UInt archreg) {
1345 IRExpr *e;
1346 vassert( archreg < 32 );
1347 e = IRExpr_Get( floatGuestRegOffset( archreg ), Ity_D64 );
1348 return e;
1350 static IRExpr* getDReg32(UInt archreg) {
1351 IRExpr *e;
1352 vassert( archreg < 32 );
1353 e = IRExpr_Get( floatGuestRegOffset( archreg ), Ity_D32 );
1354 return e;
1357 /* Read a floating point register pair and combine their contents into a
1358 128-bit value */
1359 static IRExpr *getDReg_pair(UInt archreg) {
1360 IRExpr *high = getDReg( archreg );
1361 IRExpr *low = getDReg( archreg + 1 );
1363 return binop( Iop_D64HLtoD128, high, low );
1366 /* Ditto, but write to a reg instead. */
1367 static void putDReg32(UInt archreg, IRExpr* e) {
1368 vassert( archreg < 32 );
1369 vassert( typeOfIRExpr(irsb->tyenv, e) == Ity_D32 );
1370 stmt( IRStmt_Put( floatGuestRegOffset( archreg ), e ) );
1373 static void putDReg(UInt archreg, IRExpr* e) {
1374 vassert( archreg < 32 );
1375 vassert( typeOfIRExpr(irsb->tyenv, e) == Ity_D64 );
1376 stmt( IRStmt_Put( floatGuestRegOffset( archreg ), e ) );
1379 /* Write a 128-bit floating point value into a register pair. */
1380 static void putDReg_pair(UInt archreg, IRExpr *e) {
1381 IRTemp low = newTemp( Ity_D64 );
1382 IRTemp high = newTemp( Ity_D64 );
1384 vassert( archreg < 32 );
1385 vassert( typeOfIRExpr(irsb->tyenv, e) == Ity_D128 );
1387 assign( low, unop( Iop_D128LOtoD64, e ) );
1388 assign( high, unop( Iop_D128HItoD64, e ) );
1390 stmt( IRStmt_Put( floatGuestRegOffset( archreg ), mkexpr( high ) ) );
1391 stmt( IRStmt_Put( floatGuestRegOffset( archreg + 1 ), mkexpr( low ) ) );
1394 static Int vsxGuestRegOffset ( UInt archreg )
1396 vassert(archreg < 64);
1397 switch (archreg) {
1398 case 0: return offsetofPPCGuestState(guest_VSR0);
1399 case 1: return offsetofPPCGuestState(guest_VSR1);
1400 case 2: return offsetofPPCGuestState(guest_VSR2);
1401 case 3: return offsetofPPCGuestState(guest_VSR3);
1402 case 4: return offsetofPPCGuestState(guest_VSR4);
1403 case 5: return offsetofPPCGuestState(guest_VSR5);
1404 case 6: return offsetofPPCGuestState(guest_VSR6);
1405 case 7: return offsetofPPCGuestState(guest_VSR7);
1406 case 8: return offsetofPPCGuestState(guest_VSR8);
1407 case 9: return offsetofPPCGuestState(guest_VSR9);
1408 case 10: return offsetofPPCGuestState(guest_VSR10);
1409 case 11: return offsetofPPCGuestState(guest_VSR11);
1410 case 12: return offsetofPPCGuestState(guest_VSR12);
1411 case 13: return offsetofPPCGuestState(guest_VSR13);
1412 case 14: return offsetofPPCGuestState(guest_VSR14);
1413 case 15: return offsetofPPCGuestState(guest_VSR15);
1414 case 16: return offsetofPPCGuestState(guest_VSR16);
1415 case 17: return offsetofPPCGuestState(guest_VSR17);
1416 case 18: return offsetofPPCGuestState(guest_VSR18);
1417 case 19: return offsetofPPCGuestState(guest_VSR19);
1418 case 20: return offsetofPPCGuestState(guest_VSR20);
1419 case 21: return offsetofPPCGuestState(guest_VSR21);
1420 case 22: return offsetofPPCGuestState(guest_VSR22);
1421 case 23: return offsetofPPCGuestState(guest_VSR23);
1422 case 24: return offsetofPPCGuestState(guest_VSR24);
1423 case 25: return offsetofPPCGuestState(guest_VSR25);
1424 case 26: return offsetofPPCGuestState(guest_VSR26);
1425 case 27: return offsetofPPCGuestState(guest_VSR27);
1426 case 28: return offsetofPPCGuestState(guest_VSR28);
1427 case 29: return offsetofPPCGuestState(guest_VSR29);
1428 case 30: return offsetofPPCGuestState(guest_VSR30);
1429 case 31: return offsetofPPCGuestState(guest_VSR31);
1430 case 32: return offsetofPPCGuestState(guest_VSR32);
1431 case 33: return offsetofPPCGuestState(guest_VSR33);
1432 case 34: return offsetofPPCGuestState(guest_VSR34);
1433 case 35: return offsetofPPCGuestState(guest_VSR35);
1434 case 36: return offsetofPPCGuestState(guest_VSR36);
1435 case 37: return offsetofPPCGuestState(guest_VSR37);
1436 case 38: return offsetofPPCGuestState(guest_VSR38);
1437 case 39: return offsetofPPCGuestState(guest_VSR39);
1438 case 40: return offsetofPPCGuestState(guest_VSR40);
1439 case 41: return offsetofPPCGuestState(guest_VSR41);
1440 case 42: return offsetofPPCGuestState(guest_VSR42);
1441 case 43: return offsetofPPCGuestState(guest_VSR43);
1442 case 44: return offsetofPPCGuestState(guest_VSR44);
1443 case 45: return offsetofPPCGuestState(guest_VSR45);
1444 case 46: return offsetofPPCGuestState(guest_VSR46);
1445 case 47: return offsetofPPCGuestState(guest_VSR47);
1446 case 48: return offsetofPPCGuestState(guest_VSR48);
1447 case 49: return offsetofPPCGuestState(guest_VSR49);
1448 case 50: return offsetofPPCGuestState(guest_VSR50);
1449 case 51: return offsetofPPCGuestState(guest_VSR51);
1450 case 52: return offsetofPPCGuestState(guest_VSR52);
1451 case 53: return offsetofPPCGuestState(guest_VSR53);
1452 case 54: return offsetofPPCGuestState(guest_VSR54);
1453 case 55: return offsetofPPCGuestState(guest_VSR55);
1454 case 56: return offsetofPPCGuestState(guest_VSR56);
1455 case 57: return offsetofPPCGuestState(guest_VSR57);
1456 case 58: return offsetofPPCGuestState(guest_VSR58);
1457 case 59: return offsetofPPCGuestState(guest_VSR59);
1458 case 60: return offsetofPPCGuestState(guest_VSR60);
1459 case 61: return offsetofPPCGuestState(guest_VSR61);
1460 case 62: return offsetofPPCGuestState(guest_VSR62);
1461 case 63: return offsetofPPCGuestState(guest_VSR63);
1462 default: break;
1464 vpanic("vsxGuestRegOffset(ppc)"); /*notreached*/
1467 /* Vector registers are mapped to VSX registers[32..63]. */
1468 static Int vectorGuestRegOffset ( UInt archreg )
1470 vassert(archreg < 32);
1472 switch (archreg) {
1473 case 0: return offsetofPPCGuestState(guest_VSR32);
1474 case 1: return offsetofPPCGuestState(guest_VSR33);
1475 case 2: return offsetofPPCGuestState(guest_VSR34);
1476 case 3: return offsetofPPCGuestState(guest_VSR35);
1477 case 4: return offsetofPPCGuestState(guest_VSR36);
1478 case 5: return offsetofPPCGuestState(guest_VSR37);
1479 case 6: return offsetofPPCGuestState(guest_VSR38);
1480 case 7: return offsetofPPCGuestState(guest_VSR39);
1481 case 8: return offsetofPPCGuestState(guest_VSR40);
1482 case 9: return offsetofPPCGuestState(guest_VSR41);
1483 case 10: return offsetofPPCGuestState(guest_VSR42);
1484 case 11: return offsetofPPCGuestState(guest_VSR43);
1485 case 12: return offsetofPPCGuestState(guest_VSR44);
1486 case 13: return offsetofPPCGuestState(guest_VSR45);
1487 case 14: return offsetofPPCGuestState(guest_VSR46);
1488 case 15: return offsetofPPCGuestState(guest_VSR47);
1489 case 16: return offsetofPPCGuestState(guest_VSR48);
1490 case 17: return offsetofPPCGuestState(guest_VSR49);
1491 case 18: return offsetofPPCGuestState(guest_VSR50);
1492 case 19: return offsetofPPCGuestState(guest_VSR51);
1493 case 20: return offsetofPPCGuestState(guest_VSR52);
1494 case 21: return offsetofPPCGuestState(guest_VSR53);
1495 case 22: return offsetofPPCGuestState(guest_VSR54);
1496 case 23: return offsetofPPCGuestState(guest_VSR55);
1497 case 24: return offsetofPPCGuestState(guest_VSR56);
1498 case 25: return offsetofPPCGuestState(guest_VSR57);
1499 case 26: return offsetofPPCGuestState(guest_VSR58);
1500 case 27: return offsetofPPCGuestState(guest_VSR59);
1501 case 28: return offsetofPPCGuestState(guest_VSR60);
1502 case 29: return offsetofPPCGuestState(guest_VSR61);
1503 case 30: return offsetofPPCGuestState(guest_VSR62);
1504 case 31: return offsetofPPCGuestState(guest_VSR63);
1505 default: break;
1507 vpanic("vextorGuestRegOffset(ppc)"); /*notreached*/
1510 static IRExpr* getVReg ( UInt archreg )
1512 vassert(archreg < 32);
1513 return IRExpr_Get( vectorGuestRegOffset(archreg), Ity_V128 );
1516 /* Get contents of 128-bit reg guest register */
1517 static IRExpr* getF128Reg ( UInt archreg )
1519 vassert(archreg < 64);
1520 return IRExpr_Get( vectorGuestRegOffset(archreg), Ity_F128 );
1523 /* Ditto, but write to a reg instead. */
1524 static void putF128Reg ( UInt archreg, IRExpr* e )
1526 vassert(archreg < 64);
1527 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F128);
1528 stmt( IRStmt_Put(vectorGuestRegOffset(archreg), e) );
1531 /* Ditto, but write to a reg instead. */
1532 static void putVReg ( UInt archreg, IRExpr* e )
1534 vassert(archreg < 32);
1535 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
1536 stmt( IRStmt_Put(vectorGuestRegOffset(archreg), e) );
1539 /* Get contents of VSX guest register */
1540 static IRExpr* getVSReg ( UInt archreg )
1542 vassert(archreg < 64);
1543 return IRExpr_Get( vsxGuestRegOffset(archreg), Ity_V128 );
1546 /* Ditto, but write to a VSX reg instead. */
1547 static void putVSReg ( UInt archreg, IRExpr* e )
1549 vassert(archreg < 64);
1550 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
1551 stmt( IRStmt_Put(vsxGuestRegOffset(archreg), e) );
1555 static Int guestCR321offset ( UInt cr )
1557 switch (cr) {
1558 case 0: return offsetofPPCGuestState(guest_CR0_321 );
1559 case 1: return offsetofPPCGuestState(guest_CR1_321 );
1560 case 2: return offsetofPPCGuestState(guest_CR2_321 );
1561 case 3: return offsetofPPCGuestState(guest_CR3_321 );
1562 case 4: return offsetofPPCGuestState(guest_CR4_321 );
1563 case 5: return offsetofPPCGuestState(guest_CR5_321 );
1564 case 6: return offsetofPPCGuestState(guest_CR6_321 );
1565 case 7: return offsetofPPCGuestState(guest_CR7_321 );
1566 default: vpanic("guestCR321offset(ppc)");
1570 static Int guestCR0offset ( UInt cr )
1572 switch (cr) {
1573 case 0: return offsetofPPCGuestState(guest_CR0_0 );
1574 case 1: return offsetofPPCGuestState(guest_CR1_0 );
1575 case 2: return offsetofPPCGuestState(guest_CR2_0 );
1576 case 3: return offsetofPPCGuestState(guest_CR3_0 );
1577 case 4: return offsetofPPCGuestState(guest_CR4_0 );
1578 case 5: return offsetofPPCGuestState(guest_CR5_0 );
1579 case 6: return offsetofPPCGuestState(guest_CR6_0 );
1580 case 7: return offsetofPPCGuestState(guest_CR7_0 );
1581 default: vpanic("guestCR3offset(ppc)");
1585 typedef enum {
1586 _placeholder0,
1587 _placeholder1,
1588 _placeholder2,
1589 BYTE,
1590 HWORD,
1591 WORD,
1592 DWORD
1593 } _popcount_data_type;
1595 /* Generate an IR sequence to do a popcount operation on the supplied
1596 IRTemp, and return a new IRTemp holding the result. 'ty' may be
1597 Ity_I32 or Ity_I64 only. */
1598 static IRTemp gen_POPCOUNT ( IRType ty, IRTemp src, _popcount_data_type data_type )
1600 /* Do count across 2^data_type bits,
1601 byte: data_type = 3
1602 half word: data_type = 4
1603 word: data_type = 5
1604 double word: data_type = 6 (not supported for 32-bit type)
1606 Int shift[6];
1607 _popcount_data_type idx, i;
1608 IRTemp mask[6];
1609 IRTemp old = IRTemp_INVALID;
1610 IRTemp nyu = IRTemp_INVALID;
1612 vassert(ty == Ity_I64 || ty == Ity_I32);
1614 if (ty == Ity_I32) {
1616 for (idx = 0; idx < WORD; idx++) {
1617 mask[idx] = newTemp(ty);
1618 shift[idx] = 1 << idx;
1620 assign(mask[0], mkU32(0x55555555));
1621 assign(mask[1], mkU32(0x33333333));
1622 assign(mask[2], mkU32(0x0F0F0F0F));
1623 assign(mask[3], mkU32(0x00FF00FF));
1624 assign(mask[4], mkU32(0x0000FFFF));
1625 old = src;
1626 for (i = 0; i < data_type; i++) {
1627 nyu = newTemp(ty);
1628 assign(nyu,
1629 binop(Iop_Add32,
1630 binop(Iop_And32,
1631 mkexpr(old),
1632 mkexpr(mask[i])),
1633 binop(Iop_And32,
1634 binop(Iop_Shr32, mkexpr(old), mkU8(shift[i])),
1635 mkexpr(mask[i]))));
1636 old = nyu;
1638 return nyu;
1641 // else, ty == Ity_I64
1642 vassert(mode64);
1644 for (i = 0; i < DWORD; i++) {
1645 mask[i] = newTemp( Ity_I64 );
1646 shift[i] = 1 << i;
1648 assign( mask[0], mkU64( 0x5555555555555555ULL ) );
1649 assign( mask[1], mkU64( 0x3333333333333333ULL ) );
1650 assign( mask[2], mkU64( 0x0F0F0F0F0F0F0F0FULL ) );
1651 assign( mask[3], mkU64( 0x00FF00FF00FF00FFULL ) );
1652 assign( mask[4], mkU64( 0x0000FFFF0000FFFFULL ) );
1653 assign( mask[5], mkU64( 0x00000000FFFFFFFFULL ) );
1654 old = src;
1655 for (i = 0; i < data_type; i++) {
1656 nyu = newTemp( Ity_I64 );
1657 assign( nyu,
1658 binop( Iop_Add64,
1659 binop( Iop_And64, mkexpr( old ), mkexpr( mask[i] ) ),
1660 binop( Iop_And64,
1661 binop( Iop_Shr64, mkexpr( old ), mkU8( shift[i] ) ),
1662 mkexpr( mask[i] ) ) ) );
1663 old = nyu;
1665 return nyu;
1668 /* Special purpose population count function for
1669 * vpopcntd in 32-bit mode.
1671 static IRTemp gen_vpopcntd_mode32 ( IRTemp src1, IRTemp src2 )
1673 Int i, shift[6];
1674 IRTemp mask[6];
1675 IRTemp old = IRTemp_INVALID;
1676 IRTemp nyu1 = IRTemp_INVALID;
1677 IRTemp nyu2 = IRTemp_INVALID;
1678 IRTemp retval = newTemp(Ity_I64);
1680 vassert(!mode64);
1682 for (i = 0; i < WORD; i++) {
1683 mask[i] = newTemp(Ity_I32);
1684 shift[i] = 1 << i;
1686 assign(mask[0], mkU32(0x55555555));
1687 assign(mask[1], mkU32(0x33333333));
1688 assign(mask[2], mkU32(0x0F0F0F0F));
1689 assign(mask[3], mkU32(0x00FF00FF));
1690 assign(mask[4], mkU32(0x0000FFFF));
1691 old = src1;
1692 for (i = 0; i < WORD; i++) {
1693 nyu1 = newTemp(Ity_I32);
1694 assign(nyu1,
1695 binop(Iop_Add32,
1696 binop(Iop_And32,
1697 mkexpr(old),
1698 mkexpr(mask[i])),
1699 binop(Iop_And32,
1700 binop(Iop_Shr32, mkexpr(old), mkU8(shift[i])),
1701 mkexpr(mask[i]))));
1702 old = nyu1;
1705 old = src2;
1706 for (i = 0; i < WORD; i++) {
1707 nyu2 = newTemp(Ity_I32);
1708 assign(nyu2,
1709 binop(Iop_Add32,
1710 binop(Iop_And32,
1711 mkexpr(old),
1712 mkexpr(mask[i])),
1713 binop(Iop_And32,
1714 binop(Iop_Shr32, mkexpr(old), mkU8(shift[i])),
1715 mkexpr(mask[i]))));
1716 old = nyu2;
1718 assign(retval, unop(Iop_32Uto64, binop(Iop_Add32, mkexpr(nyu1), mkexpr(nyu2))));
1719 return retval;
1723 // ROTL(src32/64, rot_amt5/6)
1724 static IRExpr* /* :: Ity_I32/64 */ ROTL ( IRExpr* src,
1725 IRExpr* rot_amt )
1727 IRExpr *mask, *rot;
1728 vassert(typeOfIRExpr(irsb->tyenv,rot_amt) == Ity_I8);
1730 if (typeOfIRExpr(irsb->tyenv,src) == Ity_I64) {
1731 // rot = (src << rot_amt) | (src >> (64-rot_amt))
1732 mask = binop(Iop_And8, rot_amt, mkU8(63));
1733 rot = binop(Iop_Or64,
1734 binop(Iop_Shl64, src, mask),
1735 binop(Iop_Shr64, src, binop(Iop_Sub8, mkU8(64), mask)));
1736 } else {
1737 // rot = (src << rot_amt) | (src >> (32-rot_amt))
1738 mask = binop(Iop_And8, rot_amt, mkU8(31));
1739 rot = binop(Iop_Or32,
1740 binop(Iop_Shl32, src, mask),
1741 binop(Iop_Shr32, src, binop(Iop_Sub8, mkU8(32), mask)));
1743 /* Note: the ITE not merely an optimisation; it's needed
1744 because otherwise the Shr is a shift by the word size when
1745 mask denotes zero. For rotates by immediates, a lot of
1746 this junk gets folded out. */
1747 return IRExpr_ITE( binop(Iop_CmpNE8, mask, mkU8(0)),
1748 /* non-zero rotate */ rot,
1749 /* zero rotate */ src);
1752 /* Standard effective address calc: (rA + rB) */
1753 static IRExpr* ea_rA_idxd ( UInt rA, UInt rB )
1755 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1756 vassert(rA < 32);
1757 vassert(rB < 32);
1758 return binop(mkSzOp(ty, Iop_Add8), getIReg(rA), getIReg(rB));
1761 /* Standard effective address calc: (rA + simm) */
1762 static IRExpr* ea_rA_simm ( UInt rA, UInt simm16 )
1764 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1765 vassert(rA < 32);
1766 return binop(mkSzOp(ty, Iop_Add8), getIReg(rA),
1767 mkSzExtendS16(ty, simm16));
1770 /* Standard effective address calc: (rA|0) */
1771 static IRExpr* ea_rAor0 ( UInt rA )
1773 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1774 vassert(rA < 32);
1775 if (rA == 0) {
1776 return mkSzImm(ty, 0);
1777 } else {
1778 return getIReg(rA);
1782 /* Standard effective address calc: (rA|0) + rB */
1783 static IRExpr* ea_rAor0_idxd ( UInt rA, UInt rB )
1785 vassert(rA < 32);
1786 vassert(rB < 32);
1787 return (rA == 0) ? getIReg(rB) : ea_rA_idxd( rA, rB );
1790 /* Standard effective address calc: (rA|0) + simm16 */
1791 static IRExpr* ea_rAor0_simm ( UInt rA, UInt simm16 )
1793 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1794 vassert(rA < 32);
1795 if (rA == 0) {
1796 return mkSzExtendS16(ty, simm16);
1797 } else {
1798 return ea_rA_simm( rA, simm16 );
1803 /* Align effective address */
1804 static IRExpr* addr_align( IRExpr* addr, UChar align )
1806 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1807 ULong mask;
1808 switch (align) {
1809 case 1: return addr; // byte aligned
1810 case 2: mask = ~0ULL << 1; break; // half-word aligned
1811 case 4: mask = ~0ULL << 2; break; // word aligned
1812 case 16: mask = ~0ULL << 4; break; // quad-word aligned
1813 default:
1814 vex_printf("addr_align: align = %u\n", align);
1815 vpanic("addr_align(ppc)");
1818 vassert(typeOfIRExpr(irsb->tyenv,addr) == ty);
1819 return binop( mkSzOp(ty, Iop_And8), addr, mkSzImm(ty, mask) );
1823 /* Exit the trace if ADDR (intended to be a guest memory address) is
1824 not ALIGN-aligned, generating a request for a SIGBUS followed by a
1825 restart of the current insn. */
1826 static void gen_SIGBUS_if_misaligned ( IRTemp addr, UChar align )
1828 vassert(align == 2 || align == 4 || align == 8 || align == 16);
1829 if (mode64) {
1830 vassert(typeOfIRTemp(irsb->tyenv, addr) == Ity_I64);
1831 stmt(
1832 IRStmt_Exit(
1833 binop(Iop_CmpNE64,
1834 binop(Iop_And64, mkexpr(addr), mkU64(align-1)),
1835 mkU64(0)),
1836 Ijk_SigBUS,
1837 IRConst_U64( guest_CIA_curr_instr ), OFFB_CIA
1840 } else {
1841 vassert(typeOfIRTemp(irsb->tyenv, addr) == Ity_I32);
1842 stmt(
1843 IRStmt_Exit(
1844 binop(Iop_CmpNE32,
1845 binop(Iop_And32, mkexpr(addr), mkU32(align-1)),
1846 mkU32(0)),
1847 Ijk_SigBUS,
1848 IRConst_U32( guest_CIA_curr_instr ), OFFB_CIA
1855 /* Generate AbiHints which mark points at which the ELF or PowerOpen
1856 ABIs say that the stack red zone (viz, -N(r1) .. -1(r1), for some
1857 N) becomes undefined. That is at function calls and returns. ELF
1858 ppc32 doesn't have this "feature" (how fortunate for it). nia is
1859 the address of the next instruction to be executed.
1861 static void make_redzone_AbiHint ( const VexAbiInfo* vbi,
1862 IRTemp nia, const HChar* who )
1864 Int szB = vbi->guest_stack_redzone_size;
1865 if (0) vex_printf("AbiHint: %s\n", who);
1866 vassert(szB >= 0);
1867 if (szB > 0) {
1868 if (mode64) {
1869 vassert(typeOfIRTemp(irsb->tyenv, nia) == Ity_I64);
1870 stmt( IRStmt_AbiHint(
1871 binop(Iop_Sub64, getIReg(1), mkU64(szB)),
1872 szB,
1873 mkexpr(nia)
1875 } else {
1876 vassert(typeOfIRTemp(irsb->tyenv, nia) == Ity_I32);
1877 stmt( IRStmt_AbiHint(
1878 binop(Iop_Sub32, getIReg(1), mkU32(szB)),
1879 szB,
1880 mkexpr(nia)
1887 /*------------------------------------------------------------*/
1888 /*--- Helpers for condition codes. ---*/
1889 /*------------------------------------------------------------*/
1891 /* Condition register layout.
1893 In the hardware, CR is laid out like this. The leftmost end is the
1894 most significant bit in the register; however the IBM documentation
1895 numbers the bits backwards for some reason.
1897 CR0 CR1 .......... CR6 CR7
1898 0 .. 3 ....................... 28 .. 31 (IBM bit numbering)
1899 31 28 3 0 (normal bit numbering)
1901 Each CR field is 4 bits: [<,>,==,SO]
1903 Hence in IBM's notation, BI=0 is CR7[SO], BI=1 is CR7[==], etc.
1905 Indexing from BI to guest state:
1907 let n = BI / 4
1908 off = BI % 4
1909 this references CR n:
1911 off==0 -> guest_CRn_321 >> 3
1912 off==1 -> guest_CRn_321 >> 2
1913 off==2 -> guest_CRn_321 >> 1
1914 off==3 -> guest_CRn_SO
1916 Bear in mind the only significant bit in guest_CRn_SO is bit 0
1917 (normal notation) and in guest_CRn_321 the significant bits are
1918 3, 2 and 1 (normal notation).
1921 static void putCR321 ( UInt cr, IRExpr* e )
1923 vassert(cr < 8);
1924 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
1925 stmt( IRStmt_Put(guestCR321offset(cr), e) );
1928 static void putCR0 ( UInt cr, IRExpr* e )
1930 vassert(cr < 8);
1931 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
1932 stmt( IRStmt_Put(guestCR0offset(cr), e) );
1935 static void putC ( IRExpr* e )
1937 /* The assumption is that the value of the Floating-Point Result
1938 * Class Descriptor bit (C) is passed in the lower four bits of a
1939 * 32 bit value.
1941 * Note, the C and FPCC bits which are fields in the FPSCR
1942 * register are stored in their own memory location of
1943 * memory. The FPCC bits are in the lower 4 bits. The C bit needs
1944 * to be shifted to bit 4 in the memory location that holds C and FPCC.
1945 * Note not all of the FPSCR register bits are supported. We are
1946 * only writing C bit.
1948 IRExpr* tmp;
1950 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
1952 /* Get the FPCC bit field */
1953 tmp = binop( Iop_And32,
1954 mkU32( 0xF ),
1955 unop( Iop_8Uto32, IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ) );
1957 stmt( IRStmt_Put( OFFB_C_FPCC,
1958 unop( Iop_32to8,
1959 binop( Iop_Or32, tmp,
1960 binop( Iop_Shl32,
1961 binop( Iop_And32, mkU32( 0x1 ), e ),
1962 mkU8( 4 ) ) ) ) ) );
1965 static IRExpr* /* :: Ity_I8 */ getCR0 ( UInt cr )
1967 vassert(cr < 8);
1968 return IRExpr_Get(guestCR0offset(cr), Ity_I8);
1971 static IRExpr* /* :: Ity_I8 */ getCR321 ( UInt cr )
1973 vassert(cr < 8);
1974 return IRExpr_Get(guestCR321offset(cr), Ity_I8);
1977 /* Fetch the specified CR bit (as per IBM/hardware notation) and
1978 return it at the bottom of an I32; the top 31 bits are guaranteed
1979 to be zero. */
1980 static IRExpr* /* :: Ity_I32 */ getCRbit ( UInt bi )
1982 UInt n = bi / 4;
1983 UInt off = bi % 4;
1984 vassert(bi < 32);
1985 if (off == 3) {
1986 /* Fetch the SO bit for this CR field */
1987 /* Note: And32 is redundant paranoia iff guest state only has 0
1988 or 1 in that slot. */
1989 return binop(Iop_And32, unop(Iop_8Uto32, getCR0(n)), mkU32(1));
1990 } else {
1991 /* Fetch the <, > or == bit for this CR field */
1992 return binop( Iop_And32,
1993 binop( Iop_Shr32,
1994 unop(Iop_8Uto32, getCR321(n)),
1995 mkU8(toUChar(3-off)) ),
1996 mkU32(1) );
2000 /* Dually, write the least significant bit of BIT to the specified CR
2001 bit. Indexing as per getCRbit. */
2002 static void putCRbit ( UInt bi, IRExpr* bit )
2004 UInt n, off;
2005 IRExpr* safe;
2006 vassert(typeOfIRExpr(irsb->tyenv,bit) == Ity_I32);
2007 safe = binop(Iop_And32, bit, mkU32(1));
2008 n = bi / 4;
2009 off = bi % 4;
2010 vassert(bi < 32);
2011 if (off == 3) {
2012 /* This is the SO bit for this CR field */
2013 putCR0(n, unop(Iop_32to8, safe));
2014 } else {
2015 off = 3 - off;
2016 vassert(off == 1 || off == 2 || off == 3);
2017 putCR321(
2019 unop( Iop_32to8,
2020 binop( Iop_Or32,
2021 /* old value with field masked out */
2022 binop(Iop_And32, unop(Iop_8Uto32, getCR321(n)),
2023 mkU32(~(1 << off))),
2024 /* new value in the right place */
2025 binop(Iop_Shl32, safe, mkU8(toUChar(off)))
2032 /* Fetch the specified CR bit (as per IBM/hardware notation) and
2033 return it somewhere in an I32; it does not matter where, but
2034 whichever bit it is, all other bits are guaranteed to be zero. In
2035 other words, the I32-typed expression will be zero if the bit is
2036 zero and nonzero if the bit is 1. Write into *where the index
2037 of where the bit will be. */
2039 static
2040 IRExpr* /* :: Ity_I32 */ getCRbit_anywhere ( UInt bi, Int* where )
2042 UInt n = bi / 4;
2043 UInt off = bi % 4;
2044 vassert(bi < 32);
2045 if (off == 3) {
2046 /* Fetch the SO bit for this CR field */
2047 /* Note: And32 is redundant paranoia iff guest state only has 0
2048 or 1 in that slot. */
2049 *where = 0;
2050 return binop(Iop_And32, unop(Iop_8Uto32, getCR0(n)), mkU32(1));
2051 } else {
2052 /* Fetch the <, > or == bit for this CR field */
2053 *where = 3-off;
2054 return binop( Iop_And32,
2055 unop(Iop_8Uto32, getCR321(n)),
2056 mkU32(1 << (3-off)) );
2060 /* Set the CR0 flags following an arithmetic operation.
2061 (Condition Register CR0 Field Definition, PPC32 p60)
2063 static IRExpr* getXER_SO ( void );
2064 static void set_CR0 ( IRExpr* result )
2066 vassert(typeOfIRExpr(irsb->tyenv,result) == Ity_I32 ||
2067 typeOfIRExpr(irsb->tyenv,result) == Ity_I64);
2068 if (mode64) {
2069 putCR321( 0, unop(Iop_64to8,
2070 binop(Iop_CmpORD64S, result, mkU64(0))) );
2071 } else {
2072 putCR321( 0, unop(Iop_32to8,
2073 binop(Iop_CmpORD32S, result, mkU32(0))) );
2075 putCR0( 0, getXER_SO() );
2079 /* Set the CR6 flags following an AltiVec compare operation.
2080 * NOTE: This also works for VSX single-precision compares.
2081 * */
2082 static void set_AV_CR6 ( IRExpr* result, Bool test_all_ones )
2084 /* CR6[0:3] = {all_ones, 0, all_zeros, 0}
2085 all_ones = (v[0] && v[1] && v[2] && v[3])
2086 all_zeros = ~(v[0] || v[1] || v[2] || v[3])
2088 IRTemp v0 = newTemp(Ity_V128);
2089 IRTemp v1 = newTemp(Ity_V128);
2090 IRTemp v2 = newTemp(Ity_V128);
2091 IRTemp v3 = newTemp(Ity_V128);
2092 IRTemp rOnes = newTemp(Ity_I8);
2093 IRTemp rZeros = newTemp(Ity_I8);
2095 vassert(typeOfIRExpr(irsb->tyenv,result) == Ity_V128);
2097 assign( v0, result );
2098 assign( v1, binop(Iop_ShrV128, result, mkU8(32)) );
2099 assign( v2, binop(Iop_ShrV128, result, mkU8(64)) );
2100 assign( v3, binop(Iop_ShrV128, result, mkU8(96)) );
2102 assign( rZeros, unop(Iop_1Uto8,
2103 binop(Iop_CmpEQ32, mkU32(0xFFFFFFFF),
2104 unop(Iop_Not32,
2105 unop(Iop_V128to32,
2106 binop(Iop_OrV128,
2107 binop(Iop_OrV128, mkexpr(v0), mkexpr(v1)),
2108 binop(Iop_OrV128, mkexpr(v2), mkexpr(v3))))
2109 ))) );
2111 if (test_all_ones) {
2112 assign( rOnes, unop(Iop_1Uto8,
2113 binop(Iop_CmpEQ32, mkU32(0xFFFFFFFF),
2114 unop(Iop_V128to32,
2115 binop(Iop_AndV128,
2116 binop(Iop_AndV128, mkexpr(v0), mkexpr(v1)),
2117 binop(Iop_AndV128, mkexpr(v2), mkexpr(v3)))
2118 ))) );
2119 putCR321( 6, binop(Iop_Or8,
2120 binop(Iop_Shl8, mkexpr(rOnes), mkU8(3)),
2121 binop(Iop_Shl8, mkexpr(rZeros), mkU8(1))) );
2122 } else {
2123 putCR321( 6, binop(Iop_Shl8, mkexpr(rZeros), mkU8(1)) );
2125 putCR0( 6, mkU8(0) );
2129 static IRExpr * create_DCM ( IRType size, IRTemp NaN, IRTemp inf, IRTemp zero,
2130 IRTemp dnorm, IRTemp pos)
2132 /* This is a general function for creating the DCM for a 32-bit or
2133 64-bit expression based on the passes size.
2135 IRTemp neg;
2136 IROp opAND, opOR, opSHL, opXto1, op1UtoX;
2138 vassert( ( size == Ity_I32 ) || ( size == Ity_I64 ) );
2140 if ( size == Ity_I32 ) {
2141 opSHL = Iop_Shl32;
2142 opAND = Iop_And32;
2143 opOR = Iop_Or32;
2144 opXto1 = Iop_32to1;
2145 op1UtoX = Iop_1Uto32;
2146 neg = newTemp( Ity_I32 );
2148 } else {
2149 opSHL = Iop_Shl64;
2150 opAND = Iop_And64;
2151 opOR = Iop_Or64;
2152 opXto1 = Iop_64to1;
2153 op1UtoX = Iop_1Uto64;
2154 neg = newTemp( Ity_I64 );
2157 assign( neg, unop( op1UtoX, mkNOT1( unop( opXto1,
2158 mkexpr ( pos ) ) ) ) );
2160 return binop( opOR,
2161 binop( opSHL, mkexpr( NaN ), mkU8( 6 ) ),
2162 binop( opOR,
2163 binop( opOR,
2164 binop( opOR,
2165 binop( opSHL,
2166 binop( opAND,
2167 mkexpr( pos ),
2168 mkexpr( inf ) ),
2169 mkU8( 5 ) ),
2170 binop( opSHL,
2171 binop( opAND,
2172 mkexpr( neg ),
2173 mkexpr( inf ) ),
2174 mkU8( 4 ) ) ),
2175 binop( opOR,
2176 binop( opSHL,
2177 binop( opAND,
2178 mkexpr( pos ),
2179 mkexpr( zero ) ),
2180 mkU8( 3 ) ),
2181 binop( opSHL,
2182 binop( opAND,
2183 mkexpr( neg ),
2184 mkexpr( zero ) ),
2185 mkU8( 2 ) ) ) ),
2186 binop( opOR,
2187 binop( opSHL,
2188 binop( opAND,
2189 mkexpr( pos ),
2190 mkexpr( dnorm ) ),
2191 mkU8( 1 ) ),
2192 binop( opAND,
2193 mkexpr( neg ),
2194 mkexpr( dnorm ) ) ) ) );
2197 /*------------------------------------------------------------*/
2198 /*--- Helpers for XER flags. ---*/
2199 /*------------------------------------------------------------*/
2201 static void putXER_SO ( IRExpr* e )
2203 IRExpr* so;
2204 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
2205 so = binop(Iop_And8, e, mkU8(1));
2206 stmt( IRStmt_Put( OFFB_XER_SO, so ) );
2209 static void putXER_OV ( IRExpr* e )
2211 /* Interface to write XER[OV] */
2212 IRExpr* ov;
2213 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
2214 ov = binop(Iop_And8, e, mkU8(1));
2215 stmt( IRStmt_Put( OFFB_XER_OV, ov ) );
2218 static void putXER_OV32 ( IRExpr* e )
2220 /*Interface to write XER[OV32] */
2221 IRExpr* ov;
2222 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
2223 ov = binop(Iop_And8, e, mkU8(1));
2225 /* The OV32 bit was added to XER in ISA 3.0. Do not write unless we
2226 * ISA 3.0 or beyond is supported. */
2227 if( OV32_CA32_supported )
2228 stmt( IRStmt_Put( OFFB_XER_OV32, ov ) );
2231 static void putXER_CA ( IRExpr* e )
2233 /* Interface to write XER[CA] */
2234 IRExpr* ca;
2235 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
2236 ca = binop(Iop_And8, e, mkU8(1));
2237 stmt( IRStmt_Put( OFFB_XER_CA, ca ) );
2240 static void putXER_CA32 ( IRExpr* e )
2242 /* Interface to write XER[CA32] */
2243 IRExpr* ca;
2244 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
2245 ca = binop(Iop_And8, e, mkU8(1));
2247 /* The CA32 bit was added to XER in ISA 3.0. Do not write unless we
2248 * ISA 3.0 or beyond is supported. */
2249 if( OV32_CA32_supported )
2250 stmt( IRStmt_Put( OFFB_XER_CA32, ca ) );
2253 static void putXER_BC ( IRExpr* e )
2255 IRExpr* bc;
2256 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
2257 bc = binop(Iop_And8, e, mkU8(0x7F));
2258 stmt( IRStmt_Put( OFFB_XER_BC, bc ) );
2261 static IRExpr* /* :: Ity_I8 */ getXER_SO ( void )
2263 return IRExpr_Get( OFFB_XER_SO, Ity_I8 );
2266 static IRExpr* /* :: Ity_I32 */ getXER_SO_32 ( void )
2268 return binop( Iop_And32, unop(Iop_8Uto32, getXER_SO()), mkU32(1) );
2271 static IRExpr* /* :: Ity_I8 */ getXER_OV ( void )
2273 return IRExpr_Get( OFFB_XER_OV, Ity_I8 );
2276 static IRExpr* /* :: Ity_I8 */ getXER_OV32 ( void )
2278 return IRExpr_Get( OFFB_XER_OV32, Ity_I8 );
2281 static IRExpr* /* :: Ity_I32 */ getXER_OV_32 ( void )
2283 /* get XER[OV], 32-bit interface */
2284 return binop( Iop_And32, unop(Iop_8Uto32, getXER_OV()), mkU32(1) );
2287 static IRExpr* /* :: Ity_I32 */ getXER_OV32_32 ( void )
2289 /* get XER[OV32], 32-bit interface */
2290 return binop( Iop_And32, unop(Iop_8Uto32, getXER_OV32()), mkU32(1) );
2293 static IRExpr* /* :: Ity_I32 */ getXER_CA_32 ( void )
2295 /* get XER[CA], 32-bit interface */
2296 IRExpr* ca = IRExpr_Get( OFFB_XER_CA, Ity_I8 );
2297 return binop( Iop_And32, unop(Iop_8Uto32, ca ), mkU32(1) );
2300 static IRExpr* /* :: Ity_I32 */ getXER_CA32_32 ( void )
2302 /* get XER[CA32], 32-bit interface */
2303 IRExpr* ca = IRExpr_Get( OFFB_XER_CA32, Ity_I8 );
2304 return binop( Iop_And32, unop(Iop_8Uto32, ca ), mkU32(1) );
2307 static IRExpr* /* :: Ity_I8 */ getXER_BC ( void )
2309 return IRExpr_Get( OFFB_XER_BC, Ity_I8 );
2312 static IRExpr* /* :: Ity_I32 */ getXER_BC_32 ( void )
2314 IRExpr* bc = IRExpr_Get( OFFB_XER_BC, Ity_I8 );
2315 return binop( Iop_And32, unop(Iop_8Uto32, bc), mkU32(0x7F) );
2319 /* RES is the result of doing OP on ARGL and ARGR. Set %XER.OV and
2320 %XER.SO accordingly. */
2322 static IRExpr* calculate_XER_OV_32( UInt op, IRExpr* res,
2323 IRExpr* argL, IRExpr* argR )
2325 IRTemp t64;
2326 IRExpr* xer_ov;
2328 # define INT32_MIN 0x80000000
2330 # define XOR2(_aa,_bb) \
2331 binop(Iop_Xor32,(_aa),(_bb))
2333 # define XOR3(_cc,_dd,_ee) \
2334 binop(Iop_Xor32,binop(Iop_Xor32,(_cc),(_dd)),(_ee))
2336 # define AND3(_ff,_gg,_hh) \
2337 binop(Iop_And32,binop(Iop_And32,(_ff),(_gg)),(_hh))
2339 #define NOT(_jj) \
2340 unop(Iop_Not32, (_jj))
2342 switch (op) {
2343 case /* 0 */ PPCG_FLAG_OP_ADD:
2344 case /* 1 */ PPCG_FLAG_OP_ADDE:
2345 /* (argL^argR^-1) & (argL^res) & (1<<31) ?1:0 */
2346 // i.e. ((both_same_sign) & (sign_changed) & (sign_mask))
2347 xer_ov
2348 = AND3( XOR3(argL,argR,mkU32(-1)),
2349 XOR2(argL,res),
2350 mkU32(INT32_MIN) );
2351 /* xer_ov can only be 0 or 1<<31 */
2352 xer_ov
2353 = binop(Iop_Shr32, xer_ov, mkU8(31) );
2354 break;
2356 case /* 2 */ PPCG_FLAG_OP_DIVW:
2357 /* (argL == INT32_MIN && argR == -1) || argR == 0 */
2358 xer_ov
2359 = mkOR1(
2360 mkAND1(
2361 binop(Iop_CmpEQ32, argL, mkU32(INT32_MIN)),
2362 binop(Iop_CmpEQ32, argR, mkU32(-1))
2364 binop(Iop_CmpEQ32, argR, mkU32(0) )
2366 xer_ov
2367 = unop(Iop_1Uto32, xer_ov);
2368 break;
2370 case /* 3 */ PPCG_FLAG_OP_DIVWU:
2371 /* argR == 0 */
2372 xer_ov
2373 = unop(Iop_1Uto32, binop(Iop_CmpEQ32, argR, mkU32(0)));
2374 break;
2376 case /* 4 */ PPCG_FLAG_OP_MULLW:
2377 /* OV true if result can't be represented in 32 bits
2378 i.e sHi != sign extension of sLo */
2379 t64 = newTemp(Ity_I64);
2380 assign( t64, binop(Iop_MullS32, argL, argR) );
2381 xer_ov
2382 = binop( Iop_CmpNE32,
2383 unop(Iop_64HIto32, mkexpr(t64)),
2384 binop( Iop_Sar32,
2385 unop(Iop_64to32, mkexpr(t64)),
2386 mkU8(31))
2388 xer_ov
2389 = unop(Iop_1Uto32, xer_ov);
2390 break;
2392 case /* 5 */ PPCG_FLAG_OP_NEG:
2393 /* argL == INT32_MIN */
2394 xer_ov
2395 = unop( Iop_1Uto32,
2396 binop(Iop_CmpEQ32, argL, mkU32(INT32_MIN)) );
2397 break;
2399 case /* 6 */ PPCG_FLAG_OP_SUBF:
2400 case /* 7 */ PPCG_FLAG_OP_SUBFC:
2401 case /* 8 */ PPCG_FLAG_OP_SUBFE:
2402 /* ((~argL)^argR^-1) & ((~argL)^res) & (1<<31) ?1:0; */
2403 xer_ov
2404 = AND3( XOR3(NOT(argL),argR,mkU32(-1)),
2405 XOR2(NOT(argL),res),
2406 mkU32(INT32_MIN) );
2407 /* xer_ov can only be 0 or 1<<31 */
2408 xer_ov
2409 = binop(Iop_Shr32, xer_ov, mkU8(31) );
2410 break;
2412 case PPCG_FLAG_OP_DIVWEU:
2413 xer_ov
2414 = binop( Iop_Or32,
2415 unop( Iop_1Uto32, binop( Iop_CmpEQ32, argR, mkU32( 0 ) ) ),
2416 unop( Iop_1Uto32, binop( Iop_CmpLT32U, argR, argL ) ) );
2417 break;
2419 case PPCG_FLAG_OP_DIVWE:
2421 /* If argR == 0 of if the result cannot fit in the 32-bit destination register,
2422 * then OV <- 1. If dest reg is 0 AND both dividend and divisor are non-zero,
2423 * an overflow is implied.
2425 xer_ov = binop( Iop_Or32,
2426 unop( Iop_1Uto32, binop( Iop_CmpEQ32, argR, mkU32( 0 ) ) ),
2427 unop( Iop_1Uto32, mkAND1( binop( Iop_CmpEQ32, res, mkU32( 0 ) ),
2428 mkAND1( binop( Iop_CmpNE32, argL, mkU32( 0 ) ),
2429 binop( Iop_CmpNE32, argR, mkU32( 0 ) ) ) ) ) );
2430 break;
2434 default:
2435 vex_printf("calculate_XER_OV_32: op = %u\n", op);
2436 vpanic("calculate_XER_OV_32(ppc)");
2439 return xer_ov;
2441 # undef INT32_MIN
2442 # undef AND3
2443 # undef XOR3
2444 # undef XOR2
2445 # undef NOT
2448 static void set_XER_OV_OV32_32( UInt op, IRExpr* res,
2449 IRExpr* argL, IRExpr* argR )
2451 IRExpr* xer_ov;
2453 vassert(op < PPCG_FLAG_OP_NUMBER);
2454 vassert(typeOfIRExpr(irsb->tyenv,res) == Ity_I32);
2455 vassert(typeOfIRExpr(irsb->tyenv,argL) == Ity_I32);
2456 vassert(typeOfIRExpr(irsb->tyenv,argR) == Ity_I32);
2458 xer_ov = calculate_XER_OV_32( op, res, argL, argR );
2460 /* xer_ov MUST denote either 0 or 1, no other value allowed */
2461 putXER_OV( unop(Iop_32to8, xer_ov) );
2462 putXER_OV32( unop(Iop_32to8, xer_ov) );
2465 static IRExpr* calculate_XER_OV_64( UInt op, IRExpr* res,
2466 IRExpr* argL, IRExpr* argR )
2468 IRExpr* xer_ov;
2470 # define INT64_MIN 0x8000000000000000ULL
2472 # define XOR2(_aa,_bb) \
2473 binop(Iop_Xor64,(_aa),(_bb))
2475 # define XOR3(_cc,_dd,_ee) \
2476 binop(Iop_Xor64,binop(Iop_Xor64,(_cc),(_dd)),(_ee))
2478 # define AND3(_ff,_gg,_hh) \
2479 binop(Iop_And64,binop(Iop_And64,(_ff),(_gg)),(_hh))
2481 #define NOT(_jj) \
2482 unop(Iop_Not64, (_jj))
2484 switch (op) {
2485 case /* 0 */ PPCG_FLAG_OP_ADD:
2486 case /* 1 */ PPCG_FLAG_OP_ADDE:
2487 /* (argL^argR^-1) & (argL^res) & (1<<63) ? 1:0 */
2488 // i.e. ((both_same_sign) & (sign_changed) & (sign_mask))
2489 xer_ov
2490 = AND3( XOR3(argL,argR,mkU64(-1)),
2491 XOR2(argL,res),
2492 mkU64(INT64_MIN) );
2493 /* xer_ov can only be 0 or 1<<63 */
2494 xer_ov
2495 = unop(Iop_64to1, binop(Iop_Shr64, xer_ov, mkU8(63)));
2496 break;
2498 case /* 2 */ PPCG_FLAG_OP_DIVW:
2499 /* (argL == INT64_MIN && argR == -1) || argR == 0 */
2500 xer_ov
2501 = mkOR1(
2502 mkAND1(
2503 binop(Iop_CmpEQ64, argL, mkU64(INT64_MIN)),
2504 binop(Iop_CmpEQ64, argR, mkU64(-1))
2506 binop(Iop_CmpEQ64, argR, mkU64(0) )
2508 break;
2510 case /* 3 */ PPCG_FLAG_OP_DIVWU:
2511 /* argR == 0 */
2512 xer_ov
2513 = binop(Iop_CmpEQ64, argR, mkU64(0));
2514 break;
2516 case /* 4 */ PPCG_FLAG_OP_MULLW: {
2517 /* OV true if result can't be represented in 64 bits
2518 i.e sHi != sign extension of sLo */
2519 xer_ov
2520 = binop( Iop_CmpNE32,
2521 unop(Iop_64HIto32, res),
2522 binop( Iop_Sar32,
2523 unop(Iop_64to32, res),
2524 mkU8(31))
2526 break;
2529 case /* 5 */ PPCG_FLAG_OP_NEG:
2530 /* argL == INT64_MIN */
2531 xer_ov
2532 = binop(Iop_CmpEQ64, argL, mkU64(INT64_MIN));
2533 break;
2535 case /* 6 */ PPCG_FLAG_OP_SUBF:
2536 case /* 7 */ PPCG_FLAG_OP_SUBFC:
2537 case /* 8 */ PPCG_FLAG_OP_SUBFE:
2538 /* ((~argL)^argR^-1) & ((~argL)^res) & (1<<63) ?1:0; */
2539 xer_ov
2540 = AND3( XOR3(NOT(argL),argR,mkU64(-1)),
2541 XOR2(NOT(argL),res),
2542 mkU64(INT64_MIN) );
2543 /* xer_ov can only be 0 or 1<<63 */
2544 xer_ov
2545 = unop(Iop_64to1, binop(Iop_Shr64, xer_ov, mkU8(63)));
2546 break;
2548 case /* 14 */ PPCG_FLAG_OP_DIVDE:
2550 /* If argR == 0, we must set the OV bit. But there's another condition
2551 * where we can get overflow set for divde . . . when the
2552 * result cannot fit in the 64-bit destination register. If dest reg is 0 AND
2553 * both dividend and divisor are non-zero, it implies an overflow.
2555 xer_ov
2556 = mkOR1( binop( Iop_CmpEQ64, argR, mkU64( 0 ) ),
2557 mkAND1( binop( Iop_CmpEQ64, res, mkU64( 0 ) ),
2558 mkAND1( binop( Iop_CmpNE64, argL, mkU64( 0 ) ),
2559 binop( Iop_CmpNE64, argR, mkU64( 0 ) ) ) ) );
2560 break;
2562 case /* 17 */ PPCG_FLAG_OP_DIVDEU:
2563 /* If argR == 0 or if argL >= argR, set OV. */
2564 xer_ov = mkOR1( binop( Iop_CmpEQ64, argR, mkU64( 0 ) ),
2565 binop( Iop_CmpLE64U, argR, argL ) );
2566 break;
2568 case /* 18 */ PPCG_FLAG_OP_MULLD: {
2569 IRTemp t128;
2570 /* OV true if result can't be represented in 64 bits
2571 i.e sHi != sign extension of sLo */
2572 t128 = newTemp(Ity_I128);
2573 assign( t128, binop(Iop_MullS64, argL, argR) );
2574 xer_ov
2575 = binop( Iop_CmpNE64,
2576 unop(Iop_128HIto64, mkexpr(t128)),
2577 binop( Iop_Sar64,
2578 unop(Iop_128to64, mkexpr(t128)),
2579 mkU8(63))
2581 break;
2584 default:
2585 vex_printf("calculate_XER_OV_64: op = %u\n", op);
2586 vpanic("calculate_XER_OV_64(ppc64)");
2589 return xer_ov;
2591 # undef INT64_MIN
2592 # undef AND3
2593 # undef XOR3
2594 # undef XOR2
2595 # undef NOT
2598 static void set_XER_OV_64( UInt op, IRExpr* res,
2599 IRExpr* argL, IRExpr* argR )
2601 IRExpr* xer_ov;
2602 vassert(op < PPCG_FLAG_OP_NUMBER);
2603 vassert(typeOfIRExpr(irsb->tyenv,res) == Ity_I64);
2604 vassert(typeOfIRExpr(irsb->tyenv,argL) == Ity_I64);
2605 vassert(typeOfIRExpr(irsb->tyenv,argR) == Ity_I64);
2607 /* xer_ov MUST denote either 0 or 1, no other value allowed */
2608 xer_ov = calculate_XER_OV_64( op, res, argL, argR);
2609 putXER_OV( unop(Iop_1Uto8, xer_ov) );
2611 /* Update the summary overflow */
2612 putXER_SO( binop(Iop_Or8, getXER_SO(), getXER_OV()) );
2615 static void update_SO( void ) {
2616 /* Update the summary overflow bit */
2617 putXER_SO( binop(Iop_Or8, getXER_SO(), getXER_OV()) );
2620 static void copy_OV_to_OV32( void ) {
2621 /* Update the OV32 to match OV */
2622 putXER_OV32( getXER_OV() );
2625 static void set_XER_OV_OV32 ( IRType ty, UInt op, IRExpr* res,
2626 IRExpr* argL, IRExpr* argR )
2628 if (ty == Ity_I32) {
2629 set_XER_OV_OV32_32( op, res, argL, argR );
2630 } else {
2631 IRExpr* xer_ov_32;
2632 set_XER_OV_64( op, res, argL, argR );
2633 xer_ov_32 = calculate_XER_OV_32( op, unop(Iop_64to32, res),
2634 unop(Iop_64to32, argL),
2635 unop(Iop_64to32, argR));
2636 putXER_OV32( unop(Iop_32to8, xer_ov_32) );
2640 static void set_XER_OV_OV32_SO ( IRType ty, UInt op, IRExpr* res,
2641 IRExpr* argL, IRExpr* argR )
2643 if (ty == Ity_I32) {
2644 set_XER_OV_OV32_32( op, res, argL, argR );
2645 } else {
2646 IRExpr* xer_ov_32;
2647 set_XER_OV_64( op, res, argL, argR );
2648 xer_ov_32 = calculate_XER_OV_32( op, unop(Iop_64to32, res),
2649 unop(Iop_64to32, argL),
2650 unop(Iop_64to32, argR));
2651 putXER_OV32( unop(Iop_32to8, xer_ov_32) );
2653 update_SO();
2658 /* RES is the result of doing OP on ARGL and ARGR with the old %XER.CA
2659 value being OLDCA. Set %XER.CA accordingly. */
2661 static IRExpr* calculate_XER_CA_32 ( UInt op, IRExpr* res,
2662 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
2664 IRExpr* xer_ca;
2666 switch (op) {
2667 case /* 0 */ PPCG_FLAG_OP_ADD:
2668 /* res <u argL */
2669 xer_ca
2670 = unop(Iop_1Uto32, binop(Iop_CmpLT32U, res, argL));
2671 break;
2673 case /* 1 */ PPCG_FLAG_OP_ADDE:
2674 /* res <u argL || (old_ca==1 && res==argL) */
2675 xer_ca
2676 = mkOR1(
2677 binop(Iop_CmpLT32U, res, argL),
2678 mkAND1(
2679 binop(Iop_CmpEQ32, oldca, mkU32(1)),
2680 binop(Iop_CmpEQ32, res, argL)
2683 xer_ca
2684 = unop(Iop_1Uto32, xer_ca);
2685 break;
2687 case /* 8 */ PPCG_FLAG_OP_SUBFE:
2688 /* res <u argR || (old_ca==1 && res==argR) */
2689 xer_ca
2690 = mkOR1(
2691 binop(Iop_CmpLT32U, res, argR),
2692 mkAND1(
2693 binop(Iop_CmpEQ32, oldca, mkU32(1)),
2694 binop(Iop_CmpEQ32, res, argR)
2697 xer_ca
2698 = unop(Iop_1Uto32, xer_ca);
2699 break;
2701 case /* 7 */ PPCG_FLAG_OP_SUBFC:
2702 case /* 9 */ PPCG_FLAG_OP_SUBFI:
2703 /* res <=u argR */
2704 xer_ca
2705 = unop(Iop_1Uto32, binop(Iop_CmpLE32U, res, argR));
2706 break;
2708 case /* 10 */ PPCG_FLAG_OP_SRAW:
2709 /* The shift amount is guaranteed to be in 0 .. 63 inclusive.
2710 If it is <= 31, behave like SRAWI; else XER.CA is the sign
2711 bit of argL. */
2712 /* This term valid for shift amount < 32 only */
2713 xer_ca
2714 = binop(
2715 Iop_And32,
2716 binop(Iop_Sar32, argL, mkU8(31)),
2717 binop( Iop_And32,
2718 argL,
2719 binop( Iop_Sub32,
2720 binop(Iop_Shl32, mkU32(1),
2721 unop(Iop_32to8,argR)),
2722 mkU32(1) )
2725 xer_ca
2726 = IRExpr_ITE(
2727 /* shift amt > 31 ? */
2728 binop(Iop_CmpLT32U, mkU32(31), argR),
2729 /* yes -- get sign bit of argL */
2730 binop(Iop_Shr32, argL, mkU8(31)),
2731 /* no -- be like srawi */
2732 unop(Iop_1Uto32, binop(Iop_CmpNE32, xer_ca, mkU32(0)))
2734 break;
2736 case /* 11 */ PPCG_FLAG_OP_SRAWI:
2737 /* xer_ca is 1 iff src was negative and bits_shifted_out !=
2738 0. Since the shift amount is known to be in the range
2739 0 .. 31 inclusive the following seems viable:
2740 xer.ca == 1 iff the following is nonzero:
2741 (argL >>s 31) -- either all 0s or all 1s
2742 & (argL & (1<<argR)-1) -- the stuff shifted out */
2743 xer_ca
2744 = binop(
2745 Iop_And32,
2746 binop(Iop_Sar32, argL, mkU8(31)),
2747 binop( Iop_And32,
2748 argL,
2749 binop( Iop_Sub32,
2750 binop(Iop_Shl32, mkU32(1),
2751 unop(Iop_32to8,argR)),
2752 mkU32(1) )
2755 xer_ca
2756 = unop(Iop_1Uto32, binop(Iop_CmpNE32, xer_ca, mkU32(0)));
2757 break;
2759 default:
2760 vex_printf("set_XER_CA: op = %u\n", op);
2761 vpanic("set_XER_CA(ppc)");
2764 return xer_ca;
2767 static void set_XER_CA_32 ( UInt op, IRExpr* res,
2768 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
2770 IRExpr* xer_ca;
2771 vassert(op < PPCG_FLAG_OP_NUMBER);
2772 vassert(typeOfIRExpr(irsb->tyenv,res) == Ity_I32);
2773 vassert(typeOfIRExpr(irsb->tyenv,argL) == Ity_I32);
2774 vassert(typeOfIRExpr(irsb->tyenv,argR) == Ity_I32);
2775 vassert(typeOfIRExpr(irsb->tyenv,oldca) == Ity_I32);
2777 /* Incoming oldca is assumed to hold the values 0 or 1 only. This
2778 seems reasonable given that it's always generated by
2779 getXER_CA_32(), which masks it accordingly. In any case it being
2780 0 or 1 is an invariant of the ppc guest state representation;
2781 if it has any other value, that invariant has been violated. */
2783 xer_ca = calculate_XER_CA_32( op, res, argL, argR, oldca);
2785 /* xer_ca MUST denote either 0 or 1, no other value allowed */
2786 putXER_CA( unop(Iop_32to8, xer_ca) );
2789 static IRExpr* calculate_XER_CA_64 ( UInt op, IRExpr* res,
2790 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
2792 IRExpr* xer_ca;
2794 switch (op) {
2795 case /* 0 */ PPCG_FLAG_OP_ADD:
2796 /* res <u argL */
2797 xer_ca
2798 = unop(Iop_1Uto32, binop(Iop_CmpLT64U, res, argL));
2799 break;
2801 case /* 1 */ PPCG_FLAG_OP_ADDE:
2802 /* res <u argL || (old_ca==1 && res==argL) */
2803 xer_ca
2804 = mkOR1(
2805 binop(Iop_CmpLT64U, res, argL),
2806 mkAND1(
2807 binop(Iop_CmpEQ64, oldca, mkU64(1)),
2808 binop(Iop_CmpEQ64, res, argL)
2811 xer_ca
2812 = unop(Iop_1Uto32, xer_ca);
2813 break;
2815 case /* 8 */ PPCG_FLAG_OP_SUBFE:
2816 /* res <u argR || (old_ca==1 && res==argR) */
2817 xer_ca
2818 = mkOR1(
2819 binop(Iop_CmpLT64U, res, argR),
2820 mkAND1(
2821 binop(Iop_CmpEQ64, oldca, mkU64(1)),
2822 binop(Iop_CmpEQ64, res, argR)
2825 xer_ca
2826 = unop(Iop_1Uto32, xer_ca);
2827 break;
2829 case /* 7 */ PPCG_FLAG_OP_SUBFC:
2830 case /* 9 */ PPCG_FLAG_OP_SUBFI:
2831 /* res <=u argR */
2832 xer_ca
2833 = unop(Iop_1Uto32, binop(Iop_CmpLE64U, res, argR));
2834 break;
2837 case /* 10 */ PPCG_FLAG_OP_SRAW:
2838 /* The shift amount is guaranteed to be in 0 .. 31 inclusive.
2839 If it is <= 31, behave like SRAWI; else XER.CA is the sign
2840 bit of argL. */
2841 /* This term valid for shift amount < 31 only */
2843 xer_ca
2844 = binop(
2845 Iop_And64,
2846 binop(Iop_Sar64, argL, mkU8(31)),
2847 binop( Iop_And64,
2848 argL,
2849 binop( Iop_Sub64,
2850 binop(Iop_Shl64, mkU64(1),
2851 unop(Iop_64to8,argR)),
2852 mkU64(1) )
2855 xer_ca
2856 = IRExpr_ITE(
2857 /* shift amt > 31 ? */
2858 binop(Iop_CmpLT64U, mkU64(31), argR),
2859 /* yes -- get sign bit of argL */
2860 unop(Iop_64to32, binop(Iop_Shr64, argL, mkU8(63))),
2861 /* no -- be like srawi */
2862 unop(Iop_1Uto32, binop(Iop_CmpNE64, xer_ca, mkU64(0)))
2864 break;
2866 case /* 11 */ PPCG_FLAG_OP_SRAWI:
2867 /* xer_ca is 1 iff src was negative and bits_shifted_out != 0.
2868 Since the shift amount is known to be in the range 0 .. 31
2869 inclusive the following seems viable:
2870 xer.ca == 1 iff the following is nonzero:
2871 (argL >>s 31) -- either all 0s or all 1s
2872 & (argL & (1<<argR)-1) -- the stuff shifted out */
2874 xer_ca
2875 = binop(
2876 Iop_And64,
2877 binop(Iop_Sar64, argL, mkU8(31)),
2878 binop( Iop_And64,
2879 argL,
2880 binop( Iop_Sub64,
2881 binop(Iop_Shl64, mkU64(1),
2882 unop(Iop_64to8,argR)),
2883 mkU64(1) )
2886 xer_ca
2887 = unop(Iop_1Uto32, binop(Iop_CmpNE64, xer_ca, mkU64(0)));
2888 break;
2891 case /* 12 */ PPCG_FLAG_OP_SRAD:
2892 /* The shift amount is guaranteed to be in 0 .. 63 inclusive.
2893 If it is <= 63, behave like SRADI; else XER.CA is the sign
2894 bit of argL. */
2895 /* This term valid for shift amount < 63 only */
2897 xer_ca
2898 = binop(
2899 Iop_And64,
2900 binop(Iop_Sar64, argL, mkU8(63)),
2901 binop( Iop_And64,
2902 argL,
2903 binop( Iop_Sub64,
2904 binop(Iop_Shl64, mkU64(1),
2905 unop(Iop_64to8,argR)),
2906 mkU64(1) )
2909 xer_ca
2910 = IRExpr_ITE(
2911 /* shift amt > 63 ? */
2912 binop(Iop_CmpLT64U, mkU64(63), argR),
2913 /* yes -- get sign bit of argL */
2914 unop(Iop_64to32, binop(Iop_Shr64, argL, mkU8(63))),
2915 /* no -- be like sradi */
2916 unop(Iop_1Uto32, binop(Iop_CmpNE64, xer_ca, mkU64(0)))
2918 break;
2921 case /* 13 */ PPCG_FLAG_OP_SRADI:
2922 /* xer_ca is 1 iff src was negative and bits_shifted_out != 0.
2923 Since the shift amount is known to be in the range 0 .. 63
2924 inclusive, the following seems viable:
2925 xer.ca == 1 iff the following is nonzero:
2926 (argL >>s 63) -- either all 0s or all 1s
2927 & (argL & (1<<argR)-1) -- the stuff shifted out */
2929 xer_ca
2930 = binop(
2931 Iop_And64,
2932 binop(Iop_Sar64, argL, mkU8(63)),
2933 binop( Iop_And64,
2934 argL,
2935 binop( Iop_Sub64,
2936 binop(Iop_Shl64, mkU64(1),
2937 unop(Iop_64to8,argR)),
2938 mkU64(1) )
2941 xer_ca
2942 = unop(Iop_1Uto32, binop(Iop_CmpNE64, xer_ca, mkU64(0)));
2943 break;
2945 default:
2946 vex_printf("set_XER_CA: op = %u\n", op);
2947 vpanic("set_XER_CA(ppc64)");
2950 return xer_ca;
2953 static void set_XER_CA_64 ( UInt op, IRExpr* res,
2954 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
2956 IRExpr* xer_ca;
2957 vassert(op < PPCG_FLAG_OP_NUMBER);
2958 vassert(typeOfIRExpr(irsb->tyenv,res) == Ity_I64);
2959 vassert(typeOfIRExpr(irsb->tyenv,argL) == Ity_I64);
2960 vassert(typeOfIRExpr(irsb->tyenv,argR) == Ity_I64);
2961 vassert(typeOfIRExpr(irsb->tyenv,oldca) == Ity_I64);
2963 /* Incoming oldca is assumed to hold the values 0 or 1 only. This
2964 seems reasonable given that it's always generated by
2965 getXER_CA_32(), which masks it accordingly. In any case it being
2966 0 or 1 is an invariant of the ppc guest state representation;
2967 if it has any other value, that invariant has been violated. */
2969 xer_ca = calculate_XER_CA_64( op, res, argL, argR, oldca );
2971 /* xer_ca MUST denote either 0 or 1, no other value allowed */
2972 putXER_CA( unop(Iop_32to8, xer_ca) );
2975 static void set_XER_CA_CA32 ( IRType ty, UInt op, IRExpr* res,
2976 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
2978 if (ty == Ity_I32) {
2979 set_XER_CA_32( op, res, argL, argR, oldca );
2980 } else {
2981 set_XER_CA_64( op, res, argL, argR, oldca );
2987 /*------------------------------------------------------------*/
2988 /*--- Read/write to guest-state --- */
2989 /*------------------------------------------------------------*/
2991 static IRExpr* /* :: Ity_I32/64 */ getGST ( PPC_GST reg )
2993 IRType ty = mode64 ? Ity_I64 : Ity_I32;
2994 switch (reg) {
2995 case PPC_GST_SPRG3_RO:
2996 return IRExpr_Get( OFFB_SPRG3_RO, ty );
2998 case PPC_GST_CIA:
2999 return IRExpr_Get( OFFB_CIA, ty );
3001 case PPC_GST_LR:
3002 return IRExpr_Get( OFFB_LR, ty );
3004 case PPC_GST_CTR:
3005 return IRExpr_Get( OFFB_CTR, ty );
3007 case PPC_GST_VRSAVE:
3008 return IRExpr_Get( OFFB_VRSAVE, Ity_I32 );
3010 case PPC_GST_VSCR:
3011 return binop(Iop_And32, IRExpr_Get( OFFB_VSCR,Ity_I32 ),
3012 mkU32(MASK_VSCR_VALID));
3014 case PPC_GST_CR: {
3015 /* Synthesise the entire CR into a single word. Expensive. */
3016 # define FIELD(_n) \
3017 binop(Iop_Shl32, \
3018 unop(Iop_8Uto32, \
3019 binop(Iop_Or8, \
3020 binop(Iop_And8, getCR321(_n), mkU8(7<<1)), \
3021 binop(Iop_And8, getCR0(_n), mkU8(1)) \
3023 ), \
3024 mkU8(4 * (7-(_n))) \
3026 return binop(Iop_Or32,
3027 binop(Iop_Or32,
3028 binop(Iop_Or32, FIELD(0), FIELD(1)),
3029 binop(Iop_Or32, FIELD(2), FIELD(3))
3031 binop(Iop_Or32,
3032 binop(Iop_Or32, FIELD(4), FIELD(5)),
3033 binop(Iop_Or32, FIELD(6), FIELD(7))
3036 # undef FIELD
3039 case PPC_GST_XER:
3040 return binop(Iop_Or32,
3041 binop(Iop_Or32,
3042 binop(Iop_Or32,
3043 binop( Iop_Shl32, getXER_SO_32(), mkU8(31)),
3044 binop( Iop_Shl32, getXER_OV_32(), mkU8(30))),
3045 binop(Iop_Or32,
3046 binop( Iop_Shl32, getXER_CA_32(), mkU8(29)),
3047 getXER_BC_32())),
3048 binop(Iop_Or32,
3049 binop( Iop_Shl32, getXER_OV32_32(), mkU8(19)),
3050 binop( Iop_Shl32, getXER_CA32_32(), mkU8(18))));
3052 case PPC_GST_TFHAR:
3053 return IRExpr_Get( OFFB_TFHAR, ty );
3055 case PPC_GST_TEXASR:
3056 return IRExpr_Get( OFFB_TEXASR, ty );
3058 case PPC_GST_TEXASRU:
3059 return IRExpr_Get( OFFB_TEXASRU, ty );
3061 case PPC_GST_TFIAR:
3062 return IRExpr_Get( OFFB_TFIAR, ty );
3064 case PPC_GST_PPR:
3065 return IRExpr_Get( OFFB_PPR, ty );
3067 case PPC_GST_PPR32:
3068 return unop( Iop_64HIto32, IRExpr_Get( OFFB_PPR, ty ) );
3070 case PPC_GST_PSPB:
3071 return IRExpr_Get( OFFB_PSPB, ty );
3073 case PPC_GST_DSCR:
3074 return IRExpr_Get( OFFB_DSCR, ty );
3076 default:
3077 vex_printf("getGST(ppc): reg = %u", reg);
3078 vpanic("getGST(ppc)");
3082 /* Get a masked word from the given reg */
3083 static IRExpr* /* ::Ity_I32 */ getGST_masked ( PPC_GST reg, ULong mask )
3085 IRTemp val = newTemp(Ity_I32);
3086 vassert( reg < PPC_GST_MAX );
3088 switch (reg) {
3090 case PPC_GST_FPSCR: {
3091 /* Vex-generated code expects the FPSCR to be set as follows:
3092 all exceptions masked, round-to-nearest.
3093 This corresponds to a FPSCR value of 0x0. */
3095 /* In the lower 32 bits of FPSCR, we're keeping track of the binary
3096 * floating point rounding mode and Floating-point Condition code, so
3097 * if the mask isn't asking for either of these, just return 0x0.
3099 if ( mask & ( MASK_FPSCR_C_FPCC | MASK_FPSCR_RN ) ) {
3100 assign( val, binop( Iop_Or32,
3101 unop( Iop_8Uto32, IRExpr_Get( OFFB_FPROUND, Ity_I8 ) ),
3102 binop( Iop_Shl32,
3103 unop( Iop_8Uto32,
3104 IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ),
3105 mkU8( 12 ) ) ) );
3106 } else {
3107 assign( val, mkU32(0x0) );
3110 break;
3113 default:
3114 vex_printf("getGST_masked(ppc): reg = %u", reg);
3115 vpanic("getGST_masked(ppc)");
3118 if ( mask != 0xFFFFFFFF ) {
3119 return binop(Iop_And32, mkexpr(val), mkU32(mask));
3120 } else {
3121 return mkexpr(val);
3125 /* Get a masked word from the given reg */
3126 static IRExpr* /* ::Ity_I32 */getGST_masked_upper(PPC_GST reg, ULong mask) {
3127 IRExpr * val;
3128 vassert( reg < PPC_GST_MAX );
3130 switch (reg) {
3132 case PPC_GST_FPSCR: {
3133 /* In the upper 32 bits of FPSCR, we're only keeping track
3134 * of the decimal floating point rounding mode, so if the mask
3135 * isn't asking for this, just return 0x0.
3137 if (mask & MASK_FPSCR_DRN) {
3138 val = binop( Iop_And32,
3139 unop( Iop_8Uto32, IRExpr_Get( OFFB_DFPROUND, Ity_I8 ) ),
3140 unop( Iop_64HIto32, mkU64( mask ) ) );
3141 } else {
3142 val = mkU32( 0x0ULL );
3144 break;
3147 default:
3148 vex_printf( "getGST_masked_upper(ppc): reg = %u", reg );
3149 vpanic( "getGST_masked_upper(ppc)" );
3151 return val;
3155 /* Fetch the specified REG[FLD] nibble (as per IBM/hardware notation)
3156 and return it at the bottom of an I32; the top 27 bits are
3157 guaranteed to be zero. */
3158 static IRExpr* /* ::Ity_I32 */ getGST_field ( PPC_GST reg, UInt fld )
3160 UInt shft, mask;
3162 vassert( fld < 8 );
3163 vassert( reg < PPC_GST_MAX );
3165 shft = 4*(7-fld);
3166 mask = 0xF<<shft;
3168 switch (reg) {
3169 case PPC_GST_XER:
3170 vassert(fld ==7);
3171 return binop(Iop_Or32,
3172 binop(Iop_Or32,
3173 binop(Iop_Shl32, getXER_SO_32(), mkU8(3)),
3174 binop(Iop_Shl32, getXER_OV_32(), mkU8(2))),
3175 binop( Iop_Shl32, getXER_CA_32(), mkU8(1)));
3176 break;
3178 default:
3179 if (shft == 0)
3180 return getGST_masked( reg, mask );
3181 else
3182 return binop(Iop_Shr32,
3183 getGST_masked( reg, mask ),
3184 mkU8(toUChar( shft )));
3188 static void putGST ( PPC_GST reg, IRExpr* src )
3190 IRType ty = mode64 ? Ity_I64 : Ity_I32;
3191 IRType ty_src = typeOfIRExpr(irsb->tyenv,src );
3192 vassert( reg < PPC_GST_MAX );
3193 switch (reg) {
3194 case PPC_GST_IP_AT_SYSCALL:
3195 vassert( ty_src == ty );
3196 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL, src ) );
3197 break;
3198 case PPC_GST_CIA:
3199 vassert( ty_src == ty );
3200 stmt( IRStmt_Put( OFFB_CIA, src ) );
3201 break;
3202 case PPC_GST_LR:
3203 vassert( ty_src == ty );
3204 stmt( IRStmt_Put( OFFB_LR, src ) );
3205 break;
3206 case PPC_GST_CTR:
3207 vassert( ty_src == ty );
3208 stmt( IRStmt_Put( OFFB_CTR, src ) );
3209 break;
3210 case PPC_GST_VRSAVE:
3211 vassert( ty_src == Ity_I32 );
3212 stmt( IRStmt_Put( OFFB_VRSAVE,src));
3213 break;
3214 case PPC_GST_VSCR:
3215 vassert( ty_src == Ity_I32 );
3216 stmt( IRStmt_Put( OFFB_VSCR,
3217 binop(Iop_And32, src,
3218 mkU32(MASK_VSCR_VALID)) ) );
3219 break;
3220 case PPC_GST_XER:
3221 vassert( ty_src == Ity_I32 );
3222 putXER_SO( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(31))) );
3223 putXER_OV( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(30))) );
3224 putXER_CA( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(29))) );
3225 putXER_OV32( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(19))) );
3226 putXER_CA32( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(18))) );
3227 putXER_BC( unop(Iop_32to8, src) );
3228 break;
3230 case PPC_GST_EMWARN:
3231 vassert( ty_src == Ity_I32 );
3232 stmt( IRStmt_Put( OFFB_EMNOTE,src) );
3233 break;
3235 case PPC_GST_CMSTART:
3236 vassert( ty_src == ty );
3237 stmt( IRStmt_Put( OFFB_CMSTART, src) );
3238 break;
3240 case PPC_GST_CMLEN:
3241 vassert( ty_src == ty );
3242 stmt( IRStmt_Put( OFFB_CMLEN, src) );
3243 break;
3245 case PPC_GST_TEXASR:
3246 vassert( ty_src == Ity_I64 );
3247 stmt( IRStmt_Put( OFFB_TEXASR, src ) );
3248 break;
3250 case PPC_GST_TEXASRU:
3251 vassert( ty_src == Ity_I32 );
3252 stmt( IRStmt_Put( OFFB_TEXASRU, src ) );
3253 break;
3255 case PPC_GST_TFIAR:
3256 vassert( ty_src == Ity_I64 );
3257 stmt( IRStmt_Put( OFFB_TFIAR, src ) );
3258 break;
3259 case PPC_GST_TFHAR:
3260 vassert( ty_src == Ity_I64 );
3261 stmt( IRStmt_Put( OFFB_TFHAR, src ) );
3262 break;
3264 case PPC_GST_PPR32:
3265 case PPC_GST_PPR:
3267 /* The Program Priority Register (PPR) stores the priority in
3268 * bits [52:50]. The user setable priorities are:
3270 * 001 very low
3271 * 010 low
3272 * 011 medium low
3273 * 100 medium
3274 * 101 medium high
3276 * If the argument is not between 0b001 and 0b100 the priority is set
3277 * to 0b100. The priority can only be set to 0b101 if the the Problem
3278 * State Boost Register is non-zero. The value of the PPR is not
3279 * changed if the input is not valid.
3282 IRTemp not_valid = newTemp(Ity_I64);
3283 IRTemp has_perm = newTemp(Ity_I64);
3284 IRTemp new_src = newTemp(Ity_I64);
3285 IRTemp PSPB_val = newTemp(Ity_I64);
3286 IRTemp value = newTemp(Ity_I64);
3288 vassert(( ty_src == Ity_I64 ) || ( ty_src == Ity_I32 ));
3289 assign( PSPB_val, binop( Iop_32HLto64,
3290 mkU32( 0 ),
3291 IRExpr_Get( OFFB_PSPB, Ity_I32 ) ) );
3292 if( reg == PPC_GST_PPR32 ) {
3293 vassert( ty_src == Ity_I32 );
3294 assign( value, binop( Iop_32HLto64,
3295 mkU32(0),
3296 binop( Iop_And32,
3297 binop( Iop_Shr32, src, mkU8( 18 ) ),
3298 mkU32( 0x7 ) ) ) );
3299 } else {
3300 vassert( ty_src == Ity_I64 );
3301 assign( value, binop( Iop_And64,
3302 binop( Iop_Shr64, src, mkU8( 50 ) ),
3303 mkU64( 0x7 ) ) );
3305 assign( has_perm,
3306 binop( Iop_And64,
3307 unop( Iop_1Sto64,
3308 binop( Iop_CmpEQ64,
3309 mkexpr( PSPB_val ),
3310 mkU64( 0 ) ) ),
3311 unop( Iop_1Sto64,
3312 binop( Iop_CmpEQ64,
3313 mkU64( 0x5 ),
3314 mkexpr( value ) ) ) ) );
3315 assign( not_valid,
3316 binop( Iop_Or64,
3317 unop( Iop_1Sto64,
3318 binop( Iop_CmpEQ64,
3319 mkexpr( value ),
3320 mkU64( 0 ) ) ),
3321 unop( Iop_1Sto64,
3322 binop( Iop_CmpLT64U,
3323 mkU64( 0x5 ),
3324 mkexpr( value ) ) ) ) );
3325 assign( new_src,
3326 binop( Iop_Or64,
3327 binop( Iop_And64,
3328 unop( Iop_Not64,
3329 mkexpr( not_valid ) ),
3330 src ),
3331 binop( Iop_And64,
3332 mkexpr( not_valid ),
3333 binop( Iop_Or64,
3334 binop( Iop_And64,
3335 mkexpr( has_perm),
3336 binop( Iop_Shl64,
3337 mkexpr( value ),
3338 mkU8( 50 ) ) ),
3339 binop( Iop_And64,
3340 IRExpr_Get( OFFB_PPR, ty ),
3341 unop( Iop_Not64,
3342 mkexpr( has_perm )
3343 ) ) ) ) ) );
3345 /* make sure we only set the valid bit field [52:50] */
3346 stmt( IRStmt_Put( OFFB_PPR,
3347 binop( Iop_And64,
3348 mkexpr( new_src ),
3349 mkU64( 0x1C000000000000) ) ) );
3350 break;
3352 case PPC_GST_DSCR:
3353 vassert( ty_src == Ity_I64 );
3354 stmt( IRStmt_Put( OFFB_DSCR, src ) );
3355 break;
3357 default:
3358 vex_printf("putGST(ppc): reg = %u", reg);
3359 vpanic("putGST(ppc)");
3363 /* Write masked src to the given reg */
3364 static void putGST_masked ( PPC_GST reg, IRExpr* src, ULong mask )
3366 IRType ty = mode64 ? Ity_I64 : Ity_I32;
3367 vassert( reg < PPC_GST_MAX );
3368 vassert( typeOfIRExpr( irsb->tyenv,src ) == Ity_I64 );
3370 switch (reg) {
3371 case PPC_GST_FPSCR: {
3372 /* Allow writes to either binary or decimal floating point
3373 Rounding Mode.
3375 /* If any part of |mask| covers FPSCR.RN, update the bits of
3376 FPSCR.RN by copying in |src| for locations where the
3377 corresponding bit in |mask| is 1, and leaving it unchanged
3378 for corresponding |mask| zero bits. */
3379 if (mask & MASK_FPSCR_RN) {
3380 stmt(
3381 IRStmt_Put(
3382 OFFB_FPROUND,
3383 unop(
3384 Iop_32to8,
3385 binop(
3386 Iop_Or32,
3387 binop(
3388 Iop_And32,
3389 unop(Iop_64to32, src),
3390 mkU32(MASK_FPSCR_RN & mask)
3392 binop(
3393 Iop_And32,
3394 unop(Iop_8Uto32, IRExpr_Get(OFFB_FPROUND,Ity_I8)),
3395 mkU32(MASK_FPSCR_RN & ~mask)
3403 if (mask & MASK_FPSCR_C_FPCC) {
3404 /* FPCC bits are in [47:51] */
3405 stmt(
3406 IRStmt_Put(
3407 OFFB_C_FPCC,
3408 unop(
3409 Iop_32to8,
3410 binop(Iop_Shr32,
3411 binop(
3412 Iop_Or32,
3413 binop(
3414 Iop_And32,
3415 unop(Iop_64to32, src),
3416 mkU32(MASK_FPSCR_C_FPCC & mask) ),
3417 binop(
3418 Iop_And32,
3419 unop(Iop_8Uto32,
3420 IRExpr_Get(OFFB_C_FPCC,Ity_I8)),
3421 mkU32(MASK_FPSCR_C_FPCC & ~mask)
3422 ) ),
3423 mkU8( 12 ) )
3424 ) ) );
3427 /* Similarly, update FPSCR.DRN if any bits of |mask|
3428 corresponding to FPSCR.DRN are set. */
3429 if (mask & MASK_FPSCR_DRN) {
3430 stmt(
3431 IRStmt_Put(
3432 OFFB_DFPROUND,
3433 unop(
3434 Iop_32to8,
3435 binop(
3436 Iop_Or32,
3437 binop(
3438 Iop_And32,
3439 unop(Iop_64HIto32, src),
3440 mkU32((MASK_FPSCR_DRN & mask) >> 32)
3442 binop(
3443 Iop_And32,
3444 unop(Iop_8Uto32, IRExpr_Get(OFFB_DFPROUND,Ity_I8)),
3445 mkU32((MASK_FPSCR_DRN & ~mask) >> 32)
3453 /* Give EmNote for attempted writes to:
3454 - Exception Controls
3455 - Non-IEEE Mode
3457 if (mask & 0xFC) { // Exception Control, Non-IEE mode
3458 VexEmNote ew = EmWarn_PPCexns;
3460 /* If any of the src::exception_control bits are actually set,
3461 side-exit to the next insn, reporting the warning,
3462 so that Valgrind's dispatcher sees the warning. */
3463 putGST( PPC_GST_EMWARN, mkU32(ew) );
3464 stmt(
3465 IRStmt_Exit(
3466 binop(Iop_CmpNE32, mkU32(ew), mkU32(EmNote_NONE)),
3467 Ijk_EmWarn,
3468 mkSzConst( ty, nextInsnAddr()), OFFB_CIA ));
3471 /* Ignore all other writes */
3472 break;
3475 default:
3476 vex_printf("putGST_masked(ppc): reg = %u", reg);
3477 vpanic("putGST_masked(ppc)");
3481 /* Write the least significant nibble of src to the specified
3482 REG[FLD] (as per IBM/hardware notation). */
3483 static void putGST_field ( PPC_GST reg, IRExpr* src, UInt fld )
3485 UInt shft;
3486 ULong mask;
3488 vassert( typeOfIRExpr(irsb->tyenv,src ) == Ity_I32 );
3489 vassert( fld < 16 );
3490 vassert( reg < PPC_GST_MAX );
3492 if (fld < 8)
3493 shft = 4*(7-fld);
3494 else
3495 shft = 4*(15-fld);
3496 mask = 0xF;
3497 mask = mask << shft;
3499 switch (reg) {
3500 case PPC_GST_CR:
3501 putCR0 (fld, binop(Iop_And8, mkU8(1 ), unop(Iop_32to8, src)));
3502 putCR321(fld, binop(Iop_And8, mkU8(7<<1), unop(Iop_32to8, src)));
3503 break;
3505 default:
3507 IRExpr * src64 = unop( Iop_32Uto64, src );
3509 if (shft == 0) {
3510 putGST_masked( reg, src64, mask );
3511 } else {
3512 putGST_masked( reg,
3513 binop( Iop_Shl64, src64, mkU8( toUChar( shft ) ) ),
3514 mask );
3520 static void putFPCC ( IRExpr* e )
3522 /* The assumption is that the value of the FPCC are passed in the lower
3523 * four bits of a 32 bit value.
3525 * Note, the C and FPCC bits which are a field of the FPSCR
3526 * register are stored in their own "register" in
3527 * memory. The FPCC bits are in the lower 4 bits. We don't need to
3528 * shift it to the bits to their location in the FPSCR register. Note,
3529 * not all of the FPSCR register bits are supported. We are writing all
3530 * of the bits in the FPCC field but not the C field.
3532 IRExpr* tmp;
3534 vassert( typeOfIRExpr( irsb->tyenv, e ) == Ity_I32 );
3535 /* Get the C bit field */
3536 tmp = binop( Iop_And32,
3537 mkU32( 0x10 ),
3538 unop( Iop_8Uto32, IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ) );
3540 stmt( IRStmt_Put( OFFB_C_FPCC,
3541 unop( Iop_32to8,
3542 binop( Iop_Or32, tmp,
3543 binop( Iop_And32, mkU32( 0xF ), e ) ) ) ) );
3547 static IRExpr* /* ::Ity_I32 */ getC ( void )
3549 /* Note, the Floating-Point Result Class Descriptor (C) bit is a field of
3550 * the FPSCR registered are stored in its own "register" in guest state
3551 * with the FPCC bit field. C | FPCC
3553 IRTemp val = newTemp(Ity_I32);
3555 assign( val, binop( Iop_Shr32,
3556 unop( Iop_8Uto32, IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ),
3557 mkU8( 4 ) ) );
3558 return mkexpr(val);
3561 static IRExpr* /* ::Ity_I32 */ getFPCC ( void )
3563 /* Note, the FPCC bits are a field of the FPSCR
3564 * register are stored in their own "register" in
3565 * guest state with the C bit field. C | FPCC
3567 IRTemp val = newTemp( Ity_I32 );
3569 assign( val, binop( Iop_And32, unop( Iop_8Uto32,
3570 IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ),
3571 mkU32( 0xF ) ));
3572 return mkexpr(val);
3575 /*------------------------------------------------------------*/
3576 /* Helpers for VSX instructions that do floating point
3577 * operations and need to determine if a src contains a
3578 * special FP value.
3580 *------------------------------------------------------------*/
3582 #define NONZERO_FRAC_MASK 0x000fffffffffffffULL
3583 #define FP_FRAC_PART(x) binop( Iop_And64, \
3584 mkexpr( x ), \
3585 mkU64( NONZERO_FRAC_MASK ) )
3587 #define NONZERO_FRAC_MASK32 0x007fffffULL
3588 #define FP_FRAC_PART32(x) binop( Iop_And32, \
3589 mkexpr( x ), \
3590 mkU32( NONZERO_FRAC_MASK32 ) )
3592 // Returns exponent part of floating point src as I32
3593 static IRExpr * fp_exp_part( IRType size, IRTemp src )
3595 IRExpr *shift_by, *mask, *tsrc;
3597 vassert( ( size == Ity_I16 ) || ( size == Ity_I32 )
3598 || ( size == Ity_I64 ) );
3600 if( size == Ity_I16 ) {
3601 /* The 16-bit floating point value is in the lower 16-bits
3602 * of the 32-bit input value.
3604 tsrc = mkexpr( src );
3605 mask = mkU32( 0x1F );
3606 shift_by = mkU8( 10 );
3608 } else if( size == Ity_I32 ) {
3609 tsrc = mkexpr( src );
3610 mask = mkU32( 0xFF );
3611 shift_by = mkU8( 23 );
3613 } else if( size == Ity_I64 ) {
3614 tsrc = unop( Iop_64HIto32, mkexpr( src ) );
3615 mask = mkU32( 0x7FF );
3616 shift_by = mkU8( 52 - 32 );
3618 } else {
3619 /*NOTREACHED*/
3620 vassert(0); // Stops gcc complaining at "-Og"
3623 return binop( Iop_And32, binop( Iop_Shr32, tsrc, shift_by ), mask );
3626 /* The following functions check the floating point value to see if it
3627 is zero, infinity, NaN, Normalized, Denormalized.
3629 /* 16-bit floating point number is stored in the lower 16-bits of 32-bit value */
3630 #define I16_EXP_MASK 0x7C00
3631 #define I16_FRACTION_MASK 0x03FF
3632 #define I16_MSB_FRACTION_MASK 0x0200
3633 #define I32_EXP_MASK 0x7F800000
3634 #define I32_FRACTION_MASK 0x007FFFFF
3635 #define I32_MSB_FRACTION_MASK 0x00400000
3636 #define I64_EXP_MASK 0x7FF0000000000000ULL
3637 #define I64_FRACTION_MASK 0x000FFFFFFFFFFFFFULL
3638 #define I64_MSB_FRACTION_MASK 0x0008000000000000ULL
3639 #define V128_EXP_MASK 0x7FFF000000000000ULL
3640 #define V128_FRACTION_MASK 0x0000FFFFFFFFFFFFULL /* upper 64-bit fractional mask */
3641 #define V128_MSB_FRACTION_MASK 0x0000800000000000ULL /* upper 64-bit fractional mask */
3643 void setup_value_check_args( IRType size, IRTemp *exp_mask, IRTemp *frac_mask,
3644 IRTemp *msb_frac_mask, IRTemp *zero );
3646 void setup_value_check_args( IRType size, IRTemp *exp_mask, IRTemp *frac_mask,
3647 IRTemp *msb_frac_mask, IRTemp *zero ) {
3649 vassert( ( size == Ity_I16 ) || ( size == Ity_I32 )
3650 || ( size == Ity_I64 ) || ( size == Ity_V128 ) );
3652 if( size == Ity_I16 ) {
3653 /* The 16-bit floating point value is in the lower 16-bits of
3654 the 32-bit input value */
3655 *frac_mask = newTemp( Ity_I32 );
3656 *msb_frac_mask = newTemp( Ity_I32 );
3657 *exp_mask = newTemp( Ity_I32 );
3658 *zero = newTemp( Ity_I32 );
3659 assign( *exp_mask, mkU32( I16_EXP_MASK ) );
3660 assign( *frac_mask, mkU32( I16_FRACTION_MASK ) );
3661 assign( *msb_frac_mask, mkU32( I16_MSB_FRACTION_MASK ) );
3662 assign( *zero, mkU32( 0 ) );
3664 } else if( size == Ity_I32 ) {
3665 *frac_mask = newTemp( Ity_I32 );
3666 *msb_frac_mask = newTemp( Ity_I32 );
3667 *exp_mask = newTemp( Ity_I32 );
3668 *zero = newTemp( Ity_I32 );
3669 assign( *exp_mask, mkU32( I32_EXP_MASK ) );
3670 assign( *frac_mask, mkU32( I32_FRACTION_MASK ) );
3671 assign( *msb_frac_mask, mkU32( I32_MSB_FRACTION_MASK ) );
3672 assign( *zero, mkU32( 0 ) );
3674 } else if( size == Ity_I64 ) {
3675 *frac_mask = newTemp( Ity_I64 );
3676 *msb_frac_mask = newTemp( Ity_I64 );
3677 *exp_mask = newTemp( Ity_I64 );
3678 *zero = newTemp( Ity_I64 );
3679 assign( *exp_mask, mkU64( I64_EXP_MASK ) );
3680 assign( *frac_mask, mkU64( I64_FRACTION_MASK ) );
3681 assign( *msb_frac_mask, mkU64( I64_MSB_FRACTION_MASK ) );
3682 assign( *zero, mkU64( 0 ) );
3684 } else {
3685 /* V128 is converted to upper and lower 64 bit values, */
3686 /* uses 64-bit operators and temps */
3687 *frac_mask = newTemp( Ity_I64 );
3688 *msb_frac_mask = newTemp( Ity_I64 );
3689 *exp_mask = newTemp( Ity_I64 );
3690 *zero = newTemp( Ity_I64 );
3691 assign( *exp_mask, mkU64( V128_EXP_MASK ) );
3692 /* upper 64-bit fractional mask */
3693 assign( *frac_mask, mkU64( V128_FRACTION_MASK ) );
3694 assign( *msb_frac_mask, mkU64( V128_MSB_FRACTION_MASK ) );
3695 assign( *zero, mkU64( 0 ) );
3699 /* Helper function for the various function which check the value of
3700 the floating point value.
3702 static IRExpr * exponent_compare( IRType size, IRTemp src,
3703 IRTemp exp_mask, IRExpr *exp_val )
3705 IROp opAND, opCmpEQ;
3707 if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
3708 /* The 16-bit floating point value is in the lower 16-bits of
3709 the 32-bit input value */
3710 opAND = Iop_And32;
3711 opCmpEQ = Iop_CmpEQ32;
3713 } else {
3714 opAND = Iop_And64;
3715 opCmpEQ = Iop_CmpEQ64;
3718 if( size == Ity_V128 ) {
3719 return binop( opCmpEQ,
3720 binop ( opAND,
3721 unop( Iop_V128HIto64, mkexpr( src ) ),
3722 mkexpr( exp_mask ) ),
3723 exp_val );
3725 } else if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
3726 return binop( opCmpEQ,
3727 binop ( opAND, mkexpr( src ), mkexpr( exp_mask ) ),
3728 exp_val );
3729 } else {
3730 /* 64-bit operands */
3732 if (mode64) {
3733 return binop( opCmpEQ,
3734 binop ( opAND, mkexpr( src ), mkexpr( exp_mask ) ),
3735 exp_val );
3736 } else {
3737 /* No support for 64-bit compares in 32-bit mode, need to do upper
3738 * and lower parts using 32-bit compare operators.
3740 return
3741 mkAND1( binop( Iop_CmpEQ32,
3742 binop ( Iop_And32,
3743 unop(Iop_64HIto32, mkexpr( src ) ),
3744 unop(Iop_64HIto32, mkexpr( exp_mask ) ) ),
3745 unop(Iop_64HIto32, exp_val ) ),
3746 binop( Iop_CmpEQ32,
3747 binop ( Iop_And32,
3748 unop(Iop_64to32, mkexpr( src ) ),
3749 unop(Iop_64to32, mkexpr( exp_mask ) ) ),
3750 unop(Iop_64to32, exp_val ) ) );
3755 static IRExpr *fractional_part_compare( IRType size, IRTemp src,
3756 IRTemp frac_mask, IRExpr *zero )
3758 IROp opAND, opCmpEQ;
3760 if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
3761 /*The 16-bit floating point value is in the lower 16-bits of
3762 the 32-bit input value */
3763 opAND = Iop_And32;
3764 opCmpEQ = Iop_CmpEQ32;
3766 } else {
3767 opAND = Iop_And64;
3768 opCmpEQ = Iop_CmpEQ64;
3771 if( size == Ity_V128 ) {
3772 /* 128-bit, note we only care if the fractional part is zero so take upper
3773 52-bits of fractional part and lower 64-bits and OR them together and test
3774 for zero. This keeps the temp variables and operators all 64-bit.
3776 return binop( opCmpEQ,
3777 binop( Iop_Or64,
3778 binop( opAND,
3779 unop( Iop_V128HIto64, mkexpr( src ) ),
3780 mkexpr( frac_mask ) ),
3781 unop( Iop_V128to64, mkexpr( src ) ) ),
3782 zero );
3784 } else if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
3785 return binop( opCmpEQ,
3786 binop( opAND, mkexpr( src ), mkexpr( frac_mask ) ),
3787 zero );
3788 } else {
3789 if (mode64) {
3790 return binop( opCmpEQ,
3791 binop( opAND, mkexpr( src ), mkexpr( frac_mask ) ),
3792 zero );
3793 } else {
3794 /* No support for 64-bit compares in 32-bit mode, need to do upper
3795 * and lower parts using 32-bit compare operators.
3797 return
3798 mkAND1( binop( Iop_CmpEQ32,
3799 binop ( Iop_And32,
3800 unop(Iop_64HIto32, mkexpr( src ) ),
3801 unop(Iop_64HIto32, mkexpr( frac_mask ) ) ),
3802 mkU32 ( 0 ) ),
3803 binop( Iop_CmpEQ32,
3804 binop ( Iop_And32,
3805 unop(Iop_64to32, mkexpr( src ) ),
3806 unop(Iop_64to32, mkexpr( frac_mask ) ) ),
3807 mkU32 ( 0 ) ) );
3812 // Infinity: exp has all bits set, and fraction is zero; s = 0/1
3813 static IRExpr * is_Inf( IRType size, IRTemp src )
3815 IRExpr *max_exp, *zero_frac;
3816 IRTemp exp_mask, frac_mask, msb_frac_mask, zero;
3818 setup_value_check_args( size, &exp_mask, &frac_mask, &msb_frac_mask,
3819 &zero );
3821 /* check exponent is all ones, i.e. (exp AND exp_mask) = exp_mask */
3822 max_exp = exponent_compare( size, src, exp_mask, mkexpr( exp_mask ) );
3824 /* check fractional part is all zeros */
3825 zero_frac = fractional_part_compare( size, src, frac_mask, mkexpr( zero ) );
3827 return mkAND1( max_exp, zero_frac );
3830 // Zero: exp is zero and fraction is zero; s = 0/1
3831 static IRExpr * is_Zero( IRType size, IRTemp src )
3833 IRExpr *zero_exp, *zero_frac;
3834 IRTemp exp_mask, frac_mask, msb_frac_mask, zero;
3836 setup_value_check_args( size, &exp_mask, &frac_mask, &msb_frac_mask,
3837 &zero );
3839 /* check the exponent is all zeros, i.e. (exp AND exp_mask) = zero */
3840 zero_exp = exponent_compare( size, src, exp_mask, mkexpr( zero ) );
3842 /* check fractional part is all zeros */
3843 zero_frac = fractional_part_compare( size, src, frac_mask, mkexpr( zero ) );
3845 return mkAND1( zero_exp, zero_frac );
3848 /* SNAN: s = 1/0; exp all 1's; fraction is nonzero, with highest bit '1'
3849 * QNAN: s = 1/0; exp all 1's; fraction is nonzero, with highest bit '0'
3851 static IRExpr * is_NaN( IRType size, IRTemp src )
3853 IRExpr *max_exp, *not_zero_frac;
3854 IRTemp exp_mask, frac_mask, msb_frac_mask, zero;
3856 setup_value_check_args( size, &exp_mask, &frac_mask, &msb_frac_mask,
3857 &zero );
3859 /* check exponent is all ones, i.e. (exp AND exp_mask) = exp_mask */
3860 max_exp = exponent_compare( size, src, exp_mask, mkexpr( exp_mask ) );
3862 /* check fractional part is not zero */
3863 not_zero_frac = unop( Iop_Not1,
3864 fractional_part_compare( size, src, frac_mask,
3865 mkexpr( zero ) ) );
3867 return mkAND1( max_exp, not_zero_frac );
3870 static IRExpr * is_sNaN( IRType size, IRTemp src )
3872 IRExpr *max_exp, *not_zero_frac, *msb_zero;
3873 IRTemp exp_mask, frac_mask, msb_frac_mask, zero;
3875 setup_value_check_args( size, &exp_mask, &frac_mask, &msb_frac_mask,
3876 &zero );
3878 /* check exponent is all ones, i.e. (exp AND exp_mask) = exp_mask */
3879 max_exp = exponent_compare( size, src, exp_mask, mkexpr( exp_mask ) );
3881 /* Most significant fractional bit is zero for sNaN */
3882 msb_zero = fractional_part_compare ( size, src, msb_frac_mask,
3883 mkexpr( zero ) );
3885 /* check fractional part is not zero */
3886 not_zero_frac = unop( Iop_Not1,
3887 fractional_part_compare( size, src, frac_mask,
3888 mkexpr( zero ) ) );
3890 return mkAND1( msb_zero, mkAND1( max_exp, not_zero_frac ) );
3893 /* Denormalized number has a zero exponent and non zero fraction. */
3894 static IRExpr * is_Denorm( IRType size, IRTemp src )
3896 IRExpr *zero_exp, *not_zero_frac;
3897 IRTemp exp_mask, frac_mask, msb_frac_mask, zero;
3899 setup_value_check_args( size, &exp_mask, &frac_mask, &msb_frac_mask,
3900 &zero );
3902 /* check exponent is all zeros */
3903 zero_exp = exponent_compare( size, src, exp_mask, mkexpr( zero ) );
3905 /* check fractional part is not zero */
3906 not_zero_frac = unop( Iop_Not1,
3907 fractional_part_compare( size, src, frac_mask,
3908 mkexpr( zero ) ) );
3910 return mkAND1( zero_exp, not_zero_frac );
3913 #if 0
3914 /* Normalized number has exponent between 1 and max_exp -1, or in other words
3915 the exponent is not zero and not equal to the max exponent value. */
3916 Currently not needed since generate_C_FPCC is now done with a C helper.
3917 Keep it around, might be useful in the future.
3918 static IRExpr * is_Norm( IRType size, IRTemp src )
3920 IRExpr *not_zero_exp, *not_max_exp;
3921 IRTemp exp_mask, zero;
3923 vassert( ( size == Ity_I16 ) || ( size == Ity_I32 )
3924 || ( size == Ity_I64 ) || ( size == Ity_V128 ) );
3926 if( size == Ity_I16 ) {
3927 /* The 16-bit floating point value is in the lower 16-bits of
3928 the 32-bit input value */
3929 exp_mask = newTemp( Ity_I32 );
3930 zero = newTemp( Ity_I32 );
3931 assign( exp_mask, mkU32( I16_EXP_MASK ) );
3932 assign( zero, mkU32( 0 ) );
3934 } else if( size == Ity_I32 ) {
3935 exp_mask = newTemp( Ity_I32 );
3936 zero = newTemp( Ity_I32 );
3937 assign( exp_mask, mkU32( I32_EXP_MASK ) );
3938 assign( zero, mkU32( 0 ) );
3940 } else if( size == Ity_I64 ) {
3941 exp_mask = newTemp( Ity_I64 );
3942 zero = newTemp( Ity_I64 );
3943 assign( exp_mask, mkU64( I64_EXP_MASK ) );
3944 assign( zero, mkU64( 0 ) );
3946 } else {
3947 /* V128 is converted to upper and lower 64 bit values, */
3948 /* uses 64-bit operators and temps */
3949 exp_mask = newTemp( Ity_I64 );
3950 zero = newTemp( Ity_I64 );
3951 assign( exp_mask, mkU64( V128_EXP_MASK ) );
3952 assign( zero, mkU64( 0 ) );
3955 not_zero_exp = unop( Iop_Not1,
3956 exponent_compare( size, src,
3957 exp_mask, mkexpr( zero ) ) );
3958 not_max_exp = unop( Iop_Not1,
3959 exponent_compare( size, src,
3960 exp_mask, mkexpr( exp_mask ) ) );
3962 return mkAND1( not_zero_exp, not_max_exp );
3964 #endif
3966 static void generate_store_FPRF( IRType size, IRTemp src,
3967 const VexAbiInfo* vbi )
3970 /* This function was originally written using IR code. It has been
3971 * replaced with a clean helper due to the large amount of IR code
3972 * needed by this function.
3975 IRTemp tmp = newTemp( Ity_I64 );
3976 vassert( ( size == Ity_I16 ) || ( size == Ity_I32 )
3977 || ( size == Ity_I64 ) || ( size == Ity_F128 ) );
3979 vassert( ( typeOfIRExpr(irsb->tyenv, mkexpr( src ) ) == Ity_I32 )
3980 || ( typeOfIRExpr(irsb->tyenv, mkexpr( src ) ) == Ity_I64 )
3981 || ( typeOfIRExpr(irsb->tyenv, mkexpr( src ) ) == Ity_F128 ) );
3983 if( size == Ity_I16 ) {
3984 assign( tmp,
3985 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
3986 "generate_store_C_FPCC_helper",
3987 fnptr_to_fnentry( vbi, &generate_C_FPCC_helper ),
3988 mkIRExprVec_3( mkU64( size ), mkU64( 0 ),
3989 mkexpr( src ) ) ) );
3990 } else if( size == Ity_I32 ) {
3991 assign( tmp,
3992 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
3993 "generate_store_C_FPCC_helper",
3994 fnptr_to_fnentry( vbi, &generate_C_FPCC_helper ),
3995 mkIRExprVec_3( mkU64( size ), mkU64( 0 ),
3996 mkexpr( src ) ) ) );
3997 } else if( size == Ity_I64 ) {
3998 assign( tmp,
3999 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4000 "generate_store_C_FPCC_helper",
4001 fnptr_to_fnentry( vbi, &generate_C_FPCC_helper ),
4002 mkIRExprVec_3( mkU64( size ), mkU64( 0 ),
4003 mkexpr( src ) ) ) );
4004 } else if( size == Ity_F128 ) {
4005 assign( tmp,
4006 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4007 "generate_store_C_FPCC_helper",
4008 fnptr_to_fnentry( vbi, &generate_C_FPCC_helper ),
4009 mkIRExprVec_3( mkU64( size ),
4010 unop( Iop_ReinterpF64asI64,
4011 unop( Iop_F128HItoF64,
4012 mkexpr( src ) ) ),
4013 unop( Iop_ReinterpF64asI64,
4014 unop( Iop_F128LOtoF64,
4015 mkexpr( src ) ) ) ) ) );
4018 /* C is in the upper 32-bits, FPCC is in the lower 32-bits of the
4019 * value returned by the helper function
4021 putC( unop( Iop_64HIto32, mkexpr( tmp) ) );
4022 putFPCC( unop( Iop_64to32, mkexpr( tmp) ) );
4025 /* This function takes an Ity_I32 input argument interpreted
4026 as a single-precision floating point value. If src is a
4027 SNaN, it is changed to a QNaN and returned; otherwise,
4028 the original value is returned. */
4029 static IRExpr * handle_SNaN_to_QNaN_32(IRExpr * src)
4031 #define SNAN_MASK32 0x00400000
4032 IRTemp tmp = newTemp(Ity_I32);
4033 IRTemp mask = newTemp(Ity_I32);
4034 IRTemp is_SNAN = newTemp(Ity_I1);
4036 vassert( typeOfIRExpr(irsb->tyenv, src ) == Ity_I32 );
4037 assign(tmp, src);
4039 /* check if input is SNaN, if it is convert to QNaN */
4040 assign( is_SNAN,
4041 mkAND1( is_NaN( Ity_I32, tmp ),
4042 binop( Iop_CmpEQ32,
4043 binop( Iop_And32, mkexpr( tmp ),
4044 mkU32( SNAN_MASK32 ) ),
4045 mkU32( 0 ) ) ) );
4046 /* create mask with QNaN bit set to make it a QNaN if tmp is SNaN */
4047 assign ( mask, binop( Iop_And32,
4048 unop( Iop_1Sto32, mkexpr( is_SNAN ) ),
4049 mkU32( SNAN_MASK32 ) ) );
4050 return binop( Iop_Or32, mkexpr( mask ), mkexpr( tmp) );
4054 /* This helper function performs the negation part of operations of the form:
4055 * "Negate Multiply-<op>"
4056 * where "<op>" is either "Add" or "Sub".
4058 * This function takes one argument -- the floating point intermediate result (converted to
4059 * Ity_I64 via Iop_ReinterpF64asI64) that was obtained from the "Multip-<op>" part of
4060 * the operation described above.
4062 static IRTemp getNegatedResult(IRTemp intermediateResult)
4064 ULong signbit_mask = 0x8000000000000000ULL;
4065 IRTemp signbit_32 = newTemp(Ity_I32);
4066 IRTemp resultantSignbit = newTemp(Ity_I1);
4067 IRTemp negatedResult = newTemp(Ity_I64);
4068 assign( signbit_32, binop( Iop_Shr32,
4069 unop( Iop_64HIto32,
4070 binop( Iop_And64, mkexpr( intermediateResult ),
4071 mkU64( signbit_mask ) ) ),
4072 mkU8( 31 ) ) );
4073 /* We negate the signbit if and only if the intermediate result from the
4074 * multiply-<op> was NOT a NaN. This is an XNOR predicate.
4076 assign( resultantSignbit,
4077 unop( Iop_Not1,
4078 binop( Iop_CmpEQ32,
4079 binop( Iop_Xor32,
4080 mkexpr( signbit_32 ),
4081 unop( Iop_1Uto32, is_NaN( Ity_I64,
4082 intermediateResult ) ) ),
4083 mkU32( 1 ) ) ) );
4085 assign( negatedResult,
4086 binop( Iop_Or64,
4087 binop( Iop_And64,
4088 mkexpr( intermediateResult ),
4089 mkU64( ~signbit_mask ) ),
4090 binop( Iop_32HLto64,
4091 binop( Iop_Shl32,
4092 unop( Iop_1Uto32, mkexpr( resultantSignbit ) ),
4093 mkU8( 31 ) ),
4094 mkU32( 0 ) ) ) );
4096 return negatedResult;
4099 /* This helper function performs the negation part of operations of the form:
4100 * "Negate Multiply-<op>"
4101 * where "<op>" is either "Add" or "Sub".
4103 * This function takes one argument -- the floating point intermediate result (converted to
4104 * Ity_I32 via Iop_ReinterpF32asI32) that was obtained from the "Multip-<op>" part of
4105 * the operation described above.
4107 static IRTemp getNegatedResult_32(IRTemp intermediateResult)
4109 UInt signbit_mask = 0x80000000;
4110 IRTemp signbit_32 = newTemp(Ity_I32);
4111 IRTemp resultantSignbit = newTemp(Ity_I1);
4112 IRTemp negatedResult = newTemp(Ity_I32);
4113 assign( signbit_32, binop( Iop_Shr32,
4114 binop( Iop_And32, mkexpr( intermediateResult ),
4115 mkU32( signbit_mask ) ),
4116 mkU8( 31 ) ) );
4117 /* We negate the signbit if and only if the intermediate result from the
4118 * multiply-<op> was NOT a NaN. This is an XNOR predicate.
4120 assign( resultantSignbit,
4121 unop( Iop_Not1,
4122 binop( Iop_CmpEQ32,
4123 binop( Iop_Xor32,
4124 mkexpr( signbit_32 ),
4125 unop( Iop_1Uto32, is_NaN( Ity_I32,
4126 intermediateResult ) ) ),
4127 mkU32( 1 ) ) ) );
4129 assign( negatedResult,
4130 binop( Iop_Or32,
4131 binop( Iop_And32,
4132 mkexpr( intermediateResult ),
4133 mkU32( ~signbit_mask ) ),
4134 binop( Iop_Shl32,
4135 unop( Iop_1Uto32, mkexpr( resultantSignbit ) ),
4136 mkU8( 31 ) ) ) );
4138 return negatedResult;
4141 /* This function takes two quad_precision floating point numbers of type
4142 V128 and return 1 if src_A > src_B, 0 otherwise. */
4143 static IRExpr * Quad_precision_gt ( IRTemp src_A, IRTemp src_B )
4145 #define FRAC_MASK64Hi 0x0000ffffffffffffULL
4146 #define MASK 0x7FFFFFFFFFFFFFFFULL /* exclude sign bit in upper 64 bits */
4147 #define EXP_MASK 0x7fff
4149 IRType ty = Ity_I64;
4150 IRTemp sign_A = newTemp( ty );
4151 IRTemp sign_B = newTemp( ty );
4152 IRTemp exp_A = newTemp( ty );
4153 IRTemp exp_B = newTemp( ty );
4154 IRTemp frac_A_hi = newTemp( ty );
4155 IRTemp frac_B_hi = newTemp( ty );
4156 IRTemp frac_A_lo = newTemp( ty );
4157 IRTemp frac_B_lo = newTemp( ty );
4160 /* extract exponents, and fractional parts so they can be compared */
4161 assign( sign_A, binop( Iop_Shr64,
4162 unop( Iop_V128HIto64, mkexpr( src_A ) ),
4163 mkU8( 63 ) ) );
4164 assign( sign_B, binop( Iop_Shr64,
4165 unop( Iop_V128HIto64, mkexpr( src_B ) ),
4166 mkU8( 63 ) ) );
4167 assign( exp_A, binop( Iop_And64,
4168 binop( Iop_Shr64,
4169 unop( Iop_V128HIto64, mkexpr( src_A ) ),
4170 mkU8( 48 ) ),
4171 mkU64( EXP_MASK ) ) );
4172 assign( exp_B, binop( Iop_And64,
4173 binop( Iop_Shr64,
4174 unop( Iop_V128HIto64, mkexpr( src_B ) ),
4175 mkU8( 48 ) ),
4176 mkU64( EXP_MASK ) ) );
4177 assign( frac_A_hi, binop( Iop_And64,
4178 unop( Iop_V128HIto64, mkexpr( src_A ) ),
4179 mkU64( FRAC_MASK64Hi ) ) );
4180 assign( frac_B_hi, binop( Iop_And64,
4181 unop( Iop_V128HIto64, mkexpr( src_B ) ),
4182 mkU64( FRAC_MASK64Hi ) ) );
4183 assign( frac_A_lo, unop( Iop_V128to64, mkexpr( src_A ) ) );
4184 assign( frac_B_lo, unop( Iop_V128to64, mkexpr( src_B ) ) );
4186 IRExpr * A_zero = mkAND1( binop( Iop_CmpEQ64,
4187 binop( Iop_And64,
4188 unop( Iop_V128HIto64,
4189 mkexpr( src_A ) ),
4190 mkU64( MASK ) ),
4191 mkU64( 0 ) ),
4192 binop( Iop_CmpEQ64,
4193 unop( Iop_V128to64, mkexpr( src_A ) ),
4194 mkU64( 0 ) ) );
4195 IRExpr * B_zero = mkAND1( binop( Iop_CmpEQ64,
4196 binop( Iop_And64,
4197 unop( Iop_V128HIto64,
4198 mkexpr( src_B ) ),
4199 mkU64( MASK ) ),
4200 mkU64( 0 ) ),
4201 binop( Iop_CmpEQ64,
4202 unop( Iop_V128to64, mkexpr( src_B ) ),
4203 mkU64( 0 ) ) );
4204 IRExpr * A_B_zero = mkAND1( A_zero, B_zero );
4206 /* Compare numbers */
4207 IRExpr * both_pos = mkAND1( binop( Iop_CmpEQ64, mkexpr( sign_A ),
4208 mkU64( 0 ) ),
4209 binop( Iop_CmpEQ64, mkexpr( sign_B ),
4210 mkU64( 0 ) ) );
4211 IRExpr * both_neg = mkAND1( binop( Iop_CmpEQ64, mkexpr( sign_A ),
4212 mkU64( 1 ) ),
4213 binop( Iop_CmpEQ64, mkexpr( sign_B ),
4214 mkU64( 1 ) ) );
4215 IRExpr * sign_eq = binop( Iop_CmpEQ64, mkexpr( sign_A ), mkexpr( sign_B ) );
4216 IRExpr * sign_gt = binop( Iop_CmpLT64U, mkexpr( sign_A ),
4217 mkexpr( sign_B ) ); /* A pos, B neg */
4219 IRExpr * exp_eq = binop( Iop_CmpEQ64, mkexpr( exp_A ), mkexpr( exp_B ) );
4220 IRExpr * exp_gt = binop( Iop_CmpLT64U, mkexpr( exp_B ), mkexpr( exp_A ) );
4221 IRExpr * exp_lt = binop( Iop_CmpLT64U, mkexpr( exp_A ), mkexpr( exp_B ) );
4223 IRExpr * frac_hi_eq = binop( Iop_CmpEQ64, mkexpr( frac_A_hi),
4224 mkexpr( frac_B_hi ) );
4225 IRExpr * frac_hi_gt = binop( Iop_CmpLT64U, mkexpr( frac_B_hi ),
4226 mkexpr( frac_A_hi ) );
4227 IRExpr * frac_hi_lt = binop( Iop_CmpLT64U, mkexpr( frac_A_hi ),
4228 mkexpr( frac_B_hi ) );
4230 IRExpr * frac_lo_gt = binop( Iop_CmpLT64U, mkexpr( frac_B_lo ),
4231 mkexpr( frac_A_lo ) );
4232 IRExpr * frac_lo_lt = binop( Iop_CmpLT64U, mkexpr( frac_A_lo ),
4233 mkexpr( frac_B_lo ) );
4235 /* src_A and src_B both positive */
4236 IRExpr *pos_cmp = mkOR1( exp_gt,
4237 mkAND1( exp_eq,
4238 mkOR1( frac_hi_gt,
4239 mkAND1( frac_hi_eq, frac_lo_gt ) )
4240 ) );
4242 /* src_A and src_B both negative */
4243 IRExpr *neg_cmp = mkOR1( exp_lt,
4244 mkAND1( exp_eq,
4245 mkOR1( frac_hi_lt,
4246 mkAND1( frac_hi_eq, frac_lo_lt ) )
4247 ) );
4249 /* Need to check the case where one value is a positive
4250 * zero and the other value is a negative zero
4252 return mkAND1( mkNOT1( A_B_zero ),
4253 mkOR1( sign_gt,
4254 mkAND1( sign_eq,
4255 mkOR1( mkAND1( both_pos, pos_cmp ),
4256 mkAND1( both_neg, neg_cmp ) ) ) ) );
4259 /*-----------------------------------------------------------
4260 * Helpers for VX instructions that work on National decimal values,
4261 * Zoned decimal values and BCD values.
4263 *------------------------------------------------------------*/
4264 static IRExpr * is_National_decimal (IRTemp src)
4266 /* The src is a 128-bit value containing a sign code in half word 7
4267 * and seven digits in halfwords 0 to 6 (IBM numbering). A valid
4268 * national decimal value has the following:
4269 * - the sign code must be 0x002B (positive) or 0x002D (negative)
4270 * - the digits must be in the range 0x0030 to 0x0039
4272 Int i;
4273 IRExpr * valid_pos_sign;
4274 IRExpr * valid_neg_sign;
4275 IRTemp valid_num[8];
4276 IRTemp digit[7];
4278 valid_pos_sign = binop( Iop_CmpEQ64,
4279 binop( Iop_And64,
4280 mkU64( 0xFFFF ),
4281 unop( Iop_V128to64, mkexpr( src ) ) ),
4282 mkU64( 0x002B ) );
4284 valid_neg_sign = binop( Iop_CmpEQ64,
4285 binop( Iop_And64,
4286 mkU64( 0xFFFF ),
4287 unop( Iop_V128to64, mkexpr( src ) ) ),
4288 mkU64( 0x002D ) );
4290 valid_num[0] = newTemp( Ity_I1 );
4291 digit[0] = newTemp( Ity_I64 );
4292 assign( valid_num[0], mkU1( 1 ) ); // Assume true to start
4294 for(i = 0; i < 7; i++) {
4295 valid_num[i+1] = newTemp( Ity_I1 );
4296 digit[i] = newTemp( Ity_I64 );
4297 assign( digit[i], binop( Iop_And64,
4298 unop( Iop_V128to64,
4299 binop( Iop_ShrV128,
4300 mkexpr( src ),
4301 mkU8( (7-i)*16 ) ) ),
4302 mkU64( 0xFFFF ) ) );
4304 assign( valid_num[i+1],
4305 mkAND1( mkexpr( valid_num[i] ),
4306 mkAND1( binop( Iop_CmpLE64U,
4307 mkexpr( digit[i] ),
4308 mkU64( 0x39 ) ),
4309 binop( Iop_CmpLE64U,
4310 mkU64( 0x30 ),
4311 mkexpr( digit[i] ) ) ) ) );
4314 return mkAND1( mkOR1( valid_pos_sign, valid_neg_sign),
4315 mkexpr( valid_num[7] ) );
4318 static IRExpr * is_Zoned_decimal (IRTemp src, UChar ps)
4320 /* The src is a 128-bit value containing a sign code the least significant
4321 * two bytes. The upper pairs of bytes contain digits. A valid Zoned
4322 * decimal value has the following:
4323 * - the sign code must be between 0x0X to 0xFX inclusive (X - don't care)
4324 * - bits [0:3] of each digit must be equal to 0x3
4325 * - bits [4:7] of each digit must be between 0x0 and 0x9
4327 * If ps = 0
4328 * Positive sign codes are: 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xA, 0xB
4329 * (note 0bX0XX XXXX is positive)
4331 * Negative sign codes are 0x4, 0x5, 0x6, 0x7, 0xC, 0xD, 0xE, 0xF
4332 * (note 0bX1XX XXXX is negative)
4334 * If ps = 1, then the sign code must be in the range 0xA to 0xF
4335 * Positive sign codes are: 0xA, 0xC, 0xE, 0xF
4337 * Negative sign codes are 0xB, 0xD
4339 Int i, mask_hi, mask_lo;
4340 IRExpr *valid_range;
4341 IRTemp valid_num[16];
4342 IRTemp digit[15];
4344 /* check the range of the sign value based on the value of ps */
4345 valid_range = mkOR1(
4346 mkAND1( binop( Iop_CmpEQ64,
4347 mkU64( 1 ),
4348 mkU64( ps ) ),
4349 mkAND1( binop( Iop_CmpLE64U,
4350 binop( Iop_And64,
4351 mkU64( 0xF0 ),
4352 unop( Iop_V128to64,
4353 mkexpr( src ) ) ),
4355 mkU64( 0xF0 ) ),
4356 binop( Iop_CmpLE64U,
4357 mkU64( 0xA0 ),
4358 binop( Iop_And64,
4359 mkU64( 0xF0 ),
4360 unop( Iop_V128to64,
4361 mkexpr( src ) ))))),
4362 binop( Iop_CmpEQ64,
4363 mkU64( 0 ),
4364 mkU64( ps ) ) );
4366 valid_num[0] = newTemp( Ity_I1 );
4367 assign( valid_num[0], mkU1( 1) ); // Assume true to start
4369 if (ps == 0) {
4370 mask_hi = 0x39;
4371 mask_lo = 0x30;
4372 } else {
4373 mask_hi = 0xF9;
4374 mask_lo = 0xF0;
4377 for(i = 0; i < 15; i++) {
4378 valid_num[i+1] = newTemp( Ity_I1 );
4379 digit[i] = newTemp( Ity_I64 );
4380 assign( digit[i], binop( Iop_And64,
4381 unop( Iop_V128to64,
4382 binop( Iop_ShrV128,
4383 mkexpr( src ),
4384 mkU8( (15-i)*8 ) ) ),
4385 mkU64( 0xFF ) ) );
4387 assign( valid_num[i+1],
4388 mkAND1( mkexpr( valid_num[i] ),
4389 mkAND1( binop( Iop_CmpLE64U,
4390 mkexpr( digit[i] ),
4391 mkU64( mask_hi ) ),
4392 binop( Iop_CmpLE64U,
4393 mkU64( mask_lo ),
4394 mkexpr( digit[i] ) ) ) ) );
4397 return mkAND1( valid_range, mkexpr( valid_num[15] ) );
4400 static IRExpr * CmpGT128U ( IRExpr *src1, IRExpr *src2 )
4402 /* Unsigend compare of two 128-bit values */
4403 IRExpr *pos_upper_gt, *pos_upper_eq, *pos_lower_gt;
4405 pos_upper_gt = binop( Iop_CmpLT64U,
4406 unop( Iop_V128HIto64, src2 ),
4407 unop( Iop_V128HIto64, src1 ) );
4408 pos_upper_eq = binop( Iop_CmpEQ64,
4409 unop( Iop_V128HIto64, src1 ),
4410 unop( Iop_V128HIto64, src2 ) );
4411 pos_lower_gt = binop( Iop_CmpLT64U,
4412 unop( Iop_V128to64, src2),
4413 unop( Iop_V128to64, src1) );
4414 return mkOR1( pos_upper_gt,
4415 mkAND1( pos_upper_eq,
4416 pos_lower_gt ) );
4420 static IRExpr * is_BCDstring128 ( const VexAbiInfo* vbi,
4421 UInt Signed, IRExpr *src )
4424 IRTemp valid = newTemp( Ity_I64 );
4426 /* The src is a 128-bit value containing a MAX_DIGITS BCD digits and
4427 * a sign. The upper bytes are BCD values between 0x0 and 0x9. The sign
4428 * byte is the least significant byte. This function returns 64-bit 1
4429 * value if sign and digits are valid, 0 otherwise.
4431 * This function was originally written using IR code. It has been
4432 * replaced with a clean helper due to the large amount of IR code
4433 * needed by this function.
4435 assign( valid,
4436 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4437 "is_BCDstring128_helper",
4438 fnptr_to_fnentry( vbi, &is_BCDstring128_helper ),
4439 mkIRExprVec_3( mkU64( Signed ),
4440 unop( Iop_V128HIto64, src ),
4441 unop( Iop_V128to64, src ) ) ) );
4442 return mkexpr( valid );
4445 static IRExpr * BCDstring_zero (IRExpr *src)
4447 /* The src is a 128-bit value containing a BCD string. The function
4448 * returns a 1 if the BCD string values are all zero, 0 otherwise.
4450 IRTemp tsrc = newTemp( Ity_V128 );
4451 assign( tsrc, src);
4453 if ( mode64 ) {
4454 return mkAND1( binop( Iop_CmpEQ64,
4455 mkU64( 0 ),
4456 unop( Iop_V128HIto64,
4457 mkexpr( tsrc ) ) ),
4458 binop( Iop_CmpEQ64,
4459 mkU64( 0 ),
4460 unop( Iop_V128to64,
4461 mkexpr( tsrc ) ) ) );
4462 } else {
4463 /* make this work in 32-bit mode */
4464 return mkAND1(
4465 mkAND1( binop( Iop_CmpEQ32,
4466 mkU32( 0 ),
4467 unop( Iop_64HIto32,
4468 unop( Iop_V128HIto64,
4469 mkexpr( tsrc ) ) ) ),
4470 binop( Iop_CmpEQ32,
4471 mkU32( 0 ),
4472 unop( Iop_64to32,
4473 unop( Iop_V128HIto64,
4474 mkexpr( tsrc ) ) ) ) ),
4475 mkAND1( binop( Iop_CmpEQ32,
4476 mkU32( 0 ),
4477 unop( Iop_64HIto32,
4478 unop( Iop_V128to64,
4479 mkexpr( tsrc ) ) ) ),
4480 binop( Iop_CmpEQ32,
4481 mkU32( 0 ),
4482 unop( Iop_64to32,
4483 unop( Iop_V128to64,
4484 mkexpr( tsrc ) ) ) ) ) );
4488 static IRExpr * check_BCD_round (IRExpr *src, IRTemp shift)
4490 /* The src is a 128-bit value containing 31 BCD digits with the sign in
4491 * the least significant byte. The bytes are BCD values between 0x0 and 0x9.
4492 * This routine checks the BCD digit in position shift (counting from
4493 * the least significant digit). If the digit is greater then five,
4494 * a 1 is returned indicating the string needs to be rounded up,
4495 * otherwise, 0 is returned. The value of shift (I64) is the index of
4496 * the BCD digit times four bits.
4498 return binop( Iop_CmpLE64U,
4499 mkU64( 6 ),
4500 binop( Iop_And64,
4501 unop( Iop_V128to64,
4502 binop( Iop_ShrV128,
4503 src,
4504 unop( Iop_64to8, mkexpr( shift ) ) ) ),
4505 mkU64( 0xF ) ) );
4508 static IRTemp increment_BCDstring ( const VexAbiInfo* vbi,
4509 IRExpr *src, IRExpr *carry_in )
4511 /* The src is a 128-bit value containing 31 BCD digits with the sign in
4512 * the least significant byte. The bytes are BCD values between 0x0 and 0x9.
4513 * This function returns the BCD string incremented by 1.
4515 * Call a clean helper to do the computation as it requires a lot of
4516 * IR code to do this.
4518 * The helper function takes a 32-bit BCD string, in a 64-bit value, and
4519 * increments the string by the 32-bi carry in value.
4521 * The incremented value is returned in the lower 32-bits of the result.
4522 * The carry out is returned in bits [35:32] of the result. The
4523 * helper function will be called for each of the four 32-bit strings
4524 * that make up the src string passing the returned carry out to the
4525 * next call.
4527 IRTemp bcd_result = newTemp( Ity_V128 );
4528 IRTemp bcd_result0 = newTemp( Ity_I64 );
4529 IRTemp bcd_result1 = newTemp( Ity_I64 );
4530 IRTemp bcd_result2 = newTemp( Ity_I64 );
4531 IRTemp bcd_result3 = newTemp( Ity_I64 );
4532 IRExpr *bcd_string0, *bcd_string1, *bcd_string2, *bcd_string3;
4534 bcd_string0 = binop( Iop_And64,
4535 mkU64( 0xFFFFFFFF ), unop( Iop_V128to64, src ) );
4536 bcd_string1 = binop( Iop_Shr64, unop( Iop_V128to64, src ), mkU8( 32 ) );
4537 bcd_string2 = binop( Iop_And64,
4538 mkU64( 0xFFFFFFFF ), unop( Iop_V128HIto64, src ) );
4539 bcd_string3 = binop( Iop_Shr64, unop( Iop_V128HIto64, src ), mkU8( 32 ) );
4541 assign( bcd_result0,
4542 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4543 "increment_BCDstring32_helper",
4544 fnptr_to_fnentry( vbi,
4545 &increment_BCDstring32_helper ),
4546 mkIRExprVec_3( mkU64( True /*Signed*/ ),
4547 bcd_string0,
4548 binop( Iop_32HLto64, mkU32( 0 ),
4549 carry_in ) ) ) );
4551 assign( bcd_result1,
4552 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4553 "increment_BCDstring32_helper",
4554 fnptr_to_fnentry( vbi,
4555 &increment_BCDstring32_helper ),
4556 mkIRExprVec_3( mkU64( False /*Unsigned*/ ),
4557 bcd_string1,
4558 binop( Iop_Shr64,
4559 mkexpr( bcd_result0 ),
4560 mkU8( 32 ) ) ) ) );
4561 assign( bcd_result2,
4562 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4563 "increment_BCDstring32_helper",
4564 fnptr_to_fnentry( vbi,
4565 &increment_BCDstring32_helper ),
4566 mkIRExprVec_3( mkU64( False /*Unsigned*/ ),
4567 bcd_string2,
4568 binop( Iop_Shr64,
4569 mkexpr( bcd_result1 ),
4570 mkU8( 32 ) ) ) ) );
4571 assign( bcd_result3,
4572 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4573 "increment_BCDstring32_helper",
4574 fnptr_to_fnentry( vbi,
4575 &increment_BCDstring32_helper ),
4576 mkIRExprVec_3( mkU64( False /*Unsigned*/ ),
4577 bcd_string3,
4578 binop( Iop_Shr64,
4579 mkexpr( bcd_result2 ),
4580 mkU8( 32 ) ) ) ) );
4582 /* Put the 128-bit result together from the intermediate results. Remember
4583 * to mask out the carry out from the upper 32 bits of the results.
4585 assign( bcd_result,
4586 binop( Iop_64HLtoV128,
4587 binop( Iop_Or64,
4588 binop( Iop_And64,
4589 mkU64( 0xFFFFFFFF ), mkexpr (bcd_result2 ) ),
4590 binop( Iop_Shl64,
4591 mkexpr (bcd_result3 ), mkU8( 32 ) ) ),
4592 binop( Iop_Or64,
4593 binop( Iop_And64,
4594 mkU64( 0xFFFFFFFF ), mkexpr (bcd_result0 ) ),
4595 binop( Iop_Shl64,
4596 mkexpr (bcd_result1 ), mkU8( 32 ) ) ) ) );
4597 return bcd_result;
4600 static IRExpr * convert_to_zoned ( const VexAbiInfo* vbi,
4601 IRExpr *src, IRExpr *upper_byte )
4603 /* The function takes a V128 packed decimal value and returns
4604 * the value in zoned format. Note, the sign of the value is ignored.
4606 IRTemp result_low = newTemp( Ity_I64 );
4607 IRTemp result_hi = newTemp( Ity_I64 );
4608 IRTemp result = newTemp( Ity_V128 );
4610 /* Since we can only return 64-bits from a clean helper, we will
4611 * have to get the lower and upper 64-bits separately.
4614 assign( result_low,
4615 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4616 "convert_to_zoned_helper",
4617 fnptr_to_fnentry( vbi, &convert_to_zoned_helper ),
4618 mkIRExprVec_4( unop( Iop_V128HIto64, src ),
4619 unop( Iop_V128to64, src ),
4620 upper_byte,
4621 mkU64( 0 ) ) ) );
4623 assign( result_hi,
4624 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4625 "convert_to_zoned_helper",
4626 fnptr_to_fnentry( vbi, &convert_to_zoned_helper ),
4627 mkIRExprVec_4( unop( Iop_V128HIto64, src ),
4628 unop( Iop_V128to64, src ),
4629 upper_byte,
4630 mkU64( 1 ) ) ) );
4633 assign( result,
4634 binop( Iop_64HLtoV128, mkexpr( result_hi ), mkexpr( result_low ) ) );
4636 return mkexpr( result );
4639 static IRExpr * convert_to_national ( const VexAbiInfo* vbi, IRExpr *src ) {
4640 /* The function takes 128-bit value which has a 64-bit packed decimal
4641 * value in the lower 64-bits of the source. The packed decimal is
4642 * converted to the national format via a clean helper. The clean
4643 * helper is used to to the large amount of IR code needed to do the
4644 * conversion. The helper returns the upper 64-bits of the 128-bit
4645 * result if return_upper != 0. Otherwise, the lower 64-bits of the
4646 * result is returned.
4648 IRTemp result_low = newTemp( Ity_I64 );
4649 IRTemp result_hi = newTemp( Ity_I64 );
4650 IRTemp result = newTemp( Ity_V128 );
4652 /* Since we can only return 64-bits from a clean helper, we will
4653 * have to get the lower and upper 64-bits separately.
4656 assign( result_low,
4657 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4658 "convert_to_national_helper",
4659 fnptr_to_fnentry( vbi, &convert_to_national_helper ),
4660 mkIRExprVec_2( unop( Iop_V128to64, src ),
4661 mkU64( 0 ) ) ) );
4663 assign( result_hi,
4664 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4665 "convert_to_national_helper",
4666 fnptr_to_fnentry( vbi, &convert_to_national_helper ),
4667 mkIRExprVec_2( unop( Iop_V128to64, src ),
4668 mkU64( 1 ) ) ) );
4670 assign( result,
4671 binop( Iop_64HLtoV128, mkexpr( result_hi ), mkexpr( result_low ) ) );
4673 return mkexpr( result );
4676 static IRExpr * convert_from_zoned ( const VexAbiInfo* vbi, IRExpr *src ) {
4677 /* The function takes 128-bit zoned value and returns a signless 64-bit
4678 * packed decimal value in the lower 64-bits of the 128-bit result.
4680 IRTemp result = newTemp( Ity_V128 );
4682 assign( result,
4683 binop( Iop_ShlV128,
4684 binop( Iop_64HLtoV128,
4685 mkU64( 0 ),
4686 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4687 "convert_from_zoned_helper",
4688 fnptr_to_fnentry( vbi,
4689 &convert_from_zoned_helper ),
4690 mkIRExprVec_2( unop( Iop_V128HIto64,
4691 src ),
4692 unop( Iop_V128to64,
4693 src ) ) ) ),
4694 mkU8( 4 ) ) );
4696 return mkexpr( result );
4699 static IRExpr * convert_from_national ( const VexAbiInfo* vbi, IRExpr *src ) {
4700 /* The function takes 128-bit national value and returns a 64-bit
4701 * packed decimal value.
4703 IRTemp result = newTemp( Ity_I64);
4705 assign( result,
4706 mkIRExprCCall( Ity_I64, 0 /*regparms*/,
4707 "convert_from_national_helper",
4708 fnptr_to_fnentry( vbi,
4709 &convert_from_national_helper ),
4710 mkIRExprVec_2( unop( Iop_V128HIto64,
4711 src ),
4712 unop( Iop_V128to64,
4713 src ) ) ) );
4715 return mkexpr( result );
4718 static IRExpr * UNSIGNED_CMP_GT_V128 ( IRExpr *vA, IRExpr *vB ) {
4719 /* This function does an unsigned compare of two V128 values. The
4720 * function is for use in 32-bit mode only as it is expensive. The
4721 * issue is that compares (GT, LT, EQ) are not supported for operands
4722 * larger then 32-bits when running in 32-bit mode. The function returns
4723 * a 1-bit expression, 1 for TRUE and 0 for FALSE.
4725 IRTemp vA_word0 = newTemp( Ity_I32);
4726 IRTemp vA_word1 = newTemp( Ity_I32);
4727 IRTemp vA_word2 = newTemp( Ity_I32);
4728 IRTemp vA_word3 = newTemp( Ity_I32);
4729 IRTemp vB_word0 = newTemp( Ity_I32);
4730 IRTemp vB_word1 = newTemp( Ity_I32);
4731 IRTemp vB_word2 = newTemp( Ity_I32);
4732 IRTemp vB_word3 = newTemp( Ity_I32);
4734 IRTemp eq_word1 = newTemp( Ity_I1);
4735 IRTemp eq_word2 = newTemp( Ity_I1);
4736 IRTemp eq_word3 = newTemp( Ity_I1);
4739 IRExpr *gt_word0, *gt_word1, *gt_word2, *gt_word3;
4740 IRExpr *eq_word3_2, *eq_word3_2_1;
4741 IRTemp result = newTemp( Ity_I1 );
4743 assign( vA_word0, unop( Iop_64to32, unop( Iop_V128to64, vA ) ) );
4744 assign( vA_word1, unop( Iop_64HIto32, unop( Iop_V128to64, vA ) ) );
4745 assign( vA_word2, unop( Iop_64to32, unop( Iop_V128HIto64, vA ) ) );
4746 assign( vA_word3, unop( Iop_64HIto32, unop( Iop_V128HIto64, vA ) ) );
4748 assign( vB_word0, unop( Iop_64to32, unop( Iop_V128to64, vB ) ) );
4749 assign( vB_word1, unop( Iop_64HIto32, unop( Iop_V128to64, vB ) ) );
4750 assign( vB_word2, unop( Iop_64to32, unop( Iop_V128HIto64, vB ) ) );
4751 assign( vB_word3, unop( Iop_64HIto32, unop( Iop_V128HIto64, vB ) ) );
4753 assign( eq_word3, binop( Iop_CmpEQ32, mkexpr( vA_word3 ),
4754 mkexpr( vB_word3 ) ) );
4755 assign( eq_word2, binop( Iop_CmpEQ32, mkexpr( vA_word2 ),
4756 mkexpr( vB_word2 ) ) );
4757 assign( eq_word1, binop( Iop_CmpEQ32, mkexpr( vA_word1 ),
4758 mkexpr( vB_word1 ) ) );
4760 gt_word3 = binop( Iop_CmpLT32U, mkexpr( vB_word3 ), mkexpr( vA_word3 ) );
4761 gt_word2 = binop( Iop_CmpLT32U, mkexpr( vB_word2 ), mkexpr( vA_word2 ) );
4762 gt_word1 = binop( Iop_CmpLT32U, mkexpr( vB_word1 ), mkexpr( vA_word1 ) );
4763 gt_word0 = binop( Iop_CmpLT32U, mkexpr( vB_word0 ), mkexpr( vA_word0 ) );
4765 eq_word3_2 = mkAND1( mkexpr( eq_word3 ), mkexpr( eq_word2 ) );
4766 eq_word3_2_1 = mkAND1( mkexpr( eq_word1 ), eq_word3_2 );
4768 assign( result, mkOR1(
4769 mkOR1( gt_word3,
4770 mkAND1( mkexpr( eq_word3 ), gt_word2 ) ),
4771 mkOR1( mkAND1( eq_word3_2, gt_word1 ),
4772 mkAND1( eq_word3_2_1, gt_word0 ) ) ) );
4773 return mkexpr( result );
4776 /*------------------------------------------------------------*/
4777 /* Transactional memory helpers
4779 *------------------------------------------------------------*/
4781 static ULong generate_TMreason( UInt failure_code,
4782 UInt persistant,
4783 UInt nest_overflow,
4784 UInt tm_exact )
4786 ULong tm_err_code =
4787 ( (ULong) 0) << (63-6) /* Failure code */
4788 | ( (ULong) persistant) << (63-7) /* Failure persistant */
4789 | ( (ULong) 0) << (63-8) /* Disallowed */
4790 | ( (ULong) nest_overflow) << (63-9) /* Nesting Overflow */
4791 | ( (ULong) 0) << (63-10) /* Footprint Overflow */
4792 | ( (ULong) 0) << (63-11) /* Self-Induced Conflict */
4793 | ( (ULong) 0) << (63-12) /* Non-Transactional Conflict */
4794 | ( (ULong) 0) << (63-13) /* Transactional Conflict */
4795 | ( (ULong) 0) << (63-14) /* Translation Invalidation Conflict */
4796 | ( (ULong) 0) << (63-15) /* Implementation-specific */
4797 | ( (ULong) 0) << (63-16) /* Instruction Fetch Conflict */
4798 | ( (ULong) 0) << (63-30) /* Reserved */
4799 | ( (ULong) 0) << (63-31) /* Abort */
4800 | ( (ULong) 0) << (63-32) /* Suspend */
4801 | ( (ULong) 0) << (63-33) /* Reserved */
4802 | ( (ULong) 0) << (63-35) /* Privilege */
4803 | ( (ULong) 0) << (63-36) /* Failure Summary */
4804 | ( (ULong) tm_exact) << (63-37) /* TFIAR Exact */
4805 | ( (ULong) 0) << (63-38) /* ROT */
4806 | ( (ULong) 0) << (63-51) /* Reserved */
4807 | ( (ULong) 0) << (63-63); /* Transaction Level */
4809 return tm_err_code;
4812 static void storeTMfailure( Addr64 err_address, ULong tm_reason,
4813 Addr64 handler_address )
4815 putGST( PPC_GST_TFIAR, mkU64( err_address ) );
4816 putGST( PPC_GST_TEXASR, mkU64( tm_reason ) );
4817 putGST( PPC_GST_TEXASRU, mkU32( 0 ) );
4818 putGST( PPC_GST_TFHAR, mkU64( handler_address ) );
4821 /*------------------------------------------------------------*/
4822 /*--- Integer Instruction Translation --- */
4823 /*------------------------------------------------------------*/
4826 Integer Arithmetic Instructions
4828 static Bool dis_int_mult_add ( UInt theInstr )
4830 /* VA-Form */
4831 UChar rD_addr = ifieldRegDS( theInstr );
4832 UChar rA_addr = ifieldRegA( theInstr );
4833 UChar rB_addr = ifieldRegB( theInstr );
4834 UChar rC_addr = ifieldRegC( theInstr );
4835 UInt opc2 = IFIELD( theInstr, 0, 6 );
4836 IRType ty = Ity_I64;
4837 IRTemp rA = newTemp( ty );
4838 IRTemp rB = newTemp( ty );
4839 IRTemp rC = newTemp( ty );
4840 IRTemp rD = newTemp( ty );
4841 IRTemp tmpLo = newTemp( Ity_I64 );
4842 IRTemp tmpHi = newTemp( Ity_I64 );
4843 IRTemp tmp2Hi = newTemp( Ity_I64 );
4844 IRTemp result = newTemp( Ity_I128 );
4845 IRTemp resultLo = newTemp( Ity_I64 );
4846 IRExpr* carryout;
4848 assign( rA, getIReg( rA_addr ) );
4849 assign( rB, getIReg( rB_addr ) );
4850 assign( rC, getIReg( rC_addr ) );
4852 switch (opc2) {
4853 case 0x30: // maddhd multiply-add High doubleword signed
4854 DIP("maddhd r%u,r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr, rC_addr);
4856 assign( result, binop( Iop_MullS64, mkexpr( rA ), mkexpr( rB ) ) );
4857 assign( tmpLo, unop( Iop_128to64, mkexpr( result ) ) );
4858 assign( tmpHi, unop( Iop_128HIto64, mkexpr( result ) ) );
4860 /* Multiply rA and rB then add rC. If the lower 32-bits of the result
4861 * is less then rC and the result rA * rB, a carry out of the lower 32
4862 * bits occurred and the upper 32 bits must be incremented by 1. Sign
4863 * extend rC and do the add to the upper 64 bits to handle the
4864 * negative case for rC.
4866 assign( resultLo, binop( Iop_Add64, mkexpr( tmpLo ), mkexpr( rC ) ) );
4867 assign( tmp2Hi, binop( Iop_Add64,
4868 mkexpr( tmpHi ),
4869 unop( Iop_1Sto64,
4870 unop( Iop_64to1,
4871 binop( Iop_Shr64,
4872 mkexpr( rC ),
4873 mkU8( 63 ) ) ) ) ) );
4875 /* need to do calculation for the upper 32 bit result */
4876 carryout = mkAND1( binop( Iop_CmpLT64U,
4877 mkexpr( resultLo ), mkexpr( rC ) ),
4878 binop( Iop_CmpLT64U,
4879 mkexpr( resultLo ), mkexpr( tmpLo ) ) );
4880 assign( rD, binop( Iop_Add64,
4881 mkexpr( tmp2Hi ),
4882 unop( Iop_1Uto64, carryout ) ) );
4883 break;
4885 case 0x31: // maddhdu multiply-add High doubleword unsigned
4886 DIP("maddhdu r%u,r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr, rC_addr);
4888 assign( result, binop( Iop_MullU64, mkexpr( rA ), mkexpr( rB ) ) );
4889 assign( tmpLo, unop( Iop_128to64, mkexpr( result ) ) );
4890 assign( tmpHi, unop( Iop_128HIto64, mkexpr( result ) ) );
4892 /* Add rC, if the lower 32-bits of the result is less then rC and
4893 * tmpLo, a carry out of the lower 32 bits occurred. Upper 32 bits
4894 * must be incremented by 1.
4896 assign( resultLo, binop( Iop_Add64, mkexpr( tmpLo ), mkexpr( rC ) ) );
4898 /* need to do calculation for the upper 32 bit result */
4899 carryout = mkAND1( binop( Iop_CmpLT64U,
4900 mkexpr(resultLo), mkexpr( rC ) ),
4901 binop( Iop_CmpLT64U,
4902 mkexpr(resultLo), mkexpr( tmpLo ) ) );
4903 assign( rD, binop( Iop_Add64,
4904 mkexpr( tmpHi ),
4905 unop( Iop_1Uto64, carryout ) ) );
4906 break;
4908 case 0x33: // maddld multiply-add Low doubleword
4909 DIP("maddld r%u,r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr, rC_addr);
4911 assign( result, binop( Iop_MullS64, mkexpr( rA ), mkexpr( rB ) ) );
4912 assign( tmpLo, unop( Iop_128to64, mkexpr( result ) ) );
4913 assign( tmpHi, unop( Iop_128HIto64, mkexpr( result ) ) );
4915 assign( rD, binop( Iop_Add64, mkexpr( tmpLo ), mkexpr( rC ) ) );
4916 break;
4918 default:
4919 vex_printf("dis_int_mult(ppc): unrecognized instruction\n");
4920 return False;
4923 putIReg( rD_addr, mkexpr(rD) );
4925 return True;
4928 static Bool dis_int_arith ( UInt theInstr )
4930 /* D-Form, XO-Form */
4931 UChar opc1 = ifieldOPC(theInstr);
4932 UChar rD_addr = ifieldRegDS(theInstr);
4933 UChar rA_addr = ifieldRegA(theInstr);
4934 UInt uimm16 = ifieldUIMM16(theInstr);
4935 UChar rB_addr = ifieldRegB(theInstr);
4936 UChar flag_OE = ifieldBIT10(theInstr);
4937 UInt opc2 = ifieldOPClo9(theInstr);
4938 UChar flag_rC = ifieldBIT0(theInstr);
4940 Long simm16 = extend_s_16to64(uimm16);
4941 IRType ty = mode64 ? Ity_I64 : Ity_I32;
4942 IRTemp rA = newTemp(ty);
4943 IRTemp rB = newTemp(ty);
4944 IRTemp rD = newTemp(ty);
4946 Bool do_rc = False;
4948 assign( rA, getIReg(rA_addr) );
4949 assign( rB, getIReg(rB_addr) ); // XO-Form: rD, rA, rB
4951 switch (opc1) {
4952 /* D-Form */
4953 case 0x0C: // addic (Add Immediate Carrying, PPC32 p351
4954 DIP("addic r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
4955 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
4956 mkSzExtendS16(ty, uimm16) ) );
4957 set_XER_CA_CA32( ty, PPCG_FLAG_OP_ADD,
4958 mkexpr(rD), mkexpr(rA), mkSzExtendS16(ty, uimm16),
4959 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
4960 break;
4962 case 0x0D: // addic. (Add Immediate Carrying and Record, PPC32 p352)
4963 DIP("addic. r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
4964 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
4965 mkSzExtendS16(ty, uimm16) ) );
4966 set_XER_CA_CA32( ty, PPCG_FLAG_OP_ADD,
4967 mkexpr(rD), mkexpr(rA), mkSzExtendS16(ty, uimm16),
4968 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
4969 do_rc = True; // Always record to CR
4970 flag_rC = 1;
4971 break;
4973 case 0x0E: // addi (Add Immediate, PPC32 p350)
4974 // li rD,val == addi rD,0,val
4975 // la disp(rA) == addi rD,rA,disp
4976 if ( rA_addr == 0 ) {
4977 DIP("li r%u,%d\n", rD_addr, (Int)simm16);
4978 assign( rD, mkSzExtendS16(ty, uimm16) );
4979 } else {
4980 DIP("addi r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
4981 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
4982 mkSzExtendS16(ty, uimm16) ) );
4984 break;
4986 case 0x0F: // addis (Add Immediate Shifted, PPC32 p353)
4987 // lis rD,val == addis rD,0,val
4988 if ( rA_addr == 0 ) {
4989 DIP("lis r%u,%d\n", rD_addr, (Int)simm16);
4990 assign( rD, mkSzExtendS32(ty, uimm16 << 16) );
4991 } else {
4992 DIP("addis r%u,r%u,0x%x\n", rD_addr, rA_addr, (UInt)simm16);
4993 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
4994 mkSzExtendS32(ty, uimm16 << 16) ) );
4996 break;
4998 case 0x07: // mulli (Multiply Low Immediate, PPC32 p490)
4999 DIP("mulli r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
5000 if (mode64)
5001 assign( rD, unop(Iop_128to64,
5002 binop(Iop_MullS64, mkexpr(rA),
5003 mkSzExtendS16(ty, uimm16))) );
5004 else
5005 assign( rD, unop(Iop_64to32,
5006 binop(Iop_MullS32, mkexpr(rA),
5007 mkSzExtendS16(ty, uimm16))) );
5008 break;
5010 case 0x08: // subfic (Subtract from Immediate Carrying, PPC32 p540)
5011 DIP("subfic r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
5012 // rD = simm16 - rA
5013 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
5014 mkSzExtendS16(ty, uimm16),
5015 mkexpr(rA)) );
5016 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SUBFI,
5017 mkexpr(rD), mkexpr(rA), mkSzExtendS16(ty, uimm16),
5018 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
5019 break;
5021 /* XO-Form */
5022 case 0x1F:
5023 do_rc = True; // All below record to CR
5025 switch (opc2) {
5026 case 0x10A: // add (Add, PPC32 p347)
5027 DIP("add%s%s r%u,r%u,r%u\n",
5028 flag_OE ? "o" : "", flag_rC ? ".":"",
5029 rD_addr, rA_addr, rB_addr);
5030 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5031 mkexpr(rA), mkexpr(rB) ) );
5032 if (flag_OE) {
5033 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_ADD,
5034 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5036 break;
5038 case 0x00A: // addc (Add Carrying, PPC32 p348)
5039 DIP("addc%s%s r%u,r%u,r%u\n",
5040 flag_OE ? "o" : "", flag_rC ? ".":"",
5041 rD_addr, rA_addr, rB_addr);
5042 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5043 mkexpr(rA), mkexpr(rB)) );
5044 set_XER_CA_CA32( ty, PPCG_FLAG_OP_ADD,
5045 mkexpr(rD), mkexpr(rA), mkexpr(rB),
5046 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
5047 if (flag_OE) {
5048 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_ADD,
5049 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5051 break;
5053 case 0x08A: { // adde (Add Extended, PPC32 p349)
5054 IRTemp old_xer_ca = newTemp(ty);
5055 DIP("adde%s%s r%u,r%u,r%u\n",
5056 flag_OE ? "o" : "", flag_rC ? ".":"",
5057 rD_addr, rA_addr, rB_addr);
5058 // rD = rA + rB + XER[CA]
5059 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA_32(), False) );
5060 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
5061 binop( mkSzOp(ty, Iop_Add8),
5062 mkexpr(rB), mkexpr(old_xer_ca))) );
5063 set_XER_CA_CA32( ty, PPCG_FLAG_OP_ADDE,
5064 mkexpr(rD), mkexpr(rA), mkexpr(rB),
5065 mkexpr(old_xer_ca) );
5066 if (flag_OE) {
5067 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_ADDE,
5068 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5070 break;
5073 case 0xAA: {// addex (Add Extended alternate carry bit Z23-form)
5074 DIP("addex r%u,r%u,r%u,%d\n", rD_addr, rA_addr, rB_addr, (Int)flag_OE);
5075 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
5076 binop( mkSzOp(ty, Iop_Add8), mkexpr(rB),
5077 mkWidenFrom8( ty, getXER_OV(), False ) ) ) );
5079 /* CY bit is same as OE bit */
5080 if (flag_OE == 0) {
5081 /* Exception, do not set SO bit */
5082 set_XER_OV_OV32( ty, PPCG_FLAG_OP_ADDE,
5083 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5084 } else {
5085 /* CY=1, 2 and 3 (AKA flag_OE) are reserved */
5086 vex_printf("addex instruction, CY = %d is reserved.\n", flag_OE);
5087 vpanic("addex instruction\n");
5089 break;
5092 case 0x0EA: { // addme (Add to Minus One Extended, PPC32 p354)
5093 IRTemp old_xer_ca = newTemp(ty);
5094 IRExpr *min_one;
5095 if (rB_addr != 0) {
5096 vex_printf("dis_int_arith(ppc)(addme,rB_addr)\n");
5097 return False;
5099 DIP("addme%s%s r%u,r%u,r%u\n",
5100 flag_OE ? "o" : "", flag_rC ? ".":"",
5101 rD_addr, rA_addr, rB_addr);
5102 // rD = rA + (-1) + XER[CA]
5103 // => Just another form of adde
5104 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA_32(), False) );
5105 min_one = mkSzImm(ty, (Long)-1);
5106 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
5107 binop( mkSzOp(ty, Iop_Add8),
5108 min_one, mkexpr(old_xer_ca)) ));
5109 set_XER_CA_CA32( ty, PPCG_FLAG_OP_ADDE,
5110 mkexpr(rD), mkexpr(rA), min_one,
5111 mkexpr(old_xer_ca) );
5112 if (flag_OE) {
5113 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_ADDE,
5114 mkexpr(rD), mkexpr(rA), min_one );
5116 break;
5119 case 0x0CA: { // addze (Add to Zero Extended, PPC32 p355)
5120 IRTemp old_xer_ca = newTemp(ty);
5121 if (rB_addr != 0) {
5122 vex_printf("dis_int_arith(ppc)(addze,rB_addr)\n");
5123 return False;
5125 DIP("addze%s%s r%u,r%u,r%u\n",
5126 flag_OE ? "o" : "", flag_rC ? ".":"",
5127 rD_addr, rA_addr, rB_addr);
5128 // rD = rA + (0) + XER[CA]
5129 // => Just another form of adde
5130 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA_32(), False) );
5131 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5132 mkexpr(rA), mkexpr(old_xer_ca)) );
5133 set_XER_CA_CA32( ty, PPCG_FLAG_OP_ADDE,
5134 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0),
5135 mkexpr(old_xer_ca) );
5136 if (flag_OE) {
5137 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_ADDE,
5138 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0) );
5140 break;
5143 case 0x1EB: // divw (Divide Word, PPC32 p388)
5144 DIP("divw%s%s r%u,r%u,r%u\n",
5145 flag_OE ? "o" : "", flag_rC ? ".":"",
5146 rD_addr, rA_addr, rB_addr);
5147 if (mode64) {
5148 /* Note:
5149 XER settings are mode independent, and reflect the
5150 overflow of the low-order 32bit result
5151 CR0[LT|GT|EQ] are undefined if flag_rC && mode64
5153 /* rD[hi32] are undefined: setting them to sign of lo32
5154 - makes set_CR0 happy */
5155 IRExpr* dividend = mk64lo32Sto64( mkexpr(rA) );
5156 IRExpr* divisor = mk64lo32Sto64( mkexpr(rB) );
5157 assign( rD, mk64lo32Uto64( binop(Iop_DivS64, dividend,
5158 divisor) ) );
5159 if (flag_OE) {
5160 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_DIVW,
5161 mkexpr(rD), dividend, divisor );
5163 } else {
5164 assign( rD, binop(Iop_DivS32, mkexpr(rA), mkexpr(rB)) );
5165 if (flag_OE) {
5166 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_DIVW,
5167 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5170 /* Note:
5171 if (0x8000_0000 / -1) or (x / 0)
5172 => rD=undef, if(flag_rC) CR7=undef, if(flag_OE) XER_OV=1
5173 => But _no_ exception raised. */
5174 break;
5176 case 0x1CB: // divwu (Divide Word Unsigned, PPC32 p389)
5177 DIP("divwu%s%s r%u,r%u,r%u\n",
5178 flag_OE ? "o" : "", flag_rC ? ".":"",
5179 rD_addr, rA_addr, rB_addr);
5180 if (mode64) {
5181 /* Note:
5182 XER settings are mode independent, and reflect the
5183 overflow of the low-order 32bit result
5184 CR0[LT|GT|EQ] are undefined if flag_rC && mode64
5186 IRExpr* dividend = mk64lo32Uto64( mkexpr(rA) );
5187 IRExpr* divisor = mk64lo32Uto64( mkexpr(rB) );
5188 assign( rD, mk64lo32Uto64( binop(Iop_DivU64, dividend,
5189 divisor) ) );
5190 if (flag_OE) {
5191 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_DIVWU,
5192 mkexpr(rD), dividend, divisor );
5194 } else {
5195 assign( rD, binop(Iop_DivU32, mkexpr(rA), mkexpr(rB)) );
5196 if (flag_OE) {
5197 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_DIVWU,
5198 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5201 /* Note: ditto comment divw, for (x / 0) */
5202 break;
5204 case 0x04B: // mulhw (Multiply High Word, PPC32 p488)
5205 if (flag_OE != 0) {
5206 vex_printf("dis_int_arith(ppc)(mulhw,flag_OE)\n");
5207 return False;
5209 DIP("mulhw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
5210 rD_addr, rA_addr, rB_addr);
5211 if (mode64) {
5212 /* rD[hi32] are undefined: setting them to sign of lo32
5213 - makes set_CR0 happy */
5214 assign( rD, binop(Iop_Sar64,
5215 binop(Iop_Mul64,
5216 mk64lo32Sto64( mkexpr(rA) ),
5217 mk64lo32Sto64( mkexpr(rB) )),
5218 mkU8(32)) );
5219 } else {
5220 assign( rD, unop(Iop_64HIto32,
5221 binop(Iop_MullS32,
5222 mkexpr(rA), mkexpr(rB))) );
5224 break;
5226 case 0x00B: // mulhwu (Multiply High Word Unsigned, PPC32 p489)
5227 if (flag_OE != 0) {
5228 vex_printf("dis_int_arith(ppc)(mulhwu,flag_OE)\n");
5229 return False;
5231 DIP("mulhwu%s r%u,r%u,r%u\n", flag_rC ? ".":"",
5232 rD_addr, rA_addr, rB_addr);
5233 if (mode64) {
5234 /* rD[hi32] are undefined: setting them to sign of lo32
5235 - makes set_CR0 happy */
5236 assign( rD, binop(Iop_Sar64,
5237 binop(Iop_Mul64,
5238 mk64lo32Uto64( mkexpr(rA) ),
5239 mk64lo32Uto64( mkexpr(rB) ) ),
5240 mkU8(32)) );
5241 } else {
5242 assign( rD, unop(Iop_64HIto32,
5243 binop(Iop_MullU32,
5244 mkexpr(rA), mkexpr(rB))) );
5246 break;
5248 case 0x0EB: // mullw (Multiply Low Word, PPC32 p491)
5249 DIP("mullw%s%s r%u,r%u,r%u\n",
5250 flag_OE ? "o" : "", flag_rC ? ".":"",
5251 rD_addr, rA_addr, rB_addr);
5252 if (mode64) {
5253 /* rD[hi32] are undefined: setting them to sign of lo32
5254 - set_XER_OV() and set_CR0() depend on this */
5255 IRExpr *a = unop(Iop_64to32, mkexpr(rA) );
5256 IRExpr *b = unop(Iop_64to32, mkexpr(rB) );
5257 assign( rD, binop(Iop_MullS32, a, b) );
5258 if (flag_OE) {
5259 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_MULLW,
5260 mkexpr(rD),
5261 unop(Iop_32Uto64, a), unop(Iop_32Uto64, b) );
5263 } else {
5264 assign( rD, unop(Iop_64to32,
5265 binop(Iop_MullU32,
5266 mkexpr(rA), mkexpr(rB))) );
5267 if (flag_OE) {
5268 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_MULLW,
5269 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5272 break;
5274 case 0x068: // neg (Negate, PPC32 p493)
5275 if (rB_addr != 0) {
5276 vex_printf("dis_int_arith(ppc)(neg,rB_addr)\n");
5277 return False;
5279 DIP("neg%s%s r%u,r%u\n",
5280 flag_OE ? "o" : "", flag_rC ? ".":"",
5281 rD_addr, rA_addr);
5282 // rD = (~rA) + 1
5283 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5284 unop( mkSzOp(ty, Iop_Not8), mkexpr(rA) ),
5285 mkSzImm(ty, 1)) );
5286 if (flag_OE) {
5287 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_NEG,
5288 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5290 break;
5292 case 0x028: // subf (Subtract From, PPC32 p537)
5293 DIP("subf%s%s r%u,r%u,r%u\n",
5294 flag_OE ? "o" : "", flag_rC ? ".":"",
5295 rD_addr, rA_addr, rB_addr);
5296 // rD = rB - rA
5297 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
5298 mkexpr(rB), mkexpr(rA)) );
5299 if (flag_OE) {
5300 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_SUBF,
5301 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5303 break;
5305 case 0x008: // subfc (Subtract from Carrying, PPC32 p538)
5306 DIP("subfc%s%s r%u,r%u,r%u\n",
5307 flag_OE ? "o" : "", flag_rC ? ".":"",
5308 rD_addr, rA_addr, rB_addr);
5309 // rD = rB - rA
5310 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
5311 mkexpr(rB), mkexpr(rA)) );
5312 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SUBFC,
5313 mkexpr(rD), mkexpr(rA), mkexpr(rB),
5314 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
5315 if (flag_OE) {
5316 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_SUBFC,
5317 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5319 break;
5321 case 0x088: {// subfe (Subtract from Extended, PPC32 p539)
5322 IRTemp old_xer_ca = newTemp(ty);
5323 DIP("subfe%s%s r%u,r%u,r%u\n",
5324 flag_OE ? "o" : "", flag_rC ? ".":"",
5325 rD_addr, rA_addr, rB_addr);
5326 // rD = (log not)rA + rB + XER[CA]
5327 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA_32(), False) );
5328 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5329 unop( mkSzOp(ty, Iop_Not8), mkexpr(rA)),
5330 binop( mkSzOp(ty, Iop_Add8),
5331 mkexpr(rB), mkexpr(old_xer_ca))) );
5332 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SUBFE,
5333 mkexpr(rD), mkexpr(rA), mkexpr(rB),
5334 mkexpr(old_xer_ca) );
5335 if (flag_OE) {
5336 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_SUBFE,
5337 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5339 break;
5342 case 0x0E8: { // subfme (Subtract from -1 Extended, PPC32 p541)
5343 IRTemp old_xer_ca = newTemp(ty);
5344 IRExpr *min_one;
5345 if (rB_addr != 0) {
5346 vex_printf("dis_int_arith(ppc)(subfme,rB_addr)\n");
5347 return False;
5349 DIP("subfme%s%s r%u,r%u\n",
5350 flag_OE ? "o" : "", flag_rC ? ".":"",
5351 rD_addr, rA_addr);
5352 // rD = (log not)rA + (-1) + XER[CA]
5353 // => Just another form of subfe
5354 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA_32(), False) );
5355 min_one = mkSzImm(ty, (Long)-1);
5356 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5357 unop( mkSzOp(ty, Iop_Not8), mkexpr(rA)),
5358 binop( mkSzOp(ty, Iop_Add8),
5359 min_one, mkexpr(old_xer_ca))) );
5360 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SUBFE,
5361 mkexpr(rD), mkexpr(rA), min_one,
5362 mkexpr(old_xer_ca) );
5363 if (flag_OE) {
5364 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_SUBFE,
5365 mkexpr(rD), mkexpr(rA), min_one );
5367 break;
5370 case 0x0C8: { // subfze (Subtract from Zero Extended, PPC32 p542)
5371 IRTemp old_xer_ca = newTemp(ty);
5372 if (rB_addr != 0) {
5373 vex_printf("dis_int_arith(ppc)(subfze,rB_addr)\n");
5374 return False;
5376 DIP("subfze%s%s r%u,r%u\n",
5377 flag_OE ? "o" : "", flag_rC ? ".":"",
5378 rD_addr, rA_addr);
5379 // rD = (log not)rA + (0) + XER[CA]
5380 // => Just another form of subfe
5381 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA_32(), False) );
5382 assign( rD, binop( mkSzOp(ty, Iop_Add8),
5383 unop( mkSzOp(ty, Iop_Not8),
5384 mkexpr(rA)), mkexpr(old_xer_ca)) );
5385 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SUBFE,
5386 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0),
5387 mkexpr(old_xer_ca) );
5388 if (flag_OE) {
5389 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_SUBFE,
5390 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0) );
5392 break;
5396 /* 64bit Arithmetic */
5397 case 0x49: // mulhd (Multiply High DWord, PPC64 p539)
5398 if (flag_OE != 0) {
5399 vex_printf("dis_int_arith(ppc)(mulhd,flagOE)\n");
5400 return False;
5402 DIP("mulhd%s r%u,r%u,r%u\n", flag_rC ? ".":"",
5403 rD_addr, rA_addr, rB_addr);
5404 assign( rD, unop(Iop_128HIto64,
5405 binop(Iop_MullS64,
5406 mkexpr(rA), mkexpr(rB))) );
5408 break;
5410 case 0x9: // mulhdu (Multiply High DWord Unsigned, PPC64 p540)
5411 if (flag_OE != 0) {
5412 vex_printf("dis_int_arith(ppc)(mulhdu,flagOE)\n");
5413 return False;
5415 DIP("mulhdu%s r%u,r%u,r%u\n", flag_rC ? ".":"",
5416 rD_addr, rA_addr, rB_addr);
5417 assign( rD, unop(Iop_128HIto64,
5418 binop(Iop_MullU64,
5419 mkexpr(rA), mkexpr(rB))) );
5420 break;
5422 case 0xE9: // mulld (Multiply Low DWord, PPC64 p543)
5423 DIP("mulld%s%s r%u,r%u,r%u\n",
5424 flag_OE ? "o" : "", flag_rC ? ".":"",
5425 rD_addr, rA_addr, rB_addr);
5426 assign( rD, binop(Iop_Mul64, mkexpr(rA), mkexpr(rB)) );
5427 if (flag_OE) {
5428 set_XER_OV_64( PPCG_FLAG_OP_MULLD,
5429 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5430 /* OV is set to 1 if product isn't representable.
5431 * In this case also need to set OV32 and SO to 1,
5432 * i.e. copy OV to OV32 and SO.
5434 copy_OV_to_OV32();
5435 update_SO();
5437 break;
5439 case 0x1E9: // divd (Divide DWord, PPC64 p419)
5440 DIP("divd%s%s r%u,r%u,r%u\n",
5441 flag_OE ? "o" : "", flag_rC ? ".":"",
5442 rD_addr, rA_addr, rB_addr);
5443 assign( rD, binop(Iop_DivS64, mkexpr(rA), mkexpr(rB)) );
5444 if (flag_OE) {
5445 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_DIVW,
5446 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5448 break;
5449 /* Note:
5450 if (0x8000_0000_0000_0000 / -1) or (x / 0)
5451 => rD=undef, if(flag_rC) CR7=undef, if(flag_OE) XER_OV=1
5452 => But _no_ exception raised. */
5454 case 0x1C9: // divdu (Divide DWord Unsigned, PPC64 p420)
5455 DIP("divdu%s%s r%u,r%u,r%u\n",
5456 flag_OE ? "o" : "", flag_rC ? ".":"",
5457 rD_addr, rA_addr, rB_addr);
5458 assign( rD, binop(Iop_DivU64, mkexpr(rA), mkexpr(rB)) );
5459 if (flag_OE) {
5460 set_XER_OV_OV32_SO( ty, PPCG_FLAG_OP_DIVWU,
5461 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
5463 break;
5464 /* Note: ditto comment divd, for (x / 0) */
5466 case 0x18B: // divweu (Divide Word Extended Unsigned)
5469 * If (RA) >= (RB), or if an attempt is made to perform the division
5470 * <anything> / 0
5471 * then the contents of register RD are undefined as are (if Rc=1) the contents of
5472 * the LT, GT, and EQ bits of CR Field 0. In these cases, if OE=1 then OV is set
5473 * to 1.
5475 IRTemp res = newTemp(Ity_I32);
5476 IRExpr * dividend, * divisor;
5477 DIP("divweu%s%s r%u,r%u,r%u\n",
5478 flag_OE ? "o" : "", flag_rC ? ".":"",
5479 rD_addr, rA_addr, rB_addr);
5480 if (mode64) {
5481 dividend = unop( Iop_64to32, mkexpr( rA ) );
5482 divisor = unop( Iop_64to32, mkexpr( rB ) );
5483 assign( res, binop( Iop_DivU32E, dividend, divisor ) );
5484 assign( rD, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( res ) ) );
5485 } else {
5486 dividend = mkexpr( rA );
5487 divisor = mkexpr( rB );
5488 assign( res, binop( Iop_DivU32E, dividend, divisor ) );
5489 assign( rD, mkexpr( res) );
5492 if (flag_OE) {
5493 set_XER_OV_OV32_32( PPCG_FLAG_OP_DIVWEU,
5494 mkexpr(res), dividend, divisor );
5495 update_SO( );
5497 break;
5500 case 0x1AB: // divwe (Divide Word Extended)
5503 * If the quotient cannot be represented in 32 bits, or if an
5504 * attempt is made to perform the division
5505 * <anything> / 0
5506 * then the contents of register RD are undefined as are (if
5507 * Rc=1) the contents of the LT, GT, and EQ bits of CR
5508 * Field 0. In these cases, if OE=1 then OV is set to 1.
5511 IRTemp res = newTemp(Ity_I32);
5512 IRExpr * dividend, * divisor;
5513 DIP("divwe%s%s r%u,r%u,r%u\n",
5514 flag_OE ? "o" : "", flag_rC ? ".":"",
5515 rD_addr, rA_addr, rB_addr);
5516 if (mode64) {
5517 dividend = unop( Iop_64to32, mkexpr( rA ) );
5518 divisor = unop( Iop_64to32, mkexpr( rB ) );
5519 assign( res, binop( Iop_DivS32E, dividend, divisor ) );
5520 assign( rD, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( res ) ) );
5521 } else {
5522 dividend = mkexpr( rA );
5523 divisor = mkexpr( rB );
5524 assign( res, binop( Iop_DivS32E, dividend, divisor ) );
5525 assign( rD, mkexpr( res) );
5528 if (flag_OE) {
5529 set_XER_OV_OV32_32( PPCG_FLAG_OP_DIVWE,
5530 mkexpr(res), dividend, divisor );
5531 update_SO( );
5533 break;
5537 case 0x1A9: // divde (Divide Doubleword Extended)
5539 * If the quotient cannot be represented in 64 bits, or if an
5540 * attempt is made to perform the division
5541 * <anything> / 0
5542 * then the contents of register RD are undefined as are (if
5543 * Rc=1) the contents of the LT, GT, and EQ bits of CR
5544 * Field 0. In these cases, if OE=1 then OV is set to 1.
5546 DIP("divde%s%s r%u,r%u,r%u\n",
5547 flag_OE ? "o" : "", flag_rC ? ".":"",
5548 rD_addr, rA_addr, rB_addr);
5549 assign( rD, binop(Iop_DivS64E, mkexpr(rA), mkexpr(rB)) );
5550 if (flag_OE) {
5551 set_XER_OV_64( PPCG_FLAG_OP_DIVDE, mkexpr( rD ),
5552 mkexpr( rA ), mkexpr( rB ) );
5553 copy_OV_to_OV32();
5554 update_SO();
5556 break;
5558 case 0x189: // divdeuo (Divide Doubleword Extended Unsigned)
5559 // Same CR and OV rules as given for divweu above
5560 DIP("divdeu%s%s r%u,r%u,r%u\n",
5561 flag_OE ? "o" : "", flag_rC ? ".":"",
5562 rD_addr, rA_addr, rB_addr);
5563 assign( rD, binop(Iop_DivU64E, mkexpr(rA), mkexpr(rB)) );
5564 if (flag_OE) {
5565 set_XER_OV_64( PPCG_FLAG_OP_DIVDEU, mkexpr( rD ),
5566 mkexpr( rA ), mkexpr( rB ) );
5567 copy_OV_to_OV32();
5568 update_SO();
5570 break;
5572 default:
5573 vex_printf("dis_int_arith(ppc)(opc2)\n");
5574 return False;
5576 break;
5578 default:
5579 vex_printf("dis_int_arith(ppc)(opc1)\n");
5580 return False;
5583 putIReg( rD_addr, mkexpr(rD) );
5585 if (do_rc && flag_rC) {
5586 set_CR0( mkexpr(rD) );
5588 return True;
5591 static Bool dis_modulo_int ( UInt theInstr )
5593 /* X-Form */
5594 UChar opc1 = ifieldOPC( theInstr );
5595 UInt opc2 = ifieldOPClo10( theInstr );
5596 UChar rA_addr = ifieldRegA( theInstr );
5597 UChar rB_addr = ifieldRegB( theInstr );
5598 UChar rD_addr = ifieldRegDS( theInstr );
5599 IRType ty = mode64 ? Ity_I64 : Ity_I32;
5600 IRTemp rD = newTemp( ty );
5602 switch (opc1) {
5603 /* X-Form */
5604 case 0x1F:
5605 switch (opc2) {
5606 case 0x109: // modud Modulo Unsigned Double Word
5608 IRTemp rA = newTemp( Ity_I64 );
5609 IRTemp rB = newTemp( Ity_I64 );
5610 IRTemp quotient = newTemp( Ity_I64 );
5611 IRTemp quotientTimesDivisor = newTemp( Ity_I64 );
5612 IRTemp remainder = newTemp( Ity_I64 );
5613 IRTemp rB_0 = newTemp( Ity_I64 ); /* all 1's if rB = 0 */
5615 DIP("modud r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
5617 assign( rA, getIReg( rA_addr ) );
5618 assign( rB, getIReg( rB_addr ) );
5620 assign( quotient,
5621 binop( Iop_DivU64, mkexpr( rA ), mkexpr( rB ) ) );
5623 assign( quotientTimesDivisor,
5624 binop( Iop_Mul64,
5625 mkexpr( quotient ),
5626 mkexpr( rB ) ) );
5628 assign( remainder,
5629 binop( Iop_Sub64,
5630 mkexpr( rA ),
5631 mkexpr( quotientTimesDivisor ) ) );
5633 /* Need to match the HW for these special cases
5634 * rB = 0 result all zeros
5636 assign( rB_0, unop( Iop_1Sto64,
5637 binop( Iop_CmpEQ64,
5638 mkexpr( rB ),
5639 mkU64( 0x0 ) ) ) );
5641 assign (rD, binop( Iop_And64,
5642 unop( Iop_Not64, mkexpr( rB_0 ) ),
5643 mkexpr( remainder ) ) );
5644 break;
5647 case 0x10B: // moduw Modulo Unsigned Word
5649 IRTemp quotient = newTemp( Ity_I32 );
5650 IRTemp quotientTimesDivisor = newTemp( Ity_I32 );
5651 IRTemp remainder = newTemp( Ity_I32 );
5653 IRTemp rA = newTemp( Ity_I32 );
5654 IRTemp rB = newTemp( Ity_I32 );
5655 IRTemp rB_0 = newTemp( Ity_I32 ); /* all 1's if rB = 0 */
5657 DIP("moduw r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
5659 if ( ty == Ity_I64 ) {
5660 /* rA and rB are 32 bit values in bits 32:63 of the
5661 * 64-bit register.
5663 assign( rA, unop( Iop_64to32, getIReg( rA_addr ) ) );
5664 assign( rB, unop( Iop_64to32, getIReg( rB_addr ) ) );
5666 } else {
5667 assign( rA, getIReg( rA_addr ) );
5668 assign( rB, getIReg( rB_addr ) );
5671 assign( quotient,
5672 binop( Iop_DivU32, mkexpr( rA ), mkexpr( rB ) ) );
5674 assign( quotientTimesDivisor,
5675 unop( Iop_64to32,
5676 binop( Iop_MullU32,
5677 mkexpr( quotient ),
5678 mkexpr( rB ) ) ) );
5680 assign( remainder,
5681 binop( Iop_Sub32,
5682 mkexpr( rA ),
5683 mkexpr( quotientTimesDivisor ) ) );
5685 /* Need to match the HW for these special cases
5686 * rB = 0 result all zeros
5688 assign( rB_0, unop( Iop_1Sto32,
5689 binop( Iop_CmpEQ32,
5690 mkexpr( rB ),
5691 mkU32( 0x0 ) ) ) );
5693 assign (rD, binop( Iop_32HLto64,
5694 mkU32( 0 ),
5695 binop( Iop_And32,
5696 unop( Iop_Not32, mkexpr( rB_0 ) ),
5697 mkexpr( remainder ) ) ) );
5698 break;
5701 case 0x21A: // cnttzw, cnttzw. Count Trailing Zero Word
5703 /* Note cnttzw RA, RS - RA is dest, RS is source. But the
5704 * order of the operands in theInst is opc1 RS RA opc2 which has
5705 * the operand fields backwards to what the standard order.
5707 UChar rA_address = ifieldRegA(theInstr);
5708 UChar rS_address = ifieldRegDS(theInstr);
5709 IRTemp rA = newTemp(Ity_I64);
5710 IRTemp rS = newTemp(Ity_I64);
5711 UChar flag_rC = ifieldBIT0(theInstr);
5712 IRTemp result = newTemp(Ity_I32);
5714 DIP("cnttzw%s r%u,r%u\n", flag_rC ? "." : "",
5715 rA_address, rS_address);
5717 assign( rS, getIReg( rS_address ) );
5718 assign( result, unop( Iop_Ctz32,
5719 unop( Iop_64to32, mkexpr( rS ) ) ) );
5720 assign( rA, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( result ) ) );
5722 if ( flag_rC )
5723 set_CR0( mkexpr( rA ) );
5725 putIReg( rA_address, mkexpr( rA ) );
5727 return True; /* Return here since this inst is not consistent
5728 * with the other instructions
5731 break;
5733 case 0x23A: // cnttzd, cnttzd. Count Trailing Zero Double word
5735 /* Note cnttzd RA, RS - RA is dest, RS is source. But the
5736 * order of the operands in theInst is opc1 RS RA opc2 which has
5737 * the operand order listed backwards to what is standard.
5739 UChar rA_address = ifieldRegA(theInstr);
5740 UChar rS_address = ifieldRegDS(theInstr);
5741 IRTemp rA = newTemp(Ity_I64);
5742 IRTemp rS = newTemp(Ity_I64);
5743 UChar flag_rC = ifieldBIT0(theInstr);
5745 DIP("cnttzd%s r%u,r%u\n", flag_rC ? "." : "",
5746 rA_address, rS_address);
5748 assign( rS, getIReg( rS_address ) );
5749 assign( rA, unop( Iop_Ctz64, mkexpr( rS ) ) );
5751 if ( flag_rC == 1 )
5752 set_CR0( mkexpr( rA ) );
5754 putIReg( rA_address, mkexpr( rA ) );
5756 return True; /* Return here since this inst is not consistent
5757 * with the other instructions
5760 break;
5762 case 0x309: // modsd Modulo Signed Double Word
5764 IRTemp rA = newTemp( Ity_I64 );
5765 IRTemp rB = newTemp( Ity_I64 );
5766 IRTemp rA2_63 = newTemp( Ity_I64 ); /* all 1's if rA != -2^63 */
5767 IRTemp rB_0 = newTemp( Ity_I1 ); /* 1 if rB = 0 */
5768 IRTemp rB_1 = newTemp( Ity_I1 ); /* 1 if rB = -1 */
5769 IRTemp rA_1 = newTemp( Ity_I1 ); /* 1 if rA = -1 */
5770 IRTemp resultis0 = newTemp( Ity_I64 );
5771 IRTemp resultisF = newTemp( Ity_I64 );
5772 IRTemp quotient = newTemp( Ity_I64 );
5773 IRTemp quotientTimesDivisor = newTemp( Ity_I64 );
5774 IRTemp remainder = newTemp( Ity_I64 );
5775 IRTemp tmp = newTemp( Ity_I64 );
5777 DIP("modsd r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
5779 assign( rA, getIReg( rA_addr ) );
5780 assign( rB, getIReg( rB_addr ) );
5782 assign( rA2_63, unop ( Iop_1Sto64,
5783 binop( Iop_CmpNE64,
5784 mkexpr( rA ),
5785 mkU64( 0x8000000000000000 ) ) ) );
5786 assign( rB_0, binop( Iop_CmpEQ64,
5787 mkexpr( rB ),
5788 mkU64( 0x0 ) ) );
5790 assign( rB_1, binop( Iop_CmpEQ64,
5791 mkexpr( rB ),
5792 mkU64( 0xFFFFFFFFFFFFFFFF ) ) );
5794 assign( rA_1, binop( Iop_CmpEQ64,
5795 mkexpr( rA ),
5796 mkU64( 0xFFFFFFFFFFFFFFFF ) ) );
5798 /* Need to match the HW for these special cases
5799 * rA = -2^31 and rB = -1 result all zeros
5800 * rA = -1 and rB = -1 result all zeros
5801 * rA = -1 and (rB != -1 AND rB != 0) result all 1's
5803 assign( resultis0,
5804 binop( Iop_Or64,
5805 mkexpr( rA2_63 ),
5806 unop ( Iop_1Sto64, mkexpr( rB_1 ) ) ) );
5807 assign( resultisF,
5808 binop( Iop_And64,
5809 unop( Iop_1Sto64, mkexpr( rA_1 ) ),
5810 binop( Iop_And64,
5811 unop( Iop_Not64,
5812 unop( Iop_1Sto64, mkexpr( rB_0 ) ) ),
5813 unop( Iop_Not64,
5814 unop( Iop_1Sto64, mkexpr( rB_1 ) ) )
5815 ) ) );
5817 /* The following remainder computation works as long as
5818 * rA != -2^63 and rB != -1.
5820 assign( quotient,
5821 binop( Iop_DivS64, mkexpr( rA ), mkexpr( rB ) ) );
5823 assign( quotientTimesDivisor,
5824 binop( Iop_Mul64,
5825 mkexpr( quotient ),
5826 mkexpr( rB ) ) );
5828 assign( remainder,
5829 binop( Iop_Sub64,
5830 mkexpr( rA ),
5831 mkexpr( quotientTimesDivisor ) ) );
5833 assign( tmp, binop( Iop_And64,
5834 mkexpr( remainder ),
5835 unop( Iop_Not64,
5836 mkexpr( resultis0 ) ) ) );
5838 assign( rD, binop( Iop_Or64,
5839 binop( Iop_And64,
5840 unop (Iop_Not64,
5841 mkexpr( resultisF ) ),
5842 mkexpr( tmp ) ),
5843 mkexpr( resultisF ) ) );
5844 break;
5846 case 0x30B: // modsw Modulo Signed Word
5848 IRTemp rA = newTemp( Ity_I32 );
5849 IRTemp rB = newTemp( Ity_I32 );
5850 IRTemp rA2_32 = newTemp( Ity_I32 ); /* all 1's if rA = -2^32 */
5851 IRTemp rB_0 = newTemp( Ity_I1 ); /* 1 if rB = 0 */
5852 IRTemp rB_1 = newTemp( Ity_I1 ); /* 1 if rB = -1 */
5853 IRTemp rA_1 = newTemp( Ity_I1 ); /* 1 if rA = -1 */
5854 IRTemp resultis0 = newTemp( Ity_I32 );
5855 IRTemp resultisF = newTemp( Ity_I64 );
5856 IRTemp quotient = newTemp( Ity_I32 );
5857 IRTemp quotientTimesDivisor = newTemp( Ity_I32 );
5858 IRTemp remainder = newTemp( Ity_I32 );
5859 IRTemp tmp = newTemp( Ity_I64 );
5861 DIP("modsw r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
5863 if ( ty == Ity_I64 ) {
5864 /* rA and rB are 32 bit values in bits 32:63 of the
5865 * 64-bit register.
5867 assign( rA, unop(Iop_64to32, getIReg(rA_addr) ) );
5868 assign( rB, unop(Iop_64to32, getIReg(rB_addr) ) );
5870 } else {
5871 assign( rA, getIReg(rA_addr) );
5872 assign( rB, getIReg(rB_addr) );
5875 assign( rA2_32, unop( Iop_1Sto32,
5876 binop( Iop_CmpEQ32,
5877 mkexpr( rA ),
5878 mkU32( 0x80000000 ) ) ) );
5879 /* If the divisor is zero, then the result is undefined.
5880 * However, we will make the result be zero to match what
5881 * the hardware does.
5883 assign( rB_0, binop( Iop_CmpEQ32,
5884 mkexpr( rB ),
5885 mkU32( 0x0 ) ) );
5887 assign( rB_1, binop( Iop_CmpEQ32,
5888 mkexpr( rB ),
5889 mkU32( 0xFFFFFFFF ) ) );
5891 assign( rA_1, binop( Iop_CmpEQ32,
5892 mkexpr( rA ),
5893 mkU32( 0xFFFFFFFF ) ) );
5895 /* Need to match the HW for these special cases
5896 * rA = -2^31 and rB = -1 result all zeros
5897 * rA = -1 and rB = -1 result all zeros
5898 * rA = -1 and (rB != -1 AND rB != 0) result all 1's
5900 assign( resultis0,
5901 binop( Iop_Or32,
5902 unop( Iop_Not32,
5903 binop( Iop_And32,
5904 mkexpr( rA2_32 ),
5905 unop( Iop_1Sto32,
5906 mkexpr( rB_1 ) ) ) ),
5907 binop( Iop_And32,
5908 unop( Iop_1Sto32, mkexpr( rA_1 ) ),
5909 unop( Iop_1Sto32, mkexpr( rB_1 ) ) ) ) );
5910 assign( resultisF,
5911 binop( Iop_And64,
5912 unop( Iop_1Sto64, mkexpr( rA_1 ) ),
5913 binop( Iop_And64,
5914 unop( Iop_Not64,
5915 unop( Iop_1Sto64, mkexpr( rB_0 ) ) ),
5916 unop( Iop_Not64,
5917 unop( Iop_1Sto64, mkexpr( rB_1 ) ) )
5918 ) ) );
5920 /* The following remainder computation works as long as
5921 * rA != -2^31 and rB != -1.
5923 assign( quotient,
5924 binop( Iop_DivS32, mkexpr( rA ), mkexpr( rB ) ) );
5926 assign( quotientTimesDivisor,
5927 unop( Iop_64to32,
5928 binop( Iop_MullS32,
5929 mkexpr( quotient ),
5930 mkexpr( rB ) ) ) );
5932 assign( remainder,
5933 binop( Iop_Sub32,
5934 mkexpr( rA ),
5935 mkexpr( quotientTimesDivisor ) ) );
5937 assign( tmp, binop( Iop_32HLto64,
5938 mkU32( 0 ),
5939 binop( Iop_And32,
5940 mkexpr( remainder ),
5941 unop( Iop_Not32,
5942 mkexpr( resultis0 ) ) ) ) );
5944 assign( rD, binop( Iop_Or64,
5945 binop( Iop_And64,
5946 unop ( Iop_Not64,
5947 mkexpr( resultisF ) ),
5948 mkexpr( tmp ) ),
5949 mkexpr( resultisF ) ) );
5950 break;
5953 default:
5954 vex_printf("dis_modulo_int(ppc)(opc2)\n");
5955 return False;
5957 break;
5959 default:
5960 vex_printf("dis_modulo_int(ppc)(opc1)\n");
5961 return False;
5964 putIReg( rD_addr, mkexpr( rD ) );
5966 return True;
5971 Byte Compare Instructions
5973 static Bool dis_byte_cmp ( UInt theInstr )
5975 /* X-Form */
5976 UChar opc1 = ifieldOPC(theInstr);
5977 UInt opc2 = ifieldOPClo10(theInstr);
5978 UChar rA_addr = ifieldRegA(theInstr);
5979 UChar rB_addr = ifieldRegB(theInstr);
5980 IRTemp rA = newTemp(Ity_I64);
5981 IRTemp rB = newTemp(Ity_I64);
5982 UChar L = toUChar( IFIELD( theInstr, 21, 1 ) );
5983 UChar BF = toUChar( IFIELD( theInstr, 23, 3 ) );
5985 assign( rA, getIReg(rA_addr) );
5986 assign( rB, getIReg(rB_addr) );
5988 if (opc1 != 0x1F) {
5989 vex_printf("dis_byte_cmp(ppc)(opc1)\n");
5990 return False;
5993 switch (opc2) {
5994 case 0xc0: // cmprb (Compare Ranged Byte)
5996 IRExpr *value;
5997 IRExpr *hi_1, *lo_1, *hi_2, *lo_2;
5998 IRExpr *inrange_1, *inrange_2;
6000 DIP("cmprb %u,%u,r%u,r%u\n", BF, L, rA_addr, rB_addr);
6002 hi_1 = binop( Iop_Shr64,
6003 binop( Iop_And64,
6004 mkexpr( rB ),
6005 mkU64( 0xFF000000 ) ),
6006 mkU8( 24 ) );
6007 lo_1 = binop( Iop_Shr64,
6008 binop( Iop_And64,
6009 mkexpr( rB ),
6010 mkU64( 0xFF0000 ) ) ,
6011 mkU8( 16 ) );
6012 hi_2 = binop( Iop_Shr64,
6013 binop( Iop_And64,
6014 mkexpr( rB ),
6015 mkU64( 0xFF00 ) ),
6016 mkU8( 8 ) );
6017 lo_2 = binop( Iop_And64,
6018 mkexpr( rB ),
6019 mkU64( 0xFF ) );
6020 value = binop( Iop_And64,
6021 mkexpr( rA ),
6022 mkU64( 0xFF ) );
6024 inrange_1 = mkAND1( binop( Iop_CmpLE64U, value, hi_1 ),
6025 mkNOT1( binop( Iop_CmpLT64U, value, lo_1 ) ) );
6026 inrange_2 = mkAND1( binop( Iop_CmpLE64U, value, hi_2 ),
6027 mkNOT1( binop( Iop_CmpLT64U, value, lo_2 ) ) );
6029 putGST_field( PPC_GST_CR,
6030 binop( Iop_Shl32,
6031 binop( Iop_Or32,
6032 unop( Iop_1Uto32, inrange_2 ),
6033 binop( Iop_And32,
6034 mkU32 ( L ),
6035 unop( Iop_1Uto32, inrange_1 ) ) ),
6036 mkU8( 2 ) ),
6037 BF );
6039 break;
6041 case 0xE0: // cmpeqb (Compare Equal Byte)
6043 Int i;
6044 IRTemp tmp[9];
6045 IRExpr *value;
6047 DIP("cmpeqb %u,r%u,r%u\n", BF, rA_addr, rB_addr);
6049 value = binop( Iop_And64,
6050 mkexpr( rA ),
6051 mkU64( 0xFF ) );
6053 tmp[0] = newTemp(Ity_I32);
6054 assign( tmp[0], mkU32( 0 ) );
6056 for(i = 0; i < 8; i++) {
6057 tmp[i+1] = newTemp(Ity_I32);
6058 assign( tmp[i+1], binop( Iop_Or32,
6059 unop( Iop_1Uto32,
6060 binop( Iop_CmpEQ64,
6061 value,
6062 binop( Iop_And64,
6063 binop( Iop_Shr64,
6064 mkexpr( rB ),
6065 mkU8( i*8 ) ),
6066 mkU64( 0xFF ) ) ) ),
6067 mkexpr( tmp[i] ) ) );
6070 putGST_field( PPC_GST_CR,
6071 binop( Iop_Shl32,
6072 unop( Iop_1Uto32,
6073 mkNOT1( binop( Iop_CmpEQ32,
6074 mkexpr( tmp[8] ),
6075 mkU32( 0 ) ) ) ),
6076 mkU8( 2 ) ),
6077 BF );
6079 break;
6081 default:
6082 vex_printf("dis_byte_cmp(ppc)(opc2)\n");
6083 return False;
6085 return True;
6089 * Integer Miscellaneous instructions
6091 static Bool dis_int_misc ( UInt theInstr )
6093 Int wc = IFIELD(theInstr, 21, 2);
6094 UChar opc1 = ifieldOPC(theInstr);
6095 UInt opc2 = ifieldOPClo10(theInstr);
6097 if ( opc1 != 0x1F ) {
6098 vex_printf("dis_modulo_int(ppc)(opc1)\n");
6099 return False;
6102 switch (opc2) {
6103 case 0x01E: // wait, (X-from)
6104 DIP("wait %u\n", wc);
6106 /* The wait instruction causes instruction fetching and execution
6107 * to be suspended. Instruction fetching and execution are resumed
6108 * when the events specified by the WC field occur.
6110 * 0b00 Resume instruction fetching and execution when an
6111 * exception or an event-based branch exception occurs,
6112 * or a resume signal from the platform is recieved.
6114 * 0b01 Reserved.
6116 * For our purposes, we will just assume the contition is always
6117 * immediately satisfied.
6119 break;
6120 default:
6121 vex_printf("dis_int_misc(ppc)(opc2)\n");
6122 return False;
6125 return True;
6129 Integer Compare Instructions
6131 static Bool dis_int_cmp ( UInt theInstr )
6133 /* D-Form, X-Form */
6134 UChar opc1 = ifieldOPC(theInstr);
6135 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
6136 UChar b22 = toUChar( IFIELD( theInstr, 22, 1 ) );
6137 UChar flag_L = toUChar( IFIELD( theInstr, 21, 1 ) );
6138 UChar rA_addr = ifieldRegA(theInstr);
6139 UInt uimm16 = ifieldUIMM16(theInstr);
6140 UChar rB_addr = ifieldRegB(theInstr);
6141 UInt opc2 = ifieldOPClo10(theInstr);
6142 UChar b0 = ifieldBIT0(theInstr);
6144 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6145 IRExpr *a = getIReg(rA_addr);
6146 IRExpr *b;
6148 if (!mode64 && flag_L==1) { // L==1 invalid for 32 bit.
6149 vex_printf("dis_int_cmp(ppc)(flag_L)\n");
6150 return False;
6153 if (( b22 != 0 ) && ( opc2 != 0x080 ) ) { // setb case exception
6154 vex_printf("dis_int_cmp(ppc)(b22)\n");
6155 return False;
6158 switch (opc1) {
6159 case 0x0B: // cmpi (Compare Immediate, PPC32 p368)
6160 DIP("cmpi cr%u,%u,r%u,%d\n", crfD, flag_L, rA_addr,
6161 (Int)extend_s_16to32(uimm16));
6162 b = mkSzExtendS16( ty, uimm16 );
6163 if (flag_L == 1) {
6164 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64S, a, b)));
6165 } else {
6166 a = mkNarrowTo32( ty, a );
6167 b = mkNarrowTo32( ty, b );
6168 putCR321(crfD, unop(Iop_32to8, binop(Iop_CmpORD32S, a, b)));
6170 putCR0( crfD, getXER_SO() );
6171 break;
6173 case 0x0A: // cmpli (Compare Logical Immediate, PPC32 p370)
6174 DIP("cmpli cr%u,%u,r%u,0x%x\n", crfD, flag_L, rA_addr, uimm16);
6175 b = mkSzImm( ty, uimm16 );
6176 if (flag_L == 1) {
6177 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64U, a, b)));
6178 } else {
6179 a = mkNarrowTo32( ty, a );
6180 b = mkNarrowTo32( ty, b );
6181 putCR321(crfD, unop(Iop_32to8, binop(Iop_CmpORD32U, a, b)));
6183 putCR0( crfD, getXER_SO() );
6184 break;
6186 /* X Form */
6187 case 0x1F:
6188 if (b0 != 0) {
6189 vex_printf("dis_int_cmp(ppc)(0x1F,b0)\n");
6190 return False;
6192 b = getIReg(rB_addr);
6194 switch (opc2) {
6195 case 0x000: // cmp (Compare, PPC32 p367)
6196 DIP("cmp cr%u,%u,r%u,r%u\n", crfD, flag_L, rA_addr, rB_addr);
6197 /* Comparing a reg with itself produces a result which
6198 doesn't depend on the contents of the reg. Therefore
6199 remove the false dependency, which has been known to cause
6200 memcheck to produce false errors. */
6201 if (rA_addr == rB_addr)
6202 a = b = typeOfIRExpr(irsb->tyenv,a) == Ity_I64
6203 ? mkU64(0) : mkU32(0);
6204 if (flag_L == 1) {
6205 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64S, a, b)));
6206 } else {
6207 a = mkNarrowTo32( ty, a );
6208 b = mkNarrowTo32( ty, b );
6209 putCR321(crfD, unop(Iop_32to8,binop(Iop_CmpORD32S, a, b)));
6211 putCR0( crfD, getXER_SO() );
6212 break;
6214 case 0x020: // cmpl (Compare Logical, PPC32 p369)
6215 DIP("cmpl cr%u,%u,r%u,r%u\n", crfD, flag_L, rA_addr, rB_addr);
6216 /* Comparing a reg with itself produces a result which
6217 doesn't depend on the contents of the reg. Therefore
6218 remove the false dependency, which has been known to cause
6219 memcheck to produce false errors. */
6220 if (rA_addr == rB_addr)
6221 a = b = typeOfIRExpr(irsb->tyenv,a) == Ity_I64
6222 ? mkU64(0) : mkU32(0);
6223 if (flag_L == 1) {
6224 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64U, a, b)));
6225 } else {
6226 a = mkNarrowTo32( ty, a );
6227 b = mkNarrowTo32( ty, b );
6228 putCR321(crfD, unop(Iop_32to8, binop(Iop_CmpORD32U, a, b)));
6230 putCR0( crfD, getXER_SO() );
6231 break;
6233 case 0x080: // setb (Set Boolean)
6235 UChar rT_addr = ifieldRegDS(theInstr);
6236 Int bfa = IFIELD(theInstr, 18, 3);
6237 IRTemp cr = newTemp(Ity_I32);
6238 IRTemp cr0 = newTemp(Ity_I32);
6239 IRTemp cr1 = newTemp(Ity_I32);
6240 IRTemp result = newTemp(Ity_I64);
6242 DIP("setb r%u,%d\n", rT_addr, bfa);
6244 /* Fetch the entire condition code value */
6245 assign( cr, getGST( PPC_GST_CR ) );
6247 /* Get bit zero (IBM numbering) of the CR field specified
6248 * by bfa.
6250 assign( cr0, binop( Iop_And32,
6251 binop( Iop_Shr32,
6252 mkexpr( cr ),
6253 mkU8( (7-bfa)*4 ) ),
6254 mkU32( 0x8 ) ) );
6255 assign( cr1, binop( Iop_And32,
6256 binop( Iop_Shr32,
6257 mkexpr( cr ),
6258 mkU8( (7-bfa)*4 ) ),
6259 mkU32( 0x4 ) ) );
6260 assign( result, binop( Iop_Or64,
6261 unop( Iop_1Sto64,
6262 binop( Iop_CmpEQ32,
6263 mkexpr( cr0 ),
6264 mkU32( 0x8 ) ) ),
6265 binop( Iop_32HLto64,
6266 mkU32( 0 ),
6267 unop( Iop_1Uto32,
6268 binop( Iop_CmpEQ32,
6269 mkexpr( cr1 ),
6270 mkU32( 0x4 ) ) ) ) ) );
6271 if ( ty == Ity_I64 )
6272 putIReg( rT_addr, mkexpr( result ) );
6273 else
6274 putIReg( rT_addr, unop( Iop_64to32, mkexpr(result ) ) );
6276 break;
6277 default:
6278 vex_printf("dis_int_cmp(ppc)(opc2)\n");
6279 return False;
6281 break;
6283 default:
6284 vex_printf("dis_int_cmp(ppc)(opc1)\n");
6285 return False;
6288 return True;
6293 Integer Logical Instructions
6295 static Bool dis_int_logic ( UInt theInstr )
6297 /* D-Form, X-Form */
6298 UChar opc1 = ifieldOPC(theInstr);
6299 UChar rS_addr = ifieldRegDS(theInstr);
6300 UChar rA_addr = ifieldRegA(theInstr);
6301 UInt uimm16 = ifieldUIMM16(theInstr);
6302 UChar rB_addr = ifieldRegB(theInstr);
6303 UInt opc2 = ifieldOPClo10(theInstr);
6304 UChar flag_rC = ifieldBIT0(theInstr);
6306 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6307 IRTemp rS = newTemp(ty);
6308 IRTemp rA = newTemp(ty);
6309 IRTemp rB = newTemp(ty);
6310 IRExpr* irx;
6311 Bool do_rc = False;
6313 assign( rS, getIReg(rS_addr) );
6314 assign( rB, getIReg(rB_addr) );
6316 switch (opc1) {
6317 case 0x1C: // andi. (AND Immediate, PPC32 p358)
6318 DIP("andi. r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
6319 assign( rA, binop( mkSzOp(ty, Iop_And8), mkexpr(rS),
6320 mkSzImm(ty, uimm16)) );
6321 do_rc = True; // Always record to CR
6322 flag_rC = 1;
6323 break;
6325 case 0x1D: // andis. (AND Immediate Shifted, PPC32 p359)
6326 DIP("andis r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
6327 assign( rA, binop( mkSzOp(ty, Iop_And8), mkexpr(rS),
6328 mkSzImm(ty, uimm16 << 16)) );
6329 do_rc = True; // Always record to CR
6330 flag_rC = 1;
6331 break;
6333 case 0x18: // ori (OR Immediate, PPC32 p497)
6334 DIP("ori r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
6335 assign( rA, binop( mkSzOp(ty, Iop_Or8), mkexpr(rS),
6336 mkSzImm(ty, uimm16)) );
6337 break;
6339 case 0x19: // oris (OR Immediate Shifted, PPC32 p498)
6340 DIP("oris r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
6341 assign( rA, binop( mkSzOp(ty, Iop_Or8), mkexpr(rS),
6342 mkSzImm(ty, uimm16 << 16)) );
6343 break;
6345 case 0x1A: // xori (XOR Immediate, PPC32 p550)
6346 DIP("xori r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
6347 assign( rA, binop( mkSzOp(ty, Iop_Xor8), mkexpr(rS),
6348 mkSzImm(ty, uimm16)) );
6349 break;
6351 case 0x1B: // xoris (XOR Immediate Shifted, PPC32 p551)
6352 DIP("xoris r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
6353 assign( rA, binop( mkSzOp(ty, Iop_Xor8), mkexpr(rS),
6354 mkSzImm(ty, uimm16 << 16)) );
6355 break;
6357 /* X Form */
6358 case 0x1F:
6360 opc2 = IFIELD( theInstr, 2, 9 );
6362 switch ( opc2 ) {
6363 case 0x1BD: // extswsli (Extend Sign Word shift left)
6365 /* sh[5] is in bit 1, sh[0:4] is in bits [14:10] of theInstr */
6366 UChar sh = IFIELD( theInstr, 11, 5 ) | (IFIELD(theInstr, 1, 1) << 5);
6367 IRTemp temp = newTemp( ty );
6369 DIP("extswsli%s r%u,r%u,%u\n", flag_rC ? ".":"",
6370 rA_addr, rS_addr, sh);
6372 assign( temp, unop( Iop_32Sto64,
6373 unop( Iop_64to32, mkexpr( rS ) ) ) );
6374 assign( rA, binop( Iop_Shl64, mkexpr( temp ), mkU8( sh ) ) );
6375 putIReg( rA_addr, mkexpr( rA ) );
6377 if ( flag_rC ) {
6378 set_CR0( mkexpr( rA ) );
6380 return True;
6382 default:
6383 break; // drop to next opc2 check
6386 do_rc = True; // All below record to CR, except for where we return at case end.
6388 opc2 = ifieldOPClo10( theInstr );
6390 switch (opc2) {
6391 case 0x01C: // and (AND, PPC32 p356)
6392 DIP("and%s r%u,r%u,r%u\n",
6393 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6394 assign(rA, binop( mkSzOp(ty, Iop_And8),
6395 mkexpr(rS), mkexpr(rB)));
6396 break;
6398 case 0x03C: // andc (AND with Complement, PPC32 p357)
6399 DIP("andc%s r%u,r%u,r%u\n",
6400 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6401 assign(rA, binop( mkSzOp(ty, Iop_And8), mkexpr(rS),
6402 unop( mkSzOp(ty, Iop_Not8),
6403 mkexpr(rB))));
6404 break;
6406 case 0x01A: { // cntlzw (Count Leading Zeros Word, PPC32 p371)
6407 IRExpr* lo32;
6408 if (rB_addr!=0) {
6409 vex_printf("dis_int_logic(ppc)(cntlzw,rB_addr)\n");
6410 return False;
6412 DIP("cntlzw%s r%u,r%u\n",
6413 flag_rC ? ".":"", rA_addr, rS_addr);
6415 // mode64: count in low word only
6416 lo32 = mode64 ? unop(Iop_64to32, mkexpr(rS)) : mkexpr(rS);
6418 // Iop_Clz32 undefined for arg==0, so deal with that case:
6419 irx = binop(Iop_CmpNE32, lo32, mkU32(0));
6420 assign(rA, mkWidenFrom32(ty,
6421 IRExpr_ITE( irx,
6422 unop(Iop_Clz32, lo32),
6423 mkU32(32)),
6424 False));
6426 // TODO: alternatively: assign(rA, verbose_Clz32(rS));
6427 break;
6430 case 0x11C: // eqv (Equivalent, PPC32 p396)
6431 DIP("eqv%s r%u,r%u,r%u\n",
6432 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6433 assign( rA, unop( mkSzOp(ty, Iop_Not8),
6434 binop( mkSzOp(ty, Iop_Xor8),
6435 mkexpr(rS), mkexpr(rB))) );
6436 break;
6438 case 0x3BA: // extsb (Extend Sign Byte, PPC32 p397
6439 if (rB_addr!=0) {
6440 vex_printf("dis_int_logic(ppc)(extsb,rB_addr)\n");
6441 return False;
6443 DIP("extsb%s r%u,r%u\n",
6444 flag_rC ? ".":"", rA_addr, rS_addr);
6445 if (mode64)
6446 assign( rA, unop(Iop_8Sto64, unop(Iop_64to8, mkexpr(rS))) );
6447 else
6448 assign( rA, unop(Iop_8Sto32, unop(Iop_32to8, mkexpr(rS))) );
6449 break;
6451 case 0x39A: // extsh (Extend Sign Half Word, PPC32 p398)
6452 if (rB_addr!=0) {
6453 vex_printf("dis_int_logic(ppc)(extsh,rB_addr)\n");
6454 return False;
6456 DIP("extsh%s r%u,r%u\n",
6457 flag_rC ? ".":"", rA_addr, rS_addr);
6458 if (mode64)
6459 assign( rA, unop(Iop_16Sto64,
6460 unop(Iop_64to16, mkexpr(rS))) );
6461 else
6462 assign( rA, unop(Iop_16Sto32,
6463 unop(Iop_32to16, mkexpr(rS))) );
6464 break;
6466 case 0x1DC: // nand (NAND, PPC32 p492)
6467 DIP("nand%s r%u,r%u,r%u\n",
6468 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6469 assign( rA, unop( mkSzOp(ty, Iop_Not8),
6470 binop( mkSzOp(ty, Iop_And8),
6471 mkexpr(rS), mkexpr(rB))) );
6472 break;
6474 case 0x07C: // nor (NOR, PPC32 p494)
6475 DIP("nor%s r%u,r%u,r%u\n",
6476 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6477 assign( rA, unop( mkSzOp(ty, Iop_Not8),
6478 binop( mkSzOp(ty, Iop_Or8),
6479 mkexpr(rS), mkexpr(rB))) );
6480 break;
6482 case 0x1BC: // or (OR, PPC32 p495)
6483 if ((!flag_rC) && rS_addr == rB_addr) {
6484 DIP("mr r%u,r%u\n", rA_addr, rS_addr);
6485 assign( rA, mkexpr(rS) );
6486 } else {
6487 DIP("or%s r%u,r%u,r%u\n",
6488 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6489 assign( rA, binop( mkSzOp(ty, Iop_Or8),
6490 mkexpr(rS), mkexpr(rB)) );
6492 break;
6494 case 0x19C: // orc (OR with Complement, PPC32 p496)
6495 DIP("orc%s r%u,r%u,r%u\n",
6496 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6497 assign( rA, binop( mkSzOp(ty, Iop_Or8), mkexpr(rS),
6498 unop(mkSzOp(ty, Iop_Not8), mkexpr(rB))));
6499 break;
6501 case 0x13C: // xor (XOR, PPC32 p549)
6502 DIP("xor%s r%u,r%u,r%u\n",
6503 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
6504 assign( rA, binop( mkSzOp(ty, Iop_Xor8),
6505 mkexpr(rS), mkexpr(rB)) );
6506 break;
6509 /* 64bit Integer Logical Instructions */
6510 case 0x3DA: // extsw (Extend Sign Word, PPC64 p430)
6511 if (rB_addr!=0) {
6512 vex_printf("dis_int_logic(ppc)(extsw,rB_addr)\n");
6513 return False;
6515 DIP("extsw%s r%u,r%u\n", flag_rC ? ".":"", rA_addr, rS_addr);
6516 assign(rA, unop(Iop_32Sto64, unop(Iop_64to32, mkexpr(rS))));
6517 break;
6519 case 0x03A: // cntlzd (Count Leading Zeros DWord, PPC64 p401)
6520 if (rB_addr!=0) {
6521 vex_printf("dis_int_logic(ppc)(cntlzd,rB_addr)\n");
6522 return False;
6524 DIP("cntlzd%s r%u,r%u\n",
6525 flag_rC ? ".":"", rA_addr, rS_addr);
6526 // Iop_Clz64 undefined for arg==0, so deal with that case:
6527 irx = binop(Iop_CmpNE64, mkexpr(rS), mkU64(0));
6528 assign(rA, IRExpr_ITE( irx,
6529 unop(Iop_Clz64, mkexpr(rS)),
6530 mkU64(64) ));
6531 // TODO: alternatively: assign(rA, verbose_Clz64(rS));
6532 break;
6534 case 0x1FC: // cmpb (Power6: compare bytes)
6535 DIP("cmpb r%u,r%u,r%u\n", rA_addr, rS_addr, rB_addr);
6537 if (mode64)
6538 assign( rA, unop( Iop_V128to64,
6539 binop( Iop_CmpEQ8x16,
6540 binop( Iop_64HLtoV128, mkU64(0), mkexpr(rS) ),
6541 binop( Iop_64HLtoV128, mkU64(0), mkexpr(rB) )
6542 )) );
6543 else
6544 assign( rA, unop( Iop_V128to32,
6545 binop( Iop_CmpEQ8x16,
6546 unop( Iop_32UtoV128, mkexpr(rS) ),
6547 unop( Iop_32UtoV128, mkexpr(rB) )
6548 )) );
6549 break;
6551 case 0x2DF: { // mftgpr (move floating-point to general purpose register)
6552 IRTemp frB = newTemp(Ity_F64);
6553 DIP("mftgpr r%u,fr%u\n", rS_addr, rB_addr);
6555 assign( frB, getFReg(rB_addr)); // always F64
6556 if (mode64)
6557 assign( rA, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
6558 else
6559 assign( rA, unop( Iop_64to32, unop( Iop_ReinterpF64asI64, mkexpr(frB))) );
6561 putIReg( rS_addr, mkexpr(rA));
6562 return True;
6565 case 0x25F: { // mffgpr (move floating-point from general purpose register)
6566 IRTemp frA = newTemp(Ity_F64);
6567 DIP("mffgpr fr%u,r%u\n", rS_addr, rB_addr);
6569 if (mode64)
6570 assign( frA, unop( Iop_ReinterpI64asF64, mkexpr(rB)) );
6571 else
6572 assign( frA, unop( Iop_ReinterpI64asF64, unop( Iop_32Uto64, mkexpr(rB))) );
6574 putFReg( rS_addr, mkexpr(frA));
6575 return True;
6577 case 0x1FA: // popcntd (population count doubleword
6579 DIP("popcntd r%u,r%u\n", rA_addr, rS_addr);
6580 IRTemp result = gen_POPCOUNT(ty, rS, DWORD);
6581 putIReg( rA_addr, mkexpr(result) );
6582 return True;
6584 case 0x17A: // popcntw (Population Count Words)
6586 DIP("popcntw r%u,r%u\n", rA_addr, rS_addr);
6587 if (mode64) {
6588 IRTemp resultHi, resultLo;
6589 IRTemp argLo = newTemp(Ity_I32);
6590 IRTemp argHi = newTemp(Ity_I32);
6591 assign(argLo, unop(Iop_64to32, mkexpr(rS)));
6592 assign(argHi, unop(Iop_64HIto32, mkexpr(rS)));
6593 resultLo = gen_POPCOUNT(Ity_I32, argLo, WORD);
6594 resultHi = gen_POPCOUNT(Ity_I32, argHi, WORD);
6595 putIReg( rA_addr, binop(Iop_32HLto64, mkexpr(resultHi), mkexpr(resultLo)));
6596 } else {
6597 IRTemp result = gen_POPCOUNT(ty, rS, WORD);
6598 putIReg( rA_addr, mkexpr(result) );
6600 return True;
6602 case 0x7A: // popcntb (Population Count Byte)
6604 DIP("popcntb r%u,r%u\n", rA_addr, rS_addr);
6606 if (mode64) {
6607 IRTemp resultHi, resultLo;
6608 IRTemp argLo = newTemp(Ity_I32);
6609 IRTemp argHi = newTemp(Ity_I32);
6610 assign(argLo, unop(Iop_64to32, mkexpr(rS)));
6611 assign(argHi, unop(Iop_64HIto32, mkexpr(rS)));
6612 resultLo = gen_POPCOUNT(Ity_I32, argLo, BYTE);
6613 resultHi = gen_POPCOUNT(Ity_I32, argHi, BYTE);
6614 putIReg( rA_addr, binop(Iop_32HLto64, mkexpr(resultHi),
6615 mkexpr(resultLo)));
6616 } else {
6617 IRTemp result = gen_POPCOUNT(ty, rS, BYTE);
6618 putIReg( rA_addr, mkexpr(result) );
6620 return True;
6622 case 0x0FC: // bpermd (Bit Permute Doubleword)
6624 /* This is a lot of rigmarole to emulate bpermd like this, as it
6625 * could be done much faster by implementing a call to the native
6626 * instruction. However, where possible I want to avoid using new
6627 * native instructions so that we can use valgrind to emulate those
6628 * instructions on older PPC64 hardware.
6630 #define BPERMD_IDX_MASK 0x00000000000000FFULL
6631 #define BPERMD_BIT_MASK 0x8000000000000000ULL
6632 int i;
6633 IRExpr * rS_expr = mkexpr(rS);
6634 IRExpr * res = binop(Iop_And64, mkU64(0), mkU64(0));
6635 DIP("bpermd r%u,r%u,r%u\n", rA_addr, rS_addr, rB_addr);
6636 for (i = 0; i < 8; i++) {
6637 IRTemp idx_tmp = newTemp( Ity_I64 );
6638 IRTemp perm_bit = newTemp( Ity_I64 );
6639 IRTemp idx = newTemp( Ity_I8 );
6640 IRTemp idx_LT64 = newTemp( Ity_I1 );
6641 IRTemp idx_LT64_ity64 = newTemp( Ity_I64 );
6643 assign( idx_tmp,
6644 binop( Iop_And64, mkU64( BPERMD_IDX_MASK ), rS_expr ) );
6645 assign( idx_LT64,
6646 binop( Iop_CmpLT64U, mkexpr( idx_tmp ), mkU64( 64 ) ) );
6647 assign( idx,
6648 binop( Iop_And8,
6649 unop( Iop_1Sto8,
6650 mkexpr(idx_LT64) ),
6651 unop( Iop_64to8, mkexpr( idx_tmp ) ) ) );
6652 /* If idx_LT64 == 0, we must force the perm bit to '0'. Below, we se idx
6653 * to determine which bit of rB to use for the perm bit, and then we shift
6654 * that bit to the MSB position. We AND that with a 64-bit-ized idx_LT64
6655 * to set the final perm bit.
6657 assign( idx_LT64_ity64,
6658 unop( Iop_32Uto64, unop( Iop_1Uto32, mkexpr(idx_LT64 ) ) ) );
6659 assign( perm_bit,
6660 binop( Iop_And64,
6661 mkexpr( idx_LT64_ity64 ),
6662 binop( Iop_Shr64,
6663 binop( Iop_And64,
6664 mkU64( BPERMD_BIT_MASK ),
6665 binop( Iop_Shl64,
6666 mkexpr( rB ),
6667 mkexpr( idx ) ) ),
6668 mkU8( 63 ) ) ) );
6669 res = binop( Iop_Or64,
6670 res,
6671 binop( Iop_Shl64,
6672 mkexpr( perm_bit ),
6673 mkU8( i ) ) );
6674 rS_expr = binop( Iop_Shr64, rS_expr, mkU8( 8 ) );
6676 putIReg(rA_addr, res);
6677 return True;
6680 default:
6681 vex_printf("dis_int_logic(ppc)(opc2)\n");
6682 return False;
6684 break;
6686 default:
6687 vex_printf("dis_int_logic(ppc)(opc1)\n");
6688 return False;
6691 putIReg( rA_addr, mkexpr(rA) );
6693 if (do_rc && flag_rC) {
6694 set_CR0( mkexpr(rA) );
6696 return True;
6700 Integer Parity Instructions
6702 static Bool dis_int_parity ( UInt theInstr )
6704 /* X-Form */
6705 UChar opc1 = ifieldOPC(theInstr);
6706 UChar rS_addr = ifieldRegDS(theInstr);
6707 UChar rA_addr = ifieldRegA(theInstr);
6708 UChar rB_addr = ifieldRegB(theInstr);
6709 UInt opc2 = ifieldOPClo10(theInstr);
6710 UChar b0 = ifieldBIT0(theInstr);
6711 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6713 IRTemp rS = newTemp(ty);
6714 IRTemp rA = newTemp(ty);
6715 IRTemp iTot1 = newTemp(Ity_I32);
6716 IRTemp iTot2 = newTemp(Ity_I32);
6717 IRTemp iTot3 = newTemp(Ity_I32);
6718 IRTemp iTot4 = newTemp(Ity_I32);
6719 IRTemp iTot5 = newTemp(Ity_I32);
6720 IRTemp iTot6 = newTemp(Ity_I32);
6721 IRTemp iTot7 = newTemp(Ity_I32);
6722 IRTemp iTot8 = newTemp(Ity_I32);
6723 IRTemp rS1 = newTemp(ty);
6724 IRTemp rS2 = newTemp(ty);
6725 IRTemp rS3 = newTemp(ty);
6726 IRTemp rS4 = newTemp(ty);
6727 IRTemp rS5 = newTemp(ty);
6728 IRTemp rS6 = newTemp(ty);
6729 IRTemp rS7 = newTemp(ty);
6730 IRTemp iHi = newTemp(Ity_I32);
6731 IRTemp iLo = newTemp(Ity_I32);
6732 IROp to_bit = (mode64 ? Iop_64to1 : Iop_32to1);
6733 IROp shr_op = (mode64 ? Iop_Shr64 : Iop_Shr32);
6735 if (opc1 != 0x1f || rB_addr || b0) {
6736 vex_printf("dis_int_parity(ppc)(0x1F,opc1:rB|b0)\n");
6737 return False;
6740 assign( rS, getIReg(rS_addr) );
6742 switch (opc2) {
6743 case 0xba: // prtyd (Parity Doubleword, ISA 2.05 p320)
6744 DIP("prtyd r%u,r%u\n", rA_addr, rS_addr);
6745 assign( iTot1, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS))) );
6746 assign( rS1, binop(shr_op, mkexpr(rS), mkU8(8)) );
6747 assign( iTot2, binop(Iop_Add32,
6748 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS1))),
6749 mkexpr(iTot1)) );
6750 assign( rS2, binop(shr_op, mkexpr(rS1), mkU8(8)) );
6751 assign( iTot3, binop(Iop_Add32,
6752 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS2))),
6753 mkexpr(iTot2)) );
6754 assign( rS3, binop(shr_op, mkexpr(rS2), mkU8(8)) );
6755 assign( iTot4, binop(Iop_Add32,
6756 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS3))),
6757 mkexpr(iTot3)) );
6758 if (mode64) {
6759 assign( rS4, binop(shr_op, mkexpr(rS3), mkU8(8)) );
6760 assign( iTot5, binop(Iop_Add32,
6761 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS4))),
6762 mkexpr(iTot4)) );
6763 assign( rS5, binop(shr_op, mkexpr(rS4), mkU8(8)) );
6764 assign( iTot6, binop(Iop_Add32,
6765 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS5))),
6766 mkexpr(iTot5)) );
6767 assign( rS6, binop(shr_op, mkexpr(rS5), mkU8(8)) );
6768 assign( iTot7, binop(Iop_Add32,
6769 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS6))),
6770 mkexpr(iTot6)) );
6771 assign( rS7, binop(shr_op, mkexpr(rS6), mkU8(8)) );
6772 assign( iTot8, binop(Iop_Add32,
6773 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS7))),
6774 mkexpr(iTot7)) );
6775 assign( rA, unop(Iop_32Uto64,
6776 binop(Iop_And32, mkexpr(iTot8), mkU32(1))) );
6777 } else
6778 assign( rA, mkexpr(iTot4) );
6780 break;
6781 case 0x9a: // prtyw (Parity Word, ISA 2.05 p320)
6782 assign( iTot1, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS))) );
6783 assign( rS1, binop(shr_op, mkexpr(rS), mkU8(8)) );
6784 assign( iTot2, binop(Iop_Add32,
6785 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS1))),
6786 mkexpr(iTot1)) );
6787 assign( rS2, binop(shr_op, mkexpr(rS1), mkU8(8)) );
6788 assign( iTot3, binop(Iop_Add32,
6789 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS2))),
6790 mkexpr(iTot2)) );
6791 assign( rS3, binop(shr_op, mkexpr(rS2), mkU8(8)) );
6792 assign( iTot4, binop(Iop_Add32,
6793 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS3))),
6794 mkexpr(iTot3)) );
6795 assign( iLo, unop(Iop_1Uto32, unop(Iop_32to1, mkexpr(iTot4) )) );
6797 if (mode64) {
6798 assign( rS4, binop(shr_op, mkexpr(rS3), mkU8(8)) );
6799 assign( iTot5, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS4))) );
6800 assign( rS5, binop(shr_op, mkexpr(rS4), mkU8(8)) );
6801 assign( iTot6, binop(Iop_Add32,
6802 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS5))),
6803 mkexpr(iTot5)) );
6804 assign( rS6, binop(shr_op, mkexpr(rS5), mkU8(8)) );
6805 assign( iTot7, binop(Iop_Add32,
6806 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS6))),
6807 mkexpr(iTot6)) );
6808 assign( rS7, binop(shr_op, mkexpr(rS6), mkU8(8)));
6809 assign( iTot8, binop(Iop_Add32,
6810 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS7))),
6811 mkexpr(iTot7)) );
6812 assign( iHi, binop(Iop_And32, mkU32(1), mkexpr(iTot8)) ),
6813 assign( rA, binop(Iop_32HLto64, mkexpr(iHi), mkexpr(iLo)) );
6814 } else
6815 assign( rA, binop(Iop_Or32, mkU32(0), mkexpr(iLo)) );
6816 break;
6817 default:
6818 vex_printf("dis_int_parity(ppc)(opc2)\n");
6819 return False;
6822 putIReg( rA_addr, mkexpr(rA) );
6824 return True;
6829 Integer Rotate Instructions
6831 static Bool dis_int_rot ( UInt theInstr )
6833 /* M-Form, MDS-Form */
6834 UChar opc1 = ifieldOPC(theInstr);
6835 UChar rS_addr = ifieldRegDS(theInstr);
6836 UChar rA_addr = ifieldRegA(theInstr);
6837 UChar rB_addr = ifieldRegB(theInstr);
6838 UChar sh_imm = rB_addr;
6839 UChar MaskBeg = toUChar( IFIELD( theInstr, 6, 5 ) );
6840 UChar MaskEnd = toUChar( IFIELD( theInstr, 1, 5 ) );
6841 UChar msk_imm = toUChar( IFIELD( theInstr, 5, 6 ) );
6842 UChar opc2 = toUChar( IFIELD( theInstr, 2, 3 ) );
6843 UChar b1 = ifieldBIT1(theInstr);
6844 UChar flag_rC = ifieldBIT0(theInstr);
6846 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6847 IRTemp rS = newTemp(ty);
6848 IRTemp rA = newTemp(ty);
6849 IRTemp rB = newTemp(ty);
6850 IRTemp rot = newTemp(ty);
6851 IRExpr *r;
6852 UInt mask32;
6853 ULong mask64;
6855 assign( rS, getIReg(rS_addr) );
6856 assign( rB, getIReg(rB_addr) );
6858 switch (opc1) {
6859 case 0x14: {
6860 // rlwimi (Rotate Left Word Imm then Mask Insert, PPC32 p500)
6861 DIP("rlwimi%s r%u,r%u,%d,%d,%d\n", flag_rC ? ".":"",
6862 rA_addr, rS_addr, sh_imm, MaskBeg, MaskEnd);
6863 if (mode64) {
6864 // tmp32 = (ROTL(rS_Lo32, Imm)
6865 // rA = ((tmp32 || tmp32) & mask64) | (rA & ~mask64)
6866 mask64 = MASK64(31-MaskEnd, 31-MaskBeg);
6867 r = ROTL( unop(Iop_64to32, mkexpr(rS) ), mkU8(sh_imm) );
6868 r = unop(Iop_32Uto64, r);
6869 assign( rot, binop(Iop_Or64, r,
6870 binop(Iop_Shl64, r, mkU8(32))) );
6871 assign( rA,
6872 binop(Iop_Or64,
6873 binop(Iop_And64, mkexpr(rot), mkU64(mask64)),
6874 binop(Iop_And64, getIReg(rA_addr), mkU64(~mask64))) );
6876 else {
6877 // rA = (ROTL(rS, Imm) & mask) | (rA & ~mask);
6878 mask32 = MASK32(31-MaskEnd, 31-MaskBeg);
6879 r = ROTL(mkexpr(rS), mkU8(sh_imm));
6880 assign( rA,
6881 binop(Iop_Or32,
6882 binop(Iop_And32, mkU32(mask32), r),
6883 binop(Iop_And32, getIReg(rA_addr), mkU32(~mask32))) );
6885 break;
6888 case 0x15: {
6889 // rlwinm (Rotate Left Word Imm then AND with Mask, PPC32 p501)
6890 vassert(MaskBeg < 32);
6891 vassert(MaskEnd < 32);
6892 vassert(sh_imm < 32);
6894 if (mode64) {
6895 IRTemp rTmp = newTemp(Ity_I64);
6896 mask64 = MASK64(31-MaskEnd, 31-MaskBeg);
6897 DIP("rlwinm%s r%u,r%u,%d,%d,%d\n", flag_rC ? ".":"",
6898 rA_addr, rS_addr, sh_imm, MaskBeg, MaskEnd);
6899 // tmp32 = (ROTL(rS_Lo32, Imm)
6900 // rA = ((tmp32 || tmp32) & mask64)
6901 r = ROTL( unop(Iop_64to32, mkexpr(rS) ), mkU8(sh_imm) );
6902 r = unop(Iop_32Uto64, r);
6903 assign( rTmp, r );
6904 r = NULL;
6905 assign( rot, binop(Iop_Or64, mkexpr(rTmp),
6906 binop(Iop_Shl64, mkexpr(rTmp), mkU8(32))) );
6907 assign( rA, binop(Iop_And64, mkexpr(rot), mkU64(mask64)) );
6909 else {
6910 if (MaskBeg == 0 && sh_imm+MaskEnd == 31) {
6911 /* Special-case the ,n,0,31-n form as that is just n-bit
6912 shift left, PPC32 p501 */
6913 DIP("slwi%s r%u,r%u,%d\n", flag_rC ? ".":"",
6914 rA_addr, rS_addr, sh_imm);
6915 assign( rA, binop(Iop_Shl32, mkexpr(rS), mkU8(sh_imm)) );
6917 else if (MaskEnd == 31 && sh_imm+MaskBeg == 32) {
6918 /* Special-case the ,32-n,n,31 form as that is just n-bit
6919 unsigned shift right, PPC32 p501 */
6920 DIP("srwi%s r%u,r%u,%d\n", flag_rC ? ".":"",
6921 rA_addr, rS_addr, MaskBeg);
6922 assign( rA, binop(Iop_Shr32, mkexpr(rS), mkU8(MaskBeg)) );
6924 else {
6925 /* General case. */
6926 mask32 = MASK32(31-MaskEnd, 31-MaskBeg);
6927 DIP("rlwinm%s r%u,r%u,%d,%d,%d\n", flag_rC ? ".":"",
6928 rA_addr, rS_addr, sh_imm, MaskBeg, MaskEnd);
6929 // rA = ROTL(rS, Imm) & mask
6930 assign( rA, binop(Iop_And32,
6931 ROTL(mkexpr(rS), mkU8(sh_imm)),
6932 mkU32(mask32)) );
6935 break;
6938 case 0x17: {
6939 // rlwnm (Rotate Left Word then AND with Mask, PPC32 p503
6940 DIP("rlwnm%s r%u,r%u,r%u,%d,%d\n", flag_rC ? ".":"",
6941 rA_addr, rS_addr, rB_addr, MaskBeg, MaskEnd);
6942 if (mode64) {
6943 mask64 = MASK64(31-MaskEnd, 31-MaskBeg);
6944 /* weird insn alert!
6945 tmp32 = (ROTL(rS_Lo32, rB[0-4])
6946 rA = ((tmp32 || tmp32) & mask64)
6948 // note, ROTL does the masking, so we don't do it here
6949 r = ROTL( unop(Iop_64to32, mkexpr(rS)),
6950 unop(Iop_64to8, mkexpr(rB)) );
6951 r = unop(Iop_32Uto64, r);
6952 assign(rot, binop(Iop_Or64, r, binop(Iop_Shl64, r, mkU8(32))));
6953 assign( rA, binop(Iop_And64, mkexpr(rot), mkU64(mask64)) );
6954 } else {
6955 mask32 = MASK32(31-MaskEnd, 31-MaskBeg);
6956 // rA = ROTL(rS, rB[0-4]) & mask
6957 // note, ROTL does the masking, so we don't do it here
6958 assign( rA, binop(Iop_And32,
6959 ROTL(mkexpr(rS),
6960 unop(Iop_32to8, mkexpr(rB))),
6961 mkU32(mask32)) );
6963 break;
6966 /* 64bit Integer Rotates */
6967 case 0x1E: {
6968 msk_imm = ((msk_imm & 1) << 5) | (msk_imm >> 1);
6969 sh_imm |= b1 << 5;
6971 vassert( msk_imm < 64 );
6972 vassert( sh_imm < 64 );
6974 switch (opc2) {
6975 case 0x4: {
6976 /* r = ROTL64( rS, rB_lo6) */
6977 r = ROTL( mkexpr(rS), unop(Iop_64to8, mkexpr(rB)) );
6979 if (b1 == 0) { // rldcl (Rotl DWord, Clear Left, PPC64 p555)
6980 DIP("rldcl%s r%u,r%u,r%u,%u\n", flag_rC ? ".":"",
6981 rA_addr, rS_addr, rB_addr, msk_imm);
6982 // note, ROTL does the masking, so we don't do it here
6983 mask64 = MASK64(0, 63-msk_imm);
6984 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
6985 break;
6986 } else { // rldcr (Rotl DWord, Clear Right, PPC64 p556)
6987 DIP("rldcr%s r%u,r%u,r%u,%u\n", flag_rC ? ".":"",
6988 rA_addr, rS_addr, rB_addr, msk_imm);
6989 mask64 = MASK64(63-msk_imm, 63);
6990 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
6991 break;
6993 break;
6995 case 0x2: // rldic (Rotl DWord Imm, Clear, PPC64 p557)
6996 DIP("rldic%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
6997 rA_addr, rS_addr, sh_imm, msk_imm);
6998 r = ROTL(mkexpr(rS), mkU8(sh_imm));
6999 mask64 = MASK64(sh_imm, 63-msk_imm);
7000 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
7001 break;
7002 // later: deal with special case: (msk_imm==0) => SHL(sh_imm)
7004 Hmm... looks like this'll do the job more simply:
7005 r = SHL(rS, sh_imm)
7006 m = ~(1 << (63-msk_imm))
7007 assign(rA, r & m);
7010 case 0x0: // rldicl (Rotl DWord Imm, Clear Left, PPC64 p558)
7011 if (mode64
7012 && sh_imm + msk_imm == 64 && msk_imm >= 1 && msk_imm <= 63) {
7013 /* special-case the ,64-n,n form as that is just
7014 unsigned shift-right by n */
7015 DIP("srdi%s r%u,r%u,%u\n",
7016 flag_rC ? ".":"", rA_addr, rS_addr, msk_imm);
7017 assign( rA, binop(Iop_Shr64, mkexpr(rS), mkU8(msk_imm)) );
7018 } else {
7019 DIP("rldicl%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
7020 rA_addr, rS_addr, sh_imm, msk_imm);
7021 r = ROTL(mkexpr(rS), mkU8(sh_imm));
7022 mask64 = MASK64(0, 63-msk_imm);
7023 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
7025 break;
7027 case 0x1: // rldicr (Rotl DWord Imm, Clear Right, PPC64 p559)
7028 if (mode64
7029 && sh_imm + msk_imm == 63 && sh_imm >= 1 && sh_imm <= 63) {
7030 /* special-case the ,n,63-n form as that is just
7031 shift-left by n */
7032 DIP("sldi%s r%u,r%u,%u\n",
7033 flag_rC ? ".":"", rA_addr, rS_addr, sh_imm);
7034 assign( rA, binop(Iop_Shl64, mkexpr(rS), mkU8(sh_imm)) );
7035 } else {
7036 DIP("rldicr%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
7037 rA_addr, rS_addr, sh_imm, msk_imm);
7038 r = ROTL(mkexpr(rS), mkU8(sh_imm));
7039 mask64 = MASK64(63-msk_imm, 63);
7040 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
7042 break;
7044 case 0x3: { // rldimi (Rotl DWord Imm, Mask Insert, PPC64 p560)
7045 IRTemp rA_orig = newTemp(ty);
7046 DIP("rldimi%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
7047 rA_addr, rS_addr, sh_imm, msk_imm);
7048 r = ROTL(mkexpr(rS), mkU8(sh_imm));
7049 mask64 = MASK64(sh_imm, 63-msk_imm);
7050 assign( rA_orig, getIReg(rA_addr) );
7051 assign( rA, binop(Iop_Or64,
7052 binop(Iop_And64, mkU64(mask64), r),
7053 binop(Iop_And64, mkU64(~mask64),
7054 mkexpr(rA_orig))) );
7055 break;
7057 default:
7058 vex_printf("dis_int_rot(ppc)(opc2)\n");
7059 return False;
7061 break;
7064 default:
7065 vex_printf("dis_int_rot(ppc)(opc1)\n");
7066 return False;
7069 putIReg( rA_addr, mkexpr(rA) );
7071 if (flag_rC) {
7072 set_CR0( mkexpr(rA) );
7074 return True;
7079 Integer Load Instructions
7081 static Bool dis_int_load ( UInt theInstr )
7083 /* D-Form, X-Form, DS-Form */
7084 UChar opc1 = ifieldOPC(theInstr);
7085 UChar rD_addr = ifieldRegDS(theInstr);
7086 UChar rA_addr = ifieldRegA(theInstr);
7087 UInt uimm16 = ifieldUIMM16(theInstr);
7088 UChar rB_addr = ifieldRegB(theInstr);
7089 UInt opc2 = ifieldOPClo10(theInstr);
7090 UChar b1 = ifieldBIT1(theInstr);
7091 UChar b0 = ifieldBIT0(theInstr);
7093 Int simm16 = extend_s_16to32(uimm16);
7094 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7095 IRTemp EA = newTemp(ty);
7096 IRExpr* val;
7098 switch (opc1) {
7099 case 0x1F: // register offset
7100 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
7101 break;
7102 case 0x38: // immediate offset: 64bit: lq: maskoff
7103 // lowest 4 bits of immediate before forming EA
7104 simm16 = simm16 & 0xFFFFFFF0;
7105 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
7106 break;
7107 case 0x3A: // immediate offset: 64bit: ld/ldu/lwa: mask off
7108 // lowest 2 bits of immediate before forming EA
7109 simm16 = simm16 & 0xFFFFFFFC;
7110 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
7111 break;
7112 default: // immediate offset
7113 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
7114 break;
7117 switch (opc1) {
7118 case 0x22: // lbz (Load B & Zero, PPC32 p433)
7119 DIP("lbz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7120 val = load(Ity_I8, mkexpr(EA));
7121 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
7122 break;
7124 case 0x23: // lbzu (Load B & Zero, Update, PPC32 p434)
7125 if (rA_addr == 0 || rA_addr == rD_addr) {
7126 vex_printf("dis_int_load(ppc)(lbzu,rA_addr|rD_addr)\n");
7127 return False;
7129 DIP("lbzu r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7130 val = load(Ity_I8, mkexpr(EA));
7131 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
7132 putIReg( rA_addr, mkexpr(EA) );
7133 break;
7135 case 0x2A: // lha (Load HW Alg, PPC32 p445)
7136 DIP("lha r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7137 val = load(Ity_I16, mkexpr(EA));
7138 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
7139 break;
7141 case 0x2B: // lhau (Load HW Alg, Update, PPC32 p446)
7142 if (rA_addr == 0 || rA_addr == rD_addr) {
7143 vex_printf("dis_int_load(ppc)(lhau,rA_addr|rD_addr)\n");
7144 return False;
7146 DIP("lhau r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7147 val = load(Ity_I16, mkexpr(EA));
7148 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
7149 putIReg( rA_addr, mkexpr(EA) );
7150 break;
7152 case 0x28: // lhz (Load HW & Zero, PPC32 p450)
7153 DIP("lhz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7154 val = load(Ity_I16, mkexpr(EA));
7155 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
7156 break;
7158 case 0x29: // lhzu (Load HW & and Zero, Update, PPC32 p451)
7159 if (rA_addr == 0 || rA_addr == rD_addr) {
7160 vex_printf("dis_int_load(ppc)(lhzu,rA_addr|rD_addr)\n");
7161 return False;
7163 DIP("lhzu r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7164 val = load(Ity_I16, mkexpr(EA));
7165 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
7166 putIReg( rA_addr, mkexpr(EA) );
7167 break;
7169 case 0x20: // lwz (Load W & Zero, PPC32 p460)
7170 DIP("lwz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7171 val = load(Ity_I32, mkexpr(EA));
7172 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
7173 break;
7175 case 0x21: // lwzu (Load W & Zero, Update, PPC32 p461))
7176 if (rA_addr == 0 || rA_addr == rD_addr) {
7177 vex_printf("dis_int_load(ppc)(lwzu,rA_addr|rD_addr)\n");
7178 return False;
7180 DIP("lwzu r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
7181 val = load(Ity_I32, mkexpr(EA));
7182 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
7183 putIReg( rA_addr, mkexpr(EA) );
7184 break;
7186 /* X Form */
7187 case 0x1F:
7188 if (b0 != 0) {
7189 vex_printf("dis_int_load(ppc)(Ox1F,b0)\n");
7190 return False;
7193 switch (opc2) {
7194 case 0x077: // lbzux (Load B & Zero, Update Indexed, PPC32 p435)
7195 DIP("lbzux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7196 if (rA_addr == 0 || rA_addr == rD_addr) {
7197 vex_printf("dis_int_load(ppc)(lwzux,rA_addr|rD_addr)\n");
7198 return False;
7200 val = load(Ity_I8, mkexpr(EA));
7201 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
7202 putIReg( rA_addr, mkexpr(EA) );
7203 break;
7205 case 0x057: // lbzx (Load B & Zero, Indexed, PPC32 p436)
7206 DIP("lbzx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7207 val = load(Ity_I8, mkexpr(EA));
7208 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
7209 break;
7211 case 0x177: // lhaux (Load HW Alg, Update Indexed, PPC32 p447)
7212 if (rA_addr == 0 || rA_addr == rD_addr) {
7213 vex_printf("dis_int_load(ppc)(lhaux,rA_addr|rD_addr)\n");
7214 return False;
7216 DIP("lhaux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7217 val = load(Ity_I16, mkexpr(EA));
7218 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
7219 putIReg( rA_addr, mkexpr(EA) );
7220 break;
7222 case 0x157: // lhax (Load HW Alg, Indexed, PPC32 p448)
7223 DIP("lhax r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7224 val = load(Ity_I16, mkexpr(EA));
7225 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
7226 break;
7228 case 0x137: // lhzux (Load HW & Zero, Update Indexed, PPC32 p452)
7229 if (rA_addr == 0 || rA_addr == rD_addr) {
7230 vex_printf("dis_int_load(ppc)(lhzux,rA_addr|rD_addr)\n");
7231 return False;
7233 DIP("lhzux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7234 val = load(Ity_I16, mkexpr(EA));
7235 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
7236 putIReg( rA_addr, mkexpr(EA) );
7237 break;
7239 case 0x117: // lhzx (Load HW & Zero, Indexed, PPC32 p453)
7240 DIP("lhzx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7241 val = load(Ity_I16, mkexpr(EA));
7242 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
7243 break;
7245 case 0x037: // lwzux (Load W & Zero, Update Indexed, PPC32 p462)
7246 if (rA_addr == 0 || rA_addr == rD_addr) {
7247 vex_printf("dis_int_load(ppc)(lwzux,rA_addr|rD_addr)\n");
7248 return False;
7250 DIP("lwzux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7251 val = load(Ity_I32, mkexpr(EA));
7252 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
7253 putIReg( rA_addr, mkexpr(EA) );
7254 break;
7256 case 0x017: // lwzx (Load W & Zero, Indexed, PPC32 p463)
7257 DIP("lwzx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7258 val = load(Ity_I32, mkexpr(EA));
7259 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
7260 break;
7263 /* 64bit Loads */
7264 case 0x035: // ldux (Load DWord, Update Indexed, PPC64 p475)
7265 if (rA_addr == 0 || rA_addr == rD_addr) {
7266 vex_printf("dis_int_load(ppc)(ldux,rA_addr|rD_addr)\n");
7267 return False;
7269 DIP("ldux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7270 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
7271 putIReg( rA_addr, mkexpr(EA) );
7272 break;
7274 case 0x015: // ldx (Load DWord, Indexed, PPC64 p476)
7275 DIP("ldx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7276 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
7277 break;
7279 case 0x175: // lwaux (Load W Alg, Update Indexed, PPC64 p501)
7280 if (rA_addr == 0 || rA_addr == rD_addr) {
7281 vex_printf("dis_int_load(ppc)(lwaux,rA_addr|rD_addr)\n");
7282 return False;
7284 DIP("lwaux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7285 putIReg( rD_addr,
7286 unop(Iop_32Sto64, load(Ity_I32, mkexpr(EA))) );
7287 putIReg( rA_addr, mkexpr(EA) );
7288 break;
7290 case 0x155: // lwax (Load W Alg, Indexed, PPC64 p502)
7291 DIP("lwax r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7292 putIReg( rD_addr,
7293 unop(Iop_32Sto64, load(Ity_I32, mkexpr(EA))) );
7294 break;
7296 default:
7297 vex_printf("dis_int_load(ppc)(opc2)\n");
7298 return False;
7300 break;
7302 /* DS Form - 64bit Loads. In each case EA will have been formed
7303 with the lowest 2 bits masked off the immediate offset. */
7304 case 0x3A:
7305 switch ((b1<<1) | b0) {
7306 case 0x0: // ld (Load DWord, PPC64 p472)
7307 DIP("ld r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
7308 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
7309 break;
7311 case 0x1: // ldu (Load DWord, Update, PPC64 p474)
7312 if (rA_addr == 0 || rA_addr == rD_addr) {
7313 vex_printf("dis_int_load(ppc)(ldu,rA_addr|rD_addr)\n");
7314 return False;
7316 DIP("ldu r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
7317 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
7318 putIReg( rA_addr, mkexpr(EA) );
7319 break;
7321 case 0x2: // lwa (Load Word Alg, PPC64 p499)
7322 DIP("lwa r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
7323 putIReg( rD_addr,
7324 unop(Iop_32Sto64, load(Ity_I32, mkexpr(EA))) );
7325 break;
7327 default:
7328 vex_printf("dis_int_load(ppc)(0x3A, opc2)\n");
7329 return False;
7331 break;
7333 case 0x38: {
7334 IRTemp high = newTemp(ty);
7335 IRTemp low = newTemp(ty);
7336 /* DQ Form - 128bit Loads. Lowest bits [1:0] are the PT field. */
7337 DIP("lq r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
7338 /* NOTE: there are some changes to XER[41:42] that have not been
7339 * implemented.
7341 // trap if EA misaligned on 16 byte address
7342 if (mode64) {
7343 if (host_endness == VexEndnessBE) {
7344 assign(high, load(ty, mkexpr( EA ) ) );
7345 assign(low, load(ty, binop( Iop_Add64,
7346 mkexpr( EA ),
7347 mkU64( 8 ) ) ) );
7348 } else {
7349 assign(low, load(ty, mkexpr( EA ) ) );
7350 assign(high, load(ty, binop( Iop_Add64,
7351 mkexpr( EA ),
7352 mkU64( 8 ) ) ) );
7354 } else {
7355 assign(high, load(ty, binop( Iop_Add32,
7356 mkexpr( EA ),
7357 mkU32( 4 ) ) ) );
7358 assign(low, load(ty, binop( Iop_Add32,
7359 mkexpr( EA ),
7360 mkU32( 12 ) ) ) );
7362 gen_SIGBUS_if_misaligned( EA, 16 );
7363 putIReg( rD_addr, mkexpr( high) );
7364 putIReg( rD_addr+1, mkexpr( low) );
7365 break;
7367 default:
7368 vex_printf("dis_int_load(ppc)(opc1)\n");
7369 return False;
7371 return True;
7377 Integer Store Instructions
7379 static Bool dis_int_store ( UInt theInstr, const VexAbiInfo* vbi )
7381 /* D-Form, X-Form, DS-Form */
7382 UChar opc1 = ifieldOPC(theInstr);
7383 UInt rS_addr = ifieldRegDS(theInstr);
7384 UInt rA_addr = ifieldRegA(theInstr);
7385 UInt uimm16 = ifieldUIMM16(theInstr);
7386 UInt rB_addr = ifieldRegB(theInstr);
7387 UInt opc2 = ifieldOPClo10(theInstr);
7388 UChar b1 = ifieldBIT1(theInstr);
7389 UChar b0 = ifieldBIT0(theInstr);
7391 Int simm16 = extend_s_16to32(uimm16);
7392 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7393 IRTemp rS = newTemp(ty);
7394 IRTemp rB = newTemp(ty);
7395 IRTemp EA = newTemp(ty);
7397 assign( rB, getIReg(rB_addr) );
7398 assign( rS, getIReg(rS_addr) );
7400 switch (opc1) {
7401 case 0x1F: // register offset
7402 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
7403 break;
7404 case 0x3E: // immediate offset: 64bit: std/stdu/stq: mask off
7405 // lowest 2 bits of immediate before forming EA
7406 simm16 = simm16 & 0xFFFFFFFC;
7407 default: // immediate offset
7408 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
7409 break;
7412 switch (opc1) {
7413 case 0x26: // stb (Store B, PPC32 p509)
7414 DIP("stb r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7415 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
7416 break;
7418 case 0x27: // stbu (Store B, Update, PPC32 p510)
7419 if (rA_addr == 0 ) {
7420 vex_printf("dis_int_store(ppc)(stbu,rA_addr)\n");
7421 return False;
7423 DIP("stbu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7424 putIReg( rA_addr, mkexpr(EA) );
7425 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
7426 break;
7428 case 0x2C: // sth (Store HW, PPC32 p522)
7429 DIP("sth r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7430 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
7431 break;
7433 case 0x2D: // sthu (Store HW, Update, PPC32 p524)
7434 if (rA_addr == 0) {
7435 vex_printf("dis_int_store(ppc)(sthu,rA_addr)\n");
7436 return False;
7438 DIP("sthu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7439 putIReg( rA_addr, mkexpr(EA) );
7440 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
7441 break;
7443 case 0x24: // stw (Store W, PPC32 p530)
7444 DIP("stw r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7445 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
7446 break;
7448 case 0x25: // stwu (Store W, Update, PPC32 p534)
7449 if (rA_addr == 0) {
7450 vex_printf("dis_int_store(ppc)(stwu,rA_addr)\n");
7451 return False;
7453 DIP("stwu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7454 putIReg( rA_addr, mkexpr(EA) );
7455 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
7456 break;
7458 /* X Form : all these use EA_indexed */
7459 case 0x1F:
7460 if (b0 != 0) {
7461 vex_printf("dis_int_store(ppc)(0x1F,b0)\n");
7462 return False;
7465 switch (opc2) {
7466 case 0x0F7: // stbux (Store B, Update Indexed, PPC32 p511)
7467 if (rA_addr == 0) {
7468 vex_printf("dis_int_store(ppc)(stbux,rA_addr)\n");
7469 return False;
7471 DIP("stbux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7472 putIReg( rA_addr, mkexpr(EA) );
7473 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
7474 break;
7476 case 0x0D7: // stbx (Store B Indexed, PPC32 p512)
7477 DIP("stbx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7478 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
7479 break;
7481 case 0x1B7: // sthux (Store HW, Update Indexed, PPC32 p525)
7482 if (rA_addr == 0) {
7483 vex_printf("dis_int_store(ppc)(sthux,rA_addr)\n");
7484 return False;
7486 DIP("sthux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7487 putIReg( rA_addr, mkexpr(EA) );
7488 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
7489 break;
7491 case 0x197: // sthx (Store HW Indexed, PPC32 p526)
7492 DIP("sthx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7493 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
7494 break;
7496 case 0x0B7: // stwux (Store W, Update Indexed, PPC32 p535)
7497 if (rA_addr == 0) {
7498 vex_printf("dis_int_store(ppc)(stwux,rA_addr)\n");
7499 return False;
7501 DIP("stwux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7502 putIReg( rA_addr, mkexpr(EA) );
7503 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
7504 break;
7506 case 0x097: // stwx (Store W Indexed, PPC32 p536)
7507 DIP("stwx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7508 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
7509 break;
7512 /* 64bit Stores */
7513 case 0x0B5: // stdux (Store DWord, Update Indexed, PPC64 p584)
7514 if (rA_addr == 0) {
7515 vex_printf("dis_int_store(ppc)(stdux,rA_addr)\n");
7516 return False;
7518 DIP("stdux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7519 putIReg( rA_addr, mkexpr(EA) );
7520 store( mkexpr(EA), mkexpr(rS) );
7521 break;
7523 case 0x095: // stdx (Store DWord Indexed, PPC64 p585)
7524 DIP("stdx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7525 store( mkexpr(EA), mkexpr(rS) );
7526 break;
7528 default:
7529 vex_printf("dis_int_store(ppc)(opc2)\n");
7530 return False;
7532 break;
7534 /* DS Form - 64bit Stores. In each case EA will have been formed
7535 with the lowest 2 bits masked off the immediate offset. */
7536 case 0x3E:
7537 switch ((b1<<1) | b0) {
7538 case 0x0: // std (Store DWord, PPC64 p580)
7539 if (!mode64)
7540 return False;
7542 DIP("std r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7543 store( mkexpr(EA), mkexpr(rS) );
7544 break;
7546 case 0x1: // stdu (Store DWord, Update, PPC64 p583)
7547 if (!mode64)
7548 return False;
7550 DIP("stdu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7551 putIReg( rA_addr, mkexpr(EA) );
7552 store( mkexpr(EA), mkexpr(rS) );
7553 break;
7555 case 0x2: { // stq (Store QuadWord, Update, PPC64 p583)
7556 IRTemp EA_hi = newTemp(ty);
7557 IRTemp EA_lo = newTemp(ty);
7558 DIP("stq r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7560 if (mode64) {
7561 if (host_endness == VexEndnessBE) {
7563 /* upper 64-bits */
7564 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
7566 /* lower 64-bits */
7567 assign( EA_lo, ea_rAor0_simm( rA_addr, simm16+8 ) );
7568 } else {
7569 /* upper 64-bits */
7570 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16+8 ) );
7572 /* lower 64-bits */
7573 assign( EA_lo, ea_rAor0_simm( rA_addr, simm16 ) );
7575 } else {
7576 /* upper half of upper 64-bits */
7577 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16+4 ) );
7579 /* lower half of upper 64-bits */
7580 assign( EA_lo, ea_rAor0_simm( rA_addr, simm16+12 ) );
7582 store( mkexpr(EA_hi), mkexpr(rS) );
7583 store( mkexpr(EA_lo), getIReg( rS_addr+1 ) );
7584 break;
7586 default:
7587 vex_printf("dis_int_load(ppc)(0x3A, opc2)\n");
7588 return False;
7590 break;
7592 default:
7593 vex_printf("dis_int_store(ppc)(opc1)\n");
7594 return False;
7596 return True;
7602 Integer Load/Store Multiple Instructions
7604 static Bool dis_int_ldst_mult ( UInt theInstr )
7606 /* D-Form */
7607 UChar opc1 = ifieldOPC(theInstr);
7608 UChar rD_addr = ifieldRegDS(theInstr);
7609 UChar rS_addr = rD_addr;
7610 UChar rA_addr = ifieldRegA(theInstr);
7611 UInt uimm16 = ifieldUIMM16(theInstr);
7613 Int simm16 = extend_s_16to32(uimm16);
7614 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7615 IROp mkAdd = mode64 ? Iop_Add64 : Iop_Add32;
7616 IRTemp EA = newTemp(ty);
7617 UInt r = 0;
7618 UInt ea_off = 0;
7619 IRExpr* irx_addr;
7621 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
7623 switch (opc1) {
7624 case 0x2E: // lmw (Load Multiple Word, PPC32 p454)
7625 if (rA_addr >= rD_addr) {
7626 vex_printf("dis_int_ldst_mult(ppc)(lmw,rA_addr)\n");
7627 return False;
7629 DIP("lmw r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
7630 for (r = rD_addr; r <= 31; r++) {
7631 irx_addr = binop(mkAdd, mkexpr(EA), mode64 ? mkU64(ea_off) : mkU32(ea_off));
7632 putIReg( r, mkWidenFrom32(ty, load(Ity_I32, irx_addr ),
7633 False) );
7634 ea_off += 4;
7636 break;
7638 case 0x2F: // stmw (Store Multiple Word, PPC32 p527)
7639 DIP("stmw r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
7640 for (r = rS_addr; r <= 31; r++) {
7641 irx_addr = binop(mkAdd, mkexpr(EA), mode64 ? mkU64(ea_off) : mkU32(ea_off));
7642 store( irx_addr, mkNarrowTo32(ty, getIReg(r)) );
7643 ea_off += 4;
7645 break;
7647 default:
7648 vex_printf("dis_int_ldst_mult(ppc)(opc1)\n");
7649 return False;
7651 return True;
7657 Integer Load/Store String Instructions
7659 static
7660 void generate_lsw_sequence ( IRTemp tNBytes, // # bytes, :: Ity_I32
7661 IRTemp EA, // EA
7662 Int rD, // first dst register
7663 Int maxBytes ) // 32 or 128
7665 Int i, shift = 24;
7666 IRExpr* e_nbytes = mkexpr(tNBytes);
7667 IRExpr* e_EA = mkexpr(EA);
7668 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7670 vassert(rD >= 0 && rD < 32);
7671 rD--; if (rD < 0) rD = 31;
7673 for (i = 0; i < maxBytes; i++) {
7674 /* if (nBytes < (i+1)) goto NIA; */
7675 stmt( IRStmt_Exit( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
7676 Ijk_Boring,
7677 mkSzConst( ty, nextInsnAddr()), OFFB_CIA ));
7678 /* when crossing into a new dest register, set it to zero. */
7679 if ((i % 4) == 0) {
7680 rD++; if (rD == 32) rD = 0;
7681 putIReg(rD, mkSzImm(ty, 0));
7682 shift = 24;
7684 /* rD |= (8Uto32(*(EA+i))) << shift */
7685 vassert(shift == 0 || shift == 8 || shift == 16 || shift == 24);
7686 putIReg(
7687 rD,
7688 mkWidenFrom32(
7689 ty,
7690 binop(
7691 Iop_Or32,
7692 mkNarrowTo32(ty, getIReg(rD)),
7693 binop(
7694 Iop_Shl32,
7695 unop(
7696 Iop_8Uto32,
7697 load( Ity_I8,
7698 binop( mkSzOp(ty,Iop_Add8),
7699 e_EA, mkSzImm(ty,i)))
7701 mkU8(toUChar(shift))
7704 /*Signed*/False
7707 shift -= 8;
7711 static
7712 void generate_stsw_sequence ( IRTemp tNBytes, // # bytes, :: Ity_I32
7713 IRTemp EA, // EA
7714 Int rS, // first src register
7715 Int maxBytes ) // 32 or 128
7717 Int i, shift = 24;
7718 IRExpr* e_nbytes = mkexpr(tNBytes);
7719 IRExpr* e_EA = mkexpr(EA);
7720 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7722 vassert(rS >= 0 && rS < 32);
7723 rS--; if (rS < 0) rS = 31;
7725 for (i = 0; i < maxBytes; i++) {
7726 /* if (nBytes < (i+1)) goto NIA; */
7727 stmt( IRStmt_Exit( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
7728 Ijk_Boring,
7729 mkSzConst( ty, nextInsnAddr() ), OFFB_CIA ));
7730 /* check for crossing into a new src register. */
7731 if ((i % 4) == 0) {
7732 rS++; if (rS == 32) rS = 0;
7733 shift = 24;
7735 /* *(EA+i) = 32to8(rS >> shift) */
7736 vassert(shift == 0 || shift == 8 || shift == 16 || shift == 24);
7737 store(
7738 binop( mkSzOp(ty,Iop_Add8), e_EA, mkSzImm(ty,i)),
7739 unop( Iop_32to8,
7740 binop( Iop_Shr32,
7741 mkNarrowTo32( ty, getIReg(rS) ),
7742 mkU8( toUChar(shift) )))
7744 shift -= 8;
7748 static Bool dis_int_ldst_str ( UInt theInstr, /*OUT*/Bool* stopHere )
7750 /* X-Form */
7751 UChar opc1 = ifieldOPC(theInstr);
7752 UChar rD_addr = ifieldRegDS(theInstr);
7753 UChar rS_addr = rD_addr;
7754 UChar rA_addr = ifieldRegA(theInstr);
7755 UChar rB_addr = ifieldRegB(theInstr);
7756 UChar NumBytes = rB_addr;
7757 UInt opc2 = ifieldOPClo10(theInstr);
7758 UChar b0 = ifieldBIT0(theInstr);
7760 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7761 IRTemp t_EA = newTemp(ty);
7762 IRTemp t_nbytes = IRTemp_INVALID;
7764 *stopHere = False;
7766 if (opc1 != 0x1F || b0 != 0) {
7767 vex_printf("dis_int_ldst_str(ppc)(opc1)\n");
7768 return False;
7771 switch (opc2) {
7772 case 0x255: // lswi (Load String Word Immediate, PPC32 p455)
7773 /* NB: does not reject the case where RA is in the range of
7774 registers to be loaded. It should. */
7775 DIP("lswi r%u,r%u,%d\n", rD_addr, rA_addr, NumBytes);
7776 assign( t_EA, ea_rAor0(rA_addr) );
7777 if (NumBytes == 8 && !mode64) {
7778 /* Special case hack */
7779 /* rD = Mem[EA]; (rD+1)%32 = Mem[EA+4] */
7780 putIReg( rD_addr,
7781 load(Ity_I32, mkexpr(t_EA)) );
7782 putIReg( (rD_addr+1) % 32,
7783 load(Ity_I32,
7784 binop(Iop_Add32, mkexpr(t_EA), mkU32(4))) );
7785 } else {
7786 t_nbytes = newTemp(Ity_I32);
7787 assign( t_nbytes, mkU32(NumBytes==0 ? 32 : NumBytes) );
7788 generate_lsw_sequence( t_nbytes, t_EA, rD_addr, 32 );
7789 *stopHere = True;
7791 return True;
7793 case 0x215: // lswx (Load String Word Indexed, PPC32 p456)
7794 /* NB: does not reject the case where RA is in the range of
7795 registers to be loaded. It should. Although considering
7796 that that can only be detected at run time, it's not easy to
7797 do so. */
7798 if (rD_addr == rA_addr || rD_addr == rB_addr)
7799 return False;
7800 if (rD_addr == 0 && rA_addr == 0)
7801 return False;
7802 DIP("lswx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
7803 t_nbytes = newTemp(Ity_I32);
7804 assign( t_EA, ea_rAor0_idxd(rA_addr,rB_addr) );
7805 assign( t_nbytes, unop( Iop_8Uto32, getXER_BC() ) );
7806 generate_lsw_sequence( t_nbytes, t_EA, rD_addr, 128 );
7807 *stopHere = True;
7808 return True;
7810 case 0x2D5: // stswi (Store String Word Immediate, PPC32 p528)
7811 DIP("stswi r%u,r%u,%d\n", rS_addr, rA_addr, NumBytes);
7812 assign( t_EA, ea_rAor0(rA_addr) );
7813 if (NumBytes == 8 && !mode64) {
7814 /* Special case hack */
7815 /* Mem[EA] = rD; Mem[EA+4] = (rD+1)%32 */
7816 store( mkexpr(t_EA),
7817 getIReg(rD_addr) );
7818 store( binop(Iop_Add32, mkexpr(t_EA), mkU32(4)),
7819 getIReg((rD_addr+1) % 32) );
7820 } else {
7821 t_nbytes = newTemp(Ity_I32);
7822 assign( t_nbytes, mkU32(NumBytes==0 ? 32 : NumBytes) );
7823 generate_stsw_sequence( t_nbytes, t_EA, rD_addr, 32 );
7824 *stopHere = True;
7826 return True;
7828 case 0x295: // stswx (Store String Word Indexed, PPC32 p529)
7829 DIP("stswx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
7830 t_nbytes = newTemp(Ity_I32);
7831 assign( t_EA, ea_rAor0_idxd(rA_addr,rB_addr) );
7832 assign( t_nbytes, unop( Iop_8Uto32, getXER_BC() ) );
7833 generate_stsw_sequence( t_nbytes, t_EA, rS_addr, 128 );
7834 *stopHere = True;
7835 return True;
7837 default:
7838 vex_printf("dis_int_ldst_str(ppc)(opc2)\n");
7839 return False;
7841 return True;
7845 /* ------------------------------------------------------------------
7846 Integer Branch Instructions
7847 ------------------------------------------------------------------ */
7850 Branch helper function
7851 ok = BO[2] | ((CTR[0] != 0) ^ BO[1])
7852 Returns an I32 which is 0x00000000 if the ctr condition failed
7853 and 0xFFFFFFFF otherwise.
7855 static IRExpr* /* :: Ity_I32 */ branch_ctr_ok( UInt BO )
7857 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7858 IRTemp ok = newTemp(Ity_I32);
7860 if ((BO >> 2) & 1) { // independent of ctr
7861 assign( ok, mkU32(0xFFFFFFFF) );
7862 } else {
7863 if ((BO >> 1) & 1) { // ctr == 0 ?
7864 assign( ok, unop( Iop_1Sto32,
7865 binop( mkSzOp(ty, Iop_CmpEQ8),
7866 getGST( PPC_GST_CTR ),
7867 mkSzImm(ty,0))) );
7868 } else { // ctr != 0 ?
7869 assign( ok, unop( Iop_1Sto32,
7870 binop( mkSzOp(ty, Iop_CmpNE8),
7871 getGST( PPC_GST_CTR ),
7872 mkSzImm(ty,0))) );
7875 return mkexpr(ok);
7880 Branch helper function cond_ok = BO[4] | (CR[BI] == BO[3])
7881 Returns an I32 which is either 0 if the condition failed or
7882 some arbitrary nonzero value otherwise. */
7884 static IRExpr* /* :: Ity_I32 */ branch_cond_ok( UInt BO, UInt BI )
7886 Int where;
7887 IRTemp res = newTemp(Ity_I32);
7888 IRTemp cr_bi = newTemp(Ity_I32);
7890 if ((BO >> 4) & 1) {
7891 assign( res, mkU32(1) );
7892 } else {
7893 // ok = (CR[BI] == BO[3]) Note, the following relies on
7894 // getCRbit_anywhere returning a value which
7895 // is either zero or has exactly 1 bit set.
7896 assign( cr_bi, getCRbit_anywhere( BI, &where ) );
7898 if ((BO >> 3) & 1) {
7899 /* We can use cr_bi as-is. */
7900 assign( res, mkexpr(cr_bi) );
7901 } else {
7902 /* We have to invert the sense of the information held in
7903 cr_bi. For that we need to know which bit
7904 getCRbit_anywhere regards as significant. */
7905 assign( res, binop(Iop_Xor32, mkexpr(cr_bi),
7906 mkU32(1<<where)) );
7909 return mkexpr(res);
7914 Integer Branch Instructions
7916 static Bool dis_branch ( UInt theInstr,
7917 const VexAbiInfo* vbi,
7918 /*OUT*/DisResult* dres,
7919 Bool (*resteerOkFn)(void*,Addr),
7920 void* callback_opaque )
7922 UChar opc1 = ifieldOPC(theInstr);
7923 UChar BO = ifieldRegDS(theInstr);
7924 UChar BI = ifieldRegA(theInstr);
7925 UInt BD_u16 = ifieldUIMM16(theInstr) & 0xFFFFFFFC; /* mask off */
7926 UChar b11to15 = ifieldRegB(theInstr);
7927 UInt opc2 = ifieldOPClo10(theInstr);
7928 UInt LI_u26 = ifieldUIMM26(theInstr) & 0xFFFFFFFC; /* mask off */
7929 UChar flag_AA = ifieldBIT1(theInstr);
7930 UChar flag_LK = ifieldBIT0(theInstr);
7932 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7933 Addr64 tgt = 0;
7934 UInt BD = extend_s_16to32(BD_u16);
7935 IRTemp do_branch = newTemp(Ity_I32);
7936 IRTemp ctr_ok = newTemp(Ity_I32);
7937 IRTemp cond_ok = newTemp(Ity_I32);
7938 IRExpr* e_nia = mkSzImm(ty, nextInsnAddr());
7939 IRConst* c_nia = mkSzConst(ty, nextInsnAddr());
7940 IRTemp lr_old = newTemp(ty);
7942 /* Hack to pass through code that just wants to read the PC */
7943 if (theInstr == 0x429F0005) {
7944 DIP("bcl 0x%x, 0x%x (a.k.a mr lr,cia+4)\n", BO, BI);
7945 putGST( PPC_GST_LR, e_nia );
7946 return True;
7949 /* The default what-next. Individual cases can override it. */
7950 dres->whatNext = Dis_StopHere;
7951 vassert(dres->jk_StopHere == Ijk_INVALID);
7953 switch (opc1) {
7954 case 0x12: // b (Branch, PPC32 p360)
7955 if (flag_AA) {
7956 tgt = mkSzAddr( ty, extend_s_26to64(LI_u26) );
7957 } else {
7958 tgt = mkSzAddr( ty, guest_CIA_curr_instr +
7959 (Long)extend_s_26to64(LI_u26) );
7961 if (mode64) {
7962 DIP("b%s%s 0x%llx\n",
7963 flag_LK ? "l" : "", flag_AA ? "a" : "", tgt);
7964 } else {
7965 DIP("b%s%s 0x%x\n",
7966 flag_LK ? "l" : "", flag_AA ? "a" : "", (Addr32)tgt);
7969 if (flag_LK) {
7970 putGST( PPC_GST_LR, e_nia );
7971 if (vbi->guest_ppc_zap_RZ_at_bl
7972 && vbi->guest_ppc_zap_RZ_at_bl( (ULong)tgt) ) {
7973 IRTemp t_tgt = newTemp(ty);
7974 assign(t_tgt, mode64 ? mkU64(tgt) : mkU32(tgt) );
7975 make_redzone_AbiHint( vbi, t_tgt,
7976 "branch-and-link (unconditional call)" );
7980 if (resteerOkFn( callback_opaque, tgt )) {
7981 dres->whatNext = Dis_ResteerU;
7982 dres->continueAt = tgt;
7983 } else {
7984 dres->jk_StopHere = flag_LK ? Ijk_Call : Ijk_Boring; ;
7985 putGST( PPC_GST_CIA, mkSzImm(ty, tgt) );
7987 break;
7989 case 0x10: // bc (Branch Conditional, PPC32 p361)
7990 DIP("bc%s%s 0x%x, 0x%x, 0x%x\n",
7991 flag_LK ? "l" : "", flag_AA ? "a" : "", BO, BI, BD);
7993 if (!(BO & 0x4)) {
7994 putGST( PPC_GST_CTR,
7995 binop(mkSzOp(ty, Iop_Sub8),
7996 getGST( PPC_GST_CTR ), mkSzImm(ty, 1)) );
7999 /* This is a bit subtle. ctr_ok is either all 0s or all 1s.
8000 cond_ok is either zero or nonzero, since that's the cheapest
8001 way to compute it. Anding them together gives a value which
8002 is either zero or non zero and so that's what we must test
8003 for in the IRStmt_Exit. */
8004 assign( ctr_ok, branch_ctr_ok( BO ) );
8005 assign( cond_ok, branch_cond_ok( BO, BI ) );
8006 assign( do_branch,
8007 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
8009 if (flag_AA) {
8010 tgt = mkSzAddr(ty, extend_s_16to64(BD_u16));
8011 } else {
8012 tgt = mkSzAddr(ty, guest_CIA_curr_instr +
8013 (Long)extend_s_16to64(BD_u16));
8015 if (flag_LK)
8016 putGST( PPC_GST_LR, e_nia );
8018 stmt( IRStmt_Exit(
8019 binop(Iop_CmpNE32, mkexpr(do_branch), mkU32(0)),
8020 flag_LK ? Ijk_Call : Ijk_Boring,
8021 mkSzConst(ty, tgt), OFFB_CIA ) );
8023 dres->jk_StopHere = Ijk_Boring;
8024 putGST( PPC_GST_CIA, e_nia );
8025 break;
8027 case 0x13:
8028 /* For bclr and bcctr, it appears that the lowest two bits of
8029 b11to15 are a branch hint, and so we only need to ensure it's
8030 of the form 000XX. */
8031 if ((b11to15 & ~3) != 0) {
8032 vex_printf("dis_int_branch(ppc)(0x13,b11to15)(%d)\n", b11to15);
8033 return False;
8036 switch (opc2) {
8037 case 0x210: // bcctr (Branch Cond. to Count Register, PPC32 p363)
8038 if ((BO & 0x4) == 0) { // "decr and test CTR" option invalid
8039 vex_printf("dis_int_branch(ppc)(bcctr,BO)\n");
8040 return False;
8042 DIP("bcctr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
8044 assign( cond_ok, branch_cond_ok( BO, BI ) );
8046 /* FIXME: this is confusing. lr_old holds the old value
8047 of ctr, not lr :-) */
8048 assign( lr_old, addr_align( getGST( PPC_GST_CTR ), 4 ));
8050 if (flag_LK)
8051 putGST( PPC_GST_LR, e_nia );
8053 stmt( IRStmt_Exit(
8054 binop(Iop_CmpEQ32, mkexpr(cond_ok), mkU32(0)),
8055 Ijk_Boring,
8056 c_nia, OFFB_CIA ));
8058 if (flag_LK && vbi->guest_ppc_zap_RZ_at_bl) {
8059 make_redzone_AbiHint( vbi, lr_old,
8060 "b-ctr-l (indirect call)" );
8063 dres->jk_StopHere = flag_LK ? Ijk_Call : Ijk_Boring;;
8064 putGST( PPC_GST_CIA, mkexpr(lr_old) );
8065 break;
8067 case 0x010: { // bclr (Branch Cond. to Link Register, PPC32 p365)
8068 Bool vanilla_return = False;
8069 if ((BO & 0x14 /* 1z1zz */) == 0x14 && flag_LK == 0) {
8070 DIP("blr\n");
8071 vanilla_return = True;
8072 } else {
8073 DIP("bclr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
8076 if (!(BO & 0x4)) {
8077 putGST( PPC_GST_CTR,
8078 binop(mkSzOp(ty, Iop_Sub8),
8079 getGST( PPC_GST_CTR ), mkSzImm(ty, 1)) );
8082 /* See comments above for 'bc' about this */
8083 assign( ctr_ok, branch_ctr_ok( BO ) );
8084 assign( cond_ok, branch_cond_ok( BO, BI ) );
8085 assign( do_branch,
8086 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
8088 assign( lr_old, addr_align( getGST( PPC_GST_LR ), 4 ));
8090 if (flag_LK)
8091 putGST( PPC_GST_LR, e_nia );
8093 stmt( IRStmt_Exit(
8094 binop(Iop_CmpEQ32, mkexpr(do_branch), mkU32(0)),
8095 Ijk_Boring,
8096 c_nia, OFFB_CIA ));
8098 if (vanilla_return && vbi->guest_ppc_zap_RZ_at_blr) {
8099 make_redzone_AbiHint( vbi, lr_old,
8100 "branch-to-lr (unconditional return)" );
8103 /* blrl is pretty strange; it's like a return that sets the
8104 return address of its caller to the insn following this
8105 one. Mark it as a return. */
8106 dres->jk_StopHere = Ijk_Ret; /* was flag_LK ? Ijk_Call : Ijk_Ret; */
8107 putGST( PPC_GST_CIA, mkexpr(lr_old) );
8108 break;
8110 default:
8111 vex_printf("dis_int_branch(ppc)(opc2)\n");
8112 return False;
8114 break;
8116 default:
8117 vex_printf("dis_int_branch(ppc)(opc1)\n");
8118 return False;
8121 return True;
8125 * PC relative instruction
8127 static Bool dis_pc_relative ( UInt theInstr )
8129 /* DX-Form */
8130 UChar opc1 = ifieldOPC(theInstr);
8131 unsigned long long D;
8132 UInt d0 = IFIELD(theInstr, 6, 10);
8133 UInt d1 = IFIELD(theInstr, 16, 5);
8134 UInt d2 = IFIELD(theInstr, 0, 1);
8135 UChar rT_addr = ifieldRegDS(theInstr);
8136 UInt opc2 = ifieldOPClo5(theInstr);
8137 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8139 if ( opc1 != 0x13) {
8140 vex_printf("dis_pc_relative(ppc)(opc1)\n");
8141 return False;
8144 switch (opc2) {
8145 case 0x002: // addpcis (Add PC immediate Shifted DX-form)
8147 IRExpr* nia = mkSzImm(ty, nextInsnAddr());
8148 IRExpr* result;
8150 D = (d0 << 6) | (d1 << 1) | d2;
8151 DIP("addpcis %u,%llu\n", rT_addr, D);
8153 if ( (D & 0x8000) == 0x8000 )
8154 D = 0xFFFFFFFFFFFF0000UL | D; // sign extend
8156 if ( ty == Ity_I32 ) {
8157 result = binop( Iop_Add32, nia, mkU32( D << 16 ) );
8158 } else {
8159 vassert( ty == Ity_I64 );
8160 result = binop( Iop_Add64, nia, mkU64( D << 16 ) );
8163 putIReg( rT_addr, result);
8165 break;
8167 default:
8168 vex_printf("dis_pc_relative(ppc)(opc2)\n");
8169 return False;
8172 return True;
8176 Condition Register Logical Instructions
8178 static Bool dis_cond_logic ( UInt theInstr )
8180 /* XL-Form */
8181 UChar opc1 = ifieldOPC(theInstr);
8182 UChar crbD_addr = ifieldRegDS(theInstr);
8183 UChar crfD_addr = toUChar( IFIELD(theInstr, 23, 3) );
8184 UChar crbA_addr = ifieldRegA(theInstr);
8185 UChar crfS_addr = toUChar( IFIELD(theInstr, 18, 3) );
8186 UChar crbB_addr = ifieldRegB(theInstr);
8187 UInt opc2 = ifieldOPClo10(theInstr);
8188 UChar b0 = ifieldBIT0(theInstr);
8190 IRTemp crbD = newTemp(Ity_I32);
8191 IRTemp crbA = newTemp(Ity_I32);
8192 IRTemp crbB = newTemp(Ity_I32);
8194 if (opc1 != 19 || b0 != 0) {
8195 vex_printf("dis_cond_logic(ppc)(opc1)\n");
8196 return False;
8199 if (opc2 == 0) { // mcrf (Move Cond Reg Field, PPC32 p464)
8200 if (((crbD_addr & 0x3) != 0) ||
8201 ((crbA_addr & 0x3) != 0) || (crbB_addr != 0)) {
8202 vex_printf("dis_cond_logic(ppc)(crbD|crbA|crbB != 0)\n");
8203 return False;
8205 DIP("mcrf cr%u,cr%u\n", crfD_addr, crfS_addr);
8206 putCR0( crfD_addr, getCR0( crfS_addr) );
8207 putCR321( crfD_addr, getCR321(crfS_addr) );
8208 } else {
8209 assign( crbA, getCRbit(crbA_addr) );
8210 if (crbA_addr == crbB_addr)
8211 crbB = crbA;
8212 else
8213 assign( crbB, getCRbit(crbB_addr) );
8215 switch (opc2) {
8216 case 0x101: // crand (Cond Reg AND, PPC32 p372)
8217 DIP("crand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8218 assign( crbD, binop(Iop_And32, mkexpr(crbA), mkexpr(crbB)) );
8219 break;
8220 case 0x081: // crandc (Cond Reg AND w. Complement, PPC32 p373)
8221 DIP("crandc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8222 assign( crbD, binop(Iop_And32,
8223 mkexpr(crbA),
8224 unop(Iop_Not32, mkexpr(crbB))) );
8225 break;
8226 case 0x121: // creqv (Cond Reg Equivalent, PPC32 p374)
8227 DIP("creqv crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8228 assign( crbD, unop(Iop_Not32,
8229 binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB))) );
8230 break;
8231 case 0x0E1: // crnand (Cond Reg NAND, PPC32 p375)
8232 DIP("crnand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8233 assign( crbD, unop(Iop_Not32,
8234 binop(Iop_And32, mkexpr(crbA), mkexpr(crbB))) );
8235 break;
8236 case 0x021: // crnor (Cond Reg NOR, PPC32 p376)
8237 DIP("crnor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8238 assign( crbD, unop(Iop_Not32,
8239 binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB))) );
8240 break;
8241 case 0x1C1: // cror (Cond Reg OR, PPC32 p377)
8242 DIP("cror crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8243 assign( crbD, binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB)) );
8244 break;
8245 case 0x1A1: // crorc (Cond Reg OR w. Complement, PPC32 p378)
8246 DIP("crorc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8247 assign( crbD, binop(Iop_Or32,
8248 mkexpr(crbA),
8249 unop(Iop_Not32, mkexpr(crbB))) );
8250 break;
8251 case 0x0C1: // crxor (Cond Reg XOR, PPC32 p379)
8252 DIP("crxor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
8253 assign( crbD, binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB)) );
8254 break;
8255 default:
8256 vex_printf("dis_cond_logic(ppc)(opc2)\n");
8257 return False;
8260 putCRbit( crbD_addr, mkexpr(crbD) );
8262 return True;
8267 Trap instructions
8270 /* Do the code generation for a trap. Returned Bool is true iff
8271 this is an unconditional trap. If the two arg IRExpr*s are
8272 Ity_I32s then the comparison is 32-bit. If they are Ity_I64s
8273 then they are 64-bit, and we must be disassembling 64-bit
8274 instructions. */
8275 static Bool do_trap ( UChar TO,
8276 IRExpr* argL0, IRExpr* argR0, Addr64 cia )
8278 IRTemp argL, argR;
8279 IRExpr *argLe, *argRe, *cond, *tmp;
8281 Bool is32bit = typeOfIRExpr(irsb->tyenv, argL0 ) == Ity_I32;
8283 IROp opAND = is32bit ? Iop_And32 : Iop_And64;
8284 IROp opOR = is32bit ? Iop_Or32 : Iop_Or64;
8285 IROp opCMPORDS = is32bit ? Iop_CmpORD32S : Iop_CmpORD64S;
8286 IROp opCMPORDU = is32bit ? Iop_CmpORD32U : Iop_CmpORD64U;
8287 IROp opCMPNE = is32bit ? Iop_CmpNE32 : Iop_CmpNE64;
8288 IROp opCMPEQ = is32bit ? Iop_CmpEQ32 : Iop_CmpEQ64;
8289 IRExpr* const0 = is32bit ? mkU32(0) : mkU64(0);
8290 IRExpr* const2 = is32bit ? mkU32(2) : mkU64(2);
8291 IRExpr* const4 = is32bit ? mkU32(4) : mkU64(4);
8292 IRExpr* const8 = is32bit ? mkU32(8) : mkU64(8);
8294 const UChar b11100 = 0x1C;
8295 const UChar b00111 = 0x07;
8297 if (is32bit) {
8298 vassert( typeOfIRExpr(irsb->tyenv, argL0) == Ity_I32 );
8299 vassert( typeOfIRExpr(irsb->tyenv, argR0) == Ity_I32 );
8300 } else {
8301 vassert( typeOfIRExpr(irsb->tyenv, argL0) == Ity_I64 );
8302 vassert( typeOfIRExpr(irsb->tyenv, argR0) == Ity_I64 );
8303 vassert( mode64 );
8306 if ((TO & b11100) == b11100 || (TO & b00111) == b00111) {
8307 /* Unconditional trap. Just do the exit without
8308 testing the arguments. */
8309 stmt( IRStmt_Exit(
8310 binop(opCMPEQ, const0, const0),
8311 Ijk_SigTRAP,
8312 mode64 ? IRConst_U64(cia) : IRConst_U32((UInt)cia),
8313 OFFB_CIA
8315 return True; /* unconditional trap */
8318 if (is32bit) {
8319 argL = newTemp(Ity_I32);
8320 argR = newTemp(Ity_I32);
8321 } else {
8322 argL = newTemp(Ity_I64);
8323 argR = newTemp(Ity_I64);
8326 assign( argL, argL0 );
8327 assign( argR, argR0 );
8329 argLe = mkexpr(argL);
8330 argRe = mkexpr(argR);
8332 cond = const0;
8333 if (TO & 16) { // L <s R
8334 tmp = binop(opAND, binop(opCMPORDS, argLe, argRe), const8);
8335 cond = binop(opOR, tmp, cond);
8337 if (TO & 8) { // L >s R
8338 tmp = binop(opAND, binop(opCMPORDS, argLe, argRe), const4);
8339 cond = binop(opOR, tmp, cond);
8341 if (TO & 4) { // L == R
8342 tmp = binop(opAND, binop(opCMPORDS, argLe, argRe), const2);
8343 cond = binop(opOR, tmp, cond);
8345 if (TO & 2) { // L <u R
8346 tmp = binop(opAND, binop(opCMPORDU, argLe, argRe), const8);
8347 cond = binop(opOR, tmp, cond);
8349 if (TO & 1) { // L >u R
8350 tmp = binop(opAND, binop(opCMPORDU, argLe, argRe), const4);
8351 cond = binop(opOR, tmp, cond);
8353 stmt( IRStmt_Exit(
8354 binop(opCMPNE, cond, const0),
8355 Ijk_SigTRAP,
8356 mode64 ? IRConst_U64(cia) : IRConst_U32((UInt)cia),
8357 OFFB_CIA
8359 return False; /* not an unconditional trap */
8362 static Bool dis_trapi ( UInt theInstr,
8363 /*OUT*/DisResult* dres )
8365 /* D-Form */
8366 UChar opc1 = ifieldOPC(theInstr);
8367 UChar TO = ifieldRegDS(theInstr);
8368 UChar rA_addr = ifieldRegA(theInstr);
8369 UInt uimm16 = ifieldUIMM16(theInstr);
8370 ULong simm16 = extend_s_16to64(uimm16);
8371 Addr64 cia = guest_CIA_curr_instr;
8372 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8373 Bool uncond = False;
8375 switch (opc1) {
8376 case 0x03: // twi (Trap Word Immediate, PPC32 p548)
8377 uncond = do_trap( TO,
8378 mode64 ? unop(Iop_64to32, getIReg(rA_addr))
8379 : getIReg(rA_addr),
8380 mkU32( (UInt)simm16 ),
8381 cia );
8382 if (TO == 4) {
8383 DIP("tweqi r%u,%d\n", rA_addr, (Int)simm16);
8384 } else {
8385 DIP("tw%di r%u,%d\n", TO, rA_addr, (Int)simm16);
8387 break;
8388 case 0x02: // tdi
8389 if (!mode64)
8390 return False;
8391 uncond = do_trap( TO, getIReg(rA_addr), mkU64( (ULong)simm16 ), cia );
8392 if (TO == 4) {
8393 DIP("tdeqi r%u,%d\n", rA_addr, (Int)simm16);
8394 } else {
8395 DIP("td%di r%u,%d\n", TO, rA_addr, (Int)simm16);
8397 break;
8398 default:
8399 return False;
8402 if (uncond) {
8403 /* If the trap shows signs of being unconditional, don't
8404 continue decoding past it. */
8405 putGST( PPC_GST_CIA, mkSzImm( ty, nextInsnAddr() ));
8406 dres->jk_StopHere = Ijk_Boring;
8407 dres->whatNext = Dis_StopHere;
8410 return True;
8413 static Bool dis_trap ( UInt theInstr,
8414 /*OUT*/DisResult* dres )
8416 /* X-Form */
8417 UInt opc2 = ifieldOPClo10(theInstr);
8418 UChar TO = ifieldRegDS(theInstr);
8419 UChar rA_addr = ifieldRegA(theInstr);
8420 UChar rB_addr = ifieldRegB(theInstr);
8421 Addr64 cia = guest_CIA_curr_instr;
8422 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8423 Bool uncond = False;
8425 if (ifieldBIT0(theInstr) != 0)
8426 return False;
8428 switch (opc2) {
8429 case 0x004: // tw (Trap Word, PPC64 p540)
8430 uncond = do_trap( TO,
8431 mode64 ? unop(Iop_64to32, getIReg(rA_addr))
8432 : getIReg(rA_addr),
8433 mode64 ? unop(Iop_64to32, getIReg(rB_addr))
8434 : getIReg(rB_addr),
8435 cia );
8436 if (TO == 4) {
8437 DIP("tweq r%u,r%u\n", rA_addr, rB_addr);
8438 } else {
8439 DIP("tw%d r%u,r%u\n", TO, rA_addr, rB_addr);
8441 break;
8442 case 0x044: // td (Trap Doubleword, PPC64 p534)
8443 if (!mode64)
8444 return False;
8445 uncond = do_trap( TO, getIReg(rA_addr), getIReg(rB_addr), cia );
8446 if (TO == 4) {
8447 DIP("tdeq r%u,r%u\n", rA_addr, rB_addr);
8448 } else {
8449 DIP("td%d r%u,r%u\n", TO, rA_addr, rB_addr);
8451 break;
8452 default:
8453 return False;
8456 if (uncond) {
8457 /* If the trap shows signs of being unconditional, don't
8458 continue decoding past it. */
8459 putGST( PPC_GST_CIA, mkSzImm( ty, nextInsnAddr() ));
8460 dres->jk_StopHere = Ijk_Boring;
8461 dres->whatNext = Dis_StopHere;
8464 return True;
8469 System Linkage Instructions
8471 static Bool dis_syslink ( UInt theInstr,
8472 const VexAbiInfo* abiinfo, DisResult* dres )
8474 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8476 if (theInstr != 0x44000002) {
8477 vex_printf("dis_syslink(ppc)(theInstr)\n");
8478 return False;
8481 // sc (System Call, PPC32 p504)
8482 DIP("sc\n");
8484 /* Copy CIA into the IP_AT_SYSCALL pseudo-register, so that on Darwin
8485 Valgrind can back the guest up to this instruction if it needs
8486 to restart the syscall. */
8487 putGST( PPC_GST_IP_AT_SYSCALL, getGST( PPC_GST_CIA ) );
8489 /* It's important that all ArchRegs carry their up-to-date value
8490 at this point. So we declare an end-of-block here, which
8491 forces any TempRegs caching ArchRegs to be flushed. */
8492 putGST( PPC_GST_CIA, mkSzImm( ty, nextInsnAddr() ));
8494 dres->whatNext = Dis_StopHere;
8495 dres->jk_StopHere = Ijk_Sys_syscall;
8496 return True;
8501 Memory Synchronization Instructions
8503 Note on Reservations:
8504 We rely on the assumption that V will in fact only allow one thread at
8505 once to run. In effect, a thread can make a reservation, but we don't
8506 check any stores it does. Instead, the reservation is cancelled when
8507 the scheduler switches to another thread (run_thread_for_a_while()).
8509 static Bool dis_memsync ( UInt theInstr )
8511 /* X-Form, XL-Form */
8512 UChar opc1 = ifieldOPC(theInstr);
8513 UInt b11to25 = IFIELD(theInstr, 11, 15);
8514 UChar flag_L = ifieldRegDS(theInstr);
8515 UInt b11to20 = IFIELD(theInstr, 11, 10);
8516 UInt M0 = IFIELD(theInstr, 11, 5);
8517 UChar rD_addr = ifieldRegDS(theInstr);
8518 UChar rS_addr = rD_addr;
8519 UChar rA_addr = ifieldRegA(theInstr);
8520 UChar rB_addr = ifieldRegB(theInstr);
8521 UInt opc2 = ifieldOPClo10(theInstr);
8522 UChar b0 = ifieldBIT0(theInstr);
8524 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8525 IRTemp EA = newTemp(ty);
8527 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
8529 switch (opc1) {
8530 /* XL-Form */
8531 case 0x13: // isync (Instruction Synchronize, PPC32 p432)
8532 if (opc2 != 0x096) {
8533 vex_printf("dis_memsync(ppc)(0x13,opc2)\n");
8534 return False;
8536 if (b11to25 != 0 || b0 != 0) {
8537 vex_printf("dis_memsync(ppc)(0x13,b11to25|b0)\n");
8538 return False;
8540 DIP("isync\n");
8541 stmt( IRStmt_MBE(Imbe_Fence) );
8542 break;
8544 /* X-Form */
8545 case 0x1F:
8546 switch (opc2) {
8547 case 0x356: // eieio or mbar (Enforce In-Order Exec of I/O, PPC32 p394)
8548 if (M0 == 0) {
8549 if (b11to20 != 0 || b0 != 0) {
8550 vex_printf("dis_memsync(ppc)(eieio,b11to20|b0)\n");
8551 return False;
8553 DIP("eieio\n");
8554 } else {
8555 if (b11to20 != 0 || b0 != 0) {
8556 vex_printf("dis_memsync(ppc)(mbar,b11to20|b0)\n");
8557 return False;
8559 DIP("mbar %d\n", M0);
8561 /* Insert a memory fence, just to be on the safe side. */
8562 stmt( IRStmt_MBE(Imbe_Fence) );
8563 break;
8565 case 0x014: { // lwarx (Load Word and Reserve Indexed, PPC32 p458)
8566 IRTemp res;
8567 /* According to the PowerPC ISA version 2.05, b0 (called EH
8568 in the documentation) is merely a hint bit to the
8569 hardware, I think as to whether or not contention is
8570 likely. So we can just ignore it. */
8571 DIP("lwarx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, b0);
8573 // trap if misaligned
8574 gen_SIGBUS_if_misaligned( EA, 4 );
8576 // and actually do the load
8577 res = newTemp(Ity_I32);
8578 stmt( stmt_load(res, mkexpr(EA), NULL/*this is a load*/) );
8580 putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(res), False) );
8581 break;
8584 case 0x034: { // lbarx (Load Word and Reserve Indexed)
8585 IRTemp res;
8586 /* According to the PowerPC ISA version 2.05, b0 (called EH
8587 in the documentation) is merely a hint bit to the
8588 hardware, I think as to whether or not contention is
8589 likely. So we can just ignore it. */
8590 DIP("lbarx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, b0);
8592 // and actually do the load
8593 res = newTemp(Ity_I8);
8594 stmt( stmt_load(res, mkexpr(EA), NULL/*this is a load*/) );
8596 putIReg( rD_addr, mkWidenFrom8(ty, mkexpr(res), False) );
8597 break;
8600 case 0x074: { // lharx (Load Word and Reserve Indexed)
8601 IRTemp res;
8602 /* According to the PowerPC ISA version 2.05, b0 (called EH
8603 in the documentation) is merely a hint bit to the
8604 hardware, I think as to whether or not contention is
8605 likely. So we can just ignore it. */
8606 DIP("lharx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, b0);
8608 // trap if misaligned
8609 gen_SIGBUS_if_misaligned( EA, 2 );
8611 // and actually do the load
8612 res = newTemp(Ity_I16);
8613 stmt( stmt_load(res, mkexpr(EA), NULL/*this is a load*/) );
8615 putIReg( rD_addr, mkWidenFrom16(ty, mkexpr(res), False) );
8616 break;
8619 case 0x096: {
8620 // stwcx. (Store Word Conditional Indexed, PPC32 p532)
8621 // Note this has to handle stwcx. in both 32- and 64-bit modes,
8622 // so isn't quite as straightforward as it might otherwise be.
8623 IRTemp rS = newTemp(Ity_I32);
8624 IRTemp resSC;
8625 if (b0 != 1) {
8626 vex_printf("dis_memsync(ppc)(stwcx.,b0)\n");
8627 return False;
8629 DIP("stwcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
8631 // trap if misaligned
8632 gen_SIGBUS_if_misaligned( EA, 4 );
8634 // Get the data to be stored, and narrow to 32 bits if necessary
8635 assign( rS, mkNarrowTo32(ty, getIReg(rS_addr)) );
8637 // Do the store, and get success/failure bit into resSC
8638 resSC = newTemp(Ity_I1);
8639 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS)) );
8641 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
8642 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
8643 putCR321(0, binop(Iop_Shl8, unop(Iop_1Uto8, mkexpr(resSC)), mkU8(1)));
8644 putCR0(0, getXER_SO());
8646 /* Note:
8647 If resaddr != lwarx_resaddr, CR0[EQ] is undefined, and
8648 whether rS is stored is dependent on that value. */
8649 /* So I guess we can just ignore this case? */
8650 break;
8653 case 0x2B6: {
8654 // stbcx. (Store Byte Conditional Indexed)
8655 // Note this has to handle stbcx. in both 32- and 64-bit modes,
8656 // so isn't quite as straightforward as it might otherwise be.
8657 IRTemp rS = newTemp(Ity_I8);
8658 IRTemp resSC;
8659 if (b0 != 1) {
8660 vex_printf("dis_memsync(ppc)(stbcx.,b0)\n");
8661 return False;
8663 DIP("stbcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
8665 // Get the data to be stored, and narrow to 32 bits if necessary
8666 assign( rS, mkNarrowTo8(ty, getIReg(rS_addr)) );
8668 // Do the store, and get success/failure bit into resSC
8669 resSC = newTemp(Ity_I1);
8670 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS)) );
8672 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
8673 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
8674 putCR321(0, binop(Iop_Shl8, unop(Iop_1Uto8, mkexpr(resSC)), mkU8(1)));
8675 putCR0(0, getXER_SO());
8677 /* Note:
8678 If resaddr != lbarx_resaddr, CR0[EQ] is undefined, and
8679 whether rS is stored is dependent on that value. */
8680 /* So I guess we can just ignore this case? */
8681 break;
8684 case 0x2D6: {
8685 // sthcx. (Store Word Conditional Indexed, PPC32 p532)
8686 // Note this has to handle sthcx. in both 32- and 64-bit modes,
8687 // so isn't quite as straightforward as it might otherwise be.
8688 IRTemp rS = newTemp(Ity_I16);
8689 IRTemp resSC;
8690 if (b0 != 1) {
8691 vex_printf("dis_memsync(ppc)(stwcx.,b0)\n");
8692 return False;
8694 DIP("sthcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
8696 // trap if misaligned
8697 gen_SIGBUS_if_misaligned( EA, 2 );
8699 // Get the data to be stored, and narrow to 16 bits if necessary
8700 assign( rS, mkNarrowTo16(ty, getIReg(rS_addr)) );
8702 // Do the store, and get success/failure bit into resSC
8703 resSC = newTemp(Ity_I1);
8704 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS)) );
8706 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
8707 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
8708 putCR321(0, binop(Iop_Shl8, unop(Iop_1Uto8, mkexpr(resSC)), mkU8(1)));
8709 putCR0(0, getXER_SO());
8711 /* Note:
8712 If resaddr != lharx_resaddr, CR0[EQ] is undefined, and
8713 whether rS is stored is dependent on that value. */
8714 /* So I guess we can just ignore this case? */
8715 break;
8718 case 0x256: // sync (Synchronize, PPC32 p543),
8719 // also lwsync (L==1), ptesync (L==2)
8720 /* http://sources.redhat.com/ml/binutils/2000-12/msg00311.html
8722 The PowerPC architecture used in IBM chips has expanded
8723 the sync instruction into two variants: lightweight sync
8724 and heavyweight sync. The original sync instruction is
8725 the new heavyweight sync and lightweight sync is a strict
8726 subset of the heavyweight sync functionality. This allows
8727 the programmer to specify a less expensive operation on
8728 high-end systems when the full sync functionality is not
8729 necessary.
8731 The basic "sync" mnemonic now utilizes an operand. "sync"
8732 without an operand now becomes a extended mnemonic for
8733 heavyweight sync. Processors without the lwsync
8734 instruction will not decode the L field and will perform a
8735 heavyweight sync. Everything is backward compatible.
8737 sync = sync 0
8738 lwsync = sync 1
8739 ptesync = sync 2 *** TODO - not implemented ***
8741 if (b11to20 != 0 || b0 != 0) {
8742 vex_printf("dis_memsync(ppc)(sync/lwsync,b11to20|b0)\n");
8743 return False;
8745 if (flag_L != 0/*sync*/ && flag_L != 1/*lwsync*/) {
8746 vex_printf("dis_memsync(ppc)(sync/lwsync,flag_L)\n");
8747 return False;
8749 DIP("%ssync\n", flag_L == 1 ? "lw" : "");
8750 /* Insert a memory fence. It's sometimes important that these
8751 are carried through to the generated code. */
8752 stmt( IRStmt_MBE(Imbe_Fence) );
8753 break;
8755 /* 64bit Memsync */
8756 case 0x054: { // ldarx (Load DWord and Reserve Indexed, PPC64 p473)
8757 IRTemp res;
8758 /* According to the PowerPC ISA version 2.05, b0 (called EH
8759 in the documentation) is merely a hint bit to the
8760 hardware, I think as to whether or not contention is
8761 likely. So we can just ignore it. */
8762 if (!mode64)
8763 return False;
8764 DIP("ldarx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, b0);
8766 // trap if misaligned
8767 gen_SIGBUS_if_misaligned( EA, 8 );
8769 // and actually do the load
8770 res = newTemp(Ity_I64);
8771 stmt( stmt_load( res, mkexpr(EA), NULL/*this is a load*/) );
8773 putIReg( rD_addr, mkexpr(res) );
8774 break;
8777 case 0x0D6: { // stdcx. (Store DWord Condition Indexd, PPC64 p581)
8778 // A marginally simplified version of the stwcx. case
8779 IRTemp rS = newTemp(Ity_I64);
8780 IRTemp resSC;
8781 if (b0 != 1) {
8782 vex_printf("dis_memsync(ppc)(stdcx.,b0)\n");
8783 return False;
8785 if (!mode64)
8786 return False;
8787 DIP("stdcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
8789 // trap if misaligned
8790 gen_SIGBUS_if_misaligned( EA, 8 );
8792 // Get the data to be stored
8793 assign( rS, getIReg(rS_addr) );
8795 // Do the store, and get success/failure bit into resSC
8796 resSC = newTemp(Ity_I1);
8797 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS)) );
8799 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
8800 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
8801 putCR321(0, binop(Iop_Shl8, unop(Iop_1Uto8, mkexpr(resSC)), mkU8(1)));
8802 putCR0(0, getXER_SO());
8804 /* Note:
8805 If resaddr != lwarx_resaddr, CR0[EQ] is undefined, and
8806 whether rS is stored is dependent on that value. */
8807 /* So I guess we can just ignore this case? */
8808 break;
8811 /* 128bit Memsync */
8812 case 0x114: { // lqarx (Load QuadWord and Reserve Indexed)
8813 IRTemp res_hi = newTemp(ty);
8814 IRTemp res_lo = newTemp(ty);
8816 /* According to the PowerPC ISA version 2.07, b0 (called EH
8817 in the documentation) is merely a hint bit to the
8818 hardware, I think as to whether or not contention is
8819 likely. So we can just ignore it. */
8820 DIP("lqarx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, b0);
8822 // trap if misaligned
8823 gen_SIGBUS_if_misaligned( EA, 16 );
8825 // and actually do the load
8826 if (mode64) {
8827 if (host_endness == VexEndnessBE) {
8828 stmt( stmt_load( res_hi,
8829 mkexpr(EA), NULL/*this is a load*/) );
8830 stmt( stmt_load( res_lo,
8831 binop(Iop_Add64, mkexpr(EA), mkU64(8) ),
8832 NULL/*this is a load*/) );
8833 } else {
8834 stmt( stmt_load( res_lo,
8835 mkexpr(EA), NULL/*this is a load*/) );
8836 stmt( stmt_load( res_hi,
8837 binop(Iop_Add64, mkexpr(EA), mkU64(8) ),
8838 NULL/*this is a load*/) );
8840 } else {
8841 stmt( stmt_load( res_hi,
8842 binop( Iop_Add32, mkexpr(EA), mkU32(4) ),
8843 NULL/*this is a load*/) );
8844 stmt( stmt_load( res_lo,
8845 binop( Iop_Add32, mkexpr(EA), mkU32(12) ),
8846 NULL/*this is a load*/) );
8848 putIReg( rD_addr, mkexpr(res_hi) );
8849 putIReg( rD_addr+1, mkexpr(res_lo) );
8850 break;
8853 case 0x0B6: { // stqcx. (Store QuadWord Condition Indexd, PPC64)
8854 // A marginally simplified version of the stwcx. case
8855 IRTemp rS_hi = newTemp(ty);
8856 IRTemp rS_lo = newTemp(ty);
8857 IRTemp resSC;
8858 if (b0 != 1) {
8859 vex_printf("dis_memsync(ppc)(stqcx.,b0)\n");
8860 return False;
8863 DIP("stqcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
8865 // trap if misaligned
8866 gen_SIGBUS_if_misaligned( EA, 16 );
8867 // Get the data to be stored
8868 assign( rS_hi, getIReg(rS_addr) );
8869 assign( rS_lo, getIReg(rS_addr+1) );
8871 // Do the store, and get success/failure bit into resSC
8872 resSC = newTemp(Ity_I1);
8874 if (mode64) {
8875 if (host_endness == VexEndnessBE) {
8876 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS_hi) ) );
8877 store( binop( Iop_Add64, mkexpr(EA), mkU64(8) ),
8878 mkexpr(rS_lo) );
8879 } else {
8880 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS_lo) ) );
8881 store( binop( Iop_Add64, mkexpr(EA), mkU64(8) ),
8882 mkexpr(rS_hi) );
8884 } else {
8885 stmt( stmt_load( resSC, binop( Iop_Add32,
8886 mkexpr(EA),
8887 mkU32(4) ),
8888 mkexpr(rS_hi) ) );
8889 store( binop(Iop_Add32, mkexpr(EA), mkU32(12) ), mkexpr(rS_lo) );
8892 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
8893 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
8894 putCR321(0, binop( Iop_Shl8,
8895 unop(Iop_1Uto8, mkexpr(resSC) ),
8896 mkU8(1)));
8897 putCR0(0, getXER_SO());
8898 break;
8901 default:
8902 vex_printf("dis_memsync(ppc)(opc2)\n");
8903 return False;
8905 break;
8907 default:
8908 vex_printf("dis_memsync(ppc)(opc1)\n");
8909 return False;
8911 return True;
8917 Integer Shift Instructions
8919 static Bool dis_int_shift ( UInt theInstr )
8921 /* X-Form, XS-Form */
8922 UChar opc1 = ifieldOPC(theInstr);
8923 UChar rS_addr = ifieldRegDS(theInstr);
8924 UChar rA_addr = ifieldRegA(theInstr);
8925 UChar rB_addr = ifieldRegB(theInstr);
8926 UChar sh_imm = rB_addr;
8927 UInt opc2 = ifieldOPClo10(theInstr);
8928 UChar b1 = ifieldBIT1(theInstr);
8929 UChar flag_rC = ifieldBIT0(theInstr);
8931 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8932 IRTemp rA = newTemp(ty);
8933 IRTemp rS = newTemp(ty);
8934 IRTemp rB = newTemp(ty);
8935 IRTemp outofrange = newTemp(Ity_I1);
8936 IRTemp rS_lo32 = newTemp(Ity_I32);
8937 IRTemp rB_lo32 = newTemp(Ity_I32);
8938 IRExpr* e_tmp;
8940 assign( rS, getIReg(rS_addr) );
8941 assign( rB, getIReg(rB_addr) );
8942 assign( rS_lo32, mkNarrowTo32(ty, mkexpr(rS)) );
8943 assign( rB_lo32, mkNarrowTo32(ty, mkexpr(rB)) );
8945 if (opc1 == 0x1F) {
8946 switch (opc2) {
8947 case 0x018: { // slw (Shift Left Word, PPC32 p505)
8948 DIP("slw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
8949 rA_addr, rS_addr, rB_addr);
8950 /* rA = rS << rB */
8951 /* ppc32 semantics are:
8952 slw(x,y) = (x << (y & 31)) -- primary result
8953 & ~((y << 26) >>s 31) -- make result 0
8954 for y in 32 .. 63
8956 e_tmp =
8957 binop( Iop_And32,
8958 binop( Iop_Shl32,
8959 mkexpr(rS_lo32),
8960 unop( Iop_32to8,
8961 binop(Iop_And32,
8962 mkexpr(rB_lo32), mkU32(31)))),
8963 unop( Iop_Not32,
8964 binop( Iop_Sar32,
8965 binop(Iop_Shl32, mkexpr(rB_lo32), mkU8(26)),
8966 mkU8(31))) );
8967 assign( rA, mkWidenFrom32(ty, e_tmp, /* Signed */False) );
8968 break;
8971 case 0x318: { // sraw (Shift Right Alg Word, PPC32 p506)
8972 IRTemp sh_amt = newTemp(Ity_I32);
8973 DIP("sraw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
8974 rA_addr, rS_addr, rB_addr);
8975 /* JRS: my reading of the (poorly worded) PPC32 doc p506 is:
8976 amt = rB & 63
8977 rA = Sar32( rS, amt > 31 ? 31 : amt )
8978 XER.CA = amt > 31 ? sign-of-rS : (computation as per srawi)
8980 assign( sh_amt, binop(Iop_And32, mkU32(0x3F),
8981 mkexpr(rB_lo32)) );
8982 assign( outofrange,
8983 binop(Iop_CmpLT32U, mkU32(31), mkexpr(sh_amt)) );
8984 e_tmp = binop( Iop_Sar32,
8985 mkexpr(rS_lo32),
8986 unop( Iop_32to8,
8987 IRExpr_ITE( mkexpr(outofrange),
8988 mkU32(31),
8989 mkexpr(sh_amt)) ) );
8990 assign( rA, mkWidenFrom32(ty, e_tmp, /* Signed */True) );
8992 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SRAW,
8993 mkexpr(rA),
8994 mkWidenFrom32(ty, mkexpr(rS_lo32), True),
8995 mkWidenFrom32(ty, mkexpr(sh_amt), True ),
8996 mkWidenFrom32(ty, getXER_CA_32(), True) );
8997 break;
9000 case 0x338: // srawi (Shift Right Alg Word Immediate, PPC32 p507)
9001 DIP("srawi%s r%u,r%u,%d\n", flag_rC ? ".":"",
9002 rA_addr, rS_addr, sh_imm);
9003 vassert(sh_imm < 32);
9004 if (mode64) {
9005 assign( rA, binop(Iop_Sar64,
9006 binop(Iop_Shl64, getIReg(rS_addr),
9007 mkU8(32)),
9008 mkU8(32 + sh_imm)) );
9009 } else {
9010 assign( rA, binop(Iop_Sar32, mkexpr(rS_lo32),
9011 mkU8(sh_imm)) );
9014 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SRAWI,
9015 mkexpr(rA),
9016 mkWidenFrom32(ty, mkexpr(rS_lo32), /* Syned */True),
9017 mkSzImm(ty, sh_imm),
9018 mkWidenFrom32(ty, getXER_CA_32(), /* Syned */False) );
9019 break;
9021 case 0x218: // srw (Shift Right Word, PPC32 p508)
9022 DIP("srw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
9023 rA_addr, rS_addr, rB_addr);
9024 /* rA = rS >>u rB */
9025 /* ppc32 semantics are:
9026 srw(x,y) = (x >>u (y & 31)) -- primary result
9027 & ~((y << 26) >>s 31) -- make result 0
9028 for y in 32 .. 63
9030 e_tmp =
9031 binop(
9032 Iop_And32,
9033 binop( Iop_Shr32,
9034 mkexpr(rS_lo32),
9035 unop( Iop_32to8,
9036 binop(Iop_And32, mkexpr(rB_lo32),
9037 mkU32(31)))),
9038 unop( Iop_Not32,
9039 binop( Iop_Sar32,
9040 binop(Iop_Shl32, mkexpr(rB_lo32),
9041 mkU8(26)),
9042 mkU8(31))));
9043 assign( rA, mkWidenFrom32(ty, e_tmp, /* Signed */False) );
9044 break;
9047 /* 64bit Shifts */
9048 case 0x01B: // sld (Shift Left DWord, PPC64 p568)
9049 DIP("sld%s r%u,r%u,r%u\n",
9050 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
9051 /* rA = rS << rB */
9052 /* ppc64 semantics are:
9053 slw(x,y) = (x << (y & 63)) -- primary result
9054 & ~((y << 57) >>s 63) -- make result 0
9055 for y in 64 ..
9057 assign( rA,
9058 binop(
9059 Iop_And64,
9060 binop( Iop_Shl64,
9061 mkexpr(rS),
9062 unop( Iop_64to8,
9063 binop(Iop_And64, mkexpr(rB), mkU64(63)))),
9064 unop( Iop_Not64,
9065 binop( Iop_Sar64,
9066 binop(Iop_Shl64, mkexpr(rB), mkU8(57)),
9067 mkU8(63)))) );
9068 break;
9070 case 0x31A: { // srad (Shift Right Alg DWord, PPC64 p570)
9071 IRTemp sh_amt = newTemp(Ity_I64);
9072 DIP("srad%s r%u,r%u,r%u\n",
9073 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
9074 /* amt = rB & 127
9075 rA = Sar64( rS, amt > 63 ? 63 : amt )
9076 XER.CA = amt > 63 ? sign-of-rS : (computation as per srawi)
9078 assign( sh_amt, binop(Iop_And64, mkU64(0x7F), mkexpr(rB)) );
9079 assign( outofrange,
9080 binop(Iop_CmpLT64U, mkU64(63), mkexpr(sh_amt)) );
9081 assign( rA,
9082 binop( Iop_Sar64,
9083 mkexpr(rS),
9084 unop( Iop_64to8,
9085 IRExpr_ITE( mkexpr(outofrange),
9086 mkU64(63),
9087 mkexpr(sh_amt)) ))
9089 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SRAD,
9090 mkexpr(rA), mkexpr(rS), mkexpr(sh_amt),
9091 mkWidenFrom32(ty, getXER_CA_32(), /* Syned */False) );
9092 break;
9095 case 0x33A: case 0x33B: // sradi (Shr Alg DWord Imm, PPC64 p571)
9096 sh_imm |= b1<<5;
9097 vassert(sh_imm < 64);
9098 DIP("sradi%s r%u,r%u,%u\n",
9099 flag_rC ? ".":"", rA_addr, rS_addr, sh_imm);
9100 assign( rA, binop(Iop_Sar64, getIReg(rS_addr), mkU8(sh_imm)) );
9102 set_XER_CA_CA32( ty, PPCG_FLAG_OP_SRADI,
9103 mkexpr(rA),
9104 getIReg(rS_addr),
9105 mkU64(sh_imm),
9106 mkWidenFrom32(ty, getXER_CA_32(), /* Syned */False) );
9107 break;
9109 case 0x21B: // srd (Shift Right DWord, PPC64 p574)
9110 DIP("srd%s r%u,r%u,r%u\n",
9111 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
9112 /* rA = rS >>u rB */
9113 /* ppc semantics are:
9114 srw(x,y) = (x >>u (y & 63)) -- primary result
9115 & ~((y << 57) >>s 63) -- make result 0
9116 for y in 64 .. 127
9118 assign( rA,
9119 binop(
9120 Iop_And64,
9121 binop( Iop_Shr64,
9122 mkexpr(rS),
9123 unop( Iop_64to8,
9124 binop(Iop_And64, mkexpr(rB), mkU64(63)))),
9125 unop( Iop_Not64,
9126 binop( Iop_Sar64,
9127 binop(Iop_Shl64, mkexpr(rB), mkU8(57)),
9128 mkU8(63)))) );
9129 break;
9131 default:
9132 vex_printf("dis_int_shift(ppc)(opc2)\n");
9133 return False;
9135 } else {
9136 vex_printf("dis_int_shift(ppc)(opc1)\n");
9137 return False;
9140 putIReg( rA_addr, mkexpr(rA) );
9142 if (flag_rC) {
9143 set_CR0( mkexpr(rA) );
9145 return True;
9151 Integer Load/Store Reverse Instructions
9153 /* Generates code to swap the byte order in an Ity_I32. */
9154 static IRExpr* /* :: Ity_I32 */ gen_byterev32 ( IRTemp t )
9156 vassert(typeOfIRTemp(irsb->tyenv, t) == Ity_I32);
9157 return
9158 binop(Iop_Or32,
9159 binop(Iop_Shl32, mkexpr(t), mkU8(24)),
9160 binop(Iop_Or32,
9161 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t), mkU8(8)),
9162 mkU32(0x00FF0000)),
9163 binop(Iop_Or32,
9164 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t), mkU8(8)),
9165 mkU32(0x0000FF00)),
9166 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t), mkU8(24)),
9167 mkU32(0x000000FF) )
9168 )));
9171 /* Generates code to swap the byte order in the lower half of an Ity_I32,
9172 and zeroes the upper half. */
9173 static IRExpr* /* :: Ity_I32 */ gen_byterev16 ( IRTemp t )
9175 vassert(typeOfIRTemp(irsb->tyenv, t) == Ity_I32);
9176 return
9177 binop(Iop_Or32,
9178 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t), mkU8(8)),
9179 mkU32(0x0000FF00)),
9180 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t), mkU8(8)),
9181 mkU32(0x000000FF))
9185 static Bool dis_int_ldst_rev ( UInt theInstr )
9187 /* X-Form */
9188 UChar opc1 = ifieldOPC(theInstr);
9189 UChar rD_addr = ifieldRegDS(theInstr);
9190 UChar rS_addr = rD_addr;
9191 UChar rA_addr = ifieldRegA(theInstr);
9192 UChar rB_addr = ifieldRegB(theInstr);
9193 UInt opc2 = ifieldOPClo10(theInstr);
9194 UChar b0 = ifieldBIT0(theInstr);
9196 IRType ty = mode64 ? Ity_I64 : Ity_I32;
9197 IRTemp EA = newTemp(ty);
9198 IRTemp w1 = newTemp(Ity_I32);
9199 IRTemp w2 = newTemp(Ity_I32);
9201 if (opc1 != 0x1F || b0 != 0) {
9202 vex_printf("dis_int_ldst_rev(ppc)(opc1|b0)\n");
9203 return False;
9206 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
9208 switch (opc2) {
9210 case 0x316: // lhbrx (Load Halfword Byte-Reverse Indexed, PPC32 p449)
9211 DIP("lhbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
9212 assign( w1, unop(Iop_16Uto32, load(Ity_I16, mkexpr(EA))) );
9213 assign( w2, gen_byterev16(w1) );
9214 putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(w2),
9215 /* Signed */False) );
9216 break;
9218 case 0x216: // lwbrx (Load Word Byte-Reverse Indexed, PPC32 p459)
9219 DIP("lwbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
9220 assign( w1, load(Ity_I32, mkexpr(EA)) );
9221 assign( w2, gen_byterev32(w1) );
9222 putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(w2),
9223 /* Signed */False) );
9224 break;
9226 case 0x214: // ldbrx (Load Doubleword Byte-Reverse Indexed)
9228 IRExpr * nextAddr;
9229 IRTemp w3 = newTemp( Ity_I32 );
9230 IRTemp w4 = newTemp( Ity_I32 );
9231 DIP("ldbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
9232 assign( w1, load( Ity_I32, mkexpr( EA ) ) );
9233 assign( w2, gen_byterev32( w1 ) );
9234 nextAddr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
9235 ty == Ity_I64 ? mkU64( 4 ) : mkU32( 4 ) );
9236 assign( w3, load( Ity_I32, nextAddr ) );
9237 assign( w4, gen_byterev32( w3 ) );
9238 if (host_endness == VexEndnessLE)
9239 putIReg( rD_addr, binop( Iop_32HLto64, mkexpr( w2 ), mkexpr( w4 ) ) );
9240 else
9241 putIReg( rD_addr, binop( Iop_32HLto64, mkexpr( w4 ), mkexpr( w2 ) ) );
9242 break;
9245 case 0x396: // sthbrx (Store Half Word Byte-Reverse Indexed, PPC32 p523)
9246 DIP("sthbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
9247 assign( w1, mkNarrowTo32(ty, getIReg(rS_addr)) );
9248 store( mkexpr(EA), unop(Iop_32to16, gen_byterev16(w1)) );
9249 break;
9251 case 0x296: // stwbrx (Store Word Byte-Reverse Indxd, PPC32 p531)
9252 DIP("stwbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
9253 assign( w1, mkNarrowTo32(ty, getIReg(rS_addr)) );
9254 store( mkexpr(EA), gen_byterev32(w1) );
9255 break;
9257 case 0x294: // stdbrx (Store Doubleword Byte-Reverse Indexed)
9259 IRTemp lo = newTemp(Ity_I32);
9260 IRTemp hi = newTemp(Ity_I32);
9261 IRTemp rS = newTemp(Ity_I64);
9262 assign( rS, getIReg( rS_addr ) );
9263 DIP("stdbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
9264 assign(lo, unop(Iop_64HIto32, mkexpr(rS)));
9265 assign(hi, unop(Iop_64to32, mkexpr(rS)));
9266 store( mkexpr( EA ),
9267 binop( Iop_32HLto64, gen_byterev32( hi ),
9268 gen_byterev32( lo ) ) );
9269 break;
9272 default:
9273 vex_printf("dis_int_ldst_rev(ppc)(opc2)\n");
9274 return False;
9276 return True;
9282 Processor Control Instructions
9284 static Bool dis_proc_ctl ( const VexAbiInfo* vbi, UInt theInstr )
9286 UChar opc1 = ifieldOPC(theInstr);
9288 /* X-Form */
9289 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
9290 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
9291 UChar rD_addr = ifieldRegDS(theInstr);
9292 UInt b11to20 = IFIELD( theInstr, 11, 10 );
9294 /* XFX-Form */
9295 UChar rS_addr = rD_addr;
9296 UInt SPR = b11to20;
9297 UInt TBR = b11to20;
9298 UChar b20 = toUChar( IFIELD( theInstr, 20, 1 ) );
9299 UInt CRM = IFIELD( theInstr, 12, 8 );
9300 UChar b11 = toUChar( IFIELD( theInstr, 11, 1 ) );
9302 UInt opc2 = ifieldOPClo10(theInstr);
9303 UChar b0 = ifieldBIT0(theInstr);
9305 IRType ty = mode64 ? Ity_I64 : Ity_I32;
9306 IRTemp rS = newTemp(ty);
9307 assign( rS, getIReg(rS_addr) );
9309 /* Reorder SPR field as per PPC32 p470 */
9310 SPR = ((SPR & 0x1F) << 5) | ((SPR >> 5) & 0x1F);
9311 /* Reorder TBR field as per PPC32 p475 */
9312 TBR = ((TBR & 31) << 5) | ((TBR >> 5) & 31);
9314 /* b0 = 0, inst is treated as floating point inst for reservation purposes
9315 * b0 = 1, inst is treated as vector inst for reservation purposes
9317 if (opc1 != 0x1F) {
9318 vex_printf("dis_proc_ctl(ppc)(opc1|b%d)\n", b0);
9319 return False;
9322 switch (opc2) {
9323 /* X-Form */
9324 case 0x200: { // mcrxr (Move to Cond Register from XER, PPC32 p466)
9325 if (b21to22 != 0 || b11to20 != 0) {
9326 vex_printf("dis_proc_ctl(ppc)(mcrxr,b21to22|b11to20)\n");
9327 return False;
9329 DIP("mcrxr crf%d\n", crfD);
9330 /* Move XER[0-3] (the top 4 bits of XER) to CR[crfD] */
9331 putGST_field( PPC_GST_CR,
9332 getGST_field( PPC_GST_XER, 7 ),
9333 crfD );
9335 // Clear XER[0-3]
9336 putXER_SO( mkU8(0) );
9337 putXER_OV( mkU8(0) );
9338 putXER_CA( mkU8(0) );
9339 break;
9342 case 0x013:
9343 // b11to20==0: mfcr (Move from Cond Register, PPC32 p467)
9344 // b20==1 & b11==0: mfocrf (Move from One CR Field)
9345 // However it seems that the 'mfcr' behaviour is an acceptable
9346 // implementation of mfocr (from the 2.02 arch spec)
9347 if (b11to20 == 0) {
9348 DIP("mfcr r%u\n", rD_addr);
9349 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_CR ),
9350 /* Signed */False) );
9351 break;
9353 if (b20 == 1 && b11 == 0) {
9354 DIP("mfocrf r%u,%u\n", rD_addr, CRM);
9355 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_CR ),
9356 /* Signed */False) );
9357 break;
9359 /* not decodable */
9360 return False;
9362 /* XFX-Form */
9363 case 0x153: // mfspr (Move from Special-Purpose Register, PPC32 p470)
9365 switch (SPR) { // Choose a register...
9366 case 0x1:
9367 DIP("mfxer r%u\n", rD_addr);
9368 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_XER ),
9369 /* Signed */False) );
9370 break;
9371 case 0x3: // 131
9372 DIP("mfspr r%u (DSCR)\n", rD_addr);
9373 putIReg( rD_addr, getGST( PPC_GST_DSCR) );
9374 break;
9375 case 0x8:
9376 DIP("mflr r%u\n", rD_addr);
9377 putIReg( rD_addr, getGST( PPC_GST_LR ) );
9378 break;
9379 case 0x9:
9380 DIP("mfctr r%u\n", rD_addr);
9381 putIReg( rD_addr, getGST( PPC_GST_CTR ) );
9382 break;
9383 case 0x80: // 128
9384 DIP("mfspr r%u (TFHAR)\n", rD_addr);
9385 putIReg( rD_addr, getGST( PPC_GST_TFHAR) );
9386 break;
9387 case 0x81: // 129
9388 DIP("mfspr r%u (TFIAR)\n", rD_addr);
9389 putIReg( rD_addr, getGST( PPC_GST_TFIAR) );
9390 break;
9391 case 0x82: // 130
9392 DIP("mfspr r%u (TEXASR)\n", rD_addr);
9393 putIReg( rD_addr, getGST( PPC_GST_TEXASR) );
9394 break;
9395 case 0x83: // 131
9396 DIP("mfspr r%u (TEXASRU)\n", rD_addr);
9397 putIReg( rD_addr, getGST( PPC_GST_TEXASRU) );
9398 break;
9399 case 0x9F: // 159
9400 DIP("mfspr r%u (PSPB)\n", rD_addr);
9401 putIReg( rD_addr, getGST( PPC_GST_PSPB) );
9402 break;
9403 case 0x380: // 896
9404 DIP("mfspr r%u (PPR)\n", rD_addr);
9405 putIReg( rD_addr, getGST( PPC_GST_PPR) );
9406 break;
9407 case 0x382: // 898
9408 DIP("mfspr r%u (PPR)32\n", rD_addr);
9409 putIReg( rD_addr, getGST( PPC_GST_PPR32) );
9410 break;
9411 case 0x100:
9412 DIP("mfvrsave r%u\n", rD_addr);
9413 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_VRSAVE ),
9414 /* Signed */False) );
9415 break;
9417 case 0x103:
9418 DIP("mfspr r%u, SPRG3(readonly)\n", rD_addr);
9419 putIReg( rD_addr, getGST( PPC_GST_SPRG3_RO ) );
9420 break;
9422 case 268 /* 0x10C TB - 64 bit time base register */:
9424 IRTemp val = newTemp(Ity_I64);
9425 IRExpr** args = mkIRExprVec_0();
9426 IRDirty* d = unsafeIRDirty_1_N(
9427 val,
9428 0/*regparms*/,
9429 "ppcg_dirtyhelper_MFTB",
9430 fnptr_to_fnentry(vbi,
9431 &ppcg_dirtyhelper_MFTB),
9432 args );
9433 /* execute the dirty call, dumping the result in val. */
9434 stmt( IRStmt_Dirty(d) );
9435 putIReg( rD_addr, (mode64) ? mkexpr(val) :
9436 unop(Iop_64to32, mkexpr(val)) );
9438 break;
9440 case 269 /* 0x10D TBU - upper 32-bits of time base register */:
9442 DIP("mfspr r%u,%u", rD_addr, SPR);
9443 IRTemp val = newTemp(Ity_I64);
9444 IRExpr** args = mkIRExprVec_0();
9445 IRDirty* d = unsafeIRDirty_1_N(
9446 val,
9447 0/*regparms*/,
9448 "ppcg_dirtyhelper_MFTB",
9449 fnptr_to_fnentry(vbi,
9450 &ppcg_dirtyhelper_MFTB),
9451 args );
9452 /* execute the dirty call, dumping the result in val. */
9453 stmt( IRStmt_Dirty(d) );
9454 putIReg( rD_addr,
9455 mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(val)),
9456 /* Signed */False) );
9457 break;
9459 case 284 /* 0x1 TBL - lower 32-bits of time base register */:
9461 DIP("mfspr r%u,%u", rD_addr, SPR);
9462 IRTemp val = newTemp(Ity_I64);
9463 IRExpr** args = mkIRExprVec_0();
9464 IRDirty* d = unsafeIRDirty_1_N(
9465 val,
9466 0/*regparms*/,
9467 "ppcg_dirtyhelper_MFTB",
9468 fnptr_to_fnentry(vbi,
9469 &ppcg_dirtyhelper_MFTB),
9470 args );
9471 /* execute the dirty call, dumping the result in val. */
9472 stmt( IRStmt_Dirty(d) );
9473 putIReg( rD_addr,
9474 mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(val)),
9475 /* Signed */False) );
9476 break;
9479 /* Again, runs natively on PPC7400 (7447, really). Not
9480 bothering with a feature test. */
9481 case 287: /* 0x11F */ {
9482 IRTemp val = newTemp(Ity_I32);
9483 IRExpr** args = mkIRExprVec_0();
9484 IRDirty* d = unsafeIRDirty_1_N(
9485 val,
9486 0/*regparms*/,
9487 "ppc32g_dirtyhelper_MFSPR_287",
9488 fnptr_to_fnentry
9489 (vbi, &ppc32g_dirtyhelper_MFSPR_287),
9490 args
9492 /* execute the dirty call, dumping the result in val. */
9493 stmt( IRStmt_Dirty(d) );
9494 putIReg( rD_addr,
9495 mkWidenFrom32(ty, mkexpr(val), False/*unsigned*/) );
9496 DIP("mfspr r%u,%u", rD_addr, SPR);
9497 break;
9500 default:
9501 vex_printf("dis_proc_ctl(ppc)(mfspr,SPR)(0x%x)\n", SPR);
9502 return False;
9504 break;
9506 case 0x173: { // mftb (Move from Time Base, PPC32 p475)
9507 IRTemp val = newTemp(Ity_I64);
9508 IRExpr** args = mkIRExprVec_0();
9509 IRDirty* d = unsafeIRDirty_1_N(
9510 val,
9511 0/*regparms*/,
9512 "ppcg_dirtyhelper_MFTB",
9513 fnptr_to_fnentry(vbi, &ppcg_dirtyhelper_MFTB),
9514 args );
9515 /* execute the dirty call, dumping the result in val. */
9516 stmt( IRStmt_Dirty(d) );
9518 switch (TBR) {
9519 case 269:
9520 DIP("mftbu r%u", rD_addr);
9521 putIReg( rD_addr,
9522 mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(val)),
9523 /* Signed */False) );
9524 break;
9525 case 268:
9526 DIP("mftb r%u", rD_addr);
9527 putIReg( rD_addr, (mode64) ? mkexpr(val) :
9528 unop(Iop_64to32, mkexpr(val)) );
9529 break;
9530 case 284:
9531 DIP("mftbl r%u", rD_addr);
9532 putIReg( rD_addr,
9533 mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(val)),
9534 /* Signed */False) );
9535 break;
9536 default:
9537 return False; /* illegal instruction */
9539 break;
9542 case 0x090: {
9543 // b20==0: mtcrf (Move to Cond Register Fields, PPC32 p477)
9544 // b20==1: mtocrf (Move to One Cond Reg Field)
9545 Int cr;
9546 UChar shft;
9547 if (b11 != 0)
9548 return False;
9549 if (b20 == 1) {
9550 /* ppc64 v2.02 spec says mtocrf gives undefined outcome if >
9551 1 field is written. It seems more robust to decline to
9552 decode the insn if so. */
9553 switch (CRM) {
9554 case 0x01: case 0x02: case 0x04: case 0x08:
9555 case 0x10: case 0x20: case 0x40: case 0x80:
9556 break;
9557 default:
9558 return False;
9561 DIP("%s 0x%x,r%u\n", b20==1 ? "mtocrf" : "mtcrf",
9562 CRM, rS_addr);
9563 /* Write to each field specified by CRM */
9564 for (cr = 0; cr < 8; cr++) {
9565 if ((CRM & (1 << (7-cr))) == 0)
9566 continue;
9567 shft = 4*(7-cr);
9568 putGST_field( PPC_GST_CR,
9569 binop(Iop_Shr32,
9570 mkNarrowTo32(ty, mkexpr(rS)),
9571 mkU8(shft)), cr );
9573 break;
9576 case 0x1D3: // mtspr (Move to Special-Purpose Register, PPC32 p483)
9578 switch (SPR) { // Choose a register...
9579 case 0x1:
9580 DIP("mtxer r%u\n", rS_addr);
9581 putGST( PPC_GST_XER, mkNarrowTo32(ty, mkexpr(rS)) );
9582 break;
9583 case 0x3:
9584 DIP("mtspr r%u (DSCR)\n", rS_addr);
9585 putGST( PPC_GST_DSCR, mkexpr(rS) );
9586 break;
9587 case 0x8:
9588 DIP("mtlr r%u\n", rS_addr);
9589 putGST( PPC_GST_LR, mkexpr(rS) );
9590 break;
9591 case 0x9:
9592 DIP("mtctr r%u\n", rS_addr);
9593 putGST( PPC_GST_CTR, mkexpr(rS) );
9594 break;
9595 case 0x100:
9596 DIP("mtvrsave r%u\n", rS_addr);
9597 putGST( PPC_GST_VRSAVE, mkNarrowTo32(ty, mkexpr(rS)) );
9598 break;
9599 case 0x80: // 128
9600 DIP("mtspr r%u (TFHAR)\n", rS_addr);
9601 putGST( PPC_GST_TFHAR, mkexpr(rS) );
9602 break;
9603 case 0x81: // 129
9604 DIP("mtspr r%u (TFIAR)\n", rS_addr);
9605 putGST( PPC_GST_TFIAR, mkexpr(rS) );
9606 break;
9607 case 0x82: // 130
9608 DIP("mtspr r%u (TEXASR)\n", rS_addr);
9609 putGST( PPC_GST_TEXASR, mkexpr(rS) );
9610 break;
9611 case 0x9F: // 159
9612 DIP("mtspr r%u (PSPB)\n", rS_addr);
9613 putGST( PPC_GST_PSPB, mkexpr(rS) );
9614 break;
9615 case 0x380: // 896
9616 DIP("mtspr r%u (PPR)\n", rS_addr);
9617 putGST( PPC_GST_PPR, mkexpr(rS) );
9618 break;
9619 case 0x382: // 898
9620 DIP("mtspr r%u (PPR32)\n", rS_addr);
9621 putGST( PPC_GST_PPR32, mkexpr(rS) );
9622 break;
9623 default:
9624 vex_printf("dis_proc_ctl(ppc)(mtspr,SPR)(%u)\n", SPR);
9625 return False;
9627 break;
9629 case 0x33: // mfvsrd
9631 UChar XS = ifieldRegXS( theInstr );
9632 UChar rA_addr = ifieldRegA(theInstr);
9633 IRExpr * high64;
9634 IRTemp vS = newTemp( Ity_V128 );
9635 DIP("mfvsrd r%u,vsr%d\n", rA_addr, XS);
9637 /* XS = SX || S
9638 * For SX=0, mfvsrd is treated as a Floating-Point
9639 * instruction in terms of resource availability.
9640 * For SX=1, mfvsrd is treated as a Vector instruction in
9641 * terms of resource availability.
9642 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
9644 assign( vS, getVSReg( XS ) );
9645 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
9646 putIReg( rA_addr, (mode64) ? high64 :
9647 unop( Iop_64to32, high64 ) );
9648 break;
9651 case 0x73: // mfvsrwz
9653 UChar XS = ifieldRegXS( theInstr );
9654 UChar rA_addr = ifieldRegA(theInstr);
9655 IRExpr * high64;
9656 IRTemp vS = newTemp( Ity_V128 );
9657 DIP("mfvsrwz r%u,vsr%d\n", rA_addr, XS);
9658 /* XS = SX || S
9659 * For SX=0, mfvsrwz is treated as a Floating-Point
9660 * instruction in terms of resource availability.
9661 * For SX=1, mfvsrwz is treated as a Vector instruction in
9662 * terms of resource availability.
9663 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
9666 assign( vS, getVSReg( XS ) );
9667 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
9668 /* move value to the destination setting the upper 32-bits to zero */
9669 putIReg( rA_addr, (mode64) ?
9670 binop( Iop_And64, high64, mkU64( 0xFFFFFFFF ) ) :
9671 unop( Iop_64to32,
9672 binop( Iop_And64, high64, mkU64( 0xFFFFFFFF ) ) ) );
9673 break;
9676 case 0xB3: // mtvsrd
9678 UChar XT = ifieldRegXT( theInstr );
9679 UChar rA_addr = ifieldRegA(theInstr);
9680 IRTemp rA = newTemp(ty);
9681 DIP("mtvsrd vsr%d,r%u\n", XT, rA_addr);
9682 /* XS = SX || S
9683 * For SX=0, mfvsrd is treated as a Floating-Point
9684 * instruction in terms of resource availability.
9685 * For SX=1, mfvsrd is treated as a Vector instruction in
9686 * terms of resource availability.
9687 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
9689 assign( rA, getIReg(rA_addr) );
9691 if (mode64)
9692 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( rA ), mkU64( 0 ) ) );
9693 else
9694 putVSReg( XT, binop( Iop_64HLtoV128,
9695 binop( Iop_32HLto64,
9696 mkU32( 0 ),
9697 mkexpr( rA ) ),
9698 mkU64( 0 ) ) );
9699 break;
9702 case 0xD3: // mtvsrwa
9704 UChar XT = ifieldRegXT( theInstr );
9705 UChar rA_addr = ifieldRegA(theInstr);
9706 IRTemp rA = newTemp( Ity_I32 );
9707 DIP("mtvsrwa vsr%d,r%u\n", XT, rA_addr);
9708 /* XS = SX || S
9709 * For SX=0, mtvsrwa is treated as a Floating-Point
9710 * instruction in terms of resource availability.
9711 * For SX=1, mtvsrwa is treated as a Vector instruction in
9712 * terms of resource availability.
9713 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
9715 if (mode64)
9716 assign( rA, unop( Iop_64to32, getIReg( rA_addr ) ) );
9717 else
9718 assign( rA, getIReg(rA_addr) );
9720 putVSReg( XT, binop( Iop_64HLtoV128,
9721 unop( Iop_32Sto64, mkexpr( rA ) ),
9722 mkU64( 0 ) ) );
9723 break;
9726 case 0xF3: // mtvsrwz
9728 UChar XT = ifieldRegXT( theInstr );
9729 UChar rA_addr = ifieldRegA(theInstr);
9730 IRTemp rA = newTemp( Ity_I32 );
9731 DIP("mtvsrwz vsr%d,r%u\n", rA_addr, XT);
9732 /* XS = SX || S
9733 * For SX=0, mtvsrwz is treated as a Floating-Point
9734 * instruction in terms of resource availability.
9735 * For SX=1, mtvsrwz is treated as a Vector instruction in
9736 * terms of resource availability.
9737 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
9739 if (mode64)
9740 assign( rA, unop( Iop_64to32, getIReg( rA_addr ) ) );
9741 else
9742 assign( rA, getIReg(rA_addr) );
9744 putVSReg( XT, binop( Iop_64HLtoV128,
9745 binop( Iop_32HLto64, mkU32( 0 ), mkexpr ( rA ) ),
9746 mkU64( 0 ) ) );
9747 break;
9750 default:
9751 vex_printf("dis_proc_ctl(ppc)(opc2)\n");
9752 return False;
9754 return True;
9759 Cache Management Instructions
9761 static Bool dis_cache_manage ( UInt theInstr,
9762 DisResult* dres,
9763 const VexArchInfo* guest_archinfo )
9765 /* X-Form */
9766 UChar opc1 = ifieldOPC(theInstr);
9767 UChar b21to25 = ifieldRegDS(theInstr);
9768 UChar rA_addr = ifieldRegA(theInstr);
9769 UChar rB_addr = ifieldRegB(theInstr);
9770 UInt opc2 = ifieldOPClo10(theInstr);
9771 UChar b0 = ifieldBIT0(theInstr);
9772 UInt lineszB = guest_archinfo->ppc_icache_line_szB;
9773 Bool is_dcbzl = False;
9775 IRType ty = mode64 ? Ity_I64 : Ity_I32;
9777 // Check for valid hint values for dcbt and dcbtst as currently described in
9778 // ISA 2.07. If valid, then we simply set b21to25 to zero since we have no
9779 // means of modeling the hint anyway.
9780 if (opc1 == 0x1F && ((opc2 == 0x116) || (opc2 == 0xF6))) {
9781 if (b21to25 == 0x10 || b21to25 < 0x10)
9782 b21to25 = 0;
9784 if (opc1 == 0x1F && opc2 == 0x116 && b21to25 == 0x11)
9785 b21to25 = 0;
9787 if (opc1 == 0x1F && opc2 == 0x3F6) { // dcbz
9788 if (b21to25 == 1) {
9789 is_dcbzl = True;
9790 b21to25 = 0;
9791 if (!(guest_archinfo->ppc_dcbzl_szB)) {
9792 vex_printf("dis_cache_manage(ppc)(dcbzl not supported by host)\n");
9793 return False;
9798 if (opc1 != 0x1F || b0 != 0) {
9799 if (0) vex_printf("dis_cache_manage %d %d\n",
9800 opc1, b0);
9801 vex_printf("dis_cache_manage(ppc)(opc1|b0)\n");
9802 return False;
9805 /* stay sane .. */
9806 vassert(lineszB == 16 || lineszB == 32 || lineszB == 64 || lineszB == 128);
9808 switch (opc2) {
9809 //zz case 0x2F6: // dcba (Data Cache Block Allocate, PPC32 p380)
9810 //zz vassert(0); /* AWAITING TEST CASE */
9811 //zz DIP("dcba r%u,r%u\n", rA_addr, rB_addr);
9812 //zz if (0) vex_printf("vex ppc->IR: kludged dcba\n");
9813 //zz break;
9815 case 0x056: // dcbf (Data Cache Block Flush, PPC32 p382)
9816 DIP("dcbf r%u,r%u\n", rA_addr, rB_addr);
9817 /* nop as far as vex is concerned */
9818 break;
9820 case 0x036: // dcbst (Data Cache Block Store, PPC32 p384)
9821 DIP("dcbst r%u,r%u\n", rA_addr, rB_addr);
9822 /* nop as far as vex is concerned */
9823 break;
9825 case 0x116: // dcbt (Data Cache Block Touch, PPC32 p385)
9826 DIP("dcbt r%u,r%u\n", rA_addr, rB_addr);
9827 /* nop as far as vex is concerned */
9828 break;
9830 case 0x0F6: // dcbtst (Data Cache Block Touch for Store, PPC32 p386)
9831 DIP("dcbtst r%u,r%u\n", rA_addr, rB_addr);
9832 /* nop as far as vex is concerned */
9833 break;
9835 case 0x3F6: { // dcbz (Data Cache Block Clear to Zero, PPC32 p387)
9836 // dcbzl (Data Cache Block Clear to Zero Long, bug#135264)
9837 /* Clear all bytes in cache block at (rA|0) + rB. */
9838 IRTemp EA = newTemp(ty);
9839 IRTemp addr = newTemp(ty);
9840 IRExpr* irx_addr;
9841 UInt i;
9842 UInt clearszB;
9843 if (is_dcbzl) {
9844 clearszB = guest_archinfo->ppc_dcbzl_szB;
9845 DIP("dcbzl r%u,r%u\n", rA_addr, rB_addr);
9847 else {
9848 clearszB = guest_archinfo->ppc_dcbz_szB;
9849 DIP("dcbz r%u,r%u\n", rA_addr, rB_addr);
9852 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
9854 if (mode64) {
9855 /* Round EA down to the start of the containing block. */
9856 assign( addr, binop( Iop_And64,
9857 mkexpr(EA),
9858 mkU64( ~((ULong)clearszB-1) )) );
9860 for (i = 0; i < clearszB / 8; i++) {
9861 irx_addr = binop( Iop_Add64, mkexpr(addr), mkU64(i*8) );
9862 store( irx_addr, mkU64(0) );
9864 } else {
9865 /* Round EA down to the start of the containing block. */
9866 assign( addr, binop( Iop_And32,
9867 mkexpr(EA),
9868 mkU32( ~(clearszB-1) )) );
9870 for (i = 0; i < clearszB / 4; i++) {
9871 irx_addr = binop( Iop_Add32, mkexpr(addr), mkU32(i*4) );
9872 store( irx_addr, mkU32(0) );
9875 break;
9878 case 0x3D6: {
9879 // icbi (Instruction Cache Block Invalidate, PPC32 p431)
9880 /* Invalidate all translations containing code from the cache
9881 block at (rA|0) + rB. */
9882 IRTemp EA = newTemp(ty);
9883 IRTemp addr = newTemp(ty);
9884 DIP("icbi r%u,r%u\n", rA_addr, rB_addr);
9885 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
9887 /* Round EA down to the start of the containing block. */
9888 assign( addr, binop( mkSzOp(ty, Iop_And8),
9889 mkexpr(EA),
9890 mkSzImm(ty, ~(((ULong)lineszB)-1) )) );
9891 putGST( PPC_GST_CMSTART, mkexpr(addr) );
9892 putGST( PPC_GST_CMLEN, mkSzImm(ty, lineszB) );
9894 /* be paranoid ... */
9895 stmt( IRStmt_MBE(Imbe_Fence) );
9897 putGST( PPC_GST_CIA, mkSzImm(ty, nextInsnAddr()));
9898 dres->jk_StopHere = Ijk_InvalICache;
9899 dres->whatNext = Dis_StopHere;
9900 break;
9903 default:
9904 vex_printf("dis_cache_manage(ppc)(opc2)\n");
9905 return False;
9907 return True;
9911 /*------------------------------------------------------------*/
9912 /*--- Floating Point Helpers ---*/
9913 /*------------------------------------------------------------*/
9915 /* --------- Synthesise a 2-bit FPU rounding mode. --------- */
9916 /* Produces a value in 0 .. 3, which is encoded as per the type
9917 IRRoundingMode. PPCRoundingMode encoding is different to
9918 IRRoundingMode, so need to map it.
9921 static IRExpr* /* :: Ity_I32 */ set_round_to_Oddmode ( void )
9923 /* PPC/ valgrind have two-bits to designate the rounding mode.
9924 ISA 3.0 adds instructions than can use a round to odd mode
9925 but did not change the number of bits for the rm. Basically,
9926 they added two instructions that only differ by the rounding
9927 mode the operation uses. In essesce, they encoded the rm
9928 in the name. In order to avoid having to create Iops, that
9929 encode the rm in th name, we will "expand" the definition of
9930 the rounding mode bits. We will just pass the rm and then
9931 map the to odd mode to the appropriate PPCFpOp name that
9932 will tell us which instruction to map to.
9934 rounding mode | PPC | IR
9935 ------------------------
9936 to nearest | 000 | 00
9937 to zero | 001 | 11
9938 to +infinity | 010 | 10
9939 to -infinity | 011 | 01
9940 to odd | 1xx | xx
9942 return mkU32(8);
9945 static IRExpr* /* :: Ity_I32 */ get_IR_roundingmode ( void )
9948 rounding mode | PPC | IR
9949 ------------------------
9950 to nearest | 00 | 00
9951 to zero | 01 | 11
9952 to +infinity | 10 | 10
9953 to -infinity | 11 | 01
9955 IRTemp rm_PPC32 = newTemp(Ity_I32);
9956 assign( rm_PPC32, getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN ) );
9958 // rm_IR = XOR( rm_PPC32, (rm_PPC32 << 1) & 2)
9959 return binop( Iop_Xor32,
9960 mkexpr(rm_PPC32),
9961 binop( Iop_And32,
9962 binop(Iop_Shl32, mkexpr(rm_PPC32), mkU8(1)),
9963 mkU32(2) ));
9966 /* The DFP IR rounding modes were chosen such that the existing PPC to IR
9967 * mapping would still work with the extended three bit DFP rounding
9968 * mode designator.
9970 * rounding mode | PPC | IR
9971 * -----------------------------------------------
9972 * to nearest, ties to even | 000 | 000
9973 * to zero | 001 | 011
9974 * to +infinity | 010 | 010
9975 * to -infinity | 011 | 001
9976 * to nearest, ties away from 0 | 100 | 100
9977 * to nearest, ties toward 0 | 101 | 111
9978 * to away from 0 | 110 | 110
9979 * to prepare for shorter precision | 111 | 101
9981 static IRExpr* /* :: Ity_I32 */ get_IR_roundingmode_DFP( void )
9983 IRTemp rm_PPC32 = newTemp( Ity_I32 );
9984 assign( rm_PPC32, getGST_masked_upper( PPC_GST_FPSCR, MASK_FPSCR_DRN ) );
9986 // rm_IR = XOR( rm_PPC32, (rm_PPC32 << 1) & 2)
9987 return binop( Iop_Xor32,
9988 mkexpr( rm_PPC32 ),
9989 binop( Iop_And32,
9990 binop( Iop_Shl32, mkexpr( rm_PPC32 ), mkU8( 1 ) ),
9991 mkU32( 2 ) ) );
9994 #define NANmaskSingle 0x7F800000
9995 #define NANmaskDouble 0x7FF00000
9997 static IRExpr * Check_NaN( IRExpr * value, IRExpr * Hi32Mask )
9999 IRTemp exp_zero = newTemp(Ity_I8);
10000 IRTemp frac_mask = newTemp(Ity_I32);
10001 IRTemp frac_not_zero = newTemp(Ity_I8);
10003 /* Check if the result is QNAN or SNAN and not +infinity or -infinity.
10004 * The input value is always 64-bits, for single precision values, the
10005 * lower 32 bits must be zero.
10007 * Single Pricision
10008 * [62:54] exponent field is equal to 0xFF for NAN and Infinity.
10009 * [53:32] fraction field is zero for Infinity and non-zero for NAN
10010 * [31:0] unused for single precision representation
10012 * Double Pricision
10013 * [62:51] exponent field is equal to 0xFF for NAN and Infinity.
10014 * [50:0] fraction field is zero for Infinity and non-zero for NAN
10016 * Returned result is a U32 value of 0xFFFFFFFF for NaN and 0 otherwise.
10018 assign( frac_mask, unop( Iop_Not32,
10019 binop( Iop_Or32,
10020 mkU32( 0x80000000ULL ), Hi32Mask) ) );
10022 assign( exp_zero,
10023 unop( Iop_1Sto8,
10024 binop( Iop_CmpEQ32,
10025 binop( Iop_And32,
10026 unop( Iop_64HIto32,
10027 unop( Iop_ReinterpF64asI64,
10028 value ) ),
10029 Hi32Mask ),
10030 Hi32Mask ) ) );
10031 assign( frac_not_zero,
10032 binop( Iop_Or8,
10033 unop( Iop_1Sto8,
10034 binop( Iop_CmpNE32,
10035 binop( Iop_And32,
10036 unop( Iop_64HIto32,
10037 unop( Iop_ReinterpF64asI64,
10038 value ) ),
10039 mkexpr( frac_mask ) ),
10040 mkU32( 0x0 ) ) ),
10041 unop( Iop_1Sto8,
10042 binop( Iop_CmpNE32,
10043 binop( Iop_And32,
10044 unop( Iop_64to32,
10045 unop( Iop_ReinterpF64asI64,
10046 value ) ),
10047 mkU32( 0xFFFFFFFF ) ),
10048 mkU32( 0x0 ) ) ) ) );
10049 return unop( Iop_8Sto32,
10050 binop( Iop_And8,
10051 mkexpr( exp_zero ),
10052 mkexpr( frac_not_zero ) ) );
10055 static IRExpr * Complement_non_NaN( IRExpr * value, IRExpr * nan_mask )
10057 /* This function will only complement the 64-bit floating point value if it
10058 * is not Nan. NaN is not a signed value. Need to do computations using
10059 * 32-bit operands to ensure it will run in 32-bit mode.
10061 return binop( Iop_32HLto64,
10062 binop( Iop_Or32,
10063 binop( Iop_And32,
10064 nan_mask,
10065 unop( Iop_64HIto32,
10066 unop( Iop_ReinterpF64asI64,
10067 value ) ) ),
10068 binop( Iop_And32,
10069 unop( Iop_Not32,
10070 nan_mask ),
10071 unop( Iop_64HIto32,
10072 unop( Iop_ReinterpF64asI64,
10073 unop( Iop_NegF64,
10074 value ) ) ) ) ),
10075 unop( Iop_64to32,
10076 unop( Iop_ReinterpF64asI64, value ) ) );
10079 /*------------------------------------------------------------*/
10080 /*--- Floating Point Instruction Translation ---*/
10081 /*------------------------------------------------------------*/
10084 Floating Point Load Instructions
10086 static Bool dis_fp_load ( UInt theInstr )
10088 /* X-Form, D-Form */
10089 UChar opc1 = ifieldOPC(theInstr);
10090 UChar frD_addr = ifieldRegDS(theInstr);
10091 UChar rA_addr = ifieldRegA(theInstr);
10092 UChar rB_addr = ifieldRegB(theInstr);
10093 UInt opc2 = ifieldOPClo10(theInstr);
10094 UChar b0 = ifieldBIT0(theInstr);
10095 UInt uimm16 = ifieldUIMM16(theInstr);
10097 Int simm16 = extend_s_16to32(uimm16);
10098 IRType ty = mode64 ? Ity_I64 : Ity_I32;
10099 IRTemp EA = newTemp(ty);
10100 IRTemp rA = newTemp(ty);
10101 IRTemp rB = newTemp(ty);
10102 IRTemp iHi = newTemp(Ity_I32);
10103 IRTemp iLo = newTemp(Ity_I32);
10105 assign( rA, getIReg(rA_addr) );
10106 assign( rB, getIReg(rB_addr) );
10108 /* These are completely straightforward from a rounding and status
10109 bits perspective: no rounding involved and no funny status or CR
10110 bits affected. */
10112 switch (opc1) {
10113 case 0x30: // lfs (Load Float Single, PPC32 p441)
10114 DIP("lfs fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
10115 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
10116 putFReg( frD_addr,
10117 unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
10118 break;
10120 case 0x31: // lfsu (Load Float Single, Update, PPC32 p442)
10121 if (rA_addr == 0)
10122 return False;
10123 DIP("lfsu fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
10124 assign( EA, ea_rA_simm(rA_addr, simm16) );
10125 putFReg( frD_addr,
10126 unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
10127 putIReg( rA_addr, mkexpr(EA) );
10128 break;
10130 case 0x32: // lfd (Load Float Double, PPC32 p437)
10131 DIP("lfd fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
10132 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
10133 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
10134 break;
10136 case 0x33: // lfdu (Load Float Double, Update, PPC32 p438)
10137 if (rA_addr == 0)
10138 return False;
10139 DIP("lfdu fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
10140 assign( EA, ea_rA_simm(rA_addr, simm16) );
10141 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
10142 putIReg( rA_addr, mkexpr(EA) );
10143 break;
10145 case 0x1F:
10146 if (b0 != 0) {
10147 vex_printf("dis_fp_load(ppc)(instr,b0)\n");
10148 return False;
10151 switch(opc2) {
10152 case 0x217: // lfsx (Load Float Single Indexed, PPC32 p444)
10153 DIP("lfsx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
10154 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
10155 putFReg( frD_addr, unop( Iop_F32toF64,
10156 load(Ity_F32, mkexpr(EA))) );
10157 break;
10159 case 0x237: // lfsux (Load Float Single, Update Indxd, PPC32 p443)
10160 if (rA_addr == 0)
10161 return False;
10162 DIP("lfsux fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
10163 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
10164 putFReg( frD_addr,
10165 unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
10166 putIReg( rA_addr, mkexpr(EA) );
10167 break;
10169 case 0x257: // lfdx (Load Float Double Indexed, PPC32 p440)
10170 DIP("lfdx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
10171 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
10172 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
10173 break;
10175 case 0x277: // lfdux (Load Float Double, Update Indxd, PPC32 p439)
10176 if (rA_addr == 0)
10177 return False;
10178 DIP("lfdux fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
10179 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
10180 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
10181 putIReg( rA_addr, mkexpr(EA) );
10182 break;
10184 case 0x357: // lfiwax (Load Float As Integer, Indxd, ISA 2.05 p120)
10185 DIP("lfiwax fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
10186 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
10187 assign( iLo, load(Ity_I32, mkexpr(EA)) );
10188 assign( iHi, binop(Iop_Sub32,
10189 mkU32(0),
10190 binop(Iop_Shr32, mkexpr(iLo), mkU8(31))) );
10191 putFReg( frD_addr, unop(Iop_ReinterpI64asF64,
10192 binop(Iop_32HLto64, mkexpr(iHi), mkexpr(iLo))) );
10193 break;
10195 case 0x377: // lfiwzx (Load floating-point as integer word, zero indexed
10197 IRTemp dw = newTemp( Ity_I64 );
10198 DIP("lfiwzx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
10199 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
10200 assign( iLo, load(Ity_I32, mkexpr(EA)) );
10201 assign( dw, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( iLo ) ) );
10202 putFReg( frD_addr, unop( Iop_ReinterpI64asF64, mkexpr( dw ) ) );
10203 break;
10206 default:
10207 vex_printf("dis_fp_load(ppc)(opc2)\n");
10208 return False;
10210 break;
10212 default:
10213 vex_printf("dis_fp_load(ppc)(opc1)\n");
10214 return False;
10216 return True;
10222 Floating Point Store Instructions
10224 static Bool dis_fp_store ( UInt theInstr )
10226 /* X-Form, D-Form */
10227 UChar opc1 = ifieldOPC(theInstr);
10228 UChar frS_addr = ifieldRegDS(theInstr);
10229 UChar rA_addr = ifieldRegA(theInstr);
10230 UChar rB_addr = ifieldRegB(theInstr);
10231 UInt opc2 = ifieldOPClo10(theInstr);
10232 UChar b0 = ifieldBIT0(theInstr);
10233 Int uimm16 = ifieldUIMM16(theInstr);
10235 Int simm16 = extend_s_16to32(uimm16);
10236 IRTemp frS = newTemp(Ity_F64);
10237 IRType ty = mode64 ? Ity_I64 : Ity_I32;
10238 IRTemp EA = newTemp(ty);
10239 IRTemp rA = newTemp(ty);
10240 IRTemp rB = newTemp(ty);
10242 assign( frS, getFReg(frS_addr) );
10243 assign( rA, getIReg(rA_addr) );
10244 assign( rB, getIReg(rB_addr) );
10246 /* These are straightforward from a status bits perspective: no
10247 funny status or CR bits affected. For single precision stores,
10248 the values are truncated and denormalised (not rounded) to turn
10249 them into single precision values. */
10251 switch (opc1) {
10253 case 0x34: // stfs (Store Float Single, PPC32 p518)
10254 DIP("stfs fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
10255 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
10256 /* Use Iop_TruncF64asF32 to truncate and possible denormalise
10257 the value to be stored in the correct way, without any
10258 rounding. */
10259 store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
10260 break;
10262 case 0x35: // stfsu (Store Float Single, Update, PPC32 p519)
10263 if (rA_addr == 0)
10264 return False;
10265 DIP("stfsu fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
10266 assign( EA, ea_rA_simm(rA_addr, simm16) );
10267 /* See comment for stfs */
10268 store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
10269 putIReg( rA_addr, mkexpr(EA) );
10270 break;
10272 case 0x36: // stfd (Store Float Double, PPC32 p513)
10273 DIP("stfd fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
10274 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
10275 store( mkexpr(EA), mkexpr(frS) );
10276 break;
10278 case 0x37: // stfdu (Store Float Double, Update, PPC32 p514)
10279 if (rA_addr == 0)
10280 return False;
10281 DIP("stfdu fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
10282 assign( EA, ea_rA_simm(rA_addr, simm16) );
10283 store( mkexpr(EA), mkexpr(frS) );
10284 putIReg( rA_addr, mkexpr(EA) );
10285 break;
10287 case 0x1F:
10288 if (b0 != 0) {
10289 vex_printf("dis_fp_store(ppc)(instr,b0)\n");
10290 return False;
10292 switch(opc2) {
10293 case 0x297: // stfsx (Store Float Single Indexed, PPC32 p521)
10294 DIP("stfsx fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
10295 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
10296 /* See note for stfs */
10297 store( mkexpr(EA),
10298 unop(Iop_TruncF64asF32, mkexpr(frS)) );
10299 break;
10301 case 0x2B7: // stfsux (Store Float Sgl, Update Indxd, PPC32 p520)
10302 if (rA_addr == 0)
10303 return False;
10304 DIP("stfsux fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
10305 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
10306 /* See note for stfs */
10307 store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
10308 putIReg( rA_addr, mkexpr(EA) );
10309 break;
10311 case 0x2D7: // stfdx (Store Float Double Indexed, PPC32 p516)
10312 DIP("stfdx fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
10313 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
10314 store( mkexpr(EA), mkexpr(frS) );
10315 break;
10317 case 0x2F7: // stfdux (Store Float Dbl, Update Indxd, PPC32 p515)
10318 if (rA_addr == 0)
10319 return False;
10320 DIP("stfdux fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
10321 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
10322 store( mkexpr(EA), mkexpr(frS) );
10323 putIReg( rA_addr, mkexpr(EA) );
10324 break;
10326 case 0x3D7: // stfiwx (Store Float as Int, Indexed, PPC32 p517)
10327 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
10328 DIP("stfiwx fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
10329 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
10330 store( mkexpr(EA),
10331 unop(Iop_64to32, unop(Iop_ReinterpF64asI64, mkexpr(frS))) );
10332 break;
10334 default:
10335 vex_printf("dis_fp_store(ppc)(opc2)\n");
10336 return False;
10338 break;
10340 default:
10341 vex_printf("dis_fp_store(ppc)(opc1)\n");
10342 return False;
10344 return True;
10350 Floating Point Arith Instructions
10352 static Bool dis_fp_arith ( UInt theInstr )
10354 /* A-Form */
10355 UChar opc1 = ifieldOPC(theInstr);
10356 UChar frD_addr = ifieldRegDS(theInstr);
10357 UChar frA_addr = ifieldRegA(theInstr);
10358 UChar frB_addr = ifieldRegB(theInstr);
10359 UChar frC_addr = ifieldRegC(theInstr);
10360 UChar opc2 = ifieldOPClo5(theInstr);
10361 UChar flag_rC = ifieldBIT0(theInstr);
10363 IRTemp frD = newTemp(Ity_F64);
10364 IRTemp frA = newTemp(Ity_F64);
10365 IRTemp frB = newTemp(Ity_F64);
10366 IRTemp frC = newTemp(Ity_F64);
10367 IRExpr* rm = get_IR_roundingmode();
10369 /* By default, we will examine the results of the operation and set
10370 fpscr[FPRF] accordingly. */
10371 Bool set_FPRF = True;
10373 /* By default, if flag_RC is set, we will clear cr1 after the
10374 operation. In reality we should set cr1 to indicate the
10375 exception status of the operation, but since we're not
10376 simulating exceptions, the exception status will appear to be
10377 zero. Hence cr1 should be cleared if this is a . form insn. */
10378 Bool clear_CR1 = True;
10380 assign( frA, getFReg(frA_addr));
10381 assign( frB, getFReg(frB_addr));
10382 assign( frC, getFReg(frC_addr));
10384 switch (opc1) {
10385 case 0x3B:
10386 switch (opc2) {
10387 case 0x12: // fdivs (Floating Divide Single, PPC32 p407)
10388 if (frC_addr != 0)
10389 return False;
10390 DIP("fdivs%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10391 frD_addr, frA_addr, frB_addr);
10392 assign( frD, triop( Iop_DivF64r32,
10393 rm, mkexpr(frA), mkexpr(frB) ));
10394 break;
10396 case 0x14: // fsubs (Floating Subtract Single, PPC32 p430)
10397 if (frC_addr != 0)
10398 return False;
10399 DIP("fsubs%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10400 frD_addr, frA_addr, frB_addr);
10401 assign( frD, triop( Iop_SubF64r32,
10402 rm, mkexpr(frA), mkexpr(frB) ));
10403 break;
10405 case 0x15: // fadds (Floating Add Single, PPC32 p401)
10406 if (frC_addr != 0)
10407 return False;
10408 DIP("fadds%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10409 frD_addr, frA_addr, frB_addr);
10410 assign( frD, triop( Iop_AddF64r32,
10411 rm, mkexpr(frA), mkexpr(frB) ));
10412 break;
10414 case 0x16: // fsqrts (Floating SqRt (Single-Precision), PPC32 p428)
10415 // NOTE: POWERPC OPTIONAL, "General-Purpose Group" (PPC32_FX)
10416 if (frA_addr != 0 || frC_addr != 0)
10417 return False;
10418 DIP("fsqrts%s fr%u,fr%u\n", flag_rC ? ".":"",
10419 frD_addr, frB_addr);
10420 // however illogically, on ppc970 this insn behaves identically
10421 // to fsqrt (double-precision). So use SqrtF64, not SqrtF64r32.
10422 assign( frD, binop( Iop_SqrtF64, rm, mkexpr(frB) ));
10423 break;
10425 case 0x18: // fres (Floating Reciprocal Estimate Single, PPC32 p421)
10426 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
10427 if (frA_addr != 0 || frC_addr != 0)
10428 return False;
10429 DIP("fres%s fr%u,fr%u\n", flag_rC ? ".":"",
10430 frD_addr, frB_addr);
10431 { IRExpr* ieee_one
10432 = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
10433 assign( frD, triop( Iop_DivF64r32,
10435 ieee_one, mkexpr(frB) ));
10437 break;
10439 case 0x19: // fmuls (Floating Multiply Single, PPC32 p414)
10440 if (frB_addr != 0)
10441 return False;
10442 DIP("fmuls%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10443 frD_addr, frA_addr, frC_addr);
10444 assign( frD, triop( Iop_MulF64r32,
10445 rm, mkexpr(frA), mkexpr(frC) ));
10446 break;
10448 case 0x1A: // frsqrtes (Floating Recip SqRt Est Single)
10449 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
10450 // Undocumented instruction?
10451 if (frA_addr != 0 || frC_addr != 0)
10452 return False;
10453 DIP("frsqrtes%s fr%u,fr%u\n", flag_rC ? ".":"",
10454 frD_addr, frB_addr);
10455 assign( frD, unop(Iop_RSqrtEst5GoodF64, mkexpr(frB)) );
10456 break;
10458 default:
10459 vex_printf("dis_fp_arith(ppc)(3B: opc2)\n");
10460 return False;
10462 break;
10464 case 0x3F:
10465 switch (opc2) {
10466 case 0x12: // fdiv (Floating Div (Double-Precision), PPC32 p406)
10467 if (frC_addr != 0)
10468 return False;
10469 DIP("fdiv%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10470 frD_addr, frA_addr, frB_addr);
10471 assign( frD, triop(Iop_DivF64, rm, mkexpr(frA), mkexpr(frB)) );
10472 break;
10474 case 0x14: // fsub (Floating Sub (Double-Precision), PPC32 p429)
10475 if (frC_addr != 0)
10476 return False;
10477 DIP("fsub%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10478 frD_addr, frA_addr, frB_addr);
10479 assign( frD, triop(Iop_SubF64, rm, mkexpr(frA), mkexpr(frB)) );
10480 break;
10482 case 0x15: // fadd (Floating Add (Double-Precision), PPC32 p400)
10483 if (frC_addr != 0)
10484 return False;
10485 DIP("fadd%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10486 frD_addr, frA_addr, frB_addr);
10487 assign( frD, triop(Iop_AddF64, rm, mkexpr(frA), mkexpr(frB)) );
10488 break;
10490 case 0x16: // fsqrt (Floating SqRt (Double-Precision), PPC32 p427)
10491 // NOTE: POWERPC OPTIONAL, "General-Purpose Group" (PPC32_FX)
10492 if (frA_addr != 0 || frC_addr != 0)
10493 return False;
10494 DIP("fsqrt%s fr%u,fr%u\n", flag_rC ? ".":"",
10495 frD_addr, frB_addr);
10496 assign( frD, binop(Iop_SqrtF64, rm, mkexpr(frB)) );
10497 break;
10499 case 0x17: { // fsel (Floating Select, PPC32 p426)
10500 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
10501 IRTemp cc = newTemp(Ity_I32);
10502 IRTemp cc_b0 = newTemp(Ity_I32);
10504 DIP("fsel%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10505 frD_addr, frA_addr, frC_addr, frB_addr);
10507 // cc: UN == 0x41, LT == 0x01, GT == 0x00, EQ == 0x40
10508 // => GT|EQ == (cc & 0x1 == 0)
10509 assign( cc, binop(Iop_CmpF64, mkexpr(frA),
10510 IRExpr_Const(IRConst_F64(0))) );
10511 assign( cc_b0, binop(Iop_And32, mkexpr(cc), mkU32(1)) );
10513 // frD = (frA >= 0.0) ? frC : frB
10514 // = (cc_b0 == 0) ? frC : frB
10515 assign( frD,
10516 IRExpr_ITE(
10517 binop(Iop_CmpEQ32, mkexpr(cc_b0), mkU32(0)),
10518 mkexpr(frC),
10519 mkexpr(frB) ));
10521 /* One of the rare ones which don't mess with FPRF */
10522 set_FPRF = False;
10523 break;
10526 case 0x18: // fre (Floating Reciprocal Estimate)
10527 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
10528 // Note: unclear whether this insn really exists or not
10529 // ppc970 doesn't have it, but POWER5 does
10530 if (frA_addr != 0 || frC_addr != 0)
10531 return False;
10532 DIP("fre%s fr%u,fr%u\n", flag_rC ? ".":"",
10533 frD_addr, frB_addr);
10534 { IRExpr* ieee_one
10535 = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
10536 assign( frD, triop( Iop_DivF64,
10538 ieee_one, mkexpr(frB) ));
10540 break;
10542 case 0x19: // fmul (Floating Mult (Double Precision), PPC32 p413)
10543 if (frB_addr != 0)
10544 vex_printf("dis_fp_arith(ppc)(instr,fmul)\n");
10545 DIP("fmul%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10546 frD_addr, frA_addr, frC_addr);
10547 assign( frD, triop(Iop_MulF64, rm, mkexpr(frA), mkexpr(frC)) );
10548 break;
10550 case 0x1A: // frsqrte (Floating Recip SqRt Est., PPC32 p424)
10551 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
10552 if (frA_addr != 0 || frC_addr != 0)
10553 return False;
10554 DIP("frsqrte%s fr%u,fr%u\n", flag_rC ? ".":"",
10555 frD_addr, frB_addr);
10556 assign( frD, unop(Iop_RSqrtEst5GoodF64, mkexpr(frB)) );
10557 break;
10559 default:
10560 vex_printf("dis_fp_arith(ppc)(3F: opc2)\n");
10561 return False;
10563 break;
10565 default:
10566 vex_printf("dis_fp_arith(ppc)(opc1)\n");
10567 return False;
10570 putFReg( frD_addr, mkexpr(frD) );
10572 if (set_FPRF) {
10573 // XXX XXX XXX FIXME
10574 // set FPRF from frD
10577 if (flag_rC && clear_CR1) {
10578 putCR321( 1, mkU8(0) );
10579 putCR0( 1, mkU8(0) );
10582 return True;
10588 Floating Point Mult-Add Instructions
10590 static Bool dis_fp_multadd ( UInt theInstr )
10592 /* A-Form */
10593 UChar opc1 = ifieldOPC(theInstr);
10594 UChar frD_addr = ifieldRegDS(theInstr);
10595 UChar frA_addr = ifieldRegA(theInstr);
10596 UChar frB_addr = ifieldRegB(theInstr);
10597 UChar frC_addr = ifieldRegC(theInstr);
10598 UChar opc2 = ifieldOPClo5(theInstr);
10599 UChar flag_rC = ifieldBIT0(theInstr);
10601 IRTemp frD = newTemp(Ity_F64);
10602 IRTemp frA = newTemp(Ity_F64);
10603 IRTemp frB = newTemp(Ity_F64);
10604 IRTemp frC = newTemp(Ity_F64);
10605 IRTemp rmt = newTemp(Ity_I32);
10606 IRTemp tmp = newTemp(Ity_F64);
10607 IRTemp sign_tmp = newTemp(Ity_I64);
10608 IRTemp nan_mask = newTemp(Ity_I32);
10609 IRExpr* rm;
10611 /* By default, we will examine the results of the operation and set
10612 fpscr[FPRF] accordingly. */
10613 Bool set_FPRF = True;
10615 /* By default, if flag_RC is set, we will clear cr1 after the
10616 operation. In reality we should set cr1 to indicate the
10617 exception status of the operation, but since we're not
10618 simulating exceptions, the exception status will appear to be
10619 zero. Hence cr1 should be cleared if this is a . form insn. */
10620 Bool clear_CR1 = True;
10622 /* Bind the rounding mode expression to a temp; there's no
10623 point in creating gratuitous CSEs, as we know we'll need
10624 to use it twice. */
10625 assign( rmt, get_IR_roundingmode() );
10626 rm = mkexpr(rmt);
10628 assign( frA, getFReg(frA_addr));
10629 assign( frB, getFReg(frB_addr));
10630 assign( frC, getFReg(frC_addr));
10632 /* The rounding in this is all a bit dodgy. The idea is to only do
10633 one rounding. That clearly isn't achieveable without dedicated
10634 four-input IR primops, although in the single precision case we
10635 can sort-of simulate it by doing the inner multiply in double
10636 precision.
10638 In the negated cases, the negation happens after rounding. */
10640 switch (opc1) {
10641 case 0x3B:
10642 switch (opc2) {
10643 case 0x1C: // fmsubs (Floating Mult-Subtr Single, PPC32 p412)
10644 DIP("fmsubs%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10645 frD_addr, frA_addr, frC_addr, frB_addr);
10646 assign( frD, qop( Iop_MSubF64r32, rm,
10647 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
10648 break;
10650 case 0x1D: // fmadds (Floating Mult-Add Single, PPC32 p409)
10651 DIP("fmadds%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10652 frD_addr, frA_addr, frC_addr, frB_addr);
10653 assign( frD, qop( Iop_MAddF64r32, rm,
10654 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
10655 break;
10657 case 0x1E: // fnmsubs (Float Neg Mult-Subtr Single, PPC32 p420)
10658 case 0x1F: // fnmadds (Floating Negative Multiply-Add Single, PPC32 p418)
10660 if (opc2 == 0x1E) {
10661 DIP("fnmsubs%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10662 frD_addr, frA_addr, frC_addr, frB_addr);
10663 assign( tmp, qop( Iop_MSubF64r32, rm,
10664 mkexpr(frA), mkexpr(frC), mkexpr(frB) ) );
10665 } else {
10666 DIP("fnmadds%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10667 frD_addr, frA_addr, frC_addr, frB_addr);
10668 assign( tmp, qop( Iop_MAddF64r32, rm,
10669 mkexpr(frA), mkexpr(frC), mkexpr(frB) ) );
10672 assign( nan_mask, Check_NaN( mkexpr( tmp ),
10673 mkU32( NANmaskSingle ) ) );
10674 assign( sign_tmp, Complement_non_NaN( mkexpr( tmp ),
10675 mkexpr( nan_mask ) ) );
10676 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr( sign_tmp ) ) );
10677 break;
10679 default:
10680 vex_printf("dis_fp_multadd(ppc)(3B: opc2)\n");
10681 return False;
10683 break;
10685 case 0x3F:
10686 switch (opc2) {
10687 case 0x1C: // fmsub (Float Mult-Sub (Dbl Precision), PPC32 p411)
10688 DIP("fmsub%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10689 frD_addr, frA_addr, frC_addr, frB_addr);
10690 assign( frD, qop( Iop_MSubF64, rm,
10691 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
10692 break;
10694 case 0x1D: // fmadd (Float Mult-Add (Dbl Precision), PPC32 p408)
10695 DIP("fmadd%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10696 frD_addr, frA_addr, frC_addr, frB_addr);
10697 assign( frD, qop( Iop_MAddF64, rm,
10698 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
10699 break;
10701 case 0x1E: // fnmsub (Float Neg Mult-Subtr (Dbl Precision), PPC32 p419)
10702 case 0x1F: // fnmadd (Float Neg Mult-Add (Dbl Precision), PPC32 p417)
10704 if (opc2 == 0x1E) {
10705 DIP("fnmsub%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10706 frD_addr, frA_addr, frC_addr, frB_addr);
10707 assign( tmp, qop( Iop_MSubF64, rm,
10708 mkexpr(frA), mkexpr(frC), mkexpr(frB) ) );
10709 } else {
10710 DIP("fnmadd%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
10711 frD_addr, frA_addr, frC_addr, frB_addr);
10712 assign( tmp, qop( Iop_MAddF64, rm,
10713 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
10716 assign( nan_mask, Check_NaN( mkexpr( tmp ),
10717 mkU32( NANmaskDouble ) ) );
10718 assign( sign_tmp, Complement_non_NaN( mkexpr( tmp ),
10719 mkexpr( nan_mask ) ) );
10720 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr( sign_tmp ) ) );
10721 break;
10723 default:
10724 vex_printf("dis_fp_multadd(ppc)(3F: opc2)\n");
10725 return False;
10727 break;
10729 default:
10730 vex_printf("dis_fp_multadd(ppc)(opc1)\n");
10731 return False;
10734 putFReg( frD_addr, mkexpr(frD) );
10736 if (set_FPRF) {
10737 // XXX XXX XXX FIXME
10738 // set FPRF from frD
10741 if (flag_rC && clear_CR1) {
10742 putCR321( 1, mkU8(0) );
10743 putCR0( 1, mkU8(0) );
10746 return True;
10750 * fe_flag is set to 1 if any of the following conditions occurs:
10751 * - The floating-point operand in register FRB is a Zero, a
10752 * NaN, an Infinity, or a negative value.
10753 * - e_b is less than or equal to: -970 for double precision; -103 for single precision
10754 * Otherwise fe_flag is set to 0.
10756 * fg_flag is set to 1 if either of the following conditions occurs.
10757 * - The floating-point operand in register FRB is a Zero, an
10758 * Infinity, or a denormalized value.
10759 * Otherwise fg_flag is set to 0.
10763 static void do_fp_tsqrt(IRTemp frB_Int, Bool sp, IRTemp * fe_flag_tmp, IRTemp * fg_flag_tmp)
10765 // The following temps are for holding intermediate results
10766 IRTemp e_b = newTemp(Ity_I32);
10767 IRExpr * fe_flag, * fg_flag;
10768 IRTemp frB_exp_shR = newTemp(Ity_I32);
10769 UInt bias = sp? 127 : 1023;
10770 IRExpr * frbNaN, * frbDenorm, * frBNeg;
10771 IRExpr * eb_LTE;
10772 IRTemp frbZero_tmp = newTemp(Ity_I1);
10773 IRTemp frbInf_tmp = newTemp(Ity_I1);
10774 *fe_flag_tmp = newTemp(Ity_I32);
10775 *fg_flag_tmp = newTemp(Ity_I32);
10777 if ( sp )
10778 assign( frB_exp_shR, fp_exp_part( Ity_I32, frB_Int ) );
10779 else
10780 assign( frB_exp_shR, fp_exp_part( Ity_I64, frB_Int ) );
10782 assign(e_b, binop( Iop_Sub32, mkexpr(frB_exp_shR), mkU32( bias ) ));
10784 ////////////////// fe_flag tests BEGIN //////////////////////
10785 /* We first do all tests that may result in setting fe_flag to '1'.
10786 * (NOTE: These tests are similar to those used for ftdiv. See do_fp_tdiv()
10787 * for details.)
10789 if ( sp ) {
10790 frbNaN = is_NaN( Ity_I32, frB_Int );
10791 assign( frbInf_tmp, is_Inf( Ity_I32, frB_Int ) );
10792 assign( frbZero_tmp, is_Zero( Ity_I32, frB_Int ) );
10794 } else {
10795 frbNaN = is_NaN( Ity_I64, frB_Int );
10796 assign( frbInf_tmp, is_Inf( Ity_I64, frB_Int ) );
10797 assign( frbZero_tmp, is_Zero( Ity_I64, frB_Int ) );
10801 // Test_value = -970 for double precision
10802 UInt test_value = sp ? 0xffffff99 : 0xfffffc36;
10803 eb_LTE = binop( Iop_CmpLE32S, mkexpr( e_b ), mkU32( test_value ) );
10805 frBNeg = binop( Iop_CmpEQ32,
10806 binop( Iop_Shr32,
10807 sp ? mkexpr( frB_Int ) : unop( Iop_64HIto32, mkexpr( frB_Int ) ),
10808 mkU8( 31 ) ),
10809 mkU32( 1 ) );
10810 ////////////////// fe_flag tests END //////////////////////
10812 ////////////////// fg_flag tests BEGIN //////////////////////
10814 * The following tests were already performed above in the fe_flag
10815 * tests. So these conditions will result in both fe_ and fg_ flags
10816 * being set.
10817 * - Test if FRB is Zero
10818 * - Test if FRB is an Infinity
10822 * Test if FRB holds a denormalized value. A denormalized value is one where
10823 * the exp is 0 and the fraction is non-zero.
10825 if (sp) {
10826 IRTemp frac_part = newTemp(Ity_I32);
10827 assign( frac_part, binop( Iop_And32, mkexpr(frB_Int), mkU32(0x007fffff)) );
10828 frbDenorm
10829 = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ), mkU32( 0 ) ),
10830 binop( Iop_CmpNE32, mkexpr( frac_part ), mkU32( 0 ) ) );
10831 } else {
10832 IRExpr * hi32, * low32, * fraction_is_nonzero;
10833 IRTemp frac_part = newTemp(Ity_I64);
10835 assign( frac_part, FP_FRAC_PART(frB_Int) );
10836 hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
10837 low32 = unop( Iop_64to32, mkexpr( frac_part ) );
10838 fraction_is_nonzero = binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
10839 mkU32( 0 ) );
10840 frbDenorm
10841 = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ), mkU32( 0 ) ),
10842 fraction_is_nonzero );
10844 ////////////////// fg_flag tests END //////////////////////
10846 /////////////////////////
10847 fe_flag = mkOR1( mkexpr( frbZero_tmp ),
10848 mkOR1( frbNaN,
10849 mkOR1( mkexpr( frbInf_tmp ),
10850 mkOR1( frBNeg, eb_LTE ) ) ) );
10852 fe_flag = unop(Iop_1Uto32, fe_flag);
10854 fg_flag = mkOR1( mkexpr( frbZero_tmp ),
10855 mkOR1( mkexpr( frbInf_tmp ), frbDenorm ) );
10856 fg_flag = unop(Iop_1Uto32, fg_flag);
10857 assign (*fg_flag_tmp, fg_flag);
10858 assign (*fe_flag_tmp, fe_flag);
10861 * fe_flag is set to 1 if any of the following conditions occurs:
10862 * - The double-precision floating-point operand in register FRA is a NaN or an
10863 * Infinity.
10864 * - The double-precision floating-point operand in register FRB is a Zero, a
10865 * NaN, or an Infinity.
10866 * - e_b is less than or equal to -1022.
10867 * - e_b is greater than or equal to 1021.
10868 * - The double-precision floating-point operand in register FRA is not a zero
10869 * and the difference, e_a - e_b, is greater than or equal to 1023.
10870 * - The double-precision floating-point operand in register FRA is not a zero
10871 * and the difference, e_a - e_b, is less than or equal to -1021.
10872 * - The double-precision floating-point operand in register FRA is not a zero
10873 * and e_a is less than or equal to -970
10874 * Otherwise fe_flag is set to 0.
10876 * fg_flag is set to 1 if either of the following conditions occurs.
10877 * - The double-precision floating-point operand in register FRA is an Infinity.
10878 * - The double-precision floating-point operand in register FRB is a Zero, an
10879 * Infinity, or a denormalized value.
10880 * Otherwise fg_flag is set to 0.
10883 static void _do_fp_tdiv(IRTemp frA_int, IRTemp frB_int, Bool sp, IRTemp * fe_flag_tmp, IRTemp * fg_flag_tmp)
10885 // The following temps are for holding intermediate results
10886 IRTemp e_a = newTemp(Ity_I32);
10887 IRTemp e_b = newTemp(Ity_I32);
10888 IRTemp frA_exp_shR = newTemp(Ity_I32);
10889 IRTemp frB_exp_shR = newTemp(Ity_I32);
10891 UInt bias = sp? 127 : 1023;
10892 *fe_flag_tmp = newTemp(Ity_I32);
10893 *fg_flag_tmp = newTemp(Ity_I32);
10895 /* The following variables hold boolean results from tests
10896 * that are OR'ed together for setting the fe_ and fg_ flags.
10897 * For some cases, the booleans are used more than once, so
10898 * I make those IRTemp's instead of IRExpr's.
10900 IRExpr * fraNaN, * frbNaN, * frbDenorm;
10901 IRExpr * eb_LTE, * eb_GTE, * ea_eb_GTE, * ea_eb_LTE, * ea_LTE;
10902 IRTemp fraInf_tmp = newTemp(Ity_I1);
10903 IRTemp frbZero_tmp = newTemp(Ity_I1);
10904 IRTemp frbInf_tmp = newTemp(Ity_I1);
10905 IRTemp fraNotZero_tmp = newTemp(Ity_I1);
10907 /* The following are the flags that are set by OR'ing the results of
10908 * all the tests done for tdiv. These flags are the input to the specified CR.
10910 IRExpr * fe_flag, * fg_flag;
10912 // Create temps that will be used throughout the following tests.
10913 if ( sp ) {
10914 assign( frA_exp_shR, fp_exp_part( Ity_I32, frA_int ) );
10915 assign( frB_exp_shR, fp_exp_part( Ity_I32, frB_int ) );
10916 } else{
10917 assign( frA_exp_shR, fp_exp_part( Ity_I64, frA_int ) );
10918 assign( frB_exp_shR, fp_exp_part( Ity_I64, frB_int ) );
10921 /* Let e_[a|b] be the unbiased exponent: i.e. exp - 1023. */
10922 assign(e_a, binop( Iop_Sub32, mkexpr(frA_exp_shR), mkU32( bias ) ));
10923 assign(e_b, binop( Iop_Sub32, mkexpr(frB_exp_shR), mkU32( bias ) ));
10926 ////////////////// fe_flag tests BEGIN //////////////////////
10927 /* We first do all tests that may result in setting fe_flag to '1'. */
10930 * Test if the double-precision floating-point operand in register FRA is
10931 * a NaN:
10933 fraNaN = sp ? is_NaN( Ity_I32, frA_int ) : is_NaN( Ity_I64, frA_int );
10935 * Test if the double-precision floating-point operands in register FRA
10936 * and FRB is an Infinity. Test if FRB is zero.
10938 if ( sp ) {
10939 assign(fraInf_tmp, is_Inf( Ity_I32, frA_int ) );
10940 assign( frbInf_tmp, is_Inf( Ity_I32, frB_int ) );
10941 assign( frbZero_tmp, is_Zero( Ity_I32, frB_int ) );
10943 } else {
10944 assign(fraInf_tmp, is_Inf( Ity_I64, frA_int ) );
10945 assign( frbInf_tmp, is_Inf( Ity_I64, frB_int ) );
10946 assign( frbZero_tmp, is_Zero( Ity_I64, frB_int ) );
10949 * Test if the double-precision floating-point operand in register FRB is
10950 * a NaN:
10952 frbNaN = sp ? is_NaN( Ity_I32, frB_int ) : is_NaN( Ity_I64, frB_int );
10955 * Test if e_b <= -1022 for double precision;
10956 * or e_b <= -126 for single precision
10959 UInt test_value = sp ? 0xffffff82 : 0xfffffc02;
10960 eb_LTE = binop(Iop_CmpLE32S, mkexpr(e_b), mkU32(test_value));
10964 * Test if e_b >= 1021 (i.e., 1021 < e_b) for double precision;
10965 * or e_b >= -125 (125 < e_b) for single precision
10968 Int test_value = sp ? 125 : 1021;
10969 eb_GTE = binop(Iop_CmpLT32S, mkU32(test_value), mkexpr(e_b));
10973 * Test if FRA != Zero and (e_a - e_b) >= bias
10975 if ( sp )
10976 assign( fraNotZero_tmp, unop( Iop_Not1, is_Zero( Ity_I32, frA_int ) ) );
10977 else
10978 assign( fraNotZero_tmp, unop( Iop_Not1, is_Zero( Ity_I64, frA_int ) ) );
10980 ea_eb_GTE = mkAND1( mkexpr( fraNotZero_tmp ),
10981 binop( Iop_CmpLT32S, mkU32( bias ),
10982 binop( Iop_Sub32, mkexpr( e_a ),
10983 mkexpr( e_b ) ) ) );
10986 * Test if FRA != Zero and (e_a - e_b) <= [-1021 (double precision) or -125 (single precision)]
10989 UInt test_value = sp ? 0xffffff83 : 0xfffffc03;
10991 ea_eb_LTE = mkAND1( mkexpr( fraNotZero_tmp ),
10992 binop( Iop_CmpLE32S,
10993 binop( Iop_Sub32,
10994 mkexpr( e_a ),
10995 mkexpr( e_b ) ),
10996 mkU32( test_value ) ) );
11000 * Test if FRA != Zero and e_a <= [-970 (double precision) or -103 (single precision)]
11003 UInt test_value = 0xfffffc36; //Int test_value = -970;
11005 ea_LTE = mkAND1( mkexpr( fraNotZero_tmp ), binop( Iop_CmpLE32S,
11006 mkexpr( e_a ),
11007 mkU32( test_value ) ) );
11009 ////////////////// fe_flag tests END //////////////////////
11011 ////////////////// fg_flag tests BEGIN //////////////////////
11013 * The following tests were already performed above in the fe_flag
11014 * tests. So these conditions will result in both fe_ and fg_ flags
11015 * being set.
11016 * - Test if FRA is an Infinity
11017 * - Test if FRB ix Zero
11018 * - Test if FRB is an Infinity
11022 * Test if FRB holds a denormalized value. A denormalized value is one where
11023 * the exp is 0 and the fraction is non-zero.
11026 IRExpr * fraction_is_nonzero;
11028 if (sp) {
11029 fraction_is_nonzero = binop( Iop_CmpNE32, FP_FRAC_PART32(frB_int),
11030 mkU32( 0 ) );
11031 } else {
11032 IRExpr * hi32, * low32;
11033 IRTemp frac_part = newTemp(Ity_I64);
11034 assign( frac_part, FP_FRAC_PART(frB_int) );
11036 hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
11037 low32 = unop( Iop_64to32, mkexpr( frac_part ) );
11038 fraction_is_nonzero = binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
11039 mkU32( 0 ) );
11041 frbDenorm = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ),
11042 mkU32( 0x0 ) ), fraction_is_nonzero );
11045 ////////////////// fg_flag tests END //////////////////////
11047 fe_flag
11048 = mkOR1(
11049 fraNaN,
11050 mkOR1(
11051 mkexpr( fraInf_tmp ),
11052 mkOR1(
11053 mkexpr( frbZero_tmp ),
11054 mkOR1(
11055 frbNaN,
11056 mkOR1(
11057 mkexpr( frbInf_tmp ),
11058 mkOR1( eb_LTE,
11059 mkOR1( eb_GTE,
11060 mkOR1( ea_eb_GTE,
11061 mkOR1( ea_eb_LTE,
11062 ea_LTE ) ) ) ) ) ) ) ) );
11064 fe_flag = unop(Iop_1Uto32, fe_flag);
11066 fg_flag = mkOR1( mkexpr( fraInf_tmp ), mkOR1( mkexpr( frbZero_tmp ),
11067 mkOR1( mkexpr( frbInf_tmp ),
11068 frbDenorm ) ) );
11069 fg_flag = unop(Iop_1Uto32, fg_flag);
11070 assign(*fe_flag_tmp, fe_flag);
11071 assign(*fg_flag_tmp, fg_flag);
11074 /* See description for _do_fp_tdiv() above. */
11075 static IRExpr * do_fp_tdiv(IRTemp frA_int, IRTemp frB_int)
11077 IRTemp fe_flag, fg_flag;
11078 /////////////////////////
11079 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
11080 * where fl_flag == 1 on ppc64.
11082 IRExpr * fl_flag = unop(Iop_Not32, mkU32(0xFFFFFE));
11083 fe_flag = fg_flag = IRTemp_INVALID;
11084 _do_fp_tdiv(frA_int, frB_int, False/*not single precision*/, &fe_flag, &fg_flag);
11085 return binop( Iop_Or32,
11086 binop( Iop_Or32,
11087 binop( Iop_Shl32, fl_flag, mkU8( 3 ) ),
11088 binop( Iop_Shl32, mkexpr(fg_flag), mkU8( 2 ) ) ),
11089 binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) );
11092 static Bool dis_fp_tests ( UInt theInstr )
11094 UChar opc1 = ifieldOPC(theInstr);
11095 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
11096 UChar frB_addr = ifieldRegB(theInstr);
11097 UChar b0 = ifieldBIT0(theInstr);
11098 UInt opc2 = ifieldOPClo10(theInstr);
11099 IRTemp frB_I64 = newTemp(Ity_I64);
11101 if (opc1 != 0x3F || b0 != 0 ){
11102 vex_printf("dis_fp_tests(ppc)(ftdiv)\n");
11103 return False;
11105 assign( frB_I64, unop( Iop_ReinterpF64asI64, getFReg( frB_addr ) ) );
11107 switch (opc2) {
11108 case 0x080: // ftdiv
11110 UChar frA_addr = ifieldRegA(theInstr);
11111 IRTemp frA_I64 = newTemp(Ity_I64);
11112 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
11113 if (b21to22 != 0 ) {
11114 vex_printf("dis_fp_tests(ppc)(ftdiv)\n");
11115 return False;
11118 assign( frA_I64, unop( Iop_ReinterpF64asI64, getFReg( frA_addr ) ) );
11119 putGST_field( PPC_GST_CR, do_fp_tdiv(frA_I64, frB_I64), crfD );
11121 DIP("ftdiv crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
11122 break;
11124 case 0x0A0: // ftsqrt
11126 IRTemp flags = newTemp(Ity_I32);
11127 IRTemp fe_flag, fg_flag;
11128 fe_flag = fg_flag = IRTemp_INVALID;
11129 UChar b18to22 = toUChar( IFIELD( theInstr, 18, 5 ) );
11130 if ( b18to22 != 0) {
11131 vex_printf("dis_fp_tests(ppc)(ftsqrt)\n");
11132 return False;
11134 DIP("ftsqrt crf%d,fr%u\n", crfD, frB_addr);
11135 do_fp_tsqrt(frB_I64, False /* not single precision*/, &fe_flag, &fg_flag);
11136 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
11137 * where fl_flag == 1 on ppc64.
11139 assign( flags,
11140 binop( Iop_Or32,
11141 binop( Iop_Or32, mkU32( 8 ), // fl_flag
11142 binop( Iop_Shl32, mkexpr(fg_flag), mkU8( 2 ) ) ),
11143 binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) ) );
11144 putGST_field( PPC_GST_CR, mkexpr(flags), crfD );
11145 break;
11148 default:
11149 vex_printf("dis_fp_tests(ppc)(opc2)\n");
11150 return False;
11153 return True;
11157 Floating Point Compare Instructions
11159 static Bool dis_fp_cmp ( UInt theInstr )
11161 /* X-Form */
11162 UChar opc1 = ifieldOPC(theInstr);
11163 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
11164 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
11165 UChar frA_addr = ifieldRegA(theInstr);
11166 UChar frB_addr = ifieldRegB(theInstr);
11167 UInt opc2 = ifieldOPClo10(theInstr);
11168 UChar b0 = ifieldBIT0(theInstr);
11170 IRTemp ccIR = newTemp(Ity_I32);
11171 IRTemp ccPPC32 = newTemp(Ity_I32);
11173 IRTemp frA = newTemp(Ity_F64);
11174 IRTemp frB = newTemp(Ity_F64);
11176 if (opc1 != 0x3F || b21to22 != 0 || b0 != 0) {
11177 vex_printf("dis_fp_cmp(ppc)(instr)\n");
11178 return False;
11181 assign( frA, getFReg(frA_addr));
11182 assign( frB, getFReg(frB_addr));
11184 assign( ccIR, binop(Iop_CmpF64, mkexpr(frA), mkexpr(frB)) );
11186 /* Map compare result from IR to PPC32 */
11188 FP cmp result | PPC | IR
11189 --------------------------
11190 UN | 0x1 | 0x45
11191 EQ | 0x2 | 0x40
11192 GT | 0x4 | 0x00
11193 LT | 0x8 | 0x01
11196 // ccPPC32 = Shl(1, (~(ccIR>>5) & 2)
11197 // | ((ccIR ^ (ccIR>>6)) & 1)
11198 assign(
11199 ccPPC32,
11200 binop(
11201 Iop_Shl32,
11202 mkU32(1),
11203 unop(
11204 Iop_32to8,
11205 binop(
11206 Iop_Or32,
11207 binop(
11208 Iop_And32,
11209 unop(
11210 Iop_Not32,
11211 binop(Iop_Shr32, mkexpr(ccIR), mkU8(5))
11213 mkU32(2)
11215 binop(
11216 Iop_And32,
11217 binop(
11218 Iop_Xor32,
11219 mkexpr(ccIR),
11220 binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))
11222 mkU32(1)
11229 putGST_field( PPC_GST_CR, mkexpr(ccPPC32), crfD );
11230 putFPCC( mkexpr( ccPPC32 ) );
11232 // XXX XXX XXX FIXME
11233 // Also write the result into FPRF (it's not entirely clear how)
11235 /* Note: Differences between fcmpu and fcmpo are only in exception
11236 flag settings, which aren't supported anyway. */
11237 switch (opc2) {
11238 case 0x000: // fcmpu (Floating Compare Unordered, PPC32 p403)
11239 DIP("fcmpu crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
11240 break;
11241 case 0x020: // fcmpo (Floating Compare Ordered, PPC32 p402)
11242 DIP("fcmpo crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
11243 break;
11244 default:
11245 vex_printf("dis_fp_cmp(ppc)(opc2)\n");
11246 return False;
11248 return True;
11254 Floating Point Rounding/Conversion Instructions
11256 static Bool dis_fp_round ( UInt theInstr )
11258 /* X-Form */
11259 UChar opc1 = ifieldOPC(theInstr);
11260 UChar b16to20 = ifieldRegA(theInstr);
11261 UChar frD_addr = ifieldRegDS(theInstr);
11262 UChar frB_addr = ifieldRegB(theInstr);
11263 UInt opc2 = ifieldOPClo10(theInstr);
11264 UChar flag_rC = ifieldBIT0(theInstr);
11266 IRTemp frD = newTemp(Ity_F64);
11267 IRTemp frB = newTemp(Ity_F64);
11268 IRTemp r_tmp32 = newTemp(Ity_I32);
11269 IRTemp r_tmp64 = newTemp(Ity_I64);
11270 IRExpr* rm = get_IR_roundingmode();
11272 /* By default, we will examine the results of the operation and set
11273 fpscr[FPRF] accordingly. */
11274 Bool set_FPRF = True;
11276 /* By default, if flag_RC is set, we will clear cr1 after the
11277 operation. In reality we should set cr1 to indicate the
11278 exception status of the operation, but since we're not
11279 simulating exceptions, the exception status will appear to be
11280 zero. Hence cr1 should be cleared if this is a . form insn. */
11281 Bool clear_CR1 = True;
11282 if ((!(opc1 == 0x3F || opc1 == 0x3B)) || b16to20 != 0) {
11283 vex_printf("dis_fp_round(ppc)(instr)\n");
11284 return False;
11287 assign( frB, getFReg(frB_addr));
11288 if (opc1 == 0x3B) {
11289 /* The fcfid[u]s instructions (from ISA 2.06) are a bit odd because
11290 * they're very similar to the other instructions handled here, but have
11291 * a different primary opcode.
11293 switch (opc2) {
11294 case 0x34E: // fcfids (Float convert from signed DWord to single precision)
11295 DIP("fcfids%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11296 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
11297 assign( frD, binop( Iop_RoundF64toF32, rm, binop( Iop_I64StoF64, rm,
11298 mkexpr( r_tmp64 ) ) ) );
11299 goto putFR;
11301 case 0x3Ce: // fcfidus (Float convert from unsigned DWord to single precision)
11302 DIP("fcfidus%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11303 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
11304 assign( frD, unop( Iop_F32toF64, binop( Iop_I64UtoF32, rm, mkexpr( r_tmp64 ) ) ) );
11305 goto putFR;
11310 switch (opc2) {
11311 case 0x00C: // frsp (Float Round to Single, PPC32 p423)
11312 DIP("frsp%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11313 assign( frD, binop( Iop_RoundF64toF32, rm, mkexpr(frB) ));
11314 break;
11316 case 0x00E: // fctiw (Float Conv to Int, PPC32 p404)
11317 DIP("fctiw%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11318 assign( r_tmp32,
11319 binop(Iop_F64toI32S, rm, mkexpr(frB)) );
11320 assign( frD, unop( Iop_ReinterpI64asF64,
11321 unop( Iop_32Uto64, mkexpr(r_tmp32))));
11322 /* FPRF is undefined after fctiw. Leave unchanged. */
11323 set_FPRF = False;
11324 break;
11326 case 0x00F: // fctiwz (Float Conv to Int, Round to Zero, PPC32 p405)
11327 DIP("fctiwz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11328 assign( r_tmp32,
11329 binop(Iop_F64toI32S, mkU32(Irrm_ZERO), mkexpr(frB) ));
11330 assign( frD, unop( Iop_ReinterpI64asF64,
11331 unop( Iop_32Uto64, mkexpr(r_tmp32))));
11332 /* FPRF is undefined after fctiwz. Leave unchanged. */
11333 set_FPRF = False;
11334 break;
11336 case 0x08F: case 0x08E: // fctiwu[z]
11337 DIP("fctiwu%s%s fr%u,fr%u\n", opc2 == 0x08F ? "z" : "",
11338 flag_rC ? ".":"", frD_addr, frB_addr);
11339 assign( r_tmp32,
11340 binop( Iop_F64toI32U,
11341 opc2 == 0x08F ? mkU32( Irrm_ZERO ) : rm,
11342 mkexpr( frB ) ) );
11343 assign( frD, unop( Iop_ReinterpI64asF64,
11344 unop( Iop_32Uto64, mkexpr(r_tmp32))));
11345 /* FPRF is undefined after fctiwz. Leave unchanged. */
11346 set_FPRF = False;
11347 break;
11350 case 0x32E: // fctid (Float Conv to Int DWord, PPC64 p437)
11351 DIP("fctid%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11352 assign( r_tmp64,
11353 binop(Iop_F64toI64S, rm, mkexpr(frB)) );
11354 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
11355 /* FPRF is undefined after fctid. Leave unchanged. */
11356 set_FPRF = False;
11357 break;
11359 case 0x32F: // fctidz (Float Conv to Int DWord, Round to Zero, PPC64 p437)
11360 DIP("fctidz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11361 assign( r_tmp64,
11362 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), mkexpr(frB)) );
11363 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
11364 /* FPRF is undefined after fctidz. Leave unchanged. */
11365 set_FPRF = False;
11366 break;
11368 case 0x3AE: case 0x3AF: // fctidu[z] (Float Conv to Int DWord Unsigned [Round to Zero])
11370 DIP("fctidu%s%s fr%u,fr%u\n", opc2 == 0x3AE ? "" : "z",
11371 flag_rC ? ".":"", frD_addr, frB_addr);
11372 assign( r_tmp64,
11373 binop(Iop_F64toI64U, opc2 == 0x3AE ? rm : mkU32(Irrm_ZERO), mkexpr(frB)) );
11374 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
11375 /* FPRF is undefined after fctidz. Leave unchanged. */
11376 set_FPRF = False;
11377 break;
11379 case 0x34E: // fcfid (Float Conv from Int DWord, PPC64 p434)
11380 DIP("fcfid%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11381 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
11382 assign( frD,
11383 binop(Iop_I64StoF64, rm, mkexpr(r_tmp64)) );
11384 break;
11386 case 0x3CE: // fcfidu (Float convert from unsigned DWord)
11387 DIP("fcfidu%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11388 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
11389 assign( frD, binop( Iop_I64UtoF64, rm, mkexpr( r_tmp64 ) ) );
11390 break;
11392 case 0x188: case 0x1A8: case 0x1C8: case 0x1E8: // frin, friz, frip, frim
11393 switch(opc2) {
11394 case 0x188: // frin (Floating Round to Integer Nearest)
11395 DIP("frin%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11396 assign( r_tmp64,
11397 binop(Iop_F64toI64S, mkU32(Irrm_NEAREST), mkexpr(frB)) );
11398 break;
11399 case 0x1A8: // friz (Floating Round to Integer Toward Zero)
11400 DIP("friz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11401 assign( r_tmp64,
11402 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), mkexpr(frB)) );
11403 break;
11404 case 0x1C8: // frip (Floating Round to Integer Plus)
11405 DIP("frip%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11406 assign( r_tmp64,
11407 binop(Iop_F64toI64S, mkU32(Irrm_PosINF), mkexpr(frB)) );
11408 break;
11409 case 0x1E8: // frim (Floating Round to Integer Minus)
11410 DIP("frim%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11411 assign( r_tmp64,
11412 binop(Iop_F64toI64S, mkU32(Irrm_NegINF), mkexpr(frB)) );
11413 break;
11416 /* don't use the rounded integer if frB is outside -9e18..9e18 */
11417 /* F64 has only log10(2**52) significant digits anyway */
11418 /* need to preserve sign of zero */
11419 /* frD = (fabs(frB) > 9e18) ? frB :
11420 (sign(frB)) ? -fabs((double)r_tmp64) : (double)r_tmp64 */
11421 assign(frD, IRExpr_ITE(
11422 binop(Iop_CmpNE8,
11423 unop(Iop_32to8,
11424 binop(Iop_CmpF64,
11425 IRExpr_Const(IRConst_F64(9e18)),
11426 unop(Iop_AbsF64, mkexpr(frB)))),
11427 mkU8(0)),
11428 mkexpr(frB),
11429 IRExpr_ITE(
11430 binop(Iop_CmpNE32,
11431 binop(Iop_Shr32,
11432 unop(Iop_64HIto32,
11433 unop(Iop_ReinterpF64asI64,
11434 mkexpr(frB))),
11435 mkU8(31)),
11436 mkU32(0)),
11437 unop(Iop_NegF64,
11438 unop( Iop_AbsF64,
11439 binop(Iop_I64StoF64, mkU32(0),
11440 mkexpr(r_tmp64)) )),
11441 binop(Iop_I64StoF64, mkU32(0), mkexpr(r_tmp64) )
11444 break;
11446 default:
11447 vex_printf("dis_fp_round(ppc)(opc2)\n");
11448 return False;
11450 putFR:
11451 putFReg( frD_addr, mkexpr(frD) );
11453 if (set_FPRF) {
11454 // XXX XXX XXX FIXME
11455 // set FPRF from frD
11458 if (flag_rC && clear_CR1) {
11459 putCR321( 1, mkU8(0) );
11460 putCR0( 1, mkU8(0) );
11463 return True;
11467 Floating Point Pair Instructions
11469 static Bool dis_fp_pair ( UInt theInstr )
11471 /* X-Form/DS-Form */
11472 UChar opc1 = ifieldOPC(theInstr);
11473 UChar frT_hi_addr = ifieldRegDS(theInstr);
11474 UChar frT_lo_addr = frT_hi_addr + 1;
11475 UChar rA_addr = ifieldRegA(theInstr);
11476 UChar rB_addr = ifieldRegB(theInstr);
11477 UInt uimm16 = ifieldUIMM16(theInstr);
11478 Int simm16 = extend_s_16to32(uimm16);
11479 UInt opc2 = ifieldOPClo10(theInstr);
11480 IRType ty = mode64 ? Ity_I64 : Ity_I32;
11481 IRTemp EA_hi = newTemp(ty);
11482 IRTemp EA_lo = newTemp(ty);
11483 IRTemp frT_hi = newTemp(Ity_F64);
11484 IRTemp frT_lo = newTemp(Ity_F64);
11485 UChar b0 = ifieldBIT0(theInstr);
11486 Bool is_load = 0;
11488 switch (opc1) {
11489 case 0x1F: // register offset
11490 /* These instructions work on a pair of registers. The specified
11491 * register must be even.
11493 if ((frT_hi_addr %2) != 0) {
11494 vex_printf("dis_fp_pair(ppc) ldpx or stdpx: odd frT register\n");
11495 return False;
11498 switch(opc2) {
11499 case 0x317: // lfdpx (FP Load Double Pair X-form, ISA 2.05 p125)
11500 DIP("ldpx fr%u,r%u,r%u\n", frT_hi_addr, rA_addr, rB_addr);
11501 is_load = 1;
11502 break;
11503 case 0x397: // stfdpx (FP STORE Double Pair X-form, ISA 2.05 p125)
11504 DIP("stdpx fr%u,r%u,r%u\n", frT_hi_addr, rA_addr, rB_addr);
11505 break;
11506 default:
11507 vex_printf("dis_fp_pair(ppc) : X-form wrong opc2\n");
11508 return False;
11511 if (b0 != 0) {
11512 vex_printf("dis_fp_pair(ppc)(0x1F,b0)\n");
11513 return False;
11515 assign( EA_hi, ea_rAor0_idxd( rA_addr, rB_addr ) );
11516 break;
11517 case 0x39:
11519 UInt DS = IFIELD( theInstr, 2, 14);
11520 UChar vRT = ifieldRegDS(theInstr);
11521 IRTemp EA = newTemp( ty );
11523 opc2 = ifieldOPC0o2(theInstr);
11525 switch(opc2) {
11526 case 0x0: // lfdp (FP Load Double Pair DS-form, ISA 2.05 p125)
11527 /* This instruction works on a pair of registers. The specified
11528 * register must be even.
11530 if ((frT_hi_addr %2) != 0) {
11531 vex_printf("dis_fp_pair(ppc) lfdp : odd frT register\n");
11532 return False;
11535 DIP("lfdp fr%u,%d(r%u)\n", frT_hi_addr, simm16, rA_addr);
11536 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
11537 is_load = 1;
11538 break;
11540 case 0x2: // lxsd (Load VSX Scalar Doubleword)
11541 DIP("lxsd v%u,%d(r%u)\n", vRT, DS, rA_addr);
11543 assign( EA, ea_rAor0_simm( rA_addr, DS<<2 ) );
11545 putVSReg( vRT+32, binop( Iop_64HLtoV128,
11546 load( Ity_I64, mkexpr( EA ) ),
11547 mkU64( 0 ) ) );
11548 return True;
11550 case 0x3: // lxssp (Load VSX Scalar Single from memory,
11551 // store as double in register)
11552 DIP("lxssp v%u,%d(r%u)\n", vRT, DS, rA_addr);
11554 assign( EA, ea_rAor0_simm( rA_addr, DS<<2 ) );
11556 putVSReg( vRT+32,
11557 binop( Iop_64HLtoV128,
11558 unop( Iop_ReinterpF64asI64,
11559 unop( Iop_F32toF64,
11560 unop( Iop_ReinterpI32asF32,
11561 load( Ity_I32, mkexpr( EA ) ) ) ) ),
11562 mkU64( 0 ) ) );
11563 return True;
11565 default:
11566 vex_printf("dis_fp_pair(ppc) : DS-form wrong opc2\n");
11567 return False;
11569 break;
11571 case 0x3d:
11573 UInt DS = IFIELD( theInstr, 2, 14);
11574 UChar vRS = ifieldRegDS(theInstr);
11575 IRTemp EA = newTemp( ty );
11577 opc2 = ifieldOPC0o2(theInstr);
11579 switch(opc2) {
11580 case 0x0:
11581 // stfdp (FP Store Double Pair DS-form, ISA 2.05 p125)
11582 /* This instruction works on a pair of registers. The specified
11583 * register must be even.
11585 if ((frT_hi_addr %2) != 0) {
11586 vex_printf("dis_fp_pair(ppc) stfdp : odd frT register\n");
11587 return False;
11590 DIP("stfdp fr%u,%d(r%u)\n", frT_hi_addr, simm16, rA_addr);
11591 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
11592 break;
11594 case 0x1:
11596 UInt ea_off = 8;
11597 IRTemp word[2];
11598 IRExpr* irx_addr;
11599 UInt T = IFIELD( theInstr, 21, 5); // T or S depending on inst
11600 UInt TX = IFIELD( theInstr, 3, 1); // TX or SX field
11602 word[0] = newTemp(Ity_I64);
11603 word[1] = newTemp(Ity_I64);
11604 DS = IFIELD( theInstr, 4, 12); // DQ in the instruction definition
11605 assign( EA, ea_rAor0_simm( rA_addr, DS<<4 ) );
11607 if ( IFIELD( theInstr, 0, 3) == 1) {
11608 // lxv (Load VSX Vector)
11609 DIP("lxv v%u,%d(r%u)\n", vRS, DS, rA_addr);
11611 assign( word[0], load( Ity_I64, mkexpr( EA ) ) );
11613 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
11614 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
11616 assign( word[1], load( Ity_I64, irx_addr ) );
11618 if (host_endness == VexEndnessBE)
11619 putVSReg( TX*32+T, binop( Iop_64HLtoV128,
11620 mkexpr( word[0] ),
11621 mkexpr( word[1] ) ) );
11622 else
11623 putVSReg( TX*32+T, binop( Iop_64HLtoV128,
11624 mkexpr( word[1] ),
11625 mkexpr( word[0] ) ) );
11626 return True;
11628 } else if ( IFIELD( theInstr, 0, 3) == 5) {
11629 // stxv (Store VSX Vector)
11630 DIP("stxv v%u,%d(r%u)\n", vRS, DS, rA_addr);
11632 if (host_endness == VexEndnessBE) {
11633 store( mkexpr(EA), unop( Iop_V128HIto64,
11634 getVSReg( TX*32+T ) ) );
11635 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
11636 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
11637 store( irx_addr, unop( Iop_V128to64,
11638 getVSReg( TX*32+T ) ) );
11639 } else {
11640 store( mkexpr(EA), unop( Iop_V128to64,
11641 getVSReg( TX*32+T ) ) );
11642 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
11643 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
11644 store( irx_addr, unop( Iop_V128HIto64,
11645 getVSReg( TX*32+T ) ) );
11647 return True;
11649 } else {
11650 vex_printf("dis_fp_pair vector load/store (ppc) : DS-form wrong opc2\n");
11651 return False;
11653 break;
11655 case 0x2:
11656 // stxsd (Store VSX Scalar Doubleword)
11657 DIP("stxsd v%u,%d(r%u)\n", vRS, DS, rA_addr);
11659 assign( EA, ea_rAor0_simm( rA_addr, DS<<2 ) );
11661 store( mkexpr(EA), unop( Iop_V128HIto64,
11662 getVSReg( vRS+32 ) ) );
11663 /* HW is clearing vector element 1. Don't see that in the ISA but
11664 * matching the HW.
11666 putVSReg( vRS+32, binop( Iop_64HLtoV128,
11667 unop( Iop_V128HIto64,
11668 getVSReg( vRS+32 ) ),
11669 mkU64( 0 ) ) );
11670 return True;
11672 case 0x3:
11674 // stxssp (Store VSX Scalar Single - store double precision
11675 // value from register into memory in single precision format)
11676 IRTemp high64 = newTemp(Ity_F64);
11677 IRTemp val32 = newTemp(Ity_I32);
11679 DIP("stxssp v%u,%d(r%u)\n", vRS, DS, rA_addr);
11681 assign( EA, ea_rAor0_simm( rA_addr, DS<<2 ) );
11682 assign(high64, unop( Iop_ReinterpI64asF64,
11683 unop( Iop_V128HIto64, getVSReg( vRS+32 ) ) ) );
11685 assign(val32, unop( Iop_ReinterpF32asI32,
11686 unop( Iop_TruncF64asF32,
11687 mkexpr(high64) ) ) );
11688 store( mkexpr(EA), mkexpr( val32 ) );
11690 return True;
11692 default:
11693 vex_printf("dis_fp_pair(ppc) : DS-form wrong opc2\n");
11694 return False;
11696 break;
11698 default: // immediate offset
11699 vex_printf("dis_fp_pair(ppc)(instr)\n");
11700 return False;
11703 if (mode64)
11704 assign( EA_lo, binop(Iop_Add64, mkexpr(EA_hi), mkU64(8)) );
11705 else
11706 assign( EA_lo, binop(Iop_Add32, mkexpr(EA_hi), mkU32(8)) );
11708 assign( frT_hi, getFReg(frT_hi_addr) );
11709 assign( frT_lo, getFReg(frT_lo_addr) );
11711 if (is_load) {
11712 putFReg( frT_hi_addr, load(Ity_F64, mkexpr(EA_hi)) );
11713 putFReg( frT_lo_addr, load(Ity_F64, mkexpr(EA_lo)) );
11714 } else {
11715 store( mkexpr(EA_hi), mkexpr(frT_hi) );
11716 store( mkexpr(EA_lo), mkexpr(frT_lo) );
11719 return True;
11724 Floating Point Merge Instructions
11726 static Bool dis_fp_merge ( UInt theInstr )
11728 /* X-Form */
11729 UInt opc2 = ifieldOPClo10(theInstr);
11730 UChar frD_addr = ifieldRegDS(theInstr);
11731 UChar frA_addr = ifieldRegA(theInstr);
11732 UChar frB_addr = ifieldRegB(theInstr);
11734 IRTemp frD = newTemp(Ity_F64);
11735 IRTemp frA = newTemp(Ity_F64);
11736 IRTemp frB = newTemp(Ity_F64);
11738 assign( frA, getFReg(frA_addr));
11739 assign( frB, getFReg(frB_addr));
11741 switch (opc2) {
11742 case 0x3c6: // fmrgew floating merge even word
11743 DIP("fmrgew fr%u,fr%u,fr%u\n", frD_addr, frA_addr, frB_addr);
11745 assign( frD, unop( Iop_ReinterpI64asF64,
11746 binop( Iop_32HLto64,
11747 unop( Iop_64HIto32,
11748 unop( Iop_ReinterpF64asI64,
11749 mkexpr(frA) ) ),
11750 unop( Iop_64HIto32,
11751 unop( Iop_ReinterpF64asI64,
11752 mkexpr(frB) ) ) ) ) );
11753 break;
11755 case 0x346: // fmrgow floating merge odd word
11756 DIP("fmrgow fr%u,fr%u,fr%u\n", frD_addr, frA_addr, frB_addr);
11758 assign( frD, unop( Iop_ReinterpI64asF64,
11759 binop( Iop_32HLto64,
11760 unop( Iop_64to32,
11761 unop( Iop_ReinterpF64asI64,
11762 mkexpr(frA) ) ),
11763 unop( Iop_64to32,
11764 unop( Iop_ReinterpF64asI64,
11765 mkexpr(frB) ) ) ) ) );
11766 break;
11768 default:
11769 vex_printf("dis_fp_merge(ppc)(opc2)\n");
11770 return False;
11773 putFReg( frD_addr, mkexpr(frD) );
11774 return True;
11778 Floating Point Move Instructions
11780 static Bool dis_fp_move ( UInt theInstr )
11782 /* X-Form */
11783 UChar opc1 = ifieldOPC(theInstr);
11784 UChar frD_addr = ifieldRegDS(theInstr);
11785 UChar frA_addr = ifieldRegA(theInstr);
11786 UChar frB_addr = ifieldRegB(theInstr);
11787 UInt opc2 = ifieldOPClo10(theInstr);
11788 UChar flag_rC = ifieldBIT0(theInstr);
11790 IRTemp frD = newTemp(Ity_F64);
11791 IRTemp frB = newTemp(Ity_F64);
11792 IRTemp itmpB = newTemp(Ity_F64);
11793 IRTemp frA;
11794 IRTemp signA;
11795 IRTemp hiD;
11797 if (opc1 != 0x3F || (frA_addr != 0 && opc2 != 0x008)) {
11798 vex_printf("dis_fp_move(ppc)(instr)\n");
11799 return False;
11802 assign( frB, getFReg(frB_addr));
11804 switch (opc2) {
11805 case 0x008: // fcpsgn (Floating Copy Sign, ISA_V2.05 p126)
11806 DIP("fcpsgn%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frA_addr,
11807 frB_addr);
11808 signA = newTemp(Ity_I32);
11809 hiD = newTemp(Ity_I32);
11810 itmpB = newTemp(Ity_I64);
11811 frA = newTemp(Ity_F64);
11812 assign( frA, getFReg(frA_addr) );
11814 /* get A's sign bit */
11815 assign(signA, binop(Iop_And32,
11816 unop(Iop_64HIto32, unop(Iop_ReinterpF64asI64,
11817 mkexpr(frA))),
11818 mkU32(0x80000000)) );
11820 assign( itmpB, unop(Iop_ReinterpF64asI64, mkexpr(frB)) );
11822 /* mask off B's sign bit and or in A's sign bit */
11823 assign(hiD, binop(Iop_Or32,
11824 binop(Iop_And32,
11825 unop(Iop_64HIto32,
11826 mkexpr(itmpB)), /* frB's high 32 bits */
11827 mkU32(0x7fffffff)),
11828 mkexpr(signA)) );
11830 /* combine hiD/loB into frD */
11831 assign( frD, unop(Iop_ReinterpI64asF64,
11832 binop(Iop_32HLto64,
11833 mkexpr(hiD),
11834 unop(Iop_64to32,
11835 mkexpr(itmpB)))) ); /* frB's low 32 bits */
11836 break;
11838 case 0x028: // fneg (Floating Negate, PPC32 p416)
11839 DIP("fneg%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11840 assign( frD, unop( Iop_NegF64, mkexpr(frB) ));
11841 break;
11843 case 0x048: // fmr (Floating Move Register, PPC32 p410)
11844 DIP("fmr%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11845 assign( frD, mkexpr(frB) );
11846 break;
11848 case 0x088: // fnabs (Floating Negative Absolute Value, PPC32 p415)
11849 DIP("fnabs%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11850 assign( frD, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr(frB) )));
11851 break;
11853 case 0x108: // fabs (Floating Absolute Value, PPC32 p399)
11854 DIP("fabs%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
11855 assign( frD, unop( Iop_AbsF64, mkexpr(frB) ));
11856 break;
11858 default:
11859 vex_printf("dis_fp_move(ppc)(opc2)\n");
11860 return False;
11863 putFReg( frD_addr, mkexpr(frD) );
11865 /* None of these change FPRF. cr1 is set in the usual way though,
11866 if flag_rC is set. */
11868 if (flag_rC) {
11869 putCR321( 1, mkU8(0) );
11870 putCR0( 1, mkU8(0) );
11873 return True;
11879 Floating Point Status/Control Register Instructions
11881 static Bool dis_fp_scr ( UInt theInstr, Bool GX_level )
11883 /* Many forms - see each switch case */
11884 UChar opc1 = ifieldOPC(theInstr);
11885 UInt opc2 = ifieldOPClo10(theInstr);
11886 UChar flag_rC = ifieldBIT0(theInstr);
11888 if (opc1 != 0x3F) {
11889 vex_printf("dis_fp_scr(ppc)(instr)\n");
11890 return False;
11893 switch (opc2) {
11894 case 0x026: { // mtfsb1 (Move to FPSCR Bit 1, PPC32 p479)
11895 // Bit crbD of the FPSCR is set.
11896 UChar crbD = ifieldRegDS(theInstr);
11897 UInt b11to20 = IFIELD(theInstr, 11, 10);
11899 if (b11to20 != 0) {
11900 vex_printf("dis_fp_scr(ppc)(instr,mtfsb1)\n");
11901 return False;
11903 DIP("mtfsb1%s crb%d \n", flag_rC ? ".":"", crbD);
11904 putGST_masked( PPC_GST_FPSCR, mkU64( 1 <<( 31 - crbD ) ),
11905 1ULL << ( 31 - crbD ) );
11906 break;
11909 case 0x040: { // mcrfs (Move to Condition Register from FPSCR, PPC32 p465)
11910 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
11911 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
11912 UChar crfS = toUChar( IFIELD( theInstr, 18, 3 ) );
11913 UChar b11to17 = toUChar( IFIELD( theInstr, 11, 7 ) );
11914 IRTemp tmp = newTemp(Ity_I32);
11915 IRExpr* fpscr_all;
11916 if (b21to22 != 0 || b11to17 != 0 || flag_rC != 0) {
11917 vex_printf("dis_fp_scr(ppc)(instr,mcrfs)\n");
11918 return False;
11920 DIP("mcrfs crf%d,crf%d\n", crfD, crfS);
11921 vassert(crfD < 8);
11922 vassert(crfS < 8);
11923 fpscr_all = getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN );
11924 assign( tmp, binop(Iop_And32,
11925 binop(Iop_Shr32,fpscr_all,mkU8(4 * (7-crfS))),
11926 mkU32(0xF)) );
11927 putGST_field( PPC_GST_CR, mkexpr(tmp), crfD );
11928 break;
11931 case 0x046: { // mtfsb0 (Move to FPSCR Bit 0, PPC32 p478)
11932 // Bit crbD of the FPSCR is cleared.
11933 UChar crbD = ifieldRegDS(theInstr);
11934 UInt b11to20 = IFIELD(theInstr, 11, 10);
11936 if (b11to20 != 0) {
11937 vex_printf("dis_fp_scr(ppc)(instr,mtfsb0)\n");
11938 return False;
11940 DIP("mtfsb0%s crb%d\n", flag_rC ? ".":"", crbD);
11941 putGST_masked( PPC_GST_FPSCR, mkU64( 0 ), 1ULL << ( 31 - crbD ) );
11942 break;
11945 case 0x086: { // mtfsfi (Move to FPSCR Field Immediate, PPC32 p481)
11946 UInt crfD = IFIELD( theInstr, 23, 3 );
11947 UChar b17to22 = toUChar( IFIELD( theInstr, 17, 6 ) );
11948 UChar IMM = toUChar( IFIELD( theInstr, 12, 4 ) );
11949 UChar b11 = toUChar( IFIELD( theInstr, 11, 1 ) );
11950 UChar Wbit = toUChar( IFIELD( theInstr, 16, 1 ) );
11952 if (b17to22 != 0 || b11 != 0 || (Wbit && !GX_level)) {
11953 vex_printf("dis_fp_scr(ppc)(instr,mtfsfi)\n");
11954 return False;
11956 DIP("mtfsfi%s crf%u,%d%s\n", flag_rC ? ".":"", crfD, IMM, Wbit ? ",1":"");
11957 crfD = crfD + (8 * (1 - Wbit) );
11958 putGST_field( PPC_GST_FPSCR, mkU32( IMM ), crfD );
11959 break;
11962 case 0x247: { // mffs (Move from FPSCR, PPC32 p468)
11963 UChar frD_addr = ifieldRegDS(theInstr);
11964 UChar frB_addr = ifieldRegB(theInstr);
11965 IRTemp frB = newTemp(Ity_F64);
11966 UInt b11to12 = IFIELD(theInstr, 19, 2);
11967 UInt b13to15 = IFIELD(theInstr, 16, 3);
11968 UInt RN = IFIELD(theInstr, 11, 2);
11969 UInt DRN = IFIELD(theInstr, 11, 3);
11971 /* The FPSCR_DRN, FPSCR_RN and FPSCR_FPCC are all stored in
11972 * their own 8-bit entries with distinct offsets. The FPSCR
11973 * register is handled as two 32-bit values. We need to
11974 * assemble the pieces into the single 64-bit value to return.
11976 IRExpr* fpscr_lower
11977 = binop( Iop_Or32,
11978 getGST_masked( PPC_GST_FPSCR, (MASK_FPSCR_RN | MASK_FPSCR_C_FPCC) ),
11979 binop( Iop_Or32,
11980 binop( Iop_Shl32,
11981 getC(),
11982 mkU8(63-47) ) ,
11983 binop( Iop_Shl32,
11984 getFPCC(),
11985 mkU8(63-51) ) ) );
11986 IRExpr* fpscr_upper = getGST_masked_upper( PPC_GST_FPSCR, MASK_FPSCR_DRN );
11988 if ((b11to12 == 0) && (b13to15 == 0)) {
11989 DIP("mffs%s fr%u\n", flag_rC ? ".":"", frD_addr);
11990 putFReg( frD_addr,
11991 unop( Iop_ReinterpI64asF64,
11992 binop( Iop_32HLto64, fpscr_upper, fpscr_lower ) ) );
11994 } else if ((b11to12 == 0) && (b13to15 == 1)) {
11995 DIP("mffsce fr%u\n", frD_addr);
11996 /* Technically as of 4/5/2017 we are not tracking VE, OE, UE, ZE,
11997 or XE but in case that changes in the future, do the masking. */
11998 putFReg( frD_addr,
11999 unop( Iop_ReinterpI64asF64,
12000 binop( Iop_32HLto64, fpscr_upper,
12001 binop( Iop_And32, fpscr_lower,
12002 mkU32( 0xFFFFFF07 ) ) ) ) );
12004 } else if ((b11to12 == 2) && (b13to15 == 4)) {
12005 IRTemp frB_int = newTemp(Ity_I64);
12007 DIP("mffscdrn fr%u,fr%u\n", frD_addr, frB_addr);
12009 assign( frB, getFReg(frB_addr));
12010 assign( frB_int, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
12012 /* Clear all of the FPSCR bits except for the DRN field, VE,
12013 OE, UE, ZE and XE bits and write the result to the frD
12014 register. Note, currently the exception bits are not tracked but
12015 will mask anyway in case that changes in the future. */
12016 putFReg( frD_addr,
12017 unop( Iop_ReinterpI64asF64,
12018 binop( Iop_32HLto64,
12019 binop( Iop_And32, mkU32(0x7), fpscr_upper ),
12020 binop( Iop_And32, mkU32(0xFF), fpscr_lower ) ) ) );
12022 /* Put new_DRN bits into the FPSCR register */
12023 putGST_masked( PPC_GST_FPSCR, mkexpr( frB_int ), MASK_FPSCR_DRN );
12025 } else if ((b11to12 == 2) && (b13to15 == 5)) {
12026 DIP("mffscdrni fr%u,%d\n", frD_addr, DRN);
12028 /* Clear all of the FPSCR bits except for the DRN field, VE,
12029 OE, UE, ZE and XE bits and write the result to the frD
12030 register. Note, currently the exception bits are not tracked but
12031 will mask anyway in case that changes in the future. */
12032 putFReg( frD_addr,
12033 unop( Iop_ReinterpI64asF64,
12034 binop( Iop_32HLto64,
12035 binop( Iop_And32, mkU32(0x7), fpscr_upper ),
12036 binop( Iop_And32, mkU32(0xFF), fpscr_lower ) ) ) );
12038 /* Put new_DRN bits into the FPSCR register */
12039 putGST_masked( PPC_GST_FPSCR, binop( Iop_32HLto64, mkU32( DRN ),
12040 mkU32( 0 ) ), MASK_FPSCR_DRN );
12042 } else if ((b11to12 == 2) && (b13to15 == 6)) {
12043 IRTemp frB_int = newTemp(Ity_I64);
12045 DIP("mffscrn fr%u,fr%u\n", frD_addr,frB_addr);
12047 assign( frB, getFReg(frB_addr));
12048 assign( frB_int, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
12050 /* Clear all of the FPSCR bits except for the DRN field, VE,
12051 OE, UE, ZE and XE bits and write the result to the frD
12052 register. Note, currently the exception bits are not tracked but
12053 will mask anyway in case that changes in the future. */
12054 putFReg( frD_addr,
12055 unop( Iop_ReinterpI64asF64,
12056 binop( Iop_32HLto64,
12057 binop( Iop_And32, mkU32(0x7), fpscr_upper ),
12058 binop( Iop_And32, mkU32(0xFF), fpscr_lower ) ) ) );
12060 /* Put new_CRN bits into the FPSCR register */
12061 putGST_masked( PPC_GST_FPSCR, mkexpr( frB_int ), MASK_FPSCR_RN );
12063 } else if ((b11to12 == 2) && (b13to15 == 7)) {
12064 DIP("mffscrni fr%u,%u\n", frD_addr, RN);
12066 /* Clear all of the FPSCR bits except for the DRN field, VE,
12067 OE, UE, ZE and XE bits and write the result to the frD
12068 register. Note, currently the exception bits are not tracked but
12069 will mask anyway in case that changes in the future. */
12070 putFReg( frD_addr,
12071 unop( Iop_ReinterpI64asF64,
12072 binop( Iop_32HLto64,
12073 binop( Iop_And32, mkU32(0x7), fpscr_upper ),
12074 binop( Iop_And32, mkU32(0xFF), fpscr_lower ) ) ) );
12076 /* Put new_RN bits into the FPSCR register */
12077 putGST_masked( PPC_GST_FPSCR, binop( Iop_32HLto64, mkU32( 0 ),
12078 mkU32( RN ) ), MASK_FPSCR_RN );
12080 } else if ((b11to12 == 3) && (b13to15 == 0)) {
12081 DIP("mffsl fr%u\n", frD_addr);
12082 /* Technically as of 4/5/2017 we are not tracking VE, OE, UE, ZE,
12083 XE, FR, FI, C, FL, FG, FE, FU. Also only track DRN in the upper
12084 bits but in case that changes in the future we will do the
12085 masking. */
12086 putFReg( frD_addr,
12087 unop( Iop_ReinterpI64asF64,
12088 binop( Iop_32HLto64,
12089 binop( Iop_And32, fpscr_upper,
12090 mkU32( 0x7 ) ),
12091 binop( Iop_And32, fpscr_lower,
12092 mkU32( 0x7F0FF ) ) ) ) );
12093 } else {
12094 vex_printf("dis_fp_scr(ppc)(mff**) Unrecognized instruction.\n");
12095 return False;
12097 break;
12100 case 0x2C7: { // mtfsf (Move to FPSCR Fields, PPC32 p480)
12101 UChar b25 = toUChar( IFIELD(theInstr, 25, 1) );
12102 UChar FM = toUChar( IFIELD(theInstr, 17, 8) );
12103 UChar frB_addr = ifieldRegB(theInstr);
12104 IRTemp frB = newTemp(Ity_F64);
12105 IRTemp rB_64 = newTemp( Ity_I64 );
12106 Int i;
12107 ULong mask;
12108 UChar Wbit;
12109 #define BFP_MASK_SEED 0x3000000000000000ULL
12110 #define DFP_MASK_SEED 0x7000000000000000ULL
12112 if (GX_level) {
12113 /* This implies that Decimal Floating Point is supported, and the
12114 * FPSCR must be managed as a 64-bit register.
12116 Wbit = toUChar( IFIELD(theInstr, 16, 1) );
12117 } else {
12118 Wbit = 0;
12121 if (b25 == 1) {
12122 /* new 64 bit move variant for power 6. If L field (bit 25) is
12123 * a one do a full 64 bit move. Note, the FPSCR is not really
12124 * properly modeled. This instruciton only changes the value of
12125 * the rounding mode bit fields RN, FPCC and DRN. The HW exception bits
12126 * do not get set in the simulator. 1/12/09
12128 DIP("mtfsf%s %d,fr%u (L=1)\n", flag_rC ? ".":"", FM, frB_addr);
12129 mask = 0x1F0001F003;
12131 } else {
12132 DIP("mtfsf%s %d,fr%u\n", flag_rC ? ".":"", FM, frB_addr);
12133 // Build 32bit mask from FM:
12134 mask = 0;
12135 for (i=0; i<8; i++) {
12136 if ((FM & (1<<(7-i))) == 1) {
12137 /* FPSCR field k is set to the contents of the corresponding
12138 * field of register FRB, where k = i+8x(1-W). In the Power
12139 * ISA, register field numbering is from left to right, so field
12140 * 15 is the least significant field in a 64-bit register. To
12141 * generate the mask, we set all the appropriate rounding mode
12142 * bits in the highest order nibble (field 0) and shift right
12143 * 'k x nibble length'.
12145 if (Wbit)
12146 mask |= DFP_MASK_SEED >> ( 4 * ( i + 8 * ( 1 - Wbit ) ) );
12147 else
12148 mask |= BFP_MASK_SEED >> ( 4 * ( i + 8 * ( 1 - Wbit ) ) );
12150 if ((FM & (1<<(7-i))) == 0x2) { //set the FPCC bits
12151 mask |= 0xF000;
12153 if ((FM & (1<<(7-i))) == 0x4) { //set the Floating-Point Class Descriptor (C) bit
12154 mask |= 0x10000;
12158 assign( frB, getFReg(frB_addr));
12159 assign( rB_64, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
12160 putGST_masked( PPC_GST_FPSCR, mkexpr( rB_64 ), mask );
12161 break;
12164 default:
12165 vex_printf("dis_fp_scr(ppc)(opc2)\n");
12166 return False;
12168 return True;
12171 /*------------------------------------------------------------*/
12172 /*--- Decimal Floating Point (DFP) Helper functions ---*/
12173 /*------------------------------------------------------------*/
12174 #define DFP_LONG 1
12175 #define DFP_EXTND 2
12176 #define DFP_LONG_BIAS 398
12177 #define DFP_LONG_ENCODED_FIELD_MASK 0x1F00
12178 #define DFP_EXTND_BIAS 6176
12179 #define DFP_EXTND_ENCODED_FIELD_MASK 0x1F000
12180 #define DFP_LONG_EXP_MSK 0XFF
12181 #define DFP_EXTND_EXP_MSK 0XFFF
12183 #define DFP_G_FIELD_LONG_MASK 0x7FFC0000 // upper 32-bits only
12184 #define DFP_LONG_GFIELD_RT_SHIFT (63 - 13 - 32) // adj for upper 32-bits
12185 #define DFP_G_FIELD_EXTND_MASK 0x7FFFC000 // upper 32-bits only
12186 #define DFP_EXTND_GFIELD_RT_SHIFT (63 - 17 - 32) //adj for upper 32 bits
12187 #define DFP_T_FIELD_LONG_MASK 0x3FFFF // mask for upper 32-bits
12188 #define DFP_T_FIELD_EXTND_MASK 0x03FFFF // mask for upper 32-bits
12189 #define DFP_LONG_EXP_MAX 369 // biased max
12190 #define DFP_LONG_EXP_MIN 0 // biased min
12191 #define DFP_EXTND_EXP_MAX 6111 // biased max
12192 #define DFP_EXTND_EXP_MIN 0 // biased min
12193 #define DFP_LONG_MAX_SIG_DIGITS 16
12194 #define DFP_EXTND_MAX_SIG_DIGITS 34
12195 #define MAX_DIGITS_IN_STRING 8
12198 #define AND(x, y) binop( Iop_And32, x, y )
12199 #define AND4(w, x, y, z) AND( AND( w, x ), AND( y, z ) )
12200 #define OR(x, y) binop( Iop_Or32, x, y )
12201 #define OR3(x, y, z) OR( x, OR( y, z ) )
12202 #define OR4(w, x, y, z) OR( OR( w, x ), OR( y, z ) )
12203 #define NOT(x) unop( Iop_1Uto32, unop( Iop_Not1, unop( Iop_32to1, mkexpr( x ) ) ) )
12205 #define SHL(value, by) binop( Iop_Shl32, value, mkU8( by ) )
12206 #define SHR(value, by) binop( Iop_Shr32, value, mkU8( by ) )
12208 #define BITS5(_b4,_b3,_b2,_b1,_b0) \
12209 (((_b4) << 4) | ((_b3) << 3) | ((_b2) << 2) | \
12210 ((_b1) << 1) | ((_b0) << 0))
12212 static IRExpr * Gfield_encoding( IRExpr * lmexp, IRExpr * lmd32 )
12214 IRTemp lmd_07_mask = newTemp( Ity_I32 );
12215 IRTemp lmd_8_mask = newTemp( Ity_I32 );
12216 IRTemp lmd_9_mask = newTemp( Ity_I32 );
12217 IRTemp lmexp_00_mask = newTemp( Ity_I32 );
12218 IRTemp lmexp_01_mask = newTemp( Ity_I32 );
12219 IRTemp lmexp_10_mask = newTemp( Ity_I32 );
12220 IRTemp lmd_07_val = newTemp( Ity_I32 );
12221 IRTemp lmd_8_val = newTemp( Ity_I32 );
12222 IRTemp lmd_9_val = newTemp( Ity_I32 );
12224 /* The encodig is as follows:
12225 * lmd - left most digit
12226 * lme - left most 2-bits of the exponent
12228 * lmd
12229 * 0 - 7 (lmexp << 3) | lmd
12230 * 8 0b11000 (24 decimal) if lme=0b00;
12231 * 0b11010 (26 decimal) if lme=0b01;
12232 * 0b11100 (28 decimal) if lme=0b10;
12233 * 9 0b11001 (25 decimal) if lme=0b00;
12234 * 0b11011 (27 decimal) if lme=0b01;
12235 * 0b11101 (29 decimal) if lme=0b10;
12238 /* Generate the masks for each condition */
12239 assign( lmd_07_mask,
12240 unop( Iop_1Sto32, binop( Iop_CmpLE32U, lmd32, mkU32( 7 ) ) ) );
12241 assign( lmd_8_mask,
12242 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmd32, mkU32( 8 ) ) ) );
12243 assign( lmd_9_mask,
12244 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmd32, mkU32( 9 ) ) ) );
12245 assign( lmexp_00_mask,
12246 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 0 ) ) ) );
12247 assign( lmexp_01_mask,
12248 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 1 ) ) ) );
12249 assign( lmexp_10_mask,
12250 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 2 ) ) ) );
12252 /* Generate the values for each LMD condition, assuming the condition
12253 * is TRUE.
12255 assign( lmd_07_val,
12256 binop( Iop_Or32, binop( Iop_Shl32, lmexp, mkU8( 3 ) ), lmd32 ) );
12257 assign( lmd_8_val,
12258 binop( Iop_Or32,
12259 binop( Iop_Or32,
12260 binop( Iop_And32,
12261 mkexpr( lmexp_00_mask ),
12262 mkU32( 24 ) ),
12263 binop( Iop_And32,
12264 mkexpr( lmexp_01_mask ),
12265 mkU32( 26 ) ) ),
12266 binop( Iop_And32, mkexpr( lmexp_10_mask ), mkU32( 28 ) ) ) );
12267 assign( lmd_9_val,
12268 binop( Iop_Or32,
12269 binop( Iop_Or32,
12270 binop( Iop_And32,
12271 mkexpr( lmexp_00_mask ),
12272 mkU32( 25 ) ),
12273 binop( Iop_And32,
12274 mkexpr( lmexp_01_mask ),
12275 mkU32( 27 ) ) ),
12276 binop( Iop_And32, mkexpr( lmexp_10_mask ), mkU32( 29 ) ) ) );
12278 /* generate the result from the possible LMD values */
12279 return binop( Iop_Or32,
12280 binop( Iop_Or32,
12281 binop( Iop_And32,
12282 mkexpr( lmd_07_mask ),
12283 mkexpr( lmd_07_val ) ),
12284 binop( Iop_And32,
12285 mkexpr( lmd_8_mask ),
12286 mkexpr( lmd_8_val ) ) ),
12287 binop( Iop_And32, mkexpr( lmd_9_mask ), mkexpr( lmd_9_val ) ) );
12290 static void Get_lmd( IRTemp * lmd, IRExpr * gfield_0_4 )
12292 /* Extract the exponent and the left most digit of the mantissa
12293 * from the G field bits [0:4].
12295 IRTemp lmd_07_mask = newTemp( Ity_I32 );
12296 IRTemp lmd_8_00_mask = newTemp( Ity_I32 );
12297 IRTemp lmd_8_01_mask = newTemp( Ity_I32 );
12298 IRTemp lmd_8_10_mask = newTemp( Ity_I32 );
12299 IRTemp lmd_9_00_mask = newTemp( Ity_I32 );
12300 IRTemp lmd_9_01_mask = newTemp( Ity_I32 );
12301 IRTemp lmd_9_10_mask = newTemp( Ity_I32 );
12303 IRTemp lmd_07_val = newTemp( Ity_I32 );
12304 IRTemp lmd_8_val = newTemp( Ity_I32 );
12305 IRTemp lmd_9_val = newTemp( Ity_I32 );
12307 /* The left most digit (LMD) encoding is as follows:
12308 * lmd
12309 * 0 - 7 (lmexp << 3) | lmd
12310 * 8 0b11000 (24 decimal) if lme=0b00;
12311 * 0b11010 (26 decimal) if lme=0b01;
12312 * 0b11100 (28 decimal) if lme=0b10
12313 * 9 0b11001 (25 decimal) if lme=0b00;
12314 * 0b11011 (27 decimal) if lme=0b01;
12315 * 0b11101 (29 decimal) if lme=0b10;
12318 /* Generate the masks for each condition of LMD and exponent bits */
12319 assign( lmd_07_mask,
12320 unop( Iop_1Sto32, binop( Iop_CmpLE32U,
12321 gfield_0_4,
12322 mkU32( BITS5(1,0,1,1,1) ) ) ) );
12323 assign( lmd_8_00_mask,
12324 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
12325 gfield_0_4,
12326 mkU32( BITS5(1,1,0,0,0) ) ) ) );
12327 assign( lmd_8_01_mask,
12328 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
12329 gfield_0_4,
12330 mkU32( BITS5(1,1,0,1,0) ) ) ) );
12331 assign( lmd_8_10_mask,
12332 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
12333 gfield_0_4,
12334 mkU32( BITS5(1,1,1,0,0) ) ) ) );
12335 assign( lmd_9_00_mask,
12336 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
12337 gfield_0_4,
12338 mkU32( BITS5(1,1,0,0,1) ) ) ) );
12339 assign( lmd_9_01_mask,
12340 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
12341 gfield_0_4,
12342 mkU32( BITS5(1,1,0,1,1) ) ) ) );
12343 assign( lmd_9_10_mask,
12344 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
12345 gfield_0_4,
12346 mkU32( BITS5(1,1,1,0,1) ) ) ) );
12348 /* Generate the values for each LMD condition, assuming the condition
12349 * is TRUE.
12351 assign( lmd_07_val, binop( Iop_And32, gfield_0_4, mkU32( 0x7 ) ) );
12352 assign( lmd_8_val, mkU32( 0x8 ) );
12353 assign( lmd_9_val, mkU32( 0x9 ) );
12355 assign( *lmd,
12356 OR( OR3 ( AND( mkexpr( lmd_07_mask ), mkexpr( lmd_07_val ) ),
12357 AND( mkexpr( lmd_8_00_mask ), mkexpr( lmd_8_val ) ),
12358 AND( mkexpr( lmd_8_01_mask ), mkexpr( lmd_8_val ) )),
12359 OR4( AND( mkexpr( lmd_8_10_mask ), mkexpr( lmd_8_val ) ),
12360 AND( mkexpr( lmd_9_00_mask ), mkexpr( lmd_9_val ) ),
12361 AND( mkexpr( lmd_9_01_mask ), mkexpr( lmd_9_val ) ),
12362 AND( mkexpr( lmd_9_10_mask ), mkexpr( lmd_9_val ) )
12363 ) ) );
12366 #define DIGIT1_SHR 4 // shift digit 1 to bottom 4 bits
12367 #define DIGIT2_SHR 8 // shift digit 2 to bottom 4 bits
12368 #define DIGIT3_SHR 12
12369 #define DIGIT4_SHR 16
12370 #define DIGIT5_SHR 20
12371 #define DIGIT6_SHR 24
12372 #define DIGIT7_SHR 28
12374 static IRExpr * bcd_digit_inval( IRExpr * bcd_u, IRExpr * bcd_l )
12376 /* 60-bit BCD string stored in two 32-bit values. Check that each,
12377 * digit is a valid BCD number, i.e. less then 9.
12379 IRTemp valid = newTemp( Ity_I32 );
12381 assign( valid,
12382 AND4( AND4 ( unop( Iop_1Sto32,
12383 binop( Iop_CmpLE32U,
12384 binop( Iop_And32,
12385 bcd_l,
12386 mkU32 ( 0xF ) ),
12387 mkU32( 0x9 ) ) ),
12388 unop( Iop_1Sto32,
12389 binop( Iop_CmpLE32U,
12390 binop( Iop_And32,
12391 binop( Iop_Shr32,
12392 bcd_l,
12393 mkU8 ( DIGIT1_SHR ) ),
12394 mkU32 ( 0xF ) ),
12395 mkU32( 0x9 ) ) ),
12396 unop( Iop_1Sto32,
12397 binop( Iop_CmpLE32U,
12398 binop( Iop_And32,
12399 binop( Iop_Shr32,
12400 bcd_l,
12401 mkU8 ( DIGIT2_SHR ) ),
12402 mkU32 ( 0xF ) ),
12403 mkU32( 0x9 ) ) ),
12404 unop( Iop_1Sto32,
12405 binop( Iop_CmpLE32U,
12406 binop( Iop_And32,
12407 binop( Iop_Shr32,
12408 bcd_l,
12409 mkU8 ( DIGIT3_SHR ) ),
12410 mkU32 ( 0xF ) ),
12411 mkU32( 0x9 ) ) ) ),
12412 AND4 ( unop( Iop_1Sto32,
12413 binop( Iop_CmpLE32U,
12414 binop( Iop_And32,
12415 binop( Iop_Shr32,
12416 bcd_l,
12417 mkU8 ( DIGIT4_SHR ) ),
12418 mkU32 ( 0xF ) ),
12419 mkU32( 0x9 ) ) ),
12420 unop( Iop_1Sto32,
12421 binop( Iop_CmpLE32U,
12422 binop( Iop_And32,
12423 binop( Iop_Shr32,
12424 bcd_l,
12425 mkU8 ( DIGIT5_SHR ) ),
12426 mkU32 ( 0xF ) ),
12427 mkU32( 0x9 ) ) ),
12428 unop( Iop_1Sto32,
12429 binop( Iop_CmpLE32U,
12430 binop( Iop_And32,
12431 binop( Iop_Shr32,
12432 bcd_l,
12433 mkU8 ( DIGIT6_SHR ) ),
12434 mkU32 ( 0xF ) ),
12435 mkU32( 0x9 ) ) ),
12436 unop( Iop_1Sto32,
12437 binop( Iop_CmpLE32U,
12438 binop( Iop_And32,
12439 binop( Iop_Shr32,
12440 bcd_l,
12441 mkU8 ( DIGIT7_SHR ) ),
12442 mkU32 ( 0xF ) ),
12443 mkU32( 0x9 ) ) ) ),
12444 AND4( unop( Iop_1Sto32,
12445 binop( Iop_CmpLE32U,
12446 binop( Iop_And32,
12447 bcd_u,
12448 mkU32 ( 0xF ) ),
12449 mkU32( 0x9 ) ) ),
12450 unop( Iop_1Sto32,
12451 binop( Iop_CmpLE32U,
12452 binop( Iop_And32,
12453 binop( Iop_Shr32,
12454 bcd_u,
12455 mkU8 ( DIGIT1_SHR ) ),
12456 mkU32 ( 0xF ) ),
12457 mkU32( 0x9 ) ) ),
12458 unop( Iop_1Sto32,
12459 binop( Iop_CmpLE32U,
12460 binop( Iop_And32,
12461 binop( Iop_Shr32,
12462 bcd_u,
12463 mkU8 ( DIGIT2_SHR ) ),
12464 mkU32 ( 0xF ) ),
12465 mkU32( 0x9 ) ) ),
12466 unop( Iop_1Sto32,
12467 binop( Iop_CmpLE32U,
12468 binop( Iop_And32,
12469 binop( Iop_Shr32,
12470 bcd_u,
12471 mkU8 ( DIGIT3_SHR ) ),
12472 mkU32 ( 0xF ) ),
12473 mkU32( 0x9 ) ) ) ),
12474 AND4( unop( Iop_1Sto32,
12475 binop( Iop_CmpLE32U,
12476 binop( Iop_And32,
12477 binop( Iop_Shr32,
12478 bcd_u,
12479 mkU8 ( DIGIT4_SHR ) ),
12480 mkU32 ( 0xF ) ),
12481 mkU32( 0x9 ) ) ),
12482 unop( Iop_1Sto32,
12483 binop( Iop_CmpLE32U,
12484 binop( Iop_And32,
12485 binop( Iop_Shr32,
12486 bcd_u,
12487 mkU8 ( DIGIT5_SHR ) ),
12488 mkU32 ( 0xF ) ),
12489 mkU32( 0x9 ) ) ),
12490 unop( Iop_1Sto32,
12491 binop( Iop_CmpLE32U,
12492 binop( Iop_And32,
12493 binop( Iop_Shr32,
12494 bcd_u,
12495 mkU8 ( DIGIT6_SHR ) ),
12496 mkU32 ( 0xF ) ),
12497 mkU32( 0x9 ) ) ),
12498 unop( Iop_1Sto32,
12499 binop( Iop_CmpLE32U,
12500 binop( Iop_And32,
12501 binop( Iop_Shr32,
12502 bcd_u,
12503 mkU8 ( DIGIT7_SHR ) ),
12504 mkU32 ( 0xF ) ),
12505 mkU32( 0x9 ) ) ) ) ) );
12507 return unop( Iop_Not32, mkexpr( valid ) );
12509 #undef DIGIT1_SHR
12510 #undef DIGIT2_SHR
12511 #undef DIGIT3_SHR
12512 #undef DIGIT4_SHR
12513 #undef DIGIT5_SHR
12514 #undef DIGIT6_SHR
12515 #undef DIGIT7_SHR
12517 static IRExpr * Generate_neg_sign_mask( IRExpr * sign )
12519 return binop( Iop_Or32,
12520 unop( Iop_1Sto32, binop( Iop_CmpEQ32, sign, mkU32( 0xB ) ) ),
12521 unop( Iop_1Sto32, binop( Iop_CmpEQ32, sign, mkU32( 0xD ) ) )
12525 static IRExpr * Generate_pos_sign_mask( IRExpr * sign )
12527 return binop( Iop_Or32,
12528 binop( Iop_Or32,
12529 unop( Iop_1Sto32,
12530 binop( Iop_CmpEQ32, sign, mkU32( 0xA ) ) ),
12531 unop( Iop_1Sto32,
12532 binop( Iop_CmpEQ32, sign, mkU32( 0xC ) ) ) ),
12533 binop( Iop_Or32,
12534 unop( Iop_1Sto32,
12535 binop( Iop_CmpEQ32, sign, mkU32( 0xE ) ) ),
12536 unop( Iop_1Sto32,
12537 binop( Iop_CmpEQ32, sign, mkU32( 0xF ) ) ) ) );
12540 static IRExpr * Generate_sign_bit( IRExpr * pos_sign_mask,
12541 IRExpr * neg_sign_mask )
12543 return binop( Iop_Or32,
12544 binop( Iop_And32, neg_sign_mask, mkU32( 0x80000000 ) ),
12545 binop( Iop_And32, pos_sign_mask, mkU32( 0x00000000 ) ) );
12548 static IRExpr * Generate_inv_mask( IRExpr * invalid_bcd_mask,
12549 IRExpr * pos_sign_mask,
12550 IRExpr * neg_sign_mask )
12551 /* first argument is all 1's if the BCD string had an invalid digit in it. */
12553 return binop( Iop_Or32,
12554 invalid_bcd_mask,
12555 unop( Iop_1Sto32,
12556 binop( Iop_CmpEQ32,
12557 binop( Iop_Or32, pos_sign_mask, neg_sign_mask ),
12558 mkU32( 0x0 ) ) ) );
12561 static void Generate_132_bit_bcd_string( IRExpr * frBI64_hi, IRExpr * frBI64_lo,
12562 IRTemp * top_12_l, IRTemp * mid_60_u,
12563 IRTemp * mid_60_l, IRTemp * low_60_u,
12564 IRTemp * low_60_l)
12566 IRTemp tmplow60 = newTemp( Ity_I64 );
12567 IRTemp tmpmid60 = newTemp( Ity_I64 );
12568 IRTemp tmptop12 = newTemp( Ity_I64 );
12569 IRTemp low_50 = newTemp( Ity_I64 );
12570 IRTemp mid_50 = newTemp( Ity_I64 );
12571 IRTemp top_10 = newTemp( Ity_I64 );
12572 IRTemp top_12_u = newTemp( Ity_I32 ); // only needed for a dummy arg
12574 /* Convert the 110-bit densely packed BCD string to a 128-bit BCD string */
12576 /* low_50[49:0] = ((frBI64_lo[49:32] << 14) | frBI64_lo[31:0]) */
12577 assign( low_50,
12578 binop( Iop_32HLto64,
12579 binop( Iop_And32,
12580 unop( Iop_64HIto32, frBI64_lo ),
12581 mkU32( 0x3FFFF ) ),
12582 unop( Iop_64to32, frBI64_lo ) ) );
12584 /* Convert the 50 bit densely packed BCD string to a 60 bit
12585 * BCD string.
12587 assign( tmplow60, unop( Iop_DPBtoBCD, mkexpr( low_50 ) ) );
12588 assign( *low_60_u, unop( Iop_64HIto32, mkexpr( tmplow60 ) ) );
12589 assign( *low_60_l, unop( Iop_64to32, mkexpr( tmplow60 ) ) );
12591 /* mid_50[49:0] = ((frBI64_hi[35:32] << 14) | frBI64_hi[31:18]) |
12592 * ((frBI64_hi[17:0] << 14) | frBI64_lo[63:50])
12594 assign( mid_50,
12595 binop( Iop_32HLto64,
12596 binop( Iop_Or32,
12597 binop( Iop_Shl32,
12598 binop( Iop_And32,
12599 unop( Iop_64HIto32, frBI64_hi ),
12600 mkU32( 0xF ) ),
12601 mkU8( 14 ) ),
12602 binop( Iop_Shr32,
12603 unop( Iop_64to32, frBI64_hi ),
12604 mkU8( 18 ) ) ),
12605 binop( Iop_Or32,
12606 binop( Iop_Shl32,
12607 unop( Iop_64to32, frBI64_hi ),
12608 mkU8( 14 ) ),
12609 binop( Iop_Shr32,
12610 unop( Iop_64HIto32, frBI64_lo ),
12611 mkU8( 18 ) ) ) ) );
12613 /* Convert the 50 bit densely packed BCD string to a 60 bit
12614 * BCD string.
12616 assign( tmpmid60, unop( Iop_DPBtoBCD, mkexpr( mid_50 ) ) );
12617 assign( *mid_60_u, unop( Iop_64HIto32, mkexpr( tmpmid60 ) ) );
12618 assign( *mid_60_l, unop( Iop_64to32, mkexpr( tmpmid60 ) ) );
12620 /* top_10[49:0] = frBI64_hi[45:36]) | */
12621 assign( top_10,
12622 binop( Iop_32HLto64,
12623 mkU32( 0 ),
12624 binop( Iop_And32,
12625 binop( Iop_Shr32,
12626 unop( Iop_64HIto32, frBI64_hi ),
12627 mkU8( 4 ) ),
12628 mkU32( 0x3FF ) ) ) );
12630 /* Convert the 10 bit densely packed BCD string to a 12 bit
12631 * BCD string.
12633 assign( tmptop12, unop( Iop_DPBtoBCD, mkexpr( top_10 ) ) );
12634 assign( top_12_u, unop( Iop_64HIto32, mkexpr( tmptop12 ) ) );
12635 assign( *top_12_l, unop( Iop_64to32, mkexpr( tmptop12 ) ) );
12638 static void Count_zeros( int start, IRExpr * init_cnt, IRExpr * init_flag,
12639 IRTemp * final_cnt, IRTemp * final_flag,
12640 IRExpr * string )
12642 IRTemp cnt[MAX_DIGITS_IN_STRING + 1];IRTemp flag[MAX_DIGITS_IN_STRING+1];
12643 int digits = MAX_DIGITS_IN_STRING;
12644 int i;
12646 cnt[start-1] = newTemp( Ity_I8 );
12647 flag[start-1] = newTemp( Ity_I8 );
12648 assign( cnt[start-1], init_cnt);
12649 assign( flag[start-1], init_flag);
12651 for ( i = start; i <= digits; i++) {
12652 cnt[i] = newTemp( Ity_I8 );
12653 flag[i] = newTemp( Ity_I8 );
12654 assign( cnt[i],
12655 binop( Iop_Add8,
12656 mkexpr( cnt[i-1] ),
12657 binop(Iop_And8,
12658 unop( Iop_1Uto8,
12659 binop(Iop_CmpEQ32,
12660 binop(Iop_And32,
12661 string,
12662 mkU32( 0xF <<
12663 ( ( digits - i ) * 4) ) ),
12664 mkU32( 0 ) ) ),
12665 binop( Iop_Xor8, /* complement flag */
12666 mkexpr( flag[i - 1] ),
12667 mkU8( 0xFF ) ) ) ) );
12669 /* set flag to 1 if digit was not a zero */
12670 assign( flag[i],
12671 binop(Iop_Or8,
12672 unop( Iop_1Sto8,
12673 binop(Iop_CmpNE32,
12674 binop(Iop_And32,
12675 string,
12676 mkU32( 0xF <<
12677 ( (digits - i) * 4) ) ),
12678 mkU32( 0 ) ) ),
12679 mkexpr( flag[i - 1] ) ) );
12682 *final_cnt = cnt[digits];
12683 *final_flag = flag[digits];
12686 static IRExpr * Count_leading_zeros_60( IRExpr * lmd, IRExpr * upper_28,
12687 IRExpr * low_32 )
12689 IRTemp num_lmd = newTemp( Ity_I8 );
12690 IRTemp num_upper = newTemp( Ity_I8 );
12691 IRTemp num_low = newTemp( Ity_I8 );
12692 IRTemp lmd_flag = newTemp( Ity_I8 );
12693 IRTemp upper_flag = newTemp( Ity_I8 );
12694 IRTemp low_flag = newTemp( Ity_I8 );
12696 assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
12697 assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
12699 Count_zeros( 2,
12700 mkexpr( num_lmd ),
12701 mkexpr( lmd_flag ),
12702 &num_upper,
12703 &upper_flag,
12704 upper_28 );
12706 Count_zeros( 1,
12707 mkexpr( num_upper ),
12708 mkexpr( upper_flag ),
12709 &num_low,
12710 &low_flag,
12711 low_32 );
12713 return mkexpr( num_low );
12716 static IRExpr * Count_leading_zeros_128( IRExpr * lmd, IRExpr * top_12_l,
12717 IRExpr * mid_60_u, IRExpr * mid_60_l,
12718 IRExpr * low_60_u, IRExpr * low_60_l)
12720 IRTemp num_lmd = newTemp( Ity_I8 );
12721 IRTemp num_top = newTemp( Ity_I8 );
12722 IRTemp num_mid_u = newTemp( Ity_I8 );
12723 IRTemp num_mid_l = newTemp( Ity_I8 );
12724 IRTemp num_low_u = newTemp( Ity_I8 );
12725 IRTemp num_low_l = newTemp( Ity_I8 );
12727 IRTemp lmd_flag = newTemp( Ity_I8 );
12728 IRTemp top_flag = newTemp( Ity_I8 );
12729 IRTemp mid_u_flag = newTemp( Ity_I8 );
12730 IRTemp mid_l_flag = newTemp( Ity_I8 );
12731 IRTemp low_u_flag = newTemp( Ity_I8 );
12732 IRTemp low_l_flag = newTemp( Ity_I8 );
12734 /* Check the LMD, digit 34, to see if it is zero. */
12735 assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
12737 assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
12739 Count_zeros( 6,
12740 mkexpr( num_lmd ),
12741 mkexpr( lmd_flag ),
12742 &num_top,
12743 &top_flag,
12744 top_12_l );
12746 Count_zeros( 2,
12747 mkexpr( num_top ),
12748 mkexpr( top_flag ),
12749 &num_mid_u,
12750 &mid_u_flag,
12751 binop( Iop_Or32,
12752 binop( Iop_Shl32, mid_60_u, mkU8( 2 ) ),
12753 binop( Iop_Shr32, mid_60_l, mkU8( 30 ) ) ) );
12755 Count_zeros( 1,
12756 mkexpr( num_mid_u ),
12757 mkexpr( mid_u_flag ),
12758 &num_mid_l,
12759 &mid_l_flag,
12760 mid_60_l );
12762 Count_zeros( 2,
12763 mkexpr( num_mid_l ),
12764 mkexpr( mid_l_flag ),
12765 &num_low_u,
12766 &low_u_flag,
12767 binop( Iop_Or32,
12768 binop( Iop_Shl32, low_60_u, mkU8( 2 ) ),
12769 binop( Iop_Shr32, low_60_l, mkU8( 30 ) ) ) );
12771 Count_zeros( 1,
12772 mkexpr( num_low_u ),
12773 mkexpr( low_u_flag ),
12774 &num_low_l,
12775 &low_l_flag,
12776 low_60_l );
12778 return mkexpr( num_low_l );
12781 static IRExpr * Check_unordered(IRExpr * val)
12783 IRTemp gfield0to5 = newTemp( Ity_I32 );
12785 /* Extract G[0:4] */
12786 assign( gfield0to5,
12787 binop( Iop_And32,
12788 binop( Iop_Shr32, unop( Iop_64HIto32, val ), mkU8( 26 ) ),
12789 mkU32( 0x1F ) ) );
12791 /* Check for unordered, return all 1'x if true */
12792 return binop( Iop_Or32, /* QNaN check */
12793 unop( Iop_1Sto32,
12794 binop( Iop_CmpEQ32,
12795 mkexpr( gfield0to5 ),
12796 mkU32( 0x1E ) ) ),
12797 unop( Iop_1Sto32, /* SNaN check */
12798 binop( Iop_CmpEQ32,
12799 mkexpr( gfield0to5 ),
12800 mkU32( 0x1F ) ) ) );
12803 #undef AND
12804 #undef AND4
12805 #undef OR
12806 #undef OR3
12807 #undef OR4
12808 #undef NOT
12809 #undef SHR
12810 #undef SHL
12811 #undef BITS5
12813 /*------------------------------------------------------------*/
12814 /*--- Decimal Floating Point (DFP) instruction translation ---*/
12815 /*------------------------------------------------------------*/
12817 /* DFP Arithmetic instructions */
12818 static Bool dis_dfp_arith(UInt theInstr)
12820 UInt opc2 = ifieldOPClo10( theInstr );
12821 UChar frS_addr = ifieldRegDS( theInstr );
12822 UChar frA_addr = ifieldRegA( theInstr );
12823 UChar frB_addr = ifieldRegB( theInstr );
12824 UChar flag_rC = ifieldBIT0( theInstr );
12826 IRTemp frA = newTemp( Ity_D64 );
12827 IRTemp frB = newTemp( Ity_D64 );
12828 IRTemp frS = newTemp( Ity_D64 );
12829 IRExpr* round = get_IR_roundingmode_DFP();
12831 /* By default, if flag_RC is set, we will clear cr1 after the
12832 * operation. In reality we should set cr1 to indicate the
12833 * exception status of the operation, but since we're not
12834 * simulating exceptions, the exception status will appear to be
12835 * zero. Hence cr1 should be cleared if this is a . form insn.
12837 Bool clear_CR1 = True;
12839 assign( frA, getDReg( frA_addr ) );
12840 assign( frB, getDReg( frB_addr ) );
12842 switch (opc2) {
12843 case 0x2: // dadd
12844 DIP( "dadd%s fr%u,fr%u,fr%u\n",
12845 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
12846 assign( frS, triop( Iop_AddD64, round, mkexpr( frA ), mkexpr( frB ) ) );
12847 break;
12848 case 0x202: // dsub
12849 DIP( "dsub%s fr%u,fr%u,fr%u\n",
12850 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
12851 assign( frS, triop( Iop_SubD64, round, mkexpr( frA ), mkexpr( frB ) ) );
12852 break;
12853 case 0x22: // dmul
12854 DIP( "dmul%s fr%u,fr%u,fr%u\n",
12855 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
12856 assign( frS, triop( Iop_MulD64, round, mkexpr( frA ), mkexpr( frB ) ) );
12857 break;
12858 case 0x222: // ddiv
12859 DIP( "ddiv%s fr%u,fr%u,fr%u\n",
12860 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
12861 assign( frS, triop( Iop_DivD64, round, mkexpr( frA ), mkexpr( frB ) ) );
12862 break;
12865 putDReg( frS_addr, mkexpr( frS ) );
12867 if (flag_rC && clear_CR1) {
12868 putCR321( 1, mkU8( 0 ) );
12869 putCR0( 1, mkU8( 0 ) );
12872 return True;
12875 /* Quad DFP Arithmetic instructions */
12876 static Bool dis_dfp_arithq(UInt theInstr)
12878 UInt opc2 = ifieldOPClo10( theInstr );
12879 UChar frS_addr = ifieldRegDS( theInstr );
12880 UChar frA_addr = ifieldRegA( theInstr );
12881 UChar frB_addr = ifieldRegB( theInstr );
12882 UChar flag_rC = ifieldBIT0( theInstr );
12884 IRTemp frA = newTemp( Ity_D128 );
12885 IRTemp frB = newTemp( Ity_D128 );
12886 IRTemp frS = newTemp( Ity_D128 );
12887 IRExpr* round = get_IR_roundingmode_DFP();
12889 /* By default, if flag_RC is set, we will clear cr1 after the
12890 * operation. In reality we should set cr1 to indicate the
12891 * exception status of the operation, but since we're not
12892 * simulating exceptions, the exception status will appear to be
12893 * zero. Hence cr1 should be cleared if this is a . form insn.
12895 Bool clear_CR1 = True;
12897 assign( frA, getDReg_pair( frA_addr ) );
12898 assign( frB, getDReg_pair( frB_addr ) );
12900 switch (opc2) {
12901 case 0x2: // daddq
12902 DIP( "daddq%s fr%u,fr%u,fr%u\n",
12903 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
12904 assign( frS, triop( Iop_AddD128, round, mkexpr( frA ), mkexpr( frB ) ) );
12905 break;
12906 case 0x202: // dsubq
12907 DIP( "dsubq%s fr%u,fr%u,fr%u\n",
12908 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
12909 assign( frS, triop( Iop_SubD128, round, mkexpr( frA ), mkexpr( frB ) ) );
12910 break;
12911 case 0x22: // dmulq
12912 DIP( "dmulq%s fr%u,fr%u,fr%u\n",
12913 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
12914 assign( frS, triop( Iop_MulD128, round, mkexpr( frA ), mkexpr( frB ) ) );
12915 break;
12916 case 0x222: // ddivq
12917 DIP( "ddivq%s fr%u,fr%u,fr%u\n",
12918 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
12919 assign( frS, triop( Iop_DivD128, round, mkexpr( frA ), mkexpr( frB ) ) );
12920 break;
12923 putDReg_pair( frS_addr, mkexpr( frS ) );
12925 if (flag_rC && clear_CR1) {
12926 putCR321( 1, mkU8( 0 ) );
12927 putCR0( 1, mkU8( 0 ) );
12930 return True;
12933 /* DFP 64-bit logical shift instructions */
12934 static Bool dis_dfp_shift(UInt theInstr) {
12935 UInt opc2 = ifieldOPClo9( theInstr );
12936 UChar frS_addr = ifieldRegDS( theInstr );
12937 UChar frA_addr = ifieldRegA( theInstr );
12938 UChar shift_val = IFIELD(theInstr, 10, 6);
12939 UChar flag_rC = ifieldBIT0( theInstr );
12941 IRTemp frA = newTemp( Ity_D64 );
12942 IRTemp frS = newTemp( Ity_D64 );
12943 Bool clear_CR1 = True;
12945 assign( frA, getDReg( frA_addr ) );
12947 switch (opc2) {
12948 case 0x42: // dscli
12949 DIP( "dscli%s fr%u,fr%u,%u\n",
12950 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
12951 assign( frS, binop( Iop_ShlD64, mkexpr( frA ), mkU8( shift_val ) ) );
12952 break;
12953 case 0x62: // dscri
12954 DIP( "dscri%s fr%u,fr%u,%u\n",
12955 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
12956 assign( frS, binop( Iop_ShrD64, mkexpr( frA ), mkU8( shift_val ) ) );
12957 break;
12960 putDReg( frS_addr, mkexpr( frS ) );
12962 if (flag_rC && clear_CR1) {
12963 putCR321( 1, mkU8( 0 ) );
12964 putCR0( 1, mkU8( 0 ) );
12967 return True;
12970 /* Quad DFP logical shift instructions */
12971 static Bool dis_dfp_shiftq(UInt theInstr) {
12972 UInt opc2 = ifieldOPClo9( theInstr );
12973 UChar frS_addr = ifieldRegDS( theInstr );
12974 UChar frA_addr = ifieldRegA( theInstr );
12975 UChar shift_val = IFIELD(theInstr, 10, 6);
12976 UChar flag_rC = ifieldBIT0( theInstr );
12978 IRTemp frA = newTemp( Ity_D128 );
12979 IRTemp frS = newTemp( Ity_D128 );
12980 Bool clear_CR1 = True;
12982 assign( frA, getDReg_pair( frA_addr ) );
12984 switch (opc2) {
12985 case 0x42: // dscliq
12986 DIP( "dscliq%s fr%u,fr%u,%u\n",
12987 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
12988 assign( frS, binop( Iop_ShlD128, mkexpr( frA ), mkU8( shift_val ) ) );
12989 break;
12990 case 0x62: // dscriq
12991 DIP( "dscriq%s fr%u,fr%u,%u\n",
12992 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
12993 assign( frS, binop( Iop_ShrD128, mkexpr( frA ), mkU8( shift_val ) ) );
12994 break;
12997 putDReg_pair( frS_addr, mkexpr( frS ) );
12999 if (flag_rC && clear_CR1) {
13000 putCR321( 1, mkU8( 0 ) );
13001 putCR0( 1, mkU8( 0 ) );
13004 return True;
13007 /* DFP 64-bit format conversion instructions */
13008 static Bool dis_dfp_fmt_conv(UInt theInstr) {
13009 UInt opc2 = ifieldOPClo10( theInstr );
13010 UChar frS_addr = ifieldRegDS( theInstr );
13011 UChar frB_addr = ifieldRegB( theInstr );
13012 IRExpr* round = get_IR_roundingmode_DFP();
13013 UChar flag_rC = ifieldBIT0( theInstr );
13014 IRTemp frB;
13015 IRTemp frS;
13016 Bool clear_CR1 = True;
13018 switch (opc2) {
13019 case 0x102: //dctdp
13020 DIP( "dctdp%s fr%u,fr%u\n",
13021 flag_rC ? ".":"", frS_addr, frB_addr );
13023 frB = newTemp( Ity_D32 );
13024 frS = newTemp( Ity_D64 );
13025 assign( frB, getDReg32( frB_addr ) );
13026 assign( frS, unop( Iop_D32toD64, mkexpr( frB ) ) );
13027 putDReg( frS_addr, mkexpr( frS ) );
13028 break;
13029 case 0x302: // drsp
13030 DIP( "drsp%s fr%u,fr%u\n",
13031 flag_rC ? ".":"", frS_addr, frB_addr );
13032 frB = newTemp( Ity_D64 );
13033 frS = newTemp( Ity_D32 );
13034 assign( frB, getDReg( frB_addr ) );
13035 assign( frS, binop( Iop_D64toD32, round, mkexpr( frB ) ) );
13036 putDReg32( frS_addr, mkexpr( frS ) );
13037 break;
13038 case 0x122: // dctfix
13040 IRTemp tmp = newTemp( Ity_I64 );
13042 DIP( "dctfix%s fr%u,fr%u\n",
13043 flag_rC ? ".":"", frS_addr, frB_addr );
13044 frB = newTemp( Ity_D64 );
13045 frS = newTemp( Ity_D64 );
13046 assign( frB, getDReg( frB_addr ) );
13047 assign( tmp, binop( Iop_D64toI64S, round, mkexpr( frB ) ) );
13048 assign( frS, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
13049 putDReg( frS_addr, mkexpr( frS ) );
13051 break;
13052 case 0x322: // dcffix
13053 DIP( "dcffix%s fr%u,fr%u\n",
13054 flag_rC ? ".":"", frS_addr, frB_addr );
13055 frB = newTemp( Ity_D64 );
13056 frS = newTemp( Ity_D64 );
13057 assign( frB, getDReg( frB_addr ) );
13058 assign( frS, binop( Iop_I64StoD64,
13059 round,
13060 unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) ) );
13061 putDReg( frS_addr, mkexpr( frS ) );
13062 break;
13065 if (flag_rC && clear_CR1) {
13066 putCR321( 1, mkU8( 0 ) );
13067 putCR0( 1, mkU8( 0 ) );
13070 return True;
13073 /* Quad DFP format conversion instructions */
13074 static Bool dis_dfp_fmt_convq(UInt theInstr) {
13075 UInt opc2 = ifieldOPClo10( theInstr );
13076 UChar frS_addr = ifieldRegDS( theInstr );
13077 UChar frB_addr = ifieldRegB( theInstr );
13078 IRExpr* round = get_IR_roundingmode_DFP();
13079 IRTemp frB64 = newTemp( Ity_D64 );
13080 IRTemp frB128 = newTemp( Ity_D128 );
13081 IRTemp frS64 = newTemp( Ity_D64 );
13082 IRTemp frS128 = newTemp( Ity_D128 );
13083 UChar flag_rC = ifieldBIT0( theInstr );
13084 Bool clear_CR1 = True;
13086 switch (opc2) {
13087 case 0x102: // dctqpq
13088 DIP( "dctqpq%s fr%u,fr%u\n",
13089 flag_rC ? ".":"", frS_addr, frB_addr );
13090 assign( frB64, getDReg( frB_addr ) );
13091 assign( frS128, unop( Iop_D64toD128, mkexpr( frB64 ) ) );
13092 putDReg_pair( frS_addr, mkexpr( frS128 ) );
13093 break;
13094 case 0x122: // dctfixq
13096 IRTemp tmp = newTemp( Ity_I64 );
13098 DIP( "dctfixq%s fr%u,fr%u\n",
13099 flag_rC ? ".":"", frS_addr, frB_addr );
13100 assign( frB128, getDReg_pair( frB_addr ) );
13101 assign( tmp, binop( Iop_D128toI64S, round, mkexpr( frB128 ) ) );
13102 assign( frS64, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
13103 putDReg( frS_addr, mkexpr( frS64 ) );
13105 break;
13106 case 0x302: //drdpq
13107 DIP( "drdpq%s fr%u,fr%u\n",
13108 flag_rC ? ".":"", frS_addr, frB_addr );
13109 assign( frB128, getDReg_pair( frB_addr ) );
13110 assign( frS64, binop( Iop_D128toD64, round, mkexpr( frB128 ) ) );
13111 putDReg( frS_addr, mkexpr( frS64 ) );
13112 break;
13113 case 0x322: // dcffixq
13115 /* Have to introduce an IOP for this instruction so it will work
13116 * on POWER 6 because emulating the instruction requires a POWER 7
13117 * DFP instruction in the emulation code.
13119 DIP( "dcffixq%s fr%u,fr%u\n",
13120 flag_rC ? ".":"", frS_addr, frB_addr );
13121 assign( frB64, getDReg( frB_addr ) );
13122 assign( frS128, unop( Iop_I64StoD128,
13123 unop( Iop_ReinterpD64asI64,
13124 mkexpr( frB64 ) ) ) );
13125 putDReg_pair( frS_addr, mkexpr( frS128 ) );
13126 break;
13130 if (flag_rC && clear_CR1) {
13131 putCR321( 1, mkU8( 0 ) );
13132 putCR0( 1, mkU8( 0 ) );
13135 return True;
13138 static Bool dis_dfp_round( UInt theInstr ) {
13139 UChar frS_addr = ifieldRegDS(theInstr);
13140 UChar R = IFIELD(theInstr, 16, 1);
13141 UChar RMC = IFIELD(theInstr, 9, 2);
13142 UChar frB_addr = ifieldRegB( theInstr );
13143 UChar flag_rC = ifieldBIT0( theInstr );
13144 IRTemp frB = newTemp( Ity_D64 );
13145 IRTemp frS = newTemp( Ity_D64 );
13146 UInt opc2 = ifieldOPClo8( theInstr );
13147 Bool clear_CR1 = True;
13149 switch (opc2) {
13150 /* drintn, is the same as drintx. The only difference is this
13151 * instruction does not generate an exception for an inexact operation.
13152 * Currently not supporting inexact exceptions.
13154 case 0x63: // drintx
13155 case 0xE3: // drintn
13156 DIP( "drintx/drintn%s fr%u,fr%u\n",
13157 flag_rC ? ".":"", frS_addr, frB_addr );
13159 /* NOTE, this instruction takes a DFP value and rounds to the
13160 * neares floating point integer value, i.e. fractional part
13161 * is zero. The result is a floating point number.
13163 /* pass the value of R and RMC in the same field */
13164 assign( frB, getDReg( frB_addr ) );
13165 assign( frS, binop( Iop_RoundD64toInt,
13166 mkU32( ( R << 3 ) | RMC ),
13167 mkexpr( frB ) ) );
13168 putDReg( frS_addr, mkexpr( frS ) );
13169 break;
13170 default:
13171 vex_printf("dis_dfp_round(ppc)(opc2)\n");
13172 return False;
13175 if (flag_rC && clear_CR1) {
13176 putCR321( 1, mkU8( 0 ) );
13177 putCR0( 1, mkU8( 0 ) );
13180 return True;
13183 static Bool dis_dfp_roundq(UInt theInstr) {
13184 UChar frS_addr = ifieldRegDS( theInstr );
13185 UChar frB_addr = ifieldRegB( theInstr );
13186 UChar R = IFIELD(theInstr, 16, 1);
13187 UChar RMC = IFIELD(theInstr, 9, 2);
13188 UChar flag_rC = ifieldBIT0( theInstr );
13189 IRTemp frB = newTemp( Ity_D128 );
13190 IRTemp frS = newTemp( Ity_D128 );
13191 Bool clear_CR1 = True;
13192 UInt opc2 = ifieldOPClo8( theInstr );
13194 switch (opc2) {
13195 /* drintnq, is the same as drintxq. The only difference is this
13196 * instruction does not generate an exception for an inexact operation.
13197 * Currently not supporting inexact exceptions.
13199 case 0x63: // drintxq
13200 case 0xE3: // drintnq
13201 DIP( "drintxq/drintnq%s fr%u,fr%u\n",
13202 flag_rC ? ".":"", frS_addr, frB_addr );
13204 /* pass the value of R and RMC in the same field */
13205 assign( frB, getDReg_pair( frB_addr ) );
13206 assign( frS, binop( Iop_RoundD128toInt,
13207 mkU32( ( R << 3 ) | RMC ),
13208 mkexpr( frB ) ) );
13209 putDReg_pair( frS_addr, mkexpr( frS ) );
13210 break;
13211 default:
13212 vex_printf("dis_dfp_roundq(ppc)(opc2)\n");
13213 return False;
13216 if (flag_rC && clear_CR1) {
13217 putCR321( 1, mkU8( 0 ) );
13218 putCR0( 1, mkU8( 0 ) );
13221 return True;
13224 static Bool dis_dfp_quantize_sig_rrnd(UInt theInstr) {
13225 UInt opc2 = ifieldOPClo8( theInstr );
13226 UChar frS_addr = ifieldRegDS( theInstr );
13227 UChar frA_addr = ifieldRegA( theInstr );
13228 UChar frB_addr = ifieldRegB( theInstr );
13229 UChar flag_rC = ifieldBIT0( theInstr );
13230 UInt TE_value = IFIELD(theInstr, 16, 4);
13231 UInt TE_sign = IFIELD(theInstr, 20, 1);
13232 UInt RMC = IFIELD(theInstr, 9, 2);
13233 IRTemp frA = newTemp( Ity_D64 );
13234 IRTemp frB = newTemp( Ity_D64 );
13235 IRTemp frS = newTemp( Ity_D64 );
13236 Bool clear_CR1 = True;
13238 assign( frB, getDReg( frB_addr ) );
13240 switch (opc2) {
13241 case 0x43: // dquai
13242 DIP( "dquai%s fr%u,fr%u,fr%u\n",
13243 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13244 IRTemp TE_I64 = newTemp( Ity_I64 );
13246 /* Generate a reference DFP value frA with the desired exponent
13247 * given by TE using significand from frB. Need to add the bias
13248 * 398 to TE. TE is stored as a 2's complement number.
13250 if (TE_sign == 1) {
13251 /* Take 2's complement of the 5-bit value and subtract from bias.
13252 * Bias is adjusted for the +1 required when taking 2's complement.
13254 assign( TE_I64,
13255 unop( Iop_32Uto64,
13256 binop( Iop_Sub32, mkU32( 397 ),
13257 binop( Iop_And32, mkU32( 0xF ),
13258 unop( Iop_Not32, mkU32( TE_value ) )
13259 ) ) ) );
13261 } else {
13262 assign( TE_I64,
13263 unop( Iop_32Uto64,
13264 binop( Iop_Add32, mkU32( 398 ), mkU32( TE_value ) )
13265 ) );
13268 assign( frA, binop( Iop_InsertExpD64, mkexpr( TE_I64 ),
13269 unop( Iop_ReinterpI64asD64, mkU64( 1 ) ) ) );
13271 assign( frS, triop( Iop_QuantizeD64,
13272 mkU32( RMC ),
13273 mkexpr( frA ),
13274 mkexpr( frB ) ) );
13275 break;
13277 case 0x3: // dqua
13278 DIP( "dqua%s fr%u,fr%u,fr%u\n",
13279 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13280 assign( frA, getDReg( frA_addr ) );
13281 assign( frS, triop( Iop_QuantizeD64,
13282 mkU32( RMC ),
13283 mkexpr( frA ),
13284 mkexpr( frB ) ) );
13285 break;
13286 case 0x23: // drrnd
13288 IRTemp tmp = newTemp( Ity_I8 );
13290 DIP( "drrnd%s fr%u,fr%u,fr%u\n",
13291 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13292 assign( frA, getDReg( frA_addr ) );
13293 /* Iop_64to8 not supported in 32 bit mode, do it in two steps. */
13294 assign( tmp, unop( Iop_32to8,
13295 unop( Iop_64to32,
13296 unop( Iop_ReinterpD64asI64,
13297 mkexpr( frA ) ) ) ) );
13298 assign( frS, triop( Iop_SignificanceRoundD64,
13299 mkU32( RMC ),
13300 mkexpr( tmp ),
13301 mkexpr( frB ) ) );
13303 break;
13304 default:
13305 vex_printf("dis_dfp_quantize_sig_rrnd(ppc)(opc2)\n");
13306 return False;
13308 putDReg( frS_addr, mkexpr( frS ) );
13310 if (flag_rC && clear_CR1) {
13311 putCR321( 1, mkU8( 0 ) );
13312 putCR0( 1, mkU8( 0 ) );
13315 return True;
13318 static Bool dis_dfp_quantize_sig_rrndq(UInt theInstr) {
13319 UInt opc2 = ifieldOPClo8( theInstr );
13320 UChar frS_addr = ifieldRegDS( theInstr );
13321 UChar frA_addr = ifieldRegA( theInstr );
13322 UChar frB_addr = ifieldRegB( theInstr );
13323 UChar flag_rC = ifieldBIT0( theInstr );
13324 UInt TE_value = IFIELD(theInstr, 16, 4);
13325 UInt TE_sign = IFIELD(theInstr, 20, 1);
13326 UInt RMC = IFIELD(theInstr, 9, 2);
13327 IRTemp frA = newTemp( Ity_D128 );
13328 IRTemp frB = newTemp( Ity_D128 );
13329 IRTemp frS = newTemp( Ity_D128 );
13330 Bool clear_CR1 = True;
13332 assign( frB, getDReg_pair( frB_addr ) );
13334 switch (opc2) {
13335 case 0x43: // dquaiq
13336 DIP( "dquaiq%s fr%u,fr%u,fr%u\n",
13337 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13338 IRTemp TE_I64 = newTemp( Ity_I64 );
13340 /* Generate a reference DFP value frA with the desired exponent
13341 * given by TE using significand of 1. Need to add the bias
13342 * 6176 to TE.
13344 if (TE_sign == 1) {
13345 /* Take 2's complement of the 5-bit value and subtract from bias.
13346 * Bias adjusted for the +1 required when taking 2's complement.
13348 assign( TE_I64,
13349 unop( Iop_32Uto64,
13350 binop( Iop_Sub32, mkU32( 6175 ),
13351 binop( Iop_And32, mkU32( 0xF ),
13352 unop( Iop_Not32, mkU32( TE_value ) )
13353 ) ) ) );
13355 } else {
13356 assign( TE_I64,
13357 unop( Iop_32Uto64,
13358 binop( Iop_Add32,
13359 mkU32( 6176 ),
13360 mkU32( TE_value ) ) ) );
13363 assign( frA,
13364 binop( Iop_InsertExpD128, mkexpr( TE_I64 ),
13365 unop( Iop_D64toD128,
13366 unop( Iop_ReinterpI64asD64, mkU64( 1 ) ) ) ) );
13367 assign( frS, triop( Iop_QuantizeD128,
13368 mkU32( RMC ),
13369 mkexpr( frA ),
13370 mkexpr( frB ) ) );
13371 break;
13372 case 0x3: // dquaq
13373 DIP( "dquaiq%s fr%u,fr%u,fr%u\n",
13374 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13375 assign( frA, getDReg_pair( frA_addr ) );
13376 assign( frS, triop( Iop_QuantizeD128,
13377 mkU32( RMC ),
13378 mkexpr( frA ),
13379 mkexpr( frB ) ) );
13380 break;
13381 case 0x23: // drrndq
13383 IRTemp tmp = newTemp( Ity_I8 );
13385 DIP( "drrndq%s fr%u,fr%u,fr%u\n",
13386 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13387 assign( frA, getDReg_pair( frA_addr ) );
13388 assign( tmp, unop( Iop_32to8,
13389 unop( Iop_64to32,
13390 unop( Iop_ReinterpD64asI64,
13391 unop( Iop_D128HItoD64,
13392 mkexpr( frA ) ) ) ) ) );
13393 assign( frS, triop( Iop_SignificanceRoundD128,
13394 mkU32( RMC ),
13395 mkexpr( tmp ),
13396 mkexpr( frB ) ) );
13398 break;
13399 default:
13400 vex_printf("dis_dfp_quantize_sig_rrndq(ppc)(opc2)\n");
13401 return False;
13403 putDReg_pair( frS_addr, mkexpr( frS ) );
13405 if (flag_rC && clear_CR1) {
13406 putCR321( 1, mkU8( 0 ) );
13407 putCR0( 1, mkU8( 0 ) );
13410 return True;
13413 static Bool dis_dfp_extract_insert(UInt theInstr) {
13414 UInt opc2 = ifieldOPClo10( theInstr );
13415 UChar frS_addr = ifieldRegDS( theInstr );
13416 UChar frA_addr = ifieldRegA( theInstr );
13417 UChar frB_addr = ifieldRegB( theInstr );
13418 UChar flag_rC = ifieldBIT0( theInstr );
13419 Bool clear_CR1 = True;
13421 IRTemp frA = newTemp( Ity_D64 );
13422 IRTemp frB = newTemp( Ity_D64 );
13423 IRTemp frS = newTemp( Ity_D64 );
13424 IRTemp tmp = newTemp( Ity_I64 );
13426 assign( frA, getDReg( frA_addr ) );
13427 assign( frB, getDReg( frB_addr ) );
13429 switch (opc2) {
13430 case 0x162: // dxex
13431 DIP( "dxex%s fr%u,fr%u,fr%u\n",
13432 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13433 assign( tmp, unop( Iop_ExtractExpD64, mkexpr( frB ) ) );
13434 assign( frS, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
13435 break;
13436 case 0x362: // diex
13437 DIP( "diex%s fr%u,fr%u,fr%u\n",
13438 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13439 assign( frS, binop( Iop_InsertExpD64,
13440 unop( Iop_ReinterpD64asI64,
13441 mkexpr( frA ) ),
13442 mkexpr( frB ) ) );
13443 break;
13444 default:
13445 vex_printf("dis_dfp_extract_insert(ppc)(opc2)\n");
13446 return False;
13449 putDReg( frS_addr, mkexpr( frS ) );
13451 if (flag_rC && clear_CR1) {
13452 putCR321( 1, mkU8( 0 ) );
13453 putCR0( 1, mkU8( 0 ) );
13456 return True;
13459 static Bool dis_dfp_extract_insertq(UInt theInstr) {
13460 UInt opc2 = ifieldOPClo10( theInstr );
13461 UChar frS_addr = ifieldRegDS( theInstr );
13462 UChar frA_addr = ifieldRegA( theInstr );
13463 UChar frB_addr = ifieldRegB( theInstr );
13464 UChar flag_rC = ifieldBIT0( theInstr );
13466 IRTemp frA = newTemp( Ity_D64 );
13467 IRTemp frB = newTemp( Ity_D128 );
13468 IRTemp frS64 = newTemp( Ity_D64 );
13469 IRTemp frS = newTemp( Ity_D128 );
13470 IRTemp tmp = newTemp( Ity_I64 );
13471 Bool clear_CR1 = True;
13473 assign( frB, getDReg_pair( frB_addr ) );
13475 switch (opc2) {
13476 case 0x162: // dxexq
13477 DIP( "dxexq%s fr%u,fr%u\n",
13478 flag_rC ? ".":"", frS_addr, frB_addr );
13479 /* Instruction actually returns a 64-bit result. So as to be
13480 * consistent and not have to add a new struct, the emulation returns
13481 * the 64-bit result in the upper and lower register.
13483 assign( tmp, unop( Iop_ExtractExpD128, mkexpr( frB ) ) );
13484 assign( frS64, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
13485 putDReg( frS_addr, mkexpr( frS64 ) );
13486 break;
13487 case 0x362: // diexq
13488 DIP( "diexq%s fr%u,fr%u,fr%u\n",
13489 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
13490 assign( frA, getDReg( frA_addr ) );
13491 assign( frS, binop( Iop_InsertExpD128,
13492 unop( Iop_ReinterpD64asI64, mkexpr( frA ) ),
13493 mkexpr( frB ) ) );
13494 putDReg_pair( frS_addr, mkexpr( frS ) );
13495 break;
13496 default:
13497 vex_printf("dis_dfp_extract_insertq(ppc)(opc2)\n");
13498 return False;
13501 if (flag_rC && clear_CR1) {
13502 putCR321( 1, mkU8( 0 ) );
13503 putCR0( 1, mkU8( 0 ) );
13506 return True;
13509 /* DFP 64-bit comparison instructions */
13510 static Bool dis_dfp_compare(UInt theInstr) {
13511 /* X-Form */
13512 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
13513 UChar frA_addr = ifieldRegA( theInstr );
13514 UChar frB_addr = ifieldRegB( theInstr );
13515 UInt opc1 = ifieldOPC( theInstr );
13516 IRTemp frA;
13517 IRTemp frB;
13519 IRTemp ccIR = newTemp( Ity_I32 );
13520 IRTemp ccPPC32 = newTemp( Ity_I32 );
13523 /* Note: Differences between dcmpu and dcmpo are only in exception
13524 flag settings, which aren't supported anyway. */
13525 switch (opc1) {
13526 case 0x3B: /* dcmpo and dcmpu, DFP 64-bit */
13527 DIP( "dcmpo %u,fr%u,fr%u\n", crfD, frA_addr, frB_addr );
13528 frA = newTemp( Ity_D64 );
13529 frB = newTemp( Ity_D64 );
13531 assign( frA, getDReg( frA_addr ) );
13532 assign( frB, getDReg( frB_addr ) );
13534 assign( ccIR, binop( Iop_CmpD64, mkexpr( frA ), mkexpr( frB ) ) );
13535 break;
13536 case 0x3F: /* dcmpoq and dcmpuq,DFP 128-bit */
13537 DIP( "dcmpoq %u,fr%u,fr%u\n", crfD, frA_addr, frB_addr );
13538 frA = newTemp( Ity_D128 );
13539 frB = newTemp( Ity_D128 );
13541 assign( frA, getDReg_pair( frA_addr ) );
13542 assign( frB, getDReg_pair( frB_addr ) );
13543 assign( ccIR, binop( Iop_CmpD128, mkexpr( frA ), mkexpr( frB ) ) );
13544 break;
13545 default:
13546 vex_printf("dis_dfp_compare(ppc)(opc2)\n");
13547 return False;
13550 /* Map compare result from IR to PPC32 */
13552 FP cmp result | PPC | IR
13553 --------------------------
13554 UN | 0x1 | 0x45
13555 EQ | 0x2 | 0x40
13556 GT | 0x4 | 0x00
13557 LT | 0x8 | 0x01
13560 assign( ccPPC32,
13561 binop( Iop_Shl32,
13562 mkU32( 1 ),
13563 unop( Iop_32to8,
13564 binop( Iop_Or32,
13565 binop( Iop_And32,
13566 unop( Iop_Not32,
13567 binop( Iop_Shr32,
13568 mkexpr( ccIR ),
13569 mkU8( 5 ) ) ),
13570 mkU32( 2 ) ),
13571 binop( Iop_And32,
13572 binop( Iop_Xor32,
13573 mkexpr( ccIR ),
13574 binop( Iop_Shr32,
13575 mkexpr( ccIR ),
13576 mkU8( 6 ) ) ),
13577 mkU32( 1 ) ) ) ) ) );
13579 putGST_field( PPC_GST_CR, mkexpr( ccPPC32 ), crfD );
13580 putFPCC( mkexpr( ccPPC32 ) );
13581 return True;
13584 /* Test class/group/exponent/significance instructions. */
13585 static Bool dis_dfp_exponent_test ( UInt theInstr )
13587 UChar frA_addr = ifieldRegA( theInstr );
13588 UChar frB_addr = ifieldRegB( theInstr );
13589 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
13590 IRTemp frA = newTemp( Ity_D64 );
13591 IRTemp frB = newTemp( Ity_D64 );
13592 IRTemp frA128 = newTemp( Ity_D128 );
13593 IRTemp frB128 = newTemp( Ity_D128 );
13594 UInt opc1 = ifieldOPC( theInstr );
13595 IRTemp gfield_A = newTemp( Ity_I32 );
13596 IRTemp gfield_B = newTemp( Ity_I32 );
13597 IRTemp gfield_mask = newTemp( Ity_I32 );
13598 IRTemp exponent_A = newTemp( Ity_I32 );
13599 IRTemp exponent_B = newTemp( Ity_I32 );
13600 IRTemp A_NaN_true = newTemp( Ity_I32 );
13601 IRTemp B_NaN_true = newTemp( Ity_I32 );
13602 IRTemp A_inf_true = newTemp( Ity_I32 );
13603 IRTemp B_inf_true = newTemp( Ity_I32 );
13604 IRTemp A_equals_B = newTemp( Ity_I32 );
13605 IRTemp finite_number = newTemp( Ity_I32 );
13606 IRTemp cc0 = newTemp( Ity_I32 );
13607 IRTemp cc1 = newTemp( Ity_I32 );
13608 IRTemp cc2 = newTemp( Ity_I32 );
13609 IRTemp cc3 = newTemp( Ity_I32 );
13610 IRTemp cc = newTemp( Ity_I32 );
13612 /* The dtstex and dtstexg instructions only differ in the size of the
13613 * exponent field. The following switch statement takes care of the size
13614 * specific setup. Once the value of the exponents, the G-field shift
13615 * and mask is setup the remaining code is identical.
13617 switch (opc1) {
13618 case 0x3b: // dtstex Extended instruction setup
13619 DIP("dtstex %u,r%u,r%d\n", crfD, frA_addr, frB_addr);
13620 assign( frA, getDReg( frA_addr ) );
13621 assign( frB, getDReg( frB_addr ) );
13622 assign( gfield_mask, mkU32( DFP_G_FIELD_LONG_MASK ) );
13623 assign(exponent_A, unop( Iop_64to32,
13624 unop( Iop_ExtractExpD64,
13625 mkexpr( frA ) ) ) );
13626 assign(exponent_B, unop( Iop_64to32,
13627 unop( Iop_ExtractExpD64,
13628 mkexpr( frB ) ) ) );
13629 break;
13631 case 0x3F: // dtstexq Quad instruction setup
13632 DIP("dtstexq %u,r%u,r%d\n", crfD, frA_addr, frB_addr);
13633 assign( frA128, getDReg_pair( frA_addr ) );
13634 assign( frB128, getDReg_pair( frB_addr ) );
13635 assign( frA, unop( Iop_D128HItoD64, mkexpr( frA128 ) ) );
13636 assign( frB, unop( Iop_D128HItoD64, mkexpr( frB128 ) ) );
13637 assign( gfield_mask, mkU32( DFP_G_FIELD_EXTND_MASK ) );
13638 assign( exponent_A, unop( Iop_64to32,
13639 unop( Iop_ExtractExpD128,
13640 mkexpr( frA128 ) ) ) );
13641 assign( exponent_B, unop( Iop_64to32,
13642 unop( Iop_ExtractExpD128,
13643 mkexpr( frB128 ) ) ) );
13644 break;
13645 default:
13646 vex_printf("dis_dfp_exponent_test(ppc)(opc2)\n");
13647 return False;
13650 /* Extract the Gfield */
13651 assign( gfield_A, binop( Iop_And32,
13652 mkexpr( gfield_mask ),
13653 unop( Iop_64HIto32,
13654 unop( Iop_ReinterpD64asI64,
13655 mkexpr(frA) ) ) ) );
13657 assign( gfield_B, binop( Iop_And32,
13658 mkexpr( gfield_mask ),
13659 unop( Iop_64HIto32,
13660 unop( Iop_ReinterpD64asI64,
13661 mkexpr(frB) ) ) ) );
13663 /* check for NAN */
13664 assign( A_NaN_true, binop(Iop_Or32,
13665 unop( Iop_1Sto32,
13666 binop( Iop_CmpEQ32,
13667 mkexpr( gfield_A ),
13668 mkU32( 0x7C000000 ) ) ),
13669 unop( Iop_1Sto32,
13670 binop( Iop_CmpEQ32,
13671 mkexpr( gfield_A ),
13672 mkU32( 0x7E000000 ) )
13673 ) ) );
13674 assign( B_NaN_true, binop(Iop_Or32,
13675 unop( Iop_1Sto32,
13676 binop( Iop_CmpEQ32,
13677 mkexpr( gfield_B ),
13678 mkU32( 0x7C000000 ) ) ),
13679 unop( Iop_1Sto32,
13680 binop( Iop_CmpEQ32,
13681 mkexpr( gfield_B ),
13682 mkU32( 0x7E000000 ) )
13683 ) ) );
13685 /* check for infinity */
13686 assign( A_inf_true,
13687 unop( Iop_1Sto32,
13688 binop( Iop_CmpEQ32,
13689 mkexpr( gfield_A ),
13690 mkU32( 0x78000000 ) ) ) );
13692 assign( B_inf_true,
13693 unop( Iop_1Sto32,
13694 binop( Iop_CmpEQ32,
13695 mkexpr( gfield_B ),
13696 mkU32( 0x78000000 ) ) ) );
13698 assign( finite_number,
13699 unop( Iop_Not32,
13700 binop( Iop_Or32,
13701 binop( Iop_Or32,
13702 mkexpr( A_NaN_true ),
13703 mkexpr( B_NaN_true ) ),
13704 binop( Iop_Or32,
13705 mkexpr( A_inf_true ),
13706 mkexpr( B_inf_true ) ) ) ) );
13708 /* Calculate the condition code bits
13709 * If QNaN,SNaN, +infinity, -infinity then cc0, cc1 and cc2 are zero
13710 * regardless of the value of the comparisons and cc3 is 1. Otherwise,
13711 * cc0, cc1 and cc0 reflect the results of the comparisons.
13713 assign( A_equals_B,
13714 binop( Iop_Or32,
13715 unop( Iop_1Uto32,
13716 binop( Iop_CmpEQ32,
13717 mkexpr( exponent_A ),
13718 mkexpr( exponent_B ) ) ),
13719 binop( Iop_Or32,
13720 binop( Iop_And32,
13721 mkexpr( A_inf_true ),
13722 mkexpr( B_inf_true ) ),
13723 binop( Iop_And32,
13724 mkexpr( A_NaN_true ),
13725 mkexpr( B_NaN_true ) ) ) ) );
13727 assign( cc0, binop( Iop_And32,
13728 mkexpr( finite_number ),
13729 binop( Iop_Shl32,
13730 unop( Iop_1Uto32,
13731 binop( Iop_CmpLT32U,
13732 mkexpr( exponent_A ),
13733 mkexpr( exponent_B ) ) ),
13734 mkU8( 3 ) ) ) );
13736 assign( cc1, binop( Iop_And32,
13737 mkexpr( finite_number ),
13738 binop( Iop_Shl32,
13739 unop( Iop_1Uto32,
13740 binop( Iop_CmpLT32U,
13741 mkexpr( exponent_B ),
13742 mkexpr( exponent_A ) ) ),
13743 mkU8( 2 ) ) ) );
13745 assign( cc2, binop( Iop_Shl32,
13746 binop( Iop_And32,
13747 mkexpr( A_equals_B ),
13748 mkU32( 1 ) ),
13749 mkU8( 1 ) ) );
13751 assign( cc3, binop( Iop_And32,
13752 unop( Iop_Not32, mkexpr( A_equals_B ) ),
13753 binop( Iop_And32,
13754 mkU32( 0x1 ),
13755 binop( Iop_Or32,
13756 binop( Iop_Or32,
13757 mkexpr ( A_inf_true ),
13758 mkexpr ( B_inf_true ) ),
13759 binop( Iop_Or32,
13760 mkexpr ( A_NaN_true ),
13761 mkexpr ( B_NaN_true ) ) )
13762 ) ) );
13764 /* store the condition code */
13765 assign( cc, binop( Iop_Or32,
13766 mkexpr( cc0 ),
13767 binop( Iop_Or32,
13768 mkexpr( cc1 ),
13769 binop( Iop_Or32,
13770 mkexpr( cc2 ),
13771 mkexpr( cc3 ) ) ) ) );
13772 putGST_field( PPC_GST_CR, mkexpr( cc ), crfD );
13773 putFPCC( mkexpr( cc ) );
13774 return True;
13777 /* Test class/group/exponent/significance instructions. */
13778 static Bool dis_dfp_class_test ( UInt theInstr )
13780 UChar frA_addr = ifieldRegA( theInstr );
13781 IRTemp frA = newTemp( Ity_D64 );
13782 IRTemp abs_frA = newTemp( Ity_D64 );
13783 IRTemp frAI64_hi = newTemp( Ity_I64 );
13784 IRTemp frAI64_lo = newTemp( Ity_I64 );
13785 UInt opc1 = ifieldOPC( theInstr );
13786 UInt opc2 = ifieldOPClo9( theInstr );
13787 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
13788 UInt DCM = IFIELD( theInstr, 10, 6 );
13789 IRTemp DCM_calc = newTemp( Ity_I32 );
13790 UInt max_exp = 0;
13791 UInt min_exp = 0;
13792 IRTemp min_subnormalD64 = newTemp( Ity_D64 );
13793 IRTemp min_subnormalD128 = newTemp( Ity_D128 );
13794 IRTemp significand64 = newTemp( Ity_D64 );
13795 IRTemp significand128 = newTemp( Ity_D128 );
13796 IRTemp exp_min_normal = newTemp( Ity_I64 );
13797 IRTemp exponent = newTemp( Ity_I32 );
13799 IRTemp infinity_true = newTemp( Ity_I32 );
13800 IRTemp SNaN_true = newTemp( Ity_I32 );
13801 IRTemp QNaN_true = newTemp( Ity_I32 );
13802 IRTemp subnormal_true = newTemp( Ity_I32 );
13803 IRTemp normal_true = newTemp( Ity_I32 );
13804 IRTemp extreme_true = newTemp( Ity_I32 );
13805 IRTemp lmd = newTemp( Ity_I32 );
13806 IRTemp lmd_zero_true = newTemp( Ity_I32 );
13807 IRTemp zero_true = newTemp( Ity_I32 );
13808 IRTemp sign = newTemp( Ity_I32 );
13809 IRTemp field = newTemp( Ity_I32 );
13810 IRTemp ccIR_zero = newTemp( Ity_I32 );
13811 IRTemp ccIR_subnormal = newTemp( Ity_I32 );
13813 /* UInt size = DFP_LONG; JRS:unused */
13814 IRTemp gfield = newTemp( Ity_I32 );
13815 IRTemp gfield_0_4_shift = newTemp( Ity_I8 );
13816 IRTemp gfield_mask = newTemp( Ity_I32 );
13817 IRTemp dcm0 = newTemp( Ity_I32 );
13818 IRTemp dcm1 = newTemp( Ity_I32 );
13819 IRTemp dcm2 = newTemp( Ity_I32 );
13820 IRTemp dcm3 = newTemp( Ity_I32 );
13821 IRTemp dcm4 = newTemp( Ity_I32 );
13822 IRTemp dcm5 = newTemp( Ity_I32 );
13824 /* The only difference between the dtstdc and dtstdcq instructions is
13825 * size of the T and G fields. The calculation of the 4 bit field
13826 * is the same. Setup the parameters and values that are DFP size
13827 * specific. The rest of the code is independent of the DFP size.
13829 * The Io_CmpD64 is used below. The instruction sets the ccIR values.
13830 * The interpretation of the ccIR values is as follows:
13832 * DFP cmp result | IR
13833 * --------------------------
13834 * UN | 0x45
13835 * EQ | 0x40
13836 * GT | 0x00
13837 * LT | 0x01
13840 assign( frA, getDReg( frA_addr ) );
13841 assign( frAI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frA ) ) );
13843 assign( abs_frA, unop( Iop_ReinterpI64asD64,
13844 binop( Iop_And64,
13845 unop( Iop_ReinterpD64asI64,
13846 mkexpr( frA ) ),
13847 mkU64( 0x7FFFFFFFFFFFFFFFULL ) ) ) );
13848 assign( gfield_0_4_shift, mkU8( 31 - 5 ) ); // G-field[0:4]
13849 switch (opc1) {
13850 case 0x3b: // dtstdc, dtstdg
13851 DIP("dtstd%s %u,r%u,%u\n", opc2 == 0xc2 ? "c" : "g",
13852 crfD, frA_addr, DCM);
13853 /* setup the parameters for the long format of the two instructions */
13854 assign( frAI64_lo, mkU64( 0 ) );
13855 assign( gfield_mask, mkU32( DFP_G_FIELD_LONG_MASK ) );
13856 max_exp = DFP_LONG_EXP_MAX;
13857 min_exp = DFP_LONG_EXP_MIN;
13859 assign( exponent, unop( Iop_64to32,
13860 unop( Iop_ExtractExpD64,
13861 mkexpr( frA ) ) ) );
13862 assign( significand64,
13863 unop( Iop_ReinterpI64asD64,
13864 mkU64( 0x2234000000000001ULL ) ) ); // dfp 1.0
13865 assign( exp_min_normal,mkU64( 398 - 383 ) );
13866 assign( min_subnormalD64,
13867 binop( Iop_InsertExpD64,
13868 mkexpr( exp_min_normal ),
13869 mkexpr( significand64 ) ) );
13871 assign( ccIR_subnormal,
13872 binop( Iop_CmpD64,
13873 mkexpr( abs_frA ),
13874 mkexpr( min_subnormalD64 ) ) );
13876 /* compare absolute value of frA with zero */
13877 assign( ccIR_zero,
13878 binop( Iop_CmpD64,
13879 mkexpr( abs_frA ),
13880 unop( Iop_ReinterpI64asD64,
13881 mkU64( 0x2238000000000000ULL ) ) ) );
13883 /* size = DFP_LONG; JRS: unused */
13884 break;
13886 case 0x3F: // dtstdcq, dtstdgq
13887 DIP("dtstd%sq %u,r%u,%u\n", opc2 == 0xc2 ? "c" : "g",
13888 crfD, frA_addr, DCM);
13889 /* setup the parameters for the extended format of the
13890 * two instructions
13892 assign( frAI64_lo, unop( Iop_ReinterpD64asI64,
13893 getDReg( frA_addr+1 ) ) );
13895 assign( gfield_mask, mkU32( DFP_G_FIELD_EXTND_MASK ) );
13896 max_exp = DFP_EXTND_EXP_MAX;
13897 min_exp = DFP_EXTND_EXP_MIN;
13898 assign( exponent, unop( Iop_64to32,
13899 unop( Iop_ExtractExpD128,
13900 getDReg_pair( frA_addr) ) ) );
13902 /* create quand exponent for minimum normal number */
13903 assign( exp_min_normal, mkU64( 6176 - 6143 ) );
13904 assign( significand128,
13905 unop( Iop_D64toD128,
13906 unop( Iop_ReinterpI64asD64,
13907 mkU64( 0x2234000000000001ULL ) ) ) ); // dfp 1.0
13909 assign( min_subnormalD128,
13910 binop( Iop_InsertExpD128,
13911 mkexpr( exp_min_normal ),
13912 mkexpr( significand128 ) ) );
13914 assign( ccIR_subnormal,
13915 binop( Iop_CmpD128,
13916 binop( Iop_D64HLtoD128,
13917 unop( Iop_ReinterpI64asD64,
13918 binop( Iop_And64,
13919 unop( Iop_ReinterpD64asI64,
13920 mkexpr( frA ) ),
13921 mkU64( 0x7FFFFFFFFFFFFFFFULL ) ) ),
13922 getDReg( frA_addr+1 ) ),
13923 mkexpr( min_subnormalD128 ) ) );
13924 assign( ccIR_zero,
13925 binop( Iop_CmpD128,
13926 binop( Iop_D64HLtoD128,
13927 mkexpr( abs_frA ),
13928 getDReg( frA_addr+1 ) ),
13929 unop( Iop_D64toD128,
13930 unop( Iop_ReinterpI64asD64,
13931 mkU64( 0x0ULL ) ) ) ) );
13933 /* size = DFP_EXTND; JRS:unused */
13934 break;
13935 default:
13936 vex_printf("dis_dfp_class_test(ppc)(opc2)\n");
13937 return False;
13940 /* The G-field is in the upper 32-bits. The I64 logical operations
13941 * do not seem to be supported in 32-bit mode so keep things as 32-bit
13942 * operations.
13944 assign( gfield, binop( Iop_And32,
13945 mkexpr( gfield_mask ),
13946 unop( Iop_64HIto32,
13947 mkexpr(frAI64_hi) ) ) );
13949 /* There is a lot of code that is the same to do the class and group
13950 * instructions. Later there is an if statement to handle the specific
13951 * instruction.
13953 * Will be using I32 values, compares, shifts and logical operations for
13954 * this code as the 64-bit compare, shifts, logical operations are not
13955 * supported in 32-bit mode.
13958 /* Check the bits for Infinity, QNaN or Signaling NaN */
13959 assign( infinity_true,
13960 unop( Iop_1Sto32,
13961 binop( Iop_CmpEQ32,
13962 binop( Iop_And32,
13963 mkU32( 0x7C000000 ),
13964 mkexpr( gfield ) ),
13965 mkU32( 0x78000000 ) ) ) );
13967 assign( SNaN_true,
13968 unop( Iop_1Sto32,
13969 binop( Iop_CmpEQ32,
13970 binop( Iop_And32,
13971 mkU32( 0x7E000000 ),
13972 mkexpr( gfield ) ),
13973 mkU32( 0x7E000000 ) ) ) );
13975 assign( QNaN_true,
13976 binop( Iop_And32,
13977 unop( Iop_1Sto32,
13978 binop( Iop_CmpEQ32,
13979 binop( Iop_And32,
13980 mkU32( 0x7E000000 ),
13981 mkexpr( gfield ) ),
13982 mkU32( 0x7C000000 ) ) ),
13983 unop( Iop_Not32,
13984 mkexpr( SNaN_true ) ) ) );
13986 assign( zero_true,
13987 binop( Iop_And32,
13988 unop(Iop_1Sto32,
13989 binop( Iop_CmpEQ32,
13990 mkexpr( ccIR_zero ),
13991 mkU32( 0x40 ) ) ), // ccIR code for Equal
13992 unop( Iop_Not32,
13993 binop( Iop_Or32,
13994 mkexpr( infinity_true ),
13995 binop( Iop_Or32,
13996 mkexpr( QNaN_true ),
13997 mkexpr( SNaN_true ) ) ) ) ) );
13999 /* Do compare of frA the minimum normal value. Comparison is size
14000 * depenent and was done above to get the ccIR value.
14002 assign( subnormal_true,
14003 binop( Iop_And32,
14004 binop( Iop_Or32,
14005 unop( Iop_1Sto32,
14006 binop( Iop_CmpEQ32,
14007 mkexpr( ccIR_subnormal ),
14008 mkU32( 0x40 ) ) ), // ccIR code for Equal
14009 unop( Iop_1Sto32,
14010 binop( Iop_CmpEQ32,
14011 mkexpr( ccIR_subnormal ),
14012 mkU32( 0x1 ) ) ) ), // ccIR code for LT
14013 unop( Iop_Not32,
14014 binop( Iop_Or32,
14015 binop( Iop_Or32,
14016 mkexpr( infinity_true ),
14017 mkexpr( zero_true) ),
14018 binop( Iop_Or32,
14019 mkexpr( QNaN_true ),
14020 mkexpr( SNaN_true ) ) ) ) ) );
14022 /* Normal number is not subnormal, infinity, NaN or Zero */
14023 assign( normal_true,
14024 unop( Iop_Not32,
14025 binop( Iop_Or32,
14026 binop( Iop_Or32,
14027 mkexpr( infinity_true ),
14028 mkexpr( zero_true ) ),
14029 binop( Iop_Or32,
14030 mkexpr( subnormal_true ),
14031 binop( Iop_Or32,
14032 mkexpr( QNaN_true ),
14033 mkexpr( SNaN_true ) ) ) ) ) );
14035 /* Calculate the DCM bit field based on the tests for the specific
14036 * instruction
14038 if (opc2 == 0xC2) { // dtstdc, dtstdcq
14039 /* DCM[0:5] Bit Data Class definition
14040 * 0 Zero
14041 * 1 Subnormal
14042 * 2 Normal
14043 * 3 Infinity
14044 * 4 Quiet NaN
14045 * 5 Signaling NaN
14048 assign( dcm0, binop( Iop_Shl32,
14049 mkexpr( zero_true ),
14050 mkU8( 5 ) ) );
14051 assign( dcm1, binop( Iop_Shl32,
14052 binop( Iop_And32,
14053 mkexpr( subnormal_true ),
14054 mkU32( 1 ) ),
14055 mkU8( 4 ) ) );
14056 assign( dcm2, binop( Iop_Shl32,
14057 binop( Iop_And32,
14058 mkexpr( normal_true ),
14059 mkU32( 1 ) ),
14060 mkU8( 3 ) ) );
14061 assign( dcm3, binop( Iop_Shl32,
14062 binop( Iop_And32,
14063 mkexpr( infinity_true),
14064 mkU32( 1 ) ),
14065 mkU8( 2 ) ) );
14066 assign( dcm4, binop( Iop_Shl32,
14067 binop( Iop_And32,
14068 mkexpr( QNaN_true ),
14069 mkU32( 1 ) ),
14070 mkU8( 1 ) ) );
14071 assign( dcm5, binop( Iop_And32, mkexpr( SNaN_true), mkU32( 1 ) ) );
14073 } else if (opc2 == 0xE2) { // dtstdg, dtstdgq
14074 /* check if the exponent is extreme */
14075 assign( extreme_true, binop( Iop_Or32,
14076 unop( Iop_1Sto32,
14077 binop( Iop_CmpEQ32,
14078 mkexpr( exponent ),
14079 mkU32( max_exp ) ) ),
14080 unop( Iop_1Sto32,
14081 binop( Iop_CmpEQ32,
14082 mkexpr( exponent ),
14083 mkU32( min_exp ) ) ) ) );
14085 /* Check if LMD is zero */
14086 Get_lmd( &lmd, binop( Iop_Shr32,
14087 mkexpr( gfield ), mkU8( 31 - 5 ) ) );
14089 assign( lmd_zero_true, unop( Iop_1Sto32,
14090 binop( Iop_CmpEQ32,
14091 mkexpr( lmd ),
14092 mkU32( 0 ) ) ) );
14094 /* DCM[0:5] Bit Data Class definition
14095 * 0 Zero with non-extreme exponent
14096 * 1 Zero with extreme exponent
14097 * 2 Subnormal or (Normal with extreme exponent)
14098 * 3 Normal with non-extreme exponent and
14099 * leftmost zero digit in significand
14100 * 4 Normal with non-extreme exponent and
14101 * leftmost nonzero digit in significand
14102 * 5 Special symbol (Infinity, QNaN, or SNaN)
14104 assign( dcm0, binop( Iop_Shl32,
14105 binop( Iop_And32,
14106 binop( Iop_And32,
14107 unop( Iop_Not32,
14108 mkexpr( extreme_true ) ),
14109 mkexpr( zero_true ) ),
14110 mkU32( 0x1 ) ),
14111 mkU8( 5 ) ) );
14113 assign( dcm1, binop( Iop_Shl32,
14114 binop( Iop_And32,
14115 binop( Iop_And32,
14116 mkexpr( extreme_true ),
14117 mkexpr( zero_true ) ),
14118 mkU32( 0x1 ) ),
14119 mkU8( 4 ) ) );
14121 assign( dcm2, binop( Iop_Shl32,
14122 binop( Iop_And32,
14123 binop( Iop_Or32,
14124 binop( Iop_And32,
14125 mkexpr( extreme_true ),
14126 mkexpr( normal_true ) ),
14127 mkexpr( subnormal_true ) ),
14128 mkU32( 0x1 ) ),
14129 mkU8( 3 ) ) );
14131 assign( dcm3, binop( Iop_Shl32,
14132 binop( Iop_And32,
14133 binop( Iop_And32,
14134 binop( Iop_And32,
14135 unop( Iop_Not32,
14136 mkexpr( extreme_true ) ),
14137 mkexpr( normal_true ) ),
14138 unop( Iop_1Sto32,
14139 binop( Iop_CmpEQ32,
14140 mkexpr( lmd ),
14141 mkU32( 0 ) ) ) ),
14142 mkU32( 0x1 ) ),
14143 mkU8( 2 ) ) );
14145 assign( dcm4, binop( Iop_Shl32,
14146 binop( Iop_And32,
14147 binop( Iop_And32,
14148 binop( Iop_And32,
14149 unop( Iop_Not32,
14150 mkexpr( extreme_true ) ),
14151 mkexpr( normal_true ) ),
14152 unop( Iop_1Sto32,
14153 binop( Iop_CmpNE32,
14154 mkexpr( lmd ),
14155 mkU32( 0 ) ) ) ),
14156 mkU32( 0x1 ) ),
14157 mkU8( 1 ) ) );
14159 assign( dcm5, binop( Iop_And32,
14160 binop( Iop_Or32,
14161 mkexpr( SNaN_true),
14162 binop( Iop_Or32,
14163 mkexpr( QNaN_true),
14164 mkexpr( infinity_true) ) ),
14165 mkU32( 0x1 ) ) );
14168 /* create DCM field */
14169 assign( DCM_calc,
14170 binop( Iop_Or32,
14171 mkexpr( dcm0 ),
14172 binop( Iop_Or32,
14173 mkexpr( dcm1 ),
14174 binop( Iop_Or32,
14175 mkexpr( dcm2 ),
14176 binop( Iop_Or32,
14177 mkexpr( dcm3 ),
14178 binop( Iop_Or32,
14179 mkexpr( dcm4 ),
14180 mkexpr( dcm5 ) ) ) ) ) ) );
14182 /* Get the sign of the DFP number, ignore sign for QNaN */
14183 assign( sign,
14184 unop( Iop_1Uto32,
14185 binop( Iop_CmpEQ32,
14186 binop( Iop_Shr32,
14187 unop( Iop_64HIto32, mkexpr( frAI64_hi ) ),
14188 mkU8( 63 - 32 ) ),
14189 mkU32( 1 ) ) ) );
14191 /* This instruction generates a four bit field to be stored in the
14192 * condition code register. The condition code register consists of 7
14193 * fields. The field to be written to is specified by the BF (AKA crfD)
14194 * field.
14196 * The field layout is as follows:
14198 * Field Meaning
14199 * 0000 Operand positive with no match
14200 * 0100 Operand positive with at least one match
14201 * 0001 Operand negative with no match
14202 * 0101 Operand negative with at least one match
14204 assign( field, binop( Iop_Or32,
14205 binop( Iop_Shl32,
14206 mkexpr( sign ),
14207 mkU8( 3 ) ),
14208 binop( Iop_Shl32,
14209 unop( Iop_1Uto32,
14210 binop( Iop_CmpNE32,
14211 binop( Iop_And32,
14212 mkU32( DCM ),
14213 mkexpr( DCM_calc ) ),
14214 mkU32( 0 ) ) ),
14215 mkU8( 1 ) ) ) );
14217 putGST_field( PPC_GST_CR, mkexpr( field ), crfD );
14218 putFPCC( mkexpr( field ) );
14219 return True;
14222 static Bool dis_dfp_bcd(UInt theInstr) {
14223 UInt opc2 = ifieldOPClo10( theInstr );
14224 ULong sp = IFIELD(theInstr, 19, 2);
14225 ULong s = IFIELD(theInstr, 20, 1);
14226 UChar frT_addr = ifieldRegDS( theInstr );
14227 UChar frB_addr = ifieldRegB( theInstr );
14228 IRTemp frB = newTemp( Ity_D64 );
14229 IRTemp frBI64 = newTemp( Ity_I64 );
14230 IRTemp result = newTemp( Ity_I64 );
14231 IRTemp resultD64 = newTemp( Ity_D64 );
14232 IRTemp bcd64 = newTemp( Ity_I64 );
14233 IRTemp bcd_u = newTemp( Ity_I32 );
14234 IRTemp bcd_l = newTemp( Ity_I32 );
14235 IRTemp dbcd_u = newTemp( Ity_I32 );
14236 IRTemp dbcd_l = newTemp( Ity_I32 );
14237 IRTemp lmd = newTemp( Ity_I32 );
14239 assign( frB, getDReg( frB_addr ) );
14240 assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
14242 switch ( opc2 ) {
14243 case 0x142: // ddedpd DFP Decode DPD to BCD
14244 DIP( "ddedpd %llu,r%u,r%u\n", sp, frT_addr, frB_addr );
14246 assign( bcd64, unop( Iop_DPBtoBCD, mkexpr( frBI64 ) ) );
14247 assign( bcd_u, unop( Iop_64HIto32, mkexpr( bcd64 ) ) );
14248 assign( bcd_l, unop( Iop_64to32, mkexpr( bcd64 ) ) );
14250 if ( ( sp == 0 ) || ( sp == 1 ) ) {
14251 /* Unsigned BCD string */
14252 Get_lmd( &lmd,
14253 binop( Iop_Shr32,
14254 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
14255 mkU8( 31 - 5 ) ) ); // G-field[0:4]
14257 assign( result,
14258 binop( Iop_32HLto64,
14259 binop( Iop_Or32,
14260 binop( Iop_Shl32, mkexpr( lmd ), mkU8( 28 ) ),
14261 mkexpr( bcd_u ) ),
14262 mkexpr( bcd_l ) ) );
14264 } else {
14265 /* Signed BCD string, the cases for sp 2 and 3 only differ in how
14266 * the positive and negative values are encoded in the least
14267 * significant bits.
14269 IRTemp sign = newTemp( Ity_I32 );
14271 if (sp == 2) {
14272 /* Positive sign = 0xC, negative sign = 0xD */
14274 assign( sign,
14275 binop( Iop_Or32,
14276 binop( Iop_Shr32,
14277 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
14278 mkU8( 31 ) ),
14279 mkU32( 0xC ) ) );
14281 } else if ( sp == 3 ) {
14282 /* Positive sign = 0xF, negative sign = 0xD */
14283 IRTemp tmp32 = newTemp( Ity_I32 );
14285 /* Complement sign bit then OR into bit position 1 */
14286 assign( tmp32,
14287 binop( Iop_Xor32,
14288 binop( Iop_Shr32,
14289 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
14290 mkU8( 30 ) ),
14291 mkU32( 0x2 ) ) );
14293 assign( sign, binop( Iop_Or32, mkexpr( tmp32 ), mkU32( 0xD ) ) );
14295 } else {
14296 vpanic( "The impossible happened: dis_dfp_bcd(ppc), undefined SP field" );
14299 /* Put sign in bottom 4 bits, move most significant 4-bits from
14300 * bcd_l to bcd_u.
14302 assign( result,
14303 binop( Iop_32HLto64,
14304 binop( Iop_Or32,
14305 binop( Iop_Shr32,
14306 mkexpr( bcd_l ),
14307 mkU8( 28 ) ),
14308 binop( Iop_Shl32,
14309 mkexpr( bcd_u ),
14310 mkU8( 4 ) ) ),
14311 binop( Iop_Or32,
14312 mkexpr( sign ),
14313 binop( Iop_Shl32,
14314 mkexpr( bcd_l ),
14315 mkU8( 4 ) ) ) ) );
14318 putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result ) ) );
14319 break;
14321 case 0x342: // denbcd DFP Encode BCD to DPD
14323 IRTemp valid_mask = newTemp( Ity_I32 );
14324 IRTemp invalid_mask = newTemp( Ity_I32 );
14325 IRTemp without_lmd = newTemp( Ity_I64 );
14326 IRTemp tmp64 = newTemp( Ity_I64 );
14327 IRTemp dbcd64 = newTemp( Ity_I64 );
14328 IRTemp left_exp = newTemp( Ity_I32 );
14329 IRTemp g0_4 = newTemp( Ity_I32 );
14331 DIP( "denbcd %llu,r%u,r%u\n", s, frT_addr, frB_addr );
14333 if ( s == 0 ) {
14334 /* Unsigned BCD string */
14335 assign( dbcd64, unop( Iop_BCDtoDPB, mkexpr(frBI64 ) ) );
14336 assign( dbcd_u, unop( Iop_64HIto32, mkexpr( dbcd64 ) ) );
14337 assign( dbcd_l, unop( Iop_64to32, mkexpr( dbcd64 ) ) );
14339 assign( lmd,
14340 binop( Iop_Shr32,
14341 binop( Iop_And32,
14342 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
14343 mkU32( 0xF0000000 ) ),
14344 mkU8( 28 ) ) );
14346 assign( invalid_mask,
14347 bcd_digit_inval( unop( Iop_64HIto32, mkexpr( frBI64 ) ),
14348 unop( Iop_64to32, mkexpr( frBI64 ) ) ) );
14349 assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
14351 assign( without_lmd,
14352 unop( Iop_ReinterpD64asI64,
14353 binop( Iop_InsertExpD64,
14354 mkU64( DFP_LONG_BIAS ),
14355 unop( Iop_ReinterpI64asD64,
14356 binop( Iop_32HLto64,
14357 mkexpr( dbcd_u ),
14358 mkexpr( dbcd_l ) ) ) ) ) );
14359 assign( left_exp,
14360 binop( Iop_Shr32,
14361 binop( Iop_And32,
14362 unop( Iop_64HIto32, mkexpr( without_lmd ) ),
14363 mkU32( 0x60000000 ) ),
14364 mkU8( 29 ) ) );
14366 assign( g0_4,
14367 binop( Iop_Shl32,
14368 Gfield_encoding( mkexpr( left_exp ), mkexpr( lmd ) ),
14369 mkU8( 26 ) ) );
14371 assign( tmp64,
14372 binop( Iop_32HLto64,
14373 binop( Iop_Or32,
14374 binop( Iop_And32,
14375 unop( Iop_64HIto32,
14376 mkexpr( without_lmd ) ),
14377 mkU32( 0x83FFFFFF ) ),
14378 mkexpr( g0_4 ) ),
14379 unop( Iop_64to32, mkexpr( without_lmd ) ) ) );
14381 } else if ( s == 1 ) {
14382 IRTemp sign = newTemp( Ity_I32 );
14383 IRTemp sign_bit = newTemp( Ity_I32 );
14384 IRTemp pos_sign_mask = newTemp( Ity_I32 );
14385 IRTemp neg_sign_mask = newTemp( Ity_I32 );
14386 IRTemp tmp = newTemp( Ity_I64 );
14388 /* Signed BCD string, least significant 4 bits are sign bits
14389 * positive sign = 0xC, negative sign = 0xD
14391 assign( tmp, unop( Iop_BCDtoDPB,
14392 binop( Iop_32HLto64,
14393 binop( Iop_Shr32,
14394 unop( Iop_64HIto32,
14395 mkexpr( frBI64 ) ),
14396 mkU8( 4 ) ),
14397 binop( Iop_Or32,
14398 binop( Iop_Shr32,
14399 unop( Iop_64to32,
14400 mkexpr( frBI64 ) ),
14401 mkU8( 4 ) ),
14402 binop( Iop_Shl32,
14403 unop( Iop_64HIto32,
14404 mkexpr( frBI64 ) ),
14405 mkU8( 28 ) ) ) ) ) );
14407 assign( dbcd_u, unop( Iop_64HIto32, mkexpr( tmp ) ) );
14408 assign( dbcd_l, unop( Iop_64to32, mkexpr( tmp ) ) );
14410 /* Get the sign of the BCD string. */
14411 assign( sign,
14412 binop( Iop_And32,
14413 unop( Iop_64to32, mkexpr( frBI64 ) ),
14414 mkU32( 0xF ) ) );
14416 assign( neg_sign_mask, Generate_neg_sign_mask( mkexpr( sign ) ) );
14417 assign( pos_sign_mask, Generate_pos_sign_mask( mkexpr( sign ) ) );
14418 assign( sign_bit,
14419 Generate_sign_bit( mkexpr( pos_sign_mask ),
14420 mkexpr( neg_sign_mask ) ) );
14422 /* Check for invalid sign and BCD digit. Don't check the bottom
14423 * four bits of bcd_l as that is the sign value.
14425 assign( invalid_mask,
14426 Generate_inv_mask(
14427 bcd_digit_inval( unop( Iop_64HIto32,
14428 mkexpr( frBI64 ) ),
14429 binop( Iop_Shr32,
14430 unop( Iop_64to32,
14431 mkexpr( frBI64 ) ),
14432 mkU8( 4 ) ) ),
14433 mkexpr( pos_sign_mask ),
14434 mkexpr( neg_sign_mask ) ) );
14436 assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
14438 /* Generate the result assuming the sign value was valid. */
14439 assign( tmp64,
14440 unop( Iop_ReinterpD64asI64,
14441 binop( Iop_InsertExpD64,
14442 mkU64( DFP_LONG_BIAS ),
14443 unop( Iop_ReinterpI64asD64,
14444 binop( Iop_32HLto64,
14445 binop( Iop_Or32,
14446 mkexpr( dbcd_u ),
14447 mkexpr( sign_bit ) ),
14448 mkexpr( dbcd_l ) ) ) ) ) );
14451 /* Generate the value to store depending on the validity of the
14452 * sign value and the validity of the BCD digits.
14454 assign( resultD64,
14455 unop( Iop_ReinterpI64asD64,
14456 binop( Iop_32HLto64,
14457 binop( Iop_Or32,
14458 binop( Iop_And32,
14459 mkexpr( valid_mask ),
14460 unop( Iop_64HIto32,
14461 mkexpr( tmp64 ) ) ),
14462 binop( Iop_And32,
14463 mkU32( 0x7C000000 ),
14464 mkexpr( invalid_mask ) ) ),
14465 binop( Iop_Or32,
14466 binop( Iop_And32,
14467 mkexpr( valid_mask ),
14468 unop( Iop_64to32, mkexpr( tmp64 ) ) ),
14469 binop( Iop_And32,
14470 mkU32( 0x0 ),
14471 mkexpr( invalid_mask ) ) ) ) ) );
14472 putDReg( frT_addr, mkexpr( resultD64 ) );
14474 break;
14475 default:
14476 vpanic( "ERROR: dis_dfp_bcd(ppc), undefined opc2 case " );
14477 return False;
14479 return True;
14482 static Bool dis_dfp_bcdq( UInt theInstr )
14484 UInt opc2 = ifieldOPClo10( theInstr );
14485 ULong sp = IFIELD(theInstr, 19, 2);
14486 ULong s = IFIELD(theInstr, 20, 1);
14487 IRTemp frB_hi = newTemp( Ity_D64 );
14488 IRTemp frB_lo = newTemp( Ity_D64 );
14489 IRTemp frBI64_hi = newTemp( Ity_I64 );
14490 IRTemp frBI64_lo = newTemp( Ity_I64 );
14491 UChar frT_addr = ifieldRegDS( theInstr );
14492 UChar frB_addr = ifieldRegB( theInstr );
14494 IRTemp lmd = newTemp( Ity_I32 );
14495 IRTemp result_hi = newTemp( Ity_I64 );
14496 IRTemp result_lo = newTemp( Ity_I64 );
14498 assign( frB_hi, getDReg( frB_addr ) );
14499 assign( frB_lo, getDReg( frB_addr + 1 ) );
14500 assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
14501 assign( frBI64_lo, unop( Iop_ReinterpD64asI64, mkexpr( frB_lo ) ) );
14503 switch ( opc2 ) {
14504 case 0x142: // ddedpdq DFP Decode DPD to BCD
14506 IRTemp low_60_u = newTemp( Ity_I32 );
14507 IRTemp low_60_l = newTemp( Ity_I32 );
14508 IRTemp mid_60_u = newTemp( Ity_I32 );
14509 IRTemp mid_60_l = newTemp( Ity_I32 );
14510 IRTemp top_12_l = newTemp( Ity_I32 );
14512 DIP( "ddedpdq %llu,r%u,r%u\n", sp, frT_addr, frB_addr );
14514 /* Note, instruction only stores the lower 32 BCD digits in
14515 * the result
14517 Generate_132_bit_bcd_string( mkexpr( frBI64_hi ),
14518 mkexpr( frBI64_lo ),
14519 &top_12_l,
14520 &mid_60_u,
14521 &mid_60_l,
14522 &low_60_u,
14523 &low_60_l );
14525 if ( ( sp == 0 ) || ( sp == 1 ) ) {
14526 /* Unsigned BCD string */
14527 assign( result_hi,
14528 binop( Iop_32HLto64,
14529 binop( Iop_Or32,
14530 binop( Iop_Shl32,
14531 mkexpr( top_12_l ),
14532 mkU8( 24 ) ),
14533 binop( Iop_Shr32,
14534 mkexpr( mid_60_u ),
14535 mkU8( 4 ) ) ),
14536 binop( Iop_Or32,
14537 binop( Iop_Shl32,
14538 mkexpr( mid_60_u ),
14539 mkU8( 28 ) ),
14540 binop( Iop_Shr32,
14541 mkexpr( mid_60_l ),
14542 mkU8( 4 ) ) ) ) );
14544 assign( result_lo,
14545 binop( Iop_32HLto64,
14546 binop( Iop_Or32,
14547 binop( Iop_Shl32,
14548 mkexpr( mid_60_l ),
14549 mkU8( 28 ) ),
14550 mkexpr( low_60_u ) ),
14551 mkexpr( low_60_l ) ) );
14553 } else {
14554 /* Signed BCD string, the cases for sp 2 and 3 only differ in how
14555 * the positive and negative values are encoded in the least
14556 * significant bits.
14558 IRTemp sign = newTemp( Ity_I32 );
14560 if ( sp == 2 ) {
14561 /* Positive sign = 0xC, negative sign = 0xD */
14562 assign( sign,
14563 binop( Iop_Or32,
14564 binop( Iop_Shr32,
14565 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
14566 mkU8( 31 ) ),
14567 mkU32( 0xC ) ) );
14569 } else if ( sp == 3 ) {
14570 IRTemp tmp32 = newTemp( Ity_I32 );
14572 /* Positive sign = 0xF, negative sign = 0xD.
14573 * Need to complement sign bit then OR into bit position 1.
14575 assign( tmp32,
14576 binop( Iop_Xor32,
14577 binop( Iop_Shr32,
14578 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
14579 mkU8( 30 ) ),
14580 mkU32( 0x2 ) ) );
14582 assign( sign, binop( Iop_Or32, mkexpr( tmp32 ), mkU32( 0xD ) ) );
14584 } else {
14585 vpanic( "The impossible happened: dis_dfp_bcd(ppc), undefined SP field" );
14588 assign( result_hi,
14589 binop( Iop_32HLto64,
14590 binop( Iop_Or32,
14591 binop( Iop_Shl32,
14592 mkexpr( top_12_l ),
14593 mkU8( 28 ) ),
14594 mkexpr( mid_60_u ) ),
14595 mkexpr( mid_60_l ) ) );
14597 assign( result_lo,
14598 binop( Iop_32HLto64,
14599 binop( Iop_Or32,
14600 binop( Iop_Shl32,
14601 mkexpr( low_60_u ),
14602 mkU8( 4 ) ),
14603 binop( Iop_Shr32,
14604 mkexpr( low_60_l ),
14605 mkU8( 28 ) ) ),
14606 binop( Iop_Or32,
14607 binop( Iop_Shl32,
14608 mkexpr( low_60_l ),
14609 mkU8( 4 ) ),
14610 mkexpr( sign ) ) ) );
14613 putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result_hi ) ) );
14614 putDReg( frT_addr + 1,
14615 unop( Iop_ReinterpI64asD64, mkexpr( result_lo ) ) );
14617 break;
14618 case 0x342: // denbcdq DFP Encode BCD to DPD
14620 IRTemp valid_mask = newTemp( Ity_I32 );
14621 IRTemp invalid_mask = newTemp( Ity_I32 );
14622 IRTemp result128 = newTemp( Ity_D128 );
14623 IRTemp dfp_significand = newTemp( Ity_D128 );
14624 IRTemp tmp_hi = newTemp( Ity_I64 );
14625 IRTemp tmp_lo = newTemp( Ity_I64 );
14626 IRTemp dbcd_top_l = newTemp( Ity_I32 );
14627 IRTemp dbcd_mid_u = newTemp( Ity_I32 );
14628 IRTemp dbcd_mid_l = newTemp( Ity_I32 );
14629 IRTemp dbcd_low_u = newTemp( Ity_I32 );
14630 IRTemp dbcd_low_l = newTemp( Ity_I32 );
14631 IRTemp bcd_top_8 = newTemp( Ity_I64 );
14632 IRTemp bcd_mid_60 = newTemp( Ity_I64 );
14633 IRTemp bcd_low_60 = newTemp( Ity_I64 );
14634 IRTemp sign_bit = newTemp( Ity_I32 );
14635 IRTemp tmptop10 = newTemp( Ity_I64 );
14636 IRTemp tmpmid50 = newTemp( Ity_I64 );
14637 IRTemp tmplow50 = newTemp( Ity_I64 );
14638 IRTemp inval_bcd_digit_mask = newTemp( Ity_I32 );
14640 DIP( "denbcd %llu,r%u,r%u\n", s, frT_addr, frB_addr );
14642 if ( s == 0 ) {
14643 /* Unsigned BCD string */
14644 assign( sign_bit, mkU32( 0 ) ); // set to zero for unsigned string
14646 assign( bcd_top_8,
14647 binop( Iop_32HLto64,
14648 mkU32( 0 ),
14649 binop( Iop_And32,
14650 binop( Iop_Shr32,
14651 unop( Iop_64HIto32,
14652 mkexpr( frBI64_hi ) ),
14653 mkU8( 24 ) ),
14654 mkU32( 0xFF ) ) ) );
14655 assign( bcd_mid_60,
14656 binop( Iop_32HLto64,
14657 binop( Iop_Or32,
14658 binop( Iop_Shr32,
14659 unop( Iop_64to32,
14660 mkexpr( frBI64_hi ) ),
14661 mkU8( 28 ) ),
14662 binop( Iop_Shl32,
14663 unop( Iop_64HIto32,
14664 mkexpr( frBI64_hi ) ),
14665 mkU8( 4 ) ) ),
14666 binop( Iop_Or32,
14667 binop( Iop_Shl32,
14668 unop( Iop_64to32,
14669 mkexpr( frBI64_hi ) ),
14670 mkU8( 4 ) ),
14671 binop( Iop_Shr32,
14672 unop( Iop_64HIto32,
14673 mkexpr( frBI64_lo ) ),
14674 mkU8( 28 ) ) ) ) );
14676 /* Note, the various helper functions ignores top 4-bits */
14677 assign( bcd_low_60, mkexpr( frBI64_lo ) );
14679 assign( tmptop10, unop( Iop_BCDtoDPB, mkexpr( bcd_top_8 ) ) );
14680 assign( dbcd_top_l, unop( Iop_64to32, mkexpr( tmptop10 ) ) );
14682 assign( tmpmid50, unop( Iop_BCDtoDPB, mkexpr( bcd_mid_60 ) ) );
14683 assign( dbcd_mid_u, unop( Iop_64HIto32, mkexpr( tmpmid50 ) ) );
14684 assign( dbcd_mid_l, unop( Iop_64to32, mkexpr( tmpmid50 ) ) );
14686 assign( tmplow50, unop( Iop_BCDtoDPB, mkexpr( bcd_low_60 ) ) );
14687 assign( dbcd_low_u, unop( Iop_64HIto32, mkexpr( tmplow50 ) ) );
14688 assign( dbcd_low_l, unop( Iop_64to32, mkexpr( tmplow50 ) ) );
14690 /* The entire BCD string fits in lower 110-bits. The LMD = 0,
14691 * value is not part of the final result. Only the right most
14692 * BCD digits are stored.
14694 assign( lmd, mkU32( 0 ) );
14696 assign( invalid_mask,
14697 binop( Iop_Or32,
14698 bcd_digit_inval( mkU32( 0 ),
14699 unop( Iop_64to32,
14700 mkexpr( bcd_top_8 ) ) ),
14701 binop( Iop_Or32,
14702 bcd_digit_inval( unop( Iop_64HIto32,
14703 mkexpr( bcd_mid_60 ) ),
14704 unop( Iop_64to32,
14705 mkexpr( bcd_mid_60 ) ) ),
14706 bcd_digit_inval( unop( Iop_64HIto32,
14707 mkexpr( bcd_low_60 ) ),
14708 unop( Iop_64to32,
14709 mkexpr( bcd_low_60 ) )
14710 ) ) ) );
14712 } else if ( s == 1 ) {
14713 IRTemp sign = newTemp( Ity_I32 );
14714 IRTemp zero = newTemp( Ity_I32 );
14715 IRTemp pos_sign_mask = newTemp( Ity_I32 );
14716 IRTemp neg_sign_mask = newTemp( Ity_I32 );
14718 /* The sign of the BCD string is stored in lower 4 bits */
14719 assign( sign,
14720 binop( Iop_And32,
14721 unop( Iop_64to32, mkexpr( frBI64_lo ) ),
14722 mkU32( 0xF ) ) );
14723 assign( neg_sign_mask, Generate_neg_sign_mask( mkexpr( sign ) ) );
14724 assign( pos_sign_mask, Generate_pos_sign_mask( mkexpr( sign ) ) );
14725 assign( sign_bit,
14726 Generate_sign_bit( mkexpr( pos_sign_mask ),
14727 mkexpr( neg_sign_mask ) ) );
14729 /* Generate the value assuminig the sign and BCD digits are vaild */
14730 assign( bcd_top_8,
14731 binop( Iop_32HLto64,
14732 mkU32( 0x0 ),
14733 binop( Iop_Shr32,
14734 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
14735 mkU8( 28 ) ) ) );
14737 /* The various helper routines ignore the upper 4-bits */
14738 assign( bcd_mid_60, mkexpr( frBI64_hi ) );
14740 /* Remove bottom four sign bits */
14741 assign( bcd_low_60,
14742 binop( Iop_32HLto64,
14743 binop( Iop_Shr32,
14744 unop( Iop_64HIto32,
14745 mkexpr( frBI64_lo ) ),
14746 mkU8( 4 ) ),
14747 binop( Iop_Or32,
14748 binop( Iop_Shl32,
14749 unop( Iop_64HIto32,
14750 mkexpr( frBI64_lo ) ),
14751 mkU8( 28 ) ),
14752 binop( Iop_Shr32,
14753 unop( Iop_64to32,
14754 mkexpr( frBI64_lo ) ),
14755 mkU8( 4 ) ) ) ) );
14756 assign( tmptop10, unop( Iop_BCDtoDPB, mkexpr(bcd_top_8 ) ) );
14757 assign( dbcd_top_l, unop( Iop_64to32, mkexpr( tmptop10 ) ) );
14759 assign( tmpmid50, unop( Iop_BCDtoDPB, mkexpr(bcd_mid_60 ) ) );
14760 assign( dbcd_mid_u, unop( Iop_64HIto32, mkexpr( tmpmid50 ) ) );
14761 assign( dbcd_mid_l, unop( Iop_64to32, mkexpr( tmpmid50 ) ) );
14763 assign( tmplow50, unop( Iop_BCDtoDPB, mkexpr( bcd_low_60 ) ) );
14764 assign( dbcd_low_u, unop( Iop_64HIto32, mkexpr( tmplow50 ) ) );
14765 assign( dbcd_low_l, unop( Iop_64to32, mkexpr( tmplow50 ) ) );
14767 /* The entire BCD string fits in lower 110-bits. The LMD value
14768 * is not stored in the final result for the DFP Long instruction.
14770 assign( lmd, mkU32( 0 ) );
14772 /* Check for invalid sign and invalid BCD digit. Don't check the
14773 * bottom four bits of frBI64_lo as that is the sign value.
14775 assign( zero, mkU32( 0 ) );
14776 assign( inval_bcd_digit_mask,
14777 binop( Iop_Or32,
14778 bcd_digit_inval( mkexpr( zero ),
14779 unop( Iop_64to32,
14780 mkexpr( bcd_top_8 ) ) ),
14781 binop( Iop_Or32,
14782 bcd_digit_inval( unop( Iop_64HIto32,
14783 mkexpr( bcd_mid_60 ) ),
14784 unop( Iop_64to32,
14785 mkexpr( bcd_mid_60 ) ) ),
14786 bcd_digit_inval( unop( Iop_64HIto32,
14787 mkexpr( frBI64_lo ) ),
14788 binop( Iop_Shr32,
14789 unop( Iop_64to32,
14790 mkexpr( frBI64_lo ) ),
14791 mkU8( 4 ) ) ) ) ) );
14792 assign( invalid_mask,
14793 Generate_inv_mask( mkexpr( inval_bcd_digit_mask ),
14794 mkexpr( pos_sign_mask ),
14795 mkexpr( neg_sign_mask ) ) );
14799 assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
14801 /* Calculate the value of the result assuming sign and BCD digits
14802 * are all valid.
14804 assign( dfp_significand,
14805 binop( Iop_D64HLtoD128,
14806 unop( Iop_ReinterpI64asD64,
14807 binop( Iop_32HLto64,
14808 binop( Iop_Or32,
14809 mkexpr( sign_bit ),
14810 mkexpr( dbcd_top_l ) ),
14811 binop( Iop_Or32,
14812 binop( Iop_Shl32,
14813 mkexpr( dbcd_mid_u ),
14814 mkU8( 18 ) ),
14815 binop( Iop_Shr32,
14816 mkexpr( dbcd_mid_l ),
14817 mkU8( 14 ) ) ) ) ),
14818 unop( Iop_ReinterpI64asD64,
14819 binop( Iop_32HLto64,
14820 binop( Iop_Or32,
14821 mkexpr( dbcd_low_u ),
14822 binop( Iop_Shl32,
14823 mkexpr( dbcd_mid_l ),
14824 mkU8( 18 ) ) ),
14825 mkexpr( dbcd_low_l ) ) ) ) );
14827 /* Break the result back down to 32-bit chunks and replace chunks.
14828 * If there was an invalid BCD digit or invalid sign value, replace
14829 * the calculated result with the invalid bit string.
14831 assign( result128,
14832 binop( Iop_InsertExpD128,
14833 mkU64( DFP_EXTND_BIAS ),
14834 mkexpr( dfp_significand ) ) );
14836 assign( tmp_hi,
14837 unop( Iop_ReinterpD64asI64,
14838 unop( Iop_D128HItoD64, mkexpr( result128 ) ) ) );
14840 assign( tmp_lo,
14841 unop( Iop_ReinterpD64asI64,
14842 unop( Iop_D128LOtoD64, mkexpr( result128 ) ) ) );
14844 assign( result_hi,
14845 binop( Iop_32HLto64,
14846 binop( Iop_Or32,
14847 binop( Iop_And32,
14848 mkexpr( valid_mask ),
14849 unop( Iop_64HIto32, mkexpr( tmp_hi ) ) ),
14850 binop( Iop_And32,
14851 mkU32( 0x7C000000 ),
14852 mkexpr( invalid_mask ) ) ),
14853 binop( Iop_Or32,
14854 binop( Iop_And32,
14855 mkexpr( valid_mask ),
14856 unop( Iop_64to32, mkexpr( tmp_hi ) ) ),
14857 binop( Iop_And32,
14858 mkU32( 0x0 ),
14859 mkexpr( invalid_mask ) ) ) ) );
14861 assign( result_lo,
14862 binop( Iop_32HLto64,
14863 binop( Iop_Or32,
14864 binop( Iop_And32,
14865 mkexpr( valid_mask ),
14866 unop( Iop_64HIto32, mkexpr( tmp_lo ) ) ),
14867 binop( Iop_And32,
14868 mkU32( 0x0 ),
14869 mkexpr( invalid_mask ) ) ),
14870 binop( Iop_Or32,
14871 binop( Iop_And32,
14872 mkexpr( valid_mask ),
14873 unop( Iop_64to32, mkexpr( tmp_lo ) ) ),
14874 binop( Iop_And32,
14875 mkU32( 0x0 ),
14876 mkexpr( invalid_mask ) ) ) ) );
14878 putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result_hi ) ) );
14879 putDReg( frT_addr + 1,
14880 unop( Iop_ReinterpI64asD64, mkexpr( result_lo ) ) );
14883 break;
14884 default:
14885 vpanic( "ERROR: dis_dfp_bcdq(ppc), undefined opc2 case " );
14886 break;
14888 return True;
14891 static Bool dis_dfp_significant_digits( UInt theInstr )
14893 UInt opc1 = ifieldOPC( theInstr );
14894 UInt opc2 = ifieldOPClo10(theInstr);
14895 UChar frA_addr = ifieldRegA( theInstr );
14896 UChar frB_addr = ifieldRegB( theInstr );
14897 IRTemp frA = newTemp( Ity_D64 );
14898 IRTemp B_sig = newTemp( Ity_I8 );
14899 IRTemp K = newTemp( Ity_I8 );
14900 IRTemp lmd_B = newTemp( Ity_I32 );
14901 IRTemp field = newTemp( Ity_I32 );
14902 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
14903 IRTemp Unordered_true = newTemp( Ity_I32 );
14904 IRTemp Eq_true_mask = newTemp( Ity_I32 );
14905 IRTemp Lt_true_mask = newTemp( Ity_I32 );
14906 IRTemp Gt_true_mask = newTemp( Ity_I32 );
14907 IRTemp KisZero_true_mask = newTemp( Ity_I32 );
14908 IRTemp KisZero_false_mask = newTemp( Ity_I32 );
14909 IRTemp cc = newTemp( Ity_I32 );
14910 UChar UIM = toUChar( IFIELD( theInstr, 16, 6 ) );
14911 IRTemp BCD_valid = newTemp( Ity_I32 );
14913 if (opc2 == 0x2A2) { // dtstsf DFP Test Significance
14914 // dtstsfq DFP Test Significance Quad
14915 /* Get the reference singificance stored in frA */
14916 assign( frA, getDReg( frA_addr ) );
14918 /* Convert from 64 bit to 8 bits in two steps. The Iop_64to8 is not
14919 * supported in 32-bit mode.
14921 assign( K, unop( Iop_32to8,
14922 binop( Iop_And32,
14923 unop( Iop_64to32,
14924 unop( Iop_ReinterpD64asI64,
14925 mkexpr( frA ) ) ),
14926 mkU32( 0x3F ) ) ) );
14928 } else if (opc2 == 0x2A3) { // dtstsfi DFP Test Significance Immediate
14929 // dtstsfiq DFP Test Significance Quad Immediate
14930 /* get the significane from the immediate field */
14931 assign( K, mkU8( UIM) );
14933 } else {
14934 vex_printf("dis_dfp_significant_digits(ppc)(opc2) wrong\n");
14935 return False;
14938 switch ( opc1 ) {
14939 case 0x3b: // dtstsf DFP Test Significance
14940 // dtstsfi DFP Test Significance Immediate
14942 IRTemp frB = newTemp( Ity_D64 );
14943 IRTemp frBI64 = newTemp( Ity_I64 );
14944 IRTemp B_bcd_u = newTemp( Ity_I32 );
14945 IRTemp B_bcd_l = newTemp( Ity_I32 );
14946 IRTemp tmp64 = newTemp( Ity_I64 );
14948 if (opc2 == 0x2A2) {
14949 DIP( "dtstsf %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
14950 } else {
14951 DIP( "dtstsfi %u,%u,r%u\n", crfD, UIM, frB_addr );
14954 assign( frB, getDReg( frB_addr ) );
14955 assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
14957 /* Get the BCD string for the value stored in a series of I32 values.
14958 * Count the number of leading zeros. Subtract the number of leading
14959 * zeros from 16 (maximum number of significant digits in DFP
14960 * Long).
14962 Get_lmd( &lmd_B,
14963 binop( Iop_Shr32,
14964 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
14965 mkU8( 31 - 5 ) ) ); // G-field[0:4]
14967 assign( tmp64, unop( Iop_DPBtoBCD, mkexpr( frBI64 ) ) );
14968 assign( B_bcd_u, unop( Iop_64HIto32, mkexpr( tmp64 ) ) );
14969 assign( B_bcd_l, unop( Iop_64to32, mkexpr( tmp64 ) ) );
14971 assign( B_sig,
14972 binop( Iop_Sub8,
14973 mkU8( DFP_LONG_MAX_SIG_DIGITS ),
14974 Count_leading_zeros_60( mkexpr( lmd_B ),
14975 mkexpr( B_bcd_u ),
14976 mkexpr( B_bcd_l ) ) ) );
14978 assign( BCD_valid,
14979 binop( Iop_Or32,
14980 bcd_digit_inval( mkexpr( B_bcd_u), mkexpr( B_bcd_l) ),
14981 bcd_digit_inval( mkexpr( lmd_B), mkU32( 0 ) ) ) );
14983 /* Set unordered to True if the number is NaN, Inf or an invalid
14984 * digit.
14986 assign( Unordered_true,
14987 binop( Iop_Or32,
14988 Check_unordered( mkexpr( frBI64 ) ),
14989 mkexpr( BCD_valid) ) );
14991 break;
14992 case 0x3F: // dtstsfq DFP Test Significance
14993 // dtstsfqi DFP Test Significance Immediate
14995 IRTemp frB_hi = newTemp( Ity_D64 );
14996 IRTemp frB_lo = newTemp( Ity_D64 );
14997 IRTemp frBI64_hi = newTemp( Ity_I64 );
14998 IRTemp frBI64_lo = newTemp( Ity_I64 );
14999 IRTemp B_low_60_u = newTemp( Ity_I32 );
15000 IRTemp B_low_60_l = newTemp( Ity_I32 );
15001 IRTemp B_mid_60_u = newTemp( Ity_I32 );
15002 IRTemp B_mid_60_l = newTemp( Ity_I32 );
15003 IRTemp B_top_12_l = newTemp( Ity_I32 );
15005 if (opc2 == 0x2A2) {
15006 DIP( "dtstsfq %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
15007 } else {
15008 DIP( "dtstsfiq %u,%u,r%u\n", crfD, UIM, frB_addr );
15011 assign( frB_hi, getDReg( frB_addr ) );
15012 assign( frB_lo, getDReg( frB_addr + 1 ) );
15014 assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
15015 assign( frBI64_lo, unop( Iop_ReinterpD64asI64, mkexpr( frB_lo ) ) );
15017 /* Get the BCD string for the value stored in a series of I32 values.
15018 * Count the number of leading zeros. Subtract the number of leading
15019 * zeros from 32 (maximum number of significant digits in DFP
15020 * extended).
15022 Get_lmd( &lmd_B,
15023 binop( Iop_Shr32,
15024 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
15025 mkU8( 31 - 5 ) ) ); // G-field[0:4]
15027 Generate_132_bit_bcd_string( mkexpr( frBI64_hi ),
15028 mkexpr( frBI64_lo ),
15029 &B_top_12_l,
15030 &B_mid_60_u,
15031 &B_mid_60_l,
15032 &B_low_60_u,
15033 &B_low_60_l );
15035 assign( BCD_valid,
15036 binop( Iop_Or32,
15037 binop( Iop_Or32,
15038 bcd_digit_inval( mkexpr( lmd_B ),
15039 mkexpr( B_top_12_l ) ),
15040 bcd_digit_inval( mkexpr( B_mid_60_u ),
15041 mkexpr( B_mid_60_l ) ) ),
15042 bcd_digit_inval( mkexpr( B_low_60_u ),
15043 mkexpr( B_low_60_l ) ) ) );
15045 assign( B_sig,
15046 binop( Iop_Sub8,
15047 mkU8( DFP_EXTND_MAX_SIG_DIGITS ),
15048 Count_leading_zeros_128( mkexpr( lmd_B ),
15049 mkexpr( B_top_12_l ),
15050 mkexpr( B_mid_60_u ),
15051 mkexpr( B_mid_60_l ),
15052 mkexpr( B_low_60_u ),
15053 mkexpr( B_low_60_l ) ) ) );
15055 /* Set unordered to True if the number is NaN, Inf or an invalid
15056 * digit.
15058 assign( Unordered_true,
15059 binop( Iop_Or32,
15060 Check_unordered( mkexpr( frBI64_hi ) ),
15061 mkexpr( BCD_valid) ) );
15063 break;
15066 /* Compare (16 - cnt[0]) against K and set the condition code field
15067 * accordingly.
15069 * The field layout is as follows:
15071 * bit[3:0] Description
15072 * 3 K != 0 and K < Number of significant digits if FRB
15073 * 2 K != 0 and K > Number of significant digits if FRB OR K = 0
15074 * 1 K != 0 and K = Number of significant digits if FRB
15075 * 0 K ? Number of significant digits if FRB
15077 assign( Eq_true_mask,
15078 unop( Iop_1Sto32,
15079 binop( Iop_CmpEQ32,
15080 unop( Iop_8Uto32, mkexpr( K ) ),
15081 unop( Iop_8Uto32, mkexpr( B_sig ) ) ) ) );
15082 assign( Lt_true_mask,
15083 unop( Iop_1Sto32,
15084 binop( Iop_CmpLT32U,
15085 unop( Iop_8Uto32, mkexpr( K ) ),
15086 unop( Iop_8Uto32, mkexpr( B_sig ) ) ) ) );
15087 assign( Gt_true_mask,
15088 unop( Iop_1Sto32,
15089 binop( Iop_CmpLT32U,
15090 unop( Iop_8Uto32, mkexpr( B_sig ) ),
15091 unop( Iop_8Uto32, mkexpr( K ) ) ) ) );
15093 assign( KisZero_true_mask,
15094 unop( Iop_1Sto32,
15095 binop( Iop_CmpEQ32,
15096 unop( Iop_8Uto32, mkexpr( K ) ),
15097 mkU32( 0 ) ) ) );
15098 assign( KisZero_false_mask,
15099 unop( Iop_1Sto32,
15100 binop( Iop_CmpNE32,
15101 unop( Iop_8Uto32, mkexpr( K ) ),
15102 mkU32( 0 ) ) ) );
15104 assign( field,
15105 binop( Iop_Or32,
15106 binop( Iop_And32,
15107 mkexpr( KisZero_false_mask ),
15108 binop( Iop_Or32,
15109 binop( Iop_And32,
15110 mkexpr( Lt_true_mask ),
15111 mkU32( 0x8 ) ),
15112 binop( Iop_Or32,
15113 binop( Iop_And32,
15114 mkexpr( Gt_true_mask ),
15115 mkU32( 0x4 ) ),
15116 binop( Iop_And32,
15117 mkexpr( Eq_true_mask ),
15118 mkU32( 0x2 ) ) ) ) ),
15119 binop( Iop_And32,
15120 mkexpr( KisZero_true_mask ),
15121 mkU32( 0x4 ) ) ) );
15123 assign( cc, binop( Iop_Or32,
15124 binop( Iop_And32,
15125 mkexpr( Unordered_true ),
15126 mkU32( 0x1 ) ),
15127 binop( Iop_And32,
15128 unop( Iop_Not32, mkexpr( Unordered_true ) ),
15129 mkexpr( field ) ) ) );
15131 putGST_field( PPC_GST_CR, mkexpr( cc ), crfD );
15132 putFPCC( mkexpr( cc ) );
15134 return True;
15136 /*------------------------------------------------------------*/
15137 /*--- AltiVec Instruction Translation ---*/
15138 /*------------------------------------------------------------*/
15141 Altivec Cache Control Instructions (Data Streams)
15143 static Bool dis_av_datastream ( UInt theInstr )
15145 /* X-Form */
15146 UChar opc1 = ifieldOPC(theInstr);
15147 UChar flag_T = toUChar( IFIELD( theInstr, 25, 1 ) );
15148 UChar flag_A = flag_T;
15149 UChar b23to24 = toUChar( IFIELD( theInstr, 23, 2 ) );
15150 UChar STRM = toUChar( IFIELD( theInstr, 21, 2 ) );
15151 UChar rA_addr = ifieldRegA(theInstr);
15152 UChar rB_addr = ifieldRegB(theInstr);
15153 UInt opc2 = ifieldOPClo10(theInstr);
15154 UChar b0 = ifieldBIT0(theInstr);
15156 if (opc1 != 0x1F || b23to24 != 0 || b0 != 0) {
15157 vex_printf("dis_av_datastream(ppc)(instr)\n");
15158 return False;
15161 switch (opc2) {
15162 case 0x156: // dst (Data Stream Touch, AV p115)
15163 DIP("dst%s r%u,r%u,%d\n", flag_T ? "t" : "",
15164 rA_addr, rB_addr, STRM);
15165 break;
15167 case 0x176: // dstst (Data Stream Touch for Store, AV p117)
15168 DIP("dstst%s r%u,r%u,%d\n", flag_T ? "t" : "",
15169 rA_addr, rB_addr, STRM);
15170 break;
15172 case 0x336: // dss (Data Stream Stop, AV p114)
15173 if (rA_addr != 0 || rB_addr != 0) {
15174 vex_printf("dis_av_datastream(ppc)(opc2,dst)\n");
15175 return False;
15177 if (flag_A == 0) {
15178 DIP("dss %d\n", STRM);
15179 } else {
15180 DIP("dssall\n");
15182 break;
15184 default:
15185 vex_printf("dis_av_datastream(ppc)(opc2)\n");
15186 return False;
15188 return True;
15192 AltiVec Processor Control Instructions
15194 static Bool dis_av_procctl ( UInt theInstr )
15196 /* VX-Form */
15197 UChar opc1 = ifieldOPC(theInstr);
15198 UChar vD_addr = ifieldRegDS(theInstr);
15199 UChar vA_addr = ifieldRegA(theInstr);
15200 UChar vB_addr = ifieldRegB(theInstr);
15201 UInt opc2 = IFIELD( theInstr, 0, 11 );
15203 if (opc1 != 0x4) {
15204 vex_printf("dis_av_procctl(ppc)(instr)\n");
15205 return False;
15208 switch (opc2) {
15209 case 0x604: // mfvscr (Move from VSCR, AV p129)
15210 if (vA_addr != 0 || vB_addr != 0) {
15211 vex_printf("dis_av_procctl(ppc)(opc2,dst)\n");
15212 return False;
15214 DIP("mfvscr v%d\n", vD_addr);
15215 putVReg( vD_addr, unop(Iop_32UtoV128, getGST( PPC_GST_VSCR )) );
15216 break;
15218 case 0x644: { // mtvscr (Move to VSCR, AV p130)
15219 IRTemp vB = newTemp(Ity_V128);
15220 if (vD_addr != 0 || vA_addr != 0) {
15221 vex_printf("dis_av_procctl(ppc)(opc2,dst)\n");
15222 return False;
15224 DIP("mtvscr v%d\n", vB_addr);
15225 assign( vB, getVReg(vB_addr));
15226 putGST( PPC_GST_VSCR, unop(Iop_V128to32, mkexpr(vB)) );
15227 break;
15229 default:
15230 vex_printf("dis_av_procctl(ppc)(opc2)\n");
15231 return False;
15233 return True;
15237 Vector Extend Sign Instructions
15239 static Bool dis_av_extend_sign_count_zero ( UInt theInstr, UInt allow_isa_3_0 )
15241 /* VX-Form, sort of, the A register field is used to select the specific
15242 * sign extension instruction or count leading/trailing zero LSB
15243 * instruction.
15246 UChar opc1 = ifieldOPC( theInstr );
15247 UChar rT_addr = ifieldRegDS (theInstr );
15248 UChar rA_addr = ifieldRegA( theInstr );
15249 UChar vB_addr = ifieldRegB( theInstr );
15250 UInt opc2 = IFIELD( theInstr, 0, 11 );
15252 IRTemp vB = newTemp( Ity_V128 );
15253 IRTemp vT = newTemp( Ity_V128 );
15255 assign( vB, getVReg ( vB_addr ) );
15257 if ( ( opc1 != 0x4 ) && ( opc2 != 0x602 ) ) {
15258 vex_printf("dis_av_extend_sign(ppc)(instr)\n");
15259 return False;
15262 switch ( rA_addr ) {
15263 case 0:
15264 case 1:
15266 UInt i;
15267 IRTemp count[17];
15268 IRTemp bit_zero[16];
15269 IRTemp byte_mask[17];
15271 /* These instructions store the result in the general purpose
15272 * register in the rT_addr field.
15275 byte_mask[0] = newTemp( Ity_I32 );
15276 count[0] = newTemp( Ity_I32 );
15277 assign( count[0], mkU32( 0 ) );
15278 assign( byte_mask[0], mkU32( 0x1 ) );
15280 if ( rA_addr == 0 ) {
15281 // vclzlsbb (Vector Count Leading Zero Least-Significant Bits Byte)
15282 DIP("vclzlsbb %d,v%d\n", rT_addr, vB_addr);
15284 } else {
15285 // vctzlsbb (Vector Count Trailing Zero Least-Significant Bits Byte)
15286 DIP("vctzlsbb %d,v%d\n", rT_addr, vB_addr);
15289 for( i = 0; i < 16; i++ ) {
15290 byte_mask[i+1] = newTemp( Ity_I32 );
15291 count[i+1] = newTemp( Ity_I32 );
15292 bit_zero[i] = newTemp( Ity_I1 );
15294 /* bit_zero[i] = 0x0 until the first 1 bit is found in lsb of
15295 * byte. When the first 1 bit is found it causes the byte_mask
15296 * to change from 0x1 to 0x0. Thus the AND of the lsb and byte_mask
15297 * will be zero which will be equal to the zero byte_mask causing
15298 * the value of bit_zero[i] to be equal to 0x1 for all remaining bits.
15301 if ( rA_addr == 0 )
15302 /* leading zero bit in byte count,
15303 work bytes from left to right
15305 assign( bit_zero[i],
15306 binop( Iop_CmpEQ32,
15307 binop( Iop_And32,
15308 unop( Iop_V128to32,
15309 binop( Iop_ShrV128,
15310 mkexpr( vB ),
15311 mkU8( ( 15 - i) * 8 ) ) ),
15312 mkexpr( byte_mask[i] ) ),
15313 mkexpr( byte_mask[i] ) ) );
15315 else if ( rA_addr == 1 )
15316 /* trailing zero bit in byte count,
15317 * work bytes from right to left
15319 assign( bit_zero[i],
15320 binop( Iop_CmpEQ32,
15321 binop( Iop_And32,
15322 unop( Iop_V128to32,
15323 binop( Iop_ShrV128,
15324 mkexpr( vB ),
15325 mkU8( i * 8 ) ) ),
15326 mkexpr( byte_mask[i] ) ),
15327 mkexpr( byte_mask[i] ) ) );
15329 /* Increment count as long as bit_zero = 0 */
15330 assign( count[i+1], binop( Iop_Add32,
15331 mkexpr( count[i] ),
15332 unop( Iop_1Uto32,
15333 unop( Iop_Not1,
15334 mkexpr( bit_zero[i] ) ) ) ) );
15336 /* If comparison fails to find a zero bit, set the byte_mask to zero
15337 * for all future comparisons so there will be no more matches.
15339 assign( byte_mask[i+1],
15340 binop( Iop_And32,
15341 unop( Iop_1Uto32,
15342 unop( Iop_Not1,
15343 mkexpr( bit_zero[i] ) ) ),
15344 mkexpr( byte_mask[i] ) ) );
15346 putIReg( rT_addr, unop( Iop_32Uto64, mkexpr( count[16] ) ) );
15347 return True;
15350 case 6: // vnegw, Vector Negate Word
15351 DIP("vnegw v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15353 /* multiply each word by -1 */
15354 assign( vT, binop( Iop_Mul32x4, mkexpr( vB ), mkV128( 0xFFFF ) ) );
15355 break;
15357 case 7: // vnegd, Vector Negate Doubleword
15358 DIP("vnegd v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15360 /* multiply each word by -1 */
15361 assign( vT, binop( Iop_64HLtoV128,
15362 binop( Iop_Mul64,
15363 unop( Iop_V128HIto64,
15364 mkexpr( vB ) ),
15365 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
15366 binop( Iop_Mul64,
15367 unop( Iop_V128to64,
15368 mkexpr( vB ) ),
15369 mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) );
15370 break;
15372 case 8: // vprtybw, Vector Parity Byte Word
15373 case 9: // vprtybd, Vector Parity Byte Doubleword
15374 case 10: // vprtybq, Vector Parity Byte Quadword
15376 UInt i;
15377 IRTemp bit_in_byte[16];
15378 IRTemp word_parity[4];
15380 for( i = 0; i < 16; i++ ) {
15381 bit_in_byte[i] = newTemp( Ity_I32 );
15382 assign( bit_in_byte[i],
15383 binop( Iop_And32,
15384 unop( Iop_V128to32,
15385 binop( Iop_ShrV128,
15386 mkexpr( vB ),
15387 mkU8( ( 15 - i ) * 8 ) ) ),
15388 mkU32( 0x1 ) ) );
15391 for( i = 0; i < 4; i++ ) {
15392 word_parity[i] = newTemp(Ity_I32);
15393 assign( word_parity[i],
15394 mkXOr4_32( bit_in_byte[0 + i * 4],
15395 bit_in_byte[1 + i * 4],
15396 bit_in_byte[2 + i * 4],
15397 bit_in_byte[3 + i * 4] ) );
15400 if ( rA_addr == 8 ) {
15401 DIP("vprtybw v%d,v%d", rT_addr, vB_addr);
15403 assign( vT, mkV128from32( word_parity[0], word_parity[1],
15404 word_parity[2], word_parity[3] ) );
15406 } else if ( rA_addr == 9 ) {
15407 DIP("vprtybd v%d,v%d", rT_addr, vB_addr);
15409 assign( vT,
15410 binop( Iop_64HLtoV128,
15411 binop( Iop_32HLto64,
15412 mkU32( 0 ),
15413 binop( Iop_Xor32,
15414 mkexpr( word_parity[0] ),
15415 mkexpr( word_parity[1] ) ) ),
15416 binop( Iop_32HLto64,
15417 mkU32( 0 ),
15418 binop( Iop_Xor32,
15419 mkexpr( word_parity[2] ),
15420 mkexpr( word_parity[3] ) ) ) ) );
15422 } else if ( rA_addr == 10 ) {
15423 DIP("vprtybq v%d,v%d", rT_addr, vB_addr);
15425 assign( vT,
15426 binop( Iop_64HLtoV128,
15427 mkU64( 0 ),
15428 unop( Iop_32Uto64,
15429 mkXOr4_32( word_parity[0],
15430 word_parity[1],
15431 word_parity[2],
15432 word_parity[3] ) ) ) );
15435 break;
15437 case 16: // vextsb2w, Vector Extend Sign Byte to Word
15438 DIP("vextsb2w v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15440 /* Iop_MullEven8Sx16 does a signed widening multiplication of byte to
15441 * two byte sign extended result. Then do a two byte to four byte sign
15442 * extended multiply. Note contents of upper three bytes in word are
15443 * "over written". So just take source and multiply by 1.
15445 assign( vT, binop( Iop_MullEven16Sx8,
15446 binop( Iop_64HLtoV128,
15447 mkU64( 0x0000000100000001 ),
15448 mkU64( 0x0000000100000001 ) ),
15449 binop( Iop_MullEven8Sx16,
15450 mkexpr( vB ),
15451 binop( Iop_64HLtoV128,
15452 mkU64( 0x0001000100010001 ),
15453 mkU64( 0x0001000100010001 ) ) ) ) );
15454 break;
15456 case 17: // vextsh2w, Vector Extend Sign Halfword to Word
15457 DIP("vextsh2w v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15459 /* Iop_MullEven16Sx8 does a signed widening multiply of four byte
15460 * 8 bytes. Note contents of upper two bytes in word are
15461 * "over written". So just take source and multiply by 1.
15463 assign( vT, binop( Iop_MullEven16Sx8,
15464 binop( Iop_64HLtoV128,
15465 mkU64( 0x0000000100000001 ),
15466 mkU64( 0x0000000100000001 ) ),
15467 mkexpr( vB ) ) );
15469 break;
15471 case 24: // vextsb2d, Vector Extend Sign Byte to Doubleword
15472 DIP("vextsb2d v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15474 /* Iop_MullEven8Sx16 does a signed widening multiplication of byte to
15475 * two byte sign extended result. Then do a two byte to four byte sign
15476 * extended multiply. Then do four byte to eight byte multiply.
15478 assign( vT, binop( Iop_MullEven32Sx4,
15479 binop( Iop_64HLtoV128,
15480 mkU64( 0x0000000000000001 ),
15481 mkU64( 0x0000000000000001 ) ),
15482 binop( Iop_MullEven16Sx8,
15483 binop( Iop_64HLtoV128,
15484 mkU64( 0x0000000100000001 ),
15485 mkU64( 0x0000000100000001 ) ),
15486 binop( Iop_MullEven8Sx16,
15487 binop( Iop_64HLtoV128,
15488 mkU64( 0x0001000100010001 ),
15489 mkU64( 0x0001000100010001 ) ),
15490 mkexpr( vB ) ) ) ) );
15491 break;
15493 case 25: // vextsh2d, Vector Extend Sign Halfword to Doubleword
15494 DIP("vextsh2d v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15496 assign( vT, binop( Iop_MullEven32Sx4,
15497 binop( Iop_64HLtoV128,
15498 mkU64( 0x0000000000000001 ),
15499 mkU64( 0x0000000000000001 ) ),
15500 binop( Iop_MullEven16Sx8,
15501 binop( Iop_64HLtoV128,
15502 mkU64( 0x0000000100000001 ),
15503 mkU64( 0x0000000100000001 ) ),
15504 mkexpr( vB ) ) ) );
15505 break;
15507 case 26: // vextsw2d, Vector Extend Sign Word to Doubleword
15508 DIP("vextsw2d v%d,%d,v%d", rT_addr, rA_addr, vB_addr);
15510 assign( vT, binop( Iop_MullEven32Sx4,
15511 binop( Iop_64HLtoV128,
15512 mkU64( 0x0000000000000001 ),
15513 mkU64( 0x0000000000000001 ) ),
15514 mkexpr( vB ) ) );
15515 break;
15517 case 28: // vctzb, Vector Count Trailing Zeros Byte
15519 DIP("vctzb v%d,v%d", rT_addr, vB_addr);
15521 /* This instruction is only available in the ISA 3.0 */
15522 if ( !mode64 || !allow_isa_3_0 ) {
15523 vex_printf("\n vctzb instruction not supported on non ISA 3.0 platform\n\n");
15524 return False;
15526 assign( vT, unop( Iop_Ctz8x16, mkexpr( vB ) ) );
15528 break;
15530 case 29: // vctzh, Vector Count Trailing Zeros Halfword
15532 DIP("vctzh v%d,v%d", rT_addr, vB_addr);
15534 /* This instruction is only available in the ISA 3.0 */
15535 if ( !mode64 || !allow_isa_3_0 ) {
15536 vex_printf("\n vctzh instruction not supported on non ISA 3.0 platform\n\n");
15537 return False;
15539 assign( vT, unop( Iop_Ctz16x8, mkexpr( vB ) ) );
15541 break;
15543 case 30: // vctzw, Vector Count Trailing Zeros Word
15545 DIP("vctzw v%d,v%d", rT_addr, vB_addr);
15547 /* This instruction is only available in the ISA 3.0 */
15548 if ( !mode64 || !allow_isa_3_0 ) {
15549 vex_printf("\n vctzw instruction not supported on non ISA 3.0 platform\n\n");
15550 return False;
15552 assign( vT, unop( Iop_Ctz32x4, mkexpr( vB ) ) );
15554 break;
15556 case 31: // vctzd, Vector Count Trailing Zeros Double word
15558 DIP("vctzd v%d,v%d", rT_addr, vB_addr);
15560 /* This instruction is only available in the ISA 3.0 */
15561 if ( !mode64 || !allow_isa_3_0 ) {
15562 vex_printf("\n vctzd instruction not supported on non ISA 3.0 platform\n\n");
15563 return False;
15565 assign( vT, unop( Iop_Ctz64x2, mkexpr( vB ) ) );
15567 break;
15569 default:
15570 vex_printf("dis_av_extend_sign(ppc)(Unsupported vector extend sign instruction)\n");
15571 return False;
15574 putVReg( rT_addr, mkexpr( vT ) );
15575 return True;
15579 Vector Rotate Instructions
15581 static Bool dis_av_rotate ( UInt theInstr )
15583 /* VX-Form */
15585 UChar opc1 = ifieldOPC( theInstr );
15586 UChar vT_addr = ifieldRegDS( theInstr );
15587 UChar vA_addr = ifieldRegA( theInstr );
15588 UChar vB_addr = ifieldRegB( theInstr );
15589 UInt opc2 = IFIELD( theInstr, 0, 11 );
15591 IRTemp vA = newTemp( Ity_V128 );
15592 IRTemp vB = newTemp( Ity_V128 );
15593 IRTemp src3 = newTemp( Ity_V128 );
15594 IRTemp vT = newTemp( Ity_V128 );
15595 IRTemp field_mask = newTemp( Ity_V128 );
15596 IRTemp mask128 = newTemp( Ity_V128 );
15597 IRTemp vA_word[4];
15598 IRTemp left_bits[4];
15599 IRTemp right_bits[4];
15600 IRTemp shift[4];
15601 IRTemp mask[4];
15602 IRTemp tmp128[4];
15603 UInt i;
15604 UInt num_words;
15605 UInt word_size;
15606 unsigned long long word_mask;
15608 if ( opc1 != 0x4 ) {
15609 vex_printf("dis_av_rotate(ppc)(instr)\n");
15610 return False;
15613 assign( vA, getVReg( vA_addr ) );
15614 assign( vB, getVReg( vB_addr ) );
15616 switch (opc2) {
15617 case 0x85: // vrlwmi, Vector Rotate Left Word then Mask Insert
15618 case 0x185: // vrlwnm, Vector Rotate Left Word then AND with Mask
15619 num_words = 4;
15620 word_size = 32;
15621 assign( field_mask, binop( Iop_64HLtoV128,
15622 mkU64( 0 ),
15623 mkU64( 0x1F ) ) );
15624 word_mask = 0xFFFFFFFF;
15625 break;
15627 case 0x0C5: // vrldmi, Vector Rotate Left Doubleword then Mask Insert
15628 case 0x1C5: // vrldnm, Vector Rotate Left Doubleword then AND with Mask
15629 num_words = 2;
15630 word_size = 64;
15631 assign( field_mask, binop( Iop_64HLtoV128,
15632 mkU64( 0 ),
15633 mkU64( 0x3F ) ) );
15634 word_mask = 0xFFFFFFFFFFFFFFFFULL;
15635 break;
15636 default:
15637 vex_printf("dis_av_rotate(ppc)(opc2)\n");
15638 return False;
15641 for( i = 0; i < num_words; i++ ) {
15642 left_bits[i] = newTemp( Ity_I8 );
15643 right_bits[i] = newTemp( Ity_I8 );
15644 shift[i] = newTemp( Ity_I8 );
15645 mask[i] = newTemp( Ity_V128 );
15646 tmp128[i] = newTemp( Ity_V128 );
15647 vA_word[i] = newTemp( Ity_V128 );
15649 assign( shift[i],
15650 unop( Iop_64to8,
15651 unop( Iop_V128to64,
15652 binop( Iop_AndV128,
15653 binop( Iop_ShrV128,
15654 mkexpr( vB ),
15655 mkU8( (num_words - 1 - i )
15656 * word_size ) ),
15657 mkexpr( field_mask ) ) ) ) );
15659 /* left_bits = 63 - mb. Tells us how many bits to the left
15660 * of mb to clear. Note for a word left_bits = 32+mb, for a double
15661 * word left_bits = mb
15663 assign( left_bits[i],
15664 unop( Iop_64to8,
15665 binop( Iop_Add64,
15666 mkU64( 64 - word_size ),
15667 unop( Iop_V128to64,
15668 binop( Iop_AndV128,
15669 binop( Iop_ShrV128,
15670 mkexpr( vB ),
15671 mkU8( ( num_words - 1 - i )
15672 * word_size + 16 ) ),
15673 mkexpr( field_mask ) ) ) ) ) );
15674 /* right_bits = 63 - me. Tells us how many bits to the right
15675 * of me to clear. Note for a word, left_bits = me+32, for a double
15676 * word left_bits = me
15678 assign( right_bits[i],
15679 unop( Iop_64to8,
15680 binop( Iop_Sub64,
15681 mkU64( word_size - 1 ),
15682 unop( Iop_V128to64,
15683 binop( Iop_AndV128,
15684 binop( Iop_ShrV128,
15685 mkexpr( vB ),
15686 mkU8( ( num_words - 1 - i )
15687 * word_size + 8 ) ),
15688 mkexpr( field_mask ) ) ) ) ) );
15690 /* create mask for 32-bit word or 64-bit word */
15691 assign( mask[i],
15692 binop( Iop_64HLtoV128,
15693 mkU64( 0 ),
15694 binop( Iop_Shl64,
15695 binop( Iop_Shr64,
15696 binop( Iop_Shr64,
15697 binop( Iop_Shl64,
15698 mkU64( 0xFFFFFFFFFFFFFFFF ),
15699 mkexpr( left_bits[i] ) ),
15700 mkexpr( left_bits[i] ) ),
15701 mkexpr( right_bits[i] ) ),
15702 mkexpr( right_bits[i] ) ) ) );
15704 /* Need to rotate vA using a left and right shift of vA OR'd together
15705 * then ANDed with the mask.
15707 assign( vA_word[i], binop( Iop_AndV128,
15708 mkexpr( vA ),
15709 binop( Iop_ShlV128,
15710 binop( Iop_64HLtoV128,
15711 mkU64( 0 ),
15712 mkU64( word_mask ) ),
15713 mkU8( ( num_words - 1 - i )
15714 * word_size ) ) ) );
15715 assign( tmp128[i],
15716 binop( Iop_AndV128,
15717 binop( Iop_ShlV128,
15718 mkexpr( mask[i] ),
15719 mkU8( ( num_words - 1 - i) * word_size ) ),
15720 binop( Iop_OrV128,
15721 binop( Iop_ShlV128,
15722 mkexpr( vA_word[i] ),
15723 mkexpr( shift[i] ) ),
15724 binop( Iop_ShrV128,
15725 mkexpr( vA_word[i] ),
15726 unop( Iop_32to8,
15727 binop(Iop_Sub32,
15728 mkU32( word_size ),
15729 unop( Iop_8Uto32,
15730 mkexpr( shift[i] ) ) )
15731 ) ) ) ) );
15734 switch (opc2) {
15735 case 0x85: // vrlwmi, Vector Rotate Left Word then Mask Insert
15736 DIP("vrlwmi %d,%d,v%d", vT_addr, vA_addr, vB_addr);
15738 assign( src3, getVReg( vT_addr ) );
15739 assign( mask128, unop( Iop_NotV128,
15740 mkOr4_V128_expr( binop( Iop_ShlV128,
15741 mkexpr( mask[0] ),
15742 mkU8( 96 ) ),
15743 binop( Iop_ShlV128,
15744 mkexpr( mask[1] ),
15745 mkU8( 64 ) ),
15746 binop( Iop_ShlV128,
15747 mkexpr( mask[2] ),
15748 mkU8( 32 ) ),
15749 mkexpr( mask[3] ) ) ) );
15750 assign( vT, binop( Iop_OrV128,
15751 binop( Iop_AndV128,
15752 mkexpr( src3 ),
15753 mkexpr( mask128 ) ),
15754 mkOr4_V128( tmp128[0], tmp128[1],
15755 tmp128[2], tmp128[3] ) ) );
15756 break;
15758 case 0xC5: // vrldmi, Vector Rotate Left Double word then Mask Insert
15759 DIP("vrldmi %d,%d,v%d", vT_addr, vA_addr, vB_addr);
15761 assign( src3, getVReg( vT_addr ) );
15762 assign( mask128, unop( Iop_NotV128,
15763 binop( Iop_OrV128,
15764 binop( Iop_ShlV128,
15765 mkexpr( mask[0] ),
15766 mkU8( 64 ) ),
15767 mkexpr( mask[1] ) ) ) );
15769 assign( vT, binop( Iop_OrV128,
15770 binop( Iop_AndV128,
15771 mkexpr( src3 ),
15772 mkexpr( mask128 ) ),
15773 binop( Iop_OrV128,
15774 mkexpr( tmp128[0] ),
15775 mkexpr( tmp128[1] ) ) ) );
15776 break;
15778 case 0x185: // vrlwnm, Vector Rotate Left Word then AND with Mask
15779 DIP("vrlwnm %d,%d,v%d", vT_addr, vA_addr, vB_addr);
15780 assign( vT, mkOr4_V128( tmp128[0], tmp128[1], tmp128[2], tmp128[3] ) );
15781 break;
15783 case 0x1C5: // vrldnm, Vector Rotate Left Doubleword then AND with Mask
15784 DIP("vrldnm %d,%d,v%d", vT_addr, vA_addr, vB_addr);
15785 assign( vT, binop( Iop_OrV128,
15786 mkexpr( tmp128[0] ),
15787 mkexpr( tmp128[1] ) ) );
15788 break;
15791 putVReg( vT_addr, mkexpr( vT ) );
15792 return True;
15796 AltiVec Vector Extract Element Instructions
15798 static Bool dis_av_extract_element ( UInt theInstr )
15800 /* VX-Form,
15801 * sorta destination and first source are GPR not vector registers
15804 UChar opc1 = ifieldOPC( theInstr );
15805 UChar rT_addr = ifieldRegDS( theInstr );
15806 UChar rA_addr = ifieldRegA( theInstr );
15807 UChar vB_addr = ifieldRegB( theInstr );
15808 UInt opc2 = IFIELD( theInstr, 0, 11 );
15810 IRTemp vB = newTemp( Ity_V128 );
15811 IRTemp rA = newTemp( Ity_I64 );
15812 IRTemp rT = newTemp( Ity_I64 );
15814 assign( vB, getVReg( vB_addr ) );
15815 assign( rA, getIReg( rA_addr ) );
15817 if ( opc1 != 0x4 ) {
15818 vex_printf("dis_av_extract_element(ppc)(instr)\n");
15819 return False;
15822 switch ( opc2 ) {
15823 case 0x60D: // vextublx, vector extract unsigned Byte Left-indexed
15824 DIP("vextublx %d,%d,v%d", rT_addr, rA_addr, vB_addr);
15826 assign( rT, extract_field_from_vector( vB,
15827 binop( Iop_Sub64,
15828 mkU64( 15 ),
15829 mkexpr( rA ) ),
15830 0xFF ) );
15832 break;
15834 case 0x64D: // vextuhlx, vector extract unsigned Halfword Left-indexed
15835 DIP("vextuhlx %d,%d,v%d", rT_addr, rA_addr, vB_addr);
15837 assign( rT, extract_field_from_vector( vB,
15838 binop( Iop_Sub64,
15839 mkU64( 14 ),
15840 mkexpr( rA ) ),
15841 0xFFFF ) );
15842 break;
15844 case 0x68D: // vextuwlx, vector extract unsigned Word Left-indexed
15845 DIP("vextuwlx %d,%d,v%d", rT_addr, rA_addr, vB_addr);
15847 assign( rT, extract_field_from_vector( vB,
15848 binop( Iop_Sub64,
15849 mkU64( 12 ),
15850 mkexpr( rA ) ),
15851 0xFFFFFFFF ) );
15852 break;
15854 case 0x70D: // vextubrx, vector extract unsigned Byte Right-indexed
15855 DIP("vextubrx %d,%d,v%d", rT_addr, rA_addr, vB_addr);
15857 assign( rT, extract_field_from_vector( vB, mkexpr( rA ), 0xFF ) );
15858 break;
15860 case 0x74D: // vextuhrx, vector extract unsigned Halfword Right-indexed
15861 DIP("vextuhrx %d,%d,v%d", rT_addr, rA_addr, vB_addr);
15863 assign( rT, extract_field_from_vector( vB, mkexpr( rA ), 0xFFFF ) );
15864 break;
15866 case 0x78D: // vextuwrx, vector extract unsigned Word Right-indexed
15867 DIP("vextuwrx %d,%d,v%d", rT_addr, rA_addr, vB_addr);
15869 assign( rT, extract_field_from_vector( vB, mkexpr( rA ), 0xFFFFFFFF ) );
15870 break;
15872 default:
15873 vex_printf("dis_av_extract_element(ppc)(opc2)\n");
15874 return False;
15876 putIReg( rT_addr, mkexpr( rT ) );
15877 return True;
15881 * VSX scalar and vector convert instructions
15883 static Bool
15884 dis_vx_conv ( UInt theInstr, UInt opc2 )
15886 /* XX2-Form */
15887 UChar opc1 = ifieldOPC( theInstr );
15888 UChar XT = ifieldRegXT( theInstr );
15889 UChar XB = ifieldRegXB( theInstr );
15890 IRTemp xB, xB2;
15891 IRTemp b3, b2, b1, b0;
15892 xB = xB2 = IRTemp_INVALID;
15894 if (opc1 != 0x3C) {
15895 vex_printf( "dis_vx_conv(ppc)(instr)\n" );
15896 return False;
15899 /* Create and assign temps only as needed for the given instruction. */
15900 switch (opc2) {
15901 // scalar double-precision floating point argument
15902 case 0x2B0: case 0x0b0: case 0x290: case 0x212: case 0x216: case 0x090:
15903 xB = newTemp(Ity_F64);
15904 assign( xB,
15905 unop( Iop_ReinterpI64asF64,
15906 unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
15907 break;
15908 // vector double-precision floating point arguments
15909 case 0x1b0: case 0x312: case 0x390: case 0x190: case 0x3B0:
15911 xB = newTemp(Ity_F64);
15912 xB2 = newTemp(Ity_F64);
15913 assign( xB,
15914 unop( Iop_ReinterpI64asF64,
15915 unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
15916 assign( xB2,
15917 unop( Iop_ReinterpI64asF64,
15918 unop( Iop_V128to64, getVSReg( XB ) ) ) );
15919 break;
15920 // vector single precision or [un]signed integer word arguments
15921 case 0x130: case 0x392: case 0x330: case 0x310: case 0x110:
15922 case 0x1f0: case 0x1d0:
15923 b3 = b2 = b1 = b0 = IRTemp_INVALID;
15924 breakV128to4x32(getVSReg(XB), &b3, &b2, &b1, &b0);
15925 break;
15926 // vector [un]signed integer doubleword argument
15927 case 0x3f0: case 0x370: case 0x3d0: case 0x350:
15928 xB = newTemp(Ity_I64);
15929 assign( xB, unop( Iop_V128HIto64, getVSReg( XB ) ) );
15930 xB2 = newTemp(Ity_I64);
15931 assign( xB2, unop( Iop_V128to64, getVSReg( XB ) ) );
15932 break;
15933 // scalar [un]signed integer doubleword argument
15934 case 0x250: case 0x270: case 0x2D0: case 0x2F0:
15935 xB = newTemp(Ity_I64);
15936 assign( xB, unop( Iop_V128HIto64, getVSReg( XB ) ) );
15937 break;
15938 // scalar single precision argument
15939 case 0x292: // xscvspdp
15940 xB = newTemp(Ity_I32);
15942 assign( xB, handle_SNaN_to_QNaN_32(unop( Iop_64HIto32,
15943 unop( Iop_V128HIto64,
15944 getVSReg( XB ) ) ) ) );
15945 break;
15946 case 0x296: // xscvspdpn (non signaling version of xscvpdp)
15947 xB = newTemp(Ity_I32);
15948 assign( xB,
15949 unop( Iop_64HIto32, unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
15950 break;
15952 /* Certain instructions have their complete implementation in the main switch statement
15953 * that follows this one; thus we have a "do nothing" case for those instructions here.
15955 case 0x170: case 0x150:
15956 break; // do nothing
15958 default:
15959 vex_printf( "dis_vx_conv(ppc)(opc2)\n" );
15960 return False;
15964 switch (opc2) {
15965 case 0x2B0:
15966 // xscvdpsxds (VSX Scalar truncate Double-Precision to integer and Convert
15967 // to Signed Integer Doubleword format with Saturate)
15968 DIP("xscvdpsxds v%u,v%u\n", XT, XB);
15969 putVSReg( XT,
15970 binop( Iop_64HLtoV128, binop( Iop_F64toI64S,
15971 mkU32( Irrm_ZERO ),
15972 mkexpr( xB ) ), mkU64( 0 ) ) );
15973 break;
15974 case 0x0b0: // xscvdpsxws (VSX Scalar truncate Double-Precision to integer and
15975 // Convert to Signed Integer Word format with Saturate)
15976 DIP("xscvdpsxws v%u,v%u\n", XT, XB);
15977 putVSReg( XT,
15978 binop( Iop_64HLtoV128,
15979 unop( Iop_32Sto64,
15980 binop( Iop_F64toI32S,
15981 mkU32( Irrm_ZERO ),
15982 mkexpr( xB ) ) ),
15983 mkU64( 0ULL ) ) );
15984 break;
15985 case 0x290: // xscvdpuxds (VSX Scalar truncate Double-Precision integer and Convert
15986 // to Unsigned Integer Doubleword format with Saturate)
15987 DIP("xscvdpuxds v%u,v%u\n", XT, XB);
15988 putVSReg( XT,
15989 binop( Iop_64HLtoV128,
15990 binop( Iop_F64toI64U,
15991 mkU32( Irrm_ZERO ),
15992 mkexpr( xB ) ),
15993 mkU64( 0ULL ) ) );
15994 break;
15995 case 0x270:
15996 // xscvsxdsp (VSX Scalar Convert and round Signed Integer Doubleword
15997 // to Single-Precision format)
15998 DIP("xscvsxdsp v%u,v%u\n", XT, XB);
15999 putVSReg( XT,
16000 binop( Iop_64HLtoV128,
16001 unop( Iop_ReinterpF64asI64,
16002 binop( Iop_RoundF64toF32,
16003 get_IR_roundingmode(),
16004 binop( Iop_I64StoF64,
16005 get_IR_roundingmode(),
16006 mkexpr( xB ) ) ) ),
16007 mkU64( 0 ) ) );
16008 break;
16009 case 0x2F0:
16010 // xscvsxddp (VSX Scalar Convert and round Signed Integer Doubleword to
16011 // Double-Precision format)
16012 DIP("xscvsxddp v%u,v%u\n", XT, XB);
16013 putVSReg( XT,
16014 binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
16015 binop( Iop_I64StoF64, get_IR_roundingmode(),
16016 mkexpr( xB ) ) ),
16017 mkU64( 0 ) ) );
16018 break;
16019 case 0x250:
16020 // xscvuxdsp (VSX Scalar Convert and round Unsigned Integer
16021 // Doubleword to Singel-Precision format)
16022 DIP("xscvuxdsp v%u,v%u\n", XT, XB);
16023 putVSReg( XT,
16024 binop( Iop_64HLtoV128,
16025 unop( Iop_ReinterpF64asI64,
16026 binop( Iop_RoundF64toF32,
16027 get_IR_roundingmode(),
16028 binop( Iop_I64UtoF64,
16029 get_IR_roundingmode(),
16030 mkexpr( xB ) ) ) ),
16031 mkU64( 0 ) ) );
16032 break;
16033 case 0x2D0:
16034 // xscvuxddp (VSX Scalar Convert and round Unsigned Integer Doubleword to
16035 // Double-Precision format)
16036 DIP("xscvuxddp v%u,v%u\n", XT, XB);
16037 putVSReg( XT,
16038 binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
16039 binop( Iop_I64UtoF64, get_IR_roundingmode(),
16040 mkexpr( xB ) ) ),
16041 mkU64( 0 ) ) );
16042 break;
16043 case 0x1b0: // xvcvdpsxws (VSX Vector truncate Double-Precision to integer and Convert
16044 // to Signed Integer Word format with Saturate)
16046 IRTemp hiResult_32 = newTemp(Ity_I32);
16047 IRTemp loResult_32 = newTemp(Ity_I32);
16048 IRExpr* rmZero = mkU32(Irrm_ZERO);
16050 DIP("xvcvdpsxws v%u,v%u\n", XT, XB);
16051 assign(hiResult_32, binop(Iop_F64toI32S, rmZero, mkexpr(xB)));
16052 assign(loResult_32, binop(Iop_F64toI32S, rmZero, mkexpr(xB2)));
16053 putVSReg( XT,
16054 binop( Iop_64HLtoV128,
16055 unop( Iop_32Sto64, mkexpr( hiResult_32 ) ),
16056 unop( Iop_32Sto64, mkexpr( loResult_32 ) ) ) );
16057 break;
16059 case 0x130: case 0x110: // xvcvspsxws, xvcvspuxws
16060 // (VSX Vector truncate Single-Precision to integer and
16061 // Convert to [Un]signed Integer Word format with Saturate)
16063 IRExpr * b0_result, * b1_result, * b2_result, * b3_result;
16064 IRTemp tempResult = newTemp(Ity_V128);
16065 IRTemp res0 = newTemp(Ity_I32);
16066 IRTemp res1 = newTemp(Ity_I32);
16067 IRTemp res2 = newTemp(Ity_I32);
16068 IRTemp res3 = newTemp(Ity_I32);
16069 IRTemp hi64 = newTemp(Ity_I64);
16070 IRTemp lo64 = newTemp(Ity_I64);
16071 Bool un_signed = (opc2 == 0x110);
16072 IROp op = un_signed ? Iop_QFtoI32Ux4_RZ : Iop_QFtoI32Sx4_RZ;
16074 DIP("xvcvsp%sxws v%u,v%u\n", un_signed ? "u" : "s", XT, XB);
16075 /* The xvcvsp{s|u}xws instruction is similar to vct{s|u}xs, except if src is a NaN,
16076 * then result is set to 0x80000000. */
16077 assign(tempResult, unop(op, getVSReg(XB)));
16078 assign( hi64, unop(Iop_V128HIto64, mkexpr(tempResult)) );
16079 assign( lo64, unop(Iop_V128to64, mkexpr(tempResult)) );
16080 assign( res3, unop(Iop_64HIto32, mkexpr(hi64)) );
16081 assign( res2, unop(Iop_64to32, mkexpr(hi64)) );
16082 assign( res1, unop(Iop_64HIto32, mkexpr(lo64)) );
16083 assign( res0, unop(Iop_64to32, mkexpr(lo64)) );
16085 b3_result = IRExpr_ITE(is_NaN(Ity_I32, b3),
16086 // then: result is 0x{8|0}80000000
16087 mkU32(un_signed ? 0x00000000 : 0x80000000),
16088 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
16089 mkexpr(res3));
16090 b2_result = IRExpr_ITE(is_NaN(Ity_I32, b2),
16091 // then: result is 0x{8|0}80000000
16092 mkU32(un_signed ? 0x00000000 : 0x80000000),
16093 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
16094 mkexpr(res2));
16095 b1_result = IRExpr_ITE(is_NaN(Ity_I32, b1),
16096 // then: result is 0x{8|0}80000000
16097 mkU32(un_signed ? 0x00000000 : 0x80000000),
16098 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
16099 mkexpr(res1));
16100 b0_result = IRExpr_ITE(is_NaN(Ity_I32, b0),
16101 // then: result is 0x{8|0}80000000
16102 mkU32(un_signed ? 0x00000000 : 0x80000000),
16103 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
16104 mkexpr(res0));
16106 putVSReg( XT,
16107 binop( Iop_64HLtoV128,
16108 binop( Iop_32HLto64, b3_result, b2_result ),
16109 binop( Iop_32HLto64, b1_result, b0_result ) ) );
16110 break;
16112 case 0x212: // xscvdpsp (VSX Scalar round Double-Precision to single-precision and
16113 // Convert to Single-Precision format
16114 DIP("xscvdpsp v%u,v%u\n", XT, XB);
16115 putVSReg( XT,
16116 binop( Iop_64HLtoV128,
16117 binop( Iop_32HLto64,
16118 unop( Iop_ReinterpF32asI32,
16119 unop( Iop_TruncF64asF32,
16120 binop( Iop_RoundF64toF32,
16121 get_IR_roundingmode(),
16122 mkexpr( xB ) ) ) ),
16123 mkU32( 0 ) ),
16124 mkU64( 0ULL ) ) );
16125 break;
16126 case 0x216: /* xscvdpspn (VSX Scalar convert scalar Single-Precision to
16127 vector Single-Precision non-signalling */
16128 DIP("xscvdpspn v%u,v%u\n", XT, XB);
16129 putVSReg( XT,
16130 binop( Iop_64HLtoV128,
16131 binop( Iop_32HLto64,
16132 unop( Iop_ReinterpF32asI32,
16133 unop( Iop_TruncF64asF32,
16134 mkexpr( xB ) ) ),
16135 mkU32( 0 ) ),
16136 mkU64( 0ULL ) ) );
16137 break;
16138 case 0x090: // xscvdpuxws (VSX Scalar truncate Double-Precision to integer
16139 // and Convert to Unsigned Integer Word format with Saturate)
16140 DIP("xscvdpuxws v%u,v%u\n", XT, XB);
16141 putVSReg( XT,
16142 binop( Iop_64HLtoV128,
16143 binop( Iop_32HLto64,
16144 mkU32( 0 ),
16145 binop( Iop_F64toI32U,
16146 mkU32( Irrm_ZERO ),
16147 mkexpr( xB ) ) ),
16148 mkU64( 0ULL ) ) );
16149 break;
16150 case 0x292: // xscvspdp (VSX Scalar Convert Single-Precision to Double-Precision format, signaling)
16151 DIP("xscvspdp v%u,v%u\n", XT, XB);
16152 putVSReg( XT,
16153 binop( Iop_64HLtoV128,
16154 unop( Iop_ReinterpF64asI64,
16155 unop( Iop_F32toF64,
16156 unop( Iop_ReinterpI32asF32, mkexpr( xB ) ) ) ),
16157 mkU64( 0ULL ) ) );
16158 break;
16159 case 0x296: // xscvspdpn (VSX Scalar Convert Single-Precision to Double-Precision format Non signaling)
16160 DIP("xscvspdpn v%u,v%u\n", XT, XB);
16161 putVSReg( XT,
16162 binop( Iop_64HLtoV128,
16163 unop( Iop_ReinterpF64asI64,
16164 unop( Iop_F32toF64,
16165 unop( Iop_ReinterpI32asF32, mkexpr( xB ) ) ) ),
16166 mkU64( 0ULL ) ) );
16167 break;
16168 case 0x312: // xvcvdpsp (VSX Vector round Double-Precision to single-precision
16169 // and Convert to Single-Precision format)
16170 DIP("xvcvdpsp v%u,v%u\n", XT, XB);
16171 putVSReg( XT,
16172 binop( Iop_64HLtoV128,
16173 binop( Iop_32HLto64,
16174 unop( Iop_ReinterpF32asI32,
16175 unop( Iop_TruncF64asF32,
16176 binop( Iop_RoundF64toF32,
16177 get_IR_roundingmode(),
16178 mkexpr( xB ) ) ) ),
16179 mkU32( 0 ) ),
16180 binop( Iop_32HLto64,
16181 unop( Iop_ReinterpF32asI32,
16182 unop( Iop_TruncF64asF32,
16183 binop( Iop_RoundF64toF32,
16184 get_IR_roundingmode(),
16185 mkexpr( xB2 ) ) ) ),
16186 mkU32( 0 ) ) ) );
16187 break;
16188 case 0x390: // xvcvdpuxds (VSX Vector truncate Double-Precision to integer
16189 // and Convert to Unsigned Integer Doubleword format
16190 // with Saturate)
16191 DIP("xvcvdpuxds v%u,v%u\n", XT, XB);
16192 putVSReg( XT,
16193 binop( Iop_64HLtoV128,
16194 binop( Iop_F64toI64U, mkU32( Irrm_ZERO ), mkexpr( xB ) ),
16195 binop( Iop_F64toI64U, mkU32( Irrm_ZERO ), mkexpr( xB2 ) ) ) );
16196 break;
16197 case 0x190: // xvcvdpuxws (VSX Vector truncate Double-Precision to integer and
16198 // Convert to Unsigned Integer Word format with Saturate)
16199 DIP("xvcvdpuxws v%u,v%u\n", XT, XB);
16200 putVSReg( XT,
16201 binop( Iop_64HLtoV128,
16202 binop( Iop_32HLto64,
16203 binop( Iop_F64toI32U,
16204 mkU32( Irrm_ZERO ),
16205 mkexpr( xB ) ),
16206 mkU32( 0 ) ),
16207 binop( Iop_32HLto64,
16208 binop( Iop_F64toI32U,
16209 mkU32( Irrm_ZERO ),
16210 mkexpr( xB2 ) ),
16211 mkU32( 0 ) ) ) );
16212 break;
16213 case 0x392: // xvcvspdp (VSX Vector Convert Single-Precision to Double-Precision format)
16214 DIP("xvcvspdp v%u,v%u\n", XT, XB);
16215 putVSReg( XT,
16216 binop( Iop_64HLtoV128,
16217 unop( Iop_ReinterpF64asI64,
16218 unop( Iop_F32toF64,
16219 unop( Iop_ReinterpI32asF32,
16220 handle_SNaN_to_QNaN_32( mkexpr( b3 ) ) ) ) ),
16221 unop( Iop_ReinterpF64asI64,
16222 unop( Iop_F32toF64,
16223 unop( Iop_ReinterpI32asF32,
16224 handle_SNaN_to_QNaN_32( mkexpr( b1 ) ) ) ) ) ) );
16225 break;
16226 case 0x330: // xvcvspsxds (VSX Vector truncate Single-Precision to integer and
16227 // Convert to Signed Integer Doubleword format with Saturate)
16228 DIP("xvcvspsxds v%u,v%u\n", XT, XB);
16229 putVSReg( XT,
16230 binop( Iop_64HLtoV128,
16231 binop( Iop_F64toI64S,
16232 mkU32( Irrm_ZERO ),
16233 unop( Iop_F32toF64,
16234 unop( Iop_ReinterpI32asF32, mkexpr( b3 ) ) ) ),
16235 binop( Iop_F64toI64S,
16236 mkU32( Irrm_ZERO ),
16237 unop( Iop_F32toF64,
16238 unop( Iop_ReinterpI32asF32, mkexpr( b1 ) ) ) ) ) );
16239 break;
16240 case 0x310: // xvcvspuxds (VSX Vector truncate Single-Precision to integer and
16241 // Convert to Unsigned Integer Doubleword format with Saturate)
16242 DIP("xvcvspuxds v%u,v%u\n", XT, XB);
16243 putVSReg( XT,
16244 binop( Iop_64HLtoV128,
16245 binop( Iop_F64toI64U,
16246 mkU32( Irrm_ZERO ),
16247 unop( Iop_F32toF64,
16248 unop( Iop_ReinterpI32asF32, mkexpr( b3 ) ) ) ),
16249 binop( Iop_F64toI64U,
16250 mkU32( Irrm_ZERO ),
16251 unop( Iop_F32toF64,
16252 unop( Iop_ReinterpI32asF32, mkexpr( b1 ) ) ) ) ) );
16253 break;
16254 case 0x3B0: // xvcvdpsxds (VSX Vector truncate Double-Precision to integer and
16255 // Convert to Signed Integer Doubleword format with Saturate)
16256 DIP("xvcvdpsxds v%u,v%u\n", XT, XB);
16257 putVSReg( XT,
16258 binop( Iop_64HLtoV128,
16259 binop( Iop_F64toI64S, mkU32( Irrm_ZERO ), mkexpr( xB ) ),
16260 binop( Iop_F64toI64S, mkU32( Irrm_ZERO ), mkexpr( xB2 ) ) ) );
16261 break;
16262 case 0x3f0: // xvcvsxddp (VSX Vector Convert and round Signed Integer Doubleword
16263 // to Double-Precision format)
16264 DIP("xvcvsxddp v%u,v%u\n", XT, XB);
16265 putVSReg( XT,
16266 binop( Iop_64HLtoV128,
16267 unop( Iop_ReinterpF64asI64,
16268 binop( Iop_I64StoF64,
16269 get_IR_roundingmode(),
16270 mkexpr( xB ) ) ),
16271 unop( Iop_ReinterpF64asI64,
16272 binop( Iop_I64StoF64,
16273 get_IR_roundingmode(),
16274 mkexpr( xB2 ) ) ) ) );
16275 break;
16276 case 0x3d0: // xvcvuxddp (VSX Vector Convert and round Unsigned Integer Doubleword
16277 // to Double-Precision format)
16278 DIP("xvcvuxddp v%u,v%u\n", XT, XB);
16279 putVSReg( XT,
16280 binop( Iop_64HLtoV128,
16281 unop( Iop_ReinterpF64asI64,
16282 binop( Iop_I64UtoF64,
16283 get_IR_roundingmode(),
16284 mkexpr( xB ) ) ),
16285 unop( Iop_ReinterpF64asI64,
16286 binop( Iop_I64UtoF64,
16287 get_IR_roundingmode(),
16288 mkexpr( xB2 ) ) ) ) );
16290 break;
16291 case 0x370: // xvcvsxdsp (VSX Vector Convert and round Signed Integer Doubleword
16292 // to Single-Precision format)
16293 DIP("xvcvsxddp v%u,v%u\n", XT, XB);
16294 putVSReg( XT,
16295 binop( Iop_64HLtoV128,
16296 binop( Iop_32HLto64,
16297 unop( Iop_ReinterpF32asI32,
16298 unop( Iop_TruncF64asF32,
16299 binop( Iop_RoundF64toF32,
16300 get_IR_roundingmode(),
16301 binop( Iop_I64StoF64,
16302 get_IR_roundingmode(),
16303 mkexpr( xB ) ) ) ) ),
16304 mkU32( 0 ) ),
16305 binop( Iop_32HLto64,
16306 unop( Iop_ReinterpF32asI32,
16307 unop( Iop_TruncF64asF32,
16308 binop( Iop_RoundF64toF32,
16309 get_IR_roundingmode(),
16310 binop( Iop_I64StoF64,
16311 get_IR_roundingmode(),
16312 mkexpr( xB2 ) ) ) ) ),
16313 mkU32( 0 ) ) ) );
16314 break;
16315 case 0x350: // xvcvuxdsp (VSX Vector Convert and round Unsigned Integer Doubleword
16316 // to Single-Precision format)
16317 DIP("xvcvuxddp v%u,v%u\n", XT, XB);
16318 putVSReg( XT,
16319 binop( Iop_64HLtoV128,
16320 binop( Iop_32HLto64,
16321 unop( Iop_ReinterpF32asI32,
16322 unop( Iop_TruncF64asF32,
16323 binop( Iop_RoundF64toF32,
16324 get_IR_roundingmode(),
16325 binop( Iop_I64UtoF64,
16326 get_IR_roundingmode(),
16327 mkexpr( xB ) ) ) ) ),
16328 mkU32( 0 ) ),
16329 binop( Iop_32HLto64,
16330 unop( Iop_ReinterpF32asI32,
16331 unop( Iop_TruncF64asF32,
16332 binop( Iop_RoundF64toF32,
16333 get_IR_roundingmode(),
16334 binop( Iop_I64UtoF64,
16335 get_IR_roundingmode(),
16336 mkexpr( xB2 ) ) ) ) ),
16337 mkU32( 0 ) ) ) );
16338 break;
16340 case 0x1f0: // xvcvsxwdp (VSX Vector Convert Signed Integer Word to Double-Precision format)
16341 DIP("xvcvsxwdp v%u,v%u\n", XT, XB);
16342 putVSReg( XT,
16343 binop( Iop_64HLtoV128,
16344 unop( Iop_ReinterpF64asI64,
16345 binop( Iop_I64StoF64, get_IR_roundingmode(),
16346 unop( Iop_32Sto64, mkexpr( b3 ) ) ) ),
16347 unop( Iop_ReinterpF64asI64,
16348 binop( Iop_I64StoF64, get_IR_roundingmode(),
16349 unop( Iop_32Sto64, mkexpr( b1 ) ) ) ) ) );
16350 break;
16351 case 0x1d0: // xvcvuxwdp (VSX Vector Convert Unsigned Integer Word to Double-Precision format)
16352 DIP("xvcvuxwdp v%u,v%u\n", XT, XB);
16353 putVSReg( XT,
16354 binop( Iop_64HLtoV128,
16355 unop( Iop_ReinterpF64asI64,
16356 binop( Iop_I64UtoF64, get_IR_roundingmode(),
16357 unop( Iop_32Uto64, mkexpr( b3 ) ) ) ),
16358 unop( Iop_ReinterpF64asI64,
16359 binop( Iop_I64UtoF64, get_IR_roundingmode(),
16360 unop( Iop_32Uto64, mkexpr( b1 ) ) ) ) ) );
16361 break;
16362 case 0x170: // xvcvsxwsp (VSX Vector Convert Signed Integer Word to Single-Precision format)
16363 DIP("xvcvsxwsp v%u,v%u\n", XT, XB);
16364 putVSReg( XT, unop( Iop_I32StoFx4, getVSReg( XB ) ) );
16365 break;
16366 case 0x150: // xvcvuxwsp (VSX Vector Convert Unsigned Integer Word to Single-Precision format)
16367 DIP("xvcvuxwsp v%u,v%u\n", XT, XB);
16368 putVSReg( XT, unop( Iop_I32UtoFx4, getVSReg( XB ) ) );
16369 break;
16371 default:
16372 vex_printf( "dis_vx_conv(ppc)(opc2)\n" );
16373 return False;
16375 return True;
16379 * VSX vector Double Precision Floating Point Arithmetic Instructions
16381 static Bool
16382 dis_vxv_dp_arith ( UInt theInstr, UInt opc2 )
16384 /* XX3-Form */
16385 UChar opc1 = ifieldOPC( theInstr );
16386 UChar XT = ifieldRegXT( theInstr );
16387 UChar XA = ifieldRegXA( theInstr );
16388 UChar XB = ifieldRegXB( theInstr );
16389 IRExpr* rm = get_IR_roundingmode();
16390 IRTemp frA = newTemp(Ity_F64);
16391 IRTemp frB = newTemp(Ity_F64);
16392 IRTemp frA2 = newTemp(Ity_F64);
16393 IRTemp frB2 = newTemp(Ity_F64);
16395 if (opc1 != 0x3C) {
16396 vex_printf( "dis_vxv_dp_arith(ppc)(instr)\n" );
16397 return False;
16400 assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
16401 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
16402 assign(frA2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg( XA ))));
16403 assign(frB2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg( XB ))));
16405 switch (opc2) {
16406 case 0x1E0: // xvdivdp (VSX Vector Divide Double-Precision)
16407 case 0x1C0: // xvmuldp (VSX Vector Multiply Double-Precision)
16408 case 0x180: // xvadddp (VSX Vector Add Double-Precision)
16409 case 0x1A0: // xvsubdp (VSX Vector Subtract Double-Precision)
16411 IROp mOp;
16412 const HChar * oper_name;
16413 switch (opc2) {
16414 case 0x1E0:
16415 mOp = Iop_DivF64;
16416 oper_name = "div";
16417 break;
16418 case 0x1C0:
16419 mOp = Iop_MulF64;
16420 oper_name = "mul";
16421 break;
16422 case 0x180:
16423 mOp = Iop_AddF64;
16424 oper_name = "add";
16425 break;
16426 case 0x1A0:
16427 mOp = Iop_SubF64;
16428 oper_name = "sub";
16429 break;
16431 default:
16432 vpanic("The impossible happened: dis_vxv_dp_arith(ppc)");
16434 IRTemp hiResult = newTemp(Ity_I64);
16435 IRTemp loResult = newTemp(Ity_I64);
16436 DIP("xv%sdp v%d,v%d,v%d\n", oper_name, XT, XA, XB);
16438 assign( hiResult,
16439 unop( Iop_ReinterpF64asI64,
16440 triop( mOp, rm, mkexpr( frA ), mkexpr( frB ) ) ) );
16441 assign( loResult,
16442 unop( Iop_ReinterpF64asI64,
16443 triop( mOp, rm, mkexpr( frA2 ), mkexpr( frB2 ) ) ) );
16444 putVSReg( XT,
16445 binop( Iop_64HLtoV128, mkexpr( hiResult ), mkexpr( loResult ) ) );
16446 break;
16448 case 0x196: // xvsqrtdp
16450 IRTemp hiResult = newTemp(Ity_I64);
16451 IRTemp loResult = newTemp(Ity_I64);
16452 DIP("xvsqrtdp v%d,v%d\n", XT, XB);
16454 assign( hiResult,
16455 unop( Iop_ReinterpF64asI64,
16456 binop( Iop_SqrtF64, rm, mkexpr( frB ) ) ) );
16457 assign( loResult,
16458 unop( Iop_ReinterpF64asI64,
16459 binop( Iop_SqrtF64, rm, mkexpr( frB2 ) ) ) );
16460 putVSReg( XT,
16461 binop( Iop_64HLtoV128, mkexpr( hiResult ), mkexpr( loResult ) ) );
16462 break;
16464 case 0x184: case 0x1A4: // xvmaddadp, xvmaddmdp (VSX Vector Multiply-Add Double-Precision)
16465 case 0x1C4: case 0x1E4: // xvmsubadp, xvmsubmdp (VSX Vector Multiply-Subtract Double-Precision)
16466 case 0x384: case 0x3A4: // xvnmaddadp, xvnmaddmdp (VSX Vector Negate Multiply-Add Double-Precision)
16467 case 0x3C4: case 0x3E4: // xvnmsubadp, xvnmsubmdp (VSX Vector Negate Multiply-Subtract Double-Precision)
16469 /* xvm{add|sub}mdp XT,XA,XB is element-wise equivalent to fm{add|sub} FRT,FRA,FRC,FRB with . . .
16470 * XT == FRC
16471 * XA == FRA
16472 * XB == FRB
16474 * and for xvm{add|sub}adp . . .
16475 * XT == FRB
16476 * XA == FRA
16477 * XB == FRC
16479 Bool negate;
16480 IROp mOp = Iop_INVALID;
16481 const HChar * oper_name = NULL;
16482 Bool mdp = False;
16484 switch (opc2) {
16485 case 0x184: case 0x1A4:
16486 case 0x384: case 0x3A4:
16487 mOp = Iop_MAddF64;
16488 oper_name = "add";
16489 mdp = (opc2 & 0x0FF) == 0x0A4;
16490 break;
16492 case 0x1C4: case 0x1E4:
16493 case 0x3C4: case 0x3E4:
16494 mOp = Iop_MSubF64;
16495 oper_name = "sub";
16496 mdp = (opc2 & 0x0FF) == 0x0E4;
16497 break;
16499 default:
16500 vpanic("The impossible happened: dis_vxv_sp_arith(ppc)");
16503 switch (opc2) {
16504 case 0x384: case 0x3A4:
16505 case 0x3C4: case 0x3E4:
16506 negate = True;
16507 break;
16508 default:
16509 negate = False;
16511 IRTemp hiResult = newTemp(Ity_I64);
16512 IRTemp loResult = newTemp(Ity_I64);
16513 IRTemp frT = newTemp(Ity_F64);
16514 IRTemp frT2 = newTemp(Ity_F64);
16515 DIP("xv%sm%s%s v%d,v%d,v%d\n", negate ? "n" : "", oper_name, mdp ? "mdp" : "adp",
16516 XT, XA, XB);
16517 assign(frT, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XT ) ) ) );
16518 assign(frT2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg( XT ) ) ) );
16520 assign( hiResult,
16521 unop( Iop_ReinterpF64asI64,
16522 qop( mOp,
16524 mkexpr( frA ),
16525 mkexpr( mdp ? frT : frB ),
16526 mkexpr( mdp ? frB : frT ) ) ) );
16527 assign( loResult,
16528 unop( Iop_ReinterpF64asI64,
16529 qop( mOp,
16531 mkexpr( frA2 ),
16532 mkexpr( mdp ? frT2 : frB2 ),
16533 mkexpr( mdp ? frB2 : frT2 ) ) ) );
16534 putVSReg( XT,
16535 binop( Iop_64HLtoV128,
16536 mkexpr( negate ? getNegatedResult( hiResult )
16537 : hiResult ),
16538 mkexpr( negate ? getNegatedResult( loResult )
16539 : loResult ) ) );
16540 break;
16542 case 0x1D4: // xvtsqrtdp (VSX Vector Test for software Square Root Double-Precision)
16544 IRTemp frBHi_I64 = newTemp(Ity_I64);
16545 IRTemp frBLo_I64 = newTemp(Ity_I64);
16546 IRTemp flagsHi = newTemp(Ity_I32);
16547 IRTemp flagsLo = newTemp(Ity_I32);
16548 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
16549 IRTemp fe_flagHi, fg_flagHi, fe_flagLo, fg_flagLo;
16550 fe_flagHi = fg_flagHi = fe_flagLo = fg_flagLo = IRTemp_INVALID;
16552 DIP("xvtsqrtdp cr%d,v%d\n", crfD, XB);
16553 assign( frBHi_I64, unop(Iop_V128HIto64, getVSReg( XB )) );
16554 assign( frBLo_I64, unop(Iop_V128to64, getVSReg( XB )) );
16555 do_fp_tsqrt(frBHi_I64, False /*not single precision*/, &fe_flagHi, &fg_flagHi);
16556 do_fp_tsqrt(frBLo_I64, False /*not single precision*/, &fe_flagLo, &fg_flagLo);
16557 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
16558 * where fl_flag == 1 on ppc64.
16560 assign( flagsHi,
16561 binop( Iop_Or32,
16562 binop( Iop_Or32, mkU32( 8 ), // fl_flag
16563 binop( Iop_Shl32, mkexpr(fg_flagHi), mkU8( 2 ) ) ),
16564 binop( Iop_Shl32, mkexpr(fe_flagHi), mkU8( 1 ) ) ) );
16565 assign( flagsLo,
16566 binop( Iop_Or32,
16567 binop( Iop_Or32, mkU32( 8 ), // fl_flag
16568 binop( Iop_Shl32, mkexpr(fg_flagLo), mkU8( 2 ) ) ),
16569 binop( Iop_Shl32, mkexpr(fe_flagLo), mkU8( 1 ) ) ) );
16570 putGST_field( PPC_GST_CR,
16571 binop( Iop_Or32, mkexpr( flagsHi ), mkexpr( flagsLo ) ),
16572 crfD );
16573 break;
16575 case 0x1F4: // xvtdivdp (VSX Vector Test for software Divide Double-Precision)
16577 IRTemp frBHi_I64 = newTemp(Ity_I64);
16578 IRTemp frBLo_I64 = newTemp(Ity_I64);
16579 IRTemp frAHi_I64 = newTemp(Ity_I64);
16580 IRTemp frALo_I64 = newTemp(Ity_I64);
16581 IRTemp flagsHi = newTemp(Ity_I32);
16582 IRTemp flagsLo = newTemp(Ity_I32);
16583 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
16584 IRTemp fe_flagHi, fg_flagHi, fe_flagLo, fg_flagLo;
16585 fe_flagHi = fg_flagHi = fe_flagLo = fg_flagLo = IRTemp_INVALID;
16587 DIP("xvtdivdp cr%d,v%d,v%d\n", crfD, XA, XB);
16588 assign( frAHi_I64, unop(Iop_V128HIto64, getVSReg( XA )) );
16589 assign( frALo_I64, unop(Iop_V128to64, getVSReg( XA )) );
16590 assign( frBHi_I64, unop(Iop_V128HIto64, getVSReg( XB )) );
16591 assign( frBLo_I64, unop(Iop_V128to64, getVSReg( XB )) );
16593 _do_fp_tdiv(frAHi_I64, frBHi_I64, False/*dp*/, &fe_flagHi, &fg_flagHi);
16594 _do_fp_tdiv(frALo_I64, frBLo_I64, False/*dp*/, &fe_flagLo, &fg_flagLo);
16595 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
16596 * where fl_flag == 1 on ppc64.
16598 assign( flagsHi,
16599 binop( Iop_Or32,
16600 binop( Iop_Or32, mkU32( 8 ), // fl_flag
16601 binop( Iop_Shl32, mkexpr(fg_flagHi), mkU8( 2 ) ) ),
16602 binop( Iop_Shl32, mkexpr(fe_flagHi), mkU8( 1 ) ) ) );
16603 assign( flagsLo,
16604 binop( Iop_Or32,
16605 binop( Iop_Or32, mkU32( 8 ), // fl_flag
16606 binop( Iop_Shl32, mkexpr(fg_flagLo), mkU8( 2 ) ) ),
16607 binop( Iop_Shl32, mkexpr(fe_flagLo), mkU8( 1 ) ) ) );
16608 putGST_field( PPC_GST_CR,
16609 binop( Iop_Or32, mkexpr( flagsHi ), mkexpr( flagsLo ) ),
16610 crfD );
16611 break;
16614 default:
16615 vex_printf( "dis_vxv_dp_arith(ppc)(opc2)\n" );
16616 return False;
16618 return True;
16622 * VSX vector Single Precision Floating Point Arithmetic Instructions
16624 static Bool
16625 dis_vxv_sp_arith ( UInt theInstr, UInt opc2 )
16627 /* XX3-Form */
16628 UChar opc1 = ifieldOPC( theInstr );
16629 UChar XT = ifieldRegXT( theInstr );
16630 UChar XA = ifieldRegXA( theInstr );
16631 UChar XB = ifieldRegXB( theInstr );
16632 IRExpr* rm = get_IR_roundingmode();
16633 IRTemp a3, a2, a1, a0;
16634 IRTemp b3, b2, b1, b0;
16635 IRTemp res0 = newTemp(Ity_I32);
16636 IRTemp res1 = newTemp(Ity_I32);
16637 IRTemp res2 = newTemp(Ity_I32);
16638 IRTemp res3 = newTemp(Ity_I32);
16640 a3 = a2 = a1 = a0 = IRTemp_INVALID;
16641 b3 = b2 = b1 = b0 = IRTemp_INVALID;
16643 if (opc1 != 0x3C) {
16644 vex_printf( "dis_vxv_sp_arith(ppc)(instr)\n" );
16645 return False;
16648 switch (opc2) {
16649 case 0x100: // xvaddsp (VSX Vector Add Single-Precision)
16650 DIP("xvaddsp v%d,v%d,v%d\n", XT, XA, XB);
16651 // WARNING: BOGUS! The backend ignores rm on Iop_Add32Fx4
16652 putVSReg( XT, triop(Iop_Add32Fx4, rm,
16653 getVSReg( XA ), getVSReg( XB )) );
16654 break;
16656 case 0x140: // xvmulsp (VSX Vector Multiply Single-Precision)
16657 DIP("xvmulsp v%d,v%d,v%d\n", XT, XA, XB);
16658 // WARNING: BOGUS! The backend ignores rm on Iop_Mul32Fx4
16659 putVSReg( XT, triop(Iop_Mul32Fx4, rm,
16660 getVSReg( XA ), getVSReg( XB )) );
16661 break;
16663 case 0x120: // xvsubsp (VSX Vector Subtract Single-Precision)
16664 DIP("xvsubsp v%d,v%d,v%d\n", XT, XA, XB);
16665 // WARNING: BOGUS! The backend ignores rm on Iop_Sub32Fx4
16666 putVSReg( XT, triop(Iop_Sub32Fx4, rm,
16667 getVSReg( XA ), getVSReg( XB )) );
16668 break;
16670 case 0x160: // xvdivsp (VSX Vector Divide Single-Precision)
16672 /* Iop_Div32Fx4 is not implemented for ppc64 (in host_ppc_{isel|defs}.c.
16673 * So there are two choices:
16674 * 1. Implement the xvdivsp with a native insn; or
16675 * 2. Extract the 4 single precision floats from each vector
16676 * register inputs and perform fdivs on each pair
16677 * I will do the latter, due to the general philosophy of
16678 * reusing existing implementations when practical.
16680 DIP("xvdivsp v%d,v%d,v%d\n", XT, XA, XB);
16681 breakV128to4xF64( getVSReg( XA ), &a3, &a2, &a1, &a0 );
16682 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
16684 assign( res0,
16685 unop( Iop_ReinterpF32asI32,
16686 unop( Iop_TruncF64asF32,
16687 triop( Iop_DivF64r32, rm, mkexpr( a0 ), mkexpr( b0 ) ) ) ) );
16688 assign( res1,
16689 unop( Iop_ReinterpF32asI32,
16690 unop( Iop_TruncF64asF32,
16691 triop( Iop_DivF64r32, rm, mkexpr( a1 ), mkexpr( b1 ) ) ) ) );
16692 assign( res2,
16693 unop( Iop_ReinterpF32asI32,
16694 unop( Iop_TruncF64asF32,
16695 triop( Iop_DivF64r32, rm, mkexpr( a2 ), mkexpr( b2 ) ) ) ) );
16696 assign( res3,
16697 unop( Iop_ReinterpF32asI32,
16698 unop( Iop_TruncF64asF32,
16699 triop( Iop_DivF64r32, rm, mkexpr( a3 ), mkexpr( b3 ) ) ) ) );
16701 putVSReg( XT,
16702 binop( Iop_64HLtoV128,
16703 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
16704 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
16705 break;
16707 case 0x116: // xvsqrtsp (VSX Vector Square Root Single-Precision)
16709 DIP("xvsqrtsp v%d,v%d\n", XT, XB);
16710 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
16711 /* Note: The native xvsqrtsp insruction does not always give the same precision
16712 * as what we get with Iop_SqrtF64. But it doesn't seem worthwhile to implement
16713 * an Iop_SqrtF32 that would give us a lower precision result, albeit more true
16714 * to the actual instruction.
16717 assign( res0,
16718 unop( Iop_ReinterpF32asI32,
16719 unop( Iop_TruncF64asF32,
16720 binop(Iop_SqrtF64, rm, mkexpr( b0 ) ) ) ) );
16721 assign( res1,
16722 unop( Iop_ReinterpF32asI32,
16723 unop( Iop_TruncF64asF32,
16724 binop(Iop_SqrtF64, rm, mkexpr( b1 ) ) ) ) );
16725 assign( res2,
16726 unop( Iop_ReinterpF32asI32,
16727 unop( Iop_TruncF64asF32,
16728 binop(Iop_SqrtF64, rm, mkexpr( b2) ) ) ) );
16729 assign( res3,
16730 unop( Iop_ReinterpF32asI32,
16731 unop( Iop_TruncF64asF32,
16732 binop(Iop_SqrtF64, rm, mkexpr( b3 ) ) ) ) );
16734 putVSReg( XT,
16735 binop( Iop_64HLtoV128,
16736 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
16737 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
16738 break;
16741 case 0x104: case 0x124: // xvmaddasp, xvmaddmsp (VSX Vector Multiply-Add Single-Precision)
16742 case 0x144: case 0x164: // xvmsubasp, xvmsubmsp (VSX Vector Multiply-Subtract Single-Precision)
16743 case 0x304: case 0x324: // xvnmaddasp, xvnmaddmsp (VSX Vector Negate Multiply-Add Single-Precision)
16744 case 0x344: case 0x364: // xvnmsubasp, xvnmsubmsp (VSX Vector Negate Multiply-Subtract Single-Precision)
16746 IRTemp t3, t2, t1, t0;
16747 Bool msp = False;
16748 Bool negate;
16749 const HChar * oper_name = NULL;
16750 IROp mOp = Iop_INVALID;
16751 switch (opc2) {
16752 case 0x104: case 0x124:
16753 case 0x304: case 0x324:
16754 msp = (opc2 & 0x0FF) == 0x024;
16755 mOp = Iop_MAddF64r32;
16756 oper_name = "madd";
16757 break;
16759 case 0x144: case 0x164:
16760 case 0x344: case 0x364:
16761 msp = (opc2 & 0x0FF) == 0x064;
16762 mOp = Iop_MSubF64r32;
16763 oper_name = "sub";
16764 break;
16766 default:
16767 vpanic("The impossible happened: dis_vxv_sp_arith(ppc)");
16770 switch (opc2) {
16771 case 0x304: case 0x324:
16772 case 0x344: case 0x364:
16773 negate = True;
16774 break;
16776 default:
16777 negate = False;
16780 DIP("xv%sm%s%s v%d,v%d,v%d\n", negate ? "n" : "", oper_name,
16781 msp ? "msp" : "asp", XT, XA, XB);
16783 t3 = t2 = t1 = t0 = IRTemp_INVALID;
16784 breakV128to4xF64( getVSReg( XA ), &a3, &a2, &a1, &a0 );
16785 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
16786 breakV128to4xF64( getVSReg( XT ), &t3, &t2, &t1, &t0 );
16788 assign( res0,
16789 unop( Iop_ReinterpF32asI32,
16790 unop( Iop_TruncF64asF32,
16791 qop( mOp,
16793 mkexpr( a0 ),
16794 mkexpr( msp ? t0 : b0 ),
16795 mkexpr( msp ? b0 : t0 ) ) ) ) );
16796 assign( res1,
16797 unop( Iop_ReinterpF32asI32,
16798 unop( Iop_TruncF64asF32,
16799 qop( mOp,
16801 mkexpr( a1 ),
16802 mkexpr( msp ? t1 : b1 ),
16803 mkexpr( msp ? b1 : t1 ) ) ) ) );
16804 assign( res2,
16805 unop( Iop_ReinterpF32asI32,
16806 unop( Iop_TruncF64asF32,
16807 qop( mOp,
16809 mkexpr( a2 ),
16810 mkexpr( msp ? t2 : b2 ),
16811 mkexpr( msp ? b2 : t2 ) ) ) ) );
16812 assign( res3,
16813 unop( Iop_ReinterpF32asI32,
16814 unop( Iop_TruncF64asF32,
16815 qop( mOp,
16817 mkexpr( a3 ),
16818 mkexpr( msp ? t3 : b3 ),
16819 mkexpr( msp ? b3 : t3 ) ) ) ) );
16821 putVSReg( XT,
16822 binop( Iop_64HLtoV128,
16823 binop( Iop_32HLto64, mkexpr( negate ? getNegatedResult_32( res3 ) : res3 ),
16824 mkexpr( negate ? getNegatedResult_32( res2 ) : res2 ) ),
16825 binop( Iop_32HLto64, mkexpr( negate ? getNegatedResult_32( res1 ) : res1 ),
16826 mkexpr( negate ? getNegatedResult_32( res0 ) : res0 ) ) ) );
16828 break;
16830 case 0x154: // xvtsqrtsp (VSX Vector Test for software Square Root Single-Precision)
16832 IRTemp flags0 = newTemp(Ity_I32);
16833 IRTemp flags1 = newTemp(Ity_I32);
16834 IRTemp flags2 = newTemp(Ity_I32);
16835 IRTemp flags3 = newTemp(Ity_I32);
16836 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
16837 IRTemp fe_flag0, fg_flag0, fe_flag1, fg_flag1;
16838 IRTemp fe_flag2, fg_flag2, fe_flag3, fg_flag3;
16839 fe_flag0 = fg_flag0 = fe_flag1 = fg_flag1 = IRTemp_INVALID;
16840 fe_flag2 = fg_flag2 = fe_flag3 = fg_flag3 = IRTemp_INVALID;
16841 DIP("xvtsqrtsp cr%d,v%d\n", crfD, XB);
16843 breakV128to4x32( getVSReg( XB ), &b3, &b2, &b1, &b0 );
16844 do_fp_tsqrt(b0, True /* single precision*/, &fe_flag0, &fg_flag0);
16845 do_fp_tsqrt(b1, True /* single precision*/, &fe_flag1, &fg_flag1);
16846 do_fp_tsqrt(b2, True /* single precision*/, &fe_flag2, &fg_flag2);
16847 do_fp_tsqrt(b3, True /* single precision*/, &fe_flag3, &fg_flag3);
16849 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
16850 * where fl_flag == 1 on ppc64.
16852 assign( flags0,
16853 binop( Iop_Or32,
16854 binop( Iop_Or32, mkU32( 8 ), // fl_flag
16855 binop( Iop_Shl32, mkexpr(fg_flag0), mkU8( 2 ) ) ),
16856 binop( Iop_Shl32, mkexpr(fe_flag0), mkU8( 1 ) ) ) );
16857 assign( flags1,
16858 binop( Iop_Or32,
16859 binop( Iop_Or32, mkU32( 8 ), // fl_flag
16860 binop( Iop_Shl32, mkexpr(fg_flag1), mkU8( 2 ) ) ),
16861 binop( Iop_Shl32, mkexpr(fe_flag1), mkU8( 1 ) ) ) );
16862 assign( flags2,
16863 binop( Iop_Or32,
16864 binop( Iop_Or32, mkU32( 8 ), // fl_flag
16865 binop( Iop_Shl32, mkexpr(fg_flag2), mkU8( 2 ) ) ),
16866 binop( Iop_Shl32, mkexpr(fe_flag2), mkU8( 1 ) ) ) );
16867 assign( flags3,
16868 binop( Iop_Or32,
16869 binop( Iop_Or32, mkU32( 8 ), // fl_flag
16870 binop( Iop_Shl32, mkexpr(fg_flag3), mkU8( 2 ) ) ),
16871 binop( Iop_Shl32, mkexpr(fe_flag3), mkU8( 1 ) ) ) );
16872 putGST_field( PPC_GST_CR,
16873 binop( Iop_Or32,
16874 mkexpr( flags0 ),
16875 binop( Iop_Or32,
16876 mkexpr( flags1 ),
16877 binop( Iop_Or32,
16878 mkexpr( flags2 ),
16879 mkexpr( flags3 ) ) ) ),
16880 crfD );
16882 break;
16884 case 0x174: // xvtdivsp (VSX Vector Test for software Divide Single-Precision)
16886 IRTemp flags0 = newTemp(Ity_I32);
16887 IRTemp flags1 = newTemp(Ity_I32);
16888 IRTemp flags2 = newTemp(Ity_I32);
16889 IRTemp flags3 = newTemp(Ity_I32);
16890 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
16891 IRTemp fe_flag0, fg_flag0, fe_flag1, fg_flag1;
16892 IRTemp fe_flag2, fg_flag2, fe_flag3, fg_flag3;
16893 fe_flag0 = fg_flag0 = fe_flag1 = fg_flag1 = IRTemp_INVALID;
16894 fe_flag2 = fg_flag2 = fe_flag3 = fg_flag3 = IRTemp_INVALID;
16895 DIP("xvtdivsp cr%d,v%d,v%d\n", crfD, XA, XB);
16897 breakV128to4x32( getVSReg( XA ), &a3, &a2, &a1, &a0 );
16898 breakV128to4x32( getVSReg( XB ), &b3, &b2, &b1, &b0 );
16899 _do_fp_tdiv(a0, b0, True /* single precision*/, &fe_flag0, &fg_flag0);
16900 _do_fp_tdiv(a1, b1, True /* single precision*/, &fe_flag1, &fg_flag1);
16901 _do_fp_tdiv(a2, b2, True /* single precision*/, &fe_flag2, &fg_flag2);
16902 _do_fp_tdiv(a3, b3, True /* single precision*/, &fe_flag3, &fg_flag3);
16904 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
16905 * where fl_flag == 1 on ppc64.
16907 assign( flags0,
16908 binop( Iop_Or32,
16909 binop( Iop_Or32, mkU32( 8 ), // fl_flag
16910 binop( Iop_Shl32, mkexpr(fg_flag0), mkU8( 2 ) ) ),
16911 binop( Iop_Shl32, mkexpr(fe_flag0), mkU8( 1 ) ) ) );
16912 assign( flags1,
16913 binop( Iop_Or32,
16914 binop( Iop_Or32, mkU32( 8 ), // fl_flag
16915 binop( Iop_Shl32, mkexpr(fg_flag1), mkU8( 2 ) ) ),
16916 binop( Iop_Shl32, mkexpr(fe_flag1), mkU8( 1 ) ) ) );
16917 assign( flags2,
16918 binop( Iop_Or32,
16919 binop( Iop_Or32, mkU32( 8 ), // fl_flag
16920 binop( Iop_Shl32, mkexpr(fg_flag2), mkU8( 2 ) ) ),
16921 binop( Iop_Shl32, mkexpr(fe_flag2), mkU8( 1 ) ) ) );
16922 assign( flags3,
16923 binop( Iop_Or32,
16924 binop( Iop_Or32, mkU32( 8 ), // fl_flag
16925 binop( Iop_Shl32, mkexpr(fg_flag3), mkU8( 2 ) ) ),
16926 binop( Iop_Shl32, mkexpr(fe_flag3), mkU8( 1 ) ) ) );
16927 putGST_field( PPC_GST_CR,
16928 binop( Iop_Or32,
16929 mkexpr( flags0 ),
16930 binop( Iop_Or32,
16931 mkexpr( flags1 ),
16932 binop( Iop_Or32,
16933 mkexpr( flags2 ),
16934 mkexpr( flags3 ) ) ) ),
16935 crfD );
16937 break;
16940 default:
16941 vex_printf( "dis_vxv_sp_arith(ppc)(opc2)\n" );
16942 return False;
16944 return True;
16948 * Vector Population Count/bit matrix transpose
16950 static Bool
16951 dis_av_count_bitTranspose ( UInt theInstr, UInt opc2 )
16953 UChar vRB_addr = ifieldRegB(theInstr);
16954 UChar vRT_addr = ifieldRegDS(theInstr);
16955 UChar opc1 = ifieldOPC( theInstr );
16956 IRTemp vB = newTemp(Ity_V128);
16957 assign( vB, getVReg(vRB_addr));
16959 if (opc1 != 0x4) {
16960 vex_printf( "dis_av_count_bitTranspose(ppc)(instr)\n" );
16961 return False;
16964 switch (opc2) {
16965 case 0x702: // vclzb
16966 DIP("vclzb v%d,v%d\n", vRT_addr, vRB_addr);
16967 putVReg( vRT_addr, unop(Iop_Clz8x16, mkexpr( vB ) ) );
16968 break;
16970 case 0x742: // vclzh
16971 DIP("vclzh v%d,v%d\n", vRT_addr, vRB_addr);
16972 putVReg( vRT_addr, unop(Iop_Clz16x8, mkexpr( vB ) ) );
16973 break;
16975 case 0x782: // vclzw
16976 DIP("vclzw v%d,v%d\n", vRT_addr, vRB_addr);
16977 putVReg( vRT_addr, unop(Iop_Clz32x4, mkexpr( vB ) ) );
16978 break;
16980 case 0x7C2: // vclzd
16981 DIP("vclzd v%d,v%d\n", vRT_addr, vRB_addr);
16982 putVReg( vRT_addr, unop(Iop_Clz64x2, mkexpr( vB ) ) );
16983 break;
16985 case 0x703: // vpopcntb
16987 /* Break vector into 32-bit words and do the population count
16988 * on byte in the words
16990 IRType ty = Ity_I32;
16991 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
16992 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
16993 IRTemp cnt_bits0_31, cnt_bits32_63, cnt_bits64_95, cnt_bits96_127;
16994 cnt_bits0_31 = cnt_bits32_63 = cnt_bits64_95 = cnt_bits96_127 = IRTemp_INVALID;
16996 DIP("vpopcntb v%d,v%d\n", vRT_addr, vRB_addr);
16997 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
16998 cnt_bits0_31 = gen_POPCOUNT(ty, bits0_31, BYTE);
16999 cnt_bits32_63 = gen_POPCOUNT(ty, bits32_63, BYTE);
17000 cnt_bits64_95 = gen_POPCOUNT(ty, bits64_95, BYTE);
17001 cnt_bits96_127 = gen_POPCOUNT(ty, bits96_127, BYTE);
17003 putVReg( vRT_addr, mkV128from32(cnt_bits96_127, cnt_bits64_95,
17004 cnt_bits32_63, cnt_bits0_31) );
17005 break;
17008 case 0x743: // vpopcnth
17010 /* Break vector into 32-bit words and do the population count
17011 * for each half word
17013 IRType ty = Ity_I32;
17014 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
17015 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
17016 IRTemp cnt_bits0_31, cnt_bits32_63, cnt_bits64_95, cnt_bits96_127;
17017 cnt_bits0_31 = cnt_bits32_63 = cnt_bits64_95 = cnt_bits96_127 = IRTemp_INVALID;
17019 DIP("vpopcnth v%d,v%d\n", vRT_addr, vRB_addr);
17020 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
17022 cnt_bits0_31 = gen_POPCOUNT(ty, bits0_31, HWORD);
17023 cnt_bits32_63 = gen_POPCOUNT(ty, bits32_63, HWORD);
17024 cnt_bits64_95 = gen_POPCOUNT(ty, bits64_95, HWORD);
17025 cnt_bits96_127 = gen_POPCOUNT(ty, bits96_127, HWORD);
17027 putVReg( vRT_addr, mkV128from32(cnt_bits96_127, cnt_bits64_95,
17028 cnt_bits32_63, cnt_bits0_31) );
17029 break;
17032 case 0x783: // vpopcntw
17034 /* Break vector into 32-bit words and do the population count
17035 * on each word.
17037 IRType ty = Ity_I32;
17038 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
17039 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
17040 IRTemp cnt_bits0_31, cnt_bits32_63, cnt_bits64_95, cnt_bits96_127;
17041 cnt_bits0_31 = cnt_bits32_63 = cnt_bits64_95 = cnt_bits96_127 = IRTemp_INVALID;
17043 DIP("vpopcntw v%d,v%d\n", vRT_addr, vRB_addr);
17044 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
17046 cnt_bits0_31 = gen_POPCOUNT(ty, bits0_31, WORD);
17047 cnt_bits32_63 = gen_POPCOUNT(ty, bits32_63, WORD);
17048 cnt_bits64_95 = gen_POPCOUNT(ty, bits64_95, WORD);
17049 cnt_bits96_127 = gen_POPCOUNT(ty, bits96_127, WORD);
17051 putVReg( vRT_addr, mkV128from32(cnt_bits96_127, cnt_bits64_95,
17052 cnt_bits32_63, cnt_bits0_31) );
17053 break;
17056 case 0x7C3: // vpopcntd
17058 if (mode64) {
17059 /* Break vector into 64-bit double words and do the population count
17060 * on each double word.
17062 IRType ty = Ity_I64;
17063 IRTemp bits0_63 = newTemp(Ity_I64);
17064 IRTemp bits64_127 = newTemp(Ity_I64);
17065 IRTemp cnt_bits0_63 = newTemp(Ity_I64);
17066 IRTemp cnt_bits64_127 = newTemp(Ity_I64);
17068 DIP("vpopcntd v%d,v%d\n", vRT_addr, vRB_addr);
17070 assign(bits0_63, unop( Iop_V128to64, mkexpr( vB ) ) );
17071 assign(bits64_127, unop( Iop_V128HIto64, mkexpr( vB ) ) );
17072 cnt_bits0_63 = gen_POPCOUNT(ty, bits0_63, DWORD);
17073 cnt_bits64_127 = gen_POPCOUNT(ty, bits64_127, DWORD);
17075 putVReg( vRT_addr, binop( Iop_64HLtoV128,
17076 mkexpr( cnt_bits64_127 ),
17077 mkexpr( cnt_bits0_63 ) ) );
17078 } else {
17079 /* Break vector into 32-bit words and do the population count
17080 * on each doubleword.
17082 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
17083 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
17084 IRTemp cnt_bits0_63 = newTemp(Ity_I64);
17085 IRTemp cnt_bits64_127 = newTemp(Ity_I64);
17087 DIP("vpopcntd v%d,v%d\n", vRT_addr, vRB_addr);
17088 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
17090 cnt_bits0_63 = gen_vpopcntd_mode32(bits0_31, bits32_63);
17091 cnt_bits64_127 = gen_vpopcntd_mode32(bits64_95, bits96_127);
17093 putVReg( vRT_addr, binop( Iop_64HLtoV128,
17094 mkexpr( cnt_bits64_127 ),
17095 mkexpr( cnt_bits0_63 ) ) );
17097 break;
17100 case 0x50C: // vgbbd Vector Gather Bits by Bytes by Doubleword
17101 DIP("vgbbd v%d,v%d\n", vRT_addr, vRB_addr);
17102 putVReg( vRT_addr, unop( Iop_PwBitMtxXpose64x2, mkexpr( vB ) ) );
17103 break;
17105 case 0x5CC: // vbpermd Vector Bit Permute Doubleword
17107 UChar vRA_addr = ifieldRegA( theInstr );
17108 IRTemp vA = newTemp( Ity_V128 );
17109 UInt j;
17110 IRTemp index_dword_hi[8]; // index in double word
17111 IRTemp index_dword_lo[8];
17112 IRTemp index_dword_hi_valid[8];
17113 IRTemp index_dword_lo_valid[8];
17114 IRTemp pb_dword_hi[8]; // permute bit
17115 IRTemp pb_dword_lo[8];
17116 IRTemp tmp_hi[9];
17117 IRTemp tmp_lo[9];
17119 DIP("vbpermd v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
17121 tmp_hi[0] = newTemp( Ity_I64 );
17122 tmp_lo[0] = newTemp( Ity_I64 );
17124 assign( vA, getVReg(vRA_addr) );
17125 assign( tmp_hi[0], mkU64( 0 ) );
17126 assign( tmp_lo[0], mkU64( 0 ) );
17128 for (j=0; j<8; j++) {
17129 index_dword_hi[j] = newTemp( Ity_I64 );
17130 index_dword_lo[j] = newTemp( Ity_I64 );
17131 index_dword_hi_valid[j] = newTemp( Ity_I64 );
17132 index_dword_lo_valid[j] = newTemp( Ity_I64 );
17133 pb_dword_hi[j] = newTemp( Ity_I64 );
17134 pb_dword_lo[j] = newTemp( Ity_I64 );
17135 tmp_hi[j+1] = newTemp( Ity_I64 );
17136 tmp_lo[j+1] = newTemp( Ity_I64 );
17138 assign( index_dword_hi[j],
17139 binop( Iop_And64,
17140 binop( Iop_Shr64,
17141 unop( Iop_V128HIto64,
17142 mkexpr( vB ) ),
17143 mkU8( ( 7 - j ) * 8 ) ),
17144 mkU64( 0xFF ) ) );
17146 assign( index_dword_lo[j],
17147 binop( Iop_And64,
17148 binop( Iop_Shr64,
17149 unop( Iop_V128to64,
17150 mkexpr( vB ) ),
17151 mkU8( ( 7 - j ) * 8 ) ),
17152 mkU64( 0xFF ) ) );
17154 assign( index_dword_hi_valid[j],
17155 unop( Iop_1Sto64,
17156 binop( Iop_CmpLT64U,
17157 mkexpr( index_dword_hi[j] ),
17158 mkU64( 64 ) ) ) );
17160 assign( index_dword_lo_valid[j],
17161 unop( Iop_1Sto64,
17162 binop( Iop_CmpLT64U,
17163 mkexpr( index_dword_lo[j] ),
17164 mkU64( 64 ) ) ) );
17165 assign( pb_dword_hi[j],
17166 binop( Iop_And64,
17167 binop( Iop_Shr64,
17168 unop( Iop_V128HIto64,
17169 mkexpr( vA ) ),
17170 unop( Iop_64to8,
17171 binop( Iop_Sub64,
17172 mkU64( 63 ),
17173 mkexpr( index_dword_hi[j] )
17174 ) ) ),
17175 mkU64( 0x1 ) ) );
17177 assign( pb_dword_lo[j],
17178 binop( Iop_And64,
17179 binop( Iop_Shr64,
17180 unop( Iop_V128to64,
17181 mkexpr( vA ) ),
17182 unop( Iop_64to8,
17183 binop( Iop_Sub64,
17184 mkU64( 63 ),
17185 mkexpr( index_dword_lo[j] )
17186 ) ) ),
17187 mkU64( 0x1 ) ) );
17189 assign( tmp_hi[j+1],
17190 binop( Iop_Or64,
17191 binop( Iop_And64,
17192 mkexpr( index_dword_hi_valid[j] ),
17193 binop( Iop_Shl64,
17194 mkexpr( pb_dword_hi[j] ),
17195 mkU8( 7 - j ) ) ),
17196 mkexpr( tmp_hi[j] ) ) );
17198 assign( tmp_lo[j+1],
17199 binop( Iop_Or64,
17200 binop( Iop_And64,
17201 mkexpr( index_dword_lo_valid[j] ),
17202 binop( Iop_Shl64,
17203 mkexpr( pb_dword_lo[j] ),
17204 mkU8( 7 - j ) ) ),
17205 mkexpr( tmp_lo[j] ) ) );
17208 putVReg( vRT_addr,
17209 binop( Iop_64HLtoV128,
17210 mkexpr( tmp_hi[8] ),
17211 mkexpr( tmp_lo[8] ) ) );
17213 break;
17215 default:
17216 vex_printf("dis_av_count_bitTranspose(ppc)(opc2)\n");
17217 return False;
17218 break;
17220 return True;
17223 typedef enum {
17224 PPC_CMP_EQ = 2,
17225 PPC_CMP_GT = 4,
17226 PPC_CMP_GE = 6,
17227 PPC_CMP_LT = 8
17228 } ppc_cmp_t;
17232 This helper function takes as input the IRExpr returned
17233 from a binop( Iop_CmpF64, fpA, fpB), whose result is returned
17234 in IR form. This helper function converts it to PPC form.
17236 Map compare result from IR to PPC
17238 FP cmp result | PPC | IR
17239 --------------------------
17240 UN | 0x1 | 0x45
17241 EQ | 0x2 | 0x40
17242 GT | 0x4 | 0x00
17243 LT | 0x8 | 0x01
17245 condcode = Shl(1, (~(ccIR>>5) & 2)
17246 | ((ccIR ^ (ccIR>>6)) & 1)
17248 static IRTemp
17249 get_fp_cmp_CR_val (IRExpr * ccIR_expr)
17251 IRTemp condcode = newTemp( Ity_I32 );
17252 IRTemp ccIR = newTemp( Ity_I32 );
17254 assign(ccIR, ccIR_expr);
17255 assign( condcode,
17256 binop( Iop_Shl32,
17257 mkU32( 1 ),
17258 unop( Iop_32to8,
17259 binop( Iop_Or32,
17260 binop( Iop_And32,
17261 unop( Iop_Not32,
17262 binop( Iop_Shr32,
17263 mkexpr( ccIR ),
17264 mkU8( 5 ) ) ),
17265 mkU32( 2 ) ),
17266 binop( Iop_And32,
17267 binop( Iop_Xor32,
17268 mkexpr( ccIR ),
17269 binop( Iop_Shr32,
17270 mkexpr( ccIR ),
17271 mkU8( 6 ) ) ),
17272 mkU32( 1 ) ) ) ) ) );
17273 return condcode;
17277 * Helper function for get_max_min_fp for ascertaining the max or min between two doubles
17278 * following these special rules:
17279 * - The max/min of a QNaN and any value is that value
17280 * (When two QNaNs are being compared, the frA QNaN is the return value.)
17281 * - The max/min of any value and an SNaN is that SNaN converted to a QNaN
17282 * (When two SNaNs are being compared, the frA SNaN is converted to a QNaN.)
17284 static IRExpr * _get_maxmin_fp_NaN(IRTemp frA_I64, IRTemp frB_I64)
17286 IRTemp frA_isNaN = newTemp(Ity_I1);
17287 IRTemp frB_isNaN = newTemp(Ity_I1);
17288 IRTemp frA_isSNaN = newTemp(Ity_I1);
17289 IRTemp frB_isSNaN = newTemp(Ity_I1);
17290 IRTemp frA_isQNaN = newTemp(Ity_I1);
17291 IRTemp frB_isQNaN = newTemp(Ity_I1);
17293 assign( frA_isNaN, is_NaN( Ity_I64, frA_I64 ) );
17294 assign( frB_isNaN, is_NaN( Ity_I64, frB_I64 ) );
17295 // If operand is a NAN and bit 12 is '0', then it's an SNaN
17296 assign( frA_isSNaN,
17297 mkAND1( mkexpr(frA_isNaN),
17298 binop( Iop_CmpEQ32,
17299 binop( Iop_And32,
17300 unop( Iop_64HIto32, mkexpr( frA_I64 ) ),
17301 mkU32( 0x00080000 ) ),
17302 mkU32( 0 ) ) ) );
17303 assign( frB_isSNaN,
17304 mkAND1( mkexpr(frB_isNaN),
17305 binop( Iop_CmpEQ32,
17306 binop( Iop_And32,
17307 unop( Iop_64HIto32, mkexpr( frB_I64 ) ),
17308 mkU32( 0x00080000 ) ),
17309 mkU32( 0 ) ) ) );
17310 assign( frA_isQNaN,
17311 mkAND1( mkexpr( frA_isNaN ), unop( Iop_Not1, mkexpr( frA_isSNaN ) ) ) );
17312 assign( frB_isQNaN,
17313 mkAND1( mkexpr( frB_isNaN ), unop( Iop_Not1, mkexpr( frB_isSNaN ) ) ) );
17315 /* Based on the rules specified in the function prologue, the algorithm is as follows:
17316 * <<<<<<<<<>>>>>>>>>>>>>>>>>>
17317 * if frA is a SNaN
17318 * result = frA converted to QNaN
17319 * else if frB is a SNaN
17320 * result = frB converted to QNaN
17321 * else if frB is a QNaN
17322 * result = frA
17323 * // One of frA or frB was a NaN in order for this function to be called, so
17324 * // if we get to this point, we KNOW that frA must be a QNaN.
17325 * else // frA is a QNaN
17326 * result = frB
17327 * <<<<<<<<<>>>>>>>>>>>>>>>>>>
17330 #define SNAN_MASK 0x0008000000000000ULL
17331 return
17332 IRExpr_ITE(mkexpr(frA_isSNaN),
17333 /* then: result = frA converted to QNaN */
17334 binop(Iop_Or64, mkexpr(frA_I64), mkU64(SNAN_MASK)),
17335 /* else: if frB is a SNaN */
17336 IRExpr_ITE(mkexpr(frB_isSNaN),
17337 /* then: result = frB converted to QNaN */
17338 binop(Iop_Or64, mkexpr(frB_I64), mkU64(SNAN_MASK)),
17339 /* else: if frB is a QNaN */
17340 IRExpr_ITE(mkexpr(frB_isQNaN),
17341 /* then: result = frA */
17342 mkexpr(frA_I64),
17343 /* else: frA is a QNaN, so result = frB */
17344 mkexpr(frB_I64))));
17348 * Helper function for get_max_min_fp.
17350 static IRExpr * _get_maxmin_fp_cmp(IRTemp src1, IRTemp src2, Bool isMin)
17352 IRTemp src1cmpsrc2 = get_fp_cmp_CR_val( binop( Iop_CmpF64,
17353 unop( Iop_ReinterpI64asF64,
17354 mkexpr( src1 ) ),
17355 unop( Iop_ReinterpI64asF64,
17356 mkexpr( src2 ) ) ) );
17358 return IRExpr_ITE( binop( Iop_CmpEQ32,
17359 mkexpr( src1cmpsrc2 ),
17360 mkU32( isMin ? PPC_CMP_LT : PPC_CMP_GT ) ),
17361 /* then: use src1 */
17362 mkexpr( src1 ),
17363 /* else: use src2 */
17364 mkexpr( src2 ) );
17368 * Helper function for "Maximum/Minimum Double Precision" operations.
17369 * Arguments: frA and frb are Ity_I64
17370 * Returns Ity_I64 IRExpr that answers the "which is Maxiumum/Minimum" question
17372 static IRExpr * get_max_min_fp(IRTemp frA_I64, IRTemp frB_I64, Bool isMin)
17374 /* There are three special cases where get_fp_cmp_CR_val is not helpful
17375 * for ascertaining the maximum between two doubles:
17376 * 1. The max/min of +0 and -0 is +0.
17377 * 2. The max/min of a QNaN and any value is that value.
17378 * 3. The max/min of any value and an SNaN is that SNaN converted to a QNaN.
17379 * We perform the check for [+/-]0 here in this function and use the
17380 * _get_maxmin_fp_NaN helper for the two NaN cases; otherwise we call _get_maxmin_fp_cmp
17381 * to do the standard comparison function.
17383 IRTemp anyNaN = newTemp(Ity_I1);
17384 IRTemp frA_isZero = newTemp(Ity_I1);
17385 IRTemp frB_isZero = newTemp(Ity_I1);
17386 assign( frA_isZero, is_Zero( Ity_I64, frA_I64 ) );
17387 assign( frB_isZero, is_Zero( Ity_I64, frB_I64 ) );
17388 assign( anyNaN, mkOR1( is_NaN( Ity_I64, frA_I64 ),
17389 is_NaN(Ity_I64, frB_I64 ) ) );
17390 #define MINUS_ZERO 0x8000000000000000ULL
17392 return IRExpr_ITE( /* If both arguments are zero . . . */
17393 mkAND1( mkexpr( frA_isZero ), mkexpr( frB_isZero ) ),
17394 /* then: if frA is -0 and isMin==True, return -0;
17395 * else if frA is +0 and isMin==False; return +0;
17396 * otherwise, simply return frB. */
17397 IRExpr_ITE( binop( Iop_CmpEQ32,
17398 unop( Iop_64HIto32,
17399 mkexpr( frA_I64 ) ),
17400 mkU32( isMin ? 0x80000000 : 0 ) ),
17401 mkU64( isMin ? MINUS_ZERO : 0ULL ),
17402 mkexpr( frB_I64 ) ),
17403 /* else: check if either input is a NaN*/
17404 IRExpr_ITE( mkexpr( anyNaN ),
17405 /* then: use "NaN helper" */
17406 _get_maxmin_fp_NaN( frA_I64, frB_I64 ),
17407 /* else: use "comparison helper" */
17408 _get_maxmin_fp_cmp( frB_I64, frA_I64, isMin ) ));
17411 static const HChar * _get_vsx_rdpi_suffix(UInt opc2)
17413 switch (opc2 & 0x7F) {
17414 case 0x72:
17415 return "m";
17416 case 0x52:
17417 return "p";
17418 case 0x56:
17419 return "c";
17420 case 0x32:
17421 return "z";
17422 case 0x12:
17423 return "";
17425 default: // Impossible to get here
17426 vex_printf("Unrecognized opcode %x\n", opc2);
17427 vpanic("_get_vsx_rdpi_suffix(ppc)(opc2)");
17432 * Helper function for vector/scalar double precision fp round to integer instructions.
17434 static IRExpr * _do_vsx_fp_roundToInt(IRTemp frB_I64, UInt opc2)
17437 /* The same rules apply for x{s|v}rdpi{m|p|c|z} as for floating point round operations (fri{m|n|p|z}). */
17438 IRTemp frB = newTemp(Ity_F64);
17439 IRTemp frD = newTemp(Ity_F64);
17440 IRTemp intermediateResult = newTemp(Ity_I64);
17441 IRTemp is_SNAN = newTemp(Ity_I1);
17442 IRExpr * hi32;
17443 IRExpr * rxpi_rm;
17444 switch (opc2 & 0x7F) {
17445 case 0x72:
17446 rxpi_rm = mkU32(Irrm_NegINF);
17447 break;
17448 case 0x52:
17449 rxpi_rm = mkU32(Irrm_PosINF);
17450 break;
17451 case 0x56:
17452 rxpi_rm = get_IR_roundingmode();
17453 break;
17454 case 0x32:
17455 rxpi_rm = mkU32(Irrm_ZERO);
17456 break;
17457 case 0x12:
17458 rxpi_rm = mkU32(Irrm_NEAREST);
17459 break;
17461 default: // Impossible to get here
17462 vex_printf("Unrecognized opcode %x\n", opc2);
17463 vpanic("_do_vsx_fp_roundToInt(ppc)(opc2)");
17465 assign(frB, unop(Iop_ReinterpI64asF64, mkexpr(frB_I64)));
17466 assign( intermediateResult,
17467 binop( Iop_F64toI64S, rxpi_rm,
17468 mkexpr( frB ) ) );
17470 /* don't use the rounded integer if frB is outside -9e18..9e18 */
17471 /* F64 has only log10(2**52) significant digits anyway */
17472 /* need to preserve sign of zero */
17473 /* frD = (fabs(frB) > 9e18) ? frB :
17474 (sign(frB)) ? -fabs((double)intermediateResult) : (double)intermediateResult */
17475 assign( frD,
17476 IRExpr_ITE(
17477 binop( Iop_CmpNE8,
17478 unop( Iop_32to8,
17479 binop( Iop_CmpF64,
17480 IRExpr_Const( IRConst_F64( 9e18 ) ),
17481 unop( Iop_AbsF64, mkexpr( frB ) ) ) ),
17482 mkU8(0) ),
17483 mkexpr( frB ),
17484 IRExpr_ITE(
17485 binop( Iop_CmpNE32,
17486 binop( Iop_Shr32,
17487 unop( Iop_64HIto32,
17488 mkexpr( frB_I64 ) ),
17489 mkU8( 31 ) ),
17490 mkU32(0) ),
17491 unop( Iop_NegF64,
17492 unop( Iop_AbsF64,
17493 binop( Iop_I64StoF64,
17494 mkU32( 0 ),
17495 mkexpr( intermediateResult ) ) ) ),
17496 binop( Iop_I64StoF64,
17497 mkU32( 0 ),
17498 mkexpr( intermediateResult ) )
17503 /* See Appendix "Floating-Point Round to Integer Model" in ISA doc.
17504 * If frB is a SNAN, then frD <- frB, with bit 12 set to '1'.
17506 #define SNAN_MASK 0x0008000000000000ULL
17507 hi32 = unop( Iop_64HIto32, mkexpr(frB_I64) );
17508 assign( is_SNAN,
17509 mkAND1( is_NaN( Ity_I64, frB_I64 ),
17510 binop( Iop_CmpEQ32,
17511 binop( Iop_And32, hi32, mkU32( 0x00080000 ) ),
17512 mkU32( 0 ) ) ) );
17514 return IRExpr_ITE( mkexpr( is_SNAN ),
17515 unop( Iop_ReinterpI64asF64,
17516 binop( Iop_Xor64,
17517 mkU64( SNAN_MASK ),
17518 mkexpr( frB_I64 ) ) ),
17519 mkexpr( frD ));
17523 * Miscellaneous VSX vector instructions
17525 static Bool
17526 dis_vxv_misc ( UInt theInstr, UInt opc2 )
17528 /* XX3-Form */
17529 UChar opc1 = ifieldOPC( theInstr );
17530 UChar XT = ifieldRegXT( theInstr );
17531 UChar XB = ifieldRegXB( theInstr );
17533 if (opc1 != 0x3C) {
17534 vex_printf( "dis_vxv_misc(ppc)(instr)\n" );
17535 return False;
17538 switch (opc2) {
17539 case 0x1B4: // xvredp (VSX Vector Reciprocal Estimate Double-Precision)
17540 case 0x194: // xvrsqrtedp (VSX Vector Reciprocal Square Root Estimate
17541 // Double-Precision)
17543 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
17544 IRExpr* rm = get_IR_roundingmode();
17545 IRTemp frB = newTemp(Ity_I64);
17546 IRTemp frB2 = newTemp(Ity_I64);
17547 Bool redp = opc2 == 0x1B4;
17548 IRTemp sqrtHi = newTemp(Ity_F64);
17549 IRTemp sqrtLo = newTemp(Ity_F64);
17550 assign(frB, unop(Iop_V128HIto64, getVSReg( XB )));
17551 assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
17553 DIP("%s v%d,v%d\n", redp ? "xvredp" : "xvrsqrtedp", XT, XB);
17555 if (!redp) {
17556 assign( sqrtHi,
17557 binop( Iop_SqrtF64,
17559 unop( Iop_ReinterpI64asF64, mkexpr( frB ) ) ) );
17560 assign( sqrtLo,
17561 binop( Iop_SqrtF64,
17563 unop( Iop_ReinterpI64asF64, mkexpr( frB2 ) ) ) );
17565 putVSReg( XT,
17566 binop( Iop_64HLtoV128,
17567 unop( Iop_ReinterpF64asI64,
17568 triop( Iop_DivF64,
17570 ieee_one,
17571 redp ? unop( Iop_ReinterpI64asF64,
17572 mkexpr( frB ) )
17573 : mkexpr( sqrtHi ) ) ),
17574 unop( Iop_ReinterpF64asI64,
17575 triop( Iop_DivF64,
17577 ieee_one,
17578 redp ? unop( Iop_ReinterpI64asF64,
17579 mkexpr( frB2 ) )
17580 : mkexpr( sqrtLo ) ) ) ) );
17581 break;
17584 case 0x134: // xvresp (VSX Vector Reciprocal Estimate Single-Precision)
17585 case 0x114: // xvrsqrtesp (VSX Vector Reciprocal Square Root Estimate Single-Precision)
17587 IRTemp b3, b2, b1, b0;
17588 IRTemp res0 = newTemp(Ity_I32);
17589 IRTemp res1 = newTemp(Ity_I32);
17590 IRTemp res2 = newTemp(Ity_I32);
17591 IRTemp res3 = newTemp(Ity_I32);
17592 IRTemp sqrt3 = newTemp(Ity_F64);
17593 IRTemp sqrt2 = newTemp(Ity_F64);
17594 IRTemp sqrt1 = newTemp(Ity_F64);
17595 IRTemp sqrt0 = newTemp(Ity_F64);
17596 IRExpr* rm = get_IR_roundingmode();
17597 Bool resp = opc2 == 0x134;
17599 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
17601 b3 = b2 = b1 = b0 = IRTemp_INVALID;
17602 DIP("%s v%d,v%d\n", resp ? "xvresp" : "xvrsqrtesp", XT, XB);
17603 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
17605 if (!resp) {
17606 assign( sqrt3, binop( Iop_SqrtF64, rm, mkexpr( b3 ) ) );
17607 assign( sqrt2, binop( Iop_SqrtF64, rm, mkexpr( b2 ) ) );
17608 assign( sqrt1, binop( Iop_SqrtF64, rm, mkexpr( b1 ) ) );
17609 assign( sqrt0, binop( Iop_SqrtF64, rm, mkexpr( b0 ) ) );
17612 assign( res0,
17613 unop( Iop_ReinterpF32asI32,
17614 unop( Iop_TruncF64asF32,
17615 triop( Iop_DivF64r32,
17617 ieee_one,
17618 resp ? mkexpr( b0 ) : mkexpr( sqrt0 ) ) ) ) );
17619 assign( res1,
17620 unop( Iop_ReinterpF32asI32,
17621 unop( Iop_TruncF64asF32,
17622 triop( Iop_DivF64r32,
17624 ieee_one,
17625 resp ? mkexpr( b1 ) : mkexpr( sqrt1 ) ) ) ) );
17626 assign( res2,
17627 unop( Iop_ReinterpF32asI32,
17628 unop( Iop_TruncF64asF32,
17629 triop( Iop_DivF64r32,
17631 ieee_one,
17632 resp ? mkexpr( b2 ) : mkexpr( sqrt2 ) ) ) ) );
17633 assign( res3,
17634 unop( Iop_ReinterpF32asI32,
17635 unop( Iop_TruncF64asF32,
17636 triop( Iop_DivF64r32,
17638 ieee_one,
17639 resp ? mkexpr( b3 ) : mkexpr( sqrt3 ) ) ) ) );
17640 putVSReg( XT,
17641 binop( Iop_64HLtoV128,
17642 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
17643 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
17644 break;
17646 case 0x300: // xvmaxsp (VSX Vector Maximum Single-Precision)
17647 case 0x320: // xvminsp (VSX Vector Minimum Single-Precision)
17649 UChar XA = ifieldRegXA( theInstr );
17650 IRTemp a3, a2, a1, a0;
17651 IRTemp b3, b2, b1, b0;
17652 IRTemp res0 = newTemp( Ity_I32 );
17653 IRTemp res1 = newTemp( Ity_I32 );
17654 IRTemp res2 = newTemp( Ity_I32 );
17655 IRTemp res3 = newTemp( Ity_I32 );
17656 IRTemp a0_I64 = newTemp( Ity_I64 );
17657 IRTemp a1_I64 = newTemp( Ity_I64 );
17658 IRTemp a2_I64 = newTemp( Ity_I64 );
17659 IRTemp a3_I64 = newTemp( Ity_I64 );
17660 IRTemp b0_I64 = newTemp( Ity_I64 );
17661 IRTemp b1_I64 = newTemp( Ity_I64 );
17662 IRTemp b2_I64 = newTemp( Ity_I64 );
17663 IRTemp b3_I64 = newTemp( Ity_I64 );
17665 Bool isMin = opc2 == 0x320 ? True : False;
17667 a3 = a2 = a1 = a0 = IRTemp_INVALID;
17668 b3 = b2 = b1 = b0 = IRTemp_INVALID;
17669 DIP("%s v%d,v%d v%d\n", isMin ? "xvminsp" : "xvmaxsp", XT, XA, XB);
17670 breakV128to4xF64( getVSReg( XA ), &a3, &a2, &a1, &a0 );
17671 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
17672 assign( a0_I64, unop( Iop_ReinterpF64asI64, mkexpr( a0 ) ) );
17673 assign( b0_I64, unop( Iop_ReinterpF64asI64, mkexpr( b0 ) ) );
17674 assign( a1_I64, unop( Iop_ReinterpF64asI64, mkexpr( a1 ) ) );
17675 assign( b1_I64, unop( Iop_ReinterpF64asI64, mkexpr( b1 ) ) );
17676 assign( a2_I64, unop( Iop_ReinterpF64asI64, mkexpr( a2 ) ) );
17677 assign( b2_I64, unop( Iop_ReinterpF64asI64, mkexpr( b2 ) ) );
17678 assign( a3_I64, unop( Iop_ReinterpF64asI64, mkexpr( a3 ) ) );
17679 assign( b3_I64, unop( Iop_ReinterpF64asI64, mkexpr( b3 ) ) );
17680 assign( res0,
17681 unop( Iop_ReinterpF32asI32,
17682 unop( Iop_TruncF64asF32,
17683 unop( Iop_ReinterpI64asF64,
17684 get_max_min_fp( a0_I64, b0_I64, isMin ) ) ) ) );
17685 assign( res1,
17686 unop( Iop_ReinterpF32asI32,
17687 unop( Iop_TruncF64asF32,
17688 unop( Iop_ReinterpI64asF64,
17689 get_max_min_fp( a1_I64, b1_I64, isMin ) ) ) ) );
17690 assign( res2,
17691 unop( Iop_ReinterpF32asI32,
17692 unop( Iop_TruncF64asF32,
17693 unop( Iop_ReinterpI64asF64,
17694 get_max_min_fp( a2_I64, b2_I64, isMin ) ) ) ) );
17695 assign( res3,
17696 unop( Iop_ReinterpF32asI32,
17697 unop( Iop_TruncF64asF32,
17698 unop( Iop_ReinterpI64asF64,
17699 get_max_min_fp( a3_I64, b3_I64, isMin ) ) ) ) );
17700 putVSReg( XT,
17701 binop( Iop_64HLtoV128,
17702 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
17703 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
17704 break;
17706 case 0x380: // xvmaxdp (VSX Vector Maximum Double-Precision)
17707 case 0x3A0: // xvmindp (VSX Vector Minimum Double-Precision)
17709 UChar XA = ifieldRegXA( theInstr );
17710 IRTemp frA = newTemp(Ity_I64);
17711 IRTemp frB = newTemp(Ity_I64);
17712 IRTemp frA2 = newTemp(Ity_I64);
17713 IRTemp frB2 = newTemp(Ity_I64);
17714 Bool isMin = opc2 == 0x3A0 ? True : False;
17716 assign(frA, unop(Iop_V128HIto64, getVSReg( XA )));
17717 assign(frB, unop(Iop_V128HIto64, getVSReg( XB )));
17718 assign(frA2, unop(Iop_V128to64, getVSReg( XA )));
17719 assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
17720 DIP("%s v%d,v%d v%d\n", isMin ? "xvmindp" : "xvmaxdp", XT, XA, XB);
17721 putVSReg( XT, binop( Iop_64HLtoV128, get_max_min_fp(frA, frB, isMin), get_max_min_fp(frA2, frB2, isMin) ) );
17723 break;
17725 case 0x3c0: // xvcpsgndp (VSX Vector Copy Sign Double-Precision)
17727 UChar XA = ifieldRegXA( theInstr );
17728 IRTemp frA = newTemp(Ity_I64);
17729 IRTemp frB = newTemp(Ity_I64);
17730 IRTemp frA2 = newTemp(Ity_I64);
17731 IRTemp frB2 = newTemp(Ity_I64);
17732 assign(frA, unop(Iop_V128HIto64, getVSReg( XA )));
17733 assign(frB, unop(Iop_V128HIto64, getVSReg( XB )));
17734 assign(frA2, unop(Iop_V128to64, getVSReg( XA )));
17735 assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
17737 DIP("xvcpsgndp v%d,v%d,v%d\n", XT, XA, XB);
17738 putVSReg( XT,
17739 binop( Iop_64HLtoV128,
17740 binop( Iop_Or64,
17741 binop( Iop_And64,
17742 mkexpr( frA ),
17743 mkU64( SIGN_BIT ) ),
17744 binop( Iop_And64,
17745 mkexpr( frB ),
17746 mkU64( SIGN_MASK ) ) ),
17747 binop( Iop_Or64,
17748 binop( Iop_And64,
17749 mkexpr( frA2 ),
17750 mkU64( SIGN_BIT ) ),
17751 binop( Iop_And64,
17752 mkexpr( frB2 ),
17753 mkU64( SIGN_MASK ) ) ) ) );
17754 break;
17756 case 0x340: // xvcpsgnsp
17758 UChar XA = ifieldRegXA( theInstr );
17759 IRTemp a3_I64, a2_I64, a1_I64, a0_I64;
17760 IRTemp b3_I64, b2_I64, b1_I64, b0_I64;
17761 IRTemp resHi = newTemp(Ity_I64);
17762 IRTemp resLo = newTemp(Ity_I64);
17764 a3_I64 = a2_I64 = a1_I64 = a0_I64 = IRTemp_INVALID;
17765 b3_I64 = b2_I64 = b1_I64 = b0_I64 = IRTemp_INVALID;
17766 DIP("xvcpsgnsp v%d,v%d v%d\n",XT, XA, XB);
17767 breakV128to4x64U( getVSReg( XA ), &a3_I64, &a2_I64, &a1_I64, &a0_I64 );
17768 breakV128to4x64U( getVSReg( XB ), &b3_I64, &b2_I64, &b1_I64, &b0_I64 );
17770 assign( resHi,
17771 binop( Iop_32HLto64,
17772 binop( Iop_Or32,
17773 binop( Iop_And32,
17774 unop(Iop_64to32, mkexpr( a3_I64 ) ),
17775 mkU32( SIGN_BIT32 ) ),
17776 binop( Iop_And32,
17777 unop(Iop_64to32, mkexpr( b3_I64 ) ),
17778 mkU32( SIGN_MASK32) ) ),
17780 binop( Iop_Or32,
17781 binop( Iop_And32,
17782 unop(Iop_64to32, mkexpr( a2_I64 ) ),
17783 mkU32( SIGN_BIT32 ) ),
17784 binop( Iop_And32,
17785 unop(Iop_64to32, mkexpr( b2_I64 ) ),
17786 mkU32( SIGN_MASK32 ) ) ) ) );
17787 assign( resLo,
17788 binop( Iop_32HLto64,
17789 binop( Iop_Or32,
17790 binop( Iop_And32,
17791 unop(Iop_64to32, mkexpr( a1_I64 ) ),
17792 mkU32( SIGN_BIT32 ) ),
17793 binop( Iop_And32,
17794 unop(Iop_64to32, mkexpr( b1_I64 ) ),
17795 mkU32( SIGN_MASK32 ) ) ),
17797 binop( Iop_Or32,
17798 binop( Iop_And32,
17799 unop(Iop_64to32, mkexpr( a0_I64 ) ),
17800 mkU32( SIGN_BIT32 ) ),
17801 binop( Iop_And32,
17802 unop(Iop_64to32, mkexpr( b0_I64 ) ),
17803 mkU32( SIGN_MASK32 ) ) ) ) );
17804 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( resHi ), mkexpr( resLo ) ) );
17805 break;
17807 case 0x3B2: // xvabsdp (VSX Vector Absolute Value Double-Precision)
17808 case 0x3D2: // xvnabsdp VSX Vector Negative Absolute Value Double-Precision)
17810 IRTemp frB = newTemp(Ity_F64);
17811 IRTemp frB2 = newTemp(Ity_F64);
17812 IRTemp abs_resultHi = newTemp(Ity_F64);
17813 IRTemp abs_resultLo = newTemp(Ity_F64);
17814 Bool make_negative = (opc2 == 0x3D2) ? True : False;
17815 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
17816 assign(frB2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg(XB))));
17818 DIP("xv%sabsdp v%d,v%d\n", make_negative ? "n" : "", XT, XB);
17819 if (make_negative) {
17820 assign(abs_resultHi, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr( frB ) ) ) );
17821 assign(abs_resultLo, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr( frB2 ) ) ) );
17823 } else {
17824 assign(abs_resultHi, unop( Iop_AbsF64, mkexpr( frB ) ) );
17825 assign(abs_resultLo, unop( Iop_AbsF64, mkexpr( frB2 ) ) );
17827 putVSReg( XT, binop( Iop_64HLtoV128,
17828 unop( Iop_ReinterpF64asI64, mkexpr( abs_resultHi ) ),
17829 unop( Iop_ReinterpF64asI64, mkexpr( abs_resultLo ) ) ) );
17830 break;
17832 case 0x332: // xvabssp (VSX Vector Absolute Value Single-Precision)
17833 case 0x352: // xvnabssp (VSX Vector Negative Absolute Value Single-Precision)
17836 * The Iop_AbsF32 IRop is not implemented for ppc64 since, up until introduction
17837 * of xvabssp, there has not been an abs(sp) type of instruction. But since emulation
17838 * of this function is so easy using shifts, I choose to emulate this instruction that
17839 * way versus a native instruction method of implementation.
17841 Bool make_negative = (opc2 == 0x352) ? True : False;
17842 IRTemp shiftVector = newTemp(Ity_V128);
17843 IRTemp absVal_vector = newTemp(Ity_V128);
17844 assign( shiftVector,
17845 binop( Iop_64HLtoV128,
17846 binop( Iop_32HLto64, mkU32( 1 ), mkU32( 1 ) ),
17847 binop( Iop_32HLto64, mkU32( 1 ), mkU32( 1 ) ) ) );
17848 assign( absVal_vector,
17849 binop( Iop_Shr32x4,
17850 binop( Iop_Shl32x4,
17851 getVSReg( XB ),
17852 mkexpr( shiftVector ) ),
17853 mkexpr( shiftVector ) ) );
17854 if (make_negative) {
17855 IRTemp signBit_vector = newTemp(Ity_V128);
17856 assign( signBit_vector,
17857 binop( Iop_64HLtoV128,
17858 binop( Iop_32HLto64,
17859 mkU32( 0x80000000 ),
17860 mkU32( 0x80000000 ) ),
17861 binop( Iop_32HLto64,
17862 mkU32( 0x80000000 ),
17863 mkU32( 0x80000000 ) ) ) );
17864 putVSReg( XT,
17865 binop( Iop_OrV128,
17866 mkexpr( absVal_vector ),
17867 mkexpr( signBit_vector ) ) );
17868 } else {
17869 putVSReg( XT, mkexpr( absVal_vector ) );
17871 break;
17873 case 0x3F2: // xvnegdp (VSX Vector Negate Double-Precision)
17875 IRTemp frB = newTemp(Ity_F64);
17876 IRTemp frB2 = newTemp(Ity_F64);
17877 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
17878 assign(frB2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg(XB))));
17879 DIP("xvnegdp v%d,v%d\n", XT, XB);
17880 putVSReg( XT,
17881 binop( Iop_64HLtoV128,
17882 unop( Iop_ReinterpF64asI64,
17883 unop( Iop_NegF64, mkexpr( frB ) ) ),
17884 unop( Iop_ReinterpF64asI64,
17885 unop( Iop_NegF64, mkexpr( frB2 ) ) ) ) );
17886 break;
17888 case 0x192: // xvrdpi (VSX Vector Round to Double-Precision Integer using round toward Nearest Away)
17889 case 0x1D6: // xvrdpic (VSX Vector Round to Double-Precision Integer using Current rounding mode)
17890 case 0x1F2: // xvrdpim (VSX Vector Round to Double-Precision Integer using round toward -Infinity)
17891 case 0x1D2: // xvrdpip (VSX Vector Round to Double-Precision Integer using round toward +Infinity)
17892 case 0x1B2: // xvrdpiz (VSX Vector Round to Double-Precision Integer using round toward Zero)
17894 IRTemp frBHi_I64 = newTemp(Ity_I64);
17895 IRTemp frBLo_I64 = newTemp(Ity_I64);
17896 IRExpr * frD_fp_roundHi = NULL;
17897 IRExpr * frD_fp_roundLo = NULL;
17899 assign( frBHi_I64, unop( Iop_V128HIto64, getVSReg( XB ) ) );
17900 frD_fp_roundHi = _do_vsx_fp_roundToInt(frBHi_I64, opc2);
17901 assign( frBLo_I64, unop( Iop_V128to64, getVSReg( XB ) ) );
17902 frD_fp_roundLo = _do_vsx_fp_roundToInt(frBLo_I64, opc2);
17904 DIP("xvrdpi%s v%d,v%d\n", _get_vsx_rdpi_suffix(opc2), XT, XB);
17905 putVSReg( XT,
17906 binop( Iop_64HLtoV128,
17907 unop( Iop_ReinterpF64asI64, frD_fp_roundHi ),
17908 unop( Iop_ReinterpF64asI64, frD_fp_roundLo ) ) );
17909 break;
17911 case 0x112: // xvrspi (VSX Vector Round to Single-Precision Integer using round toward Nearest Away)
17912 case 0x156: // xvrspic (VSX Vector Round to SinglePrecision Integer using Current rounding mode)
17913 case 0x172: // xvrspim (VSX Vector Round to SinglePrecision Integer using round toward -Infinity)
17914 case 0x152: // xvrspip (VSX Vector Round to SinglePrecision Integer using round toward +Infinity)
17915 case 0x132: // xvrspiz (VSX Vector Round to SinglePrecision Integer using round toward Zero)
17917 const HChar * insn_suffix = NULL;
17918 IROp op;
17919 if (opc2 != 0x156) {
17920 // Use pre-defined IRop's for vrfi{m|n|p|z}
17921 switch (opc2) {
17922 case 0x112:
17923 insn_suffix = "";
17924 op = Iop_RoundF32x4_RN;
17925 break;
17926 case 0x172:
17927 insn_suffix = "m";
17928 op = Iop_RoundF32x4_RM;
17929 break;
17930 case 0x152:
17931 insn_suffix = "p";
17932 op = Iop_RoundF32x4_RP;
17933 break;
17934 case 0x132:
17935 insn_suffix = "z";
17936 op = Iop_RoundF32x4_RZ;
17937 break;
17939 default:
17940 vex_printf("Unrecognized opcode %x\n", opc2);
17941 vpanic("dis_vxv_misc(ppc)(vrspi<x>)(opc2)\n");
17943 DIP("xvrspi%s v%d,v%d\n", insn_suffix, XT, XB);
17944 putVSReg( XT, unop( op, getVSReg(XB) ) );
17945 } else {
17946 // Handle xvrspic. Unfortunately there is no corresponding "vfric" instruction.
17947 IRExpr * frD_fp_roundb3, * frD_fp_roundb2, * frD_fp_roundb1, * frD_fp_roundb0;
17948 IRTemp b3_F64, b2_F64, b1_F64, b0_F64;
17949 IRTemp b3_I64 = newTemp(Ity_I64);
17950 IRTemp b2_I64 = newTemp(Ity_I64);
17951 IRTemp b1_I64 = newTemp(Ity_I64);
17952 IRTemp b0_I64 = newTemp(Ity_I64);
17954 b3_F64 = b2_F64 = b1_F64 = b0_F64 = IRTemp_INVALID;
17955 frD_fp_roundb3 = frD_fp_roundb2 = frD_fp_roundb1 = frD_fp_roundb0 = NULL;
17956 breakV128to4xF64( getVSReg(XB), &b3_F64, &b2_F64, &b1_F64, &b0_F64);
17957 assign(b3_I64, unop(Iop_ReinterpF64asI64, mkexpr(b3_F64)));
17958 assign(b2_I64, unop(Iop_ReinterpF64asI64, mkexpr(b2_F64)));
17959 assign(b1_I64, unop(Iop_ReinterpF64asI64, mkexpr(b1_F64)));
17960 assign(b0_I64, unop(Iop_ReinterpF64asI64, mkexpr(b0_F64)));
17961 frD_fp_roundb3 = unop(Iop_TruncF64asF32,
17962 _do_vsx_fp_roundToInt(b3_I64, opc2));
17963 frD_fp_roundb2 = unop(Iop_TruncF64asF32,
17964 _do_vsx_fp_roundToInt(b2_I64, opc2));
17965 frD_fp_roundb1 = unop(Iop_TruncF64asF32,
17966 _do_vsx_fp_roundToInt(b1_I64, opc2));
17967 frD_fp_roundb0 = unop(Iop_TruncF64asF32,
17968 _do_vsx_fp_roundToInt(b0_I64, opc2));
17969 DIP("xvrspic v%d,v%d\n", XT, XB);
17970 putVSReg( XT,
17971 binop( Iop_64HLtoV128,
17972 binop( Iop_32HLto64,
17973 unop( Iop_ReinterpF32asI32, frD_fp_roundb3 ),
17974 unop( Iop_ReinterpF32asI32, frD_fp_roundb2 ) ),
17975 binop( Iop_32HLto64,
17976 unop( Iop_ReinterpF32asI32, frD_fp_roundb1 ),
17977 unop( Iop_ReinterpF32asI32, frD_fp_roundb0 ) ) ) );
17979 break;
17982 default:
17983 vex_printf( "dis_vxv_misc(ppc)(opc2)\n" );
17984 return False;
17986 return True;
17991 * VSX Scalar Floating Point Arithmetic Instructions
17993 static Bool
17994 dis_vxs_arith ( UInt theInstr, UInt opc2 )
17996 /* XX3-Form */
17997 UChar opc1 = ifieldOPC( theInstr );
17998 UChar XT = ifieldRegXT( theInstr );
17999 UChar XA = ifieldRegXA( theInstr );
18000 UChar XB = ifieldRegXB( theInstr );
18001 IRExpr* rm = get_IR_roundingmode();
18002 IRTemp frA = newTemp(Ity_F64);
18003 IRTemp frB = newTemp(Ity_F64);
18005 if (opc1 != 0x3C) {
18006 vex_printf( "dis_vxs_arith(ppc)(instr)\n" );
18007 return False;
18010 assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
18011 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
18013 /* For all the VSX sclar arithmetic instructions, the contents of doubleword element 1
18014 * of VSX[XT] are undefined after the operation; therefore, we can simply set
18015 * element to zero where it makes sense to do so.
18017 switch (opc2) {
18018 case 0x000: // xsaddsp (VSX Scalar Add Single-Precision)
18019 DIP("xsaddsp v%d,v%d,v%d\n", XT, XA, XB);
18020 putVSReg( XT, binop( Iop_64HLtoV128,
18021 unop( Iop_ReinterpF64asI64,
18022 binop( Iop_RoundF64toF32, rm,
18023 triop( Iop_AddF64, rm,
18024 mkexpr( frA ),
18025 mkexpr( frB ) ) ) ),
18026 mkU64( 0 ) ) );
18027 break;
18028 case 0x020: // xssubsp (VSX Scalar Subtract Single-Precision)
18029 DIP("xssubsp v%d,v%d,v%d\n", XT, XA, XB);
18030 putVSReg( XT, binop( Iop_64HLtoV128,
18031 unop( Iop_ReinterpF64asI64,
18032 binop( Iop_RoundF64toF32, rm,
18033 triop( Iop_SubF64, rm,
18034 mkexpr( frA ),
18035 mkexpr( frB ) ) ) ),
18036 mkU64( 0 ) ) );
18037 break;
18038 case 0x080: // xsadddp (VSX scalar add double-precision)
18039 DIP("xsadddp v%d,v%d,v%d\n", XT, XA, XB);
18040 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18041 triop( Iop_AddF64, rm,
18042 mkexpr( frA ),
18043 mkexpr( frB ) ) ),
18044 mkU64( 0 ) ) );
18045 break;
18046 case 0x060: // xsdivsp (VSX scalar divide single-precision)
18047 DIP("xsdivsp v%d,v%d,v%d\n", XT, XA, XB);
18048 putVSReg( XT, binop( Iop_64HLtoV128,
18049 unop( Iop_ReinterpF64asI64,
18050 binop( Iop_RoundF64toF32, rm,
18051 triop( Iop_DivF64, rm,
18052 mkexpr( frA ),
18053 mkexpr( frB ) ) ) ),
18054 mkU64( 0 ) ) );
18055 break;
18056 case 0x0E0: // xsdivdp (VSX scalar divide double-precision)
18057 DIP("xsdivdp v%d,v%d,v%d\n", XT, XA, XB);
18058 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18059 triop( Iop_DivF64, rm,
18060 mkexpr( frA ),
18061 mkexpr( frB ) ) ),
18062 mkU64( 0 ) ) );
18063 break;
18064 case 0x004: case 0x024: /* xsmaddasp, xsmaddmsp (VSX scalar multiply-add
18065 * single-precision)
18068 IRTemp frT = newTemp(Ity_F64);
18069 Bool mdp = opc2 == 0x024;
18070 DIP("xsmadd%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18071 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18072 getVSReg( XT ) ) ) );
18073 putVSReg( XT,
18074 binop( Iop_64HLtoV128,
18075 unop( Iop_ReinterpF64asI64,
18076 binop( Iop_RoundF64toF32, rm,
18077 qop( Iop_MAddF64, rm,
18078 mkexpr( frA ),
18079 mkexpr( mdp ? frT : frB ),
18080 mkexpr( mdp ? frB : frT ) ) ) ),
18081 mkU64( 0 ) ) );
18082 break;
18084 case 0x084: case 0x0A4: // xsmaddadp, xsmaddmdp (VSX scalar multiply-add double-precision)
18086 IRTemp frT = newTemp(Ity_F64);
18087 Bool mdp = opc2 == 0x0A4;
18088 DIP("xsmadd%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18089 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18090 getVSReg( XT ) ) ) );
18091 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18092 qop( Iop_MAddF64, rm,
18093 mkexpr( frA ),
18094 mkexpr( mdp ? frT : frB ),
18095 mkexpr( mdp ? frB : frT ) ) ),
18096 mkU64( 0 ) ) );
18097 break;
18099 case 0x044: case 0x064: /* xsmsubasp, xsmsubmsp (VSX scalar
18100 * multiply-subtract single-precision)
18103 IRTemp frT = newTemp(Ity_F64);
18104 Bool mdp = opc2 == 0x064;
18105 DIP("xsmsub%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18106 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18107 getVSReg( XT ) ) ) );
18108 putVSReg( XT,
18109 binop( Iop_64HLtoV128,
18110 unop( Iop_ReinterpF64asI64,
18111 binop( Iop_RoundF64toF32, rm,
18112 qop( Iop_MSubF64, rm,
18113 mkexpr( frA ),
18114 mkexpr( mdp ? frT : frB ),
18115 mkexpr( mdp ? frB : frT ) ) ) ),
18116 mkU64( 0 ) ) );
18117 break;
18119 case 0x0C4: case 0x0E4: // xsmsubadp, xsmsubmdp (VSX scalar multiply-subtract double-precision)
18121 IRTemp frT = newTemp(Ity_F64);
18122 Bool mdp = opc2 == 0x0E4;
18123 DIP("xsmsub%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18124 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18125 getVSReg( XT ) ) ) );
18126 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18127 qop( Iop_MSubF64, rm,
18128 mkexpr( frA ),
18129 mkexpr( mdp ? frT : frB ),
18130 mkexpr( mdp ? frB : frT ) ) ),
18131 mkU64( 0 ) ) );
18132 break;
18134 case 0x284: case 0x2A4: // xsnmaddadp, xsnmaddmdp (VSX scalar multiply-add double-precision)
18136 /* TODO: mpj -- Naturally, I expected to be able to leverage the implementation
18137 * of fnmadd and use pretty much the same code. However, that code has a bug in the
18138 * way it blindly negates the signbit, even if the floating point result is a NaN.
18139 * So, the TODO is to fix fnmadd (which I'll do in a different patch).
18140 * FIXED 7/1/2012: carll fnmadd and fnmsubs fixed to not negate sign
18141 * bit for NaN result.
18143 Bool mdp = opc2 == 0x2A4;
18144 IRTemp frT = newTemp(Ity_F64);
18145 IRTemp maddResult = newTemp(Ity_I64);
18147 DIP("xsnmadd%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18148 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18149 getVSReg( XT ) ) ) );
18150 assign( maddResult, unop( Iop_ReinterpF64asI64, qop( Iop_MAddF64, rm,
18151 mkexpr( frA ),
18152 mkexpr( mdp ? frT : frB ),
18153 mkexpr( mdp ? frB : frT ) ) ) );
18155 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( getNegatedResult(maddResult) ),
18156 mkU64( 0 ) ) );
18157 break;
18159 case 0x204: case 0x224: /* xsnmaddasp, xsnmaddmsp (VSX scalar
18160 * multiply-add single-precision)
18163 Bool mdp = opc2 == 0x224;
18164 IRTemp frT = newTemp(Ity_F64);
18165 IRTemp maddResult = newTemp(Ity_I64);
18167 DIP("xsnmadd%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18168 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18169 getVSReg( XT ) ) ) );
18170 assign( maddResult,
18171 unop( Iop_ReinterpF64asI64,
18172 binop( Iop_RoundF64toF32, rm,
18173 qop( Iop_MAddF64, rm,
18174 mkexpr( frA ),
18175 mkexpr( mdp ? frT : frB ),
18176 mkexpr( mdp ? frB : frT ) ) ) ) );
18178 putVSReg( XT, binop( Iop_64HLtoV128,
18179 mkexpr( getNegatedResult(maddResult) ),
18180 mkU64( 0 ) ) );
18181 break;
18183 case 0x244: case 0x264: /* xsnmsubasp, xsnmsubmsp (VSX Scalar Negative
18184 * Multiply-Subtract Single-Precision)
18187 IRTemp frT = newTemp(Ity_F64);
18188 Bool mdp = opc2 == 0x264;
18189 IRTemp msubResult = newTemp(Ity_I64);
18191 DIP("xsnmsub%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18192 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18193 getVSReg( XT ) ) ) );
18194 assign( msubResult,
18195 unop( Iop_ReinterpF64asI64,
18196 binop( Iop_RoundF64toF32, rm,
18197 qop( Iop_MSubF64, rm,
18198 mkexpr( frA ),
18199 mkexpr( mdp ? frT : frB ),
18200 mkexpr( mdp ? frB : frT ) ) ) ) );
18202 putVSReg( XT, binop( Iop_64HLtoV128,
18203 mkexpr( getNegatedResult(msubResult) ),
18204 mkU64( 0 ) ) );
18206 break;
18209 case 0x2C4: case 0x2E4: // xsnmsubadp, xsnmsubmdp (VSX Scalar Negative Multiply-Subtract Double-Precision)
18211 IRTemp frT = newTemp(Ity_F64);
18212 Bool mdp = opc2 == 0x2E4;
18213 IRTemp msubResult = newTemp(Ity_I64);
18215 DIP("xsnmsub%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", XT, XA, XB);
18216 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
18217 getVSReg( XT ) ) ) );
18218 assign(msubResult, unop( Iop_ReinterpF64asI64,
18219 qop( Iop_MSubF64,
18221 mkexpr( frA ),
18222 mkexpr( mdp ? frT : frB ),
18223 mkexpr( mdp ? frB : frT ) ) ));
18225 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( getNegatedResult(msubResult) ), mkU64( 0 ) ) );
18227 break;
18230 case 0x040: // xsmulsp (VSX Scalar Multiply Single-Precision)
18231 DIP("xsmulsp v%d,v%d,v%d\n", XT, XA, XB);
18232 putVSReg( XT, binop( Iop_64HLtoV128,
18233 unop( Iop_ReinterpF64asI64,
18234 binop( Iop_RoundF64toF32, rm,
18235 triop( Iop_MulF64, rm,
18236 mkexpr( frA ),
18237 mkexpr( frB ) ) ) ),
18238 mkU64( 0 ) ) );
18239 break;
18241 case 0x0C0: // xsmuldp (VSX Scalar Multiply Double-Precision)
18242 DIP("xsmuldp v%d,v%d,v%d\n", XT, XA, XB);
18243 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18244 triop( Iop_MulF64, rm,
18245 mkexpr( frA ),
18246 mkexpr( frB ) ) ),
18247 mkU64( 0 ) ) );
18248 break;
18249 case 0x0A0: // xssubdp (VSX Scalar Subtract Double-Precision)
18250 DIP("xssubdp v%d,v%d,v%d\n", XT, XA, XB);
18251 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18252 triop( Iop_SubF64, rm,
18253 mkexpr( frA ),
18254 mkexpr( frB ) ) ),
18255 mkU64( 0 ) ) );
18256 break;
18258 case 0x016: // xssqrtsp (VSX Scalar Square Root Single-Precision)
18259 DIP("xssqrtsp v%d,v%d\n", XT, XB);
18260 putVSReg( XT,
18261 binop( Iop_64HLtoV128,
18262 unop( Iop_ReinterpF64asI64,
18263 binop( Iop_RoundF64toF32, rm,
18264 binop( Iop_SqrtF64, rm,
18265 mkexpr( frB ) ) ) ),
18266 mkU64( 0 ) ) );
18267 break;
18269 case 0x096: // xssqrtdp (VSX Scalar Square Root Double-Precision)
18270 DIP("xssqrtdp v%d,v%d\n", XT, XB);
18271 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
18272 binop( Iop_SqrtF64, rm,
18273 mkexpr( frB ) ) ),
18274 mkU64( 0 ) ) );
18275 break;
18277 case 0x0F4: // xstdivdp (VSX Scalar Test for software Divide Double-Precision)
18279 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
18280 IRTemp frA_I64 = newTemp(Ity_I64);
18281 IRTemp frB_I64 = newTemp(Ity_I64);
18282 DIP("xstdivdp crf%d,v%d,v%d\n", crfD, XA, XB);
18283 assign( frA_I64, unop( Iop_ReinterpF64asI64, mkexpr( frA ) ) );
18284 assign( frB_I64, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
18285 putGST_field( PPC_GST_CR, do_fp_tdiv(frA_I64, frB_I64), crfD );
18286 break;
18288 case 0x0D4: // xstsqrtdp (VSX Vector Test for software Square Root Double-Precision)
18290 IRTemp frB_I64 = newTemp(Ity_I64);
18291 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
18292 IRTemp flags = newTemp(Ity_I32);
18293 IRTemp fe_flag, fg_flag;
18294 fe_flag = fg_flag = IRTemp_INVALID;
18295 DIP("xstsqrtdp v%d,v%d\n", XT, XB);
18296 assign( frB_I64, unop(Iop_V128HIto64, getVSReg( XB )) );
18297 do_fp_tsqrt(frB_I64, False /*not single precision*/, &fe_flag, &fg_flag);
18298 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
18299 * where fl_flag == 1 on ppc64.
18301 assign( flags,
18302 binop( Iop_Or32,
18303 binop( Iop_Or32, mkU32( 8 ), // fl_flag
18304 binop( Iop_Shl32, mkexpr(fg_flag), mkU8( 2 ) ) ),
18305 binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) ) );
18306 putGST_field( PPC_GST_CR, mkexpr(flags), crfD );
18307 break;
18310 default:
18311 vex_printf( "dis_vxs_arith(ppc)(opc2)\n" );
18312 return False;
18315 return True;
18320 * VSX Floating Point Compare Instructions
18322 static Bool
18323 dis_vx_cmp( UInt theInstr, UInt opc2 )
18325 /* XX3-Form and XX2-Form */
18326 UChar opc1 = ifieldOPC( theInstr );
18327 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
18328 IRTemp ccPPC32;
18329 UChar XA = ifieldRegXA ( theInstr );
18330 UChar XB = ifieldRegXB ( theInstr );
18331 IRTemp frA = newTemp(Ity_F64);
18332 IRTemp frB = newTemp(Ity_F64);
18334 if (opc1 != 0x3C) {
18335 vex_printf( "dis_vx_cmp(ppc)(instr)\n" );
18336 return False;
18339 assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
18340 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
18341 switch (opc2) {
18342 case 0x08C: case 0x0AC: // xscmpudp, xscmpodp
18343 /* Note: Differences between xscmpudp and xscmpodp are only in
18344 * exception flag settings, which aren't supported anyway. */
18345 DIP("xscmp%sdp crf%d,fr%u,fr%u\n", opc2 == 0x08c ? "u" : "o",
18346 crfD, XA, XB);
18347 ccPPC32 = get_fp_cmp_CR_val( binop(Iop_CmpF64, mkexpr(frA), mkexpr(frB)));
18348 putGST_field( PPC_GST_CR, mkexpr(ccPPC32), crfD );
18349 putFPCC( mkexpr( ccPPC32 ) );
18350 break;
18352 default:
18353 vex_printf( "dis_vx_cmp(ppc)(opc2)\n" );
18354 return False;
18356 return True;
18359 static void
18360 do_vvec_fp_cmp ( IRTemp vA, IRTemp vB, UChar XT, UChar flag_rC,
18361 ppc_cmp_t cmp_type )
18363 IRTemp frA_hi = newTemp(Ity_F64);
18364 IRTemp frB_hi = newTemp(Ity_F64);
18365 IRTemp frA_lo = newTemp(Ity_F64);
18366 IRTemp frB_lo = newTemp(Ity_F64);
18367 IRTemp ccPPC32 = newTemp(Ity_I32);
18368 IRTemp ccIR_hi;
18369 IRTemp ccIR_lo;
18371 IRTemp hiResult = newTemp(Ity_I64);
18372 IRTemp loResult = newTemp(Ity_I64);
18373 IRTemp hiEQlo = newTemp(Ity_I1);
18374 IRTemp all_elem_true = newTemp(Ity_I32);
18375 IRTemp all_elem_false = newTemp(Ity_I32);
18377 assign(frA_hi, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, mkexpr( vA ))));
18378 assign(frB_hi, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, mkexpr( vB ))));
18379 assign(frA_lo, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, mkexpr( vA ))));
18380 assign(frB_lo, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, mkexpr( vB ))));
18382 ccIR_hi = get_fp_cmp_CR_val( binop( Iop_CmpF64,
18383 mkexpr( frA_hi ),
18384 mkexpr( frB_hi ) ) );
18385 ccIR_lo = get_fp_cmp_CR_val( binop( Iop_CmpF64,
18386 mkexpr( frA_lo ),
18387 mkexpr( frB_lo ) ) );
18389 if (cmp_type != PPC_CMP_GE) {
18390 assign( hiResult,
18391 unop( Iop_1Sto64,
18392 binop( Iop_CmpEQ32, mkexpr( ccIR_hi ), mkU32( cmp_type ) ) ) );
18393 assign( loResult,
18394 unop( Iop_1Sto64,
18395 binop( Iop_CmpEQ32, mkexpr( ccIR_lo ), mkU32( cmp_type ) ) ) );
18396 } else {
18397 // For PPC_CMP_GE, one element compare may return "4" (for "greater than") and
18398 // the other element compare may return "2" (for "equal to").
18399 IRTemp lo_GE = newTemp(Ity_I1);
18400 IRTemp hi_GE = newTemp(Ity_I1);
18402 assign(hi_GE, mkOR1( binop( Iop_CmpEQ32, mkexpr( ccIR_hi ), mkU32( 2 ) ),
18403 binop( Iop_CmpEQ32, mkexpr( ccIR_hi ), mkU32( 4 ) ) ) );
18404 assign( hiResult,unop( Iop_1Sto64, mkexpr( hi_GE ) ) );
18406 assign(lo_GE, mkOR1( binop( Iop_CmpEQ32, mkexpr( ccIR_lo ), mkU32( 2 ) ),
18407 binop( Iop_CmpEQ32, mkexpr( ccIR_lo ), mkU32( 4 ) ) ) );
18408 assign( loResult, unop( Iop_1Sto64, mkexpr( lo_GE ) ) );
18411 // The [hi/lo]Result will be all 1's or all 0's. We just look at the lower word.
18412 assign( hiEQlo,
18413 binop( Iop_CmpEQ32,
18414 unop( Iop_64to32, mkexpr( hiResult ) ),
18415 unop( Iop_64to32, mkexpr( loResult ) ) ) );
18416 putVSReg( XT,
18417 binop( Iop_64HLtoV128, mkexpr( hiResult ), mkexpr( loResult ) ) );
18419 assign( all_elem_true,
18420 unop( Iop_1Uto32,
18421 mkAND1( mkexpr( hiEQlo ),
18422 binop( Iop_CmpEQ32,
18423 mkU32( 0xffffffff ),
18424 unop( Iop_64to32,
18425 mkexpr( hiResult ) ) ) ) ) );
18427 assign( all_elem_false,
18428 unop( Iop_1Uto32,
18429 mkAND1( mkexpr( hiEQlo ),
18430 binop( Iop_CmpEQ32,
18431 mkU32( 0 ),
18432 unop( Iop_64to32,
18433 mkexpr( hiResult ) ) ) ) ) );
18434 assign( ccPPC32,
18435 binop( Iop_Or32,
18436 binop( Iop_Shl32, mkexpr( all_elem_false ), mkU8( 1 ) ),
18437 binop( Iop_Shl32, mkexpr( all_elem_true ), mkU8( 3 ) ) ) );
18439 if (flag_rC) {
18440 putGST_field( PPC_GST_CR, mkexpr(ccPPC32), 6 );
18445 * VSX Vector Compare Instructions
18447 static Bool
18448 dis_vvec_cmp( UInt theInstr, UInt opc2 )
18450 /* XX3-Form */
18451 UChar opc1 = ifieldOPC( theInstr );
18452 UChar XT = ifieldRegXT ( theInstr );
18453 UChar XA = ifieldRegXA ( theInstr );
18454 UChar XB = ifieldRegXB ( theInstr );
18455 UChar flag_rC = ifieldBIT10(theInstr);
18456 IRTemp vA = newTemp( Ity_V128 );
18457 IRTemp vB = newTemp( Ity_V128 );
18459 if (opc1 != 0x3C) {
18460 vex_printf( "dis_vvec_cmp(ppc)(instr)\n" );
18461 return False;
18464 assign( vA, getVSReg( XA ) );
18465 assign( vB, getVSReg( XB ) );
18467 switch (opc2) {
18468 case 0x18C: // xvcmpeqdp[.] (VSX Vector Compare Equal To Double-Precision [ & Record ])
18470 DIP("xvcmpeqdp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
18471 XT, XA, XB);
18472 do_vvec_fp_cmp(vA, vB, XT, flag_rC, PPC_CMP_EQ);
18473 break;
18476 case 0x1CC: // xvcmpgedp[.] (VSX Vector Compare Greater Than or Equal To Double-Precision [ & Record ])
18478 DIP("xvcmpgedp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
18479 XT, XA, XB);
18480 do_vvec_fp_cmp(vA, vB, XT, flag_rC, PPC_CMP_GE);
18481 break;
18484 case 0x1AC: // xvcmpgtdp[.] (VSX Vector Compare Greater Than Double-Precision [ & Record ])
18486 DIP("xvcmpgtdp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
18487 XT, XA, XB);
18488 do_vvec_fp_cmp(vA, vB, XT, flag_rC, PPC_CMP_GT);
18489 break;
18492 case 0x10C: // xvcmpeqsp[.] (VSX Vector Compare Equal To Single-Precision [ & Record ])
18494 IRTemp vD = newTemp(Ity_V128);
18496 DIP("xvcmpeqsp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
18497 XT, XA, XB);
18498 assign( vD, binop(Iop_CmpEQ32Fx4, mkexpr(vA), mkexpr(vB)) );
18499 putVSReg( XT, mkexpr(vD) );
18500 if (flag_rC) {
18501 set_AV_CR6( mkexpr(vD), True );
18503 break;
18506 case 0x14C: // xvcmpgesp[.] (VSX Vector Compare Greater Than or Equal To Single-Precision [ & Record ])
18508 IRTemp vD = newTemp(Ity_V128);
18510 DIP("xvcmpgesp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
18511 XT, XA, XB);
18512 assign( vD, binop(Iop_CmpGE32Fx4, mkexpr(vA), mkexpr(vB)) );
18513 putVSReg( XT, mkexpr(vD) );
18514 if (flag_rC) {
18515 set_AV_CR6( mkexpr(vD), True );
18517 break;
18520 case 0x12C: //xvcmpgtsp[.] (VSX Vector Compare Greater Than Single-Precision [ & Record ])
18522 IRTemp vD = newTemp(Ity_V128);
18524 DIP("xvcmpgtsp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
18525 XT, XA, XB);
18526 assign( vD, binop(Iop_CmpGT32Fx4, mkexpr(vA), mkexpr(vB)) );
18527 putVSReg( XT, mkexpr(vD) );
18528 if (flag_rC) {
18529 set_AV_CR6( mkexpr(vD), True );
18531 break;
18534 default:
18535 vex_printf( "dis_vvec_cmp(ppc)(opc2)\n" );
18536 return False;
18538 return True;
18541 * Miscellaneous VSX Scalar Instructions
18543 static Bool
18544 dis_vxs_misc( UInt theInstr, const VexAbiInfo* vbi, UInt opc2,
18545 int allow_isa_3_0 )
18547 #define VG_PPC_SIGN_MASK 0x7fffffffffffffffULL
18548 /* XX3-Form and XX2-Form */
18549 UChar opc1 = ifieldOPC( theInstr );
18550 UChar XT = ifieldRegXT ( theInstr );
18551 UChar XA = ifieldRegXA ( theInstr );
18552 UChar XB = ifieldRegXB ( theInstr );
18553 IRTemp vA = newTemp( Ity_V128 );
18554 IRTemp vB = newTemp( Ity_V128 );
18556 if (opc1 != 0x3C) {
18557 vex_printf( "dis_vxs_misc(ppc)(instr)\n" );
18558 return False;
18561 assign( vA, getVSReg( XA ) );
18562 assign( vB, getVSReg( XB ) );
18564 /* For all the VSX move instructions, the contents of doubleword element 1
18565 * of VSX[XT] are undefined after the operation; therefore, we can simply
18566 * move the entire array element where it makes sense to do so.
18568 if (( opc2 == 0x168 ) && ( IFIELD( theInstr, 19, 2 ) == 0 ) )
18570 /* Special case of XX1-Form with immediate value
18571 * xxspltib (VSX Vector Splat Immediate Byte)
18573 UInt uim = IFIELD( theInstr, 11, 8 );
18574 UInt word_value = ( uim << 24 ) | ( uim << 16 ) | ( uim << 8 ) | uim;
18576 DIP("xxspltib v%d,%d\n", (UInt)XT, uim);
18577 putVSReg(XT, binop( Iop_64HLtoV128,
18578 binop( Iop_32HLto64,
18579 mkU32( word_value ),
18580 mkU32( word_value ) ),
18581 binop( Iop_32HLto64,
18582 mkU32( word_value ),
18583 mkU32( word_value ) ) ) );
18584 return True;
18587 switch ( opc2 ) {
18588 case 0x0ec: // xscmpexpdp (VSX Scalar Compare Exponents Double-Precision)
18590 /* Compare 64-bit data, 128-bit layout:
18591 src1[0:63] is double word, src1[64:127] is unused
18592 src2[0:63] is double word, src2[64:127] is unused
18594 IRExpr *bit4, *bit5, *bit6, *bit7;
18595 UInt BF = IFIELD( theInstr, 23, 3 );
18596 IRTemp eq_lt_gt = newTemp( Ity_I32 );
18597 IRTemp CC = newTemp( Ity_I32 );
18598 IRTemp vA_hi = newTemp( Ity_I64 );
18599 IRTemp vB_hi = newTemp( Ity_I64 );
18600 IRExpr *mask = mkU64( 0x7FF0000000000000 );
18602 DIP("xscmpexpdp %d,v%d,v%d\n", BF, XA, XB);
18604 assign( vA_hi, unop( Iop_V128HIto64, mkexpr( vA ) ) );
18605 assign( vB_hi, unop( Iop_V128HIto64, mkexpr( vB ) ) );
18607 /* A exp < B exp */
18608 bit4 = binop( Iop_CmpLT64U,
18609 binop( Iop_And64,
18610 mkexpr( vA_hi ),
18611 mask ),
18612 binop( Iop_And64,
18613 mkexpr( vB_hi ),
18614 mask ) );
18615 /* A exp > B exp */
18616 bit5 = binop( Iop_CmpLT64U,
18617 binop( Iop_And64,
18618 mkexpr( vB_hi ),
18619 mask ),
18620 binop( Iop_And64,
18621 mkexpr( vA_hi ),
18622 mask ) );
18623 /* test equal */
18624 bit6 = binop( Iop_CmpEQ64,
18625 binop( Iop_And64,
18626 mkexpr( vA_hi ),
18627 mask ),
18628 binop( Iop_And64,
18629 mkexpr( vB_hi ),
18630 mask ) );
18632 /* exp A or exp B is NaN */
18633 bit7 = mkOR1( is_NaN( Ity_I64, vA_hi ),
18634 is_NaN( Ity_I64, vB_hi ) );
18636 assign( eq_lt_gt, binop( Iop_Or32,
18637 binop( Iop_Shl32,
18638 unop( Iop_1Uto32, bit4 ),
18639 mkU8( 3) ),
18640 binop( Iop_Or32,
18641 binop( Iop_Shl32,
18642 unop( Iop_1Uto32, bit5 ),
18643 mkU8( 2) ),
18644 binop( Iop_Shl32,
18645 unop( Iop_1Uto32, bit6 ),
18646 mkU8( 1 ) ) ) ) );
18647 assign(CC, binop( Iop_Or32,
18648 binop( Iop_And32,
18649 mkexpr( eq_lt_gt ) ,
18650 unop( Iop_Not32, unop( Iop_1Sto32, bit7 ) ) ),
18651 unop( Iop_1Uto32, bit7 ) ) );
18653 putGST_field( PPC_GST_CR, mkexpr( CC ), BF );
18654 putFPCC( mkexpr( CC ) );
18655 return True;
18657 break;
18659 case 0x14A: // xxextractuw (VSX Vector Extract Unsigned Word)
18661 UInt uim = IFIELD( theInstr, 16, 4 );
18663 DIP("xxextractuw v%d,v%d,%d\n", (UInt)XT, (UInt)XB, uim);
18665 putVSReg( XT,
18666 binop( Iop_ShlV128,
18667 binop( Iop_AndV128,
18668 binop( Iop_ShrV128,
18669 mkexpr( vB ),
18670 mkU8( ( 12 - uim ) * 8 ) ),
18671 binop(Iop_64HLtoV128,
18672 mkU64( 0 ),
18673 mkU64( 0xFFFFFFFF ) ) ),
18674 mkU8( ( 32*2 ) ) ) );
18675 break;
18677 case 0x16A: // xxinsertw (VSX Vector insert Word)
18679 UInt uim = IFIELD( theInstr, 16, 4 );
18680 IRTemp vT = newTemp( Ity_V128 );
18681 IRTemp tmp = newTemp( Ity_V128 );
18683 DIP("xxinsertw v%d,v%d,%d\n", (UInt)XT, (UInt)XB, uim);
18685 assign( vT, getVSReg( XT ) );
18686 assign( tmp, binop( Iop_AndV128,
18687 mkexpr( vT ),
18688 unop( Iop_NotV128,
18689 binop( Iop_ShlV128,
18690 binop( Iop_64HLtoV128,
18691 mkU64( 0x0 ),
18692 mkU64( 0xFFFFFFFF) ),
18693 mkU8( ( 12 - uim ) * 8 ) ) ) ) );
18695 putVSReg( XT,
18696 binop( Iop_OrV128,
18697 binop( Iop_ShlV128,
18698 binop( Iop_AndV128,
18699 binop( Iop_ShrV128,
18700 mkexpr( vB ),
18701 mkU8( 32 * 2 ) ),
18702 binop( Iop_64HLtoV128,
18703 mkU64( 0 ),
18704 mkU64( 0xFFFFFFFF ) ) ),
18705 mkU8( ( 12 - uim ) * 8 ) ),
18706 mkexpr( tmp ) ) );
18707 break;
18710 case 0x2B2: // xsabsdp (VSX scalar absolute value double-precision
18712 /* Move abs val of dw 0 of VSX[XB] to dw 0 of VSX[XT]. */
18713 IRTemp absVal = newTemp(Ity_V128);
18714 if (host_endness == VexEndnessLE) {
18715 IRTemp hi64 = newTemp(Ity_I64);
18716 IRTemp lo64 = newTemp(Ity_I64);
18717 assign( hi64, unop( Iop_V128HIto64, mkexpr(vB) ) );
18718 assign( lo64, unop( Iop_V128to64, mkexpr(vB) ) );
18719 assign( absVal, binop( Iop_64HLtoV128,
18720 binop( Iop_And64, mkexpr(hi64),
18721 mkU64(VG_PPC_SIGN_MASK) ),
18722 mkexpr(lo64) ) );
18723 } else {
18724 assign(absVal, binop(Iop_ShrV128,
18725 binop(Iop_ShlV128, mkexpr(vB),
18726 mkU8(1)), mkU8(1)));
18728 DIP("xsabsdp v%d,v%d\n", XT, XB);
18729 putVSReg(XT, mkexpr(absVal));
18730 break;
18733 case 0x2b6: // xsxexpdp (VSX Scalar Extract Exponent Double-Precision)
18734 // xsxsigdp (VSX Scalar Extract Significand Doulbe-Precision)
18735 // xsvhpdp (VSX Scalar Convert Half-Precision format
18736 // to Double-Precision format)
18737 // xscvdphp (VSX Scalar round & convert Double-precision
18738 // format to Half-precision format)
18740 IRTemp rT = newTemp( Ity_I64 );
18741 UInt inst_select = IFIELD( theInstr, 16, 5);
18743 if (inst_select == 0) {
18744 DIP("xsxexpd %d,v%d\n", (UInt)XT, (UInt)XB);
18746 assign( rT, binop( Iop_Shr64,
18747 binop( Iop_And64,
18748 unop( Iop_V128HIto64, mkexpr( vB ) ),
18749 mkU64( 0x7FF0000000000000 ) ),
18750 mkU8 ( 52 ) ) );
18751 } else if (inst_select == 1) {
18752 IRExpr *normal;
18753 IRTemp tmp = newTemp(Ity_I64);
18755 DIP("xsxsigdp v%d,v%d\n", (UInt)XT, (UInt)XB);
18757 assign( tmp, unop( Iop_V128HIto64, mkexpr( vB ) ) );
18759 /* Value is normal if it isn't infinite, zero or denormalized */
18760 normal = mkNOT1( mkOR1(
18761 mkOR1( is_NaN( Ity_I64, tmp ),
18762 is_Inf( Ity_I64, tmp ) ),
18763 mkOR1( is_Zero( Ity_I64, tmp ),
18764 is_Denorm( Ity_I64, tmp ) ) ) );
18766 assign( rT, binop( Iop_Or64,
18767 binop( Iop_And64,
18768 mkexpr( tmp ),
18769 mkU64( 0xFFFFFFFFFFFFF ) ),
18770 binop( Iop_Shl64,
18771 unop( Iop_1Uto64, normal),
18772 mkU8( 52 ) ) ) );
18773 putIReg( XT, mkexpr( rT ) );
18775 } else if (inst_select == 16) {
18776 IRTemp result = newTemp( Ity_V128 );
18777 IRTemp value = newTemp( Ity_I64 );
18778 /* Note: PPC only coverts the 16-bit value in the upper 64-bits
18779 * of the source V128 to a 64-bit value stored in the upper
18780 * 64-bits of the V128 result. The contents of the lower 64-bits
18781 * is undefined.
18784 DIP("xscvhpdp v%d, v%d\n", (UInt)XT, (UInt)XB);
18785 assign( result, unop( Iop_F16toF64x2, mkexpr( vB ) ) );
18787 putVSReg( XT, mkexpr( result ) );
18789 assign( value, unop( Iop_V128HIto64, mkexpr( result ) ) );
18790 generate_store_FPRF( Ity_I64, value, vbi );
18791 return True;
18793 } else if (inst_select == 17) { // xscvdphp
18794 IRTemp value = newTemp( Ity_I32 );
18795 IRTemp result = newTemp( Ity_V128 );
18796 /* Note: PPC only coverts the 64-bit value in the upper 64-bits of
18797 * the V128 and stores the 16-bit result in the upper word of the
18798 * V128 result. The contents of the lower 64-bits is undefined.
18800 DIP("xscvdphp v%d, v%d\n", (UInt)XT, (UInt)XB);
18801 assign( result, unop( Iop_F64toF16x2, mkexpr( vB ) ) );
18802 assign( value, unop( Iop_64to32, unop( Iop_V128HIto64,
18803 mkexpr( result ) ) ) );
18804 putVSReg( XT, mkexpr( result ) );
18805 generate_store_FPRF( Ity_I16, value, vbi );
18806 return True;
18808 } else {
18809 vex_printf( "dis_vxv_scalar_extract_exp_sig invalid inst_select (ppc)(opc2)\n" );
18810 vex_printf("inst_select = %d\n", inst_select);
18811 return False;
18814 break;
18816 case 0x254: // xststdcsp (VSX Scalar Test Data Class Single-Precision)
18817 case 0x2D4: // xststdcdp (VSX Scalar Test Data Class Double-Precision)
18819 /* These instructions only differ in that the single precision
18820 instruction, xststdcsp, has the additional constraint on the
18821 denormal test that the exponent be greater then zero and
18822 less then 0x381. */
18823 IRTemp vB_hi = newTemp( Ity_I64 );
18824 UInt BF = IFIELD( theInstr, 23, 3 );
18825 UInt DCMX_mask = IFIELD( theInstr, 16, 7 );
18826 IRTemp NaN = newTemp( Ity_I64 );
18827 IRTemp inf = newTemp( Ity_I64 );
18828 IRTemp zero = newTemp( Ity_I64 );
18829 IRTemp dnorm = newTemp( Ity_I64 );
18830 IRTemp pos = newTemp( Ity_I64 );
18831 IRTemp not_sp = newTemp( Ity_I64 );
18832 IRTemp DCM = newTemp( Ity_I64 );
18833 IRTemp CC = newTemp( Ity_I64 );
18834 IRTemp exponent = newTemp( Ity_I64 );
18835 IRTemp tmp = newTemp( Ity_I64 );
18837 assign( vB_hi, unop( Iop_V128HIto64, mkexpr( vB ) ) );
18839 assign( pos, unop( Iop_1Uto64,
18840 binop( Iop_CmpEQ64,
18841 binop( Iop_Shr64,
18842 mkexpr( vB_hi ),
18843 mkU8( 63 ) ),
18844 mkU64( 0 ) ) ) );
18846 assign( NaN, unop( Iop_1Uto64, is_NaN( Ity_I64, vB_hi ) ) );
18847 assign( inf, unop( Iop_1Uto64, is_Inf( Ity_I64, vB_hi ) ) );
18848 assign( zero, unop( Iop_1Uto64, is_Zero( Ity_I64, vB_hi ) ) );
18850 if (opc2 == 0x254) {
18851 DIP("xststdcsp %d,v%d,%d\n", BF, (UInt)XB, DCMX_mask);
18853 /* The least significant bit of the CC is set to 1 if the double
18854 precision value is not representable as a single precision
18855 value. The spec says the bit is set if:
18856 src != convert_SPtoDP(convert_DPtoSP(src))
18858 assign( tmp,
18859 unop( Iop_ReinterpF64asI64,
18860 unop( Iop_F32toF64,
18861 unop( Iop_TruncF64asF32,
18862 unop( Iop_ReinterpI64asF64,
18863 mkexpr( vB_hi ) ) ) ) ) );
18864 assign( not_sp, unop( Iop_1Uto64,
18865 mkNOT1( binop( Iop_CmpEQ64,
18866 mkexpr( vB_hi ),
18867 mkexpr( tmp ) ) ) ) );
18868 assign( exponent,
18869 binop( Iop_Shr64,
18870 binop( Iop_And64,
18871 mkexpr( vB_hi ),
18872 mkU64( 0x7ff0000000000000 ) ),
18873 mkU8( 52 ) ) );
18874 assign( dnorm, unop( Iop_1Uto64,
18875 mkOR1( is_Denorm( Ity_I64, vB_hi ),
18876 mkAND1( binop( Iop_CmpLT64U,
18877 mkexpr( exponent ),
18878 mkU64( 0x381 ) ),
18879 binop( Iop_CmpNE64,
18880 mkexpr( exponent ),
18881 mkU64( 0x0 ) ) ) ) ) );
18883 } else {
18884 DIP("xststdcdp %d,v%d,%d\n", BF, (UInt)XB, DCMX_mask);
18885 assign( not_sp, mkU64( 0 ) );
18886 assign( dnorm, unop( Iop_1Uto64, is_Denorm( Ity_I64, vB_hi ) ) );
18889 assign( DCM, create_DCM( Ity_I64, NaN, inf, zero, dnorm, pos ) );
18890 assign( CC,
18891 binop( Iop_Or64,
18892 binop( Iop_And64, /* vB sign bit */
18893 binop( Iop_Shr64,
18894 mkexpr( vB_hi ),
18895 mkU8( 60 ) ),
18896 mkU64( 0x8 ) ),
18897 binop( Iop_Or64,
18898 binop( Iop_Shl64,
18899 unop( Iop_1Uto64,
18900 binop( Iop_CmpNE64,
18901 binop( Iop_And64,
18902 mkexpr( DCM ),
18903 mkU64( DCMX_mask ) ),
18904 mkU64( 0 ) ) ),
18905 mkU8( 1 ) ),
18906 mkexpr( not_sp ) ) ) );
18907 putGST_field( PPC_GST_CR, unop( Iop_64to32, mkexpr( CC ) ), BF );
18908 putFPCC( unop( Iop_64to32, mkexpr( CC ) ) );
18910 return True;
18912 case 0x2C0: // xscpsgndp
18914 /* Scalar copy sign double-precision */
18915 IRTemp vecA_signed = newTemp(Ity_I64);
18916 IRTemp vecB_unsigned = newTemp(Ity_I64);
18917 IRTemp vec_result = newTemp(Ity_V128);
18918 DIP("xscpsgndp v%d,v%d v%d\n", XT, XA, XB);
18919 assign( vecA_signed, binop( Iop_And64,
18920 unop( Iop_V128HIto64,
18921 mkexpr(vA)),
18922 mkU64(~VG_PPC_SIGN_MASK) ) );
18923 assign( vecB_unsigned, binop( Iop_And64,
18924 unop( Iop_V128HIto64,
18925 mkexpr(vB) ),
18926 mkU64(VG_PPC_SIGN_MASK) ) );
18927 assign( vec_result, binop( Iop_64HLtoV128,
18928 binop( Iop_Or64,
18929 mkexpr(vecA_signed),
18930 mkexpr(vecB_unsigned) ),
18931 mkU64(0x0ULL)));
18932 putVSReg(XT, mkexpr(vec_result));
18933 break;
18935 case 0x2D2: // xsnabsdp
18937 /* Scalar negative absolute value double-precision */
18938 IRTemp BHi_signed = newTemp(Ity_I64);
18939 DIP("xsnabsdp v%d,v%d\n", XT, XB);
18940 assign( BHi_signed, binop( Iop_Or64,
18941 unop( Iop_V128HIto64,
18942 mkexpr(vB) ),
18943 mkU64(~VG_PPC_SIGN_MASK) ) );
18944 putVSReg(XT, binop( Iop_64HLtoV128,
18945 mkexpr(BHi_signed), mkU64(0x0ULL) ) );
18946 break;
18948 case 0x2F2: // xsnegdp
18950 /* Scalar negate double-precision */
18951 IRTemp BHi_signed = newTemp(Ity_I64);
18952 IRTemp BHi_unsigned = newTemp(Ity_I64);
18953 IRTemp BHi_negated = newTemp(Ity_I64);
18954 IRTemp BHi_negated_signbit = newTemp(Ity_I1);
18955 IRTemp vec_result = newTemp(Ity_V128);
18956 DIP("xsnabsdp v%d,v%d\n", XT, XB);
18957 assign( BHi_signed, unop( Iop_V128HIto64, mkexpr(vB) ) );
18958 assign( BHi_unsigned, binop( Iop_And64, mkexpr(BHi_signed),
18959 mkU64(VG_PPC_SIGN_MASK) ) );
18960 assign( BHi_negated_signbit,
18961 unop( Iop_Not1,
18962 unop( Iop_32to1,
18963 binop( Iop_Shr32,
18964 unop( Iop_64HIto32,
18965 binop( Iop_And64,
18966 mkexpr(BHi_signed),
18967 mkU64(~VG_PPC_SIGN_MASK) )
18969 mkU8(31) ) ) ) );
18970 assign( BHi_negated,
18971 binop( Iop_Or64,
18972 binop( Iop_32HLto64,
18973 binop( Iop_Shl32,
18974 unop( Iop_1Uto32,
18975 mkexpr(BHi_negated_signbit) ),
18976 mkU8(31) ),
18977 mkU32(0) ),
18978 mkexpr(BHi_unsigned) ) );
18979 assign( vec_result, binop( Iop_64HLtoV128, mkexpr(BHi_negated),
18980 mkU64(0x0ULL)));
18981 putVSReg( XT, mkexpr(vec_result));
18982 break;
18984 case 0x280: // xsmaxdp (VSX Scalar Maximum Double-Precision)
18985 case 0x2A0: // xsmindp (VSX Scalar Minimum Double-Precision)
18987 IRTemp frA = newTemp(Ity_I64);
18988 IRTemp frB = newTemp(Ity_I64);
18989 Bool isMin = opc2 == 0x2A0 ? True : False;
18990 DIP("%s v%d,v%d v%d\n", isMin ? "xsmaxdp" : "xsmindp", XT, XA, XB);
18992 assign(frA, unop(Iop_V128HIto64, mkexpr( vA )));
18993 assign(frB, unop(Iop_V128HIto64, mkexpr( vB )));
18994 putVSReg( XT, binop( Iop_64HLtoV128, get_max_min_fp(frA, frB, isMin), mkU64( 0 ) ) );
18996 break;
18998 case 0x0F2: // xsrdpim (VSX Scalar Round to Double-Precision Integer using round toward -Infinity)
18999 case 0x0D2: // xsrdpip (VSX Scalar Round to Double-Precision Integer using round toward +Infinity)
19000 case 0x0D6: // xsrdpic (VSX Scalar Round to Double-Precision Integer using Current rounding mode)
19001 case 0x0B2: // xsrdpiz (VSX Scalar Round to Double-Precision Integer using round toward Zero)
19002 case 0x092: // xsrdpi (VSX Scalar Round to Double-Precision Integer using round toward Nearest Away)
19004 IRTemp frB_I64 = newTemp(Ity_I64);
19005 IRExpr * frD_fp_round = NULL;
19007 assign(frB_I64, unop(Iop_V128HIto64, mkexpr( vB )));
19008 frD_fp_round = _do_vsx_fp_roundToInt(frB_I64, opc2);
19010 DIP("xsrdpi%s v%d,v%d\n", _get_vsx_rdpi_suffix(opc2), XT, XB);
19011 putVSReg( XT,
19012 binop( Iop_64HLtoV128,
19013 unop( Iop_ReinterpF64asI64, frD_fp_round),
19014 mkU64( 0 ) ) );
19015 break;
19017 case 0x034: // xsresp (VSX Scalar Reciprocal Estimate single-Precision)
19018 case 0x014: /* xsrsqrtesp (VSX Scalar Reciprocal Square Root Estimate
19019 * single-Precision)
19022 IRTemp frB = newTemp(Ity_F64);
19023 IRTemp sqrt = newTemp(Ity_F64);
19024 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
19025 IRExpr* rm = get_IR_roundingmode();
19026 Bool redp = opc2 == 0x034;
19027 DIP("%s v%d,v%d\n", redp ? "xsresp" : "xsrsqrtesp", XT,
19028 XB);
19030 assign( frB,
19031 unop( Iop_ReinterpI64asF64,
19032 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
19034 if (!redp)
19035 assign( sqrt,
19036 binop( Iop_SqrtF64,
19038 mkexpr(frB) ) );
19039 putVSReg( XT,
19040 binop( Iop_64HLtoV128,
19041 unop( Iop_ReinterpF64asI64,
19042 binop( Iop_RoundF64toF32, rm,
19043 triop( Iop_DivF64,
19045 ieee_one,
19046 redp ? mkexpr( frB ) :
19047 mkexpr( sqrt ) ) ) ),
19048 mkU64( 0 ) ) );
19049 break;
19052 case 0x0B4: // xsredp (VSX Scalar Reciprocal Estimate Double-Precision)
19053 case 0x094: // xsrsqrtedp (VSX Scalar Reciprocal Square Root Estimate Double-Precision)
19056 IRTemp frB = newTemp(Ity_F64);
19057 IRTemp sqrt = newTemp(Ity_F64);
19058 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
19059 IRExpr* rm = get_IR_roundingmode();
19060 Bool redp = opc2 == 0x0B4;
19061 DIP("%s v%d,v%d\n", redp ? "xsredp" : "xsrsqrtedp", XT, XB);
19062 assign( frB,
19063 unop( Iop_ReinterpI64asF64,
19064 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
19066 if (!redp)
19067 assign( sqrt,
19068 binop( Iop_SqrtF64,
19070 mkexpr(frB) ) );
19071 putVSReg( XT,
19072 binop( Iop_64HLtoV128,
19073 unop( Iop_ReinterpF64asI64,
19074 triop( Iop_DivF64,
19076 ieee_one,
19077 redp ? mkexpr( frB ) : mkexpr( sqrt ) ) ),
19078 mkU64( 0 ) ) );
19079 break;
19082 case 0x232: // xsrsp (VSX Scalar Round to Single-Precision)
19084 IRTemp frB = newTemp(Ity_F64);
19085 IRExpr* rm = get_IR_roundingmode();
19086 DIP("xsrsp v%d, v%d\n", XT, XB);
19087 assign( frB,
19088 unop( Iop_ReinterpI64asF64,
19089 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
19091 putVSReg( XT, binop( Iop_64HLtoV128,
19092 unop( Iop_ReinterpF64asI64,
19093 binop( Iop_RoundF64toF32,
19095 mkexpr( frB ) ) ),
19096 mkU64( 0 ) ) );
19097 break;
19100 case 0x354: // xvtstdcsp (VSX Test Data Class Single-Precision)
19102 UInt DX_mask = IFIELD( theInstr, 16, 5 );
19103 UInt DC_mask = IFIELD( theInstr, 6, 1 );
19104 UInt DM_mask = IFIELD( theInstr, 2, 1 );
19105 UInt DCMX_mask = (DC_mask << 6) | (DM_mask << 5) | DX_mask;
19107 IRTemp match_value[4];
19108 IRTemp value[4];
19109 IRTemp NaN[4];
19110 IRTemp inf[4];
19111 IRTemp pos[4];
19112 IRTemp DCM[4];
19113 IRTemp zero[4];
19114 IRTemp dnorm[4];
19115 Int i;
19117 DIP("xvtstdcsp v%d,v%d,%d\n", (UInt)XT, (UInt)XB, DCMX_mask);
19119 for (i = 0; i < 4; i++) {
19120 NaN[i] = newTemp(Ity_I32);
19121 inf[i] = newTemp(Ity_I32);
19122 pos[i] = newTemp(Ity_I32);
19123 DCM[i] = newTemp(Ity_I32);
19124 zero[i] = newTemp(Ity_I32);
19125 dnorm[i] = newTemp(Ity_I32);
19127 value[i] = newTemp(Ity_I32);
19128 match_value[i] = newTemp(Ity_I32);
19130 assign( value[i],
19131 unop( Iop_64to32,
19132 unop( Iop_V128to64,
19133 binop( Iop_AndV128,
19134 binop( Iop_ShrV128,
19135 mkexpr( vB ),
19136 mkU8( (3-i)*32 ) ),
19137 binop( Iop_64HLtoV128,
19138 mkU64( 0x0 ),
19139 mkU64( 0xFFFFFFFF ) ) ) ) ) );
19141 assign( pos[i], unop( Iop_1Uto32,
19142 binop( Iop_CmpEQ32,
19143 binop( Iop_Shr32,
19144 mkexpr( value[i] ),
19145 mkU8( 31 ) ),
19146 mkU32( 0 ) ) ) );
19148 assign( NaN[i], unop( Iop_1Uto32, is_NaN( Ity_I32, value[i] ) ));
19149 assign( inf[i], unop( Iop_1Uto32, is_Inf( Ity_I32, value[i] ) ) );
19150 assign( zero[i], unop( Iop_1Uto32, is_Zero( Ity_I32, value[i] ) ) );
19152 assign( dnorm[i], unop( Iop_1Uto32, is_Denorm( Ity_I32,
19153 value[i] ) ) );
19154 assign( DCM[i], create_DCM( Ity_I32, NaN[i], inf[i], zero[i],
19155 dnorm[i], pos[i] ) );
19157 assign( match_value[i],
19158 unop( Iop_1Sto32,
19159 binop( Iop_CmpNE32,
19160 binop( Iop_And32,
19161 mkU32( DCMX_mask ),
19162 mkexpr( DCM[i] ) ),
19163 mkU32( 0 ) ) ) );
19166 putVSReg( XT, binop( Iop_64HLtoV128,
19167 binop( Iop_32HLto64,
19168 mkexpr( match_value[0] ),
19169 mkexpr( match_value[1] ) ),
19170 binop( Iop_32HLto64,
19171 mkexpr( match_value[2] ),
19172 mkexpr( match_value[3] ) ) ) );
19174 break;
19176 case 0x360: // xviexpsp (VSX Vector Insert Exponent Single-Precision)
19178 Int i;
19179 IRTemp new_XT[5];
19180 IRTemp A_value[4];
19181 IRTemp B_value[4];
19182 IRExpr *sign[4], *expr[4], *fract[4];
19184 DIP("xviexpsp v%d,v%d\n", XT, XB);
19185 new_XT[0] = newTemp(Ity_V128);
19186 assign( new_XT[0], binop( Iop_64HLtoV128,
19187 mkU64( 0x0 ),
19188 mkU64( 0x0 ) ) );
19190 for (i = 0; i < 4; i++) {
19191 A_value[i] = newTemp(Ity_I32);
19192 B_value[i] = newTemp(Ity_I32);
19194 assign( A_value[i],
19195 unop( Iop_64to32,
19196 unop( Iop_V128to64,
19197 binop( Iop_AndV128,
19198 binop( Iop_ShrV128,
19199 mkexpr( vA ),
19200 mkU8( (3-i)*32 ) ),
19201 binop( Iop_64HLtoV128,
19202 mkU64( 0x0 ),
19203 mkU64( 0xFFFFFFFF ) ) ) ) ) );
19204 assign( B_value[i],
19205 unop( Iop_64to32,
19206 unop( Iop_V128to64,
19207 binop( Iop_AndV128,
19208 binop( Iop_ShrV128,
19209 mkexpr( vB ),
19210 mkU8( (3-i)*32 ) ),
19211 binop( Iop_64HLtoV128,
19212 mkU64( 0x0 ),
19213 mkU64( 0xFFFFFFFF ) ) ) ) ) );
19215 sign[i] = binop( Iop_And32, mkexpr( A_value[i] ),
19216 mkU32( 0x80000000 ) );
19217 expr[i] = binop( Iop_Shl32,
19218 binop( Iop_And32, mkexpr( B_value[i] ),
19219 mkU32( 0xFF ) ),
19220 mkU8( 23 ) );
19221 fract[i] = binop( Iop_And32, mkexpr( A_value[i] ),
19222 mkU32( 0x007FFFFF ) );
19224 new_XT[i+1] = newTemp(Ity_V128);
19225 assign( new_XT[i+1],
19226 binop( Iop_OrV128,
19227 binop( Iop_ShlV128,
19228 binop( Iop_64HLtoV128,
19229 mkU64( 0 ),
19230 binop( Iop_32HLto64,
19231 mkU32( 0 ),
19232 binop( Iop_Or32,
19233 binop( Iop_Or32,
19234 sign[i],
19235 expr[i] ),
19236 fract[i] ) ) ),
19237 mkU8( (3-i)*32 ) ),
19238 mkexpr( new_XT[i] ) ) );
19240 putVSReg( XT, mkexpr( new_XT[4] ) );
19242 break;
19244 case 0x396: // xsiexpdp (VSX Scalar Insert Exponent Double-Precision)
19246 IRExpr *sign, *expr, *fract;
19247 UChar rA_addr = ifieldRegA(theInstr);
19248 UChar rB_addr = ifieldRegB(theInstr);
19249 IRTemp rA = newTemp( Ity_I64 );
19250 IRTemp rB = newTemp( Ity_I64 );
19252 DIP("xsiexpdp v%d,%d,%d\n", (UInt)XT, (UInt)rA_addr, (UInt)rB_addr);
19253 assign( rA, getIReg(rA_addr));
19254 assign( rB, getIReg(rB_addr));
19256 sign = binop( Iop_And64, mkexpr( rA ), mkU64( 0x8000000000000000 ) );
19257 expr = binop( Iop_Shl64,
19258 binop( Iop_And64, mkexpr( rB ), mkU64( 0x7FF ) ),
19259 mkU8( 52 ) );
19260 fract = binop( Iop_And64, mkexpr( rA ), mkU64( 0x000FFFFFFFFFFFFF ) );
19262 putVSReg( XT, binop( Iop_64HLtoV128,
19263 binop( Iop_Or64,
19264 binop( Iop_Or64, sign, expr ),
19265 fract ),
19266 mkU64( 0 ) ) );
19268 break;
19270 case 0x3B6: // xvxexpdp (VSX Vector Extract Exponent Double-Precision)
19271 // xvxsigdp (VSX Vector Extract Significand Double-Precision)
19272 // xxbrh
19273 // xvxexpsp (VSX Vector Extract Exponent Single-Precision)
19274 // xvxsigsp (VSX Vector Extract Significand Single-Precision)
19275 // xxbrw
19276 // xxbrd
19277 // xxbrq
19278 // xvcvhpsp (VSX Vector Convert Half-Precision format to Single-Precision format)
19279 // xvcvsphp (VSX Vector round and convert Single-Precision format to Half-Precision format)
19281 UInt inst_select = IFIELD( theInstr, 16, 5);
19283 if (inst_select == 0) {
19284 DIP("xvxexpdp v%d,v%d\n", XT, XB);
19286 putVSReg( XT, binop( Iop_ShrV128,
19287 binop( Iop_AndV128,
19288 mkexpr( vB ),
19289 binop( Iop_64HLtoV128,
19290 mkU64( 0x7FF0000000000000 ),
19291 mkU64( 0x7FF0000000000000 ) ) ),
19292 mkU8( 52 ) ) );
19294 } else if (inst_select == 1) {
19295 Int i;
19296 IRExpr *normal[2];
19297 IRTemp value[2];
19298 IRTemp new_XT[3];
19300 DIP("xvxsigdp v%d,v%d\n", XT, XB);
19301 new_XT[0] = newTemp(Ity_V128);
19302 assign( new_XT[0], binop( Iop_64HLtoV128,
19303 mkU64( 0x0 ),
19304 mkU64( 0x0 ) ) );
19306 for (i = 0; i < 2; i++) {
19307 value[i] = newTemp(Ity_I64);
19308 assign( value[i],
19309 unop( Iop_V128to64,
19310 binop( Iop_AndV128,
19311 binop( Iop_ShrV128,
19312 mkexpr( vB ),
19313 mkU8( (1-i)*64 ) ),
19314 binop( Iop_64HLtoV128,
19315 mkU64( 0x0 ),
19316 mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) ) );
19318 /* Value is normal if it isn't infinite, zero or denormalized */
19319 normal[i] = mkNOT1( mkOR1(
19320 mkOR1( is_NaN( Ity_I64, value[i] ),
19321 is_Inf( Ity_I64, value[i] ) ),
19322 mkOR1( is_Zero( Ity_I64, value[i] ),
19323 is_Denorm( Ity_I64,
19324 value[i] ) ) ) );
19325 new_XT[i+1] = newTemp(Ity_V128);
19327 assign( new_XT[i+1],
19328 binop( Iop_OrV128,
19329 binop( Iop_ShlV128,
19330 binop( Iop_64HLtoV128,
19331 mkU64( 0x0 ),
19332 binop( Iop_Or64,
19333 binop( Iop_And64,
19334 mkexpr( value[i] ),
19335 mkU64( 0xFFFFFFFFFFFFF ) ),
19336 binop( Iop_Shl64,
19337 unop( Iop_1Uto64,
19338 normal[i]),
19339 mkU8( 52 ) ) ) ),
19340 mkU8( (1-i)*64 ) ),
19341 mkexpr( new_XT[i] ) ) );
19343 putVSReg( XT, mkexpr( new_XT[2] ) );
19345 } else if (inst_select == 7) {
19346 IRTemp sub_element0 = newTemp( Ity_V128 );
19347 IRTemp sub_element1 = newTemp( Ity_V128 );
19349 DIP("xxbrh v%d, v%d\n", (UInt)XT, (UInt)XB);
19351 assign( sub_element0,
19352 binop( Iop_ShrV128,
19353 binop( Iop_AndV128,
19354 binop(Iop_64HLtoV128,
19355 mkU64( 0xFF00FF00FF00FF00 ),
19356 mkU64( 0xFF00FF00FF00FF00 ) ),
19357 mkexpr( vB ) ),
19358 mkU8( 8 ) ) );
19359 assign( sub_element1,
19360 binop( Iop_ShlV128,
19361 binop( Iop_AndV128,
19362 binop(Iop_64HLtoV128,
19363 mkU64( 0x00FF00FF00FF00FF ),
19364 mkU64( 0x00FF00FF00FF00FF ) ),
19365 mkexpr( vB ) ),
19366 mkU8( 8 ) ) );
19368 putVSReg(XT, binop( Iop_OrV128,
19369 mkexpr( sub_element1 ),
19370 mkexpr( sub_element0 ) ) );
19372 } else if (inst_select == 8) {
19373 DIP("xvxexpsp v%d,v%d\n", XT, XB);
19375 putVSReg( XT, binop( Iop_ShrV128,
19376 binop( Iop_AndV128,
19377 mkexpr( vB ),
19378 binop( Iop_64HLtoV128,
19379 mkU64( 0x7F8000007F800000 ),
19380 mkU64( 0x7F8000007F800000 ) ) ),
19381 mkU8( 23 ) ) );
19382 } else if (inst_select == 9) {
19383 Int i;
19384 IRExpr *normal[4];
19385 IRTemp value[4];
19386 IRTemp new_value[4];
19387 IRTemp new_XT[5];
19389 DIP("xvxsigsp v%d,v%d\n", XT, XB);
19390 new_XT[0] = newTemp(Ity_V128);
19391 assign( new_XT[0], binop( Iop_64HLtoV128,
19392 mkU64( 0x0 ),
19393 mkU64( 0x0 ) ) );
19395 for (i = 0; i < 4; i++) {
19396 value[i] = newTemp(Ity_I32);
19397 assign( value[i],
19398 unop( Iop_64to32,
19399 unop( Iop_V128to64,
19400 binop( Iop_AndV128,
19401 binop( Iop_ShrV128,
19402 mkexpr( vB ),
19403 mkU8( (3-i)*32 ) ),
19404 binop( Iop_64HLtoV128,
19405 mkU64( 0x0 ),
19406 mkU64( 0xFFFFFFFF ) ) ) ) ) );
19408 new_XT[i+1] = newTemp(Ity_V128);
19410 /* Value is normal if it isn't infinite, zero or denormalized */
19411 normal[i] = mkNOT1( mkOR1(
19412 mkOR1( is_NaN( Ity_I32, value[i] ),
19413 is_Inf( Ity_I32, value[i] ) ),
19414 mkOR1( is_Zero( Ity_I32, value[i] ),
19415 is_Denorm( Ity_I32,
19416 value[i] ) ) ) );
19417 new_value[i] = newTemp(Ity_I32);
19418 assign( new_value[i],
19419 binop( Iop_Or32,
19420 binop( Iop_And32,
19421 mkexpr( value[i] ),
19422 mkU32( 0x7FFFFF ) ),
19423 binop( Iop_Shl32,
19424 unop( Iop_1Uto32,
19425 normal[i]),
19426 mkU8( 23 ) ) ) );
19428 assign( new_XT[i+1],
19429 binop( Iop_OrV128,
19430 binop( Iop_ShlV128,
19431 binop( Iop_64HLtoV128,
19432 mkU64( 0x0 ),
19433 binop( Iop_32HLto64,
19434 mkU32( 0x0 ),
19435 mkexpr( new_value[i] ) ) ),
19436 mkU8( (3-i)*32 ) ),
19437 mkexpr( new_XT[i] ) ) );
19439 putVSReg( XT, mkexpr( new_XT[4] ) );
19441 } else if (inst_select == 15) {
19442 IRTemp sub_element0 = newTemp( Ity_V128 );
19443 IRTemp sub_element1 = newTemp( Ity_V128 );
19444 IRTemp sub_element2 = newTemp( Ity_V128 );
19445 IRTemp sub_element3 = newTemp( Ity_V128 );
19447 DIP("xxbrw v%d, v%d\n", (UInt)XT, (UInt)XB);
19449 assign( sub_element0,
19450 binop( Iop_ShrV128,
19451 binop( Iop_AndV128,
19452 binop(Iop_64HLtoV128,
19453 mkU64( 0xFF000000FF000000 ),
19454 mkU64( 0xFF000000FF000000 ) ),
19455 mkexpr( vB ) ),
19456 mkU8( 24 ) ) );
19457 assign( sub_element1,
19458 binop( Iop_ShrV128,
19459 binop( Iop_AndV128,
19460 binop(Iop_64HLtoV128,
19461 mkU64( 0x00FF000000FF0000 ),
19462 mkU64( 0x00FF000000FF0000 ) ),
19463 mkexpr( vB ) ),
19464 mkU8( 8 ) ) );
19465 assign( sub_element2,
19466 binop( Iop_ShlV128,
19467 binop( Iop_AndV128,
19468 binop(Iop_64HLtoV128,
19469 mkU64( 0x0000FF000000FF00 ),
19470 mkU64( 0x0000FF000000FF00 ) ),
19471 mkexpr( vB ) ),
19472 mkU8( 8 ) ) );
19473 assign( sub_element3,
19474 binop( Iop_ShlV128,
19475 binop( Iop_AndV128,
19476 binop(Iop_64HLtoV128,
19477 mkU64( 0x00000000FF000000FF ),
19478 mkU64( 0x00000000FF000000FF ) ),
19479 mkexpr( vB ) ),
19480 mkU8( 24 ) ) );
19482 putVSReg( XT,
19483 binop( Iop_OrV128,
19484 binop( Iop_OrV128,
19485 mkexpr( sub_element3 ),
19486 mkexpr( sub_element2 ) ),
19487 binop( Iop_OrV128,
19488 mkexpr( sub_element1 ),
19489 mkexpr( sub_element0 ) ) ) );
19491 } else if (inst_select == 23) {
19492 DIP("xxbrd v%d, v%d\n", (UInt)XT, (UInt)XB);
19494 int i;
19495 int shift = 56;
19496 IRTemp sub_element[16];
19497 IRTemp new_xT[17];
19499 new_xT[0] = newTemp( Ity_V128 );
19500 assign( new_xT[0], binop( Iop_64HLtoV128,
19501 mkU64( 0 ),
19502 mkU64( 0 ) ) );
19504 for ( i = 0; i < 4; i++ ) {
19505 new_xT[i+1] = newTemp( Ity_V128 );
19506 sub_element[i] = newTemp( Ity_V128 );
19507 sub_element[i+4] = newTemp( Ity_V128 );
19509 assign( sub_element[i],
19510 binop( Iop_ShrV128,
19511 binop( Iop_AndV128,
19512 binop( Iop_64HLtoV128,
19513 mkU64( (0xFFULL << (7 - i) * 8) ),
19514 mkU64( (0xFFULL << (7 - i) * 8) ) ),
19515 mkexpr( vB ) ),
19516 mkU8( shift ) ) );
19518 assign( sub_element[i+4],
19519 binop( Iop_ShlV128,
19520 binop( Iop_AndV128,
19521 binop( Iop_64HLtoV128,
19522 mkU64( (0xFFULL << i*8) ),
19523 mkU64( (0xFFULL << i*8) ) ),
19524 mkexpr( vB ) ),
19525 mkU8( shift ) ) );
19526 shift = shift - 16;
19528 assign( new_xT[i+1],
19529 binop( Iop_OrV128,
19530 mkexpr( new_xT[i] ),
19531 binop( Iop_OrV128,
19532 mkexpr ( sub_element[i] ),
19533 mkexpr ( sub_element[i+4] ) ) ) );
19536 putVSReg( XT, mkexpr( new_xT[4] ) );
19538 } else if (inst_select == 24) {
19539 // xvcvhpsp, (VSX Vector Convert half-precision format to
19540 // Single-precision format)
19541 /* only supported on ISA 3.0 and newer */
19542 IRTemp result = newTemp( Ity_V128 );
19543 IRTemp src = newTemp( Ity_I64 );
19545 if (!allow_isa_3_0) return False;
19547 DIP("xvcvhpsp v%d,v%d\n", XT,XB);
19548 /* The instruction does not set the C or FPCC fields. The
19549 * instruction takes four 16-bit values stored in a 128-bit value
19550 * as follows: x V | x V | x V | x V where V is a 16-bit
19551 * value and x is an unused 16-bit value. To use Iop_F16toF32x4
19552 * the four 16-bit values will be gathered into a single 64 bit
19553 * value. The backend will scatter the four 16-bit values back
19554 * into a 128-bit operand before issuing the instruction.
19556 /* Gather 16-bit float values from V128 source into new 64-bit
19557 * source value for the Iop.
19559 assign( src,
19560 unop( Iop_V128to64,
19561 binop( Iop_Perm8x16,
19562 mkexpr( vB ),
19563 binop ( Iop_64HLtoV128,
19564 mkU64( 0 ),
19565 mkU64( 0x020306070A0B0E0F) ) ) ) );
19567 assign( result, unop( Iop_F16toF32x4, mkexpr( src ) ) );
19569 putVSReg( XT, mkexpr( result ) );
19571 } else if (inst_select == 25) {
19572 // xvcvsphp, (VSX Vector round and Convert single-precision
19573 // format to half-precision format)
19574 /* only supported on ISA 3.0 and newer */
19575 IRTemp result = newTemp( Ity_V128 );
19576 IRTemp tmp64 = newTemp( Ity_I64 );
19578 if (!allow_isa_3_0) return False;
19579 DIP("xvcvsphp v%d,v%d\n", XT,XB);
19581 /* Iop_F32toF16x4 is V128 -> I64, scatter the 16-bit floats in the
19582 * I64 result to the V128 register to store.
19584 assign( tmp64, unop( Iop_F32toF16x4, mkexpr( vB ) ) );
19586 /* Scatter 16-bit float values from returned 64-bit value
19587 * of V128 result.
19589 if (host_endness == VexEndnessLE)
19590 /* Note location 0 may have a valid number in it. Location
19591 * 15 should always be zero. Use 0xF to put zeros in the
19592 * desired bytes.
19594 assign( result,
19595 binop( Iop_Perm8x16,
19596 binop( Iop_64HLtoV128,
19597 mkexpr( tmp64 ),
19598 mkU64( 0 ) ),
19599 binop ( Iop_64HLtoV128,
19600 mkU64( 0x0F0F00010F0F0203 ),
19601 mkU64( 0x0F0F04050F0F0607 ) ) ) );
19602 else
19603 assign( result,
19604 binop( Iop_Perm8x16,
19605 binop( Iop_64HLtoV128,
19606 mkexpr( tmp64 ),
19607 mkU64( 0 ) ),
19608 binop ( Iop_64HLtoV128,
19609 mkU64( 0x0F0F06070F0F0405 ),
19610 mkU64( 0x0F0F02030F0F0001 ) ) ) );
19611 putVSReg( XT, mkexpr( result ) );
19613 } else if ( inst_select == 31 ) {
19614 int i;
19615 int shift_left = 8;
19616 int shift_right = 120;
19617 IRTemp sub_element[16];
19618 IRTemp new_xT[9];
19620 DIP("xxbrq v%d, v%d\n", (UInt) XT, (UInt) XB);
19622 new_xT[0] = newTemp( Ity_V128 );
19623 assign( new_xT[0], binop( Iop_64HLtoV128,
19624 mkU64( 0 ),
19625 mkU64( 0 ) ) );
19627 for ( i = 0; i < 8; i++ ) {
19628 new_xT[i+1] = newTemp( Ity_V128 );
19629 sub_element[i] = newTemp( Ity_V128 );
19630 sub_element[i+8] = newTemp( Ity_V128 );
19632 assign( sub_element[i],
19633 binop( Iop_ShrV128,
19634 binop( Iop_AndV128,
19635 binop( Iop_64HLtoV128,
19636 mkU64( ( 0xFFULL << (7 - i) * 8 ) ),
19637 mkU64( 0x0ULL ) ),
19638 mkexpr( vB ) ),
19639 mkU8( shift_right ) ) );
19640 shift_right = shift_right - 16;
19642 assign( sub_element[i+8],
19643 binop( Iop_ShlV128,
19644 binop( Iop_AndV128,
19645 binop( Iop_64HLtoV128,
19646 mkU64( 0x0ULL ),
19647 mkU64( ( 0xFFULL << (7 - i) * 8 ) ) ),
19648 mkexpr( vB ) ),
19649 mkU8( shift_left ) ) );
19650 shift_left = shift_left + 16;
19652 assign( new_xT[i+1],
19653 binop( Iop_OrV128,
19654 mkexpr( new_xT[i] ),
19655 binop( Iop_OrV128,
19656 mkexpr ( sub_element[i] ),
19657 mkexpr ( sub_element[i+8] ) ) ) );
19660 putVSReg( XT, mkexpr( new_xT[8] ) );
19662 } else {
19663 vex_printf("dis_vxs_misc(ppc) Invalid instruction selection\n");
19664 return False;
19666 break;
19669 case 0x3D4: // xvtstdcdp (VSX Test Data Class Double-Precision)
19671 UInt DX_mask = IFIELD( theInstr, 16, 5 );
19672 UInt DC_mask = IFIELD( theInstr, 6, 1 );
19673 UInt DM_mask = IFIELD( theInstr, 2, 1 );
19674 UInt DCMX_mask = (DC_mask << 6) | (DM_mask << 5) | DX_mask;
19676 IRTemp NaN[2], inf[2], zero[2], dnorm[2], pos[2], DCM[2];
19677 IRTemp match_value[2];
19678 IRTemp value[2];
19679 Int i;
19681 DIP("xvtstdcdp v%d,v%d,%d\n", (UInt)XT, (UInt)XB, DCMX_mask);
19683 for (i = 0; i < 2; i++) {
19684 NaN[i] = newTemp(Ity_I64);
19685 inf[i] = newTemp(Ity_I64);
19686 pos[i] = newTemp(Ity_I64);
19687 DCM[i] = newTemp(Ity_I64);
19688 zero[i] = newTemp(Ity_I64);
19689 dnorm[i] = newTemp(Ity_I64);
19691 value[i] = newTemp(Ity_I64);
19692 match_value[i] = newTemp(Ity_I64);
19694 assign( value[i],
19695 unop( Iop_V128to64,
19696 binop( Iop_AndV128,
19697 binop( Iop_ShrV128,
19698 mkexpr( vB ),
19699 mkU8( (1-i)*64 ) ),
19700 binop( Iop_64HLtoV128,
19701 mkU64( 0x0 ),
19702 mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) ) );
19704 assign( pos[i], unop( Iop_1Uto64,
19705 binop( Iop_CmpEQ64,
19706 binop( Iop_Shr64,
19707 mkexpr( value[i] ),
19708 mkU8( 63 ) ),
19709 mkU64( 0 ) ) ) );
19711 assign( NaN[i], unop( Iop_1Uto64, is_NaN( Ity_I64, value[i] ) ) );
19712 assign( inf[i], unop( Iop_1Uto64, is_Inf( Ity_I64, value[i] ) ) );
19713 assign( zero[i], unop( Iop_1Uto64, is_Zero( Ity_I64, value[i] ) ) );
19714 assign( dnorm[i], unop( Iop_1Uto64, is_Denorm( Ity_I64,
19715 value[i] ) ) );
19717 assign( DCM[i], create_DCM( Ity_I64, NaN[i], inf[i], zero[i],
19718 dnorm[i], pos[i] ) );
19720 assign( match_value[i],
19721 unop( Iop_1Sto64,
19722 binop( Iop_CmpNE64,
19723 binop( Iop_And64,
19724 mkU64( DCMX_mask ),
19725 mkexpr( DCM[i] ) ),
19726 mkU64( 0 ) ) ) );
19728 putVSReg( XT, binop( Iop_64HLtoV128,
19729 mkexpr( match_value[0] ),
19730 mkexpr( match_value[1] ) ) );
19732 break;
19734 case 0x3E0: // xviexpdp (VSX Vector Insert Exponent Double-Precision)
19736 Int i;
19737 IRTemp new_XT[3];
19738 IRTemp A_value[2];
19739 IRTemp B_value[2];
19740 IRExpr *sign[2], *expr[2], *fract[2];
19742 DIP("xviexpdp v%d,v%d\n", XT, XB);
19743 new_XT[0] = newTemp(Ity_V128);
19744 assign( new_XT[0], binop( Iop_64HLtoV128,
19745 mkU64( 0x0 ),
19746 mkU64( 0x0 ) ) );
19748 for (i = 0; i < 2; i++) {
19749 A_value[i] = newTemp(Ity_I64);
19750 B_value[i] = newTemp(Ity_I64);
19752 assign( A_value[i],
19753 unop( Iop_V128to64,
19754 binop( Iop_AndV128,
19755 binop( Iop_ShrV128,
19756 mkexpr( vA ),
19757 mkU8( (1-i)*64 ) ),
19758 binop( Iop_64HLtoV128,
19759 mkU64( 0x0 ),
19760 mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) ) );
19761 assign( B_value[i],
19762 unop( Iop_V128to64,
19763 binop( Iop_AndV128,
19764 binop( Iop_ShrV128,
19765 mkexpr( vB ),
19766 mkU8( (1-i)*64 ) ),
19767 binop( Iop_64HLtoV128,
19768 mkU64( 0x0 ),
19769 mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) ) );
19771 sign[i] = binop( Iop_And64, mkexpr( A_value[i] ),
19772 mkU64( 0x8000000000000000 ) );
19773 expr[i] = binop( Iop_Shl64,
19774 binop( Iop_And64, mkexpr( B_value[i] ),
19775 mkU64( 0x7FF ) ),
19776 mkU8( 52 ) );
19777 fract[i] = binop( Iop_And64, mkexpr( A_value[i] ),
19778 mkU64( 0x000FFFFFFFFFFFFF ) );
19780 new_XT[i+1] = newTemp(Ity_V128);
19781 assign( new_XT[i+1],
19782 binop( Iop_OrV128,
19783 binop( Iop_ShlV128,
19784 binop( Iop_64HLtoV128,
19785 mkU64( 0 ),
19786 binop( Iop_Or64,
19787 binop( Iop_Or64,
19788 sign[i],
19789 expr[i] ),
19790 fract[i] ) ),
19791 mkU8( (1-i)*64 ) ),
19792 mkexpr( new_XT[i] ) ) );
19794 putVSReg( XT, mkexpr( new_XT[2] ) );
19796 break;
19798 default:
19799 vex_printf( "dis_vxs_misc(ppc)(opc2)\n" );
19800 return False;
19802 return True;
19806 * VSX vector miscellaneous instructions
19809 static Bool
19810 dis_vx_misc ( UInt theInstr, UInt opc2 )
19812 /* XX3-Form */
19813 UChar XT = ifieldRegXT ( theInstr );
19814 UChar XA = ifieldRegXA ( theInstr );
19815 UChar XB = ifieldRegXB ( theInstr );
19816 IRTemp vA = newTemp( Ity_V128 );
19817 IRTemp vB = newTemp( Ity_V128 );
19818 IRTemp src1 = newTemp(Ity_I64);
19819 IRTemp src2 = newTemp(Ity_I64);
19820 IRTemp result_mask = newTemp(Ity_I64);
19821 IRTemp cmp_mask = newTemp(Ity_I64);
19822 IRTemp nan_mask = newTemp(Ity_I64);
19823 IRTemp snan_mask = newTemp(Ity_I64);
19824 IRTemp word_result = newTemp(Ity_I64);
19825 IRTemp check_result = newTemp(Ity_I64);
19826 IRTemp xT = newTemp( Ity_V128 );
19827 IRTemp nan_cmp_value = newTemp(Ity_I64);
19828 UInt trap_enabled = 0; /* 0 - trap enabled is False */
19830 assign( vA, getVSReg( XA ) );
19831 assign( vB, getVSReg( XB ) );
19832 assign( xT, getVSReg( XT ) );
19834 assign(src1, unop( Iop_V128HIto64, mkexpr( vA ) ) );
19835 assign(src2, unop( Iop_V128HIto64, mkexpr( vB ) ) );
19837 assign( nan_mask,
19838 binop( Iop_Or64,
19839 unop( Iop_1Sto64, is_NaN( Ity_I64, src1 ) ),
19840 unop( Iop_1Sto64, is_NaN( Ity_I64, src2 ) ) ) );
19842 if ( trap_enabled == 0 )
19843 /* Traps on invalid operation are assumed not enabled, assign
19844 result of comparison to xT.
19846 assign( snan_mask, mkU64( 0 ) );
19848 else
19849 assign( snan_mask,
19850 binop( Iop_Or64,
19851 unop( Iop_1Sto64, is_sNaN( Ity_I64, src1 ) ),
19852 unop( Iop_1Sto64, is_sNaN( Ity_I64, src2 ) ) ) );
19854 assign (result_mask, binop( Iop_Or64,
19855 mkexpr( snan_mask ),
19856 mkexpr( nan_mask ) ) );
19858 switch (opc2) {
19859 case 0xC: //xscmpeqdp
19861 DIP("xscmpeqdp v%d,v%d,v%d\n", XT, XA, XB);
19862 /* extract double-precision floating point source values from
19863 double word 0 */
19865 /* result of Iop_CmpF64 is 0x40 if operands are equal,
19866 mask is all 1's if equal. */
19868 assign( cmp_mask,
19869 unop( Iop_1Sto64,
19870 unop(Iop_32to1,
19871 binop(Iop_Shr32,
19872 binop( Iop_CmpF64,
19873 unop( Iop_ReinterpI64asF64,
19874 mkexpr( src1 ) ),
19875 unop( Iop_ReinterpI64asF64,
19876 mkexpr( src2 ) ) ),
19877 mkU8( 6 ) ) ) ) );
19879 assign( word_result,
19880 binop( Iop_Or64,
19881 binop( Iop_And64, mkexpr( cmp_mask ),
19882 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
19883 binop( Iop_And64,
19884 unop( Iop_Not64, mkexpr( cmp_mask ) ),
19885 mkU64( 0x0 ) ) ) );
19886 assign( nan_cmp_value, mkU64( 0 ) );
19887 break;
19890 case 0x2C: //xscmpgtdp
19892 DIP("xscmpgtdp v%d,v%d,v%d\n", XT, XA, XB);
19893 /* Test for src1 > src2 */
19895 /* Result of Iop_CmpF64 is 0x1 if op1 < op2, set mask to all 1's. */
19896 assign( cmp_mask,
19897 unop( Iop_1Sto64,
19898 unop(Iop_32to1,
19899 binop(Iop_CmpF64,
19900 unop( Iop_ReinterpI64asF64,
19901 mkexpr( src2 ) ),
19902 unop( Iop_ReinterpI64asF64,
19903 mkexpr( src1 ) ) ) ) ) );
19904 assign( word_result,
19905 binop( Iop_Or64,
19906 binop( Iop_And64, mkexpr( cmp_mask ),
19907 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
19908 binop( Iop_And64,
19909 unop( Iop_Not64, mkexpr( cmp_mask ) ),
19910 mkU64( 0x0 ) ) ) );
19911 assign( nan_cmp_value, mkU64( 0 ) );
19912 break;
19915 case 0x4C: //xscmpgedp
19917 DIP("xscmpeqdp v%d,v%d,v%d\n", XT, XA, XB);
19918 /* compare src 1 >= src 2 */
19919 /* result of Iop_CmpF64 is 0x40 if operands are equal,
19920 mask is all 1's if equal. */
19921 assign( cmp_mask,
19922 unop( Iop_1Sto64,
19923 unop(Iop_32to1,
19924 binop( Iop_Or32,
19925 binop( Iop_Shr32,
19926 binop(Iop_CmpF64, /* EQ test */
19927 unop( Iop_ReinterpI64asF64,
19928 mkexpr( src1 ) ),
19929 unop( Iop_ReinterpI64asF64,
19930 mkexpr( src2 ) ) ),
19931 mkU8( 6 ) ),
19932 binop(Iop_CmpF64, /* src2 < src 1 test */
19933 unop( Iop_ReinterpI64asF64,
19934 mkexpr( src2 ) ),
19935 unop( Iop_ReinterpI64asF64,
19936 mkexpr( src1 ) ) ) ) ) ) );
19937 assign( word_result,
19938 binop( Iop_Or64,
19939 binop( Iop_And64, mkexpr( cmp_mask ),
19940 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
19941 binop( Iop_And64,
19942 unop( Iop_Not64, mkexpr( cmp_mask ) ),
19943 mkU64( 0x0 ) ) ) );
19944 assign( nan_cmp_value, mkU64( 0 ) );
19945 break;
19948 case 0x200: //xsmaxcdp
19950 DIP("xsmaxcdp v%d,v%d,v%d\n", XT, XA, XB);
19951 /* extract double-precision floating point source values from
19952 double word 0 */
19954 /* result of Iop_CmpF64 is 0x1 if arg1 LT then arg2, */
19955 assign( cmp_mask,
19956 unop( Iop_1Sto64,
19957 unop( Iop_32to1,
19958 binop(Iop_CmpF64,
19959 unop( Iop_ReinterpI64asF64,
19960 mkexpr( src2 ) ),
19961 unop( Iop_ReinterpI64asF64,
19962 mkexpr( src1 ) ) ) ) ) );
19963 assign( word_result,
19964 binop( Iop_Or64,
19965 binop( Iop_And64, mkexpr( cmp_mask ), mkexpr( src1 ) ),
19966 binop( Iop_And64,
19967 unop( Iop_Not64, mkexpr( cmp_mask ) ),
19968 mkexpr( src2 ) ) ) );
19969 assign( nan_cmp_value, mkexpr( src2 ) );
19970 break;
19973 case 0x220: //xsmincdp
19975 DIP("xsmincdp v%d,v%d,v%d\n", XT, XA, XB);
19976 /* extract double-precision floating point source values from
19977 double word 0 */
19979 /* result of Iop_CmpF64 is 0x1 if arg1 less then arg2, */
19980 assign( cmp_mask,
19981 unop( Iop_1Sto64,
19982 unop( Iop_32to1,
19983 binop(Iop_CmpF64,
19984 unop( Iop_ReinterpI64asF64,
19985 mkexpr( src1 ) ),
19986 unop( Iop_ReinterpI64asF64,
19987 mkexpr( src2 ) ) ) ) ) );
19988 assign( word_result,
19989 binop( Iop_Or64,
19990 binop( Iop_And64, mkexpr( cmp_mask ), mkexpr( src1 ) ),
19991 binop( Iop_And64,
19992 unop( Iop_Not64, mkexpr( cmp_mask ) ),
19993 mkexpr( src2 ) ) ) );
19994 assign( nan_cmp_value, mkexpr( src2 ) );
19995 break;
19998 default:
19999 vex_printf( "dis_vx_misc(ppc)(opc2)\n" );
20000 return False;
20003 /* If either argument is NaN, result is src2. If either argument is
20004 SNaN, we are supposed to generate invalid operation exception.
20005 Currently don't support generating exceptions. In case of an
20006 trap enabled invalid operation (SNaN) XT is not changed. The
20007 snan_mask is setup appropriately for trap enabled or not.
20009 assign( check_result,
20010 binop( Iop_Or64,
20011 binop( Iop_And64, mkexpr( snan_mask ),
20012 unop( Iop_V128HIto64, mkexpr( xT ) ) ),
20013 binop( Iop_And64, unop( Iop_Not64,
20014 mkexpr( snan_mask ) ),
20015 binop( Iop_Or64,
20016 binop( Iop_And64, mkexpr( nan_mask ),
20017 mkexpr( nan_cmp_value ) ),
20018 binop( Iop_And64,
20019 unop( Iop_Not64,
20020 mkexpr( nan_mask ) ),
20021 mkU64( 0 ) ) ) ) ) );
20023 /* If SNaN is true, then the result is unchanged if a trap-enabled
20024 Invalid Operation occurs. Result mask already setup for trap-enabled
20025 case.
20027 putVSReg( XT,
20028 binop( Iop_64HLtoV128,
20029 binop( Iop_Or64,
20030 binop( Iop_And64,
20031 unop( Iop_Not64, mkexpr( result_mask ) ),
20032 mkexpr( word_result ) ),
20033 binop( Iop_And64,
20034 mkexpr( result_mask ),
20035 mkexpr( check_result ) ) ),
20036 mkU64( 0 ) ) );
20037 return True;
20041 * VSX Logical Instructions
20043 static Bool
20044 dis_vx_logic ( UInt theInstr, UInt opc2 )
20046 /* XX3-Form */
20047 UChar opc1 = ifieldOPC( theInstr );
20048 UChar XT = ifieldRegXT ( theInstr );
20049 UChar XA = ifieldRegXA ( theInstr );
20050 UChar XB = ifieldRegXB ( theInstr );
20051 IRTemp vA = newTemp( Ity_V128 );
20052 IRTemp vB = newTemp( Ity_V128 );
20054 if (opc1 != 0x3C) {
20055 vex_printf( "dis_vx_logic(ppc)(instr)\n" );
20056 return False;
20059 assign( vA, getVSReg( XA ) );
20060 assign( vB, getVSReg( XB ) );
20062 switch (opc2) {
20063 case 0x268: // xxlxor
20064 DIP("xxlxor v%d,v%d,v%d\n", XT, XA, XB);
20065 putVSReg( XT, binop( Iop_XorV128, mkexpr( vA ), mkexpr( vB ) ) );
20066 break;
20067 case 0x248: // xxlor
20068 DIP("xxlor v%d,v%d,v%d\n", XT, XA, XB);
20069 putVSReg( XT, binop( Iop_OrV128, mkexpr( vA ), mkexpr( vB ) ) );
20070 break;
20071 case 0x288: // xxlnor
20072 DIP("xxlnor v%d,v%d,v%d\n", XT, XA, XB);
20073 putVSReg( XT, unop( Iop_NotV128, binop( Iop_OrV128, mkexpr( vA ),
20074 mkexpr( vB ) ) ) );
20075 break;
20076 case 0x208: // xxland
20077 DIP("xxland v%d,v%d,v%d\n", XT, XA, XB);
20078 putVSReg( XT, binop( Iop_AndV128, mkexpr( vA ), mkexpr( vB ) ) );
20079 break;
20080 case 0x228: //xxlandc
20081 DIP("xxlandc v%d,v%d,v%d\n", XT, XA, XB);
20082 putVSReg( XT, binop( Iop_AndV128, mkexpr( vA ), unop( Iop_NotV128,
20083 mkexpr( vB ) ) ) );
20084 break;
20085 case 0x2A8: // xxlorc (VSX Logical OR with complement)
20086 DIP("xxlorc v%d,v%d,v%d\n", XT, XA, XB);
20087 putVSReg( XT, binop( Iop_OrV128,
20088 mkexpr( vA ),
20089 unop( Iop_NotV128, mkexpr( vB ) ) ) );
20090 break;
20091 case 0x2C8: // xxlnand (VSX Logical NAND)
20092 DIP("xxlnand v%d,v%d,v%d\n", XT, XA, XB);
20093 putVSReg( XT, unop( Iop_NotV128,
20094 binop( Iop_AndV128, mkexpr( vA ),
20095 mkexpr( vB ) ) ) );
20096 break;
20097 case 0x2E8: // xxleqv (VSX Logical Equivalence)
20098 DIP("xxleqv v%d,v%d,v%d\n", XT, XA, XB);
20099 putVSReg( XT, unop( Iop_NotV128,
20100 binop( Iop_XorV128,
20101 mkexpr( vA ), mkexpr( vB ) ) ) );
20102 break;
20103 default:
20104 vex_printf( "dis_vx_logic(ppc)(opc2)\n" );
20105 return False;
20107 return True;
20111 * VSX Load Instructions
20112 * NOTE: VSX supports word-aligned storage access.
20114 static Bool
20115 dis_vx_load ( UInt theInstr )
20117 /* XX1-Form */
20118 UChar opc1 = ifieldOPC( theInstr );
20119 UChar XT = ifieldRegXT ( theInstr );
20120 UChar rA_addr = ifieldRegA( theInstr );
20121 UChar rB_addr = ifieldRegB( theInstr );
20122 UInt opc2 = ifieldOPClo10( theInstr );
20124 IRType ty = mode64 ? Ity_I64 : Ity_I32;
20125 IRTemp EA = newTemp( ty );
20127 if (opc1 != 0x1F) {
20128 vex_printf( "dis_vx_load(ppc)(instr)\n" );
20129 return False;
20132 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
20134 switch (opc2) {
20135 case 0x00C: // lxsiwzx (Load VSX Scalar as Integer Word and Zero Indexed)
20137 IRExpr * exp;
20138 DIP("lxsiwzx %d,r%u,r%u\n", XT, rA_addr, rB_addr);
20140 if (host_endness == VexEndnessLE)
20141 exp = unop( Iop_64to32, load( Ity_I64, mkexpr( EA ) ) );
20142 else
20143 exp = unop( Iop_64HIto32, load( Ity_I64, mkexpr( EA ) ) );
20145 putVSReg( XT, binop( Iop_64HLtoV128,
20146 unop( Iop_32Uto64, exp),
20147 mkU64(0) ) );
20148 break;
20150 case 0x04C: // lxsiwax (Load VSX Scalar as Integer Word Algebraic Indexed)
20152 IRExpr * exp;
20153 DIP("lxsiwax %d,r%u,r%u\n", XT, rA_addr, rB_addr);
20155 if (host_endness == VexEndnessLE)
20156 exp = unop( Iop_64to32, load( Ity_I64, mkexpr( EA ) ) );
20157 else
20158 exp = unop( Iop_64HIto32, load( Ity_I64, mkexpr( EA ) ) );
20160 putVSReg( XT, binop( Iop_64HLtoV128,
20161 unop( Iop_32Sto64, exp),
20162 mkU64(0) ) );
20163 break;
20165 case 0x10C: // lxvx
20167 UInt ea_off = 0;
20168 IRExpr* irx_addr;
20169 IRTemp word[4];
20170 int i;
20172 DIP("lxvx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
20174 if ( host_endness == VexEndnessBE ) {
20175 for ( i = 3; i>= 0; i-- ) {
20176 word[i] = newTemp( Ity_I64 );
20178 irx_addr =
20179 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20180 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20182 assign( word[i], unop( Iop_32Uto64,
20183 load( Ity_I32, irx_addr ) ) );
20184 ea_off += 4;
20187 putVSReg( XT, binop( Iop_64HLtoV128,
20188 binop( Iop_Or64,
20189 mkexpr( word[2] ),
20190 binop( Iop_Shl64,
20191 mkexpr( word[3] ),
20192 mkU8( 32 ) ) ),
20193 binop( Iop_Or64,
20194 mkexpr( word[0] ),
20195 binop( Iop_Shl64,
20196 mkexpr( word[1] ),
20197 mkU8( 32 ) ) ) ) );
20198 } else {
20199 for ( i = 0; i< 4; i++ ) {
20200 word[i] = newTemp( Ity_I64 );
20202 irx_addr =
20203 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20204 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20206 assign( word[i], unop( Iop_32Uto64,
20207 load( Ity_I32, irx_addr ) ) );
20208 ea_off += 4;
20211 putVSReg( XT, binop( Iop_64HLtoV128,
20212 binop( Iop_Or64,
20213 mkexpr( word[2] ),
20214 binop( Iop_Shl64,
20215 mkexpr( word[3] ),
20216 mkU8( 32 ) ) ),
20217 binop( Iop_Or64,
20218 mkexpr( word[0] ),
20219 binop( Iop_Shl64,
20220 mkexpr( word[1] ),
20221 mkU8( 32 ) ) ) ) );
20223 break;
20226 case 0x10D: // lxvl
20228 DIP("lxvl %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
20230 IRTemp byte[16];
20231 UInt i;
20232 UInt ea_off = 0;
20233 IRExpr* irx_addr;
20234 IRTemp tmp_low[9];
20235 IRTemp tmp_hi[9];
20236 IRTemp shift = newTemp( Ity_I8 );
20237 IRTemp nb_gt16 = newTemp( Ity_I8 );
20238 IRTemp ld_result = newTemp( Ity_V128 );
20239 IRTemp nb_not_zero = newTemp( Ity_I64 );
20241 IRTemp base_addr = newTemp( ty );
20243 tmp_low[0] = newTemp( Ity_I64 );
20244 tmp_hi[0] = newTemp( Ity_I64 );
20246 assign( base_addr, ea_rAor0( rA_addr ) );
20247 assign( tmp_low[0], mkU64( 0 ) );
20248 assign( tmp_hi[0], mkU64( 0 ) );
20250 /* shift is 15 - nb, where nb = rB[0:7], used to zero out upper bytes */
20251 assign( nb_not_zero, unop( Iop_1Sto64,
20252 binop( Iop_CmpNE64,
20253 mkU64( 0 ),
20254 binop( Iop_Shr64,
20255 getIReg( rB_addr ),
20256 mkU8( 56 ) ) ) ) );
20258 assign( nb_gt16, unop( Iop_1Sto8,
20259 binop( Iop_CmpLT64U,
20260 binop( Iop_Shr64,
20261 getIReg( rB_addr ),
20262 mkU8( 60 ) ),
20263 mkU64( 1 ) ) ) );
20265 /* Set the shift to 0, by ANDing with nb_gt16. nb_gt16 will be all
20266 * zeros if nb > 16. This will result in quad word load being stored.
20268 assign( shift,
20269 binop( Iop_And8,
20270 unop( Iop_64to8,
20271 binop( Iop_Mul64,
20272 binop( Iop_Sub64,
20273 mkU64 ( 16 ),
20274 binop( Iop_Shr64,
20275 getIReg( rB_addr ),
20276 mkU8( 56 ) ) ),
20277 mkU64( 8 ) ) ),
20278 mkexpr( nb_gt16 ) ) );
20280 /* fetch all 16 bytes, we will remove what we don't want later */
20281 if ( host_endness == VexEndnessBE ) {
20282 for ( i = 0; i < 8; i++ ) {
20283 byte[i] = newTemp( Ity_I64 );
20284 tmp_hi[i+1] = newTemp( Ity_I64 );
20286 irx_addr =
20287 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
20288 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20289 ea_off += 1;
20291 assign( byte[i], binop( Iop_Shl64,
20292 unop( Iop_8Uto64,
20293 load( Ity_I8, irx_addr ) ),
20294 mkU8( 8 * ( 7 - i ) ) ) );
20296 assign( tmp_hi[i+1], binop( Iop_Or64,
20297 mkexpr( byte[i] ),
20298 mkexpr( tmp_hi[i] ) ) );
20301 for ( i = 0; i < 8; i++ ) {
20302 byte[i+8] = newTemp( Ity_I64 );
20303 tmp_low[i+1] = newTemp( Ity_I64 );
20305 irx_addr =
20306 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
20307 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20308 ea_off += 1;
20310 assign( byte[i+8], binop( Iop_Shl64,
20311 unop( Iop_8Uto64,
20312 load( Ity_I8, irx_addr ) ),
20313 mkU8( 8 * ( 7 - i ) ) ) );
20315 assign( tmp_low[i+1], binop( Iop_Or64,
20316 mkexpr( byte[i+8] ),
20317 mkexpr( tmp_low[i] ) ) );
20319 assign( ld_result, binop( Iop_ShlV128,
20320 binop( Iop_ShrV128,
20321 binop( Iop_64HLtoV128,
20322 mkexpr( tmp_hi[8] ),
20323 mkexpr( tmp_low[8] ) ),
20324 mkexpr( shift ) ),
20325 mkexpr( shift ) ) );
20326 } else {
20327 for ( i = 0; i < 8; i++ ) {
20328 byte[i] = newTemp( Ity_I64 );
20329 tmp_low[i+1] = newTemp( Ity_I64 );
20331 irx_addr =
20332 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
20333 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20334 ea_off += 1;
20336 assign( byte[i], binop( Iop_Shl64,
20337 unop( Iop_8Uto64,
20338 load( Ity_I8, irx_addr ) ),
20339 mkU8( 8 * i ) ) );
20341 assign( tmp_low[i+1],
20342 binop( Iop_Or64,
20343 mkexpr( byte[i] ), mkexpr( tmp_low[i] ) ) );
20346 for ( i = 0; i < 8; i++ ) {
20347 byte[i + 8] = newTemp( Ity_I64 );
20348 tmp_hi[i+1] = newTemp( Ity_I64 );
20350 irx_addr =
20351 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
20352 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20353 ea_off += 1;
20355 assign( byte[i+8], binop( Iop_Shl64,
20356 unop( Iop_8Uto64,
20357 load( Ity_I8, irx_addr ) ),
20358 mkU8( 8 * i ) ) );
20360 assign( tmp_hi[i+1], binop( Iop_Or64,
20361 mkexpr( byte[i+8] ),
20362 mkexpr( tmp_hi[i] ) ) );
20364 assign( ld_result, binop( Iop_ShrV128,
20365 binop( Iop_ShlV128,
20366 binop( Iop_64HLtoV128,
20367 mkexpr( tmp_hi[8] ),
20368 mkexpr( tmp_low[8] ) ),
20369 mkexpr( shift ) ),
20370 mkexpr( shift ) ) );
20374 /* If nb = 0, mask out the calculated load result so the stored
20375 * value is zero.
20378 putVSReg( XT, binop( Iop_AndV128,
20379 mkexpr( ld_result ),
20380 binop( Iop_64HLtoV128,
20381 mkexpr( nb_not_zero ),
20382 mkexpr( nb_not_zero ) ) ) );
20383 break;
20386 case 0x12D: // lxvll (Load VSX Vector Left-Justified with Length XX1 form)
20388 IRTemp byte[16];
20389 IRTemp tmp_low[9];
20390 IRTemp tmp_hi[9];
20391 IRTemp mask = newTemp(Ity_V128);
20392 IRTemp rB = newTemp( Ity_I64 );
20393 IRTemp nb = newTemp( Ity_I64 );
20394 IRTemp nb_zero = newTemp(Ity_V128);
20395 IRTemp mask_shift = newTemp(Ity_I64);
20396 Int i;
20397 UInt ea_off = 0;
20398 IRExpr* irx_addr;
20399 IRTemp base_addr = newTemp( ty );
20400 IRTemp nb_compare_zero = newTemp( Ity_I64 );
20402 DIP("lxvll %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
20404 tmp_low[0] = newTemp(Ity_I64);
20405 tmp_hi[0] = newTemp(Ity_I64);
20407 assign( rB, getIReg(rB_addr));
20408 assign( base_addr, ea_rAor0( rA_addr ) );
20409 assign( tmp_low[0], mkU64( 0 ) );
20410 assign( tmp_hi[0], mkU64( 0 ) );
20412 /* mask_shift is number of 16 bytes minus (nb times 8-bits per byte) */
20413 assign( nb, binop( Iop_Shr64, mkexpr( rB ), mkU8( 56 ) ) );
20415 assign( nb_compare_zero, unop( Iop_1Sto64,
20416 binop( Iop_CmpEQ64,
20417 mkexpr( nb ),
20418 mkU64( 0 ) ) ) );
20420 /* nb_zero is 0xFF..FF if the nb_field = 0 */
20421 assign( nb_zero, binop( Iop_64HLtoV128,
20422 mkexpr( nb_compare_zero ),
20423 mkexpr( nb_compare_zero ) ) );
20425 assign( mask_shift, binop( Iop_Sub64,
20426 mkU64( 16*8 ),
20427 binop( Iop_Mul64,
20428 mkexpr( nb ),
20429 mkU64( 8 ) ) ) );
20431 /* fetch all 16 bytes, we will remove what we don't want later */
20432 for (i = 0; i < 8; i++) {
20433 byte[i] = newTemp(Ity_I64);
20434 tmp_hi[i+1] = newTemp(Ity_I64);
20436 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
20437 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20438 ea_off += 1;
20440 /* Instruction always loads in Big Endian format */
20441 assign( byte[i], binop( Iop_Shl64,
20442 unop( Iop_8Uto64,
20443 load( Ity_I8, irx_addr ) ),
20444 mkU8( 8 * (7 - i) ) ) );
20445 assign( tmp_hi[i+1],
20446 binop( Iop_Or64,
20447 mkexpr( byte[i] ), mkexpr( tmp_hi[i] ) ) );
20450 for (i = 0; i < 8; i++) {
20451 byte[i + 8] = newTemp(Ity_I64);
20452 tmp_low[i+1] = newTemp(Ity_I64);
20454 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
20455 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20456 ea_off += 1;
20458 /* Instruction always loads in Big Endian format */
20459 assign( byte[i+8], binop( Iop_Shl64,
20460 unop( Iop_8Uto64,
20461 load( Ity_I8, irx_addr ) ),
20462 mkU8( 8 * (7 - i) ) ) );
20463 assign( tmp_low[i+1], binop( Iop_Or64,
20464 mkexpr( byte[i+8] ),
20465 mkexpr( tmp_low[i] ) ) );
20468 /* Create mask to clear the right most 16 - nb bytes, set to zero
20469 * if nb= 0.
20471 assign( mask, binop( Iop_AndV128,
20472 binop( Iop_ShlV128,
20473 binop( Iop_ShrV128,
20474 mkV128( 0xFFFF ),
20475 unop( Iop_64to8, mkexpr( mask_shift ) ) ),
20476 unop( Iop_64to8, mkexpr( mask_shift ) ) ),
20477 unop( Iop_NotV128, mkexpr( nb_zero ) ) ) );
20479 putVSReg( XT, binop( Iop_AndV128,
20480 mkexpr( mask ),
20481 binop( Iop_64HLtoV128,
20482 mkexpr( tmp_hi[8] ),
20483 mkexpr( tmp_low[8] ) ) ) );
20484 break;
20487 case 0x16C: // lxvwsx
20489 IRTemp data = newTemp( Ity_I64 );
20491 DIP("lxvwsx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
20493 /* The load is a 64-bit fetch that is Endian aware, just want
20494 * the lower 32 bits. */
20495 if ( host_endness == VexEndnessBE ) {
20496 UInt ea_off = 4;
20497 IRExpr* irx_addr;
20499 irx_addr =
20500 binop( mkSzOp( ty, Iop_Sub8 ), mkexpr( EA ),
20501 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20503 assign( data, binop( Iop_And64,
20504 load( Ity_I64, irx_addr ),
20505 mkU64( 0xFFFFFFFF ) ) );
20507 } else {
20508 assign( data, binop( Iop_And64,
20509 load( Ity_I64, mkexpr( EA ) ),
20510 mkU64( 0xFFFFFFFF ) ) );
20513 /* Take lower 32-bits and spat across the four word positions */
20514 putVSReg( XT,
20515 binop( Iop_64HLtoV128,
20516 binop( Iop_Or64,
20517 mkexpr( data ),
20518 binop( Iop_Shl64,
20519 mkexpr( data ),
20520 mkU8( 32 ) ) ),
20521 binop( Iop_Or64,
20522 mkexpr( data ),
20523 binop( Iop_Shl64,
20524 mkexpr( data ),
20525 mkU8( 32 ) ) ) ) );
20526 break;
20529 case 0x20C: // lxsspx (Load VSX Scalar Single-Precision Indexed)
20531 IRExpr * exp;
20532 DIP("lxsspx %d,r%u,r%u\n", XT, rA_addr, rB_addr);
20533 /* Take 32-bit floating point value in the upper half of the fetched
20534 * 64-bit value, convert to 64-bit floating point value and load into
20535 * top word of V128.
20537 exp = unop( Iop_ReinterpF64asI64,
20538 unop( Iop_F32toF64,
20539 unop( Iop_ReinterpI32asF32,
20540 load( Ity_I32, mkexpr( EA ) ) ) ) );
20542 putVSReg( XT, binop( Iop_64HLtoV128, exp, mkU64( 0 ) ) );
20543 break;
20545 case 0x24C: // lxsdx
20547 IRExpr * exp;
20548 DIP("lxsdx %d,r%u,r%u\n", XT, rA_addr, rB_addr);
20549 exp = load( Ity_I64, mkexpr( EA ) );
20550 // We need to pass an expression of type Ity_V128 with putVSReg, but the load
20551 // we just performed is only a DW. But since the contents of VSR[XT] element 1
20552 // are undefined after this operation, we can just do a splat op.
20553 putVSReg( XT, binop( Iop_64HLtoV128, exp, exp ) );
20554 break;
20557 case 0x30D: // lxsibzx
20559 IRExpr *byte;
20560 IRExpr* irx_addr;
20562 DIP("lxsibzx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
20564 if ( host_endness == VexEndnessBE )
20565 irx_addr = binop( Iop_Sub64, mkexpr( EA ), mkU64( 7 ) );
20567 else
20568 irx_addr = mkexpr( EA );
20570 byte = load( Ity_I64, irx_addr );
20571 putVSReg( XT, binop( Iop_64HLtoV128,
20572 binop( Iop_And64,
20573 byte,
20574 mkU64( 0xFF ) ),
20575 mkU64( 0 ) ) );
20576 break;
20579 case 0x32D: // lxsihzx
20581 IRExpr *byte;
20582 IRExpr* irx_addr;
20584 DIP("lxsihzx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
20586 if ( host_endness == VexEndnessBE )
20587 irx_addr = binop( Iop_Sub64, mkexpr( EA ), mkU64( 6 ) );
20589 else
20590 irx_addr = mkexpr( EA );
20592 byte = load( Ity_I64, irx_addr );
20593 putVSReg( XT, binop( Iop_64HLtoV128,
20594 binop( Iop_And64,
20595 byte,
20596 mkU64( 0xFFFF ) ),
20597 mkU64( 0 ) ) );
20598 break;
20600 case 0x34C: // lxvd2x
20602 IROp addOp = ty == Ity_I64 ? Iop_Add64 : Iop_Add32;
20603 IRExpr * high, *low;
20604 ULong ea_off = 8;
20605 IRExpr* high_addr;
20606 DIP("lxvd2x %d,r%u,r%u\n", XT, rA_addr, rB_addr);
20607 high = load( Ity_I64, mkexpr( EA ) );
20608 high_addr = binop( addOp, mkexpr( EA ), ty == Ity_I64 ? mkU64( ea_off )
20609 : mkU32( ea_off ) );
20610 low = load( Ity_I64, high_addr );
20611 putVSReg( XT, binop( Iop_64HLtoV128, high, low ) );
20612 break;
20614 case 0x14C: // lxvdsx
20616 IRTemp data = newTemp(Ity_I64);
20617 DIP("lxvdsx %d,r%u,r%u\n", XT, rA_addr, rB_addr);
20618 assign( data, load( Ity_I64, mkexpr( EA ) ) );
20619 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( data ), mkexpr( data ) ) );
20620 break;
20622 case 0x30C:
20624 IRExpr *t0;
20626 DIP("lxvw4x %d,r%u,r%u\n", XT, rA_addr, rB_addr);
20628 /* The load will result in the data being in BE order. */
20629 if (host_endness == VexEndnessLE) {
20630 IRExpr *t0_BE;
20631 IRTemp perm_LE = newTemp(Ity_V128);
20633 t0_BE = load( Ity_V128, mkexpr( EA ) );
20635 /* Permute the data to LE format */
20636 assign( perm_LE, binop( Iop_64HLtoV128, mkU64(0x0c0d0e0f08090a0bULL),
20637 mkU64(0x0405060700010203ULL)));
20639 t0 = binop( Iop_Perm8x16, t0_BE, mkexpr(perm_LE) );
20640 } else {
20641 t0 = load( Ity_V128, mkexpr( EA ) );
20644 putVSReg( XT, t0 );
20645 break;
20648 case 0x32C: // lxvh8x
20650 DIP("lxvh8x %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
20652 IRTemp h_word[8];
20653 int i;
20654 UInt ea_off = 0;
20655 IRExpr* irx_addr;
20656 IRTemp tmp_low[5];
20657 IRTemp tmp_hi[5];
20659 tmp_low[0] = newTemp( Ity_I64 );
20660 tmp_hi[0] = newTemp( Ity_I64 );
20661 assign( tmp_low[0], mkU64( 0 ) );
20662 assign( tmp_hi[0], mkU64( 0 ) );
20664 for ( i = 0; i < 4; i++ ) {
20665 h_word[i] = newTemp(Ity_I64);
20666 tmp_low[i+1] = newTemp(Ity_I64);
20668 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20669 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20670 ea_off += 2;
20672 assign( h_word[i], binop( Iop_Shl64,
20673 unop( Iop_16Uto64,
20674 load( Ity_I16, irx_addr ) ),
20675 mkU8( 16 * ( 3 - i ) ) ) );
20677 assign( tmp_low[i+1],
20678 binop( Iop_Or64,
20679 mkexpr( h_word[i] ), mkexpr( tmp_low[i] ) ) );
20682 for ( i = 0; i < 4; i++ ) {
20683 h_word[i+4] = newTemp( Ity_I64 );
20684 tmp_hi[i+1] = newTemp( Ity_I64 );
20686 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20687 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20688 ea_off += 2;
20690 assign( h_word[i+4], binop( Iop_Shl64,
20691 unop( Iop_16Uto64,
20692 load( Ity_I16, irx_addr ) ),
20693 mkU8( 16 * ( 3 - i ) ) ) );
20695 assign( tmp_hi[i+1], binop( Iop_Or64,
20696 mkexpr( h_word[i+4] ),
20697 mkexpr( tmp_hi[i] ) ) );
20699 putVSReg( XT, binop( Iop_64HLtoV128,
20700 mkexpr( tmp_low[4] ), mkexpr( tmp_hi[4] ) ) );
20701 break;
20704 case 0x36C: // lxvb16x
20706 DIP("lxvb16x %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
20708 IRTemp byte[16];
20709 int i;
20710 UInt ea_off = 0;
20711 IRExpr* irx_addr;
20712 IRTemp tmp_low[9];
20713 IRTemp tmp_hi[9];
20715 tmp_low[0] = newTemp( Ity_I64 );
20716 tmp_hi[0] = newTemp( Ity_I64 );
20717 assign( tmp_low[0], mkU64( 0 ) );
20718 assign( tmp_hi[0], mkU64( 0 ) );
20720 for ( i = 0; i < 8; i++ ) {
20721 byte[i] = newTemp( Ity_I64 );
20722 tmp_low[i+1] = newTemp( Ity_I64 );
20724 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20725 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20726 ea_off += 1;
20728 assign( byte[i], binop( Iop_Shl64,
20729 unop( Iop_8Uto64,
20730 load( Ity_I8, irx_addr ) ),
20731 mkU8( 8 * ( 7 - i ) ) ) );
20733 assign( tmp_low[i+1],
20734 binop( Iop_Or64,
20735 mkexpr( byte[i] ), mkexpr( tmp_low[i] ) ) );
20738 for ( i = 0; i < 8; i++ ) {
20739 byte[i + 8] = newTemp( Ity_I64 );
20740 tmp_hi[i+1] = newTemp( Ity_I64 );
20742 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20743 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20744 ea_off += 1;
20746 assign( byte[i+8], binop( Iop_Shl64,
20747 unop( Iop_8Uto64,
20748 load( Ity_I8, irx_addr ) ),
20749 mkU8( 8 * ( 7 - i ) ) ) );
20750 assign( tmp_hi[i+1], binop( Iop_Or64,
20751 mkexpr( byte[i+8] ),
20752 mkexpr( tmp_hi[i] ) ) );
20754 putVSReg( XT, binop( Iop_64HLtoV128,
20755 mkexpr( tmp_low[8] ), mkexpr( tmp_hi[8] ) ) );
20756 break;
20759 default:
20760 vex_printf( "dis_vx_load(ppc)(opc2)\n" );
20761 return False;
20763 return True;
20767 * VSX Move Instructions
20769 static Bool
20770 dis_vx_move ( UInt theInstr )
20772 /* XX1-Form */
20773 UChar opc1 = ifieldOPC( theInstr );
20774 UChar XS = ifieldRegXS( theInstr );
20775 UChar rA_addr = ifieldRegA( theInstr );
20776 UChar rB_addr = ifieldRegB( theInstr );
20777 IRTemp vS = newTemp( Ity_V128 );
20778 UInt opc2 = ifieldOPClo10( theInstr );
20779 IRType ty = Ity_I64;
20781 if ( opc1 != 0x1F ) {
20782 vex_printf( "dis_vx_move(ppc)(instr)\n" );
20783 return False;
20786 switch (opc2) {
20787 case 0x133: // mfvsrld RA,XS Move From VSR Lower Doubleword
20788 DIP("mfvsrld %d,r%u\n", (UInt)XS, rA_addr);
20790 assign( vS, getVSReg( XS ) );
20791 putIReg( rA_addr, unop(Iop_V128to64, mkexpr( vS) ) );
20793 break;
20795 case 0x193: // mfvsrdd XT,RA,RB Move to VSR Double Doubleword
20797 IRTemp tmp = newTemp( Ity_I32 );
20799 DIP("mfvsrdd %d,r%u\n", (UInt)XS, rA_addr);
20801 assign( tmp, unop( Iop_64to32, getIReg(rA_addr) ) );
20802 assign( vS, binop( Iop_64HLtoV128,
20803 binop( Iop_32HLto64,
20804 mkexpr( tmp ),
20805 mkexpr( tmp ) ),
20806 binop( Iop_32HLto64,
20807 mkexpr( tmp ),
20808 mkexpr( tmp ) ) ) );
20809 putVSReg( XS, mkexpr( vS ) );
20811 break;
20813 case 0x1B3: // mtvsrws XT,RA Move to VSR word & Splat
20815 IRTemp rA = newTemp( ty );
20816 IRTemp rB = newTemp( ty );
20818 DIP("mfvsrws %d,r%u\n", (UInt)XS, rA_addr);
20820 if ( rA_addr == 0 )
20821 assign( rA, mkU64 ( 0 ) );
20822 else
20823 assign( rA, getIReg(rA_addr) );
20825 assign( rB, getIReg(rB_addr) );
20826 assign( vS, binop( Iop_64HLtoV128, mkexpr( rA ), mkexpr( rB ) ) );
20827 putVSReg( XS, mkexpr( vS ) );
20829 break;
20831 default:
20832 vex_printf( "dis_vx_move(ppc)(opc2)\n" );
20833 return False;
20835 return True;
20839 * VSX Store Instructions
20840 * NOTE: VSX supports word-aligned storage access.
20842 static Bool
20843 dis_vx_store ( UInt theInstr )
20845 /* XX1-Form */
20846 UChar opc1 = ifieldOPC( theInstr );
20847 UChar XS = ifieldRegXS( theInstr );
20848 UChar rA_addr = ifieldRegA( theInstr );
20849 UChar rB_addr = ifieldRegB( theInstr );
20850 IRTemp vS = newTemp( Ity_V128 );
20851 UInt opc2 = ifieldOPClo10( theInstr );
20853 IRType ty = mode64 ? Ity_I64 : Ity_I32;
20854 IRTemp EA = newTemp( ty );
20856 if (opc1 != 0x1F) {
20857 vex_printf( "dis_vx_store(ppc)(instr)\n" );
20858 return False;
20861 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
20862 assign( vS, getVSReg( XS ) );
20864 switch (opc2) {
20865 case 0x08C:
20867 /* Need the next to the most significant 32-bit word from
20868 * the 128-bit vector.
20870 IRExpr * high64, * low32;
20871 DIP("stxsiwx %d,r%u,r%u\n", XS, rA_addr, rB_addr);
20872 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
20873 low32 = unop( Iop_64to32, high64 );
20874 store( mkexpr( EA ), low32 );
20875 break;
20878 case 0x18C: // stxvx Store VSX Vector Indexed
20880 UInt ea_off = 0;
20881 IRExpr* irx_addr;
20882 IRTemp word0 = newTemp( Ity_I64 );
20883 IRTemp word1 = newTemp( Ity_I64 );
20884 IRTemp word2 = newTemp( Ity_I64 );
20885 IRTemp word3 = newTemp( Ity_I64 );
20886 DIP("stxvx %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
20888 assign( word0, binop( Iop_Shr64,
20889 unop( Iop_V128HIto64, mkexpr( vS ) ),
20890 mkU8( 32 ) ) );
20892 assign( word1, binop( Iop_And64,
20893 unop( Iop_V128HIto64, mkexpr( vS ) ),
20894 mkU64( 0xFFFFFFFF ) ) );
20896 assign( word2, binop( Iop_Shr64,
20897 unop( Iop_V128to64, mkexpr( vS ) ),
20898 mkU8( 32 ) ) );
20900 assign( word3, binop( Iop_And64,
20901 unop( Iop_V128to64, mkexpr( vS ) ),
20902 mkU64( 0xFFFFFFFF ) ) );
20904 if (host_endness == VexEndnessBE) {
20905 store( mkexpr( EA ), unop( Iop_64to32, mkexpr( word0 ) ) );
20907 ea_off += 4;
20908 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20909 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20911 store( irx_addr, unop( Iop_64to32, mkexpr( word1 ) ) );
20913 ea_off += 4;
20914 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20915 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20917 store( irx_addr, unop( Iop_64to32, mkexpr( word2 ) ) );
20918 ea_off += 4;
20919 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20920 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20922 store( irx_addr, unop( Iop_64to32, mkexpr( word3 ) ) );
20923 } else {
20924 store( mkexpr( EA ), unop( Iop_64to32, mkexpr( word3 ) ) );
20926 ea_off += 4;
20927 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20928 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20930 store( irx_addr, unop( Iop_64to32, mkexpr( word2 ) ) );
20932 ea_off += 4;
20933 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20934 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20936 store( irx_addr, unop( Iop_64to32, mkexpr( word1 ) ) );
20937 ea_off += 4;
20938 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
20939 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
20941 store( irx_addr, unop( Iop_64to32, mkexpr( word0 ) ) );
20943 break;
20946 case 0x18D: // stxvl Store VSX Vector Indexed
20948 UInt ea_off = 0;
20949 IRExpr* irx_addr;
20950 IRTemp word0 = newTemp( Ity_I64 );
20951 IRTemp word1 = newTemp( Ity_I64 );
20952 IRTemp word2 = newTemp( Ity_I64 );
20953 IRTemp word3 = newTemp( Ity_I64 );
20954 IRTemp shift = newTemp( Ity_I8 );
20955 IRTemp nb_gt16 = newTemp( Ity_I8 );
20956 IRTemp nb_zero = newTemp( Ity_V128 );
20957 IRTemp nb = newTemp( Ity_I8 );
20958 IRTemp nb_field = newTemp( Ity_I64 );
20959 IRTemp n_bytes = newTemp( Ity_I8 );
20960 IRTemp base_addr = newTemp( ty );
20961 IRTemp current_mem = newTemp( Ity_V128 );
20962 IRTemp store_val = newTemp( Ity_V128 );
20963 IRTemp nb_mask = newTemp( Ity_V128 );
20965 DIP("stxvl %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
20967 assign( nb_field, binop( Iop_Shr64,
20968 getIReg(rB_addr),
20969 mkU8( 56 ) ) );
20971 assign( nb, unop( Iop_64to8, mkexpr( nb_field ) ) );
20973 /* nb_gt16 will be all zeros if nb > 16 */
20974 assign( nb_gt16, unop( Iop_1Sto8,
20975 binop( Iop_CmpLT64U,
20976 binop( Iop_Shr64,
20977 mkexpr( nb_field ),
20978 mkU8( 4 ) ),
20979 mkU64( 1 ) ) ) );
20981 /* nb_zero is 0xFF..FF if the nb_field = 0 */
20982 assign( nb_zero, binop( Iop_64HLtoV128,
20983 unop( Iop_1Sto64,
20984 binop( Iop_CmpEQ64,
20985 mkexpr( nb_field ),
20986 mkU64( 0 ) ) ),
20987 unop( Iop_1Sto64,
20988 binop( Iop_CmpEQ64,
20989 mkexpr( nb_field ),
20990 mkU64( 0 ) ) ) ) );
20992 /* set n_bytes to 0 if nb >= 16. Otherwise, set to nb. */
20993 assign( n_bytes, binop( Iop_And8, mkexpr( nb ), mkexpr( nb_gt16 ) ) );
20994 assign( shift, unop( Iop_64to8,
20995 binop( Iop_Mul64,
20996 binop( Iop_Sub64,
20997 mkU64( 16 ),
20998 unop( Iop_8Uto64,
20999 mkexpr( n_bytes ) ) ),
21000 mkU64( 8 ) ) ) );
21002 /* We only have a 32-bit store function. So, need to fetch the
21003 * contents of memory merge with the store value and do two
21004 * 32-byte stores so we preserve the contents of memory not
21005 * addressed by nb.
21007 assign( base_addr, ea_rAor0( rA_addr ) );
21009 assign( current_mem,
21010 binop( Iop_64HLtoV128,
21011 load( Ity_I64,
21012 binop( mkSzOp( ty, Iop_Add8 ),
21013 mkexpr( base_addr ),
21014 ty == Ity_I64 ? mkU64( 8 ) : mkU32( 8 )
21015 ) ),
21016 load( Ity_I64, mkexpr( base_addr ) ) ) );
21018 /* Set the nb_mask to all zeros if nb = 0 so the current contents
21019 * of memory get written back without modifications.
21021 * The store_val is a combination of the current memory value
21022 * and the bytes you want to store. The nb_mask selects the
21023 * bytes you want stored from Vs.
21025 assign( nb_mask,
21026 binop( Iop_OrV128,
21027 binop( Iop_AndV128,
21028 mkexpr( nb_zero ),
21029 mkV128( 0 ) ),
21030 binop( Iop_AndV128,
21031 binop( Iop_ShrV128,
21032 mkV128( 0xFFFF ),
21033 mkexpr( shift ) ),
21034 unop( Iop_NotV128, mkexpr( nb_zero ) ) ) ) );
21036 assign( store_val,
21037 binop( Iop_OrV128,
21038 binop( Iop_AndV128,
21039 mkexpr( vS ),
21040 mkexpr( nb_mask ) ),
21041 binop( Iop_AndV128,
21042 unop( Iop_NotV128, mkexpr( nb_mask ) ),
21043 mkexpr( current_mem) ) ) );
21045 /* Store the value in 32-byte chunks */
21046 assign( word0, binop( Iop_Shr64,
21047 unop( Iop_V128HIto64, mkexpr( store_val ) ),
21048 mkU8( 32 ) ) );
21050 assign( word1, binop( Iop_And64,
21051 unop( Iop_V128HIto64, mkexpr( store_val ) ),
21052 mkU64( 0xFFFFFFFF ) ) );
21054 assign( word2, binop( Iop_Shr64,
21055 unop( Iop_V128to64, mkexpr( store_val ) ),
21056 mkU8( 32 ) ) );
21058 assign( word3, binop( Iop_And64,
21059 unop( Iop_V128to64, mkexpr( store_val ) ),
21060 mkU64( 0xFFFFFFFF ) ) );
21062 ea_off = 0;
21063 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21064 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21066 store( irx_addr, unop( Iop_64to32, mkexpr( word3 ) ) );
21068 ea_off += 4;
21069 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21070 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21072 store( irx_addr, unop( Iop_64to32, mkexpr( word2 ) ) );
21074 ea_off += 4;
21075 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21076 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21078 store( irx_addr, unop( Iop_64to32, mkexpr( word1 ) ) );
21080 ea_off += 4;
21081 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21082 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21084 store( irx_addr, unop( Iop_64to32, mkexpr( word0 ) ) );
21085 break;
21088 case 0x1AD: // stxvll (Store VSX Vector Left-justified with length XX1-form)
21090 UInt ea_off = 0;
21091 IRExpr* irx_addr;
21092 IRTemp word0[5];
21093 IRTemp word1[5];
21094 IRTemp word2[5];
21095 IRTemp word3[5];
21096 IRTemp shift = newTemp(Ity_I8);
21097 IRTemp nb_gt16 = newTemp(Ity_I8);
21098 IRTemp nb_zero = newTemp(Ity_V128);
21099 IRTemp nb = newTemp(Ity_I8);
21100 IRTemp nb_field = newTemp(Ity_I64);
21101 IRTemp n_bytes = newTemp(Ity_I8);
21102 IRTemp base_addr = newTemp( ty );
21103 IRTemp current_mem = newTemp(Ity_V128);
21104 IRTemp store_val = newTemp(Ity_V128);
21105 IRTemp nb_mask = newTemp(Ity_V128);
21106 IRTemp mask = newTemp( Ity_I64 );
21107 IRTemp byte[16];
21108 IRTemp tmp_low[9];
21109 IRTemp tmp_hi[9];
21110 IRTemp nb_field_compare_zero = newTemp( Ity_I64 );
21111 Int i;
21113 DIP("stxvll %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21115 assign( nb_field, binop( Iop_Shr64,
21116 getIReg(rB_addr),
21117 mkU8( 56 ) ) );
21118 assign( nb, unop( Iop_64to8, mkexpr( nb_field ) ) );
21119 assign( mask, mkU64( 0xFFFFFFFFFFFFFFFFULL ) );
21121 /* nb_gt16 will be all zeros if nb > 16 */
21122 assign( nb_gt16, unop( Iop_1Sto8,
21123 binop( Iop_CmpLT64U,
21124 binop( Iop_Shr64,
21125 mkexpr( nb_field ),
21126 mkU8( 4 ) ),
21127 mkU64( 1 ) ) ) );
21129 assign( nb_field_compare_zero, unop( Iop_1Sto64,
21130 binop( Iop_CmpEQ64,
21131 mkexpr( nb_field ),
21132 mkU64( 0 ) ) ) );
21134 /* nb_zero is 0xFF..FF if the nb_field = 0 */
21135 assign( nb_zero, binop( Iop_64HLtoV128,
21136 mkexpr( nb_field_compare_zero ),
21137 mkexpr( nb_field_compare_zero ) ) );
21140 /* set n_bytes to 0 if nb >= 16. Otherwise, set to nb. */
21141 assign( n_bytes, binop( Iop_And8, mkexpr( nb ), mkexpr( nb_gt16 ) ) );
21142 assign( shift,
21143 unop( Iop_64to8,
21144 binop( Iop_Mul64,
21145 binop( Iop_Sub64,
21146 mkU64( 16 ),
21147 unop( Iop_8Uto64, mkexpr( n_bytes ) )),
21148 mkU64( 8 ) ) ) );
21150 /* We only have a 32-bit store function. So, need to fetch the
21151 * contents of memory merge with the store value and do two
21152 * 32-byte stores so we preserve the contents of memory not
21153 * addressed by nb.
21155 assign( base_addr, ea_rAor0( rA_addr ) );
21156 /* fetch all 16 bytes and store in Big Endian format */
21157 word0[0] = newTemp(Ity_I64);
21158 assign( word0[0], mkU64( 0 ) );
21160 word1[0] = newTemp(Ity_I64);
21161 assign( word1[0], mkU64( 0 ) );
21163 word2[0] = newTemp(Ity_I64);
21164 assign( word2[0], mkU64( 0 ) );
21166 word3[0] = newTemp(Ity_I64);
21167 assign( word3[0], mkU64( 0 ) );
21169 for (i = 0; i < 4; i++) {
21170 word0[i+1] = newTemp(Ity_I64);
21172 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21173 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21174 ea_off += 1;
21176 /* Instruction always loads in Big Endian format */
21177 assign( word0[i+1],
21178 binop( Iop_Or64,
21179 binop( Iop_Shl64,
21180 unop( Iop_8Uto64,
21181 load( Ity_I8,
21182 irx_addr ) ),
21183 mkU8( (3-i)*8 ) ),
21184 mkexpr( word0[i] ) ) );
21187 for (i = 0; i < 4; i++) {
21188 word1[i+1] = newTemp(Ity_I64);
21190 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21191 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21192 ea_off += 1;
21194 /* Instruction always loads in Big Endian format */
21195 assign( word1[i+1],
21196 binop( Iop_Or64,
21197 binop( Iop_Shl64,
21198 unop( Iop_8Uto64,
21199 load( Ity_I8,
21200 irx_addr ) ),
21201 mkU8( (3-i)*8 ) ),
21202 mkexpr( word1[i] ) ) );
21204 for (i = 0; i < 4; i++) {
21205 word2[i+1] = newTemp(Ity_I64);
21207 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21208 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21209 ea_off += 1;
21211 /* Instruction always loads in Big Endian format */
21212 assign( word2[i+1],
21213 binop( Iop_Or64,
21214 binop( Iop_Shl64,
21215 unop( Iop_8Uto64,
21216 load( Ity_I8,
21217 irx_addr ) ),
21218 mkU8( (3-i)*8 ) ),
21219 mkexpr( word2[i] ) ) );
21221 for (i = 0; i < 4; i++) {
21222 word3[i+1] = newTemp(Ity_I64);
21224 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21225 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21226 ea_off += 1;
21228 /* Instruction always loads in Big Endian format */
21229 assign( word3[i+1],
21230 binop( Iop_Or64,
21231 binop( Iop_Shl64,
21232 unop( Iop_8Uto64,
21233 load( Ity_I8,
21234 irx_addr ) ),
21235 mkU8( (3-i)*8 ) ),
21236 mkexpr( word3[i] ) ) );
21240 assign( current_mem,
21241 binop( Iop_64HLtoV128,
21242 binop( Iop_Or64,
21243 binop( Iop_Shl64,
21244 mkexpr( word0[4] ),
21245 mkU8( 32 ) ),
21246 mkexpr( word1[4] ) ),
21247 binop( Iop_Or64,
21248 binop( Iop_Shl64,
21249 mkexpr( word2[4] ),
21250 mkU8( 32 ) ),
21251 mkexpr( word3[4] ) ) ) );
21253 /* Set the nb_mask to all zeros if nb = 0 so the current contents
21254 * of memory get written back without modifications.
21256 * The store_val is a combination of the current memory value
21257 * and the bytes you want to store. The nb_mask selects the
21258 * bytes you want stored from Vs.
21260 /* The instruction always uses Big Endian order */
21261 assign( nb_mask,
21262 binop( Iop_OrV128,
21263 binop( Iop_AndV128,
21264 binop( Iop_ShlV128,
21265 binop( Iop_ShrV128,
21266 binop( Iop_64HLtoV128,
21267 mkexpr( mask ),
21268 mkexpr( mask ) ),
21269 mkexpr( shift ) ),
21270 mkexpr( shift ) ),
21271 unop( Iop_NotV128, mkexpr( nb_zero ) ) ),
21272 binop( Iop_AndV128,
21273 mkexpr( nb_zero ),
21274 binop( Iop_64HLtoV128,
21275 mkU64( 0x0 ),
21276 mkU64( 0x0 ) ) ) ) );
21278 assign( store_val,
21279 binop( Iop_OrV128,
21280 binop( Iop_AndV128,
21281 mkexpr( vS ),
21282 mkexpr( nb_mask ) ),
21283 binop( Iop_AndV128,
21284 unop( Iop_NotV128, mkexpr( nb_mask ) ),
21285 mkexpr( current_mem) ) ) );
21287 /* store the merged value in Big Endian format */
21288 tmp_low[0] = newTemp(Ity_I64);
21289 tmp_hi[0] = newTemp(Ity_I64);
21290 assign( tmp_low[0], mkU64( 0 ) );
21291 assign( tmp_hi[0], mkU64( 0 ) );
21293 for (i = 0; i < 8; i++) {
21294 byte[i] = newTemp(Ity_I64);
21295 byte[i+8] = newTemp(Ity_I64);
21296 tmp_low[i+1] = newTemp(Ity_I64);
21297 tmp_hi[i+1] = newTemp(Ity_I64);
21299 assign( byte[i], binop( Iop_And64,
21300 binop( Iop_Shr64,
21301 unop( Iop_V128HIto64,
21302 mkexpr( store_val ) ),
21303 mkU8( (7-i)*8 ) ),
21304 mkU64( 0xFF ) ) );
21305 assign( byte[i+8], binop( Iop_And64,
21306 binop( Iop_Shr64,
21307 unop( Iop_V128to64,
21308 mkexpr( store_val ) ),
21309 mkU8( (7-i)*8 ) ),
21310 mkU64( 0xFF ) ) );
21312 assign( tmp_low[i+1],
21313 binop( Iop_Or64,
21314 mkexpr( tmp_low[i] ),
21315 binop( Iop_Shl64, mkexpr( byte[i] ), mkU8( i*8 ) ) ) );
21316 assign( tmp_hi[i+1],
21317 binop( Iop_Or64,
21318 mkexpr( tmp_hi[i] ),
21319 binop( Iop_Shl64, mkexpr( byte[i+8] ),
21320 mkU8( i*8 ) ) ) );
21323 /* Store the value in 32-byte chunks */
21324 ea_off = 0;
21325 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21326 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21328 store( irx_addr, unop( Iop_64to32, mkexpr( tmp_low[8] ) ) );
21330 ea_off += 4;
21331 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21332 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21334 store( irx_addr, unop( Iop_64HIto32, mkexpr( tmp_low[8] ) ) );
21336 ea_off += 4;
21337 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21338 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21340 store( irx_addr, unop( Iop_64to32, mkexpr( tmp_hi[8] ) ) );
21342 ea_off += 4;
21343 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
21344 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21346 store( irx_addr, unop( Iop_64HIto32, mkexpr( tmp_hi[8] ) ) );
21348 break;
21351 case 0x28C:
21353 IRTemp high64 = newTemp(Ity_F64);
21354 IRTemp val32 = newTemp(Ity_I32);
21355 DIP("stxsspx %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21356 assign(high64, unop( Iop_ReinterpI64asF64,
21357 unop( Iop_V128HIto64, mkexpr( vS ) ) ) );
21358 assign(val32, unop( Iop_ReinterpF32asI32,
21359 unop( Iop_TruncF64asF32,
21360 mkexpr(high64) ) ) );
21361 store( mkexpr( EA ), mkexpr( val32 ) );
21362 break;
21364 case 0x2CC:
21366 IRExpr * high64;
21367 DIP("stxsdx %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21368 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
21369 store( mkexpr( EA ), high64 );
21370 break;
21373 case 0x38D: // stxsibx
21375 IRExpr *stored_word;
21376 IRTemp byte_to_store = newTemp( Ity_I64 );
21378 DIP("stxsibx %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21380 /* Can't store just a byte, need to fetch the word at EA merge data
21381 * and store.
21383 stored_word = load( Ity_I64, mkexpr( EA ) );
21384 assign( byte_to_store, binop( Iop_And64,
21385 unop( Iop_V128HIto64,
21386 mkexpr( vS ) ),
21387 mkU64( 0xFF ) ) );
21389 store( mkexpr( EA ), binop( Iop_Or64,
21390 binop( Iop_And64,
21391 stored_word,
21392 mkU64( 0xFFFFFFFFFFFFFF00 ) ),
21393 mkexpr( byte_to_store ) ) );
21394 break;
21397 case 0x3AD: // stxsihx
21399 IRExpr *stored_word;
21400 IRTemp byte_to_store = newTemp( Ity_I64 );
21402 DIP("stxsihx %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21404 /* Can't store just a halfword, need to fetch the word at EA merge data
21405 * and store.
21407 stored_word = load( Ity_I64, mkexpr( EA ) );
21408 assign( byte_to_store, binop( Iop_And64,
21409 unop( Iop_V128HIto64,
21410 mkexpr( vS ) ),
21411 mkU64( 0xFFFF ) ) );
21413 store( mkexpr( EA ), binop( Iop_Or64,
21414 binop( Iop_And64,
21415 stored_word,
21416 mkU64( 0xFFFFFFFFFFFF0000 ) ),
21417 mkexpr( byte_to_store ) ) );
21418 break;
21421 case 0x3CC:
21423 IRExpr * high64, *low64;
21424 DIP("stxvd2x %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21425 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
21426 low64 = unop( Iop_V128to64, mkexpr( vS ) );
21427 store( mkexpr( EA ), high64 );
21428 store( binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21429 ty == Ity_I64 ? mkU64( 8 ) : mkU32( 8 ) ), low64 );
21430 break;
21432 case 0x38C:
21434 UInt ea_off = 0;
21435 IRExpr* irx_addr;
21436 IRTemp hi64 = newTemp( Ity_I64 );
21437 IRTemp lo64 = newTemp( Ity_I64 );
21439 DIP("stxvw4x %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21441 // This instruction supports word-aligned stores, so EA may not be
21442 // quad-word aligned. Therefore, do 4 individual word-size stores.
21443 assign( hi64, unop( Iop_V128HIto64, mkexpr( vS ) ) );
21444 assign( lo64, unop( Iop_V128to64, mkexpr( vS ) ) );
21445 store( mkexpr( EA ), unop( Iop_64HIto32, mkexpr( hi64 ) ) );
21446 ea_off += 4;
21447 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21448 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21449 store( irx_addr, unop( Iop_64to32, mkexpr( hi64 ) ) );
21450 ea_off += 4;
21451 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21452 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21453 store( irx_addr, unop( Iop_64HIto32, mkexpr( lo64 ) ) );
21454 ea_off += 4;
21455 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21456 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21457 store( irx_addr, unop( Iop_64to32, mkexpr( lo64 ) ) );
21459 break;
21461 case 0x3AC: // stxvh8x Store VSX Vector Halfword*8 Indexed
21463 UInt ea_off = 0;
21464 IRExpr* irx_addr;
21465 IRTemp half_word0 = newTemp( Ity_I64 );
21466 IRTemp half_word1 = newTemp( Ity_I64 );
21467 IRTemp half_word2 = newTemp( Ity_I64 );
21468 IRTemp half_word3 = newTemp( Ity_I64 );
21469 IRTemp half_word4 = newTemp( Ity_I64 );
21470 IRTemp half_word5 = newTemp( Ity_I64 );
21471 IRTemp half_word6 = newTemp( Ity_I64 );
21472 IRTemp half_word7 = newTemp( Ity_I64 );
21474 DIP("stxvb8x %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21476 assign( half_word0, binop( Iop_Shr64,
21477 unop( Iop_V128HIto64, mkexpr( vS ) ),
21478 mkU8( 48 ) ) );
21480 assign( half_word1, binop( Iop_And64,
21481 binop( Iop_Shr64,
21482 unop( Iop_V128HIto64, mkexpr( vS ) ),
21483 mkU8( 32 ) ),
21484 mkU64( 0xFFFF ) ) );
21486 assign( half_word2, binop( Iop_And64,
21487 binop( Iop_Shr64,
21488 unop( Iop_V128HIto64, mkexpr( vS ) ),
21489 mkU8( 16 ) ),
21490 mkU64( 0xFFFF ) ) );
21492 assign( half_word3, binop( Iop_And64,
21493 unop( Iop_V128HIto64, mkexpr( vS ) ),
21494 mkU64( 0xFFFF ) ) );
21496 assign( half_word4, binop( Iop_Shr64,
21497 unop( Iop_V128to64, mkexpr( vS ) ),
21498 mkU8( 48 ) ) );
21500 assign( half_word5, binop( Iop_And64,
21501 binop( Iop_Shr64,
21502 unop( Iop_V128to64, mkexpr( vS ) ),
21503 mkU8( 32 ) ),
21504 mkU64( 0xFFFF ) ) );
21506 assign( half_word6, binop( Iop_And64,
21507 binop( Iop_Shr64,
21508 unop( Iop_V128to64, mkexpr( vS ) ),
21509 mkU8( 16 ) ),
21510 mkU64( 0xFFFF ) ) );
21512 assign( half_word7, binop( Iop_And64,
21513 unop( Iop_V128to64, mkexpr( vS ) ),
21514 mkU64( 0xFFFF ) ) );
21516 /* Do the 32-bit stores. The store() does an Endian aware store. */
21517 if ( host_endness == VexEndnessBE ) {
21518 store( mkexpr( EA ), unop( Iop_64to32,
21519 binop( Iop_Or64,
21520 mkexpr( half_word1 ),
21521 binop( Iop_Shl64,
21522 mkexpr( half_word0 ),
21523 mkU8( 16 ) ) ) ) );
21525 ea_off += 4;
21526 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21527 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21530 store( irx_addr, unop( Iop_64to32,
21531 binop( Iop_Or64,
21532 mkexpr( half_word3 ),
21533 binop( Iop_Shl64,
21534 mkexpr( half_word2 ),
21535 mkU8( 16 ) ) ) ) );
21537 ea_off += 4;
21538 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21539 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21541 store( irx_addr, unop( Iop_64to32,
21542 binop( Iop_Or64,
21543 mkexpr( half_word5 ),
21544 binop( Iop_Shl64,
21545 mkexpr( half_word4 ),
21546 mkU8( 16 ) ) ) ) );
21547 ea_off += 4;
21548 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21549 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21551 store( irx_addr, unop( Iop_64to32,
21552 binop( Iop_Or64,
21553 mkexpr( half_word7 ),
21554 binop( Iop_Shl64,
21555 mkexpr( half_word6 ),
21556 mkU8( 16 ) ) ) ) );
21558 } else {
21559 store( mkexpr( EA ), unop( Iop_64to32,
21560 binop( Iop_Or64,
21561 mkexpr( half_word0 ),
21562 binop( Iop_Shl64,
21563 mkexpr( half_word1 ),
21564 mkU8( 16 ) ) ) ) );
21566 ea_off += 4;
21567 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21568 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21570 store( irx_addr, unop( Iop_64to32,
21571 binop( Iop_Or64,
21572 mkexpr( half_word2 ),
21573 binop( Iop_Shl64,
21574 mkexpr( half_word3 ),
21575 mkU8( 16 ) ) ) ) );
21576 ea_off += 4;
21577 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21578 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21580 store( irx_addr, unop( Iop_64to32,
21581 binop( Iop_Or64,
21582 mkexpr( half_word4 ),
21583 binop( Iop_Shl64,
21584 mkexpr( half_word5 ),
21585 mkU8( 16 ) ) ) ) );
21586 ea_off += 4;
21587 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21588 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21590 store( irx_addr, unop( Iop_64to32,
21591 binop( Iop_Or64,
21592 mkexpr( half_word6 ),
21593 binop( Iop_Shl64,
21594 mkexpr( half_word7 ),
21595 mkU8( 16 ) ) ) ) );
21597 break;
21600 case 0x3EC: // stxvb16x Store VSX Vector Byte*16 Indexed
21602 UInt ea_off = 0;
21603 int i;
21604 IRExpr* irx_addr;
21605 IRTemp byte[16];
21607 DIP("stxvb16x %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
21609 for ( i = 0; i < 8; i++ ) {
21610 byte[i] = newTemp( Ity_I64 );
21611 byte[i+8] = newTemp( Ity_I64 );
21613 assign( byte[i], binop( Iop_And64,
21614 binop( Iop_Shr64,
21615 unop( Iop_V128HIto64, mkexpr( vS ) ),
21616 mkU8( 56 - i*8 ) ),
21617 mkU64( 0xFF ) ) );
21619 assign( byte[i+8], binop( Iop_And64,
21620 binop( Iop_Shr64,
21621 unop( Iop_V128to64, mkexpr( vS ) ),
21622 mkU8( 56 - i*8) ),
21623 mkU64( 0xFF ) ) );
21626 if ( host_endness == VexEndnessBE ) {
21627 for ( i = 0; i < 16; i = i + 4) {
21628 irx_addr =
21629 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21630 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21632 store( irx_addr,
21633 unop( Iop_64to32,
21634 binop( Iop_Or64,
21635 binop( Iop_Or64,
21636 mkexpr( byte[i+3] ),
21637 binop( Iop_Shl64,
21638 mkexpr( byte[i+2] ),
21639 mkU8( 8 ) ) ),
21640 binop( Iop_Or64,
21641 binop( Iop_Shl64,
21642 mkexpr( byte[i+1] ),
21643 mkU8( 16 ) ),
21644 binop( Iop_Shl64,
21645 mkexpr( byte[i] ),
21646 mkU8( 24 ) ) ) ) ) );
21647 ea_off += 4;
21650 } else {
21651 for ( i = 0; i < 16; i = i + 4) {
21652 irx_addr =
21653 binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
21654 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
21656 store( irx_addr,
21657 unop( Iop_64to32,
21658 binop( Iop_Or64,
21659 binop( Iop_Or64,
21660 mkexpr( byte[i] ),
21661 binop( Iop_Shl64,
21662 mkexpr( byte[i+1] ),
21663 mkU8( 8 ) ) ),
21664 binop( Iop_Or64,
21665 binop( Iop_Shl64,
21666 mkexpr( byte[i+2] ),
21667 mkU8( 16 ) ),
21668 binop( Iop_Shl64,
21669 mkexpr( byte[i+3] ),
21670 mkU8( 24 ) ) ) ) ) );
21672 ea_off += 4;
21675 break;
21678 default:
21679 vex_printf( "dis_vx_store(ppc)(opc2)\n" );
21680 return False;
21682 return True;
21685 static Bool
21686 dis_vx_Scalar_Round_to_quad_integer( UInt theInstr, const VexAbiInfo* vbi )
21688 /* The ISA 3.0 instructions supported in this function require
21689 * the underlying hardware platform that supports the ISA3.0
21690 * instruction set.
21692 /* XX1-Form */
21693 UChar opc1 = ifieldOPC( theInstr );
21694 UInt opc2 = IFIELD( theInstr, 1, 8 );
21695 UChar vT_addr = ifieldRegDS( theInstr );
21696 UChar vB_addr = ifieldRegB( theInstr );
21697 IRTemp vB = newTemp( Ity_F128 );
21698 IRTemp vT = newTemp( Ity_F128 );
21699 UChar EX = IFIELD( theInstr, 0, 1 );
21701 assign( vB, getF128Reg( vB_addr ) );
21702 if (opc1 != 0x3F) {
21703 vex_printf( "dis_vx_Scalar_Round_to_quad_integer(ppc)(instr)\n" );
21704 return False;
21706 switch (opc2) {
21707 case 0x005: // VSX Scalar Round to Quad-Precision Integer [with Inexact]
21709 UChar R = IFIELD( theInstr, 16, 1 );
21710 UChar RMC = IFIELD( theInstr, 9, 2 );
21712 /* Store the rm specification bits. Will extract them later when
21713 * the isntruction is issued.
21715 IRExpr* rm = mkU32( R << 3 | RMC << 1 | EX);
21717 if ( EX == 0 ) { // xsrqpi
21718 DIP("xsrqpi %d,v%d,v%d,%d\n", R, vT_addr, vB_addr, RMC);
21719 assign( vT, binop( Iop_F128toI128S, rm, mkexpr( vB ) ) );
21721 } else { // xsrqpix
21722 DIP("xsrqpix %d,v%d,v%d,%d\n", R, vT_addr, vB_addr, RMC);
21723 assign( vT, binop( Iop_F128toI128S, rm, mkexpr( vB ) ) );
21725 generate_store_FPRF( Ity_F128, vT, vbi );
21726 } /* case 0x005 */
21727 break;
21728 case 0x025: // xsrqpxp VSX Scalar Round Quad-Precision to
21729 // Double-Extended Precision
21731 UChar R = IFIELD( theInstr, 16, 1 );
21732 UChar RMC = IFIELD( theInstr, 9, 2 );
21734 /* Store the rm specification bits. Will extract them later when
21735 * the isntruction is issued.
21737 IRExpr* rm = mkU32( R << 3 | RMC << 1 );
21739 DIP("xsrqpxp %d,v%d,v%d,%d\n", R, vT_addr, vB_addr, RMC);
21740 assign( vT, binop( Iop_RndF128, rm, mkexpr( vB ) ) );
21741 generate_store_FPRF( Ity_F128, vT, vbi );
21742 } /* case 0x025 */
21743 break;
21744 default:
21745 vex_printf( "dis_vx_Scalar_Round_to_quad_integer(ppc)(opc2)\n" );
21746 return False;
21747 } /* switch opc2 */
21748 putF128Reg( vT_addr, mkexpr( vT ) );
21749 return True;
21752 static Bool
21753 dis_vx_Floating_Point_Arithmetic_quad_precision( UInt theInstr,
21754 const VexAbiInfo* vbi )
21756 /* The ISA 3.0 instructions supported in this function require
21757 * the underlying hardware platform that supports the ISA 3.0
21758 * instruction set.
21760 /* XX1-Form */
21761 UChar opc1 = ifieldOPC( theInstr );
21762 UInt opc2 = ifieldOPClo10( theInstr );
21763 UChar vT_addr = ifieldRegDS( theInstr );
21764 UChar vA_addr = ifieldRegA( theInstr );
21765 UChar vB_addr = ifieldRegB( theInstr );
21766 IRTemp vA = newTemp( Ity_F128 );
21767 IRTemp vB = newTemp( Ity_F128 );
21768 IRTemp vT = newTemp( Ity_F128 );
21769 IRExpr* rm = get_IR_roundingmode();
21770 UChar R0 = IFIELD( theInstr, 0, 1 );
21772 assign( vB, getF128Reg( vB_addr ) );
21774 if ( opc1 != 0x3F ) {
21775 vex_printf( "Erorr, dis_vx_Floating_Point_Arithmetic_quad_precision(ppc)(instr)\n" );
21776 return False;
21778 switch ( opc2 ) {
21779 case 0x004: // xsaddqp (VSX Scalar Add Quad-Precision[using round to Odd])
21781 assign( vA, getF128Reg( vA_addr ) );
21783 if ( R0 == 0 ) {
21784 /* rounding mode specified by RN. Issue inst with R0 = 0 */
21785 DIP("xsaddqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21786 assign( vT, triop( Iop_AddF128, rm, mkexpr( vA ), mkexpr( vB ) ) );
21788 } else {
21789 /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
21790 DIP("xsaddqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21791 assign( vT, triop( Iop_AddF128, set_round_to_Oddmode(),
21792 mkexpr( vA ), mkexpr( vB ) ) );
21794 generate_store_FPRF( Ity_F128, vT, vbi );
21795 break;
21797 case 0x024: // xsmulqp (VSX Scalar Multiply Quad-Precision[using round to Odd])
21799 assign( vA, getF128Reg( vA_addr ) );
21801 if ( R0 == 0 ) {
21802 /* rounding mode specified by RN. Issue inst with R0 = 0 */
21803 DIP("xsmulqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21804 assign( vT, triop( Iop_MulF128, rm, mkexpr( vA ), mkexpr( vB ) ) );
21806 } else {
21807 /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
21808 DIP("xsmulqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21809 assign( vT, triop( Iop_MulF128, set_round_to_Oddmode(), mkexpr( vA ),
21810 mkexpr( vB ) ) );
21812 generate_store_FPRF( Ity_F128, vT, vbi );
21813 break;
21815 case 0x184: // xsmaddqp (VSX Scalar Multiply add Quad-Precision[using round to Odd])
21817 /* instruction computes (vA * vB) + vC */
21818 IRTemp vC = newTemp( Ity_F128 );
21820 assign( vA, getF128Reg( vA_addr ) );
21821 assign( vC, getF128Reg( vT_addr ) );
21823 if ( R0 == 0 ) {
21824 /* rounding mode specified by RN. Issue inst with R0 = 0 */
21825 DIP("xsmaddqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21826 assign( vT,
21827 qop( Iop_MAddF128, rm, mkexpr( vA ),
21828 mkexpr( vC ), mkexpr( vB ) ) );
21830 } else {
21831 /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
21832 DIP("xsmaddqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21833 assign( vT,
21834 qop( Iop_MAddF128, set_round_to_Oddmode(), mkexpr( vA ),
21835 mkexpr( vC ), mkexpr( vB ) ) );
21837 generate_store_FPRF( Ity_F128, vT, vbi );
21838 break;
21840 case 0x1A4: // xsmsubqp (VSX Scalar Multiply Subtract Quad-Precision[using round to Odd])
21842 IRTemp vC = newTemp( Ity_F128 );
21844 assign( vA, getF128Reg( vA_addr ) );
21845 assign( vC, getF128Reg( vT_addr ) );
21847 if ( R0 == 0 ) {
21848 /* rounding mode specified by RN. Issue inst with R0 = 0 */
21849 DIP("xsmsubqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21850 assign( vT,
21851 qop( Iop_MSubF128, rm, mkexpr( vA ),
21852 mkexpr( vC ), mkexpr( vB ) ) );
21854 } else {
21855 /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
21856 DIP("xsmsubqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21857 assign( vT,
21858 qop( Iop_MSubF128, set_round_to_Oddmode(),
21859 mkexpr( vA ), mkexpr( vC ), mkexpr( vB ) ) );
21861 generate_store_FPRF( Ity_F128, vT, vbi );
21862 break;
21864 case 0x1C4: // xsnmaddqp (VSX Scalar Negative Multiply Add Quad-Precision[using round to Odd])
21866 IRTemp vC = newTemp( Ity_F128 );
21868 assign( vA, getF128Reg( vA_addr ) );
21869 assign( vC, getF128Reg( vT_addr ) );
21871 if ( R0 == 0 ) {
21872 /* rounding mode specified by RN. Issue inst with R0 = 0 */
21873 DIP("xsnmaddqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21874 assign( vT,
21875 qop( Iop_NegMAddF128, rm, mkexpr( vA ),
21876 mkexpr( vC ), mkexpr( vB ) ) );
21878 } else {
21879 /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
21880 DIP("xsnmaddqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21881 assign( vT,
21882 qop( Iop_NegMAddF128, set_round_to_Oddmode(),
21883 mkexpr( vA ), mkexpr( vC ), mkexpr( vB ) ) );
21885 generate_store_FPRF( Ity_F128, vT, vbi );
21886 break;
21888 case 0x1E4: // xsmsubqp (VSX Scalar Negatve Multiply Subtract Quad-Precision[using round to Odd])
21890 IRTemp vC = newTemp( Ity_F128 );
21892 assign( vA, getF128Reg( vA_addr ) );
21893 assign( vC, getF128Reg( vT_addr ) );
21895 if ( R0 == 0 ) {
21896 /* rounding mode specified by RN. Issue inst with R0 = 0 */
21897 DIP("xsnmsubqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21898 assign( vT,
21899 qop( Iop_NegMSubF128, rm, mkexpr( vA ),
21900 mkexpr( vC ), mkexpr( vB ) ) );
21902 } else {
21903 /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
21904 DIP("xsnmsubqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21905 assign( vT,
21906 qop( Iop_NegMSubF128, set_round_to_Oddmode(),
21907 mkexpr( vA ), mkexpr( vC ), mkexpr( vB ) ) );
21909 generate_store_FPRF( Ity_F128, vT, vbi );
21910 break;
21912 case 0x204: // xssubqp (VSX Scalar Subtract Quad-Precision[using round to Odd])
21914 assign( vA, getF128Reg( vA_addr ) );
21915 if ( R0 == 0 ) {
21916 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
21917 DIP("xssubqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21918 assign( vT, triop( Iop_SubF128, rm, mkexpr( vA ), mkexpr( vB ) ) );
21920 } else {
21921 /* use rounding mode specified by Round to odd. Issue inst with R0 = 1 */
21922 DIP("xssubqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21923 assign( vT, triop( Iop_SubF128, set_round_to_Oddmode(), mkexpr( vA ),
21924 mkexpr( vB ) ) );
21926 generate_store_FPRF( Ity_F128, vT, vbi );
21927 break;
21929 case 0x224: // xsdivqp (VSX Scalar Divide Quad-Precision[using round to Odd])
21931 assign( vA, getF128Reg( vA_addr ) );
21932 if ( R0 == 0 ) {
21933 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
21934 DIP("xsdivqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21935 assign( vT, triop( Iop_DivF128, rm, mkexpr( vA ), mkexpr( vB ) ) );
21937 } else {
21938 /* use rounding mode specified by Round to odd. Issue inst with R0 = 1 */
21939 DIP("xsdivqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
21940 assign( vT, triop( Iop_DivF128, set_round_to_Oddmode(), mkexpr( vA ),
21941 mkexpr( vB ) ) );
21943 generate_store_FPRF( Ity_F128, vT, vbi );
21944 break;
21946 case 0x324: // xssqrtqp (VSX Scalar Square root Quad-Precision[using round to Odd])
21948 UInt inst_select = IFIELD( theInstr, 16, 5 );
21950 switch (inst_select) {
21951 case 27:
21953 if ( R0 == 0 ) { // xssqrtqp
21954 /* rounding mode specified by RN. Issue inst with R0 = 0 */
21955 DIP("xssqrtqp v%d,v%d\n", vT_addr, vB_addr);
21956 assign( vT, binop( Iop_SqrtF128, rm, mkexpr( vB ) ) );
21958 } else { // xssqrtqpo
21959 /* rounding mode is Round to odd. Issue inst with R0 = 1 */
21960 DIP("xssqrtqpo v%d,v%d\n", vT_addr, vB_addr);
21961 assign( vT, binop( Iop_SqrtF128, set_round_to_Oddmode(),
21962 mkexpr( vB ) ) );
21964 generate_store_FPRF( Ity_F128, vT, vbi );
21965 break;
21966 } /* end case 27 */
21967 default:
21968 vex_printf("dis_vx_Floating_Point_Arithmetic_quad_precision(0x324 unknown inst_select)\n");
21969 return False;
21970 } /* end switch inst_select */
21971 break;
21972 } /* end case 0x324 */
21974 case 0x344:
21976 UInt inst_select = IFIELD( theInstr, 16, 5);
21978 switch (inst_select) {
21979 case 1: // xscvqpuwz VSX Scalar Truncate & Convert Quad-Precision
21980 // format to Unsigned Word format
21982 DIP("xscvqpuwz v%d,v%d\n", vT_addr, vB_addr);
21983 assign( vT, unop( Iop_TruncF128toI32U, mkexpr( vB ) ) );
21984 break;
21986 case 2: // xscvudqp VSX Scalar Convert from Unsigned Doubleword
21987 // format to Quad-Precision format
21989 IRTemp tmp = newTemp( Ity_I64 );
21991 DIP("xscvudqp v%d,v%d\n", vT_addr, vB_addr);
21992 assign( tmp, unop( Iop_ReinterpF64asI64,
21993 unop( Iop_F128HItoF64, mkexpr( vB ) ) ) );
21994 assign( vT, unop( Iop_I64UtoF128, mkexpr( tmp ) ) );
21995 generate_store_FPRF( Ity_F128, vT, vbi );
21996 break;
21998 case 9: // xsvqpswz VSX Scalar Truncate & Convert Quad-Precision
21999 // format to Signed Word format
22001 DIP("xscvqpswz v%d,v%d\n", vT_addr, vB_addr);
22002 assign( vT, unop( Iop_TruncF128toI32S, mkexpr( vB ) ) );
22003 break;
22005 case 10: // xscvsdqp VSX Scalar from Signed Doubleword format
22006 // Quad-Precision format
22008 IRTemp tmp = newTemp( Ity_I64 );
22010 DIP("xscvsdqp v%d,v%d\n", vT_addr, vB_addr);
22012 assign( tmp, unop( Iop_ReinterpF64asI64,
22013 unop( Iop_F128HItoF64, mkexpr( vB ) ) ) );
22014 assign( vT, unop( Iop_I64StoF128, mkexpr( tmp ) ) );
22015 generate_store_FPRF( Ity_F128, vT, vbi );
22016 break;
22018 case 17: // xsvqpudz VSX Scalar Truncate & Convert Quad-Precision
22019 // format to Unigned Doubleword format
22021 DIP("xscvqpudz v%d,v%d\n", vT_addr, vB_addr);
22022 assign( vT, unop( Iop_TruncF128toI64U, mkexpr( vB ) ) );
22023 break;
22025 case 20: // xscvqpdp Scalar round & Conver Quad-Precision
22026 // format to Double-Precision format [using round to Odd]
22028 IRTemp ftmp = newTemp( Ity_F64 );
22029 IRTemp tmp = newTemp( Ity_I64 );
22031 /* This instruction takes a 128-bit floating point value and
22032 * converts it to a 64-bit floating point value. The 64-bit
22033 * result is stored in the upper 64-bit of the 128-bit result
22034 * register. The lower 64-bit are undefined.
22036 if (R0 == 0) { // xscvqpdp
22037 /* rounding mode specified by RN. Issue inst with R0 = 0 */
22038 DIP("xscvqpdp v%d,v%d\n", vT_addr, vB_addr);
22040 assign( ftmp, binop( Iop_F128toF64, rm, mkexpr( vB ) ) );
22042 } else { // xscvqpdpo
22043 /* rounding mode is Round to odd. Issue inst with R0 = 1 */
22044 DIP("xscvqpdpo v%d,v%d\n", vT_addr, vB_addr);
22045 assign( ftmp,
22046 binop( Iop_F128toF64,
22047 set_round_to_Oddmode(), mkexpr( vB ) ) );
22050 /* store 64-bit float in upper 64-bits of 128-bit register,
22051 * lower 64-bits are zero.
22053 if (host_endness == VexEndnessLE)
22054 assign( vT,
22055 binop( Iop_F64HLtoF128,
22056 mkexpr( ftmp ),
22057 unop( Iop_ReinterpI64asF64, mkU64( 0 ) ) ) );
22058 else
22059 assign( vT,
22060 binop( Iop_F64HLtoF128,
22061 unop( Iop_ReinterpI64asF64, mkU64( 0 ) ),
22062 mkexpr( ftmp ) ) );
22064 assign( tmp, unop( Iop_ReinterpF64asI64,
22065 unop( Iop_F128HItoF64, mkexpr( vT ) ) ) );
22067 generate_store_FPRF( Ity_I64, tmp, vbi );
22068 break;
22070 case 22: // xscvdpqp VSX Scalar Convert from Double-Precision
22071 // format to Quad-Precision format
22073 DIP("xscvdpqp v%d,v%d\n", vT_addr, vB_addr);
22074 /* The 64-bit value is in the upper 64 bit of the src */
22075 assign( vT, unop( Iop_F64toF128,
22076 unop( Iop_F128HItoF64, mkexpr( vB ) ) ) );
22078 generate_store_FPRF( Ity_F128, vT, vbi );
22079 break;
22081 case 25: // xsvqpsdz VSX Scalar Truncate & Convert Quad-Precision
22082 // format to Signed Doubleword format
22084 DIP("xscvqpsdz v%d,v%d\n", vT_addr, vB_addr);
22085 assign( vT, unop( Iop_TruncF128toI64S, mkexpr( vB ) ) );
22086 break;
22088 default:
22089 vex_printf( "dis_vx_Floating_Point_Arithmetic_quad_precision invalid inst_select (ppc)(opc2)\n" );
22090 return False;
22091 } /* switch inst_select */
22092 } /* end case 0x344 */
22093 break;
22094 default: /* switch opc2 */
22095 vex_printf( "dis_vx_Floating_Point_Arithmetic_quad_precision(ppc)(opc2)\n" );
22096 return False;
22098 putF128Reg( vT_addr, mkexpr( vT ) );
22099 return True;
22103 /* VSX Scalar Quad-Precision instructions */
22104 static Bool
22105 dis_vx_scalar_quad_precision ( UInt theInstr )
22107 /* This function emulates the 128-bit floating point instructions
22108 * using existing 128-bit vector instructions (Iops). The 128-bit
22109 * floating point instructions use the same 128-bit vector register
22110 * set.
22112 /* XX1-Form */
22113 UChar opc1 = ifieldOPC( theInstr );
22114 UInt opc2 = ifieldOPClo10( theInstr );
22115 UChar vT_addr = ifieldRegDS( theInstr ) + 32;
22116 UChar vA_addr = ifieldRegA( theInstr ) + 32;
22117 UChar vB_addr = ifieldRegB( theInstr ) + 32;
22118 IRTemp vA = newTemp( Ity_V128 );
22119 IRTemp vB = newTemp( Ity_V128 );
22120 IRTemp vT = newTemp( Ity_V128 );
22122 assign( vB, getVSReg( vB_addr ) );
22124 if (opc1 != 0x3F) {
22125 vex_printf( "dis_vx_scalar_quad_precision(ppc)(instr)\n" );
22126 return False;
22129 switch (opc2) {
22131 case 0x064: // xscpsgnqp (VSX Scalar Copy Sign Quad-Precision)
22133 IRTemp sign_vA = newTemp( Ity_I64 );
22134 IRTemp vB_hi = newTemp( Ity_I64 );
22136 DIP("xscpsgnqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22138 assign( vA, getVSReg(vA_addr) );
22140 assign( sign_vA, binop( Iop_And64,
22141 unop( Iop_V128HIto64,
22142 mkexpr( vA ) ),
22143 mkU64( 0x8000000000000000ULL ) ) );
22144 assign( vB_hi, binop( Iop_Or64,
22145 binop( Iop_And64,
22146 unop( Iop_V128HIto64,
22147 mkexpr( vB ) ),
22148 mkU64( 0x7FFFFFFFFFFFFFFFULL ) ),
22149 mkexpr( sign_vA ) ) );
22150 assign( vT, binop( Iop_64HLtoV128,
22151 mkexpr( vB_hi ),
22152 unop( Iop_V128to64, mkexpr( vB ) ) ) );
22153 break;
22156 case 0x084: // xscmpoqp (VSX Scalar Compare Ordered Quad-Precision)
22157 case 0x284: // xscmpuqp (VSX Scalar Compare Unrdered Quad-Precision)
22159 /* Note, only differece between xscmoqp and xscmpuqp is the
22160 exception flag settings which are not supported anyway. */
22161 IRExpr *bit4, *bit5, *bit6, *bit7;
22162 IRExpr *bit_zero, *bit_inf, *same_sign;
22163 UInt BF = IFIELD( theInstr, 23, 3 );
22164 IRTemp eq_lt_gt = newTemp( Ity_I32 );
22165 IRTemp CC = newTemp( Ity_I32 );
22167 if (opc2 == 0x084) {
22168 DIP("xscmpoqp %d,v%d,v%d\n", BF, vA_addr, vB_addr);
22169 } else {
22170 DIP("xscmpuqp %d,v%d,v%d\n", BF, vA_addr, vB_addr);
22173 assign( vA, getVSReg(vA_addr));
22175 /* A and B have the same sign */
22176 same_sign = binop( Iop_CmpEQ64,
22177 binop( Iop_Shr64,
22178 unop( Iop_V128HIto64,
22179 mkexpr( vA ) ),
22180 mkU8( 63 ) ),
22181 binop( Iop_Shr64,
22182 unop( Iop_V128HIto64,
22183 mkexpr( vB ) ),
22184 mkU8( 63 ) ) );
22186 /* A < B */
22187 bit4 = Quad_precision_gt( vB, vA );
22189 /* A > B */
22190 bit5 = Quad_precision_gt( vA, vB );
22192 /* A equal B */
22193 bit6 = mkAND1( binop( Iop_CmpEQ64,
22194 unop( Iop_V128HIto64,
22195 mkexpr( vA ) ),
22196 unop( Iop_V128HIto64,
22197 mkexpr( vB ) ) ),
22198 binop( Iop_CmpEQ64,
22199 unop( Iop_V128to64,
22200 mkexpr( vA ) ),
22201 unop( Iop_V128to64,
22202 mkexpr( vB ) ) ) );
22204 /* test both zero don't care about sign */
22205 bit_zero = mkAND1( is_Zero( Ity_V128, vA ), is_Zero( Ity_V128, vB ) );
22207 /* test both for infinity, don't care about sign */
22208 bit_inf = mkAND1(
22209 mkAND1( is_Inf( Ity_V128, vA ), is_Inf( Ity_V128, vB ) ),
22210 binop( Iop_CmpEQ64,
22211 binop( Iop_And64,
22212 unop( Iop_V128to64,
22213 mkexpr( vA ) ),
22214 mkU64( 0x80000000) ),
22215 binop( Iop_And64,
22216 unop( Iop_V128to64,
22217 mkexpr( vB ) ),
22218 mkU64( 0x80000000) ) ) );
22220 /* exp A or exp B is NaN */
22221 bit7 = mkOR1( is_NaN( Ity_V128, vA ),
22222 is_NaN( Ity_V128, vB ) );
22224 assign( eq_lt_gt,
22225 binop( Iop_Or32,
22226 binop( Iop_Or32,
22227 binop( Iop_Shl32,
22228 unop( Iop_1Uto32, bit4 ),
22229 mkU8( 3 ) ),
22230 binop( Iop_Shl32,
22231 unop( Iop_1Uto32, bit5 ),
22232 mkU8( 2 ) ) ),
22233 binop( Iop_Or32,
22234 binop( Iop_Shl32,
22235 unop( Iop_1Uto32, bit6 ),
22236 mkU8( 1 ) ),
22237 binop( Iop_Or32,
22238 binop( Iop_Shl32,
22239 unop( Iop_1Uto32,
22240 bit_zero ),
22241 mkU8( 1 ) ),
22242 binop( Iop_Shl32,
22243 unop( Iop_1Uto32,
22244 mkAND1( bit_inf, same_sign ) ),
22245 mkU8( 1 ) ) ) ) ) );
22247 assign(CC, binop( Iop_Or32,
22248 binop( Iop_And32,
22249 unop( Iop_Not32,
22250 unop( Iop_1Sto32, bit7 ) ),
22251 mkexpr( eq_lt_gt ) ),
22252 unop( Iop_1Uto32, bit7 ) ) );
22254 /* put result of the comparison into CC and FPCC */
22255 putGST_field( PPC_GST_CR, mkexpr( CC ), BF );
22256 putFPCC( mkexpr( CC ) );
22257 return True;
22259 break;
22261 case 0xA4: // xscmpexpqp (VSX Scalar Compare Exponents Double-Precision)
22263 IRExpr *bit4, *bit5, *bit6, *bit7;
22264 UInt BF = IFIELD( theInstr, 23, 3 );
22266 IRTemp eq_lt_gt = newTemp( Ity_I32 );
22267 IRTemp CC = newTemp( Ity_I32 );
22269 DIP("xscmpexpqp %d,v%d,v%d\n", BF, vA_addr, vB_addr);
22271 assign( vA, getVSReg(vA_addr));
22273 /* A exp < B exp */
22274 bit4 = binop( Iop_CmpLT64U,
22275 binop( Iop_And64,
22276 unop( Iop_V128HIto64,
22277 mkexpr( vA ) ),
22278 mkU64( 0x7FFF000000000000 ) ),
22279 binop( Iop_And64,
22280 unop( Iop_V128HIto64,
22281 mkexpr( vB ) ),
22282 mkU64( 0x7FFF000000000000 ) ) );
22283 /* exp > B exp */
22284 bit5 = binop( Iop_CmpLT64U,
22285 binop( Iop_And64,
22286 unop( Iop_V128HIto64,
22287 mkexpr( vB ) ),
22288 mkU64( 0x7FFF000000000000 ) ),
22289 binop( Iop_And64,
22290 unop( Iop_V128HIto64,
22291 mkexpr( vA ) ),
22292 mkU64( 0x7FFF000000000000 ) ) );
22293 /* test equal */
22294 bit6 = binop( Iop_CmpEQ64,
22295 binop( Iop_And64,
22296 unop( Iop_V128HIto64,
22297 mkexpr( vA ) ),
22298 mkU64( 0x7FFF000000000000 ) ),
22299 binop( Iop_And64,
22300 unop( Iop_V128HIto64,
22301 mkexpr( vB ) ),
22302 mkU64( 0x7FFF000000000000 ) ) );
22304 /* exp A or exp B is NaN */
22305 bit7 = mkOR1( is_NaN( Ity_V128, vA ),
22306 is_NaN( Ity_V128, vB ) );
22308 /* NaN over rules the other comparisons */
22309 assign( eq_lt_gt, binop( Iop_Or32,
22310 binop( Iop_Shl32,
22311 unop( Iop_1Uto32, bit4 ),
22312 mkU8( 3) ),
22313 binop( Iop_Or32,
22314 binop( Iop_Shl32,
22315 unop( Iop_1Uto32, bit5 ),
22316 mkU8( 2) ),
22317 binop( Iop_Shl32,
22318 unop( Iop_1Uto32, bit6 ),
22319 mkU8( 1 ) ) ) ) );
22320 assign(CC, binop( Iop_Or32,
22321 binop( Iop_And32,
22322 unop( Iop_Not32,
22323 unop( Iop_1Sto32, bit7 ) ),
22324 mkexpr( eq_lt_gt ) ),
22325 unop( Iop_1Uto32, bit7 ) ) );
22327 /* put result of the comparison into CC and FPCC */
22328 putGST_field( PPC_GST_CR, mkexpr( CC ), BF );
22329 putFPCC( mkexpr( CC ) );
22330 return True;
22332 break;
22334 case 0x2C4: // xststdcqp (VSX Scalar Quad-Precision Test Data Class)
22336 UInt BF = IFIELD( theInstr, 23, 3 );
22337 UInt DCMX_mask = IFIELD( theInstr, 16, 7 );
22338 IRTemp CC = newTemp( Ity_I64 );
22339 IRTemp NaN = newTemp( Ity_I64 );
22340 IRTemp inf = newTemp( Ity_I64 );
22341 IRTemp pos = newTemp( Ity_I64 );
22342 IRTemp DCM = newTemp( Ity_I64 );
22343 IRTemp zero = newTemp( Ity_I64 );
22344 IRTemp dnorm = newTemp( Ity_I64 );
22346 DIP("xststdcqp %d,v%d,%d\n", BF, vB_addr, DCMX_mask);
22348 assign( zero, unop( Iop_1Uto64, is_Zero( Ity_V128, vB ) ) );
22349 assign( pos, unop( Iop_1Uto64,
22350 binop( Iop_CmpEQ64,
22351 binop( Iop_Shr64,
22352 unop( Iop_V128HIto64,
22353 mkexpr( vB ) ),
22354 mkU8( 63 ) ),
22355 mkU64( 0 ) ) ) );
22357 assign( NaN, unop( Iop_1Uto64, is_NaN( Ity_V128, vB ) ) );
22358 assign( inf, unop( Iop_1Uto64, is_Inf( Ity_V128, vB ) ) );
22360 assign( dnorm, unop( Iop_1Uto64, is_Denorm( Ity_V128, vB ) ) );
22361 assign( DCM, create_DCM( Ity_I64, NaN, inf, zero, dnorm, pos ) );
22362 assign( CC, binop( Iop_Or64,
22363 binop( Iop_And64, /* vB sign bit */
22364 binop( Iop_Shr64,
22365 unop( Iop_V128HIto64, mkexpr( vB ) ),
22366 mkU8( 60 ) ),
22367 mkU64( 0x8 ) ),
22368 binop( Iop_Shl64,
22369 unop( Iop_1Uto64,
22370 binop( Iop_CmpNE64,
22371 binop( Iop_And64,
22372 mkexpr( DCM ),
22373 mkU64( DCMX_mask ) ),
22374 mkU64( 0 ) ) ),
22375 mkU8( 1 ) ) ) );
22377 putGST_field( PPC_GST_CR, unop(Iop_64to32, mkexpr( CC ) ), BF );
22378 putFPCC( unop(Iop_64to32, mkexpr( CC ) ) );
22379 return True;
22381 break;
22383 case 0x324: // xsabsqp (VSX Scalar Absolute Quad-Precision)
22384 // xsxexpqp (VSX Scalaar Extract Exponent Quad-Precision)
22385 // xsnabsqp (VSX Scalar Negative Absolute Quad-Precision)
22386 // xsnegqp (VSX Scalar Negate Quad-Precision)
22387 // xsxsigqp (VSX Scalar Extract Significand Quad-Precision)
22389 UInt inst_select = IFIELD( theInstr, 16, 5);
22391 switch (inst_select) {
22392 case 0:
22393 DIP("xsabsqp v%d,v%d\n", vT_addr, vB_addr);
22394 assign( vT, binop( Iop_AndV128, mkexpr( vB ),
22395 binop( Iop_64HLtoV128,
22396 mkU64( 0x7FFFFFFFFFFFFFFF ),
22397 mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) );
22398 break;
22400 case 2:
22401 DIP("xsxexpqp v%d,v%d\n", vT_addr, vB_addr);
22402 assign( vT, binop( Iop_ShrV128,
22403 binop( Iop_AndV128, mkexpr( vB ),
22404 binop( Iop_64HLtoV128,
22405 mkU64( 0x7FFF000000000000 ),
22406 mkU64( 0x0000000000000000 ) ) ),
22407 mkU8( 48 ) ) );
22408 break;
22410 case 8:
22411 DIP("xsnabsqp v%d,v%d\n", vT_addr, vB_addr);
22412 assign( vT, binop( Iop_OrV128, mkexpr( vB ),
22413 binop( Iop_64HLtoV128,
22414 mkU64( 0x8000000000000000 ),
22415 mkU64( 0x0000000000000000 ) ) ) );
22416 break;
22418 case 16:
22419 DIP("xsnegqp v%d,v%d\n", vT_addr, vB_addr);
22420 assign( vT, binop( Iop_XorV128, mkexpr( vB ),
22421 binop( Iop_64HLtoV128,
22422 mkU64( 0x8000000000000000 ),
22423 mkU64( 0x0000000000000000 ) ) ) );
22424 break;
22426 case 18:
22428 IRTemp expZero = newTemp( Ity_I64 );
22429 IRTemp expInfinity = newTemp( Ity_I64 );
22431 DIP("xsxsigqp v%d,v%d\n", vT_addr, vB_addr);
22433 assign( expZero, unop( Iop_1Uto64,
22434 binop( Iop_CmpNE64,
22435 binop( Iop_And64,
22436 unop( Iop_V128HIto64,
22437 mkexpr( vB ) ),
22438 mkU64( 0x7FFF000000000000 ) ),
22439 mkU64( 0x0 ) ) ) );
22441 assign( expInfinity,
22442 unop( Iop_1Uto64,
22443 binop( Iop_CmpNE64,
22444 binop( Iop_And64,
22445 unop( Iop_V128HIto64,
22446 mkexpr( vB ) ),
22447 mkU64( 0x7FFF000000000000 ) ),
22448 mkU64( 0x7FFF000000000000 ) ) ) );
22450 /* Clear upper 16 bits to 0x0000. If the exp was zero or infinity
22451 * set bit 48 (lsb = 0) to 0, otherwise set bit 48 to 1.
22453 assign( vT,
22454 binop( Iop_OrV128,
22455 binop( Iop_ShrV128,
22456 binop( Iop_ShlV128,
22457 mkexpr( vB ),
22458 mkU8( 16 ) ),
22459 mkU8( 16 ) ),
22460 binop( Iop_64HLtoV128,
22461 binop( Iop_Shl64,
22462 binop( Iop_And64,
22463 mkexpr( expZero ),
22464 mkexpr( expInfinity ) ),
22465 mkU8( 48 ) ),
22466 mkU64( 0 ) ) ) );
22468 break;
22470 default:
22471 vex_printf( "dis_vx_scalar_quad_precision invalid inst_select (ppc)(opc2)\n" );
22472 return False;
22475 break;
22476 case 0x364: // xsiexpqp (VST Scalar Insert Exponent Quad-Precision)
22478 IRTemp exp = newTemp( Ity_I64 );
22480 DIP("xsiexpqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
22482 assign( vA, getVSReg( vA_addr ) );
22483 assign( exp, binop( Iop_And64,
22484 unop( Iop_V128HIto64,
22485 mkexpr( vB ) ),
22486 mkU64( 0x7FFFULL ) ) );
22487 assign( vT, binop( Iop_64HLtoV128,
22488 binop( Iop_Or64,
22489 binop( Iop_And64,
22490 unop( Iop_V128HIto64,
22491 mkexpr( vA ) ),
22492 mkU64( 0x8000FFFFFFFFFFFFULL ) ),
22493 binop( Iop_Shl64,
22494 mkexpr( exp ),
22495 mkU8( 48 ) ) ),
22496 unop( Iop_V128to64,
22497 mkexpr( vA ) ) ) );
22499 break;
22501 default:
22502 vex_printf( "dis_vx_scalar_quad_precision(ppc)(opc2)\n" );
22504 return False;
22507 putVSReg( vT_addr, mkexpr( vT ) );
22508 return True;
22512 * VSX permute and other miscealleous instructions
22514 static Bool
22515 dis_vx_permute_misc( UInt theInstr, UInt opc2 )
22517 /* XX3-Form */
22518 UChar opc1 = ifieldOPC( theInstr );
22519 UChar XT = ifieldRegXT ( theInstr );
22520 UChar XA = ifieldRegXA ( theInstr );
22521 UChar XB = ifieldRegXB ( theInstr );
22522 IRTemp vT = newTemp( Ity_V128 );
22523 IRTemp vA = newTemp( Ity_V128 );
22524 IRTemp vB = newTemp( Ity_V128 );
22526 if (opc1 != 0x3C) {
22527 vex_printf( "dis_vx_permute_misc(ppc)(instr)\n" );
22528 return False;
22531 assign( vA, getVSReg( XA ) );
22532 assign( vB, getVSReg( XB ) );
22534 switch (opc2) {
22535 case 0x8: // xxsldwi (VSX Shift Left Double by Word Immediate)
22537 UChar SHW = ifieldSHW ( theInstr );
22538 IRTemp result = newTemp(Ity_V128);
22539 if ( SHW != 0 ) {
22540 IRTemp hi = newTemp(Ity_V128);
22541 IRTemp lo = newTemp(Ity_V128);
22542 assign( hi, binop(Iop_ShlV128, mkexpr(vA), mkU8(SHW*32)) );
22543 assign( lo, binop(Iop_ShrV128, mkexpr(vB), mkU8(128-SHW*32)) );
22544 assign ( result, binop(Iop_OrV128, mkexpr(hi), mkexpr(lo)) );
22545 } else
22546 assign ( result, mkexpr(vA) );
22547 DIP("xxsldwi v%d,v%d,v%d,%d\n", XT, XA, XB, SHW);
22548 putVSReg( XT, mkexpr(result) );
22549 break;
22551 case 0x28: // xpermdi (VSX Permute Doubleword Immediate)
22553 UChar DM = ifieldDM ( theInstr );
22554 IRTemp hi = newTemp(Ity_I64);
22555 IRTemp lo = newTemp(Ity_I64);
22557 if (DM & 0x2)
22558 assign( hi, unop(Iop_V128to64, mkexpr(vA)) );
22559 else
22560 assign( hi, unop(Iop_V128HIto64, mkexpr(vA)) );
22562 if (DM & 0x1)
22563 assign( lo, unop(Iop_V128to64, mkexpr(vB)) );
22564 else
22565 assign( lo, unop(Iop_V128HIto64, mkexpr(vB)) );
22567 assign( vT, binop(Iop_64HLtoV128, mkexpr(hi), mkexpr(lo)) );
22569 DIP("xxpermdi v%d,v%d,v%d,0x%x\n", XT, XA, XB, DM);
22570 putVSReg( XT, mkexpr( vT ) );
22571 break;
22573 case 0x48: // xxmrghw (VSX Merge High Word)
22574 case 0xc8: // xxmrglw (VSX Merge Low Word)
22576 const HChar type = (opc2 == 0x48) ? 'h' : 'l';
22577 IROp word_op = (opc2 == 0x48) ? Iop_V128HIto64 : Iop_V128to64;
22578 IRTemp a64 = newTemp(Ity_I64);
22579 IRTemp ahi32 = newTemp(Ity_I32);
22580 IRTemp alo32 = newTemp(Ity_I32);
22581 IRTemp b64 = newTemp(Ity_I64);
22582 IRTemp bhi32 = newTemp(Ity_I32);
22583 IRTemp blo32 = newTemp(Ity_I32);
22585 assign( a64, unop(word_op, mkexpr(vA)) );
22586 assign( ahi32, unop(Iop_64HIto32, mkexpr(a64)) );
22587 assign( alo32, unop(Iop_64to32, mkexpr(a64)) );
22589 assign( b64, unop(word_op, mkexpr(vB)) );
22590 assign( bhi32, unop(Iop_64HIto32, mkexpr(b64)) );
22591 assign( blo32, unop(Iop_64to32, mkexpr(b64)) );
22593 assign( vT, binop(Iop_64HLtoV128,
22594 binop(Iop_32HLto64, mkexpr(ahi32), mkexpr(bhi32)),
22595 binop(Iop_32HLto64, mkexpr(alo32), mkexpr(blo32))) );
22597 DIP("xxmrg%cw v%d,v%d,v%d\n", type, XT, XA, XB);
22598 putVSReg( XT, mkexpr( vT ) );
22599 break;
22601 case 0x018: // xxsel (VSX Select)
22603 UChar XC = ifieldRegXC(theInstr);
22604 IRTemp vC = newTemp( Ity_V128 );
22605 assign( vC, getVSReg( XC ) );
22606 DIP("xxsel v%d,v%d,v%d,v%d\n", XT, XA, XB, XC);
22607 /* vD = (vA & ~vC) | (vB & vC) */
22608 putVSReg( XT, binop(Iop_OrV128,
22609 binop(Iop_AndV128, mkexpr(vA), unop(Iop_NotV128, mkexpr(vC))),
22610 binop(Iop_AndV128, mkexpr(vB), mkexpr(vC))) );
22611 break;
22614 case 0x68: // xxperm (VSX Permute )
22615 case 0xE8: // xxpermr (VSX Permute right-index )
22618 /* The xxperm instruction performs the same operation as
22619 the vperm except the xxperm operates on the VSR register
22620 file. while vperm operates on the VR register file.
22621 Lets borrow some code here from vperm. The mapping of
22622 the source registers is also a little different.
22624 IRTemp a_perm = newTemp(Ity_V128);
22625 IRTemp b_perm = newTemp(Ity_V128);
22626 IRTemp mask = newTemp(Ity_V128);
22627 IRTemp perm_val = newTemp(Ity_V128);
22628 IRTemp vB_adj = newTemp( Ity_V128 );
22630 if ( opc2 == 0x68 ) {
22631 DIP("xxperm v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
22633 } else {
22634 /* Same as xperm just the index is 31 - idx */
22635 DIP("xxpermr v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
22638 assign( vT, getVSReg( XT ) );
22640 if ( opc2 == 0x68 ) // xxperm
22641 assign( vB_adj, mkexpr( vB ) );
22643 else // xxpermr
22644 assign( vB_adj,
22645 binop( Iop_Sub16x8,
22646 unop( Iop_Dup8x16, mkU8( 0x1F ) ),
22647 mkexpr( vB ) ) );
22649 /* Limit the Perm8x16 steering values to 0 .. 15 as that is what
22650 IR specifies, and also to hide irrelevant bits from
22651 memcheck.
22653 assign( perm_val,
22654 binop( Iop_AndV128, mkexpr( vB_adj ),
22655 unop( Iop_Dup8x16, mkU8( 0xF ) ) ) );
22656 assign( a_perm,
22657 binop( Iop_Perm8x16, mkexpr( vA ), mkexpr( perm_val ) ) );
22658 assign( b_perm,
22659 binop( Iop_Perm8x16, mkexpr( vT ), mkexpr( perm_val ) ) );
22660 assign( mask, binop( Iop_SarN8x16,
22661 binop( Iop_ShlN8x16, mkexpr( vB_adj ),
22662 mkU8( 3 ) ),
22663 mkU8( 7 ) ) );
22664 // dst = (a & ~mask) | (b & mask)
22665 putVSReg( XT, binop( Iop_OrV128,
22666 binop( Iop_AndV128, mkexpr( a_perm ),
22667 unop( Iop_NotV128, mkexpr( mask ) ) ),
22668 binop( Iop_AndV128, mkexpr( b_perm ),
22669 mkexpr( mask ) ) ) );
22670 break;
22673 case 0x148: // xxspltw (VSX Splat Word)
22675 UChar UIM = ifieldRegA(theInstr) & 3;
22676 UChar sh_uim = (3 - (UIM)) * 32;
22677 DIP("xxspltw v%d,v%d,%d\n", XT, XB, UIM);
22678 putVSReg( XT,
22679 unop( Iop_Dup32x4,
22680 unop( Iop_V128to32,
22681 binop( Iop_ShrV128, mkexpr( vB ), mkU8( sh_uim ) ) ) ) );
22682 break;
22685 default:
22686 vex_printf( "dis_vx_permute_misc(ppc)(opc2)\n" );
22687 return False;
22689 return True;
22693 AltiVec Load Instructions
22695 static Bool dis_av_load ( const VexAbiInfo* vbi, UInt theInstr )
22697 /* X-Form */
22698 UChar opc1 = ifieldOPC(theInstr);
22699 UChar vD_addr = ifieldRegDS(theInstr);
22700 UChar rA_addr = ifieldRegA(theInstr);
22701 UChar rB_addr = ifieldRegB(theInstr);
22702 UInt opc2 = ifieldOPClo10(theInstr);
22703 UChar b0 = ifieldBIT0(theInstr);
22705 IRType ty = mode64 ? Ity_I64 : Ity_I32;
22706 IRTemp EA = newTemp(ty);
22707 IRTemp EA_align16 = newTemp(ty);
22709 if (opc1 != 0x1F || b0 != 0) {
22710 vex_printf("dis_av_load(ppc)(instr)\n");
22711 return False;
22714 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
22715 assign( EA_align16, addr_align( mkexpr(EA), 16 ) );
22717 switch (opc2) {
22719 case 0x006: { // lvsl (Load Vector for Shift Left, AV p123)
22720 IRDirty* d;
22721 UInt vD_off = vectorGuestRegOffset(vD_addr);
22722 IRExpr** args_be = mkIRExprVec_5(
22723 IRExpr_GSPTR(),
22724 mkU32(vD_off),
22725 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
22726 mkU32(0xF)),
22727 mkU32(0)/*left*/,
22728 mkU32(1)/*Big Endian*/);
22729 IRExpr** args_le = mkIRExprVec_5(
22730 IRExpr_GSPTR(),
22731 mkU32(vD_off),
22732 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
22733 mkU32(0xF)),
22734 mkU32(0)/*left*/,
22735 mkU32(0)/*Little Endian*/);
22736 if (!mode64) {
22737 d = unsafeIRDirty_0_N (
22738 0/*regparms*/,
22739 "ppc32g_dirtyhelper_LVS",
22740 fnptr_to_fnentry(vbi, &ppc32g_dirtyhelper_LVS),
22741 args_be );
22742 } else {
22743 if (host_endness == VexEndnessBE)
22744 d = unsafeIRDirty_0_N (
22745 0/*regparms*/,
22746 "ppc64g_dirtyhelper_LVS",
22747 fnptr_to_fnentry(vbi, &ppc64g_dirtyhelper_LVS),
22748 args_be );
22749 else
22750 d = unsafeIRDirty_0_N (
22751 0/*regparms*/,
22752 "ppc64g_dirtyhelper_LVS",
22753 fnptr_to_fnentry( vbi, &ppc64g_dirtyhelper_LVS ),
22754 args_le );
22756 DIP("lvsl v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
22757 /* declare guest state effects */
22758 d->nFxState = 1;
22759 vex_bzero(&d->fxState, sizeof(d->fxState));
22760 d->fxState[0].fx = Ifx_Write;
22761 d->fxState[0].offset = vD_off;
22762 d->fxState[0].size = sizeof(U128);
22764 /* execute the dirty call, side-effecting guest state */
22765 stmt( IRStmt_Dirty(d) );
22766 break;
22768 case 0x026: { // lvsr (Load Vector for Shift Right, AV p125)
22769 IRDirty* d;
22770 UInt vD_off = vectorGuestRegOffset(vD_addr);
22771 IRExpr** args_be = mkIRExprVec_5(
22772 IRExpr_GSPTR(),
22773 mkU32(vD_off),
22774 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
22775 mkU32(0xF)),
22776 mkU32(1)/*right*/,
22777 mkU32(1)/*Big Endian*/);
22778 IRExpr** args_le = mkIRExprVec_5(
22779 IRExpr_GSPTR(),
22780 mkU32(vD_off),
22781 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
22782 mkU32(0xF)),
22783 mkU32(1)/*right*/,
22784 mkU32(0)/*Little Endian*/);
22786 if (!mode64) {
22787 d = unsafeIRDirty_0_N (
22788 0/*regparms*/,
22789 "ppc32g_dirtyhelper_LVS",
22790 fnptr_to_fnentry(vbi, &ppc32g_dirtyhelper_LVS),
22791 args_be );
22792 } else {
22793 if (host_endness == VexEndnessBE)
22794 d = unsafeIRDirty_0_N (
22795 0/*regparms*/,
22796 "ppc64g_dirtyhelper_LVS",
22797 fnptr_to_fnentry(vbi, &ppc64g_dirtyhelper_LVS),
22798 args_be );
22799 else
22800 d = unsafeIRDirty_0_N (
22801 0/*regparms*/,
22802 "ppc64g_dirtyhelper_LVS",
22803 fnptr_to_fnentry( vbi, &ppc64g_dirtyhelper_LVS ),
22804 args_le );
22806 DIP("lvsr v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
22807 /* declare guest state effects */
22808 d->nFxState = 1;
22809 vex_bzero(&d->fxState, sizeof(d->fxState));
22810 d->fxState[0].fx = Ifx_Write;
22811 d->fxState[0].offset = vD_off;
22812 d->fxState[0].size = sizeof(U128);
22814 /* execute the dirty call, side-effecting guest state */
22815 stmt( IRStmt_Dirty(d) );
22816 break;
22818 case 0x007: // lvebx (Load Vector Element Byte Indexed, AV p119)
22819 DIP("lvebx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
22820 /* loads addressed byte into vector[EA[0:3]
22821 since all other destination bytes are undefined,
22822 can simply load entire vector from 16-aligned EA */
22823 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
22824 break;
22826 case 0x027: // lvehx (Load Vector Element Half Word Indexed, AV p121)
22827 DIP("lvehx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
22828 /* see note for lvebx */
22829 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
22830 break;
22832 case 0x047: // lvewx (Load Vector Element Word Indexed, AV p122)
22833 DIP("lvewx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
22834 /* see note for lvebx */
22835 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
22836 break;
22838 case 0x067: // lvx (Load Vector Indexed, AV p127)
22839 DIP("lvx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
22840 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
22841 break;
22843 case 0x167: // lvxl (Load Vector Indexed LRU, AV p128)
22844 DIP("lvxl v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
22845 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
22846 break;
22848 default:
22849 vex_printf("dis_av_load(ppc)(opc2)\n");
22850 return False;
22852 return True;
22856 AltiVec Store Instructions
22858 static Bool dis_av_store ( UInt theInstr )
22860 /* X-Form */
22861 UChar opc1 = ifieldOPC(theInstr);
22862 UChar vS_addr = ifieldRegDS(theInstr);
22863 UChar rA_addr = ifieldRegA(theInstr);
22864 UChar rB_addr = ifieldRegB(theInstr);
22865 UInt opc2 = ifieldOPClo10(theInstr);
22866 UChar b0 = ifieldBIT0(theInstr);
22868 IRType ty = mode64 ? Ity_I64 : Ity_I32;
22869 IRTemp EA = newTemp(ty);
22870 IRTemp addr_aligned = newTemp(ty);
22871 IRTemp vS = newTemp(Ity_V128);
22872 IRTemp eb = newTemp(Ity_I8);
22873 IRTemp idx = newTemp(Ity_I8);
22875 if (opc1 != 0x1F || b0 != 0) {
22876 vex_printf("dis_av_store(ppc)(instr)\n");
22877 return False;
22880 assign( vS, getVReg(vS_addr));
22881 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
22883 switch (opc2) {
22884 case 0x087: { // stvebx (Store Vector Byte Indexed, AV p131)
22885 DIP("stvebx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
22886 assign( eb, binop(Iop_And8, mkU8(0xF),
22887 unop(Iop_32to8,
22888 mkNarrowTo32(ty, mkexpr(EA)) )) );
22889 if (host_endness == VexEndnessLE) {
22890 assign( idx, binop(Iop_Shl8, mkexpr(eb), mkU8(3)) );
22891 } else {
22892 assign( idx, binop(Iop_Shl8,
22893 binop(Iop_Sub8, mkU8(15), mkexpr(eb)),
22894 mkU8(3)) );
22896 store( mkexpr(EA),
22897 unop( Iop_32to8, unop(Iop_V128to32,
22898 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx)))) );
22899 break;
22901 case 0x0A7: { // stvehx (Store Vector Half Word Indexed, AV p132)
22902 DIP("stvehx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
22903 assign( addr_aligned, addr_align(mkexpr(EA), 2) );
22904 assign( eb, binop(Iop_And8, mkU8(0xF),
22905 mkNarrowTo8(ty, mkexpr(addr_aligned) )) );
22906 if (host_endness == VexEndnessLE) {
22907 assign( idx, binop(Iop_Shl8, mkexpr(eb), mkU8(3)) );
22908 } else {
22909 assign( idx, binop(Iop_Shl8,
22910 binop(Iop_Sub8, mkU8(14), mkexpr(eb)),
22911 mkU8(3)) );
22913 store( mkexpr(addr_aligned),
22914 unop( Iop_32to16, unop(Iop_V128to32,
22915 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx)))) );
22916 break;
22918 case 0x0C7: { // stvewx (Store Vector Word Indexed, AV p133)
22919 DIP("stvewx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
22920 assign( addr_aligned, addr_align(mkexpr(EA), 4) );
22921 assign( eb, binop(Iop_And8, mkU8(0xF),
22922 mkNarrowTo8(ty, mkexpr(addr_aligned) )) );
22923 if (host_endness == VexEndnessLE) {
22924 assign( idx, binop(Iop_Shl8, mkexpr(eb), mkU8(3)) );
22925 } else {
22926 assign( idx, binop(Iop_Shl8,
22927 binop(Iop_Sub8, mkU8(12), mkexpr(eb)),
22928 mkU8(3)) );
22930 store( mkexpr( addr_aligned),
22931 unop( Iop_V128to32,
22932 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx))) );
22933 break;
22936 case 0x0E7: // stvx (Store Vector Indexed, AV p134)
22937 DIP("stvx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
22938 store( addr_align( mkexpr(EA), 16 ), mkexpr(vS) );
22939 break;
22941 case 0x1E7: // stvxl (Store Vector Indexed LRU, AV p135)
22942 DIP("stvxl v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
22943 store( addr_align( mkexpr(EA), 16 ), mkexpr(vS) );
22944 break;
22946 default:
22947 vex_printf("dis_av_store(ppc)(opc2)\n");
22948 return False;
22950 return True;
22954 AltiVec Arithmetic Instructions
22956 static Bool dis_av_arith ( UInt theInstr )
22958 /* VX-Form */
22959 UChar opc1 = ifieldOPC(theInstr);
22960 UChar vD_addr = ifieldRegDS(theInstr);
22961 UChar vA_addr = ifieldRegA(theInstr);
22962 UChar vB_addr = ifieldRegB(theInstr);
22963 UInt opc2 = IFIELD( theInstr, 0, 11 );
22965 IRTemp vA = newTemp(Ity_V128);
22966 IRTemp vB = newTemp(Ity_V128);
22967 IRTemp z3 = newTemp(Ity_I64);
22968 IRTemp z2 = newTemp(Ity_I64);
22969 IRTemp z1 = newTemp(Ity_I64);
22970 IRTemp z0 = newTemp(Ity_I64);
22971 IRTemp aEvn, aOdd;
22972 IRTemp a15, a14, a13, a12, a11, a10, a9, a8;
22973 IRTemp a7, a6, a5, a4, a3, a2, a1, a0;
22974 IRTemp b3, b2, b1, b0;
22976 aEvn = aOdd = IRTemp_INVALID;
22977 a15 = a14 = a13 = a12 = a11 = a10 = a9 = a8 = IRTemp_INVALID;
22978 a7 = a6 = a5 = a4 = a3 = a2 = a1 = a0 = IRTemp_INVALID;
22979 b3 = b2 = b1 = b0 = IRTemp_INVALID;
22981 assign( vA, getVReg( vA_addr ) );
22982 assign( vB, getVReg( vB_addr ) );
22984 if (opc1 != 0x4) {
22985 vex_printf("dis_av_arith(ppc)(opc1 != 0x4)\n");
22986 return False;
22989 switch (opc2) {
22990 /* Add */
22991 case 0x180: { // vaddcuw (Add Carryout Unsigned Word, AV p136)
22992 DIP("vaddcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
22993 /* unsigned_ov(x+y) = (y >u not(x)) */
22994 putVReg( vD_addr, binop( Iop_ShrN32x4,
22995 binop( Iop_CmpGT32Ux4, mkexpr( vB ),
22996 unop( Iop_NotV128, mkexpr( vA ) ) ),
22997 mkU8( 31 ) ) );
22998 break;
23000 case 0x000: // vaddubm (Add Unsigned Byte Modulo, AV p141)
23001 DIP("vaddubm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23002 putVReg( vD_addr, binop(Iop_Add8x16, mkexpr(vA), mkexpr(vB)) );
23003 break;
23005 case 0x040: // vadduhm (Add Unsigned Half Word Modulo, AV p143)
23006 DIP("vadduhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23007 putVReg( vD_addr, binop(Iop_Add16x8, mkexpr(vA), mkexpr(vB)) );
23008 break;
23010 case 0x080: // vadduwm (Add Unsigned Word Modulo, AV p145)
23011 DIP("vadduwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23012 putVReg( vD_addr, binop(Iop_Add32x4, mkexpr(vA), mkexpr(vB)) );
23013 break;
23015 case 0x0C0: // vaddudm (Add Unsigned Double Word Modulo)
23016 DIP("vaddudm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23017 putVReg( vD_addr, binop(Iop_Add64x2, mkexpr(vA), mkexpr(vB)) );
23018 break;
23020 case 0x200: // vaddubs (Add Unsigned Byte Saturate, AV p142)
23021 DIP("vaddubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23022 putVReg( vD_addr, binop(Iop_QAdd8Ux16, mkexpr(vA), mkexpr(vB)) );
23023 // TODO: set VSCR[SAT], perhaps via new primop: Iop_SatOfQAdd8Ux16
23024 break;
23026 case 0x240: // vadduhs (Add Unsigned Half Word Saturate, AV p144)
23027 DIP("vadduhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23028 putVReg( vD_addr, binop(Iop_QAdd16Ux8, mkexpr(vA), mkexpr(vB)) );
23029 // TODO: set VSCR[SAT]
23030 break;
23032 case 0x280: // vadduws (Add Unsigned Word Saturate, AV p146)
23033 DIP("vadduws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23034 putVReg( vD_addr, binop(Iop_QAdd32Ux4, mkexpr(vA), mkexpr(vB)) );
23035 // TODO: set VSCR[SAT]
23036 break;
23038 case 0x300: // vaddsbs (Add Signed Byte Saturate, AV p138)
23039 DIP("vaddsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23040 putVReg( vD_addr, binop(Iop_QAdd8Sx16, mkexpr(vA), mkexpr(vB)) );
23041 // TODO: set VSCR[SAT]
23042 break;
23044 case 0x340: // vaddshs (Add Signed Half Word Saturate, AV p139)
23045 DIP("vaddshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23046 putVReg( vD_addr, binop(Iop_QAdd16Sx8, mkexpr(vA), mkexpr(vB)) );
23047 // TODO: set VSCR[SAT]
23048 break;
23050 case 0x380: // vaddsws (Add Signed Word Saturate, AV p140)
23051 DIP("vaddsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23052 putVReg( vD_addr, binop(Iop_QAdd32Sx4, mkexpr(vA), mkexpr(vB)) );
23053 // TODO: set VSCR[SAT]
23054 break;
23057 /* Subtract */
23058 case 0x580: { // vsubcuw (Subtract Carryout Unsigned Word, AV p260)
23059 DIP("vsubcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23060 /* unsigned_ov(x-y) = (y >u x) */
23061 putVReg( vD_addr, binop(Iop_ShrN32x4,
23062 unop(Iop_NotV128,
23063 binop(Iop_CmpGT32Ux4, mkexpr(vB),
23064 mkexpr(vA))),
23065 mkU8(31)) );
23066 break;
23068 case 0x400: // vsububm (Subtract Unsigned Byte Modulo, AV p265)
23069 DIP("vsububm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23070 putVReg( vD_addr, binop(Iop_Sub8x16, mkexpr(vA), mkexpr(vB)) );
23071 break;
23073 case 0x440: // vsubuhm (Subtract Unsigned Half Word Modulo, AV p267)
23074 DIP("vsubuhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23075 putVReg( vD_addr, binop(Iop_Sub16x8, mkexpr(vA), mkexpr(vB)) );
23076 break;
23078 case 0x480: // vsubuwm (Subtract Unsigned Word Modulo, AV p269)
23079 DIP("vsubuwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23080 putVReg( vD_addr, binop(Iop_Sub32x4, mkexpr(vA), mkexpr(vB)) );
23081 break;
23083 case 0x4C0: // vsubudm (Subtract Unsigned Double Word Modulo)
23084 DIP("vsubudm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23085 putVReg( vD_addr, binop(Iop_Sub64x2, mkexpr(vA), mkexpr(vB)) );
23086 break;
23088 case 0x600: // vsububs (Subtract Unsigned Byte Saturate, AV p266)
23089 DIP("vsububs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23090 putVReg( vD_addr, binop(Iop_QSub8Ux16, mkexpr(vA), mkexpr(vB)) );
23091 // TODO: set VSCR[SAT]
23092 break;
23094 case 0x640: // vsubuhs (Subtract Unsigned HWord Saturate, AV p268)
23095 DIP("vsubuhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23096 putVReg( vD_addr, binop(Iop_QSub16Ux8, mkexpr(vA), mkexpr(vB)) );
23097 // TODO: set VSCR[SAT]
23098 break;
23100 case 0x680: // vsubuws (Subtract Unsigned Word Saturate, AV p270)
23101 DIP("vsubuws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23102 putVReg( vD_addr, binop(Iop_QSub32Ux4, mkexpr(vA), mkexpr(vB)) );
23103 // TODO: set VSCR[SAT]
23104 break;
23106 case 0x700: // vsubsbs (Subtract Signed Byte Saturate, AV p262)
23107 DIP("vsubsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23108 putVReg( vD_addr, binop(Iop_QSub8Sx16, mkexpr(vA), mkexpr(vB)) );
23109 // TODO: set VSCR[SAT]
23110 break;
23112 case 0x740: // vsubshs (Subtract Signed Half Word Saturate, AV p263)
23113 DIP("vsubshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23114 putVReg( vD_addr, binop(Iop_QSub16Sx8, mkexpr(vA), mkexpr(vB)) );
23115 // TODO: set VSCR[SAT]
23116 break;
23118 case 0x780: // vsubsws (Subtract Signed Word Saturate, AV p264)
23119 DIP("vsubsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23120 putVReg( vD_addr, binop(Iop_QSub32Sx4, mkexpr(vA), mkexpr(vB)) );
23121 // TODO: set VSCR[SAT]
23122 break;
23125 /* Maximum */
23126 case 0x002: // vmaxub (Maximum Unsigned Byte, AV p182)
23127 DIP("vmaxub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23128 putVReg( vD_addr, binop(Iop_Max8Ux16, mkexpr(vA), mkexpr(vB)) );
23129 break;
23131 case 0x042: // vmaxuh (Maximum Unsigned Half Word, AV p183)
23132 DIP("vmaxuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23133 putVReg( vD_addr, binop(Iop_Max16Ux8, mkexpr(vA), mkexpr(vB)) );
23134 break;
23136 case 0x082: // vmaxuw (Maximum Unsigned Word, AV p184)
23137 DIP("vmaxuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23138 putVReg( vD_addr, binop(Iop_Max32Ux4, mkexpr(vA), mkexpr(vB)) );
23139 break;
23141 case 0x0C2: // vmaxud (Maximum Unsigned Double word)
23142 DIP("vmaxud v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23143 putVReg( vD_addr, binop(Iop_Max64Ux2, mkexpr(vA), mkexpr(vB)) );
23144 break;
23146 case 0x102: // vmaxsb (Maximum Signed Byte, AV p179)
23147 DIP("vmaxsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23148 putVReg( vD_addr, binop(Iop_Max8Sx16, mkexpr(vA), mkexpr(vB)) );
23149 break;
23151 case 0x142: // vmaxsh (Maximum Signed Half Word, AV p180)
23152 DIP("vmaxsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23153 putVReg( vD_addr, binop(Iop_Max16Sx8, mkexpr(vA), mkexpr(vB)) );
23154 break;
23156 case 0x182: // vmaxsw (Maximum Signed Word, AV p181)
23157 DIP("vmaxsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23158 putVReg( vD_addr, binop(Iop_Max32Sx4, mkexpr(vA), mkexpr(vB)) );
23159 break;
23161 case 0x1C2: // vmaxsd (Maximum Signed Double word)
23162 DIP("vmaxsd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23163 putVReg( vD_addr, binop(Iop_Max64Sx2, mkexpr(vA), mkexpr(vB)) );
23164 break;
23166 /* Minimum */
23167 case 0x202: // vminub (Minimum Unsigned Byte, AV p191)
23168 DIP("vminub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23169 putVReg( vD_addr, binop(Iop_Min8Ux16, mkexpr(vA), mkexpr(vB)) );
23170 break;
23172 case 0x242: // vminuh (Minimum Unsigned Half Word, AV p192)
23173 DIP("vminuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23174 putVReg( vD_addr, binop(Iop_Min16Ux8, mkexpr(vA), mkexpr(vB)) );
23175 break;
23177 case 0x282: // vminuw (Minimum Unsigned Word, AV p193)
23178 DIP("vminuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23179 putVReg( vD_addr, binop(Iop_Min32Ux4, mkexpr(vA), mkexpr(vB)) );
23180 break;
23182 case 0x2C2: // vminud (Minimum Unsigned Double Word)
23183 DIP("vminud v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23184 putVReg( vD_addr, binop(Iop_Min64Ux2, mkexpr(vA), mkexpr(vB)) );
23185 break;
23187 case 0x302: // vminsb (Minimum Signed Byte, AV p188)
23188 DIP("vminsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23189 putVReg( vD_addr, binop(Iop_Min8Sx16, mkexpr(vA), mkexpr(vB)) );
23190 break;
23192 case 0x342: // vminsh (Minimum Signed Half Word, AV p189)
23193 DIP("vminsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23194 putVReg( vD_addr, binop(Iop_Min16Sx8, mkexpr(vA), mkexpr(vB)) );
23195 break;
23197 case 0x382: // vminsw (Minimum Signed Word, AV p190)
23198 DIP("vminsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23199 putVReg( vD_addr, binop(Iop_Min32Sx4, mkexpr(vA), mkexpr(vB)) );
23200 break;
23202 case 0x3C2: // vminsd (Minimum Signed Double Word)
23203 DIP("vminsd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23204 putVReg( vD_addr, binop(Iop_Min64Sx2, mkexpr(vA), mkexpr(vB)) );
23205 break;
23208 /* Average */
23209 case 0x402: // vavgub (Average Unsigned Byte, AV p152)
23210 DIP("vavgub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23211 putVReg( vD_addr, binop(Iop_Avg8Ux16, mkexpr(vA), mkexpr(vB)) );
23212 break;
23214 case 0x442: // vavguh (Average Unsigned Half Word, AV p153)
23215 DIP("vavguh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23216 putVReg( vD_addr, binop(Iop_Avg16Ux8, mkexpr(vA), mkexpr(vB)) );
23217 break;
23219 case 0x482: // vavguw (Average Unsigned Word, AV p154)
23220 DIP("vavguw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23221 putVReg( vD_addr, binop(Iop_Avg32Ux4, mkexpr(vA), mkexpr(vB)) );
23222 break;
23224 case 0x502: // vavgsb (Average Signed Byte, AV p149)
23225 DIP("vavgsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23226 putVReg( vD_addr, binop(Iop_Avg8Sx16, mkexpr(vA), mkexpr(vB)) );
23227 break;
23229 case 0x542: // vavgsh (Average Signed Half Word, AV p150)
23230 DIP("vavgsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23231 putVReg( vD_addr, binop(Iop_Avg16Sx8, mkexpr(vA), mkexpr(vB)) );
23232 break;
23234 case 0x582: // vavgsw (Average Signed Word, AV p151)
23235 DIP("vavgsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23236 putVReg( vD_addr, binop(Iop_Avg32Sx4, mkexpr(vA), mkexpr(vB)) );
23237 break;
23240 /* Multiply */
23241 case 0x008: // vmuloub (Multiply Odd Unsigned Byte, AV p213)
23242 DIP("vmuloub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23243 putVReg( vD_addr,
23244 binop(Iop_MullEven8Ux16, mkexpr(vA), mkexpr(vB)));
23245 break;
23247 case 0x048: // vmulouh (Multiply Odd Unsigned Half Word, AV p214)
23248 DIP("vmulouh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23249 putVReg( vD_addr,
23250 binop(Iop_MullEven16Ux8, mkexpr(vA), mkexpr(vB)));
23251 break;
23253 case 0x088: // vmulouw (Multiply Odd Unsigned Word)
23254 DIP("vmulouw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23255 putVReg( vD_addr, binop( Iop_MullEven32Ux4, mkexpr(vA), mkexpr(vB) ) );
23256 break;
23258 case 0x089: // vmuluwm (Multiply Unsigned Word Modulo)
23259 DIP("vmuluwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23260 putVReg( vD_addr, binop( Iop_Mul32x4, mkexpr(vA), mkexpr(vB) ) );
23261 break;
23263 case 0x108: // vmulosb (Multiply Odd Signed Byte, AV p211)
23264 DIP("vmulosb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23265 putVReg( vD_addr,
23266 binop(Iop_MullEven8Sx16, mkexpr(vA), mkexpr(vB)));
23267 break;
23269 case 0x148: // vmulosh (Multiply Odd Signed Half Word, AV p212)
23270 DIP("vmulosh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23271 putVReg( vD_addr,
23272 binop(Iop_MullEven16Sx8, mkexpr(vA), mkexpr(vB)));
23273 break;
23275 case 0x188: // vmulosw (Multiply Odd Signed Word)
23276 DIP("vmulosw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23277 putVReg( vD_addr, binop( Iop_MullEven32Sx4, mkexpr(vA), mkexpr(vB) ) );
23278 break;
23280 case 0x208: // vmuleub (Multiply Even Unsigned Byte, AV p209)
23281 DIP("vmuleub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23282 putVReg( vD_addr, MK_Iop_MullOdd8Ux16( mkexpr(vA), mkexpr(vB) ));
23283 break;
23285 case 0x248: // vmuleuh (Multiply Even Unsigned Half Word, AV p210)
23286 DIP("vmuleuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23287 putVReg( vD_addr, MK_Iop_MullOdd16Ux8( mkexpr(vA), mkexpr(vB) ));
23288 break;
23290 case 0x288: // vmuleuw (Multiply Even Unsigned Word)
23291 DIP("vmuleuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23292 putVReg( vD_addr, MK_Iop_MullOdd32Ux4( mkexpr(vA), mkexpr(vB) ) );
23293 break;
23295 case 0x308: // vmulesb (Multiply Even Signed Byte, AV p207)
23296 DIP("vmulesb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23297 putVReg( vD_addr, MK_Iop_MullOdd8Sx16( mkexpr(vA), mkexpr(vB) ));
23298 break;
23300 case 0x348: // vmulesh (Multiply Even Signed Half Word, AV p208)
23301 DIP("vmulesh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23302 putVReg( vD_addr, MK_Iop_MullOdd16Sx8( mkexpr(vA), mkexpr(vB) ));
23303 break;
23305 case 0x388: // vmulesw (Multiply Even Signed Word)
23306 DIP("vmulesw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23307 putVReg( vD_addr, MK_Iop_MullOdd32Sx4( mkexpr(vA), mkexpr(vB) ) );
23308 break;
23310 /* Sum Across Partial */
23311 case 0x608: { // vsum4ubs (Sum Partial (1/4) UB Saturate, AV p275)
23312 IRTemp aEE, aEO, aOE, aOO;
23313 aEE = aEO = aOE = aOO = IRTemp_INVALID;
23314 DIP("vsum4ubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23316 /* vA: V128_8Ux16 -> 4 x V128_32Ux4, sign-extended */
23317 expand8Ux16( mkexpr(vA), &aEvn, &aOdd ); // (15,13...),(14,12...)
23318 expand16Ux8( mkexpr(aEvn), &aEE, &aEO ); // (15,11...),(13, 9...)
23319 expand16Ux8( mkexpr(aOdd), &aOE, &aOO ); // (14,10...),(12, 8...)
23321 /* break V128 to 4xI32's, zero-extending to I64's */
23322 breakV128to4x64U( mkexpr(aEE), &a15, &a11, &a7, &a3 );
23323 breakV128to4x64U( mkexpr(aOE), &a14, &a10, &a6, &a2 );
23324 breakV128to4x64U( mkexpr(aEO), &a13, &a9, &a5, &a1 );
23325 breakV128to4x64U( mkexpr(aOO), &a12, &a8, &a4, &a0 );
23326 breakV128to4x64U( mkexpr(vB), &b3, &b2, &b1, &b0 );
23328 /* add lanes */
23329 assign( z3, binop(Iop_Add64, mkexpr(b3),
23330 binop(Iop_Add64,
23331 binop(Iop_Add64, mkexpr(a15), mkexpr(a14)),
23332 binop(Iop_Add64, mkexpr(a13), mkexpr(a12)))) );
23333 assign( z2, binop(Iop_Add64, mkexpr(b2),
23334 binop(Iop_Add64,
23335 binop(Iop_Add64, mkexpr(a11), mkexpr(a10)),
23336 binop(Iop_Add64, mkexpr(a9), mkexpr(a8)))) );
23337 assign( z1, binop(Iop_Add64, mkexpr(b1),
23338 binop(Iop_Add64,
23339 binop(Iop_Add64, mkexpr(a7), mkexpr(a6)),
23340 binop(Iop_Add64, mkexpr(a5), mkexpr(a4)))) );
23341 assign( z0, binop(Iop_Add64, mkexpr(b0),
23342 binop(Iop_Add64,
23343 binop(Iop_Add64, mkexpr(a3), mkexpr(a2)),
23344 binop(Iop_Add64, mkexpr(a1), mkexpr(a0)))) );
23346 /* saturate-narrow to 32bit, and combine to V128 */
23347 putVReg( vD_addr, mkV128from4x64U( mkexpr(z3), mkexpr(z2),
23348 mkexpr(z1), mkexpr(z0)) );
23349 break;
23351 case 0x708: { // vsum4sbs (Sum Partial (1/4) SB Saturate, AV p273)
23352 IRTemp aEE, aEO, aOE, aOO;
23353 aEE = aEO = aOE = aOO = IRTemp_INVALID;
23354 DIP("vsum4sbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23356 /* vA: V128_8Sx16 -> 4 x V128_32Sx4, sign-extended */
23357 expand8Sx16( mkexpr(vA), &aEvn, &aOdd ); // (15,13...),(14,12...)
23358 expand16Sx8( mkexpr(aEvn), &aEE, &aEO ); // (15,11...),(13, 9...)
23359 expand16Sx8( mkexpr(aOdd), &aOE, &aOO ); // (14,10...),(12, 8...)
23361 /* break V128 to 4xI32's, sign-extending to I64's */
23362 breakV128to4x64S( mkexpr(aEE), &a15, &a11, &a7, &a3 );
23363 breakV128to4x64S( mkexpr(aOE), &a14, &a10, &a6, &a2 );
23364 breakV128to4x64S( mkexpr(aEO), &a13, &a9, &a5, &a1 );
23365 breakV128to4x64S( mkexpr(aOO), &a12, &a8, &a4, &a0 );
23366 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
23368 /* add lanes */
23369 assign( z3, binop(Iop_Add64, mkexpr(b3),
23370 binop(Iop_Add64,
23371 binop(Iop_Add64, mkexpr(a15), mkexpr(a14)),
23372 binop(Iop_Add64, mkexpr(a13), mkexpr(a12)))) );
23373 assign( z2, binop(Iop_Add64, mkexpr(b2),
23374 binop(Iop_Add64,
23375 binop(Iop_Add64, mkexpr(a11), mkexpr(a10)),
23376 binop(Iop_Add64, mkexpr(a9), mkexpr(a8)))) );
23377 assign( z1, binop(Iop_Add64, mkexpr(b1),
23378 binop(Iop_Add64,
23379 binop(Iop_Add64, mkexpr(a7), mkexpr(a6)),
23380 binop(Iop_Add64, mkexpr(a5), mkexpr(a4)))) );
23381 assign( z0, binop(Iop_Add64, mkexpr(b0),
23382 binop(Iop_Add64,
23383 binop(Iop_Add64, mkexpr(a3), mkexpr(a2)),
23384 binop(Iop_Add64, mkexpr(a1), mkexpr(a0)))) );
23386 /* saturate-narrow to 32bit, and combine to V128 */
23387 putVReg( vD_addr, mkV128from4x64S( mkexpr(z3), mkexpr(z2),
23388 mkexpr(z1), mkexpr(z0)) );
23389 break;
23391 case 0x648: { // vsum4shs (Sum Partial (1/4) SHW Saturate, AV p274)
23392 DIP("vsum4shs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23394 /* vA: V128_16Sx8 -> 2 x V128_32Sx4, sign-extended */
23395 expand16Sx8( mkexpr(vA), &aEvn, &aOdd ); // (7,5...),(6,4...)
23397 /* break V128 to 4xI32's, sign-extending to I64's */
23398 breakV128to4x64S( mkexpr(aEvn), &a7, &a5, &a3, &a1 );
23399 breakV128to4x64S( mkexpr(aOdd), &a6, &a4, &a2, &a0 );
23400 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
23402 /* add lanes */
23403 assign( z3, binop(Iop_Add64, mkexpr(b3),
23404 binop(Iop_Add64, mkexpr(a7), mkexpr(a6))));
23405 assign( z2, binop(Iop_Add64, mkexpr(b2),
23406 binop(Iop_Add64, mkexpr(a5), mkexpr(a4))));
23407 assign( z1, binop(Iop_Add64, mkexpr(b1),
23408 binop(Iop_Add64, mkexpr(a3), mkexpr(a2))));
23409 assign( z0, binop(Iop_Add64, mkexpr(b0),
23410 binop(Iop_Add64, mkexpr(a1), mkexpr(a0))));
23412 /* saturate-narrow to 32bit, and combine to V128 */
23413 putVReg( vD_addr, mkV128from4x64S( mkexpr(z3), mkexpr(z2),
23414 mkexpr(z1), mkexpr(z0)) );
23415 break;
23417 case 0x688: { // vsum2sws (Sum Partial (1/2) SW Saturate, AV p272)
23418 DIP("vsum2sws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23420 /* break V128 to 4xI32's, sign-extending to I64's */
23421 breakV128to4x64S( mkexpr(vA), &a3, &a2, &a1, &a0 );
23422 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
23424 /* add lanes */
23425 assign( z2, binop(Iop_Add64, mkexpr(b2),
23426 binop(Iop_Add64, mkexpr(a3), mkexpr(a2))) );
23427 assign( z0, binop(Iop_Add64, mkexpr(b0),
23428 binop(Iop_Add64, mkexpr(a1), mkexpr(a0))) );
23430 /* saturate-narrow to 32bit, and combine to V128 */
23431 putVReg( vD_addr, mkV128from4x64S( mkU64(0), mkexpr(z2),
23432 mkU64(0), mkexpr(z0)) );
23433 break;
23435 case 0x788: { // vsumsws (Sum SW Saturate, AV p271)
23436 DIP("vsumsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23438 /* break V128 to 4xI32's, sign-extending to I64's */
23439 breakV128to4x64S( mkexpr(vA), &a3, &a2, &a1, &a0 );
23440 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
23442 /* add lanes */
23443 assign( z0, binop(Iop_Add64, mkexpr(b0),
23444 binop(Iop_Add64,
23445 binop(Iop_Add64, mkexpr(a3), mkexpr(a2)),
23446 binop(Iop_Add64, mkexpr(a1), mkexpr(a0)))) );
23448 /* saturate-narrow to 32bit, and combine to V128 */
23449 putVReg( vD_addr, mkV128from4x64S( mkU64(0), mkU64(0),
23450 mkU64(0), mkexpr(z0)) );
23451 break;
23453 default:
23454 vex_printf("dis_av_arith(ppc)(opc2=0x%x)\n", opc2);
23455 return False;
23457 return True;
23461 AltiVec Logic Instructions
23463 static Bool dis_av_logic ( UInt theInstr )
23465 /* VX-Form */
23466 UChar opc1 = ifieldOPC(theInstr);
23467 UChar vD_addr = ifieldRegDS(theInstr);
23468 UChar vA_addr = ifieldRegA(theInstr);
23469 UChar vB_addr = ifieldRegB(theInstr);
23470 UInt opc2 = IFIELD( theInstr, 0, 11 );
23472 IRTemp vA = newTemp(Ity_V128);
23473 IRTemp vB = newTemp(Ity_V128);
23474 assign( vA, getVReg(vA_addr));
23475 assign( vB, getVReg(vB_addr));
23477 if (opc1 != 0x4) {
23478 vex_printf("dis_av_logic(ppc)(opc1 != 0x4)\n");
23479 return False;
23482 switch (opc2) {
23483 case 0x404: // vand (And, AV p147)
23484 DIP("vand v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23485 putVReg( vD_addr, binop(Iop_AndV128, mkexpr(vA), mkexpr(vB)) );
23486 break;
23488 case 0x444: // vandc (And, AV p148)
23489 DIP("vandc v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23490 putVReg( vD_addr, binop(Iop_AndV128, mkexpr(vA),
23491 unop(Iop_NotV128, mkexpr(vB))) );
23492 break;
23494 case 0x484: // vor (Or, AV p217)
23495 DIP("vor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23496 putVReg( vD_addr, binop(Iop_OrV128, mkexpr(vA), mkexpr(vB)) );
23497 break;
23499 case 0x4C4: // vxor (Xor, AV p282)
23500 DIP("vxor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23501 putVReg( vD_addr, binop(Iop_XorV128, mkexpr(vA), mkexpr(vB)) );
23502 break;
23504 case 0x504: // vnor (Nor, AV p216)
23505 DIP("vnor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23506 putVReg( vD_addr,
23507 unop(Iop_NotV128, binop(Iop_OrV128, mkexpr(vA), mkexpr(vB))) );
23508 break;
23510 case 0x544: // vorc (vA Or'd with complement of vb)
23511 DIP("vorc v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23512 putVReg( vD_addr, binop( Iop_OrV128,
23513 mkexpr( vA ),
23514 unop( Iop_NotV128, mkexpr( vB ) ) ) );
23515 break;
23517 case 0x584: // vnand (Nand)
23518 DIP("vnand v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23519 putVReg( vD_addr, unop( Iop_NotV128,
23520 binop(Iop_AndV128, mkexpr( vA ),
23521 mkexpr( vB ) ) ) );
23522 break;
23524 case 0x684: // veqv (complemented XOr)
23525 DIP("veqv v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
23526 putVReg( vD_addr, unop( Iop_NotV128,
23527 binop( Iop_XorV128, mkexpr( vA ),
23528 mkexpr( vB ) ) ) );
23529 break;
23531 default:
23532 vex_printf("dis_av_logic(ppc)(opc2=0x%x)\n", opc2);
23533 return False;
23535 return True;
23539 AltiVec Compare Instructions
23541 static Bool dis_av_cmp ( UInt theInstr )
23543 /* VXR-Form */
23544 UChar opc1 = ifieldOPC(theInstr);
23545 UChar vD_addr = ifieldRegDS(theInstr);
23546 UChar vA_addr = ifieldRegA(theInstr);
23547 UChar vB_addr = ifieldRegB(theInstr);
23548 UChar flag_rC = ifieldBIT10(theInstr);
23549 UInt opc2 = IFIELD( theInstr, 0, 10 );
23551 IRTemp vA = newTemp(Ity_V128);
23552 IRTemp vB = newTemp(Ity_V128);
23553 IRTemp vD = newTemp(Ity_V128);
23554 assign( vA, getVReg(vA_addr));
23555 assign( vB, getVReg(vB_addr));
23557 if (opc1 != 0x4) {
23558 vex_printf("dis_av_cmp(ppc)(instr)\n");
23559 return False;
23562 switch (opc2) {
23563 case 0x006: // vcmpequb (Compare Equal-to Unsigned B, AV p160)
23564 DIP("vcmpequb%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23565 vD_addr, vA_addr, vB_addr);
23566 assign( vD, binop(Iop_CmpEQ8x16, mkexpr(vA), mkexpr(vB)) );
23567 break;
23569 case 0x007: // vcmpneb (Compare Not Equal byte)
23570 DIP("vcmpneb%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23571 vD_addr, vA_addr, vB_addr);
23572 assign( vD, unop( Iop_NotV128,
23573 binop( Iop_CmpEQ8x16, mkexpr( vA ), mkexpr( vB ) ) ) );
23574 break;
23576 case 0x046: // vcmpequh (Compare Equal-to Unsigned HW, AV p161)
23577 DIP("vcmpequh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23578 vD_addr, vA_addr, vB_addr);
23579 assign( vD, binop(Iop_CmpEQ16x8, mkexpr(vA), mkexpr(vB)) );
23580 break;
23582 case 0x047: // vcmpneh (Compare Not Equal-to Halfword)
23583 DIP("vcmpneh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23584 vD_addr, vA_addr, vB_addr);
23585 assign( vD, unop( Iop_NotV128,
23586 binop( Iop_CmpEQ16x8, mkexpr( vA ), mkexpr( vB ) ) ) );
23587 break;
23589 case 0x086: // vcmpequw (Compare Equal-to Unsigned W, AV p162)
23590 DIP("vcmpequw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23591 vD_addr, vA_addr, vB_addr);
23592 assign( vD, binop(Iop_CmpEQ32x4, mkexpr(vA), mkexpr(vB)) );
23593 break;
23595 case 0x087: // vcmpnew (Compare Not Equal-to Word)
23596 DIP("vcmpnew%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23597 vD_addr, vA_addr, vB_addr);
23598 assign( vD, unop( Iop_NotV128,
23599 binop( Iop_CmpEQ32x4, mkexpr( vA ), mkexpr( vB ) ) ) );
23600 break;
23602 case 0x107: // vcmpnezb (Compare Not Equal or Zero byte)
23604 IRTemp vAeqvB = newTemp( Ity_V128 );
23605 IRTemp vAeq0 = newTemp( Ity_V128 );
23606 IRTemp vBeq0 = newTemp( Ity_V128 );
23607 IRTemp zero = newTemp( Ity_V128 );
23609 DIP("vcmpnezb%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23610 vD_addr, vA_addr, vB_addr);
23612 assign( zero, binop( Iop_64HLtoV128, mkU64( 0 ), mkU64( 0 ) ) );
23613 assign( vAeq0, binop( Iop_CmpEQ8x16, mkexpr( vA ), mkexpr( zero ) ) );
23614 assign( vBeq0, binop( Iop_CmpEQ8x16, mkexpr( vB ), mkexpr( zero ) ) );
23615 assign( vAeqvB, unop( Iop_NotV128,
23616 binop( Iop_CmpEQ8x16, mkexpr( vA ),
23617 mkexpr( vB ) ) ) );
23619 assign( vD, mkOr3_V128( vAeqvB, vAeq0, vBeq0 ) );
23621 break;
23623 case 0x147: // vcmpnezh (Compare Not Equal or Zero Halfword)
23625 IRTemp vAeqvB = newTemp( Ity_V128 );
23626 IRTemp vAeq0 = newTemp( Ity_V128 );
23627 IRTemp vBeq0 = newTemp( Ity_V128 );
23628 IRTemp zero = newTemp( Ity_V128 );
23630 DIP("vcmpnezh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23631 vD_addr, vA_addr, vB_addr);
23633 assign( zero, binop( Iop_64HLtoV128, mkU64( 0 ), mkU64( 0 ) ) );
23634 assign( vAeq0, binop( Iop_CmpEQ16x8, mkexpr( vA ), mkexpr( zero ) ) );
23635 assign( vBeq0, binop( Iop_CmpEQ16x8, mkexpr( vB ), mkexpr( zero ) ) );
23636 assign( vAeqvB, unop( Iop_NotV128,
23637 binop(Iop_CmpEQ16x8, mkexpr( vA ),
23638 mkexpr( vB ) ) ) );
23640 assign( vD, binop( Iop_OrV128,
23641 binop( Iop_OrV128,
23642 mkexpr( vAeq0 ),
23643 mkexpr( vBeq0 ) ),
23644 mkexpr( vAeqvB ) ) );
23646 break;
23648 case 0x187: // vcmpnezw (Compare Not Equal or Zero Word)
23650 IRTemp vAeqvB = newTemp( Ity_V128 );
23651 IRTemp vAeq0 = newTemp( Ity_V128 );
23652 IRTemp vBeq0 = newTemp( Ity_V128 );
23653 IRTemp zero = newTemp( Ity_V128 );
23655 DIP("vcmpnezw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23656 vD_addr, vA_addr, vB_addr);
23658 assign( zero, binop( Iop_64HLtoV128, mkU64( 0 ), mkU64( 0 ) ) );
23659 assign( vAeq0, binop( Iop_CmpEQ32x4, mkexpr( vA ), mkexpr( zero ) ) );
23660 assign( vBeq0, binop( Iop_CmpEQ32x4, mkexpr( vB ), mkexpr( zero ) ) );
23661 assign( vAeqvB, unop( Iop_NotV128,
23662 binop(Iop_CmpEQ32x4, mkexpr( vA ),
23663 mkexpr( vB ) ) ) );
23665 assign( vD, binop( Iop_OrV128,
23666 binop( Iop_OrV128,
23667 mkexpr( vAeq0 ),
23668 mkexpr( vBeq0 ) ),
23669 mkexpr( vAeqvB ) ) );
23671 break;
23673 case 0x0C7: // vcmpequd (Compare Equal-to Unsigned Doubleword)
23674 DIP("vcmpequd%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23675 vD_addr, vA_addr, vB_addr);
23676 assign( vD, binop(Iop_CmpEQ64x2, mkexpr(vA), mkexpr(vB)) );
23677 break;
23679 case 0x206: // vcmpgtub (Compare Greater-than Unsigned B, AV p168)
23680 DIP("vcmpgtub%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23681 vD_addr, vA_addr, vB_addr);
23682 assign( vD, binop(Iop_CmpGT8Ux16, mkexpr(vA), mkexpr(vB)) );
23683 break;
23685 case 0x246: // vcmpgtuh (Compare Greater-than Unsigned HW, AV p169)
23686 DIP("vcmpgtuh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23687 vD_addr, vA_addr, vB_addr);
23688 assign( vD, binop(Iop_CmpGT16Ux8, mkexpr(vA), mkexpr(vB)) );
23689 break;
23691 case 0x286: // vcmpgtuw (Compare Greater-than Unsigned W, AV p170)
23692 DIP("vcmpgtuw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23693 vD_addr, vA_addr, vB_addr);
23694 assign( vD, binop(Iop_CmpGT32Ux4, mkexpr(vA), mkexpr(vB)) );
23695 break;
23697 case 0x2C7: // vcmpgtud (Compare Greater-than Unsigned double)
23698 DIP("vcmpgtud%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23699 vD_addr, vA_addr, vB_addr);
23700 assign( vD, binop(Iop_CmpGT64Ux2, mkexpr(vA), mkexpr(vB)) );
23701 break;
23703 case 0x306: // vcmpgtsb (Compare Greater-than Signed B, AV p165)
23704 DIP("vcmpgtsb%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23705 vD_addr, vA_addr, vB_addr);
23706 assign( vD, binop(Iop_CmpGT8Sx16, mkexpr(vA), mkexpr(vB)) );
23707 break;
23709 case 0x346: // vcmpgtsh (Compare Greater-than Signed HW, AV p166)
23710 DIP("vcmpgtsh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23711 vD_addr, vA_addr, vB_addr);
23712 assign( vD, binop(Iop_CmpGT16Sx8, mkexpr(vA), mkexpr(vB)) );
23713 break;
23715 case 0x386: // vcmpgtsw (Compare Greater-than Signed W, AV p167)
23716 DIP("vcmpgtsw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23717 vD_addr, vA_addr, vB_addr);
23718 assign( vD, binop(Iop_CmpGT32Sx4, mkexpr(vA), mkexpr(vB)) );
23719 break;
23721 case 0x3C7: // vcmpgtsd (Compare Greater-than Signed double)
23722 DIP("vcmpgtsd%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
23723 vD_addr, vA_addr, vB_addr);
23724 assign( vD, binop(Iop_CmpGT64Sx2, mkexpr(vA), mkexpr(vB)) );
23725 break;
23727 default:
23728 vex_printf("dis_av_cmp(ppc)(opc2)\n");
23729 return False;
23732 putVReg( vD_addr, mkexpr(vD) );
23734 if (flag_rC) {
23735 set_AV_CR6( mkexpr(vD), True );
23737 return True;
23741 AltiVec Multiply-Sum Instructions
23743 static Bool dis_av_multarith ( UInt theInstr )
23745 /* VA-Form */
23746 UChar opc1 = ifieldOPC(theInstr);
23747 UChar vD_addr = ifieldRegDS(theInstr);
23748 UChar vA_addr = ifieldRegA(theInstr);
23749 UChar vB_addr = ifieldRegB(theInstr);
23750 UChar vC_addr = ifieldRegC(theInstr);
23751 UChar opc2 = toUChar( IFIELD( theInstr, 0, 6 ) );
23753 IRTemp vA = newTemp(Ity_V128);
23754 IRTemp vB = newTemp(Ity_V128);
23755 IRTemp vC = newTemp(Ity_V128);
23756 IRTemp zeros = newTemp(Ity_V128);
23757 IRTemp aLo = newTemp(Ity_V128);
23758 IRTemp bLo = newTemp(Ity_V128);
23759 IRTemp cLo = newTemp(Ity_V128);
23760 IRTemp zLo = newTemp(Ity_V128);
23761 IRTemp aHi = newTemp(Ity_V128);
23762 IRTemp bHi = newTemp(Ity_V128);
23763 IRTemp cHi = newTemp(Ity_V128);
23764 IRTemp zHi = newTemp(Ity_V128);
23765 IRTemp abEvn = newTemp(Ity_V128);
23766 IRTemp abOdd = newTemp(Ity_V128);
23767 IRTemp z3 = newTemp(Ity_I64);
23768 IRTemp z2 = newTemp(Ity_I64);
23769 IRTemp z1 = newTemp(Ity_I64);
23770 IRTemp z0 = newTemp(Ity_I64);
23771 IRTemp ab7, ab6, ab5, ab4, ab3, ab2, ab1, ab0;
23772 IRTemp c3, c2, c1, c0;
23774 ab7 = ab6 = ab5 = ab4 = ab3 = ab2 = ab1 = ab0 = IRTemp_INVALID;
23775 c3 = c2 = c1 = c0 = IRTemp_INVALID;
23777 assign( vA, getVReg(vA_addr));
23778 assign( vB, getVReg(vB_addr));
23779 assign( vC, getVReg(vC_addr));
23780 assign( zeros, unop(Iop_Dup32x4, mkU32(0)) );
23782 if (opc1 != 0x4) {
23783 vex_printf("dis_av_multarith(ppc)(instr)\n");
23784 return False;
23787 switch (opc2) {
23788 /* Multiply-Add */
23789 case 0x20: { // vmhaddshs (Mult Hi, Add Signed HW Saturate, AV p185)
23790 IRTemp cSigns = newTemp(Ity_V128);
23791 DIP("vmhaddshs v%d,v%d,v%d,v%d\n",
23792 vD_addr, vA_addr, vB_addr, vC_addr);
23793 assign(cSigns, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vC)));
23794 assign(aLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vA)));
23795 assign(bLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vB)));
23796 assign(cLo, binop(Iop_InterleaveLO16x8, mkexpr(cSigns),mkexpr(vC)));
23797 assign(aHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vA)));
23798 assign(bHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vB)));
23799 assign(cHi, binop(Iop_InterleaveHI16x8, mkexpr(cSigns),mkexpr(vC)));
23801 assign( zLo, binop(Iop_Add32x4, mkexpr(cLo),
23802 binop(Iop_SarN32x4,
23803 binop(Iop_MullEven16Sx8,
23804 mkexpr(aLo), mkexpr(bLo)),
23805 mkU8(15))) );
23807 assign( zHi, binop(Iop_Add32x4, mkexpr(cHi),
23808 binop(Iop_SarN32x4,
23809 binop(Iop_MullEven16Sx8,
23810 mkexpr(aHi), mkexpr(bHi)),
23811 mkU8(15))) );
23813 putVReg( vD_addr,
23814 binop(Iop_QNarrowBin32Sto16Sx8, mkexpr(zHi), mkexpr(zLo)) );
23815 break;
23817 case 0x21: { // vmhraddshs (Mult High Round, Add Signed HW Saturate, AV p186)
23818 IRTemp zKonst = newTemp(Ity_V128);
23819 IRTemp cSigns = newTemp(Ity_V128);
23820 DIP("vmhraddshs v%d,v%d,v%d,v%d\n",
23821 vD_addr, vA_addr, vB_addr, vC_addr);
23822 assign(cSigns, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vC)) );
23823 assign(aLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vA)));
23824 assign(bLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vB)));
23825 assign(cLo, binop(Iop_InterleaveLO16x8, mkexpr(cSigns),mkexpr(vC)));
23826 assign(aHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vA)));
23827 assign(bHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vB)));
23828 assign(cHi, binop(Iop_InterleaveHI16x8, mkexpr(cSigns),mkexpr(vC)));
23830 /* shifting our const avoids store/load version of Dup */
23831 assign( zKonst, binop(Iop_ShlN32x4, unop(Iop_Dup32x4, mkU32(0x1)),
23832 mkU8(14)) );
23834 assign( zLo, binop(Iop_Add32x4, mkexpr(cLo),
23835 binop(Iop_SarN32x4,
23836 binop(Iop_Add32x4, mkexpr(zKonst),
23837 binop(Iop_MullEven16Sx8,
23838 mkexpr(aLo), mkexpr(bLo))),
23839 mkU8(15))) );
23841 assign( zHi, binop(Iop_Add32x4, mkexpr(cHi),
23842 binop(Iop_SarN32x4,
23843 binop(Iop_Add32x4, mkexpr(zKonst),
23844 binop(Iop_MullEven16Sx8,
23845 mkexpr(aHi), mkexpr(bHi))),
23846 mkU8(15))) );
23848 putVReg( vD_addr,
23849 binop(Iop_QNarrowBin32Sto16Sx8, mkexpr(zHi), mkexpr(zLo)) );
23850 break;
23852 case 0x22: { // vmladduhm (Mult Low, Add Unsigned HW Modulo, AV p194)
23853 DIP("vmladduhm v%d,v%d,v%d,v%d\n",
23854 vD_addr, vA_addr, vB_addr, vC_addr);
23855 assign(aLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vA)));
23856 assign(bLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vB)));
23857 assign(cLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vC)));
23858 assign(aHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vA)));
23859 assign(bHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vB)));
23860 assign(cHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vC)));
23861 assign(zLo, binop(Iop_Add32x4,
23862 binop(Iop_MullEven16Ux8, mkexpr(aLo), mkexpr(bLo)),
23863 mkexpr(cLo)) );
23864 assign(zHi, binop(Iop_Add32x4,
23865 binop(Iop_MullEven16Ux8, mkexpr(aHi), mkexpr(bHi)),
23866 mkexpr(cHi)));
23867 putVReg( vD_addr,
23868 binop(Iop_NarrowBin32to16x8, mkexpr(zHi), mkexpr(zLo)) );
23869 break;
23872 case 0x23: { // vmsumudm
23873 DIP("vmsumudm v%d,v%d,v%d,v%d\n",
23874 vD_addr, vA_addr, vB_addr, vC_addr);
23875 /* This instruction takes input vectors VA, VB consisting of 2 usigned
23876 64-bit integer elements and a 128 bit unsigned input U128_C. The
23877 instruction performs the following operation:
23879 VA[0] * VB[0] -> U128_mul_result0;
23880 VA[1] * VB[1] -> U128_mul_result1;
23881 U128_C + U128_mul_result0 + U128_mul_result1 -> U128_partial_sum;
23882 carry out and overflow is discarded.
23885 /* The Iop_MulI128low assumes the upper 64-bits in the two input operands
23886 are zero. */
23887 IRTemp mul_result0 = newTemp( Ity_I128 );
23888 IRTemp mul_result1 = newTemp( Ity_I128 );
23889 IRTemp partial_sum_hi = newTemp( Ity_I64 );
23890 IRTemp partial_sum_low = newTemp( Ity_I64 );
23891 IRTemp result_hi = newTemp( Ity_I64 );
23892 IRTemp result_low = newTemp( Ity_I64 );
23893 IRExpr *ca_sum, *ca_result;
23896 /* Do multiplications */
23897 assign ( mul_result0, binop( Iop_MullU64,
23898 unop( Iop_V128to64, mkexpr( vA ) ),
23899 unop( Iop_V128to64, mkexpr( vB) ) ) );
23901 assign ( mul_result1, binop( Iop_MullU64,
23902 unop( Iop_V128HIto64, mkexpr( vA ) ),
23903 unop( Iop_V128HIto64, mkexpr( vB) ) ) );
23905 /* Add the two 128-bit results using 64-bit unsigned adds, calculate carry
23906 from low 64-bits add into sum of upper 64-bits. Throw away carry out
23907 of the upper 64-bit sum. */
23908 assign ( partial_sum_low, binop( Iop_Add64,
23909 unop( Iop_128to64, mkexpr( mul_result0 ) ),
23910 unop( Iop_128to64, mkexpr( mul_result1 ) )
23911 ) );
23913 /* ca_sum is type U32 */
23914 ca_sum = calculate_XER_CA_64 ( PPCG_FLAG_OP_ADD,
23915 mkexpr(partial_sum_low ),
23916 unop( Iop_128to64, mkexpr( mul_result0 ) ),
23917 unop( Iop_128to64, mkexpr( mul_result1 ) ),
23918 mkU64( 0 ) );
23920 assign ( partial_sum_hi,
23921 binop( Iop_Add64,
23922 binop( Iop_Add64,
23923 unop( Iop_128HIto64, mkexpr( mul_result0 ) ),
23924 unop( Iop_128HIto64, mkexpr( mul_result1 ) ) ),
23925 binop( Iop_32HLto64, mkU32( 0 ), ca_sum ) ) );
23927 /* Now add in the value of C */
23928 assign ( result_low, binop( Iop_Add64,
23929 mkexpr( partial_sum_low ),
23930 unop( Iop_V128to64, mkexpr( vC ) ) ) );
23932 /* ca_result is type U32 */
23933 ca_result = calculate_XER_CA_64( PPCG_FLAG_OP_ADD,
23934 mkexpr( result_low ),
23935 mkexpr( partial_sum_low ),
23936 unop( Iop_V128to64,
23937 mkexpr( vC ) ),
23938 mkU64( 0 ) );
23940 assign ( result_hi,
23941 binop( Iop_Add64,
23942 binop( Iop_Add64,
23943 mkexpr( partial_sum_hi ),
23944 unop( Iop_V128HIto64, mkexpr( vC ) ) ),
23945 binop( Iop_32HLto64, mkU32( 0 ), ca_result ) ) );
23947 putVReg( vD_addr, binop( Iop_64HLtoV128,
23948 mkexpr( result_hi ), mkexpr ( result_low ) ) );
23949 break;
23952 /* Multiply-Sum */
23953 case 0x24: { // vmsumubm (Multiply Sum Unsigned B Modulo, AV p204)
23954 IRTemp abEE, abEO, abOE, abOO;
23955 abEE = abEO = abOE = abOO = IRTemp_INVALID;
23956 DIP("vmsumubm v%d,v%d,v%d,v%d\n",
23957 vD_addr, vA_addr, vB_addr, vC_addr);
23959 /* multiply vA,vB (unsigned, widening) */
23960 assign( abEvn, MK_Iop_MullOdd8Ux16( mkexpr(vA), mkexpr(vB) ));
23961 assign( abOdd, binop(Iop_MullEven8Ux16, mkexpr(vA), mkexpr(vB)) );
23963 /* evn,odd: V128_16Ux8 -> 2 x V128_32Ux4, zero-extended */
23964 expand16Ux8( mkexpr(abEvn), &abEE, &abEO );
23965 expand16Ux8( mkexpr(abOdd), &abOE, &abOO );
23967 putVReg( vD_addr,
23968 binop(Iop_Add32x4, mkexpr(vC),
23969 binop(Iop_Add32x4,
23970 binop(Iop_Add32x4, mkexpr(abEE), mkexpr(abEO)),
23971 binop(Iop_Add32x4, mkexpr(abOE), mkexpr(abOO)))) );
23972 break;
23974 case 0x25: { // vmsummbm (Multiply Sum Mixed-Sign B Modulo, AV p201)
23975 IRTemp aEvn, aOdd, bEvn, bOdd;
23976 IRTemp abEE = newTemp(Ity_V128);
23977 IRTemp abEO = newTemp(Ity_V128);
23978 IRTemp abOE = newTemp(Ity_V128);
23979 IRTemp abOO = newTemp(Ity_V128);
23980 aEvn = aOdd = bEvn = bOdd = IRTemp_INVALID;
23981 DIP("vmsummbm v%d,v%d,v%d,v%d\n",
23982 vD_addr, vA_addr, vB_addr, vC_addr);
23984 /* sign-extend vA, zero-extend vB, for mixed-sign multiply
23985 (separating out adjacent lanes to different vectors) */
23986 expand8Sx16( mkexpr(vA), &aEvn, &aOdd );
23987 expand8Ux16( mkexpr(vB), &bEvn, &bOdd );
23989 /* multiply vA, vB, again separating adjacent lanes */
23990 assign( abEE, MK_Iop_MullOdd16Sx8( mkexpr(aEvn), mkexpr(bEvn) ));
23991 assign( abEO, binop(Iop_MullEven16Sx8, mkexpr(aEvn), mkexpr(bEvn)) );
23992 assign( abOE, MK_Iop_MullOdd16Sx8( mkexpr(aOdd), mkexpr(bOdd) ));
23993 assign( abOO, binop(Iop_MullEven16Sx8, mkexpr(aOdd), mkexpr(bOdd)) );
23995 /* add results together, + vC */
23996 putVReg( vD_addr,
23997 binop(Iop_QAdd32Sx4, mkexpr(vC),
23998 binop(Iop_QAdd32Sx4,
23999 binop(Iop_QAdd32Sx4, mkexpr(abEE), mkexpr(abEO)),
24000 binop(Iop_QAdd32Sx4, mkexpr(abOE), mkexpr(abOO)))) );
24001 break;
24003 case 0x26: { // vmsumuhm (Multiply Sum Unsigned HW Modulo, AV p205)
24004 DIP("vmsumuhm v%d,v%d,v%d,v%d\n",
24005 vD_addr, vA_addr, vB_addr, vC_addr);
24006 assign( abEvn, MK_Iop_MullOdd16Ux8( mkexpr(vA), mkexpr(vB) ));
24007 assign( abOdd, binop(Iop_MullEven16Ux8, mkexpr(vA), mkexpr(vB)) );
24008 putVReg( vD_addr,
24009 binop(Iop_Add32x4, mkexpr(vC),
24010 binop(Iop_Add32x4, mkexpr(abEvn), mkexpr(abOdd))) );
24011 break;
24013 case 0x27: { // vmsumuhs (Multiply Sum Unsigned HW Saturate, AV p206)
24014 DIP("vmsumuhs v%d,v%d,v%d,v%d\n",
24015 vD_addr, vA_addr, vB_addr, vC_addr);
24016 /* widening multiply, separating lanes */
24017 assign( abEvn, MK_Iop_MullOdd16Ux8(mkexpr(vA), mkexpr(vB) ));
24018 assign( abOdd, binop(Iop_MullEven16Ux8, mkexpr(vA), mkexpr(vB)) );
24020 /* break V128 to 4xI32's, zero-extending to I64's */
24021 breakV128to4x64U( mkexpr(abEvn), &ab7, &ab5, &ab3, &ab1 );
24022 breakV128to4x64U( mkexpr(abOdd), &ab6, &ab4, &ab2, &ab0 );
24023 breakV128to4x64U( mkexpr(vC), &c3, &c2, &c1, &c0 );
24025 /* add lanes */
24026 assign( z3, binop(Iop_Add64, mkexpr(c3),
24027 binop(Iop_Add64, mkexpr(ab7), mkexpr(ab6))));
24028 assign( z2, binop(Iop_Add64, mkexpr(c2),
24029 binop(Iop_Add64, mkexpr(ab5), mkexpr(ab4))));
24030 assign( z1, binop(Iop_Add64, mkexpr(c1),
24031 binop(Iop_Add64, mkexpr(ab3), mkexpr(ab2))));
24032 assign( z0, binop(Iop_Add64, mkexpr(c0),
24033 binop(Iop_Add64, mkexpr(ab1), mkexpr(ab0))));
24035 /* saturate-narrow to 32bit, and combine to V128 */
24036 putVReg( vD_addr, mkV128from4x64U( mkexpr(z3), mkexpr(z2),
24037 mkexpr(z1), mkexpr(z0)) );
24039 break;
24041 case 0x28: { // vmsumshm (Multiply Sum Signed HW Modulo, AV p202)
24042 DIP("vmsumshm v%d,v%d,v%d,v%d\n",
24043 vD_addr, vA_addr, vB_addr, vC_addr);
24044 assign( abEvn, MK_Iop_MullOdd16Sx8( mkexpr(vA), mkexpr(vB) ));
24045 assign( abOdd, binop(Iop_MullEven16Sx8, mkexpr(vA), mkexpr(vB)) );
24046 putVReg( vD_addr,
24047 binop(Iop_Add32x4, mkexpr(vC),
24048 binop(Iop_Add32x4, mkexpr(abOdd), mkexpr(abEvn))) );
24049 break;
24051 case 0x29: { // vmsumshs (Multiply Sum Signed HW Saturate, AV p203)
24052 DIP("vmsumshs v%d,v%d,v%d,v%d\n",
24053 vD_addr, vA_addr, vB_addr, vC_addr);
24054 /* widening multiply, separating lanes */
24055 assign( abEvn, MK_Iop_MullOdd16Sx8( mkexpr(vA), mkexpr(vB) ));
24056 assign( abOdd, binop(Iop_MullEven16Sx8, mkexpr(vA), mkexpr(vB)) );
24058 /* break V128 to 4xI32's, sign-extending to I64's */
24059 breakV128to4x64S( mkexpr(abEvn), &ab7, &ab5, &ab3, &ab1 );
24060 breakV128to4x64S( mkexpr(abOdd), &ab6, &ab4, &ab2, &ab0 );
24061 breakV128to4x64S( mkexpr(vC), &c3, &c2, &c1, &c0 );
24063 /* add lanes */
24064 assign( z3, binop(Iop_Add64, mkexpr(c3),
24065 binop(Iop_Add64, mkexpr(ab7), mkexpr(ab6))));
24066 assign( z2, binop(Iop_Add64, mkexpr(c2),
24067 binop(Iop_Add64, mkexpr(ab5), mkexpr(ab4))));
24068 assign( z1, binop(Iop_Add64, mkexpr(c1),
24069 binop(Iop_Add64, mkexpr(ab3), mkexpr(ab2))));
24070 assign( z0, binop(Iop_Add64, mkexpr(c0),
24071 binop(Iop_Add64, mkexpr(ab1), mkexpr(ab0))));
24073 /* saturate-narrow to 32bit, and combine to V128 */
24074 putVReg( vD_addr, mkV128from4x64S( mkexpr(z3), mkexpr(z2),
24075 mkexpr(z1), mkexpr(z0)) );
24076 break;
24078 default:
24079 vex_printf("dis_av_multarith(ppc)(opc2)\n");
24080 return False;
24082 return True;
24086 AltiVec Polynomial Multiply-Sum Instructions
24088 static Bool dis_av_polymultarith ( UInt theInstr )
24090 /* VA-Form */
24091 UChar opc1 = ifieldOPC(theInstr);
24092 UChar vD_addr = ifieldRegDS(theInstr);
24093 UChar vA_addr = ifieldRegA(theInstr);
24094 UChar vB_addr = ifieldRegB(theInstr);
24095 UChar vC_addr = ifieldRegC(theInstr);
24096 UInt opc2 = IFIELD(theInstr, 0, 11);
24097 IRTemp vA = newTemp(Ity_V128);
24098 IRTemp vB = newTemp(Ity_V128);
24099 IRTemp vC = newTemp(Ity_V128);
24101 assign( vA, getVReg(vA_addr));
24102 assign( vB, getVReg(vB_addr));
24103 assign( vC, getVReg(vC_addr));
24105 if (opc1 != 0x4) {
24106 vex_printf("dis_av_polymultarith(ppc)(instr)\n");
24107 return False;
24110 switch (opc2) {
24111 /* Polynomial Multiply-Add */
24112 case 0x408: // vpmsumb Vector Polynomial Multiply-sum Byte
24113 DIP("vpmsumb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24114 putVReg( vD_addr, binop(Iop_PolynomialMulAdd8x16,
24115 mkexpr(vA), mkexpr(vB)) );
24116 break;
24117 case 0x448: // vpmsumd Vector Polynomial Multiply-sum Double Word
24118 DIP("vpmsumd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24119 putVReg( vD_addr, binop(Iop_PolynomialMulAdd64x2,
24120 mkexpr(vA), mkexpr(vB)) );
24121 break;
24122 case 0x488: // vpmsumw Vector Polynomial Multiply-sum Word
24123 DIP("vpmsumw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24124 putVReg( vD_addr, binop(Iop_PolynomialMulAdd32x4,
24125 mkexpr(vA), mkexpr(vB)) );
24126 break;
24127 case 0x4C8: // vpmsumh Vector Polynomial Multiply-sum Half Word
24128 DIP("vpmsumh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24129 putVReg( vD_addr, binop(Iop_PolynomialMulAdd16x8,
24130 mkexpr(vA), mkexpr(vB)) );
24131 break;
24132 default:
24133 vex_printf("dis_av_polymultarith(ppc)(opc2=0x%x)\n", opc2);
24134 return False;
24136 return True;
24140 AltiVec Shift/Rotate Instructions
24142 static Bool dis_av_shift ( UInt theInstr )
24144 /* VX-Form */
24145 UChar opc1 = ifieldOPC(theInstr);
24146 UChar vD_addr = ifieldRegDS(theInstr);
24147 UChar vA_addr = ifieldRegA(theInstr);
24148 UChar vB_addr = ifieldRegB(theInstr);
24149 UInt opc2 = IFIELD( theInstr, 0, 11 );
24151 IRTemp vA = newTemp(Ity_V128);
24152 IRTemp vB = newTemp(Ity_V128);
24153 assign( vA, getVReg(vA_addr));
24154 assign( vB, getVReg(vB_addr));
24156 if (opc1 != 0x4){
24157 vex_printf("dis_av_shift(ppc)(instr)\n");
24158 return False;
24161 switch (opc2) {
24162 /* Rotate */
24163 case 0x004: // vrlb (Rotate Left Integer B, AV p234)
24164 DIP("vrlb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24165 putVReg( vD_addr, binop(Iop_Rol8x16, mkexpr(vA), mkexpr(vB)) );
24166 break;
24168 case 0x044: // vrlh (Rotate Left Integer HW, AV p235)
24169 DIP("vrlh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24170 putVReg( vD_addr, binop(Iop_Rol16x8, mkexpr(vA), mkexpr(vB)) );
24171 break;
24173 case 0x084: // vrlw (Rotate Left Integer W, AV p236)
24174 DIP("vrlw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24175 putVReg( vD_addr, binop(Iop_Rol32x4, mkexpr(vA), mkexpr(vB)) );
24176 break;
24178 case 0x0C4: // vrld (Rotate Left Integer Double Word)
24179 DIP("vrld v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24180 putVReg( vD_addr, binop(Iop_Rol64x2, mkexpr(vA), mkexpr(vB)) );
24181 break;
24184 /* Shift Left */
24185 case 0x104: // vslb (Shift Left Integer B, AV p240)
24186 DIP("vslb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24187 putVReg( vD_addr, binop(Iop_Shl8x16, mkexpr(vA), mkexpr(vB)) );
24188 break;
24190 case 0x144: // vslh (Shift Left Integer HW, AV p242)
24191 DIP("vslh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24192 putVReg( vD_addr, binop(Iop_Shl16x8, mkexpr(vA), mkexpr(vB)) );
24193 break;
24195 case 0x184: // vslw (Shift Left Integer W, AV p244)
24196 DIP("vslw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24197 putVReg( vD_addr, binop(Iop_Shl32x4, mkexpr(vA), mkexpr(vB)) );
24198 break;
24200 case 0x5C4: // vsld (Shift Left Integer Double Word)
24201 DIP("vsld v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24202 putVReg( vD_addr, binop(Iop_Shl64x2, mkexpr(vA), mkexpr(vB)) );
24203 break;
24205 case 0x1C4: { // vsl (Shift Left, AV p239)
24206 IRTemp sh = newTemp(Ity_I8);
24207 DIP("vsl v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24208 assign( sh, binop(Iop_And8, mkU8(0x7),
24209 unop(Iop_32to8,
24210 unop(Iop_V128to32, mkexpr(vB)))) );
24211 putVReg( vD_addr,
24212 binop(Iop_ShlV128, mkexpr(vA), mkexpr(sh)) );
24213 break;
24215 case 0x40C: { // vslo (Shift Left by Octet, AV p243)
24216 IRTemp sh = newTemp(Ity_I8);
24217 DIP("vslo v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24218 assign( sh, binop(Iop_And8, mkU8(0x78),
24219 unop(Iop_32to8,
24220 unop(Iop_V128to32, mkexpr(vB)))) );
24221 putVReg( vD_addr,
24222 binop(Iop_ShlV128, mkexpr(vA), mkexpr(sh)) );
24223 break;
24227 /* Shift Right */
24228 case 0x204: // vsrb (Shift Right B, AV p256)
24229 DIP("vsrb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24230 putVReg( vD_addr, binop(Iop_Shr8x16, mkexpr(vA), mkexpr(vB)) );
24231 break;
24233 case 0x244: // vsrh (Shift Right HW, AV p257)
24234 DIP("vsrh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24235 putVReg( vD_addr, binop(Iop_Shr16x8, mkexpr(vA), mkexpr(vB)) );
24236 break;
24238 case 0x284: // vsrw (Shift Right W, AV p259)
24239 DIP("vsrw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24240 putVReg( vD_addr, binop(Iop_Shr32x4, mkexpr(vA), mkexpr(vB)) );
24241 break;
24243 case 0x2C4: { // vsr (Shift Right, AV p251)
24244 IRTemp sh = newTemp(Ity_I8);
24245 DIP("vsr v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24246 assign( sh, binop(Iop_And8, mkU8(0x7),
24247 unop(Iop_32to8,
24248 unop(Iop_V128to32, mkexpr(vB)))) );
24249 putVReg( vD_addr,
24250 binop(Iop_ShrV128, mkexpr(vA), mkexpr(sh)) );
24251 break;
24253 case 0x304: // vsrab (Shift Right Alg B, AV p253)
24254 DIP("vsrab v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24255 putVReg( vD_addr, binop(Iop_Sar8x16, mkexpr(vA), mkexpr(vB)) );
24256 break;
24258 case 0x344: // vsrah (Shift Right Alg HW, AV p254)
24259 DIP("vsrah v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24260 putVReg( vD_addr, binop(Iop_Sar16x8, mkexpr(vA), mkexpr(vB)) );
24261 break;
24263 case 0x384: // vsraw (Shift Right Alg W, AV p255)
24264 DIP("vsraw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24265 putVReg( vD_addr, binop(Iop_Sar32x4, mkexpr(vA), mkexpr(vB)) );
24266 break;
24268 case 0x3C4: // vsrad (Shift Right Alg Double Word)
24269 DIP("vsrad v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24270 putVReg( vD_addr, binop(Iop_Sar64x2, mkexpr(vA), mkexpr(vB)) );
24271 break;
24273 case 0x44C: { // vsro (Shift Right by Octet, AV p258)
24274 IRTemp sh = newTemp(Ity_I8);
24275 DIP("vsro v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24276 assign( sh, binop(Iop_And8, mkU8(0x78),
24277 unop(Iop_32to8,
24278 unop(Iop_V128to32, mkexpr(vB)))) );
24279 putVReg( vD_addr,
24280 binop(Iop_ShrV128, mkexpr(vA), mkexpr(sh)) );
24281 break;
24284 case 0x6C4: // vsrd (Shift Right Double Word)
24285 DIP("vsrd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24286 putVReg( vD_addr, binop(Iop_Shr64x2, mkexpr(vA), mkexpr(vB)) );
24287 break;
24290 default:
24291 vex_printf("dis_av_shift(ppc)(opc2)\n");
24292 return False;
24294 return True;
24298 AltiVec Permute Instructions
24300 static Bool dis_av_permute ( UInt theInstr )
24302 /* VA-Form, VX-Form */
24303 UChar opc1 = ifieldOPC(theInstr);
24304 UChar vD_addr = ifieldRegDS(theInstr);
24305 UChar vA_addr = ifieldRegA(theInstr);
24306 UChar UIMM_5 = vA_addr;
24307 UChar vB_addr = ifieldRegB(theInstr);
24308 UChar vC_addr = ifieldRegC(theInstr);
24309 UChar b10 = ifieldBIT10(theInstr);
24310 UChar SHB_uimm4 = toUChar( IFIELD( theInstr, 6, 4 ) );
24311 UInt opc2 = toUChar( IFIELD( theInstr, 0, 6 ) );
24313 UChar SIMM_8 = extend_s_5to8(UIMM_5);
24315 IRTemp vA = newTemp(Ity_V128);
24316 IRTemp vB = newTemp(Ity_V128);
24317 IRTemp vC = newTemp(Ity_V128);
24318 assign( vA, getVReg(vA_addr));
24319 assign( vB, getVReg(vB_addr));
24320 assign( vC, getVReg(vC_addr));
24322 if (opc1 != 0x4) {
24323 vex_printf("dis_av_permute(ppc)(instr)\n");
24324 return False;
24327 switch (opc2) {
24328 case 0x2A: // vsel (Conditional Select, AV p238)
24329 DIP("vsel v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
24330 /* vD = (vA & ~vC) | (vB & vC) */
24331 putVReg( vD_addr, binop(Iop_OrV128,
24332 binop(Iop_AndV128, mkexpr(vA), unop(Iop_NotV128, mkexpr(vC))),
24333 binop(Iop_AndV128, mkexpr(vB), mkexpr(vC))) );
24334 return True;
24336 case 0x2B: { // vperm (Permute, AV p218)
24337 /* limited to two args for IR, so have to play games... */
24338 IRTemp a_perm = newTemp(Ity_V128);
24339 IRTemp b_perm = newTemp(Ity_V128);
24340 IRTemp mask = newTemp(Ity_V128);
24341 IRTemp vC_andF = newTemp(Ity_V128);
24342 DIP("vperm v%d,v%d,v%d,v%d\n",
24343 vD_addr, vA_addr, vB_addr, vC_addr);
24344 /* Limit the Perm8x16 steering values to 0 .. 15 as that is what
24345 IR specifies, and also to hide irrelevant bits from
24346 memcheck */
24347 assign( vC_andF,
24348 binop(Iop_AndV128, mkexpr(vC),
24349 unop(Iop_Dup8x16, mkU8(0xF))) );
24350 assign( a_perm,
24351 binop(Iop_Perm8x16, mkexpr(vA), mkexpr(vC_andF)) );
24352 assign( b_perm,
24353 binop(Iop_Perm8x16, mkexpr(vB), mkexpr(vC_andF)) );
24354 // mask[i8] = (vC[i8]_4 == 1) ? 0xFF : 0x0
24355 assign( mask, binop(Iop_SarN8x16,
24356 binop(Iop_ShlN8x16, mkexpr(vC), mkU8(3)),
24357 mkU8(7)) );
24358 // dst = (a & ~mask) | (b & mask)
24359 putVReg( vD_addr, binop(Iop_OrV128,
24360 binop(Iop_AndV128, mkexpr(a_perm),
24361 unop(Iop_NotV128, mkexpr(mask))),
24362 binop(Iop_AndV128, mkexpr(b_perm),
24363 mkexpr(mask))) );
24364 return True;
24366 case 0x2C: // vsldoi (Shift Left Double by Octet Imm, AV p241)
24367 if (b10 != 0) {
24368 vex_printf("dis_av_permute(ppc)(vsldoi)\n");
24369 return False;
24371 DIP("vsldoi v%d,v%d,v%d,%d\n",
24372 vD_addr, vA_addr, vB_addr, SHB_uimm4);
24373 if (SHB_uimm4 == 0)
24374 putVReg( vD_addr, mkexpr(vA) );
24375 else
24376 putVReg( vD_addr,
24377 binop(Iop_OrV128,
24378 binop(Iop_ShlV128, mkexpr(vA), mkU8(SHB_uimm4*8)),
24379 binop(Iop_ShrV128, mkexpr(vB), mkU8((16-SHB_uimm4)*8))) );
24380 return True;
24381 case 0x2D: { // vpermxor (Vector Permute and Exclusive-OR)
24382 IRTemp a_perm = newTemp(Ity_V128);
24383 IRTemp b_perm = newTemp(Ity_V128);
24384 IRTemp vrc_a = newTemp(Ity_V128);
24385 IRTemp vrc_b = newTemp(Ity_V128);
24387 DIP("vpermxor v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
24389 /* IBM index is 0:7, Change index value to index 7:0 */
24390 assign( vrc_b, binop( Iop_AndV128, mkexpr( vC ),
24391 unop( Iop_Dup8x16, mkU8( 0xF ) ) ) );
24392 assign( vrc_a, binop( Iop_ShrV128,
24393 binop( Iop_AndV128, mkexpr( vC ),
24394 unop( Iop_Dup8x16, mkU8( 0xF0 ) ) ),
24395 mkU8 ( 4 ) ) );
24396 assign( a_perm, binop( Iop_Perm8x16, mkexpr( vA ), mkexpr( vrc_a ) ) );
24397 assign( b_perm, binop( Iop_Perm8x16, mkexpr( vB ), mkexpr( vrc_b ) ) );
24398 putVReg( vD_addr, binop( Iop_XorV128,
24399 mkexpr( a_perm ), mkexpr( b_perm) ) );
24400 return True;
24403 case 0x3B: { // vpermr (Vector Permute Right-indexed)
24404 /* limited to two args for IR, so have to play games... */
24405 IRTemp a_perm = newTemp( Ity_V128 );
24406 IRTemp b_perm = newTemp( Ity_V128 );
24407 IRTemp mask = newTemp( Ity_V128 );
24408 IRTemp vC_andF = newTemp( Ity_V128 );
24409 IRTemp vC_adj = newTemp( Ity_V128 );
24411 DIP( "vpermr v%d,v%d,v%d,v%d\n",
24412 vD_addr, vA_addr, vB_addr, vC_addr);
24413 /* Limit the Perm8x16 steering values to 0 .. 15 as that is what
24414 IR specifies, and also to hide irrelevant bits from
24415 memcheck.
24418 assign( vC_adj,
24419 binop( Iop_Sub16x8,
24420 unop( Iop_Dup8x16, mkU8( 0x1F ) ),
24421 mkexpr( vC ) ) );
24422 assign( vC_andF,
24423 binop( Iop_AndV128, mkexpr( vC_adj),
24424 unop( Iop_Dup8x16, mkU8( 0xF ) ) ) );
24425 assign( a_perm,
24426 binop( Iop_Perm8x16, mkexpr( vA ), mkexpr( vC_andF ) ) );
24427 assign( b_perm,
24428 binop( Iop_Perm8x16, mkexpr( vB ), mkexpr( vC_andF ) ) );
24429 // mask[i8] = (vC[i8]_4 == 1) ? 0xFF : 0x0
24430 assign( mask, binop(Iop_SarN8x16,
24431 binop( Iop_ShlN8x16, mkexpr( vC_adj ),
24432 mkU8( 3 ) ), mkU8( 7 ) ) );
24433 // dst = (a & ~mask) | (b & mask)
24434 putVReg( vD_addr, binop( Iop_OrV128,
24435 binop( Iop_AndV128, mkexpr( a_perm ),
24436 unop( Iop_NotV128, mkexpr( mask ) ) ),
24437 binop( Iop_AndV128, mkexpr( b_perm ),
24438 mkexpr( mask ) ) ) );
24439 return True;
24442 default:
24443 break; // Fall through...
24446 opc2 = IFIELD( theInstr, 0, 11 );
24447 switch (opc2) {
24449 /* Merge */
24450 case 0x00C: // vmrghb (Merge High B, AV p195)
24451 DIP("vmrghb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24452 putVReg( vD_addr,
24453 binop(Iop_InterleaveHI8x16, mkexpr(vA), mkexpr(vB)) );
24454 break;
24456 case 0x04C: // vmrghh (Merge High HW, AV p196)
24457 DIP("vmrghh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24458 putVReg( vD_addr,
24459 binop(Iop_InterleaveHI16x8, mkexpr(vA), mkexpr(vB)) );
24460 break;
24462 case 0x08C: // vmrghw (Merge High W, AV p197)
24463 DIP("vmrghw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24464 putVReg( vD_addr,
24465 binop(Iop_InterleaveHI32x4, mkexpr(vA), mkexpr(vB)) );
24466 break;
24468 case 0x10C: // vmrglb (Merge Low B, AV p198)
24469 DIP("vmrglb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24470 putVReg( vD_addr,
24471 binop(Iop_InterleaveLO8x16, mkexpr(vA), mkexpr(vB)) );
24472 break;
24474 case 0x14C: // vmrglh (Merge Low HW, AV p199)
24475 DIP("vmrglh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24476 putVReg( vD_addr,
24477 binop(Iop_InterleaveLO16x8, mkexpr(vA), mkexpr(vB)) );
24478 break;
24480 case 0x18C: // vmrglw (Merge Low W, AV p200)
24481 DIP("vmrglw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24482 putVReg( vD_addr,
24483 binop(Iop_InterleaveLO32x4, mkexpr(vA), mkexpr(vB)) );
24484 break;
24486 /* Extract instructions */
24487 case 0x20D: // vextractub (Vector Extract Unsigned Byte)
24489 UChar uim = IFIELD( theInstr, 16, 4 );
24491 DIP("vextractub v%d,v%d,%d\n", vD_addr, vB_addr, uim);
24493 putVReg( vD_addr, binop( Iop_ShlV128,
24494 binop( Iop_AndV128,
24495 binop( Iop_ShrV128,
24496 mkexpr( vB ),
24497 unop( Iop_32to8,
24498 binop( Iop_Mul32,
24499 mkU32( 8 ),
24500 mkU32( 31 - uim ) ) ) ),
24501 binop( Iop_64HLtoV128,
24502 mkU64( 0x0ULL ),
24503 mkU64( 0xFFULL ) ) ),
24504 mkU8( 64 ) ) );
24506 break;
24508 case 0x24D: // vextractuh (Vector Extract Unsigned Halfword)
24510 UChar uim = IFIELD( theInstr, 16, 4 );
24512 DIP("vextractuh v%d,v%d,%d\n", vD_addr, vB_addr, uim);
24514 putVReg( vD_addr, binop( Iop_ShlV128,
24515 binop( Iop_AndV128,
24516 binop( Iop_ShrV128,
24517 mkexpr( vB ),
24518 unop( Iop_32to8,
24519 binop( Iop_Mul32,
24520 mkU32( 8 ),
24521 mkU32( 30 - uim ) ) ) ),
24522 binop( Iop_64HLtoV128,
24523 mkU64( 0x0ULL ),
24524 mkU64( 0xFFFFULL ) ) ),
24525 mkU8( 64 ) ) );
24527 break;
24529 case 0x28D: // vextractuw (Vector Extract Unsigned Word)
24531 UChar uim = IFIELD( theInstr, 16, 4 );
24533 DIP("vextractuw v%d,v%d,%d\n", vD_addr, vB_addr, uim);
24535 putVReg( vD_addr,
24536 binop( Iop_ShlV128,
24537 binop( Iop_AndV128,
24538 binop( Iop_ShrV128,
24539 mkexpr( vB ),
24540 unop( Iop_32to8,
24541 binop( Iop_Mul32,
24542 mkU32( 8 ),
24543 mkU32( 28 - uim ) ) ) ),
24544 binop( Iop_64HLtoV128,
24545 mkU64( 0x0ULL ),
24546 mkU64( 0xFFFFFFFFULL ) ) ),
24547 mkU8( 64 ) ) );
24549 break;
24551 case 0x2CD: // vextractd (Vector Extract Double Word)
24553 UChar uim = IFIELD( theInstr, 16, 4 );
24555 DIP("vextractd v%d,v%d,%d\n", vD_addr, vB_addr, uim);
24557 putVReg( vD_addr,
24558 binop( Iop_ShlV128,
24559 binop( Iop_AndV128,
24560 binop( Iop_ShrV128,
24561 mkexpr( vB ),
24562 unop( Iop_32to8,
24563 binop( Iop_Mul32,
24564 mkU32( 8 ),
24565 mkU32( 24 - uim ) ) ) ),
24566 binop( Iop_64HLtoV128,
24567 mkU64( 0x0ULL ),
24568 mkU64( 0xFFFFFFFFFFFFFFFFULL ) ) ),
24569 mkU8( 64 ) ) );
24571 break;
24573 /* Insert instructions */
24574 case 0x30D: // vinsertb (Vector insert Unsigned Byte)
24576 UChar uim = IFIELD( theInstr, 16, 4 );
24577 IRTemp shift = newTemp( Ity_I8 );
24578 IRTemp vD = newTemp( Ity_V128 );
24580 DIP("vinsertb v%d,v%d,%d\n", vD_addr, vB_addr, uim);
24582 assign( vD, getVReg( vD_addr ) );
24584 assign( shift, unop( Iop_32to8,
24585 binop( Iop_Mul32,
24586 mkU32( 8 ),
24587 mkU32( 15 - ( uim + 0 ) ) ) ) );
24589 putVReg( vD_addr,
24590 binop( Iop_OrV128,
24591 binop( Iop_ShlV128,
24592 binop( Iop_AndV128,
24593 binop( Iop_ShrV128,
24594 mkexpr( vB ),
24595 mkU8( ( 15 - 7 )*8 ) ),
24596 binop( Iop_64HLtoV128,
24597 mkU64( 0x0ULL ),
24598 mkU64( 0xFFULL ) ) ),
24599 mkexpr( shift ) ),
24600 binop( Iop_AndV128,
24601 unop( Iop_NotV128,
24602 binop( Iop_ShlV128,
24603 binop( Iop_64HLtoV128,
24604 mkU64( 0x0ULL ),
24605 mkU64( 0xFFULL ) ),
24606 mkexpr( shift ) ) ),
24607 mkexpr( vD ) ) ) );
24609 break;
24611 case 0x34D: // vinserth (Vector insert Halfword)
24613 UChar uim = IFIELD( theInstr, 16, 4 );
24614 IRTemp shift = newTemp( Ity_I8 );
24615 IRTemp vD = newTemp( Ity_V128 );
24617 DIP("vinserth v%d,v%d,%d\n", vD_addr, vB_addr, uim);
24619 assign( vD, getVReg( vD_addr ) );
24621 assign( shift, unop( Iop_32to8,
24622 binop( Iop_Mul32,
24623 mkU32( 8 ),
24624 mkU32( 15 - ( uim + 1 ) ) ) ) );
24626 putVReg( vD_addr,
24627 binop( Iop_OrV128,
24628 binop( Iop_ShlV128,
24629 binop( Iop_AndV128,
24630 binop( Iop_ShrV128,
24631 mkexpr( vB ),
24632 mkU8( (7 - 3)*16 ) ),
24633 binop( Iop_64HLtoV128,
24634 mkU64( 0x0ULL ),
24635 mkU64( 0xFFFFULL ) ) ),
24636 mkexpr( shift ) ),
24637 binop( Iop_AndV128,
24638 unop( Iop_NotV128,
24639 binop( Iop_ShlV128,
24640 binop( Iop_64HLtoV128,
24641 mkU64( 0x0ULL ),
24642 mkU64( 0xFFFFULL ) ),
24643 mkexpr( shift ) ) ),
24644 mkexpr( vD ) ) ) );
24646 break;
24648 case 0x38D: // vinsertw (Vector insert Word)
24650 UChar uim = IFIELD( theInstr, 16, 4 );
24651 IRTemp shift = newTemp( Ity_I8 );
24652 IRTemp vD = newTemp( Ity_V128 );
24654 DIP("vinsertw v%d,v%d,%d\n", vD_addr, vB_addr, uim);
24656 assign( vD, getVReg( vD_addr ) );
24658 assign( shift, unop( Iop_32to8,
24659 binop( Iop_Mul32,
24660 mkU32( 8 ),
24661 mkU32( 15 - ( uim + 3 ) ) ) ) );
24663 putVReg( vD_addr,
24664 binop( Iop_OrV128,
24665 binop( Iop_ShlV128,
24666 binop( Iop_AndV128,
24667 binop( Iop_ShrV128,
24668 mkexpr( vB ),
24669 mkU8( (3 - 1) * 32 ) ),
24670 binop( Iop_64HLtoV128,
24671 mkU64( 0x0ULL ),
24672 mkU64( 0xFFFFFFFFULL ) ) ),
24673 mkexpr( shift ) ),
24674 binop( Iop_AndV128,
24675 unop( Iop_NotV128,
24676 binop( Iop_ShlV128,
24677 binop( Iop_64HLtoV128,
24678 mkU64( 0x0ULL ),
24679 mkU64( 0xFFFFFFFFULL ) ),
24680 mkexpr( shift ) ) ),
24681 mkexpr( vD ) ) ) );
24683 break;
24685 case 0x3CD: // vinsertd (Vector insert Doubleword)
24687 UChar uim = IFIELD( theInstr, 16, 4 );
24688 IRTemp shift = newTemp( Ity_I8 );
24689 IRTemp vD = newTemp( Ity_V128 );
24691 DIP("vinsertd v%d,v%d,%d\n", vD_addr, vB_addr, uim);
24693 assign( vD, getVReg( vD_addr ) );
24695 assign( shift, unop( Iop_32to8,
24696 binop( Iop_Mul32,
24697 mkU32( 8 ),
24698 mkU32( 15 - ( uim + 7 ) ) ) ) );
24700 putVReg( vD_addr,
24701 binop( Iop_OrV128,
24702 binop( Iop_ShlV128,
24703 binop( Iop_AndV128,
24704 binop( Iop_ShrV128,
24705 mkexpr( vB ),
24706 mkU8( ( 1 - 0 ) * 64 ) ),
24707 binop( Iop_64HLtoV128,
24708 mkU64( 0x0ULL ),
24709 mkU64( 0xFFFFFFFFFFFFFFFFULL ) ) ),
24710 mkexpr( shift ) ),
24711 binop( Iop_AndV128,
24712 unop( Iop_NotV128,
24713 binop( Iop_ShlV128,
24714 binop( Iop_64HLtoV128,
24715 mkU64( 0x0ULL ),
24716 mkU64( 0xFFFFFFFFFFFFFFFFULL ) ),
24717 mkexpr( shift ) ) ),
24718 mkexpr( vD ) ) ) );
24720 break;
24722 /* Splat */
24723 case 0x20C: { // vspltb (Splat Byte, AV p245)
24724 /* vD = Dup8x16( vB[UIMM_5] ) */
24725 UChar sh_uimm = (15 - (UIMM_5 & 15)) * 8;
24726 DIP("vspltb v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
24727 putVReg( vD_addr, unop(Iop_Dup8x16,
24728 unop(Iop_32to8, unop(Iop_V128to32,
24729 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm))))) );
24730 break;
24732 case 0x24C: { // vsplth (Splat Half Word, AV p246)
24733 UChar sh_uimm = (7 - (UIMM_5 & 7)) * 16;
24734 DIP("vsplth v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
24735 putVReg( vD_addr, unop(Iop_Dup16x8,
24736 unop(Iop_32to16, unop(Iop_V128to32,
24737 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm))))) );
24738 break;
24740 case 0x28C: { // vspltw (Splat Word, AV p250)
24741 /* vD = Dup32x4( vB[UIMM_5] ) */
24742 UChar sh_uimm = (3 - (UIMM_5 & 3)) * 32;
24743 DIP("vspltw v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
24744 putVReg( vD_addr, unop(Iop_Dup32x4,
24745 unop(Iop_V128to32,
24746 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm)))) );
24747 break;
24749 case 0x30C: // vspltisb (Splat Immediate Signed B, AV p247)
24750 DIP("vspltisb v%d,%d\n", vD_addr, (Char)SIMM_8);
24751 putVReg( vD_addr, unop(Iop_Dup8x16, mkU8(SIMM_8)) );
24752 break;
24754 case 0x34C: // vspltish (Splat Immediate Signed HW, AV p248)
24755 DIP("vspltish v%d,%d\n", vD_addr, (Char)SIMM_8);
24756 putVReg( vD_addr,
24757 unop(Iop_Dup16x8, mkU16(extend_s_8to32(SIMM_8))) );
24758 break;
24760 case 0x38C: // vspltisw (Splat Immediate Signed W, AV p249)
24761 DIP("vspltisw v%d,%d\n", vD_addr, (Char)SIMM_8);
24762 putVReg( vD_addr,
24763 unop(Iop_Dup32x4, mkU32(extend_s_8to32(SIMM_8))) );
24764 break;
24766 case 0x68C: // vmrgow (Merge Odd Word)
24767 DIP("vmrgow v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24768 /* VD[0] <- VA[1]
24769 VD[1] <- VB[1]
24770 VD[2] <- VA[3]
24771 VD[3] <- VB[3]
24773 putVReg( vD_addr,
24774 binop(Iop_CatOddLanes32x4, mkexpr(vA), mkexpr(vB) ) );
24775 break;
24777 case 0x78C: // vmrgew (Merge Even Word)
24778 DIP("vmrgew v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24779 /* VD[0] <- VA[0]
24780 VD[1] <- VB[0]
24781 VD[2] <- VA[2]
24782 VD[3] <- VB[2]
24784 putVReg( vD_addr,
24785 binop(Iop_CatEvenLanes32x4, mkexpr(vA), mkexpr(vB) ) );
24786 break;
24788 default:
24789 vex_printf("dis_av_permute(ppc)(opc2)\n");
24790 return False;
24792 return True;
24796 Vector Integer Absolute Difference
24798 static Bool dis_abs_diff ( UInt theInstr )
24800 /* VX-Form */
24801 UChar opc1 = ifieldOPC( theInstr );
24802 UChar vT_addr = ifieldRegDS( theInstr );
24803 UChar vA_addr = ifieldRegA( theInstr );
24804 UChar vB_addr = ifieldRegB( theInstr );
24805 UInt opc2 = IFIELD( theInstr, 0, 11 );
24807 IRTemp vA = newTemp( Ity_V128 );
24808 IRTemp vB = newTemp( Ity_V128 );
24809 IRTemp vT = newTemp( Ity_V128 );
24811 IRTemp vAminusB = newTemp( Ity_V128 );
24812 IRTemp vBminusA = newTemp( Ity_V128 );
24813 IRTemp vMask = newTemp( Ity_V128 );
24815 assign( vA, getVReg( vA_addr ) );
24816 assign( vB, getVReg( vB_addr ) );
24818 if ( opc1 != 0x4 ) {
24819 vex_printf("dis_abs_diff(ppc)(instr)\n");
24820 return False;
24823 switch ( opc2 ) {
24824 case 0x403: // vabsdub Vector absolute difference Unsigned Byte
24826 DIP("vabsdub v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
24828 /* Determine which of the corresponding bytes is larger,
24829 * create mask with 1's in byte positions where vA[i] > vB[i]
24831 assign( vMask, binop( Iop_CmpGT8Ux16, mkexpr( vA ), mkexpr( vB ) ) );
24833 assign( vAminusB,
24834 binop( Iop_AndV128,
24835 binop( Iop_Sub8x16, mkexpr( vA ), mkexpr( vB ) ),
24836 mkexpr( vMask ) ) );
24838 assign( vBminusA,
24839 binop( Iop_AndV128,
24840 binop( Iop_Sub8x16, mkexpr( vB ), mkexpr( vA ) ),
24841 unop ( Iop_NotV128, mkexpr( vMask ) ) ) );
24843 assign( vT, binop( Iop_OrV128,
24844 mkexpr( vAminusB ),
24845 mkexpr( vBminusA ) ) );
24847 break;
24849 case 0x443: // vabsduh Vector absolute difference Unsigned Halfword
24851 DIP("vabsduh v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
24853 /* Determine which of the corresponding halfwords is larger,
24854 * create mask with 1's in halfword positions where vA[i] > vB[i]
24856 assign( vMask, binop( Iop_CmpGT16Ux8, mkexpr( vA ), mkexpr( vB ) ) );
24858 assign( vAminusB,
24859 binop( Iop_AndV128,
24860 binop( Iop_Sub16x8, mkexpr( vA ), mkexpr( vB ) ),
24861 mkexpr( vMask ) ) );
24863 assign( vBminusA,
24864 binop( Iop_AndV128,
24865 binop( Iop_Sub16x8, mkexpr( vB ), mkexpr( vA ) ),
24866 unop ( Iop_NotV128, mkexpr( vMask ) ) ) );
24868 assign( vT, binop( Iop_OrV128,
24869 mkexpr( vAminusB ),
24870 mkexpr( vBminusA ) ) );
24872 break;
24874 case 0x483: // vabsduw Vector absolute difference Unsigned Word
24876 DIP("vabsduw v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
24878 /* Determine which of the corresponding words is larger,
24879 * create mask with 1's in word positions where vA[i] > vB[i]
24881 assign( vMask, binop( Iop_CmpGT32Ux4, mkexpr( vA ), mkexpr( vB ) ) );
24883 assign( vAminusB,
24884 binop( Iop_AndV128,
24885 binop( Iop_Sub32x4, mkexpr( vA ), mkexpr( vB ) ),
24886 mkexpr( vMask ) ) );
24888 assign( vBminusA,
24889 binop( Iop_AndV128,
24890 binop( Iop_Sub32x4, mkexpr( vB ), mkexpr( vA ) ),
24891 unop ( Iop_NotV128, mkexpr( vMask ) ) ) );
24893 assign( vT, binop( Iop_OrV128,
24894 mkexpr( vAminusB ),
24895 mkexpr( vBminusA ) ) );
24897 break;
24899 default:
24900 return False;
24903 putVReg( vT_addr, mkexpr( vT ) );
24905 return True;
24909 AltiVec 128 bit integer multiply by 10 Instructions
24911 static Bool dis_av_mult10 ( UInt theInstr )
24913 /* VX-Form */
24914 UChar opc1 = ifieldOPC(theInstr);
24915 UChar vT_addr = ifieldRegDS(theInstr);
24916 UChar vA_addr = ifieldRegA(theInstr);
24917 UChar vB_addr = ifieldRegB(theInstr);
24918 UInt opc2 = IFIELD( theInstr, 0, 11 );
24920 IRTemp vA = newTemp(Ity_V128);
24921 assign( vA, getVReg(vA_addr));
24923 if (opc1 != 0x4) {
24924 vex_printf("dis_av_mult10(ppc)(instr)\n");
24925 return False;
24927 switch (opc2) {
24928 case 0x001: { // vmul10cuq (Vector Multiply-by-10 and write carry
24929 DIP("vmul10cuq v%d,v%d\n", vT_addr, vA_addr);
24930 putVReg( vT_addr,
24931 unop( Iop_MulI128by10Carry, mkexpr( vA ) ) );
24932 break;
24934 case 0x041: { // vmul10uq (Vector Multiply-by-10 Extended and write carry
24935 // Unsigned Quadword VX form)
24936 IRTemp vB = newTemp(Ity_V128);
24937 assign( vB, getVReg(vB_addr));
24938 DIP("vmul10ecuq v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
24939 putVReg( vT_addr,
24940 binop( Iop_MulI128by10ECarry, mkexpr( vA ), mkexpr( vB ) ) );
24941 break;
24943 case 0x201: { // vmul10uq (Vector Multiply-by-10 Unsigned Quadword VX form)
24944 DIP("vmul10uq v%d,v%d\n", vT_addr, vA_addr);
24945 putVReg( vT_addr,
24946 unop( Iop_MulI128by10, mkexpr( vA ) ) );
24947 break;
24949 case 0x241: { // vmul10uq (Vector Multiply-by-10 Extended
24950 // Unsigned Quadword VX form)
24951 IRTemp vB = newTemp(Ity_V128);
24952 assign( vB, getVReg(vB_addr));
24953 DIP("vmul10euq v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
24954 putVReg( vT_addr,
24955 binop( Iop_MulI128by10E, mkexpr( vA ), mkexpr( vB ) ) );
24956 break;
24958 default:
24959 vex_printf("dis_av_mult10(ppc)(opc2)\n");
24960 return False;
24962 return True;
24966 AltiVec Pack/Unpack Instructions
24968 static Bool dis_av_pack ( UInt theInstr )
24970 /* VX-Form */
24971 UChar opc1 = ifieldOPC(theInstr);
24972 UChar vD_addr = ifieldRegDS(theInstr);
24973 UChar vA_addr = ifieldRegA(theInstr);
24974 UChar vB_addr = ifieldRegB(theInstr);
24975 UInt opc2 = IFIELD( theInstr, 0, 11 );
24977 IRTemp signs = IRTemp_INVALID;
24978 IRTemp zeros = IRTemp_INVALID;
24979 IRTemp vA = newTemp(Ity_V128);
24980 IRTemp vB = newTemp(Ity_V128);
24981 assign( vA, getVReg(vA_addr));
24982 assign( vB, getVReg(vB_addr));
24984 if (opc1 != 0x4) {
24985 vex_printf("dis_av_pack(ppc)(instr)\n");
24986 return False;
24988 switch (opc2) {
24989 /* Packing */
24990 case 0x00E: // vpkuhum (Pack Unsigned HW Unsigned Modulo, AV p224)
24991 DIP("vpkuhum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24992 putVReg( vD_addr,
24993 binop(Iop_NarrowBin16to8x16, mkexpr(vA), mkexpr(vB)) );
24994 return True;
24996 case 0x04E: // vpkuwum (Pack Unsigned W Unsigned Modulo, AV p226)
24997 DIP("vpkuwum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
24998 putVReg( vD_addr,
24999 binop(Iop_NarrowBin32to16x8, mkexpr(vA), mkexpr(vB)) );
25000 return True;
25002 case 0x08E: // vpkuhus (Pack Unsigned HW Unsigned Saturate, AV p225)
25003 DIP("vpkuhus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25004 putVReg( vD_addr,
25005 binop(Iop_QNarrowBin16Uto8Ux16, mkexpr(vA), mkexpr(vB)) );
25006 // TODO: set VSCR[SAT]
25007 return True;
25009 case 0x0CE: // vpkuwus (Pack Unsigned W Unsigned Saturate, AV p227)
25010 DIP("vpkuwus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25011 putVReg( vD_addr,
25012 binop(Iop_QNarrowBin32Uto16Ux8, mkexpr(vA), mkexpr(vB)) );
25013 // TODO: set VSCR[SAT]
25014 return True;
25016 case 0x10E: { // vpkshus (Pack Signed HW Unsigned Saturate, AV p221)
25017 // This insn does a signed->unsigned saturating conversion.
25018 // Conversion done here, then uses unsigned->unsigned vpk insn:
25019 // => UnsignedSaturatingNarrow( x & ~ (x >>s 15) )
25020 IRTemp vA_tmp = newTemp(Ity_V128);
25021 IRTemp vB_tmp = newTemp(Ity_V128);
25022 DIP("vpkshus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25023 assign( vA_tmp, binop(Iop_AndV128, mkexpr(vA),
25024 unop(Iop_NotV128,
25025 binop(Iop_SarN16x8,
25026 mkexpr(vA), mkU8(15)))) );
25027 assign( vB_tmp, binop(Iop_AndV128, mkexpr(vB),
25028 unop(Iop_NotV128,
25029 binop(Iop_SarN16x8,
25030 mkexpr(vB), mkU8(15)))) );
25031 putVReg( vD_addr, binop(Iop_QNarrowBin16Uto8Ux16,
25032 mkexpr(vA_tmp), mkexpr(vB_tmp)) );
25033 // TODO: set VSCR[SAT]
25034 return True;
25036 case 0x14E: { // vpkswus (Pack Signed W Unsigned Saturate, AV p223)
25037 // This insn does a signed->unsigned saturating conversion.
25038 // Conversion done here, then uses unsigned->unsigned vpk insn:
25039 // => UnsignedSaturatingNarrow( x & ~ (x >>s 31) )
25040 IRTemp vA_tmp = newTemp(Ity_V128);
25041 IRTemp vB_tmp = newTemp(Ity_V128);
25042 DIP("vpkswus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25043 assign( vA_tmp, binop(Iop_AndV128, mkexpr(vA),
25044 unop(Iop_NotV128,
25045 binop(Iop_SarN32x4,
25046 mkexpr(vA), mkU8(31)))) );
25047 assign( vB_tmp, binop(Iop_AndV128, mkexpr(vB),
25048 unop(Iop_NotV128,
25049 binop(Iop_SarN32x4,
25050 mkexpr(vB), mkU8(31)))) );
25051 putVReg( vD_addr, binop(Iop_QNarrowBin32Uto16Ux8,
25052 mkexpr(vA_tmp), mkexpr(vB_tmp)) );
25053 // TODO: set VSCR[SAT]
25054 return True;
25056 case 0x18E: // vpkshss (Pack Signed HW Signed Saturate, AV p220)
25057 DIP("vpkshss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25058 putVReg( vD_addr,
25059 binop(Iop_QNarrowBin16Sto8Sx16, mkexpr(vA), mkexpr(vB)) );
25060 // TODO: set VSCR[SAT]
25061 return True;
25063 case 0x1CE: // vpkswss (Pack Signed W Signed Saturate, AV p222)
25064 DIP("vpkswss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25065 putVReg( vD_addr,
25066 binop(Iop_QNarrowBin32Sto16Sx8, mkexpr(vA), mkexpr(vB)) );
25067 // TODO: set VSCR[SAT]
25068 return True;
25070 case 0x30E: { // vpkpx (Pack Pixel, AV p219)
25071 /* CAB: Worth a new primop? */
25072 /* Using shifts to compact pixel elements, then packing them */
25073 IRTemp a1 = newTemp(Ity_V128);
25074 IRTemp a2 = newTemp(Ity_V128);
25075 IRTemp a3 = newTemp(Ity_V128);
25076 IRTemp a_tmp = newTemp(Ity_V128);
25077 IRTemp b1 = newTemp(Ity_V128);
25078 IRTemp b2 = newTemp(Ity_V128);
25079 IRTemp b3 = newTemp(Ity_V128);
25080 IRTemp b_tmp = newTemp(Ity_V128);
25081 DIP("vpkpx v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25082 assign( a1, binop(Iop_ShlN16x8,
25083 binop(Iop_ShrN32x4, mkexpr(vA), mkU8(19)),
25084 mkU8(10)) );
25085 assign( a2, binop(Iop_ShlN16x8,
25086 binop(Iop_ShrN16x8, mkexpr(vA), mkU8(11)),
25087 mkU8(5)) );
25088 assign( a3, binop(Iop_ShrN16x8,
25089 binop(Iop_ShlN16x8, mkexpr(vA), mkU8(8)),
25090 mkU8(11)) );
25091 assign( a_tmp, binop(Iop_OrV128, mkexpr(a1),
25092 binop(Iop_OrV128, mkexpr(a2), mkexpr(a3))) );
25094 assign( b1, binop(Iop_ShlN16x8,
25095 binop(Iop_ShrN32x4, mkexpr(vB), mkU8(19)),
25096 mkU8(10)) );
25097 assign( b2, binop(Iop_ShlN16x8,
25098 binop(Iop_ShrN16x8, mkexpr(vB), mkU8(11)),
25099 mkU8(5)) );
25100 assign( b3, binop(Iop_ShrN16x8,
25101 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(8)),
25102 mkU8(11)) );
25103 assign( b_tmp, binop(Iop_OrV128, mkexpr(b1),
25104 binop(Iop_OrV128, mkexpr(b2), mkexpr(b3))) );
25106 putVReg( vD_addr, binop(Iop_NarrowBin32to16x8,
25107 mkexpr(a_tmp), mkexpr(b_tmp)) );
25108 return True;
25111 case 0x44E: // vpkudum (Pack Unsigned Double Word Unsigned Modulo)
25112 DIP("vpkudum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25113 putVReg( vD_addr,
25114 binop(Iop_NarrowBin64to32x4, mkexpr(vA), mkexpr(vB)) );
25115 return True;
25117 case 0x4CE: // vpkudus (Pack Unsigned Double Word Unsigned Saturate)
25118 DIP("vpkudus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25119 putVReg( vD_addr,
25120 binop(Iop_QNarrowBin64Uto32Ux4, mkexpr(vA), mkexpr(vB)) );
25121 // TODO: set VSCR[SAT]
25122 return True;
25124 case 0x54E: { // vpksdus (Pack Signed Double Word Unsigned Saturate)
25125 // This insn does a doubled signed->double unsigned saturating conversion
25126 // Conversion done here, then uses unsigned->unsigned vpk insn:
25127 // => UnsignedSaturatingNarrow( x & ~ (x >>s 31) )
25128 // This is similar to the technique used for vpkswus, except done
25129 // with double word integers versus word integers.
25130 IRTemp vA_tmp = newTemp(Ity_V128);
25131 IRTemp vB_tmp = newTemp(Ity_V128);
25132 DIP("vpksdus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25133 assign( vA_tmp, binop(Iop_AndV128, mkexpr(vA),
25134 unop(Iop_NotV128,
25135 binop(Iop_SarN64x2,
25136 mkexpr(vA), mkU8(63)))) );
25137 assign( vB_tmp, binop(Iop_AndV128, mkexpr(vB),
25138 unop(Iop_NotV128,
25139 binop(Iop_SarN64x2,
25140 mkexpr(vB), mkU8(63)))) );
25141 putVReg( vD_addr, binop(Iop_QNarrowBin64Uto32Ux4,
25142 mkexpr(vA_tmp), mkexpr(vB_tmp)) );
25143 // TODO: set VSCR[SAT]
25144 return True;
25147 case 0x5CE: // vpksdss (Pack Signed double word Signed Saturate)
25148 DIP("vpksdss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25149 putVReg( vD_addr,
25150 binop(Iop_QNarrowBin64Sto32Sx4, mkexpr(vA), mkexpr(vB)) );
25151 // TODO: set VSCR[SAT]
25152 return True;
25153 default:
25154 break; // Fall through...
25158 if (vA_addr != 0) {
25159 vex_printf("dis_av_pack(ppc)(vA_addr)\n");
25160 return False;
25163 signs = newTemp(Ity_V128);
25164 zeros = newTemp(Ity_V128);
25165 assign( zeros, unop(Iop_Dup32x4, mkU32(0)) );
25167 switch (opc2) {
25168 /* Unpacking */
25169 case 0x20E: { // vupkhsb (Unpack High Signed B, AV p277)
25170 DIP("vupkhsb v%d,v%d\n", vD_addr, vB_addr);
25171 assign( signs, binop(Iop_CmpGT8Sx16, mkexpr(zeros), mkexpr(vB)) );
25172 putVReg( vD_addr,
25173 binop(Iop_InterleaveHI8x16, mkexpr(signs), mkexpr(vB)) );
25174 break;
25176 case 0x24E: { // vupkhsh (Unpack High Signed HW, AV p278)
25177 DIP("vupkhsh v%d,v%d\n", vD_addr, vB_addr);
25178 assign( signs, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vB)) );
25179 putVReg( vD_addr,
25180 binop(Iop_InterleaveHI16x8, mkexpr(signs), mkexpr(vB)) );
25181 break;
25183 case 0x28E: { // vupklsb (Unpack Low Signed B, AV p280)
25184 DIP("vupklsb v%d,v%d\n", vD_addr, vB_addr);
25185 assign( signs, binop(Iop_CmpGT8Sx16, mkexpr(zeros), mkexpr(vB)) );
25186 putVReg( vD_addr,
25187 binop(Iop_InterleaveLO8x16, mkexpr(signs), mkexpr(vB)) );
25188 break;
25190 case 0x2CE: { // vupklsh (Unpack Low Signed HW, AV p281)
25191 DIP("vupklsh v%d,v%d\n", vD_addr, vB_addr);
25192 assign( signs, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vB)) );
25193 putVReg( vD_addr,
25194 binop(Iop_InterleaveLO16x8, mkexpr(signs), mkexpr(vB)) );
25195 break;
25197 case 0x34E: { // vupkhpx (Unpack High Pixel16, AV p276)
25198 /* CAB: Worth a new primop? */
25199 /* Using shifts to isolate pixel elements, then expanding them */
25200 IRTemp z0 = newTemp(Ity_V128);
25201 IRTemp z1 = newTemp(Ity_V128);
25202 IRTemp z01 = newTemp(Ity_V128);
25203 IRTemp z2 = newTemp(Ity_V128);
25204 IRTemp z3 = newTemp(Ity_V128);
25205 IRTemp z23 = newTemp(Ity_V128);
25206 DIP("vupkhpx v%d,v%d\n", vD_addr, vB_addr);
25207 assign( z0, binop(Iop_ShlN16x8,
25208 binop(Iop_SarN16x8, mkexpr(vB), mkU8(15)),
25209 mkU8(8)) );
25210 assign( z1, binop(Iop_ShrN16x8,
25211 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(1)),
25212 mkU8(11)) );
25213 assign( z01, binop(Iop_InterleaveHI16x8, mkexpr(zeros),
25214 binop(Iop_OrV128, mkexpr(z0), mkexpr(z1))) );
25215 assign( z2, binop(Iop_ShrN16x8,
25216 binop(Iop_ShlN16x8,
25217 binop(Iop_ShrN16x8, mkexpr(vB), mkU8(5)),
25218 mkU8(11)),
25219 mkU8(3)) );
25220 assign( z3, binop(Iop_ShrN16x8,
25221 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(11)),
25222 mkU8(11)) );
25223 assign( z23, binop(Iop_InterleaveHI16x8, mkexpr(zeros),
25224 binop(Iop_OrV128, mkexpr(z2), mkexpr(z3))) );
25225 putVReg( vD_addr,
25226 binop(Iop_OrV128,
25227 binop(Iop_ShlN32x4, mkexpr(z01), mkU8(16)),
25228 mkexpr(z23)) );
25229 break;
25231 case 0x3CE: { // vupklpx (Unpack Low Pixel16, AV p279)
25232 /* identical to vupkhpx, except interleaving LO */
25233 IRTemp z0 = newTemp(Ity_V128);
25234 IRTemp z1 = newTemp(Ity_V128);
25235 IRTemp z01 = newTemp(Ity_V128);
25236 IRTemp z2 = newTemp(Ity_V128);
25237 IRTemp z3 = newTemp(Ity_V128);
25238 IRTemp z23 = newTemp(Ity_V128);
25239 DIP("vupklpx v%d,v%d\n", vD_addr, vB_addr);
25240 assign( z0, binop(Iop_ShlN16x8,
25241 binop(Iop_SarN16x8, mkexpr(vB), mkU8(15)),
25242 mkU8(8)) );
25243 assign( z1, binop(Iop_ShrN16x8,
25244 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(1)),
25245 mkU8(11)) );
25246 assign( z01, binop(Iop_InterleaveLO16x8, mkexpr(zeros),
25247 binop(Iop_OrV128, mkexpr(z0), mkexpr(z1))) );
25248 assign( z2, binop(Iop_ShrN16x8,
25249 binop(Iop_ShlN16x8,
25250 binop(Iop_ShrN16x8, mkexpr(vB), mkU8(5)),
25251 mkU8(11)),
25252 mkU8(3)) );
25253 assign( z3, binop(Iop_ShrN16x8,
25254 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(11)),
25255 mkU8(11)) );
25256 assign( z23, binop(Iop_InterleaveLO16x8, mkexpr(zeros),
25257 binop(Iop_OrV128, mkexpr(z2), mkexpr(z3))) );
25258 putVReg( vD_addr,
25259 binop(Iop_OrV128,
25260 binop(Iop_ShlN32x4, mkexpr(z01), mkU8(16)),
25261 mkexpr(z23)) );
25262 break;
25264 case 0x64E: { // vupkhsw (Unpack High Signed Word)
25265 DIP("vupkhsw v%d,v%d\n", vD_addr, vB_addr);
25266 assign( signs, binop(Iop_CmpGT32Sx4, mkexpr(zeros), mkexpr(vB)) );
25267 putVReg( vD_addr,
25268 binop(Iop_InterleaveHI32x4, mkexpr(signs), mkexpr(vB)) );
25269 break;
25271 case 0x6CE: { // vupklsw (Unpack Low Signed Word)
25272 DIP("vupklsw v%d,v%d\n", vD_addr, vB_addr);
25273 assign( signs, binop(Iop_CmpGT32Sx4, mkexpr(zeros), mkexpr(vB)) );
25274 putVReg( vD_addr,
25275 binop(Iop_InterleaveLO32x4, mkexpr(signs), mkexpr(vB)) );
25276 break;
25278 default:
25279 vex_printf("dis_av_pack(ppc)(opc2)\n");
25280 return False;
25282 return True;
25286 AltiVec Cipher Instructions
25288 static Bool dis_av_cipher ( UInt theInstr )
25290 /* VX-Form */
25291 UChar opc1 = ifieldOPC(theInstr);
25292 UChar vD_addr = ifieldRegDS(theInstr);
25293 UChar vA_addr = ifieldRegA(theInstr);
25294 UChar vB_addr = ifieldRegB(theInstr);
25295 UInt opc2 = IFIELD( theInstr, 0, 11 );
25297 IRTemp vA = newTemp(Ity_V128);
25298 IRTemp vB = newTemp(Ity_V128);
25299 assign( vA, getVReg(vA_addr));
25300 assign( vB, getVReg(vB_addr));
25302 if (opc1 != 0x4) {
25303 vex_printf("dis_av_cipher(ppc)(instr)\n");
25304 return False;
25306 switch (opc2) {
25307 case 0x508: // vcipher (Vector Inverser Cipher)
25308 DIP("vcipher v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25309 putVReg( vD_addr,
25310 binop(Iop_CipherV128, mkexpr(vA), mkexpr(vB)) );
25311 return True;
25313 case 0x509: // vcipherlast (Vector Inverser Cipher Last)
25314 DIP("vcipherlast v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25315 putVReg( vD_addr,
25316 binop(Iop_CipherLV128, mkexpr(vA), mkexpr(vB)) );
25317 return True;
25319 case 0x548: // vncipher (Vector Inverser Cipher)
25320 DIP("vncipher v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25321 putVReg( vD_addr,
25322 binop(Iop_NCipherV128, mkexpr(vA), mkexpr(vB)) );
25323 return True;
25325 case 0x549: // vncipherlast (Vector Inverser Cipher Last)
25326 DIP("vncipherlast v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
25327 putVReg( vD_addr,
25328 binop(Iop_NCipherLV128, mkexpr(vA), mkexpr(vB)) );
25329 return True;
25331 case 0x5C8: /* vsbox (Vector SubBytes, this does the cipher
25332 * subBytes transform)
25334 DIP("vsbox v%d,v%d\n", vD_addr, vA_addr);
25335 putVReg( vD_addr,
25336 unop(Iop_CipherSV128, mkexpr(vA) ) );
25337 return True;
25339 default:
25340 vex_printf("dis_av_cipher(ppc)(opc2)\n");
25341 return False;
25343 return True;
25347 AltiVec Secure Hash Instructions
25349 static Bool dis_av_hash ( UInt theInstr )
25351 /* VX-Form */
25352 UChar opc1 = ifieldOPC(theInstr);
25353 UChar vRT_addr = ifieldRegDS(theInstr);
25354 UChar vRA_addr = ifieldRegA(theInstr);
25355 UChar s_field = IFIELD( theInstr, 11, 5 ); // st and six field
25356 UChar st = IFIELD( theInstr, 15, 1 ); // st
25357 UChar six = IFIELD( theInstr, 11, 4 ); // six field
25358 UInt opc2 = IFIELD( theInstr, 0, 11 );
25360 IRTemp vA = newTemp(Ity_V128);
25361 IRTemp dst = newTemp(Ity_V128);
25362 assign( vA, getVReg(vRA_addr));
25364 if (opc1 != 0x4) {
25365 vex_printf("dis_av_hash(ppc)(instr)\n");
25366 return False;
25369 switch (opc2) {
25370 case 0x682: // vshasigmaw
25371 DIP("vshasigmaw v%d,v%d,%u,%u\n", vRT_addr, vRA_addr, st, six);
25372 assign( dst, binop( Iop_SHA256, mkexpr( vA ), mkU8( s_field) ) );
25373 putVReg( vRT_addr, mkexpr(dst));
25374 return True;
25376 case 0x6C2: // vshasigmad,
25377 DIP("vshasigmad v%d,v%d,%u,%u\n", vRT_addr, vRA_addr, st, six);
25378 putVReg( vRT_addr, binop( Iop_SHA512, mkexpr( vA ), mkU8( s_field) ) );
25379 return True;
25381 default:
25382 vex_printf("dis_av_hash(ppc)(opc2)\n");
25383 return False;
25385 return True;
25389 * This function is used by the Vector add/subtract [extended] modulo/carry
25390 * instructions.
25391 * - For the non-extended add instructions, the cin arg is set to zero.
25392 * - For the extended add instructions, cin is the integer value of
25393 * src3.bit[127].
25394 * - For the non-extended subtract instructions, src1 is added to the one's
25395 * complement of src2 + 1. We re-use the cin argument to hold the '1'
25396 * value for this operation.
25397 * - For the extended subtract instructions, cin is the integer value of src3.bit[127].
25399 static IRTemp _get_quad_modulo_or_carry(IRExpr * vecA, IRExpr * vecB,
25400 IRExpr * cin, Bool modulo)
25402 IRTemp _vecA_32 = IRTemp_INVALID;
25403 IRTemp _vecB_32 = IRTemp_INVALID;
25404 IRTemp res_32 = IRTemp_INVALID;
25405 IRTemp res_64 = IRTemp_INVALID;
25406 IRTemp result = IRTemp_INVALID;
25407 IRTemp tmp_result = IRTemp_INVALID;
25408 IRTemp carry = IRTemp_INVALID;
25409 Int i;
25410 IRExpr * _vecA_low64 = unop( Iop_V128to64, vecA );
25411 IRExpr * _vecB_low64 = unop( Iop_V128to64, vecB );
25412 IRExpr * _vecA_high64 = unop( Iop_V128HIto64, vecA );
25413 IRExpr * _vecB_high64 = unop( Iop_V128HIto64, vecB );
25415 carry = newTemp(Ity_I32);
25416 assign( carry, cin );
25418 for (i = 0; i < 4; i++) {
25419 _vecA_32 = newTemp(Ity_I32);
25420 _vecB_32 = newTemp(Ity_I32);
25421 res_32 = newTemp(Ity_I32);
25422 res_64 = newTemp(Ity_I64);
25424 switch (i) {
25425 case 0:
25426 assign(_vecA_32, unop( Iop_64to32, _vecA_low64 ) );
25427 assign(_vecB_32, unop( Iop_64to32, _vecB_low64 ) );
25428 break;
25429 case 1:
25430 assign(_vecA_32, unop( Iop_64HIto32, _vecA_low64 ) );
25431 assign(_vecB_32, unop( Iop_64HIto32, _vecB_low64 ) );
25432 break;
25433 case 2:
25434 assign(_vecA_32, unop( Iop_64to32, _vecA_high64 ) );
25435 assign(_vecB_32, unop( Iop_64to32, _vecB_high64 ) );
25436 break;
25437 case 3:
25438 assign(_vecA_32, unop( Iop_64HIto32, _vecA_high64 ) );
25439 assign(_vecB_32, unop( Iop_64HIto32, _vecB_high64 ) );
25440 break;
25443 assign( res_64, binop( Iop_Add64,
25444 binop ( Iop_Add64,
25445 binop( Iop_32HLto64,
25446 mkU32( 0 ),
25447 mkexpr(_vecA_32) ),
25448 binop( Iop_32HLto64,
25449 mkU32( 0 ),
25450 mkexpr(_vecB_32) ) ),
25451 binop( Iop_32HLto64,
25452 mkU32( 0 ),
25453 mkexpr( carry ) ) ) );
25455 /* Calculate the carry to the next higher 32 bits. */
25456 carry = newTemp(Ity_I32);
25457 assign(carry, unop( Iop_64HIto32, mkexpr( res_64 ) ) );
25459 /* result is the lower 32-bits */
25460 assign(res_32, unop( Iop_64to32, mkexpr( res_64 ) ) );
25462 if (modulo) {
25463 result = newTemp(Ity_V128);
25464 assign(result, binop( Iop_OrV128,
25465 (i == 0) ? binop( Iop_64HLtoV128,
25466 mkU64(0),
25467 mkU64(0) ) : mkexpr(tmp_result),
25468 binop( Iop_ShlV128,
25469 binop( Iop_64HLtoV128,
25470 mkU64(0),
25471 binop( Iop_32HLto64,
25472 mkU32(0),
25473 mkexpr(res_32) ) ),
25474 mkU8(i * 32) ) ) );
25475 tmp_result = newTemp(Ity_V128);
25476 assign(tmp_result, mkexpr(result));
25479 if (modulo)
25480 return result;
25481 else
25482 return carry;
25486 static Bool dis_av_quad ( UInt theInstr )
25488 /* VX-Form */
25489 UChar opc1 = ifieldOPC(theInstr);
25490 UChar vRT_addr = ifieldRegDS(theInstr);
25491 UChar vRA_addr = ifieldRegA(theInstr);
25492 UChar vRB_addr = ifieldRegB(theInstr);
25493 UChar vRC_addr;
25494 UInt opc2 = IFIELD( theInstr, 0, 11 );
25496 IRTemp vA = newTemp(Ity_V128);
25497 IRTemp vB = newTemp(Ity_V128);
25498 IRTemp vC = IRTemp_INVALID;
25499 IRTemp cin = IRTemp_INVALID;
25500 assign( vA, getVReg(vRA_addr));
25501 assign( vB, getVReg(vRB_addr));
25503 if (opc1 != 0x4) {
25504 vex_printf("dis_av_quad(ppc)(instr)\n");
25505 return False;
25508 switch (opc2) {
25509 case 0x140: // vaddcuq
25510 DIP("vaddcuq v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
25511 putVReg( vRT_addr, unop( Iop_32UtoV128,
25512 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
25513 mkexpr(vB),
25514 mkU32(0), False) ) ) );
25515 return True;
25516 case 0x100: // vadduqm
25517 DIP("vadduqm v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
25518 putVReg( vRT_addr, mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
25519 mkexpr(vB), mkU32(0), True) ) );
25520 return True;
25521 case 0x540: // vsubcuq
25522 DIP("vsubcuq v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
25523 putVReg( vRT_addr,
25524 unop( Iop_32UtoV128,
25525 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
25526 unop( Iop_NotV128,
25527 mkexpr(vB) ),
25528 mkU32(1), False) ) ) );
25529 return True;
25530 case 0x500: // vsubuqm
25531 DIP("vsubuqm v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
25532 putVReg( vRT_addr,
25533 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
25534 unop( Iop_NotV128, mkexpr(vB) ),
25535 mkU32(1), True) ) );
25536 return True;
25537 case 0x054C: // vbpermq
25539 #define BPERMD_IDX_MASK 0x00000000000000FFULL
25540 #define BPERMD_BIT_MASK 0x8000000000000000ULL
25541 int i;
25542 IRExpr * vB_expr = mkexpr(vB);
25543 IRExpr * res = binop(Iop_AndV128, mkV128(0), mkV128(0));
25544 DIP("vbpermq v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
25545 for (i = 0; i < 16; i++) {
25546 IRTemp idx_tmp = newTemp( Ity_V128 );
25547 IRTemp perm_bit = newTemp( Ity_V128 );
25548 IRTemp idx = newTemp( Ity_I8 );
25549 IRTemp idx_LT127 = newTemp( Ity_I1 );
25550 IRTemp idx_LT127_ity128 = newTemp( Ity_V128 );
25552 assign( idx_tmp,
25553 binop( Iop_AndV128,
25554 binop( Iop_64HLtoV128,
25555 mkU64(0),
25556 mkU64(BPERMD_IDX_MASK) ),
25557 vB_expr ) );
25558 assign( idx_LT127,
25559 binop( Iop_CmpEQ32,
25560 unop ( Iop_64to32,
25561 unop( Iop_V128to64, binop( Iop_ShrV128,
25562 mkexpr(idx_tmp),
25563 mkU8(7) ) ) ),
25564 mkU32(0) ) );
25566 /* Below, we set idx to determine which bit of vA to use for the
25567 * perm bit. If idx_LT127 is 0, the perm bit is forced to '0'.
25569 assign( idx,
25570 binop( Iop_And8,
25571 unop( Iop_1Sto8,
25572 mkexpr(idx_LT127) ),
25573 unop( Iop_32to8,
25574 unop( Iop_V128to32, mkexpr( idx_tmp ) ) ) ) );
25576 assign( idx_LT127_ity128,
25577 binop( Iop_64HLtoV128,
25578 mkU64(0),
25579 unop( Iop_32Uto64,
25580 unop( Iop_1Uto32, mkexpr(idx_LT127 ) ) ) ) );
25581 assign( perm_bit,
25582 binop( Iop_AndV128,
25583 mkexpr( idx_LT127_ity128 ),
25584 binop( Iop_ShrV128,
25585 binop( Iop_AndV128,
25586 binop (Iop_64HLtoV128,
25587 mkU64( BPERMD_BIT_MASK ),
25588 mkU64(0)),
25589 binop( Iop_ShlV128,
25590 mkexpr( vA ),
25591 mkexpr( idx ) ) ),
25592 mkU8( 127 ) ) ) );
25593 res = binop( Iop_OrV128,
25594 res,
25595 binop( Iop_ShlV128,
25596 mkexpr( perm_bit ),
25597 mkU8( i + 64 ) ) );
25598 vB_expr = binop( Iop_ShrV128, vB_expr, mkU8( 8 ) );
25600 putVReg( vRT_addr, res);
25601 return True;
25602 #undef BPERMD_IDX_MASK
25603 #undef BPERMD_BIT_MASK
25606 default:
25607 break; // fall through
25610 opc2 = IFIELD( theInstr, 0, 6 );
25611 vRC_addr = ifieldRegC(theInstr);
25612 vC = newTemp(Ity_V128);
25613 cin = newTemp(Ity_I32);
25614 switch (opc2) {
25615 case 0x3D: // vaddecuq
25616 assign( vC, getVReg(vRC_addr));
25617 DIP("vaddecuq v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
25618 vRC_addr);
25619 assign(cin, binop( Iop_And32,
25620 unop( Iop_64to32,
25621 unop( Iop_V128to64, mkexpr(vC) ) ),
25622 mkU32(1) ) );
25623 putVReg( vRT_addr,
25624 unop( Iop_32UtoV128,
25625 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA), mkexpr(vB),
25626 mkexpr(cin),
25627 False) ) ) );
25628 return True;
25629 case 0x3C: // vaddeuqm
25630 assign( vC, getVReg(vRC_addr));
25631 DIP("vaddeuqm v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
25632 vRC_addr);
25633 assign(cin, binop( Iop_And32,
25634 unop( Iop_64to32,
25635 unop( Iop_V128to64, mkexpr(vC) ) ),
25636 mkU32(1) ) );
25637 putVReg( vRT_addr,
25638 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA), mkexpr(vB),
25639 mkexpr(cin),
25640 True) ) );
25641 return True;
25642 case 0x3F: // vsubecuq
25643 assign( vC, getVReg(vRC_addr));
25644 DIP("vsubecuq v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
25645 vRC_addr);
25646 assign(cin, binop( Iop_And32,
25647 unop( Iop_64to32,
25648 unop( Iop_V128to64, mkexpr(vC) ) ),
25649 mkU32(1) ) );
25650 putVReg( vRT_addr,
25651 unop( Iop_32UtoV128,
25652 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
25653 unop( Iop_NotV128,
25654 mkexpr(vB) ),
25655 mkexpr(cin),
25656 False) ) ) );
25657 return True;
25658 case 0x3E: // vsubeuqm
25659 assign( vC, getVReg(vRC_addr));
25660 DIP("vsubeuqm v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
25661 vRC_addr);
25662 assign(cin, binop( Iop_And32,
25663 unop( Iop_64to32,
25664 unop( Iop_V128to64, mkexpr(vC) ) ),
25665 mkU32(1) ) );
25666 putVReg( vRT_addr,
25667 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
25668 unop( Iop_NotV128, mkexpr(vB) ),
25669 mkexpr(cin),
25670 True) ) );
25671 return True;
25672 default:
25673 vex_printf("dis_av_quad(ppc)(opc2.2)\n");
25674 return False;
25677 return True;
25680 static IRExpr * bcd_sign_code_adjust( UInt ps, IRExpr * tmp)
25682 /* The Iop_BCDAdd and Iop_BCDSub will result in the corresponding Power PC
25683 * instruction being issued with ps = 0. If ps = 1, the sign code, which
25684 * is in the least significant four bits of the result, needs to be updated
25685 * per the ISA:
25687 * If PS=0, the sign code of the result is set to 0b1100.
25688 * If PS=1, the sign code of the result is set to 0b1111.
25690 * Note, the ps value is NOT being passed down to the instruction issue
25691 * because passing a constant via triop() breaks the vbit-test test. The
25692 * vbit-tester assumes it can set non-zero shadow bits for the triop()
25693 * arguments. Thus they have to be expressions not a constant.
25694 * Use 32-bit compare instructiions as 64-bit compares are not supported
25695 * in 32-bit mode.
25697 IRTemp mask = newTemp(Ity_I64);
25698 IRExpr *rtn;
25700 if ( ps == 0 ) {
25701 /* sign code is correct, just return it. */
25702 rtn = tmp;
25704 } else {
25705 /* Check if lower four bits are 0b1100, if so, change to 0b1111 */
25706 /* Make this work in 32-bit mode using only 32-bit compares */
25707 assign( mask, unop( Iop_1Sto64,
25708 binop( Iop_CmpEQ32, mkU32( 0xC ),
25709 binop( Iop_And32, mkU32( 0xF ),
25710 unop( Iop_64to32,
25711 unop( Iop_V128to64, tmp )
25712 ) ) ) ) );
25713 rtn = binop( Iop_64HLtoV128,
25714 unop( Iop_V128HIto64, tmp ),
25715 binop( Iop_Or64,
25716 binop( Iop_And64, mkU64( 0xF ), mkexpr( mask ) ),
25717 unop( Iop_V128to64, tmp ) ) );
25720 return rtn;
25724 AltiVec BCD Arithmetic instructions.
25725 These instructions modify CR6 for various conditions in the result,
25726 including when an overflow occurs. We could easily detect all conditions
25727 except when an overflow occurs. But since we can't be 100% accurate
25728 in our emulation of CR6, it seems best to just not support it all.
25730 static Bool dis_av_bcd_misc ( UInt theInstr, const VexAbiInfo* vbi )
25732 UChar opc1 = ifieldOPC(theInstr);
25733 UChar vRT_addr = ifieldRegDS(theInstr);
25734 UChar vRA_addr = ifieldRegA(theInstr);
25735 UChar vRB_addr = ifieldRegB(theInstr);
25736 IRTemp vA = newTemp(Ity_V128);
25737 IRTemp vB = newTemp(Ity_V128);
25738 UInt opc2 = IFIELD( theInstr, 0, 11 );
25739 IRExpr *pos, *neg, *valid, *zero, *sign;
25740 IRTemp eq_lt_gt = newTemp( Ity_I32 );
25742 assign( vA, getVReg(vRA_addr));
25743 assign( vB, getVReg(vRB_addr));
25745 if (opc1 != 0x4) {
25746 vex_printf("dis_av_bcd_misc(ppc)(instr)\n");
25747 return False;
25750 switch (opc2) {
25751 case 0x341: // bcdcpsgn. Decimal Copy Sign VX-form
25753 IRExpr *sign_vb, *value_va;
25754 DIP("bcdcpsgn. v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
25756 zero =
25757 BCDstring_zero( binop( Iop_AndV128,
25758 binop( Iop_64HLtoV128,
25759 mkU64( 0xFFFFFFFFFFFFFFFF ),
25760 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
25761 mkexpr( vA ) ) );
25763 /* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
25764 * codes 0xB and 0xD are negative.
25766 sign = binop( Iop_And64, mkU64( 0xF ),
25767 unop( Iop_V128to64, mkexpr( vB ) ) );
25769 neg = mkOR1( binop( Iop_CmpEQ64,
25770 sign,
25771 mkU64 ( 0xB ) ),
25772 binop( Iop_CmpEQ64,
25773 sign,
25774 mkU64 ( 0xD ) ) );
25776 pos = mkNOT1( neg );
25778 /* invalid if vA or vB is not valid */
25779 valid =
25780 unop( Iop_64to32,
25781 binop( Iop_And64,
25782 is_BCDstring128( vbi,
25783 /*Signed*/True, mkexpr( vA ) ),
25784 is_BCDstring128( vbi,
25785 /*Signed*/True, mkexpr( vB ) ) ) );
25787 sign_vb = binop( Iop_AndV128,
25788 binop( Iop_64HLtoV128,
25789 mkU64( 0 ),
25790 mkU64( 0xF ) ),
25791 mkexpr( vB ) );
25793 value_va = binop( Iop_AndV128,
25794 binop( Iop_64HLtoV128,
25795 mkU64( 0xFFFFFFFFFFFFFFFF ),
25796 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
25797 mkexpr( vA ) );
25798 putVReg( vRT_addr, binop( Iop_OrV128, sign_vb, value_va ) );
25800 break;
25802 default:
25803 vex_printf("dis_av_bcd_misc(ppc)(opc2)\n");
25804 return False;
25807 /* set CR field 6 to:
25808 * 0b1000 if vB less then 0, i.e. vB is neg and not zero,
25809 * 0b0100 if vB greter then 0, i.e. vB is pos and not zero,
25810 * 0b1000 if vB equals 0,
25811 * 0b0001 if vB is invalid over rules lt, gt, eq
25813 assign( eq_lt_gt,
25814 binop( Iop_Or32,
25815 binop( Iop_Shl32,
25816 unop( Iop_1Uto32,
25817 mkAND1( neg,
25818 mkNOT1( zero ) ) ),
25819 mkU8( 3 ) ),
25820 binop( Iop_Or32,
25821 binop( Iop_Shl32,
25822 unop( Iop_1Uto32,
25823 mkAND1( pos,
25824 mkNOT1( zero ) ) ),
25825 mkU8( 2 ) ),
25826 binop( Iop_Shl32,
25827 unop( Iop_1Uto32, zero ),
25828 mkU8( 1 ) ) ) ) );
25830 IRTemp valid_mask = newTemp( Ity_I32 );
25832 assign( valid_mask, unop( Iop_1Sto32, unop( Iop_32to1, valid ) ) );
25834 putGST_field( PPC_GST_CR,
25835 binop( Iop_Or32,
25836 binop( Iop_And32,
25837 mkexpr( valid_mask ),
25838 mkexpr( eq_lt_gt ) ),
25839 binop( Iop_And32,
25840 unop( Iop_Not32, mkexpr( valid_mask ) ),
25841 mkU32( 1 ) ) ),
25842 6 );
25843 return True;
25846 static Bool dis_av_bcd ( UInt theInstr, const VexAbiInfo* vbi )
25848 /* VX-Form */
25849 UChar opc1 = ifieldOPC(theInstr);
25850 UChar vRT_addr = ifieldRegDS(theInstr);
25851 UChar vRA_addr = ifieldRegA(theInstr);
25852 UChar vRB_addr = ifieldRegB(theInstr);
25853 UChar ps = IFIELD( theInstr, 9, 1 );
25854 UInt opc2 = IFIELD( theInstr, 0, 9 );
25855 IRTemp vA = newTemp(Ity_V128);
25856 IRTemp vB = newTemp(Ity_V128);
25857 IRTemp dst = newTemp(Ity_V128);
25858 IRExpr *pos, *neg, *valid, *zero, *sign_digit, *in_range;
25859 IRTemp eq_lt_gt = newTemp( Ity_I32 );
25860 IRExpr *overflow, *value;
25862 assign( vA, getVReg(vRA_addr));
25863 assign( vB, getVReg(vRB_addr));
25865 if (opc1 != 0x4) {
25866 vex_printf("dis_av_bcd(ppc)(instr)\n");
25867 return False;
25870 switch (opc2) {
25871 case 0x1: // bcdadd.
25872 case 0x41: // bcdsub.
25874 /* NOTE 64 bit compares are not supported in 32-bit mode. Use
25875 * 32-bit compares only.
25878 IRExpr *sign, *res_smaller;
25879 IRExpr *signA, *signB, *sign_digitA, *sign_digitB;
25880 IRExpr *zeroA, *zeroB, *posA, *posB, *negA, *negB;
25882 if ( opc2 == 0x1 ) {
25883 DIP("bcdadd. v%d,v%d,v%d,%u\n", vRT_addr, vRA_addr, vRB_addr, ps);
25884 assign( dst, bcd_sign_code_adjust( ps,
25885 binop( Iop_BCDAdd,
25886 mkexpr( vA ),
25887 mkexpr( vB ) ) ) );
25888 } else {
25889 DIP("bcdsub. v%d,v%d,v%d,%u\n", vRT_addr, vRA_addr, vRB_addr, ps);
25890 assign( dst, bcd_sign_code_adjust( ps,
25891 binop( Iop_BCDSub,
25892 mkexpr( vA ),
25893 mkexpr( vB ) ) ) );
25896 putVReg( vRT_addr, mkexpr( dst ) );
25897 /* set CR field 6 */
25898 /* result */
25899 zero = BCDstring_zero( binop( Iop_AndV128,
25900 binop( Iop_64HLtoV128,
25901 mkU64( 0xFFFFFFFFFFFFFFFF ),
25902 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
25903 mkexpr(dst) ) ); // ignore sign
25905 sign_digit = binop( Iop_And32, mkU32( 0xF ),
25906 unop( Iop_64to32,
25907 unop( Iop_V128to64, mkexpr( dst ) ) ) );
25909 sign = mkOR1( binop( Iop_CmpEQ32,
25910 sign_digit,
25911 mkU32 ( 0xB ) ),
25912 binop( Iop_CmpEQ32,
25913 sign_digit,
25914 mkU32 ( 0xD ) ) );
25915 neg = mkAND1( sign, mkNOT1( zero ) );
25917 /* Pos position AKA gt = 1 if ((not neg) & (not eq zero)) */
25918 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
25919 valid = unop( Iop_64to32,
25920 binop( Iop_And64,
25921 is_BCDstring128( vbi,
25922 /*Signed*/True, mkexpr( vA ) ),
25923 is_BCDstring128( vbi,
25924 /*Signed*/True, mkexpr( vB ) )
25925 ) );
25927 /* src A */
25928 zeroA = BCDstring_zero( binop( Iop_AndV128,
25929 binop( Iop_64HLtoV128,
25930 mkU64( 0xFFFFFFFFFFFFFFFF ),
25931 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
25932 mkexpr( vA ) ) ); // ignore sign
25933 sign_digitA = binop( Iop_And32, mkU32( 0xF ),
25934 unop( Iop_64to32,
25935 unop( Iop_V128to64, mkexpr( vA ) ) ) );
25937 signA = mkOR1( binop( Iop_CmpEQ32,
25938 sign_digitA,
25939 mkU32 ( 0xB ) ),
25940 binop( Iop_CmpEQ32,
25941 sign_digitA,
25942 mkU32 ( 0xD ) ) );
25943 negA = mkAND1( signA, mkNOT1( zeroA ) );
25944 /* Pos position AKA gt = 1 if ((not neg) & (not eq zero)) */
25945 posA = mkAND1( mkNOT1( signA ), mkNOT1( zeroA ) );
25947 /* src B */
25948 zeroB = BCDstring_zero( binop( Iop_AndV128,
25949 binop( Iop_64HLtoV128,
25950 mkU64( 0xFFFFFFFFFFFFFFFF ),
25951 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
25952 mkexpr( vB ) ) ); // ignore sign
25953 sign_digitB = binop( Iop_And32, mkU32( 0xF ),
25954 unop( Iop_64to32,
25955 unop( Iop_V128to64, mkexpr( vB ) ) ) );
25957 signB = mkOR1( binop( Iop_CmpEQ32,
25958 sign_digitB,
25959 mkU32 ( 0xB ) ),
25960 binop( Iop_CmpEQ32,
25961 sign_digitB,
25962 mkU32 ( 0xD ) ) );
25963 negB = mkAND1( signB, mkNOT1( zeroB ) );
25966 /* Pos position AKA gt = 1 if ((not neg) & (not eq zero)) */
25967 posB = mkAND1( mkNOT1( signB ), mkNOT1( zeroB ) );
25970 if (mode64) {
25971 res_smaller = mkAND1( CmpGT128U( mkexpr( vA ), mkexpr( dst ) ),
25972 CmpGT128U( mkexpr( vB ), mkexpr( dst ) ) );
25974 } else {
25975 /* Have to do this with 32-bit compares, expensive */
25976 res_smaller = mkAND1( UNSIGNED_CMP_GT_V128( mkexpr( vA ),
25977 mkexpr( dst ) ),
25978 UNSIGNED_CMP_GT_V128( mkexpr( vB ),
25979 mkexpr( dst ) ) );
25982 if ( opc2 == 0x1) {
25983 /* Overflow for Add can only occur if the signs of the operands
25984 * are the same and the two operands are non-zero. On overflow,
25985 * the PPC hardware produces a result consisting of just the lower
25986 * digits of the result. So, if the result is less then both
25987 * operands and the sign of the operands are the same overflow
25988 * occured.
25990 overflow = mkOR1( mkAND1( res_smaller, mkAND1( negA, negB ) ),
25991 mkAND1( res_smaller, mkAND1( posA, posB ) ) );
25992 } else {
25993 /* Overflow for Add can only occur if the signs of the operands
25994 * are the different and the two operands are non-zero. On overflow,
25995 * the PPC hardware produces a result consisting of just the lower
25996 * digits of the result. So, if the result is less then both
25997 * operands and the sign of the operands are different overflow
25998 * occured.
26000 overflow = mkOR1( mkAND1( res_smaller, mkAND1( negA, posB ) ),
26001 mkAND1( res_smaller, mkAND1( posA, negB ) ) );
26004 break;
26006 case 0x081: // bcdus. Decimal Unsigned Shift VX-form
26007 case 0x0C1: // bcds. Decimal Shift VX-form
26008 case 0x1C1: // bcdsr. Decimal Shift and Round VX-form
26010 IRExpr *shift_dir;
26011 IRExpr *shift_mask, *result, *new_sign_val, *sign;
26012 IRExpr *not_excess_shift, *not_excess_shift_mask;
26013 IRTemp shift_dir_mask = newTemp( Ity_I64 );
26014 IRTemp shift_by = newTemp( Ity_I64 );
26015 IRTemp shift_field = newTemp( Ity_I64 );
26016 IRTemp shifted_out = newTemp( Ity_V128 );
26017 IRTemp value_shl = newTemp( Ity_V128 );
26018 IRTemp value_shr = newTemp( Ity_V128 );
26019 IRTemp round = newTemp( Ity_I32);
26021 ULong value_mask_low = 0;
26022 UInt max_shift = 0;
26024 if (opc2 == 0x0C1) {
26025 DIP("bcds. v%d,v%d,v%d,%d\n", vRT_addr, vRA_addr, vRB_addr, ps);
26026 value_mask_low = 0xFFFFFFFFFFFFFFF0;
26027 max_shift = 30 * 4; /* maximum without shifting all digits out */
26029 } else if (opc2 == 0x1C1) {
26030 DIP("bcdsr. v%d,v%d,v%d,%d\n", vRT_addr, vRA_addr, vRB_addr, ps);
26032 value_mask_low = 0xFFFFFFFFFFFFFFF0;
26033 max_shift = 30 * 4; /* maximum without shifting all digits out */
26035 } else {
26036 DIP("bcdus. v%d,v%d,v%d,%d\n", vRT_addr, vRA_addr,
26037 vRB_addr, ps);
26038 value_mask_low = 0xFFFFFFFFFFFFFFFF;
26039 max_shift = 31 * 4; /* maximum without shifting all digits out */
26042 value = binop( Iop_AndV128,
26043 binop( Iop_64HLtoV128,
26044 mkU64( 0xFFFFFFFFFFFFFFFF ),
26045 mkU64( value_mask_low ) ),
26046 mkexpr( vB ) );
26048 zero = BCDstring_zero( value );
26050 /* Shift field is 2's complement value */
26051 assign( shift_field, unop( Iop_V128to64,
26052 binop( Iop_ShrV128,
26053 binop( Iop_AndV128,
26054 binop( Iop_64HLtoV128,
26055 mkU64( 0xFF ),
26056 mkU64( 0x0) ),
26057 mkexpr( vA ) ),
26058 mkU8( 64 ) ) ) );
26060 /* if shift_dir = 0 shift left, otherwise shift right */
26061 shift_dir = binop( Iop_CmpEQ64,
26062 binop( Iop_Shr64,
26063 mkexpr( shift_field ),
26064 mkU8( 7 ) ),
26065 mkU64( 1 ) );
26067 assign( shift_dir_mask, unop( Iop_1Sto64, shift_dir ) );
26069 /* Shift field is stored in 2's complement form */
26070 assign(shift_by,
26071 binop( Iop_Mul64,
26072 binop( Iop_Or64,
26073 binop( Iop_And64,
26074 unop( Iop_Not64,
26075 mkexpr( shift_dir_mask ) ),
26076 mkexpr( shift_field ) ),
26077 binop( Iop_And64,
26078 mkexpr( shift_dir_mask ),
26079 binop( Iop_And64,
26080 binop( Iop_Add64,
26081 mkU64( 1 ),
26082 unop( Iop_Not64,
26083 mkexpr( shift_field ) ) ),
26084 mkU64( 0xFF ) ) ) ),
26085 mkU64( 4 ) ) );
26087 /* If the shift exceeds 128 bits, we need to force the result
26088 * to zero because Valgrind shift amount is only 7-bits. Otherwise,
26089 * we get a shift amount of mod(shift_by, 127)
26091 not_excess_shift = unop( Iop_1Sto64,
26092 binop( Iop_CmpLE64U,
26093 mkexpr( shift_by ),
26094 mkU64( max_shift ) ) );
26096 not_excess_shift_mask = binop( Iop_64HLtoV128,
26097 not_excess_shift,
26098 not_excess_shift );
26100 assign( value_shl,
26101 binop( Iop_ShlV128, value, unop( Iop_64to8,
26102 mkexpr( shift_by) ) ) );
26103 assign( value_shr,
26104 binop( Iop_AndV128,
26105 binop( Iop_64HLtoV128,
26106 mkU64( 0xFFFFFFFFFFFFFFFF ),
26107 mkU64( value_mask_low) ),
26108 binop( Iop_ShrV128,
26109 value,
26110 unop( Iop_64to8,
26111 mkexpr( shift_by ) ) ) ) );
26113 /* Overflow occurs if the shift amount is greater than zero, the
26114 * operation is a left shift and any non-zero digits are left
26115 * shifted out.
26117 assign( shifted_out,
26118 binop( Iop_OrV128,
26119 binop( Iop_ShrV128,
26120 value,
26121 unop( Iop_64to8,
26122 binop( Iop_Sub64,
26123 mkU64( 32*4 ),
26124 mkexpr( shift_by ) ) ) ),
26125 binop( Iop_AndV128,
26126 unop( Iop_NotV128,
26127 not_excess_shift_mask ),
26128 value ) ) );
26130 overflow = mkAND1( mkNOT1( BCDstring_zero( mkexpr( shifted_out ) ) ),
26131 mkAND1( mkNOT1( shift_dir ),
26132 binop( Iop_CmpNE64,
26133 mkexpr( shift_by ),
26134 mkU64( 0 ) ) ) );
26136 if ((opc2 == 0xC1) || (opc2 == 0x1C1)) {
26137 /* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
26138 * codes 0xB and 0xD are negative.
26140 sign_digit = binop( Iop_And64, mkU64( 0xF ),
26141 unop( Iop_V128to64, mkexpr( vB ) ) );
26143 sign = mkOR1( binop( Iop_CmpEQ64,
26144 sign_digit,
26145 mkU64 ( 0xB ) ),
26146 binop( Iop_CmpEQ64,
26147 sign_digit,
26148 mkU64 ( 0xD ) ) );
26149 neg = mkAND1( sign, mkNOT1( zero ) );
26151 /* Pos position AKA gt = 1 if ((not neg) & (not eq zero)) */
26152 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
26154 valid =
26155 unop( Iop_64to32,
26156 is_BCDstring128( vbi, /* Signed */True, mkexpr( vB ) ) );
26158 } else {
26159 /* string is an unsigned BCD value */
26160 pos = mkU1( 1 );
26161 neg = mkU1( 0 );
26162 sign = mkU1( 0 );
26164 valid =
26165 unop( Iop_64to32,
26166 is_BCDstring128( vbi, /* Unsigned */False,
26167 mkexpr( vB ) ) );
26170 /* if PS = 0
26171 vB positive, sign is C
26172 vB negative, sign is D
26173 if PS = 1
26174 vB positive, sign is F
26175 vB negative, sign is D
26176 Note can't use pos or neg here since they are ANDed with zero,
26177 use sign instead.
26179 if (ps == 0) {
26180 new_sign_val = binop( Iop_Or64,
26181 unop( Iop_1Uto64, sign ),
26182 mkU64( 0xC ) );
26184 } else {
26185 new_sign_val = binop( Iop_Xor64,
26186 binop( Iop_Shl64,
26187 unop( Iop_1Uto64, sign ),
26188 mkU8( 1 ) ),
26189 mkU64( 0xF ) );
26192 shift_mask = binop( Iop_64HLtoV128,
26193 unop( Iop_1Sto64, shift_dir ),
26194 unop( Iop_1Sto64, shift_dir ) );
26196 result = binop( Iop_OrV128,
26197 binop( Iop_AndV128, mkexpr( value_shr ), shift_mask ),
26198 binop( Iop_AndV128,
26199 mkexpr( value_shl ),
26200 unop( Iop_NotV128, shift_mask ) ) );
26202 if (opc2 == 0xC1) { // bcds.
26203 putVReg( vRT_addr, binop( Iop_OrV128,
26204 binop( Iop_64HLtoV128,
26205 mkU64( 0 ),
26206 new_sign_val ),
26207 binop( Iop_AndV128,
26208 not_excess_shift_mask,
26209 result ) ) );
26210 } else if (opc2 == 0x1C1) { //bcdsr.
26211 /* If shifting right, need to round up if needed */
26212 assign( round, unop( Iop_1Uto32,
26213 mkAND1( shift_dir,
26214 check_BCD_round( value,
26215 shift_by ) ) ) );
26217 putVReg( vRT_addr,
26218 binop( Iop_OrV128,
26219 binop( Iop_64HLtoV128,
26220 mkU64( 0 ),
26221 new_sign_val ),
26222 binop( Iop_AndV128,
26223 not_excess_shift_mask,
26224 mkexpr( increment_BCDstring( vbi, result,
26225 mkexpr( round)
26226 ) ) ) ) );
26227 } else { // bcdus.
26228 putVReg( vRT_addr, binop( Iop_AndV128,
26229 not_excess_shift_mask,
26230 result ) );
26233 break;
26235 case 0x101: // bcdtrunc. Decimal Truncate VX-form
26236 case 0x141: // bcdutrunc. Decimal Unsigned Truncate VX-form
26238 IRTemp length = newTemp( Ity_I64 );
26239 IRTemp masked_out = newTemp( Ity_V128 );
26240 IRExpr *new_sign_val, *result, *shift;
26241 IRExpr *length_neq_128, *sign;
26242 ULong value_mask_low;
26243 Int max_digits;
26245 if ( opc2 == 0x101) { // bcdtrunc.
26246 value_mask_low = 0xFFFFFFFFFFFFFFF0;
26247 max_digits = 31;
26248 } else {
26249 value_mask_low = 0xFFFFFFFFFFFFFFFF;
26250 max_digits = 32;
26253 assign( length, binop( Iop_And64,
26254 unop( Iop_V128HIto64,
26255 mkexpr( vA ) ),
26256 mkU64( 0xFFFF ) ) );
26257 shift = unop( Iop_64to8,
26258 binop( Iop_Mul64,
26259 binop( Iop_Sub64,
26260 mkU64( max_digits ),
26261 mkexpr( length ) ),
26262 mkU64( 4 ) ) );
26264 /* Note ShrV128 gets masked by 127 so a shift of 128 results in
26265 * the value not being shifted. A shift of 128 sets the register
26266 * zero. So if length+1 = 128, just set the value to 0.
26268 length_neq_128 = mkNOT1( binop( Iop_CmpEQ64,
26269 mkexpr( length),
26270 mkU64( 0x1F ) ) );
26272 assign( masked_out,
26273 binop( Iop_AndV128,
26274 binop( Iop_64HLtoV128,
26275 unop( Iop_1Sto64, length_neq_128 ),
26276 unop( Iop_1Sto64, length_neq_128 ) ),
26277 binop( Iop_ShrV128,
26278 mkexpr( vB ),
26279 unop( Iop_64to8,
26280 binop( Iop_Mul64,
26281 mkU64( 4 ),
26282 binop( Iop_Add64,
26283 mkU64( 1 ),
26284 mkexpr( length ) ) ) ) )
26285 ) );
26287 /* Overflow occurs if any of the left most 31-length digits of vB
26288 * are non-zero.
26290 overflow = mkNOT1( BCDstring_zero( mkexpr( masked_out ) ) );
26292 value = binop( Iop_AndV128,
26293 binop( Iop_64HLtoV128,
26294 mkU64( 0xFFFFFFFFFFFFFFFF ),
26295 mkU64( value_mask_low ) ),
26296 mkexpr( vB ) );
26299 if ( opc2 == 0x101 ) { // bcdtrunc.
26300 /* Check if all of the non-sign digits are zero */
26301 zero = BCDstring_zero( binop( Iop_AndV128,
26302 binop( Iop_64HLtoV128,
26303 mkU64( 0xFFFFFFFFFFFFFFFF ),
26304 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
26305 value ) );
26307 /* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
26308 * codes 0xB and 0xD are negative.
26310 sign_digit = binop( Iop_And64, mkU64( 0xF ),
26311 unop( Iop_V128to64, mkexpr( vB ) ) );
26313 sign = mkOR1( binop( Iop_CmpEQ64,
26314 sign_digit,
26315 mkU64 ( 0xB ) ),
26316 binop( Iop_CmpEQ64,
26317 sign_digit,
26318 mkU64 ( 0xD ) ) );
26319 neg = mkAND1( sign, mkNOT1( zero ) );
26321 /* Pos position AKA gt = 1 if ((not neg) & (not eq zero)) */
26322 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
26324 /* Note can't use pos or neg here since they are ANDed with zero,
26325 use sign instead.
26327 if (ps == 0) {
26328 new_sign_val = binop( Iop_Or64,
26329 unop( Iop_1Uto64, sign ),
26330 mkU64( 0xC ) );
26331 } else {
26332 new_sign_val = binop( Iop_Xor64,
26333 binop( Iop_Shl64,
26334 unop( Iop_1Uto64, sign ),
26335 mkU8 ( 1 ) ),
26336 mkU64( 0xF ) );
26338 valid =
26339 unop( Iop_64to32,
26340 is_BCDstring128( vbi, /* Signed */True, mkexpr( vB ) ) );
26342 } else { // bcdutrunc.
26343 /* Check if all of the digits are zero */
26344 zero = BCDstring_zero( value );
26346 /* unsigned value, need to make CC code happy */
26347 neg = mkU1( 0 );
26349 /* Pos position AKA gt = 1 if (not eq zero) */
26350 pos = mkNOT1( zero );
26351 valid =
26352 unop( Iop_64to32,
26353 is_BCDstring128( vbi, /* Unsigned */False,
26354 mkexpr( vB ) ) );
26357 /* If vB is not valid, the result is undefined, but we need to
26358 * match the hardware so the output of the test suite will match.
26359 * Hardware sets result to 0x0.
26361 result = binop( Iop_AndV128,
26362 mkV128( 0xFFFF ),
26363 binop( Iop_ShrV128,
26364 binop( Iop_ShlV128, value, shift ),
26365 shift ) );
26367 if ( opc2 == 0x101) { // bcdtrunc.
26368 putVReg( vRT_addr, binop( Iop_OrV128,
26369 binop( Iop_64HLtoV128,
26370 mkU64( 0 ),
26371 new_sign_val ),
26372 result ) );
26373 } else {
26374 putVReg( vRT_addr, result );
26377 break;
26379 case 0x181: // bcdctz., bcdctn., bcdcfz., bcdcfn., bcdsetsgn.,
26380 // bcdcfsq., bcdctsq.
26382 UInt inst_select = IFIELD( theInstr, 16, 5);
26384 switch (inst_select) {
26385 case 0: // bcdctsq. (Decimal Convert to Signed Quadword VX-form)
26387 IRExpr *sign;
26389 /* The instruction takes a 32-bit integer in a vector source
26390 * register and returns the signed packed decimal number
26391 * in a vector register. The source integer needs to be moved
26392 * from the V128 to an I32 for the Iop.
26395 DIP("bcdctsq v%d, v%d\n", vRT_addr, vRB_addr);
26397 putVReg( vRT_addr, unop( Iop_BCD128toI128S, mkexpr( vB ) ) );
26399 sign = binop( Iop_And64,
26400 unop( Iop_V128to64, mkexpr( vB ) ),
26401 mkU64( 0xF ) );
26402 zero = mkAND1( binop( Iop_CmpEQ64,
26403 unop( Iop_V128HIto64, mkexpr( vB ) ),
26404 mkU64( 0x0 ) ),
26405 binop( Iop_CmpEQ64,
26406 binop( Iop_And64,
26407 unop( Iop_V128to64, mkexpr( vB ) ),
26408 mkU64( 0xFFFFFFF0 ) ),
26409 mkU64( 0x0 ) ) );
26410 pos = mkAND1( mkNOT1( zero ),
26411 mkOR1( mkOR1( binop( Iop_CmpEQ64,
26412 sign, mkU64( 0xA ) ),
26413 binop( Iop_CmpEQ64,
26414 sign, mkU64( 0xC ) ) ),
26415 mkOR1( binop( Iop_CmpEQ64,
26416 sign, mkU64( 0xE ) ),
26417 binop( Iop_CmpEQ64,
26418 sign, mkU64( 0xF ) ) ) ) );
26419 neg = mkAND1( mkNOT1( zero ),
26420 mkOR1( binop( Iop_CmpEQ64, sign, mkU64( 0xB ) ),
26421 binop( Iop_CmpEQ64, sign, mkU64( 0xD ) ) ) );
26423 /* Check each of the nibbles for a valid digit 0 to 9 */
26424 valid =
26425 unop( Iop_64to32,
26426 is_BCDstring128( vbi, /* Signed */True,
26427 mkexpr( vB ) ) );
26428 overflow = mkU1( 0 ); // not used
26430 break;
26432 case 2: // bcdcfsq. (Decimal Convert from Signed Quadword VX-form)
26434 IRExpr *pos_upper_gt, *pos_upper_eq, *pos_lower_gt;
26435 IRExpr *neg_upper_lt, *neg_upper_eq, *neg_lower_lt;
26437 DIP("bcdcfsq v%d, v%d, %d\n", vRT_addr, vRB_addr, ps);
26439 /* The instruction takes a signed packed decimal number and
26440 * returns the integer value in the vector register. The Iop
26441 * returns an I32 which needs to be moved to the destination
26442 * vector register.
26444 putVReg( vRT_addr,
26445 binop( Iop_I128StoBCD128, mkexpr( vB ), mkU8( ps ) ) );
26447 zero = mkAND1( binop( Iop_CmpEQ64, mkU64( 0 ),
26448 unop( Iop_V128to64, mkexpr( vB ) ) ),
26449 binop( Iop_CmpEQ64, mkU64( 0 ),
26450 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
26451 pos = mkAND1( mkNOT1 ( zero ),
26452 binop( Iop_CmpEQ64, mkU64( 0 ),
26453 binop( Iop_And64,
26454 unop( Iop_V128HIto64,
26455 mkexpr( vB ) ),
26456 mkU64( 0x8000000000000000UL ) ) ) );
26457 neg = mkAND1( mkNOT1 ( zero ),
26458 binop( Iop_CmpEQ64, mkU64( 0x8000000000000000UL ),
26459 binop( Iop_And64,
26460 unop( Iop_V128HIto64,
26461 mkexpr( vB ) ),
26462 mkU64( 0x8000000000000000UL ) ) ) );
26464 /* Overflow occurs if: vB > 10^31-1 OR vB < -10^31-1
26465 * do not have a 128 bit compare. Will have to compare the
26466 * upper 64 bit and athe lower 64 bits. If the upper 64-bits
26467 * are equal then overflow if the lower 64 bits of vB is greater
26468 * otherwise if the upper bits of vB is greater then the max
26469 * for the upper 64-bits then overflow
26471 * 10^31-1 = 0x7E37BE2022C0914B267FFFFFFF
26473 pos_upper_gt = binop( Iop_CmpLT64U,
26474 mkU64( 0x7E37BE2022 ),
26475 unop( Iop_V128HIto64, mkexpr( vB ) ) );
26476 pos_upper_eq = binop( Iop_CmpEQ64,
26477 unop( Iop_V128HIto64, mkexpr( vB ) ),
26478 mkU64( 0x7E37BE2022 ) );
26479 pos_lower_gt = binop( Iop_CmpLT64U,
26480 mkU64( 0x0914B267FFFFFFF ),
26481 unop( Iop_V128to64, mkexpr( vB ) ) );
26482 /* -10^31-1 = 0X81C841DFDD3F6EB4D97FFFFFFF */
26483 neg_upper_lt = binop( Iop_CmpLT64U,
26484 mkU64( 0X81C841DFDD ),
26485 unop( Iop_V128HIto64, mkexpr( vB ) ) );
26486 neg_upper_eq = binop( Iop_CmpEQ64,
26487 unop( Iop_V128HIto64, mkexpr( vB ) ),
26488 mkU64( 0X81C841DFDD ) );
26489 neg_lower_lt = binop( Iop_CmpLT64U,
26490 mkU64( 0x3F6EB4D97FFFFFFF ),
26491 unop( Iop_V128to64, mkexpr( vB ) ) );
26493 /* calculate overflow, masking for positive and negative */
26494 overflow = mkOR1( mkAND1( pos,
26495 mkOR1( pos_upper_gt,
26496 mkAND1( pos_upper_eq,
26497 pos_lower_gt ) ) ),
26498 mkAND1( neg,
26499 mkOR1( neg_upper_lt,
26500 mkAND1( neg_upper_eq,
26501 neg_lower_lt )
26502 ) ) );
26503 valid = mkU32( 1 );
26505 break;
26507 case 4: // bcdctz. (Decimal Convert to Zoned VX-form)
26509 IRExpr *ox_flag, *sign, *vrb_nibble30;
26510 int neg_bit_shift;
26511 unsigned int upper_byte, sign_byte;
26512 IRTemp tmp = newTemp( Ity_V128 );
26514 DIP("bcdctz. v%d,v%d,%d\n", vRT_addr, vRB_addr, ps);
26516 if (ps == 0) {
26517 upper_byte = 0x30;
26518 sign_byte = 0x30;
26519 neg_bit_shift = 4+2; /* sign byte is in bits [7:4] */
26520 } else {
26521 upper_byte = 0xF0;
26522 sign_byte = 0xC0;
26523 neg_bit_shift = 4+0;
26526 /* Grab vB bits[7:4]. It goes into bits [3:0] of the
26527 * result.
26529 vrb_nibble30 = binop( Iop_Shr64,
26530 binop( Iop_And64,
26531 unop( Iop_V128to64, mkexpr( vB ) ),
26532 mkU64( 0xF0 ) ),
26533 mkU8( 4 ) );
26535 /* Upper 24 hex digits of VB, i.e. hex digits vB[0:23],
26536 * must be zero for the value to be zero. This goes
26537 * in the overflow position of the condition code register.
26539 ox_flag = binop( Iop_CmpEQ64,
26540 binop( Iop_And64,
26541 unop( Iop_V128to64, mkexpr( vB ) ),
26542 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
26543 mkU64( 0 ) );
26545 /* zero is the same as eq_flag */
26546 zero = mkAND1( binop( Iop_CmpEQ64,
26547 binop( Iop_And64,
26548 unop( Iop_V128HIto64, mkexpr( vB ) ),
26549 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
26550 mkU64( 0 ) ),
26551 binop( Iop_CmpEQ64,
26552 binop( Iop_And64,
26553 unop( Iop_V128to64, mkexpr( vB ) ),
26554 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
26555 mkU64( 0 ) ) );
26557 /* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
26558 * codes 0xB and 0xD are negative.
26560 sign_digit = binop( Iop_And64, mkU64( 0xF ),
26561 unop( Iop_V128to64, mkexpr( vB ) ) );
26563 /* The negative value goes in the LT bit position of the
26564 * condition code register. Set neg if the sign of vB
26565 * is negative and zero is true.
26567 sign = mkOR1( binop( Iop_CmpEQ64,
26568 sign_digit,
26569 mkU64 ( 0xB ) ),
26570 binop( Iop_CmpEQ64,
26571 sign_digit,
26572 mkU64 ( 0xD ) ) );
26573 neg = mkAND1( sign, mkNOT1( zero ) );
26575 /* The positive value goes in the LT bit position of the
26576 * condition code register. Set positive if the sign of the
26577 * value is not negative.
26579 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
26581 assign( tmp,
26582 convert_to_zoned( vbi, mkexpr( vB ),
26583 mkU64( upper_byte ) ) );
26585 /* Insert the sign based on ps and sign of vB
26586 * in the lower byte.
26588 putVReg( vRT_addr,
26589 binop( Iop_OrV128,
26590 binop( Iop_64HLtoV128,
26591 mkU64( 0 ),
26592 vrb_nibble30 ),
26593 binop( Iop_OrV128,
26594 mkexpr( tmp ),
26595 binop( Iop_64HLtoV128,
26596 mkU64( 0 ),
26597 binop( Iop_Or64,
26598 mkU64( sign_byte ),
26599 binop( Iop_Shl64,
26600 unop( Iop_1Uto64,
26601 sign ),
26602 mkU8( neg_bit_shift)
26603 ) ) ) ) ) );
26605 /* A valid number must have a value that is less then or
26606 * equal to 10^16 - 1. This is checked by making sure
26607 * bytes [31:16] of vB are zero.
26609 in_range = binop( Iop_CmpEQ64,
26610 binop( Iop_And64,
26611 mkU64( 0xFFFFFFFFFFFFFFF0 ),
26612 unop( Iop_V128HIto64, mkexpr( vB ) ) ),
26613 mkU64( 0 ) );
26615 /* overflow is set if ox_flag or not in_inrange. Setting is
26616 * ORed with the other condition code values.
26618 overflow = mkOR1( ox_flag, mkNOT1( in_range ) );
26620 /* The sign code must be between 0xA and 0xF and all digits are
26621 * between 0x0 and 0x9. The vB must be in range to be valid.
26622 * If not valid, condition code set to 0x0001.
26624 valid =
26625 unop( Iop_64to32,
26626 is_BCDstring128( vbi, /* Signed */True,
26627 mkexpr( vB ) ) );
26629 break;
26631 case 5: // bcdctn. (Decimal Convert to National VX-form)
26633 IRExpr *ox_flag, *sign;
26634 IRTemp tmp = newTemp( Ity_V128 );;
26636 DIP("bcdctn. v%d,v%d\n", vRT_addr, vRB_addr);
26638 value = binop( Iop_And64,
26639 mkU64( 0xFFFFFFFF ),
26640 unop( Iop_V128to64, mkexpr( vB ) ) );
26642 /* A valid number must have a value that is less then or
26643 * equal to 10^7 - 1. This is checked by making sure
26644 * bytes [31:8] of vB are zero.
26646 in_range = mkAND1( binop( Iop_CmpEQ64,
26647 unop( Iop_V128HIto64, mkexpr( vB ) ),
26648 mkU64( 0 ) ),
26649 binop( Iop_CmpEQ64,
26650 binop( Iop_Shr64,
26651 unop( Iop_V128to64,
26652 mkexpr( vB ) ),
26653 mkU8( 32 ) ),
26654 mkU64( 0 ) ) );
26656 /* The sign code must be between 0xA and 0xF and all digits are
26657 * between 0x0 and 0x9.
26659 valid =
26660 unop( Iop_64to32,
26661 is_BCDstring128( vbi, /* Signed */True,
26662 mkexpr( vB ) ) );
26664 /* Upper 24 hex digits of VB, i.e. hex ditgits vB[0:23],
26665 * must be zero for the ox_flag to be zero. This goes
26666 * in the LSB position (variable overflow) of the
26667 * condition code register.
26669 ox_flag =
26670 mkNOT1( mkAND1( binop( Iop_CmpEQ64,
26671 binop( Iop_And64,
26672 unop( Iop_V128HIto64,
26673 mkexpr( vB ) ),
26674 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
26675 mkU64( 0 ) ),
26676 binop( Iop_CmpEQ64,
26677 binop( Iop_And64,
26678 unop( Iop_V128to64,
26679 mkexpr( vB ) ),
26680 mkU64( 0xFFFFFFFF00000000 ) ),
26681 mkU64( 0 ) ) ) );
26683 /* Set zero to 1 if all of the bytes in vB are zero. This is
26684 * used when setting the lt_flag (variable neg) and the gt_flag
26685 * (variable pos).
26687 zero = mkAND1( binop( Iop_CmpEQ64,
26688 binop( Iop_And64,
26689 unop( Iop_V128HIto64,
26690 mkexpr( vB ) ),
26691 mkU64( 0xFFFFFFFFFFFFFFFF ) ),
26692 mkU64( 0 ) ),
26693 binop( Iop_CmpEQ64,
26694 binop( Iop_And64,
26695 unop( Iop_V128to64, mkexpr( vB ) ),
26696 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
26697 mkU64( 0 ) ) );
26699 /* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
26700 * codes 0xB and 0xD are negative.
26702 sign_digit = binop( Iop_And64, mkU64( 0xF ), value );
26704 /* The negative value goes in the LT bit position of the
26705 * condition code register. Set neg if the sign of the
26706 * value is negative and the value is zero.
26708 sign = mkOR1( binop( Iop_CmpEQ64,
26709 sign_digit,
26710 mkU64 ( 0xB ) ),
26711 binop( Iop_CmpEQ64,
26712 sign_digit,
26713 mkU64 ( 0xD ) ) );
26714 neg = mkAND1( sign, mkNOT1( zero ) );
26716 /* The positive value goes in the LT bit position of the
26717 * condition code register. Set neg if the sign of the
26718 * value is not negative and the value is zero.
26720 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
26722 assign( tmp,
26723 convert_to_national( vbi, mkexpr( vB ) ) );
26725 /* If vB is positive insert sign value 0x002B, otherwise
26726 * insert 0x002D for negative. Have to use sign not neg
26727 * because neg has been ANDed with zero. This is 0x29
26728 * OR'd with (sign << 1 | NOT sign) << 1.
26729 * sign = 1 if vB is negative.
26731 putVReg( vRT_addr,
26732 binop( Iop_OrV128,
26733 mkexpr( tmp ),
26734 binop( Iop_64HLtoV128,
26735 mkU64( 0 ),
26736 binop( Iop_Or64,
26737 mkU64( 0x29 ),
26738 binop( Iop_Or64,
26739 binop( Iop_Shl64,
26740 unop( Iop_1Uto64,
26741 sign ),
26742 mkU8( 2 ) ),
26743 binop( Iop_Shl64,
26744 unop( Iop_1Uto64,
26745 mkNOT1(sign)),
26746 mkU8( 1 ) )
26747 ) ) ) ) );
26750 /* The sign code must be between 0xA and 0xF and all digits are
26751 * between 0x0 and 0x9. The vB must be in range to be valid.
26753 valid =
26754 unop( Iop_64to32,
26755 is_BCDstring128( vbi, /* Signed */True,
26756 mkexpr( vB ) ) );
26758 overflow = ox_flag;
26760 break;
26762 case 6: // bcdcfz. (Decimal Convert From Zoned VX-form)
26764 IRExpr *sign;
26765 IRTemp tmp = newTemp( Ity_V128 );;
26767 DIP("bcdcfz. v%d,v%d,%d\n", vRT_addr, vRB_addr, ps);
26769 valid = unop( Iop_1Uto32, is_Zoned_decimal( vB, ps ) );
26771 assign( tmp,
26772 convert_from_zoned( vbi, mkexpr( vB ) ) );
26774 /* If the result of checking the lower 4 bits of each 8-bit
26775 * value is zero, then the "number" was zero.
26777 zero =
26778 binop( Iop_CmpEQ64,
26779 binop( Iop_Or64,
26780 binop( Iop_And64,
26781 unop( Iop_V128to64, mkexpr( vB ) ),
26782 mkU64( 0x0F0F0F0F0F0F0F0FULL ) ),
26783 binop( Iop_And64,
26784 unop( Iop_V128to64, mkexpr( vB ) ),
26785 mkU64( 0x0F0F0F0F0F0F0F0FULL ) ) ),
26786 mkU64( 0 ) );
26788 /* Sign bit is in bit 6 of vB. */
26789 sign_digit = binop( Iop_And64, mkU64( 0xF0 ),
26790 unop( Iop_V128to64, mkexpr( vB ) ) );
26792 if ( ps == 0 ) {
26793 /* sign will be equal to 0 for positive number */
26794 sign = binop( Iop_CmpEQ64,
26795 binop( Iop_And64,
26796 sign_digit,
26797 mkU64( 0x40 ) ),
26798 mkU64( 0x40 ) );
26799 } else {
26800 sign = mkOR1(
26801 binop( Iop_CmpEQ64, sign_digit, mkU64( 0xB0 ) ),
26802 binop( Iop_CmpEQ64, sign_digit, mkU64( 0xD0 ) ) );
26805 /* The negative value goes in the LT bit position of the
26806 * condition code register. Set neg if the sign of the
26807 * value is negative and the value is zero.
26809 neg = mkAND1( sign, mkNOT1( zero ) );
26811 /* The positive value goes in the GT bit position of the
26812 * condition code register. Set neg if the sign of the
26813 * value is not negative and the value is zero.
26815 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
26817 /* sign of the result is 0xC for positive, 0xD for negative */
26818 putVReg( vRT_addr,
26819 binop( Iop_OrV128,
26820 mkexpr( tmp ),
26821 binop( Iop_64HLtoV128,
26822 mkU64( 0 ),
26823 binop( Iop_Or64,
26824 mkU64( 0xC ),
26825 unop( Iop_1Uto64, sign )
26826 ) ) ) );
26827 /* For this instructions the LSB position in the CC
26828 * field, the overflow position in the other instructions,
26829 * is given by 0. There is nothing to or with LT, EQ or GT.
26831 overflow = mkU1( 0 );
26833 break;
26835 case 7: // bcdcfn. (Decimal Convert From National VX-form)
26837 IRTemp hword_7 = newTemp( Ity_I64 );
26838 IRExpr *sign;
26839 IRTemp tmp = newTemp( Ity_I64 );;
26841 DIP("bcdcfn. v%d,v%d,%d\n", vRT_addr, vRB_addr, ps);
26843 /* check that the value is valid */
26844 valid = unop( Iop_1Uto32, is_National_decimal( vB ) );
26846 assign( hword_7, binop( Iop_And64,
26847 unop( Iop_V128to64, mkexpr( vB ) ),
26848 mkU64( 0xFFF ) ) );
26849 /* sign = 1 if vB is negative */
26850 sign = binop( Iop_CmpEQ64, mkexpr( hword_7 ), mkU64( 0x002D ) );
26852 assign( tmp, convert_from_national( vbi, mkexpr( vB ) ) );
26854 /* If the result of checking the lower 4 bits of each 16-bit
26855 * value is zero, then the "number" was zero.
26857 zero =
26858 binop( Iop_CmpEQ64,
26859 binop( Iop_Or64,
26860 binop( Iop_And64,
26861 unop( Iop_V128HIto64, mkexpr( vB ) ),
26862 mkU64( 0x000F000F000F000FULL ) ),
26863 binop( Iop_And64,
26864 unop( Iop_V128to64, mkexpr( vB ) ),
26865 mkU64( 0x000F000F000F0000ULL ) ) ),
26866 mkU64( 0 ) );
26869 /* The negative value goes in the LT bit position of the
26870 * condition code register. Set neg if the sign of the
26871 * value is negative and the value is zero.
26873 neg = mkAND1( sign, mkNOT1( zero ) );
26875 /* The positive value goes in the GT bit position of the
26876 * condition code register. Set neg if the sign of the
26877 * value is not negative and the value is zero.
26879 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
26881 /* For this instructions the LSB position in the CC
26882 * field, the overflow position in the other instructions,
26883 * is given by invalid. There is nothing to OR with the valid
26884 * flag.
26886 overflow = mkU1( 0 );
26888 /* sign of the result is:
26889 ( 0b1100 OR neg) OR (ps OR (ps AND pos) << 1 )
26892 putVReg( vRT_addr,
26893 binop( Iop_64HLtoV128,
26894 mkU64( 0 ),
26895 binop( Iop_Or64,
26896 binop( Iop_Or64,
26897 binop( Iop_Shl64,
26898 binop( Iop_And64,
26899 mkU64( ps ),
26900 unop( Iop_1Uto64,
26901 mkNOT1(sign))),
26902 mkU8( 1 ) ),
26903 mkU64( ps ) ),
26904 binop( Iop_Or64,
26905 binop( Iop_Or64,
26906 mkU64( 0xC ),
26907 unop( Iop_1Uto64, sign ) ),
26908 mkexpr( tmp ) ) ) ) );
26911 break;
26913 case 31: // bcdsetsgn. (BCD set sign)
26915 IRExpr *new_sign_val, *sign;
26917 DIP("bcdsetsgn. v%d,v%d,%d\n", vRT_addr, vRB_addr, ps);
26919 value = binop( Iop_AndV128,
26920 binop( Iop_64HLtoV128,
26921 mkU64( 0xFFFFFFFFFFFFFFFF ),
26922 mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
26923 mkexpr( vB ) );
26924 zero = BCDstring_zero( value );
26926 /* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
26927 * codes 0xB and 0xD are negative.
26929 sign_digit = binop( Iop_And64, mkU64( 0xF ),
26930 unop( Iop_V128to64, mkexpr( vB ) ) );
26932 sign = mkOR1( binop( Iop_CmpEQ64,
26933 sign_digit,
26934 mkU64 ( 0xB ) ),
26935 binop( Iop_CmpEQ64,
26936 sign_digit,
26937 mkU64 ( 0xD ) ) );
26938 neg = mkAND1( sign, mkNOT1( zero ) );
26940 pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
26942 valid =
26943 unop( Iop_64to32,
26944 is_BCDstring128( vbi, /* Signed */True,
26945 mkexpr( vB ) ) );
26947 /* if PS = 0
26948 vB positive, sign is C
26949 vB negative, sign is D
26950 if PS = 1
26951 vB positive, sign is F
26952 vB negative, sign is D
26953 Note can't use pos or neg here since they are ANDed with
26954 zero, use sign instead.
26956 if (ps == 0) {
26957 new_sign_val = binop( Iop_Or64,
26958 unop( Iop_1Uto64, sign ),
26959 mkU64( 0xC ) );
26961 } else {
26962 new_sign_val = binop( Iop_Xor64,
26963 binop( Iop_Shl64,
26964 unop( Iop_1Uto64, sign ),
26965 mkU8( 1 ) ),
26966 mkU64( 0xF ) );
26969 putVReg( vRT_addr, binop( Iop_OrV128,
26970 binop( Iop_64HLtoV128,
26971 mkU64( 0 ),
26972 new_sign_val ),
26973 value ) );
26974 /* For this instructions the LSB position in the CC
26975 * field, the overflow position in the other instructions,
26976 * is given by invalid.
26978 overflow = unop( Iop_32to1, unop( Iop_Not32, valid ) );
26980 break;
26982 default:
26983 vex_printf("dis_av_bcd(ppc)(invalid inst_select)\n");
26984 return False;
26987 break;
26989 default:
26990 vex_printf("dis_av_bcd(ppc)(opc2)\n");
26991 return False;
26994 IRTemp valid_mask = newTemp( Ity_I32 );
26996 assign( valid_mask, unop( Iop_1Sto32, unop( Iop_32to1, valid ) ) );
26998 /* set CR field 6 to:
26999 * 0b1000 if vB less then 0, i.e. vB is neg and not zero,
27000 * 0b0100 if vB greter then 0, i.e. vB is pos and not zero,
27001 * 0b0010 if vB equals 0,
27002 * 0b0001 if vB is invalid over rules lt, gt, eq
27004 assign( eq_lt_gt,
27005 binop( Iop_Or32,
27006 binop( Iop_Shl32,
27007 unop( Iop_1Uto32, neg ),
27008 mkU8( 3 ) ),
27009 binop( Iop_Or32,
27010 binop( Iop_Shl32,
27011 unop( Iop_1Uto32, pos ),
27012 mkU8( 2 ) ),
27013 binop( Iop_Shl32,
27014 unop( Iop_1Uto32, zero ),
27015 mkU8( 1 ) ) ) ) );
27016 /* valid is 1 if it is a valid number, complement and put in the
27017 * invalid bit location, overriding ls, eq, gt, overflow.
27019 putGST_field( PPC_GST_CR,
27020 binop( Iop_Or32,
27021 binop( Iop_And32,
27022 mkexpr( valid_mask ),
27023 binop( Iop_Or32,
27024 mkexpr( eq_lt_gt ),
27025 unop( Iop_1Uto32, overflow ) ) ),
27026 binop( Iop_And32,
27027 unop( Iop_Not32, mkexpr( valid_mask ) ),
27028 mkU32( 1 ) ) ),
27029 6 );
27030 return True;
27034 AltiVec Floating Point Arithmetic Instructions
27036 static Bool dis_av_fp_arith ( UInt theInstr )
27038 /* VA-Form */
27039 UChar opc1 = ifieldOPC(theInstr);
27040 UChar vD_addr = ifieldRegDS(theInstr);
27041 UChar vA_addr = ifieldRegA(theInstr);
27042 UChar vB_addr = ifieldRegB(theInstr);
27043 UChar vC_addr = ifieldRegC(theInstr);
27044 UInt opc2=0;
27046 IRTemp vA = newTemp(Ity_V128);
27047 IRTemp vB = newTemp(Ity_V128);
27048 IRTemp vC = newTemp(Ity_V128);
27049 assign( vA, getVReg(vA_addr));
27050 assign( vB, getVReg(vB_addr));
27051 assign( vC, getVReg(vC_addr));
27053 if (opc1 != 0x4) {
27054 vex_printf("dis_av_fp_arith(ppc)(instr)\n");
27055 return False;
27058 IRTemp rm = newTemp(Ity_I32);
27059 assign(rm, get_IR_roundingmode());
27061 opc2 = IFIELD( theInstr, 0, 6 );
27062 switch (opc2) {
27063 case 0x2E: // vmaddfp (Multiply Add FP, AV p177)
27064 DIP("vmaddfp v%d,v%d,v%d,v%d\n",
27065 vD_addr, vA_addr, vC_addr, vB_addr);
27066 putVReg( vD_addr,
27067 triop(Iop_Add32Fx4, mkU32(Irrm_NEAREST),
27068 mkexpr(vB),
27069 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
27070 mkexpr(vA), mkexpr(vC))) );
27071 return True;
27073 case 0x2F: { // vnmsubfp (Negative Multiply-Subtract FP, AV p215)
27074 DIP("vnmsubfp v%d,v%d,v%d,v%d\n",
27075 vD_addr, vA_addr, vC_addr, vB_addr);
27076 putVReg( vD_addr,
27077 triop(Iop_Sub32Fx4, mkU32(Irrm_NEAREST),
27078 mkexpr(vB),
27079 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
27080 mkexpr(vA), mkexpr(vC))) );
27081 return True;
27084 default:
27085 break; // Fall through...
27088 opc2 = IFIELD( theInstr, 0, 11 );
27089 switch (opc2) {
27090 case 0x00A: // vaddfp (Add FP, AV p137)
27091 DIP("vaddfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
27092 putVReg( vD_addr, triop(Iop_Add32Fx4,
27093 mkU32(Irrm_NEAREST), mkexpr(vA), mkexpr(vB)) );
27094 return True;
27096 case 0x04A: // vsubfp (Subtract FP, AV p261)
27097 DIP("vsubfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
27098 putVReg( vD_addr, triop(Iop_Sub32Fx4,
27099 mkU32(Irrm_NEAREST), mkexpr(vA), mkexpr(vB)) );
27100 return True;
27102 case 0x40A: // vmaxfp (Maximum FP, AV p178)
27103 DIP("vmaxfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
27104 putVReg( vD_addr, binop(Iop_Max32Fx4, mkexpr(vA), mkexpr(vB)) );
27105 return True;
27107 case 0x44A: // vminfp (Minimum FP, AV p187)
27108 DIP("vminfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
27109 putVReg( vD_addr, binop(Iop_Min32Fx4, mkexpr(vA), mkexpr(vB)) );
27110 return True;
27112 default:
27113 break; // Fall through...
27117 if (vA_addr != 0) {
27118 vex_printf("dis_av_fp_arith(ppc)(vA_addr)\n");
27119 return False;
27122 switch (opc2) {
27123 case 0x10A: // vrefp (Reciprocal Esimate FP, AV p228)
27124 DIP("vrefp v%d,v%d\n", vD_addr, vB_addr);
27125 putVReg( vD_addr, unop(Iop_RecipEst32Fx4, mkexpr(vB)) );
27126 return True;
27128 case 0x14A: // vrsqrtefp (Reciprocal Sqrt Estimate FP, AV p237)
27129 DIP("vrsqrtefp v%d,v%d\n", vD_addr, vB_addr);
27130 putVReg( vD_addr, unop(Iop_RSqrtEst32Fx4, mkexpr(vB)) );
27131 return True;
27133 case 0x18A: // vexptefp (2 Raised to the Exp Est FP, AV p173)
27134 DIP("vexptefp v%d,v%d\n", vD_addr, vB_addr);
27135 DIP(" => not implemented\n");
27136 return False;
27138 case 0x1CA: // vlogefp (Log2 Estimate FP, AV p175)
27139 DIP("vlogefp v%d,v%d\n", vD_addr, vB_addr);
27140 DIP(" => not implemented\n");
27141 return False;
27143 default:
27144 vex_printf("dis_av_fp_arith(ppc)(opc2=0x%x)\n",opc2);
27145 return False;
27147 return True;
27151 AltiVec Floating Point Compare Instructions
27153 static Bool dis_av_fp_cmp ( UInt theInstr )
27155 /* VXR-Form */
27156 UChar opc1 = ifieldOPC(theInstr);
27157 UChar vD_addr = ifieldRegDS(theInstr);
27158 UChar vA_addr = ifieldRegA(theInstr);
27159 UChar vB_addr = ifieldRegB(theInstr);
27160 UChar flag_rC = ifieldBIT10(theInstr);
27161 UInt opc2 = IFIELD( theInstr, 0, 10 );
27163 Bool cmp_bounds = False;
27165 IRTemp vA = newTemp(Ity_V128);
27166 IRTemp vB = newTemp(Ity_V128);
27167 IRTemp vD = newTemp(Ity_V128);
27168 assign( vA, getVReg(vA_addr));
27169 assign( vB, getVReg(vB_addr));
27171 if (opc1 != 0x4) {
27172 vex_printf("dis_av_fp_cmp(ppc)(instr)\n");
27173 return False;
27176 switch (opc2) {
27177 case 0x0C6: // vcmpeqfp (Compare Equal-to FP, AV p159)
27178 DIP("vcmpeqfp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
27179 vD_addr, vA_addr, vB_addr);
27180 assign( vD, binop(Iop_CmpEQ32Fx4, mkexpr(vA), mkexpr(vB)) );
27181 break;
27183 case 0x1C6: // vcmpgefp (Compare Greater-than-or-Equal-to, AV p163)
27184 DIP("vcmpgefp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
27185 vD_addr, vA_addr, vB_addr);
27186 assign( vD, binop(Iop_CmpGE32Fx4, mkexpr(vA), mkexpr(vB)) );
27187 break;
27189 case 0x2C6: // vcmpgtfp (Compare Greater-than FP, AV p164)
27190 DIP("vcmpgtfp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
27191 vD_addr, vA_addr, vB_addr);
27192 assign( vD, binop(Iop_CmpGT32Fx4, mkexpr(vA), mkexpr(vB)) );
27193 break;
27195 case 0x3C6: { // vcmpbfp (Compare Bounds FP, AV p157)
27196 IRTemp gt = newTemp(Ity_V128);
27197 IRTemp lt = newTemp(Ity_V128);
27198 IRTemp zeros = newTemp(Ity_V128);
27199 DIP("vcmpbfp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
27200 vD_addr, vA_addr, vB_addr);
27201 cmp_bounds = True;
27202 assign( zeros, unop(Iop_Dup32x4, mkU32(0)) );
27204 /* Note: making use of fact that the ppc backend for compare insns
27205 return zero'd lanes if either of the corresponding arg lanes is
27206 a nan.
27208 Perhaps better to have an irop Iop_isNan32Fx4, but then we'd
27209 need this for the other compares too (vcmpeqfp etc)...
27210 Better still, tighten down the spec for compare irops.
27212 assign( gt, unop(Iop_NotV128,
27213 binop(Iop_CmpLE32Fx4, mkexpr(vA), mkexpr(vB))) );
27214 assign( lt, unop(Iop_NotV128,
27215 binop(Iop_CmpGE32Fx4, mkexpr(vA),
27216 triop(Iop_Sub32Fx4, mkU32(Irrm_NEAREST),
27217 mkexpr(zeros),
27218 mkexpr(vB)))) );
27220 // finally, just shift gt,lt to correct position
27221 assign( vD, binop(Iop_ShlN32x4,
27222 binop(Iop_OrV128,
27223 binop(Iop_AndV128, mkexpr(gt),
27224 unop(Iop_Dup32x4, mkU32(0x2))),
27225 binop(Iop_AndV128, mkexpr(lt),
27226 unop(Iop_Dup32x4, mkU32(0x1)))),
27227 mkU8(30)) );
27228 break;
27231 default:
27232 vex_printf("dis_av_fp_cmp(ppc)(opc2)\n");
27233 return False;
27236 putVReg( vD_addr, mkexpr(vD) );
27238 if (flag_rC) {
27239 set_AV_CR6( mkexpr(vD), !cmp_bounds );
27241 return True;
27245 AltiVec Floating Point Convert/Round Instructions
27247 static Bool dis_av_fp_convert ( UInt theInstr )
27249 /* VX-Form */
27250 UChar opc1 = ifieldOPC(theInstr);
27251 UChar vD_addr = ifieldRegDS(theInstr);
27252 UChar UIMM_5 = ifieldRegA(theInstr);
27253 UChar vB_addr = ifieldRegB(theInstr);
27254 UInt opc2 = IFIELD( theInstr, 0, 11 );
27256 IRTemp vB = newTemp(Ity_V128);
27257 IRTemp vScale = newTemp(Ity_V128);
27258 IRTemp vInvScale = newTemp(Ity_V128);
27260 float scale, inv_scale;
27262 assign( vB, getVReg(vB_addr));
27264 /* scale = 2^UIMM, cast to float, reinterpreted as uint */
27265 scale = (float)( (unsigned int) 1<<UIMM_5 );
27266 assign( vScale, unop(Iop_Dup32x4, mkU32( float_to_bits(scale) )) );
27267 inv_scale = 1/scale;
27268 assign( vInvScale,
27269 unop(Iop_Dup32x4, mkU32( float_to_bits(inv_scale) )) );
27271 if (opc1 != 0x4) {
27272 vex_printf("dis_av_fp_convert(ppc)(instr)\n");
27273 return False;
27276 switch (opc2) {
27277 case 0x30A: // vcfux (Convert from Unsigned Fixed-Point W, AV p156)
27278 DIP("vcfux v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
27279 putVReg( vD_addr, triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
27280 unop(Iop_I32UtoFx4, mkexpr(vB)),
27281 mkexpr(vInvScale)) );
27282 return True;
27284 case 0x34A: // vcfsx (Convert from Signed Fixed-Point W, AV p155)
27285 DIP("vcfsx v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
27287 putVReg( vD_addr, triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
27288 unop(Iop_I32StoFx4, mkexpr(vB)),
27289 mkexpr(vInvScale)) );
27290 return True;
27292 case 0x38A: // vctuxs (Convert to Unsigned Fixed-Point W Saturate, AV p172)
27293 DIP("vctuxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
27294 putVReg( vD_addr,
27295 unop(Iop_QFtoI32Ux4_RZ,
27296 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
27297 mkexpr(vB), mkexpr(vScale))) );
27298 return True;
27300 case 0x3CA: // vctsxs (Convert to Signed Fixed-Point W Saturate, AV p171)
27301 DIP("vctsxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
27302 putVReg( vD_addr,
27303 unop(Iop_QFtoI32Sx4_RZ,
27304 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
27305 mkexpr(vB), mkexpr(vScale))) );
27306 return True;
27308 default:
27309 break; // Fall through...
27312 if (UIMM_5 != 0) {
27313 vex_printf("dis_av_fp_convert(ppc)(UIMM_5)\n");
27314 return False;
27317 switch (opc2) {
27318 case 0x20A: // vrfin (Round to FP Integer Nearest, AV p231)
27319 DIP("vrfin v%d,v%d\n", vD_addr, vB_addr);
27320 putVReg( vD_addr, unop(Iop_RoundF32x4_RN, mkexpr(vB)) );
27321 break;
27323 case 0x24A: // vrfiz (Round to FP Integer toward zero, AV p233)
27324 DIP("vrfiz v%d,v%d\n", vD_addr, vB_addr);
27325 putVReg( vD_addr, unop(Iop_RoundF32x4_RZ, mkexpr(vB)) );
27326 break;
27328 case 0x28A: // vrfip (Round to FP Integer toward +inf, AV p232)
27329 DIP("vrfip v%d,v%d\n", vD_addr, vB_addr);
27330 putVReg( vD_addr, unop(Iop_RoundF32x4_RP, mkexpr(vB)) );
27331 break;
27333 case 0x2CA: // vrfim (Round to FP Integer toward -inf, AV p230)
27334 DIP("vrfim v%d,v%d\n", vD_addr, vB_addr);
27335 putVReg( vD_addr, unop(Iop_RoundF32x4_RM, mkexpr(vB)) );
27336 break;
27338 default:
27339 vex_printf("dis_av_fp_convert(ppc)(opc2)\n");
27340 return False;
27342 return True;
27345 static Bool dis_transactional_memory ( UInt theInstr, UInt nextInstr,
27346 const VexAbiInfo* vbi,
27347 /*OUT*/DisResult* dres,
27348 Bool (*resteerOkFn)(void*,Addr),
27349 void* callback_opaque )
27351 UInt opc2 = IFIELD( theInstr, 1, 10 );
27353 switch (opc2) {
27354 case 0x28E: { //tbegin.
27355 /* The current implementation is to just fail the tbegin and execute
27356 * the failure path. The failure path is assumed to be functionaly
27357 * equivalent to the transactional path with the needed data locking
27358 * to ensure correctness. The tend is just a noop and shouldn't
27359 * actually get executed.
27360 * 1) set cr0 to 0x2
27361 * 2) Initialize TFHAR to CIA+4
27362 * 3) Initialize TEXASR
27363 * 4) Initialize TFIAR (probably to CIA, ie, the address of tbegin.)
27364 * 5) Continue executing at the next instruction.
27366 UInt R = IFIELD( theInstr, 21, 1 );
27368 ULong tm_reason;
27369 UInt failure_code = 0; /* Forcing failure, will not be due to tabort
27370 * or treclaim.
27372 UInt persistant = 1; /* set persistant since we are always failing
27373 * the tbegin.
27375 UInt nest_overflow = 1; /* Alowed nesting depth overflow, we use this
27376 as the reason for failing the trasaction */
27377 UInt tm_exact = 1; /* have exact address for failure */
27379 DIP("tbegin. %u\n", R);
27381 /* Set the CR0 field to indicate the tbegin failed. Then let
27382 * the code do the branch to the failure path.
27384 * 000 || 0 Transaction initiation successful,
27385 * unnested (Transaction state of
27386 * Non-transactional prior to tbegin.)
27387 * 010 || 0 Transaction initiation successful, nested
27388 * (Transaction state of Transactional
27389 * prior to tbegin.)
27390 * 001 || 0 Transaction initiation unsuccessful,
27391 * (Transaction state of Suspended prior
27392 * to tbegin.)
27394 putCR321( 0, mkU8( 0x2 ) );
27396 tm_reason = generate_TMreason( failure_code, persistant,
27397 nest_overflow, tm_exact );
27399 storeTMfailure( guest_CIA_curr_instr, tm_reason,
27400 guest_CIA_curr_instr+4 );
27402 return True;
27404 break;
27407 case 0x2AE: { //tend.
27408 /* The tend. is just a noop. Do nothing */
27409 UInt A = IFIELD( theInstr, 25, 1 );
27411 DIP("tend. %u\n", A);
27412 break;
27415 case 0x2EE: { //tsr.
27416 /* The tsr. is just a noop. Do nothing */
27417 UInt L = IFIELD( theInstr, 21, 1 );
27419 DIP("tsr. %u\n", L);
27420 break;
27423 case 0x2CE: { //tcheck.
27424 /* The tcheck. is just a noop. Do nothing */
27425 UInt BF = IFIELD( theInstr, 25, 1 );
27427 DIP("tcheck. %u\n", BF);
27428 break;
27431 case 0x30E: { //tbortwc.
27432 /* The tabortwc. is just a noop. Do nothing */
27433 UInt TO = IFIELD( theInstr, 25, 1 );
27434 UInt RA = IFIELD( theInstr, 16, 5 );
27435 UInt RB = IFIELD( theInstr, 11, 5 );
27437 DIP("tabortwc. %u,%u,%u\n", TO, RA, RB);
27438 break;
27441 case 0x32E: { //tbortdc.
27442 /* The tabortdc. is just a noop. Do nothing */
27443 UInt TO = IFIELD( theInstr, 25, 1 );
27444 UInt RA = IFIELD( theInstr, 16, 5 );
27445 UInt RB = IFIELD( theInstr, 11, 5 );
27447 DIP("tabortdc. %u,%u,%u\n", TO, RA, RB);
27448 break;
27451 case 0x34E: { //tbortwci.
27452 /* The tabortwci. is just a noop. Do nothing */
27453 UInt TO = IFIELD( theInstr, 25, 1 );
27454 UInt RA = IFIELD( theInstr, 16, 5 );
27455 UInt SI = IFIELD( theInstr, 11, 5 );
27457 DIP("tabortwci. %u,%u,%u\n", TO, RA, SI);
27458 break;
27461 case 0x36E: { //tbortdci.
27462 /* The tabortdci. is just a noop. Do nothing */
27463 UInt TO = IFIELD( theInstr, 25, 1 );
27464 UInt RA = IFIELD( theInstr, 16, 5 );
27465 UInt SI = IFIELD( theInstr, 11, 5 );
27467 DIP("tabortdci. %u,%u,%u\n", TO, RA, SI);
27468 break;
27471 case 0x38E: { //tbort.
27472 /* The tabort. is just a noop. Do nothing */
27473 UInt RA = IFIELD( theInstr, 16, 5 );
27475 DIP("tabort. %u\n", RA);
27476 break;
27479 case 0x3AE: { //treclaim.
27480 /* The treclaim. is just a noop. Do nothing */
27481 UInt RA = IFIELD( theInstr, 16, 5 );
27483 DIP("treclaim. %u\n", RA);
27484 break;
27487 case 0x3EE: { //trechkpt.
27488 /* The trechkpt. is just a noop. Do nothing */
27489 DIP("trechkpt.\n");
27490 break;
27493 default:
27494 vex_printf("dis_transactional_memory(ppc): unrecognized instruction\n");
27495 return False;
27498 return True;
27502 /* The 0x3C primary opcode (VSX category) uses several different forms of
27503 * extended opcodes:
27504 * o XX2-form:
27505 * - [10:2] (IBM notation [21:29])
27506 * o XX3-form variants:
27507 * - variant 1: [10:3] (IBM notation [21:28])
27508 * - variant 2: [9:3] (IBM notation [22:28])
27509 * - variant 3: [7:3] (IBM notation [24:28])
27510 * o XX-4 form:
27511 * - [10:6] (IBM notation [21:25])
27513 * The XX2-form needs bit 0 masked from the standard extended opcode
27514 * as returned by ifieldOPClo10; the XX3-form needs bits 0 and 1 masked;
27515 * and the XX4-form needs bits 0, 1, and 2 masked. Additionally, the
27516 * XX4 and XX3 (variants 2 and 3) forms need certain bits masked on the
27517 * front end since their encoding does not begin at bit 21 like the standard
27518 * format.
27520 * The get_VSX60_opc2() function uses the vsx_insn array below to obtain the
27521 * secondary opcode for such VSX instructions.
27526 struct vsx_insn {
27527 UInt opcode;
27528 const HChar * name;
27531 // ATTENTION: Keep this array sorted on the opcocde!!!
27532 static struct vsx_insn vsx_xx2[] = {
27533 { 0x14, "xsrsqrtesp" },
27534 { 0x16, "xssqrtsp" },
27535 { 0x18, "xxsel" },
27536 { 0x34, "xsresp" },
27537 { 0x90, "xscvdpuxws" },
27538 { 0x92, "xsrdpi" },
27539 { 0x94, "xsrsqrtedp" },
27540 { 0x96, "xssqrtdp" },
27541 { 0xb0, "xscvdpsxws" },
27542 { 0xb2, "xsrdpiz" },
27543 { 0xb4, "xsredp" },
27544 { 0xd2, "xsrdpip" },
27545 { 0xd4, "xstsqrtdp" },
27546 { 0xd6, "xsrdpic" },
27547 { 0xf2, "xsrdpim" },
27548 { 0x112, "xvrspi" },
27549 { 0x116, "xvsqrtsp" },
27550 { 0x130, "xvcvspsxws" },
27551 { 0x132, "xvrspiz" },
27552 { 0x134, "xvresp" },
27553 { 0x148, "xxspltw" },
27554 { 0x14A, "xxextractuw" },
27555 { 0x150, "xvcvuxwsp" },
27556 { 0x152, "xvrspip" },
27557 { 0x154, "xvtsqrtsp" },
27558 { 0x156, "xvrspic" },
27559 { 0x16A, "xxinsertw" },
27560 { 0x170, "xvcvsxwsp" },
27561 { 0x172, "xvrspim" },
27562 { 0x190, "xvcvdpuxws" },
27563 { 0x192, "xvrdpi" },
27564 { 0x194, "xvrsqrtedp" },
27565 { 0x196, "xvsqrtdp" },
27566 { 0x1b0, "xvcvdpsxws" },
27567 { 0x1b2, "xvrdpiz" },
27568 { 0x1b4, "xvredp" },
27569 { 0x1d0, "xvcvuxwdp" },
27570 { 0x1d2, "xvrdpip" },
27571 { 0x1d4, "xvtsqrtdp" },
27572 { 0x1d6, "xvrdpic" },
27573 { 0x1f0, "xvcvsxwdp" },
27574 { 0x1f2, "xvrdpim" },
27575 { 0x212, "xscvdpsp" },
27576 { 0x216, "xscvdpspn" },
27577 { 0x232, "xxrsp" },
27578 { 0x250, "xscvuxdsp" },
27579 { 0x254, "xststdcsp" },
27580 { 0x270, "xscvsxdsp" },
27581 { 0x290, "xscvdpuxds" },
27582 { 0x292, "xscvspdp" },
27583 { 0x296, "xscvspdpn" },
27584 { 0x2b0, "xscvdpsxds" },
27585 { 0x2b2, "xsabsdp" },
27586 { 0x2b6, "xsxexpdp_xsxigdp" },
27587 { 0x2d0, "xscvuxddp" },
27588 { 0x2d2, "xsnabsdp" },
27589 { 0x2d4, "xststdcdp" },
27590 { 0x2e4, "xsnmsubmdp" },
27591 { 0x2f0, "xscvsxddp" },
27592 { 0x2f2, "xsnegdp" },
27593 { 0x310, "xvcvspuxds" },
27594 { 0x312, "xvcvdpsp" },
27595 { 0x330, "xvcvspsxds" },
27596 { 0x332, "xvabssp" },
27597 { 0x350, "xvcvuxdsp" },
27598 { 0x352, "xvnabssp" },
27599 { 0x370, "xvcvsxdsp" },
27600 { 0x372, "xvnegsp" },
27601 { 0x390, "xvcvdpuxds" },
27602 { 0x392, "xvcvspdp" },
27603 { 0x3b0, "xvcvdpsxds" },
27604 { 0x3b2, "xvabsdp" },
27605 { 0x3b6, "xxbr[h|w|d|q]|xvxexpdp|xvxexpsp|xvxsigdp|xvxsigsp|xvcvhpsp|xvcvsphp|xscvdphp|xscvhpdp" },
27606 { 0x3d0, "xvcvuxddp" },
27607 { 0x3d2, "xvnabsdp" },
27608 { 0x3f2, "xvnegdp" }
27610 #define VSX_XX2_LEN (sizeof vsx_xx2 / sizeof *vsx_xx2)
27612 // ATTENTION: Keep this array sorted on the opcocde!!!
27613 static struct vsx_insn vsx_xx3[] = {
27614 { 0x0, "xsaddsp" },
27615 { 0x4, "xsmaddasp" },
27616 { 0x9, "xsmaddmsp" },
27617 { 0xC, "xscmpeqdp" },
27618 { 0x20, "xssubsp" },
27619 { 0x24, "xsmaddmsp" },
27620 { 0x2C, "xscmpgtdp" },
27621 { 0x3A, "xxpermr" },
27622 { 0x40, "xsmulsp" },
27623 { 0x44, "xsmsubasp" },
27624 { 0x48, "xxmrghw" },
27625 { 0x4C, "xscmpgedp" },
27626 { 0x60, "xsdivsp" },
27627 { 0x64, "xsmsubmsp" },
27628 { 0x68, "xxperm" },
27629 { 0x80, "xsadddp" },
27630 { 0x84, "xsmaddadp" },
27631 { 0x8c, "xscmpudp" },
27632 { 0xa0, "xssubdp" },
27633 { 0xa4, "xsmaddmdp" },
27634 { 0xac, "xscmpodp" },
27635 { 0xc0, "xsmuldp" },
27636 { 0xc4, "xsmsubadp" },
27637 { 0xc8, "xxmrglw" },
27638 { 0xd4, "xstsqrtdp" },
27639 { 0xe0, "xsdivdp" },
27640 { 0xe4, "xsmsubmdp" },
27641 { 0xe8, "xxpermr" },
27642 { 0xeC, "xscmpexpdp" },
27643 { 0xf4, "xstdivdp" },
27644 { 0x100, "xvaddsp" },
27645 { 0x104, "xvmaddasp" },
27646 { 0x10C, "xvcmpeqsp" },
27647 { 0x110, "xvcvspuxws" },
27648 { 0x114, "xvrsqrtesp" },
27649 { 0x120, "xvsubsp" },
27650 { 0x124, "xvmaddmsp" },
27651 { 0x130, "xvcvspsxws" },
27652 { 0x140, "xvmulsp" },
27653 { 0x144, "xvmsubasp" },
27654 { 0x14C, "xvcmpgesp", },
27655 { 0x160, "xvdivsp" },
27656 { 0x164, "xvmsubmsp" },
27657 { 0x174, "xvtdivsp" },
27658 { 0x180, "xvadddp" },
27659 { 0x184, "xvmaddadp" },
27660 { 0x18C, "xvcmpeqdp" },
27661 { 0x1a0, "xvsubdp" },
27662 { 0x1a4, "xvmaddmdp" },
27663 { 0x1aC, "xvcmpgtdp" },
27664 { 0x1c0, "xvmuldp" },
27665 { 0x1c4, "xvmsubadp" },
27666 { 0x1cc, "xvcmpgedp" },
27667 { 0x1e0, "xvdivdp" },
27668 { 0x1e4, "xvmsubmdp" },
27669 { 0x1f4, "xvtdivdp" },
27670 { 0x200, "xsmaxcdp" },
27671 { 0x204, "xsnmaddasp" },
27672 { 0x208, "xxland" },
27673 { 0x220, "xsmincdp" },
27674 { 0x224, "xsnmaddmsp" },
27675 { 0x228, "xxlandc" },
27676 { 0x244, "xsnmsubasp" },
27677 { 0x248, "xxlor" },
27678 { 0x264, "xsnmsubmsp" },
27679 { 0x268, "xxlxor" },
27680 { 0x280, "xsmaxdp" },
27681 { 0x284, "xsnmaddadp" },
27682 { 0x288, "xxlnor" },
27683 { 0x2a0, "xsmindp" },
27684 { 0x2a4, "xsnmaddmdp" },
27685 { 0x2a8, "xxlorc" },
27686 { 0x2c0, "xscpsgndp" },
27687 { 0x2c4, "xsnmsubadp" },
27688 { 0x2c8, "xxlnand" },
27689 { 0x2e4, "xsnmsubmdp" },
27690 { 0x2e8, "xxleqv" },
27691 { 0x300, "xvmaxsp" },
27692 { 0x304, "xvnmaddasp" },
27693 { 0x320, "xvminsp" },
27694 { 0x324, "xvnmaddmsp" },
27695 { 0x340, "xvcpsgnsp" },
27696 { 0x344, "xvnmsubasp" },
27697 { 0x360, "xviexpsp" },
27698 { 0x364, "xvnmsubmsp" },
27699 { 0x380, "xvmaxdp" },
27700 { 0x384, "xvnmaddadp" },
27701 { 0x3a0, "xvmindp" },
27702 { 0x3a4, "xvnmaddmdp" },
27703 { 0x3c0, "xvcpsgndp" },
27704 { 0x3c4, "xvnmsubadp" },
27705 { 0x3e0, "xviexpdp" },
27706 { 0x3e4, "xvnmsubmdp" },
27707 { 0x3f0, "xvcvsxddp" },
27709 #define VSX_XX3_LEN (sizeof vsx_xx3 / sizeof *vsx_xx3)
27712 /* ATTENTION: These search functions assumes vsx_xx2 and vsx_xx3 arrays
27713 * are sorted.
27715 static Int findVSXextOpCode_xx2(UInt opcode)
27717 Int low, mid, high;
27718 low = 0;
27719 high = VSX_XX2_LEN - 1;
27720 while (low <= high) {
27721 mid = (low + high)/2;
27722 if (opcode < vsx_xx2[mid].opcode)
27723 high = mid - 1;
27724 else if (opcode > vsx_xx2[mid].opcode)
27725 low = mid + 1;
27726 else
27727 return mid;
27729 return -1;
27732 static Int findVSXextOpCode_xx3(UInt opcode)
27734 Int low, mid, high;
27735 low = 0;
27736 high = VSX_XX3_LEN - 1;
27737 while (low <= high) {
27738 mid = (low + high)/2;
27739 if (opcode < vsx_xx3[mid].opcode)
27740 high = mid - 1;
27741 else if (opcode > vsx_xx3[mid].opcode)
27742 low = mid + 1;
27743 else
27744 return mid;
27746 return -1;
27750 /* The full 10-bit extended opcode retrieved via ifieldOPClo10 is
27751 * passed, and we then try to match it up with one of the VSX forms
27752 * below.
27754 static UInt get_VSX60_opc2(UInt opc2_full, UInt theInstr)
27756 #define XX2_1_MASK 0x000003FF // xsiexpdp specific
27757 #define XX2_2_MASK 0x000003FE
27758 #define XX3_1_MASK 0x000003FC
27759 #define XX3_2_MASK 0x000001FC
27760 #define XX3_4_MASK 0x0000027C
27761 #define XX3_5_MASK 0x000003DC
27762 #define XX4_MASK 0x00000018
27764 Int ret;
27765 UInt vsxExtOpcode = 0;
27767 if (( ret = findVSXextOpCode_xx2(opc2_full & XX2_2_MASK)) >= 0)
27768 return vsx_xx2[ret].opcode;
27769 else if ((opc2_full & XX2_1_MASK) == 0x396 ) // xsiexpdp
27770 return 0x396;
27771 else if (( ret = findVSXextOpCode_xx3(opc2_full & XX3_1_MASK)) >= 0)
27772 return vsx_xx3[ret].opcode;
27773 else {
27775 /* There are only a few codes in each of these cases it is
27776 * probably faster to check for the codes then do the array lookups.
27778 vsxExtOpcode = opc2_full & XX3_2_MASK;
27780 switch (vsxExtOpcode) {
27781 case 0x10C: return vsxExtOpcode; // xvcmpeqsp
27782 case 0x12C: return vsxExtOpcode; // xvcmpgtsp, xvcmpgtsp.
27783 case 0x14C: return vsxExtOpcode; // xvcmpgesp, xvcmpgesp.
27784 case 0x18C: return vsxExtOpcode; // xvcmpeqdp, xvcmpeqdp.
27785 case 0x1AC: return vsxExtOpcode; // xvcmpgtdp, xvcmpgtdp.
27786 case 0x1CC: return vsxExtOpcode; // xvcmpgedp, xvcmpgedp.
27787 default: break;
27790 vsxExtOpcode = opc2_full & XX3_4_MASK;
27792 switch (vsxExtOpcode) {
27793 case 0x8: return vsxExtOpcode; // xxsldwi
27794 case 0x28: return vsxExtOpcode; // xxpermdi
27795 default: break;
27798 vsxExtOpcode = opc2_full & XX3_5_MASK;
27800 switch (vsxExtOpcode) {
27801 case 0x354: return vsxExtOpcode; // xvtstdcsp
27802 case 0x3D4: return vsxExtOpcode; // xvtstdcdp
27803 default: break;
27806 if (( opc2_full & XX4_MASK ) == XX4_MASK ) { // xxsel
27807 vsxExtOpcode = 0x18;
27808 return vsxExtOpcode;
27812 vex_printf( "Error: undefined opcode 0x %x, the instruction = 0x %x\n",
27813 opc2_full, theInstr );
27814 vpanic( "ERROR: get_VSX60_opc2()\n" );
27815 return 0;
27818 /*------------------------------------------------------------*/
27819 /*--- Disassemble a single instruction ---*/
27820 /*------------------------------------------------------------*/
27822 /* Disassemble a single instruction into IR. The instruction
27823 is located in host memory at &guest_code[delta]. */
27825 static
27826 DisResult disInstr_PPC_WRK (
27827 Bool (*resteerOkFn) ( /*opaque*/void*, Addr ),
27828 Bool resteerCisOk,
27829 void* callback_opaque,
27830 Long delta64,
27831 const VexArchInfo* archinfo,
27832 const VexAbiInfo* abiinfo,
27833 Bool sigill_diag
27836 UChar opc1;
27837 UInt opc2;
27838 DisResult dres;
27839 UInt theInstr;
27840 IRType ty = mode64 ? Ity_I64 : Ity_I32;
27841 UInt hwcaps = archinfo->hwcaps;
27842 Long delta;
27843 Bool allow_F = False;
27844 Bool allow_V = False;
27845 Bool allow_FX = False;
27846 Bool allow_GX = False;
27847 Bool allow_VX = False; // Equates to "supports Power ISA 2.06
27848 Bool allow_DFP = False;
27849 Bool allow_isa_2_07 = False;
27850 Bool allow_isa_3_0 = False;
27852 /* What insn variants are we supporting today? */
27853 if (mode64) {
27854 allow_F = True;
27855 allow_V = (0 != (hwcaps & VEX_HWCAPS_PPC64_V));
27856 allow_FX = (0 != (hwcaps & VEX_HWCAPS_PPC64_FX));
27857 allow_GX = (0 != (hwcaps & VEX_HWCAPS_PPC64_GX));
27858 allow_VX = (0 != (hwcaps & VEX_HWCAPS_PPC64_VX));
27859 allow_DFP = (0 != (hwcaps & VEX_HWCAPS_PPC64_DFP));
27860 allow_isa_2_07 = (0 != (hwcaps & VEX_HWCAPS_PPC64_ISA2_07));
27861 allow_isa_3_0 = (0 != (hwcaps & VEX_HWCAPS_PPC64_ISA3_0));
27862 } else {
27863 allow_F = (0 != (hwcaps & VEX_HWCAPS_PPC32_F));
27864 allow_V = (0 != (hwcaps & VEX_HWCAPS_PPC32_V));
27865 allow_FX = (0 != (hwcaps & VEX_HWCAPS_PPC32_FX));
27866 allow_GX = (0 != (hwcaps & VEX_HWCAPS_PPC32_GX));
27867 allow_VX = (0 != (hwcaps & VEX_HWCAPS_PPC32_VX));
27868 allow_DFP = (0 != (hwcaps & VEX_HWCAPS_PPC32_DFP));
27869 allow_isa_2_07 = (0 != (hwcaps & VEX_HWCAPS_PPC32_ISA2_07));
27870 allow_isa_3_0 = (0 != (hwcaps & VEX_HWCAPS_PPC32_ISA3_0));
27873 /* Enable writting the OV32 and CA32 bits added with ISA3.0 */
27874 OV32_CA32_supported = allow_isa_3_0;
27876 /* The running delta */
27877 delta = (Long)mkSzAddr(ty, (ULong)delta64);
27879 /* Set result defaults. */
27880 dres.whatNext = Dis_Continue;
27881 dres.len = 0;
27882 dres.continueAt = 0;
27883 dres.jk_StopHere = Ijk_INVALID;
27884 dres.hint = Dis_HintNone;
27886 /* At least this is simple on PPC32: insns are all 4 bytes long, and
27887 4-aligned. So just fish the whole thing out of memory right now
27888 and have done. */
27889 theInstr = getUIntPPCendianly( &guest_code[delta] );
27891 if (0) vex_printf("insn: 0x%x\n", theInstr);
27893 DIP("\t0x%llx: ", (ULong)guest_CIA_curr_instr);
27895 /* Spot "Special" instructions (see comment at top of file). */
27897 const UChar* code = guest_code + delta;
27898 /* Spot the 16-byte preamble:
27899 32-bit mode:
27900 5400183E rlwinm 0,0,3,0,31
27901 5400683E rlwinm 0,0,13,0,31
27902 5400E83E rlwinm 0,0,29,0,31
27903 5400983E rlwinm 0,0,19,0,31
27904 64-bit mode:
27905 78001800 rotldi 0,0,3
27906 78006800 rotldi 0,0,13
27907 7800E802 rotldi 0,0,61
27908 78009802 rotldi 0,0,51
27910 UInt word1 = mode64 ? 0x78001800 : 0x5400183E;
27911 UInt word2 = mode64 ? 0x78006800 : 0x5400683E;
27912 UInt word3 = mode64 ? 0x7800E802 : 0x5400E83E;
27913 UInt word4 = mode64 ? 0x78009802 : 0x5400983E;
27914 Bool is_special_preamble = False;
27915 if (getUIntPPCendianly(code+ 0) == word1 &&
27916 getUIntPPCendianly(code+ 4) == word2 &&
27917 getUIntPPCendianly(code+ 8) == word3 &&
27918 getUIntPPCendianly(code+12) == word4) {
27919 is_special_preamble = True;
27920 } else if (! mode64 &&
27921 getUIntPPCendianly(code+ 0) == 0x54001800 &&
27922 getUIntPPCendianly(code+ 4) == 0x54006800 &&
27923 getUIntPPCendianly(code+ 8) == 0x5400E800 &&
27924 getUIntPPCendianly(code+12) == 0x54009800) {
27925 static Bool reported = False;
27926 if (!reported) {
27927 vex_printf("disInstr(ppc): old ppc32 instruction magic detected. Code might clobber r0.\n");
27928 vex_printf("disInstr(ppc): source needs to be recompiled against latest valgrind.h.\n");
27929 reported = True;
27931 is_special_preamble = True;
27933 if (is_special_preamble) {
27934 /* Got a "Special" instruction preamble. Which one is it? */
27935 if (getUIntPPCendianly(code+16) == 0x7C210B78 /* or 1,1,1 */) {
27936 /* %R3 = client_request ( %R4 ) */
27937 DIP("r3 = client_request ( %%r4 )\n");
27938 delta += 20;
27939 putGST( PPC_GST_CIA, mkSzImm( ty, guest_CIA_bbstart + delta ));
27940 dres.jk_StopHere = Ijk_ClientReq;
27941 dres.whatNext = Dis_StopHere;
27942 goto decode_success;
27944 else
27945 if (getUIntPPCendianly(code+16) == 0x7C421378 /* or 2,2,2 */) {
27946 /* %R3 = guest_NRADDR */
27947 DIP("r3 = guest_NRADDR\n");
27948 delta += 20;
27949 dres.len = 20;
27950 putIReg(3, IRExpr_Get( OFFB_NRADDR, ty ));
27951 goto decode_success;
27953 else
27954 if (getUIntPPCendianly(code+16) == 0x7C631B78 /* or 3,3,3 */) {
27955 delta += 20;
27956 if (host_endness == VexEndnessLE) {
27957 /* branch-and-link-to-noredir %R12 */
27958 DIP("branch-and-link-to-noredir r12\n");
27959 putGST( PPC_GST_LR,
27960 mkSzImm(ty, guest_CIA_bbstart + (Long)delta) );
27961 putGST( PPC_GST_CIA, getIReg(12));
27962 } else {
27963 /* branch-and-link-to-noredir %R11 */
27964 DIP("branch-and-link-to-noredir r11\n");
27965 putGST( PPC_GST_LR,
27966 mkSzImm(ty, guest_CIA_bbstart + (Long)delta) );
27967 putGST( PPC_GST_CIA, getIReg(11));
27969 dres.jk_StopHere = Ijk_NoRedir;
27970 dres.whatNext = Dis_StopHere;
27971 goto decode_success;
27973 else
27974 if (getUIntPPCendianly(code+16) == 0x7C842378 /* or 4,4,4 */) {
27975 /* %R3 = guest_NRADDR_GPR2 */
27976 DIP("r3 = guest_NRADDR_GPR2\n");
27977 delta += 20;
27978 dres.len = 20;
27979 putIReg(3, IRExpr_Get( OFFB_NRADDR_GPR2, ty ));
27980 goto decode_success;
27982 else
27983 if (getUIntPPCendianly(code+16) == 0x7CA52B78 /* or 5,5,5 */) {
27984 DIP("IR injection\n");
27985 if (host_endness == VexEndnessBE)
27986 vex_inject_ir(irsb, Iend_BE);
27987 else
27988 vex_inject_ir(irsb, Iend_LE);
27990 delta += 20;
27991 dres.len = 20;
27993 // Invalidate the current insn. The reason is that the IRop we're
27994 // injecting here can change. In which case the translation has to
27995 // be redone. For ease of handling, we simply invalidate all the
27996 // time.
27998 stmt(IRStmt_Put(OFFB_CMSTART, mkSzImm(ty, guest_CIA_curr_instr)));
27999 stmt(IRStmt_Put(OFFB_CMLEN, mkSzImm(ty, 20)));
28001 putGST( PPC_GST_CIA, mkSzImm( ty, guest_CIA_bbstart + delta ));
28002 dres.whatNext = Dis_StopHere;
28003 dres.jk_StopHere = Ijk_InvalICache;
28004 goto decode_success;
28006 /* We don't know what it is. Set opc1/opc2 so decode_failure
28007 can print the insn following the Special-insn preamble. */
28008 theInstr = getUIntPPCendianly(code+16);
28009 opc1 = ifieldOPC(theInstr);
28010 opc2 = ifieldOPClo10(theInstr);
28011 goto decode_failure;
28012 /*NOTREACHED*/
28016 opc1 = ifieldOPC(theInstr);
28017 opc2 = ifieldOPClo10(theInstr);
28019 // Note: all 'reserved' bits must be cleared, else invalid
28020 switch (opc1) {
28022 /* Integer Arithmetic Instructions */
28023 case 0x0C: case 0x0D: case 0x0E: // addic, addic., addi
28024 case 0x0F: case 0x07: case 0x08: // addis, mulli, subfic
28025 if (dis_int_arith( theInstr )) goto decode_success;
28026 goto decode_failure;
28028 /* Integer Compare Instructions */
28029 case 0x0B: case 0x0A: // cmpi, cmpli
28030 if (dis_int_cmp( theInstr )) goto decode_success;
28031 goto decode_failure;
28033 /* Integer Logical Instructions */
28034 case 0x1C: case 0x1D: case 0x18: // andi., andis., ori
28035 case 0x19: case 0x1A: case 0x1B: // oris, xori, xoris
28036 if (dis_int_logic( theInstr )) goto decode_success;
28037 goto decode_failure;
28039 /* Integer Rotate Instructions */
28040 case 0x14: case 0x15: case 0x17: // rlwimi, rlwinm, rlwnm
28041 if (dis_int_rot( theInstr )) goto decode_success;
28042 goto decode_failure;
28044 /* 64bit Integer Rotate Instructions */
28045 case 0x1E: // rldcl, rldcr, rldic, rldicl, rldicr, rldimi
28046 if (!mode64) goto decode_failure;
28047 if (dis_int_rot( theInstr )) goto decode_success;
28048 goto decode_failure;
28050 /* Integer Load Instructions */
28051 case 0x22: case 0x23: case 0x2A: // lbz, lbzu, lha
28052 case 0x2B: case 0x28: case 0x29: // lhau, lhz, lhzu
28053 case 0x20: case 0x21: // lwz, lwzu
28054 if (dis_int_load( theInstr )) goto decode_success;
28055 goto decode_failure;
28057 /* Integer Store Instructions */
28058 case 0x26: case 0x27: case 0x2C: // stb, stbu, sth
28059 case 0x2D: case 0x24: case 0x25: // sthu, stw, stwu
28060 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
28061 goto decode_failure;
28063 /* Integer Load and Store Multiple Instructions */
28064 case 0x2E: case 0x2F: // lmw, stmw
28065 if (dis_int_ldst_mult( theInstr )) goto decode_success;
28066 goto decode_failure;
28068 /* Branch Instructions */
28069 case 0x12: case 0x10: // b, bc
28070 if (dis_branch(theInstr, abiinfo, &dres,
28071 resteerOkFn, callback_opaque))
28072 goto decode_success;
28073 goto decode_failure;
28075 /* System Linkage Instructions */
28076 case 0x11: // sc
28077 if (dis_syslink(theInstr, abiinfo, &dres)) goto decode_success;
28078 goto decode_failure;
28080 /* Trap Instructions */
28081 case 0x02: // tdi
28082 if (!mode64) goto decode_failure;
28083 if (dis_trapi(theInstr, &dres)) goto decode_success;
28084 goto decode_failure;
28086 case 0x03: // twi
28087 if (dis_trapi(theInstr, &dres)) goto decode_success;
28088 goto decode_failure;
28090 /* Floating Point Load Instructions */
28091 case 0x30: case 0x31: case 0x32: // lfs, lfsu, lfd
28092 case 0x33: // lfdu
28093 if (!allow_F) goto decode_noF;
28094 if (dis_fp_load( theInstr )) goto decode_success;
28095 goto decode_failure;
28097 /* Floating Point Store Instructions */
28098 case 0x34: case 0x35: case 0x36: // stfsx, stfsux, stfdx
28099 case 0x37: // stfdux
28100 if (!allow_F) goto decode_noF;
28101 if (dis_fp_store( theInstr )) goto decode_success;
28102 goto decode_failure;
28104 /* Floating Point Load Double Pair Instructions */
28105 case 0x39: case 0x3D: // lfdp, lxsd, lxssp, lxv
28106 // stfdp, stxsd, stxssp, stxv
28107 if (!allow_F) goto decode_noF;
28108 if (dis_fp_pair( theInstr )) goto decode_success;
28109 goto decode_failure;
28111 /* 128-bit Integer Load */
28112 case 0x38: // lq
28113 if (dis_int_load( theInstr )) goto decode_success;
28114 goto decode_failure;
28116 /* 64bit Integer Loads */
28117 case 0x3A: // ld, ldu, lwa
28118 if (!mode64) goto decode_failure;
28119 if (dis_int_load( theInstr )) goto decode_success;
28120 goto decode_failure;
28122 case 0x3B:
28123 if (!allow_F) goto decode_noF;
28124 opc2 = ifieldOPClo10(theInstr);
28126 switch (opc2) {
28127 case 0x2: // dadd - DFP Add
28128 case 0x202: // dsub - DFP Subtract
28129 case 0x22: // dmul - DFP Mult
28130 case 0x222: // ddiv - DFP Divide
28131 if (!allow_DFP) goto decode_noDFP;
28132 if (dis_dfp_arith( theInstr ))
28133 goto decode_success;
28134 case 0x82: // dcmpo, DFP comparison ordered instruction
28135 case 0x282: // dcmpu, DFP comparison unordered instruction
28136 if (!allow_DFP) goto decode_noDFP;
28137 if (dis_dfp_compare( theInstr ) )
28138 goto decode_success;
28139 goto decode_failure;
28140 case 0x102: // dctdp - DFP convert to DFP long
28141 case 0x302: // drsp - DFP round to dfp short
28142 case 0x122: // dctfix - DFP convert to fixed
28143 if (!allow_DFP) goto decode_noDFP;
28144 if (dis_dfp_fmt_conv( theInstr ))
28145 goto decode_success;
28146 goto decode_failure;
28147 case 0x322: // POWER 7 inst, dcffix - DFP convert from fixed
28148 if (!allow_VX)
28149 goto decode_failure;
28150 if (!allow_DFP) goto decode_noDFP;
28151 if (dis_dfp_fmt_conv( theInstr ))
28152 goto decode_success;
28153 goto decode_failure;
28154 case 0x2A2: // dtstsf - DFP number of significant digits
28155 case 0x2A3: // dtstsfi - DFP number of significant digits Immediate
28156 if (!allow_DFP) goto decode_noDFP;
28157 if (dis_dfp_significant_digits(theInstr))
28158 goto decode_success;
28159 goto decode_failure;
28160 case 0x142: // ddedpd DFP Decode DPD to BCD
28161 case 0x342: // denbcd DFP Encode BCD to DPD
28162 if (!allow_DFP) goto decode_noDFP;
28163 if (dis_dfp_bcd(theInstr))
28164 goto decode_success;
28165 goto decode_failure;
28166 case 0x162: // dxex - Extract exponent
28167 case 0x362: // diex - Insert exponent
28168 if (!allow_DFP) goto decode_noDFP;
28169 if (dis_dfp_extract_insert( theInstr ) )
28170 goto decode_success;
28171 goto decode_failure;
28172 case 0x3CE: // fcfidus (implemented as native insn)
28173 if (!allow_VX)
28174 goto decode_noVX;
28175 if (dis_fp_round( theInstr ))
28176 goto decode_success;
28177 goto decode_failure;
28178 case 0x34E: // fcfids
28179 if (dis_fp_round( theInstr ))
28180 goto decode_success;
28181 goto decode_failure;
28184 opc2 = ifieldOPClo9( theInstr );
28185 switch (opc2) {
28186 case 0x42: // dscli, DFP shift left
28187 case 0x62: // dscri, DFP shift right
28188 if (!allow_DFP) goto decode_noDFP;
28189 if (dis_dfp_shift( theInstr ))
28190 goto decode_success;
28191 goto decode_failure;
28192 case 0xc2: // dtstdc, DFP test data class
28193 case 0xe2: // dtstdg, DFP test data group
28194 if (!allow_DFP) goto decode_noDFP;
28195 if (dis_dfp_class_test( theInstr ))
28196 goto decode_success;
28197 goto decode_failure;
28200 opc2 = ifieldOPClo8( theInstr );
28201 switch (opc2) {
28202 case 0x3: // dqua - DFP Quantize
28203 case 0x23: // drrnd - DFP Reround
28204 case 0x43: // dquai - DFP Quantize immediate
28205 if (!allow_DFP) goto decode_noDFP;
28206 if (dis_dfp_quantize_sig_rrnd( theInstr ) )
28207 goto decode_success;
28208 goto decode_failure;
28209 case 0xA2: // dtstex - DFP Test exponent
28210 if (!allow_DFP) goto decode_noDFP;
28211 if (dis_dfp_exponent_test( theInstr ) )
28212 goto decode_success;
28213 goto decode_failure;
28214 case 0x63: // drintx - Round to an integer value
28215 case 0xE3: // drintn - Round to an integer value
28216 if (!allow_DFP) goto decode_noDFP;
28217 if (dis_dfp_round( theInstr ) ) {
28218 goto decode_success;
28220 goto decode_failure;
28221 default:
28222 break; /* fall through to next opc2 check */
28225 opc2 = IFIELD(theInstr, 1, 5);
28226 switch (opc2) {
28227 /* Floating Point Arith Instructions */
28228 case 0x12: case 0x14: case 0x15: // fdivs, fsubs, fadds
28229 case 0x19: // fmuls
28230 if (dis_fp_arith(theInstr)) goto decode_success;
28231 goto decode_failure;
28232 case 0x16: // fsqrts
28233 if (!allow_FX) goto decode_noFX;
28234 if (dis_fp_arith(theInstr)) goto decode_success;
28235 goto decode_failure;
28236 case 0x18: // fres
28237 if (!allow_GX) goto decode_noGX;
28238 if (dis_fp_arith(theInstr)) goto decode_success;
28239 goto decode_failure;
28241 /* Floating Point Mult-Add Instructions */
28242 case 0x1C: case 0x1D: case 0x1E: // fmsubs, fmadds, fnmsubs
28243 case 0x1F: // fnmadds
28244 if (dis_fp_multadd(theInstr)) goto decode_success;
28245 goto decode_failure;
28247 case 0x1A: // frsqrtes
28248 if (!allow_GX) goto decode_noGX;
28249 if (dis_fp_arith(theInstr)) goto decode_success;
28250 goto decode_failure;
28252 default:
28253 goto decode_failure;
28255 break;
28257 case 0x3C: // VSX instructions (except load/store)
28259 // All of these VSX instructions use some VMX facilities, so
28260 // if allow_V is not set, we'll skip trying to decode.
28261 if (!allow_V) goto decode_noVX;
28262 /* The xvtstdcdp and xvtstdcsp instructions do not have a
28263 contiguous opc2 field. The following vsxOpc2 = get_VSX60_opc2()
28264 doesn't correctly match these instructions for dc != 0. So,
28265 we will explicitly look for the two instructions. */
28266 opc2 = ifieldOPClo10(theInstr);
28267 UInt opc2hi = IFIELD(theInstr, 7, 4);
28268 UInt opc2lo = IFIELD(theInstr, 3, 3);
28269 UInt vsxOpc2;
28271 if (( opc2hi == 13 ) && ( opc2lo == 5)) { //xvtstdcsp
28272 if (dis_vxs_misc(theInstr, abiinfo, 0x354, allow_isa_3_0))
28273 goto decode_success;
28274 goto decode_failure;
28277 if (( opc2hi == 15 ) && ( opc2lo == 5)) { //xvtstdcdp
28278 if (dis_vxs_misc(theInstr, abiinfo, 0x3D4, allow_isa_3_0))
28279 goto decode_success;
28280 goto decode_failure;
28283 /* The vsxOpc2 returned is the "normalized" value, representing the
28284 * instructions secondary opcode as taken from the standard secondary
28285 * opcode field [21:30] (IBM notatition), even if the actual field
28286 * is non-standard. These normalized values are given in the opcode
28287 * appendices of the ISA 2.06 document.
28289 if ( ( opc2 == 0x168 ) && ( IFIELD( theInstr, 19, 2 ) == 0 ) )// xxspltib
28291 /* This is a special case of the XX1 form where the RA, RB
28292 * fields hold an immediate value.
28294 if (dis_vxs_misc(theInstr, abiinfo, opc2, allow_isa_3_0)) goto decode_success;
28295 goto decode_failure;
28298 vsxOpc2 = get_VSX60_opc2(opc2, theInstr);
28300 switch (vsxOpc2) {
28301 case 0x8: case 0x28: case 0x48: case 0xc8: // xxsldwi, xxpermdi, xxmrghw, xxmrglw
28302 case 0x068: case 0xE8: // xxperm, xxpermr
28303 case 0x018: case 0x148: // xxsel, xxspltw
28304 if (dis_vx_permute_misc(theInstr, vsxOpc2 ))
28305 goto decode_success;
28306 goto decode_failure;
28307 case 0xC: case 0x2C: case 0x4C: // xscmpeqdp, xscmpgtdp, xscmpgedp
28308 case 0x200: case 0x220: //xsmaxcdp, xsmincdp
28309 if (dis_vx_misc(theInstr, vsxOpc2)) goto decode_success;
28310 goto decode_failure;
28311 case 0x268: case 0x248: case 0x288: // xxlxor, xxlor, xxlnor,
28312 case 0x208: case 0x228: // xxland, xxlandc
28313 case 0x2A8: case 0x2C8: case 0x2E8: // xxlorc, xxlnand, xxleqv
28314 if (dis_vx_logic(theInstr, vsxOpc2)) goto decode_success;
28315 goto decode_failure;
28316 case 0x0ec: // xscmpexpdp
28317 case 0x14A: case 0x16A: // xxextractuw, xxinsertw
28318 case 0x2B2: case 0x2C0: // xsabsdp, xscpsgndp
28319 case 0x2D2: case 0x2F2: // xsnabsdp, xsnegdp
28320 case 0x280: case 0x2A0: // xsmaxdp, xsmindp
28321 case 0x0F2: case 0x0D2: // xsrdpim, xsrdpip
28322 case 0x034: case 0x014: // xsresp, xsrsqrtesp
28323 case 0x0B4: case 0x094: // xsredp, xsrsqrtedp
28324 case 0x0D6: case 0x0B2: // xsrdpic, xsrdpiz
28325 case 0x092: case 0x232: // xsrdpi, xsrsp
28326 case 0x3B6: // xxbrh, xvxexpdp, xvxexpsp, xvxsigdp
28327 // xvxsigsp, xvcvhpsp
28328 case 0x2b6: // xsxexpdp, xsxsigdp
28329 case 0x254: case 0x2d4: // xststdcsp, xststdcdp
28330 case 0x354: // xvtstdcsp
28331 case 0x360:case 0x396: // xviexpsp, xsiexpdp
28332 case 0x3D4: case 0x3E0: // xvtstdcdp, xviexpdp
28333 if (dis_vxs_misc(theInstr, abiinfo, vsxOpc2, allow_isa_3_0))
28334 goto decode_success;
28335 goto decode_failure;
28336 case 0x08C: case 0x0AC: // xscmpudp, xscmpodp
28337 if (dis_vx_cmp(theInstr, vsxOpc2)) goto decode_success;
28338 goto decode_failure;
28339 case 0x0: case 0x020: // xsaddsp, xssubsp
28340 case 0x080: // xsadddp
28341 case 0x060: case 0x0E0: // xsdivsp, xsdivdp
28342 case 0x004: case 0x024: // xsmaddasp, xsmaddmsp
28343 case 0x084: case 0x0A4: // xsmaddadp, xsmaddmdp
28344 case 0x044: case 0x064: // xsmsubasp, xsmsubmsp
28345 case 0x0C4: case 0x0E4: // xsmsubadp, xsmsubmdp
28346 case 0x204: case 0x224: // xsnmaddasp, xsnmaddmsp
28347 case 0x284: case 0x2A4: // xsnmaddadp, xsnmaddmdp
28348 case 0x244: case 0x264: // xsnmsubasp, xsnmsubmsp
28349 case 0x2C4: case 0x2E4: // xsnmsubadp, xsnmsubmdp
28350 case 0x040: case 0x0C0: // xsmulsp, xsmuldp
28351 case 0x0A0: // xssubdp
28352 case 0x016: case 0x096: // xssqrtsp,xssqrtdp
28353 case 0x0F4: case 0x0D4: // xstdivdp, xstsqrtdp
28354 if (dis_vxs_arith(theInstr, vsxOpc2)) goto decode_success;
28355 goto decode_failure;
28356 case 0x180: // xvadddp
28357 case 0x1E0: // xvdivdp
28358 case 0x1C0: // xvmuldp
28359 case 0x1A0: // xvsubdp
28360 case 0x184: case 0x1A4: // xvmaddadp, xvmaddmdp
28361 case 0x1C4: case 0x1E4: // xvmsubadp, xvmsubmdp
28362 case 0x384: case 0x3A4: // xvnmaddadp, xvnmaddmdp
28363 case 0x3C4: case 0x3E4: // xvnmsubadp, xvnmsubmdp
28364 case 0x1D4: case 0x1F4: // xvtsqrtdp, xvtdivdp
28365 case 0x196: // xvsqrtdp
28366 if (dis_vxv_dp_arith(theInstr, vsxOpc2)) goto decode_success;
28367 goto decode_failure;
28368 case 0x100: // xvaddsp
28369 case 0x160: // xvdivsp
28370 case 0x140: // xvmulsp
28371 case 0x120: // xvsubsp
28372 case 0x104: case 0x124: // xvmaddasp, xvmaddmsp
28373 case 0x144: case 0x164: // xvmsubasp, xvmsubmsp
28374 case 0x304: case 0x324: // xvnmaddasp, xvnmaddmsp
28375 case 0x344: case 0x364: // xvnmsubasp, xvnmsubmsp
28376 case 0x154: case 0x174: // xvtsqrtsp, xvtdivsp
28377 case 0x116: // xvsqrtsp
28378 if (dis_vxv_sp_arith(theInstr, vsxOpc2)) goto decode_success;
28379 goto decode_failure;
28381 case 0x250: // xscvuxdsp
28382 case 0x2D0: case 0x3d0: // xscvuxddp, xvcvuxddp
28383 case 0x350: case 0x1d0: // xvcvuxdsp, xvcvuxwdp
28384 case 0x090: // xscvdpuxws
28385 // The above VSX conversion instructions employ some ISA 2.06
28386 // floating point conversion instructions under the covers,
28387 // so if allow_VX (which means "supports ISA 2.06") is not set,
28388 // we'll skip the decode.
28389 if (!allow_VX) goto decode_noVX;
28390 if (dis_vx_conv(theInstr, vsxOpc2)) goto decode_success;
28391 goto decode_failure;
28393 case 0x2B0: // xscvdpsxds
28394 case 0x270: case 0x2F0: // xscvsxdsp, xscvsxddp
28395 case 0x1b0: case 0x130: // xvcvdpsxws, xvcvspsxws
28396 case 0x0b0: case 0x290: // xscvdpsxws, xscvdpuxds
28397 case 0x212: case 0x216: // xscvdpsp, xscvdpspn
28398 case 0x292: case 0x296: // xscvspdp, xscvspdpn
28399 case 0x312: // xvcvdpsp
28400 case 0x390: case 0x190: // xvcvdpuxds, xvcvdpuxws
28401 case 0x3B0: case 0x310: // xvcvdpsxds, xvcvspuxds
28402 case 0x392: case 0x330: // xvcvspdp, xvcvspsxds
28403 case 0x110: case 0x3f0: // xvcvspuxws, xvcvsxddp
28404 case 0x370: case 0x1f0: // xvcvsxdsp, xvcvsxwdp
28405 case 0x170: case 0x150: // xvcvsxwsp, xvcvuxwsp
28406 if (dis_vx_conv(theInstr, vsxOpc2)) goto decode_success;
28407 goto decode_failure;
28409 case 0x18C: // xvcmpeqdp[.]
28410 case 0x10C: // xvcmpeqsp[.]
28411 case 0x14C: // xvcmpgesp[.]
28412 case 0x12C: // xvcmpgtsp[.]
28413 case 0x1CC: // xvcmpgedp[.]
28414 case 0x1AC: // xvcmpgtdp[.]
28415 if (dis_vvec_cmp(theInstr, vsxOpc2)) goto decode_success;
28416 goto decode_failure;
28418 case 0x134: // xvresp
28419 case 0x1B4: // xvredp
28420 case 0x194: case 0x114: // xvrsqrtedp, xvrsqrtesp
28421 case 0x380: case 0x3A0: // xvmaxdp, xvmindp
28422 case 0x300: case 0x320: // xvmaxsp, xvminsp
28423 case 0x3C0: case 0x340: // xvcpsgndp, xvcpsgnsp
28424 case 0x3B2: case 0x332: // xvabsdp, xvabssp
28425 case 0x3D2: case 0x352: // xvnabsdp, xvnabssp
28426 case 0x192: case 0x1D6: // xvrdpi, xvrdpic
28427 case 0x1F2: case 0x1D2: // xvrdpim, xvrdpip
28428 case 0x1B2: case 0x3F2: // xvrdpiz, xvnegdp
28429 case 0x112: case 0x156: // xvrspi, xvrspic
28430 case 0x172: case 0x152: // xvrspim, xvrspip
28431 case 0x132: // xvrspiz
28432 if (dis_vxv_misc(theInstr, vsxOpc2)) goto decode_success;
28433 goto decode_failure;
28435 default:
28436 goto decode_failure;
28438 break;
28441 /* 64bit Integer Stores */
28442 case 0x3E: // std, stdu, stq
28443 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
28444 goto decode_failure;
28446 case 0x3F:
28447 if (!allow_F) goto decode_noF;
28448 /* Instrs using opc[1:5] never overlap instrs using opc[1:10],
28449 so we can simply fall through the first switch statement */
28451 opc2 = IFIELD(theInstr, 1, 5);
28452 switch (opc2) {
28453 /* Floating Point Arith Instructions */
28454 case 0x12: case 0x14: case 0x15: // fdiv, fsub, fadd
28455 case 0x19: // fmul
28456 if (dis_fp_arith(theInstr)) goto decode_success;
28457 goto decode_failure;
28458 case 0x16: // fsqrt
28459 if (!allow_FX) goto decode_noFX;
28460 if (dis_fp_arith(theInstr)) goto decode_success;
28461 goto decode_failure;
28462 case 0x17: case 0x1A: // fsel, frsqrte
28463 if (!allow_GX) goto decode_noGX;
28464 if (dis_fp_arith(theInstr)) goto decode_success;
28465 goto decode_failure;
28467 /* Floating Point Mult-Add Instructions */
28468 case 0x1C: case 0x1D: case 0x1E: // fmsub, fmadd, fnmsub
28469 case 0x1F: // fnmadd
28470 if (dis_fp_multadd(theInstr)) goto decode_success;
28471 goto decode_failure;
28473 case 0x18: // fre
28474 if (!allow_GX) goto decode_noGX;
28475 if (dis_fp_arith(theInstr)) goto decode_success;
28476 goto decode_failure;
28478 default:
28479 break; // Fall through
28482 opc2 = IFIELD(theInstr, 1, 8);
28483 switch (opc2) {
28484 case 0x5: // xsrqpi, xsrqpix
28485 case 0x25: // xsrqpxp
28486 if ( !mode64 || !allow_isa_3_0 ) goto decode_failure;
28487 if ( dis_vx_Scalar_Round_to_quad_integer( theInstr, abiinfo ) )
28488 goto decode_success;
28489 goto decode_failure;
28490 default:
28491 break; // Fall through
28494 opc2 = IFIELD(theInstr, 1, 10);
28495 UInt inst_select = IFIELD( theInstr, 16, 5 );
28497 switch (opc2) {
28498 /* 128-bit DFP instructions */
28499 case 0x2: // daddq - DFP Add
28500 case 0x202: // dsubq - DFP Subtract
28501 case 0x22: // dmulq - DFP Mult
28502 case 0x222: // ddivq - DFP Divide
28503 if (!allow_DFP) goto decode_noDFP;
28504 if (dis_dfp_arithq( theInstr ))
28505 goto decode_success;
28506 goto decode_failure;
28507 case 0x162: // dxexq - DFP Extract exponent
28508 case 0x362: // diexq - DFP Insert exponent
28509 if (!allow_DFP) goto decode_noDFP;
28510 if (dis_dfp_extract_insertq( theInstr ))
28511 goto decode_success;
28512 goto decode_failure;
28514 case 0x82: // dcmpoq, DFP comparison ordered instruction
28515 case 0x282: // dcmpuq, DFP comparison unordered instruction
28516 if (!allow_DFP) goto decode_noDFP;
28517 if (dis_dfp_compare( theInstr ) )
28518 goto decode_success;
28519 goto decode_failure;
28521 case 0x102: // dctqpq - DFP convert to DFP extended
28522 case 0x302: // drdpq - DFP round to dfp Long
28523 case 0x122: // dctfixq - DFP convert to fixed quad
28524 case 0x322: // dcffixq - DFP convert from fixed quad
28525 if (!allow_DFP) goto decode_noDFP;
28526 if (dis_dfp_fmt_convq( theInstr ))
28527 goto decode_success;
28528 goto decode_failure;
28530 case 0x2A2: // dtstsfq - DFP number of significant digits
28531 case 0x2A3: // dtstsfiq - DFP number of significant digits Immediate
28532 if (!allow_DFP) goto decode_noDFP;
28533 if (dis_dfp_significant_digits(theInstr))
28534 goto decode_success;
28535 goto decode_failure;
28537 case 0x142: // ddedpdq DFP Decode DPD to BCD
28538 case 0x342: // denbcdq DFP Encode BCD to DPD
28539 if (!allow_DFP) goto decode_noDFP;
28540 if (dis_dfp_bcdq(theInstr))
28541 goto decode_success;
28542 goto decode_failure;
28544 /* Floating Point Compare Instructions */
28545 case 0x000: // fcmpu
28546 case 0x020: // fcmpo
28547 if (dis_fp_cmp(theInstr)) goto decode_success;
28548 goto decode_failure;
28550 case 0x080: // ftdiv
28551 case 0x0A0: // ftsqrt
28552 if (dis_fp_tests(theInstr)) goto decode_success;
28553 goto decode_failure;
28555 /* Floating Point Rounding/Conversion Instructions */
28556 case 0x00C: // frsp
28557 case 0x00E: // fctiw
28558 case 0x00F: // fctiwz
28559 case 0x32E: // fctid
28560 case 0x32F: // fctidz
28561 case 0x34E: // fcfid
28562 if (dis_fp_round(theInstr)) goto decode_success;
28563 goto decode_failure;
28564 case 0x3CE: case 0x3AE: case 0x3AF: // fcfidu, fctidu[z] (implemented as native insns)
28565 case 0x08F: case 0x08E: // fctiwu[z] (implemented as native insns)
28566 if (!allow_VX) goto decode_noVX;
28567 if (dis_fp_round(theInstr)) goto decode_success;
28568 goto decode_failure;
28570 /* Power6 rounding stuff */
28571 case 0x1E8: // frim
28572 case 0x1C8: // frip
28573 case 0x188: // frin
28574 case 0x1A8: // friz
28575 /* A hack to check for P6 capability . . . */
28576 if ((allow_F && allow_V && allow_FX && allow_GX) &&
28577 (dis_fp_round(theInstr)))
28578 goto decode_success;
28579 goto decode_failure;
28581 /* Floating Point Move Instructions */
28582 case 0x008: // fcpsgn
28583 case 0x028: // fneg
28584 case 0x048: // fmr
28585 case 0x088: // fnabs
28586 case 0x108: // fabs
28587 if (dis_fp_move( theInstr )) goto decode_success;
28588 goto decode_failure;
28590 case 0x3c6: case 0x346: // fmrgew, fmrgow
28591 if (dis_fp_merge( theInstr )) goto decode_success;
28592 goto decode_failure;
28594 /* Floating Point Status/Control Register Instructions */
28595 case 0x026: // mtfsb1
28596 case 0x040: // mcrfs
28597 case 0x046: // mtfsb0
28598 case 0x086: // mtfsfi
28599 case 0x247: // mffs, mmfs., mffsce, mffscdrn, mffscdrni,
28600 // mffscrn, mffscrn, mffscri, mffsl
28601 case 0x2C7: // mtfsf
28602 // Some of the above instructions need to know more about the
28603 // ISA level supported by the host.
28604 if (dis_fp_scr( theInstr, allow_GX )) goto decode_success;
28605 goto decode_failure;
28607 case 0x324: // xsabsqp, xsxexpqp,xsnabsqp, xsnegqp, xsxsigqp
28608 if ( inst_select == 27 ) { // xssqrtqp
28609 if ( dis_vx_Floating_Point_Arithmetic_quad_precision( theInstr,
28610 abiinfo ) )
28611 goto decode_success;
28614 /* Instructions implemented with Pre ISA 3.0 Iops */
28615 /* VSX Scalar Quad-Precision instructions */
28616 case 0x064: // xscpsgnqp
28617 case 0x0A4: // xscmpexpqp
28618 case 0x084: // xscmpoqp
28619 case 0x284: // xscmpuqp
28620 case 0x2C4: // xststdcqp
28621 case 0x364: // xsiexpqp
28622 if (dis_vx_scalar_quad_precision( theInstr )) goto decode_success;
28623 goto decode_failure;
28625 /* Instructions implemented using ISA 3.0 instructions */
28626 // xsaddqpo (VSX Scalar Add Quad-Precision [using round to ODD]
28627 case 0x004: // xsaddqp (VSX Scalar Add Quad-Precision [using RN mode]
28628 // xsmulqpo (VSX Scalar Multiply Quad-Precision [using round to ODD]
28629 case 0x024: // xsmulqp (VSX Scalar Multiply Quad-Precision [using RN mode]
28630 // xsmaddqpo (VSX Scalar Multiply Add Quad-Precision [using round to ODD]
28631 case 0x184: // xsmaddqp (VSX Scalar Multiply Add Quad-Precision [using RN mode]
28632 // xsmsubqpo (VSX Scalar Multiply Sub Quad-Precision [using round to ODD]
28633 case 0x1A4: // xsmsubqp (VSX Scalar Multiply Sub Quad-Precision [using RN mode]
28634 // xsnmaddqpo (VSX Scalar Negative Multiply Add Quad-Precision [using round to ODD]
28635 case 0x1C4: // xsnmaddqp (VSX Scalar Negative Multiply Add Quad-Precision [using RN mode]
28636 // xsnmsubqpo (VSX Scalar Negative Multiply Sub Quad-Precision [using round to ODD]
28637 case 0x1E4: // xsnmsubqp (VSX Scalar Negative Multiply Sub Quad-Precision [usin RN mode]
28638 // xssubqpo (VSX Scalar Subrtact Quad-Precision [using round to ODD]
28639 case 0x204: // xssubqp (VSX Scalar Subrtact Quad-Precision [using RN mode]
28640 // xsdivqpo (VSX Scalar Divde Quad-Precision [using round to ODD]
28641 case 0x224: // xsdivqp (VSX Scalar Divde Quad-Precision [using RN mode]
28642 case 0x344: // xscvudqp, xscvsdqp, xscvqpdp, xscvqpdpo, xsvqpdp
28643 // xscvqpswz, xscvqpuwz, xscvqpudz, xscvqpsdz
28644 if ( !mode64 || !allow_isa_3_0 ) goto decode_failure;
28645 if ( dis_vx_Floating_Point_Arithmetic_quad_precision( theInstr,
28646 abiinfo ) )
28647 goto decode_success;
28648 goto decode_failure;
28650 default:
28651 break; // Fall through...
28654 opc2 = ifieldOPClo9( theInstr );
28655 switch (opc2) {
28656 case 0x42: // dscli, DFP shift left
28657 case 0x62: // dscri, DFP shift right
28658 if (!allow_DFP) goto decode_noDFP;
28659 if (dis_dfp_shiftq( theInstr ))
28660 goto decode_success;
28661 goto decode_failure;
28662 case 0xc2: // dtstdc, DFP test data class
28663 case 0xe2: // dtstdg, DFP test data group
28664 if (!allow_DFP) goto decode_noDFP;
28665 if (dis_dfp_class_test( theInstr ))
28666 goto decode_success;
28667 goto decode_failure;
28668 default:
28669 break;
28672 opc2 = ifieldOPClo8( theInstr );
28673 switch (opc2) {
28674 case 0x3: // dquaq - DFP Quantize Quad
28675 case 0x23: // drrndq - DFP Reround Quad
28676 case 0x43: // dquaiq - DFP Quantize immediate Quad
28677 if (!allow_DFP) goto decode_noDFP;
28678 if (dis_dfp_quantize_sig_rrndq( theInstr ))
28679 goto decode_success;
28680 goto decode_failure;
28681 case 0xA2: // dtstexq - DFP Test exponent Quad
28682 if (!allow_DFP) goto decode_noDFP;
28683 if (dis_dfp_exponent_test( theInstr ) )
28684 goto decode_success;
28685 goto decode_failure;
28686 case 0x63: // drintxq - DFP Round to an integer value
28687 case 0xE3: // drintnq - DFP Round to an integer value
28688 if (!allow_DFP) goto decode_noDFP;
28689 if (dis_dfp_roundq( theInstr ))
28690 goto decode_success;
28691 goto decode_failure;
28693 default:
28694 goto decode_failure;
28696 break;
28698 case 0x13:
28700 opc2 = ifieldOPClo5(theInstr);
28701 switch (opc2) {
28703 /* PC relative load/store */
28704 case 0x002: // addpcis
28705 if (dis_pc_relative(theInstr)) goto decode_success;
28706 goto decode_failure;
28708 /* fall through to the next opc2 field size */
28711 opc2 = ifieldOPClo10(theInstr);
28712 switch (opc2) {
28714 /* Condition Register Logical Instructions */
28715 case 0x101: case 0x081: case 0x121: // crand, crandc, creqv
28716 case 0x0E1: case 0x021: case 0x1C1: // crnand, crnor, cror
28717 case 0x1A1: case 0x0C1: case 0x000: // crorc, crxor, mcrf
28718 if (dis_cond_logic( theInstr )) goto decode_success;
28719 goto decode_failure;
28721 /* Branch Instructions */
28722 case 0x210: case 0x010: // bcctr, bclr
28723 if (dis_branch(theInstr, abiinfo, &dres,
28724 resteerOkFn, callback_opaque))
28725 goto decode_success;
28726 goto decode_failure;
28728 /* Memory Synchronization Instructions */
28729 case 0x096: // isync
28730 if (dis_memsync( theInstr )) goto decode_success;
28731 goto decode_failure;
28733 default:
28734 goto decode_failure;
28736 break;
28739 case 0x1F:
28741 /* For arith instns, bit10 is the OE flag (overflow enable) */
28743 opc2 = IFIELD(theInstr, 1, 9);
28744 switch (opc2) {
28745 /* Integer Arithmetic Instructions */
28746 case 0x10A: case 0x00A: case 0x08A: // add, addc, adde
28747 case 0x0AA: // addex
28748 case 0x0EA: case 0x0CA: case 0x1EB: // addme, addze, divw
28749 case 0x1CB: case 0x04B: case 0x00B: // divwu, mulhw, mulhwu
28750 case 0x0EB: case 0x068: case 0x028: // mullw, neg, subf
28751 case 0x008: case 0x088: case 0x0E8: // subfc, subfe, subfme
28752 case 0x0C8: // subfze
28753 if (dis_int_arith( theInstr )) goto decode_success;
28754 goto decode_failure;
28756 case 0x18B: // divweu (implemented as native insn)
28757 case 0x1AB: // divwe (implemented as native insn)
28758 if (!allow_VX) goto decode_noVX;
28759 if (dis_int_arith( theInstr )) goto decode_success;
28760 goto decode_failure;
28762 /* 64bit Integer Arithmetic */
28763 case 0x009: case 0x049: case 0x0E9: // mulhdu, mulhd, mulld
28764 case 0x1C9: case 0x1E9: // divdu, divd
28765 if (!mode64) goto decode_failure;
28766 if (dis_int_arith( theInstr )) goto decode_success;
28767 goto decode_failure;
28769 case 0x1A9: // divde (implemented as native insn)
28770 case 0x189: // divdeuo (implemented as native insn)
28771 if (!allow_VX) goto decode_noVX;
28772 if (!mode64) goto decode_failure;
28773 if (dis_int_arith( theInstr )) goto decode_success;
28774 goto decode_failure;
28776 case 0x1FC: // cmpb
28777 if (dis_int_logic( theInstr )) goto decode_success;
28778 goto decode_failure;
28780 default:
28781 break; // Fall through...
28784 /* All remaining opcodes use full 10 bits. */
28786 opc2 = IFIELD(theInstr, 1, 10);
28787 switch (opc2) {
28789 /* Integer miscellaneous instructions */
28790 case 0x01E: // wait RFC 2500
28791 if (dis_int_misc( theInstr )) goto decode_success;
28792 goto decode_failure;
28795 /* Integer Compare Instructions */
28796 case 0x000: case 0x020: case 0x080: // cmp, cmpl, setb
28797 if (dis_int_cmp( theInstr )) goto decode_success;
28798 goto decode_failure;
28800 case 0x0C0: case 0x0E0: // cmprb, cmpeqb
28801 if (dis_byte_cmp( theInstr )) goto decode_success;
28802 goto decode_failure;
28804 case 0x10B: case 0x30B: // moduw, modsw
28805 case 0x109: case 0x309: // modsd, modud
28806 case 0x21A: case 0x23A: // cnttzw, cnttzd
28807 if (dis_modulo_int( theInstr )) goto decode_success;
28808 goto decode_failure;
28810 /* Integer Logical Instructions */
28811 case 0x01C: case 0x03C: case 0x01A: // and, andc, cntlzw
28812 case 0x11C: case 0x3BA: case 0x39A: // eqv, extsb, extsh
28813 case 0x1DC: case 0x07C: case 0x1BC: // nand, nor, or
28814 case 0x19C: case 0x13C: // orc, xor
28815 case 0x2DF: case 0x25F: // mftgpr, mffgpr
28816 if (dis_int_logic( theInstr )) goto decode_success;
28817 goto decode_failure;
28819 case 0x28E: case 0x2AE: // tbegin., tend.
28820 case 0x2EE: case 0x2CE: case 0x30E: // tsr., tcheck., tabortwc.
28821 case 0x32E: case 0x34E: case 0x36E: // tabortdc., tabortwci., tabortdci.
28822 case 0x38E: case 0x3AE: case 0x3EE: // tabort., treclaim., trechkpt.
28823 if (dis_transactional_memory( theInstr,
28824 getUIntPPCendianly( &guest_code[delta + 4]),
28825 abiinfo, &dres,
28826 resteerOkFn, callback_opaque))
28827 goto decode_success;
28828 goto decode_failure;
28830 /* 64bit Integer Logical Instructions */
28831 case 0x3DA: case 0x03A: // extsw, cntlzd
28832 if (!mode64) goto decode_failure;
28833 if (dis_int_logic( theInstr )) goto decode_success;
28834 goto decode_failure;
28836 /* 64bit Integer Parity Instructions */
28837 case 0xba: // prtyd
28838 if (!mode64) goto decode_failure;
28839 if (dis_int_parity( theInstr )) goto decode_success;
28840 goto decode_failure;
28842 case 0x9a: // prtyw
28843 if (dis_int_parity( theInstr )) goto decode_success;
28844 goto decode_failure;
28846 /* Integer Shift Instructions */
28847 case 0x018: case 0x318: case 0x338: // slw, sraw, srawi
28848 case 0x218: // srw
28849 if (dis_int_shift( theInstr )) goto decode_success;
28850 goto decode_failure;
28852 /* 64bit Integer Shift Instructions */
28853 case 0x01B: case 0x31A: // sld, srad
28854 case 0x33A: case 0x33B: // sradi
28855 case 0x21B: // srd
28856 if (!mode64) goto decode_failure;
28857 if (dis_int_shift( theInstr )) goto decode_success;
28858 goto decode_failure;
28860 /* Integer Load Instructions */
28861 case 0x057: case 0x077: case 0x157: // lbzx, lbzux, lhax
28862 case 0x177: case 0x117: case 0x137: // lhaux, lhzx, lhzux
28863 case 0x017: case 0x037: // lwzx, lwzux
28864 if (dis_int_load( theInstr )) goto decode_success;
28865 goto decode_failure;
28867 /* 64bit Integer Load Instructions */
28868 case 0x035: case 0x015: // ldux, ldx
28869 case 0x175: case 0x155: // lwaux, lwax
28870 if (!mode64) goto decode_failure;
28871 if (dis_int_load( theInstr )) goto decode_success;
28872 goto decode_failure;
28874 /* Integer Store Instructions */
28875 case 0x0F7: case 0x0D7: case 0x1B7: // stbux, stbx, sthux
28876 case 0x197: case 0x0B7: case 0x097: // sthx, stwux, stwx
28877 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
28878 goto decode_failure;
28880 /* 64bit Integer Store Instructions */
28881 case 0x0B5: case 0x095: // stdux, stdx
28882 if (!mode64) goto decode_failure;
28883 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
28884 goto decode_failure;
28886 /* Integer Load and Store with Byte Reverse Instructions */
28887 case 0x214: case 0x294: // ldbrx, stdbrx
28888 if (!mode64) goto decode_failure;
28889 if (dis_int_ldst_rev( theInstr )) goto decode_success;
28890 goto decode_failure;
28892 case 0x216: case 0x316: case 0x296: // lwbrx, lhbrx, stwbrx
28893 case 0x396: // sthbrx
28894 if (dis_int_ldst_rev( theInstr )) goto decode_success;
28895 goto decode_failure;
28897 /* Integer Load and Store String Instructions */
28898 case 0x255: case 0x215: case 0x2D5: // lswi, lswx, stswi
28899 case 0x295: { // stswx
28900 Bool stopHere = False;
28901 Bool ok = dis_int_ldst_str( theInstr, &stopHere );
28902 if (!ok) goto decode_failure;
28903 if (stopHere) {
28904 putGST( PPC_GST_CIA, mkSzImm(ty, nextInsnAddr()) );
28905 dres.jk_StopHere = Ijk_Boring;
28906 dres.whatNext = Dis_StopHere;
28908 goto decode_success;
28911 /* Memory Synchronization Instructions */
28912 case 0x034: case 0x074: // lbarx, lharx
28913 case 0x2B6: case 0x2D6: // stbcx, sthcx
28914 if (!allow_isa_2_07) goto decode_noP8;
28915 if (dis_memsync( theInstr )) goto decode_success;
28916 goto decode_failure;
28918 case 0x356: case 0x014: case 0x096: // eieio, lwarx, stwcx.
28919 case 0x256: // sync
28920 if (dis_memsync( theInstr )) goto decode_success;
28921 goto decode_failure;
28923 /* 64bit Memory Synchronization Instructions */
28924 case 0x054: case 0x0D6: // ldarx, stdcx.
28925 if (!mode64) goto decode_failure;
28926 if (dis_memsync( theInstr )) goto decode_success;
28927 goto decode_failure;
28929 case 0x114: case 0x0B6: // lqarx, stqcx.
28930 if (dis_memsync( theInstr )) goto decode_success;
28931 goto decode_failure;
28933 /* Processor Control Instructions */
28934 case 0x33: case 0x73: // mfvsrd, mfvsrwz
28935 case 0xB3: case 0xD3: case 0xF3: // mtvsrd, mtvsrwa, mtvsrwz
28936 case 0x200: case 0x013: case 0x153: // mcrxr, mfcr, mfspr
28937 case 0x173: case 0x090: case 0x1D3: // mftb, mtcrf, mtspr
28938 case 0x220: // mcrxrt
28939 if (dis_proc_ctl( abiinfo, theInstr )) goto decode_success;
28940 goto decode_failure;
28942 /* Cache Management Instructions */
28943 case 0x2F6: case 0x056: case 0x036: // dcba, dcbf, dcbst
28944 case 0x116: case 0x0F6: case 0x3F6: // dcbt, dcbtst, dcbz
28945 case 0x3D6: // icbi
28946 if (dis_cache_manage( theInstr, &dres, archinfo ))
28947 goto decode_success;
28948 goto decode_failure;
28950 //zz /* External Control Instructions */
28951 //zz case 0x136: case 0x1B6: // eciwx, ecowx
28952 //zz DIP("external control op => not implemented\n");
28953 //zz goto decode_failure;
28955 /* Trap Instructions */
28956 case 0x004: // tw
28957 if (dis_trap(theInstr, &dres)) goto decode_success;
28958 goto decode_failure;
28960 case 0x044: // td
28961 if (!mode64) goto decode_failure;
28962 if (dis_trap(theInstr, &dres)) goto decode_success;
28963 goto decode_failure;
28965 /* Floating Point Load Instructions */
28966 case 0x217: case 0x237: case 0x257: // lfsx, lfsux, lfdx
28967 case 0x277: // lfdux
28968 if (!allow_F) goto decode_noF;
28969 if (dis_fp_load( theInstr )) goto decode_success;
28970 goto decode_failure;
28972 /* Floating Point Store Instructions */
28973 case 0x297: case 0x2B7: case 0x2D7: // stfs, stfsu, stfd
28974 case 0x2F7: // stfdu, stfiwx
28975 if (!allow_F) goto decode_noF;
28976 if (dis_fp_store( theInstr )) goto decode_success;
28977 goto decode_failure;
28978 case 0x3D7: // stfiwx
28979 if (!allow_F) goto decode_noF;
28980 if (!allow_GX) goto decode_noGX;
28981 if (dis_fp_store( theInstr )) goto decode_success;
28982 goto decode_failure;
28984 /* Floating Point Double Pair Indexed Instructions */
28985 case 0x317: // lfdpx (Power6)
28986 case 0x397: // stfdpx (Power6)
28987 if (!allow_F) goto decode_noF;
28988 if (dis_fp_pair(theInstr)) goto decode_success;
28989 goto decode_failure;
28991 case 0x357: // lfiwax
28992 if (!allow_F) goto decode_noF;
28993 if (dis_fp_load( theInstr )) goto decode_success;
28994 goto decode_failure;
28996 case 0x377: // lfiwzx
28997 if (!allow_F) goto decode_noF;
28998 if (dis_fp_load( theInstr )) goto decode_success;
28999 goto decode_failure;
29001 /* AltiVec instructions */
29003 /* AV Cache Control - Data streams */
29004 case 0x156: case 0x176: case 0x336: // dst, dstst, dss
29005 if (!allow_V) goto decode_noV;
29006 if (dis_av_datastream( theInstr )) goto decode_success;
29007 goto decode_failure;
29009 /* AV Load */
29010 case 0x006: case 0x026: // lvsl, lvsr
29011 case 0x007: case 0x027: case 0x047: // lvebx, lvehx, lvewx
29012 case 0x067: case 0x167: // lvx, lvxl
29013 if (!allow_V) goto decode_noV;
29014 if (dis_av_load( abiinfo, theInstr )) goto decode_success;
29015 goto decode_failure;
29017 /* AV Store */
29018 case 0x087: case 0x0A7: case 0x0C7: // stvebx, stvehx, stvewx
29019 case 0x0E7: case 0x1E7: // stvx, stvxl
29020 if (!allow_V) goto decode_noV;
29021 if (dis_av_store( theInstr )) goto decode_success;
29022 goto decode_failure;
29024 /* VSX Load */
29025 case 0x00C: // lxsiwzx
29026 case 0x04C: // lxsiwax
29027 case 0x10C: // lxvx
29028 case 0x10D: // lxvl
29029 case 0x12D: // lxvll
29030 case 0x16C: // lxvwsx
29031 case 0x20C: // lxsspx
29032 case 0x24C: // lxsdx
29033 case 0x32C: // lxvh8x
29034 case 0x30D: // lxsibzx
29035 case 0x32D: // lxsihzx
29036 case 0x34C: // lxvd2x
29037 case 0x36C: // lxvb16x
29038 case 0x14C: // lxvdsx
29039 case 0x30C: // lxvw4x
29040 // All of these VSX load instructions use some VMX facilities, so
29041 // if allow_V is not set, we'll skip trying to decode.
29042 if (!allow_V) goto decode_noV;
29044 if (dis_vx_load( theInstr )) goto decode_success;
29045 goto decode_failure;
29047 /* VSX Store */
29048 case 0x08C: // stxsiwx
29049 case 0x18C: // stxvx
29050 case 0x18D: // stxvl
29051 case 0x1AD: // stxvll
29052 case 0x28C: // stxsspx
29053 case 0x2CC: // stxsdx
29054 case 0x38C: // stxvw4x
29055 case 0x3CC: // stxvd2x
29056 case 0x38D: // stxsibx
29057 case 0x3AD: // stxsihx
29058 case 0x3AC: // stxvh8x
29059 case 0x3EC: // stxvb16x
29060 // All of these VSX store instructions use some VMX facilities, so
29061 // if allow_V is not set, we'll skip trying to decode.
29062 if (!allow_V) goto decode_noV;
29064 if (dis_vx_store( theInstr )) goto decode_success;
29065 goto decode_failure;
29067 case 0x133: case 0x193: case 0x1B3: // mfvsrld, mfvsrdd, mtvsrws
29068 // The move from/to VSX instructions use some VMX facilities, so
29069 // if allow_V is not set, we'll skip trying to decode.
29070 if (!allow_V) goto decode_noV;
29071 if (dis_vx_move( theInstr )) goto decode_success;
29072 goto decode_failure;
29074 /* Miscellaneous ISA 2.06 instructions */
29075 case 0x1FA: // popcntd
29076 case 0x17A: // popcntw
29077 case 0x7A: // popcntb
29078 if (dis_int_logic( theInstr )) goto decode_success;
29079 goto decode_failure;
29081 case 0x0FC: // bpermd
29082 if (!mode64) goto decode_failure;
29083 if (dis_int_logic( theInstr )) goto decode_success;
29084 goto decode_failure;
29086 default:
29087 /* Deal with some other cases that we would otherwise have
29088 punted on. */
29089 /* --- ISEL (PowerISA_V2.05.pdf, p74) --- */
29090 /* only decode this insn when reserved bit 0 (31 in IBM's
29091 notation) is zero */
29092 if (IFIELD(theInstr, 0, 6) == (15<<1)) {
29093 UInt rT = ifieldRegDS( theInstr );
29094 UInt rA = ifieldRegA( theInstr );
29095 UInt rB = ifieldRegB( theInstr );
29096 UInt bi = ifieldRegC( theInstr );
29097 putIReg(
29099 IRExpr_ITE( binop(Iop_CmpNE32, getCRbit( bi ), mkU32(0)),
29100 rA == 0 ? (mode64 ? mkU64(0) : mkU32(0))
29101 : getIReg(rA),
29102 getIReg(rB))
29105 DIP("isel r%u,r%u,r%u,crb%u\n", rT,rA,rB,bi);
29106 goto decode_success;
29110 opc2 = IFIELD(theInstr, 2, 9);
29111 switch (opc2) {
29112 case 0x1BD:
29113 if (!mode64) goto decode_failure;
29114 if (dis_int_logic( theInstr )) goto decode_success;
29115 goto decode_failure;
29117 default:
29118 goto decode_failure;
29120 break;
29123 case 0x04:
29124 /* AltiVec instructions */
29126 opc2 = IFIELD(theInstr, 0, 6);
29127 switch (opc2) {
29128 /* AV Mult-Add, Mult-Sum */
29129 case 0x20: case 0x21: case 0x22: // vmhaddshs, vmhraddshs, vmladduhm
29130 case 0x23: // vmsumudm
29131 case 0x24: case 0x25: case 0x26: // vmsumubm, vmsummbm, vmsumuhm
29132 case 0x27: case 0x28: case 0x29: // vmsumuhs, vmsumshm, vmsumshs
29133 if (!allow_V) goto decode_noV;
29134 if (dis_av_multarith( theInstr )) goto decode_success;
29135 goto decode_failure;
29137 case 0x30: case 0x31: case 0x33: // maddhd, madhdu, maddld
29138 if (!mode64) goto decode_failure;
29139 if (dis_int_mult_add( theInstr )) goto decode_success;
29140 goto decode_failure;
29142 /* AV Permutations */
29143 case 0x2A: // vsel
29144 case 0x2B: // vperm
29145 case 0x2C: // vsldoi
29146 if (!allow_V) goto decode_noV;
29147 if (dis_av_permute( theInstr )) goto decode_success;
29148 goto decode_failure;
29150 case 0x2D: // vpermxor
29151 case 0x3B: // vpermr
29152 if (!allow_isa_2_07) goto decode_noP8;
29153 if (dis_av_permute( theInstr )) goto decode_success;
29154 goto decode_failure;
29156 /* AV Floating Point Mult-Add/Sub */
29157 case 0x2E: case 0x2F: // vmaddfp, vnmsubfp
29158 if (!allow_V) goto decode_noV;
29159 if (dis_av_fp_arith( theInstr )) goto decode_success;
29160 goto decode_failure;
29162 case 0x3D: case 0x3C: // vaddecuq, vaddeuqm
29163 case 0x3F: case 0x3E: // vsubecuq, vsubeuqm
29164 if (!allow_V) goto decode_noV;
29165 if (dis_av_quad( theInstr)) goto decode_success;
29166 goto decode_failure;
29168 default:
29169 break; // Fall through...
29172 opc2 = IFIELD(theInstr, 0, 9);
29173 if (IFIELD(theInstr, 10, 1) == 1) {
29174 /* The following instructions have bit 21 set and a PS bit (bit 22)
29175 * Bit 21 distinquishes them from instructions with an 11 bit opc2
29176 * field.
29178 switch (opc2) {
29179 /* BCD arithmetic */
29180 case 0x001: case 0x041: // bcdadd, bcdsub
29181 case 0x101: case 0x141: // bcdtrunc., bcdutrunc.
29182 case 0x081: case 0x0C1: case 0x1C1: // bcdus., bcds., bcdsr.
29183 case 0x181: // bcdcfn., bcdcfz.
29184 // bcdctz., bcdcfsq., bcdctsq.
29185 if (!allow_isa_2_07) goto decode_noP8;
29186 if (dis_av_bcd( theInstr, abiinfo )) goto decode_success;
29187 goto decode_failure;
29188 default:
29189 break; // Fall through...
29193 opc2 = IFIELD(theInstr, 0, 11);
29194 switch (opc2) {
29195 /* BCD manipulation */
29196 case 0x341: // bcdcpsgn
29198 if (!allow_isa_2_07) goto decode_noP8;
29199 if (dis_av_bcd_misc( theInstr, abiinfo )) goto decode_success;
29200 goto decode_failure;
29203 /* AV Arithmetic */
29204 case 0x180: // vaddcuw
29205 case 0x000: case 0x040: case 0x080: // vaddubm, vadduhm, vadduwm
29206 case 0x200: case 0x240: case 0x280: // vaddubs, vadduhs, vadduws
29207 case 0x300: case 0x340: case 0x380: // vaddsbs, vaddshs, vaddsws
29208 case 0x580: // vsubcuw
29209 case 0x400: case 0x440: case 0x480: // vsububm, vsubuhm, vsubuwm
29210 case 0x600: case 0x640: case 0x680: // vsububs, vsubuhs, vsubuws
29211 case 0x700: case 0x740: case 0x780: // vsubsbs, vsubshs, vsubsws
29212 case 0x402: case 0x442: case 0x482: // vavgub, vavguh, vavguw
29213 case 0x502: case 0x542: case 0x582: // vavgsb, vavgsh, vavgsw
29214 case 0x002: case 0x042: case 0x082: // vmaxub, vmaxuh, vmaxuw
29215 case 0x102: case 0x142: case 0x182: // vmaxsb, vmaxsh, vmaxsw
29216 case 0x202: case 0x242: case 0x282: // vminub, vminuh, vminuw
29217 case 0x302: case 0x342: case 0x382: // vminsb, vminsh, vminsw
29218 case 0x008: case 0x048: // vmuloub, vmulouh
29219 case 0x108: case 0x148: // vmulosb, vmulosh
29220 case 0x208: case 0x248: // vmuleub, vmuleuh
29221 case 0x308: case 0x348: // vmulesb, vmulesh
29222 case 0x608: case 0x708: case 0x648: // vsum4ubs, vsum4sbs, vsum4shs
29223 case 0x688: case 0x788: // vsum2sws, vsumsws
29224 if (!allow_V) goto decode_noV;
29225 if (dis_av_arith( theInstr )) goto decode_success;
29226 goto decode_failure;
29228 case 0x088: case 0x089: // vmulouw, vmuluwm
29229 case 0x0C0: case 0x0C2: // vaddudm, vmaxud
29230 case 0x1C2: case 0x2C2: case 0x3C2: // vnaxsd, vminud, vminsd
29231 case 0x188: case 0x288: case 0x388: // vmulosw, vmuleuw, vmulesw
29232 case 0x4C0: // vsubudm
29233 if (!allow_isa_2_07) goto decode_noP8;
29234 if (dis_av_arith( theInstr )) goto decode_success;
29235 goto decode_failure;
29237 /* AV Polynomial Vector Multiply Add */
29238 case 0x408: case 0x448: // vpmsumb, vpmsumd
29239 case 0x488: case 0x4C8: // vpmsumw, vpmsumh
29240 if (!allow_isa_2_07) goto decode_noP8;
29241 if (dis_av_polymultarith( theInstr )) goto decode_success;
29242 goto decode_failure;
29244 /* AV Rotate, Shift */
29245 case 0x004: case 0x044: case 0x084: // vrlb, vrlh, vrlw
29246 case 0x104: case 0x144: case 0x184: // vslb, vslh, vslw
29247 case 0x204: case 0x244: case 0x284: // vsrb, vsrh, vsrw
29248 case 0x304: case 0x344: case 0x384: // vsrab, vsrah, vsraw
29249 case 0x1C4: case 0x2C4: // vsl, vsr
29250 case 0x40C: case 0x44C: // vslo, vsro
29251 if (!allow_V) goto decode_noV;
29252 if (dis_av_shift( theInstr )) goto decode_success;
29253 goto decode_failure;
29255 case 0x0C4: // vrld
29256 case 0x3C4: case 0x5C4: case 0x6C4: // vsrad, vsld, vsrd
29257 if (!allow_isa_2_07) goto decode_noP8;
29258 if (dis_av_shift( theInstr )) goto decode_success;
29259 goto decode_failure;
29261 /* AV Logic */
29262 case 0x404: case 0x444: case 0x484: // vand, vandc, vor
29263 case 0x4C4: case 0x504: // vxor, vnor
29264 if (!allow_V) goto decode_noV;
29265 if (dis_av_logic( theInstr )) goto decode_success;
29266 goto decode_failure;
29268 case 0x544: // vorc
29269 case 0x584: case 0x684: // vnand, veqv
29270 if (!allow_isa_2_07) goto decode_noP8;
29271 if (dis_av_logic( theInstr )) goto decode_success;
29272 goto decode_failure;
29274 /* AV Rotate */
29275 case 0x085: case 0x185: // vrlwmi, vrlwnm
29276 case 0x0C5: case 0x1C5: // vrldmi, vrldnm
29277 if (!allow_V) goto decode_noV;
29278 if (dis_av_rotate( theInstr )) goto decode_success;
29279 goto decode_failure;
29281 /* AV Processor Control */
29282 case 0x604: case 0x644: // mfvscr, mtvscr
29283 if (!allow_V) goto decode_noV;
29284 if (dis_av_procctl( theInstr )) goto decode_success;
29285 goto decode_failure;
29287 /* AV Vector Extract Element instructions */
29288 case 0x60D: case 0x64D: case 0x68D: // vextublx, vextuhlx, vextuwlx
29289 case 0x70D: case 0x74D: case 0x78D: // vextubrx, vextuhrx, vextuwrx
29290 if (!allow_V) goto decode_noV;
29291 if (dis_av_extract_element( theInstr )) goto decode_success;
29292 goto decode_failure;
29295 /* AV Floating Point Arithmetic */
29296 case 0x00A: case 0x04A: // vaddfp, vsubfp
29297 case 0x10A: case 0x14A: case 0x18A: // vrefp, vrsqrtefp, vexptefp
29298 case 0x1CA: // vlogefp
29299 case 0x40A: case 0x44A: // vmaxfp, vminfp
29300 if (!allow_V) goto decode_noV;
29301 if (dis_av_fp_arith( theInstr )) goto decode_success;
29302 goto decode_failure;
29304 /* AV Floating Point Round/Convert */
29305 case 0x20A: case 0x24A: case 0x28A: // vrfin, vrfiz, vrfip
29306 case 0x2CA: // vrfim
29307 case 0x30A: case 0x34A: case 0x38A: // vcfux, vcfsx, vctuxs
29308 case 0x3CA: // vctsxs
29309 if (!allow_V) goto decode_noV;
29310 if (dis_av_fp_convert( theInstr )) goto decode_success;
29311 goto decode_failure;
29313 /* AV Merge, Splat, Extract, Insert */
29314 case 0x00C: case 0x04C: case 0x08C: // vmrghb, vmrghh, vmrghw
29315 case 0x10C: case 0x14C: case 0x18C: // vmrglb, vmrglh, vmrglw
29316 case 0x20C: case 0x24C: case 0x28C: // vspltb, vsplth, vspltw
29317 case 0x20D: case 0x24D: // vextractub, vextractuh,
29318 case 0x28D: case 0x2CD: // vextractuw, vextractd,
29319 case 0x30D: case 0x34D: // vinsertb, vinserth
29320 case 0x38D: case 0x3CD: // vinsertw, vinsertd
29321 case 0x30C: case 0x34C: case 0x38C: // vspltisb, vspltish, vspltisw
29322 if (!allow_V) goto decode_noV;
29323 if (dis_av_permute( theInstr )) goto decode_success;
29324 goto decode_failure;
29326 case 0x68C: case 0x78C: // vmrgow, vmrgew
29327 if (!allow_isa_2_07) goto decode_noP8;
29328 if (dis_av_permute( theInstr )) goto decode_success;
29329 goto decode_failure;
29331 /* AltiVec 128 bit integer multiply by 10 Instructions */
29332 case 0x201: case 0x001: //vmul10uq, vmul10cuq
29333 case 0x241: case 0x041: //vmul10euq, vmul10ceuq
29334 if (!allow_V) goto decode_noV;
29335 if (!allow_isa_3_0) goto decode_noP9;
29336 if (dis_av_mult10( theInstr )) goto decode_success;
29337 goto decode_failure;
29339 /* AV Pack, Unpack */
29340 case 0x00E: case 0x04E: case 0x08E: // vpkuhum, vpkuwum, vpkuhus
29341 case 0x0CE: // vpkuwus
29342 case 0x10E: case 0x14E: case 0x18E: // vpkshus, vpkswus, vpkshss
29343 case 0x1CE: // vpkswss
29344 case 0x20E: case 0x24E: case 0x28E: // vupkhsb, vupkhsh, vupklsb
29345 case 0x2CE: // vupklsh
29346 case 0x30E: case 0x34E: case 0x3CE: // vpkpx, vupkhpx, vupklpx
29347 if (!allow_V) goto decode_noV;
29348 if (dis_av_pack( theInstr )) goto decode_success;
29349 goto decode_failure;
29351 case 0x403: case 0x443: case 0x483: // vabsdub, vabsduh, vabsduw
29352 if (!allow_V) goto decode_noV;
29353 if (dis_abs_diff( theInstr )) goto decode_success;
29354 goto decode_failure;
29356 case 0x44E: case 0x4CE: case 0x54E: // vpkudum, vpkudus, vpksdus
29357 case 0x5CE: case 0x64E: case 0x6cE: // vpksdss, vupkhsw, vupklsw
29358 if (!allow_isa_2_07) goto decode_noP8;
29359 if (dis_av_pack( theInstr )) goto decode_success;
29360 goto decode_failure;
29362 case 0x508: case 0x509: // vcipher, vcipherlast
29363 case 0x548: case 0x549: // vncipher, vncipherlast
29364 case 0x5C8: // vsbox
29365 if (!allow_isa_2_07) goto decode_noP8;
29366 if (dis_av_cipher( theInstr )) goto decode_success;
29367 goto decode_failure;
29369 /* AV Vector Extend Sign Instructions and
29370 * Vector Count Leading/Trailing zero Least-Significant bits Byte.
29371 * Vector Integer Negate Instructions
29373 case 0x602: // vextsb2w, vextsh2w, vextsb2d, vextsh2d, vextsw2d
29374 // vclzlsbb and vctzlsbb
29375 // vnegw, vnegd
29376 // vprtybw, vprtybd, vprtybq
29377 // vctzb, vctzh, vctzw, vctzd
29378 if (!allow_V) goto decode_noV;
29379 if (dis_av_extend_sign_count_zero( theInstr, allow_isa_3_0 ))
29380 goto decode_success;
29381 goto decode_failure;
29383 case 0x6C2: case 0x682: // vshasigmaw, vshasigmad
29384 if (!allow_isa_2_07) goto decode_noP8;
29385 if (dis_av_hash( theInstr )) goto decode_success;
29386 goto decode_failure;
29388 case 0x702: case 0x742: // vclzb, vclzh
29389 case 0x782: case 0x7c2: // vclzw, vclzd
29390 if (!allow_isa_2_07) goto decode_noP8;
29391 if (dis_av_count_bitTranspose( theInstr, opc2 )) goto decode_success;
29392 goto decode_failure;
29394 case 0x703: case 0x743: // vpopcntb, vpopcnth
29395 case 0x783: case 0x7c3: // vpopcntw, vpopcntd
29396 if (!allow_isa_2_07) goto decode_noP8;
29397 if (dis_av_count_bitTranspose( theInstr, opc2 )) goto decode_success;
29398 goto decode_failure;
29400 case 0x50c: // vgbbd
29401 case 0x5cc: // vbpermd
29402 if (!allow_isa_2_07) goto decode_noP8;
29403 if (dis_av_count_bitTranspose( theInstr, opc2 )) goto decode_success;
29404 goto decode_failure;
29406 case 0x140: case 0x100: // vaddcuq, vadduqm
29407 case 0x540: case 0x500: // vsubcuq, vsubuqm
29408 case 0x54C: // vbpermq
29409 if (!allow_V) goto decode_noV;
29410 if (dis_av_quad( theInstr)) goto decode_success;
29411 goto decode_failure;
29413 default:
29414 break; // Fall through...
29417 opc2 = IFIELD(theInstr, 0, 10);
29418 switch (opc2) {
29420 /* AV Compare */
29421 case 0x006: case 0x007: case 0x107: // vcmpequb, vcmpneb, vcmpnezb
29422 case 0x046: case 0x047: case 0x147: // vcmpequh, vcmpneh, vcmpnezh
29423 case 0x086: case 0x087: case 0x187: // vcmpequw, vcmpnew, vcmpnezw
29424 case 0x206: case 0x246: case 0x286: // vcmpgtub, vcmpgtuh, vcmpgtuw
29425 case 0x306: case 0x346: case 0x386: // vcmpgtsb, vcmpgtsh, vcmpgtsw
29426 if (!allow_V) goto decode_noV;
29427 if (dis_av_cmp( theInstr )) goto decode_success;
29428 goto decode_failure;
29430 case 0x0C7: // vcmpequd
29431 case 0x2C7: // vcmpgtud
29432 case 0x3C7: // vcmpgtsd
29433 if (!allow_isa_2_07) goto decode_noP8;
29434 if (dis_av_cmp( theInstr )) goto decode_success;
29435 goto decode_failure;
29437 /* AV Floating Point Compare */
29438 case 0x0C6: case 0x1C6: case 0x2C6: // vcmpeqfp, vcmpgefp, vcmpgtfp
29439 case 0x3C6: // vcmpbfp
29440 if (!allow_V) goto decode_noV;
29441 if (dis_av_fp_cmp( theInstr )) goto decode_success;
29442 goto decode_failure;
29444 default:
29445 goto decode_failure;
29447 break;
29449 default:
29450 goto decode_failure;
29452 decode_noF:
29453 vassert(!allow_F);
29454 if (sigill_diag)
29455 vex_printf("disInstr(ppc): found the Floating Point instruction 0x%x that\n"
29456 "can't be handled by Valgrind on this host. This instruction\n"
29457 "requires a host that supports Floating Point instructions.\n",
29458 theInstr);
29459 goto not_supported;
29460 decode_noV:
29461 vassert(!allow_V);
29462 if (sigill_diag)
29463 vex_printf("disInstr(ppc): found an AltiVec or an e500 instruction 0x%x\n"
29464 "that can't be handled by Valgrind. If this instruction is an\n"
29465 "Altivec instruction, Valgrind must be run on a host that supports"
29466 "AltiVec instructions. If the application was compiled for e500, then\n"
29467 "unfortunately Valgrind does not yet support e500 instructions.\n",
29468 theInstr);
29469 goto not_supported;
29470 decode_noVX:
29471 vassert(!allow_VX);
29472 if (sigill_diag)
29473 vex_printf("disInstr(ppc): found the instruction 0x%x that is defined in the\n"
29474 "Power ISA 2.06 ABI but can't be handled by Valgrind on this host.\n"
29475 "This instruction \nrequires a host that supports the ISA 2.06 ABI.\n",
29476 theInstr);
29477 goto not_supported;
29478 decode_noFX:
29479 vassert(!allow_FX);
29480 if (sigill_diag)
29481 vex_printf("disInstr(ppc): found the General Purpose-Optional instruction 0x%x\n"
29482 "that can't be handled by Valgrind on this host. This instruction\n"
29483 "requires a host that supports the General Purpose-Optional instructions.\n",
29484 theInstr);
29485 goto not_supported;
29486 decode_noGX:
29487 vassert(!allow_GX);
29488 if (sigill_diag)
29489 vex_printf("disInstr(ppc): found the Graphics-Optional instruction 0x%x\n"
29490 "that can't be handled by Valgrind on this host. This instruction\n"
29491 "requires a host that supports the Graphic-Optional instructions.\n",
29492 theInstr);
29493 goto not_supported;
29494 decode_noDFP:
29495 vassert(!allow_DFP);
29496 if (sigill_diag)
29497 vex_printf("disInstr(ppc): found the decimal floating point (DFP) instruction 0x%x\n"
29498 "that can't be handled by Valgrind on this host. This instruction\n"
29499 "requires a host that supports DFP instructions.\n",
29500 theInstr);
29501 goto not_supported;
29502 decode_noP8:
29503 vassert(!allow_isa_2_07);
29504 if (sigill_diag)
29505 vex_printf("disInstr(ppc): found the Power 8 instruction 0x%x that can't be handled\n"
29506 "by Valgrind on this host. This instruction requires a host that\n"
29507 "supports Power 8 instructions.\n",
29508 theInstr);
29509 goto not_supported;
29511 decode_noP9:
29512 vassert(!allow_isa_3_0);
29513 if (sigill_diag)
29514 vex_printf("disInstr(ppc): found the Power 9 instruction 0x%x that can't be handled\n"
29515 "by Valgrind on this host. This instruction requires a host that\n"
29516 "supports Power 9 instructions.\n",
29517 theInstr);
29518 goto not_supported;
29520 decode_failure:
29521 /* All decode failures end up here. */
29522 opc2 = (theInstr) & 0x7FF;
29523 if (sigill_diag) {
29524 vex_printf("disInstr(ppc): unhandled instruction: "
29525 "0x%x\n", theInstr);
29526 vex_printf(" primary %d(0x%x), secondary %u(0x%x)\n",
29527 opc1, opc1, opc2, opc2);
29530 not_supported:
29531 /* Tell the dispatcher that this insn cannot be decoded, and so has
29532 not been executed, and (is currently) the next to be executed.
29533 CIA should be up-to-date since it made so at the start of each
29534 insn, but nevertheless be paranoid and update it again right
29535 now. */
29536 putGST( PPC_GST_CIA, mkSzImm(ty, guest_CIA_curr_instr) );
29537 dres.len = 0;
29538 dres.whatNext = Dis_StopHere;
29539 dres.jk_StopHere = Ijk_NoDecode;
29540 dres.continueAt = 0;
29541 return dres;
29542 } /* switch (opc) for the main (primary) opcode switch. */
29544 decode_success:
29545 /* All decode successes end up here. */
29546 switch (dres.whatNext) {
29547 case Dis_Continue:
29548 putGST( PPC_GST_CIA, mkSzImm(ty, guest_CIA_curr_instr + 4));
29549 break;
29550 case Dis_ResteerU:
29551 case Dis_ResteerC:
29552 putGST( PPC_GST_CIA, mkSzImm(ty, dres.continueAt));
29553 break;
29554 case Dis_StopHere:
29555 break;
29556 default:
29557 vassert(0);
29559 DIP("\n");
29561 if (dres.len == 0) {
29562 dres.len = 4;
29563 } else {
29564 vassert(dres.len == 20);
29566 return dres;
29569 #undef DIP
29570 #undef DIS
29573 /*------------------------------------------------------------*/
29574 /*--- Top-level fn ---*/
29575 /*------------------------------------------------------------*/
29577 /* Disassemble a single instruction into IR. The instruction
29578 is located in host memory at &guest_code[delta]. */
29580 DisResult disInstr_PPC ( IRSB* irsb_IN,
29581 Bool (*resteerOkFn) ( void*, Addr ),
29582 Bool resteerCisOk,
29583 void* callback_opaque,
29584 const UChar* guest_code_IN,
29585 Long delta,
29586 Addr guest_IP,
29587 VexArch guest_arch,
29588 const VexArchInfo* archinfo,
29589 const VexAbiInfo* abiinfo,
29590 VexEndness host_endness_IN,
29591 Bool sigill_diag_IN )
29593 IRType ty;
29594 DisResult dres;
29595 UInt mask32, mask64;
29596 UInt hwcaps_guest = archinfo->hwcaps;
29598 vassert(guest_arch == VexArchPPC32 || guest_arch == VexArchPPC64);
29600 /* global -- ick */
29601 mode64 = guest_arch == VexArchPPC64;
29602 ty = mode64 ? Ity_I64 : Ity_I32;
29603 if (!mode64 && (host_endness_IN == VexEndnessLE)) {
29604 vex_printf("disInstr(ppc): Little Endian 32-bit mode is not supported\n");
29605 dres.len = 0;
29606 dres.whatNext = Dis_StopHere;
29607 dres.jk_StopHere = Ijk_NoDecode;
29608 dres.continueAt = 0;
29609 dres.hint = Dis_HintNone;
29610 return dres;
29613 /* do some sanity checks */
29614 mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
29615 | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX
29616 | VEX_HWCAPS_PPC32_DFP | VEX_HWCAPS_PPC32_ISA2_07;
29618 mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
29619 | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP
29620 | VEX_HWCAPS_PPC64_ISA2_07 | VEX_HWCAPS_PPC64_ISA3_0;
29622 if (mode64) {
29623 vassert((hwcaps_guest & mask32) == 0);
29624 } else {
29625 vassert((hwcaps_guest & mask64) == 0);
29628 /* Set globals (see top of this file) */
29629 guest_code = guest_code_IN;
29630 irsb = irsb_IN;
29631 host_endness = host_endness_IN;
29633 guest_CIA_curr_instr = mkSzAddr(ty, guest_IP);
29634 guest_CIA_bbstart = mkSzAddr(ty, guest_IP - delta);
29636 dres = disInstr_PPC_WRK ( resteerOkFn, resteerCisOk, callback_opaque,
29637 delta, archinfo, abiinfo, sigill_diag_IN);
29639 return dres;
29643 /*------------------------------------------------------------*/
29644 /*--- Unused stuff ---*/
29645 /*------------------------------------------------------------*/
29647 ///* A potentially more memcheck-friendly implementation of Clz32, with
29648 // the boundary case Clz32(0) = 32, which is what ppc requires. */
29650 //static IRExpr* /* :: Ity_I32 */ verbose_Clz32 ( IRTemp arg )
29652 // /* Welcome ... to SSA R Us. */
29653 // IRTemp n1 = newTemp(Ity_I32);
29654 // IRTemp n2 = newTemp(Ity_I32);
29655 // IRTemp n3 = newTemp(Ity_I32);
29656 // IRTemp n4 = newTemp(Ity_I32);
29657 // IRTemp n5 = newTemp(Ity_I32);
29658 // IRTemp n6 = newTemp(Ity_I32);
29659 // IRTemp n7 = newTemp(Ity_I32);
29660 // IRTemp n8 = newTemp(Ity_I32);
29661 // IRTemp n9 = newTemp(Ity_I32);
29662 // IRTemp n10 = newTemp(Ity_I32);
29663 // IRTemp n11 = newTemp(Ity_I32);
29664 // IRTemp n12 = newTemp(Ity_I32);
29666 // /* First, propagate the most significant 1-bit into all lower
29667 // positions in the word. */
29668 // /* unsigned int clz ( unsigned int n )
29669 // {
29670 // n |= (n >> 1);
29671 // n |= (n >> 2);
29672 // n |= (n >> 4);
29673 // n |= (n >> 8);
29674 // n |= (n >> 16);
29675 // return bitcount(~n);
29676 // }
29677 // */
29678 // assign(n1, mkexpr(arg));
29679 // assign(n2, binop(Iop_Or32, mkexpr(n1), binop(Iop_Shr32, mkexpr(n1), mkU8(1))));
29680 // assign(n3, binop(Iop_Or32, mkexpr(n2), binop(Iop_Shr32, mkexpr(n2), mkU8(2))));
29681 // assign(n4, binop(Iop_Or32, mkexpr(n3), binop(Iop_Shr32, mkexpr(n3), mkU8(4))));
29682 // assign(n5, binop(Iop_Or32, mkexpr(n4), binop(Iop_Shr32, mkexpr(n4), mkU8(8))));
29683 // assign(n6, binop(Iop_Or32, mkexpr(n5), binop(Iop_Shr32, mkexpr(n5), mkU8(16))));
29684 // /* This gives a word of the form 0---01---1. Now invert it, giving
29685 // a word of the form 1---10---0, then do a population-count idiom
29686 // (to count the 1s, which is the number of leading zeroes, or 32
29687 // if the original word was 0. */
29688 // assign(n7, unop(Iop_Not32, mkexpr(n6)));
29690 // /* unsigned int bitcount ( unsigned int n )
29691 // {
29692 // n = n - ((n >> 1) & 0x55555555);
29693 // n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
29694 // n = (n + (n >> 4)) & 0x0F0F0F0F;
29695 // n = n + (n >> 8);
29696 // n = (n + (n >> 16)) & 0x3F;
29697 // return n;
29698 // }
29699 // */
29700 // assign(n8,
29701 // binop(Iop_Sub32,
29702 // mkexpr(n7),
29703 // binop(Iop_And32,
29704 // binop(Iop_Shr32, mkexpr(n7), mkU8(1)),
29705 // mkU32(0x55555555))));
29706 // assign(n9,
29707 // binop(Iop_Add32,
29708 // binop(Iop_And32, mkexpr(n8), mkU32(0x33333333)),
29709 // binop(Iop_And32,
29710 // binop(Iop_Shr32, mkexpr(n8), mkU8(2)),
29711 // mkU32(0x33333333))));
29712 // assign(n10,
29713 // binop(Iop_And32,
29714 // binop(Iop_Add32,
29715 // mkexpr(n9),
29716 // binop(Iop_Shr32, mkexpr(n9), mkU8(4))),
29717 // mkU32(0x0F0F0F0F)));
29718 // assign(n11,
29719 // binop(Iop_Add32,
29720 // mkexpr(n10),
29721 // binop(Iop_Shr32, mkexpr(n10), mkU8(8))));
29722 // assign(n12,
29723 // binop(Iop_Add32,
29724 // mkexpr(n11),
29725 // binop(Iop_Shr32, mkexpr(n11), mkU8(16))));
29726 // return
29727 // binop(Iop_And32, mkexpr(n12), mkU32(0x3F));
29730 /*--------------------------------------------------------------------*/
29731 /*--- end guest_ppc_toIR.c ---*/
29732 /*--------------------------------------------------------------------*/