blob: 40c7888163c089f74f62a632f25de0dab68875ab [file] [log] [blame]
sewardja1a370f2004-08-17 13:31:55 +00001
2/*---------------------------------------------------------------*/
3/*--- ---*/
4/*--- This file (ir/iropt.c) is ---*/
sewardjdbcfae72005-08-02 11:14:04 +00005/*--- Copyright (C) OpenWorks LLP. All rights reserved. ---*/
sewardja1a370f2004-08-17 13:31:55 +00006/*--- ---*/
7/*---------------------------------------------------------------*/
8
sewardjf8ed9d82004-11-12 17:40:23 +00009/*
10 This file is part of LibVEX, a library for dynamic binary
11 instrumentation and translation.
12
sewardje7441532007-01-08 05:51:05 +000013 Copyright (C) 2004-2007 OpenWorks LLP. All rights reserved.
sewardjf8ed9d82004-11-12 17:40:23 +000014
sewardj7bd6ffe2005-08-03 16:07:36 +000015 This library is made available under a dual licensing scheme.
sewardjf8ed9d82004-11-12 17:40:23 +000016
sewardj7bd6ffe2005-08-03 16:07:36 +000017 If you link LibVEX against other code all of which is itself
18 licensed under the GNU General Public License, version 2 dated June
19 1991 ("GPL v2"), then you may use LibVEX under the terms of the GPL
20 v2, as appearing in the file LICENSE.GPL. If the file LICENSE.GPL
21 is missing, you can obtain a copy of the GPL v2 from the Free
22 Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 02110-1301, USA.
24
25 For any other uses of LibVEX, you must first obtain a commercial
26 license from OpenWorks LLP. Please contact info@open-works.co.uk
27 for information about commercial licensing.
28
29 This software is provided by OpenWorks LLP "as is" and any express
30 or implied warranties, including, but not limited to, the implied
31 warranties of merchantability and fitness for a particular purpose
32 are disclaimed. In no event shall OpenWorks LLP be liable for any
33 direct, indirect, incidental, special, exemplary, or consequential
34 damages (including, but not limited to, procurement of substitute
35 goods or services; loss of use, data, or profits; or business
36 interruption) however caused and on any theory of liability,
37 whether in contract, strict liability, or tort (including
38 negligence or otherwise) arising in any way out of the use of this
39 software, even if advised of the possibility of such damage.
sewardjf8ed9d82004-11-12 17:40:23 +000040
41 Neither the names of the U.S. Department of Energy nor the
42 University of California nor the names of its contributors may be
43 used to endorse or promote products derived from this software
44 without prior written permission.
sewardjf8ed9d82004-11-12 17:40:23 +000045*/
46
sewardja1a370f2004-08-17 13:31:55 +000047#include "libvex_basictypes.h"
sewardjedf4d692004-08-17 13:52:58 +000048#include "libvex_ir.h"
sewardja1a370f2004-08-17 13:31:55 +000049#include "libvex.h"
50
51#include "main/vex_util.h"
sewardj08613742004-10-25 13:01:45 +000052#include "main/vex_globals.h"
sewardjedf4d692004-08-17 13:52:58 +000053#include "ir/iropt.h"
sewardja1a370f2004-08-17 13:31:55 +000054
sewardjd0863ff2004-10-23 00:22:32 +000055
sewardj088bcb42004-08-19 17:16:52 +000056/* Set to 1 for lots of debugging output. */
57#define DEBUG_IROPT 0
58
sewardja1a370f2004-08-17 13:31:55 +000059
sewardj08210532004-12-29 17:09:11 +000060/* What iropt does, 29 Dec 04.
61
sewardjf6c8ebf2007-02-06 01:52:52 +000062 It takes an IRSB and produces a new one with the same meaning,
sewardj08210532004-12-29 17:09:11 +000063 defined thus:
64
65 After execution of the new BB, all guest state and guest memory is
66 the same as after execution of the original. This is true
67 regardless of how the block was exited (at the end vs side exit).
68
69 In addition, parts of the guest state will be identical to that
70 created by execution of the original at the following observation
71 points:
72
73 * In a dirty helper call, any parts of the guest state that the
74 helper states that it reads or modifies will be up to date.
75 Also, guest memory will be up to date. Parts of the guest state
76 not marked as being read or modified by the helper cannot be
77 assumed to be up-to-date at the point where the helper is called.
78
79 * Immediately prior to any load or store, those parts of the guest
80 state marked as requiring precise exceptions will be up to date.
81 Also, guest memory will be up to date. Parts of the guest state
82 not marked as requiring precise exceptions cannot be assumed to
83 be up-to-date at the point of the load/store.
84
85 The relative order of loads and stores (including loads/stores of
86 guest memory done by dirty helpers annotated as such) is not
87 changed. However, the relative order of loads with no intervening
88 stores/modifies may be changed.
89
90 Transformation order
91 ~~~~~~~~~~~~~~~~~~~~
92
93 There are three levels of optimisation, controlled by
94 vex_control.iropt_level. Define first:
95
96 "Cheap transformations" are the following sequence:
97 * Redundant-Get removal
98 * Redundant-Put removal
99 * Constant propagation/folding
100 * Dead code removal
101 * Specialisation of clean helper functions
102 * Dead code removal
103
104 "Expensive transformations" are the following sequence:
105 * CSE
106 * Folding of add/sub chains
107 * Redundant-GetI removal
108 * Redundant-PutI removal
109 * Dead code removal
sewardj08210532004-12-29 17:09:11 +0000110
111 Then the transformations are as follows, as defined by
112 vex_control.iropt_level:
113
114 Level 0:
115 * Flatten into atomic form.
116
117 Level 1: the following sequence:
118 * Flatten into atomic form.
119 * Cheap transformations.
sewardj08210532004-12-29 17:09:11 +0000120
121 Level 2: the following sequence
122 * Flatten into atomic form.
123 * Cheap transformations.
sewardjb183b852006-02-03 16:08:03 +0000124 * If block contains any floating or vector types, CSE.
sewardj08210532004-12-29 17:09:11 +0000125 * If block contains GetI or PutI, Expensive transformations.
126 * Try unrolling loops. Three possible outcomes:
127 - No effect: do nothing more.
128 - Unrolled a loop, and block does not contain GetI or PutI:
129 Do: * CSE
130 * Dead code removal
sewardj08210532004-12-29 17:09:11 +0000131 - Unrolled a loop, and block contains GetI or PutI:
132 Do: * Expensive transformations
133 * Cheap transformations
sewardj08210532004-12-29 17:09:11 +0000134*/
135
sewardj98430292004-12-29 17:34:50 +0000136/* Implementation notes, 29 Dec 04.
137
138 TODO (important): I think rPutI removal ignores precise exceptions
139 and is therefore in a sense, wrong. In the sense that PutIs are
140 assumed not to write parts of the guest state that we need to have
141 up-to-date at loads/stores. So far on x86 guest that has not
142 mattered since indeed only the x87 FP registers and tags are
143 accessed using GetI/PutI, and there is no need so far for them to
144 be up to date at mem exception points. The rPutI pass should be
145 fixed.
sewardjfb44d552004-10-25 09:48:47 +0000146
sewardj4c5f6d52004-10-26 13:25:33 +0000147 TODO: improve pessimistic handling of precise exceptions
148 in the tree builder.
149
sewardjfb44d552004-10-25 09:48:47 +0000150 TODO: check interaction of rGetI and dirty helpers.
sewardjc0b42282004-10-12 13:44:12 +0000151
152 F64i constants are treated differently from other constants.
153 They are not regarded as atoms, and instead lifted off and
154 bound to temps. This allows them to participate in CSE, which
155 is important for getting good performance for x86 guest code.
sewardj695cff92004-10-13 14:50:14 +0000156
sewardja5aa9cf2004-10-15 22:56:38 +0000157 CSE up F64 literals (already doing F64is)
sewardj4c5f6d52004-10-26 13:25:33 +0000158
159 CSE: consider carefully the requirement for precise exns
sewardj98430292004-12-29 17:34:50 +0000160 prior to making CSE any more aggressive. */
sewardjc0b42282004-10-12 13:44:12 +0000161
162
sewardja1a370f2004-08-17 13:31:55 +0000163/*---------------------------------------------------------------*/
164/*--- Finite mappery, of a sort ---*/
165/*---------------------------------------------------------------*/
166
sewardj08210532004-12-29 17:09:11 +0000167/* General map from HWord-sized thing HWord-sized thing. Could be by
168 hashing, but it's not clear whether or not this would really be any
169 faster. */
sewardja1a370f2004-08-17 13:31:55 +0000170
171typedef
172 struct {
173 Bool* inuse;
sewardjea602bc2004-10-14 21:40:12 +0000174 HWord* key;
175 HWord* val;
sewardja1a370f2004-08-17 13:31:55 +0000176 Int size;
177 Int used;
178 }
sewardjea602bc2004-10-14 21:40:12 +0000179 HashHW;
sewardja1a370f2004-08-17 13:31:55 +0000180
sewardjea602bc2004-10-14 21:40:12 +0000181static HashHW* newHHW ( void )
sewardja1a370f2004-08-17 13:31:55 +0000182{
sewardjea602bc2004-10-14 21:40:12 +0000183 HashHW* h = LibVEX_Alloc(sizeof(HashHW));
sewardj29632392004-08-22 02:38:11 +0000184 h->size = 8;
sewardja1a370f2004-08-17 13:31:55 +0000185 h->used = 0;
186 h->inuse = LibVEX_Alloc(h->size * sizeof(Bool));
sewardjea602bc2004-10-14 21:40:12 +0000187 h->key = LibVEX_Alloc(h->size * sizeof(HWord));
188 h->val = LibVEX_Alloc(h->size * sizeof(HWord));
sewardja1a370f2004-08-17 13:31:55 +0000189 return h;
190}
191
192
sewardj84be7372004-08-18 13:59:33 +0000193/* Look up key in the map. */
sewardja1a370f2004-08-17 13:31:55 +0000194
sewardjea602bc2004-10-14 21:40:12 +0000195static Bool lookupHHW ( HashHW* h, /*OUT*/HWord* val, HWord key )
sewardja1a370f2004-08-17 13:31:55 +0000196{
197 Int i;
sewardj08210532004-12-29 17:09:11 +0000198 /* vex_printf("lookupHHW(%llx)\n", key ); */
sewardja1a370f2004-08-17 13:31:55 +0000199 for (i = 0; i < h->used; i++) {
200 if (h->inuse[i] && h->key[i] == key) {
sewardj39e3f242004-08-18 16:54:52 +0000201 if (val)
202 *val = h->val[i];
sewardja1a370f2004-08-17 13:31:55 +0000203 return True;
204 }
205 }
206 return False;
207}
208
209
sewardja1a370f2004-08-17 13:31:55 +0000210/* Add key->val to the map. Replaces any existing binding for key. */
211
sewardjea602bc2004-10-14 21:40:12 +0000212static void addToHHW ( HashHW* h, HWord key, HWord val )
sewardja1a370f2004-08-17 13:31:55 +0000213{
214 Int i, j;
sewardj08210532004-12-29 17:09:11 +0000215 /* vex_printf("addToHHW(%llx, %llx)\n", key, val); */
sewardja1a370f2004-08-17 13:31:55 +0000216
217 /* Find and replace existing binding, if any. */
218 for (i = 0; i < h->used; i++) {
219 if (h->inuse[i] && h->key[i] == key) {
220 h->val[i] = val;
221 return;
222 }
223 }
224
225 /* Ensure a space is available. */
226 if (h->used == h->size) {
227 /* Copy into arrays twice the size. */
228 Bool* inuse2 = LibVEX_Alloc(2 * h->size * sizeof(Bool));
sewardjea602bc2004-10-14 21:40:12 +0000229 HWord* key2 = LibVEX_Alloc(2 * h->size * sizeof(HWord));
230 HWord* val2 = LibVEX_Alloc(2 * h->size * sizeof(HWord));
sewardja1a370f2004-08-17 13:31:55 +0000231 for (i = j = 0; i < h->size; i++) {
232 if (!h->inuse[i]) continue;
233 inuse2[j] = True;
234 key2[j] = h->key[i];
235 val2[j] = h->val[i];
236 j++;
237 }
238 h->used = j;
239 h->size *= 2;
240 h->inuse = inuse2;
241 h->key = key2;
242 h->val = val2;
243 }
244
245 /* Finally, add it. */
246 vassert(h->used < h->size);
247 h->inuse[h->used] = True;
248 h->key[h->used] = key;
sewardj84be7372004-08-18 13:59:33 +0000249 h->val[h->used] = val;
sewardja1a370f2004-08-17 13:31:55 +0000250 h->used++;
251}
252
sewardj84be7372004-08-18 13:59:33 +0000253
sewardjd7cb8532004-08-17 23:59:23 +0000254/*---------------------------------------------------------------*/
sewardj08210532004-12-29 17:09:11 +0000255/*--- Flattening out a BB into atomic SSA form ---*/
sewardjd7cb8532004-08-17 23:59:23 +0000256/*---------------------------------------------------------------*/
257
sewardje80679a2004-09-21 23:00:11 +0000258/* Non-critical helper, heuristic for reducing the number of tmp-tmp
259 copies made by flattening. If in doubt return False. */
260
261static Bool isFlat ( IRExpr* e )
262{
sewardj695cff92004-10-13 14:50:14 +0000263 if (e->tag == Iex_Get)
264 return True;
sewardje80679a2004-09-21 23:00:11 +0000265 if (e->tag == Iex_Binop)
sewardj496a58d2005-03-20 18:44:44 +0000266 return toBool( isIRAtom(e->Iex.Binop.arg1)
267 && isIRAtom(e->Iex.Binop.arg2) );
sewardjaf1ceca2005-06-30 23:31:27 +0000268 if (e->tag == Iex_Load)
269 return isIRAtom(e->Iex.Load.addr);
sewardje80679a2004-09-21 23:00:11 +0000270 return False;
271}
272
sewardjd7cb8532004-08-17 23:59:23 +0000273/* Flatten out 'ex' so it is atomic, returning a new expression with
274 the same value, after having appended extra IRTemp assignments to
275 the end of 'bb'. */
276
sewardjdd40fdf2006-12-24 02:20:24 +0000277static IRExpr* flatten_Expr ( IRSB* bb, IRExpr* ex )
sewardjd7cb8532004-08-17 23:59:23 +0000278{
279 Int i;
280 IRExpr** newargs;
281 IRType ty = typeOfIRExpr(bb->tyenv, ex);
282 IRTemp t1;
283
284 switch (ex->tag) {
285
sewardjd7217032004-08-19 10:49:10 +0000286 case Iex_GetI:
287 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000288 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardj2d3f77c2004-09-22 23:49:09 +0000289 IRExpr_GetI(ex->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +0000290 flatten_Expr(bb, ex->Iex.GetI.ix),
sewardj2d3f77c2004-09-22 23:49:09 +0000291 ex->Iex.GetI.bias)));
sewardjdd40fdf2006-12-24 02:20:24 +0000292 return IRExpr_RdTmp(t1);
sewardjd7217032004-08-19 10:49:10 +0000293
sewardjd7cb8532004-08-17 23:59:23 +0000294 case Iex_Get:
295 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000296 addStmtToIRSB(bb,
297 IRStmt_WrTmp(t1, ex));
298 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000299
sewardj40c80262006-02-08 19:30:46 +0000300 case Iex_Qop:
301 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000302 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardj40c80262006-02-08 19:30:46 +0000303 IRExpr_Qop(ex->Iex.Qop.op,
304 flatten_Expr(bb, ex->Iex.Qop.arg1),
305 flatten_Expr(bb, ex->Iex.Qop.arg2),
306 flatten_Expr(bb, ex->Iex.Qop.arg3),
307 flatten_Expr(bb, ex->Iex.Qop.arg4))));
sewardjdd40fdf2006-12-24 02:20:24 +0000308 return IRExpr_RdTmp(t1);
sewardj40c80262006-02-08 19:30:46 +0000309
sewardjb183b852006-02-03 16:08:03 +0000310 case Iex_Triop:
311 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000312 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjb183b852006-02-03 16:08:03 +0000313 IRExpr_Triop(ex->Iex.Triop.op,
314 flatten_Expr(bb, ex->Iex.Triop.arg1),
315 flatten_Expr(bb, ex->Iex.Triop.arg2),
316 flatten_Expr(bb, ex->Iex.Triop.arg3))));
sewardjdd40fdf2006-12-24 02:20:24 +0000317 return IRExpr_RdTmp(t1);
sewardjb183b852006-02-03 16:08:03 +0000318
sewardjd7cb8532004-08-17 23:59:23 +0000319 case Iex_Binop:
320 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000321 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjd7cb8532004-08-17 23:59:23 +0000322 IRExpr_Binop(ex->Iex.Binop.op,
323 flatten_Expr(bb, ex->Iex.Binop.arg1),
324 flatten_Expr(bb, ex->Iex.Binop.arg2))));
sewardjdd40fdf2006-12-24 02:20:24 +0000325 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000326
327 case Iex_Unop:
328 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000329 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjd7cb8532004-08-17 23:59:23 +0000330 IRExpr_Unop(ex->Iex.Unop.op,
331 flatten_Expr(bb, ex->Iex.Unop.arg))));
sewardjdd40fdf2006-12-24 02:20:24 +0000332 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000333
sewardjaf1ceca2005-06-30 23:31:27 +0000334 case Iex_Load:
sewardjd7cb8532004-08-17 23:59:23 +0000335 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000336 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjaf1ceca2005-06-30 23:31:27 +0000337 IRExpr_Load(ex->Iex.Load.end,
338 ex->Iex.Load.ty,
339 flatten_Expr(bb, ex->Iex.Load.addr))));
sewardjdd40fdf2006-12-24 02:20:24 +0000340 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000341
342 case Iex_CCall:
sewardjdd40fdf2006-12-24 02:20:24 +0000343 newargs = shallowCopyIRExprVec(ex->Iex.CCall.args);
sewardjd7cb8532004-08-17 23:59:23 +0000344 for (i = 0; newargs[i]; i++)
345 newargs[i] = flatten_Expr(bb, newargs[i]);
346 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000347 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardj8ea867b2004-10-30 19:03:02 +0000348 IRExpr_CCall(ex->Iex.CCall.cee,
sewardjd7cb8532004-08-17 23:59:23 +0000349 ex->Iex.CCall.retty,
350 newargs)));
sewardjdd40fdf2006-12-24 02:20:24 +0000351 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000352
353 case Iex_Mux0X:
354 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000355 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjd7cb8532004-08-17 23:59:23 +0000356 IRExpr_Mux0X(flatten_Expr(bb, ex->Iex.Mux0X.cond),
357 flatten_Expr(bb, ex->Iex.Mux0X.expr0),
358 flatten_Expr(bb, ex->Iex.Mux0X.exprX))));
sewardjdd40fdf2006-12-24 02:20:24 +0000359 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000360
361 case Iex_Const:
sewardjc0b42282004-10-12 13:44:12 +0000362 /* Lift F64i constants out onto temps so they can be CSEd
363 later. */
364 if (ex->Iex.Const.con->tag == Ico_F64i) {
365 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000366 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjc0b42282004-10-12 13:44:12 +0000367 IRExpr_Const(ex->Iex.Const.con)));
sewardjdd40fdf2006-12-24 02:20:24 +0000368 return IRExpr_RdTmp(t1);
sewardjc0b42282004-10-12 13:44:12 +0000369 } else {
370 /* Leave all other constants alone. */
371 return ex;
372 }
373
sewardjdd40fdf2006-12-24 02:20:24 +0000374 case Iex_RdTmp:
sewardjd7cb8532004-08-17 23:59:23 +0000375 return ex;
376
377 default:
378 vex_printf("\n");
379 ppIRExpr(ex);
380 vex_printf("\n");
381 vpanic("flatten_Expr");
382 }
383}
384
385
386/* Append a completely flattened form of 'st' to the end of 'bb'. */
387
sewardjdd40fdf2006-12-24 02:20:24 +0000388static void flatten_Stmt ( IRSB* bb, IRStmt* st )
sewardjd7cb8532004-08-17 23:59:23 +0000389{
sewardj17442fe2004-09-20 14:54:28 +0000390 Int i;
391 IRExpr *e1, *e2;
392 IRDirty *d, *d2;
sewardjd7cb8532004-08-17 23:59:23 +0000393 switch (st->tag) {
394 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +0000395 if (isIRAtom(st->Ist.Put.data)) {
sewardj49651f42004-10-28 22:11:04 +0000396 /* optimisation to reduce the amount of heap wasted
397 by the flattener */
sewardjdd40fdf2006-12-24 02:20:24 +0000398 addStmtToIRSB(bb, st);
sewardj49651f42004-10-28 22:11:04 +0000399 } else {
400 /* general case, always correct */
401 e1 = flatten_Expr(bb, st->Ist.Put.data);
sewardjdd40fdf2006-12-24 02:20:24 +0000402 addStmtToIRSB(bb, IRStmt_Put(st->Ist.Put.offset, e1));
sewardj49651f42004-10-28 22:11:04 +0000403 }
sewardjd7cb8532004-08-17 23:59:23 +0000404 break;
sewardjd7cb8532004-08-17 23:59:23 +0000405 case Ist_PutI:
sewardjeeac8412004-11-02 00:26:55 +0000406 e1 = flatten_Expr(bb, st->Ist.PutI.ix);
sewardj2d3f77c2004-09-22 23:49:09 +0000407 e2 = flatten_Expr(bb, st->Ist.PutI.data);
sewardjdd40fdf2006-12-24 02:20:24 +0000408 addStmtToIRSB(bb, IRStmt_PutI(st->Ist.PutI.descr,
sewardj2d3f77c2004-09-22 23:49:09 +0000409 e1,
410 st->Ist.PutI.bias,
411 e2));
sewardjd7217032004-08-19 10:49:10 +0000412 break;
sewardjdd40fdf2006-12-24 02:20:24 +0000413 case Ist_WrTmp:
414 if (isFlat(st->Ist.WrTmp.data)) {
sewardje80679a2004-09-21 23:00:11 +0000415 /* optimisation, to reduce the number of tmp-tmp
416 copies generated */
sewardjdd40fdf2006-12-24 02:20:24 +0000417 addStmtToIRSB(bb, st);
sewardje80679a2004-09-21 23:00:11 +0000418 } else {
419 /* general case, always correct */
sewardjdd40fdf2006-12-24 02:20:24 +0000420 e1 = flatten_Expr(bb, st->Ist.WrTmp.data);
421 addStmtToIRSB(bb, IRStmt_WrTmp(st->Ist.WrTmp.tmp, e1));
sewardje80679a2004-09-21 23:00:11 +0000422 }
sewardjd7cb8532004-08-17 23:59:23 +0000423 break;
sewardjaf1ceca2005-06-30 23:31:27 +0000424 case Ist_Store:
425 e1 = flatten_Expr(bb, st->Ist.Store.addr);
426 e2 = flatten_Expr(bb, st->Ist.Store.data);
sewardjdd40fdf2006-12-24 02:20:24 +0000427 addStmtToIRSB(bb, IRStmt_Store(st->Ist.Store.end, e1,e2));
sewardjd7cb8532004-08-17 23:59:23 +0000428 break;
sewardj17442fe2004-09-20 14:54:28 +0000429 case Ist_Dirty:
430 d = st->Ist.Dirty.details;
431 d2 = emptyIRDirty();
432 *d2 = *d;
sewardjdd40fdf2006-12-24 02:20:24 +0000433 d2->args = shallowCopyIRExprVec(d2->args);
sewardj17442fe2004-09-20 14:54:28 +0000434 if (d2->mFx != Ifx_None) {
435 d2->mAddr = flatten_Expr(bb, d2->mAddr);
436 } else {
437 vassert(d2->mAddr == NULL);
438 }
sewardjb8385d82004-11-02 01:34:15 +0000439 d2->guard = flatten_Expr(bb, d2->guard);
sewardj17442fe2004-09-20 14:54:28 +0000440 for (i = 0; d2->args[i]; i++)
441 d2->args[i] = flatten_Expr(bb, d2->args[i]);
sewardjdd40fdf2006-12-24 02:20:24 +0000442 addStmtToIRSB(bb, IRStmt_Dirty(d2));
sewardj17442fe2004-09-20 14:54:28 +0000443 break;
sewardjd2445f62005-03-21 00:15:53 +0000444 case Ist_NoOp:
sewardj3e838932005-01-07 12:09:15 +0000445 case Ist_MFence:
sewardjd2445f62005-03-21 00:15:53 +0000446 case Ist_IMark:
sewardjdd40fdf2006-12-24 02:20:24 +0000447 addStmtToIRSB(bb, st);
sewardj3e838932005-01-07 12:09:15 +0000448 break;
sewardj5a9ffab2005-05-12 17:55:01 +0000449 case Ist_AbiHint:
450 e1 = flatten_Expr(bb, st->Ist.AbiHint.base);
sewardjdd40fdf2006-12-24 02:20:24 +0000451 addStmtToIRSB(bb, IRStmt_AbiHint(e1, st->Ist.AbiHint.len));
sewardj5a9ffab2005-05-12 17:55:01 +0000452 break;
sewardjd7cb8532004-08-17 23:59:23 +0000453 case Ist_Exit:
sewardj0276d4b2004-11-15 15:30:21 +0000454 e1 = flatten_Expr(bb, st->Ist.Exit.guard);
sewardjdd40fdf2006-12-24 02:20:24 +0000455 addStmtToIRSB(bb, IRStmt_Exit(e1, st->Ist.Exit.jk,
sewardj893aada2004-11-29 19:57:54 +0000456 st->Ist.Exit.dst));
sewardjd7cb8532004-08-17 23:59:23 +0000457 break;
458 default:
459 vex_printf("\n");
460 ppIRStmt(st);
461 vex_printf("\n");
462 vpanic("flatten_Stmt");
463 }
464}
465
sewardj08210532004-12-29 17:09:11 +0000466
sewardjdd40fdf2006-12-24 02:20:24 +0000467static IRSB* flatten_BB ( IRSB* in )
sewardjd7cb8532004-08-17 23:59:23 +0000468{
469 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +0000470 IRSB* out;
471 out = emptyIRSB();
472 out->tyenv = deepCopyIRTypeEnv( in->tyenv );
sewardjd7cb8532004-08-17 23:59:23 +0000473 for (i = 0; i < in->stmts_used; i++)
sewardj4345f7a2004-09-22 19:49:27 +0000474 if (in->stmts[i])
475 flatten_Stmt( out, in->stmts[i] );
sewardjd7cb8532004-08-17 23:59:23 +0000476 out->next = flatten_Expr( out, in->next );
477 out->jumpkind = in->jumpkind;
478 return out;
479}
480
sewardjedf4d692004-08-17 13:52:58 +0000481
sewardj08210532004-12-29 17:09:11 +0000482/*---------------------------------------------------------------*/
483/*--- In-place removal of redundant GETs ---*/
484/*---------------------------------------------------------------*/
485
486/* Scan forwards, building up an environment binding (min offset, max
487 offset) pairs to values, which will either be temps or constants.
488
489 On seeing 't = Get(minoff,maxoff)', look up (minoff,maxoff) in the
490 env and if it matches, replace the Get with the stored value. If
491 there is no match, add a (minoff,maxoff) :-> t binding.
492
493 On seeing 'Put (minoff,maxoff) = t or c', first remove in the env
494 any binding which fully or partially overlaps with (minoff,maxoff).
495 Then add a new (minoff,maxoff) :-> t or c binding. */
496
497/* Extract the min/max offsets from a guest state array descriptor. */
498
499inline
sewardjdd40fdf2006-12-24 02:20:24 +0000500static void getArrayBounds ( IRRegArray* descr,
501 UInt* minoff, UInt* maxoff )
sewardj08210532004-12-29 17:09:11 +0000502{
503 *minoff = descr->base;
504 *maxoff = *minoff + descr->nElems*sizeofIRType(descr->elemTy) - 1;
505 vassert((*minoff & ~0xFFFF) == 0);
506 vassert((*maxoff & ~0xFFFF) == 0);
507 vassert(*minoff <= *maxoff);
508}
509
510/* Create keys, of the form ((minoffset << 16) | maxoffset). */
511
512static UInt mk_key_GetPut ( Int offset, IRType ty )
513{
514 /* offset should fit in 16 bits. */
515 UInt minoff = offset;
516 UInt maxoff = minoff + sizeofIRType(ty) - 1;
517 vassert((minoff & ~0xFFFF) == 0);
518 vassert((maxoff & ~0xFFFF) == 0);
519 return (minoff << 16) | maxoff;
520}
521
sewardjdd40fdf2006-12-24 02:20:24 +0000522static UInt mk_key_GetIPutI ( IRRegArray* descr )
sewardj08210532004-12-29 17:09:11 +0000523{
524 UInt minoff, maxoff;
525 getArrayBounds( descr, &minoff, &maxoff );
526 vassert((minoff & ~0xFFFF) == 0);
527 vassert((maxoff & ~0xFFFF) == 0);
528 return (minoff << 16) | maxoff;
529}
530
531/* Supposing h has keys of the form generated by mk_key_GetPut and
532 mk_key_GetIPutI, invalidate any key which overlaps (k_lo
533 .. k_hi).
534*/
535static void invalidateOverlaps ( HashHW* h, UInt k_lo, UInt k_hi )
536{
537 Int j;
538 UInt e_lo, e_hi;
539 vassert(k_lo <= k_hi);
540 /* invalidate any env entries which in any way overlap (k_lo
541 .. k_hi) */
542 /* vex_printf("invalidate %d .. %d\n", k_lo, k_hi ); */
543
544 for (j = 0; j < h->used; j++) {
545 if (!h->inuse[j])
546 continue;
547 e_lo = (((UInt)h->key[j]) >> 16) & 0xFFFF;
548 e_hi = ((UInt)h->key[j]) & 0xFFFF;
549 vassert(e_lo <= e_hi);
550 if (e_hi < k_lo || k_hi < e_lo)
551 continue; /* no overlap possible */
552 else
553 /* overlap; invalidate */
554 h->inuse[j] = False;
555 }
556}
557
558
sewardjdd40fdf2006-12-24 02:20:24 +0000559static void redundant_get_removal_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +0000560{
561 HashHW* env = newHHW();
562 UInt key = 0; /* keep gcc -O happy */
563 Int i, j;
564 HWord val;
565
566 for (i = 0; i < bb->stmts_used; i++) {
567 IRStmt* st = bb->stmts[i];
568
sewardj8bee6d12005-03-22 02:24:05 +0000569 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +0000570 continue;
571
572 /* Deal with Gets */
sewardjdd40fdf2006-12-24 02:20:24 +0000573 if (st->tag == Ist_WrTmp
574 && st->Ist.WrTmp.data->tag == Iex_Get) {
sewardj08210532004-12-29 17:09:11 +0000575 /* st is 't = Get(...)'. Look up in the environment and see
576 if the Get can be replaced. */
sewardjdd40fdf2006-12-24 02:20:24 +0000577 IRExpr* get = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +0000578 key = (HWord)mk_key_GetPut( get->Iex.Get.offset,
579 get->Iex.Get.ty );
580 if (lookupHHW(env, &val, (HWord)key)) {
581 /* found it */
582 /* Note, we could do better here. If the types are
583 different we don't do the substitution, since doing so
584 could lead to invalidly-typed IR. An improvement would
585 be to stick in a reinterpret-style cast, although that
586 would make maintaining flatness more difficult. */
587 IRExpr* valE = (IRExpr*)val;
sewardj9d2e7692005-02-07 01:11:31 +0000588 Bool typesOK = toBool( typeOfIRExpr(bb->tyenv,valE)
sewardjdd40fdf2006-12-24 02:20:24 +0000589 == st->Ist.WrTmp.data->Iex.Get.ty );
sewardj08210532004-12-29 17:09:11 +0000590 if (typesOK && DEBUG_IROPT) {
591 vex_printf("rGET: "); ppIRExpr(get);
592 vex_printf(" -> "); ppIRExpr(valE);
593 vex_printf("\n");
594 }
595 if (typesOK)
sewardjdd40fdf2006-12-24 02:20:24 +0000596 bb->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, valE);
sewardj08210532004-12-29 17:09:11 +0000597 } else {
598 /* Not found, but at least we know that t and the Get(...)
599 are now associated. So add a binding to reflect that
600 fact. */
601 addToHHW( env, (HWord)key,
sewardjdd40fdf2006-12-24 02:20:24 +0000602 (HWord)(void*)(IRExpr_RdTmp(st->Ist.WrTmp.tmp)) );
sewardj08210532004-12-29 17:09:11 +0000603 }
604 }
605
606 /* Deal with Puts: invalidate any env entries overlapped by this
607 Put */
608 if (st->tag == Ist_Put || st->tag == Ist_PutI) {
609 UInt k_lo, k_hi;
610 if (st->tag == Ist_Put) {
611 key = mk_key_GetPut( st->Ist.Put.offset,
612 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
613 } else {
614 vassert(st->tag == Ist_PutI);
615 key = mk_key_GetIPutI( st->Ist.PutI.descr );
616 }
617
618 k_lo = (key >> 16) & 0xFFFF;
619 k_hi = key & 0xFFFF;
620 invalidateOverlaps(env, k_lo, k_hi);
621 }
622 else
623 if (st->tag == Ist_Dirty) {
624 /* Deal with dirty helpers which write or modify guest state.
625 Invalidate the entire env. We could do a lot better
626 here. */
627 IRDirty* d = st->Ist.Dirty.details;
628 Bool writes = False;
629 for (j = 0; j < d->nFxState; j++) {
630 if (d->fxState[j].fx == Ifx_Modify
631 || d->fxState[j].fx == Ifx_Write)
632 writes = True;
633 }
634 if (writes) {
635 /* dump the entire env (not clever, but correct ...) */
636 for (j = 0; j < env->used; j++)
637 env->inuse[j] = False;
638 if (0) vex_printf("rGET: trash env due to dirty helper\n");
639 }
640 }
641
642 /* add this one to the env, if appropriate */
643 if (st->tag == Ist_Put) {
sewardj496a58d2005-03-20 18:44:44 +0000644 vassert(isIRAtom(st->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +0000645 addToHHW( env, (HWord)key, (HWord)(st->Ist.Put.data));
646 }
647
648 } /* for (i = 0; i < bb->stmts_used; i++) */
649
650}
651
652
653/*---------------------------------------------------------------*/
654/*--- In-place removal of redundant PUTs ---*/
655/*---------------------------------------------------------------*/
656
657/* Find any Get uses in st and invalidate any partially or fully
658 overlapping ranges listed in env. Due to the flattening phase, the
sewardjdd40fdf2006-12-24 02:20:24 +0000659 only stmt kind we expect to find a Get on is IRStmt_WrTmp. */
sewardj08210532004-12-29 17:09:11 +0000660
661static void handle_gets_Stmt (
662 HashHW* env,
663 IRStmt* st,
664 Bool (*preciseMemExnsFn)(Int,Int)
665 )
666{
667 Int j;
668 UInt key = 0; /* keep gcc -O happy */
669 Bool isGet;
670 Bool memRW = False;
671 IRExpr* e;
672
673 switch (st->tag) {
674
675 /* This is the only interesting case. Deal with Gets in the RHS
676 expression. */
sewardjdd40fdf2006-12-24 02:20:24 +0000677 case Ist_WrTmp:
678 e = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +0000679 switch (e->tag) {
680 case Iex_Get:
681 isGet = True;
682 key = mk_key_GetPut ( e->Iex.Get.offset, e->Iex.Get.ty );
683 break;
684 case Iex_GetI:
685 isGet = True;
686 key = mk_key_GetIPutI ( e->Iex.GetI.descr );
687 break;
sewardjaf1ceca2005-06-30 23:31:27 +0000688 case Iex_Load:
sewardj08210532004-12-29 17:09:11 +0000689 isGet = False;
690 memRW = True;
691 break;
692 default:
693 isGet = False;
694 }
695 if (isGet) {
696 UInt k_lo, k_hi;
697 k_lo = (key >> 16) & 0xFFFF;
698 k_hi = key & 0xFFFF;
699 invalidateOverlaps(env, k_lo, k_hi);
700 }
701 break;
702
703 /* Be very conservative for dirty helper calls; dump the entire
704 environment. The helper might read guest state, in which
705 case it needs to be flushed first. Also, the helper might
706 access guest memory, in which case all parts of the guest
707 state requiring precise exceptions needs to be flushed. The
708 crude solution is just to flush everything; we could easily
709 enough do a lot better if needed. */
sewardj3e838932005-01-07 12:09:15 +0000710 /* Probably also overly-conservative, but also dump everything
sewardj5a9ffab2005-05-12 17:55:01 +0000711 if we hit a memory fence. Ditto AbiHints.*/
712 case Ist_AbiHint:
713 vassert(isIRAtom(st->Ist.AbiHint.base));
714 /* fall through */
sewardj3e838932005-01-07 12:09:15 +0000715 case Ist_MFence:
sewardj08210532004-12-29 17:09:11 +0000716 case Ist_Dirty:
717 for (j = 0; j < env->used; j++)
718 env->inuse[j] = False;
719 break;
720
721 /* all other cases are boring. */
sewardjaf1ceca2005-06-30 23:31:27 +0000722 case Ist_Store:
723 vassert(isIRAtom(st->Ist.Store.addr));
724 vassert(isIRAtom(st->Ist.Store.data));
sewardj08210532004-12-29 17:09:11 +0000725 memRW = True;
726 break;
727
728 case Ist_Exit:
sewardj496a58d2005-03-20 18:44:44 +0000729 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +0000730 break;
731
732 case Ist_PutI:
sewardj496a58d2005-03-20 18:44:44 +0000733 vassert(isIRAtom(st->Ist.PutI.ix));
734 vassert(isIRAtom(st->Ist.PutI.data));
sewardj08210532004-12-29 17:09:11 +0000735 break;
736
sewardjd2445f62005-03-21 00:15:53 +0000737 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +0000738 case Ist_IMark:
739 break;
740
sewardj08210532004-12-29 17:09:11 +0000741 default:
742 vex_printf("\n");
743 ppIRStmt(st);
744 vex_printf("\n");
745 vpanic("handle_gets_Stmt");
746 }
747
748 if (memRW) {
749 /* This statement accesses memory. So we need to dump all parts
750 of the environment corresponding to guest state that may not
751 be reordered with respect to memory references. That means
752 at least the stack pointer. */
753 for (j = 0; j < env->used; j++) {
754 if (!env->inuse[j])
755 continue;
756 if (vex_control.iropt_precise_memory_exns) {
757 /* Precise exceptions required. Flush all guest state. */
758 env->inuse[j] = False;
759 } else {
760 /* Just flush the minimal amount required, as computed by
761 preciseMemExnsFn. */
762 HWord k_lo = (env->key[j] >> 16) & 0xFFFF;
763 HWord k_hi = env->key[j] & 0xFFFF;
764 if (preciseMemExnsFn( k_lo, k_hi ))
765 env->inuse[j] = False;
766 }
767 }
768 } /* if (memRW) */
769
770}
771
772
773/* Scan backwards, building up a set of (min offset, max
774 offset) pairs, indicating those parts of the guest state
775 for which the next event is a write.
776
777 On seeing a conditional exit, empty the set.
778
779 On seeing 'Put (minoff,maxoff) = t or c', if (minoff,maxoff) is
780 completely within the set, remove the Put. Otherwise, add
781 (minoff,maxoff) to the set.
782
783 On seeing 'Get (minoff,maxoff)', remove any part of the set
sewardj98430292004-12-29 17:34:50 +0000784 overlapping (minoff,maxoff). The same has to happen for any events
785 which implicitly read parts of the guest state: dirty helper calls
786 and loads/stores.
sewardj08210532004-12-29 17:09:11 +0000787*/
788
789static void redundant_put_removal_BB (
sewardjdd40fdf2006-12-24 02:20:24 +0000790 IRSB* bb,
sewardj08210532004-12-29 17:09:11 +0000791 Bool (*preciseMemExnsFn)(Int,Int)
792 )
793{
794 Int i, j;
795 Bool isPut;
796 IRStmt* st;
797 UInt key = 0; /* keep gcc -O happy */
798
799 HashHW* env = newHHW();
800 for (i = bb->stmts_used-1; i >= 0; i--) {
801 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +0000802
803 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +0000804 continue;
805
806 /* Deal with conditional exits. */
807 if (st->tag == Ist_Exit) {
808 /* Since control may not get beyond this point, we must empty
809 out the set, since we can no longer claim that the next
810 event for any part of the guest state is definitely a
811 write. */
sewardj496a58d2005-03-20 18:44:44 +0000812 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +0000813 for (j = 0; j < env->used; j++)
814 env->inuse[j] = False;
815 continue;
816 }
817
818 /* Deal with Puts */
819 switch (st->tag) {
820 case Ist_Put:
821 isPut = True;
822 key = mk_key_GetPut( st->Ist.Put.offset,
823 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
sewardj496a58d2005-03-20 18:44:44 +0000824 vassert(isIRAtom(st->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +0000825 break;
826 case Ist_PutI:
827 isPut = True;
828 key = mk_key_GetIPutI( st->Ist.PutI.descr );
sewardj496a58d2005-03-20 18:44:44 +0000829 vassert(isIRAtom(st->Ist.PutI.ix));
830 vassert(isIRAtom(st->Ist.PutI.data));
sewardj08210532004-12-29 17:09:11 +0000831 break;
832 default:
833 isPut = False;
834 }
835 if (isPut && st->tag != Ist_PutI) {
836 /* See if any single entry in env overlaps this Put. This is
837 simplistic in that the transformation is valid if, say, two
838 or more entries in the env overlap this Put, but the use of
839 lookupHHW will only find a single entry which exactly
840 overlaps this Put. This is suboptimal but safe. */
841 if (lookupHHW(env, NULL, (HWord)key)) {
842 /* This Put is redundant because a later one will overwrite
843 it. So NULL (nop) it out. */
844 if (DEBUG_IROPT) {
845 vex_printf("rPUT: "); ppIRStmt(st);
846 vex_printf("\n");
847 }
sewardjd2445f62005-03-21 00:15:53 +0000848 bb->stmts[i] = IRStmt_NoOp();
sewardj08210532004-12-29 17:09:11 +0000849 } else {
850 /* We can't demonstrate that this Put is redundant, so add it
851 to the running collection. */
852 addToHHW(env, (HWord)key, 0);
853 }
854 continue;
855 }
856
857 /* Deal with Gets. These remove bits of the environment since
858 appearance of a Get means that the next event for that slice
sewardj98430292004-12-29 17:34:50 +0000859 of the guest state is no longer a write, but a read. Also
860 deals with implicit reads of guest state needed to maintain
861 precise exceptions. */
sewardj08210532004-12-29 17:09:11 +0000862 handle_gets_Stmt( env, st, preciseMemExnsFn );
863 }
864}
865
sewardj84be7372004-08-18 13:59:33 +0000866
867/*---------------------------------------------------------------*/
868/*--- Constant propagation and folding ---*/
869/*---------------------------------------------------------------*/
870
sewardj62617ef2004-10-13 23:29:22 +0000871/* The env in this section is a map from IRTemp to IRExpr*,
872 that is, an array indexed by IRTemp. */
sewardjf6501992004-08-27 11:58:24 +0000873
sewardjf6729012004-08-25 12:45:13 +0000874/* Are both expressions simply the same IRTemp ? */
875static Bool sameIRTemps ( IRExpr* e1, IRExpr* e2 )
876{
sewardjdd40fdf2006-12-24 02:20:24 +0000877 return toBool( e1->tag == Iex_RdTmp
878 && e2->tag == Iex_RdTmp
879 && e1->Iex.RdTmp.tmp == e2->Iex.RdTmp.tmp );
sewardjf6729012004-08-25 12:45:13 +0000880}
881
sewardje1d45da2004-11-12 00:13:21 +0000882static Bool notBool ( Bool b )
883{
884 if (b == True) return False;
885 if (b == False) return True;
886 vpanic("notBool");
887}
888
sewardj0033ddc2005-04-26 23:34:34 +0000889/* Make a zero which has the same type as the result of the given
890 primop. */
891static IRExpr* mkZeroForXor ( IROp op )
892{
893 switch (op) {
894 case Iop_Xor8: return IRExpr_Const(IRConst_U8(0));
895 case Iop_Xor16: return IRExpr_Const(IRConst_U16(0));
896 case Iop_Xor32: return IRExpr_Const(IRConst_U32(0));
897 case Iop_Xor64: return IRExpr_Const(IRConst_U64(0));
sewardj04744272007-01-16 19:19:55 +0000898 case Iop_XorV128: return IRExpr_Const(IRConst_V128(0));
sewardj0033ddc2005-04-26 23:34:34 +0000899 default: vpanic("mkZeroForXor: bad primop");
900 }
901}
902
903
sewardj84be7372004-08-18 13:59:33 +0000904static IRExpr* fold_Expr ( IRExpr* e )
905{
sewardj278c44c2004-08-20 00:28:13 +0000906 Int shift;
sewardj84be7372004-08-18 13:59:33 +0000907 IRExpr* e2 = e; /* e2 is the result of folding e, if possible */
908
909 /* UNARY ops */
910 if (e->tag == Iex_Unop
911 && e->Iex.Unop.arg->tag == Iex_Const) {
912 switch (e->Iex.Unop.op) {
sewardjae27ab62004-10-15 21:21:46 +0000913 case Iop_1Uto8:
sewardj9d2e7692005-02-07 01:11:31 +0000914 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardjba999312004-11-15 15:21:17 +0000915 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardj9d2e7692005-02-07 01:11:31 +0000916 ? 1 : 0)));
sewardjae27ab62004-10-15 21:21:46 +0000917 break;
sewardjf4a821d2004-10-09 00:58:19 +0000918 case Iop_1Uto32:
919 e2 = IRExpr_Const(IRConst_U32(
sewardjba999312004-11-15 15:21:17 +0000920 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardjf4a821d2004-10-09 00:58:19 +0000921 ? 1 : 0));
922 break;
sewardj2716ff12005-05-20 19:21:45 +0000923 case Iop_1Uto64:
924 e2 = IRExpr_Const(IRConst_U64(
925 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
926 ? 1 : 0));
927 break;
sewardje6b39932004-11-06 17:01:15 +0000928
sewardj1bee5612005-11-10 18:10:58 +0000929 case Iop_1Sto8:
930 e2 = IRExpr_Const(IRConst_U8(toUChar(
931 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
932 ? 0xFF : 0)));
933 break;
sewardj68884ef2005-07-18 13:58:49 +0000934 case Iop_1Sto16:
sewardj743d8f02005-07-27 00:22:37 +0000935 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardj68884ef2005-07-18 13:58:49 +0000936 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardj743d8f02005-07-27 00:22:37 +0000937 ? 0xFFFF : 0)));
sewardj68884ef2005-07-18 13:58:49 +0000938 break;
sewardjd9997882004-11-04 19:42:59 +0000939 case Iop_1Sto32:
940 e2 = IRExpr_Const(IRConst_U32(
sewardjba999312004-11-15 15:21:17 +0000941 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardjd9997882004-11-04 19:42:59 +0000942 ? 0xFFFFFFFF : 0));
943 break;
sewardje6b39932004-11-06 17:01:15 +0000944 case Iop_1Sto64:
945 e2 = IRExpr_Const(IRConst_U64(
sewardjba999312004-11-15 15:21:17 +0000946 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardje6b39932004-11-06 17:01:15 +0000947 ? 0xFFFFFFFFFFFFFFFFULL : 0));
948 break;
949
sewardj883b00b2004-09-11 09:30:24 +0000950 case Iop_8Sto32: {
951 /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
952 s32 <<= 24;
953 s32 >>= 24;
954 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
955 break;
956 }
sewardj291a7e82005-04-27 11:42:44 +0000957 case Iop_8Uto64:
958 e2 = IRExpr_Const(IRConst_U64(
959 0xFFULL & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
960 break;
961 case Iop_16Uto64:
962 e2 = IRExpr_Const(IRConst_U64(
963 0xFFFFULL & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
964 break;
sewardj84be7372004-08-18 13:59:33 +0000965 case Iop_8Uto32:
966 e2 = IRExpr_Const(IRConst_U32(
967 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
968 break;
969 case Iop_16Uto32:
970 e2 = IRExpr_Const(IRConst_U32(
971 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
972 break;
sewardj73017432004-10-14 19:33:25 +0000973 case Iop_32to16:
sewardj9d2e7692005-02-07 01:11:31 +0000974 e2 = IRExpr_Const(IRConst_U16(toUShort(
975 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
sewardj73017432004-10-14 19:33:25 +0000976 break;
sewardj4345f7a2004-09-22 19:49:27 +0000977 case Iop_32to8:
sewardj9d2e7692005-02-07 01:11:31 +0000978 e2 = IRExpr_Const(IRConst_U8(toUChar(
979 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
sewardj4345f7a2004-09-22 19:49:27 +0000980 break;
sewardj7447b5b2004-10-16 11:30:42 +0000981 case Iop_32to1:
sewardj9d2e7692005-02-07 01:11:31 +0000982 e2 = IRExpr_Const(IRConst_U1(toBool(
983 1 == (1 & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)
984 )));
sewardj7447b5b2004-10-16 11:30:42 +0000985 break;
sewardj291a7e82005-04-27 11:42:44 +0000986 case Iop_64to1:
987 e2 = IRExpr_Const(IRConst_U1(toBool(
988 1 == (1 & e->Iex.Unop.arg->Iex.Const.con->Ico.U64)
989 )));
990 break;
sewardje6b39932004-11-06 17:01:15 +0000991
sewardjf057afb2005-02-27 13:35:41 +0000992 case Iop_Not64:
993 e2 = IRExpr_Const(IRConst_U64(
994 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U64)));
995 break;
sewardj883b00b2004-09-11 09:30:24 +0000996 case Iop_Not32:
997 e2 = IRExpr_Const(IRConst_U32(
998 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
999 break;
sewardje6b39932004-11-06 17:01:15 +00001000 case Iop_Not16:
sewardj9d2e7692005-02-07 01:11:31 +00001001 e2 = IRExpr_Const(IRConst_U16(toUShort(
1002 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U16))));
sewardje6b39932004-11-06 17:01:15 +00001003 break;
sewardjd9997882004-11-04 19:42:59 +00001004 case Iop_Not8:
sewardj9d2e7692005-02-07 01:11:31 +00001005 e2 = IRExpr_Const(IRConst_U8(toUChar(
1006 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U8))));
sewardjd9997882004-11-04 19:42:59 +00001007 break;
sewardje6b39932004-11-06 17:01:15 +00001008
sewardje1d45da2004-11-12 00:13:21 +00001009 case Iop_Not1:
sewardjba999312004-11-15 15:21:17 +00001010 e2 = IRExpr_Const(IRConst_U1(
1011 notBool(e->Iex.Unop.arg->Iex.Const.con->Ico.U1)));
sewardje1d45da2004-11-12 00:13:21 +00001012 break;
1013
sewardj291a7e82005-04-27 11:42:44 +00001014 case Iop_Neg64:
1015 e2 = IRExpr_Const(IRConst_U64(
1016 - (e->Iex.Unop.arg->Iex.Const.con->Ico.U64)));
1017 break;
sewardj0033ddc2005-04-26 23:34:34 +00001018 case Iop_Neg32:
1019 e2 = IRExpr_Const(IRConst_U32(
1020 - (e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
1021 break;
1022 case Iop_Neg8:
sewardj65b17c62005-05-02 15:52:44 +00001023 e2 = IRExpr_Const(IRConst_U8(toUChar(
1024 - (e->Iex.Unop.arg->Iex.Const.con->Ico.U8))));
sewardj0033ddc2005-04-26 23:34:34 +00001025 break;
1026
sewardj291a7e82005-04-27 11:42:44 +00001027 case Iop_64to8: {
1028 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1029 w64 &= 0xFFULL;
1030 e2 = IRExpr_Const(IRConst_U8( (UChar)w64 ));
1031 break;
1032 }
1033 case Iop_64to16: {
1034 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1035 w64 &= 0xFFFFULL;
sewardje85bc402005-05-06 16:29:26 +00001036 e2 = IRExpr_Const(IRConst_U16( (UShort)w64 ));
sewardj291a7e82005-04-27 11:42:44 +00001037 break;
1038 }
sewardj1d8ce202004-12-13 14:14:16 +00001039 case Iop_64to32: {
1040 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1041 w64 &= 0x00000000FFFFFFFFULL;
1042 e2 = IRExpr_Const(IRConst_U32( (UInt)w64 ));
sewardj37010592004-12-13 10:47:15 +00001043 break;
sewardj1d8ce202004-12-13 14:14:16 +00001044 }
sewardj1d8ce202004-12-13 14:14:16 +00001045 case Iop_64HIto32: {
1046 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1047 w64 >>= 32;
1048 e2 = IRExpr_Const(IRConst_U32( (UInt)w64 ));
1049 break;
1050 }
sewardjb5710b82005-01-27 16:05:09 +00001051 case Iop_32Uto64:
1052 e2 = IRExpr_Const(IRConst_U64(
1053 0xFFFFFFFFULL
1054 & e->Iex.Unop.arg->Iex.Const.con->Ico.U32));
1055 break;
sewardj37010592004-12-13 10:47:15 +00001056
sewardj0033ddc2005-04-26 23:34:34 +00001057 case Iop_CmpNEZ8:
1058 e2 = IRExpr_Const(IRConst_U1(toBool(
1059 0 !=
1060 (0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8)
1061 )));
1062 break;
1063 case Iop_CmpNEZ32:
1064 e2 = IRExpr_Const(IRConst_U1(toBool(
1065 0 !=
1066 (0xFFFFFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)
1067 )));
1068 break;
1069 case Iop_CmpNEZ64:
1070 e2 = IRExpr_Const(IRConst_U1(toBool(
1071 0ULL != e->Iex.Unop.arg->Iex.Const.con->Ico.U64
1072 )));
1073 break;
1074
sewardj84be7372004-08-18 13:59:33 +00001075 default:
1076 goto unhandled;
1077 }
1078 }
1079
1080 /* BINARY ops */
1081 if (e->tag == Iex_Binop) {
1082 if (e->Iex.Binop.arg1->tag == Iex_Const
1083 && e->Iex.Binop.arg2->tag == Iex_Const) {
1084 /* cases where both args are consts */
1085 switch (e->Iex.Binop.op) {
sewardje6b39932004-11-06 17:01:15 +00001086
sewardj855dc722005-02-17 09:26:05 +00001087 /* -- Or -- */
sewardjd9997882004-11-04 19:42:59 +00001088 case Iop_Or8:
sewardj9d2e7692005-02-07 01:11:31 +00001089 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardjd9997882004-11-04 19:42:59 +00001090 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001091 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardjd9997882004-11-04 19:42:59 +00001092 break;
sewardje6b39932004-11-06 17:01:15 +00001093 case Iop_Or16:
sewardj9d2e7692005-02-07 01:11:31 +00001094 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardje6b39932004-11-06 17:01:15 +00001095 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
sewardj9d2e7692005-02-07 01:11:31 +00001096 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
sewardje6b39932004-11-06 17:01:15 +00001097 break;
1098 case Iop_Or32:
1099 e2 = IRExpr_Const(IRConst_U32(
1100 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1101 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1102 break;
sewardjf057afb2005-02-27 13:35:41 +00001103 case Iop_Or64:
1104 e2 = IRExpr_Const(IRConst_U64(
1105 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1106 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1107 break;
sewardje6b39932004-11-06 17:01:15 +00001108
sewardj855dc722005-02-17 09:26:05 +00001109 /* -- Xor -- */
sewardj883b00b2004-09-11 09:30:24 +00001110 case Iop_Xor8:
sewardj9d2e7692005-02-07 01:11:31 +00001111 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj883b00b2004-09-11 09:30:24 +00001112 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001113 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj883b00b2004-09-11 09:30:24 +00001114 break;
sewardj82c9f2f2005-03-02 16:05:13 +00001115 case Iop_Xor16:
sewardjc7c098f2005-03-21 01:06:20 +00001116 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardj82c9f2f2005-03-02 16:05:13 +00001117 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
sewardjc7c098f2005-03-21 01:06:20 +00001118 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
sewardj82c9f2f2005-03-02 16:05:13 +00001119 break;
sewardj855dc722005-02-17 09:26:05 +00001120 case Iop_Xor32:
1121 e2 = IRExpr_Const(IRConst_U32(
1122 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1123 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1124 break;
sewardjf057afb2005-02-27 13:35:41 +00001125 case Iop_Xor64:
1126 e2 = IRExpr_Const(IRConst_U64(
1127 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1128 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1129 break;
sewardj855dc722005-02-17 09:26:05 +00001130
1131 /* -- And -- */
sewardj84be7372004-08-18 13:59:33 +00001132 case Iop_And8:
sewardj9d2e7692005-02-07 01:11:31 +00001133 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj84be7372004-08-18 13:59:33 +00001134 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001135 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj84be7372004-08-18 13:59:33 +00001136 break;
sewardj855dc722005-02-17 09:26:05 +00001137 case Iop_And32:
1138 e2 = IRExpr_Const(IRConst_U32(
1139 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1140 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1141 break;
1142 case Iop_And64:
1143 e2 = IRExpr_Const(IRConst_U64(
1144 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1145 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1146 break;
1147
1148 /* -- Add -- */
sewardj4345f7a2004-09-22 19:49:27 +00001149 case Iop_Add8:
sewardj9d2e7692005-02-07 01:11:31 +00001150 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj4345f7a2004-09-22 19:49:27 +00001151 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001152 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj4345f7a2004-09-22 19:49:27 +00001153 break;
sewardj855dc722005-02-17 09:26:05 +00001154 case Iop_Add32:
1155 e2 = IRExpr_Const(IRConst_U32(
1156 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1157 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1158 break;
1159 case Iop_Add64:
1160 e2 = IRExpr_Const(IRConst_U64(
1161 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1162 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1163 break;
1164
1165 /* -- Sub -- */
sewardj84be7372004-08-18 13:59:33 +00001166 case Iop_Sub8:
sewardj9d2e7692005-02-07 01:11:31 +00001167 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj84be7372004-08-18 13:59:33 +00001168 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001169 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj84be7372004-08-18 13:59:33 +00001170 break;
sewardjd7217032004-08-19 10:49:10 +00001171 case Iop_Sub32:
1172 e2 = IRExpr_Const(IRConst_U32(
1173 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1174 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1175 break;
sewardj70a8ddf2005-02-13 02:24:26 +00001176 case Iop_Sub64:
1177 e2 = IRExpr_Const(IRConst_U64(
1178 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1179 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1180 break;
sewardjc2bcb6f2005-02-07 00:17:12 +00001181
sewardj855dc722005-02-17 09:26:05 +00001182 /* -- Mul -- */
sewardjb9c5cf62004-08-24 15:10:38 +00001183 case Iop_Mul32:
1184 e2 = IRExpr_Const(IRConst_U32(
1185 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1186 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1187 break;
sewardja34c0712005-03-30 23:19:46 +00001188 case Iop_Mul64:
1189 e2 = IRExpr_Const(IRConst_U64(
1190 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1191 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1192 break;
1193
sewardjea6bccb2005-03-01 10:19:23 +00001194 case Iop_MullS32: {
1195 /* very paranoid */
1196 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1197 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1198 Int s32a = (Int)u32a;
1199 Int s32b = (Int)u32b;
1200 Long s64a = (Long)s32a;
1201 Long s64b = (Long)s32b;
1202 Long sres = s64a * s64b;
1203 ULong ures = (ULong)sres;
1204 e2 = IRExpr_Const(IRConst_U64(ures));
1205 break;
1206 }
sewardjb095fba2005-02-13 14:13:04 +00001207
sewardj855dc722005-02-17 09:26:05 +00001208 /* -- Shl -- */
sewardjd7217032004-08-19 10:49:10 +00001209 case Iop_Shl32:
sewardj61348472004-08-20 01:01:04 +00001210 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1211 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj29632392004-08-22 02:38:11 +00001212 if (shift >= 0 && shift <= 31)
sewardj278c44c2004-08-20 00:28:13 +00001213 e2 = IRExpr_Const(IRConst_U32(
1214 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1215 << shift)));
sewardjd7217032004-08-19 10:49:10 +00001216 break;
sewardjb095fba2005-02-13 14:13:04 +00001217 case Iop_Shl64:
1218 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1219 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1220 if (shift >= 0 && shift <= 63)
1221 e2 = IRExpr_Const(IRConst_U64(
1222 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1223 << shift)));
1224 break;
1225
sewardj855dc722005-02-17 09:26:05 +00001226 /* -- Sar -- */
sewardj278c44c2004-08-20 00:28:13 +00001227 case Iop_Sar32: {
1228 /* paranoid ... */
1229 /*signed*/ Int s32;
sewardj61348472004-08-20 01:01:04 +00001230 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj278c44c2004-08-20 00:28:13 +00001231 s32 = (Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +00001232 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj278c44c2004-08-20 00:28:13 +00001233 if (shift >= 0 && shift <= 31) {
1234 s32 >>=/*signed*/ shift;
1235 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
1236 }
1237 break;
1238 }
sewardj855dc722005-02-17 09:26:05 +00001239 case Iop_Sar64: {
1240 /* paranoid ... */
1241 /*signed*/ Long s64;
1242 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1243 s64 = (Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64);
1244 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1245 if (shift >= 0 && shift <= 63) {
1246 s64 >>=/*signed*/ shift;
1247 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1248 }
1249 break;
1250 }
1251
1252 /* -- Shr -- */
sewardj61348472004-08-20 01:01:04 +00001253 case Iop_Shr32: {
1254 /* paranoid ... */
sewardj4add7142005-02-21 08:20:22 +00001255 /*unsigned*/ UInt u32;
sewardj61348472004-08-20 01:01:04 +00001256 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj4add7142005-02-21 08:20:22 +00001257 u32 = (UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +00001258 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1259 if (shift >= 0 && shift <= 31) {
sewardj4add7142005-02-21 08:20:22 +00001260 u32 >>=/*unsigned*/ shift;
1261 e2 = IRExpr_Const(IRConst_U32(u32));
1262 }
1263 break;
1264 }
1265 case Iop_Shr64: {
1266 /* paranoid ... */
1267 /*unsigned*/ ULong u64;
1268 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1269 u64 = (ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64);
1270 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1271 if (shift >= 0 && shift <= 63) {
1272 u64 >>=/*unsigned*/ shift;
1273 e2 = IRExpr_Const(IRConst_U64(u64));
sewardj61348472004-08-20 01:01:04 +00001274 }
1275 break;
1276 }
sewardj855dc722005-02-17 09:26:05 +00001277
1278 /* -- CmpEQ -- */
sewardjb8e75862004-08-19 17:58:45 +00001279 case Iop_CmpEQ32:
sewardj9d2e7692005-02-07 01:11:31 +00001280 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardjb8e75862004-08-19 17:58:45 +00001281 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
sewardj9d2e7692005-02-07 01:11:31 +00001282 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))));
sewardjb8e75862004-08-19 17:58:45 +00001283 break;
sewardj855dc722005-02-17 09:26:05 +00001284 case Iop_CmpEQ64:
1285 e2 = IRExpr_Const(IRConst_U1(toBool(
1286 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1287 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U64))));
1288 break;
1289
1290 /* -- CmpNE -- */
1291 case Iop_CmpNE8:
1292 e2 = IRExpr_Const(IRConst_U1(toBool(
1293 ((0xFF & e->Iex.Binop.arg1->Iex.Const.con->Ico.U8)
1294 != (0xFF & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)))));
1295 break;
sewardjae27ab62004-10-15 21:21:46 +00001296 case Iop_CmpNE32:
sewardj9d2e7692005-02-07 01:11:31 +00001297 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardjae27ab62004-10-15 21:21:46 +00001298 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
sewardj9d2e7692005-02-07 01:11:31 +00001299 != e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))));
sewardjae27ab62004-10-15 21:21:46 +00001300 break;
sewardje6b39932004-11-06 17:01:15 +00001301 case Iop_CmpNE64:
sewardj9d2e7692005-02-07 01:11:31 +00001302 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardje6b39932004-11-06 17:01:15 +00001303 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
sewardj9d2e7692005-02-07 01:11:31 +00001304 != e->Iex.Binop.arg2->Iex.Const.con->Ico.U64))));
sewardje6b39932004-11-06 17:01:15 +00001305 break;
1306
sewardj855dc722005-02-17 09:26:05 +00001307 /* -- CmpLEU -- */
sewardj7447b5b2004-10-16 11:30:42 +00001308 case Iop_CmpLE32U:
sewardj9d2e7692005-02-07 01:11:31 +00001309 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj7447b5b2004-10-16 11:30:42 +00001310 ((UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001311 <= (UInt)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj7447b5b2004-10-16 11:30:42 +00001312 break;
sewardj855dc722005-02-17 09:26:05 +00001313
1314 /* -- CmpLES -- */
sewardj088e4f72004-10-19 01:25:02 +00001315 case Iop_CmpLE32S:
sewardj9d2e7692005-02-07 01:11:31 +00001316 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj088e4f72004-10-19 01:25:02 +00001317 ((Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001318 <= (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj088e4f72004-10-19 01:25:02 +00001319 break;
sewardje1d45da2004-11-12 00:13:21 +00001320
sewardj855dc722005-02-17 09:26:05 +00001321 /* -- CmpLTS -- */
sewardj9bdd2652004-10-19 12:56:33 +00001322 case Iop_CmpLT32S:
sewardj9d2e7692005-02-07 01:11:31 +00001323 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj9bdd2652004-10-19 12:56:33 +00001324 ((Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001325 < (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj9bdd2652004-10-19 12:56:33 +00001326 break;
sewardj855dc722005-02-17 09:26:05 +00001327
1328 /* -- CmpLTU -- */
sewardje1d45da2004-11-12 00:13:21 +00001329 case Iop_CmpLT32U:
sewardj9d2e7692005-02-07 01:11:31 +00001330 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardje1d45da2004-11-12 00:13:21 +00001331 ((UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001332 < (UInt)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardje1d45da2004-11-12 00:13:21 +00001333 break;
sewardj7447b5b2004-10-16 11:30:42 +00001334
sewardjb51f0f42005-07-18 11:38:02 +00001335 /* -- CmpORD -- */
1336 case Iop_CmpORD32S: {
1337 /* very paranoid */
1338 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1339 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1340 Int s32a = (Int)u32a;
1341 Int s32b = (Int)u32b;
1342 Int r = 0x2; /* EQ */
1343 if (s32a < s32b) {
1344 r = 0x8; /* LT */
1345 }
1346 else if (s32a > s32b) {
1347 r = 0x4; /* GT */
1348 }
1349 e2 = IRExpr_Const(IRConst_U32(r));
1350 break;
1351 }
1352
sewardj855dc722005-02-17 09:26:05 +00001353 /* -- nHLto2n -- */
sewardj088bcb42004-08-19 17:16:52 +00001354 case Iop_32HLto64:
1355 e2 = IRExpr_Const(IRConst_U64(
1356 (((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)) << 32)
1357 | ((ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))
1358 ));
1359 break;
sewardj3bc8a592005-05-02 10:47:22 +00001360 case Iop_64HLto128:
1361 /* We can't fold this, because there is no way to
1362 express he result in IR, but at least pretend to
1363 handle it, so as to stop getting blasted with
1364 no-rule-for-this-primop messages. */
1365 break;
sewardj855dc722005-02-17 09:26:05 +00001366
sewardj607dd4f2004-09-08 18:20:19 +00001367 default:
1368 goto unhandled;
sewardjd7217032004-08-19 10:49:10 +00001369 }
sewardjf6729012004-08-25 12:45:13 +00001370
sewardj84be7372004-08-18 13:59:33 +00001371 } else {
sewardjf6729012004-08-25 12:45:13 +00001372
sewardj84be7372004-08-18 13:59:33 +00001373 /* other cases (identities, etc) */
sewardj291a7e82005-04-27 11:42:44 +00001374
1375 /* Shl64/Shr64(x,0) ==> x */
1376 if ((e->Iex.Binop.op == Iop_Shl64 || e->Iex.Binop.op == Iop_Shr64)
1377 && e->Iex.Binop.arg2->tag == Iex_Const
1378 && e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 == 0) {
1379 e2 = e->Iex.Binop.arg1;
1380 } else
1381
sewardj4afab822005-01-20 10:04:05 +00001382 /* Shl32/Shr32(x,0) ==> x */
1383 if ((e->Iex.Binop.op == Iop_Shl32 || e->Iex.Binop.op == Iop_Shr32)
sewardj52345402004-10-13 16:08:14 +00001384 && e->Iex.Binop.arg2->tag == Iex_Const
sewardj4980c6b2004-10-13 16:16:27 +00001385 && e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 == 0) {
sewardj52345402004-10-13 16:08:14 +00001386 e2 = e->Iex.Binop.arg1;
1387 } else
1388
sewardj8ac9bc92005-04-21 01:35:48 +00001389 /* Or8(x,0) ==> x */
1390 if ((e->Iex.Binop.op == Iop_Or8)
1391 && e->Iex.Binop.arg2->tag == Iex_Const
1392 && e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 == 0) {
1393 e2 = e->Iex.Binop.arg1;
1394 } else
1395
sewardj0033ddc2005-04-26 23:34:34 +00001396 /* Or16(x,0) ==> x */
1397 if ((e->Iex.Binop.op == Iop_Or16)
1398 && e->Iex.Binop.arg2->tag == Iex_Const
1399 && e->Iex.Binop.arg2->Iex.Const.con->Ico.U16 == 0) {
1400 e2 = e->Iex.Binop.arg1;
1401 } else
1402
sewardjd9997882004-11-04 19:42:59 +00001403 /* Or32/Add32(x,0) ==> x */
1404 if ((e->Iex.Binop.op == Iop_Add32 || e->Iex.Binop.op == Iop_Or32)
sewardj84be7372004-08-18 13:59:33 +00001405 && e->Iex.Binop.arg2->tag == Iex_Const
1406 && e->Iex.Binop.arg2->Iex.Const.con->Ico.U32 == 0) {
1407 e2 = e->Iex.Binop.arg1;
sewardjf6729012004-08-25 12:45:13 +00001408 } else
1409
sewardj89d89e92006-05-14 18:46:55 +00001410 /* Add32(t,t) ==> t << 1. Memcheck doesn't understand that
1411 x+x produces a defined least significant bit, and it seems
1412 simplest just to get rid of the problem by rewriting it
1413 out, since the opportunity to do so exists. */
1414 if (e->Iex.Binop.op == Iop_Add32
sewardjdd40fdf2006-12-24 02:20:24 +00001415 && e->Iex.Binop.arg1->tag == Iex_RdTmp
1416 && e->Iex.Binop.arg2->tag == Iex_RdTmp
1417 && e->Iex.Binop.arg1->Iex.RdTmp.tmp
1418 == e->Iex.Binop.arg2->Iex.RdTmp.tmp) {
sewardj89d89e92006-05-14 18:46:55 +00001419 e2 = IRExpr_Binop(Iop_Shl32,
1420 e->Iex.Binop.arg1,
1421 IRExpr_Const(IRConst_U8(1)));
1422 } else
1423
sewardj346d9a12006-05-21 01:02:31 +00001424 /* Add64(t,t) ==> t << 1; rationale as for Add32(t,t) above. */
1425 if (e->Iex.Binop.op == Iop_Add64
sewardjdd40fdf2006-12-24 02:20:24 +00001426 && e->Iex.Binop.arg1->tag == Iex_RdTmp
1427 && e->Iex.Binop.arg2->tag == Iex_RdTmp
1428 && e->Iex.Binop.arg1->Iex.RdTmp.tmp
1429 == e->Iex.Binop.arg2->Iex.RdTmp.tmp) {
sewardj346d9a12006-05-21 01:02:31 +00001430 e2 = IRExpr_Binop(Iop_Shl64,
1431 e->Iex.Binop.arg1,
1432 IRExpr_Const(IRConst_U8(1)));
1433 } else
1434
sewardjdcd6c882004-12-16 11:41:06 +00001435 /* Or64/Add64(x,0) ==> x */
1436 if ((e->Iex.Binop.op == Iop_Add64 || e->Iex.Binop.op == Iop_Or64)
1437 && e->Iex.Binop.arg2->tag == Iex_Const
1438 && e->Iex.Binop.arg2->Iex.Const.con->Ico.U64 == 0) {
1439 e2 = e->Iex.Binop.arg1;
1440 } else
1441
sewardj832853b2004-11-06 12:10:04 +00001442 /* And32(x,0xFFFFFFFF) ==> x */
1443 if (e->Iex.Binop.op == Iop_And32
1444 && e->Iex.Binop.arg2->tag == Iex_Const
1445 && e->Iex.Binop.arg2->Iex.Const.con->Ico.U32 == 0xFFFFFFFF) {
1446 e2 = e->Iex.Binop.arg1;
1447 } else
1448
sewardj23256992005-07-01 10:51:24 +00001449 /* And32(x,0) ==> 0 */
1450 if (e->Iex.Binop.op == Iop_And32
1451 && e->Iex.Binop.arg2->tag == Iex_Const
1452 && e->Iex.Binop.arg2->Iex.Const.con->Ico.U32 == 0) {
1453 e2 = IRExpr_Const(IRConst_U32(0));
1454 } else
1455
sewardjb183b852006-02-03 16:08:03 +00001456 /* And32(0,x) ==> 0 */
1457 if (e->Iex.Binop.op == Iop_And32
1458 && e->Iex.Binop.arg1->tag == Iex_Const
1459 && e->Iex.Binop.arg1->Iex.Const.con->Ico.U32 == 0) {
1460 e2 = IRExpr_Const(IRConst_U32(0));
1461 } else
1462
sewardjd9997882004-11-04 19:42:59 +00001463 /* Or32(0,x) ==> x */
1464 if (e->Iex.Binop.op == Iop_Or32
1465 && e->Iex.Binop.arg1->tag == Iex_Const
1466 && e->Iex.Binop.arg1->Iex.Const.con->Ico.U32 == 0) {
1467 e2 = e->Iex.Binop.arg2;
1468 } else
1469
sewardjb183b852006-02-03 16:08:03 +00001470 /* Or64(0,x) ==> x */
1471 if (e->Iex.Binop.op == Iop_Or64
1472 && e->Iex.Binop.arg1->tag == Iex_Const
1473 && e->Iex.Binop.arg1->Iex.Const.con->Ico.U64 == 0) {
1474 e2 = e->Iex.Binop.arg2;
1475 } else
1476
sewardjdcd6c882004-12-16 11:41:06 +00001477 /* Or8/16/32/64(t,t) ==> t, for some IRTemp t */
1478 /* And8/16/32/64(t,t) ==> t, for some IRTemp t */
1479 if ( (e->Iex.Binop.op == Iop_And64
1480 || e->Iex.Binop.op == Iop_And32
sewardjf6729012004-08-25 12:45:13 +00001481 || e->Iex.Binop.op == Iop_And16
sewardjdcd6c882004-12-16 11:41:06 +00001482 || e->Iex.Binop.op == Iop_And8
1483 || e->Iex.Binop.op == Iop_Or64
1484 || e->Iex.Binop.op == Iop_Or32
1485 || e->Iex.Binop.op == Iop_Or16
1486 || e->Iex.Binop.op == Iop_Or8)
sewardjf6729012004-08-25 12:45:13 +00001487 && sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
1488 e2 = e->Iex.Binop.arg1;
sewardjaba4fff2004-10-08 21:37:15 +00001489 }
sewardjf6729012004-08-25 12:45:13 +00001490
sewardj04744272007-01-16 19:19:55 +00001491 /* Xor8/16/32/64/V128(t,t) ==> 0, for some IRTemp t */
sewardj0033ddc2005-04-26 23:34:34 +00001492 if ( (e->Iex.Binop.op == Iop_Xor64
1493 || e->Iex.Binop.op == Iop_Xor32
1494 || e->Iex.Binop.op == Iop_Xor16
sewardj04744272007-01-16 19:19:55 +00001495 || e->Iex.Binop.op == Iop_Xor8
1496 || e->Iex.Binop.op == Iop_XorV128)
sewardj0033ddc2005-04-26 23:34:34 +00001497 && sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj0033ddc2005-04-26 23:34:34 +00001498 e2 = mkZeroForXor(e->Iex.Binop.op);
1499 }
1500
sewardj84be7372004-08-18 13:59:33 +00001501 }
1502 }
1503
1504 /* Mux0X */
1505 if (e->tag == Iex_Mux0X
1506 && e->Iex.Mux0X.cond->tag == Iex_Const) {
1507 Bool zero;
1508 /* assured us by the IR type rules */
1509 vassert(e->Iex.Mux0X.cond->Iex.Const.con->tag == Ico_U8);
sewardj9d2e7692005-02-07 01:11:31 +00001510 zero = toBool(0 == (0xFF & e->Iex.Mux0X.cond
1511 ->Iex.Const.con->Ico.U8));
sewardj84be7372004-08-18 13:59:33 +00001512 e2 = zero ? e->Iex.Mux0X.expr0 : e->Iex.Mux0X.exprX;
1513 }
1514
sewardj088bcb42004-08-19 17:16:52 +00001515 if (DEBUG_IROPT && e2 != e) {
1516 vex_printf("FOLD: ");
sewardj84be7372004-08-18 13:59:33 +00001517 ppIRExpr(e); vex_printf(" -> ");
1518 ppIRExpr(e2); vex_printf("\n");
1519 }
1520
1521 return e2;
1522
1523 unhandled:
sewardj883b00b2004-09-11 09:30:24 +00001524# if 0
sewardj84be7372004-08-18 13:59:33 +00001525 vex_printf("\n\n");
1526 ppIRExpr(e);
1527 vpanic("fold_Expr: no rule for the above");
sewardj883b00b2004-09-11 09:30:24 +00001528# else
sewardj328b54b2005-06-13 16:30:18 +00001529 if (vex_control.iropt_verbosity > 0) {
1530 vex_printf("vex iropt: fold_Expr: no rule for: ");
1531 ppIRExpr(e);
1532 vex_printf("\n");
1533 }
sewardj883b00b2004-09-11 09:30:24 +00001534 return e2;
1535# endif
sewardj84be7372004-08-18 13:59:33 +00001536}
1537
1538
sewardj84be7372004-08-18 13:59:33 +00001539/* Apply the subst to a simple 1-level expression -- guaranteed to be
1540 1-level due to previous flattening pass. */
1541
sewardj62617ef2004-10-13 23:29:22 +00001542static IRExpr* subst_Expr ( IRExpr** env, IRExpr* ex )
sewardj84be7372004-08-18 13:59:33 +00001543{
sewardj62617ef2004-10-13 23:29:22 +00001544 switch (ex->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +00001545 case Iex_RdTmp:
1546 if (env[(Int)ex->Iex.RdTmp.tmp] != NULL) {
1547 return env[(Int)ex->Iex.RdTmp.tmp];
sewardj62617ef2004-10-13 23:29:22 +00001548 } else {
1549 /* not bound in env */
1550 return ex;
1551 }
1552
1553 case Iex_Const:
1554 case Iex_Get:
sewardj84be7372004-08-18 13:59:33 +00001555 return ex;
sewardj62617ef2004-10-13 23:29:22 +00001556
1557 case Iex_GetI:
sewardj496a58d2005-03-20 18:44:44 +00001558 vassert(isIRAtom(ex->Iex.GetI.ix));
sewardj62617ef2004-10-13 23:29:22 +00001559 return IRExpr_GetI(
1560 ex->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +00001561 subst_Expr(env, ex->Iex.GetI.ix),
sewardj62617ef2004-10-13 23:29:22 +00001562 ex->Iex.GetI.bias
1563 );
1564
sewardj40c80262006-02-08 19:30:46 +00001565 case Iex_Qop:
1566 vassert(isIRAtom(ex->Iex.Qop.arg1));
1567 vassert(isIRAtom(ex->Iex.Qop.arg2));
1568 vassert(isIRAtom(ex->Iex.Qop.arg3));
1569 vassert(isIRAtom(ex->Iex.Qop.arg4));
1570 return IRExpr_Qop(
1571 ex->Iex.Qop.op,
1572 subst_Expr(env, ex->Iex.Qop.arg1),
1573 subst_Expr(env, ex->Iex.Qop.arg2),
1574 subst_Expr(env, ex->Iex.Qop.arg3),
1575 subst_Expr(env, ex->Iex.Qop.arg4)
1576 );
1577
sewardjb183b852006-02-03 16:08:03 +00001578 case Iex_Triop:
1579 vassert(isIRAtom(ex->Iex.Triop.arg1));
1580 vassert(isIRAtom(ex->Iex.Triop.arg2));
1581 vassert(isIRAtom(ex->Iex.Triop.arg3));
1582 return IRExpr_Triop(
1583 ex->Iex.Triop.op,
1584 subst_Expr(env, ex->Iex.Triop.arg1),
1585 subst_Expr(env, ex->Iex.Triop.arg2),
1586 subst_Expr(env, ex->Iex.Triop.arg3)
1587 );
1588
sewardj62617ef2004-10-13 23:29:22 +00001589 case Iex_Binop:
sewardj496a58d2005-03-20 18:44:44 +00001590 vassert(isIRAtom(ex->Iex.Binop.arg1));
1591 vassert(isIRAtom(ex->Iex.Binop.arg2));
sewardj62617ef2004-10-13 23:29:22 +00001592 return IRExpr_Binop(
1593 ex->Iex.Binop.op,
1594 subst_Expr(env, ex->Iex.Binop.arg1),
1595 subst_Expr(env, ex->Iex.Binop.arg2)
1596 );
1597
1598 case Iex_Unop:
sewardj496a58d2005-03-20 18:44:44 +00001599 vassert(isIRAtom(ex->Iex.Unop.arg));
sewardj62617ef2004-10-13 23:29:22 +00001600 return IRExpr_Unop(
1601 ex->Iex.Unop.op,
1602 subst_Expr(env, ex->Iex.Unop.arg)
1603 );
1604
sewardjaf1ceca2005-06-30 23:31:27 +00001605 case Iex_Load:
1606 vassert(isIRAtom(ex->Iex.Load.addr));
1607 return IRExpr_Load(
1608 ex->Iex.Load.end,
1609 ex->Iex.Load.ty,
1610 subst_Expr(env, ex->Iex.Load.addr)
sewardj62617ef2004-10-13 23:29:22 +00001611 );
1612
1613 case Iex_CCall: {
1614 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +00001615 IRExpr** args2 = shallowCopyIRExprVec(ex->Iex.CCall.args);
sewardj62617ef2004-10-13 23:29:22 +00001616 for (i = 0; args2[i]; i++) {
sewardj496a58d2005-03-20 18:44:44 +00001617 vassert(isIRAtom(args2[i]));
sewardj62617ef2004-10-13 23:29:22 +00001618 args2[i] = subst_Expr(env, args2[i]);
1619 }
1620 return IRExpr_CCall(
sewardj8ea867b2004-10-30 19:03:02 +00001621 ex->Iex.CCall.cee,
sewardj62617ef2004-10-13 23:29:22 +00001622 ex->Iex.CCall.retty,
1623 args2
1624 );
sewardj84be7372004-08-18 13:59:33 +00001625 }
sewardj62617ef2004-10-13 23:29:22 +00001626
1627 case Iex_Mux0X:
sewardj496a58d2005-03-20 18:44:44 +00001628 vassert(isIRAtom(ex->Iex.Mux0X.cond));
1629 vassert(isIRAtom(ex->Iex.Mux0X.expr0));
1630 vassert(isIRAtom(ex->Iex.Mux0X.exprX));
sewardj62617ef2004-10-13 23:29:22 +00001631 return IRExpr_Mux0X(
1632 subst_Expr(env, ex->Iex.Mux0X.cond),
1633 subst_Expr(env, ex->Iex.Mux0X.expr0),
1634 subst_Expr(env, ex->Iex.Mux0X.exprX)
1635 );
1636
1637 default:
1638 vex_printf("\n\n"); ppIRExpr(ex);
1639 vpanic("subst_Expr");
1640
sewardj84be7372004-08-18 13:59:33 +00001641 }
sewardj84be7372004-08-18 13:59:33 +00001642}
1643
1644
1645/* Apply the subst to stmt, then fold the result as much as possible.
sewardjd2445f62005-03-21 00:15:53 +00001646 Much simplified due to stmt being previously flattened. As a
1647 result of this, the stmt may wind up being turned into a no-op.
1648*/
sewardj62617ef2004-10-13 23:29:22 +00001649static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st )
sewardj84be7372004-08-18 13:59:33 +00001650{
1651# if 0
1652 vex_printf("\nsubst and fold stmt\n");
1653 ppIRStmt(st);
1654 vex_printf("\n");
1655# endif
1656
sewardj62617ef2004-10-13 23:29:22 +00001657 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00001658 case Ist_AbiHint:
1659 vassert(isIRAtom(st->Ist.AbiHint.base));
1660 return IRStmt_AbiHint(
1661 fold_Expr(subst_Expr(env, st->Ist.AbiHint.base)),
1662 st->Ist.AbiHint.len
1663 );
sewardj62617ef2004-10-13 23:29:22 +00001664 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00001665 vassert(isIRAtom(st->Ist.Put.data));
sewardj62617ef2004-10-13 23:29:22 +00001666 return IRStmt_Put(
1667 st->Ist.Put.offset,
1668 fold_Expr(subst_Expr(env, st->Ist.Put.data))
1669 );
sewardj84be7372004-08-18 13:59:33 +00001670
sewardj62617ef2004-10-13 23:29:22 +00001671 case Ist_PutI:
sewardj496a58d2005-03-20 18:44:44 +00001672 vassert(isIRAtom(st->Ist.PutI.ix));
1673 vassert(isIRAtom(st->Ist.PutI.data));
sewardj62617ef2004-10-13 23:29:22 +00001674 return IRStmt_PutI(
1675 st->Ist.PutI.descr,
sewardjeeac8412004-11-02 00:26:55 +00001676 fold_Expr(subst_Expr(env, st->Ist.PutI.ix)),
sewardj62617ef2004-10-13 23:29:22 +00001677 st->Ist.PutI.bias,
1678 fold_Expr(subst_Expr(env, st->Ist.PutI.data))
1679 );
sewardjd7217032004-08-19 10:49:10 +00001680
sewardjdd40fdf2006-12-24 02:20:24 +00001681 case Ist_WrTmp:
1682 /* This is the one place where an expr (st->Ist.WrTmp.data) is
sewardj62617ef2004-10-13 23:29:22 +00001683 allowed to be more than just a constant or a tmp. */
sewardjdd40fdf2006-12-24 02:20:24 +00001684 return IRStmt_WrTmp(
1685 st->Ist.WrTmp.tmp,
1686 fold_Expr(subst_Expr(env, st->Ist.WrTmp.data))
sewardj62617ef2004-10-13 23:29:22 +00001687 );
sewardj84be7372004-08-18 13:59:33 +00001688
sewardjaf1ceca2005-06-30 23:31:27 +00001689 case Ist_Store:
1690 vassert(isIRAtom(st->Ist.Store.addr));
1691 vassert(isIRAtom(st->Ist.Store.data));
1692 return IRStmt_Store(
1693 st->Ist.Store.end,
1694 fold_Expr(subst_Expr(env, st->Ist.Store.addr)),
1695 fold_Expr(subst_Expr(env, st->Ist.Store.data))
sewardj62617ef2004-10-13 23:29:22 +00001696 );
sewardj84be7372004-08-18 13:59:33 +00001697
sewardj62617ef2004-10-13 23:29:22 +00001698 case Ist_Dirty: {
1699 Int i;
1700 IRDirty *d, *d2;
1701 d = st->Ist.Dirty.details;
1702 d2 = emptyIRDirty();
1703 *d2 = *d;
sewardjdd40fdf2006-12-24 02:20:24 +00001704 d2->args = shallowCopyIRExprVec(d2->args);
sewardj62617ef2004-10-13 23:29:22 +00001705 if (d2->mFx != Ifx_None) {
sewardj496a58d2005-03-20 18:44:44 +00001706 vassert(isIRAtom(d2->mAddr));
sewardj62617ef2004-10-13 23:29:22 +00001707 d2->mAddr = fold_Expr(subst_Expr(env, d2->mAddr));
sewardjb8e75862004-08-19 17:58:45 +00001708 }
sewardj496a58d2005-03-20 18:44:44 +00001709 vassert(isIRAtom(d2->guard));
sewardjb8385d82004-11-02 01:34:15 +00001710 d2->guard = fold_Expr(subst_Expr(env, d2->guard));
sewardj62617ef2004-10-13 23:29:22 +00001711 for (i = 0; d2->args[i]; i++) {
sewardj496a58d2005-03-20 18:44:44 +00001712 vassert(isIRAtom(d2->args[i]));
sewardj62617ef2004-10-13 23:29:22 +00001713 d2->args[i] = fold_Expr(subst_Expr(env, d2->args[i]));
1714 }
1715 return IRStmt_Dirty(d2);
sewardjb8e75862004-08-19 17:58:45 +00001716 }
sewardj84be7372004-08-18 13:59:33 +00001717
sewardjf1689312005-03-16 18:19:10 +00001718 case Ist_IMark:
1719 return IRStmt_IMark(st->Ist.IMark.addr, st->Ist.IMark.len);
1720
sewardjd2445f62005-03-21 00:15:53 +00001721 case Ist_NoOp:
1722 return IRStmt_NoOp();
1723
sewardj3e838932005-01-07 12:09:15 +00001724 case Ist_MFence:
1725 return IRStmt_MFence();
1726
sewardj62617ef2004-10-13 23:29:22 +00001727 case Ist_Exit: {
1728 IRExpr* fcond;
sewardj496a58d2005-03-20 18:44:44 +00001729 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj0276d4b2004-11-15 15:30:21 +00001730 fcond = fold_Expr(subst_Expr(env, st->Ist.Exit.guard));
sewardj62617ef2004-10-13 23:29:22 +00001731 if (fcond->tag == Iex_Const) {
1732 /* Interesting. The condition on this exit has folded down to
1733 a constant. */
sewardjba999312004-11-15 15:21:17 +00001734 vassert(fcond->Iex.Const.con->tag == Ico_U1);
sewardj98430292004-12-29 17:34:50 +00001735 vassert(fcond->Iex.Const.con->Ico.U1 == False
1736 || fcond->Iex.Const.con->Ico.U1 == True);
sewardjba999312004-11-15 15:21:17 +00001737 if (fcond->Iex.Const.con->Ico.U1 == False) {
sewardj62617ef2004-10-13 23:29:22 +00001738 /* exit is never going to happen, so dump the statement. */
sewardjd2445f62005-03-21 00:15:53 +00001739 return IRStmt_NoOp();
sewardj62617ef2004-10-13 23:29:22 +00001740 } else {
sewardjba999312004-11-15 15:21:17 +00001741 vassert(fcond->Iex.Const.con->Ico.U1 == True);
sewardje810c192005-09-09 08:33:03 +00001742 /* Hmmm. The exit has become unconditional. Leave it
1743 as it is for now, since we'd have to truncate the BB
1744 at this point, which is tricky. Such truncation is
1745 done later by the dead-code elimination pass. */
sewardj62617ef2004-10-13 23:29:22 +00001746 /* fall out into the reconstruct-the-exit code. */
sewardj08613742004-10-25 13:01:45 +00001747 if (vex_control.iropt_verbosity > 0)
1748 /* really a misuse of vex_control.iropt_verbosity */
sewardj8c2c10b2004-10-16 20:51:52 +00001749 vex_printf("vex iropt: IRStmt_Exit became unconditional\n");
sewardj62617ef2004-10-13 23:29:22 +00001750 }
1751 }
sewardj893aada2004-11-29 19:57:54 +00001752 return IRStmt_Exit(fcond, st->Ist.Exit.jk, st->Ist.Exit.dst);
sewardj62617ef2004-10-13 23:29:22 +00001753 }
1754
1755 default:
1756 vex_printf("\n"); ppIRStmt(st);
1757 vpanic("subst_and_fold_Stmt");
1758 }
sewardj84be7372004-08-18 13:59:33 +00001759}
1760
1761
sewardjdd40fdf2006-12-24 02:20:24 +00001762IRSB* cprop_BB ( IRSB* in )
sewardj84be7372004-08-18 13:59:33 +00001763{
sewardj62617ef2004-10-13 23:29:22 +00001764 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +00001765 IRSB* out;
sewardj62617ef2004-10-13 23:29:22 +00001766 IRStmt* st2;
1767 Int n_tmps = in->tyenv->types_used;
1768 IRExpr** env = LibVEX_Alloc(n_tmps * sizeof(IRExpr*));
sewardj84be7372004-08-18 13:59:33 +00001769
sewardjdd40fdf2006-12-24 02:20:24 +00001770 out = emptyIRSB();
1771 out->tyenv = deepCopyIRTypeEnv( in->tyenv );
sewardj84be7372004-08-18 13:59:33 +00001772
1773 /* Set up the env with which travels forward. This holds a
1774 substitution, mapping IRTemps to atoms, that is, IRExprs which
1775 are either IRTemps or IRConsts. Thus, copy and constant
1776 propagation is done. The environment is to be applied as we
1777 move along. Keys are IRTemps. Values are IRExpr*s.
1778 */
sewardj62617ef2004-10-13 23:29:22 +00001779 for (i = 0; i < n_tmps; i++)
1780 env[i] = NULL;
sewardj84be7372004-08-18 13:59:33 +00001781
1782 /* For each original SSA-form stmt ... */
1783 for (i = 0; i < in->stmts_used; i++) {
1784
1785 /* First apply the substitution to the current stmt. This
1786 propagates in any constants and tmp-tmp assignments
1787 accumulated prior to this point. As part of the subst_Stmt
1788 call, also then fold any constant expressions resulting. */
1789
sewardjf0e43162004-08-20 00:11:12 +00001790 st2 = in->stmts[i];
1791
1792 /* perhaps st2 is already a no-op? */
sewardj8bee6d12005-03-22 02:24:05 +00001793 if (st2->tag == Ist_NoOp) continue;
sewardjf0e43162004-08-20 00:11:12 +00001794
1795 st2 = subst_and_fold_Stmt( env, st2 );
sewardj84be7372004-08-18 13:59:33 +00001796
sewardjb8e75862004-08-19 17:58:45 +00001797 /* If the statement has been folded into a no-op, forget it. */
sewardj8bee6d12005-03-22 02:24:05 +00001798 if (st2->tag == Ist_NoOp) continue;
sewardjb8e75862004-08-19 17:58:45 +00001799
sewardj84be7372004-08-18 13:59:33 +00001800 /* Now consider what the stmt looks like. If it's of the form
1801 't = const' or 't1 = t2', add it to the running environment
1802 and not to the output BB. Otherwise, add it to the output
sewardjc0b42282004-10-12 13:44:12 +00001803 BB. Note, we choose not to propagate const when const is an
1804 F64i, so that F64i literals can be CSE'd later. This helps
1805 x86 floating point code generation. */
sewardj84be7372004-08-18 13:59:33 +00001806
sewardjdd40fdf2006-12-24 02:20:24 +00001807 if (st2->tag == Ist_WrTmp
1808 && st2->Ist.WrTmp.data->tag == Iex_Const
1809 && st2->Ist.WrTmp.data->Iex.Const.con->tag != Ico_F64i) {
sewardj84be7372004-08-18 13:59:33 +00001810 /* 't = const' -- add to env.
1811 The pair (IRTemp, IRExpr*) is added. */
sewardjdd40fdf2006-12-24 02:20:24 +00001812 env[(Int)(st2->Ist.WrTmp.tmp)] = st2->Ist.WrTmp.data;
sewardj84be7372004-08-18 13:59:33 +00001813 }
1814 else
sewardjdd40fdf2006-12-24 02:20:24 +00001815 if (st2->tag == Ist_WrTmp && st2->Ist.WrTmp.data->tag == Iex_RdTmp) {
sewardj84be7372004-08-18 13:59:33 +00001816 /* 't1 = t2' -- add to env.
1817 The pair (IRTemp, IRExpr*) is added. */
sewardjdd40fdf2006-12-24 02:20:24 +00001818 env[(Int)(st2->Ist.WrTmp.tmp)] = st2->Ist.WrTmp.data;
sewardj84be7372004-08-18 13:59:33 +00001819 }
1820 else {
1821 /* Not interesting, copy st2 into the output block. */
sewardjdd40fdf2006-12-24 02:20:24 +00001822 addStmtToIRSB( out, st2 );
sewardj84be7372004-08-18 13:59:33 +00001823 }
1824 }
1825
sewardj84be7372004-08-18 13:59:33 +00001826 out->next = subst_Expr( env, in->next );
1827 out->jumpkind = in->jumpkind;
1828 return out;
1829}
1830
1831
sewardjedf4d692004-08-17 13:52:58 +00001832/*---------------------------------------------------------------*/
sewardj39e3f242004-08-18 16:54:52 +00001833/*--- Dead code (t = E) removal ---*/
1834/*---------------------------------------------------------------*/
1835
sewardje810c192005-09-09 08:33:03 +00001836/* As a side effect, also removes all code following an unconditional
1837 side exit. */
1838
sewardjea602bc2004-10-14 21:40:12 +00001839/* The type of the HashHW map is: a map from IRTemp to nothing
sewardj39e3f242004-08-18 16:54:52 +00001840 -- really just operating a set or IRTemps.
1841*/
1842
sewardjd503a322004-10-13 22:41:16 +00001843inline
1844static void addUses_Temp ( Bool* set, IRTemp tmp )
sewardj17442fe2004-09-20 14:54:28 +00001845{
sewardjd503a322004-10-13 22:41:16 +00001846 set[(Int)tmp] = True;
sewardj17442fe2004-09-20 14:54:28 +00001847}
1848
sewardjd503a322004-10-13 22:41:16 +00001849static void addUses_Expr ( Bool* set, IRExpr* e )
sewardj39e3f242004-08-18 16:54:52 +00001850{
1851 Int i;
1852 switch (e->tag) {
sewardjd7217032004-08-19 10:49:10 +00001853 case Iex_GetI:
sewardjeeac8412004-11-02 00:26:55 +00001854 addUses_Expr(set, e->Iex.GetI.ix);
sewardjd7217032004-08-19 10:49:10 +00001855 return;
sewardj39e3f242004-08-18 16:54:52 +00001856 case Iex_Mux0X:
1857 addUses_Expr(set, e->Iex.Mux0X.cond);
1858 addUses_Expr(set, e->Iex.Mux0X.expr0);
1859 addUses_Expr(set, e->Iex.Mux0X.exprX);
1860 return;
1861 case Iex_CCall:
1862 for (i = 0; e->Iex.CCall.args[i]; i++)
1863 addUses_Expr(set, e->Iex.CCall.args[i]);
1864 return;
sewardjaf1ceca2005-06-30 23:31:27 +00001865 case Iex_Load:
1866 addUses_Expr(set, e->Iex.Load.addr);
sewardj39e3f242004-08-18 16:54:52 +00001867 return;
sewardj40c80262006-02-08 19:30:46 +00001868 case Iex_Qop:
1869 addUses_Expr(set, e->Iex.Qop.arg1);
1870 addUses_Expr(set, e->Iex.Qop.arg2);
1871 addUses_Expr(set, e->Iex.Qop.arg3);
1872 addUses_Expr(set, e->Iex.Qop.arg4);
1873 return;
sewardjb183b852006-02-03 16:08:03 +00001874 case Iex_Triop:
1875 addUses_Expr(set, e->Iex.Triop.arg1);
1876 addUses_Expr(set, e->Iex.Triop.arg2);
1877 addUses_Expr(set, e->Iex.Triop.arg3);
1878 return;
sewardj39e3f242004-08-18 16:54:52 +00001879 case Iex_Binop:
1880 addUses_Expr(set, e->Iex.Binop.arg1);
1881 addUses_Expr(set, e->Iex.Binop.arg2);
1882 return;
1883 case Iex_Unop:
1884 addUses_Expr(set, e->Iex.Unop.arg);
1885 return;
sewardjdd40fdf2006-12-24 02:20:24 +00001886 case Iex_RdTmp:
1887 addUses_Temp(set, e->Iex.RdTmp.tmp);
sewardj39e3f242004-08-18 16:54:52 +00001888 return;
1889 case Iex_Const:
1890 case Iex_Get:
1891 return;
1892 default:
1893 vex_printf("\n");
1894 ppIRExpr(e);
1895 vpanic("addUses_Expr");
1896 }
1897}
1898
sewardjd503a322004-10-13 22:41:16 +00001899static void addUses_Stmt ( Bool* set, IRStmt* st )
sewardj39e3f242004-08-18 16:54:52 +00001900{
sewardj17442fe2004-09-20 14:54:28 +00001901 Int i;
1902 IRDirty* d;
sewardj39e3f242004-08-18 16:54:52 +00001903 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00001904 case Ist_AbiHint:
1905 addUses_Expr(set, st->Ist.AbiHint.base);
1906 return;
sewardjd7217032004-08-19 10:49:10 +00001907 case Ist_PutI:
sewardjeeac8412004-11-02 00:26:55 +00001908 addUses_Expr(set, st->Ist.PutI.ix);
sewardj2d3f77c2004-09-22 23:49:09 +00001909 addUses_Expr(set, st->Ist.PutI.data);
sewardjd7217032004-08-19 10:49:10 +00001910 return;
sewardjdd40fdf2006-12-24 02:20:24 +00001911 case Ist_WrTmp:
1912 addUses_Expr(set, st->Ist.WrTmp.data);
sewardj39e3f242004-08-18 16:54:52 +00001913 return;
1914 case Ist_Put:
sewardj6d076362004-09-23 11:06:17 +00001915 addUses_Expr(set, st->Ist.Put.data);
sewardj39e3f242004-08-18 16:54:52 +00001916 return;
sewardjaf1ceca2005-06-30 23:31:27 +00001917 case Ist_Store:
1918 addUses_Expr(set, st->Ist.Store.addr);
1919 addUses_Expr(set, st->Ist.Store.data);
sewardj39e3f242004-08-18 16:54:52 +00001920 return;
sewardj17442fe2004-09-20 14:54:28 +00001921 case Ist_Dirty:
1922 d = st->Ist.Dirty.details;
1923 if (d->mFx != Ifx_None)
1924 addUses_Expr(set, d->mAddr);
sewardjb8385d82004-11-02 01:34:15 +00001925 addUses_Expr(set, d->guard);
sewardj17442fe2004-09-20 14:54:28 +00001926 for (i = 0; d->args[i] != NULL; i++)
1927 addUses_Expr(set, d->args[i]);
1928 return;
sewardjd2445f62005-03-21 00:15:53 +00001929 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00001930 case Ist_IMark:
sewardj3e838932005-01-07 12:09:15 +00001931 case Ist_MFence:
1932 return;
sewardj17442fe2004-09-20 14:54:28 +00001933 case Ist_Exit:
sewardj0276d4b2004-11-15 15:30:21 +00001934 addUses_Expr(set, st->Ist.Exit.guard);
sewardj17442fe2004-09-20 14:54:28 +00001935 return;
sewardj39e3f242004-08-18 16:54:52 +00001936 default:
1937 vex_printf("\n");
1938 ppIRStmt(st);
1939 vpanic("addUses_Stmt");
sewardjd503a322004-10-13 22:41:16 +00001940 }
sewardj39e3f242004-08-18 16:54:52 +00001941}
1942
1943
sewardjba999312004-11-15 15:21:17 +00001944/* Is this literally IRExpr_Const(IRConst_U1(False)) ? */
1945static Bool isZeroU1 ( IRExpr* e )
sewardjd9997882004-11-04 19:42:59 +00001946{
sewardj9d2e7692005-02-07 01:11:31 +00001947 return toBool( e->tag == Iex_Const
1948 && e->Iex.Const.con->tag == Ico_U1
1949 && e->Iex.Const.con->Ico.U1 == False );
sewardjd9997882004-11-04 19:42:59 +00001950}
1951
sewardje810c192005-09-09 08:33:03 +00001952/* Is this literally IRExpr_Const(IRConst_U1(True)) ? */
1953static Bool isOneU1 ( IRExpr* e )
1954{
1955 return toBool( e->tag == Iex_Const
1956 && e->Iex.Const.con->tag == Ico_U1
1957 && e->Iex.Const.con->Ico.U1 == True );
1958}
1959
sewardj39e3f242004-08-18 16:54:52 +00001960
sewardjdd40fdf2006-12-24 02:20:24 +00001961/* Note, this destructively modifies the given IRSB. */
sewardj39e3f242004-08-18 16:54:52 +00001962
1963/* Scan backwards through statements, carrying a set of IRTemps which
1964 are known to be used after the current point. On encountering 't =
1965 E', delete the binding if it is not used. Otherwise, add any temp
sewardje810c192005-09-09 08:33:03 +00001966 uses to the set and keep on moving backwards.
1967
1968 As an enhancement, the first (backwards) pass searches for IR exits
1969 with always-taken conditions and notes the location of the earliest
1970 one in the block. If any such are found, a second pass copies the
1971 exit destination and jump kind to the bb-end. Then, the exit and
1972 all statements following it are turned into no-ops.
1973*/
sewardj39e3f242004-08-18 16:54:52 +00001974
sewardjdd40fdf2006-12-24 02:20:24 +00001975/* notstatic */ void do_deadcode_BB ( IRSB* bb )
sewardj39e3f242004-08-18 16:54:52 +00001976{
sewardje810c192005-09-09 08:33:03 +00001977 Int i, i_unconditional_exit;
sewardjd503a322004-10-13 22:41:16 +00001978 Int n_tmps = bb->tyenv->types_used;
1979 Bool* set = LibVEX_Alloc(n_tmps * sizeof(Bool));
sewardj39e3f242004-08-18 16:54:52 +00001980 IRStmt* st;
1981
sewardjd503a322004-10-13 22:41:16 +00001982 for (i = 0; i < n_tmps; i++)
1983 set[i] = False;
1984
sewardj39e3f242004-08-18 16:54:52 +00001985 /* start off by recording IRTemp uses in the next field. */
1986 addUses_Expr(set, bb->next);
1987
sewardje810c192005-09-09 08:33:03 +00001988 /* First pass */
1989
sewardj39e3f242004-08-18 16:54:52 +00001990 /* Work backwards through the stmts */
sewardje810c192005-09-09 08:33:03 +00001991 i_unconditional_exit = -1;
sewardj39e3f242004-08-18 16:54:52 +00001992 for (i = bb->stmts_used-1; i >= 0; i--) {
1993 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00001994 if (st->tag == Ist_NoOp)
sewardj84ff0652004-08-23 16:16:08 +00001995 continue;
sewardje810c192005-09-09 08:33:03 +00001996 /* take note of any unconditional exits */
1997 if (st->tag == Ist_Exit
1998 && isOneU1(st->Ist.Exit.guard))
1999 i_unconditional_exit = i;
sewardjdd40fdf2006-12-24 02:20:24 +00002000 if (st->tag == Ist_WrTmp
2001 && set[(Int)(st->Ist.WrTmp.tmp)] == False) {
sewardj39e3f242004-08-18 16:54:52 +00002002 /* it's an IRTemp which never got used. Delete it. */
sewardj088bcb42004-08-19 17:16:52 +00002003 if (DEBUG_IROPT) {
sewardj39e3f242004-08-18 16:54:52 +00002004 vex_printf("DEAD: ");
2005 ppIRStmt(st);
2006 vex_printf("\n");
2007 }
sewardjd2445f62005-03-21 00:15:53 +00002008 bb->stmts[i] = IRStmt_NoOp();
sewardjd9997882004-11-04 19:42:59 +00002009 }
2010 else
2011 if (st->tag == Ist_Dirty
2012 && st->Ist.Dirty.details->guard
sewardjba999312004-11-15 15:21:17 +00002013 && isZeroU1(st->Ist.Dirty.details->guard)) {
sewardjd2445f62005-03-21 00:15:53 +00002014 /* This is a dirty helper which will never get called.
2015 Delete it. */
2016 bb->stmts[i] = IRStmt_NoOp();
sewardjd9997882004-11-04 19:42:59 +00002017 }
2018 else {
sewardj39e3f242004-08-18 16:54:52 +00002019 /* Note any IRTemp uses made by the current statement. */
2020 addUses_Stmt(set, st);
2021 }
2022 }
sewardje810c192005-09-09 08:33:03 +00002023
2024 /* Optional second pass: if any unconditional exits were found,
2025 delete them and all following statements. */
2026
2027 if (i_unconditional_exit != -1) {
2028 if (0) vex_printf("ZAPPING ALL FORWARDS from %d\n",
2029 i_unconditional_exit);
2030 vassert(i_unconditional_exit >= 0
2031 && i_unconditional_exit < bb->stmts_used);
2032 bb->next
2033 = IRExpr_Const( bb->stmts[i_unconditional_exit]->Ist.Exit.dst );
2034 bb->jumpkind
2035 = bb->stmts[i_unconditional_exit]->Ist.Exit.jk;
2036 for (i = i_unconditional_exit; i < bb->stmts_used; i++)
2037 bb->stmts[i] = IRStmt_NoOp();
2038 }
sewardj39e3f242004-08-18 16:54:52 +00002039}
2040
sewardje810c192005-09-09 08:33:03 +00002041
sewardj84ff0652004-08-23 16:16:08 +00002042/*---------------------------------------------------------------*/
2043/*--- Specialisation of helper function calls, in ---*/
2044/*--- collaboration with the front end ---*/
2045/*---------------------------------------------------------------*/
2046
2047static
sewardjdd40fdf2006-12-24 02:20:24 +00002048IRSB* spec_helpers_BB ( IRSB* bb,
sewardj9d2e7692005-02-07 01:11:31 +00002049 IRExpr* (*specHelper) ( HChar*, IRExpr**) )
sewardj84ff0652004-08-23 16:16:08 +00002050{
sewardjb9230752004-12-29 19:25:06 +00002051 Int i;
sewardj84ff0652004-08-23 16:16:08 +00002052 IRStmt* st;
2053 IRExpr* ex;
sewardjb9230752004-12-29 19:25:06 +00002054 Bool any = False;
sewardj84ff0652004-08-23 16:16:08 +00002055
2056 for (i = bb->stmts_used-1; i >= 0; i--) {
2057 st = bb->stmts[i];
2058
sewardjdd40fdf2006-12-24 02:20:24 +00002059 if (st->tag != Ist_WrTmp
2060 || st->Ist.WrTmp.data->tag != Iex_CCall)
sewardj8bee6d12005-03-22 02:24:05 +00002061 continue;
sewardj84ff0652004-08-23 16:16:08 +00002062
sewardjdd40fdf2006-12-24 02:20:24 +00002063 ex = (*specHelper)( st->Ist.WrTmp.data->Iex.CCall.cee->name,
2064 st->Ist.WrTmp.data->Iex.CCall.args );
sewardj84ff0652004-08-23 16:16:08 +00002065 if (!ex)
sewardjaba4fff2004-10-08 21:37:15 +00002066 /* the front end can't think of a suitable replacement */
2067 continue;
sewardj84ff0652004-08-23 16:16:08 +00002068
2069 /* We got something better. Install it in the bb. */
sewardjb9230752004-12-29 19:25:06 +00002070 any = True;
sewardj84ff0652004-08-23 16:16:08 +00002071 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00002072 = IRStmt_WrTmp(st->Ist.WrTmp.tmp, ex);
sewardj84ff0652004-08-23 16:16:08 +00002073
2074 if (0) {
2075 vex_printf("SPEC: ");
sewardjdd40fdf2006-12-24 02:20:24 +00002076 ppIRExpr(st->Ist.WrTmp.data);
sewardj84ff0652004-08-23 16:16:08 +00002077 vex_printf(" --> ");
2078 ppIRExpr(ex);
2079 vex_printf("\n");
2080 }
2081 }
sewardjb9230752004-12-29 19:25:06 +00002082
2083 if (any)
2084 bb = flatten_BB(bb);
2085 return bb;
sewardj84ff0652004-08-23 16:16:08 +00002086}
2087
sewardj29632392004-08-22 02:38:11 +00002088
2089/*---------------------------------------------------------------*/
sewardj9b0cc582006-02-04 15:24:00 +00002090/*--- Determination of guest state aliasing relationships ---*/
2091/*---------------------------------------------------------------*/
2092
2093/* These are helper functions for CSE and GetI/PutI transformations.
2094
2095 Determine, to the extent possible, the relationship between two
2096 guest state accesses. The possible outcomes are:
2097
2098 * Exact alias. These two accesses denote precisely the same
2099 piece of the guest state.
2100
2101 * Definitely no alias. These two accesses are guaranteed not to
2102 overlap any part of the guest state.
2103
2104 * Unknown -- if neither of the above can be established.
2105
2106 If in doubt, return Unknown. */
2107
2108typedef
2109 enum { ExactAlias, NoAlias, UnknownAlias }
2110 GSAliasing;
2111
2112
2113/* Produces the alias relation between an indexed guest
2114 state access and a non-indexed access. */
2115
2116static
sewardjdd40fdf2006-12-24 02:20:24 +00002117GSAliasing getAliasingRelation_IC ( IRRegArray* descr1, IRExpr* ix1,
sewardj9b0cc582006-02-04 15:24:00 +00002118 Int offset2, IRType ty2 )
2119{
2120 UInt minoff1, maxoff1, minoff2, maxoff2;
2121
2122 getArrayBounds( descr1, &minoff1, &maxoff1 );
2123 minoff2 = offset2;
2124 maxoff2 = minoff2 + sizeofIRType(ty2) - 1;
2125
2126 if (maxoff1 < minoff2 || maxoff2 < minoff1)
2127 return NoAlias;
2128
2129 /* Could probably do better here if required. For the moment
2130 however just claim not to know anything more. */
2131 return UnknownAlias;
2132}
2133
2134
2135/* Produces the alias relation between two indexed guest state
2136 accesses. */
2137
2138static
2139GSAliasing getAliasingRelation_II (
sewardjdd40fdf2006-12-24 02:20:24 +00002140 IRRegArray* descr1, IRExpr* ix1, Int bias1,
2141 IRRegArray* descr2, IRExpr* ix2, Int bias2
sewardj9b0cc582006-02-04 15:24:00 +00002142 )
2143{
2144 UInt minoff1, maxoff1, minoff2, maxoff2;
2145 Int iters;
2146
2147 /* First try hard to show they don't alias. */
2148 getArrayBounds( descr1, &minoff1, &maxoff1 );
2149 getArrayBounds( descr2, &minoff2, &maxoff2 );
2150 if (maxoff1 < minoff2 || maxoff2 < minoff1)
2151 return NoAlias;
2152
2153 /* So the two arrays at least partially overlap. To get any
2154 further we'll have to be sure that the descriptors are
2155 identical. */
sewardjdd40fdf2006-12-24 02:20:24 +00002156 if (!eqIRRegArray(descr1, descr2))
sewardj9b0cc582006-02-04 15:24:00 +00002157 return UnknownAlias;
2158
2159 /* The descriptors are identical. Now the only difference can be
2160 in the index expressions. If they cannot be shown to be
2161 identical, we have to say we don't know what the aliasing
2162 relation will be. Now, since the IR is flattened, the index
2163 expressions should be atoms -- either consts or tmps. So that
2164 makes the comparison simple. */
2165 vassert(isIRAtom(ix1));
2166 vassert(isIRAtom(ix2));
2167 if (!eqIRAtom(ix1,ix2))
2168 return UnknownAlias;
2169
2170 /* Ok, the index expressions are identical. So now the only way
2171 they can be different is in the bias. Normalise this
2172 paranoidly, to reliably establish equality/non-equality. */
2173
2174 /* So now we know that the GetI and PutI index the same array
2175 with the same base. Are the offsets the same, modulo the
2176 array size? Do this paranoidly. */
2177 vassert(descr1->nElems == descr2->nElems);
2178 vassert(descr1->elemTy == descr2->elemTy);
2179 vassert(descr1->base == descr2->base);
2180 iters = 0;
2181 while (bias1 < 0 || bias2 < 0) {
2182 bias1 += descr1->nElems;
2183 bias2 += descr1->nElems;
2184 iters++;
2185 if (iters > 10)
2186 vpanic("getAliasingRelation: iters");
2187 }
2188 vassert(bias1 >= 0 && bias2 >= 0);
2189 bias1 %= descr1->nElems;
2190 bias2 %= descr1->nElems;
2191 vassert(bias1 >= 0 && bias1 < descr1->nElems);
2192 vassert(bias2 >= 0 && bias2 < descr1->nElems);
2193
2194 /* Finally, biasP and biasG are normalised into the range
2195 0 .. descrP/G->nElems - 1. And so we can establish
2196 equality/non-equality. */
2197
2198 return bias1==bias2 ? ExactAlias : NoAlias;
2199}
2200
2201
2202/*---------------------------------------------------------------*/
sewardj08210532004-12-29 17:09:11 +00002203/*--- Common Subexpression Elimination ---*/
2204/*---------------------------------------------------------------*/
2205
2206/* Expensive in time and space. */
2207
2208/* Uses two environments:
2209 a IRTemp -> IRTemp mapping
2210 a mapping from AvailExpr* to IRTemp
2211*/
2212
2213typedef
2214 struct {
sewardj9b0cc582006-02-04 15:24:00 +00002215 enum { Ut, Btt, Btc, Bct, Cf64i, Mttt, GetIt } tag;
sewardj08210532004-12-29 17:09:11 +00002216 union {
2217 /* unop(tmp) */
2218 struct {
2219 IROp op;
2220 IRTemp arg;
2221 } Ut;
2222 /* binop(tmp,tmp) */
2223 struct {
2224 IROp op;
2225 IRTemp arg1;
2226 IRTemp arg2;
2227 } Btt;
2228 /* binop(tmp,const) */
2229 struct {
2230 IROp op;
2231 IRTemp arg1;
2232 IRConst con2;
2233 } Btc;
2234 /* binop(const,tmp) */
2235 struct {
2236 IROp op;
2237 IRConst con1;
2238 IRTemp arg2;
2239 } Bct;
2240 /* F64i-style const */
2241 struct {
2242 ULong f64i;
2243 } Cf64i;
sewardj9b0cc582006-02-04 15:24:00 +00002244 /* Mux0X(tmp,tmp,tmp) */
2245 struct {
2246 IRTemp co;
2247 IRTemp e0;
2248 IRTemp eX;
2249 } Mttt;
2250 /* GetI(descr,tmp,bias)*/
2251 struct {
sewardjdd40fdf2006-12-24 02:20:24 +00002252 IRRegArray* descr;
2253 IRTemp ix;
2254 Int bias;
sewardj9b0cc582006-02-04 15:24:00 +00002255 } GetIt;
sewardj08210532004-12-29 17:09:11 +00002256 } u;
2257 }
2258 AvailExpr;
2259
2260static Bool eq_AvailExpr ( AvailExpr* a1, AvailExpr* a2 )
2261{
2262 if (a1->tag != a2->tag)
2263 return False;
2264 switch (a1->tag) {
2265 case Ut:
sewardj9d2e7692005-02-07 01:11:31 +00002266 return toBool(
2267 a1->u.Ut.op == a2->u.Ut.op
2268 && a1->u.Ut.arg == a2->u.Ut.arg);
sewardj08210532004-12-29 17:09:11 +00002269 case Btt:
sewardj9d2e7692005-02-07 01:11:31 +00002270 return toBool(
2271 a1->u.Btt.op == a2->u.Btt.op
sewardj08210532004-12-29 17:09:11 +00002272 && a1->u.Btt.arg1 == a2->u.Btt.arg1
sewardj9d2e7692005-02-07 01:11:31 +00002273 && a1->u.Btt.arg2 == a2->u.Btt.arg2);
sewardj08210532004-12-29 17:09:11 +00002274 case Btc:
sewardj9d2e7692005-02-07 01:11:31 +00002275 return toBool(
2276 a1->u.Btc.op == a2->u.Btc.op
sewardj08210532004-12-29 17:09:11 +00002277 && a1->u.Btc.arg1 == a2->u.Btc.arg1
sewardj9d2e7692005-02-07 01:11:31 +00002278 && eqIRConst(&a1->u.Btc.con2, &a2->u.Btc.con2));
sewardj08210532004-12-29 17:09:11 +00002279 case Bct:
sewardj9d2e7692005-02-07 01:11:31 +00002280 return toBool(
2281 a1->u.Bct.op == a2->u.Bct.op
sewardj08210532004-12-29 17:09:11 +00002282 && a1->u.Bct.arg2 == a2->u.Bct.arg2
sewardj9d2e7692005-02-07 01:11:31 +00002283 && eqIRConst(&a1->u.Bct.con1, &a2->u.Bct.con1));
sewardj08210532004-12-29 17:09:11 +00002284 case Cf64i:
sewardj9d2e7692005-02-07 01:11:31 +00002285 return toBool(a1->u.Cf64i.f64i == a2->u.Cf64i.f64i);
sewardj9b0cc582006-02-04 15:24:00 +00002286 case Mttt:
2287 return toBool(a1->u.Mttt.co == a2->u.Mttt.co
2288 && a1->u.Mttt.e0 == a2->u.Mttt.e0
2289 && a1->u.Mttt.eX == a2->u.Mttt.eX);
2290 case GetIt:
sewardjdd40fdf2006-12-24 02:20:24 +00002291 return toBool(eqIRRegArray(a1->u.GetIt.descr, a2->u.GetIt.descr)
sewardj9b0cc582006-02-04 15:24:00 +00002292 && a1->u.GetIt.ix == a2->u.GetIt.ix
2293 && a1->u.GetIt.bias == a2->u.GetIt.bias);
sewardj08210532004-12-29 17:09:11 +00002294 default: vpanic("eq_AvailExpr");
2295 }
2296}
2297
2298static IRExpr* availExpr_to_IRExpr ( AvailExpr* ae )
2299{
2300 IRConst* con;
2301 switch (ae->tag) {
2302 case Ut:
sewardjdd40fdf2006-12-24 02:20:24 +00002303 return IRExpr_Unop( ae->u.Ut.op, IRExpr_RdTmp(ae->u.Ut.arg) );
sewardj08210532004-12-29 17:09:11 +00002304 case Btt:
2305 return IRExpr_Binop( ae->u.Btt.op,
sewardjdd40fdf2006-12-24 02:20:24 +00002306 IRExpr_RdTmp(ae->u.Btt.arg1),
2307 IRExpr_RdTmp(ae->u.Btt.arg2) );
sewardj08210532004-12-29 17:09:11 +00002308 case Btc:
2309 con = LibVEX_Alloc(sizeof(IRConst));
2310 *con = ae->u.Btc.con2;
2311 return IRExpr_Binop( ae->u.Btc.op,
sewardjdd40fdf2006-12-24 02:20:24 +00002312 IRExpr_RdTmp(ae->u.Btc.arg1),
2313 IRExpr_Const(con) );
sewardj08210532004-12-29 17:09:11 +00002314 case Bct:
2315 con = LibVEX_Alloc(sizeof(IRConst));
2316 *con = ae->u.Bct.con1;
2317 return IRExpr_Binop( ae->u.Bct.op,
sewardjdd40fdf2006-12-24 02:20:24 +00002318 IRExpr_Const(con),
2319 IRExpr_RdTmp(ae->u.Bct.arg2) );
sewardj08210532004-12-29 17:09:11 +00002320 case Cf64i:
2321 return IRExpr_Const(IRConst_F64i(ae->u.Cf64i.f64i));
sewardj9b0cc582006-02-04 15:24:00 +00002322 case Mttt:
sewardjdd40fdf2006-12-24 02:20:24 +00002323 return IRExpr_Mux0X(IRExpr_RdTmp(ae->u.Mttt.co),
2324 IRExpr_RdTmp(ae->u.Mttt.e0),
2325 IRExpr_RdTmp(ae->u.Mttt.eX));
sewardj9b0cc582006-02-04 15:24:00 +00002326 case GetIt:
2327 return IRExpr_GetI(ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00002328 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00002329 ae->u.GetIt.bias);
sewardj08210532004-12-29 17:09:11 +00002330 default:
2331 vpanic("availExpr_to_IRExpr");
2332 }
2333}
2334
2335inline
2336static IRTemp subst_AvailExpr_Temp ( HashHW* env, IRTemp tmp )
2337{
2338 HWord res;
2339 /* env :: IRTemp -> IRTemp */
2340 if (lookupHHW( env, &res, (HWord)tmp ))
2341 return (IRTemp)res;
2342 else
2343 return tmp;
2344}
2345
2346static void subst_AvailExpr ( HashHW* env, AvailExpr* ae )
2347{
2348 /* env :: IRTemp -> IRTemp */
2349 switch (ae->tag) {
2350 case Ut:
2351 ae->u.Ut.arg = subst_AvailExpr_Temp( env, ae->u.Ut.arg );
2352 break;
2353 case Btt:
2354 ae->u.Btt.arg1 = subst_AvailExpr_Temp( env, ae->u.Btt.arg1 );
2355 ae->u.Btt.arg2 = subst_AvailExpr_Temp( env, ae->u.Btt.arg2 );
2356 break;
2357 case Btc:
2358 ae->u.Btc.arg1 = subst_AvailExpr_Temp( env, ae->u.Btc.arg1 );
2359 break;
2360 case Bct:
2361 ae->u.Bct.arg2 = subst_AvailExpr_Temp( env, ae->u.Bct.arg2 );
2362 break;
2363 case Cf64i:
2364 break;
sewardj9b0cc582006-02-04 15:24:00 +00002365 case Mttt:
2366 ae->u.Mttt.co = subst_AvailExpr_Temp( env, ae->u.Mttt.co );
2367 ae->u.Mttt.e0 = subst_AvailExpr_Temp( env, ae->u.Mttt.e0 );
2368 ae->u.Mttt.eX = subst_AvailExpr_Temp( env, ae->u.Mttt.eX );
2369 break;
2370 case GetIt:
2371 ae->u.GetIt.ix = subst_AvailExpr_Temp( env, ae->u.GetIt.ix );
2372 break;
sewardj08210532004-12-29 17:09:11 +00002373 default:
2374 vpanic("subst_AvailExpr");
2375 }
2376}
2377
2378static AvailExpr* irExpr_to_AvailExpr ( IRExpr* e )
2379{
2380 AvailExpr* ae;
2381
2382 if (e->tag == Iex_Unop
sewardjdd40fdf2006-12-24 02:20:24 +00002383 && e->Iex.Unop.arg->tag == Iex_RdTmp) {
sewardj08210532004-12-29 17:09:11 +00002384 ae = LibVEX_Alloc(sizeof(AvailExpr));
2385 ae->tag = Ut;
2386 ae->u.Ut.op = e->Iex.Unop.op;
sewardjdd40fdf2006-12-24 02:20:24 +00002387 ae->u.Ut.arg = e->Iex.Unop.arg->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002388 return ae;
2389 }
2390
2391 if (e->tag == Iex_Binop
sewardjdd40fdf2006-12-24 02:20:24 +00002392 && e->Iex.Binop.arg1->tag == Iex_RdTmp
2393 && e->Iex.Binop.arg2->tag == Iex_RdTmp) {
sewardj08210532004-12-29 17:09:11 +00002394 ae = LibVEX_Alloc(sizeof(AvailExpr));
2395 ae->tag = Btt;
2396 ae->u.Btt.op = e->Iex.Binop.op;
sewardjdd40fdf2006-12-24 02:20:24 +00002397 ae->u.Btt.arg1 = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
2398 ae->u.Btt.arg2 = e->Iex.Binop.arg2->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002399 return ae;
2400 }
2401
2402 if (e->tag == Iex_Binop
sewardjdd40fdf2006-12-24 02:20:24 +00002403 && e->Iex.Binop.arg1->tag == Iex_RdTmp
sewardj08210532004-12-29 17:09:11 +00002404 && e->Iex.Binop.arg2->tag == Iex_Const) {
2405 ae = LibVEX_Alloc(sizeof(AvailExpr));
2406 ae->tag = Btc;
2407 ae->u.Btc.op = e->Iex.Binop.op;
sewardjdd40fdf2006-12-24 02:20:24 +00002408 ae->u.Btc.arg1 = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002409 ae->u.Btc.con2 = *(e->Iex.Binop.arg2->Iex.Const.con);
2410 return ae;
2411 }
2412
2413 if (e->tag == Iex_Binop
2414 && e->Iex.Binop.arg1->tag == Iex_Const
sewardjdd40fdf2006-12-24 02:20:24 +00002415 && e->Iex.Binop.arg2->tag == Iex_RdTmp) {
sewardj08210532004-12-29 17:09:11 +00002416 ae = LibVEX_Alloc(sizeof(AvailExpr));
2417 ae->tag = Bct;
2418 ae->u.Bct.op = e->Iex.Binop.op;
sewardjdd40fdf2006-12-24 02:20:24 +00002419 ae->u.Bct.arg2 = e->Iex.Binop.arg2->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002420 ae->u.Bct.con1 = *(e->Iex.Binop.arg1->Iex.Const.con);
2421 return ae;
2422 }
2423
2424 if (e->tag == Iex_Const
2425 && e->Iex.Const.con->tag == Ico_F64i) {
2426 ae = LibVEX_Alloc(sizeof(AvailExpr));
2427 ae->tag = Cf64i;
2428 ae->u.Cf64i.f64i = e->Iex.Const.con->Ico.F64i;
2429 return ae;
2430 }
2431
sewardj9b0cc582006-02-04 15:24:00 +00002432 if (e->tag == Iex_Mux0X
sewardjdd40fdf2006-12-24 02:20:24 +00002433 && e->Iex.Mux0X.cond->tag == Iex_RdTmp
2434 && e->Iex.Mux0X.expr0->tag == Iex_RdTmp
2435 && e->Iex.Mux0X.exprX->tag == Iex_RdTmp) {
sewardj9b0cc582006-02-04 15:24:00 +00002436 ae = LibVEX_Alloc(sizeof(AvailExpr));
2437 ae->tag = Mttt;
sewardjdd40fdf2006-12-24 02:20:24 +00002438 ae->u.Mttt.co = e->Iex.Mux0X.cond->Iex.RdTmp.tmp;
2439 ae->u.Mttt.e0 = e->Iex.Mux0X.expr0->Iex.RdTmp.tmp;
2440 ae->u.Mttt.eX = e->Iex.Mux0X.exprX->Iex.RdTmp.tmp;
sewardj9b0cc582006-02-04 15:24:00 +00002441 return ae;
2442 }
2443
2444 if (e->tag == Iex_GetI
sewardjdd40fdf2006-12-24 02:20:24 +00002445 && e->Iex.GetI.ix->tag == Iex_RdTmp) {
sewardj9b0cc582006-02-04 15:24:00 +00002446 ae = LibVEX_Alloc(sizeof(AvailExpr));
2447 ae->tag = GetIt;
2448 ae->u.GetIt.descr = e->Iex.GetI.descr;
sewardjdd40fdf2006-12-24 02:20:24 +00002449 ae->u.GetIt.ix = e->Iex.GetI.ix->Iex.RdTmp.tmp;
sewardj9b0cc582006-02-04 15:24:00 +00002450 ae->u.GetIt.bias = e->Iex.GetI.bias;
2451 return ae;
2452 }
2453
sewardj08210532004-12-29 17:09:11 +00002454 return NULL;
2455}
2456
2457
sewardj9b0cc582006-02-04 15:24:00 +00002458/* The BB is modified in-place. Returns True if any changes were
2459 made. */
sewardj08210532004-12-29 17:09:11 +00002460
sewardjdd40fdf2006-12-24 02:20:24 +00002461static Bool do_cse_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00002462{
sewardj9b0cc582006-02-04 15:24:00 +00002463 Int i, j, paranoia;
sewardj08210532004-12-29 17:09:11 +00002464 IRTemp t, q;
2465 IRStmt* st;
2466 AvailExpr* eprime;
sewardj9b0cc582006-02-04 15:24:00 +00002467 AvailExpr* ae;
2468 Bool invalidate;
2469 Bool anyDone = False;
sewardj08210532004-12-29 17:09:11 +00002470
2471 HashHW* tenv = newHHW(); /* :: IRTemp -> IRTemp */
2472 HashHW* aenv = newHHW(); /* :: AvailExpr* -> IRTemp */
2473
2474 vassert(sizeof(IRTemp) <= sizeof(HWord));
2475
sewardjdd40fdf2006-12-24 02:20:24 +00002476 if (0) { ppIRSB(bb); vex_printf("\n\n"); }
sewardj08210532004-12-29 17:09:11 +00002477
2478 /* Iterate forwards over the stmts.
sewardjb183b852006-02-03 16:08:03 +00002479 On seeing "t = E", where E is one of the 5 AvailExpr forms:
sewardj08210532004-12-29 17:09:11 +00002480 let E' = apply tenv substitution to E
2481 search aenv for E'
2482 if a mapping E' -> q is found,
2483 replace this stmt by "t = q"
2484 and add binding t -> q to tenv
2485 else
2486 add binding E' -> t to aenv
2487 replace this stmt by "t = E'"
sewardj9b0cc582006-02-04 15:24:00 +00002488
2489 Other statements are only interesting to the extent that they
2490 might invalidate some of the expressions in aenv. So there is
2491 an invalidate-bindings check for each statement seen.
sewardj08210532004-12-29 17:09:11 +00002492 */
2493 for (i = 0; i < bb->stmts_used; i++) {
2494 st = bb->stmts[i];
2495
sewardj9b0cc582006-02-04 15:24:00 +00002496 /* ------ BEGIN invalidate aenv bindings ------ */
2497 /* This is critical: remove from aenv any E' -> .. bindings
2498 which might be invalidated by this statement. The only
2499 vulnerable kind of bindings are the GetIt kind.
2500 Dirty call - dump (paranoia level -> 2)
2501 Store - dump (ditto)
2502 Put, PutI - dump unless no-overlap is proven (.. -> 1)
2503 Uses getAliasingRelation_IC and getAliasingRelation_II
2504 to do the no-overlap assessments needed for Put/PutI.
2505 */
2506 switch (st->tag) {
2507 case Ist_Dirty: case Ist_Store:
2508 paranoia = 2; break;
2509 case Ist_Put: case Ist_PutI:
2510 paranoia = 1; break;
2511 case Ist_NoOp: case Ist_IMark: case Ist_AbiHint:
sewardjdd40fdf2006-12-24 02:20:24 +00002512 case Ist_WrTmp: case Ist_MFence: case Ist_Exit:
sewardj9b0cc582006-02-04 15:24:00 +00002513 paranoia = 0; break;
2514 default:
2515 vpanic("do_cse_BB(1)");
2516 }
2517
2518 if (paranoia > 0) {
2519 for (j = 0; j < aenv->used; j++) {
2520 if (!aenv->inuse[j])
2521 continue;
2522 ae = (AvailExpr*)aenv->key[j];
2523 if (ae->tag != GetIt)
2524 continue;
2525 invalidate = False;
2526 if (paranoia >= 2) {
2527 invalidate = True;
2528 } else {
2529 vassert(paranoia == 1);
2530 if (st->tag == Ist_Put) {
2531 if (getAliasingRelation_IC(
2532 ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00002533 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00002534 st->Ist.Put.offset,
2535 typeOfIRExpr(bb->tyenv,st->Ist.Put.data)
2536 ) != NoAlias)
2537 invalidate = True;
2538 }
2539 else
2540 if (st->tag == Ist_PutI) {
2541 if (getAliasingRelation_II(
2542 ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00002543 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00002544 ae->u.GetIt.bias,
2545 st->Ist.PutI.descr,
2546 st->Ist.PutI.ix,
2547 st->Ist.PutI.bias
2548 ) != NoAlias)
2549 invalidate = True;
2550 }
2551 else
2552 vpanic("do_cse_BB(2)");
2553 }
2554
2555 if (invalidate) {
2556 aenv->inuse[j] = False;
2557 aenv->key[j] = (HWord)NULL; /* be sure */
2558 }
2559 } /* for j */
2560 } /* paranoia > 0 */
2561
2562 /* ------ ENV invalidate aenv bindings ------ */
2563
sewardj08210532004-12-29 17:09:11 +00002564 /* ignore not-interestings */
sewardjdd40fdf2006-12-24 02:20:24 +00002565 if (st->tag != Ist_WrTmp)
sewardj08210532004-12-29 17:09:11 +00002566 continue;
2567
sewardjdd40fdf2006-12-24 02:20:24 +00002568 t = st->Ist.WrTmp.tmp;
2569 eprime = irExpr_to_AvailExpr(st->Ist.WrTmp.data);
sewardj08210532004-12-29 17:09:11 +00002570 /* ignore if not of AvailExpr form */
2571 if (!eprime)
2572 continue;
2573
2574 /* vex_printf("considering: " ); ppIRStmt(st); vex_printf("\n"); */
2575
2576 /* apply tenv */
2577 subst_AvailExpr( tenv, eprime );
2578
2579 /* search aenv for eprime, unfortunately the hard way */
2580 for (j = 0; j < aenv->used; j++)
2581 if (aenv->inuse[j] && eq_AvailExpr(eprime, (AvailExpr*)aenv->key[j]))
2582 break;
2583
2584 if (j < aenv->used) {
2585 /* A binding E' -> q was found. Replace stmt by "t = q" and
2586 note the t->q binding in tenv. */
2587 /* (this is the core of the CSE action) */
2588 q = (IRTemp)aenv->val[j];
sewardjdd40fdf2006-12-24 02:20:24 +00002589 bb->stmts[i] = IRStmt_WrTmp( t, IRExpr_RdTmp(q) );
sewardj08210532004-12-29 17:09:11 +00002590 addToHHW( tenv, (HWord)t, (HWord)q );
sewardj9b0cc582006-02-04 15:24:00 +00002591 anyDone = True;
sewardj08210532004-12-29 17:09:11 +00002592 } else {
2593 /* No binding was found, so instead we add E' -> t to our
2594 collection of available expressions, replace this stmt
2595 with "t = E'", and move on. */
sewardjdd40fdf2006-12-24 02:20:24 +00002596 bb->stmts[i] = IRStmt_WrTmp( t, availExpr_to_IRExpr(eprime) );
sewardj08210532004-12-29 17:09:11 +00002597 addToHHW( aenv, (HWord)eprime, (HWord)t );
2598 }
2599 }
2600
sewardjb183b852006-02-03 16:08:03 +00002601 /*
sewardjdd40fdf2006-12-24 02:20:24 +00002602 ppIRSB(bb);
2603 sanityCheckIRSB(bb, Ity_I32);
sewardjb183b852006-02-03 16:08:03 +00002604 vex_printf("\n\n");
2605 */
sewardj9b0cc582006-02-04 15:24:00 +00002606 return anyDone;
sewardj08210532004-12-29 17:09:11 +00002607}
2608
2609
2610/*---------------------------------------------------------------*/
2611/*--- Add32/Sub32 chain collapsing ---*/
2612/*---------------------------------------------------------------*/
2613
2614/* ----- Helper functions for Add32/Sub32 chain collapsing ----- */
2615
2616/* Is this expression "Add32(tmp,const)" or "Sub32(tmp,const)" ? If
2617 yes, set *tmp and *i32 appropriately. *i32 is set as if the
2618 root node is Add32, not Sub32. */
2619
2620static Bool isAdd32OrSub32 ( IRExpr* e, IRTemp* tmp, Int* i32 )
2621{
2622 if (e->tag != Iex_Binop)
2623 return False;
2624 if (e->Iex.Binop.op != Iop_Add32 && e->Iex.Binop.op != Iop_Sub32)
2625 return False;
sewardjdd40fdf2006-12-24 02:20:24 +00002626 if (e->Iex.Binop.arg1->tag != Iex_RdTmp)
sewardj08210532004-12-29 17:09:11 +00002627 return False;
2628 if (e->Iex.Binop.arg2->tag != Iex_Const)
2629 return False;
sewardjdd40fdf2006-12-24 02:20:24 +00002630 *tmp = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002631 *i32 = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32);
2632 if (e->Iex.Binop.op == Iop_Sub32)
2633 *i32 = -*i32;
2634 return True;
2635}
2636
2637
2638/* Figure out if tmp can be expressed as tmp2 +32 const, for some
2639 other tmp2. Scan backwards from the specified start point -- an
2640 optimisation. */
2641
sewardjdd40fdf2006-12-24 02:20:24 +00002642static Bool collapseChain ( IRSB* bb, Int startHere,
sewardj08210532004-12-29 17:09:11 +00002643 IRTemp tmp,
2644 IRTemp* tmp2, Int* i32 )
2645{
2646 Int j, ii;
2647 IRTemp vv;
2648 IRStmt* st;
2649 IRExpr* e;
2650
2651 /* the (var, con) pair contain the current 'representation' for
2652 'tmp'. We start with 'tmp + 0'. */
2653 IRTemp var = tmp;
2654 Int con = 0;
2655
2656 /* Scan backwards to see if tmp can be replaced by some other tmp
2657 +/- a constant. */
2658 for (j = startHere; j >= 0; j--) {
2659 st = bb->stmts[j];
sewardjdd40fdf2006-12-24 02:20:24 +00002660 if (st->tag != Ist_WrTmp)
sewardj08210532004-12-29 17:09:11 +00002661 continue;
sewardjdd40fdf2006-12-24 02:20:24 +00002662 if (st->Ist.WrTmp.tmp != var)
sewardj08210532004-12-29 17:09:11 +00002663 continue;
sewardjdd40fdf2006-12-24 02:20:24 +00002664 e = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +00002665 if (!isAdd32OrSub32(e, &vv, &ii))
2666 break;
2667 var = vv;
2668 con += ii;
2669 }
2670 if (j == -1)
2671 /* no earlier binding for var .. ill-formed IR */
2672 vpanic("collapseChain");
2673
2674 /* so, did we find anything interesting? */
2675 if (var == tmp)
2676 return False; /* no .. */
2677
2678 *tmp2 = var;
2679 *i32 = con;
2680 return True;
2681}
2682
2683
2684/* ------- Main function for Add32/Sub32 chain collapsing ------ */
2685
sewardjdd40fdf2006-12-24 02:20:24 +00002686static void collapse_AddSub_chains_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00002687{
2688 IRStmt *st;
2689 IRTemp var, var2;
2690 Int i, con, con2;
2691
2692 for (i = bb->stmts_used-1; i >= 0; i--) {
2693 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00002694 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00002695 continue;
2696
2697 /* Try to collapse 't1 = Add32/Sub32(t2, con)'. */
2698
sewardjdd40fdf2006-12-24 02:20:24 +00002699 if (st->tag == Ist_WrTmp
2700 && isAdd32OrSub32(st->Ist.WrTmp.data, &var, &con)) {
sewardj08210532004-12-29 17:09:11 +00002701
2702 /* So e1 is of the form Add32(var,con) or Sub32(var,-con).
2703 Find out if var can be expressed as var2 + con2. */
2704 if (collapseChain(bb, i-1, var, &var2, &con2)) {
2705 if (DEBUG_IROPT) {
2706 vex_printf("replacing1 ");
2707 ppIRStmt(st);
2708 vex_printf(" with ");
2709 }
2710 con2 += con;
2711 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00002712 = IRStmt_WrTmp(
2713 st->Ist.WrTmp.tmp,
sewardj08210532004-12-29 17:09:11 +00002714 (con2 >= 0)
2715 ? IRExpr_Binop(Iop_Add32,
sewardjdd40fdf2006-12-24 02:20:24 +00002716 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00002717 IRExpr_Const(IRConst_U32(con2)))
2718 : IRExpr_Binop(Iop_Sub32,
sewardjdd40fdf2006-12-24 02:20:24 +00002719 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00002720 IRExpr_Const(IRConst_U32(-con2)))
2721 );
2722 if (DEBUG_IROPT) {
2723 ppIRStmt(bb->stmts[i]);
2724 vex_printf("\n");
2725 }
2726 }
2727
2728 continue;
2729 }
2730
2731 /* Try to collapse 't1 = GetI[t2, con]'. */
2732
sewardjdd40fdf2006-12-24 02:20:24 +00002733 if (st->tag == Ist_WrTmp
2734 && st->Ist.WrTmp.data->tag == Iex_GetI
2735 && st->Ist.WrTmp.data->Iex.GetI.ix->tag == Iex_RdTmp
2736 && collapseChain(bb, i-1, st->Ist.WrTmp.data->Iex.GetI.ix
2737 ->Iex.RdTmp.tmp, &var2, &con2)) {
sewardj08210532004-12-29 17:09:11 +00002738 if (DEBUG_IROPT) {
2739 vex_printf("replacing3 ");
2740 ppIRStmt(st);
2741 vex_printf(" with ");
2742 }
sewardjdd40fdf2006-12-24 02:20:24 +00002743 con2 += st->Ist.WrTmp.data->Iex.GetI.bias;
sewardj08210532004-12-29 17:09:11 +00002744 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00002745 = IRStmt_WrTmp(
2746 st->Ist.WrTmp.tmp,
2747 IRExpr_GetI(st->Ist.WrTmp.data->Iex.GetI.descr,
2748 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00002749 con2));
2750 if (DEBUG_IROPT) {
2751 ppIRStmt(bb->stmts[i]);
2752 vex_printf("\n");
2753 }
2754 continue;
2755 }
2756
2757 /* Perhaps st is PutI[t, con] ? */
2758
2759 if (st->tag == Ist_PutI
sewardjdd40fdf2006-12-24 02:20:24 +00002760 && st->Ist.PutI.ix->tag == Iex_RdTmp
2761 && collapseChain(bb, i-1, st->Ist.PutI.ix->Iex.RdTmp.tmp,
sewardj08210532004-12-29 17:09:11 +00002762 &var2, &con2)) {
2763 if (DEBUG_IROPT) {
2764 vex_printf("replacing2 ");
2765 ppIRStmt(st);
2766 vex_printf(" with ");
2767 }
2768 con2 += st->Ist.PutI.bias;
2769 bb->stmts[i]
2770 = IRStmt_PutI(st->Ist.PutI.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00002771 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00002772 con2,
2773 st->Ist.PutI.data);
2774 if (DEBUG_IROPT) {
2775 ppIRStmt(bb->stmts[i]);
2776 vex_printf("\n");
2777 }
2778 continue;
2779 }
2780
2781 } /* for */
2782}
2783
2784
2785/*---------------------------------------------------------------*/
2786/*--- PutI/GetI transformations ---*/
2787/*---------------------------------------------------------------*/
2788
sewardj08210532004-12-29 17:09:11 +00002789/* Given the parts (descr, tmp, bias) for a GetI, scan backwards from
2790 the given starting point to find, if any, a PutI which writes
2791 exactly the same piece of guest state, and so return the expression
2792 that the PutI writes. This is the core of PutI-GetI forwarding. */
2793
2794static
sewardjdd40fdf2006-12-24 02:20:24 +00002795IRExpr* findPutI ( IRSB* bb, Int startHere,
2796 IRRegArray* descrG, IRExpr* ixG, Int biasG )
sewardj08210532004-12-29 17:09:11 +00002797{
2798 Int j;
2799 IRStmt* st;
2800 GSAliasing relation;
2801
2802 if (0) {
2803 vex_printf("\nfindPutI ");
sewardjdd40fdf2006-12-24 02:20:24 +00002804 ppIRRegArray(descrG);
sewardj08210532004-12-29 17:09:11 +00002805 vex_printf(" ");
2806 ppIRExpr(ixG);
2807 vex_printf(" %d\n", biasG);
2808 }
2809
2810 /* Scan backwards in bb from startHere to find a suitable PutI
2811 binding for (descrG, ixG, biasG), if any. */
2812
2813 for (j = startHere; j >= 0; j--) {
2814 st = bb->stmts[j];
sewardj8bee6d12005-03-22 02:24:05 +00002815 if (st->tag == Ist_NoOp)
2816 continue;
sewardj08210532004-12-29 17:09:11 +00002817
2818 if (st->tag == Ist_Put) {
2819 /* Non-indexed Put. This can't give a binding, but we do
2820 need to check it doesn't invalidate the search by
2821 overlapping any part of the indexed guest state. */
2822
2823 relation
2824 = getAliasingRelation_IC(
2825 descrG, ixG,
2826 st->Ist.Put.offset,
2827 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
2828
2829 if (relation == NoAlias) {
2830 /* we're OK; keep going */
2831 continue;
2832 } else {
2833 /* relation == UnknownAlias || relation == ExactAlias */
2834 /* If this assertion fails, we've found a Put which writes
2835 an area of guest state which is read by a GetI. Which
2836 is unlikely (although not per se wrong). */
2837 vassert(relation != ExactAlias);
2838 /* This Put potentially writes guest state that the GetI
2839 reads; we must fail. */
2840 return NULL;
2841 }
2842 }
2843
2844 if (st->tag == Ist_PutI) {
2845
2846 relation = getAliasingRelation_II(
2847 descrG, ixG, biasG,
2848 st->Ist.PutI.descr,
2849 st->Ist.PutI.ix,
2850 st->Ist.PutI.bias
2851 );
2852
2853 if (relation == NoAlias) {
2854 /* This PutI definitely doesn't overlap. Ignore it and
2855 keep going. */
2856 continue; /* the for j loop */
2857 }
2858
2859 if (relation == UnknownAlias) {
2860 /* We don't know if this PutI writes to the same guest
2861 state that the GetI, or not. So we have to give up. */
2862 return NULL;
2863 }
2864
2865 /* Otherwise, we've found what we're looking for. */
2866 vassert(relation == ExactAlias);
2867 return st->Ist.PutI.data;
2868
2869 } /* if (st->tag == Ist_PutI) */
2870
2871 if (st->tag == Ist_Dirty) {
2872 /* Be conservative. If the dirty call has any guest effects at
2873 all, give up. We could do better -- only give up if there
2874 are any guest writes/modifies. */
2875 if (st->Ist.Dirty.details->nFxState > 0)
2876 return NULL;
2877 }
2878
2879 } /* for */
2880
2881 /* No valid replacement was found. */
2882 return NULL;
2883}
2884
2885
2886
2887/* Assuming pi is a PutI stmt, is s2 identical to it (in the sense
2888 that it writes exactly the same piece of guest state) ? Safe
2889 answer: False. */
2890
2891static Bool identicalPutIs ( IRStmt* pi, IRStmt* s2 )
2892{
2893 vassert(pi->tag == Ist_PutI);
2894 if (s2->tag != Ist_PutI)
2895 return False;
2896
sewardj9d2e7692005-02-07 01:11:31 +00002897 return toBool(
2898 getAliasingRelation_II(
sewardj08210532004-12-29 17:09:11 +00002899 pi->Ist.PutI.descr, pi->Ist.PutI.ix, pi->Ist.PutI.bias,
2900 s2->Ist.PutI.descr, s2->Ist.PutI.ix, s2->Ist.PutI.bias
2901 )
sewardj9d2e7692005-02-07 01:11:31 +00002902 == ExactAlias
2903 );
sewardj08210532004-12-29 17:09:11 +00002904}
2905
2906
2907/* Assuming pi is a PutI stmt, is s2 a Get/GetI/Put/PutI which might
2908 overlap it? Safe answer: True. Note, we could do a lot better
2909 than this if needed. */
2910
2911static
2912Bool guestAccessWhichMightOverlapPutI (
2913 IRTypeEnv* tyenv, IRStmt* pi, IRStmt* s2
2914 )
2915{
2916 GSAliasing relation;
2917 UInt minoffP, maxoffP;
2918
2919 vassert(pi->tag == Ist_PutI);
2920 getArrayBounds(pi->Ist.PutI.descr, &minoffP, &maxoffP);
2921 switch (s2->tag) {
2922
sewardjd2445f62005-03-21 00:15:53 +00002923 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00002924 case Ist_IMark:
2925 return False;
2926
sewardjbb3f52d2005-01-07 14:14:50 +00002927 case Ist_MFence:
sewardj5a9ffab2005-05-12 17:55:01 +00002928 case Ist_AbiHint:
2929 /* just be paranoid ... these should be rare. */
sewardjbb3f52d2005-01-07 14:14:50 +00002930 return True;
2931
sewardj08210532004-12-29 17:09:11 +00002932 case Ist_Dirty:
2933 /* If the dirty call has any guest effects at all, give up.
2934 Probably could do better. */
2935 if (s2->Ist.Dirty.details->nFxState > 0)
2936 return True;
2937 return False;
2938
2939 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00002940 vassert(isIRAtom(s2->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +00002941 relation
2942 = getAliasingRelation_IC(
2943 pi->Ist.PutI.descr, pi->Ist.PutI.ix,
2944 s2->Ist.Put.offset,
2945 typeOfIRExpr(tyenv,s2->Ist.Put.data)
2946 );
2947 goto have_relation;
2948
2949 case Ist_PutI:
sewardj496a58d2005-03-20 18:44:44 +00002950 vassert(isIRAtom(s2->Ist.PutI.ix));
2951 vassert(isIRAtom(s2->Ist.PutI.data));
sewardj08210532004-12-29 17:09:11 +00002952 relation
2953 = getAliasingRelation_II(
2954 pi->Ist.PutI.descr, pi->Ist.PutI.ix, pi->Ist.PutI.bias,
2955 s2->Ist.PutI.descr, s2->Ist.PutI.ix, s2->Ist.PutI.bias
2956 );
2957 goto have_relation;
2958
sewardjdd40fdf2006-12-24 02:20:24 +00002959 case Ist_WrTmp:
2960 if (s2->Ist.WrTmp.data->tag == Iex_GetI) {
sewardj08210532004-12-29 17:09:11 +00002961 relation
2962 = getAliasingRelation_II(
2963 pi->Ist.PutI.descr, pi->Ist.PutI.ix,
2964 pi->Ist.PutI.bias,
sewardjdd40fdf2006-12-24 02:20:24 +00002965 s2->Ist.WrTmp.data->Iex.GetI.descr,
2966 s2->Ist.WrTmp.data->Iex.GetI.ix,
2967 s2->Ist.WrTmp.data->Iex.GetI.bias
sewardj08210532004-12-29 17:09:11 +00002968 );
2969 goto have_relation;
2970 }
sewardjdd40fdf2006-12-24 02:20:24 +00002971 if (s2->Ist.WrTmp.data->tag == Iex_Get) {
sewardj08210532004-12-29 17:09:11 +00002972 relation
2973 = getAliasingRelation_IC(
2974 pi->Ist.PutI.descr, pi->Ist.PutI.ix,
sewardjdd40fdf2006-12-24 02:20:24 +00002975 s2->Ist.WrTmp.data->Iex.Get.offset,
2976 s2->Ist.WrTmp.data->Iex.Get.ty
sewardj08210532004-12-29 17:09:11 +00002977 );
2978 goto have_relation;
2979 }
2980 return False;
2981
sewardjaf1ceca2005-06-30 23:31:27 +00002982 case Ist_Store:
2983 vassert(isIRAtom(s2->Ist.Store.addr));
2984 vassert(isIRAtom(s2->Ist.Store.data));
sewardj08210532004-12-29 17:09:11 +00002985 return False;
2986
2987 default:
2988 vex_printf("\n"); ppIRStmt(s2); vex_printf("\n");
2989 vpanic("guestAccessWhichMightOverlapPutI");
2990 }
2991
2992 have_relation:
2993 if (relation == NoAlias)
2994 return False;
2995 else
2996 return True; /* ExactAlias or UnknownAlias */
2997}
2998
2999
3000
3001/* ---------- PutI/GetI transformations main functions --------- */
3002
3003/* Remove redundant GetIs, to the extent that they can be detected.
3004 bb is modified in-place. */
3005
3006static
sewardjdd40fdf2006-12-24 02:20:24 +00003007void do_redundant_GetI_elimination ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003008{
3009 Int i;
3010 IRStmt* st;
3011
3012 for (i = bb->stmts_used-1; i >= 0; i--) {
3013 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003014 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00003015 continue;
3016
sewardjdd40fdf2006-12-24 02:20:24 +00003017 if (st->tag == Ist_WrTmp
3018 && st->Ist.WrTmp.data->tag == Iex_GetI
3019 && st->Ist.WrTmp.data->Iex.GetI.ix->tag == Iex_RdTmp) {
3020 IRRegArray* descr = st->Ist.WrTmp.data->Iex.GetI.descr;
3021 IRExpr* ix = st->Ist.WrTmp.data->Iex.GetI.ix;
3022 Int bias = st->Ist.WrTmp.data->Iex.GetI.bias;
3023 IRExpr* replacement = findPutI(bb, i-1, descr, ix, bias);
sewardj08210532004-12-29 17:09:11 +00003024 if (replacement
sewardj496a58d2005-03-20 18:44:44 +00003025 && isIRAtom(replacement)
sewardj08210532004-12-29 17:09:11 +00003026 /* Make sure we're doing a type-safe transformation! */
3027 && typeOfIRExpr(bb->tyenv, replacement) == descr->elemTy) {
3028 if (DEBUG_IROPT) {
3029 vex_printf("rGI: ");
sewardjdd40fdf2006-12-24 02:20:24 +00003030 ppIRExpr(st->Ist.WrTmp.data);
sewardj08210532004-12-29 17:09:11 +00003031 vex_printf(" -> ");
3032 ppIRExpr(replacement);
3033 vex_printf("\n");
3034 }
sewardjdd40fdf2006-12-24 02:20:24 +00003035 bb->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, replacement);
sewardj08210532004-12-29 17:09:11 +00003036 }
3037 }
3038 }
3039
3040}
3041
3042
3043/* Remove redundant PutIs, to the extent which they can be detected.
3044 bb is modified in-place. */
3045
3046static
sewardjdd40fdf2006-12-24 02:20:24 +00003047void do_redundant_PutI_elimination ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003048{
3049 Int i, j;
3050 Bool delete;
3051 IRStmt *st, *stj;
3052
3053 for (i = 0; i < bb->stmts_used; i++) {
3054 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003055 if (st->tag != Ist_PutI)
sewardj08210532004-12-29 17:09:11 +00003056 continue;
3057 /* Ok, search forwards from here to see if we can find another
3058 PutI which makes this one redundant, and dodging various
3059 hazards. Search forwards:
3060 * If conditional exit, give up (because anything after that
3061 does not postdominate this put).
3062 * If a Get which might overlap, give up (because this PutI
3063 not necessarily dead).
3064 * If a Put which is identical, stop with success.
3065 * If a Put which might overlap, but is not identical, give up.
3066 * If a dirty helper call which might write guest state, give up.
3067 * If a Put which definitely doesn't overlap, or any other
3068 kind of stmt, continue.
3069 */
3070 delete = False;
3071 for (j = i+1; j < bb->stmts_used; j++) {
3072 stj = bb->stmts[j];
sewardj8bee6d12005-03-22 02:24:05 +00003073 if (stj->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00003074 continue;
3075 if (identicalPutIs(st, stj)) {
3076 /* success! */
3077 delete = True;
3078 break;
3079 }
3080 if (stj->tag == Ist_Exit)
3081 /* give up */
3082 break;
3083 if (st->tag == Ist_Dirty)
3084 /* give up; could do better here */
3085 break;
3086 if (guestAccessWhichMightOverlapPutI(bb->tyenv, st, stj))
3087 /* give up */
3088 break;
3089 }
3090
3091 if (delete) {
3092 if (DEBUG_IROPT) {
3093 vex_printf("rPI: ");
3094 ppIRStmt(st);
3095 vex_printf("\n");
3096 }
sewardjd2445f62005-03-21 00:15:53 +00003097 bb->stmts[i] = IRStmt_NoOp();
sewardj08210532004-12-29 17:09:11 +00003098 }
3099
3100 }
3101}
3102
3103
3104/*---------------------------------------------------------------*/
3105/*--- Loop unrolling ---*/
3106/*---------------------------------------------------------------*/
3107
3108/* Adjust all tmp values (names) in e by delta. e is destructively
3109 modified. */
3110
3111static void deltaIRExpr ( IRExpr* e, Int delta )
3112{
3113 Int i;
3114 switch (e->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +00003115 case Iex_RdTmp:
3116 e->Iex.RdTmp.tmp += delta;
sewardj08210532004-12-29 17:09:11 +00003117 break;
3118 case Iex_Get:
3119 case Iex_Const:
3120 break;
3121 case Iex_GetI:
3122 deltaIRExpr(e->Iex.GetI.ix, delta);
3123 break;
sewardj1a866b42006-02-09 02:54:03 +00003124 case Iex_Qop:
3125 deltaIRExpr(e->Iex.Qop.arg1, delta);
3126 deltaIRExpr(e->Iex.Qop.arg2, delta);
3127 deltaIRExpr(e->Iex.Qop.arg3, delta);
3128 deltaIRExpr(e->Iex.Qop.arg4, delta);
3129 break;
sewardjb183b852006-02-03 16:08:03 +00003130 case Iex_Triop:
3131 deltaIRExpr(e->Iex.Triop.arg1, delta);
3132 deltaIRExpr(e->Iex.Triop.arg2, delta);
3133 deltaIRExpr(e->Iex.Triop.arg3, delta);
3134 break;
sewardj08210532004-12-29 17:09:11 +00003135 case Iex_Binop:
3136 deltaIRExpr(e->Iex.Binop.arg1, delta);
3137 deltaIRExpr(e->Iex.Binop.arg2, delta);
3138 break;
3139 case Iex_Unop:
3140 deltaIRExpr(e->Iex.Unop.arg, delta);
3141 break;
sewardjaf1ceca2005-06-30 23:31:27 +00003142 case Iex_Load:
3143 deltaIRExpr(e->Iex.Load.addr, delta);
sewardj08210532004-12-29 17:09:11 +00003144 break;
3145 case Iex_CCall:
3146 for (i = 0; e->Iex.CCall.args[i]; i++)
3147 deltaIRExpr(e->Iex.CCall.args[i], delta);
3148 break;
3149 case Iex_Mux0X:
3150 deltaIRExpr(e->Iex.Mux0X.cond, delta);
3151 deltaIRExpr(e->Iex.Mux0X.expr0, delta);
3152 deltaIRExpr(e->Iex.Mux0X.exprX, delta);
3153 break;
3154 default:
3155 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3156 vpanic("deltaIRExpr");
3157 }
3158}
3159
3160/* Adjust all tmp values (names) in st by delta. st is destructively
3161 modified. */
3162
3163static void deltaIRStmt ( IRStmt* st, Int delta )
3164{
3165 Int i;
3166 IRDirty* d;
3167 switch (st->tag) {
sewardjd2445f62005-03-21 00:15:53 +00003168 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00003169 case Ist_IMark:
sewardjf4860352005-06-30 13:38:38 +00003170 case Ist_MFence:
sewardjf1689312005-03-16 18:19:10 +00003171 break;
sewardj5a9ffab2005-05-12 17:55:01 +00003172 case Ist_AbiHint:
3173 deltaIRExpr(st->Ist.AbiHint.base, delta);
3174 break;
sewardj08210532004-12-29 17:09:11 +00003175 case Ist_Put:
3176 deltaIRExpr(st->Ist.Put.data, delta);
3177 break;
3178 case Ist_PutI:
3179 deltaIRExpr(st->Ist.PutI.ix, delta);
3180 deltaIRExpr(st->Ist.PutI.data, delta);
3181 break;
sewardjdd40fdf2006-12-24 02:20:24 +00003182 case Ist_WrTmp:
3183 st->Ist.WrTmp.tmp += delta;
3184 deltaIRExpr(st->Ist.WrTmp.data, delta);
sewardj08210532004-12-29 17:09:11 +00003185 break;
3186 case Ist_Exit:
3187 deltaIRExpr(st->Ist.Exit.guard, delta);
3188 break;
sewardjaf1ceca2005-06-30 23:31:27 +00003189 case Ist_Store:
3190 deltaIRExpr(st->Ist.Store.addr, delta);
3191 deltaIRExpr(st->Ist.Store.data, delta);
sewardj08210532004-12-29 17:09:11 +00003192 break;
3193 case Ist_Dirty:
3194 d = st->Ist.Dirty.details;
3195 deltaIRExpr(d->guard, delta);
3196 for (i = 0; d->args[i]; i++)
3197 deltaIRExpr(d->args[i], delta);
3198 if (d->tmp != IRTemp_INVALID)
3199 d->tmp += delta;
3200 if (d->mAddr)
3201 deltaIRExpr(d->mAddr, delta);
3202 break;
3203 default:
3204 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
3205 vpanic("deltaIRStmt");
3206 }
3207}
3208
3209
3210/* If possible, return a loop-unrolled version of bb0. The original
3211 is changed. If not possible, return NULL. */
3212
3213/* The two schemas considered are:
3214
3215 X: BODY; goto X
3216
3217 which unrolls to (eg) X: BODY;BODY; goto X
3218
3219 and
3220
3221 X: BODY; if (c) goto X; goto Y
3222 which trivially transforms to
3223 X: BODY; if (!c) goto Y; goto X;
3224 so it falls in the scope of the first case.
3225
3226 X and Y must be literal (guest) addresses.
3227*/
3228
sewardjdd40fdf2006-12-24 02:20:24 +00003229static Int calc_unroll_factor( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003230{
3231 Int n_stmts, i;
3232
3233 n_stmts = 0;
sewardj0ddbf792005-04-04 23:12:54 +00003234 for (i = 0; i < bb->stmts_used; i++) {
3235 if (bb->stmts[i]->tag != Ist_NoOp)
3236 n_stmts++;
3237 }
sewardj08210532004-12-29 17:09:11 +00003238
3239 if (n_stmts <= vex_control.iropt_unroll_thresh/8) {
3240 if (vex_control.iropt_verbosity > 0)
3241 vex_printf("vex iropt: 8 x unrolling (%d sts -> %d sts)\n",
3242 n_stmts, 8* n_stmts);
3243 return 8;
3244 }
3245 if (n_stmts <= vex_control.iropt_unroll_thresh/4) {
3246 if (vex_control.iropt_verbosity > 0)
3247 vex_printf("vex iropt: 4 x unrolling (%d sts -> %d sts)\n",
3248 n_stmts, 4* n_stmts);
3249 return 4;
3250 }
3251
3252 if (n_stmts <= vex_control.iropt_unroll_thresh/2) {
3253 if (vex_control.iropt_verbosity > 0)
3254 vex_printf("vex iropt: 2 x unrolling (%d sts -> %d sts)\n",
3255 n_stmts, 2* n_stmts);
3256 return 2;
3257 }
3258
3259 if (vex_control.iropt_verbosity > 0)
3260 vex_printf("vex iropt: not unrolling (%d sts)\n", n_stmts);
3261
3262 return 1;
3263}
3264
3265
sewardjdd40fdf2006-12-24 02:20:24 +00003266static IRSB* maybe_loop_unroll_BB ( IRSB* bb0, Addr64 my_addr )
sewardj08210532004-12-29 17:09:11 +00003267{
3268 Int i, j, jmax, n_vars;
3269 Bool xxx_known;
3270 Addr64 xxx_value, yyy_value;
3271 IRExpr* udst;
3272 IRStmt* st;
3273 IRConst* con;
sewardjdd40fdf2006-12-24 02:20:24 +00003274 IRSB *bb1, *bb2;
sewardj08210532004-12-29 17:09:11 +00003275 Int unroll_factor;
3276
3277 if (vex_control.iropt_unroll_thresh <= 0)
3278 return NULL;
3279
3280 /* First off, figure out if we can unroll this loop. Do this
3281 without modifying bb0. */
3282
3283 if (bb0->jumpkind != Ijk_Boring)
3284 return NULL;
3285
3286 xxx_known = False;
3287 xxx_value = 0;
3288
3289 /* Extract the next-guest address. If it isn't a literal, we
3290 have to give up. */
3291
3292 udst = bb0->next;
3293 if (udst->tag == Iex_Const
3294 && (udst->Iex.Const.con->tag == Ico_U32
3295 || udst->Iex.Const.con->tag == Ico_U64)) {
3296 /* The BB ends in a jump to a literal location. */
3297 xxx_known = True;
3298 xxx_value = udst->Iex.Const.con->tag == Ico_U64
3299 ? udst->Iex.Const.con->Ico.U64
3300 : (Addr64)(udst->Iex.Const.con->Ico.U32);
3301 }
3302
3303 if (!xxx_known)
3304 return NULL;
3305
3306 /* Now we know the BB ends to a jump to a literal location. If
3307 it's a jump to itself (viz, idiom #1), move directly to the
3308 unrolling stage, first cloning the bb so the original isn't
3309 modified. */
3310 if (xxx_value == my_addr) {
3311 unroll_factor = calc_unroll_factor( bb0 );
3312 if (unroll_factor < 2)
3313 return NULL;
sewardjdd40fdf2006-12-24 02:20:24 +00003314 bb1 = deepCopyIRSB( bb0 );
sewardj08210532004-12-29 17:09:11 +00003315 bb0 = NULL;
3316 udst = NULL; /* is now invalid */
3317 goto do_unroll;
3318 }
3319
3320 /* Search for the second idiomatic form:
3321 X: BODY; if (c) goto X; goto Y
3322 We know Y, but need to establish that the last stmt
3323 is 'if (c) goto X'.
3324 */
3325 yyy_value = xxx_value;
3326 for (i = bb0->stmts_used-1; i >= 0; i--)
3327 if (bb0->stmts[i])
3328 break;
3329
3330 if (i < 0)
3331 return NULL; /* block with no stmts. Strange. */
3332
3333 st = bb0->stmts[i];
3334 if (st->tag != Ist_Exit)
3335 return NULL;
3336 if (st->Ist.Exit.jk != Ijk_Boring)
3337 return NULL;
3338
3339 con = st->Ist.Exit.dst;
3340 vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
3341
3342 xxx_value = con->tag == Ico_U64
3343 ? st->Ist.Exit.dst->Ico.U64
3344 : (Addr64)(st->Ist.Exit.dst->Ico.U32);
3345
3346 /* If this assertion fails, we have some kind of type error. */
3347 vassert(con->tag == udst->Iex.Const.con->tag);
3348
3349 if (xxx_value != my_addr)
3350 /* We didn't find either idiom. Give up. */
3351 return NULL;
3352
3353 /* Ok, we found idiom #2. Copy the BB, switch around the xxx and
3354 yyy values (which makes it look like idiom #1), and go into
3355 unrolling proper. This means finding (again) the last stmt, in
3356 the copied BB. */
3357
3358 unroll_factor = calc_unroll_factor( bb0 );
3359 if (unroll_factor < 2)
3360 return NULL;
3361
sewardjdd40fdf2006-12-24 02:20:24 +00003362 bb1 = deepCopyIRSB( bb0 );
sewardj08210532004-12-29 17:09:11 +00003363 bb0 = NULL;
3364 udst = NULL; /* is now invalid */
3365 for (i = bb1->stmts_used-1; i >= 0; i--)
3366 if (bb1->stmts[i])
3367 break;
3368
3369 /* The next bunch of assertions should be true since we already
3370 found and checked the last stmt in the original bb. */
3371
3372 vassert(i >= 0);
3373
3374 st = bb1->stmts[i];
3375 vassert(st->tag == Ist_Exit);
3376
3377 con = st->Ist.Exit.dst;
3378 vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
3379
3380 udst = bb1->next;
3381 vassert(udst->tag == Iex_Const);
3382 vassert(udst->Iex.Const.con->tag == Ico_U32
3383 || udst->Iex.Const.con->tag == Ico_U64);
3384 vassert(con->tag == udst->Iex.Const.con->tag);
3385
3386 /* switch the xxx and yyy fields around */
3387 if (con->tag == Ico_U64) {
3388 udst->Iex.Const.con->Ico.U64 = xxx_value;
3389 con->Ico.U64 = yyy_value;
3390 } else {
3391 udst->Iex.Const.con->Ico.U32 = (UInt)xxx_value;
cerion57b4c6d2005-02-22 11:07:35 +00003392 con->Ico.U32 = (UInt)yyy_value;
sewardj08210532004-12-29 17:09:11 +00003393 }
3394
3395 /* negate the test condition */
3396 st->Ist.Exit.guard
sewardjdd40fdf2006-12-24 02:20:24 +00003397 = IRExpr_Unop(Iop_Not1,deepCopyIRExpr(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +00003398
3399 /* --- The unroller proper. Both idioms are by now --- */
3400 /* --- now converted to idiom 1. --- */
3401
3402 do_unroll:
3403
3404 vassert(unroll_factor == 2
3405 || unroll_factor == 4
3406 || unroll_factor == 8);
3407
3408 jmax = unroll_factor==8 ? 3 : (unroll_factor==4 ? 2 : 1);
3409 for (j = 1; j <= jmax; j++) {
3410
3411 n_vars = bb1->tyenv->types_used;
3412
sewardjdd40fdf2006-12-24 02:20:24 +00003413 bb2 = deepCopyIRSB(bb1);
sewardj08210532004-12-29 17:09:11 +00003414 for (i = 0; i < n_vars; i++)
3415 (void)newIRTemp(bb1->tyenv, bb2->tyenv->types[i]);
3416
3417 for (i = 0; i < bb2->stmts_used; i++) {
sewardj08210532004-12-29 17:09:11 +00003418 /* deltaIRStmt destructively modifies the stmt, but
3419 that's OK since bb2 is a complete fresh copy of bb1. */
3420 deltaIRStmt(bb2->stmts[i], n_vars);
sewardjdd40fdf2006-12-24 02:20:24 +00003421 addStmtToIRSB(bb1, bb2->stmts[i]);
sewardj08210532004-12-29 17:09:11 +00003422 }
3423 }
3424
3425 if (DEBUG_IROPT) {
3426 vex_printf("\nUNROLLED (%llx)\n", my_addr);
sewardjdd40fdf2006-12-24 02:20:24 +00003427 ppIRSB(bb1);
sewardj08210532004-12-29 17:09:11 +00003428 vex_printf("\n");
3429 }
3430
3431 /* Flattening; sigh. The unroller succeeds in breaking flatness
3432 by negating the test condition. This should be fixed properly.
3433 For the moment use this shotgun approach. */
3434 return flatten_BB(bb1);
3435}
3436
3437
3438/*---------------------------------------------------------------*/
sewardj29632392004-08-22 02:38:11 +00003439/*--- The tree builder ---*/
3440/*---------------------------------------------------------------*/
3441
sewardj08210532004-12-29 17:09:11 +00003442/* This isn't part of IR optimisation. Really it's a pass done prior
3443 to instruction selection, which improves the code that the
3444 instruction selector can produce. */
3445
sewardjf9517d02005-11-28 13:39:37 +00003446/* --- The 'tmp' environment is the central data structure here --- */
sewardj29632392004-08-22 02:38:11 +00003447
sewardjf9517d02005-11-28 13:39:37 +00003448/* The number of outstanding bindings we're prepared to track.
3449 The number of times the env becomes full and we have to dump
3450 the oldest binding (hence reducing code quality) falls very
3451 rapidly as the env size increases. 8 gives reasonable performance
3452 under most circumstances. */
3453#define A_NENV 10
3454
3455/* bindee == NULL === slot is not in use
3456 bindee != NULL === slot is in use
sewardj29632392004-08-22 02:38:11 +00003457*/
sewardjf9517d02005-11-28 13:39:37 +00003458typedef
3459 struct {
3460 IRTemp binder;
3461 IRExpr* bindee;
3462 Bool doesLoad;
3463 Bool doesGet;
sewardj17442fe2004-09-20 14:54:28 +00003464 }
sewardjf9517d02005-11-28 13:39:37 +00003465 ATmpInfo;
sewardj17442fe2004-09-20 14:54:28 +00003466
sewardjf9517d02005-11-28 13:39:37 +00003467__attribute__((unused))
3468static void ppAEnv ( ATmpInfo* env )
sewardj29632392004-08-22 02:38:11 +00003469{
sewardj17442fe2004-09-20 14:54:28 +00003470 Int i;
sewardjf9517d02005-11-28 13:39:37 +00003471 for (i = 0; i < A_NENV; i++) {
3472 vex_printf("%d tmp %d val ", i, (Int)env[i].binder);
3473 if (env[i].bindee)
3474 ppIRExpr(env[i].bindee);
3475 else
3476 vex_printf("(null)");
3477 vex_printf("\n");
sewardj29632392004-08-22 02:38:11 +00003478 }
3479}
3480
sewardjf9517d02005-11-28 13:39:37 +00003481/* --- Tree-traversal fns --- */
sewardj29632392004-08-22 02:38:11 +00003482
sewardj37d38012004-08-24 00:37:04 +00003483/* Traverse an expr, and detect if any part of it reads memory or does
3484 a Get. Be careful ... this really controls how much the
3485 tree-builder can reorder the code, so getting it right is critical.
3486*/
sewardj29632392004-08-22 02:38:11 +00003487static void setHints_Expr (Bool* doesLoad, Bool* doesGet, IRExpr* e )
3488{
sewardjc41f1fb2004-08-22 09:48:08 +00003489 Int i;
sewardj29632392004-08-22 02:38:11 +00003490 switch (e->tag) {
sewardjc41f1fb2004-08-22 09:48:08 +00003491 case Iex_CCall:
3492 for (i = 0; e->Iex.CCall.args[i]; i++)
3493 setHints_Expr(doesLoad, doesGet, e->Iex.CCall.args[i]);
3494 return;
3495 case Iex_Mux0X:
3496 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.cond);
3497 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.expr0);
3498 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.exprX);
3499 return;
sewardj40c80262006-02-08 19:30:46 +00003500 case Iex_Qop:
3501 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.arg1);
3502 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.arg2);
3503 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.arg3);
3504 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.arg4);
3505 return;
sewardjb183b852006-02-03 16:08:03 +00003506 case Iex_Triop:
3507 setHints_Expr(doesLoad, doesGet, e->Iex.Triop.arg1);
3508 setHints_Expr(doesLoad, doesGet, e->Iex.Triop.arg2);
3509 setHints_Expr(doesLoad, doesGet, e->Iex.Triop.arg3);
3510 return;
sewardjc41f1fb2004-08-22 09:48:08 +00003511 case Iex_Binop:
3512 setHints_Expr(doesLoad, doesGet, e->Iex.Binop.arg1);
3513 setHints_Expr(doesLoad, doesGet, e->Iex.Binop.arg2);
3514 return;
3515 case Iex_Unop:
3516 setHints_Expr(doesLoad, doesGet, e->Iex.Unop.arg);
3517 return;
sewardjaf1ceca2005-06-30 23:31:27 +00003518 case Iex_Load:
sewardjc9ad1152004-10-14 00:08:21 +00003519 *doesLoad = True;
sewardjaf1ceca2005-06-30 23:31:27 +00003520 setHints_Expr(doesLoad, doesGet, e->Iex.Load.addr);
sewardjc41f1fb2004-08-22 09:48:08 +00003521 return;
sewardj29632392004-08-22 02:38:11 +00003522 case Iex_Get:
sewardjc9ad1152004-10-14 00:08:21 +00003523 *doesGet = True;
sewardj29632392004-08-22 02:38:11 +00003524 return;
sewardjf6501992004-08-27 11:58:24 +00003525 case Iex_GetI:
sewardjc9ad1152004-10-14 00:08:21 +00003526 *doesGet = True;
sewardjeeac8412004-11-02 00:26:55 +00003527 setHints_Expr(doesLoad, doesGet, e->Iex.GetI.ix);
sewardjf6501992004-08-27 11:58:24 +00003528 return;
sewardjdd40fdf2006-12-24 02:20:24 +00003529 case Iex_RdTmp:
sewardjc41f1fb2004-08-22 09:48:08 +00003530 case Iex_Const:
3531 return;
sewardj29632392004-08-22 02:38:11 +00003532 default:
3533 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3534 vpanic("setHints_Expr");
3535 }
3536}
3537
3538
sewardjf9517d02005-11-28 13:39:37 +00003539/* Add a binding to the front of the env and slide all the rest
3540 backwards. It should be the case that the last slot is free. */
3541static void addToEnvFront ( ATmpInfo* env, IRTemp binder, IRExpr* bindee )
sewardj29632392004-08-22 02:38:11 +00003542{
sewardjf9517d02005-11-28 13:39:37 +00003543 Int i;
3544 vassert(env[A_NENV-1].bindee == NULL);
3545 for (i = A_NENV-1; i >= 1; i--)
3546 env[i] = env[i-1];
3547 env[0].binder = binder;
3548 env[0].bindee = bindee;
3549 env[0].doesLoad = False; /* filled in later */
3550 env[0].doesGet = False; /* filled in later */
3551}
sewardj29632392004-08-22 02:38:11 +00003552
sewardjf9517d02005-11-28 13:39:37 +00003553/* Given uses :: array of UShort, indexed by IRTemp
3554 Add the use-occurrences of temps in this expression
3555 to the env.
3556*/
3557static void aoccCount_Expr ( UShort* uses, IRExpr* e )
3558{
3559 Int i;
sewardj29632392004-08-22 02:38:11 +00003560
sewardjf9517d02005-11-28 13:39:37 +00003561 switch (e->tag) {
3562
sewardjdd40fdf2006-12-24 02:20:24 +00003563 case Iex_RdTmp: /* the only interesting case */
3564 uses[e->Iex.RdTmp.tmp]++;
sewardj8bee6d12005-03-22 02:24:05 +00003565 return;
sewardj29632392004-08-22 02:38:11 +00003566
sewardjf9517d02005-11-28 13:39:37 +00003567 case Iex_Mux0X:
3568 aoccCount_Expr(uses, e->Iex.Mux0X.cond);
3569 aoccCount_Expr(uses, e->Iex.Mux0X.expr0);
3570 aoccCount_Expr(uses, e->Iex.Mux0X.exprX);
3571 return;
sewardj29632392004-08-22 02:38:11 +00003572
sewardj40c80262006-02-08 19:30:46 +00003573 case Iex_Qop:
3574 aoccCount_Expr(uses, e->Iex.Qop.arg1);
3575 aoccCount_Expr(uses, e->Iex.Qop.arg2);
3576 aoccCount_Expr(uses, e->Iex.Qop.arg3);
3577 aoccCount_Expr(uses, e->Iex.Qop.arg4);
3578 return;
3579
sewardjb183b852006-02-03 16:08:03 +00003580 case Iex_Triop:
3581 aoccCount_Expr(uses, e->Iex.Triop.arg1);
3582 aoccCount_Expr(uses, e->Iex.Triop.arg2);
3583 aoccCount_Expr(uses, e->Iex.Triop.arg3);
3584 return;
3585
sewardjf9517d02005-11-28 13:39:37 +00003586 case Iex_Binop:
3587 aoccCount_Expr(uses, e->Iex.Binop.arg1);
3588 aoccCount_Expr(uses, e->Iex.Binop.arg2);
3589 return;
sewardj29632392004-08-22 02:38:11 +00003590
sewardjf9517d02005-11-28 13:39:37 +00003591 case Iex_Unop:
3592 aoccCount_Expr(uses, e->Iex.Unop.arg);
3593 return;
3594
3595 case Iex_Load:
3596 aoccCount_Expr(uses, e->Iex.Load.addr);
3597 return;
3598
3599 case Iex_CCall:
3600 for (i = 0; e->Iex.CCall.args[i]; i++)
3601 aoccCount_Expr(uses, e->Iex.CCall.args[i]);
3602 return;
3603
3604 case Iex_GetI:
3605 aoccCount_Expr(uses, e->Iex.GetI.ix);
3606 return;
3607
3608 case Iex_Const:
3609 case Iex_Get:
3610 return;
3611
3612 default:
3613 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3614 vpanic("aoccCount_Expr");
3615 }
sewardj29632392004-08-22 02:38:11 +00003616}
3617
3618
sewardjf9517d02005-11-28 13:39:37 +00003619/* Given uses :: array of UShort, indexed by IRTemp
3620 Add the use-occurrences of temps in this statement
3621 to the env.
3622*/
3623static void aoccCount_Stmt ( UShort* uses, IRStmt* st )
sewardj29632392004-08-22 02:38:11 +00003624{
sewardjf9517d02005-11-28 13:39:37 +00003625 Int i;
3626 IRDirty* d;
3627 switch (st->tag) {
3628 case Ist_AbiHint:
3629 aoccCount_Expr(uses, st->Ist.AbiHint.base);
3630 return;
sewardjdd40fdf2006-12-24 02:20:24 +00003631 case Ist_WrTmp:
3632 aoccCount_Expr(uses, st->Ist.WrTmp.data);
sewardjf9517d02005-11-28 13:39:37 +00003633 return;
3634 case Ist_Put:
3635 aoccCount_Expr(uses, st->Ist.Put.data);
3636 return;
3637 case Ist_PutI:
3638 aoccCount_Expr(uses, st->Ist.PutI.ix);
3639 aoccCount_Expr(uses, st->Ist.PutI.data);
3640 return;
3641 case Ist_Store:
3642 aoccCount_Expr(uses, st->Ist.Store.addr);
3643 aoccCount_Expr(uses, st->Ist.Store.data);
3644 return;
3645 case Ist_Dirty:
3646 d = st->Ist.Dirty.details;
3647 if (d->mFx != Ifx_None)
3648 aoccCount_Expr(uses, d->mAddr);
3649 aoccCount_Expr(uses, d->guard);
3650 for (i = 0; d->args[i]; i++)
3651 aoccCount_Expr(uses, d->args[i]);
3652 return;
3653 case Ist_NoOp:
3654 case Ist_IMark:
3655 case Ist_MFence:
3656 return;
3657 case Ist_Exit:
3658 aoccCount_Expr(uses, st->Ist.Exit.guard);
3659 return;
3660 default:
3661 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
3662 vpanic("aoccCount_Stmt");
3663 }
3664}
3665
3666/* Look up a binding for tmp in the env. If found, return the bound
3667 expression, and set the env's binding to NULL so it is marked as
3668 used. If not found, return NULL. */
3669
3670static IRExpr* atbSubst_Temp ( ATmpInfo* env, IRTemp tmp )
3671{
3672 Int i;
3673 for (i = 0; i < A_NENV; i++) {
3674 if (env[i].binder == tmp && env[i].bindee != NULL) {
3675 IRExpr* bindee = env[i].bindee;
3676 env[i].bindee = NULL;
3677 return bindee;
3678 }
3679 }
3680 return NULL;
3681}
3682
3683/* Traverse e, looking for temps. For each observed temp, see if env
3684 contains a binding for the temp, and if so return the bound value.
3685 The env has the property that any binding it holds is
3686 'single-shot', so once a binding is used, it is marked as no longer
3687 available, by setting its .bindee field to NULL. */
3688
3689static IRExpr* atbSubst_Expr ( ATmpInfo* env, IRExpr* e )
3690{
3691 IRExpr* e2;
3692 IRExpr** args2;
3693 Int i;
3694
3695 switch (e->tag) {
3696
3697 case Iex_CCall:
sewardjdd40fdf2006-12-24 02:20:24 +00003698 args2 = shallowCopyIRExprVec(e->Iex.CCall.args);
sewardjf9517d02005-11-28 13:39:37 +00003699 for (i = 0; args2[i]; i++)
3700 args2[i] = atbSubst_Expr(env,args2[i]);
3701 return IRExpr_CCall(
3702 e->Iex.CCall.cee,
3703 e->Iex.CCall.retty,
3704 args2
3705 );
sewardjdd40fdf2006-12-24 02:20:24 +00003706 case Iex_RdTmp:
3707 e2 = atbSubst_Temp(env, e->Iex.RdTmp.tmp);
sewardjf9517d02005-11-28 13:39:37 +00003708 return e2 ? e2 : e;
3709 case Iex_Mux0X:
3710 return IRExpr_Mux0X(
3711 atbSubst_Expr(env, e->Iex.Mux0X.cond),
3712 atbSubst_Expr(env, e->Iex.Mux0X.expr0),
3713 atbSubst_Expr(env, e->Iex.Mux0X.exprX)
3714 );
sewardj40c80262006-02-08 19:30:46 +00003715 case Iex_Qop:
3716 return IRExpr_Qop(
3717 e->Iex.Qop.op,
3718 atbSubst_Expr(env, e->Iex.Qop.arg1),
3719 atbSubst_Expr(env, e->Iex.Qop.arg2),
3720 atbSubst_Expr(env, e->Iex.Qop.arg3),
3721 atbSubst_Expr(env, e->Iex.Qop.arg4)
3722 );
sewardjb183b852006-02-03 16:08:03 +00003723 case Iex_Triop:
3724 return IRExpr_Triop(
3725 e->Iex.Triop.op,
3726 atbSubst_Expr(env, e->Iex.Triop.arg1),
3727 atbSubst_Expr(env, e->Iex.Triop.arg2),
3728 atbSubst_Expr(env, e->Iex.Triop.arg3)
3729 );
sewardjf9517d02005-11-28 13:39:37 +00003730 case Iex_Binop:
3731 return IRExpr_Binop(
3732 e->Iex.Binop.op,
3733 atbSubst_Expr(env, e->Iex.Binop.arg1),
3734 atbSubst_Expr(env, e->Iex.Binop.arg2)
3735 );
3736 case Iex_Unop:
3737 return IRExpr_Unop(
3738 e->Iex.Unop.op,
3739 atbSubst_Expr(env, e->Iex.Unop.arg)
3740 );
3741 case Iex_Load:
3742 return IRExpr_Load(
3743 e->Iex.Load.end,
3744 e->Iex.Load.ty,
3745 atbSubst_Expr(env, e->Iex.Load.addr)
3746 );
3747 case Iex_GetI:
3748 return IRExpr_GetI(
3749 e->Iex.GetI.descr,
3750 atbSubst_Expr(env, e->Iex.GetI.ix),
3751 e->Iex.GetI.bias
3752 );
3753 case Iex_Const:
3754 case Iex_Get:
3755 return e;
3756 default:
3757 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3758 vpanic("atbSubst_Expr");
3759 }
3760}
3761
3762/* Same deal as atbSubst_Expr, except for stmts. */
3763
3764static IRStmt* atbSubst_Stmt ( ATmpInfo* env, IRStmt* st )
3765{
3766 Int i;
3767 IRDirty* d;
3768 IRDirty* d2;
3769 switch (st->tag) {
3770 case Ist_AbiHint:
3771 return IRStmt_AbiHint(
3772 atbSubst_Expr(env, st->Ist.AbiHint.base),
3773 st->Ist.AbiHint.len
3774 );
3775 case Ist_Store:
3776 return IRStmt_Store(
3777 st->Ist.Store.end,
3778 atbSubst_Expr(env, st->Ist.Store.addr),
3779 atbSubst_Expr(env, st->Ist.Store.data)
3780 );
sewardjdd40fdf2006-12-24 02:20:24 +00003781 case Ist_WrTmp:
3782 return IRStmt_WrTmp(
3783 st->Ist.WrTmp.tmp,
3784 atbSubst_Expr(env, st->Ist.WrTmp.data)
sewardjf9517d02005-11-28 13:39:37 +00003785 );
3786 case Ist_Put:
3787 return IRStmt_Put(
3788 st->Ist.Put.offset,
3789 atbSubst_Expr(env, st->Ist.Put.data)
3790 );
3791 case Ist_PutI:
3792 return IRStmt_PutI(
3793 st->Ist.PutI.descr,
3794 atbSubst_Expr(env, st->Ist.PutI.ix),
3795 st->Ist.PutI.bias,
3796 atbSubst_Expr(env, st->Ist.PutI.data)
3797 );
3798
3799 case Ist_Exit:
3800 return IRStmt_Exit(
3801 atbSubst_Expr(env, st->Ist.Exit.guard),
3802 st->Ist.Exit.jk,
3803 st->Ist.Exit.dst
3804 );
3805 case Ist_IMark:
3806 return IRStmt_IMark(st->Ist.IMark.addr, st->Ist.IMark.len);
3807 case Ist_NoOp:
3808 return IRStmt_NoOp();
3809 case Ist_MFence:
3810 return IRStmt_MFence();
3811 case Ist_Dirty:
3812 d = st->Ist.Dirty.details;
3813 d2 = emptyIRDirty();
3814 *d2 = *d;
3815 if (d2->mFx != Ifx_None)
3816 d2->mAddr = atbSubst_Expr(env, d2->mAddr);
3817 d2->guard = atbSubst_Expr(env, d2->guard);
3818 for (i = 0; d2->args[i]; i++)
3819 d2->args[i] = atbSubst_Expr(env, d2->args[i]);
3820 return IRStmt_Dirty(d2);
3821 default:
3822 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
3823 vpanic("atbSubst_Stmt");
3824 }
3825}
3826
sewardjdd40fdf2006-12-24 02:20:24 +00003827/* notstatic */ void ado_treebuild_BB ( IRSB* bb )
sewardjf9517d02005-11-28 13:39:37 +00003828{
3829 Int i, j, k, m;
3830 Bool stmtPuts, stmtStores, invalidateMe;
sewardj29632392004-08-22 02:38:11 +00003831 IRStmt* st;
3832 IRStmt* st2;
sewardjf9517d02005-11-28 13:39:37 +00003833 ATmpInfo env[A_NENV];
sewardj29632392004-08-22 02:38:11 +00003834
sewardjc9ad1152004-10-14 00:08:21 +00003835 Int n_tmps = bb->tyenv->types_used;
sewardjf9517d02005-11-28 13:39:37 +00003836 UShort* uses = LibVEX_Alloc(n_tmps * sizeof(UShort));
sewardj29632392004-08-22 02:38:11 +00003837
3838 /* Phase 1. Scan forwards in bb, counting use occurrences of each
3839 temp. Also count occurrences in the bb->next field. */
3840
sewardjf9517d02005-11-28 13:39:37 +00003841 for (i = 0; i < n_tmps; i++)
3842 uses[i] = 0;
3843
sewardj29632392004-08-22 02:38:11 +00003844 for (i = 0; i < bb->stmts_used; i++) {
3845 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003846 if (st->tag == Ist_NoOp)
sewardj29632392004-08-22 02:38:11 +00003847 continue;
sewardjf9517d02005-11-28 13:39:37 +00003848 aoccCount_Stmt( uses, st );
sewardj29632392004-08-22 02:38:11 +00003849 }
sewardjf9517d02005-11-28 13:39:37 +00003850 aoccCount_Expr(uses, bb->next );
sewardj29632392004-08-22 02:38:11 +00003851
sewardjc9ad1152004-10-14 00:08:21 +00003852# if 0
sewardjf9517d02005-11-28 13:39:37 +00003853 for (i = 0; i < n_tmps; i++) {
3854 if (uses[i] == 0)
sewardj29632392004-08-22 02:38:11 +00003855 continue;
sewardjf9517d02005-11-28 13:39:37 +00003856 ppIRTemp( (IRTemp)i );
3857 vex_printf(" used %d\n", (Int)uses[i] );
sewardj29632392004-08-22 02:38:11 +00003858 }
sewardjc9ad1152004-10-14 00:08:21 +00003859# endif
sewardj29632392004-08-22 02:38:11 +00003860
sewardjf9517d02005-11-28 13:39:37 +00003861 /* Phase 2. Scan forwards in bb. For each statement in turn:
sewardj29632392004-08-22 02:38:11 +00003862
sewardjf9517d02005-11-28 13:39:37 +00003863 If the env is full, emit the end element. This guarantees
3864 there is at least one free slot in the following.
sewardj29632392004-08-22 02:38:11 +00003865
sewardjf9517d02005-11-28 13:39:37 +00003866 On seeing 't = E', occ(t)==1,
3867 let E'=env(E)
3868 delete this stmt
3869 add t -> E' to the front of the env
3870 Examine E' and set the hints for E' appropriately
sewardj29632392004-08-22 02:38:11 +00003871 (doesLoad? doesGet?)
3872
sewardjf9517d02005-11-28 13:39:37 +00003873 On seeing any other stmt,
sewardj29632392004-08-22 02:38:11 +00003874 let stmt' = env(stmt)
3875 remove from env any 't=E' binds invalidated by stmt
3876 emit the invalidated stmts
3877 emit stmt'
sewardjf9517d02005-11-28 13:39:37 +00003878 compact any holes in env
3879 by sliding entries towards the front
sewardj29632392004-08-22 02:38:11 +00003880
sewardjf9517d02005-11-28 13:39:37 +00003881 Finally, apply env to bb->next.
sewardj29632392004-08-22 02:38:11 +00003882 */
3883
sewardjf9517d02005-11-28 13:39:37 +00003884 for (i = 0; i < A_NENV; i++) {
3885 env[i].bindee = NULL;
3886 env[i].binder = IRTemp_INVALID;
3887 }
3888
sewardj29632392004-08-22 02:38:11 +00003889 /* The stmts in bb are being reordered, and we are guaranteed to
3890 end up with no more than the number we started with. Use i to
3891 be the cursor of the current stmt examined and j <= i to be that
3892 for the current stmt being written.
3893 */
3894 j = 0;
3895 for (i = 0; i < bb->stmts_used; i++) {
sewardjf9517d02005-11-28 13:39:37 +00003896
sewardj29632392004-08-22 02:38:11 +00003897 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003898 if (st->tag == Ist_NoOp)
sewardj29632392004-08-22 02:38:11 +00003899 continue;
3900
sewardjf9517d02005-11-28 13:39:37 +00003901 /* Ensure there's at least one space in the env, by emitting
3902 the oldest binding if necessary. */
3903 if (env[A_NENV-1].bindee != NULL) {
sewardjdd40fdf2006-12-24 02:20:24 +00003904 bb->stmts[j] = IRStmt_WrTmp( env[A_NENV-1].binder,
3905 env[A_NENV-1].bindee );
sewardjf9517d02005-11-28 13:39:37 +00003906 j++;
3907 vassert(j <= i);
3908 env[A_NENV-1].bindee = NULL;
3909 }
3910
3911 /* Consider current stmt. */
sewardjdd40fdf2006-12-24 02:20:24 +00003912 if (st->tag == Ist_WrTmp && uses[st->Ist.WrTmp.tmp] <= 1) {
sewardj63327402006-01-25 03:26:27 +00003913 IRExpr *e, *e2;
sewardjf9517d02005-11-28 13:39:37 +00003914
3915 /* optional extra: dump dead bindings as we find them.
3916 Removes the need for a prior dead-code removal pass. */
sewardjdd40fdf2006-12-24 02:20:24 +00003917 if (uses[st->Ist.WrTmp.tmp] == 0) {
sewardjb183b852006-02-03 16:08:03 +00003918 if (0) vex_printf("DEAD binding\n");
sewardjf9517d02005-11-28 13:39:37 +00003919 continue; /* for (i = 0; i < bb->stmts_used; i++) loop */
sewardj29632392004-08-22 02:38:11 +00003920 }
sewardjdd40fdf2006-12-24 02:20:24 +00003921 vassert(uses[st->Ist.WrTmp.tmp] == 1);
sewardjf9517d02005-11-28 13:39:37 +00003922
3923 /* ok, we have 't = E', occ(t)==1. Do the abovementioned
3924 actions. */
sewardjdd40fdf2006-12-24 02:20:24 +00003925 e = st->Ist.WrTmp.data;
sewardj63327402006-01-25 03:26:27 +00003926 e2 = atbSubst_Expr(env, e);
sewardjdd40fdf2006-12-24 02:20:24 +00003927 addToEnvFront(env, st->Ist.WrTmp.tmp, e2);
sewardjf9517d02005-11-28 13:39:37 +00003928 setHints_Expr(&env[0].doesLoad, &env[0].doesGet, e2);
3929 /* don't advance j, as we are deleting this stmt and instead
3930 holding it temporarily in the env. */
3931 continue; /* for (i = 0; i < bb->stmts_used; i++) loop */
sewardj29632392004-08-22 02:38:11 +00003932 }
3933
3934 /* we get here for any other kind of statement. */
3935 /* 'use up' any bindings required by the current statement. */
sewardjf9517d02005-11-28 13:39:37 +00003936 st2 = atbSubst_Stmt(env, st);
sewardj29632392004-08-22 02:38:11 +00003937
sewardjf9517d02005-11-28 13:39:37 +00003938 /* Now, before this stmt, dump any bindings in env that it
3939 invalidates. These need to be dumped in the order in which
3940 they originally entered env -- that means from oldest to
3941 youngest. */
sewardj3e838932005-01-07 12:09:15 +00003942
sewardjf9517d02005-11-28 13:39:37 +00003943 /* stmtPuts/stmtStores characterise what the stmt under
3944 consideration does. */
3945 stmtPuts = toBool(st->tag == Ist_Put
3946 || st->tag == Ist_PutI
sewardj9d2e7692005-02-07 01:11:31 +00003947 || st->tag == Ist_Dirty);
sewardj29632392004-08-22 02:38:11 +00003948
sewardjf9517d02005-11-28 13:39:37 +00003949 stmtStores = toBool(st->tag == Ist_Store
3950 || st->tag == Ist_Dirty);
sewardj29632392004-08-22 02:38:11 +00003951
sewardjf9517d02005-11-28 13:39:37 +00003952 for (k = A_NENV-1; k >= 0; k--) {
3953 if (env[k].bindee == NULL)
3954 continue;
3955 /* Compare the actions of this stmt with the actions of
3956 binding 'k', to see if they invalidate the binding. */
3957 invalidateMe
sewardj9d2e7692005-02-07 01:11:31 +00003958 = toBool(
3959 /* a store invalidates loaded data */
sewardjf9517d02005-11-28 13:39:37 +00003960 (env[k].doesLoad && stmtStores)
sewardj4c5f6d52004-10-26 13:25:33 +00003961 /* a put invalidates get'd data */
sewardjf9517d02005-11-28 13:39:37 +00003962 || (env[k].doesGet && stmtPuts)
sewardj4c5f6d52004-10-26 13:25:33 +00003963 /* a put invalidates loaded data. Note, we could do
3964 much better here in the sense that we only need to
3965 invalidate trees containing loads if the Put in
3966 question is marked as requiring precise
3967 exceptions. */
sewardjf9517d02005-11-28 13:39:37 +00003968 || (env[k].doesLoad && stmtPuts)
sewardj3e838932005-01-07 12:09:15 +00003969 /* probably overly conservative: a memory fence
3970 invalidates absolutely everything, so that all
3971 computation prior to it is forced to complete before
3972 proceeding with the fence. */
sewardj9d2e7692005-02-07 01:11:31 +00003973 || st->tag == Ist_MFence
sewardj5a9ffab2005-05-12 17:55:01 +00003974 /* also be (probably overly) paranoid re AbiHints */
3975 || st->tag == Ist_AbiHint
sewardj9d2e7692005-02-07 01:11:31 +00003976 );
sewardjf9517d02005-11-28 13:39:37 +00003977 if (invalidateMe) {
sewardjdd40fdf2006-12-24 02:20:24 +00003978 bb->stmts[j] = IRStmt_WrTmp( env[k].binder, env[k].bindee );
sewardjf9517d02005-11-28 13:39:37 +00003979 j++;
3980 vassert(j <= i);
3981 env[k].bindee = NULL;
3982 }
sewardj29632392004-08-22 02:38:11 +00003983 }
3984
sewardjf9517d02005-11-28 13:39:37 +00003985 /* Slide in-use entries in env up to the front */
3986 m = 0;
3987 for (k = 0; k < A_NENV; k++) {
3988 if (env[k].bindee != NULL) {
3989 env[m] = env[k];
3990 m++;
3991 }
3992 }
3993 for (m = m; m < A_NENV; m++) {
3994 env[m].bindee = NULL;
3995 }
sewardj29632392004-08-22 02:38:11 +00003996
3997 /* finally, emit the substituted statement */
3998 bb->stmts[j] = st2;
sewardjf9517d02005-11-28 13:39:37 +00003999 /* vex_printf("**2 "); ppIRStmt(bb->stmts[j]); vex_printf("\n"); */
sewardj29632392004-08-22 02:38:11 +00004000 j++;
4001
4002 vassert(j <= i+1);
4003 } /* for each stmt in the original bb ... */
4004
4005 /* Finally ... substitute the ->next field as much as possible, and
4006 dump any left-over bindings. Hmm. Perhaps there should be no
4007 left over bindings? Or any left-over bindings are
4008 by definition dead? */
sewardjf9517d02005-11-28 13:39:37 +00004009 bb->next = atbSubst_Expr(env, bb->next);
sewardj29632392004-08-22 02:38:11 +00004010 bb->stmts_used = j;
4011}
4012
4013
sewardj695cff92004-10-13 14:50:14 +00004014/*---------------------------------------------------------------*/
sewardjedf4d692004-08-17 13:52:58 +00004015/*--- iropt main ---*/
4016/*---------------------------------------------------------------*/
4017
sewardjb183b852006-02-03 16:08:03 +00004018static Bool iropt_verbose = False; /* True; */
sewardj4345f7a2004-09-22 19:49:27 +00004019
4020
sewardj4345f7a2004-09-22 19:49:27 +00004021/* Do a simple cleanup pass on bb. This is: redundant Get removal,
4022 redundant Put removal, constant propagation, dead code removal,
4023 clean helper specialisation, and dead code removal (again).
sewardjb9230752004-12-29 19:25:06 +00004024*/
sewardj695cff92004-10-13 14:50:14 +00004025
sewardj4345f7a2004-09-22 19:49:27 +00004026
4027static
sewardjdd40fdf2006-12-24 02:20:24 +00004028IRSB* cheap_transformations (
4029 IRSB* bb,
sewardj9d2e7692005-02-07 01:11:31 +00004030 IRExpr* (*specHelper) (HChar*, IRExpr**),
sewardj8d2291c2004-10-25 14:50:21 +00004031 Bool (*preciseMemExnsFn)(Int,Int)
4032 )
sewardj4345f7a2004-09-22 19:49:27 +00004033{
4034 redundant_get_removal_BB ( bb );
4035 if (iropt_verbose) {
4036 vex_printf("\n========= REDUNDANT GET\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004037 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004038 }
sewardj044a2152004-10-21 10:22:10 +00004039
sewardj8d2291c2004-10-25 14:50:21 +00004040 redundant_put_removal_BB ( bb, preciseMemExnsFn );
sewardj4345f7a2004-09-22 19:49:27 +00004041 if (iropt_verbose) {
4042 vex_printf("\n========= REDUNDANT PUT\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004043 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004044 }
sewardj044a2152004-10-21 10:22:10 +00004045
sewardj4345f7a2004-09-22 19:49:27 +00004046 bb = cprop_BB ( bb );
4047 if (iropt_verbose) {
4048 vex_printf("\n========= CPROPD\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004049 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004050 }
4051
sewardj49651f42004-10-28 22:11:04 +00004052 do_deadcode_BB ( bb );
sewardj4345f7a2004-09-22 19:49:27 +00004053 if (iropt_verbose) {
4054 vex_printf("\n========= DEAD\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004055 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004056 }
4057
sewardjb9230752004-12-29 19:25:06 +00004058 bb = spec_helpers_BB ( bb, specHelper );
sewardj49651f42004-10-28 22:11:04 +00004059 do_deadcode_BB ( bb );
sewardj4345f7a2004-09-22 19:49:27 +00004060 if (iropt_verbose) {
4061 vex_printf("\n========= SPECd \n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004062 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004063 }
4064
4065 return bb;
4066}
4067
sewardj695cff92004-10-13 14:50:14 +00004068
4069/* Do some more expensive transformations on bb, which are aimed at
4070 optimising as much as possible in the presence of GetI and PutI. */
4071
4072static
sewardjdd40fdf2006-12-24 02:20:24 +00004073IRSB* expensive_transformations( IRSB* bb )
sewardj695cff92004-10-13 14:50:14 +00004074{
sewardj9b0cc582006-02-04 15:24:00 +00004075 (void)do_cse_BB( bb );
sewardj695cff92004-10-13 14:50:14 +00004076 collapse_AddSub_chains_BB( bb );
sewardj08210532004-12-29 17:09:11 +00004077 do_redundant_GetI_elimination( bb );
sewardj695cff92004-10-13 14:50:14 +00004078 do_redundant_PutI_elimination( bb );
sewardj49651f42004-10-28 22:11:04 +00004079 do_deadcode_BB( bb );
sewardjb9230752004-12-29 19:25:06 +00004080 return bb;
sewardj695cff92004-10-13 14:50:14 +00004081}
4082
4083
sewardjb183b852006-02-03 16:08:03 +00004084/* Scan a flattened BB to look for signs that more expensive
4085 optimisations might be useful:
4086 - find out if there are any GetIs and PutIs
4087 - find out if there are any floating or vector-typed temporaries
4088*/
sewardj695cff92004-10-13 14:50:14 +00004089
sewardjb183b852006-02-03 16:08:03 +00004090static void considerExpensives ( /*OUT*/Bool* hasGetIorPutI,
4091 /*OUT*/Bool* hasVorFtemps,
sewardjdd40fdf2006-12-24 02:20:24 +00004092 IRSB* bb )
sewardj4345f7a2004-09-22 19:49:27 +00004093{
4094 Int i, j;
4095 IRStmt* st;
4096 IRDirty* d;
4097
sewardjb183b852006-02-03 16:08:03 +00004098 *hasGetIorPutI = False;
4099 *hasVorFtemps = False;
4100
sewardj4345f7a2004-09-22 19:49:27 +00004101 for (i = 0; i < bb->stmts_used; i++) {
4102 st = bb->stmts[i];
sewardj4345f7a2004-09-22 19:49:27 +00004103 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00004104 case Ist_AbiHint:
4105 vassert(isIRAtom(st->Ist.AbiHint.base));
4106 break;
sewardj4345f7a2004-09-22 19:49:27 +00004107 case Ist_PutI:
sewardjb183b852006-02-03 16:08:03 +00004108 *hasGetIorPutI = True;
4109 break;
sewardjdd40fdf2006-12-24 02:20:24 +00004110 case Ist_WrTmp:
4111 if (st->Ist.WrTmp.data->tag == Iex_GetI)
sewardjb183b852006-02-03 16:08:03 +00004112 *hasGetIorPutI = True;
sewardjdd40fdf2006-12-24 02:20:24 +00004113 switch (typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp)) {
sewardjb183b852006-02-03 16:08:03 +00004114 case Ity_I1: case Ity_I8: case Ity_I16:
4115 case Ity_I32: case Ity_I64: case Ity_I128:
4116 break;
4117 case Ity_F32: case Ity_F64: case Ity_V128:
4118 *hasVorFtemps = True;
4119 break;
4120 default:
4121 goto bad;
4122 }
sewardj4345f7a2004-09-22 19:49:27 +00004123 break;
4124 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00004125 vassert(isIRAtom(st->Ist.Put.data));
sewardj4345f7a2004-09-22 19:49:27 +00004126 break;
sewardjaf1ceca2005-06-30 23:31:27 +00004127 case Ist_Store:
4128 vassert(isIRAtom(st->Ist.Store.addr));
4129 vassert(isIRAtom(st->Ist.Store.data));
sewardj4345f7a2004-09-22 19:49:27 +00004130 break;
sewardj4345f7a2004-09-22 19:49:27 +00004131 case Ist_Dirty:
4132 d = st->Ist.Dirty.details;
sewardj496a58d2005-03-20 18:44:44 +00004133 vassert(isIRAtom(d->guard));
sewardj4345f7a2004-09-22 19:49:27 +00004134 for (j = 0; d->args[j]; j++)
sewardj496a58d2005-03-20 18:44:44 +00004135 vassert(isIRAtom(d->args[j]));
sewardj4345f7a2004-09-22 19:49:27 +00004136 if (d->mFx != Ifx_None)
sewardj496a58d2005-03-20 18:44:44 +00004137 vassert(isIRAtom(d->mAddr));
sewardj4345f7a2004-09-22 19:49:27 +00004138 break;
sewardjd2445f62005-03-21 00:15:53 +00004139 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00004140 case Ist_IMark:
sewardj3e838932005-01-07 12:09:15 +00004141 case Ist_MFence:
4142 break;
4143 case Ist_Exit:
sewardj496a58d2005-03-20 18:44:44 +00004144 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj3e838932005-01-07 12:09:15 +00004145 break;
sewardj4345f7a2004-09-22 19:49:27 +00004146 default:
sewardjb183b852006-02-03 16:08:03 +00004147 bad:
sewardj4345f7a2004-09-22 19:49:27 +00004148 ppIRStmt(st);
4149 vpanic("hasGetIorPutI");
4150 }
sewardj4345f7a2004-09-22 19:49:27 +00004151 }
sewardj4345f7a2004-09-22 19:49:27 +00004152}
4153
4154
sewardj695cff92004-10-13 14:50:14 +00004155/* ---------------- The main iropt entry point. ---------------- */
4156
sewardjedf4d692004-08-17 13:52:58 +00004157/* exported from this file */
sewardj695cff92004-10-13 14:50:14 +00004158/* Rules of the game:
4159
4160 - IRExpr/IRStmt trees should be treated as immutable, as they
4161 may get shared. So never change a field of such a tree node;
4162 instead construct and return a new one if needed.
4163*/
4164
sewardj4345f7a2004-09-22 19:49:27 +00004165
sewardjdd40fdf2006-12-24 02:20:24 +00004166IRSB* do_iropt_BB ( IRSB* bb0,
sewardj9d2e7692005-02-07 01:11:31 +00004167 IRExpr* (*specHelper) (HChar*, IRExpr**),
sewardj8d2291c2004-10-25 14:50:21 +00004168 Bool (*preciseMemExnsFn)(Int,Int),
sewardj695cff92004-10-13 14:50:14 +00004169 Addr64 guest_addr )
sewardjedf4d692004-08-17 13:52:58 +00004170{
sewardj9d2e7692005-02-07 01:11:31 +00004171 static Int n_total = 0;
4172 static Int n_expensive = 0;
sewardj29632392004-08-22 02:38:11 +00004173
sewardjb183b852006-02-03 16:08:03 +00004174 Bool hasGetIorPutI, hasVorFtemps;
sewardjdd40fdf2006-12-24 02:20:24 +00004175 IRSB *bb, *bb2;
sewardj8c2c10b2004-10-16 20:51:52 +00004176
sewardj4345f7a2004-09-22 19:49:27 +00004177 n_total++;
4178
4179 /* First flatten the block out, since all other
4180 phases assume flat code. */
4181
4182 bb = flatten_BB ( bb0 );
4183
4184 if (iropt_verbose) {
4185 vex_printf("\n========= FLAT\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004186 ppIRSB(bb);
sewardj84be7372004-08-18 13:59:33 +00004187 }
sewardjd7217032004-08-19 10:49:10 +00004188
sewardj08210532004-12-29 17:09:11 +00004189 /* If at level 0, stop now. */
4190 if (vex_control.iropt_level <= 0) return bb;
4191
sewardj695cff92004-10-13 14:50:14 +00004192 /* Now do a preliminary cleanup pass, and figure out if we also
4193 need to do 'expensive' optimisations. Expensive optimisations
4194 are deemed necessary if the block contains any GetIs or PutIs.
4195 If needed, do expensive transformations and then another cheap
4196 cleanup pass. */
sewardj4345f7a2004-09-22 19:49:27 +00004197
sewardj8d2291c2004-10-25 14:50:21 +00004198 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj695cff92004-10-13 14:50:14 +00004199
sewardj08613742004-10-25 13:01:45 +00004200 if (vex_control.iropt_level > 1) {
sewardjb183b852006-02-03 16:08:03 +00004201
4202 /* Peer at what we have, to decide how much more effort to throw
4203 at it. */
4204 considerExpensives( &hasGetIorPutI, &hasVorFtemps, bb );
4205
sewardj9b0cc582006-02-04 15:24:00 +00004206 if (hasVorFtemps && !hasGetIorPutI) {
sewardjb183b852006-02-03 16:08:03 +00004207 /* If any evidence of FP or Vector activity, CSE, as that
4208 tends to mop up all manner of lardy code to do with
sewardj9b0cc582006-02-04 15:24:00 +00004209 rounding modes. Don't bother if hasGetIorPutI since that
4210 case leads into the expensive transformations, which do
4211 CSE anyway. */
4212 (void)do_cse_BB( bb );
sewardjb183b852006-02-03 16:08:03 +00004213 do_deadcode_BB( bb );
4214 }
4215
4216 if (hasGetIorPutI) {
sewardj9b0cc582006-02-04 15:24:00 +00004217 Bool cses;
sewardj39555aa2004-10-24 22:29:19 +00004218 n_expensive++;
sewardj39555aa2004-10-24 22:29:19 +00004219 if (DEBUG_IROPT)
4220 vex_printf("***** EXPENSIVE %d %d\n", n_total, n_expensive);
sewardj695cff92004-10-13 14:50:14 +00004221 bb = expensive_transformations( bb );
sewardj8d2291c2004-10-25 14:50:21 +00004222 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj9b0cc582006-02-04 15:24:00 +00004223 /* Potentially common up GetIs */
4224 cses = do_cse_BB( bb );
4225 if (cses)
4226 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj695cff92004-10-13 14:50:14 +00004227 }
sewardj39555aa2004-10-24 22:29:19 +00004228
4229 /* Now have a go at unrolling simple (single-BB) loops. If
4230 successful, clean up the results as much as possible. */
4231
4232 bb2 = maybe_loop_unroll_BB( bb, guest_addr );
4233 if (bb2) {
sewardj8d2291c2004-10-25 14:50:21 +00004234 bb = cheap_transformations( bb2, specHelper, preciseMemExnsFn );
sewardjb183b852006-02-03 16:08:03 +00004235 if (hasGetIorPutI) {
sewardj39555aa2004-10-24 22:29:19 +00004236 bb = expensive_transformations( bb );
sewardj8d2291c2004-10-25 14:50:21 +00004237 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj39555aa2004-10-24 22:29:19 +00004238 } else {
4239 /* at least do CSE and dead code removal */
sewardjfe1ccfc2004-11-11 02:14:45 +00004240 do_cse_BB( bb );
sewardj49651f42004-10-28 22:11:04 +00004241 do_deadcode_BB( bb );
sewardj39555aa2004-10-24 22:29:19 +00004242 }
4243 if (0) vex_printf("vex iropt: unrolled a loop\n");
4244 }
4245
sewardjd7217032004-08-19 10:49:10 +00004246 }
4247
sewardj4345f7a2004-09-22 19:49:27 +00004248 return bb;
sewardjedf4d692004-08-17 13:52:58 +00004249}
4250
4251
sewardja1a370f2004-08-17 13:31:55 +00004252/*---------------------------------------------------------------*/
4253/*--- end ir/iropt.c ---*/
4254/*---------------------------------------------------------------*/