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-2015 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 UInt v = u & 0xFFFF;
2479
2480 v = (Int)(v << 16) >> 16; /* sign extend */
2481
2482 return u == v;
2483 }
2484
uLong_fits_in_16_bits(ULong u)2485 static Bool uLong_fits_in_16_bits ( ULong u )
2486 {
2487 /* Is u the same as the sign-extend of its lower 16 bits? */
2488 ULong v = u & 0xFFFFULL;
2489
2490 v = (Long)(v << 48) >> 48; /* sign extend */
2491
2492 return u == v;
2493 }
2494
uLong_is_4_aligned(ULong u)2495 static Bool uLong_is_4_aligned ( ULong u )
2496 {
2497 return toBool((u & 3ULL) == 0);
2498 }
2499
sane_AMode(ISelEnv * env,PPCAMode * am)2500 static Bool sane_AMode ( ISelEnv* env, PPCAMode* am )
2501 {
2502 Bool mode64 = env->mode64;
2503 switch (am->tag) {
2504 case Pam_IR:
2505 /* Using uInt_fits_in_16_bits in 64-bit mode seems a bit bogus,
2506 somehow, but I think it's OK. */
2507 return toBool( hregClass(am->Pam.IR.base) == HRcGPR(mode64) &&
2508 hregIsVirtual(am->Pam.IR.base) &&
2509 uInt_fits_in_16_bits(am->Pam.IR.index) );
2510 case Pam_RR:
2511 return toBool( hregClass(am->Pam.RR.base) == HRcGPR(mode64) &&
2512 hregIsVirtual(am->Pam.RR.base) &&
2513 hregClass(am->Pam.RR.index) == HRcGPR(mode64) &&
2514 hregIsVirtual(am->Pam.RR.index) );
2515 default:
2516 vpanic("sane_AMode: unknown ppc amode tag");
2517 }
2518 }
2519
2520 static
iselWordExpr_AMode(ISelEnv * env,IRExpr * e,IRType xferTy,IREndness IEndianess)2521 PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy,
2522 IREndness IEndianess )
2523 {
2524 PPCAMode* am = iselWordExpr_AMode_wrk(env, e, xferTy, IEndianess);
2525 vassert(sane_AMode(env, am));
2526 return am;
2527 }
2528
2529 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_AMode_wrk(ISelEnv * env,IRExpr * e,IRType xferTy,IREndness IEndianess)2530 static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e,
2531 IRType xferTy, IREndness IEndianess )
2532 {
2533 IRType ty = typeOfIRExpr(env->type_env,e);
2534
2535 if (env->mode64) {
2536
2537 /* If the data load/store type is I32 or I64, this amode might
2538 be destined for use in ld/ldu/lwa/st/stu. In which case
2539 insist that if it comes out as an _IR, the immediate must
2540 have its bottom two bits be zero. This does assume that for
2541 any other type (I8/I16/I128/F32/F64/V128) the amode will not
2542 be parked in any such instruction. But that seems a
2543 reasonable assumption. */
2544 Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
2545
2546 vassert(ty == Ity_I64);
2547
2548 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
2549 if (e->tag == Iex_Binop
2550 && e->Iex.Binop.op == Iop_Add64
2551 && e->Iex.Binop.arg2->tag == Iex_Const
2552 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
2553 && (aligned4imm ? uLong_is_4_aligned(e->Iex.Binop.arg2
2554 ->Iex.Const.con->Ico.U64)
2555 : True)
2556 && uLong_fits_in_16_bits(e->Iex.Binop.arg2
2557 ->Iex.Const.con->Ico.U64)) {
2558 return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
2559 iselWordExpr_R(env, e->Iex.Binop.arg1,
2560 IEndianess) );
2561 }
2562
2563 /* Add64(expr,expr) */
2564 if (e->tag == Iex_Binop
2565 && e->Iex.Binop.op == Iop_Add64) {
2566 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2567 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
2568 return PPCAMode_RR( r_idx, r_base );
2569 }
2570
2571 } else {
2572
2573 vassert(ty == Ity_I32);
2574
2575 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
2576 if (e->tag == Iex_Binop
2577 && e->Iex.Binop.op == Iop_Add32
2578 && e->Iex.Binop.arg2->tag == Iex_Const
2579 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
2580 && uInt_fits_in_16_bits(e->Iex.Binop.arg2
2581 ->Iex.Const.con->Ico.U32)) {
2582 return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
2583 iselWordExpr_R(env, e->Iex.Binop.arg1,
2584 IEndianess) );
2585 }
2586
2587 /* Add32(expr,expr) */
2588 if (e->tag == Iex_Binop
2589 && e->Iex.Binop.op == Iop_Add32) {
2590 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2591 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
2592 return PPCAMode_RR( r_idx, r_base );
2593 }
2594
2595 }
2596
2597 /* Doesn't match anything in particular. Generate it into
2598 a register and use that. */
2599 return PPCAMode_IR( 0, iselWordExpr_R(env,e,IEndianess) );
2600 }
2601
2602
2603 /* --------------------- RH --------------------- */
2604
2605 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
2606 (reg-or-halfword-immediate). It's important to specify whether the
2607 immediate is to be regarded as signed or not. If yes, this will
2608 never return -32768 as an immediate; this guaranteed that all
2609 signed immediates that are return can have their sign inverted if
2610 need be. */
2611
iselWordExpr_RH(ISelEnv * env,Bool syned,IRExpr * e,IREndness IEndianess)2612 static PPCRH* iselWordExpr_RH ( ISelEnv* env, Bool syned, IRExpr* e,
2613 IREndness IEndianess )
2614 {
2615 PPCRH* ri = iselWordExpr_RH_wrk(env, syned, e, IEndianess);
2616 /* sanity checks ... */
2617 switch (ri->tag) {
2618 case Prh_Imm:
2619 vassert(ri->Prh.Imm.syned == syned);
2620 if (syned)
2621 vassert(ri->Prh.Imm.imm16 != 0x8000);
2622 return ri;
2623 case Prh_Reg:
2624 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2625 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2626 return ri;
2627 default:
2628 vpanic("iselIntExpr_RH: unknown ppc RH tag");
2629 }
2630 }
2631
2632 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH_wrk(ISelEnv * env,Bool syned,IRExpr * e,IREndness IEndianess)2633 static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, Bool syned, IRExpr* e,
2634 IREndness IEndianess )
2635 {
2636 ULong u;
2637 Long l;
2638 IRType ty = typeOfIRExpr(env->type_env,e);
2639 vassert(ty == Ity_I8 || ty == Ity_I16 ||
2640 ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2641
2642 /* special case: immediate */
2643 if (e->tag == Iex_Const) {
2644 IRConst* con = e->Iex.Const.con;
2645 /* What value are we aiming to generate? */
2646 switch (con->tag) {
2647 /* Note: Not sign-extending - we carry 'syned' around */
2648 case Ico_U64: vassert(env->mode64);
2649 u = con->Ico.U64; break;
2650 case Ico_U32: u = 0xFFFFFFFF & con->Ico.U32; break;
2651 case Ico_U16: u = 0x0000FFFF & con->Ico.U16; break;
2652 case Ico_U8: u = 0x000000FF & con->Ico.U8; break;
2653 default: vpanic("iselIntExpr_RH.Iex_Const(ppch)");
2654 }
2655 l = (Long)u;
2656 /* Now figure out if it's representable. */
2657 if (!syned && u <= 65535) {
2658 return PPCRH_Imm(False/*unsigned*/, toUShort(u & 0xFFFF));
2659 }
2660 if (syned && l >= -32767 && l <= 32767) {
2661 return PPCRH_Imm(True/*signed*/, toUShort(u & 0xFFFF));
2662 }
2663 /* no luck; use the Slow Way. */
2664 }
2665
2666 /* default case: calculate into a register and return that */
2667 return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2668 }
2669
2670
2671 /* --------------------- RIs --------------------- */
2672
2673 /* Calculate an expression into an PPCRI operand. As with
2674 iselIntExpr_R, the expression can have type 32, 16 or 8 bits, or,
2675 in 64-bit mode, 64 bits. */
2676
iselWordExpr_RI(ISelEnv * env,IRExpr * e,IREndness IEndianess)2677 static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
2678 {
2679 PPCRI* ri = iselWordExpr_RI_wrk(env, e, IEndianess);
2680 /* sanity checks ... */
2681 switch (ri->tag) {
2682 case Pri_Imm:
2683 return ri;
2684 case Pri_Reg:
2685 vassert(hregClass(ri->Pri.Reg) == HRcGPR(env->mode64));
2686 vassert(hregIsVirtual(ri->Pri.Reg));
2687 return ri;
2688 default:
2689 vpanic("iselIntExpr_RI: unknown ppc RI tag");
2690 }
2691 }
2692
2693 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RI_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2694 static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e,
2695 IREndness IEndianess )
2696 {
2697 Long l;
2698 IRType ty = typeOfIRExpr(env->type_env,e);
2699 vassert(ty == Ity_I8 || ty == Ity_I16 ||
2700 ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2701
2702 /* special case: immediate */
2703 if (e->tag == Iex_Const) {
2704 IRConst* con = e->Iex.Const.con;
2705 switch (con->tag) {
2706 case Ico_U64: vassert(env->mode64);
2707 l = (Long) con->Ico.U64; break;
2708 case Ico_U32: l = (Long)(Int) con->Ico.U32; break;
2709 case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
2710 case Ico_U8: l = (Long)(Int)(Char )con->Ico.U8; break;
2711 default: vpanic("iselIntExpr_RI.Iex_Const(ppch)");
2712 }
2713 return PPCRI_Imm((ULong)l);
2714 }
2715
2716 /* default case: calculate into a register and return that */
2717 return PPCRI_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2718 }
2719
2720
2721 /* --------------------- RH5u --------------------- */
2722
2723 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
2724 being an immediate in the range 1 .. 31 inclusive. Used for doing
2725 shift amounts. Only used in 32-bit mode. */
2726
iselWordExpr_RH5u(ISelEnv * env,IRExpr * e,IREndness IEndianess)2727 static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e,
2728 IREndness IEndianess )
2729 {
2730 PPCRH* ri;
2731 vassert(!env->mode64);
2732 ri = iselWordExpr_RH5u_wrk(env, e, IEndianess);
2733 /* sanity checks ... */
2734 switch (ri->tag) {
2735 case Prh_Imm:
2736 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 31);
2737 vassert(!ri->Prh.Imm.syned);
2738 return ri;
2739 case Prh_Reg:
2740 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2741 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2742 return ri;
2743 default:
2744 vpanic("iselIntExpr_RH5u: unknown ppc RI tag");
2745 }
2746 }
2747
2748 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH5u_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2749 static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e,
2750 IREndness IEndianess )
2751 {
2752 IRType ty = typeOfIRExpr(env->type_env,e);
2753 vassert(ty == Ity_I8);
2754
2755 /* special case: immediate */
2756 if (e->tag == Iex_Const
2757 && e->Iex.Const.con->tag == Ico_U8
2758 && e->Iex.Const.con->Ico.U8 >= 1
2759 && e->Iex.Const.con->Ico.U8 <= 31) {
2760 return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2761 }
2762
2763 /* default case: calculate into a register and return that */
2764 return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2765 }
2766
2767
2768 /* --------------------- RH6u --------------------- */
2769
2770 /* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter
2771 being an immediate in the range 1 .. 63 inclusive. Used for doing
2772 shift amounts. Only used in 64-bit mode. */
2773
iselWordExpr_RH6u(ISelEnv * env,IRExpr * e,IREndness IEndianess)2774 static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e,
2775 IREndness IEndianess )
2776 {
2777 PPCRH* ri;
2778 vassert(env->mode64);
2779 ri = iselWordExpr_RH6u_wrk(env, e, IEndianess);
2780 /* sanity checks ... */
2781 switch (ri->tag) {
2782 case Prh_Imm:
2783 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 63);
2784 vassert(!ri->Prh.Imm.syned);
2785 return ri;
2786 case Prh_Reg:
2787 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2788 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2789 return ri;
2790 default:
2791 vpanic("iselIntExpr_RH6u: unknown ppc64 RI tag");
2792 }
2793 }
2794
2795 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH6u_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2796 static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e,
2797 IREndness IEndianess )
2798 {
2799 IRType ty = typeOfIRExpr(env->type_env,e);
2800 vassert(ty == Ity_I8);
2801
2802 /* special case: immediate */
2803 if (e->tag == Iex_Const
2804 && e->Iex.Const.con->tag == Ico_U8
2805 && e->Iex.Const.con->Ico.U8 >= 1
2806 && e->Iex.Const.con->Ico.U8 <= 63) {
2807 return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2808 }
2809
2810 /* default case: calculate into a register and return that */
2811 return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2812 }
2813
2814
2815 /* --------------------- CONDCODE --------------------- */
2816
2817 /* Generate code to evaluated a bit-typed expression, returning the
2818 condition code which would correspond when the expression would
2819 notionally have returned 1. */
2820
iselCondCode(ISelEnv * env,IRExpr * e,IREndness IEndianess)2821 static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e,
2822 IREndness IEndianess )
2823 {
2824 /* Uh, there's nothing we can sanity check here, unfortunately. */
2825 return iselCondCode_wrk(env,e, IEndianess);
2826 }
2827
2828 /* DO NOT CALL THIS DIRECTLY ! */
iselCondCode_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2829 static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e,
2830 IREndness IEndianess )
2831 {
2832 vassert(e);
2833 vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
2834
2835 /* Constant 1:Bit */
2836 if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) {
2837 // Make a compare that will always be true:
2838 HReg r_zero = newVRegI(env);
2839 addInstr(env, PPCInstr_LI(r_zero, 0, env->mode64));
2840 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2841 7/*cr*/, r_zero, PPCRH_Reg(r_zero)));
2842 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2843 }
2844
2845 /* Not1(...) */
2846 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
2847 /* Generate code for the arg, and negate the test condition */
2848 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
2849 cond.test = invertCondTest(cond.test);
2850 return cond;
2851 }
2852
2853 /* --- patterns rooted at: 32to1 or 64to1 --- */
2854
2855 /* 32to1, 64to1 */
2856 if (e->tag == Iex_Unop &&
2857 (e->Iex.Unop.op == Iop_32to1 || e->Iex.Unop.op == Iop_64to1)) {
2858 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2859 HReg tmp = newVRegI(env);
2860 /* could do better, probably -- andi. */
2861 addInstr(env, PPCInstr_Alu(Palu_AND, tmp,
2862 src, PPCRH_Imm(False,1)));
2863 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2864 7/*cr*/, tmp, PPCRH_Imm(False,1)));
2865 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2866 }
2867
2868 /* --- patterns rooted at: CmpNEZ8 --- */
2869
2870 /* CmpNEZ8(x) */
2871 /* Note this cloned as CmpNE8(x,0) below. */
2872 /* could do better -- andi. */
2873 if (e->tag == Iex_Unop
2874 && e->Iex.Unop.op == Iop_CmpNEZ8) {
2875 HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2876 HReg tmp = newVRegI(env);
2877 addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
2878 PPCRH_Imm(False,0xFF)));
2879 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2880 7/*cr*/, tmp, PPCRH_Imm(False,0)));
2881 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2882 }
2883
2884 /* --- patterns rooted at: CmpNEZ32 --- */
2885
2886 /* CmpNEZ32(x) */
2887 if (e->tag == Iex_Unop
2888 && e->Iex.Unop.op == Iop_CmpNEZ32) {
2889 HReg r1 = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2890 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2891 7/*cr*/, r1, PPCRH_Imm(False,0)));
2892 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2893 }
2894
2895 /* --- patterns rooted at: Cmp*32* --- */
2896
2897 /* Cmp*32*(x,y) */
2898 if (e->tag == Iex_Binop
2899 && (e->Iex.Binop.op == Iop_CmpEQ32
2900 || e->Iex.Binop.op == Iop_CmpNE32
2901 || e->Iex.Binop.op == Iop_CmpLT32S
2902 || e->Iex.Binop.op == Iop_CmpLT32U
2903 || e->Iex.Binop.op == Iop_CmpLE32S
2904 || e->Iex.Binop.op == Iop_CmpLE32U)) {
2905 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S ||
2906 e->Iex.Binop.op == Iop_CmpLE32S);
2907 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2908 PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2, IEndianess);
2909 addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
2910 7/*cr*/, r1, ri2));
2911
2912 switch (e->Iex.Binop.op) {
2913 case Iop_CmpEQ32: return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2914 case Iop_CmpNE32: return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2915 case Iop_CmpLT32U: case Iop_CmpLT32S:
2916 return mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
2917 case Iop_CmpLE32U: case Iop_CmpLE32S:
2918 return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2919 default: vpanic("iselCondCode(ppc): CmpXX32");
2920 }
2921 }
2922
2923 /* --- patterns rooted at: CmpNEZ64 --- */
2924
2925 /* CmpNEZ64 */
2926 if (e->tag == Iex_Unop
2927 && e->Iex.Unop.op == Iop_CmpNEZ64) {
2928 if (!env->mode64) {
2929 HReg hi, lo;
2930 HReg tmp = newVRegI(env);
2931 iselInt64Expr( &hi, &lo, env, e->Iex.Unop.arg, IEndianess );
2932 addInstr(env, PPCInstr_Alu(Palu_OR, tmp, lo, PPCRH_Reg(hi)));
2933 addInstr(env, PPCInstr_Cmp(False/*sign*/, True/*32bit cmp*/,
2934 7/*cr*/, tmp,PPCRH_Imm(False,0)));
2935 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2936 } else { // mode64
2937 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2938 addInstr(env, PPCInstr_Cmp(False/*sign*/, False/*64bit cmp*/,
2939 7/*cr*/, r_src,PPCRH_Imm(False,0)));
2940 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2941 }
2942 }
2943
2944 /* --- patterns rooted at: Cmp*64* --- */
2945
2946 /* Cmp*64*(x,y) */
2947 if (e->tag == Iex_Binop
2948 && (e->Iex.Binop.op == Iop_CmpEQ64
2949 || e->Iex.Binop.op == Iop_CmpNE64
2950 || e->Iex.Binop.op == Iop_CmpLT64S
2951 || e->Iex.Binop.op == Iop_CmpLT64U
2952 || e->Iex.Binop.op == Iop_CmpLE64S
2953 || e->Iex.Binop.op == Iop_CmpLE64U)) {
2954 Bool syned = (e->Iex.Binop.op == Iop_CmpLT64S ||
2955 e->Iex.Binop.op == Iop_CmpLE64S);
2956 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2957 PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2, IEndianess);
2958 vassert(env->mode64);
2959 addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
2960 7/*cr*/, r1, ri2));
2961
2962 switch (e->Iex.Binop.op) {
2963 case Iop_CmpEQ64: return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2964 case Iop_CmpNE64: return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2965 case Iop_CmpLT64U: return mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
2966 case Iop_CmpLE64U: return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2967 default: vpanic("iselCondCode(ppc): CmpXX64");
2968 }
2969 }
2970
2971 /* --- patterns rooted at: CmpNE8 --- */
2972
2973 /* CmpNE8(x,0) */
2974 /* Note this is a direct copy of CmpNEZ8 above. */
2975 /* could do better -- andi. */
2976 if (e->tag == Iex_Binop
2977 && e->Iex.Binop.op == Iop_CmpNE8
2978 && isZeroU8(e->Iex.Binop.arg2)) {
2979 HReg arg = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2980 HReg tmp = newVRegI(env);
2981 addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
2982 PPCRH_Imm(False,0xFF)));
2983 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2984 7/*cr*/, tmp, PPCRH_Imm(False,0)));
2985 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2986 }
2987
2988 /* var */
2989 if (e->tag == Iex_RdTmp) {
2990 HReg r_src = lookupIRTemp(env, e->Iex.RdTmp.tmp);
2991 HReg src_masked = newVRegI(env);
2992 addInstr(env,
2993 PPCInstr_Alu(Palu_AND, src_masked,
2994 r_src, PPCRH_Imm(False,1)));
2995 addInstr(env,
2996 PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2997 7/*cr*/, src_masked, PPCRH_Imm(False,1)));
2998 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2999 }
3000
3001 vex_printf("iselCondCode(ppc): No such tag(%u)\n", e->tag);
3002 ppIRExpr(e);
3003 vpanic("iselCondCode(ppc)");
3004 }
3005
3006
3007 /*---------------------------------------------------------*/
3008 /*--- ISEL: Integer expressions (128 bit) ---*/
3009 /*---------------------------------------------------------*/
3010
3011 /* 64-bit mode ONLY: compute a 128-bit value into a register pair,
3012 which is returned as the first two parameters. As with
3013 iselWordExpr_R, these may be either real or virtual regs; in any
3014 case they must not be changed by subsequent code emitted by the
3015 caller. */
3016
iselInt128Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3017 static void iselInt128Expr ( HReg* rHi, HReg* rLo,
3018 ISelEnv* env, IRExpr* e, IREndness IEndianess )
3019 {
3020 vassert(env->mode64);
3021 iselInt128Expr_wrk(rHi, rLo, env, e, IEndianess);
3022 # if 0
3023 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3024 # endif
3025 vassert(hregClass(*rHi) == HRcGPR(env->mode64));
3026 vassert(hregIsVirtual(*rHi));
3027 vassert(hregClass(*rLo) == HRcGPR(env->mode64));
3028 vassert(hregIsVirtual(*rLo));
3029 }
3030
3031 /* DO NOT CALL THIS DIRECTLY ! */
iselInt128Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3032 static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
3033 ISelEnv* env, IRExpr* e, IREndness IEndianess )
3034 {
3035 vassert(e);
3036 vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
3037
3038 /* read 128-bit IRTemp */
3039 if (e->tag == Iex_RdTmp) {
3040 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
3041 return;
3042 }
3043
3044 /* --------- BINARY ops --------- */
3045 if (e->tag == Iex_Binop) {
3046 switch (e->Iex.Binop.op) {
3047 /* 64 x 64 -> 128 multiply */
3048 case Iop_MullU64:
3049 case Iop_MullS64: {
3050 HReg tLo = newVRegI(env);
3051 HReg tHi = newVRegI(env);
3052 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64);
3053 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3054 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3055 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
3056 False/*lo64*/, False/*64bit mul*/,
3057 tLo, r_srcL, r_srcR));
3058 addInstr(env, PPCInstr_MulL(syned,
3059 True/*hi64*/, False/*64bit mul*/,
3060 tHi, r_srcL, r_srcR));
3061 *rHi = tHi;
3062 *rLo = tLo;
3063 return;
3064 }
3065
3066 /* 64HLto128(e1,e2) */
3067 case Iop_64HLto128:
3068 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3069 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3070 return;
3071 default:
3072 break;
3073 }
3074 } /* if (e->tag == Iex_Binop) */
3075
3076
3077 /* --------- UNARY ops --------- */
3078 if (e->tag == Iex_Unop) {
3079 switch (e->Iex.Unop.op) {
3080 default:
3081 break;
3082 }
3083 } /* if (e->tag == Iex_Unop) */
3084
3085 vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e->tag);
3086 ppIRExpr(e);
3087 vpanic("iselInt128Expr(ppc64)");
3088 }
3089
3090
3091 /*---------------------------------------------------------*/
3092 /*--- ISEL: Integer expressions (64 bit) ---*/
3093 /*---------------------------------------------------------*/
3094
3095 /* 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)3096 static void iselInt128Expr_to_32x4 ( HReg* rHi, HReg* rMedHi, HReg* rMedLo,
3097 HReg* rLo, ISelEnv* env, IRExpr* e,
3098 IREndness IEndianess )
3099 {
3100 vassert(!env->mode64);
3101 iselInt128Expr_to_32x4_wrk(rHi, rMedHi, rMedLo, rLo, env, e, IEndianess);
3102 # if 0
3103 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3104 # endif
3105 vassert(hregClass(*rHi) == HRcInt32);
3106 vassert(hregIsVirtual(*rHi));
3107 vassert(hregClass(*rMedHi) == HRcInt32);
3108 vassert(hregIsVirtual(*rMedHi));
3109 vassert(hregClass(*rMedLo) == HRcInt32);
3110 vassert(hregIsVirtual(*rMedLo));
3111 vassert(hregClass(*rLo) == HRcInt32);
3112 vassert(hregIsVirtual(*rLo));
3113 }
3114
iselInt128Expr_to_32x4_wrk(HReg * rHi,HReg * rMedHi,HReg * rMedLo,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3115 static void iselInt128Expr_to_32x4_wrk ( HReg* rHi, HReg* rMedHi,
3116 HReg* rMedLo, HReg* rLo,
3117 ISelEnv* env, IRExpr* e,
3118 IREndness IEndianess )
3119 {
3120 vassert(e);
3121 vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
3122
3123 /* read 128-bit IRTemp */
3124 if (e->tag == Iex_RdTmp) {
3125 lookupIRTempQuad( rHi, rMedHi, rMedLo, rLo, env, e->Iex.RdTmp.tmp);
3126 return;
3127 }
3128
3129 if (e->tag == Iex_Binop) {
3130
3131 IROp op_binop = e->Iex.Binop.op;
3132 switch (op_binop) {
3133 case Iop_64HLto128:
3134 iselInt64Expr(rHi, rMedHi, env, e->Iex.Binop.arg1, IEndianess);
3135 iselInt64Expr(rMedLo, rLo, env, e->Iex.Binop.arg2, IEndianess);
3136 return;
3137 default:
3138 vex_printf("iselInt128Expr_to_32x4_wrk: Binop case 0x%x not found\n",
3139 op_binop);
3140 break;
3141 }
3142 }
3143
3144 vex_printf("iselInt128Expr_to_32x4_wrk: e->tag 0x%x not found\n", e->tag);
3145 return;
3146 }
3147
3148 /* 32-bit mode ONLY: compute a 64-bit value into a register pair,
3149 which is returned as the first two parameters. As with
3150 iselIntExpr_R, these may be either real or virtual regs; in any
3151 case they must not be changed by subsequent code emitted by the
3152 caller. */
3153
iselInt64Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3154 static void iselInt64Expr ( HReg* rHi, HReg* rLo,
3155 ISelEnv* env, IRExpr* e,
3156 IREndness IEndianess )
3157 {
3158 vassert(!env->mode64);
3159 iselInt64Expr_wrk(rHi, rLo, env, e, IEndianess);
3160 # if 0
3161 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3162 # endif
3163 vassert(hregClass(*rHi) == HRcInt32);
3164 vassert(hregIsVirtual(*rHi));
3165 vassert(hregClass(*rLo) == HRcInt32);
3166 vassert(hregIsVirtual(*rLo));
3167 }
3168
3169 /* DO NOT CALL THIS DIRECTLY ! */
iselInt64Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3170 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
3171 ISelEnv* env, IRExpr* e,
3172 IREndness IEndianess )
3173 {
3174 vassert(e);
3175 vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
3176
3177 /* 64-bit load */
3178 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3179 HReg tLo = newVRegI(env);
3180 HReg tHi = newVRegI(env);
3181 HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr, IEndianess);
3182 vassert(!env->mode64);
3183 addInstr(env, PPCInstr_Load( 4/*byte-load*/,
3184 tHi, PPCAMode_IR( 0, r_addr ),
3185 False/*32-bit insn please*/) );
3186 addInstr(env, PPCInstr_Load( 4/*byte-load*/,
3187 tLo, PPCAMode_IR( 4, r_addr ),
3188 False/*32-bit insn please*/) );
3189 *rHi = tHi;
3190 *rLo = tLo;
3191 return;
3192 }
3193
3194 /* 64-bit literal */
3195 if (e->tag == Iex_Const) {
3196 ULong w64 = e->Iex.Const.con->Ico.U64;
3197 UInt wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF;
3198 UInt wLo = ((UInt)w64) & 0xFFFFFFFF;
3199 HReg tLo = newVRegI(env);
3200 HReg tHi = newVRegI(env);
3201 vassert(e->Iex.Const.con->tag == Ico_U64);
3202 addInstr(env, PPCInstr_LI(tHi, (Long)(Int)wHi, False/*mode32*/));
3203 addInstr(env, PPCInstr_LI(tLo, (Long)(Int)wLo, False/*mode32*/));
3204 *rHi = tHi;
3205 *rLo = tLo;
3206 return;
3207 }
3208
3209 /* read 64-bit IRTemp */
3210 if (e->tag == Iex_RdTmp) {
3211 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
3212 return;
3213 }
3214
3215 /* 64-bit GET */
3216 if (e->tag == Iex_Get) {
3217 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3218 GuestStatePtr(False/*mode32*/) );
3219 PPCAMode* am_addr4 = advance4(env, am_addr);
3220 HReg tLo = newVRegI(env);
3221 HReg tHi = newVRegI(env);
3222 addInstr(env, PPCInstr_Load( 4, tHi, am_addr, False/*mode32*/ ));
3223 addInstr(env, PPCInstr_Load( 4, tLo, am_addr4, False/*mode32*/ ));
3224 *rHi = tHi;
3225 *rLo = tLo;
3226 return;
3227 }
3228
3229 /* 64-bit ITE */
3230 if (e->tag == Iex_ITE) { // VFD
3231 HReg e0Lo, e0Hi, eXLo, eXHi;
3232 iselInt64Expr(&eXHi, &eXLo, env, e->Iex.ITE.iftrue, IEndianess);
3233 iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.ITE.iffalse, IEndianess);
3234 HReg tLo = newVRegI(env);
3235 HReg tHi = newVRegI(env);
3236 addInstr(env, mk_iMOVds_RR(tHi,e0Hi));
3237 addInstr(env, mk_iMOVds_RR(tLo,e0Lo));
3238 PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
3239 addInstr(env, PPCInstr_CMov(cc,tHi,PPCRI_Reg(eXHi)));
3240 addInstr(env, PPCInstr_CMov(cc,tLo,PPCRI_Reg(eXLo)));
3241 *rHi = tHi;
3242 *rLo = tLo;
3243 return;
3244 }
3245
3246 /* --------- BINARY ops --------- */
3247 if (e->tag == Iex_Binop) {
3248 IROp op_binop = e->Iex.Binop.op;
3249 switch (op_binop) {
3250 /* 32 x 32 -> 64 multiply */
3251 case Iop_MullU32:
3252 case Iop_MullS32: {
3253 HReg tLo = newVRegI(env);
3254 HReg tHi = newVRegI(env);
3255 Bool syned = toBool(op_binop == Iop_MullS32);
3256 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1,
3257 IEndianess);
3258 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2,
3259 IEndianess);
3260 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
3261 False/*lo32*/, True/*32bit mul*/,
3262 tLo, r_srcL, r_srcR));
3263 addInstr(env, PPCInstr_MulL(syned,
3264 True/*hi32*/, True/*32bit mul*/,
3265 tHi, r_srcL, r_srcR));
3266 *rHi = tHi;
3267 *rLo = tLo;
3268 return;
3269 }
3270
3271 /* Or64/And64/Xor64 */
3272 case Iop_Or64:
3273 case Iop_And64:
3274 case Iop_Xor64: {
3275 HReg xLo, xHi, yLo, yHi;
3276 HReg tLo = newVRegI(env);
3277 HReg tHi = newVRegI(env);
3278 PPCAluOp op = (op_binop == Iop_Or64) ? Palu_OR :
3279 (op_binop == Iop_And64) ? Palu_AND : Palu_XOR;
3280 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1, IEndianess);
3281 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2, IEndianess);
3282 addInstr(env, PPCInstr_Alu(op, tHi, xHi, PPCRH_Reg(yHi)));
3283 addInstr(env, PPCInstr_Alu(op, tLo, xLo, PPCRH_Reg(yLo)));
3284 *rHi = tHi;
3285 *rLo = tLo;
3286 return;
3287 }
3288
3289 /* Add64 */
3290 case Iop_Add64: {
3291 HReg xLo, xHi, yLo, yHi;
3292 HReg tLo = newVRegI(env);
3293 HReg tHi = newVRegI(env);
3294 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1, IEndianess);
3295 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2, IEndianess);
3296 addInstr(env, PPCInstr_AddSubC( True/*add*/, True /*set carry*/,
3297 tLo, xLo, yLo));
3298 addInstr(env, PPCInstr_AddSubC( True/*add*/, False/*read carry*/,
3299 tHi, xHi, yHi));
3300 *rHi = tHi;
3301 *rLo = tLo;
3302 return;
3303 }
3304
3305 /* 32HLto64(e1,e2) */
3306 case Iop_32HLto64:
3307 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3308 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3309 return;
3310
3311 /* F64toI64[S|U] */
3312 case Iop_F64toI64S: case Iop_F64toI64U: {
3313 HReg tLo = newVRegI(env);
3314 HReg tHi = newVRegI(env);
3315 HReg r1 = StackFramePtr(env->mode64);
3316 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3317 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3318 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2,
3319 IEndianess);
3320 HReg ftmp = newVRegF(env);
3321
3322 vassert(!env->mode64);
3323 /* Set host rounding mode */
3324 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3325
3326 sub_from_sp( env, 16 );
3327 addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/,
3328 (op_binop == Iop_F64toI64S) ? True : False,
3329 True, ftmp, fsrc));
3330 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
3331 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3332 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3333 add_to_sp( env, 16 );
3334
3335 ///* Restore default FPU rounding. */
3336 //set_FPU_rounding_default( env );
3337 *rHi = tHi;
3338 *rLo = tLo;
3339 return;
3340 }
3341 case Iop_D64toI64S: {
3342 HReg tLo = newVRegI(env);
3343 HReg tHi = newVRegI(env);
3344 HReg r1 = StackFramePtr(env->mode64);
3345 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3346 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3347 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
3348 HReg tmp = newVRegF(env);
3349
3350 vassert(!env->mode64);
3351 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3352 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTFIX, tmp, fr_src));
3353
3354 sub_from_sp( env, 16 );
3355 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3356 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3357 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3358 add_to_sp( env, 16 );
3359 *rHi = tHi;
3360 *rLo = tLo;
3361 return;
3362 }
3363 case Iop_D128toI64S: {
3364 PPCFpOp fpop = Pfp_DCTFIXQ;
3365 HReg r_srcHi = newVRegF(env);
3366 HReg r_srcLo = newVRegF(env);
3367 HReg tLo = newVRegI(env);
3368 HReg tHi = newVRegI(env);
3369 HReg ftmp = newVRegF(env);
3370 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3371 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3372
3373 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3374 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
3375 IEndianess);
3376 addInstr(env, PPCInstr_DfpD128toD64(fpop, ftmp, r_srcHi, r_srcLo));
3377
3378 // put the D64 result into an integer register pair
3379 sub_from_sp( env, 16 );
3380 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
3381 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3382 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3383 add_to_sp( env, 16 );
3384 *rHi = tHi;
3385 *rLo = tLo;
3386 return;
3387 }
3388 default:
3389 break;
3390 }
3391 } /* if (e->tag == Iex_Binop) */
3392
3393
3394 /* --------- UNARY ops --------- */
3395 if (e->tag == Iex_Unop) {
3396 switch (e->Iex.Unop.op) {
3397
3398 /* CmpwNEZ64(e) */
3399 case Iop_CmpwNEZ64: {
3400 HReg argHi, argLo;
3401 HReg tmp1 = newVRegI(env);
3402 HReg tmp2 = newVRegI(env);
3403 iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg, IEndianess);
3404 /* tmp1 = argHi | argLo */
3405 addInstr(env, PPCInstr_Alu(Palu_OR, tmp1, argHi, PPCRH_Reg(argLo)));
3406 /* tmp2 = (tmp1 | -tmp1) >>s 31 */
3407 addInstr(env, PPCInstr_Unary(Pun_NEG,tmp2,tmp1));
3408 addInstr(env, PPCInstr_Alu(Palu_OR, tmp2, tmp2, PPCRH_Reg(tmp1)));
3409 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3410 tmp2, tmp2, PPCRH_Imm(False, 31)));
3411 *rHi = tmp2;
3412 *rLo = tmp2; /* yes, really tmp2 */
3413 return;
3414 }
3415
3416 /* Left64 */
3417 case Iop_Left64: {
3418 HReg argHi, argLo;
3419 HReg zero32 = newVRegI(env);
3420 HReg resHi = newVRegI(env);
3421 HReg resLo = newVRegI(env);
3422 iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg, IEndianess);
3423 vassert(env->mode64 == False);
3424 addInstr(env, PPCInstr_LI(zero32, 0, env->mode64));
3425 /* resHi:resLo = - argHi:argLo */
3426 addInstr(env, PPCInstr_AddSubC( False/*sub*/, True/*set carry*/,
3427 resLo, zero32, argLo ));
3428 addInstr(env, PPCInstr_AddSubC( False/*sub*/, False/*read carry*/,
3429 resHi, zero32, argHi ));
3430 /* resHi:resLo |= srcHi:srcLo */
3431 addInstr(env, PPCInstr_Alu(Palu_OR, resLo, resLo, PPCRH_Reg(argLo)));
3432 addInstr(env, PPCInstr_Alu(Palu_OR, resHi, resHi, PPCRH_Reg(argHi)));
3433 *rHi = resHi;
3434 *rLo = resLo;
3435 return;
3436 }
3437
3438 /* 32Sto64(e) */
3439 case Iop_32Sto64: {
3440 HReg tHi = newVRegI(env);
3441 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3442 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3443 tHi, src, PPCRH_Imm(False,31)));
3444 *rHi = tHi;
3445 *rLo = src;
3446 return;
3447 }
3448 case Iop_ExtractExpD64: {
3449 HReg tmp = newVRegF(env);
3450 HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
3451 HReg tLo = newVRegI(env);
3452 HReg tHi = newVRegI(env);
3453 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3454 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3455
3456 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DXEX, tmp, fr_src));
3457
3458 // put the D64 result into a integer register pair
3459 sub_from_sp( env, 16 );
3460 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3461 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3462 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3463 add_to_sp( env, 16 );
3464 *rHi = tHi;
3465 *rLo = tLo;
3466 return;
3467 }
3468 case Iop_ExtractExpD128: {
3469 HReg r_srcHi;
3470 HReg r_srcLo;
3471 HReg tmp = newVRegF(env);
3472 HReg tLo = newVRegI(env);
3473 HReg tHi = newVRegI(env);
3474 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3475 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3476
3477 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Unop.arg, IEndianess);
3478 addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, tmp,
3479 r_srcHi, r_srcLo));
3480
3481 // put the D64 result into a integer register pair
3482 sub_from_sp( env, 16 );
3483 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3484 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3485 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3486 add_to_sp( env, 16 );
3487 *rHi = tHi;
3488 *rLo = tLo;
3489 return;
3490 }
3491
3492 /* 32Uto64(e) */
3493 case Iop_32Uto64: {
3494 HReg tHi = newVRegI(env);
3495 HReg tLo = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3496 addInstr(env, PPCInstr_LI(tHi, 0, False/*mode32*/));
3497 *rHi = tHi;
3498 *rLo = tLo;
3499 return;
3500 }
3501
3502 case Iop_128to64: {
3503 /* Narrow, return the low 64-bit half as a 32-bit
3504 * register pair */
3505 HReg r_Hi = INVALID_HREG;
3506 HReg r_MedHi = INVALID_HREG;
3507 HReg r_MedLo = INVALID_HREG;
3508 HReg r_Lo = INVALID_HREG;
3509
3510 iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo,
3511 env, e->Iex.Unop.arg, IEndianess);
3512 *rHi = r_MedLo;
3513 *rLo = r_Lo;
3514 return;
3515 }
3516
3517 case Iop_128HIto64: {
3518 /* Narrow, return the high 64-bit half as a 32-bit
3519 * register pair */
3520 HReg r_Hi = INVALID_HREG;
3521 HReg r_MedHi = INVALID_HREG;
3522 HReg r_MedLo = INVALID_HREG;
3523 HReg r_Lo = INVALID_HREG;
3524
3525 iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo,
3526 env, e->Iex.Unop.arg, IEndianess);
3527 *rHi = r_Hi;
3528 *rLo = r_MedHi;
3529 return;
3530 }
3531
3532 /* V128{HI}to64 */
3533 case Iop_V128HIto64:
3534 case Iop_V128to64: {
3535 HReg r_aligned16;
3536 Int off = e->Iex.Unop.op==Iop_V128HIto64 ? 0 : 8;
3537 HReg tLo = newVRegI(env);
3538 HReg tHi = newVRegI(env);
3539 HReg vec = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
3540 PPCAMode *am_off0, *am_offLO, *am_offHI;
3541 sub_from_sp( env, 32 ); // Move SP down 32 bytes
3542
3543 // get a quadword aligned address within our stack space
3544 r_aligned16 = get_sp_aligned16( env );
3545 am_off0 = PPCAMode_IR( 0, r_aligned16 );
3546 am_offHI = PPCAMode_IR( off, r_aligned16 );
3547 am_offLO = PPCAMode_IR( off+4, r_aligned16 );
3548
3549 // store as Vec128
3550 addInstr(env,
3551 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
3552
3553 // load hi,lo words (of hi/lo half of vec) as Ity_I32's
3554 addInstr(env,
3555 PPCInstr_Load( 4, tHi, am_offHI, False/*mode32*/ ));
3556 addInstr(env,
3557 PPCInstr_Load( 4, tLo, am_offLO, False/*mode32*/ ));
3558
3559 add_to_sp( env, 32 ); // Reset SP
3560 *rHi = tHi;
3561 *rLo = tLo;
3562 return;
3563 }
3564
3565 /* could do better than this, but for now ... */
3566 case Iop_1Sto64: {
3567 HReg tLo = newVRegI(env);
3568 HReg tHi = newVRegI(env);
3569 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
3570 addInstr(env, PPCInstr_Set(cond,tLo));
3571 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
3572 tLo, tLo, PPCRH_Imm(False,31)));
3573 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3574 tLo, tLo, PPCRH_Imm(False,31)));
3575 addInstr(env, mk_iMOVds_RR(tHi, tLo));
3576 *rHi = tHi;
3577 *rLo = tLo;
3578 return;
3579 }
3580
3581 case Iop_Not64: {
3582 HReg xLo, xHi;
3583 HReg tmpLo = newVRegI(env);
3584 HReg tmpHi = newVRegI(env);
3585 iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg, IEndianess);
3586 addInstr(env, PPCInstr_Unary(Pun_NOT,tmpLo,xLo));
3587 addInstr(env, PPCInstr_Unary(Pun_NOT,tmpHi,xHi));
3588 *rHi = tmpHi;
3589 *rLo = tmpLo;
3590 return;
3591 }
3592
3593 /* ReinterpF64asI64(e) */
3594 /* Given an IEEE754 double, produce an I64 with the same bit
3595 pattern. */
3596 case Iop_ReinterpF64asI64: {
3597 PPCAMode *am_addr0, *am_addr1;
3598 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
3599 HReg r_dstLo = newVRegI(env);
3600 HReg r_dstHi = newVRegI(env);
3601
3602 sub_from_sp( env, 16 ); // Move SP down 16 bytes
3603 am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
3604 am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
3605
3606 // store as F64
3607 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3608 fr_src, am_addr0 ));
3609
3610 // load hi,lo as Ity_I32's
3611 addInstr(env, PPCInstr_Load( 4, r_dstHi,
3612 am_addr0, False/*mode32*/ ));
3613 addInstr(env, PPCInstr_Load( 4, r_dstLo,
3614 am_addr1, False/*mode32*/ ));
3615 *rHi = r_dstHi;
3616 *rLo = r_dstLo;
3617
3618 add_to_sp( env, 16 ); // Reset SP
3619 return;
3620 }
3621
3622 case Iop_ReinterpD64asI64: {
3623 HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
3624 PPCAMode *am_addr0, *am_addr1;
3625 HReg r_dstLo = newVRegI(env);
3626 HReg r_dstHi = newVRegI(env);
3627
3628
3629 sub_from_sp( env, 16 ); // Move SP down 16 bytes
3630 am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
3631 am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
3632
3633 // store as D64
3634 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3635 fr_src, am_addr0 ));
3636
3637 // load hi,lo as Ity_I32's
3638 addInstr(env, PPCInstr_Load( 4, r_dstHi,
3639 am_addr0, False/*mode32*/ ));
3640 addInstr(env, PPCInstr_Load( 4, r_dstLo,
3641 am_addr1, False/*mode32*/ ));
3642 *rHi = r_dstHi;
3643 *rLo = r_dstLo;
3644
3645 add_to_sp( env, 16 ); // Reset SP
3646
3647 return;
3648 }
3649
3650 case Iop_BCDtoDPB: {
3651 PPCCondCode cc;
3652 UInt argiregs;
3653 HReg argregs[2];
3654 Int argreg;
3655 HReg tLo = newVRegI(env);
3656 HReg tHi = newVRegI(env);
3657 HReg tmpHi;
3658 HReg tmpLo;
3659 Bool mode64 = env->mode64;
3660
3661 argregs[0] = hregPPC_GPR3(mode64);
3662 argregs[1] = hregPPC_GPR4(mode64);
3663
3664 argiregs = 0;
3665 argreg = 0;
3666
3667 iselInt64Expr( &tmpHi, &tmpLo, env, e->Iex.Unop.arg, IEndianess );
3668
3669 argiregs |= ( 1 << (argreg+3 ) );
3670 addInstr( env, mk_iMOVds_RR( argregs[argreg++], tmpHi ) );
3671
3672 argiregs |= ( 1 << (argreg+3 ) );
3673 addInstr( env, mk_iMOVds_RR( argregs[argreg], tmpLo ) );
3674
3675 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
3676
3677 if (IEndianess == Iend_LE) {
3678 addInstr( env, PPCInstr_Call( cc, (Addr)h_calc_BCDtoDPB,
3679 argiregs,
3680 mk_RetLoc_simple(RLPri_2Int) ) );
3681 } else {
3682 Addr64 target;
3683 target = mode64 ? (Addr)h_calc_BCDtoDPB :
3684 toUInt( (Addr)h_calc_BCDtoDPB );
3685 addInstr( env, PPCInstr_Call( cc, target,
3686 argiregs,
3687 mk_RetLoc_simple(RLPri_2Int) ) );
3688 }
3689
3690 addInstr( env, mk_iMOVds_RR( tHi, argregs[argreg-1] ) );
3691 addInstr( env, mk_iMOVds_RR( tLo, argregs[argreg] ) );
3692
3693 *rHi = tHi;
3694 *rLo = tLo;
3695 return;
3696 }
3697
3698 case Iop_DPBtoBCD: {
3699 PPCCondCode cc;
3700 UInt argiregs;
3701 HReg argregs[2];
3702 Int argreg;
3703 HReg tLo = newVRegI(env);
3704 HReg tHi = newVRegI(env);
3705 HReg tmpHi;
3706 HReg tmpLo;
3707 Bool mode64 = env->mode64;
3708
3709 argregs[0] = hregPPC_GPR3(mode64);
3710 argregs[1] = hregPPC_GPR4(mode64);
3711
3712 argiregs = 0;
3713 argreg = 0;
3714
3715 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg, IEndianess);
3716
3717 argiregs |= (1 << (argreg+3));
3718 addInstr(env, mk_iMOVds_RR( argregs[argreg++], tmpHi ));
3719
3720 argiregs |= (1 << (argreg+3));
3721 addInstr(env, mk_iMOVds_RR( argregs[argreg], tmpLo));
3722
3723 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
3724
3725 if (IEndianess == Iend_LE) {
3726 addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_DPBtoBCD,
3727 argiregs,
3728 mk_RetLoc_simple(RLPri_2Int) ) );
3729 } else {
3730 Addr64 target;
3731 target = mode64 ? (Addr)h_calc_DPBtoBCD :
3732 toUInt( (Addr)h_calc_DPBtoBCD );
3733 addInstr(env, PPCInstr_Call( cc, target, argiregs,
3734 mk_RetLoc_simple(RLPri_2Int) ) );
3735 }
3736
3737 addInstr(env, mk_iMOVds_RR(tHi, argregs[argreg-1]));
3738 addInstr(env, mk_iMOVds_RR(tLo, argregs[argreg]));
3739
3740 *rHi = tHi;
3741 *rLo = tLo;
3742 return;
3743 }
3744
3745 default:
3746 break;
3747 }
3748 } /* if (e->tag == Iex_Unop) */
3749
3750 vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e->tag);
3751 ppIRExpr(e);
3752 vpanic("iselInt64Expr(ppc)");
3753 }
3754
3755
3756 /*---------------------------------------------------------*/
3757 /*--- ISEL: Floating point expressions (32 bit) ---*/
3758 /*---------------------------------------------------------*/
3759
3760 /* Nothing interesting here; really just wrappers for
3761 64-bit stuff. */
3762
iselFltExpr(ISelEnv * env,IRExpr * e,IREndness IEndianess)3763 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3764 {
3765 HReg r = iselFltExpr_wrk( env, e, IEndianess );
3766 # if 0
3767 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3768 # endif
3769 vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */
3770 vassert(hregIsVirtual(r));
3771 return r;
3772 }
3773
3774 /* DO NOT CALL THIS DIRECTLY */
iselFltExpr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)3775 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3776 {
3777 Bool mode64 = env->mode64;
3778
3779 IRType ty = typeOfIRExpr(env->type_env,e);
3780 vassert(ty == Ity_F32);
3781
3782 if (e->tag == Iex_RdTmp) {
3783 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3784 }
3785
3786 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3787 PPCAMode* am_addr;
3788 HReg r_dst = newVRegF(env);
3789 vassert(e->Iex.Load.ty == Ity_F32);
3790 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F32/*xfer*/,
3791 IEndianess);
3792 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
3793 return r_dst;
3794 }
3795
3796 if (e->tag == Iex_Get) {
3797 HReg r_dst = newVRegF(env);
3798 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3799 GuestStatePtr(env->mode64) );
3800 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4, r_dst, am_addr ));
3801 return r_dst;
3802 }
3803
3804 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
3805 /* This is quite subtle. The only way to do the relevant
3806 truncation is to do a single-precision store and then a
3807 double precision load to get it back into a register. The
3808 problem is, if the data is then written to memory a second
3809 time, as in
3810
3811 STbe(...) = TruncF64asF32(...)
3812
3813 then will the second truncation further alter the value? The
3814 answer is no: flds (as generated here) followed by fsts
3815 (generated for the STbe) is the identity function on 32-bit
3816 floats, so we are safe.
3817
3818 Another upshot of this is that if iselStmt can see the
3819 entirety of
3820
3821 STbe(...) = TruncF64asF32(arg)
3822
3823 then it can short circuit having to deal with TruncF64asF32
3824 individually; instead just compute arg into a 64-bit FP
3825 register and do 'fsts' (since that itself does the
3826 truncation).
3827
3828 We generate pretty poor code here (should be ok both for
3829 32-bit and 64-bit mode); but it is expected that for the most
3830 part the latter optimisation will apply and hence this code
3831 will not often be used.
3832 */
3833 HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
3834 HReg fdst = newVRegF(env);
3835 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3836
3837 sub_from_sp( env, 16 );
3838 // store as F32, hence truncating
3839 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
3840 fsrc, zero_r1 ));
3841 // and reload. Good huh?! (sigh)
3842 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4,
3843 fdst, zero_r1 ));
3844 add_to_sp( env, 16 );
3845 return fdst;
3846 }
3847
3848 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64UtoF32) {
3849 if (mode64) {
3850 HReg fdst = newVRegF(env);
3851 HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3852 HReg r1 = StackFramePtr(env->mode64);
3853 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3854
3855 /* Set host rounding mode */
3856 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3857
3858 sub_from_sp( env, 16 );
3859
3860 addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
3861 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3862 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3863 False, False,
3864 fdst, fdst));
3865
3866 add_to_sp( env, 16 );
3867
3868 ///* Restore default FPU rounding. */
3869 //set_FPU_rounding_default( env );
3870 return fdst;
3871 } else {
3872 /* 32-bit mode */
3873 HReg fdst = newVRegF(env);
3874 HReg isrcHi, isrcLo;
3875 HReg r1 = StackFramePtr(env->mode64);
3876 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3877 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3878
3879 iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2, IEndianess);
3880
3881 /* Set host rounding mode */
3882 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3883
3884 sub_from_sp( env, 16 );
3885
3886 addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
3887 addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
3888 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3889 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3890 False, False,
3891 fdst, fdst));
3892
3893 add_to_sp( env, 16 );
3894
3895 ///* Restore default FPU rounding. */
3896 //set_FPU_rounding_default( env );
3897 return fdst;
3898 }
3899
3900 }
3901
3902 vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e->tag);
3903 ppIRExpr(e);
3904 vpanic("iselFltExpr_wrk(ppc)");
3905 }
3906
3907
3908 /*---------------------------------------------------------*/
3909 /*--- ISEL: Floating point expressions (64 bit) ---*/
3910 /*---------------------------------------------------------*/
3911
3912 /* Compute a 64-bit floating point value into a register, the identity
3913 of which is returned. As with iselIntExpr_R, the reg may be either
3914 real or virtual; in any case it must not be changed by subsequent
3915 code emitted by the caller. */
3916
3917 /* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm:
3918
3919 Type S (1 bit) E (11 bits) F (52 bits)
3920 ---- --------- ----------- -----------
3921 signalling NaN u 2047 (max) .0uuuuu---u
3922 (with at least
3923 one 1 bit)
3924 quiet NaN u 2047 (max) .1uuuuu---u
3925
3926 negative infinity 1 2047 (max) .000000---0
3927
3928 positive infinity 0 2047 (max) .000000---0
3929
3930 negative zero 1 0 .000000---0
3931
3932 positive zero 0 0 .000000---0
3933 */
3934
iselDblExpr(ISelEnv * env,IRExpr * e,IREndness IEndianess)3935 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3936 {
3937 HReg r = iselDblExpr_wrk( env, e, IEndianess );
3938 # if 0
3939 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3940 # endif
3941 vassert(hregClass(r) == HRcFlt64);
3942 vassert(hregIsVirtual(r));
3943 return r;
3944 }
3945
3946 /* DO NOT CALL THIS DIRECTLY */
iselDblExpr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)3947 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3948 {
3949 Bool mode64 = env->mode64;
3950 IRType ty = typeOfIRExpr(env->type_env,e);
3951 vassert(e);
3952 vassert(ty == Ity_F64);
3953
3954 if (e->tag == Iex_RdTmp) {
3955 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3956 }
3957
3958 /* --------- LITERAL --------- */
3959 if (e->tag == Iex_Const) {
3960 union { UInt u32x2[2]; ULong u64; Double f64; } u;
3961 vassert(sizeof(u) == 8);
3962 vassert(sizeof(u.u64) == 8);
3963 vassert(sizeof(u.f64) == 8);
3964 vassert(sizeof(u.u32x2) == 8);
3965
3966 if (e->Iex.Const.con->tag == Ico_F64) {
3967 u.f64 = e->Iex.Const.con->Ico.F64;
3968 }
3969 else if (e->Iex.Const.con->tag == Ico_F64i) {
3970 u.u64 = e->Iex.Const.con->Ico.F64i;
3971 }
3972 else
3973 vpanic("iselDblExpr(ppc): const");
3974
3975 if (!mode64) {
3976 HReg r_srcHi = newVRegI(env);
3977 HReg r_srcLo = newVRegI(env);
3978 addInstr(env, PPCInstr_LI(r_srcHi, u.u32x2[0], mode64));
3979 addInstr(env, PPCInstr_LI(r_srcLo, u.u32x2[1], mode64));
3980 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
3981 } else { // mode64
3982 HReg r_src = newVRegI(env);
3983 addInstr(env, PPCInstr_LI(r_src, u.u64, mode64));
3984 return mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64
3985 }
3986 }
3987
3988 /* --------- LOAD --------- */
3989 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3990 HReg r_dst = newVRegF(env);
3991 PPCAMode* am_addr;
3992 vassert(e->Iex.Load.ty == Ity_F64);
3993 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F64/*xfer*/,
3994 IEndianess);
3995 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
3996 return r_dst;
3997 }
3998
3999 /* --------- GET --------- */
4000 if (e->tag == Iex_Get) {
4001 HReg r_dst = newVRegF(env);
4002 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4003 GuestStatePtr(mode64) );
4004 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ));
4005 return r_dst;
4006 }
4007
4008 /* --------- OPS --------- */
4009 if (e->tag == Iex_Qop) {
4010 PPCFpOp fpop = Pfp_INVALID;
4011 switch (e->Iex.Qop.details->op) {
4012 case Iop_MAddF64: fpop = Pfp_MADDD; break;
4013 case Iop_MAddF64r32: fpop = Pfp_MADDS; break;
4014 case Iop_MSubF64: fpop = Pfp_MSUBD; break;
4015 case Iop_MSubF64r32: fpop = Pfp_MSUBS; break;
4016 default: break;
4017 }
4018 if (fpop != Pfp_INVALID) {
4019 HReg r_dst = newVRegF(env);
4020 HReg r_srcML = iselDblExpr(env, e->Iex.Qop.details->arg2,
4021 IEndianess);
4022 HReg r_srcMR = iselDblExpr(env, e->Iex.Qop.details->arg3,
4023 IEndianess);
4024 HReg r_srcAcc = iselDblExpr(env, e->Iex.Qop.details->arg4,
4025 IEndianess);
4026 set_FPU_rounding_mode( env, e->Iex.Qop.details->arg1, IEndianess );
4027 addInstr(env, PPCInstr_FpMulAcc(fpop, r_dst,
4028 r_srcML, r_srcMR, r_srcAcc));
4029 return r_dst;
4030 }
4031 }
4032
4033 if (e->tag == Iex_Triop) {
4034 IRTriop *triop = e->Iex.Triop.details;
4035 PPCFpOp fpop = Pfp_INVALID;
4036 switch (triop->op) {
4037 case Iop_AddF64: fpop = Pfp_ADDD; break;
4038 case Iop_SubF64: fpop = Pfp_SUBD; break;
4039 case Iop_MulF64: fpop = Pfp_MULD; break;
4040 case Iop_DivF64: fpop = Pfp_DIVD; break;
4041 case Iop_AddF64r32: fpop = Pfp_ADDS; break;
4042 case Iop_SubF64r32: fpop = Pfp_SUBS; break;
4043 case Iop_MulF64r32: fpop = Pfp_MULS; break;
4044 case Iop_DivF64r32: fpop = Pfp_DIVS; break;
4045 default: break;
4046 }
4047 if (fpop != Pfp_INVALID) {
4048 HReg r_dst = newVRegF(env);
4049 HReg r_srcL = iselDblExpr(env, triop->arg2, IEndianess);
4050 HReg r_srcR = iselDblExpr(env, triop->arg3, IEndianess);
4051 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4052 addInstr(env, PPCInstr_FpBinary(fpop, r_dst, r_srcL, r_srcR));
4053 return r_dst;
4054 }
4055 }
4056
4057 if (e->tag == Iex_Binop) {
4058 PPCFpOp fpop = Pfp_INVALID;
4059 switch (e->Iex.Binop.op) {
4060 case Iop_SqrtF64: fpop = Pfp_SQRT; break;
4061 default: break;
4062 }
4063 if (fpop == Pfp_SQRT) {
4064 HReg fr_dst = newVRegF(env);
4065 HReg fr_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4066 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4067 addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
4068 return fr_dst;
4069 }
4070 }
4071
4072 if (e->tag == Iex_Binop) {
4073
4074 if (e->Iex.Binop.op == Iop_RoundF64toF32) {
4075 HReg r_dst = newVRegF(env);
4076 HReg r_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4077 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4078 addInstr(env, PPCInstr_FpRSP(r_dst, r_src));
4079 //set_FPU_rounding_default( env );
4080 return r_dst;
4081 }
4082
4083 if (e->Iex.Binop.op == Iop_I64StoF64 || e->Iex.Binop.op == Iop_I64UtoF64) {
4084 if (mode64) {
4085 HReg fdst = newVRegF(env);
4086 HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
4087 HReg r1 = StackFramePtr(env->mode64);
4088 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
4089
4090 /* Set host rounding mode */
4091 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4092
4093 sub_from_sp( env, 16 );
4094
4095 addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
4096 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
4097 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
4098 e->Iex.Binop.op == Iop_I64StoF64,
4099 True/*fdst is 64 bit*/,
4100 fdst, fdst));
4101
4102 add_to_sp( env, 16 );
4103
4104 ///* Restore default FPU rounding. */
4105 //set_FPU_rounding_default( env );
4106 return fdst;
4107 } else {
4108 /* 32-bit mode */
4109 HReg fdst = newVRegF(env);
4110 HReg isrcHi, isrcLo;
4111 HReg r1 = StackFramePtr(env->mode64);
4112 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
4113 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
4114
4115 iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2,
4116 IEndianess);
4117
4118 /* Set host rounding mode */
4119 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4120
4121 sub_from_sp( env, 16 );
4122
4123 addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
4124 addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
4125 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
4126 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
4127 e->Iex.Binop.op == Iop_I64StoF64,
4128 True/*fdst is 64 bit*/,
4129 fdst, fdst));
4130
4131 add_to_sp( env, 16 );
4132
4133 ///* Restore default FPU rounding. */
4134 //set_FPU_rounding_default( env );
4135 return fdst;
4136 }
4137 }
4138
4139 }
4140
4141 if (e->tag == Iex_Unop) {
4142 PPCFpOp fpop = Pfp_INVALID;
4143 switch (e->Iex.Unop.op) {
4144 case Iop_NegF64: fpop = Pfp_NEG; break;
4145 case Iop_AbsF64: fpop = Pfp_ABS; break;
4146 case Iop_RSqrtEst5GoodF64: fpop = Pfp_RSQRTE; break;
4147 case Iop_RoundF64toF64_NegINF: fpop = Pfp_FRIM; break;
4148 case Iop_RoundF64toF64_PosINF: fpop = Pfp_FRIP; break;
4149 case Iop_RoundF64toF64_NEAREST: fpop = Pfp_FRIN; break;
4150 case Iop_RoundF64toF64_ZERO: fpop = Pfp_FRIZ; break;
4151 default: break;
4152 }
4153 if (fpop != Pfp_INVALID) {
4154 HReg fr_dst = newVRegF(env);
4155 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
4156 addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
4157 return fr_dst;
4158 }
4159 }
4160
4161 if (e->tag == Iex_Unop) {
4162 switch (e->Iex.Unop.op) {
4163 case Iop_ReinterpI64asF64: {
4164 /* Given an I64, produce an IEEE754 double with the same
4165 bit pattern. */
4166 if (!mode64) {
4167 HReg r_srcHi, r_srcLo;
4168 iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
4169 IEndianess);
4170 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
4171 } else {
4172 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4173 return mk_LoadR64toFPR( env, r_src );
4174 }
4175 }
4176
4177 case Iop_F32toF64: {
4178 if (e->Iex.Unop.arg->tag == Iex_Unop &&
4179 e->Iex.Unop.arg->Iex.Unop.op == Iop_ReinterpI32asF32 ) {
4180 e = e->Iex.Unop.arg;
4181
4182 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4183 HReg fr_dst = newVRegF(env);
4184 PPCAMode *am_addr;
4185
4186 sub_from_sp( env, 16 ); // Move SP down 16 bytes
4187 am_addr = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4188
4189 // store src as Ity_I32's
4190 addInstr(env, PPCInstr_Store( 4, am_addr, src, env->mode64 ));
4191
4192 // load single precision float, but the end results loads into a
4193 // 64-bit FP register -- i.e., F64.
4194 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, fr_dst, am_addr));
4195
4196 add_to_sp( env, 16 ); // Reset SP
4197 return fr_dst;
4198 }
4199
4200
4201 /* this is a no-op */
4202 HReg res = iselFltExpr(env, e->Iex.Unop.arg, IEndianess);
4203 return res;
4204 }
4205 default:
4206 break;
4207 }
4208 }
4209
4210 /* --------- MULTIPLEX --------- */
4211 if (e->tag == Iex_ITE) { // VFD
4212 if (ty == Ity_F64
4213 && typeOfIRExpr(env->type_env,e->Iex.ITE.cond) == Ity_I1) {
4214 HReg fr1 = iselDblExpr(env, e->Iex.ITE.iftrue, IEndianess);
4215 HReg fr0 = iselDblExpr(env, e->Iex.ITE.iffalse, IEndianess);
4216 HReg fr_dst = newVRegF(env);
4217 addInstr(env, PPCInstr_FpUnary( Pfp_MOV, fr_dst, fr0 ));
4218 PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
4219 addInstr(env, PPCInstr_FpCMov( cc, fr_dst, fr1 ));
4220 return fr_dst;
4221 }
4222 }
4223
4224 vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e->tag);
4225 ppIRExpr(e);
4226 vpanic("iselDblExpr_wrk(ppc)");
4227 }
4228
iselDfp32Expr(ISelEnv * env,IRExpr * e,IREndness IEndianess)4229 static HReg iselDfp32Expr(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4230 {
4231 HReg r = iselDfp32Expr_wrk( env, e, IEndianess );
4232 vassert(hregClass(r) == HRcFlt64);
4233 vassert( hregIsVirtual(r) );
4234 return r;
4235 }
4236
4237 /* DO NOT CALL THIS DIRECTLY */
iselDfp32Expr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)4238 static HReg iselDfp32Expr_wrk(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4239 {
4240 Bool mode64 = env->mode64;
4241 IRType ty = typeOfIRExpr( env->type_env, e );
4242
4243 vassert( e );
4244 vassert( ty == Ity_D32 );
4245
4246 /* --------- GET --------- */
4247 if (e->tag == Iex_Get) {
4248 HReg r_dst = newVRegF( env );
4249 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4250 GuestStatePtr(mode64) );
4251 addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) );
4252 return r_dst;
4253 }
4254
4255 /* --------- LOAD --------- */
4256 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4257 PPCAMode* am_addr;
4258 HReg r_dst = newVRegF(env);
4259 vassert(e->Iex.Load.ty == Ity_D32);
4260 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_D32/*xfer*/,
4261 IEndianess);
4262 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
4263 return r_dst;
4264 }
4265
4266 /* --------- OPS --------- */
4267 if (e->tag == Iex_Binop) {
4268 if (e->Iex.Binop.op == Iop_D64toD32) {
4269 HReg fr_dst = newVRegF(env);
4270 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4271 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4272 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DRSP, fr_dst, fr_src));
4273 return fr_dst;
4274 }
4275 }
4276
4277 ppIRExpr( e );
4278 vpanic( "iselDfp32Expr_wrk(ppc)" );
4279 }
4280
iselDfp64Expr(ISelEnv * env,IRExpr * e,IREndness IEndianess)4281 static HReg iselDfp64Expr(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4282 {
4283 HReg r = iselDfp64Expr_wrk( env, e, IEndianess );
4284 vassert(hregClass(r) == HRcFlt64);
4285 vassert( hregIsVirtual(r) );
4286 return r;
4287 }
4288
4289 /* DO NOT CALL THIS DIRECTLY */
iselDfp64Expr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)4290 static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4291 {
4292 Bool mode64 = env->mode64;
4293 IRType ty = typeOfIRExpr( env->type_env, e );
4294 HReg r_dstHi, r_dstLo;
4295
4296 vassert( e );
4297 vassert( ty == Ity_D64 );
4298
4299 if (e->tag == Iex_RdTmp) {
4300 return lookupIRTemp( env, e->Iex.RdTmp.tmp );
4301 }
4302
4303 /* --------- GET --------- */
4304 if (e->tag == Iex_Get) {
4305 HReg r_dst = newVRegF( env );
4306 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4307 GuestStatePtr(mode64) );
4308 addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) );
4309 return r_dst;
4310 }
4311
4312 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4313 PPCAMode* am_addr;
4314 HReg r_dst = newVRegF(env);
4315 vassert(e->Iex.Load.ty == Ity_D64);
4316 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_D64/*xfer*/,
4317 IEndianess);
4318 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
4319 return r_dst;
4320 }
4321
4322 /* --------- OPS --------- */
4323 if (e->tag == Iex_Qop) {
4324 HReg r_dst = newVRegF( env );
4325 return r_dst;
4326 }
4327
4328 if (e->tag == Iex_Unop) {
4329 HReg fr_dst = newVRegF(env);
4330 switch (e->Iex.Unop.op) {
4331 case Iop_ReinterpI64asD64: {
4332 /* Given an I64, produce an IEEE754 DFP with the same
4333 bit pattern. */
4334 if (!mode64) {
4335 HReg r_srcHi, r_srcLo;
4336 iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
4337 IEndianess);
4338 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
4339 } else {
4340 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4341 return mk_LoadR64toFPR( env, r_src );
4342 }
4343 }
4344 case Iop_D32toD64: {
4345 HReg fr_src = iselDfp32Expr(env, e->Iex.Unop.arg, IEndianess);
4346 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTDP, fr_dst, fr_src));
4347 return fr_dst;
4348 }
4349 case Iop_D128HItoD64:
4350 iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg,
4351 IEndianess );
4352 return r_dstHi;
4353 case Iop_D128LOtoD64:
4354 iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg,
4355 IEndianess );
4356 return r_dstLo;
4357 case Iop_InsertExpD64: {
4358 HReg fr_srcL = iselDblExpr(env, e->Iex.Binop.arg1, IEndianess);
4359 HReg fr_srcR = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4360
4361 addInstr(env, PPCInstr_Dfp64Binary(Pfp_DIEX, fr_dst, fr_srcL,
4362 fr_srcR));
4363 return fr_dst;
4364 }
4365 default:
4366 vex_printf( "ERROR: iselDfp64Expr_wrk, UNKNOWN unop case %d\n",
4367 (Int)e->Iex.Unop.op );
4368 }
4369 }
4370
4371 if (e->tag == Iex_Binop) {
4372 PPCFpOp fpop = Pfp_INVALID;
4373 HReg fr_dst = newVRegF(env);
4374
4375 switch (e->Iex.Binop.op) {
4376 case Iop_D128toD64: fpop = Pfp_DRDPQ; break;
4377 case Iop_D64toD32: fpop = Pfp_DRSP; break;
4378 case Iop_I64StoD64: fpop = Pfp_DCFFIX; break;
4379 case Iop_RoundD64toInt: fpop = Pfp_DRINTN; break;
4380 default: break;
4381 }
4382 if (fpop == Pfp_DRDPQ) {
4383 HReg r_srcHi = newVRegF(env);
4384 HReg r_srcLo = newVRegF(env);
4385
4386 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4387 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4388 IEndianess);
4389 addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
4390 return fr_dst;
4391
4392 } else if (fpop == Pfp_DRINTN) {
4393 HReg fr_src = newVRegF(env);
4394 PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
4395
4396 /* NOTE, this IOP takes a DFP value and rounds to the
4397 * neares floating point integer value, i.e. fractional part
4398 * is zero. The result is a decimal floating point number.
4399 * the INT in the name is a bit misleading.
4400 */
4401 fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4402 addInstr(env, PPCInstr_DfpRound(fr_dst, fr_src, r_rmc));
4403 return fr_dst;
4404
4405 } else if (fpop == Pfp_DRSP) {
4406 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4407 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4408 addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
4409 return fr_dst;
4410
4411 } else if (fpop == Pfp_DCFFIX) {
4412 HReg fr_src = newVRegF(env);
4413 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4414
4415 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4416 sub_from_sp( env, 16 );
4417
4418 // put the I64 value into a floating point register
4419 if (mode64) {
4420 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
4421
4422 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4423 } else {
4424 HReg tmpHi, tmpLo;
4425 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4426
4427 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg2,
4428 IEndianess);
4429 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
4430 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
4431 }
4432
4433 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_src, zero_r1));
4434 addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
4435 add_to_sp( env, 16 );
4436 return fr_dst;
4437 }
4438
4439 switch (e->Iex.Binop.op) {
4440 /* shift instructions D64, I32 -> D64 */
4441 case Iop_ShlD64: fpop = Pfp_DSCLI; break;
4442 case Iop_ShrD64: fpop = Pfp_DSCRI; break;
4443 default: break;
4444 }
4445 if (fpop != Pfp_INVALID) {
4446 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg1, IEndianess);
4447 PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
4448
4449 /* shift value must be an immediate value */
4450 vassert(shift->tag == Pri_Imm);
4451
4452 addInstr(env, PPCInstr_DfpShift(fpop, fr_dst, fr_src, shift));
4453 return fr_dst;
4454 }
4455
4456 switch (e->Iex.Binop.op) {
4457 case Iop_InsertExpD64:
4458 fpop = Pfp_DIEX;
4459 break;
4460 default: break;
4461 }
4462 if (fpop != Pfp_INVALID) {
4463 HReg fr_srcL = newVRegF(env);
4464 HReg fr_srcR = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4465 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4466 sub_from_sp( env, 16 );
4467
4468 if (env->mode64) {
4469 // put the I64 value into a floating point reg
4470 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
4471
4472 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4473 } else {
4474 // put the I64 register pair into a floating point reg
4475 HReg tmpHi;
4476 HReg tmpLo;
4477 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4478
4479 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg1,
4480 IEndianess);
4481 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*!mode64*/));
4482 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*!mode64*/));
4483 }
4484 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_srcL, zero_r1));
4485 addInstr(env, PPCInstr_Dfp64Binary(fpop, fr_dst, fr_srcL,
4486 fr_srcR));
4487 add_to_sp( env, 16 );
4488 return fr_dst;
4489 }
4490 }
4491
4492 if (e->tag == Iex_Triop) {
4493 IRTriop *triop = e->Iex.Triop.details;
4494 PPCFpOp fpop = Pfp_INVALID;
4495
4496 switch (triop->op) {
4497 case Iop_AddD64:
4498 fpop = Pfp_DFPADD;
4499 break;
4500 case Iop_SubD64:
4501 fpop = Pfp_DFPSUB;
4502 break;
4503 case Iop_MulD64:
4504 fpop = Pfp_DFPMUL;
4505 break;
4506 case Iop_DivD64:
4507 fpop = Pfp_DFPDIV;
4508 break;
4509 default:
4510 break;
4511 }
4512 if (fpop != Pfp_INVALID) {
4513 HReg r_dst = newVRegF( env );
4514 HReg r_srcL = iselDfp64Expr( env, triop->arg2, IEndianess );
4515 HReg r_srcR = iselDfp64Expr( env, triop->arg3, IEndianess );
4516
4517 set_FPU_DFP_rounding_mode( env, triop->arg1, IEndianess );
4518 addInstr( env, PPCInstr_Dfp64Binary( fpop, r_dst, r_srcL, r_srcR ) );
4519 return r_dst;
4520 }
4521
4522 switch (triop->op) {
4523 case Iop_QuantizeD64: fpop = Pfp_DQUA; break;
4524 case Iop_SignificanceRoundD64: fpop = Pfp_RRDTR; break;
4525 default: break;
4526 }
4527 if (fpop == Pfp_DQUA) {
4528 HReg r_dst = newVRegF(env);
4529 HReg r_srcL = iselDfp64Expr(env, triop->arg2, IEndianess);
4530 HReg r_srcR = iselDfp64Expr(env, triop->arg3, IEndianess);
4531 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
4532 addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR,
4533 rmc));
4534 return r_dst;
4535
4536 } else if (fpop == Pfp_RRDTR) {
4537 HReg r_dst = newVRegF(env);
4538 HReg r_srcL = newVRegF(env);
4539 HReg r_srcR = iselDfp64Expr(env, triop->arg3, IEndianess);
4540 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
4541 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4542 HReg i8_val = iselWordExpr_R(env, triop->arg2, IEndianess);
4543
4544 /* Move I8 to float register to issue instruction */
4545 sub_from_sp( env, 16 );
4546 if (mode64)
4547 addInstr(env, PPCInstr_Store(8, zero_r1, i8_val, True/*mode64*/));
4548 else
4549 addInstr(env, PPCInstr_Store(4, zero_r1, i8_val, False/*mode32*/));
4550
4551 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1));
4552 add_to_sp( env, 16 );
4553
4554 // will set TE and RMC when issuing instruction
4555 addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR, rmc));
4556 return r_dst;
4557 }
4558 }
4559
4560 ppIRExpr( e );
4561 vpanic( "iselDfp64Expr_wrk(ppc)" );
4562 }
4563
iselDfp128Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)4564 static void iselDfp128Expr(HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e,
4565 IREndness IEndianess)
4566 {
4567 iselDfp128Expr_wrk( rHi, rLo, env, e, IEndianess );
4568 vassert( hregIsVirtual(*rHi) );
4569 vassert( hregIsVirtual(*rLo) );
4570 }
4571
4572 /* DO NOT CALL THIS DIRECTLY */
iselDfp128Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)4573 static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e,
4574 IREndness IEndianess)
4575 {
4576 vassert( e );
4577 vassert( typeOfIRExpr(env->type_env,e) == Ity_D128 );
4578
4579 /* read 128-bit IRTemp */
4580 if (e->tag == Iex_RdTmp) {
4581 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp );
4582 return;
4583 }
4584
4585 if (e->tag == Iex_Unop) {
4586 HReg r_dstHi = newVRegF(env);
4587 HReg r_dstLo = newVRegF(env);
4588
4589 if (e->Iex.Unop.op == Iop_I64StoD128) {
4590 HReg fr_src = newVRegF(env);
4591 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4592
4593 // put the I64 value into a floating point reg
4594 if (env->mode64) {
4595 HReg tmp = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4596 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4597 } else {
4598 HReg tmpHi, tmpLo;
4599 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4600
4601 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg,
4602 IEndianess);
4603 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
4604 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
4605 }
4606
4607 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_src, zero_r1));
4608 addInstr(env, PPCInstr_DfpI64StoD128(Pfp_DCFFIXQ, r_dstHi, r_dstLo,
4609 fr_src));
4610 }
4611
4612 if (e->Iex.Unop.op == Iop_D64toD128) {
4613 HReg r_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
4614
4615 /* Source is 64bit, result is 128 bit. High 64bit source arg,
4616 * is ignored by the instruction. Set high arg to r_src just
4617 * to meet the vassert tests.
4618 */
4619 addInstr(env, PPCInstr_Dfp128Unary(Pfp_DCTQPQ, r_dstHi, r_dstLo,
4620 r_src, r_src));
4621 }
4622 *rHi = r_dstHi;
4623 *rLo = r_dstLo;
4624 return;
4625 }
4626
4627 /* --------- OPS --------- */
4628 if (e->tag == Iex_Binop) {
4629 HReg r_srcHi;
4630 HReg r_srcLo;
4631
4632 switch (e->Iex.Binop.op) {
4633 case Iop_D64HLtoD128:
4634 r_srcHi = iselDfp64Expr( env, e->Iex.Binop.arg1, IEndianess );
4635 r_srcLo = iselDfp64Expr( env, e->Iex.Binop.arg2, IEndianess );
4636 *rHi = r_srcHi;
4637 *rLo = r_srcLo;
4638 return;
4639 break;
4640 case Iop_D128toD64: {
4641 PPCFpOp fpop = Pfp_DRDPQ;
4642 HReg fr_dst = newVRegF(env);
4643
4644 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4645 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4646 IEndianess);
4647 addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
4648
4649 /* Need to meet the interface spec but the result is
4650 * just 64-bits so send the result back in both halfs.
4651 */
4652 *rHi = fr_dst;
4653 *rLo = fr_dst;
4654 return;
4655 }
4656 case Iop_ShlD128:
4657 case Iop_ShrD128: {
4658 HReg fr_dst_hi = newVRegF(env);
4659 HReg fr_dst_lo = newVRegF(env);
4660 PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
4661 PPCFpOp fpop = Pfp_DSCLIQ; /* fix later if necessary */
4662
4663 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg1,
4664 IEndianess);
4665
4666 if (e->Iex.Binop.op == Iop_ShrD128)
4667 fpop = Pfp_DSCRIQ;
4668
4669 addInstr(env, PPCInstr_DfpShift128(fpop, fr_dst_hi, fr_dst_lo,
4670 r_srcHi, r_srcLo, shift));
4671
4672 *rHi = fr_dst_hi;
4673 *rLo = fr_dst_lo;
4674 return;
4675 }
4676 case Iop_RoundD128toInt: {
4677 HReg r_dstHi = newVRegF(env);
4678 HReg r_dstLo = newVRegF(env);
4679 PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
4680
4681 // will set R and RMC when issuing instruction
4682 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4683 IEndianess);
4684
4685 addInstr(env, PPCInstr_DfpRound128(r_dstHi, r_dstLo,
4686 r_srcHi, r_srcLo, r_rmc));
4687 *rHi = r_dstHi;
4688 *rLo = r_dstLo;
4689 return;
4690 }
4691 case Iop_InsertExpD128: {
4692 HReg r_dstHi = newVRegF(env);
4693 HReg r_dstLo = newVRegF(env);
4694 HReg r_srcL = newVRegF(env);
4695 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4696 r_srcHi = newVRegF(env);
4697 r_srcLo = newVRegF(env);
4698
4699 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4700 IEndianess);
4701
4702 /* Move I64 to float register to issue instruction */
4703 if (env->mode64) {
4704 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
4705 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4706 } else {
4707 HReg tmpHi, tmpLo;
4708 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4709
4710 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg,
4711 IEndianess);
4712 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
4713 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
4714 }
4715
4716 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1));
4717 addInstr(env, PPCInstr_InsertExpD128(Pfp_DIEXQ,
4718 r_dstHi, r_dstLo,
4719 r_srcL, r_srcHi, r_srcLo));
4720 *rHi = r_dstHi;
4721 *rLo = r_dstLo;
4722 return;
4723 }
4724 default:
4725 vex_printf( "ERROR: iselDfp128Expr_wrk, UNKNOWN binop case %d\n",
4726 (Int)e->Iex.Binop.op );
4727 break;
4728 }
4729 }
4730
4731 if (e->tag == Iex_Triop) {
4732 IRTriop *triop = e->Iex.Triop.details;
4733 PPCFpOp fpop = Pfp_INVALID;
4734 HReg r_dstHi = newVRegF(env);
4735 HReg r_dstLo = newVRegF(env);
4736
4737 switch (triop->op) {
4738 case Iop_AddD128:
4739 fpop = Pfp_DFPADDQ;
4740 break;
4741 case Iop_SubD128:
4742 fpop = Pfp_DFPSUBQ;
4743 break;
4744 case Iop_MulD128:
4745 fpop = Pfp_DFPMULQ;
4746 break;
4747 case Iop_DivD128:
4748 fpop = Pfp_DFPDIVQ;
4749 break;
4750 default:
4751 break;
4752 }
4753
4754 if (fpop != Pfp_INVALID) {
4755 HReg r_srcRHi = newVRegV( env );
4756 HReg r_srcRLo = newVRegV( env );
4757
4758 /* dst will be used to pass in the left operand and get the result. */
4759 iselDfp128Expr( &r_dstHi, &r_dstLo, env, triop->arg2, IEndianess );
4760 iselDfp128Expr( &r_srcRHi, &r_srcRLo, env, triop->arg3, IEndianess );
4761 set_FPU_DFP_rounding_mode( env, triop->arg1, IEndianess );
4762 addInstr( env,
4763 PPCInstr_Dfp128Binary( fpop, r_dstHi, r_dstLo,
4764 r_srcRHi, r_srcRLo ) );
4765 *rHi = r_dstHi;
4766 *rLo = r_dstLo;
4767 return;
4768 }
4769 switch (triop->op) {
4770 case Iop_QuantizeD128: fpop = Pfp_DQUAQ; break;
4771 case Iop_SignificanceRoundD128: fpop = Pfp_DRRNDQ; break;
4772 default: break;
4773 }
4774 if (fpop == Pfp_DQUAQ) {
4775 HReg r_srcHi = newVRegF(env);
4776 HReg r_srcLo = newVRegF(env);
4777 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
4778
4779 /* dst will be used to pass in the left operand and get the result */
4780 iselDfp128Expr(&r_dstHi, &r_dstLo, env, triop->arg2, IEndianess);
4781 iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3, IEndianess);
4782
4783 // will set RMC when issuing instruction
4784 addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo,
4785 r_srcHi, r_srcLo, rmc));
4786 *rHi = r_dstHi;
4787 *rLo = r_dstLo;
4788 return;
4789
4790 } else if (fpop == Pfp_DRRNDQ) {
4791 HReg r_srcHi = newVRegF(env);
4792 HReg r_srcLo = newVRegF(env);
4793 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
4794 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4795 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4796 HReg i8_val = iselWordExpr_R(env, triop->arg2, IEndianess);
4797 HReg r_zero = newVRegI( env );
4798
4799 iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3, IEndianess);
4800
4801 /* dst will be used to pass in the left operand and get the result */
4802 /* Move I8 to float register to issue instruction. Note, the
4803 * instruction only looks at the bottom 6 bits so we really don't
4804 * have to clear the upper bits since the iselWordExpr_R sets the
4805 * bottom 8-bits.
4806 */
4807 sub_from_sp( env, 16 );
4808
4809 if (env->mode64)
4810 addInstr(env, PPCInstr_Store(4, four_r1, i8_val, True/*mode64*/));
4811 else
4812 addInstr(env, PPCInstr_Store(4, four_r1, i8_val, False/*mode32*/));
4813
4814 /* Have to write to the upper bits to ensure they have been
4815 * initialized. The instruction ignores all but the lower 6-bits.
4816 */
4817 addInstr( env, PPCInstr_LI( r_zero, 0, env->mode64 ) );
4818 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstHi, zero_r1));
4819 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstLo, zero_r1));
4820
4821 add_to_sp( env, 16 );
4822
4823 // will set RMC when issuing instruction
4824 addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo,
4825 r_srcHi, r_srcLo, rmc));
4826 *rHi = r_dstHi;
4827 *rLo = r_dstLo;
4828 return;
4829 }
4830 }
4831
4832 ppIRExpr( e );
4833 vpanic( "iselDfp128Expr(ppc64)" );
4834 }
4835
4836
4837 /*---------------------------------------------------------*/
4838 /*--- ISEL: SIMD (Vector) expressions, 128 bit. ---*/
4839 /*---------------------------------------------------------*/
4840
iselVecExpr(ISelEnv * env,IRExpr * e,IREndness IEndianess)4841 static HReg iselVecExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
4842 {
4843 HReg r = iselVecExpr_wrk( env, e, IEndianess );
4844 # if 0
4845 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4846 # endif
4847 vassert(hregClass(r) == HRcVec128);
4848 vassert(hregIsVirtual(r));
4849 return r;
4850 }
4851
4852 /* DO NOT CALL THIS DIRECTLY */
iselVecExpr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)4853 static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
4854 {
4855 Bool mode64 = env->mode64;
4856 PPCAvOp op = Pav_INVALID;
4857 PPCAvFpOp fpop = Pavfp_INVALID;
4858 IRType ty = typeOfIRExpr(env->type_env,e);
4859 vassert(e);
4860 vassert(ty == Ity_V128);
4861
4862 if (e->tag == Iex_RdTmp) {
4863 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
4864 }
4865
4866 if (e->tag == Iex_Get) {
4867 /* Guest state vectors are 16byte aligned,
4868 so don't need to worry here */
4869 HReg dst = newVRegV(env);
4870 addInstr(env,
4871 PPCInstr_AvLdSt( True/*load*/, 16, dst,
4872 PPCAMode_IR( e->Iex.Get.offset,
4873 GuestStatePtr(mode64) )));
4874 return dst;
4875 }
4876
4877 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4878 /* Need to be able to do V128 unaligned loads. The BE unaligned load
4879 * can be accomplised using the following code sequece from the ISA.
4880 * It uses the lvx instruction that does two aligned loads and then
4881 * permute the data to store the required data as if it had been an
4882 * unaligned load.
4883 *
4884 * lvx Vhi,0,Rb # load MSQ, using the unaligned address in Rb
4885 * lvsl Vp, 0,Rb # Set permute control vector
4886 * addi Rb,Rb,15 # Address of LSQ
4887 * lvx Vlo,0,Rb # load LSQ
4888 * vperm Vt,Vhi,Vlo,Vp # align the data as requested
4889 */
4890
4891 HReg Vhi = newVRegV(env);
4892 HReg Vlo = newVRegV(env);
4893 HReg Vp = newVRegV(env);
4894 HReg v_dst = newVRegV(env);
4895 HReg rB;
4896 HReg rB_plus_15 = newVRegI(env);
4897
4898 vassert(e->Iex.Load.ty == Ity_V128);
4899 rB = iselWordExpr_R( env, e->Iex.Load.addr, IEndianess );
4900
4901 // lvx Vhi, 0, Rb
4902 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vhi,
4903 PPCAMode_IR(0, rB)) );
4904
4905 if (IEndianess == Iend_LE)
4906 // lvsr Vp, 0, Rb
4907 addInstr(env, PPCInstr_AvSh( False/*right shift*/, Vp,
4908 PPCAMode_IR(0, rB)) );
4909 else
4910 // lvsl Vp, 0, Rb
4911 addInstr(env, PPCInstr_AvSh( True/*left shift*/, Vp,
4912 PPCAMode_IR(0, rB)) );
4913
4914 // addi Rb_plus_15, Rb, 15
4915 addInstr(env, PPCInstr_Alu( Palu_ADD, rB_plus_15,
4916 rB, PPCRH_Imm(True, toUShort(15))) );
4917
4918 // lvx Vlo, 0, Rb_plus_15
4919 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vlo,
4920 PPCAMode_IR(0, rB_plus_15)) );
4921
4922 if (IEndianess == Iend_LE)
4923 // vperm Vt, Vhi, Vlo, Vp
4924 addInstr(env, PPCInstr_AvPerm( v_dst, Vlo, Vhi, Vp ));
4925 else
4926 // vperm Vt, Vhi, Vlo, Vp
4927 addInstr(env, PPCInstr_AvPerm( v_dst, Vhi, Vlo, Vp ));
4928
4929 return v_dst;
4930 }
4931
4932 if (e->tag == Iex_Unop) {
4933 switch (e->Iex.Unop.op) {
4934
4935 case Iop_NotV128: {
4936 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4937 HReg dst = newVRegV(env);
4938 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, arg));
4939 return dst;
4940 }
4941
4942 case Iop_CmpNEZ8x16: {
4943 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4944 HReg zero = newVRegV(env);
4945 HReg dst = newVRegV(env);
4946 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4947 addInstr(env, PPCInstr_AvBin8x16(Pav_CMPEQU, dst, arg, zero));
4948 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4949 return dst;
4950 }
4951
4952 case Iop_CmpNEZ16x8: {
4953 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4954 HReg zero = newVRegV(env);
4955 HReg dst = newVRegV(env);
4956 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4957 addInstr(env, PPCInstr_AvBin16x8(Pav_CMPEQU, dst, arg, zero));
4958 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4959 return dst;
4960 }
4961
4962 case Iop_CmpNEZ32x4: {
4963 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4964 HReg zero = newVRegV(env);
4965 HReg dst = newVRegV(env);
4966 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4967 addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, dst, arg, zero));
4968 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4969 return dst;
4970 }
4971
4972 case Iop_CmpNEZ64x2: {
4973 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4974 HReg zero = newVRegV(env);
4975 HReg dst = newVRegV(env);
4976 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4977 addInstr(env, PPCInstr_AvBin64x2(Pav_CMPEQU, dst, arg, zero));
4978 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4979 return dst;
4980 }
4981
4982 case Iop_RecipEst32Fx4: fpop = Pavfp_RCPF; goto do_32Fx4_unary;
4983 case Iop_RSqrtEst32Fx4: fpop = Pavfp_RSQRTF; goto do_32Fx4_unary;
4984 case Iop_I32UtoFx4: fpop = Pavfp_CVTU2F; goto do_32Fx4_unary;
4985 case Iop_I32StoFx4: fpop = Pavfp_CVTS2F; goto do_32Fx4_unary;
4986 case Iop_QFtoI32Ux4_RZ: fpop = Pavfp_QCVTF2U; goto do_32Fx4_unary;
4987 case Iop_QFtoI32Sx4_RZ: fpop = Pavfp_QCVTF2S; goto do_32Fx4_unary;
4988 case Iop_RoundF32x4_RM: fpop = Pavfp_ROUNDM; goto do_32Fx4_unary;
4989 case Iop_RoundF32x4_RP: fpop = Pavfp_ROUNDP; goto do_32Fx4_unary;
4990 case Iop_RoundF32x4_RN: fpop = Pavfp_ROUNDN; goto do_32Fx4_unary;
4991 case Iop_RoundF32x4_RZ: fpop = Pavfp_ROUNDZ; goto do_32Fx4_unary;
4992 do_32Fx4_unary:
4993 {
4994 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4995 HReg dst = newVRegV(env);
4996 addInstr(env, PPCInstr_AvUn32Fx4(fpop, dst, arg));
4997 return dst;
4998 }
4999
5000 case Iop_32UtoV128: {
5001 HReg r_aligned16, r_zeros;
5002 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
5003 HReg dst = newVRegV(env);
5004 PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
5005 sub_from_sp( env, 32 ); // Move SP down
5006
5007 /* Get a quadword aligned address within our stack space */
5008 r_aligned16 = get_sp_aligned16( env );
5009 am_off0 = PPCAMode_IR( 0, r_aligned16 );
5010 am_off4 = PPCAMode_IR( 4, r_aligned16 );
5011 am_off8 = PPCAMode_IR( 8, r_aligned16 );
5012 am_off12 = PPCAMode_IR( 12, r_aligned16 );
5013
5014 /* Store zeros */
5015 r_zeros = newVRegI(env);
5016 addInstr(env, PPCInstr_LI(r_zeros, 0x0, mode64));
5017 if (IEndianess == Iend_LE)
5018 addInstr(env, PPCInstr_Store( 4, am_off0, r_src, mode64 ));
5019 else
5020 addInstr(env, PPCInstr_Store( 4, am_off0, r_zeros, mode64 ));
5021 addInstr(env, PPCInstr_Store( 4, am_off4, r_zeros, mode64 ));
5022 addInstr(env, PPCInstr_Store( 4, am_off8, r_zeros, mode64 ));
5023
5024 /* Store r_src in low word of quadword-aligned mem */
5025 if (IEndianess == Iend_LE)
5026 addInstr(env, PPCInstr_Store( 4, am_off12, r_zeros, mode64 ));
5027 else
5028 addInstr(env, PPCInstr_Store( 4, am_off12, r_src, mode64 ));
5029
5030 /* Load word into low word of quadword vector reg */
5031 if (IEndianess == Iend_LE)
5032 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off0 ));
5033 else
5034 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off12 ));
5035
5036 add_to_sp( env, 32 ); // Reset SP
5037 return dst;
5038 }
5039
5040 case Iop_Dup8x16:
5041 case Iop_Dup16x8:
5042 case Iop_Dup32x4:
5043 return mk_AvDuplicateRI(env, e->Iex.Unop.arg, IEndianess);
5044
5045 case Iop_CipherSV128: op = Pav_CIPHERSUBV128; goto do_AvCipherV128Un;
5046 do_AvCipherV128Un: {
5047 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5048 HReg dst = newVRegV(env);
5049 addInstr(env, PPCInstr_AvCipherV128Unary(op, dst, arg));
5050 return dst;
5051 }
5052
5053 case Iop_Clz8x16: op = Pav_ZEROCNTBYTE; goto do_zerocnt;
5054 case Iop_Clz16x8: op = Pav_ZEROCNTHALF; goto do_zerocnt;
5055 case Iop_Clz32x4: op = Pav_ZEROCNTWORD; goto do_zerocnt;
5056 case Iop_Clz64x2: op = Pav_ZEROCNTDBL; goto do_zerocnt;
5057 case Iop_PwBitMtxXpose64x2: op = Pav_BITMTXXPOSE; goto do_zerocnt;
5058 do_zerocnt:
5059 {
5060 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5061 HReg dst = newVRegV(env);
5062 addInstr(env, PPCInstr_AvUnary(op, dst, arg));
5063 return dst;
5064 }
5065
5066 default:
5067 break;
5068 } /* switch (e->Iex.Unop.op) */
5069 } /* if (e->tag == Iex_Unop) */
5070
5071 if (e->tag == Iex_Binop) {
5072 switch (e->Iex.Binop.op) {
5073
5074 case Iop_64HLtoV128: {
5075 if (!mode64) {
5076 HReg r3, r2, r1, r0, r_aligned16;
5077 PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
5078 HReg dst = newVRegV(env);
5079 /* do this via the stack (easy, convenient, etc) */
5080 sub_from_sp( env, 32 ); // Move SP down
5081
5082 // get a quadword aligned address within our stack space
5083 r_aligned16 = get_sp_aligned16( env );
5084 am_off0 = PPCAMode_IR( 0, r_aligned16 );
5085 am_off4 = PPCAMode_IR( 4, r_aligned16 );
5086 am_off8 = PPCAMode_IR( 8, r_aligned16 );
5087 am_off12 = PPCAMode_IR( 12, r_aligned16 );
5088
5089 /* Do the less significant 64 bits */
5090 iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2, IEndianess);
5091 addInstr(env, PPCInstr_Store( 4, am_off12, r0, mode64 ));
5092 addInstr(env, PPCInstr_Store( 4, am_off8, r1, mode64 ));
5093 /* Do the more significant 64 bits */
5094 iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1, IEndianess);
5095 addInstr(env, PPCInstr_Store( 4, am_off4, r2, mode64 ));
5096 addInstr(env, PPCInstr_Store( 4, am_off0, r3, mode64 ));
5097
5098 /* Fetch result back from stack. */
5099 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
5100
5101 add_to_sp( env, 32 ); // Reset SP
5102 return dst;
5103 } else {
5104 HReg rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
5105 HReg rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
5106 HReg dst = newVRegV(env);
5107 HReg r_aligned16;
5108 PPCAMode *am_off0, *am_off8;
5109 /* do this via the stack (easy, convenient, etc) */
5110 sub_from_sp( env, 32 ); // Move SP down
5111
5112 // get a quadword aligned address within our stack space
5113 r_aligned16 = get_sp_aligned16( env );
5114 am_off0 = PPCAMode_IR( 0, r_aligned16 );
5115 am_off8 = PPCAMode_IR( 8, r_aligned16 );
5116
5117 /* Store 2*I64 to stack */
5118 if (IEndianess == Iend_LE) {
5119 addInstr(env, PPCInstr_Store( 8, am_off0, rLo, mode64 ));
5120 addInstr(env, PPCInstr_Store( 8, am_off8, rHi, mode64 ));
5121 } else {
5122 addInstr(env, PPCInstr_Store( 8, am_off0, rHi, mode64 ));
5123 addInstr(env, PPCInstr_Store( 8, am_off8, rLo, mode64 ));
5124 }
5125 /* Fetch result back from stack. */
5126 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
5127
5128 add_to_sp( env, 32 ); // Reset SP
5129 return dst;
5130 }
5131 }
5132
5133 case Iop_Max32Fx4: fpop = Pavfp_MAXF; goto do_32Fx4;
5134 case Iop_Min32Fx4: fpop = Pavfp_MINF; goto do_32Fx4;
5135 case Iop_CmpEQ32Fx4: fpop = Pavfp_CMPEQF; goto do_32Fx4;
5136 case Iop_CmpGT32Fx4: fpop = Pavfp_CMPGTF; goto do_32Fx4;
5137 case Iop_CmpGE32Fx4: fpop = Pavfp_CMPGEF; goto do_32Fx4;
5138 do_32Fx4:
5139 {
5140 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5141 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5142 HReg dst = newVRegV(env);
5143 addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
5144 return dst;
5145 }
5146
5147 case Iop_CmpLE32Fx4: {
5148 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5149 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5150 HReg dst = newVRegV(env);
5151
5152 /* stay consistent with native ppc compares:
5153 if a left/right lane holds a nan, return zeros for that lane
5154 so: le == NOT(gt OR isNan)
5155 */
5156 HReg isNanLR = newVRegV(env);
5157 HReg isNanL = isNan(env, argL, IEndianess);
5158 HReg isNanR = isNan(env, argR, IEndianess);
5159 addInstr(env, PPCInstr_AvBinary(Pav_OR, isNanLR,
5160 isNanL, isNanR));
5161
5162 addInstr(env, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF, dst,
5163 argL, argR));
5164 addInstr(env, PPCInstr_AvBinary(Pav_OR, dst, dst, isNanLR));
5165 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
5166 return dst;
5167 }
5168
5169 case Iop_AndV128: op = Pav_AND; goto do_AvBin;
5170 case Iop_OrV128: op = Pav_OR; goto do_AvBin;
5171 case Iop_XorV128: op = Pav_XOR; goto do_AvBin;
5172 do_AvBin: {
5173 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5174 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5175 HReg dst = newVRegV(env);
5176 addInstr(env, PPCInstr_AvBinary(op, dst, arg1, arg2));
5177 return dst;
5178 }
5179
5180 case Iop_Shl8x16: op = Pav_SHL; goto do_AvBin8x16;
5181 case Iop_Shr8x16: op = Pav_SHR; goto do_AvBin8x16;
5182 case Iop_Sar8x16: op = Pav_SAR; goto do_AvBin8x16;
5183 case Iop_Rol8x16: op = Pav_ROTL; goto do_AvBin8x16;
5184 case Iop_InterleaveHI8x16: op = Pav_MRGHI; goto do_AvBin8x16;
5185 case Iop_InterleaveLO8x16: op = Pav_MRGLO; goto do_AvBin8x16;
5186 case Iop_Add8x16: op = Pav_ADDU; goto do_AvBin8x16;
5187 case Iop_QAdd8Ux16: op = Pav_QADDU; goto do_AvBin8x16;
5188 case Iop_QAdd8Sx16: op = Pav_QADDS; goto do_AvBin8x16;
5189 case Iop_Sub8x16: op = Pav_SUBU; goto do_AvBin8x16;
5190 case Iop_QSub8Ux16: op = Pav_QSUBU; goto do_AvBin8x16;
5191 case Iop_QSub8Sx16: op = Pav_QSUBS; goto do_AvBin8x16;
5192 case Iop_Avg8Ux16: op = Pav_AVGU; goto do_AvBin8x16;
5193 case Iop_Avg8Sx16: op = Pav_AVGS; goto do_AvBin8x16;
5194 case Iop_Max8Ux16: op = Pav_MAXU; goto do_AvBin8x16;
5195 case Iop_Max8Sx16: op = Pav_MAXS; goto do_AvBin8x16;
5196 case Iop_Min8Ux16: op = Pav_MINU; goto do_AvBin8x16;
5197 case Iop_Min8Sx16: op = Pav_MINS; goto do_AvBin8x16;
5198 case Iop_MullEven8Ux16: op = Pav_OMULU; goto do_AvBin8x16;
5199 case Iop_MullEven8Sx16: op = Pav_OMULS; goto do_AvBin8x16;
5200 case Iop_CmpEQ8x16: op = Pav_CMPEQU; goto do_AvBin8x16;
5201 case Iop_CmpGT8Ux16: op = Pav_CMPGTU; goto do_AvBin8x16;
5202 case Iop_CmpGT8Sx16: op = Pav_CMPGTS; goto do_AvBin8x16;
5203 case Iop_PolynomialMulAdd8x16: op = Pav_POLYMULADD; goto do_AvBin8x16;
5204 do_AvBin8x16: {
5205 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5206 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5207 HReg dst = newVRegV(env);
5208 addInstr(env, PPCInstr_AvBin8x16(op, dst, arg1, arg2));
5209 return dst;
5210 }
5211
5212 case Iop_Shl16x8: op = Pav_SHL; goto do_AvBin16x8;
5213 case Iop_Shr16x8: op = Pav_SHR; goto do_AvBin16x8;
5214 case Iop_Sar16x8: op = Pav_SAR; goto do_AvBin16x8;
5215 case Iop_Rol16x8: op = Pav_ROTL; goto do_AvBin16x8;
5216 case Iop_NarrowBin16to8x16: op = Pav_PACKUU; goto do_AvBin16x8;
5217 case Iop_QNarrowBin16Uto8Ux16: op = Pav_QPACKUU; goto do_AvBin16x8;
5218 case Iop_QNarrowBin16Sto8Sx16: op = Pav_QPACKSS; goto do_AvBin16x8;
5219 case Iop_InterleaveHI16x8: op = Pav_MRGHI; goto do_AvBin16x8;
5220 case Iop_InterleaveLO16x8: op = Pav_MRGLO; goto do_AvBin16x8;
5221 case Iop_Add16x8: op = Pav_ADDU; goto do_AvBin16x8;
5222 case Iop_QAdd16Ux8: op = Pav_QADDU; goto do_AvBin16x8;
5223 case Iop_QAdd16Sx8: op = Pav_QADDS; goto do_AvBin16x8;
5224 case Iop_Sub16x8: op = Pav_SUBU; goto do_AvBin16x8;
5225 case Iop_QSub16Ux8: op = Pav_QSUBU; goto do_AvBin16x8;
5226 case Iop_QSub16Sx8: op = Pav_QSUBS; goto do_AvBin16x8;
5227 case Iop_Avg16Ux8: op = Pav_AVGU; goto do_AvBin16x8;
5228 case Iop_Avg16Sx8: op = Pav_AVGS; goto do_AvBin16x8;
5229 case Iop_Max16Ux8: op = Pav_MAXU; goto do_AvBin16x8;
5230 case Iop_Max16Sx8: op = Pav_MAXS; goto do_AvBin16x8;
5231 case Iop_Min16Ux8: op = Pav_MINU; goto do_AvBin16x8;
5232 case Iop_Min16Sx8: op = Pav_MINS; goto do_AvBin16x8;
5233 case Iop_MullEven16Ux8: op = Pav_OMULU; goto do_AvBin16x8;
5234 case Iop_MullEven16Sx8: op = Pav_OMULS; goto do_AvBin16x8;
5235 case Iop_CmpEQ16x8: op = Pav_CMPEQU; goto do_AvBin16x8;
5236 case Iop_CmpGT16Ux8: op = Pav_CMPGTU; goto do_AvBin16x8;
5237 case Iop_CmpGT16Sx8: op = Pav_CMPGTS; goto do_AvBin16x8;
5238 case Iop_PolynomialMulAdd16x8: op = Pav_POLYMULADD; goto do_AvBin16x8;
5239 do_AvBin16x8: {
5240 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5241 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5242 HReg dst = newVRegV(env);
5243 addInstr(env, PPCInstr_AvBin16x8(op, dst, arg1, arg2));
5244 return dst;
5245 }
5246
5247 case Iop_Shl32x4: op = Pav_SHL; goto do_AvBin32x4;
5248 case Iop_Shr32x4: op = Pav_SHR; goto do_AvBin32x4;
5249 case Iop_Sar32x4: op = Pav_SAR; goto do_AvBin32x4;
5250 case Iop_Rol32x4: op = Pav_ROTL; goto do_AvBin32x4;
5251 case Iop_NarrowBin32to16x8: op = Pav_PACKUU; goto do_AvBin32x4;
5252 case Iop_QNarrowBin32Uto16Ux8: op = Pav_QPACKUU; goto do_AvBin32x4;
5253 case Iop_QNarrowBin32Sto16Sx8: op = Pav_QPACKSS; goto do_AvBin32x4;
5254 case Iop_InterleaveHI32x4: op = Pav_MRGHI; goto do_AvBin32x4;
5255 case Iop_InterleaveLO32x4: op = Pav_MRGLO; goto do_AvBin32x4;
5256 case Iop_Add32x4: op = Pav_ADDU; goto do_AvBin32x4;
5257 case Iop_QAdd32Ux4: op = Pav_QADDU; goto do_AvBin32x4;
5258 case Iop_QAdd32Sx4: op = Pav_QADDS; goto do_AvBin32x4;
5259 case Iop_Sub32x4: op = Pav_SUBU; goto do_AvBin32x4;
5260 case Iop_QSub32Ux4: op = Pav_QSUBU; goto do_AvBin32x4;
5261 case Iop_QSub32Sx4: op = Pav_QSUBS; goto do_AvBin32x4;
5262 case Iop_Avg32Ux4: op = Pav_AVGU; goto do_AvBin32x4;
5263 case Iop_Avg32Sx4: op = Pav_AVGS; goto do_AvBin32x4;
5264 case Iop_Max32Ux4: op = Pav_MAXU; goto do_AvBin32x4;
5265 case Iop_Max32Sx4: op = Pav_MAXS; goto do_AvBin32x4;
5266 case Iop_Min32Ux4: op = Pav_MINU; goto do_AvBin32x4;
5267 case Iop_Min32Sx4: op = Pav_MINS; goto do_AvBin32x4;
5268 case Iop_Mul32x4: op = Pav_MULU; goto do_AvBin32x4;
5269 case Iop_MullEven32Ux4: op = Pav_OMULU; goto do_AvBin32x4;
5270 case Iop_MullEven32Sx4: op = Pav_OMULS; goto do_AvBin32x4;
5271 case Iop_CmpEQ32x4: op = Pav_CMPEQU; goto do_AvBin32x4;
5272 case Iop_CmpGT32Ux4: op = Pav_CMPGTU; goto do_AvBin32x4;
5273 case Iop_CmpGT32Sx4: op = Pav_CMPGTS; goto do_AvBin32x4;
5274 case Iop_CatOddLanes32x4: op = Pav_CATODD; goto do_AvBin32x4;
5275 case Iop_CatEvenLanes32x4: op = Pav_CATEVEN; goto do_AvBin32x4;
5276 case Iop_PolynomialMulAdd32x4: op = Pav_POLYMULADD; goto do_AvBin32x4;
5277 do_AvBin32x4: {
5278 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5279 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5280 HReg dst = newVRegV(env);
5281 addInstr(env, PPCInstr_AvBin32x4(op, dst, arg1, arg2));
5282 return dst;
5283 }
5284
5285 case Iop_Shl64x2: op = Pav_SHL; goto do_AvBin64x2;
5286 case Iop_Shr64x2: op = Pav_SHR; goto do_AvBin64x2;
5287 case Iop_Sar64x2: op = Pav_SAR; goto do_AvBin64x2;
5288 case Iop_Rol64x2: op = Pav_ROTL; goto do_AvBin64x2;
5289 case Iop_NarrowBin64to32x4: op = Pav_PACKUU; goto do_AvBin64x2;
5290 case Iop_QNarrowBin64Sto32Sx4: op = Pav_QPACKSS; goto do_AvBin64x2;
5291 case Iop_QNarrowBin64Uto32Ux4: op = Pav_QPACKUU; goto do_AvBin64x2;
5292 case Iop_InterleaveHI64x2: op = Pav_MRGHI; goto do_AvBin64x2;
5293 case Iop_InterleaveLO64x2: op = Pav_MRGLO; goto do_AvBin64x2;
5294 case Iop_Add64x2: op = Pav_ADDU; goto do_AvBin64x2;
5295 case Iop_Sub64x2: op = Pav_SUBU; goto do_AvBin64x2;
5296 case Iop_Max64Ux2: op = Pav_MAXU; goto do_AvBin64x2;
5297 case Iop_Max64Sx2: op = Pav_MAXS; goto do_AvBin64x2;
5298 case Iop_Min64Ux2: op = Pav_MINU; goto do_AvBin64x2;
5299 case Iop_Min64Sx2: op = Pav_MINS; goto do_AvBin64x2;
5300 case Iop_CmpEQ64x2: op = Pav_CMPEQU; goto do_AvBin64x2;
5301 case Iop_CmpGT64Ux2: op = Pav_CMPGTU; goto do_AvBin64x2;
5302 case Iop_CmpGT64Sx2: op = Pav_CMPGTS; goto do_AvBin64x2;
5303 case Iop_PolynomialMulAdd64x2: op = Pav_POLYMULADD; goto do_AvBin64x2;
5304 do_AvBin64x2: {
5305 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5306 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5307 HReg dst = newVRegV(env);
5308 addInstr(env, PPCInstr_AvBin64x2(op, dst, arg1, arg2));
5309 return dst;
5310 }
5311
5312 case Iop_ShlN8x16: op = Pav_SHL; goto do_AvShift8x16;
5313 case Iop_SarN8x16: op = Pav_SAR; goto do_AvShift8x16;
5314 do_AvShift8x16: {
5315 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5316 HReg dst = newVRegV(env);
5317 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5318 addInstr(env, PPCInstr_AvBin8x16(op, dst, r_src, v_shft));
5319 return dst;
5320 }
5321
5322 case Iop_ShlN16x8: op = Pav_SHL; goto do_AvShift16x8;
5323 case Iop_ShrN16x8: op = Pav_SHR; goto do_AvShift16x8;
5324 case Iop_SarN16x8: op = Pav_SAR; goto do_AvShift16x8;
5325 do_AvShift16x8: {
5326 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5327 HReg dst = newVRegV(env);
5328 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5329 addInstr(env, PPCInstr_AvBin16x8(op, dst, r_src, v_shft));
5330 return dst;
5331 }
5332
5333 case Iop_ShlN32x4: op = Pav_SHL; goto do_AvShift32x4;
5334 case Iop_ShrN32x4: op = Pav_SHR; goto do_AvShift32x4;
5335 case Iop_SarN32x4: op = Pav_SAR; goto do_AvShift32x4;
5336 do_AvShift32x4: {
5337 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5338 HReg dst = newVRegV(env);
5339 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5340 addInstr(env, PPCInstr_AvBin32x4(op, dst, r_src, v_shft));
5341 return dst;
5342 }
5343
5344 case Iop_ShlN64x2: op = Pav_SHL; goto do_AvShift64x2;
5345 case Iop_ShrN64x2: op = Pav_SHR; goto do_AvShift64x2;
5346 case Iop_SarN64x2: op = Pav_SAR; goto do_AvShift64x2;
5347 do_AvShift64x2: {
5348 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5349 HReg dst = newVRegV(env);
5350 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5351 addInstr(env, PPCInstr_AvBin64x2(op, dst, r_src, v_shft));
5352 return dst;
5353 }
5354
5355 case Iop_ShrV128: op = Pav_SHR; goto do_AvShiftV128;
5356 case Iop_ShlV128: op = Pav_SHL; goto do_AvShiftV128;
5357 do_AvShiftV128: {
5358 HReg dst = newVRegV(env);
5359 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5360 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5361 /* Note: shift value gets masked by 127 */
5362 addInstr(env, PPCInstr_AvBinary(op, dst, r_src, v_shft));
5363 return dst;
5364 }
5365
5366 case Iop_Perm8x16: {
5367 HReg dst = newVRegV(env);
5368 HReg v_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5369 HReg v_ctl = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5370 addInstr(env, PPCInstr_AvPerm(dst, v_src, v_src, v_ctl));
5371 return dst;
5372 }
5373
5374 case Iop_CipherV128: op = Pav_CIPHERV128; goto do_AvCipherV128;
5375 case Iop_CipherLV128: op = Pav_CIPHERLV128; goto do_AvCipherV128;
5376 case Iop_NCipherV128: op = Pav_NCIPHERV128; goto do_AvCipherV128;
5377 case Iop_NCipherLV128:op = Pav_NCIPHERLV128; goto do_AvCipherV128;
5378 do_AvCipherV128: {
5379 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5380 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5381 HReg dst = newVRegV(env);
5382 addInstr(env, PPCInstr_AvCipherV128Binary(op, dst, arg1, arg2));
5383 return dst;
5384 }
5385
5386 case Iop_SHA256:op = Pav_SHA256; goto do_AvHashV128;
5387 case Iop_SHA512:op = Pav_SHA512; goto do_AvHashV128;
5388 do_AvHashV128: {
5389 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5390 HReg dst = newVRegV(env);
5391 PPCRI* s_field = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
5392 addInstr(env, PPCInstr_AvHashV128Binary(op, dst, arg1, s_field));
5393 return dst;
5394 }
5395 default:
5396 break;
5397 } /* switch (e->Iex.Binop.op) */
5398 } /* if (e->tag == Iex_Binop) */
5399
5400 if (e->tag == Iex_Triop) {
5401 IRTriop *triop = e->Iex.Triop.details;
5402 switch (triop->op) {
5403 case Iop_BCDAdd:op = Pav_BCDAdd; goto do_AvBCDV128;
5404 case Iop_BCDSub:op = Pav_BCDSub; goto do_AvBCDV128;
5405 do_AvBCDV128: {
5406 HReg arg1 = iselVecExpr(env, triop->arg1, IEndianess);
5407 HReg arg2 = iselVecExpr(env, triop->arg2, IEndianess);
5408 HReg dst = newVRegV(env);
5409 PPCRI* ps = iselWordExpr_RI(env, triop->arg3, IEndianess);
5410 addInstr(env, PPCInstr_AvBCDV128Trinary(op, dst, arg1, arg2, ps));
5411 return dst;
5412 }
5413
5414 case Iop_Add32Fx4: fpop = Pavfp_ADDF; goto do_32Fx4_with_rm;
5415 case Iop_Sub32Fx4: fpop = Pavfp_SUBF; goto do_32Fx4_with_rm;
5416 case Iop_Mul32Fx4: fpop = Pavfp_MULF; goto do_32Fx4_with_rm;
5417 do_32Fx4_with_rm:
5418 {
5419 HReg argL = iselVecExpr(env, triop->arg2, IEndianess);
5420 HReg argR = iselVecExpr(env, triop->arg3, IEndianess);
5421 HReg dst = newVRegV(env);
5422 /* FIXME: this is bogus, in the sense that Altivec ignores
5423 FPSCR.RM, at least for some FP operations. So setting the
5424 RM is pointless. This is only really correct in the case
5425 where the RM is known, at JIT time, to be Irrm_NEAREST,
5426 since -- at least for Altivec FP add/sub/mul -- the
5427 emitted insn is hardwired to round to nearest. */
5428 set_FPU_rounding_mode(env, triop->arg1, IEndianess);
5429 addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
5430 return dst;
5431 }
5432
5433 default:
5434 break;
5435 } /* switch (e->Iex.Triop.op) */
5436 } /* if (e->tag == Iex_Trinop) */
5437
5438
5439 if (e->tag == Iex_Const ) {
5440 vassert(e->Iex.Const.con->tag == Ico_V128);
5441 if (e->Iex.Const.con->Ico.V128 == 0x0000) {
5442 return generate_zeroes_V128(env);
5443 }
5444 else if (e->Iex.Const.con->Ico.V128 == 0xffff) {
5445 return generate_ones_V128(env);
5446 }
5447 }
5448
5449 vex_printf("iselVecExpr(ppc) (subarch = %s): can't reduce\n",
5450 LibVEX_ppVexHwCaps(mode64 ? VexArchPPC64 : VexArchPPC32,
5451 env->hwcaps));
5452 ppIRExpr(e);
5453 vpanic("iselVecExpr_wrk(ppc)");
5454 }
5455
5456
5457 /*---------------------------------------------------------*/
5458 /*--- ISEL: Statements ---*/
5459 /*---------------------------------------------------------*/
5460
iselStmt(ISelEnv * env,IRStmt * stmt,IREndness IEndianess)5461 static void iselStmt ( ISelEnv* env, IRStmt* stmt, IREndness IEndianess )
5462 {
5463 Bool mode64 = env->mode64;
5464 if (vex_traceflags & VEX_TRACE_VCODE) {
5465 vex_printf("\n -- ");
5466 ppIRStmt(stmt);
5467 vex_printf("\n");
5468 }
5469
5470 switch (stmt->tag) {
5471
5472 /* --------- STORE --------- */
5473 case Ist_Store: {
5474 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
5475 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
5476 IREndness end = stmt->Ist.Store.end;
5477
5478 if (end != IEndianess)
5479 goto stmt_fail;
5480 if (!mode64 && (tya != Ity_I32))
5481 goto stmt_fail;
5482 if (mode64 && (tya != Ity_I64))
5483 goto stmt_fail;
5484
5485 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
5486 (mode64 && (tyd == Ity_I64))) {
5487 PPCAMode* am_addr
5488 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5489 IEndianess);
5490 HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data, IEndianess);
5491 addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(tyd)),
5492 am_addr, r_src, mode64 ));
5493 return;
5494 }
5495 if (tyd == Ity_F64) {
5496 PPCAMode* am_addr
5497 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5498 IEndianess);
5499 HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data, IEndianess);
5500 addInstr(env,
5501 PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
5502 return;
5503 }
5504 if (tyd == Ity_F32) {
5505 PPCAMode* am_addr
5506 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5507 IEndianess);
5508 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data, IEndianess);
5509 addInstr(env,
5510 PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
5511 return;
5512 }
5513 if (tyd == Ity_D64) {
5514 PPCAMode* am_addr
5515 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5516 IEndianess);
5517 HReg fr_src = iselDfp64Expr(env, stmt->Ist.Store.data, IEndianess);
5518 addInstr(env,
5519 PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
5520 return;
5521 }
5522 if (tyd == Ity_D32) {
5523 PPCAMode* am_addr
5524 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5525 IEndianess);
5526 HReg fr_src = iselDfp32Expr(env, stmt->Ist.Store.data, IEndianess);
5527 addInstr(env,
5528 PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
5529 return;
5530 }
5531 if (tyd == Ity_V128) {
5532 PPCAMode* am_addr
5533 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5534 IEndianess);
5535 HReg v_src = iselVecExpr(env, stmt->Ist.Store.data, IEndianess);
5536 addInstr(env,
5537 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
5538 return;
5539 }
5540 if (tyd == Ity_I64 && !mode64) {
5541 /* Just calculate the address in the register. Life is too
5542 short to arse around trying and possibly failing to adjust
5543 the offset in a 'reg+offset' style amode. */
5544 HReg rHi32, rLo32;
5545 HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr, IEndianess);
5546 iselInt64Expr( &rHi32, &rLo32, env, stmt->Ist.Store.data,
5547 IEndianess );
5548 addInstr(env, PPCInstr_Store( 4/*byte-store*/,
5549 PPCAMode_IR( 0, r_addr ),
5550 rHi32,
5551 False/*32-bit insn please*/) );
5552 addInstr(env, PPCInstr_Store( 4/*byte-store*/,
5553 PPCAMode_IR( 4, r_addr ),
5554 rLo32,
5555 False/*32-bit insn please*/) );
5556 return;
5557 }
5558 break;
5559 }
5560
5561 /* --------- PUT --------- */
5562 case Ist_Put: {
5563 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
5564 if (ty == Ity_I8 || ty == Ity_I16 ||
5565 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
5566 HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data, IEndianess);
5567 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5568 GuestStatePtr(mode64) );
5569 addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(ty)),
5570 am_addr, r_src, mode64 ));
5571 return;
5572 }
5573 if (!mode64 && ty == Ity_I64) {
5574 HReg rHi, rLo;
5575 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5576 GuestStatePtr(mode64) );
5577 PPCAMode* am_addr4 = advance4(env, am_addr);
5578 iselInt64Expr(&rHi,&rLo, env, stmt->Ist.Put.data, IEndianess);
5579 addInstr(env, PPCInstr_Store( 4, am_addr, rHi, mode64 ));
5580 addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 ));
5581 return;
5582 }
5583 if (ty == Ity_V128) {
5584 /* Guest state vectors are 16byte aligned,
5585 so don't need to worry here */
5586 HReg v_src = iselVecExpr(env, stmt->Ist.Put.data, IEndianess);
5587 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5588 GuestStatePtr(mode64) );
5589 addInstr(env,
5590 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
5591 return;
5592 }
5593 if (ty == Ity_F64) {
5594 HReg fr_src = iselDblExpr(env, stmt->Ist.Put.data, IEndianess);
5595 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5596 GuestStatePtr(mode64) );
5597 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
5598 fr_src, am_addr ));
5599 return;
5600 }
5601 if (ty == Ity_D32) {
5602 /* The 32-bit value is stored in a 64-bit register */
5603 HReg fr_src = iselDfp32Expr( env, stmt->Ist.Put.data, IEndianess );
5604 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5605 GuestStatePtr(mode64) );
5606 addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8,
5607 fr_src, am_addr ) );
5608 return;
5609 }
5610 if (ty == Ity_D64) {
5611 HReg fr_src = iselDfp64Expr( env, stmt->Ist.Put.data, IEndianess );
5612 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5613 GuestStatePtr(mode64) );
5614 addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8, fr_src, am_addr ) );
5615 return;
5616 }
5617 break;
5618 }
5619
5620 /* --------- Indexed PUT --------- */
5621 case Ist_PutI: {
5622 IRPutI *puti = stmt->Ist.PutI.details;
5623
5624 PPCAMode* dst_am
5625 = genGuestArrayOffset(
5626 env, puti->descr,
5627 puti->ix, puti->bias,
5628 IEndianess );
5629 IRType ty = typeOfIRExpr(env->type_env, puti->data);
5630 if (mode64 && ty == Ity_I64) {
5631 HReg r_src = iselWordExpr_R(env, puti->data, IEndianess);
5632 addInstr(env, PPCInstr_Store( toUChar(8),
5633 dst_am, r_src, mode64 ));
5634 return;
5635 }
5636 if ((!mode64) && ty == Ity_I32) {
5637 HReg r_src = iselWordExpr_R(env, puti->data, IEndianess);
5638 addInstr(env, PPCInstr_Store( toUChar(4),
5639 dst_am, r_src, mode64 ));
5640 return;
5641 }
5642 break;
5643 }
5644
5645 /* --------- TMP --------- */
5646 case Ist_WrTmp: {
5647 IRTemp tmp = stmt->Ist.WrTmp.tmp;
5648 IRType ty = typeOfIRTemp(env->type_env, tmp);
5649 if (ty == Ity_I8 || ty == Ity_I16 ||
5650 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
5651 HReg r_dst = lookupIRTemp(env, tmp);
5652 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data, IEndianess);
5653 addInstr(env, mk_iMOVds_RR( r_dst, r_src ));
5654 return;
5655 }
5656 if (!mode64 && ty == Ity_I64) {
5657 HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
5658
5659 iselInt64Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data,
5660 IEndianess);
5661 lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
5662 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
5663 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
5664 return;
5665 }
5666 if (mode64 && ty == Ity_I128) {
5667 HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
5668 iselInt128Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data,
5669 IEndianess);
5670 lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
5671 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
5672 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
5673 return;
5674 }
5675 if (!mode64 && ty == Ity_I128) {
5676 HReg r_srcHi, r_srcMedHi, r_srcMedLo, r_srcLo;
5677 HReg r_dstHi, r_dstMedHi, r_dstMedLo, r_dstLo;
5678
5679 iselInt128Expr_to_32x4(&r_srcHi, &r_srcMedHi,
5680 &r_srcMedLo, &r_srcLo,
5681 env, stmt->Ist.WrTmp.data, IEndianess);
5682
5683 lookupIRTempQuad( &r_dstHi, &r_dstMedHi, &r_dstMedLo,
5684 &r_dstLo, env, tmp);
5685
5686 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
5687 addInstr(env, mk_iMOVds_RR(r_dstMedHi, r_srcMedHi) );
5688 addInstr(env, mk_iMOVds_RR(r_dstMedLo, r_srcMedLo) );
5689 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
5690 return;
5691 }
5692 if (ty == Ity_I1) {
5693 PPCCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data,
5694 IEndianess);
5695 HReg r_dst = lookupIRTemp(env, tmp);
5696 addInstr(env, PPCInstr_Set(cond, r_dst));
5697 return;
5698 }
5699 if (ty == Ity_F64) {
5700 HReg fr_dst = lookupIRTemp(env, tmp);
5701 HReg fr_src = iselDblExpr(env, stmt->Ist.WrTmp.data, IEndianess);
5702 addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
5703 return;
5704 }
5705 if (ty == Ity_F32) {
5706 HReg fr_dst = lookupIRTemp(env, tmp);
5707 HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data, IEndianess);
5708 addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
5709 return;
5710 }
5711 if (ty == Ity_D32) {
5712 HReg fr_dst = lookupIRTemp(env, tmp);
5713 HReg fr_src = iselDfp32Expr(env, stmt->Ist.WrTmp.data, IEndianess);
5714 addInstr(env, PPCInstr_Dfp64Unary(Pfp_MOV, fr_dst, fr_src));
5715 return;
5716 }
5717 if (ty == Ity_V128) {
5718 HReg v_dst = lookupIRTemp(env, tmp);
5719 HReg v_src = iselVecExpr(env, stmt->Ist.WrTmp.data, IEndianess);
5720 addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src));
5721 return;
5722 }
5723 if (ty == Ity_D64) {
5724 HReg fr_dst = lookupIRTemp( env, tmp );
5725 HReg fr_src = iselDfp64Expr( env, stmt->Ist.WrTmp.data, IEndianess );
5726 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dst, fr_src ) );
5727 return;
5728 }
5729 if (ty == Ity_D128) {
5730 HReg fr_srcHi, fr_srcLo, fr_dstHi, fr_dstLo;
5731 // lookupDfp128IRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
5732 lookupIRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
5733 iselDfp128Expr( &fr_srcHi, &fr_srcLo, env, stmt->Ist.WrTmp.data,
5734 IEndianess );
5735 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstHi, fr_srcHi ) );
5736 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstLo, fr_srcLo ) );
5737 return;
5738 }
5739 break;
5740 }
5741
5742 /* --------- Load Linked or Store Conditional --------- */
5743 case Ist_LLSC: {
5744 IRTemp res = stmt->Ist.LLSC.result;
5745 IRType tyRes = typeOfIRTemp(env->type_env, res);
5746 IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
5747
5748 if (stmt->Ist.LLSC.end != IEndianess)
5749 goto stmt_fail;
5750 if (!mode64 && (tyAddr != Ity_I32))
5751 goto stmt_fail;
5752 if (mode64 && (tyAddr != Ity_I64))
5753 goto stmt_fail;
5754
5755 if (stmt->Ist.LLSC.storedata == NULL) {
5756 /* LL */
5757 HReg r_addr = iselWordExpr_R( env, stmt->Ist.LLSC.addr, IEndianess );
5758 HReg r_dst = lookupIRTemp(env, res);
5759 if (tyRes == Ity_I8) {
5760 addInstr(env, PPCInstr_LoadL( 1, r_dst, r_addr, mode64 ));
5761 return;
5762 }
5763 if (tyRes == Ity_I16) {
5764 addInstr(env, PPCInstr_LoadL( 2, r_dst, r_addr, mode64 ));
5765 return;
5766 }
5767 if (tyRes == Ity_I32) {
5768 addInstr(env, PPCInstr_LoadL( 4, r_dst, r_addr, mode64 ));
5769 return;
5770 }
5771 if (tyRes == Ity_I64 && mode64) {
5772 addInstr(env, PPCInstr_LoadL( 8, r_dst, r_addr, mode64 ));
5773 return;
5774 }
5775 /* fallthru */;
5776 } else {
5777 /* SC */
5778 HReg r_res = lookupIRTemp(env, res); /* :: Ity_I1 */
5779 HReg r_a = iselWordExpr_R(env, stmt->Ist.LLSC.addr, IEndianess);
5780 HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata,
5781 IEndianess);
5782 HReg r_tmp = newVRegI(env);
5783 IRType tyData = typeOfIRExpr(env->type_env,
5784 stmt->Ist.LLSC.storedata);
5785 vassert(tyRes == Ity_I1);
5786 if (tyData == Ity_I8 || tyData == Ity_I16 || tyData == Ity_I32 ||
5787 (tyData == Ity_I64 && mode64)) {
5788 int size = 0;
5789
5790 if (tyData == Ity_I64)
5791 size = 8;
5792 else if (tyData == Ity_I32)
5793 size = 4;
5794 else if (tyData == Ity_I16)
5795 size = 2;
5796 else if (tyData == Ity_I8)
5797 size = 1;
5798
5799 addInstr(env, PPCInstr_StoreC( size,
5800 r_a, r_src, mode64 ));
5801 addInstr(env, PPCInstr_MfCR( r_tmp ));
5802 addInstr(env, PPCInstr_Shft(
5803 Pshft_SHR,
5804 env->mode64 ? False : True
5805 /*F:64-bit, T:32-bit shift*/,
5806 r_tmp, r_tmp,
5807 PPCRH_Imm(False/*unsigned*/, 29)));
5808 /* Probably unnecessary, since the IR dest type is Ity_I1,
5809 and so we are entitled to leave whatever junk we like
5810 drifting round in the upper 31 or 63 bits of r_res.
5811 However, for the sake of conservativeness .. */
5812 addInstr(env, PPCInstr_Alu(
5813 Palu_AND,
5814 r_res, r_tmp,
5815 PPCRH_Imm(False/*signed*/, 1)));
5816 return;
5817 }
5818 /* fallthru */
5819 }
5820 goto stmt_fail;
5821 /*NOTREACHED*/
5822 }
5823
5824 /* --------- Call to DIRTY helper --------- */
5825 case Ist_Dirty: {
5826 IRDirty* d = stmt->Ist.Dirty.details;
5827
5828 /* Figure out the return type, if any. */
5829 IRType retty = Ity_INVALID;
5830 if (d->tmp != IRTemp_INVALID)
5831 retty = typeOfIRTemp(env->type_env, d->tmp);
5832
5833 /* Throw out any return types we don't know about. The set of
5834 acceptable return types is the same in both 32- and 64-bit
5835 mode, so we don't need to inspect mode64 to make a
5836 decision. */
5837 Bool retty_ok = False;
5838 switch (retty) {
5839 case Ity_INVALID: /* function doesn't return anything */
5840 case Ity_V128:
5841 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
5842 retty_ok = True; break;
5843 default:
5844 break;
5845 }
5846 if (!retty_ok)
5847 break; /* will go to stmt_fail: */
5848
5849 /* Marshal args, do the call, clear stack, set the return value
5850 to 0x555..555 if this is a conditional call that returns a
5851 value and the call is skipped. */
5852 UInt addToSp = 0;
5853 RetLoc rloc = mk_RetLoc_INVALID();
5854 doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args,
5855 IEndianess );
5856 vassert(is_sane_RetLoc(rloc));
5857
5858 /* Now figure out what to do with the returned value, if any. */
5859 switch (retty) {
5860 case Ity_INVALID: {
5861 /* No return value. Nothing to do. */
5862 vassert(d->tmp == IRTemp_INVALID);
5863 vassert(rloc.pri == RLPri_None);
5864 vassert(addToSp == 0);
5865 return;
5866 }
5867 case Ity_I32: case Ity_I16: case Ity_I8: {
5868 /* The returned value is in %r3. Park it in the register
5869 associated with tmp. */
5870 HReg r_dst = lookupIRTemp(env, d->tmp);
5871 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
5872 vassert(rloc.pri == RLPri_Int);
5873 vassert(addToSp == 0);
5874 return;
5875 }
5876 case Ity_I64:
5877 if (mode64) {
5878 /* The returned value is in %r3. Park it in the register
5879 associated with tmp. */
5880 HReg r_dst = lookupIRTemp(env, d->tmp);
5881 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
5882 vassert(rloc.pri == RLPri_Int);
5883 vassert(addToSp == 0);
5884 } else {
5885 /* The returned value is in %r3:%r4. Park it in the
5886 register-pair associated with tmp. */
5887 HReg r_dstHi = INVALID_HREG;
5888 HReg r_dstLo = INVALID_HREG;
5889 lookupIRTempPair( &r_dstHi, &r_dstLo, env, d->tmp);
5890 addInstr(env, mk_iMOVds_RR(r_dstHi, hregPPC_GPR3(mode64)));
5891 addInstr(env, mk_iMOVds_RR(r_dstLo, hregPPC_GPR4(mode64)));
5892 vassert(rloc.pri == RLPri_2Int);
5893 vassert(addToSp == 0);
5894 }
5895 return;
5896 case Ity_V128: {
5897 /* The returned value is on the stack, and *retloc tells
5898 us where. Fish it off the stack and then move the
5899 stack pointer upwards to clear it, as directed by
5900 doHelperCall. */
5901 vassert(rloc.pri == RLPri_V128SpRel);
5902 vassert(addToSp >= 16);
5903 HReg dst = lookupIRTemp(env, d->tmp);
5904 PPCAMode* am = PPCAMode_IR(rloc.spOff, StackFramePtr(mode64));
5905 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, dst, am ));
5906 add_to_sp(env, addToSp);
5907 return;
5908 }
5909 default:
5910 /*NOTREACHED*/
5911 vassert(0);
5912 }
5913 }
5914
5915 /* --------- MEM FENCE --------- */
5916 case Ist_MBE:
5917 switch (stmt->Ist.MBE.event) {
5918 case Imbe_Fence:
5919 addInstr(env, PPCInstr_MFence());
5920 return;
5921 default:
5922 break;
5923 }
5924 break;
5925
5926 /* --------- INSTR MARK --------- */
5927 /* Doesn't generate any executable code ... */
5928 case Ist_IMark:
5929 return;
5930
5931 /* --------- ABI HINT --------- */
5932 /* These have no meaning (denotation in the IR) and so we ignore
5933 them ... if any actually made it this far. */
5934 case Ist_AbiHint:
5935 return;
5936
5937 /* --------- NO-OP --------- */
5938 /* Fairly self-explanatory, wouldn't you say? */
5939 case Ist_NoOp:
5940 return;
5941
5942 /* --------- EXIT --------- */
5943 case Ist_Exit: {
5944 IRConst* dst = stmt->Ist.Exit.dst;
5945 if (!mode64 && dst->tag != Ico_U32)
5946 vpanic("iselStmt(ppc): Ist_Exit: dst is not a 32-bit value");
5947 if (mode64 && dst->tag != Ico_U64)
5948 vpanic("iselStmt(ppc64): Ist_Exit: dst is not a 64-bit value");
5949
5950 PPCCondCode cc = iselCondCode(env, stmt->Ist.Exit.guard, IEndianess);
5951 PPCAMode* amCIA = PPCAMode_IR(stmt->Ist.Exit.offsIP,
5952 hregPPC_GPR31(mode64));
5953
5954 /* Case: boring transfer to known address */
5955 if (stmt->Ist.Exit.jk == Ijk_Boring
5956 || stmt->Ist.Exit.jk == Ijk_Call
5957 /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
5958 if (env->chainingAllowed) {
5959 /* .. almost always true .. */
5960 /* Skip the event check at the dst if this is a forwards
5961 edge. */
5962 Bool toFastEP
5963 = mode64
5964 ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga)
5965 : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga);
5966 if (0) vex_printf("%s", toFastEP ? "Y" : ",");
5967 addInstr(env, PPCInstr_XDirect(
5968 mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64
5969 : (Addr64)stmt->Ist.Exit.dst->Ico.U32,
5970 amCIA, cc, toFastEP));
5971 } else {
5972 /* .. very occasionally .. */
5973 /* We can't use chaining, so ask for an assisted transfer,
5974 as that's the only alternative that is allowable. */
5975 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst),
5976 IEndianess);
5977 addInstr(env, PPCInstr_XAssisted(r, amCIA, cc, Ijk_Boring));
5978 }
5979 return;
5980 }
5981
5982 /* Case: assisted transfer to arbitrary address */
5983 switch (stmt->Ist.Exit.jk) {
5984 /* Keep this list in sync with that in iselNext below */
5985 case Ijk_ClientReq:
5986 case Ijk_EmFail:
5987 case Ijk_EmWarn:
5988 case Ijk_NoDecode:
5989 case Ijk_NoRedir:
5990 case Ijk_SigBUS:
5991 case Ijk_SigTRAP:
5992 case Ijk_Sys_syscall:
5993 case Ijk_InvalICache:
5994 {
5995 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst),
5996 IEndianess);
5997 addInstr(env, PPCInstr_XAssisted(r, amCIA, cc,
5998 stmt->Ist.Exit.jk));
5999 return;
6000 }
6001 default:
6002 break;
6003 }
6004
6005 /* Do we ever expect to see any other kind? */
6006 goto stmt_fail;
6007 }
6008
6009 default: break;
6010 }
6011 stmt_fail:
6012 ppIRStmt(stmt);
6013 vpanic("iselStmt(ppc)");
6014 }
6015
6016
6017 /*---------------------------------------------------------*/
6018 /*--- ISEL: Basic block terminators (Nexts) ---*/
6019 /*---------------------------------------------------------*/
6020
iselNext(ISelEnv * env,IRExpr * next,IRJumpKind jk,Int offsIP,IREndness IEndianess)6021 static void iselNext ( ISelEnv* env,
6022 IRExpr* next, IRJumpKind jk, Int offsIP,
6023 IREndness IEndianess)
6024 {
6025 if (vex_traceflags & VEX_TRACE_VCODE) {
6026 vex_printf( "\n-- PUT(%d) = ", offsIP);
6027 ppIRExpr( next );
6028 vex_printf( "; exit-");
6029 ppIRJumpKind(jk);
6030 vex_printf( "\n");
6031 }
6032
6033 PPCCondCode always = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
6034
6035 /* Case: boring transfer to known address */
6036 if (next->tag == Iex_Const) {
6037 IRConst* cdst = next->Iex.Const.con;
6038 vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32));
6039 if (jk == Ijk_Boring || jk == Ijk_Call) {
6040 /* Boring transfer to known address */
6041 PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6042 if (env->chainingAllowed) {
6043 /* .. almost always true .. */
6044 /* Skip the event check at the dst if this is a forwards
6045 edge. */
6046 Bool toFastEP
6047 = env->mode64
6048 ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga)
6049 : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga);
6050 if (0) vex_printf("%s", toFastEP ? "X" : ".");
6051 addInstr(env, PPCInstr_XDirect(
6052 env->mode64 ? (Addr64)cdst->Ico.U64
6053 : (Addr64)cdst->Ico.U32,
6054 amCIA, always, toFastEP));
6055 } else {
6056 /* .. very occasionally .. */
6057 /* We can't use chaining, so ask for an assisted transfer,
6058 as that's the only alternative that is allowable. */
6059 HReg r = iselWordExpr_R(env, next, IEndianess);
6060 addInstr(env, PPCInstr_XAssisted(r, amCIA, always,
6061 Ijk_Boring));
6062 }
6063 return;
6064 }
6065 }
6066
6067 /* Case: call/return (==boring) transfer to any address */
6068 switch (jk) {
6069 case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
6070 HReg r = iselWordExpr_R(env, next, IEndianess);
6071 PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6072 if (env->chainingAllowed) {
6073 addInstr(env, PPCInstr_XIndir(r, amCIA, always));
6074 } else {
6075 addInstr(env, PPCInstr_XAssisted(r, amCIA, always,
6076 Ijk_Boring));
6077 }
6078 return;
6079 }
6080 default:
6081 break;
6082 }
6083
6084 /* Case: assisted transfer to arbitrary address */
6085 switch (jk) {
6086 /* Keep this list in sync with that for Ist_Exit above */
6087 case Ijk_ClientReq:
6088 case Ijk_EmFail:
6089 case Ijk_EmWarn:
6090 case Ijk_NoDecode:
6091 case Ijk_NoRedir:
6092 case Ijk_SigBUS:
6093 case Ijk_SigTRAP:
6094 case Ijk_Sys_syscall:
6095 case Ijk_InvalICache:
6096 {
6097 HReg r = iselWordExpr_R(env, next, IEndianess);
6098 PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6099 addInstr(env, PPCInstr_XAssisted(r, amCIA, always, jk));
6100 return;
6101 }
6102 default:
6103 break;
6104 }
6105
6106 vex_printf( "\n-- PUT(%d) = ", offsIP);
6107 ppIRExpr( next );
6108 vex_printf( "; exit-");
6109 ppIRJumpKind(jk);
6110 vex_printf( "\n");
6111 vassert(0); // are we expecting any other kind?
6112 }
6113
6114
6115 /*---------------------------------------------------------*/
6116 /*--- Insn selector top-level ---*/
6117 /*---------------------------------------------------------*/
6118
6119 /* 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)6120 HInstrArray* iselSB_PPC ( const IRSB* bb,
6121 VexArch arch_host,
6122 const VexArchInfo* archinfo_host,
6123 const VexAbiInfo* vbi,
6124 Int offs_Host_EvC_Counter,
6125 Int offs_Host_EvC_FailAddr,
6126 Bool chainingAllowed,
6127 Bool addProfInc,
6128 Addr max_ga)
6129
6130 {
6131 Int i, j;
6132 HReg hregLo, hregMedLo, hregMedHi, hregHi;
6133 ISelEnv* env;
6134 UInt hwcaps_host = archinfo_host->hwcaps;
6135 Bool mode64 = False;
6136 UInt mask32, mask64;
6137 PPCAMode *amCounter, *amFailAddr;
6138 IREndness IEndianess;
6139
6140 vassert(arch_host == VexArchPPC32 || arch_host == VexArchPPC64);
6141 mode64 = arch_host == VexArchPPC64;
6142
6143 /* do some sanity checks */
6144 mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
6145 | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX
6146 | VEX_HWCAPS_PPC32_DFP | VEX_HWCAPS_PPC32_ISA2_07;
6147
6148
6149 mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
6150 | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP
6151 | VEX_HWCAPS_PPC64_ISA2_07;
6152
6153 if (mode64) {
6154 vassert((hwcaps_host & mask32) == 0);
6155 } else {
6156 vassert((hwcaps_host & mask64) == 0);
6157 }
6158
6159 /* Check that the host's endianness is as expected. */
6160 vassert((archinfo_host->endness == VexEndnessBE) ||
6161 (archinfo_host->endness == VexEndnessLE));
6162
6163 if (archinfo_host->endness == VexEndnessBE)
6164 IEndianess = Iend_BE;
6165 else
6166 IEndianess = Iend_LE;
6167
6168 /* Make up an initial environment to use. */
6169 env = LibVEX_Alloc_inline(sizeof(ISelEnv));
6170 env->vreg_ctr = 0;
6171
6172 /* Are we being ppc32 or ppc64? */
6173 env->mode64 = mode64;
6174
6175 /* Set up output code array. */
6176 env->code = newHInstrArray();
6177
6178 /* Copy BB's type env. */
6179 env->type_env = bb->tyenv;
6180
6181 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
6182 * change as we go along.
6183 *
6184 * vregmap2 and vregmap3 are only used in 32 bit mode
6185 * for supporting I128 in 32-bit mode
6186 */
6187 env->n_vregmap = bb->tyenv->types_used;
6188 env->vregmapLo = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6189 env->vregmapMedLo = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6190 if (mode64) {
6191 env->vregmapMedHi = NULL;
6192 env->vregmapHi = NULL;
6193 } else {
6194 env->vregmapMedHi = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6195 env->vregmapHi = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6196 }
6197
6198 /* and finally ... */
6199 env->chainingAllowed = chainingAllowed;
6200 env->max_ga = max_ga;
6201 env->hwcaps = hwcaps_host;
6202 env->previous_rm = NULL;
6203 env->vbi = vbi;
6204
6205 /* For each IR temporary, allocate a suitably-kinded virtual
6206 register. */
6207 j = 0;
6208 for (i = 0; i < env->n_vregmap; i++) {
6209 hregLo = hregMedLo = hregMedHi = hregHi = INVALID_HREG;
6210 switch (bb->tyenv->types[i]) {
6211 case Ity_I1:
6212 case Ity_I8:
6213 case Ity_I16:
6214 case Ity_I32:
6215 if (mode64) {
6216 hregLo = mkHReg(True, HRcInt64, 0, j++);
6217 } else {
6218 hregLo = mkHReg(True, HRcInt32, 0, j++);
6219 }
6220 break;
6221 case Ity_I64:
6222 if (mode64) {
6223 hregLo = mkHReg(True, HRcInt64, 0, j++);
6224 } else {
6225 hregLo = mkHReg(True, HRcInt32, 0, j++);
6226 hregMedLo = mkHReg(True, HRcInt32, 0, j++);
6227 }
6228 break;
6229 case Ity_I128:
6230 if (mode64) {
6231 hregLo = mkHReg(True, HRcInt64, 0, j++);
6232 hregMedLo = mkHReg(True, HRcInt64, 0, j++);
6233 } else {
6234 hregLo = mkHReg(True, HRcInt32, 0, j++);
6235 hregMedLo = mkHReg(True, HRcInt32, 0, j++);
6236 hregMedHi = mkHReg(True, HRcInt32, 0, j++);
6237 hregHi = mkHReg(True, HRcInt32, 0, j++);
6238 }
6239 break;
6240 case Ity_F32:
6241 case Ity_F64:
6242 hregLo = mkHReg(True, HRcFlt64, 0, j++);
6243 break;
6244 case Ity_V128:
6245 hregLo = mkHReg(True, HRcVec128, 0, j++);
6246 break;
6247 case Ity_D32:
6248 case Ity_D64:
6249 hregLo = mkHReg(True, HRcFlt64, 0, j++);
6250 break;
6251 case Ity_D128:
6252 hregLo = mkHReg(True, HRcFlt64, 0, j++);
6253 hregMedLo = mkHReg(True, HRcFlt64, 0, j++);
6254 break;
6255 default:
6256 ppIRType(bb->tyenv->types[i]);
6257 vpanic("iselBB(ppc): IRTemp type");
6258 }
6259 env->vregmapLo[i] = hregLo;
6260 env->vregmapMedLo[i] = hregMedLo;
6261 if (!mode64) {
6262 env->vregmapMedHi[i] = hregMedHi;
6263 env->vregmapHi[i] = hregHi;
6264 }
6265 }
6266 env->vreg_ctr = j;
6267
6268 /* The very first instruction must be an event check. */
6269 amCounter = PPCAMode_IR(offs_Host_EvC_Counter, hregPPC_GPR31(mode64));
6270 amFailAddr = PPCAMode_IR(offs_Host_EvC_FailAddr, hregPPC_GPR31(mode64));
6271 addInstr(env, PPCInstr_EvCheck(amCounter, amFailAddr));
6272
6273 /* Possibly a block counter increment (for profiling). At this
6274 point we don't know the address of the counter, so just pretend
6275 it is zero. It will have to be patched later, but before this
6276 translation is used, by a call to LibVEX_patchProfCtr. */
6277 if (addProfInc) {
6278 addInstr(env, PPCInstr_ProfInc());
6279 }
6280
6281 /* Ok, finally we can iterate over the statements. */
6282 for (i = 0; i < bb->stmts_used; i++)
6283 iselStmt(env, bb->stmts[i], IEndianess);
6284
6285 iselNext(env, bb->next, bb->jumpkind, bb->offsIP, IEndianess);
6286
6287 /* record the number of vregs we used. */
6288 env->code->n_vregs = env->vreg_ctr;
6289 return env->code;
6290 }
6291
6292
6293 /*---------------------------------------------------------------*/
6294 /*--- end host_ppc_isel.c ---*/
6295 /*---------------------------------------------------------------*/
6296