blob: eb406cb3c589f6c93664c7b21014e620e536b260 [file] [log] [blame]
sewardjc97096c2004-06-30 09:28:04 +00001
2/*---------------------------------------------------------------*/
3/*--- ---*/
sewardjc0ee2ed2004-07-27 10:29:41 +00004/*--- This file (host-x86/isel.c) is ---*/
sewardjc97096c2004-06-30 09:28:04 +00005/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*---------------------------------------------------------------*/
8
sewardj887a11a2004-07-05 17:26:47 +00009#include "libvex_basictypes.h"
10#include "libvex_ir.h"
11#include "libvex.h"
sewardj35421a32004-07-05 13:12:34 +000012
sewardjc0ee2ed2004-07-27 10:29:41 +000013#include "main/vex_util.h"
14#include "main/vex_globals.h"
15#include "host-generic/h_generic_regs.h"
16#include "host-x86/hdefs.h"
sewardjc97096c2004-06-30 09:28:04 +000017
18
19/*---------------------------------------------------------*/
sewardj443cd9d2004-07-18 23:06:45 +000020/*--- Stuff for pattern matching on IR. This isn't ---*/
21/*--- x86 specific, and should be moved elsewhere. ---*/
22/*---------------------------------------------------------*/
23
24#define DECLARE_PATTERN(_patt) \
25 static IRExpr* _patt = NULL
26
27#define DEFINE_PATTERN(_patt,_expr) \
28 do { \
29 if (!(_patt)) { \
30 vassert(LibVEX_GetAllocMode() == AllocModeTEMPORARY); \
31 LibVEX_SetAllocMode(AllocModePERMANENT); \
32 _patt = (_expr); \
33 LibVEX_SetAllocMode(AllocModeTEMPORARY); \
34 vassert(LibVEX_GetAllocMode() == AllocModeTEMPORARY); \
35 } \
36 } while (0)
37
38
39#define N_MATCH_BINDERS 4
40typedef
41 struct {
42 IRExpr* bindee[N_MATCH_BINDERS];
43 }
44 MatchInfo;
45
46
47static void setBindee ( MatchInfo* mi, Int n, IRExpr* bindee )
48{
49 if (n < 0 || n >= N_MATCH_BINDERS)
50 vpanic("setBindee: out of range index");
51 if (mi->bindee[n] != NULL)
52 vpanic("setBindee: bindee already set");
53 mi->bindee[n] = bindee;
54}
55
56static Bool matchWrk ( MatchInfo* mi, IRExpr* p/*attern*/, IRExpr* e/*xpr*/ )
57{
58 switch (p->tag) {
59 case Iex_Binder: /* aha, what we were looking for. */
60 setBindee(mi, p->Iex.Binder.binder, e);
61 return True;
62 case Iex_Unop:
63 if (e->tag != Iex_Unop) return False;
64 if (p->Iex.Unop.op != e->Iex.Unop.op) return False;
65 if (!matchWrk(mi, p->Iex.Unop.arg, e->Iex.Unop.arg))
66 return False;
67 return True;
68 case Iex_Binop:
69 if (e->tag != Iex_Binop) return False;
70 if (p->Iex.Binop.op != e->Iex.Binop.op) return False;
71 if (!matchWrk(mi, p->Iex.Binop.arg1, e->Iex.Binop.arg1))
72 return False;
73 if (!matchWrk(mi, p->Iex.Binop.arg2, e->Iex.Binop.arg2))
74 return False;
75 return True;
sewardjd18d1bf2004-08-25 12:49:22 +000076 case Iex_LDle:
77 if (e->tag != Iex_LDle) return False;
78 if (p->Iex.LDle.ty != e->Iex.LDle.ty) return False;
79 if (!matchWrk(mi, p->Iex.LDle.addr, e->Iex.LDle.addr))
80 return False;
81 return True;
sewardj443cd9d2004-07-18 23:06:45 +000082 case Iex_Const:
83 if (e->tag != Iex_Const) return False;
84 switch (p->Iex.Const.con->tag) {
85 case Ico_U8: return e->Iex.Const.con->tag==Ico_U8
86 ? (p->Iex.Const.con->Ico.U8
87 == e->Iex.Const.con->Ico.U8)
88 : False;
89 case Ico_U16: return e->Iex.Const.con->tag==Ico_U16
90 ? (p->Iex.Const.con->Ico.U16
91 == e->Iex.Const.con->Ico.U16)
92 : False;
93 case Ico_U32: return e->Iex.Const.con->tag==Ico_U32
94 ? (p->Iex.Const.con->Ico.U32
95 == e->Iex.Const.con->Ico.U32)
96 : False;
97 case Ico_U64: return e->Iex.Const.con->tag==Ico_U64
98 ? (p->Iex.Const.con->Ico.U64
99 == e->Iex.Const.con->Ico.U64)
100 : False;
sewardja58ea662004-08-15 03:12:41 +0000101 case Ico_F64: return e->Iex.Const.con->tag==Ico_F64
102 ? (p->Iex.Const.con->Ico.F64
103 == e->Iex.Const.con->Ico.F64)
104 : False;
sewardj443cd9d2004-07-18 23:06:45 +0000105 }
106 vpanic("matchIRExpr.Iex_Const");
107 /*NOTREACHED*/
108 default:
109 ppIRExpr(p);
110 vpanic("match");
111 }
112}
113
114static Bool matchIRExpr ( MatchInfo* mi, IRExpr* p/*attern*/, IRExpr* e/*xpr*/ )
115{
116 Int i;
117 for (i = 0; i < N_MATCH_BINDERS; i++)
118 mi->bindee[i] = NULL;
119 return matchWrk(mi, p, e);
120}
121
122/*-----*/
123/* These are duplicated in x86toIR.c */
124static IRExpr* unop ( IROp op, IRExpr* a )
125{
126 return IRExpr_Unop(op, a);
127}
128
129static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
130{
131 return IRExpr_Binop(op, a1, a2);
132}
133
134static IRExpr* bind ( Int binder )
135{
136 return IRExpr_Binder(binder);
137}
138
139
140
141
142/*---------------------------------------------------------*/
sewardjc97096c2004-06-30 09:28:04 +0000143/*--- ISelEnv ---*/
144/*---------------------------------------------------------*/
145
146/* This carries around:
147
sewardj36ca5132004-07-24 13:12:23 +0000148 - A function for looking up the address of helper functions.
149
sewardjc97096c2004-06-30 09:28:04 +0000150 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
151 might encounter. This is computed before insn selection starts,
152 and does not change.
153
154 - A mapping from IRTemp to HReg. This tells the insn selector
sewardje8e9d732004-07-16 21:03:45 +0000155 which virtual register(s) are associated with each IRTemp
156 temporary. This is computed before insn selection starts, and
157 does not change. We expect this mapping to map precisely the
158 same set of IRTemps as the type mapping does.
159
160 - vregmap holds the primary register for the IRTemp.
161 - vregmapHI is only used for 64-bit integer-typed
162 IRTemps. It holds the identity of a second
163 32-bit virtual HReg, which holds the high half
164 of the value.
sewardjc97096c2004-06-30 09:28:04 +0000165
166 - The code array, that is, the insns selected so far.
167
168 - A counter, for generating new virtual registers.
169
sewardje8e9d732004-07-16 21:03:45 +0000170 Note, this is all host-independent. */
sewardjc97096c2004-06-30 09:28:04 +0000171
172typedef
173 struct {
sewardj36ca5132004-07-24 13:12:23 +0000174 Addr64 (*find_helper)(Char*);
175
sewardj194d54a2004-07-03 19:08:18 +0000176 IRTypeEnv* type_env;
sewardjc97096c2004-06-30 09:28:04 +0000177
sewardje539a402004-07-14 18:24:17 +0000178 HReg* vregmap;
sewardje8e9d732004-07-16 21:03:45 +0000179 HReg* vregmapHI;
sewardj194d54a2004-07-03 19:08:18 +0000180 Int n_vregmap;
sewardjc97096c2004-06-30 09:28:04 +0000181
sewardj2cd80dc2004-07-02 15:20:40 +0000182 HInstrArray* code;
sewardjc97096c2004-06-30 09:28:04 +0000183
sewardj194d54a2004-07-03 19:08:18 +0000184 Int vreg_ctr;
sewardjc97096c2004-06-30 09:28:04 +0000185 }
186 ISelEnv;
187
188
189static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
190{
sewardje539a402004-07-14 18:24:17 +0000191 vassert(tmp >= 0);
192 vassert(tmp < env->n_vregmap);
193 return env->vregmap[tmp];
sewardjc97096c2004-06-30 09:28:04 +0000194}
195
sewardj597b71b2004-07-19 02:51:12 +0000196static void lookupIRTemp64 ( HReg* vrHI, HReg* vrLO, ISelEnv* env, IRTemp tmp )
sewardje8e9d732004-07-16 21:03:45 +0000197{
198 vassert(tmp >= 0);
199 vassert(tmp < env->n_vregmap);
sewardj597b71b2004-07-19 02:51:12 +0000200 vassert(env->vregmapHI[tmp] != INVALID_HREG);
sewardje8e9d732004-07-16 21:03:45 +0000201 *vrLO = env->vregmap[tmp];
202 *vrHI = env->vregmapHI[tmp];
203}
204
sewardj2cd80dc2004-07-02 15:20:40 +0000205static void addInstr ( ISelEnv* env, X86Instr* instr )
sewardjc97096c2004-06-30 09:28:04 +0000206{
sewardj2cd80dc2004-07-02 15:20:40 +0000207 addHInstr(env->code, instr);
sewardj1f40a0a2004-07-21 12:28:07 +0000208 if (vex_verbosity > 0) {
209 ppX86Instr(instr);
210 vex_printf("\n");
211 }
sewardjc97096c2004-06-30 09:28:04 +0000212}
213
214static HReg newVRegI ( ISelEnv* env )
215{
sewardj194d54a2004-07-03 19:08:18 +0000216 HReg reg = mkHReg(env->vreg_ctr, HRcInt, True/*virtual reg*/);
217 env->vreg_ctr++;
sewardjc97096c2004-06-30 09:28:04 +0000218 return reg;
219}
220
sewardj3196daf2004-08-13 00:18:58 +0000221static HReg newVRegF ( ISelEnv* env )
222{
223 HReg reg = mkHReg(env->vreg_ctr, HRcFloat, True/*virtual reg*/);
224 env->vreg_ctr++;
225 return reg;
226}
227
sewardjd18d1bf2004-08-25 12:49:22 +0000228/* Misc helpers looking for a proper home. */
sewardj66f2f792004-06-30 16:37:16 +0000229
sewardj443cd9d2004-07-18 23:06:45 +0000230static X86Instr* mk_MOVsd_RR ( HReg src, HReg dst )
sewardj66f2f792004-06-30 16:37:16 +0000231{
sewardj35421a32004-07-05 13:12:34 +0000232 vassert(hregClass(src) == HRcInt);
233 vassert(hregClass(dst) == HRcInt);
sewardj66f2f792004-06-30 16:37:16 +0000234 return X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst);
235}
236
237
sewardjd18d1bf2004-08-25 12:49:22 +0000238/*---------------------------------------------------------*/
239/*--- ISEL: Forward declarations ---*/
240/*---------------------------------------------------------*/
241
242/* These are organised as iselXXX and iselXXX_wrk pairs. The
243 iselXXX_wrk do the real work, but are not to be called directly.
244 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
245 checks that all returned registers are virtual.
246*/
247
248static X86RMI* iselIntExpr_RMI_wrk ( ISelEnv* env, IRExpr* e );
249static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e );
250
251static X86RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e );
252static X86RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e );
253
254static X86RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e );
255static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e );
256
257static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e );
258static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e );
259
260static X86AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e );
261static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e );
262
263static void iselIntExpr64_wrk ( HReg* rHi, HReg* rLo,
264 ISelEnv* env, IRExpr* e );
265static void iselIntExpr64 ( HReg* rHi, HReg* rLo,
266 ISelEnv* env, IRExpr* e );
267
268static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e );
269static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e );
270
sewardj89cd0932004-09-08 18:23:25 +0000271static HReg iselDblExpr ( ISelEnv* env, IRExpr* e );
272
sewardjd18d1bf2004-08-25 12:49:22 +0000273
274/*---------------------------------------------------------*/
275/*--- ISEL: Integer expressions (32/16/8 bit) ---*/
276/*---------------------------------------------------------*/
277
sewardjc97096c2004-06-30 09:28:04 +0000278/* Select insns for an integer-typed expression, and add them to the
sewardjd18d1bf2004-08-25 12:49:22 +0000279 code list. Return a reg holding the result. This reg will be a
280 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
281 want to modify it, ask for a new vreg, copy it in there, and modify
282 the copy. The register allocator will do its best to map both
283 vregs to the same real register, so the copies will often disappear
284 later in the game.
sewardj4042c7e2004-07-18 01:28:30 +0000285
286 This should handle expressions of 32, 16 and 8-bit type. All
287 results are returned in a 32-bit register. For 16- and 8-bit
sewardjd18d1bf2004-08-25 12:49:22 +0000288 expressions, the upper 16/24 bits are arbitrary, so you should mask
289 or sign extend partial values if necessary.
sewardjc97096c2004-06-30 09:28:04 +0000290*/
sewardjd18d1bf2004-08-25 12:49:22 +0000291
sewardj66f2f792004-06-30 16:37:16 +0000292static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
sewardjc97096c2004-06-30 09:28:04 +0000293{
sewardjd18d1bf2004-08-25 12:49:22 +0000294 HReg r = iselIntExpr_R_wrk(env, e);
295 /* sanity checks ... */
296# if 0
297 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
298# endif
299 vassert(hregClass(r) == HRcInt);
300 vassert(hregIsVirtual(r));
301 return r;
302}
303
304/* DO NOT CALL THIS DIRECTLY ! */
305static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
306{
sewardj443cd9d2004-07-18 23:06:45 +0000307 MatchInfo mi;
sewardj84ff0652004-08-23 16:16:08 +0000308 DECLARE_PATTERN(p_32to1_then_1Uto8);
sewardj443cd9d2004-07-18 23:06:45 +0000309
sewardje8e9d732004-07-16 21:03:45 +0000310 IRType ty = typeOfIRExpr(env->type_env,e);
sewardj4042c7e2004-07-18 01:28:30 +0000311 vassert(ty == Ity_I32 || Ity_I16 || Ity_I8);
sewardjc97096c2004-06-30 09:28:04 +0000312
313 switch (e->tag) {
314
sewardj60f4e3c2004-07-19 01:56:50 +0000315 /* --------- TEMP --------- */
sewardje8e9d732004-07-16 21:03:45 +0000316 case Iex_Tmp: {
sewardje8e9d732004-07-16 21:03:45 +0000317 return lookupIRTemp(env, e->Iex.Tmp.tmp);
318 }
sewardjc97096c2004-06-30 09:28:04 +0000319
sewardj60f4e3c2004-07-19 01:56:50 +0000320 /* --------- LOAD --------- */
sewardje8e9d732004-07-16 21:03:45 +0000321 case Iex_LDle: {
sewardje8e9d732004-07-16 21:03:45 +0000322 HReg dst = newVRegI(env);
sewardj4042c7e2004-07-18 01:28:30 +0000323 X86AMode* amode = iselIntExpr_AMode ( env, e->Iex.LDle.addr );
324 if (ty == Ity_I32) {
325 addInstr(env, X86Instr_Alu32R(Xalu_MOV,
326 X86RMI_Mem(amode), dst) );
327 return dst;
328 }
329 if (ty == Ity_I16) {
330 addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
331 return dst;
332 }
sewardj443cd9d2004-07-18 23:06:45 +0000333 if (ty == Ity_I8) {
334 addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
335 return dst;
336 }
sewardj4042c7e2004-07-18 01:28:30 +0000337 break;
sewardje8e9d732004-07-16 21:03:45 +0000338 }
339
sewardj60f4e3c2004-07-19 01:56:50 +0000340 /* --------- BINARY OP --------- */
sewardje8e9d732004-07-16 21:03:45 +0000341 case Iex_Binop: {
342 X86AluOp aluOp;
343 X86ShiftOp shOp;
sewardj8c7f1ab2004-07-29 20:31:09 +0000344
sewardj85126a42004-08-20 23:39:55 +0000345#if 0
346 { DECLARE_PATTERN(p_rol32);
347 DEFINE_PATTERN(p_rol32,
348 binop(Iop_Or32,
349 binop(Iop_Shl32,bind(0),bind(1)),
350 binop(Iop_Shr32,
351 bind(2),
352 binop(Iop_Sub8,IRConst_U8(32),bind(3)))));
353 if (matchIRExpr(&mi,p_rol32,e)
354 && eqIRExpr(mi.bindee[0], mi.bindee[2])
355 && eqIRExpr(mi.bindee[1], mi.bindee[3])) {
356 /* emit roll */
357 }
358 }
359#endif
360
sewardj4042c7e2004-07-18 01:28:30 +0000361 /* Is it an addition or logical style op? */
sewardje8e9d732004-07-16 21:03:45 +0000362 switch (e->Iex.Binop.op) {
sewardja2384712004-07-29 14:36:40 +0000363 case Iop_Add8: case Iop_Add16: case Iop_Add32:
sewardj1813dbe2004-07-28 17:09:04 +0000364 aluOp = Xalu_ADD; break;
sewardj60f4e3c2004-07-19 01:56:50 +0000365 case Iop_Sub8: case Iop_Sub16: case Iop_Sub32:
366 aluOp = Xalu_SUB; break;
sewardj5c34dc92004-07-19 12:48:11 +0000367 case Iop_And8: case Iop_And16: case Iop_And32:
368 aluOp = Xalu_AND; break;
sewardj750f4072004-07-26 22:39:11 +0000369 case Iop_Or8: case Iop_Or16: case Iop_Or32:
sewardj597b71b2004-07-19 02:51:12 +0000370 aluOp = Xalu_OR; break;
sewardja2384712004-07-29 14:36:40 +0000371 case Iop_Xor8: case Iop_Xor16: case Iop_Xor32:
sewardj597b71b2004-07-19 02:51:12 +0000372 aluOp = Xalu_XOR; break;
sewardjb81f8b32004-07-30 10:17:50 +0000373 case Iop_Mul16: case Iop_Mul32:
374 aluOp = Xalu_MUL; break;
375 default:
376 aluOp = Xalu_INVALID; break;
sewardje8e9d732004-07-16 21:03:45 +0000377 }
378 /* For commutative ops we assume any literal
sewardj66f2f792004-06-30 16:37:16 +0000379 values are on the second operand. */
sewardje8e9d732004-07-16 21:03:45 +0000380 if (aluOp != Xalu_INVALID) {
sewardj66f2f792004-06-30 16:37:16 +0000381 HReg dst = newVRegI(env);
382 HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
383 X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
sewardj443cd9d2004-07-18 23:06:45 +0000384 addInstr(env, mk_MOVsd_RR(reg,dst));
sewardje8e9d732004-07-16 21:03:45 +0000385 addInstr(env, X86Instr_Alu32R(aluOp, rmi, dst));
sewardj66f2f792004-06-30 16:37:16 +0000386 return dst;
sewardjc97096c2004-06-30 09:28:04 +0000387 }
sewardj4f391492004-08-24 22:45:30 +0000388 /* Could do better here; forcing the first arg into a reg
389 isn't always clever.
390 -- t70 = Xor32(And32(Xor32(LDle:I32(Add32(t41,0xFFFFFFA0:I32)),
391 LDle:I32(Add32(t41,0xFFFFFFA4:I32))),LDle:I32(Add32(
392 t41,0xFFFFFFA8:I32))),LDle:I32(Add32(t41,0xFFFFFFA0:I32)))
393 movl 0xFFFFFFA0(%vr41),%vr107
394 movl 0xFFFFFFA4(%vr41),%vr108
395 movl %vr107,%vr106
396 xorl %vr108,%vr106
397 movl 0xFFFFFFA8(%vr41),%vr109
398 movl %vr106,%vr105
399 andl %vr109,%vr105
400 movl 0xFFFFFFA0(%vr41),%vr110
401 movl %vr105,%vr104
402 xorl %vr110,%vr104
403 movl %vr104,%vr70
404 */
sewardj8c7f1ab2004-07-29 20:31:09 +0000405
sewardj4042c7e2004-07-18 01:28:30 +0000406 /* Perhaps a shift op? */
sewardje8e9d732004-07-16 21:03:45 +0000407 switch (e->Iex.Binop.op) {
sewardj1813dbe2004-07-28 17:09:04 +0000408 case Iop_Shl32: case Iop_Shl16: case Iop_Shl8:
409 shOp = Xsh_SHL; break;
410 case Iop_Shr32: case Iop_Shr16: case Iop_Shr8:
sewardj5c34dc92004-07-19 12:48:11 +0000411 shOp = Xsh_SHR; break;
sewardj8c7f1ab2004-07-29 20:31:09 +0000412 case Iop_Sar32: case Iop_Sar16: case Iop_Sar8:
sewardj1813dbe2004-07-28 17:09:04 +0000413 shOp = Xsh_SAR; break;
414 default:
415 shOp = Xsh_INVALID; break;
sewardje8e9d732004-07-16 21:03:45 +0000416 }
417 if (shOp != Xsh_INVALID) {
sewardj8c7f1ab2004-07-29 20:31:09 +0000418 HReg dst = newVRegI(env);
sewardj38ff3d82004-07-26 23:27:08 +0000419
420 /* regL = the value to be shifted */
sewardj96efe572004-07-03 14:48:24 +0000421 HReg regL = iselIntExpr_R(env, e->Iex.Binop.arg1);
sewardj443cd9d2004-07-18 23:06:45 +0000422 addInstr(env, mk_MOVsd_RR(regL,dst));
sewardj38ff3d82004-07-26 23:27:08 +0000423
sewardj5c34dc92004-07-19 12:48:11 +0000424 /* Do any necessary widening for 16/8 bit operands */
425 switch (e->Iex.Binop.op) {
426 case Iop_Shr8:
427 addInstr(env, X86Instr_Alu32R(
428 Xalu_AND, X86RMI_Imm(0xFF), dst));
429 break;
430 case Iop_Shr16:
431 addInstr(env, X86Instr_Alu32R(
432 Xalu_AND, X86RMI_Imm(0xFFFF), dst));
433 break;
sewardj8c7f1ab2004-07-29 20:31:09 +0000434 case Iop_Sar8:
435 addInstr(env, X86Instr_Sh32(Xsh_SHL, 24, X86RM_Reg(dst)));
436 addInstr(env, X86Instr_Sh32(Xsh_SAR, 24, X86RM_Reg(dst)));
437 break;
438 case Iop_Sar16:
439 addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(dst)));
440 addInstr(env, X86Instr_Sh32(Xsh_SAR, 16, X86RM_Reg(dst)));
441 break;
sewardj5c34dc92004-07-19 12:48:11 +0000442 default: break;
443 }
sewardj38ff3d82004-07-26 23:27:08 +0000444
445 /* Now consider the shift amount. If it's a literal, we
446 can do a much better job than the general case. */
447 if (e->Iex.Binop.arg2->tag == Iex_Const) {
448 /* assert that the IR is well-typed */
449 Int nshift;
450 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj38ff3d82004-07-26 23:27:08 +0000451 nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
sewardj3bd676c2004-07-27 10:50:38 +0000452 vassert(nshift >= 0);
sewardj38ff3d82004-07-26 23:27:08 +0000453 if (nshift > 0)
sewardjb81f8b32004-07-30 10:17:50 +0000454 /* Can't allow nshift==0 since that means %cl */
sewardj38ff3d82004-07-26 23:27:08 +0000455 addInstr(env, X86Instr_Sh32(
456 shOp,
457 nshift,
458 X86RM_Reg(dst)));
459 } else {
460 /* General case; we have to force the amount into %cl. */
461 HReg regR = iselIntExpr_R(env, e->Iex.Binop.arg2);
462 addInstr(env, mk_MOVsd_RR(regR,hregX86_ECX()));
463 addInstr(env, X86Instr_Sh32(shOp, 0/* %cl */, X86RM_Reg(dst)));
464 }
sewardjd9c2b792004-07-08 01:44:38 +0000465 return dst;
466 }
sewardj8c7f1ab2004-07-29 20:31:09 +0000467
468 /* Handle misc other ops. */
469 if (e->Iex.Binop.op == Iop_16HLto32) {
470 HReg hi16 = newVRegI(env);
471 HReg lo16 = newVRegI(env);
472 HReg hi16s = iselIntExpr_R(env, e->Iex.Binop.arg1);
473 HReg lo16s = iselIntExpr_R(env, e->Iex.Binop.arg2);
474 addInstr(env, mk_MOVsd_RR(hi16s, hi16));
475 addInstr(env, mk_MOVsd_RR(lo16s, lo16));
476 addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(hi16)));
477 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFFFF), lo16));
478 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo16), hi16));
479 return hi16;
480 }
481
sewardjb81f8b32004-07-30 10:17:50 +0000482 if (e->Iex.Binop.op == Iop_MullS16 || e->Iex.Binop.op == Iop_MullS8
483 || e->Iex.Binop.op == Iop_MullU16 || e->Iex.Binop.op == Iop_MullU8) {
484 HReg a16 = newVRegI(env);
485 HReg b16 = newVRegI(env);
486 HReg a16s = iselIntExpr_R(env, e->Iex.Binop.arg1);
487 HReg b16s = iselIntExpr_R(env, e->Iex.Binop.arg2);
488 Int shift = (e->Iex.Binop.op == Iop_MullS8
489 || e->Iex.Binop.op == Iop_MullU8)
490 ? 24 : 16;
491 X86ShiftOp shr_op = (e->Iex.Binop.op == Iop_MullS8
492 || e->Iex.Binop.op == Iop_MullS16)
493 ? Xsh_SAR : Xsh_SHR;
494
495 addInstr(env, mk_MOVsd_RR(a16s, a16));
496 addInstr(env, mk_MOVsd_RR(b16s, b16));
497 addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(a16)));
498 addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(b16)));
499 addInstr(env, X86Instr_Sh32(shr_op, shift, X86RM_Reg(a16)));
500 addInstr(env, X86Instr_Sh32(shr_op, shift, X86RM_Reg(b16)));
501 addInstr(env, X86Instr_Alu32R(Xalu_MUL, X86RMI_Reg(a16), b16));
502 return b16;
503 }
504
sewardjbdc7d212004-09-09 02:46:40 +0000505 if (e->Iex.Binop.op == Iop_CmpF64) {
506 HReg fL = iselDblExpr(env, e->Iex.Binop.arg1);
507 HReg fR = iselDblExpr(env, e->Iex.Binop.arg2);
508 HReg dst = newVRegI(env);
509 addInstr(env, X86Instr_FpCmp(fL,fR,dst));
510 /* shift this right 8 bits so as to conform to CmpF64
511 definition. */
512 addInstr(env, X86Instr_Sh32(Xsh_SHR, 8, X86RM_Reg(dst)));
513 return dst;
514 }
515
sewardj8f3debf2004-09-08 23:42:23 +0000516 if (e->Iex.Binop.op == Iop_F64toI32 || e->Iex.Binop.op == Iop_F64toI16) {
517 Int sz = e->Iex.Binop.op == Iop_F64toI16 ? 2 : 4;
518 HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
519 HReg rrm = iselIntExpr_R(env, e->Iex.Binop.arg1);
520 HReg rrm2 = newVRegI(env);
521 HReg dst = newVRegI(env);
522
523 /* Used several times ... */
524 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
525
526 /* rf now holds the value to be converted, and rrm holds the
527 rounding mode value, encoded as per the IRRoundingMode
528 enum. The first thing to do is set the FPU's rounding
529 mode accordingly. */
530
531 /* Create a space, both for the control word messing, and for
sewardjbdc7d212004-09-09 02:46:40 +0000532 the actual store conversion. */
sewardj8f3debf2004-09-08 23:42:23 +0000533 /* subl $4, %esp */
534 addInstr(env,
535 X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(4), hregX86_ESP()));
536 /* movl %rrm, %rrm2
537 andl $3, %rrm2 -- shouldn't be needed; paranoia
538 shll $10, %rrm2
539 orl $0x037F, %rrm2
540 movl %rrm2, 0(%esp)
541 fldcw 0(%esp)
542 */
543 addInstr(env, mk_MOVsd_RR(rrm, rrm2));
544 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(3), rrm2));
545 addInstr(env, X86Instr_Sh32(Xsh_SHL, 10, X86RM_Reg(rrm2)));
546 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Imm(0x037F), rrm2));
547 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(rrm2), zero_esp));
548 addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
549
550 /* gistw/l %rf, 0(%esp) */
551 addInstr(env, X86Instr_FpLdStI(False/*store*/, sz, rf, zero_esp));
552
553 if (sz == 2) {
554 /* movzwl 0(%esp), %dst */
555 addInstr(env, X86Instr_LoadEX(2,False,zero_esp,dst));
556 } else {
557 /* movl 0(%esp), %dst */
558 vassert(sz == 4);
559 addInstr(env, X86Instr_Alu32R(
560 Xalu_MOV, X86RMI_Mem(zero_esp), dst));
561 }
562
563 /* Restore default FPU control.
564 movl $0x037F, 0(%esp)
565 fldcw 0(%esp)
566 */
567 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Imm(0x037F), zero_esp));
568 addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
569
570 /* addl $4, %esp */
571 addInstr(env,
572 X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(4), hregX86_ESP()));
573 return dst;
574 }
575
sewardj46de4072004-09-11 19:23:24 +0000576 /* C3210 flags following FPU partial remainder (fprem). */
577 if (e->Iex.Binop.op == Iop_PRemC3210F64) {
578 HReg junk = newVRegF(env);
579 HReg dst = newVRegI(env);
580 HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1);
581 HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2);
582 addInstr(env, X86Instr_FpBinary(Xfp_PREM,srcL,srcR,junk));
583 /* The previous pseudo-insn will have left the FPU's C3210
584 flags set correctly. So bag them. */
585 addInstr(env, X86Instr_FpStSW_AX());
586 addInstr(env, mk_MOVsd_RR(hregX86_EAX(), dst));
587 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0x4700), dst));
588 return dst;
589 }
590
sewardje8e9d732004-07-16 21:03:45 +0000591 break;
sewardjd9c2b792004-07-08 01:44:38 +0000592 }
593
sewardj60f4e3c2004-07-19 01:56:50 +0000594 /* --------- UNARY OP --------- */
sewardj4042c7e2004-07-18 01:28:30 +0000595 case Iex_Unop: {
sewardj443cd9d2004-07-18 23:06:45 +0000596 /* 1Uto8(32to1(expr32)) */
597 DEFINE_PATTERN(p_32to1_then_1Uto8,
sewardj38ff3d82004-07-26 23:27:08 +0000598 unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
sewardj443cd9d2004-07-18 23:06:45 +0000599 if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
600 IRExpr* expr32 = mi.bindee[0];
sewardj38ff3d82004-07-26 23:27:08 +0000601 HReg dst = newVRegI(env);
sewardj443cd9d2004-07-18 23:06:45 +0000602 HReg src = iselIntExpr_R(env, expr32);
603 addInstr(env, mk_MOVsd_RR(src,dst) );
604 addInstr(env, X86Instr_Alu32R(Xalu_AND,
605 X86RMI_Imm(1), dst));
606 return dst;
607 }
608
sewardjd18d1bf2004-08-25 12:49:22 +0000609 /* 16Uto32(LDle(expr32)) */
610 {
611 DECLARE_PATTERN(p_LDle16_then_16Uto32);
612 DEFINE_PATTERN(p_LDle16_then_16Uto32,
613 unop(Iop_16Uto32,IRExpr_LDle(Ity_I16,bind(0))) );
614 if (matchIRExpr(&mi,p_LDle16_then_16Uto32,e)) {
615 HReg dst = newVRegI(env);
616 X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
617 addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
618 return dst;
619 }
620 }
621
sewardj4042c7e2004-07-18 01:28:30 +0000622 switch (e->Iex.Unop.op) {
sewardj443cd9d2004-07-18 23:06:45 +0000623 case Iop_8Uto32:
624 case Iop_16Uto32: {
sewardj4042c7e2004-07-18 01:28:30 +0000625 HReg dst = newVRegI(env);
626 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
sewardj443cd9d2004-07-18 23:06:45 +0000627 UInt mask = e->Iex.Unop.op==Iop_8Uto32 ? 0xFF : 0xFFFF;
628 addInstr(env, mk_MOVsd_RR(src,dst) );
sewardj4042c7e2004-07-18 01:28:30 +0000629 addInstr(env, X86Instr_Alu32R(Xalu_AND,
sewardj443cd9d2004-07-18 23:06:45 +0000630 X86RMI_Imm(mask), dst));
631 return dst;
632 }
sewardjc22a6fd2004-07-29 23:41:47 +0000633 case Iop_8Sto32:
634 case Iop_16Sto32: {
635 HReg dst = newVRegI(env);
636 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
637 UInt amt = e->Iex.Unop.op==Iop_8Sto32 ? 24 : 16;
638 addInstr(env, mk_MOVsd_RR(src,dst) );
639 addInstr(env, X86Instr_Sh32(Xsh_SHL, amt, X86RM_Reg(dst)));
640 addInstr(env, X86Instr_Sh32(Xsh_SAR, amt, X86RM_Reg(dst)));
641 return dst;
642 }
sewardja2384712004-07-29 14:36:40 +0000643 case Iop_Not8:
644 case Iop_Not16:
sewardj443cd9d2004-07-18 23:06:45 +0000645 case Iop_Not32: {
646 HReg dst = newVRegI(env);
647 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
648 addInstr(env, mk_MOVsd_RR(src,dst) );
sewardj60f4e3c2004-07-19 01:56:50 +0000649 addInstr(env, X86Instr_Unary32(Xun_Not,X86RM_Reg(dst)));
sewardj4042c7e2004-07-18 01:28:30 +0000650 return dst;
651 }
sewardj597b71b2004-07-19 02:51:12 +0000652 case Iop_64HIto32: {
653 HReg rHi, rLo;
654 iselIntExpr64(&rHi,&rLo, env, e->Iex.Unop.arg);
655 return rHi; /* and abandon rLo .. poor wee thing :-) */
656 }
sewardj8c7f1ab2004-07-29 20:31:09 +0000657 case Iop_64to32: {
sewardj597b71b2004-07-19 02:51:12 +0000658 HReg rHi, rLo;
659 iselIntExpr64(&rHi,&rLo, env, e->Iex.Unop.arg);
660 return rLo; /* similar stupid comment to the above ... */
661 }
sewardjb81f8b32004-07-30 10:17:50 +0000662 case Iop_16HIto8:
sewardj8c7f1ab2004-07-29 20:31:09 +0000663 case Iop_32HIto16: {
sewardjb81f8b32004-07-30 10:17:50 +0000664 HReg dst = newVRegI(env);
665 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
666 Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16;
sewardj8c7f1ab2004-07-29 20:31:09 +0000667 addInstr(env, mk_MOVsd_RR(src,dst) );
sewardjb81f8b32004-07-30 10:17:50 +0000668 addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, X86RM_Reg(dst)));
sewardj8c7f1ab2004-07-29 20:31:09 +0000669 return dst;
670 }
sewardj84ff0652004-08-23 16:16:08 +0000671 case Iop_1Uto32:
sewardjd7cb8532004-08-17 23:59:23 +0000672 case Iop_1Uto8: {
673 HReg dst = newVRegI(env);
674 X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
675 addInstr(env, X86Instr_Set32(cond,dst));
676 return dst;
677 }
sewardjce646f22004-08-31 23:55:54 +0000678 case Iop_Ctz32: {
679 /* Count trailing zeroes, implemented by x86 'bsfl' */
680 HReg dst = newVRegI(env);
681 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
682 addInstr(env, X86Instr_Bsfr32(True,src,dst));
683 return dst;
684 }
685 case Iop_Clz32: {
686 /* Count leading zeroes. Do 'bsrl' to establish the index
687 of the highest set bit, and subtract that value from
688 31. */
689 HReg tmp = newVRegI(env);
690 HReg dst = newVRegI(env);
691 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
692 addInstr(env, X86Instr_Bsfr32(False,src,tmp));
693 addInstr(env, X86Instr_Alu32R(Xalu_MOV,
694 X86RMI_Imm(31), dst));
695 addInstr(env, X86Instr_Alu32R(Xalu_SUB,
696 X86RMI_Reg(tmp), dst));
697 return dst;
698 }
sewardj89cd0932004-09-08 18:23:25 +0000699
sewardjb81f8b32004-07-30 10:17:50 +0000700 case Iop_16to8:
sewardja2384712004-07-29 14:36:40 +0000701 case Iop_32to8:
702 case Iop_32to16:
sewardjb81f8b32004-07-30 10:17:50 +0000703 /* These are no-ops. */
sewardja2384712004-07-29 14:36:40 +0000704 return iselIntExpr_R(env, e->Iex.Unop.arg);
705
sewardj4042c7e2004-07-18 01:28:30 +0000706 default:
707 break;
708 }
709 break;
710 }
711
sewardj60f4e3c2004-07-19 01:56:50 +0000712 /* --------- GET --------- */
sewardje8e9d732004-07-16 21:03:45 +0000713 case Iex_Get: {
714 if (ty == Ity_I32) {
715 HReg dst = newVRegI(env);
716 addInstr(env, X86Instr_Alu32R(
717 Xalu_MOV,
718 X86RMI_Mem(X86AMode_IR(e->Iex.Get.offset,
719 hregX86_EBP())),
720 dst));
721 return dst;
sewardjc97096c2004-06-30 09:28:04 +0000722 }
sewardj60f4e3c2004-07-19 01:56:50 +0000723 if (ty == Ity_I8 || ty == Ity_I16) {
sewardj4042c7e2004-07-18 01:28:30 +0000724 HReg dst = newVRegI(env);
725 addInstr(env, X86Instr_LoadEX(
sewardj60f4e3c2004-07-19 01:56:50 +0000726 ty==Ity_I8 ? 1 : 2,
727 False,
sewardj4042c7e2004-07-18 01:28:30 +0000728 X86AMode_IR(e->Iex.Get.offset,hregX86_EBP()),
729 dst));
730 return dst;
731 }
sewardje8e9d732004-07-16 21:03:45 +0000732 break;
sewardjc97096c2004-06-30 09:28:04 +0000733 }
sewardje8e9d732004-07-16 21:03:45 +0000734
sewardj33124f62004-08-30 17:54:18 +0000735 case Iex_GetI: {
736 /* First off, compute the index expression into an integer reg.
737 The referenced address will then be 0 + ebp + reg*1, that is,
738 an X86AMode_IRRS. */
739 HReg idx = iselIntExpr_R(env, e->Iex.GetI.offset);
740 HReg dst = newVRegI(env);
741 if (ty == Ity_I8) {
742 addInstr(env,
743 X86Instr_LoadEX(
744 1, False,
745 X86AMode_IRRS(0, hregX86_EBP(), idx, 0),
746 dst ));
747 return dst;
748 }
749 }
750
sewardj60f4e3c2004-07-19 01:56:50 +0000751 /* --------- CCALL --------- */
sewardje8e9d732004-07-16 21:03:45 +0000752 case Iex_CCall: {
sewardj36ca5132004-07-24 13:12:23 +0000753 Addr64 helper;
sewardjc4be80c2004-09-10 16:17:45 +0000754 Int i, n_args, n_arg_ws;
755 UInt target;
sewardje8e9d732004-07-16 21:03:45 +0000756 IRExpr* arg;
sewardjc4be80c2004-09-10 16:17:45 +0000757 IRType arg_ty;
sewardjd18d1bf2004-08-25 12:49:22 +0000758 HReg dst = newVRegI(env);
sewardje8e9d732004-07-16 21:03:45 +0000759 vassert(ty == Ity_I32);
sewardjc4be80c2004-09-10 16:17:45 +0000760
761 /* be very restrictive for now. Only 32/64-bit ints allowed
762 for args, and 32 bits for return type. */
sewardj4042c7e2004-07-18 01:28:30 +0000763 if (e->Iex.CCall.retty != Ity_I32)
sewardjd18d1bf2004-08-25 12:49:22 +0000764 goto irreducible;
sewardjc4be80c2004-09-10 16:17:45 +0000765
sewardje8e9d732004-07-16 21:03:45 +0000766 /* push args on the stack, right to left. */
sewardjc4be80c2004-09-10 16:17:45 +0000767 n_arg_ws = n_args = 0;
768 while (e->Iex.CCall.args[n_args]) n_args++;
769
770 for (i = n_args-1; i >= 0; i--) {
771 arg = e->Iex.CCall.args[i];
772 arg_ty = typeOfIRExpr(env->type_env, arg);
773 if (arg_ty == Ity_I32) {
774 addInstr(env, X86Instr_Push(iselIntExpr_RMI(env, arg)));
775 n_arg_ws ++;
776 } else
777 if (arg_ty == Ity_I64) {
778 HReg rHi, rLo;
779 iselIntExpr64(&rHi, &rLo, env, arg);
780 addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
781 addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
782 n_arg_ws += 2;
783 }
784 else goto irreducible;
sewardj4042c7e2004-07-18 01:28:30 +0000785 }
sewardjc4be80c2004-09-10 16:17:45 +0000786
sewardj36ca5132004-07-24 13:12:23 +0000787 /* Find the function to call. Since the host -- for which we
788 are generating code -- is a 32-bit machine (x86) -- the upper
789 32 bit of the helper address should be zero. */
790 helper = env->find_helper(e->Iex.CCall.name);
791 vassert((helper & 0xFFFFFFFF00000000LL) == 0);
792 target = helper & 0xFFFFFFFF;
sewardj4042c7e2004-07-18 01:28:30 +0000793 addInstr(env, X86Instr_Alu32R(
794 Xalu_MOV,
795 X86RMI_Imm(target),
796 hregX86_EAX()));
797 addInstr(env, X86Instr_Call(hregX86_EAX()));
sewardjc4be80c2004-09-10 16:17:45 +0000798 if (n_arg_ws > 0)
sewardj4042c7e2004-07-18 01:28:30 +0000799 addInstr(env, X86Instr_Alu32R(Xalu_ADD,
sewardjc4be80c2004-09-10 16:17:45 +0000800 X86RMI_Imm(4*n_arg_ws),
sewardj4042c7e2004-07-18 01:28:30 +0000801 hregX86_ESP()));
sewardjd18d1bf2004-08-25 12:49:22 +0000802 addInstr(env, mk_MOVsd_RR(hregX86_EAX(), dst));
803 return dst;
sewardje8e9d732004-07-16 21:03:45 +0000804 }
805
sewardj60f4e3c2004-07-19 01:56:50 +0000806 /* --------- LITERAL --------- */
sewardje8e9d732004-07-16 21:03:45 +0000807 /* 32/16/8-bit literals */
808 case Iex_Const: {
sewardj4042c7e2004-07-18 01:28:30 +0000809 X86RMI* rmi = iselIntExpr_RMI ( env, e );
810 HReg r = newVRegI(env);
811 addInstr(env, X86Instr_Alu32R(Xalu_MOV, rmi, r));
sewardje8e9d732004-07-16 21:03:45 +0000812 return r;
813 }
sewardjc97096c2004-06-30 09:28:04 +0000814
sewardj60f4e3c2004-07-19 01:56:50 +0000815 /* --------- MULTIPLEX --------- */
sewardj4042c7e2004-07-18 01:28:30 +0000816 case Iex_Mux0X: {
sewardjc744e872004-08-26 11:24:39 +0000817 if ((ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8)
sewardj4042c7e2004-07-18 01:28:30 +0000818 && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
sewardj2e56f9f2004-07-24 01:24:38 +0000819 HReg r8;
sewardj38ff3d82004-07-26 23:27:08 +0000820 HReg rX = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
821 X86RM* r0 = iselIntExpr_RM(env, e->Iex.Mux0X.expr0);
822 HReg dst = newVRegI(env);
823 addInstr(env, mk_MOVsd_RR(rX,dst));
824 r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
825 addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8)));
826 addInstr(env, X86Instr_CMov32(Xcc_Z,r0,dst));
827 return dst;
sewardj4042c7e2004-07-18 01:28:30 +0000828 }
829 break;
830 }
831
sewardjc97096c2004-06-30 09:28:04 +0000832 default:
833 break;
834 } /* switch (e->tag) */
835
836 /* We get here if no pattern matched. */
sewardje8e9d732004-07-16 21:03:45 +0000837 irreducible:
sewardj35421a32004-07-05 13:12:34 +0000838 ppIRExpr(e);
sewardjd9c2b792004-07-08 01:44:38 +0000839 vpanic("iselIntExpr_R: cannot reduce tree");
sewardjc97096c2004-06-30 09:28:04 +0000840}
841
842
sewardj66f2f792004-06-30 16:37:16 +0000843/*---------------------------------------------------------*/
844/*--- ISEL: Integer expression auxiliaries ---*/
845/*---------------------------------------------------------*/
846
sewardjd18d1bf2004-08-25 12:49:22 +0000847/* --------------------- AMODEs --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +0000848
sewardj66f2f792004-06-30 16:37:16 +0000849/* Return an AMode which computes the value of the specified
850 expression, possibly also adding insns to the code list as a
sewardj4042c7e2004-07-18 01:28:30 +0000851 result. The expression may only be a 32-bit one.
sewardjc97096c2004-06-30 09:28:04 +0000852*/
sewardjd18d1bf2004-08-25 12:49:22 +0000853
854static Bool sane_AMode ( X86AMode* am )
855{
856 switch (am->tag) {
857 case Xam_IR:
858 return hregClass(am->Xam.IR.reg) == HRcInt
859 && (hregIsVirtual(am->Xam.IR.reg)
860 || am->Xam.IR.reg == hregX86_EBP());
861 case Xam_IRRS:
862 return hregClass(am->Xam.IRRS.base) == HRcInt
863 && hregIsVirtual(am->Xam.IRRS.base)
864 && hregClass(am->Xam.IRRS.index) == HRcInt
865 && hregIsVirtual(am->Xam.IRRS.index);
866 default:
867 vpanic("sane_AMode: unknown x86 amode tag");
868 }
869}
870
sewardj66f2f792004-06-30 16:37:16 +0000871static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e )
sewardjc97096c2004-06-30 09:28:04 +0000872{
sewardjd18d1bf2004-08-25 12:49:22 +0000873 X86AMode* am = iselIntExpr_AMode_wrk(env, e);
874 vassert(sane_AMode(am));
875 return am;
876}
877
878/* DO NOT CALL THIS DIRECTLY ! */
879static X86AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e )
880{
sewardj4042c7e2004-07-18 01:28:30 +0000881 IRType ty = typeOfIRExpr(env->type_env,e);
882 vassert(ty == Ity_I32);
sewardjc97096c2004-06-30 09:28:04 +0000883
884 /* Add32(expr1, Shl32(expr2, imm)) */
885 if (e->tag == Iex_Binop
886 && e->Iex.Binop.op == Iop_Add32
887 && e->Iex.Binop.arg2->tag == Iex_Binop
888 && e->Iex.Binop.arg2->Iex.Binop.op == Iop_Shl32
889 && e->Iex.Binop.arg2->Iex.Binop.arg2->tag == Iex_Const
sewardjd18d1bf2004-08-25 12:49:22 +0000890 && e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8) {
891 UInt shift = e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
892 if (shift == 1 || shift == 2 || shift == 3) {
sewardj66f2f792004-06-30 16:37:16 +0000893 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
894 HReg r2 = iselIntExpr_R(env, e->Iex.Binop.arg2->Iex.Binop.arg1 );
sewardjc97096c2004-06-30 09:28:04 +0000895 return X86AMode_IRRS(0, r1, r2, shift);
896 }
897 }
898
899 /* Add32(expr,i) */
900 if (e->tag == Iex_Binop
901 && e->Iex.Binop.op == Iop_Add32
902 && e->Iex.Binop.arg2->tag == Iex_Const
903 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
sewardj66f2f792004-06-30 16:37:16 +0000904 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
sewardjd9c2b792004-07-08 01:44:38 +0000905 return X86AMode_IR(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32, r1);
sewardjc97096c2004-06-30 09:28:04 +0000906 }
907
908 /* Doesn't match anything in particular. Generate it into
909 a register and use that. */
910 {
sewardj66f2f792004-06-30 16:37:16 +0000911 HReg r1 = iselIntExpr_R(env, e);
sewardjd9c2b792004-07-08 01:44:38 +0000912 return X86AMode_IR(0, r1);
sewardjc97096c2004-06-30 09:28:04 +0000913 }
914}
915
916
sewardjd18d1bf2004-08-25 12:49:22 +0000917/* --------------------- RMIs --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +0000918
sewardj4042c7e2004-07-18 01:28:30 +0000919/* Similarly, calculate an expression into an X86RMI operand. As with
920 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
sewardj66f2f792004-06-30 16:37:16 +0000921
922static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e )
923{
sewardjd18d1bf2004-08-25 12:49:22 +0000924 X86RMI* rmi = iselIntExpr_RMI_wrk(env, e);
925 /* sanity checks ... */
926 switch (rmi->tag) {
927 case Xrmi_Imm:
928 return rmi;
929 case Xrmi_Reg:
930 vassert(hregClass(rmi->Xrmi.Reg.reg) == HRcInt);
931 vassert(hregIsVirtual(rmi->Xrmi.Reg.reg));
932 return rmi;
933 case Xrmi_Mem:
934 vassert(sane_AMode(rmi->Xrmi.Mem.am));
935 return rmi;
936 default:
937 vpanic("iselIntExpr_RMI: unknown x86 RMI tag");
938 }
939}
940
941/* DO NOT CALL THIS DIRECTLY ! */
942static X86RMI* iselIntExpr_RMI_wrk ( ISelEnv* env, IRExpr* e )
943{
sewardj4042c7e2004-07-18 01:28:30 +0000944 IRType ty = typeOfIRExpr(env->type_env,e);
945 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
sewardj66f2f792004-06-30 16:37:16 +0000946
947 /* special case: immediate */
sewardj4042c7e2004-07-18 01:28:30 +0000948 if (e->tag == Iex_Const) {
949 UInt u;
950 switch (e->Iex.Const.con->tag) {
951 case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
952 case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
953 case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break;
954 default: vpanic("iselIntExpr_RMI.Iex_Const(x86h)");
955 }
956 return X86RMI_Imm(u);
sewardj66f2f792004-06-30 16:37:16 +0000957 }
958
sewardje8e9d732004-07-16 21:03:45 +0000959 /* special case: 32-bit GET */
sewardj4042c7e2004-07-18 01:28:30 +0000960 if (e->tag == Iex_Get && ty == Ity_I32) {
sewardje8e9d732004-07-16 21:03:45 +0000961 return X86RMI_Mem(X86AMode_IR(e->Iex.Get.offset,
962 hregX86_EBP()));
963 }
964
sewardj66f2f792004-06-30 16:37:16 +0000965 /* special case: load from memory */
966
967 /* default case: calculate into a register and return that */
968 {
969 HReg r = iselIntExpr_R ( env, e );
970 return X86RMI_Reg(r);
971 }
972}
973
974
sewardjd18d1bf2004-08-25 12:49:22 +0000975/* --------------------- RIs --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +0000976
sewardj4042c7e2004-07-18 01:28:30 +0000977/* Calculate an expression into an X86RI operand. As with
978 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
sewardj66f2f792004-06-30 16:37:16 +0000979
980static X86RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e )
981{
sewardjd18d1bf2004-08-25 12:49:22 +0000982 X86RI* ri = iselIntExpr_RI_wrk(env, e);
983 /* sanity checks ... */
984 switch (ri->tag) {
985 case Xri_Imm:
986 return ri;
987 case Xrmi_Reg:
988 vassert(hregClass(ri->Xri.Reg.reg) == HRcInt);
989 vassert(hregIsVirtual(ri->Xri.Reg.reg));
990 return ri;
991 default:
992 vpanic("iselIntExpr_RI: unknown x86 RI tag");
993 }
994}
995
996/* DO NOT CALL THIS DIRECTLY ! */
997static X86RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e )
998{
sewardj4042c7e2004-07-18 01:28:30 +0000999 IRType ty = typeOfIRExpr(env->type_env,e);
1000 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
sewardj66f2f792004-06-30 16:37:16 +00001001
1002 /* special case: immediate */
sewardj4042c7e2004-07-18 01:28:30 +00001003 if (e->tag == Iex_Const) {
1004 UInt u;
1005 switch (e->Iex.Const.con->tag) {
1006 case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
1007 case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
1008 case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break;
1009 default: vpanic("iselIntExpr_RMI.Iex_Const(x86h)");
1010 }
1011 return X86RI_Imm(u);
sewardj66f2f792004-06-30 16:37:16 +00001012 }
1013
1014 /* default case: calculate into a register and return that */
1015 {
1016 HReg r = iselIntExpr_R ( env, e );
1017 return X86RI_Reg(r);
1018 }
1019}
1020
1021
sewardjd18d1bf2004-08-25 12:49:22 +00001022/* --------------------- RMs --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +00001023
sewardj4042c7e2004-07-18 01:28:30 +00001024/* Similarly, calculate an expression into an X86RM operand. As with
1025 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
1026
1027static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e )
1028{
sewardjd18d1bf2004-08-25 12:49:22 +00001029 X86RM* rm = iselIntExpr_RM_wrk(env, e);
1030 /* sanity checks ... */
1031 switch (rm->tag) {
1032 case Xrm_Reg:
1033 vassert(hregClass(rm->Xrm.Reg.reg) == HRcInt);
1034 vassert(hregIsVirtual(rm->Xrm.Reg.reg));
1035 return rm;
1036 case Xrm_Mem:
1037 vassert(sane_AMode(rm->Xrm.Mem.am));
1038 return rm;
1039 default:
1040 vpanic("iselIntExpr_RM: unknown x86 RM tag");
1041 }
1042}
1043
1044/* DO NOT CALL THIS DIRECTLY ! */
1045static X86RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e )
1046{
sewardj4042c7e2004-07-18 01:28:30 +00001047 IRType ty = typeOfIRExpr(env->type_env,e);
1048 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
1049
1050 /* special case: 32-bit GET */
1051 if (e->tag == Iex_Get && ty == Ity_I32) {
1052 return X86RM_Mem(X86AMode_IR(e->Iex.Get.offset,
1053 hregX86_EBP()));
1054 }
1055
1056 /* special case: load from memory */
1057
1058 /* default case: calculate into a register and return that */
1059 {
1060 HReg r = iselIntExpr_R ( env, e );
1061 return X86RM_Reg(r);
1062 }
1063}
1064
1065
sewardjd18d1bf2004-08-25 12:49:22 +00001066/* --------------------- CONDCODE --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +00001067
sewardj443cd9d2004-07-18 23:06:45 +00001068/* Generate code to evaluated a bit-typed expression, returning the
1069 condition code which would correspond when the expression would
1070 notionally have returned 1. */
1071
1072static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e )
1073{
sewardjd18d1bf2004-08-25 12:49:22 +00001074 /* Uh, there's nothing we can sanity check here, unfortunately. */
1075 return iselCondCode_wrk(env,e);
1076}
1077
1078/* DO NOT CALL THIS DIRECTLY ! */
1079static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
1080{
sewardj443cd9d2004-07-18 23:06:45 +00001081 MatchInfo mi;
1082 DECLARE_PATTERN(p_32to1);
sewardj8f3debf2004-09-08 23:42:23 +00001083 //DECLARE_PATTERN(p_eq32_literal);
1084 //DECLARE_PATTERN(p_ne32_zero);
sewardj84ff0652004-08-23 16:16:08 +00001085 DECLARE_PATTERN(p_1Uto32_then_32to1);
sewardj443cd9d2004-07-18 23:06:45 +00001086
1087 vassert(e);
1088 vassert(typeOfIRExpr(env->type_env,e) == Ity_Bit);
1089
sewardj84ff0652004-08-23 16:16:08 +00001090 /* 32to1(1Uto32(expr1)) -- the casts are pointless, ignore them */
1091 DEFINE_PATTERN(p_1Uto32_then_32to1,
1092 unop(Iop_32to1,unop(Iop_1Uto32,bind(0))));
1093 if (matchIRExpr(&mi,p_1Uto32_then_32to1,e)) {
1094 IRExpr* expr1 = mi.bindee[0];
1095 return iselCondCode(env, expr1);
1096 }
1097
sewardj443cd9d2004-07-18 23:06:45 +00001098 /* pattern: 32to1(expr32) */
1099 DEFINE_PATTERN(p_32to1,
1100 unop(Iop_32to1,bind(0))
1101 );
1102 if (matchIRExpr(&mi,p_32to1,e)) {
sewardj09cc2fe2004-08-18 00:28:48 +00001103 X86RM* rm = iselIntExpr_RM(env, mi.bindee[0]);
1104 addInstr(env, X86Instr_Test32(X86RI_Imm(1),rm));
sewardj443cd9d2004-07-18 23:06:45 +00001105 return Xcc_NZ;
1106 }
1107
sewardjb9c5cf62004-08-24 15:10:38 +00001108 /* CmpEQ8 / CmpNE8 */
sewardj84ff0652004-08-23 16:16:08 +00001109 if (e->tag == Iex_Binop
sewardjb9c5cf62004-08-24 15:10:38 +00001110 && (e->Iex.Binop.op == Iop_CmpEQ8
1111 || e->Iex.Binop.op == Iop_CmpNE8)) {
1112 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1113 X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
1114 HReg r = newVRegI(env);
1115 addInstr(env, mk_MOVsd_RR(r1,r));
1116 addInstr(env, X86Instr_Alu32R(Xalu_XOR,rmi2,r));
1117 addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(0xFF),r));
1118 switch (e->Iex.Binop.op) {
1119 case Iop_CmpEQ8: return Xcc_Z;
1120 case Iop_CmpNE8: return Xcc_NZ;
1121 default: vpanic("iselCondCode(x86): CmpXX8");
1122 }
1123 }
1124
1125 /* CmpEQ16 / CmpNE16 */
1126 if (e->tag == Iex_Binop
1127 && (e->Iex.Binop.op == Iop_CmpEQ16
1128 || e->Iex.Binop.op == Iop_CmpNE16)) {
1129 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1130 X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
1131 HReg r = newVRegI(env);
1132 addInstr(env, mk_MOVsd_RR(r1,r));
1133 addInstr(env, X86Instr_Alu32R(Xalu_XOR,rmi2,r));
1134 addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(0xFFFF),r));
1135 switch (e->Iex.Binop.op) {
1136 case Iop_CmpEQ16: return Xcc_Z;
1137 case Iop_CmpNE16: return Xcc_NZ;
1138 default: vpanic("iselCondCode(x86): CmpXX8");
1139 }
1140 }
1141
1142 /* Cmp*32*(x,y) */
1143 if (e->tag == Iex_Binop
1144 && (e->Iex.Binop.op == Iop_CmpEQ32
1145 || e->Iex.Binop.op == Iop_CmpNE32
1146 || e->Iex.Binop.op == Iop_CmpLT32S
sewardj84ff0652004-08-23 16:16:08 +00001147 || e->Iex.Binop.op == Iop_CmpLT32U
1148 || e->Iex.Binop.op == Iop_CmpLE32S
1149 || e->Iex.Binop.op == Iop_CmpLE32U)) {
sewardjb9c5cf62004-08-24 15:10:38 +00001150 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
sewardj84ff0652004-08-23 16:16:08 +00001151 X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
1152 addInstr(env, X86Instr_Alu32R(Xalu_CMP,rmi2,r1));
1153 switch (e->Iex.Binop.op) {
sewardjb9c5cf62004-08-24 15:10:38 +00001154 case Iop_CmpEQ32: return Xcc_Z;
1155 case Iop_CmpNE32: return Xcc_NZ;
sewardj84ff0652004-08-23 16:16:08 +00001156 case Iop_CmpLT32S: return Xcc_L;
1157 case Iop_CmpLT32U: return Xcc_B;
1158 case Iop_CmpLE32S: return Xcc_LE;
1159 case Iop_CmpLE32U: return Xcc_BE;
sewardjb9c5cf62004-08-24 15:10:38 +00001160 default: vpanic("iselCondCode(x86): CmpXX32");
sewardj84ff0652004-08-23 16:16:08 +00001161 }
1162 }
1163
sewardjd7cb8532004-08-17 23:59:23 +00001164 /* var */
1165 if (e->tag == Iex_Tmp) {
1166 HReg r32 = lookupIRTemp(env, e->Iex.Tmp.tmp);
1167 HReg dst = newVRegI(env);
1168 addInstr(env, mk_MOVsd_RR(r32,dst));
1169 addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(1),dst));
1170 return Xcc_NZ;
1171 }
1172
sewardj443cd9d2004-07-18 23:06:45 +00001173 ppIRExpr(e);
1174 vpanic("iselCondCode");
1175}
1176
1177
sewardj597b71b2004-07-19 02:51:12 +00001178/*---------------------------------------------------------*/
1179/*--- ISEL: Integer expressions (64 bit) ---*/
1180/*---------------------------------------------------------*/
1181
1182/* Compute a 64-bit value into a register pair, which is returned as
1183 the first two parameters. As with iselIntExpr_R, these may be
1184 either real or virtual regs; in any case they must not be changed
1185 by subsequent code emitted by the caller. */
1186
1187static void iselIntExpr64 ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
1188{
sewardjd18d1bf2004-08-25 12:49:22 +00001189 iselIntExpr64_wrk(rHi, rLo, env, e);
1190# if 0
1191 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1192# endif
1193 vassert(hregClass(*rHi) == HRcInt);
1194 vassert(hregIsVirtual(*rHi));
1195 vassert(hregClass(*rLo) == HRcInt);
1196 vassert(hregIsVirtual(*rLo));
1197}
1198
1199/* DO NOT CALL THIS DIRECTLY ! */
1200static void iselIntExpr64_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
1201{
sewardj597b71b2004-07-19 02:51:12 +00001202 // MatchInfo mi;
1203 vassert(e);
1204 vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
1205
sewardjc09278c2004-08-19 17:15:49 +00001206 if (e->tag == Iex_Const) {
1207 ULong w64 = e->Iex.Const.con->Ico.U64;
1208 UInt wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF;
1209 UInt wLo = ((UInt)w64) & 0xFFFFFFFF;
1210 HReg tLo = newVRegI(env);
1211 HReg tHi = newVRegI(env);
1212 vassert(e->Iex.Const.con->tag == Ico_U64);
1213 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(wHi), tHi));
1214 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(wLo), tLo));
1215 *rHi = tHi;
1216 *rLo = tLo;
1217 return;
1218 }
1219
sewardj597b71b2004-07-19 02:51:12 +00001220 /* read 64-bit IRTemp */
1221 if (e->tag == Iex_Tmp) {
1222 lookupIRTemp64( rHi, rLo, env, e->Iex.Tmp.tmp);
1223 return;
1224 }
1225
sewardjbdc7d212004-09-09 02:46:40 +00001226 /* 64-bit load */
1227 if (e->tag == Iex_LDle) {
1228 vassert(e->Iex.LDle.ty == Ity_I64);
1229 HReg tLo = newVRegI(env);
1230 HReg tHi = newVRegI(env);
1231 HReg rA = iselIntExpr_R(env, e->Iex.LDle.addr);
1232 addInstr(env, X86Instr_Alu32R(
1233 Xalu_MOV,
1234 X86RMI_Mem(X86AMode_IR(0, rA)), tLo));
1235 addInstr(env, X86Instr_Alu32R(
1236 Xalu_MOV,
1237 X86RMI_Mem(X86AMode_IR(4, rA)), tHi));
1238 *rHi = tHi;
1239 *rLo = tLo;
1240 return;
1241 }
1242
sewardj597b71b2004-07-19 02:51:12 +00001243 /* 32 x 32 -> 64 multiply */
1244 if (e->tag == Iex_Binop
1245 && (e->Iex.Binop.op == Iop_MullU32
1246 || e->Iex.Binop.op == Iop_MullS32)) {
1247 /* get one operand into %eax, and the other into a R/M. Need to
1248 make an educated guess about which is better in which. */
sewardjd18d1bf2004-08-25 12:49:22 +00001249 HReg tLo = newVRegI(env);
1250 HReg tHi = newVRegI(env);
sewardj597b71b2004-07-19 02:51:12 +00001251 Bool syned = e->Iex.Binop.op == Iop_MullS32;
1252 X86RM* rmLeft = iselIntExpr_RM(env, e->Iex.Binop.arg1);
1253 HReg rRight = iselIntExpr_R(env, e->Iex.Binop.arg2);
1254 addInstr(env, mk_MOVsd_RR(rRight, hregX86_EAX()));
1255 addInstr(env, X86Instr_MulL(syned, Xss_32, rmLeft));
1256 /* Result is now in EDX:EAX. Tell the caller. */
sewardjd18d1bf2004-08-25 12:49:22 +00001257 addInstr(env, mk_MOVsd_RR(hregX86_EDX(), tHi));
1258 addInstr(env, mk_MOVsd_RR(hregX86_EAX(), tLo));
1259 *rHi = tHi;
1260 *rLo = tLo;
sewardj597b71b2004-07-19 02:51:12 +00001261 return;
1262 }
1263
sewardj5c34dc92004-07-19 12:48:11 +00001264 /* 64 x 32 -> (32(rem),32(div)) division */
1265 if (e->tag == Iex_Binop
1266 && (e->Iex.Binop.op == Iop_DivModU64to32
1267 || e->Iex.Binop.op == Iop_DivModS64to32)) {
1268 /* Get the 64-bit operand into edx:eax, and the other
1269 into any old R/M. */
1270 HReg sHi, sLo;
sewardjd18d1bf2004-08-25 12:49:22 +00001271 HReg tLo = newVRegI(env);
1272 HReg tHi = newVRegI(env);
sewardjacbfdd02004-07-30 14:08:17 +00001273 Bool syned = e->Iex.Binop.op == Iop_DivModS64to32;
sewardj5c34dc92004-07-19 12:48:11 +00001274 X86RM* rmRight = iselIntExpr_RM(env, e->Iex.Binop.arg2);
1275 iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
1276 addInstr(env, mk_MOVsd_RR(sHi, hregX86_EDX()));
1277 addInstr(env, mk_MOVsd_RR(sLo, hregX86_EAX()));
1278 addInstr(env, X86Instr_Div(syned, Xss_32, rmRight));
sewardjd18d1bf2004-08-25 12:49:22 +00001279 addInstr(env, mk_MOVsd_RR(hregX86_EDX(), tHi));
1280 addInstr(env, mk_MOVsd_RR(hregX86_EAX(), tLo));
1281 *rHi = tHi;
1282 *rLo = tLo;
sewardj5c34dc92004-07-19 12:48:11 +00001283 return;
1284 }
1285
1286 /* 32HLto64(e1,e2) */
1287 if (e->tag == Iex_Binop
1288 && e->Iex.Binop.op == Iop_32HLto64) {
1289 *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1);
1290 *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2);
1291 return;
1292 }
1293
sewardjbb53f8c2004-08-14 11:50:01 +00001294 /* 32Sto64(e) */
1295 if (e->tag == Iex_Unop
1296 && e->Iex.Unop.op == Iop_32Sto64) {
1297 HReg tLo = newVRegI(env);
1298 HReg tHi = newVRegI(env);
1299 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1300 addInstr(env, mk_MOVsd_RR(src,tHi));
1301 addInstr(env, mk_MOVsd_RR(src,tLo));
1302 addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(tHi)));
1303 *rHi = tHi;
1304 *rLo = tLo;
1305 return;
1306 }
1307
sewardje5427e82004-09-11 19:43:51 +00001308 /* 32Uto64(e) */
1309 if (e->tag == Iex_Unop
1310 && e->Iex.Unop.op == Iop_32Uto64) {
1311 HReg tLo = newVRegI(env);
1312 HReg tHi = newVRegI(env);
1313 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1314 addInstr(env, mk_MOVsd_RR(src,tLo));
1315 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tHi));
1316 *rHi = tHi;
1317 *rLo = tLo;
1318 return;
1319 }
1320
sewardj5c34dc92004-07-19 12:48:11 +00001321 /* 64-bit shifts */
1322 if (e->tag == Iex_Binop
1323 && e->Iex.Binop.op == Iop_Shl64) {
1324 /* We use the same ingenious scheme as gcc. Put the value
1325 to be shifted into %hi:%lo, and the shift amount into %cl.
1326 Then (dsts on right, a la ATT syntax):
1327
1328 shldl %cl, %lo, %hi -- make %hi be right for the shift amt
1329 -- %cl % 32
1330 shll %cl, %lo -- make %lo be right for the shift amt
1331 -- %cl % 32
1332
1333 Now, if (shift amount % 64) is in the range 32 .. 63, we have
1334 to do a fixup, which puts the result low half into the result
1335 high half, and zeroes the low half:
1336
1337 testl $32, %ecx
1338
1339 cmovnz %lo, %hi
1340 movl $0, %tmp -- sigh; need yet another reg
1341 cmovnz %tmp, %lo
1342 */
1343 HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
1344 tLo = newVRegI(env);
1345 tHi = newVRegI(env);
1346 tTemp = newVRegI(env);
1347 rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
1348 iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
1349 addInstr(env, mk_MOVsd_RR(rAmt, hregX86_ECX()));
1350 addInstr(env, mk_MOVsd_RR(sHi, tHi));
1351 addInstr(env, mk_MOVsd_RR(sLo, tLo));
1352 /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo and
1353 those regs are legitimately modifiable. */
sewardje5f384c2004-07-30 16:17:28 +00001354 addInstr(env, X86Instr_Sh3232(Xsh_SHL, 0/*%cl*/, tLo, tHi));
sewardj5c34dc92004-07-19 12:48:11 +00001355 addInstr(env, X86Instr_Sh32(Xsh_SHL, 0/*%cl*/, X86RM_Reg(tLo)));
sewardje8c922f2004-07-23 01:34:11 +00001356 addInstr(env, X86Instr_Test32(X86RI_Imm(32), X86RM_Reg(hregX86_ECX())));
sewardj5c34dc92004-07-19 12:48:11 +00001357 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tLo), tHi));
1358 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
1359 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tLo));
1360 *rHi = tHi;
1361 *rLo = tLo;
1362 return;
1363 }
1364
sewardj68511542004-07-28 00:15:44 +00001365 if (e->tag == Iex_Binop
1366 && e->Iex.Binop.op == Iop_Shr64) {
1367 /* We use the same ingenious scheme as gcc. Put the value
1368 to be shifted into %hi:%lo, and the shift amount into %cl.
1369 Then:
1370
1371 shrdl %cl, %hi, %lo -- make %lo be right for the shift amt
1372 -- %cl % 32
sewardj80f8c302004-07-29 22:21:31 +00001373 shrl %cl, %hi -- make %hi be right for the shift amt
sewardj68511542004-07-28 00:15:44 +00001374 -- %cl % 32
1375
1376 Now, if (shift amount % 64) is in the range 32 .. 63, we have
1377 to do a fixup, which puts the result high half into the result
1378 low half, and zeroes the high half:
1379
1380 testl $32, %ecx
1381
1382 cmovnz %hi, %lo
1383 movl $0, %tmp -- sigh; need yet another reg
1384 cmovnz %tmp, %hi
1385 */
1386 HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
1387 tLo = newVRegI(env);
1388 tHi = newVRegI(env);
1389 tTemp = newVRegI(env);
1390 rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
1391 iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
1392 addInstr(env, mk_MOVsd_RR(rAmt, hregX86_ECX()));
1393 addInstr(env, mk_MOVsd_RR(sHi, tHi));
1394 addInstr(env, mk_MOVsd_RR(sLo, tLo));
1395 /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo and
1396 those regs are legitimately modifiable. */
sewardje5f384c2004-07-30 16:17:28 +00001397 addInstr(env, X86Instr_Sh3232(Xsh_SHR, 0/*%cl*/, tHi, tLo));
sewardj68511542004-07-28 00:15:44 +00001398 addInstr(env, X86Instr_Sh32(Xsh_SHR, 0/*%cl*/, X86RM_Reg(tHi)));
1399 addInstr(env, X86Instr_Test32(X86RI_Imm(32), X86RM_Reg(hregX86_ECX())));
1400 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tHi), tLo));
1401 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
1402 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tHi));
1403 *rHi = tHi;
1404 *rLo = tLo;
1405 return;
1406 }
1407
sewardjcfded9a2004-09-09 11:44:16 +00001408 /* F64 -> I64 */
1409 /* Sigh, this is an almost exact copy of the F64 -> I32/I16 case.
1410 Unfortunately I see no easy way to avoid the duplication. */
1411 if (e->tag == Iex_Binop
1412 && e->Iex.Binop.op == Iop_F64toI64) {
1413 HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
1414 HReg rrm = iselIntExpr_R(env, e->Iex.Binop.arg1);
1415 HReg rrm2 = newVRegI(env);
sewardjcfded9a2004-09-09 11:44:16 +00001416 HReg tLo = newVRegI(env);
1417 HReg tHi = newVRegI(env);
1418
1419 /* Used several times ... */
1420 /* Careful ... this sharing is only safe because
1421 zero_esp/four_esp do not hold any registers which the
1422 register allocator could attempt to swizzle later. */
1423 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
1424 X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP());
1425
1426 /* rf now holds the value to be converted, and rrm holds the
1427 rounding mode value, encoded as per the IRRoundingMode enum.
1428 The first thing to do is set the FPU's rounding mode
1429 accordingly. */
1430
1431 /* Create a space, both for the control word messing, and for
1432 the actual store conversion. */
1433 /* subl $8, %esp */
1434 addInstr(env,
1435 X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(8), hregX86_ESP()));
1436 /* movl %rrm, %rrm2
1437 andl $3, %rrm2 -- shouldn't be needed; paranoia
1438 shll $10, %rrm2
1439 orl $0x037F, %rrm2
1440 movl %rrm2, 0(%esp)
1441 fldcw 0(%esp)
1442 */
1443 addInstr(env, mk_MOVsd_RR(rrm, rrm2));
1444 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(3), rrm2));
1445 addInstr(env, X86Instr_Sh32(Xsh_SHL, 10, X86RM_Reg(rrm2)));
1446 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Imm(0x037F), rrm2));
1447 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(rrm2), zero_esp));
1448 addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
1449
1450 /* gistll %rf, 0(%esp) */
1451 addInstr(env, X86Instr_FpLdStI(False/*store*/, 8, rf, zero_esp));
1452
1453 /* movl 0(%esp), %dstLo */
1454 /* movl 4(%esp), %dstHi */
1455 addInstr(env, X86Instr_Alu32R(
1456 Xalu_MOV, X86RMI_Mem(zero_esp), tLo));
1457 addInstr(env, X86Instr_Alu32R(
1458 Xalu_MOV, X86RMI_Mem(four_esp), tHi));
1459
1460 /* Restore default FPU control.
1461 movl $0x037F, 0(%esp)
1462 fldcw 0(%esp)
1463 */
1464 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Imm(0x037F), zero_esp));
1465 addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
1466
1467 /* addl $8, %esp */
1468 addInstr(env,
1469 X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(8), hregX86_ESP()));
1470
1471 *rHi = tHi;
1472 *rLo = tLo;
sewardjc4be80c2004-09-10 16:17:45 +00001473 return;
1474 }
1475
1476 if (e->tag == Iex_GetI) {
1477 /* First off, compute the index expression into an integer reg.
1478 The referenced address will then be 0 + ebp + reg*1, that is,
1479 an X86AMode_IRRS. */
1480 vassert(e->Iex.GetI.ty == Ity_I64);
1481 HReg tLo = newVRegI(env);
1482 HReg tHi = newVRegI(env);
1483 HReg idx = iselIntExpr_R(env, e->Iex.GetI.offset);
1484
1485 /* This (x86) is a little-endian target. The front end will
1486 have laid out the baseblock in accordance with the back-end's
1487 endianness, so this hardwired assumption here that the 64-bit
1488 value is stored little-endian is OK. */
1489 addInstr(env, X86Instr_Alu32R(
1490 Xalu_MOV,
1491 X86RMI_Mem(X86AMode_IRRS(0, hregX86_EBP(), idx, 0)),
1492 tLo));
1493 addInstr(env, X86Instr_Alu32R(
1494 Xalu_MOV,
1495 X86RMI_Mem(X86AMode_IRRS(4, hregX86_EBP(), idx, 0)),
1496 tHi));
1497 *rHi = tHi;
1498 *rLo = tLo;
1499 return;
sewardjcfded9a2004-09-09 11:44:16 +00001500 }
1501
sewardj597b71b2004-07-19 02:51:12 +00001502 ppIRExpr(e);
1503 vpanic("iselIntExpr64");
1504}
1505
1506
sewardj4042c7e2004-07-18 01:28:30 +00001507
sewardjc97096c2004-06-30 09:28:04 +00001508/*---------------------------------------------------------*/
sewardj3196daf2004-08-13 00:18:58 +00001509/*--- ISEL: Floating point expressions (64 bit) ---*/
1510/*---------------------------------------------------------*/
1511
1512/* Compute a 64-bit floating point value into a register, the identity
1513 of which is returned. As with iselIntExpr_R, the reg may be either
1514 real or virtual; in any case it must not be changed by subsequent
1515 code emitted by the caller. */
1516
sewardj3fc76d22004-08-31 11:47:54 +00001517/* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm:
1518
1519 Type S (1 bit) E (11 bits) F (52 bits)
1520 ---- --------- ----------- -----------
1521 signalling NaN u 2047 (max) .0uuuuu---u
1522 (with at least
1523 one 1 bit)
1524 quiet NaN u 2047 (max) .1uuuuu---u
1525
1526 negative infinity 1 2047 (max) .000000---0
1527
1528 positive infinity 0 2047 (max) .000000---0
1529
1530 negative zero 1 0 .000000---0
1531
1532 positive zero 0 0 .000000---0
1533*/
1534
sewardj89cd0932004-09-08 18:23:25 +00001535static HReg iselFltExpr ( ISelEnv* env, IRExpr* e )
1536{
1537 // MatchInfo mi;
1538 IRType ty = typeOfIRExpr(env->type_env,e);
1539 vassert(ty == Ity_F32);
1540
1541 if (e->tag == Iex_LDle) {
1542 X86AMode* am;
1543 HReg res = newVRegF(env);
1544 vassert(e->Iex.LDle.ty == Ity_F32);
1545 am = iselIntExpr_AMode(env, e->Iex.LDle.addr);
1546 addInstr(env, X86Instr_FpLdSt(True/*load*/, 4, res, am));
1547 return res;
1548 }
1549
1550 if (e->tag == Iex_Unop
1551 && e->Iex.Unop.op == Iop_F64toF32) {
1552 /* this is a no-op */
1553 return iselDblExpr(env, e->Iex.Unop.arg);
1554 }
1555
1556 ppIRExpr(e);
1557 vpanic("iselFltExpr");
1558}
1559
1560
sewardj3196daf2004-08-13 00:18:58 +00001561static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
1562{
sewardj33124f62004-08-30 17:54:18 +00001563 // MatchInfo mi;
1564 IRType ty = typeOfIRExpr(env->type_env,e);
sewardj3196daf2004-08-13 00:18:58 +00001565 vassert(e);
sewardj33124f62004-08-30 17:54:18 +00001566 vassert(ty == Ity_F64);
sewardj3196daf2004-08-13 00:18:58 +00001567
sewardjbb53f8c2004-08-14 11:50:01 +00001568 if (e->tag == Iex_Tmp) {
1569 return lookupIRTemp(env, e->Iex.Tmp.tmp);
1570 }
1571
sewardja58ea662004-08-15 03:12:41 +00001572 if (e->tag == Iex_Const) {
1573 union { UInt i64[2]; Double f64; } u;
1574 HReg freg = newVRegF(env);
1575 vassert(sizeof(u) == 8);
1576 vassert(sizeof(u.i64) == 8);
1577 vassert(sizeof(u.f64) == 8);
sewardj3fc76d22004-08-31 11:47:54 +00001578
1579 if (e->Iex.Const.con->tag == Ico_F64) {
1580 u.f64 = e->Iex.Const.con->Ico.F64;
1581 }
1582 else if (e->Iex.Const.con->tag == Ico_NaN64) {
1583 /* QNaN is 0 2047 1 0(51times)
1584 == 0b 11111111111b 1 0(51times)
1585 == 0x7FF8 0000 0000 0000
1586 */
1587 /* Since we're running on a little-endian target, and
1588 generating code for one: */
1589 u.i64[1] = 0x7FF80000;
1590 u.i64[0] = 0x00000000;
1591 }
1592 else
1593 vpanic("iselDblExpr(x86): const");
1594
sewardja58ea662004-08-15 03:12:41 +00001595 addInstr(env, X86Instr_Push(X86RMI_Imm(u.i64[1])));
1596 addInstr(env, X86Instr_Push(X86RMI_Imm(u.i64[0])));
1597 addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, freg,
1598 X86AMode_IR(0, hregX86_ESP())));
1599 addInstr(env, X86Instr_Alu32R(Xalu_ADD,
1600 X86RMI_Imm(8),
1601 hregX86_ESP()));
1602 return freg;
1603 }
1604
sewardj3196daf2004-08-13 00:18:58 +00001605 if (e->tag == Iex_LDle) {
1606 X86AMode* am;
1607 HReg res = newVRegF(env);
1608 vassert(e->Iex.LDle.ty == Ity_F64);
1609 am = iselIntExpr_AMode(env, e->Iex.LDle.addr);
1610 addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, res, am));
1611 return res;
1612 }
1613
sewardjbb53f8c2004-08-14 11:50:01 +00001614 if (e->tag == Iex_GetI) {
1615 /* First off, compute the index expression into an integer reg.
sewardj33124f62004-08-30 17:54:18 +00001616 The referenced address will then be 0 + ebp + reg*1, that is,
1617 an X86AMode_IRRS. */
sewardjbb53f8c2004-08-14 11:50:01 +00001618 HReg idx = iselIntExpr_R(env, e->Iex.GetI.offset);
1619 HReg res = newVRegF(env);
1620 addInstr(env,
1621 X86Instr_FpLdSt( True/*load*/, 8, res,
1622 X86AMode_IRRS(0, hregX86_EBP(), idx, 0)) );
1623 return res;
1624 }
1625
1626 if (e->tag == Iex_Binop) {
1627 X86FpOp fpop = Xfp_INVALID;
1628 switch (e->Iex.Binop.op) {
sewardj46de4072004-09-11 19:23:24 +00001629 case Iop_AddF64: fpop = Xfp_ADD; break;
1630 case Iop_SubF64: fpop = Xfp_SUB; break;
1631 case Iop_MulF64: fpop = Xfp_MUL; break;
1632 case Iop_DivF64: fpop = Xfp_DIV; break;
1633 case Iop_AtanF64: fpop = Xfp_ATAN; break;
1634 case Iop_PRemF64: fpop = Xfp_PREM; break;
sewardjbb53f8c2004-08-14 11:50:01 +00001635 default: break;
1636 }
1637 if (fpop != Xfp_INVALID) {
1638 HReg res = newVRegF(env);
1639 HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1);
1640 HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2);
1641 addInstr(env, X86Instr_FpBinary(fpop,srcL,srcR,res));
1642 return res;
1643 }
1644 }
1645
sewardje6709112004-09-10 18:37:18 +00001646 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_RoundF64) {
1647 HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
1648 HReg rrm = iselIntExpr_R(env, e->Iex.Binop.arg1);
1649 HReg rrm2 = newVRegI(env);
1650 HReg dst = newVRegF(env);
1651
1652 /* Used several times ... */
1653 /* Careful ... this sharing is only safe because
1654 zero_esp does not hold any registers which the
1655 register allocator could attempt to swizzle later. */
1656 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
1657
1658 /* rf now holds the value to be rounded, and rrm holds the
1659 rounding mode value, encoded as per the IRRoundingMode enum.
1660 The first thing to do is set the FPU's rounding mode
1661 accordingly. */
1662
1663 /* subl $4, %esp */
1664 addInstr(env,
1665 X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(4), hregX86_ESP()));
1666 /* movl %rrm, %rrm2
1667 andl $3, %rrm2 -- shouldn't be needed; paranoia
1668 shll $10, %rrm2
1669 orl $0x037F, %rrm2
1670 movl %rrm2, 0(%esp)
1671 fldcw 0(%esp)
1672 */
1673 addInstr(env, mk_MOVsd_RR(rrm, rrm2));
1674 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(3), rrm2));
1675 addInstr(env, X86Instr_Sh32(Xsh_SHL, 10, X86RM_Reg(rrm2)));
1676 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Imm(0x037F), rrm2));
1677 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(rrm2), zero_esp));
1678 addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
1679
1680 /* grndint %rf, %dst */
1681 addInstr(env, X86Instr_FpUnary(Xfp_ROUND, rf, dst));
1682
1683 /* Restore default FPU control.
1684 movl $0x037F, 0(%esp)
1685 fldcw 0(%esp)
1686 */
1687 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Imm(0x037F), zero_esp));
1688 addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
1689
1690 /* addl $4, %esp */
1691 addInstr(env,
1692 X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(4), hregX86_ESP()));
1693 return dst;
1694 }
1695
1696
sewardjbb53f8c2004-08-14 11:50:01 +00001697 if (e->tag == Iex_Unop) {
sewardjcfded9a2004-09-09 11:44:16 +00001698 X86FpOp fpop = Xfp_INVALID;
1699 switch (e->Iex.Unop.op) {
sewardj883b00b2004-09-11 09:30:24 +00001700 case Iop_NegF64: fpop = Xfp_NEG; break;
1701 case Iop_AbsF64: fpop = Xfp_ABS; break;
sewardjc4be80c2004-09-10 16:17:45 +00001702 case Iop_SqrtF64: fpop = Xfp_SQRT; break;
1703 case Iop_SinF64: fpop = Xfp_SIN; break;
1704 case Iop_CosF64: fpop = Xfp_COS; break;
sewardjcfded9a2004-09-09 11:44:16 +00001705 default: break;
1706 }
1707 if (fpop != Xfp_INVALID) {
1708 HReg res = newVRegF(env);
1709 HReg src = iselDblExpr(env, e->Iex.Unop.arg);
1710 addInstr(env, X86Instr_FpUnary(fpop,src,res));
1711 return res;
1712 }
1713 }
1714
1715 if (e->tag == Iex_Unop) {
sewardj89cd0932004-09-08 18:23:25 +00001716 switch (e->Iex.Unop.op) {
1717 case Iop_I32toF64: {
1718 HReg dst = newVRegF(env);
1719 HReg ri = iselIntExpr_R(env, e->Iex.Unop.arg);
1720 addInstr(env, X86Instr_Push(X86RMI_Reg(ri)));
1721 addInstr(env, X86Instr_FpLdStI(
1722 True/*load*/, 4, dst,
1723 X86AMode_IR(0, hregX86_ESP())));
1724 addInstr(env, X86Instr_Alu32R(Xalu_ADD,
1725 X86RMI_Imm(4),
1726 hregX86_ESP()));
1727 return dst;
1728 }
sewardjbdc7d212004-09-09 02:46:40 +00001729 case Iop_I64toF64: {
1730 HReg dst = newVRegF(env);
1731 HReg rHi,rLo;
1732 iselIntExpr64( &rHi, &rLo, env, e->Iex.Unop.arg);
1733 addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
1734 addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
1735 addInstr(env, X86Instr_FpLdStI(
1736 True/*load*/, 8, dst,
1737 X86AMode_IR(0, hregX86_ESP())));
1738 addInstr(env, X86Instr_Alu32R(Xalu_ADD,
1739 X86RMI_Imm(8),
1740 hregX86_ESP()));
1741 return dst;
1742 }
sewardj89cd0932004-09-08 18:23:25 +00001743 case Iop_F32toF64:
1744 /* this is a no-op */
1745 return iselFltExpr(env, e->Iex.Unop.arg);
1746 default:
1747 break;
sewardjbb53f8c2004-08-14 11:50:01 +00001748 }
sewardj89cd0932004-09-08 18:23:25 +00001749
sewardjbb53f8c2004-08-14 11:50:01 +00001750 }
1751
sewardj33124f62004-08-30 17:54:18 +00001752 /* --------- MULTIPLEX --------- */
1753 if (e->tag == Iex_Mux0X) {
1754 if (ty == Ity_F64
1755 && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
1756 HReg r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
1757 HReg rX = iselDblExpr(env, e->Iex.Mux0X.exprX);
1758 HReg r0 = iselDblExpr(env, e->Iex.Mux0X.expr0);
1759 HReg dst = newVRegF(env);
sewardj3fc76d22004-08-31 11:47:54 +00001760 addInstr(env, X86Instr_FpUnary(Xfp_MOV,rX,dst));
sewardj33124f62004-08-30 17:54:18 +00001761 addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8)));
1762 addInstr(env, X86Instr_FpCMov(Xcc_Z,r0,dst));
1763 return dst;
1764 }
1765 }
1766
sewardj3196daf2004-08-13 00:18:58 +00001767 ppIRExpr(e);
sewardjbb53f8c2004-08-14 11:50:01 +00001768 vpanic("iselDblExpr");
sewardj3196daf2004-08-13 00:18:58 +00001769}
1770
1771
1772
1773/*---------------------------------------------------------*/
sewardjc97096c2004-06-30 09:28:04 +00001774/*--- ISEL: Statements ---*/
1775/*---------------------------------------------------------*/
1776
sewardjf13a16a2004-07-05 17:10:14 +00001777static void iselStmt ( ISelEnv* env, IRStmt* stmt )
sewardjc97096c2004-06-30 09:28:04 +00001778{
sewardj1f40a0a2004-07-21 12:28:07 +00001779 if (vex_verbosity > 0) {
1780 vex_printf("-- ");
1781 ppIRStmt(stmt);
1782 vex_printf("\n");
1783 }
sewardj66f2f792004-06-30 16:37:16 +00001784
sewardjc97096c2004-06-30 09:28:04 +00001785 switch (stmt->tag) {
1786
sewardj60f4e3c2004-07-19 01:56:50 +00001787 /* --------- STORE --------- */
sewardjd9c2b792004-07-08 01:44:38 +00001788 case Ist_STle: {
sewardja58ea662004-08-15 03:12:41 +00001789 X86AMode* am;
sewardjd9c2b792004-07-08 01:44:38 +00001790 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.STle.addr);
1791 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.STle.data);
1792 vassert(tya == Ity_I32);
sewardja58ea662004-08-15 03:12:41 +00001793 am = iselIntExpr_AMode(env, stmt->Ist.STle.addr);
sewardjd9c2b792004-07-08 01:44:38 +00001794 if (tyd == Ity_I32) {
sewardja58ea662004-08-15 03:12:41 +00001795 X86RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data);
sewardjd9c2b792004-07-08 01:44:38 +00001796 addInstr(env, X86Instr_Alu32M(Xalu_MOV,ri,am));
1797 return;
1798 }
sewardj60f4e3c2004-07-19 01:56:50 +00001799 if (tyd == Ity_I8 || tyd == Ity_I16) {
sewardja58ea662004-08-15 03:12:41 +00001800 HReg r = iselIntExpr_R(env, stmt->Ist.STle.data);
sewardj60f4e3c2004-07-19 01:56:50 +00001801 addInstr(env, X86Instr_Store(tyd==Ity_I8 ? 1 : 2,
1802 r,am));
sewardj443cd9d2004-07-18 23:06:45 +00001803 return;
1804 }
sewardja58ea662004-08-15 03:12:41 +00001805 if (tyd == Ity_F64) {
1806 HReg r = iselDblExpr(env, stmt->Ist.STle.data);
1807 addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, r, am));
1808 return;
1809 }
sewardj89cd0932004-09-08 18:23:25 +00001810 if (tyd == Ity_F32) {
1811 HReg r = iselFltExpr(env, stmt->Ist.STle.data);
1812 addInstr(env, X86Instr_FpLdSt(False/*store*/, 4, r, am));
1813 return;
1814 }
sewardjcfded9a2004-09-09 11:44:16 +00001815 if (tyd == Ity_I64) {
1816 HReg vHi, vLo, rA;
1817 iselIntExpr64(&vHi, &vLo, env, stmt->Ist.STle.data);
1818 rA = iselIntExpr_R(env, stmt->Ist.STle.addr);
1819 addInstr(env, X86Instr_Alu32M(
1820 Xalu_MOV, X86RI_Reg(vLo), X86AMode_IR(0, rA)));
1821 addInstr(env, X86Instr_Alu32M(
1822 Xalu_MOV, X86RI_Reg(vHi), X86AMode_IR(4, rA)));
1823 return;
1824 }
sewardjd9c2b792004-07-08 01:44:38 +00001825 break;
sewardj79453082004-07-02 17:29:14 +00001826 }
1827
sewardj60f4e3c2004-07-19 01:56:50 +00001828 /* --------- PUT --------- */
sewardjd9c2b792004-07-08 01:44:38 +00001829 case Ist_Put: {
1830 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.expr);
1831 if (ty == Ity_I32) {
1832 /* We're going to write to memory, so compute the RHS into an
1833 X86RI. */
1834 X86RI* ri = iselIntExpr_RI(env, stmt->Ist.Put.expr);
1835 addInstr(env,
1836 X86Instr_Alu32M(
1837 Xalu_MOV,
1838 ri,
1839 X86AMode_IR(stmt->Ist.Put.offset,hregX86_EBP())
1840 ));
1841 return;
1842 }
sewardj597b71b2004-07-19 02:51:12 +00001843 if (ty == Ity_I8 || ty == Ity_I16) {
sewardjbb53f8c2004-08-14 11:50:01 +00001844 HReg r = iselIntExpr_R(env, stmt->Ist.Put.expr);
sewardj443cd9d2004-07-18 23:06:45 +00001845 addInstr(env, X86Instr_Store(
sewardj597b71b2004-07-19 02:51:12 +00001846 ty==Ity_I8 ? 1 : 2,
1847 r,
sewardj443cd9d2004-07-18 23:06:45 +00001848 X86AMode_IR(stmt->Ist.Put.offset,
1849 hregX86_EBP())));
1850 return;
1851 }
sewardjd9c2b792004-07-08 01:44:38 +00001852 break;
1853 }
sewardje8e9d732004-07-16 21:03:45 +00001854
sewardj3196daf2004-08-13 00:18:58 +00001855 /* --------- Indexed PUT --------- */
1856 case Ist_PutI: {
1857 /* First off, compute the index expression into an integer reg.
1858 The written address will then be 0 + ebp + reg*1, that is, an
1859 X86AMode_IRRS. */
1860 HReg idx = iselIntExpr_R(env, stmt->Ist.PutI.offset);
1861
1862 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.PutI.expr);
1863 if (ty == Ity_F64) {
1864 HReg val = iselDblExpr(env, stmt->Ist.PutI.expr);
1865 addInstr(env,
1866 X86Instr_FpLdSt( False/*store*/, 8, val,
1867 X86AMode_IRRS(0, hregX86_EBP(), idx, 0)) );
1868 return;
1869 }
sewardj3fc76d22004-08-31 11:47:54 +00001870 if (ty == Ity_I8) {
1871 HReg r = iselIntExpr_R(env, stmt->Ist.Put.expr);
1872 addInstr(env, X86Instr_Store(
1873 1,
1874 r,
1875 X86AMode_IRRS(0, hregX86_EBP(), idx, 0)) );
1876 return;
1877 }
sewardj3196daf2004-08-13 00:18:58 +00001878 break;
1879 }
1880
sewardj60f4e3c2004-07-19 01:56:50 +00001881 /* --------- TMP --------- */
sewardjd9c2b792004-07-08 01:44:38 +00001882 case Ist_Tmp: {
1883 IRTemp tmp = stmt->Ist.Tmp.tmp;
1884 IRType ty = lookupIRTypeEnv(env->type_env, tmp);
sewardj4042c7e2004-07-18 01:28:30 +00001885 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
sewardjd9c2b792004-07-08 01:44:38 +00001886 X86RMI* rmi = iselIntExpr_RMI(env, stmt->Ist.Tmp.expr);
1887 HReg dst = lookupIRTemp(env, tmp);
1888 addInstr(env, X86Instr_Alu32R(Xalu_MOV,rmi,dst));
1889 return;
1890 }
sewardj597b71b2004-07-19 02:51:12 +00001891 if (ty == Ity_I64) {
1892 HReg rHi, rLo, dstHi, dstLo;
sewardj38ff3d82004-07-26 23:27:08 +00001893 iselIntExpr64(&rHi,&rLo, env, stmt->Ist.Tmp.expr);
sewardj597b71b2004-07-19 02:51:12 +00001894 lookupIRTemp64( &dstHi, &dstLo, env, tmp);
1895 addInstr(env, mk_MOVsd_RR(rHi,dstHi) );
1896 addInstr(env, mk_MOVsd_RR(rLo,dstLo) );
1897 return;
1898 }
sewardjd7cb8532004-08-17 23:59:23 +00001899 if (ty == Ity_Bit) {
1900 X86CondCode cond = iselCondCode(env, stmt->Ist.Tmp.expr);
1901 HReg dst = lookupIRTemp(env, tmp);
1902 addInstr(env, X86Instr_Set32(cond, dst));
1903 return;
1904 }
sewardjbb53f8c2004-08-14 11:50:01 +00001905 if (ty == Ity_F64) {
1906 HReg dst = lookupIRTemp(env, tmp);
1907 HReg src = iselDblExpr(env, stmt->Ist.Tmp.expr);
1908 addInstr(env, X86Instr_FpUnary(Xfp_MOV,src,dst));
1909 return;
1910 }
sewardjd9c2b792004-07-08 01:44:38 +00001911 break;
1912 }
sewardj79453082004-07-02 17:29:14 +00001913
sewardj60f4e3c2004-07-19 01:56:50 +00001914 /* --------- EXIT --------- */
sewardje8e9d732004-07-16 21:03:45 +00001915 case Ist_Exit: {
sewardj2e56f9f2004-07-24 01:24:38 +00001916 X86RI* dst;
1917 X86CondCode cc;
1918 if (stmt->Ist.Exit.dst->tag != Ico_U32)
1919 vpanic("isel_x86: Ist_Exit: dst is not a 32-bit value");
1920 dst = iselIntExpr_RI(env, IRExpr_Const(stmt->Ist.Exit.dst));
1921 cc = iselCondCode(env,stmt->Ist.Exit.cond);
sewardj750f4072004-07-26 22:39:11 +00001922 addInstr(env, X86Instr_Goto(Ijk_Boring, cc, dst));
sewardj2e56f9f2004-07-24 01:24:38 +00001923 return;
sewardje8e9d732004-07-16 21:03:45 +00001924 }
1925
sewardjc97096c2004-06-30 09:28:04 +00001926 default: break;
1927 }
sewardj35421a32004-07-05 13:12:34 +00001928 ppIRStmt(stmt);
1929 vpanic("iselStmt");
sewardjc97096c2004-06-30 09:28:04 +00001930}
1931
1932
1933/*---------------------------------------------------------*/
1934/*--- ISEL: Basic block terminators (Nexts) ---*/
1935/*---------------------------------------------------------*/
1936
sewardje539a402004-07-14 18:24:17 +00001937static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
sewardjc97096c2004-06-30 09:28:04 +00001938{
sewardje8e9d732004-07-16 21:03:45 +00001939 X86RI* ri;
sewardj1f40a0a2004-07-21 12:28:07 +00001940 if (vex_verbosity > 0) {
sewardj750f4072004-07-26 22:39:11 +00001941 vex_printf("-- goto {");
1942 ppIRJumpKind(jk);
1943 vex_printf("} ");
sewardj1f40a0a2004-07-21 12:28:07 +00001944 ppIRExpr(next);
1945 vex_printf("\n");
1946 }
sewardje8e9d732004-07-16 21:03:45 +00001947 ri = iselIntExpr_RI(env, next);
sewardj750f4072004-07-26 22:39:11 +00001948 addInstr(env, X86Instr_Goto(jk, Xcc_ALWAYS,ri));
sewardjc97096c2004-06-30 09:28:04 +00001949}
1950
1951
1952/*---------------------------------------------------------*/
1953/*--- Insn selector top-level ---*/
1954/*---------------------------------------------------------*/
1955
sewardj194d54a2004-07-03 19:08:18 +00001956/* Translate an entire BB to x86 code. */
1957
sewardj36ca5132004-07-24 13:12:23 +00001958HInstrArray* iselBB_X86 ( IRBB* bb, Addr64(*find_helper)(Char*) )
sewardjc97096c2004-06-30 09:28:04 +00001959{
sewardj597b71b2004-07-19 02:51:12 +00001960 Int i, j;
sewardje8e9d732004-07-16 21:03:45 +00001961 HReg hreg, hregHI;
sewardjc97096c2004-06-30 09:28:04 +00001962
1963 /* Make up an initial environment to use. */
sewardj35421a32004-07-05 13:12:34 +00001964 ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv));
sewardj194d54a2004-07-03 19:08:18 +00001965 env->vreg_ctr = 0;
sewardjc97096c2004-06-30 09:28:04 +00001966
sewardj36ca5132004-07-24 13:12:23 +00001967 /* Register helper-function-finder. */
1968 env->find_helper = find_helper;
1969
sewardjc97096c2004-06-30 09:28:04 +00001970 /* Set up output code array. */
sewardj2cd80dc2004-07-02 15:20:40 +00001971 env->code = newHInstrArray();
sewardjc97096c2004-06-30 09:28:04 +00001972
1973 /* Copy BB's type env. */
1974 env->type_env = bb->tyenv;
1975
1976 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
1977 change as we go along. */
sewardje539a402004-07-14 18:24:17 +00001978 env->n_vregmap = bb->tyenv->types_used;
1979 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
sewardje8e9d732004-07-16 21:03:45 +00001980 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
sewardjc97096c2004-06-30 09:28:04 +00001981
1982 /* For each IR temporary, allocate a suitably-kinded virtual
1983 register. */
sewardj597b71b2004-07-19 02:51:12 +00001984 j = 0;
sewardjc97096c2004-06-30 09:28:04 +00001985 for (i = 0; i < env->n_vregmap; i++) {
sewardje8e9d732004-07-16 21:03:45 +00001986 hregHI = hreg = INVALID_HREG;
sewardje539a402004-07-14 18:24:17 +00001987 switch (bb->tyenv->types[i]) {
sewardje8e9d732004-07-16 21:03:45 +00001988 case Ity_Bit:
1989 case Ity_I8:
sewardj4042c7e2004-07-18 01:28:30 +00001990 case Ity_I16:
sewardj597b71b2004-07-19 02:51:12 +00001991 case Ity_I32: hreg = mkHReg(j++, HRcInt, True); break;
1992 case Ity_I64: hreg = mkHReg(j++, HRcInt, True);
1993 hregHI = mkHReg(j++, HRcInt, True); break;
sewardj89cd0932004-09-08 18:23:25 +00001994 case Ity_F32:
sewardjbb53f8c2004-08-14 11:50:01 +00001995 case Ity_F64: hreg = mkHReg(j++, HRcFloat, True); break;
sewardje8e9d732004-07-16 21:03:45 +00001996 default: ppIRType(bb->tyenv->types[i]);
1997 vpanic("iselBB: IRTemp type");
sewardjc97096c2004-06-30 09:28:04 +00001998 }
sewardje8e9d732004-07-16 21:03:45 +00001999 env->vregmap[i] = hreg;
2000 env->vregmapHI[i] = hregHI;
sewardjc97096c2004-06-30 09:28:04 +00002001 }
sewardje322b0a2004-07-28 07:12:30 +00002002 env->vreg_ctr = j;
sewardjc97096c2004-06-30 09:28:04 +00002003
2004 /* Ok, finally we can iterate over the statements. */
sewardjd7cb8532004-08-17 23:59:23 +00002005 for (i = 0; i < bb->stmts_used; i++)
sewardj39e3f242004-08-18 16:54:52 +00002006 if (bb->stmts[i])
2007 iselStmt(env,bb->stmts[i]);
sewardjc97096c2004-06-30 09:28:04 +00002008
sewardje539a402004-07-14 18:24:17 +00002009 iselNext(env,bb->next,bb->jumpkind);
sewardj2cd80dc2004-07-02 15:20:40 +00002010
sewardj194d54a2004-07-03 19:08:18 +00002011 /* record the number of vregs we used. */
2012 env->code->n_vregs = env->vreg_ctr;
sewardj2cd80dc2004-07-02 15:20:40 +00002013 return env->code;
sewardjc97096c2004-06-30 09:28:04 +00002014}
sewardj887a11a2004-07-05 17:26:47 +00002015
2016
2017/*---------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +00002018/*--- end host-x86/isel.c ---*/
sewardj887a11a2004-07-05 17:26:47 +00002019/*---------------------------------------------------------------*/