blob: 8fb9a4c7be45e005a63fbe8baace5ee531a35bd2 [file] [log] [blame]
sewardja1a370f2004-08-17 13:31:55 +00001
2/*---------------------------------------------------------------*/
3/*--- ---*/
4/*--- This file (ir/iropt.c) is ---*/
5/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*---------------------------------------------------------------*/
8
9#include "libvex_basictypes.h"
sewardjedf4d692004-08-17 13:52:58 +000010#include "libvex_ir.h"
sewardja1a370f2004-08-17 13:31:55 +000011#include "libvex.h"
12
13#include "main/vex_util.h"
sewardjedf4d692004-08-17 13:52:58 +000014#include "ir/iropt.h"
sewardja1a370f2004-08-17 13:31:55 +000015
sewardj088bcb42004-08-19 17:16:52 +000016/* Set to 1 for lots of debugging output. */
17#define DEBUG_IROPT 0
18
sewardja1a370f2004-08-17 13:31:55 +000019
20/*---------------------------------------------------------------*/
21/*--- Finite mappery, of a sort ---*/
22/*---------------------------------------------------------------*/
23
24/* General map from 64-bit thing 64-bit thing. Could be done faster
25 by hashing. */
26
27typedef
28 struct {
29 Bool* inuse;
30 ULong* key;
31 ULong* val;
32 Int size;
33 Int used;
34 }
35 Hash64;
36
37static Hash64* newH64 ( void )
38{
39 Hash64* h = LibVEX_Alloc(sizeof(Hash64));
sewardj29632392004-08-22 02:38:11 +000040 h->size = 8;
sewardja1a370f2004-08-17 13:31:55 +000041 h->used = 0;
42 h->inuse = LibVEX_Alloc(h->size * sizeof(Bool));
43 h->key = LibVEX_Alloc(h->size * sizeof(ULong));
44 h->val = LibVEX_Alloc(h->size * sizeof(ULong));
45 return h;
46}
47
48
sewardj84be7372004-08-18 13:59:33 +000049/* Look up key in the map. */
sewardja1a370f2004-08-17 13:31:55 +000050
sewardj84be7372004-08-18 13:59:33 +000051static Bool lookupH64 ( Hash64* h, /*OUT*/ULong* val, ULong key )
sewardja1a370f2004-08-17 13:31:55 +000052{
53 Int i;
sewardj84be7372004-08-18 13:59:33 +000054 //vex_printf("lookupH64(%llx)\n", key );
sewardja1a370f2004-08-17 13:31:55 +000055 for (i = 0; i < h->used; i++) {
56 if (h->inuse[i] && h->key[i] == key) {
sewardj39e3f242004-08-18 16:54:52 +000057 if (val)
58 *val = h->val[i];
sewardja1a370f2004-08-17 13:31:55 +000059 return True;
60 }
61 }
62 return False;
63}
64
65
66/* Delete any binding for key in h. */
67
68static void delFromH64 ( Hash64* h, ULong key )
69{
70 Int i;
71 for (i = 0; i < h->used; i++) {
72 if (h->inuse[i] && h->key[i] == key) {
73 h->inuse[i] = False;
74 return;
75 }
76 }
77}
78
79
80
81/* Add key->val to the map. Replaces any existing binding for key. */
82
83static void addToH64 ( Hash64* h, ULong key, ULong val )
84{
85 Int i, j;
86
sewardj84be7372004-08-18 13:59:33 +000087 //vex_printf("addToH64(%llx, %llx)\n", key, val);
sewardja1a370f2004-08-17 13:31:55 +000088 /* Find and replace existing binding, if any. */
89 for (i = 0; i < h->used; i++) {
90 if (h->inuse[i] && h->key[i] == key) {
91 h->val[i] = val;
92 return;
93 }
94 }
95
96 /* Ensure a space is available. */
97 if (h->used == h->size) {
98 /* Copy into arrays twice the size. */
99 Bool* inuse2 = LibVEX_Alloc(2 * h->size * sizeof(Bool));
100 ULong* key2 = LibVEX_Alloc(2 * h->size * sizeof(ULong));
101 ULong* val2 = LibVEX_Alloc(2 * h->size * sizeof(ULong));
102 for (i = j = 0; i < h->size; i++) {
103 if (!h->inuse[i]) continue;
104 inuse2[j] = True;
105 key2[j] = h->key[i];
106 val2[j] = h->val[i];
107 j++;
108 }
109 h->used = j;
110 h->size *= 2;
111 h->inuse = inuse2;
112 h->key = key2;
113 h->val = val2;
114 }
115
116 /* Finally, add it. */
117 vassert(h->used < h->size);
118 h->inuse[h->used] = True;
119 h->key[h->used] = key;
sewardj84be7372004-08-18 13:59:33 +0000120 h->val[h->used] = val;
sewardja1a370f2004-08-17 13:31:55 +0000121 h->used++;
122}
123
sewardj84be7372004-08-18 13:59:33 +0000124
sewardjd7cb8532004-08-17 23:59:23 +0000125/*---------------------------------------------------------------*/
126/*--- Flattening out a BB into pure SSA form ---*/
127/*---------------------------------------------------------------*/
128
sewardjedeb4c42004-09-21 23:39:25 +0000129inline
sewardje80679a2004-09-21 23:00:11 +0000130static Bool isAtom ( IRExpr* e )
131{
132 return e->tag == Iex_Tmp || e->tag == Iex_Const;
133}
134
135
sewardjd7cb8532004-08-17 23:59:23 +0000136/* Clone the NULL-terminated vector of IRExpr*s attached to a
137 CCall. */
138
sewardj17442fe2004-09-20 14:54:28 +0000139static IRExpr** copyIRExprCallArgs ( IRExpr** vec )
sewardjd7cb8532004-08-17 23:59:23 +0000140{
141 Int i;
142 IRExpr** newvec;
143 for (i = 0; vec[i]; i++)
144 ;
145 newvec = LibVEX_Alloc((i+1)*sizeof(IRExpr*));
146 for (i = 0; vec[i]; i++)
147 newvec[i] = vec[i];
148 newvec[i] = NULL;
149 return newvec;
150}
151
152
sewardje80679a2004-09-21 23:00:11 +0000153/* Non-critical helper, heuristic for reducing the number of tmp-tmp
154 copies made by flattening. If in doubt return False. */
155
156static Bool isFlat ( IRExpr* e )
157{
158 if (e->tag == Iex_Get) return True;
159 if (e->tag == Iex_Binop)
160 return isAtom(e->Iex.Binop.arg1) && isAtom(e->Iex.Binop.arg2);
161 if (e->tag == Iex_LDle)
162 return isAtom(e->Iex.LDle.addr);
163 return False;
164}
165
sewardjd7cb8532004-08-17 23:59:23 +0000166/* Flatten out 'ex' so it is atomic, returning a new expression with
167 the same value, after having appended extra IRTemp assignments to
168 the end of 'bb'. */
169
170static IRExpr* flatten_Expr ( IRBB* bb, IRExpr* ex )
171{
172 Int i;
173 IRExpr** newargs;
174 IRType ty = typeOfIRExpr(bb->tyenv, ex);
175 IRTemp t1;
176
177 switch (ex->tag) {
178
sewardjd7217032004-08-19 10:49:10 +0000179 case Iex_GetI:
180 t1 = newIRTemp(bb->tyenv, ty);
181 addStmtToIRBB(bb, IRStmt_Tmp(t1,
sewardj2d3f77c2004-09-22 23:49:09 +0000182 IRExpr_GetI(ex->Iex.GetI.descr,
183 flatten_Expr(bb, ex->Iex.GetI.off),
184 ex->Iex.GetI.bias)));
sewardjd7217032004-08-19 10:49:10 +0000185 return IRExpr_Tmp(t1);
186
sewardjd7cb8532004-08-17 23:59:23 +0000187 case Iex_Get:
188 t1 = newIRTemp(bb->tyenv, ty);
189 addStmtToIRBB(bb,
190 IRStmt_Tmp(t1, ex));
191 return IRExpr_Tmp(t1);
192
193 case Iex_Binop:
194 t1 = newIRTemp(bb->tyenv, ty);
195 addStmtToIRBB(bb, IRStmt_Tmp(t1,
196 IRExpr_Binop(ex->Iex.Binop.op,
197 flatten_Expr(bb, ex->Iex.Binop.arg1),
198 flatten_Expr(bb, ex->Iex.Binop.arg2))));
199 return IRExpr_Tmp(t1);
200
201 case Iex_Unop:
202 t1 = newIRTemp(bb->tyenv, ty);
203 addStmtToIRBB(bb, IRStmt_Tmp(t1,
204 IRExpr_Unop(ex->Iex.Unop.op,
205 flatten_Expr(bb, ex->Iex.Unop.arg))));
206 return IRExpr_Tmp(t1);
207
208 case Iex_LDle:
209 t1 = newIRTemp(bb->tyenv, ty);
210 addStmtToIRBB(bb, IRStmt_Tmp(t1,
211 IRExpr_LDle(ex->Iex.LDle.ty,
212 flatten_Expr(bb, ex->Iex.LDle.addr))));
213 return IRExpr_Tmp(t1);
214
215 case Iex_CCall:
sewardj17442fe2004-09-20 14:54:28 +0000216 newargs = copyIRExprCallArgs(ex->Iex.CCall.args);
sewardjd7cb8532004-08-17 23:59:23 +0000217 for (i = 0; newargs[i]; i++)
218 newargs[i] = flatten_Expr(bb, newargs[i]);
219 t1 = newIRTemp(bb->tyenv, ty);
220 addStmtToIRBB(bb, IRStmt_Tmp(t1,
221 IRExpr_CCall(ex->Iex.CCall.name,
222 ex->Iex.CCall.retty,
223 newargs)));
224 return IRExpr_Tmp(t1);
225
226 case Iex_Mux0X:
227 t1 = newIRTemp(bb->tyenv, ty);
228 addStmtToIRBB(bb, IRStmt_Tmp(t1,
229 IRExpr_Mux0X(flatten_Expr(bb, ex->Iex.Mux0X.cond),
230 flatten_Expr(bb, ex->Iex.Mux0X.expr0),
231 flatten_Expr(bb, ex->Iex.Mux0X.exprX))));
232 return IRExpr_Tmp(t1);
233
234 case Iex_Const:
235 case Iex_Tmp:
236 return ex;
237
238 default:
239 vex_printf("\n");
240 ppIRExpr(ex);
241 vex_printf("\n");
242 vpanic("flatten_Expr");
243 }
244}
245
246
247/* Append a completely flattened form of 'st' to the end of 'bb'. */
248
249static void flatten_Stmt ( IRBB* bb, IRStmt* st )
250{
sewardj17442fe2004-09-20 14:54:28 +0000251 Int i;
252 IRExpr *e1, *e2;
253 IRDirty *d, *d2;
sewardjd7cb8532004-08-17 23:59:23 +0000254 switch (st->tag) {
255 case Ist_Put:
sewardj6d076362004-09-23 11:06:17 +0000256 e1 = flatten_Expr(bb, st->Ist.Put.data);
sewardjd7cb8532004-08-17 23:59:23 +0000257 addStmtToIRBB(bb, IRStmt_Put(st->Ist.Put.offset, e1));
258 break;
sewardjd7cb8532004-08-17 23:59:23 +0000259 case Ist_PutI:
sewardj2d3f77c2004-09-22 23:49:09 +0000260 e1 = flatten_Expr(bb, st->Ist.PutI.off);
261 e2 = flatten_Expr(bb, st->Ist.PutI.data);
262 addStmtToIRBB(bb, IRStmt_PutI(st->Ist.PutI.descr,
263 e1,
264 st->Ist.PutI.bias,
265 e2));
sewardjd7217032004-08-19 10:49:10 +0000266 break;
sewardjd7cb8532004-08-17 23:59:23 +0000267 case Ist_Tmp:
sewardj6d076362004-09-23 11:06:17 +0000268 if (isFlat(st->Ist.Tmp.data)) {
sewardje80679a2004-09-21 23:00:11 +0000269 /* optimisation, to reduce the number of tmp-tmp
270 copies generated */
271 addStmtToIRBB(bb, st);
272 } else {
273 /* general case, always correct */
sewardj6d076362004-09-23 11:06:17 +0000274 e1 = flatten_Expr(bb, st->Ist.Tmp.data);
sewardje80679a2004-09-21 23:00:11 +0000275 addStmtToIRBB(bb, IRStmt_Tmp(st->Ist.Tmp.tmp, e1));
276 }
sewardjd7cb8532004-08-17 23:59:23 +0000277 break;
278 case Ist_STle:
279 e1 = flatten_Expr(bb, st->Ist.STle.addr);
280 e2 = flatten_Expr(bb, st->Ist.STle.data);
281 addStmtToIRBB(bb, IRStmt_STle(e1,e2));
282 break;
sewardj17442fe2004-09-20 14:54:28 +0000283 case Ist_Dirty:
284 d = st->Ist.Dirty.details;
285 d2 = emptyIRDirty();
286 *d2 = *d;
287 d2->args = copyIRExprCallArgs(d2->args);
288 if (d2->mFx != Ifx_None) {
289 d2->mAddr = flatten_Expr(bb, d2->mAddr);
290 } else {
291 vassert(d2->mAddr == NULL);
292 }
293 for (i = 0; d2->args[i]; i++)
294 d2->args[i] = flatten_Expr(bb, d2->args[i]);
295 addStmtToIRBB(bb, IRStmt_Dirty(d2));
296 break;
sewardjd7cb8532004-08-17 23:59:23 +0000297 case Ist_Exit:
298 e1 = flatten_Expr(bb, st->Ist.Exit.cond);
299 addStmtToIRBB(bb, IRStmt_Exit(e1, st->Ist.Exit.dst));
300 break;
301 default:
302 vex_printf("\n");
303 ppIRStmt(st);
304 vex_printf("\n");
305 vpanic("flatten_Stmt");
306 }
307}
308
309static IRBB* flatten_BB ( IRBB* in )
310{
311 Int i;
312 IRBB* out;
313 out = emptyIRBB();
314 out->tyenv = copyIRTypeEnv( in->tyenv );
315 for (i = 0; i < in->stmts_used; i++)
sewardj4345f7a2004-09-22 19:49:27 +0000316 if (in->stmts[i])
317 flatten_Stmt( out, in->stmts[i] );
sewardjd7cb8532004-08-17 23:59:23 +0000318 out->next = flatten_Expr( out, in->next );
319 out->jumpkind = in->jumpkind;
320 return out;
321}
322
sewardjedf4d692004-08-17 13:52:58 +0000323
sewardj84be7372004-08-18 13:59:33 +0000324
325/*---------------------------------------------------------------*/
326/*--- Constant propagation and folding ---*/
327/*---------------------------------------------------------------*/
328
sewardjf6501992004-08-27 11:58:24 +0000329/* The env in this section is a map from IRTemp to IRExpr*. */
330
sewardjf6729012004-08-25 12:45:13 +0000331/* Are both expressions simply the same IRTemp ? */
332static Bool sameIRTemps ( IRExpr* e1, IRExpr* e2 )
333{
334 return e1->tag == Iex_Tmp
335 && e2->tag == Iex_Tmp
336 && e1->Iex.Tmp.tmp == e2->Iex.Tmp.tmp;
337}
338
sewardj84be7372004-08-18 13:59:33 +0000339static IRExpr* fold_Expr ( IRExpr* e )
340{
sewardj278c44c2004-08-20 00:28:13 +0000341 Int shift;
sewardj84be7372004-08-18 13:59:33 +0000342 IRExpr* e2 = e; /* e2 is the result of folding e, if possible */
343
344 /* UNARY ops */
345 if (e->tag == Iex_Unop
346 && e->Iex.Unop.arg->tag == Iex_Const) {
347 switch (e->Iex.Unop.op) {
sewardj883b00b2004-09-11 09:30:24 +0000348 case Iop_8Sto32: {
349 /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
350 s32 <<= 24;
351 s32 >>= 24;
352 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
353 break;
354 }
sewardj84be7372004-08-18 13:59:33 +0000355 case Iop_8Uto32:
356 e2 = IRExpr_Const(IRConst_U32(
357 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
358 break;
359 case Iop_16Uto32:
360 e2 = IRExpr_Const(IRConst_U32(
361 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
362 break;
sewardj4345f7a2004-09-22 19:49:27 +0000363 case Iop_32to8:
364 e2 = IRExpr_Const(IRConst_U8(
365 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32));
366 break;
sewardj883b00b2004-09-11 09:30:24 +0000367 case Iop_Not32:
368 e2 = IRExpr_Const(IRConst_U32(
369 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
370 break;
sewardj84be7372004-08-18 13:59:33 +0000371 default:
372 goto unhandled;
373 }
374 }
375
376 /* BINARY ops */
377 if (e->tag == Iex_Binop) {
378 if (e->Iex.Binop.arg1->tag == Iex_Const
379 && e->Iex.Binop.arg2->tag == Iex_Const) {
380 /* cases where both args are consts */
381 switch (e->Iex.Binop.op) {
sewardj883b00b2004-09-11 09:30:24 +0000382 case Iop_Xor8:
383 e2 = IRExpr_Const(IRConst_U8(0xFF &
384 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
385 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)));
386 break;
sewardj84be7372004-08-18 13:59:33 +0000387 case Iop_And8:
388 e2 = IRExpr_Const(IRConst_U8(0xFF &
389 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
390 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)));
391 break;
sewardj4345f7a2004-09-22 19:49:27 +0000392 case Iop_Add8:
393 e2 = IRExpr_Const(IRConst_U8(0xFF &
394 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
395 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)));
396 break;
sewardj84be7372004-08-18 13:59:33 +0000397 case Iop_Sub8:
398 e2 = IRExpr_Const(IRConst_U8(0xFF &
399 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
400 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)));
401 break;
sewardjd7217032004-08-19 10:49:10 +0000402 case Iop_Sub32:
403 e2 = IRExpr_Const(IRConst_U32(
404 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
405 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
406 break;
407 case Iop_Add32:
408 e2 = IRExpr_Const(IRConst_U32(
409 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
410 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
411 break;
sewardj883b00b2004-09-11 09:30:24 +0000412 case Iop_Xor32:
413 e2 = IRExpr_Const(IRConst_U32(
414 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
415 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
416 break;
sewardjd7217032004-08-19 10:49:10 +0000417 case Iop_And32:
418 e2 = IRExpr_Const(IRConst_U32(
419 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
420 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
421 break;
sewardjb8e75862004-08-19 17:58:45 +0000422 case Iop_Or32:
423 e2 = IRExpr_Const(IRConst_U32(
424 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
425 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
426 break;
sewardjb9c5cf62004-08-24 15:10:38 +0000427 case Iop_Mul32:
428 e2 = IRExpr_Const(IRConst_U32(
429 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
430 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
431 break;
sewardjd7217032004-08-19 10:49:10 +0000432 case Iop_Shl32:
sewardj61348472004-08-20 01:01:04 +0000433 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
434 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj29632392004-08-22 02:38:11 +0000435 if (shift >= 0 && shift <= 31)
sewardj278c44c2004-08-20 00:28:13 +0000436 e2 = IRExpr_Const(IRConst_U32(
437 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
438 << shift)));
sewardjd7217032004-08-19 10:49:10 +0000439 break;
sewardj278c44c2004-08-20 00:28:13 +0000440 case Iop_Sar32: {
441 /* paranoid ... */
442 /*signed*/ Int s32;
sewardj61348472004-08-20 01:01:04 +0000443 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj278c44c2004-08-20 00:28:13 +0000444 s32 = (Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +0000445 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj278c44c2004-08-20 00:28:13 +0000446 if (shift >= 0 && shift <= 31) {
447 s32 >>=/*signed*/ shift;
448 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
449 }
450 break;
451 }
sewardj61348472004-08-20 01:01:04 +0000452 case Iop_Shr32: {
453 /* paranoid ... */
454 /*unsigned*/ UInt s32;
455 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
456 s32 = (Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
457 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
458 if (shift >= 0 && shift <= 31) {
459 s32 >>=/*unsigned*/ shift;
460 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
461 }
462 break;
463 }
sewardjb8e75862004-08-19 17:58:45 +0000464 case Iop_CmpEQ32:
465 e2 = IRExpr_Const(IRConst_Bit(
466 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
467 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
468 break;
sewardj088bcb42004-08-19 17:16:52 +0000469 case Iop_32HLto64:
470 e2 = IRExpr_Const(IRConst_U64(
471 (((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)) << 32)
472 | ((ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))
473 ));
474 break;
sewardj607dd4f2004-09-08 18:20:19 +0000475 default:
476 goto unhandled;
sewardjd7217032004-08-19 10:49:10 +0000477 }
sewardjf6729012004-08-25 12:45:13 +0000478
sewardj84be7372004-08-18 13:59:33 +0000479 } else {
sewardjf6729012004-08-25 12:45:13 +0000480
sewardj84be7372004-08-18 13:59:33 +0000481 /* other cases (identities, etc) */
sewardjf6729012004-08-25 12:45:13 +0000482 /* Add32(x,0) ==> x */
sewardj84be7372004-08-18 13:59:33 +0000483 if (e->Iex.Binop.op == Iop_Add32
484 && e->Iex.Binop.arg2->tag == Iex_Const
485 && e->Iex.Binop.arg2->Iex.Const.con->Ico.U32 == 0) {
486 e2 = e->Iex.Binop.arg1;
sewardjf6729012004-08-25 12:45:13 +0000487 } else
488
489 /* And8/16/32(t,t) ==> t, for some IRTemp t */
490 if ((e->Iex.Binop.op == Iop_And32
491 || e->Iex.Binop.op == Iop_And16
492 || e->Iex.Binop.op == Iop_And8)
493 && sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
494 e2 = e->Iex.Binop.arg1;
495 }
496
sewardj84be7372004-08-18 13:59:33 +0000497 }
498 }
499
500 /* Mux0X */
501 if (e->tag == Iex_Mux0X
502 && e->Iex.Mux0X.cond->tag == Iex_Const) {
503 Bool zero;
504 /* assured us by the IR type rules */
505 vassert(e->Iex.Mux0X.cond->Iex.Const.con->tag == Ico_U8);
506 zero = 0 == e->Iex.Mux0X.cond->Iex.Const.con->Ico.U8;
507 e2 = zero ? e->Iex.Mux0X.expr0 : e->Iex.Mux0X.exprX;
508 }
509
sewardj088bcb42004-08-19 17:16:52 +0000510 if (DEBUG_IROPT && e2 != e) {
511 vex_printf("FOLD: ");
sewardj84be7372004-08-18 13:59:33 +0000512 ppIRExpr(e); vex_printf(" -> ");
513 ppIRExpr(e2); vex_printf("\n");
514 }
515
516 return e2;
517
518 unhandled:
sewardj883b00b2004-09-11 09:30:24 +0000519# if 0
sewardj84be7372004-08-18 13:59:33 +0000520 vex_printf("\n\n");
521 ppIRExpr(e);
522 vpanic("fold_Expr: no rule for the above");
sewardj883b00b2004-09-11 09:30:24 +0000523# else
524 vex_printf("vex iropt: fold_Expr: no rule for: ");
525 ppIRExpr(e);
526 vex_printf("\n");
527 return e2;
528# endif
sewardj84be7372004-08-18 13:59:33 +0000529}
530
531
sewardj84be7372004-08-18 13:59:33 +0000532/* Apply the subst to a simple 1-level expression -- guaranteed to be
533 1-level due to previous flattening pass. */
534
535static IRExpr* subst_Expr ( Hash64* env, IRExpr* ex )
536{
537 if (ex->tag == Iex_Tmp) {
538 ULong res;
539 if (lookupH64(env, &res, (ULong)ex->Iex.Tmp.tmp)) {
540 return (IRExpr*)res;
541 } else {
542 /* not bound in env */
543 return ex;
544 }
545 }
546
547 if (ex->tag == Iex_Const)
548 return ex;
549 if (ex->tag == Iex_Get)
550 return ex;
551
sewardjd7217032004-08-19 10:49:10 +0000552 if (ex->tag == Iex_GetI) {
sewardj2d3f77c2004-09-22 23:49:09 +0000553 vassert(isAtom(ex->Iex.GetI.off));
sewardjd7217032004-08-19 10:49:10 +0000554 return IRExpr_GetI(
sewardj2d3f77c2004-09-22 23:49:09 +0000555 ex->Iex.GetI.descr,
556 subst_Expr(env, ex->Iex.GetI.off),
557 ex->Iex.GetI.bias
sewardjd7217032004-08-19 10:49:10 +0000558 );
559 }
560
sewardj84be7372004-08-18 13:59:33 +0000561 if (ex->tag == Iex_Binop) {
562 vassert(isAtom(ex->Iex.Binop.arg1));
563 vassert(isAtom(ex->Iex.Binop.arg2));
564 return IRExpr_Binop(
565 ex->Iex.Binop.op,
566 subst_Expr(env, ex->Iex.Binop.arg1),
567 subst_Expr(env, ex->Iex.Binop.arg2)
568 );
569 }
570
571 if (ex->tag == Iex_Unop) {
572 vassert(isAtom(ex->Iex.Unop.arg));
573 return IRExpr_Unop(
574 ex->Iex.Unop.op,
575 subst_Expr(env, ex->Iex.Unop.arg)
576 );
577 }
578
579 if (ex->tag == Iex_LDle) {
580 vassert(isAtom(ex->Iex.LDle.addr));
581 return IRExpr_LDle(
582 ex->Iex.LDle.ty,
583 subst_Expr(env, ex->Iex.LDle.addr)
584 );
585 }
586
587 if (ex->tag == Iex_CCall) {
588 Int i;
sewardj17442fe2004-09-20 14:54:28 +0000589 IRExpr** args2 = copyIRExprCallArgs ( ex->Iex.CCall.args );
sewardj84be7372004-08-18 13:59:33 +0000590 for (i = 0; args2[i]; i++) {
591 vassert(isAtom(args2[i]));
592 args2[i] = subst_Expr(env, args2[i]);
593 }
594 return IRExpr_CCall(
595 ex->Iex.CCall.name,
596 ex->Iex.CCall.retty,
597 args2
598 );
599 }
600
601 if (ex->tag == Iex_Mux0X) {
602 vassert(isAtom(ex->Iex.Mux0X.cond));
603 vassert(isAtom(ex->Iex.Mux0X.expr0));
604 vassert(isAtom(ex->Iex.Mux0X.exprX));
605 return IRExpr_Mux0X(
606 subst_Expr(env, ex->Iex.Mux0X.cond),
607 subst_Expr(env, ex->Iex.Mux0X.expr0),
608 subst_Expr(env, ex->Iex.Mux0X.exprX)
609 );
610 }
611
612 vex_printf("\n\n");
613 ppIRExpr(ex);
614 vpanic("subst_Expr");
615}
616
617
618/* Apply the subst to stmt, then fold the result as much as possible.
sewardjb8e75862004-08-19 17:58:45 +0000619 Much simplified due to stmt being previously flattened. Returning
620 NULL means the statement has been turned into a no-op. */
sewardj84be7372004-08-18 13:59:33 +0000621
622static IRStmt* subst_and_fold_Stmt ( Hash64* env, IRStmt* st )
623{
624# if 0
625 vex_printf("\nsubst and fold stmt\n");
626 ppIRStmt(st);
627 vex_printf("\n");
628# endif
629
630 if (st->tag == Ist_Put) {
sewardj6d076362004-09-23 11:06:17 +0000631 vassert(isAtom(st->Ist.Put.data));
sewardj84be7372004-08-18 13:59:33 +0000632 return IRStmt_Put(
633 st->Ist.Put.offset,
sewardj6d076362004-09-23 11:06:17 +0000634 fold_Expr(subst_Expr(env, st->Ist.Put.data))
sewardj84be7372004-08-18 13:59:33 +0000635 );
636 }
637
sewardjd7217032004-08-19 10:49:10 +0000638 if (st->tag == Ist_PutI) {
sewardj2d3f77c2004-09-22 23:49:09 +0000639 vassert(isAtom(st->Ist.PutI.off));
640 vassert(isAtom(st->Ist.PutI.data));
sewardjd7217032004-08-19 10:49:10 +0000641 return IRStmt_PutI(
sewardj2d3f77c2004-09-22 23:49:09 +0000642 st->Ist.PutI.descr,
643 fold_Expr(subst_Expr(env, st->Ist.PutI.off)),
644 st->Ist.PutI.bias,
645 fold_Expr(subst_Expr(env, st->Ist.PutI.data))
sewardjd7217032004-08-19 10:49:10 +0000646 );
647 }
648
sewardj84be7372004-08-18 13:59:33 +0000649 if (st->tag == Ist_Tmp) {
sewardj6d076362004-09-23 11:06:17 +0000650 /* This is the one place where an expr (st->Ist.Tmp.data) is
sewardj84be7372004-08-18 13:59:33 +0000651 allowed to be more than just a constant or a tmp. */
652 return IRStmt_Tmp(
653 st->Ist.Tmp.tmp,
sewardj6d076362004-09-23 11:06:17 +0000654 fold_Expr(subst_Expr(env, st->Ist.Tmp.data))
sewardj84be7372004-08-18 13:59:33 +0000655 );
656 }
657
658 if (st->tag == Ist_STle) {
659 vassert(isAtom(st->Ist.STle.addr));
660 vassert(isAtom(st->Ist.STle.data));
661 return IRStmt_STle(
662 fold_Expr(subst_Expr(env, st->Ist.STle.addr)),
663 fold_Expr(subst_Expr(env, st->Ist.STle.data))
664 );
665 }
666
sewardj17442fe2004-09-20 14:54:28 +0000667 if (st->tag == Ist_Dirty) {
668 Int i;
669 IRDirty *d, *d2;
670 d = st->Ist.Dirty.details;
671 d2 = emptyIRDirty();
672 *d2 = *d;
673 d2->args = copyIRExprCallArgs(d2->args);
674 if (d2->mFx != Ifx_None) {
675 vassert(isAtom(d2->mAddr));
676 d2->mAddr = fold_Expr(subst_Expr(env, d2->mAddr));
677 }
678 for (i = 0; d2->args[i]; i++) {
679 vassert(isAtom(d2->args[i]));
680 d2->args[i] = fold_Expr(subst_Expr(env, d2->args[i]));
681 }
682 return IRStmt_Dirty(d2);
683 }
684
sewardj84be7372004-08-18 13:59:33 +0000685 if (st->tag == Ist_Exit) {
sewardjb8e75862004-08-19 17:58:45 +0000686 IRExpr* fcond;
687 vassert(isAtom(st->Ist.Exit.cond));
688 fcond = fold_Expr(subst_Expr(env, st->Ist.Exit.cond));
689 if (fcond->tag == Iex_Const) {
690 /* Interesting. The condition on this exit has folded down to
691 a constant. */
692 vassert(fcond->Iex.Const.con->tag == Ico_Bit);
693 if (fcond->Iex.Const.con->Ico.Bit == False) {
694 /* exit is never going to happen, so dump the statement. */
695 return NULL;
696 } else {
697 vassert(fcond->Iex.Const.con->Ico.Bit == True);
698 /* Hmmm. The exit has become unconditional. Leave it as
699 it is for now, since we'd have to truncate the BB at
700 this point, which is tricky. */
701 /* fall out into the reconstruct-the-exit code. */
sewardj17442fe2004-09-20 14:54:28 +0000702 vex_printf("vex iropt: IRStmt_Exit became unconditional\n");
sewardjb8e75862004-08-19 17:58:45 +0000703 }
704 }
705 return IRStmt_Exit(fcond,st->Ist.Exit.dst);
sewardj84be7372004-08-18 13:59:33 +0000706 }
707
708 vex_printf("\n");
709 ppIRStmt(st);
710 vpanic("subst_and_fold_Stmt");
711}
712
713
714static IRBB* cprop_BB ( IRBB* in )
715{
716 Int i;
717 IRBB* out;
718 Hash64* env;
719 IRStmt* st2;
720
721 out = emptyIRBB();
722 out->tyenv = copyIRTypeEnv( in->tyenv );
723
724 /* Set up the env with which travels forward. This holds a
725 substitution, mapping IRTemps to atoms, that is, IRExprs which
726 are either IRTemps or IRConsts. Thus, copy and constant
727 propagation is done. The environment is to be applied as we
728 move along. Keys are IRTemps. Values are IRExpr*s.
729 */
730 env = newH64();
731
732 /* For each original SSA-form stmt ... */
733 for (i = 0; i < in->stmts_used; i++) {
734
735 /* First apply the substitution to the current stmt. This
736 propagates in any constants and tmp-tmp assignments
737 accumulated prior to this point. As part of the subst_Stmt
738 call, also then fold any constant expressions resulting. */
739
sewardjf0e43162004-08-20 00:11:12 +0000740 st2 = in->stmts[i];
741
742 /* perhaps st2 is already a no-op? */
743 if (!st2) continue;
744
745 st2 = subst_and_fold_Stmt( env, st2 );
sewardj84be7372004-08-18 13:59:33 +0000746
sewardjb8e75862004-08-19 17:58:45 +0000747 /* If the statement has been folded into a no-op, forget it. */
sewardjf0e43162004-08-20 00:11:12 +0000748 if (!st2) continue;
sewardjb8e75862004-08-19 17:58:45 +0000749
sewardj84be7372004-08-18 13:59:33 +0000750 /* Now consider what the stmt looks like. If it's of the form
751 't = const' or 't1 = t2', add it to the running environment
752 and not to the output BB. Otherwise, add it to the output
753 BB. */
754
sewardj6d076362004-09-23 11:06:17 +0000755 if (st2->tag == Ist_Tmp && st2->Ist.Tmp.data->tag == Iex_Const) {
sewardj84be7372004-08-18 13:59:33 +0000756 /* 't = const' -- add to env.
757 The pair (IRTemp, IRExpr*) is added. */
758 addToH64(env, (ULong)(st2->Ist.Tmp.tmp),
sewardj6d076362004-09-23 11:06:17 +0000759 (ULong)(st2->Ist.Tmp.data) );
sewardj84be7372004-08-18 13:59:33 +0000760 }
761 else
sewardj6d076362004-09-23 11:06:17 +0000762 if (st2->tag == Ist_Tmp && st2->Ist.Tmp.data->tag == Iex_Tmp) {
sewardj84be7372004-08-18 13:59:33 +0000763 /* 't1 = t2' -- add to env.
764 The pair (IRTemp, IRExpr*) is added. */
765 addToH64(env, (ULong)(st2->Ist.Tmp.tmp),
sewardj6d076362004-09-23 11:06:17 +0000766 (ULong)(st2->Ist.Tmp.data) );
sewardj84be7372004-08-18 13:59:33 +0000767 }
768 else {
769 /* Not interesting, copy st2 into the output block. */
770 addStmtToIRBB( out, st2 );
771 }
772 }
773
sewardj84be7372004-08-18 13:59:33 +0000774 out->next = subst_Expr( env, in->next );
775 out->jumpkind = in->jumpkind;
776 return out;
777}
778
779
780
sewardjedf4d692004-08-17 13:52:58 +0000781/*---------------------------------------------------------------*/
sewardj39e3f242004-08-18 16:54:52 +0000782/*--- Dead code (t = E) removal ---*/
783/*---------------------------------------------------------------*/
784
785/* The type of the Hash64 map is: a map from IRTemp to nothing
786 -- really just operating a set or IRTemps.
787*/
788
sewardj17442fe2004-09-20 14:54:28 +0000789static void addUses_Temp ( Hash64* set, IRTemp tmp )
790{
791 addToH64(set, (ULong)tmp, 0);
792}
793
sewardj39e3f242004-08-18 16:54:52 +0000794static void addUses_Expr ( Hash64* set, IRExpr* e )
795{
796 Int i;
797 switch (e->tag) {
sewardjd7217032004-08-19 10:49:10 +0000798 case Iex_GetI:
sewardj2d3f77c2004-09-22 23:49:09 +0000799 addUses_Expr(set, e->Iex.GetI.off);
sewardjd7217032004-08-19 10:49:10 +0000800 return;
sewardj39e3f242004-08-18 16:54:52 +0000801 case Iex_Mux0X:
802 addUses_Expr(set, e->Iex.Mux0X.cond);
803 addUses_Expr(set, e->Iex.Mux0X.expr0);
804 addUses_Expr(set, e->Iex.Mux0X.exprX);
805 return;
806 case Iex_CCall:
807 for (i = 0; e->Iex.CCall.args[i]; i++)
808 addUses_Expr(set, e->Iex.CCall.args[i]);
809 return;
810 case Iex_LDle:
811 addUses_Expr(set, e->Iex.LDle.addr);
812 return;
813 case Iex_Binop:
814 addUses_Expr(set, e->Iex.Binop.arg1);
815 addUses_Expr(set, e->Iex.Binop.arg2);
816 return;
817 case Iex_Unop:
818 addUses_Expr(set, e->Iex.Unop.arg);
819 return;
820 case Iex_Tmp:
sewardj17442fe2004-09-20 14:54:28 +0000821 addUses_Temp(set, e->Iex.Tmp.tmp);
sewardj39e3f242004-08-18 16:54:52 +0000822 return;
823 case Iex_Const:
824 case Iex_Get:
825 return;
826 default:
827 vex_printf("\n");
828 ppIRExpr(e);
829 vpanic("addUses_Expr");
830 }
831}
832
833static void addUses_Stmt ( Hash64* set, IRStmt* st )
834{
sewardj17442fe2004-09-20 14:54:28 +0000835 Int i;
836 IRDirty* d;
sewardj39e3f242004-08-18 16:54:52 +0000837 switch (st->tag) {
sewardjd7217032004-08-19 10:49:10 +0000838 case Ist_PutI:
sewardj2d3f77c2004-09-22 23:49:09 +0000839 addUses_Expr(set, st->Ist.PutI.off);
840 addUses_Expr(set, st->Ist.PutI.data);
sewardjd7217032004-08-19 10:49:10 +0000841 return;
sewardj39e3f242004-08-18 16:54:52 +0000842 case Ist_Tmp:
sewardj6d076362004-09-23 11:06:17 +0000843 addUses_Expr(set, st->Ist.Tmp.data);
sewardj39e3f242004-08-18 16:54:52 +0000844 return;
845 case Ist_Put:
sewardj6d076362004-09-23 11:06:17 +0000846 addUses_Expr(set, st->Ist.Put.data);
sewardj39e3f242004-08-18 16:54:52 +0000847 return;
848 case Ist_STle:
849 addUses_Expr(set, st->Ist.STle.addr);
850 addUses_Expr(set, st->Ist.STle.data);
851 return;
sewardj17442fe2004-09-20 14:54:28 +0000852 case Ist_Dirty:
853 d = st->Ist.Dirty.details;
854 if (d->mFx != Ifx_None)
855 addUses_Expr(set, d->mAddr);
856 for (i = 0; d->args[i] != NULL; i++)
857 addUses_Expr(set, d->args[i]);
858 return;
859 case Ist_Exit:
860 addUses_Expr(set, st->Ist.Exit.cond);
861 return;
sewardj39e3f242004-08-18 16:54:52 +0000862 default:
863 vex_printf("\n");
864 ppIRStmt(st);
865 vpanic("addUses_Stmt");
866 }
867}
868
869
870
871/* Note, this destructively modifies the given IRBB. */
872
873/* Scan backwards through statements, carrying a set of IRTemps which
874 are known to be used after the current point. On encountering 't =
875 E', delete the binding if it is not used. Otherwise, add any temp
876 uses to the set and keep on moving backwards. */
877
sewardjd7217032004-08-19 10:49:10 +0000878static void dead_BB ( IRBB* bb )
sewardj39e3f242004-08-18 16:54:52 +0000879{
880 Int i;
881 Hash64* set = newH64();
882 IRStmt* st;
883
884 /* start off by recording IRTemp uses in the next field. */
885 addUses_Expr(set, bb->next);
886
887 /* Work backwards through the stmts */
888 for (i = bb->stmts_used-1; i >= 0; i--) {
889 st = bb->stmts[i];
sewardj84ff0652004-08-23 16:16:08 +0000890 if (!st)
891 continue;
sewardj39e3f242004-08-18 16:54:52 +0000892 if (st->tag == Ist_Tmp
893 && !lookupH64(set, NULL, (ULong)(st->Ist.Tmp.tmp))) {
894 /* it's an IRTemp which never got used. Delete it. */
sewardj088bcb42004-08-19 17:16:52 +0000895 if (DEBUG_IROPT) {
sewardj39e3f242004-08-18 16:54:52 +0000896 vex_printf("DEAD: ");
897 ppIRStmt(st);
898 vex_printf("\n");
899 }
900 bb->stmts[i] = NULL;
901 } else {
902 /* Note any IRTemp uses made by the current statement. */
903 addUses_Stmt(set, st);
904 }
905 }
906}
907
908
909/*---------------------------------------------------------------*/
sewardjd7217032004-08-19 10:49:10 +0000910/*--- In-place removal of redundant GETs ---*/
911/*---------------------------------------------------------------*/
912
sewardjf0e43162004-08-20 00:11:12 +0000913/* Scan forwards, building up an environment binding (min offset, max
914 offset) pairs to values, which will either be temps or constants.
sewardjd7217032004-08-19 10:49:10 +0000915
sewardjf0e43162004-08-20 00:11:12 +0000916 On seeing 't = Get(minoff,maxoff)', look up (minoff,maxoff) in the
sewardj29632392004-08-22 02:38:11 +0000917 env and if it matches, replace the Get with the stored value. If
918 there is no match, add a (minoff,maxoff) :-> t binding.
sewardjd7217032004-08-19 10:49:10 +0000919
sewardjf0e43162004-08-20 00:11:12 +0000920 On seeing 'Put (minoff,maxoff) = t or c', first remove in the env
921 any binding which fully or partially overlaps with (minoff,maxoff).
922 Then add a new (minoff,maxoff) :-> t or c binding. */
sewardjd7217032004-08-19 10:49:10 +0000923
924/* Create keys, of the form ((minoffset << 16) | maxoffset). */
925
926static UInt mk_key_GetPut ( Int offset, IRType ty )
927{
928 /* offset should fit in 16 bits. */
929 UInt minoff = offset;
930 UInt maxoff = minoff + sizeofIRType(ty) - 1;
931 vassert((minoff & 0xFFFF0000) == 0);
932 vassert((maxoff & 0xFFFF0000) == 0);
933 return (minoff << 16) | maxoff;
934}
935
sewardj2d3f77c2004-09-22 23:49:09 +0000936static UInt mk_key_GetIPutI ( IRArray* descr )
sewardjd7217032004-08-19 10:49:10 +0000937{
sewardj2d3f77c2004-09-22 23:49:09 +0000938 UInt minoff = descr->base;
939 UInt maxoff = minoff + descr->nElems*sizeofIRType(descr->elemTy) - 1;
940 vassert((minoff & 0xFFFF0000) == 0);
941 vassert((maxoff & 0xFFFF0000) == 0);
sewardjd7217032004-08-19 10:49:10 +0000942 return (minoff << 16) | maxoff;
943}
944
sewardjf0e43162004-08-20 00:11:12 +0000945/* Supposing h has keys of the form generated by mk_key_GetPut and
946 mk_key_GetIPutI, invalidate any key which overlaps (k_lo
947 .. k_hi).
948*/
949
950static void invalidateOverlaps ( Hash64* h, UInt k_lo, UInt k_hi )
951{
952 Int j;
953 UInt e_lo, e_hi;
954 vassert(k_lo <= k_hi);
955 /* invalidate any env entries which in any way overlap (k_lo
956 .. k_hi) */
sewardj29632392004-08-22 02:38:11 +0000957 /* vex_printf("invalidate %d .. %d\n", k_lo, k_hi ); */
958
sewardjf0e43162004-08-20 00:11:12 +0000959 for (j = 0; j < h->used; j++) {
960 if (!h->inuse[j])
961 continue;
962 e_lo = (((UInt)h->key[j]) >> 16) & 0xFFFF;
963 e_hi = ((UInt)h->key[j]) & 0xFFFF;
964 vassert(e_lo <= e_hi);
965 if (e_hi < k_lo || k_hi < e_lo)
966 continue; /* no overlap possible */
967 else
968 /* overlap; invalidate */
969 h->inuse[j] = False;
970 }
971}
972
sewardjd7217032004-08-19 10:49:10 +0000973
974static void redundant_get_removal_BB ( IRBB* bb )
975{
976 Hash64* env = newH64();
sewardjbaf29ed2004-09-08 23:40:57 +0000977 UInt key = 0; /* keep gcc -O happy */
sewardjf0e43162004-08-20 00:11:12 +0000978 Int i;
sewardj088bcb42004-08-19 17:16:52 +0000979 Bool isPut;
sewardjf0e43162004-08-20 00:11:12 +0000980 ULong val;
sewardjd7217032004-08-19 10:49:10 +0000981
982 for (i = 0; i < bb->stmts_used; i++) {
983 IRStmt* st = bb->stmts[i];
984
985 if (!st)
986 continue;
987
988 /* Deal with Gets */
989 if (st->tag == Ist_Tmp
sewardj6d076362004-09-23 11:06:17 +0000990 && st->Ist.Tmp.data->tag == Iex_Get) {
sewardjd7217032004-08-19 10:49:10 +0000991 /* st is 't = Get(...)'. Look up in the environment and see
992 if the Get can be replaced. */
sewardj6d076362004-09-23 11:06:17 +0000993 IRExpr* get = st->Ist.Tmp.data;
sewardjd7217032004-08-19 10:49:10 +0000994 key = (ULong)mk_key_GetPut( get->Iex.Get.offset,
995 get->Iex.Get.ty );
996 if (lookupH64(env, &val, (ULong)key)) {
997 /* found it */
sewardj088bcb42004-08-19 17:16:52 +0000998 if (DEBUG_IROPT) {
sewardjd7217032004-08-19 10:49:10 +0000999 vex_printf("rGET: "); ppIRExpr(get);
1000 vex_printf(" -> "); ppIRExpr((IRExpr*)val);
1001 vex_printf("\n");
sewardj29632392004-08-22 02:38:11 +00001002 }
sewardjd7217032004-08-19 10:49:10 +00001003 bb->stmts[i] = IRStmt_Tmp(st->Ist.Tmp.tmp,
1004 (IRExpr*)val);
sewardj29632392004-08-22 02:38:11 +00001005 } else {
1006 /* Not found, but at least we know that t and the Get(...)
1007 are now associated. So add a binding to reflect that
1008 fact. */
1009 addToH64( env, (ULong)key,
1010 (ULong)(IRExpr_Tmp(st->Ist.Tmp.tmp)) );
sewardjd7217032004-08-19 10:49:10 +00001011 }
1012 }
1013
1014 /* Deal with Puts */
1015 switch (st->tag) {
1016 case Ist_Put:
1017 isPut = True;
1018 key = mk_key_GetPut( st->Ist.Put.offset,
sewardj6d076362004-09-23 11:06:17 +00001019 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
sewardjd7217032004-08-19 10:49:10 +00001020 break;
1021 case Ist_PutI:
1022 isPut = True;
sewardj2d3f77c2004-09-22 23:49:09 +00001023 key = mk_key_GetIPutI( st->Ist.PutI.descr );
sewardjd7217032004-08-19 10:49:10 +00001024 break;
1025 default:
1026 isPut = False;
1027 }
1028
1029 /* invalidate any env entries overlapped by this Put */
1030 if (isPut) {
sewardjf0e43162004-08-20 00:11:12 +00001031 UInt k_lo, k_hi;
sewardjd7217032004-08-19 10:49:10 +00001032 k_lo = (key >> 16) & 0xFFFF;
1033 k_hi = key & 0xFFFF;
sewardjf0e43162004-08-20 00:11:12 +00001034 invalidateOverlaps(env, k_lo, k_hi);
sewardjd7217032004-08-19 10:49:10 +00001035 }
1036
1037 /* add this one to the env, if appropriate */
1038 if (st->tag == Ist_Put) {
sewardj6d076362004-09-23 11:06:17 +00001039 vassert(isAtom(st->Ist.Put.data));
1040 addToH64( env, (ULong)key, (ULong)(st->Ist.Put.data));
sewardjd7217032004-08-19 10:49:10 +00001041 }
1042
1043 } /* for (i = 0; i < bb->stmts_used; i++) */
1044
1045}
1046
1047
1048/*---------------------------------------------------------------*/
sewardjf0e43162004-08-20 00:11:12 +00001049/*--- In-place removal of redundant PUTs ---*/
1050/*---------------------------------------------------------------*/
1051
1052/* Find any Get uses in st and invalidate any partially or fully
1053 overlapping ranges listed in env. Due to the flattening phase, the
1054 only stmt kind we expect to find a Get on is IRStmt_Tmp. */
1055
1056static void handle_gets_Stmt ( Hash64* env, IRStmt* st )
1057{
sewardjbaf29ed2004-09-08 23:40:57 +00001058 UInt key = 0; /* keep gcc -O happy */
sewardjf0e43162004-08-20 00:11:12 +00001059 Bool isGet;
1060 IRExpr* e;
1061 switch (st->tag) {
1062
1063 /* This is the only interesting case. Deal with Gets in the RHS
1064 expression. */
1065 case Ist_Tmp:
sewardj6d076362004-09-23 11:06:17 +00001066 e = st->Ist.Tmp.data;
sewardjf0e43162004-08-20 00:11:12 +00001067 switch (e->tag) {
1068 case Iex_Get:
1069 isGet = True;
1070 key = mk_key_GetPut ( e->Iex.Get.offset, e->Iex.Get.ty );
1071 break;
1072 case Iex_GetI:
1073 isGet = True;
sewardj2d3f77c2004-09-22 23:49:09 +00001074 key = mk_key_GetIPutI ( e->Iex.GetI.descr );
sewardjf0e43162004-08-20 00:11:12 +00001075 break;
1076 default:
1077 isGet = False;
1078 }
1079 if (isGet) {
1080 UInt k_lo, k_hi;
1081 k_lo = (key >> 16) & 0xFFFF;
1082 k_hi = key & 0xFFFF;
1083 invalidateOverlaps(env, k_lo, k_hi);
1084 }
1085 break;
1086
1087 /* all other cases are boring. */
1088 case Ist_STle:
1089 vassert(isAtom(st->Ist.STle.addr));
1090 vassert(isAtom(st->Ist.STle.data));
1091 return;
1092
sewardj17442fe2004-09-20 14:54:28 +00001093 case Ist_Dirty:
1094 return;
1095
sewardjf0e43162004-08-20 00:11:12 +00001096 case Ist_Exit:
1097 vassert(isAtom(st->Ist.Exit.cond));
1098 return;
1099
sewardjcf1ea9c2004-09-06 23:51:00 +00001100 case Ist_PutI:
sewardj2d3f77c2004-09-22 23:49:09 +00001101 vassert(isAtom(st->Ist.PutI.off));
1102 vassert(isAtom(st->Ist.PutI.data));
sewardjcf1ea9c2004-09-06 23:51:00 +00001103 return;
1104
sewardjf0e43162004-08-20 00:11:12 +00001105 default:
1106 vex_printf("\n");
1107 ppIRStmt(st);
1108 vex_printf("\n");
1109 vpanic("handle_gets_Stmt");
1110 }
1111}
1112
1113
1114/* Scan backwards, building up a set of (min offset, max
1115 offset) pairs, indicating those parts of the guest state
1116 for which the next event is a write.
1117
1118 On seeing a conditional exit, empty the set.
1119
1120 On seeing 'Put (minoff,maxoff) = t or c', if (minoff,maxoff) is
1121 completely within the set, remove the Put. Otherwise, add
1122 (minoff,maxoff) to the set.
1123
1124 On seeing 'Get (minoff,maxoff)', remove any part of the set
1125 overlapping (minoff,maxoff).
1126*/
1127
1128static void redundant_put_removal_BB ( IRBB* bb )
1129{
1130 Int i, j;
1131 Bool isPut;
1132 IRStmt* st;
sewardjbaf29ed2004-09-08 23:40:57 +00001133 UInt key = 0; /* keep gcc -O happy */
sewardjf0e43162004-08-20 00:11:12 +00001134
1135 Hash64* env = newH64();
1136 for (i = bb->stmts_used-1; i >= 0; i--) {
1137 st = bb->stmts[i];
1138
1139 /* Deal with conditional exits. */
1140 if (st->tag == Ist_Exit) {
1141 /* Since control may not get beyond this point, we must empty
1142 out the set, since we can no longer claim that the next
1143 event for any part of the guest state is definitely a
1144 write. */
1145 vassert(isAtom(st->Ist.Exit.cond));
1146 for (j = 0; j < env->used; j++)
1147 env->inuse[j] = False;
1148 continue;
1149 }
1150
1151 /* Deal with Puts */
1152 switch (st->tag) {
1153 case Ist_Put:
1154 isPut = True;
1155 key = mk_key_GetPut( st->Ist.Put.offset,
sewardj6d076362004-09-23 11:06:17 +00001156 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
1157 vassert(isAtom(st->Ist.Put.data));
sewardjf0e43162004-08-20 00:11:12 +00001158 break;
1159 case Ist_PutI:
1160 isPut = True;
sewardj2d3f77c2004-09-22 23:49:09 +00001161 key = mk_key_GetIPutI( st->Ist.PutI.descr );
1162 vassert(isAtom(st->Ist.PutI.off));
1163 vassert(isAtom(st->Ist.PutI.data));
sewardjf0e43162004-08-20 00:11:12 +00001164 break;
1165 default:
1166 isPut = False;
1167 }
sewardjcf1ea9c2004-09-06 23:51:00 +00001168 if (isPut && st->tag != Ist_PutI) {
sewardjf0e43162004-08-20 00:11:12 +00001169 /* See if any single entry in env overlaps this Put. This is
1170 simplistic in that the transformation is valid if, say, two
1171 or more entries in the env overlap this Put, but the use of
1172 lookupH64 will only find a single entry which exactly
1173 overlaps this Put. This is suboptimal but safe. */
1174 if (lookupH64(env, NULL, (ULong)key)) {
1175 /* This Put is redundant because a later one will overwrite
1176 it. So NULL (nop) it out. */
1177 if (DEBUG_IROPT) {
1178 vex_printf("rPUT: "); ppIRStmt(st);
1179 vex_printf("\n");
sewardj29632392004-08-22 02:38:11 +00001180 }
sewardjf0e43162004-08-20 00:11:12 +00001181 bb->stmts[i] = NULL;
1182 } else {
1183 /* We can't demonstrate that this Put is redundant, so add it
1184 to the running collection. */
1185 addToH64(env, (ULong)key, 0);
1186 }
1187 continue;
1188 }
1189
1190 /* Deal with Gets. These remove bits of the environment since
1191 appearance of a Get means that the next event for that slice
1192 of the guest state is no longer a write, but a read. */
1193 handle_gets_Stmt( env, st );
1194 }
1195}
1196
1197
sewardj84ff0652004-08-23 16:16:08 +00001198/*---------------------------------------------------------------*/
1199/*--- Specialisation of helper function calls, in ---*/
1200/*--- collaboration with the front end ---*/
1201/*---------------------------------------------------------------*/
1202
1203static
1204void spec_helpers_BB ( IRBB* bb,
1205 IRExpr* (*specHelper) ( Char*, IRExpr**) )
1206{
1207 Int i;
1208 IRStmt* st;
1209 IRExpr* ex;
1210
1211 for (i = bb->stmts_used-1; i >= 0; i--) {
1212 st = bb->stmts[i];
1213
1214 if (!st
1215 || st->tag != Ist_Tmp
sewardj6d076362004-09-23 11:06:17 +00001216 || st->Ist.Tmp.data->tag != Iex_CCall)
sewardj84ff0652004-08-23 16:16:08 +00001217 continue;
1218
sewardj6d076362004-09-23 11:06:17 +00001219 ex = (*specHelper)( st->Ist.Tmp.data->Iex.CCall.name,
1220 st->Ist.Tmp.data->Iex.CCall.args );
sewardj84ff0652004-08-23 16:16:08 +00001221 if (!ex)
1222 /* the front end can't think of a suitable replacement */
1223 continue;
1224
1225 /* We got something better. Install it in the bb. */
1226 bb->stmts[i]
1227 = IRStmt_Tmp(st->Ist.Tmp.tmp, ex);
1228
1229 if (0) {
1230 vex_printf("SPEC: ");
sewardj6d076362004-09-23 11:06:17 +00001231 ppIRExpr(st->Ist.Tmp.data);
sewardj84ff0652004-08-23 16:16:08 +00001232 vex_printf(" --> ");
1233 ppIRExpr(ex);
1234 vex_printf("\n");
1235 }
1236 }
1237}
1238
sewardj29632392004-08-22 02:38:11 +00001239
1240/*---------------------------------------------------------------*/
1241/*--- The tree builder ---*/
1242/*---------------------------------------------------------------*/
1243
1244typedef
1245 struct {
1246 Int occ; /* occurrence count for this tmp */
sewardj84ff0652004-08-23 16:16:08 +00001247 IRExpr* expr; /* expr it is bound to,
1248 or NULL if already 'used' */
sewardj29632392004-08-22 02:38:11 +00001249 Bool eDoesLoad; /* True <=> expr reads mem */
1250 Bool eDoesGet; /* True <=> expr reads guest state */
1251 Bool invalidateMe; /* used when dumping bindings */
1252 Int origPos; /* posn of the binder in the original bb */
1253 }
1254 TmpInfo;
1255
1256/* Given env :: IRTemp -> TmpInfo*
1257 Add the use-occurrences of temps in this expression
1258 to the environment.
1259*/
sewardj17442fe2004-09-20 14:54:28 +00001260static void occCount_Temp ( Hash64* env, IRTemp tmp )
1261{
1262 ULong res;
1263 TmpInfo* ti;
1264 if (lookupH64(env, &res, (ULong)tmp)) {
1265 ti = (TmpInfo*)res;
1266 ti->occ++;
1267 } else {
1268 ti = LibVEX_Alloc(sizeof(TmpInfo));
1269 ti->occ = 1;
1270 ti->expr = NULL;
1271 ti->eDoesLoad = False;
1272 ti->eDoesGet = False;
1273 ti->invalidateMe = False;
1274 ti->origPos = -1; /* filed in properly later */
1275 addToH64(env, (ULong)tmp, (ULong)ti );
1276 }
1277}
1278
sewardj29632392004-08-22 02:38:11 +00001279static void occCount_Expr ( Hash64* env, IRExpr* e )
1280{
sewardj17442fe2004-09-20 14:54:28 +00001281 Int i;
sewardj29632392004-08-22 02:38:11 +00001282
1283 switch (e->tag) {
1284
1285 case Iex_Tmp: /* the only interesting case */
sewardj17442fe2004-09-20 14:54:28 +00001286 occCount_Temp(env, e->Iex.Tmp.tmp);
sewardj29632392004-08-22 02:38:11 +00001287 return;
1288
1289 case Iex_Mux0X:
1290 occCount_Expr(env, e->Iex.Mux0X.cond);
1291 occCount_Expr(env, e->Iex.Mux0X.expr0);
1292 occCount_Expr(env, e->Iex.Mux0X.exprX);
1293 return;
1294
1295 case Iex_Binop:
1296 occCount_Expr(env, e->Iex.Binop.arg1);
1297 occCount_Expr(env, e->Iex.Binop.arg2);
1298 return;
1299
1300 case Iex_Unop:
1301 occCount_Expr(env, e->Iex.Unop.arg);
1302 return;
1303
1304 case Iex_LDle:
1305 occCount_Expr(env, e->Iex.LDle.addr);
1306 return;
1307
1308 case Iex_CCall:
1309 for (i = 0; e->Iex.CCall.args[i]; i++)
1310 occCount_Expr(env, e->Iex.CCall.args[i]);
1311 return;
1312
sewardjf6501992004-08-27 11:58:24 +00001313 case Iex_GetI:
sewardj2d3f77c2004-09-22 23:49:09 +00001314 occCount_Expr(env, e->Iex.GetI.off);
sewardjf6501992004-08-27 11:58:24 +00001315 return;
1316
sewardj29632392004-08-22 02:38:11 +00001317 case Iex_Const:
1318 case Iex_Get:
1319 return;
1320
1321 default:
1322 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1323 vpanic("occCount_Expr");
1324 }
1325}
1326
1327
1328/* Given env :: IRTemp -> TmpInfo*
1329 Add the use-occurrences of temps in this expression
1330 to the environment.
1331*/
1332static void occCount_Stmt ( Hash64* env, IRStmt* st )
1333{
sewardj17442fe2004-09-20 14:54:28 +00001334 Int i;
1335 IRDirty* d;
sewardj29632392004-08-22 02:38:11 +00001336 switch (st->tag) {
1337 case Ist_Tmp:
sewardj6d076362004-09-23 11:06:17 +00001338 occCount_Expr(env, st->Ist.Tmp.data);
sewardj29632392004-08-22 02:38:11 +00001339 return;
1340 case Ist_Put:
sewardj6d076362004-09-23 11:06:17 +00001341 occCount_Expr(env, st->Ist.Put.data);
sewardj29632392004-08-22 02:38:11 +00001342 return;
sewardjf6501992004-08-27 11:58:24 +00001343 case Ist_PutI:
sewardj2d3f77c2004-09-22 23:49:09 +00001344 occCount_Expr(env, st->Ist.PutI.off);
1345 occCount_Expr(env, st->Ist.PutI.data);
sewardjf6501992004-08-27 11:58:24 +00001346 return;
sewardj29632392004-08-22 02:38:11 +00001347 case Ist_STle:
1348 occCount_Expr(env, st->Ist.STle.addr);
1349 occCount_Expr(env, st->Ist.STle.data);
1350 return;
sewardj17442fe2004-09-20 14:54:28 +00001351 case Ist_Dirty:
1352 d = st->Ist.Dirty.details;
1353 if (d->mFx != Ifx_None)
1354 occCount_Expr(env, d->mAddr);
1355 for (i = 0; d->args[i]; i++)
1356 occCount_Expr(env, d->args[i]);
1357 return;
sewardj29632392004-08-22 02:38:11 +00001358 case Ist_Exit:
1359 occCount_Expr(env, st->Ist.Exit.cond);
1360 return;
1361 default:
1362 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
1363 vpanic("occCount_Stmt");
1364 }
1365}
1366
sewardj17442fe2004-09-20 14:54:28 +00001367/* Look up a binding for tmp in the env. If found, return the bound
1368 expression, and set the env's binding to NULL so it is marked as
1369 used. If not found, return NULL. */
1370
1371static IRExpr* tbSubst_Temp ( Hash64* env, IRTemp tmp )
1372{
1373 TmpInfo* ti;
1374 ULong res;
1375 IRExpr* e;
1376 if (lookupH64(env, &res, (ULong)tmp)) {
1377 ti = (TmpInfo*)res;
1378 e = ti->expr;
1379 if (e) {
1380 ti->expr = NULL;
1381 return e;
1382 } else {
1383 return NULL;
1384 }
1385 } else {
1386 return NULL;
1387 }
1388}
sewardj29632392004-08-22 02:38:11 +00001389
1390/* Traverse e, looking for temps. For each observed temp, see if env
1391 contains a binding for the temp, and if so return the bound value.
1392 The env has the property that any binding it holds is
1393 'single-shot', so once a binding is used, it is marked as no longer
1394 available, by setting its .expr field to NULL. */
1395
1396static IRExpr* tbSubst_Expr ( Hash64* env, IRExpr* e )
1397{
sewardjc41f1fb2004-08-22 09:48:08 +00001398 IRExpr* e2;
1399 IRExpr** args2;
1400 Int i;
sewardj29632392004-08-22 02:38:11 +00001401
1402 switch (e->tag) {
1403
sewardjc41f1fb2004-08-22 09:48:08 +00001404 case Iex_CCall:
sewardj17442fe2004-09-20 14:54:28 +00001405 args2 = copyIRExprCallArgs(e->Iex.CCall.args);
sewardjc41f1fb2004-08-22 09:48:08 +00001406 for (i = 0; args2[i]; i++)
1407 args2[i] = tbSubst_Expr(env,args2[i]);
1408 return IRExpr_CCall(e->Iex.CCall.name,
1409 e->Iex.CCall.retty,
1410 args2
1411 );
sewardj29632392004-08-22 02:38:11 +00001412 case Iex_Tmp:
sewardj17442fe2004-09-20 14:54:28 +00001413 e2 = tbSubst_Temp(env, e->Iex.Tmp.tmp);
1414 return e2 ? e2 : e;
sewardjc41f1fb2004-08-22 09:48:08 +00001415 case Iex_Mux0X:
1416 return IRExpr_Mux0X(
1417 tbSubst_Expr(env, e->Iex.Mux0X.cond),
1418 tbSubst_Expr(env, e->Iex.Mux0X.expr0),
1419 tbSubst_Expr(env, e->Iex.Mux0X.exprX)
1420 );
1421 case Iex_Binop:
1422 return IRExpr_Binop(
1423 e->Iex.Binop.op,
1424 tbSubst_Expr(env, e->Iex.Binop.arg1),
1425 tbSubst_Expr(env, e->Iex.Binop.arg2)
1426 );
1427 case Iex_Unop:
1428 return IRExpr_Unop(
1429 e->Iex.Unop.op,
1430 tbSubst_Expr(env, e->Iex.Unop.arg)
1431 );
1432 case Iex_LDle:
1433 return IRExpr_LDle(
1434 e->Iex.LDle.ty,
sewardjf6501992004-08-27 11:58:24 +00001435 tbSubst_Expr(env, e->Iex.LDle.addr)
sewardjc41f1fb2004-08-22 09:48:08 +00001436 );
sewardjf6501992004-08-27 11:58:24 +00001437 case Iex_GetI:
1438 return IRExpr_GetI(
sewardj2d3f77c2004-09-22 23:49:09 +00001439 e->Iex.GetI.descr,
1440 tbSubst_Expr(env, e->Iex.GetI.off),
1441 e->Iex.GetI.bias
1442 );
sewardjc41f1fb2004-08-22 09:48:08 +00001443 case Iex_Const:
sewardj29632392004-08-22 02:38:11 +00001444 case Iex_Get:
1445 return e;
1446 default:
1447 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1448 vpanic("tbSubst_Expr");
1449 }
1450}
1451
1452/* Same deal as tbSubst_Expr, except for stmts. */
1453
1454static IRStmt* tbSubst_Stmt ( Hash64* env, IRStmt* st )
1455{
sewardj17442fe2004-09-20 14:54:28 +00001456 Int i;
1457 IRDirty* d;
1458 IRDirty* d2;
sewardj29632392004-08-22 02:38:11 +00001459 switch (st->tag) {
sewardj17442fe2004-09-20 14:54:28 +00001460 case Ist_STle:
1461 return IRStmt_STle(
1462 tbSubst_Expr(env, st->Ist.STle.addr),
1463 tbSubst_Expr(env, st->Ist.STle.data)
1464 );
sewardj29632392004-08-22 02:38:11 +00001465 case Ist_Tmp:
1466 return IRStmt_Tmp(
1467 st->Ist.Tmp.tmp,
sewardj6d076362004-09-23 11:06:17 +00001468 tbSubst_Expr(env, st->Ist.Tmp.data)
sewardj29632392004-08-22 02:38:11 +00001469 );
1470 case Ist_Put:
1471 return IRStmt_Put(
1472 st->Ist.Put.offset,
sewardj6d076362004-09-23 11:06:17 +00001473 tbSubst_Expr(env, st->Ist.Put.data)
sewardj29632392004-08-22 02:38:11 +00001474 );
sewardjf6501992004-08-27 11:58:24 +00001475 case Ist_PutI:
1476 return IRStmt_PutI(
sewardj2d3f77c2004-09-22 23:49:09 +00001477 st->Ist.PutI.descr,
1478 tbSubst_Expr(env, st->Ist.PutI.off),
1479 st->Ist.PutI.bias,
1480 tbSubst_Expr(env, st->Ist.PutI.data)
1481 );
sewardjf6501992004-08-27 11:58:24 +00001482
sewardj29632392004-08-22 02:38:11 +00001483 case Ist_Exit:
1484 return IRStmt_Exit(
1485 tbSubst_Expr(env, st->Ist.Exit.cond),
1486 st->Ist.Exit.dst
1487 );
sewardj17442fe2004-09-20 14:54:28 +00001488 case Ist_Dirty:
1489 d = st->Ist.Dirty.details;
1490 d2 = emptyIRDirty();
1491 *d2 = *d;
1492 if (d2->mFx != Ifx_None)
1493 d2->mAddr = tbSubst_Expr(env, d2->mAddr);
1494 for (i = 0; d2->args[i]; i++)
1495 d2->args[i] = tbSubst_Expr(env, d2->args[i]);
1496 return IRStmt_Dirty(d2);
sewardj29632392004-08-22 02:38:11 +00001497 default:
1498 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
1499 vpanic("tbSubst_Stmt");
1500 }
1501}
1502
1503
sewardj37d38012004-08-24 00:37:04 +00001504/* Traverse an expr, and detect if any part of it reads memory or does
1505 a Get. Be careful ... this really controls how much the
1506 tree-builder can reorder the code, so getting it right is critical.
1507*/
sewardj29632392004-08-22 02:38:11 +00001508static void setHints_Expr (Bool* doesLoad, Bool* doesGet, IRExpr* e )
1509{
sewardjc41f1fb2004-08-22 09:48:08 +00001510 Int i;
sewardj29632392004-08-22 02:38:11 +00001511 switch (e->tag) {
sewardjc41f1fb2004-08-22 09:48:08 +00001512 case Iex_CCall:
1513 for (i = 0; e->Iex.CCall.args[i]; i++)
1514 setHints_Expr(doesLoad, doesGet, e->Iex.CCall.args[i]);
1515 return;
1516 case Iex_Mux0X:
1517 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.cond);
1518 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.expr0);
1519 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.exprX);
1520 return;
1521 case Iex_Binop:
1522 setHints_Expr(doesLoad, doesGet, e->Iex.Binop.arg1);
1523 setHints_Expr(doesLoad, doesGet, e->Iex.Binop.arg2);
1524 return;
1525 case Iex_Unop:
1526 setHints_Expr(doesLoad, doesGet, e->Iex.Unop.arg);
1527 return;
1528 case Iex_LDle:
1529 *doesLoad |= True;
sewardj37d38012004-08-24 00:37:04 +00001530 setHints_Expr(doesLoad, doesGet, e->Iex.LDle.addr);
sewardjc41f1fb2004-08-22 09:48:08 +00001531 return;
sewardj29632392004-08-22 02:38:11 +00001532 case Iex_Get:
1533 *doesGet |= True;
1534 return;
sewardjf6501992004-08-27 11:58:24 +00001535 case Iex_GetI:
1536 *doesGet |= True;
sewardj2d3f77c2004-09-22 23:49:09 +00001537 setHints_Expr(doesLoad, doesGet, e->Iex.GetI.off);
sewardjf6501992004-08-27 11:58:24 +00001538 return;
sewardjc41f1fb2004-08-22 09:48:08 +00001539 case Iex_Tmp:
1540 case Iex_Const:
1541 return;
sewardj29632392004-08-22 02:38:11 +00001542 default:
1543 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1544 vpanic("setHints_Expr");
1545 }
1546}
1547
1548
1549static void dumpInvalidated ( Hash64* env, IRBB* bb, /*INOUT*/Int* j )
1550{
1551 Int k, oldest_op, oldest_k;
1552 TmpInfo* ti;
1553
1554 /* Dump all the bindings to marked as invalidated, in order. */
1555 while (True) {
1556
1557 /* find the oldest bind marked 'invalidateMe'. */
1558 oldest_op = 1<<30;
1559 oldest_k = 1<<30;
1560 for (k = 0; k < env->used; k++) {
1561 if (!env->inuse[k])
1562 continue;
1563 ti = (TmpInfo*)(env->val[k]);
1564 if (!ti->expr)
1565 continue;
1566 if (!ti->invalidateMe)
1567 continue;
sewardjc41f1fb2004-08-22 09:48:08 +00001568 /* vex_printf("FOUND INVAL %d %d\n", ti->origPos, oldest_op); */
sewardj29632392004-08-22 02:38:11 +00001569 if (ti->origPos < oldest_op) {
1570 oldest_op = ti->origPos;
1571 oldest_k = k;
1572 }
1573 }
1574
1575 /* No more binds to invalidate. */
1576 if (oldest_op == 1<<30)
sewardjc41f1fb2004-08-22 09:48:08 +00001577 return;
sewardj29632392004-08-22 02:38:11 +00001578
1579 /* the oldest bind to invalidate has been identified */
1580 vassert(oldest_op != 1<<31 && oldest_k != 1<<31);
1581 ti = (TmpInfo*)(env->val[oldest_k]);
1582 vassert(ti->expr && ti->invalidateMe);
1583
1584 /* and invalidate it ... */
1585 bb->stmts[*j] = IRStmt_Tmp( (IRTemp)(env->key[oldest_k]), ti->expr);
1586 /* vex_printf("**1 "); ppIRStmt(bb->stmts[*j]); vex_printf("\n"); */
1587 (*j)++;
1588 ti->invalidateMe = False;
1589 ti->expr = NULL; /* no longer available for substitution */
1590
1591 } /* loop which dumps the binds marked for invalidation */
1592}
1593
1594
1595
1596static void treebuild_BB ( IRBB* bb )
1597{
1598 Int i, j, k;
1599 ULong res;
1600 Bool invPut, invStore;
1601 IRStmt* st;
1602 IRStmt* st2;
1603 TmpInfo* ti;
1604 IRExpr* next2;
1605
1606 /* Mapping from IRTemp to TmpInfo*. */
1607 Hash64* env = newH64();
1608
1609 /* Phase 1. Scan forwards in bb, counting use occurrences of each
1610 temp. Also count occurrences in the bb->next field. */
1611
1612 for (i = 0; i < bb->stmts_used; i++) {
1613 st = bb->stmts[i];
1614 if (!st)
1615 continue;
1616 occCount_Stmt( env, st );
1617 }
1618 occCount_Expr(env, bb->next );
1619
1620#if 0
1621 for (i = 0; i < env->used; i++) {
1622 if (!env->inuse[i])
1623 continue;
1624 ppIRTemp( (IRTemp)(env->key[i]) );
1625 vex_printf(" used %d\n", ((TmpInfo*)env->val[i])->occ );
1626 }
1627#endif
1628
1629 /* Phase 2. Fill in the origPos fields. */
1630
1631 for (i = 0; i < bb->stmts_used; i++) {
1632 st = bb->stmts[i];
1633 if (!st)
1634 continue;
1635 if (st->tag != Ist_Tmp)
1636 continue;
1637
1638 if (!lookupH64(env, &res, (ULong)(st->Ist.Tmp.tmp))) {
sewardj84ff0652004-08-23 16:16:08 +00001639 vex_printf("\n");
1640 ppIRTemp(st->Ist.Tmp.tmp);
1641 vex_printf("\n");
sewardj29632392004-08-22 02:38:11 +00001642 vpanic("treebuild_BB (phase 2): unmapped IRTemp");
1643 }
1644 ti = (TmpInfo*)res;
1645 ti->origPos = i;
1646 }
1647
1648 /* Phase 3. Scan forwards in bb.
1649
1650 On seeing 't = E', occ(t)==1,
1651 let E'=env(E), set t's binding to be E', and
1652 delete this stmt.
1653 Also examine E' and set the hints for E' appropriately
1654 (doesLoad? doesGet?)
1655
1656 On seeing any other stmt,
1657 let stmt' = env(stmt)
1658 remove from env any 't=E' binds invalidated by stmt
1659 emit the invalidated stmts
1660 emit stmt'
1661
1662 Apply env to bb->next.
1663 */
1664
1665 /* The stmts in bb are being reordered, and we are guaranteed to
1666 end up with no more than the number we started with. Use i to
1667 be the cursor of the current stmt examined and j <= i to be that
1668 for the current stmt being written.
1669 */
1670 j = 0;
1671 for (i = 0; i < bb->stmts_used; i++) {
1672 st = bb->stmts[i];
1673 if (!st)
1674 continue;
1675
1676 if (st->tag == Ist_Tmp) {
sewardje80679a2004-09-21 23:00:11 +00001677 /* vex_printf("acquire binding\n"); */
sewardj29632392004-08-22 02:38:11 +00001678 if (!lookupH64(env, &res, (ULong)(st->Ist.Tmp.tmp))) {
1679 vpanic("treebuild_BB (phase 2): unmapped IRTemp");
1680 }
1681 ti = (TmpInfo*)res;
1682 if (ti->occ == 1) {
1683 /* ok, we have 't = E', occ(t)==1. Do the abovementioned actions. */
sewardj6d076362004-09-23 11:06:17 +00001684 IRExpr* e = st->Ist.Tmp.data;
sewardj29632392004-08-22 02:38:11 +00001685 IRExpr* e2 = tbSubst_Expr(env, e);
1686 ti->expr = e2;
1687 ti->eDoesLoad = ti->eDoesGet = False;
1688 setHints_Expr(&ti->eDoesLoad, &ti->eDoesGet, e2);
1689 /* don't advance j, as we are deleting this stmt and instead
1690 holding it temporarily in the env. */
1691 continue; /* the for (i = 0; i < bb->stmts_used; i++) loop */
1692 }
1693 }
1694
1695 /* we get here for any other kind of statement. */
1696 /* 'use up' any bindings required by the current statement. */
1697 st2 = tbSubst_Stmt(env, st);
1698
1699 /* Now, before this stmt, dump any bindings it invalidates.
1700 These need to be dumped in the order in which they originally
1701 appeared. (Stupid algorithm): first, mark all bindings which
1702 need to be dumped. Then, dump them in the order in which
1703 they were defined. */
sewardj17442fe2004-09-20 14:54:28 +00001704 invPut = st->tag == Ist_Put
1705 || st->tag == Ist_PutI || st->tag == Ist_Dirty;
1706 invStore = st->tag == Ist_STle
1707 || st->tag == Ist_Dirty;
sewardj29632392004-08-22 02:38:11 +00001708
1709 for (k = 0; k < env->used; k++) {
1710 if (!env->inuse[k])
1711 continue;
1712 ti = (TmpInfo*)(env->val[k]);
1713 if (!ti->expr)
1714 continue;
1715
1716 /* We have to invalidate this binding. */
1717 ti->invalidateMe
1718 = (ti->eDoesLoad && invStore) || (ti->eDoesGet && invPut);
sewardjc41f1fb2004-08-22 09:48:08 +00001719 /*
1720 if (ti->invalidateMe)
1721 vex_printf("SET INVAL\n");
1722 */
sewardj29632392004-08-22 02:38:11 +00001723 }
1724
1725 dumpInvalidated ( env, bb, &j );
1726
1727 /* finally, emit the substituted statement */
1728 bb->stmts[j] = st2;
1729 /* vex_printf("**2 "); ppIRStmt(bb->stmts[j]); vex_printf("\n"); */
1730 j++;
1731
1732 vassert(j <= i+1);
1733 } /* for each stmt in the original bb ... */
1734
1735 /* Finally ... substitute the ->next field as much as possible, and
1736 dump any left-over bindings. Hmm. Perhaps there should be no
1737 left over bindings? Or any left-over bindings are
1738 by definition dead? */
1739 next2 = tbSubst_Expr(env, bb->next);
1740 bb->next = next2;
1741 bb->stmts_used = j;
1742}
1743
1744
1745
sewardjf0e43162004-08-20 00:11:12 +00001746/*---------------------------------------------------------------*/
sewardj4345f7a2004-09-22 19:49:27 +00001747/*--- Common Subexpression Elimination ---*/
1748/*---------------------------------------------------------------*/
1749
1750/* Expensive in time and space. */
1751
1752/* Uses two environments:
1753 a IRTemp -> IRTemp mapping
1754 a mapping from AvailExpr* to IRTemp
1755*/
1756
1757typedef
1758 struct {
1759 enum { Ut, Btt, Btc } tag;
1760 union {
1761 /* unop(tmp) */
1762 struct {
1763 IROp op;
1764 IRTemp arg;
1765 } Ut;
1766 struct {
1767 IROp op;
1768 IRTemp arg1;
1769 IRTemp arg2;
1770 } Btt;
1771 struct {
1772 IROp op;
1773 IRTemp arg1;
1774 IRConst con2;
1775 } Btc;
1776 } u;
1777 }
1778 AvailExpr;
1779
1780static Bool eq_AvailExpr ( AvailExpr* a1, AvailExpr* a2 )
1781{
1782 if (a1->tag != a2->tag)
1783 return False;
1784 switch (a1->tag) {
1785 case Ut: return a1->u.Ut.op == a2->u.Ut.op
1786 && a1->u.Ut.arg == a2->u.Ut.arg;
1787 case Btt: return a1->u.Btt.op == a2->u.Btt.op
1788 && a1->u.Btt.arg1 == a2->u.Btt.arg1
1789 && a1->u.Btt.arg2 == a2->u.Btt.arg2;
1790 case Btc: return a1->u.Btc.op == a2->u.Btc.op
1791 && a1->u.Btc.arg1 == a2->u.Btc.arg1
1792 && eqIRConst(&a1->u.Btc.con2, &a2->u.Btc.con2);
1793 default: vpanic("eq_AvailExpr");
1794 }
1795}
1796
1797static IRExpr* availExpr_to_IRExpr ( AvailExpr* ae )
1798{
1799 IRConst* con;
1800 switch (ae->tag) {
1801 case Ut:
1802 return IRExpr_Unop( ae->u.Ut.op, IRExpr_Tmp(ae->u.Ut.arg) );
1803 case Btt:
1804 return IRExpr_Binop( ae->u.Btt.op,
1805 IRExpr_Tmp(ae->u.Btt.arg1),
1806 IRExpr_Tmp(ae->u.Btt.arg2) );
1807 case Btc:
1808 con = LibVEX_Alloc(sizeof(IRConst));
1809 *con = ae->u.Btc.con2;
1810 return IRExpr_Binop( ae->u.Btc.op,
1811 IRExpr_Tmp(ae->u.Btc.arg1), IRExpr_Const(con) );
1812 default:
1813 vpanic("availExpr_to_IRExpr");
1814 }
1815}
1816
1817inline
1818static IRTemp subst_AvailExpr_Temp ( Hash64* env, IRTemp tmp )
1819{
1820 ULong res;
1821 /* env :: IRTemp -> IRTemp */
1822 if (lookupH64( env, &res, (ULong)tmp ))
1823 return (IRTemp)res;
1824 else
1825 return tmp;
1826}
1827
1828static void subst_AvailExpr ( Hash64* env, AvailExpr* ae )
1829{
1830 /* env :: IRTemp -> IRTemp */
1831 switch (ae->tag) {
1832 case Ut:
1833 ae->u.Ut.arg = subst_AvailExpr_Temp( env, ae->u.Ut.arg );
1834 break;
1835 case Btt:
1836 ae->u.Btt.arg1 = subst_AvailExpr_Temp( env, ae->u.Btt.arg1 );
1837 ae->u.Btt.arg2 = subst_AvailExpr_Temp( env, ae->u.Btt.arg2 );
1838 break;
1839 case Btc:
1840 ae->u.Btc.arg1 = subst_AvailExpr_Temp( env, ae->u.Btc.arg1 );
1841 break;
1842 default:
1843 vpanic("subst_AvailExpr");
1844 }
1845}
1846
1847static AvailExpr* irExpr_to_AvailExpr ( IRExpr* e )
1848{
1849 AvailExpr* ae;
1850
1851 if (e->tag == Iex_Unop
1852 && e->Iex.Unop.arg->tag == Iex_Tmp) {
1853 ae = LibVEX_Alloc(sizeof(AvailExpr));
1854 ae->tag = Ut;
1855 ae->u.Ut.op = e->Iex.Unop.op;
1856 ae->u.Ut.arg = e->Iex.Unop.arg->Iex.Tmp.tmp;
1857 return ae;
1858 }
1859
1860 if (e->tag == Iex_Binop
1861 && e->Iex.Binop.arg1->tag == Iex_Tmp
1862 && e->Iex.Binop.arg2->tag == Iex_Tmp) {
1863 ae = LibVEX_Alloc(sizeof(AvailExpr));
1864 ae->tag = Btt;
1865 ae->u.Btt.op = e->Iex.Binop.op;
1866 ae->u.Btt.arg1 = e->Iex.Binop.arg1->Iex.Tmp.tmp;
1867 ae->u.Btt.arg2 = e->Iex.Binop.arg2->Iex.Tmp.tmp;
1868 return ae;
1869 }
1870
1871 if (e->tag == Iex_Binop
1872 && e->Iex.Binop.arg1->tag == Iex_Tmp
1873 && e->Iex.Binop.arg2->tag == Iex_Const) {
1874 ae = LibVEX_Alloc(sizeof(AvailExpr));
1875 ae->tag = Btc;
1876 ae->u.Btc.op = e->Iex.Binop.op;
1877 ae->u.Btc.arg1 = e->Iex.Binop.arg1->Iex.Tmp.tmp;
1878 ae->u.Btc.con2 = *(e->Iex.Binop.arg2->Iex.Const.con);
1879 return ae;
1880 }
1881
1882 return NULL;
1883}
1884
1885
1886/* The BB is modified in-place. */
1887
1888static void cse_BB ( IRBB* bb )
1889{
1890 Int i, j;
1891 IRTemp t, q;
1892 IRStmt* st;
1893 AvailExpr* eprime;
1894
1895 Hash64* tenv = newH64(); /* :: IRTemp -> IRTemp */
1896 Hash64* aenv = newH64(); /* :: AvailExpr -> IRTemp */
1897
1898 //ppIRBB(bb);
1899 //vex_printf("\n\n");
1900
1901 /* Iterate forwards over the stmts.
1902 On seeing "t = E", where E is one of the 3 AvailExpr forms:
1903 let E' = apply tenv substitution to E
1904 search aenv for E'
1905 if a mapping E' -> q is found,
1906 replace this stmt by "t = q"
1907 and add binding t -> q to tenv
1908 else
1909 add binding E' -> t to aenv
1910 replace this stmt by "t = E'"
1911 Ignore any other kind of stmt.
1912 */
1913 for (i = 0; i < bb->stmts_used; i++) {
1914 st = bb->stmts[i];
1915
1916 /* ignore not-interestings */
1917 if ((!st) || st->tag != Ist_Tmp)
1918 continue;
1919
1920 t = st->Ist.Tmp.tmp;
sewardj6d076362004-09-23 11:06:17 +00001921 eprime = irExpr_to_AvailExpr(st->Ist.Tmp.data);
sewardj4345f7a2004-09-22 19:49:27 +00001922 /* ignore if not of AvailExpr form */
1923 if (!eprime)
1924 continue;
1925
1926 //vex_printf("considering: " ); ppIRStmt(st); vex_printf("\n");
1927
1928 /* apply tenv */
1929 subst_AvailExpr( tenv, eprime );
1930
1931 /* search aenv for eprime, unfortunately the hard way */
1932 for (j = 0; j < aenv->used; j++)
1933 if (aenv->inuse[j] && eq_AvailExpr(eprime, (AvailExpr*)aenv->key[j]))
1934 break;
1935
1936 if (j < aenv->used) {
1937 /* A binding E' -> q was found. Replace stmt by "t = q" and
1938 note the t->q binding in tenv. */
1939 /* (this is the core of the CSE action) */
1940 q = (IRTemp)aenv->val[j];
1941 bb->stmts[i] = IRStmt_Tmp( t, IRExpr_Tmp(q) );
1942 addToH64( tenv, (ULong)t, (ULong)q );
1943 } else {
1944 /* No binding was found, so instead we add E' -> t to our
1945 collection of available expressions, replace this stmt
1946 with "t = E'", and move on. */
1947 bb->stmts[i] = IRStmt_Tmp( t, availExpr_to_IRExpr(eprime) );
1948 addToH64( aenv, (ULong)eprime, (ULong)t );
1949 }
1950 }
1951
1952 //ppIRBB(bb);
1953 //sanityCheckIRBB(bb, Ity_I32);
1954 //vex_printf("\n\n");
1955
1956}
1957
sewardja5dc3482004-10-03 23:10:48 +00001958
sewardj728c9d52004-09-24 17:19:22 +00001959/*---------------------------------------------------------------*/
1960/*--- Add32/Sub32 chain collapsing ---*/
1961/*---------------------------------------------------------------*/
1962
sewardja5dc3482004-10-03 23:10:48 +00001963/* Is this expression "Add32(tmp,const)" or "Sub32(tmp,const)" ? If
1964 yes, set *tmp and *i32 appropriately. *i32 is set as if the
1965 root node is Add32, not Sub32. */
1966
1967static Bool isAdd32OrSub32 ( IRExpr* e, IRTemp* tmp, Int* i32 )
1968{
1969 if (e->tag != Iex_Binop)
1970 return False;
1971 if (e->Iex.Binop.op != Iop_Add32 && e->Iex.Binop.op != Iop_Sub32)
1972 return False;
1973 if (e->Iex.Binop.arg1->tag != Iex_Tmp)
1974 return False;
1975 if (e->Iex.Binop.arg2->tag != Iex_Const)
1976 return False;
1977 *tmp = e->Iex.Binop.arg1->Iex.Tmp.tmp;
1978 *i32 = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32);
1979 if (e->Iex.Binop.op == Iop_Sub32)
1980 *i32 = -*i32;
1981 return True;
sewardj728c9d52004-09-24 17:19:22 +00001982}
1983
sewardja5dc3482004-10-03 23:10:48 +00001984
1985/* Figure out if tmp can be expressed as tmp3 +32 const, for some
1986 other tmp2. Scan backwards from the specified start point -- an
1987 optimisation. */
1988
1989static Bool collapseChain ( IRBB* bb, Int startHere,
1990 IRTemp tmp,
1991 IRTemp* tmp2, Int* i32 )
1992{
1993 Int j, ii;
1994 IRTemp vv;
1995 IRStmt* st;
1996 IRExpr* e;
1997
1998 /* the (var, con) pair contain the current 'representation' for
1999 'tmp'. We start with 'tmp + 0'. */
2000 IRTemp var = tmp;
2001 Int con = 0;
2002
2003 /* Scan backwards to see if tmp can be replaced by some other tmp
2004 +/- a constant. */
2005 for (j = startHere; j >= 0; j--) {
2006 st = bb->stmts[j];
2007 if (!st || st->tag != Ist_Tmp)
2008 continue;
2009 if (st->Ist.Tmp.tmp != var)
2010 continue;
2011 e = st->Ist.Tmp.data;
2012 if (!isAdd32OrSub32(e, &vv, &ii))
2013 break;
2014 var = vv;
2015 con += ii;
2016 }
2017 if (j == -1)
2018 /* no earlier binding for var .. ill-formed IR */
2019 vpanic("collapseChain");
2020
2021 /* so, did we find anything interesting? */
2022 if (var == tmp)
2023 return False; /* no .. */
2024
2025 *tmp2 = var;
2026 *i32 = con;
2027 return True;
2028}
2029
2030
sewardje98dcf22004-10-04 09:15:11 +00002031static
2032IRExpr* findPutI ( IRBB* bb, Int startHere,
2033 IRArray* descrG, IRTemp tmpG, Int biasG )
2034{
2035 Int j, iters;
2036 UInt minoffP, maxoffP, minoffG, maxoffG;
2037 IRArray* descrP;
2038 IRStmt* st;
2039 IRTemp tmpP;
2040 Int biasP;
2041
2042 if (0) {
2043 vex_printf("\nfindPutI ");
2044 ppIRArray(descrG);
2045 vex_printf(" ");
2046 ppIRTemp(tmpG);
2047 vex_printf(" %d\n", biasG);
2048 }
2049
2050 /* Scan backwards in bb from startHere to find a suitable
2051 PutI binding for (descr, tmp, bias), if any. */
2052 minoffG = descrG->base;
2053 maxoffG = minoffG + descrG->nElems*sizeofIRType(descrG->elemTy) - 1;
2054 vassert((minoffG & 0xFFFF0000) == 0);
2055 vassert((maxoffG & 0xFFFF0000) == 0);
2056 vassert(minoffG < maxoffG);
2057
2058 for (j = startHere; j >= 0; j--) {
2059 st = bb->stmts[j];
2060 if (!st) continue;
2061
2062 if (st->tag == Ist_Put) {
2063 /* Non-indexed Put. This can't give a binding, but we do need
2064 to check it doesn't invalidate the search by overlapping any
2065 part of the indexed guest state. */
2066 minoffP = st->Ist.Put.offset;
2067 maxoffP = minoffP + sizeofIRType(typeOfIRExpr(bb->tyenv,st->Ist.Put.data)) - 1;
2068 vassert((minoffP & 0xFFFF0000) == 0);
2069 vassert((maxoffP & 0xFFFF0000) == 0);
2070 vassert(minoffP < maxoffP);
2071 if (maxoffP < minoffG || maxoffG < minoffP) {
2072 /* we're OK; keep going */
2073 continue;
2074 } else {
2075 /* This Put potentially writes guest state that the GetI reads;
2076 we must fail. */
2077 return NULL;
2078 }
2079 }
2080
2081 if (st->tag == Ist_PutI) {
2082
2083 /* Indexed Put. First off, do an invalidation check. */
2084 descrP = st->Ist.PutI.descr;
2085 minoffP = descrP->base;
2086 maxoffP = minoffP + descrP->nElems*sizeofIRType(descrP->elemTy) - 1;
2087 vassert((minoffP & 0xFFFF0000) == 0);
2088 vassert((maxoffP & 0xFFFF0000) == 0);
2089 vassert(minoffP < maxoffP);
2090 if (maxoffP < minoffG || maxoffG < minoffP) {
2091 /* This PutI definitely doesn't overlap. Ignore it and keep going. */
2092 continue;
2093 }
2094 /* This PutI potentially writes the same array that the GetI reads.
2095It's safe to keep going provided we can show the PutI writes some
2096*other* element in the same array -- not this one. */
2097 if (!eqIRArray(descrG, descrP))
2098 /* The written array has different base, type or size from
2099 the read array. Better give up. */
2100 return NULL;
2101
2102 if (st->Ist.PutI.off->tag != Iex_Tmp) {
2103 ppIRStmt(st);
2104 vpanic("vex iropt: findPutI: .off is not Tmp");
2105 }
2106 tmpP = st->Ist.PutI.off->Iex.Tmp.tmp;
2107 if (tmpP != tmpG)
2108 /* We can't show that the base offsets are different. Prior CSE and
2109 Add/Sub-chain collapsing passes should have made them the same wherever possible. Give up. */
2110 return NULL;
2111
2112 biasP = st->Ist.PutI.bias;
2113 /* So now we know that the GetI and PutI index the same array with the same base. Are the offsets the same, modulo the array size? Do this paranoidly. */
2114 vassert(descrP->nElems == descrG->nElems);
2115 iters = 0;
2116 while (biasP < 0 || biasG < 0) {
2117 biasP += descrP->nElems;
2118 biasG += descrP->nElems;
2119 iters++;
2120 if (iters > 10)
2121 vpanic("findPutI: iters");
2122 }
2123 vassert(biasP >= 0 && biasG >= 0);
2124 biasP %= descrP->nElems;
2125 biasG %= descrP->nElems;
2126
2127 /* Finally, biasP and biasG are normalised into the range
2128 0 .. descrP/G->nElems - 1. And so we can establish equality/non-equality. */
2129
2130 /* Now we know the PutI doesn't invalidate the search. But does it
2131 supply a binding for the GetI ? */
2132 if (0) {
2133 vex_printf("considering P ");
2134 ppIRStmt(st);
2135 vex_printf("\n");
2136 }
2137 if (biasP == biasG) {
2138 /* Yup, found a replacement. */
2139 return st->Ist.PutI.data;
2140 }
2141
2142 /* else ... no, they don't match. Keep going. */
2143
2144
2145 }
2146
2147
2148 } /* for */
2149
2150 return NULL;
2151}
2152
2153
sewardja5dc3482004-10-03 23:10:48 +00002154/* The main function. Needs renaming. */
2155
sewardj728c9d52004-09-24 17:19:22 +00002156static void track_deltas_BB ( IRBB* bb )
2157{
sewardja5dc3482004-10-03 23:10:48 +00002158 IRStmt *st;
2159 IRTemp var, var2;
2160 Int i, con, con2;
2161
sewardj728c9d52004-09-24 17:19:22 +00002162 for (i = bb->stmts_used-1; i >= 0; i--) {
2163 st = bb->stmts[i];
sewardja5dc3482004-10-03 23:10:48 +00002164 if (!st)
2165 continue;
sewardj728c9d52004-09-24 17:19:22 +00002166
sewardja5dc3482004-10-03 23:10:48 +00002167 /* Try to collapse 't1 = Add32/Sub32(t2, con)'. */
sewardj728c9d52004-09-24 17:19:22 +00002168
sewardja5dc3482004-10-03 23:10:48 +00002169 if (st->tag == Ist_Tmp
2170 && isAdd32OrSub32(st->Ist.Tmp.data, &var, &con)) {
2171
2172 /* So e1 is of the form Add32(var,con) or Sub32(var,-con).
2173 Find out if var can be expressed as var2 + con2. */
2174 if (collapseChain(bb, i-1, var, &var2, &con2)) {
2175 if (DEBUG_IROPT) {
2176 vex_printf("replacing1 ");
2177 ppIRStmt(st);
2178 vex_printf(" with ");
2179 }
2180 con2 += con;
2181 bb->stmts[i]
2182 = IRStmt_Tmp(
2183 st->Ist.Tmp.tmp,
2184 (con2 >= 0)
2185 ? IRExpr_Binop(Iop_Add32,
2186 IRExpr_Tmp(var2),
2187 IRExpr_Const(IRConst_U32(con2)))
2188 : IRExpr_Binop(Iop_Sub32,
2189 IRExpr_Tmp(var2),
2190 IRExpr_Const(IRConst_U32(-con2)))
2191 );
2192 if (DEBUG_IROPT) {
2193 ppIRStmt(bb->stmts[i]);
2194 vex_printf("\n");
2195 }
2196 }
2197
2198 continue;
sewardj728c9d52004-09-24 17:19:22 +00002199 }
sewardj728c9d52004-09-24 17:19:22 +00002200
sewardja5dc3482004-10-03 23:10:48 +00002201 /* Try to collapse 't1 = GetI[t2, con]'. */
2202
2203 if (st->tag == Ist_Tmp
2204 && st->Ist.Tmp.data->tag == Iex_GetI
2205 && st->Ist.Tmp.data->Iex.GetI.off->tag == Iex_Tmp
2206 && collapseChain(bb, i-1, st->Ist.Tmp.data->Iex.GetI.off
2207 ->Iex.Tmp.tmp, &var2, &con2)) {
2208 if (DEBUG_IROPT) {
2209 vex_printf("replacing3 ");
2210 ppIRStmt(st);
2211 vex_printf(" with ");
2212 }
2213 con2 += st->Ist.Tmp.data->Iex.GetI.bias;
2214 bb->stmts[i]
2215 = IRStmt_Tmp(
2216 st->Ist.Tmp.tmp,
2217 IRExpr_GetI(st->Ist.Tmp.data->Iex.GetI.descr,
2218 IRExpr_Tmp(var2),
2219 con2));
2220 if (DEBUG_IROPT) {
2221 ppIRStmt(bb->stmts[i]);
2222 vex_printf("\n");
2223 }
2224 continue;
sewardj728c9d52004-09-24 17:19:22 +00002225 }
sewardja5dc3482004-10-03 23:10:48 +00002226
2227 /* Perhaps st is PutI[t, con] ? */
2228
2229 if (st->tag == Ist_PutI
2230 && st->Ist.PutI.off->tag == Iex_Tmp
2231 && collapseChain(bb, i-1, st->Ist.PutI.off->Iex.Tmp.tmp,
2232 &var2, &con2)) {
2233 if (DEBUG_IROPT) {
2234 vex_printf("replacing2 ");
2235 ppIRStmt(st);
2236 vex_printf(" with ");
2237 }
2238 con2 += st->Ist.PutI.bias;
2239 bb->stmts[i]
2240 = IRStmt_PutI(st->Ist.PutI.descr,
2241 IRExpr_Tmp(var2),
2242 con2,
2243 st->Ist.PutI.data);
2244 if (DEBUG_IROPT) {
2245 ppIRStmt(bb->stmts[i]);
2246 vex_printf("\n");
2247 }
2248 continue;
2249 }
2250
2251 } /* for */
sewardj728c9d52004-09-24 17:19:22 +00002252
sewardje98dcf22004-10-04 09:15:11 +00002253 /* ----------------------- */
2254 /* PutI -> GetI forwarding */
2255
2256 for (i = bb->stmts_used-1; i >= 0; i--) {
2257 st = bb->stmts[i];
2258 if (!st)
2259 continue;
2260
2261 if (st->tag == Ist_Tmp
2262 && st->Ist.Tmp.data->tag == Iex_GetI
2263 && st->Ist.Tmp.data->Iex.GetI.off->tag == Iex_Tmp) {
2264 IRArray* descr = st->Ist.Tmp.data->Iex.GetI.descr;
2265 IRTemp tmp = st->Ist.Tmp.data->Iex.GetI.off->Iex.Tmp.tmp;
2266 Int bias = st->Ist.Tmp.data->Iex.GetI.bias;
2267 IRExpr* replacement
2268 = findPutI(bb, i-1, descr, tmp, bias);
2269 if (replacement && isAtom(replacement)) {
2270 if (DEBUG_IROPT) {
2271 vex_printf("PiGi: ");
2272 ppIRExpr(st->Ist.Tmp.data);
2273 vex_printf(" -> ");
2274 ppIRExpr(replacement);
2275 vex_printf("\n");
2276 }
2277 bb->stmts[i] = IRStmt_Tmp(st->Ist.Tmp.tmp,
2278 replacement);
2279 }
2280 }
2281 }
2282
sewardj728c9d52004-09-24 17:19:22 +00002283}
sewardj4345f7a2004-09-22 19:49:27 +00002284
2285/*---------------------------------------------------------------*/
sewardjedf4d692004-08-17 13:52:58 +00002286/*--- iropt main ---*/
2287/*---------------------------------------------------------------*/
2288
sewardj4345f7a2004-09-22 19:49:27 +00002289static Bool iropt_verbose = False;
2290
2291
sewardjedf4d692004-08-17 13:52:58 +00002292/* Rules of the game:
2293
2294 - IRExpr/IRStmt trees should be treated as immutable, as they
2295 may get shared. So never change a field of such a tree node;
2296 instead construct and return a new one if needed.
2297*/
2298
sewardj4345f7a2004-09-22 19:49:27 +00002299/* Do a simple cleanup pass on bb. This is: redundant Get removal,
2300 redundant Put removal, constant propagation, dead code removal,
2301 clean helper specialisation, and dead code removal (again).
2302*/
2303
2304static
2305IRBB* baseline_cleanup ( IRBB* bb,
2306 IRExpr* (*specHelper) ( Char*, IRExpr**) )
2307{
2308 redundant_get_removal_BB ( bb );
2309 if (iropt_verbose) {
2310 vex_printf("\n========= REDUNDANT GET\n\n" );
2311 ppIRBB(bb);
2312 }
2313
2314 redundant_put_removal_BB ( bb );
2315 if (iropt_verbose) {
2316 vex_printf("\n========= REDUNDANT PUT\n\n" );
2317 ppIRBB(bb);
2318 }
2319
2320 bb = cprop_BB ( bb );
2321 if (iropt_verbose) {
2322 vex_printf("\n========= CPROPD\n\n" );
2323 ppIRBB(bb);
2324 }
2325
2326 dead_BB ( bb );
2327 if (iropt_verbose) {
2328 vex_printf("\n========= DEAD\n\n" );
2329 ppIRBB(bb);
2330 }
2331
2332 spec_helpers_BB ( bb, specHelper );
2333 dead_BB ( bb );
2334 if (iropt_verbose) {
2335 vex_printf("\n========= SPECd \n\n" );
2336 ppIRBB(bb);
2337 }
2338
2339 return bb;
2340}
2341
2342/* Scan a flattened BB to see if it has any GetI or PutIs in it. Used
2343 as a heuristic hack to see if iropt needs to do expensive
2344 optimisations (CSE, PutI -> GetI forwarding) to improve code with
2345 those in.
2346*/
2347static Bool hasGetIorPutI ( IRBB* bb )
2348{
2349 Int i, j;
2350 IRStmt* st;
2351 IRDirty* d;
2352
2353 for (i = 0; i < bb->stmts_used; i++) {
2354 st = bb->stmts[i];
2355 if (!st)
2356 continue;
2357
2358 switch (st->tag) {
2359 case Ist_PutI:
2360 return True;
2361 case Ist_Tmp:
sewardj6d076362004-09-23 11:06:17 +00002362 if (st->Ist.Tmp.data->tag == Iex_GetI)
sewardj4345f7a2004-09-22 19:49:27 +00002363 return True;
2364 break;
2365 case Ist_Put:
sewardj6d076362004-09-23 11:06:17 +00002366 vassert(isAtom(st->Ist.Put.data));
sewardj4345f7a2004-09-22 19:49:27 +00002367 break;
2368 case Ist_STle:
2369 vassert(isAtom(st->Ist.STle.addr));
2370 vassert(isAtom(st->Ist.STle.data));
2371 break;
2372 case Ist_Exit:
2373 vassert(isAtom(st->Ist.Exit.cond));
2374 break;
2375 case Ist_Dirty:
2376 d = st->Ist.Dirty.details;
2377 for (j = 0; d->args[j]; j++)
2378 vassert(isAtom(d->args[j]));
2379 if (d->mFx != Ifx_None)
2380 vassert(isAtom(d->mAddr));
2381 break;
2382 default:
2383 ppIRStmt(st);
2384 vpanic("hasGetIorPutI");
2385 }
2386
2387 }
2388 return False;
2389
2390}
2391
2392
sewardjedf4d692004-08-17 13:52:58 +00002393/* exported from this file */
sewardj4345f7a2004-09-22 19:49:27 +00002394/* The main iropt entry point. */
2395
sewardj84ff0652004-08-23 16:16:08 +00002396IRBB* do_iropt_BB ( IRBB* bb0,
2397 IRExpr* (*specHelper) ( Char*, IRExpr**) )
sewardjedf4d692004-08-17 13:52:58 +00002398{
sewardj4345f7a2004-09-22 19:49:27 +00002399 static UInt n_total = 0;
2400 static UInt n_expensive = 0;
sewardj29632392004-08-22 02:38:11 +00002401
sewardj4345f7a2004-09-22 19:49:27 +00002402 Bool show_res = False;
2403
2404 IRBB *bb;
2405
2406 n_total++;
2407
2408 /* First flatten the block out, since all other
2409 phases assume flat code. */
2410
2411 bb = flatten_BB ( bb0 );
2412
2413 if (iropt_verbose) {
2414 vex_printf("\n========= FLAT\n\n" );
2415 ppIRBB(bb);
sewardj84be7372004-08-18 13:59:33 +00002416 }
sewardjd7217032004-08-19 10:49:10 +00002417
sewardj4345f7a2004-09-22 19:49:27 +00002418 /* Now do a preliminary cleanup pass. */
2419
2420 bb = baseline_cleanup( bb, specHelper );
2421
2422 /* If there are GetI/PutI in this block, do some expensive
2423 transformations:
2424
2425 - CSE
2426 - re-run of the baseline cleanup
2427
2428 */
2429
2430 if (hasGetIorPutI(bb)) {
2431 n_expensive++;
2432 vex_printf("***** EXPENSIVE %d %d\n", n_total, n_expensive);
sewardj4345f7a2004-09-22 19:49:27 +00002433 cse_BB( bb );
sewardja5dc3482004-10-03 23:10:48 +00002434 //ppIRBB(bb); vex_printf("\n\n");
sewardj728c9d52004-09-24 17:19:22 +00002435 track_deltas_BB( bb );
sewardj4345f7a2004-09-22 19:49:27 +00002436 /*
2437 ppIRBB(bb); vex_printf("\n\n");
2438 dead_BB( bb );
2439 bb = cprop_BB ( bb );
2440 dead_BB(bb);
2441 */
2442 //ppIRBB(bb); vex_printf("\n\nQQQQ\n");
2443 bb = baseline_cleanup( flatten_BB(bb), specHelper );
2444 //vassert(0);
2445 // vex_printf("expensive done\n");
2446 //show_res = True;
sewardjd7217032004-08-19 10:49:10 +00002447 }
2448
sewardj4345f7a2004-09-22 19:49:27 +00002449 /* Finally, rebuild trees, for the benefit of instruction
2450 selection. */
sewardjf0e43162004-08-20 00:11:12 +00002451
sewardj4345f7a2004-09-22 19:49:27 +00002452 treebuild_BB ( bb );
2453 if (show_res || iropt_verbose) {
sewardj29632392004-08-22 02:38:11 +00002454 vex_printf("\n========= TREEd \n\n" );
sewardj4345f7a2004-09-22 19:49:27 +00002455 ppIRBB(bb);
sewardj29632392004-08-22 02:38:11 +00002456 }
sewardj29632392004-08-22 02:38:11 +00002457
sewardj4345f7a2004-09-22 19:49:27 +00002458 return bb;
sewardjedf4d692004-08-17 13:52:58 +00002459}
2460
2461
sewardja1a370f2004-08-17 13:31:55 +00002462/*---------------------------------------------------------------*/
2463/*--- end ir/iropt.c ---*/
2464/*---------------------------------------------------------------*/