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