blob: f2850db61d66dc5282c39f25ac8b3ced1f25b83a [file] [log] [blame]
florianf6402ab2012-01-29 02:19:43 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
sewardja1a370f2004-08-17 13:31:55 +00002
3/*---------------------------------------------------------------*/
sewardj752f9062010-05-03 21:38:49 +00004/*--- begin ir_opt.c ---*/
sewardja1a370f2004-08-17 13:31:55 +00005/*---------------------------------------------------------------*/
6
sewardjf8ed9d82004-11-12 17:40:23 +00007/*
sewardj752f9062010-05-03 21:38:49 +00008 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
sewardjf8ed9d82004-11-12 17:40:23 +000010
sewardje6c53e02011-10-23 07:33:43 +000011 Copyright (C) 2004-2011 OpenWorks LLP
sewardj752f9062010-05-03 21:38:49 +000012 info@open-works.net
sewardjf8ed9d82004-11-12 17:40:23 +000013
sewardj752f9062010-05-03 21:38:49 +000014 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
sewardjf8ed9d82004-11-12 17:40:23 +000018
sewardj752f9062010-05-03 21:38:49 +000019 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
sewardj7bd6ffe2005-08-03 16:07:36 +000027 02110-1301, USA.
28
sewardj752f9062010-05-03 21:38:49 +000029 The GNU General Public License is contained in the file COPYING.
sewardjf8ed9d82004-11-12 17:40:23 +000030
31 Neither the names of the U.S. Department of Energy nor the
32 University of California nor the names of its contributors may be
33 used to endorse or promote products derived from this software
34 without prior written permission.
sewardjf8ed9d82004-11-12 17:40:23 +000035*/
36
sewardja1a370f2004-08-17 13:31:55 +000037#include "libvex_basictypes.h"
sewardjedf4d692004-08-17 13:52:58 +000038#include "libvex_ir.h"
sewardja1a370f2004-08-17 13:31:55 +000039#include "libvex.h"
40
sewardjcef7d3e2009-07-02 12:21:59 +000041#include "main_util.h"
42#include "main_globals.h"
43#include "ir_opt.h"
sewardja1a370f2004-08-17 13:31:55 +000044
sewardjd0863ff2004-10-23 00:22:32 +000045
sewardj088bcb42004-08-19 17:16:52 +000046/* Set to 1 for lots of debugging output. */
47#define DEBUG_IROPT 0
48
floriancdb5fee2012-02-13 00:06:29 +000049/* Set to 1 to gather some statistics. Currently only for sameIRExprs. */
50#define STATS_IROPT 0
51
sewardja1a370f2004-08-17 13:31:55 +000052
sewardj08210532004-12-29 17:09:11 +000053/* What iropt does, 29 Dec 04.
54
sewardjf6c8ebf2007-02-06 01:52:52 +000055 It takes an IRSB and produces a new one with the same meaning,
sewardj08210532004-12-29 17:09:11 +000056 defined thus:
57
58 After execution of the new BB, all guest state and guest memory is
59 the same as after execution of the original. This is true
60 regardless of how the block was exited (at the end vs side exit).
61
62 In addition, parts of the guest state will be identical to that
63 created by execution of the original at the following observation
64 points:
65
66 * In a dirty helper call, any parts of the guest state that the
67 helper states that it reads or modifies will be up to date.
68 Also, guest memory will be up to date. Parts of the guest state
69 not marked as being read or modified by the helper cannot be
70 assumed to be up-to-date at the point where the helper is called.
71
72 * Immediately prior to any load or store, those parts of the guest
73 state marked as requiring precise exceptions will be up to date.
74 Also, guest memory will be up to date. Parts of the guest state
75 not marked as requiring precise exceptions cannot be assumed to
76 be up-to-date at the point of the load/store.
77
78 The relative order of loads and stores (including loads/stores of
79 guest memory done by dirty helpers annotated as such) is not
80 changed. However, the relative order of loads with no intervening
81 stores/modifies may be changed.
82
83 Transformation order
84 ~~~~~~~~~~~~~~~~~~~~
85
86 There are three levels of optimisation, controlled by
87 vex_control.iropt_level. Define first:
88
89 "Cheap transformations" are the following sequence:
90 * Redundant-Get removal
91 * Redundant-Put removal
92 * Constant propagation/folding
93 * Dead code removal
94 * Specialisation of clean helper functions
95 * Dead code removal
96
97 "Expensive transformations" are the following sequence:
98 * CSE
99 * Folding of add/sub chains
100 * Redundant-GetI removal
101 * Redundant-PutI removal
102 * Dead code removal
sewardj08210532004-12-29 17:09:11 +0000103
104 Then the transformations are as follows, as defined by
105 vex_control.iropt_level:
106
107 Level 0:
108 * Flatten into atomic form.
109
110 Level 1: the following sequence:
111 * Flatten into atomic form.
112 * Cheap transformations.
sewardj08210532004-12-29 17:09:11 +0000113
114 Level 2: the following sequence
115 * Flatten into atomic form.
116 * Cheap transformations.
sewardjb183b852006-02-03 16:08:03 +0000117 * If block contains any floating or vector types, CSE.
sewardj08210532004-12-29 17:09:11 +0000118 * If block contains GetI or PutI, Expensive transformations.
119 * Try unrolling loops. Three possible outcomes:
120 - No effect: do nothing more.
121 - Unrolled a loop, and block does not contain GetI or PutI:
122 Do: * CSE
123 * Dead code removal
sewardj08210532004-12-29 17:09:11 +0000124 - Unrolled a loop, and block contains GetI or PutI:
125 Do: * Expensive transformations
126 * Cheap transformations
sewardj08210532004-12-29 17:09:11 +0000127*/
128
sewardj98430292004-12-29 17:34:50 +0000129/* Implementation notes, 29 Dec 04.
130
131 TODO (important): I think rPutI removal ignores precise exceptions
132 and is therefore in a sense, wrong. In the sense that PutIs are
133 assumed not to write parts of the guest state that we need to have
134 up-to-date at loads/stores. So far on x86 guest that has not
135 mattered since indeed only the x87 FP registers and tags are
136 accessed using GetI/PutI, and there is no need so far for them to
137 be up to date at mem exception points. The rPutI pass should be
138 fixed.
sewardjfb44d552004-10-25 09:48:47 +0000139
sewardj4c5f6d52004-10-26 13:25:33 +0000140 TODO: improve pessimistic handling of precise exceptions
141 in the tree builder.
142
sewardjfb44d552004-10-25 09:48:47 +0000143 TODO: check interaction of rGetI and dirty helpers.
sewardjc0b42282004-10-12 13:44:12 +0000144
145 F64i constants are treated differently from other constants.
146 They are not regarded as atoms, and instead lifted off and
147 bound to temps. This allows them to participate in CSE, which
148 is important for getting good performance for x86 guest code.
sewardj695cff92004-10-13 14:50:14 +0000149
sewardja5aa9cf2004-10-15 22:56:38 +0000150 CSE up F64 literals (already doing F64is)
sewardj4c5f6d52004-10-26 13:25:33 +0000151
152 CSE: consider carefully the requirement for precise exns
sewardj98430292004-12-29 17:34:50 +0000153 prior to making CSE any more aggressive. */
sewardjc0b42282004-10-12 13:44:12 +0000154
155
sewardja1a370f2004-08-17 13:31:55 +0000156/*---------------------------------------------------------------*/
157/*--- Finite mappery, of a sort ---*/
158/*---------------------------------------------------------------*/
159
sewardj08210532004-12-29 17:09:11 +0000160/* General map from HWord-sized thing HWord-sized thing. Could be by
161 hashing, but it's not clear whether or not this would really be any
162 faster. */
sewardja1a370f2004-08-17 13:31:55 +0000163
164typedef
165 struct {
166 Bool* inuse;
sewardjea602bc2004-10-14 21:40:12 +0000167 HWord* key;
168 HWord* val;
sewardja1a370f2004-08-17 13:31:55 +0000169 Int size;
170 Int used;
171 }
sewardjea602bc2004-10-14 21:40:12 +0000172 HashHW;
sewardja1a370f2004-08-17 13:31:55 +0000173
sewardjea602bc2004-10-14 21:40:12 +0000174static HashHW* newHHW ( void )
sewardja1a370f2004-08-17 13:31:55 +0000175{
sewardjea602bc2004-10-14 21:40:12 +0000176 HashHW* h = LibVEX_Alloc(sizeof(HashHW));
sewardj29632392004-08-22 02:38:11 +0000177 h->size = 8;
sewardja1a370f2004-08-17 13:31:55 +0000178 h->used = 0;
179 h->inuse = LibVEX_Alloc(h->size * sizeof(Bool));
sewardjea602bc2004-10-14 21:40:12 +0000180 h->key = LibVEX_Alloc(h->size * sizeof(HWord));
181 h->val = LibVEX_Alloc(h->size * sizeof(HWord));
sewardja1a370f2004-08-17 13:31:55 +0000182 return h;
183}
184
185
sewardj84be7372004-08-18 13:59:33 +0000186/* Look up key in the map. */
sewardja1a370f2004-08-17 13:31:55 +0000187
sewardjea602bc2004-10-14 21:40:12 +0000188static Bool lookupHHW ( HashHW* h, /*OUT*/HWord* val, HWord key )
sewardja1a370f2004-08-17 13:31:55 +0000189{
190 Int i;
sewardj08210532004-12-29 17:09:11 +0000191 /* vex_printf("lookupHHW(%llx)\n", key ); */
sewardja1a370f2004-08-17 13:31:55 +0000192 for (i = 0; i < h->used; i++) {
193 if (h->inuse[i] && h->key[i] == key) {
sewardj39e3f242004-08-18 16:54:52 +0000194 if (val)
195 *val = h->val[i];
sewardja1a370f2004-08-17 13:31:55 +0000196 return True;
197 }
198 }
199 return False;
200}
201
202
sewardja1a370f2004-08-17 13:31:55 +0000203/* Add key->val to the map. Replaces any existing binding for key. */
204
sewardjea602bc2004-10-14 21:40:12 +0000205static void addToHHW ( HashHW* h, HWord key, HWord val )
sewardja1a370f2004-08-17 13:31:55 +0000206{
207 Int i, j;
sewardj08210532004-12-29 17:09:11 +0000208 /* vex_printf("addToHHW(%llx, %llx)\n", key, val); */
sewardja1a370f2004-08-17 13:31:55 +0000209
210 /* Find and replace existing binding, if any. */
211 for (i = 0; i < h->used; i++) {
212 if (h->inuse[i] && h->key[i] == key) {
213 h->val[i] = val;
214 return;
215 }
216 }
217
218 /* Ensure a space is available. */
219 if (h->used == h->size) {
220 /* Copy into arrays twice the size. */
221 Bool* inuse2 = LibVEX_Alloc(2 * h->size * sizeof(Bool));
sewardjea602bc2004-10-14 21:40:12 +0000222 HWord* key2 = LibVEX_Alloc(2 * h->size * sizeof(HWord));
223 HWord* val2 = LibVEX_Alloc(2 * h->size * sizeof(HWord));
sewardja1a370f2004-08-17 13:31:55 +0000224 for (i = j = 0; i < h->size; i++) {
225 if (!h->inuse[i]) continue;
226 inuse2[j] = True;
227 key2[j] = h->key[i];
228 val2[j] = h->val[i];
229 j++;
230 }
231 h->used = j;
232 h->size *= 2;
233 h->inuse = inuse2;
234 h->key = key2;
235 h->val = val2;
236 }
237
238 /* Finally, add it. */
239 vassert(h->used < h->size);
240 h->inuse[h->used] = True;
241 h->key[h->used] = key;
sewardj84be7372004-08-18 13:59:33 +0000242 h->val[h->used] = val;
sewardja1a370f2004-08-17 13:31:55 +0000243 h->used++;
244}
245
sewardj84be7372004-08-18 13:59:33 +0000246
sewardjd7cb8532004-08-17 23:59:23 +0000247/*---------------------------------------------------------------*/
sewardj08210532004-12-29 17:09:11 +0000248/*--- Flattening out a BB into atomic SSA form ---*/
sewardjd7cb8532004-08-17 23:59:23 +0000249/*---------------------------------------------------------------*/
250
sewardje80679a2004-09-21 23:00:11 +0000251/* Non-critical helper, heuristic for reducing the number of tmp-tmp
252 copies made by flattening. If in doubt return False. */
253
254static Bool isFlat ( IRExpr* e )
255{
sewardj695cff92004-10-13 14:50:14 +0000256 if (e->tag == Iex_Get)
257 return True;
sewardje80679a2004-09-21 23:00:11 +0000258 if (e->tag == Iex_Binop)
sewardj496a58d2005-03-20 18:44:44 +0000259 return toBool( isIRAtom(e->Iex.Binop.arg1)
260 && isIRAtom(e->Iex.Binop.arg2) );
sewardjaf1ceca2005-06-30 23:31:27 +0000261 if (e->tag == Iex_Load)
262 return isIRAtom(e->Iex.Load.addr);
sewardje80679a2004-09-21 23:00:11 +0000263 return False;
264}
265
sewardjd7cb8532004-08-17 23:59:23 +0000266/* Flatten out 'ex' so it is atomic, returning a new expression with
267 the same value, after having appended extra IRTemp assignments to
268 the end of 'bb'. */
269
sewardjdd40fdf2006-12-24 02:20:24 +0000270static IRExpr* flatten_Expr ( IRSB* bb, IRExpr* ex )
sewardjd7cb8532004-08-17 23:59:23 +0000271{
272 Int i;
273 IRExpr** newargs;
274 IRType ty = typeOfIRExpr(bb->tyenv, ex);
275 IRTemp t1;
276
277 switch (ex->tag) {
278
sewardjd7217032004-08-19 10:49:10 +0000279 case Iex_GetI:
280 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000281 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardj2d3f77c2004-09-22 23:49:09 +0000282 IRExpr_GetI(ex->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +0000283 flatten_Expr(bb, ex->Iex.GetI.ix),
sewardj2d3f77c2004-09-22 23:49:09 +0000284 ex->Iex.GetI.bias)));
sewardjdd40fdf2006-12-24 02:20:24 +0000285 return IRExpr_RdTmp(t1);
sewardjd7217032004-08-19 10:49:10 +0000286
sewardjd7cb8532004-08-17 23:59:23 +0000287 case Iex_Get:
288 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000289 addStmtToIRSB(bb,
290 IRStmt_WrTmp(t1, ex));
291 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000292
sewardj40c80262006-02-08 19:30:46 +0000293 case Iex_Qop:
294 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000295 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardj40c80262006-02-08 19:30:46 +0000296 IRExpr_Qop(ex->Iex.Qop.op,
297 flatten_Expr(bb, ex->Iex.Qop.arg1),
298 flatten_Expr(bb, ex->Iex.Qop.arg2),
299 flatten_Expr(bb, ex->Iex.Qop.arg3),
300 flatten_Expr(bb, ex->Iex.Qop.arg4))));
sewardjdd40fdf2006-12-24 02:20:24 +0000301 return IRExpr_RdTmp(t1);
sewardj40c80262006-02-08 19:30:46 +0000302
sewardjb183b852006-02-03 16:08:03 +0000303 case Iex_Triop:
304 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000305 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjb183b852006-02-03 16:08:03 +0000306 IRExpr_Triop(ex->Iex.Triop.op,
307 flatten_Expr(bb, ex->Iex.Triop.arg1),
308 flatten_Expr(bb, ex->Iex.Triop.arg2),
309 flatten_Expr(bb, ex->Iex.Triop.arg3))));
sewardjdd40fdf2006-12-24 02:20:24 +0000310 return IRExpr_RdTmp(t1);
sewardjb183b852006-02-03 16:08:03 +0000311
sewardjd7cb8532004-08-17 23:59:23 +0000312 case Iex_Binop:
313 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000314 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjd7cb8532004-08-17 23:59:23 +0000315 IRExpr_Binop(ex->Iex.Binop.op,
316 flatten_Expr(bb, ex->Iex.Binop.arg1),
317 flatten_Expr(bb, ex->Iex.Binop.arg2))));
sewardjdd40fdf2006-12-24 02:20:24 +0000318 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000319
320 case Iex_Unop:
321 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000322 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjd7cb8532004-08-17 23:59:23 +0000323 IRExpr_Unop(ex->Iex.Unop.op,
324 flatten_Expr(bb, ex->Iex.Unop.arg))));
sewardjdd40fdf2006-12-24 02:20:24 +0000325 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000326
sewardjaf1ceca2005-06-30 23:31:27 +0000327 case Iex_Load:
sewardjd7cb8532004-08-17 23:59:23 +0000328 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000329 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardje768e922009-11-26 17:17:37 +0000330 IRExpr_Load(ex->Iex.Load.end,
sewardjaf1ceca2005-06-30 23:31:27 +0000331 ex->Iex.Load.ty,
332 flatten_Expr(bb, ex->Iex.Load.addr))));
sewardjdd40fdf2006-12-24 02:20:24 +0000333 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000334
335 case Iex_CCall:
sewardjdd40fdf2006-12-24 02:20:24 +0000336 newargs = shallowCopyIRExprVec(ex->Iex.CCall.args);
sewardjd7cb8532004-08-17 23:59:23 +0000337 for (i = 0; newargs[i]; i++)
338 newargs[i] = flatten_Expr(bb, newargs[i]);
339 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000340 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardj8ea867b2004-10-30 19:03:02 +0000341 IRExpr_CCall(ex->Iex.CCall.cee,
sewardjd7cb8532004-08-17 23:59:23 +0000342 ex->Iex.CCall.retty,
343 newargs)));
sewardjdd40fdf2006-12-24 02:20:24 +0000344 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000345
346 case Iex_Mux0X:
347 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000348 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjd7cb8532004-08-17 23:59:23 +0000349 IRExpr_Mux0X(flatten_Expr(bb, ex->Iex.Mux0X.cond),
350 flatten_Expr(bb, ex->Iex.Mux0X.expr0),
351 flatten_Expr(bb, ex->Iex.Mux0X.exprX))));
sewardjdd40fdf2006-12-24 02:20:24 +0000352 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000353
354 case Iex_Const:
sewardjc0b42282004-10-12 13:44:12 +0000355 /* Lift F64i constants out onto temps so they can be CSEd
356 later. */
357 if (ex->Iex.Const.con->tag == Ico_F64i) {
358 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000359 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjc0b42282004-10-12 13:44:12 +0000360 IRExpr_Const(ex->Iex.Const.con)));
sewardjdd40fdf2006-12-24 02:20:24 +0000361 return IRExpr_RdTmp(t1);
sewardjc0b42282004-10-12 13:44:12 +0000362 } else {
363 /* Leave all other constants alone. */
364 return ex;
365 }
366
sewardjdd40fdf2006-12-24 02:20:24 +0000367 case Iex_RdTmp:
sewardjd7cb8532004-08-17 23:59:23 +0000368 return ex;
369
370 default:
371 vex_printf("\n");
372 ppIRExpr(ex);
373 vex_printf("\n");
374 vpanic("flatten_Expr");
375 }
376}
377
378
379/* Append a completely flattened form of 'st' to the end of 'bb'. */
380
sewardjdd40fdf2006-12-24 02:20:24 +0000381static void flatten_Stmt ( IRSB* bb, IRStmt* st )
sewardjd7cb8532004-08-17 23:59:23 +0000382{
sewardj17442fe2004-09-20 14:54:28 +0000383 Int i;
sewardje9d8a262009-07-01 08:06:34 +0000384 IRExpr *e1, *e2, *e3, *e4, *e5;
sewardj17442fe2004-09-20 14:54:28 +0000385 IRDirty *d, *d2;
sewardje9d8a262009-07-01 08:06:34 +0000386 IRCAS *cas, *cas2;
sewardjd7cb8532004-08-17 23:59:23 +0000387 switch (st->tag) {
388 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +0000389 if (isIRAtom(st->Ist.Put.data)) {
sewardj49651f42004-10-28 22:11:04 +0000390 /* optimisation to reduce the amount of heap wasted
391 by the flattener */
sewardjdd40fdf2006-12-24 02:20:24 +0000392 addStmtToIRSB(bb, st);
sewardj49651f42004-10-28 22:11:04 +0000393 } else {
394 /* general case, always correct */
395 e1 = flatten_Expr(bb, st->Ist.Put.data);
sewardjdd40fdf2006-12-24 02:20:24 +0000396 addStmtToIRSB(bb, IRStmt_Put(st->Ist.Put.offset, e1));
sewardj49651f42004-10-28 22:11:04 +0000397 }
sewardjd7cb8532004-08-17 23:59:23 +0000398 break;
sewardjd7cb8532004-08-17 23:59:23 +0000399 case Ist_PutI:
sewardjeeac8412004-11-02 00:26:55 +0000400 e1 = flatten_Expr(bb, st->Ist.PutI.ix);
sewardj2d3f77c2004-09-22 23:49:09 +0000401 e2 = flatten_Expr(bb, st->Ist.PutI.data);
sewardjdd40fdf2006-12-24 02:20:24 +0000402 addStmtToIRSB(bb, IRStmt_PutI(st->Ist.PutI.descr,
sewardj2d3f77c2004-09-22 23:49:09 +0000403 e1,
404 st->Ist.PutI.bias,
405 e2));
sewardjd7217032004-08-19 10:49:10 +0000406 break;
sewardjdd40fdf2006-12-24 02:20:24 +0000407 case Ist_WrTmp:
408 if (isFlat(st->Ist.WrTmp.data)) {
sewardje80679a2004-09-21 23:00:11 +0000409 /* optimisation, to reduce the number of tmp-tmp
410 copies generated */
sewardjdd40fdf2006-12-24 02:20:24 +0000411 addStmtToIRSB(bb, st);
sewardje80679a2004-09-21 23:00:11 +0000412 } else {
413 /* general case, always correct */
sewardjdd40fdf2006-12-24 02:20:24 +0000414 e1 = flatten_Expr(bb, st->Ist.WrTmp.data);
415 addStmtToIRSB(bb, IRStmt_WrTmp(st->Ist.WrTmp.tmp, e1));
sewardje80679a2004-09-21 23:00:11 +0000416 }
sewardjd7cb8532004-08-17 23:59:23 +0000417 break;
sewardjaf1ceca2005-06-30 23:31:27 +0000418 case Ist_Store:
419 e1 = flatten_Expr(bb, st->Ist.Store.addr);
420 e2 = flatten_Expr(bb, st->Ist.Store.data);
sewardje768e922009-11-26 17:17:37 +0000421 addStmtToIRSB(bb, IRStmt_Store(st->Ist.Store.end, e1,e2));
sewardje9d8a262009-07-01 08:06:34 +0000422 break;
423 case Ist_CAS:
424 cas = st->Ist.CAS.details;
425 e1 = flatten_Expr(bb, cas->addr);
426 e2 = cas->expdHi ? flatten_Expr(bb, cas->expdHi) : NULL;
427 e3 = flatten_Expr(bb, cas->expdLo);
428 e4 = cas->dataHi ? flatten_Expr(bb, cas->dataHi) : NULL;
429 e5 = flatten_Expr(bb, cas->dataLo);
430 cas2 = mkIRCAS( cas->oldHi, cas->oldLo, cas->end,
431 e1, e2, e3, e4, e5 );
432 addStmtToIRSB(bb, IRStmt_CAS(cas2));
sewardjd7cb8532004-08-17 23:59:23 +0000433 break;
sewardje768e922009-11-26 17:17:37 +0000434 case Ist_LLSC:
435 e1 = flatten_Expr(bb, st->Ist.LLSC.addr);
436 e2 = st->Ist.LLSC.storedata
437 ? flatten_Expr(bb, st->Ist.LLSC.storedata)
438 : NULL;
439 addStmtToIRSB(bb, IRStmt_LLSC(st->Ist.LLSC.end,
440 st->Ist.LLSC.result, e1, e2));
441 break;
sewardj17442fe2004-09-20 14:54:28 +0000442 case Ist_Dirty:
443 d = st->Ist.Dirty.details;
444 d2 = emptyIRDirty();
445 *d2 = *d;
sewardjdd40fdf2006-12-24 02:20:24 +0000446 d2->args = shallowCopyIRExprVec(d2->args);
sewardj17442fe2004-09-20 14:54:28 +0000447 if (d2->mFx != Ifx_None) {
448 d2->mAddr = flatten_Expr(bb, d2->mAddr);
449 } else {
450 vassert(d2->mAddr == NULL);
451 }
sewardjb8385d82004-11-02 01:34:15 +0000452 d2->guard = flatten_Expr(bb, d2->guard);
sewardj17442fe2004-09-20 14:54:28 +0000453 for (i = 0; d2->args[i]; i++)
454 d2->args[i] = flatten_Expr(bb, d2->args[i]);
sewardjdd40fdf2006-12-24 02:20:24 +0000455 addStmtToIRSB(bb, IRStmt_Dirty(d2));
sewardj17442fe2004-09-20 14:54:28 +0000456 break;
sewardjd2445f62005-03-21 00:15:53 +0000457 case Ist_NoOp:
sewardjc4356f02007-11-09 21:15:04 +0000458 case Ist_MBE:
sewardjd2445f62005-03-21 00:15:53 +0000459 case Ist_IMark:
sewardjdd40fdf2006-12-24 02:20:24 +0000460 addStmtToIRSB(bb, st);
sewardj3e838932005-01-07 12:09:15 +0000461 break;
sewardj5a9ffab2005-05-12 17:55:01 +0000462 case Ist_AbiHint:
463 e1 = flatten_Expr(bb, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +0000464 e2 = flatten_Expr(bb, st->Ist.AbiHint.nia);
465 addStmtToIRSB(bb, IRStmt_AbiHint(e1, st->Ist.AbiHint.len, e2));
sewardj5a9ffab2005-05-12 17:55:01 +0000466 break;
sewardjd7cb8532004-08-17 23:59:23 +0000467 case Ist_Exit:
sewardj0276d4b2004-11-15 15:30:21 +0000468 e1 = flatten_Expr(bb, st->Ist.Exit.guard);
sewardjdd40fdf2006-12-24 02:20:24 +0000469 addStmtToIRSB(bb, IRStmt_Exit(e1, st->Ist.Exit.jk,
sewardj893aada2004-11-29 19:57:54 +0000470 st->Ist.Exit.dst));
sewardjd7cb8532004-08-17 23:59:23 +0000471 break;
472 default:
473 vex_printf("\n");
474 ppIRStmt(st);
475 vex_printf("\n");
476 vpanic("flatten_Stmt");
477 }
478}
479
sewardj08210532004-12-29 17:09:11 +0000480
sewardjdd40fdf2006-12-24 02:20:24 +0000481static IRSB* flatten_BB ( IRSB* in )
sewardjd7cb8532004-08-17 23:59:23 +0000482{
483 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +0000484 IRSB* out;
485 out = emptyIRSB();
486 out->tyenv = deepCopyIRTypeEnv( in->tyenv );
sewardjd7cb8532004-08-17 23:59:23 +0000487 for (i = 0; i < in->stmts_used; i++)
sewardj4345f7a2004-09-22 19:49:27 +0000488 if (in->stmts[i])
489 flatten_Stmt( out, in->stmts[i] );
sewardjd7cb8532004-08-17 23:59:23 +0000490 out->next = flatten_Expr( out, in->next );
491 out->jumpkind = in->jumpkind;
492 return out;
493}
494
sewardjedf4d692004-08-17 13:52:58 +0000495
sewardj08210532004-12-29 17:09:11 +0000496/*---------------------------------------------------------------*/
497/*--- In-place removal of redundant GETs ---*/
498/*---------------------------------------------------------------*/
499
500/* Scan forwards, building up an environment binding (min offset, max
501 offset) pairs to values, which will either be temps or constants.
502
503 On seeing 't = Get(minoff,maxoff)', look up (minoff,maxoff) in the
504 env and if it matches, replace the Get with the stored value. If
505 there is no match, add a (minoff,maxoff) :-> t binding.
506
507 On seeing 'Put (minoff,maxoff) = t or c', first remove in the env
508 any binding which fully or partially overlaps with (minoff,maxoff).
509 Then add a new (minoff,maxoff) :-> t or c binding. */
510
511/* Extract the min/max offsets from a guest state array descriptor. */
512
513inline
sewardjdd40fdf2006-12-24 02:20:24 +0000514static void getArrayBounds ( IRRegArray* descr,
515 UInt* minoff, UInt* maxoff )
sewardj08210532004-12-29 17:09:11 +0000516{
517 *minoff = descr->base;
518 *maxoff = *minoff + descr->nElems*sizeofIRType(descr->elemTy) - 1;
519 vassert((*minoff & ~0xFFFF) == 0);
520 vassert((*maxoff & ~0xFFFF) == 0);
521 vassert(*minoff <= *maxoff);
522}
523
524/* Create keys, of the form ((minoffset << 16) | maxoffset). */
525
526static UInt mk_key_GetPut ( Int offset, IRType ty )
527{
528 /* offset should fit in 16 bits. */
529 UInt minoff = offset;
530 UInt maxoff = minoff + sizeofIRType(ty) - 1;
531 vassert((minoff & ~0xFFFF) == 0);
532 vassert((maxoff & ~0xFFFF) == 0);
533 return (minoff << 16) | maxoff;
534}
535
sewardjdd40fdf2006-12-24 02:20:24 +0000536static UInt mk_key_GetIPutI ( IRRegArray* descr )
sewardj08210532004-12-29 17:09:11 +0000537{
538 UInt minoff, maxoff;
539 getArrayBounds( descr, &minoff, &maxoff );
540 vassert((minoff & ~0xFFFF) == 0);
541 vassert((maxoff & ~0xFFFF) == 0);
542 return (minoff << 16) | maxoff;
543}
544
545/* Supposing h has keys of the form generated by mk_key_GetPut and
546 mk_key_GetIPutI, invalidate any key which overlaps (k_lo
547 .. k_hi).
548*/
549static void invalidateOverlaps ( HashHW* h, UInt k_lo, UInt k_hi )
550{
551 Int j;
552 UInt e_lo, e_hi;
553 vassert(k_lo <= k_hi);
554 /* invalidate any env entries which in any way overlap (k_lo
555 .. k_hi) */
556 /* vex_printf("invalidate %d .. %d\n", k_lo, k_hi ); */
557
558 for (j = 0; j < h->used; j++) {
559 if (!h->inuse[j])
560 continue;
561 e_lo = (((UInt)h->key[j]) >> 16) & 0xFFFF;
562 e_hi = ((UInt)h->key[j]) & 0xFFFF;
563 vassert(e_lo <= e_hi);
564 if (e_hi < k_lo || k_hi < e_lo)
565 continue; /* no overlap possible */
566 else
567 /* overlap; invalidate */
568 h->inuse[j] = False;
569 }
570}
571
572
sewardjdd40fdf2006-12-24 02:20:24 +0000573static void redundant_get_removal_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +0000574{
575 HashHW* env = newHHW();
576 UInt key = 0; /* keep gcc -O happy */
577 Int i, j;
578 HWord val;
579
580 for (i = 0; i < bb->stmts_used; i++) {
581 IRStmt* st = bb->stmts[i];
582
sewardj8bee6d12005-03-22 02:24:05 +0000583 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +0000584 continue;
585
586 /* Deal with Gets */
sewardjdd40fdf2006-12-24 02:20:24 +0000587 if (st->tag == Ist_WrTmp
588 && st->Ist.WrTmp.data->tag == Iex_Get) {
sewardj08210532004-12-29 17:09:11 +0000589 /* st is 't = Get(...)'. Look up in the environment and see
590 if the Get can be replaced. */
sewardjdd40fdf2006-12-24 02:20:24 +0000591 IRExpr* get = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +0000592 key = (HWord)mk_key_GetPut( get->Iex.Get.offset,
593 get->Iex.Get.ty );
594 if (lookupHHW(env, &val, (HWord)key)) {
595 /* found it */
596 /* Note, we could do better here. If the types are
597 different we don't do the substitution, since doing so
598 could lead to invalidly-typed IR. An improvement would
599 be to stick in a reinterpret-style cast, although that
600 would make maintaining flatness more difficult. */
601 IRExpr* valE = (IRExpr*)val;
sewardj9d2e7692005-02-07 01:11:31 +0000602 Bool typesOK = toBool( typeOfIRExpr(bb->tyenv,valE)
sewardjdd40fdf2006-12-24 02:20:24 +0000603 == st->Ist.WrTmp.data->Iex.Get.ty );
sewardj08210532004-12-29 17:09:11 +0000604 if (typesOK && DEBUG_IROPT) {
605 vex_printf("rGET: "); ppIRExpr(get);
606 vex_printf(" -> "); ppIRExpr(valE);
607 vex_printf("\n");
608 }
609 if (typesOK)
sewardjdd40fdf2006-12-24 02:20:24 +0000610 bb->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, valE);
sewardj08210532004-12-29 17:09:11 +0000611 } else {
612 /* Not found, but at least we know that t and the Get(...)
613 are now associated. So add a binding to reflect that
614 fact. */
615 addToHHW( env, (HWord)key,
sewardjdd40fdf2006-12-24 02:20:24 +0000616 (HWord)(void*)(IRExpr_RdTmp(st->Ist.WrTmp.tmp)) );
sewardj08210532004-12-29 17:09:11 +0000617 }
618 }
619
620 /* Deal with Puts: invalidate any env entries overlapped by this
621 Put */
622 if (st->tag == Ist_Put || st->tag == Ist_PutI) {
623 UInt k_lo, k_hi;
624 if (st->tag == Ist_Put) {
625 key = mk_key_GetPut( st->Ist.Put.offset,
626 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
627 } else {
628 vassert(st->tag == Ist_PutI);
629 key = mk_key_GetIPutI( st->Ist.PutI.descr );
630 }
631
632 k_lo = (key >> 16) & 0xFFFF;
633 k_hi = key & 0xFFFF;
634 invalidateOverlaps(env, k_lo, k_hi);
635 }
636 else
637 if (st->tag == Ist_Dirty) {
638 /* Deal with dirty helpers which write or modify guest state.
639 Invalidate the entire env. We could do a lot better
640 here. */
641 IRDirty* d = st->Ist.Dirty.details;
642 Bool writes = False;
643 for (j = 0; j < d->nFxState; j++) {
644 if (d->fxState[j].fx == Ifx_Modify
645 || d->fxState[j].fx == Ifx_Write)
646 writes = True;
647 }
648 if (writes) {
649 /* dump the entire env (not clever, but correct ...) */
650 for (j = 0; j < env->used; j++)
651 env->inuse[j] = False;
652 if (0) vex_printf("rGET: trash env due to dirty helper\n");
653 }
654 }
655
656 /* add this one to the env, if appropriate */
657 if (st->tag == Ist_Put) {
sewardj496a58d2005-03-20 18:44:44 +0000658 vassert(isIRAtom(st->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +0000659 addToHHW( env, (HWord)key, (HWord)(st->Ist.Put.data));
660 }
661
662 } /* for (i = 0; i < bb->stmts_used; i++) */
663
664}
665
666
667/*---------------------------------------------------------------*/
668/*--- In-place removal of redundant PUTs ---*/
669/*---------------------------------------------------------------*/
670
671/* Find any Get uses in st and invalidate any partially or fully
672 overlapping ranges listed in env. Due to the flattening phase, the
sewardjdd40fdf2006-12-24 02:20:24 +0000673 only stmt kind we expect to find a Get on is IRStmt_WrTmp. */
sewardj08210532004-12-29 17:09:11 +0000674
675static void handle_gets_Stmt (
676 HashHW* env,
677 IRStmt* st,
678 Bool (*preciseMemExnsFn)(Int,Int)
679 )
680{
681 Int j;
682 UInt key = 0; /* keep gcc -O happy */
683 Bool isGet;
684 Bool memRW = False;
685 IRExpr* e;
686
687 switch (st->tag) {
688
689 /* This is the only interesting case. Deal with Gets in the RHS
690 expression. */
sewardjdd40fdf2006-12-24 02:20:24 +0000691 case Ist_WrTmp:
692 e = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +0000693 switch (e->tag) {
694 case Iex_Get:
695 isGet = True;
696 key = mk_key_GetPut ( e->Iex.Get.offset, e->Iex.Get.ty );
697 break;
698 case Iex_GetI:
699 isGet = True;
700 key = mk_key_GetIPutI ( e->Iex.GetI.descr );
701 break;
sewardjaf1ceca2005-06-30 23:31:27 +0000702 case Iex_Load:
sewardj08210532004-12-29 17:09:11 +0000703 isGet = False;
704 memRW = True;
705 break;
706 default:
707 isGet = False;
708 }
709 if (isGet) {
710 UInt k_lo, k_hi;
711 k_lo = (key >> 16) & 0xFFFF;
712 k_hi = key & 0xFFFF;
713 invalidateOverlaps(env, k_lo, k_hi);
714 }
715 break;
716
717 /* Be very conservative for dirty helper calls; dump the entire
718 environment. The helper might read guest state, in which
719 case it needs to be flushed first. Also, the helper might
720 access guest memory, in which case all parts of the guest
721 state requiring precise exceptions needs to be flushed. The
722 crude solution is just to flush everything; we could easily
723 enough do a lot better if needed. */
sewardj3e838932005-01-07 12:09:15 +0000724 /* Probably also overly-conservative, but also dump everything
sewardjc4356f02007-11-09 21:15:04 +0000725 if we hit a memory bus event (fence, lock, unlock). Ditto
sewardje768e922009-11-26 17:17:37 +0000726 AbiHints, CASs, LLs and SCs. */
sewardj5a9ffab2005-05-12 17:55:01 +0000727 case Ist_AbiHint:
728 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +0000729 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +0000730 /* fall through */
sewardjc4356f02007-11-09 21:15:04 +0000731 case Ist_MBE:
sewardj08210532004-12-29 17:09:11 +0000732 case Ist_Dirty:
sewardje9d8a262009-07-01 08:06:34 +0000733 case Ist_CAS:
sewardje768e922009-11-26 17:17:37 +0000734 case Ist_LLSC:
sewardj08210532004-12-29 17:09:11 +0000735 for (j = 0; j < env->used; j++)
736 env->inuse[j] = False;
737 break;
738
739 /* all other cases are boring. */
sewardjaf1ceca2005-06-30 23:31:27 +0000740 case Ist_Store:
741 vassert(isIRAtom(st->Ist.Store.addr));
742 vassert(isIRAtom(st->Ist.Store.data));
sewardj08210532004-12-29 17:09:11 +0000743 memRW = True;
744 break;
745
746 case Ist_Exit:
sewardj496a58d2005-03-20 18:44:44 +0000747 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +0000748 break;
749
750 case Ist_PutI:
sewardj496a58d2005-03-20 18:44:44 +0000751 vassert(isIRAtom(st->Ist.PutI.ix));
752 vassert(isIRAtom(st->Ist.PutI.data));
sewardj08210532004-12-29 17:09:11 +0000753 break;
754
sewardjd2445f62005-03-21 00:15:53 +0000755 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +0000756 case Ist_IMark:
757 break;
758
sewardj08210532004-12-29 17:09:11 +0000759 default:
760 vex_printf("\n");
761 ppIRStmt(st);
762 vex_printf("\n");
763 vpanic("handle_gets_Stmt");
764 }
765
766 if (memRW) {
767 /* This statement accesses memory. So we need to dump all parts
768 of the environment corresponding to guest state that may not
769 be reordered with respect to memory references. That means
770 at least the stack pointer. */
771 for (j = 0; j < env->used; j++) {
772 if (!env->inuse[j])
773 continue;
774 if (vex_control.iropt_precise_memory_exns) {
775 /* Precise exceptions required. Flush all guest state. */
776 env->inuse[j] = False;
777 } else {
778 /* Just flush the minimal amount required, as computed by
779 preciseMemExnsFn. */
780 HWord k_lo = (env->key[j] >> 16) & 0xFFFF;
781 HWord k_hi = env->key[j] & 0xFFFF;
782 if (preciseMemExnsFn( k_lo, k_hi ))
783 env->inuse[j] = False;
784 }
785 }
786 } /* if (memRW) */
787
788}
789
790
791/* Scan backwards, building up a set of (min offset, max
792 offset) pairs, indicating those parts of the guest state
793 for which the next event is a write.
794
795 On seeing a conditional exit, empty the set.
796
797 On seeing 'Put (minoff,maxoff) = t or c', if (minoff,maxoff) is
798 completely within the set, remove the Put. Otherwise, add
799 (minoff,maxoff) to the set.
800
801 On seeing 'Get (minoff,maxoff)', remove any part of the set
sewardj98430292004-12-29 17:34:50 +0000802 overlapping (minoff,maxoff). The same has to happen for any events
803 which implicitly read parts of the guest state: dirty helper calls
804 and loads/stores.
sewardj08210532004-12-29 17:09:11 +0000805*/
806
807static void redundant_put_removal_BB (
sewardjdd40fdf2006-12-24 02:20:24 +0000808 IRSB* bb,
sewardj08210532004-12-29 17:09:11 +0000809 Bool (*preciseMemExnsFn)(Int,Int)
810 )
811{
812 Int i, j;
813 Bool isPut;
814 IRStmt* st;
815 UInt key = 0; /* keep gcc -O happy */
816
817 HashHW* env = newHHW();
818 for (i = bb->stmts_used-1; i >= 0; i--) {
819 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +0000820
821 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +0000822 continue;
823
824 /* Deal with conditional exits. */
825 if (st->tag == Ist_Exit) {
826 /* Since control may not get beyond this point, we must empty
827 out the set, since we can no longer claim that the next
828 event for any part of the guest state is definitely a
829 write. */
sewardj496a58d2005-03-20 18:44:44 +0000830 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +0000831 for (j = 0; j < env->used; j++)
832 env->inuse[j] = False;
833 continue;
834 }
835
836 /* Deal with Puts */
837 switch (st->tag) {
838 case Ist_Put:
839 isPut = True;
840 key = mk_key_GetPut( st->Ist.Put.offset,
841 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
sewardj496a58d2005-03-20 18:44:44 +0000842 vassert(isIRAtom(st->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +0000843 break;
844 case Ist_PutI:
845 isPut = True;
846 key = mk_key_GetIPutI( st->Ist.PutI.descr );
sewardj496a58d2005-03-20 18:44:44 +0000847 vassert(isIRAtom(st->Ist.PutI.ix));
848 vassert(isIRAtom(st->Ist.PutI.data));
sewardj08210532004-12-29 17:09:11 +0000849 break;
850 default:
851 isPut = False;
852 }
853 if (isPut && st->tag != Ist_PutI) {
854 /* See if any single entry in env overlaps this Put. This is
855 simplistic in that the transformation is valid if, say, two
856 or more entries in the env overlap this Put, but the use of
857 lookupHHW will only find a single entry which exactly
858 overlaps this Put. This is suboptimal but safe. */
859 if (lookupHHW(env, NULL, (HWord)key)) {
860 /* This Put is redundant because a later one will overwrite
861 it. So NULL (nop) it out. */
862 if (DEBUG_IROPT) {
863 vex_printf("rPUT: "); ppIRStmt(st);
864 vex_printf("\n");
865 }
sewardjd2445f62005-03-21 00:15:53 +0000866 bb->stmts[i] = IRStmt_NoOp();
sewardj08210532004-12-29 17:09:11 +0000867 } else {
868 /* We can't demonstrate that this Put is redundant, so add it
869 to the running collection. */
870 addToHHW(env, (HWord)key, 0);
871 }
872 continue;
873 }
874
875 /* Deal with Gets. These remove bits of the environment since
876 appearance of a Get means that the next event for that slice
sewardj98430292004-12-29 17:34:50 +0000877 of the guest state is no longer a write, but a read. Also
878 deals with implicit reads of guest state needed to maintain
879 precise exceptions. */
sewardj08210532004-12-29 17:09:11 +0000880 handle_gets_Stmt( env, st, preciseMemExnsFn );
881 }
882}
883
sewardj84be7372004-08-18 13:59:33 +0000884
885/*---------------------------------------------------------------*/
886/*--- Constant propagation and folding ---*/
887/*---------------------------------------------------------------*/
888
floriancdb5fee2012-02-13 00:06:29 +0000889#if STATS_IROPT
890/* How often sameIRExprs was invoked */
891static UInt invocation_count;
892/* How often sameIRExprs recursed through IRTemp assignments */
893static UInt recursion_count;
894/* How often sameIRExprs found identical IRExprs */
895static UInt success_count;
896/* How often recursing through assignments to IRTemps helped
897 establishing equality. */
898static UInt recursion_success_count;
899/* Whether or not recursing through an IRTemp assignment helped
900 establishing IRExpr equality for a given sameIRExprs invocation. */
901static Bool recursion_helped;
902/* Whether or not a given sameIRExprs invocation recursed through an
903 IRTemp assignment */
904static Bool recursed;
905/* Maximum number of nodes ever visited when comparing two IRExprs. */
906static UInt max_nodes_visited;
907#endif /* STATS_IROPT */
908
909/* Count the number of nodes visited for a given sameIRExprs invocation. */
910static UInt num_nodes_visited;
911
912/* Do not visit more than NODE_LIMIT nodes when comparing two IRExprs.
913 This is to guard against performance degradation by visiting large
914 trees without success. */
915#define NODE_LIMIT 30
916
917
sewardj62617ef2004-10-13 23:29:22 +0000918/* The env in this section is a map from IRTemp to IRExpr*,
919 that is, an array indexed by IRTemp. */
sewardjf6501992004-08-27 11:58:24 +0000920
floriancdb5fee2012-02-13 00:06:29 +0000921/* Do both expressions compute the same value? The answer is generally
922 conservative, i.e. it will report that the expressions do not compute
923 the same value when in fact they do. The reason is that we do not
924 keep track of changes in the guest state and memory. Thusly, two
925 Get's, GetI's or Load's, even when accessing the same location, will be
926 assumed to compute different values. After all the accesses may happen
927 at different times and the guest state / memory can have changed in
928 the meantime. */
929static Bool sameIRExprs_aux ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
sewardjf6729012004-08-25 12:45:13 +0000930{
floriancdb5fee2012-02-13 00:06:29 +0000931 if (e1->tag != e2->tag) return False;
sewardjf6729012004-08-25 12:45:13 +0000932
floriancdb5fee2012-02-13 00:06:29 +0000933 if (num_nodes_visited++ > NODE_LIMIT) return False;
sewardj6c299f32009-12-31 18:00:12 +0000934
sewardj6c299f32009-12-31 18:00:12 +0000935 switch (e1->tag) {
936 case Iex_RdTmp:
floriancdb5fee2012-02-13 00:06:29 +0000937 if (e1->Iex.RdTmp.tmp == e2->Iex.RdTmp.tmp) return True;
938
939 if (env[e1->Iex.RdTmp.tmp] && env[e2->Iex.RdTmp.tmp]) {
940 Bool same = sameIRExprs_aux(env, env[e1->Iex.RdTmp.tmp],
941 env[e2->Iex.RdTmp.tmp]);
942#if STATS_IROPT
943 recursed = True;
944 if (same) recursion_helped = True;
945#endif
946 return same;
947 }
sewardj6c299f32009-12-31 18:00:12 +0000948 return False;
floriancdb5fee2012-02-13 00:06:29 +0000949
950 case Iex_Get:
951 case Iex_GetI:
952 case Iex_Load:
953 /* Guest state / memory could have changed in the meantime. */
954 return False;
955
956 case Iex_Binop:
957 return toBool( e1->Iex.Binop.op == e2->Iex.Binop.op
958 && sameIRExprs_aux( env, e1->Iex.Binop.arg1, e2->Iex.Binop.arg1 )
959 && sameIRExprs_aux( env, e1->Iex.Binop.arg2, e2->Iex.Binop.arg2 ));
960
961 case Iex_Unop:
962 return toBool( e1->Iex.Unop.op == e2->Iex.Unop.op
963 && sameIRExprs_aux( env, e1->Iex.Unop.arg, e2->Iex.Unop.arg ));
964
965 case Iex_Const: {
966 IRConst *c1 = e1->Iex.Const.con;
967 IRConst *c2 = e2->Iex.Const.con;
968 vassert(c1->tag == c2->tag);
969 switch (c1->tag) {
970 case Ico_U1: return toBool( c1->Ico.U1 == c2->Ico.U1 );
971 case Ico_U8: return toBool( c1->Ico.U8 == c2->Ico.U8 );
972 case Ico_U16: return toBool( c1->Ico.U16 == c2->Ico.U16 );
973 case Ico_U32: return toBool( c1->Ico.U32 == c2->Ico.U32 );
974 case Ico_U64: return toBool( c1->Ico.U64 == c2->Ico.U64 );
975 default: break;
976 }
977 return False;
978 }
979
980 case Iex_Triop:
981 return toBool( e1->Iex.Triop.op == e2->Iex.Triop.op
982 && sameIRExprs_aux( env, e1->Iex.Triop.arg1, e2->Iex.Triop.arg1 )
983 && sameIRExprs_aux( env, e1->Iex.Triop.arg2, e2->Iex.Triop.arg2 )
984 && sameIRExprs_aux( env, e1->Iex.Triop.arg3, e2->Iex.Triop.arg3 ));
985
986 case Iex_Mux0X:
987 return toBool( sameIRExprs_aux( env, e1->Iex.Mux0X.cond, e2->Iex.Mux0X.cond )
988 && sameIRExprs_aux( env, e1->Iex.Mux0X.expr0, e2->Iex.Mux0X.expr0 )
989 && sameIRExprs_aux( env, e1->Iex.Mux0X.exprX, e2->Iex.Mux0X.exprX ));
990
991 default:
992 /* Not very likely to be "same". */
993 break;
sewardj6c299f32009-12-31 18:00:12 +0000994 }
floriancdb5fee2012-02-13 00:06:29 +0000995
996 return False;
sewardj6c299f32009-12-31 18:00:12 +0000997}
998
floriancdb5fee2012-02-13 00:06:29 +0000999static Bool sameIRExprs ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
1000{
1001 Bool same;
1002
1003 num_nodes_visited = 0;
1004 same = sameIRExprs_aux(env, e1, e2);
1005
1006#if STATS_IROPT
1007 ++invocation_count;
1008 if (recursed) ++recursion_count;
1009 success_count += same;
1010 if (same && recursion_helped)
1011 ++recursion_success_count;
1012 if (num_nodes_visited > max_nodes_visited)
1013 max_nodes_visited = num_nodes_visited;
1014 recursed = False; /* reset */
1015 recursion_helped = False; /* reset */
1016#endif /* STATS_IROPT */
1017
1018 return same;
1019}
1020
1021
florianea7eab72011-07-21 16:21:58 +00001022/* Is this literally IRExpr_Const(IRConst_U32(0)) ? */
1023static Bool isZeroU32 ( IRExpr* e )
1024{
1025 return toBool( e->tag == Iex_Const
1026 && e->Iex.Const.con->tag == Ico_U32
1027 && e->Iex.Const.con->Ico.U32 == 0);
1028}
1029
sewardjcf4be4a2012-03-26 09:44:39 +00001030/* Is this literally IRExpr_Const(IRConst_U32(1---1)) ? */
1031static Bool isOnesU32 ( IRExpr* e )
1032{
1033 return toBool( e->tag == Iex_Const
1034 && e->Iex.Const.con->tag == Ico_U32
1035 && e->Iex.Const.con->Ico.U32 == 0xFFFFFFFF );
1036}
1037
florianea7eab72011-07-21 16:21:58 +00001038/* Is this literally IRExpr_Const(IRConst_U64(0)) ? */
1039static Bool isZeroU64 ( IRExpr* e )
1040{
1041 return toBool( e->tag == Iex_Const
1042 && e->Iex.Const.con->tag == Ico_U64
1043 && e->Iex.Const.con->Ico.U64 == 0);
1044}
1045
florianf6402ab2012-01-29 02:19:43 +00001046/* Is this an integer constant with value 0 ? */
1047static Bool isZeroU ( IRExpr* e )
1048{
1049 if (e->tag != Iex_Const) return False;
florianf6402ab2012-01-29 02:19:43 +00001050 switch (e->Iex.Const.con->tag) {
1051 case Ico_U1: return toBool( e->Iex.Const.con->Ico.U1 == 0);
1052 case Ico_U8: return toBool( e->Iex.Const.con->Ico.U8 == 0);
1053 case Ico_U16: return toBool( e->Iex.Const.con->Ico.U16 == 0);
1054 case Ico_U32: return toBool( e->Iex.Const.con->Ico.U32 == 0);
1055 case Ico_U64: return toBool( e->Iex.Const.con->Ico.U64 == 0);
1056 default: vpanic("isZeroU");
1057 }
1058}
1059
sewardjcf4be4a2012-03-26 09:44:39 +00001060/* Is this an integer constant with value 1---1b ? */
1061static Bool isOnesU ( IRExpr* e )
1062{
1063 if (e->tag != Iex_Const) return False;
1064 switch (e->Iex.Const.con->tag) {
1065 case Ico_U8: return toBool( e->Iex.Const.con->Ico.U8 == 0xFF);
1066 case Ico_U16: return toBool( e->Iex.Const.con->Ico.U16 == 0xFFFF);
1067 case Ico_U32: return toBool( e->Iex.Const.con->Ico.U32
1068 == 0xFFFFFFFF);
1069 case Ico_U64: return toBool( e->Iex.Const.con->Ico.U64
1070 == 0xFFFFFFFFFFFFFFFFULL);
1071 default: ppIRExpr(e); vpanic("isOnesU");
1072 }
1073}
1074
sewardje1d45da2004-11-12 00:13:21 +00001075static Bool notBool ( Bool b )
1076{
1077 if (b == True) return False;
1078 if (b == False) return True;
1079 vpanic("notBool");
1080}
1081
sewardj0033ddc2005-04-26 23:34:34 +00001082/* Make a zero which has the same type as the result of the given
1083 primop. */
sewardj64d776c2010-10-01 14:06:22 +00001084static IRExpr* mkZeroOfPrimopResultType ( IROp op )
sewardj0033ddc2005-04-26 23:34:34 +00001085{
1086 switch (op) {
1087 case Iop_Xor8: return IRExpr_Const(IRConst_U8(0));
1088 case Iop_Xor16: return IRExpr_Const(IRConst_U16(0));
sewardjbe917912010-08-22 12:38:53 +00001089 case Iop_Sub32:
sewardj0033ddc2005-04-26 23:34:34 +00001090 case Iop_Xor32: return IRExpr_Const(IRConst_U32(0));
sewardj64d776c2010-10-01 14:06:22 +00001091 case Iop_Sub64:
sewardj0033ddc2005-04-26 23:34:34 +00001092 case Iop_Xor64: return IRExpr_Const(IRConst_U64(0));
sewardj04744272007-01-16 19:19:55 +00001093 case Iop_XorV128: return IRExpr_Const(IRConst_V128(0));
sewardj64d776c2010-10-01 14:06:22 +00001094 default: vpanic("mkZeroOfPrimopResultType: bad primop");
1095 }
1096}
1097
1098/* Make a value containing all 1-bits, which has the same type as the
1099 result of the given primop. */
1100static IRExpr* mkOnesOfPrimopResultType ( IROp op )
1101{
1102 switch (op) {
1103 case Iop_CmpEQ64:
1104 return IRExpr_Const(IRConst_U1(toBool(1)));
sewardjcf4be4a2012-03-26 09:44:39 +00001105 case Iop_Or8:
1106 return IRExpr_Const(IRConst_U8(0xFF));
1107 case Iop_Or16:
1108 return IRExpr_Const(IRConst_U16(0xFFFF));
1109 case Iop_Or32:
1110 return IRExpr_Const(IRConst_U32(0xFFFFFFFF));
sewardj64d776c2010-10-01 14:06:22 +00001111 case Iop_CmpEQ8x8:
sewardjcf4be4a2012-03-26 09:44:39 +00001112 case Iop_Or64:
sewardj64d776c2010-10-01 14:06:22 +00001113 return IRExpr_Const(IRConst_U64(0xFFFFFFFFFFFFFFFFULL));
1114 case Iop_CmpEQ8x16:
1115 return IRExpr_Const(IRConst_V128(0xFFFF));
1116 default:
sewardjcf4be4a2012-03-26 09:44:39 +00001117 ppIROp(op);
sewardj64d776c2010-10-01 14:06:22 +00001118 vpanic("mkOnesOfPrimopResultType: bad primop");
sewardj0033ddc2005-04-26 23:34:34 +00001119 }
1120}
1121
sewardj4cba9f42011-03-07 18:34:34 +00001122/* Helpers for folding Clz32/64. */
1123static UInt fold_Clz64 ( ULong value )
1124{
1125 UInt i;
1126 vassert(value != 0ULL); /* no defined semantics for arg==0 */
1127 for (i = 0; i < 64; ++i) {
sewardj7f6330d2011-04-05 11:06:02 +00001128 if (0ULL != (value & (((ULong)1) << (63 - i)))) return i;
sewardj4cba9f42011-03-07 18:34:34 +00001129 }
1130 vassert(0);
1131 /*NOTREACHED*/
1132 return 0;
1133}
1134
1135static UInt fold_Clz32 ( UInt value )
1136{
1137 UInt i;
1138 vassert(value != 0); /* no defined semantics for arg==0 */
1139 for (i = 0; i < 32; ++i) {
sewardj7f6330d2011-04-05 11:06:02 +00001140 if (0 != (value & (((UInt)1) << (31 - i)))) return i;
sewardj4cba9f42011-03-07 18:34:34 +00001141 }
1142 vassert(0);
1143 /*NOTREACHED*/
1144 return 0;
1145}
1146
sewardj0033ddc2005-04-26 23:34:34 +00001147
floriancdb5fee2012-02-13 00:06:29 +00001148static IRExpr* fold_Expr ( IRExpr** env, IRExpr* e )
sewardj84be7372004-08-18 13:59:33 +00001149{
sewardj278c44c2004-08-20 00:28:13 +00001150 Int shift;
sewardj84be7372004-08-18 13:59:33 +00001151 IRExpr* e2 = e; /* e2 is the result of folding e, if possible */
1152
florian708417d2012-02-15 00:43:36 +00001153 switch (e->tag) {
1154 case Iex_Unop:
1155 /* UNARY ops */
1156 if (e->Iex.Unop.arg->tag == Iex_Const) {
1157 switch (e->Iex.Unop.op) {
sewardjae27ab62004-10-15 21:21:46 +00001158 case Iop_1Uto8:
sewardj9d2e7692005-02-07 01:11:31 +00001159 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardjba999312004-11-15 15:21:17 +00001160 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardj9d2e7692005-02-07 01:11:31 +00001161 ? 1 : 0)));
sewardjae27ab62004-10-15 21:21:46 +00001162 break;
sewardjf4a821d2004-10-09 00:58:19 +00001163 case Iop_1Uto32:
1164 e2 = IRExpr_Const(IRConst_U32(
sewardjba999312004-11-15 15:21:17 +00001165 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardjf4a821d2004-10-09 00:58:19 +00001166 ? 1 : 0));
1167 break;
sewardj2716ff12005-05-20 19:21:45 +00001168 case Iop_1Uto64:
1169 e2 = IRExpr_Const(IRConst_U64(
1170 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
1171 ? 1 : 0));
1172 break;
sewardje6b39932004-11-06 17:01:15 +00001173
sewardj1bee5612005-11-10 18:10:58 +00001174 case Iop_1Sto8:
1175 e2 = IRExpr_Const(IRConst_U8(toUChar(
1176 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
1177 ? 0xFF : 0)));
1178 break;
sewardj68884ef2005-07-18 13:58:49 +00001179 case Iop_1Sto16:
sewardj743d8f02005-07-27 00:22:37 +00001180 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardj68884ef2005-07-18 13:58:49 +00001181 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardj743d8f02005-07-27 00:22:37 +00001182 ? 0xFFFF : 0)));
sewardj68884ef2005-07-18 13:58:49 +00001183 break;
sewardjd9997882004-11-04 19:42:59 +00001184 case Iop_1Sto32:
1185 e2 = IRExpr_Const(IRConst_U32(
sewardjba999312004-11-15 15:21:17 +00001186 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardjd9997882004-11-04 19:42:59 +00001187 ? 0xFFFFFFFF : 0));
1188 break;
sewardje6b39932004-11-06 17:01:15 +00001189 case Iop_1Sto64:
1190 e2 = IRExpr_Const(IRConst_U64(
sewardjba999312004-11-15 15:21:17 +00001191 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardje6b39932004-11-06 17:01:15 +00001192 ? 0xFFFFFFFFFFFFFFFFULL : 0));
1193 break;
1194
sewardj883b00b2004-09-11 09:30:24 +00001195 case Iop_8Sto32: {
1196 /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
1197 s32 <<= 24;
1198 s32 >>= 24;
1199 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
1200 break;
1201 }
sewardj7f6330d2011-04-05 11:06:02 +00001202 case Iop_16Sto32: {
1203 /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1204 s32 <<= 16;
1205 s32 >>= 16;
1206 e2 = IRExpr_Const(IRConst_U32( (UInt)s32) );
1207 break;
1208 }
sewardj291a7e82005-04-27 11:42:44 +00001209 case Iop_8Uto64:
1210 e2 = IRExpr_Const(IRConst_U64(
1211 0xFFULL & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1212 break;
1213 case Iop_16Uto64:
1214 e2 = IRExpr_Const(IRConst_U64(
1215 0xFFFFULL & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
1216 break;
sewardj84be7372004-08-18 13:59:33 +00001217 case Iop_8Uto32:
1218 e2 = IRExpr_Const(IRConst_U32(
1219 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1220 break;
sewardj7f6330d2011-04-05 11:06:02 +00001221 case Iop_8Sto16: {
1222 /* signed */ Short s16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
1223 s16 <<= 8;
1224 s16 >>= 8;
1225 e2 = IRExpr_Const(IRConst_U16( (UShort)s16) );
1226 break;
1227 }
1228 case Iop_8Uto16:
1229 e2 = IRExpr_Const(IRConst_U16(
1230 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1231 break;
sewardj84be7372004-08-18 13:59:33 +00001232 case Iop_16Uto32:
1233 e2 = IRExpr_Const(IRConst_U32(
1234 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
1235 break;
sewardj73017432004-10-14 19:33:25 +00001236 case Iop_32to16:
sewardj9d2e7692005-02-07 01:11:31 +00001237 e2 = IRExpr_Const(IRConst_U16(toUShort(
1238 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
sewardj73017432004-10-14 19:33:25 +00001239 break;
sewardj4345f7a2004-09-22 19:49:27 +00001240 case Iop_32to8:
sewardj9d2e7692005-02-07 01:11:31 +00001241 e2 = IRExpr_Const(IRConst_U8(toUChar(
1242 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
sewardj4345f7a2004-09-22 19:49:27 +00001243 break;
sewardj7447b5b2004-10-16 11:30:42 +00001244 case Iop_32to1:
sewardj9d2e7692005-02-07 01:11:31 +00001245 e2 = IRExpr_Const(IRConst_U1(toBool(
1246 1 == (1 & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)
1247 )));
sewardj7447b5b2004-10-16 11:30:42 +00001248 break;
sewardj291a7e82005-04-27 11:42:44 +00001249 case Iop_64to1:
1250 e2 = IRExpr_Const(IRConst_U1(toBool(
1251 1 == (1 & e->Iex.Unop.arg->Iex.Const.con->Ico.U64)
1252 )));
1253 break;
sewardje6b39932004-11-06 17:01:15 +00001254
sewardjf057afb2005-02-27 13:35:41 +00001255 case Iop_Not64:
1256 e2 = IRExpr_Const(IRConst_U64(
1257 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U64)));
1258 break;
sewardj883b00b2004-09-11 09:30:24 +00001259 case Iop_Not32:
1260 e2 = IRExpr_Const(IRConst_U32(
1261 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
1262 break;
sewardje6b39932004-11-06 17:01:15 +00001263 case Iop_Not16:
sewardj9d2e7692005-02-07 01:11:31 +00001264 e2 = IRExpr_Const(IRConst_U16(toUShort(
1265 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U16))));
sewardje6b39932004-11-06 17:01:15 +00001266 break;
sewardjd9997882004-11-04 19:42:59 +00001267 case Iop_Not8:
sewardj9d2e7692005-02-07 01:11:31 +00001268 e2 = IRExpr_Const(IRConst_U8(toUChar(
1269 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U8))));
sewardjd9997882004-11-04 19:42:59 +00001270 break;
sewardje6b39932004-11-06 17:01:15 +00001271
sewardje1d45da2004-11-12 00:13:21 +00001272 case Iop_Not1:
sewardjba999312004-11-15 15:21:17 +00001273 e2 = IRExpr_Const(IRConst_U1(
1274 notBool(e->Iex.Unop.arg->Iex.Const.con->Ico.U1)));
sewardje1d45da2004-11-12 00:13:21 +00001275 break;
1276
sewardj291a7e82005-04-27 11:42:44 +00001277 case Iop_64to8: {
1278 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1279 w64 &= 0xFFULL;
1280 e2 = IRExpr_Const(IRConst_U8( (UChar)w64 ));
1281 break;
1282 }
1283 case Iop_64to16: {
1284 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1285 w64 &= 0xFFFFULL;
sewardje85bc402005-05-06 16:29:26 +00001286 e2 = IRExpr_Const(IRConst_U16( (UShort)w64 ));
sewardj291a7e82005-04-27 11:42:44 +00001287 break;
1288 }
sewardj1d8ce202004-12-13 14:14:16 +00001289 case Iop_64to32: {
1290 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1291 w64 &= 0x00000000FFFFFFFFULL;
1292 e2 = IRExpr_Const(IRConst_U32( (UInt)w64 ));
sewardj37010592004-12-13 10:47:15 +00001293 break;
sewardj1d8ce202004-12-13 14:14:16 +00001294 }
sewardj1d8ce202004-12-13 14:14:16 +00001295 case Iop_64HIto32: {
1296 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1297 w64 >>= 32;
1298 e2 = IRExpr_Const(IRConst_U32( (UInt)w64 ));
1299 break;
1300 }
sewardjb5710b82005-01-27 16:05:09 +00001301 case Iop_32Uto64:
1302 e2 = IRExpr_Const(IRConst_U64(
1303 0xFFFFFFFFULL
1304 & e->Iex.Unop.arg->Iex.Const.con->Ico.U32));
1305 break;
sewardj7f6330d2011-04-05 11:06:02 +00001306 case Iop_16Sto64: {
1307 /* signed */ Long s64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1308 s64 <<= 48;
1309 s64 >>= 48;
1310 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1311 break;
1312 }
sewardj287e9bb2010-07-29 16:12:41 +00001313 case Iop_32Sto64: {
1314 /* signed */ Long s64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1315 s64 <<= 32;
1316 s64 >>= 32;
1317 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1318 break;
1319 }
sewardj7f6330d2011-04-05 11:06:02 +00001320
1321 case Iop_16to8: {
1322 UShort w16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1323 w16 &= 0xFF;
1324 e2 = IRExpr_Const(IRConst_U8( (UChar)w16 ));
1325 break;
1326 }
1327 case Iop_16HIto8: {
1328 UShort w16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1329 w16 >>= 8;
1330 w16 &= 0xFF;
1331 e2 = IRExpr_Const(IRConst_U8( (UChar)w16 ));
1332 break;
1333 }
1334
sewardj0033ddc2005-04-26 23:34:34 +00001335 case Iop_CmpNEZ8:
1336 e2 = IRExpr_Const(IRConst_U1(toBool(
1337 0 !=
1338 (0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8)
1339 )));
1340 break;
1341 case Iop_CmpNEZ32:
1342 e2 = IRExpr_Const(IRConst_U1(toBool(
1343 0 !=
1344 (0xFFFFFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)
1345 )));
1346 break;
1347 case Iop_CmpNEZ64:
1348 e2 = IRExpr_Const(IRConst_U1(toBool(
1349 0ULL != e->Iex.Unop.arg->Iex.Const.con->Ico.U64
1350 )));
1351 break;
1352
sewardjeb17e492007-08-25 23:07:44 +00001353 case Iop_CmpwNEZ32: {
1354 UInt w32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1355 if (w32 == 0)
1356 e2 = IRExpr_Const(IRConst_U32( 0 ));
1357 else
1358 e2 = IRExpr_Const(IRConst_U32( 0xFFFFFFFF ));
1359 break;
1360 }
1361 case Iop_CmpwNEZ64: {
1362 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1363 if (w64 == 0)
1364 e2 = IRExpr_Const(IRConst_U64( 0 ));
1365 else
1366 e2 = IRExpr_Const(IRConst_U64( 0xFFFFFFFFFFFFFFFFULL ));
1367 break;
1368 }
1369
1370 case Iop_Left32: {
1371 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1372 Int s32 = (Int)(u32 & 0xFFFFFFFF);
1373 s32 = (s32 | (-s32));
1374 e2 = IRExpr_Const( IRConst_U32( (UInt)s32 ));
1375 break;
1376 }
1377
1378 case Iop_Left64: {
1379 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1380 Long s64 = (Long)u64;
1381 s64 = (s64 | (-s64));
1382 e2 = IRExpr_Const( IRConst_U64( (ULong)s64 ));
1383 break;
1384 }
1385
sewardj4cba9f42011-03-07 18:34:34 +00001386 case Iop_Clz32: {
1387 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1388 if (u32 != 0)
1389 e2 = IRExpr_Const(IRConst_U32(fold_Clz32(u32)));
1390 break;
1391 }
1392 case Iop_Clz64: {
1393 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1394 if (u64 != 0ULL)
1395 e2 = IRExpr_Const(IRConst_U64(fold_Clz64(u64)));
1396 break;
1397 }
1398
sewardj84be7372004-08-18 13:59:33 +00001399 default:
1400 goto unhandled;
1401 }
florian708417d2012-02-15 00:43:36 +00001402 }
1403 break;
sewardj84be7372004-08-18 13:59:33 +00001404
florian708417d2012-02-15 00:43:36 +00001405 case Iex_Binop:
1406 /* BINARY ops */
sewardj84be7372004-08-18 13:59:33 +00001407 if (e->Iex.Binop.arg1->tag == Iex_Const
1408 && e->Iex.Binop.arg2->tag == Iex_Const) {
1409 /* cases where both args are consts */
1410 switch (e->Iex.Binop.op) {
sewardje6b39932004-11-06 17:01:15 +00001411
sewardj855dc722005-02-17 09:26:05 +00001412 /* -- Or -- */
sewardjd9997882004-11-04 19:42:59 +00001413 case Iop_Or8:
sewardj9d2e7692005-02-07 01:11:31 +00001414 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardjd9997882004-11-04 19:42:59 +00001415 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001416 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardjd9997882004-11-04 19:42:59 +00001417 break;
sewardje6b39932004-11-06 17:01:15 +00001418 case Iop_Or16:
sewardj9d2e7692005-02-07 01:11:31 +00001419 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardje6b39932004-11-06 17:01:15 +00001420 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
sewardj9d2e7692005-02-07 01:11:31 +00001421 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
sewardje6b39932004-11-06 17:01:15 +00001422 break;
1423 case Iop_Or32:
1424 e2 = IRExpr_Const(IRConst_U32(
1425 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1426 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1427 break;
sewardjf057afb2005-02-27 13:35:41 +00001428 case Iop_Or64:
1429 e2 = IRExpr_Const(IRConst_U64(
1430 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1431 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1432 break;
sewardje6b39932004-11-06 17:01:15 +00001433
sewardj855dc722005-02-17 09:26:05 +00001434 /* -- Xor -- */
sewardj883b00b2004-09-11 09:30:24 +00001435 case Iop_Xor8:
sewardj9d2e7692005-02-07 01:11:31 +00001436 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj883b00b2004-09-11 09:30:24 +00001437 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001438 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj883b00b2004-09-11 09:30:24 +00001439 break;
sewardj82c9f2f2005-03-02 16:05:13 +00001440 case Iop_Xor16:
sewardjc7c098f2005-03-21 01:06:20 +00001441 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardj82c9f2f2005-03-02 16:05:13 +00001442 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
sewardjc7c098f2005-03-21 01:06:20 +00001443 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
sewardj82c9f2f2005-03-02 16:05:13 +00001444 break;
sewardj855dc722005-02-17 09:26:05 +00001445 case Iop_Xor32:
1446 e2 = IRExpr_Const(IRConst_U32(
1447 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1448 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1449 break;
sewardjf057afb2005-02-27 13:35:41 +00001450 case Iop_Xor64:
1451 e2 = IRExpr_Const(IRConst_U64(
1452 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1453 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1454 break;
sewardj855dc722005-02-17 09:26:05 +00001455
1456 /* -- And -- */
sewardj84be7372004-08-18 13:59:33 +00001457 case Iop_And8:
sewardj9d2e7692005-02-07 01:11:31 +00001458 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj84be7372004-08-18 13:59:33 +00001459 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001460 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj84be7372004-08-18 13:59:33 +00001461 break;
sewardj7f6330d2011-04-05 11:06:02 +00001462 case Iop_And16:
1463 e2 = IRExpr_Const(IRConst_U16(toUShort(
1464 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
1465 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
1466 break;
sewardj855dc722005-02-17 09:26:05 +00001467 case Iop_And32:
1468 e2 = IRExpr_Const(IRConst_U32(
1469 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1470 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1471 break;
1472 case Iop_And64:
1473 e2 = IRExpr_Const(IRConst_U64(
1474 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1475 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1476 break;
1477
1478 /* -- Add -- */
sewardj4345f7a2004-09-22 19:49:27 +00001479 case Iop_Add8:
sewardj9d2e7692005-02-07 01:11:31 +00001480 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj4345f7a2004-09-22 19:49:27 +00001481 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001482 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj4345f7a2004-09-22 19:49:27 +00001483 break;
sewardj855dc722005-02-17 09:26:05 +00001484 case Iop_Add32:
1485 e2 = IRExpr_Const(IRConst_U32(
1486 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1487 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1488 break;
1489 case Iop_Add64:
1490 e2 = IRExpr_Const(IRConst_U64(
1491 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1492 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1493 break;
1494
1495 /* -- Sub -- */
sewardj84be7372004-08-18 13:59:33 +00001496 case Iop_Sub8:
sewardj9d2e7692005-02-07 01:11:31 +00001497 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj84be7372004-08-18 13:59:33 +00001498 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001499 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj84be7372004-08-18 13:59:33 +00001500 break;
sewardjd7217032004-08-19 10:49:10 +00001501 case Iop_Sub32:
1502 e2 = IRExpr_Const(IRConst_U32(
1503 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1504 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1505 break;
sewardj70a8ddf2005-02-13 02:24:26 +00001506 case Iop_Sub64:
1507 e2 = IRExpr_Const(IRConst_U64(
1508 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1509 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1510 break;
sewardjc2bcb6f2005-02-07 00:17:12 +00001511
sewardj478646f2008-05-01 20:13:04 +00001512 /* -- Max32U -- */
1513 case Iop_Max32U: {
1514 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1515 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1516 UInt res = u32a > u32b ? u32a : u32b;
1517 e2 = IRExpr_Const(IRConst_U32(res));
1518 break;
1519 }
1520
sewardj855dc722005-02-17 09:26:05 +00001521 /* -- Mul -- */
sewardjb9c5cf62004-08-24 15:10:38 +00001522 case Iop_Mul32:
1523 e2 = IRExpr_Const(IRConst_U32(
1524 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1525 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1526 break;
sewardja34c0712005-03-30 23:19:46 +00001527 case Iop_Mul64:
1528 e2 = IRExpr_Const(IRConst_U64(
1529 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1530 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1531 break;
1532
sewardjea6bccb2005-03-01 10:19:23 +00001533 case Iop_MullS32: {
1534 /* very paranoid */
1535 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1536 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1537 Int s32a = (Int)u32a;
1538 Int s32b = (Int)u32b;
1539 Long s64a = (Long)s32a;
1540 Long s64b = (Long)s32b;
1541 Long sres = s64a * s64b;
1542 ULong ures = (ULong)sres;
1543 e2 = IRExpr_Const(IRConst_U64(ures));
1544 break;
1545 }
sewardjb095fba2005-02-13 14:13:04 +00001546
sewardj855dc722005-02-17 09:26:05 +00001547 /* -- Shl -- */
sewardjd7217032004-08-19 10:49:10 +00001548 case Iop_Shl32:
sewardj61348472004-08-20 01:01:04 +00001549 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1550 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj29632392004-08-22 02:38:11 +00001551 if (shift >= 0 && shift <= 31)
sewardj278c44c2004-08-20 00:28:13 +00001552 e2 = IRExpr_Const(IRConst_U32(
1553 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1554 << shift)));
sewardjd7217032004-08-19 10:49:10 +00001555 break;
sewardjb095fba2005-02-13 14:13:04 +00001556 case Iop_Shl64:
1557 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1558 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1559 if (shift >= 0 && shift <= 63)
1560 e2 = IRExpr_Const(IRConst_U64(
1561 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1562 << shift)));
1563 break;
1564
sewardj855dc722005-02-17 09:26:05 +00001565 /* -- Sar -- */
sewardj278c44c2004-08-20 00:28:13 +00001566 case Iop_Sar32: {
1567 /* paranoid ... */
1568 /*signed*/ Int s32;
sewardj61348472004-08-20 01:01:04 +00001569 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj278c44c2004-08-20 00:28:13 +00001570 s32 = (Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +00001571 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj278c44c2004-08-20 00:28:13 +00001572 if (shift >= 0 && shift <= 31) {
1573 s32 >>=/*signed*/ shift;
1574 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
1575 }
1576 break;
1577 }
sewardj855dc722005-02-17 09:26:05 +00001578 case Iop_Sar64: {
1579 /* paranoid ... */
1580 /*signed*/ Long s64;
1581 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1582 s64 = (Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64);
1583 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1584 if (shift >= 0 && shift <= 63) {
1585 s64 >>=/*signed*/ shift;
1586 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1587 }
1588 break;
1589 }
1590
1591 /* -- Shr -- */
sewardj61348472004-08-20 01:01:04 +00001592 case Iop_Shr32: {
1593 /* paranoid ... */
sewardj4add7142005-02-21 08:20:22 +00001594 /*unsigned*/ UInt u32;
sewardj61348472004-08-20 01:01:04 +00001595 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj4add7142005-02-21 08:20:22 +00001596 u32 = (UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +00001597 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1598 if (shift >= 0 && shift <= 31) {
sewardj4add7142005-02-21 08:20:22 +00001599 u32 >>=/*unsigned*/ shift;
1600 e2 = IRExpr_Const(IRConst_U32(u32));
1601 }
1602 break;
1603 }
1604 case Iop_Shr64: {
1605 /* paranoid ... */
1606 /*unsigned*/ ULong u64;
1607 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1608 u64 = (ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64);
1609 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1610 if (shift >= 0 && shift <= 63) {
1611 u64 >>=/*unsigned*/ shift;
1612 e2 = IRExpr_Const(IRConst_U64(u64));
sewardj61348472004-08-20 01:01:04 +00001613 }
1614 break;
1615 }
sewardj855dc722005-02-17 09:26:05 +00001616
1617 /* -- CmpEQ -- */
sewardjb8e75862004-08-19 17:58:45 +00001618 case Iop_CmpEQ32:
sewardj9d2e7692005-02-07 01:11:31 +00001619 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardjb8e75862004-08-19 17:58:45 +00001620 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
sewardj9d2e7692005-02-07 01:11:31 +00001621 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))));
sewardjb8e75862004-08-19 17:58:45 +00001622 break;
sewardj855dc722005-02-17 09:26:05 +00001623 case Iop_CmpEQ64:
1624 e2 = IRExpr_Const(IRConst_U1(toBool(
1625 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1626 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U64))));
1627 break;
1628
1629 /* -- CmpNE -- */
1630 case Iop_CmpNE8:
1631 e2 = IRExpr_Const(IRConst_U1(toBool(
1632 ((0xFF & e->Iex.Binop.arg1->Iex.Const.con->Ico.U8)
1633 != (0xFF & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)))));
1634 break;
sewardjae27ab62004-10-15 21:21:46 +00001635 case Iop_CmpNE32:
sewardj9d2e7692005-02-07 01:11:31 +00001636 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardjae27ab62004-10-15 21:21:46 +00001637 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
sewardj9d2e7692005-02-07 01:11:31 +00001638 != e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))));
sewardjae27ab62004-10-15 21:21:46 +00001639 break;
sewardje6b39932004-11-06 17:01:15 +00001640 case Iop_CmpNE64:
sewardj9d2e7692005-02-07 01:11:31 +00001641 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardje6b39932004-11-06 17:01:15 +00001642 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
sewardj9d2e7692005-02-07 01:11:31 +00001643 != e->Iex.Binop.arg2->Iex.Const.con->Ico.U64))));
sewardje6b39932004-11-06 17:01:15 +00001644 break;
1645
sewardj855dc722005-02-17 09:26:05 +00001646 /* -- CmpLEU -- */
sewardj7447b5b2004-10-16 11:30:42 +00001647 case Iop_CmpLE32U:
sewardj9d2e7692005-02-07 01:11:31 +00001648 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj7447b5b2004-10-16 11:30:42 +00001649 ((UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001650 <= (UInt)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj7447b5b2004-10-16 11:30:42 +00001651 break;
sewardj7f6330d2011-04-05 11:06:02 +00001652 case Iop_CmpLE64U:
1653 e2 = IRExpr_Const(IRConst_U1(toBool(
1654 ((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1655 <= (ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1656 break;
sewardj855dc722005-02-17 09:26:05 +00001657
1658 /* -- CmpLES -- */
sewardj088e4f72004-10-19 01:25:02 +00001659 case Iop_CmpLE32S:
sewardj9d2e7692005-02-07 01:11:31 +00001660 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj088e4f72004-10-19 01:25:02 +00001661 ((Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001662 <= (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj088e4f72004-10-19 01:25:02 +00001663 break;
sewardj7f6330d2011-04-05 11:06:02 +00001664 case Iop_CmpLE64S:
1665 e2 = IRExpr_Const(IRConst_U1(toBool(
1666 ((Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1667 <= (Long)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1668 break;
sewardje1d45da2004-11-12 00:13:21 +00001669
sewardj855dc722005-02-17 09:26:05 +00001670 /* -- CmpLTS -- */
sewardj9bdd2652004-10-19 12:56:33 +00001671 case Iop_CmpLT32S:
sewardj9d2e7692005-02-07 01:11:31 +00001672 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj9bdd2652004-10-19 12:56:33 +00001673 ((Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001674 < (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj9bdd2652004-10-19 12:56:33 +00001675 break;
sewardj7f6330d2011-04-05 11:06:02 +00001676 case Iop_CmpLT64S:
1677 e2 = IRExpr_Const(IRConst_U1(toBool(
1678 ((Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1679 < (Long)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1680 break;
sewardj855dc722005-02-17 09:26:05 +00001681
1682 /* -- CmpLTU -- */
sewardje1d45da2004-11-12 00:13:21 +00001683 case Iop_CmpLT32U:
sewardj9d2e7692005-02-07 01:11:31 +00001684 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardje1d45da2004-11-12 00:13:21 +00001685 ((UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001686 < (UInt)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardje1d45da2004-11-12 00:13:21 +00001687 break;
sewardj7f6330d2011-04-05 11:06:02 +00001688 case Iop_CmpLT64U:
1689 e2 = IRExpr_Const(IRConst_U1(toBool(
1690 ((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1691 < (ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1692 break;
sewardj7447b5b2004-10-16 11:30:42 +00001693
sewardjb51f0f42005-07-18 11:38:02 +00001694 /* -- CmpORD -- */
1695 case Iop_CmpORD32S: {
1696 /* very paranoid */
1697 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1698 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1699 Int s32a = (Int)u32a;
1700 Int s32b = (Int)u32b;
1701 Int r = 0x2; /* EQ */
1702 if (s32a < s32b) {
1703 r = 0x8; /* LT */
1704 }
1705 else if (s32a > s32b) {
1706 r = 0x4; /* GT */
1707 }
1708 e2 = IRExpr_Const(IRConst_U32(r));
1709 break;
1710 }
1711
sewardj855dc722005-02-17 09:26:05 +00001712 /* -- nHLto2n -- */
sewardj088bcb42004-08-19 17:16:52 +00001713 case Iop_32HLto64:
1714 e2 = IRExpr_Const(IRConst_U64(
1715 (((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)) << 32)
1716 | ((ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))
1717 ));
1718 break;
sewardj3bc8a592005-05-02 10:47:22 +00001719 case Iop_64HLto128:
1720 /* We can't fold this, because there is no way to
1721 express he result in IR, but at least pretend to
1722 handle it, so as to stop getting blasted with
1723 no-rule-for-this-primop messages. */
1724 break;
sewardj855dc722005-02-17 09:26:05 +00001725
sewardj607dd4f2004-09-08 18:20:19 +00001726 default:
1727 goto unhandled;
sewardjd7217032004-08-19 10:49:10 +00001728 }
sewardjf6729012004-08-25 12:45:13 +00001729
sewardj84be7372004-08-18 13:59:33 +00001730 } else {
sewardjf6729012004-08-25 12:45:13 +00001731
sewardj84be7372004-08-18 13:59:33 +00001732 /* other cases (identities, etc) */
sewardj64d776c2010-10-01 14:06:22 +00001733 switch (e->Iex.Binop.op) {
florianf6402ab2012-01-29 02:19:43 +00001734
1735 case Iop_Shl32:
1736 case Iop_Shl64:
1737 case Iop_Shr64:
1738 /* Shl32/Shl64/Shr64(x,0) ==> x */
1739 if (isZeroU(e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00001740 e2 = e->Iex.Binop.arg1;
florianf6402ab2012-01-29 02:19:43 +00001741 break;
1742 }
1743 /* Shl32/Shl64/Shr64(0,x) ==> 0 */
1744 if (isZeroU(e->Iex.Binop.arg1)) {
1745 e2 = e->Iex.Binop.arg1;
1746 break;
1747 }
sewardj64d776c2010-10-01 14:06:22 +00001748 break;
sewardjf6729012004-08-25 12:45:13 +00001749
florianf6402ab2012-01-29 02:19:43 +00001750 case Iop_Shr32:
1751 /* Shr32(x,0) ==> x */
1752 if (isZeroU(e->Iex.Binop.arg2)) {
1753 e2 = e->Iex.Binop.arg1;
1754 break;
1755 }
1756 break;
1757
1758 case Iop_Or8:
1759 case Iop_Or16:
1760 case Iop_Or32:
1761 case Iop_Or64:
1762 case Iop_Max32U:
sewardjcf4be4a2012-03-26 09:44:39 +00001763 /* Or8/Or16/Or32/Or64/Max32U(x,0) ==> x */
florianf6402ab2012-01-29 02:19:43 +00001764 if (isZeroU(e->Iex.Binop.arg2)) {
1765 e2 = e->Iex.Binop.arg1;
1766 break;
1767 }
sewardjcf4be4a2012-03-26 09:44:39 +00001768 /* Or8/Or16/Or32/Or64/Max32U(0,x) ==> x */
florianf6402ab2012-01-29 02:19:43 +00001769 if (isZeroU(e->Iex.Binop.arg1)) {
1770 e2 = e->Iex.Binop.arg2;
1771 break;
1772 }
sewardjcf4be4a2012-03-26 09:44:39 +00001773 /* Or8/Or16/Or32/Or64/Max32U(x,1---1b) ==> 1---1b */
1774 /* Or8/Or16/Or32/Or64/Max32U(1---1b,x) ==> 1---1b */
1775 if (isOnesU(e->Iex.Binop.arg1) || isOnesU(e->Iex.Binop.arg2)) {
1776 e2 = mkOnesOfPrimopResultType(e->Iex.Binop.op);
1777 break;
1778 }
1779 /* Or8/Or16/Or32/Or64/Max32U(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00001780 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00001781 e2 = e->Iex.Binop.arg1;
1782 break;
1783 }
1784 break;
1785
1786 case Iop_Add8:
1787 /* Add8(t,t) ==> t << 1.
1788 Memcheck doesn't understand that
1789 x+x produces a defined least significant bit, and it seems
1790 simplest just to get rid of the problem by rewriting it
1791 out, since the opportunity to do so exists. */
floriancdb5fee2012-02-13 00:06:29 +00001792 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00001793 e2 = IRExpr_Binop(Iop_Shl8, e->Iex.Binop.arg1,
1794 IRExpr_Const(IRConst_U8(1)));
1795 break;
1796 }
1797 break;
1798
1799 /* NB no Add16(t,t) case yet as no known test case exists */
1800
1801 case Iop_Add32:
1802 case Iop_Add64:
1803 /* Add32/Add64(x,0) ==> x */
1804 if (isZeroU(e->Iex.Binop.arg2)) {
1805 e2 = e->Iex.Binop.arg1;
1806 break;
1807 }
1808 /* Add32/Add64(0,x) ==> x */
1809 if (isZeroU(e->Iex.Binop.arg1)) {
1810 e2 = e->Iex.Binop.arg2;
1811 break;
1812 }
1813 /* Add32/Add64(t,t) ==> t << 1. Same rationale as for Add8. */
floriancdb5fee2012-02-13 00:06:29 +00001814 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00001815 e2 = IRExpr_Binop(e->Iex.Binop.op == Iop_Add32 ? Iop_Shl32 : Iop_Shl64,
1816 e->Iex.Binop.arg1, IRExpr_Const(IRConst_U8(1)));
1817 break;
1818 }
1819 break;
1820
1821 case Iop_Sub64:
1822 /* Sub64(x,0) ==> x */
1823 if (isZeroU64(e->Iex.Binop.arg2)) {
1824 e2 = e->Iex.Binop.arg1;
1825 break;
1826 }
1827 /* Sub64(t,t) ==> 0, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00001828 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00001829 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
florianf6402ab2012-01-29 02:19:43 +00001830 break;
1831 }
sewardj64d776c2010-10-01 14:06:22 +00001832 break;
sewardj64d776c2010-10-01 14:06:22 +00001833
florianf6402ab2012-01-29 02:19:43 +00001834 case Iop_And32:
1835 /* And32(x,0xFFFFFFFF) ==> x */
sewardjcf4be4a2012-03-26 09:44:39 +00001836 if (isOnesU32(e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00001837 e2 = e->Iex.Binop.arg1;
1838 break;
1839 }
1840 /* And32(x,0) ==> 0 */
1841 if (isZeroU32(e->Iex.Binop.arg2)) {
1842 e2 = e->Iex.Binop.arg2;
1843 break;
1844 }
1845 /* And32(0,x) ==> 0 */
1846 if (isZeroU32(e->Iex.Binop.arg1)) {
1847 e2 = e->Iex.Binop.arg1;
1848 break;
1849 }
1850 /* And32(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00001851 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00001852 e2 = e->Iex.Binop.arg1;
1853 break;
1854 }
1855 break;
1856
1857 case Iop_And8:
1858 case Iop_And16:
1859 case Iop_And64:
1860 /* And8/And16/And64(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00001861 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00001862 e2 = e->Iex.Binop.arg1;
1863 break;
1864 }
1865 break;
1866
1867 case Iop_OrV128:
1868 /* V128(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00001869 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00001870 e2 = e->Iex.Binop.arg1;
1871 break;
1872 }
1873 break;
1874
1875 case Iop_Xor8:
1876 case Iop_Xor16:
1877 case Iop_Xor32:
1878 case Iop_Xor64:
1879 case Iop_XorV128:
1880 /* Xor8/16/32/64/V128(t,t) ==> 0, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00001881 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00001882 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
1883 break;
1884 }
1885 break;
1886
1887 case Iop_Sub32:
1888 /* Sub32(t,t) ==> 0, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00001889 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00001890 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
1891 break;
1892 }
1893 break;
1894
sewardj64d776c2010-10-01 14:06:22 +00001895 case Iop_CmpEQ64:
1896 case Iop_CmpEQ8x8:
1897 case Iop_CmpEQ8x16:
floriancdb5fee2012-02-13 00:06:29 +00001898 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00001899 e2 = mkOnesOfPrimopResultType(e->Iex.Binop.op);
florianf6402ab2012-01-29 02:19:43 +00001900 break;
1901 }
sewardj64d776c2010-10-01 14:06:22 +00001902 break;
florianf6402ab2012-01-29 02:19:43 +00001903
sewardj64d776c2010-10-01 14:06:22 +00001904 default:
1905 break;
sewardj0033ddc2005-04-26 23:34:34 +00001906 }
sewardj84be7372004-08-18 13:59:33 +00001907 }
florian708417d2012-02-15 00:43:36 +00001908 break;
sewardj84be7372004-08-18 13:59:33 +00001909
florian708417d2012-02-15 00:43:36 +00001910 case Iex_Mux0X:
1911 /* Mux0X */
1912
sewardj6c299f32009-12-31 18:00:12 +00001913 /* is the discriminant is a constant? */
1914 if (e->Iex.Mux0X.cond->tag == Iex_Const) {
1915 Bool zero;
1916 /* assured us by the IR type rules */
1917 vassert(e->Iex.Mux0X.cond->Iex.Const.con->tag == Ico_U8);
1918 zero = toBool(0 == (0xFF & e->Iex.Mux0X.cond
1919 ->Iex.Const.con->Ico.U8));
1920 e2 = zero ? e->Iex.Mux0X.expr0 : e->Iex.Mux0X.exprX;
1921 }
1922 else
1923 /* are the arms identical? (pretty weedy test) */
floriancdb5fee2012-02-13 00:06:29 +00001924 if (sameIRExprs(env, e->Iex.Mux0X.expr0,
1925 e->Iex.Mux0X.exprX)) {
sewardj6c299f32009-12-31 18:00:12 +00001926 e2 = e->Iex.Mux0X.expr0;
1927 }
florian708417d2012-02-15 00:43:36 +00001928 break;
1929
1930 default:
1931 /* not considered */
1932 break;
sewardj84be7372004-08-18 13:59:33 +00001933 }
1934
sewardj64d776c2010-10-01 14:06:22 +00001935 /* Show cases where we've found but not folded 'op(t,t)'. */
1936 if (0 && e == e2 && e->tag == Iex_Binop
floriancdb5fee2012-02-13 00:06:29 +00001937 && sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00001938 vex_printf("IDENT: ");
1939 ppIRExpr(e); vex_printf("\n");
1940 }
1941
1942 /* Show the overall results of folding. */
sewardj088bcb42004-08-19 17:16:52 +00001943 if (DEBUG_IROPT && e2 != e) {
1944 vex_printf("FOLD: ");
sewardj84be7372004-08-18 13:59:33 +00001945 ppIRExpr(e); vex_printf(" -> ");
1946 ppIRExpr(e2); vex_printf("\n");
1947 }
1948
1949 return e2;
1950
1951 unhandled:
sewardj883b00b2004-09-11 09:30:24 +00001952# if 0
sewardj84be7372004-08-18 13:59:33 +00001953 vex_printf("\n\n");
1954 ppIRExpr(e);
1955 vpanic("fold_Expr: no rule for the above");
sewardj883b00b2004-09-11 09:30:24 +00001956# else
sewardj328b54b2005-06-13 16:30:18 +00001957 if (vex_control.iropt_verbosity > 0) {
1958 vex_printf("vex iropt: fold_Expr: no rule for: ");
1959 ppIRExpr(e);
1960 vex_printf("\n");
1961 }
sewardj883b00b2004-09-11 09:30:24 +00001962 return e2;
1963# endif
sewardj84be7372004-08-18 13:59:33 +00001964}
1965
1966
sewardj84be7372004-08-18 13:59:33 +00001967/* Apply the subst to a simple 1-level expression -- guaranteed to be
1968 1-level due to previous flattening pass. */
1969
sewardj62617ef2004-10-13 23:29:22 +00001970static IRExpr* subst_Expr ( IRExpr** env, IRExpr* ex )
sewardj84be7372004-08-18 13:59:33 +00001971{
sewardj62617ef2004-10-13 23:29:22 +00001972 switch (ex->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +00001973 case Iex_RdTmp:
1974 if (env[(Int)ex->Iex.RdTmp.tmp] != NULL) {
floriancdb5fee2012-02-13 00:06:29 +00001975 IRExpr *rhs = env[(Int)ex->Iex.RdTmp.tmp];
1976 if (rhs->tag == Iex_RdTmp)
1977 return rhs;
1978 if (rhs->tag == Iex_Const
1979 && rhs->Iex.Const.con->tag != Ico_F64i)
1980 return rhs;
sewardj62617ef2004-10-13 23:29:22 +00001981 }
floriancdb5fee2012-02-13 00:06:29 +00001982 /* not bound in env */
1983 return ex;
sewardj62617ef2004-10-13 23:29:22 +00001984
1985 case Iex_Const:
1986 case Iex_Get:
sewardj84be7372004-08-18 13:59:33 +00001987 return ex;
sewardj62617ef2004-10-13 23:29:22 +00001988
1989 case Iex_GetI:
sewardj496a58d2005-03-20 18:44:44 +00001990 vassert(isIRAtom(ex->Iex.GetI.ix));
sewardj62617ef2004-10-13 23:29:22 +00001991 return IRExpr_GetI(
1992 ex->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +00001993 subst_Expr(env, ex->Iex.GetI.ix),
sewardj62617ef2004-10-13 23:29:22 +00001994 ex->Iex.GetI.bias
1995 );
1996
sewardj40c80262006-02-08 19:30:46 +00001997 case Iex_Qop:
1998 vassert(isIRAtom(ex->Iex.Qop.arg1));
1999 vassert(isIRAtom(ex->Iex.Qop.arg2));
2000 vassert(isIRAtom(ex->Iex.Qop.arg3));
2001 vassert(isIRAtom(ex->Iex.Qop.arg4));
2002 return IRExpr_Qop(
2003 ex->Iex.Qop.op,
2004 subst_Expr(env, ex->Iex.Qop.arg1),
2005 subst_Expr(env, ex->Iex.Qop.arg2),
2006 subst_Expr(env, ex->Iex.Qop.arg3),
2007 subst_Expr(env, ex->Iex.Qop.arg4)
2008 );
2009
sewardjb183b852006-02-03 16:08:03 +00002010 case Iex_Triop:
2011 vassert(isIRAtom(ex->Iex.Triop.arg1));
2012 vassert(isIRAtom(ex->Iex.Triop.arg2));
2013 vassert(isIRAtom(ex->Iex.Triop.arg3));
2014 return IRExpr_Triop(
2015 ex->Iex.Triop.op,
2016 subst_Expr(env, ex->Iex.Triop.arg1),
2017 subst_Expr(env, ex->Iex.Triop.arg2),
2018 subst_Expr(env, ex->Iex.Triop.arg3)
2019 );
2020
sewardj62617ef2004-10-13 23:29:22 +00002021 case Iex_Binop:
sewardj496a58d2005-03-20 18:44:44 +00002022 vassert(isIRAtom(ex->Iex.Binop.arg1));
2023 vassert(isIRAtom(ex->Iex.Binop.arg2));
sewardj62617ef2004-10-13 23:29:22 +00002024 return IRExpr_Binop(
2025 ex->Iex.Binop.op,
2026 subst_Expr(env, ex->Iex.Binop.arg1),
2027 subst_Expr(env, ex->Iex.Binop.arg2)
2028 );
2029
2030 case Iex_Unop:
sewardj496a58d2005-03-20 18:44:44 +00002031 vassert(isIRAtom(ex->Iex.Unop.arg));
sewardj62617ef2004-10-13 23:29:22 +00002032 return IRExpr_Unop(
2033 ex->Iex.Unop.op,
2034 subst_Expr(env, ex->Iex.Unop.arg)
2035 );
2036
sewardjaf1ceca2005-06-30 23:31:27 +00002037 case Iex_Load:
2038 vassert(isIRAtom(ex->Iex.Load.addr));
2039 return IRExpr_Load(
2040 ex->Iex.Load.end,
2041 ex->Iex.Load.ty,
2042 subst_Expr(env, ex->Iex.Load.addr)
sewardj62617ef2004-10-13 23:29:22 +00002043 );
2044
2045 case Iex_CCall: {
2046 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +00002047 IRExpr** args2 = shallowCopyIRExprVec(ex->Iex.CCall.args);
sewardj62617ef2004-10-13 23:29:22 +00002048 for (i = 0; args2[i]; i++) {
sewardj496a58d2005-03-20 18:44:44 +00002049 vassert(isIRAtom(args2[i]));
sewardj62617ef2004-10-13 23:29:22 +00002050 args2[i] = subst_Expr(env, args2[i]);
2051 }
2052 return IRExpr_CCall(
sewardj8ea867b2004-10-30 19:03:02 +00002053 ex->Iex.CCall.cee,
sewardj62617ef2004-10-13 23:29:22 +00002054 ex->Iex.CCall.retty,
2055 args2
2056 );
sewardj84be7372004-08-18 13:59:33 +00002057 }
sewardj62617ef2004-10-13 23:29:22 +00002058
2059 case Iex_Mux0X:
sewardj496a58d2005-03-20 18:44:44 +00002060 vassert(isIRAtom(ex->Iex.Mux0X.cond));
2061 vassert(isIRAtom(ex->Iex.Mux0X.expr0));
2062 vassert(isIRAtom(ex->Iex.Mux0X.exprX));
sewardj62617ef2004-10-13 23:29:22 +00002063 return IRExpr_Mux0X(
2064 subst_Expr(env, ex->Iex.Mux0X.cond),
2065 subst_Expr(env, ex->Iex.Mux0X.expr0),
2066 subst_Expr(env, ex->Iex.Mux0X.exprX)
2067 );
2068
2069 default:
2070 vex_printf("\n\n"); ppIRExpr(ex);
2071 vpanic("subst_Expr");
2072
sewardj84be7372004-08-18 13:59:33 +00002073 }
sewardj84be7372004-08-18 13:59:33 +00002074}
2075
2076
2077/* Apply the subst to stmt, then fold the result as much as possible.
sewardjd2445f62005-03-21 00:15:53 +00002078 Much simplified due to stmt being previously flattened. As a
2079 result of this, the stmt may wind up being turned into a no-op.
2080*/
sewardj62617ef2004-10-13 23:29:22 +00002081static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st )
sewardj84be7372004-08-18 13:59:33 +00002082{
2083# if 0
2084 vex_printf("\nsubst and fold stmt\n");
2085 ppIRStmt(st);
2086 vex_printf("\n");
2087# endif
2088
sewardj62617ef2004-10-13 23:29:22 +00002089 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00002090 case Ist_AbiHint:
2091 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +00002092 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +00002093 return IRStmt_AbiHint(
floriancdb5fee2012-02-13 00:06:29 +00002094 fold_Expr(env, subst_Expr(env, st->Ist.AbiHint.base)),
sewardj478646f2008-05-01 20:13:04 +00002095 st->Ist.AbiHint.len,
floriancdb5fee2012-02-13 00:06:29 +00002096 fold_Expr(env, subst_Expr(env, st->Ist.AbiHint.nia))
sewardj5a9ffab2005-05-12 17:55:01 +00002097 );
sewardj62617ef2004-10-13 23:29:22 +00002098 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00002099 vassert(isIRAtom(st->Ist.Put.data));
sewardj62617ef2004-10-13 23:29:22 +00002100 return IRStmt_Put(
2101 st->Ist.Put.offset,
floriancdb5fee2012-02-13 00:06:29 +00002102 fold_Expr(env, subst_Expr(env, st->Ist.Put.data))
sewardj62617ef2004-10-13 23:29:22 +00002103 );
sewardj84be7372004-08-18 13:59:33 +00002104
sewardj62617ef2004-10-13 23:29:22 +00002105 case Ist_PutI:
sewardj496a58d2005-03-20 18:44:44 +00002106 vassert(isIRAtom(st->Ist.PutI.ix));
2107 vassert(isIRAtom(st->Ist.PutI.data));
sewardj62617ef2004-10-13 23:29:22 +00002108 return IRStmt_PutI(
2109 st->Ist.PutI.descr,
floriancdb5fee2012-02-13 00:06:29 +00002110 fold_Expr(env, subst_Expr(env, st->Ist.PutI.ix)),
sewardj62617ef2004-10-13 23:29:22 +00002111 st->Ist.PutI.bias,
floriancdb5fee2012-02-13 00:06:29 +00002112 fold_Expr(env, subst_Expr(env, st->Ist.PutI.data))
sewardj62617ef2004-10-13 23:29:22 +00002113 );
sewardjd7217032004-08-19 10:49:10 +00002114
sewardjdd40fdf2006-12-24 02:20:24 +00002115 case Ist_WrTmp:
2116 /* This is the one place where an expr (st->Ist.WrTmp.data) is
sewardj62617ef2004-10-13 23:29:22 +00002117 allowed to be more than just a constant or a tmp. */
sewardjdd40fdf2006-12-24 02:20:24 +00002118 return IRStmt_WrTmp(
2119 st->Ist.WrTmp.tmp,
floriancdb5fee2012-02-13 00:06:29 +00002120 fold_Expr(env, subst_Expr(env, st->Ist.WrTmp.data))
sewardj62617ef2004-10-13 23:29:22 +00002121 );
sewardj84be7372004-08-18 13:59:33 +00002122
sewardjaf1ceca2005-06-30 23:31:27 +00002123 case Ist_Store:
2124 vassert(isIRAtom(st->Ist.Store.addr));
2125 vassert(isIRAtom(st->Ist.Store.data));
2126 return IRStmt_Store(
2127 st->Ist.Store.end,
floriancdb5fee2012-02-13 00:06:29 +00002128 fold_Expr(env, subst_Expr(env, st->Ist.Store.addr)),
2129 fold_Expr(env, subst_Expr(env, st->Ist.Store.data))
sewardj62617ef2004-10-13 23:29:22 +00002130 );
sewardj84be7372004-08-18 13:59:33 +00002131
sewardje9d8a262009-07-01 08:06:34 +00002132 case Ist_CAS: {
2133 IRCAS *cas, *cas2;
2134 cas = st->Ist.CAS.details;
2135 vassert(isIRAtom(cas->addr));
2136 vassert(cas->expdHi == NULL || isIRAtom(cas->expdHi));
2137 vassert(isIRAtom(cas->expdLo));
2138 vassert(cas->dataHi == NULL || isIRAtom(cas->dataHi));
2139 vassert(isIRAtom(cas->dataLo));
2140 cas2 = mkIRCAS(
2141 cas->oldHi, cas->oldLo, cas->end,
floriancdb5fee2012-02-13 00:06:29 +00002142 fold_Expr(env, subst_Expr(env, cas->addr)),
2143 cas->expdHi ? fold_Expr(env, subst_Expr(env, cas->expdHi)) : NULL,
2144 fold_Expr(env, subst_Expr(env, cas->expdLo)),
2145 cas->dataHi ? fold_Expr(env, subst_Expr(env, cas->dataHi)) : NULL,
2146 fold_Expr(env, subst_Expr(env, cas->dataLo))
sewardje9d8a262009-07-01 08:06:34 +00002147 );
2148 return IRStmt_CAS(cas2);
2149 }
2150
sewardje768e922009-11-26 17:17:37 +00002151 case Ist_LLSC:
2152 vassert(isIRAtom(st->Ist.LLSC.addr));
2153 if (st->Ist.LLSC.storedata)
2154 vassert(isIRAtom(st->Ist.LLSC.storedata));
2155 return IRStmt_LLSC(
2156 st->Ist.LLSC.end,
2157 st->Ist.LLSC.result,
floriancdb5fee2012-02-13 00:06:29 +00002158 fold_Expr(env, subst_Expr(env, st->Ist.LLSC.addr)),
sewardje768e922009-11-26 17:17:37 +00002159 st->Ist.LLSC.storedata
floriancdb5fee2012-02-13 00:06:29 +00002160 ? fold_Expr(env, subst_Expr(env, st->Ist.LLSC.storedata))
sewardje768e922009-11-26 17:17:37 +00002161 : NULL
2162 );
2163
sewardj62617ef2004-10-13 23:29:22 +00002164 case Ist_Dirty: {
2165 Int i;
2166 IRDirty *d, *d2;
2167 d = st->Ist.Dirty.details;
2168 d2 = emptyIRDirty();
2169 *d2 = *d;
sewardjdd40fdf2006-12-24 02:20:24 +00002170 d2->args = shallowCopyIRExprVec(d2->args);
sewardj62617ef2004-10-13 23:29:22 +00002171 if (d2->mFx != Ifx_None) {
sewardj496a58d2005-03-20 18:44:44 +00002172 vassert(isIRAtom(d2->mAddr));
floriancdb5fee2012-02-13 00:06:29 +00002173 d2->mAddr = fold_Expr(env, subst_Expr(env, d2->mAddr));
sewardjb8e75862004-08-19 17:58:45 +00002174 }
sewardj496a58d2005-03-20 18:44:44 +00002175 vassert(isIRAtom(d2->guard));
floriancdb5fee2012-02-13 00:06:29 +00002176 d2->guard = fold_Expr(env, subst_Expr(env, d2->guard));
sewardj62617ef2004-10-13 23:29:22 +00002177 for (i = 0; d2->args[i]; i++) {
sewardj496a58d2005-03-20 18:44:44 +00002178 vassert(isIRAtom(d2->args[i]));
floriancdb5fee2012-02-13 00:06:29 +00002179 d2->args[i] = fold_Expr(env, subst_Expr(env, d2->args[i]));
sewardj62617ef2004-10-13 23:29:22 +00002180 }
2181 return IRStmt_Dirty(d2);
sewardjb8e75862004-08-19 17:58:45 +00002182 }
sewardj84be7372004-08-18 13:59:33 +00002183
sewardjf1689312005-03-16 18:19:10 +00002184 case Ist_IMark:
sewardj2f10aa62011-05-27 13:20:56 +00002185 return IRStmt_IMark(st->Ist.IMark.addr,
2186 st->Ist.IMark.len,
2187 st->Ist.IMark.delta);
sewardjf1689312005-03-16 18:19:10 +00002188
sewardjd2445f62005-03-21 00:15:53 +00002189 case Ist_NoOp:
2190 return IRStmt_NoOp();
2191
sewardjc4356f02007-11-09 21:15:04 +00002192 case Ist_MBE:
2193 return IRStmt_MBE(st->Ist.MBE.event);
sewardj3e838932005-01-07 12:09:15 +00002194
sewardj62617ef2004-10-13 23:29:22 +00002195 case Ist_Exit: {
2196 IRExpr* fcond;
sewardj496a58d2005-03-20 18:44:44 +00002197 vassert(isIRAtom(st->Ist.Exit.guard));
floriancdb5fee2012-02-13 00:06:29 +00002198 fcond = fold_Expr(env, subst_Expr(env, st->Ist.Exit.guard));
sewardj62617ef2004-10-13 23:29:22 +00002199 if (fcond->tag == Iex_Const) {
2200 /* Interesting. The condition on this exit has folded down to
2201 a constant. */
sewardjba999312004-11-15 15:21:17 +00002202 vassert(fcond->Iex.Const.con->tag == Ico_U1);
sewardj98430292004-12-29 17:34:50 +00002203 vassert(fcond->Iex.Const.con->Ico.U1 == False
2204 || fcond->Iex.Const.con->Ico.U1 == True);
sewardjba999312004-11-15 15:21:17 +00002205 if (fcond->Iex.Const.con->Ico.U1 == False) {
sewardj62617ef2004-10-13 23:29:22 +00002206 /* exit is never going to happen, so dump the statement. */
sewardjd2445f62005-03-21 00:15:53 +00002207 return IRStmt_NoOp();
sewardj62617ef2004-10-13 23:29:22 +00002208 } else {
sewardjba999312004-11-15 15:21:17 +00002209 vassert(fcond->Iex.Const.con->Ico.U1 == True);
sewardje810c192005-09-09 08:33:03 +00002210 /* Hmmm. The exit has become unconditional. Leave it
2211 as it is for now, since we'd have to truncate the BB
2212 at this point, which is tricky. Such truncation is
2213 done later by the dead-code elimination pass. */
sewardj62617ef2004-10-13 23:29:22 +00002214 /* fall out into the reconstruct-the-exit code. */
sewardj08613742004-10-25 13:01:45 +00002215 if (vex_control.iropt_verbosity > 0)
2216 /* really a misuse of vex_control.iropt_verbosity */
sewardj8c2c10b2004-10-16 20:51:52 +00002217 vex_printf("vex iropt: IRStmt_Exit became unconditional\n");
sewardj62617ef2004-10-13 23:29:22 +00002218 }
2219 }
sewardj893aada2004-11-29 19:57:54 +00002220 return IRStmt_Exit(fcond, st->Ist.Exit.jk, st->Ist.Exit.dst);
sewardj62617ef2004-10-13 23:29:22 +00002221 }
2222
2223 default:
2224 vex_printf("\n"); ppIRStmt(st);
2225 vpanic("subst_and_fold_Stmt");
2226 }
sewardj84be7372004-08-18 13:59:33 +00002227}
2228
2229
sewardjdd40fdf2006-12-24 02:20:24 +00002230IRSB* cprop_BB ( IRSB* in )
sewardj84be7372004-08-18 13:59:33 +00002231{
sewardj62617ef2004-10-13 23:29:22 +00002232 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +00002233 IRSB* out;
sewardj62617ef2004-10-13 23:29:22 +00002234 IRStmt* st2;
2235 Int n_tmps = in->tyenv->types_used;
2236 IRExpr** env = LibVEX_Alloc(n_tmps * sizeof(IRExpr*));
sewardj84be7372004-08-18 13:59:33 +00002237
sewardjdd40fdf2006-12-24 02:20:24 +00002238 out = emptyIRSB();
2239 out->tyenv = deepCopyIRTypeEnv( in->tyenv );
sewardj84be7372004-08-18 13:59:33 +00002240
2241 /* Set up the env with which travels forward. This holds a
floriancdb5fee2012-02-13 00:06:29 +00002242 substitution, mapping IRTemps to IRExprs. The environment
2243 is to be applied as we move along. Keys are IRTemps.
2244 Values are IRExpr*s.
sewardj84be7372004-08-18 13:59:33 +00002245 */
sewardj62617ef2004-10-13 23:29:22 +00002246 for (i = 0; i < n_tmps; i++)
2247 env[i] = NULL;
sewardj84be7372004-08-18 13:59:33 +00002248
2249 /* For each original SSA-form stmt ... */
2250 for (i = 0; i < in->stmts_used; i++) {
2251
2252 /* First apply the substitution to the current stmt. This
2253 propagates in any constants and tmp-tmp assignments
2254 accumulated prior to this point. As part of the subst_Stmt
2255 call, also then fold any constant expressions resulting. */
2256
sewardjf0e43162004-08-20 00:11:12 +00002257 st2 = in->stmts[i];
2258
2259 /* perhaps st2 is already a no-op? */
sewardj8bee6d12005-03-22 02:24:05 +00002260 if (st2->tag == Ist_NoOp) continue;
sewardjf0e43162004-08-20 00:11:12 +00002261
2262 st2 = subst_and_fold_Stmt( env, st2 );
sewardj84be7372004-08-18 13:59:33 +00002263
sewardjb8e75862004-08-19 17:58:45 +00002264 /* If the statement has been folded into a no-op, forget it. */
sewardj8bee6d12005-03-22 02:24:05 +00002265 if (st2->tag == Ist_NoOp) continue;
sewardjb8e75862004-08-19 17:58:45 +00002266
floriancdb5fee2012-02-13 00:06:29 +00002267 /* If the statement assigns to an IRTemp add it to the running
2268 environment. This is for the benefit of copy propagation
2269 and to allow sameIRExpr look through IRTemps. */
2270 if (st2->tag == Ist_WrTmp) {
2271 vassert(env[(Int)(st2->Ist.WrTmp.tmp)] == NULL);
2272 env[(Int)(st2->Ist.WrTmp.tmp)] = st2->Ist.WrTmp.data;
sewardj84be7372004-08-18 13:59:33 +00002273
floriancdb5fee2012-02-13 00:06:29 +00002274 /* 't1 = t2' -- don't add to BB; will be optimized out */
2275 if (st2->Ist.WrTmp.data->tag == Iex_RdTmp) continue;
2276
2277 /* 't = const' && 'const != F64i' -- don't add to BB
2278 Note, we choose not to propagate const when const is an
2279 F64i, so that F64i literals can be CSE'd later. This helps
2280 x86 floating point code generation. */
2281 if (st2->Ist.WrTmp.data->tag == Iex_Const
2282 && st2->Ist.WrTmp.data->Iex.Const.con->tag != Ico_F64i) continue;
sewardj84be7372004-08-18 13:59:33 +00002283 }
floriancdb5fee2012-02-13 00:06:29 +00002284
2285 /* Not interesting, copy st2 into the output block. */
2286 addStmtToIRSB( out, st2 );
sewardj84be7372004-08-18 13:59:33 +00002287 }
2288
floriancdb5fee2012-02-13 00:06:29 +00002289#if STATS_IROPT
2290 vex_printf("sameIRExpr: invoked = %u/%u equal = %u/%u max_nodes = %u\n",
2291 invocation_count, recursion_count, success_count,
2292 recursion_success_count, max_nodes_visited);
2293#endif
2294
sewardj84be7372004-08-18 13:59:33 +00002295 out->next = subst_Expr( env, in->next );
2296 out->jumpkind = in->jumpkind;
2297 return out;
2298}
2299
2300
sewardjedf4d692004-08-17 13:52:58 +00002301/*---------------------------------------------------------------*/
sewardj39e3f242004-08-18 16:54:52 +00002302/*--- Dead code (t = E) removal ---*/
2303/*---------------------------------------------------------------*/
2304
sewardje810c192005-09-09 08:33:03 +00002305/* As a side effect, also removes all code following an unconditional
2306 side exit. */
2307
sewardjea602bc2004-10-14 21:40:12 +00002308/* The type of the HashHW map is: a map from IRTemp to nothing
sewardj39e3f242004-08-18 16:54:52 +00002309 -- really just operating a set or IRTemps.
2310*/
2311
sewardjd503a322004-10-13 22:41:16 +00002312inline
2313static void addUses_Temp ( Bool* set, IRTemp tmp )
sewardj17442fe2004-09-20 14:54:28 +00002314{
sewardjd503a322004-10-13 22:41:16 +00002315 set[(Int)tmp] = True;
sewardj17442fe2004-09-20 14:54:28 +00002316}
2317
sewardjd503a322004-10-13 22:41:16 +00002318static void addUses_Expr ( Bool* set, IRExpr* e )
sewardj39e3f242004-08-18 16:54:52 +00002319{
2320 Int i;
2321 switch (e->tag) {
sewardjd7217032004-08-19 10:49:10 +00002322 case Iex_GetI:
sewardjeeac8412004-11-02 00:26:55 +00002323 addUses_Expr(set, e->Iex.GetI.ix);
sewardjd7217032004-08-19 10:49:10 +00002324 return;
sewardj39e3f242004-08-18 16:54:52 +00002325 case Iex_Mux0X:
2326 addUses_Expr(set, e->Iex.Mux0X.cond);
2327 addUses_Expr(set, e->Iex.Mux0X.expr0);
2328 addUses_Expr(set, e->Iex.Mux0X.exprX);
2329 return;
2330 case Iex_CCall:
2331 for (i = 0; e->Iex.CCall.args[i]; i++)
2332 addUses_Expr(set, e->Iex.CCall.args[i]);
2333 return;
sewardjaf1ceca2005-06-30 23:31:27 +00002334 case Iex_Load:
2335 addUses_Expr(set, e->Iex.Load.addr);
sewardj39e3f242004-08-18 16:54:52 +00002336 return;
sewardj40c80262006-02-08 19:30:46 +00002337 case Iex_Qop:
2338 addUses_Expr(set, e->Iex.Qop.arg1);
2339 addUses_Expr(set, e->Iex.Qop.arg2);
2340 addUses_Expr(set, e->Iex.Qop.arg3);
2341 addUses_Expr(set, e->Iex.Qop.arg4);
2342 return;
sewardjb183b852006-02-03 16:08:03 +00002343 case Iex_Triop:
2344 addUses_Expr(set, e->Iex.Triop.arg1);
2345 addUses_Expr(set, e->Iex.Triop.arg2);
2346 addUses_Expr(set, e->Iex.Triop.arg3);
2347 return;
sewardj39e3f242004-08-18 16:54:52 +00002348 case Iex_Binop:
2349 addUses_Expr(set, e->Iex.Binop.arg1);
2350 addUses_Expr(set, e->Iex.Binop.arg2);
2351 return;
2352 case Iex_Unop:
2353 addUses_Expr(set, e->Iex.Unop.arg);
2354 return;
sewardjdd40fdf2006-12-24 02:20:24 +00002355 case Iex_RdTmp:
2356 addUses_Temp(set, e->Iex.RdTmp.tmp);
sewardj39e3f242004-08-18 16:54:52 +00002357 return;
2358 case Iex_Const:
2359 case Iex_Get:
2360 return;
2361 default:
2362 vex_printf("\n");
2363 ppIRExpr(e);
2364 vpanic("addUses_Expr");
2365 }
2366}
2367
sewardjd503a322004-10-13 22:41:16 +00002368static void addUses_Stmt ( Bool* set, IRStmt* st )
sewardj39e3f242004-08-18 16:54:52 +00002369{
sewardj17442fe2004-09-20 14:54:28 +00002370 Int i;
2371 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00002372 IRCAS* cas;
sewardj39e3f242004-08-18 16:54:52 +00002373 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00002374 case Ist_AbiHint:
2375 addUses_Expr(set, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +00002376 addUses_Expr(set, st->Ist.AbiHint.nia);
sewardj5a9ffab2005-05-12 17:55:01 +00002377 return;
sewardjd7217032004-08-19 10:49:10 +00002378 case Ist_PutI:
sewardjeeac8412004-11-02 00:26:55 +00002379 addUses_Expr(set, st->Ist.PutI.ix);
sewardj2d3f77c2004-09-22 23:49:09 +00002380 addUses_Expr(set, st->Ist.PutI.data);
sewardjd7217032004-08-19 10:49:10 +00002381 return;
sewardjdd40fdf2006-12-24 02:20:24 +00002382 case Ist_WrTmp:
2383 addUses_Expr(set, st->Ist.WrTmp.data);
sewardj39e3f242004-08-18 16:54:52 +00002384 return;
2385 case Ist_Put:
sewardj6d076362004-09-23 11:06:17 +00002386 addUses_Expr(set, st->Ist.Put.data);
sewardj39e3f242004-08-18 16:54:52 +00002387 return;
sewardjaf1ceca2005-06-30 23:31:27 +00002388 case Ist_Store:
2389 addUses_Expr(set, st->Ist.Store.addr);
2390 addUses_Expr(set, st->Ist.Store.data);
sewardj39e3f242004-08-18 16:54:52 +00002391 return;
sewardje9d8a262009-07-01 08:06:34 +00002392 case Ist_CAS:
2393 cas = st->Ist.CAS.details;
2394 addUses_Expr(set, cas->addr);
2395 if (cas->expdHi)
2396 addUses_Expr(set, cas->expdHi);
2397 addUses_Expr(set, cas->expdLo);
2398 if (cas->dataHi)
2399 addUses_Expr(set, cas->dataHi);
2400 addUses_Expr(set, cas->dataLo);
2401 return;
sewardje768e922009-11-26 17:17:37 +00002402 case Ist_LLSC:
2403 addUses_Expr(set, st->Ist.LLSC.addr);
2404 if (st->Ist.LLSC.storedata)
2405 addUses_Expr(set, st->Ist.LLSC.storedata);
2406 return;
sewardj17442fe2004-09-20 14:54:28 +00002407 case Ist_Dirty:
2408 d = st->Ist.Dirty.details;
2409 if (d->mFx != Ifx_None)
2410 addUses_Expr(set, d->mAddr);
sewardjb8385d82004-11-02 01:34:15 +00002411 addUses_Expr(set, d->guard);
sewardj17442fe2004-09-20 14:54:28 +00002412 for (i = 0; d->args[i] != NULL; i++)
2413 addUses_Expr(set, d->args[i]);
2414 return;
sewardjd2445f62005-03-21 00:15:53 +00002415 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00002416 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00002417 case Ist_MBE:
sewardj3e838932005-01-07 12:09:15 +00002418 return;
sewardj17442fe2004-09-20 14:54:28 +00002419 case Ist_Exit:
sewardj0276d4b2004-11-15 15:30:21 +00002420 addUses_Expr(set, st->Ist.Exit.guard);
sewardj17442fe2004-09-20 14:54:28 +00002421 return;
sewardj39e3f242004-08-18 16:54:52 +00002422 default:
2423 vex_printf("\n");
2424 ppIRStmt(st);
2425 vpanic("addUses_Stmt");
sewardjd503a322004-10-13 22:41:16 +00002426 }
sewardj39e3f242004-08-18 16:54:52 +00002427}
2428
2429
sewardjba999312004-11-15 15:21:17 +00002430/* Is this literally IRExpr_Const(IRConst_U1(False)) ? */
2431static Bool isZeroU1 ( IRExpr* e )
sewardjd9997882004-11-04 19:42:59 +00002432{
sewardj9d2e7692005-02-07 01:11:31 +00002433 return toBool( e->tag == Iex_Const
2434 && e->Iex.Const.con->tag == Ico_U1
2435 && e->Iex.Const.con->Ico.U1 == False );
sewardjd9997882004-11-04 19:42:59 +00002436}
2437
sewardje810c192005-09-09 08:33:03 +00002438/* Is this literally IRExpr_Const(IRConst_U1(True)) ? */
2439static Bool isOneU1 ( IRExpr* e )
2440{
2441 return toBool( e->tag == Iex_Const
2442 && e->Iex.Const.con->tag == Ico_U1
2443 && e->Iex.Const.con->Ico.U1 == True );
2444}
2445
sewardj39e3f242004-08-18 16:54:52 +00002446
sewardjdd40fdf2006-12-24 02:20:24 +00002447/* Note, this destructively modifies the given IRSB. */
sewardj39e3f242004-08-18 16:54:52 +00002448
2449/* Scan backwards through statements, carrying a set of IRTemps which
2450 are known to be used after the current point. On encountering 't =
2451 E', delete the binding if it is not used. Otherwise, add any temp
sewardje810c192005-09-09 08:33:03 +00002452 uses to the set and keep on moving backwards.
2453
2454 As an enhancement, the first (backwards) pass searches for IR exits
2455 with always-taken conditions and notes the location of the earliest
2456 one in the block. If any such are found, a second pass copies the
2457 exit destination and jump kind to the bb-end. Then, the exit and
2458 all statements following it are turned into no-ops.
2459*/
sewardj39e3f242004-08-18 16:54:52 +00002460
sewardjdd40fdf2006-12-24 02:20:24 +00002461/* notstatic */ void do_deadcode_BB ( IRSB* bb )
sewardj39e3f242004-08-18 16:54:52 +00002462{
sewardje810c192005-09-09 08:33:03 +00002463 Int i, i_unconditional_exit;
sewardjd503a322004-10-13 22:41:16 +00002464 Int n_tmps = bb->tyenv->types_used;
2465 Bool* set = LibVEX_Alloc(n_tmps * sizeof(Bool));
sewardj39e3f242004-08-18 16:54:52 +00002466 IRStmt* st;
2467
sewardjd503a322004-10-13 22:41:16 +00002468 for (i = 0; i < n_tmps; i++)
2469 set[i] = False;
2470
sewardj39e3f242004-08-18 16:54:52 +00002471 /* start off by recording IRTemp uses in the next field. */
2472 addUses_Expr(set, bb->next);
2473
sewardje810c192005-09-09 08:33:03 +00002474 /* First pass */
2475
sewardj39e3f242004-08-18 16:54:52 +00002476 /* Work backwards through the stmts */
sewardje810c192005-09-09 08:33:03 +00002477 i_unconditional_exit = -1;
sewardj39e3f242004-08-18 16:54:52 +00002478 for (i = bb->stmts_used-1; i >= 0; i--) {
2479 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00002480 if (st->tag == Ist_NoOp)
sewardj84ff0652004-08-23 16:16:08 +00002481 continue;
sewardje810c192005-09-09 08:33:03 +00002482 /* take note of any unconditional exits */
2483 if (st->tag == Ist_Exit
2484 && isOneU1(st->Ist.Exit.guard))
2485 i_unconditional_exit = i;
sewardjdd40fdf2006-12-24 02:20:24 +00002486 if (st->tag == Ist_WrTmp
2487 && set[(Int)(st->Ist.WrTmp.tmp)] == False) {
sewardj39e3f242004-08-18 16:54:52 +00002488 /* it's an IRTemp which never got used. Delete it. */
sewardj088bcb42004-08-19 17:16:52 +00002489 if (DEBUG_IROPT) {
sewardj39e3f242004-08-18 16:54:52 +00002490 vex_printf("DEAD: ");
2491 ppIRStmt(st);
2492 vex_printf("\n");
2493 }
sewardjd2445f62005-03-21 00:15:53 +00002494 bb->stmts[i] = IRStmt_NoOp();
sewardjd9997882004-11-04 19:42:59 +00002495 }
2496 else
2497 if (st->tag == Ist_Dirty
2498 && st->Ist.Dirty.details->guard
sewardjba999312004-11-15 15:21:17 +00002499 && isZeroU1(st->Ist.Dirty.details->guard)) {
sewardjd2445f62005-03-21 00:15:53 +00002500 /* This is a dirty helper which will never get called.
2501 Delete it. */
2502 bb->stmts[i] = IRStmt_NoOp();
sewardjd9997882004-11-04 19:42:59 +00002503 }
2504 else {
sewardj39e3f242004-08-18 16:54:52 +00002505 /* Note any IRTemp uses made by the current statement. */
2506 addUses_Stmt(set, st);
2507 }
2508 }
sewardje810c192005-09-09 08:33:03 +00002509
2510 /* Optional second pass: if any unconditional exits were found,
2511 delete them and all following statements. */
2512
2513 if (i_unconditional_exit != -1) {
2514 if (0) vex_printf("ZAPPING ALL FORWARDS from %d\n",
2515 i_unconditional_exit);
2516 vassert(i_unconditional_exit >= 0
2517 && i_unconditional_exit < bb->stmts_used);
2518 bb->next
2519 = IRExpr_Const( bb->stmts[i_unconditional_exit]->Ist.Exit.dst );
2520 bb->jumpkind
2521 = bb->stmts[i_unconditional_exit]->Ist.Exit.jk;
2522 for (i = i_unconditional_exit; i < bb->stmts_used; i++)
2523 bb->stmts[i] = IRStmt_NoOp();
2524 }
sewardj39e3f242004-08-18 16:54:52 +00002525}
2526
sewardje810c192005-09-09 08:33:03 +00002527
sewardj84ff0652004-08-23 16:16:08 +00002528/*---------------------------------------------------------------*/
2529/*--- Specialisation of helper function calls, in ---*/
2530/*--- collaboration with the front end ---*/
2531/*---------------------------------------------------------------*/
2532
2533static
sewardjbe917912010-08-22 12:38:53 +00002534IRSB* spec_helpers_BB(
2535 IRSB* bb,
2536 IRExpr* (*specHelper) (HChar*, IRExpr**, IRStmt**, Int)
2537 )
sewardj84ff0652004-08-23 16:16:08 +00002538{
sewardjb9230752004-12-29 19:25:06 +00002539 Int i;
sewardj84ff0652004-08-23 16:16:08 +00002540 IRStmt* st;
2541 IRExpr* ex;
sewardjb9230752004-12-29 19:25:06 +00002542 Bool any = False;
sewardj84ff0652004-08-23 16:16:08 +00002543
2544 for (i = bb->stmts_used-1; i >= 0; i--) {
2545 st = bb->stmts[i];
2546
sewardjdd40fdf2006-12-24 02:20:24 +00002547 if (st->tag != Ist_WrTmp
2548 || st->Ist.WrTmp.data->tag != Iex_CCall)
sewardj8bee6d12005-03-22 02:24:05 +00002549 continue;
sewardj84ff0652004-08-23 16:16:08 +00002550
sewardjdd40fdf2006-12-24 02:20:24 +00002551 ex = (*specHelper)( st->Ist.WrTmp.data->Iex.CCall.cee->name,
sewardjbe917912010-08-22 12:38:53 +00002552 st->Ist.WrTmp.data->Iex.CCall.args,
2553 &bb->stmts[0], i );
sewardj84ff0652004-08-23 16:16:08 +00002554 if (!ex)
sewardjaba4fff2004-10-08 21:37:15 +00002555 /* the front end can't think of a suitable replacement */
2556 continue;
sewardj84ff0652004-08-23 16:16:08 +00002557
2558 /* We got something better. Install it in the bb. */
sewardjb9230752004-12-29 19:25:06 +00002559 any = True;
sewardj84ff0652004-08-23 16:16:08 +00002560 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00002561 = IRStmt_WrTmp(st->Ist.WrTmp.tmp, ex);
sewardj84ff0652004-08-23 16:16:08 +00002562
2563 if (0) {
2564 vex_printf("SPEC: ");
sewardjdd40fdf2006-12-24 02:20:24 +00002565 ppIRExpr(st->Ist.WrTmp.data);
sewardj84ff0652004-08-23 16:16:08 +00002566 vex_printf(" --> ");
2567 ppIRExpr(ex);
2568 vex_printf("\n");
2569 }
2570 }
sewardjb9230752004-12-29 19:25:06 +00002571
2572 if (any)
2573 bb = flatten_BB(bb);
2574 return bb;
sewardj84ff0652004-08-23 16:16:08 +00002575}
2576
sewardj29632392004-08-22 02:38:11 +00002577
2578/*---------------------------------------------------------------*/
sewardj9b0cc582006-02-04 15:24:00 +00002579/*--- Determination of guest state aliasing relationships ---*/
2580/*---------------------------------------------------------------*/
2581
2582/* These are helper functions for CSE and GetI/PutI transformations.
2583
2584 Determine, to the extent possible, the relationship between two
2585 guest state accesses. The possible outcomes are:
2586
2587 * Exact alias. These two accesses denote precisely the same
2588 piece of the guest state.
2589
2590 * Definitely no alias. These two accesses are guaranteed not to
2591 overlap any part of the guest state.
2592
2593 * Unknown -- if neither of the above can be established.
2594
2595 If in doubt, return Unknown. */
2596
2597typedef
2598 enum { ExactAlias, NoAlias, UnknownAlias }
2599 GSAliasing;
2600
2601
2602/* Produces the alias relation between an indexed guest
2603 state access and a non-indexed access. */
2604
2605static
sewardjdd40fdf2006-12-24 02:20:24 +00002606GSAliasing getAliasingRelation_IC ( IRRegArray* descr1, IRExpr* ix1,
sewardj9b0cc582006-02-04 15:24:00 +00002607 Int offset2, IRType ty2 )
2608{
2609 UInt minoff1, maxoff1, minoff2, maxoff2;
2610
2611 getArrayBounds( descr1, &minoff1, &maxoff1 );
2612 minoff2 = offset2;
2613 maxoff2 = minoff2 + sizeofIRType(ty2) - 1;
2614
2615 if (maxoff1 < minoff2 || maxoff2 < minoff1)
2616 return NoAlias;
2617
2618 /* Could probably do better here if required. For the moment
2619 however just claim not to know anything more. */
2620 return UnknownAlias;
2621}
2622
2623
2624/* Produces the alias relation between two indexed guest state
2625 accesses. */
2626
2627static
2628GSAliasing getAliasingRelation_II (
sewardjdd40fdf2006-12-24 02:20:24 +00002629 IRRegArray* descr1, IRExpr* ix1, Int bias1,
2630 IRRegArray* descr2, IRExpr* ix2, Int bias2
sewardj9b0cc582006-02-04 15:24:00 +00002631 )
2632{
2633 UInt minoff1, maxoff1, minoff2, maxoff2;
2634 Int iters;
2635
2636 /* First try hard to show they don't alias. */
2637 getArrayBounds( descr1, &minoff1, &maxoff1 );
2638 getArrayBounds( descr2, &minoff2, &maxoff2 );
2639 if (maxoff1 < minoff2 || maxoff2 < minoff1)
2640 return NoAlias;
2641
2642 /* So the two arrays at least partially overlap. To get any
2643 further we'll have to be sure that the descriptors are
2644 identical. */
sewardjdd40fdf2006-12-24 02:20:24 +00002645 if (!eqIRRegArray(descr1, descr2))
sewardj9b0cc582006-02-04 15:24:00 +00002646 return UnknownAlias;
2647
2648 /* The descriptors are identical. Now the only difference can be
2649 in the index expressions. If they cannot be shown to be
2650 identical, we have to say we don't know what the aliasing
2651 relation will be. Now, since the IR is flattened, the index
2652 expressions should be atoms -- either consts or tmps. So that
2653 makes the comparison simple. */
2654 vassert(isIRAtom(ix1));
2655 vassert(isIRAtom(ix2));
2656 if (!eqIRAtom(ix1,ix2))
2657 return UnknownAlias;
2658
2659 /* Ok, the index expressions are identical. So now the only way
2660 they can be different is in the bias. Normalise this
2661 paranoidly, to reliably establish equality/non-equality. */
2662
2663 /* So now we know that the GetI and PutI index the same array
2664 with the same base. Are the offsets the same, modulo the
2665 array size? Do this paranoidly. */
2666 vassert(descr1->nElems == descr2->nElems);
2667 vassert(descr1->elemTy == descr2->elemTy);
2668 vassert(descr1->base == descr2->base);
2669 iters = 0;
2670 while (bias1 < 0 || bias2 < 0) {
2671 bias1 += descr1->nElems;
2672 bias2 += descr1->nElems;
2673 iters++;
2674 if (iters > 10)
2675 vpanic("getAliasingRelation: iters");
2676 }
2677 vassert(bias1 >= 0 && bias2 >= 0);
2678 bias1 %= descr1->nElems;
2679 bias2 %= descr1->nElems;
2680 vassert(bias1 >= 0 && bias1 < descr1->nElems);
2681 vassert(bias2 >= 0 && bias2 < descr1->nElems);
2682
2683 /* Finally, biasP and biasG are normalised into the range
2684 0 .. descrP/G->nElems - 1. And so we can establish
2685 equality/non-equality. */
2686
2687 return bias1==bias2 ? ExactAlias : NoAlias;
2688}
2689
2690
2691/*---------------------------------------------------------------*/
sewardj08210532004-12-29 17:09:11 +00002692/*--- Common Subexpression Elimination ---*/
2693/*---------------------------------------------------------------*/
2694
2695/* Expensive in time and space. */
2696
2697/* Uses two environments:
2698 a IRTemp -> IRTemp mapping
2699 a mapping from AvailExpr* to IRTemp
2700*/
2701
2702typedef
2703 struct {
sewardj9b0cc582006-02-04 15:24:00 +00002704 enum { Ut, Btt, Btc, Bct, Cf64i, Mttt, GetIt } tag;
sewardj08210532004-12-29 17:09:11 +00002705 union {
2706 /* unop(tmp) */
2707 struct {
2708 IROp op;
2709 IRTemp arg;
2710 } Ut;
2711 /* binop(tmp,tmp) */
2712 struct {
2713 IROp op;
2714 IRTemp arg1;
2715 IRTemp arg2;
2716 } Btt;
2717 /* binop(tmp,const) */
2718 struct {
2719 IROp op;
2720 IRTemp arg1;
2721 IRConst con2;
2722 } Btc;
2723 /* binop(const,tmp) */
2724 struct {
2725 IROp op;
2726 IRConst con1;
2727 IRTemp arg2;
2728 } Bct;
2729 /* F64i-style const */
2730 struct {
2731 ULong f64i;
2732 } Cf64i;
sewardj9b0cc582006-02-04 15:24:00 +00002733 /* Mux0X(tmp,tmp,tmp) */
2734 struct {
2735 IRTemp co;
2736 IRTemp e0;
2737 IRTemp eX;
2738 } Mttt;
2739 /* GetI(descr,tmp,bias)*/
2740 struct {
sewardjdd40fdf2006-12-24 02:20:24 +00002741 IRRegArray* descr;
2742 IRTemp ix;
2743 Int bias;
sewardj9b0cc582006-02-04 15:24:00 +00002744 } GetIt;
sewardj08210532004-12-29 17:09:11 +00002745 } u;
2746 }
2747 AvailExpr;
2748
2749static Bool eq_AvailExpr ( AvailExpr* a1, AvailExpr* a2 )
2750{
2751 if (a1->tag != a2->tag)
2752 return False;
2753 switch (a1->tag) {
2754 case Ut:
sewardj9d2e7692005-02-07 01:11:31 +00002755 return toBool(
2756 a1->u.Ut.op == a2->u.Ut.op
2757 && a1->u.Ut.arg == a2->u.Ut.arg);
sewardj08210532004-12-29 17:09:11 +00002758 case Btt:
sewardj9d2e7692005-02-07 01:11:31 +00002759 return toBool(
2760 a1->u.Btt.op == a2->u.Btt.op
sewardj08210532004-12-29 17:09:11 +00002761 && a1->u.Btt.arg1 == a2->u.Btt.arg1
sewardj9d2e7692005-02-07 01:11:31 +00002762 && a1->u.Btt.arg2 == a2->u.Btt.arg2);
sewardj08210532004-12-29 17:09:11 +00002763 case Btc:
sewardj9d2e7692005-02-07 01:11:31 +00002764 return toBool(
2765 a1->u.Btc.op == a2->u.Btc.op
sewardj08210532004-12-29 17:09:11 +00002766 && a1->u.Btc.arg1 == a2->u.Btc.arg1
sewardj9d2e7692005-02-07 01:11:31 +00002767 && eqIRConst(&a1->u.Btc.con2, &a2->u.Btc.con2));
sewardj08210532004-12-29 17:09:11 +00002768 case Bct:
sewardj9d2e7692005-02-07 01:11:31 +00002769 return toBool(
2770 a1->u.Bct.op == a2->u.Bct.op
sewardj08210532004-12-29 17:09:11 +00002771 && a1->u.Bct.arg2 == a2->u.Bct.arg2
sewardj9d2e7692005-02-07 01:11:31 +00002772 && eqIRConst(&a1->u.Bct.con1, &a2->u.Bct.con1));
sewardj08210532004-12-29 17:09:11 +00002773 case Cf64i:
sewardj9d2e7692005-02-07 01:11:31 +00002774 return toBool(a1->u.Cf64i.f64i == a2->u.Cf64i.f64i);
sewardj9b0cc582006-02-04 15:24:00 +00002775 case Mttt:
2776 return toBool(a1->u.Mttt.co == a2->u.Mttt.co
2777 && a1->u.Mttt.e0 == a2->u.Mttt.e0
2778 && a1->u.Mttt.eX == a2->u.Mttt.eX);
2779 case GetIt:
sewardjdd40fdf2006-12-24 02:20:24 +00002780 return toBool(eqIRRegArray(a1->u.GetIt.descr, a2->u.GetIt.descr)
sewardj9b0cc582006-02-04 15:24:00 +00002781 && a1->u.GetIt.ix == a2->u.GetIt.ix
2782 && a1->u.GetIt.bias == a2->u.GetIt.bias);
sewardj08210532004-12-29 17:09:11 +00002783 default: vpanic("eq_AvailExpr");
2784 }
2785}
2786
2787static IRExpr* availExpr_to_IRExpr ( AvailExpr* ae )
2788{
2789 IRConst* con;
2790 switch (ae->tag) {
2791 case Ut:
sewardjdd40fdf2006-12-24 02:20:24 +00002792 return IRExpr_Unop( ae->u.Ut.op, IRExpr_RdTmp(ae->u.Ut.arg) );
sewardj08210532004-12-29 17:09:11 +00002793 case Btt:
2794 return IRExpr_Binop( ae->u.Btt.op,
sewardjdd40fdf2006-12-24 02:20:24 +00002795 IRExpr_RdTmp(ae->u.Btt.arg1),
2796 IRExpr_RdTmp(ae->u.Btt.arg2) );
sewardj08210532004-12-29 17:09:11 +00002797 case Btc:
2798 con = LibVEX_Alloc(sizeof(IRConst));
2799 *con = ae->u.Btc.con2;
2800 return IRExpr_Binop( ae->u.Btc.op,
sewardjdd40fdf2006-12-24 02:20:24 +00002801 IRExpr_RdTmp(ae->u.Btc.arg1),
2802 IRExpr_Const(con) );
sewardj08210532004-12-29 17:09:11 +00002803 case Bct:
2804 con = LibVEX_Alloc(sizeof(IRConst));
2805 *con = ae->u.Bct.con1;
2806 return IRExpr_Binop( ae->u.Bct.op,
sewardjdd40fdf2006-12-24 02:20:24 +00002807 IRExpr_Const(con),
2808 IRExpr_RdTmp(ae->u.Bct.arg2) );
sewardj08210532004-12-29 17:09:11 +00002809 case Cf64i:
2810 return IRExpr_Const(IRConst_F64i(ae->u.Cf64i.f64i));
sewardj9b0cc582006-02-04 15:24:00 +00002811 case Mttt:
sewardjdd40fdf2006-12-24 02:20:24 +00002812 return IRExpr_Mux0X(IRExpr_RdTmp(ae->u.Mttt.co),
2813 IRExpr_RdTmp(ae->u.Mttt.e0),
2814 IRExpr_RdTmp(ae->u.Mttt.eX));
sewardj9b0cc582006-02-04 15:24:00 +00002815 case GetIt:
2816 return IRExpr_GetI(ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00002817 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00002818 ae->u.GetIt.bias);
sewardj08210532004-12-29 17:09:11 +00002819 default:
2820 vpanic("availExpr_to_IRExpr");
2821 }
2822}
2823
2824inline
2825static IRTemp subst_AvailExpr_Temp ( HashHW* env, IRTemp tmp )
2826{
2827 HWord res;
2828 /* env :: IRTemp -> IRTemp */
2829 if (lookupHHW( env, &res, (HWord)tmp ))
2830 return (IRTemp)res;
2831 else
2832 return tmp;
2833}
2834
2835static void subst_AvailExpr ( HashHW* env, AvailExpr* ae )
2836{
2837 /* env :: IRTemp -> IRTemp */
2838 switch (ae->tag) {
2839 case Ut:
2840 ae->u.Ut.arg = subst_AvailExpr_Temp( env, ae->u.Ut.arg );
2841 break;
2842 case Btt:
2843 ae->u.Btt.arg1 = subst_AvailExpr_Temp( env, ae->u.Btt.arg1 );
2844 ae->u.Btt.arg2 = subst_AvailExpr_Temp( env, ae->u.Btt.arg2 );
2845 break;
2846 case Btc:
2847 ae->u.Btc.arg1 = subst_AvailExpr_Temp( env, ae->u.Btc.arg1 );
2848 break;
2849 case Bct:
2850 ae->u.Bct.arg2 = subst_AvailExpr_Temp( env, ae->u.Bct.arg2 );
2851 break;
2852 case Cf64i:
2853 break;
sewardj9b0cc582006-02-04 15:24:00 +00002854 case Mttt:
2855 ae->u.Mttt.co = subst_AvailExpr_Temp( env, ae->u.Mttt.co );
2856 ae->u.Mttt.e0 = subst_AvailExpr_Temp( env, ae->u.Mttt.e0 );
2857 ae->u.Mttt.eX = subst_AvailExpr_Temp( env, ae->u.Mttt.eX );
2858 break;
2859 case GetIt:
2860 ae->u.GetIt.ix = subst_AvailExpr_Temp( env, ae->u.GetIt.ix );
2861 break;
sewardj08210532004-12-29 17:09:11 +00002862 default:
2863 vpanic("subst_AvailExpr");
2864 }
2865}
2866
2867static AvailExpr* irExpr_to_AvailExpr ( IRExpr* e )
2868{
2869 AvailExpr* ae;
2870
2871 if (e->tag == Iex_Unop
sewardjdd40fdf2006-12-24 02:20:24 +00002872 && e->Iex.Unop.arg->tag == Iex_RdTmp) {
sewardj08210532004-12-29 17:09:11 +00002873 ae = LibVEX_Alloc(sizeof(AvailExpr));
2874 ae->tag = Ut;
2875 ae->u.Ut.op = e->Iex.Unop.op;
sewardjdd40fdf2006-12-24 02:20:24 +00002876 ae->u.Ut.arg = e->Iex.Unop.arg->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002877 return ae;
2878 }
2879
2880 if (e->tag == Iex_Binop
sewardjdd40fdf2006-12-24 02:20:24 +00002881 && e->Iex.Binop.arg1->tag == Iex_RdTmp
2882 && e->Iex.Binop.arg2->tag == Iex_RdTmp) {
sewardj08210532004-12-29 17:09:11 +00002883 ae = LibVEX_Alloc(sizeof(AvailExpr));
2884 ae->tag = Btt;
2885 ae->u.Btt.op = e->Iex.Binop.op;
sewardjdd40fdf2006-12-24 02:20:24 +00002886 ae->u.Btt.arg1 = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
2887 ae->u.Btt.arg2 = e->Iex.Binop.arg2->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002888 return ae;
2889 }
2890
2891 if (e->tag == Iex_Binop
sewardjdd40fdf2006-12-24 02:20:24 +00002892 && e->Iex.Binop.arg1->tag == Iex_RdTmp
sewardj08210532004-12-29 17:09:11 +00002893 && e->Iex.Binop.arg2->tag == Iex_Const) {
2894 ae = LibVEX_Alloc(sizeof(AvailExpr));
2895 ae->tag = Btc;
2896 ae->u.Btc.op = e->Iex.Binop.op;
sewardjdd40fdf2006-12-24 02:20:24 +00002897 ae->u.Btc.arg1 = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002898 ae->u.Btc.con2 = *(e->Iex.Binop.arg2->Iex.Const.con);
2899 return ae;
2900 }
2901
2902 if (e->tag == Iex_Binop
2903 && e->Iex.Binop.arg1->tag == Iex_Const
sewardjdd40fdf2006-12-24 02:20:24 +00002904 && e->Iex.Binop.arg2->tag == Iex_RdTmp) {
sewardj08210532004-12-29 17:09:11 +00002905 ae = LibVEX_Alloc(sizeof(AvailExpr));
2906 ae->tag = Bct;
2907 ae->u.Bct.op = e->Iex.Binop.op;
sewardjdd40fdf2006-12-24 02:20:24 +00002908 ae->u.Bct.arg2 = e->Iex.Binop.arg2->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002909 ae->u.Bct.con1 = *(e->Iex.Binop.arg1->Iex.Const.con);
2910 return ae;
2911 }
2912
2913 if (e->tag == Iex_Const
2914 && e->Iex.Const.con->tag == Ico_F64i) {
2915 ae = LibVEX_Alloc(sizeof(AvailExpr));
2916 ae->tag = Cf64i;
2917 ae->u.Cf64i.f64i = e->Iex.Const.con->Ico.F64i;
2918 return ae;
2919 }
2920
sewardj9b0cc582006-02-04 15:24:00 +00002921 if (e->tag == Iex_Mux0X
sewardjdd40fdf2006-12-24 02:20:24 +00002922 && e->Iex.Mux0X.cond->tag == Iex_RdTmp
2923 && e->Iex.Mux0X.expr0->tag == Iex_RdTmp
2924 && e->Iex.Mux0X.exprX->tag == Iex_RdTmp) {
sewardj9b0cc582006-02-04 15:24:00 +00002925 ae = LibVEX_Alloc(sizeof(AvailExpr));
2926 ae->tag = Mttt;
sewardjdd40fdf2006-12-24 02:20:24 +00002927 ae->u.Mttt.co = e->Iex.Mux0X.cond->Iex.RdTmp.tmp;
2928 ae->u.Mttt.e0 = e->Iex.Mux0X.expr0->Iex.RdTmp.tmp;
2929 ae->u.Mttt.eX = e->Iex.Mux0X.exprX->Iex.RdTmp.tmp;
sewardj9b0cc582006-02-04 15:24:00 +00002930 return ae;
2931 }
2932
2933 if (e->tag == Iex_GetI
sewardjdd40fdf2006-12-24 02:20:24 +00002934 && e->Iex.GetI.ix->tag == Iex_RdTmp) {
sewardj9b0cc582006-02-04 15:24:00 +00002935 ae = LibVEX_Alloc(sizeof(AvailExpr));
2936 ae->tag = GetIt;
2937 ae->u.GetIt.descr = e->Iex.GetI.descr;
sewardjdd40fdf2006-12-24 02:20:24 +00002938 ae->u.GetIt.ix = e->Iex.GetI.ix->Iex.RdTmp.tmp;
sewardj9b0cc582006-02-04 15:24:00 +00002939 ae->u.GetIt.bias = e->Iex.GetI.bias;
2940 return ae;
2941 }
2942
sewardj08210532004-12-29 17:09:11 +00002943 return NULL;
2944}
2945
2946
sewardj9b0cc582006-02-04 15:24:00 +00002947/* The BB is modified in-place. Returns True if any changes were
2948 made. */
sewardj08210532004-12-29 17:09:11 +00002949
sewardjdd40fdf2006-12-24 02:20:24 +00002950static Bool do_cse_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00002951{
sewardj9b0cc582006-02-04 15:24:00 +00002952 Int i, j, paranoia;
sewardj08210532004-12-29 17:09:11 +00002953 IRTemp t, q;
2954 IRStmt* st;
2955 AvailExpr* eprime;
sewardj9b0cc582006-02-04 15:24:00 +00002956 AvailExpr* ae;
2957 Bool invalidate;
2958 Bool anyDone = False;
sewardj08210532004-12-29 17:09:11 +00002959
2960 HashHW* tenv = newHHW(); /* :: IRTemp -> IRTemp */
2961 HashHW* aenv = newHHW(); /* :: AvailExpr* -> IRTemp */
2962
2963 vassert(sizeof(IRTemp) <= sizeof(HWord));
2964
sewardjdd40fdf2006-12-24 02:20:24 +00002965 if (0) { ppIRSB(bb); vex_printf("\n\n"); }
sewardj08210532004-12-29 17:09:11 +00002966
2967 /* Iterate forwards over the stmts.
sewardjb183b852006-02-03 16:08:03 +00002968 On seeing "t = E", where E is one of the 5 AvailExpr forms:
sewardj08210532004-12-29 17:09:11 +00002969 let E' = apply tenv substitution to E
2970 search aenv for E'
2971 if a mapping E' -> q is found,
2972 replace this stmt by "t = q"
2973 and add binding t -> q to tenv
2974 else
2975 add binding E' -> t to aenv
2976 replace this stmt by "t = E'"
sewardj9b0cc582006-02-04 15:24:00 +00002977
2978 Other statements are only interesting to the extent that they
2979 might invalidate some of the expressions in aenv. So there is
2980 an invalidate-bindings check for each statement seen.
sewardj08210532004-12-29 17:09:11 +00002981 */
2982 for (i = 0; i < bb->stmts_used; i++) {
2983 st = bb->stmts[i];
2984
sewardj9b0cc582006-02-04 15:24:00 +00002985 /* ------ BEGIN invalidate aenv bindings ------ */
2986 /* This is critical: remove from aenv any E' -> .. bindings
2987 which might be invalidated by this statement. The only
sewardjc4356f02007-11-09 21:15:04 +00002988 vulnerable kind of bindings are the GetI kind.
sewardj9b0cc582006-02-04 15:24:00 +00002989 Dirty call - dump (paranoia level -> 2)
2990 Store - dump (ditto)
2991 Put, PutI - dump unless no-overlap is proven (.. -> 1)
2992 Uses getAliasingRelation_IC and getAliasingRelation_II
2993 to do the no-overlap assessments needed for Put/PutI.
2994 */
2995 switch (st->tag) {
sewardje768e922009-11-26 17:17:37 +00002996 case Ist_Dirty: case Ist_Store: case Ist_MBE:
2997 case Ist_CAS: case Ist_LLSC:
sewardj9b0cc582006-02-04 15:24:00 +00002998 paranoia = 2; break;
2999 case Ist_Put: case Ist_PutI:
3000 paranoia = 1; break;
3001 case Ist_NoOp: case Ist_IMark: case Ist_AbiHint:
sewardjc4356f02007-11-09 21:15:04 +00003002 case Ist_WrTmp: case Ist_Exit:
sewardj9b0cc582006-02-04 15:24:00 +00003003 paranoia = 0; break;
3004 default:
3005 vpanic("do_cse_BB(1)");
3006 }
3007
3008 if (paranoia > 0) {
3009 for (j = 0; j < aenv->used; j++) {
3010 if (!aenv->inuse[j])
3011 continue;
3012 ae = (AvailExpr*)aenv->key[j];
3013 if (ae->tag != GetIt)
3014 continue;
3015 invalidate = False;
3016 if (paranoia >= 2) {
3017 invalidate = True;
3018 } else {
3019 vassert(paranoia == 1);
3020 if (st->tag == Ist_Put) {
3021 if (getAliasingRelation_IC(
3022 ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003023 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00003024 st->Ist.Put.offset,
3025 typeOfIRExpr(bb->tyenv,st->Ist.Put.data)
3026 ) != NoAlias)
3027 invalidate = True;
3028 }
3029 else
3030 if (st->tag == Ist_PutI) {
3031 if (getAliasingRelation_II(
3032 ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003033 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00003034 ae->u.GetIt.bias,
3035 st->Ist.PutI.descr,
3036 st->Ist.PutI.ix,
3037 st->Ist.PutI.bias
3038 ) != NoAlias)
3039 invalidate = True;
3040 }
3041 else
3042 vpanic("do_cse_BB(2)");
3043 }
3044
3045 if (invalidate) {
3046 aenv->inuse[j] = False;
3047 aenv->key[j] = (HWord)NULL; /* be sure */
3048 }
3049 } /* for j */
3050 } /* paranoia > 0 */
3051
3052 /* ------ ENV invalidate aenv bindings ------ */
3053
sewardj08210532004-12-29 17:09:11 +00003054 /* ignore not-interestings */
sewardjdd40fdf2006-12-24 02:20:24 +00003055 if (st->tag != Ist_WrTmp)
sewardj08210532004-12-29 17:09:11 +00003056 continue;
3057
sewardjdd40fdf2006-12-24 02:20:24 +00003058 t = st->Ist.WrTmp.tmp;
3059 eprime = irExpr_to_AvailExpr(st->Ist.WrTmp.data);
sewardj08210532004-12-29 17:09:11 +00003060 /* ignore if not of AvailExpr form */
3061 if (!eprime)
3062 continue;
3063
3064 /* vex_printf("considering: " ); ppIRStmt(st); vex_printf("\n"); */
3065
3066 /* apply tenv */
3067 subst_AvailExpr( tenv, eprime );
3068
3069 /* search aenv for eprime, unfortunately the hard way */
3070 for (j = 0; j < aenv->used; j++)
3071 if (aenv->inuse[j] && eq_AvailExpr(eprime, (AvailExpr*)aenv->key[j]))
3072 break;
3073
3074 if (j < aenv->used) {
3075 /* A binding E' -> q was found. Replace stmt by "t = q" and
3076 note the t->q binding in tenv. */
3077 /* (this is the core of the CSE action) */
3078 q = (IRTemp)aenv->val[j];
sewardjdd40fdf2006-12-24 02:20:24 +00003079 bb->stmts[i] = IRStmt_WrTmp( t, IRExpr_RdTmp(q) );
sewardj08210532004-12-29 17:09:11 +00003080 addToHHW( tenv, (HWord)t, (HWord)q );
sewardj9b0cc582006-02-04 15:24:00 +00003081 anyDone = True;
sewardj08210532004-12-29 17:09:11 +00003082 } else {
3083 /* No binding was found, so instead we add E' -> t to our
3084 collection of available expressions, replace this stmt
3085 with "t = E'", and move on. */
sewardjdd40fdf2006-12-24 02:20:24 +00003086 bb->stmts[i] = IRStmt_WrTmp( t, availExpr_to_IRExpr(eprime) );
sewardj08210532004-12-29 17:09:11 +00003087 addToHHW( aenv, (HWord)eprime, (HWord)t );
3088 }
3089 }
3090
sewardjb183b852006-02-03 16:08:03 +00003091 /*
sewardjdd40fdf2006-12-24 02:20:24 +00003092 ppIRSB(bb);
3093 sanityCheckIRSB(bb, Ity_I32);
sewardjb183b852006-02-03 16:08:03 +00003094 vex_printf("\n\n");
3095 */
sewardj9b0cc582006-02-04 15:24:00 +00003096 return anyDone;
sewardj08210532004-12-29 17:09:11 +00003097}
3098
3099
3100/*---------------------------------------------------------------*/
3101/*--- Add32/Sub32 chain collapsing ---*/
3102/*---------------------------------------------------------------*/
3103
3104/* ----- Helper functions for Add32/Sub32 chain collapsing ----- */
3105
3106/* Is this expression "Add32(tmp,const)" or "Sub32(tmp,const)" ? If
3107 yes, set *tmp and *i32 appropriately. *i32 is set as if the
3108 root node is Add32, not Sub32. */
3109
3110static Bool isAdd32OrSub32 ( IRExpr* e, IRTemp* tmp, Int* i32 )
3111{
3112 if (e->tag != Iex_Binop)
3113 return False;
3114 if (e->Iex.Binop.op != Iop_Add32 && e->Iex.Binop.op != Iop_Sub32)
3115 return False;
sewardjdd40fdf2006-12-24 02:20:24 +00003116 if (e->Iex.Binop.arg1->tag != Iex_RdTmp)
sewardj08210532004-12-29 17:09:11 +00003117 return False;
3118 if (e->Iex.Binop.arg2->tag != Iex_Const)
3119 return False;
sewardjdd40fdf2006-12-24 02:20:24 +00003120 *tmp = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00003121 *i32 = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32);
3122 if (e->Iex.Binop.op == Iop_Sub32)
3123 *i32 = -*i32;
3124 return True;
3125}
3126
3127
3128/* Figure out if tmp can be expressed as tmp2 +32 const, for some
3129 other tmp2. Scan backwards from the specified start point -- an
3130 optimisation. */
3131
sewardjdd40fdf2006-12-24 02:20:24 +00003132static Bool collapseChain ( IRSB* bb, Int startHere,
sewardj08210532004-12-29 17:09:11 +00003133 IRTemp tmp,
3134 IRTemp* tmp2, Int* i32 )
3135{
3136 Int j, ii;
3137 IRTemp vv;
3138 IRStmt* st;
3139 IRExpr* e;
3140
3141 /* the (var, con) pair contain the current 'representation' for
3142 'tmp'. We start with 'tmp + 0'. */
3143 IRTemp var = tmp;
3144 Int con = 0;
3145
3146 /* Scan backwards to see if tmp can be replaced by some other tmp
3147 +/- a constant. */
3148 for (j = startHere; j >= 0; j--) {
3149 st = bb->stmts[j];
sewardjdd40fdf2006-12-24 02:20:24 +00003150 if (st->tag != Ist_WrTmp)
sewardj08210532004-12-29 17:09:11 +00003151 continue;
sewardjdd40fdf2006-12-24 02:20:24 +00003152 if (st->Ist.WrTmp.tmp != var)
sewardj08210532004-12-29 17:09:11 +00003153 continue;
sewardjdd40fdf2006-12-24 02:20:24 +00003154 e = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +00003155 if (!isAdd32OrSub32(e, &vv, &ii))
3156 break;
3157 var = vv;
3158 con += ii;
3159 }
3160 if (j == -1)
3161 /* no earlier binding for var .. ill-formed IR */
3162 vpanic("collapseChain");
3163
3164 /* so, did we find anything interesting? */
3165 if (var == tmp)
3166 return False; /* no .. */
3167
3168 *tmp2 = var;
3169 *i32 = con;
3170 return True;
3171}
3172
3173
3174/* ------- Main function for Add32/Sub32 chain collapsing ------ */
3175
sewardjdd40fdf2006-12-24 02:20:24 +00003176static void collapse_AddSub_chains_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003177{
3178 IRStmt *st;
3179 IRTemp var, var2;
3180 Int i, con, con2;
3181
3182 for (i = bb->stmts_used-1; i >= 0; i--) {
3183 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003184 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00003185 continue;
3186
3187 /* Try to collapse 't1 = Add32/Sub32(t2, con)'. */
3188
sewardjdd40fdf2006-12-24 02:20:24 +00003189 if (st->tag == Ist_WrTmp
3190 && isAdd32OrSub32(st->Ist.WrTmp.data, &var, &con)) {
sewardj08210532004-12-29 17:09:11 +00003191
3192 /* So e1 is of the form Add32(var,con) or Sub32(var,-con).
3193 Find out if var can be expressed as var2 + con2. */
3194 if (collapseChain(bb, i-1, var, &var2, &con2)) {
3195 if (DEBUG_IROPT) {
3196 vex_printf("replacing1 ");
3197 ppIRStmt(st);
3198 vex_printf(" with ");
3199 }
3200 con2 += con;
3201 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00003202 = IRStmt_WrTmp(
3203 st->Ist.WrTmp.tmp,
sewardj08210532004-12-29 17:09:11 +00003204 (con2 >= 0)
3205 ? IRExpr_Binop(Iop_Add32,
sewardjdd40fdf2006-12-24 02:20:24 +00003206 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00003207 IRExpr_Const(IRConst_U32(con2)))
3208 : IRExpr_Binop(Iop_Sub32,
sewardjdd40fdf2006-12-24 02:20:24 +00003209 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00003210 IRExpr_Const(IRConst_U32(-con2)))
3211 );
3212 if (DEBUG_IROPT) {
3213 ppIRStmt(bb->stmts[i]);
3214 vex_printf("\n");
3215 }
3216 }
3217
3218 continue;
3219 }
3220
3221 /* Try to collapse 't1 = GetI[t2, con]'. */
3222
sewardjdd40fdf2006-12-24 02:20:24 +00003223 if (st->tag == Ist_WrTmp
3224 && st->Ist.WrTmp.data->tag == Iex_GetI
3225 && st->Ist.WrTmp.data->Iex.GetI.ix->tag == Iex_RdTmp
3226 && collapseChain(bb, i-1, st->Ist.WrTmp.data->Iex.GetI.ix
3227 ->Iex.RdTmp.tmp, &var2, &con2)) {
sewardj08210532004-12-29 17:09:11 +00003228 if (DEBUG_IROPT) {
3229 vex_printf("replacing3 ");
3230 ppIRStmt(st);
3231 vex_printf(" with ");
3232 }
sewardjdd40fdf2006-12-24 02:20:24 +00003233 con2 += st->Ist.WrTmp.data->Iex.GetI.bias;
sewardj08210532004-12-29 17:09:11 +00003234 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00003235 = IRStmt_WrTmp(
3236 st->Ist.WrTmp.tmp,
3237 IRExpr_GetI(st->Ist.WrTmp.data->Iex.GetI.descr,
3238 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00003239 con2));
3240 if (DEBUG_IROPT) {
3241 ppIRStmt(bb->stmts[i]);
3242 vex_printf("\n");
3243 }
3244 continue;
3245 }
3246
3247 /* Perhaps st is PutI[t, con] ? */
3248
3249 if (st->tag == Ist_PutI
sewardjdd40fdf2006-12-24 02:20:24 +00003250 && st->Ist.PutI.ix->tag == Iex_RdTmp
3251 && collapseChain(bb, i-1, st->Ist.PutI.ix->Iex.RdTmp.tmp,
sewardj08210532004-12-29 17:09:11 +00003252 &var2, &con2)) {
3253 if (DEBUG_IROPT) {
3254 vex_printf("replacing2 ");
3255 ppIRStmt(st);
3256 vex_printf(" with ");
3257 }
3258 con2 += st->Ist.PutI.bias;
3259 bb->stmts[i]
3260 = IRStmt_PutI(st->Ist.PutI.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003261 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00003262 con2,
3263 st->Ist.PutI.data);
3264 if (DEBUG_IROPT) {
3265 ppIRStmt(bb->stmts[i]);
3266 vex_printf("\n");
3267 }
3268 continue;
3269 }
3270
3271 } /* for */
3272}
3273
3274
3275/*---------------------------------------------------------------*/
3276/*--- PutI/GetI transformations ---*/
3277/*---------------------------------------------------------------*/
3278
sewardj08210532004-12-29 17:09:11 +00003279/* Given the parts (descr, tmp, bias) for a GetI, scan backwards from
3280 the given starting point to find, if any, a PutI which writes
3281 exactly the same piece of guest state, and so return the expression
3282 that the PutI writes. This is the core of PutI-GetI forwarding. */
3283
3284static
sewardjdd40fdf2006-12-24 02:20:24 +00003285IRExpr* findPutI ( IRSB* bb, Int startHere,
3286 IRRegArray* descrG, IRExpr* ixG, Int biasG )
sewardj08210532004-12-29 17:09:11 +00003287{
3288 Int j;
3289 IRStmt* st;
3290 GSAliasing relation;
3291
3292 if (0) {
3293 vex_printf("\nfindPutI ");
sewardjdd40fdf2006-12-24 02:20:24 +00003294 ppIRRegArray(descrG);
sewardj08210532004-12-29 17:09:11 +00003295 vex_printf(" ");
3296 ppIRExpr(ixG);
3297 vex_printf(" %d\n", biasG);
3298 }
3299
3300 /* Scan backwards in bb from startHere to find a suitable PutI
3301 binding for (descrG, ixG, biasG), if any. */
3302
3303 for (j = startHere; j >= 0; j--) {
3304 st = bb->stmts[j];
sewardj8bee6d12005-03-22 02:24:05 +00003305 if (st->tag == Ist_NoOp)
3306 continue;
sewardj08210532004-12-29 17:09:11 +00003307
3308 if (st->tag == Ist_Put) {
3309 /* Non-indexed Put. This can't give a binding, but we do
3310 need to check it doesn't invalidate the search by
3311 overlapping any part of the indexed guest state. */
3312
3313 relation
3314 = getAliasingRelation_IC(
3315 descrG, ixG,
3316 st->Ist.Put.offset,
3317 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
3318
3319 if (relation == NoAlias) {
3320 /* we're OK; keep going */
3321 continue;
3322 } else {
3323 /* relation == UnknownAlias || relation == ExactAlias */
3324 /* If this assertion fails, we've found a Put which writes
3325 an area of guest state which is read by a GetI. Which
3326 is unlikely (although not per se wrong). */
3327 vassert(relation != ExactAlias);
3328 /* This Put potentially writes guest state that the GetI
3329 reads; we must fail. */
3330 return NULL;
3331 }
3332 }
3333
3334 if (st->tag == Ist_PutI) {
3335
3336 relation = getAliasingRelation_II(
3337 descrG, ixG, biasG,
3338 st->Ist.PutI.descr,
3339 st->Ist.PutI.ix,
3340 st->Ist.PutI.bias
3341 );
3342
3343 if (relation == NoAlias) {
3344 /* This PutI definitely doesn't overlap. Ignore it and
3345 keep going. */
3346 continue; /* the for j loop */
3347 }
3348
3349 if (relation == UnknownAlias) {
3350 /* We don't know if this PutI writes to the same guest
3351 state that the GetI, or not. So we have to give up. */
3352 return NULL;
3353 }
3354
3355 /* Otherwise, we've found what we're looking for. */
3356 vassert(relation == ExactAlias);
3357 return st->Ist.PutI.data;
3358
3359 } /* if (st->tag == Ist_PutI) */
3360
3361 if (st->tag == Ist_Dirty) {
3362 /* Be conservative. If the dirty call has any guest effects at
3363 all, give up. We could do better -- only give up if there
3364 are any guest writes/modifies. */
3365 if (st->Ist.Dirty.details->nFxState > 0)
3366 return NULL;
3367 }
3368
3369 } /* for */
3370
3371 /* No valid replacement was found. */
3372 return NULL;
3373}
3374
3375
3376
3377/* Assuming pi is a PutI stmt, is s2 identical to it (in the sense
3378 that it writes exactly the same piece of guest state) ? Safe
3379 answer: False. */
3380
3381static Bool identicalPutIs ( IRStmt* pi, IRStmt* s2 )
3382{
3383 vassert(pi->tag == Ist_PutI);
3384 if (s2->tag != Ist_PutI)
3385 return False;
3386
sewardj9d2e7692005-02-07 01:11:31 +00003387 return toBool(
3388 getAliasingRelation_II(
sewardj08210532004-12-29 17:09:11 +00003389 pi->Ist.PutI.descr, pi->Ist.PutI.ix, pi->Ist.PutI.bias,
3390 s2->Ist.PutI.descr, s2->Ist.PutI.ix, s2->Ist.PutI.bias
3391 )
sewardj9d2e7692005-02-07 01:11:31 +00003392 == ExactAlias
3393 );
sewardj08210532004-12-29 17:09:11 +00003394}
3395
3396
3397/* Assuming pi is a PutI stmt, is s2 a Get/GetI/Put/PutI which might
3398 overlap it? Safe answer: True. Note, we could do a lot better
3399 than this if needed. */
3400
3401static
3402Bool guestAccessWhichMightOverlapPutI (
3403 IRTypeEnv* tyenv, IRStmt* pi, IRStmt* s2
3404 )
3405{
3406 GSAliasing relation;
3407 UInt minoffP, maxoffP;
3408
3409 vassert(pi->tag == Ist_PutI);
3410 getArrayBounds(pi->Ist.PutI.descr, &minoffP, &maxoffP);
3411 switch (s2->tag) {
3412
sewardjd2445f62005-03-21 00:15:53 +00003413 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00003414 case Ist_IMark:
3415 return False;
3416
sewardjc4356f02007-11-09 21:15:04 +00003417 case Ist_MBE:
sewardj5a9ffab2005-05-12 17:55:01 +00003418 case Ist_AbiHint:
3419 /* just be paranoid ... these should be rare. */
sewardjbb3f52d2005-01-07 14:14:50 +00003420 return True;
3421
sewardje9d8a262009-07-01 08:06:34 +00003422 case Ist_CAS:
3423 /* This is unbelievably lame, but it's probably not
3424 significant from a performance point of view. Really, a
3425 CAS is a load-store op, so it should be safe to say False.
3426 However .. */
3427 return True;
3428
sewardj08210532004-12-29 17:09:11 +00003429 case Ist_Dirty:
3430 /* If the dirty call has any guest effects at all, give up.
3431 Probably could do better. */
3432 if (s2->Ist.Dirty.details->nFxState > 0)
3433 return True;
3434 return False;
3435
3436 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00003437 vassert(isIRAtom(s2->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +00003438 relation
3439 = getAliasingRelation_IC(
3440 pi->Ist.PutI.descr, pi->Ist.PutI.ix,
3441 s2->Ist.Put.offset,
3442 typeOfIRExpr(tyenv,s2->Ist.Put.data)
3443 );
3444 goto have_relation;
3445
3446 case Ist_PutI:
sewardj496a58d2005-03-20 18:44:44 +00003447 vassert(isIRAtom(s2->Ist.PutI.ix));
3448 vassert(isIRAtom(s2->Ist.PutI.data));
sewardj08210532004-12-29 17:09:11 +00003449 relation
3450 = getAliasingRelation_II(
3451 pi->Ist.PutI.descr, pi->Ist.PutI.ix, pi->Ist.PutI.bias,
3452 s2->Ist.PutI.descr, s2->Ist.PutI.ix, s2->Ist.PutI.bias
3453 );
3454 goto have_relation;
3455
sewardjdd40fdf2006-12-24 02:20:24 +00003456 case Ist_WrTmp:
3457 if (s2->Ist.WrTmp.data->tag == Iex_GetI) {
sewardj08210532004-12-29 17:09:11 +00003458 relation
3459 = getAliasingRelation_II(
3460 pi->Ist.PutI.descr, pi->Ist.PutI.ix,
3461 pi->Ist.PutI.bias,
sewardjdd40fdf2006-12-24 02:20:24 +00003462 s2->Ist.WrTmp.data->Iex.GetI.descr,
3463 s2->Ist.WrTmp.data->Iex.GetI.ix,
3464 s2->Ist.WrTmp.data->Iex.GetI.bias
sewardj08210532004-12-29 17:09:11 +00003465 );
3466 goto have_relation;
3467 }
sewardjdd40fdf2006-12-24 02:20:24 +00003468 if (s2->Ist.WrTmp.data->tag == Iex_Get) {
sewardj08210532004-12-29 17:09:11 +00003469 relation
3470 = getAliasingRelation_IC(
3471 pi->Ist.PutI.descr, pi->Ist.PutI.ix,
sewardjdd40fdf2006-12-24 02:20:24 +00003472 s2->Ist.WrTmp.data->Iex.Get.offset,
3473 s2->Ist.WrTmp.data->Iex.Get.ty
sewardj08210532004-12-29 17:09:11 +00003474 );
3475 goto have_relation;
3476 }
3477 return False;
3478
sewardjaf1ceca2005-06-30 23:31:27 +00003479 case Ist_Store:
3480 vassert(isIRAtom(s2->Ist.Store.addr));
3481 vassert(isIRAtom(s2->Ist.Store.data));
sewardj08210532004-12-29 17:09:11 +00003482 return False;
3483
3484 default:
3485 vex_printf("\n"); ppIRStmt(s2); vex_printf("\n");
3486 vpanic("guestAccessWhichMightOverlapPutI");
3487 }
3488
3489 have_relation:
3490 if (relation == NoAlias)
3491 return False;
3492 else
3493 return True; /* ExactAlias or UnknownAlias */
3494}
3495
3496
3497
3498/* ---------- PutI/GetI transformations main functions --------- */
3499
3500/* Remove redundant GetIs, to the extent that they can be detected.
3501 bb is modified in-place. */
3502
3503static
sewardjdd40fdf2006-12-24 02:20:24 +00003504void do_redundant_GetI_elimination ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003505{
3506 Int i;
3507 IRStmt* st;
3508
3509 for (i = bb->stmts_used-1; i >= 0; i--) {
3510 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003511 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00003512 continue;
3513
sewardjdd40fdf2006-12-24 02:20:24 +00003514 if (st->tag == Ist_WrTmp
3515 && st->Ist.WrTmp.data->tag == Iex_GetI
3516 && st->Ist.WrTmp.data->Iex.GetI.ix->tag == Iex_RdTmp) {
3517 IRRegArray* descr = st->Ist.WrTmp.data->Iex.GetI.descr;
3518 IRExpr* ix = st->Ist.WrTmp.data->Iex.GetI.ix;
3519 Int bias = st->Ist.WrTmp.data->Iex.GetI.bias;
3520 IRExpr* replacement = findPutI(bb, i-1, descr, ix, bias);
sewardj08210532004-12-29 17:09:11 +00003521 if (replacement
sewardj496a58d2005-03-20 18:44:44 +00003522 && isIRAtom(replacement)
sewardj08210532004-12-29 17:09:11 +00003523 /* Make sure we're doing a type-safe transformation! */
3524 && typeOfIRExpr(bb->tyenv, replacement) == descr->elemTy) {
3525 if (DEBUG_IROPT) {
3526 vex_printf("rGI: ");
sewardjdd40fdf2006-12-24 02:20:24 +00003527 ppIRExpr(st->Ist.WrTmp.data);
sewardj08210532004-12-29 17:09:11 +00003528 vex_printf(" -> ");
3529 ppIRExpr(replacement);
3530 vex_printf("\n");
3531 }
sewardjdd40fdf2006-12-24 02:20:24 +00003532 bb->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, replacement);
sewardj08210532004-12-29 17:09:11 +00003533 }
3534 }
3535 }
3536
3537}
3538
3539
3540/* Remove redundant PutIs, to the extent which they can be detected.
3541 bb is modified in-place. */
3542
3543static
sewardjdd40fdf2006-12-24 02:20:24 +00003544void do_redundant_PutI_elimination ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003545{
3546 Int i, j;
3547 Bool delete;
3548 IRStmt *st, *stj;
3549
3550 for (i = 0; i < bb->stmts_used; i++) {
3551 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003552 if (st->tag != Ist_PutI)
sewardj08210532004-12-29 17:09:11 +00003553 continue;
3554 /* Ok, search forwards from here to see if we can find another
3555 PutI which makes this one redundant, and dodging various
3556 hazards. Search forwards:
3557 * If conditional exit, give up (because anything after that
3558 does not postdominate this put).
3559 * If a Get which might overlap, give up (because this PutI
3560 not necessarily dead).
3561 * If a Put which is identical, stop with success.
3562 * If a Put which might overlap, but is not identical, give up.
3563 * If a dirty helper call which might write guest state, give up.
3564 * If a Put which definitely doesn't overlap, or any other
3565 kind of stmt, continue.
3566 */
3567 delete = False;
3568 for (j = i+1; j < bb->stmts_used; j++) {
3569 stj = bb->stmts[j];
sewardj8bee6d12005-03-22 02:24:05 +00003570 if (stj->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00003571 continue;
3572 if (identicalPutIs(st, stj)) {
3573 /* success! */
3574 delete = True;
3575 break;
3576 }
3577 if (stj->tag == Ist_Exit)
3578 /* give up */
3579 break;
3580 if (st->tag == Ist_Dirty)
3581 /* give up; could do better here */
3582 break;
3583 if (guestAccessWhichMightOverlapPutI(bb->tyenv, st, stj))
3584 /* give up */
3585 break;
3586 }
3587
3588 if (delete) {
3589 if (DEBUG_IROPT) {
3590 vex_printf("rPI: ");
3591 ppIRStmt(st);
3592 vex_printf("\n");
3593 }
sewardjd2445f62005-03-21 00:15:53 +00003594 bb->stmts[i] = IRStmt_NoOp();
sewardj08210532004-12-29 17:09:11 +00003595 }
3596
3597 }
3598}
3599
3600
3601/*---------------------------------------------------------------*/
3602/*--- Loop unrolling ---*/
3603/*---------------------------------------------------------------*/
3604
3605/* Adjust all tmp values (names) in e by delta. e is destructively
3606 modified. */
3607
3608static void deltaIRExpr ( IRExpr* e, Int delta )
3609{
3610 Int i;
3611 switch (e->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +00003612 case Iex_RdTmp:
3613 e->Iex.RdTmp.tmp += delta;
sewardj08210532004-12-29 17:09:11 +00003614 break;
3615 case Iex_Get:
3616 case Iex_Const:
3617 break;
3618 case Iex_GetI:
3619 deltaIRExpr(e->Iex.GetI.ix, delta);
3620 break;
sewardj1a866b42006-02-09 02:54:03 +00003621 case Iex_Qop:
3622 deltaIRExpr(e->Iex.Qop.arg1, delta);
3623 deltaIRExpr(e->Iex.Qop.arg2, delta);
3624 deltaIRExpr(e->Iex.Qop.arg3, delta);
3625 deltaIRExpr(e->Iex.Qop.arg4, delta);
3626 break;
sewardjb183b852006-02-03 16:08:03 +00003627 case Iex_Triop:
3628 deltaIRExpr(e->Iex.Triop.arg1, delta);
3629 deltaIRExpr(e->Iex.Triop.arg2, delta);
3630 deltaIRExpr(e->Iex.Triop.arg3, delta);
3631 break;
sewardj08210532004-12-29 17:09:11 +00003632 case Iex_Binop:
3633 deltaIRExpr(e->Iex.Binop.arg1, delta);
3634 deltaIRExpr(e->Iex.Binop.arg2, delta);
3635 break;
3636 case Iex_Unop:
3637 deltaIRExpr(e->Iex.Unop.arg, delta);
3638 break;
sewardjaf1ceca2005-06-30 23:31:27 +00003639 case Iex_Load:
3640 deltaIRExpr(e->Iex.Load.addr, delta);
sewardj08210532004-12-29 17:09:11 +00003641 break;
3642 case Iex_CCall:
3643 for (i = 0; e->Iex.CCall.args[i]; i++)
3644 deltaIRExpr(e->Iex.CCall.args[i], delta);
3645 break;
3646 case Iex_Mux0X:
3647 deltaIRExpr(e->Iex.Mux0X.cond, delta);
3648 deltaIRExpr(e->Iex.Mux0X.expr0, delta);
3649 deltaIRExpr(e->Iex.Mux0X.exprX, delta);
3650 break;
3651 default:
3652 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3653 vpanic("deltaIRExpr");
3654 }
3655}
3656
3657/* Adjust all tmp values (names) in st by delta. st is destructively
3658 modified. */
3659
3660static void deltaIRStmt ( IRStmt* st, Int delta )
3661{
3662 Int i;
3663 IRDirty* d;
3664 switch (st->tag) {
sewardjd2445f62005-03-21 00:15:53 +00003665 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00003666 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00003667 case Ist_MBE:
sewardjf1689312005-03-16 18:19:10 +00003668 break;
sewardj5a9ffab2005-05-12 17:55:01 +00003669 case Ist_AbiHint:
3670 deltaIRExpr(st->Ist.AbiHint.base, delta);
sewardj478646f2008-05-01 20:13:04 +00003671 deltaIRExpr(st->Ist.AbiHint.nia, delta);
sewardj5a9ffab2005-05-12 17:55:01 +00003672 break;
sewardj08210532004-12-29 17:09:11 +00003673 case Ist_Put:
3674 deltaIRExpr(st->Ist.Put.data, delta);
3675 break;
3676 case Ist_PutI:
3677 deltaIRExpr(st->Ist.PutI.ix, delta);
3678 deltaIRExpr(st->Ist.PutI.data, delta);
3679 break;
sewardjdd40fdf2006-12-24 02:20:24 +00003680 case Ist_WrTmp:
3681 st->Ist.WrTmp.tmp += delta;
3682 deltaIRExpr(st->Ist.WrTmp.data, delta);
sewardj08210532004-12-29 17:09:11 +00003683 break;
3684 case Ist_Exit:
3685 deltaIRExpr(st->Ist.Exit.guard, delta);
3686 break;
sewardjaf1ceca2005-06-30 23:31:27 +00003687 case Ist_Store:
3688 deltaIRExpr(st->Ist.Store.addr, delta);
3689 deltaIRExpr(st->Ist.Store.data, delta);
sewardj08210532004-12-29 17:09:11 +00003690 break;
sewardje9d8a262009-07-01 08:06:34 +00003691 case Ist_CAS:
3692 if (st->Ist.CAS.details->oldHi != IRTemp_INVALID)
3693 st->Ist.CAS.details->oldHi += delta;
3694 st->Ist.CAS.details->oldLo += delta;
3695 deltaIRExpr(st->Ist.CAS.details->addr, delta);
3696 if (st->Ist.CAS.details->expdHi)
3697 deltaIRExpr(st->Ist.CAS.details->expdHi, delta);
3698 deltaIRExpr(st->Ist.CAS.details->expdLo, delta);
3699 if (st->Ist.CAS.details->dataHi)
3700 deltaIRExpr(st->Ist.CAS.details->dataHi, delta);
3701 deltaIRExpr(st->Ist.CAS.details->dataLo, delta);
3702 break;
sewardje768e922009-11-26 17:17:37 +00003703 case Ist_LLSC:
3704 st->Ist.LLSC.result += delta;
3705 deltaIRExpr(st->Ist.LLSC.addr, delta);
3706 if (st->Ist.LLSC.storedata)
3707 deltaIRExpr(st->Ist.LLSC.storedata, delta);
3708 break;
sewardj08210532004-12-29 17:09:11 +00003709 case Ist_Dirty:
3710 d = st->Ist.Dirty.details;
3711 deltaIRExpr(d->guard, delta);
3712 for (i = 0; d->args[i]; i++)
3713 deltaIRExpr(d->args[i], delta);
3714 if (d->tmp != IRTemp_INVALID)
3715 d->tmp += delta;
3716 if (d->mAddr)
3717 deltaIRExpr(d->mAddr, delta);
3718 break;
3719 default:
3720 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
3721 vpanic("deltaIRStmt");
3722 }
3723}
3724
3725
3726/* If possible, return a loop-unrolled version of bb0. The original
3727 is changed. If not possible, return NULL. */
3728
3729/* The two schemas considered are:
3730
3731 X: BODY; goto X
3732
3733 which unrolls to (eg) X: BODY;BODY; goto X
3734
3735 and
3736
3737 X: BODY; if (c) goto X; goto Y
3738 which trivially transforms to
3739 X: BODY; if (!c) goto Y; goto X;
3740 so it falls in the scope of the first case.
3741
3742 X and Y must be literal (guest) addresses.
3743*/
3744
sewardjdd40fdf2006-12-24 02:20:24 +00003745static Int calc_unroll_factor( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003746{
3747 Int n_stmts, i;
3748
3749 n_stmts = 0;
sewardj0ddbf792005-04-04 23:12:54 +00003750 for (i = 0; i < bb->stmts_used; i++) {
3751 if (bb->stmts[i]->tag != Ist_NoOp)
3752 n_stmts++;
3753 }
sewardj08210532004-12-29 17:09:11 +00003754
3755 if (n_stmts <= vex_control.iropt_unroll_thresh/8) {
3756 if (vex_control.iropt_verbosity > 0)
3757 vex_printf("vex iropt: 8 x unrolling (%d sts -> %d sts)\n",
3758 n_stmts, 8* n_stmts);
3759 return 8;
3760 }
3761 if (n_stmts <= vex_control.iropt_unroll_thresh/4) {
3762 if (vex_control.iropt_verbosity > 0)
3763 vex_printf("vex iropt: 4 x unrolling (%d sts -> %d sts)\n",
3764 n_stmts, 4* n_stmts);
3765 return 4;
3766 }
3767
3768 if (n_stmts <= vex_control.iropt_unroll_thresh/2) {
3769 if (vex_control.iropt_verbosity > 0)
3770 vex_printf("vex iropt: 2 x unrolling (%d sts -> %d sts)\n",
3771 n_stmts, 2* n_stmts);
3772 return 2;
3773 }
3774
3775 if (vex_control.iropt_verbosity > 0)
3776 vex_printf("vex iropt: not unrolling (%d sts)\n", n_stmts);
3777
3778 return 1;
3779}
3780
3781
sewardjdd40fdf2006-12-24 02:20:24 +00003782static IRSB* maybe_loop_unroll_BB ( IRSB* bb0, Addr64 my_addr )
sewardj08210532004-12-29 17:09:11 +00003783{
3784 Int i, j, jmax, n_vars;
3785 Bool xxx_known;
3786 Addr64 xxx_value, yyy_value;
3787 IRExpr* udst;
3788 IRStmt* st;
3789 IRConst* con;
sewardjdd40fdf2006-12-24 02:20:24 +00003790 IRSB *bb1, *bb2;
sewardj08210532004-12-29 17:09:11 +00003791 Int unroll_factor;
3792
3793 if (vex_control.iropt_unroll_thresh <= 0)
3794 return NULL;
3795
3796 /* First off, figure out if we can unroll this loop. Do this
3797 without modifying bb0. */
3798
3799 if (bb0->jumpkind != Ijk_Boring)
3800 return NULL;
3801
3802 xxx_known = False;
3803 xxx_value = 0;
3804
3805 /* Extract the next-guest address. If it isn't a literal, we
3806 have to give up. */
3807
3808 udst = bb0->next;
3809 if (udst->tag == Iex_Const
3810 && (udst->Iex.Const.con->tag == Ico_U32
3811 || udst->Iex.Const.con->tag == Ico_U64)) {
3812 /* The BB ends in a jump to a literal location. */
3813 xxx_known = True;
3814 xxx_value = udst->Iex.Const.con->tag == Ico_U64
3815 ? udst->Iex.Const.con->Ico.U64
3816 : (Addr64)(udst->Iex.Const.con->Ico.U32);
3817 }
3818
3819 if (!xxx_known)
3820 return NULL;
3821
3822 /* Now we know the BB ends to a jump to a literal location. If
3823 it's a jump to itself (viz, idiom #1), move directly to the
3824 unrolling stage, first cloning the bb so the original isn't
3825 modified. */
3826 if (xxx_value == my_addr) {
3827 unroll_factor = calc_unroll_factor( bb0 );
3828 if (unroll_factor < 2)
3829 return NULL;
sewardjdd40fdf2006-12-24 02:20:24 +00003830 bb1 = deepCopyIRSB( bb0 );
sewardj08210532004-12-29 17:09:11 +00003831 bb0 = NULL;
3832 udst = NULL; /* is now invalid */
3833 goto do_unroll;
3834 }
3835
3836 /* Search for the second idiomatic form:
3837 X: BODY; if (c) goto X; goto Y
3838 We know Y, but need to establish that the last stmt
3839 is 'if (c) goto X'.
3840 */
3841 yyy_value = xxx_value;
3842 for (i = bb0->stmts_used-1; i >= 0; i--)
3843 if (bb0->stmts[i])
3844 break;
3845
3846 if (i < 0)
3847 return NULL; /* block with no stmts. Strange. */
3848
3849 st = bb0->stmts[i];
3850 if (st->tag != Ist_Exit)
3851 return NULL;
3852 if (st->Ist.Exit.jk != Ijk_Boring)
3853 return NULL;
3854
3855 con = st->Ist.Exit.dst;
3856 vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
3857
3858 xxx_value = con->tag == Ico_U64
3859 ? st->Ist.Exit.dst->Ico.U64
3860 : (Addr64)(st->Ist.Exit.dst->Ico.U32);
3861
3862 /* If this assertion fails, we have some kind of type error. */
3863 vassert(con->tag == udst->Iex.Const.con->tag);
3864
3865 if (xxx_value != my_addr)
3866 /* We didn't find either idiom. Give up. */
3867 return NULL;
3868
3869 /* Ok, we found idiom #2. Copy the BB, switch around the xxx and
3870 yyy values (which makes it look like idiom #1), and go into
3871 unrolling proper. This means finding (again) the last stmt, in
3872 the copied BB. */
3873
3874 unroll_factor = calc_unroll_factor( bb0 );
3875 if (unroll_factor < 2)
3876 return NULL;
3877
sewardjdd40fdf2006-12-24 02:20:24 +00003878 bb1 = deepCopyIRSB( bb0 );
sewardj08210532004-12-29 17:09:11 +00003879 bb0 = NULL;
3880 udst = NULL; /* is now invalid */
3881 for (i = bb1->stmts_used-1; i >= 0; i--)
3882 if (bb1->stmts[i])
3883 break;
3884
3885 /* The next bunch of assertions should be true since we already
3886 found and checked the last stmt in the original bb. */
3887
3888 vassert(i >= 0);
3889
3890 st = bb1->stmts[i];
3891 vassert(st->tag == Ist_Exit);
3892
3893 con = st->Ist.Exit.dst;
3894 vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
3895
3896 udst = bb1->next;
3897 vassert(udst->tag == Iex_Const);
3898 vassert(udst->Iex.Const.con->tag == Ico_U32
3899 || udst->Iex.Const.con->tag == Ico_U64);
3900 vassert(con->tag == udst->Iex.Const.con->tag);
3901
3902 /* switch the xxx and yyy fields around */
3903 if (con->tag == Ico_U64) {
3904 udst->Iex.Const.con->Ico.U64 = xxx_value;
3905 con->Ico.U64 = yyy_value;
3906 } else {
3907 udst->Iex.Const.con->Ico.U32 = (UInt)xxx_value;
cerion57b4c6d2005-02-22 11:07:35 +00003908 con->Ico.U32 = (UInt)yyy_value;
sewardj08210532004-12-29 17:09:11 +00003909 }
3910
3911 /* negate the test condition */
3912 st->Ist.Exit.guard
sewardjdd40fdf2006-12-24 02:20:24 +00003913 = IRExpr_Unop(Iop_Not1,deepCopyIRExpr(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +00003914
3915 /* --- The unroller proper. Both idioms are by now --- */
3916 /* --- now converted to idiom 1. --- */
3917
3918 do_unroll:
3919
3920 vassert(unroll_factor == 2
3921 || unroll_factor == 4
3922 || unroll_factor == 8);
3923
3924 jmax = unroll_factor==8 ? 3 : (unroll_factor==4 ? 2 : 1);
3925 for (j = 1; j <= jmax; j++) {
3926
3927 n_vars = bb1->tyenv->types_used;
3928
sewardjdd40fdf2006-12-24 02:20:24 +00003929 bb2 = deepCopyIRSB(bb1);
sewardj08210532004-12-29 17:09:11 +00003930 for (i = 0; i < n_vars; i++)
3931 (void)newIRTemp(bb1->tyenv, bb2->tyenv->types[i]);
3932
3933 for (i = 0; i < bb2->stmts_used; i++) {
sewardj08210532004-12-29 17:09:11 +00003934 /* deltaIRStmt destructively modifies the stmt, but
3935 that's OK since bb2 is a complete fresh copy of bb1. */
3936 deltaIRStmt(bb2->stmts[i], n_vars);
sewardjdd40fdf2006-12-24 02:20:24 +00003937 addStmtToIRSB(bb1, bb2->stmts[i]);
sewardj08210532004-12-29 17:09:11 +00003938 }
3939 }
3940
3941 if (DEBUG_IROPT) {
3942 vex_printf("\nUNROLLED (%llx)\n", my_addr);
sewardjdd40fdf2006-12-24 02:20:24 +00003943 ppIRSB(bb1);
sewardj08210532004-12-29 17:09:11 +00003944 vex_printf("\n");
3945 }
3946
3947 /* Flattening; sigh. The unroller succeeds in breaking flatness
3948 by negating the test condition. This should be fixed properly.
3949 For the moment use this shotgun approach. */
3950 return flatten_BB(bb1);
3951}
3952
3953
3954/*---------------------------------------------------------------*/
sewardj29632392004-08-22 02:38:11 +00003955/*--- The tree builder ---*/
3956/*---------------------------------------------------------------*/
3957
sewardj08210532004-12-29 17:09:11 +00003958/* This isn't part of IR optimisation. Really it's a pass done prior
3959 to instruction selection, which improves the code that the
3960 instruction selector can produce. */
3961
sewardjf9517d02005-11-28 13:39:37 +00003962/* --- The 'tmp' environment is the central data structure here --- */
sewardj29632392004-08-22 02:38:11 +00003963
sewardjf9517d02005-11-28 13:39:37 +00003964/* The number of outstanding bindings we're prepared to track.
3965 The number of times the env becomes full and we have to dump
3966 the oldest binding (hence reducing code quality) falls very
3967 rapidly as the env size increases. 8 gives reasonable performance
3968 under most circumstances. */
3969#define A_NENV 10
3970
3971/* bindee == NULL === slot is not in use
3972 bindee != NULL === slot is in use
sewardj29632392004-08-22 02:38:11 +00003973*/
sewardjf9517d02005-11-28 13:39:37 +00003974typedef
3975 struct {
3976 IRTemp binder;
3977 IRExpr* bindee;
3978 Bool doesLoad;
3979 Bool doesGet;
sewardj17442fe2004-09-20 14:54:28 +00003980 }
sewardjf9517d02005-11-28 13:39:37 +00003981 ATmpInfo;
sewardj17442fe2004-09-20 14:54:28 +00003982
sewardjf9517d02005-11-28 13:39:37 +00003983__attribute__((unused))
3984static void ppAEnv ( ATmpInfo* env )
sewardj29632392004-08-22 02:38:11 +00003985{
sewardj17442fe2004-09-20 14:54:28 +00003986 Int i;
sewardjf9517d02005-11-28 13:39:37 +00003987 for (i = 0; i < A_NENV; i++) {
3988 vex_printf("%d tmp %d val ", i, (Int)env[i].binder);
3989 if (env[i].bindee)
3990 ppIRExpr(env[i].bindee);
3991 else
3992 vex_printf("(null)");
3993 vex_printf("\n");
sewardj29632392004-08-22 02:38:11 +00003994 }
3995}
3996
sewardjf9517d02005-11-28 13:39:37 +00003997/* --- Tree-traversal fns --- */
sewardj29632392004-08-22 02:38:11 +00003998
sewardj37d38012004-08-24 00:37:04 +00003999/* Traverse an expr, and detect if any part of it reads memory or does
4000 a Get. Be careful ... this really controls how much the
4001 tree-builder can reorder the code, so getting it right is critical.
4002*/
sewardj29632392004-08-22 02:38:11 +00004003static void setHints_Expr (Bool* doesLoad, Bool* doesGet, IRExpr* e )
4004{
sewardjc41f1fb2004-08-22 09:48:08 +00004005 Int i;
sewardj29632392004-08-22 02:38:11 +00004006 switch (e->tag) {
sewardjc41f1fb2004-08-22 09:48:08 +00004007 case Iex_CCall:
4008 for (i = 0; e->Iex.CCall.args[i]; i++)
4009 setHints_Expr(doesLoad, doesGet, e->Iex.CCall.args[i]);
4010 return;
4011 case Iex_Mux0X:
4012 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.cond);
4013 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.expr0);
4014 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.exprX);
4015 return;
sewardj40c80262006-02-08 19:30:46 +00004016 case Iex_Qop:
4017 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.arg1);
4018 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.arg2);
4019 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.arg3);
4020 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.arg4);
4021 return;
sewardjb183b852006-02-03 16:08:03 +00004022 case Iex_Triop:
4023 setHints_Expr(doesLoad, doesGet, e->Iex.Triop.arg1);
4024 setHints_Expr(doesLoad, doesGet, e->Iex.Triop.arg2);
4025 setHints_Expr(doesLoad, doesGet, e->Iex.Triop.arg3);
4026 return;
sewardjc41f1fb2004-08-22 09:48:08 +00004027 case Iex_Binop:
4028 setHints_Expr(doesLoad, doesGet, e->Iex.Binop.arg1);
4029 setHints_Expr(doesLoad, doesGet, e->Iex.Binop.arg2);
4030 return;
4031 case Iex_Unop:
4032 setHints_Expr(doesLoad, doesGet, e->Iex.Unop.arg);
4033 return;
sewardjaf1ceca2005-06-30 23:31:27 +00004034 case Iex_Load:
sewardjc9ad1152004-10-14 00:08:21 +00004035 *doesLoad = True;
sewardjaf1ceca2005-06-30 23:31:27 +00004036 setHints_Expr(doesLoad, doesGet, e->Iex.Load.addr);
sewardjc41f1fb2004-08-22 09:48:08 +00004037 return;
sewardj29632392004-08-22 02:38:11 +00004038 case Iex_Get:
sewardjc9ad1152004-10-14 00:08:21 +00004039 *doesGet = True;
sewardj29632392004-08-22 02:38:11 +00004040 return;
sewardjf6501992004-08-27 11:58:24 +00004041 case Iex_GetI:
sewardjc9ad1152004-10-14 00:08:21 +00004042 *doesGet = True;
sewardjeeac8412004-11-02 00:26:55 +00004043 setHints_Expr(doesLoad, doesGet, e->Iex.GetI.ix);
sewardjf6501992004-08-27 11:58:24 +00004044 return;
sewardjdd40fdf2006-12-24 02:20:24 +00004045 case Iex_RdTmp:
sewardjc41f1fb2004-08-22 09:48:08 +00004046 case Iex_Const:
4047 return;
sewardj29632392004-08-22 02:38:11 +00004048 default:
4049 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4050 vpanic("setHints_Expr");
4051 }
4052}
4053
4054
sewardjf9517d02005-11-28 13:39:37 +00004055/* Add a binding to the front of the env and slide all the rest
4056 backwards. It should be the case that the last slot is free. */
4057static void addToEnvFront ( ATmpInfo* env, IRTemp binder, IRExpr* bindee )
sewardj29632392004-08-22 02:38:11 +00004058{
sewardjf9517d02005-11-28 13:39:37 +00004059 Int i;
4060 vassert(env[A_NENV-1].bindee == NULL);
4061 for (i = A_NENV-1; i >= 1; i--)
4062 env[i] = env[i-1];
4063 env[0].binder = binder;
4064 env[0].bindee = bindee;
4065 env[0].doesLoad = False; /* filled in later */
4066 env[0].doesGet = False; /* filled in later */
4067}
sewardj29632392004-08-22 02:38:11 +00004068
sewardjf9517d02005-11-28 13:39:37 +00004069/* Given uses :: array of UShort, indexed by IRTemp
4070 Add the use-occurrences of temps in this expression
4071 to the env.
4072*/
4073static void aoccCount_Expr ( UShort* uses, IRExpr* e )
4074{
4075 Int i;
sewardj29632392004-08-22 02:38:11 +00004076
sewardjf9517d02005-11-28 13:39:37 +00004077 switch (e->tag) {
4078
sewardjdd40fdf2006-12-24 02:20:24 +00004079 case Iex_RdTmp: /* the only interesting case */
4080 uses[e->Iex.RdTmp.tmp]++;
sewardj8bee6d12005-03-22 02:24:05 +00004081 return;
sewardj29632392004-08-22 02:38:11 +00004082
sewardjf9517d02005-11-28 13:39:37 +00004083 case Iex_Mux0X:
4084 aoccCount_Expr(uses, e->Iex.Mux0X.cond);
4085 aoccCount_Expr(uses, e->Iex.Mux0X.expr0);
4086 aoccCount_Expr(uses, e->Iex.Mux0X.exprX);
4087 return;
sewardj29632392004-08-22 02:38:11 +00004088
sewardj40c80262006-02-08 19:30:46 +00004089 case Iex_Qop:
4090 aoccCount_Expr(uses, e->Iex.Qop.arg1);
4091 aoccCount_Expr(uses, e->Iex.Qop.arg2);
4092 aoccCount_Expr(uses, e->Iex.Qop.arg3);
4093 aoccCount_Expr(uses, e->Iex.Qop.arg4);
4094 return;
4095
sewardjb183b852006-02-03 16:08:03 +00004096 case Iex_Triop:
4097 aoccCount_Expr(uses, e->Iex.Triop.arg1);
4098 aoccCount_Expr(uses, e->Iex.Triop.arg2);
4099 aoccCount_Expr(uses, e->Iex.Triop.arg3);
4100 return;
4101
sewardjf9517d02005-11-28 13:39:37 +00004102 case Iex_Binop:
4103 aoccCount_Expr(uses, e->Iex.Binop.arg1);
4104 aoccCount_Expr(uses, e->Iex.Binop.arg2);
4105 return;
sewardj29632392004-08-22 02:38:11 +00004106
sewardjf9517d02005-11-28 13:39:37 +00004107 case Iex_Unop:
4108 aoccCount_Expr(uses, e->Iex.Unop.arg);
4109 return;
4110
4111 case Iex_Load:
4112 aoccCount_Expr(uses, e->Iex.Load.addr);
4113 return;
4114
4115 case Iex_CCall:
4116 for (i = 0; e->Iex.CCall.args[i]; i++)
4117 aoccCount_Expr(uses, e->Iex.CCall.args[i]);
4118 return;
4119
4120 case Iex_GetI:
4121 aoccCount_Expr(uses, e->Iex.GetI.ix);
4122 return;
4123
4124 case Iex_Const:
4125 case Iex_Get:
4126 return;
4127
4128 default:
4129 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4130 vpanic("aoccCount_Expr");
4131 }
sewardj29632392004-08-22 02:38:11 +00004132}
4133
4134
sewardjf9517d02005-11-28 13:39:37 +00004135/* Given uses :: array of UShort, indexed by IRTemp
4136 Add the use-occurrences of temps in this statement
4137 to the env.
4138*/
4139static void aoccCount_Stmt ( UShort* uses, IRStmt* st )
sewardj29632392004-08-22 02:38:11 +00004140{
sewardjf9517d02005-11-28 13:39:37 +00004141 Int i;
4142 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00004143 IRCAS* cas;
sewardjf9517d02005-11-28 13:39:37 +00004144 switch (st->tag) {
4145 case Ist_AbiHint:
4146 aoccCount_Expr(uses, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +00004147 aoccCount_Expr(uses, st->Ist.AbiHint.nia);
sewardjf9517d02005-11-28 13:39:37 +00004148 return;
sewardjdd40fdf2006-12-24 02:20:24 +00004149 case Ist_WrTmp:
4150 aoccCount_Expr(uses, st->Ist.WrTmp.data);
sewardjf9517d02005-11-28 13:39:37 +00004151 return;
4152 case Ist_Put:
4153 aoccCount_Expr(uses, st->Ist.Put.data);
4154 return;
4155 case Ist_PutI:
4156 aoccCount_Expr(uses, st->Ist.PutI.ix);
4157 aoccCount_Expr(uses, st->Ist.PutI.data);
4158 return;
4159 case Ist_Store:
4160 aoccCount_Expr(uses, st->Ist.Store.addr);
4161 aoccCount_Expr(uses, st->Ist.Store.data);
4162 return;
sewardje9d8a262009-07-01 08:06:34 +00004163 case Ist_CAS:
4164 cas = st->Ist.CAS.details;
4165 aoccCount_Expr(uses, cas->addr);
4166 if (cas->expdHi)
4167 aoccCount_Expr(uses, cas->expdHi);
4168 aoccCount_Expr(uses, cas->expdLo);
4169 if (cas->dataHi)
4170 aoccCount_Expr(uses, cas->dataHi);
4171 aoccCount_Expr(uses, cas->dataLo);
4172 return;
sewardje768e922009-11-26 17:17:37 +00004173 case Ist_LLSC:
4174 aoccCount_Expr(uses, st->Ist.LLSC.addr);
4175 if (st->Ist.LLSC.storedata)
4176 aoccCount_Expr(uses, st->Ist.LLSC.storedata);
4177 return;
sewardjf9517d02005-11-28 13:39:37 +00004178 case Ist_Dirty:
4179 d = st->Ist.Dirty.details;
4180 if (d->mFx != Ifx_None)
4181 aoccCount_Expr(uses, d->mAddr);
4182 aoccCount_Expr(uses, d->guard);
4183 for (i = 0; d->args[i]; i++)
4184 aoccCount_Expr(uses, d->args[i]);
4185 return;
4186 case Ist_NoOp:
4187 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00004188 case Ist_MBE:
sewardjf9517d02005-11-28 13:39:37 +00004189 return;
4190 case Ist_Exit:
4191 aoccCount_Expr(uses, st->Ist.Exit.guard);
4192 return;
4193 default:
4194 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
4195 vpanic("aoccCount_Stmt");
4196 }
4197}
4198
4199/* Look up a binding for tmp in the env. If found, return the bound
4200 expression, and set the env's binding to NULL so it is marked as
4201 used. If not found, return NULL. */
4202
4203static IRExpr* atbSubst_Temp ( ATmpInfo* env, IRTemp tmp )
4204{
4205 Int i;
4206 for (i = 0; i < A_NENV; i++) {
4207 if (env[i].binder == tmp && env[i].bindee != NULL) {
4208 IRExpr* bindee = env[i].bindee;
4209 env[i].bindee = NULL;
4210 return bindee;
4211 }
4212 }
4213 return NULL;
4214}
4215
4216/* Traverse e, looking for temps. For each observed temp, see if env
4217 contains a binding for the temp, and if so return the bound value.
4218 The env has the property that any binding it holds is
4219 'single-shot', so once a binding is used, it is marked as no longer
4220 available, by setting its .bindee field to NULL. */
4221
sewardjeb17e492007-08-25 23:07:44 +00004222static inline Bool is_Unop ( IRExpr* e, IROp op ) {
4223 return e->tag == Iex_Unop && e->Iex.Unop.op == op;
4224}
4225static inline Bool is_Binop ( IRExpr* e, IROp op ) {
4226 return e->tag == Iex_Binop && e->Iex.Binop.op == op;
4227}
4228
4229static IRExpr* fold_IRExpr_Binop ( IROp op, IRExpr* a1, IRExpr* a2 )
4230{
4231 switch (op) {
4232 case Iop_Or32:
4233 /* Or32( CmpwNEZ32(x), CmpwNEZ32(y) ) --> CmpwNEZ32( Or32( x, y ) ) */
4234 if (is_Unop(a1, Iop_CmpwNEZ32) && is_Unop(a2, Iop_CmpwNEZ32))
4235 return IRExpr_Unop( Iop_CmpwNEZ32,
4236 IRExpr_Binop( Iop_Or32, a1->Iex.Unop.arg,
4237 a2->Iex.Unop.arg ) );
4238 break;
florian51d26fd2011-07-23 00:23:02 +00004239
4240 case Iop_CmpNE32:
4241 /* Since X has type Ity_I1 we can simplify:
4242 CmpNE32(1Uto32(X),0)) ==> X */
4243 if (is_Unop(a1, Iop_1Uto32) && isZeroU32(a2))
4244 return a1->Iex.Unop.arg;
4245 break;
4246
sewardjeb17e492007-08-25 23:07:44 +00004247 default:
4248 break;
4249 }
4250 /* no reduction rule applies */
4251 return IRExpr_Binop( op, a1, a2 );
4252}
4253
4254static IRExpr* fold_IRExpr_Unop ( IROp op, IRExpr* aa )
4255{
4256 switch (op) {
4257 case Iop_CmpwNEZ64:
4258 /* CmpwNEZ64( Or64 ( CmpwNEZ64(x), y ) ) --> CmpwNEZ64( Or64( x, y ) ) */
4259 if (is_Binop(aa, Iop_Or64)
4260 && is_Unop(aa->Iex.Binop.arg1, Iop_CmpwNEZ64))
4261 return fold_IRExpr_Unop(
4262 Iop_CmpwNEZ64,
4263 IRExpr_Binop(Iop_Or64,
4264 aa->Iex.Binop.arg1->Iex.Unop.arg,
4265 aa->Iex.Binop.arg2));
4266 /* CmpwNEZ64( Or64 ( x, CmpwNEZ64(y) ) ) --> CmpwNEZ64( Or64( x, y ) ) */
4267 if (is_Binop(aa, Iop_Or64)
4268 && is_Unop(aa->Iex.Binop.arg2, Iop_CmpwNEZ64))
4269 return fold_IRExpr_Unop(
4270 Iop_CmpwNEZ64,
4271 IRExpr_Binop(Iop_Or64,
4272 aa->Iex.Binop.arg1,
4273 aa->Iex.Binop.arg2->Iex.Unop.arg));
4274 break;
4275 case Iop_CmpNEZ64:
4276 /* CmpNEZ64( Left64(x) ) --> CmpNEZ64(x) */
4277 if (is_Unop(aa, Iop_Left64))
4278 return IRExpr_Unop(Iop_CmpNEZ64, aa->Iex.Unop.arg);
4279 break;
4280 case Iop_CmpwNEZ32:
4281 /* CmpwNEZ32( CmpwNEZ32 ( x ) ) --> CmpwNEZ32 ( x ) */
4282 if (is_Unop(aa, Iop_CmpwNEZ32))
4283 return IRExpr_Unop( Iop_CmpwNEZ32, aa->Iex.Unop.arg );
4284 break;
4285 case Iop_CmpNEZ32:
4286 /* CmpNEZ32( Left32(x) ) --> CmpNEZ32(x) */
4287 if (is_Unop(aa, Iop_Left32))
4288 return IRExpr_Unop(Iop_CmpNEZ32, aa->Iex.Unop.arg);
florian51d26fd2011-07-23 00:23:02 +00004289 /* CmpNEZ32( 1Uto32(X) ) --> X */
4290 if (is_Unop(aa, Iop_1Uto32))
4291 return aa->Iex.Unop.arg;
4292 break;
4293 case Iop_CmpNEZ8:
4294 /* CmpNEZ8( 1Uto8(X) ) --> X */
4295 if (is_Unop(aa, Iop_1Uto8))
4296 return aa->Iex.Unop.arg;
sewardjeb17e492007-08-25 23:07:44 +00004297 break;
4298 case Iop_Left32:
4299 /* Left32( Left32(x) ) --> Left32(x) */
4300 if (is_Unop(aa, Iop_Left32))
4301 return IRExpr_Unop( Iop_Left32, aa->Iex.Unop.arg );
4302 break;
4303 case Iop_32to1:
4304 /* 32to1( 1Uto32 ( x ) ) --> x */
4305 if (is_Unop(aa, Iop_1Uto32))
4306 return aa->Iex.Unop.arg;
4307 /* 32to1( CmpwNEZ32 ( x )) --> CmpNEZ32(x) */
4308 if (is_Unop(aa, Iop_CmpwNEZ32))
4309 return IRExpr_Unop( Iop_CmpNEZ32, aa->Iex.Unop.arg );
4310 break;
4311 case Iop_64to1:
4312 /* 64to1( 1Uto64 ( x ) ) --> x */
4313 if (is_Unop(aa, Iop_1Uto64))
4314 return aa->Iex.Unop.arg;
4315 /* 64to1( CmpwNEZ64 ( x )) --> CmpNEZ64(x) */
4316 if (is_Unop(aa, Iop_CmpwNEZ64))
4317 return IRExpr_Unop( Iop_CmpNEZ64, aa->Iex.Unop.arg );
4318 break;
sewardjef425db2010-01-11 10:46:18 +00004319 case Iop_64to32:
4320 /* 64to32( 32Uto64 ( x )) --> x */
4321 if (is_Unop(aa, Iop_32Uto64))
4322 return aa->Iex.Unop.arg;
sewardjca257bc2010-09-08 08:34:52 +00004323 /* 64to32( 8Uto64 ( x )) --> 8Uto32(x) */
4324 if (is_Unop(aa, Iop_8Uto64))
4325 return IRExpr_Unop(Iop_8Uto32, aa->Iex.Unop.arg);
4326 break;
4327
4328 case Iop_32Uto64:
4329 /* 32Uto64( 8Uto32( x )) --> 8Uto64(x) */
4330 if (is_Unop(aa, Iop_8Uto32))
4331 return IRExpr_Unop(Iop_8Uto64, aa->Iex.Unop.arg);
4332 /* 32Uto64( 16Uto32( x )) --> 16Uto64(x) */
4333 if (is_Unop(aa, Iop_16Uto32))
4334 return IRExpr_Unop(Iop_16Uto64, aa->Iex.Unop.arg);
sewardjef425db2010-01-11 10:46:18 +00004335 break;
sewardj6c299f32009-12-31 18:00:12 +00004336
4337 case Iop_1Sto32:
4338 /* 1Sto32( CmpNEZ8( 32to8( 1Uto32( CmpNEZ32( x ))))) -> CmpwNEZ32(x) */
4339 if (is_Unop(aa, Iop_CmpNEZ8)
4340 && is_Unop(aa->Iex.Unop.arg, Iop_32to8)
4341 && is_Unop(aa->Iex.Unop.arg->Iex.Unop.arg, Iop_1Uto32)
4342 && is_Unop(aa->Iex.Unop.arg->Iex.Unop.arg->Iex.Unop.arg,
4343 Iop_CmpNEZ32)) {
4344 return IRExpr_Unop( Iop_CmpwNEZ32,
4345 aa->Iex.Unop.arg->Iex.Unop.arg
4346 ->Iex.Unop.arg->Iex.Unop.arg);
4347 }
4348 break;
4349
sewardjef425db2010-01-11 10:46:18 +00004350
sewardjeb17e492007-08-25 23:07:44 +00004351 default:
4352 break;
4353 }
4354 /* no reduction rule applies */
4355 return IRExpr_Unop( op, aa );
4356}
4357
sewardjf9517d02005-11-28 13:39:37 +00004358static IRExpr* atbSubst_Expr ( ATmpInfo* env, IRExpr* e )
4359{
4360 IRExpr* e2;
4361 IRExpr** args2;
4362 Int i;
4363
4364 switch (e->tag) {
4365
4366 case Iex_CCall:
sewardjdd40fdf2006-12-24 02:20:24 +00004367 args2 = shallowCopyIRExprVec(e->Iex.CCall.args);
sewardjf9517d02005-11-28 13:39:37 +00004368 for (i = 0; args2[i]; i++)
4369 args2[i] = atbSubst_Expr(env,args2[i]);
4370 return IRExpr_CCall(
4371 e->Iex.CCall.cee,
4372 e->Iex.CCall.retty,
4373 args2
4374 );
sewardjdd40fdf2006-12-24 02:20:24 +00004375 case Iex_RdTmp:
4376 e2 = atbSubst_Temp(env, e->Iex.RdTmp.tmp);
sewardjf9517d02005-11-28 13:39:37 +00004377 return e2 ? e2 : e;
4378 case Iex_Mux0X:
4379 return IRExpr_Mux0X(
4380 atbSubst_Expr(env, e->Iex.Mux0X.cond),
4381 atbSubst_Expr(env, e->Iex.Mux0X.expr0),
4382 atbSubst_Expr(env, e->Iex.Mux0X.exprX)
4383 );
sewardj40c80262006-02-08 19:30:46 +00004384 case Iex_Qop:
4385 return IRExpr_Qop(
4386 e->Iex.Qop.op,
4387 atbSubst_Expr(env, e->Iex.Qop.arg1),
4388 atbSubst_Expr(env, e->Iex.Qop.arg2),
4389 atbSubst_Expr(env, e->Iex.Qop.arg3),
4390 atbSubst_Expr(env, e->Iex.Qop.arg4)
4391 );
sewardjb183b852006-02-03 16:08:03 +00004392 case Iex_Triop:
4393 return IRExpr_Triop(
4394 e->Iex.Triop.op,
4395 atbSubst_Expr(env, e->Iex.Triop.arg1),
4396 atbSubst_Expr(env, e->Iex.Triop.arg2),
4397 atbSubst_Expr(env, e->Iex.Triop.arg3)
4398 );
sewardjf9517d02005-11-28 13:39:37 +00004399 case Iex_Binop:
sewardjeb17e492007-08-25 23:07:44 +00004400 return fold_IRExpr_Binop(
sewardjf9517d02005-11-28 13:39:37 +00004401 e->Iex.Binop.op,
4402 atbSubst_Expr(env, e->Iex.Binop.arg1),
4403 atbSubst_Expr(env, e->Iex.Binop.arg2)
4404 );
4405 case Iex_Unop:
sewardjeb17e492007-08-25 23:07:44 +00004406 return fold_IRExpr_Unop(
sewardjf9517d02005-11-28 13:39:37 +00004407 e->Iex.Unop.op,
4408 atbSubst_Expr(env, e->Iex.Unop.arg)
4409 );
4410 case Iex_Load:
4411 return IRExpr_Load(
4412 e->Iex.Load.end,
4413 e->Iex.Load.ty,
4414 atbSubst_Expr(env, e->Iex.Load.addr)
4415 );
4416 case Iex_GetI:
4417 return IRExpr_GetI(
4418 e->Iex.GetI.descr,
4419 atbSubst_Expr(env, e->Iex.GetI.ix),
4420 e->Iex.GetI.bias
4421 );
4422 case Iex_Const:
4423 case Iex_Get:
4424 return e;
4425 default:
4426 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4427 vpanic("atbSubst_Expr");
4428 }
4429}
4430
4431/* Same deal as atbSubst_Expr, except for stmts. */
4432
4433static IRStmt* atbSubst_Stmt ( ATmpInfo* env, IRStmt* st )
4434{
sewardje9d8a262009-07-01 08:06:34 +00004435 Int i;
4436 IRDirty *d, *d2;
4437 IRCAS *cas, *cas2;
sewardjf9517d02005-11-28 13:39:37 +00004438 switch (st->tag) {
4439 case Ist_AbiHint:
4440 return IRStmt_AbiHint(
4441 atbSubst_Expr(env, st->Ist.AbiHint.base),
sewardj478646f2008-05-01 20:13:04 +00004442 st->Ist.AbiHint.len,
4443 atbSubst_Expr(env, st->Ist.AbiHint.nia)
sewardjf9517d02005-11-28 13:39:37 +00004444 );
4445 case Ist_Store:
4446 return IRStmt_Store(
4447 st->Ist.Store.end,
4448 atbSubst_Expr(env, st->Ist.Store.addr),
4449 atbSubst_Expr(env, st->Ist.Store.data)
4450 );
sewardjdd40fdf2006-12-24 02:20:24 +00004451 case Ist_WrTmp:
4452 return IRStmt_WrTmp(
4453 st->Ist.WrTmp.tmp,
4454 atbSubst_Expr(env, st->Ist.WrTmp.data)
sewardjf9517d02005-11-28 13:39:37 +00004455 );
4456 case Ist_Put:
4457 return IRStmt_Put(
4458 st->Ist.Put.offset,
4459 atbSubst_Expr(env, st->Ist.Put.data)
4460 );
4461 case Ist_PutI:
4462 return IRStmt_PutI(
4463 st->Ist.PutI.descr,
4464 atbSubst_Expr(env, st->Ist.PutI.ix),
4465 st->Ist.PutI.bias,
4466 atbSubst_Expr(env, st->Ist.PutI.data)
4467 );
4468
4469 case Ist_Exit:
4470 return IRStmt_Exit(
4471 atbSubst_Expr(env, st->Ist.Exit.guard),
4472 st->Ist.Exit.jk,
4473 st->Ist.Exit.dst
4474 );
4475 case Ist_IMark:
sewardj2f10aa62011-05-27 13:20:56 +00004476 return IRStmt_IMark(st->Ist.IMark.addr,
4477 st->Ist.IMark.len,
4478 st->Ist.IMark.delta);
sewardjf9517d02005-11-28 13:39:37 +00004479 case Ist_NoOp:
4480 return IRStmt_NoOp();
sewardjc4356f02007-11-09 21:15:04 +00004481 case Ist_MBE:
4482 return IRStmt_MBE(st->Ist.MBE.event);
sewardje9d8a262009-07-01 08:06:34 +00004483 case Ist_CAS:
4484 cas = st->Ist.CAS.details;
4485 cas2 = mkIRCAS(
4486 cas->oldHi, cas->oldLo, cas->end,
4487 atbSubst_Expr(env, cas->addr),
4488 cas->expdHi ? atbSubst_Expr(env, cas->expdHi) : NULL,
4489 atbSubst_Expr(env, cas->expdLo),
4490 cas->dataHi ? atbSubst_Expr(env, cas->dataHi) : NULL,
4491 atbSubst_Expr(env, cas->dataLo)
4492 );
4493 return IRStmt_CAS(cas2);
sewardje768e922009-11-26 17:17:37 +00004494 case Ist_LLSC:
4495 return IRStmt_LLSC(
4496 st->Ist.LLSC.end,
4497 st->Ist.LLSC.result,
4498 atbSubst_Expr(env, st->Ist.LLSC.addr),
4499 st->Ist.LLSC.storedata
4500 ? atbSubst_Expr(env, st->Ist.LLSC.storedata) : NULL
4501 );
sewardjf9517d02005-11-28 13:39:37 +00004502 case Ist_Dirty:
4503 d = st->Ist.Dirty.details;
4504 d2 = emptyIRDirty();
4505 *d2 = *d;
4506 if (d2->mFx != Ifx_None)
4507 d2->mAddr = atbSubst_Expr(env, d2->mAddr);
4508 d2->guard = atbSubst_Expr(env, d2->guard);
4509 for (i = 0; d2->args[i]; i++)
4510 d2->args[i] = atbSubst_Expr(env, d2->args[i]);
4511 return IRStmt_Dirty(d2);
4512 default:
4513 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
4514 vpanic("atbSubst_Stmt");
4515 }
4516}
4517
sewardjdd40fdf2006-12-24 02:20:24 +00004518/* notstatic */ void ado_treebuild_BB ( IRSB* bb )
sewardjf9517d02005-11-28 13:39:37 +00004519{
4520 Int i, j, k, m;
4521 Bool stmtPuts, stmtStores, invalidateMe;
sewardj29632392004-08-22 02:38:11 +00004522 IRStmt* st;
4523 IRStmt* st2;
sewardjf9517d02005-11-28 13:39:37 +00004524 ATmpInfo env[A_NENV];
sewardj29632392004-08-22 02:38:11 +00004525
sewardjc9ad1152004-10-14 00:08:21 +00004526 Int n_tmps = bb->tyenv->types_used;
sewardjf9517d02005-11-28 13:39:37 +00004527 UShort* uses = LibVEX_Alloc(n_tmps * sizeof(UShort));
sewardj29632392004-08-22 02:38:11 +00004528
4529 /* Phase 1. Scan forwards in bb, counting use occurrences of each
4530 temp. Also count occurrences in the bb->next field. */
4531
sewardjf9517d02005-11-28 13:39:37 +00004532 for (i = 0; i < n_tmps; i++)
4533 uses[i] = 0;
4534
sewardj29632392004-08-22 02:38:11 +00004535 for (i = 0; i < bb->stmts_used; i++) {
4536 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00004537 if (st->tag == Ist_NoOp)
sewardj29632392004-08-22 02:38:11 +00004538 continue;
sewardjf9517d02005-11-28 13:39:37 +00004539 aoccCount_Stmt( uses, st );
sewardj29632392004-08-22 02:38:11 +00004540 }
sewardjf9517d02005-11-28 13:39:37 +00004541 aoccCount_Expr(uses, bb->next );
sewardj29632392004-08-22 02:38:11 +00004542
sewardjc9ad1152004-10-14 00:08:21 +00004543# if 0
sewardjf9517d02005-11-28 13:39:37 +00004544 for (i = 0; i < n_tmps; i++) {
4545 if (uses[i] == 0)
sewardj29632392004-08-22 02:38:11 +00004546 continue;
sewardjf9517d02005-11-28 13:39:37 +00004547 ppIRTemp( (IRTemp)i );
4548 vex_printf(" used %d\n", (Int)uses[i] );
sewardj29632392004-08-22 02:38:11 +00004549 }
sewardjc9ad1152004-10-14 00:08:21 +00004550# endif
sewardj29632392004-08-22 02:38:11 +00004551
sewardjf9517d02005-11-28 13:39:37 +00004552 /* Phase 2. Scan forwards in bb. For each statement in turn:
sewardj29632392004-08-22 02:38:11 +00004553
sewardjf9517d02005-11-28 13:39:37 +00004554 If the env is full, emit the end element. This guarantees
4555 there is at least one free slot in the following.
sewardj29632392004-08-22 02:38:11 +00004556
sewardjf9517d02005-11-28 13:39:37 +00004557 On seeing 't = E', occ(t)==1,
4558 let E'=env(E)
4559 delete this stmt
4560 add t -> E' to the front of the env
4561 Examine E' and set the hints for E' appropriately
sewardj29632392004-08-22 02:38:11 +00004562 (doesLoad? doesGet?)
4563
sewardjf9517d02005-11-28 13:39:37 +00004564 On seeing any other stmt,
sewardj29632392004-08-22 02:38:11 +00004565 let stmt' = env(stmt)
4566 remove from env any 't=E' binds invalidated by stmt
4567 emit the invalidated stmts
4568 emit stmt'
sewardjf9517d02005-11-28 13:39:37 +00004569 compact any holes in env
4570 by sliding entries towards the front
sewardj29632392004-08-22 02:38:11 +00004571
sewardjf9517d02005-11-28 13:39:37 +00004572 Finally, apply env to bb->next.
sewardj29632392004-08-22 02:38:11 +00004573 */
4574
sewardjf9517d02005-11-28 13:39:37 +00004575 for (i = 0; i < A_NENV; i++) {
4576 env[i].bindee = NULL;
4577 env[i].binder = IRTemp_INVALID;
4578 }
4579
sewardj29632392004-08-22 02:38:11 +00004580 /* The stmts in bb are being reordered, and we are guaranteed to
4581 end up with no more than the number we started with. Use i to
4582 be the cursor of the current stmt examined and j <= i to be that
4583 for the current stmt being written.
4584 */
4585 j = 0;
4586 for (i = 0; i < bb->stmts_used; i++) {
sewardjf9517d02005-11-28 13:39:37 +00004587
sewardj29632392004-08-22 02:38:11 +00004588 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00004589 if (st->tag == Ist_NoOp)
sewardj29632392004-08-22 02:38:11 +00004590 continue;
4591
sewardjf9517d02005-11-28 13:39:37 +00004592 /* Ensure there's at least one space in the env, by emitting
4593 the oldest binding if necessary. */
4594 if (env[A_NENV-1].bindee != NULL) {
sewardjdd40fdf2006-12-24 02:20:24 +00004595 bb->stmts[j] = IRStmt_WrTmp( env[A_NENV-1].binder,
4596 env[A_NENV-1].bindee );
sewardjf9517d02005-11-28 13:39:37 +00004597 j++;
4598 vassert(j <= i);
4599 env[A_NENV-1].bindee = NULL;
4600 }
4601
4602 /* Consider current stmt. */
sewardjdd40fdf2006-12-24 02:20:24 +00004603 if (st->tag == Ist_WrTmp && uses[st->Ist.WrTmp.tmp] <= 1) {
sewardj63327402006-01-25 03:26:27 +00004604 IRExpr *e, *e2;
sewardjf9517d02005-11-28 13:39:37 +00004605
4606 /* optional extra: dump dead bindings as we find them.
4607 Removes the need for a prior dead-code removal pass. */
sewardjdd40fdf2006-12-24 02:20:24 +00004608 if (uses[st->Ist.WrTmp.tmp] == 0) {
sewardjb183b852006-02-03 16:08:03 +00004609 if (0) vex_printf("DEAD binding\n");
sewardjf9517d02005-11-28 13:39:37 +00004610 continue; /* for (i = 0; i < bb->stmts_used; i++) loop */
sewardj29632392004-08-22 02:38:11 +00004611 }
sewardjdd40fdf2006-12-24 02:20:24 +00004612 vassert(uses[st->Ist.WrTmp.tmp] == 1);
sewardjf9517d02005-11-28 13:39:37 +00004613
4614 /* ok, we have 't = E', occ(t)==1. Do the abovementioned
4615 actions. */
sewardjdd40fdf2006-12-24 02:20:24 +00004616 e = st->Ist.WrTmp.data;
sewardj63327402006-01-25 03:26:27 +00004617 e2 = atbSubst_Expr(env, e);
sewardjdd40fdf2006-12-24 02:20:24 +00004618 addToEnvFront(env, st->Ist.WrTmp.tmp, e2);
sewardjf9517d02005-11-28 13:39:37 +00004619 setHints_Expr(&env[0].doesLoad, &env[0].doesGet, e2);
4620 /* don't advance j, as we are deleting this stmt and instead
4621 holding it temporarily in the env. */
4622 continue; /* for (i = 0; i < bb->stmts_used; i++) loop */
sewardj29632392004-08-22 02:38:11 +00004623 }
4624
4625 /* we get here for any other kind of statement. */
4626 /* 'use up' any bindings required by the current statement. */
sewardjf9517d02005-11-28 13:39:37 +00004627 st2 = atbSubst_Stmt(env, st);
sewardj29632392004-08-22 02:38:11 +00004628
sewardjf9517d02005-11-28 13:39:37 +00004629 /* Now, before this stmt, dump any bindings in env that it
4630 invalidates. These need to be dumped in the order in which
4631 they originally entered env -- that means from oldest to
4632 youngest. */
sewardj3e838932005-01-07 12:09:15 +00004633
sewardjf9517d02005-11-28 13:39:37 +00004634 /* stmtPuts/stmtStores characterise what the stmt under
sewardje9d8a262009-07-01 08:06:34 +00004635 consideration does, or might do (sidely safe @ True). */
4636 stmtPuts
4637 = toBool( st->tag == Ist_Put
4638 || st->tag == Ist_PutI
4639 || st->tag == Ist_Dirty );
sewardj29632392004-08-22 02:38:11 +00004640
sewardje9d8a262009-07-01 08:06:34 +00004641 /* be True if this stmt writes memory or might do (==> we don't
4642 want to reorder other loads or stores relative to it). Also,
sewardje768e922009-11-26 17:17:37 +00004643 both LL and SC fall under this classification, since we
sewardje9d8a262009-07-01 08:06:34 +00004644 really ought to be conservative and not reorder any other
sewardje768e922009-11-26 17:17:37 +00004645 memory transactions relative to them. */
sewardje9d8a262009-07-01 08:06:34 +00004646 stmtStores
4647 = toBool( st->tag == Ist_Store
sewardje768e922009-11-26 17:17:37 +00004648 || st->tag == Ist_Dirty
sewardj0f621982012-04-12 21:05:16 +00004649 || st->tag == Ist_LLSC
4650 || st->tag == Ist_CAS );
sewardj29632392004-08-22 02:38:11 +00004651
sewardjf9517d02005-11-28 13:39:37 +00004652 for (k = A_NENV-1; k >= 0; k--) {
4653 if (env[k].bindee == NULL)
4654 continue;
4655 /* Compare the actions of this stmt with the actions of
4656 binding 'k', to see if they invalidate the binding. */
4657 invalidateMe
sewardj9d2e7692005-02-07 01:11:31 +00004658 = toBool(
4659 /* a store invalidates loaded data */
sewardjf9517d02005-11-28 13:39:37 +00004660 (env[k].doesLoad && stmtStores)
sewardj4c5f6d52004-10-26 13:25:33 +00004661 /* a put invalidates get'd data */
sewardjf9517d02005-11-28 13:39:37 +00004662 || (env[k].doesGet && stmtPuts)
sewardj4c5f6d52004-10-26 13:25:33 +00004663 /* a put invalidates loaded data. Note, we could do
4664 much better here in the sense that we only need to
4665 invalidate trees containing loads if the Put in
4666 question is marked as requiring precise
4667 exceptions. */
sewardjf9517d02005-11-28 13:39:37 +00004668 || (env[k].doesLoad && stmtPuts)
sewardjc4356f02007-11-09 21:15:04 +00004669 /* probably overly conservative: a memory bus event
sewardj3e838932005-01-07 12:09:15 +00004670 invalidates absolutely everything, so that all
4671 computation prior to it is forced to complete before
sewardjc4356f02007-11-09 21:15:04 +00004672 proceeding with the event (fence,lock,unlock). */
4673 || st->tag == Ist_MBE
sewardj5a9ffab2005-05-12 17:55:01 +00004674 /* also be (probably overly) paranoid re AbiHints */
4675 || st->tag == Ist_AbiHint
sewardj9d2e7692005-02-07 01:11:31 +00004676 );
sewardjf9517d02005-11-28 13:39:37 +00004677 if (invalidateMe) {
sewardjdd40fdf2006-12-24 02:20:24 +00004678 bb->stmts[j] = IRStmt_WrTmp( env[k].binder, env[k].bindee );
sewardjf9517d02005-11-28 13:39:37 +00004679 j++;
4680 vassert(j <= i);
4681 env[k].bindee = NULL;
4682 }
sewardj29632392004-08-22 02:38:11 +00004683 }
4684
sewardjf9517d02005-11-28 13:39:37 +00004685 /* Slide in-use entries in env up to the front */
4686 m = 0;
4687 for (k = 0; k < A_NENV; k++) {
4688 if (env[k].bindee != NULL) {
4689 env[m] = env[k];
4690 m++;
4691 }
4692 }
4693 for (m = m; m < A_NENV; m++) {
4694 env[m].bindee = NULL;
4695 }
sewardj29632392004-08-22 02:38:11 +00004696
4697 /* finally, emit the substituted statement */
4698 bb->stmts[j] = st2;
sewardjf9517d02005-11-28 13:39:37 +00004699 /* vex_printf("**2 "); ppIRStmt(bb->stmts[j]); vex_printf("\n"); */
sewardj29632392004-08-22 02:38:11 +00004700 j++;
4701
4702 vassert(j <= i+1);
4703 } /* for each stmt in the original bb ... */
4704
4705 /* Finally ... substitute the ->next field as much as possible, and
4706 dump any left-over bindings. Hmm. Perhaps there should be no
4707 left over bindings? Or any left-over bindings are
4708 by definition dead? */
sewardjf9517d02005-11-28 13:39:37 +00004709 bb->next = atbSubst_Expr(env, bb->next);
sewardj29632392004-08-22 02:38:11 +00004710 bb->stmts_used = j;
4711}
4712
4713
sewardj695cff92004-10-13 14:50:14 +00004714/*---------------------------------------------------------------*/
sewardjedf4d692004-08-17 13:52:58 +00004715/*--- iropt main ---*/
4716/*---------------------------------------------------------------*/
4717
sewardjb183b852006-02-03 16:08:03 +00004718static Bool iropt_verbose = False; /* True; */
sewardj4345f7a2004-09-22 19:49:27 +00004719
4720
sewardj4345f7a2004-09-22 19:49:27 +00004721/* Do a simple cleanup pass on bb. This is: redundant Get removal,
4722 redundant Put removal, constant propagation, dead code removal,
4723 clean helper specialisation, and dead code removal (again).
sewardjb9230752004-12-29 19:25:06 +00004724*/
sewardj695cff92004-10-13 14:50:14 +00004725
sewardj4345f7a2004-09-22 19:49:27 +00004726
4727static
sewardjdd40fdf2006-12-24 02:20:24 +00004728IRSB* cheap_transformations (
4729 IRSB* bb,
sewardjbe917912010-08-22 12:38:53 +00004730 IRExpr* (*specHelper) (HChar*, IRExpr**, IRStmt**, Int),
sewardj8d2291c2004-10-25 14:50:21 +00004731 Bool (*preciseMemExnsFn)(Int,Int)
4732 )
sewardj4345f7a2004-09-22 19:49:27 +00004733{
4734 redundant_get_removal_BB ( bb );
4735 if (iropt_verbose) {
4736 vex_printf("\n========= REDUNDANT GET\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004737 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004738 }
sewardj044a2152004-10-21 10:22:10 +00004739
sewardj8d2291c2004-10-25 14:50:21 +00004740 redundant_put_removal_BB ( bb, preciseMemExnsFn );
sewardj4345f7a2004-09-22 19:49:27 +00004741 if (iropt_verbose) {
4742 vex_printf("\n========= REDUNDANT PUT\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004743 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004744 }
sewardj044a2152004-10-21 10:22:10 +00004745
sewardj4345f7a2004-09-22 19:49:27 +00004746 bb = cprop_BB ( bb );
4747 if (iropt_verbose) {
4748 vex_printf("\n========= CPROPD\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004749 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004750 }
4751
sewardj49651f42004-10-28 22:11:04 +00004752 do_deadcode_BB ( bb );
sewardj4345f7a2004-09-22 19:49:27 +00004753 if (iropt_verbose) {
4754 vex_printf("\n========= DEAD\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004755 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004756 }
4757
sewardjb9230752004-12-29 19:25:06 +00004758 bb = spec_helpers_BB ( bb, specHelper );
sewardj49651f42004-10-28 22:11:04 +00004759 do_deadcode_BB ( bb );
sewardj4345f7a2004-09-22 19:49:27 +00004760 if (iropt_verbose) {
4761 vex_printf("\n========= SPECd \n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004762 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004763 }
4764
4765 return bb;
4766}
4767
sewardj695cff92004-10-13 14:50:14 +00004768
4769/* Do some more expensive transformations on bb, which are aimed at
4770 optimising as much as possible in the presence of GetI and PutI. */
4771
4772static
sewardjdd40fdf2006-12-24 02:20:24 +00004773IRSB* expensive_transformations( IRSB* bb )
sewardj695cff92004-10-13 14:50:14 +00004774{
sewardj9b0cc582006-02-04 15:24:00 +00004775 (void)do_cse_BB( bb );
sewardj695cff92004-10-13 14:50:14 +00004776 collapse_AddSub_chains_BB( bb );
sewardj08210532004-12-29 17:09:11 +00004777 do_redundant_GetI_elimination( bb );
sewardj695cff92004-10-13 14:50:14 +00004778 do_redundant_PutI_elimination( bb );
sewardj49651f42004-10-28 22:11:04 +00004779 do_deadcode_BB( bb );
sewardjb9230752004-12-29 19:25:06 +00004780 return bb;
sewardj695cff92004-10-13 14:50:14 +00004781}
4782
4783
sewardjb183b852006-02-03 16:08:03 +00004784/* Scan a flattened BB to look for signs that more expensive
4785 optimisations might be useful:
4786 - find out if there are any GetIs and PutIs
4787 - find out if there are any floating or vector-typed temporaries
4788*/
sewardj695cff92004-10-13 14:50:14 +00004789
sewardjb183b852006-02-03 16:08:03 +00004790static void considerExpensives ( /*OUT*/Bool* hasGetIorPutI,
4791 /*OUT*/Bool* hasVorFtemps,
sewardjdd40fdf2006-12-24 02:20:24 +00004792 IRSB* bb )
sewardj4345f7a2004-09-22 19:49:27 +00004793{
sewardje9d8a262009-07-01 08:06:34 +00004794 Int i, j;
4795 IRStmt* st;
sewardj4345f7a2004-09-22 19:49:27 +00004796 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00004797 IRCAS* cas;
sewardj4345f7a2004-09-22 19:49:27 +00004798
sewardjb183b852006-02-03 16:08:03 +00004799 *hasGetIorPutI = False;
4800 *hasVorFtemps = False;
4801
sewardj4345f7a2004-09-22 19:49:27 +00004802 for (i = 0; i < bb->stmts_used; i++) {
4803 st = bb->stmts[i];
sewardj4345f7a2004-09-22 19:49:27 +00004804 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00004805 case Ist_AbiHint:
4806 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +00004807 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +00004808 break;
sewardj4345f7a2004-09-22 19:49:27 +00004809 case Ist_PutI:
sewardjb183b852006-02-03 16:08:03 +00004810 *hasGetIorPutI = True;
4811 break;
sewardjdd40fdf2006-12-24 02:20:24 +00004812 case Ist_WrTmp:
4813 if (st->Ist.WrTmp.data->tag == Iex_GetI)
sewardjb183b852006-02-03 16:08:03 +00004814 *hasGetIorPutI = True;
sewardjdd40fdf2006-12-24 02:20:24 +00004815 switch (typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp)) {
sewardjb183b852006-02-03 16:08:03 +00004816 case Ity_I1: case Ity_I8: case Ity_I16:
4817 case Ity_I32: case Ity_I64: case Ity_I128:
4818 break;
sewardj2019a972011-03-07 16:04:07 +00004819 case Ity_F32: case Ity_F64: case Ity_F128: case Ity_V128:
sewardjb183b852006-02-03 16:08:03 +00004820 *hasVorFtemps = True;
4821 break;
sewardjc6bbd472012-04-02 10:20:48 +00004822 case Ity_D32: case Ity_D64: case Ity_D128:
4823 *hasVorFtemps = True;
4824 break;
sewardjb183b852006-02-03 16:08:03 +00004825 default:
4826 goto bad;
4827 }
sewardj4345f7a2004-09-22 19:49:27 +00004828 break;
4829 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00004830 vassert(isIRAtom(st->Ist.Put.data));
sewardj4345f7a2004-09-22 19:49:27 +00004831 break;
sewardjaf1ceca2005-06-30 23:31:27 +00004832 case Ist_Store:
4833 vassert(isIRAtom(st->Ist.Store.addr));
4834 vassert(isIRAtom(st->Ist.Store.data));
sewardj4345f7a2004-09-22 19:49:27 +00004835 break;
sewardje9d8a262009-07-01 08:06:34 +00004836 case Ist_CAS:
4837 cas = st->Ist.CAS.details;
4838 vassert(isIRAtom(cas->addr));
4839 vassert(cas->expdHi == NULL || isIRAtom(cas->expdHi));
4840 vassert(isIRAtom(cas->expdLo));
4841 vassert(cas->dataHi == NULL || isIRAtom(cas->dataHi));
4842 vassert(isIRAtom(cas->dataLo));
4843 break;
sewardje768e922009-11-26 17:17:37 +00004844 case Ist_LLSC:
4845 vassert(isIRAtom(st->Ist.LLSC.addr));
4846 if (st->Ist.LLSC.storedata)
4847 vassert(isIRAtom(st->Ist.LLSC.storedata));
4848 break;
sewardj4345f7a2004-09-22 19:49:27 +00004849 case Ist_Dirty:
4850 d = st->Ist.Dirty.details;
sewardj496a58d2005-03-20 18:44:44 +00004851 vassert(isIRAtom(d->guard));
sewardj4345f7a2004-09-22 19:49:27 +00004852 for (j = 0; d->args[j]; j++)
sewardj496a58d2005-03-20 18:44:44 +00004853 vassert(isIRAtom(d->args[j]));
sewardj4345f7a2004-09-22 19:49:27 +00004854 if (d->mFx != Ifx_None)
sewardj496a58d2005-03-20 18:44:44 +00004855 vassert(isIRAtom(d->mAddr));
sewardj4345f7a2004-09-22 19:49:27 +00004856 break;
sewardjd2445f62005-03-21 00:15:53 +00004857 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00004858 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00004859 case Ist_MBE:
sewardj3e838932005-01-07 12:09:15 +00004860 break;
4861 case Ist_Exit:
sewardj496a58d2005-03-20 18:44:44 +00004862 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj3e838932005-01-07 12:09:15 +00004863 break;
sewardj4345f7a2004-09-22 19:49:27 +00004864 default:
sewardjb183b852006-02-03 16:08:03 +00004865 bad:
sewardj4345f7a2004-09-22 19:49:27 +00004866 ppIRStmt(st);
sewardje768e922009-11-26 17:17:37 +00004867 vpanic("considerExpensives");
sewardj4345f7a2004-09-22 19:49:27 +00004868 }
sewardj4345f7a2004-09-22 19:49:27 +00004869 }
sewardj4345f7a2004-09-22 19:49:27 +00004870}
4871
4872
sewardj695cff92004-10-13 14:50:14 +00004873/* ---------------- The main iropt entry point. ---------------- */
4874
sewardjedf4d692004-08-17 13:52:58 +00004875/* exported from this file */
sewardj695cff92004-10-13 14:50:14 +00004876/* Rules of the game:
4877
4878 - IRExpr/IRStmt trees should be treated as immutable, as they
4879 may get shared. So never change a field of such a tree node;
4880 instead construct and return a new one if needed.
4881*/
4882
sewardj4345f7a2004-09-22 19:49:27 +00004883
sewardjbe917912010-08-22 12:38:53 +00004884IRSB* do_iropt_BB(
4885 IRSB* bb0,
4886 IRExpr* (*specHelper) (HChar*, IRExpr**, IRStmt**, Int),
4887 Bool (*preciseMemExnsFn)(Int,Int),
4888 Addr64 guest_addr,
4889 VexArch guest_arch
4890 )
sewardjedf4d692004-08-17 13:52:58 +00004891{
sewardj9d2e7692005-02-07 01:11:31 +00004892 static Int n_total = 0;
4893 static Int n_expensive = 0;
sewardj29632392004-08-22 02:38:11 +00004894
sewardjb183b852006-02-03 16:08:03 +00004895 Bool hasGetIorPutI, hasVorFtemps;
sewardjdd40fdf2006-12-24 02:20:24 +00004896 IRSB *bb, *bb2;
sewardj8c2c10b2004-10-16 20:51:52 +00004897
sewardj4345f7a2004-09-22 19:49:27 +00004898 n_total++;
4899
4900 /* First flatten the block out, since all other
4901 phases assume flat code. */
4902
4903 bb = flatten_BB ( bb0 );
4904
4905 if (iropt_verbose) {
4906 vex_printf("\n========= FLAT\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004907 ppIRSB(bb);
sewardj84be7372004-08-18 13:59:33 +00004908 }
sewardjd7217032004-08-19 10:49:10 +00004909
sewardj08210532004-12-29 17:09:11 +00004910 /* If at level 0, stop now. */
4911 if (vex_control.iropt_level <= 0) return bb;
4912
sewardj695cff92004-10-13 14:50:14 +00004913 /* Now do a preliminary cleanup pass, and figure out if we also
4914 need to do 'expensive' optimisations. Expensive optimisations
4915 are deemed necessary if the block contains any GetIs or PutIs.
4916 If needed, do expensive transformations and then another cheap
4917 cleanup pass. */
sewardj4345f7a2004-09-22 19:49:27 +00004918
sewardj8d2291c2004-10-25 14:50:21 +00004919 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj695cff92004-10-13 14:50:14 +00004920
sewardjbe917912010-08-22 12:38:53 +00004921 if (guest_arch == VexArchARM) {
4922 /* Translating Thumb2 code produces a lot of chaff. We have to
4923 work extra hard to get rid of it. */
4924 bb = cprop_BB(bb);
4925 bb = spec_helpers_BB ( bb, specHelper );
4926 redundant_put_removal_BB ( bb, preciseMemExnsFn );
sewardjd5436ce2011-05-01 18:36:51 +00004927 do_cse_BB( bb );
sewardjbe917912010-08-22 12:38:53 +00004928 do_deadcode_BB( bb );
4929 }
4930
sewardj08613742004-10-25 13:01:45 +00004931 if (vex_control.iropt_level > 1) {
sewardjb183b852006-02-03 16:08:03 +00004932
4933 /* Peer at what we have, to decide how much more effort to throw
4934 at it. */
4935 considerExpensives( &hasGetIorPutI, &hasVorFtemps, bb );
4936
sewardj9b0cc582006-02-04 15:24:00 +00004937 if (hasVorFtemps && !hasGetIorPutI) {
sewardjb183b852006-02-03 16:08:03 +00004938 /* If any evidence of FP or Vector activity, CSE, as that
4939 tends to mop up all manner of lardy code to do with
sewardj9b0cc582006-02-04 15:24:00 +00004940 rounding modes. Don't bother if hasGetIorPutI since that
4941 case leads into the expensive transformations, which do
4942 CSE anyway. */
4943 (void)do_cse_BB( bb );
sewardjb183b852006-02-03 16:08:03 +00004944 do_deadcode_BB( bb );
4945 }
4946
4947 if (hasGetIorPutI) {
sewardj9b0cc582006-02-04 15:24:00 +00004948 Bool cses;
sewardj39555aa2004-10-24 22:29:19 +00004949 n_expensive++;
sewardj39555aa2004-10-24 22:29:19 +00004950 if (DEBUG_IROPT)
4951 vex_printf("***** EXPENSIVE %d %d\n", n_total, n_expensive);
sewardj695cff92004-10-13 14:50:14 +00004952 bb = expensive_transformations( bb );
sewardj8d2291c2004-10-25 14:50:21 +00004953 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj9b0cc582006-02-04 15:24:00 +00004954 /* Potentially common up GetIs */
4955 cses = do_cse_BB( bb );
4956 if (cses)
4957 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj695cff92004-10-13 14:50:14 +00004958 }
sewardj39555aa2004-10-24 22:29:19 +00004959
4960 /* Now have a go at unrolling simple (single-BB) loops. If
4961 successful, clean up the results as much as possible. */
4962
4963 bb2 = maybe_loop_unroll_BB( bb, guest_addr );
4964 if (bb2) {
sewardj8d2291c2004-10-25 14:50:21 +00004965 bb = cheap_transformations( bb2, specHelper, preciseMemExnsFn );
sewardjb183b852006-02-03 16:08:03 +00004966 if (hasGetIorPutI) {
sewardj39555aa2004-10-24 22:29:19 +00004967 bb = expensive_transformations( bb );
sewardj8d2291c2004-10-25 14:50:21 +00004968 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj39555aa2004-10-24 22:29:19 +00004969 } else {
4970 /* at least do CSE and dead code removal */
sewardjfe1ccfc2004-11-11 02:14:45 +00004971 do_cse_BB( bb );
sewardj49651f42004-10-28 22:11:04 +00004972 do_deadcode_BB( bb );
sewardj39555aa2004-10-24 22:29:19 +00004973 }
4974 if (0) vex_printf("vex iropt: unrolled a loop\n");
4975 }
4976
sewardjd7217032004-08-19 10:49:10 +00004977 }
4978
sewardj4345f7a2004-09-22 19:49:27 +00004979 return bb;
sewardjedf4d692004-08-17 13:52:58 +00004980}
4981
4982
sewardja1a370f2004-08-17 13:31:55 +00004983/*---------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +00004984/*--- end ir_opt.c ---*/
sewardja1a370f2004-08-17 13:31:55 +00004985/*---------------------------------------------------------------*/