sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1 | |
| 2 | /*---------------------------------------------------------------*/ |
| 3 | /*--- ---*/ |
sewardj | c0ee2ed | 2004-07-27 10:29:41 +0000 | [diff] [blame] | 4 | /*--- This file (host-x86/isel.c) is ---*/ |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 5 | /*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/ |
| 6 | /*--- ---*/ |
| 7 | /*---------------------------------------------------------------*/ |
| 8 | |
sewardj | 887a11a | 2004-07-05 17:26:47 +0000 | [diff] [blame] | 9 | #include "libvex_basictypes.h" |
| 10 | #include "libvex_ir.h" |
| 11 | #include "libvex.h" |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 12 | |
sewardj | c0ee2ed | 2004-07-27 10:29:41 +0000 | [diff] [blame] | 13 | #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" |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 17 | |
| 18 | |
| 19 | /*---------------------------------------------------------*/ |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 20 | /*--- 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 |
| 40 | typedef |
| 41 | struct { |
| 42 | IRExpr* bindee[N_MATCH_BINDERS]; |
| 43 | } |
| 44 | MatchInfo; |
| 45 | |
| 46 | |
| 47 | static 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 | |
| 56 | static 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 | |
| 104 | static 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 */ |
| 114 | static IRExpr* unop ( IROp op, IRExpr* a ) |
| 115 | { |
| 116 | return IRExpr_Unop(op, a); |
| 117 | } |
| 118 | |
| 119 | static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 ) |
| 120 | { |
| 121 | return IRExpr_Binop(op, a1, a2); |
| 122 | } |
| 123 | |
| 124 | static IRExpr* bind ( Int binder ) |
| 125 | { |
| 126 | return IRExpr_Binder(binder); |
| 127 | } |
| 128 | |
| 129 | |
| 130 | |
| 131 | |
| 132 | /*---------------------------------------------------------*/ |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 133 | /*--- ISelEnv ---*/ |
| 134 | /*---------------------------------------------------------*/ |
| 135 | |
| 136 | /* This carries around: |
| 137 | |
sewardj | 36ca513 | 2004-07-24 13:12:23 +0000 | [diff] [blame] | 138 | - A function for looking up the address of helper functions. |
| 139 | |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 140 | - 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 |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 145 | 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. |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 155 | |
| 156 | - The code array, that is, the insns selected so far. |
| 157 | |
| 158 | - A counter, for generating new virtual registers. |
| 159 | |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 160 | Note, this is all host-independent. */ |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 161 | |
| 162 | typedef |
| 163 | struct { |
sewardj | 36ca513 | 2004-07-24 13:12:23 +0000 | [diff] [blame] | 164 | Addr64 (*find_helper)(Char*); |
| 165 | |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 166 | IRTypeEnv* type_env; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 167 | |
sewardj | e539a40 | 2004-07-14 18:24:17 +0000 | [diff] [blame] | 168 | HReg* vregmap; |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 169 | HReg* vregmapHI; |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 170 | Int n_vregmap; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 171 | |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 172 | HInstrArray* code; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 173 | |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 174 | Int vreg_ctr; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 175 | } |
| 176 | ISelEnv; |
| 177 | |
| 178 | |
| 179 | static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp ) |
| 180 | { |
sewardj | e539a40 | 2004-07-14 18:24:17 +0000 | [diff] [blame] | 181 | vassert(tmp >= 0); |
| 182 | vassert(tmp < env->n_vregmap); |
| 183 | return env->vregmap[tmp]; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 184 | } |
| 185 | |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 186 | static void lookupIRTemp64 ( HReg* vrHI, HReg* vrLO, ISelEnv* env, IRTemp tmp ) |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 187 | { |
| 188 | vassert(tmp >= 0); |
| 189 | vassert(tmp < env->n_vregmap); |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 190 | vassert(env->vregmapHI[tmp] != INVALID_HREG); |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 191 | *vrLO = env->vregmap[tmp]; |
| 192 | *vrHI = env->vregmapHI[tmp]; |
| 193 | } |
| 194 | |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 195 | static void addInstr ( ISelEnv* env, X86Instr* instr ) |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 196 | { |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 197 | addHInstr(env->code, instr); |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 198 | if (vex_verbosity > 0) { |
| 199 | ppX86Instr(instr); |
| 200 | vex_printf("\n"); |
| 201 | } |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | static HReg newVRegI ( ISelEnv* env ) |
| 205 | { |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 206 | HReg reg = mkHReg(env->vreg_ctr, HRcInt, True/*virtual reg*/); |
| 207 | env->vreg_ctr++; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 208 | return reg; |
| 209 | } |
| 210 | |
| 211 | |
| 212 | /*---------------------------------------------------------*/ |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 213 | /*--- ISEL: Integer expressions (32/16/8 bit) ---*/ |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 214 | /*---------------------------------------------------------*/ |
| 215 | |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 216 | /* forwards ... */ |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 217 | static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e ); |
| 218 | static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e ); |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 219 | static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e ); |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 220 | static void iselIntExpr64 ( HReg* rHi, HReg* rLo, |
| 221 | ISelEnv* env, IRExpr* e ); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 222 | |
| 223 | |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 224 | static X86Instr* mk_MOVsd_RR ( HReg src, HReg dst ) |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 225 | { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 226 | vassert(hregClass(src) == HRcInt); |
| 227 | vassert(hregClass(dst) == HRcInt); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 228 | return X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst); |
| 229 | } |
| 230 | |
| 231 | |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 232 | /* Select insns for an integer-typed expression, and add them to the |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 233 | 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. |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 239 | |
| 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 |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 243 | mask or sign extend partial values if necessary. |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 244 | */ |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 245 | static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ) |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 246 | { |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 247 | MatchInfo mi; |
| 248 | DECLARE_PATTERN(p_32to1_then_1Uto8); |
| 249 | |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 250 | IRType ty = typeOfIRExpr(env->type_env,e); |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 251 | vassert(ty == Ity_I32 || Ity_I16 || Ity_I8); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 252 | |
| 253 | switch (e->tag) { |
| 254 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 255 | /* --------- TEMP --------- */ |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 256 | case Iex_Tmp: { |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 257 | return lookupIRTemp(env, e->Iex.Tmp.tmp); |
| 258 | } |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 259 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 260 | /* --------- LOAD --------- */ |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 261 | case Iex_LDle: { |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 262 | HReg dst = newVRegI(env); |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 263 | 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 | } |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 273 | if (ty == Ity_I8) { |
| 274 | addInstr(env, X86Instr_LoadEX(1,False,amode,dst)); |
| 275 | return dst; |
| 276 | } |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 277 | break; |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 278 | } |
| 279 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 280 | /* --------- BINARY OP --------- */ |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 281 | case Iex_Binop: { |
| 282 | X86AluOp aluOp; |
| 283 | X86ShiftOp shOp; |
sewardj | 8c7f1ab | 2004-07-29 20:31:09 +0000 | [diff] [blame] | 284 | |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 285 | /* Is it an addition or logical style op? */ |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 286 | switch (e->Iex.Binop.op) { |
sewardj | a238471 | 2004-07-29 14:36:40 +0000 | [diff] [blame] | 287 | case Iop_Add8: case Iop_Add16: case Iop_Add32: |
sewardj | 1813dbe | 2004-07-28 17:09:04 +0000 | [diff] [blame] | 288 | aluOp = Xalu_ADD; break; |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 289 | case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: |
| 290 | aluOp = Xalu_SUB; break; |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 291 | case Iop_And8: case Iop_And16: case Iop_And32: |
| 292 | aluOp = Xalu_AND; break; |
sewardj | 750f407 | 2004-07-26 22:39:11 +0000 | [diff] [blame] | 293 | case Iop_Or8: case Iop_Or16: case Iop_Or32: |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 294 | aluOp = Xalu_OR; break; |
sewardj | a238471 | 2004-07-29 14:36:40 +0000 | [diff] [blame] | 295 | case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 296 | aluOp = Xalu_XOR; break; |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 297 | case Iop_Mul32: aluOp = Xalu_MUL; break; |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 298 | default: aluOp = Xalu_INVALID; break; |
| 299 | } |
| 300 | /* For commutative ops we assume any literal |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 301 | values are on the second operand. */ |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 302 | if (aluOp != Xalu_INVALID) { |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 303 | HReg dst = newVRegI(env); |
| 304 | HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg1); |
| 305 | X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2); |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 306 | addInstr(env, mk_MOVsd_RR(reg,dst)); |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 307 | addInstr(env, X86Instr_Alu32R(aluOp, rmi, dst)); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 308 | return dst; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 309 | } |
sewardj | 8c7f1ab | 2004-07-29 20:31:09 +0000 | [diff] [blame] | 310 | |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 311 | /* Perhaps a shift op? */ |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 312 | switch (e->Iex.Binop.op) { |
sewardj | 1813dbe | 2004-07-28 17:09:04 +0000 | [diff] [blame] | 313 | case Iop_Shl32: case Iop_Shl16: case Iop_Shl8: |
| 314 | shOp = Xsh_SHL; break; |
| 315 | case Iop_Shr32: case Iop_Shr16: case Iop_Shr8: |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 316 | shOp = Xsh_SHR; break; |
sewardj | 8c7f1ab | 2004-07-29 20:31:09 +0000 | [diff] [blame] | 317 | case Iop_Sar32: case Iop_Sar16: case Iop_Sar8: |
sewardj | 1813dbe | 2004-07-28 17:09:04 +0000 | [diff] [blame] | 318 | shOp = Xsh_SAR; break; |
| 319 | default: |
| 320 | shOp = Xsh_INVALID; break; |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 321 | } |
| 322 | if (shOp != Xsh_INVALID) { |
sewardj | 8c7f1ab | 2004-07-29 20:31:09 +0000 | [diff] [blame] | 323 | HReg dst = newVRegI(env); |
sewardj | 38ff3d8 | 2004-07-26 23:27:08 +0000 | [diff] [blame] | 324 | |
| 325 | /* regL = the value to be shifted */ |
sewardj | 96efe57 | 2004-07-03 14:48:24 +0000 | [diff] [blame] | 326 | HReg regL = iselIntExpr_R(env, e->Iex.Binop.arg1); |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 327 | addInstr(env, mk_MOVsd_RR(regL,dst)); |
sewardj | 38ff3d8 | 2004-07-26 23:27:08 +0000 | [diff] [blame] | 328 | |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 329 | /* 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; |
sewardj | 8c7f1ab | 2004-07-29 20:31:09 +0000 | [diff] [blame] | 339 | 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; |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 347 | default: break; |
| 348 | } |
sewardj | 38ff3d8 | 2004-07-26 23:27:08 +0000 | [diff] [blame] | 349 | |
| 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); |
sewardj | 38ff3d8 | 2004-07-26 23:27:08 +0000 | [diff] [blame] | 356 | nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8; |
sewardj | 3bd676c | 2004-07-27 10:50:38 +0000 | [diff] [blame] | 357 | vassert(nshift >= 0); |
sewardj | 38ff3d8 | 2004-07-26 23:27:08 +0000 | [diff] [blame] | 358 | 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 | } |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 369 | return dst; |
| 370 | } |
sewardj | 8c7f1ab | 2004-07-29 20:31:09 +0000 | [diff] [blame] | 371 | |
| 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 | |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 386 | break; |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 387 | } |
| 388 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 389 | /* --------- UNARY OP --------- */ |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 390 | case Iex_Unop: { |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 391 | /* 1Uto8(32to1(expr32)) */ |
| 392 | DEFINE_PATTERN(p_32to1_then_1Uto8, |
sewardj | 38ff3d8 | 2004-07-26 23:27:08 +0000 | [diff] [blame] | 393 | unop(Iop_1Uto8,unop(Iop_32to1,bind(0)))); |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 394 | if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) { |
| 395 | IRExpr* expr32 = mi.bindee[0]; |
sewardj | 38ff3d8 | 2004-07-26 23:27:08 +0000 | [diff] [blame] | 396 | HReg dst = newVRegI(env); |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 397 | 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 | |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 404 | switch (e->Iex.Unop.op) { |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 405 | case Iop_8Uto32: |
| 406 | case Iop_16Uto32: { |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 407 | HReg dst = newVRegI(env); |
| 408 | HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 409 | UInt mask = e->Iex.Unop.op==Iop_8Uto32 ? 0xFF : 0xFFFF; |
| 410 | addInstr(env, mk_MOVsd_RR(src,dst) ); |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 411 | addInstr(env, X86Instr_Alu32R(Xalu_AND, |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 412 | X86RMI_Imm(mask), dst)); |
| 413 | return dst; |
| 414 | } |
sewardj | a238471 | 2004-07-29 14:36:40 +0000 | [diff] [blame] | 415 | case Iop_Not8: |
| 416 | case Iop_Not16: |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 417 | 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) ); |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 421 | addInstr(env, X86Instr_Unary32(Xun_Not,X86RM_Reg(dst))); |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 422 | return dst; |
| 423 | } |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 424 | 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 | } |
sewardj | 8c7f1ab | 2004-07-29 20:31:09 +0000 | [diff] [blame] | 429 | case Iop_64to32: { |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 430 | HReg rHi, rLo; |
| 431 | iselIntExpr64(&rHi,&rLo, env, e->Iex.Unop.arg); |
| 432 | return rLo; /* similar stupid comment to the above ... */ |
| 433 | } |
sewardj | 8c7f1ab | 2004-07-29 20:31:09 +0000 | [diff] [blame] | 434 | 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 | } |
sewardj | a238471 | 2004-07-29 14:36:40 +0000 | [diff] [blame] | 441 | case Iop_32to8: |
| 442 | case Iop_32to16: |
| 443 | /* These are both no-ops. */ |
| 444 | return iselIntExpr_R(env, e->Iex.Unop.arg); |
| 445 | |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 446 | default: |
| 447 | break; |
| 448 | } |
| 449 | break; |
| 450 | } |
| 451 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 452 | /* --------- GET --------- */ |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 453 | 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; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 462 | } |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 463 | if (ty == Ity_I8 || ty == Ity_I16) { |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 464 | HReg dst = newVRegI(env); |
| 465 | addInstr(env, X86Instr_LoadEX( |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 466 | ty==Ity_I8 ? 1 : 2, |
| 467 | False, |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 468 | X86AMode_IR(e->Iex.Get.offset,hregX86_EBP()), |
| 469 | dst)); |
| 470 | return dst; |
| 471 | } |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 472 | break; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 473 | } |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 474 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 475 | /* --------- CCALL --------- */ |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 476 | case Iex_CCall: { |
sewardj | 36ca513 | 2004-07-24 13:12:23 +0000 | [diff] [blame] | 477 | Addr64 helper; |
| 478 | Int i, nargs; |
| 479 | UInt target; |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 480 | IRExpr* arg; |
| 481 | vassert(ty == Ity_I32); |
| 482 | /* be very restrictive for now. Only 32-bit ints allowed |
| 483 | for args and return type. */ |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 484 | if (e->Iex.CCall.retty != Ity_I32) |
| 485 | break; |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 486 | /* push args on the stack, right to left. */ |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 487 | 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 | } |
sewardj | 36ca513 | 2004-07-24 13:12:23 +0000 | [diff] [blame] | 495 | /* 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; |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 501 | 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(); |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 511 | } |
| 512 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 513 | /* --------- LITERAL --------- */ |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 514 | /* 32/16/8-bit literals */ |
| 515 | case Iex_Const: { |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 516 | X86RMI* rmi = iselIntExpr_RMI ( env, e ); |
| 517 | HReg r = newVRegI(env); |
| 518 | addInstr(env, X86Instr_Alu32R(Xalu_MOV, rmi, r)); |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 519 | return r; |
| 520 | } |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 521 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 522 | /* --------- MULTIPLEX --------- */ |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 523 | case Iex_Mux0X: { |
| 524 | if (ty == Ity_I32 |
| 525 | && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) { |
sewardj | 2e56f9f | 2004-07-24 01:24:38 +0000 | [diff] [blame] | 526 | HReg r8; |
sewardj | 38ff3d8 | 2004-07-26 23:27:08 +0000 | [diff] [blame] | 527 | 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; |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 535 | } |
| 536 | break; |
| 537 | } |
| 538 | |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 539 | default: |
| 540 | break; |
| 541 | } /* switch (e->tag) */ |
| 542 | |
| 543 | /* We get here if no pattern matched. */ |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 544 | irreducible: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 545 | ppIRExpr(e); |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 546 | vpanic("iselIntExpr_R: cannot reduce tree"); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 547 | } |
| 548 | |
| 549 | |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 550 | /*---------------------------------------------------------*/ |
| 551 | /*--- ISEL: Integer expression auxiliaries ---*/ |
| 552 | /*---------------------------------------------------------*/ |
| 553 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 554 | /* --------------- AMODEs --------------- */ |
| 555 | |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 556 | /* Return an AMode which computes the value of the specified |
| 557 | expression, possibly also adding insns to the code list as a |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 558 | result. The expression may only be a 32-bit one. |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 559 | */ |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 560 | static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e ) |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 561 | { |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 562 | IRType ty = typeOfIRExpr(env->type_env,e); |
| 563 | vassert(ty == Ity_I32); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 564 | |
| 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) { |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 574 | HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1); |
| 575 | HReg r2 = iselIntExpr_R(env, e->Iex.Binop.arg2->Iex.Binop.arg1 ); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 576 | 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) { |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 585 | HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1); |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 586 | return X86AMode_IR(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32, r1); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 587 | } |
| 588 | |
| 589 | /* Doesn't match anything in particular. Generate it into |
| 590 | a register and use that. */ |
| 591 | { |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 592 | HReg r1 = iselIntExpr_R(env, e); |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 593 | return X86AMode_IR(0, r1); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 594 | } |
| 595 | } |
| 596 | |
| 597 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 598 | /* --------------- RMIs --------------- */ |
| 599 | |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 600 | /* Similarly, calculate an expression into an X86RMI operand. As with |
| 601 | iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */ |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 602 | |
| 603 | static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e ) |
| 604 | { |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 605 | IRType ty = typeOfIRExpr(env->type_env,e); |
| 606 | vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 607 | |
| 608 | /* special case: immediate */ |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 609 | 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); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 618 | } |
| 619 | |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 620 | /* special case: 32-bit GET */ |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 621 | if (e->tag == Iex_Get && ty == Ity_I32) { |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 622 | return X86RMI_Mem(X86AMode_IR(e->Iex.Get.offset, |
| 623 | hregX86_EBP())); |
| 624 | } |
| 625 | |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 626 | /* 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 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 636 | /* --------------- RIs --------------- */ |
| 637 | |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 638 | /* Calculate an expression into an X86RI operand. As with |
| 639 | iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */ |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 640 | |
| 641 | static X86RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e ) |
| 642 | { |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 643 | IRType ty = typeOfIRExpr(env->type_env,e); |
| 644 | vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 645 | |
| 646 | /* special case: immediate */ |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 647 | 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); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 656 | } |
| 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 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 666 | /* --------------- RMs --------------- */ |
| 667 | |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 668 | /* Similarly, calculate an expression into an X86RM operand. As with |
| 669 | iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */ |
| 670 | |
| 671 | static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e ) |
| 672 | { |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 673 | 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 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 692 | /* --------------- CONDCODE --------------- */ |
| 693 | |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 694 | /* 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 | |
| 698 | static 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)); |
sewardj | 6707ccc | 2004-07-28 01:49:14 +0000 | [diff] [blame] | 726 | return Xcc_Z; |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 727 | } |
| 728 | |
| 729 | ppIRExpr(e); |
| 730 | vpanic("iselCondCode"); |
| 731 | } |
| 732 | |
| 733 | |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 734 | /*---------------------------------------------------------*/ |
| 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 | |
| 743 | static 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 | |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 772 | /* 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))); |
sewardj | e8c922f | 2004-07-23 01:34:11 +0000 | [diff] [blame] | 833 | addInstr(env, X86Instr_Test32(X86RI_Imm(32), X86RM_Reg(hregX86_ECX()))); |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 834 | 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 | |
sewardj | 6851154 | 2004-07-28 00:15:44 +0000 | [diff] [blame] | 842 | 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 |
sewardj | 80f8c30 | 2004-07-29 22:21:31 +0000 | [diff] [blame^] | 850 | shrl %cl, %hi -- make %hi be right for the shift amt |
sewardj | 6851154 | 2004-07-28 00:15:44 +0000 | [diff] [blame] | 851 | -- %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 | |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 885 | ppIRExpr(e); |
| 886 | vpanic("iselIntExpr64"); |
| 887 | } |
| 888 | |
| 889 | |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 890 | |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 891 | /*---------------------------------------------------------*/ |
| 892 | /*--- ISEL: Statements ---*/ |
| 893 | /*---------------------------------------------------------*/ |
| 894 | |
sewardj | f13a16a | 2004-07-05 17:10:14 +0000 | [diff] [blame] | 895 | static void iselStmt ( ISelEnv* env, IRStmt* stmt ) |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 896 | { |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 897 | if (vex_verbosity > 0) { |
| 898 | vex_printf("-- "); |
| 899 | ppIRStmt(stmt); |
| 900 | vex_printf("\n"); |
| 901 | } |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 902 | |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 903 | switch (stmt->tag) { |
| 904 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 905 | /* --------- STORE --------- */ |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 906 | 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); |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 912 | X86RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data); |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 913 | addInstr(env, X86Instr_Alu32M(Xalu_MOV,ri,am)); |
| 914 | return; |
| 915 | } |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 916 | if (tyd == Ity_I8 || tyd == Ity_I16) { |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 917 | X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.STle.addr); |
| 918 | HReg r = iselIntExpr_R(env, stmt->Ist.STle.data); |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 919 | addInstr(env, X86Instr_Store(tyd==Ity_I8 ? 1 : 2, |
| 920 | r,am)); |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 921 | return; |
| 922 | } |
| 923 | |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 924 | break; |
sewardj | 7945308 | 2004-07-02 17:29:14 +0000 | [diff] [blame] | 925 | } |
| 926 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 927 | /* --------- PUT --------- */ |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 928 | 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 | } |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 942 | if (ty == Ity_I8 || ty == Ity_I16) { |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 943 | /* 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( |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 947 | ty==Ity_I8 ? 1 : 2, |
| 948 | r, |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 949 | X86AMode_IR(stmt->Ist.Put.offset, |
| 950 | hregX86_EBP()))); |
| 951 | return; |
| 952 | } |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 953 | break; |
| 954 | } |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 955 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 956 | /* --------- TMP --------- */ |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 957 | case Ist_Tmp: { |
| 958 | IRTemp tmp = stmt->Ist.Tmp.tmp; |
| 959 | IRType ty = lookupIRTypeEnv(env->type_env, tmp); |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 960 | if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) { |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 961 | 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 | } |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 966 | if (ty == Ity_I64) { |
| 967 | HReg rHi, rLo, dstHi, dstLo; |
sewardj | 38ff3d8 | 2004-07-26 23:27:08 +0000 | [diff] [blame] | 968 | iselIntExpr64(&rHi,&rLo, env, stmt->Ist.Tmp.expr); |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 969 | lookupIRTemp64( &dstHi, &dstLo, env, tmp); |
| 970 | addInstr(env, mk_MOVsd_RR(rHi,dstHi) ); |
| 971 | addInstr(env, mk_MOVsd_RR(rLo,dstLo) ); |
| 972 | return; |
| 973 | } |
sewardj | d9c2b79 | 2004-07-08 01:44:38 +0000 | [diff] [blame] | 974 | break; |
| 975 | } |
sewardj | 7945308 | 2004-07-02 17:29:14 +0000 | [diff] [blame] | 976 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 977 | /* --------- EXIT --------- */ |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 978 | case Ist_Exit: { |
sewardj | 2e56f9f | 2004-07-24 01:24:38 +0000 | [diff] [blame] | 979 | 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); |
sewardj | 750f407 | 2004-07-26 22:39:11 +0000 | [diff] [blame] | 985 | addInstr(env, X86Instr_Goto(Ijk_Boring, cc, dst)); |
sewardj | 2e56f9f | 2004-07-24 01:24:38 +0000 | [diff] [blame] | 986 | return; |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 987 | } |
| 988 | |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 989 | default: break; |
| 990 | } |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 991 | ppIRStmt(stmt); |
| 992 | vpanic("iselStmt"); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 993 | } |
| 994 | |
| 995 | |
| 996 | /*---------------------------------------------------------*/ |
| 997 | /*--- ISEL: Basic block terminators (Nexts) ---*/ |
| 998 | /*---------------------------------------------------------*/ |
| 999 | |
sewardj | e539a40 | 2004-07-14 18:24:17 +0000 | [diff] [blame] | 1000 | static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk ) |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1001 | { |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 1002 | X86RI* ri; |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 1003 | if (vex_verbosity > 0) { |
sewardj | 750f407 | 2004-07-26 22:39:11 +0000 | [diff] [blame] | 1004 | vex_printf("-- goto {"); |
| 1005 | ppIRJumpKind(jk); |
| 1006 | vex_printf("} "); |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 1007 | ppIRExpr(next); |
| 1008 | vex_printf("\n"); |
| 1009 | } |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 1010 | ri = iselIntExpr_RI(env, next); |
sewardj | 750f407 | 2004-07-26 22:39:11 +0000 | [diff] [blame] | 1011 | addInstr(env, X86Instr_Goto(jk, Xcc_ALWAYS,ri)); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1012 | } |
| 1013 | |
| 1014 | |
| 1015 | /*---------------------------------------------------------*/ |
| 1016 | /*--- Insn selector top-level ---*/ |
| 1017 | /*---------------------------------------------------------*/ |
| 1018 | |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 1019 | /* Translate an entire BB to x86 code. */ |
| 1020 | |
sewardj | 36ca513 | 2004-07-24 13:12:23 +0000 | [diff] [blame] | 1021 | HInstrArray* iselBB_X86 ( IRBB* bb, Addr64(*find_helper)(Char*) ) |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1022 | { |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 1023 | Int i, j; |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 1024 | HReg hreg, hregHI; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1025 | IRStmt* stmt; |
| 1026 | |
| 1027 | /* Make up an initial environment to use. */ |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 1028 | ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv)); |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 1029 | env->vreg_ctr = 0; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1030 | |
sewardj | 36ca513 | 2004-07-24 13:12:23 +0000 | [diff] [blame] | 1031 | /* Register helper-function-finder. */ |
| 1032 | env->find_helper = find_helper; |
| 1033 | |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1034 | /* Set up output code array. */ |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 1035 | env->code = newHInstrArray(); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1036 | |
| 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. */ |
sewardj | e539a40 | 2004-07-14 18:24:17 +0000 | [diff] [blame] | 1042 | env->n_vregmap = bb->tyenv->types_used; |
| 1043 | env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg)); |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 1044 | env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg)); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1045 | |
| 1046 | /* For each IR temporary, allocate a suitably-kinded virtual |
| 1047 | register. */ |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 1048 | j = 0; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1049 | for (i = 0; i < env->n_vregmap; i++) { |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 1050 | hregHI = hreg = INVALID_HREG; |
sewardj | e539a40 | 2004-07-14 18:24:17 +0000 | [diff] [blame] | 1051 | switch (bb->tyenv->types[i]) { |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 1052 | case Ity_Bit: |
| 1053 | case Ity_I8: |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 1054 | case Ity_I16: |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 1055 | 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; |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 1058 | default: ppIRType(bb->tyenv->types[i]); |
| 1059 | vpanic("iselBB: IRTemp type"); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1060 | } |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 1061 | env->vregmap[i] = hreg; |
| 1062 | env->vregmapHI[i] = hregHI; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1063 | } |
sewardj | e322b0a | 2004-07-28 07:12:30 +0000 | [diff] [blame] | 1064 | env->vreg_ctr = j; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1065 | |
| 1066 | /* Ok, finally we can iterate over the statements. */ |
| 1067 | for (stmt = bb->stmts; stmt; stmt=stmt->link) |
| 1068 | iselStmt(env,stmt); |
| 1069 | |
sewardj | e539a40 | 2004-07-14 18:24:17 +0000 | [diff] [blame] | 1070 | iselNext(env,bb->next,bb->jumpkind); |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 1071 | |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 1072 | /* record the number of vregs we used. */ |
| 1073 | env->code->n_vregs = env->vreg_ctr; |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 1074 | return env->code; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1075 | } |
sewardj | 887a11a | 2004-07-05 17:26:47 +0000 | [diff] [blame] | 1076 | |
| 1077 | |
| 1078 | /*---------------------------------------------------------------*/ |
sewardj | c0ee2ed | 2004-07-27 10:29:41 +0000 | [diff] [blame] | 1079 | /*--- end host-x86/isel.c ---*/ |
sewardj | 887a11a | 2004-07-05 17:26:47 +0000 | [diff] [blame] | 1080 | /*---------------------------------------------------------------*/ |