blob: 7a879d484b921fa9d2eb907a2158c9117564d7d7 [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
sewardj25e54732012-08-05 15:36:51 +000011 Copyright (C) 2004-2012 OpenWorks LLP
sewardj752f9062010-05-03 21:38:49 +000012 info@open-works.net
sewardjf8ed9d82004-11-12 17:40:23 +000013
sewardj752f9062010-05-03 21:38:49 +000014 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
sewardjf8ed9d82004-11-12 17:40:23 +000018
sewardj752f9062010-05-03 21:38:49 +000019 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
sewardj7bd6ffe2005-08-03 16:07:36 +000027 02110-1301, USA.
28
sewardj752f9062010-05-03 21:38:49 +000029 The GNU General Public License is contained in the file COPYING.
sewardjf8ed9d82004-11-12 17:40:23 +000030
31 Neither the names of the U.S. Department of Energy nor the
32 University of California nor the names of its contributors may be
33 used to endorse or promote products derived from this software
34 without prior written permission.
sewardjf8ed9d82004-11-12 17:40:23 +000035*/
36
sewardja1a370f2004-08-17 13:31:55 +000037#include "libvex_basictypes.h"
sewardjedf4d692004-08-17 13:52:58 +000038#include "libvex_ir.h"
sewardja1a370f2004-08-17 13:31:55 +000039#include "libvex.h"
40
sewardjcef7d3e2009-07-02 12:21:59 +000041#include "main_util.h"
42#include "main_globals.h"
43#include "ir_opt.h"
sewardja1a370f2004-08-17 13:31:55 +000044
sewardjd0863ff2004-10-23 00:22:32 +000045
sewardj088bcb42004-08-19 17:16:52 +000046/* Set to 1 for lots of debugging output. */
47#define DEBUG_IROPT 0
48
floriancdb5fee2012-02-13 00:06:29 +000049/* Set to 1 to gather some statistics. Currently only for sameIRExprs. */
50#define STATS_IROPT 0
51
sewardja1a370f2004-08-17 13:31:55 +000052
sewardj08210532004-12-29 17:09:11 +000053/* What iropt does, 29 Dec 04.
54
sewardjf6c8ebf2007-02-06 01:52:52 +000055 It takes an IRSB and produces a new one with the same meaning,
sewardj08210532004-12-29 17:09:11 +000056 defined thus:
57
58 After execution of the new BB, all guest state and guest memory is
59 the same as after execution of the original. This is true
60 regardless of how the block was exited (at the end vs side exit).
61
62 In addition, parts of the guest state will be identical to that
63 created by execution of the original at the following observation
64 points:
65
66 * In a dirty helper call, any parts of the guest state that the
67 helper states that it reads or modifies will be up to date.
68 Also, guest memory will be up to date. Parts of the guest state
69 not marked as being read or modified by the helper cannot be
70 assumed to be up-to-date at the point where the helper is called.
71
philippe6c46bef2012-08-14 22:29:01 +000072 * If iropt_register_updates == VexRegUpdSpAtMemAccess :
73 The guest state is only up to date only as explained above
74 (i.e. at SB exits and as specified by dirty helper call).
75 Also, the stack pointer register is up to date at memory
76 exception points (as this is needed for the stack extension
77 logic in m_signals.c).
78
philippec8e2f982012-08-01 22:04:13 +000079 * If iropt_register_updates == VexRegUpdUnwindregsAtMemAccess :
80 Immediately prior to any load or store, those parts of the guest
sewardj08210532004-12-29 17:09:11 +000081 state marked as requiring precise exceptions will be up to date.
82 Also, guest memory will be up to date. Parts of the guest state
83 not marked as requiring precise exceptions cannot be assumed to
84 be up-to-date at the point of the load/store.
85
philippe6c46bef2012-08-14 22:29:01 +000086 * If iropt_register_updates == VexRegUpdAllregsAtMemAccess:
philippec8e2f982012-08-01 22:04:13 +000087 Same as minimal, but all the guest state is up to date at memory
88 exception points.
89
philippe6c46bef2012-08-14 22:29:01 +000090 * If iropt_register_updates == VexRegUpdAllregsAtEachInsn :
philippec8e2f982012-08-01 22:04:13 +000091 Guest state is up to date at each instruction.
92
sewardj08210532004-12-29 17:09:11 +000093 The relative order of loads and stores (including loads/stores of
94 guest memory done by dirty helpers annotated as such) is not
95 changed. However, the relative order of loads with no intervening
96 stores/modifies may be changed.
97
98 Transformation order
99 ~~~~~~~~~~~~~~~~~~~~
100
101 There are three levels of optimisation, controlled by
102 vex_control.iropt_level. Define first:
103
104 "Cheap transformations" are the following sequence:
105 * Redundant-Get removal
106 * Redundant-Put removal
107 * Constant propagation/folding
108 * Dead code removal
109 * Specialisation of clean helper functions
110 * Dead code removal
111
112 "Expensive transformations" are the following sequence:
113 * CSE
114 * Folding of add/sub chains
115 * Redundant-GetI removal
116 * Redundant-PutI removal
117 * Dead code removal
sewardj08210532004-12-29 17:09:11 +0000118
119 Then the transformations are as follows, as defined by
120 vex_control.iropt_level:
121
122 Level 0:
123 * Flatten into atomic form.
124
125 Level 1: the following sequence:
126 * Flatten into atomic form.
127 * Cheap transformations.
sewardj08210532004-12-29 17:09:11 +0000128
129 Level 2: the following sequence
130 * Flatten into atomic form.
131 * Cheap transformations.
sewardjb183b852006-02-03 16:08:03 +0000132 * If block contains any floating or vector types, CSE.
sewardj08210532004-12-29 17:09:11 +0000133 * If block contains GetI or PutI, Expensive transformations.
134 * Try unrolling loops. Three possible outcomes:
135 - No effect: do nothing more.
136 - Unrolled a loop, and block does not contain GetI or PutI:
137 Do: * CSE
138 * Dead code removal
sewardj08210532004-12-29 17:09:11 +0000139 - Unrolled a loop, and block contains GetI or PutI:
140 Do: * Expensive transformations
141 * Cheap transformations
sewardj08210532004-12-29 17:09:11 +0000142*/
143
sewardj98430292004-12-29 17:34:50 +0000144/* Implementation notes, 29 Dec 04.
145
146 TODO (important): I think rPutI removal ignores precise exceptions
147 and is therefore in a sense, wrong. In the sense that PutIs are
148 assumed not to write parts of the guest state that we need to have
149 up-to-date at loads/stores. So far on x86 guest that has not
150 mattered since indeed only the x87 FP registers and tags are
151 accessed using GetI/PutI, and there is no need so far for them to
152 be up to date at mem exception points. The rPutI pass should be
153 fixed.
sewardjfb44d552004-10-25 09:48:47 +0000154
sewardj4c5f6d52004-10-26 13:25:33 +0000155 TODO: improve pessimistic handling of precise exceptions
156 in the tree builder.
157
sewardjfb44d552004-10-25 09:48:47 +0000158 TODO: check interaction of rGetI and dirty helpers.
sewardjc0b42282004-10-12 13:44:12 +0000159
160 F64i constants are treated differently from other constants.
161 They are not regarded as atoms, and instead lifted off and
162 bound to temps. This allows them to participate in CSE, which
163 is important for getting good performance for x86 guest code.
sewardj695cff92004-10-13 14:50:14 +0000164
sewardja5aa9cf2004-10-15 22:56:38 +0000165 CSE up F64 literals (already doing F64is)
sewardj4c5f6d52004-10-26 13:25:33 +0000166
167 CSE: consider carefully the requirement for precise exns
sewardj98430292004-12-29 17:34:50 +0000168 prior to making CSE any more aggressive. */
sewardjc0b42282004-10-12 13:44:12 +0000169
170
sewardja1a370f2004-08-17 13:31:55 +0000171/*---------------------------------------------------------------*/
172/*--- Finite mappery, of a sort ---*/
173/*---------------------------------------------------------------*/
174
sewardj08210532004-12-29 17:09:11 +0000175/* General map from HWord-sized thing HWord-sized thing. Could be by
176 hashing, but it's not clear whether or not this would really be any
177 faster. */
sewardja1a370f2004-08-17 13:31:55 +0000178
179typedef
180 struct {
181 Bool* inuse;
sewardjea602bc2004-10-14 21:40:12 +0000182 HWord* key;
183 HWord* val;
sewardja1a370f2004-08-17 13:31:55 +0000184 Int size;
185 Int used;
186 }
sewardjea602bc2004-10-14 21:40:12 +0000187 HashHW;
sewardja1a370f2004-08-17 13:31:55 +0000188
sewardjea602bc2004-10-14 21:40:12 +0000189static HashHW* newHHW ( void )
sewardja1a370f2004-08-17 13:31:55 +0000190{
sewardjea602bc2004-10-14 21:40:12 +0000191 HashHW* h = LibVEX_Alloc(sizeof(HashHW));
sewardj29632392004-08-22 02:38:11 +0000192 h->size = 8;
sewardja1a370f2004-08-17 13:31:55 +0000193 h->used = 0;
194 h->inuse = LibVEX_Alloc(h->size * sizeof(Bool));
sewardjea602bc2004-10-14 21:40:12 +0000195 h->key = LibVEX_Alloc(h->size * sizeof(HWord));
196 h->val = LibVEX_Alloc(h->size * sizeof(HWord));
sewardja1a370f2004-08-17 13:31:55 +0000197 return h;
198}
199
200
sewardj84be7372004-08-18 13:59:33 +0000201/* Look up key in the map. */
sewardja1a370f2004-08-17 13:31:55 +0000202
sewardjea602bc2004-10-14 21:40:12 +0000203static Bool lookupHHW ( HashHW* h, /*OUT*/HWord* val, HWord key )
sewardja1a370f2004-08-17 13:31:55 +0000204{
205 Int i;
sewardj08210532004-12-29 17:09:11 +0000206 /* vex_printf("lookupHHW(%llx)\n", key ); */
sewardja1a370f2004-08-17 13:31:55 +0000207 for (i = 0; i < h->used; i++) {
208 if (h->inuse[i] && h->key[i] == key) {
sewardj39e3f242004-08-18 16:54:52 +0000209 if (val)
210 *val = h->val[i];
sewardja1a370f2004-08-17 13:31:55 +0000211 return True;
212 }
213 }
214 return False;
215}
216
217
sewardja1a370f2004-08-17 13:31:55 +0000218/* Add key->val to the map. Replaces any existing binding for key. */
219
sewardjea602bc2004-10-14 21:40:12 +0000220static void addToHHW ( HashHW* h, HWord key, HWord val )
sewardja1a370f2004-08-17 13:31:55 +0000221{
222 Int i, j;
sewardj08210532004-12-29 17:09:11 +0000223 /* vex_printf("addToHHW(%llx, %llx)\n", key, val); */
sewardja1a370f2004-08-17 13:31:55 +0000224
225 /* Find and replace existing binding, if any. */
226 for (i = 0; i < h->used; i++) {
227 if (h->inuse[i] && h->key[i] == key) {
228 h->val[i] = val;
229 return;
230 }
231 }
232
233 /* Ensure a space is available. */
234 if (h->used == h->size) {
235 /* Copy into arrays twice the size. */
236 Bool* inuse2 = LibVEX_Alloc(2 * h->size * sizeof(Bool));
sewardjea602bc2004-10-14 21:40:12 +0000237 HWord* key2 = LibVEX_Alloc(2 * h->size * sizeof(HWord));
238 HWord* val2 = LibVEX_Alloc(2 * h->size * sizeof(HWord));
sewardja1a370f2004-08-17 13:31:55 +0000239 for (i = j = 0; i < h->size; i++) {
240 if (!h->inuse[i]) continue;
241 inuse2[j] = True;
242 key2[j] = h->key[i];
243 val2[j] = h->val[i];
244 j++;
245 }
246 h->used = j;
247 h->size *= 2;
248 h->inuse = inuse2;
249 h->key = key2;
250 h->val = val2;
251 }
252
253 /* Finally, add it. */
254 vassert(h->used < h->size);
255 h->inuse[h->used] = True;
256 h->key[h->used] = key;
sewardj84be7372004-08-18 13:59:33 +0000257 h->val[h->used] = val;
sewardja1a370f2004-08-17 13:31:55 +0000258 h->used++;
259}
260
sewardj84be7372004-08-18 13:59:33 +0000261
sewardjd7cb8532004-08-17 23:59:23 +0000262/*---------------------------------------------------------------*/
sewardj08210532004-12-29 17:09:11 +0000263/*--- Flattening out a BB into atomic SSA form ---*/
sewardjd7cb8532004-08-17 23:59:23 +0000264/*---------------------------------------------------------------*/
265
sewardje80679a2004-09-21 23:00:11 +0000266/* Non-critical helper, heuristic for reducing the number of tmp-tmp
267 copies made by flattening. If in doubt return False. */
268
269static Bool isFlat ( IRExpr* e )
270{
sewardj695cff92004-10-13 14:50:14 +0000271 if (e->tag == Iex_Get)
272 return True;
sewardje80679a2004-09-21 23:00:11 +0000273 if (e->tag == Iex_Binop)
sewardj496a58d2005-03-20 18:44:44 +0000274 return toBool( isIRAtom(e->Iex.Binop.arg1)
275 && isIRAtom(e->Iex.Binop.arg2) );
sewardjaf1ceca2005-06-30 23:31:27 +0000276 if (e->tag == Iex_Load)
277 return isIRAtom(e->Iex.Load.addr);
sewardje80679a2004-09-21 23:00:11 +0000278 return False;
279}
280
sewardjd7cb8532004-08-17 23:59:23 +0000281/* Flatten out 'ex' so it is atomic, returning a new expression with
282 the same value, after having appended extra IRTemp assignments to
283 the end of 'bb'. */
284
sewardjdd40fdf2006-12-24 02:20:24 +0000285static IRExpr* flatten_Expr ( IRSB* bb, IRExpr* ex )
sewardjd7cb8532004-08-17 23:59:23 +0000286{
287 Int i;
288 IRExpr** newargs;
289 IRType ty = typeOfIRExpr(bb->tyenv, ex);
290 IRTemp t1;
291
292 switch (ex->tag) {
293
sewardjd7217032004-08-19 10:49:10 +0000294 case Iex_GetI:
295 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000296 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardj2d3f77c2004-09-22 23:49:09 +0000297 IRExpr_GetI(ex->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +0000298 flatten_Expr(bb, ex->Iex.GetI.ix),
sewardj2d3f77c2004-09-22 23:49:09 +0000299 ex->Iex.GetI.bias)));
sewardjdd40fdf2006-12-24 02:20:24 +0000300 return IRExpr_RdTmp(t1);
sewardjd7217032004-08-19 10:49:10 +0000301
sewardjd7cb8532004-08-17 23:59:23 +0000302 case Iex_Get:
303 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000304 addStmtToIRSB(bb,
305 IRStmt_WrTmp(t1, ex));
306 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000307
florian96d7cc32012-06-01 20:41:24 +0000308 case Iex_Qop: {
309 IRQop* qop = ex->Iex.Qop.details;
sewardj40c80262006-02-08 19:30:46 +0000310 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000311 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
florian96d7cc32012-06-01 20:41:24 +0000312 IRExpr_Qop(qop->op,
313 flatten_Expr(bb, qop->arg1),
314 flatten_Expr(bb, qop->arg2),
315 flatten_Expr(bb, qop->arg3),
316 flatten_Expr(bb, qop->arg4))));
sewardjdd40fdf2006-12-24 02:20:24 +0000317 return IRExpr_RdTmp(t1);
florian96d7cc32012-06-01 20:41:24 +0000318 }
sewardj40c80262006-02-08 19:30:46 +0000319
florian420bfa92012-06-02 20:29:22 +0000320 case Iex_Triop: {
321 IRTriop* triop = ex->Iex.Triop.details;
sewardjb183b852006-02-03 16:08:03 +0000322 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000323 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
florian420bfa92012-06-02 20:29:22 +0000324 IRExpr_Triop(triop->op,
325 flatten_Expr(bb, triop->arg1),
326 flatten_Expr(bb, triop->arg2),
327 flatten_Expr(bb, triop->arg3))));
sewardjdd40fdf2006-12-24 02:20:24 +0000328 return IRExpr_RdTmp(t1);
florian420bfa92012-06-02 20:29:22 +0000329 }
sewardjb183b852006-02-03 16:08:03 +0000330
sewardjd7cb8532004-08-17 23:59:23 +0000331 case Iex_Binop:
332 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000333 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjd7cb8532004-08-17 23:59:23 +0000334 IRExpr_Binop(ex->Iex.Binop.op,
335 flatten_Expr(bb, ex->Iex.Binop.arg1),
336 flatten_Expr(bb, ex->Iex.Binop.arg2))));
sewardjdd40fdf2006-12-24 02:20:24 +0000337 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000338
339 case Iex_Unop:
340 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000341 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjd7cb8532004-08-17 23:59:23 +0000342 IRExpr_Unop(ex->Iex.Unop.op,
343 flatten_Expr(bb, ex->Iex.Unop.arg))));
sewardjdd40fdf2006-12-24 02:20:24 +0000344 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000345
sewardjaf1ceca2005-06-30 23:31:27 +0000346 case Iex_Load:
sewardjd7cb8532004-08-17 23:59:23 +0000347 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000348 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardje768e922009-11-26 17:17:37 +0000349 IRExpr_Load(ex->Iex.Load.end,
sewardjaf1ceca2005-06-30 23:31:27 +0000350 ex->Iex.Load.ty,
351 flatten_Expr(bb, ex->Iex.Load.addr))));
sewardjdd40fdf2006-12-24 02:20:24 +0000352 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000353
354 case Iex_CCall:
sewardjdd40fdf2006-12-24 02:20:24 +0000355 newargs = shallowCopyIRExprVec(ex->Iex.CCall.args);
sewardjd7cb8532004-08-17 23:59:23 +0000356 for (i = 0; newargs[i]; i++)
357 newargs[i] = flatten_Expr(bb, newargs[i]);
358 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000359 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardj8ea867b2004-10-30 19:03:02 +0000360 IRExpr_CCall(ex->Iex.CCall.cee,
sewardjd7cb8532004-08-17 23:59:23 +0000361 ex->Iex.CCall.retty,
362 newargs)));
sewardjdd40fdf2006-12-24 02:20:24 +0000363 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000364
365 case Iex_Mux0X:
366 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000367 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjd7cb8532004-08-17 23:59:23 +0000368 IRExpr_Mux0X(flatten_Expr(bb, ex->Iex.Mux0X.cond),
369 flatten_Expr(bb, ex->Iex.Mux0X.expr0),
370 flatten_Expr(bb, ex->Iex.Mux0X.exprX))));
sewardjdd40fdf2006-12-24 02:20:24 +0000371 return IRExpr_RdTmp(t1);
sewardjd7cb8532004-08-17 23:59:23 +0000372
373 case Iex_Const:
sewardjc0b42282004-10-12 13:44:12 +0000374 /* Lift F64i constants out onto temps so they can be CSEd
375 later. */
376 if (ex->Iex.Const.con->tag == Ico_F64i) {
377 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000378 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
sewardjc0b42282004-10-12 13:44:12 +0000379 IRExpr_Const(ex->Iex.Const.con)));
sewardjdd40fdf2006-12-24 02:20:24 +0000380 return IRExpr_RdTmp(t1);
sewardjc0b42282004-10-12 13:44:12 +0000381 } else {
382 /* Leave all other constants alone. */
383 return ex;
384 }
385
sewardjdd40fdf2006-12-24 02:20:24 +0000386 case Iex_RdTmp:
sewardjd7cb8532004-08-17 23:59:23 +0000387 return ex;
388
389 default:
390 vex_printf("\n");
391 ppIRExpr(ex);
392 vex_printf("\n");
393 vpanic("flatten_Expr");
394 }
395}
396
397
398/* Append a completely flattened form of 'st' to the end of 'bb'. */
399
sewardjdd40fdf2006-12-24 02:20:24 +0000400static void flatten_Stmt ( IRSB* bb, IRStmt* st )
sewardjd7cb8532004-08-17 23:59:23 +0000401{
sewardj17442fe2004-09-20 14:54:28 +0000402 Int i;
sewardje9d8a262009-07-01 08:06:34 +0000403 IRExpr *e1, *e2, *e3, *e4, *e5;
sewardj17442fe2004-09-20 14:54:28 +0000404 IRDirty *d, *d2;
sewardje9d8a262009-07-01 08:06:34 +0000405 IRCAS *cas, *cas2;
floriand6f38b32012-05-31 15:46:18 +0000406 IRPutI *puti, *puti2;
sewardjd7cb8532004-08-17 23:59:23 +0000407 switch (st->tag) {
408 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +0000409 if (isIRAtom(st->Ist.Put.data)) {
sewardj49651f42004-10-28 22:11:04 +0000410 /* optimisation to reduce the amount of heap wasted
411 by the flattener */
sewardjdd40fdf2006-12-24 02:20:24 +0000412 addStmtToIRSB(bb, st);
sewardj49651f42004-10-28 22:11:04 +0000413 } else {
414 /* general case, always correct */
415 e1 = flatten_Expr(bb, st->Ist.Put.data);
sewardjdd40fdf2006-12-24 02:20:24 +0000416 addStmtToIRSB(bb, IRStmt_Put(st->Ist.Put.offset, e1));
sewardj49651f42004-10-28 22:11:04 +0000417 }
sewardjd7cb8532004-08-17 23:59:23 +0000418 break;
sewardjd7cb8532004-08-17 23:59:23 +0000419 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +0000420 puti = st->Ist.PutI.details;
421 e1 = flatten_Expr(bb, puti->ix);
422 e2 = flatten_Expr(bb, puti->data);
423 puti2 = mkIRPutI(puti->descr, e1, puti->bias, e2);
424 addStmtToIRSB(bb, IRStmt_PutI(puti2));
sewardjd7217032004-08-19 10:49:10 +0000425 break;
sewardjdd40fdf2006-12-24 02:20:24 +0000426 case Ist_WrTmp:
427 if (isFlat(st->Ist.WrTmp.data)) {
sewardje80679a2004-09-21 23:00:11 +0000428 /* optimisation, to reduce the number of tmp-tmp
429 copies generated */
sewardjdd40fdf2006-12-24 02:20:24 +0000430 addStmtToIRSB(bb, st);
sewardje80679a2004-09-21 23:00:11 +0000431 } else {
432 /* general case, always correct */
sewardjdd40fdf2006-12-24 02:20:24 +0000433 e1 = flatten_Expr(bb, st->Ist.WrTmp.data);
434 addStmtToIRSB(bb, IRStmt_WrTmp(st->Ist.WrTmp.tmp, e1));
sewardje80679a2004-09-21 23:00:11 +0000435 }
sewardjd7cb8532004-08-17 23:59:23 +0000436 break;
sewardjaf1ceca2005-06-30 23:31:27 +0000437 case Ist_Store:
438 e1 = flatten_Expr(bb, st->Ist.Store.addr);
439 e2 = flatten_Expr(bb, st->Ist.Store.data);
sewardje768e922009-11-26 17:17:37 +0000440 addStmtToIRSB(bb, IRStmt_Store(st->Ist.Store.end, e1,e2));
sewardje9d8a262009-07-01 08:06:34 +0000441 break;
442 case Ist_CAS:
443 cas = st->Ist.CAS.details;
444 e1 = flatten_Expr(bb, cas->addr);
445 e2 = cas->expdHi ? flatten_Expr(bb, cas->expdHi) : NULL;
446 e3 = flatten_Expr(bb, cas->expdLo);
447 e4 = cas->dataHi ? flatten_Expr(bb, cas->dataHi) : NULL;
448 e5 = flatten_Expr(bb, cas->dataLo);
449 cas2 = mkIRCAS( cas->oldHi, cas->oldLo, cas->end,
450 e1, e2, e3, e4, e5 );
451 addStmtToIRSB(bb, IRStmt_CAS(cas2));
sewardjd7cb8532004-08-17 23:59:23 +0000452 break;
sewardje768e922009-11-26 17:17:37 +0000453 case Ist_LLSC:
454 e1 = flatten_Expr(bb, st->Ist.LLSC.addr);
455 e2 = st->Ist.LLSC.storedata
456 ? flatten_Expr(bb, st->Ist.LLSC.storedata)
457 : NULL;
458 addStmtToIRSB(bb, IRStmt_LLSC(st->Ist.LLSC.end,
459 st->Ist.LLSC.result, e1, e2));
460 break;
sewardj17442fe2004-09-20 14:54:28 +0000461 case Ist_Dirty:
462 d = st->Ist.Dirty.details;
463 d2 = emptyIRDirty();
464 *d2 = *d;
sewardjdd40fdf2006-12-24 02:20:24 +0000465 d2->args = shallowCopyIRExprVec(d2->args);
sewardj17442fe2004-09-20 14:54:28 +0000466 if (d2->mFx != Ifx_None) {
467 d2->mAddr = flatten_Expr(bb, d2->mAddr);
468 } else {
469 vassert(d2->mAddr == NULL);
470 }
sewardjb8385d82004-11-02 01:34:15 +0000471 d2->guard = flatten_Expr(bb, d2->guard);
sewardj17442fe2004-09-20 14:54:28 +0000472 for (i = 0; d2->args[i]; i++)
473 d2->args[i] = flatten_Expr(bb, d2->args[i]);
sewardjdd40fdf2006-12-24 02:20:24 +0000474 addStmtToIRSB(bb, IRStmt_Dirty(d2));
sewardj17442fe2004-09-20 14:54:28 +0000475 break;
sewardjd2445f62005-03-21 00:15:53 +0000476 case Ist_NoOp:
sewardjc4356f02007-11-09 21:15:04 +0000477 case Ist_MBE:
sewardjd2445f62005-03-21 00:15:53 +0000478 case Ist_IMark:
sewardjdd40fdf2006-12-24 02:20:24 +0000479 addStmtToIRSB(bb, st);
sewardj3e838932005-01-07 12:09:15 +0000480 break;
sewardj5a9ffab2005-05-12 17:55:01 +0000481 case Ist_AbiHint:
482 e1 = flatten_Expr(bb, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +0000483 e2 = flatten_Expr(bb, st->Ist.AbiHint.nia);
484 addStmtToIRSB(bb, IRStmt_AbiHint(e1, st->Ist.AbiHint.len, e2));
sewardj5a9ffab2005-05-12 17:55:01 +0000485 break;
sewardjd7cb8532004-08-17 23:59:23 +0000486 case Ist_Exit:
sewardj0276d4b2004-11-15 15:30:21 +0000487 e1 = flatten_Expr(bb, st->Ist.Exit.guard);
sewardjdd40fdf2006-12-24 02:20:24 +0000488 addStmtToIRSB(bb, IRStmt_Exit(e1, st->Ist.Exit.jk,
sewardjc6f970f2012-04-02 21:54:49 +0000489 st->Ist.Exit.dst,
490 st->Ist.Exit.offsIP));
sewardjd7cb8532004-08-17 23:59:23 +0000491 break;
492 default:
493 vex_printf("\n");
494 ppIRStmt(st);
495 vex_printf("\n");
496 vpanic("flatten_Stmt");
497 }
498}
499
sewardj08210532004-12-29 17:09:11 +0000500
sewardjdd40fdf2006-12-24 02:20:24 +0000501static IRSB* flatten_BB ( IRSB* in )
sewardjd7cb8532004-08-17 23:59:23 +0000502{
503 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +0000504 IRSB* out;
505 out = emptyIRSB();
506 out->tyenv = deepCopyIRTypeEnv( in->tyenv );
sewardjd7cb8532004-08-17 23:59:23 +0000507 for (i = 0; i < in->stmts_used; i++)
sewardj4345f7a2004-09-22 19:49:27 +0000508 if (in->stmts[i])
509 flatten_Stmt( out, in->stmts[i] );
sewardjd7cb8532004-08-17 23:59:23 +0000510 out->next = flatten_Expr( out, in->next );
511 out->jumpkind = in->jumpkind;
sewardjc6f970f2012-04-02 21:54:49 +0000512 out->offsIP = in->offsIP;
sewardjd7cb8532004-08-17 23:59:23 +0000513 return out;
514}
515
sewardjedf4d692004-08-17 13:52:58 +0000516
sewardj08210532004-12-29 17:09:11 +0000517/*---------------------------------------------------------------*/
518/*--- In-place removal of redundant GETs ---*/
519/*---------------------------------------------------------------*/
520
521/* Scan forwards, building up an environment binding (min offset, max
522 offset) pairs to values, which will either be temps or constants.
523
524 On seeing 't = Get(minoff,maxoff)', look up (minoff,maxoff) in the
525 env and if it matches, replace the Get with the stored value. If
526 there is no match, add a (minoff,maxoff) :-> t binding.
527
528 On seeing 'Put (minoff,maxoff) = t or c', first remove in the env
529 any binding which fully or partially overlaps with (minoff,maxoff).
530 Then add a new (minoff,maxoff) :-> t or c binding. */
531
532/* Extract the min/max offsets from a guest state array descriptor. */
533
534inline
sewardjdd40fdf2006-12-24 02:20:24 +0000535static void getArrayBounds ( IRRegArray* descr,
536 UInt* minoff, UInt* maxoff )
sewardj08210532004-12-29 17:09:11 +0000537{
538 *minoff = descr->base;
539 *maxoff = *minoff + descr->nElems*sizeofIRType(descr->elemTy) - 1;
540 vassert((*minoff & ~0xFFFF) == 0);
541 vassert((*maxoff & ~0xFFFF) == 0);
542 vassert(*minoff <= *maxoff);
543}
544
545/* Create keys, of the form ((minoffset << 16) | maxoffset). */
546
547static UInt mk_key_GetPut ( Int offset, IRType ty )
548{
549 /* offset should fit in 16 bits. */
550 UInt minoff = offset;
551 UInt maxoff = minoff + sizeofIRType(ty) - 1;
552 vassert((minoff & ~0xFFFF) == 0);
553 vassert((maxoff & ~0xFFFF) == 0);
554 return (minoff << 16) | maxoff;
555}
556
sewardjdd40fdf2006-12-24 02:20:24 +0000557static UInt mk_key_GetIPutI ( IRRegArray* descr )
sewardj08210532004-12-29 17:09:11 +0000558{
559 UInt minoff, maxoff;
560 getArrayBounds( descr, &minoff, &maxoff );
561 vassert((minoff & ~0xFFFF) == 0);
562 vassert((maxoff & ~0xFFFF) == 0);
563 return (minoff << 16) | maxoff;
564}
565
566/* Supposing h has keys of the form generated by mk_key_GetPut and
567 mk_key_GetIPutI, invalidate any key which overlaps (k_lo
568 .. k_hi).
569*/
570static void invalidateOverlaps ( HashHW* h, UInt k_lo, UInt k_hi )
571{
572 Int j;
573 UInt e_lo, e_hi;
574 vassert(k_lo <= k_hi);
575 /* invalidate any env entries which in any way overlap (k_lo
576 .. k_hi) */
577 /* vex_printf("invalidate %d .. %d\n", k_lo, k_hi ); */
578
579 for (j = 0; j < h->used; j++) {
580 if (!h->inuse[j])
581 continue;
582 e_lo = (((UInt)h->key[j]) >> 16) & 0xFFFF;
583 e_hi = ((UInt)h->key[j]) & 0xFFFF;
584 vassert(e_lo <= e_hi);
585 if (e_hi < k_lo || k_hi < e_lo)
586 continue; /* no overlap possible */
587 else
588 /* overlap; invalidate */
589 h->inuse[j] = False;
590 }
591}
592
593
sewardjdd40fdf2006-12-24 02:20:24 +0000594static void redundant_get_removal_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +0000595{
596 HashHW* env = newHHW();
597 UInt key = 0; /* keep gcc -O happy */
598 Int i, j;
599 HWord val;
600
601 for (i = 0; i < bb->stmts_used; i++) {
602 IRStmt* st = bb->stmts[i];
603
sewardj8bee6d12005-03-22 02:24:05 +0000604 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +0000605 continue;
606
607 /* Deal with Gets */
sewardjdd40fdf2006-12-24 02:20:24 +0000608 if (st->tag == Ist_WrTmp
609 && st->Ist.WrTmp.data->tag == Iex_Get) {
sewardj08210532004-12-29 17:09:11 +0000610 /* st is 't = Get(...)'. Look up in the environment and see
611 if the Get can be replaced. */
sewardjdd40fdf2006-12-24 02:20:24 +0000612 IRExpr* get = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +0000613 key = (HWord)mk_key_GetPut( get->Iex.Get.offset,
614 get->Iex.Get.ty );
615 if (lookupHHW(env, &val, (HWord)key)) {
616 /* found it */
617 /* Note, we could do better here. If the types are
618 different we don't do the substitution, since doing so
619 could lead to invalidly-typed IR. An improvement would
620 be to stick in a reinterpret-style cast, although that
621 would make maintaining flatness more difficult. */
622 IRExpr* valE = (IRExpr*)val;
sewardj9d2e7692005-02-07 01:11:31 +0000623 Bool typesOK = toBool( typeOfIRExpr(bb->tyenv,valE)
sewardjdd40fdf2006-12-24 02:20:24 +0000624 == st->Ist.WrTmp.data->Iex.Get.ty );
sewardj08210532004-12-29 17:09:11 +0000625 if (typesOK && DEBUG_IROPT) {
626 vex_printf("rGET: "); ppIRExpr(get);
627 vex_printf(" -> "); ppIRExpr(valE);
628 vex_printf("\n");
629 }
630 if (typesOK)
sewardjdd40fdf2006-12-24 02:20:24 +0000631 bb->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, valE);
sewardj08210532004-12-29 17:09:11 +0000632 } else {
633 /* Not found, but at least we know that t and the Get(...)
634 are now associated. So add a binding to reflect that
635 fact. */
636 addToHHW( env, (HWord)key,
sewardjdd40fdf2006-12-24 02:20:24 +0000637 (HWord)(void*)(IRExpr_RdTmp(st->Ist.WrTmp.tmp)) );
sewardj08210532004-12-29 17:09:11 +0000638 }
639 }
640
641 /* Deal with Puts: invalidate any env entries overlapped by this
642 Put */
643 if (st->tag == Ist_Put || st->tag == Ist_PutI) {
644 UInt k_lo, k_hi;
645 if (st->tag == Ist_Put) {
646 key = mk_key_GetPut( st->Ist.Put.offset,
647 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
648 } else {
649 vassert(st->tag == Ist_PutI);
floriand6f38b32012-05-31 15:46:18 +0000650 key = mk_key_GetIPutI( st->Ist.PutI.details->descr );
sewardj08210532004-12-29 17:09:11 +0000651 }
652
653 k_lo = (key >> 16) & 0xFFFF;
654 k_hi = key & 0xFFFF;
655 invalidateOverlaps(env, k_lo, k_hi);
656 }
657 else
658 if (st->tag == Ist_Dirty) {
659 /* Deal with dirty helpers which write or modify guest state.
660 Invalidate the entire env. We could do a lot better
661 here. */
662 IRDirty* d = st->Ist.Dirty.details;
663 Bool writes = False;
664 for (j = 0; j < d->nFxState; j++) {
665 if (d->fxState[j].fx == Ifx_Modify
666 || d->fxState[j].fx == Ifx_Write)
667 writes = True;
668 }
669 if (writes) {
670 /* dump the entire env (not clever, but correct ...) */
671 for (j = 0; j < env->used; j++)
672 env->inuse[j] = False;
673 if (0) vex_printf("rGET: trash env due to dirty helper\n");
674 }
675 }
676
677 /* add this one to the env, if appropriate */
678 if (st->tag == Ist_Put) {
sewardj496a58d2005-03-20 18:44:44 +0000679 vassert(isIRAtom(st->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +0000680 addToHHW( env, (HWord)key, (HWord)(st->Ist.Put.data));
681 }
682
683 } /* for (i = 0; i < bb->stmts_used; i++) */
684
685}
686
687
688/*---------------------------------------------------------------*/
689/*--- In-place removal of redundant PUTs ---*/
690/*---------------------------------------------------------------*/
691
692/* Find any Get uses in st and invalidate any partially or fully
693 overlapping ranges listed in env. Due to the flattening phase, the
sewardjdd40fdf2006-12-24 02:20:24 +0000694 only stmt kind we expect to find a Get on is IRStmt_WrTmp. */
sewardj08210532004-12-29 17:09:11 +0000695
696static void handle_gets_Stmt (
697 HashHW* env,
698 IRStmt* st,
699 Bool (*preciseMemExnsFn)(Int,Int)
700 )
701{
702 Int j;
703 UInt key = 0; /* keep gcc -O happy */
704 Bool isGet;
705 Bool memRW = False;
706 IRExpr* e;
707
708 switch (st->tag) {
709
710 /* This is the only interesting case. Deal with Gets in the RHS
711 expression. */
sewardjdd40fdf2006-12-24 02:20:24 +0000712 case Ist_WrTmp:
713 e = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +0000714 switch (e->tag) {
715 case Iex_Get:
716 isGet = True;
717 key = mk_key_GetPut ( e->Iex.Get.offset, e->Iex.Get.ty );
718 break;
719 case Iex_GetI:
720 isGet = True;
721 key = mk_key_GetIPutI ( e->Iex.GetI.descr );
722 break;
sewardjaf1ceca2005-06-30 23:31:27 +0000723 case Iex_Load:
sewardj08210532004-12-29 17:09:11 +0000724 isGet = False;
725 memRW = True;
726 break;
727 default:
728 isGet = False;
729 }
730 if (isGet) {
731 UInt k_lo, k_hi;
732 k_lo = (key >> 16) & 0xFFFF;
733 k_hi = key & 0xFFFF;
734 invalidateOverlaps(env, k_lo, k_hi);
735 }
736 break;
737
738 /* Be very conservative for dirty helper calls; dump the entire
739 environment. The helper might read guest state, in which
740 case it needs to be flushed first. Also, the helper might
741 access guest memory, in which case all parts of the guest
742 state requiring precise exceptions needs to be flushed. The
743 crude solution is just to flush everything; we could easily
744 enough do a lot better if needed. */
sewardj3e838932005-01-07 12:09:15 +0000745 /* Probably also overly-conservative, but also dump everything
sewardjc4356f02007-11-09 21:15:04 +0000746 if we hit a memory bus event (fence, lock, unlock). Ditto
sewardje768e922009-11-26 17:17:37 +0000747 AbiHints, CASs, LLs and SCs. */
sewardj5a9ffab2005-05-12 17:55:01 +0000748 case Ist_AbiHint:
749 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +0000750 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +0000751 /* fall through */
sewardjc4356f02007-11-09 21:15:04 +0000752 case Ist_MBE:
sewardj08210532004-12-29 17:09:11 +0000753 case Ist_Dirty:
sewardje9d8a262009-07-01 08:06:34 +0000754 case Ist_CAS:
sewardje768e922009-11-26 17:17:37 +0000755 case Ist_LLSC:
sewardj08210532004-12-29 17:09:11 +0000756 for (j = 0; j < env->used; j++)
757 env->inuse[j] = False;
758 break;
759
760 /* all other cases are boring. */
sewardjaf1ceca2005-06-30 23:31:27 +0000761 case Ist_Store:
762 vassert(isIRAtom(st->Ist.Store.addr));
763 vassert(isIRAtom(st->Ist.Store.data));
sewardj08210532004-12-29 17:09:11 +0000764 memRW = True;
765 break;
766
767 case Ist_Exit:
sewardj496a58d2005-03-20 18:44:44 +0000768 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +0000769 break;
770
771 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +0000772 vassert(isIRAtom(st->Ist.PutI.details->ix));
773 vassert(isIRAtom(st->Ist.PutI.details->data));
sewardj08210532004-12-29 17:09:11 +0000774 break;
775
sewardjd2445f62005-03-21 00:15:53 +0000776 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +0000777 case Ist_IMark:
778 break;
779
sewardj08210532004-12-29 17:09:11 +0000780 default:
781 vex_printf("\n");
782 ppIRStmt(st);
783 vex_printf("\n");
784 vpanic("handle_gets_Stmt");
785 }
786
787 if (memRW) {
philippe6c46bef2012-08-14 22:29:01 +0000788 /* This statement accesses memory. So we might need to dump all parts
sewardj08210532004-12-29 17:09:11 +0000789 of the environment corresponding to guest state that may not
790 be reordered with respect to memory references. That means
791 at least the stack pointer. */
philippec8e2f982012-08-01 22:04:13 +0000792 switch (vex_control.iropt_register_updates) {
793 case VexRegUpdAllregsAtMemAccess:
794 /* Precise exceptions required at mem access.
795 Flush all guest state. */
796 for (j = 0; j < env->used; j++)
sewardj08210532004-12-29 17:09:11 +0000797 env->inuse[j] = False;
philippec8e2f982012-08-01 22:04:13 +0000798 break;
philippe6c46bef2012-08-14 22:29:01 +0000799 case VexRegUpdSpAtMemAccess:
800 /* We need to dump the stack pointer
801 (needed for stack extension in m_signals.c).
802 preciseMemExnsFn will use vex_control.iropt_register_updates
803 to verify only the sp is to be checked. */
804 /* fallthrough */
philippec8e2f982012-08-01 22:04:13 +0000805 case VexRegUpdUnwindregsAtMemAccess:
806 for (j = 0; j < env->used; j++) {
807 if (!env->inuse[j])
808 continue;
809 /* Just flush the minimal amount required, as computed by
810 preciseMemExnsFn. */
811 HWord k_lo = (env->key[j] >> 16) & 0xFFFF;
812 HWord k_hi = env->key[j] & 0xFFFF;
813 if (preciseMemExnsFn( k_lo, k_hi ))
814 env->inuse[j] = False;
815 }
816 break;
817 default:
818 // VexRegUpdAllregsAtEachInsn cannot happen here.
819 // Neither any rubbish other value.
820 vassert(0);
sewardj08210532004-12-29 17:09:11 +0000821 }
822 } /* if (memRW) */
823
824}
825
826
827/* Scan backwards, building up a set of (min offset, max
828 offset) pairs, indicating those parts of the guest state
829 for which the next event is a write.
830
831 On seeing a conditional exit, empty the set.
832
833 On seeing 'Put (minoff,maxoff) = t or c', if (minoff,maxoff) is
834 completely within the set, remove the Put. Otherwise, add
835 (minoff,maxoff) to the set.
836
837 On seeing 'Get (minoff,maxoff)', remove any part of the set
sewardj98430292004-12-29 17:34:50 +0000838 overlapping (minoff,maxoff). The same has to happen for any events
839 which implicitly read parts of the guest state: dirty helper calls
840 and loads/stores.
sewardj08210532004-12-29 17:09:11 +0000841*/
842
843static void redundant_put_removal_BB (
sewardjdd40fdf2006-12-24 02:20:24 +0000844 IRSB* bb,
sewardj08210532004-12-29 17:09:11 +0000845 Bool (*preciseMemExnsFn)(Int,Int)
846 )
847{
848 Int i, j;
849 Bool isPut;
850 IRStmt* st;
851 UInt key = 0; /* keep gcc -O happy */
852
philippe6c46bef2012-08-14 22:29:01 +0000853 vassert(vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn);
philippec8e2f982012-08-01 22:04:13 +0000854
sewardj08210532004-12-29 17:09:11 +0000855 HashHW* env = newHHW();
sewardjc6f970f2012-04-02 21:54:49 +0000856
857 /* Initialise the running env with the fact that the final exit
858 writes the IP (or, whatever it claims to write. We don't
859 care.) */
860 key = mk_key_GetPut(bb->offsIP, typeOfIRExpr(bb->tyenv, bb->next));
861 addToHHW(env, (HWord)key, 0);
862
863 /* And now scan backwards through the statements. */
sewardj08210532004-12-29 17:09:11 +0000864 for (i = bb->stmts_used-1; i >= 0; i--) {
865 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +0000866
867 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +0000868 continue;
869
870 /* Deal with conditional exits. */
871 if (st->tag == Ist_Exit) {
sewardjc6f970f2012-04-02 21:54:49 +0000872 //Bool re_add;
873 /* Need to throw out from the env, any part of it which
874 doesn't overlap with the guest state written by this exit.
875 Since the exit only writes one section, it's simplest to
876 do this: (1) check whether env contains a write that
877 completely overlaps the write done by this exit; (2) empty
878 out env; and (3) if (1) was true, add the write done by
879 this exit.
880
881 To make (1) a bit simpler, merely search for a write that
882 exactly matches the one done by this exit. That's safe
883 because it will fail as often or more often than a full
884 overlap check, and failure to find an overlapping write in
885 env is the safe case (we just nuke env if that
886 happens). */
887 //vassert(isIRAtom(st->Ist.Exit.guard));
888 /* (1) */
889 //key = mk_key_GetPut(st->Ist.Exit.offsIP,
890 // typeOfIRConst(st->Ist.Exit.dst));
891 //re_add = lookupHHW(env, NULL, key);
892 /* (2) */
sewardj08210532004-12-29 17:09:11 +0000893 for (j = 0; j < env->used; j++)
894 env->inuse[j] = False;
sewardjc6f970f2012-04-02 21:54:49 +0000895 /* (3) */
896 //if (0 && re_add)
897 // addToHHW(env, (HWord)key, 0);
sewardj08210532004-12-29 17:09:11 +0000898 continue;
899 }
900
901 /* Deal with Puts */
902 switch (st->tag) {
903 case Ist_Put:
904 isPut = True;
905 key = mk_key_GetPut( st->Ist.Put.offset,
906 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
sewardj496a58d2005-03-20 18:44:44 +0000907 vassert(isIRAtom(st->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +0000908 break;
909 case Ist_PutI:
910 isPut = True;
floriand6f38b32012-05-31 15:46:18 +0000911 key = mk_key_GetIPutI( st->Ist.PutI.details->descr );
912 vassert(isIRAtom(st->Ist.PutI.details->ix));
913 vassert(isIRAtom(st->Ist.PutI.details->data));
sewardj08210532004-12-29 17:09:11 +0000914 break;
915 default:
916 isPut = False;
917 }
918 if (isPut && st->tag != Ist_PutI) {
919 /* See if any single entry in env overlaps this Put. This is
920 simplistic in that the transformation is valid if, say, two
921 or more entries in the env overlap this Put, but the use of
922 lookupHHW will only find a single entry which exactly
923 overlaps this Put. This is suboptimal but safe. */
924 if (lookupHHW(env, NULL, (HWord)key)) {
925 /* This Put is redundant because a later one will overwrite
926 it. So NULL (nop) it out. */
927 if (DEBUG_IROPT) {
928 vex_printf("rPUT: "); ppIRStmt(st);
929 vex_printf("\n");
930 }
sewardjd2445f62005-03-21 00:15:53 +0000931 bb->stmts[i] = IRStmt_NoOp();
sewardj08210532004-12-29 17:09:11 +0000932 } else {
933 /* We can't demonstrate that this Put is redundant, so add it
934 to the running collection. */
935 addToHHW(env, (HWord)key, 0);
936 }
937 continue;
938 }
939
940 /* Deal with Gets. These remove bits of the environment since
941 appearance of a Get means that the next event for that slice
sewardj98430292004-12-29 17:34:50 +0000942 of the guest state is no longer a write, but a read. Also
943 deals with implicit reads of guest state needed to maintain
944 precise exceptions. */
sewardj08210532004-12-29 17:09:11 +0000945 handle_gets_Stmt( env, st, preciseMemExnsFn );
946 }
947}
948
sewardj84be7372004-08-18 13:59:33 +0000949
950/*---------------------------------------------------------------*/
951/*--- Constant propagation and folding ---*/
952/*---------------------------------------------------------------*/
953
floriancdb5fee2012-02-13 00:06:29 +0000954#if STATS_IROPT
955/* How often sameIRExprs was invoked */
956static UInt invocation_count;
957/* How often sameIRExprs recursed through IRTemp assignments */
958static UInt recursion_count;
959/* How often sameIRExprs found identical IRExprs */
960static UInt success_count;
961/* How often recursing through assignments to IRTemps helped
962 establishing equality. */
963static UInt recursion_success_count;
964/* Whether or not recursing through an IRTemp assignment helped
965 establishing IRExpr equality for a given sameIRExprs invocation. */
966static Bool recursion_helped;
967/* Whether or not a given sameIRExprs invocation recursed through an
968 IRTemp assignment */
969static Bool recursed;
970/* Maximum number of nodes ever visited when comparing two IRExprs. */
971static UInt max_nodes_visited;
972#endif /* STATS_IROPT */
973
974/* Count the number of nodes visited for a given sameIRExprs invocation. */
975static UInt num_nodes_visited;
976
977/* Do not visit more than NODE_LIMIT nodes when comparing two IRExprs.
978 This is to guard against performance degradation by visiting large
979 trees without success. */
980#define NODE_LIMIT 30
981
982
sewardj62617ef2004-10-13 23:29:22 +0000983/* The env in this section is a map from IRTemp to IRExpr*,
984 that is, an array indexed by IRTemp. */
sewardjf6501992004-08-27 11:58:24 +0000985
floriancdb5fee2012-02-13 00:06:29 +0000986/* Do both expressions compute the same value? The answer is generally
987 conservative, i.e. it will report that the expressions do not compute
988 the same value when in fact they do. The reason is that we do not
989 keep track of changes in the guest state and memory. Thusly, two
990 Get's, GetI's or Load's, even when accessing the same location, will be
991 assumed to compute different values. After all the accesses may happen
992 at different times and the guest state / memory can have changed in
sewardja7e96382012-06-29 16:26:17 +0000993 the meantime.
994
995 XXX IMPORTANT XXX the two expressions must have the same IR type.
996 DO NOT CALL HERE WITH DIFFERENTLY-TYPED EXPRESSIONS. */
sewardjc6f970f2012-04-02 21:54:49 +0000997
998/* JRS 20-Mar-2012: split sameIRExprs_aux into a fast inlineable
999 wrapper that deals with the common tags-don't-match case, and a
1000 slower out of line general case. Saves a few insns. */
1001
1002__attribute__((noinline))
1003static Bool sameIRExprs_aux2 ( IRExpr** env, IRExpr* e1, IRExpr* e2 );
1004
1005inline
floriancdb5fee2012-02-13 00:06:29 +00001006static Bool sameIRExprs_aux ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
sewardjf6729012004-08-25 12:45:13 +00001007{
floriancdb5fee2012-02-13 00:06:29 +00001008 if (e1->tag != e2->tag) return False;
sewardjc6f970f2012-04-02 21:54:49 +00001009 return sameIRExprs_aux2(env, e1, e2);
1010}
sewardjf6729012004-08-25 12:45:13 +00001011
sewardjc6f970f2012-04-02 21:54:49 +00001012__attribute__((noinline))
1013static Bool sameIRExprs_aux2 ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
1014{
floriancdb5fee2012-02-13 00:06:29 +00001015 if (num_nodes_visited++ > NODE_LIMIT) return False;
sewardj6c299f32009-12-31 18:00:12 +00001016
sewardj6c299f32009-12-31 18:00:12 +00001017 switch (e1->tag) {
1018 case Iex_RdTmp:
floriancdb5fee2012-02-13 00:06:29 +00001019 if (e1->Iex.RdTmp.tmp == e2->Iex.RdTmp.tmp) return True;
1020
1021 if (env[e1->Iex.RdTmp.tmp] && env[e2->Iex.RdTmp.tmp]) {
1022 Bool same = sameIRExprs_aux(env, env[e1->Iex.RdTmp.tmp],
1023 env[e2->Iex.RdTmp.tmp]);
1024#if STATS_IROPT
1025 recursed = True;
1026 if (same) recursion_helped = True;
1027#endif
1028 return same;
1029 }
sewardj6c299f32009-12-31 18:00:12 +00001030 return False;
floriancdb5fee2012-02-13 00:06:29 +00001031
1032 case Iex_Get:
1033 case Iex_GetI:
1034 case Iex_Load:
1035 /* Guest state / memory could have changed in the meantime. */
1036 return False;
1037
1038 case Iex_Binop:
1039 return toBool( e1->Iex.Binop.op == e2->Iex.Binop.op
sewardj6399f812012-06-29 15:36:44 +00001040 && sameIRExprs_aux( env, e1->Iex.Binop.arg1,
1041 e2->Iex.Binop.arg1 )
1042 && sameIRExprs_aux( env, e1->Iex.Binop.arg2,
1043 e2->Iex.Binop.arg2 ));
floriancdb5fee2012-02-13 00:06:29 +00001044
1045 case Iex_Unop:
1046 return toBool( e1->Iex.Unop.op == e2->Iex.Unop.op
sewardj6399f812012-06-29 15:36:44 +00001047 && sameIRExprs_aux( env, e1->Iex.Unop.arg,
1048 e2->Iex.Unop.arg ));
floriancdb5fee2012-02-13 00:06:29 +00001049
1050 case Iex_Const: {
1051 IRConst *c1 = e1->Iex.Const.con;
1052 IRConst *c2 = e2->Iex.Const.con;
1053 vassert(c1->tag == c2->tag);
1054 switch (c1->tag) {
1055 case Ico_U1: return toBool( c1->Ico.U1 == c2->Ico.U1 );
1056 case Ico_U8: return toBool( c1->Ico.U8 == c2->Ico.U8 );
1057 case Ico_U16: return toBool( c1->Ico.U16 == c2->Ico.U16 );
1058 case Ico_U32: return toBool( c1->Ico.U32 == c2->Ico.U32 );
1059 case Ico_U64: return toBool( c1->Ico.U64 == c2->Ico.U64 );
1060 default: break;
1061 }
1062 return False;
1063 }
1064
florian420bfa92012-06-02 20:29:22 +00001065 case Iex_Triop: {
1066 IRTriop *tri1 = e1->Iex.Triop.details;
1067 IRTriop *tri2 = e2->Iex.Triop.details;
1068 return toBool( tri1->op == tri2->op
1069 && sameIRExprs_aux( env, tri1->arg1, tri2->arg1 )
1070 && sameIRExprs_aux( env, tri1->arg2, tri2->arg2 )
1071 && sameIRExprs_aux( env, tri1->arg3, tri2->arg3 ));
1072 }
floriancdb5fee2012-02-13 00:06:29 +00001073
1074 case Iex_Mux0X:
sewardj6399f812012-06-29 15:36:44 +00001075 return toBool( sameIRExprs_aux( env, e1->Iex.Mux0X.cond,
1076 e2->Iex.Mux0X.cond )
1077 && sameIRExprs_aux( env, e1->Iex.Mux0X.expr0,
1078 e2->Iex.Mux0X.expr0 )
1079 && sameIRExprs_aux( env, e1->Iex.Mux0X.exprX,
1080 e2->Iex.Mux0X.exprX ));
floriancdb5fee2012-02-13 00:06:29 +00001081
1082 default:
1083 /* Not very likely to be "same". */
1084 break;
sewardj6c299f32009-12-31 18:00:12 +00001085 }
floriancdb5fee2012-02-13 00:06:29 +00001086
1087 return False;
sewardj6c299f32009-12-31 18:00:12 +00001088}
1089
sewardjc6f970f2012-04-02 21:54:49 +00001090inline
floriancdb5fee2012-02-13 00:06:29 +00001091static Bool sameIRExprs ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
1092{
1093 Bool same;
1094
1095 num_nodes_visited = 0;
1096 same = sameIRExprs_aux(env, e1, e2);
1097
1098#if STATS_IROPT
1099 ++invocation_count;
1100 if (recursed) ++recursion_count;
1101 success_count += same;
1102 if (same && recursion_helped)
1103 ++recursion_success_count;
1104 if (num_nodes_visited > max_nodes_visited)
1105 max_nodes_visited = num_nodes_visited;
1106 recursed = False; /* reset */
1107 recursion_helped = False; /* reset */
1108#endif /* STATS_IROPT */
1109
1110 return same;
1111}
1112
1113
sewardja7e96382012-06-29 16:26:17 +00001114/* Debugging-only hack (not used in production runs): make a guess
1115 whether sameIRExprs might assert due to the two args being of
1116 different types. If in doubt return False. Is only used when
1117 --vex-iropt-level > 0, that is, vex_control.iropt_verbosity > 0.
1118 Bad because it duplicates functionality from typeOfIRExpr. See
1119 comment on the single use point below for rationale. */
1120static
1121Bool debug_only_hack_sameIRExprs_might_assert ( IRExpr* e1, IRExpr* e2 )
1122{
1123 if (e1->tag != e2->tag) return False;
1124 switch (e1->tag) {
1125 case Iex_Const: {
1126 /* The only interesting case */
1127 IRConst *c1 = e1->Iex.Const.con;
1128 IRConst *c2 = e2->Iex.Const.con;
1129 return c1->tag != c2->tag;
1130 }
1131 default:
1132 break;
1133 }
1134 return False;
1135}
1136
1137
florianea7eab72011-07-21 16:21:58 +00001138/* Is this literally IRExpr_Const(IRConst_U32(0)) ? */
1139static Bool isZeroU32 ( IRExpr* e )
1140{
1141 return toBool( e->tag == Iex_Const
1142 && e->Iex.Const.con->tag == Ico_U32
1143 && e->Iex.Const.con->Ico.U32 == 0);
1144}
1145
sewardjcf4be4a2012-03-26 09:44:39 +00001146/* Is this literally IRExpr_Const(IRConst_U32(1---1)) ? */
1147static Bool isOnesU32 ( IRExpr* e )
1148{
1149 return toBool( e->tag == Iex_Const
1150 && e->Iex.Const.con->tag == Ico_U32
1151 && e->Iex.Const.con->Ico.U32 == 0xFFFFFFFF );
1152}
1153
florianea7eab72011-07-21 16:21:58 +00001154/* Is this literally IRExpr_Const(IRConst_U64(0)) ? */
1155static Bool isZeroU64 ( IRExpr* e )
1156{
1157 return toBool( e->tag == Iex_Const
1158 && e->Iex.Const.con->tag == Ico_U64
1159 && e->Iex.Const.con->Ico.U64 == 0);
1160}
1161
florianf6402ab2012-01-29 02:19:43 +00001162/* Is this an integer constant with value 0 ? */
1163static Bool isZeroU ( IRExpr* e )
1164{
1165 if (e->tag != Iex_Const) return False;
florianf6402ab2012-01-29 02:19:43 +00001166 switch (e->Iex.Const.con->tag) {
1167 case Ico_U1: return toBool( e->Iex.Const.con->Ico.U1 == 0);
1168 case Ico_U8: return toBool( e->Iex.Const.con->Ico.U8 == 0);
1169 case Ico_U16: return toBool( e->Iex.Const.con->Ico.U16 == 0);
1170 case Ico_U32: return toBool( e->Iex.Const.con->Ico.U32 == 0);
1171 case Ico_U64: return toBool( e->Iex.Const.con->Ico.U64 == 0);
1172 default: vpanic("isZeroU");
1173 }
1174}
1175
sewardjcf4be4a2012-03-26 09:44:39 +00001176/* Is this an integer constant with value 1---1b ? */
1177static Bool isOnesU ( IRExpr* e )
1178{
1179 if (e->tag != Iex_Const) return False;
1180 switch (e->Iex.Const.con->tag) {
1181 case Ico_U8: return toBool( e->Iex.Const.con->Ico.U8 == 0xFF);
1182 case Ico_U16: return toBool( e->Iex.Const.con->Ico.U16 == 0xFFFF);
1183 case Ico_U32: return toBool( e->Iex.Const.con->Ico.U32
1184 == 0xFFFFFFFF);
1185 case Ico_U64: return toBool( e->Iex.Const.con->Ico.U64
1186 == 0xFFFFFFFFFFFFFFFFULL);
1187 default: ppIRExpr(e); vpanic("isOnesU");
1188 }
1189}
1190
sewardje1d45da2004-11-12 00:13:21 +00001191static Bool notBool ( Bool b )
1192{
1193 if (b == True) return False;
1194 if (b == False) return True;
1195 vpanic("notBool");
1196}
1197
sewardj0033ddc2005-04-26 23:34:34 +00001198/* Make a zero which has the same type as the result of the given
1199 primop. */
sewardj64d776c2010-10-01 14:06:22 +00001200static IRExpr* mkZeroOfPrimopResultType ( IROp op )
sewardj0033ddc2005-04-26 23:34:34 +00001201{
1202 switch (op) {
sewardja7e96382012-06-29 16:26:17 +00001203 case Iop_CmpNE32: return IRExpr_Const(IRConst_U1(toBool(0)));
sewardj0033ddc2005-04-26 23:34:34 +00001204 case Iop_Xor8: return IRExpr_Const(IRConst_U8(0));
1205 case Iop_Xor16: return IRExpr_Const(IRConst_U16(0));
sewardjbe917912010-08-22 12:38:53 +00001206 case Iop_Sub32:
sewardj0033ddc2005-04-26 23:34:34 +00001207 case Iop_Xor32: return IRExpr_Const(IRConst_U32(0));
sewardj64d776c2010-10-01 14:06:22 +00001208 case Iop_Sub64:
sewardj0033ddc2005-04-26 23:34:34 +00001209 case Iop_Xor64: return IRExpr_Const(IRConst_U64(0));
sewardj04744272007-01-16 19:19:55 +00001210 case Iop_XorV128: return IRExpr_Const(IRConst_V128(0));
sewardj64d776c2010-10-01 14:06:22 +00001211 default: vpanic("mkZeroOfPrimopResultType: bad primop");
1212 }
1213}
1214
1215/* Make a value containing all 1-bits, which has the same type as the
1216 result of the given primop. */
1217static IRExpr* mkOnesOfPrimopResultType ( IROp op )
1218{
1219 switch (op) {
sewardja7e96382012-06-29 16:26:17 +00001220 case Iop_CmpEQ32:
sewardj64d776c2010-10-01 14:06:22 +00001221 case Iop_CmpEQ64:
1222 return IRExpr_Const(IRConst_U1(toBool(1)));
sewardjcf4be4a2012-03-26 09:44:39 +00001223 case Iop_Or8:
1224 return IRExpr_Const(IRConst_U8(0xFF));
1225 case Iop_Or16:
1226 return IRExpr_Const(IRConst_U16(0xFFFF));
1227 case Iop_Or32:
1228 return IRExpr_Const(IRConst_U32(0xFFFFFFFF));
sewardj64d776c2010-10-01 14:06:22 +00001229 case Iop_CmpEQ8x8:
sewardjcf4be4a2012-03-26 09:44:39 +00001230 case Iop_Or64:
sewardj64d776c2010-10-01 14:06:22 +00001231 return IRExpr_Const(IRConst_U64(0xFFFFFFFFFFFFFFFFULL));
1232 case Iop_CmpEQ8x16:
sewardj899d1832012-07-10 21:41:01 +00001233 case Iop_CmpEQ16x8:
sewardjffccf2b2012-06-29 15:33:09 +00001234 case Iop_CmpEQ32x4:
sewardj64d776c2010-10-01 14:06:22 +00001235 return IRExpr_Const(IRConst_V128(0xFFFF));
1236 default:
sewardjcf4be4a2012-03-26 09:44:39 +00001237 ppIROp(op);
sewardj64d776c2010-10-01 14:06:22 +00001238 vpanic("mkOnesOfPrimopResultType: bad primop");
sewardj0033ddc2005-04-26 23:34:34 +00001239 }
1240}
1241
sewardj4cba9f42011-03-07 18:34:34 +00001242/* Helpers for folding Clz32/64. */
1243static UInt fold_Clz64 ( ULong value )
1244{
1245 UInt i;
1246 vassert(value != 0ULL); /* no defined semantics for arg==0 */
1247 for (i = 0; i < 64; ++i) {
sewardj7f6330d2011-04-05 11:06:02 +00001248 if (0ULL != (value & (((ULong)1) << (63 - i)))) return i;
sewardj4cba9f42011-03-07 18:34:34 +00001249 }
1250 vassert(0);
1251 /*NOTREACHED*/
1252 return 0;
1253}
1254
1255static UInt fold_Clz32 ( UInt value )
1256{
1257 UInt i;
1258 vassert(value != 0); /* no defined semantics for arg==0 */
1259 for (i = 0; i < 32; ++i) {
sewardj7f6330d2011-04-05 11:06:02 +00001260 if (0 != (value & (((UInt)1) << (31 - i)))) return i;
sewardj4cba9f42011-03-07 18:34:34 +00001261 }
1262 vassert(0);
1263 /*NOTREACHED*/
1264 return 0;
1265}
1266
sewardj4a0bee02012-06-29 14:44:44 +00001267/* V64 holds 8 summary-constant bits in V128/V256 style. Convert to
1268 the corresponding real constant. */
1269//XXX re-check this before use
1270//static ULong de_summarise_V64 ( UChar v64 )
1271//{
1272// ULong r = 0;
1273// if (v64 & (1<<0)) r |= 0x00000000000000FFULL;
1274// if (v64 & (1<<1)) r |= 0x000000000000FF00ULL;
1275// if (v64 & (1<<2)) r |= 0x0000000000FF0000ULL;
1276// if (v64 & (1<<3)) r |= 0x00000000FF000000ULL;
1277// if (v64 & (1<<4)) r |= 0x000000FF00000000ULL;
1278// if (v64 & (1<<5)) r |= 0x0000FF0000000000ULL;
1279// if (v64 & (1<<6)) r |= 0x00FF000000000000ULL;
1280// if (v64 & (1<<7)) r |= 0xFF00000000000000ULL;
1281// return r;
1282//}
sewardj0033ddc2005-04-26 23:34:34 +00001283
floriancdb5fee2012-02-13 00:06:29 +00001284static IRExpr* fold_Expr ( IRExpr** env, IRExpr* e )
sewardj84be7372004-08-18 13:59:33 +00001285{
sewardj278c44c2004-08-20 00:28:13 +00001286 Int shift;
sewardj84be7372004-08-18 13:59:33 +00001287 IRExpr* e2 = e; /* e2 is the result of folding e, if possible */
1288
florian708417d2012-02-15 00:43:36 +00001289 switch (e->tag) {
1290 case Iex_Unop:
1291 /* UNARY ops */
1292 if (e->Iex.Unop.arg->tag == Iex_Const) {
1293 switch (e->Iex.Unop.op) {
sewardjae27ab62004-10-15 21:21:46 +00001294 case Iop_1Uto8:
sewardj9d2e7692005-02-07 01:11:31 +00001295 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardjba999312004-11-15 15:21:17 +00001296 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardj9d2e7692005-02-07 01:11:31 +00001297 ? 1 : 0)));
sewardjae27ab62004-10-15 21:21:46 +00001298 break;
sewardjf4a821d2004-10-09 00:58:19 +00001299 case Iop_1Uto32:
1300 e2 = IRExpr_Const(IRConst_U32(
sewardjba999312004-11-15 15:21:17 +00001301 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardjf4a821d2004-10-09 00:58:19 +00001302 ? 1 : 0));
1303 break;
sewardj2716ff12005-05-20 19:21:45 +00001304 case Iop_1Uto64:
1305 e2 = IRExpr_Const(IRConst_U64(
1306 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
1307 ? 1 : 0));
1308 break;
sewardje6b39932004-11-06 17:01:15 +00001309
sewardj1bee5612005-11-10 18:10:58 +00001310 case Iop_1Sto8:
1311 e2 = IRExpr_Const(IRConst_U8(toUChar(
1312 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
1313 ? 0xFF : 0)));
1314 break;
sewardj68884ef2005-07-18 13:58:49 +00001315 case Iop_1Sto16:
sewardj743d8f02005-07-27 00:22:37 +00001316 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardj68884ef2005-07-18 13:58:49 +00001317 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardj743d8f02005-07-27 00:22:37 +00001318 ? 0xFFFF : 0)));
sewardj68884ef2005-07-18 13:58:49 +00001319 break;
sewardjd9997882004-11-04 19:42:59 +00001320 case Iop_1Sto32:
1321 e2 = IRExpr_Const(IRConst_U32(
sewardjba999312004-11-15 15:21:17 +00001322 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardjd9997882004-11-04 19:42:59 +00001323 ? 0xFFFFFFFF : 0));
1324 break;
sewardje6b39932004-11-06 17:01:15 +00001325 case Iop_1Sto64:
1326 e2 = IRExpr_Const(IRConst_U64(
sewardjba999312004-11-15 15:21:17 +00001327 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardje6b39932004-11-06 17:01:15 +00001328 ? 0xFFFFFFFFFFFFFFFFULL : 0));
1329 break;
1330
sewardj883b00b2004-09-11 09:30:24 +00001331 case Iop_8Sto32: {
1332 /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
1333 s32 <<= 24;
1334 s32 >>= 24;
1335 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
1336 break;
1337 }
sewardj7f6330d2011-04-05 11:06:02 +00001338 case Iop_16Sto32: {
1339 /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1340 s32 <<= 16;
1341 s32 >>= 16;
1342 e2 = IRExpr_Const(IRConst_U32( (UInt)s32) );
1343 break;
1344 }
sewardj291a7e82005-04-27 11:42:44 +00001345 case Iop_8Uto64:
1346 e2 = IRExpr_Const(IRConst_U64(
1347 0xFFULL & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1348 break;
1349 case Iop_16Uto64:
1350 e2 = IRExpr_Const(IRConst_U64(
1351 0xFFFFULL & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
1352 break;
sewardj84be7372004-08-18 13:59:33 +00001353 case Iop_8Uto32:
1354 e2 = IRExpr_Const(IRConst_U32(
1355 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1356 break;
sewardj7f6330d2011-04-05 11:06:02 +00001357 case Iop_8Sto16: {
1358 /* signed */ Short s16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
1359 s16 <<= 8;
1360 s16 >>= 8;
1361 e2 = IRExpr_Const(IRConst_U16( (UShort)s16) );
1362 break;
1363 }
1364 case Iop_8Uto16:
1365 e2 = IRExpr_Const(IRConst_U16(
1366 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1367 break;
sewardj84be7372004-08-18 13:59:33 +00001368 case Iop_16Uto32:
1369 e2 = IRExpr_Const(IRConst_U32(
1370 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
1371 break;
sewardj73017432004-10-14 19:33:25 +00001372 case Iop_32to16:
sewardj9d2e7692005-02-07 01:11:31 +00001373 e2 = IRExpr_Const(IRConst_U16(toUShort(
1374 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
sewardj73017432004-10-14 19:33:25 +00001375 break;
sewardj4345f7a2004-09-22 19:49:27 +00001376 case Iop_32to8:
sewardj9d2e7692005-02-07 01:11:31 +00001377 e2 = IRExpr_Const(IRConst_U8(toUChar(
1378 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
sewardj4345f7a2004-09-22 19:49:27 +00001379 break;
sewardj7447b5b2004-10-16 11:30:42 +00001380 case Iop_32to1:
sewardj9d2e7692005-02-07 01:11:31 +00001381 e2 = IRExpr_Const(IRConst_U1(toBool(
1382 1 == (1 & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)
1383 )));
sewardj7447b5b2004-10-16 11:30:42 +00001384 break;
sewardj291a7e82005-04-27 11:42:44 +00001385 case Iop_64to1:
1386 e2 = IRExpr_Const(IRConst_U1(toBool(
1387 1 == (1 & e->Iex.Unop.arg->Iex.Const.con->Ico.U64)
1388 )));
1389 break;
sewardje6b39932004-11-06 17:01:15 +00001390
sewardj4a0bee02012-06-29 14:44:44 +00001391 case Iop_NotV128:
1392 e2 = IRExpr_Const(IRConst_V128(
1393 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.V128)));
1394 break;
sewardjf057afb2005-02-27 13:35:41 +00001395 case Iop_Not64:
1396 e2 = IRExpr_Const(IRConst_U64(
1397 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U64)));
1398 break;
sewardj883b00b2004-09-11 09:30:24 +00001399 case Iop_Not32:
1400 e2 = IRExpr_Const(IRConst_U32(
1401 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
1402 break;
sewardje6b39932004-11-06 17:01:15 +00001403 case Iop_Not16:
sewardj9d2e7692005-02-07 01:11:31 +00001404 e2 = IRExpr_Const(IRConst_U16(toUShort(
1405 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U16))));
sewardje6b39932004-11-06 17:01:15 +00001406 break;
sewardjd9997882004-11-04 19:42:59 +00001407 case Iop_Not8:
sewardj9d2e7692005-02-07 01:11:31 +00001408 e2 = IRExpr_Const(IRConst_U8(toUChar(
1409 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U8))));
sewardjd9997882004-11-04 19:42:59 +00001410 break;
sewardje6b39932004-11-06 17:01:15 +00001411
sewardje1d45da2004-11-12 00:13:21 +00001412 case Iop_Not1:
sewardjba999312004-11-15 15:21:17 +00001413 e2 = IRExpr_Const(IRConst_U1(
1414 notBool(e->Iex.Unop.arg->Iex.Const.con->Ico.U1)));
sewardje1d45da2004-11-12 00:13:21 +00001415 break;
1416
sewardj291a7e82005-04-27 11:42:44 +00001417 case Iop_64to8: {
1418 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1419 w64 &= 0xFFULL;
1420 e2 = IRExpr_Const(IRConst_U8( (UChar)w64 ));
1421 break;
1422 }
1423 case Iop_64to16: {
1424 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1425 w64 &= 0xFFFFULL;
sewardje85bc402005-05-06 16:29:26 +00001426 e2 = IRExpr_Const(IRConst_U16( (UShort)w64 ));
sewardj291a7e82005-04-27 11:42:44 +00001427 break;
1428 }
sewardj1d8ce202004-12-13 14:14:16 +00001429 case Iop_64to32: {
1430 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1431 w64 &= 0x00000000FFFFFFFFULL;
1432 e2 = IRExpr_Const(IRConst_U32( (UInt)w64 ));
sewardj37010592004-12-13 10:47:15 +00001433 break;
sewardj1d8ce202004-12-13 14:14:16 +00001434 }
sewardj1d8ce202004-12-13 14:14:16 +00001435 case Iop_64HIto32: {
1436 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1437 w64 >>= 32;
1438 e2 = IRExpr_Const(IRConst_U32( (UInt)w64 ));
1439 break;
1440 }
sewardjb5710b82005-01-27 16:05:09 +00001441 case Iop_32Uto64:
1442 e2 = IRExpr_Const(IRConst_U64(
1443 0xFFFFFFFFULL
1444 & e->Iex.Unop.arg->Iex.Const.con->Ico.U32));
1445 break;
sewardj7f6330d2011-04-05 11:06:02 +00001446 case Iop_16Sto64: {
1447 /* signed */ Long s64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1448 s64 <<= 48;
1449 s64 >>= 48;
1450 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1451 break;
1452 }
sewardj287e9bb2010-07-29 16:12:41 +00001453 case Iop_32Sto64: {
1454 /* signed */ Long s64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1455 s64 <<= 32;
1456 s64 >>= 32;
1457 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1458 break;
1459 }
sewardj7f6330d2011-04-05 11:06:02 +00001460
1461 case Iop_16to8: {
1462 UShort w16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1463 w16 &= 0xFF;
1464 e2 = IRExpr_Const(IRConst_U8( (UChar)w16 ));
1465 break;
1466 }
1467 case Iop_16HIto8: {
1468 UShort w16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1469 w16 >>= 8;
1470 w16 &= 0xFF;
1471 e2 = IRExpr_Const(IRConst_U8( (UChar)w16 ));
1472 break;
1473 }
1474
sewardj0033ddc2005-04-26 23:34:34 +00001475 case Iop_CmpNEZ8:
1476 e2 = IRExpr_Const(IRConst_U1(toBool(
1477 0 !=
1478 (0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8)
1479 )));
1480 break;
1481 case Iop_CmpNEZ32:
1482 e2 = IRExpr_Const(IRConst_U1(toBool(
1483 0 !=
1484 (0xFFFFFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)
1485 )));
1486 break;
1487 case Iop_CmpNEZ64:
1488 e2 = IRExpr_Const(IRConst_U1(toBool(
1489 0ULL != e->Iex.Unop.arg->Iex.Const.con->Ico.U64
1490 )));
1491 break;
1492
sewardjeb17e492007-08-25 23:07:44 +00001493 case Iop_CmpwNEZ32: {
1494 UInt w32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1495 if (w32 == 0)
1496 e2 = IRExpr_Const(IRConst_U32( 0 ));
1497 else
1498 e2 = IRExpr_Const(IRConst_U32( 0xFFFFFFFF ));
1499 break;
1500 }
1501 case Iop_CmpwNEZ64: {
1502 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1503 if (w64 == 0)
1504 e2 = IRExpr_Const(IRConst_U64( 0 ));
1505 else
1506 e2 = IRExpr_Const(IRConst_U64( 0xFFFFFFFFFFFFFFFFULL ));
1507 break;
1508 }
1509
1510 case Iop_Left32: {
1511 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1512 Int s32 = (Int)(u32 & 0xFFFFFFFF);
1513 s32 = (s32 | (-s32));
1514 e2 = IRExpr_Const( IRConst_U32( (UInt)s32 ));
1515 break;
1516 }
1517
1518 case Iop_Left64: {
1519 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1520 Long s64 = (Long)u64;
1521 s64 = (s64 | (-s64));
1522 e2 = IRExpr_Const( IRConst_U64( (ULong)s64 ));
1523 break;
1524 }
1525
sewardj4cba9f42011-03-07 18:34:34 +00001526 case Iop_Clz32: {
1527 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1528 if (u32 != 0)
1529 e2 = IRExpr_Const(IRConst_U32(fold_Clz32(u32)));
1530 break;
1531 }
1532 case Iop_Clz64: {
1533 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1534 if (u64 != 0ULL)
1535 e2 = IRExpr_Const(IRConst_U64(fold_Clz64(u64)));
1536 break;
1537 }
1538
sewardj4a0bee02012-06-29 14:44:44 +00001539 /* For these vector ones, can't fold all cases, but at least
1540 do the most obvious one. Could do better here using
1541 summarise/desummarise of vector constants, but too
1542 difficult to verify; hence just handle the zero cases. */
1543 case Iop_32UtoV128: {
1544 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1545 if (0 == u32) {
1546 e2 = IRExpr_Const(IRConst_V128(0x0000));
1547 } else {
1548 goto unhandled;
1549 }
1550 break;
1551 }
1552 case Iop_V128to64: {
1553 UShort v128 = e->Iex.Unop.arg->Iex.Const.con->Ico.V128;
1554 if (0 == ((v128 >> 0) & 0xFF)) {
1555 e2 = IRExpr_Const(IRConst_U64(0));
1556 } else {
1557 goto unhandled;
1558 }
1559 break;
1560 }
1561 case Iop_V128HIto64: {
1562 UShort v128 = e->Iex.Unop.arg->Iex.Const.con->Ico.V128;
1563 if (0 == ((v128 >> 8) & 0xFF)) {
1564 e2 = IRExpr_Const(IRConst_U64(0));
1565 } else {
1566 goto unhandled;
1567 }
1568 break;
1569 }
1570 case Iop_64UtoV128: {
1571 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1572 if (0 == u64) {
1573 e2 = IRExpr_Const(IRConst_V128(0x0000));
1574 } else {
1575 goto unhandled;
1576 }
1577 break;
1578 }
1579
sewardjffccf2b2012-06-29 15:33:09 +00001580 /* Even stupider (although still correct ..) */
1581 case Iop_V256to64_0: case Iop_V256to64_1:
1582 case Iop_V256to64_2: case Iop_V256to64_3: {
1583 UInt v256 = e->Iex.Unop.arg->Iex.Const.con->Ico.V256;
1584 if (v256 == 0x00000000) {
1585 e2 = IRExpr_Const(IRConst_U64(0));
1586 } else {
1587 goto unhandled;
1588 }
1589 break;
1590 }
1591
sewardj84be7372004-08-18 13:59:33 +00001592 default:
1593 goto unhandled;
1594 }
florian708417d2012-02-15 00:43:36 +00001595 }
1596 break;
sewardj84be7372004-08-18 13:59:33 +00001597
florian708417d2012-02-15 00:43:36 +00001598 case Iex_Binop:
1599 /* BINARY ops */
sewardj84be7372004-08-18 13:59:33 +00001600 if (e->Iex.Binop.arg1->tag == Iex_Const
1601 && e->Iex.Binop.arg2->tag == Iex_Const) {
1602 /* cases where both args are consts */
1603 switch (e->Iex.Binop.op) {
sewardje6b39932004-11-06 17:01:15 +00001604
sewardj855dc722005-02-17 09:26:05 +00001605 /* -- Or -- */
sewardjd9997882004-11-04 19:42:59 +00001606 case Iop_Or8:
sewardj9d2e7692005-02-07 01:11:31 +00001607 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardjd9997882004-11-04 19:42:59 +00001608 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001609 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardjd9997882004-11-04 19:42:59 +00001610 break;
sewardje6b39932004-11-06 17:01:15 +00001611 case Iop_Or16:
sewardj9d2e7692005-02-07 01:11:31 +00001612 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardje6b39932004-11-06 17:01:15 +00001613 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
sewardj9d2e7692005-02-07 01:11:31 +00001614 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
sewardje6b39932004-11-06 17:01:15 +00001615 break;
1616 case Iop_Or32:
1617 e2 = IRExpr_Const(IRConst_U32(
1618 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1619 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1620 break;
sewardjf057afb2005-02-27 13:35:41 +00001621 case Iop_Or64:
1622 e2 = IRExpr_Const(IRConst_U64(
1623 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1624 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1625 break;
sewardj4a0bee02012-06-29 14:44:44 +00001626 case Iop_OrV128:
1627 e2 = IRExpr_Const(IRConst_V128(
1628 (e->Iex.Binop.arg1->Iex.Const.con->Ico.V128
1629 | e->Iex.Binop.arg2->Iex.Const.con->Ico.V128)));
1630 break;
sewardje6b39932004-11-06 17:01:15 +00001631
sewardj855dc722005-02-17 09:26:05 +00001632 /* -- Xor -- */
sewardj883b00b2004-09-11 09:30:24 +00001633 case Iop_Xor8:
sewardj9d2e7692005-02-07 01:11:31 +00001634 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj883b00b2004-09-11 09:30:24 +00001635 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001636 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj883b00b2004-09-11 09:30:24 +00001637 break;
sewardj82c9f2f2005-03-02 16:05:13 +00001638 case Iop_Xor16:
sewardjc7c098f2005-03-21 01:06:20 +00001639 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardj82c9f2f2005-03-02 16:05:13 +00001640 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
sewardjc7c098f2005-03-21 01:06:20 +00001641 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
sewardj82c9f2f2005-03-02 16:05:13 +00001642 break;
sewardj855dc722005-02-17 09:26:05 +00001643 case Iop_Xor32:
1644 e2 = IRExpr_Const(IRConst_U32(
1645 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1646 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1647 break;
sewardjf057afb2005-02-27 13:35:41 +00001648 case Iop_Xor64:
1649 e2 = IRExpr_Const(IRConst_U64(
1650 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1651 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1652 break;
sewardj4a0bee02012-06-29 14:44:44 +00001653 case Iop_XorV128:
1654 e2 = IRExpr_Const(IRConst_V128(
1655 (e->Iex.Binop.arg1->Iex.Const.con->Ico.V128
1656 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.V128)));
1657 break;
sewardj855dc722005-02-17 09:26:05 +00001658
1659 /* -- And -- */
sewardj84be7372004-08-18 13:59:33 +00001660 case Iop_And8:
sewardj9d2e7692005-02-07 01:11:31 +00001661 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj84be7372004-08-18 13:59:33 +00001662 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001663 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj84be7372004-08-18 13:59:33 +00001664 break;
sewardj7f6330d2011-04-05 11:06:02 +00001665 case Iop_And16:
1666 e2 = IRExpr_Const(IRConst_U16(toUShort(
1667 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
1668 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
1669 break;
sewardj855dc722005-02-17 09:26:05 +00001670 case Iop_And32:
1671 e2 = IRExpr_Const(IRConst_U32(
1672 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1673 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1674 break;
1675 case Iop_And64:
1676 e2 = IRExpr_Const(IRConst_U64(
1677 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1678 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1679 break;
sewardj4a0bee02012-06-29 14:44:44 +00001680 case Iop_AndV128:
1681 e2 = IRExpr_Const(IRConst_V128(
1682 (e->Iex.Binop.arg1->Iex.Const.con->Ico.V128
1683 & e->Iex.Binop.arg2->Iex.Const.con->Ico.V128)));
1684 break;
sewardj855dc722005-02-17 09:26:05 +00001685
1686 /* -- Add -- */
sewardj4345f7a2004-09-22 19:49:27 +00001687 case Iop_Add8:
sewardj9d2e7692005-02-07 01:11:31 +00001688 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj4345f7a2004-09-22 19:49:27 +00001689 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001690 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj4345f7a2004-09-22 19:49:27 +00001691 break;
sewardj855dc722005-02-17 09:26:05 +00001692 case Iop_Add32:
1693 e2 = IRExpr_Const(IRConst_U32(
1694 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1695 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1696 break;
1697 case Iop_Add64:
1698 e2 = IRExpr_Const(IRConst_U64(
1699 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1700 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1701 break;
1702
1703 /* -- Sub -- */
sewardj84be7372004-08-18 13:59:33 +00001704 case Iop_Sub8:
sewardj9d2e7692005-02-07 01:11:31 +00001705 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj84be7372004-08-18 13:59:33 +00001706 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001707 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj84be7372004-08-18 13:59:33 +00001708 break;
sewardjd7217032004-08-19 10:49:10 +00001709 case Iop_Sub32:
1710 e2 = IRExpr_Const(IRConst_U32(
1711 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1712 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1713 break;
sewardj70a8ddf2005-02-13 02:24:26 +00001714 case Iop_Sub64:
1715 e2 = IRExpr_Const(IRConst_U64(
1716 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1717 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1718 break;
sewardjc2bcb6f2005-02-07 00:17:12 +00001719
sewardj478646f2008-05-01 20:13:04 +00001720 /* -- Max32U -- */
1721 case Iop_Max32U: {
1722 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1723 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1724 UInt res = u32a > u32b ? u32a : u32b;
1725 e2 = IRExpr_Const(IRConst_U32(res));
1726 break;
1727 }
1728
sewardj855dc722005-02-17 09:26:05 +00001729 /* -- Mul -- */
sewardjb9c5cf62004-08-24 15:10:38 +00001730 case Iop_Mul32:
1731 e2 = IRExpr_Const(IRConst_U32(
1732 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1733 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1734 break;
sewardja34c0712005-03-30 23:19:46 +00001735 case Iop_Mul64:
1736 e2 = IRExpr_Const(IRConst_U64(
1737 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1738 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1739 break;
1740
sewardjea6bccb2005-03-01 10:19:23 +00001741 case Iop_MullS32: {
1742 /* very paranoid */
1743 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1744 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1745 Int s32a = (Int)u32a;
1746 Int s32b = (Int)u32b;
1747 Long s64a = (Long)s32a;
1748 Long s64b = (Long)s32b;
1749 Long sres = s64a * s64b;
1750 ULong ures = (ULong)sres;
1751 e2 = IRExpr_Const(IRConst_U64(ures));
1752 break;
1753 }
sewardjb095fba2005-02-13 14:13:04 +00001754
sewardj855dc722005-02-17 09:26:05 +00001755 /* -- Shl -- */
sewardjd7217032004-08-19 10:49:10 +00001756 case Iop_Shl32:
sewardj61348472004-08-20 01:01:04 +00001757 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1758 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj29632392004-08-22 02:38:11 +00001759 if (shift >= 0 && shift <= 31)
sewardj278c44c2004-08-20 00:28:13 +00001760 e2 = IRExpr_Const(IRConst_U32(
1761 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1762 << shift)));
sewardjd7217032004-08-19 10:49:10 +00001763 break;
sewardjb095fba2005-02-13 14:13:04 +00001764 case Iop_Shl64:
1765 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1766 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1767 if (shift >= 0 && shift <= 63)
1768 e2 = IRExpr_Const(IRConst_U64(
1769 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1770 << shift)));
1771 break;
1772
sewardj855dc722005-02-17 09:26:05 +00001773 /* -- Sar -- */
sewardj278c44c2004-08-20 00:28:13 +00001774 case Iop_Sar32: {
1775 /* paranoid ... */
1776 /*signed*/ Int s32;
sewardj61348472004-08-20 01:01:04 +00001777 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj278c44c2004-08-20 00:28:13 +00001778 s32 = (Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +00001779 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj278c44c2004-08-20 00:28:13 +00001780 if (shift >= 0 && shift <= 31) {
1781 s32 >>=/*signed*/ shift;
1782 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
1783 }
1784 break;
1785 }
sewardj855dc722005-02-17 09:26:05 +00001786 case Iop_Sar64: {
1787 /* paranoid ... */
1788 /*signed*/ Long s64;
1789 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1790 s64 = (Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64);
1791 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1792 if (shift >= 0 && shift <= 63) {
1793 s64 >>=/*signed*/ shift;
1794 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1795 }
1796 break;
1797 }
1798
1799 /* -- Shr -- */
sewardj61348472004-08-20 01:01:04 +00001800 case Iop_Shr32: {
1801 /* paranoid ... */
sewardj4add7142005-02-21 08:20:22 +00001802 /*unsigned*/ UInt u32;
sewardj61348472004-08-20 01:01:04 +00001803 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj4add7142005-02-21 08:20:22 +00001804 u32 = (UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +00001805 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1806 if (shift >= 0 && shift <= 31) {
sewardj4add7142005-02-21 08:20:22 +00001807 u32 >>=/*unsigned*/ shift;
1808 e2 = IRExpr_Const(IRConst_U32(u32));
1809 }
1810 break;
1811 }
1812 case Iop_Shr64: {
1813 /* paranoid ... */
1814 /*unsigned*/ ULong u64;
1815 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1816 u64 = (ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64);
1817 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1818 if (shift >= 0 && shift <= 63) {
1819 u64 >>=/*unsigned*/ shift;
1820 e2 = IRExpr_Const(IRConst_U64(u64));
sewardj61348472004-08-20 01:01:04 +00001821 }
1822 break;
1823 }
sewardj855dc722005-02-17 09:26:05 +00001824
1825 /* -- CmpEQ -- */
sewardjb8e75862004-08-19 17:58:45 +00001826 case Iop_CmpEQ32:
sewardj9d2e7692005-02-07 01:11:31 +00001827 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardjb8e75862004-08-19 17:58:45 +00001828 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
sewardj9d2e7692005-02-07 01:11:31 +00001829 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))));
sewardjb8e75862004-08-19 17:58:45 +00001830 break;
sewardj855dc722005-02-17 09:26:05 +00001831 case Iop_CmpEQ64:
1832 e2 = IRExpr_Const(IRConst_U1(toBool(
1833 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1834 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U64))));
1835 break;
1836
1837 /* -- CmpNE -- */
1838 case Iop_CmpNE8:
sewardje13074c2012-11-08 10:57:08 +00001839 case Iop_CasCmpNE8:
1840 case Iop_ExpCmpNE8:
sewardj855dc722005-02-17 09:26:05 +00001841 e2 = IRExpr_Const(IRConst_U1(toBool(
1842 ((0xFF & e->Iex.Binop.arg1->Iex.Const.con->Ico.U8)
1843 != (0xFF & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)))));
1844 break;
sewardjae27ab62004-10-15 21:21:46 +00001845 case Iop_CmpNE32:
sewardje13074c2012-11-08 10:57:08 +00001846 case Iop_CasCmpNE32:
1847 case Iop_ExpCmpNE32:
sewardj9d2e7692005-02-07 01:11:31 +00001848 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardjae27ab62004-10-15 21:21:46 +00001849 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
sewardj9d2e7692005-02-07 01:11:31 +00001850 != e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))));
sewardjae27ab62004-10-15 21:21:46 +00001851 break;
sewardje6b39932004-11-06 17:01:15 +00001852 case Iop_CmpNE64:
sewardje13074c2012-11-08 10:57:08 +00001853 case Iop_CasCmpNE64:
1854 case Iop_ExpCmpNE64:
sewardj9d2e7692005-02-07 01:11:31 +00001855 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardje6b39932004-11-06 17:01:15 +00001856 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
sewardj9d2e7692005-02-07 01:11:31 +00001857 != e->Iex.Binop.arg2->Iex.Const.con->Ico.U64))));
sewardje6b39932004-11-06 17:01:15 +00001858 break;
1859
sewardj855dc722005-02-17 09:26:05 +00001860 /* -- CmpLEU -- */
sewardj7447b5b2004-10-16 11:30:42 +00001861 case Iop_CmpLE32U:
sewardj9d2e7692005-02-07 01:11:31 +00001862 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj7447b5b2004-10-16 11:30:42 +00001863 ((UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001864 <= (UInt)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj7447b5b2004-10-16 11:30:42 +00001865 break;
sewardj7f6330d2011-04-05 11:06:02 +00001866 case Iop_CmpLE64U:
1867 e2 = IRExpr_Const(IRConst_U1(toBool(
1868 ((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1869 <= (ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1870 break;
sewardj855dc722005-02-17 09:26:05 +00001871
1872 /* -- CmpLES -- */
sewardj088e4f72004-10-19 01:25:02 +00001873 case Iop_CmpLE32S:
sewardj9d2e7692005-02-07 01:11:31 +00001874 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj088e4f72004-10-19 01:25:02 +00001875 ((Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001876 <= (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj088e4f72004-10-19 01:25:02 +00001877 break;
sewardj7f6330d2011-04-05 11:06:02 +00001878 case Iop_CmpLE64S:
1879 e2 = IRExpr_Const(IRConst_U1(toBool(
1880 ((Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1881 <= (Long)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1882 break;
sewardje1d45da2004-11-12 00:13:21 +00001883
sewardj855dc722005-02-17 09:26:05 +00001884 /* -- CmpLTS -- */
sewardj9bdd2652004-10-19 12:56:33 +00001885 case Iop_CmpLT32S:
sewardj9d2e7692005-02-07 01:11:31 +00001886 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj9bdd2652004-10-19 12:56:33 +00001887 ((Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001888 < (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj9bdd2652004-10-19 12:56:33 +00001889 break;
sewardj7f6330d2011-04-05 11:06:02 +00001890 case Iop_CmpLT64S:
1891 e2 = IRExpr_Const(IRConst_U1(toBool(
1892 ((Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1893 < (Long)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1894 break;
sewardj855dc722005-02-17 09:26:05 +00001895
1896 /* -- CmpLTU -- */
sewardje1d45da2004-11-12 00:13:21 +00001897 case Iop_CmpLT32U:
sewardj9d2e7692005-02-07 01:11:31 +00001898 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardje1d45da2004-11-12 00:13:21 +00001899 ((UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001900 < (UInt)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardje1d45da2004-11-12 00:13:21 +00001901 break;
sewardj7f6330d2011-04-05 11:06:02 +00001902 case Iop_CmpLT64U:
1903 e2 = IRExpr_Const(IRConst_U1(toBool(
1904 ((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1905 < (ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1906 break;
sewardj7447b5b2004-10-16 11:30:42 +00001907
sewardjb51f0f42005-07-18 11:38:02 +00001908 /* -- CmpORD -- */
1909 case Iop_CmpORD32S: {
1910 /* very paranoid */
1911 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1912 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1913 Int s32a = (Int)u32a;
1914 Int s32b = (Int)u32b;
1915 Int r = 0x2; /* EQ */
1916 if (s32a < s32b) {
1917 r = 0x8; /* LT */
1918 }
1919 else if (s32a > s32b) {
1920 r = 0x4; /* GT */
1921 }
1922 e2 = IRExpr_Const(IRConst_U32(r));
1923 break;
1924 }
1925
sewardj855dc722005-02-17 09:26:05 +00001926 /* -- nHLto2n -- */
sewardj088bcb42004-08-19 17:16:52 +00001927 case Iop_32HLto64:
1928 e2 = IRExpr_Const(IRConst_U64(
sewardj4a0bee02012-06-29 14:44:44 +00001929 (((ULong)(e->Iex.Binop.arg1
1930 ->Iex.Const.con->Ico.U32)) << 32)
sewardj088bcb42004-08-19 17:16:52 +00001931 | ((ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))
1932 ));
1933 break;
sewardj3bc8a592005-05-02 10:47:22 +00001934 case Iop_64HLto128:
1935 /* We can't fold this, because there is no way to
1936 express he result in IR, but at least pretend to
1937 handle it, so as to stop getting blasted with
1938 no-rule-for-this-primop messages. */
1939 break;
sewardj4a0bee02012-06-29 14:44:44 +00001940 /* For this vector one, can't fold all cases, but at
1941 least do the most obvious one. Could do better here
1942 using summarise/desummarise of vector constants, but
1943 too difficult to verify; hence just handle the zero
1944 cases. */
1945 case Iop_64HLtoV128: {
1946 ULong argHi = e->Iex.Binop.arg1->Iex.Const.con->Ico.U64;
1947 ULong argLo = e->Iex.Binop.arg2->Iex.Const.con->Ico.U64;
1948 if (0 == argHi && 0 == argLo) {
1949 e2 = IRExpr_Const(IRConst_V128(0));
1950 } else {
1951 goto unhandled;
1952 }
1953 break;
1954 }
1955
1956 /* -- V128 stuff -- */
1957 case Iop_InterleaveLO8x16: {
1958 /* This turns up a lot in Memcheck instrumentation of
1959 Icc generated code. I don't know why. */
1960 UShort arg1 = e->Iex.Binop.arg1->Iex.Const.con->Ico.V128;
1961 UShort arg2 = e->Iex.Binop.arg2->Iex.Const.con->Ico.V128;
1962 if (0 == arg1 && 0 == arg2) {
1963 e2 = IRExpr_Const(IRConst_V128(0));
1964 } else {
1965 goto unhandled;
1966 }
1967 break;
1968 }
sewardj855dc722005-02-17 09:26:05 +00001969
sewardj607dd4f2004-09-08 18:20:19 +00001970 default:
1971 goto unhandled;
sewardjd7217032004-08-19 10:49:10 +00001972 }
sewardjf6729012004-08-25 12:45:13 +00001973
sewardj84be7372004-08-18 13:59:33 +00001974 } else {
sewardjf6729012004-08-25 12:45:13 +00001975
sewardj84be7372004-08-18 13:59:33 +00001976 /* other cases (identities, etc) */
sewardj64d776c2010-10-01 14:06:22 +00001977 switch (e->Iex.Binop.op) {
florianf6402ab2012-01-29 02:19:43 +00001978
1979 case Iop_Shl32:
1980 case Iop_Shl64:
1981 case Iop_Shr64:
1982 /* Shl32/Shl64/Shr64(x,0) ==> x */
1983 if (isZeroU(e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00001984 e2 = e->Iex.Binop.arg1;
florianf6402ab2012-01-29 02:19:43 +00001985 break;
1986 }
1987 /* Shl32/Shl64/Shr64(0,x) ==> 0 */
1988 if (isZeroU(e->Iex.Binop.arg1)) {
1989 e2 = e->Iex.Binop.arg1;
1990 break;
1991 }
sewardj64d776c2010-10-01 14:06:22 +00001992 break;
sewardjf6729012004-08-25 12:45:13 +00001993
florianf6402ab2012-01-29 02:19:43 +00001994 case Iop_Shr32:
1995 /* Shr32(x,0) ==> x */
1996 if (isZeroU(e->Iex.Binop.arg2)) {
1997 e2 = e->Iex.Binop.arg1;
1998 break;
1999 }
2000 break;
2001
2002 case Iop_Or8:
2003 case Iop_Or16:
2004 case Iop_Or32:
2005 case Iop_Or64:
2006 case Iop_Max32U:
sewardjcf4be4a2012-03-26 09:44:39 +00002007 /* Or8/Or16/Or32/Or64/Max32U(x,0) ==> x */
florianf6402ab2012-01-29 02:19:43 +00002008 if (isZeroU(e->Iex.Binop.arg2)) {
2009 e2 = e->Iex.Binop.arg1;
2010 break;
2011 }
sewardjcf4be4a2012-03-26 09:44:39 +00002012 /* Or8/Or16/Or32/Or64/Max32U(0,x) ==> x */
florianf6402ab2012-01-29 02:19:43 +00002013 if (isZeroU(e->Iex.Binop.arg1)) {
2014 e2 = e->Iex.Binop.arg2;
2015 break;
2016 }
sewardjcf4be4a2012-03-26 09:44:39 +00002017 /* Or8/Or16/Or32/Or64/Max32U(x,1---1b) ==> 1---1b */
2018 /* Or8/Or16/Or32/Or64/Max32U(1---1b,x) ==> 1---1b */
2019 if (isOnesU(e->Iex.Binop.arg1) || isOnesU(e->Iex.Binop.arg2)) {
2020 e2 = mkOnesOfPrimopResultType(e->Iex.Binop.op);
2021 break;
2022 }
2023 /* Or8/Or16/Or32/Or64/Max32U(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002024 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002025 e2 = e->Iex.Binop.arg1;
2026 break;
2027 }
2028 break;
2029
2030 case Iop_Add8:
2031 /* Add8(t,t) ==> t << 1.
2032 Memcheck doesn't understand that
2033 x+x produces a defined least significant bit, and it seems
2034 simplest just to get rid of the problem by rewriting it
2035 out, since the opportunity to do so exists. */
floriancdb5fee2012-02-13 00:06:29 +00002036 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002037 e2 = IRExpr_Binop(Iop_Shl8, e->Iex.Binop.arg1,
2038 IRExpr_Const(IRConst_U8(1)));
2039 break;
2040 }
2041 break;
2042
2043 /* NB no Add16(t,t) case yet as no known test case exists */
2044
2045 case Iop_Add32:
2046 case Iop_Add64:
2047 /* Add32/Add64(x,0) ==> x */
2048 if (isZeroU(e->Iex.Binop.arg2)) {
2049 e2 = e->Iex.Binop.arg1;
2050 break;
2051 }
2052 /* Add32/Add64(0,x) ==> x */
2053 if (isZeroU(e->Iex.Binop.arg1)) {
2054 e2 = e->Iex.Binop.arg2;
2055 break;
2056 }
2057 /* Add32/Add64(t,t) ==> t << 1. Same rationale as for Add8. */
floriancdb5fee2012-02-13 00:06:29 +00002058 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj6399f812012-06-29 15:36:44 +00002059 e2 = IRExpr_Binop(
2060 e->Iex.Binop.op == Iop_Add32 ? Iop_Shl32 : Iop_Shl64,
2061 e->Iex.Binop.arg1, IRExpr_Const(IRConst_U8(1)));
florianf6402ab2012-01-29 02:19:43 +00002062 break;
2063 }
2064 break;
2065
sewardj1beb4332012-12-19 15:28:43 +00002066 case Iop_Sub32:
florianf6402ab2012-01-29 02:19:43 +00002067 case Iop_Sub64:
sewardj1beb4332012-12-19 15:28:43 +00002068 /* Sub32/Sub64(x,0) ==> x */
2069 if (isZeroU(e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002070 e2 = e->Iex.Binop.arg1;
2071 break;
2072 }
sewardj1beb4332012-12-19 15:28:43 +00002073 /* Sub32/Sub64(t,t) ==> 0, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002074 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00002075 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
florianf6402ab2012-01-29 02:19:43 +00002076 break;
2077 }
sewardj64d776c2010-10-01 14:06:22 +00002078 break;
sewardj64d776c2010-10-01 14:06:22 +00002079
florianf6402ab2012-01-29 02:19:43 +00002080 case Iop_And32:
2081 /* And32(x,0xFFFFFFFF) ==> x */
sewardjcf4be4a2012-03-26 09:44:39 +00002082 if (isOnesU32(e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002083 e2 = e->Iex.Binop.arg1;
2084 break;
2085 }
2086 /* And32(x,0) ==> 0 */
2087 if (isZeroU32(e->Iex.Binop.arg2)) {
2088 e2 = e->Iex.Binop.arg2;
2089 break;
2090 }
2091 /* And32(0,x) ==> 0 */
2092 if (isZeroU32(e->Iex.Binop.arg1)) {
2093 e2 = e->Iex.Binop.arg1;
2094 break;
2095 }
2096 /* And32(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002097 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002098 e2 = e->Iex.Binop.arg1;
2099 break;
2100 }
2101 break;
2102
2103 case Iop_And8:
2104 case Iop_And16:
2105 case Iop_And64:
sewardj4a0bee02012-06-29 14:44:44 +00002106 case Iop_AndV128:
2107 case Iop_AndV256:
2108 /* And8/And16/And64/AndV128/AndV256(t,t)
2109 ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002110 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002111 e2 = e->Iex.Binop.arg1;
2112 break;
2113 }
2114 break;
2115
2116 case Iop_OrV128:
sewardj4a0bee02012-06-29 14:44:44 +00002117 case Iop_OrV256:
2118 /* V128/V256(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002119 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002120 e2 = e->Iex.Binop.arg1;
2121 break;
2122 }
2123 break;
2124
2125 case Iop_Xor8:
2126 case Iop_Xor16:
2127 case Iop_Xor32:
2128 case Iop_Xor64:
2129 case Iop_XorV128:
2130 /* Xor8/16/32/64/V128(t,t) ==> 0, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002131 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002132 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
2133 break;
2134 }
2135 break;
2136
sewardja7e96382012-06-29 16:26:17 +00002137 case Iop_CmpNE32:
sewardj1beb4332012-12-19 15:28:43 +00002138 /* CmpNE32(t,t) ==> 0, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002139 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002140 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
2141 break;
2142 }
2143 break;
2144
sewardja7e96382012-06-29 16:26:17 +00002145 case Iop_CmpEQ32:
sewardj64d776c2010-10-01 14:06:22 +00002146 case Iop_CmpEQ64:
2147 case Iop_CmpEQ8x8:
2148 case Iop_CmpEQ8x16:
sewardj899d1832012-07-10 21:41:01 +00002149 case Iop_CmpEQ16x8:
sewardjffccf2b2012-06-29 15:33:09 +00002150 case Iop_CmpEQ32x4:
floriancdb5fee2012-02-13 00:06:29 +00002151 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00002152 e2 = mkOnesOfPrimopResultType(e->Iex.Binop.op);
florianf6402ab2012-01-29 02:19:43 +00002153 break;
2154 }
sewardj64d776c2010-10-01 14:06:22 +00002155 break;
florianf6402ab2012-01-29 02:19:43 +00002156
sewardj64d776c2010-10-01 14:06:22 +00002157 default:
2158 break;
sewardj0033ddc2005-04-26 23:34:34 +00002159 }
sewardj84be7372004-08-18 13:59:33 +00002160 }
florian708417d2012-02-15 00:43:36 +00002161 break;
sewardj84be7372004-08-18 13:59:33 +00002162
florian708417d2012-02-15 00:43:36 +00002163 case Iex_Mux0X:
2164 /* Mux0X */
2165
sewardj6c299f32009-12-31 18:00:12 +00002166 /* is the discriminant is a constant? */
2167 if (e->Iex.Mux0X.cond->tag == Iex_Const) {
2168 Bool zero;
2169 /* assured us by the IR type rules */
2170 vassert(e->Iex.Mux0X.cond->Iex.Const.con->tag == Ico_U8);
2171 zero = toBool(0 == (0xFF & e->Iex.Mux0X.cond
2172 ->Iex.Const.con->Ico.U8));
2173 e2 = zero ? e->Iex.Mux0X.expr0 : e->Iex.Mux0X.exprX;
2174 }
2175 else
2176 /* are the arms identical? (pretty weedy test) */
floriancdb5fee2012-02-13 00:06:29 +00002177 if (sameIRExprs(env, e->Iex.Mux0X.expr0,
2178 e->Iex.Mux0X.exprX)) {
sewardj6c299f32009-12-31 18:00:12 +00002179 e2 = e->Iex.Mux0X.expr0;
2180 }
florian708417d2012-02-15 00:43:36 +00002181 break;
2182
2183 default:
2184 /* not considered */
2185 break;
sewardj84be7372004-08-18 13:59:33 +00002186 }
2187
sewardja7e96382012-06-29 16:26:17 +00002188 /* Show cases where we've found but not folded 'op(t,t)'. Be
2189 careful not to call sameIRExprs with values of different types,
2190 though, else it will assert (and so it should!). We can't
2191 conveniently call typeOfIRExpr on the two args without a whole
2192 bunch of extra plumbing to pass in a type env, so just use a
2193 hacky test to check the arguments are not anything that might
2194 sameIRExprs to assert. This is only OK because this kludge is
2195 only used for debug printing, not for "real" operation. For
2196 "real" operation (ie, all other calls to sameIRExprs), it is
2197 essential that the to args have the same type.
2198
2199 The "right" solution is to plumb the containing block's
2200 IRTypeEnv through to here and use typeOfIRExpr to be sure. But
2201 that's a bunch of extra parameter passing which will just slow
2202 down the normal case, for no purpose. */
2203 if (vex_control.iropt_verbosity > 0
2204 && e == e2
2205 && e->tag == Iex_Binop
2206 && !debug_only_hack_sameIRExprs_might_assert(e->Iex.Binop.arg1,
2207 e->Iex.Binop.arg2)
floriancdb5fee2012-02-13 00:06:29 +00002208 && sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj4a0bee02012-06-29 14:44:44 +00002209 vex_printf("vex iropt: fold_Expr: no ident rule for: ");
2210 ppIRExpr(e);
2211 vex_printf("\n");
sewardj64d776c2010-10-01 14:06:22 +00002212 }
2213
2214 /* Show the overall results of folding. */
sewardj088bcb42004-08-19 17:16:52 +00002215 if (DEBUG_IROPT && e2 != e) {
2216 vex_printf("FOLD: ");
sewardj84be7372004-08-18 13:59:33 +00002217 ppIRExpr(e); vex_printf(" -> ");
2218 ppIRExpr(e2); vex_printf("\n");
2219 }
2220
2221 return e2;
2222
2223 unhandled:
sewardj883b00b2004-09-11 09:30:24 +00002224# if 0
sewardj84be7372004-08-18 13:59:33 +00002225 vex_printf("\n\n");
2226 ppIRExpr(e);
2227 vpanic("fold_Expr: no rule for the above");
sewardj883b00b2004-09-11 09:30:24 +00002228# else
sewardj328b54b2005-06-13 16:30:18 +00002229 if (vex_control.iropt_verbosity > 0) {
sewardj4a0bee02012-06-29 14:44:44 +00002230 vex_printf("vex iropt: fold_Expr: no const rule for: ");
sewardj328b54b2005-06-13 16:30:18 +00002231 ppIRExpr(e);
2232 vex_printf("\n");
2233 }
sewardj883b00b2004-09-11 09:30:24 +00002234 return e2;
2235# endif
sewardj84be7372004-08-18 13:59:33 +00002236}
2237
2238
sewardj84be7372004-08-18 13:59:33 +00002239/* Apply the subst to a simple 1-level expression -- guaranteed to be
2240 1-level due to previous flattening pass. */
2241
sewardj62617ef2004-10-13 23:29:22 +00002242static IRExpr* subst_Expr ( IRExpr** env, IRExpr* ex )
sewardj84be7372004-08-18 13:59:33 +00002243{
sewardj62617ef2004-10-13 23:29:22 +00002244 switch (ex->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +00002245 case Iex_RdTmp:
2246 if (env[(Int)ex->Iex.RdTmp.tmp] != NULL) {
floriancdb5fee2012-02-13 00:06:29 +00002247 IRExpr *rhs = env[(Int)ex->Iex.RdTmp.tmp];
2248 if (rhs->tag == Iex_RdTmp)
2249 return rhs;
2250 if (rhs->tag == Iex_Const
2251 && rhs->Iex.Const.con->tag != Ico_F64i)
2252 return rhs;
sewardj62617ef2004-10-13 23:29:22 +00002253 }
floriancdb5fee2012-02-13 00:06:29 +00002254 /* not bound in env */
2255 return ex;
sewardj62617ef2004-10-13 23:29:22 +00002256
2257 case Iex_Const:
2258 case Iex_Get:
sewardj84be7372004-08-18 13:59:33 +00002259 return ex;
sewardj62617ef2004-10-13 23:29:22 +00002260
2261 case Iex_GetI:
sewardj496a58d2005-03-20 18:44:44 +00002262 vassert(isIRAtom(ex->Iex.GetI.ix));
sewardj62617ef2004-10-13 23:29:22 +00002263 return IRExpr_GetI(
2264 ex->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +00002265 subst_Expr(env, ex->Iex.GetI.ix),
sewardj62617ef2004-10-13 23:29:22 +00002266 ex->Iex.GetI.bias
2267 );
2268
florian96d7cc32012-06-01 20:41:24 +00002269 case Iex_Qop: {
2270 IRQop* qop = ex->Iex.Qop.details;
2271 vassert(isIRAtom(qop->arg1));
2272 vassert(isIRAtom(qop->arg2));
2273 vassert(isIRAtom(qop->arg3));
2274 vassert(isIRAtom(qop->arg4));
sewardj40c80262006-02-08 19:30:46 +00002275 return IRExpr_Qop(
florian96d7cc32012-06-01 20:41:24 +00002276 qop->op,
2277 subst_Expr(env, qop->arg1),
2278 subst_Expr(env, qop->arg2),
2279 subst_Expr(env, qop->arg3),
2280 subst_Expr(env, qop->arg4)
sewardj40c80262006-02-08 19:30:46 +00002281 );
florian96d7cc32012-06-01 20:41:24 +00002282 }
sewardj40c80262006-02-08 19:30:46 +00002283
florian420bfa92012-06-02 20:29:22 +00002284 case Iex_Triop: {
2285 IRTriop* triop = ex->Iex.Triop.details;
2286 vassert(isIRAtom(triop->arg1));
2287 vassert(isIRAtom(triop->arg2));
2288 vassert(isIRAtom(triop->arg3));
sewardjb183b852006-02-03 16:08:03 +00002289 return IRExpr_Triop(
florian420bfa92012-06-02 20:29:22 +00002290 triop->op,
2291 subst_Expr(env, triop->arg1),
2292 subst_Expr(env, triop->arg2),
2293 subst_Expr(env, triop->arg3)
sewardjb183b852006-02-03 16:08:03 +00002294 );
florian420bfa92012-06-02 20:29:22 +00002295 }
sewardjb183b852006-02-03 16:08:03 +00002296
sewardj62617ef2004-10-13 23:29:22 +00002297 case Iex_Binop:
sewardj496a58d2005-03-20 18:44:44 +00002298 vassert(isIRAtom(ex->Iex.Binop.arg1));
2299 vassert(isIRAtom(ex->Iex.Binop.arg2));
sewardj62617ef2004-10-13 23:29:22 +00002300 return IRExpr_Binop(
2301 ex->Iex.Binop.op,
2302 subst_Expr(env, ex->Iex.Binop.arg1),
2303 subst_Expr(env, ex->Iex.Binop.arg2)
2304 );
2305
2306 case Iex_Unop:
sewardj496a58d2005-03-20 18:44:44 +00002307 vassert(isIRAtom(ex->Iex.Unop.arg));
sewardj62617ef2004-10-13 23:29:22 +00002308 return IRExpr_Unop(
2309 ex->Iex.Unop.op,
2310 subst_Expr(env, ex->Iex.Unop.arg)
2311 );
2312
sewardjaf1ceca2005-06-30 23:31:27 +00002313 case Iex_Load:
2314 vassert(isIRAtom(ex->Iex.Load.addr));
2315 return IRExpr_Load(
2316 ex->Iex.Load.end,
2317 ex->Iex.Load.ty,
2318 subst_Expr(env, ex->Iex.Load.addr)
sewardj62617ef2004-10-13 23:29:22 +00002319 );
2320
2321 case Iex_CCall: {
2322 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +00002323 IRExpr** args2 = shallowCopyIRExprVec(ex->Iex.CCall.args);
sewardj62617ef2004-10-13 23:29:22 +00002324 for (i = 0; args2[i]; i++) {
sewardj496a58d2005-03-20 18:44:44 +00002325 vassert(isIRAtom(args2[i]));
sewardj62617ef2004-10-13 23:29:22 +00002326 args2[i] = subst_Expr(env, args2[i]);
2327 }
2328 return IRExpr_CCall(
sewardj8ea867b2004-10-30 19:03:02 +00002329 ex->Iex.CCall.cee,
sewardj62617ef2004-10-13 23:29:22 +00002330 ex->Iex.CCall.retty,
2331 args2
2332 );
sewardj84be7372004-08-18 13:59:33 +00002333 }
sewardj62617ef2004-10-13 23:29:22 +00002334
2335 case Iex_Mux0X:
sewardj496a58d2005-03-20 18:44:44 +00002336 vassert(isIRAtom(ex->Iex.Mux0X.cond));
2337 vassert(isIRAtom(ex->Iex.Mux0X.expr0));
2338 vassert(isIRAtom(ex->Iex.Mux0X.exprX));
sewardj62617ef2004-10-13 23:29:22 +00002339 return IRExpr_Mux0X(
2340 subst_Expr(env, ex->Iex.Mux0X.cond),
2341 subst_Expr(env, ex->Iex.Mux0X.expr0),
2342 subst_Expr(env, ex->Iex.Mux0X.exprX)
2343 );
2344
2345 default:
2346 vex_printf("\n\n"); ppIRExpr(ex);
2347 vpanic("subst_Expr");
2348
sewardj84be7372004-08-18 13:59:33 +00002349 }
sewardj84be7372004-08-18 13:59:33 +00002350}
2351
2352
2353/* Apply the subst to stmt, then fold the result as much as possible.
sewardjd2445f62005-03-21 00:15:53 +00002354 Much simplified due to stmt being previously flattened. As a
2355 result of this, the stmt may wind up being turned into a no-op.
2356*/
sewardj62617ef2004-10-13 23:29:22 +00002357static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st )
sewardj84be7372004-08-18 13:59:33 +00002358{
2359# if 0
2360 vex_printf("\nsubst and fold stmt\n");
2361 ppIRStmt(st);
2362 vex_printf("\n");
2363# endif
2364
sewardj62617ef2004-10-13 23:29:22 +00002365 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00002366 case Ist_AbiHint:
2367 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +00002368 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +00002369 return IRStmt_AbiHint(
floriancdb5fee2012-02-13 00:06:29 +00002370 fold_Expr(env, subst_Expr(env, st->Ist.AbiHint.base)),
sewardj478646f2008-05-01 20:13:04 +00002371 st->Ist.AbiHint.len,
floriancdb5fee2012-02-13 00:06:29 +00002372 fold_Expr(env, subst_Expr(env, st->Ist.AbiHint.nia))
sewardj5a9ffab2005-05-12 17:55:01 +00002373 );
sewardj62617ef2004-10-13 23:29:22 +00002374 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00002375 vassert(isIRAtom(st->Ist.Put.data));
sewardj62617ef2004-10-13 23:29:22 +00002376 return IRStmt_Put(
2377 st->Ist.Put.offset,
floriancdb5fee2012-02-13 00:06:29 +00002378 fold_Expr(env, subst_Expr(env, st->Ist.Put.data))
sewardj62617ef2004-10-13 23:29:22 +00002379 );
sewardj84be7372004-08-18 13:59:33 +00002380
floriand6f38b32012-05-31 15:46:18 +00002381 case Ist_PutI: {
2382 IRPutI *puti, *puti2;
2383 puti = st->Ist.PutI.details;
2384 vassert(isIRAtom(puti->ix));
2385 vassert(isIRAtom(puti->data));
2386 puti2 = mkIRPutI(puti->descr,
2387 fold_Expr(env, subst_Expr(env, puti->ix)),
2388 puti->bias,
2389 fold_Expr(env, subst_Expr(env, puti->data)));
2390 return IRStmt_PutI(puti2);
2391 }
sewardjd7217032004-08-19 10:49:10 +00002392
sewardjdd40fdf2006-12-24 02:20:24 +00002393 case Ist_WrTmp:
2394 /* This is the one place where an expr (st->Ist.WrTmp.data) is
sewardj62617ef2004-10-13 23:29:22 +00002395 allowed to be more than just a constant or a tmp. */
sewardjdd40fdf2006-12-24 02:20:24 +00002396 return IRStmt_WrTmp(
2397 st->Ist.WrTmp.tmp,
floriancdb5fee2012-02-13 00:06:29 +00002398 fold_Expr(env, subst_Expr(env, st->Ist.WrTmp.data))
sewardj62617ef2004-10-13 23:29:22 +00002399 );
sewardj84be7372004-08-18 13:59:33 +00002400
sewardjaf1ceca2005-06-30 23:31:27 +00002401 case Ist_Store:
2402 vassert(isIRAtom(st->Ist.Store.addr));
2403 vassert(isIRAtom(st->Ist.Store.data));
2404 return IRStmt_Store(
2405 st->Ist.Store.end,
floriancdb5fee2012-02-13 00:06:29 +00002406 fold_Expr(env, subst_Expr(env, st->Ist.Store.addr)),
2407 fold_Expr(env, subst_Expr(env, st->Ist.Store.data))
sewardj62617ef2004-10-13 23:29:22 +00002408 );
sewardj84be7372004-08-18 13:59:33 +00002409
sewardje9d8a262009-07-01 08:06:34 +00002410 case Ist_CAS: {
2411 IRCAS *cas, *cas2;
2412 cas = st->Ist.CAS.details;
2413 vassert(isIRAtom(cas->addr));
2414 vassert(cas->expdHi == NULL || isIRAtom(cas->expdHi));
2415 vassert(isIRAtom(cas->expdLo));
2416 vassert(cas->dataHi == NULL || isIRAtom(cas->dataHi));
2417 vassert(isIRAtom(cas->dataLo));
2418 cas2 = mkIRCAS(
2419 cas->oldHi, cas->oldLo, cas->end,
floriancdb5fee2012-02-13 00:06:29 +00002420 fold_Expr(env, subst_Expr(env, cas->addr)),
sewardj6399f812012-06-29 15:36:44 +00002421 cas->expdHi ? fold_Expr(env, subst_Expr(env, cas->expdHi))
2422 : NULL,
floriancdb5fee2012-02-13 00:06:29 +00002423 fold_Expr(env, subst_Expr(env, cas->expdLo)),
sewardj6399f812012-06-29 15:36:44 +00002424 cas->dataHi ? fold_Expr(env, subst_Expr(env, cas->dataHi))
2425 : NULL,
floriancdb5fee2012-02-13 00:06:29 +00002426 fold_Expr(env, subst_Expr(env, cas->dataLo))
sewardje9d8a262009-07-01 08:06:34 +00002427 );
2428 return IRStmt_CAS(cas2);
2429 }
2430
sewardje768e922009-11-26 17:17:37 +00002431 case Ist_LLSC:
2432 vassert(isIRAtom(st->Ist.LLSC.addr));
2433 if (st->Ist.LLSC.storedata)
2434 vassert(isIRAtom(st->Ist.LLSC.storedata));
2435 return IRStmt_LLSC(
2436 st->Ist.LLSC.end,
2437 st->Ist.LLSC.result,
floriancdb5fee2012-02-13 00:06:29 +00002438 fold_Expr(env, subst_Expr(env, st->Ist.LLSC.addr)),
sewardje768e922009-11-26 17:17:37 +00002439 st->Ist.LLSC.storedata
floriancdb5fee2012-02-13 00:06:29 +00002440 ? fold_Expr(env, subst_Expr(env, st->Ist.LLSC.storedata))
sewardje768e922009-11-26 17:17:37 +00002441 : NULL
2442 );
2443
sewardj62617ef2004-10-13 23:29:22 +00002444 case Ist_Dirty: {
2445 Int i;
2446 IRDirty *d, *d2;
2447 d = st->Ist.Dirty.details;
2448 d2 = emptyIRDirty();
2449 *d2 = *d;
sewardjdd40fdf2006-12-24 02:20:24 +00002450 d2->args = shallowCopyIRExprVec(d2->args);
sewardj62617ef2004-10-13 23:29:22 +00002451 if (d2->mFx != Ifx_None) {
sewardj496a58d2005-03-20 18:44:44 +00002452 vassert(isIRAtom(d2->mAddr));
floriancdb5fee2012-02-13 00:06:29 +00002453 d2->mAddr = fold_Expr(env, subst_Expr(env, d2->mAddr));
sewardjb8e75862004-08-19 17:58:45 +00002454 }
sewardj496a58d2005-03-20 18:44:44 +00002455 vassert(isIRAtom(d2->guard));
floriancdb5fee2012-02-13 00:06:29 +00002456 d2->guard = fold_Expr(env, subst_Expr(env, d2->guard));
sewardj62617ef2004-10-13 23:29:22 +00002457 for (i = 0; d2->args[i]; i++) {
sewardj496a58d2005-03-20 18:44:44 +00002458 vassert(isIRAtom(d2->args[i]));
floriancdb5fee2012-02-13 00:06:29 +00002459 d2->args[i] = fold_Expr(env, subst_Expr(env, d2->args[i]));
sewardj62617ef2004-10-13 23:29:22 +00002460 }
2461 return IRStmt_Dirty(d2);
sewardjb8e75862004-08-19 17:58:45 +00002462 }
sewardj84be7372004-08-18 13:59:33 +00002463
sewardjf1689312005-03-16 18:19:10 +00002464 case Ist_IMark:
sewardj2f10aa62011-05-27 13:20:56 +00002465 return IRStmt_IMark(st->Ist.IMark.addr,
2466 st->Ist.IMark.len,
2467 st->Ist.IMark.delta);
sewardjf1689312005-03-16 18:19:10 +00002468
sewardjd2445f62005-03-21 00:15:53 +00002469 case Ist_NoOp:
2470 return IRStmt_NoOp();
2471
sewardjc4356f02007-11-09 21:15:04 +00002472 case Ist_MBE:
2473 return IRStmt_MBE(st->Ist.MBE.event);
sewardj3e838932005-01-07 12:09:15 +00002474
sewardj62617ef2004-10-13 23:29:22 +00002475 case Ist_Exit: {
2476 IRExpr* fcond;
sewardj496a58d2005-03-20 18:44:44 +00002477 vassert(isIRAtom(st->Ist.Exit.guard));
floriancdb5fee2012-02-13 00:06:29 +00002478 fcond = fold_Expr(env, subst_Expr(env, st->Ist.Exit.guard));
sewardj62617ef2004-10-13 23:29:22 +00002479 if (fcond->tag == Iex_Const) {
2480 /* Interesting. The condition on this exit has folded down to
2481 a constant. */
sewardjba999312004-11-15 15:21:17 +00002482 vassert(fcond->Iex.Const.con->tag == Ico_U1);
sewardj98430292004-12-29 17:34:50 +00002483 vassert(fcond->Iex.Const.con->Ico.U1 == False
2484 || fcond->Iex.Const.con->Ico.U1 == True);
sewardjba999312004-11-15 15:21:17 +00002485 if (fcond->Iex.Const.con->Ico.U1 == False) {
sewardj62617ef2004-10-13 23:29:22 +00002486 /* exit is never going to happen, so dump the statement. */
sewardjd2445f62005-03-21 00:15:53 +00002487 return IRStmt_NoOp();
sewardj62617ef2004-10-13 23:29:22 +00002488 } else {
sewardjba999312004-11-15 15:21:17 +00002489 vassert(fcond->Iex.Const.con->Ico.U1 == True);
sewardje810c192005-09-09 08:33:03 +00002490 /* Hmmm. The exit has become unconditional. Leave it
2491 as it is for now, since we'd have to truncate the BB
2492 at this point, which is tricky. Such truncation is
2493 done later by the dead-code elimination pass. */
sewardj62617ef2004-10-13 23:29:22 +00002494 /* fall out into the reconstruct-the-exit code. */
sewardj08613742004-10-25 13:01:45 +00002495 if (vex_control.iropt_verbosity > 0)
2496 /* really a misuse of vex_control.iropt_verbosity */
sewardj8c2c10b2004-10-16 20:51:52 +00002497 vex_printf("vex iropt: IRStmt_Exit became unconditional\n");
sewardj62617ef2004-10-13 23:29:22 +00002498 }
2499 }
sewardjc6f970f2012-04-02 21:54:49 +00002500 return IRStmt_Exit(fcond, st->Ist.Exit.jk,
2501 st->Ist.Exit.dst, st->Ist.Exit.offsIP);
sewardj62617ef2004-10-13 23:29:22 +00002502 }
2503
2504 default:
2505 vex_printf("\n"); ppIRStmt(st);
2506 vpanic("subst_and_fold_Stmt");
2507 }
sewardj84be7372004-08-18 13:59:33 +00002508}
2509
2510
sewardjdd40fdf2006-12-24 02:20:24 +00002511IRSB* cprop_BB ( IRSB* in )
sewardj84be7372004-08-18 13:59:33 +00002512{
sewardj62617ef2004-10-13 23:29:22 +00002513 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +00002514 IRSB* out;
sewardj62617ef2004-10-13 23:29:22 +00002515 IRStmt* st2;
2516 Int n_tmps = in->tyenv->types_used;
2517 IRExpr** env = LibVEX_Alloc(n_tmps * sizeof(IRExpr*));
sewardj84be7372004-08-18 13:59:33 +00002518
sewardjdd40fdf2006-12-24 02:20:24 +00002519 out = emptyIRSB();
2520 out->tyenv = deepCopyIRTypeEnv( in->tyenv );
sewardj84be7372004-08-18 13:59:33 +00002521
2522 /* Set up the env with which travels forward. This holds a
floriancdb5fee2012-02-13 00:06:29 +00002523 substitution, mapping IRTemps to IRExprs. The environment
2524 is to be applied as we move along. Keys are IRTemps.
2525 Values are IRExpr*s.
sewardj84be7372004-08-18 13:59:33 +00002526 */
sewardj62617ef2004-10-13 23:29:22 +00002527 for (i = 0; i < n_tmps; i++)
2528 env[i] = NULL;
sewardj84be7372004-08-18 13:59:33 +00002529
2530 /* For each original SSA-form stmt ... */
2531 for (i = 0; i < in->stmts_used; i++) {
2532
2533 /* First apply the substitution to the current stmt. This
2534 propagates in any constants and tmp-tmp assignments
2535 accumulated prior to this point. As part of the subst_Stmt
2536 call, also then fold any constant expressions resulting. */
2537
sewardjf0e43162004-08-20 00:11:12 +00002538 st2 = in->stmts[i];
2539
2540 /* perhaps st2 is already a no-op? */
sewardj8bee6d12005-03-22 02:24:05 +00002541 if (st2->tag == Ist_NoOp) continue;
sewardjf0e43162004-08-20 00:11:12 +00002542
2543 st2 = subst_and_fold_Stmt( env, st2 );
sewardj84be7372004-08-18 13:59:33 +00002544
sewardjb8e75862004-08-19 17:58:45 +00002545 /* If the statement has been folded into a no-op, forget it. */
sewardj8bee6d12005-03-22 02:24:05 +00002546 if (st2->tag == Ist_NoOp) continue;
sewardjb8e75862004-08-19 17:58:45 +00002547
floriancdb5fee2012-02-13 00:06:29 +00002548 /* If the statement assigns to an IRTemp add it to the running
2549 environment. This is for the benefit of copy propagation
2550 and to allow sameIRExpr look through IRTemps. */
2551 if (st2->tag == Ist_WrTmp) {
2552 vassert(env[(Int)(st2->Ist.WrTmp.tmp)] == NULL);
2553 env[(Int)(st2->Ist.WrTmp.tmp)] = st2->Ist.WrTmp.data;
sewardj84be7372004-08-18 13:59:33 +00002554
floriancdb5fee2012-02-13 00:06:29 +00002555 /* 't1 = t2' -- don't add to BB; will be optimized out */
2556 if (st2->Ist.WrTmp.data->tag == Iex_RdTmp) continue;
2557
2558 /* 't = const' && 'const != F64i' -- don't add to BB
2559 Note, we choose not to propagate const when const is an
2560 F64i, so that F64i literals can be CSE'd later. This helps
2561 x86 floating point code generation. */
2562 if (st2->Ist.WrTmp.data->tag == Iex_Const
2563 && st2->Ist.WrTmp.data->Iex.Const.con->tag != Ico_F64i) continue;
sewardj84be7372004-08-18 13:59:33 +00002564 }
floriancdb5fee2012-02-13 00:06:29 +00002565
2566 /* Not interesting, copy st2 into the output block. */
2567 addStmtToIRSB( out, st2 );
sewardj84be7372004-08-18 13:59:33 +00002568 }
2569
floriancdb5fee2012-02-13 00:06:29 +00002570#if STATS_IROPT
2571 vex_printf("sameIRExpr: invoked = %u/%u equal = %u/%u max_nodes = %u\n",
2572 invocation_count, recursion_count, success_count,
2573 recursion_success_count, max_nodes_visited);
2574#endif
2575
sewardj84be7372004-08-18 13:59:33 +00002576 out->next = subst_Expr( env, in->next );
2577 out->jumpkind = in->jumpkind;
sewardjc6f970f2012-04-02 21:54:49 +00002578 out->offsIP = in->offsIP;
sewardj84be7372004-08-18 13:59:33 +00002579 return out;
2580}
2581
2582
sewardjedf4d692004-08-17 13:52:58 +00002583/*---------------------------------------------------------------*/
sewardj39e3f242004-08-18 16:54:52 +00002584/*--- Dead code (t = E) removal ---*/
2585/*---------------------------------------------------------------*/
2586
sewardje810c192005-09-09 08:33:03 +00002587/* As a side effect, also removes all code following an unconditional
2588 side exit. */
2589
sewardjea602bc2004-10-14 21:40:12 +00002590/* The type of the HashHW map is: a map from IRTemp to nothing
sewardj39e3f242004-08-18 16:54:52 +00002591 -- really just operating a set or IRTemps.
2592*/
2593
sewardjd503a322004-10-13 22:41:16 +00002594inline
2595static void addUses_Temp ( Bool* set, IRTemp tmp )
sewardj17442fe2004-09-20 14:54:28 +00002596{
sewardjd503a322004-10-13 22:41:16 +00002597 set[(Int)tmp] = True;
sewardj17442fe2004-09-20 14:54:28 +00002598}
2599
sewardjd503a322004-10-13 22:41:16 +00002600static void addUses_Expr ( Bool* set, IRExpr* e )
sewardj39e3f242004-08-18 16:54:52 +00002601{
2602 Int i;
2603 switch (e->tag) {
sewardjd7217032004-08-19 10:49:10 +00002604 case Iex_GetI:
sewardjeeac8412004-11-02 00:26:55 +00002605 addUses_Expr(set, e->Iex.GetI.ix);
sewardjd7217032004-08-19 10:49:10 +00002606 return;
sewardj39e3f242004-08-18 16:54:52 +00002607 case Iex_Mux0X:
2608 addUses_Expr(set, e->Iex.Mux0X.cond);
2609 addUses_Expr(set, e->Iex.Mux0X.expr0);
2610 addUses_Expr(set, e->Iex.Mux0X.exprX);
2611 return;
2612 case Iex_CCall:
2613 for (i = 0; e->Iex.CCall.args[i]; i++)
2614 addUses_Expr(set, e->Iex.CCall.args[i]);
2615 return;
sewardjaf1ceca2005-06-30 23:31:27 +00002616 case Iex_Load:
2617 addUses_Expr(set, e->Iex.Load.addr);
sewardj39e3f242004-08-18 16:54:52 +00002618 return;
sewardj40c80262006-02-08 19:30:46 +00002619 case Iex_Qop:
florian96d7cc32012-06-01 20:41:24 +00002620 addUses_Expr(set, e->Iex.Qop.details->arg1);
2621 addUses_Expr(set, e->Iex.Qop.details->arg2);
2622 addUses_Expr(set, e->Iex.Qop.details->arg3);
2623 addUses_Expr(set, e->Iex.Qop.details->arg4);
sewardj40c80262006-02-08 19:30:46 +00002624 return;
sewardjb183b852006-02-03 16:08:03 +00002625 case Iex_Triop:
florian420bfa92012-06-02 20:29:22 +00002626 addUses_Expr(set, e->Iex.Triop.details->arg1);
2627 addUses_Expr(set, e->Iex.Triop.details->arg2);
2628 addUses_Expr(set, e->Iex.Triop.details->arg3);
sewardjb183b852006-02-03 16:08:03 +00002629 return;
sewardj39e3f242004-08-18 16:54:52 +00002630 case Iex_Binop:
2631 addUses_Expr(set, e->Iex.Binop.arg1);
2632 addUses_Expr(set, e->Iex.Binop.arg2);
2633 return;
2634 case Iex_Unop:
2635 addUses_Expr(set, e->Iex.Unop.arg);
2636 return;
sewardjdd40fdf2006-12-24 02:20:24 +00002637 case Iex_RdTmp:
2638 addUses_Temp(set, e->Iex.RdTmp.tmp);
sewardj39e3f242004-08-18 16:54:52 +00002639 return;
2640 case Iex_Const:
2641 case Iex_Get:
2642 return;
2643 default:
2644 vex_printf("\n");
2645 ppIRExpr(e);
2646 vpanic("addUses_Expr");
2647 }
2648}
2649
sewardjd503a322004-10-13 22:41:16 +00002650static void addUses_Stmt ( Bool* set, IRStmt* st )
sewardj39e3f242004-08-18 16:54:52 +00002651{
sewardj17442fe2004-09-20 14:54:28 +00002652 Int i;
2653 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00002654 IRCAS* cas;
sewardj39e3f242004-08-18 16:54:52 +00002655 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00002656 case Ist_AbiHint:
2657 addUses_Expr(set, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +00002658 addUses_Expr(set, st->Ist.AbiHint.nia);
sewardj5a9ffab2005-05-12 17:55:01 +00002659 return;
sewardjd7217032004-08-19 10:49:10 +00002660 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +00002661 addUses_Expr(set, st->Ist.PutI.details->ix);
2662 addUses_Expr(set, st->Ist.PutI.details->data);
sewardjd7217032004-08-19 10:49:10 +00002663 return;
sewardjdd40fdf2006-12-24 02:20:24 +00002664 case Ist_WrTmp:
2665 addUses_Expr(set, st->Ist.WrTmp.data);
sewardj39e3f242004-08-18 16:54:52 +00002666 return;
2667 case Ist_Put:
sewardj6d076362004-09-23 11:06:17 +00002668 addUses_Expr(set, st->Ist.Put.data);
sewardj39e3f242004-08-18 16:54:52 +00002669 return;
sewardjaf1ceca2005-06-30 23:31:27 +00002670 case Ist_Store:
2671 addUses_Expr(set, st->Ist.Store.addr);
2672 addUses_Expr(set, st->Ist.Store.data);
sewardj39e3f242004-08-18 16:54:52 +00002673 return;
sewardje9d8a262009-07-01 08:06:34 +00002674 case Ist_CAS:
2675 cas = st->Ist.CAS.details;
2676 addUses_Expr(set, cas->addr);
2677 if (cas->expdHi)
2678 addUses_Expr(set, cas->expdHi);
2679 addUses_Expr(set, cas->expdLo);
2680 if (cas->dataHi)
2681 addUses_Expr(set, cas->dataHi);
2682 addUses_Expr(set, cas->dataLo);
2683 return;
sewardje768e922009-11-26 17:17:37 +00002684 case Ist_LLSC:
2685 addUses_Expr(set, st->Ist.LLSC.addr);
2686 if (st->Ist.LLSC.storedata)
2687 addUses_Expr(set, st->Ist.LLSC.storedata);
2688 return;
sewardj17442fe2004-09-20 14:54:28 +00002689 case Ist_Dirty:
2690 d = st->Ist.Dirty.details;
2691 if (d->mFx != Ifx_None)
2692 addUses_Expr(set, d->mAddr);
sewardjb8385d82004-11-02 01:34:15 +00002693 addUses_Expr(set, d->guard);
sewardj17442fe2004-09-20 14:54:28 +00002694 for (i = 0; d->args[i] != NULL; i++)
2695 addUses_Expr(set, d->args[i]);
2696 return;
sewardjd2445f62005-03-21 00:15:53 +00002697 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00002698 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00002699 case Ist_MBE:
sewardj3e838932005-01-07 12:09:15 +00002700 return;
sewardj17442fe2004-09-20 14:54:28 +00002701 case Ist_Exit:
sewardj0276d4b2004-11-15 15:30:21 +00002702 addUses_Expr(set, st->Ist.Exit.guard);
sewardj17442fe2004-09-20 14:54:28 +00002703 return;
sewardj39e3f242004-08-18 16:54:52 +00002704 default:
2705 vex_printf("\n");
2706 ppIRStmt(st);
2707 vpanic("addUses_Stmt");
sewardjd503a322004-10-13 22:41:16 +00002708 }
sewardj39e3f242004-08-18 16:54:52 +00002709}
2710
2711
sewardjba999312004-11-15 15:21:17 +00002712/* Is this literally IRExpr_Const(IRConst_U1(False)) ? */
2713static Bool isZeroU1 ( IRExpr* e )
sewardjd9997882004-11-04 19:42:59 +00002714{
sewardj9d2e7692005-02-07 01:11:31 +00002715 return toBool( e->tag == Iex_Const
2716 && e->Iex.Const.con->tag == Ico_U1
2717 && e->Iex.Const.con->Ico.U1 == False );
sewardjd9997882004-11-04 19:42:59 +00002718}
2719
sewardje810c192005-09-09 08:33:03 +00002720/* Is this literally IRExpr_Const(IRConst_U1(True)) ? */
2721static Bool isOneU1 ( IRExpr* e )
2722{
2723 return toBool( e->tag == Iex_Const
2724 && e->Iex.Const.con->tag == Ico_U1
2725 && e->Iex.Const.con->Ico.U1 == True );
2726}
2727
sewardj39e3f242004-08-18 16:54:52 +00002728
sewardjdd40fdf2006-12-24 02:20:24 +00002729/* Note, this destructively modifies the given IRSB. */
sewardj39e3f242004-08-18 16:54:52 +00002730
2731/* Scan backwards through statements, carrying a set of IRTemps which
2732 are known to be used after the current point. On encountering 't =
2733 E', delete the binding if it is not used. Otherwise, add any temp
sewardje810c192005-09-09 08:33:03 +00002734 uses to the set and keep on moving backwards.
2735
2736 As an enhancement, the first (backwards) pass searches for IR exits
2737 with always-taken conditions and notes the location of the earliest
2738 one in the block. If any such are found, a second pass copies the
2739 exit destination and jump kind to the bb-end. Then, the exit and
2740 all statements following it are turned into no-ops.
2741*/
sewardj39e3f242004-08-18 16:54:52 +00002742
sewardjdd40fdf2006-12-24 02:20:24 +00002743/* notstatic */ void do_deadcode_BB ( IRSB* bb )
sewardj39e3f242004-08-18 16:54:52 +00002744{
sewardje810c192005-09-09 08:33:03 +00002745 Int i, i_unconditional_exit;
sewardjd503a322004-10-13 22:41:16 +00002746 Int n_tmps = bb->tyenv->types_used;
2747 Bool* set = LibVEX_Alloc(n_tmps * sizeof(Bool));
sewardj39e3f242004-08-18 16:54:52 +00002748 IRStmt* st;
2749
sewardjd503a322004-10-13 22:41:16 +00002750 for (i = 0; i < n_tmps; i++)
2751 set[i] = False;
2752
sewardj39e3f242004-08-18 16:54:52 +00002753 /* start off by recording IRTemp uses in the next field. */
2754 addUses_Expr(set, bb->next);
2755
sewardje810c192005-09-09 08:33:03 +00002756 /* First pass */
2757
sewardj39e3f242004-08-18 16:54:52 +00002758 /* Work backwards through the stmts */
sewardje810c192005-09-09 08:33:03 +00002759 i_unconditional_exit = -1;
sewardj39e3f242004-08-18 16:54:52 +00002760 for (i = bb->stmts_used-1; i >= 0; i--) {
2761 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00002762 if (st->tag == Ist_NoOp)
sewardj84ff0652004-08-23 16:16:08 +00002763 continue;
sewardje810c192005-09-09 08:33:03 +00002764 /* take note of any unconditional exits */
2765 if (st->tag == Ist_Exit
2766 && isOneU1(st->Ist.Exit.guard))
2767 i_unconditional_exit = i;
sewardjdd40fdf2006-12-24 02:20:24 +00002768 if (st->tag == Ist_WrTmp
2769 && set[(Int)(st->Ist.WrTmp.tmp)] == False) {
sewardj39e3f242004-08-18 16:54:52 +00002770 /* it's an IRTemp which never got used. Delete it. */
sewardj088bcb42004-08-19 17:16:52 +00002771 if (DEBUG_IROPT) {
sewardj39e3f242004-08-18 16:54:52 +00002772 vex_printf("DEAD: ");
2773 ppIRStmt(st);
2774 vex_printf("\n");
2775 }
sewardjd2445f62005-03-21 00:15:53 +00002776 bb->stmts[i] = IRStmt_NoOp();
sewardjd9997882004-11-04 19:42:59 +00002777 }
2778 else
2779 if (st->tag == Ist_Dirty
2780 && st->Ist.Dirty.details->guard
sewardjba999312004-11-15 15:21:17 +00002781 && isZeroU1(st->Ist.Dirty.details->guard)) {
sewardjd2445f62005-03-21 00:15:53 +00002782 /* This is a dirty helper which will never get called.
2783 Delete it. */
2784 bb->stmts[i] = IRStmt_NoOp();
sewardjd9997882004-11-04 19:42:59 +00002785 }
2786 else {
sewardj39e3f242004-08-18 16:54:52 +00002787 /* Note any IRTemp uses made by the current statement. */
2788 addUses_Stmt(set, st);
2789 }
2790 }
sewardje810c192005-09-09 08:33:03 +00002791
2792 /* Optional second pass: if any unconditional exits were found,
2793 delete them and all following statements. */
2794
2795 if (i_unconditional_exit != -1) {
2796 if (0) vex_printf("ZAPPING ALL FORWARDS from %d\n",
2797 i_unconditional_exit);
2798 vassert(i_unconditional_exit >= 0
2799 && i_unconditional_exit < bb->stmts_used);
2800 bb->next
2801 = IRExpr_Const( bb->stmts[i_unconditional_exit]->Ist.Exit.dst );
2802 bb->jumpkind
2803 = bb->stmts[i_unconditional_exit]->Ist.Exit.jk;
sewardjc6f970f2012-04-02 21:54:49 +00002804 bb->offsIP
2805 = bb->stmts[i_unconditional_exit]->Ist.Exit.offsIP;
sewardje810c192005-09-09 08:33:03 +00002806 for (i = i_unconditional_exit; i < bb->stmts_used; i++)
2807 bb->stmts[i] = IRStmt_NoOp();
2808 }
sewardj39e3f242004-08-18 16:54:52 +00002809}
2810
sewardje810c192005-09-09 08:33:03 +00002811
sewardj84ff0652004-08-23 16:16:08 +00002812/*---------------------------------------------------------------*/
2813/*--- Specialisation of helper function calls, in ---*/
2814/*--- collaboration with the front end ---*/
2815/*---------------------------------------------------------------*/
2816
2817static
sewardjbe917912010-08-22 12:38:53 +00002818IRSB* spec_helpers_BB(
2819 IRSB* bb,
florian1ff47562012-10-21 02:09:51 +00002820 IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int)
sewardjbe917912010-08-22 12:38:53 +00002821 )
sewardj84ff0652004-08-23 16:16:08 +00002822{
sewardjb9230752004-12-29 19:25:06 +00002823 Int i;
sewardj84ff0652004-08-23 16:16:08 +00002824 IRStmt* st;
2825 IRExpr* ex;
sewardjb9230752004-12-29 19:25:06 +00002826 Bool any = False;
sewardj84ff0652004-08-23 16:16:08 +00002827
2828 for (i = bb->stmts_used-1; i >= 0; i--) {
2829 st = bb->stmts[i];
2830
sewardjdd40fdf2006-12-24 02:20:24 +00002831 if (st->tag != Ist_WrTmp
2832 || st->Ist.WrTmp.data->tag != Iex_CCall)
sewardj8bee6d12005-03-22 02:24:05 +00002833 continue;
sewardj84ff0652004-08-23 16:16:08 +00002834
sewardjdd40fdf2006-12-24 02:20:24 +00002835 ex = (*specHelper)( st->Ist.WrTmp.data->Iex.CCall.cee->name,
sewardjbe917912010-08-22 12:38:53 +00002836 st->Ist.WrTmp.data->Iex.CCall.args,
2837 &bb->stmts[0], i );
sewardj84ff0652004-08-23 16:16:08 +00002838 if (!ex)
sewardjaba4fff2004-10-08 21:37:15 +00002839 /* the front end can't think of a suitable replacement */
2840 continue;
sewardj84ff0652004-08-23 16:16:08 +00002841
2842 /* We got something better. Install it in the bb. */
sewardjb9230752004-12-29 19:25:06 +00002843 any = True;
sewardj84ff0652004-08-23 16:16:08 +00002844 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00002845 = IRStmt_WrTmp(st->Ist.WrTmp.tmp, ex);
sewardj84ff0652004-08-23 16:16:08 +00002846
2847 if (0) {
2848 vex_printf("SPEC: ");
sewardjdd40fdf2006-12-24 02:20:24 +00002849 ppIRExpr(st->Ist.WrTmp.data);
sewardj84ff0652004-08-23 16:16:08 +00002850 vex_printf(" --> ");
2851 ppIRExpr(ex);
2852 vex_printf("\n");
2853 }
2854 }
sewardjb9230752004-12-29 19:25:06 +00002855
2856 if (any)
2857 bb = flatten_BB(bb);
2858 return bb;
sewardj84ff0652004-08-23 16:16:08 +00002859}
2860
sewardj29632392004-08-22 02:38:11 +00002861
2862/*---------------------------------------------------------------*/
sewardj9b0cc582006-02-04 15:24:00 +00002863/*--- Determination of guest state aliasing relationships ---*/
2864/*---------------------------------------------------------------*/
2865
2866/* These are helper functions for CSE and GetI/PutI transformations.
2867
2868 Determine, to the extent possible, the relationship between two
2869 guest state accesses. The possible outcomes are:
2870
2871 * Exact alias. These two accesses denote precisely the same
2872 piece of the guest state.
2873
2874 * Definitely no alias. These two accesses are guaranteed not to
2875 overlap any part of the guest state.
2876
2877 * Unknown -- if neither of the above can be established.
2878
2879 If in doubt, return Unknown. */
2880
2881typedef
2882 enum { ExactAlias, NoAlias, UnknownAlias }
2883 GSAliasing;
2884
2885
2886/* Produces the alias relation between an indexed guest
2887 state access and a non-indexed access. */
2888
2889static
sewardjdd40fdf2006-12-24 02:20:24 +00002890GSAliasing getAliasingRelation_IC ( IRRegArray* descr1, IRExpr* ix1,
sewardj9b0cc582006-02-04 15:24:00 +00002891 Int offset2, IRType ty2 )
2892{
2893 UInt minoff1, maxoff1, minoff2, maxoff2;
2894
2895 getArrayBounds( descr1, &minoff1, &maxoff1 );
2896 minoff2 = offset2;
2897 maxoff2 = minoff2 + sizeofIRType(ty2) - 1;
2898
2899 if (maxoff1 < minoff2 || maxoff2 < minoff1)
2900 return NoAlias;
2901
2902 /* Could probably do better here if required. For the moment
2903 however just claim not to know anything more. */
2904 return UnknownAlias;
2905}
2906
2907
2908/* Produces the alias relation between two indexed guest state
2909 accesses. */
2910
2911static
2912GSAliasing getAliasingRelation_II (
sewardjdd40fdf2006-12-24 02:20:24 +00002913 IRRegArray* descr1, IRExpr* ix1, Int bias1,
2914 IRRegArray* descr2, IRExpr* ix2, Int bias2
sewardj9b0cc582006-02-04 15:24:00 +00002915 )
2916{
2917 UInt minoff1, maxoff1, minoff2, maxoff2;
2918 Int iters;
2919
2920 /* First try hard to show they don't alias. */
2921 getArrayBounds( descr1, &minoff1, &maxoff1 );
2922 getArrayBounds( descr2, &minoff2, &maxoff2 );
2923 if (maxoff1 < minoff2 || maxoff2 < minoff1)
2924 return NoAlias;
2925
2926 /* So the two arrays at least partially overlap. To get any
2927 further we'll have to be sure that the descriptors are
2928 identical. */
sewardjdd40fdf2006-12-24 02:20:24 +00002929 if (!eqIRRegArray(descr1, descr2))
sewardj9b0cc582006-02-04 15:24:00 +00002930 return UnknownAlias;
2931
2932 /* The descriptors are identical. Now the only difference can be
2933 in the index expressions. If they cannot be shown to be
2934 identical, we have to say we don't know what the aliasing
2935 relation will be. Now, since the IR is flattened, the index
2936 expressions should be atoms -- either consts or tmps. So that
2937 makes the comparison simple. */
2938 vassert(isIRAtom(ix1));
2939 vassert(isIRAtom(ix2));
2940 if (!eqIRAtom(ix1,ix2))
2941 return UnknownAlias;
2942
2943 /* Ok, the index expressions are identical. So now the only way
2944 they can be different is in the bias. Normalise this
2945 paranoidly, to reliably establish equality/non-equality. */
2946
2947 /* So now we know that the GetI and PutI index the same array
2948 with the same base. Are the offsets the same, modulo the
2949 array size? Do this paranoidly. */
2950 vassert(descr1->nElems == descr2->nElems);
2951 vassert(descr1->elemTy == descr2->elemTy);
2952 vassert(descr1->base == descr2->base);
2953 iters = 0;
2954 while (bias1 < 0 || bias2 < 0) {
2955 bias1 += descr1->nElems;
2956 bias2 += descr1->nElems;
2957 iters++;
2958 if (iters > 10)
2959 vpanic("getAliasingRelation: iters");
2960 }
2961 vassert(bias1 >= 0 && bias2 >= 0);
2962 bias1 %= descr1->nElems;
2963 bias2 %= descr1->nElems;
2964 vassert(bias1 >= 0 && bias1 < descr1->nElems);
2965 vassert(bias2 >= 0 && bias2 < descr1->nElems);
2966
2967 /* Finally, biasP and biasG are normalised into the range
2968 0 .. descrP/G->nElems - 1. And so we can establish
2969 equality/non-equality. */
2970
2971 return bias1==bias2 ? ExactAlias : NoAlias;
2972}
2973
2974
2975/*---------------------------------------------------------------*/
sewardj08210532004-12-29 17:09:11 +00002976/*--- Common Subexpression Elimination ---*/
2977/*---------------------------------------------------------------*/
2978
2979/* Expensive in time and space. */
2980
2981/* Uses two environments:
2982 a IRTemp -> IRTemp mapping
2983 a mapping from AvailExpr* to IRTemp
2984*/
2985
2986typedef
2987 struct {
sewardje8578042012-04-13 11:42:50 +00002988 enum { TCc, TCt } tag;
2989 union { IRTemp tmp; IRConst* con; } u;
2990 }
2991 TmpOrConst;
2992
2993static Bool eqTmpOrConst ( TmpOrConst* tc1, TmpOrConst* tc2 )
2994{
2995 if (tc1->tag != tc2->tag)
2996 return False;
2997 switch (tc1->tag) {
2998 case TCc:
2999 return eqIRConst(tc1->u.con, tc2->u.con);
3000 case TCt:
3001 return tc1->u.tmp == tc2->u.tmp;
3002 default:
3003 vpanic("eqTmpOrConst");
3004 }
3005}
3006
3007static Bool eqIRCallee ( IRCallee* cee1, IRCallee* cee2 )
3008{
3009 Bool eq = cee1->addr == cee2->addr;
3010 if (eq) {
3011 vassert(cee1->regparms == cee2->regparms);
3012 vassert(cee1->mcx_mask == cee2->mcx_mask);
3013 /* Names should be the same too, but we don't bother to
3014 check. */
3015 }
3016 return eq;
3017}
3018
3019/* Convert a NULL terminated IRExpr* vector to an array of
3020 TmpOrConsts, and a length. */
3021static void irExprVec_to_TmpOrConsts ( /*OUT*/TmpOrConst** outs,
3022 /*OUT*/Int* nOuts,
3023 IRExpr** ins )
3024{
3025 Int i, n;
3026 /* We have to make two passes, one to count, one to copy. */
3027 for (n = 0; ins[n]; n++)
3028 ;
3029 *outs = LibVEX_Alloc(n * sizeof(TmpOrConst));
3030 *nOuts = n;
3031 /* and now copy .. */
3032 for (i = 0; i < n; i++) {
3033 IRExpr* arg = ins[i];
3034 TmpOrConst* dst = &(*outs)[i];
3035 if (arg->tag == Iex_RdTmp) {
3036 dst->tag = TCt;
3037 dst->u.tmp = arg->Iex.RdTmp.tmp;
3038 }
3039 else if (arg->tag == Iex_Const) {
3040 dst->tag = TCc;
3041 dst->u.con = arg->Iex.Const.con;
3042 }
3043 else {
3044 /* Failure of this is serious; it means that the presented arg
3045 isn't an IR atom, as it should be. */
3046 vpanic("irExprVec_to_TmpOrConsts");
3047 }
3048 }
3049}
3050
3051typedef
3052 struct {
florianda25edd2012-09-12 16:40:54 +00003053 enum { Ut, Btt, Btc, Bct, Cf64i, Mttt, Mtct, Mttc, Mtcc, GetIt,
3054 CCall
3055 } tag;
sewardj08210532004-12-29 17:09:11 +00003056 union {
3057 /* unop(tmp) */
3058 struct {
3059 IROp op;
3060 IRTemp arg;
3061 } Ut;
3062 /* binop(tmp,tmp) */
3063 struct {
3064 IROp op;
3065 IRTemp arg1;
3066 IRTemp arg2;
3067 } Btt;
3068 /* binop(tmp,const) */
3069 struct {
3070 IROp op;
3071 IRTemp arg1;
3072 IRConst con2;
3073 } Btc;
3074 /* binop(const,tmp) */
3075 struct {
3076 IROp op;
3077 IRConst con1;
3078 IRTemp arg2;
3079 } Bct;
3080 /* F64i-style const */
3081 struct {
3082 ULong f64i;
3083 } Cf64i;
sewardj9b0cc582006-02-04 15:24:00 +00003084 /* Mux0X(tmp,tmp,tmp) */
3085 struct {
3086 IRTemp co;
3087 IRTemp e0;
3088 IRTemp eX;
3089 } Mttt;
florianda25edd2012-09-12 16:40:54 +00003090 /* Mux0X(tmp,const,tmp) */
3091 struct {
3092 IRTemp co;
3093 IRConst con0;
3094 IRTemp eX;
3095 } Mtct;
3096 /* Mux0X(tmp,tmp,const) */
3097 struct {
3098 IRTemp co;
3099 IRTemp e0;
3100 IRConst conX;
3101 } Mttc;
3102 /* Mux0X(tmp,const,const) */
3103 struct {
3104 IRTemp co;
3105 IRConst con0;
3106 IRConst conX;
3107 } Mtcc;
sewardj9b0cc582006-02-04 15:24:00 +00003108 /* GetI(descr,tmp,bias)*/
3109 struct {
sewardjdd40fdf2006-12-24 02:20:24 +00003110 IRRegArray* descr;
3111 IRTemp ix;
3112 Int bias;
sewardj9b0cc582006-02-04 15:24:00 +00003113 } GetIt;
sewardje8578042012-04-13 11:42:50 +00003114 /* Clean helper call */
3115 struct {
3116 IRCallee* cee;
3117 TmpOrConst* args;
3118 Int nArgs;
3119 IRType retty;
3120 } CCall;
sewardj08210532004-12-29 17:09:11 +00003121 } u;
3122 }
3123 AvailExpr;
3124
3125static Bool eq_AvailExpr ( AvailExpr* a1, AvailExpr* a2 )
3126{
sewardje8578042012-04-13 11:42:50 +00003127 if (LIKELY(a1->tag != a2->tag))
sewardj08210532004-12-29 17:09:11 +00003128 return False;
3129 switch (a1->tag) {
3130 case Ut:
sewardj9d2e7692005-02-07 01:11:31 +00003131 return toBool(
3132 a1->u.Ut.op == a2->u.Ut.op
3133 && a1->u.Ut.arg == a2->u.Ut.arg);
sewardj08210532004-12-29 17:09:11 +00003134 case Btt:
sewardj9d2e7692005-02-07 01:11:31 +00003135 return toBool(
3136 a1->u.Btt.op == a2->u.Btt.op
sewardj08210532004-12-29 17:09:11 +00003137 && a1->u.Btt.arg1 == a2->u.Btt.arg1
sewardj9d2e7692005-02-07 01:11:31 +00003138 && a1->u.Btt.arg2 == a2->u.Btt.arg2);
sewardj08210532004-12-29 17:09:11 +00003139 case Btc:
sewardj9d2e7692005-02-07 01:11:31 +00003140 return toBool(
3141 a1->u.Btc.op == a2->u.Btc.op
sewardj08210532004-12-29 17:09:11 +00003142 && a1->u.Btc.arg1 == a2->u.Btc.arg1
sewardj9d2e7692005-02-07 01:11:31 +00003143 && eqIRConst(&a1->u.Btc.con2, &a2->u.Btc.con2));
sewardj08210532004-12-29 17:09:11 +00003144 case Bct:
sewardj9d2e7692005-02-07 01:11:31 +00003145 return toBool(
3146 a1->u.Bct.op == a2->u.Bct.op
sewardj08210532004-12-29 17:09:11 +00003147 && a1->u.Bct.arg2 == a2->u.Bct.arg2
sewardj9d2e7692005-02-07 01:11:31 +00003148 && eqIRConst(&a1->u.Bct.con1, &a2->u.Bct.con1));
sewardj08210532004-12-29 17:09:11 +00003149 case Cf64i:
sewardj9d2e7692005-02-07 01:11:31 +00003150 return toBool(a1->u.Cf64i.f64i == a2->u.Cf64i.f64i);
sewardj9b0cc582006-02-04 15:24:00 +00003151 case Mttt:
3152 return toBool(a1->u.Mttt.co == a2->u.Mttt.co
3153 && a1->u.Mttt.e0 == a2->u.Mttt.e0
3154 && a1->u.Mttt.eX == a2->u.Mttt.eX);
florianda25edd2012-09-12 16:40:54 +00003155 case Mtct:
3156 return toBool(a1->u.Mtct.co == a2->u.Mtct.co
3157 && eqIRConst(&a1->u.Mtct.con0, &a2->u.Mtct.con0)
3158 && a1->u.Mtct.eX == a2->u.Mtct.eX);
3159 case Mttc:
3160 return toBool(a1->u.Mttc.co == a2->u.Mttc.co
3161 && a1->u.Mttc.e0 == a2->u.Mttc.e0
3162 && eqIRConst(&a1->u.Mttc.conX, &a2->u.Mttc.conX));
3163 case Mtcc:
3164 return toBool(a1->u.Mtcc.co == a2->u.Mtcc.co
3165 && eqIRConst(&a1->u.Mtcc.con0, &a2->u.Mtcc.con0)
3166 && eqIRConst(&a1->u.Mtcc.conX, &a2->u.Mtcc.conX));
sewardj9b0cc582006-02-04 15:24:00 +00003167 case GetIt:
sewardjdd40fdf2006-12-24 02:20:24 +00003168 return toBool(eqIRRegArray(a1->u.GetIt.descr, a2->u.GetIt.descr)
sewardj9b0cc582006-02-04 15:24:00 +00003169 && a1->u.GetIt.ix == a2->u.GetIt.ix
3170 && a1->u.GetIt.bias == a2->u.GetIt.bias);
sewardje8578042012-04-13 11:42:50 +00003171 case CCall: {
3172 Int i, n;
3173 Bool eq = a1->u.CCall.nArgs == a2->u.CCall.nArgs
3174 && eqIRCallee(a1->u.CCall.cee, a2->u.CCall.cee);
3175 if (eq) {
3176 n = a1->u.CCall.nArgs;
3177 for (i = 0; i < n; i++) {
3178 if (!eqTmpOrConst( &a1->u.CCall.args[i],
3179 &a2->u.CCall.args[i] )) {
3180 eq = False;
3181 break;
3182 }
3183 }
3184 }
3185 if (eq) vassert(a1->u.CCall.retty == a2->u.CCall.retty);
3186 return eq;
3187 }
sewardj08210532004-12-29 17:09:11 +00003188 default: vpanic("eq_AvailExpr");
3189 }
3190}
3191
3192static IRExpr* availExpr_to_IRExpr ( AvailExpr* ae )
3193{
florianda25edd2012-09-12 16:40:54 +00003194 IRConst *con, *con0, *conX;
sewardj08210532004-12-29 17:09:11 +00003195 switch (ae->tag) {
3196 case Ut:
sewardjdd40fdf2006-12-24 02:20:24 +00003197 return IRExpr_Unop( ae->u.Ut.op, IRExpr_RdTmp(ae->u.Ut.arg) );
sewardj08210532004-12-29 17:09:11 +00003198 case Btt:
3199 return IRExpr_Binop( ae->u.Btt.op,
sewardjdd40fdf2006-12-24 02:20:24 +00003200 IRExpr_RdTmp(ae->u.Btt.arg1),
3201 IRExpr_RdTmp(ae->u.Btt.arg2) );
sewardj08210532004-12-29 17:09:11 +00003202 case Btc:
3203 con = LibVEX_Alloc(sizeof(IRConst));
3204 *con = ae->u.Btc.con2;
3205 return IRExpr_Binop( ae->u.Btc.op,
sewardjdd40fdf2006-12-24 02:20:24 +00003206 IRExpr_RdTmp(ae->u.Btc.arg1),
3207 IRExpr_Const(con) );
sewardj08210532004-12-29 17:09:11 +00003208 case Bct:
3209 con = LibVEX_Alloc(sizeof(IRConst));
3210 *con = ae->u.Bct.con1;
3211 return IRExpr_Binop( ae->u.Bct.op,
sewardjdd40fdf2006-12-24 02:20:24 +00003212 IRExpr_Const(con),
3213 IRExpr_RdTmp(ae->u.Bct.arg2) );
sewardj08210532004-12-29 17:09:11 +00003214 case Cf64i:
3215 return IRExpr_Const(IRConst_F64i(ae->u.Cf64i.f64i));
sewardj9b0cc582006-02-04 15:24:00 +00003216 case Mttt:
sewardjdd40fdf2006-12-24 02:20:24 +00003217 return IRExpr_Mux0X(IRExpr_RdTmp(ae->u.Mttt.co),
3218 IRExpr_RdTmp(ae->u.Mttt.e0),
3219 IRExpr_RdTmp(ae->u.Mttt.eX));
florianda25edd2012-09-12 16:40:54 +00003220 case Mtct:
3221 con0 = LibVEX_Alloc(sizeof(IRConst));
3222 *con0 = ae->u.Mtct.con0;
3223 return IRExpr_Mux0X(IRExpr_RdTmp(ae->u.Mtct.co),
3224 IRExpr_Const(con0),
3225 IRExpr_RdTmp(ae->u.Mtct.eX));
3226 case Mttc:
3227 conX = LibVEX_Alloc(sizeof(IRConst));
3228 *conX = ae->u.Mttc.conX;
3229 return IRExpr_Mux0X(IRExpr_RdTmp(ae->u.Mttc.co),
3230 IRExpr_RdTmp(ae->u.Mttc.e0),
3231 IRExpr_Const(conX));
3232 case Mtcc:
3233 con0 = LibVEX_Alloc(sizeof(IRConst));
3234 conX = LibVEX_Alloc(sizeof(IRConst));
3235 *con0 = ae->u.Mtcc.con0;
3236 *conX = ae->u.Mtcc.conX;
3237 return IRExpr_Mux0X(IRExpr_RdTmp(ae->u.Mtcc.co),
3238 IRExpr_Const(con0),
3239 IRExpr_Const(conX));
sewardj9b0cc582006-02-04 15:24:00 +00003240 case GetIt:
3241 return IRExpr_GetI(ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003242 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00003243 ae->u.GetIt.bias);
sewardje8578042012-04-13 11:42:50 +00003244 case CCall: {
3245 Int i, n = ae->u.CCall.nArgs;
3246 vassert(n >= 0);
3247 IRExpr** vec = LibVEX_Alloc((n+1) * sizeof(IRExpr*));
3248 vec[n] = NULL;
3249 for (i = 0; i < n; i++) {
3250 TmpOrConst* tc = &ae->u.CCall.args[i];
3251 if (tc->tag == TCc) {
3252 vec[i] = IRExpr_Const(tc->u.con);
3253 }
3254 else if (tc->tag == TCt) {
3255 vec[i] = IRExpr_RdTmp(tc->u.tmp);
3256 }
3257 else vpanic("availExpr_to_IRExpr:CCall-arg");
3258 }
3259 return IRExpr_CCall(ae->u.CCall.cee,
3260 ae->u.CCall.retty,
3261 vec);
3262 }
sewardj08210532004-12-29 17:09:11 +00003263 default:
3264 vpanic("availExpr_to_IRExpr");
3265 }
3266}
3267
3268inline
3269static IRTemp subst_AvailExpr_Temp ( HashHW* env, IRTemp tmp )
3270{
3271 HWord res;
3272 /* env :: IRTemp -> IRTemp */
3273 if (lookupHHW( env, &res, (HWord)tmp ))
3274 return (IRTemp)res;
3275 else
3276 return tmp;
3277}
3278
3279static void subst_AvailExpr ( HashHW* env, AvailExpr* ae )
3280{
3281 /* env :: IRTemp -> IRTemp */
3282 switch (ae->tag) {
3283 case Ut:
3284 ae->u.Ut.arg = subst_AvailExpr_Temp( env, ae->u.Ut.arg );
3285 break;
3286 case Btt:
3287 ae->u.Btt.arg1 = subst_AvailExpr_Temp( env, ae->u.Btt.arg1 );
3288 ae->u.Btt.arg2 = subst_AvailExpr_Temp( env, ae->u.Btt.arg2 );
3289 break;
3290 case Btc:
3291 ae->u.Btc.arg1 = subst_AvailExpr_Temp( env, ae->u.Btc.arg1 );
3292 break;
3293 case Bct:
3294 ae->u.Bct.arg2 = subst_AvailExpr_Temp( env, ae->u.Bct.arg2 );
3295 break;
3296 case Cf64i:
3297 break;
sewardj9b0cc582006-02-04 15:24:00 +00003298 case Mttt:
3299 ae->u.Mttt.co = subst_AvailExpr_Temp( env, ae->u.Mttt.co );
3300 ae->u.Mttt.e0 = subst_AvailExpr_Temp( env, ae->u.Mttt.e0 );
3301 ae->u.Mttt.eX = subst_AvailExpr_Temp( env, ae->u.Mttt.eX );
3302 break;
florianda25edd2012-09-12 16:40:54 +00003303 case Mtct:
3304 ae->u.Mtct.co = subst_AvailExpr_Temp( env, ae->u.Mtct.co );
3305 ae->u.Mtct.eX = subst_AvailExpr_Temp( env, ae->u.Mtct.eX );
3306 break;
3307 case Mttc:
3308 ae->u.Mttc.co = subst_AvailExpr_Temp( env, ae->u.Mttc.co );
3309 ae->u.Mttc.e0 = subst_AvailExpr_Temp( env, ae->u.Mttc.e0 );
3310 break;
3311 case Mtcc:
3312 ae->u.Mtcc.co = subst_AvailExpr_Temp( env, ae->u.Mtcc.co );
3313 break;
sewardj9b0cc582006-02-04 15:24:00 +00003314 case GetIt:
3315 ae->u.GetIt.ix = subst_AvailExpr_Temp( env, ae->u.GetIt.ix );
3316 break;
sewardje8578042012-04-13 11:42:50 +00003317 case CCall: {
3318 Int i, n = ae->u.CCall.nArgs;;
3319 for (i = 0; i < n; i++) {
3320 TmpOrConst* tc = &ae->u.CCall.args[i];
3321 if (tc->tag == TCt) {
3322 tc->u.tmp = subst_AvailExpr_Temp( env, tc->u.tmp );
3323 }
3324 }
3325 break;
3326 }
sewardj08210532004-12-29 17:09:11 +00003327 default:
3328 vpanic("subst_AvailExpr");
3329 }
3330}
3331
3332static AvailExpr* irExpr_to_AvailExpr ( IRExpr* e )
3333{
3334 AvailExpr* ae;
3335
florianc1b9e392012-09-20 02:40:57 +00003336 switch (e->tag) {
3337 case Iex_Unop:
3338 if (e->Iex.Unop.arg->tag == Iex_RdTmp) {
3339 ae = LibVEX_Alloc(sizeof(AvailExpr));
3340 ae->tag = Ut;
3341 ae->u.Ut.op = e->Iex.Unop.op;
3342 ae->u.Ut.arg = e->Iex.Unop.arg->Iex.RdTmp.tmp;
3343 return ae;
3344 }
3345 break;
sewardj08210532004-12-29 17:09:11 +00003346
florianc1b9e392012-09-20 02:40:57 +00003347 case Iex_Binop:
3348 if (e->Iex.Binop.arg1->tag == Iex_RdTmp) {
3349 if (e->Iex.Binop.arg2->tag == Iex_RdTmp) {
3350 ae = LibVEX_Alloc(sizeof(AvailExpr));
3351 ae->tag = Btt;
3352 ae->u.Btt.op = e->Iex.Binop.op;
3353 ae->u.Btt.arg1 = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
3354 ae->u.Btt.arg2 = e->Iex.Binop.arg2->Iex.RdTmp.tmp;
3355 return ae;
3356 }
3357 if (e->Iex.Binop.arg2->tag == Iex_Const) {
3358 ae = LibVEX_Alloc(sizeof(AvailExpr));
3359 ae->tag = Btc;
3360 ae->u.Btc.op = e->Iex.Binop.op;
3361 ae->u.Btc.arg1 = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
3362 ae->u.Btc.con2 = *(e->Iex.Binop.arg2->Iex.Const.con);
3363 return ae;
3364 }
3365 } else if (e->Iex.Binop.arg1->tag == Iex_Const
3366 && e->Iex.Binop.arg2->tag == Iex_RdTmp) {
3367 ae = LibVEX_Alloc(sizeof(AvailExpr));
3368 ae->tag = Bct;
3369 ae->u.Bct.op = e->Iex.Binop.op;
3370 ae->u.Bct.arg2 = e->Iex.Binop.arg2->Iex.RdTmp.tmp;
3371 ae->u.Bct.con1 = *(e->Iex.Binop.arg1->Iex.Const.con);
3372 return ae;
3373 }
3374 break;
sewardj08210532004-12-29 17:09:11 +00003375
florianc1b9e392012-09-20 02:40:57 +00003376 case Iex_Const:
3377 if (e->Iex.Const.con->tag == Ico_F64i) {
3378 ae = LibVEX_Alloc(sizeof(AvailExpr));
3379 ae->tag = Cf64i;
3380 ae->u.Cf64i.f64i = e->Iex.Const.con->Ico.F64i;
3381 return ae;
3382 }
3383 break;
sewardj08210532004-12-29 17:09:11 +00003384
florianc1b9e392012-09-20 02:40:57 +00003385 case Iex_Mux0X:
3386 if (e->Iex.Mux0X.cond->tag == Iex_RdTmp) {
3387 if (e->Iex.Mux0X.expr0->tag == Iex_RdTmp) {
3388 if (e->Iex.Mux0X.exprX->tag == Iex_RdTmp) {
3389 ae = LibVEX_Alloc(sizeof(AvailExpr));
3390 ae->tag = Mttt;
3391 ae->u.Mttt.co = e->Iex.Mux0X.cond->Iex.RdTmp.tmp;
3392 ae->u.Mttt.e0 = e->Iex.Mux0X.expr0->Iex.RdTmp.tmp;
3393 ae->u.Mttt.eX = e->Iex.Mux0X.exprX->Iex.RdTmp.tmp;
3394 return ae;
3395 }
3396 if (e->Iex.Mux0X.exprX->tag == Iex_Const) {
3397 ae = LibVEX_Alloc(sizeof(AvailExpr));
3398 ae->tag = Mttc;
3399 ae->u.Mttc.co = e->Iex.Mux0X.cond->Iex.RdTmp.tmp;
3400 ae->u.Mttc.e0 = e->Iex.Mux0X.expr0->Iex.RdTmp.tmp;
3401 ae->u.Mttc.conX = *(e->Iex.Mux0X.exprX->Iex.Const.con);
3402 return ae;
3403 }
3404 } else if (e->Iex.Mux0X.expr0->tag == Iex_Const) {
3405 if (e->Iex.Mux0X.exprX->tag == Iex_RdTmp) {
3406 ae = LibVEX_Alloc(sizeof(AvailExpr));
3407 ae->tag = Mtct;
3408 ae->u.Mtct.co = e->Iex.Mux0X.cond->Iex.RdTmp.tmp;
3409 ae->u.Mtct.con0 = *(e->Iex.Mux0X.expr0->Iex.Const.con);
3410 ae->u.Mtct.eX = e->Iex.Mux0X.exprX->Iex.RdTmp.tmp;
3411 return ae;
3412 }
3413 if (e->Iex.Mux0X.exprX->tag == Iex_Const) {
3414 ae = LibVEX_Alloc(sizeof(AvailExpr));
3415 ae->tag = Mtcc;
3416 ae->u.Mtcc.co = e->Iex.Mux0X.cond->Iex.RdTmp.tmp;
3417 ae->u.Mtcc.con0 = *(e->Iex.Mux0X.expr0->Iex.Const.con);
3418 ae->u.Mtcc.conX = *(e->Iex.Mux0X.exprX->Iex.Const.con);
3419 return ae;
3420 }
3421 }
3422 }
3423 break;
sewardj08210532004-12-29 17:09:11 +00003424
florianc1b9e392012-09-20 02:40:57 +00003425 case Iex_GetI:
3426 if (e->Iex.GetI.ix->tag == Iex_RdTmp) {
3427 ae = LibVEX_Alloc(sizeof(AvailExpr));
3428 ae->tag = GetIt;
3429 ae->u.GetIt.descr = e->Iex.GetI.descr;
3430 ae->u.GetIt.ix = e->Iex.GetI.ix->Iex.RdTmp.tmp;
3431 ae->u.GetIt.bias = e->Iex.GetI.bias;
3432 return ae;
3433 }
3434 break;
sewardj08210532004-12-29 17:09:11 +00003435
florianc1b9e392012-09-20 02:40:57 +00003436 case Iex_CCall:
3437 ae = LibVEX_Alloc(sizeof(AvailExpr));
3438 ae->tag = CCall;
3439 /* Ok to share only the cee, since it is immutable. */
3440 ae->u.CCall.cee = e->Iex.CCall.cee;
3441 ae->u.CCall.retty = e->Iex.CCall.retty;
3442 /* irExprVec_to_TmpOrConsts will assert if the args are
3443 neither tmps nor constants, but that's ok .. that's all they
3444 should be. */
3445 irExprVec_to_TmpOrConsts(
3446 &ae->u.CCall.args, &ae->u.CCall.nArgs,
3447 e->Iex.CCall.args
3448 );
3449 return ae;
sewardj9b0cc582006-02-04 15:24:00 +00003450
florianc1b9e392012-09-20 02:40:57 +00003451 default:
3452 break;
sewardje8578042012-04-13 11:42:50 +00003453 }
3454
sewardj08210532004-12-29 17:09:11 +00003455 return NULL;
3456}
3457
3458
sewardj9b0cc582006-02-04 15:24:00 +00003459/* The BB is modified in-place. Returns True if any changes were
3460 made. */
sewardj08210532004-12-29 17:09:11 +00003461
sewardjdd40fdf2006-12-24 02:20:24 +00003462static Bool do_cse_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003463{
sewardj9b0cc582006-02-04 15:24:00 +00003464 Int i, j, paranoia;
sewardj08210532004-12-29 17:09:11 +00003465 IRTemp t, q;
3466 IRStmt* st;
3467 AvailExpr* eprime;
sewardj9b0cc582006-02-04 15:24:00 +00003468 AvailExpr* ae;
3469 Bool invalidate;
3470 Bool anyDone = False;
sewardj08210532004-12-29 17:09:11 +00003471
3472 HashHW* tenv = newHHW(); /* :: IRTemp -> IRTemp */
3473 HashHW* aenv = newHHW(); /* :: AvailExpr* -> IRTemp */
3474
3475 vassert(sizeof(IRTemp) <= sizeof(HWord));
3476
sewardjdd40fdf2006-12-24 02:20:24 +00003477 if (0) { ppIRSB(bb); vex_printf("\n\n"); }
sewardj08210532004-12-29 17:09:11 +00003478
3479 /* Iterate forwards over the stmts.
sewardjb183b852006-02-03 16:08:03 +00003480 On seeing "t = E", where E is one of the 5 AvailExpr forms:
sewardj08210532004-12-29 17:09:11 +00003481 let E' = apply tenv substitution to E
3482 search aenv for E'
3483 if a mapping E' -> q is found,
3484 replace this stmt by "t = q"
3485 and add binding t -> q to tenv
3486 else
3487 add binding E' -> t to aenv
3488 replace this stmt by "t = E'"
sewardj9b0cc582006-02-04 15:24:00 +00003489
3490 Other statements are only interesting to the extent that they
3491 might invalidate some of the expressions in aenv. So there is
3492 an invalidate-bindings check for each statement seen.
sewardj08210532004-12-29 17:09:11 +00003493 */
3494 for (i = 0; i < bb->stmts_used; i++) {
3495 st = bb->stmts[i];
3496
sewardj9b0cc582006-02-04 15:24:00 +00003497 /* ------ BEGIN invalidate aenv bindings ------ */
3498 /* This is critical: remove from aenv any E' -> .. bindings
3499 which might be invalidated by this statement. The only
sewardjc4356f02007-11-09 21:15:04 +00003500 vulnerable kind of bindings are the GetI kind.
sewardj9b0cc582006-02-04 15:24:00 +00003501 Dirty call - dump (paranoia level -> 2)
3502 Store - dump (ditto)
3503 Put, PutI - dump unless no-overlap is proven (.. -> 1)
3504 Uses getAliasingRelation_IC and getAliasingRelation_II
3505 to do the no-overlap assessments needed for Put/PutI.
3506 */
3507 switch (st->tag) {
sewardje768e922009-11-26 17:17:37 +00003508 case Ist_Dirty: case Ist_Store: case Ist_MBE:
3509 case Ist_CAS: case Ist_LLSC:
sewardj9b0cc582006-02-04 15:24:00 +00003510 paranoia = 2; break;
3511 case Ist_Put: case Ist_PutI:
3512 paranoia = 1; break;
3513 case Ist_NoOp: case Ist_IMark: case Ist_AbiHint:
sewardjc4356f02007-11-09 21:15:04 +00003514 case Ist_WrTmp: case Ist_Exit:
sewardj9b0cc582006-02-04 15:24:00 +00003515 paranoia = 0; break;
3516 default:
3517 vpanic("do_cse_BB(1)");
3518 }
3519
3520 if (paranoia > 0) {
3521 for (j = 0; j < aenv->used; j++) {
3522 if (!aenv->inuse[j])
3523 continue;
3524 ae = (AvailExpr*)aenv->key[j];
3525 if (ae->tag != GetIt)
3526 continue;
3527 invalidate = False;
3528 if (paranoia >= 2) {
3529 invalidate = True;
3530 } else {
3531 vassert(paranoia == 1);
3532 if (st->tag == Ist_Put) {
3533 if (getAliasingRelation_IC(
3534 ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003535 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00003536 st->Ist.Put.offset,
3537 typeOfIRExpr(bb->tyenv,st->Ist.Put.data)
3538 ) != NoAlias)
3539 invalidate = True;
3540 }
3541 else
3542 if (st->tag == Ist_PutI) {
floriand6f38b32012-05-31 15:46:18 +00003543 IRPutI *puti = st->Ist.PutI.details;
sewardj9b0cc582006-02-04 15:24:00 +00003544 if (getAliasingRelation_II(
3545 ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003546 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00003547 ae->u.GetIt.bias,
floriand6f38b32012-05-31 15:46:18 +00003548 puti->descr,
3549 puti->ix,
3550 puti->bias
sewardj9b0cc582006-02-04 15:24:00 +00003551 ) != NoAlias)
3552 invalidate = True;
3553 }
3554 else
3555 vpanic("do_cse_BB(2)");
3556 }
3557
3558 if (invalidate) {
3559 aenv->inuse[j] = False;
3560 aenv->key[j] = (HWord)NULL; /* be sure */
3561 }
3562 } /* for j */
3563 } /* paranoia > 0 */
3564
3565 /* ------ ENV invalidate aenv bindings ------ */
3566
sewardj08210532004-12-29 17:09:11 +00003567 /* ignore not-interestings */
sewardjdd40fdf2006-12-24 02:20:24 +00003568 if (st->tag != Ist_WrTmp)
sewardj08210532004-12-29 17:09:11 +00003569 continue;
3570
sewardjdd40fdf2006-12-24 02:20:24 +00003571 t = st->Ist.WrTmp.tmp;
3572 eprime = irExpr_to_AvailExpr(st->Ist.WrTmp.data);
sewardj08210532004-12-29 17:09:11 +00003573 /* ignore if not of AvailExpr form */
3574 if (!eprime)
3575 continue;
3576
3577 /* vex_printf("considering: " ); ppIRStmt(st); vex_printf("\n"); */
3578
3579 /* apply tenv */
3580 subst_AvailExpr( tenv, eprime );
3581
3582 /* search aenv for eprime, unfortunately the hard way */
3583 for (j = 0; j < aenv->used; j++)
3584 if (aenv->inuse[j] && eq_AvailExpr(eprime, (AvailExpr*)aenv->key[j]))
3585 break;
3586
3587 if (j < aenv->used) {
3588 /* A binding E' -> q was found. Replace stmt by "t = q" and
3589 note the t->q binding in tenv. */
3590 /* (this is the core of the CSE action) */
3591 q = (IRTemp)aenv->val[j];
sewardjdd40fdf2006-12-24 02:20:24 +00003592 bb->stmts[i] = IRStmt_WrTmp( t, IRExpr_RdTmp(q) );
sewardj08210532004-12-29 17:09:11 +00003593 addToHHW( tenv, (HWord)t, (HWord)q );
sewardj9b0cc582006-02-04 15:24:00 +00003594 anyDone = True;
sewardj08210532004-12-29 17:09:11 +00003595 } else {
3596 /* No binding was found, so instead we add E' -> t to our
3597 collection of available expressions, replace this stmt
3598 with "t = E'", and move on. */
sewardjdd40fdf2006-12-24 02:20:24 +00003599 bb->stmts[i] = IRStmt_WrTmp( t, availExpr_to_IRExpr(eprime) );
sewardj08210532004-12-29 17:09:11 +00003600 addToHHW( aenv, (HWord)eprime, (HWord)t );
3601 }
3602 }
3603
sewardjb183b852006-02-03 16:08:03 +00003604 /*
sewardjdd40fdf2006-12-24 02:20:24 +00003605 ppIRSB(bb);
3606 sanityCheckIRSB(bb, Ity_I32);
sewardjb183b852006-02-03 16:08:03 +00003607 vex_printf("\n\n");
3608 */
sewardj9b0cc582006-02-04 15:24:00 +00003609 return anyDone;
sewardj08210532004-12-29 17:09:11 +00003610}
3611
3612
3613/*---------------------------------------------------------------*/
3614/*--- Add32/Sub32 chain collapsing ---*/
3615/*---------------------------------------------------------------*/
3616
3617/* ----- Helper functions for Add32/Sub32 chain collapsing ----- */
3618
3619/* Is this expression "Add32(tmp,const)" or "Sub32(tmp,const)" ? If
3620 yes, set *tmp and *i32 appropriately. *i32 is set as if the
3621 root node is Add32, not Sub32. */
3622
3623static Bool isAdd32OrSub32 ( IRExpr* e, IRTemp* tmp, Int* i32 )
3624{
3625 if (e->tag != Iex_Binop)
3626 return False;
3627 if (e->Iex.Binop.op != Iop_Add32 && e->Iex.Binop.op != Iop_Sub32)
3628 return False;
sewardjdd40fdf2006-12-24 02:20:24 +00003629 if (e->Iex.Binop.arg1->tag != Iex_RdTmp)
sewardj08210532004-12-29 17:09:11 +00003630 return False;
3631 if (e->Iex.Binop.arg2->tag != Iex_Const)
3632 return False;
sewardjdd40fdf2006-12-24 02:20:24 +00003633 *tmp = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00003634 *i32 = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32);
3635 if (e->Iex.Binop.op == Iop_Sub32)
3636 *i32 = -*i32;
3637 return True;
3638}
3639
3640
3641/* Figure out if tmp can be expressed as tmp2 +32 const, for some
3642 other tmp2. Scan backwards from the specified start point -- an
3643 optimisation. */
3644
sewardjdd40fdf2006-12-24 02:20:24 +00003645static Bool collapseChain ( IRSB* bb, Int startHere,
sewardj08210532004-12-29 17:09:11 +00003646 IRTemp tmp,
3647 IRTemp* tmp2, Int* i32 )
3648{
3649 Int j, ii;
3650 IRTemp vv;
3651 IRStmt* st;
3652 IRExpr* e;
3653
3654 /* the (var, con) pair contain the current 'representation' for
3655 'tmp'. We start with 'tmp + 0'. */
3656 IRTemp var = tmp;
3657 Int con = 0;
3658
3659 /* Scan backwards to see if tmp can be replaced by some other tmp
3660 +/- a constant. */
3661 for (j = startHere; j >= 0; j--) {
3662 st = bb->stmts[j];
sewardjdd40fdf2006-12-24 02:20:24 +00003663 if (st->tag != Ist_WrTmp)
sewardj08210532004-12-29 17:09:11 +00003664 continue;
sewardjdd40fdf2006-12-24 02:20:24 +00003665 if (st->Ist.WrTmp.tmp != var)
sewardj08210532004-12-29 17:09:11 +00003666 continue;
sewardjdd40fdf2006-12-24 02:20:24 +00003667 e = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +00003668 if (!isAdd32OrSub32(e, &vv, &ii))
3669 break;
3670 var = vv;
3671 con += ii;
3672 }
3673 if (j == -1)
3674 /* no earlier binding for var .. ill-formed IR */
3675 vpanic("collapseChain");
3676
3677 /* so, did we find anything interesting? */
3678 if (var == tmp)
3679 return False; /* no .. */
3680
3681 *tmp2 = var;
3682 *i32 = con;
3683 return True;
3684}
3685
3686
3687/* ------- Main function for Add32/Sub32 chain collapsing ------ */
3688
sewardjdd40fdf2006-12-24 02:20:24 +00003689static void collapse_AddSub_chains_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003690{
3691 IRStmt *st;
3692 IRTemp var, var2;
3693 Int i, con, con2;
3694
3695 for (i = bb->stmts_used-1; i >= 0; i--) {
3696 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003697 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00003698 continue;
3699
3700 /* Try to collapse 't1 = Add32/Sub32(t2, con)'. */
3701
sewardjdd40fdf2006-12-24 02:20:24 +00003702 if (st->tag == Ist_WrTmp
3703 && isAdd32OrSub32(st->Ist.WrTmp.data, &var, &con)) {
sewardj08210532004-12-29 17:09:11 +00003704
3705 /* So e1 is of the form Add32(var,con) or Sub32(var,-con).
3706 Find out if var can be expressed as var2 + con2. */
3707 if (collapseChain(bb, i-1, var, &var2, &con2)) {
3708 if (DEBUG_IROPT) {
3709 vex_printf("replacing1 ");
3710 ppIRStmt(st);
3711 vex_printf(" with ");
3712 }
3713 con2 += con;
3714 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00003715 = IRStmt_WrTmp(
3716 st->Ist.WrTmp.tmp,
sewardj08210532004-12-29 17:09:11 +00003717 (con2 >= 0)
3718 ? IRExpr_Binop(Iop_Add32,
sewardjdd40fdf2006-12-24 02:20:24 +00003719 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00003720 IRExpr_Const(IRConst_U32(con2)))
3721 : IRExpr_Binop(Iop_Sub32,
sewardjdd40fdf2006-12-24 02:20:24 +00003722 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00003723 IRExpr_Const(IRConst_U32(-con2)))
3724 );
3725 if (DEBUG_IROPT) {
3726 ppIRStmt(bb->stmts[i]);
3727 vex_printf("\n");
3728 }
3729 }
3730
3731 continue;
3732 }
3733
3734 /* Try to collapse 't1 = GetI[t2, con]'. */
3735
sewardjdd40fdf2006-12-24 02:20:24 +00003736 if (st->tag == Ist_WrTmp
3737 && st->Ist.WrTmp.data->tag == Iex_GetI
3738 && st->Ist.WrTmp.data->Iex.GetI.ix->tag == Iex_RdTmp
3739 && collapseChain(bb, i-1, st->Ist.WrTmp.data->Iex.GetI.ix
3740 ->Iex.RdTmp.tmp, &var2, &con2)) {
sewardj08210532004-12-29 17:09:11 +00003741 if (DEBUG_IROPT) {
3742 vex_printf("replacing3 ");
3743 ppIRStmt(st);
3744 vex_printf(" with ");
3745 }
sewardjdd40fdf2006-12-24 02:20:24 +00003746 con2 += st->Ist.WrTmp.data->Iex.GetI.bias;
sewardj08210532004-12-29 17:09:11 +00003747 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00003748 = IRStmt_WrTmp(
3749 st->Ist.WrTmp.tmp,
3750 IRExpr_GetI(st->Ist.WrTmp.data->Iex.GetI.descr,
3751 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00003752 con2));
3753 if (DEBUG_IROPT) {
3754 ppIRStmt(bb->stmts[i]);
3755 vex_printf("\n");
3756 }
3757 continue;
3758 }
3759
3760 /* Perhaps st is PutI[t, con] ? */
floriand6f38b32012-05-31 15:46:18 +00003761 IRPutI *puti = st->Ist.PutI.details;
sewardj08210532004-12-29 17:09:11 +00003762 if (st->tag == Ist_PutI
floriand6f38b32012-05-31 15:46:18 +00003763 && puti->ix->tag == Iex_RdTmp
3764 && collapseChain(bb, i-1, puti->ix->Iex.RdTmp.tmp,
sewardj08210532004-12-29 17:09:11 +00003765 &var2, &con2)) {
3766 if (DEBUG_IROPT) {
3767 vex_printf("replacing2 ");
3768 ppIRStmt(st);
3769 vex_printf(" with ");
3770 }
floriand6f38b32012-05-31 15:46:18 +00003771 con2 += puti->bias;
sewardj08210532004-12-29 17:09:11 +00003772 bb->stmts[i]
floriand6f38b32012-05-31 15:46:18 +00003773 = IRStmt_PutI(mkIRPutI(puti->descr,
3774 IRExpr_RdTmp(var2),
3775 con2,
3776 puti->data));
sewardj08210532004-12-29 17:09:11 +00003777 if (DEBUG_IROPT) {
3778 ppIRStmt(bb->stmts[i]);
3779 vex_printf("\n");
3780 }
3781 continue;
3782 }
3783
3784 } /* for */
3785}
3786
3787
3788/*---------------------------------------------------------------*/
3789/*--- PutI/GetI transformations ---*/
3790/*---------------------------------------------------------------*/
3791
sewardj08210532004-12-29 17:09:11 +00003792/* Given the parts (descr, tmp, bias) for a GetI, scan backwards from
3793 the given starting point to find, if any, a PutI which writes
3794 exactly the same piece of guest state, and so return the expression
3795 that the PutI writes. This is the core of PutI-GetI forwarding. */
3796
3797static
sewardjdd40fdf2006-12-24 02:20:24 +00003798IRExpr* findPutI ( IRSB* bb, Int startHere,
3799 IRRegArray* descrG, IRExpr* ixG, Int biasG )
sewardj08210532004-12-29 17:09:11 +00003800{
3801 Int j;
3802 IRStmt* st;
3803 GSAliasing relation;
3804
3805 if (0) {
3806 vex_printf("\nfindPutI ");
sewardjdd40fdf2006-12-24 02:20:24 +00003807 ppIRRegArray(descrG);
sewardj08210532004-12-29 17:09:11 +00003808 vex_printf(" ");
3809 ppIRExpr(ixG);
3810 vex_printf(" %d\n", biasG);
3811 }
3812
3813 /* Scan backwards in bb from startHere to find a suitable PutI
3814 binding for (descrG, ixG, biasG), if any. */
3815
3816 for (j = startHere; j >= 0; j--) {
3817 st = bb->stmts[j];
sewardj8bee6d12005-03-22 02:24:05 +00003818 if (st->tag == Ist_NoOp)
3819 continue;
sewardj08210532004-12-29 17:09:11 +00003820
3821 if (st->tag == Ist_Put) {
3822 /* Non-indexed Put. This can't give a binding, but we do
3823 need to check it doesn't invalidate the search by
3824 overlapping any part of the indexed guest state. */
3825
3826 relation
3827 = getAliasingRelation_IC(
3828 descrG, ixG,
3829 st->Ist.Put.offset,
3830 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
3831
3832 if (relation == NoAlias) {
3833 /* we're OK; keep going */
3834 continue;
3835 } else {
3836 /* relation == UnknownAlias || relation == ExactAlias */
3837 /* If this assertion fails, we've found a Put which writes
3838 an area of guest state which is read by a GetI. Which
3839 is unlikely (although not per se wrong). */
3840 vassert(relation != ExactAlias);
3841 /* This Put potentially writes guest state that the GetI
3842 reads; we must fail. */
3843 return NULL;
3844 }
3845 }
3846
3847 if (st->tag == Ist_PutI) {
floriand6f38b32012-05-31 15:46:18 +00003848 IRPutI *puti = st->Ist.PutI.details;
sewardj08210532004-12-29 17:09:11 +00003849
3850 relation = getAliasingRelation_II(
3851 descrG, ixG, biasG,
floriand6f38b32012-05-31 15:46:18 +00003852 puti->descr,
3853 puti->ix,
3854 puti->bias
sewardj08210532004-12-29 17:09:11 +00003855 );
3856
3857 if (relation == NoAlias) {
3858 /* This PutI definitely doesn't overlap. Ignore it and
3859 keep going. */
3860 continue; /* the for j loop */
3861 }
3862
3863 if (relation == UnknownAlias) {
3864 /* We don't know if this PutI writes to the same guest
3865 state that the GetI, or not. So we have to give up. */
3866 return NULL;
3867 }
3868
3869 /* Otherwise, we've found what we're looking for. */
3870 vassert(relation == ExactAlias);
floriand6f38b32012-05-31 15:46:18 +00003871 return puti->data;
sewardj08210532004-12-29 17:09:11 +00003872
3873 } /* if (st->tag == Ist_PutI) */
3874
3875 if (st->tag == Ist_Dirty) {
3876 /* Be conservative. If the dirty call has any guest effects at
3877 all, give up. We could do better -- only give up if there
3878 are any guest writes/modifies. */
3879 if (st->Ist.Dirty.details->nFxState > 0)
3880 return NULL;
3881 }
3882
3883 } /* for */
3884
3885 /* No valid replacement was found. */
3886 return NULL;
3887}
3888
3889
3890
3891/* Assuming pi is a PutI stmt, is s2 identical to it (in the sense
3892 that it writes exactly the same piece of guest state) ? Safe
3893 answer: False. */
3894
3895static Bool identicalPutIs ( IRStmt* pi, IRStmt* s2 )
3896{
3897 vassert(pi->tag == Ist_PutI);
3898 if (s2->tag != Ist_PutI)
3899 return False;
3900
floriand6f38b32012-05-31 15:46:18 +00003901 IRPutI *p1 = pi->Ist.PutI.details;
3902 IRPutI *p2 = s2->Ist.PutI.details;
3903
sewardj9d2e7692005-02-07 01:11:31 +00003904 return toBool(
3905 getAliasingRelation_II(
floriand6f38b32012-05-31 15:46:18 +00003906 p1->descr, p1->ix, p1->bias,
3907 p2->descr, p2->ix, p2->bias
sewardj08210532004-12-29 17:09:11 +00003908 )
sewardj9d2e7692005-02-07 01:11:31 +00003909 == ExactAlias
3910 );
sewardj08210532004-12-29 17:09:11 +00003911}
3912
3913
3914/* Assuming pi is a PutI stmt, is s2 a Get/GetI/Put/PutI which might
3915 overlap it? Safe answer: True. Note, we could do a lot better
3916 than this if needed. */
3917
3918static
3919Bool guestAccessWhichMightOverlapPutI (
3920 IRTypeEnv* tyenv, IRStmt* pi, IRStmt* s2
3921 )
3922{
3923 GSAliasing relation;
3924 UInt minoffP, maxoffP;
3925
3926 vassert(pi->tag == Ist_PutI);
floriand6f38b32012-05-31 15:46:18 +00003927
3928 IRPutI *p1 = pi->Ist.PutI.details;
3929
3930 getArrayBounds(p1->descr, &minoffP, &maxoffP);
sewardj08210532004-12-29 17:09:11 +00003931 switch (s2->tag) {
3932
sewardjd2445f62005-03-21 00:15:53 +00003933 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00003934 case Ist_IMark:
3935 return False;
3936
sewardjc4356f02007-11-09 21:15:04 +00003937 case Ist_MBE:
sewardj5a9ffab2005-05-12 17:55:01 +00003938 case Ist_AbiHint:
3939 /* just be paranoid ... these should be rare. */
sewardjbb3f52d2005-01-07 14:14:50 +00003940 return True;
3941
sewardje9d8a262009-07-01 08:06:34 +00003942 case Ist_CAS:
3943 /* This is unbelievably lame, but it's probably not
3944 significant from a performance point of view. Really, a
3945 CAS is a load-store op, so it should be safe to say False.
3946 However .. */
3947 return True;
3948
sewardj08210532004-12-29 17:09:11 +00003949 case Ist_Dirty:
3950 /* If the dirty call has any guest effects at all, give up.
3951 Probably could do better. */
3952 if (s2->Ist.Dirty.details->nFxState > 0)
3953 return True;
3954 return False;
3955
3956 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00003957 vassert(isIRAtom(s2->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +00003958 relation
3959 = getAliasingRelation_IC(
floriand6f38b32012-05-31 15:46:18 +00003960 p1->descr, p1->ix,
sewardj08210532004-12-29 17:09:11 +00003961 s2->Ist.Put.offset,
3962 typeOfIRExpr(tyenv,s2->Ist.Put.data)
3963 );
3964 goto have_relation;
3965
floriand6f38b32012-05-31 15:46:18 +00003966 case Ist_PutI: {
3967 IRPutI *p2 = s2->Ist.PutI.details;
3968
3969 vassert(isIRAtom(p2->ix));
3970 vassert(isIRAtom(p2->data));
sewardj08210532004-12-29 17:09:11 +00003971 relation
3972 = getAliasingRelation_II(
floriand6f38b32012-05-31 15:46:18 +00003973 p1->descr, p1->ix, p1->bias,
3974 p2->descr, p2->ix, p2->bias
sewardj08210532004-12-29 17:09:11 +00003975 );
3976 goto have_relation;
floriand6f38b32012-05-31 15:46:18 +00003977 }
sewardj08210532004-12-29 17:09:11 +00003978
sewardjdd40fdf2006-12-24 02:20:24 +00003979 case Ist_WrTmp:
3980 if (s2->Ist.WrTmp.data->tag == Iex_GetI) {
sewardj08210532004-12-29 17:09:11 +00003981 relation
3982 = getAliasingRelation_II(
floriand6f38b32012-05-31 15:46:18 +00003983 p1->descr, p1->ix, p1->bias,
sewardjdd40fdf2006-12-24 02:20:24 +00003984 s2->Ist.WrTmp.data->Iex.GetI.descr,
3985 s2->Ist.WrTmp.data->Iex.GetI.ix,
3986 s2->Ist.WrTmp.data->Iex.GetI.bias
sewardj08210532004-12-29 17:09:11 +00003987 );
3988 goto have_relation;
3989 }
sewardjdd40fdf2006-12-24 02:20:24 +00003990 if (s2->Ist.WrTmp.data->tag == Iex_Get) {
sewardj08210532004-12-29 17:09:11 +00003991 relation
3992 = getAliasingRelation_IC(
floriand6f38b32012-05-31 15:46:18 +00003993 p1->descr, p1->ix,
sewardjdd40fdf2006-12-24 02:20:24 +00003994 s2->Ist.WrTmp.data->Iex.Get.offset,
3995 s2->Ist.WrTmp.data->Iex.Get.ty
sewardj08210532004-12-29 17:09:11 +00003996 );
3997 goto have_relation;
3998 }
3999 return False;
4000
sewardjaf1ceca2005-06-30 23:31:27 +00004001 case Ist_Store:
4002 vassert(isIRAtom(s2->Ist.Store.addr));
4003 vassert(isIRAtom(s2->Ist.Store.data));
sewardj08210532004-12-29 17:09:11 +00004004 return False;
4005
4006 default:
4007 vex_printf("\n"); ppIRStmt(s2); vex_printf("\n");
4008 vpanic("guestAccessWhichMightOverlapPutI");
4009 }
4010
4011 have_relation:
4012 if (relation == NoAlias)
4013 return False;
4014 else
4015 return True; /* ExactAlias or UnknownAlias */
4016}
4017
4018
4019
4020/* ---------- PutI/GetI transformations main functions --------- */
4021
4022/* Remove redundant GetIs, to the extent that they can be detected.
4023 bb is modified in-place. */
4024
4025static
sewardjdd40fdf2006-12-24 02:20:24 +00004026void do_redundant_GetI_elimination ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00004027{
4028 Int i;
4029 IRStmt* st;
4030
4031 for (i = bb->stmts_used-1; i >= 0; i--) {
4032 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00004033 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00004034 continue;
4035
sewardjdd40fdf2006-12-24 02:20:24 +00004036 if (st->tag == Ist_WrTmp
4037 && st->Ist.WrTmp.data->tag == Iex_GetI
4038 && st->Ist.WrTmp.data->Iex.GetI.ix->tag == Iex_RdTmp) {
4039 IRRegArray* descr = st->Ist.WrTmp.data->Iex.GetI.descr;
4040 IRExpr* ix = st->Ist.WrTmp.data->Iex.GetI.ix;
4041 Int bias = st->Ist.WrTmp.data->Iex.GetI.bias;
4042 IRExpr* replacement = findPutI(bb, i-1, descr, ix, bias);
sewardj08210532004-12-29 17:09:11 +00004043 if (replacement
sewardj496a58d2005-03-20 18:44:44 +00004044 && isIRAtom(replacement)
sewardj08210532004-12-29 17:09:11 +00004045 /* Make sure we're doing a type-safe transformation! */
4046 && typeOfIRExpr(bb->tyenv, replacement) == descr->elemTy) {
4047 if (DEBUG_IROPT) {
4048 vex_printf("rGI: ");
sewardjdd40fdf2006-12-24 02:20:24 +00004049 ppIRExpr(st->Ist.WrTmp.data);
sewardj08210532004-12-29 17:09:11 +00004050 vex_printf(" -> ");
4051 ppIRExpr(replacement);
4052 vex_printf("\n");
4053 }
sewardjdd40fdf2006-12-24 02:20:24 +00004054 bb->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, replacement);
sewardj08210532004-12-29 17:09:11 +00004055 }
4056 }
4057 }
4058
4059}
4060
4061
4062/* Remove redundant PutIs, to the extent which they can be detected.
4063 bb is modified in-place. */
4064
4065static
sewardjdd40fdf2006-12-24 02:20:24 +00004066void do_redundant_PutI_elimination ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00004067{
4068 Int i, j;
4069 Bool delete;
4070 IRStmt *st, *stj;
4071
philippe6c46bef2012-08-14 22:29:01 +00004072 vassert(vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn);
philippec8e2f982012-08-01 22:04:13 +00004073
sewardj08210532004-12-29 17:09:11 +00004074 for (i = 0; i < bb->stmts_used; i++) {
4075 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00004076 if (st->tag != Ist_PutI)
sewardj08210532004-12-29 17:09:11 +00004077 continue;
4078 /* Ok, search forwards from here to see if we can find another
4079 PutI which makes this one redundant, and dodging various
4080 hazards. Search forwards:
4081 * If conditional exit, give up (because anything after that
4082 does not postdominate this put).
4083 * If a Get which might overlap, give up (because this PutI
4084 not necessarily dead).
4085 * If a Put which is identical, stop with success.
4086 * If a Put which might overlap, but is not identical, give up.
4087 * If a dirty helper call which might write guest state, give up.
4088 * If a Put which definitely doesn't overlap, or any other
4089 kind of stmt, continue.
4090 */
4091 delete = False;
4092 for (j = i+1; j < bb->stmts_used; j++) {
4093 stj = bb->stmts[j];
sewardj8bee6d12005-03-22 02:24:05 +00004094 if (stj->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00004095 continue;
4096 if (identicalPutIs(st, stj)) {
4097 /* success! */
4098 delete = True;
4099 break;
4100 }
4101 if (stj->tag == Ist_Exit)
4102 /* give up */
4103 break;
4104 if (st->tag == Ist_Dirty)
4105 /* give up; could do better here */
4106 break;
4107 if (guestAccessWhichMightOverlapPutI(bb->tyenv, st, stj))
4108 /* give up */
4109 break;
4110 }
4111
4112 if (delete) {
4113 if (DEBUG_IROPT) {
4114 vex_printf("rPI: ");
4115 ppIRStmt(st);
4116 vex_printf("\n");
4117 }
sewardjd2445f62005-03-21 00:15:53 +00004118 bb->stmts[i] = IRStmt_NoOp();
sewardj08210532004-12-29 17:09:11 +00004119 }
4120
4121 }
4122}
4123
4124
4125/*---------------------------------------------------------------*/
4126/*--- Loop unrolling ---*/
4127/*---------------------------------------------------------------*/
4128
4129/* Adjust all tmp values (names) in e by delta. e is destructively
4130 modified. */
4131
4132static void deltaIRExpr ( IRExpr* e, Int delta )
4133{
4134 Int i;
4135 switch (e->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +00004136 case Iex_RdTmp:
4137 e->Iex.RdTmp.tmp += delta;
sewardj08210532004-12-29 17:09:11 +00004138 break;
4139 case Iex_Get:
4140 case Iex_Const:
4141 break;
4142 case Iex_GetI:
4143 deltaIRExpr(e->Iex.GetI.ix, delta);
4144 break;
sewardj1a866b42006-02-09 02:54:03 +00004145 case Iex_Qop:
florian96d7cc32012-06-01 20:41:24 +00004146 deltaIRExpr(e->Iex.Qop.details->arg1, delta);
4147 deltaIRExpr(e->Iex.Qop.details->arg2, delta);
4148 deltaIRExpr(e->Iex.Qop.details->arg3, delta);
4149 deltaIRExpr(e->Iex.Qop.details->arg4, delta);
sewardj1a866b42006-02-09 02:54:03 +00004150 break;
sewardjb183b852006-02-03 16:08:03 +00004151 case Iex_Triop:
florian420bfa92012-06-02 20:29:22 +00004152 deltaIRExpr(e->Iex.Triop.details->arg1, delta);
4153 deltaIRExpr(e->Iex.Triop.details->arg2, delta);
4154 deltaIRExpr(e->Iex.Triop.details->arg3, delta);
sewardjb183b852006-02-03 16:08:03 +00004155 break;
sewardj08210532004-12-29 17:09:11 +00004156 case Iex_Binop:
4157 deltaIRExpr(e->Iex.Binop.arg1, delta);
4158 deltaIRExpr(e->Iex.Binop.arg2, delta);
4159 break;
4160 case Iex_Unop:
4161 deltaIRExpr(e->Iex.Unop.arg, delta);
4162 break;
sewardjaf1ceca2005-06-30 23:31:27 +00004163 case Iex_Load:
4164 deltaIRExpr(e->Iex.Load.addr, delta);
sewardj08210532004-12-29 17:09:11 +00004165 break;
4166 case Iex_CCall:
4167 for (i = 0; e->Iex.CCall.args[i]; i++)
4168 deltaIRExpr(e->Iex.CCall.args[i], delta);
4169 break;
4170 case Iex_Mux0X:
4171 deltaIRExpr(e->Iex.Mux0X.cond, delta);
4172 deltaIRExpr(e->Iex.Mux0X.expr0, delta);
4173 deltaIRExpr(e->Iex.Mux0X.exprX, delta);
4174 break;
4175 default:
4176 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4177 vpanic("deltaIRExpr");
4178 }
4179}
4180
4181/* Adjust all tmp values (names) in st by delta. st is destructively
4182 modified. */
4183
4184static void deltaIRStmt ( IRStmt* st, Int delta )
4185{
4186 Int i;
4187 IRDirty* d;
4188 switch (st->tag) {
sewardjd2445f62005-03-21 00:15:53 +00004189 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00004190 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00004191 case Ist_MBE:
sewardjf1689312005-03-16 18:19:10 +00004192 break;
sewardj5a9ffab2005-05-12 17:55:01 +00004193 case Ist_AbiHint:
4194 deltaIRExpr(st->Ist.AbiHint.base, delta);
sewardj478646f2008-05-01 20:13:04 +00004195 deltaIRExpr(st->Ist.AbiHint.nia, delta);
sewardj5a9ffab2005-05-12 17:55:01 +00004196 break;
sewardj08210532004-12-29 17:09:11 +00004197 case Ist_Put:
4198 deltaIRExpr(st->Ist.Put.data, delta);
4199 break;
4200 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +00004201 deltaIRExpr(st->Ist.PutI.details->ix, delta);
4202 deltaIRExpr(st->Ist.PutI.details->data, delta);
sewardj08210532004-12-29 17:09:11 +00004203 break;
sewardjdd40fdf2006-12-24 02:20:24 +00004204 case Ist_WrTmp:
4205 st->Ist.WrTmp.tmp += delta;
4206 deltaIRExpr(st->Ist.WrTmp.data, delta);
sewardj08210532004-12-29 17:09:11 +00004207 break;
4208 case Ist_Exit:
4209 deltaIRExpr(st->Ist.Exit.guard, delta);
4210 break;
sewardjaf1ceca2005-06-30 23:31:27 +00004211 case Ist_Store:
4212 deltaIRExpr(st->Ist.Store.addr, delta);
4213 deltaIRExpr(st->Ist.Store.data, delta);
sewardj08210532004-12-29 17:09:11 +00004214 break;
sewardje9d8a262009-07-01 08:06:34 +00004215 case Ist_CAS:
4216 if (st->Ist.CAS.details->oldHi != IRTemp_INVALID)
4217 st->Ist.CAS.details->oldHi += delta;
4218 st->Ist.CAS.details->oldLo += delta;
4219 deltaIRExpr(st->Ist.CAS.details->addr, delta);
4220 if (st->Ist.CAS.details->expdHi)
4221 deltaIRExpr(st->Ist.CAS.details->expdHi, delta);
4222 deltaIRExpr(st->Ist.CAS.details->expdLo, delta);
4223 if (st->Ist.CAS.details->dataHi)
4224 deltaIRExpr(st->Ist.CAS.details->dataHi, delta);
4225 deltaIRExpr(st->Ist.CAS.details->dataLo, delta);
4226 break;
sewardje768e922009-11-26 17:17:37 +00004227 case Ist_LLSC:
4228 st->Ist.LLSC.result += delta;
4229 deltaIRExpr(st->Ist.LLSC.addr, delta);
4230 if (st->Ist.LLSC.storedata)
4231 deltaIRExpr(st->Ist.LLSC.storedata, delta);
4232 break;
sewardj08210532004-12-29 17:09:11 +00004233 case Ist_Dirty:
4234 d = st->Ist.Dirty.details;
4235 deltaIRExpr(d->guard, delta);
4236 for (i = 0; d->args[i]; i++)
4237 deltaIRExpr(d->args[i], delta);
4238 if (d->tmp != IRTemp_INVALID)
4239 d->tmp += delta;
4240 if (d->mAddr)
4241 deltaIRExpr(d->mAddr, delta);
4242 break;
4243 default:
4244 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
4245 vpanic("deltaIRStmt");
4246 }
4247}
4248
4249
4250/* If possible, return a loop-unrolled version of bb0. The original
4251 is changed. If not possible, return NULL. */
4252
4253/* The two schemas considered are:
4254
4255 X: BODY; goto X
4256
4257 which unrolls to (eg) X: BODY;BODY; goto X
4258
4259 and
4260
4261 X: BODY; if (c) goto X; goto Y
4262 which trivially transforms to
4263 X: BODY; if (!c) goto Y; goto X;
4264 so it falls in the scope of the first case.
4265
4266 X and Y must be literal (guest) addresses.
4267*/
4268
sewardjdd40fdf2006-12-24 02:20:24 +00004269static Int calc_unroll_factor( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00004270{
4271 Int n_stmts, i;
4272
4273 n_stmts = 0;
sewardj0ddbf792005-04-04 23:12:54 +00004274 for (i = 0; i < bb->stmts_used; i++) {
4275 if (bb->stmts[i]->tag != Ist_NoOp)
4276 n_stmts++;
4277 }
sewardj08210532004-12-29 17:09:11 +00004278
4279 if (n_stmts <= vex_control.iropt_unroll_thresh/8) {
4280 if (vex_control.iropt_verbosity > 0)
4281 vex_printf("vex iropt: 8 x unrolling (%d sts -> %d sts)\n",
4282 n_stmts, 8* n_stmts);
4283 return 8;
4284 }
4285 if (n_stmts <= vex_control.iropt_unroll_thresh/4) {
4286 if (vex_control.iropt_verbosity > 0)
4287 vex_printf("vex iropt: 4 x unrolling (%d sts -> %d sts)\n",
4288 n_stmts, 4* n_stmts);
4289 return 4;
4290 }
4291
4292 if (n_stmts <= vex_control.iropt_unroll_thresh/2) {
4293 if (vex_control.iropt_verbosity > 0)
4294 vex_printf("vex iropt: 2 x unrolling (%d sts -> %d sts)\n",
4295 n_stmts, 2* n_stmts);
4296 return 2;
4297 }
4298
4299 if (vex_control.iropt_verbosity > 0)
4300 vex_printf("vex iropt: not unrolling (%d sts)\n", n_stmts);
4301
4302 return 1;
4303}
4304
4305
sewardjdd40fdf2006-12-24 02:20:24 +00004306static IRSB* maybe_loop_unroll_BB ( IRSB* bb0, Addr64 my_addr )
sewardj08210532004-12-29 17:09:11 +00004307{
4308 Int i, j, jmax, n_vars;
4309 Bool xxx_known;
4310 Addr64 xxx_value, yyy_value;
4311 IRExpr* udst;
4312 IRStmt* st;
4313 IRConst* con;
sewardjdd40fdf2006-12-24 02:20:24 +00004314 IRSB *bb1, *bb2;
sewardj08210532004-12-29 17:09:11 +00004315 Int unroll_factor;
4316
4317 if (vex_control.iropt_unroll_thresh <= 0)
4318 return NULL;
4319
4320 /* First off, figure out if we can unroll this loop. Do this
4321 without modifying bb0. */
4322
4323 if (bb0->jumpkind != Ijk_Boring)
4324 return NULL;
4325
4326 xxx_known = False;
4327 xxx_value = 0;
4328
4329 /* Extract the next-guest address. If it isn't a literal, we
4330 have to give up. */
4331
4332 udst = bb0->next;
4333 if (udst->tag == Iex_Const
4334 && (udst->Iex.Const.con->tag == Ico_U32
4335 || udst->Iex.Const.con->tag == Ico_U64)) {
4336 /* The BB ends in a jump to a literal location. */
4337 xxx_known = True;
4338 xxx_value = udst->Iex.Const.con->tag == Ico_U64
4339 ? udst->Iex.Const.con->Ico.U64
4340 : (Addr64)(udst->Iex.Const.con->Ico.U32);
4341 }
4342
4343 if (!xxx_known)
4344 return NULL;
4345
4346 /* Now we know the BB ends to a jump to a literal location. If
4347 it's a jump to itself (viz, idiom #1), move directly to the
4348 unrolling stage, first cloning the bb so the original isn't
4349 modified. */
4350 if (xxx_value == my_addr) {
4351 unroll_factor = calc_unroll_factor( bb0 );
4352 if (unroll_factor < 2)
4353 return NULL;
sewardjdd40fdf2006-12-24 02:20:24 +00004354 bb1 = deepCopyIRSB( bb0 );
sewardj08210532004-12-29 17:09:11 +00004355 bb0 = NULL;
4356 udst = NULL; /* is now invalid */
4357 goto do_unroll;
4358 }
4359
4360 /* Search for the second idiomatic form:
4361 X: BODY; if (c) goto X; goto Y
4362 We know Y, but need to establish that the last stmt
4363 is 'if (c) goto X'.
4364 */
4365 yyy_value = xxx_value;
4366 for (i = bb0->stmts_used-1; i >= 0; i--)
4367 if (bb0->stmts[i])
4368 break;
4369
4370 if (i < 0)
4371 return NULL; /* block with no stmts. Strange. */
4372
4373 st = bb0->stmts[i];
4374 if (st->tag != Ist_Exit)
4375 return NULL;
4376 if (st->Ist.Exit.jk != Ijk_Boring)
4377 return NULL;
4378
4379 con = st->Ist.Exit.dst;
4380 vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
4381
4382 xxx_value = con->tag == Ico_U64
4383 ? st->Ist.Exit.dst->Ico.U64
4384 : (Addr64)(st->Ist.Exit.dst->Ico.U32);
4385
4386 /* If this assertion fails, we have some kind of type error. */
4387 vassert(con->tag == udst->Iex.Const.con->tag);
4388
4389 if (xxx_value != my_addr)
4390 /* We didn't find either idiom. Give up. */
4391 return NULL;
4392
4393 /* Ok, we found idiom #2. Copy the BB, switch around the xxx and
4394 yyy values (which makes it look like idiom #1), and go into
4395 unrolling proper. This means finding (again) the last stmt, in
4396 the copied BB. */
4397
4398 unroll_factor = calc_unroll_factor( bb0 );
4399 if (unroll_factor < 2)
4400 return NULL;
4401
sewardjdd40fdf2006-12-24 02:20:24 +00004402 bb1 = deepCopyIRSB( bb0 );
sewardj08210532004-12-29 17:09:11 +00004403 bb0 = NULL;
4404 udst = NULL; /* is now invalid */
4405 for (i = bb1->stmts_used-1; i >= 0; i--)
4406 if (bb1->stmts[i])
4407 break;
4408
4409 /* The next bunch of assertions should be true since we already
4410 found and checked the last stmt in the original bb. */
4411
4412 vassert(i >= 0);
4413
4414 st = bb1->stmts[i];
4415 vassert(st->tag == Ist_Exit);
4416
4417 con = st->Ist.Exit.dst;
4418 vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
4419
4420 udst = bb1->next;
4421 vassert(udst->tag == Iex_Const);
4422 vassert(udst->Iex.Const.con->tag == Ico_U32
4423 || udst->Iex.Const.con->tag == Ico_U64);
4424 vassert(con->tag == udst->Iex.Const.con->tag);
4425
4426 /* switch the xxx and yyy fields around */
4427 if (con->tag == Ico_U64) {
4428 udst->Iex.Const.con->Ico.U64 = xxx_value;
4429 con->Ico.U64 = yyy_value;
4430 } else {
4431 udst->Iex.Const.con->Ico.U32 = (UInt)xxx_value;
cerion57b4c6d2005-02-22 11:07:35 +00004432 con->Ico.U32 = (UInt)yyy_value;
sewardj08210532004-12-29 17:09:11 +00004433 }
4434
4435 /* negate the test condition */
4436 st->Ist.Exit.guard
sewardjdd40fdf2006-12-24 02:20:24 +00004437 = IRExpr_Unop(Iop_Not1,deepCopyIRExpr(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +00004438
4439 /* --- The unroller proper. Both idioms are by now --- */
4440 /* --- now converted to idiom 1. --- */
4441
4442 do_unroll:
4443
4444 vassert(unroll_factor == 2
4445 || unroll_factor == 4
4446 || unroll_factor == 8);
4447
4448 jmax = unroll_factor==8 ? 3 : (unroll_factor==4 ? 2 : 1);
4449 for (j = 1; j <= jmax; j++) {
4450
4451 n_vars = bb1->tyenv->types_used;
4452
sewardjdd40fdf2006-12-24 02:20:24 +00004453 bb2 = deepCopyIRSB(bb1);
sewardj08210532004-12-29 17:09:11 +00004454 for (i = 0; i < n_vars; i++)
4455 (void)newIRTemp(bb1->tyenv, bb2->tyenv->types[i]);
4456
4457 for (i = 0; i < bb2->stmts_used; i++) {
sewardj08210532004-12-29 17:09:11 +00004458 /* deltaIRStmt destructively modifies the stmt, but
4459 that's OK since bb2 is a complete fresh copy of bb1. */
4460 deltaIRStmt(bb2->stmts[i], n_vars);
sewardjdd40fdf2006-12-24 02:20:24 +00004461 addStmtToIRSB(bb1, bb2->stmts[i]);
sewardj08210532004-12-29 17:09:11 +00004462 }
4463 }
4464
4465 if (DEBUG_IROPT) {
4466 vex_printf("\nUNROLLED (%llx)\n", my_addr);
sewardjdd40fdf2006-12-24 02:20:24 +00004467 ppIRSB(bb1);
sewardj08210532004-12-29 17:09:11 +00004468 vex_printf("\n");
4469 }
4470
4471 /* Flattening; sigh. The unroller succeeds in breaking flatness
4472 by negating the test condition. This should be fixed properly.
4473 For the moment use this shotgun approach. */
4474 return flatten_BB(bb1);
4475}
4476
4477
4478/*---------------------------------------------------------------*/
sewardj29632392004-08-22 02:38:11 +00004479/*--- The tree builder ---*/
4480/*---------------------------------------------------------------*/
4481
sewardj08210532004-12-29 17:09:11 +00004482/* This isn't part of IR optimisation. Really it's a pass done prior
4483 to instruction selection, which improves the code that the
4484 instruction selector can produce. */
4485
sewardjf9517d02005-11-28 13:39:37 +00004486/* --- The 'tmp' environment is the central data structure here --- */
sewardj29632392004-08-22 02:38:11 +00004487
sewardjf9517d02005-11-28 13:39:37 +00004488/* The number of outstanding bindings we're prepared to track.
4489 The number of times the env becomes full and we have to dump
4490 the oldest binding (hence reducing code quality) falls very
4491 rapidly as the env size increases. 8 gives reasonable performance
4492 under most circumstances. */
4493#define A_NENV 10
4494
4495/* bindee == NULL === slot is not in use
4496 bindee != NULL === slot is in use
sewardj29632392004-08-22 02:38:11 +00004497*/
sewardjf9517d02005-11-28 13:39:37 +00004498typedef
4499 struct {
4500 IRTemp binder;
4501 IRExpr* bindee;
4502 Bool doesLoad;
4503 Bool doesGet;
sewardj17442fe2004-09-20 14:54:28 +00004504 }
sewardjf9517d02005-11-28 13:39:37 +00004505 ATmpInfo;
sewardj17442fe2004-09-20 14:54:28 +00004506
sewardjf9517d02005-11-28 13:39:37 +00004507__attribute__((unused))
4508static void ppAEnv ( ATmpInfo* env )
sewardj29632392004-08-22 02:38:11 +00004509{
sewardj17442fe2004-09-20 14:54:28 +00004510 Int i;
sewardjf9517d02005-11-28 13:39:37 +00004511 for (i = 0; i < A_NENV; i++) {
4512 vex_printf("%d tmp %d val ", i, (Int)env[i].binder);
4513 if (env[i].bindee)
4514 ppIRExpr(env[i].bindee);
4515 else
4516 vex_printf("(null)");
4517 vex_printf("\n");
sewardj29632392004-08-22 02:38:11 +00004518 }
4519}
4520
sewardjf9517d02005-11-28 13:39:37 +00004521/* --- Tree-traversal fns --- */
sewardj29632392004-08-22 02:38:11 +00004522
sewardj37d38012004-08-24 00:37:04 +00004523/* Traverse an expr, and detect if any part of it reads memory or does
4524 a Get. Be careful ... this really controls how much the
4525 tree-builder can reorder the code, so getting it right is critical.
4526*/
sewardj29632392004-08-22 02:38:11 +00004527static void setHints_Expr (Bool* doesLoad, Bool* doesGet, IRExpr* e )
4528{
sewardjc41f1fb2004-08-22 09:48:08 +00004529 Int i;
sewardj29632392004-08-22 02:38:11 +00004530 switch (e->tag) {
sewardjc41f1fb2004-08-22 09:48:08 +00004531 case Iex_CCall:
4532 for (i = 0; e->Iex.CCall.args[i]; i++)
4533 setHints_Expr(doesLoad, doesGet, e->Iex.CCall.args[i]);
4534 return;
4535 case Iex_Mux0X:
4536 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.cond);
4537 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.expr0);
4538 setHints_Expr(doesLoad, doesGet, e->Iex.Mux0X.exprX);
4539 return;
sewardj40c80262006-02-08 19:30:46 +00004540 case Iex_Qop:
florian96d7cc32012-06-01 20:41:24 +00004541 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.details->arg1);
4542 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.details->arg2);
4543 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.details->arg3);
4544 setHints_Expr(doesLoad, doesGet, e->Iex.Qop.details->arg4);
sewardj40c80262006-02-08 19:30:46 +00004545 return;
sewardjb183b852006-02-03 16:08:03 +00004546 case Iex_Triop:
florian420bfa92012-06-02 20:29:22 +00004547 setHints_Expr(doesLoad, doesGet, e->Iex.Triop.details->arg1);
4548 setHints_Expr(doesLoad, doesGet, e->Iex.Triop.details->arg2);
4549 setHints_Expr(doesLoad, doesGet, e->Iex.Triop.details->arg3);
sewardjb183b852006-02-03 16:08:03 +00004550 return;
sewardjc41f1fb2004-08-22 09:48:08 +00004551 case Iex_Binop:
4552 setHints_Expr(doesLoad, doesGet, e->Iex.Binop.arg1);
4553 setHints_Expr(doesLoad, doesGet, e->Iex.Binop.arg2);
4554 return;
4555 case Iex_Unop:
4556 setHints_Expr(doesLoad, doesGet, e->Iex.Unop.arg);
4557 return;
sewardjaf1ceca2005-06-30 23:31:27 +00004558 case Iex_Load:
sewardjc9ad1152004-10-14 00:08:21 +00004559 *doesLoad = True;
sewardjaf1ceca2005-06-30 23:31:27 +00004560 setHints_Expr(doesLoad, doesGet, e->Iex.Load.addr);
sewardjc41f1fb2004-08-22 09:48:08 +00004561 return;
sewardj29632392004-08-22 02:38:11 +00004562 case Iex_Get:
sewardjc9ad1152004-10-14 00:08:21 +00004563 *doesGet = True;
sewardj29632392004-08-22 02:38:11 +00004564 return;
sewardjf6501992004-08-27 11:58:24 +00004565 case Iex_GetI:
sewardjc9ad1152004-10-14 00:08:21 +00004566 *doesGet = True;
sewardjeeac8412004-11-02 00:26:55 +00004567 setHints_Expr(doesLoad, doesGet, e->Iex.GetI.ix);
sewardjf6501992004-08-27 11:58:24 +00004568 return;
sewardjdd40fdf2006-12-24 02:20:24 +00004569 case Iex_RdTmp:
sewardjc41f1fb2004-08-22 09:48:08 +00004570 case Iex_Const:
4571 return;
sewardj29632392004-08-22 02:38:11 +00004572 default:
4573 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4574 vpanic("setHints_Expr");
4575 }
4576}
4577
4578
sewardjf9517d02005-11-28 13:39:37 +00004579/* Add a binding to the front of the env and slide all the rest
4580 backwards. It should be the case that the last slot is free. */
4581static void addToEnvFront ( ATmpInfo* env, IRTemp binder, IRExpr* bindee )
sewardj29632392004-08-22 02:38:11 +00004582{
sewardjf9517d02005-11-28 13:39:37 +00004583 Int i;
4584 vassert(env[A_NENV-1].bindee == NULL);
4585 for (i = A_NENV-1; i >= 1; i--)
4586 env[i] = env[i-1];
4587 env[0].binder = binder;
4588 env[0].bindee = bindee;
4589 env[0].doesLoad = False; /* filled in later */
4590 env[0].doesGet = False; /* filled in later */
4591}
sewardj29632392004-08-22 02:38:11 +00004592
sewardjf9517d02005-11-28 13:39:37 +00004593/* Given uses :: array of UShort, indexed by IRTemp
4594 Add the use-occurrences of temps in this expression
4595 to the env.
4596*/
4597static void aoccCount_Expr ( UShort* uses, IRExpr* e )
4598{
4599 Int i;
sewardj29632392004-08-22 02:38:11 +00004600
sewardjf9517d02005-11-28 13:39:37 +00004601 switch (e->tag) {
4602
sewardjdd40fdf2006-12-24 02:20:24 +00004603 case Iex_RdTmp: /* the only interesting case */
4604 uses[e->Iex.RdTmp.tmp]++;
sewardj8bee6d12005-03-22 02:24:05 +00004605 return;
sewardj29632392004-08-22 02:38:11 +00004606
sewardjf9517d02005-11-28 13:39:37 +00004607 case Iex_Mux0X:
4608 aoccCount_Expr(uses, e->Iex.Mux0X.cond);
4609 aoccCount_Expr(uses, e->Iex.Mux0X.expr0);
4610 aoccCount_Expr(uses, e->Iex.Mux0X.exprX);
4611 return;
sewardj29632392004-08-22 02:38:11 +00004612
sewardj40c80262006-02-08 19:30:46 +00004613 case Iex_Qop:
florian96d7cc32012-06-01 20:41:24 +00004614 aoccCount_Expr(uses, e->Iex.Qop.details->arg1);
4615 aoccCount_Expr(uses, e->Iex.Qop.details->arg2);
4616 aoccCount_Expr(uses, e->Iex.Qop.details->arg3);
4617 aoccCount_Expr(uses, e->Iex.Qop.details->arg4);
sewardj40c80262006-02-08 19:30:46 +00004618 return;
4619
sewardjb183b852006-02-03 16:08:03 +00004620 case Iex_Triop:
florian420bfa92012-06-02 20:29:22 +00004621 aoccCount_Expr(uses, e->Iex.Triop.details->arg1);
4622 aoccCount_Expr(uses, e->Iex.Triop.details->arg2);
4623 aoccCount_Expr(uses, e->Iex.Triop.details->arg3);
sewardjb183b852006-02-03 16:08:03 +00004624 return;
4625
sewardjf9517d02005-11-28 13:39:37 +00004626 case Iex_Binop:
4627 aoccCount_Expr(uses, e->Iex.Binop.arg1);
4628 aoccCount_Expr(uses, e->Iex.Binop.arg2);
4629 return;
sewardj29632392004-08-22 02:38:11 +00004630
sewardjf9517d02005-11-28 13:39:37 +00004631 case Iex_Unop:
4632 aoccCount_Expr(uses, e->Iex.Unop.arg);
4633 return;
4634
4635 case Iex_Load:
4636 aoccCount_Expr(uses, e->Iex.Load.addr);
4637 return;
4638
4639 case Iex_CCall:
4640 for (i = 0; e->Iex.CCall.args[i]; i++)
4641 aoccCount_Expr(uses, e->Iex.CCall.args[i]);
4642 return;
4643
4644 case Iex_GetI:
4645 aoccCount_Expr(uses, e->Iex.GetI.ix);
4646 return;
4647
4648 case Iex_Const:
4649 case Iex_Get:
4650 return;
4651
4652 default:
4653 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4654 vpanic("aoccCount_Expr");
4655 }
sewardj29632392004-08-22 02:38:11 +00004656}
4657
4658
sewardjf9517d02005-11-28 13:39:37 +00004659/* Given uses :: array of UShort, indexed by IRTemp
4660 Add the use-occurrences of temps in this statement
4661 to the env.
4662*/
4663static void aoccCount_Stmt ( UShort* uses, IRStmt* st )
sewardj29632392004-08-22 02:38:11 +00004664{
sewardjf9517d02005-11-28 13:39:37 +00004665 Int i;
4666 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00004667 IRCAS* cas;
sewardjf9517d02005-11-28 13:39:37 +00004668 switch (st->tag) {
4669 case Ist_AbiHint:
4670 aoccCount_Expr(uses, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +00004671 aoccCount_Expr(uses, st->Ist.AbiHint.nia);
sewardjf9517d02005-11-28 13:39:37 +00004672 return;
sewardjdd40fdf2006-12-24 02:20:24 +00004673 case Ist_WrTmp:
4674 aoccCount_Expr(uses, st->Ist.WrTmp.data);
sewardjf9517d02005-11-28 13:39:37 +00004675 return;
4676 case Ist_Put:
4677 aoccCount_Expr(uses, st->Ist.Put.data);
4678 return;
4679 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +00004680 aoccCount_Expr(uses, st->Ist.PutI.details->ix);
4681 aoccCount_Expr(uses, st->Ist.PutI.details->data);
sewardjf9517d02005-11-28 13:39:37 +00004682 return;
4683 case Ist_Store:
4684 aoccCount_Expr(uses, st->Ist.Store.addr);
4685 aoccCount_Expr(uses, st->Ist.Store.data);
4686 return;
sewardje9d8a262009-07-01 08:06:34 +00004687 case Ist_CAS:
4688 cas = st->Ist.CAS.details;
4689 aoccCount_Expr(uses, cas->addr);
4690 if (cas->expdHi)
4691 aoccCount_Expr(uses, cas->expdHi);
4692 aoccCount_Expr(uses, cas->expdLo);
4693 if (cas->dataHi)
4694 aoccCount_Expr(uses, cas->dataHi);
4695 aoccCount_Expr(uses, cas->dataLo);
4696 return;
sewardje768e922009-11-26 17:17:37 +00004697 case Ist_LLSC:
4698 aoccCount_Expr(uses, st->Ist.LLSC.addr);
4699 if (st->Ist.LLSC.storedata)
4700 aoccCount_Expr(uses, st->Ist.LLSC.storedata);
4701 return;
sewardjf9517d02005-11-28 13:39:37 +00004702 case Ist_Dirty:
4703 d = st->Ist.Dirty.details;
4704 if (d->mFx != Ifx_None)
4705 aoccCount_Expr(uses, d->mAddr);
4706 aoccCount_Expr(uses, d->guard);
4707 for (i = 0; d->args[i]; i++)
4708 aoccCount_Expr(uses, d->args[i]);
4709 return;
4710 case Ist_NoOp:
4711 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00004712 case Ist_MBE:
sewardjf9517d02005-11-28 13:39:37 +00004713 return;
4714 case Ist_Exit:
4715 aoccCount_Expr(uses, st->Ist.Exit.guard);
4716 return;
4717 default:
4718 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
4719 vpanic("aoccCount_Stmt");
4720 }
4721}
4722
4723/* Look up a binding for tmp in the env. If found, return the bound
4724 expression, and set the env's binding to NULL so it is marked as
4725 used. If not found, return NULL. */
4726
4727static IRExpr* atbSubst_Temp ( ATmpInfo* env, IRTemp tmp )
4728{
4729 Int i;
4730 for (i = 0; i < A_NENV; i++) {
4731 if (env[i].binder == tmp && env[i].bindee != NULL) {
4732 IRExpr* bindee = env[i].bindee;
4733 env[i].bindee = NULL;
4734 return bindee;
4735 }
4736 }
4737 return NULL;
4738}
4739
4740/* Traverse e, looking for temps. For each observed temp, see if env
4741 contains a binding for the temp, and if so return the bound value.
4742 The env has the property that any binding it holds is
4743 'single-shot', so once a binding is used, it is marked as no longer
4744 available, by setting its .bindee field to NULL. */
4745
sewardjeb17e492007-08-25 23:07:44 +00004746static inline Bool is_Unop ( IRExpr* e, IROp op ) {
4747 return e->tag == Iex_Unop && e->Iex.Unop.op == op;
4748}
4749static inline Bool is_Binop ( IRExpr* e, IROp op ) {
4750 return e->tag == Iex_Binop && e->Iex.Binop.op == op;
4751}
4752
4753static IRExpr* fold_IRExpr_Binop ( IROp op, IRExpr* a1, IRExpr* a2 )
4754{
4755 switch (op) {
4756 case Iop_Or32:
4757 /* Or32( CmpwNEZ32(x), CmpwNEZ32(y) ) --> CmpwNEZ32( Or32( x, y ) ) */
4758 if (is_Unop(a1, Iop_CmpwNEZ32) && is_Unop(a2, Iop_CmpwNEZ32))
4759 return IRExpr_Unop( Iop_CmpwNEZ32,
4760 IRExpr_Binop( Iop_Or32, a1->Iex.Unop.arg,
4761 a2->Iex.Unop.arg ) );
4762 break;
florian51d26fd2011-07-23 00:23:02 +00004763
4764 case Iop_CmpNE32:
4765 /* Since X has type Ity_I1 we can simplify:
4766 CmpNE32(1Uto32(X),0)) ==> X */
4767 if (is_Unop(a1, Iop_1Uto32) && isZeroU32(a2))
4768 return a1->Iex.Unop.arg;
4769 break;
4770
sewardjeb17e492007-08-25 23:07:44 +00004771 default:
4772 break;
4773 }
4774 /* no reduction rule applies */
4775 return IRExpr_Binop( op, a1, a2 );
4776}
4777
4778static IRExpr* fold_IRExpr_Unop ( IROp op, IRExpr* aa )
4779{
4780 switch (op) {
4781 case Iop_CmpwNEZ64:
4782 /* CmpwNEZ64( Or64 ( CmpwNEZ64(x), y ) ) --> CmpwNEZ64( Or64( x, y ) ) */
4783 if (is_Binop(aa, Iop_Or64)
4784 && is_Unop(aa->Iex.Binop.arg1, Iop_CmpwNEZ64))
4785 return fold_IRExpr_Unop(
4786 Iop_CmpwNEZ64,
4787 IRExpr_Binop(Iop_Or64,
4788 aa->Iex.Binop.arg1->Iex.Unop.arg,
4789 aa->Iex.Binop.arg2));
4790 /* CmpwNEZ64( Or64 ( x, CmpwNEZ64(y) ) ) --> CmpwNEZ64( Or64( x, y ) ) */
4791 if (is_Binop(aa, Iop_Or64)
4792 && is_Unop(aa->Iex.Binop.arg2, Iop_CmpwNEZ64))
4793 return fold_IRExpr_Unop(
4794 Iop_CmpwNEZ64,
4795 IRExpr_Binop(Iop_Or64,
4796 aa->Iex.Binop.arg1,
4797 aa->Iex.Binop.arg2->Iex.Unop.arg));
4798 break;
4799 case Iop_CmpNEZ64:
4800 /* CmpNEZ64( Left64(x) ) --> CmpNEZ64(x) */
4801 if (is_Unop(aa, Iop_Left64))
4802 return IRExpr_Unop(Iop_CmpNEZ64, aa->Iex.Unop.arg);
4803 break;
4804 case Iop_CmpwNEZ32:
4805 /* CmpwNEZ32( CmpwNEZ32 ( x ) ) --> CmpwNEZ32 ( x ) */
4806 if (is_Unop(aa, Iop_CmpwNEZ32))
4807 return IRExpr_Unop( Iop_CmpwNEZ32, aa->Iex.Unop.arg );
4808 break;
4809 case Iop_CmpNEZ32:
4810 /* CmpNEZ32( Left32(x) ) --> CmpNEZ32(x) */
4811 if (is_Unop(aa, Iop_Left32))
4812 return IRExpr_Unop(Iop_CmpNEZ32, aa->Iex.Unop.arg);
florian51d26fd2011-07-23 00:23:02 +00004813 /* CmpNEZ32( 1Uto32(X) ) --> X */
4814 if (is_Unop(aa, Iop_1Uto32))
4815 return aa->Iex.Unop.arg;
4816 break;
4817 case Iop_CmpNEZ8:
4818 /* CmpNEZ8( 1Uto8(X) ) --> X */
4819 if (is_Unop(aa, Iop_1Uto8))
4820 return aa->Iex.Unop.arg;
sewardjeb17e492007-08-25 23:07:44 +00004821 break;
4822 case Iop_Left32:
4823 /* Left32( Left32(x) ) --> Left32(x) */
4824 if (is_Unop(aa, Iop_Left32))
4825 return IRExpr_Unop( Iop_Left32, aa->Iex.Unop.arg );
4826 break;
4827 case Iop_32to1:
4828 /* 32to1( 1Uto32 ( x ) ) --> x */
4829 if (is_Unop(aa, Iop_1Uto32))
4830 return aa->Iex.Unop.arg;
4831 /* 32to1( CmpwNEZ32 ( x )) --> CmpNEZ32(x) */
4832 if (is_Unop(aa, Iop_CmpwNEZ32))
4833 return IRExpr_Unop( Iop_CmpNEZ32, aa->Iex.Unop.arg );
4834 break;
4835 case Iop_64to1:
4836 /* 64to1( 1Uto64 ( x ) ) --> x */
4837 if (is_Unop(aa, Iop_1Uto64))
4838 return aa->Iex.Unop.arg;
4839 /* 64to1( CmpwNEZ64 ( x )) --> CmpNEZ64(x) */
4840 if (is_Unop(aa, Iop_CmpwNEZ64))
4841 return IRExpr_Unop( Iop_CmpNEZ64, aa->Iex.Unop.arg );
4842 break;
sewardjef425db2010-01-11 10:46:18 +00004843 case Iop_64to32:
4844 /* 64to32( 32Uto64 ( x )) --> x */
4845 if (is_Unop(aa, Iop_32Uto64))
4846 return aa->Iex.Unop.arg;
sewardjca257bc2010-09-08 08:34:52 +00004847 /* 64to32( 8Uto64 ( x )) --> 8Uto32(x) */
4848 if (is_Unop(aa, Iop_8Uto64))
4849 return IRExpr_Unop(Iop_8Uto32, aa->Iex.Unop.arg);
4850 break;
4851
4852 case Iop_32Uto64:
4853 /* 32Uto64( 8Uto32( x )) --> 8Uto64(x) */
4854 if (is_Unop(aa, Iop_8Uto32))
4855 return IRExpr_Unop(Iop_8Uto64, aa->Iex.Unop.arg);
4856 /* 32Uto64( 16Uto32( x )) --> 16Uto64(x) */
4857 if (is_Unop(aa, Iop_16Uto32))
4858 return IRExpr_Unop(Iop_16Uto64, aa->Iex.Unop.arg);
sewardjbba356d2012-04-25 16:47:53 +00004859 /* 32Uto64(64to32( Shr64( 32Uto64(64to32(x)), sh ))
4860 --> Shr64( 32Uto64(64to32(x)), sh )) */
4861 if (is_Unop(aa, Iop_64to32)
4862 && is_Binop(aa->Iex.Unop.arg, Iop_Shr64)
4863 && is_Unop(aa->Iex.Unop.arg->Iex.Binop.arg1, Iop_32Uto64)
4864 && is_Unop(aa->Iex.Unop.arg->Iex.Binop.arg1->Iex.Unop.arg,
4865 Iop_64to32)) {
4866 return aa->Iex.Unop.arg;
4867 }
4868 /* 32Uto64(64to32( Shl64( 32Uto64(64to32(x)), sh ))
4869 --> 32Uto64(64to32( Shl64( x, sh )) */
4870 if (is_Unop(aa, Iop_64to32)
4871 && is_Binop(aa->Iex.Unop.arg, Iop_Shl64)
4872 && is_Unop(aa->Iex.Unop.arg->Iex.Binop.arg1, Iop_32Uto64)
4873 && is_Unop(aa->Iex.Unop.arg->Iex.Binop.arg1->Iex.Unop.arg,
4874 Iop_64to32)) {
4875 return
4876 IRExpr_Unop(
4877 Iop_32Uto64,
4878 IRExpr_Unop(
4879 Iop_64to32,
4880 IRExpr_Binop(
4881 Iop_Shl64,
4882 aa->Iex.Unop.arg->Iex.Binop.arg1->Iex.Unop.arg->Iex.Unop.arg,
4883 aa->Iex.Unop.arg->Iex.Binop.arg2
4884 )));
4885 }
sewardjef425db2010-01-11 10:46:18 +00004886 break;
sewardj6c299f32009-12-31 18:00:12 +00004887
4888 case Iop_1Sto32:
4889 /* 1Sto32( CmpNEZ8( 32to8( 1Uto32( CmpNEZ32( x ))))) -> CmpwNEZ32(x) */
4890 if (is_Unop(aa, Iop_CmpNEZ8)
4891 && is_Unop(aa->Iex.Unop.arg, Iop_32to8)
4892 && is_Unop(aa->Iex.Unop.arg->Iex.Unop.arg, Iop_1Uto32)
4893 && is_Unop(aa->Iex.Unop.arg->Iex.Unop.arg->Iex.Unop.arg,
4894 Iop_CmpNEZ32)) {
4895 return IRExpr_Unop( Iop_CmpwNEZ32,
4896 aa->Iex.Unop.arg->Iex.Unop.arg
4897 ->Iex.Unop.arg->Iex.Unop.arg);
4898 }
4899 break;
4900
sewardjeb17e492007-08-25 23:07:44 +00004901 default:
4902 break;
4903 }
4904 /* no reduction rule applies */
4905 return IRExpr_Unop( op, aa );
4906}
4907
sewardjf9517d02005-11-28 13:39:37 +00004908static IRExpr* atbSubst_Expr ( ATmpInfo* env, IRExpr* e )
4909{
4910 IRExpr* e2;
4911 IRExpr** args2;
4912 Int i;
4913
4914 switch (e->tag) {
4915
4916 case Iex_CCall:
sewardjdd40fdf2006-12-24 02:20:24 +00004917 args2 = shallowCopyIRExprVec(e->Iex.CCall.args);
sewardjf9517d02005-11-28 13:39:37 +00004918 for (i = 0; args2[i]; i++)
4919 args2[i] = atbSubst_Expr(env,args2[i]);
4920 return IRExpr_CCall(
4921 e->Iex.CCall.cee,
4922 e->Iex.CCall.retty,
4923 args2
4924 );
sewardjdd40fdf2006-12-24 02:20:24 +00004925 case Iex_RdTmp:
4926 e2 = atbSubst_Temp(env, e->Iex.RdTmp.tmp);
sewardjf9517d02005-11-28 13:39:37 +00004927 return e2 ? e2 : e;
4928 case Iex_Mux0X:
4929 return IRExpr_Mux0X(
4930 atbSubst_Expr(env, e->Iex.Mux0X.cond),
4931 atbSubst_Expr(env, e->Iex.Mux0X.expr0),
4932 atbSubst_Expr(env, e->Iex.Mux0X.exprX)
4933 );
sewardj40c80262006-02-08 19:30:46 +00004934 case Iex_Qop:
4935 return IRExpr_Qop(
florian96d7cc32012-06-01 20:41:24 +00004936 e->Iex.Qop.details->op,
4937 atbSubst_Expr(env, e->Iex.Qop.details->arg1),
4938 atbSubst_Expr(env, e->Iex.Qop.details->arg2),
4939 atbSubst_Expr(env, e->Iex.Qop.details->arg3),
4940 atbSubst_Expr(env, e->Iex.Qop.details->arg4)
sewardj40c80262006-02-08 19:30:46 +00004941 );
sewardjb183b852006-02-03 16:08:03 +00004942 case Iex_Triop:
4943 return IRExpr_Triop(
florian420bfa92012-06-02 20:29:22 +00004944 e->Iex.Triop.details->op,
4945 atbSubst_Expr(env, e->Iex.Triop.details->arg1),
4946 atbSubst_Expr(env, e->Iex.Triop.details->arg2),
4947 atbSubst_Expr(env, e->Iex.Triop.details->arg3)
sewardjb183b852006-02-03 16:08:03 +00004948 );
sewardjf9517d02005-11-28 13:39:37 +00004949 case Iex_Binop:
sewardjeb17e492007-08-25 23:07:44 +00004950 return fold_IRExpr_Binop(
sewardjf9517d02005-11-28 13:39:37 +00004951 e->Iex.Binop.op,
4952 atbSubst_Expr(env, e->Iex.Binop.arg1),
4953 atbSubst_Expr(env, e->Iex.Binop.arg2)
4954 );
4955 case Iex_Unop:
sewardjeb17e492007-08-25 23:07:44 +00004956 return fold_IRExpr_Unop(
sewardjf9517d02005-11-28 13:39:37 +00004957 e->Iex.Unop.op,
4958 atbSubst_Expr(env, e->Iex.Unop.arg)
4959 );
4960 case Iex_Load:
4961 return IRExpr_Load(
4962 e->Iex.Load.end,
4963 e->Iex.Load.ty,
4964 atbSubst_Expr(env, e->Iex.Load.addr)
4965 );
4966 case Iex_GetI:
4967 return IRExpr_GetI(
4968 e->Iex.GetI.descr,
4969 atbSubst_Expr(env, e->Iex.GetI.ix),
4970 e->Iex.GetI.bias
4971 );
4972 case Iex_Const:
4973 case Iex_Get:
4974 return e;
4975 default:
4976 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4977 vpanic("atbSubst_Expr");
4978 }
4979}
4980
4981/* Same deal as atbSubst_Expr, except for stmts. */
4982
4983static IRStmt* atbSubst_Stmt ( ATmpInfo* env, IRStmt* st )
4984{
sewardje9d8a262009-07-01 08:06:34 +00004985 Int i;
4986 IRDirty *d, *d2;
4987 IRCAS *cas, *cas2;
floriand6f38b32012-05-31 15:46:18 +00004988 IRPutI *puti, *puti2;
4989
sewardjf9517d02005-11-28 13:39:37 +00004990 switch (st->tag) {
4991 case Ist_AbiHint:
4992 return IRStmt_AbiHint(
4993 atbSubst_Expr(env, st->Ist.AbiHint.base),
sewardj478646f2008-05-01 20:13:04 +00004994 st->Ist.AbiHint.len,
4995 atbSubst_Expr(env, st->Ist.AbiHint.nia)
sewardjf9517d02005-11-28 13:39:37 +00004996 );
4997 case Ist_Store:
4998 return IRStmt_Store(
4999 st->Ist.Store.end,
5000 atbSubst_Expr(env, st->Ist.Store.addr),
5001 atbSubst_Expr(env, st->Ist.Store.data)
5002 );
sewardjdd40fdf2006-12-24 02:20:24 +00005003 case Ist_WrTmp:
5004 return IRStmt_WrTmp(
5005 st->Ist.WrTmp.tmp,
5006 atbSubst_Expr(env, st->Ist.WrTmp.data)
sewardjf9517d02005-11-28 13:39:37 +00005007 );
5008 case Ist_Put:
5009 return IRStmt_Put(
5010 st->Ist.Put.offset,
5011 atbSubst_Expr(env, st->Ist.Put.data)
5012 );
5013 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +00005014 puti = st->Ist.PutI.details;
5015 puti2 = mkIRPutI(puti->descr,
5016 atbSubst_Expr(env, puti->ix),
5017 puti->bias,
5018 atbSubst_Expr(env, puti->data));
5019 return IRStmt_PutI(puti2);
sewardjf9517d02005-11-28 13:39:37 +00005020
5021 case Ist_Exit:
5022 return IRStmt_Exit(
5023 atbSubst_Expr(env, st->Ist.Exit.guard),
5024 st->Ist.Exit.jk,
sewardjc6f970f2012-04-02 21:54:49 +00005025 st->Ist.Exit.dst,
5026 st->Ist.Exit.offsIP
sewardjf9517d02005-11-28 13:39:37 +00005027 );
5028 case Ist_IMark:
sewardj2f10aa62011-05-27 13:20:56 +00005029 return IRStmt_IMark(st->Ist.IMark.addr,
5030 st->Ist.IMark.len,
5031 st->Ist.IMark.delta);
sewardjf9517d02005-11-28 13:39:37 +00005032 case Ist_NoOp:
5033 return IRStmt_NoOp();
sewardjc4356f02007-11-09 21:15:04 +00005034 case Ist_MBE:
5035 return IRStmt_MBE(st->Ist.MBE.event);
sewardje9d8a262009-07-01 08:06:34 +00005036 case Ist_CAS:
5037 cas = st->Ist.CAS.details;
5038 cas2 = mkIRCAS(
5039 cas->oldHi, cas->oldLo, cas->end,
5040 atbSubst_Expr(env, cas->addr),
5041 cas->expdHi ? atbSubst_Expr(env, cas->expdHi) : NULL,
5042 atbSubst_Expr(env, cas->expdLo),
5043 cas->dataHi ? atbSubst_Expr(env, cas->dataHi) : NULL,
5044 atbSubst_Expr(env, cas->dataLo)
5045 );
5046 return IRStmt_CAS(cas2);
sewardje768e922009-11-26 17:17:37 +00005047 case Ist_LLSC:
5048 return IRStmt_LLSC(
5049 st->Ist.LLSC.end,
5050 st->Ist.LLSC.result,
5051 atbSubst_Expr(env, st->Ist.LLSC.addr),
5052 st->Ist.LLSC.storedata
5053 ? atbSubst_Expr(env, st->Ist.LLSC.storedata) : NULL
5054 );
sewardjf9517d02005-11-28 13:39:37 +00005055 case Ist_Dirty:
5056 d = st->Ist.Dirty.details;
5057 d2 = emptyIRDirty();
5058 *d2 = *d;
5059 if (d2->mFx != Ifx_None)
5060 d2->mAddr = atbSubst_Expr(env, d2->mAddr);
5061 d2->guard = atbSubst_Expr(env, d2->guard);
5062 for (i = 0; d2->args[i]; i++)
5063 d2->args[i] = atbSubst_Expr(env, d2->args[i]);
5064 return IRStmt_Dirty(d2);
5065 default:
5066 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
5067 vpanic("atbSubst_Stmt");
5068 }
5069}
5070
sewardjc6f970f2012-04-02 21:54:49 +00005071/* notstatic */ Addr64 ado_treebuild_BB ( IRSB* bb )
sewardjf9517d02005-11-28 13:39:37 +00005072{
5073 Int i, j, k, m;
5074 Bool stmtPuts, stmtStores, invalidateMe;
sewardj29632392004-08-22 02:38:11 +00005075 IRStmt* st;
5076 IRStmt* st2;
sewardjf9517d02005-11-28 13:39:37 +00005077 ATmpInfo env[A_NENV];
sewardj29632392004-08-22 02:38:11 +00005078
sewardjc6f970f2012-04-02 21:54:49 +00005079 Bool max_ga_known = False;
5080 Addr64 max_ga = 0;
5081
sewardjc9ad1152004-10-14 00:08:21 +00005082 Int n_tmps = bb->tyenv->types_used;
sewardjf9517d02005-11-28 13:39:37 +00005083 UShort* uses = LibVEX_Alloc(n_tmps * sizeof(UShort));
sewardj29632392004-08-22 02:38:11 +00005084
5085 /* Phase 1. Scan forwards in bb, counting use occurrences of each
sewardjc6f970f2012-04-02 21:54:49 +00005086 temp. Also count occurrences in the bb->next field. Take the
5087 opportunity to also find the maximum guest address in the block,
5088 since that will be needed later for deciding when we can safely
5089 elide event checks. */
sewardj29632392004-08-22 02:38:11 +00005090
sewardjf9517d02005-11-28 13:39:37 +00005091 for (i = 0; i < n_tmps; i++)
5092 uses[i] = 0;
5093
sewardj29632392004-08-22 02:38:11 +00005094 for (i = 0; i < bb->stmts_used; i++) {
5095 st = bb->stmts[i];
sewardjc6f970f2012-04-02 21:54:49 +00005096 switch (st->tag) {
5097 case Ist_NoOp:
5098 continue;
5099 case Ist_IMark: {
5100 Int len = st->Ist.IMark.len;
5101 Addr64 mga = st->Ist.IMark.addr + (len < 1 ? 1 : len) - 1;
5102 max_ga_known = True;
5103 if (mga > max_ga)
5104 max_ga = mga;
5105 break;
5106 }
5107 default:
5108 break;
5109 }
sewardjf9517d02005-11-28 13:39:37 +00005110 aoccCount_Stmt( uses, st );
sewardj29632392004-08-22 02:38:11 +00005111 }
sewardjf9517d02005-11-28 13:39:37 +00005112 aoccCount_Expr(uses, bb->next );
sewardj29632392004-08-22 02:38:11 +00005113
sewardjc9ad1152004-10-14 00:08:21 +00005114# if 0
sewardjf9517d02005-11-28 13:39:37 +00005115 for (i = 0; i < n_tmps; i++) {
5116 if (uses[i] == 0)
sewardj29632392004-08-22 02:38:11 +00005117 continue;
sewardjf9517d02005-11-28 13:39:37 +00005118 ppIRTemp( (IRTemp)i );
5119 vex_printf(" used %d\n", (Int)uses[i] );
sewardj29632392004-08-22 02:38:11 +00005120 }
sewardjc9ad1152004-10-14 00:08:21 +00005121# endif
sewardj29632392004-08-22 02:38:11 +00005122
sewardjf9517d02005-11-28 13:39:37 +00005123 /* Phase 2. Scan forwards in bb. For each statement in turn:
sewardj29632392004-08-22 02:38:11 +00005124
sewardjf9517d02005-11-28 13:39:37 +00005125 If the env is full, emit the end element. This guarantees
5126 there is at least one free slot in the following.
sewardj29632392004-08-22 02:38:11 +00005127
sewardjf9517d02005-11-28 13:39:37 +00005128 On seeing 't = E', occ(t)==1,
5129 let E'=env(E)
5130 delete this stmt
5131 add t -> E' to the front of the env
5132 Examine E' and set the hints for E' appropriately
sewardj29632392004-08-22 02:38:11 +00005133 (doesLoad? doesGet?)
5134
sewardjf9517d02005-11-28 13:39:37 +00005135 On seeing any other stmt,
sewardj29632392004-08-22 02:38:11 +00005136 let stmt' = env(stmt)
5137 remove from env any 't=E' binds invalidated by stmt
5138 emit the invalidated stmts
5139 emit stmt'
sewardjf9517d02005-11-28 13:39:37 +00005140 compact any holes in env
5141 by sliding entries towards the front
sewardj29632392004-08-22 02:38:11 +00005142
sewardjf9517d02005-11-28 13:39:37 +00005143 Finally, apply env to bb->next.
sewardj29632392004-08-22 02:38:11 +00005144 */
5145
sewardjf9517d02005-11-28 13:39:37 +00005146 for (i = 0; i < A_NENV; i++) {
5147 env[i].bindee = NULL;
5148 env[i].binder = IRTemp_INVALID;
5149 }
5150
sewardj29632392004-08-22 02:38:11 +00005151 /* The stmts in bb are being reordered, and we are guaranteed to
5152 end up with no more than the number we started with. Use i to
5153 be the cursor of the current stmt examined and j <= i to be that
5154 for the current stmt being written.
5155 */
5156 j = 0;
5157 for (i = 0; i < bb->stmts_used; i++) {
sewardjf9517d02005-11-28 13:39:37 +00005158
sewardj29632392004-08-22 02:38:11 +00005159 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00005160 if (st->tag == Ist_NoOp)
sewardj29632392004-08-22 02:38:11 +00005161 continue;
5162
sewardjf9517d02005-11-28 13:39:37 +00005163 /* Ensure there's at least one space in the env, by emitting
5164 the oldest binding if necessary. */
5165 if (env[A_NENV-1].bindee != NULL) {
sewardjdd40fdf2006-12-24 02:20:24 +00005166 bb->stmts[j] = IRStmt_WrTmp( env[A_NENV-1].binder,
5167 env[A_NENV-1].bindee );
sewardjf9517d02005-11-28 13:39:37 +00005168 j++;
5169 vassert(j <= i);
5170 env[A_NENV-1].bindee = NULL;
5171 }
5172
5173 /* Consider current stmt. */
sewardjdd40fdf2006-12-24 02:20:24 +00005174 if (st->tag == Ist_WrTmp && uses[st->Ist.WrTmp.tmp] <= 1) {
sewardj63327402006-01-25 03:26:27 +00005175 IRExpr *e, *e2;
sewardjf9517d02005-11-28 13:39:37 +00005176
5177 /* optional extra: dump dead bindings as we find them.
5178 Removes the need for a prior dead-code removal pass. */
sewardjdd40fdf2006-12-24 02:20:24 +00005179 if (uses[st->Ist.WrTmp.tmp] == 0) {
sewardjb183b852006-02-03 16:08:03 +00005180 if (0) vex_printf("DEAD binding\n");
sewardjf9517d02005-11-28 13:39:37 +00005181 continue; /* for (i = 0; i < bb->stmts_used; i++) loop */
sewardj29632392004-08-22 02:38:11 +00005182 }
sewardjdd40fdf2006-12-24 02:20:24 +00005183 vassert(uses[st->Ist.WrTmp.tmp] == 1);
sewardjf9517d02005-11-28 13:39:37 +00005184
5185 /* ok, we have 't = E', occ(t)==1. Do the abovementioned
5186 actions. */
sewardjdd40fdf2006-12-24 02:20:24 +00005187 e = st->Ist.WrTmp.data;
sewardj63327402006-01-25 03:26:27 +00005188 e2 = atbSubst_Expr(env, e);
sewardjdd40fdf2006-12-24 02:20:24 +00005189 addToEnvFront(env, st->Ist.WrTmp.tmp, e2);
sewardjf9517d02005-11-28 13:39:37 +00005190 setHints_Expr(&env[0].doesLoad, &env[0].doesGet, e2);
5191 /* don't advance j, as we are deleting this stmt and instead
5192 holding it temporarily in the env. */
5193 continue; /* for (i = 0; i < bb->stmts_used; i++) loop */
sewardj29632392004-08-22 02:38:11 +00005194 }
5195
5196 /* we get here for any other kind of statement. */
5197 /* 'use up' any bindings required by the current statement. */
sewardjf9517d02005-11-28 13:39:37 +00005198 st2 = atbSubst_Stmt(env, st);
sewardj29632392004-08-22 02:38:11 +00005199
sewardjf9517d02005-11-28 13:39:37 +00005200 /* Now, before this stmt, dump any bindings in env that it
5201 invalidates. These need to be dumped in the order in which
5202 they originally entered env -- that means from oldest to
5203 youngest. */
sewardj3e838932005-01-07 12:09:15 +00005204
sewardjf9517d02005-11-28 13:39:37 +00005205 /* stmtPuts/stmtStores characterise what the stmt under
sewardje9d8a262009-07-01 08:06:34 +00005206 consideration does, or might do (sidely safe @ True). */
5207 stmtPuts
5208 = toBool( st->tag == Ist_Put
5209 || st->tag == Ist_PutI
5210 || st->tag == Ist_Dirty );
sewardj29632392004-08-22 02:38:11 +00005211
sewardje9d8a262009-07-01 08:06:34 +00005212 /* be True if this stmt writes memory or might do (==> we don't
5213 want to reorder other loads or stores relative to it). Also,
sewardje768e922009-11-26 17:17:37 +00005214 both LL and SC fall under this classification, since we
sewardje9d8a262009-07-01 08:06:34 +00005215 really ought to be conservative and not reorder any other
sewardje768e922009-11-26 17:17:37 +00005216 memory transactions relative to them. */
sewardje9d8a262009-07-01 08:06:34 +00005217 stmtStores
5218 = toBool( st->tag == Ist_Store
sewardje768e922009-11-26 17:17:37 +00005219 || st->tag == Ist_Dirty
sewardj0f621982012-04-12 21:05:16 +00005220 || st->tag == Ist_LLSC
5221 || st->tag == Ist_CAS );
sewardj29632392004-08-22 02:38:11 +00005222
sewardjf9517d02005-11-28 13:39:37 +00005223 for (k = A_NENV-1; k >= 0; k--) {
5224 if (env[k].bindee == NULL)
5225 continue;
5226 /* Compare the actions of this stmt with the actions of
5227 binding 'k', to see if they invalidate the binding. */
5228 invalidateMe
sewardj9d2e7692005-02-07 01:11:31 +00005229 = toBool(
5230 /* a store invalidates loaded data */
sewardjf9517d02005-11-28 13:39:37 +00005231 (env[k].doesLoad && stmtStores)
sewardj4c5f6d52004-10-26 13:25:33 +00005232 /* a put invalidates get'd data */
sewardjf9517d02005-11-28 13:39:37 +00005233 || (env[k].doesGet && stmtPuts)
sewardj4c5f6d52004-10-26 13:25:33 +00005234 /* a put invalidates loaded data. Note, we could do
5235 much better here in the sense that we only need to
5236 invalidate trees containing loads if the Put in
5237 question is marked as requiring precise
5238 exceptions. */
sewardjf9517d02005-11-28 13:39:37 +00005239 || (env[k].doesLoad && stmtPuts)
sewardjc4356f02007-11-09 21:15:04 +00005240 /* probably overly conservative: a memory bus event
sewardj3e838932005-01-07 12:09:15 +00005241 invalidates absolutely everything, so that all
5242 computation prior to it is forced to complete before
sewardjc4356f02007-11-09 21:15:04 +00005243 proceeding with the event (fence,lock,unlock). */
5244 || st->tag == Ist_MBE
sewardj5a9ffab2005-05-12 17:55:01 +00005245 /* also be (probably overly) paranoid re AbiHints */
5246 || st->tag == Ist_AbiHint
sewardj9d2e7692005-02-07 01:11:31 +00005247 );
sewardjf9517d02005-11-28 13:39:37 +00005248 if (invalidateMe) {
sewardjdd40fdf2006-12-24 02:20:24 +00005249 bb->stmts[j] = IRStmt_WrTmp( env[k].binder, env[k].bindee );
sewardjf9517d02005-11-28 13:39:37 +00005250 j++;
5251 vassert(j <= i);
5252 env[k].bindee = NULL;
5253 }
sewardj29632392004-08-22 02:38:11 +00005254 }
5255
sewardjf9517d02005-11-28 13:39:37 +00005256 /* Slide in-use entries in env up to the front */
5257 m = 0;
5258 for (k = 0; k < A_NENV; k++) {
5259 if (env[k].bindee != NULL) {
5260 env[m] = env[k];
5261 m++;
5262 }
5263 }
5264 for (m = m; m < A_NENV; m++) {
5265 env[m].bindee = NULL;
5266 }
sewardj29632392004-08-22 02:38:11 +00005267
5268 /* finally, emit the substituted statement */
5269 bb->stmts[j] = st2;
sewardjf9517d02005-11-28 13:39:37 +00005270 /* vex_printf("**2 "); ppIRStmt(bb->stmts[j]); vex_printf("\n"); */
sewardj29632392004-08-22 02:38:11 +00005271 j++;
5272
5273 vassert(j <= i+1);
5274 } /* for each stmt in the original bb ... */
5275
5276 /* Finally ... substitute the ->next field as much as possible, and
5277 dump any left-over bindings. Hmm. Perhaps there should be no
5278 left over bindings? Or any left-over bindings are
5279 by definition dead? */
sewardjf9517d02005-11-28 13:39:37 +00005280 bb->next = atbSubst_Expr(env, bb->next);
sewardj29632392004-08-22 02:38:11 +00005281 bb->stmts_used = j;
sewardjc6f970f2012-04-02 21:54:49 +00005282
5283 return max_ga_known ? max_ga : ~(Addr64)0;
sewardj29632392004-08-22 02:38:11 +00005284}
5285
5286
sewardj695cff92004-10-13 14:50:14 +00005287/*---------------------------------------------------------------*/
sewardjedf4d692004-08-17 13:52:58 +00005288/*--- iropt main ---*/
5289/*---------------------------------------------------------------*/
5290
sewardjb183b852006-02-03 16:08:03 +00005291static Bool iropt_verbose = False; /* True; */
sewardj4345f7a2004-09-22 19:49:27 +00005292
5293
sewardj4345f7a2004-09-22 19:49:27 +00005294/* Do a simple cleanup pass on bb. This is: redundant Get removal,
5295 redundant Put removal, constant propagation, dead code removal,
5296 clean helper specialisation, and dead code removal (again).
sewardjb9230752004-12-29 19:25:06 +00005297*/
sewardj695cff92004-10-13 14:50:14 +00005298
sewardj4345f7a2004-09-22 19:49:27 +00005299
5300static
sewardjdd40fdf2006-12-24 02:20:24 +00005301IRSB* cheap_transformations (
5302 IRSB* bb,
florian1ff47562012-10-21 02:09:51 +00005303 IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int),
sewardj8d2291c2004-10-25 14:50:21 +00005304 Bool (*preciseMemExnsFn)(Int,Int)
5305 )
sewardj4345f7a2004-09-22 19:49:27 +00005306{
5307 redundant_get_removal_BB ( bb );
5308 if (iropt_verbose) {
5309 vex_printf("\n========= REDUNDANT GET\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005310 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005311 }
sewardj044a2152004-10-21 10:22:10 +00005312
philippe6c46bef2012-08-14 22:29:01 +00005313 if (vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn) {
philippec8e2f982012-08-01 22:04:13 +00005314 redundant_put_removal_BB ( bb, preciseMemExnsFn );
5315 }
sewardj4345f7a2004-09-22 19:49:27 +00005316 if (iropt_verbose) {
5317 vex_printf("\n========= REDUNDANT PUT\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005318 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005319 }
sewardj044a2152004-10-21 10:22:10 +00005320
sewardj4345f7a2004-09-22 19:49:27 +00005321 bb = cprop_BB ( bb );
5322 if (iropt_verbose) {
5323 vex_printf("\n========= CPROPD\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005324 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005325 }
5326
sewardj49651f42004-10-28 22:11:04 +00005327 do_deadcode_BB ( bb );
sewardj4345f7a2004-09-22 19:49:27 +00005328 if (iropt_verbose) {
5329 vex_printf("\n========= DEAD\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005330 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005331 }
5332
sewardjb9230752004-12-29 19:25:06 +00005333 bb = spec_helpers_BB ( bb, specHelper );
sewardj49651f42004-10-28 22:11:04 +00005334 do_deadcode_BB ( bb );
sewardj4345f7a2004-09-22 19:49:27 +00005335 if (iropt_verbose) {
5336 vex_printf("\n========= SPECd \n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005337 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005338 }
5339
5340 return bb;
5341}
5342
sewardj695cff92004-10-13 14:50:14 +00005343
5344/* Do some more expensive transformations on bb, which are aimed at
5345 optimising as much as possible in the presence of GetI and PutI. */
5346
5347static
sewardjdd40fdf2006-12-24 02:20:24 +00005348IRSB* expensive_transformations( IRSB* bb )
sewardj695cff92004-10-13 14:50:14 +00005349{
sewardj9b0cc582006-02-04 15:24:00 +00005350 (void)do_cse_BB( bb );
sewardj695cff92004-10-13 14:50:14 +00005351 collapse_AddSub_chains_BB( bb );
sewardj08210532004-12-29 17:09:11 +00005352 do_redundant_GetI_elimination( bb );
philippe6c46bef2012-08-14 22:29:01 +00005353 if (vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn) {
philippec8e2f982012-08-01 22:04:13 +00005354 do_redundant_PutI_elimination( bb );
5355 }
sewardj49651f42004-10-28 22:11:04 +00005356 do_deadcode_BB( bb );
sewardjb9230752004-12-29 19:25:06 +00005357 return bb;
sewardj695cff92004-10-13 14:50:14 +00005358}
5359
5360
sewardjb183b852006-02-03 16:08:03 +00005361/* Scan a flattened BB to look for signs that more expensive
5362 optimisations might be useful:
5363 - find out if there are any GetIs and PutIs
5364 - find out if there are any floating or vector-typed temporaries
5365*/
sewardj695cff92004-10-13 14:50:14 +00005366
sewardjb183b852006-02-03 16:08:03 +00005367static void considerExpensives ( /*OUT*/Bool* hasGetIorPutI,
5368 /*OUT*/Bool* hasVorFtemps,
sewardjdd40fdf2006-12-24 02:20:24 +00005369 IRSB* bb )
sewardj4345f7a2004-09-22 19:49:27 +00005370{
sewardje9d8a262009-07-01 08:06:34 +00005371 Int i, j;
5372 IRStmt* st;
sewardj4345f7a2004-09-22 19:49:27 +00005373 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00005374 IRCAS* cas;
sewardj4345f7a2004-09-22 19:49:27 +00005375
sewardjb183b852006-02-03 16:08:03 +00005376 *hasGetIorPutI = False;
5377 *hasVorFtemps = False;
5378
sewardj4345f7a2004-09-22 19:49:27 +00005379 for (i = 0; i < bb->stmts_used; i++) {
5380 st = bb->stmts[i];
sewardj4345f7a2004-09-22 19:49:27 +00005381 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00005382 case Ist_AbiHint:
5383 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +00005384 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +00005385 break;
sewardj4345f7a2004-09-22 19:49:27 +00005386 case Ist_PutI:
sewardjb183b852006-02-03 16:08:03 +00005387 *hasGetIorPutI = True;
5388 break;
sewardjdd40fdf2006-12-24 02:20:24 +00005389 case Ist_WrTmp:
5390 if (st->Ist.WrTmp.data->tag == Iex_GetI)
sewardjb183b852006-02-03 16:08:03 +00005391 *hasGetIorPutI = True;
sewardjdd40fdf2006-12-24 02:20:24 +00005392 switch (typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp)) {
sewardjb183b852006-02-03 16:08:03 +00005393 case Ity_I1: case Ity_I8: case Ity_I16:
5394 case Ity_I32: case Ity_I64: case Ity_I128:
5395 break;
sewardjc4530ae2012-05-21 10:18:49 +00005396 case Ity_F32: case Ity_F64: case Ity_F128:
5397 case Ity_V128: case Ity_V256:
sewardjb183b852006-02-03 16:08:03 +00005398 *hasVorFtemps = True;
5399 break;
sewardjc6bbd472012-04-02 10:20:48 +00005400 case Ity_D32: case Ity_D64: case Ity_D128:
5401 *hasVorFtemps = True;
5402 break;
sewardjb183b852006-02-03 16:08:03 +00005403 default:
5404 goto bad;
5405 }
sewardj4345f7a2004-09-22 19:49:27 +00005406 break;
5407 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00005408 vassert(isIRAtom(st->Ist.Put.data));
sewardj4345f7a2004-09-22 19:49:27 +00005409 break;
sewardjaf1ceca2005-06-30 23:31:27 +00005410 case Ist_Store:
5411 vassert(isIRAtom(st->Ist.Store.addr));
5412 vassert(isIRAtom(st->Ist.Store.data));
sewardj4345f7a2004-09-22 19:49:27 +00005413 break;
sewardje9d8a262009-07-01 08:06:34 +00005414 case Ist_CAS:
5415 cas = st->Ist.CAS.details;
5416 vassert(isIRAtom(cas->addr));
5417 vassert(cas->expdHi == NULL || isIRAtom(cas->expdHi));
5418 vassert(isIRAtom(cas->expdLo));
5419 vassert(cas->dataHi == NULL || isIRAtom(cas->dataHi));
5420 vassert(isIRAtom(cas->dataLo));
5421 break;
sewardje768e922009-11-26 17:17:37 +00005422 case Ist_LLSC:
5423 vassert(isIRAtom(st->Ist.LLSC.addr));
5424 if (st->Ist.LLSC.storedata)
5425 vassert(isIRAtom(st->Ist.LLSC.storedata));
5426 break;
sewardj4345f7a2004-09-22 19:49:27 +00005427 case Ist_Dirty:
5428 d = st->Ist.Dirty.details;
sewardj496a58d2005-03-20 18:44:44 +00005429 vassert(isIRAtom(d->guard));
sewardj4345f7a2004-09-22 19:49:27 +00005430 for (j = 0; d->args[j]; j++)
sewardj496a58d2005-03-20 18:44:44 +00005431 vassert(isIRAtom(d->args[j]));
sewardj4345f7a2004-09-22 19:49:27 +00005432 if (d->mFx != Ifx_None)
sewardj496a58d2005-03-20 18:44:44 +00005433 vassert(isIRAtom(d->mAddr));
sewardj4345f7a2004-09-22 19:49:27 +00005434 break;
sewardjd2445f62005-03-21 00:15:53 +00005435 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00005436 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00005437 case Ist_MBE:
sewardj3e838932005-01-07 12:09:15 +00005438 break;
5439 case Ist_Exit:
sewardj496a58d2005-03-20 18:44:44 +00005440 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj3e838932005-01-07 12:09:15 +00005441 break;
sewardj4345f7a2004-09-22 19:49:27 +00005442 default:
sewardjb183b852006-02-03 16:08:03 +00005443 bad:
sewardj4345f7a2004-09-22 19:49:27 +00005444 ppIRStmt(st);
sewardje768e922009-11-26 17:17:37 +00005445 vpanic("considerExpensives");
sewardj4345f7a2004-09-22 19:49:27 +00005446 }
sewardj4345f7a2004-09-22 19:49:27 +00005447 }
sewardj4345f7a2004-09-22 19:49:27 +00005448}
5449
5450
sewardj695cff92004-10-13 14:50:14 +00005451/* ---------------- The main iropt entry point. ---------------- */
5452
sewardjedf4d692004-08-17 13:52:58 +00005453/* exported from this file */
sewardj695cff92004-10-13 14:50:14 +00005454/* Rules of the game:
5455
5456 - IRExpr/IRStmt trees should be treated as immutable, as they
5457 may get shared. So never change a field of such a tree node;
5458 instead construct and return a new one if needed.
5459*/
5460
sewardj4345f7a2004-09-22 19:49:27 +00005461
sewardjbe917912010-08-22 12:38:53 +00005462IRSB* do_iropt_BB(
5463 IRSB* bb0,
florian1ff47562012-10-21 02:09:51 +00005464 IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int),
sewardjbe917912010-08-22 12:38:53 +00005465 Bool (*preciseMemExnsFn)(Int,Int),
5466 Addr64 guest_addr,
5467 VexArch guest_arch
5468 )
sewardjedf4d692004-08-17 13:52:58 +00005469{
sewardj9d2e7692005-02-07 01:11:31 +00005470 static Int n_total = 0;
5471 static Int n_expensive = 0;
sewardj29632392004-08-22 02:38:11 +00005472
sewardjb183b852006-02-03 16:08:03 +00005473 Bool hasGetIorPutI, hasVorFtemps;
sewardjdd40fdf2006-12-24 02:20:24 +00005474 IRSB *bb, *bb2;
sewardj8c2c10b2004-10-16 20:51:52 +00005475
sewardj4345f7a2004-09-22 19:49:27 +00005476 n_total++;
5477
5478 /* First flatten the block out, since all other
5479 phases assume flat code. */
5480
5481 bb = flatten_BB ( bb0 );
5482
5483 if (iropt_verbose) {
5484 vex_printf("\n========= FLAT\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005485 ppIRSB(bb);
sewardj84be7372004-08-18 13:59:33 +00005486 }
sewardjd7217032004-08-19 10:49:10 +00005487
sewardj08210532004-12-29 17:09:11 +00005488 /* If at level 0, stop now. */
5489 if (vex_control.iropt_level <= 0) return bb;
5490
sewardj695cff92004-10-13 14:50:14 +00005491 /* Now do a preliminary cleanup pass, and figure out if we also
5492 need to do 'expensive' optimisations. Expensive optimisations
5493 are deemed necessary if the block contains any GetIs or PutIs.
5494 If needed, do expensive transformations and then another cheap
5495 cleanup pass. */
sewardj4345f7a2004-09-22 19:49:27 +00005496
sewardj8d2291c2004-10-25 14:50:21 +00005497 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj695cff92004-10-13 14:50:14 +00005498
sewardjbe917912010-08-22 12:38:53 +00005499 if (guest_arch == VexArchARM) {
5500 /* Translating Thumb2 code produces a lot of chaff. We have to
5501 work extra hard to get rid of it. */
5502 bb = cprop_BB(bb);
5503 bb = spec_helpers_BB ( bb, specHelper );
philippe6c46bef2012-08-14 22:29:01 +00005504 if (vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn) {
philippec8e2f982012-08-01 22:04:13 +00005505 redundant_put_removal_BB ( bb, preciseMemExnsFn );
5506 }
sewardjd5436ce2011-05-01 18:36:51 +00005507 do_cse_BB( bb );
sewardjbe917912010-08-22 12:38:53 +00005508 do_deadcode_BB( bb );
5509 }
5510
sewardj08613742004-10-25 13:01:45 +00005511 if (vex_control.iropt_level > 1) {
sewardjb183b852006-02-03 16:08:03 +00005512
5513 /* Peer at what we have, to decide how much more effort to throw
5514 at it. */
5515 considerExpensives( &hasGetIorPutI, &hasVorFtemps, bb );
5516
sewardj9b0cc582006-02-04 15:24:00 +00005517 if (hasVorFtemps && !hasGetIorPutI) {
sewardjb183b852006-02-03 16:08:03 +00005518 /* If any evidence of FP or Vector activity, CSE, as that
5519 tends to mop up all manner of lardy code to do with
sewardj9b0cc582006-02-04 15:24:00 +00005520 rounding modes. Don't bother if hasGetIorPutI since that
5521 case leads into the expensive transformations, which do
5522 CSE anyway. */
5523 (void)do_cse_BB( bb );
sewardjb183b852006-02-03 16:08:03 +00005524 do_deadcode_BB( bb );
5525 }
5526
5527 if (hasGetIorPutI) {
sewardj9b0cc582006-02-04 15:24:00 +00005528 Bool cses;
sewardj39555aa2004-10-24 22:29:19 +00005529 n_expensive++;
sewardj39555aa2004-10-24 22:29:19 +00005530 if (DEBUG_IROPT)
5531 vex_printf("***** EXPENSIVE %d %d\n", n_total, n_expensive);
sewardj695cff92004-10-13 14:50:14 +00005532 bb = expensive_transformations( bb );
sewardj8d2291c2004-10-25 14:50:21 +00005533 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj9b0cc582006-02-04 15:24:00 +00005534 /* Potentially common up GetIs */
5535 cses = do_cse_BB( bb );
5536 if (cses)
5537 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj695cff92004-10-13 14:50:14 +00005538 }
sewardj39555aa2004-10-24 22:29:19 +00005539
5540 /* Now have a go at unrolling simple (single-BB) loops. If
5541 successful, clean up the results as much as possible. */
5542
5543 bb2 = maybe_loop_unroll_BB( bb, guest_addr );
5544 if (bb2) {
sewardj8d2291c2004-10-25 14:50:21 +00005545 bb = cheap_transformations( bb2, specHelper, preciseMemExnsFn );
sewardjb183b852006-02-03 16:08:03 +00005546 if (hasGetIorPutI) {
sewardj39555aa2004-10-24 22:29:19 +00005547 bb = expensive_transformations( bb );
sewardj8d2291c2004-10-25 14:50:21 +00005548 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj39555aa2004-10-24 22:29:19 +00005549 } else {
5550 /* at least do CSE and dead code removal */
sewardjfe1ccfc2004-11-11 02:14:45 +00005551 do_cse_BB( bb );
sewardj49651f42004-10-28 22:11:04 +00005552 do_deadcode_BB( bb );
sewardj39555aa2004-10-24 22:29:19 +00005553 }
5554 if (0) vex_printf("vex iropt: unrolled a loop\n");
5555 }
5556
sewardjd7217032004-08-19 10:49:10 +00005557 }
5558
sewardj4345f7a2004-09-22 19:49:27 +00005559 return bb;
sewardjedf4d692004-08-17 13:52:58 +00005560}
5561
5562
sewardja1a370f2004-08-17 13:31:55 +00005563/*---------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +00005564/*--- end ir_opt.c ---*/
sewardja1a370f2004-08-17 13:31:55 +00005565/*---------------------------------------------------------------*/