blob: f15783715d9f8684b0a7c077626162effccff388 [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/*---------------------------------------------------------------*/
sewardjd7217032004-08-19 10:49:10 +000021/*--- Should be made public (to vex) ---*/
22/*---------------------------------------------------------------*/
23
24static Int sizeofIRType ( IRType ty )
25{
26 switch (ty) {
27 case Ity_I8: return 1;
28 case Ity_I16: return 2;
29 case Ity_I32: return 4;
30 default: vex_printf("\n"); ppIRType(ty); vex_printf("\n");
31 vpanic("sizeofIType");
32 }
33}
34
35
36/*---------------------------------------------------------------*/
sewardja1a370f2004-08-17 13:31:55 +000037/*--- Finite mappery, of a sort ---*/
38/*---------------------------------------------------------------*/
39
40/* General map from 64-bit thing 64-bit thing. Could be done faster
41 by hashing. */
42
43typedef
44 struct {
45 Bool* inuse;
46 ULong* key;
47 ULong* val;
48 Int size;
49 Int used;
50 }
51 Hash64;
52
53static Hash64* newH64 ( void )
54{
55 Hash64* h = LibVEX_Alloc(sizeof(Hash64));
sewardj29632392004-08-22 02:38:11 +000056 h->size = 8;
sewardja1a370f2004-08-17 13:31:55 +000057 h->used = 0;
58 h->inuse = LibVEX_Alloc(h->size * sizeof(Bool));
59 h->key = LibVEX_Alloc(h->size * sizeof(ULong));
60 h->val = LibVEX_Alloc(h->size * sizeof(ULong));
61 return h;
62}
63
64
sewardj84be7372004-08-18 13:59:33 +000065/* Look up key in the map. */
sewardja1a370f2004-08-17 13:31:55 +000066
sewardj84be7372004-08-18 13:59:33 +000067static Bool lookupH64 ( Hash64* h, /*OUT*/ULong* val, ULong key )
sewardja1a370f2004-08-17 13:31:55 +000068{
69 Int i;
sewardj84be7372004-08-18 13:59:33 +000070 //vex_printf("lookupH64(%llx)\n", key );
sewardja1a370f2004-08-17 13:31:55 +000071 for (i = 0; i < h->used; i++) {
72 if (h->inuse[i] && h->key[i] == key) {
sewardj39e3f242004-08-18 16:54:52 +000073 if (val)
74 *val = h->val[i];
sewardja1a370f2004-08-17 13:31:55 +000075 return True;
76 }
77 }
78 return False;
79}
80
81
82/* Delete any binding for key in h. */
83
84static void delFromH64 ( Hash64* h, ULong key )
85{
86 Int i;
87 for (i = 0; i < h->used; i++) {
88 if (h->inuse[i] && h->key[i] == key) {
89 h->inuse[i] = False;
90 return;
91 }
92 }
93}
94
95
96
97/* Add key->val to the map. Replaces any existing binding for key. */
98
99static void addToH64 ( Hash64* h, ULong key, ULong val )
100{
101 Int i, j;
102
sewardj84be7372004-08-18 13:59:33 +0000103 //vex_printf("addToH64(%llx, %llx)\n", key, val);
sewardja1a370f2004-08-17 13:31:55 +0000104 /* Find and replace existing binding, if any. */
105 for (i = 0; i < h->used; i++) {
106 if (h->inuse[i] && h->key[i] == key) {
107 h->val[i] = val;
108 return;
109 }
110 }
111
112 /* Ensure a space is available. */
113 if (h->used == h->size) {
114 /* Copy into arrays twice the size. */
115 Bool* inuse2 = LibVEX_Alloc(2 * h->size * sizeof(Bool));
116 ULong* key2 = LibVEX_Alloc(2 * h->size * sizeof(ULong));
117 ULong* val2 = LibVEX_Alloc(2 * h->size * sizeof(ULong));
118 for (i = j = 0; i < h->size; i++) {
119 if (!h->inuse[i]) continue;
120 inuse2[j] = True;
121 key2[j] = h->key[i];
122 val2[j] = h->val[i];
123 j++;
124 }
125 h->used = j;
126 h->size *= 2;
127 h->inuse = inuse2;
128 h->key = key2;
129 h->val = val2;
130 }
131
132 /* Finally, add it. */
133 vassert(h->used < h->size);
134 h->inuse[h->used] = True;
135 h->key[h->used] = key;
sewardj84be7372004-08-18 13:59:33 +0000136 h->val[h->used] = val;
sewardja1a370f2004-08-17 13:31:55 +0000137 h->used++;
138}
139
sewardj84be7372004-08-18 13:59:33 +0000140
sewardjd7cb8532004-08-17 23:59:23 +0000141/*---------------------------------------------------------------*/
142/*--- Flattening out a BB into pure SSA form ---*/
143/*---------------------------------------------------------------*/
144
145/* Clone the NULL-terminated vector of IRExpr*s attached to a
146 CCall. */
147
148static IRExpr** copyIexCCallArgs ( IRExpr** vec )
149{
150 Int i;
151 IRExpr** newvec;
152 for (i = 0; vec[i]; i++)
153 ;
154 newvec = LibVEX_Alloc((i+1)*sizeof(IRExpr*));
155 for (i = 0; vec[i]; i++)
156 newvec[i] = vec[i];
157 newvec[i] = NULL;
158 return newvec;
159}
160
161
162/* Flatten out 'ex' so it is atomic, returning a new expression with
163 the same value, after having appended extra IRTemp assignments to
164 the end of 'bb'. */
165
166static IRExpr* flatten_Expr ( IRBB* bb, IRExpr* ex )
167{
168 Int i;
169 IRExpr** newargs;
170 IRType ty = typeOfIRExpr(bb->tyenv, ex);
171 IRTemp t1;
172
173 switch (ex->tag) {
174
sewardjd7217032004-08-19 10:49:10 +0000175 case Iex_GetI:
176 t1 = newIRTemp(bb->tyenv, ty);
177 addStmtToIRBB(bb, IRStmt_Tmp(t1,
178 IRExpr_GetI(flatten_Expr(bb, ex->Iex.GetI.offset),
179 ex->Iex.GetI.ty,
180 ex->Iex.GetI.minoff,
181 ex->Iex.GetI.maxoff)));
182 return IRExpr_Tmp(t1);
183
sewardjd7cb8532004-08-17 23:59:23 +0000184 case Iex_Get:
185 t1 = newIRTemp(bb->tyenv, ty);
186 addStmtToIRBB(bb,
187 IRStmt_Tmp(t1, ex));
188 return IRExpr_Tmp(t1);
189
190 case Iex_Binop:
191 t1 = newIRTemp(bb->tyenv, ty);
192 addStmtToIRBB(bb, IRStmt_Tmp(t1,
193 IRExpr_Binop(ex->Iex.Binop.op,
194 flatten_Expr(bb, ex->Iex.Binop.arg1),
195 flatten_Expr(bb, ex->Iex.Binop.arg2))));
196 return IRExpr_Tmp(t1);
197
198 case Iex_Unop:
199 t1 = newIRTemp(bb->tyenv, ty);
200 addStmtToIRBB(bb, IRStmt_Tmp(t1,
201 IRExpr_Unop(ex->Iex.Unop.op,
202 flatten_Expr(bb, ex->Iex.Unop.arg))));
203 return IRExpr_Tmp(t1);
204
205 case Iex_LDle:
206 t1 = newIRTemp(bb->tyenv, ty);
207 addStmtToIRBB(bb, IRStmt_Tmp(t1,
208 IRExpr_LDle(ex->Iex.LDle.ty,
209 flatten_Expr(bb, ex->Iex.LDle.addr))));
210 return IRExpr_Tmp(t1);
211
212 case Iex_CCall:
213 newargs = copyIexCCallArgs(ex->Iex.CCall.args);
214 for (i = 0; newargs[i]; i++)
215 newargs[i] = flatten_Expr(bb, newargs[i]);
216 t1 = newIRTemp(bb->tyenv, ty);
217 addStmtToIRBB(bb, IRStmt_Tmp(t1,
218 IRExpr_CCall(ex->Iex.CCall.name,
219 ex->Iex.CCall.retty,
220 newargs)));
221 return IRExpr_Tmp(t1);
222
223 case Iex_Mux0X:
224 t1 = newIRTemp(bb->tyenv, ty);
225 addStmtToIRBB(bb, IRStmt_Tmp(t1,
226 IRExpr_Mux0X(flatten_Expr(bb, ex->Iex.Mux0X.cond),
227 flatten_Expr(bb, ex->Iex.Mux0X.expr0),
228 flatten_Expr(bb, ex->Iex.Mux0X.exprX))));
229 return IRExpr_Tmp(t1);
230
231 case Iex_Const:
232 case Iex_Tmp:
233 return ex;
234
235 default:
236 vex_printf("\n");
237 ppIRExpr(ex);
238 vex_printf("\n");
239 vpanic("flatten_Expr");
240 }
241}
242
243
244/* Append a completely flattened form of 'st' to the end of 'bb'. */
245
246static void flatten_Stmt ( IRBB* bb, IRStmt* st )
247{
248 IRExpr *e1, *e2;
249 switch (st->tag) {
250 case Ist_Put:
251 e1 = flatten_Expr(bb, st->Ist.Put.expr);
252 addStmtToIRBB(bb, IRStmt_Put(st->Ist.Put.offset, e1));
253 break;
sewardjd7cb8532004-08-17 23:59:23 +0000254 case Ist_PutI:
sewardjd7217032004-08-19 10:49:10 +0000255 e1 = flatten_Expr(bb, st->Ist.PutI.offset);
256 e2 = flatten_Expr(bb, st->Ist.PutI.expr);
257 addStmtToIRBB(bb, IRStmt_PutI(e1, e2,
258 st->Ist.PutI.minoff,
259 st->Ist.PutI.maxoff));
260 break;
sewardjd7cb8532004-08-17 23:59:23 +0000261 case Ist_Tmp:
262 e1 = flatten_Expr(bb, st->Ist.Tmp.expr);
263 addStmtToIRBB(bb, IRStmt_Tmp(st->Ist.Tmp.tmp, e1));
264 break;
265 case Ist_STle:
266 e1 = flatten_Expr(bb, st->Ist.STle.addr);
267 e2 = flatten_Expr(bb, st->Ist.STle.data);
268 addStmtToIRBB(bb, IRStmt_STle(e1,e2));
269 break;
270 case Ist_Exit:
271 e1 = flatten_Expr(bb, st->Ist.Exit.cond);
272 addStmtToIRBB(bb, IRStmt_Exit(e1, st->Ist.Exit.dst));
273 break;
274 default:
275 vex_printf("\n");
276 ppIRStmt(st);
277 vex_printf("\n");
278 vpanic("flatten_Stmt");
279 }
280}
281
282static IRBB* flatten_BB ( IRBB* in )
283{
284 Int i;
285 IRBB* out;
286 out = emptyIRBB();
287 out->tyenv = copyIRTypeEnv( in->tyenv );
288 for (i = 0; i < in->stmts_used; i++)
289 flatten_Stmt( out, in->stmts[i] );
290 out->next = flatten_Expr( out, in->next );
291 out->jumpkind = in->jumpkind;
292 return out;
293}
294
sewardjedf4d692004-08-17 13:52:58 +0000295
sewardj84be7372004-08-18 13:59:33 +0000296
297/*---------------------------------------------------------------*/
298/*--- Constant propagation and folding ---*/
299/*---------------------------------------------------------------*/
300
sewardjf6501992004-08-27 11:58:24 +0000301/* The env in this section is a map from IRTemp to IRExpr*. */
302
sewardjf6729012004-08-25 12:45:13 +0000303/* Are both expressions simply the same IRTemp ? */
304static Bool sameIRTemps ( IRExpr* e1, IRExpr* e2 )
305{
306 return e1->tag == Iex_Tmp
307 && e2->tag == Iex_Tmp
308 && e1->Iex.Tmp.tmp == e2->Iex.Tmp.tmp;
309}
310
sewardj84be7372004-08-18 13:59:33 +0000311static IRExpr* fold_Expr ( IRExpr* e )
312{
sewardj278c44c2004-08-20 00:28:13 +0000313 Int shift;
sewardj84be7372004-08-18 13:59:33 +0000314 IRExpr* e2 = e; /* e2 is the result of folding e, if possible */
315
316 /* UNARY ops */
317 if (e->tag == Iex_Unop
318 && e->Iex.Unop.arg->tag == Iex_Const) {
319 switch (e->Iex.Unop.op) {
320 case Iop_8Uto32:
321 e2 = IRExpr_Const(IRConst_U32(
322 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
323 break;
324 case Iop_16Uto32:
325 e2 = IRExpr_Const(IRConst_U32(
326 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
327 break;
328 default:
329 goto unhandled;
330 }
331 }
332
333 /* BINARY ops */
334 if (e->tag == Iex_Binop) {
335 if (e->Iex.Binop.arg1->tag == Iex_Const
336 && e->Iex.Binop.arg2->tag == Iex_Const) {
337 /* cases where both args are consts */
338 switch (e->Iex.Binop.op) {
339 case Iop_And8:
340 e2 = IRExpr_Const(IRConst_U8(0xFF &
341 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
342 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)));
343 break;
344 case Iop_Sub8:
345 e2 = IRExpr_Const(IRConst_U8(0xFF &
346 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
347 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)));
348 break;
sewardjd7217032004-08-19 10:49:10 +0000349 case Iop_Sub32:
350 e2 = IRExpr_Const(IRConst_U32(
351 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
352 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
353 break;
354 case Iop_Add32:
355 e2 = IRExpr_Const(IRConst_U32(
356 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
357 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
358 break;
359 case Iop_And32:
360 e2 = IRExpr_Const(IRConst_U32(
361 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
362 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
363 break;
sewardjb8e75862004-08-19 17:58:45 +0000364 case Iop_Or32:
365 e2 = IRExpr_Const(IRConst_U32(
366 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
367 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
368 break;
sewardjb9c5cf62004-08-24 15:10:38 +0000369 case Iop_Mul32:
370 e2 = IRExpr_Const(IRConst_U32(
371 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
372 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
373 break;
sewardjd7217032004-08-19 10:49:10 +0000374 case Iop_Shl32:
sewardj61348472004-08-20 01:01:04 +0000375 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
376 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj29632392004-08-22 02:38:11 +0000377 if (shift >= 0 && shift <= 31)
sewardj278c44c2004-08-20 00:28:13 +0000378 e2 = IRExpr_Const(IRConst_U32(
379 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
380 << shift)));
sewardjd7217032004-08-19 10:49:10 +0000381 break;
sewardj278c44c2004-08-20 00:28:13 +0000382 case Iop_Sar32: {
383 /* paranoid ... */
384 /*signed*/ Int s32;
sewardj61348472004-08-20 01:01:04 +0000385 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj278c44c2004-08-20 00:28:13 +0000386 s32 = (Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +0000387 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj278c44c2004-08-20 00:28:13 +0000388 if (shift >= 0 && shift <= 31) {
389 s32 >>=/*signed*/ shift;
390 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
391 }
392 break;
393 }
sewardj61348472004-08-20 01:01:04 +0000394 case Iop_Shr32: {
395 /* paranoid ... */
396 /*unsigned*/ UInt s32;
397 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
398 s32 = (Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
399 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
400 if (shift >= 0 && shift <= 31) {
401 s32 >>=/*unsigned*/ shift;
402 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
403 }
404 break;
405 }
sewardjb8e75862004-08-19 17:58:45 +0000406 case Iop_CmpEQ32:
407 e2 = IRExpr_Const(IRConst_Bit(
408 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
409 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
410 break;
sewardj088bcb42004-08-19 17:16:52 +0000411 case Iop_32HLto64:
412 e2 = IRExpr_Const(IRConst_U64(
413 (((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)) << 32)
414 | ((ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))
415 ));
416 break;
sewardj84be7372004-08-18 13:59:33 +0000417 default:
418 goto unhandled;
sewardjd7217032004-08-19 10:49:10 +0000419 }
sewardjf6729012004-08-25 12:45:13 +0000420
sewardj84be7372004-08-18 13:59:33 +0000421 } else {
sewardjf6729012004-08-25 12:45:13 +0000422
sewardj84be7372004-08-18 13:59:33 +0000423 /* other cases (identities, etc) */
sewardjf6729012004-08-25 12:45:13 +0000424 /* Add32(x,0) ==> x */
sewardj84be7372004-08-18 13:59:33 +0000425 if (e->Iex.Binop.op == Iop_Add32
426 && e->Iex.Binop.arg2->tag == Iex_Const
427 && e->Iex.Binop.arg2->Iex.Const.con->Ico.U32 == 0) {
428 e2 = e->Iex.Binop.arg1;
sewardjf6729012004-08-25 12:45:13 +0000429 } else
430
431 /* And8/16/32(t,t) ==> t, for some IRTemp t */
432 if ((e->Iex.Binop.op == Iop_And32
433 || e->Iex.Binop.op == Iop_And16
434 || e->Iex.Binop.op == Iop_And8)
435 && sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
436 e2 = e->Iex.Binop.arg1;
437 }
438
sewardj84be7372004-08-18 13:59:33 +0000439 }
440 }
441
442 /* Mux0X */
443 if (e->tag == Iex_Mux0X
444 && e->Iex.Mux0X.cond->tag == Iex_Const) {
445 Bool zero;
446 /* assured us by the IR type rules */
447 vassert(e->Iex.Mux0X.cond->Iex.Const.con->tag == Ico_U8);
448 zero = 0 == e->Iex.Mux0X.cond->Iex.Const.con->Ico.U8;
449 e2 = zero ? e->Iex.Mux0X.expr0 : e->Iex.Mux0X.exprX;
450 }
451
sewardj088bcb42004-08-19 17:16:52 +0000452 if (DEBUG_IROPT && e2 != e) {
453 vex_printf("FOLD: ");
sewardj84be7372004-08-18 13:59:33 +0000454 ppIRExpr(e); vex_printf(" -> ");
455 ppIRExpr(e2); vex_printf("\n");
456 }
457
458 return e2;
459
460 unhandled:
461 vex_printf("\n\n");
462 ppIRExpr(e);
463 vpanic("fold_Expr: no rule for the above");
464}
465
466
467static Bool isAtom ( IRExpr* e )
468{
469 return e->tag == Iex_Tmp || e->tag == Iex_Const;
470}
471
472
473/* Apply the subst to a simple 1-level expression -- guaranteed to be
474 1-level due to previous flattening pass. */
475
476static IRExpr* subst_Expr ( Hash64* env, IRExpr* ex )
477{
478 if (ex->tag == Iex_Tmp) {
479 ULong res;
480 if (lookupH64(env, &res, (ULong)ex->Iex.Tmp.tmp)) {
481 return (IRExpr*)res;
482 } else {
483 /* not bound in env */
484 return ex;
485 }
486 }
487
488 if (ex->tag == Iex_Const)
489 return ex;
490 if (ex->tag == Iex_Get)
491 return ex;
492
sewardjd7217032004-08-19 10:49:10 +0000493 if (ex->tag == Iex_GetI) {
494 vassert(isAtom(ex->Iex.GetI.offset));
495 return IRExpr_GetI(
496 subst_Expr(env, ex->Iex.GetI.offset),
497 ex->Iex.GetI.ty,
498 ex->Iex.GetI.minoff,
499 ex->Iex.GetI.maxoff
500 );
501 }
502
sewardj84be7372004-08-18 13:59:33 +0000503 if (ex->tag == Iex_Binop) {
504 vassert(isAtom(ex->Iex.Binop.arg1));
505 vassert(isAtom(ex->Iex.Binop.arg2));
506 return IRExpr_Binop(
507 ex->Iex.Binop.op,
508 subst_Expr(env, ex->Iex.Binop.arg1),
509 subst_Expr(env, ex->Iex.Binop.arg2)
510 );
511 }
512
513 if (ex->tag == Iex_Unop) {
514 vassert(isAtom(ex->Iex.Unop.arg));
515 return IRExpr_Unop(
516 ex->Iex.Unop.op,
517 subst_Expr(env, ex->Iex.Unop.arg)
518 );
519 }
520
521 if (ex->tag == Iex_LDle) {
522 vassert(isAtom(ex->Iex.LDle.addr));
523 return IRExpr_LDle(
524 ex->Iex.LDle.ty,
525 subst_Expr(env, ex->Iex.LDle.addr)
526 );
527 }
528
529 if (ex->tag == Iex_CCall) {
530 Int i;
531 IRExpr** args2 = copyIexCCallArgs ( ex->Iex.CCall.args );
532 for (i = 0; args2[i]; i++) {
533 vassert(isAtom(args2[i]));
534 args2[i] = subst_Expr(env, args2[i]);
535 }
536 return IRExpr_CCall(
537 ex->Iex.CCall.name,
538 ex->Iex.CCall.retty,
539 args2
540 );
541 }
542
543 if (ex->tag == Iex_Mux0X) {
544 vassert(isAtom(ex->Iex.Mux0X.cond));
545 vassert(isAtom(ex->Iex.Mux0X.expr0));
546 vassert(isAtom(ex->Iex.Mux0X.exprX));
547 return IRExpr_Mux0X(
548 subst_Expr(env, ex->Iex.Mux0X.cond),
549 subst_Expr(env, ex->Iex.Mux0X.expr0),
550 subst_Expr(env, ex->Iex.Mux0X.exprX)
551 );
552 }
553
554 vex_printf("\n\n");
555 ppIRExpr(ex);
556 vpanic("subst_Expr");
557}
558
559
560/* Apply the subst to stmt, then fold the result as much as possible.
sewardjb8e75862004-08-19 17:58:45 +0000561 Much simplified due to stmt being previously flattened. Returning
562 NULL means the statement has been turned into a no-op. */
sewardj84be7372004-08-18 13:59:33 +0000563
564static IRStmt* subst_and_fold_Stmt ( Hash64* env, IRStmt* st )
565{
566# if 0
567 vex_printf("\nsubst and fold stmt\n");
568 ppIRStmt(st);
569 vex_printf("\n");
570# endif
571
572 if (st->tag == Ist_Put) {
573 vassert(isAtom(st->Ist.Put.expr));
574 return IRStmt_Put(
575 st->Ist.Put.offset,
576 fold_Expr(subst_Expr(env, st->Ist.Put.expr))
577 );
578 }
579
sewardjd7217032004-08-19 10:49:10 +0000580 if (st->tag == Ist_PutI) {
581 vassert(isAtom(st->Ist.PutI.offset));
582 vassert(isAtom(st->Ist.PutI.expr));
583 return IRStmt_PutI(
584 fold_Expr(subst_Expr(env, st->Ist.PutI.offset)),
585 fold_Expr(subst_Expr(env, st->Ist.PutI.expr)),
586 st->Ist.PutI.minoff,
587 st->Ist.PutI.maxoff
588 );
589 }
590
sewardj84be7372004-08-18 13:59:33 +0000591 if (st->tag == Ist_Tmp) {
592 /* This is the one place where an expr (st->Ist.Tmp.expr) is
593 allowed to be more than just a constant or a tmp. */
594 return IRStmt_Tmp(
595 st->Ist.Tmp.tmp,
596 fold_Expr(subst_Expr(env, st->Ist.Tmp.expr))
597 );
598 }
599
600 if (st->tag == Ist_STle) {
601 vassert(isAtom(st->Ist.STle.addr));
602 vassert(isAtom(st->Ist.STle.data));
603 return IRStmt_STle(
604 fold_Expr(subst_Expr(env, st->Ist.STle.addr)),
605 fold_Expr(subst_Expr(env, st->Ist.STle.data))
606 );
607 }
608
609 if (st->tag == Ist_Exit) {
sewardjb8e75862004-08-19 17:58:45 +0000610 IRExpr* fcond;
611 vassert(isAtom(st->Ist.Exit.cond));
612 fcond = fold_Expr(subst_Expr(env, st->Ist.Exit.cond));
613 if (fcond->tag == Iex_Const) {
614 /* Interesting. The condition on this exit has folded down to
615 a constant. */
616 vassert(fcond->Iex.Const.con->tag == Ico_Bit);
617 if (fcond->Iex.Const.con->Ico.Bit == False) {
618 /* exit is never going to happen, so dump the statement. */
619 return NULL;
620 } else {
621 vassert(fcond->Iex.Const.con->Ico.Bit == True);
622 /* Hmmm. The exit has become unconditional. Leave it as
623 it is for now, since we'd have to truncate the BB at
624 this point, which is tricky. */
625 /* fall out into the reconstruct-the-exit code. */
sewardj29632392004-08-22 02:38:11 +0000626 vex_printf("subst_and_fold_Stmt: IRStmt_Exit became unconditional\n");
sewardjb8e75862004-08-19 17:58:45 +0000627 }
628 }
629 return IRStmt_Exit(fcond,st->Ist.Exit.dst);
sewardj84be7372004-08-18 13:59:33 +0000630 }
631
632 vex_printf("\n");
633 ppIRStmt(st);
634 vpanic("subst_and_fold_Stmt");
635}
636
637
638static IRBB* cprop_BB ( IRBB* in )
639{
640 Int i;
641 IRBB* out;
642 Hash64* env;
643 IRStmt* st2;
644
645 out = emptyIRBB();
646 out->tyenv = copyIRTypeEnv( in->tyenv );
647
648 /* Set up the env with which travels forward. This holds a
649 substitution, mapping IRTemps to atoms, that is, IRExprs which
650 are either IRTemps or IRConsts. Thus, copy and constant
651 propagation is done. The environment is to be applied as we
652 move along. Keys are IRTemps. Values are IRExpr*s.
653 */
654 env = newH64();
655
656 /* For each original SSA-form stmt ... */
657 for (i = 0; i < in->stmts_used; i++) {
658
659 /* First apply the substitution to the current stmt. This
660 propagates in any constants and tmp-tmp assignments
661 accumulated prior to this point. As part of the subst_Stmt
662 call, also then fold any constant expressions resulting. */
663
sewardjf0e43162004-08-20 00:11:12 +0000664 st2 = in->stmts[i];
665
666 /* perhaps st2 is already a no-op? */
667 if (!st2) continue;
668
669 st2 = subst_and_fold_Stmt( env, st2 );
sewardj84be7372004-08-18 13:59:33 +0000670
sewardjb8e75862004-08-19 17:58:45 +0000671 /* If the statement has been folded into a no-op, forget it. */
sewardjf0e43162004-08-20 00:11:12 +0000672 if (!st2) continue;
sewardjb8e75862004-08-19 17:58:45 +0000673
sewardj84be7372004-08-18 13:59:33 +0000674 /* Now consider what the stmt looks like. If it's of the form
675 't = const' or 't1 = t2', add it to the running environment
676 and not to the output BB. Otherwise, add it to the output
677 BB. */
678
679 if (st2->tag == Ist_Tmp && st2->Ist.Tmp.expr->tag == Iex_Const) {
680 /* 't = const' -- add to env.
681 The pair (IRTemp, IRExpr*) is added. */
682 addToH64(env, (ULong)(st2->Ist.Tmp.tmp),
683 (ULong)(st2->Ist.Tmp.expr) );
684 }
685 else
686 if (st2->tag == Ist_Tmp && st2->Ist.Tmp.expr->tag == Iex_Tmp) {
687 /* 't1 = t2' -- add to env.
688 The pair (IRTemp, IRExpr*) is added. */
689 addToH64(env, (ULong)(st2->Ist.Tmp.tmp),
690 (ULong)(st2->Ist.Tmp.expr) );
691 }
692 else {
693 /* Not interesting, copy st2 into the output block. */
694 addStmtToIRBB( out, st2 );
695 }
696 }
697
sewardj84be7372004-08-18 13:59:33 +0000698 out->next = subst_Expr( env, in->next );
699 out->jumpkind = in->jumpkind;
700 return out;
701}
702
703
704
sewardjedf4d692004-08-17 13:52:58 +0000705/*---------------------------------------------------------------*/
sewardj39e3f242004-08-18 16:54:52 +0000706/*--- Dead code (t = E) removal ---*/
707/*---------------------------------------------------------------*/
708
709/* The type of the Hash64 map is: a map from IRTemp to nothing
710 -- really just operating a set or IRTemps.
711*/
712
713static void addUses_Expr ( Hash64* set, IRExpr* e )
714{
715 Int i;
716 switch (e->tag) {
sewardjd7217032004-08-19 10:49:10 +0000717 case Iex_GetI:
718 addUses_Expr(set, e->Iex.GetI.offset);
719 return;
sewardj39e3f242004-08-18 16:54:52 +0000720 case Iex_Mux0X:
721 addUses_Expr(set, e->Iex.Mux0X.cond);
722 addUses_Expr(set, e->Iex.Mux0X.expr0);
723 addUses_Expr(set, e->Iex.Mux0X.exprX);
724 return;
725 case Iex_CCall:
726 for (i = 0; e->Iex.CCall.args[i]; i++)
727 addUses_Expr(set, e->Iex.CCall.args[i]);
728 return;
729 case Iex_LDle:
730 addUses_Expr(set, e->Iex.LDle.addr);
731 return;
732 case Iex_Binop:
733 addUses_Expr(set, e->Iex.Binop.arg1);
734 addUses_Expr(set, e->Iex.Binop.arg2);
735 return;
736 case Iex_Unop:
737 addUses_Expr(set, e->Iex.Unop.arg);
738 return;
739 case Iex_Tmp:
740 addToH64(set, (ULong)(e->Iex.Tmp.tmp), 0);
741 return;
742 case Iex_Const:
743 case Iex_Get:
744 return;
745 default:
746 vex_printf("\n");
747 ppIRExpr(e);
748 vpanic("addUses_Expr");
749 }
750}
751
752static void addUses_Stmt ( Hash64* set, IRStmt* st )
753{
754 switch (st->tag) {
sewardjd7217032004-08-19 10:49:10 +0000755 case Ist_PutI:
756 addUses_Expr(set, st->Ist.PutI.offset);
757 addUses_Expr(set, st->Ist.PutI.expr);
758 return;
sewardj39e3f242004-08-18 16:54:52 +0000759 case Ist_Exit:
760 addUses_Expr(set, st->Ist.Exit.cond);
761 return;
762 case Ist_Tmp:
763 addUses_Expr(set, st->Ist.Tmp.expr);
764 return;
765 case Ist_Put:
766 addUses_Expr(set, st->Ist.Put.expr);
767 return;
768 case Ist_STle:
769 addUses_Expr(set, st->Ist.STle.addr);
770 addUses_Expr(set, st->Ist.STle.data);
771 return;
772 default:
773 vex_printf("\n");
774 ppIRStmt(st);
775 vpanic("addUses_Stmt");
776 }
777}
778
779
780
781/* Note, this destructively modifies the given IRBB. */
782
783/* Scan backwards through statements, carrying a set of IRTemps which
784 are known to be used after the current point. On encountering 't =
785 E', delete the binding if it is not used. Otherwise, add any temp
786 uses to the set and keep on moving backwards. */
787
sewardjd7217032004-08-19 10:49:10 +0000788static void dead_BB ( IRBB* bb )
sewardj39e3f242004-08-18 16:54:52 +0000789{
790 Int i;
791 Hash64* set = newH64();
792 IRStmt* st;
793
794 /* start off by recording IRTemp uses in the next field. */
795 addUses_Expr(set, bb->next);
796
797 /* Work backwards through the stmts */
798 for (i = bb->stmts_used-1; i >= 0; i--) {
799 st = bb->stmts[i];
sewardj84ff0652004-08-23 16:16:08 +0000800 if (!st)
801 continue;
sewardj39e3f242004-08-18 16:54:52 +0000802 if (st->tag == Ist_Tmp
803 && !lookupH64(set, NULL, (ULong)(st->Ist.Tmp.tmp))) {
804 /* it's an IRTemp which never got used. Delete it. */
sewardj088bcb42004-08-19 17:16:52 +0000805 if (DEBUG_IROPT) {
sewardj39e3f242004-08-18 16:54:52 +0000806 vex_printf("DEAD: ");
807 ppIRStmt(st);
808 vex_printf("\n");
809 }
810 bb->stmts[i] = NULL;
811 } else {
812 /* Note any IRTemp uses made by the current statement. */
813 addUses_Stmt(set, st);
814 }
815 }
816}
817
818
819/*---------------------------------------------------------------*/
sewardjd7217032004-08-19 10:49:10 +0000820/*--- In-place removal of redundant GETs ---*/
821/*---------------------------------------------------------------*/
822
sewardjf0e43162004-08-20 00:11:12 +0000823/* Scan forwards, building up an environment binding (min offset, max
824 offset) pairs to values, which will either be temps or constants.
sewardjd7217032004-08-19 10:49:10 +0000825
sewardjf0e43162004-08-20 00:11:12 +0000826 On seeing 't = Get(minoff,maxoff)', look up (minoff,maxoff) in the
sewardj29632392004-08-22 02:38:11 +0000827 env and if it matches, replace the Get with the stored value. If
828 there is no match, add a (minoff,maxoff) :-> t binding.
sewardjd7217032004-08-19 10:49:10 +0000829
sewardjf0e43162004-08-20 00:11:12 +0000830 On seeing 'Put (minoff,maxoff) = t or c', first remove in the env
831 any binding which fully or partially overlaps with (minoff,maxoff).
832 Then add a new (minoff,maxoff) :-> t or c binding. */
sewardjd7217032004-08-19 10:49:10 +0000833
834/* Create keys, of the form ((minoffset << 16) | maxoffset). */
835
836static UInt mk_key_GetPut ( Int offset, IRType ty )
837{
838 /* offset should fit in 16 bits. */
839 UInt minoff = offset;
840 UInt maxoff = minoff + sizeofIRType(ty) - 1;
841 vassert((minoff & 0xFFFF0000) == 0);
842 vassert((maxoff & 0xFFFF0000) == 0);
843 return (minoff << 16) | maxoff;
844}
845
846static UInt mk_key_GetIPutI ( UShort minoff16, UShort maxoff16 )
847{
848 UInt minoff = (UInt)minoff16;
849 UInt maxoff = (UInt)maxoff16;
850 return (minoff << 16) | maxoff;
851}
852
sewardjf0e43162004-08-20 00:11:12 +0000853/* Supposing h has keys of the form generated by mk_key_GetPut and
854 mk_key_GetIPutI, invalidate any key which overlaps (k_lo
855 .. k_hi).
856*/
857
858static void invalidateOverlaps ( Hash64* h, UInt k_lo, UInt k_hi )
859{
860 Int j;
861 UInt e_lo, e_hi;
862 vassert(k_lo <= k_hi);
863 /* invalidate any env entries which in any way overlap (k_lo
864 .. k_hi) */
sewardj29632392004-08-22 02:38:11 +0000865 /* vex_printf("invalidate %d .. %d\n", k_lo, k_hi ); */
866
sewardjf0e43162004-08-20 00:11:12 +0000867 for (j = 0; j < h->used; j++) {
868 if (!h->inuse[j])
869 continue;
870 e_lo = (((UInt)h->key[j]) >> 16) & 0xFFFF;
871 e_hi = ((UInt)h->key[j]) & 0xFFFF;
872 vassert(e_lo <= e_hi);
873 if (e_hi < k_lo || k_hi < e_lo)
874 continue; /* no overlap possible */
875 else
876 /* overlap; invalidate */
877 h->inuse[j] = False;
878 }
879}
880
sewardjd7217032004-08-19 10:49:10 +0000881
882static void redundant_get_removal_BB ( IRBB* bb )
883{
884 Hash64* env = newH64();
sewardj088bcb42004-08-19 17:16:52 +0000885 UInt key;
sewardjf0e43162004-08-20 00:11:12 +0000886 Int i;
sewardj088bcb42004-08-19 17:16:52 +0000887 Bool isPut;
sewardjf0e43162004-08-20 00:11:12 +0000888 ULong val;
sewardjd7217032004-08-19 10:49:10 +0000889
890 for (i = 0; i < bb->stmts_used; i++) {
891 IRStmt* st = bb->stmts[i];
892
893 if (!st)
894 continue;
895
896 /* Deal with Gets */
897 if (st->tag == Ist_Tmp
898 && st->Ist.Tmp.expr->tag == Iex_Get) {
899 /* st is 't = Get(...)'. Look up in the environment and see
900 if the Get can be replaced. */
sewardjd7217032004-08-19 10:49:10 +0000901 IRExpr* get = st->Ist.Tmp.expr;
902 key = (ULong)mk_key_GetPut( get->Iex.Get.offset,
903 get->Iex.Get.ty );
904 if (lookupH64(env, &val, (ULong)key)) {
905 /* found it */
sewardj088bcb42004-08-19 17:16:52 +0000906 if (DEBUG_IROPT) {
sewardjd7217032004-08-19 10:49:10 +0000907 vex_printf("rGET: "); ppIRExpr(get);
908 vex_printf(" -> "); ppIRExpr((IRExpr*)val);
909 vex_printf("\n");
sewardj29632392004-08-22 02:38:11 +0000910 }
sewardjd7217032004-08-19 10:49:10 +0000911 bb->stmts[i] = IRStmt_Tmp(st->Ist.Tmp.tmp,
912 (IRExpr*)val);
sewardj29632392004-08-22 02:38:11 +0000913 } else {
914 /* Not found, but at least we know that t and the Get(...)
915 are now associated. So add a binding to reflect that
916 fact. */
917 addToH64( env, (ULong)key,
918 (ULong)(IRExpr_Tmp(st->Ist.Tmp.tmp)) );
sewardjd7217032004-08-19 10:49:10 +0000919 }
920 }
921
922 /* Deal with Puts */
923 switch (st->tag) {
924 case Ist_Put:
925 isPut = True;
926 key = mk_key_GetPut( st->Ist.Put.offset,
927 typeOfIRExpr(bb->tyenv,st->Ist.Put.expr) );
928 break;
929 case Ist_PutI:
930 isPut = True;
931 key = mk_key_GetIPutI( st->Ist.PutI.minoff,
932 st->Ist.PutI.maxoff );
933 break;
934 default:
935 isPut = False;
936 }
937
938 /* invalidate any env entries overlapped by this Put */
939 if (isPut) {
sewardjf0e43162004-08-20 00:11:12 +0000940 UInt k_lo, k_hi;
sewardjd7217032004-08-19 10:49:10 +0000941 k_lo = (key >> 16) & 0xFFFF;
942 k_hi = key & 0xFFFF;
sewardjf0e43162004-08-20 00:11:12 +0000943 invalidateOverlaps(env, k_lo, k_hi);
sewardjd7217032004-08-19 10:49:10 +0000944 }
945
946 /* add this one to the env, if appropriate */
947 if (st->tag == Ist_Put) {
948 vassert(isAtom(st->Ist.Put.expr));
949 addToH64( env, (ULong)key, (ULong)(st->Ist.Put.expr));
950 }
951
952 } /* for (i = 0; i < bb->stmts_used; i++) */
953
954}
955
956
957/*---------------------------------------------------------------*/
sewardjf0e43162004-08-20 00:11:12 +0000958/*--- In-place removal of redundant PUTs ---*/
959/*---------------------------------------------------------------*/
960
961/* Find any Get uses in st and invalidate any partially or fully
962 overlapping ranges listed in env. Due to the flattening phase, the
963 only stmt kind we expect to find a Get on is IRStmt_Tmp. */
964
965static void handle_gets_Stmt ( Hash64* env, IRStmt* st )
966{
967 UInt key;
968 Bool isGet;
969 IRExpr* e;
970 switch (st->tag) {
971
972 /* This is the only interesting case. Deal with Gets in the RHS
973 expression. */
974 case Ist_Tmp:
975 e = st->Ist.Tmp.expr;
976 switch (e->tag) {
977 case Iex_Get:
978 isGet = True;
979 key = mk_key_GetPut ( e->Iex.Get.offset, e->Iex.Get.ty );
980 break;
981 case Iex_GetI:
982 isGet = True;
983 key = mk_key_GetIPutI ( e->Iex.GetI.minoff, e->Iex.GetI.maxoff );
984 break;
985 default:
986 isGet = False;
987 }
988 if (isGet) {
989 UInt k_lo, k_hi;
990 k_lo = (key >> 16) & 0xFFFF;
991 k_hi = key & 0xFFFF;
992 invalidateOverlaps(env, k_lo, k_hi);
993 }
994 break;
995
996 /* all other cases are boring. */
997 case Ist_STle:
998 vassert(isAtom(st->Ist.STle.addr));
999 vassert(isAtom(st->Ist.STle.data));
1000 return;
1001
1002 case Ist_Exit:
1003 vassert(isAtom(st->Ist.Exit.cond));
1004 return;
1005
1006 default:
1007 vex_printf("\n");
1008 ppIRStmt(st);
1009 vex_printf("\n");
1010 vpanic("handle_gets_Stmt");
1011 }
1012}
1013
1014
1015/* Scan backwards, building up a set of (min offset, max
1016 offset) pairs, indicating those parts of the guest state
1017 for which the next event is a write.
1018
1019 On seeing a conditional exit, empty the set.
1020
1021 On seeing 'Put (minoff,maxoff) = t or c', if (minoff,maxoff) is
1022 completely within the set, remove the Put. Otherwise, add
1023 (minoff,maxoff) to the set.
1024
1025 On seeing 'Get (minoff,maxoff)', remove any part of the set
1026 overlapping (minoff,maxoff).
1027*/
1028
1029static void redundant_put_removal_BB ( IRBB* bb )
1030{
1031 Int i, j;
1032 Bool isPut;
1033 IRStmt* st;
1034 UInt key;
1035
1036 Hash64* env = newH64();
1037 for (i = bb->stmts_used-1; i >= 0; i--) {
1038 st = bb->stmts[i];
1039
1040 /* Deal with conditional exits. */
1041 if (st->tag == Ist_Exit) {
1042 /* Since control may not get beyond this point, we must empty
1043 out the set, since we can no longer claim that the next
1044 event for any part of the guest state is definitely a
1045 write. */
1046 vassert(isAtom(st->Ist.Exit.cond));
1047 for (j = 0; j < env->used; j++)
1048 env->inuse[j] = False;
1049 continue;
1050 }
1051
1052 /* Deal with Puts */
1053 switch (st->tag) {
1054 case Ist_Put:
1055 isPut = True;
1056 key = mk_key_GetPut( st->Ist.Put.offset,
1057 typeOfIRExpr(bb->tyenv,st->Ist.Put.expr) );
1058 vassert(isAtom(st->Ist.Put.expr));
1059 break;
1060 case Ist_PutI:
1061 isPut = True;
1062 key = mk_key_GetIPutI( st->Ist.PutI.minoff,
1063 st->Ist.PutI.maxoff );
1064 vassert(isAtom(st->Ist.PutI.expr));
1065 break;
1066 default:
1067 isPut = False;
1068 }
1069 if (isPut) {
1070 /* See if any single entry in env overlaps this Put. This is
1071 simplistic in that the transformation is valid if, say, two
1072 or more entries in the env overlap this Put, but the use of
1073 lookupH64 will only find a single entry which exactly
1074 overlaps this Put. This is suboptimal but safe. */
1075 if (lookupH64(env, NULL, (ULong)key)) {
1076 /* This Put is redundant because a later one will overwrite
1077 it. So NULL (nop) it out. */
1078 if (DEBUG_IROPT) {
1079 vex_printf("rPUT: "); ppIRStmt(st);
1080 vex_printf("\n");
sewardj29632392004-08-22 02:38:11 +00001081 }
sewardjf0e43162004-08-20 00:11:12 +00001082 bb->stmts[i] = NULL;
1083 } else {
1084 /* We can't demonstrate that this Put is redundant, so add it
1085 to the running collection. */
1086 addToH64(env, (ULong)key, 0);
1087 }
1088 continue;
1089 }
1090
1091 /* Deal with Gets. These remove bits of the environment since
1092 appearance of a Get means that the next event for that slice
1093 of the guest state is no longer a write, but a read. */
1094 handle_gets_Stmt( env, st );
1095 }
1096}
1097
1098
sewardj84ff0652004-08-23 16:16:08 +00001099/*---------------------------------------------------------------*/
1100/*--- Specialisation of helper function calls, in ---*/
1101/*--- collaboration with the front end ---*/
1102/*---------------------------------------------------------------*/
1103
1104static
1105void spec_helpers_BB ( IRBB* bb,
1106 IRExpr* (*specHelper) ( Char*, IRExpr**) )
1107{
1108 Int i;
1109 IRStmt* st;
1110 IRExpr* ex;
1111
1112 for (i = bb->stmts_used-1; i >= 0; i--) {
1113 st = bb->stmts[i];
1114
1115 if (!st
1116 || st->tag != Ist_Tmp
1117 || st->Ist.Tmp.expr->tag != Iex_CCall)
1118 continue;
1119
1120 ex = (*specHelper)( st->Ist.Tmp.expr->Iex.CCall.name,
1121 st->Ist.Tmp.expr->Iex.CCall.args );
1122 if (!ex)
1123 /* the front end can't think of a suitable replacement */
1124 continue;
1125
1126 /* We got something better. Install it in the bb. */
1127 bb->stmts[i]
1128 = IRStmt_Tmp(st->Ist.Tmp.tmp, ex);
1129
1130 if (0) {
1131 vex_printf("SPEC: ");
1132 ppIRExpr(st->Ist.Tmp.expr);
1133 vex_printf(" --> ");
1134 ppIRExpr(ex);
1135 vex_printf("\n");
1136 }
1137 }
1138}
1139
sewardj29632392004-08-22 02:38:11 +00001140
1141/*---------------------------------------------------------------*/
1142/*--- The tree builder ---*/
1143/*---------------------------------------------------------------*/
1144
1145typedef
1146 struct {
1147 Int occ; /* occurrence count for this tmp */
sewardj84ff0652004-08-23 16:16:08 +00001148 IRExpr* expr; /* expr it is bound to,
1149 or NULL if already 'used' */
sewardj29632392004-08-22 02:38:11 +00001150 Bool eDoesLoad; /* True <=> expr reads mem */
1151 Bool eDoesGet; /* True <=> expr reads guest state */
1152 Bool invalidateMe; /* used when dumping bindings */
1153 Int origPos; /* posn of the binder in the original bb */
1154 }
1155 TmpInfo;
1156
1157/* Given env :: IRTemp -> TmpInfo*
1158 Add the use-occurrences of temps in this expression
1159 to the environment.
1160*/
1161static void occCount_Expr ( Hash64* env, IRExpr* e )
1162{
1163 Int i;
1164 TmpInfo* ti;
1165 ULong res;
1166
1167 switch (e->tag) {
1168
1169 case Iex_Tmp: /* the only interesting case */
1170 if (lookupH64(env, &res, (ULong)(e->Iex.Tmp.tmp))) {
1171 ti = (TmpInfo*)res;
1172 ti->occ++;
1173 } else {
1174 ti = LibVEX_Alloc(sizeof(TmpInfo));
1175 ti->occ = 1;
1176 ti->expr = NULL;
1177 ti->eDoesLoad = False;
1178 ti->eDoesGet = False;
1179 ti->invalidateMe = False;
1180 ti->origPos = -1; /* filed in properly later */
1181 addToH64(env, (ULong)(e->Iex.Tmp.tmp), (ULong)ti );
1182 }
1183 return;
1184
1185 case Iex_Mux0X:
1186 occCount_Expr(env, e->Iex.Mux0X.cond);
1187 occCount_Expr(env, e->Iex.Mux0X.expr0);
1188 occCount_Expr(env, e->Iex.Mux0X.exprX);
1189 return;
1190
1191 case Iex_Binop:
1192 occCount_Expr(env, e->Iex.Binop.arg1);
1193 occCount_Expr(env, e->Iex.Binop.arg2);
1194 return;
1195
1196 case Iex_Unop:
1197 occCount_Expr(env, e->Iex.Unop.arg);
1198 return;
1199
1200 case Iex_LDle:
1201 occCount_Expr(env, e->Iex.LDle.addr);
1202 return;
1203
1204 case Iex_CCall:
1205 for (i = 0; e->Iex.CCall.args[i]; i++)
1206 occCount_Expr(env, e->Iex.CCall.args[i]);
1207 return;
1208
sewardjf6501992004-08-27 11:58:24 +00001209 case Iex_GetI:
1210 occCount_Expr(env, e->Iex.GetI.offset);
1211 return;
1212
sewardj29632392004-08-22 02:38:11 +00001213 case Iex_Const:
1214 case Iex_Get:
1215 return;
1216
1217 default:
1218 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1219 vpanic("occCount_Expr");
1220 }
1221}
1222
1223
1224/* Given env :: IRTemp -> TmpInfo*
1225 Add the use-occurrences of temps in this expression
1226 to the environment.
1227*/
1228static void occCount_Stmt ( Hash64* env, IRStmt* st )
1229{
1230 switch (st->tag) {
1231 case Ist_Tmp:
1232 occCount_Expr(env, st->Ist.Tmp.expr);
1233 return;
1234 case Ist_Put:
1235 occCount_Expr(env, st->Ist.Put.expr);
1236 return;
sewardjf6501992004-08-27 11:58:24 +00001237 case Ist_PutI:
1238 occCount_Expr(env, st->Ist.PutI.offset);
1239 occCount_Expr(env, st->Ist.PutI.expr);
1240 return;
sewardj29632392004-08-22 02:38:11 +00001241 case Ist_STle:
1242 occCount_Expr(env, st->Ist.STle.addr);
1243 occCount_Expr(env, st->Ist.STle.data);
1244 return;
1245 case Ist_Exit:
1246 occCount_Expr(env, st->Ist.Exit.cond);
1247 return;
1248 default:
1249 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
1250 vpanic("occCount_Stmt");
1251 }
1252}
1253
1254
1255/* Traverse e, looking for temps. For each observed temp, see if env
1256 contains a binding for the temp, and if so return the bound value.
1257 The env has the property that any binding it holds is
1258 'single-shot', so once a binding is used, it is marked as no longer
1259 available, by setting its .expr field to NULL. */
1260
1261static IRExpr* tbSubst_Expr ( Hash64* env, IRExpr* e )
1262{
sewardjc41f1fb2004-08-22 09:48:08 +00001263 TmpInfo* ti;
1264 ULong res;
1265 IRExpr* e2;
1266 IRExpr** args2;
1267 Int i;
sewardj29632392004-08-22 02:38:11 +00001268
1269 switch (e->tag) {
1270
sewardjc41f1fb2004-08-22 09:48:08 +00001271 case Iex_CCall:
1272 args2 = copyIexCCallArgs(e->Iex.CCall.args);
1273 for (i = 0; args2[i]; i++)
1274 args2[i] = tbSubst_Expr(env,args2[i]);
1275 return IRExpr_CCall(e->Iex.CCall.name,
1276 e->Iex.CCall.retty,
1277 args2
1278 );
sewardj29632392004-08-22 02:38:11 +00001279 case Iex_Tmp:
sewardjc41f1fb2004-08-22 09:48:08 +00001280 if (lookupH64(env, &res, (ULong)(e->Iex.Tmp.tmp))) {
1281 ti = (TmpInfo*)res;
1282 e2 = ti->expr;
1283 if (e2) {
1284 ti->expr = NULL;
1285 return e2;
1286 } else {
1287 return e;
1288 }
1289 } else {
1290 return e;
1291 }
1292 case Iex_Mux0X:
1293 return IRExpr_Mux0X(
1294 tbSubst_Expr(env, e->Iex.Mux0X.cond),
1295 tbSubst_Expr(env, e->Iex.Mux0X.expr0),
1296 tbSubst_Expr(env, e->Iex.Mux0X.exprX)
1297 );
1298 case Iex_Binop:
1299 return IRExpr_Binop(
1300 e->Iex.Binop.op,
1301 tbSubst_Expr(env, e->Iex.Binop.arg1),
1302 tbSubst_Expr(env, e->Iex.Binop.arg2)
1303 );
1304 case Iex_Unop:
1305 return IRExpr_Unop(
1306 e->Iex.Unop.op,
1307 tbSubst_Expr(env, e->Iex.Unop.arg)
1308 );
1309 case Iex_LDle:
1310 return IRExpr_LDle(
1311 e->Iex.LDle.ty,
sewardjf6501992004-08-27 11:58:24 +00001312 tbSubst_Expr(env, e->Iex.LDle.addr)
sewardjc41f1fb2004-08-22 09:48:08 +00001313 );
sewardjf6501992004-08-27 11:58:24 +00001314 case Iex_GetI:
1315 return IRExpr_GetI(
1316 tbSubst_Expr(env, e->Iex.GetI.offset),
1317 e->Iex.GetI.ty,
1318 e->Iex.GetI.minoff,
1319 e->Iex.GetI.maxoff
1320 );
sewardjc41f1fb2004-08-22 09:48:08 +00001321 case Iex_Const:
sewardj29632392004-08-22 02:38:11 +00001322 case Iex_Get:
1323 return e;
1324 default:
1325 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1326 vpanic("tbSubst_Expr");
1327 }
1328}
1329
1330/* Same deal as tbSubst_Expr, except for stmts. */
1331
1332static IRStmt* tbSubst_Stmt ( Hash64* env, IRStmt* st )
1333{
1334 switch (st->tag) {
1335 case Ist_STle:
1336 return IRStmt_STle(
sewardjc41f1fb2004-08-22 09:48:08 +00001337 tbSubst_Expr(env, st->Ist.STle.addr),
1338 tbSubst_Expr(env, st->Ist.STle.data)
1339 );
sewardj29632392004-08-22 02:38:11 +00001340 case Ist_Tmp:
1341 return IRStmt_Tmp(
1342 st->Ist.Tmp.tmp,
1343 tbSubst_Expr(env, st->Ist.Tmp.expr)
1344 );
1345 case Ist_Put:
1346 return IRStmt_Put(
1347 st->Ist.Put.offset,
1348 tbSubst_Expr(env, st->Ist.Put.expr)
1349 );
sewardjf6501992004-08-27 11:58:24 +00001350 case Ist_PutI:
1351 return IRStmt_PutI(
1352 tbSubst_Expr(env, st->Ist.PutI.offset),
1353 tbSubst_Expr(env, st->Ist.PutI.expr),
1354 st->Ist.PutI.minoff,
1355 st->Ist.PutI.maxoff
1356 );
1357
sewardj29632392004-08-22 02:38:11 +00001358 case Ist_Exit:
1359 return IRStmt_Exit(
1360 tbSubst_Expr(env, st->Ist.Exit.cond),
1361 st->Ist.Exit.dst
1362 );
1363 default:
1364 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
1365 vpanic("tbSubst_Stmt");
1366 }
1367}
1368
1369
sewardj37d38012004-08-24 00:37:04 +00001370/* Traverse an expr, and detect if any part of it reads memory or does
1371 a Get. Be careful ... this really controls how much the
1372 tree-builder can reorder the code, so getting it right is critical.
1373*/
sewardj29632392004-08-22 02:38:11 +00001374static void setHints_Expr (Bool* doesLoad, Bool* doesGet, IRExpr* e )
1375{
sewardjc41f1fb2004-08-22 09:48:08 +00001376 Int i;
sewardj29632392004-08-22 02:38:11 +00001377 switch (e->tag) {
sewardjc41f1fb2004-08-22 09:48:08 +00001378 case Iex_CCall:
1379 for (i = 0; e->Iex.CCall.args[i]; i++)
1380 setHints_Expr(doesLoad, doesGet, e->Iex.CCall.args[i]);
1381 return;
1382 case Iex_Mux0X:
1383 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.cond);
1384 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.expr0);
1385 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.exprX);
1386 return;
1387 case Iex_Binop:
1388 setHints_Expr(doesLoad, doesGet, e->Iex.Binop.arg1);
1389 setHints_Expr(doesLoad, doesGet, e->Iex.Binop.arg2);
1390 return;
1391 case Iex_Unop:
1392 setHints_Expr(doesLoad, doesGet, e->Iex.Unop.arg);
1393 return;
1394 case Iex_LDle:
1395 *doesLoad |= True;
sewardj37d38012004-08-24 00:37:04 +00001396 setHints_Expr(doesLoad, doesGet, e->Iex.LDle.addr);
sewardjc41f1fb2004-08-22 09:48:08 +00001397 return;
sewardj29632392004-08-22 02:38:11 +00001398 case Iex_Get:
1399 *doesGet |= True;
1400 return;
sewardjf6501992004-08-27 11:58:24 +00001401 case Iex_GetI:
1402 *doesGet |= True;
1403 setHints_Expr(doesLoad, doesGet, e->Iex.GetI.offset);
1404 return;
sewardjc41f1fb2004-08-22 09:48:08 +00001405 case Iex_Tmp:
1406 case Iex_Const:
1407 return;
sewardj29632392004-08-22 02:38:11 +00001408 default:
1409 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1410 vpanic("setHints_Expr");
1411 }
1412}
1413
1414
1415static void dumpInvalidated ( Hash64* env, IRBB* bb, /*INOUT*/Int* j )
1416{
1417 Int k, oldest_op, oldest_k;
1418 TmpInfo* ti;
1419
1420 /* Dump all the bindings to marked as invalidated, in order. */
1421 while (True) {
1422
1423 /* find the oldest bind marked 'invalidateMe'. */
1424 oldest_op = 1<<30;
1425 oldest_k = 1<<30;
1426 for (k = 0; k < env->used; k++) {
1427 if (!env->inuse[k])
1428 continue;
1429 ti = (TmpInfo*)(env->val[k]);
1430 if (!ti->expr)
1431 continue;
1432 if (!ti->invalidateMe)
1433 continue;
sewardjc41f1fb2004-08-22 09:48:08 +00001434 /* vex_printf("FOUND INVAL %d %d\n", ti->origPos, oldest_op); */
sewardj29632392004-08-22 02:38:11 +00001435 if (ti->origPos < oldest_op) {
1436 oldest_op = ti->origPos;
1437 oldest_k = k;
1438 }
1439 }
1440
1441 /* No more binds to invalidate. */
1442 if (oldest_op == 1<<30)
sewardjc41f1fb2004-08-22 09:48:08 +00001443 return;
sewardj29632392004-08-22 02:38:11 +00001444
1445 /* the oldest bind to invalidate has been identified */
1446 vassert(oldest_op != 1<<31 && oldest_k != 1<<31);
1447 ti = (TmpInfo*)(env->val[oldest_k]);
1448 vassert(ti->expr && ti->invalidateMe);
1449
1450 /* and invalidate it ... */
1451 bb->stmts[*j] = IRStmt_Tmp( (IRTemp)(env->key[oldest_k]), ti->expr);
1452 /* vex_printf("**1 "); ppIRStmt(bb->stmts[*j]); vex_printf("\n"); */
1453 (*j)++;
1454 ti->invalidateMe = False;
1455 ti->expr = NULL; /* no longer available for substitution */
1456
1457 } /* loop which dumps the binds marked for invalidation */
1458}
1459
1460
1461
1462static void treebuild_BB ( IRBB* bb )
1463{
1464 Int i, j, k;
1465 ULong res;
1466 Bool invPut, invStore;
1467 IRStmt* st;
1468 IRStmt* st2;
1469 TmpInfo* ti;
1470 IRExpr* next2;
1471
1472 /* Mapping from IRTemp to TmpInfo*. */
1473 Hash64* env = newH64();
1474
1475 /* Phase 1. Scan forwards in bb, counting use occurrences of each
1476 temp. Also count occurrences in the bb->next field. */
1477
1478 for (i = 0; i < bb->stmts_used; i++) {
1479 st = bb->stmts[i];
1480 if (!st)
1481 continue;
1482 occCount_Stmt( env, st );
1483 }
1484 occCount_Expr(env, bb->next );
1485
1486#if 0
1487 for (i = 0; i < env->used; i++) {
1488 if (!env->inuse[i])
1489 continue;
1490 ppIRTemp( (IRTemp)(env->key[i]) );
1491 vex_printf(" used %d\n", ((TmpInfo*)env->val[i])->occ );
1492 }
1493#endif
1494
1495 /* Phase 2. Fill in the origPos fields. */
1496
1497 for (i = 0; i < bb->stmts_used; i++) {
1498 st = bb->stmts[i];
1499 if (!st)
1500 continue;
1501 if (st->tag != Ist_Tmp)
1502 continue;
1503
1504 if (!lookupH64(env, &res, (ULong)(st->Ist.Tmp.tmp))) {
sewardj84ff0652004-08-23 16:16:08 +00001505 vex_printf("\n");
1506 ppIRTemp(st->Ist.Tmp.tmp);
1507 vex_printf("\n");
sewardj29632392004-08-22 02:38:11 +00001508 vpanic("treebuild_BB (phase 2): unmapped IRTemp");
1509 }
1510 ti = (TmpInfo*)res;
1511 ti->origPos = i;
1512 }
1513
1514 /* Phase 3. Scan forwards in bb.
1515
1516 On seeing 't = E', occ(t)==1,
1517 let E'=env(E), set t's binding to be E', and
1518 delete this stmt.
1519 Also examine E' and set the hints for E' appropriately
1520 (doesLoad? doesGet?)
1521
1522 On seeing any other stmt,
1523 let stmt' = env(stmt)
1524 remove from env any 't=E' binds invalidated by stmt
1525 emit the invalidated stmts
1526 emit stmt'
1527
1528 Apply env to bb->next.
1529 */
1530
1531 /* The stmts in bb are being reordered, and we are guaranteed to
1532 end up with no more than the number we started with. Use i to
1533 be the cursor of the current stmt examined and j <= i to be that
1534 for the current stmt being written.
1535 */
1536 j = 0;
1537 for (i = 0; i < bb->stmts_used; i++) {
1538 st = bb->stmts[i];
1539 if (!st)
1540 continue;
1541
1542 if (st->tag == Ist_Tmp) {
sewardjc41f1fb2004-08-22 09:48:08 +00001543 /* vex_printf("acquire binding\n"); */
sewardj29632392004-08-22 02:38:11 +00001544 if (!lookupH64(env, &res, (ULong)(st->Ist.Tmp.tmp))) {
1545 vpanic("treebuild_BB (phase 2): unmapped IRTemp");
1546 }
1547 ti = (TmpInfo*)res;
1548 if (ti->occ == 1) {
1549 /* ok, we have 't = E', occ(t)==1. Do the abovementioned actions. */
1550 IRExpr* e = st->Ist.Tmp.expr;
1551 IRExpr* e2 = tbSubst_Expr(env, e);
1552 ti->expr = e2;
1553 ti->eDoesLoad = ti->eDoesGet = False;
1554 setHints_Expr(&ti->eDoesLoad, &ti->eDoesGet, e2);
1555 /* don't advance j, as we are deleting this stmt and instead
1556 holding it temporarily in the env. */
1557 continue; /* the for (i = 0; i < bb->stmts_used; i++) loop */
1558 }
1559 }
1560
1561 /* we get here for any other kind of statement. */
1562 /* 'use up' any bindings required by the current statement. */
1563 st2 = tbSubst_Stmt(env, st);
1564
1565 /* Now, before this stmt, dump any bindings it invalidates.
1566 These need to be dumped in the order in which they originally
1567 appeared. (Stupid algorithm): first, mark all bindings which
1568 need to be dumped. Then, dump them in the order in which
1569 they were defined. */
sewardj37d38012004-08-24 00:37:04 +00001570 invPut = st->tag == Ist_Put || st->tag == Ist_PutI;
sewardj29632392004-08-22 02:38:11 +00001571 invStore = st->tag == Ist_STle;
1572
1573 for (k = 0; k < env->used; k++) {
1574 if (!env->inuse[k])
1575 continue;
1576 ti = (TmpInfo*)(env->val[k]);
1577 if (!ti->expr)
1578 continue;
1579
1580 /* We have to invalidate this binding. */
1581 ti->invalidateMe
1582 = (ti->eDoesLoad && invStore) || (ti->eDoesGet && invPut);
sewardjc41f1fb2004-08-22 09:48:08 +00001583 /*
1584 if (ti->invalidateMe)
1585 vex_printf("SET INVAL\n");
1586 */
sewardj29632392004-08-22 02:38:11 +00001587 }
1588
1589 dumpInvalidated ( env, bb, &j );
1590
1591 /* finally, emit the substituted statement */
1592 bb->stmts[j] = st2;
1593 /* vex_printf("**2 "); ppIRStmt(bb->stmts[j]); vex_printf("\n"); */
1594 j++;
1595
1596 vassert(j <= i+1);
1597 } /* for each stmt in the original bb ... */
1598
1599 /* Finally ... substitute the ->next field as much as possible, and
1600 dump any left-over bindings. Hmm. Perhaps there should be no
1601 left over bindings? Or any left-over bindings are
1602 by definition dead? */
1603 next2 = tbSubst_Expr(env, bb->next);
1604 bb->next = next2;
1605 bb->stmts_used = j;
1606}
1607
1608
1609
sewardjf0e43162004-08-20 00:11:12 +00001610/*---------------------------------------------------------------*/
sewardjedf4d692004-08-17 13:52:58 +00001611/*--- iropt main ---*/
1612/*---------------------------------------------------------------*/
1613
1614/* Rules of the game:
1615
1616 - IRExpr/IRStmt trees should be treated as immutable, as they
1617 may get shared. So never change a field of such a tree node;
1618 instead construct and return a new one if needed.
1619*/
1620
1621/* exported from this file */
sewardj84ff0652004-08-23 16:16:08 +00001622IRBB* do_iropt_BB ( IRBB* bb0,
1623 IRExpr* (*specHelper) ( Char*, IRExpr**) )
sewardjedf4d692004-08-17 13:52:58 +00001624{
sewardj84be7372004-08-18 13:59:33 +00001625 Bool verbose = False;
1626 IRBB *flat, *cpd;
sewardj29632392004-08-22 02:38:11 +00001627
sewardj84be7372004-08-18 13:59:33 +00001628 flat = flatten_BB ( bb0 );
1629 if (verbose) {
1630 vex_printf("\n************************ FLAT\n\n" );
1631 ppIRBB(flat);
1632 }
sewardjd7217032004-08-19 10:49:10 +00001633
1634 redundant_get_removal_BB ( flat );
1635 if (verbose) {
1636 vex_printf("\n========= REDUNDANT GET\n\n" );
1637 ppIRBB(flat);
1638 }
1639
sewardjf0e43162004-08-20 00:11:12 +00001640 redundant_put_removal_BB ( flat );
1641 if (verbose) {
1642 vex_printf("\n========= REDUNDANT PUT\n\n" );
1643 ppIRBB(flat);
1644 }
1645
sewardjd7217032004-08-19 10:49:10 +00001646 cpd = cprop_BB ( flat );
sewardj84be7372004-08-18 13:59:33 +00001647 if (verbose) {
1648 vex_printf("\n========= CPROPD\n\n" );
1649 ppIRBB(cpd);
1650 }
sewardj29632392004-08-22 02:38:11 +00001651
sewardj39e3f242004-08-18 16:54:52 +00001652 dead_BB ( cpd );
sewardj84ff0652004-08-23 16:16:08 +00001653 if (verbose) {
sewardj39e3f242004-08-18 16:54:52 +00001654 vex_printf("\n========= DEAD\n\n" );
1655 ppIRBB(cpd);
1656 }
sewardj29632392004-08-22 02:38:11 +00001657
sewardj84ff0652004-08-23 16:16:08 +00001658 spec_helpers_BB ( cpd, specHelper );
1659 dead_BB ( cpd );
1660 if (verbose) {
1661 vex_printf("\n========= SPECd \n\n" );
1662 ppIRBB(cpd);
1663 }
1664
sewardj29632392004-08-22 02:38:11 +00001665 treebuild_BB ( cpd );
sewardj84ff0652004-08-23 16:16:08 +00001666 if (verbose) {
sewardj29632392004-08-22 02:38:11 +00001667 vex_printf("\n========= TREEd \n\n" );
1668 ppIRBB(cpd);
1669 }
sewardj29632392004-08-22 02:38:11 +00001670
sewardj84be7372004-08-18 13:59:33 +00001671 return cpd;
sewardjd7217032004-08-19 10:49:10 +00001672
sewardjedf4d692004-08-17 13:52:58 +00001673}
1674
1675
sewardja1a370f2004-08-17 13:31:55 +00001676/*---------------------------------------------------------------*/
1677/*--- end ir/iropt.c ---*/
1678/*---------------------------------------------------------------*/