blob: fdc517a393ee81d5514a9ea783c4b2d9df202859 [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;
76 case Iex_Const:
77 if (e->tag != Iex_Const) return False;
78 switch (p->Iex.Const.con->tag) {
79 case Ico_U8: return e->Iex.Const.con->tag==Ico_U8
80 ? (p->Iex.Const.con->Ico.U8
81 == e->Iex.Const.con->Ico.U8)
82 : False;
83 case Ico_U16: return e->Iex.Const.con->tag==Ico_U16
84 ? (p->Iex.Const.con->Ico.U16
85 == e->Iex.Const.con->Ico.U16)
86 : False;
87 case Ico_U32: return e->Iex.Const.con->tag==Ico_U32
88 ? (p->Iex.Const.con->Ico.U32
89 == e->Iex.Const.con->Ico.U32)
90 : False;
91 case Ico_U64: return e->Iex.Const.con->tag==Ico_U64
92 ? (p->Iex.Const.con->Ico.U64
93 == e->Iex.Const.con->Ico.U64)
94 : False;
95 }
96 vpanic("matchIRExpr.Iex_Const");
97 /*NOTREACHED*/
98 default:
99 ppIRExpr(p);
100 vpanic("match");
101 }
102}
103
104static Bool matchIRExpr ( MatchInfo* mi, IRExpr* p/*attern*/, IRExpr* e/*xpr*/ )
105{
106 Int i;
107 for (i = 0; i < N_MATCH_BINDERS; i++)
108 mi->bindee[i] = NULL;
109 return matchWrk(mi, p, e);
110}
111
112/*-----*/
113/* These are duplicated in x86toIR.c */
114static IRExpr* unop ( IROp op, IRExpr* a )
115{
116 return IRExpr_Unop(op, a);
117}
118
119static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
120{
121 return IRExpr_Binop(op, a1, a2);
122}
123
124static IRExpr* bind ( Int binder )
125{
126 return IRExpr_Binder(binder);
127}
128
129
130
131
132/*---------------------------------------------------------*/
sewardjc97096c2004-06-30 09:28:04 +0000133/*--- ISelEnv ---*/
134/*---------------------------------------------------------*/
135
136/* This carries around:
137
sewardj36ca5132004-07-24 13:12:23 +0000138 - A function for looking up the address of helper functions.
139
sewardjc97096c2004-06-30 09:28:04 +0000140 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
141 might encounter. This is computed before insn selection starts,
142 and does not change.
143
144 - A mapping from IRTemp to HReg. This tells the insn selector
sewardje8e9d732004-07-16 21:03:45 +0000145 which virtual register(s) are associated with each IRTemp
146 temporary. This is computed before insn selection starts, and
147 does not change. We expect this mapping to map precisely the
148 same set of IRTemps as the type mapping does.
149
150 - vregmap holds the primary register for the IRTemp.
151 - vregmapHI is only used for 64-bit integer-typed
152 IRTemps. It holds the identity of a second
153 32-bit virtual HReg, which holds the high half
154 of the value.
sewardjc97096c2004-06-30 09:28:04 +0000155
156 - The code array, that is, the insns selected so far.
157
158 - A counter, for generating new virtual registers.
159
sewardje8e9d732004-07-16 21:03:45 +0000160 Note, this is all host-independent. */
sewardjc97096c2004-06-30 09:28:04 +0000161
162typedef
163 struct {
sewardj36ca5132004-07-24 13:12:23 +0000164 Addr64 (*find_helper)(Char*);
165
sewardj194d54a2004-07-03 19:08:18 +0000166 IRTypeEnv* type_env;
sewardjc97096c2004-06-30 09:28:04 +0000167
sewardje539a402004-07-14 18:24:17 +0000168 HReg* vregmap;
sewardje8e9d732004-07-16 21:03:45 +0000169 HReg* vregmapHI;
sewardj194d54a2004-07-03 19:08:18 +0000170 Int n_vregmap;
sewardjc97096c2004-06-30 09:28:04 +0000171
sewardj2cd80dc2004-07-02 15:20:40 +0000172 HInstrArray* code;
sewardjc97096c2004-06-30 09:28:04 +0000173
sewardj194d54a2004-07-03 19:08:18 +0000174 Int vreg_ctr;
sewardjc97096c2004-06-30 09:28:04 +0000175 }
176 ISelEnv;
177
178
179static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
180{
sewardje539a402004-07-14 18:24:17 +0000181 vassert(tmp >= 0);
182 vassert(tmp < env->n_vregmap);
183 return env->vregmap[tmp];
sewardjc97096c2004-06-30 09:28:04 +0000184}
185
sewardj597b71b2004-07-19 02:51:12 +0000186static void lookupIRTemp64 ( HReg* vrHI, HReg* vrLO, ISelEnv* env, IRTemp tmp )
sewardje8e9d732004-07-16 21:03:45 +0000187{
188 vassert(tmp >= 0);
189 vassert(tmp < env->n_vregmap);
sewardj597b71b2004-07-19 02:51:12 +0000190 vassert(env->vregmapHI[tmp] != INVALID_HREG);
sewardje8e9d732004-07-16 21:03:45 +0000191 *vrLO = env->vregmap[tmp];
192 *vrHI = env->vregmapHI[tmp];
193}
194
sewardj2cd80dc2004-07-02 15:20:40 +0000195static void addInstr ( ISelEnv* env, X86Instr* instr )
sewardjc97096c2004-06-30 09:28:04 +0000196{
sewardj2cd80dc2004-07-02 15:20:40 +0000197 addHInstr(env->code, instr);
sewardj1f40a0a2004-07-21 12:28:07 +0000198 if (vex_verbosity > 0) {
199 ppX86Instr(instr);
200 vex_printf("\n");
201 }
sewardjc97096c2004-06-30 09:28:04 +0000202}
203
204static HReg newVRegI ( ISelEnv* env )
205{
sewardj194d54a2004-07-03 19:08:18 +0000206 HReg reg = mkHReg(env->vreg_ctr, HRcInt, True/*virtual reg*/);
207 env->vreg_ctr++;
sewardjc97096c2004-06-30 09:28:04 +0000208 return reg;
209}
210
211
212/*---------------------------------------------------------*/
sewardj597b71b2004-07-19 02:51:12 +0000213/*--- ISEL: Integer expressions (32/16/8 bit) ---*/
sewardjc97096c2004-06-30 09:28:04 +0000214/*---------------------------------------------------------*/
215
sewardj66f2f792004-06-30 16:37:16 +0000216/* forwards ... */
sewardj4042c7e2004-07-18 01:28:30 +0000217static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e );
218static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e );
sewardje8e9d732004-07-16 21:03:45 +0000219static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e );
sewardj597b71b2004-07-19 02:51:12 +0000220static void iselIntExpr64 ( HReg* rHi, HReg* rLo,
221 ISelEnv* env, IRExpr* e );
sewardj66f2f792004-06-30 16:37:16 +0000222
223
sewardj443cd9d2004-07-18 23:06:45 +0000224static X86Instr* mk_MOVsd_RR ( HReg src, HReg dst )
sewardj66f2f792004-06-30 16:37:16 +0000225{
sewardj35421a32004-07-05 13:12:34 +0000226 vassert(hregClass(src) == HRcInt);
227 vassert(hregClass(dst) == HRcInt);
sewardj66f2f792004-06-30 16:37:16 +0000228 return X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst);
229}
230
231
sewardjc97096c2004-06-30 09:28:04 +0000232/* Select insns for an integer-typed expression, and add them to the
sewardj597b71b2004-07-19 02:51:12 +0000233 code list. Return a reg holding the result. This reg may be
234 either a real or virtual reg; you get no guarantees. THE RETURNED
235 REG MUST NOT BE MODIFIED. If you want to modify it, ask for a new
236 vreg, copy it in there, and modify the copy. The register
237 allocator will do its best to map both vregs to the same real
238 register, so the copies will often disappear later in the game.
sewardj4042c7e2004-07-18 01:28:30 +0000239
240 This should handle expressions of 32, 16 and 8-bit type. All
241 results are returned in a 32-bit register. For 16- and 8-bit
242 expressions, the upper 16/24 bits are arbitrary, so you should
sewardj597b71b2004-07-19 02:51:12 +0000243 mask or sign extend partial values if necessary.
sewardjc97096c2004-06-30 09:28:04 +0000244*/
sewardj66f2f792004-06-30 16:37:16 +0000245static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
sewardjc97096c2004-06-30 09:28:04 +0000246{
sewardj443cd9d2004-07-18 23:06:45 +0000247 MatchInfo mi;
248 DECLARE_PATTERN(p_32to1_then_1Uto8);
249
sewardje8e9d732004-07-16 21:03:45 +0000250 IRType ty = typeOfIRExpr(env->type_env,e);
sewardj4042c7e2004-07-18 01:28:30 +0000251 vassert(ty == Ity_I32 || Ity_I16 || Ity_I8);
sewardjc97096c2004-06-30 09:28:04 +0000252
253 switch (e->tag) {
254
sewardj60f4e3c2004-07-19 01:56:50 +0000255 /* --------- TEMP --------- */
sewardje8e9d732004-07-16 21:03:45 +0000256 case Iex_Tmp: {
sewardje8e9d732004-07-16 21:03:45 +0000257 return lookupIRTemp(env, e->Iex.Tmp.tmp);
258 }
sewardjc97096c2004-06-30 09:28:04 +0000259
sewardj60f4e3c2004-07-19 01:56:50 +0000260 /* --------- LOAD --------- */
sewardje8e9d732004-07-16 21:03:45 +0000261 case Iex_LDle: {
sewardje8e9d732004-07-16 21:03:45 +0000262 HReg dst = newVRegI(env);
sewardj4042c7e2004-07-18 01:28:30 +0000263 X86AMode* amode = iselIntExpr_AMode ( env, e->Iex.LDle.addr );
264 if (ty == Ity_I32) {
265 addInstr(env, X86Instr_Alu32R(Xalu_MOV,
266 X86RMI_Mem(amode), dst) );
267 return dst;
268 }
269 if (ty == Ity_I16) {
270 addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
271 return dst;
272 }
sewardj443cd9d2004-07-18 23:06:45 +0000273 if (ty == Ity_I8) {
274 addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
275 return dst;
276 }
sewardj4042c7e2004-07-18 01:28:30 +0000277 break;
sewardje8e9d732004-07-16 21:03:45 +0000278 }
279
sewardj60f4e3c2004-07-19 01:56:50 +0000280 /* --------- BINARY OP --------- */
sewardje8e9d732004-07-16 21:03:45 +0000281 case Iex_Binop: {
282 X86AluOp aluOp;
283 X86ShiftOp shOp;
sewardj8c7f1ab2004-07-29 20:31:09 +0000284
sewardj4042c7e2004-07-18 01:28:30 +0000285 /* Is it an addition or logical style op? */
sewardje8e9d732004-07-16 21:03:45 +0000286 switch (e->Iex.Binop.op) {
sewardja2384712004-07-29 14:36:40 +0000287 case Iop_Add8: case Iop_Add16: case Iop_Add32:
sewardj1813dbe2004-07-28 17:09:04 +0000288 aluOp = Xalu_ADD; break;
sewardj60f4e3c2004-07-19 01:56:50 +0000289 case Iop_Sub8: case Iop_Sub16: case Iop_Sub32:
290 aluOp = Xalu_SUB; break;
sewardj5c34dc92004-07-19 12:48:11 +0000291 case Iop_And8: case Iop_And16: case Iop_And32:
292 aluOp = Xalu_AND; break;
sewardj750f4072004-07-26 22:39:11 +0000293 case Iop_Or8: case Iop_Or16: case Iop_Or32:
sewardj597b71b2004-07-19 02:51:12 +0000294 aluOp = Xalu_OR; break;
sewardja2384712004-07-29 14:36:40 +0000295 case Iop_Xor8: case Iop_Xor16: case Iop_Xor32:
sewardj597b71b2004-07-19 02:51:12 +0000296 aluOp = Xalu_XOR; break;
sewardj60f4e3c2004-07-19 01:56:50 +0000297 case Iop_Mul32: aluOp = Xalu_MUL; break;
sewardje8e9d732004-07-16 21:03:45 +0000298 default: aluOp = Xalu_INVALID; break;
299 }
300 /* For commutative ops we assume any literal
sewardj66f2f792004-06-30 16:37:16 +0000301 values are on the second operand. */
sewardje8e9d732004-07-16 21:03:45 +0000302 if (aluOp != Xalu_INVALID) {
sewardj66f2f792004-06-30 16:37:16 +0000303 HReg dst = newVRegI(env);
304 HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
305 X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
sewardj443cd9d2004-07-18 23:06:45 +0000306 addInstr(env, mk_MOVsd_RR(reg,dst));
sewardje8e9d732004-07-16 21:03:45 +0000307 addInstr(env, X86Instr_Alu32R(aluOp, rmi, dst));
sewardj66f2f792004-06-30 16:37:16 +0000308 return dst;
sewardjc97096c2004-06-30 09:28:04 +0000309 }
sewardj8c7f1ab2004-07-29 20:31:09 +0000310
sewardj4042c7e2004-07-18 01:28:30 +0000311 /* Perhaps a shift op? */
sewardje8e9d732004-07-16 21:03:45 +0000312 switch (e->Iex.Binop.op) {
sewardj1813dbe2004-07-28 17:09:04 +0000313 case Iop_Shl32: case Iop_Shl16: case Iop_Shl8:
314 shOp = Xsh_SHL; break;
315 case Iop_Shr32: case Iop_Shr16: case Iop_Shr8:
sewardj5c34dc92004-07-19 12:48:11 +0000316 shOp = Xsh_SHR; break;
sewardj8c7f1ab2004-07-29 20:31:09 +0000317 case Iop_Sar32: case Iop_Sar16: case Iop_Sar8:
sewardj1813dbe2004-07-28 17:09:04 +0000318 shOp = Xsh_SAR; break;
319 default:
320 shOp = Xsh_INVALID; break;
sewardje8e9d732004-07-16 21:03:45 +0000321 }
322 if (shOp != Xsh_INVALID) {
sewardj8c7f1ab2004-07-29 20:31:09 +0000323 HReg dst = newVRegI(env);
sewardj38ff3d82004-07-26 23:27:08 +0000324
325 /* regL = the value to be shifted */
sewardj96efe572004-07-03 14:48:24 +0000326 HReg regL = iselIntExpr_R(env, e->Iex.Binop.arg1);
sewardj443cd9d2004-07-18 23:06:45 +0000327 addInstr(env, mk_MOVsd_RR(regL,dst));
sewardj38ff3d82004-07-26 23:27:08 +0000328
sewardj5c34dc92004-07-19 12:48:11 +0000329 /* Do any necessary widening for 16/8 bit operands */
330 switch (e->Iex.Binop.op) {
331 case Iop_Shr8:
332 addInstr(env, X86Instr_Alu32R(
333 Xalu_AND, X86RMI_Imm(0xFF), dst));
334 break;
335 case Iop_Shr16:
336 addInstr(env, X86Instr_Alu32R(
337 Xalu_AND, X86RMI_Imm(0xFFFF), dst));
338 break;
sewardj8c7f1ab2004-07-29 20:31:09 +0000339 case Iop_Sar8:
340 addInstr(env, X86Instr_Sh32(Xsh_SHL, 24, X86RM_Reg(dst)));
341 addInstr(env, X86Instr_Sh32(Xsh_SAR, 24, X86RM_Reg(dst)));
342 break;
343 case Iop_Sar16:
344 addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(dst)));
345 addInstr(env, X86Instr_Sh32(Xsh_SAR, 16, X86RM_Reg(dst)));
346 break;
sewardj5c34dc92004-07-19 12:48:11 +0000347 default: break;
348 }
sewardj38ff3d82004-07-26 23:27:08 +0000349
350 /* Now consider the shift amount. If it's a literal, we
351 can do a much better job than the general case. */
352 if (e->Iex.Binop.arg2->tag == Iex_Const) {
353 /* assert that the IR is well-typed */
354 Int nshift;
355 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj38ff3d82004-07-26 23:27:08 +0000356 nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
sewardj3bd676c2004-07-27 10:50:38 +0000357 vassert(nshift >= 0);
sewardj38ff3d82004-07-26 23:27:08 +0000358 if (nshift > 0)
359 addInstr(env, X86Instr_Sh32(
360 shOp,
361 nshift,
362 X86RM_Reg(dst)));
363 } else {
364 /* General case; we have to force the amount into %cl. */
365 HReg regR = iselIntExpr_R(env, e->Iex.Binop.arg2);
366 addInstr(env, mk_MOVsd_RR(regR,hregX86_ECX()));
367 addInstr(env, X86Instr_Sh32(shOp, 0/* %cl */, X86RM_Reg(dst)));
368 }
sewardjd9c2b792004-07-08 01:44:38 +0000369 return dst;
370 }
sewardj8c7f1ab2004-07-29 20:31:09 +0000371
372 /* Handle misc other ops. */
373 if (e->Iex.Binop.op == Iop_16HLto32) {
374 HReg hi16 = newVRegI(env);
375 HReg lo16 = newVRegI(env);
376 HReg hi16s = iselIntExpr_R(env, e->Iex.Binop.arg1);
377 HReg lo16s = iselIntExpr_R(env, e->Iex.Binop.arg2);
378 addInstr(env, mk_MOVsd_RR(hi16s, hi16));
379 addInstr(env, mk_MOVsd_RR(lo16s, lo16));
380 addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(hi16)));
381 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFFFF), lo16));
382 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo16), hi16));
383 return hi16;
384 }
385
sewardje8e9d732004-07-16 21:03:45 +0000386 break;
sewardjd9c2b792004-07-08 01:44:38 +0000387 }
388
sewardj60f4e3c2004-07-19 01:56:50 +0000389 /* --------- UNARY OP --------- */
sewardj4042c7e2004-07-18 01:28:30 +0000390 case Iex_Unop: {
sewardj443cd9d2004-07-18 23:06:45 +0000391 /* 1Uto8(32to1(expr32)) */
392 DEFINE_PATTERN(p_32to1_then_1Uto8,
sewardj38ff3d82004-07-26 23:27:08 +0000393 unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
sewardj443cd9d2004-07-18 23:06:45 +0000394 if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
395 IRExpr* expr32 = mi.bindee[0];
sewardj38ff3d82004-07-26 23:27:08 +0000396 HReg dst = newVRegI(env);
sewardj443cd9d2004-07-18 23:06:45 +0000397 HReg src = iselIntExpr_R(env, expr32);
398 addInstr(env, mk_MOVsd_RR(src,dst) );
399 addInstr(env, X86Instr_Alu32R(Xalu_AND,
400 X86RMI_Imm(1), dst));
401 return dst;
402 }
403
sewardj4042c7e2004-07-18 01:28:30 +0000404 switch (e->Iex.Unop.op) {
sewardj443cd9d2004-07-18 23:06:45 +0000405 case Iop_8Uto32:
406 case Iop_16Uto32: {
sewardj4042c7e2004-07-18 01:28:30 +0000407 HReg dst = newVRegI(env);
408 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
sewardj443cd9d2004-07-18 23:06:45 +0000409 UInt mask = e->Iex.Unop.op==Iop_8Uto32 ? 0xFF : 0xFFFF;
410 addInstr(env, mk_MOVsd_RR(src,dst) );
sewardj4042c7e2004-07-18 01:28:30 +0000411 addInstr(env, X86Instr_Alu32R(Xalu_AND,
sewardj443cd9d2004-07-18 23:06:45 +0000412 X86RMI_Imm(mask), dst));
413 return dst;
414 }
sewardja2384712004-07-29 14:36:40 +0000415 case Iop_Not8:
416 case Iop_Not16:
sewardj443cd9d2004-07-18 23:06:45 +0000417 case Iop_Not32: {
418 HReg dst = newVRegI(env);
419 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
420 addInstr(env, mk_MOVsd_RR(src,dst) );
sewardj60f4e3c2004-07-19 01:56:50 +0000421 addInstr(env, X86Instr_Unary32(Xun_Not,X86RM_Reg(dst)));
sewardj4042c7e2004-07-18 01:28:30 +0000422 return dst;
423 }
sewardj597b71b2004-07-19 02:51:12 +0000424 case Iop_64HIto32: {
425 HReg rHi, rLo;
426 iselIntExpr64(&rHi,&rLo, env, e->Iex.Unop.arg);
427 return rHi; /* and abandon rLo .. poor wee thing :-) */
428 }
sewardj8c7f1ab2004-07-29 20:31:09 +0000429 case Iop_64to32: {
sewardj597b71b2004-07-19 02:51:12 +0000430 HReg rHi, rLo;
431 iselIntExpr64(&rHi,&rLo, env, e->Iex.Unop.arg);
432 return rLo; /* similar stupid comment to the above ... */
433 }
sewardj8c7f1ab2004-07-29 20:31:09 +0000434 case Iop_32HIto16: {
435 HReg dst = newVRegI(env);
436 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
437 addInstr(env, mk_MOVsd_RR(src,dst) );
438 addInstr(env, X86Instr_Sh32(Xsh_SHR, 16, X86RM_Reg(dst)));
439 return dst;
440 }
sewardja2384712004-07-29 14:36:40 +0000441 case Iop_32to8:
442 case Iop_32to16:
443 /* These are both no-ops. */
444 return iselIntExpr_R(env, e->Iex.Unop.arg);
445
sewardj4042c7e2004-07-18 01:28:30 +0000446 default:
447 break;
448 }
449 break;
450 }
451
sewardj60f4e3c2004-07-19 01:56:50 +0000452 /* --------- GET --------- */
sewardje8e9d732004-07-16 21:03:45 +0000453 case Iex_Get: {
454 if (ty == Ity_I32) {
455 HReg dst = newVRegI(env);
456 addInstr(env, X86Instr_Alu32R(
457 Xalu_MOV,
458 X86RMI_Mem(X86AMode_IR(e->Iex.Get.offset,
459 hregX86_EBP())),
460 dst));
461 return dst;
sewardjc97096c2004-06-30 09:28:04 +0000462 }
sewardj60f4e3c2004-07-19 01:56:50 +0000463 if (ty == Ity_I8 || ty == Ity_I16) {
sewardj4042c7e2004-07-18 01:28:30 +0000464 HReg dst = newVRegI(env);
465 addInstr(env, X86Instr_LoadEX(
sewardj60f4e3c2004-07-19 01:56:50 +0000466 ty==Ity_I8 ? 1 : 2,
467 False,
sewardj4042c7e2004-07-18 01:28:30 +0000468 X86AMode_IR(e->Iex.Get.offset,hregX86_EBP()),
469 dst));
470 return dst;
471 }
sewardje8e9d732004-07-16 21:03:45 +0000472 break;
sewardjc97096c2004-06-30 09:28:04 +0000473 }
sewardje8e9d732004-07-16 21:03:45 +0000474
sewardj60f4e3c2004-07-19 01:56:50 +0000475 /* --------- CCALL --------- */
sewardje8e9d732004-07-16 21:03:45 +0000476 case Iex_CCall: {
sewardj36ca5132004-07-24 13:12:23 +0000477 Addr64 helper;
478 Int i, nargs;
479 UInt target;
sewardje8e9d732004-07-16 21:03:45 +0000480 IRExpr* arg;
481 vassert(ty == Ity_I32);
482 /* be very restrictive for now. Only 32-bit ints allowed
483 for args and return type. */
sewardj4042c7e2004-07-18 01:28:30 +0000484 if (e->Iex.CCall.retty != Ity_I32)
485 break;
sewardje8e9d732004-07-16 21:03:45 +0000486 /* push args on the stack, right to left. */
sewardj4042c7e2004-07-18 01:28:30 +0000487 nargs = 0;
488 while (e->Iex.CCall.args[nargs]) nargs++;
489 for (i = nargs-1; i >= 0; i--) {
490 arg = e->Iex.CCall.args[i];
491 if (typeOfIRExpr(env->type_env,arg) != Ity_I32)
492 goto irreducible;
493 addInstr(env, X86Instr_Push(iselIntExpr_RMI(env, arg)));
494 }
sewardj36ca5132004-07-24 13:12:23 +0000495 /* Find the function to call. Since the host -- for which we
496 are generating code -- is a 32-bit machine (x86) -- the upper
497 32 bit of the helper address should be zero. */
498 helper = env->find_helper(e->Iex.CCall.name);
499 vassert((helper & 0xFFFFFFFF00000000LL) == 0);
500 target = helper & 0xFFFFFFFF;
sewardj4042c7e2004-07-18 01:28:30 +0000501 addInstr(env, X86Instr_Alu32R(
502 Xalu_MOV,
503 X86RMI_Imm(target),
504 hregX86_EAX()));
505 addInstr(env, X86Instr_Call(hregX86_EAX()));
506 if (nargs > 0)
507 addInstr(env, X86Instr_Alu32R(Xalu_ADD,
508 X86RMI_Imm(4*nargs),
509 hregX86_ESP()));
510 return hregX86_EAX();
sewardje8e9d732004-07-16 21:03:45 +0000511 }
512
sewardj60f4e3c2004-07-19 01:56:50 +0000513 /* --------- LITERAL --------- */
sewardje8e9d732004-07-16 21:03:45 +0000514 /* 32/16/8-bit literals */
515 case Iex_Const: {
sewardj4042c7e2004-07-18 01:28:30 +0000516 X86RMI* rmi = iselIntExpr_RMI ( env, e );
517 HReg r = newVRegI(env);
518 addInstr(env, X86Instr_Alu32R(Xalu_MOV, rmi, r));
sewardje8e9d732004-07-16 21:03:45 +0000519 return r;
520 }
sewardjc97096c2004-06-30 09:28:04 +0000521
sewardj60f4e3c2004-07-19 01:56:50 +0000522 /* --------- MULTIPLEX --------- */
sewardj4042c7e2004-07-18 01:28:30 +0000523 case Iex_Mux0X: {
524 if (ty == Ity_I32
525 && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
sewardj2e56f9f2004-07-24 01:24:38 +0000526 HReg r8;
sewardj38ff3d82004-07-26 23:27:08 +0000527 HReg rX = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
528 X86RM* r0 = iselIntExpr_RM(env, e->Iex.Mux0X.expr0);
529 HReg dst = newVRegI(env);
530 addInstr(env, mk_MOVsd_RR(rX,dst));
531 r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
532 addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8)));
533 addInstr(env, X86Instr_CMov32(Xcc_Z,r0,dst));
534 return dst;
sewardj4042c7e2004-07-18 01:28:30 +0000535 }
536 break;
537 }
538
sewardjc97096c2004-06-30 09:28:04 +0000539 default:
540 break;
541 } /* switch (e->tag) */
542
543 /* We get here if no pattern matched. */
sewardje8e9d732004-07-16 21:03:45 +0000544 irreducible:
sewardj35421a32004-07-05 13:12:34 +0000545 ppIRExpr(e);
sewardjd9c2b792004-07-08 01:44:38 +0000546 vpanic("iselIntExpr_R: cannot reduce tree");
sewardjc97096c2004-06-30 09:28:04 +0000547}
548
549
sewardj66f2f792004-06-30 16:37:16 +0000550/*---------------------------------------------------------*/
551/*--- ISEL: Integer expression auxiliaries ---*/
552/*---------------------------------------------------------*/
553
sewardj60f4e3c2004-07-19 01:56:50 +0000554/* --------------- AMODEs --------------- */
555
sewardj66f2f792004-06-30 16:37:16 +0000556/* Return an AMode which computes the value of the specified
557 expression, possibly also adding insns to the code list as a
sewardj4042c7e2004-07-18 01:28:30 +0000558 result. The expression may only be a 32-bit one.
sewardjc97096c2004-06-30 09:28:04 +0000559*/
sewardj66f2f792004-06-30 16:37:16 +0000560static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e )
sewardjc97096c2004-06-30 09:28:04 +0000561{
sewardj4042c7e2004-07-18 01:28:30 +0000562 IRType ty = typeOfIRExpr(env->type_env,e);
563 vassert(ty == Ity_I32);
sewardjc97096c2004-06-30 09:28:04 +0000564
565 /* Add32(expr1, Shl32(expr2, imm)) */
566 if (e->tag == Iex_Binop
567 && e->Iex.Binop.op == Iop_Add32
568 && e->Iex.Binop.arg2->tag == Iex_Binop
569 && e->Iex.Binop.arg2->Iex.Binop.op == Iop_Shl32
570 && e->Iex.Binop.arg2->Iex.Binop.arg2->tag == Iex_Const
571 && e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
572 UInt shift = e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
573 if (shift == 2 || shift == 4 || shift == 8) {
sewardj66f2f792004-06-30 16:37:16 +0000574 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
575 HReg r2 = iselIntExpr_R(env, e->Iex.Binop.arg2->Iex.Binop.arg1 );
sewardjc97096c2004-06-30 09:28:04 +0000576 return X86AMode_IRRS(0, r1, r2, shift);
577 }
578 }
579
580 /* Add32(expr,i) */
581 if (e->tag == Iex_Binop
582 && e->Iex.Binop.op == Iop_Add32
583 && e->Iex.Binop.arg2->tag == Iex_Const
584 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
sewardj66f2f792004-06-30 16:37:16 +0000585 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
sewardjd9c2b792004-07-08 01:44:38 +0000586 return X86AMode_IR(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32, r1);
sewardjc97096c2004-06-30 09:28:04 +0000587 }
588
589 /* Doesn't match anything in particular. Generate it into
590 a register and use that. */
591 {
sewardj66f2f792004-06-30 16:37:16 +0000592 HReg r1 = iselIntExpr_R(env, e);
sewardjd9c2b792004-07-08 01:44:38 +0000593 return X86AMode_IR(0, r1);
sewardjc97096c2004-06-30 09:28:04 +0000594 }
595}
596
597
sewardj60f4e3c2004-07-19 01:56:50 +0000598/* --------------- RMIs --------------- */
599
sewardj4042c7e2004-07-18 01:28:30 +0000600/* Similarly, calculate an expression into an X86RMI operand. As with
601 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
sewardj66f2f792004-06-30 16:37:16 +0000602
603static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e )
604{
sewardj4042c7e2004-07-18 01:28:30 +0000605 IRType ty = typeOfIRExpr(env->type_env,e);
606 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
sewardj66f2f792004-06-30 16:37:16 +0000607
608 /* special case: immediate */
sewardj4042c7e2004-07-18 01:28:30 +0000609 if (e->tag == Iex_Const) {
610 UInt u;
611 switch (e->Iex.Const.con->tag) {
612 case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
613 case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
614 case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break;
615 default: vpanic("iselIntExpr_RMI.Iex_Const(x86h)");
616 }
617 return X86RMI_Imm(u);
sewardj66f2f792004-06-30 16:37:16 +0000618 }
619
sewardje8e9d732004-07-16 21:03:45 +0000620 /* special case: 32-bit GET */
sewardj4042c7e2004-07-18 01:28:30 +0000621 if (e->tag == Iex_Get && ty == Ity_I32) {
sewardje8e9d732004-07-16 21:03:45 +0000622 return X86RMI_Mem(X86AMode_IR(e->Iex.Get.offset,
623 hregX86_EBP()));
624 }
625
sewardj66f2f792004-06-30 16:37:16 +0000626 /* special case: load from memory */
627
628 /* default case: calculate into a register and return that */
629 {
630 HReg r = iselIntExpr_R ( env, e );
631 return X86RMI_Reg(r);
632 }
633}
634
635
sewardj60f4e3c2004-07-19 01:56:50 +0000636/* --------------- RIs --------------- */
637
sewardj4042c7e2004-07-18 01:28:30 +0000638/* Calculate an expression into an X86RI operand. As with
639 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
sewardj66f2f792004-06-30 16:37:16 +0000640
641static X86RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e )
642{
sewardj4042c7e2004-07-18 01:28:30 +0000643 IRType ty = typeOfIRExpr(env->type_env,e);
644 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
sewardj66f2f792004-06-30 16:37:16 +0000645
646 /* special case: immediate */
sewardj4042c7e2004-07-18 01:28:30 +0000647 if (e->tag == Iex_Const) {
648 UInt u;
649 switch (e->Iex.Const.con->tag) {
650 case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
651 case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
652 case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break;
653 default: vpanic("iselIntExpr_RMI.Iex_Const(x86h)");
654 }
655 return X86RI_Imm(u);
sewardj66f2f792004-06-30 16:37:16 +0000656 }
657
658 /* default case: calculate into a register and return that */
659 {
660 HReg r = iselIntExpr_R ( env, e );
661 return X86RI_Reg(r);
662 }
663}
664
665
sewardj60f4e3c2004-07-19 01:56:50 +0000666/* --------------- RMs --------------- */
667
sewardj4042c7e2004-07-18 01:28:30 +0000668/* Similarly, calculate an expression into an X86RM operand. As with
669 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
670
671static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e )
672{
sewardj4042c7e2004-07-18 01:28:30 +0000673 IRType ty = typeOfIRExpr(env->type_env,e);
674 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
675
676 /* special case: 32-bit GET */
677 if (e->tag == Iex_Get && ty == Ity_I32) {
678 return X86RM_Mem(X86AMode_IR(e->Iex.Get.offset,
679 hregX86_EBP()));
680 }
681
682 /* special case: load from memory */
683
684 /* default case: calculate into a register and return that */
685 {
686 HReg r = iselIntExpr_R ( env, e );
687 return X86RM_Reg(r);
688 }
689}
690
691
sewardj60f4e3c2004-07-19 01:56:50 +0000692/* --------------- CONDCODE --------------- */
693
sewardj443cd9d2004-07-18 23:06:45 +0000694/* Generate code to evaluated a bit-typed expression, returning the
695 condition code which would correspond when the expression would
696 notionally have returned 1. */
697
698static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e )
699{
700 MatchInfo mi;
701 DECLARE_PATTERN(p_32to1);
702 DECLARE_PATTERN(p_eq32_zero);
703
704 vassert(e);
705 vassert(typeOfIRExpr(env->type_env,e) == Ity_Bit);
706
707 /* pattern: 32to1(expr32) */
708 DEFINE_PATTERN(p_32to1,
709 unop(Iop_32to1,bind(0))
710 );
711 if (matchIRExpr(&mi,p_32to1,e)) {
712 HReg src = iselIntExpr_R(env, mi.bindee[0]);
713 HReg dst = newVRegI(env);
714 addInstr(env, mk_MOVsd_RR(src,dst));
715 addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(1),dst));
716 return Xcc_NZ;
717 }
718
719 /* pattern: CmpEQ32(expr32,0) */
720 DEFINE_PATTERN(p_eq32_zero,
721 binop( Iop_CmpEQ32, bind(0), IRExpr_Const(IRConst_U32(0)) )
722 );
723 if (matchIRExpr(&mi,p_eq32_zero,e)) {
724 HReg src = iselIntExpr_R(env, mi.bindee[0]);
725 addInstr(env, X86Instr_Alu32R(Xalu_CMP,X86RMI_Imm(0),src));
sewardj6707ccc2004-07-28 01:49:14 +0000726 return Xcc_Z;
sewardj443cd9d2004-07-18 23:06:45 +0000727 }
728
729 ppIRExpr(e);
730 vpanic("iselCondCode");
731}
732
733
sewardj597b71b2004-07-19 02:51:12 +0000734/*---------------------------------------------------------*/
735/*--- ISEL: Integer expressions (64 bit) ---*/
736/*---------------------------------------------------------*/
737
738/* Compute a 64-bit value into a register pair, which is returned as
739 the first two parameters. As with iselIntExpr_R, these may be
740 either real or virtual regs; in any case they must not be changed
741 by subsequent code emitted by the caller. */
742
743static void iselIntExpr64 ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
744{
745 // MatchInfo mi;
746 vassert(e);
747 vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
748
749 /* read 64-bit IRTemp */
750 if (e->tag == Iex_Tmp) {
751 lookupIRTemp64( rHi, rLo, env, e->Iex.Tmp.tmp);
752 return;
753 }
754
755 /* 32 x 32 -> 64 multiply */
756 if (e->tag == Iex_Binop
757 && (e->Iex.Binop.op == Iop_MullU32
758 || e->Iex.Binop.op == Iop_MullS32)) {
759 /* get one operand into %eax, and the other into a R/M. Need to
760 make an educated guess about which is better in which. */
761 Bool syned = e->Iex.Binop.op == Iop_MullS32;
762 X86RM* rmLeft = iselIntExpr_RM(env, e->Iex.Binop.arg1);
763 HReg rRight = iselIntExpr_R(env, e->Iex.Binop.arg2);
764 addInstr(env, mk_MOVsd_RR(rRight, hregX86_EAX()));
765 addInstr(env, X86Instr_MulL(syned, Xss_32, rmLeft));
766 /* Result is now in EDX:EAX. Tell the caller. */
767 *rHi = hregX86_EDX();
768 *rLo = hregX86_EAX();
769 return;
770 }
771
sewardj5c34dc92004-07-19 12:48:11 +0000772 /* 64 x 32 -> (32(rem),32(div)) division */
773 if (e->tag == Iex_Binop
774 && (e->Iex.Binop.op == Iop_DivModU64to32
775 || e->Iex.Binop.op == Iop_DivModS64to32)) {
776 /* Get the 64-bit operand into edx:eax, and the other
777 into any old R/M. */
778 HReg sHi, sLo;
779 Bool syned = e->Iex.Binop.op == Iop_MullS32;
780 X86RM* rmRight = iselIntExpr_RM(env, e->Iex.Binop.arg2);
781 iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
782 addInstr(env, mk_MOVsd_RR(sHi, hregX86_EDX()));
783 addInstr(env, mk_MOVsd_RR(sLo, hregX86_EAX()));
784 addInstr(env, X86Instr_Div(syned, Xss_32, rmRight));
785 *rHi = hregX86_EDX();
786 *rLo = hregX86_EAX();
787 return;
788 }
789
790 /* 32HLto64(e1,e2) */
791 if (e->tag == Iex_Binop
792 && e->Iex.Binop.op == Iop_32HLto64) {
793 *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1);
794 *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2);
795 return;
796 }
797
798 /* 64-bit shifts */
799 if (e->tag == Iex_Binop
800 && e->Iex.Binop.op == Iop_Shl64) {
801 /* We use the same ingenious scheme as gcc. Put the value
802 to be shifted into %hi:%lo, and the shift amount into %cl.
803 Then (dsts on right, a la ATT syntax):
804
805 shldl %cl, %lo, %hi -- make %hi be right for the shift amt
806 -- %cl % 32
807 shll %cl, %lo -- make %lo be right for the shift amt
808 -- %cl % 32
809
810 Now, if (shift amount % 64) is in the range 32 .. 63, we have
811 to do a fixup, which puts the result low half into the result
812 high half, and zeroes the low half:
813
814 testl $32, %ecx
815
816 cmovnz %lo, %hi
817 movl $0, %tmp -- sigh; need yet another reg
818 cmovnz %tmp, %lo
819 */
820 HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
821 tLo = newVRegI(env);
822 tHi = newVRegI(env);
823 tTemp = newVRegI(env);
824 rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
825 iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
826 addInstr(env, mk_MOVsd_RR(rAmt, hregX86_ECX()));
827 addInstr(env, mk_MOVsd_RR(sHi, tHi));
828 addInstr(env, mk_MOVsd_RR(sLo, tLo));
829 /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo and
830 those regs are legitimately modifiable. */
831 addInstr(env, X86Instr_Sh3232(Xsh_SHL, 0/*%cl*/, tHi, tLo));
832 addInstr(env, X86Instr_Sh32(Xsh_SHL, 0/*%cl*/, X86RM_Reg(tLo)));
sewardje8c922f2004-07-23 01:34:11 +0000833 addInstr(env, X86Instr_Test32(X86RI_Imm(32), X86RM_Reg(hregX86_ECX())));
sewardj5c34dc92004-07-19 12:48:11 +0000834 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tLo), tHi));
835 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
836 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tLo));
837 *rHi = tHi;
838 *rLo = tLo;
839 return;
840 }
841
sewardj68511542004-07-28 00:15:44 +0000842 if (e->tag == Iex_Binop
843 && e->Iex.Binop.op == Iop_Shr64) {
844 /* We use the same ingenious scheme as gcc. Put the value
845 to be shifted into %hi:%lo, and the shift amount into %cl.
846 Then:
847
848 shrdl %cl, %hi, %lo -- make %lo be right for the shift amt
849 -- %cl % 32
sewardj80f8c302004-07-29 22:21:31 +0000850 shrl %cl, %hi -- make %hi be right for the shift amt
sewardj68511542004-07-28 00:15:44 +0000851 -- %cl % 32
852
853 Now, if (shift amount % 64) is in the range 32 .. 63, we have
854 to do a fixup, which puts the result high half into the result
855 low half, and zeroes the high half:
856
857 testl $32, %ecx
858
859 cmovnz %hi, %lo
860 movl $0, %tmp -- sigh; need yet another reg
861 cmovnz %tmp, %hi
862 */
863 HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
864 tLo = newVRegI(env);
865 tHi = newVRegI(env);
866 tTemp = newVRegI(env);
867 rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
868 iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
869 addInstr(env, mk_MOVsd_RR(rAmt, hregX86_ECX()));
870 addInstr(env, mk_MOVsd_RR(sHi, tHi));
871 addInstr(env, mk_MOVsd_RR(sLo, tLo));
872 /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo and
873 those regs are legitimately modifiable. */
874 addInstr(env, X86Instr_Sh3232(Xsh_SHR, 0/*%cl*/, tLo, tHi));
875 addInstr(env, X86Instr_Sh32(Xsh_SHR, 0/*%cl*/, X86RM_Reg(tHi)));
876 addInstr(env, X86Instr_Test32(X86RI_Imm(32), X86RM_Reg(hregX86_ECX())));
877 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tHi), tLo));
878 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
879 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tHi));
880 *rHi = tHi;
881 *rLo = tLo;
882 return;
883 }
884
sewardj597b71b2004-07-19 02:51:12 +0000885 ppIRExpr(e);
886 vpanic("iselIntExpr64");
887}
888
889
sewardj4042c7e2004-07-18 01:28:30 +0000890
sewardjc97096c2004-06-30 09:28:04 +0000891/*---------------------------------------------------------*/
892/*--- ISEL: Statements ---*/
893/*---------------------------------------------------------*/
894
sewardjf13a16a2004-07-05 17:10:14 +0000895static void iselStmt ( ISelEnv* env, IRStmt* stmt )
sewardjc97096c2004-06-30 09:28:04 +0000896{
sewardj1f40a0a2004-07-21 12:28:07 +0000897 if (vex_verbosity > 0) {
898 vex_printf("-- ");
899 ppIRStmt(stmt);
900 vex_printf("\n");
901 }
sewardj66f2f792004-06-30 16:37:16 +0000902
sewardjc97096c2004-06-30 09:28:04 +0000903 switch (stmt->tag) {
904
sewardj60f4e3c2004-07-19 01:56:50 +0000905 /* --------- STORE --------- */
sewardjd9c2b792004-07-08 01:44:38 +0000906 case Ist_STle: {
907 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.STle.addr);
908 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.STle.data);
909 vassert(tya == Ity_I32);
910 if (tyd == Ity_I32) {
911 X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.STle.addr);
sewardj443cd9d2004-07-18 23:06:45 +0000912 X86RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data);
sewardjd9c2b792004-07-08 01:44:38 +0000913 addInstr(env, X86Instr_Alu32M(Xalu_MOV,ri,am));
914 return;
915 }
sewardj60f4e3c2004-07-19 01:56:50 +0000916 if (tyd == Ity_I8 || tyd == Ity_I16) {
sewardj443cd9d2004-07-18 23:06:45 +0000917 X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.STle.addr);
918 HReg r = iselIntExpr_R(env, stmt->Ist.STle.data);
sewardj60f4e3c2004-07-19 01:56:50 +0000919 addInstr(env, X86Instr_Store(tyd==Ity_I8 ? 1 : 2,
920 r,am));
sewardj443cd9d2004-07-18 23:06:45 +0000921 return;
922 }
923
sewardjd9c2b792004-07-08 01:44:38 +0000924 break;
sewardj79453082004-07-02 17:29:14 +0000925 }
926
sewardj60f4e3c2004-07-19 01:56:50 +0000927 /* --------- PUT --------- */
sewardjd9c2b792004-07-08 01:44:38 +0000928 case Ist_Put: {
929 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.expr);
930 if (ty == Ity_I32) {
931 /* We're going to write to memory, so compute the RHS into an
932 X86RI. */
933 X86RI* ri = iselIntExpr_RI(env, stmt->Ist.Put.expr);
934 addInstr(env,
935 X86Instr_Alu32M(
936 Xalu_MOV,
937 ri,
938 X86AMode_IR(stmt->Ist.Put.offset,hregX86_EBP())
939 ));
940 return;
941 }
sewardj597b71b2004-07-19 02:51:12 +0000942 if (ty == Ity_I8 || ty == Ity_I16) {
sewardj443cd9d2004-07-18 23:06:45 +0000943 /* We're going to write to memory, so compute the RHS into an
944 X86RI. */
945 HReg r = iselIntExpr_R(env, stmt->Ist.Put.expr);
946 addInstr(env, X86Instr_Store(
sewardj597b71b2004-07-19 02:51:12 +0000947 ty==Ity_I8 ? 1 : 2,
948 r,
sewardj443cd9d2004-07-18 23:06:45 +0000949 X86AMode_IR(stmt->Ist.Put.offset,
950 hregX86_EBP())));
951 return;
952 }
sewardjd9c2b792004-07-08 01:44:38 +0000953 break;
954 }
sewardje8e9d732004-07-16 21:03:45 +0000955
sewardj60f4e3c2004-07-19 01:56:50 +0000956 /* --------- TMP --------- */
sewardjd9c2b792004-07-08 01:44:38 +0000957 case Ist_Tmp: {
958 IRTemp tmp = stmt->Ist.Tmp.tmp;
959 IRType ty = lookupIRTypeEnv(env->type_env, tmp);
sewardj4042c7e2004-07-18 01:28:30 +0000960 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
sewardjd9c2b792004-07-08 01:44:38 +0000961 X86RMI* rmi = iselIntExpr_RMI(env, stmt->Ist.Tmp.expr);
962 HReg dst = lookupIRTemp(env, tmp);
963 addInstr(env, X86Instr_Alu32R(Xalu_MOV,rmi,dst));
964 return;
965 }
sewardj597b71b2004-07-19 02:51:12 +0000966 if (ty == Ity_I64) {
967 HReg rHi, rLo, dstHi, dstLo;
sewardj38ff3d82004-07-26 23:27:08 +0000968 iselIntExpr64(&rHi,&rLo, env, stmt->Ist.Tmp.expr);
sewardj597b71b2004-07-19 02:51:12 +0000969 lookupIRTemp64( &dstHi, &dstLo, env, tmp);
970 addInstr(env, mk_MOVsd_RR(rHi,dstHi) );
971 addInstr(env, mk_MOVsd_RR(rLo,dstLo) );
972 return;
973 }
sewardjd9c2b792004-07-08 01:44:38 +0000974 break;
975 }
sewardj79453082004-07-02 17:29:14 +0000976
sewardj60f4e3c2004-07-19 01:56:50 +0000977 /* --------- EXIT --------- */
sewardje8e9d732004-07-16 21:03:45 +0000978 case Ist_Exit: {
sewardj2e56f9f2004-07-24 01:24:38 +0000979 X86RI* dst;
980 X86CondCode cc;
981 if (stmt->Ist.Exit.dst->tag != Ico_U32)
982 vpanic("isel_x86: Ist_Exit: dst is not a 32-bit value");
983 dst = iselIntExpr_RI(env, IRExpr_Const(stmt->Ist.Exit.dst));
984 cc = iselCondCode(env,stmt->Ist.Exit.cond);
sewardj750f4072004-07-26 22:39:11 +0000985 addInstr(env, X86Instr_Goto(Ijk_Boring, cc, dst));
sewardj2e56f9f2004-07-24 01:24:38 +0000986 return;
sewardje8e9d732004-07-16 21:03:45 +0000987 }
988
sewardjc97096c2004-06-30 09:28:04 +0000989 default: break;
990 }
sewardj35421a32004-07-05 13:12:34 +0000991 ppIRStmt(stmt);
992 vpanic("iselStmt");
sewardjc97096c2004-06-30 09:28:04 +0000993}
994
995
996/*---------------------------------------------------------*/
997/*--- ISEL: Basic block terminators (Nexts) ---*/
998/*---------------------------------------------------------*/
999
sewardje539a402004-07-14 18:24:17 +00001000static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
sewardjc97096c2004-06-30 09:28:04 +00001001{
sewardje8e9d732004-07-16 21:03:45 +00001002 X86RI* ri;
sewardj1f40a0a2004-07-21 12:28:07 +00001003 if (vex_verbosity > 0) {
sewardj750f4072004-07-26 22:39:11 +00001004 vex_printf("-- goto {");
1005 ppIRJumpKind(jk);
1006 vex_printf("} ");
sewardj1f40a0a2004-07-21 12:28:07 +00001007 ppIRExpr(next);
1008 vex_printf("\n");
1009 }
sewardje8e9d732004-07-16 21:03:45 +00001010 ri = iselIntExpr_RI(env, next);
sewardj750f4072004-07-26 22:39:11 +00001011 addInstr(env, X86Instr_Goto(jk, Xcc_ALWAYS,ri));
sewardjc97096c2004-06-30 09:28:04 +00001012}
1013
1014
1015/*---------------------------------------------------------*/
1016/*--- Insn selector top-level ---*/
1017/*---------------------------------------------------------*/
1018
sewardj194d54a2004-07-03 19:08:18 +00001019/* Translate an entire BB to x86 code. */
1020
sewardj36ca5132004-07-24 13:12:23 +00001021HInstrArray* iselBB_X86 ( IRBB* bb, Addr64(*find_helper)(Char*) )
sewardjc97096c2004-06-30 09:28:04 +00001022{
sewardj597b71b2004-07-19 02:51:12 +00001023 Int i, j;
sewardje8e9d732004-07-16 21:03:45 +00001024 HReg hreg, hregHI;
sewardjc97096c2004-06-30 09:28:04 +00001025 IRStmt* stmt;
1026
1027 /* Make up an initial environment to use. */
sewardj35421a32004-07-05 13:12:34 +00001028 ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv));
sewardj194d54a2004-07-03 19:08:18 +00001029 env->vreg_ctr = 0;
sewardjc97096c2004-06-30 09:28:04 +00001030
sewardj36ca5132004-07-24 13:12:23 +00001031 /* Register helper-function-finder. */
1032 env->find_helper = find_helper;
1033
sewardjc97096c2004-06-30 09:28:04 +00001034 /* Set up output code array. */
sewardj2cd80dc2004-07-02 15:20:40 +00001035 env->code = newHInstrArray();
sewardjc97096c2004-06-30 09:28:04 +00001036
1037 /* Copy BB's type env. */
1038 env->type_env = bb->tyenv;
1039
1040 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
1041 change as we go along. */
sewardje539a402004-07-14 18:24:17 +00001042 env->n_vregmap = bb->tyenv->types_used;
1043 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
sewardje8e9d732004-07-16 21:03:45 +00001044 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
sewardjc97096c2004-06-30 09:28:04 +00001045
1046 /* For each IR temporary, allocate a suitably-kinded virtual
1047 register. */
sewardj597b71b2004-07-19 02:51:12 +00001048 j = 0;
sewardjc97096c2004-06-30 09:28:04 +00001049 for (i = 0; i < env->n_vregmap; i++) {
sewardje8e9d732004-07-16 21:03:45 +00001050 hregHI = hreg = INVALID_HREG;
sewardje539a402004-07-14 18:24:17 +00001051 switch (bb->tyenv->types[i]) {
sewardje8e9d732004-07-16 21:03:45 +00001052 case Ity_Bit:
1053 case Ity_I8:
sewardj4042c7e2004-07-18 01:28:30 +00001054 case Ity_I16:
sewardj597b71b2004-07-19 02:51:12 +00001055 case Ity_I32: hreg = mkHReg(j++, HRcInt, True); break;
1056 case Ity_I64: hreg = mkHReg(j++, HRcInt, True);
1057 hregHI = mkHReg(j++, HRcInt, True); break;
sewardje8e9d732004-07-16 21:03:45 +00001058 default: ppIRType(bb->tyenv->types[i]);
1059 vpanic("iselBB: IRTemp type");
sewardjc97096c2004-06-30 09:28:04 +00001060 }
sewardje8e9d732004-07-16 21:03:45 +00001061 env->vregmap[i] = hreg;
1062 env->vregmapHI[i] = hregHI;
sewardjc97096c2004-06-30 09:28:04 +00001063 }
sewardje322b0a2004-07-28 07:12:30 +00001064 env->vreg_ctr = j;
sewardjc97096c2004-06-30 09:28:04 +00001065
1066 /* Ok, finally we can iterate over the statements. */
1067 for (stmt = bb->stmts; stmt; stmt=stmt->link)
1068 iselStmt(env,stmt);
1069
sewardje539a402004-07-14 18:24:17 +00001070 iselNext(env,bb->next,bb->jumpkind);
sewardj2cd80dc2004-07-02 15:20:40 +00001071
sewardj194d54a2004-07-03 19:08:18 +00001072 /* record the number of vregs we used. */
1073 env->code->n_vregs = env->vreg_ctr;
sewardj2cd80dc2004-07-02 15:20:40 +00001074 return env->code;
sewardjc97096c2004-06-30 09:28:04 +00001075}
sewardj887a11a2004-07-05 17:26:47 +00001076
1077
1078/*---------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +00001079/*--- end host-x86/isel.c ---*/
sewardj887a11a2004-07-05 17:26:47 +00001080/*---------------------------------------------------------------*/