1
2 /*---------------------------------------------------------------*/
3 /*--- begin host_ppc_isel.c ---*/
4 /*---------------------------------------------------------------*/
5
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2004-2013 OpenWorks LLP
11 info@open-works.net
12
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.
17
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.
22
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.
27
28 The GNU General Public License is contained in the file COPYING.
29
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.
34 */
35
36 #include "libvex_basictypes.h"
37 #include "libvex_ir.h"
38 #include "libvex.h"
39
40 #include "ir_match.h"
41 #include "main_util.h"
42 #include "main_globals.h"
43 #include "host_generic_regs.h"
44 #include "host_generic_simd64.h"
45 #include "host_ppc_defs.h"
46
47 /* GPR register class for ppc32/64 */
48 #define HRcGPR(_mode64) ((_mode64) ? HRcInt64 : HRcInt32)
49
50
51 /*---------------------------------------------------------*/
52 /*--- Register Usage Conventions ---*/
53 /*---------------------------------------------------------*/
54 /*
55 Integer Regs
56 ------------
57 GPR0 Reserved
58 GPR1 Stack Pointer
59 GPR2 not used - TOC pointer
60 GPR3:10 Allocateable
61 GPR11 if mode64: not used - calls by ptr / env ptr for some langs
62 GPR12 if mode64: not used - exceptions / global linkage code
63 GPR13 not used - Thread-specific pointer
64 GPR14:28 Allocateable
65 GPR29 Unused by us (reserved for the dispatcher)
66 GPR30 AltiVec temp spill register
67 GPR31 GuestStatePointer
68
69 Of Allocateable regs:
70 if (mode64)
71 GPR3:10 Caller-saved regs
72 else
73 GPR3:12 Caller-saved regs
74 GPR14:29 Callee-saved regs
75
76 GPR3 [Return | Parameter] - carrying reg
77 GPR4:10 Parameter-carrying regs
78
79
80 Floating Point Regs
81 -------------------
82 FPR0:31 Allocateable
83
84 FPR0 Caller-saved - scratch reg
85 if (mode64)
86 FPR1:13 Caller-saved - param & return regs
87 else
88 FPR1:8 Caller-saved - param & return regs
89 FPR9:13 Caller-saved regs
90 FPR14:31 Callee-saved regs
91
92
93 Vector Regs (on processors with the VMX feature)
94 -----------
95 VR0-VR1 Volatile scratch registers
96 VR2-VR13 Volatile vector parameters registers
97 VR14-VR19 Volatile scratch registers
98 VR20-VR31 Non-volatile registers
99 VRSAVE Non-volatile 32-bit register
100 */
101
102
103 /*---------------------------------------------------------*/
104 /*--- PPC FP Status & Control Register Conventions ---*/
105 /*---------------------------------------------------------*/
106 /*
107 Vex-generated code expects to run with the FPU set as follows: all
108 exceptions masked. The rounding mode is set appropriately before
109 each floating point insn emitted (or left unchanged if known to be
110 correct already). There are a few fp insns (fmr,fneg,fabs,fnabs),
111 which are unaffected by the rm and so the rounding mode is not set
112 prior to them.
113
114 At least on MPC7447A (Mac Mini), frsqrte is also not affected by
115 rounding mode. At some point the ppc docs get sufficiently vague
116 that the only way to find out is to write test programs.
117 */
118 /* Notes on the FP instruction set, 6 Feb 06.
119
120 What exns -> CR1 ? Sets FPRF ? Observes RM ?
121 -------------------------------------------------------------
122
123 fmr[.] if . n n
124 fneg[.] if . n n
125 fabs[.] if . n n
126 fnabs[.] if . n n
127
128 fadd[.] if . y y
129 fadds[.] if . y y
130 fcfid[.] (Si64->dbl) if . y y
131 fcfidU[.] (Ui64->dbl) if . y y
132 fcfids[.] (Si64->sngl) if . Y Y
133 fcfidus[.] (Ui64->sngl) if . Y Y
134 fcmpo (cmp, result n n n
135 fcmpu to crfD) n n n
136 fctid[.] (dbl->i64) if . ->undef y
137 fctidz[.] (dbl->i64) if . ->undef rounds-to-zero
138 fctiw[.] (dbl->i32) if . ->undef y
139 fctiwz[.] (dbl->i32) if . ->undef rounds-to-zero
140 fdiv[.] if . y y
141 fdivs[.] if . y y
142 fmadd[.] if . y y
143 fmadds[.] if . y y
144 fmsub[.] if . y y
145 fmsubs[.] if . y y
146 fmul[.] if . y y
147 fmuls[.] if . y y
148
149 (note: for fnm*, rounding happens before final negation)
150 fnmadd[.] if . y y
151 fnmadds[.] if . y y
152 fnmsub[.] if . y y
153 fnmsubs[.] if . y y
154
155 fre[.] if . y y
156 fres[.] if . y y
157
158 frsqrte[.] if . y apparently not
159
160 fsqrt[.] if . y y
161 fsqrts[.] if . y y
162 fsub[.] if . y y
163 fsubs[.] if . y y
164
165
166 fpscr: bits 30-31 (ibm) is RM
167 24-29 (ibm) are exnmasks/non-IEEE bit, all zero
168 15-19 (ibm) is FPRF: class, <, =, >, UNord
169
170 ppc fe(guest) makes fpscr read as all zeros except RM (and maybe FPRF
171 in future)
172
173 mcrfs - move fpscr field to CR field
174 mtfsfi[.] - 4 bit imm moved to fpscr field
175 mtfsf[.] - move frS[low 1/2] to fpscr but using 8-bit field mask
176 mtfsb1[.] - set given fpscr bit
177 mtfsb0[.] - clear given fpscr bit
178 mffs[.] - move all fpscr to frD[low 1/2]
179
180 For [.] presumably cr1 is set with exn summary bits, as per
181 main FP insns
182
183 A single precision store truncates/denormalises the in-register value,
184 but does not round it. This is so that flds followed by fsts is
185 always the identity.
186 */
187
188
189 /*---------------------------------------------------------*/
190 /*--- misc helpers ---*/
191 /*---------------------------------------------------------*/
192
193 /* These are duplicated in guest-ppc/toIR.c */
unop(IROp op,IRExpr * a)194 static IRExpr* unop ( IROp op, IRExpr* a )
195 {
196 return IRExpr_Unop(op, a);
197 }
198
mkU32(UInt i)199 static IRExpr* mkU32 ( UInt i )
200 {
201 return IRExpr_Const(IRConst_U32(i));
202 }
203
bind(Int binder)204 static IRExpr* bind ( Int binder )
205 {
206 return IRExpr_Binder(binder);
207 }
208
isZeroU8(IRExpr * e)209 static Bool isZeroU8 ( IRExpr* e )
210 {
211 return e->tag == Iex_Const
212 && e->Iex.Const.con->tag == Ico_U8
213 && e->Iex.Const.con->Ico.U8 == 0;
214 }
215
216
217 /*---------------------------------------------------------*/
218 /*--- ISelEnv ---*/
219 /*---------------------------------------------------------*/
220
221 /* This carries around:
222
223 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
224 might encounter. This is computed before insn selection starts,
225 and does not change.
226
227 - A mapping from IRTemp to HReg. This tells the insn selector
228 which virtual register(s) are associated with each IRTemp
229 temporary. This is computed before insn selection starts, and
230 does not change. We expect this mapping to map precisely the
231 same set of IRTemps as the type mapping does.
232
233 - vregmapLo holds the primary register for the IRTemp.
234 - vregmapMedLo holds the secondary register for the IRTemp,
235 if any is needed. That's only for Ity_I64 temps
236 in 32 bit mode or Ity_I128 temps in 64-bit mode.
237 - vregmapMedHi is only for dealing with Ity_I128 temps in
238 32 bit mode. It holds bits 95:64 (Intel numbering)
239 of the IRTemp.
240 - vregmapHi is also only for dealing with Ity_I128 temps
241 in 32 bit mode. It holds the most significant bits
242 (127:96 in Intel numbering) of the IRTemp.
243
244 - The code array, that is, the insns selected so far.
245
246 - A counter, for generating new virtual registers.
247
248 - The host subarchitecture we are selecting insns for.
249 This is set at the start and does not change.
250
251 - A Bool to tell us if the host is 32 or 64bit.
252 This is set at the start and does not change.
253
254 - An IRExpr*, which may be NULL, holding the IR expression (an
255 IRRoundingMode-encoded value) to which the FPU's rounding mode
256 was most recently set. Setting to NULL is always safe. Used to
257 avoid redundant settings of the FPU's rounding mode, as
258 described in set_FPU_rounding_mode below.
259
260 - A VexMiscInfo*, needed for knowing how to generate
261 function calls for this target.
262
263 - The maximum guest address of any guest insn in this block.
264 Actually, the address of the highest-addressed byte from any
265 insn in this block. Is set at the start and does not change.
266 This is used for detecting jumps which are definitely
267 forward-edges from this block, and therefore can be made
268 (chained) to the fast entry point of the destination, thereby
269 avoiding the destination's event check.
270 */
271
272 typedef
273 struct {
274 /* Constant -- are set at the start and do not change. */
275 IRTypeEnv* type_env;
276 // 64-bit mode 32-bit mode
277 HReg* vregmapLo; // Low 64-bits [63:0] Low 32-bits [31:0]
278 HReg* vregmapMedLo; // high 64-bits[127:64] Next 32-bits [63:32]
279 HReg* vregmapMedHi; // unused Next 32-bits [95:64]
280 HReg* vregmapHi; // unused highest 32-bits [127:96]
281 Int n_vregmap;
282
283 /* 27 Jan 06: Not currently used, but should be */
284 UInt hwcaps;
285
286 Bool mode64;
287
288 const VexAbiInfo* vbi; // unused
289
290 Bool chainingAllowed;
291 Addr64 max_ga;
292
293 /* These are modified as we go along. */
294 HInstrArray* code;
295 Int vreg_ctr;
296
297 IRExpr* previous_rm;
298 }
299 ISelEnv;
300
301
lookupIRTemp(ISelEnv * env,IRTemp tmp)302 static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
303 {
304 vassert(tmp >= 0);
305 vassert(tmp < env->n_vregmap);
306 return env->vregmapLo[tmp];
307 }
308
lookupIRTempPair(HReg * vrHI,HReg * vrLO,ISelEnv * env,IRTemp tmp)309 static void lookupIRTempPair ( HReg* vrHI, HReg* vrLO,
310 ISelEnv* env, IRTemp tmp )
311 {
312 vassert(tmp >= 0);
313 vassert(tmp < env->n_vregmap);
314 vassert(! hregIsInvalid(env->vregmapMedLo[tmp]));
315 *vrLO = env->vregmapLo[tmp];
316 *vrHI = env->vregmapMedLo[tmp];
317 }
318
319 /* Only for used in 32-bit mode */
lookupIRTempQuad(HReg * vrHi,HReg * vrMedHi,HReg * vrMedLo,HReg * vrLo,ISelEnv * env,IRTemp tmp)320 static void lookupIRTempQuad ( HReg* vrHi, HReg* vrMedHi, HReg* vrMedLo,
321 HReg* vrLo, ISelEnv* env, IRTemp tmp )
322 {
323 vassert(!env->mode64);
324 vassert(tmp >= 0);
325 vassert(tmp < env->n_vregmap);
326 vassert(! hregIsInvalid(env->vregmapMedLo[tmp]));
327 *vrHi = env->vregmapHi[tmp];
328 *vrMedHi = env->vregmapMedHi[tmp];
329 *vrMedLo = env->vregmapMedLo[tmp];
330 *vrLo = env->vregmapLo[tmp];
331 }
332
addInstr(ISelEnv * env,PPCInstr * instr)333 static void addInstr ( ISelEnv* env, PPCInstr* instr )
334 {
335 addHInstr(env->code, instr);
336 if (vex_traceflags & VEX_TRACE_VCODE) {
337 ppPPCInstr(instr, env->mode64);
338 vex_printf("\n");
339 }
340 }
341
newVRegI(ISelEnv * env)342 static HReg newVRegI ( ISelEnv* env )
343 {
344 HReg reg
345 = mkHReg(True/*vreg*/, HRcGPR(env->mode64), 0/*enc*/, env->vreg_ctr);
346 env->vreg_ctr++;
347 return reg;
348 }
349
newVRegF(ISelEnv * env)350 static HReg newVRegF ( ISelEnv* env )
351 {
352 HReg reg = mkHReg(True/*vreg*/, HRcFlt64, 0/*enc*/, env->vreg_ctr);
353 env->vreg_ctr++;
354 return reg;
355 }
356
newVRegV(ISelEnv * env)357 static HReg newVRegV ( ISelEnv* env )
358 {
359 HReg reg = mkHReg(True/*vreg*/, HRcVec128, 0/*enc*/, env->vreg_ctr);
360 env->vreg_ctr++;
361 return reg;
362 }
363
364
365 /*---------------------------------------------------------*/
366 /*--- ISEL: Forward declarations ---*/
367 /*---------------------------------------------------------*/
368
369 /* These are organised as iselXXX and iselXXX_wrk pairs. The
370 iselXXX_wrk do the real work, but are not to be called directly.
371 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
372 checks that all returned registers are virtual. You should not
373 call the _wrk version directly.
374
375 'Word' refers to the size of the native machine word, that is,
376 32-bit int in 32-bit mode and 64-bit int in 64-bit mode. '2Word'
377 therefore refers to a double-width (64/128-bit) quantity in two
378 integer registers.
379 */
380 /* 32-bit mode: compute an I8/I16/I32 into a GPR.
381 64-bit mode: compute an I8/I16/I32/I64 into a GPR. */
382 static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e,
383 IREndness IEndianess );
384 static HReg iselWordExpr_R ( ISelEnv* env, IRExpr* e,
385 IREndness IEndianess );
386
387 /* 32-bit mode: Compute an I8/I16/I32 into a RH
388 (reg-or-halfword-immediate).
389 64-bit mode: Compute an I8/I16/I32/I64 into a RH
390 (reg-or-halfword-immediate).
391 It's important to specify whether the immediate is to be regarded
392 as signed or not. If yes, this will never return -32768 as an
393 immediate; this guaranteed that all signed immediates that are
394 return can have their sign inverted if need be.
395 */
396 static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env,
397 Bool syned, IRExpr* e,
398 IREndness IEndianess );
399 static PPCRH* iselWordExpr_RH ( ISelEnv* env,
400 Bool syned, IRExpr* e,
401 IREndness IEndianess );
402
403 /* 32-bit mode: compute an I32 into a RI (reg or 32-bit immediate).
404 64-bit mode: compute an I64 into a RI (reg or 64-bit immediate). */
405 static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e,
406 IREndness IEndianess );
407 static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e,
408 IREndness IEndianess );
409
410 /* In 32 bit mode ONLY, compute an I8 into a
411 reg-or-5-bit-unsigned-immediate, the latter being an immediate in
412 the range 1 .. 31 inclusive. Used for doing shift amounts. */
413 static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e,
414 IREndness IEndianess );
415 static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e,
416 IREndness IEndianess );
417
418 /* In 64-bit mode ONLY, compute an I8 into a
419 reg-or-6-bit-unsigned-immediate, the latter being an immediate in
420 the range 1 .. 63 inclusive. Used for doing shift amounts. */
421 static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e,
422 IREndness IEndianess );
423 static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e,
424 IREndness IEndianess );
425
426 /* 32-bit mode: compute an I32 into an AMode.
427 64-bit mode: compute an I64 into an AMode.
428
429 Requires to know (xferTy) the type of data to be loaded/stored
430 using this amode. That is so that, for 64-bit code generation, any
431 PPCAMode_IR returned will have an index (immediate offset) field
432 that is guaranteed to be 4-aligned, if there is any chance that the
433 amode is to be used in ld/ldu/lda/std/stdu.
434
435 Since there are no such restrictions on 32-bit insns, xferTy is
436 ignored for 32-bit code generation. */
437 static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e,
438 IRType xferTy,
439 IREndness IEndianess );
440 static PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e,
441 IRType xferTy,
442 IREndness IEndianess );
443
444 static void iselInt128Expr_to_32x4_wrk ( HReg* rHi, HReg* rMedHi,
445 HReg* rMedLo, HReg* rLo,
446 ISelEnv* env, IRExpr* e,
447 IREndness IEndianess );
448 static void iselInt128Expr_to_32x4 ( HReg* rHi, HReg* rMedHi,
449 HReg* rMedLo, HReg* rLo,
450 ISelEnv* env, IRExpr* e,
451 IREndness IEndianess );
452
453
454 /* 32-bit mode ONLY: compute an I64 into a GPR pair. */
455 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
456 ISelEnv* env, IRExpr* e,
457 IREndness IEndianess );
458 static void iselInt64Expr ( HReg* rHi, HReg* rLo,
459 ISelEnv* env, IRExpr* e,
460 IREndness IEndianess );
461
462 /* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */
463 static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
464 ISelEnv* env, IRExpr* e,
465 IREndness IEndianess );
466
467 static void iselInt128Expr ( HReg* rHi, HReg* rLo,
468 ISelEnv* env, IRExpr* e,
469 IREndness IEndianess );
470
471 static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e,
472 IREndness IEndianess );
473 static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e,
474 IREndness IEndianess );
475
476 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e,
477 IREndness IEndianess );
478 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e,
479 IREndness IEndianess );
480
481 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e,
482 IREndness IEndianess );
483 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e,
484 IREndness IEndianess );
485
486 static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e,
487 IREndness IEndianess );
488 static HReg iselVecExpr ( ISelEnv* env, IRExpr* e,
489 IREndness IEndianess );
490
491 /* 64-bit mode ONLY. */
492 static HReg iselDfp32Expr_wrk ( ISelEnv* env, IRExpr* e,
493 IREndness IEndianess );
494 static HReg iselDfp32Expr ( ISelEnv* env, IRExpr* e,
495 IREndness IEndianess );
496 static HReg iselDfp64Expr_wrk ( ISelEnv* env, IRExpr* e,
497 IREndness IEndianess );
498 static HReg iselDfp64Expr ( ISelEnv* env, IRExpr* e,
499 IREndness IEndianess );
500
501 /* 64-bit mode ONLY: compute an D128 into a GPR64 pair. */
502 static void iselDfp128Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env,
503 IRExpr* e, IREndness IEndianess );
504 static void iselDfp128Expr ( HReg* rHi, HReg* rLo, ISelEnv* env,
505 IRExpr* e, IREndness IEndianess );
506
507 /*---------------------------------------------------------*/
508 /*--- ISEL: Misc helpers ---*/
509 /*---------------------------------------------------------*/
510
511 /* Make an int reg-reg move. */
512
mk_iMOVds_RR(HReg r_dst,HReg r_src)513 static PPCInstr* mk_iMOVds_RR ( HReg r_dst, HReg r_src )
514 {
515 vassert(hregClass(r_dst) == hregClass(r_src));
516 vassert(hregClass(r_src) == HRcInt32 ||
517 hregClass(r_src) == HRcInt64);
518 return PPCInstr_Alu(Palu_OR, r_dst, r_src, PPCRH_Reg(r_src));
519 }
520
521 /* Advance/retreat %r1 by n. */
522
add_to_sp(ISelEnv * env,UInt n)523 static void add_to_sp ( ISelEnv* env, UInt n )
524 {
525 HReg sp = StackFramePtr(env->mode64);
526 vassert(n <= 1024 && (n%16) == 0);
527 addInstr(env, PPCInstr_Alu( Palu_ADD, sp, sp,
528 PPCRH_Imm(True,toUShort(n)) ));
529 }
530
sub_from_sp(ISelEnv * env,UInt n)531 static void sub_from_sp ( ISelEnv* env, UInt n )
532 {
533 HReg sp = StackFramePtr(env->mode64);
534 vassert(n <= 1024 && (n%16) == 0);
535 addInstr(env, PPCInstr_Alu( Palu_SUB, sp, sp,
536 PPCRH_Imm(True,toUShort(n)) ));
537 }
538
539 /*
540 returns a quadword aligned address on the stack
541 - copies SP, adds 16bytes, aligns to quadword.
542 use sub_from_sp(32) before calling this,
543 as expects to have 32 bytes to play with.
544 */
get_sp_aligned16(ISelEnv * env)545 static HReg get_sp_aligned16 ( ISelEnv* env )
546 {
547 HReg r = newVRegI(env);
548 HReg align16 = newVRegI(env);
549 addInstr(env, mk_iMOVds_RR(r, StackFramePtr(env->mode64)));
550 // add 16
551 addInstr(env, PPCInstr_Alu( Palu_ADD, r, r,
552 PPCRH_Imm(True,toUShort(16)) ));
553 // mask to quadword
554 addInstr(env,
555 PPCInstr_LI(align16, 0xFFFFFFFFFFFFFFF0ULL, env->mode64));
556 addInstr(env, PPCInstr_Alu(Palu_AND, r,r, PPCRH_Reg(align16)));
557 return r;
558 }
559
560
561
562 /* Load 2*I32 regs to fp reg */
mk_LoadRR32toFPR(ISelEnv * env,HReg r_srcHi,HReg r_srcLo)563 static HReg mk_LoadRR32toFPR ( ISelEnv* env,
564 HReg r_srcHi, HReg r_srcLo )
565 {
566 HReg fr_dst = newVRegF(env);
567 PPCAMode *am_addr0, *am_addr1;
568
569 vassert(!env->mode64);
570 vassert(hregClass(r_srcHi) == HRcInt32);
571 vassert(hregClass(r_srcLo) == HRcInt32);
572
573 sub_from_sp( env, 16 ); // Move SP down 16 bytes
574 am_addr0 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
575 am_addr1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
576
577 // store hi,lo as Ity_I32's
578 addInstr(env, PPCInstr_Store( 4, am_addr0, r_srcHi, env->mode64 ));
579 addInstr(env, PPCInstr_Store( 4, am_addr1, r_srcLo, env->mode64 ));
580
581 // load as float
582 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0));
583
584 add_to_sp( env, 16 ); // Reset SP
585 return fr_dst;
586 }
587
588 /* Load I64 reg to fp reg */
mk_LoadR64toFPR(ISelEnv * env,HReg r_src)589 static HReg mk_LoadR64toFPR ( ISelEnv* env, HReg r_src )
590 {
591 HReg fr_dst = newVRegF(env);
592 PPCAMode *am_addr0;
593
594 vassert(env->mode64);
595 vassert(hregClass(r_src) == HRcInt64);
596
597 sub_from_sp( env, 16 ); // Move SP down 16 bytes
598 am_addr0 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
599
600 // store as Ity_I64
601 addInstr(env, PPCInstr_Store( 8, am_addr0, r_src, env->mode64 ));
602
603 // load as float
604 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0));
605
606 add_to_sp( env, 16 ); // Reset SP
607 return fr_dst;
608 }
609
610
611 /* Given an amode, return one which references 4 bytes further
612 along. */
613
advance4(ISelEnv * env,PPCAMode * am)614 static PPCAMode* advance4 ( ISelEnv* env, PPCAMode* am )
615 {
616 PPCAMode* am4 = dopyPPCAMode( am );
617 if (am4->tag == Pam_IR
618 && am4->Pam.IR.index + 4 <= 32767) {
619 am4->Pam.IR.index += 4;
620 } else {
621 vpanic("advance4(ppc,host)");
622 }
623 return am4;
624 }
625
626
627 /* Given a guest-state array descriptor, an index expression and a
628 bias, generate a PPCAMode pointing at the relevant piece of
629 guest state. */
630 static
genGuestArrayOffset(ISelEnv * env,IRRegArray * descr,IRExpr * off,Int bias,IREndness IEndianess)631 PPCAMode* genGuestArrayOffset ( ISelEnv* env, IRRegArray* descr,
632 IRExpr* off, Int bias, IREndness IEndianess )
633 {
634 HReg rtmp, roff;
635 Int elemSz = sizeofIRType(descr->elemTy);
636 Int nElems = descr->nElems;
637 Int shift = 0;
638
639 /* Throw out any cases we don't need. In theory there might be a
640 day where we need to handle others, but not today. */
641
642 if (nElems != 16 && nElems != 32)
643 vpanic("genGuestArrayOffset(ppc host)(1)");
644
645 switch (elemSz) {
646 case 4: shift = 2; break;
647 case 8: shift = 3; break;
648 default: vpanic("genGuestArrayOffset(ppc host)(2)");
649 }
650
651 if (bias < -100 || bias > 100) /* somewhat arbitrarily */
652 vpanic("genGuestArrayOffset(ppc host)(3)");
653 if (descr->base < 0 || descr->base > 5000) /* somewhat arbitrarily */
654 vpanic("genGuestArrayOffset(ppc host)(4)");
655
656 /* Compute off into a reg, %off. Then return:
657
658 addi %tmp, %off, bias (if bias != 0)
659 andi %tmp, nElems-1
660 sldi %tmp, shift
661 addi %tmp, %tmp, base
662 ... Baseblockptr + %tmp ...
663 */
664 roff = iselWordExpr_R(env, off, IEndianess);
665 rtmp = newVRegI(env);
666 addInstr(env, PPCInstr_Alu(
667 Palu_ADD,
668 rtmp, roff,
669 PPCRH_Imm(True/*signed*/, toUShort(bias))));
670 addInstr(env, PPCInstr_Alu(
671 Palu_AND,
672 rtmp, rtmp,
673 PPCRH_Imm(False/*unsigned*/, toUShort(nElems-1))));
674 addInstr(env, PPCInstr_Shft(
675 Pshft_SHL,
676 env->mode64 ? False : True/*F:64-bit, T:32-bit shift*/,
677 rtmp, rtmp,
678 PPCRH_Imm(False/*unsigned*/, toUShort(shift))));
679 addInstr(env, PPCInstr_Alu(
680 Palu_ADD,
681 rtmp, rtmp,
682 PPCRH_Imm(True/*signed*/, toUShort(descr->base))));
683 return
684 PPCAMode_RR( GuestStatePtr(env->mode64), rtmp );
685 }
686
687
688 /*---------------------------------------------------------*/
689 /*--- ISEL: Function call helpers ---*/
690 /*---------------------------------------------------------*/
691
692 /* Used only in doHelperCall. See big comment in doHelperCall re
693 handling of register-parameter args. This function figures out
694 whether evaluation of an expression might require use of a fixed
695 register. If in doubt return True (safe but suboptimal).
696 */
697 static
mightRequireFixedRegs(IRExpr * e)698 Bool mightRequireFixedRegs ( IRExpr* e )
699 {
700 switch (e->tag) {
701 case Iex_RdTmp: case Iex_Const: case Iex_Get:
702 return False;
703 default:
704 return True;
705 }
706 }
707
708
709 /* Do a complete function call. |guard| is a Ity_Bit expression
710 indicating whether or not the call happens. If guard==NULL, the
711 call is unconditional. |retloc| is set to indicate where the
712 return value is after the call. The caller (of this fn) must
713 generate code to add |stackAdjustAfterCall| to the stack pointer
714 after the call is done. */
715
716 static
doHelperCall(UInt * stackAdjustAfterCall,RetLoc * retloc,ISelEnv * env,IRExpr * guard,IRCallee * cee,IRType retTy,IRExpr ** args,IREndness IEndianess)717 void doHelperCall ( /*OUT*/UInt* stackAdjustAfterCall,
718 /*OUT*/RetLoc* retloc,
719 ISelEnv* env,
720 IRExpr* guard,
721 IRCallee* cee, IRType retTy, IRExpr** args,
722 IREndness IEndianess)
723 {
724 PPCCondCode cc;
725 HReg argregs[PPC_N_REGPARMS];
726 HReg tmpregs[PPC_N_REGPARMS];
727 Bool go_fast;
728 Int n_args, i, argreg;
729 UInt argiregs;
730 Bool mode64 = env->mode64;
731
732 /* Set default returns. We'll update them later if needed. */
733 *stackAdjustAfterCall = 0;
734 *retloc = mk_RetLoc_INVALID();
735
736 /* These are used for cross-checking that IR-level constraints on
737 the use of IRExpr_VECRET() and IRExpr_BBPTR() are observed. */
738 UInt nVECRETs = 0;
739 UInt nBBPTRs = 0;
740
741 /* Marshal args for a call and do the call.
742
743 This function only deals with a tiny set of possibilities, which
744 cover all helpers in practice. The restrictions are that only
745 arguments in registers are supported, hence only PPC_N_REGPARMS x
746 (mode32:32 | mode64:64) integer bits in total can be passed.
747 In fact the only supported arg type is (mode32:I32 | mode64:I64).
748
749 The return type can be I{64,32,16,8} or V{128,256}. In the
750 latter two cases, it is expected that |args| will contain the
751 special node IRExpr_VECRET(), in which case this routine
752 generates code to allocate space on the stack for the vector
753 return value. Since we are not passing any scalars on the
754 stack, it is enough to preallocate the return space before
755 marshalling any arguments, in this case.
756
757 |args| may also contain IRExpr_BBPTR(), in which case the value
758 in the guest state pointer register is passed as the
759 corresponding argument.
760
761 Generating code which is both efficient and correct when
762 parameters are to be passed in registers is difficult, for the
763 reasons elaborated in detail in comments attached to
764 doHelperCall() in priv/host-x86/isel.c. Here, we use a variant
765 of the method described in those comments.
766
767 The problem is split into two cases: the fast scheme and the
768 slow scheme. In the fast scheme, arguments are computed
769 directly into the target (real) registers. This is only safe
770 when we can be sure that computation of each argument will not
771 trash any real registers set by computation of any other
772 argument.
773
774 In the slow scheme, all args are first computed into vregs, and
775 once they are all done, they are moved to the relevant real
776 regs. This always gives correct code, but it also gives a bunch
777 of vreg-to-rreg moves which are usually redundant but are hard
778 for the register allocator to get rid of.
779
780 To decide which scheme to use, all argument expressions are
781 first examined. If they are all so simple that it is clear they
782 will be evaluated without use of any fixed registers, use the
783 fast scheme, else use the slow scheme. Note also that only
784 unconditional calls may use the fast scheme, since having to
785 compute a condition expression could itself trash real
786 registers.
787
788 Note this requires being able to examine an expression and
789 determine whether or not evaluation of it might use a fixed
790 register. That requires knowledge of how the rest of this insn
791 selector works. Currently just the following 3 are regarded as
792 safe -- hopefully they cover the majority of arguments in
793 practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
794 */
795
796 /* Note that the cee->regparms field is meaningless on PPC32/64 host
797 (since there is only one calling convention) and so we always
798 ignore it. */
799
800 n_args = 0;
801 for (i = 0; args[i]; i++)
802 n_args++;
803
804 if (n_args > PPC_N_REGPARMS) {
805 vpanic("doHelperCall(PPC): cannot currently handle > 8 args");
806 // PPC_N_REGPARMS
807 }
808
809 /* This is kind of stupid .. the arrays are sized as PPC_N_REGPARMS
810 but we then assume that that value is 8. */
811 vassert(PPC_N_REGPARMS == 8);
812
813 argregs[0] = hregPPC_GPR3(mode64);
814 argregs[1] = hregPPC_GPR4(mode64);
815 argregs[2] = hregPPC_GPR5(mode64);
816 argregs[3] = hregPPC_GPR6(mode64);
817 argregs[4] = hregPPC_GPR7(mode64);
818 argregs[5] = hregPPC_GPR8(mode64);
819 argregs[6] = hregPPC_GPR9(mode64);
820 argregs[7] = hregPPC_GPR10(mode64);
821 argiregs = 0;
822
823 tmpregs[0] = tmpregs[1] = tmpregs[2] =
824 tmpregs[3] = tmpregs[4] = tmpregs[5] =
825 tmpregs[6] = tmpregs[7] = INVALID_HREG;
826
827 /* First decide which scheme (slow or fast) is to be used. First
828 assume the fast scheme, and select slow if any contraindications
829 (wow) appear. */
830
831 go_fast = True;
832
833 /* We'll need space on the stack for the return value. Avoid
834 possible complications with nested calls by using the slow
835 scheme. */
836 if (retTy == Ity_V128 || retTy == Ity_V256)
837 go_fast = False;
838
839 if (go_fast && guard) {
840 if (guard->tag == Iex_Const
841 && guard->Iex.Const.con->tag == Ico_U1
842 && guard->Iex.Const.con->Ico.U1 == True) {
843 /* unconditional */
844 } else {
845 /* Not manifestly unconditional -- be conservative. */
846 go_fast = False;
847 }
848 }
849
850 if (go_fast) {
851 for (i = 0; i < n_args; i++) {
852 IRExpr* arg = args[i];
853 if (UNLIKELY(arg->tag == Iex_BBPTR)) {
854 /* that's OK */
855 }
856 else if (UNLIKELY(arg->tag == Iex_VECRET)) {
857 /* This implies ill-formed IR, since if the IR was
858 well-formed, the return-type test above would have
859 filtered it out. */
860 vpanic("doHelperCall(PPC): invalid IR");
861 }
862 else if (mightRequireFixedRegs(arg)) {
863 go_fast = False;
864 break;
865 }
866 }
867 }
868
869 /* At this point the scheme to use has been established. Generate
870 code to get the arg values into the argument rregs. */
871
872 if (go_fast) {
873
874 /* FAST SCHEME */
875 argreg = 0;
876
877 for (i = 0; i < n_args; i++) {
878 IRExpr* arg = args[i];
879 vassert(argreg < PPC_N_REGPARMS);
880
881 if (arg->tag == Iex_BBPTR) {
882 argiregs |= (1 << (argreg+3));
883 addInstr(env, mk_iMOVds_RR( argregs[argreg],
884 GuestStatePtr(mode64) ));
885 argreg++;
886 } else {
887 vassert(arg->tag != Iex_VECRET);
888 IRType ty = typeOfIRExpr(env->type_env, arg);
889 vassert(ty == Ity_I32 || ty == Ity_I64);
890 if (!mode64) {
891 if (ty == Ity_I32) {
892 argiregs |= (1 << (argreg+3));
893 addInstr(env,
894 mk_iMOVds_RR( argregs[argreg],
895 iselWordExpr_R(env, arg,
896 IEndianess) ));
897 } else { // Ity_I64 in 32-bit mode
898 HReg rHi, rLo;
899 if ((argreg%2) == 1)
900 // ppc32 ELF abi spec for passing LONG_LONG
901 argreg++; // XXX: odd argreg => even rN
902 vassert(argreg < PPC_N_REGPARMS-1);
903 iselInt64Expr(&rHi,&rLo, env, arg, IEndianess);
904 argiregs |= (1 << (argreg+3));
905 addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi ));
906 argiregs |= (1 << (argreg+3));
907 addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo));
908 }
909 } else { // mode64
910 argiregs |= (1 << (argreg+3));
911 addInstr(env, mk_iMOVds_RR( argregs[argreg],
912 iselWordExpr_R(env, arg,
913 IEndianess) ));
914 }
915 argreg++;
916 } /* if (arg == IRExprP__BBPR) */
917 }
918
919 /* Fast scheme only applies for unconditional calls. Hence: */
920 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
921
922 } else {
923
924 /* SLOW SCHEME; move via temporaries */
925 argreg = 0;
926
927 /* If we have a vector return type, allocate a place for it on
928 the stack and record its address. Rather than figure out the
929 complexities of PPC{32,64} ELF ABI stack frame layout, simply
930 drop the SP by 1024 and allocate the return point in the
931 middle. I think this should comfortably clear any ABI
932 mandated register save areas. Note that it doesn't maintain
933 the backchain as it should, since we're not doing st{d,w}u to
934 adjust the SP, but .. that doesn't seem to be a big deal.
935 Since we're not expecting to have to unwind out of here. */
936 HReg r_vecRetAddr = INVALID_HREG;
937 if (retTy == Ity_V128) {
938 r_vecRetAddr = newVRegI(env);
939 sub_from_sp(env, 512);
940 addInstr(env, mk_iMOVds_RR( r_vecRetAddr, StackFramePtr(mode64) ));
941 sub_from_sp(env, 512);
942 }
943 else if (retTy == Ity_V256) {
944 vassert(0); //ATC
945 r_vecRetAddr = newVRegI(env);
946 sub_from_sp(env, 512);
947 addInstr(env, mk_iMOVds_RR( r_vecRetAddr, StackFramePtr(mode64) ));
948 sub_from_sp(env, 512);
949 }
950
951 vassert(n_args >= 0 && n_args <= 8);
952 for (i = 0; i < n_args; i++) {
953 IRExpr* arg = args[i];
954 vassert(argreg < PPC_N_REGPARMS);
955 if (UNLIKELY(arg->tag == Iex_BBPTR)) {
956 tmpregs[argreg] = newVRegI(env);
957 addInstr(env, mk_iMOVds_RR( tmpregs[argreg],
958 GuestStatePtr(mode64) ));
959 nBBPTRs++;
960 }
961 else if (UNLIKELY(arg->tag == Iex_VECRET)) {
962 /* We stashed the address of the return slot earlier, so just
963 retrieve it now. */
964 vassert(!hregIsInvalid(r_vecRetAddr));
965 tmpregs[i] = r_vecRetAddr;
966 nVECRETs++;
967 }
968 else {
969 IRType ty = typeOfIRExpr(env->type_env, arg);
970 vassert(ty == Ity_I32 || ty == Ity_I64);
971 if (!mode64) {
972 if (ty == Ity_I32) {
973 tmpregs[argreg] = iselWordExpr_R(env, arg, IEndianess);
974 } else { // Ity_I64 in 32-bit mode
975 HReg rHi, rLo;
976 if ((argreg%2) == 1)
977 // ppc32 ELF abi spec for passing LONG_LONG
978 argreg++; // XXX: odd argreg => even rN
979 vassert(argreg < PPC_N_REGPARMS-1);
980 iselInt64Expr(&rHi,&rLo, env, arg, IEndianess);
981 tmpregs[argreg++] = rHi;
982 tmpregs[argreg] = rLo;
983 }
984 } else { // mode64
985 tmpregs[argreg] = iselWordExpr_R(env, arg, IEndianess);
986 }
987 }
988 argreg++;
989 }
990
991 /* Now we can compute the condition. We can't do it earlier
992 because the argument computations could trash the condition
993 codes. Be a bit clever to handle the common case where the
994 guard is 1:Bit. */
995 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
996 if (guard) {
997 if (guard->tag == Iex_Const
998 && guard->Iex.Const.con->tag == Ico_U1
999 && guard->Iex.Const.con->Ico.U1 == True) {
1000 /* unconditional -- do nothing */
1001 } else {
1002 cc = iselCondCode( env, guard, IEndianess );
1003 }
1004 }
1005
1006 /* Move the args to their final destinations. */
1007 for (i = 0; i < argreg; i++) {
1008 if (hregIsInvalid(tmpregs[i])) // Skip invalid regs
1009 continue;
1010 /* None of these insns, including any spill code that might
1011 be generated, may alter the condition codes. */
1012 argiregs |= (1 << (i+3));
1013 addInstr( env, mk_iMOVds_RR( argregs[i], tmpregs[i] ) );
1014 }
1015
1016 }
1017
1018 /* Do final checks, set the return values, and generate the call
1019 instruction proper. */
1020 if (retTy == Ity_V128 || retTy == Ity_V256) {
1021 vassert(nVECRETs == 1);
1022 } else {
1023 vassert(nVECRETs == 0);
1024 }
1025
1026 vassert(nBBPTRs == 0 || nBBPTRs == 1);
1027
1028 vassert(*stackAdjustAfterCall == 0);
1029 vassert(is_RetLoc_INVALID(*retloc));
1030 switch (retTy) {
1031 case Ity_INVALID:
1032 /* Function doesn't return a value. */
1033 *retloc = mk_RetLoc_simple(RLPri_None);
1034 break;
1035 case Ity_I64:
1036 *retloc = mk_RetLoc_simple(mode64 ? RLPri_Int : RLPri_2Int);
1037 break;
1038 case Ity_I32: case Ity_I16: case Ity_I8:
1039 *retloc = mk_RetLoc_simple(RLPri_Int);
1040 break;
1041 case Ity_V128:
1042 /* Result is 512 bytes up the stack, and after it has been
1043 retrieved, adjust SP upwards by 1024. */
1044 *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 512);
1045 *stackAdjustAfterCall = 1024;
1046 break;
1047 case Ity_V256:
1048 vassert(0); // ATC
1049 /* Ditto */
1050 *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 512);
1051 *stackAdjustAfterCall = 1024;
1052 break;
1053 default:
1054 /* IR can denote other possible return types, but we don't
1055 handle those here. */
1056 vassert(0);
1057 }
1058
1059 /* Finally, generate the call itself. This needs the *retloc value
1060 set in the switch above, which is why it's at the end. */
1061
1062 Addr64 target = mode64 ? (Addr)cee->addr
1063 : toUInt((Addr)(cee->addr));
1064 addInstr(env, PPCInstr_Call( cc, target, argiregs, *retloc ));
1065 }
1066
1067
1068 /*---------------------------------------------------------*/
1069 /*--- ISEL: FP rounding mode helpers ---*/
1070 /*---------------------------------------------------------*/
1071
1072 ///* Set FPU's rounding mode to the default */
1073 //static
1074 //void set_FPU_rounding_default ( ISelEnv* env )
1075 //{
1076 // HReg fr_src = newVRegF(env);
1077 // HReg r_src = newVRegI(env);
1078 //
1079 // /* Default rounding mode = 0x0
1080 // Only supporting the rounding-mode bits - the rest of FPSCR is 0x0
1081 // - so we can set the whole register at once (faster)
1082 // note: upper 32 bits ignored by FpLdFPSCR
1083 // */
1084 // addInstr(env, PPCInstr_LI(r_src, 0x0, env->mode64));
1085 // if (env->mode64) {
1086 // fr_src = mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64
1087 // } else {
1088 // fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
1089 // }
1090 // addInstr(env, PPCInstr_FpLdFPSCR( fr_src ));
1091 //}
1092
1093 /* Convert IR rounding mode to PPC encoding */
roundModeIRtoPPC(ISelEnv * env,HReg r_rmIR)1094 static HReg roundModeIRtoPPC ( ISelEnv* env, HReg r_rmIR )
1095 {
1096 /*
1097 rounding mode | PPC | IR
1098 -----------------------------------------------
1099 to nearest, ties to even | 000 | 000
1100 to zero | 001 | 011
1101 to +infinity | 010 | 010
1102 to -infinity | 011 | 001
1103 +++++ Below are the extended rounding modes for decimal floating point +++++
1104 to nearest, ties away from 0 | 100 | 100
1105 to nearest, ties toward 0 | 101 | 111
1106 to away from 0 | 110 | 110
1107 to prepare for shorter precision | 111 | 101
1108 */
1109 HReg r_rmPPC = newVRegI(env);
1110 HReg r_tmp1 = newVRegI(env);
1111 HReg r_tmp2 = newVRegI(env);
1112
1113 vassert(hregClass(r_rmIR) == HRcGPR(env->mode64));
1114
1115 // r_rmPPC = XOR(r_rmIR, r_rmIR << 1) & 3
1116 //
1117 // slwi tmp1, r_rmIR, 1
1118 // xor tmp1, r_rmIR, tmp1
1119 // andi r_rmPPC, tmp1, 3
1120
1121 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1122 r_tmp1, r_rmIR, PPCRH_Imm(False,1)));
1123
1124 addInstr( env, PPCInstr_Alu( Palu_AND,
1125 r_tmp2, r_tmp1, PPCRH_Imm( False, 3 ) ) );
1126
1127 addInstr( env, PPCInstr_Alu( Palu_XOR,
1128 r_rmPPC, r_rmIR, PPCRH_Reg( r_tmp2 ) ) );
1129
1130 return r_rmPPC;
1131 }
1132
1133
1134 /* Set the FPU's rounding mode: 'mode' is an I32-typed expression
1135 denoting a value in the range 0 .. 7, indicating a round mode
1136 encoded as per type IRRoundingMode. Set the PPC FPSCR to have the
1137 same rounding. When the dfp_rm arg is True, set the decimal
1138 floating point rounding mode bits (29:31); otherwise, set the
1139 binary floating point rounding mode bits (62:63).
1140
1141 For speed & simplicity, we're setting the *entire* FPSCR here.
1142
1143 Setting the rounding mode is expensive. So this function tries to
1144 avoid repeatedly setting the rounding mode to the same thing by
1145 first comparing 'mode' to the 'mode' tree supplied in the previous
1146 call to this function, if any. (The previous value is stored in
1147 env->previous_rm.) If 'mode' is a single IR temporary 't' and
1148 env->previous_rm is also just 't', then the setting is skipped.
1149
1150 This is safe because of the SSA property of IR: an IR temporary can
1151 only be defined once and so will have the same value regardless of
1152 where it appears in the block. Cool stuff, SSA.
1153
1154 A safety condition: all attempts to set the RM must be aware of
1155 this mechanism - by being routed through the functions here.
1156
1157 Of course this only helps if blocks where the RM is set more than
1158 once and it is set to the same value each time, *and* that value is
1159 held in the same IR temporary each time. In order to assure the
1160 latter as much as possible, the IR optimiser takes care to do CSE
1161 on any block with any sign of floating point activity.
1162 */
1163 static
_set_FPU_rounding_mode(ISelEnv * env,IRExpr * mode,Bool dfp_rm,IREndness IEndianess)1164 void _set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode, Bool dfp_rm,
1165 IREndness IEndianess )
1166 {
1167 HReg fr_src = newVRegF(env);
1168 HReg r_src;
1169
1170 vassert(typeOfIRExpr(env->type_env,mode) == Ity_I32);
1171
1172 /* Do we need to do anything? */
1173 if (env->previous_rm
1174 && env->previous_rm->tag == Iex_RdTmp
1175 && mode->tag == Iex_RdTmp
1176 && env->previous_rm->Iex.RdTmp.tmp == mode->Iex.RdTmp.tmp) {
1177 /* no - setting it to what it was before. */
1178 vassert(typeOfIRExpr(env->type_env, env->previous_rm) == Ity_I32);
1179 return;
1180 }
1181
1182 /* No luck - we better set it, and remember what we set it to. */
1183 env->previous_rm = mode;
1184
1185 /* Only supporting the rounding-mode bits - the rest of FPSCR is
1186 0x0 - so we can set the whole register at once (faster). */
1187
1188 // Resolve rounding mode and convert to PPC representation
1189 r_src = roundModeIRtoPPC( env, iselWordExpr_R(env, mode, IEndianess) );
1190
1191 // gpr -> fpr
1192 if (env->mode64) {
1193 if (dfp_rm) {
1194 HReg r_tmp1 = newVRegI( env );
1195 addInstr( env,
1196 PPCInstr_Shft( Pshft_SHL, False/*64bit shift*/,
1197 r_tmp1, r_src, PPCRH_Imm( False, 32 ) ) );
1198 fr_src = mk_LoadR64toFPR( env, r_tmp1 );
1199 } else {
1200 fr_src = mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64
1201 }
1202 } else {
1203 if (dfp_rm) {
1204 HReg r_zero = newVRegI( env );
1205 addInstr( env, PPCInstr_LI( r_zero, 0, env->mode64 ) );
1206 fr_src = mk_LoadRR32toFPR( env, r_src, r_zero );
1207 } else {
1208 fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
1209 }
1210 }
1211
1212 // Move to FPSCR
1213 addInstr(env, PPCInstr_FpLdFPSCR( fr_src, dfp_rm ));
1214 }
1215
set_FPU_rounding_mode(ISelEnv * env,IRExpr * mode,IREndness IEndianess)1216 static void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode,
1217 IREndness IEndianess )
1218 {
1219 _set_FPU_rounding_mode(env, mode, False, IEndianess);
1220 }
1221
set_FPU_DFP_rounding_mode(ISelEnv * env,IRExpr * mode,IREndness IEndianess)1222 static void set_FPU_DFP_rounding_mode ( ISelEnv* env, IRExpr* mode,
1223 IREndness IEndianess )
1224 {
1225 _set_FPU_rounding_mode(env, mode, True, IEndianess);
1226 }
1227
1228
1229 /*---------------------------------------------------------*/
1230 /*--- ISEL: vector helpers ---*/
1231 /*---------------------------------------------------------*/
1232
1233 /* Generate all-zeroes into a new vector register.
1234 */
generate_zeroes_V128(ISelEnv * env)1235 static HReg generate_zeroes_V128 ( ISelEnv* env )
1236 {
1237 HReg dst = newVRegV(env);
1238 addInstr(env, PPCInstr_AvBinary(Pav_XOR, dst, dst, dst));
1239 return dst;
1240 }
1241
1242 /* Generate all-ones into a new vector register.
1243 */
generate_ones_V128(ISelEnv * env)1244 static HReg generate_ones_V128 ( ISelEnv* env )
1245 {
1246 HReg dst = newVRegV(env);
1247 PPCVI5s * src = PPCVI5s_Imm(-1);
1248 addInstr(env, PPCInstr_AvSplat(8, dst, src));
1249 return dst;
1250 }
1251
1252
1253 /*
1254 Generates code for AvSplat
1255 - takes in IRExpr* of type 8|16|32
1256 returns vector reg of duplicated lanes of input
1257 - uses AvSplat(imm) for imms up to simm6.
1258 otherwise must use store reg & load vector
1259 */
mk_AvDuplicateRI(ISelEnv * env,IRExpr * e,IREndness IEndianess)1260 static HReg mk_AvDuplicateRI( ISelEnv* env, IRExpr* e, IREndness IEndianess )
1261 {
1262 HReg r_src;
1263 HReg dst = newVRegV(env);
1264 PPCRI* ri = iselWordExpr_RI(env, e, IEndianess);
1265 IRType ty = typeOfIRExpr(env->type_env,e);
1266 UInt sz = (ty == Ity_I8) ? 8 : (ty == Ity_I16) ? 16 : 32;
1267 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1268
1269 /* special case: immediate */
1270 if (ri->tag == Pri_Imm) {
1271 Int simm32 = (Int)ri->Pri.Imm;
1272
1273 /* figure out if it's do-able with imm splats. */
1274 if (simm32 >= -32 && simm32 <= 31) {
1275 Char simm6 = (Char)simm32;
1276 if (simm6 > 15) { /* 16:31 inclusive */
1277 HReg v1 = newVRegV(env);
1278 HReg v2 = newVRegV(env);
1279 addInstr(env, PPCInstr_AvSplat(sz, v1, PPCVI5s_Imm(-16)));
1280 addInstr(env, PPCInstr_AvSplat(sz, v2, PPCVI5s_Imm(simm6-16)));
1281 addInstr(env,
1282 (sz== 8) ? PPCInstr_AvBin8x16(Pav_SUBU, dst, v2, v1) :
1283 (sz==16) ? PPCInstr_AvBin16x8(Pav_SUBU, dst, v2, v1)
1284 : PPCInstr_AvBin32x4(Pav_SUBU, dst, v2, v1) );
1285 return dst;
1286 }
1287 if (simm6 < -16) { /* -32:-17 inclusive */
1288 HReg v1 = newVRegV(env);
1289 HReg v2 = newVRegV(env);
1290 addInstr(env, PPCInstr_AvSplat(sz, v1, PPCVI5s_Imm(-16)));
1291 addInstr(env, PPCInstr_AvSplat(sz, v2, PPCVI5s_Imm(simm6+16)));
1292 addInstr(env,
1293 (sz== 8) ? PPCInstr_AvBin8x16(Pav_ADDU, dst, v2, v1) :
1294 (sz==16) ? PPCInstr_AvBin16x8(Pav_ADDU, dst, v2, v1)
1295 : PPCInstr_AvBin32x4(Pav_ADDU, dst, v2, v1) );
1296 return dst;
1297 }
1298 /* simplest form: -16:15 inclusive */
1299 addInstr(env, PPCInstr_AvSplat(sz, dst, PPCVI5s_Imm(simm6)));
1300 return dst;
1301 }
1302
1303 /* no luck; use the Slow way. */
1304 r_src = newVRegI(env);
1305 addInstr(env, PPCInstr_LI(r_src, (Long)simm32, env->mode64));
1306 }
1307 else {
1308 r_src = ri->Pri.Reg;
1309 }
1310
1311 {
1312 /* Store r_src multiple times (sz dependent); then load the dest vector. */
1313 HReg r_aligned16;
1314 PPCAMode *am_offset, *am_offset_zero;
1315
1316 sub_from_sp( env, 32 ); // Move SP down
1317 /* Get a 16-aligned address within our stack space */
1318 r_aligned16 = get_sp_aligned16( env );
1319
1320 Int i;
1321 Int stride = (sz == 8) ? 1 : (sz == 16) ? 2 : 4;
1322 UChar num_bytes_to_store = stride;
1323 am_offset_zero = PPCAMode_IR( 0, r_aligned16 );
1324 am_offset = am_offset_zero;
1325 for (i = 0; i < 16; i+=stride, am_offset = PPCAMode_IR( i, r_aligned16)) {
1326 addInstr(env, PPCInstr_Store( num_bytes_to_store, am_offset, r_src, env->mode64 ));
1327 }
1328
1329 /* Effectively splat the r_src value to dst */
1330 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 16, dst, am_offset_zero ) );
1331 add_to_sp( env, 32 ); // Reset SP
1332
1333 return dst;
1334 }
1335 }
1336
1337
1338 /* for each lane of vSrc: lane == nan ? laneX = all 1's : all 0's */
isNan(ISelEnv * env,HReg vSrc,IREndness IEndianess)1339 static HReg isNan ( ISelEnv* env, HReg vSrc, IREndness IEndianess )
1340 {
1341 HReg zeros, msk_exp, msk_mnt, expt, mnts, vIsNan;
1342
1343 vassert(hregClass(vSrc) == HRcVec128);
1344
1345 zeros = mk_AvDuplicateRI(env, mkU32(0), IEndianess);
1346 msk_exp = mk_AvDuplicateRI(env, mkU32(0x7F800000), IEndianess);
1347 msk_mnt = mk_AvDuplicateRI(env, mkU32(0x7FFFFF), IEndianess);
1348 expt = newVRegV(env);
1349 mnts = newVRegV(env);
1350 vIsNan = newVRegV(env);
1351
1352 /* 32bit float => sign(1) | exponent(8) | mantissa(23)
1353 nan => exponent all ones, mantissa > 0 */
1354
1355 addInstr(env, PPCInstr_AvBinary(Pav_AND, expt, vSrc, msk_exp));
1356 addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, expt, expt, msk_exp));
1357 addInstr(env, PPCInstr_AvBinary(Pav_AND, mnts, vSrc, msk_mnt));
1358 addInstr(env, PPCInstr_AvBin32x4(Pav_CMPGTU, mnts, mnts, zeros));
1359 addInstr(env, PPCInstr_AvBinary(Pav_AND, vIsNan, expt, mnts));
1360 return vIsNan;
1361 }
1362
1363
1364 /*---------------------------------------------------------*/
1365 /*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
1366 /*---------------------------------------------------------*/
1367
1368 /* Select insns for an integer-typed expression, and add them to the
1369 code list. Return a reg holding the result. This reg will be a
1370 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
1371 want to modify it, ask for a new vreg, copy it in there, and modify
1372 the copy. The register allocator will do its best to map both
1373 vregs to the same real register, so the copies will often disappear
1374 later in the game.
1375
1376 This should handle expressions of 64, 32, 16 and 8-bit type.
1377 All results are returned in a (mode64 ? 64bit : 32bit) register.
1378 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
1379 are arbitrary, so you should mask or sign extend partial values
1380 if necessary.
1381 */
1382
iselWordExpr_R(ISelEnv * env,IRExpr * e,IREndness IEndianess)1383 static HReg iselWordExpr_R ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
1384 {
1385 HReg r = iselWordExpr_R_wrk(env, e, IEndianess);
1386 /* sanity checks ... */
1387 # if 0
1388 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1389 # endif
1390
1391 vassert(hregClass(r) == HRcGPR(env->mode64));
1392 vassert(hregIsVirtual(r));
1393 return r;
1394 }
1395
1396 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_R_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)1397 static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e,
1398 IREndness IEndianess )
1399 {
1400 Bool mode64 = env->mode64;
1401 MatchInfo mi;
1402 DECLARE_PATTERN(p_32to1_then_1Uto8);
1403
1404 IRType ty = typeOfIRExpr(env->type_env,e);
1405 vassert(ty == Ity_I8 || ty == Ity_I16 ||
1406 ty == Ity_I32 || ((ty == Ity_I64) && mode64));
1407
1408 switch (e->tag) {
1409
1410 /* --------- TEMP --------- */
1411 case Iex_RdTmp:
1412 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
1413
1414 /* --------- LOAD --------- */
1415 case Iex_Load: {
1416 HReg r_dst;
1417 PPCAMode* am_addr;
1418 if (e->Iex.Load.end != IEndianess)
1419 goto irreducible;
1420 r_dst = newVRegI(env);
1421 am_addr = iselWordExpr_AMode( env, e->Iex.Load.addr, ty/*of xfer*/,
1422 IEndianess );
1423 addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)),
1424 r_dst, am_addr, mode64 ));
1425 return r_dst;
1426 /*NOTREACHED*/
1427 }
1428
1429 /* --------- BINARY OP --------- */
1430 case Iex_Binop: {
1431 PPCAluOp aluOp;
1432 PPCShftOp shftOp;
1433
1434 /* Is it an addition or logical style op? */
1435 switch (e->Iex.Binop.op) {
1436 case Iop_Add8: case Iop_Add16: case Iop_Add32: case Iop_Add64:
1437 aluOp = Palu_ADD; break;
1438 case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: case Iop_Sub64:
1439 aluOp = Palu_SUB; break;
1440 case Iop_And8: case Iop_And16: case Iop_And32: case Iop_And64:
1441 aluOp = Palu_AND; break;
1442 case Iop_Or8: case Iop_Or16: case Iop_Or32: case Iop_Or64:
1443 aluOp = Palu_OR; break;
1444 case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: case Iop_Xor64:
1445 aluOp = Palu_XOR; break;
1446 default:
1447 aluOp = Palu_INVALID; break;
1448 }
1449 /* For commutative ops we assume any literal
1450 values are on the second operand. */
1451 if (aluOp != Palu_INVALID) {
1452 HReg r_dst = newVRegI(env);
1453 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1454 PPCRH* ri_srcR = NULL;
1455 /* get right arg into an RH, in the appropriate way */
1456 switch (aluOp) {
1457 case Palu_ADD: case Palu_SUB:
1458 ri_srcR = iselWordExpr_RH(env, True/*signed*/,
1459 e->Iex.Binop.arg2, IEndianess);
1460 break;
1461 case Palu_AND: case Palu_OR: case Palu_XOR:
1462 ri_srcR = iselWordExpr_RH(env, False/*signed*/,
1463 e->Iex.Binop.arg2, IEndianess);
1464 break;
1465 default:
1466 vpanic("iselWordExpr_R_wrk-aluOp-arg2");
1467 }
1468 addInstr(env, PPCInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR));
1469 return r_dst;
1470 }
1471
1472 /* a shift? */
1473 switch (e->Iex.Binop.op) {
1474 case Iop_Shl8: case Iop_Shl16: case Iop_Shl32: case Iop_Shl64:
1475 shftOp = Pshft_SHL; break;
1476 case Iop_Shr8: case Iop_Shr16: case Iop_Shr32: case Iop_Shr64:
1477 shftOp = Pshft_SHR; break;
1478 case Iop_Sar8: case Iop_Sar16: case Iop_Sar32: case Iop_Sar64:
1479 shftOp = Pshft_SAR; break;
1480 default:
1481 shftOp = Pshft_INVALID; break;
1482 }
1483 /* we assume any literal values are on the second operand. */
1484 if (shftOp != Pshft_INVALID) {
1485 HReg r_dst = newVRegI(env);
1486 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1487 PPCRH* ri_srcR = NULL;
1488 /* get right arg into an RH, in the appropriate way */
1489 switch (shftOp) {
1490 case Pshft_SHL: case Pshft_SHR: case Pshft_SAR:
1491 if (!mode64)
1492 ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2, IEndianess);
1493 else
1494 ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2, IEndianess);
1495 break;
1496 default:
1497 vpanic("iselIntExpr_R_wrk-shftOp-arg2");
1498 }
1499 /* widen the left arg if needed */
1500 if (shftOp == Pshft_SHR || shftOp == Pshft_SAR) {
1501 if (ty == Ity_I8 || ty == Ity_I16) {
1502 PPCRH* amt = PPCRH_Imm(False,
1503 toUShort(ty == Ity_I8 ? 24 : 16));
1504 HReg tmp = newVRegI(env);
1505 addInstr(env, PPCInstr_Shft(Pshft_SHL,
1506 True/*32bit shift*/,
1507 tmp, r_srcL, amt));
1508 addInstr(env, PPCInstr_Shft(shftOp,
1509 True/*32bit shift*/,
1510 tmp, tmp, amt));
1511 r_srcL = tmp;
1512 vassert(0); /* AWAITING TEST CASE */
1513 }
1514 }
1515 /* Only 64 expressions need 64bit shifts,
1516 32bit shifts are fine for all others */
1517 if (ty == Ity_I64) {
1518 vassert(mode64);
1519 addInstr(env, PPCInstr_Shft(shftOp, False/*64bit shift*/,
1520 r_dst, r_srcL, ri_srcR));
1521 } else {
1522 addInstr(env, PPCInstr_Shft(shftOp, True/*32bit shift*/,
1523 r_dst, r_srcL, ri_srcR));
1524 }
1525 return r_dst;
1526 }
1527
1528 /* How about a div? */
1529 if (e->Iex.Binop.op == Iop_DivS32 ||
1530 e->Iex.Binop.op == Iop_DivU32 ||
1531 e->Iex.Binop.op == Iop_DivS32E ||
1532 e->Iex.Binop.op == Iop_DivU32E) {
1533 Bool syned = toBool((e->Iex.Binop.op == Iop_DivS32) || (e->Iex.Binop.op == Iop_DivS32E));
1534 HReg r_dst = newVRegI(env);
1535 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1536 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
1537 addInstr( env,
1538 PPCInstr_Div( ( ( e->Iex.Binop.op == Iop_DivU32E )
1539 || ( e->Iex.Binop.op == Iop_DivS32E ) ) ? True
1540 : False,
1541 syned,
1542 True/*32bit div*/,
1543 r_dst,
1544 r_srcL,
1545 r_srcR ) );
1546 return r_dst;
1547 }
1548 if (e->Iex.Binop.op == Iop_DivS64 ||
1549 e->Iex.Binop.op == Iop_DivU64 || e->Iex.Binop.op == Iop_DivS64E
1550 || e->Iex.Binop.op == Iop_DivU64E ) {
1551 Bool syned = toBool((e->Iex.Binop.op == Iop_DivS64) ||(e->Iex.Binop.op == Iop_DivS64E));
1552 HReg r_dst = newVRegI(env);
1553 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1554 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
1555 vassert(mode64);
1556 addInstr( env,
1557 PPCInstr_Div( ( ( e->Iex.Binop.op == Iop_DivS64E )
1558 || ( e->Iex.Binop.op
1559 == Iop_DivU64E ) ) ? True
1560 : False,
1561 syned,
1562 False/*64bit div*/,
1563 r_dst,
1564 r_srcL,
1565 r_srcR ) );
1566 return r_dst;
1567 }
1568
1569 /* No? Anyone for a mul? */
1570 if (e->Iex.Binop.op == Iop_Mul32
1571 || e->Iex.Binop.op == Iop_Mul64) {
1572 Bool syned = False;
1573 Bool sz32 = (e->Iex.Binop.op != Iop_Mul64);
1574 HReg r_dst = newVRegI(env);
1575 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1576 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
1577 addInstr(env, PPCInstr_MulL(syned, False/*lo32*/, sz32,
1578 r_dst, r_srcL, r_srcR));
1579 return r_dst;
1580 }
1581
1582 /* 32 x 32 -> 64 multiply */
1583 if (mode64
1584 && (e->Iex.Binop.op == Iop_MullU32
1585 || e->Iex.Binop.op == Iop_MullS32)) {
1586 HReg tLo = newVRegI(env);
1587 HReg tHi = newVRegI(env);
1588 HReg r_dst = newVRegI(env);
1589 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS32);
1590 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1591 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
1592 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
1593 False/*lo32*/, True/*32bit mul*/,
1594 tLo, r_srcL, r_srcR));
1595 addInstr(env, PPCInstr_MulL(syned,
1596 True/*hi32*/, True/*32bit mul*/,
1597 tHi, r_srcL, r_srcR));
1598 addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1599 r_dst, tHi, PPCRH_Imm(False,32)));
1600 addInstr(env, PPCInstr_Alu(Palu_OR,
1601 r_dst, r_dst, PPCRH_Reg(tLo)));
1602 return r_dst;
1603 }
1604
1605 /* El-mutanto 3-way compare? */
1606 if (e->Iex.Binop.op == Iop_CmpORD32S
1607 || e->Iex.Binop.op == Iop_CmpORD32U) {
1608 Bool syned = toBool(e->Iex.Binop.op == Iop_CmpORD32S);
1609 HReg dst = newVRegI(env);
1610 HReg srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1611 PPCRH* srcR = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2,
1612 IEndianess);
1613 addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
1614 7/*cr*/, srcL, srcR));
1615 addInstr(env, PPCInstr_MfCR(dst));
1616 addInstr(env, PPCInstr_Alu(Palu_AND, dst, dst,
1617 PPCRH_Imm(False,7<<1)));
1618 return dst;
1619 }
1620
1621 if (e->Iex.Binop.op == Iop_CmpORD64S
1622 || e->Iex.Binop.op == Iop_CmpORD64U) {
1623 Bool syned = toBool(e->Iex.Binop.op == Iop_CmpORD64S);
1624 HReg dst = newVRegI(env);
1625 HReg srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1626 PPCRH* srcR = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2,
1627 IEndianess);
1628 vassert(mode64);
1629 addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
1630 7/*cr*/, srcL, srcR));
1631 addInstr(env, PPCInstr_MfCR(dst));
1632 addInstr(env, PPCInstr_Alu(Palu_AND, dst, dst,
1633 PPCRH_Imm(False,7<<1)));
1634 return dst;
1635 }
1636
1637 if (e->Iex.Binop.op == Iop_Max32U) {
1638 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1639 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
1640 HReg rdst = newVRegI(env);
1641 PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
1642 addInstr(env, mk_iMOVds_RR(rdst, r1));
1643 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
1644 7/*cr*/, rdst, PPCRH_Reg(r2)));
1645 addInstr(env, PPCInstr_CMov(cc, rdst, PPCRI_Reg(r2)));
1646 return rdst;
1647 }
1648
1649 if (e->Iex.Binop.op == Iop_32HLto64) {
1650 HReg r_Hi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1651 HReg r_Lo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
1652 HReg r_Tmp = newVRegI(env);
1653 HReg r_dst = newVRegI(env);
1654 HReg msk = newVRegI(env);
1655 vassert(mode64);
1656 /* r_dst = OR( r_Hi<<32, r_Lo ) */
1657 addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1658 r_dst, r_Hi, PPCRH_Imm(False,32)));
1659 addInstr(env, PPCInstr_LI(msk, 0xFFFFFFFF, mode64));
1660 addInstr(env, PPCInstr_Alu( Palu_AND, r_Tmp, r_Lo,
1661 PPCRH_Reg(msk) ));
1662 addInstr(env, PPCInstr_Alu( Palu_OR, r_dst, r_dst,
1663 PPCRH_Reg(r_Tmp) ));
1664 return r_dst;
1665 }
1666
1667 if ((e->Iex.Binop.op == Iop_CmpF64) ||
1668 (e->Iex.Binop.op == Iop_CmpD64) ||
1669 (e->Iex.Binop.op == Iop_CmpD128)) {
1670 HReg fr_srcL;
1671 HReg fr_srcL_lo;
1672 HReg fr_srcR;
1673 HReg fr_srcR_lo;
1674
1675 HReg r_ccPPC = newVRegI(env);
1676 HReg r_ccIR = newVRegI(env);
1677 HReg r_ccIR_b0 = newVRegI(env);
1678 HReg r_ccIR_b2 = newVRegI(env);
1679 HReg r_ccIR_b6 = newVRegI(env);
1680
1681 if (e->Iex.Binop.op == Iop_CmpF64) {
1682 fr_srcL = iselDblExpr(env, e->Iex.Binop.arg1, IEndianess);
1683 fr_srcR = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
1684 addInstr(env, PPCInstr_FpCmp(r_ccPPC, fr_srcL, fr_srcR));
1685
1686 } else if (e->Iex.Binop.op == Iop_CmpD64) {
1687 fr_srcL = iselDfp64Expr(env, e->Iex.Binop.arg1, IEndianess);
1688 fr_srcR = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
1689 addInstr(env, PPCInstr_Dfp64Cmp(r_ccPPC, fr_srcL, fr_srcR));
1690
1691 } else { // e->Iex.Binop.op == Iop_CmpD128
1692 iselDfp128Expr(&fr_srcL, &fr_srcL_lo, env, e->Iex.Binop.arg1,
1693 IEndianess);
1694 iselDfp128Expr(&fr_srcR, &fr_srcR_lo, env, e->Iex.Binop.arg2,
1695 IEndianess);
1696 addInstr(env, PPCInstr_Dfp128Cmp(r_ccPPC, fr_srcL, fr_srcL_lo,
1697 fr_srcR, fr_srcR_lo));
1698 }
1699
1700 /* Map compare result from PPC to IR,
1701 conforming to CmpF64 definition. */
1702 /*
1703 FP cmp result | PPC | IR
1704 --------------------------
1705 UN | 0x1 | 0x45
1706 EQ | 0x2 | 0x40
1707 GT | 0x4 | 0x00
1708 LT | 0x8 | 0x01
1709 */
1710
1711 // r_ccIR_b0 = r_ccPPC[0] | r_ccPPC[3]
1712 addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1713 r_ccIR_b0, r_ccPPC,
1714 PPCRH_Imm(False,0x3)));
1715 addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR_b0,
1716 r_ccPPC, PPCRH_Reg(r_ccIR_b0)));
1717 addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b0,
1718 r_ccIR_b0, PPCRH_Imm(False,0x1)));
1719
1720 // r_ccIR_b2 = r_ccPPC[0]
1721 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1722 r_ccIR_b2, r_ccPPC,
1723 PPCRH_Imm(False,0x2)));
1724 addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b2,
1725 r_ccIR_b2, PPCRH_Imm(False,0x4)));
1726
1727 // r_ccIR_b6 = r_ccPPC[0] | r_ccPPC[1]
1728 addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1729 r_ccIR_b6, r_ccPPC,
1730 PPCRH_Imm(False,0x1)));
1731 addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR_b6,
1732 r_ccPPC, PPCRH_Reg(r_ccIR_b6)));
1733 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1734 r_ccIR_b6, r_ccIR_b6,
1735 PPCRH_Imm(False,0x6)));
1736 addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b6,
1737 r_ccIR_b6, PPCRH_Imm(False,0x40)));
1738
1739 // r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6
1740 addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR,
1741 r_ccIR_b0, PPCRH_Reg(r_ccIR_b2)));
1742 addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR,
1743 r_ccIR, PPCRH_Reg(r_ccIR_b6)));
1744 return r_ccIR;
1745 }
1746
1747 if ( e->Iex.Binop.op == Iop_F64toI32S ||
1748 e->Iex.Binop.op == Iop_F64toI32U ) {
1749 /* This works in both mode64 and mode32. */
1750 HReg r1 = StackFramePtr(env->mode64);
1751 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1752 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
1753 HReg ftmp = newVRegF(env);
1754 HReg idst = newVRegI(env);
1755
1756 /* Set host rounding mode */
1757 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
1758
1759 sub_from_sp( env, 16 );
1760 addInstr(env, PPCInstr_FpCftI(False/*F->I*/, True/*int32*/,
1761 e->Iex.Binop.op == Iop_F64toI32S ? True/*syned*/
1762 : False,
1763 True/*flt64*/,
1764 ftmp, fsrc));
1765 addInstr(env, PPCInstr_FpSTFIW(r1, ftmp));
1766 addInstr(env, PPCInstr_Load(4, idst, zero_r1, mode64));
1767
1768 /* in 64-bit mode we need to sign-widen idst. */
1769 if (mode64)
1770 addInstr(env, PPCInstr_Unary(Pun_EXTSW, idst, idst));
1771
1772 add_to_sp( env, 16 );
1773
1774 ///* Restore default FPU rounding. */
1775 //set_FPU_rounding_default( env );
1776 return idst;
1777 }
1778
1779 if (e->Iex.Binop.op == Iop_F64toI64S || e->Iex.Binop.op == Iop_F64toI64U ) {
1780 if (mode64) {
1781 HReg r1 = StackFramePtr(env->mode64);
1782 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1783 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2,
1784 IEndianess);
1785 HReg idst = newVRegI(env);
1786 HReg ftmp = newVRegF(env);
1787
1788 /* Set host rounding mode */
1789 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
1790
1791 sub_from_sp( env, 16 );
1792 addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/,
1793 ( e->Iex.Binop.op == Iop_F64toI64S ) ? True
1794 : False,
1795 True, ftmp, fsrc));
1796 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
1797 addInstr(env, PPCInstr_Load(8, idst, zero_r1, True/*mode64*/));
1798 add_to_sp( env, 16 );
1799
1800 ///* Restore default FPU rounding. */
1801 //set_FPU_rounding_default( env );
1802 return idst;
1803 }
1804 }
1805
1806 if (e->Iex.Binop.op == Iop_D64toI64S ) {
1807 HReg r1 = StackFramePtr(env->mode64);
1808 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1809 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
1810 HReg idst = newVRegI(env);
1811 HReg ftmp = newVRegF(env);
1812
1813 /* Set host rounding mode */
1814 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
1815 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTFIX, ftmp, fr_src));
1816 sub_from_sp( env, 16 );
1817 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
1818 addInstr(env, PPCInstr_Load(8, idst, zero_r1, mode64));
1819
1820 add_to_sp( env, 16 );
1821
1822 ///* Restore default FPU rounding. */
1823 //set_FPU_rounding_default( env );
1824 return idst;
1825 }
1826
1827 if (e->Iex.Binop.op == Iop_D128toI64S ) {
1828 PPCFpOp fpop = Pfp_DCTFIXQ;
1829 HReg r_srcHi = newVRegF(env);
1830 HReg r_srcLo = newVRegF(env);
1831 HReg idst = newVRegI(env);
1832 HReg ftmp = newVRegF(env);
1833 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
1834
1835 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
1836 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
1837 IEndianess);
1838 addInstr(env, PPCInstr_DfpD128toD64(fpop, ftmp, r_srcHi, r_srcLo));
1839
1840 // put the D64 result into an integer register
1841 sub_from_sp( env, 16 );
1842 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
1843 addInstr(env, PPCInstr_Load(8, idst, zero_r1, True/*mode64*/));
1844 add_to_sp( env, 16 );
1845 return idst;
1846 }
1847 break;
1848 }
1849
1850 /* --------- UNARY OP --------- */
1851 case Iex_Unop: {
1852 IROp op_unop = e->Iex.Unop.op;
1853
1854 /* 1Uto8(32to1(expr32)) */
1855 DEFINE_PATTERN(p_32to1_then_1Uto8,
1856 unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
1857 if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
1858 IRExpr* expr32 = mi.bindee[0];
1859 HReg r_dst = newVRegI(env);
1860 HReg r_src = iselWordExpr_R(env, expr32, IEndianess);
1861 addInstr(env, PPCInstr_Alu(Palu_AND, r_dst,
1862 r_src, PPCRH_Imm(False,1)));
1863 return r_dst;
1864 }
1865
1866 /* 16Uto32(LDbe:I16(expr32)) */
1867 {
1868 DECLARE_PATTERN(p_LDbe16_then_16Uto32);
1869 DEFINE_PATTERN(p_LDbe16_then_16Uto32,
1870 unop(Iop_16Uto32,
1871 IRExpr_Load(IEndianess,Ity_I16,bind(0))) );
1872 if (matchIRExpr(&mi,p_LDbe16_then_16Uto32,e)) {
1873 HReg r_dst = newVRegI(env);
1874 PPCAMode* amode
1875 = iselWordExpr_AMode( env, mi.bindee[0], Ity_I16/*xfer*/,
1876 IEndianess );
1877 addInstr(env, PPCInstr_Load(2,r_dst,amode, mode64));
1878 return r_dst;
1879 }
1880 }
1881
1882 switch (op_unop) {
1883 case Iop_8Uto16:
1884 case Iop_8Uto32:
1885 case Iop_8Uto64:
1886 case Iop_16Uto32:
1887 case Iop_16Uto64: {
1888 HReg r_dst = newVRegI(env);
1889 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1890 UShort mask = toUShort(op_unop==Iop_16Uto64 ? 0xFFFF :
1891 op_unop==Iop_16Uto32 ? 0xFFFF : 0xFF);
1892 addInstr(env, PPCInstr_Alu(Palu_AND,r_dst,r_src,
1893 PPCRH_Imm(False,mask)));
1894 return r_dst;
1895 }
1896 case Iop_32Uto64: {
1897 HReg r_dst = newVRegI(env);
1898 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1899 vassert(mode64);
1900 addInstr(env,
1901 PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1902 r_dst, r_src, PPCRH_Imm(False,32)));
1903 addInstr(env,
1904 PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/,
1905 r_dst, r_dst, PPCRH_Imm(False,32)));
1906 return r_dst;
1907 }
1908 case Iop_8Sto16:
1909 case Iop_8Sto32:
1910 case Iop_16Sto32: {
1911 HReg r_dst = newVRegI(env);
1912 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1913 UShort amt = toUShort(op_unop==Iop_16Sto32 ? 16 : 24);
1914 addInstr(env,
1915 PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1916 r_dst, r_src, PPCRH_Imm(False,amt)));
1917 addInstr(env,
1918 PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1919 r_dst, r_dst, PPCRH_Imm(False,amt)));
1920 return r_dst;
1921 }
1922 case Iop_8Sto64:
1923 case Iop_16Sto64: {
1924 HReg r_dst = newVRegI(env);
1925 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1926 UShort amt = toUShort(op_unop==Iop_8Sto64 ? 56 : 48);
1927 vassert(mode64);
1928 addInstr(env,
1929 PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1930 r_dst, r_src, PPCRH_Imm(False,amt)));
1931 addInstr(env,
1932 PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
1933 r_dst, r_dst, PPCRH_Imm(False,amt)));
1934 return r_dst;
1935 }
1936 case Iop_32Sto64: {
1937 HReg r_dst = newVRegI(env);
1938 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1939 vassert(mode64);
1940 /* According to the IBM docs, in 64 bit mode, srawi r,r,0
1941 sign extends the lower 32 bits into the upper 32 bits. */
1942 addInstr(env,
1943 PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1944 r_dst, r_src, PPCRH_Imm(False,0)));
1945 return r_dst;
1946 }
1947 case Iop_Not8:
1948 case Iop_Not16:
1949 case Iop_Not32:
1950 case Iop_Not64: {
1951 if (op_unop == Iop_Not64) vassert(mode64);
1952 HReg r_dst = newVRegI(env);
1953 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1954 addInstr(env, PPCInstr_Unary(Pun_NOT,r_dst,r_src));
1955 return r_dst;
1956 }
1957 case Iop_64HIto32: {
1958 if (!mode64) {
1959 HReg rHi, rLo;
1960 iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg, IEndianess);
1961 return rHi; /* and abandon rLo .. poor wee thing :-) */
1962 } else {
1963 HReg r_dst = newVRegI(env);
1964 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1965 addInstr(env,
1966 PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/,
1967 r_dst, r_src, PPCRH_Imm(False,32)));
1968 return r_dst;
1969 }
1970 }
1971 case Iop_64to32: {
1972 if (!mode64) {
1973 HReg rHi, rLo;
1974 iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg, IEndianess);
1975 return rLo; /* similar stupid comment to the above ... */
1976 } else {
1977 /* This is a no-op. */
1978 return iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1979 }
1980 }
1981 case Iop_64to16: {
1982 if (mode64) { /* This is a no-op. */
1983 return iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1984 }
1985 break; /* evidently not used in 32-bit mode */
1986 }
1987 case Iop_16HIto8:
1988 case Iop_32HIto16: {
1989 HReg r_dst = newVRegI(env);
1990 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1991 UShort shift = toUShort(op_unop == Iop_16HIto8 ? 8 : 16);
1992 addInstr(env,
1993 PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1994 r_dst, r_src, PPCRH_Imm(False,shift)));
1995 return r_dst;
1996 }
1997 case Iop_128HIto64:
1998 if (mode64) {
1999 HReg rHi, rLo;
2000 iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg, IEndianess);
2001 return rHi; /* and abandon rLo .. poor wee thing :-) */
2002 }
2003 break;
2004 case Iop_128to64:
2005 if (mode64) {
2006 HReg rHi, rLo;
2007 iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg, IEndianess);
2008 return rLo; /* similar stupid comment to the above ... */
2009 }
2010 break;
2011 case Iop_1Uto64:
2012 case Iop_1Uto32:
2013 case Iop_1Uto8:
2014 if ((op_unop != Iop_1Uto64) || mode64) {
2015 HReg r_dst = newVRegI(env);
2016 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
2017 addInstr(env, PPCInstr_Set(cond,r_dst));
2018 return r_dst;
2019 }
2020 break;
2021 case Iop_1Sto8:
2022 case Iop_1Sto16:
2023 case Iop_1Sto32: {
2024 /* could do better than this, but for now ... */
2025 HReg r_dst = newVRegI(env);
2026 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
2027 addInstr(env, PPCInstr_Set(cond,r_dst));
2028 addInstr(env,
2029 PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
2030 r_dst, r_dst, PPCRH_Imm(False,31)));
2031 addInstr(env,
2032 PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2033 r_dst, r_dst, PPCRH_Imm(False,31)));
2034 return r_dst;
2035 }
2036 case Iop_1Sto64:
2037 if (mode64) {
2038 /* could do better than this, but for now ... */
2039 HReg r_dst = newVRegI(env);
2040 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
2041 addInstr(env, PPCInstr_Set(cond,r_dst));
2042 addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
2043 r_dst, r_dst, PPCRH_Imm(False,63)));
2044 addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
2045 r_dst, r_dst, PPCRH_Imm(False,63)));
2046 return r_dst;
2047 }
2048 break;
2049 case Iop_Clz32:
2050 case Iop_Clz64: {
2051 HReg r_src, r_dst;
2052 PPCUnaryOp op_clz = (op_unop == Iop_Clz32) ? Pun_CLZ32 :
2053 Pun_CLZ64;
2054 if (op_unop == Iop_Clz64 && !mode64)
2055 goto irreducible;
2056 /* Count leading zeroes. */
2057 r_dst = newVRegI(env);
2058 r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2059 addInstr(env, PPCInstr_Unary(op_clz,r_dst,r_src));
2060 return r_dst;
2061 }
2062
2063 case Iop_Left8:
2064 case Iop_Left16:
2065 case Iop_Left32:
2066 case Iop_Left64: {
2067 HReg r_src, r_dst;
2068 if (op_unop == Iop_Left64 && !mode64)
2069 goto irreducible;
2070 r_dst = newVRegI(env);
2071 r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2072 addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
2073 addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
2074 return r_dst;
2075 }
2076
2077 case Iop_CmpwNEZ32: {
2078 HReg r_dst = newVRegI(env);
2079 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2080 addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
2081 addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
2082 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2083 r_dst, r_dst, PPCRH_Imm(False, 31)));
2084 return r_dst;
2085 }
2086
2087 case Iop_CmpwNEZ64: {
2088 HReg r_dst = newVRegI(env);
2089 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2090 if (!mode64) goto irreducible;
2091 addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
2092 addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
2093 addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
2094 r_dst, r_dst, PPCRH_Imm(False, 63)));
2095 return r_dst;
2096 }
2097
2098 case Iop_V128to32: {
2099 HReg r_aligned16;
2100 HReg dst = newVRegI(env);
2101 HReg vec = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
2102 PPCAMode *am_off0, *am_off_word0;
2103 sub_from_sp( env, 32 ); // Move SP down 32 bytes
2104
2105 // get a quadword aligned address within our stack space
2106 r_aligned16 = get_sp_aligned16( env );
2107 am_off0 = PPCAMode_IR( 0, r_aligned16 );
2108
2109 /* Note that the store below (done via PPCInstr_AvLdSt) uses
2110 * stvx, which stores the vector in proper LE format,
2111 * with byte zero (far right byte of the register in LE format)
2112 * stored at the lowest memory address. Therefore, to obtain
2113 * integer word zero, we need to use that lowest memory address
2114 * as the base for the load.
2115 */
2116 if (IEndianess == Iend_LE)
2117 am_off_word0 = am_off0;
2118 else
2119 am_off_word0 = PPCAMode_IR( 12,r_aligned16 );
2120
2121 // store vec, load low word to dst
2122 addInstr(env,
2123 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
2124 addInstr(env,
2125 PPCInstr_Load( 4, dst, am_off_word0, mode64 ));
2126
2127 add_to_sp( env, 32 ); // Reset SP
2128 return dst;
2129 }
2130
2131 case Iop_V128to64:
2132 case Iop_V128HIto64:
2133 if (mode64) {
2134 HReg r_aligned16;
2135 HReg dst = newVRegI(env);
2136 HReg vec = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
2137 PPCAMode *am_off0, *am_off8, *am_off_arg;
2138 sub_from_sp( env, 32 ); // Move SP down 32 bytes
2139
2140 // get a quadword aligned address within our stack space
2141 r_aligned16 = get_sp_aligned16( env );
2142 am_off0 = PPCAMode_IR( 0, r_aligned16 );
2143 am_off8 = PPCAMode_IR( 8 ,r_aligned16 );
2144
2145 // store vec, load low word or high to dst
2146 addInstr(env,
2147 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
2148 if (IEndianess == Iend_LE) {
2149 if (op_unop == Iop_V128HIto64)
2150 am_off_arg = am_off8;
2151 else
2152 am_off_arg = am_off0;
2153 } else {
2154 if (op_unop == Iop_V128HIto64)
2155 am_off_arg = am_off0;
2156 else
2157 am_off_arg = am_off8;
2158 }
2159 addInstr(env,
2160 PPCInstr_Load(
2161 8, dst,
2162 am_off_arg,
2163 mode64 ));
2164
2165 add_to_sp( env, 32 ); // Reset SP
2166 return dst;
2167 }
2168 break;
2169 case Iop_16to8:
2170 case Iop_32to8:
2171 case Iop_32to16:
2172 case Iop_64to8:
2173 /* These are no-ops. */
2174 return iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2175
2176 /* ReinterpF64asI64(e) */
2177 /* Given an IEEE754 double, produce an I64 with the same bit
2178 pattern. */
2179 case Iop_ReinterpF64asI64:
2180 if (mode64) {
2181 PPCAMode *am_addr;
2182 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
2183 HReg r_dst = newVRegI(env);
2184
2185 sub_from_sp( env, 16 ); // Move SP down 16 bytes
2186 am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
2187
2188 // store as F64
2189 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
2190 fr_src, am_addr ));
2191 // load as Ity_I64
2192 addInstr(env, PPCInstr_Load( 8, r_dst, am_addr, mode64 ));
2193
2194 add_to_sp( env, 16 ); // Reset SP
2195 return r_dst;
2196 }
2197 break;
2198
2199 /* ReinterpF32asI32(e) */
2200 /* Given an IEEE754 float, produce an I32 with the same bit
2201 pattern. */
2202 case Iop_ReinterpF32asI32: {
2203 /* I believe this generates correct code for both 32- and
2204 64-bit hosts. */
2205 PPCAMode *am_addr;
2206 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg, IEndianess);
2207 HReg r_dst = newVRegI(env);
2208
2209 sub_from_sp( env, 16 ); // Move SP down 16 bytes
2210 am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
2211
2212 // store as F32
2213 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
2214 fr_src, am_addr ));
2215 // load as Ity_I32
2216 addInstr(env, PPCInstr_Load( 4, r_dst, am_addr, mode64 ));
2217
2218 add_to_sp( env, 16 ); // Reset SP
2219 return r_dst;
2220 }
2221 break;
2222
2223 case Iop_ReinterpD64asI64:
2224 if (mode64) {
2225 PPCAMode *am_addr;
2226 HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
2227 HReg r_dst = newVRegI(env);
2228
2229 sub_from_sp( env, 16 ); // Move SP down 16 bytes
2230 am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
2231
2232 // store as D64
2233 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
2234 fr_src, am_addr ));
2235 // load as Ity_I64
2236 addInstr(env, PPCInstr_Load( 8, r_dst, am_addr, mode64 ));
2237 add_to_sp( env, 16 ); // Reset SP
2238 return r_dst;
2239 }
2240 break;
2241
2242 case Iop_BCDtoDPB: {
2243 /* the following is only valid in 64 bit mode */
2244 if (!mode64) break;
2245
2246 PPCCondCode cc;
2247 UInt argiregs;
2248 HReg argregs[1];
2249 HReg r_dst = newVRegI(env);
2250 Int argreg;
2251
2252 argiregs = 0;
2253 argreg = 0;
2254 argregs[0] = hregPPC_GPR3(mode64);
2255
2256 argiregs |= (1 << (argreg+3));
2257 addInstr(env, mk_iMOVds_RR( argregs[argreg++],
2258 iselWordExpr_R(env, e->Iex.Unop.arg,
2259 IEndianess) ) );
2260
2261 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
2262 if (IEndianess == Iend_LE) {
2263 addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_BCDtoDPB,
2264 argiregs,
2265 mk_RetLoc_simple(RLPri_Int)) );
2266 } else {
2267 HWord* fdescr;
2268 fdescr = (HWord*)h_calc_BCDtoDPB;
2269 addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]),
2270 argiregs,
2271 mk_RetLoc_simple(RLPri_Int)) );
2272 }
2273
2274 addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
2275 return r_dst;
2276 }
2277
2278 case Iop_DPBtoBCD: {
2279 /* the following is only valid in 64 bit mode */
2280 if (!mode64) break;
2281
2282 PPCCondCode cc;
2283 UInt argiregs;
2284 HReg argregs[1];
2285 HReg r_dst = newVRegI(env);
2286 Int argreg;
2287
2288 argiregs = 0;
2289 argreg = 0;
2290 argregs[0] = hregPPC_GPR3(mode64);
2291
2292 argiregs |= (1 << (argreg+3));
2293 addInstr(env, mk_iMOVds_RR( argregs[argreg++],
2294 iselWordExpr_R(env, e->Iex.Unop.arg,
2295 IEndianess) ) );
2296
2297 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
2298
2299 if (IEndianess == Iend_LE) {
2300 addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_DPBtoBCD,
2301 argiregs,
2302 mk_RetLoc_simple(RLPri_Int) ) );
2303 } else {
2304 HWord* fdescr;
2305 fdescr = (HWord*)h_calc_DPBtoBCD;
2306 addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]),
2307 argiregs,
2308 mk_RetLoc_simple(RLPri_Int) ) );
2309 }
2310
2311 addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
2312 return r_dst;
2313 }
2314
2315 default:
2316 break;
2317 }
2318
2319 switch (e->Iex.Unop.op) {
2320 case Iop_ExtractExpD64: {
2321
2322 HReg fr_dst = newVRegI(env);
2323 HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
2324 HReg tmp = newVRegF(env);
2325 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
2326 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DXEX, tmp, fr_src));
2327
2328 // put the D64 result into a integer register
2329 sub_from_sp( env, 16 );
2330 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
2331 addInstr(env, PPCInstr_Load(8, fr_dst, zero_r1, env->mode64));
2332 add_to_sp( env, 16 );
2333 return fr_dst;
2334 }
2335 case Iop_ExtractExpD128: {
2336 HReg fr_dst = newVRegI(env);
2337 HReg r_srcHi;
2338 HReg r_srcLo;
2339 HReg tmp = newVRegF(env);
2340 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
2341
2342 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
2343 IEndianess);
2344 addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, tmp,
2345 r_srcHi, r_srcLo));
2346
2347 sub_from_sp( env, 16 );
2348 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
2349 addInstr(env, PPCInstr_Load(8, fr_dst, zero_r1, env->mode64));
2350 add_to_sp( env, 16 );
2351 return fr_dst;
2352 }
2353 default:
2354 break;
2355 }
2356
2357 break;
2358 }
2359
2360 /* --------- GET --------- */
2361 case Iex_Get: {
2362 if (ty == Ity_I8 || ty == Ity_I16 ||
2363 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
2364 HReg r_dst = newVRegI(env);
2365 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
2366 GuestStatePtr(mode64) );
2367 addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)),
2368 r_dst, am_addr, mode64 ));
2369 return r_dst;
2370 }
2371 break;
2372 }
2373
2374 case Iex_GetI: {
2375 PPCAMode* src_am
2376 = genGuestArrayOffset( env, e->Iex.GetI.descr,
2377 e->Iex.GetI.ix, e->Iex.GetI.bias,
2378 IEndianess );
2379 HReg r_dst = newVRegI(env);
2380 if (mode64 && ty == Ity_I64) {
2381 addInstr(env, PPCInstr_Load( toUChar(8),
2382 r_dst, src_am, mode64 ));
2383 return r_dst;
2384 }
2385 if ((!mode64) && ty == Ity_I32) {
2386 addInstr(env, PPCInstr_Load( toUChar(4),
2387 r_dst, src_am, mode64 ));
2388 return r_dst;
2389 }
2390 break;
2391 }
2392
2393 /* --------- CCALL --------- */
2394 case Iex_CCall: {
2395 vassert(ty == e->Iex.CCall.retty); /* well-formedness of IR */
2396
2397 /* be very restrictive for now. Only 32/64-bit ints allowed for
2398 args, and 32 bits or host machine word for return type. */
2399 if (!(ty == Ity_I32 || (mode64 && ty == Ity_I64)))
2400 goto irreducible;
2401
2402 /* Marshal args, do the call, clear stack. */
2403 UInt addToSp = 0;
2404 RetLoc rloc = mk_RetLoc_INVALID();
2405 doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
2406 e->Iex.CCall.cee, e->Iex.CCall.retty, e->Iex.CCall.args,
2407 IEndianess );
2408 vassert(is_sane_RetLoc(rloc));
2409 vassert(rloc.pri == RLPri_Int);
2410 vassert(addToSp == 0);
2411
2412 /* GPR3 now holds the destination address from Pin_Goto */
2413 HReg r_dst = newVRegI(env);
2414 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
2415 return r_dst;
2416 }
2417
2418 /* --------- LITERAL --------- */
2419 /* 32/16/8-bit literals */
2420 case Iex_Const: {
2421 Long l;
2422 HReg r_dst = newVRegI(env);
2423 IRConst* con = e->Iex.Const.con;
2424 switch (con->tag) {
2425 case Ico_U64: if (!mode64) goto irreducible;
2426 l = (Long) con->Ico.U64; break;
2427 case Ico_U32: l = (Long)(Int) con->Ico.U32; break;
2428 case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
2429 case Ico_U8: l = (Long)(Int)(Char )con->Ico.U8; break;
2430 default: vpanic("iselIntExpr_R.const(ppc)");
2431 }
2432 addInstr(env, PPCInstr_LI(r_dst, (ULong)l, mode64));
2433 return r_dst;
2434 }
2435
2436 /* --------- MULTIPLEX --------- */
2437 case Iex_ITE: { // VFD
2438 if ((ty == Ity_I8 || ty == Ity_I16 ||
2439 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) &&
2440 typeOfIRExpr(env->type_env,e->Iex.ITE.cond) == Ity_I1) {
2441 PPCRI* r1 = iselWordExpr_RI(env, e->Iex.ITE.iftrue, IEndianess);
2442 HReg r0 = iselWordExpr_R(env, e->Iex.ITE.iffalse, IEndianess);
2443 HReg r_dst = newVRegI(env);
2444 addInstr(env, mk_iMOVds_RR(r_dst,r0));
2445 PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
2446 addInstr(env, PPCInstr_CMov(cc, r_dst, r1));
2447 return r_dst;
2448 }
2449 break;
2450 }
2451
2452 default:
2453 break;
2454 } /* switch (e->tag) */
2455
2456
2457 /* We get here if no pattern matched. */
2458 irreducible:
2459 ppIRExpr(e);
2460 vpanic("iselIntExpr_R(ppc): cannot reduce tree");
2461 }
2462
2463
2464 /*---------------------------------------------------------*/
2465 /*--- ISEL: Integer expression auxiliaries ---*/
2466 /*---------------------------------------------------------*/
2467
2468 /* --------------------- AMODEs --------------------- */
2469
2470 /* Return an AMode which computes the value of the specified
2471 expression, possibly also adding insns to the code list as a
2472 result. The expression may only be a word-size one.
2473 */
2474
uInt_fits_in_16_bits(UInt u)2475 static Bool uInt_fits_in_16_bits ( UInt u )
2476 {
2477 /* Is u the same as the sign-extend of its lower 16 bits? */
2478 Int i = u & 0xFFFF;
2479 i <<= 16;
2480 i >>= 16;
2481 return toBool(u == (UInt)i);
2482 }
2483
uLong_fits_in_16_bits(ULong u)2484 static Bool uLong_fits_in_16_bits ( ULong u )
2485 {
2486 /* Is u the same as the sign-extend of its lower 16 bits? */
2487 Long i = u & 0xFFFFULL;
2488 i <<= 48;
2489 i >>= 48;
2490 return toBool(u == (ULong)i);
2491 }
2492
uLong_is_4_aligned(ULong u)2493 static Bool uLong_is_4_aligned ( ULong u )
2494 {
2495 return toBool((u & 3ULL) == 0);
2496 }
2497
sane_AMode(ISelEnv * env,PPCAMode * am)2498 static Bool sane_AMode ( ISelEnv* env, PPCAMode* am )
2499 {
2500 Bool mode64 = env->mode64;
2501 switch (am->tag) {
2502 case Pam_IR:
2503 /* Using uInt_fits_in_16_bits in 64-bit mode seems a bit bogus,
2504 somehow, but I think it's OK. */
2505 return toBool( hregClass(am->Pam.IR.base) == HRcGPR(mode64) &&
2506 hregIsVirtual(am->Pam.IR.base) &&
2507 uInt_fits_in_16_bits(am->Pam.IR.index) );
2508 case Pam_RR:
2509 return toBool( hregClass(am->Pam.RR.base) == HRcGPR(mode64) &&
2510 hregIsVirtual(am->Pam.RR.base) &&
2511 hregClass(am->Pam.RR.index) == HRcGPR(mode64) &&
2512 hregIsVirtual(am->Pam.RR.index) );
2513 default:
2514 vpanic("sane_AMode: unknown ppc amode tag");
2515 }
2516 }
2517
2518 static
iselWordExpr_AMode(ISelEnv * env,IRExpr * e,IRType xferTy,IREndness IEndianess)2519 PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy,
2520 IREndness IEndianess )
2521 {
2522 PPCAMode* am = iselWordExpr_AMode_wrk(env, e, xferTy, IEndianess);
2523 vassert(sane_AMode(env, am));
2524 return am;
2525 }
2526
2527 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_AMode_wrk(ISelEnv * env,IRExpr * e,IRType xferTy,IREndness IEndianess)2528 static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e,
2529 IRType xferTy, IREndness IEndianess )
2530 {
2531 IRType ty = typeOfIRExpr(env->type_env,e);
2532
2533 if (env->mode64) {
2534
2535 /* If the data load/store type is I32 or I64, this amode might
2536 be destined for use in ld/ldu/lwa/st/stu. In which case
2537 insist that if it comes out as an _IR, the immediate must
2538 have its bottom two bits be zero. This does assume that for
2539 any other type (I8/I16/I128/F32/F64/V128) the amode will not
2540 be parked in any such instruction. But that seems a
2541 reasonable assumption. */
2542 Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
2543
2544 vassert(ty == Ity_I64);
2545
2546 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
2547 if (e->tag == Iex_Binop
2548 && e->Iex.Binop.op == Iop_Add64
2549 && e->Iex.Binop.arg2->tag == Iex_Const
2550 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
2551 && (aligned4imm ? uLong_is_4_aligned(e->Iex.Binop.arg2
2552 ->Iex.Const.con->Ico.U64)
2553 : True)
2554 && uLong_fits_in_16_bits(e->Iex.Binop.arg2
2555 ->Iex.Const.con->Ico.U64)) {
2556 return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
2557 iselWordExpr_R(env, e->Iex.Binop.arg1,
2558 IEndianess) );
2559 }
2560
2561 /* Add64(expr,expr) */
2562 if (e->tag == Iex_Binop
2563 && e->Iex.Binop.op == Iop_Add64) {
2564 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2565 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
2566 return PPCAMode_RR( r_idx, r_base );
2567 }
2568
2569 } else {
2570
2571 vassert(ty == Ity_I32);
2572
2573 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
2574 if (e->tag == Iex_Binop
2575 && e->Iex.Binop.op == Iop_Add32
2576 && e->Iex.Binop.arg2->tag == Iex_Const
2577 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
2578 && uInt_fits_in_16_bits(e->Iex.Binop.arg2
2579 ->Iex.Const.con->Ico.U32)) {
2580 return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
2581 iselWordExpr_R(env, e->Iex.Binop.arg1,
2582 IEndianess) );
2583 }
2584
2585 /* Add32(expr,expr) */
2586 if (e->tag == Iex_Binop
2587 && e->Iex.Binop.op == Iop_Add32) {
2588 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2589 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
2590 return PPCAMode_RR( r_idx, r_base );
2591 }
2592
2593 }
2594
2595 /* Doesn't match anything in particular. Generate it into
2596 a register and use that. */
2597 return PPCAMode_IR( 0, iselWordExpr_R(env,e,IEndianess) );
2598 }
2599
2600
2601 /* --------------------- RH --------------------- */
2602
2603 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
2604 (reg-or-halfword-immediate). It's important to specify whether the
2605 immediate is to be regarded as signed or not. If yes, this will
2606 never return -32768 as an immediate; this guaranteed that all
2607 signed immediates that are return can have their sign inverted if
2608 need be. */
2609
iselWordExpr_RH(ISelEnv * env,Bool syned,IRExpr * e,IREndness IEndianess)2610 static PPCRH* iselWordExpr_RH ( ISelEnv* env, Bool syned, IRExpr* e,
2611 IREndness IEndianess )
2612 {
2613 PPCRH* ri = iselWordExpr_RH_wrk(env, syned, e, IEndianess);
2614 /* sanity checks ... */
2615 switch (ri->tag) {
2616 case Prh_Imm:
2617 vassert(ri->Prh.Imm.syned == syned);
2618 if (syned)
2619 vassert(ri->Prh.Imm.imm16 != 0x8000);
2620 return ri;
2621 case Prh_Reg:
2622 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2623 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2624 return ri;
2625 default:
2626 vpanic("iselIntExpr_RH: unknown ppc RH tag");
2627 }
2628 }
2629
2630 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH_wrk(ISelEnv * env,Bool syned,IRExpr * e,IREndness IEndianess)2631 static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, Bool syned, IRExpr* e,
2632 IREndness IEndianess )
2633 {
2634 ULong u;
2635 Long l;
2636 IRType ty = typeOfIRExpr(env->type_env,e);
2637 vassert(ty == Ity_I8 || ty == Ity_I16 ||
2638 ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2639
2640 /* special case: immediate */
2641 if (e->tag == Iex_Const) {
2642 IRConst* con = e->Iex.Const.con;
2643 /* What value are we aiming to generate? */
2644 switch (con->tag) {
2645 /* Note: Not sign-extending - we carry 'syned' around */
2646 case Ico_U64: vassert(env->mode64);
2647 u = con->Ico.U64; break;
2648 case Ico_U32: u = 0xFFFFFFFF & con->Ico.U32; break;
2649 case Ico_U16: u = 0x0000FFFF & con->Ico.U16; break;
2650 case Ico_U8: u = 0x000000FF & con->Ico.U8; break;
2651 default: vpanic("iselIntExpr_RH.Iex_Const(ppch)");
2652 }
2653 l = (Long)u;
2654 /* Now figure out if it's representable. */
2655 if (!syned && u <= 65535) {
2656 return PPCRH_Imm(False/*unsigned*/, toUShort(u & 0xFFFF));
2657 }
2658 if (syned && l >= -32767 && l <= 32767) {
2659 return PPCRH_Imm(True/*signed*/, toUShort(u & 0xFFFF));
2660 }
2661 /* no luck; use the Slow Way. */
2662 }
2663
2664 /* default case: calculate into a register and return that */
2665 return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2666 }
2667
2668
2669 /* --------------------- RIs --------------------- */
2670
2671 /* Calculate an expression into an PPCRI operand. As with
2672 iselIntExpr_R, the expression can have type 32, 16 or 8 bits, or,
2673 in 64-bit mode, 64 bits. */
2674
iselWordExpr_RI(ISelEnv * env,IRExpr * e,IREndness IEndianess)2675 static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
2676 {
2677 PPCRI* ri = iselWordExpr_RI_wrk(env, e, IEndianess);
2678 /* sanity checks ... */
2679 switch (ri->tag) {
2680 case Pri_Imm:
2681 return ri;
2682 case Pri_Reg:
2683 vassert(hregClass(ri->Pri.Reg) == HRcGPR(env->mode64));
2684 vassert(hregIsVirtual(ri->Pri.Reg));
2685 return ri;
2686 default:
2687 vpanic("iselIntExpr_RI: unknown ppc RI tag");
2688 }
2689 }
2690
2691 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RI_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2692 static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e,
2693 IREndness IEndianess )
2694 {
2695 Long l;
2696 IRType ty = typeOfIRExpr(env->type_env,e);
2697 vassert(ty == Ity_I8 || ty == Ity_I16 ||
2698 ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2699
2700 /* special case: immediate */
2701 if (e->tag == Iex_Const) {
2702 IRConst* con = e->Iex.Const.con;
2703 switch (con->tag) {
2704 case Ico_U64: vassert(env->mode64);
2705 l = (Long) con->Ico.U64; break;
2706 case Ico_U32: l = (Long)(Int) con->Ico.U32; break;
2707 case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
2708 case Ico_U8: l = (Long)(Int)(Char )con->Ico.U8; break;
2709 default: vpanic("iselIntExpr_RI.Iex_Const(ppch)");
2710 }
2711 return PPCRI_Imm((ULong)l);
2712 }
2713
2714 /* default case: calculate into a register and return that */
2715 return PPCRI_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2716 }
2717
2718
2719 /* --------------------- RH5u --------------------- */
2720
2721 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
2722 being an immediate in the range 1 .. 31 inclusive. Used for doing
2723 shift amounts. Only used in 32-bit mode. */
2724
iselWordExpr_RH5u(ISelEnv * env,IRExpr * e,IREndness IEndianess)2725 static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e,
2726 IREndness IEndianess )
2727 {
2728 PPCRH* ri;
2729 vassert(!env->mode64);
2730 ri = iselWordExpr_RH5u_wrk(env, e, IEndianess);
2731 /* sanity checks ... */
2732 switch (ri->tag) {
2733 case Prh_Imm:
2734 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 31);
2735 vassert(!ri->Prh.Imm.syned);
2736 return ri;
2737 case Prh_Reg:
2738 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2739 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2740 return ri;
2741 default:
2742 vpanic("iselIntExpr_RH5u: unknown ppc RI tag");
2743 }
2744 }
2745
2746 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH5u_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2747 static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e,
2748 IREndness IEndianess )
2749 {
2750 IRType ty = typeOfIRExpr(env->type_env,e);
2751 vassert(ty == Ity_I8);
2752
2753 /* special case: immediate */
2754 if (e->tag == Iex_Const
2755 && e->Iex.Const.con->tag == Ico_U8
2756 && e->Iex.Const.con->Ico.U8 >= 1
2757 && e->Iex.Const.con->Ico.U8 <= 31) {
2758 return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2759 }
2760
2761 /* default case: calculate into a register and return that */
2762 return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2763 }
2764
2765
2766 /* --------------------- RH6u --------------------- */
2767
2768 /* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter
2769 being an immediate in the range 1 .. 63 inclusive. Used for doing
2770 shift amounts. Only used in 64-bit mode. */
2771
iselWordExpr_RH6u(ISelEnv * env,IRExpr * e,IREndness IEndianess)2772 static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e,
2773 IREndness IEndianess )
2774 {
2775 PPCRH* ri;
2776 vassert(env->mode64);
2777 ri = iselWordExpr_RH6u_wrk(env, e, IEndianess);
2778 /* sanity checks ... */
2779 switch (ri->tag) {
2780 case Prh_Imm:
2781 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 63);
2782 vassert(!ri->Prh.Imm.syned);
2783 return ri;
2784 case Prh_Reg:
2785 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2786 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2787 return ri;
2788 default:
2789 vpanic("iselIntExpr_RH6u: unknown ppc64 RI tag");
2790 }
2791 }
2792
2793 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH6u_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2794 static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e,
2795 IREndness IEndianess )
2796 {
2797 IRType ty = typeOfIRExpr(env->type_env,e);
2798 vassert(ty == Ity_I8);
2799
2800 /* special case: immediate */
2801 if (e->tag == Iex_Const
2802 && e->Iex.Const.con->tag == Ico_U8
2803 && e->Iex.Const.con->Ico.U8 >= 1
2804 && e->Iex.Const.con->Ico.U8 <= 63) {
2805 return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2806 }
2807
2808 /* default case: calculate into a register and return that */
2809 return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2810 }
2811
2812
2813 /* --------------------- CONDCODE --------------------- */
2814
2815 /* Generate code to evaluated a bit-typed expression, returning the
2816 condition code which would correspond when the expression would
2817 notionally have returned 1. */
2818
iselCondCode(ISelEnv * env,IRExpr * e,IREndness IEndianess)2819 static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e,
2820 IREndness IEndianess )
2821 {
2822 /* Uh, there's nothing we can sanity check here, unfortunately. */
2823 return iselCondCode_wrk(env,e, IEndianess);
2824 }
2825
2826 /* DO NOT CALL THIS DIRECTLY ! */
iselCondCode_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2827 static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e,
2828 IREndness IEndianess )
2829 {
2830 vassert(e);
2831 vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
2832
2833 /* Constant 1:Bit */
2834 if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) {
2835 // Make a compare that will always be true:
2836 HReg r_zero = newVRegI(env);
2837 addInstr(env, PPCInstr_LI(r_zero, 0, env->mode64));
2838 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2839 7/*cr*/, r_zero, PPCRH_Reg(r_zero)));
2840 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2841 }
2842
2843 /* Not1(...) */
2844 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
2845 /* Generate code for the arg, and negate the test condition */
2846 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
2847 cond.test = invertCondTest(cond.test);
2848 return cond;
2849 }
2850
2851 /* --- patterns rooted at: 32to1 or 64to1 --- */
2852
2853 /* 32to1, 64to1 */
2854 if (e->tag == Iex_Unop &&
2855 (e->Iex.Unop.op == Iop_32to1 || e->Iex.Unop.op == Iop_64to1)) {
2856 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2857 HReg tmp = newVRegI(env);
2858 /* could do better, probably -- andi. */
2859 addInstr(env, PPCInstr_Alu(Palu_AND, tmp,
2860 src, PPCRH_Imm(False,1)));
2861 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2862 7/*cr*/, tmp, PPCRH_Imm(False,1)));
2863 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2864 }
2865
2866 /* --- patterns rooted at: CmpNEZ8 --- */
2867
2868 /* CmpNEZ8(x) */
2869 /* Note this cloned as CmpNE8(x,0) below. */
2870 /* could do better -- andi. */
2871 if (e->tag == Iex_Unop
2872 && e->Iex.Unop.op == Iop_CmpNEZ8) {
2873 HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2874 HReg tmp = newVRegI(env);
2875 addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
2876 PPCRH_Imm(False,0xFF)));
2877 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2878 7/*cr*/, tmp, PPCRH_Imm(False,0)));
2879 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2880 }
2881
2882 /* --- patterns rooted at: CmpNEZ32 --- */
2883
2884 /* CmpNEZ32(x) */
2885 if (e->tag == Iex_Unop
2886 && e->Iex.Unop.op == Iop_CmpNEZ32) {
2887 HReg r1 = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2888 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2889 7/*cr*/, r1, PPCRH_Imm(False,0)));
2890 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2891 }
2892
2893 /* --- patterns rooted at: Cmp*32* --- */
2894
2895 /* Cmp*32*(x,y) */
2896 if (e->tag == Iex_Binop
2897 && (e->Iex.Binop.op == Iop_CmpEQ32
2898 || e->Iex.Binop.op == Iop_CmpNE32
2899 || e->Iex.Binop.op == Iop_CmpLT32S
2900 || e->Iex.Binop.op == Iop_CmpLT32U
2901 || e->Iex.Binop.op == Iop_CmpLE32S
2902 || e->Iex.Binop.op == Iop_CmpLE32U)) {
2903 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S ||
2904 e->Iex.Binop.op == Iop_CmpLE32S);
2905 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2906 PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2, IEndianess);
2907 addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
2908 7/*cr*/, r1, ri2));
2909
2910 switch (e->Iex.Binop.op) {
2911 case Iop_CmpEQ32: return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2912 case Iop_CmpNE32: return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2913 case Iop_CmpLT32U: case Iop_CmpLT32S:
2914 return mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
2915 case Iop_CmpLE32U: case Iop_CmpLE32S:
2916 return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2917 default: vpanic("iselCondCode(ppc): CmpXX32");
2918 }
2919 }
2920
2921 /* --- patterns rooted at: CmpNEZ64 --- */
2922
2923 /* CmpNEZ64 */
2924 if (e->tag == Iex_Unop
2925 && e->Iex.Unop.op == Iop_CmpNEZ64) {
2926 if (!env->mode64) {
2927 HReg hi, lo;
2928 HReg tmp = newVRegI(env);
2929 iselInt64Expr( &hi, &lo, env, e->Iex.Unop.arg, IEndianess );
2930 addInstr(env, PPCInstr_Alu(Palu_OR, tmp, lo, PPCRH_Reg(hi)));
2931 addInstr(env, PPCInstr_Cmp(False/*sign*/, True/*32bit cmp*/,
2932 7/*cr*/, tmp,PPCRH_Imm(False,0)));
2933 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2934 } else { // mode64
2935 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2936 addInstr(env, PPCInstr_Cmp(False/*sign*/, False/*64bit cmp*/,
2937 7/*cr*/, r_src,PPCRH_Imm(False,0)));
2938 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2939 }
2940 }
2941
2942 /* --- patterns rooted at: Cmp*64* --- */
2943
2944 /* Cmp*64*(x,y) */
2945 if (e->tag == Iex_Binop
2946 && (e->Iex.Binop.op == Iop_CmpEQ64
2947 || e->Iex.Binop.op == Iop_CmpNE64
2948 || e->Iex.Binop.op == Iop_CmpLT64S
2949 || e->Iex.Binop.op == Iop_CmpLT64U
2950 || e->Iex.Binop.op == Iop_CmpLE64S
2951 || e->Iex.Binop.op == Iop_CmpLE64U)) {
2952 Bool syned = (e->Iex.Binop.op == Iop_CmpLT64S ||
2953 e->Iex.Binop.op == Iop_CmpLE64S);
2954 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2955 PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2, IEndianess);
2956 vassert(env->mode64);
2957 addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
2958 7/*cr*/, r1, ri2));
2959
2960 switch (e->Iex.Binop.op) {
2961 case Iop_CmpEQ64: return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2962 case Iop_CmpNE64: return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2963 case Iop_CmpLT64U: return mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
2964 case Iop_CmpLE64U: return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2965 default: vpanic("iselCondCode(ppc): CmpXX64");
2966 }
2967 }
2968
2969 /* --- patterns rooted at: CmpNE8 --- */
2970
2971 /* CmpNE8(x,0) */
2972 /* Note this is a direct copy of CmpNEZ8 above. */
2973 /* could do better -- andi. */
2974 if (e->tag == Iex_Binop
2975 && e->Iex.Binop.op == Iop_CmpNE8
2976 && isZeroU8(e->Iex.Binop.arg2)) {
2977 HReg arg = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2978 HReg tmp = newVRegI(env);
2979 addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
2980 PPCRH_Imm(False,0xFF)));
2981 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2982 7/*cr*/, tmp, PPCRH_Imm(False,0)));
2983 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2984 }
2985
2986 /* var */
2987 if (e->tag == Iex_RdTmp) {
2988 HReg r_src = lookupIRTemp(env, e->Iex.RdTmp.tmp);
2989 HReg src_masked = newVRegI(env);
2990 addInstr(env,
2991 PPCInstr_Alu(Palu_AND, src_masked,
2992 r_src, PPCRH_Imm(False,1)));
2993 addInstr(env,
2994 PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2995 7/*cr*/, src_masked, PPCRH_Imm(False,1)));
2996 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2997 }
2998
2999 vex_printf("iselCondCode(ppc): No such tag(%u)\n", e->tag);
3000 ppIRExpr(e);
3001 vpanic("iselCondCode(ppc)");
3002 }
3003
3004
3005 /*---------------------------------------------------------*/
3006 /*--- ISEL: Integer expressions (128 bit) ---*/
3007 /*---------------------------------------------------------*/
3008
3009 /* 64-bit mode ONLY: compute a 128-bit value into a register pair,
3010 which is returned as the first two parameters. As with
3011 iselWordExpr_R, these may be either real or virtual regs; in any
3012 case they must not be changed by subsequent code emitted by the
3013 caller. */
3014
iselInt128Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3015 static void iselInt128Expr ( HReg* rHi, HReg* rLo,
3016 ISelEnv* env, IRExpr* e, IREndness IEndianess )
3017 {
3018 vassert(env->mode64);
3019 iselInt128Expr_wrk(rHi, rLo, env, e, IEndianess);
3020 # if 0
3021 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3022 # endif
3023 vassert(hregClass(*rHi) == HRcGPR(env->mode64));
3024 vassert(hregIsVirtual(*rHi));
3025 vassert(hregClass(*rLo) == HRcGPR(env->mode64));
3026 vassert(hregIsVirtual(*rLo));
3027 }
3028
3029 /* DO NOT CALL THIS DIRECTLY ! */
iselInt128Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3030 static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
3031 ISelEnv* env, IRExpr* e, IREndness IEndianess )
3032 {
3033 vassert(e);
3034 vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
3035
3036 /* read 128-bit IRTemp */
3037 if (e->tag == Iex_RdTmp) {
3038 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
3039 return;
3040 }
3041
3042 /* --------- BINARY ops --------- */
3043 if (e->tag == Iex_Binop) {
3044 switch (e->Iex.Binop.op) {
3045 /* 64 x 64 -> 128 multiply */
3046 case Iop_MullU64:
3047 case Iop_MullS64: {
3048 HReg tLo = newVRegI(env);
3049 HReg tHi = newVRegI(env);
3050 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64);
3051 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3052 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3053 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
3054 False/*lo64*/, False/*64bit mul*/,
3055 tLo, r_srcL, r_srcR));
3056 addInstr(env, PPCInstr_MulL(syned,
3057 True/*hi64*/, False/*64bit mul*/,
3058 tHi, r_srcL, r_srcR));
3059 *rHi = tHi;
3060 *rLo = tLo;
3061 return;
3062 }
3063
3064 /* 64HLto128(e1,e2) */
3065 case Iop_64HLto128:
3066 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3067 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3068 return;
3069 default:
3070 break;
3071 }
3072 } /* if (e->tag == Iex_Binop) */
3073
3074
3075 /* --------- UNARY ops --------- */
3076 if (e->tag == Iex_Unop) {
3077 switch (e->Iex.Unop.op) {
3078 default:
3079 break;
3080 }
3081 } /* if (e->tag == Iex_Unop) */
3082
3083 vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e->tag);
3084 ppIRExpr(e);
3085 vpanic("iselInt128Expr(ppc64)");
3086 }
3087
3088
3089 /*---------------------------------------------------------*/
3090 /*--- ISEL: Integer expressions (64 bit) ---*/
3091 /*---------------------------------------------------------*/
3092
3093 /* 32-bit mode ONLY: compute a 128-bit value into a register quad */
iselInt128Expr_to_32x4(HReg * rHi,HReg * rMedHi,HReg * rMedLo,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3094 static void iselInt128Expr_to_32x4 ( HReg* rHi, HReg* rMedHi, HReg* rMedLo,
3095 HReg* rLo, ISelEnv* env, IRExpr* e,
3096 IREndness IEndianess )
3097 {
3098 vassert(!env->mode64);
3099 iselInt128Expr_to_32x4_wrk(rHi, rMedHi, rMedLo, rLo, env, e, IEndianess);
3100 # if 0
3101 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3102 # endif
3103 vassert(hregClass(*rHi) == HRcInt32);
3104 vassert(hregIsVirtual(*rHi));
3105 vassert(hregClass(*rMedHi) == HRcInt32);
3106 vassert(hregIsVirtual(*rMedHi));
3107 vassert(hregClass(*rMedLo) == HRcInt32);
3108 vassert(hregIsVirtual(*rMedLo));
3109 vassert(hregClass(*rLo) == HRcInt32);
3110 vassert(hregIsVirtual(*rLo));
3111 }
3112
iselInt128Expr_to_32x4_wrk(HReg * rHi,HReg * rMedHi,HReg * rMedLo,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3113 static void iselInt128Expr_to_32x4_wrk ( HReg* rHi, HReg* rMedHi,
3114 HReg* rMedLo, HReg* rLo,
3115 ISelEnv* env, IRExpr* e,
3116 IREndness IEndianess )
3117 {
3118 vassert(e);
3119 vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
3120
3121 /* read 128-bit IRTemp */
3122 if (e->tag == Iex_RdTmp) {
3123 lookupIRTempQuad( rHi, rMedHi, rMedLo, rLo, env, e->Iex.RdTmp.tmp);
3124 return;
3125 }
3126
3127 if (e->tag == Iex_Binop) {
3128
3129 IROp op_binop = e->Iex.Binop.op;
3130 switch (op_binop) {
3131 case Iop_64HLto128:
3132 iselInt64Expr(rHi, rMedHi, env, e->Iex.Binop.arg1, IEndianess);
3133 iselInt64Expr(rMedLo, rLo, env, e->Iex.Binop.arg2, IEndianess);
3134 return;
3135 default:
3136 vex_printf("iselInt128Expr_to_32x4_wrk: Binop case 0x%x not found\n",
3137 op_binop);
3138 break;
3139 }
3140 }
3141
3142 vex_printf("iselInt128Expr_to_32x4_wrk: e->tag 0x%x not found\n", e->tag);
3143 return;
3144 }
3145
3146 /* 32-bit mode ONLY: compute a 64-bit value into a register pair,
3147 which is returned as the first two parameters. As with
3148 iselIntExpr_R, these may be either real or virtual regs; in any
3149 case they must not be changed by subsequent code emitted by the
3150 caller. */
3151
iselInt64Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3152 static void iselInt64Expr ( HReg* rHi, HReg* rLo,
3153 ISelEnv* env, IRExpr* e,
3154 IREndness IEndianess )
3155 {
3156 vassert(!env->mode64);
3157 iselInt64Expr_wrk(rHi, rLo, env, e, IEndianess);
3158 # if 0
3159 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3160 # endif
3161 vassert(hregClass(*rHi) == HRcInt32);
3162 vassert(hregIsVirtual(*rHi));
3163 vassert(hregClass(*rLo) == HRcInt32);
3164 vassert(hregIsVirtual(*rLo));
3165 }
3166
3167 /* DO NOT CALL THIS DIRECTLY ! */
iselInt64Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3168 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
3169 ISelEnv* env, IRExpr* e,
3170 IREndness IEndianess )
3171 {
3172 vassert(e);
3173 vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
3174
3175 /* 64-bit load */
3176 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3177 HReg tLo = newVRegI(env);
3178 HReg tHi = newVRegI(env);
3179 HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr, IEndianess);
3180 vassert(!env->mode64);
3181 addInstr(env, PPCInstr_Load( 4/*byte-load*/,
3182 tHi, PPCAMode_IR( 0, r_addr ),
3183 False/*32-bit insn please*/) );
3184 addInstr(env, PPCInstr_Load( 4/*byte-load*/,
3185 tLo, PPCAMode_IR( 4, r_addr ),
3186 False/*32-bit insn please*/) );
3187 *rHi = tHi;
3188 *rLo = tLo;
3189 return;
3190 }
3191
3192 /* 64-bit literal */
3193 if (e->tag == Iex_Const) {
3194 ULong w64 = e->Iex.Const.con->Ico.U64;
3195 UInt wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF;
3196 UInt wLo = ((UInt)w64) & 0xFFFFFFFF;
3197 HReg tLo = newVRegI(env);
3198 HReg tHi = newVRegI(env);
3199 vassert(e->Iex.Const.con->tag == Ico_U64);
3200 addInstr(env, PPCInstr_LI(tHi, (Long)(Int)wHi, False/*mode32*/));
3201 addInstr(env, PPCInstr_LI(tLo, (Long)(Int)wLo, False/*mode32*/));
3202 *rHi = tHi;
3203 *rLo = tLo;
3204 return;
3205 }
3206
3207 /* read 64-bit IRTemp */
3208 if (e->tag == Iex_RdTmp) {
3209 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
3210 return;
3211 }
3212
3213 /* 64-bit GET */
3214 if (e->tag == Iex_Get) {
3215 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3216 GuestStatePtr(False/*mode32*/) );
3217 PPCAMode* am_addr4 = advance4(env, am_addr);
3218 HReg tLo = newVRegI(env);
3219 HReg tHi = newVRegI(env);
3220 addInstr(env, PPCInstr_Load( 4, tHi, am_addr, False/*mode32*/ ));
3221 addInstr(env, PPCInstr_Load( 4, tLo, am_addr4, False/*mode32*/ ));
3222 *rHi = tHi;
3223 *rLo = tLo;
3224 return;
3225 }
3226
3227 /* 64-bit ITE */
3228 if (e->tag == Iex_ITE) { // VFD
3229 HReg e0Lo, e0Hi, eXLo, eXHi;
3230 iselInt64Expr(&eXHi, &eXLo, env, e->Iex.ITE.iftrue, IEndianess);
3231 iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.ITE.iffalse, IEndianess);
3232 HReg tLo = newVRegI(env);
3233 HReg tHi = newVRegI(env);
3234 addInstr(env, mk_iMOVds_RR(tHi,e0Hi));
3235 addInstr(env, mk_iMOVds_RR(tLo,e0Lo));
3236 PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
3237 addInstr(env, PPCInstr_CMov(cc,tHi,PPCRI_Reg(eXHi)));
3238 addInstr(env, PPCInstr_CMov(cc,tLo,PPCRI_Reg(eXLo)));
3239 *rHi = tHi;
3240 *rLo = tLo;
3241 return;
3242 }
3243
3244 /* --------- BINARY ops --------- */
3245 if (e->tag == Iex_Binop) {
3246 IROp op_binop = e->Iex.Binop.op;
3247 switch (op_binop) {
3248 /* 32 x 32 -> 64 multiply */
3249 case Iop_MullU32:
3250 case Iop_MullS32: {
3251 HReg tLo = newVRegI(env);
3252 HReg tHi = newVRegI(env);
3253 Bool syned = toBool(op_binop == Iop_MullS32);
3254 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1,
3255 IEndianess);
3256 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2,
3257 IEndianess);
3258 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
3259 False/*lo32*/, True/*32bit mul*/,
3260 tLo, r_srcL, r_srcR));
3261 addInstr(env, PPCInstr_MulL(syned,
3262 True/*hi32*/, True/*32bit mul*/,
3263 tHi, r_srcL, r_srcR));
3264 *rHi = tHi;
3265 *rLo = tLo;
3266 return;
3267 }
3268
3269 /* Or64/And64/Xor64 */
3270 case Iop_Or64:
3271 case Iop_And64:
3272 case Iop_Xor64: {
3273 HReg xLo, xHi, yLo, yHi;
3274 HReg tLo = newVRegI(env);
3275 HReg tHi = newVRegI(env);
3276 PPCAluOp op = (op_binop == Iop_Or64) ? Palu_OR :
3277 (op_binop == Iop_And64) ? Palu_AND : Palu_XOR;
3278 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1, IEndianess);
3279 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2, IEndianess);
3280 addInstr(env, PPCInstr_Alu(op, tHi, xHi, PPCRH_Reg(yHi)));
3281 addInstr(env, PPCInstr_Alu(op, tLo, xLo, PPCRH_Reg(yLo)));
3282 *rHi = tHi;
3283 *rLo = tLo;
3284 return;
3285 }
3286
3287 /* Add64 */
3288 case Iop_Add64: {
3289 HReg xLo, xHi, yLo, yHi;
3290 HReg tLo = newVRegI(env);
3291 HReg tHi = newVRegI(env);
3292 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1, IEndianess);
3293 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2, IEndianess);
3294 addInstr(env, PPCInstr_AddSubC( True/*add*/, True /*set carry*/,
3295 tLo, xLo, yLo));
3296 addInstr(env, PPCInstr_AddSubC( True/*add*/, False/*read carry*/,
3297 tHi, xHi, yHi));
3298 *rHi = tHi;
3299 *rLo = tLo;
3300 return;
3301 }
3302
3303 /* 32HLto64(e1,e2) */
3304 case Iop_32HLto64:
3305 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3306 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3307 return;
3308
3309 /* F64toI64[S|U] */
3310 case Iop_F64toI64S: case Iop_F64toI64U: {
3311 HReg tLo = newVRegI(env);
3312 HReg tHi = newVRegI(env);
3313 HReg r1 = StackFramePtr(env->mode64);
3314 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3315 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3316 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2,
3317 IEndianess);
3318 HReg ftmp = newVRegF(env);
3319
3320 vassert(!env->mode64);
3321 /* Set host rounding mode */
3322 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3323
3324 sub_from_sp( env, 16 );
3325 addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/,
3326 (op_binop == Iop_F64toI64S) ? True : False,
3327 True, ftmp, fsrc));
3328 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
3329 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3330 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3331 add_to_sp( env, 16 );
3332
3333 ///* Restore default FPU rounding. */
3334 //set_FPU_rounding_default( env );
3335 *rHi = tHi;
3336 *rLo = tLo;
3337 return;
3338 }
3339 case Iop_D64toI64S: {
3340 HReg tLo = newVRegI(env);
3341 HReg tHi = newVRegI(env);
3342 HReg r1 = StackFramePtr(env->mode64);
3343 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3344 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3345 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
3346 HReg tmp = newVRegF(env);
3347
3348 vassert(!env->mode64);
3349 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3350 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTFIX, tmp, fr_src));
3351
3352 sub_from_sp( env, 16 );
3353 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3354 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3355 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3356 add_to_sp( env, 16 );
3357 *rHi = tHi;
3358 *rLo = tLo;
3359 return;
3360 }
3361 case Iop_D128toI64S: {
3362 PPCFpOp fpop = Pfp_DCTFIXQ;
3363 HReg r_srcHi = newVRegF(env);
3364 HReg r_srcLo = newVRegF(env);
3365 HReg tLo = newVRegI(env);
3366 HReg tHi = newVRegI(env);
3367 HReg ftmp = newVRegF(env);
3368 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3369 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3370
3371 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3372 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
3373 IEndianess);
3374 addInstr(env, PPCInstr_DfpD128toD64(fpop, ftmp, r_srcHi, r_srcLo));
3375
3376 // put the D64 result into an integer register pair
3377 sub_from_sp( env, 16 );
3378 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
3379 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3380 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3381 add_to_sp( env, 16 );
3382 *rHi = tHi;
3383 *rLo = tLo;
3384 return;
3385 }
3386 default:
3387 break;
3388 }
3389 } /* if (e->tag == Iex_Binop) */
3390
3391
3392 /* --------- UNARY ops --------- */
3393 if (e->tag == Iex_Unop) {
3394 switch (e->Iex.Unop.op) {
3395
3396 /* CmpwNEZ64(e) */
3397 case Iop_CmpwNEZ64: {
3398 HReg argHi, argLo;
3399 HReg tmp1 = newVRegI(env);
3400 HReg tmp2 = newVRegI(env);
3401 iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg, IEndianess);
3402 /* tmp1 = argHi | argLo */
3403 addInstr(env, PPCInstr_Alu(Palu_OR, tmp1, argHi, PPCRH_Reg(argLo)));
3404 /* tmp2 = (tmp1 | -tmp1) >>s 31 */
3405 addInstr(env, PPCInstr_Unary(Pun_NEG,tmp2,tmp1));
3406 addInstr(env, PPCInstr_Alu(Palu_OR, tmp2, tmp2, PPCRH_Reg(tmp1)));
3407 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3408 tmp2, tmp2, PPCRH_Imm(False, 31)));
3409 *rHi = tmp2;
3410 *rLo = tmp2; /* yes, really tmp2 */
3411 return;
3412 }
3413
3414 /* Left64 */
3415 case Iop_Left64: {
3416 HReg argHi, argLo;
3417 HReg zero32 = newVRegI(env);
3418 HReg resHi = newVRegI(env);
3419 HReg resLo = newVRegI(env);
3420 iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg, IEndianess);
3421 vassert(env->mode64 == False);
3422 addInstr(env, PPCInstr_LI(zero32, 0, env->mode64));
3423 /* resHi:resLo = - argHi:argLo */
3424 addInstr(env, PPCInstr_AddSubC( False/*sub*/, True/*set carry*/,
3425 resLo, zero32, argLo ));
3426 addInstr(env, PPCInstr_AddSubC( False/*sub*/, False/*read carry*/,
3427 resHi, zero32, argHi ));
3428 /* resHi:resLo |= srcHi:srcLo */
3429 addInstr(env, PPCInstr_Alu(Palu_OR, resLo, resLo, PPCRH_Reg(argLo)));
3430 addInstr(env, PPCInstr_Alu(Palu_OR, resHi, resHi, PPCRH_Reg(argHi)));
3431 *rHi = resHi;
3432 *rLo = resLo;
3433 return;
3434 }
3435
3436 /* 32Sto64(e) */
3437 case Iop_32Sto64: {
3438 HReg tHi = newVRegI(env);
3439 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3440 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3441 tHi, src, PPCRH_Imm(False,31)));
3442 *rHi = tHi;
3443 *rLo = src;
3444 return;
3445 }
3446 case Iop_ExtractExpD64: {
3447 HReg tmp = newVRegF(env);
3448 HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
3449 HReg tLo = newVRegI(env);
3450 HReg tHi = newVRegI(env);
3451 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3452 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3453
3454 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DXEX, tmp, fr_src));
3455
3456 // put the D64 result into a integer register pair
3457 sub_from_sp( env, 16 );
3458 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3459 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3460 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3461 add_to_sp( env, 16 );
3462 *rHi = tHi;
3463 *rLo = tLo;
3464 return;
3465 }
3466 case Iop_ExtractExpD128: {
3467 HReg r_srcHi;
3468 HReg r_srcLo;
3469 HReg tmp = newVRegF(env);
3470 HReg tLo = newVRegI(env);
3471 HReg tHi = newVRegI(env);
3472 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3473 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3474
3475 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Unop.arg, IEndianess);
3476 addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, tmp,
3477 r_srcHi, r_srcLo));
3478
3479 // put the D64 result into a integer register pair
3480 sub_from_sp( env, 16 );
3481 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3482 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3483 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3484 add_to_sp( env, 16 );
3485 *rHi = tHi;
3486 *rLo = tLo;
3487 return;
3488 }
3489
3490 /* 32Uto64(e) */
3491 case Iop_32Uto64: {
3492 HReg tHi = newVRegI(env);
3493 HReg tLo = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3494 addInstr(env, PPCInstr_LI(tHi, 0, False/*mode32*/));
3495 *rHi = tHi;
3496 *rLo = tLo;
3497 return;
3498 }
3499
3500 case Iop_128to64: {
3501 /* Narrow, return the low 64-bit half as a 32-bit
3502 * register pair */
3503 HReg r_Hi = INVALID_HREG;
3504 HReg r_MedHi = INVALID_HREG;
3505 HReg r_MedLo = INVALID_HREG;
3506 HReg r_Lo = INVALID_HREG;
3507
3508 iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo,
3509 env, e->Iex.Unop.arg, IEndianess);
3510 *rHi = r_MedLo;
3511 *rLo = r_Lo;
3512 return;
3513 }
3514
3515 case Iop_128HIto64: {
3516 /* Narrow, return the high 64-bit half as a 32-bit
3517 * register pair */
3518 HReg r_Hi = INVALID_HREG;
3519 HReg r_MedHi = INVALID_HREG;
3520 HReg r_MedLo = INVALID_HREG;
3521 HReg r_Lo = INVALID_HREG;
3522
3523 iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo,
3524 env, e->Iex.Unop.arg, IEndianess);
3525 *rHi = r_Hi;
3526 *rLo = r_MedHi;
3527 return;
3528 }
3529
3530 /* V128{HI}to64 */
3531 case Iop_V128HIto64:
3532 case Iop_V128to64: {
3533 HReg r_aligned16;
3534 Int off = e->Iex.Unop.op==Iop_V128HIto64 ? 0 : 8;
3535 HReg tLo = newVRegI(env);
3536 HReg tHi = newVRegI(env);
3537 HReg vec = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
3538 PPCAMode *am_off0, *am_offLO, *am_offHI;
3539 sub_from_sp( env, 32 ); // Move SP down 32 bytes
3540
3541 // get a quadword aligned address within our stack space
3542 r_aligned16 = get_sp_aligned16( env );
3543 am_off0 = PPCAMode_IR( 0, r_aligned16 );
3544 am_offHI = PPCAMode_IR( off, r_aligned16 );
3545 am_offLO = PPCAMode_IR( off+4, r_aligned16 );
3546
3547 // store as Vec128
3548 addInstr(env,
3549 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
3550
3551 // load hi,lo words (of hi/lo half of vec) as Ity_I32's
3552 addInstr(env,
3553 PPCInstr_Load( 4, tHi, am_offHI, False/*mode32*/ ));
3554 addInstr(env,
3555 PPCInstr_Load( 4, tLo, am_offLO, False/*mode32*/ ));
3556
3557 add_to_sp( env, 32 ); // Reset SP
3558 *rHi = tHi;
3559 *rLo = tLo;
3560 return;
3561 }
3562
3563 /* could do better than this, but for now ... */
3564 case Iop_1Sto64: {
3565 HReg tLo = newVRegI(env);
3566 HReg tHi = newVRegI(env);
3567 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
3568 addInstr(env, PPCInstr_Set(cond,tLo));
3569 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
3570 tLo, tLo, PPCRH_Imm(False,31)));
3571 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3572 tLo, tLo, PPCRH_Imm(False,31)));
3573 addInstr(env, mk_iMOVds_RR(tHi, tLo));
3574 *rHi = tHi;
3575 *rLo = tLo;
3576 return;
3577 }
3578
3579 case Iop_Not64: {
3580 HReg xLo, xHi;
3581 HReg tmpLo = newVRegI(env);
3582 HReg tmpHi = newVRegI(env);
3583 iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg, IEndianess);
3584 addInstr(env, PPCInstr_Unary(Pun_NOT,tmpLo,xLo));
3585 addInstr(env, PPCInstr_Unary(Pun_NOT,tmpHi,xHi));
3586 *rHi = tmpHi;
3587 *rLo = tmpLo;
3588 return;
3589 }
3590
3591 /* ReinterpF64asI64(e) */
3592 /* Given an IEEE754 double, produce an I64 with the same bit
3593 pattern. */
3594 case Iop_ReinterpF64asI64: {
3595 PPCAMode *am_addr0, *am_addr1;
3596 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
3597 HReg r_dstLo = newVRegI(env);
3598 HReg r_dstHi = newVRegI(env);
3599
3600 sub_from_sp( env, 16 ); // Move SP down 16 bytes
3601 am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
3602 am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
3603
3604 // store as F64
3605 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3606 fr_src, am_addr0 ));
3607
3608 // load hi,lo as Ity_I32's
3609 addInstr(env, PPCInstr_Load( 4, r_dstHi,
3610 am_addr0, False/*mode32*/ ));
3611 addInstr(env, PPCInstr_Load( 4, r_dstLo,
3612 am_addr1, False/*mode32*/ ));
3613 *rHi = r_dstHi;
3614 *rLo = r_dstLo;
3615
3616 add_to_sp( env, 16 ); // Reset SP
3617 return;
3618 }
3619
3620 case Iop_ReinterpD64asI64: {
3621 HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
3622 PPCAMode *am_addr0, *am_addr1;
3623 HReg r_dstLo = newVRegI(env);
3624 HReg r_dstHi = newVRegI(env);
3625
3626
3627 sub_from_sp( env, 16 ); // Move SP down 16 bytes
3628 am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
3629 am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
3630
3631 // store as D64
3632 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3633 fr_src, am_addr0 ));
3634
3635 // load hi,lo as Ity_I32's
3636 addInstr(env, PPCInstr_Load( 4, r_dstHi,
3637 am_addr0, False/*mode32*/ ));
3638 addInstr(env, PPCInstr_Load( 4, r_dstLo,
3639 am_addr1, False/*mode32*/ ));
3640 *rHi = r_dstHi;
3641 *rLo = r_dstLo;
3642
3643 add_to_sp( env, 16 ); // Reset SP
3644
3645 return;
3646 }
3647
3648 case Iop_BCDtoDPB: {
3649 PPCCondCode cc;
3650 UInt argiregs;
3651 HReg argregs[2];
3652 Int argreg;
3653 HReg tLo = newVRegI(env);
3654 HReg tHi = newVRegI(env);
3655 HReg tmpHi;
3656 HReg tmpLo;
3657 Bool mode64 = env->mode64;
3658
3659 argregs[0] = hregPPC_GPR3(mode64);
3660 argregs[1] = hregPPC_GPR4(mode64);
3661
3662 argiregs = 0;
3663 argreg = 0;
3664
3665 iselInt64Expr( &tmpHi, &tmpLo, env, e->Iex.Unop.arg, IEndianess );
3666
3667 argiregs |= ( 1 << (argreg+3 ) );
3668 addInstr( env, mk_iMOVds_RR( argregs[argreg++], tmpHi ) );
3669
3670 argiregs |= ( 1 << (argreg+3 ) );
3671 addInstr( env, mk_iMOVds_RR( argregs[argreg], tmpLo ) );
3672
3673 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
3674
3675 if (IEndianess == Iend_LE) {
3676 addInstr( env, PPCInstr_Call( cc, (Addr)h_calc_BCDtoDPB,
3677 argiregs,
3678 mk_RetLoc_simple(RLPri_2Int) ) );
3679 } else {
3680 Addr64 target;
3681 target = mode64 ? (Addr)h_calc_BCDtoDPB :
3682 toUInt( (Addr)h_calc_BCDtoDPB );
3683 addInstr( env, PPCInstr_Call( cc, target,
3684 argiregs,
3685 mk_RetLoc_simple(RLPri_2Int) ) );
3686 }
3687
3688 addInstr( env, mk_iMOVds_RR( tHi, argregs[argreg-1] ) );
3689 addInstr( env, mk_iMOVds_RR( tLo, argregs[argreg] ) );
3690
3691 *rHi = tHi;
3692 *rLo = tLo;
3693 return;
3694 }
3695
3696 case Iop_DPBtoBCD: {
3697 PPCCondCode cc;
3698 UInt argiregs;
3699 HReg argregs[2];
3700 Int argreg;
3701 HReg tLo = newVRegI(env);
3702 HReg tHi = newVRegI(env);
3703 HReg tmpHi;
3704 HReg tmpLo;
3705 Bool mode64 = env->mode64;
3706
3707 argregs[0] = hregPPC_GPR3(mode64);
3708 argregs[1] = hregPPC_GPR4(mode64);
3709
3710 argiregs = 0;
3711 argreg = 0;
3712
3713 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg, IEndianess);
3714
3715 argiregs |= (1 << (argreg+3));
3716 addInstr(env, mk_iMOVds_RR( argregs[argreg++], tmpHi ));
3717
3718 argiregs |= (1 << (argreg+3));
3719 addInstr(env, mk_iMOVds_RR( argregs[argreg], tmpLo));
3720
3721 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
3722
3723 if (IEndianess == Iend_LE) {
3724 addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_DPBtoBCD,
3725 argiregs,
3726 mk_RetLoc_simple(RLPri_2Int) ) );
3727 } else {
3728 Addr64 target;
3729 target = mode64 ? (Addr)h_calc_DPBtoBCD :
3730 toUInt( (Addr)h_calc_DPBtoBCD );
3731 addInstr(env, PPCInstr_Call( cc, target, argiregs,
3732 mk_RetLoc_simple(RLPri_2Int) ) );
3733 }
3734
3735 addInstr(env, mk_iMOVds_RR(tHi, argregs[argreg-1]));
3736 addInstr(env, mk_iMOVds_RR(tLo, argregs[argreg]));
3737
3738 *rHi = tHi;
3739 *rLo = tLo;
3740 return;
3741 }
3742
3743 default:
3744 break;
3745 }
3746 } /* if (e->tag == Iex_Unop) */
3747
3748 vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e->tag);
3749 ppIRExpr(e);
3750 vpanic("iselInt64Expr(ppc)");
3751 }
3752
3753
3754 /*---------------------------------------------------------*/
3755 /*--- ISEL: Floating point expressions (32 bit) ---*/
3756 /*---------------------------------------------------------*/
3757
3758 /* Nothing interesting here; really just wrappers for
3759 64-bit stuff. */
3760
iselFltExpr(ISelEnv * env,IRExpr * e,IREndness IEndianess)3761 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3762 {
3763 HReg r = iselFltExpr_wrk( env, e, IEndianess );
3764 # if 0
3765 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3766 # endif
3767 vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */
3768 vassert(hregIsVirtual(r));
3769 return r;
3770 }
3771
3772 /* DO NOT CALL THIS DIRECTLY */
iselFltExpr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)3773 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3774 {
3775 Bool mode64 = env->mode64;
3776
3777 IRType ty = typeOfIRExpr(env->type_env,e);
3778 vassert(ty == Ity_F32);
3779
3780 if (e->tag == Iex_RdTmp) {
3781 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3782 }
3783
3784 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3785 PPCAMode* am_addr;
3786 HReg r_dst = newVRegF(env);
3787 vassert(e->Iex.Load.ty == Ity_F32);
3788 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F32/*xfer*/,
3789 IEndianess);
3790 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
3791 return r_dst;
3792 }
3793
3794 if (e->tag == Iex_Get) {
3795 HReg r_dst = newVRegF(env);
3796 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3797 GuestStatePtr(env->mode64) );
3798 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4, r_dst, am_addr ));
3799 return r_dst;
3800 }
3801
3802 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
3803 /* This is quite subtle. The only way to do the relevant
3804 truncation is to do a single-precision store and then a
3805 double precision load to get it back into a register. The
3806 problem is, if the data is then written to memory a second
3807 time, as in
3808
3809 STbe(...) = TruncF64asF32(...)
3810
3811 then will the second truncation further alter the value? The
3812 answer is no: flds (as generated here) followed by fsts
3813 (generated for the STbe) is the identity function on 32-bit
3814 floats, so we are safe.
3815
3816 Another upshot of this is that if iselStmt can see the
3817 entirety of
3818
3819 STbe(...) = TruncF64asF32(arg)
3820
3821 then it can short circuit having to deal with TruncF64asF32
3822 individually; instead just compute arg into a 64-bit FP
3823 register and do 'fsts' (since that itself does the
3824 truncation).
3825
3826 We generate pretty poor code here (should be ok both for
3827 32-bit and 64-bit mode); but it is expected that for the most
3828 part the latter optimisation will apply and hence this code
3829 will not often be used.
3830 */
3831 HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
3832 HReg fdst = newVRegF(env);
3833 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3834
3835 sub_from_sp( env, 16 );
3836 // store as F32, hence truncating
3837 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
3838 fsrc, zero_r1 ));
3839 // and reload. Good huh?! (sigh)
3840 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4,
3841 fdst, zero_r1 ));
3842 add_to_sp( env, 16 );
3843 return fdst;
3844 }
3845
3846 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64UtoF32) {
3847 if (mode64) {
3848 HReg fdst = newVRegF(env);
3849 HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3850 HReg r1 = StackFramePtr(env->mode64);
3851 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3852
3853 /* Set host rounding mode */
3854 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3855
3856 sub_from_sp( env, 16 );
3857
3858 addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
3859 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3860 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3861 False, False,
3862 fdst, fdst));
3863
3864 add_to_sp( env, 16 );
3865
3866 ///* Restore default FPU rounding. */
3867 //set_FPU_rounding_default( env );
3868 return fdst;
3869 } else {
3870 /* 32-bit mode */
3871 HReg fdst = newVRegF(env);
3872 HReg isrcHi, isrcLo;
3873 HReg r1 = StackFramePtr(env->mode64);
3874 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3875 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3876
3877 iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2, IEndianess);
3878
3879 /* Set host rounding mode */
3880 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3881
3882 sub_from_sp( env, 16 );
3883
3884 addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
3885 addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
3886 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3887 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3888 False, False,
3889 fdst, fdst));
3890
3891 add_to_sp( env, 16 );
3892
3893 ///* Restore default FPU rounding. */
3894 //set_FPU_rounding_default( env );
3895 return fdst;
3896 }
3897
3898 }
3899
3900 vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e->tag);
3901 ppIRExpr(e);
3902 vpanic("iselFltExpr_wrk(ppc)");
3903 }
3904
3905
3906 /*---------------------------------------------------------*/
3907 /*--- ISEL: Floating point expressions (64 bit) ---*/
3908 /*---------------------------------------------------------*/
3909
3910 /* Compute a 64-bit floating point value into a register, the identity
3911 of which is returned. As with iselIntExpr_R, the reg may be either
3912 real or virtual; in any case it must not be changed by subsequent
3913 code emitted by the caller. */
3914
3915 /* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm:
3916
3917 Type S (1 bit) E (11 bits) F (52 bits)
3918 ---- --------- ----------- -----------
3919 signalling NaN u 2047 (max) .0uuuuu---u
3920 (with at least
3921 one 1 bit)
3922 quiet NaN u 2047 (max) .1uuuuu---u
3923
3924 negative infinity 1 2047 (max) .000000---0
3925
3926 positive infinity 0 2047 (max) .000000---0
3927
3928 negative zero 1 0 .000000---0
3929
3930 positive zero 0 0 .000000---0
3931 */
3932
iselDblExpr(ISelEnv * env,IRExpr * e,IREndness IEndianess)3933 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3934 {
3935 HReg r = iselDblExpr_wrk( env, e, IEndianess );
3936 # if 0
3937 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3938 # endif
3939 vassert(hregClass(r) == HRcFlt64);
3940 vassert(hregIsVirtual(r));
3941 return r;
3942 }
3943
3944 /* DO NOT CALL THIS DIRECTLY */
iselDblExpr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)3945 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3946 {
3947 Bool mode64 = env->mode64;
3948 IRType ty = typeOfIRExpr(env->type_env,e);
3949 vassert(e);
3950 vassert(ty == Ity_F64);
3951
3952 if (e->tag == Iex_RdTmp) {
3953 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3954 }
3955
3956 /* --------- LITERAL --------- */
3957 if (e->tag == Iex_Const) {
3958 union { UInt u32x2[2]; ULong u64; Double f64; } u;
3959 vassert(sizeof(u) == 8);
3960 vassert(sizeof(u.u64) == 8);
3961 vassert(sizeof(u.f64) == 8);
3962 vassert(sizeof(u.u32x2) == 8);
3963
3964 if (e->Iex.Const.con->tag == Ico_F64) {
3965 u.f64 = e->Iex.Const.con->Ico.F64;
3966 }
3967 else if (e->Iex.Const.con->tag == Ico_F64i) {
3968 u.u64 = e->Iex.Const.con->Ico.F64i;
3969 }
3970 else
3971 vpanic("iselDblExpr(ppc): const");
3972
3973 if (!mode64) {
3974 HReg r_srcHi = newVRegI(env);
3975 HReg r_srcLo = newVRegI(env);
3976 addInstr(env, PPCInstr_LI(r_srcHi, u.u32x2[0], mode64));
3977 addInstr(env, PPCInstr_LI(r_srcLo, u.u32x2[1], mode64));
3978 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
3979 } else { // mode64
3980 HReg r_src = newVRegI(env);
3981 addInstr(env, PPCInstr_LI(r_src, u.u64, mode64));
3982 return mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64
3983 }
3984 }
3985
3986 /* --------- LOAD --------- */
3987 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3988 HReg r_dst = newVRegF(env);
3989 PPCAMode* am_addr;
3990 vassert(e->Iex.Load.ty == Ity_F64);
3991 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F64/*xfer*/,
3992 IEndianess);
3993 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
3994 return r_dst;
3995 }
3996
3997 /* --------- GET --------- */
3998 if (e->tag == Iex_Get) {
3999 HReg r_dst = newVRegF(env);
4000 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4001 GuestStatePtr(mode64) );
4002 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ));
4003 return r_dst;
4004 }
4005
4006 /* --------- OPS --------- */
4007 if (e->tag == Iex_Qop) {
4008 PPCFpOp fpop = Pfp_INVALID;
4009 switch (e->Iex.Qop.details->op) {
4010 case Iop_MAddF64: fpop = Pfp_MADDD; break;
4011 case Iop_MAddF64r32: fpop = Pfp_MADDS; break;
4012 case Iop_MSubF64: fpop = Pfp_MSUBD; break;
4013 case Iop_MSubF64r32: fpop = Pfp_MSUBS; break;
4014 default: break;
4015 }
4016 if (fpop != Pfp_INVALID) {
4017 HReg r_dst = newVRegF(env);
4018 HReg r_srcML = iselDblExpr(env, e->Iex.Qop.details->arg2,
4019 IEndianess);
4020 HReg r_srcMR = iselDblExpr(env, e->Iex.Qop.details->arg3,
4021 IEndianess);
4022 HReg r_srcAcc = iselDblExpr(env, e->Iex.Qop.details->arg4,
4023 IEndianess);
4024 set_FPU_rounding_mode( env, e->Iex.Qop.details->arg1, IEndianess );
4025 addInstr(env, PPCInstr_FpMulAcc(fpop, r_dst,
4026 r_srcML, r_srcMR, r_srcAcc));
4027 return r_dst;
4028 }
4029 }
4030
4031 if (e->tag == Iex_Triop) {
4032 IRTriop *triop = e->Iex.Triop.details;
4033 PPCFpOp fpop = Pfp_INVALID;
4034 switch (triop->op) {
4035 case Iop_AddF64: fpop = Pfp_ADDD; break;
4036 case Iop_SubF64: fpop = Pfp_SUBD; break;
4037 case Iop_MulF64: fpop = Pfp_MULD; break;
4038 case Iop_DivF64: fpop = Pfp_DIVD; break;
4039 case Iop_AddF64r32: fpop = Pfp_ADDS; break;
4040 case Iop_SubF64r32: fpop = Pfp_SUBS; break;
4041 case Iop_MulF64r32: fpop = Pfp_MULS; break;
4042 case Iop_DivF64r32: fpop = Pfp_DIVS; break;
4043 default: break;
4044 }
4045 if (fpop != Pfp_INVALID) {
4046 HReg r_dst = newVRegF(env);
4047 HReg r_srcL = iselDblExpr(env, triop->arg2, IEndianess);
4048 HReg r_srcR = iselDblExpr(env, triop->arg3, IEndianess);
4049 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4050 addInstr(env, PPCInstr_FpBinary(fpop, r_dst, r_srcL, r_srcR));
4051 return r_dst;
4052 }
4053 }
4054
4055 if (e->tag == Iex_Binop) {
4056 PPCFpOp fpop = Pfp_INVALID;
4057 switch (e->Iex.Binop.op) {
4058 case Iop_SqrtF64: fpop = Pfp_SQRT; break;
4059 default: break;
4060 }
4061 if (fpop == Pfp_SQRT) {
4062 HReg fr_dst = newVRegF(env);
4063 HReg fr_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4064 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4065 addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
4066 return fr_dst;
4067 }
4068 }
4069
4070 if (e->tag == Iex_Binop) {
4071
4072 if (e->Iex.Binop.op == Iop_RoundF64toF32) {
4073 HReg r_dst = newVRegF(env);
4074 HReg r_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4075 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4076 addInstr(env, PPCInstr_FpRSP(r_dst, r_src));
4077 //set_FPU_rounding_default( env );
4078 return r_dst;
4079 }
4080
4081 if (e->Iex.Binop.op == Iop_I64StoF64 || e->Iex.Binop.op == Iop_I64UtoF64) {
4082 if (mode64) {
4083 HReg fdst = newVRegF(env);
4084 HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
4085 HReg r1 = StackFramePtr(env->mode64);
4086 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
4087
4088 /* Set host rounding mode */
4089 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4090
4091 sub_from_sp( env, 16 );
4092
4093 addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
4094 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
4095 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
4096 e->Iex.Binop.op == Iop_I64StoF64,
4097 True/*fdst is 64 bit*/,
4098 fdst, fdst));
4099
4100 add_to_sp( env, 16 );
4101
4102 ///* Restore default FPU rounding. */
4103 //set_FPU_rounding_default( env );
4104 return fdst;
4105 } else {
4106 /* 32-bit mode */
4107 HReg fdst = newVRegF(env);
4108 HReg isrcHi, isrcLo;
4109 HReg r1 = StackFramePtr(env->mode64);
4110 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
4111 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
4112
4113 iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2,
4114 IEndianess);
4115
4116 /* Set host rounding mode */
4117 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4118
4119 sub_from_sp( env, 16 );
4120
4121 addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
4122 addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
4123 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
4124 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
4125 e->Iex.Binop.op == Iop_I64StoF64,
4126 True/*fdst is 64 bit*/,
4127 fdst, fdst));
4128
4129 add_to_sp( env, 16 );
4130
4131 ///* Restore default FPU rounding. */
4132 //set_FPU_rounding_default( env );
4133 return fdst;
4134 }
4135 }
4136
4137 }
4138
4139 if (e->tag == Iex_Unop) {
4140 PPCFpOp fpop = Pfp_INVALID;
4141 switch (e->Iex.Unop.op) {
4142 case Iop_NegF64: fpop = Pfp_NEG; break;
4143 case Iop_AbsF64: fpop = Pfp_ABS; break;
4144 case Iop_RSqrtEst5GoodF64: fpop = Pfp_RSQRTE; break;
4145 case Iop_RoundF64toF64_NegINF: fpop = Pfp_FRIM; break;
4146 case Iop_RoundF64toF64_PosINF: fpop = Pfp_FRIP; break;
4147 case Iop_RoundF64toF64_NEAREST: fpop = Pfp_FRIN; break;
4148 case Iop_RoundF64toF64_ZERO: fpop = Pfp_FRIZ; break;
4149 default: break;
4150 }
4151 if (fpop != Pfp_INVALID) {
4152 HReg fr_dst = newVRegF(env);
4153 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
4154 addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
4155 return fr_dst;
4156 }
4157 }
4158
4159 if (e->tag == Iex_Unop) {
4160 switch (e->Iex.Unop.op) {
4161 case Iop_ReinterpI64asF64: {
4162 /* Given an I64, produce an IEEE754 double with the same
4163 bit pattern. */
4164 if (!mode64) {
4165 HReg r_srcHi, r_srcLo;
4166 iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
4167 IEndianess);
4168 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
4169 } else {
4170 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4171 return mk_LoadR64toFPR( env, r_src );
4172 }
4173 }
4174
4175 case Iop_F32toF64: {
4176 if (e->Iex.Unop.arg->tag == Iex_Unop &&
4177 e->Iex.Unop.arg->Iex.Unop.op == Iop_ReinterpI32asF32 ) {
4178 e = e->Iex.Unop.arg;
4179
4180 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4181 HReg fr_dst = newVRegF(env);
4182 PPCAMode *am_addr;
4183
4184 sub_from_sp( env, 16 ); // Move SP down 16 bytes
4185 am_addr = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4186
4187 // store src as Ity_I32's
4188 addInstr(env, PPCInstr_Store( 4, am_addr, src, env->mode64 ));
4189
4190 // load single precision float, but the end results loads into a
4191 // 64-bit FP register -- i.e., F64.
4192 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, fr_dst, am_addr));
4193
4194 add_to_sp( env, 16 ); // Reset SP
4195 return fr_dst;
4196 }
4197
4198
4199 /* this is a no-op */
4200 HReg res = iselFltExpr(env, e->Iex.Unop.arg, IEndianess);
4201 return res;
4202 }
4203 default:
4204 break;
4205 }
4206 }
4207
4208 /* --------- MULTIPLEX --------- */
4209 if (e->tag == Iex_ITE) { // VFD
4210 if (ty == Ity_F64
4211 && typeOfIRExpr(env->type_env,e->Iex.ITE.cond) == Ity_I1) {
4212 HReg fr1 = iselDblExpr(env, e->Iex.ITE.iftrue, IEndianess);
4213 HReg fr0 = iselDblExpr(env, e->Iex.ITE.iffalse, IEndianess);
4214 HReg fr_dst = newVRegF(env);
4215 addInstr(env, PPCInstr_FpUnary( Pfp_MOV, fr_dst, fr0 ));
4216 PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
4217 addInstr(env, PPCInstr_FpCMov( cc, fr_dst, fr1 ));
4218 return fr_dst;
4219 }
4220 }
4221
4222 vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e->tag);
4223 ppIRExpr(e);
4224 vpanic("iselDblExpr_wrk(ppc)");
4225 }
4226
iselDfp32Expr(ISelEnv * env,IRExpr * e,IREndness IEndianess)4227 static HReg iselDfp32Expr(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4228 {
4229 HReg r = iselDfp32Expr_wrk( env, e, IEndianess );
4230 vassert(hregClass(r) == HRcFlt64);
4231 vassert( hregIsVirtual(r) );
4232 return r;
4233 }
4234
4235 /* DO NOT CALL THIS DIRECTLY */
iselDfp32Expr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)4236 static HReg iselDfp32Expr_wrk(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4237 {
4238 Bool mode64 = env->mode64;
4239 IRType ty = typeOfIRExpr( env->type_env, e );
4240
4241 vassert( e );
4242 vassert( ty == Ity_D32 );
4243
4244 /* --------- GET --------- */
4245 if (e->tag == Iex_Get) {
4246 HReg r_dst = newVRegF( env );
4247 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4248 GuestStatePtr(mode64) );
4249 addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) );
4250 return r_dst;
4251 }
4252
4253 /* --------- LOAD --------- */
4254 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4255 PPCAMode* am_addr;
4256 HReg r_dst = newVRegF(env);
4257 vassert(e->Iex.Load.ty == Ity_D32);
4258 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_D32/*xfer*/,
4259 IEndianess);
4260 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
4261 return r_dst;
4262 }
4263
4264 /* --------- OPS --------- */
4265 if (e->tag == Iex_Binop) {
4266 if (e->Iex.Binop.op == Iop_D64toD32) {
4267 HReg fr_dst = newVRegF(env);
4268 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4269 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4270 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DRSP, fr_dst, fr_src));
4271 return fr_dst;
4272 }
4273 }
4274
4275 ppIRExpr( e );
4276 vpanic( "iselDfp32Expr_wrk(ppc)" );
4277 }
4278
iselDfp64Expr(ISelEnv * env,IRExpr * e,IREndness IEndianess)4279 static HReg iselDfp64Expr(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4280 {
4281 HReg r = iselDfp64Expr_wrk( env, e, IEndianess );
4282 vassert(hregClass(r) == HRcFlt64);
4283 vassert( hregIsVirtual(r) );
4284 return r;
4285 }
4286
4287 /* DO NOT CALL THIS DIRECTLY */
iselDfp64Expr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)4288 static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4289 {
4290 Bool mode64 = env->mode64;
4291 IRType ty = typeOfIRExpr( env->type_env, e );
4292 HReg r_dstHi, r_dstLo;
4293
4294 vassert( e );
4295 vassert( ty == Ity_D64 );
4296
4297 if (e->tag == Iex_RdTmp) {
4298 return lookupIRTemp( env, e->Iex.RdTmp.tmp );
4299 }
4300
4301 /* --------- GET --------- */
4302 if (e->tag == Iex_Get) {
4303 HReg r_dst = newVRegF( env );
4304 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4305 GuestStatePtr(mode64) );
4306 addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) );
4307 return r_dst;
4308 }
4309
4310 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4311 PPCAMode* am_addr;
4312 HReg r_dst = newVRegF(env);
4313 vassert(e->Iex.Load.ty == Ity_D64);
4314 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_D64/*xfer*/,
4315 IEndianess);
4316 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
4317 return r_dst;
4318 }
4319
4320 /* --------- OPS --------- */
4321 if (e->tag == Iex_Qop) {
4322 HReg r_dst = newVRegF( env );
4323 return r_dst;
4324 }
4325
4326 if (e->tag == Iex_Unop) {
4327 HReg fr_dst = newVRegF(env);
4328 switch (e->Iex.Unop.op) {
4329 case Iop_ReinterpI64asD64: {
4330 /* Given an I64, produce an IEEE754 DFP with the same
4331 bit pattern. */
4332 if (!mode64) {
4333 HReg r_srcHi, r_srcLo;
4334 iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
4335 IEndianess);
4336 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
4337 } else {
4338 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4339 return mk_LoadR64toFPR( env, r_src );
4340 }
4341 }
4342 case Iop_D32toD64: {
4343 HReg fr_src = iselDfp32Expr(env, e->Iex.Unop.arg, IEndianess);
4344 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTDP, fr_dst, fr_src));
4345 return fr_dst;
4346 }
4347 case Iop_D128HItoD64:
4348 iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg,
4349 IEndianess );
4350 return r_dstHi;
4351 case Iop_D128LOtoD64:
4352 iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg,
4353 IEndianess );
4354 return r_dstLo;
4355 case Iop_InsertExpD64: {
4356 HReg fr_srcL = iselDblExpr(env, e->Iex.Binop.arg1, IEndianess);
4357 HReg fr_srcR = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4358
4359 addInstr(env, PPCInstr_Dfp64Binary(Pfp_DIEX, fr_dst, fr_srcL,
4360 fr_srcR));
4361 return fr_dst;
4362 }
4363 default:
4364 vex_printf( "ERROR: iselDfp64Expr_wrk, UNKNOWN unop case %d\n",
4365 e->Iex.Unop.op );
4366 }
4367 }
4368
4369 if (e->tag == Iex_Binop) {
4370 PPCFpOp fpop = Pfp_INVALID;
4371 HReg fr_dst = newVRegF(env);
4372
4373 switch (e->Iex.Binop.op) {
4374 case Iop_D128toD64: fpop = Pfp_DRDPQ; break;
4375 case Iop_D64toD32: fpop = Pfp_DRSP; break;
4376 case Iop_I64StoD64: fpop = Pfp_DCFFIX; break;
4377 case Iop_RoundD64toInt: fpop = Pfp_DRINTN; break;
4378 default: break;
4379 }
4380 if (fpop == Pfp_DRDPQ) {
4381 HReg r_srcHi = newVRegF(env);
4382 HReg r_srcLo = newVRegF(env);
4383
4384 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4385 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4386 IEndianess);
4387 addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
4388 return fr_dst;
4389
4390 } else if (fpop == Pfp_DRINTN) {
4391 HReg fr_src = newVRegF(env);
4392 PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
4393
4394 /* NOTE, this IOP takes a DFP value and rounds to the
4395 * neares floating point integer value, i.e. fractional part
4396 * is zero. The result is a decimal floating point number.
4397 * the INT in the name is a bit misleading.
4398 */
4399 fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4400 addInstr(env, PPCInstr_DfpRound(fr_dst, fr_src, r_rmc));
4401 return fr_dst;
4402
4403 } else if (fpop == Pfp_DRSP) {
4404 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4405 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4406 addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
4407 return fr_dst;
4408
4409 } else if (fpop == Pfp_DCFFIX) {
4410 HReg fr_src = newVRegF(env);
4411 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4412
4413 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4414 sub_from_sp( env, 16 );
4415
4416 // put the I64 value into a floating point register
4417 if (mode64) {
4418 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
4419
4420 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4421 } else {
4422 HReg tmpHi, tmpLo;
4423 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4424
4425 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg2,
4426 IEndianess);
4427 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
4428 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
4429 }
4430
4431 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_src, zero_r1));
4432 addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
4433 add_to_sp( env, 16 );
4434 return fr_dst;
4435 }
4436
4437 switch (e->Iex.Binop.op) {
4438 /* shift instructions D64, I32 -> D64 */
4439 case Iop_ShlD64: fpop = Pfp_DSCLI; break;
4440 case Iop_ShrD64: fpop = Pfp_DSCRI; break;
4441 default: break;
4442 }
4443 if (fpop != Pfp_INVALID) {
4444 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg1, IEndianess);
4445 PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
4446
4447 /* shift value must be an immediate value */
4448 vassert(shift->tag == Pri_Imm);
4449
4450 addInstr(env, PPCInstr_DfpShift(fpop, fr_dst, fr_src, shift));
4451 return fr_dst;
4452 }
4453
4454 switch (e->Iex.Binop.op) {
4455 case Iop_InsertExpD64:
4456 fpop = Pfp_DIEX;
4457 break;
4458 default: break;
4459 }
4460 if (fpop != Pfp_INVALID) {
4461 HReg fr_srcL = newVRegF(env);
4462 HReg fr_srcR = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4463 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4464 sub_from_sp( env, 16 );
4465
4466 if (env->mode64) {
4467 // put the I64 value into a floating point reg
4468 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
4469
4470 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4471 } else {
4472 // put the I64 register pair into a floating point reg
4473 HReg tmpHi;
4474 HReg tmpLo;
4475 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4476
4477 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg1,
4478 IEndianess);
4479 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*!mode64*/));
4480 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*!mode64*/));
4481 }
4482 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_srcL, zero_r1));
4483 addInstr(env, PPCInstr_Dfp64Binary(fpop, fr_dst, fr_srcL,
4484 fr_srcR));
4485 add_to_sp( env, 16 );
4486 return fr_dst;
4487 }
4488 }
4489
4490 if (e->tag == Iex_Triop) {
4491 IRTriop *triop = e->Iex.Triop.details;
4492 PPCFpOp fpop = Pfp_INVALID;
4493
4494 switch (triop->op) {
4495 case Iop_AddD64:
4496 fpop = Pfp_DFPADD;
4497 break;
4498 case Iop_SubD64:
4499 fpop = Pfp_DFPSUB;
4500 break;
4501 case Iop_MulD64:
4502 fpop = Pfp_DFPMUL;
4503 break;
4504 case Iop_DivD64:
4505 fpop = Pfp_DFPDIV;
4506 break;
4507 default:
4508 break;
4509 }
4510 if (fpop != Pfp_INVALID) {
4511 HReg r_dst = newVRegF( env );
4512 HReg r_srcL = iselDfp64Expr( env, triop->arg2, IEndianess );
4513 HReg r_srcR = iselDfp64Expr( env, triop->arg3, IEndianess );
4514
4515 set_FPU_DFP_rounding_mode( env, triop->arg1, IEndianess );
4516 addInstr( env, PPCInstr_Dfp64Binary( fpop, r_dst, r_srcL, r_srcR ) );
4517 return r_dst;
4518 }
4519
4520 switch (triop->op) {
4521 case Iop_QuantizeD64: fpop = Pfp_DQUA; break;
4522 case Iop_SignificanceRoundD64: fpop = Pfp_RRDTR; break;
4523 default: break;
4524 }
4525 if (fpop == Pfp_DQUA) {
4526 HReg r_dst = newVRegF(env);
4527 HReg r_srcL = iselDfp64Expr(env, triop->arg2, IEndianess);
4528 HReg r_srcR = iselDfp64Expr(env, triop->arg3, IEndianess);
4529 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
4530 addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR,
4531 rmc));
4532 return r_dst;
4533
4534 } else if (fpop == Pfp_RRDTR) {
4535 HReg r_dst = newVRegF(env);
4536 HReg r_srcL = newVRegF(env);
4537 HReg r_srcR = iselDfp64Expr(env, triop->arg3, IEndianess);
4538 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
4539 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4540 HReg i8_val = iselWordExpr_R(env, triop->arg2, IEndianess);
4541
4542 /* Move I8 to float register to issue instruction */
4543 sub_from_sp( env, 16 );
4544 if (mode64)
4545 addInstr(env, PPCInstr_Store(8, zero_r1, i8_val, True/*mode64*/));
4546 else
4547 addInstr(env, PPCInstr_Store(4, zero_r1, i8_val, False/*mode32*/));
4548
4549 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1));
4550 add_to_sp( env, 16 );
4551
4552 // will set TE and RMC when issuing instruction
4553 addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR, rmc));
4554 return r_dst;
4555 }
4556 }
4557
4558 ppIRExpr( e );
4559 vpanic( "iselDfp64Expr_wrk(ppc)" );
4560 }
4561
iselDfp128Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)4562 static void iselDfp128Expr(HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e,
4563 IREndness IEndianess)
4564 {
4565 iselDfp128Expr_wrk( rHi, rLo, env, e, IEndianess );
4566 vassert( hregIsVirtual(*rHi) );
4567 vassert( hregIsVirtual(*rLo) );
4568 }
4569
4570 /* DO NOT CALL THIS DIRECTLY */
iselDfp128Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)4571 static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e,
4572 IREndness IEndianess)
4573 {
4574 vassert( e );
4575 vassert( typeOfIRExpr(env->type_env,e) == Ity_D128 );
4576
4577 /* read 128-bit IRTemp */
4578 if (e->tag == Iex_RdTmp) {
4579 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp );
4580 return;
4581 }
4582
4583 if (e->tag == Iex_Unop) {
4584 HReg r_dstHi = newVRegF(env);
4585 HReg r_dstLo = newVRegF(env);
4586
4587 if (e->Iex.Unop.op == Iop_I64StoD128) {
4588 HReg fr_src = newVRegF(env);
4589 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4590
4591 // put the I64 value into a floating point reg
4592 if (env->mode64) {
4593 HReg tmp = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4594 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4595 } else {
4596 HReg tmpHi, tmpLo;
4597 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4598
4599 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg,
4600 IEndianess);
4601 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
4602 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
4603 }
4604
4605 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_src, zero_r1));
4606 addInstr(env, PPCInstr_DfpI64StoD128(Pfp_DCFFIXQ, r_dstHi, r_dstLo,
4607 fr_src));
4608 }
4609
4610 if (e->Iex.Unop.op == Iop_D64toD128) {
4611 HReg r_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
4612
4613 /* Source is 64bit, result is 128 bit. High 64bit source arg,
4614 * is ignored by the instruction. Set high arg to r_src just
4615 * to meet the vassert tests.
4616 */
4617 addInstr(env, PPCInstr_Dfp128Unary(Pfp_DCTQPQ, r_dstHi, r_dstLo,
4618 r_src, r_src));
4619 }
4620 *rHi = r_dstHi;
4621 *rLo = r_dstLo;
4622 return;
4623 }
4624
4625 /* --------- OPS --------- */
4626 if (e->tag == Iex_Binop) {
4627 HReg r_srcHi;
4628 HReg r_srcLo;
4629
4630 switch (e->Iex.Binop.op) {
4631 case Iop_D64HLtoD128:
4632 r_srcHi = iselDfp64Expr( env, e->Iex.Binop.arg1, IEndianess );
4633 r_srcLo = iselDfp64Expr( env, e->Iex.Binop.arg2, IEndianess );
4634 *rHi = r_srcHi;
4635 *rLo = r_srcLo;
4636 return;
4637 break;
4638 case Iop_D128toD64: {
4639 PPCFpOp fpop = Pfp_DRDPQ;
4640 HReg fr_dst = newVRegF(env);
4641
4642 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4643 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4644 IEndianess);
4645 addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
4646
4647 /* Need to meet the interface spec but the result is
4648 * just 64-bits so send the result back in both halfs.
4649 */
4650 *rHi = fr_dst;
4651 *rLo = fr_dst;
4652 return;
4653 }
4654 case Iop_ShlD128:
4655 case Iop_ShrD128: {
4656 HReg fr_dst_hi = newVRegF(env);
4657 HReg fr_dst_lo = newVRegF(env);
4658 PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
4659 PPCFpOp fpop = Pfp_DSCLIQ; /* fix later if necessary */
4660
4661 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg1,
4662 IEndianess);
4663
4664 if (e->Iex.Binop.op == Iop_ShrD128)
4665 fpop = Pfp_DSCRIQ;
4666
4667 addInstr(env, PPCInstr_DfpShift128(fpop, fr_dst_hi, fr_dst_lo,
4668 r_srcHi, r_srcLo, shift));
4669
4670 *rHi = fr_dst_hi;
4671 *rLo = fr_dst_lo;
4672 return;
4673 }
4674 case Iop_RoundD128toInt: {
4675 HReg r_dstHi = newVRegF(env);
4676 HReg r_dstLo = newVRegF(env);
4677 PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
4678
4679 // will set R and RMC when issuing instruction
4680 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4681 IEndianess);
4682
4683 addInstr(env, PPCInstr_DfpRound128(r_dstHi, r_dstLo,
4684 r_srcHi, r_srcLo, r_rmc));
4685 *rHi = r_dstHi;
4686 *rLo = r_dstLo;
4687 return;
4688 }
4689 case Iop_InsertExpD128: {
4690 HReg r_dstHi = newVRegF(env);
4691 HReg r_dstLo = newVRegF(env);
4692 HReg r_srcL = newVRegF(env);
4693 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4694 r_srcHi = newVRegF(env);
4695 r_srcLo = newVRegF(env);
4696
4697 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4698 IEndianess);
4699
4700 /* Move I64 to float register to issue instruction */
4701 if (env->mode64) {
4702 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
4703 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4704 } else {
4705 HReg tmpHi, tmpLo;
4706 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4707
4708 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg,
4709 IEndianess);
4710 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
4711 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
4712 }
4713
4714 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1));
4715 addInstr(env, PPCInstr_InsertExpD128(Pfp_DIEXQ,
4716 r_dstHi, r_dstLo,
4717 r_srcL, r_srcHi, r_srcLo));
4718 *rHi = r_dstHi;
4719 *rLo = r_dstLo;
4720 return;
4721 }
4722 default:
4723 vex_printf( "ERROR: iselDfp128Expr_wrk, UNKNOWN binop case %d\n",
4724 e->Iex.Binop.op );
4725 break;
4726 }
4727 }
4728
4729 if (e->tag == Iex_Triop) {
4730 IRTriop *triop = e->Iex.Triop.details;
4731 PPCFpOp fpop = Pfp_INVALID;
4732 HReg r_dstHi = newVRegF(env);
4733 HReg r_dstLo = newVRegF(env);
4734
4735 switch (triop->op) {
4736 case Iop_AddD128:
4737 fpop = Pfp_DFPADDQ;
4738 break;
4739 case Iop_SubD128:
4740 fpop = Pfp_DFPSUBQ;
4741 break;
4742 case Iop_MulD128:
4743 fpop = Pfp_DFPMULQ;
4744 break;
4745 case Iop_DivD128:
4746 fpop = Pfp_DFPDIVQ;
4747 break;
4748 default:
4749 break;
4750 }
4751
4752 if (fpop != Pfp_INVALID) {
4753 HReg r_srcRHi = newVRegV( env );
4754 HReg r_srcRLo = newVRegV( env );
4755
4756 /* dst will be used to pass in the left operand and get the result. */
4757 iselDfp128Expr( &r_dstHi, &r_dstLo, env, triop->arg2, IEndianess );
4758 iselDfp128Expr( &r_srcRHi, &r_srcRLo, env, triop->arg3, IEndianess );
4759 set_FPU_DFP_rounding_mode( env, triop->arg1, IEndianess );
4760 addInstr( env,
4761 PPCInstr_Dfp128Binary( fpop, r_dstHi, r_dstLo,
4762 r_srcRHi, r_srcRLo ) );
4763 *rHi = r_dstHi;
4764 *rLo = r_dstLo;
4765 return;
4766 }
4767 switch (triop->op) {
4768 case Iop_QuantizeD128: fpop = Pfp_DQUAQ; break;
4769 case Iop_SignificanceRoundD128: fpop = Pfp_DRRNDQ; break;
4770 default: break;
4771 }
4772 if (fpop == Pfp_DQUAQ) {
4773 HReg r_srcHi = newVRegF(env);
4774 HReg r_srcLo = newVRegF(env);
4775 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
4776
4777 /* dst will be used to pass in the left operand and get the result */
4778 iselDfp128Expr(&r_dstHi, &r_dstLo, env, triop->arg2, IEndianess);
4779 iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3, IEndianess);
4780
4781 // will set RMC when issuing instruction
4782 addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo,
4783 r_srcHi, r_srcLo, rmc));
4784 *rHi = r_dstHi;
4785 *rLo = r_dstLo;
4786 return;
4787
4788 } else if (fpop == Pfp_DRRNDQ) {
4789 HReg r_srcHi = newVRegF(env);
4790 HReg r_srcLo = newVRegF(env);
4791 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
4792 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4793 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4794 HReg i8_val = iselWordExpr_R(env, triop->arg2, IEndianess);
4795 HReg r_zero = newVRegI( env );
4796
4797 iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3, IEndianess);
4798
4799 /* dst will be used to pass in the left operand and get the result */
4800 /* Move I8 to float register to issue instruction. Note, the
4801 * instruction only looks at the bottom 6 bits so we really don't
4802 * have to clear the upper bits since the iselWordExpr_R sets the
4803 * bottom 8-bits.
4804 */
4805 sub_from_sp( env, 16 );
4806
4807 if (env->mode64)
4808 addInstr(env, PPCInstr_Store(4, four_r1, i8_val, True/*mode64*/));
4809 else
4810 addInstr(env, PPCInstr_Store(4, four_r1, i8_val, False/*mode32*/));
4811
4812 /* Have to write to the upper bits to ensure they have been
4813 * initialized. The instruction ignores all but the lower 6-bits.
4814 */
4815 addInstr( env, PPCInstr_LI( r_zero, 0, env->mode64 ) );
4816 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstHi, zero_r1));
4817 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstLo, zero_r1));
4818
4819 add_to_sp( env, 16 );
4820
4821 // will set RMC when issuing instruction
4822 addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo,
4823 r_srcHi, r_srcLo, rmc));
4824 *rHi = r_dstHi;
4825 *rLo = r_dstLo;
4826 return;
4827 }
4828 }
4829
4830 ppIRExpr( e );
4831 vpanic( "iselDfp128Expr(ppc64)" );
4832 }
4833
4834
4835 /*---------------------------------------------------------*/
4836 /*--- ISEL: SIMD (Vector) expressions, 128 bit. ---*/
4837 /*---------------------------------------------------------*/
4838
iselVecExpr(ISelEnv * env,IRExpr * e,IREndness IEndianess)4839 static HReg iselVecExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
4840 {
4841 HReg r = iselVecExpr_wrk( env, e, IEndianess );
4842 # if 0
4843 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4844 # endif
4845 vassert(hregClass(r) == HRcVec128);
4846 vassert(hregIsVirtual(r));
4847 return r;
4848 }
4849
4850 /* DO NOT CALL THIS DIRECTLY */
iselVecExpr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)4851 static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
4852 {
4853 Bool mode64 = env->mode64;
4854 PPCAvOp op = Pav_INVALID;
4855 PPCAvFpOp fpop = Pavfp_INVALID;
4856 IRType ty = typeOfIRExpr(env->type_env,e);
4857 vassert(e);
4858 vassert(ty == Ity_V128);
4859
4860 if (e->tag == Iex_RdTmp) {
4861 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
4862 }
4863
4864 if (e->tag == Iex_Get) {
4865 /* Guest state vectors are 16byte aligned,
4866 so don't need to worry here */
4867 HReg dst = newVRegV(env);
4868 addInstr(env,
4869 PPCInstr_AvLdSt( True/*load*/, 16, dst,
4870 PPCAMode_IR( e->Iex.Get.offset,
4871 GuestStatePtr(mode64) )));
4872 return dst;
4873 }
4874
4875 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4876 /* Need to be able to do V128 unaligned loads. The BE unaligned load
4877 * can be accomplised using the following code sequece from the ISA.
4878 * It uses the lvx instruction that does two aligned loads and then
4879 * permute the data to store the required data as if it had been an
4880 * unaligned load.
4881 *
4882 * lvx Vhi,0,Rb # load MSQ, using the unaligned address in Rb
4883 * lvsl Vp, 0,Rb # Set permute control vector
4884 * addi Rb,Rb,15 # Address of LSQ
4885 * lvx Vlo,0,Rb # load LSQ
4886 * vperm Vt,Vhi,Vlo,Vp # align the data as requested
4887 */
4888
4889 HReg Vhi = newVRegV(env);
4890 HReg Vlo = newVRegV(env);
4891 HReg Vp = newVRegV(env);
4892 HReg v_dst = newVRegV(env);
4893 HReg rB;
4894 HReg rB_plus_15 = newVRegI(env);
4895
4896 vassert(e->Iex.Load.ty == Ity_V128);
4897 rB = iselWordExpr_R( env, e->Iex.Load.addr, IEndianess );
4898
4899 // lvx Vhi, 0, Rb
4900 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vhi,
4901 PPCAMode_IR(0, rB)) );
4902
4903 if (IEndianess == Iend_LE)
4904 // lvsr Vp, 0, Rb
4905 addInstr(env, PPCInstr_AvSh( False/*right shift*/, Vp,
4906 PPCAMode_IR(0, rB)) );
4907 else
4908 // lvsl Vp, 0, Rb
4909 addInstr(env, PPCInstr_AvSh( True/*left shift*/, Vp,
4910 PPCAMode_IR(0, rB)) );
4911
4912 // addi Rb_plus_15, Rb, 15
4913 addInstr(env, PPCInstr_Alu( Palu_ADD, rB_plus_15,
4914 rB, PPCRH_Imm(True, toUShort(15))) );
4915
4916 // lvx Vlo, 0, Rb_plus_15
4917 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vlo,
4918 PPCAMode_IR(0, rB_plus_15)) );
4919
4920 if (IEndianess == Iend_LE)
4921 // vperm Vt, Vhi, Vlo, Vp
4922 addInstr(env, PPCInstr_AvPerm( v_dst, Vlo, Vhi, Vp ));
4923 else
4924 // vperm Vt, Vhi, Vlo, Vp
4925 addInstr(env, PPCInstr_AvPerm( v_dst, Vhi, Vlo, Vp ));
4926
4927 return v_dst;
4928 }
4929
4930 if (e->tag == Iex_Unop) {
4931 switch (e->Iex.Unop.op) {
4932
4933 case Iop_NotV128: {
4934 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4935 HReg dst = newVRegV(env);
4936 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, arg));
4937 return dst;
4938 }
4939
4940 case Iop_CmpNEZ8x16: {
4941 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4942 HReg zero = newVRegV(env);
4943 HReg dst = newVRegV(env);
4944 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4945 addInstr(env, PPCInstr_AvBin8x16(Pav_CMPEQU, dst, arg, zero));
4946 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4947 return dst;
4948 }
4949
4950 case Iop_CmpNEZ16x8: {
4951 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4952 HReg zero = newVRegV(env);
4953 HReg dst = newVRegV(env);
4954 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4955 addInstr(env, PPCInstr_AvBin16x8(Pav_CMPEQU, dst, arg, zero));
4956 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4957 return dst;
4958 }
4959
4960 case Iop_CmpNEZ32x4: {
4961 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4962 HReg zero = newVRegV(env);
4963 HReg dst = newVRegV(env);
4964 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4965 addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, dst, arg, zero));
4966 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4967 return dst;
4968 }
4969
4970 case Iop_CmpNEZ64x2: {
4971 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4972 HReg zero = newVRegV(env);
4973 HReg dst = newVRegV(env);
4974 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4975 addInstr(env, PPCInstr_AvBin64x2(Pav_CMPEQU, dst, arg, zero));
4976 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4977 return dst;
4978 }
4979
4980 case Iop_RecipEst32Fx4: fpop = Pavfp_RCPF; goto do_32Fx4_unary;
4981 case Iop_RSqrtEst32Fx4: fpop = Pavfp_RSQRTF; goto do_32Fx4_unary;
4982 case Iop_I32UtoFx4: fpop = Pavfp_CVTU2F; goto do_32Fx4_unary;
4983 case Iop_I32StoFx4: fpop = Pavfp_CVTS2F; goto do_32Fx4_unary;
4984 case Iop_QFtoI32Ux4_RZ: fpop = Pavfp_QCVTF2U; goto do_32Fx4_unary;
4985 case Iop_QFtoI32Sx4_RZ: fpop = Pavfp_QCVTF2S; goto do_32Fx4_unary;
4986 case Iop_RoundF32x4_RM: fpop = Pavfp_ROUNDM; goto do_32Fx4_unary;
4987 case Iop_RoundF32x4_RP: fpop = Pavfp_ROUNDP; goto do_32Fx4_unary;
4988 case Iop_RoundF32x4_RN: fpop = Pavfp_ROUNDN; goto do_32Fx4_unary;
4989 case Iop_RoundF32x4_RZ: fpop = Pavfp_ROUNDZ; goto do_32Fx4_unary;
4990 do_32Fx4_unary:
4991 {
4992 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4993 HReg dst = newVRegV(env);
4994 addInstr(env, PPCInstr_AvUn32Fx4(fpop, dst, arg));
4995 return dst;
4996 }
4997
4998 case Iop_32UtoV128: {
4999 HReg r_aligned16, r_zeros;
5000 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
5001 HReg dst = newVRegV(env);
5002 PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
5003 sub_from_sp( env, 32 ); // Move SP down
5004
5005 /* Get a quadword aligned address within our stack space */
5006 r_aligned16 = get_sp_aligned16( env );
5007 am_off0 = PPCAMode_IR( 0, r_aligned16 );
5008 am_off4 = PPCAMode_IR( 4, r_aligned16 );
5009 am_off8 = PPCAMode_IR( 8, r_aligned16 );
5010 am_off12 = PPCAMode_IR( 12, r_aligned16 );
5011
5012 /* Store zeros */
5013 r_zeros = newVRegI(env);
5014 addInstr(env, PPCInstr_LI(r_zeros, 0x0, mode64));
5015 if (IEndianess == Iend_LE)
5016 addInstr(env, PPCInstr_Store( 4, am_off0, r_src, mode64 ));
5017 else
5018 addInstr(env, PPCInstr_Store( 4, am_off0, r_zeros, mode64 ));
5019 addInstr(env, PPCInstr_Store( 4, am_off4, r_zeros, mode64 ));
5020 addInstr(env, PPCInstr_Store( 4, am_off8, r_zeros, mode64 ));
5021
5022 /* Store r_src in low word of quadword-aligned mem */
5023 if (IEndianess == Iend_LE)
5024 addInstr(env, PPCInstr_Store( 4, am_off12, r_zeros, mode64 ));
5025 else
5026 addInstr(env, PPCInstr_Store( 4, am_off12, r_src, mode64 ));
5027
5028 /* Load word into low word of quadword vector reg */
5029 if (IEndianess == Iend_LE)
5030 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off0 ));
5031 else
5032 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off12 ));
5033
5034 add_to_sp( env, 32 ); // Reset SP
5035 return dst;
5036 }
5037
5038 case Iop_Dup8x16:
5039 case Iop_Dup16x8:
5040 case Iop_Dup32x4:
5041 return mk_AvDuplicateRI(env, e->Iex.Unop.arg, IEndianess);
5042
5043 case Iop_CipherSV128: op = Pav_CIPHERSUBV128; goto do_AvCipherV128Un;
5044 do_AvCipherV128Un: {
5045 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5046 HReg dst = newVRegV(env);
5047 addInstr(env, PPCInstr_AvCipherV128Unary(op, dst, arg));
5048 return dst;
5049 }
5050
5051 case Iop_Clz8x16: op = Pav_ZEROCNTBYTE; goto do_zerocnt;
5052 case Iop_Clz16x8: op = Pav_ZEROCNTHALF; goto do_zerocnt;
5053 case Iop_Clz32x4: op = Pav_ZEROCNTWORD; goto do_zerocnt;
5054 case Iop_Clz64x2: op = Pav_ZEROCNTDBL; goto do_zerocnt;
5055 case Iop_PwBitMtxXpose64x2: op = Pav_BITMTXXPOSE; goto do_zerocnt;
5056 do_zerocnt:
5057 {
5058 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5059 HReg dst = newVRegV(env);
5060 addInstr(env, PPCInstr_AvUnary(op, dst, arg));
5061 return dst;
5062 }
5063
5064 default:
5065 break;
5066 } /* switch (e->Iex.Unop.op) */
5067 } /* if (e->tag == Iex_Unop) */
5068
5069 if (e->tag == Iex_Binop) {
5070 switch (e->Iex.Binop.op) {
5071
5072 case Iop_64HLtoV128: {
5073 if (!mode64) {
5074 HReg r3, r2, r1, r0, r_aligned16;
5075 PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
5076 HReg dst = newVRegV(env);
5077 /* do this via the stack (easy, convenient, etc) */
5078 sub_from_sp( env, 32 ); // Move SP down
5079
5080 // get a quadword aligned address within our stack space
5081 r_aligned16 = get_sp_aligned16( env );
5082 am_off0 = PPCAMode_IR( 0, r_aligned16 );
5083 am_off4 = PPCAMode_IR( 4, r_aligned16 );
5084 am_off8 = PPCAMode_IR( 8, r_aligned16 );
5085 am_off12 = PPCAMode_IR( 12, r_aligned16 );
5086
5087 /* Do the less significant 64 bits */
5088 iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2, IEndianess);
5089 addInstr(env, PPCInstr_Store( 4, am_off12, r0, mode64 ));
5090 addInstr(env, PPCInstr_Store( 4, am_off8, r1, mode64 ));
5091 /* Do the more significant 64 bits */
5092 iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1, IEndianess);
5093 addInstr(env, PPCInstr_Store( 4, am_off4, r2, mode64 ));
5094 addInstr(env, PPCInstr_Store( 4, am_off0, r3, mode64 ));
5095
5096 /* Fetch result back from stack. */
5097 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
5098
5099 add_to_sp( env, 32 ); // Reset SP
5100 return dst;
5101 } else {
5102 HReg rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
5103 HReg rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
5104 HReg dst = newVRegV(env);
5105 HReg r_aligned16;
5106 PPCAMode *am_off0, *am_off8;
5107 /* do this via the stack (easy, convenient, etc) */
5108 sub_from_sp( env, 32 ); // Move SP down
5109
5110 // get a quadword aligned address within our stack space
5111 r_aligned16 = get_sp_aligned16( env );
5112 am_off0 = PPCAMode_IR( 0, r_aligned16 );
5113 am_off8 = PPCAMode_IR( 8, r_aligned16 );
5114
5115 /* Store 2*I64 to stack */
5116 if (IEndianess == Iend_LE) {
5117 addInstr(env, PPCInstr_Store( 8, am_off0, rLo, mode64 ));
5118 addInstr(env, PPCInstr_Store( 8, am_off8, rHi, mode64 ));
5119 } else {
5120 addInstr(env, PPCInstr_Store( 8, am_off0, rHi, mode64 ));
5121 addInstr(env, PPCInstr_Store( 8, am_off8, rLo, mode64 ));
5122 }
5123 /* Fetch result back from stack. */
5124 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
5125
5126 add_to_sp( env, 32 ); // Reset SP
5127 return dst;
5128 }
5129 }
5130
5131 case Iop_Max32Fx4: fpop = Pavfp_MAXF; goto do_32Fx4;
5132 case Iop_Min32Fx4: fpop = Pavfp_MINF; goto do_32Fx4;
5133 case Iop_CmpEQ32Fx4: fpop = Pavfp_CMPEQF; goto do_32Fx4;
5134 case Iop_CmpGT32Fx4: fpop = Pavfp_CMPGTF; goto do_32Fx4;
5135 case Iop_CmpGE32Fx4: fpop = Pavfp_CMPGEF; goto do_32Fx4;
5136 do_32Fx4:
5137 {
5138 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5139 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5140 HReg dst = newVRegV(env);
5141 addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
5142 return dst;
5143 }
5144
5145 case Iop_CmpLE32Fx4: {
5146 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5147 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5148 HReg dst = newVRegV(env);
5149
5150 /* stay consistent with native ppc compares:
5151 if a left/right lane holds a nan, return zeros for that lane
5152 so: le == NOT(gt OR isNan)
5153 */
5154 HReg isNanLR = newVRegV(env);
5155 HReg isNanL = isNan(env, argL, IEndianess);
5156 HReg isNanR = isNan(env, argR, IEndianess);
5157 addInstr(env, PPCInstr_AvBinary(Pav_OR, isNanLR,
5158 isNanL, isNanR));
5159
5160 addInstr(env, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF, dst,
5161 argL, argR));
5162 addInstr(env, PPCInstr_AvBinary(Pav_OR, dst, dst, isNanLR));
5163 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
5164 return dst;
5165 }
5166
5167 case Iop_AndV128: op = Pav_AND; goto do_AvBin;
5168 case Iop_OrV128: op = Pav_OR; goto do_AvBin;
5169 case Iop_XorV128: op = Pav_XOR; goto do_AvBin;
5170 do_AvBin: {
5171 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5172 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5173 HReg dst = newVRegV(env);
5174 addInstr(env, PPCInstr_AvBinary(op, dst, arg1, arg2));
5175 return dst;
5176 }
5177
5178 case Iop_Shl8x16: op = Pav_SHL; goto do_AvBin8x16;
5179 case Iop_Shr8x16: op = Pav_SHR; goto do_AvBin8x16;
5180 case Iop_Sar8x16: op = Pav_SAR; goto do_AvBin8x16;
5181 case Iop_Rol8x16: op = Pav_ROTL; goto do_AvBin8x16;
5182 case Iop_InterleaveHI8x16: op = Pav_MRGHI; goto do_AvBin8x16;
5183 case Iop_InterleaveLO8x16: op = Pav_MRGLO; goto do_AvBin8x16;
5184 case Iop_Add8x16: op = Pav_ADDU; goto do_AvBin8x16;
5185 case Iop_QAdd8Ux16: op = Pav_QADDU; goto do_AvBin8x16;
5186 case Iop_QAdd8Sx16: op = Pav_QADDS; goto do_AvBin8x16;
5187 case Iop_Sub8x16: op = Pav_SUBU; goto do_AvBin8x16;
5188 case Iop_QSub8Ux16: op = Pav_QSUBU; goto do_AvBin8x16;
5189 case Iop_QSub8Sx16: op = Pav_QSUBS; goto do_AvBin8x16;
5190 case Iop_Avg8Ux16: op = Pav_AVGU; goto do_AvBin8x16;
5191 case Iop_Avg8Sx16: op = Pav_AVGS; goto do_AvBin8x16;
5192 case Iop_Max8Ux16: op = Pav_MAXU; goto do_AvBin8x16;
5193 case Iop_Max8Sx16: op = Pav_MAXS; goto do_AvBin8x16;
5194 case Iop_Min8Ux16: op = Pav_MINU; goto do_AvBin8x16;
5195 case Iop_Min8Sx16: op = Pav_MINS; goto do_AvBin8x16;
5196 case Iop_MullEven8Ux16: op = Pav_OMULU; goto do_AvBin8x16;
5197 case Iop_MullEven8Sx16: op = Pav_OMULS; goto do_AvBin8x16;
5198 case Iop_CmpEQ8x16: op = Pav_CMPEQU; goto do_AvBin8x16;
5199 case Iop_CmpGT8Ux16: op = Pav_CMPGTU; goto do_AvBin8x16;
5200 case Iop_CmpGT8Sx16: op = Pav_CMPGTS; goto do_AvBin8x16;
5201 case Iop_PolynomialMulAdd8x16: op = Pav_POLYMULADD; goto do_AvBin8x16;
5202 do_AvBin8x16: {
5203 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5204 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5205 HReg dst = newVRegV(env);
5206 addInstr(env, PPCInstr_AvBin8x16(op, dst, arg1, arg2));
5207 return dst;
5208 }
5209
5210 case Iop_Shl16x8: op = Pav_SHL; goto do_AvBin16x8;
5211 case Iop_Shr16x8: op = Pav_SHR; goto do_AvBin16x8;
5212 case Iop_Sar16x8: op = Pav_SAR; goto do_AvBin16x8;
5213 case Iop_Rol16x8: op = Pav_ROTL; goto do_AvBin16x8;
5214 case Iop_NarrowBin16to8x16: op = Pav_PACKUU; goto do_AvBin16x8;
5215 case Iop_QNarrowBin16Uto8Ux16: op = Pav_QPACKUU; goto do_AvBin16x8;
5216 case Iop_QNarrowBin16Sto8Sx16: op = Pav_QPACKSS; goto do_AvBin16x8;
5217 case Iop_InterleaveHI16x8: op = Pav_MRGHI; goto do_AvBin16x8;
5218 case Iop_InterleaveLO16x8: op = Pav_MRGLO; goto do_AvBin16x8;
5219 case Iop_Add16x8: op = Pav_ADDU; goto do_AvBin16x8;
5220 case Iop_QAdd16Ux8: op = Pav_QADDU; goto do_AvBin16x8;
5221 case Iop_QAdd16Sx8: op = Pav_QADDS; goto do_AvBin16x8;
5222 case Iop_Sub16x8: op = Pav_SUBU; goto do_AvBin16x8;
5223 case Iop_QSub16Ux8: op = Pav_QSUBU; goto do_AvBin16x8;
5224 case Iop_QSub16Sx8: op = Pav_QSUBS; goto do_AvBin16x8;
5225 case Iop_Avg16Ux8: op = Pav_AVGU; goto do_AvBin16x8;
5226 case Iop_Avg16Sx8: op = Pav_AVGS; goto do_AvBin16x8;
5227 case Iop_Max16Ux8: op = Pav_MAXU; goto do_AvBin16x8;
5228 case Iop_Max16Sx8: op = Pav_MAXS; goto do_AvBin16x8;
5229 case Iop_Min16Ux8: op = Pav_MINU; goto do_AvBin16x8;
5230 case Iop_Min16Sx8: op = Pav_MINS; goto do_AvBin16x8;
5231 case Iop_MullEven16Ux8: op = Pav_OMULU; goto do_AvBin16x8;
5232 case Iop_MullEven16Sx8: op = Pav_OMULS; goto do_AvBin16x8;
5233 case Iop_CmpEQ16x8: op = Pav_CMPEQU; goto do_AvBin16x8;
5234 case Iop_CmpGT16Ux8: op = Pav_CMPGTU; goto do_AvBin16x8;
5235 case Iop_CmpGT16Sx8: op = Pav_CMPGTS; goto do_AvBin16x8;
5236 case Iop_PolynomialMulAdd16x8: op = Pav_POLYMULADD; goto do_AvBin16x8;
5237 do_AvBin16x8: {
5238 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5239 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5240 HReg dst = newVRegV(env);
5241 addInstr(env, PPCInstr_AvBin16x8(op, dst, arg1, arg2));
5242 return dst;
5243 }
5244
5245 case Iop_Shl32x4: op = Pav_SHL; goto do_AvBin32x4;
5246 case Iop_Shr32x4: op = Pav_SHR; goto do_AvBin32x4;
5247 case Iop_Sar32x4: op = Pav_SAR; goto do_AvBin32x4;
5248 case Iop_Rol32x4: op = Pav_ROTL; goto do_AvBin32x4;
5249 case Iop_NarrowBin32to16x8: op = Pav_PACKUU; goto do_AvBin32x4;
5250 case Iop_QNarrowBin32Uto16Ux8: op = Pav_QPACKUU; goto do_AvBin32x4;
5251 case Iop_QNarrowBin32Sto16Sx8: op = Pav_QPACKSS; goto do_AvBin32x4;
5252 case Iop_InterleaveHI32x4: op = Pav_MRGHI; goto do_AvBin32x4;
5253 case Iop_InterleaveLO32x4: op = Pav_MRGLO; goto do_AvBin32x4;
5254 case Iop_Add32x4: op = Pav_ADDU; goto do_AvBin32x4;
5255 case Iop_QAdd32Ux4: op = Pav_QADDU; goto do_AvBin32x4;
5256 case Iop_QAdd32Sx4: op = Pav_QADDS; goto do_AvBin32x4;
5257 case Iop_Sub32x4: op = Pav_SUBU; goto do_AvBin32x4;
5258 case Iop_QSub32Ux4: op = Pav_QSUBU; goto do_AvBin32x4;
5259 case Iop_QSub32Sx4: op = Pav_QSUBS; goto do_AvBin32x4;
5260 case Iop_Avg32Ux4: op = Pav_AVGU; goto do_AvBin32x4;
5261 case Iop_Avg32Sx4: op = Pav_AVGS; goto do_AvBin32x4;
5262 case Iop_Max32Ux4: op = Pav_MAXU; goto do_AvBin32x4;
5263 case Iop_Max32Sx4: op = Pav_MAXS; goto do_AvBin32x4;
5264 case Iop_Min32Ux4: op = Pav_MINU; goto do_AvBin32x4;
5265 case Iop_Min32Sx4: op = Pav_MINS; goto do_AvBin32x4;
5266 case Iop_Mul32x4: op = Pav_MULU; goto do_AvBin32x4;
5267 case Iop_MullEven32Ux4: op = Pav_OMULU; goto do_AvBin32x4;
5268 case Iop_MullEven32Sx4: op = Pav_OMULS; goto do_AvBin32x4;
5269 case Iop_CmpEQ32x4: op = Pav_CMPEQU; goto do_AvBin32x4;
5270 case Iop_CmpGT32Ux4: op = Pav_CMPGTU; goto do_AvBin32x4;
5271 case Iop_CmpGT32Sx4: op = Pav_CMPGTS; goto do_AvBin32x4;
5272 case Iop_CatOddLanes32x4: op = Pav_CATODD; goto do_AvBin32x4;
5273 case Iop_CatEvenLanes32x4: op = Pav_CATEVEN; goto do_AvBin32x4;
5274 case Iop_PolynomialMulAdd32x4: op = Pav_POLYMULADD; goto do_AvBin32x4;
5275 do_AvBin32x4: {
5276 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5277 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5278 HReg dst = newVRegV(env);
5279 addInstr(env, PPCInstr_AvBin32x4(op, dst, arg1, arg2));
5280 return dst;
5281 }
5282
5283 case Iop_Shl64x2: op = Pav_SHL; goto do_AvBin64x2;
5284 case Iop_Shr64x2: op = Pav_SHR; goto do_AvBin64x2;
5285 case Iop_Sar64x2: op = Pav_SAR; goto do_AvBin64x2;
5286 case Iop_Rol64x2: op = Pav_ROTL; goto do_AvBin64x2;
5287 case Iop_NarrowBin64to32x4: op = Pav_PACKUU; goto do_AvBin64x2;
5288 case Iop_QNarrowBin64Sto32Sx4: op = Pav_QPACKSS; goto do_AvBin64x2;
5289 case Iop_QNarrowBin64Uto32Ux4: op = Pav_QPACKUU; goto do_AvBin64x2;
5290 case Iop_InterleaveHI64x2: op = Pav_MRGHI; goto do_AvBin64x2;
5291 case Iop_InterleaveLO64x2: op = Pav_MRGLO; goto do_AvBin64x2;
5292 case Iop_Add64x2: op = Pav_ADDU; goto do_AvBin64x2;
5293 case Iop_Sub64x2: op = Pav_SUBU; goto do_AvBin64x2;
5294 case Iop_Max64Ux2: op = Pav_MAXU; goto do_AvBin64x2;
5295 case Iop_Max64Sx2: op = Pav_MAXS; goto do_AvBin64x2;
5296 case Iop_Min64Ux2: op = Pav_MINU; goto do_AvBin64x2;
5297 case Iop_Min64Sx2: op = Pav_MINS; goto do_AvBin64x2;
5298 case Iop_CmpEQ64x2: op = Pav_CMPEQU; goto do_AvBin64x2;
5299 case Iop_CmpGT64Ux2: op = Pav_CMPGTU; goto do_AvBin64x2;
5300 case Iop_CmpGT64Sx2: op = Pav_CMPGTS; goto do_AvBin64x2;
5301 case Iop_PolynomialMulAdd64x2: op = Pav_POLYMULADD; goto do_AvBin64x2;
5302 do_AvBin64x2: {
5303 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5304 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5305 HReg dst = newVRegV(env);
5306 addInstr(env, PPCInstr_AvBin64x2(op, dst, arg1, arg2));
5307 return dst;
5308 }
5309
5310 case Iop_ShlN8x16: op = Pav_SHL; goto do_AvShift8x16;
5311 case Iop_SarN8x16: op = Pav_SAR; goto do_AvShift8x16;
5312 do_AvShift8x16: {
5313 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5314 HReg dst = newVRegV(env);
5315 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5316 addInstr(env, PPCInstr_AvBin8x16(op, dst, r_src, v_shft));
5317 return dst;
5318 }
5319
5320 case Iop_ShlN16x8: op = Pav_SHL; goto do_AvShift16x8;
5321 case Iop_ShrN16x8: op = Pav_SHR; goto do_AvShift16x8;
5322 case Iop_SarN16x8: op = Pav_SAR; goto do_AvShift16x8;
5323 do_AvShift16x8: {
5324 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5325 HReg dst = newVRegV(env);
5326 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5327 addInstr(env, PPCInstr_AvBin16x8(op, dst, r_src, v_shft));
5328 return dst;
5329 }
5330
5331 case Iop_ShlN32x4: op = Pav_SHL; goto do_AvShift32x4;
5332 case Iop_ShrN32x4: op = Pav_SHR; goto do_AvShift32x4;
5333 case Iop_SarN32x4: op = Pav_SAR; goto do_AvShift32x4;
5334 do_AvShift32x4: {
5335 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5336 HReg dst = newVRegV(env);
5337 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5338 addInstr(env, PPCInstr_AvBin32x4(op, dst, r_src, v_shft));
5339 return dst;
5340 }
5341
5342 case Iop_ShlN64x2: op = Pav_SHL; goto do_AvShift64x2;
5343 case Iop_ShrN64x2: op = Pav_SHR; goto do_AvShift64x2;
5344 case Iop_SarN64x2: op = Pav_SAR; goto do_AvShift64x2;
5345 do_AvShift64x2: {
5346 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5347 HReg dst = newVRegV(env);
5348 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5349 addInstr(env, PPCInstr_AvBin64x2(op, dst, r_src, v_shft));
5350 return dst;
5351 }
5352
5353 case Iop_ShrV128: op = Pav_SHR; goto do_AvShiftV128;
5354 case Iop_ShlV128: op = Pav_SHL; goto do_AvShiftV128;
5355 do_AvShiftV128: {
5356 HReg dst = newVRegV(env);
5357 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5358 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5359 /* Note: shift value gets masked by 127 */
5360 addInstr(env, PPCInstr_AvBinary(op, dst, r_src, v_shft));
5361 return dst;
5362 }
5363
5364 case Iop_Perm8x16: {
5365 HReg dst = newVRegV(env);
5366 HReg v_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5367 HReg v_ctl = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5368 addInstr(env, PPCInstr_AvPerm(dst, v_src, v_src, v_ctl));
5369 return dst;
5370 }
5371
5372 case Iop_CipherV128: op = Pav_CIPHERV128; goto do_AvCipherV128;
5373 case Iop_CipherLV128: op = Pav_CIPHERLV128; goto do_AvCipherV128;
5374 case Iop_NCipherV128: op = Pav_NCIPHERV128; goto do_AvCipherV128;
5375 case Iop_NCipherLV128:op = Pav_NCIPHERLV128; goto do_AvCipherV128;
5376 do_AvCipherV128: {
5377 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5378 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5379 HReg dst = newVRegV(env);
5380 addInstr(env, PPCInstr_AvCipherV128Binary(op, dst, arg1, arg2));
5381 return dst;
5382 }
5383
5384 case Iop_SHA256:op = Pav_SHA256; goto do_AvHashV128;
5385 case Iop_SHA512:op = Pav_SHA512; goto do_AvHashV128;
5386 do_AvHashV128: {
5387 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5388 HReg dst = newVRegV(env);
5389 PPCRI* s_field = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
5390 addInstr(env, PPCInstr_AvHashV128Binary(op, dst, arg1, s_field));
5391 return dst;
5392 }
5393 default:
5394 break;
5395 } /* switch (e->Iex.Binop.op) */
5396 } /* if (e->tag == Iex_Binop) */
5397
5398 if (e->tag == Iex_Triop) {
5399 IRTriop *triop = e->Iex.Triop.details;
5400 switch (triop->op) {
5401 case Iop_BCDAdd:op = Pav_BCDAdd; goto do_AvBCDV128;
5402 case Iop_BCDSub:op = Pav_BCDSub; goto do_AvBCDV128;
5403 do_AvBCDV128: {
5404 HReg arg1 = iselVecExpr(env, triop->arg1, IEndianess);
5405 HReg arg2 = iselVecExpr(env, triop->arg2, IEndianess);
5406 HReg dst = newVRegV(env);
5407 PPCRI* ps = iselWordExpr_RI(env, triop->arg3, IEndianess);
5408 addInstr(env, PPCInstr_AvBCDV128Trinary(op, dst, arg1, arg2, ps));
5409 return dst;
5410 }
5411
5412 case Iop_Add32Fx4: fpop = Pavfp_ADDF; goto do_32Fx4_with_rm;
5413 case Iop_Sub32Fx4: fpop = Pavfp_SUBF; goto do_32Fx4_with_rm;
5414 case Iop_Mul32Fx4: fpop = Pavfp_MULF; goto do_32Fx4_with_rm;
5415 do_32Fx4_with_rm:
5416 {
5417 HReg argL = iselVecExpr(env, triop->arg2, IEndianess);
5418 HReg argR = iselVecExpr(env, triop->arg3, IEndianess);
5419 HReg dst = newVRegV(env);
5420 /* FIXME: this is bogus, in the sense that Altivec ignores
5421 FPSCR.RM, at least for some FP operations. So setting the
5422 RM is pointless. This is only really correct in the case
5423 where the RM is known, at JIT time, to be Irrm_NEAREST,
5424 since -- at least for Altivec FP add/sub/mul -- the
5425 emitted insn is hardwired to round to nearest. */
5426 set_FPU_rounding_mode(env, triop->arg1, IEndianess);
5427 addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
5428 return dst;
5429 }
5430
5431 default:
5432 break;
5433 } /* switch (e->Iex.Triop.op) */
5434 } /* if (e->tag == Iex_Trinop) */
5435
5436
5437 if (e->tag == Iex_Const ) {
5438 vassert(e->Iex.Const.con->tag == Ico_V128);
5439 if (e->Iex.Const.con->Ico.V128 == 0x0000) {
5440 return generate_zeroes_V128(env);
5441 }
5442 else if (e->Iex.Const.con->Ico.V128 == 0xffff) {
5443 return generate_ones_V128(env);
5444 }
5445 }
5446
5447 vex_printf("iselVecExpr(ppc) (subarch = %s): can't reduce\n",
5448 LibVEX_ppVexHwCaps(mode64 ? VexArchPPC64 : VexArchPPC32,
5449 env->hwcaps));
5450 ppIRExpr(e);
5451 vpanic("iselVecExpr_wrk(ppc)");
5452 }
5453
5454
5455 /*---------------------------------------------------------*/
5456 /*--- ISEL: Statements ---*/
5457 /*---------------------------------------------------------*/
5458
iselStmt(ISelEnv * env,IRStmt * stmt,IREndness IEndianess)5459 static void iselStmt ( ISelEnv* env, IRStmt* stmt, IREndness IEndianess )
5460 {
5461 Bool mode64 = env->mode64;
5462 if (vex_traceflags & VEX_TRACE_VCODE) {
5463 vex_printf("\n -- ");
5464 ppIRStmt(stmt);
5465 vex_printf("\n");
5466 }
5467
5468 switch (stmt->tag) {
5469
5470 /* --------- STORE --------- */
5471 case Ist_Store: {
5472 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
5473 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
5474 IREndness end = stmt->Ist.Store.end;
5475
5476 if (end != IEndianess)
5477 goto stmt_fail;
5478 if (!mode64 && (tya != Ity_I32))
5479 goto stmt_fail;
5480 if (mode64 && (tya != Ity_I64))
5481 goto stmt_fail;
5482
5483 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
5484 (mode64 && (tyd == Ity_I64))) {
5485 PPCAMode* am_addr
5486 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5487 IEndianess);
5488 HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data, IEndianess);
5489 addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(tyd)),
5490 am_addr, r_src, mode64 ));
5491 return;
5492 }
5493 if (tyd == Ity_F64) {
5494 PPCAMode* am_addr
5495 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5496 IEndianess);
5497 HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data, IEndianess);
5498 addInstr(env,
5499 PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
5500 return;
5501 }
5502 if (tyd == Ity_F32) {
5503 PPCAMode* am_addr
5504 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5505 IEndianess);
5506 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data, IEndianess);
5507 addInstr(env,
5508 PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
5509 return;
5510 }
5511 if (tyd == Ity_D64) {
5512 PPCAMode* am_addr
5513 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5514 IEndianess);
5515 HReg fr_src = iselDfp64Expr(env, stmt->Ist.Store.data, IEndianess);
5516 addInstr(env,
5517 PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
5518 return;
5519 }
5520 if (tyd == Ity_D32) {
5521 PPCAMode* am_addr
5522 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5523 IEndianess);
5524 HReg fr_src = iselDfp32Expr(env, stmt->Ist.Store.data, IEndianess);
5525 addInstr(env,
5526 PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
5527 return;
5528 }
5529 if (tyd == Ity_V128) {
5530 PPCAMode* am_addr
5531 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5532 IEndianess);
5533 HReg v_src = iselVecExpr(env, stmt->Ist.Store.data, IEndianess);
5534 addInstr(env,
5535 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
5536 return;
5537 }
5538 if (tyd == Ity_I64 && !mode64) {
5539 /* Just calculate the address in the register. Life is too
5540 short to arse around trying and possibly failing to adjust
5541 the offset in a 'reg+offset' style amode. */
5542 HReg rHi32, rLo32;
5543 HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr, IEndianess);
5544 iselInt64Expr( &rHi32, &rLo32, env, stmt->Ist.Store.data,
5545 IEndianess );
5546 addInstr(env, PPCInstr_Store( 4/*byte-store*/,
5547 PPCAMode_IR( 0, r_addr ),
5548 rHi32,
5549 False/*32-bit insn please*/) );
5550 addInstr(env, PPCInstr_Store( 4/*byte-store*/,
5551 PPCAMode_IR( 4, r_addr ),
5552 rLo32,
5553 False/*32-bit insn please*/) );
5554 return;
5555 }
5556 break;
5557 }
5558
5559 /* --------- PUT --------- */
5560 case Ist_Put: {
5561 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
5562 if (ty == Ity_I8 || ty == Ity_I16 ||
5563 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
5564 HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data, IEndianess);
5565 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5566 GuestStatePtr(mode64) );
5567 addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(ty)),
5568 am_addr, r_src, mode64 ));
5569 return;
5570 }
5571 if (!mode64 && ty == Ity_I64) {
5572 HReg rHi, rLo;
5573 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5574 GuestStatePtr(mode64) );
5575 PPCAMode* am_addr4 = advance4(env, am_addr);
5576 iselInt64Expr(&rHi,&rLo, env, stmt->Ist.Put.data, IEndianess);
5577 addInstr(env, PPCInstr_Store( 4, am_addr, rHi, mode64 ));
5578 addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 ));
5579 return;
5580 }
5581 if (ty == Ity_V128) {
5582 /* Guest state vectors are 16byte aligned,
5583 so don't need to worry here */
5584 HReg v_src = iselVecExpr(env, stmt->Ist.Put.data, IEndianess);
5585 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5586 GuestStatePtr(mode64) );
5587 addInstr(env,
5588 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
5589 return;
5590 }
5591 if (ty == Ity_F64) {
5592 HReg fr_src = iselDblExpr(env, stmt->Ist.Put.data, IEndianess);
5593 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5594 GuestStatePtr(mode64) );
5595 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
5596 fr_src, am_addr ));
5597 return;
5598 }
5599 if (ty == Ity_D32) {
5600 /* The 32-bit value is stored in a 64-bit register */
5601 HReg fr_src = iselDfp32Expr( env, stmt->Ist.Put.data, IEndianess );
5602 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5603 GuestStatePtr(mode64) );
5604 addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8,
5605 fr_src, am_addr ) );
5606 return;
5607 }
5608 if (ty == Ity_D64) {
5609 HReg fr_src = iselDfp64Expr( env, stmt->Ist.Put.data, IEndianess );
5610 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5611 GuestStatePtr(mode64) );
5612 addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8, fr_src, am_addr ) );
5613 return;
5614 }
5615 break;
5616 }
5617
5618 /* --------- Indexed PUT --------- */
5619 case Ist_PutI: {
5620 IRPutI *puti = stmt->Ist.PutI.details;
5621
5622 PPCAMode* dst_am
5623 = genGuestArrayOffset(
5624 env, puti->descr,
5625 puti->ix, puti->bias,
5626 IEndianess );
5627 IRType ty = typeOfIRExpr(env->type_env, puti->data);
5628 if (mode64 && ty == Ity_I64) {
5629 HReg r_src = iselWordExpr_R(env, puti->data, IEndianess);
5630 addInstr(env, PPCInstr_Store( toUChar(8),
5631 dst_am, r_src, mode64 ));
5632 return;
5633 }
5634 if ((!mode64) && ty == Ity_I32) {
5635 HReg r_src = iselWordExpr_R(env, puti->data, IEndianess);
5636 addInstr(env, PPCInstr_Store( toUChar(4),
5637 dst_am, r_src, mode64 ));
5638 return;
5639 }
5640 break;
5641 }
5642
5643 /* --------- TMP --------- */
5644 case Ist_WrTmp: {
5645 IRTemp tmp = stmt->Ist.WrTmp.tmp;
5646 IRType ty = typeOfIRTemp(env->type_env, tmp);
5647 if (ty == Ity_I8 || ty == Ity_I16 ||
5648 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
5649 HReg r_dst = lookupIRTemp(env, tmp);
5650 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data, IEndianess);
5651 addInstr(env, mk_iMOVds_RR( r_dst, r_src ));
5652 return;
5653 }
5654 if (!mode64 && ty == Ity_I64) {
5655 HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
5656
5657 iselInt64Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data,
5658 IEndianess);
5659 lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
5660 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
5661 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
5662 return;
5663 }
5664 if (mode64 && ty == Ity_I128) {
5665 HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
5666 iselInt128Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data,
5667 IEndianess);
5668 lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
5669 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
5670 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
5671 return;
5672 }
5673 if (!mode64 && ty == Ity_I128) {
5674 HReg r_srcHi, r_srcMedHi, r_srcMedLo, r_srcLo;
5675 HReg r_dstHi, r_dstMedHi, r_dstMedLo, r_dstLo;
5676
5677 iselInt128Expr_to_32x4(&r_srcHi, &r_srcMedHi,
5678 &r_srcMedLo, &r_srcLo,
5679 env, stmt->Ist.WrTmp.data, IEndianess);
5680
5681 lookupIRTempQuad( &r_dstHi, &r_dstMedHi, &r_dstMedLo,
5682 &r_dstLo, env, tmp);
5683
5684 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
5685 addInstr(env, mk_iMOVds_RR(r_dstMedHi, r_srcMedHi) );
5686 addInstr(env, mk_iMOVds_RR(r_dstMedLo, r_srcMedLo) );
5687 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
5688 return;
5689 }
5690 if (ty == Ity_I1) {
5691 PPCCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data,
5692 IEndianess);
5693 HReg r_dst = lookupIRTemp(env, tmp);
5694 addInstr(env, PPCInstr_Set(cond, r_dst));
5695 return;
5696 }
5697 if (ty == Ity_F64) {
5698 HReg fr_dst = lookupIRTemp(env, tmp);
5699 HReg fr_src = iselDblExpr(env, stmt->Ist.WrTmp.data, IEndianess);
5700 addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
5701 return;
5702 }
5703 if (ty == Ity_F32) {
5704 HReg fr_dst = lookupIRTemp(env, tmp);
5705 HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data, IEndianess);
5706 addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
5707 return;
5708 }
5709 if (ty == Ity_D32) {
5710 HReg fr_dst = lookupIRTemp(env, tmp);
5711 HReg fr_src = iselDfp32Expr(env, stmt->Ist.WrTmp.data, IEndianess);
5712 addInstr(env, PPCInstr_Dfp64Unary(Pfp_MOV, fr_dst, fr_src));
5713 return;
5714 }
5715 if (ty == Ity_V128) {
5716 HReg v_dst = lookupIRTemp(env, tmp);
5717 HReg v_src = iselVecExpr(env, stmt->Ist.WrTmp.data, IEndianess);
5718 addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src));
5719 return;
5720 }
5721 if (ty == Ity_D64) {
5722 HReg fr_dst = lookupIRTemp( env, tmp );
5723 HReg fr_src = iselDfp64Expr( env, stmt->Ist.WrTmp.data, IEndianess );
5724 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dst, fr_src ) );
5725 return;
5726 }
5727 if (ty == Ity_D128) {
5728 HReg fr_srcHi, fr_srcLo, fr_dstHi, fr_dstLo;
5729 // lookupDfp128IRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
5730 lookupIRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
5731 iselDfp128Expr( &fr_srcHi, &fr_srcLo, env, stmt->Ist.WrTmp.data,
5732 IEndianess );
5733 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstHi, fr_srcHi ) );
5734 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstLo, fr_srcLo ) );
5735 return;
5736 }
5737 break;
5738 }
5739
5740 /* --------- Load Linked or Store Conditional --------- */
5741 case Ist_LLSC: {
5742 IRTemp res = stmt->Ist.LLSC.result;
5743 IRType tyRes = typeOfIRTemp(env->type_env, res);
5744 IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
5745
5746 if (stmt->Ist.LLSC.end != IEndianess)
5747 goto stmt_fail;
5748 if (!mode64 && (tyAddr != Ity_I32))
5749 goto stmt_fail;
5750 if (mode64 && (tyAddr != Ity_I64))
5751 goto stmt_fail;
5752
5753 if (stmt->Ist.LLSC.storedata == NULL) {
5754 /* LL */
5755 HReg r_addr = iselWordExpr_R( env, stmt->Ist.LLSC.addr, IEndianess );
5756 HReg r_dst = lookupIRTemp(env, res);
5757 if (tyRes == Ity_I8) {
5758 addInstr(env, PPCInstr_LoadL( 1, r_dst, r_addr, mode64 ));
5759 return;
5760 }
5761 if (tyRes == Ity_I16) {
5762 addInstr(env, PPCInstr_LoadL( 2, r_dst, r_addr, mode64 ));
5763 return;
5764 }
5765 if (tyRes == Ity_I32) {
5766 addInstr(env, PPCInstr_LoadL( 4, r_dst, r_addr, mode64 ));
5767 return;
5768 }
5769 if (tyRes == Ity_I64 && mode64) {
5770 addInstr(env, PPCInstr_LoadL( 8, r_dst, r_addr, mode64 ));
5771 return;
5772 }
5773 /* fallthru */;
5774 } else {
5775 /* SC */
5776 HReg r_res = lookupIRTemp(env, res); /* :: Ity_I1 */
5777 HReg r_a = iselWordExpr_R(env, stmt->Ist.LLSC.addr, IEndianess);
5778 HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata,
5779 IEndianess);
5780 HReg r_tmp = newVRegI(env);
5781 IRType tyData = typeOfIRExpr(env->type_env,
5782 stmt->Ist.LLSC.storedata);
5783 vassert(tyRes == Ity_I1);
5784 if (tyData == Ity_I8 || tyData == Ity_I16 || tyData == Ity_I32 ||
5785 (tyData == Ity_I64 && mode64)) {
5786 int size = 0;
5787
5788 if (tyData == Ity_I64)
5789 size = 8;
5790 else if (tyData == Ity_I32)
5791 size = 4;
5792 else if (tyData == Ity_I16)
5793 size = 2;
5794 else if (tyData == Ity_I8)
5795 size = 1;
5796
5797 addInstr(env, PPCInstr_StoreC( size,
5798 r_a, r_src, mode64 ));
5799 addInstr(env, PPCInstr_MfCR( r_tmp ));
5800 addInstr(env, PPCInstr_Shft(
5801 Pshft_SHR,
5802 env->mode64 ? False : True
5803 /*F:64-bit, T:32-bit shift*/,
5804 r_tmp, r_tmp,
5805 PPCRH_Imm(False/*unsigned*/, 29)));
5806 /* Probably unnecessary, since the IR dest type is Ity_I1,
5807 and so we are entitled to leave whatever junk we like
5808 drifting round in the upper 31 or 63 bits of r_res.
5809 However, for the sake of conservativeness .. */
5810 addInstr(env, PPCInstr_Alu(
5811 Palu_AND,
5812 r_res, r_tmp,
5813 PPCRH_Imm(False/*signed*/, 1)));
5814 return;
5815 }
5816 /* fallthru */
5817 }
5818 goto stmt_fail;
5819 /*NOTREACHED*/
5820 }
5821
5822 /* --------- Call to DIRTY helper --------- */
5823 case Ist_Dirty: {
5824 IRDirty* d = stmt->Ist.Dirty.details;
5825
5826 /* Figure out the return type, if any. */
5827 IRType retty = Ity_INVALID;
5828 if (d->tmp != IRTemp_INVALID)
5829 retty = typeOfIRTemp(env->type_env, d->tmp);
5830
5831 /* Throw out any return types we don't know about. The set of
5832 acceptable return types is the same in both 32- and 64-bit
5833 mode, so we don't need to inspect mode64 to make a
5834 decision. */
5835 Bool retty_ok = False;
5836 switch (retty) {
5837 case Ity_INVALID: /* function doesn't return anything */
5838 case Ity_V128:
5839 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
5840 retty_ok = True; break;
5841 default:
5842 break;
5843 }
5844 if (!retty_ok)
5845 break; /* will go to stmt_fail: */
5846
5847 /* Marshal args, do the call, clear stack, set the return value
5848 to 0x555..555 if this is a conditional call that returns a
5849 value and the call is skipped. */
5850 UInt addToSp = 0;
5851 RetLoc rloc = mk_RetLoc_INVALID();
5852 doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args,
5853 IEndianess );
5854 vassert(is_sane_RetLoc(rloc));
5855
5856 /* Now figure out what to do with the returned value, if any. */
5857 switch (retty) {
5858 case Ity_INVALID: {
5859 /* No return value. Nothing to do. */
5860 vassert(d->tmp == IRTemp_INVALID);
5861 vassert(rloc.pri == RLPri_None);
5862 vassert(addToSp == 0);
5863 return;
5864 }
5865 case Ity_I32: case Ity_I16: case Ity_I8: {
5866 /* The returned value is in %r3. Park it in the register
5867 associated with tmp. */
5868 HReg r_dst = lookupIRTemp(env, d->tmp);
5869 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
5870 vassert(rloc.pri == RLPri_Int);
5871 vassert(addToSp == 0);
5872 return;
5873 }
5874 case Ity_I64:
5875 if (mode64) {
5876 /* The returned value is in %r3. Park it in the register
5877 associated with tmp. */
5878 HReg r_dst = lookupIRTemp(env, d->tmp);
5879 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
5880 vassert(rloc.pri == RLPri_Int);
5881 vassert(addToSp == 0);
5882 } else {
5883 /* The returned value is in %r3:%r4. Park it in the
5884 register-pair associated with tmp. */
5885 HReg r_dstHi = INVALID_HREG;
5886 HReg r_dstLo = INVALID_HREG;
5887 lookupIRTempPair( &r_dstHi, &r_dstLo, env, d->tmp);
5888 addInstr(env, mk_iMOVds_RR(r_dstHi, hregPPC_GPR3(mode64)));
5889 addInstr(env, mk_iMOVds_RR(r_dstLo, hregPPC_GPR4(mode64)));
5890 vassert(rloc.pri == RLPri_2Int);
5891 vassert(addToSp == 0);
5892 }
5893 return;
5894 case Ity_V128: {
5895 /* The returned value is on the stack, and *retloc tells
5896 us where. Fish it off the stack and then move the
5897 stack pointer upwards to clear it, as directed by
5898 doHelperCall. */
5899 vassert(rloc.pri == RLPri_V128SpRel);
5900 vassert(addToSp >= 16);
5901 HReg dst = lookupIRTemp(env, d->tmp);
5902 PPCAMode* am = PPCAMode_IR(rloc.spOff, StackFramePtr(mode64));
5903 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, dst, am ));
5904 add_to_sp(env, addToSp);
5905 return;
5906 }
5907 default:
5908 /*NOTREACHED*/
5909 vassert(0);
5910 }
5911 }
5912
5913 /* --------- MEM FENCE --------- */
5914 case Ist_MBE:
5915 switch (stmt->Ist.MBE.event) {
5916 case Imbe_Fence:
5917 addInstr(env, PPCInstr_MFence());
5918 return;
5919 default:
5920 break;
5921 }
5922 break;
5923
5924 /* --------- INSTR MARK --------- */
5925 /* Doesn't generate any executable code ... */
5926 case Ist_IMark:
5927 return;
5928
5929 /* --------- ABI HINT --------- */
5930 /* These have no meaning (denotation in the IR) and so we ignore
5931 them ... if any actually made it this far. */
5932 case Ist_AbiHint:
5933 return;
5934
5935 /* --------- NO-OP --------- */
5936 /* Fairly self-explanatory, wouldn't you say? */
5937 case Ist_NoOp:
5938 return;
5939
5940 /* --------- EXIT --------- */
5941 case Ist_Exit: {
5942 IRConst* dst = stmt->Ist.Exit.dst;
5943 if (!mode64 && dst->tag != Ico_U32)
5944 vpanic("iselStmt(ppc): Ist_Exit: dst is not a 32-bit value");
5945 if (mode64 && dst->tag != Ico_U64)
5946 vpanic("iselStmt(ppc64): Ist_Exit: dst is not a 64-bit value");
5947
5948 PPCCondCode cc = iselCondCode(env, stmt->Ist.Exit.guard, IEndianess);
5949 PPCAMode* amCIA = PPCAMode_IR(stmt->Ist.Exit.offsIP,
5950 hregPPC_GPR31(mode64));
5951
5952 /* Case: boring transfer to known address */
5953 if (stmt->Ist.Exit.jk == Ijk_Boring
5954 || stmt->Ist.Exit.jk == Ijk_Call
5955 /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
5956 if (env->chainingAllowed) {
5957 /* .. almost always true .. */
5958 /* Skip the event check at the dst if this is a forwards
5959 edge. */
5960 Bool toFastEP
5961 = mode64
5962 ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga)
5963 : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga);
5964 if (0) vex_printf("%s", toFastEP ? "Y" : ",");
5965 addInstr(env, PPCInstr_XDirect(
5966 mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64
5967 : (Addr64)stmt->Ist.Exit.dst->Ico.U32,
5968 amCIA, cc, toFastEP));
5969 } else {
5970 /* .. very occasionally .. */
5971 /* We can't use chaining, so ask for an assisted transfer,
5972 as that's the only alternative that is allowable. */
5973 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst),
5974 IEndianess);
5975 addInstr(env, PPCInstr_XAssisted(r, amCIA, cc, Ijk_Boring));
5976 }
5977 return;
5978 }
5979
5980 /* Case: assisted transfer to arbitrary address */
5981 switch (stmt->Ist.Exit.jk) {
5982 /* Keep this list in sync with that in iselNext below */
5983 case Ijk_ClientReq:
5984 case Ijk_EmFail:
5985 case Ijk_EmWarn:
5986 case Ijk_NoDecode:
5987 case Ijk_NoRedir:
5988 case Ijk_SigBUS:
5989 case Ijk_SigTRAP:
5990 case Ijk_Sys_syscall:
5991 case Ijk_InvalICache:
5992 {
5993 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst),
5994 IEndianess);
5995 addInstr(env, PPCInstr_XAssisted(r, amCIA, cc,
5996 stmt->Ist.Exit.jk));
5997 return;
5998 }
5999 default:
6000 break;
6001 }
6002
6003 /* Do we ever expect to see any other kind? */
6004 goto stmt_fail;
6005 }
6006
6007 default: break;
6008 }
6009 stmt_fail:
6010 ppIRStmt(stmt);
6011 vpanic("iselStmt(ppc)");
6012 }
6013
6014
6015 /*---------------------------------------------------------*/
6016 /*--- ISEL: Basic block terminators (Nexts) ---*/
6017 /*---------------------------------------------------------*/
6018
iselNext(ISelEnv * env,IRExpr * next,IRJumpKind jk,Int offsIP,IREndness IEndianess)6019 static void iselNext ( ISelEnv* env,
6020 IRExpr* next, IRJumpKind jk, Int offsIP,
6021 IREndness IEndianess)
6022 {
6023 if (vex_traceflags & VEX_TRACE_VCODE) {
6024 vex_printf( "\n-- PUT(%d) = ", offsIP);
6025 ppIRExpr( next );
6026 vex_printf( "; exit-");
6027 ppIRJumpKind(jk);
6028 vex_printf( "\n");
6029 }
6030
6031 PPCCondCode always = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
6032
6033 /* Case: boring transfer to known address */
6034 if (next->tag == Iex_Const) {
6035 IRConst* cdst = next->Iex.Const.con;
6036 vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32));
6037 if (jk == Ijk_Boring || jk == Ijk_Call) {
6038 /* Boring transfer to known address */
6039 PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6040 if (env->chainingAllowed) {
6041 /* .. almost always true .. */
6042 /* Skip the event check at the dst if this is a forwards
6043 edge. */
6044 Bool toFastEP
6045 = env->mode64
6046 ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga)
6047 : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga);
6048 if (0) vex_printf("%s", toFastEP ? "X" : ".");
6049 addInstr(env, PPCInstr_XDirect(
6050 env->mode64 ? (Addr64)cdst->Ico.U64
6051 : (Addr64)cdst->Ico.U32,
6052 amCIA, always, toFastEP));
6053 } else {
6054 /* .. very occasionally .. */
6055 /* We can't use chaining, so ask for an assisted transfer,
6056 as that's the only alternative that is allowable. */
6057 HReg r = iselWordExpr_R(env, next, IEndianess);
6058 addInstr(env, PPCInstr_XAssisted(r, amCIA, always,
6059 Ijk_Boring));
6060 }
6061 return;
6062 }
6063 }
6064
6065 /* Case: call/return (==boring) transfer to any address */
6066 switch (jk) {
6067 case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
6068 HReg r = iselWordExpr_R(env, next, IEndianess);
6069 PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6070 if (env->chainingAllowed) {
6071 addInstr(env, PPCInstr_XIndir(r, amCIA, always));
6072 } else {
6073 addInstr(env, PPCInstr_XAssisted(r, amCIA, always,
6074 Ijk_Boring));
6075 }
6076 return;
6077 }
6078 default:
6079 break;
6080 }
6081
6082 /* Case: assisted transfer to arbitrary address */
6083 switch (jk) {
6084 /* Keep this list in sync with that for Ist_Exit above */
6085 case Ijk_ClientReq:
6086 case Ijk_EmFail:
6087 case Ijk_EmWarn:
6088 case Ijk_NoDecode:
6089 case Ijk_NoRedir:
6090 case Ijk_SigBUS:
6091 case Ijk_SigTRAP:
6092 case Ijk_Sys_syscall:
6093 case Ijk_InvalICache:
6094 {
6095 HReg r = iselWordExpr_R(env, next, IEndianess);
6096 PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6097 addInstr(env, PPCInstr_XAssisted(r, amCIA, always, jk));
6098 return;
6099 }
6100 default:
6101 break;
6102 }
6103
6104 vex_printf( "\n-- PUT(%d) = ", offsIP);
6105 ppIRExpr( next );
6106 vex_printf( "; exit-");
6107 ppIRJumpKind(jk);
6108 vex_printf( "\n");
6109 vassert(0); // are we expecting any other kind?
6110 }
6111
6112
6113 /*---------------------------------------------------------*/
6114 /*--- Insn selector top-level ---*/
6115 /*---------------------------------------------------------*/
6116
6117 /* Translate an entire SB to ppc code. */
iselSB_PPC(const IRSB * bb,VexArch arch_host,const VexArchInfo * archinfo_host,const VexAbiInfo * vbi,Int offs_Host_EvC_Counter,Int offs_Host_EvC_FailAddr,Bool chainingAllowed,Bool addProfInc,Addr max_ga)6118 HInstrArray* iselSB_PPC ( const IRSB* bb,
6119 VexArch arch_host,
6120 const VexArchInfo* archinfo_host,
6121 const VexAbiInfo* vbi,
6122 Int offs_Host_EvC_Counter,
6123 Int offs_Host_EvC_FailAddr,
6124 Bool chainingAllowed,
6125 Bool addProfInc,
6126 Addr max_ga)
6127
6128 {
6129 Int i, j;
6130 HReg hregLo, hregMedLo, hregMedHi, hregHi;
6131 ISelEnv* env;
6132 UInt hwcaps_host = archinfo_host->hwcaps;
6133 Bool mode64 = False;
6134 UInt mask32, mask64;
6135 PPCAMode *amCounter, *amFailAddr;
6136 IREndness IEndianess;
6137
6138 vassert(arch_host == VexArchPPC32 || arch_host == VexArchPPC64);
6139 mode64 = arch_host == VexArchPPC64;
6140
6141 /* do some sanity checks */
6142 mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
6143 | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX
6144 | VEX_HWCAPS_PPC32_DFP | VEX_HWCAPS_PPC32_ISA2_07;
6145
6146
6147 mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
6148 | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP
6149 | VEX_HWCAPS_PPC64_ISA2_07;
6150
6151 if (mode64) {
6152 vassert((hwcaps_host & mask32) == 0);
6153 } else {
6154 vassert((hwcaps_host & mask64) == 0);
6155 }
6156
6157 /* Check that the host's endianness is as expected. */
6158 vassert((archinfo_host->endness == VexEndnessBE) ||
6159 (archinfo_host->endness == VexEndnessLE));
6160
6161 if (archinfo_host->endness == VexEndnessBE)
6162 IEndianess = Iend_BE;
6163 else
6164 IEndianess = Iend_LE;
6165
6166 /* Make up an initial environment to use. */
6167 env = LibVEX_Alloc_inline(sizeof(ISelEnv));
6168 env->vreg_ctr = 0;
6169
6170 /* Are we being ppc32 or ppc64? */
6171 env->mode64 = mode64;
6172
6173 /* Set up output code array. */
6174 env->code = newHInstrArray();
6175
6176 /* Copy BB's type env. */
6177 env->type_env = bb->tyenv;
6178
6179 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
6180 * change as we go along.
6181 *
6182 * vregmap2 and vregmap3 are only used in 32 bit mode
6183 * for supporting I128 in 32-bit mode
6184 */
6185 env->n_vregmap = bb->tyenv->types_used;
6186 env->vregmapLo = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6187 env->vregmapMedLo = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6188 if (mode64) {
6189 env->vregmapMedHi = NULL;
6190 env->vregmapHi = NULL;
6191 } else {
6192 env->vregmapMedHi = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6193 env->vregmapHi = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6194 }
6195
6196 /* and finally ... */
6197 env->chainingAllowed = chainingAllowed;
6198 env->max_ga = max_ga;
6199 env->hwcaps = hwcaps_host;
6200 env->previous_rm = NULL;
6201 env->vbi = vbi;
6202
6203 /* For each IR temporary, allocate a suitably-kinded virtual
6204 register. */
6205 j = 0;
6206 for (i = 0; i < env->n_vregmap; i++) {
6207 hregLo = hregMedLo = hregMedHi = hregHi = INVALID_HREG;
6208 switch (bb->tyenv->types[i]) {
6209 case Ity_I1:
6210 case Ity_I8:
6211 case Ity_I16:
6212 case Ity_I32:
6213 if (mode64) {
6214 hregLo = mkHReg(True, HRcInt64, 0, j++);
6215 } else {
6216 hregLo = mkHReg(True, HRcInt32, 0, j++);
6217 }
6218 break;
6219 case Ity_I64:
6220 if (mode64) {
6221 hregLo = mkHReg(True, HRcInt64, 0, j++);
6222 } else {
6223 hregLo = mkHReg(True, HRcInt32, 0, j++);
6224 hregMedLo = mkHReg(True, HRcInt32, 0, j++);
6225 }
6226 break;
6227 case Ity_I128:
6228 if (mode64) {
6229 hregLo = mkHReg(True, HRcInt64, 0, j++);
6230 hregMedLo = mkHReg(True, HRcInt64, 0, j++);
6231 } else {
6232 hregLo = mkHReg(True, HRcInt32, 0, j++);
6233 hregMedLo = mkHReg(True, HRcInt32, 0, j++);
6234 hregMedHi = mkHReg(True, HRcInt32, 0, j++);
6235 hregHi = mkHReg(True, HRcInt32, 0, j++);
6236 }
6237 break;
6238 case Ity_F32:
6239 case Ity_F64:
6240 hregLo = mkHReg(True, HRcFlt64, 0, j++);
6241 break;
6242 case Ity_V128:
6243 hregLo = mkHReg(True, HRcVec128, 0, j++);
6244 break;
6245 case Ity_D32:
6246 case Ity_D64:
6247 hregLo = mkHReg(True, HRcFlt64, 0, j++);
6248 break;
6249 case Ity_D128:
6250 hregLo = mkHReg(True, HRcFlt64, 0, j++);
6251 hregMedLo = mkHReg(True, HRcFlt64, 0, j++);
6252 break;
6253 default:
6254 ppIRType(bb->tyenv->types[i]);
6255 vpanic("iselBB(ppc): IRTemp type");
6256 }
6257 env->vregmapLo[i] = hregLo;
6258 env->vregmapMedLo[i] = hregMedLo;
6259 if (!mode64) {
6260 env->vregmapMedHi[i] = hregMedHi;
6261 env->vregmapHi[i] = hregHi;
6262 }
6263 }
6264 env->vreg_ctr = j;
6265
6266 /* The very first instruction must be an event check. */
6267 amCounter = PPCAMode_IR(offs_Host_EvC_Counter, hregPPC_GPR31(mode64));
6268 amFailAddr = PPCAMode_IR(offs_Host_EvC_FailAddr, hregPPC_GPR31(mode64));
6269 addInstr(env, PPCInstr_EvCheck(amCounter, amFailAddr));
6270
6271 /* Possibly a block counter increment (for profiling). At this
6272 point we don't know the address of the counter, so just pretend
6273 it is zero. It will have to be patched later, but before this
6274 translation is used, by a call to LibVEX_patchProfCtr. */
6275 if (addProfInc) {
6276 addInstr(env, PPCInstr_ProfInc());
6277 }
6278
6279 /* Ok, finally we can iterate over the statements. */
6280 for (i = 0; i < bb->stmts_used; i++)
6281 iselStmt(env, bb->stmts[i], IEndianess);
6282
6283 iselNext(env, bb->next, bb->jumpkind, bb->offsIP, IEndianess);
6284
6285 /* record the number of vregs we used. */
6286 env->code->n_vregs = env->vreg_ctr;
6287 return env->code;
6288 }
6289
6290
6291 /*---------------------------------------------------------------*/
6292 /*--- end host_ppc_isel.c ---*/
6293 /*---------------------------------------------------------------*/
6294