blob: 0698cf7d50a95008b65cc982fda721f22367bd33 [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
sewardja1a370f2004-08-17 13:31:55 +000049
sewardj08210532004-12-29 17:09:11 +000050/* What iropt does, 29 Dec 04.
51
sewardjf6c8ebf2007-02-06 01:52:52 +000052 It takes an IRSB and produces a new one with the same meaning,
sewardj08210532004-12-29 17:09:11 +000053 defined thus:
54
55 After execution of the new BB, all guest state and guest memory is
56 the same as after execution of the original. This is true
57 regardless of how the block was exited (at the end vs side exit).
58
59 In addition, parts of the guest state will be identical to that
60 created by execution of the original at the following observation
61 points:
62
63 * In a dirty helper call, any parts of the guest state that the
64 helper states that it reads or modifies will be up to date.
65 Also, guest memory will be up to date. Parts of the guest state
66 not marked as being read or modified by the helper cannot be
67 assumed to be up-to-date at the point where the helper is called.
68
69 * Immediately prior to any load or store, those parts of the guest
70 state marked as requiring precise exceptions will be up to date.
71 Also, guest memory will be up to date. Parts of the guest state
72 not marked as requiring precise exceptions cannot be assumed to
73 be up-to-date at the point of the load/store.
74
75 The relative order of loads and stores (including loads/stores of
76 guest memory done by dirty helpers annotated as such) is not
77 changed. However, the relative order of loads with no intervening
78 stores/modifies may be changed.
79
80 Transformation order
81 ~~~~~~~~~~~~~~~~~~~~
82
83 There are three levels of optimisation, controlled by
84 vex_control.iropt_level. Define first:
85
86 "Cheap transformations" are the following sequence:
87 * Redundant-Get removal
88 * Redundant-Put removal
89 * Constant propagation/folding
90 * Dead code removal
91 * Specialisation of clean helper functions
92 * Dead code removal
93
94 "Expensive transformations" are the following sequence:
95 * CSE
96 * Folding of add/sub chains
97 * Redundant-GetI removal
98 * Redundant-PutI removal
99 * Dead code removal
sewardj08210532004-12-29 17:09:11 +0000100
101 Then the transformations are as follows, as defined by
102 vex_control.iropt_level:
103
104 Level 0:
105 * Flatten into atomic form.
106
107 Level 1: the following sequence:
108 * Flatten into atomic form.
109 * Cheap transformations.
sewardj08210532004-12-29 17:09:11 +0000110
111 Level 2: the following sequence
112 * Flatten into atomic form.
113 * Cheap transformations.
sewardjb183b852006-02-03 16:08:03 +0000114 * If block contains any floating or vector types, CSE.
sewardj08210532004-12-29 17:09:11 +0000115 * If block contains GetI or PutI, Expensive transformations.
116 * Try unrolling loops. Three possible outcomes:
117 - No effect: do nothing more.
118 - Unrolled a loop, and block does not contain GetI or PutI:
119 Do: * CSE
120 * Dead code removal
sewardj08210532004-12-29 17:09:11 +0000121 - Unrolled a loop, and block contains GetI or PutI:
122 Do: * Expensive transformations
123 * Cheap transformations
sewardj08210532004-12-29 17:09:11 +0000124*/
125
sewardj98430292004-12-29 17:34:50 +0000126/* Implementation notes, 29 Dec 04.
127
128 TODO (important): I think rPutI removal ignores precise exceptions
129 and is therefore in a sense, wrong. In the sense that PutIs are
130 assumed not to write parts of the guest state that we need to have
131 up-to-date at loads/stores. So far on x86 guest that has not
132 mattered since indeed only the x87 FP registers and tags are
133 accessed using GetI/PutI, and there is no need so far for them to
134 be up to date at mem exception points. The rPutI pass should be
135 fixed.
sewardjfb44d552004-10-25 09:48:47 +0000136
sewardj4c5f6d52004-10-26 13:25:33 +0000137 TODO: improve pessimistic handling of precise exceptions
138 in the tree builder.
139
sewardjfb44d552004-10-25 09:48:47 +0000140 TODO: check interaction of rGetI and dirty helpers.
sewardjc0b42282004-10-12 13:44:12 +0000141
142 F64i constants are treated differently from other constants.
143 They are not regarded as atoms, and instead lifted off and
144 bound to temps. This allows them to participate in CSE, which
145 is important for getting good performance for x86 guest code.
sewardj695cff92004-10-13 14:50:14 +0000146
sewardja5aa9cf2004-10-15 22:56:38 +0000147 CSE up F64 literals (already doing F64is)
sewardj4c5f6d52004-10-26 13:25:33 +0000148
149 CSE: consider carefully the requirement for precise exns
sewardj98430292004-12-29 17:34:50 +0000150 prior to making CSE any more aggressive. */
sewardjc0b42282004-10-12 13:44:12 +0000151
152
sewardja1a370f2004-08-17 13:31:55 +0000153/*---------------------------------------------------------------*/
154/*--- Finite mappery, of a sort ---*/
155/*---------------------------------------------------------------*/
156
sewardj08210532004-12-29 17:09:11 +0000157/* General map from HWord-sized thing HWord-sized thing. Could be by
158 hashing, but it's not clear whether or not this would really be any
159 faster. */
sewardja1a370f2004-08-17 13:31:55 +0000160
161typedef
162 struct {
163 Bool* inuse;
sewardjea602bc2004-10-14 21:40:12 +0000164 HWord* key;
165 HWord* val;
sewardja1a370f2004-08-17 13:31:55 +0000166 Int size;
167 Int used;
168 }
sewardjea602bc2004-10-14 21:40:12 +0000169 HashHW;
sewardja1a370f2004-08-17 13:31:55 +0000170
sewardjea602bc2004-10-14 21:40:12 +0000171static HashHW* newHHW ( void )
sewardja1a370f2004-08-17 13:31:55 +0000172{
sewardjea602bc2004-10-14 21:40:12 +0000173 HashHW* h = LibVEX_Alloc(sizeof(HashHW));
sewardj29632392004-08-22 02:38:11 +0000174 h->size = 8;
sewardja1a370f2004-08-17 13:31:55 +0000175 h->used = 0;
176 h->inuse = LibVEX_Alloc(h->size * sizeof(Bool));
sewardjea602bc2004-10-14 21:40:12 +0000177 h->key = LibVEX_Alloc(h->size * sizeof(HWord));
178 h->val = LibVEX_Alloc(h->size * sizeof(HWord));
sewardja1a370f2004-08-17 13:31:55 +0000179 return h;
180}
181
182
sewardj84be7372004-08-18 13:59:33 +0000183/* Look up key in the map. */
sewardja1a370f2004-08-17 13:31:55 +0000184
sewardjea602bc2004-10-14 21:40:12 +0000185static Bool lookupHHW ( HashHW* h, /*OUT*/HWord* val, HWord key )
sewardja1a370f2004-08-17 13:31:55 +0000186{
187 Int i;
sewardj08210532004-12-29 17:09:11 +0000188 /* vex_printf("lookupHHW(%llx)\n", key ); */
sewardja1a370f2004-08-17 13:31:55 +0000189 for (i = 0; i < h->used; i++) {
190 if (h->inuse[i] && h->key[i] == key) {
sewardj39e3f242004-08-18 16:54:52 +0000191 if (val)
192 *val = h->val[i];
sewardja1a370f2004-08-17 13:31:55 +0000193 return True;
194 }
195 }
196 return False;
197}
198
199
sewardja1a370f2004-08-17 13:31:55 +0000200/* Add key->val to the map. Replaces any existing binding for key. */
201
sewardjea602bc2004-10-14 21:40:12 +0000202static void addToHHW ( HashHW* h, HWord key, HWord val )
sewardja1a370f2004-08-17 13:31:55 +0000203{
204 Int i, j;
sewardj08210532004-12-29 17:09:11 +0000205 /* vex_printf("addToHHW(%llx, %llx)\n", key, val); */
sewardja1a370f2004-08-17 13:31:55 +0000206
207 /* Find and replace existing binding, if any. */
208 for (i = 0; i < h->used; i++) {
209 if (h->inuse[i] && h->key[i] == key) {
210 h->val[i] = val;
211 return;
212 }
213 }
214
215 /* Ensure a space is available. */
216 if (h->used == h->size) {
217 /* Copy into arrays twice the size. */
218 Bool* inuse2 = LibVEX_Alloc(2 * h->size * sizeof(Bool));
sewardjea602bc2004-10-14 21:40:12 +0000219 HWord* key2 = LibVEX_Alloc(2 * h->size * sizeof(HWord));
220 HWord* val2 = LibVEX_Alloc(2 * h->size * sizeof(HWord));
sewardja1a370f2004-08-17 13:31:55 +0000221 for (i = j = 0; i < h->size; i++) {
222 if (!h->inuse[i]) continue;
223 inuse2[j] = True;
224 key2[j] = h->key[i];
225 val2[j] = h->val[i];
226 j++;
227 }
228 h->used = j;
229 h->size *= 2;
230 h->inuse = inuse2;
231 h->key = key2;
232 h->val = val2;
233 }
234
235 /* Finally, add it. */
236 vassert(h->used < h->size);
237 h->inuse[h->used] = True;
238 h->key[h->used] = key;
sewardj84be7372004-08-18 13:59:33 +0000239 h->val[h->used] = val;
sewardja1a370f2004-08-17 13:31:55 +0000240 h->used++;
241}
242
sewardj84be7372004-08-18 13:59:33 +0000243
sewardjd7cb8532004-08-17 23:59:23 +0000244/*---------------------------------------------------------------*/
sewardj08210532004-12-29 17:09:11 +0000245/*--- Flattening out a BB into atomic SSA form ---*/
sewardjd7cb8532004-08-17 23:59:23 +0000246/*---------------------------------------------------------------*/
247
sewardje80679a2004-09-21 23:00:11 +0000248/* Non-critical helper, heuristic for reducing the number of tmp-tmp
249 copies made by flattening. If in doubt return False. */
250
251static Bool isFlat ( IRExpr* e )
252{
sewardj695cff92004-10-13 14:50:14 +0000253 if (e->tag == Iex_Get)
254 return True;
sewardje80679a2004-09-21 23:00:11 +0000255 if (e->tag == Iex_Binop)
sewardj496a58d2005-03-20 18:44:44 +0000256 return toBool( isIRAtom(e->Iex.Binop.arg1)
257 && isIRAtom(e->Iex.Binop.arg2) );
sewardjaf1ceca2005-06-30 23:31:27 +0000258 if (e->tag == Iex_Load)
259 return isIRAtom(e->Iex.Load.addr);
sewardje80679a2004-09-21 23:00:11 +0000260 return False;
261}
262
sewardjd7cb8532004-08-17 23:59:23 +0000263/* Flatten out 'ex' so it is atomic, returning a new expression with
264 the same value, after having appended extra IRTemp assignments to
265 the end of 'bb'. */
266
sewardjdd40fdf2006-12-24 02:20:24 +0000267static IRExpr* flatten_Expr ( IRSB* bb, IRExpr* ex )
sewardjd7cb8532004-08-17 23:59:23 +0000268{
269 Int i;
270 IRExpr** newargs;
271 IRType ty = typeOfIRExpr(bb->tyenv, ex);
272 IRTemp t1;
273
274 switch (ex->tag) {
275
sewardjd7217032004-08-19 10:49:10 +0000276 case Iex_GetI:
277 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000278 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardj2d3f77c2004-09-22 23:49:09 +0000279 IRExpr_GetI(ex->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +0000280 flatten_Expr(bb, ex->Iex.GetI.ix),
sewardj2d3f77c2004-09-22 23:49:09 +0000281 ex->Iex.GetI.bias)));
sewardjdd40fdf2006-12-24 02:20:24 +0000282 return IRExpr_RdTmp(t1);
sewardjd7217032004-08-19 10:49:10 +0000283
sewardjd7cb8532004-08-17 23:59:23 +0000284 case Iex_Get:
285 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000286 addStmtToIRSB(bb,
287 IRStmt_WrTmp(t1, ex));
288 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000289
sewardj40c80262006-02-08 19:30:46 +0000290 case Iex_Qop:
291 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000292 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardj40c80262006-02-08 19:30:46 +0000293 IRExpr_Qop(ex->Iex.Qop.op,
294 flatten_Expr(bb, ex->Iex.Qop.arg1),
295 flatten_Expr(bb, ex->Iex.Qop.arg2),
296 flatten_Expr(bb, ex->Iex.Qop.arg3),
297 flatten_Expr(bb, ex->Iex.Qop.arg4))));
sewardjdd40fdf2006-12-24 02:20:24 +0000298 return IRExpr_RdTmp(t1);
sewardj40c80262006-02-08 19:30:46 +0000299
sewardjb183b852006-02-03 16:08:03 +0000300 case Iex_Triop:
301 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000302 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjb183b852006-02-03 16:08:03 +0000303 IRExpr_Triop(ex->Iex.Triop.op,
304 flatten_Expr(bb, ex->Iex.Triop.arg1),
305 flatten_Expr(bb, ex->Iex.Triop.arg2),
306 flatten_Expr(bb, ex->Iex.Triop.arg3))));
sewardjdd40fdf2006-12-24 02:20:24 +0000307 return IRExpr_RdTmp(t1);
sewardjb183b852006-02-03 16:08:03 +0000308
sewardjd7cb8532004-08-17 23:59:23 +0000309 case Iex_Binop:
310 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000311 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjd7cb8532004-08-17 23:59:23 +0000312 IRExpr_Binop(ex->Iex.Binop.op,
313 flatten_Expr(bb, ex->Iex.Binop.arg1),
314 flatten_Expr(bb, ex->Iex.Binop.arg2))));
sewardjdd40fdf2006-12-24 02:20:24 +0000315 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000316
317 case Iex_Unop:
318 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000319 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjd7cb8532004-08-17 23:59:23 +0000320 IRExpr_Unop(ex->Iex.Unop.op,
321 flatten_Expr(bb, ex->Iex.Unop.arg))));
sewardjdd40fdf2006-12-24 02:20:24 +0000322 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000323
sewardjaf1ceca2005-06-30 23:31:27 +0000324 case Iex_Load:
sewardjd7cb8532004-08-17 23:59:23 +0000325 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000326 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardje768e922009-11-26 17:17:37 +0000327 IRExpr_Load(ex->Iex.Load.end,
sewardjaf1ceca2005-06-30 23:31:27 +0000328 ex->Iex.Load.ty,
329 flatten_Expr(bb, ex->Iex.Load.addr))));
sewardjdd40fdf2006-12-24 02:20:24 +0000330 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000331
332 case Iex_CCall:
sewardjdd40fdf2006-12-24 02:20:24 +0000333 newargs = shallowCopyIRExprVec(ex->Iex.CCall.args);
sewardjd7cb8532004-08-17 23:59:23 +0000334 for (i = 0; newargs[i]; i++)
335 newargs[i] = flatten_Expr(bb, newargs[i]);
336 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000337 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardj8ea867b2004-10-30 19:03:02 +0000338 IRExpr_CCall(ex->Iex.CCall.cee,
sewardjd7cb8532004-08-17 23:59:23 +0000339 ex->Iex.CCall.retty,
340 newargs)));
sewardjdd40fdf2006-12-24 02:20:24 +0000341 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000342
343 case Iex_Mux0X:
344 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000345 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjd7cb8532004-08-17 23:59:23 +0000346 IRExpr_Mux0X(flatten_Expr(bb, ex->Iex.Mux0X.cond),
347 flatten_Expr(bb, ex->Iex.Mux0X.expr0),
348 flatten_Expr(bb, ex->Iex.Mux0X.exprX))));
sewardjdd40fdf2006-12-24 02:20:24 +0000349 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000350
351 case Iex_Const:
sewardjc0b42282004-10-12 13:44:12 +0000352 /* Lift F64i constants out onto temps so they can be CSEd
353 later. */
354 if (ex->Iex.Const.con->tag == Ico_F64i) {
355 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000356 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjc0b42282004-10-12 13:44:12 +0000357 IRExpr_Const(ex->Iex.Const.con)));
sewardjdd40fdf2006-12-24 02:20:24 +0000358 return IRExpr_RdTmp(t1);
sewardjc0b42282004-10-12 13:44:12 +0000359 } else {
360 /* Leave all other constants alone. */
361 return ex;
362 }
363
sewardjdd40fdf2006-12-24 02:20:24 +0000364 case Iex_RdTmp:
sewardjd7cb8532004-08-17 23:59:23 +0000365 return ex;
366
367 default:
368 vex_printf("\n");
369 ppIRExpr(ex);
370 vex_printf("\n");
371 vpanic("flatten_Expr");
372 }
373}
374
375
376/* Append a completely flattened form of 'st' to the end of 'bb'. */
377
sewardjdd40fdf2006-12-24 02:20:24 +0000378static void flatten_Stmt ( IRSB* bb, IRStmt* st )
sewardjd7cb8532004-08-17 23:59:23 +0000379{
sewardj17442fe2004-09-20 14:54:28 +0000380 Int i;
sewardje9d8a262009-07-01 08:06:34 +0000381 IRExpr *e1, *e2, *e3, *e4, *e5;
sewardj17442fe2004-09-20 14:54:28 +0000382 IRDirty *d, *d2;
sewardje9d8a262009-07-01 08:06:34 +0000383 IRCAS *cas, *cas2;
sewardjd7cb8532004-08-17 23:59:23 +0000384 switch (st->tag) {
385 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +0000386 if (isIRAtom(st->Ist.Put.data)) {
sewardj49651f42004-10-28 22:11:04 +0000387 /* optimisation to reduce the amount of heap wasted
388 by the flattener */
sewardjdd40fdf2006-12-24 02:20:24 +0000389 addStmtToIRSB(bb, st);
sewardj49651f42004-10-28 22:11:04 +0000390 } else {
391 /* general case, always correct */
392 e1 = flatten_Expr(bb, st->Ist.Put.data);
sewardjdd40fdf2006-12-24 02:20:24 +0000393 addStmtToIRSB(bb, IRStmt_Put(st->Ist.Put.offset, e1));
sewardj49651f42004-10-28 22:11:04 +0000394 }
sewardjd7cb8532004-08-17 23:59:23 +0000395 break;
sewardjd7cb8532004-08-17 23:59:23 +0000396 case Ist_PutI:
sewardjeeac8412004-11-02 00:26:55 +0000397 e1 = flatten_Expr(bb, st->Ist.PutI.ix);
sewardj2d3f77c2004-09-22 23:49:09 +0000398 e2 = flatten_Expr(bb, st->Ist.PutI.data);
sewardjdd40fdf2006-12-24 02:20:24 +0000399 addStmtToIRSB(bb, IRStmt_PutI(st->Ist.PutI.descr,
sewardj2d3f77c2004-09-22 23:49:09 +0000400 e1,
401 st->Ist.PutI.bias,
402 e2));
sewardjd7217032004-08-19 10:49:10 +0000403 break;
sewardjdd40fdf2006-12-24 02:20:24 +0000404 case Ist_WrTmp:
405 if (isFlat(st->Ist.WrTmp.data)) {
sewardje80679a2004-09-21 23:00:11 +0000406 /* optimisation, to reduce the number of tmp-tmp
407 copies generated */
sewardjdd40fdf2006-12-24 02:20:24 +0000408 addStmtToIRSB(bb, st);
sewardje80679a2004-09-21 23:00:11 +0000409 } else {
410 /* general case, always correct */
sewardjdd40fdf2006-12-24 02:20:24 +0000411 e1 = flatten_Expr(bb, st->Ist.WrTmp.data);
412 addStmtToIRSB(bb, IRStmt_WrTmp(st->Ist.WrTmp.tmp, e1));
sewardje80679a2004-09-21 23:00:11 +0000413 }
sewardjd7cb8532004-08-17 23:59:23 +0000414 break;
sewardjaf1ceca2005-06-30 23:31:27 +0000415 case Ist_Store:
416 e1 = flatten_Expr(bb, st->Ist.Store.addr);
417 e2 = flatten_Expr(bb, st->Ist.Store.data);
sewardje768e922009-11-26 17:17:37 +0000418 addStmtToIRSB(bb, IRStmt_Store(st->Ist.Store.end, e1,e2));
sewardje9d8a262009-07-01 08:06:34 +0000419 break;
420 case Ist_CAS:
421 cas = st->Ist.CAS.details;
422 e1 = flatten_Expr(bb, cas->addr);
423 e2 = cas->expdHi ? flatten_Expr(bb, cas->expdHi) : NULL;
424 e3 = flatten_Expr(bb, cas->expdLo);
425 e4 = cas->dataHi ? flatten_Expr(bb, cas->dataHi) : NULL;
426 e5 = flatten_Expr(bb, cas->dataLo);
427 cas2 = mkIRCAS( cas->oldHi, cas->oldLo, cas->end,
428 e1, e2, e3, e4, e5 );
429 addStmtToIRSB(bb, IRStmt_CAS(cas2));
sewardjd7cb8532004-08-17 23:59:23 +0000430 break;
sewardje768e922009-11-26 17:17:37 +0000431 case Ist_LLSC:
432 e1 = flatten_Expr(bb, st->Ist.LLSC.addr);
433 e2 = st->Ist.LLSC.storedata
434 ? flatten_Expr(bb, st->Ist.LLSC.storedata)
435 : NULL;
436 addStmtToIRSB(bb, IRStmt_LLSC(st->Ist.LLSC.end,
437 st->Ist.LLSC.result, e1, e2));
438 break;
sewardj17442fe2004-09-20 14:54:28 +0000439 case Ist_Dirty:
440 d = st->Ist.Dirty.details;
441 d2 = emptyIRDirty();
442 *d2 = *d;
sewardjdd40fdf2006-12-24 02:20:24 +0000443 d2->args = shallowCopyIRExprVec(d2->args);
sewardj17442fe2004-09-20 14:54:28 +0000444 if (d2->mFx != Ifx_None) {
445 d2->mAddr = flatten_Expr(bb, d2->mAddr);
446 } else {
447 vassert(d2->mAddr == NULL);
448 }
sewardjb8385d82004-11-02 01:34:15 +0000449 d2->guard = flatten_Expr(bb, d2->guard);
sewardj17442fe2004-09-20 14:54:28 +0000450 for (i = 0; d2->args[i]; i++)
451 d2->args[i] = flatten_Expr(bb, d2->args[i]);
sewardjdd40fdf2006-12-24 02:20:24 +0000452 addStmtToIRSB(bb, IRStmt_Dirty(d2));
sewardj17442fe2004-09-20 14:54:28 +0000453 break;
sewardjd2445f62005-03-21 00:15:53 +0000454 case Ist_NoOp:
sewardjc4356f02007-11-09 21:15:04 +0000455 case Ist_MBE:
sewardjd2445f62005-03-21 00:15:53 +0000456 case Ist_IMark:
sewardjdd40fdf2006-12-24 02:20:24 +0000457 addStmtToIRSB(bb, st);
sewardj3e838932005-01-07 12:09:15 +0000458 break;
sewardj5a9ffab2005-05-12 17:55:01 +0000459 case Ist_AbiHint:
460 e1 = flatten_Expr(bb, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +0000461 e2 = flatten_Expr(bb, st->Ist.AbiHint.nia);
462 addStmtToIRSB(bb, IRStmt_AbiHint(e1, st->Ist.AbiHint.len, e2));
sewardj5a9ffab2005-05-12 17:55:01 +0000463 break;
sewardjd7cb8532004-08-17 23:59:23 +0000464 case Ist_Exit:
sewardj0276d4b2004-11-15 15:30:21 +0000465 e1 = flatten_Expr(bb, st->Ist.Exit.guard);
sewardjdd40fdf2006-12-24 02:20:24 +0000466 addStmtToIRSB(bb, IRStmt_Exit(e1, st->Ist.Exit.jk,
sewardj893aada2004-11-29 19:57:54 +0000467 st->Ist.Exit.dst));
sewardjd7cb8532004-08-17 23:59:23 +0000468 break;
469 default:
470 vex_printf("\n");
471 ppIRStmt(st);
472 vex_printf("\n");
473 vpanic("flatten_Stmt");
474 }
475}
476
sewardj08210532004-12-29 17:09:11 +0000477
sewardjdd40fdf2006-12-24 02:20:24 +0000478static IRSB* flatten_BB ( IRSB* in )
sewardjd7cb8532004-08-17 23:59:23 +0000479{
480 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +0000481 IRSB* out;
482 out = emptyIRSB();
483 out->tyenv = deepCopyIRTypeEnv( in->tyenv );
sewardjd7cb8532004-08-17 23:59:23 +0000484 for (i = 0; i < in->stmts_used; i++)
sewardj4345f7a2004-09-22 19:49:27 +0000485 if (in->stmts[i])
486 flatten_Stmt( out, in->stmts[i] );
sewardjd7cb8532004-08-17 23:59:23 +0000487 out->next = flatten_Expr( out, in->next );
488 out->jumpkind = in->jumpkind;
489 return out;
490}
491
sewardjedf4d692004-08-17 13:52:58 +0000492
sewardj08210532004-12-29 17:09:11 +0000493/*---------------------------------------------------------------*/
494/*--- In-place removal of redundant GETs ---*/
495/*---------------------------------------------------------------*/
496
497/* Scan forwards, building up an environment binding (min offset, max
498 offset) pairs to values, which will either be temps or constants.
499
500 On seeing 't = Get(minoff,maxoff)', look up (minoff,maxoff) in the
501 env and if it matches, replace the Get with the stored value. If
502 there is no match, add a (minoff,maxoff) :-> t binding.
503
504 On seeing 'Put (minoff,maxoff) = t or c', first remove in the env
505 any binding which fully or partially overlaps with (minoff,maxoff).
506 Then add a new (minoff,maxoff) :-> t or c binding. */
507
508/* Extract the min/max offsets from a guest state array descriptor. */
509
510inline
sewardjdd40fdf2006-12-24 02:20:24 +0000511static void getArrayBounds ( IRRegArray* descr,
512 UInt* minoff, UInt* maxoff )
sewardj08210532004-12-29 17:09:11 +0000513{
514 *minoff = descr->base;
515 *maxoff = *minoff + descr->nElems*sizeofIRType(descr->elemTy) - 1;
516 vassert((*minoff & ~0xFFFF) == 0);
517 vassert((*maxoff & ~0xFFFF) == 0);
518 vassert(*minoff <= *maxoff);
519}
520
521/* Create keys, of the form ((minoffset << 16) | maxoffset). */
522
523static UInt mk_key_GetPut ( Int offset, IRType ty )
524{
525 /* offset should fit in 16 bits. */
526 UInt minoff = offset;
527 UInt maxoff = minoff + sizeofIRType(ty) - 1;
528 vassert((minoff & ~0xFFFF) == 0);
529 vassert((maxoff & ~0xFFFF) == 0);
530 return (minoff << 16) | maxoff;
531}
532
sewardjdd40fdf2006-12-24 02:20:24 +0000533static UInt mk_key_GetIPutI ( IRRegArray* descr )
sewardj08210532004-12-29 17:09:11 +0000534{
535 UInt minoff, maxoff;
536 getArrayBounds( descr, &minoff, &maxoff );
537 vassert((minoff & ~0xFFFF) == 0);
538 vassert((maxoff & ~0xFFFF) == 0);
539 return (minoff << 16) | maxoff;
540}
541
542/* Supposing h has keys of the form generated by mk_key_GetPut and
543 mk_key_GetIPutI, invalidate any key which overlaps (k_lo
544 .. k_hi).
545*/
546static void invalidateOverlaps ( HashHW* h, UInt k_lo, UInt k_hi )
547{
548 Int j;
549 UInt e_lo, e_hi;
550 vassert(k_lo <= k_hi);
551 /* invalidate any env entries which in any way overlap (k_lo
552 .. k_hi) */
553 /* vex_printf("invalidate %d .. %d\n", k_lo, k_hi ); */
554
555 for (j = 0; j < h->used; j++) {
556 if (!h->inuse[j])
557 continue;
558 e_lo = (((UInt)h->key[j]) >> 16) & 0xFFFF;
559 e_hi = ((UInt)h->key[j]) & 0xFFFF;
560 vassert(e_lo <= e_hi);
561 if (e_hi < k_lo || k_hi < e_lo)
562 continue; /* no overlap possible */
563 else
564 /* overlap; invalidate */
565 h->inuse[j] = False;
566 }
567}
568
569
sewardjdd40fdf2006-12-24 02:20:24 +0000570static void redundant_get_removal_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +0000571{
572 HashHW* env = newHHW();
573 UInt key = 0; /* keep gcc -O happy */
574 Int i, j;
575 HWord val;
576
577 for (i = 0; i < bb->stmts_used; i++) {
578 IRStmt* st = bb->stmts[i];
579
sewardj8bee6d12005-03-22 02:24:05 +0000580 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +0000581 continue;
582
583 /* Deal with Gets */
sewardjdd40fdf2006-12-24 02:20:24 +0000584 if (st->tag == Ist_WrTmp
585 && st->Ist.WrTmp.data->tag == Iex_Get) {
sewardj08210532004-12-29 17:09:11 +0000586 /* st is 't = Get(...)'. Look up in the environment and see
587 if the Get can be replaced. */
sewardjdd40fdf2006-12-24 02:20:24 +0000588 IRExpr* get = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +0000589 key = (HWord)mk_key_GetPut( get->Iex.Get.offset,
590 get->Iex.Get.ty );
591 if (lookupHHW(env, &val, (HWord)key)) {
592 /* found it */
593 /* Note, we could do better here. If the types are
594 different we don't do the substitution, since doing so
595 could lead to invalidly-typed IR. An improvement would
596 be to stick in a reinterpret-style cast, although that
597 would make maintaining flatness more difficult. */
598 IRExpr* valE = (IRExpr*)val;
sewardj9d2e7692005-02-07 01:11:31 +0000599 Bool typesOK = toBool( typeOfIRExpr(bb->tyenv,valE)
sewardjdd40fdf2006-12-24 02:20:24 +0000600 == st->Ist.WrTmp.data->Iex.Get.ty );
sewardj08210532004-12-29 17:09:11 +0000601 if (typesOK && DEBUG_IROPT) {
602 vex_printf("rGET: "); ppIRExpr(get);
603 vex_printf(" -> "); ppIRExpr(valE);
604 vex_printf("\n");
605 }
606 if (typesOK)
sewardjdd40fdf2006-12-24 02:20:24 +0000607 bb->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, valE);
sewardj08210532004-12-29 17:09:11 +0000608 } else {
609 /* Not found, but at least we know that t and the Get(...)
610 are now associated. So add a binding to reflect that
611 fact. */
612 addToHHW( env, (HWord)key,
sewardjdd40fdf2006-12-24 02:20:24 +0000613 (HWord)(void*)(IRExpr_RdTmp(st->Ist.WrTmp.tmp)) );
sewardj08210532004-12-29 17:09:11 +0000614 }
615 }
616
617 /* Deal with Puts: invalidate any env entries overlapped by this
618 Put */
619 if (st->tag == Ist_Put || st->tag == Ist_PutI) {
620 UInt k_lo, k_hi;
621 if (st->tag == Ist_Put) {
622 key = mk_key_GetPut( st->Ist.Put.offset,
623 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
624 } else {
625 vassert(st->tag == Ist_PutI);
626 key = mk_key_GetIPutI( st->Ist.PutI.descr );
627 }
628
629 k_lo = (key >> 16) & 0xFFFF;
630 k_hi = key & 0xFFFF;
631 invalidateOverlaps(env, k_lo, k_hi);
632 }
633 else
634 if (st->tag == Ist_Dirty) {
635 /* Deal with dirty helpers which write or modify guest state.
636 Invalidate the entire env. We could do a lot better
637 here. */
638 IRDirty* d = st->Ist.Dirty.details;
639 Bool writes = False;
640 for (j = 0; j < d->nFxState; j++) {
641 if (d->fxState[j].fx == Ifx_Modify
642 || d->fxState[j].fx == Ifx_Write)
643 writes = True;
644 }
645 if (writes) {
646 /* dump the entire env (not clever, but correct ...) */
647 for (j = 0; j < env->used; j++)
648 env->inuse[j] = False;
649 if (0) vex_printf("rGET: trash env due to dirty helper\n");
650 }
651 }
652
653 /* add this one to the env, if appropriate */
654 if (st->tag == Ist_Put) {
sewardj496a58d2005-03-20 18:44:44 +0000655 vassert(isIRAtom(st->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +0000656 addToHHW( env, (HWord)key, (HWord)(st->Ist.Put.data));
657 }
658
659 } /* for (i = 0; i < bb->stmts_used; i++) */
660
661}
662
663
664/*---------------------------------------------------------------*/
665/*--- In-place removal of redundant PUTs ---*/
666/*---------------------------------------------------------------*/
667
668/* Find any Get uses in st and invalidate any partially or fully
669 overlapping ranges listed in env. Due to the flattening phase, the
sewardjdd40fdf2006-12-24 02:20:24 +0000670 only stmt kind we expect to find a Get on is IRStmt_WrTmp. */
sewardj08210532004-12-29 17:09:11 +0000671
672static void handle_gets_Stmt (
673 HashHW* env,
674 IRStmt* st,
675 Bool (*preciseMemExnsFn)(Int,Int)
676 )
677{
678 Int j;
679 UInt key = 0; /* keep gcc -O happy */
680 Bool isGet;
681 Bool memRW = False;
682 IRExpr* e;
683
684 switch (st->tag) {
685
686 /* This is the only interesting case. Deal with Gets in the RHS
687 expression. */
sewardjdd40fdf2006-12-24 02:20:24 +0000688 case Ist_WrTmp:
689 e = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +0000690 switch (e->tag) {
691 case Iex_Get:
692 isGet = True;
693 key = mk_key_GetPut ( e->Iex.Get.offset, e->Iex.Get.ty );
694 break;
695 case Iex_GetI:
696 isGet = True;
697 key = mk_key_GetIPutI ( e->Iex.GetI.descr );
698 break;
sewardjaf1ceca2005-06-30 23:31:27 +0000699 case Iex_Load:
sewardj08210532004-12-29 17:09:11 +0000700 isGet = False;
701 memRW = True;
702 break;
703 default:
704 isGet = False;
705 }
706 if (isGet) {
707 UInt k_lo, k_hi;
708 k_lo = (key >> 16) & 0xFFFF;
709 k_hi = key & 0xFFFF;
710 invalidateOverlaps(env, k_lo, k_hi);
711 }
712 break;
713
714 /* Be very conservative for dirty helper calls; dump the entire
715 environment. The helper might read guest state, in which
716 case it needs to be flushed first. Also, the helper might
717 access guest memory, in which case all parts of the guest
718 state requiring precise exceptions needs to be flushed. The
719 crude solution is just to flush everything; we could easily
720 enough do a lot better if needed. */
sewardj3e838932005-01-07 12:09:15 +0000721 /* Probably also overly-conservative, but also dump everything
sewardjc4356f02007-11-09 21:15:04 +0000722 if we hit a memory bus event (fence, lock, unlock). Ditto
sewardje768e922009-11-26 17:17:37 +0000723 AbiHints, CASs, LLs and SCs. */
sewardj5a9ffab2005-05-12 17:55:01 +0000724 case Ist_AbiHint:
725 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +0000726 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +0000727 /* fall through */
sewardjc4356f02007-11-09 21:15:04 +0000728 case Ist_MBE:
sewardj08210532004-12-29 17:09:11 +0000729 case Ist_Dirty:
sewardje9d8a262009-07-01 08:06:34 +0000730 case Ist_CAS:
sewardje768e922009-11-26 17:17:37 +0000731 case Ist_LLSC:
sewardj08210532004-12-29 17:09:11 +0000732 for (j = 0; j < env->used; j++)
733 env->inuse[j] = False;
734 break;
735
736 /* all other cases are boring. */
sewardjaf1ceca2005-06-30 23:31:27 +0000737 case Ist_Store:
738 vassert(isIRAtom(st->Ist.Store.addr));
739 vassert(isIRAtom(st->Ist.Store.data));
sewardj08210532004-12-29 17:09:11 +0000740 memRW = True;
741 break;
742
743 case Ist_Exit:
sewardj496a58d2005-03-20 18:44:44 +0000744 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +0000745 break;
746
747 case Ist_PutI:
sewardj496a58d2005-03-20 18:44:44 +0000748 vassert(isIRAtom(st->Ist.PutI.ix));
749 vassert(isIRAtom(st->Ist.PutI.data));
sewardj08210532004-12-29 17:09:11 +0000750 break;
751
sewardjd2445f62005-03-21 00:15:53 +0000752 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +0000753 case Ist_IMark:
754 break;
755
sewardj08210532004-12-29 17:09:11 +0000756 default:
757 vex_printf("\n");
758 ppIRStmt(st);
759 vex_printf("\n");
760 vpanic("handle_gets_Stmt");
761 }
762
763 if (memRW) {
764 /* This statement accesses memory. So we need to dump all parts
765 of the environment corresponding to guest state that may not
766 be reordered with respect to memory references. That means
767 at least the stack pointer. */
768 for (j = 0; j < env->used; j++) {
769 if (!env->inuse[j])
770 continue;
771 if (vex_control.iropt_precise_memory_exns) {
772 /* Precise exceptions required. Flush all guest state. */
773 env->inuse[j] = False;
774 } else {
775 /* Just flush the minimal amount required, as computed by
776 preciseMemExnsFn. */
777 HWord k_lo = (env->key[j] >> 16) & 0xFFFF;
778 HWord k_hi = env->key[j] & 0xFFFF;
779 if (preciseMemExnsFn( k_lo, k_hi ))
780 env->inuse[j] = False;
781 }
782 }
783 } /* if (memRW) */
784
785}
786
787
788/* Scan backwards, building up a set of (min offset, max
789 offset) pairs, indicating those parts of the guest state
790 for which the next event is a write.
791
792 On seeing a conditional exit, empty the set.
793
794 On seeing 'Put (minoff,maxoff) = t or c', if (minoff,maxoff) is
795 completely within the set, remove the Put. Otherwise, add
796 (minoff,maxoff) to the set.
797
798 On seeing 'Get (minoff,maxoff)', remove any part of the set
sewardj98430292004-12-29 17:34:50 +0000799 overlapping (minoff,maxoff). The same has to happen for any events
800 which implicitly read parts of the guest state: dirty helper calls
801 and loads/stores.
sewardj08210532004-12-29 17:09:11 +0000802*/
803
804static void redundant_put_removal_BB (
sewardjdd40fdf2006-12-24 02:20:24 +0000805 IRSB* bb,
sewardj08210532004-12-29 17:09:11 +0000806 Bool (*preciseMemExnsFn)(Int,Int)
807 )
808{
809 Int i, j;
810 Bool isPut;
811 IRStmt* st;
812 UInt key = 0; /* keep gcc -O happy */
813
814 HashHW* env = newHHW();
815 for (i = bb->stmts_used-1; i >= 0; i--) {
816 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +0000817
818 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +0000819 continue;
820
821 /* Deal with conditional exits. */
822 if (st->tag == Ist_Exit) {
823 /* Since control may not get beyond this point, we must empty
824 out the set, since we can no longer claim that the next
825 event for any part of the guest state is definitely a
826 write. */
sewardj496a58d2005-03-20 18:44:44 +0000827 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +0000828 for (j = 0; j < env->used; j++)
829 env->inuse[j] = False;
830 continue;
831 }
832
833 /* Deal with Puts */
834 switch (st->tag) {
835 case Ist_Put:
836 isPut = True;
837 key = mk_key_GetPut( st->Ist.Put.offset,
838 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
sewardj496a58d2005-03-20 18:44:44 +0000839 vassert(isIRAtom(st->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +0000840 break;
841 case Ist_PutI:
842 isPut = True;
843 key = mk_key_GetIPutI( st->Ist.PutI.descr );
sewardj496a58d2005-03-20 18:44:44 +0000844 vassert(isIRAtom(st->Ist.PutI.ix));
845 vassert(isIRAtom(st->Ist.PutI.data));
sewardj08210532004-12-29 17:09:11 +0000846 break;
847 default:
848 isPut = False;
849 }
850 if (isPut && st->tag != Ist_PutI) {
851 /* See if any single entry in env overlaps this Put. This is
852 simplistic in that the transformation is valid if, say, two
853 or more entries in the env overlap this Put, but the use of
854 lookupHHW will only find a single entry which exactly
855 overlaps this Put. This is suboptimal but safe. */
856 if (lookupHHW(env, NULL, (HWord)key)) {
857 /* This Put is redundant because a later one will overwrite
858 it. So NULL (nop) it out. */
859 if (DEBUG_IROPT) {
860 vex_printf("rPUT: "); ppIRStmt(st);
861 vex_printf("\n");
862 }
sewardjd2445f62005-03-21 00:15:53 +0000863 bb->stmts[i] = IRStmt_NoOp();
sewardj08210532004-12-29 17:09:11 +0000864 } else {
865 /* We can't demonstrate that this Put is redundant, so add it
866 to the running collection. */
867 addToHHW(env, (HWord)key, 0);
868 }
869 continue;
870 }
871
872 /* Deal with Gets. These remove bits of the environment since
873 appearance of a Get means that the next event for that slice
sewardj98430292004-12-29 17:34:50 +0000874 of the guest state is no longer a write, but a read. Also
875 deals with implicit reads of guest state needed to maintain
876 precise exceptions. */
sewardj08210532004-12-29 17:09:11 +0000877 handle_gets_Stmt( env, st, preciseMemExnsFn );
878 }
879}
880
sewardj84be7372004-08-18 13:59:33 +0000881
882/*---------------------------------------------------------------*/
883/*--- Constant propagation and folding ---*/
884/*---------------------------------------------------------------*/
885
sewardj62617ef2004-10-13 23:29:22 +0000886/* The env in this section is a map from IRTemp to IRExpr*,
887 that is, an array indexed by IRTemp. */
sewardjf6501992004-08-27 11:58:24 +0000888
sewardjf6729012004-08-25 12:45:13 +0000889/* Are both expressions simply the same IRTemp ? */
890static Bool sameIRTemps ( IRExpr* e1, IRExpr* e2 )
891{
sewardjdd40fdf2006-12-24 02:20:24 +0000892 return toBool( e1->tag == Iex_RdTmp
893 && e2->tag == Iex_RdTmp
894 && e1->Iex.RdTmp.tmp == e2->Iex.RdTmp.tmp );
sewardjf6729012004-08-25 12:45:13 +0000895}
896
sewardj6c299f32009-12-31 18:00:12 +0000897static Bool sameIcoU32s ( IRExpr* e1, IRExpr* e2 )
898{
899 return toBool( e1->tag == Iex_Const
900 && e2->tag == Iex_Const
901 && e1->Iex.Const.con->tag == Ico_U32
902 && e2->Iex.Const.con->tag == Ico_U32
903 && e1->Iex.Const.con->Ico.U32
904 == e2->Iex.Const.con->Ico.U32 );
905}
906
907/* Are both expressions either the same IRTemp or IRConst-U32s ? If
908 in doubt, say No. */
909static Bool sameIRTempsOrIcoU32s ( IRExpr* e1, IRExpr* e2 )
910{
911 switch (e1->tag) {
912 case Iex_RdTmp:
913 return sameIRTemps(e1, e2);
914 case Iex_Const:
915 return sameIcoU32s(e1, e2);
916 default:
917 return False;
918 }
919}
920
florianea7eab72011-07-21 16:21:58 +0000921/* Is this literally IRExpr_Const(IRConst_U32(0)) ? */
922static Bool isZeroU32 ( IRExpr* e )
923{
924 return toBool( e->tag == Iex_Const
925 && e->Iex.Const.con->tag == Ico_U32
926 && e->Iex.Const.con->Ico.U32 == 0);
927}
928
929/* Is this literally IRExpr_Const(IRConst_U64(0)) ? */
930static Bool isZeroU64 ( IRExpr* e )
931{
932 return toBool( e->tag == Iex_Const
933 && e->Iex.Const.con->tag == Ico_U64
934 && e->Iex.Const.con->Ico.U64 == 0);
935}
936
florianf6402ab2012-01-29 02:19:43 +0000937/* Is this an integer constant with value 0 ? */
938static Bool isZeroU ( IRExpr* e )
939{
940 if (e->tag != Iex_Const) return False;
941
942 switch (e->Iex.Const.con->tag) {
943 case Ico_U1: return toBool( e->Iex.Const.con->Ico.U1 == 0);
944 case Ico_U8: return toBool( e->Iex.Const.con->Ico.U8 == 0);
945 case Ico_U16: return toBool( e->Iex.Const.con->Ico.U16 == 0);
946 case Ico_U32: return toBool( e->Iex.Const.con->Ico.U32 == 0);
947 case Ico_U64: return toBool( e->Iex.Const.con->Ico.U64 == 0);
948 default: vpanic("isZeroU");
949 }
950}
951
sewardje1d45da2004-11-12 00:13:21 +0000952static Bool notBool ( Bool b )
953{
954 if (b == True) return False;
955 if (b == False) return True;
956 vpanic("notBool");
957}
958
sewardj0033ddc2005-04-26 23:34:34 +0000959/* Make a zero which has the same type as the result of the given
960 primop. */
sewardj64d776c2010-10-01 14:06:22 +0000961static IRExpr* mkZeroOfPrimopResultType ( IROp op )
sewardj0033ddc2005-04-26 23:34:34 +0000962{
963 switch (op) {
964 case Iop_Xor8: return IRExpr_Const(IRConst_U8(0));
965 case Iop_Xor16: return IRExpr_Const(IRConst_U16(0));
sewardjbe917912010-08-22 12:38:53 +0000966 case Iop_Sub32:
sewardj0033ddc2005-04-26 23:34:34 +0000967 case Iop_Xor32: return IRExpr_Const(IRConst_U32(0));
sewardj64d776c2010-10-01 14:06:22 +0000968 case Iop_Sub64:
sewardj0033ddc2005-04-26 23:34:34 +0000969 case Iop_Xor64: return IRExpr_Const(IRConst_U64(0));
sewardj04744272007-01-16 19:19:55 +0000970 case Iop_XorV128: return IRExpr_Const(IRConst_V128(0));
sewardj64d776c2010-10-01 14:06:22 +0000971 default: vpanic("mkZeroOfPrimopResultType: bad primop");
972 }
973}
974
975/* Make a value containing all 1-bits, which has the same type as the
976 result of the given primop. */
977static IRExpr* mkOnesOfPrimopResultType ( IROp op )
978{
979 switch (op) {
980 case Iop_CmpEQ64:
981 return IRExpr_Const(IRConst_U1(toBool(1)));
982 case Iop_CmpEQ8x8:
983 return IRExpr_Const(IRConst_U64(0xFFFFFFFFFFFFFFFFULL));
984 case Iop_CmpEQ8x16:
985 return IRExpr_Const(IRConst_V128(0xFFFF));
986 default:
987 vpanic("mkOnesOfPrimopResultType: bad primop");
sewardj0033ddc2005-04-26 23:34:34 +0000988 }
989}
990
sewardj4cba9f42011-03-07 18:34:34 +0000991/* Helpers for folding Clz32/64. */
992static UInt fold_Clz64 ( ULong value )
993{
994 UInt i;
995 vassert(value != 0ULL); /* no defined semantics for arg==0 */
996 for (i = 0; i < 64; ++i) {
sewardj7f6330d2011-04-05 11:06:02 +0000997 if (0ULL != (value & (((ULong)1) << (63 - i)))) return i;
sewardj4cba9f42011-03-07 18:34:34 +0000998 }
999 vassert(0);
1000 /*NOTREACHED*/
1001 return 0;
1002}
1003
1004static UInt fold_Clz32 ( UInt value )
1005{
1006 UInt i;
1007 vassert(value != 0); /* no defined semantics for arg==0 */
1008 for (i = 0; i < 32; ++i) {
sewardj7f6330d2011-04-05 11:06:02 +00001009 if (0 != (value & (((UInt)1) << (31 - i)))) return i;
sewardj4cba9f42011-03-07 18:34:34 +00001010 }
1011 vassert(0);
1012 /*NOTREACHED*/
1013 return 0;
1014}
1015
sewardj0033ddc2005-04-26 23:34:34 +00001016
sewardj84be7372004-08-18 13:59:33 +00001017static IRExpr* fold_Expr ( IRExpr* e )
1018{
sewardj278c44c2004-08-20 00:28:13 +00001019 Int shift;
sewardj84be7372004-08-18 13:59:33 +00001020 IRExpr* e2 = e; /* e2 is the result of folding e, if possible */
1021
1022 /* UNARY ops */
1023 if (e->tag == Iex_Unop
1024 && e->Iex.Unop.arg->tag == Iex_Const) {
1025 switch (e->Iex.Unop.op) {
sewardjae27ab62004-10-15 21:21:46 +00001026 case Iop_1Uto8:
sewardj9d2e7692005-02-07 01:11:31 +00001027 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardjba999312004-11-15 15:21:17 +00001028 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardj9d2e7692005-02-07 01:11:31 +00001029 ? 1 : 0)));
sewardjae27ab62004-10-15 21:21:46 +00001030 break;
sewardjf4a821d2004-10-09 00:58:19 +00001031 case Iop_1Uto32:
1032 e2 = IRExpr_Const(IRConst_U32(
sewardjba999312004-11-15 15:21:17 +00001033 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardjf4a821d2004-10-09 00:58:19 +00001034 ? 1 : 0));
1035 break;
sewardj2716ff12005-05-20 19:21:45 +00001036 case Iop_1Uto64:
1037 e2 = IRExpr_Const(IRConst_U64(
1038 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
1039 ? 1 : 0));
1040 break;
sewardje6b39932004-11-06 17:01:15 +00001041
sewardj1bee5612005-11-10 18:10:58 +00001042 case Iop_1Sto8:
1043 e2 = IRExpr_Const(IRConst_U8(toUChar(
1044 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
1045 ? 0xFF : 0)));
1046 break;
sewardj68884ef2005-07-18 13:58:49 +00001047 case Iop_1Sto16:
sewardj743d8f02005-07-27 00:22:37 +00001048 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardj68884ef2005-07-18 13:58:49 +00001049 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardj743d8f02005-07-27 00:22:37 +00001050 ? 0xFFFF : 0)));
sewardj68884ef2005-07-18 13:58:49 +00001051 break;
sewardjd9997882004-11-04 19:42:59 +00001052 case Iop_1Sto32:
1053 e2 = IRExpr_Const(IRConst_U32(
sewardjba999312004-11-15 15:21:17 +00001054 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardjd9997882004-11-04 19:42:59 +00001055 ? 0xFFFFFFFF : 0));
1056 break;
sewardje6b39932004-11-06 17:01:15 +00001057 case Iop_1Sto64:
1058 e2 = IRExpr_Const(IRConst_U64(
sewardjba999312004-11-15 15:21:17 +00001059 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardje6b39932004-11-06 17:01:15 +00001060 ? 0xFFFFFFFFFFFFFFFFULL : 0));
1061 break;
1062
sewardj883b00b2004-09-11 09:30:24 +00001063 case Iop_8Sto32: {
1064 /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
1065 s32 <<= 24;
1066 s32 >>= 24;
1067 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
1068 break;
1069 }
sewardj7f6330d2011-04-05 11:06:02 +00001070 case Iop_16Sto32: {
1071 /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1072 s32 <<= 16;
1073 s32 >>= 16;
1074 e2 = IRExpr_Const(IRConst_U32( (UInt)s32) );
1075 break;
1076 }
sewardj291a7e82005-04-27 11:42:44 +00001077 case Iop_8Uto64:
1078 e2 = IRExpr_Const(IRConst_U64(
1079 0xFFULL & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1080 break;
1081 case Iop_16Uto64:
1082 e2 = IRExpr_Const(IRConst_U64(
1083 0xFFFFULL & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
1084 break;
sewardj84be7372004-08-18 13:59:33 +00001085 case Iop_8Uto32:
1086 e2 = IRExpr_Const(IRConst_U32(
1087 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1088 break;
sewardj7f6330d2011-04-05 11:06:02 +00001089 case Iop_8Sto16: {
1090 /* signed */ Short s16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
1091 s16 <<= 8;
1092 s16 >>= 8;
1093 e2 = IRExpr_Const(IRConst_U16( (UShort)s16) );
1094 break;
1095 }
1096 case Iop_8Uto16:
1097 e2 = IRExpr_Const(IRConst_U16(
1098 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1099 break;
sewardj84be7372004-08-18 13:59:33 +00001100 case Iop_16Uto32:
1101 e2 = IRExpr_Const(IRConst_U32(
1102 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
1103 break;
sewardj73017432004-10-14 19:33:25 +00001104 case Iop_32to16:
sewardj9d2e7692005-02-07 01:11:31 +00001105 e2 = IRExpr_Const(IRConst_U16(toUShort(
1106 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
sewardj73017432004-10-14 19:33:25 +00001107 break;
sewardj4345f7a2004-09-22 19:49:27 +00001108 case Iop_32to8:
sewardj9d2e7692005-02-07 01:11:31 +00001109 e2 = IRExpr_Const(IRConst_U8(toUChar(
1110 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
sewardj4345f7a2004-09-22 19:49:27 +00001111 break;
sewardj7447b5b2004-10-16 11:30:42 +00001112 case Iop_32to1:
sewardj9d2e7692005-02-07 01:11:31 +00001113 e2 = IRExpr_Const(IRConst_U1(toBool(
1114 1 == (1 & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)
1115 )));
sewardj7447b5b2004-10-16 11:30:42 +00001116 break;
sewardj291a7e82005-04-27 11:42:44 +00001117 case Iop_64to1:
1118 e2 = IRExpr_Const(IRConst_U1(toBool(
1119 1 == (1 & e->Iex.Unop.arg->Iex.Const.con->Ico.U64)
1120 )));
1121 break;
sewardje6b39932004-11-06 17:01:15 +00001122
sewardjf057afb2005-02-27 13:35:41 +00001123 case Iop_Not64:
1124 e2 = IRExpr_Const(IRConst_U64(
1125 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U64)));
1126 break;
sewardj883b00b2004-09-11 09:30:24 +00001127 case Iop_Not32:
1128 e2 = IRExpr_Const(IRConst_U32(
1129 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
1130 break;
sewardje6b39932004-11-06 17:01:15 +00001131 case Iop_Not16:
sewardj9d2e7692005-02-07 01:11:31 +00001132 e2 = IRExpr_Const(IRConst_U16(toUShort(
1133 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U16))));
sewardje6b39932004-11-06 17:01:15 +00001134 break;
sewardjd9997882004-11-04 19:42:59 +00001135 case Iop_Not8:
sewardj9d2e7692005-02-07 01:11:31 +00001136 e2 = IRExpr_Const(IRConst_U8(toUChar(
1137 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U8))));
sewardjd9997882004-11-04 19:42:59 +00001138 break;
sewardje6b39932004-11-06 17:01:15 +00001139
sewardje1d45da2004-11-12 00:13:21 +00001140 case Iop_Not1:
sewardjba999312004-11-15 15:21:17 +00001141 e2 = IRExpr_Const(IRConst_U1(
1142 notBool(e->Iex.Unop.arg->Iex.Const.con->Ico.U1)));
sewardje1d45da2004-11-12 00:13:21 +00001143 break;
1144
sewardj291a7e82005-04-27 11:42:44 +00001145 case Iop_64to8: {
1146 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1147 w64 &= 0xFFULL;
1148 e2 = IRExpr_Const(IRConst_U8( (UChar)w64 ));
1149 break;
1150 }
1151 case Iop_64to16: {
1152 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1153 w64 &= 0xFFFFULL;
sewardje85bc402005-05-06 16:29:26 +00001154 e2 = IRExpr_Const(IRConst_U16( (UShort)w64 ));
sewardj291a7e82005-04-27 11:42:44 +00001155 break;
1156 }
sewardj1d8ce202004-12-13 14:14:16 +00001157 case Iop_64to32: {
1158 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1159 w64 &= 0x00000000FFFFFFFFULL;
1160 e2 = IRExpr_Const(IRConst_U32( (UInt)w64 ));
sewardj37010592004-12-13 10:47:15 +00001161 break;
sewardj1d8ce202004-12-13 14:14:16 +00001162 }
sewardj1d8ce202004-12-13 14:14:16 +00001163 case Iop_64HIto32: {
1164 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1165 w64 >>= 32;
1166 e2 = IRExpr_Const(IRConst_U32( (UInt)w64 ));
1167 break;
1168 }
sewardjb5710b82005-01-27 16:05:09 +00001169 case Iop_32Uto64:
1170 e2 = IRExpr_Const(IRConst_U64(
1171 0xFFFFFFFFULL
1172 & e->Iex.Unop.arg->Iex.Const.con->Ico.U32));
1173 break;
sewardj7f6330d2011-04-05 11:06:02 +00001174 case Iop_16Sto64: {
1175 /* signed */ Long s64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1176 s64 <<= 48;
1177 s64 >>= 48;
1178 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1179 break;
1180 }
sewardj287e9bb2010-07-29 16:12:41 +00001181 case Iop_32Sto64: {
1182 /* signed */ Long s64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1183 s64 <<= 32;
1184 s64 >>= 32;
1185 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1186 break;
1187 }
sewardj7f6330d2011-04-05 11:06:02 +00001188
1189 case Iop_16to8: {
1190 UShort w16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1191 w16 &= 0xFF;
1192 e2 = IRExpr_Const(IRConst_U8( (UChar)w16 ));
1193 break;
1194 }
1195 case Iop_16HIto8: {
1196 UShort w16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1197 w16 >>= 8;
1198 w16 &= 0xFF;
1199 e2 = IRExpr_Const(IRConst_U8( (UChar)w16 ));
1200 break;
1201 }
1202
sewardj0033ddc2005-04-26 23:34:34 +00001203 case Iop_CmpNEZ8:
1204 e2 = IRExpr_Const(IRConst_U1(toBool(
1205 0 !=
1206 (0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8)
1207 )));
1208 break;
1209 case Iop_CmpNEZ32:
1210 e2 = IRExpr_Const(IRConst_U1(toBool(
1211 0 !=
1212 (0xFFFFFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)
1213 )));
1214 break;
1215 case Iop_CmpNEZ64:
1216 e2 = IRExpr_Const(IRConst_U1(toBool(
1217 0ULL != e->Iex.Unop.arg->Iex.Const.con->Ico.U64
1218 )));
1219 break;
1220
sewardjeb17e492007-08-25 23:07:44 +00001221 case Iop_CmpwNEZ32: {
1222 UInt w32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1223 if (w32 == 0)
1224 e2 = IRExpr_Const(IRConst_U32( 0 ));
1225 else
1226 e2 = IRExpr_Const(IRConst_U32( 0xFFFFFFFF ));
1227 break;
1228 }
1229 case Iop_CmpwNEZ64: {
1230 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1231 if (w64 == 0)
1232 e2 = IRExpr_Const(IRConst_U64( 0 ));
1233 else
1234 e2 = IRExpr_Const(IRConst_U64( 0xFFFFFFFFFFFFFFFFULL ));
1235 break;
1236 }
1237
1238 case Iop_Left32: {
1239 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1240 Int s32 = (Int)(u32 & 0xFFFFFFFF);
1241 s32 = (s32 | (-s32));
1242 e2 = IRExpr_Const( IRConst_U32( (UInt)s32 ));
1243 break;
1244 }
1245
1246 case Iop_Left64: {
1247 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1248 Long s64 = (Long)u64;
1249 s64 = (s64 | (-s64));
1250 e2 = IRExpr_Const( IRConst_U64( (ULong)s64 ));
1251 break;
1252 }
1253
sewardj4cba9f42011-03-07 18:34:34 +00001254 case Iop_Clz32: {
1255 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1256 if (u32 != 0)
1257 e2 = IRExpr_Const(IRConst_U32(fold_Clz32(u32)));
1258 break;
1259 }
1260 case Iop_Clz64: {
1261 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1262 if (u64 != 0ULL)
1263 e2 = IRExpr_Const(IRConst_U64(fold_Clz64(u64)));
1264 break;
1265 }
1266
sewardj84be7372004-08-18 13:59:33 +00001267 default:
1268 goto unhandled;
1269 }
1270 }
1271
1272 /* BINARY ops */
1273 if (e->tag == Iex_Binop) {
1274 if (e->Iex.Binop.arg1->tag == Iex_Const
1275 && e->Iex.Binop.arg2->tag == Iex_Const) {
1276 /* cases where both args are consts */
1277 switch (e->Iex.Binop.op) {
sewardje6b39932004-11-06 17:01:15 +00001278
sewardj855dc722005-02-17 09:26:05 +00001279 /* -- Or -- */
sewardjd9997882004-11-04 19:42:59 +00001280 case Iop_Or8:
sewardj9d2e7692005-02-07 01:11:31 +00001281 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardjd9997882004-11-04 19:42:59 +00001282 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001283 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardjd9997882004-11-04 19:42:59 +00001284 break;
sewardje6b39932004-11-06 17:01:15 +00001285 case Iop_Or16:
sewardj9d2e7692005-02-07 01:11:31 +00001286 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardje6b39932004-11-06 17:01:15 +00001287 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
sewardj9d2e7692005-02-07 01:11:31 +00001288 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
sewardje6b39932004-11-06 17:01:15 +00001289 break;
1290 case Iop_Or32:
1291 e2 = IRExpr_Const(IRConst_U32(
1292 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1293 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1294 break;
sewardjf057afb2005-02-27 13:35:41 +00001295 case Iop_Or64:
1296 e2 = IRExpr_Const(IRConst_U64(
1297 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1298 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1299 break;
sewardje6b39932004-11-06 17:01:15 +00001300
sewardj855dc722005-02-17 09:26:05 +00001301 /* -- Xor -- */
sewardj883b00b2004-09-11 09:30:24 +00001302 case Iop_Xor8:
sewardj9d2e7692005-02-07 01:11:31 +00001303 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj883b00b2004-09-11 09:30:24 +00001304 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001305 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj883b00b2004-09-11 09:30:24 +00001306 break;
sewardj82c9f2f2005-03-02 16:05:13 +00001307 case Iop_Xor16:
sewardjc7c098f2005-03-21 01:06:20 +00001308 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardj82c9f2f2005-03-02 16:05:13 +00001309 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
sewardjc7c098f2005-03-21 01:06:20 +00001310 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
sewardj82c9f2f2005-03-02 16:05:13 +00001311 break;
sewardj855dc722005-02-17 09:26:05 +00001312 case Iop_Xor32:
1313 e2 = IRExpr_Const(IRConst_U32(
1314 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1315 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1316 break;
sewardjf057afb2005-02-27 13:35:41 +00001317 case Iop_Xor64:
1318 e2 = IRExpr_Const(IRConst_U64(
1319 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1320 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1321 break;
sewardj855dc722005-02-17 09:26:05 +00001322
1323 /* -- And -- */
sewardj84be7372004-08-18 13:59:33 +00001324 case Iop_And8:
sewardj9d2e7692005-02-07 01:11:31 +00001325 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj84be7372004-08-18 13:59:33 +00001326 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001327 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj84be7372004-08-18 13:59:33 +00001328 break;
sewardj7f6330d2011-04-05 11:06:02 +00001329 case Iop_And16:
1330 e2 = IRExpr_Const(IRConst_U16(toUShort(
1331 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
1332 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
1333 break;
sewardj855dc722005-02-17 09:26:05 +00001334 case Iop_And32:
1335 e2 = IRExpr_Const(IRConst_U32(
1336 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1337 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1338 break;
1339 case Iop_And64:
1340 e2 = IRExpr_Const(IRConst_U64(
1341 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1342 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1343 break;
1344
1345 /* -- Add -- */
sewardj4345f7a2004-09-22 19:49:27 +00001346 case Iop_Add8:
sewardj9d2e7692005-02-07 01:11:31 +00001347 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj4345f7a2004-09-22 19:49:27 +00001348 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001349 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj4345f7a2004-09-22 19:49:27 +00001350 break;
sewardj855dc722005-02-17 09:26:05 +00001351 case Iop_Add32:
1352 e2 = IRExpr_Const(IRConst_U32(
1353 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1354 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1355 break;
1356 case Iop_Add64:
1357 e2 = IRExpr_Const(IRConst_U64(
1358 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1359 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1360 break;
1361
1362 /* -- Sub -- */
sewardj84be7372004-08-18 13:59:33 +00001363 case Iop_Sub8:
sewardj9d2e7692005-02-07 01:11:31 +00001364 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj84be7372004-08-18 13:59:33 +00001365 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001366 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj84be7372004-08-18 13:59:33 +00001367 break;
sewardjd7217032004-08-19 10:49:10 +00001368 case Iop_Sub32:
1369 e2 = IRExpr_Const(IRConst_U32(
1370 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1371 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1372 break;
sewardj70a8ddf2005-02-13 02:24:26 +00001373 case Iop_Sub64:
1374 e2 = IRExpr_Const(IRConst_U64(
1375 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1376 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1377 break;
sewardjc2bcb6f2005-02-07 00:17:12 +00001378
sewardj478646f2008-05-01 20:13:04 +00001379 /* -- Max32U -- */
1380 case Iop_Max32U: {
1381 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1382 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1383 UInt res = u32a > u32b ? u32a : u32b;
1384 e2 = IRExpr_Const(IRConst_U32(res));
1385 break;
1386 }
1387
sewardj855dc722005-02-17 09:26:05 +00001388 /* -- Mul -- */
sewardjb9c5cf62004-08-24 15:10:38 +00001389 case Iop_Mul32:
1390 e2 = IRExpr_Const(IRConst_U32(
1391 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1392 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1393 break;
sewardja34c0712005-03-30 23:19:46 +00001394 case Iop_Mul64:
1395 e2 = IRExpr_Const(IRConst_U64(
1396 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1397 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1398 break;
1399
sewardjea6bccb2005-03-01 10:19:23 +00001400 case Iop_MullS32: {
1401 /* very paranoid */
1402 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1403 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1404 Int s32a = (Int)u32a;
1405 Int s32b = (Int)u32b;
1406 Long s64a = (Long)s32a;
1407 Long s64b = (Long)s32b;
1408 Long sres = s64a * s64b;
1409 ULong ures = (ULong)sres;
1410 e2 = IRExpr_Const(IRConst_U64(ures));
1411 break;
1412 }
sewardjb095fba2005-02-13 14:13:04 +00001413
sewardj855dc722005-02-17 09:26:05 +00001414 /* -- Shl -- */
sewardjd7217032004-08-19 10:49:10 +00001415 case Iop_Shl32:
sewardj61348472004-08-20 01:01:04 +00001416 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1417 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj29632392004-08-22 02:38:11 +00001418 if (shift >= 0 && shift <= 31)
sewardj278c44c2004-08-20 00:28:13 +00001419 e2 = IRExpr_Const(IRConst_U32(
1420 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1421 << shift)));
sewardjd7217032004-08-19 10:49:10 +00001422 break;
sewardjb095fba2005-02-13 14:13:04 +00001423 case Iop_Shl64:
1424 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1425 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1426 if (shift >= 0 && shift <= 63)
1427 e2 = IRExpr_Const(IRConst_U64(
1428 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1429 << shift)));
1430 break;
1431
sewardj855dc722005-02-17 09:26:05 +00001432 /* -- Sar -- */
sewardj278c44c2004-08-20 00:28:13 +00001433 case Iop_Sar32: {
1434 /* paranoid ... */
1435 /*signed*/ Int s32;
sewardj61348472004-08-20 01:01:04 +00001436 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj278c44c2004-08-20 00:28:13 +00001437 s32 = (Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +00001438 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj278c44c2004-08-20 00:28:13 +00001439 if (shift >= 0 && shift <= 31) {
1440 s32 >>=/*signed*/ shift;
1441 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
1442 }
1443 break;
1444 }
sewardj855dc722005-02-17 09:26:05 +00001445 case Iop_Sar64: {
1446 /* paranoid ... */
1447 /*signed*/ Long s64;
1448 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1449 s64 = (Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64);
1450 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1451 if (shift >= 0 && shift <= 63) {
1452 s64 >>=/*signed*/ shift;
1453 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1454 }
1455 break;
1456 }
1457
1458 /* -- Shr -- */
sewardj61348472004-08-20 01:01:04 +00001459 case Iop_Shr32: {
1460 /* paranoid ... */
sewardj4add7142005-02-21 08:20:22 +00001461 /*unsigned*/ UInt u32;
sewardj61348472004-08-20 01:01:04 +00001462 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj4add7142005-02-21 08:20:22 +00001463 u32 = (UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +00001464 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1465 if (shift >= 0 && shift <= 31) {
sewardj4add7142005-02-21 08:20:22 +00001466 u32 >>=/*unsigned*/ shift;
1467 e2 = IRExpr_Const(IRConst_U32(u32));
1468 }
1469 break;
1470 }
1471 case Iop_Shr64: {
1472 /* paranoid ... */
1473 /*unsigned*/ ULong u64;
1474 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1475 u64 = (ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64);
1476 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1477 if (shift >= 0 && shift <= 63) {
1478 u64 >>=/*unsigned*/ shift;
1479 e2 = IRExpr_Const(IRConst_U64(u64));
sewardj61348472004-08-20 01:01:04 +00001480 }
1481 break;
1482 }
sewardj855dc722005-02-17 09:26:05 +00001483
1484 /* -- CmpEQ -- */
sewardjb8e75862004-08-19 17:58:45 +00001485 case Iop_CmpEQ32:
sewardj9d2e7692005-02-07 01:11:31 +00001486 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardjb8e75862004-08-19 17:58:45 +00001487 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
sewardj9d2e7692005-02-07 01:11:31 +00001488 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))));
sewardjb8e75862004-08-19 17:58:45 +00001489 break;
sewardj855dc722005-02-17 09:26:05 +00001490 case Iop_CmpEQ64:
1491 e2 = IRExpr_Const(IRConst_U1(toBool(
1492 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1493 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U64))));
1494 break;
1495
1496 /* -- CmpNE -- */
1497 case Iop_CmpNE8:
1498 e2 = IRExpr_Const(IRConst_U1(toBool(
1499 ((0xFF & e->Iex.Binop.arg1->Iex.Const.con->Ico.U8)
1500 != (0xFF & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)))));
1501 break;
sewardjae27ab62004-10-15 21:21:46 +00001502 case Iop_CmpNE32:
sewardj9d2e7692005-02-07 01:11:31 +00001503 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardjae27ab62004-10-15 21:21:46 +00001504 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
sewardj9d2e7692005-02-07 01:11:31 +00001505 != e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))));
sewardjae27ab62004-10-15 21:21:46 +00001506 break;
sewardje6b39932004-11-06 17:01:15 +00001507 case Iop_CmpNE64:
sewardj9d2e7692005-02-07 01:11:31 +00001508 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardje6b39932004-11-06 17:01:15 +00001509 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
sewardj9d2e7692005-02-07 01:11:31 +00001510 != e->Iex.Binop.arg2->Iex.Const.con->Ico.U64))));
sewardje6b39932004-11-06 17:01:15 +00001511 break;
1512
sewardj855dc722005-02-17 09:26:05 +00001513 /* -- CmpLEU -- */
sewardj7447b5b2004-10-16 11:30:42 +00001514 case Iop_CmpLE32U:
sewardj9d2e7692005-02-07 01:11:31 +00001515 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj7447b5b2004-10-16 11:30:42 +00001516 ((UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001517 <= (UInt)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj7447b5b2004-10-16 11:30:42 +00001518 break;
sewardj7f6330d2011-04-05 11:06:02 +00001519 case Iop_CmpLE64U:
1520 e2 = IRExpr_Const(IRConst_U1(toBool(
1521 ((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1522 <= (ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1523 break;
sewardj855dc722005-02-17 09:26:05 +00001524
1525 /* -- CmpLES -- */
sewardj088e4f72004-10-19 01:25:02 +00001526 case Iop_CmpLE32S:
sewardj9d2e7692005-02-07 01:11:31 +00001527 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj088e4f72004-10-19 01:25:02 +00001528 ((Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001529 <= (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj088e4f72004-10-19 01:25:02 +00001530 break;
sewardj7f6330d2011-04-05 11:06:02 +00001531 case Iop_CmpLE64S:
1532 e2 = IRExpr_Const(IRConst_U1(toBool(
1533 ((Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1534 <= (Long)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1535 break;
sewardje1d45da2004-11-12 00:13:21 +00001536
sewardj855dc722005-02-17 09:26:05 +00001537 /* -- CmpLTS -- */
sewardj9bdd2652004-10-19 12:56:33 +00001538 case Iop_CmpLT32S:
sewardj9d2e7692005-02-07 01:11:31 +00001539 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj9bdd2652004-10-19 12:56:33 +00001540 ((Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001541 < (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj9bdd2652004-10-19 12:56:33 +00001542 break;
sewardj7f6330d2011-04-05 11:06:02 +00001543 case Iop_CmpLT64S:
1544 e2 = IRExpr_Const(IRConst_U1(toBool(
1545 ((Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1546 < (Long)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1547 break;
sewardj855dc722005-02-17 09:26:05 +00001548
1549 /* -- CmpLTU -- */
sewardje1d45da2004-11-12 00:13:21 +00001550 case Iop_CmpLT32U:
sewardj9d2e7692005-02-07 01:11:31 +00001551 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardje1d45da2004-11-12 00:13:21 +00001552 ((UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001553 < (UInt)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardje1d45da2004-11-12 00:13:21 +00001554 break;
sewardj7f6330d2011-04-05 11:06:02 +00001555 case Iop_CmpLT64U:
1556 e2 = IRExpr_Const(IRConst_U1(toBool(
1557 ((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1558 < (ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1559 break;
sewardj7447b5b2004-10-16 11:30:42 +00001560
sewardjb51f0f42005-07-18 11:38:02 +00001561 /* -- CmpORD -- */
1562 case Iop_CmpORD32S: {
1563 /* very paranoid */
1564 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1565 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1566 Int s32a = (Int)u32a;
1567 Int s32b = (Int)u32b;
1568 Int r = 0x2; /* EQ */
1569 if (s32a < s32b) {
1570 r = 0x8; /* LT */
1571 }
1572 else if (s32a > s32b) {
1573 r = 0x4; /* GT */
1574 }
1575 e2 = IRExpr_Const(IRConst_U32(r));
1576 break;
1577 }
1578
sewardj855dc722005-02-17 09:26:05 +00001579 /* -- nHLto2n -- */
sewardj088bcb42004-08-19 17:16:52 +00001580 case Iop_32HLto64:
1581 e2 = IRExpr_Const(IRConst_U64(
1582 (((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)) << 32)
1583 | ((ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))
1584 ));
1585 break;
sewardj3bc8a592005-05-02 10:47:22 +00001586 case Iop_64HLto128:
1587 /* We can't fold this, because there is no way to
1588 express he result in IR, but at least pretend to
1589 handle it, so as to stop getting blasted with
1590 no-rule-for-this-primop messages. */
1591 break;
sewardj855dc722005-02-17 09:26:05 +00001592
sewardj607dd4f2004-09-08 18:20:19 +00001593 default:
1594 goto unhandled;
sewardjd7217032004-08-19 10:49:10 +00001595 }
sewardjf6729012004-08-25 12:45:13 +00001596
sewardj84be7372004-08-18 13:59:33 +00001597 } else {
sewardjf6729012004-08-25 12:45:13 +00001598
sewardj84be7372004-08-18 13:59:33 +00001599 /* other cases (identities, etc) */
sewardj64d776c2010-10-01 14:06:22 +00001600 switch (e->Iex.Binop.op) {
florianf6402ab2012-01-29 02:19:43 +00001601
1602 case Iop_Shl32:
1603 case Iop_Shl64:
1604 case Iop_Shr64:
1605 /* Shl32/Shl64/Shr64(x,0) ==> x */
1606 if (isZeroU(e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00001607 e2 = e->Iex.Binop.arg1;
florianf6402ab2012-01-29 02:19:43 +00001608 break;
1609 }
1610 /* Shl32/Shl64/Shr64(0,x) ==> 0 */
1611 if (isZeroU(e->Iex.Binop.arg1)) {
1612 e2 = e->Iex.Binop.arg1;
1613 break;
1614 }
sewardj64d776c2010-10-01 14:06:22 +00001615 break;
sewardjf6729012004-08-25 12:45:13 +00001616
florianf6402ab2012-01-29 02:19:43 +00001617 case Iop_Shr32:
1618 /* Shr32(x,0) ==> x */
1619 if (isZeroU(e->Iex.Binop.arg2)) {
1620 e2 = e->Iex.Binop.arg1;
1621 break;
1622 }
1623 break;
1624
1625 case Iop_Or8:
1626 case Iop_Or16:
1627 case Iop_Or32:
1628 case Iop_Or64:
1629 case Iop_Max32U:
1630 /* Or8/Or16/Or32/Max32U(x,0) ==> x */
1631 if (isZeroU(e->Iex.Binop.arg2)) {
1632 e2 = e->Iex.Binop.arg1;
1633 break;
1634 }
1635 /* Or8/Or16/Or32/Max32U(0,x) ==> x */
1636 if (isZeroU(e->Iex.Binop.arg1)) {
1637 e2 = e->Iex.Binop.arg2;
1638 break;
1639 }
1640 /* Or8/Or16/Or32/Max32U(t,t) ==> t, for some IRTemp t */
1641 if (sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
1642 e2 = e->Iex.Binop.arg1;
1643 break;
1644 }
1645 break;
1646
1647 case Iop_Add8:
1648 /* Add8(t,t) ==> t << 1.
1649 Memcheck doesn't understand that
1650 x+x produces a defined least significant bit, and it seems
1651 simplest just to get rid of the problem by rewriting it
1652 out, since the opportunity to do so exists. */
1653 if (sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
1654 e2 = IRExpr_Binop(Iop_Shl8, e->Iex.Binop.arg1,
1655 IRExpr_Const(IRConst_U8(1)));
1656 break;
1657 }
1658 break;
1659
1660 /* NB no Add16(t,t) case yet as no known test case exists */
1661
1662 case Iop_Add32:
1663 case Iop_Add64:
1664 /* Add32/Add64(x,0) ==> x */
1665 if (isZeroU(e->Iex.Binop.arg2)) {
1666 e2 = e->Iex.Binop.arg1;
1667 break;
1668 }
1669 /* Add32/Add64(0,x) ==> x */
1670 if (isZeroU(e->Iex.Binop.arg1)) {
1671 e2 = e->Iex.Binop.arg2;
1672 break;
1673 }
1674 /* Add32/Add64(t,t) ==> t << 1. Same rationale as for Add8. */
1675 if (sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
1676 e2 = IRExpr_Binop(e->Iex.Binop.op == Iop_Add32 ? Iop_Shl32 : Iop_Shl64,
1677 e->Iex.Binop.arg1, IRExpr_Const(IRConst_U8(1)));
1678 break;
1679 }
1680 break;
1681
1682 case Iop_Sub64:
1683 /* Sub64(x,0) ==> x */
1684 if (isZeroU64(e->Iex.Binop.arg2)) {
1685 e2 = e->Iex.Binop.arg1;
1686 break;
1687 }
1688 /* Sub64(t,t) ==> 0, for some IRTemp t */
1689 if (sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00001690 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
florianf6402ab2012-01-29 02:19:43 +00001691 break;
1692 }
sewardj64d776c2010-10-01 14:06:22 +00001693 break;
sewardj64d776c2010-10-01 14:06:22 +00001694
florianf6402ab2012-01-29 02:19:43 +00001695 case Iop_And32:
1696 /* And32(x,0xFFFFFFFF) ==> x */
1697 if (e->Iex.Binop.arg2->tag == Iex_Const
1698 && e->Iex.Binop.arg2->Iex.Const.con->Ico.U32 == 0xFFFFFFFF) {
1699 e2 = e->Iex.Binop.arg1;
1700 break;
1701 }
1702 /* And32(x,0) ==> 0 */
1703 if (isZeroU32(e->Iex.Binop.arg2)) {
1704 e2 = e->Iex.Binop.arg2;
1705 break;
1706 }
1707 /* And32(0,x) ==> 0 */
1708 if (isZeroU32(e->Iex.Binop.arg1)) {
1709 e2 = e->Iex.Binop.arg1;
1710 break;
1711 }
1712 /* And32(t,t) ==> t, for some IRTemp t */
1713 if (sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
1714 e2 = e->Iex.Binop.arg1;
1715 break;
1716 }
1717 break;
1718
1719 case Iop_And8:
1720 case Iop_And16:
1721 case Iop_And64:
1722 /* And8/And16/And64(t,t) ==> t, for some IRTemp t */
1723 if (sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
1724 e2 = e->Iex.Binop.arg1;
1725 break;
1726 }
1727 break;
1728
1729 case Iop_OrV128:
1730 /* V128(t,t) ==> t, for some IRTemp t */
1731 if (sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
1732 e2 = e->Iex.Binop.arg1;
1733 break;
1734 }
1735 break;
1736
1737 case Iop_Xor8:
1738 case Iop_Xor16:
1739 case Iop_Xor32:
1740 case Iop_Xor64:
1741 case Iop_XorV128:
1742 /* Xor8/16/32/64/V128(t,t) ==> 0, for some IRTemp t */
1743 if (sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
1744 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
1745 break;
1746 }
1747 break;
1748
1749 case Iop_Sub32:
1750 /* Sub32(t,t) ==> 0, for some IRTemp t */
1751 if (sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
1752 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
1753 break;
1754 }
1755 break;
1756
sewardj64d776c2010-10-01 14:06:22 +00001757 case Iop_CmpEQ64:
1758 case Iop_CmpEQ8x8:
1759 case Iop_CmpEQ8x16:
florianf6402ab2012-01-29 02:19:43 +00001760 if (sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00001761 e2 = mkOnesOfPrimopResultType(e->Iex.Binop.op);
florianf6402ab2012-01-29 02:19:43 +00001762 break;
1763 }
sewardj64d776c2010-10-01 14:06:22 +00001764 break;
florianf6402ab2012-01-29 02:19:43 +00001765
sewardj64d776c2010-10-01 14:06:22 +00001766 default:
1767 break;
sewardj0033ddc2005-04-26 23:34:34 +00001768 }
sewardj84be7372004-08-18 13:59:33 +00001769 }
1770 }
1771
1772 /* Mux0X */
sewardj6c299f32009-12-31 18:00:12 +00001773 if (e->tag == Iex_Mux0X) {
1774 /* is the discriminant is a constant? */
1775 if (e->Iex.Mux0X.cond->tag == Iex_Const) {
1776 Bool zero;
1777 /* assured us by the IR type rules */
1778 vassert(e->Iex.Mux0X.cond->Iex.Const.con->tag == Ico_U8);
1779 zero = toBool(0 == (0xFF & e->Iex.Mux0X.cond
1780 ->Iex.Const.con->Ico.U8));
1781 e2 = zero ? e->Iex.Mux0X.expr0 : e->Iex.Mux0X.exprX;
1782 }
1783 else
1784 /* are the arms identical? (pretty weedy test) */
1785 if (sameIRTempsOrIcoU32s(e->Iex.Mux0X.expr0,
1786 e->Iex.Mux0X.exprX)) {
1787 e2 = e->Iex.Mux0X.expr0;
1788 }
sewardj84be7372004-08-18 13:59:33 +00001789 }
1790
sewardj64d776c2010-10-01 14:06:22 +00001791 /* Show cases where we've found but not folded 'op(t,t)'. */
1792 if (0 && e == e2 && e->tag == Iex_Binop
1793 && sameIRTemps(e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
1794 vex_printf("IDENT: ");
1795 ppIRExpr(e); vex_printf("\n");
1796 }
1797
1798 /* Show the overall results of folding. */
sewardj088bcb42004-08-19 17:16:52 +00001799 if (DEBUG_IROPT && e2 != e) {
1800 vex_printf("FOLD: ");
sewardj84be7372004-08-18 13:59:33 +00001801 ppIRExpr(e); vex_printf(" -> ");
1802 ppIRExpr(e2); vex_printf("\n");
1803 }
1804
1805 return e2;
1806
1807 unhandled:
sewardj883b00b2004-09-11 09:30:24 +00001808# if 0
sewardj84be7372004-08-18 13:59:33 +00001809 vex_printf("\n\n");
1810 ppIRExpr(e);
1811 vpanic("fold_Expr: no rule for the above");
sewardj883b00b2004-09-11 09:30:24 +00001812# else
sewardj328b54b2005-06-13 16:30:18 +00001813 if (vex_control.iropt_verbosity > 0) {
1814 vex_printf("vex iropt: fold_Expr: no rule for: ");
1815 ppIRExpr(e);
1816 vex_printf("\n");
1817 }
sewardj883b00b2004-09-11 09:30:24 +00001818 return e2;
1819# endif
sewardj84be7372004-08-18 13:59:33 +00001820}
1821
1822
sewardj84be7372004-08-18 13:59:33 +00001823/* Apply the subst to a simple 1-level expression -- guaranteed to be
1824 1-level due to previous flattening pass. */
1825
sewardj62617ef2004-10-13 23:29:22 +00001826static IRExpr* subst_Expr ( IRExpr** env, IRExpr* ex )
sewardj84be7372004-08-18 13:59:33 +00001827{
sewardj62617ef2004-10-13 23:29:22 +00001828 switch (ex->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +00001829 case Iex_RdTmp:
1830 if (env[(Int)ex->Iex.RdTmp.tmp] != NULL) {
1831 return env[(Int)ex->Iex.RdTmp.tmp];
sewardj62617ef2004-10-13 23:29:22 +00001832 } else {
1833 /* not bound in env */
1834 return ex;
1835 }
1836
1837 case Iex_Const:
1838 case Iex_Get:
sewardj84be7372004-08-18 13:59:33 +00001839 return ex;
sewardj62617ef2004-10-13 23:29:22 +00001840
1841 case Iex_GetI:
sewardj496a58d2005-03-20 18:44:44 +00001842 vassert(isIRAtom(ex->Iex.GetI.ix));
sewardj62617ef2004-10-13 23:29:22 +00001843 return IRExpr_GetI(
1844 ex->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +00001845 subst_Expr(env, ex->Iex.GetI.ix),
sewardj62617ef2004-10-13 23:29:22 +00001846 ex->Iex.GetI.bias
1847 );
1848
sewardj40c80262006-02-08 19:30:46 +00001849 case Iex_Qop:
1850 vassert(isIRAtom(ex->Iex.Qop.arg1));
1851 vassert(isIRAtom(ex->Iex.Qop.arg2));
1852 vassert(isIRAtom(ex->Iex.Qop.arg3));
1853 vassert(isIRAtom(ex->Iex.Qop.arg4));
1854 return IRExpr_Qop(
1855 ex->Iex.Qop.op,
1856 subst_Expr(env, ex->Iex.Qop.arg1),
1857 subst_Expr(env, ex->Iex.Qop.arg2),
1858 subst_Expr(env, ex->Iex.Qop.arg3),
1859 subst_Expr(env, ex->Iex.Qop.arg4)
1860 );
1861
sewardjb183b852006-02-03 16:08:03 +00001862 case Iex_Triop:
1863 vassert(isIRAtom(ex->Iex.Triop.arg1));
1864 vassert(isIRAtom(ex->Iex.Triop.arg2));
1865 vassert(isIRAtom(ex->Iex.Triop.arg3));
1866 return IRExpr_Triop(
1867 ex->Iex.Triop.op,
1868 subst_Expr(env, ex->Iex.Triop.arg1),
1869 subst_Expr(env, ex->Iex.Triop.arg2),
1870 subst_Expr(env, ex->Iex.Triop.arg3)
1871 );
1872
sewardj62617ef2004-10-13 23:29:22 +00001873 case Iex_Binop:
sewardj496a58d2005-03-20 18:44:44 +00001874 vassert(isIRAtom(ex->Iex.Binop.arg1));
1875 vassert(isIRAtom(ex->Iex.Binop.arg2));
sewardj62617ef2004-10-13 23:29:22 +00001876 return IRExpr_Binop(
1877 ex->Iex.Binop.op,
1878 subst_Expr(env, ex->Iex.Binop.arg1),
1879 subst_Expr(env, ex->Iex.Binop.arg2)
1880 );
1881
1882 case Iex_Unop:
sewardj496a58d2005-03-20 18:44:44 +00001883 vassert(isIRAtom(ex->Iex.Unop.arg));
sewardj62617ef2004-10-13 23:29:22 +00001884 return IRExpr_Unop(
1885 ex->Iex.Unop.op,
1886 subst_Expr(env, ex->Iex.Unop.arg)
1887 );
1888
sewardjaf1ceca2005-06-30 23:31:27 +00001889 case Iex_Load:
1890 vassert(isIRAtom(ex->Iex.Load.addr));
1891 return IRExpr_Load(
1892 ex->Iex.Load.end,
1893 ex->Iex.Load.ty,
1894 subst_Expr(env, ex->Iex.Load.addr)
sewardj62617ef2004-10-13 23:29:22 +00001895 );
1896
1897 case Iex_CCall: {
1898 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +00001899 IRExpr** args2 = shallowCopyIRExprVec(ex->Iex.CCall.args);
sewardj62617ef2004-10-13 23:29:22 +00001900 for (i = 0; args2[i]; i++) {
sewardj496a58d2005-03-20 18:44:44 +00001901 vassert(isIRAtom(args2[i]));
sewardj62617ef2004-10-13 23:29:22 +00001902 args2[i] = subst_Expr(env, args2[i]);
1903 }
1904 return IRExpr_CCall(
sewardj8ea867b2004-10-30 19:03:02 +00001905 ex->Iex.CCall.cee,
sewardj62617ef2004-10-13 23:29:22 +00001906 ex->Iex.CCall.retty,
1907 args2
1908 );
sewardj84be7372004-08-18 13:59:33 +00001909 }
sewardj62617ef2004-10-13 23:29:22 +00001910
1911 case Iex_Mux0X:
sewardj496a58d2005-03-20 18:44:44 +00001912 vassert(isIRAtom(ex->Iex.Mux0X.cond));
1913 vassert(isIRAtom(ex->Iex.Mux0X.expr0));
1914 vassert(isIRAtom(ex->Iex.Mux0X.exprX));
sewardj62617ef2004-10-13 23:29:22 +00001915 return IRExpr_Mux0X(
1916 subst_Expr(env, ex->Iex.Mux0X.cond),
1917 subst_Expr(env, ex->Iex.Mux0X.expr0),
1918 subst_Expr(env, ex->Iex.Mux0X.exprX)
1919 );
1920
1921 default:
1922 vex_printf("\n\n"); ppIRExpr(ex);
1923 vpanic("subst_Expr");
1924
sewardj84be7372004-08-18 13:59:33 +00001925 }
sewardj84be7372004-08-18 13:59:33 +00001926}
1927
1928
1929/* Apply the subst to stmt, then fold the result as much as possible.
sewardjd2445f62005-03-21 00:15:53 +00001930 Much simplified due to stmt being previously flattened. As a
1931 result of this, the stmt may wind up being turned into a no-op.
1932*/
sewardj62617ef2004-10-13 23:29:22 +00001933static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st )
sewardj84be7372004-08-18 13:59:33 +00001934{
1935# if 0
1936 vex_printf("\nsubst and fold stmt\n");
1937 ppIRStmt(st);
1938 vex_printf("\n");
1939# endif
1940
sewardj62617ef2004-10-13 23:29:22 +00001941 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00001942 case Ist_AbiHint:
1943 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +00001944 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +00001945 return IRStmt_AbiHint(
1946 fold_Expr(subst_Expr(env, st->Ist.AbiHint.base)),
sewardj478646f2008-05-01 20:13:04 +00001947 st->Ist.AbiHint.len,
1948 fold_Expr(subst_Expr(env, st->Ist.AbiHint.nia))
sewardj5a9ffab2005-05-12 17:55:01 +00001949 );
sewardj62617ef2004-10-13 23:29:22 +00001950 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00001951 vassert(isIRAtom(st->Ist.Put.data));
sewardj62617ef2004-10-13 23:29:22 +00001952 return IRStmt_Put(
1953 st->Ist.Put.offset,
1954 fold_Expr(subst_Expr(env, st->Ist.Put.data))
1955 );
sewardj84be7372004-08-18 13:59:33 +00001956
sewardj62617ef2004-10-13 23:29:22 +00001957 case Ist_PutI:
sewardj496a58d2005-03-20 18:44:44 +00001958 vassert(isIRAtom(st->Ist.PutI.ix));
1959 vassert(isIRAtom(st->Ist.PutI.data));
sewardj62617ef2004-10-13 23:29:22 +00001960 return IRStmt_PutI(
1961 st->Ist.PutI.descr,
sewardjeeac8412004-11-02 00:26:55 +00001962 fold_Expr(subst_Expr(env, st->Ist.PutI.ix)),
sewardj62617ef2004-10-13 23:29:22 +00001963 st->Ist.PutI.bias,
1964 fold_Expr(subst_Expr(env, st->Ist.PutI.data))
1965 );
sewardjd7217032004-08-19 10:49:10 +00001966
sewardjdd40fdf2006-12-24 02:20:24 +00001967 case Ist_WrTmp:
1968 /* This is the one place where an expr (st->Ist.WrTmp.data) is
sewardj62617ef2004-10-13 23:29:22 +00001969 allowed to be more than just a constant or a tmp. */
sewardjdd40fdf2006-12-24 02:20:24 +00001970 return IRStmt_WrTmp(
1971 st->Ist.WrTmp.tmp,
1972 fold_Expr(subst_Expr(env, st->Ist.WrTmp.data))
sewardj62617ef2004-10-13 23:29:22 +00001973 );
sewardj84be7372004-08-18 13:59:33 +00001974
sewardjaf1ceca2005-06-30 23:31:27 +00001975 case Ist_Store:
1976 vassert(isIRAtom(st->Ist.Store.addr));
1977 vassert(isIRAtom(st->Ist.Store.data));
1978 return IRStmt_Store(
1979 st->Ist.Store.end,
1980 fold_Expr(subst_Expr(env, st->Ist.Store.addr)),
1981 fold_Expr(subst_Expr(env, st->Ist.Store.data))
sewardj62617ef2004-10-13 23:29:22 +00001982 );
sewardj84be7372004-08-18 13:59:33 +00001983
sewardje9d8a262009-07-01 08:06:34 +00001984 case Ist_CAS: {
1985 IRCAS *cas, *cas2;
1986 cas = st->Ist.CAS.details;
1987 vassert(isIRAtom(cas->addr));
1988 vassert(cas->expdHi == NULL || isIRAtom(cas->expdHi));
1989 vassert(isIRAtom(cas->expdLo));
1990 vassert(cas->dataHi == NULL || isIRAtom(cas->dataHi));
1991 vassert(isIRAtom(cas->dataLo));
1992 cas2 = mkIRCAS(
1993 cas->oldHi, cas->oldLo, cas->end,
1994 fold_Expr(subst_Expr(env, cas->addr)),
1995 cas->expdHi ? fold_Expr(subst_Expr(env, cas->expdHi)) : NULL,
1996 fold_Expr(subst_Expr(env, cas->expdLo)),
1997 cas->dataHi ? fold_Expr(subst_Expr(env, cas->dataHi)) : NULL,
1998 fold_Expr(subst_Expr(env, cas->dataLo))
1999 );
2000 return IRStmt_CAS(cas2);
2001 }
2002
sewardje768e922009-11-26 17:17:37 +00002003 case Ist_LLSC:
2004 vassert(isIRAtom(st->Ist.LLSC.addr));
2005 if (st->Ist.LLSC.storedata)
2006 vassert(isIRAtom(st->Ist.LLSC.storedata));
2007 return IRStmt_LLSC(
2008 st->Ist.LLSC.end,
2009 st->Ist.LLSC.result,
2010 fold_Expr(subst_Expr(env, st->Ist.LLSC.addr)),
2011 st->Ist.LLSC.storedata
2012 ? fold_Expr(subst_Expr(env, st->Ist.LLSC.storedata))
2013 : NULL
2014 );
2015
sewardj62617ef2004-10-13 23:29:22 +00002016 case Ist_Dirty: {
2017 Int i;
2018 IRDirty *d, *d2;
2019 d = st->Ist.Dirty.details;
2020 d2 = emptyIRDirty();
2021 *d2 = *d;
sewardjdd40fdf2006-12-24 02:20:24 +00002022 d2->args = shallowCopyIRExprVec(d2->args);
sewardj62617ef2004-10-13 23:29:22 +00002023 if (d2->mFx != Ifx_None) {
sewardj496a58d2005-03-20 18:44:44 +00002024 vassert(isIRAtom(d2->mAddr));
sewardj62617ef2004-10-13 23:29:22 +00002025 d2->mAddr = fold_Expr(subst_Expr(env, d2->mAddr));
sewardjb8e75862004-08-19 17:58:45 +00002026 }
sewardj496a58d2005-03-20 18:44:44 +00002027 vassert(isIRAtom(d2->guard));
sewardjb8385d82004-11-02 01:34:15 +00002028 d2->guard = fold_Expr(subst_Expr(env, d2->guard));
sewardj62617ef2004-10-13 23:29:22 +00002029 for (i = 0; d2->args[i]; i++) {
sewardj496a58d2005-03-20 18:44:44 +00002030 vassert(isIRAtom(d2->args[i]));
sewardj62617ef2004-10-13 23:29:22 +00002031 d2->args[i] = fold_Expr(subst_Expr(env, d2->args[i]));
2032 }
2033 return IRStmt_Dirty(d2);
sewardjb8e75862004-08-19 17:58:45 +00002034 }
sewardj84be7372004-08-18 13:59:33 +00002035
sewardjf1689312005-03-16 18:19:10 +00002036 case Ist_IMark:
sewardj2f10aa62011-05-27 13:20:56 +00002037 return IRStmt_IMark(st->Ist.IMark.addr,
2038 st->Ist.IMark.len,
2039 st->Ist.IMark.delta);
sewardjf1689312005-03-16 18:19:10 +00002040
sewardjd2445f62005-03-21 00:15:53 +00002041 case Ist_NoOp:
2042 return IRStmt_NoOp();
2043
sewardjc4356f02007-11-09 21:15:04 +00002044 case Ist_MBE:
2045 return IRStmt_MBE(st->Ist.MBE.event);
sewardj3e838932005-01-07 12:09:15 +00002046
sewardj62617ef2004-10-13 23:29:22 +00002047 case Ist_Exit: {
2048 IRExpr* fcond;
sewardj496a58d2005-03-20 18:44:44 +00002049 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj0276d4b2004-11-15 15:30:21 +00002050 fcond = fold_Expr(subst_Expr(env, st->Ist.Exit.guard));
sewardj62617ef2004-10-13 23:29:22 +00002051 if (fcond->tag == Iex_Const) {
2052 /* Interesting. The condition on this exit has folded down to
2053 a constant. */
sewardjba999312004-11-15 15:21:17 +00002054 vassert(fcond->Iex.Const.con->tag == Ico_U1);
sewardj98430292004-12-29 17:34:50 +00002055 vassert(fcond->Iex.Const.con->Ico.U1 == False
2056 || fcond->Iex.Const.con->Ico.U1 == True);
sewardjba999312004-11-15 15:21:17 +00002057 if (fcond->Iex.Const.con->Ico.U1 == False) {
sewardj62617ef2004-10-13 23:29:22 +00002058 /* exit is never going to happen, so dump the statement. */
sewardjd2445f62005-03-21 00:15:53 +00002059 return IRStmt_NoOp();
sewardj62617ef2004-10-13 23:29:22 +00002060 } else {
sewardjba999312004-11-15 15:21:17 +00002061 vassert(fcond->Iex.Const.con->Ico.U1 == True);
sewardje810c192005-09-09 08:33:03 +00002062 /* Hmmm. The exit has become unconditional. Leave it
2063 as it is for now, since we'd have to truncate the BB
2064 at this point, which is tricky. Such truncation is
2065 done later by the dead-code elimination pass. */
sewardj62617ef2004-10-13 23:29:22 +00002066 /* fall out into the reconstruct-the-exit code. */
sewardj08613742004-10-25 13:01:45 +00002067 if (vex_control.iropt_verbosity > 0)
2068 /* really a misuse of vex_control.iropt_verbosity */
sewardj8c2c10b2004-10-16 20:51:52 +00002069 vex_printf("vex iropt: IRStmt_Exit became unconditional\n");
sewardj62617ef2004-10-13 23:29:22 +00002070 }
2071 }
sewardj893aada2004-11-29 19:57:54 +00002072 return IRStmt_Exit(fcond, st->Ist.Exit.jk, st->Ist.Exit.dst);
sewardj62617ef2004-10-13 23:29:22 +00002073 }
2074
2075 default:
2076 vex_printf("\n"); ppIRStmt(st);
2077 vpanic("subst_and_fold_Stmt");
2078 }
sewardj84be7372004-08-18 13:59:33 +00002079}
2080
2081
sewardjdd40fdf2006-12-24 02:20:24 +00002082IRSB* cprop_BB ( IRSB* in )
sewardj84be7372004-08-18 13:59:33 +00002083{
sewardj62617ef2004-10-13 23:29:22 +00002084 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +00002085 IRSB* out;
sewardj62617ef2004-10-13 23:29:22 +00002086 IRStmt* st2;
2087 Int n_tmps = in->tyenv->types_used;
2088 IRExpr** env = LibVEX_Alloc(n_tmps * sizeof(IRExpr*));
sewardj84be7372004-08-18 13:59:33 +00002089
sewardjdd40fdf2006-12-24 02:20:24 +00002090 out = emptyIRSB();
2091 out->tyenv = deepCopyIRTypeEnv( in->tyenv );
sewardj84be7372004-08-18 13:59:33 +00002092
2093 /* Set up the env with which travels forward. This holds a
2094 substitution, mapping IRTemps to atoms, that is, IRExprs which
2095 are either IRTemps or IRConsts. Thus, copy and constant
2096 propagation is done. The environment is to be applied as we
2097 move along. Keys are IRTemps. Values are IRExpr*s.
2098 */
sewardj62617ef2004-10-13 23:29:22 +00002099 for (i = 0; i < n_tmps; i++)
2100 env[i] = NULL;
sewardj84be7372004-08-18 13:59:33 +00002101
2102 /* For each original SSA-form stmt ... */
2103 for (i = 0; i < in->stmts_used; i++) {
2104
2105 /* First apply the substitution to the current stmt. This
2106 propagates in any constants and tmp-tmp assignments
2107 accumulated prior to this point. As part of the subst_Stmt
2108 call, also then fold any constant expressions resulting. */
2109
sewardjf0e43162004-08-20 00:11:12 +00002110 st2 = in->stmts[i];
2111
2112 /* perhaps st2 is already a no-op? */
sewardj8bee6d12005-03-22 02:24:05 +00002113 if (st2->tag == Ist_NoOp) continue;
sewardjf0e43162004-08-20 00:11:12 +00002114
2115 st2 = subst_and_fold_Stmt( env, st2 );
sewardj84be7372004-08-18 13:59:33 +00002116
sewardjb8e75862004-08-19 17:58:45 +00002117 /* If the statement has been folded into a no-op, forget it. */
sewardj8bee6d12005-03-22 02:24:05 +00002118 if (st2->tag == Ist_NoOp) continue;
sewardjb8e75862004-08-19 17:58:45 +00002119
sewardj84be7372004-08-18 13:59:33 +00002120 /* Now consider what the stmt looks like. If it's of the form
2121 't = const' or 't1 = t2', add it to the running environment
2122 and not to the output BB. Otherwise, add it to the output
sewardjc0b42282004-10-12 13:44:12 +00002123 BB. Note, we choose not to propagate const when const is an
2124 F64i, so that F64i literals can be CSE'd later. This helps
2125 x86 floating point code generation. */
sewardj84be7372004-08-18 13:59:33 +00002126
sewardjdd40fdf2006-12-24 02:20:24 +00002127 if (st2->tag == Ist_WrTmp
2128 && st2->Ist.WrTmp.data->tag == Iex_Const
2129 && st2->Ist.WrTmp.data->Iex.Const.con->tag != Ico_F64i) {
sewardj84be7372004-08-18 13:59:33 +00002130 /* 't = const' -- add to env.
2131 The pair (IRTemp, IRExpr*) is added. */
sewardjdd40fdf2006-12-24 02:20:24 +00002132 env[(Int)(st2->Ist.WrTmp.tmp)] = st2->Ist.WrTmp.data;
sewardj84be7372004-08-18 13:59:33 +00002133 }
2134 else
sewardjdd40fdf2006-12-24 02:20:24 +00002135 if (st2->tag == Ist_WrTmp && st2->Ist.WrTmp.data->tag == Iex_RdTmp) {
sewardj84be7372004-08-18 13:59:33 +00002136 /* 't1 = t2' -- add to env.
2137 The pair (IRTemp, IRExpr*) is added. */
sewardjdd40fdf2006-12-24 02:20:24 +00002138 env[(Int)(st2->Ist.WrTmp.tmp)] = st2->Ist.WrTmp.data;
sewardj84be7372004-08-18 13:59:33 +00002139 }
2140 else {
2141 /* Not interesting, copy st2 into the output block. */
sewardjdd40fdf2006-12-24 02:20:24 +00002142 addStmtToIRSB( out, st2 );
sewardj84be7372004-08-18 13:59:33 +00002143 }
2144 }
2145
sewardj84be7372004-08-18 13:59:33 +00002146 out->next = subst_Expr( env, in->next );
2147 out->jumpkind = in->jumpkind;
2148 return out;
2149}
2150
2151
sewardjedf4d692004-08-17 13:52:58 +00002152/*---------------------------------------------------------------*/
sewardj39e3f242004-08-18 16:54:52 +00002153/*--- Dead code (t = E) removal ---*/
2154/*---------------------------------------------------------------*/
2155
sewardje810c192005-09-09 08:33:03 +00002156/* As a side effect, also removes all code following an unconditional
2157 side exit. */
2158
sewardjea602bc2004-10-14 21:40:12 +00002159/* The type of the HashHW map is: a map from IRTemp to nothing
sewardj39e3f242004-08-18 16:54:52 +00002160 -- really just operating a set or IRTemps.
2161*/
2162
sewardjd503a322004-10-13 22:41:16 +00002163inline
2164static void addUses_Temp ( Bool* set, IRTemp tmp )
sewardj17442fe2004-09-20 14:54:28 +00002165{
sewardjd503a322004-10-13 22:41:16 +00002166 set[(Int)tmp] = True;
sewardj17442fe2004-09-20 14:54:28 +00002167}
2168
sewardjd503a322004-10-13 22:41:16 +00002169static void addUses_Expr ( Bool* set, IRExpr* e )
sewardj39e3f242004-08-18 16:54:52 +00002170{
2171 Int i;
2172 switch (e->tag) {
sewardjd7217032004-08-19 10:49:10 +00002173 case Iex_GetI:
sewardjeeac8412004-11-02 00:26:55 +00002174 addUses_Expr(set, e->Iex.GetI.ix);
sewardjd7217032004-08-19 10:49:10 +00002175 return;
sewardj39e3f242004-08-18 16:54:52 +00002176 case Iex_Mux0X:
2177 addUses_Expr(set, e->Iex.Mux0X.cond);
2178 addUses_Expr(set, e->Iex.Mux0X.expr0);
2179 addUses_Expr(set, e->Iex.Mux0X.exprX);
2180 return;
2181 case Iex_CCall:
2182 for (i = 0; e->Iex.CCall.args[i]; i++)
2183 addUses_Expr(set, e->Iex.CCall.args[i]);
2184 return;
sewardjaf1ceca2005-06-30 23:31:27 +00002185 case Iex_Load:
2186 addUses_Expr(set, e->Iex.Load.addr);
sewardj39e3f242004-08-18 16:54:52 +00002187 return;
sewardj40c80262006-02-08 19:30:46 +00002188 case Iex_Qop:
2189 addUses_Expr(set, e->Iex.Qop.arg1);
2190 addUses_Expr(set, e->Iex.Qop.arg2);
2191 addUses_Expr(set, e->Iex.Qop.arg3);
2192 addUses_Expr(set, e->Iex.Qop.arg4);
2193 return;
sewardjb183b852006-02-03 16:08:03 +00002194 case Iex_Triop:
2195 addUses_Expr(set, e->Iex.Triop.arg1);
2196 addUses_Expr(set, e->Iex.Triop.arg2);
2197 addUses_Expr(set, e->Iex.Triop.arg3);
2198 return;
sewardj39e3f242004-08-18 16:54:52 +00002199 case Iex_Binop:
2200 addUses_Expr(set, e->Iex.Binop.arg1);
2201 addUses_Expr(set, e->Iex.Binop.arg2);
2202 return;
2203 case Iex_Unop:
2204 addUses_Expr(set, e->Iex.Unop.arg);
2205 return;
sewardjdd40fdf2006-12-24 02:20:24 +00002206 case Iex_RdTmp:
2207 addUses_Temp(set, e->Iex.RdTmp.tmp);
sewardj39e3f242004-08-18 16:54:52 +00002208 return;
2209 case Iex_Const:
2210 case Iex_Get:
2211 return;
2212 default:
2213 vex_printf("\n");
2214 ppIRExpr(e);
2215 vpanic("addUses_Expr");
2216 }
2217}
2218
sewardjd503a322004-10-13 22:41:16 +00002219static void addUses_Stmt ( Bool* set, IRStmt* st )
sewardj39e3f242004-08-18 16:54:52 +00002220{
sewardj17442fe2004-09-20 14:54:28 +00002221 Int i;
2222 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00002223 IRCAS* cas;
sewardj39e3f242004-08-18 16:54:52 +00002224 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00002225 case Ist_AbiHint:
2226 addUses_Expr(set, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +00002227 addUses_Expr(set, st->Ist.AbiHint.nia);
sewardj5a9ffab2005-05-12 17:55:01 +00002228 return;
sewardjd7217032004-08-19 10:49:10 +00002229 case Ist_PutI:
sewardjeeac8412004-11-02 00:26:55 +00002230 addUses_Expr(set, st->Ist.PutI.ix);
sewardj2d3f77c2004-09-22 23:49:09 +00002231 addUses_Expr(set, st->Ist.PutI.data);
sewardjd7217032004-08-19 10:49:10 +00002232 return;
sewardjdd40fdf2006-12-24 02:20:24 +00002233 case Ist_WrTmp:
2234 addUses_Expr(set, st->Ist.WrTmp.data);
sewardj39e3f242004-08-18 16:54:52 +00002235 return;
2236 case Ist_Put:
sewardj6d076362004-09-23 11:06:17 +00002237 addUses_Expr(set, st->Ist.Put.data);
sewardj39e3f242004-08-18 16:54:52 +00002238 return;
sewardjaf1ceca2005-06-30 23:31:27 +00002239 case Ist_Store:
2240 addUses_Expr(set, st->Ist.Store.addr);
2241 addUses_Expr(set, st->Ist.Store.data);
sewardj39e3f242004-08-18 16:54:52 +00002242 return;
sewardje9d8a262009-07-01 08:06:34 +00002243 case Ist_CAS:
2244 cas = st->Ist.CAS.details;
2245 addUses_Expr(set, cas->addr);
2246 if (cas->expdHi)
2247 addUses_Expr(set, cas->expdHi);
2248 addUses_Expr(set, cas->expdLo);
2249 if (cas->dataHi)
2250 addUses_Expr(set, cas->dataHi);
2251 addUses_Expr(set, cas->dataLo);
2252 return;
sewardje768e922009-11-26 17:17:37 +00002253 case Ist_LLSC:
2254 addUses_Expr(set, st->Ist.LLSC.addr);
2255 if (st->Ist.LLSC.storedata)
2256 addUses_Expr(set, st->Ist.LLSC.storedata);
2257 return;
sewardj17442fe2004-09-20 14:54:28 +00002258 case Ist_Dirty:
2259 d = st->Ist.Dirty.details;
2260 if (d->mFx != Ifx_None)
2261 addUses_Expr(set, d->mAddr);
sewardjb8385d82004-11-02 01:34:15 +00002262 addUses_Expr(set, d->guard);
sewardj17442fe2004-09-20 14:54:28 +00002263 for (i = 0; d->args[i] != NULL; i++)
2264 addUses_Expr(set, d->args[i]);
2265 return;
sewardjd2445f62005-03-21 00:15:53 +00002266 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00002267 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00002268 case Ist_MBE:
sewardj3e838932005-01-07 12:09:15 +00002269 return;
sewardj17442fe2004-09-20 14:54:28 +00002270 case Ist_Exit:
sewardj0276d4b2004-11-15 15:30:21 +00002271 addUses_Expr(set, st->Ist.Exit.guard);
sewardj17442fe2004-09-20 14:54:28 +00002272 return;
sewardj39e3f242004-08-18 16:54:52 +00002273 default:
2274 vex_printf("\n");
2275 ppIRStmt(st);
2276 vpanic("addUses_Stmt");
sewardjd503a322004-10-13 22:41:16 +00002277 }
sewardj39e3f242004-08-18 16:54:52 +00002278}
2279
2280
sewardjba999312004-11-15 15:21:17 +00002281/* Is this literally IRExpr_Const(IRConst_U1(False)) ? */
2282static Bool isZeroU1 ( IRExpr* e )
sewardjd9997882004-11-04 19:42:59 +00002283{
sewardj9d2e7692005-02-07 01:11:31 +00002284 return toBool( e->tag == Iex_Const
2285 && e->Iex.Const.con->tag == Ico_U1
2286 && e->Iex.Const.con->Ico.U1 == False );
sewardjd9997882004-11-04 19:42:59 +00002287}
2288
sewardje810c192005-09-09 08:33:03 +00002289/* Is this literally IRExpr_Const(IRConst_U1(True)) ? */
2290static Bool isOneU1 ( IRExpr* e )
2291{
2292 return toBool( e->tag == Iex_Const
2293 && e->Iex.Const.con->tag == Ico_U1
2294 && e->Iex.Const.con->Ico.U1 == True );
2295}
2296
sewardj39e3f242004-08-18 16:54:52 +00002297
sewardjdd40fdf2006-12-24 02:20:24 +00002298/* Note, this destructively modifies the given IRSB. */
sewardj39e3f242004-08-18 16:54:52 +00002299
2300/* Scan backwards through statements, carrying a set of IRTemps which
2301 are known to be used after the current point. On encountering 't =
2302 E', delete the binding if it is not used. Otherwise, add any temp
sewardje810c192005-09-09 08:33:03 +00002303 uses to the set and keep on moving backwards.
2304
2305 As an enhancement, the first (backwards) pass searches for IR exits
2306 with always-taken conditions and notes the location of the earliest
2307 one in the block. If any such are found, a second pass copies the
2308 exit destination and jump kind to the bb-end. Then, the exit and
2309 all statements following it are turned into no-ops.
2310*/
sewardj39e3f242004-08-18 16:54:52 +00002311
sewardjdd40fdf2006-12-24 02:20:24 +00002312/* notstatic */ void do_deadcode_BB ( IRSB* bb )
sewardj39e3f242004-08-18 16:54:52 +00002313{
sewardje810c192005-09-09 08:33:03 +00002314 Int i, i_unconditional_exit;
sewardjd503a322004-10-13 22:41:16 +00002315 Int n_tmps = bb->tyenv->types_used;
2316 Bool* set = LibVEX_Alloc(n_tmps * sizeof(Bool));
sewardj39e3f242004-08-18 16:54:52 +00002317 IRStmt* st;
2318
sewardjd503a322004-10-13 22:41:16 +00002319 for (i = 0; i < n_tmps; i++)
2320 set[i] = False;
2321
sewardj39e3f242004-08-18 16:54:52 +00002322 /* start off by recording IRTemp uses in the next field. */
2323 addUses_Expr(set, bb->next);
2324
sewardje810c192005-09-09 08:33:03 +00002325 /* First pass */
2326
sewardj39e3f242004-08-18 16:54:52 +00002327 /* Work backwards through the stmts */
sewardje810c192005-09-09 08:33:03 +00002328 i_unconditional_exit = -1;
sewardj39e3f242004-08-18 16:54:52 +00002329 for (i = bb->stmts_used-1; i >= 0; i--) {
2330 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00002331 if (st->tag == Ist_NoOp)
sewardj84ff0652004-08-23 16:16:08 +00002332 continue;
sewardje810c192005-09-09 08:33:03 +00002333 /* take note of any unconditional exits */
2334 if (st->tag == Ist_Exit
2335 && isOneU1(st->Ist.Exit.guard))
2336 i_unconditional_exit = i;
sewardjdd40fdf2006-12-24 02:20:24 +00002337 if (st->tag == Ist_WrTmp
2338 && set[(Int)(st->Ist.WrTmp.tmp)] == False) {
sewardj39e3f242004-08-18 16:54:52 +00002339 /* it's an IRTemp which never got used. Delete it. */
sewardj088bcb42004-08-19 17:16:52 +00002340 if (DEBUG_IROPT) {
sewardj39e3f242004-08-18 16:54:52 +00002341 vex_printf("DEAD: ");
2342 ppIRStmt(st);
2343 vex_printf("\n");
2344 }
sewardjd2445f62005-03-21 00:15:53 +00002345 bb->stmts[i] = IRStmt_NoOp();
sewardjd9997882004-11-04 19:42:59 +00002346 }
2347 else
2348 if (st->tag == Ist_Dirty
2349 && st->Ist.Dirty.details->guard
sewardjba999312004-11-15 15:21:17 +00002350 && isZeroU1(st->Ist.Dirty.details->guard)) {
sewardjd2445f62005-03-21 00:15:53 +00002351 /* This is a dirty helper which will never get called.
2352 Delete it. */
2353 bb->stmts[i] = IRStmt_NoOp();
sewardjd9997882004-11-04 19:42:59 +00002354 }
2355 else {
sewardj39e3f242004-08-18 16:54:52 +00002356 /* Note any IRTemp uses made by the current statement. */
2357 addUses_Stmt(set, st);
2358 }
2359 }
sewardje810c192005-09-09 08:33:03 +00002360
2361 /* Optional second pass: if any unconditional exits were found,
2362 delete them and all following statements. */
2363
2364 if (i_unconditional_exit != -1) {
2365 if (0) vex_printf("ZAPPING ALL FORWARDS from %d\n",
2366 i_unconditional_exit);
2367 vassert(i_unconditional_exit >= 0
2368 && i_unconditional_exit < bb->stmts_used);
2369 bb->next
2370 = IRExpr_Const( bb->stmts[i_unconditional_exit]->Ist.Exit.dst );
2371 bb->jumpkind
2372 = bb->stmts[i_unconditional_exit]->Ist.Exit.jk;
2373 for (i = i_unconditional_exit; i < bb->stmts_used; i++)
2374 bb->stmts[i] = IRStmt_NoOp();
2375 }
sewardj39e3f242004-08-18 16:54:52 +00002376}
2377
sewardje810c192005-09-09 08:33:03 +00002378
sewardj84ff0652004-08-23 16:16:08 +00002379/*---------------------------------------------------------------*/
2380/*--- Specialisation of helper function calls, in ---*/
2381/*--- collaboration with the front end ---*/
2382/*---------------------------------------------------------------*/
2383
2384static
sewardjbe917912010-08-22 12:38:53 +00002385IRSB* spec_helpers_BB(
2386 IRSB* bb,
2387 IRExpr* (*specHelper) (HChar*, IRExpr**, IRStmt**, Int)
2388 )
sewardj84ff0652004-08-23 16:16:08 +00002389{
sewardjb9230752004-12-29 19:25:06 +00002390 Int i;
sewardj84ff0652004-08-23 16:16:08 +00002391 IRStmt* st;
2392 IRExpr* ex;
sewardjb9230752004-12-29 19:25:06 +00002393 Bool any = False;
sewardj84ff0652004-08-23 16:16:08 +00002394
2395 for (i = bb->stmts_used-1; i >= 0; i--) {
2396 st = bb->stmts[i];
2397
sewardjdd40fdf2006-12-24 02:20:24 +00002398 if (st->tag != Ist_WrTmp
2399 || st->Ist.WrTmp.data->tag != Iex_CCall)
sewardj8bee6d12005-03-22 02:24:05 +00002400 continue;
sewardj84ff0652004-08-23 16:16:08 +00002401
sewardjdd40fdf2006-12-24 02:20:24 +00002402 ex = (*specHelper)( st->Ist.WrTmp.data->Iex.CCall.cee->name,
sewardjbe917912010-08-22 12:38:53 +00002403 st->Ist.WrTmp.data->Iex.CCall.args,
2404 &bb->stmts[0], i );
sewardj84ff0652004-08-23 16:16:08 +00002405 if (!ex)
sewardjaba4fff2004-10-08 21:37:15 +00002406 /* the front end can't think of a suitable replacement */
2407 continue;
sewardj84ff0652004-08-23 16:16:08 +00002408
2409 /* We got something better. Install it in the bb. */
sewardjb9230752004-12-29 19:25:06 +00002410 any = True;
sewardj84ff0652004-08-23 16:16:08 +00002411 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00002412 = IRStmt_WrTmp(st->Ist.WrTmp.tmp, ex);
sewardj84ff0652004-08-23 16:16:08 +00002413
2414 if (0) {
2415 vex_printf("SPEC: ");
sewardjdd40fdf2006-12-24 02:20:24 +00002416 ppIRExpr(st->Ist.WrTmp.data);
sewardj84ff0652004-08-23 16:16:08 +00002417 vex_printf(" --> ");
2418 ppIRExpr(ex);
2419 vex_printf("\n");
2420 }
2421 }
sewardjb9230752004-12-29 19:25:06 +00002422
2423 if (any)
2424 bb = flatten_BB(bb);
2425 return bb;
sewardj84ff0652004-08-23 16:16:08 +00002426}
2427
sewardj29632392004-08-22 02:38:11 +00002428
2429/*---------------------------------------------------------------*/
sewardj9b0cc582006-02-04 15:24:00 +00002430/*--- Determination of guest state aliasing relationships ---*/
2431/*---------------------------------------------------------------*/
2432
2433/* These are helper functions for CSE and GetI/PutI transformations.
2434
2435 Determine, to the extent possible, the relationship between two
2436 guest state accesses. The possible outcomes are:
2437
2438 * Exact alias. These two accesses denote precisely the same
2439 piece of the guest state.
2440
2441 * Definitely no alias. These two accesses are guaranteed not to
2442 overlap any part of the guest state.
2443
2444 * Unknown -- if neither of the above can be established.
2445
2446 If in doubt, return Unknown. */
2447
2448typedef
2449 enum { ExactAlias, NoAlias, UnknownAlias }
2450 GSAliasing;
2451
2452
2453/* Produces the alias relation between an indexed guest
2454 state access and a non-indexed access. */
2455
2456static
sewardjdd40fdf2006-12-24 02:20:24 +00002457GSAliasing getAliasingRelation_IC ( IRRegArray* descr1, IRExpr* ix1,
sewardj9b0cc582006-02-04 15:24:00 +00002458 Int offset2, IRType ty2 )
2459{
2460 UInt minoff1, maxoff1, minoff2, maxoff2;
2461
2462 getArrayBounds( descr1, &minoff1, &maxoff1 );
2463 minoff2 = offset2;
2464 maxoff2 = minoff2 + sizeofIRType(ty2) - 1;
2465
2466 if (maxoff1 < minoff2 || maxoff2 < minoff1)
2467 return NoAlias;
2468
2469 /* Could probably do better here if required. For the moment
2470 however just claim not to know anything more. */
2471 return UnknownAlias;
2472}
2473
2474
2475/* Produces the alias relation between two indexed guest state
2476 accesses. */
2477
2478static
2479GSAliasing getAliasingRelation_II (
sewardjdd40fdf2006-12-24 02:20:24 +00002480 IRRegArray* descr1, IRExpr* ix1, Int bias1,
2481 IRRegArray* descr2, IRExpr* ix2, Int bias2
sewardj9b0cc582006-02-04 15:24:00 +00002482 )
2483{
2484 UInt minoff1, maxoff1, minoff2, maxoff2;
2485 Int iters;
2486
2487 /* First try hard to show they don't alias. */
2488 getArrayBounds( descr1, &minoff1, &maxoff1 );
2489 getArrayBounds( descr2, &minoff2, &maxoff2 );
2490 if (maxoff1 < minoff2 || maxoff2 < minoff1)
2491 return NoAlias;
2492
2493 /* So the two arrays at least partially overlap. To get any
2494 further we'll have to be sure that the descriptors are
2495 identical. */
sewardjdd40fdf2006-12-24 02:20:24 +00002496 if (!eqIRRegArray(descr1, descr2))
sewardj9b0cc582006-02-04 15:24:00 +00002497 return UnknownAlias;
2498
2499 /* The descriptors are identical. Now the only difference can be
2500 in the index expressions. If they cannot be shown to be
2501 identical, we have to say we don't know what the aliasing
2502 relation will be. Now, since the IR is flattened, the index
2503 expressions should be atoms -- either consts or tmps. So that
2504 makes the comparison simple. */
2505 vassert(isIRAtom(ix1));
2506 vassert(isIRAtom(ix2));
2507 if (!eqIRAtom(ix1,ix2))
2508 return UnknownAlias;
2509
2510 /* Ok, the index expressions are identical. So now the only way
2511 they can be different is in the bias. Normalise this
2512 paranoidly, to reliably establish equality/non-equality. */
2513
2514 /* So now we know that the GetI and PutI index the same array
2515 with the same base. Are the offsets the same, modulo the
2516 array size? Do this paranoidly. */
2517 vassert(descr1->nElems == descr2->nElems);
2518 vassert(descr1->elemTy == descr2->elemTy);
2519 vassert(descr1->base == descr2->base);
2520 iters = 0;
2521 while (bias1 < 0 || bias2 < 0) {
2522 bias1 += descr1->nElems;
2523 bias2 += descr1->nElems;
2524 iters++;
2525 if (iters > 10)
2526 vpanic("getAliasingRelation: iters");
2527 }
2528 vassert(bias1 >= 0 && bias2 >= 0);
2529 bias1 %= descr1->nElems;
2530 bias2 %= descr1->nElems;
2531 vassert(bias1 >= 0 && bias1 < descr1->nElems);
2532 vassert(bias2 >= 0 && bias2 < descr1->nElems);
2533
2534 /* Finally, biasP and biasG are normalised into the range
2535 0 .. descrP/G->nElems - 1. And so we can establish
2536 equality/non-equality. */
2537
2538 return bias1==bias2 ? ExactAlias : NoAlias;
2539}
2540
2541
2542/*---------------------------------------------------------------*/
sewardj08210532004-12-29 17:09:11 +00002543/*--- Common Subexpression Elimination ---*/
2544/*---------------------------------------------------------------*/
2545
2546/* Expensive in time and space. */
2547
2548/* Uses two environments:
2549 a IRTemp -> IRTemp mapping
2550 a mapping from AvailExpr* to IRTemp
2551*/
2552
2553typedef
2554 struct {
sewardj9b0cc582006-02-04 15:24:00 +00002555 enum { Ut, Btt, Btc, Bct, Cf64i, Mttt, GetIt } tag;
sewardj08210532004-12-29 17:09:11 +00002556 union {
2557 /* unop(tmp) */
2558 struct {
2559 IROp op;
2560 IRTemp arg;
2561 } Ut;
2562 /* binop(tmp,tmp) */
2563 struct {
2564 IROp op;
2565 IRTemp arg1;
2566 IRTemp arg2;
2567 } Btt;
2568 /* binop(tmp,const) */
2569 struct {
2570 IROp op;
2571 IRTemp arg1;
2572 IRConst con2;
2573 } Btc;
2574 /* binop(const,tmp) */
2575 struct {
2576 IROp op;
2577 IRConst con1;
2578 IRTemp arg2;
2579 } Bct;
2580 /* F64i-style const */
2581 struct {
2582 ULong f64i;
2583 } Cf64i;
sewardj9b0cc582006-02-04 15:24:00 +00002584 /* Mux0X(tmp,tmp,tmp) */
2585 struct {
2586 IRTemp co;
2587 IRTemp e0;
2588 IRTemp eX;
2589 } Mttt;
2590 /* GetI(descr,tmp,bias)*/
2591 struct {
sewardjdd40fdf2006-12-24 02:20:24 +00002592 IRRegArray* descr;
2593 IRTemp ix;
2594 Int bias;
sewardj9b0cc582006-02-04 15:24:00 +00002595 } GetIt;
sewardj08210532004-12-29 17:09:11 +00002596 } u;
2597 }
2598 AvailExpr;
2599
2600static Bool eq_AvailExpr ( AvailExpr* a1, AvailExpr* a2 )
2601{
2602 if (a1->tag != a2->tag)
2603 return False;
2604 switch (a1->tag) {
2605 case Ut:
sewardj9d2e7692005-02-07 01:11:31 +00002606 return toBool(
2607 a1->u.Ut.op == a2->u.Ut.op
2608 && a1->u.Ut.arg == a2->u.Ut.arg);
sewardj08210532004-12-29 17:09:11 +00002609 case Btt:
sewardj9d2e7692005-02-07 01:11:31 +00002610 return toBool(
2611 a1->u.Btt.op == a2->u.Btt.op
sewardj08210532004-12-29 17:09:11 +00002612 && a1->u.Btt.arg1 == a2->u.Btt.arg1
sewardj9d2e7692005-02-07 01:11:31 +00002613 && a1->u.Btt.arg2 == a2->u.Btt.arg2);
sewardj08210532004-12-29 17:09:11 +00002614 case Btc:
sewardj9d2e7692005-02-07 01:11:31 +00002615 return toBool(
2616 a1->u.Btc.op == a2->u.Btc.op
sewardj08210532004-12-29 17:09:11 +00002617 && a1->u.Btc.arg1 == a2->u.Btc.arg1
sewardj9d2e7692005-02-07 01:11:31 +00002618 && eqIRConst(&a1->u.Btc.con2, &a2->u.Btc.con2));
sewardj08210532004-12-29 17:09:11 +00002619 case Bct:
sewardj9d2e7692005-02-07 01:11:31 +00002620 return toBool(
2621 a1->u.Bct.op == a2->u.Bct.op
sewardj08210532004-12-29 17:09:11 +00002622 && a1->u.Bct.arg2 == a2->u.Bct.arg2
sewardj9d2e7692005-02-07 01:11:31 +00002623 && eqIRConst(&a1->u.Bct.con1, &a2->u.Bct.con1));
sewardj08210532004-12-29 17:09:11 +00002624 case Cf64i:
sewardj9d2e7692005-02-07 01:11:31 +00002625 return toBool(a1->u.Cf64i.f64i == a2->u.Cf64i.f64i);
sewardj9b0cc582006-02-04 15:24:00 +00002626 case Mttt:
2627 return toBool(a1->u.Mttt.co == a2->u.Mttt.co
2628 && a1->u.Mttt.e0 == a2->u.Mttt.e0
2629 && a1->u.Mttt.eX == a2->u.Mttt.eX);
2630 case GetIt:
sewardjdd40fdf2006-12-24 02:20:24 +00002631 return toBool(eqIRRegArray(a1->u.GetIt.descr, a2->u.GetIt.descr)
sewardj9b0cc582006-02-04 15:24:00 +00002632 && a1->u.GetIt.ix == a2->u.GetIt.ix
2633 && a1->u.GetIt.bias == a2->u.GetIt.bias);
sewardj08210532004-12-29 17:09:11 +00002634 default: vpanic("eq_AvailExpr");
2635 }
2636}
2637
2638static IRExpr* availExpr_to_IRExpr ( AvailExpr* ae )
2639{
2640 IRConst* con;
2641 switch (ae->tag) {
2642 case Ut:
sewardjdd40fdf2006-12-24 02:20:24 +00002643 return IRExpr_Unop( ae->u.Ut.op, IRExpr_RdTmp(ae->u.Ut.arg) );
sewardj08210532004-12-29 17:09:11 +00002644 case Btt:
2645 return IRExpr_Binop( ae->u.Btt.op,
sewardjdd40fdf2006-12-24 02:20:24 +00002646 IRExpr_RdTmp(ae->u.Btt.arg1),
2647 IRExpr_RdTmp(ae->u.Btt.arg2) );
sewardj08210532004-12-29 17:09:11 +00002648 case Btc:
2649 con = LibVEX_Alloc(sizeof(IRConst));
2650 *con = ae->u.Btc.con2;
2651 return IRExpr_Binop( ae->u.Btc.op,
sewardjdd40fdf2006-12-24 02:20:24 +00002652 IRExpr_RdTmp(ae->u.Btc.arg1),
2653 IRExpr_Const(con) );
sewardj08210532004-12-29 17:09:11 +00002654 case Bct:
2655 con = LibVEX_Alloc(sizeof(IRConst));
2656 *con = ae->u.Bct.con1;
2657 return IRExpr_Binop( ae->u.Bct.op,
sewardjdd40fdf2006-12-24 02:20:24 +00002658 IRExpr_Const(con),
2659 IRExpr_RdTmp(ae->u.Bct.arg2) );
sewardj08210532004-12-29 17:09:11 +00002660 case Cf64i:
2661 return IRExpr_Const(IRConst_F64i(ae->u.Cf64i.f64i));
sewardj9b0cc582006-02-04 15:24:00 +00002662 case Mttt:
sewardjdd40fdf2006-12-24 02:20:24 +00002663 return IRExpr_Mux0X(IRExpr_RdTmp(ae->u.Mttt.co),
2664 IRExpr_RdTmp(ae->u.Mttt.e0),
2665 IRExpr_RdTmp(ae->u.Mttt.eX));
sewardj9b0cc582006-02-04 15:24:00 +00002666 case GetIt:
2667 return IRExpr_GetI(ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00002668 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00002669 ae->u.GetIt.bias);
sewardj08210532004-12-29 17:09:11 +00002670 default:
2671 vpanic("availExpr_to_IRExpr");
2672 }
2673}
2674
2675inline
2676static IRTemp subst_AvailExpr_Temp ( HashHW* env, IRTemp tmp )
2677{
2678 HWord res;
2679 /* env :: IRTemp -> IRTemp */
2680 if (lookupHHW( env, &res, (HWord)tmp ))
2681 return (IRTemp)res;
2682 else
2683 return tmp;
2684}
2685
2686static void subst_AvailExpr ( HashHW* env, AvailExpr* ae )
2687{
2688 /* env :: IRTemp -> IRTemp */
2689 switch (ae->tag) {
2690 case Ut:
2691 ae->u.Ut.arg = subst_AvailExpr_Temp( env, ae->u.Ut.arg );
2692 break;
2693 case Btt:
2694 ae->u.Btt.arg1 = subst_AvailExpr_Temp( env, ae->u.Btt.arg1 );
2695 ae->u.Btt.arg2 = subst_AvailExpr_Temp( env, ae->u.Btt.arg2 );
2696 break;
2697 case Btc:
2698 ae->u.Btc.arg1 = subst_AvailExpr_Temp( env, ae->u.Btc.arg1 );
2699 break;
2700 case Bct:
2701 ae->u.Bct.arg2 = subst_AvailExpr_Temp( env, ae->u.Bct.arg2 );
2702 break;
2703 case Cf64i:
2704 break;
sewardj9b0cc582006-02-04 15:24:00 +00002705 case Mttt:
2706 ae->u.Mttt.co = subst_AvailExpr_Temp( env, ae->u.Mttt.co );
2707 ae->u.Mttt.e0 = subst_AvailExpr_Temp( env, ae->u.Mttt.e0 );
2708 ae->u.Mttt.eX = subst_AvailExpr_Temp( env, ae->u.Mttt.eX );
2709 break;
2710 case GetIt:
2711 ae->u.GetIt.ix = subst_AvailExpr_Temp( env, ae->u.GetIt.ix );
2712 break;
sewardj08210532004-12-29 17:09:11 +00002713 default:
2714 vpanic("subst_AvailExpr");
2715 }
2716}
2717
2718static AvailExpr* irExpr_to_AvailExpr ( IRExpr* e )
2719{
2720 AvailExpr* ae;
2721
2722 if (e->tag == Iex_Unop
sewardjdd40fdf2006-12-24 02:20:24 +00002723 && e->Iex.Unop.arg->tag == Iex_RdTmp) {
sewardj08210532004-12-29 17:09:11 +00002724 ae = LibVEX_Alloc(sizeof(AvailExpr));
2725 ae->tag = Ut;
2726 ae->u.Ut.op = e->Iex.Unop.op;
sewardjdd40fdf2006-12-24 02:20:24 +00002727 ae->u.Ut.arg = e->Iex.Unop.arg->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002728 return ae;
2729 }
2730
2731 if (e->tag == Iex_Binop
sewardjdd40fdf2006-12-24 02:20:24 +00002732 && e->Iex.Binop.arg1->tag == Iex_RdTmp
2733 && e->Iex.Binop.arg2->tag == Iex_RdTmp) {
sewardj08210532004-12-29 17:09:11 +00002734 ae = LibVEX_Alloc(sizeof(AvailExpr));
2735 ae->tag = Btt;
2736 ae->u.Btt.op = e->Iex.Binop.op;
sewardjdd40fdf2006-12-24 02:20:24 +00002737 ae->u.Btt.arg1 = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
2738 ae->u.Btt.arg2 = e->Iex.Binop.arg2->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002739 return ae;
2740 }
2741
2742 if (e->tag == Iex_Binop
sewardjdd40fdf2006-12-24 02:20:24 +00002743 && e->Iex.Binop.arg1->tag == Iex_RdTmp
sewardj08210532004-12-29 17:09:11 +00002744 && e->Iex.Binop.arg2->tag == Iex_Const) {
2745 ae = LibVEX_Alloc(sizeof(AvailExpr));
2746 ae->tag = Btc;
2747 ae->u.Btc.op = e->Iex.Binop.op;
sewardjdd40fdf2006-12-24 02:20:24 +00002748 ae->u.Btc.arg1 = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002749 ae->u.Btc.con2 = *(e->Iex.Binop.arg2->Iex.Const.con);
2750 return ae;
2751 }
2752
2753 if (e->tag == Iex_Binop
2754 && e->Iex.Binop.arg1->tag == Iex_Const
sewardjdd40fdf2006-12-24 02:20:24 +00002755 && e->Iex.Binop.arg2->tag == Iex_RdTmp) {
sewardj08210532004-12-29 17:09:11 +00002756 ae = LibVEX_Alloc(sizeof(AvailExpr));
2757 ae->tag = Bct;
2758 ae->u.Bct.op = e->Iex.Binop.op;
sewardjdd40fdf2006-12-24 02:20:24 +00002759 ae->u.Bct.arg2 = e->Iex.Binop.arg2->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002760 ae->u.Bct.con1 = *(e->Iex.Binop.arg1->Iex.Const.con);
2761 return ae;
2762 }
2763
2764 if (e->tag == Iex_Const
2765 && e->Iex.Const.con->tag == Ico_F64i) {
2766 ae = LibVEX_Alloc(sizeof(AvailExpr));
2767 ae->tag = Cf64i;
2768 ae->u.Cf64i.f64i = e->Iex.Const.con->Ico.F64i;
2769 return ae;
2770 }
2771
sewardj9b0cc582006-02-04 15:24:00 +00002772 if (e->tag == Iex_Mux0X
sewardjdd40fdf2006-12-24 02:20:24 +00002773 && e->Iex.Mux0X.cond->tag == Iex_RdTmp
2774 && e->Iex.Mux0X.expr0->tag == Iex_RdTmp
2775 && e->Iex.Mux0X.exprX->tag == Iex_RdTmp) {
sewardj9b0cc582006-02-04 15:24:00 +00002776 ae = LibVEX_Alloc(sizeof(AvailExpr));
2777 ae->tag = Mttt;
sewardjdd40fdf2006-12-24 02:20:24 +00002778 ae->u.Mttt.co = e->Iex.Mux0X.cond->Iex.RdTmp.tmp;
2779 ae->u.Mttt.e0 = e->Iex.Mux0X.expr0->Iex.RdTmp.tmp;
2780 ae->u.Mttt.eX = e->Iex.Mux0X.exprX->Iex.RdTmp.tmp;
sewardj9b0cc582006-02-04 15:24:00 +00002781 return ae;
2782 }
2783
2784 if (e->tag == Iex_GetI
sewardjdd40fdf2006-12-24 02:20:24 +00002785 && e->Iex.GetI.ix->tag == Iex_RdTmp) {
sewardj9b0cc582006-02-04 15:24:00 +00002786 ae = LibVEX_Alloc(sizeof(AvailExpr));
2787 ae->tag = GetIt;
2788 ae->u.GetIt.descr = e->Iex.GetI.descr;
sewardjdd40fdf2006-12-24 02:20:24 +00002789 ae->u.GetIt.ix = e->Iex.GetI.ix->Iex.RdTmp.tmp;
sewardj9b0cc582006-02-04 15:24:00 +00002790 ae->u.GetIt.bias = e->Iex.GetI.bias;
2791 return ae;
2792 }
2793
sewardj08210532004-12-29 17:09:11 +00002794 return NULL;
2795}
2796
2797
sewardj9b0cc582006-02-04 15:24:00 +00002798/* The BB is modified in-place. Returns True if any changes were
2799 made. */
sewardj08210532004-12-29 17:09:11 +00002800
sewardjdd40fdf2006-12-24 02:20:24 +00002801static Bool do_cse_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00002802{
sewardj9b0cc582006-02-04 15:24:00 +00002803 Int i, j, paranoia;
sewardj08210532004-12-29 17:09:11 +00002804 IRTemp t, q;
2805 IRStmt* st;
2806 AvailExpr* eprime;
sewardj9b0cc582006-02-04 15:24:00 +00002807 AvailExpr* ae;
2808 Bool invalidate;
2809 Bool anyDone = False;
sewardj08210532004-12-29 17:09:11 +00002810
2811 HashHW* tenv = newHHW(); /* :: IRTemp -> IRTemp */
2812 HashHW* aenv = newHHW(); /* :: AvailExpr* -> IRTemp */
2813
2814 vassert(sizeof(IRTemp) <= sizeof(HWord));
2815
sewardjdd40fdf2006-12-24 02:20:24 +00002816 if (0) { ppIRSB(bb); vex_printf("\n\n"); }
sewardj08210532004-12-29 17:09:11 +00002817
2818 /* Iterate forwards over the stmts.
sewardjb183b852006-02-03 16:08:03 +00002819 On seeing "t = E", where E is one of the 5 AvailExpr forms:
sewardj08210532004-12-29 17:09:11 +00002820 let E' = apply tenv substitution to E
2821 search aenv for E'
2822 if a mapping E' -> q is found,
2823 replace this stmt by "t = q"
2824 and add binding t -> q to tenv
2825 else
2826 add binding E' -> t to aenv
2827 replace this stmt by "t = E'"
sewardj9b0cc582006-02-04 15:24:00 +00002828
2829 Other statements are only interesting to the extent that they
2830 might invalidate some of the expressions in aenv. So there is
2831 an invalidate-bindings check for each statement seen.
sewardj08210532004-12-29 17:09:11 +00002832 */
2833 for (i = 0; i < bb->stmts_used; i++) {
2834 st = bb->stmts[i];
2835
sewardj9b0cc582006-02-04 15:24:00 +00002836 /* ------ BEGIN invalidate aenv bindings ------ */
2837 /* This is critical: remove from aenv any E' -> .. bindings
2838 which might be invalidated by this statement. The only
sewardjc4356f02007-11-09 21:15:04 +00002839 vulnerable kind of bindings are the GetI kind.
sewardj9b0cc582006-02-04 15:24:00 +00002840 Dirty call - dump (paranoia level -> 2)
2841 Store - dump (ditto)
2842 Put, PutI - dump unless no-overlap is proven (.. -> 1)
2843 Uses getAliasingRelation_IC and getAliasingRelation_II
2844 to do the no-overlap assessments needed for Put/PutI.
2845 */
2846 switch (st->tag) {
sewardje768e922009-11-26 17:17:37 +00002847 case Ist_Dirty: case Ist_Store: case Ist_MBE:
2848 case Ist_CAS: case Ist_LLSC:
sewardj9b0cc582006-02-04 15:24:00 +00002849 paranoia = 2; break;
2850 case Ist_Put: case Ist_PutI:
2851 paranoia = 1; break;
2852 case Ist_NoOp: case Ist_IMark: case Ist_AbiHint:
sewardjc4356f02007-11-09 21:15:04 +00002853 case Ist_WrTmp: case Ist_Exit:
sewardj9b0cc582006-02-04 15:24:00 +00002854 paranoia = 0; break;
2855 default:
2856 vpanic("do_cse_BB(1)");
2857 }
2858
2859 if (paranoia > 0) {
2860 for (j = 0; j < aenv->used; j++) {
2861 if (!aenv->inuse[j])
2862 continue;
2863 ae = (AvailExpr*)aenv->key[j];
2864 if (ae->tag != GetIt)
2865 continue;
2866 invalidate = False;
2867 if (paranoia >= 2) {
2868 invalidate = True;
2869 } else {
2870 vassert(paranoia == 1);
2871 if (st->tag == Ist_Put) {
2872 if (getAliasingRelation_IC(
2873 ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00002874 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00002875 st->Ist.Put.offset,
2876 typeOfIRExpr(bb->tyenv,st->Ist.Put.data)
2877 ) != NoAlias)
2878 invalidate = True;
2879 }
2880 else
2881 if (st->tag == Ist_PutI) {
2882 if (getAliasingRelation_II(
2883 ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00002884 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00002885 ae->u.GetIt.bias,
2886 st->Ist.PutI.descr,
2887 st->Ist.PutI.ix,
2888 st->Ist.PutI.bias
2889 ) != NoAlias)
2890 invalidate = True;
2891 }
2892 else
2893 vpanic("do_cse_BB(2)");
2894 }
2895
2896 if (invalidate) {
2897 aenv->inuse[j] = False;
2898 aenv->key[j] = (HWord)NULL; /* be sure */
2899 }
2900 } /* for j */
2901 } /* paranoia > 0 */
2902
2903 /* ------ ENV invalidate aenv bindings ------ */
2904
sewardj08210532004-12-29 17:09:11 +00002905 /* ignore not-interestings */
sewardjdd40fdf2006-12-24 02:20:24 +00002906 if (st->tag != Ist_WrTmp)
sewardj08210532004-12-29 17:09:11 +00002907 continue;
2908
sewardjdd40fdf2006-12-24 02:20:24 +00002909 t = st->Ist.WrTmp.tmp;
2910 eprime = irExpr_to_AvailExpr(st->Ist.WrTmp.data);
sewardj08210532004-12-29 17:09:11 +00002911 /* ignore if not of AvailExpr form */
2912 if (!eprime)
2913 continue;
2914
2915 /* vex_printf("considering: " ); ppIRStmt(st); vex_printf("\n"); */
2916
2917 /* apply tenv */
2918 subst_AvailExpr( tenv, eprime );
2919
2920 /* search aenv for eprime, unfortunately the hard way */
2921 for (j = 0; j < aenv->used; j++)
2922 if (aenv->inuse[j] && eq_AvailExpr(eprime, (AvailExpr*)aenv->key[j]))
2923 break;
2924
2925 if (j < aenv->used) {
2926 /* A binding E' -> q was found. Replace stmt by "t = q" and
2927 note the t->q binding in tenv. */
2928 /* (this is the core of the CSE action) */
2929 q = (IRTemp)aenv->val[j];
sewardjdd40fdf2006-12-24 02:20:24 +00002930 bb->stmts[i] = IRStmt_WrTmp( t, IRExpr_RdTmp(q) );
sewardj08210532004-12-29 17:09:11 +00002931 addToHHW( tenv, (HWord)t, (HWord)q );
sewardj9b0cc582006-02-04 15:24:00 +00002932 anyDone = True;
sewardj08210532004-12-29 17:09:11 +00002933 } else {
2934 /* No binding was found, so instead we add E' -> t to our
2935 collection of available expressions, replace this stmt
2936 with "t = E'", and move on. */
sewardjdd40fdf2006-12-24 02:20:24 +00002937 bb->stmts[i] = IRStmt_WrTmp( t, availExpr_to_IRExpr(eprime) );
sewardj08210532004-12-29 17:09:11 +00002938 addToHHW( aenv, (HWord)eprime, (HWord)t );
2939 }
2940 }
2941
sewardjb183b852006-02-03 16:08:03 +00002942 /*
sewardjdd40fdf2006-12-24 02:20:24 +00002943 ppIRSB(bb);
2944 sanityCheckIRSB(bb, Ity_I32);
sewardjb183b852006-02-03 16:08:03 +00002945 vex_printf("\n\n");
2946 */
sewardj9b0cc582006-02-04 15:24:00 +00002947 return anyDone;
sewardj08210532004-12-29 17:09:11 +00002948}
2949
2950
2951/*---------------------------------------------------------------*/
2952/*--- Add32/Sub32 chain collapsing ---*/
2953/*---------------------------------------------------------------*/
2954
2955/* ----- Helper functions for Add32/Sub32 chain collapsing ----- */
2956
2957/* Is this expression "Add32(tmp,const)" or "Sub32(tmp,const)" ? If
2958 yes, set *tmp and *i32 appropriately. *i32 is set as if the
2959 root node is Add32, not Sub32. */
2960
2961static Bool isAdd32OrSub32 ( IRExpr* e, IRTemp* tmp, Int* i32 )
2962{
2963 if (e->tag != Iex_Binop)
2964 return False;
2965 if (e->Iex.Binop.op != Iop_Add32 && e->Iex.Binop.op != Iop_Sub32)
2966 return False;
sewardjdd40fdf2006-12-24 02:20:24 +00002967 if (e->Iex.Binop.arg1->tag != Iex_RdTmp)
sewardj08210532004-12-29 17:09:11 +00002968 return False;
2969 if (e->Iex.Binop.arg2->tag != Iex_Const)
2970 return False;
sewardjdd40fdf2006-12-24 02:20:24 +00002971 *tmp = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00002972 *i32 = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32);
2973 if (e->Iex.Binop.op == Iop_Sub32)
2974 *i32 = -*i32;
2975 return True;
2976}
2977
2978
2979/* Figure out if tmp can be expressed as tmp2 +32 const, for some
2980 other tmp2. Scan backwards from the specified start point -- an
2981 optimisation. */
2982
sewardjdd40fdf2006-12-24 02:20:24 +00002983static Bool collapseChain ( IRSB* bb, Int startHere,
sewardj08210532004-12-29 17:09:11 +00002984 IRTemp tmp,
2985 IRTemp* tmp2, Int* i32 )
2986{
2987 Int j, ii;
2988 IRTemp vv;
2989 IRStmt* st;
2990 IRExpr* e;
2991
2992 /* the (var, con) pair contain the current 'representation' for
2993 'tmp'. We start with 'tmp + 0'. */
2994 IRTemp var = tmp;
2995 Int con = 0;
2996
2997 /* Scan backwards to see if tmp can be replaced by some other tmp
2998 +/- a constant. */
2999 for (j = startHere; j >= 0; j--) {
3000 st = bb->stmts[j];
sewardjdd40fdf2006-12-24 02:20:24 +00003001 if (st->tag != Ist_WrTmp)
sewardj08210532004-12-29 17:09:11 +00003002 continue;
sewardjdd40fdf2006-12-24 02:20:24 +00003003 if (st->Ist.WrTmp.tmp != var)
sewardj08210532004-12-29 17:09:11 +00003004 continue;
sewardjdd40fdf2006-12-24 02:20:24 +00003005 e = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +00003006 if (!isAdd32OrSub32(e, &vv, &ii))
3007 break;
3008 var = vv;
3009 con += ii;
3010 }
3011 if (j == -1)
3012 /* no earlier binding for var .. ill-formed IR */
3013 vpanic("collapseChain");
3014
3015 /* so, did we find anything interesting? */
3016 if (var == tmp)
3017 return False; /* no .. */
3018
3019 *tmp2 = var;
3020 *i32 = con;
3021 return True;
3022}
3023
3024
3025/* ------- Main function for Add32/Sub32 chain collapsing ------ */
3026
sewardjdd40fdf2006-12-24 02:20:24 +00003027static void collapse_AddSub_chains_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003028{
3029 IRStmt *st;
3030 IRTemp var, var2;
3031 Int i, con, con2;
3032
3033 for (i = bb->stmts_used-1; i >= 0; i--) {
3034 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003035 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00003036 continue;
3037
3038 /* Try to collapse 't1 = Add32/Sub32(t2, con)'. */
3039
sewardjdd40fdf2006-12-24 02:20:24 +00003040 if (st->tag == Ist_WrTmp
3041 && isAdd32OrSub32(st->Ist.WrTmp.data, &var, &con)) {
sewardj08210532004-12-29 17:09:11 +00003042
3043 /* So e1 is of the form Add32(var,con) or Sub32(var,-con).
3044 Find out if var can be expressed as var2 + con2. */
3045 if (collapseChain(bb, i-1, var, &var2, &con2)) {
3046 if (DEBUG_IROPT) {
3047 vex_printf("replacing1 ");
3048 ppIRStmt(st);
3049 vex_printf(" with ");
3050 }
3051 con2 += con;
3052 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00003053 = IRStmt_WrTmp(
3054 st->Ist.WrTmp.tmp,
sewardj08210532004-12-29 17:09:11 +00003055 (con2 >= 0)
3056 ? IRExpr_Binop(Iop_Add32,
sewardjdd40fdf2006-12-24 02:20:24 +00003057 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00003058 IRExpr_Const(IRConst_U32(con2)))
3059 : IRExpr_Binop(Iop_Sub32,
sewardjdd40fdf2006-12-24 02:20:24 +00003060 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00003061 IRExpr_Const(IRConst_U32(-con2)))
3062 );
3063 if (DEBUG_IROPT) {
3064 ppIRStmt(bb->stmts[i]);
3065 vex_printf("\n");
3066 }
3067 }
3068
3069 continue;
3070 }
3071
3072 /* Try to collapse 't1 = GetI[t2, con]'. */
3073
sewardjdd40fdf2006-12-24 02:20:24 +00003074 if (st->tag == Ist_WrTmp
3075 && st->Ist.WrTmp.data->tag == Iex_GetI
3076 && st->Ist.WrTmp.data->Iex.GetI.ix->tag == Iex_RdTmp
3077 && collapseChain(bb, i-1, st->Ist.WrTmp.data->Iex.GetI.ix
3078 ->Iex.RdTmp.tmp, &var2, &con2)) {
sewardj08210532004-12-29 17:09:11 +00003079 if (DEBUG_IROPT) {
3080 vex_printf("replacing3 ");
3081 ppIRStmt(st);
3082 vex_printf(" with ");
3083 }
sewardjdd40fdf2006-12-24 02:20:24 +00003084 con2 += st->Ist.WrTmp.data->Iex.GetI.bias;
sewardj08210532004-12-29 17:09:11 +00003085 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00003086 = IRStmt_WrTmp(
3087 st->Ist.WrTmp.tmp,
3088 IRExpr_GetI(st->Ist.WrTmp.data->Iex.GetI.descr,
3089 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00003090 con2));
3091 if (DEBUG_IROPT) {
3092 ppIRStmt(bb->stmts[i]);
3093 vex_printf("\n");
3094 }
3095 continue;
3096 }
3097
3098 /* Perhaps st is PutI[t, con] ? */
3099
3100 if (st->tag == Ist_PutI
sewardjdd40fdf2006-12-24 02:20:24 +00003101 && st->Ist.PutI.ix->tag == Iex_RdTmp
3102 && collapseChain(bb, i-1, st->Ist.PutI.ix->Iex.RdTmp.tmp,
sewardj08210532004-12-29 17:09:11 +00003103 &var2, &con2)) {
3104 if (DEBUG_IROPT) {
3105 vex_printf("replacing2 ");
3106 ppIRStmt(st);
3107 vex_printf(" with ");
3108 }
3109 con2 += st->Ist.PutI.bias;
3110 bb->stmts[i]
3111 = IRStmt_PutI(st->Ist.PutI.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003112 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00003113 con2,
3114 st->Ist.PutI.data);
3115 if (DEBUG_IROPT) {
3116 ppIRStmt(bb->stmts[i]);
3117 vex_printf("\n");
3118 }
3119 continue;
3120 }
3121
3122 } /* for */
3123}
3124
3125
3126/*---------------------------------------------------------------*/
3127/*--- PutI/GetI transformations ---*/
3128/*---------------------------------------------------------------*/
3129
sewardj08210532004-12-29 17:09:11 +00003130/* Given the parts (descr, tmp, bias) for a GetI, scan backwards from
3131 the given starting point to find, if any, a PutI which writes
3132 exactly the same piece of guest state, and so return the expression
3133 that the PutI writes. This is the core of PutI-GetI forwarding. */
3134
3135static
sewardjdd40fdf2006-12-24 02:20:24 +00003136IRExpr* findPutI ( IRSB* bb, Int startHere,
3137 IRRegArray* descrG, IRExpr* ixG, Int biasG )
sewardj08210532004-12-29 17:09:11 +00003138{
3139 Int j;
3140 IRStmt* st;
3141 GSAliasing relation;
3142
3143 if (0) {
3144 vex_printf("\nfindPutI ");
sewardjdd40fdf2006-12-24 02:20:24 +00003145 ppIRRegArray(descrG);
sewardj08210532004-12-29 17:09:11 +00003146 vex_printf(" ");
3147 ppIRExpr(ixG);
3148 vex_printf(" %d\n", biasG);
3149 }
3150
3151 /* Scan backwards in bb from startHere to find a suitable PutI
3152 binding for (descrG, ixG, biasG), if any. */
3153
3154 for (j = startHere; j >= 0; j--) {
3155 st = bb->stmts[j];
sewardj8bee6d12005-03-22 02:24:05 +00003156 if (st->tag == Ist_NoOp)
3157 continue;
sewardj08210532004-12-29 17:09:11 +00003158
3159 if (st->tag == Ist_Put) {
3160 /* Non-indexed Put. This can't give a binding, but we do
3161 need to check it doesn't invalidate the search by
3162 overlapping any part of the indexed guest state. */
3163
3164 relation
3165 = getAliasingRelation_IC(
3166 descrG, ixG,
3167 st->Ist.Put.offset,
3168 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
3169
3170 if (relation == NoAlias) {
3171 /* we're OK; keep going */
3172 continue;
3173 } else {
3174 /* relation == UnknownAlias || relation == ExactAlias */
3175 /* If this assertion fails, we've found a Put which writes
3176 an area of guest state which is read by a GetI. Which
3177 is unlikely (although not per se wrong). */
3178 vassert(relation != ExactAlias);
3179 /* This Put potentially writes guest state that the GetI
3180 reads; we must fail. */
3181 return NULL;
3182 }
3183 }
3184
3185 if (st->tag == Ist_PutI) {
3186
3187 relation = getAliasingRelation_II(
3188 descrG, ixG, biasG,
3189 st->Ist.PutI.descr,
3190 st->Ist.PutI.ix,
3191 st->Ist.PutI.bias
3192 );
3193
3194 if (relation == NoAlias) {
3195 /* This PutI definitely doesn't overlap. Ignore it and
3196 keep going. */
3197 continue; /* the for j loop */
3198 }
3199
3200 if (relation == UnknownAlias) {
3201 /* We don't know if this PutI writes to the same guest
3202 state that the GetI, or not. So we have to give up. */
3203 return NULL;
3204 }
3205
3206 /* Otherwise, we've found what we're looking for. */
3207 vassert(relation == ExactAlias);
3208 return st->Ist.PutI.data;
3209
3210 } /* if (st->tag == Ist_PutI) */
3211
3212 if (st->tag == Ist_Dirty) {
3213 /* Be conservative. If the dirty call has any guest effects at
3214 all, give up. We could do better -- only give up if there
3215 are any guest writes/modifies. */
3216 if (st->Ist.Dirty.details->nFxState > 0)
3217 return NULL;
3218 }
3219
3220 } /* for */
3221
3222 /* No valid replacement was found. */
3223 return NULL;
3224}
3225
3226
3227
3228/* Assuming pi is a PutI stmt, is s2 identical to it (in the sense
3229 that it writes exactly the same piece of guest state) ? Safe
3230 answer: False. */
3231
3232static Bool identicalPutIs ( IRStmt* pi, IRStmt* s2 )
3233{
3234 vassert(pi->tag == Ist_PutI);
3235 if (s2->tag != Ist_PutI)
3236 return False;
3237
sewardj9d2e7692005-02-07 01:11:31 +00003238 return toBool(
3239 getAliasingRelation_II(
sewardj08210532004-12-29 17:09:11 +00003240 pi->Ist.PutI.descr, pi->Ist.PutI.ix, pi->Ist.PutI.bias,
3241 s2->Ist.PutI.descr, s2->Ist.PutI.ix, s2->Ist.PutI.bias
3242 )
sewardj9d2e7692005-02-07 01:11:31 +00003243 == ExactAlias
3244 );
sewardj08210532004-12-29 17:09:11 +00003245}
3246
3247
3248/* Assuming pi is a PutI stmt, is s2 a Get/GetI/Put/PutI which might
3249 overlap it? Safe answer: True. Note, we could do a lot better
3250 than this if needed. */
3251
3252static
3253Bool guestAccessWhichMightOverlapPutI (
3254 IRTypeEnv* tyenv, IRStmt* pi, IRStmt* s2
3255 )
3256{
3257 GSAliasing relation;
3258 UInt minoffP, maxoffP;
3259
3260 vassert(pi->tag == Ist_PutI);
3261 getArrayBounds(pi->Ist.PutI.descr, &minoffP, &maxoffP);
3262 switch (s2->tag) {
3263
sewardjd2445f62005-03-21 00:15:53 +00003264 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00003265 case Ist_IMark:
3266 return False;
3267
sewardjc4356f02007-11-09 21:15:04 +00003268 case Ist_MBE:
sewardj5a9ffab2005-05-12 17:55:01 +00003269 case Ist_AbiHint:
3270 /* just be paranoid ... these should be rare. */
sewardjbb3f52d2005-01-07 14:14:50 +00003271 return True;
3272
sewardje9d8a262009-07-01 08:06:34 +00003273 case Ist_CAS:
3274 /* This is unbelievably lame, but it's probably not
3275 significant from a performance point of view. Really, a
3276 CAS is a load-store op, so it should be safe to say False.
3277 However .. */
3278 return True;
3279
sewardj08210532004-12-29 17:09:11 +00003280 case Ist_Dirty:
3281 /* If the dirty call has any guest effects at all, give up.
3282 Probably could do better. */
3283 if (s2->Ist.Dirty.details->nFxState > 0)
3284 return True;
3285 return False;
3286
3287 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00003288 vassert(isIRAtom(s2->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +00003289 relation
3290 = getAliasingRelation_IC(
3291 pi->Ist.PutI.descr, pi->Ist.PutI.ix,
3292 s2->Ist.Put.offset,
3293 typeOfIRExpr(tyenv,s2->Ist.Put.data)
3294 );
3295 goto have_relation;
3296
3297 case Ist_PutI:
sewardj496a58d2005-03-20 18:44:44 +00003298 vassert(isIRAtom(s2->Ist.PutI.ix));
3299 vassert(isIRAtom(s2->Ist.PutI.data));
sewardj08210532004-12-29 17:09:11 +00003300 relation
3301 = getAliasingRelation_II(
3302 pi->Ist.PutI.descr, pi->Ist.PutI.ix, pi->Ist.PutI.bias,
3303 s2->Ist.PutI.descr, s2->Ist.PutI.ix, s2->Ist.PutI.bias
3304 );
3305 goto have_relation;
3306
sewardjdd40fdf2006-12-24 02:20:24 +00003307 case Ist_WrTmp:
3308 if (s2->Ist.WrTmp.data->tag == Iex_GetI) {
sewardj08210532004-12-29 17:09:11 +00003309 relation
3310 = getAliasingRelation_II(
3311 pi->Ist.PutI.descr, pi->Ist.PutI.ix,
3312 pi->Ist.PutI.bias,
sewardjdd40fdf2006-12-24 02:20:24 +00003313 s2->Ist.WrTmp.data->Iex.GetI.descr,
3314 s2->Ist.WrTmp.data->Iex.GetI.ix,
3315 s2->Ist.WrTmp.data->Iex.GetI.bias
sewardj08210532004-12-29 17:09:11 +00003316 );
3317 goto have_relation;
3318 }
sewardjdd40fdf2006-12-24 02:20:24 +00003319 if (s2->Ist.WrTmp.data->tag == Iex_Get) {
sewardj08210532004-12-29 17:09:11 +00003320 relation
3321 = getAliasingRelation_IC(
3322 pi->Ist.PutI.descr, pi->Ist.PutI.ix,
sewardjdd40fdf2006-12-24 02:20:24 +00003323 s2->Ist.WrTmp.data->Iex.Get.offset,
3324 s2->Ist.WrTmp.data->Iex.Get.ty
sewardj08210532004-12-29 17:09:11 +00003325 );
3326 goto have_relation;
3327 }
3328 return False;
3329
sewardjaf1ceca2005-06-30 23:31:27 +00003330 case Ist_Store:
3331 vassert(isIRAtom(s2->Ist.Store.addr));
3332 vassert(isIRAtom(s2->Ist.Store.data));
sewardj08210532004-12-29 17:09:11 +00003333 return False;
3334
3335 default:
3336 vex_printf("\n"); ppIRStmt(s2); vex_printf("\n");
3337 vpanic("guestAccessWhichMightOverlapPutI");
3338 }
3339
3340 have_relation:
3341 if (relation == NoAlias)
3342 return False;
3343 else
3344 return True; /* ExactAlias or UnknownAlias */
3345}
3346
3347
3348
3349/* ---------- PutI/GetI transformations main functions --------- */
3350
3351/* Remove redundant GetIs, to the extent that they can be detected.
3352 bb is modified in-place. */
3353
3354static
sewardjdd40fdf2006-12-24 02:20:24 +00003355void do_redundant_GetI_elimination ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003356{
3357 Int i;
3358 IRStmt* st;
3359
3360 for (i = bb->stmts_used-1; i >= 0; i--) {
3361 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003362 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00003363 continue;
3364
sewardjdd40fdf2006-12-24 02:20:24 +00003365 if (st->tag == Ist_WrTmp
3366 && st->Ist.WrTmp.data->tag == Iex_GetI
3367 && st->Ist.WrTmp.data->Iex.GetI.ix->tag == Iex_RdTmp) {
3368 IRRegArray* descr = st->Ist.WrTmp.data->Iex.GetI.descr;
3369 IRExpr* ix = st->Ist.WrTmp.data->Iex.GetI.ix;
3370 Int bias = st->Ist.WrTmp.data->Iex.GetI.bias;
3371 IRExpr* replacement = findPutI(bb, i-1, descr, ix, bias);
sewardj08210532004-12-29 17:09:11 +00003372 if (replacement
sewardj496a58d2005-03-20 18:44:44 +00003373 && isIRAtom(replacement)
sewardj08210532004-12-29 17:09:11 +00003374 /* Make sure we're doing a type-safe transformation! */
3375 && typeOfIRExpr(bb->tyenv, replacement) == descr->elemTy) {
3376 if (DEBUG_IROPT) {
3377 vex_printf("rGI: ");
sewardjdd40fdf2006-12-24 02:20:24 +00003378 ppIRExpr(st->Ist.WrTmp.data);
sewardj08210532004-12-29 17:09:11 +00003379 vex_printf(" -> ");
3380 ppIRExpr(replacement);
3381 vex_printf("\n");
3382 }
sewardjdd40fdf2006-12-24 02:20:24 +00003383 bb->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, replacement);
sewardj08210532004-12-29 17:09:11 +00003384 }
3385 }
3386 }
3387
3388}
3389
3390
3391/* Remove redundant PutIs, to the extent which they can be detected.
3392 bb is modified in-place. */
3393
3394static
sewardjdd40fdf2006-12-24 02:20:24 +00003395void do_redundant_PutI_elimination ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003396{
3397 Int i, j;
3398 Bool delete;
3399 IRStmt *st, *stj;
3400
3401 for (i = 0; i < bb->stmts_used; i++) {
3402 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003403 if (st->tag != Ist_PutI)
sewardj08210532004-12-29 17:09:11 +00003404 continue;
3405 /* Ok, search forwards from here to see if we can find another
3406 PutI which makes this one redundant, and dodging various
3407 hazards. Search forwards:
3408 * If conditional exit, give up (because anything after that
3409 does not postdominate this put).
3410 * If a Get which might overlap, give up (because this PutI
3411 not necessarily dead).
3412 * If a Put which is identical, stop with success.
3413 * If a Put which might overlap, but is not identical, give up.
3414 * If a dirty helper call which might write guest state, give up.
3415 * If a Put which definitely doesn't overlap, or any other
3416 kind of stmt, continue.
3417 */
3418 delete = False;
3419 for (j = i+1; j < bb->stmts_used; j++) {
3420 stj = bb->stmts[j];
sewardj8bee6d12005-03-22 02:24:05 +00003421 if (stj->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00003422 continue;
3423 if (identicalPutIs(st, stj)) {
3424 /* success! */
3425 delete = True;
3426 break;
3427 }
3428 if (stj->tag == Ist_Exit)
3429 /* give up */
3430 break;
3431 if (st->tag == Ist_Dirty)
3432 /* give up; could do better here */
3433 break;
3434 if (guestAccessWhichMightOverlapPutI(bb->tyenv, st, stj))
3435 /* give up */
3436 break;
3437 }
3438
3439 if (delete) {
3440 if (DEBUG_IROPT) {
3441 vex_printf("rPI: ");
3442 ppIRStmt(st);
3443 vex_printf("\n");
3444 }
sewardjd2445f62005-03-21 00:15:53 +00003445 bb->stmts[i] = IRStmt_NoOp();
sewardj08210532004-12-29 17:09:11 +00003446 }
3447
3448 }
3449}
3450
3451
3452/*---------------------------------------------------------------*/
3453/*--- Loop unrolling ---*/
3454/*---------------------------------------------------------------*/
3455
3456/* Adjust all tmp values (names) in e by delta. e is destructively
3457 modified. */
3458
3459static void deltaIRExpr ( IRExpr* e, Int delta )
3460{
3461 Int i;
3462 switch (e->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +00003463 case Iex_RdTmp:
3464 e->Iex.RdTmp.tmp += delta;
sewardj08210532004-12-29 17:09:11 +00003465 break;
3466 case Iex_Get:
3467 case Iex_Const:
3468 break;
3469 case Iex_GetI:
3470 deltaIRExpr(e->Iex.GetI.ix, delta);
3471 break;
sewardj1a866b42006-02-09 02:54:03 +00003472 case Iex_Qop:
3473 deltaIRExpr(e->Iex.Qop.arg1, delta);
3474 deltaIRExpr(e->Iex.Qop.arg2, delta);
3475 deltaIRExpr(e->Iex.Qop.arg3, delta);
3476 deltaIRExpr(e->Iex.Qop.arg4, delta);
3477 break;
sewardjb183b852006-02-03 16:08:03 +00003478 case Iex_Triop:
3479 deltaIRExpr(e->Iex.Triop.arg1, delta);
3480 deltaIRExpr(e->Iex.Triop.arg2, delta);
3481 deltaIRExpr(e->Iex.Triop.arg3, delta);
3482 break;
sewardj08210532004-12-29 17:09:11 +00003483 case Iex_Binop:
3484 deltaIRExpr(e->Iex.Binop.arg1, delta);
3485 deltaIRExpr(e->Iex.Binop.arg2, delta);
3486 break;
3487 case Iex_Unop:
3488 deltaIRExpr(e->Iex.Unop.arg, delta);
3489 break;
sewardjaf1ceca2005-06-30 23:31:27 +00003490 case Iex_Load:
3491 deltaIRExpr(e->Iex.Load.addr, delta);
sewardj08210532004-12-29 17:09:11 +00003492 break;
3493 case Iex_CCall:
3494 for (i = 0; e->Iex.CCall.args[i]; i++)
3495 deltaIRExpr(e->Iex.CCall.args[i], delta);
3496 break;
3497 case Iex_Mux0X:
3498 deltaIRExpr(e->Iex.Mux0X.cond, delta);
3499 deltaIRExpr(e->Iex.Mux0X.expr0, delta);
3500 deltaIRExpr(e->Iex.Mux0X.exprX, delta);
3501 break;
3502 default:
3503 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3504 vpanic("deltaIRExpr");
3505 }
3506}
3507
3508/* Adjust all tmp values (names) in st by delta. st is destructively
3509 modified. */
3510
3511static void deltaIRStmt ( IRStmt* st, Int delta )
3512{
3513 Int i;
3514 IRDirty* d;
3515 switch (st->tag) {
sewardjd2445f62005-03-21 00:15:53 +00003516 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00003517 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00003518 case Ist_MBE:
sewardjf1689312005-03-16 18:19:10 +00003519 break;
sewardj5a9ffab2005-05-12 17:55:01 +00003520 case Ist_AbiHint:
3521 deltaIRExpr(st->Ist.AbiHint.base, delta);
sewardj478646f2008-05-01 20:13:04 +00003522 deltaIRExpr(st->Ist.AbiHint.nia, delta);
sewardj5a9ffab2005-05-12 17:55:01 +00003523 break;
sewardj08210532004-12-29 17:09:11 +00003524 case Ist_Put:
3525 deltaIRExpr(st->Ist.Put.data, delta);
3526 break;
3527 case Ist_PutI:
3528 deltaIRExpr(st->Ist.PutI.ix, delta);
3529 deltaIRExpr(st->Ist.PutI.data, delta);
3530 break;
sewardjdd40fdf2006-12-24 02:20:24 +00003531 case Ist_WrTmp:
3532 st->Ist.WrTmp.tmp += delta;
3533 deltaIRExpr(st->Ist.WrTmp.data, delta);
sewardj08210532004-12-29 17:09:11 +00003534 break;
3535 case Ist_Exit:
3536 deltaIRExpr(st->Ist.Exit.guard, delta);
3537 break;
sewardjaf1ceca2005-06-30 23:31:27 +00003538 case Ist_Store:
3539 deltaIRExpr(st->Ist.Store.addr, delta);
3540 deltaIRExpr(st->Ist.Store.data, delta);
sewardj08210532004-12-29 17:09:11 +00003541 break;
sewardje9d8a262009-07-01 08:06:34 +00003542 case Ist_CAS:
3543 if (st->Ist.CAS.details->oldHi != IRTemp_INVALID)
3544 st->Ist.CAS.details->oldHi += delta;
3545 st->Ist.CAS.details->oldLo += delta;
3546 deltaIRExpr(st->Ist.CAS.details->addr, delta);
3547 if (st->Ist.CAS.details->expdHi)
3548 deltaIRExpr(st->Ist.CAS.details->expdHi, delta);
3549 deltaIRExpr(st->Ist.CAS.details->expdLo, delta);
3550 if (st->Ist.CAS.details->dataHi)
3551 deltaIRExpr(st->Ist.CAS.details->dataHi, delta);
3552 deltaIRExpr(st->Ist.CAS.details->dataLo, delta);
3553 break;
sewardje768e922009-11-26 17:17:37 +00003554 case Ist_LLSC:
3555 st->Ist.LLSC.result += delta;
3556 deltaIRExpr(st->Ist.LLSC.addr, delta);
3557 if (st->Ist.LLSC.storedata)
3558 deltaIRExpr(st->Ist.LLSC.storedata, delta);
3559 break;
sewardj08210532004-12-29 17:09:11 +00003560 case Ist_Dirty:
3561 d = st->Ist.Dirty.details;
3562 deltaIRExpr(d->guard, delta);
3563 for (i = 0; d->args[i]; i++)
3564 deltaIRExpr(d->args[i], delta);
3565 if (d->tmp != IRTemp_INVALID)
3566 d->tmp += delta;
3567 if (d->mAddr)
3568 deltaIRExpr(d->mAddr, delta);
3569 break;
3570 default:
3571 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
3572 vpanic("deltaIRStmt");
3573 }
3574}
3575
3576
3577/* If possible, return a loop-unrolled version of bb0. The original
3578 is changed. If not possible, return NULL. */
3579
3580/* The two schemas considered are:
3581
3582 X: BODY; goto X
3583
3584 which unrolls to (eg) X: BODY;BODY; goto X
3585
3586 and
3587
3588 X: BODY; if (c) goto X; goto Y
3589 which trivially transforms to
3590 X: BODY; if (!c) goto Y; goto X;
3591 so it falls in the scope of the first case.
3592
3593 X and Y must be literal (guest) addresses.
3594*/
3595
sewardjdd40fdf2006-12-24 02:20:24 +00003596static Int calc_unroll_factor( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003597{
3598 Int n_stmts, i;
3599
3600 n_stmts = 0;
sewardj0ddbf792005-04-04 23:12:54 +00003601 for (i = 0; i < bb->stmts_used; i++) {
3602 if (bb->stmts[i]->tag != Ist_NoOp)
3603 n_stmts++;
3604 }
sewardj08210532004-12-29 17:09:11 +00003605
3606 if (n_stmts <= vex_control.iropt_unroll_thresh/8) {
3607 if (vex_control.iropt_verbosity > 0)
3608 vex_printf("vex iropt: 8 x unrolling (%d sts -> %d sts)\n",
3609 n_stmts, 8* n_stmts);
3610 return 8;
3611 }
3612 if (n_stmts <= vex_control.iropt_unroll_thresh/4) {
3613 if (vex_control.iropt_verbosity > 0)
3614 vex_printf("vex iropt: 4 x unrolling (%d sts -> %d sts)\n",
3615 n_stmts, 4* n_stmts);
3616 return 4;
3617 }
3618
3619 if (n_stmts <= vex_control.iropt_unroll_thresh/2) {
3620 if (vex_control.iropt_verbosity > 0)
3621 vex_printf("vex iropt: 2 x unrolling (%d sts -> %d sts)\n",
3622 n_stmts, 2* n_stmts);
3623 return 2;
3624 }
3625
3626 if (vex_control.iropt_verbosity > 0)
3627 vex_printf("vex iropt: not unrolling (%d sts)\n", n_stmts);
3628
3629 return 1;
3630}
3631
3632
sewardjdd40fdf2006-12-24 02:20:24 +00003633static IRSB* maybe_loop_unroll_BB ( IRSB* bb0, Addr64 my_addr )
sewardj08210532004-12-29 17:09:11 +00003634{
3635 Int i, j, jmax, n_vars;
3636 Bool xxx_known;
3637 Addr64 xxx_value, yyy_value;
3638 IRExpr* udst;
3639 IRStmt* st;
3640 IRConst* con;
sewardjdd40fdf2006-12-24 02:20:24 +00003641 IRSB *bb1, *bb2;
sewardj08210532004-12-29 17:09:11 +00003642 Int unroll_factor;
3643
3644 if (vex_control.iropt_unroll_thresh <= 0)
3645 return NULL;
3646
3647 /* First off, figure out if we can unroll this loop. Do this
3648 without modifying bb0. */
3649
3650 if (bb0->jumpkind != Ijk_Boring)
3651 return NULL;
3652
3653 xxx_known = False;
3654 xxx_value = 0;
3655
3656 /* Extract the next-guest address. If it isn't a literal, we
3657 have to give up. */
3658
3659 udst = bb0->next;
3660 if (udst->tag == Iex_Const
3661 && (udst->Iex.Const.con->tag == Ico_U32
3662 || udst->Iex.Const.con->tag == Ico_U64)) {
3663 /* The BB ends in a jump to a literal location. */
3664 xxx_known = True;
3665 xxx_value = udst->Iex.Const.con->tag == Ico_U64
3666 ? udst->Iex.Const.con->Ico.U64
3667 : (Addr64)(udst->Iex.Const.con->Ico.U32);
3668 }
3669
3670 if (!xxx_known)
3671 return NULL;
3672
3673 /* Now we know the BB ends to a jump to a literal location. If
3674 it's a jump to itself (viz, idiom #1), move directly to the
3675 unrolling stage, first cloning the bb so the original isn't
3676 modified. */
3677 if (xxx_value == my_addr) {
3678 unroll_factor = calc_unroll_factor( bb0 );
3679 if (unroll_factor < 2)
3680 return NULL;
sewardjdd40fdf2006-12-24 02:20:24 +00003681 bb1 = deepCopyIRSB( bb0 );
sewardj08210532004-12-29 17:09:11 +00003682 bb0 = NULL;
3683 udst = NULL; /* is now invalid */
3684 goto do_unroll;
3685 }
3686
3687 /* Search for the second idiomatic form:
3688 X: BODY; if (c) goto X; goto Y
3689 We know Y, but need to establish that the last stmt
3690 is 'if (c) goto X'.
3691 */
3692 yyy_value = xxx_value;
3693 for (i = bb0->stmts_used-1; i >= 0; i--)
3694 if (bb0->stmts[i])
3695 break;
3696
3697 if (i < 0)
3698 return NULL; /* block with no stmts. Strange. */
3699
3700 st = bb0->stmts[i];
3701 if (st->tag != Ist_Exit)
3702 return NULL;
3703 if (st->Ist.Exit.jk != Ijk_Boring)
3704 return NULL;
3705
3706 con = st->Ist.Exit.dst;
3707 vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
3708
3709 xxx_value = con->tag == Ico_U64
3710 ? st->Ist.Exit.dst->Ico.U64
3711 : (Addr64)(st->Ist.Exit.dst->Ico.U32);
3712
3713 /* If this assertion fails, we have some kind of type error. */
3714 vassert(con->tag == udst->Iex.Const.con->tag);
3715
3716 if (xxx_value != my_addr)
3717 /* We didn't find either idiom. Give up. */
3718 return NULL;
3719
3720 /* Ok, we found idiom #2. Copy the BB, switch around the xxx and
3721 yyy values (which makes it look like idiom #1), and go into
3722 unrolling proper. This means finding (again) the last stmt, in
3723 the copied BB. */
3724
3725 unroll_factor = calc_unroll_factor( bb0 );
3726 if (unroll_factor < 2)
3727 return NULL;
3728
sewardjdd40fdf2006-12-24 02:20:24 +00003729 bb1 = deepCopyIRSB( bb0 );
sewardj08210532004-12-29 17:09:11 +00003730 bb0 = NULL;
3731 udst = NULL; /* is now invalid */
3732 for (i = bb1->stmts_used-1; i >= 0; i--)
3733 if (bb1->stmts[i])
3734 break;
3735
3736 /* The next bunch of assertions should be true since we already
3737 found and checked the last stmt in the original bb. */
3738
3739 vassert(i >= 0);
3740
3741 st = bb1->stmts[i];
3742 vassert(st->tag == Ist_Exit);
3743
3744 con = st->Ist.Exit.dst;
3745 vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
3746
3747 udst = bb1->next;
3748 vassert(udst->tag == Iex_Const);
3749 vassert(udst->Iex.Const.con->tag == Ico_U32
3750 || udst->Iex.Const.con->tag == Ico_U64);
3751 vassert(con->tag == udst->Iex.Const.con->tag);
3752
3753 /* switch the xxx and yyy fields around */
3754 if (con->tag == Ico_U64) {
3755 udst->Iex.Const.con->Ico.U64 = xxx_value;
3756 con->Ico.U64 = yyy_value;
3757 } else {
3758 udst->Iex.Const.con->Ico.U32 = (UInt)xxx_value;
cerion57b4c6d2005-02-22 11:07:35 +00003759 con->Ico.U32 = (UInt)yyy_value;
sewardj08210532004-12-29 17:09:11 +00003760 }
3761
3762 /* negate the test condition */
3763 st->Ist.Exit.guard
sewardjdd40fdf2006-12-24 02:20:24 +00003764 = IRExpr_Unop(Iop_Not1,deepCopyIRExpr(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +00003765
3766 /* --- The unroller proper. Both idioms are by now --- */
3767 /* --- now converted to idiom 1. --- */
3768
3769 do_unroll:
3770
3771 vassert(unroll_factor == 2
3772 || unroll_factor == 4
3773 || unroll_factor == 8);
3774
3775 jmax = unroll_factor==8 ? 3 : (unroll_factor==4 ? 2 : 1);
3776 for (j = 1; j <= jmax; j++) {
3777
3778 n_vars = bb1->tyenv->types_used;
3779
sewardjdd40fdf2006-12-24 02:20:24 +00003780 bb2 = deepCopyIRSB(bb1);
sewardj08210532004-12-29 17:09:11 +00003781 for (i = 0; i < n_vars; i++)
3782 (void)newIRTemp(bb1->tyenv, bb2->tyenv->types[i]);
3783
3784 for (i = 0; i < bb2->stmts_used; i++) {
sewardj08210532004-12-29 17:09:11 +00003785 /* deltaIRStmt destructively modifies the stmt, but
3786 that's OK since bb2 is a complete fresh copy of bb1. */
3787 deltaIRStmt(bb2->stmts[i], n_vars);
sewardjdd40fdf2006-12-24 02:20:24 +00003788 addStmtToIRSB(bb1, bb2->stmts[i]);
sewardj08210532004-12-29 17:09:11 +00003789 }
3790 }
3791
3792 if (DEBUG_IROPT) {
3793 vex_printf("\nUNROLLED (%llx)\n", my_addr);
sewardjdd40fdf2006-12-24 02:20:24 +00003794 ppIRSB(bb1);
sewardj08210532004-12-29 17:09:11 +00003795 vex_printf("\n");
3796 }
3797
3798 /* Flattening; sigh. The unroller succeeds in breaking flatness
3799 by negating the test condition. This should be fixed properly.
3800 For the moment use this shotgun approach. */
3801 return flatten_BB(bb1);
3802}
3803
3804
3805/*---------------------------------------------------------------*/
sewardj29632392004-08-22 02:38:11 +00003806/*--- The tree builder ---*/
3807/*---------------------------------------------------------------*/
3808
sewardj08210532004-12-29 17:09:11 +00003809/* This isn't part of IR optimisation. Really it's a pass done prior
3810 to instruction selection, which improves the code that the
3811 instruction selector can produce. */
3812
sewardjf9517d02005-11-28 13:39:37 +00003813/* --- The 'tmp' environment is the central data structure here --- */
sewardj29632392004-08-22 02:38:11 +00003814
sewardjf9517d02005-11-28 13:39:37 +00003815/* The number of outstanding bindings we're prepared to track.
3816 The number of times the env becomes full and we have to dump
3817 the oldest binding (hence reducing code quality) falls very
3818 rapidly as the env size increases. 8 gives reasonable performance
3819 under most circumstances. */
3820#define A_NENV 10
3821
3822/* bindee == NULL === slot is not in use
3823 bindee != NULL === slot is in use
sewardj29632392004-08-22 02:38:11 +00003824*/
sewardjf9517d02005-11-28 13:39:37 +00003825typedef
3826 struct {
3827 IRTemp binder;
3828 IRExpr* bindee;
3829 Bool doesLoad;
3830 Bool doesGet;
sewardj17442fe2004-09-20 14:54:28 +00003831 }
sewardjf9517d02005-11-28 13:39:37 +00003832 ATmpInfo;
sewardj17442fe2004-09-20 14:54:28 +00003833
sewardjf9517d02005-11-28 13:39:37 +00003834__attribute__((unused))
3835static void ppAEnv ( ATmpInfo* env )
sewardj29632392004-08-22 02:38:11 +00003836{
sewardj17442fe2004-09-20 14:54:28 +00003837 Int i;
sewardjf9517d02005-11-28 13:39:37 +00003838 for (i = 0; i < A_NENV; i++) {
3839 vex_printf("%d tmp %d val ", i, (Int)env[i].binder);
3840 if (env[i].bindee)
3841 ppIRExpr(env[i].bindee);
3842 else
3843 vex_printf("(null)");
3844 vex_printf("\n");
sewardj29632392004-08-22 02:38:11 +00003845 }
3846}
3847
sewardjf9517d02005-11-28 13:39:37 +00003848/* --- Tree-traversal fns --- */
sewardj29632392004-08-22 02:38:11 +00003849
sewardj37d38012004-08-24 00:37:04 +00003850/* Traverse an expr, and detect if any part of it reads memory or does
3851 a Get. Be careful ... this really controls how much the
3852 tree-builder can reorder the code, so getting it right is critical.
3853*/
sewardj29632392004-08-22 02:38:11 +00003854static void setHints_Expr (Bool* doesLoad, Bool* doesGet, IRExpr* e )
3855{
sewardjc41f1fb2004-08-22 09:48:08 +00003856 Int i;
sewardj29632392004-08-22 02:38:11 +00003857 switch (e->tag) {
sewardjc41f1fb2004-08-22 09:48:08 +00003858 case Iex_CCall:
3859 for (i = 0; e->Iex.CCall.args[i]; i++)
3860 setHints_Expr(doesLoad, doesGet, e->Iex.CCall.args[i]);
3861 return;
3862 case Iex_Mux0X:
3863 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.cond);
3864 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.expr0);
3865 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.exprX);
3866 return;
sewardj40c80262006-02-08 19:30:46 +00003867 case Iex_Qop:
3868 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.arg1);
3869 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.arg2);
3870 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.arg3);
3871 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.arg4);
3872 return;
sewardjb183b852006-02-03 16:08:03 +00003873 case Iex_Triop:
3874 setHints_Expr(doesLoad, doesGet, e->Iex.Triop.arg1);
3875 setHints_Expr(doesLoad, doesGet, e->Iex.Triop.arg2);
3876 setHints_Expr(doesLoad, doesGet, e->Iex.Triop.arg3);
3877 return;
sewardjc41f1fb2004-08-22 09:48:08 +00003878 case Iex_Binop:
3879 setHints_Expr(doesLoad, doesGet, e->Iex.Binop.arg1);
3880 setHints_Expr(doesLoad, doesGet, e->Iex.Binop.arg2);
3881 return;
3882 case Iex_Unop:
3883 setHints_Expr(doesLoad, doesGet, e->Iex.Unop.arg);
3884 return;
sewardjaf1ceca2005-06-30 23:31:27 +00003885 case Iex_Load:
sewardjc9ad1152004-10-14 00:08:21 +00003886 *doesLoad = True;
sewardjaf1ceca2005-06-30 23:31:27 +00003887 setHints_Expr(doesLoad, doesGet, e->Iex.Load.addr);
sewardjc41f1fb2004-08-22 09:48:08 +00003888 return;
sewardj29632392004-08-22 02:38:11 +00003889 case Iex_Get:
sewardjc9ad1152004-10-14 00:08:21 +00003890 *doesGet = True;
sewardj29632392004-08-22 02:38:11 +00003891 return;
sewardjf6501992004-08-27 11:58:24 +00003892 case Iex_GetI:
sewardjc9ad1152004-10-14 00:08:21 +00003893 *doesGet = True;
sewardjeeac8412004-11-02 00:26:55 +00003894 setHints_Expr(doesLoad, doesGet, e->Iex.GetI.ix);
sewardjf6501992004-08-27 11:58:24 +00003895 return;
sewardjdd40fdf2006-12-24 02:20:24 +00003896 case Iex_RdTmp:
sewardjc41f1fb2004-08-22 09:48:08 +00003897 case Iex_Const:
3898 return;
sewardj29632392004-08-22 02:38:11 +00003899 default:
3900 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3901 vpanic("setHints_Expr");
3902 }
3903}
3904
3905
sewardjf9517d02005-11-28 13:39:37 +00003906/* Add a binding to the front of the env and slide all the rest
3907 backwards. It should be the case that the last slot is free. */
3908static void addToEnvFront ( ATmpInfo* env, IRTemp binder, IRExpr* bindee )
sewardj29632392004-08-22 02:38:11 +00003909{
sewardjf9517d02005-11-28 13:39:37 +00003910 Int i;
3911 vassert(env[A_NENV-1].bindee == NULL);
3912 for (i = A_NENV-1; i >= 1; i--)
3913 env[i] = env[i-1];
3914 env[0].binder = binder;
3915 env[0].bindee = bindee;
3916 env[0].doesLoad = False; /* filled in later */
3917 env[0].doesGet = False; /* filled in later */
3918}
sewardj29632392004-08-22 02:38:11 +00003919
sewardjf9517d02005-11-28 13:39:37 +00003920/* Given uses :: array of UShort, indexed by IRTemp
3921 Add the use-occurrences of temps in this expression
3922 to the env.
3923*/
3924static void aoccCount_Expr ( UShort* uses, IRExpr* e )
3925{
3926 Int i;
sewardj29632392004-08-22 02:38:11 +00003927
sewardjf9517d02005-11-28 13:39:37 +00003928 switch (e->tag) {
3929
sewardjdd40fdf2006-12-24 02:20:24 +00003930 case Iex_RdTmp: /* the only interesting case */
3931 uses[e->Iex.RdTmp.tmp]++;
sewardj8bee6d12005-03-22 02:24:05 +00003932 return;
sewardj29632392004-08-22 02:38:11 +00003933
sewardjf9517d02005-11-28 13:39:37 +00003934 case Iex_Mux0X:
3935 aoccCount_Expr(uses, e->Iex.Mux0X.cond);
3936 aoccCount_Expr(uses, e->Iex.Mux0X.expr0);
3937 aoccCount_Expr(uses, e->Iex.Mux0X.exprX);
3938 return;
sewardj29632392004-08-22 02:38:11 +00003939
sewardj40c80262006-02-08 19:30:46 +00003940 case Iex_Qop:
3941 aoccCount_Expr(uses, e->Iex.Qop.arg1);
3942 aoccCount_Expr(uses, e->Iex.Qop.arg2);
3943 aoccCount_Expr(uses, e->Iex.Qop.arg3);
3944 aoccCount_Expr(uses, e->Iex.Qop.arg4);
3945 return;
3946
sewardjb183b852006-02-03 16:08:03 +00003947 case Iex_Triop:
3948 aoccCount_Expr(uses, e->Iex.Triop.arg1);
3949 aoccCount_Expr(uses, e->Iex.Triop.arg2);
3950 aoccCount_Expr(uses, e->Iex.Triop.arg3);
3951 return;
3952
sewardjf9517d02005-11-28 13:39:37 +00003953 case Iex_Binop:
3954 aoccCount_Expr(uses, e->Iex.Binop.arg1);
3955 aoccCount_Expr(uses, e->Iex.Binop.arg2);
3956 return;
sewardj29632392004-08-22 02:38:11 +00003957
sewardjf9517d02005-11-28 13:39:37 +00003958 case Iex_Unop:
3959 aoccCount_Expr(uses, e->Iex.Unop.arg);
3960 return;
3961
3962 case Iex_Load:
3963 aoccCount_Expr(uses, e->Iex.Load.addr);
3964 return;
3965
3966 case Iex_CCall:
3967 for (i = 0; e->Iex.CCall.args[i]; i++)
3968 aoccCount_Expr(uses, e->Iex.CCall.args[i]);
3969 return;
3970
3971 case Iex_GetI:
3972 aoccCount_Expr(uses, e->Iex.GetI.ix);
3973 return;
3974
3975 case Iex_Const:
3976 case Iex_Get:
3977 return;
3978
3979 default:
3980 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3981 vpanic("aoccCount_Expr");
3982 }
sewardj29632392004-08-22 02:38:11 +00003983}
3984
3985
sewardjf9517d02005-11-28 13:39:37 +00003986/* Given uses :: array of UShort, indexed by IRTemp
3987 Add the use-occurrences of temps in this statement
3988 to the env.
3989*/
3990static void aoccCount_Stmt ( UShort* uses, IRStmt* st )
sewardj29632392004-08-22 02:38:11 +00003991{
sewardjf9517d02005-11-28 13:39:37 +00003992 Int i;
3993 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00003994 IRCAS* cas;
sewardjf9517d02005-11-28 13:39:37 +00003995 switch (st->tag) {
3996 case Ist_AbiHint:
3997 aoccCount_Expr(uses, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +00003998 aoccCount_Expr(uses, st->Ist.AbiHint.nia);
sewardjf9517d02005-11-28 13:39:37 +00003999 return;
sewardjdd40fdf2006-12-24 02:20:24 +00004000 case Ist_WrTmp:
4001 aoccCount_Expr(uses, st->Ist.WrTmp.data);
sewardjf9517d02005-11-28 13:39:37 +00004002 return;
4003 case Ist_Put:
4004 aoccCount_Expr(uses, st->Ist.Put.data);
4005 return;
4006 case Ist_PutI:
4007 aoccCount_Expr(uses, st->Ist.PutI.ix);
4008 aoccCount_Expr(uses, st->Ist.PutI.data);
4009 return;
4010 case Ist_Store:
4011 aoccCount_Expr(uses, st->Ist.Store.addr);
4012 aoccCount_Expr(uses, st->Ist.Store.data);
4013 return;
sewardje9d8a262009-07-01 08:06:34 +00004014 case Ist_CAS:
4015 cas = st->Ist.CAS.details;
4016 aoccCount_Expr(uses, cas->addr);
4017 if (cas->expdHi)
4018 aoccCount_Expr(uses, cas->expdHi);
4019 aoccCount_Expr(uses, cas->expdLo);
4020 if (cas->dataHi)
4021 aoccCount_Expr(uses, cas->dataHi);
4022 aoccCount_Expr(uses, cas->dataLo);
4023 return;
sewardje768e922009-11-26 17:17:37 +00004024 case Ist_LLSC:
4025 aoccCount_Expr(uses, st->Ist.LLSC.addr);
4026 if (st->Ist.LLSC.storedata)
4027 aoccCount_Expr(uses, st->Ist.LLSC.storedata);
4028 return;
sewardjf9517d02005-11-28 13:39:37 +00004029 case Ist_Dirty:
4030 d = st->Ist.Dirty.details;
4031 if (d->mFx != Ifx_None)
4032 aoccCount_Expr(uses, d->mAddr);
4033 aoccCount_Expr(uses, d->guard);
4034 for (i = 0; d->args[i]; i++)
4035 aoccCount_Expr(uses, d->args[i]);
4036 return;
4037 case Ist_NoOp:
4038 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00004039 case Ist_MBE:
sewardjf9517d02005-11-28 13:39:37 +00004040 return;
4041 case Ist_Exit:
4042 aoccCount_Expr(uses, st->Ist.Exit.guard);
4043 return;
4044 default:
4045 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
4046 vpanic("aoccCount_Stmt");
4047 }
4048}
4049
4050/* Look up a binding for tmp in the env. If found, return the bound
4051 expression, and set the env's binding to NULL so it is marked as
4052 used. If not found, return NULL. */
4053
4054static IRExpr* atbSubst_Temp ( ATmpInfo* env, IRTemp tmp )
4055{
4056 Int i;
4057 for (i = 0; i < A_NENV; i++) {
4058 if (env[i].binder == tmp && env[i].bindee != NULL) {
4059 IRExpr* bindee = env[i].bindee;
4060 env[i].bindee = NULL;
4061 return bindee;
4062 }
4063 }
4064 return NULL;
4065}
4066
4067/* Traverse e, looking for temps. For each observed temp, see if env
4068 contains a binding for the temp, and if so return the bound value.
4069 The env has the property that any binding it holds is
4070 'single-shot', so once a binding is used, it is marked as no longer
4071 available, by setting its .bindee field to NULL. */
4072
sewardjeb17e492007-08-25 23:07:44 +00004073static inline Bool is_Unop ( IRExpr* e, IROp op ) {
4074 return e->tag == Iex_Unop && e->Iex.Unop.op == op;
4075}
4076static inline Bool is_Binop ( IRExpr* e, IROp op ) {
4077 return e->tag == Iex_Binop && e->Iex.Binop.op == op;
4078}
4079
4080static IRExpr* fold_IRExpr_Binop ( IROp op, IRExpr* a1, IRExpr* a2 )
4081{
4082 switch (op) {
4083 case Iop_Or32:
4084 /* Or32( CmpwNEZ32(x), CmpwNEZ32(y) ) --> CmpwNEZ32( Or32( x, y ) ) */
4085 if (is_Unop(a1, Iop_CmpwNEZ32) && is_Unop(a2, Iop_CmpwNEZ32))
4086 return IRExpr_Unop( Iop_CmpwNEZ32,
4087 IRExpr_Binop( Iop_Or32, a1->Iex.Unop.arg,
4088 a2->Iex.Unop.arg ) );
4089 break;
florian51d26fd2011-07-23 00:23:02 +00004090
4091 case Iop_CmpNE32:
4092 /* Since X has type Ity_I1 we can simplify:
4093 CmpNE32(1Uto32(X),0)) ==> X */
4094 if (is_Unop(a1, Iop_1Uto32) && isZeroU32(a2))
4095 return a1->Iex.Unop.arg;
4096 break;
4097
sewardjeb17e492007-08-25 23:07:44 +00004098 default:
4099 break;
4100 }
4101 /* no reduction rule applies */
4102 return IRExpr_Binop( op, a1, a2 );
4103}
4104
4105static IRExpr* fold_IRExpr_Unop ( IROp op, IRExpr* aa )
4106{
4107 switch (op) {
4108 case Iop_CmpwNEZ64:
4109 /* CmpwNEZ64( Or64 ( CmpwNEZ64(x), y ) ) --> CmpwNEZ64( Or64( x, y ) ) */
4110 if (is_Binop(aa, Iop_Or64)
4111 && is_Unop(aa->Iex.Binop.arg1, Iop_CmpwNEZ64))
4112 return fold_IRExpr_Unop(
4113 Iop_CmpwNEZ64,
4114 IRExpr_Binop(Iop_Or64,
4115 aa->Iex.Binop.arg1->Iex.Unop.arg,
4116 aa->Iex.Binop.arg2));
4117 /* CmpwNEZ64( Or64 ( x, CmpwNEZ64(y) ) ) --> CmpwNEZ64( Or64( x, y ) ) */
4118 if (is_Binop(aa, Iop_Or64)
4119 && is_Unop(aa->Iex.Binop.arg2, Iop_CmpwNEZ64))
4120 return fold_IRExpr_Unop(
4121 Iop_CmpwNEZ64,
4122 IRExpr_Binop(Iop_Or64,
4123 aa->Iex.Binop.arg1,
4124 aa->Iex.Binop.arg2->Iex.Unop.arg));
4125 break;
4126 case Iop_CmpNEZ64:
4127 /* CmpNEZ64( Left64(x) ) --> CmpNEZ64(x) */
4128 if (is_Unop(aa, Iop_Left64))
4129 return IRExpr_Unop(Iop_CmpNEZ64, aa->Iex.Unop.arg);
4130 break;
4131 case Iop_CmpwNEZ32:
4132 /* CmpwNEZ32( CmpwNEZ32 ( x ) ) --> CmpwNEZ32 ( x ) */
4133 if (is_Unop(aa, Iop_CmpwNEZ32))
4134 return IRExpr_Unop( Iop_CmpwNEZ32, aa->Iex.Unop.arg );
4135 break;
4136 case Iop_CmpNEZ32:
4137 /* CmpNEZ32( Left32(x) ) --> CmpNEZ32(x) */
4138 if (is_Unop(aa, Iop_Left32))
4139 return IRExpr_Unop(Iop_CmpNEZ32, aa->Iex.Unop.arg);
florian51d26fd2011-07-23 00:23:02 +00004140 /* CmpNEZ32( 1Uto32(X) ) --> X */
4141 if (is_Unop(aa, Iop_1Uto32))
4142 return aa->Iex.Unop.arg;
4143 break;
4144 case Iop_CmpNEZ8:
4145 /* CmpNEZ8( 1Uto8(X) ) --> X */
4146 if (is_Unop(aa, Iop_1Uto8))
4147 return aa->Iex.Unop.arg;
sewardjeb17e492007-08-25 23:07:44 +00004148 break;
4149 case Iop_Left32:
4150 /* Left32( Left32(x) ) --> Left32(x) */
4151 if (is_Unop(aa, Iop_Left32))
4152 return IRExpr_Unop( Iop_Left32, aa->Iex.Unop.arg );
4153 break;
4154 case Iop_32to1:
4155 /* 32to1( 1Uto32 ( x ) ) --> x */
4156 if (is_Unop(aa, Iop_1Uto32))
4157 return aa->Iex.Unop.arg;
4158 /* 32to1( CmpwNEZ32 ( x )) --> CmpNEZ32(x) */
4159 if (is_Unop(aa, Iop_CmpwNEZ32))
4160 return IRExpr_Unop( Iop_CmpNEZ32, aa->Iex.Unop.arg );
4161 break;
4162 case Iop_64to1:
4163 /* 64to1( 1Uto64 ( x ) ) --> x */
4164 if (is_Unop(aa, Iop_1Uto64))
4165 return aa->Iex.Unop.arg;
4166 /* 64to1( CmpwNEZ64 ( x )) --> CmpNEZ64(x) */
4167 if (is_Unop(aa, Iop_CmpwNEZ64))
4168 return IRExpr_Unop( Iop_CmpNEZ64, aa->Iex.Unop.arg );
4169 break;
sewardjef425db2010-01-11 10:46:18 +00004170 case Iop_64to32:
4171 /* 64to32( 32Uto64 ( x )) --> x */
4172 if (is_Unop(aa, Iop_32Uto64))
4173 return aa->Iex.Unop.arg;
sewardjca257bc2010-09-08 08:34:52 +00004174 /* 64to32( 8Uto64 ( x )) --> 8Uto32(x) */
4175 if (is_Unop(aa, Iop_8Uto64))
4176 return IRExpr_Unop(Iop_8Uto32, aa->Iex.Unop.arg);
4177 break;
4178
4179 case Iop_32Uto64:
4180 /* 32Uto64( 8Uto32( x )) --> 8Uto64(x) */
4181 if (is_Unop(aa, Iop_8Uto32))
4182 return IRExpr_Unop(Iop_8Uto64, aa->Iex.Unop.arg);
4183 /* 32Uto64( 16Uto32( x )) --> 16Uto64(x) */
4184 if (is_Unop(aa, Iop_16Uto32))
4185 return IRExpr_Unop(Iop_16Uto64, aa->Iex.Unop.arg);
sewardjef425db2010-01-11 10:46:18 +00004186 break;
sewardj6c299f32009-12-31 18:00:12 +00004187
4188 case Iop_1Sto32:
4189 /* 1Sto32( CmpNEZ8( 32to8( 1Uto32( CmpNEZ32( x ))))) -> CmpwNEZ32(x) */
4190 if (is_Unop(aa, Iop_CmpNEZ8)
4191 && is_Unop(aa->Iex.Unop.arg, Iop_32to8)
4192 && is_Unop(aa->Iex.Unop.arg->Iex.Unop.arg, Iop_1Uto32)
4193 && is_Unop(aa->Iex.Unop.arg->Iex.Unop.arg->Iex.Unop.arg,
4194 Iop_CmpNEZ32)) {
4195 return IRExpr_Unop( Iop_CmpwNEZ32,
4196 aa->Iex.Unop.arg->Iex.Unop.arg
4197 ->Iex.Unop.arg->Iex.Unop.arg);
4198 }
4199 break;
4200
sewardjef425db2010-01-11 10:46:18 +00004201
sewardjeb17e492007-08-25 23:07:44 +00004202 default:
4203 break;
4204 }
4205 /* no reduction rule applies */
4206 return IRExpr_Unop( op, aa );
4207}
4208
sewardjf9517d02005-11-28 13:39:37 +00004209static IRExpr* atbSubst_Expr ( ATmpInfo* env, IRExpr* e )
4210{
4211 IRExpr* e2;
4212 IRExpr** args2;
4213 Int i;
4214
4215 switch (e->tag) {
4216
4217 case Iex_CCall:
sewardjdd40fdf2006-12-24 02:20:24 +00004218 args2 = shallowCopyIRExprVec(e->Iex.CCall.args);
sewardjf9517d02005-11-28 13:39:37 +00004219 for (i = 0; args2[i]; i++)
4220 args2[i] = atbSubst_Expr(env,args2[i]);
4221 return IRExpr_CCall(
4222 e->Iex.CCall.cee,
4223 e->Iex.CCall.retty,
4224 args2
4225 );
sewardjdd40fdf2006-12-24 02:20:24 +00004226 case Iex_RdTmp:
4227 e2 = atbSubst_Temp(env, e->Iex.RdTmp.tmp);
sewardjf9517d02005-11-28 13:39:37 +00004228 return e2 ? e2 : e;
4229 case Iex_Mux0X:
4230 return IRExpr_Mux0X(
4231 atbSubst_Expr(env, e->Iex.Mux0X.cond),
4232 atbSubst_Expr(env, e->Iex.Mux0X.expr0),
4233 atbSubst_Expr(env, e->Iex.Mux0X.exprX)
4234 );
sewardj40c80262006-02-08 19:30:46 +00004235 case Iex_Qop:
4236 return IRExpr_Qop(
4237 e->Iex.Qop.op,
4238 atbSubst_Expr(env, e->Iex.Qop.arg1),
4239 atbSubst_Expr(env, e->Iex.Qop.arg2),
4240 atbSubst_Expr(env, e->Iex.Qop.arg3),
4241 atbSubst_Expr(env, e->Iex.Qop.arg4)
4242 );
sewardjb183b852006-02-03 16:08:03 +00004243 case Iex_Triop:
4244 return IRExpr_Triop(
4245 e->Iex.Triop.op,
4246 atbSubst_Expr(env, e->Iex.Triop.arg1),
4247 atbSubst_Expr(env, e->Iex.Triop.arg2),
4248 atbSubst_Expr(env, e->Iex.Triop.arg3)
4249 );
sewardjf9517d02005-11-28 13:39:37 +00004250 case Iex_Binop:
sewardjeb17e492007-08-25 23:07:44 +00004251 return fold_IRExpr_Binop(
sewardjf9517d02005-11-28 13:39:37 +00004252 e->Iex.Binop.op,
4253 atbSubst_Expr(env, e->Iex.Binop.arg1),
4254 atbSubst_Expr(env, e->Iex.Binop.arg2)
4255 );
4256 case Iex_Unop:
sewardjeb17e492007-08-25 23:07:44 +00004257 return fold_IRExpr_Unop(
sewardjf9517d02005-11-28 13:39:37 +00004258 e->Iex.Unop.op,
4259 atbSubst_Expr(env, e->Iex.Unop.arg)
4260 );
4261 case Iex_Load:
4262 return IRExpr_Load(
4263 e->Iex.Load.end,
4264 e->Iex.Load.ty,
4265 atbSubst_Expr(env, e->Iex.Load.addr)
4266 );
4267 case Iex_GetI:
4268 return IRExpr_GetI(
4269 e->Iex.GetI.descr,
4270 atbSubst_Expr(env, e->Iex.GetI.ix),
4271 e->Iex.GetI.bias
4272 );
4273 case Iex_Const:
4274 case Iex_Get:
4275 return e;
4276 default:
4277 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4278 vpanic("atbSubst_Expr");
4279 }
4280}
4281
4282/* Same deal as atbSubst_Expr, except for stmts. */
4283
4284static IRStmt* atbSubst_Stmt ( ATmpInfo* env, IRStmt* st )
4285{
sewardje9d8a262009-07-01 08:06:34 +00004286 Int i;
4287 IRDirty *d, *d2;
4288 IRCAS *cas, *cas2;
sewardjf9517d02005-11-28 13:39:37 +00004289 switch (st->tag) {
4290 case Ist_AbiHint:
4291 return IRStmt_AbiHint(
4292 atbSubst_Expr(env, st->Ist.AbiHint.base),
sewardj478646f2008-05-01 20:13:04 +00004293 st->Ist.AbiHint.len,
4294 atbSubst_Expr(env, st->Ist.AbiHint.nia)
sewardjf9517d02005-11-28 13:39:37 +00004295 );
4296 case Ist_Store:
4297 return IRStmt_Store(
4298 st->Ist.Store.end,
4299 atbSubst_Expr(env, st->Ist.Store.addr),
4300 atbSubst_Expr(env, st->Ist.Store.data)
4301 );
sewardjdd40fdf2006-12-24 02:20:24 +00004302 case Ist_WrTmp:
4303 return IRStmt_WrTmp(
4304 st->Ist.WrTmp.tmp,
4305 atbSubst_Expr(env, st->Ist.WrTmp.data)
sewardjf9517d02005-11-28 13:39:37 +00004306 );
4307 case Ist_Put:
4308 return IRStmt_Put(
4309 st->Ist.Put.offset,
4310 atbSubst_Expr(env, st->Ist.Put.data)
4311 );
4312 case Ist_PutI:
4313 return IRStmt_PutI(
4314 st->Ist.PutI.descr,
4315 atbSubst_Expr(env, st->Ist.PutI.ix),
4316 st->Ist.PutI.bias,
4317 atbSubst_Expr(env, st->Ist.PutI.data)
4318 );
4319
4320 case Ist_Exit:
4321 return IRStmt_Exit(
4322 atbSubst_Expr(env, st->Ist.Exit.guard),
4323 st->Ist.Exit.jk,
4324 st->Ist.Exit.dst
4325 );
4326 case Ist_IMark:
sewardj2f10aa62011-05-27 13:20:56 +00004327 return IRStmt_IMark(st->Ist.IMark.addr,
4328 st->Ist.IMark.len,
4329 st->Ist.IMark.delta);
sewardjf9517d02005-11-28 13:39:37 +00004330 case Ist_NoOp:
4331 return IRStmt_NoOp();
sewardjc4356f02007-11-09 21:15:04 +00004332 case Ist_MBE:
4333 return IRStmt_MBE(st->Ist.MBE.event);
sewardje9d8a262009-07-01 08:06:34 +00004334 case Ist_CAS:
4335 cas = st->Ist.CAS.details;
4336 cas2 = mkIRCAS(
4337 cas->oldHi, cas->oldLo, cas->end,
4338 atbSubst_Expr(env, cas->addr),
4339 cas->expdHi ? atbSubst_Expr(env, cas->expdHi) : NULL,
4340 atbSubst_Expr(env, cas->expdLo),
4341 cas->dataHi ? atbSubst_Expr(env, cas->dataHi) : NULL,
4342 atbSubst_Expr(env, cas->dataLo)
4343 );
4344 return IRStmt_CAS(cas2);
sewardje768e922009-11-26 17:17:37 +00004345 case Ist_LLSC:
4346 return IRStmt_LLSC(
4347 st->Ist.LLSC.end,
4348 st->Ist.LLSC.result,
4349 atbSubst_Expr(env, st->Ist.LLSC.addr),
4350 st->Ist.LLSC.storedata
4351 ? atbSubst_Expr(env, st->Ist.LLSC.storedata) : NULL
4352 );
sewardjf9517d02005-11-28 13:39:37 +00004353 case Ist_Dirty:
4354 d = st->Ist.Dirty.details;
4355 d2 = emptyIRDirty();
4356 *d2 = *d;
4357 if (d2->mFx != Ifx_None)
4358 d2->mAddr = atbSubst_Expr(env, d2->mAddr);
4359 d2->guard = atbSubst_Expr(env, d2->guard);
4360 for (i = 0; d2->args[i]; i++)
4361 d2->args[i] = atbSubst_Expr(env, d2->args[i]);
4362 return IRStmt_Dirty(d2);
4363 default:
4364 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
4365 vpanic("atbSubst_Stmt");
4366 }
4367}
4368
sewardjdd40fdf2006-12-24 02:20:24 +00004369/* notstatic */ void ado_treebuild_BB ( IRSB* bb )
sewardjf9517d02005-11-28 13:39:37 +00004370{
4371 Int i, j, k, m;
4372 Bool stmtPuts, stmtStores, invalidateMe;
sewardj29632392004-08-22 02:38:11 +00004373 IRStmt* st;
4374 IRStmt* st2;
sewardjf9517d02005-11-28 13:39:37 +00004375 ATmpInfo env[A_NENV];
sewardj29632392004-08-22 02:38:11 +00004376
sewardjc9ad1152004-10-14 00:08:21 +00004377 Int n_tmps = bb->tyenv->types_used;
sewardjf9517d02005-11-28 13:39:37 +00004378 UShort* uses = LibVEX_Alloc(n_tmps * sizeof(UShort));
sewardj29632392004-08-22 02:38:11 +00004379
4380 /* Phase 1. Scan forwards in bb, counting use occurrences of each
4381 temp. Also count occurrences in the bb->next field. */
4382
sewardjf9517d02005-11-28 13:39:37 +00004383 for (i = 0; i < n_tmps; i++)
4384 uses[i] = 0;
4385
sewardj29632392004-08-22 02:38:11 +00004386 for (i = 0; i < bb->stmts_used; i++) {
4387 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00004388 if (st->tag == Ist_NoOp)
sewardj29632392004-08-22 02:38:11 +00004389 continue;
sewardjf9517d02005-11-28 13:39:37 +00004390 aoccCount_Stmt( uses, st );
sewardj29632392004-08-22 02:38:11 +00004391 }
sewardjf9517d02005-11-28 13:39:37 +00004392 aoccCount_Expr(uses, bb->next );
sewardj29632392004-08-22 02:38:11 +00004393
sewardjc9ad1152004-10-14 00:08:21 +00004394# if 0
sewardjf9517d02005-11-28 13:39:37 +00004395 for (i = 0; i < n_tmps; i++) {
4396 if (uses[i] == 0)
sewardj29632392004-08-22 02:38:11 +00004397 continue;
sewardjf9517d02005-11-28 13:39:37 +00004398 ppIRTemp( (IRTemp)i );
4399 vex_printf(" used %d\n", (Int)uses[i] );
sewardj29632392004-08-22 02:38:11 +00004400 }
sewardjc9ad1152004-10-14 00:08:21 +00004401# endif
sewardj29632392004-08-22 02:38:11 +00004402
sewardjf9517d02005-11-28 13:39:37 +00004403 /* Phase 2. Scan forwards in bb. For each statement in turn:
sewardj29632392004-08-22 02:38:11 +00004404
sewardjf9517d02005-11-28 13:39:37 +00004405 If the env is full, emit the end element. This guarantees
4406 there is at least one free slot in the following.
sewardj29632392004-08-22 02:38:11 +00004407
sewardjf9517d02005-11-28 13:39:37 +00004408 On seeing 't = E', occ(t)==1,
4409 let E'=env(E)
4410 delete this stmt
4411 add t -> E' to the front of the env
4412 Examine E' and set the hints for E' appropriately
sewardj29632392004-08-22 02:38:11 +00004413 (doesLoad? doesGet?)
4414
sewardjf9517d02005-11-28 13:39:37 +00004415 On seeing any other stmt,
sewardj29632392004-08-22 02:38:11 +00004416 let stmt' = env(stmt)
4417 remove from env any 't=E' binds invalidated by stmt
4418 emit the invalidated stmts
4419 emit stmt'
sewardjf9517d02005-11-28 13:39:37 +00004420 compact any holes in env
4421 by sliding entries towards the front
sewardj29632392004-08-22 02:38:11 +00004422
sewardjf9517d02005-11-28 13:39:37 +00004423 Finally, apply env to bb->next.
sewardj29632392004-08-22 02:38:11 +00004424 */
4425
sewardjf9517d02005-11-28 13:39:37 +00004426 for (i = 0; i < A_NENV; i++) {
4427 env[i].bindee = NULL;
4428 env[i].binder = IRTemp_INVALID;
4429 }
4430
sewardj29632392004-08-22 02:38:11 +00004431 /* The stmts in bb are being reordered, and we are guaranteed to
4432 end up with no more than the number we started with. Use i to
4433 be the cursor of the current stmt examined and j <= i to be that
4434 for the current stmt being written.
4435 */
4436 j = 0;
4437 for (i = 0; i < bb->stmts_used; i++) {
sewardjf9517d02005-11-28 13:39:37 +00004438
sewardj29632392004-08-22 02:38:11 +00004439 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00004440 if (st->tag == Ist_NoOp)
sewardj29632392004-08-22 02:38:11 +00004441 continue;
4442
sewardjf9517d02005-11-28 13:39:37 +00004443 /* Ensure there's at least one space in the env, by emitting
4444 the oldest binding if necessary. */
4445 if (env[A_NENV-1].bindee != NULL) {
sewardjdd40fdf2006-12-24 02:20:24 +00004446 bb->stmts[j] = IRStmt_WrTmp( env[A_NENV-1].binder,
4447 env[A_NENV-1].bindee );
sewardjf9517d02005-11-28 13:39:37 +00004448 j++;
4449 vassert(j <= i);
4450 env[A_NENV-1].bindee = NULL;
4451 }
4452
4453 /* Consider current stmt. */
sewardjdd40fdf2006-12-24 02:20:24 +00004454 if (st->tag == Ist_WrTmp && uses[st->Ist.WrTmp.tmp] <= 1) {
sewardj63327402006-01-25 03:26:27 +00004455 IRExpr *e, *e2;
sewardjf9517d02005-11-28 13:39:37 +00004456
4457 /* optional extra: dump dead bindings as we find them.
4458 Removes the need for a prior dead-code removal pass. */
sewardjdd40fdf2006-12-24 02:20:24 +00004459 if (uses[st->Ist.WrTmp.tmp] == 0) {
sewardjb183b852006-02-03 16:08:03 +00004460 if (0) vex_printf("DEAD binding\n");
sewardjf9517d02005-11-28 13:39:37 +00004461 continue; /* for (i = 0; i < bb->stmts_used; i++) loop */
sewardj29632392004-08-22 02:38:11 +00004462 }
sewardjdd40fdf2006-12-24 02:20:24 +00004463 vassert(uses[st->Ist.WrTmp.tmp] == 1);
sewardjf9517d02005-11-28 13:39:37 +00004464
4465 /* ok, we have 't = E', occ(t)==1. Do the abovementioned
4466 actions. */
sewardjdd40fdf2006-12-24 02:20:24 +00004467 e = st->Ist.WrTmp.data;
sewardj63327402006-01-25 03:26:27 +00004468 e2 = atbSubst_Expr(env, e);
sewardjdd40fdf2006-12-24 02:20:24 +00004469 addToEnvFront(env, st->Ist.WrTmp.tmp, e2);
sewardjf9517d02005-11-28 13:39:37 +00004470 setHints_Expr(&env[0].doesLoad, &env[0].doesGet, e2);
4471 /* don't advance j, as we are deleting this stmt and instead
4472 holding it temporarily in the env. */
4473 continue; /* for (i = 0; i < bb->stmts_used; i++) loop */
sewardj29632392004-08-22 02:38:11 +00004474 }
4475
4476 /* we get here for any other kind of statement. */
4477 /* 'use up' any bindings required by the current statement. */
sewardjf9517d02005-11-28 13:39:37 +00004478 st2 = atbSubst_Stmt(env, st);
sewardj29632392004-08-22 02:38:11 +00004479
sewardjf9517d02005-11-28 13:39:37 +00004480 /* Now, before this stmt, dump any bindings in env that it
4481 invalidates. These need to be dumped in the order in which
4482 they originally entered env -- that means from oldest to
4483 youngest. */
sewardj3e838932005-01-07 12:09:15 +00004484
sewardjf9517d02005-11-28 13:39:37 +00004485 /* stmtPuts/stmtStores characterise what the stmt under
sewardje9d8a262009-07-01 08:06:34 +00004486 consideration does, or might do (sidely safe @ True). */
4487 stmtPuts
4488 = toBool( st->tag == Ist_Put
4489 || st->tag == Ist_PutI
4490 || st->tag == Ist_Dirty );
sewardj29632392004-08-22 02:38:11 +00004491
sewardje9d8a262009-07-01 08:06:34 +00004492 /* be True if this stmt writes memory or might do (==> we don't
4493 want to reorder other loads or stores relative to it). Also,
sewardje768e922009-11-26 17:17:37 +00004494 both LL and SC fall under this classification, since we
sewardje9d8a262009-07-01 08:06:34 +00004495 really ought to be conservative and not reorder any other
sewardje768e922009-11-26 17:17:37 +00004496 memory transactions relative to them. */
sewardje9d8a262009-07-01 08:06:34 +00004497 stmtStores
4498 = toBool( st->tag == Ist_Store
sewardje768e922009-11-26 17:17:37 +00004499 || st->tag == Ist_Dirty
4500 || st->tag == Ist_LLSC );
sewardj29632392004-08-22 02:38:11 +00004501
sewardjf9517d02005-11-28 13:39:37 +00004502 for (k = A_NENV-1; k >= 0; k--) {
4503 if (env[k].bindee == NULL)
4504 continue;
4505 /* Compare the actions of this stmt with the actions of
4506 binding 'k', to see if they invalidate the binding. */
4507 invalidateMe
sewardj9d2e7692005-02-07 01:11:31 +00004508 = toBool(
4509 /* a store invalidates loaded data */
sewardjf9517d02005-11-28 13:39:37 +00004510 (env[k].doesLoad && stmtStores)
sewardj4c5f6d52004-10-26 13:25:33 +00004511 /* a put invalidates get'd data */
sewardjf9517d02005-11-28 13:39:37 +00004512 || (env[k].doesGet && stmtPuts)
sewardj4c5f6d52004-10-26 13:25:33 +00004513 /* a put invalidates loaded data. Note, we could do
4514 much better here in the sense that we only need to
4515 invalidate trees containing loads if the Put in
4516 question is marked as requiring precise
4517 exceptions. */
sewardjf9517d02005-11-28 13:39:37 +00004518 || (env[k].doesLoad && stmtPuts)
sewardjc4356f02007-11-09 21:15:04 +00004519 /* probably overly conservative: a memory bus event
sewardj3e838932005-01-07 12:09:15 +00004520 invalidates absolutely everything, so that all
4521 computation prior to it is forced to complete before
sewardjc4356f02007-11-09 21:15:04 +00004522 proceeding with the event (fence,lock,unlock). */
4523 || st->tag == Ist_MBE
sewardj5a9ffab2005-05-12 17:55:01 +00004524 /* also be (probably overly) paranoid re AbiHints */
4525 || st->tag == Ist_AbiHint
sewardj9d2e7692005-02-07 01:11:31 +00004526 );
sewardjf9517d02005-11-28 13:39:37 +00004527 if (invalidateMe) {
sewardjdd40fdf2006-12-24 02:20:24 +00004528 bb->stmts[j] = IRStmt_WrTmp( env[k].binder, env[k].bindee );
sewardjf9517d02005-11-28 13:39:37 +00004529 j++;
4530 vassert(j <= i);
4531 env[k].bindee = NULL;
4532 }
sewardj29632392004-08-22 02:38:11 +00004533 }
4534
sewardjf9517d02005-11-28 13:39:37 +00004535 /* Slide in-use entries in env up to the front */
4536 m = 0;
4537 for (k = 0; k < A_NENV; k++) {
4538 if (env[k].bindee != NULL) {
4539 env[m] = env[k];
4540 m++;
4541 }
4542 }
4543 for (m = m; m < A_NENV; m++) {
4544 env[m].bindee = NULL;
4545 }
sewardj29632392004-08-22 02:38:11 +00004546
4547 /* finally, emit the substituted statement */
4548 bb->stmts[j] = st2;
sewardjf9517d02005-11-28 13:39:37 +00004549 /* vex_printf("**2 "); ppIRStmt(bb->stmts[j]); vex_printf("\n"); */
sewardj29632392004-08-22 02:38:11 +00004550 j++;
4551
4552 vassert(j <= i+1);
4553 } /* for each stmt in the original bb ... */
4554
4555 /* Finally ... substitute the ->next field as much as possible, and
4556 dump any left-over bindings. Hmm. Perhaps there should be no
4557 left over bindings? Or any left-over bindings are
4558 by definition dead? */
sewardjf9517d02005-11-28 13:39:37 +00004559 bb->next = atbSubst_Expr(env, bb->next);
sewardj29632392004-08-22 02:38:11 +00004560 bb->stmts_used = j;
4561}
4562
4563
sewardj695cff92004-10-13 14:50:14 +00004564/*---------------------------------------------------------------*/
sewardjedf4d692004-08-17 13:52:58 +00004565/*--- iropt main ---*/
4566/*---------------------------------------------------------------*/
4567
sewardjb183b852006-02-03 16:08:03 +00004568static Bool iropt_verbose = False; /* True; */
sewardj4345f7a2004-09-22 19:49:27 +00004569
4570
sewardj4345f7a2004-09-22 19:49:27 +00004571/* Do a simple cleanup pass on bb. This is: redundant Get removal,
4572 redundant Put removal, constant propagation, dead code removal,
4573 clean helper specialisation, and dead code removal (again).
sewardjb9230752004-12-29 19:25:06 +00004574*/
sewardj695cff92004-10-13 14:50:14 +00004575
sewardj4345f7a2004-09-22 19:49:27 +00004576
4577static
sewardjdd40fdf2006-12-24 02:20:24 +00004578IRSB* cheap_transformations (
4579 IRSB* bb,
sewardjbe917912010-08-22 12:38:53 +00004580 IRExpr* (*specHelper) (HChar*, IRExpr**, IRStmt**, Int),
sewardj8d2291c2004-10-25 14:50:21 +00004581 Bool (*preciseMemExnsFn)(Int,Int)
4582 )
sewardj4345f7a2004-09-22 19:49:27 +00004583{
4584 redundant_get_removal_BB ( bb );
4585 if (iropt_verbose) {
4586 vex_printf("\n========= REDUNDANT GET\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004587 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004588 }
sewardj044a2152004-10-21 10:22:10 +00004589
sewardj8d2291c2004-10-25 14:50:21 +00004590 redundant_put_removal_BB ( bb, preciseMemExnsFn );
sewardj4345f7a2004-09-22 19:49:27 +00004591 if (iropt_verbose) {
4592 vex_printf("\n========= REDUNDANT PUT\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004593 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004594 }
sewardj044a2152004-10-21 10:22:10 +00004595
sewardj4345f7a2004-09-22 19:49:27 +00004596 bb = cprop_BB ( bb );
4597 if (iropt_verbose) {
4598 vex_printf("\n========= CPROPD\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004599 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004600 }
4601
sewardj49651f42004-10-28 22:11:04 +00004602 do_deadcode_BB ( bb );
sewardj4345f7a2004-09-22 19:49:27 +00004603 if (iropt_verbose) {
4604 vex_printf("\n========= DEAD\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004605 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004606 }
4607
sewardjb9230752004-12-29 19:25:06 +00004608 bb = spec_helpers_BB ( bb, specHelper );
sewardj49651f42004-10-28 22:11:04 +00004609 do_deadcode_BB ( bb );
sewardj4345f7a2004-09-22 19:49:27 +00004610 if (iropt_verbose) {
4611 vex_printf("\n========= SPECd \n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004612 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00004613 }
4614
4615 return bb;
4616}
4617
sewardj695cff92004-10-13 14:50:14 +00004618
4619/* Do some more expensive transformations on bb, which are aimed at
4620 optimising as much as possible in the presence of GetI and PutI. */
4621
4622static
sewardjdd40fdf2006-12-24 02:20:24 +00004623IRSB* expensive_transformations( IRSB* bb )
sewardj695cff92004-10-13 14:50:14 +00004624{
sewardj9b0cc582006-02-04 15:24:00 +00004625 (void)do_cse_BB( bb );
sewardj695cff92004-10-13 14:50:14 +00004626 collapse_AddSub_chains_BB( bb );
sewardj08210532004-12-29 17:09:11 +00004627 do_redundant_GetI_elimination( bb );
sewardj695cff92004-10-13 14:50:14 +00004628 do_redundant_PutI_elimination( bb );
sewardj49651f42004-10-28 22:11:04 +00004629 do_deadcode_BB( bb );
sewardjb9230752004-12-29 19:25:06 +00004630 return bb;
sewardj695cff92004-10-13 14:50:14 +00004631}
4632
4633
sewardjb183b852006-02-03 16:08:03 +00004634/* Scan a flattened BB to look for signs that more expensive
4635 optimisations might be useful:
4636 - find out if there are any GetIs and PutIs
4637 - find out if there are any floating or vector-typed temporaries
4638*/
sewardj695cff92004-10-13 14:50:14 +00004639
sewardjb183b852006-02-03 16:08:03 +00004640static void considerExpensives ( /*OUT*/Bool* hasGetIorPutI,
4641 /*OUT*/Bool* hasVorFtemps,
sewardjdd40fdf2006-12-24 02:20:24 +00004642 IRSB* bb )
sewardj4345f7a2004-09-22 19:49:27 +00004643{
sewardje9d8a262009-07-01 08:06:34 +00004644 Int i, j;
4645 IRStmt* st;
sewardj4345f7a2004-09-22 19:49:27 +00004646 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00004647 IRCAS* cas;
sewardj4345f7a2004-09-22 19:49:27 +00004648
sewardjb183b852006-02-03 16:08:03 +00004649 *hasGetIorPutI = False;
4650 *hasVorFtemps = False;
4651
sewardj4345f7a2004-09-22 19:49:27 +00004652 for (i = 0; i < bb->stmts_used; i++) {
4653 st = bb->stmts[i];
sewardj4345f7a2004-09-22 19:49:27 +00004654 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00004655 case Ist_AbiHint:
4656 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +00004657 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +00004658 break;
sewardj4345f7a2004-09-22 19:49:27 +00004659 case Ist_PutI:
sewardjb183b852006-02-03 16:08:03 +00004660 *hasGetIorPutI = True;
4661 break;
sewardjdd40fdf2006-12-24 02:20:24 +00004662 case Ist_WrTmp:
4663 if (st->Ist.WrTmp.data->tag == Iex_GetI)
sewardjb183b852006-02-03 16:08:03 +00004664 *hasGetIorPutI = True;
sewardjdd40fdf2006-12-24 02:20:24 +00004665 switch (typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp)) {
sewardjb183b852006-02-03 16:08:03 +00004666 case Ity_I1: case Ity_I8: case Ity_I16:
4667 case Ity_I32: case Ity_I64: case Ity_I128:
4668 break;
sewardj2019a972011-03-07 16:04:07 +00004669 case Ity_F32: case Ity_F64: case Ity_F128: case Ity_V128:
sewardjb183b852006-02-03 16:08:03 +00004670 *hasVorFtemps = True;
4671 break;
4672 default:
4673 goto bad;
4674 }
sewardj4345f7a2004-09-22 19:49:27 +00004675 break;
4676 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00004677 vassert(isIRAtom(st->Ist.Put.data));
sewardj4345f7a2004-09-22 19:49:27 +00004678 break;
sewardjaf1ceca2005-06-30 23:31:27 +00004679 case Ist_Store:
4680 vassert(isIRAtom(st->Ist.Store.addr));
4681 vassert(isIRAtom(st->Ist.Store.data));
sewardj4345f7a2004-09-22 19:49:27 +00004682 break;
sewardje9d8a262009-07-01 08:06:34 +00004683 case Ist_CAS:
4684 cas = st->Ist.CAS.details;
4685 vassert(isIRAtom(cas->addr));
4686 vassert(cas->expdHi == NULL || isIRAtom(cas->expdHi));
4687 vassert(isIRAtom(cas->expdLo));
4688 vassert(cas->dataHi == NULL || isIRAtom(cas->dataHi));
4689 vassert(isIRAtom(cas->dataLo));
4690 break;
sewardje768e922009-11-26 17:17:37 +00004691 case Ist_LLSC:
4692 vassert(isIRAtom(st->Ist.LLSC.addr));
4693 if (st->Ist.LLSC.storedata)
4694 vassert(isIRAtom(st->Ist.LLSC.storedata));
4695 break;
sewardj4345f7a2004-09-22 19:49:27 +00004696 case Ist_Dirty:
4697 d = st->Ist.Dirty.details;
sewardj496a58d2005-03-20 18:44:44 +00004698 vassert(isIRAtom(d->guard));
sewardj4345f7a2004-09-22 19:49:27 +00004699 for (j = 0; d->args[j]; j++)
sewardj496a58d2005-03-20 18:44:44 +00004700 vassert(isIRAtom(d->args[j]));
sewardj4345f7a2004-09-22 19:49:27 +00004701 if (d->mFx != Ifx_None)
sewardj496a58d2005-03-20 18:44:44 +00004702 vassert(isIRAtom(d->mAddr));
sewardj4345f7a2004-09-22 19:49:27 +00004703 break;
sewardjd2445f62005-03-21 00:15:53 +00004704 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00004705 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00004706 case Ist_MBE:
sewardj3e838932005-01-07 12:09:15 +00004707 break;
4708 case Ist_Exit:
sewardj496a58d2005-03-20 18:44:44 +00004709 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj3e838932005-01-07 12:09:15 +00004710 break;
sewardj4345f7a2004-09-22 19:49:27 +00004711 default:
sewardjb183b852006-02-03 16:08:03 +00004712 bad:
sewardj4345f7a2004-09-22 19:49:27 +00004713 ppIRStmt(st);
sewardje768e922009-11-26 17:17:37 +00004714 vpanic("considerExpensives");
sewardj4345f7a2004-09-22 19:49:27 +00004715 }
sewardj4345f7a2004-09-22 19:49:27 +00004716 }
sewardj4345f7a2004-09-22 19:49:27 +00004717}
4718
4719
sewardj695cff92004-10-13 14:50:14 +00004720/* ---------------- The main iropt entry point. ---------------- */
4721
sewardjedf4d692004-08-17 13:52:58 +00004722/* exported from this file */
sewardj695cff92004-10-13 14:50:14 +00004723/* Rules of the game:
4724
4725 - IRExpr/IRStmt trees should be treated as immutable, as they
4726 may get shared. So never change a field of such a tree node;
4727 instead construct and return a new one if needed.
4728*/
4729
sewardj4345f7a2004-09-22 19:49:27 +00004730
sewardjbe917912010-08-22 12:38:53 +00004731IRSB* do_iropt_BB(
4732 IRSB* bb0,
4733 IRExpr* (*specHelper) (HChar*, IRExpr**, IRStmt**, Int),
4734 Bool (*preciseMemExnsFn)(Int,Int),
4735 Addr64 guest_addr,
4736 VexArch guest_arch
4737 )
sewardjedf4d692004-08-17 13:52:58 +00004738{
sewardj9d2e7692005-02-07 01:11:31 +00004739 static Int n_total = 0;
4740 static Int n_expensive = 0;
sewardj29632392004-08-22 02:38:11 +00004741
sewardjb183b852006-02-03 16:08:03 +00004742 Bool hasGetIorPutI, hasVorFtemps;
sewardjdd40fdf2006-12-24 02:20:24 +00004743 IRSB *bb, *bb2;
sewardj8c2c10b2004-10-16 20:51:52 +00004744
sewardj4345f7a2004-09-22 19:49:27 +00004745 n_total++;
4746
4747 /* First flatten the block out, since all other
4748 phases assume flat code. */
4749
4750 bb = flatten_BB ( bb0 );
4751
4752 if (iropt_verbose) {
4753 vex_printf("\n========= FLAT\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00004754 ppIRSB(bb);
sewardj84be7372004-08-18 13:59:33 +00004755 }
sewardjd7217032004-08-19 10:49:10 +00004756
sewardj08210532004-12-29 17:09:11 +00004757 /* If at level 0, stop now. */
4758 if (vex_control.iropt_level <= 0) return bb;
4759
sewardj695cff92004-10-13 14:50:14 +00004760 /* Now do a preliminary cleanup pass, and figure out if we also
4761 need to do 'expensive' optimisations. Expensive optimisations
4762 are deemed necessary if the block contains any GetIs or PutIs.
4763 If needed, do expensive transformations and then another cheap
4764 cleanup pass. */
sewardj4345f7a2004-09-22 19:49:27 +00004765
sewardj8d2291c2004-10-25 14:50:21 +00004766 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj695cff92004-10-13 14:50:14 +00004767
sewardjbe917912010-08-22 12:38:53 +00004768 if (guest_arch == VexArchARM) {
4769 /* Translating Thumb2 code produces a lot of chaff. We have to
4770 work extra hard to get rid of it. */
4771 bb = cprop_BB(bb);
4772 bb = spec_helpers_BB ( bb, specHelper );
4773 redundant_put_removal_BB ( bb, preciseMemExnsFn );
sewardjd5436ce2011-05-01 18:36:51 +00004774 do_cse_BB( bb );
sewardjbe917912010-08-22 12:38:53 +00004775 do_deadcode_BB( bb );
4776 }
4777
sewardj08613742004-10-25 13:01:45 +00004778 if (vex_control.iropt_level > 1) {
sewardjb183b852006-02-03 16:08:03 +00004779
4780 /* Peer at what we have, to decide how much more effort to throw
4781 at it. */
4782 considerExpensives( &hasGetIorPutI, &hasVorFtemps, bb );
4783
sewardj9b0cc582006-02-04 15:24:00 +00004784 if (hasVorFtemps && !hasGetIorPutI) {
sewardjb183b852006-02-03 16:08:03 +00004785 /* If any evidence of FP or Vector activity, CSE, as that
4786 tends to mop up all manner of lardy code to do with
sewardj9b0cc582006-02-04 15:24:00 +00004787 rounding modes. Don't bother if hasGetIorPutI since that
4788 case leads into the expensive transformations, which do
4789 CSE anyway. */
4790 (void)do_cse_BB( bb );
sewardjb183b852006-02-03 16:08:03 +00004791 do_deadcode_BB( bb );
4792 }
4793
4794 if (hasGetIorPutI) {
sewardj9b0cc582006-02-04 15:24:00 +00004795 Bool cses;
sewardj39555aa2004-10-24 22:29:19 +00004796 n_expensive++;
sewardj39555aa2004-10-24 22:29:19 +00004797 if (DEBUG_IROPT)
4798 vex_printf("***** EXPENSIVE %d %d\n", n_total, n_expensive);
sewardj695cff92004-10-13 14:50:14 +00004799 bb = expensive_transformations( bb );
sewardj8d2291c2004-10-25 14:50:21 +00004800 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj9b0cc582006-02-04 15:24:00 +00004801 /* Potentially common up GetIs */
4802 cses = do_cse_BB( bb );
4803 if (cses)
4804 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj695cff92004-10-13 14:50:14 +00004805 }
sewardj39555aa2004-10-24 22:29:19 +00004806
4807 /* Now have a go at unrolling simple (single-BB) loops. If
4808 successful, clean up the results as much as possible. */
4809
4810 bb2 = maybe_loop_unroll_BB( bb, guest_addr );
4811 if (bb2) {
sewardj8d2291c2004-10-25 14:50:21 +00004812 bb = cheap_transformations( bb2, specHelper, preciseMemExnsFn );
sewardjb183b852006-02-03 16:08:03 +00004813 if (hasGetIorPutI) {
sewardj39555aa2004-10-24 22:29:19 +00004814 bb = expensive_transformations( bb );
sewardj8d2291c2004-10-25 14:50:21 +00004815 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj39555aa2004-10-24 22:29:19 +00004816 } else {
4817 /* at least do CSE and dead code removal */
sewardjfe1ccfc2004-11-11 02:14:45 +00004818 do_cse_BB( bb );
sewardj49651f42004-10-28 22:11:04 +00004819 do_deadcode_BB( bb );
sewardj39555aa2004-10-24 22:29:19 +00004820 }
4821 if (0) vex_printf("vex iropt: unrolled a loop\n");
4822 }
4823
sewardjd7217032004-08-19 10:49:10 +00004824 }
4825
sewardj4345f7a2004-09-22 19:49:27 +00004826 return bb;
sewardjedf4d692004-08-17 13:52:58 +00004827}
4828
4829
sewardja1a370f2004-08-17 13:31:55 +00004830/*---------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +00004831/*--- end ir_opt.c ---*/
sewardja1a370f2004-08-17 13:31:55 +00004832/*---------------------------------------------------------------*/