blob: 86bd6464bd8f60ff24dec44c597c62041762c811 [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
sewardj89ae8472013-10-18 14:12:58 +000011 Copyright (C) 2004-2013 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
florian99dd03e2013-01-29 03:56:06 +0000365 case Iex_ITE:
sewardjd7cb8532004-08-17 23:59:23 +0000366 t1 = newIRTemp(bb->tyenv, ty);
sewardjdd40fdf2006-12-24 02:20:24 +0000367 addStmtToIRSB(bb, IRStmt_WrTmp(t1,
florian99dd03e2013-01-29 03:56:06 +0000368 IRExpr_ITE(flatten_Expr(bb, ex->Iex.ITE.cond),
369 flatten_Expr(bb, ex->Iex.ITE.iftrue),
370 flatten_Expr(bb, ex->Iex.ITE.iffalse))));
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;
sewardjcfe046e2013-01-17 14:23:53 +0000403 IRExpr *e1, *e2, *e3, *e4, *e5;
404 IRDirty *d, *d2;
405 IRCAS *cas, *cas2;
406 IRPutI *puti, *puti2;
407 IRLoadG *lg;
408 IRStoreG *sg;
sewardjd7cb8532004-08-17 23:59:23 +0000409 switch (st->tag) {
410 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +0000411 if (isIRAtom(st->Ist.Put.data)) {
sewardj49651f42004-10-28 22:11:04 +0000412 /* optimisation to reduce the amount of heap wasted
413 by the flattener */
sewardjdd40fdf2006-12-24 02:20:24 +0000414 addStmtToIRSB(bb, st);
sewardj49651f42004-10-28 22:11:04 +0000415 } else {
416 /* general case, always correct */
417 e1 = flatten_Expr(bb, st->Ist.Put.data);
sewardjdd40fdf2006-12-24 02:20:24 +0000418 addStmtToIRSB(bb, IRStmt_Put(st->Ist.Put.offset, e1));
sewardj49651f42004-10-28 22:11:04 +0000419 }
sewardjd7cb8532004-08-17 23:59:23 +0000420 break;
sewardjd7cb8532004-08-17 23:59:23 +0000421 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +0000422 puti = st->Ist.PutI.details;
423 e1 = flatten_Expr(bb, puti->ix);
424 e2 = flatten_Expr(bb, puti->data);
425 puti2 = mkIRPutI(puti->descr, e1, puti->bias, e2);
426 addStmtToIRSB(bb, IRStmt_PutI(puti2));
sewardjd7217032004-08-19 10:49:10 +0000427 break;
sewardjdd40fdf2006-12-24 02:20:24 +0000428 case Ist_WrTmp:
429 if (isFlat(st->Ist.WrTmp.data)) {
sewardje80679a2004-09-21 23:00:11 +0000430 /* optimisation, to reduce the number of tmp-tmp
431 copies generated */
sewardjdd40fdf2006-12-24 02:20:24 +0000432 addStmtToIRSB(bb, st);
sewardje80679a2004-09-21 23:00:11 +0000433 } else {
434 /* general case, always correct */
sewardjdd40fdf2006-12-24 02:20:24 +0000435 e1 = flatten_Expr(bb, st->Ist.WrTmp.data);
436 addStmtToIRSB(bb, IRStmt_WrTmp(st->Ist.WrTmp.tmp, e1));
sewardje80679a2004-09-21 23:00:11 +0000437 }
sewardjd7cb8532004-08-17 23:59:23 +0000438 break;
sewardjaf1ceca2005-06-30 23:31:27 +0000439 case Ist_Store:
440 e1 = flatten_Expr(bb, st->Ist.Store.addr);
441 e2 = flatten_Expr(bb, st->Ist.Store.data);
sewardje768e922009-11-26 17:17:37 +0000442 addStmtToIRSB(bb, IRStmt_Store(st->Ist.Store.end, e1,e2));
sewardje9d8a262009-07-01 08:06:34 +0000443 break;
sewardjcfe046e2013-01-17 14:23:53 +0000444 case Ist_StoreG:
445 sg = st->Ist.StoreG.details;
446 e1 = flatten_Expr(bb, sg->addr);
447 e2 = flatten_Expr(bb, sg->data);
448 e3 = flatten_Expr(bb, sg->guard);
449 addStmtToIRSB(bb, IRStmt_StoreG(sg->end, e1, e2, e3));
450 break;
451 case Ist_LoadG:
452 lg = st->Ist.LoadG.details;
453 e1 = flatten_Expr(bb, lg->addr);
454 e2 = flatten_Expr(bb, lg->alt);
455 e3 = flatten_Expr(bb, lg->guard);
456 addStmtToIRSB(bb, IRStmt_LoadG(lg->end, lg->cvt, lg->dst,
457 e1, e2, e3));
458 break;
sewardje9d8a262009-07-01 08:06:34 +0000459 case Ist_CAS:
460 cas = st->Ist.CAS.details;
461 e1 = flatten_Expr(bb, cas->addr);
462 e2 = cas->expdHi ? flatten_Expr(bb, cas->expdHi) : NULL;
463 e3 = flatten_Expr(bb, cas->expdLo);
464 e4 = cas->dataHi ? flatten_Expr(bb, cas->dataHi) : NULL;
465 e5 = flatten_Expr(bb, cas->dataLo);
466 cas2 = mkIRCAS( cas->oldHi, cas->oldLo, cas->end,
467 e1, e2, e3, e4, e5 );
468 addStmtToIRSB(bb, IRStmt_CAS(cas2));
sewardjd7cb8532004-08-17 23:59:23 +0000469 break;
sewardje768e922009-11-26 17:17:37 +0000470 case Ist_LLSC:
471 e1 = flatten_Expr(bb, st->Ist.LLSC.addr);
472 e2 = st->Ist.LLSC.storedata
473 ? flatten_Expr(bb, st->Ist.LLSC.storedata)
474 : NULL;
475 addStmtToIRSB(bb, IRStmt_LLSC(st->Ist.LLSC.end,
476 st->Ist.LLSC.result, e1, e2));
477 break;
sewardj17442fe2004-09-20 14:54:28 +0000478 case Ist_Dirty:
479 d = st->Ist.Dirty.details;
480 d2 = emptyIRDirty();
481 *d2 = *d;
sewardjdd40fdf2006-12-24 02:20:24 +0000482 d2->args = shallowCopyIRExprVec(d2->args);
sewardj17442fe2004-09-20 14:54:28 +0000483 if (d2->mFx != Ifx_None) {
484 d2->mAddr = flatten_Expr(bb, d2->mAddr);
485 } else {
486 vassert(d2->mAddr == NULL);
487 }
sewardjb8385d82004-11-02 01:34:15 +0000488 d2->guard = flatten_Expr(bb, d2->guard);
sewardj74142b82013-08-08 10:28:59 +0000489 for (i = 0; d2->args[i]; i++) {
490 IRExpr* arg = d2->args[i];
florian90419562013-08-15 20:54:52 +0000491 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +0000492 d2->args[i] = flatten_Expr(bb, arg);
493 }
sewardjdd40fdf2006-12-24 02:20:24 +0000494 addStmtToIRSB(bb, IRStmt_Dirty(d2));
sewardj17442fe2004-09-20 14:54:28 +0000495 break;
sewardjd2445f62005-03-21 00:15:53 +0000496 case Ist_NoOp:
sewardjc4356f02007-11-09 21:15:04 +0000497 case Ist_MBE:
sewardjd2445f62005-03-21 00:15:53 +0000498 case Ist_IMark:
sewardjdd40fdf2006-12-24 02:20:24 +0000499 addStmtToIRSB(bb, st);
sewardj3e838932005-01-07 12:09:15 +0000500 break;
sewardj5a9ffab2005-05-12 17:55:01 +0000501 case Ist_AbiHint:
502 e1 = flatten_Expr(bb, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +0000503 e2 = flatten_Expr(bb, st->Ist.AbiHint.nia);
504 addStmtToIRSB(bb, IRStmt_AbiHint(e1, st->Ist.AbiHint.len, e2));
sewardj5a9ffab2005-05-12 17:55:01 +0000505 break;
sewardjd7cb8532004-08-17 23:59:23 +0000506 case Ist_Exit:
sewardj0276d4b2004-11-15 15:30:21 +0000507 e1 = flatten_Expr(bb, st->Ist.Exit.guard);
sewardjdd40fdf2006-12-24 02:20:24 +0000508 addStmtToIRSB(bb, IRStmt_Exit(e1, st->Ist.Exit.jk,
sewardjc6f970f2012-04-02 21:54:49 +0000509 st->Ist.Exit.dst,
510 st->Ist.Exit.offsIP));
sewardjd7cb8532004-08-17 23:59:23 +0000511 break;
512 default:
513 vex_printf("\n");
514 ppIRStmt(st);
515 vex_printf("\n");
516 vpanic("flatten_Stmt");
517 }
518}
519
sewardj08210532004-12-29 17:09:11 +0000520
sewardjdd40fdf2006-12-24 02:20:24 +0000521static IRSB* flatten_BB ( IRSB* in )
sewardjd7cb8532004-08-17 23:59:23 +0000522{
523 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +0000524 IRSB* out;
525 out = emptyIRSB();
526 out->tyenv = deepCopyIRTypeEnv( in->tyenv );
sewardjd7cb8532004-08-17 23:59:23 +0000527 for (i = 0; i < in->stmts_used; i++)
sewardj4345f7a2004-09-22 19:49:27 +0000528 if (in->stmts[i])
529 flatten_Stmt( out, in->stmts[i] );
sewardjd7cb8532004-08-17 23:59:23 +0000530 out->next = flatten_Expr( out, in->next );
531 out->jumpkind = in->jumpkind;
sewardjc6f970f2012-04-02 21:54:49 +0000532 out->offsIP = in->offsIP;
sewardjd7cb8532004-08-17 23:59:23 +0000533 return out;
534}
535
sewardjedf4d692004-08-17 13:52:58 +0000536
sewardj08210532004-12-29 17:09:11 +0000537/*---------------------------------------------------------------*/
538/*--- In-place removal of redundant GETs ---*/
539/*---------------------------------------------------------------*/
540
541/* Scan forwards, building up an environment binding (min offset, max
542 offset) pairs to values, which will either be temps or constants.
543
544 On seeing 't = Get(minoff,maxoff)', look up (minoff,maxoff) in the
545 env and if it matches, replace the Get with the stored value. If
546 there is no match, add a (minoff,maxoff) :-> t binding.
547
548 On seeing 'Put (minoff,maxoff) = t or c', first remove in the env
549 any binding which fully or partially overlaps with (minoff,maxoff).
550 Then add a new (minoff,maxoff) :-> t or c binding. */
551
552/* Extract the min/max offsets from a guest state array descriptor. */
553
554inline
sewardjdd40fdf2006-12-24 02:20:24 +0000555static void getArrayBounds ( IRRegArray* descr,
556 UInt* minoff, UInt* maxoff )
sewardj08210532004-12-29 17:09:11 +0000557{
558 *minoff = descr->base;
559 *maxoff = *minoff + descr->nElems*sizeofIRType(descr->elemTy) - 1;
560 vassert((*minoff & ~0xFFFF) == 0);
561 vassert((*maxoff & ~0xFFFF) == 0);
562 vassert(*minoff <= *maxoff);
563}
564
565/* Create keys, of the form ((minoffset << 16) | maxoffset). */
566
567static UInt mk_key_GetPut ( Int offset, IRType ty )
568{
569 /* offset should fit in 16 bits. */
570 UInt minoff = offset;
571 UInt maxoff = minoff + sizeofIRType(ty) - 1;
572 vassert((minoff & ~0xFFFF) == 0);
573 vassert((maxoff & ~0xFFFF) == 0);
574 return (minoff << 16) | maxoff;
575}
576
sewardjdd40fdf2006-12-24 02:20:24 +0000577static UInt mk_key_GetIPutI ( IRRegArray* descr )
sewardj08210532004-12-29 17:09:11 +0000578{
579 UInt minoff, maxoff;
580 getArrayBounds( descr, &minoff, &maxoff );
581 vassert((minoff & ~0xFFFF) == 0);
582 vassert((maxoff & ~0xFFFF) == 0);
583 return (minoff << 16) | maxoff;
584}
585
586/* Supposing h has keys of the form generated by mk_key_GetPut and
587 mk_key_GetIPutI, invalidate any key which overlaps (k_lo
588 .. k_hi).
589*/
590static void invalidateOverlaps ( HashHW* h, UInt k_lo, UInt k_hi )
591{
592 Int j;
593 UInt e_lo, e_hi;
594 vassert(k_lo <= k_hi);
595 /* invalidate any env entries which in any way overlap (k_lo
596 .. k_hi) */
597 /* vex_printf("invalidate %d .. %d\n", k_lo, k_hi ); */
598
599 for (j = 0; j < h->used; j++) {
600 if (!h->inuse[j])
601 continue;
602 e_lo = (((UInt)h->key[j]) >> 16) & 0xFFFF;
603 e_hi = ((UInt)h->key[j]) & 0xFFFF;
604 vassert(e_lo <= e_hi);
605 if (e_hi < k_lo || k_hi < e_lo)
606 continue; /* no overlap possible */
607 else
608 /* overlap; invalidate */
609 h->inuse[j] = False;
610 }
611}
612
613
sewardjdd40fdf2006-12-24 02:20:24 +0000614static void redundant_get_removal_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +0000615{
616 HashHW* env = newHHW();
617 UInt key = 0; /* keep gcc -O happy */
618 Int i, j;
619 HWord val;
620
621 for (i = 0; i < bb->stmts_used; i++) {
622 IRStmt* st = bb->stmts[i];
623
sewardj8bee6d12005-03-22 02:24:05 +0000624 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +0000625 continue;
626
627 /* Deal with Gets */
sewardjdd40fdf2006-12-24 02:20:24 +0000628 if (st->tag == Ist_WrTmp
629 && st->Ist.WrTmp.data->tag == Iex_Get) {
sewardj08210532004-12-29 17:09:11 +0000630 /* st is 't = Get(...)'. Look up in the environment and see
631 if the Get can be replaced. */
sewardjdd40fdf2006-12-24 02:20:24 +0000632 IRExpr* get = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +0000633 key = (HWord)mk_key_GetPut( get->Iex.Get.offset,
634 get->Iex.Get.ty );
635 if (lookupHHW(env, &val, (HWord)key)) {
636 /* found it */
637 /* Note, we could do better here. If the types are
638 different we don't do the substitution, since doing so
639 could lead to invalidly-typed IR. An improvement would
640 be to stick in a reinterpret-style cast, although that
641 would make maintaining flatness more difficult. */
642 IRExpr* valE = (IRExpr*)val;
sewardj9d2e7692005-02-07 01:11:31 +0000643 Bool typesOK = toBool( typeOfIRExpr(bb->tyenv,valE)
sewardjdd40fdf2006-12-24 02:20:24 +0000644 == st->Ist.WrTmp.data->Iex.Get.ty );
sewardj08210532004-12-29 17:09:11 +0000645 if (typesOK && DEBUG_IROPT) {
646 vex_printf("rGET: "); ppIRExpr(get);
647 vex_printf(" -> "); ppIRExpr(valE);
648 vex_printf("\n");
649 }
650 if (typesOK)
sewardjdd40fdf2006-12-24 02:20:24 +0000651 bb->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, valE);
sewardj08210532004-12-29 17:09:11 +0000652 } else {
653 /* Not found, but at least we know that t and the Get(...)
654 are now associated. So add a binding to reflect that
655 fact. */
656 addToHHW( env, (HWord)key,
sewardjdd40fdf2006-12-24 02:20:24 +0000657 (HWord)(void*)(IRExpr_RdTmp(st->Ist.WrTmp.tmp)) );
sewardj08210532004-12-29 17:09:11 +0000658 }
659 }
660
661 /* Deal with Puts: invalidate any env entries overlapped by this
662 Put */
663 if (st->tag == Ist_Put || st->tag == Ist_PutI) {
664 UInt k_lo, k_hi;
665 if (st->tag == Ist_Put) {
666 key = mk_key_GetPut( st->Ist.Put.offset,
667 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
668 } else {
669 vassert(st->tag == Ist_PutI);
floriand6f38b32012-05-31 15:46:18 +0000670 key = mk_key_GetIPutI( st->Ist.PutI.details->descr );
sewardj08210532004-12-29 17:09:11 +0000671 }
672
673 k_lo = (key >> 16) & 0xFFFF;
674 k_hi = key & 0xFFFF;
675 invalidateOverlaps(env, k_lo, k_hi);
676 }
677 else
678 if (st->tag == Ist_Dirty) {
679 /* Deal with dirty helpers which write or modify guest state.
680 Invalidate the entire env. We could do a lot better
681 here. */
682 IRDirty* d = st->Ist.Dirty.details;
683 Bool writes = False;
684 for (j = 0; j < d->nFxState; j++) {
685 if (d->fxState[j].fx == Ifx_Modify
686 || d->fxState[j].fx == Ifx_Write)
687 writes = True;
688 }
689 if (writes) {
690 /* dump the entire env (not clever, but correct ...) */
691 for (j = 0; j < env->used; j++)
692 env->inuse[j] = False;
693 if (0) vex_printf("rGET: trash env due to dirty helper\n");
694 }
695 }
696
697 /* add this one to the env, if appropriate */
698 if (st->tag == Ist_Put) {
sewardj496a58d2005-03-20 18:44:44 +0000699 vassert(isIRAtom(st->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +0000700 addToHHW( env, (HWord)key, (HWord)(st->Ist.Put.data));
701 }
702
703 } /* for (i = 0; i < bb->stmts_used; i++) */
704
705}
706
707
708/*---------------------------------------------------------------*/
709/*--- In-place removal of redundant PUTs ---*/
710/*---------------------------------------------------------------*/
711
712/* Find any Get uses in st and invalidate any partially or fully
713 overlapping ranges listed in env. Due to the flattening phase, the
sewardjdd40fdf2006-12-24 02:20:24 +0000714 only stmt kind we expect to find a Get on is IRStmt_WrTmp. */
sewardj08210532004-12-29 17:09:11 +0000715
716static void handle_gets_Stmt (
717 HashHW* env,
718 IRStmt* st,
719 Bool (*preciseMemExnsFn)(Int,Int)
720 )
721{
722 Int j;
723 UInt key = 0; /* keep gcc -O happy */
724 Bool isGet;
725 Bool memRW = False;
726 IRExpr* e;
727
728 switch (st->tag) {
729
730 /* This is the only interesting case. Deal with Gets in the RHS
731 expression. */
sewardjdd40fdf2006-12-24 02:20:24 +0000732 case Ist_WrTmp:
733 e = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +0000734 switch (e->tag) {
735 case Iex_Get:
736 isGet = True;
737 key = mk_key_GetPut ( e->Iex.Get.offset, e->Iex.Get.ty );
738 break;
739 case Iex_GetI:
740 isGet = True;
741 key = mk_key_GetIPutI ( e->Iex.GetI.descr );
742 break;
sewardjaf1ceca2005-06-30 23:31:27 +0000743 case Iex_Load:
sewardj08210532004-12-29 17:09:11 +0000744 isGet = False;
745 memRW = True;
746 break;
747 default:
748 isGet = False;
749 }
750 if (isGet) {
751 UInt k_lo, k_hi;
752 k_lo = (key >> 16) & 0xFFFF;
753 k_hi = key & 0xFFFF;
754 invalidateOverlaps(env, k_lo, k_hi);
755 }
756 break;
757
758 /* Be very conservative for dirty helper calls; dump the entire
759 environment. The helper might read guest state, in which
760 case it needs to be flushed first. Also, the helper might
761 access guest memory, in which case all parts of the guest
762 state requiring precise exceptions needs to be flushed. The
763 crude solution is just to flush everything; we could easily
764 enough do a lot better if needed. */
sewardj3e838932005-01-07 12:09:15 +0000765 /* Probably also overly-conservative, but also dump everything
sewardjc4356f02007-11-09 21:15:04 +0000766 if we hit a memory bus event (fence, lock, unlock). Ditto
sewardje768e922009-11-26 17:17:37 +0000767 AbiHints, CASs, LLs and SCs. */
sewardj5a9ffab2005-05-12 17:55:01 +0000768 case Ist_AbiHint:
769 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +0000770 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +0000771 /* fall through */
sewardjc4356f02007-11-09 21:15:04 +0000772 case Ist_MBE:
sewardj08210532004-12-29 17:09:11 +0000773 case Ist_Dirty:
sewardje9d8a262009-07-01 08:06:34 +0000774 case Ist_CAS:
sewardje768e922009-11-26 17:17:37 +0000775 case Ist_LLSC:
sewardj08210532004-12-29 17:09:11 +0000776 for (j = 0; j < env->used; j++)
777 env->inuse[j] = False;
778 break;
779
780 /* all other cases are boring. */
sewardjaf1ceca2005-06-30 23:31:27 +0000781 case Ist_Store:
782 vassert(isIRAtom(st->Ist.Store.addr));
783 vassert(isIRAtom(st->Ist.Store.data));
sewardj08210532004-12-29 17:09:11 +0000784 memRW = True;
785 break;
sewardjcfe046e2013-01-17 14:23:53 +0000786 case Ist_StoreG: {
787 IRStoreG* sg = st->Ist.StoreG.details;
788 vassert(isIRAtom(sg->addr));
789 vassert(isIRAtom(sg->data));
790 vassert(isIRAtom(sg->guard));
791 memRW = True;
792 break;
793 }
794 case Ist_LoadG: {
795 IRLoadG* lg = st->Ist.LoadG.details;
796 vassert(isIRAtom(lg->addr));
797 vassert(isIRAtom(lg->alt));
798 vassert(isIRAtom(lg->guard));
799 memRW = True;
800 break;
801 }
sewardj08210532004-12-29 17:09:11 +0000802 case Ist_Exit:
sewardj496a58d2005-03-20 18:44:44 +0000803 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +0000804 break;
805
floriane74ce2e2014-09-16 22:33:52 +0000806 case Ist_Put:
807 vassert(isIRAtom(st->Ist.Put.data));
808 break;
809
sewardj08210532004-12-29 17:09:11 +0000810 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +0000811 vassert(isIRAtom(st->Ist.PutI.details->ix));
812 vassert(isIRAtom(st->Ist.PutI.details->data));
sewardj08210532004-12-29 17:09:11 +0000813 break;
814
sewardjd2445f62005-03-21 00:15:53 +0000815 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +0000816 case Ist_IMark:
817 break;
818
sewardj08210532004-12-29 17:09:11 +0000819 default:
820 vex_printf("\n");
821 ppIRStmt(st);
822 vex_printf("\n");
823 vpanic("handle_gets_Stmt");
824 }
825
826 if (memRW) {
philippe6c46bef2012-08-14 22:29:01 +0000827 /* This statement accesses memory. So we might need to dump all parts
sewardj08210532004-12-29 17:09:11 +0000828 of the environment corresponding to guest state that may not
829 be reordered with respect to memory references. That means
830 at least the stack pointer. */
philippec8e2f982012-08-01 22:04:13 +0000831 switch (vex_control.iropt_register_updates) {
832 case VexRegUpdAllregsAtMemAccess:
833 /* Precise exceptions required at mem access.
834 Flush all guest state. */
835 for (j = 0; j < env->used; j++)
sewardj08210532004-12-29 17:09:11 +0000836 env->inuse[j] = False;
philippec8e2f982012-08-01 22:04:13 +0000837 break;
philippe6c46bef2012-08-14 22:29:01 +0000838 case VexRegUpdSpAtMemAccess:
839 /* We need to dump the stack pointer
840 (needed for stack extension in m_signals.c).
841 preciseMemExnsFn will use vex_control.iropt_register_updates
842 to verify only the sp is to be checked. */
843 /* fallthrough */
philippec8e2f982012-08-01 22:04:13 +0000844 case VexRegUpdUnwindregsAtMemAccess:
845 for (j = 0; j < env->used; j++) {
846 if (!env->inuse[j])
847 continue;
848 /* Just flush the minimal amount required, as computed by
849 preciseMemExnsFn. */
850 HWord k_lo = (env->key[j] >> 16) & 0xFFFF;
851 HWord k_hi = env->key[j] & 0xFFFF;
852 if (preciseMemExnsFn( k_lo, k_hi ))
853 env->inuse[j] = False;
854 }
855 break;
floriane74ce2e2014-09-16 22:33:52 +0000856 case VexRegUpdAllregsAtEachInsn:
philippec8e2f982012-08-01 22:04:13 +0000857 // VexRegUpdAllregsAtEachInsn cannot happen here.
floriane74ce2e2014-09-16 22:33:52 +0000858 // fall through
859 default:
philippec8e2f982012-08-01 22:04:13 +0000860 vassert(0);
sewardj08210532004-12-29 17:09:11 +0000861 }
862 } /* if (memRW) */
863
864}
865
866
867/* Scan backwards, building up a set of (min offset, max
868 offset) pairs, indicating those parts of the guest state
869 for which the next event is a write.
870
871 On seeing a conditional exit, empty the set.
872
873 On seeing 'Put (minoff,maxoff) = t or c', if (minoff,maxoff) is
874 completely within the set, remove the Put. Otherwise, add
875 (minoff,maxoff) to the set.
876
877 On seeing 'Get (minoff,maxoff)', remove any part of the set
sewardj98430292004-12-29 17:34:50 +0000878 overlapping (minoff,maxoff). The same has to happen for any events
879 which implicitly read parts of the guest state: dirty helper calls
880 and loads/stores.
sewardj08210532004-12-29 17:09:11 +0000881*/
882
883static void redundant_put_removal_BB (
sewardjdd40fdf2006-12-24 02:20:24 +0000884 IRSB* bb,
sewardj08210532004-12-29 17:09:11 +0000885 Bool (*preciseMemExnsFn)(Int,Int)
886 )
887{
888 Int i, j;
889 Bool isPut;
890 IRStmt* st;
891 UInt key = 0; /* keep gcc -O happy */
892
philippe6c46bef2012-08-14 22:29:01 +0000893 vassert(vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn);
philippec8e2f982012-08-01 22:04:13 +0000894
sewardj08210532004-12-29 17:09:11 +0000895 HashHW* env = newHHW();
sewardjc6f970f2012-04-02 21:54:49 +0000896
897 /* Initialise the running env with the fact that the final exit
898 writes the IP (or, whatever it claims to write. We don't
899 care.) */
900 key = mk_key_GetPut(bb->offsIP, typeOfIRExpr(bb->tyenv, bb->next));
901 addToHHW(env, (HWord)key, 0);
902
903 /* And now scan backwards through the statements. */
sewardj08210532004-12-29 17:09:11 +0000904 for (i = bb->stmts_used-1; i >= 0; i--) {
905 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +0000906
907 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +0000908 continue;
909
910 /* Deal with conditional exits. */
911 if (st->tag == Ist_Exit) {
sewardjc6f970f2012-04-02 21:54:49 +0000912 //Bool re_add;
913 /* Need to throw out from the env, any part of it which
914 doesn't overlap with the guest state written by this exit.
915 Since the exit only writes one section, it's simplest to
916 do this: (1) check whether env contains a write that
917 completely overlaps the write done by this exit; (2) empty
918 out env; and (3) if (1) was true, add the write done by
919 this exit.
920
921 To make (1) a bit simpler, merely search for a write that
922 exactly matches the one done by this exit. That's safe
923 because it will fail as often or more often than a full
924 overlap check, and failure to find an overlapping write in
925 env is the safe case (we just nuke env if that
926 happens). */
927 //vassert(isIRAtom(st->Ist.Exit.guard));
928 /* (1) */
929 //key = mk_key_GetPut(st->Ist.Exit.offsIP,
930 // typeOfIRConst(st->Ist.Exit.dst));
931 //re_add = lookupHHW(env, NULL, key);
932 /* (2) */
sewardj08210532004-12-29 17:09:11 +0000933 for (j = 0; j < env->used; j++)
934 env->inuse[j] = False;
sewardjc6f970f2012-04-02 21:54:49 +0000935 /* (3) */
936 //if (0 && re_add)
937 // addToHHW(env, (HWord)key, 0);
sewardj08210532004-12-29 17:09:11 +0000938 continue;
939 }
940
941 /* Deal with Puts */
942 switch (st->tag) {
943 case Ist_Put:
944 isPut = True;
945 key = mk_key_GetPut( st->Ist.Put.offset,
946 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
sewardj496a58d2005-03-20 18:44:44 +0000947 vassert(isIRAtom(st->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +0000948 break;
949 case Ist_PutI:
950 isPut = True;
floriand6f38b32012-05-31 15:46:18 +0000951 key = mk_key_GetIPutI( st->Ist.PutI.details->descr );
952 vassert(isIRAtom(st->Ist.PutI.details->ix));
953 vassert(isIRAtom(st->Ist.PutI.details->data));
sewardj08210532004-12-29 17:09:11 +0000954 break;
955 default:
956 isPut = False;
957 }
958 if (isPut && st->tag != Ist_PutI) {
959 /* See if any single entry in env overlaps this Put. This is
960 simplistic in that the transformation is valid if, say, two
961 or more entries in the env overlap this Put, but the use of
962 lookupHHW will only find a single entry which exactly
963 overlaps this Put. This is suboptimal but safe. */
964 if (lookupHHW(env, NULL, (HWord)key)) {
965 /* This Put is redundant because a later one will overwrite
966 it. So NULL (nop) it out. */
967 if (DEBUG_IROPT) {
968 vex_printf("rPUT: "); ppIRStmt(st);
969 vex_printf("\n");
970 }
sewardjd2445f62005-03-21 00:15:53 +0000971 bb->stmts[i] = IRStmt_NoOp();
sewardj08210532004-12-29 17:09:11 +0000972 } else {
973 /* We can't demonstrate that this Put is redundant, so add it
974 to the running collection. */
975 addToHHW(env, (HWord)key, 0);
976 }
977 continue;
978 }
979
980 /* Deal with Gets. These remove bits of the environment since
981 appearance of a Get means that the next event for that slice
sewardj98430292004-12-29 17:34:50 +0000982 of the guest state is no longer a write, but a read. Also
983 deals with implicit reads of guest state needed to maintain
984 precise exceptions. */
sewardj08210532004-12-29 17:09:11 +0000985 handle_gets_Stmt( env, st, preciseMemExnsFn );
986 }
987}
988
sewardj84be7372004-08-18 13:59:33 +0000989
990/*---------------------------------------------------------------*/
991/*--- Constant propagation and folding ---*/
992/*---------------------------------------------------------------*/
993
floriancdb5fee2012-02-13 00:06:29 +0000994#if STATS_IROPT
995/* How often sameIRExprs was invoked */
996static UInt invocation_count;
997/* How often sameIRExprs recursed through IRTemp assignments */
998static UInt recursion_count;
999/* How often sameIRExprs found identical IRExprs */
1000static UInt success_count;
1001/* How often recursing through assignments to IRTemps helped
1002 establishing equality. */
1003static UInt recursion_success_count;
1004/* Whether or not recursing through an IRTemp assignment helped
1005 establishing IRExpr equality for a given sameIRExprs invocation. */
1006static Bool recursion_helped;
1007/* Whether or not a given sameIRExprs invocation recursed through an
1008 IRTemp assignment */
1009static Bool recursed;
1010/* Maximum number of nodes ever visited when comparing two IRExprs. */
1011static UInt max_nodes_visited;
1012#endif /* STATS_IROPT */
1013
1014/* Count the number of nodes visited for a given sameIRExprs invocation. */
1015static UInt num_nodes_visited;
1016
1017/* Do not visit more than NODE_LIMIT nodes when comparing two IRExprs.
1018 This is to guard against performance degradation by visiting large
1019 trees without success. */
1020#define NODE_LIMIT 30
1021
1022
sewardj62617ef2004-10-13 23:29:22 +00001023/* The env in this section is a map from IRTemp to IRExpr*,
1024 that is, an array indexed by IRTemp. */
sewardjf6501992004-08-27 11:58:24 +00001025
floriancdb5fee2012-02-13 00:06:29 +00001026/* Do both expressions compute the same value? The answer is generally
1027 conservative, i.e. it will report that the expressions do not compute
1028 the same value when in fact they do. The reason is that we do not
1029 keep track of changes in the guest state and memory. Thusly, two
1030 Get's, GetI's or Load's, even when accessing the same location, will be
1031 assumed to compute different values. After all the accesses may happen
1032 at different times and the guest state / memory can have changed in
sewardja7e96382012-06-29 16:26:17 +00001033 the meantime.
1034
1035 XXX IMPORTANT XXX the two expressions must have the same IR type.
1036 DO NOT CALL HERE WITH DIFFERENTLY-TYPED EXPRESSIONS. */
sewardjc6f970f2012-04-02 21:54:49 +00001037
1038/* JRS 20-Mar-2012: split sameIRExprs_aux into a fast inlineable
1039 wrapper that deals with the common tags-don't-match case, and a
1040 slower out of line general case. Saves a few insns. */
1041
1042__attribute__((noinline))
1043static Bool sameIRExprs_aux2 ( IRExpr** env, IRExpr* e1, IRExpr* e2 );
1044
1045inline
floriancdb5fee2012-02-13 00:06:29 +00001046static Bool sameIRExprs_aux ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
sewardjf6729012004-08-25 12:45:13 +00001047{
floriancdb5fee2012-02-13 00:06:29 +00001048 if (e1->tag != e2->tag) return False;
sewardjc6f970f2012-04-02 21:54:49 +00001049 return sameIRExprs_aux2(env, e1, e2);
1050}
sewardjf6729012004-08-25 12:45:13 +00001051
sewardjc6f970f2012-04-02 21:54:49 +00001052__attribute__((noinline))
1053static Bool sameIRExprs_aux2 ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
1054{
floriancdb5fee2012-02-13 00:06:29 +00001055 if (num_nodes_visited++ > NODE_LIMIT) return False;
sewardj6c299f32009-12-31 18:00:12 +00001056
sewardj6c299f32009-12-31 18:00:12 +00001057 switch (e1->tag) {
1058 case Iex_RdTmp:
floriancdb5fee2012-02-13 00:06:29 +00001059 if (e1->Iex.RdTmp.tmp == e2->Iex.RdTmp.tmp) return True;
1060
1061 if (env[e1->Iex.RdTmp.tmp] && env[e2->Iex.RdTmp.tmp]) {
1062 Bool same = sameIRExprs_aux(env, env[e1->Iex.RdTmp.tmp],
1063 env[e2->Iex.RdTmp.tmp]);
1064#if STATS_IROPT
1065 recursed = True;
1066 if (same) recursion_helped = True;
1067#endif
1068 return same;
1069 }
sewardj6c299f32009-12-31 18:00:12 +00001070 return False;
floriancdb5fee2012-02-13 00:06:29 +00001071
1072 case Iex_Get:
1073 case Iex_GetI:
1074 case Iex_Load:
1075 /* Guest state / memory could have changed in the meantime. */
1076 return False;
1077
1078 case Iex_Binop:
1079 return toBool( e1->Iex.Binop.op == e2->Iex.Binop.op
sewardj6399f812012-06-29 15:36:44 +00001080 && sameIRExprs_aux( env, e1->Iex.Binop.arg1,
1081 e2->Iex.Binop.arg1 )
1082 && sameIRExprs_aux( env, e1->Iex.Binop.arg2,
1083 e2->Iex.Binop.arg2 ));
floriancdb5fee2012-02-13 00:06:29 +00001084
1085 case Iex_Unop:
1086 return toBool( e1->Iex.Unop.op == e2->Iex.Unop.op
sewardj6399f812012-06-29 15:36:44 +00001087 && sameIRExprs_aux( env, e1->Iex.Unop.arg,
1088 e2->Iex.Unop.arg ));
floriancdb5fee2012-02-13 00:06:29 +00001089
1090 case Iex_Const: {
1091 IRConst *c1 = e1->Iex.Const.con;
1092 IRConst *c2 = e2->Iex.Const.con;
1093 vassert(c1->tag == c2->tag);
1094 switch (c1->tag) {
1095 case Ico_U1: return toBool( c1->Ico.U1 == c2->Ico.U1 );
1096 case Ico_U8: return toBool( c1->Ico.U8 == c2->Ico.U8 );
1097 case Ico_U16: return toBool( c1->Ico.U16 == c2->Ico.U16 );
1098 case Ico_U32: return toBool( c1->Ico.U32 == c2->Ico.U32 );
1099 case Ico_U64: return toBool( c1->Ico.U64 == c2->Ico.U64 );
1100 default: break;
1101 }
1102 return False;
1103 }
1104
florian420bfa92012-06-02 20:29:22 +00001105 case Iex_Triop: {
1106 IRTriop *tri1 = e1->Iex.Triop.details;
1107 IRTriop *tri2 = e2->Iex.Triop.details;
1108 return toBool( tri1->op == tri2->op
1109 && sameIRExprs_aux( env, tri1->arg1, tri2->arg1 )
1110 && sameIRExprs_aux( env, tri1->arg2, tri2->arg2 )
1111 && sameIRExprs_aux( env, tri1->arg3, tri2->arg3 ));
1112 }
floriancdb5fee2012-02-13 00:06:29 +00001113
florian99dd03e2013-01-29 03:56:06 +00001114 case Iex_ITE:
1115 return toBool( sameIRExprs_aux( env, e1->Iex.ITE.cond,
1116 e2->Iex.ITE.cond )
1117 && sameIRExprs_aux( env, e1->Iex.ITE.iftrue,
1118 e2->Iex.ITE.iftrue )
1119 && sameIRExprs_aux( env, e1->Iex.ITE.iffalse,
1120 e2->Iex.ITE.iffalse ));
floriancdb5fee2012-02-13 00:06:29 +00001121
1122 default:
1123 /* Not very likely to be "same". */
1124 break;
sewardj6c299f32009-12-31 18:00:12 +00001125 }
floriancdb5fee2012-02-13 00:06:29 +00001126
1127 return False;
sewardj6c299f32009-12-31 18:00:12 +00001128}
1129
sewardjc6f970f2012-04-02 21:54:49 +00001130inline
floriancdb5fee2012-02-13 00:06:29 +00001131static Bool sameIRExprs ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
1132{
1133 Bool same;
1134
1135 num_nodes_visited = 0;
1136 same = sameIRExprs_aux(env, e1, e2);
1137
1138#if STATS_IROPT
1139 ++invocation_count;
1140 if (recursed) ++recursion_count;
1141 success_count += same;
1142 if (same && recursion_helped)
1143 ++recursion_success_count;
1144 if (num_nodes_visited > max_nodes_visited)
1145 max_nodes_visited = num_nodes_visited;
1146 recursed = False; /* reset */
1147 recursion_helped = False; /* reset */
1148#endif /* STATS_IROPT */
1149
1150 return same;
1151}
1152
1153
sewardja7e96382012-06-29 16:26:17 +00001154/* Debugging-only hack (not used in production runs): make a guess
1155 whether sameIRExprs might assert due to the two args being of
1156 different types. If in doubt return False. Is only used when
1157 --vex-iropt-level > 0, that is, vex_control.iropt_verbosity > 0.
1158 Bad because it duplicates functionality from typeOfIRExpr. See
1159 comment on the single use point below for rationale. */
1160static
1161Bool debug_only_hack_sameIRExprs_might_assert ( IRExpr* e1, IRExpr* e2 )
1162{
1163 if (e1->tag != e2->tag) return False;
1164 switch (e1->tag) {
1165 case Iex_Const: {
1166 /* The only interesting case */
1167 IRConst *c1 = e1->Iex.Const.con;
1168 IRConst *c2 = e2->Iex.Const.con;
1169 return c1->tag != c2->tag;
1170 }
1171 default:
1172 break;
1173 }
1174 return False;
1175}
1176
1177
florianea7eab72011-07-21 16:21:58 +00001178/* Is this literally IRExpr_Const(IRConst_U32(0)) ? */
1179static Bool isZeroU32 ( IRExpr* e )
1180{
1181 return toBool( e->tag == Iex_Const
1182 && e->Iex.Const.con->tag == Ico_U32
1183 && e->Iex.Const.con->Ico.U32 == 0);
1184}
1185
florian40226d12014-07-16 20:29:38 +00001186/* Is this literally IRExpr_Const(IRConst_U64(0)) ?
1187 Currently unused; commented out to avoid compiler warning */
1188#if 0
sewardjbbcf1882014-01-12 12:49:10 +00001189static Bool isZeroU64 ( IRExpr* e )
1190{
1191 return toBool( e->tag == Iex_Const
1192 && e->Iex.Const.con->tag == Ico_U64
1193 && e->Iex.Const.con->Ico.U64 == 0);
1194}
florian40226d12014-07-16 20:29:38 +00001195#endif
sewardjbbcf1882014-01-12 12:49:10 +00001196
sewardj9571dc02014-01-26 18:34:23 +00001197/* Is this literally IRExpr_Const(IRConst_V128(0)) ? */
1198static Bool isZeroV128 ( IRExpr* e )
1199{
1200 return toBool( e->tag == Iex_Const
1201 && e->Iex.Const.con->tag == Ico_V128
1202 && e->Iex.Const.con->Ico.V128 == 0x0000);
1203}
1204
1205/* Is this literally IRExpr_Const(IRConst_V256(0)) ? */
1206static Bool isZeroV256 ( IRExpr* e )
1207{
1208 return toBool( e->tag == Iex_Const
1209 && e->Iex.Const.con->tag == Ico_V256
1210 && e->Iex.Const.con->Ico.V256 == 0x00000000);
1211}
1212
florianf6402ab2012-01-29 02:19:43 +00001213/* Is this an integer constant with value 0 ? */
1214static Bool isZeroU ( IRExpr* e )
1215{
1216 if (e->tag != Iex_Const) return False;
florianf6402ab2012-01-29 02:19:43 +00001217 switch (e->Iex.Const.con->tag) {
1218 case Ico_U1: return toBool( e->Iex.Const.con->Ico.U1 == 0);
1219 case Ico_U8: return toBool( e->Iex.Const.con->Ico.U8 == 0);
1220 case Ico_U16: return toBool( e->Iex.Const.con->Ico.U16 == 0);
1221 case Ico_U32: return toBool( e->Iex.Const.con->Ico.U32 == 0);
1222 case Ico_U64: return toBool( e->Iex.Const.con->Ico.U64 == 0);
1223 default: vpanic("isZeroU");
1224 }
1225}
1226
sewardjcf4be4a2012-03-26 09:44:39 +00001227/* Is this an integer constant with value 1---1b ? */
1228static Bool isOnesU ( IRExpr* e )
1229{
1230 if (e->tag != Iex_Const) return False;
1231 switch (e->Iex.Const.con->tag) {
1232 case Ico_U8: return toBool( e->Iex.Const.con->Ico.U8 == 0xFF);
1233 case Ico_U16: return toBool( e->Iex.Const.con->Ico.U16 == 0xFFFF);
1234 case Ico_U32: return toBool( e->Iex.Const.con->Ico.U32
1235 == 0xFFFFFFFF);
1236 case Ico_U64: return toBool( e->Iex.Const.con->Ico.U64
1237 == 0xFFFFFFFFFFFFFFFFULL);
1238 default: ppIRExpr(e); vpanic("isOnesU");
1239 }
1240}
1241
sewardje1d45da2004-11-12 00:13:21 +00001242static Bool notBool ( Bool b )
1243{
1244 if (b == True) return False;
1245 if (b == False) return True;
1246 vpanic("notBool");
1247}
1248
sewardj0033ddc2005-04-26 23:34:34 +00001249/* Make a zero which has the same type as the result of the given
1250 primop. */
sewardj64d776c2010-10-01 14:06:22 +00001251static IRExpr* mkZeroOfPrimopResultType ( IROp op )
sewardj0033ddc2005-04-26 23:34:34 +00001252{
1253 switch (op) {
sewardja7e96382012-06-29 16:26:17 +00001254 case Iop_CmpNE32: return IRExpr_Const(IRConst_U1(toBool(0)));
sewardj0033ddc2005-04-26 23:34:34 +00001255 case Iop_Xor8: return IRExpr_Const(IRConst_U8(0));
1256 case Iop_Xor16: return IRExpr_Const(IRConst_U16(0));
sewardjbe917912010-08-22 12:38:53 +00001257 case Iop_Sub32:
sewardj0033ddc2005-04-26 23:34:34 +00001258 case Iop_Xor32: return IRExpr_Const(IRConst_U32(0));
sewardjbbcf1882014-01-12 12:49:10 +00001259 case Iop_And64:
sewardj64d776c2010-10-01 14:06:22 +00001260 case Iop_Sub64:
sewardj0033ddc2005-04-26 23:34:34 +00001261 case Iop_Xor64: return IRExpr_Const(IRConst_U64(0));
sewardj36a911a2014-04-03 13:48:21 +00001262 case Iop_XorV128:
1263 case Iop_AndV128: return IRExpr_Const(IRConst_V128(0));
florian1b7c4712014-07-16 20:17:49 +00001264 case Iop_AndV256: return IRExpr_Const(IRConst_V256(0));
sewardj64d776c2010-10-01 14:06:22 +00001265 default: vpanic("mkZeroOfPrimopResultType: bad primop");
1266 }
1267}
1268
1269/* Make a value containing all 1-bits, which has the same type as the
1270 result of the given primop. */
1271static IRExpr* mkOnesOfPrimopResultType ( IROp op )
1272{
1273 switch (op) {
sewardja7e96382012-06-29 16:26:17 +00001274 case Iop_CmpEQ32:
sewardj64d776c2010-10-01 14:06:22 +00001275 case Iop_CmpEQ64:
1276 return IRExpr_Const(IRConst_U1(toBool(1)));
sewardjcf4be4a2012-03-26 09:44:39 +00001277 case Iop_Or8:
1278 return IRExpr_Const(IRConst_U8(0xFF));
1279 case Iop_Or16:
1280 return IRExpr_Const(IRConst_U16(0xFFFF));
1281 case Iop_Or32:
1282 return IRExpr_Const(IRConst_U32(0xFFFFFFFF));
sewardj64d776c2010-10-01 14:06:22 +00001283 case Iop_CmpEQ8x8:
sewardjcf4be4a2012-03-26 09:44:39 +00001284 case Iop_Or64:
sewardj64d776c2010-10-01 14:06:22 +00001285 return IRExpr_Const(IRConst_U64(0xFFFFFFFFFFFFFFFFULL));
1286 case Iop_CmpEQ8x16:
sewardj899d1832012-07-10 21:41:01 +00001287 case Iop_CmpEQ16x8:
sewardjffccf2b2012-06-29 15:33:09 +00001288 case Iop_CmpEQ32x4:
sewardj64d776c2010-10-01 14:06:22 +00001289 return IRExpr_Const(IRConst_V128(0xFFFF));
1290 default:
sewardjcf4be4a2012-03-26 09:44:39 +00001291 ppIROp(op);
sewardj64d776c2010-10-01 14:06:22 +00001292 vpanic("mkOnesOfPrimopResultType: bad primop");
sewardj0033ddc2005-04-26 23:34:34 +00001293 }
1294}
1295
sewardj4cba9f42011-03-07 18:34:34 +00001296/* Helpers for folding Clz32/64. */
1297static UInt fold_Clz64 ( ULong value )
1298{
1299 UInt i;
1300 vassert(value != 0ULL); /* no defined semantics for arg==0 */
1301 for (i = 0; i < 64; ++i) {
sewardj7f6330d2011-04-05 11:06:02 +00001302 if (0ULL != (value & (((ULong)1) << (63 - i)))) return i;
sewardj4cba9f42011-03-07 18:34:34 +00001303 }
1304 vassert(0);
1305 /*NOTREACHED*/
1306 return 0;
1307}
1308
1309static UInt fold_Clz32 ( UInt value )
1310{
1311 UInt i;
1312 vassert(value != 0); /* no defined semantics for arg==0 */
1313 for (i = 0; i < 32; ++i) {
sewardj7f6330d2011-04-05 11:06:02 +00001314 if (0 != (value & (((UInt)1) << (31 - i)))) return i;
sewardj4cba9f42011-03-07 18:34:34 +00001315 }
1316 vassert(0);
1317 /*NOTREACHED*/
1318 return 0;
1319}
1320
sewardj4a0bee02012-06-29 14:44:44 +00001321/* V64 holds 8 summary-constant bits in V128/V256 style. Convert to
1322 the corresponding real constant. */
1323//XXX re-check this before use
1324//static ULong de_summarise_V64 ( UChar v64 )
1325//{
1326// ULong r = 0;
1327// if (v64 & (1<<0)) r |= 0x00000000000000FFULL;
1328// if (v64 & (1<<1)) r |= 0x000000000000FF00ULL;
1329// if (v64 & (1<<2)) r |= 0x0000000000FF0000ULL;
1330// if (v64 & (1<<3)) r |= 0x00000000FF000000ULL;
1331// if (v64 & (1<<4)) r |= 0x000000FF00000000ULL;
1332// if (v64 & (1<<5)) r |= 0x0000FF0000000000ULL;
1333// if (v64 & (1<<6)) r |= 0x00FF000000000000ULL;
1334// if (v64 & (1<<7)) r |= 0xFF00000000000000ULL;
1335// return r;
1336//}
sewardj0033ddc2005-04-26 23:34:34 +00001337
sewardj009230b2013-01-26 11:47:55 +00001338/* Helper for arbitrary expression pattern matching in flat IR. If
1339 'e' is a reference to a tmp, look it up in env -- repeatedly, if
1340 necessary -- until it resolves to a non-tmp. Note that this can
1341 return NULL if it can't resolve 'e' to a new expression, which will
1342 be the case if 'e' is instead defined by an IRStmt (IRDirty or
1343 LLSC). */
1344static IRExpr* chase ( IRExpr** env, IRExpr* e )
1345{
1346 /* Why is this loop guaranteed to terminate? Because all tmps must
1347 have definitions before use, hence a tmp cannot be bound
1348 (directly or indirectly) to itself. */
1349 while (e->tag == Iex_RdTmp) {
1350 if (0) { vex_printf("chase "); ppIRExpr(e); vex_printf("\n"); }
1351 e = env[(Int)e->Iex.RdTmp.tmp];
1352 if (e == NULL) break;
1353 }
1354 return e;
1355}
1356
floriancdb5fee2012-02-13 00:06:29 +00001357static IRExpr* fold_Expr ( IRExpr** env, IRExpr* e )
sewardj84be7372004-08-18 13:59:33 +00001358{
sewardj278c44c2004-08-20 00:28:13 +00001359 Int shift;
sewardj84be7372004-08-18 13:59:33 +00001360 IRExpr* e2 = e; /* e2 is the result of folding e, if possible */
1361
florian708417d2012-02-15 00:43:36 +00001362 switch (e->tag) {
1363 case Iex_Unop:
1364 /* UNARY ops */
1365 if (e->Iex.Unop.arg->tag == Iex_Const) {
1366 switch (e->Iex.Unop.op) {
sewardjae27ab62004-10-15 21:21:46 +00001367 case Iop_1Uto8:
sewardj9d2e7692005-02-07 01:11:31 +00001368 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardjba999312004-11-15 15:21:17 +00001369 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardj9d2e7692005-02-07 01:11:31 +00001370 ? 1 : 0)));
sewardjae27ab62004-10-15 21:21:46 +00001371 break;
sewardjf4a821d2004-10-09 00:58:19 +00001372 case Iop_1Uto32:
1373 e2 = IRExpr_Const(IRConst_U32(
sewardjba999312004-11-15 15:21:17 +00001374 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardjf4a821d2004-10-09 00:58:19 +00001375 ? 1 : 0));
1376 break;
sewardj2716ff12005-05-20 19:21:45 +00001377 case Iop_1Uto64:
1378 e2 = IRExpr_Const(IRConst_U64(
1379 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
1380 ? 1 : 0));
1381 break;
sewardje6b39932004-11-06 17:01:15 +00001382
sewardj1bee5612005-11-10 18:10:58 +00001383 case Iop_1Sto8:
1384 e2 = IRExpr_Const(IRConst_U8(toUChar(
1385 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
1386 ? 0xFF : 0)));
1387 break;
sewardj68884ef2005-07-18 13:58:49 +00001388 case Iop_1Sto16:
sewardj743d8f02005-07-27 00:22:37 +00001389 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardj68884ef2005-07-18 13:58:49 +00001390 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardj743d8f02005-07-27 00:22:37 +00001391 ? 0xFFFF : 0)));
sewardj68884ef2005-07-18 13:58:49 +00001392 break;
sewardjd9997882004-11-04 19:42:59 +00001393 case Iop_1Sto32:
1394 e2 = IRExpr_Const(IRConst_U32(
sewardjba999312004-11-15 15:21:17 +00001395 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardjd9997882004-11-04 19:42:59 +00001396 ? 0xFFFFFFFF : 0));
1397 break;
sewardje6b39932004-11-06 17:01:15 +00001398 case Iop_1Sto64:
1399 e2 = IRExpr_Const(IRConst_U64(
sewardjba999312004-11-15 15:21:17 +00001400 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardje6b39932004-11-06 17:01:15 +00001401 ? 0xFFFFFFFFFFFFFFFFULL : 0));
1402 break;
1403
sewardj883b00b2004-09-11 09:30:24 +00001404 case Iop_8Sto32: {
1405 /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
1406 s32 <<= 24;
1407 s32 >>= 24;
1408 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
1409 break;
1410 }
sewardj7f6330d2011-04-05 11:06:02 +00001411 case Iop_16Sto32: {
1412 /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1413 s32 <<= 16;
1414 s32 >>= 16;
1415 e2 = IRExpr_Const(IRConst_U32( (UInt)s32) );
1416 break;
1417 }
sewardj291a7e82005-04-27 11:42:44 +00001418 case Iop_8Uto64:
1419 e2 = IRExpr_Const(IRConst_U64(
1420 0xFFULL & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1421 break;
1422 case Iop_16Uto64:
1423 e2 = IRExpr_Const(IRConst_U64(
1424 0xFFFFULL & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
1425 break;
sewardj84be7372004-08-18 13:59:33 +00001426 case Iop_8Uto32:
1427 e2 = IRExpr_Const(IRConst_U32(
1428 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1429 break;
sewardj7f6330d2011-04-05 11:06:02 +00001430 case Iop_8Sto16: {
1431 /* signed */ Short s16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
1432 s16 <<= 8;
1433 s16 >>= 8;
1434 e2 = IRExpr_Const(IRConst_U16( (UShort)s16) );
1435 break;
1436 }
1437 case Iop_8Uto16:
1438 e2 = IRExpr_Const(IRConst_U16(
1439 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1440 break;
sewardj84be7372004-08-18 13:59:33 +00001441 case Iop_16Uto32:
1442 e2 = IRExpr_Const(IRConst_U32(
1443 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
1444 break;
sewardj73017432004-10-14 19:33:25 +00001445 case Iop_32to16:
sewardj9d2e7692005-02-07 01:11:31 +00001446 e2 = IRExpr_Const(IRConst_U16(toUShort(
1447 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
sewardj73017432004-10-14 19:33:25 +00001448 break;
sewardj4345f7a2004-09-22 19:49:27 +00001449 case Iop_32to8:
sewardj9d2e7692005-02-07 01:11:31 +00001450 e2 = IRExpr_Const(IRConst_U8(toUChar(
1451 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
sewardj4345f7a2004-09-22 19:49:27 +00001452 break;
sewardj7447b5b2004-10-16 11:30:42 +00001453 case Iop_32to1:
sewardj9d2e7692005-02-07 01:11:31 +00001454 e2 = IRExpr_Const(IRConst_U1(toBool(
1455 1 == (1 & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)
1456 )));
sewardj7447b5b2004-10-16 11:30:42 +00001457 break;
sewardj291a7e82005-04-27 11:42:44 +00001458 case Iop_64to1:
1459 e2 = IRExpr_Const(IRConst_U1(toBool(
1460 1 == (1 & e->Iex.Unop.arg->Iex.Const.con->Ico.U64)
1461 )));
1462 break;
sewardje6b39932004-11-06 17:01:15 +00001463
sewardj4a0bee02012-06-29 14:44:44 +00001464 case Iop_NotV128:
1465 e2 = IRExpr_Const(IRConst_V128(
1466 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.V128)));
1467 break;
sewardjf057afb2005-02-27 13:35:41 +00001468 case Iop_Not64:
1469 e2 = IRExpr_Const(IRConst_U64(
1470 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U64)));
1471 break;
sewardj883b00b2004-09-11 09:30:24 +00001472 case Iop_Not32:
1473 e2 = IRExpr_Const(IRConst_U32(
1474 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
1475 break;
sewardje6b39932004-11-06 17:01:15 +00001476 case Iop_Not16:
sewardj9d2e7692005-02-07 01:11:31 +00001477 e2 = IRExpr_Const(IRConst_U16(toUShort(
1478 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U16))));
sewardje6b39932004-11-06 17:01:15 +00001479 break;
sewardjd9997882004-11-04 19:42:59 +00001480 case Iop_Not8:
sewardj9d2e7692005-02-07 01:11:31 +00001481 e2 = IRExpr_Const(IRConst_U8(toUChar(
1482 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U8))));
sewardjd9997882004-11-04 19:42:59 +00001483 break;
sewardje6b39932004-11-06 17:01:15 +00001484
sewardje1d45da2004-11-12 00:13:21 +00001485 case Iop_Not1:
sewardjba999312004-11-15 15:21:17 +00001486 e2 = IRExpr_Const(IRConst_U1(
1487 notBool(e->Iex.Unop.arg->Iex.Const.con->Ico.U1)));
sewardje1d45da2004-11-12 00:13:21 +00001488 break;
1489
sewardj291a7e82005-04-27 11:42:44 +00001490 case Iop_64to8: {
1491 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1492 w64 &= 0xFFULL;
1493 e2 = IRExpr_Const(IRConst_U8( (UChar)w64 ));
1494 break;
1495 }
1496 case Iop_64to16: {
1497 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1498 w64 &= 0xFFFFULL;
sewardje85bc402005-05-06 16:29:26 +00001499 e2 = IRExpr_Const(IRConst_U16( (UShort)w64 ));
sewardj291a7e82005-04-27 11:42:44 +00001500 break;
1501 }
sewardj1d8ce202004-12-13 14:14:16 +00001502 case Iop_64to32: {
1503 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1504 w64 &= 0x00000000FFFFFFFFULL;
1505 e2 = IRExpr_Const(IRConst_U32( (UInt)w64 ));
sewardj37010592004-12-13 10:47:15 +00001506 break;
sewardj1d8ce202004-12-13 14:14:16 +00001507 }
sewardj1d8ce202004-12-13 14:14:16 +00001508 case Iop_64HIto32: {
1509 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1510 w64 >>= 32;
1511 e2 = IRExpr_Const(IRConst_U32( (UInt)w64 ));
1512 break;
1513 }
sewardjb5710b82005-01-27 16:05:09 +00001514 case Iop_32Uto64:
1515 e2 = IRExpr_Const(IRConst_U64(
1516 0xFFFFFFFFULL
1517 & e->Iex.Unop.arg->Iex.Const.con->Ico.U32));
1518 break;
sewardj7f6330d2011-04-05 11:06:02 +00001519 case Iop_16Sto64: {
1520 /* signed */ Long s64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1521 s64 <<= 48;
1522 s64 >>= 48;
1523 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1524 break;
1525 }
sewardj287e9bb2010-07-29 16:12:41 +00001526 case Iop_32Sto64: {
1527 /* signed */ Long s64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1528 s64 <<= 32;
1529 s64 >>= 32;
1530 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1531 break;
1532 }
sewardj7f6330d2011-04-05 11:06:02 +00001533
1534 case Iop_16to8: {
1535 UShort w16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1536 w16 &= 0xFF;
1537 e2 = IRExpr_Const(IRConst_U8( (UChar)w16 ));
1538 break;
1539 }
1540 case Iop_16HIto8: {
1541 UShort w16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1542 w16 >>= 8;
1543 w16 &= 0xFF;
1544 e2 = IRExpr_Const(IRConst_U8( (UChar)w16 ));
1545 break;
1546 }
1547
sewardj0033ddc2005-04-26 23:34:34 +00001548 case Iop_CmpNEZ8:
1549 e2 = IRExpr_Const(IRConst_U1(toBool(
1550 0 !=
1551 (0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8)
1552 )));
1553 break;
1554 case Iop_CmpNEZ32:
1555 e2 = IRExpr_Const(IRConst_U1(toBool(
1556 0 !=
1557 (0xFFFFFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)
1558 )));
1559 break;
1560 case Iop_CmpNEZ64:
1561 e2 = IRExpr_Const(IRConst_U1(toBool(
1562 0ULL != e->Iex.Unop.arg->Iex.Const.con->Ico.U64
1563 )));
1564 break;
1565
sewardjeb17e492007-08-25 23:07:44 +00001566 case Iop_CmpwNEZ32: {
1567 UInt w32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1568 if (w32 == 0)
1569 e2 = IRExpr_Const(IRConst_U32( 0 ));
1570 else
1571 e2 = IRExpr_Const(IRConst_U32( 0xFFFFFFFF ));
1572 break;
1573 }
1574 case Iop_CmpwNEZ64: {
1575 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1576 if (w64 == 0)
1577 e2 = IRExpr_Const(IRConst_U64( 0 ));
1578 else
1579 e2 = IRExpr_Const(IRConst_U64( 0xFFFFFFFFFFFFFFFFULL ));
1580 break;
1581 }
1582
1583 case Iop_Left32: {
1584 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1585 Int s32 = (Int)(u32 & 0xFFFFFFFF);
1586 s32 = (s32 | (-s32));
1587 e2 = IRExpr_Const( IRConst_U32( (UInt)s32 ));
1588 break;
1589 }
1590
1591 case Iop_Left64: {
1592 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1593 Long s64 = (Long)u64;
1594 s64 = (s64 | (-s64));
1595 e2 = IRExpr_Const( IRConst_U64( (ULong)s64 ));
1596 break;
1597 }
1598
sewardj4cba9f42011-03-07 18:34:34 +00001599 case Iop_Clz32: {
1600 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1601 if (u32 != 0)
1602 e2 = IRExpr_Const(IRConst_U32(fold_Clz32(u32)));
1603 break;
1604 }
1605 case Iop_Clz64: {
1606 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1607 if (u64 != 0ULL)
1608 e2 = IRExpr_Const(IRConst_U64(fold_Clz64(u64)));
1609 break;
1610 }
1611
sewardj4a0bee02012-06-29 14:44:44 +00001612 /* For these vector ones, can't fold all cases, but at least
1613 do the most obvious one. Could do better here using
1614 summarise/desummarise of vector constants, but too
1615 difficult to verify; hence just handle the zero cases. */
1616 case Iop_32UtoV128: {
1617 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1618 if (0 == u32) {
1619 e2 = IRExpr_Const(IRConst_V128(0x0000));
1620 } else {
1621 goto unhandled;
1622 }
1623 break;
1624 }
1625 case Iop_V128to64: {
1626 UShort v128 = e->Iex.Unop.arg->Iex.Const.con->Ico.V128;
1627 if (0 == ((v128 >> 0) & 0xFF)) {
1628 e2 = IRExpr_Const(IRConst_U64(0));
1629 } else {
1630 goto unhandled;
1631 }
1632 break;
1633 }
1634 case Iop_V128HIto64: {
1635 UShort v128 = e->Iex.Unop.arg->Iex.Const.con->Ico.V128;
1636 if (0 == ((v128 >> 8) & 0xFF)) {
1637 e2 = IRExpr_Const(IRConst_U64(0));
1638 } else {
1639 goto unhandled;
1640 }
1641 break;
1642 }
1643 case Iop_64UtoV128: {
1644 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1645 if (0 == u64) {
1646 e2 = IRExpr_Const(IRConst_V128(0x0000));
1647 } else {
1648 goto unhandled;
1649 }
1650 break;
1651 }
1652
sewardjffccf2b2012-06-29 15:33:09 +00001653 /* Even stupider (although still correct ..) */
1654 case Iop_V256to64_0: case Iop_V256to64_1:
1655 case Iop_V256to64_2: case Iop_V256to64_3: {
1656 UInt v256 = e->Iex.Unop.arg->Iex.Const.con->Ico.V256;
1657 if (v256 == 0x00000000) {
1658 e2 = IRExpr_Const(IRConst_U64(0));
1659 } else {
1660 goto unhandled;
1661 }
1662 break;
1663 }
1664
sewardjfbe569d2014-08-14 22:25:31 +00001665 case Iop_ZeroHI64ofV128: {
1666 /* Could do better here -- only need to look at the bottom 64 bits
1667 of the argument, really. */
1668 UShort v128 = e->Iex.Unop.arg->Iex.Const.con->Ico.V128;
1669 if (v128 == 0x0000) {
1670 e2 = IRExpr_Const(IRConst_V128(0x0000));
1671 } else {
1672 goto unhandled;
1673 }
1674 break;
1675 }
1676
sewardj84be7372004-08-18 13:59:33 +00001677 default:
1678 goto unhandled;
1679 }
florian708417d2012-02-15 00:43:36 +00001680 }
1681 break;
sewardj84be7372004-08-18 13:59:33 +00001682
florian708417d2012-02-15 00:43:36 +00001683 case Iex_Binop:
1684 /* BINARY ops */
sewardj84be7372004-08-18 13:59:33 +00001685 if (e->Iex.Binop.arg1->tag == Iex_Const
1686 && e->Iex.Binop.arg2->tag == Iex_Const) {
1687 /* cases where both args are consts */
1688 switch (e->Iex.Binop.op) {
sewardje6b39932004-11-06 17:01:15 +00001689
sewardj855dc722005-02-17 09:26:05 +00001690 /* -- Or -- */
sewardjd9997882004-11-04 19:42:59 +00001691 case Iop_Or8:
sewardj9d2e7692005-02-07 01:11:31 +00001692 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardjd9997882004-11-04 19:42:59 +00001693 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001694 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardjd9997882004-11-04 19:42:59 +00001695 break;
sewardje6b39932004-11-06 17:01:15 +00001696 case Iop_Or16:
sewardj9d2e7692005-02-07 01:11:31 +00001697 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardje6b39932004-11-06 17:01:15 +00001698 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
sewardj9d2e7692005-02-07 01:11:31 +00001699 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
sewardje6b39932004-11-06 17:01:15 +00001700 break;
1701 case Iop_Or32:
1702 e2 = IRExpr_Const(IRConst_U32(
1703 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1704 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1705 break;
sewardjf057afb2005-02-27 13:35:41 +00001706 case Iop_Or64:
1707 e2 = IRExpr_Const(IRConst_U64(
1708 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1709 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1710 break;
sewardj4a0bee02012-06-29 14:44:44 +00001711 case Iop_OrV128:
1712 e2 = IRExpr_Const(IRConst_V128(
1713 (e->Iex.Binop.arg1->Iex.Const.con->Ico.V128
1714 | e->Iex.Binop.arg2->Iex.Const.con->Ico.V128)));
1715 break;
sewardje6b39932004-11-06 17:01:15 +00001716
sewardj855dc722005-02-17 09:26:05 +00001717 /* -- Xor -- */
sewardj883b00b2004-09-11 09:30:24 +00001718 case Iop_Xor8:
sewardj9d2e7692005-02-07 01:11:31 +00001719 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj883b00b2004-09-11 09:30:24 +00001720 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001721 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj883b00b2004-09-11 09:30:24 +00001722 break;
sewardj82c9f2f2005-03-02 16:05:13 +00001723 case Iop_Xor16:
sewardjc7c098f2005-03-21 01:06:20 +00001724 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardj82c9f2f2005-03-02 16:05:13 +00001725 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
sewardjc7c098f2005-03-21 01:06:20 +00001726 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
sewardj82c9f2f2005-03-02 16:05:13 +00001727 break;
sewardj855dc722005-02-17 09:26:05 +00001728 case Iop_Xor32:
1729 e2 = IRExpr_Const(IRConst_U32(
1730 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1731 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1732 break;
sewardjf057afb2005-02-27 13:35:41 +00001733 case Iop_Xor64:
1734 e2 = IRExpr_Const(IRConst_U64(
1735 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1736 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1737 break;
sewardj4a0bee02012-06-29 14:44:44 +00001738 case Iop_XorV128:
1739 e2 = IRExpr_Const(IRConst_V128(
1740 (e->Iex.Binop.arg1->Iex.Const.con->Ico.V128
1741 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.V128)));
1742 break;
sewardj855dc722005-02-17 09:26:05 +00001743
1744 /* -- And -- */
sewardj84be7372004-08-18 13:59:33 +00001745 case Iop_And8:
sewardj9d2e7692005-02-07 01:11:31 +00001746 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj84be7372004-08-18 13:59:33 +00001747 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001748 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj84be7372004-08-18 13:59:33 +00001749 break;
sewardj7f6330d2011-04-05 11:06:02 +00001750 case Iop_And16:
1751 e2 = IRExpr_Const(IRConst_U16(toUShort(
1752 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
1753 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
1754 break;
sewardj855dc722005-02-17 09:26:05 +00001755 case Iop_And32:
1756 e2 = IRExpr_Const(IRConst_U32(
1757 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1758 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1759 break;
1760 case Iop_And64:
1761 e2 = IRExpr_Const(IRConst_U64(
1762 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1763 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1764 break;
sewardj4a0bee02012-06-29 14:44:44 +00001765 case Iop_AndV128:
1766 e2 = IRExpr_Const(IRConst_V128(
1767 (e->Iex.Binop.arg1->Iex.Const.con->Ico.V128
1768 & e->Iex.Binop.arg2->Iex.Const.con->Ico.V128)));
1769 break;
sewardj855dc722005-02-17 09:26:05 +00001770
1771 /* -- Add -- */
sewardj4345f7a2004-09-22 19:49:27 +00001772 case Iop_Add8:
sewardj9d2e7692005-02-07 01:11:31 +00001773 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj4345f7a2004-09-22 19:49:27 +00001774 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001775 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj4345f7a2004-09-22 19:49:27 +00001776 break;
sewardj855dc722005-02-17 09:26:05 +00001777 case Iop_Add32:
1778 e2 = IRExpr_Const(IRConst_U32(
1779 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1780 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1781 break;
1782 case Iop_Add64:
1783 e2 = IRExpr_Const(IRConst_U64(
1784 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1785 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1786 break;
1787
1788 /* -- Sub -- */
sewardj84be7372004-08-18 13:59:33 +00001789 case Iop_Sub8:
sewardj9d2e7692005-02-07 01:11:31 +00001790 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj84be7372004-08-18 13:59:33 +00001791 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001792 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj84be7372004-08-18 13:59:33 +00001793 break;
sewardjd7217032004-08-19 10:49:10 +00001794 case Iop_Sub32:
1795 e2 = IRExpr_Const(IRConst_U32(
1796 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1797 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1798 break;
sewardj70a8ddf2005-02-13 02:24:26 +00001799 case Iop_Sub64:
1800 e2 = IRExpr_Const(IRConst_U64(
1801 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1802 - e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1803 break;
sewardjc2bcb6f2005-02-07 00:17:12 +00001804
sewardj478646f2008-05-01 20:13:04 +00001805 /* -- Max32U -- */
1806 case Iop_Max32U: {
1807 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1808 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1809 UInt res = u32a > u32b ? u32a : u32b;
1810 e2 = IRExpr_Const(IRConst_U32(res));
1811 break;
1812 }
1813
sewardj855dc722005-02-17 09:26:05 +00001814 /* -- Mul -- */
sewardjb9c5cf62004-08-24 15:10:38 +00001815 case Iop_Mul32:
1816 e2 = IRExpr_Const(IRConst_U32(
1817 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1818 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1819 break;
sewardja34c0712005-03-30 23:19:46 +00001820 case Iop_Mul64:
1821 e2 = IRExpr_Const(IRConst_U64(
1822 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1823 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1824 break;
1825
sewardjea6bccb2005-03-01 10:19:23 +00001826 case Iop_MullS32: {
1827 /* very paranoid */
1828 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1829 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1830 Int s32a = (Int)u32a;
1831 Int s32b = (Int)u32b;
1832 Long s64a = (Long)s32a;
1833 Long s64b = (Long)s32b;
1834 Long sres = s64a * s64b;
1835 ULong ures = (ULong)sres;
1836 e2 = IRExpr_Const(IRConst_U64(ures));
1837 break;
1838 }
sewardjb095fba2005-02-13 14:13:04 +00001839
sewardj855dc722005-02-17 09:26:05 +00001840 /* -- Shl -- */
sewardjd7217032004-08-19 10:49:10 +00001841 case Iop_Shl32:
sewardj61348472004-08-20 01:01:04 +00001842 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1843 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj29632392004-08-22 02:38:11 +00001844 if (shift >= 0 && shift <= 31)
sewardj278c44c2004-08-20 00:28:13 +00001845 e2 = IRExpr_Const(IRConst_U32(
1846 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1847 << shift)));
sewardjd7217032004-08-19 10:49:10 +00001848 break;
sewardjb095fba2005-02-13 14:13:04 +00001849 case Iop_Shl64:
1850 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1851 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1852 if (shift >= 0 && shift <= 63)
1853 e2 = IRExpr_Const(IRConst_U64(
1854 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1855 << shift)));
1856 break;
1857
sewardj855dc722005-02-17 09:26:05 +00001858 /* -- Sar -- */
sewardj278c44c2004-08-20 00:28:13 +00001859 case Iop_Sar32: {
1860 /* paranoid ... */
1861 /*signed*/ Int s32;
sewardj61348472004-08-20 01:01:04 +00001862 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj278c44c2004-08-20 00:28:13 +00001863 s32 = (Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +00001864 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj278c44c2004-08-20 00:28:13 +00001865 if (shift >= 0 && shift <= 31) {
1866 s32 >>=/*signed*/ shift;
1867 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
1868 }
1869 break;
1870 }
sewardj855dc722005-02-17 09:26:05 +00001871 case Iop_Sar64: {
1872 /* paranoid ... */
1873 /*signed*/ Long s64;
1874 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1875 s64 = (Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64);
1876 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1877 if (shift >= 0 && shift <= 63) {
1878 s64 >>=/*signed*/ shift;
1879 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1880 }
1881 break;
1882 }
1883
1884 /* -- Shr -- */
sewardj61348472004-08-20 01:01:04 +00001885 case Iop_Shr32: {
1886 /* paranoid ... */
sewardj4add7142005-02-21 08:20:22 +00001887 /*unsigned*/ UInt u32;
sewardj61348472004-08-20 01:01:04 +00001888 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj4add7142005-02-21 08:20:22 +00001889 u32 = (UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +00001890 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1891 if (shift >= 0 && shift <= 31) {
sewardj4add7142005-02-21 08:20:22 +00001892 u32 >>=/*unsigned*/ shift;
1893 e2 = IRExpr_Const(IRConst_U32(u32));
1894 }
1895 break;
1896 }
1897 case Iop_Shr64: {
1898 /* paranoid ... */
1899 /*unsigned*/ ULong u64;
1900 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1901 u64 = (ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64);
1902 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1903 if (shift >= 0 && shift <= 63) {
1904 u64 >>=/*unsigned*/ shift;
1905 e2 = IRExpr_Const(IRConst_U64(u64));
sewardj61348472004-08-20 01:01:04 +00001906 }
1907 break;
1908 }
sewardj855dc722005-02-17 09:26:05 +00001909
1910 /* -- CmpEQ -- */
sewardjb8e75862004-08-19 17:58:45 +00001911 case Iop_CmpEQ32:
sewardj9d2e7692005-02-07 01:11:31 +00001912 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardjb8e75862004-08-19 17:58:45 +00001913 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
sewardj9d2e7692005-02-07 01:11:31 +00001914 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))));
sewardjb8e75862004-08-19 17:58:45 +00001915 break;
sewardj855dc722005-02-17 09:26:05 +00001916 case Iop_CmpEQ64:
1917 e2 = IRExpr_Const(IRConst_U1(toBool(
1918 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1919 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U64))));
1920 break;
1921
1922 /* -- CmpNE -- */
1923 case Iop_CmpNE8:
sewardje13074c2012-11-08 10:57:08 +00001924 case Iop_CasCmpNE8:
1925 case Iop_ExpCmpNE8:
sewardj855dc722005-02-17 09:26:05 +00001926 e2 = IRExpr_Const(IRConst_U1(toBool(
1927 ((0xFF & e->Iex.Binop.arg1->Iex.Const.con->Ico.U8)
1928 != (0xFF & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)))));
1929 break;
sewardjae27ab62004-10-15 21:21:46 +00001930 case Iop_CmpNE32:
sewardje13074c2012-11-08 10:57:08 +00001931 case Iop_CasCmpNE32:
1932 case Iop_ExpCmpNE32:
sewardj9d2e7692005-02-07 01:11:31 +00001933 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardjae27ab62004-10-15 21:21:46 +00001934 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
sewardj9d2e7692005-02-07 01:11:31 +00001935 != e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))));
sewardjae27ab62004-10-15 21:21:46 +00001936 break;
sewardje6b39932004-11-06 17:01:15 +00001937 case Iop_CmpNE64:
sewardje13074c2012-11-08 10:57:08 +00001938 case Iop_CasCmpNE64:
1939 case Iop_ExpCmpNE64:
sewardj9d2e7692005-02-07 01:11:31 +00001940 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardje6b39932004-11-06 17:01:15 +00001941 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
sewardj9d2e7692005-02-07 01:11:31 +00001942 != e->Iex.Binop.arg2->Iex.Const.con->Ico.U64))));
sewardje6b39932004-11-06 17:01:15 +00001943 break;
1944
sewardj855dc722005-02-17 09:26:05 +00001945 /* -- CmpLEU -- */
sewardj7447b5b2004-10-16 11:30:42 +00001946 case Iop_CmpLE32U:
sewardj9d2e7692005-02-07 01:11:31 +00001947 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj7447b5b2004-10-16 11:30:42 +00001948 ((UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001949 <= (UInt)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj7447b5b2004-10-16 11:30:42 +00001950 break;
sewardj7f6330d2011-04-05 11:06:02 +00001951 case Iop_CmpLE64U:
1952 e2 = IRExpr_Const(IRConst_U1(toBool(
1953 ((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1954 <= (ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1955 break;
sewardj855dc722005-02-17 09:26:05 +00001956
1957 /* -- CmpLES -- */
sewardj088e4f72004-10-19 01:25:02 +00001958 case Iop_CmpLE32S:
sewardj9d2e7692005-02-07 01:11:31 +00001959 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj088e4f72004-10-19 01:25:02 +00001960 ((Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001961 <= (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj088e4f72004-10-19 01:25:02 +00001962 break;
sewardj7f6330d2011-04-05 11:06:02 +00001963 case Iop_CmpLE64S:
1964 e2 = IRExpr_Const(IRConst_U1(toBool(
1965 ((Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1966 <= (Long)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1967 break;
sewardje1d45da2004-11-12 00:13:21 +00001968
sewardj855dc722005-02-17 09:26:05 +00001969 /* -- CmpLTS -- */
sewardj9bdd2652004-10-19 12:56:33 +00001970 case Iop_CmpLT32S:
sewardj9d2e7692005-02-07 01:11:31 +00001971 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj9bdd2652004-10-19 12:56:33 +00001972 ((Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001973 < (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj9bdd2652004-10-19 12:56:33 +00001974 break;
sewardj7f6330d2011-04-05 11:06:02 +00001975 case Iop_CmpLT64S:
1976 e2 = IRExpr_Const(IRConst_U1(toBool(
1977 ((Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1978 < (Long)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1979 break;
sewardj855dc722005-02-17 09:26:05 +00001980
1981 /* -- CmpLTU -- */
sewardje1d45da2004-11-12 00:13:21 +00001982 case Iop_CmpLT32U:
sewardj9d2e7692005-02-07 01:11:31 +00001983 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardje1d45da2004-11-12 00:13:21 +00001984 ((UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001985 < (UInt)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardje1d45da2004-11-12 00:13:21 +00001986 break;
sewardj7f6330d2011-04-05 11:06:02 +00001987 case Iop_CmpLT64U:
1988 e2 = IRExpr_Const(IRConst_U1(toBool(
1989 ((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1990 < (ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1991 break;
sewardj7447b5b2004-10-16 11:30:42 +00001992
sewardjb51f0f42005-07-18 11:38:02 +00001993 /* -- CmpORD -- */
1994 case Iop_CmpORD32S: {
1995 /* very paranoid */
1996 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1997 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1998 Int s32a = (Int)u32a;
1999 Int s32b = (Int)u32b;
2000 Int r = 0x2; /* EQ */
2001 if (s32a < s32b) {
2002 r = 0x8; /* LT */
2003 }
2004 else if (s32a > s32b) {
2005 r = 0x4; /* GT */
2006 }
2007 e2 = IRExpr_Const(IRConst_U32(r));
2008 break;
2009 }
2010
sewardj855dc722005-02-17 09:26:05 +00002011 /* -- nHLto2n -- */
sewardj088bcb42004-08-19 17:16:52 +00002012 case Iop_32HLto64:
2013 e2 = IRExpr_Const(IRConst_U64(
sewardj4a0bee02012-06-29 14:44:44 +00002014 (((ULong)(e->Iex.Binop.arg1
2015 ->Iex.Const.con->Ico.U32)) << 32)
sewardj088bcb42004-08-19 17:16:52 +00002016 | ((ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))
2017 ));
2018 break;
sewardj3bc8a592005-05-02 10:47:22 +00002019 case Iop_64HLto128:
2020 /* We can't fold this, because there is no way to
2021 express he result in IR, but at least pretend to
2022 handle it, so as to stop getting blasted with
2023 no-rule-for-this-primop messages. */
2024 break;
sewardj4a0bee02012-06-29 14:44:44 +00002025 /* For this vector one, can't fold all cases, but at
2026 least do the most obvious one. Could do better here
2027 using summarise/desummarise of vector constants, but
2028 too difficult to verify; hence just handle the zero
2029 cases. */
2030 case Iop_64HLtoV128: {
2031 ULong argHi = e->Iex.Binop.arg1->Iex.Const.con->Ico.U64;
2032 ULong argLo = e->Iex.Binop.arg2->Iex.Const.con->Ico.U64;
2033 if (0 == argHi && 0 == argLo) {
2034 e2 = IRExpr_Const(IRConst_V128(0));
2035 } else {
2036 goto unhandled;
2037 }
2038 break;
2039 }
sewardj9571dc02014-01-26 18:34:23 +00002040 /* Same reasoning for the 256-bit version. */
2041 case Iop_V128HLtoV256: {
2042 IRExpr* argHi = e->Iex.Binop.arg1;
2043 IRExpr* argLo = e->Iex.Binop.arg2;
2044 if (isZeroV128(argHi) && isZeroV128(argLo)) {
2045 e2 = IRExpr_Const(IRConst_V256(0));
2046 } else {
2047 goto unhandled;
2048 }
2049 break;
2050 }
sewardj4a0bee02012-06-29 14:44:44 +00002051
2052 /* -- V128 stuff -- */
2053 case Iop_InterleaveLO8x16: {
2054 /* This turns up a lot in Memcheck instrumentation of
2055 Icc generated code. I don't know why. */
2056 UShort arg1 = e->Iex.Binop.arg1->Iex.Const.con->Ico.V128;
2057 UShort arg2 = e->Iex.Binop.arg2->Iex.Const.con->Ico.V128;
2058 if (0 == arg1 && 0 == arg2) {
2059 e2 = IRExpr_Const(IRConst_V128(0));
2060 } else {
2061 goto unhandled;
2062 }
2063 break;
2064 }
sewardj855dc722005-02-17 09:26:05 +00002065
sewardj607dd4f2004-09-08 18:20:19 +00002066 default:
2067 goto unhandled;
sewardjd7217032004-08-19 10:49:10 +00002068 }
sewardjf6729012004-08-25 12:45:13 +00002069
sewardj84be7372004-08-18 13:59:33 +00002070 } else {
sewardjf6729012004-08-25 12:45:13 +00002071
sewardj84be7372004-08-18 13:59:33 +00002072 /* other cases (identities, etc) */
sewardj64d776c2010-10-01 14:06:22 +00002073 switch (e->Iex.Binop.op) {
florianf6402ab2012-01-29 02:19:43 +00002074
2075 case Iop_Shl32:
2076 case Iop_Shl64:
2077 case Iop_Shr64:
sewardjb979d7a2014-10-02 16:13:20 +00002078 case Iop_Sar64:
2079 /* Shl32/Shl64/Shr64/Sar64(x,0) ==> x */
florianf6402ab2012-01-29 02:19:43 +00002080 if (isZeroU(e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00002081 e2 = e->Iex.Binop.arg1;
florianf6402ab2012-01-29 02:19:43 +00002082 break;
2083 }
2084 /* Shl32/Shl64/Shr64(0,x) ==> 0 */
2085 if (isZeroU(e->Iex.Binop.arg1)) {
2086 e2 = e->Iex.Binop.arg1;
2087 break;
2088 }
sewardj64d776c2010-10-01 14:06:22 +00002089 break;
sewardjf6729012004-08-25 12:45:13 +00002090
sewardjb979d7a2014-10-02 16:13:20 +00002091 case Iop_Sar32:
florianf6402ab2012-01-29 02:19:43 +00002092 case Iop_Shr32:
sewardjb979d7a2014-10-02 16:13:20 +00002093 /* Shr32/Sar32(x,0) ==> x */
florianf6402ab2012-01-29 02:19:43 +00002094 if (isZeroU(e->Iex.Binop.arg2)) {
2095 e2 = e->Iex.Binop.arg1;
2096 break;
2097 }
2098 break;
2099
2100 case Iop_Or8:
2101 case Iop_Or16:
2102 case Iop_Or32:
2103 case Iop_Or64:
2104 case Iop_Max32U:
sewardjcf4be4a2012-03-26 09:44:39 +00002105 /* Or8/Or16/Or32/Or64/Max32U(x,0) ==> x */
florianf6402ab2012-01-29 02:19:43 +00002106 if (isZeroU(e->Iex.Binop.arg2)) {
2107 e2 = e->Iex.Binop.arg1;
2108 break;
2109 }
sewardjcf4be4a2012-03-26 09:44:39 +00002110 /* Or8/Or16/Or32/Or64/Max32U(0,x) ==> x */
florianf6402ab2012-01-29 02:19:43 +00002111 if (isZeroU(e->Iex.Binop.arg1)) {
2112 e2 = e->Iex.Binop.arg2;
2113 break;
2114 }
sewardjcf4be4a2012-03-26 09:44:39 +00002115 /* Or8/Or16/Or32/Or64/Max32U(x,1---1b) ==> 1---1b */
2116 /* Or8/Or16/Or32/Or64/Max32U(1---1b,x) ==> 1---1b */
2117 if (isOnesU(e->Iex.Binop.arg1) || isOnesU(e->Iex.Binop.arg2)) {
2118 e2 = mkOnesOfPrimopResultType(e->Iex.Binop.op);
2119 break;
2120 }
2121 /* Or8/Or16/Or32/Or64/Max32U(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002122 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002123 e2 = e->Iex.Binop.arg1;
2124 break;
2125 }
2126 break;
2127
2128 case Iop_Add8:
2129 /* Add8(t,t) ==> t << 1.
2130 Memcheck doesn't understand that
2131 x+x produces a defined least significant bit, and it seems
2132 simplest just to get rid of the problem by rewriting it
2133 out, since the opportunity to do so exists. */
floriancdb5fee2012-02-13 00:06:29 +00002134 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002135 e2 = IRExpr_Binop(Iop_Shl8, e->Iex.Binop.arg1,
2136 IRExpr_Const(IRConst_U8(1)));
2137 break;
2138 }
2139 break;
2140
2141 /* NB no Add16(t,t) case yet as no known test case exists */
2142
2143 case Iop_Add32:
2144 case Iop_Add64:
2145 /* Add32/Add64(x,0) ==> x */
2146 if (isZeroU(e->Iex.Binop.arg2)) {
2147 e2 = e->Iex.Binop.arg1;
2148 break;
2149 }
2150 /* Add32/Add64(0,x) ==> x */
2151 if (isZeroU(e->Iex.Binop.arg1)) {
2152 e2 = e->Iex.Binop.arg2;
2153 break;
2154 }
2155 /* Add32/Add64(t,t) ==> t << 1. Same rationale as for Add8. */
floriancdb5fee2012-02-13 00:06:29 +00002156 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj6399f812012-06-29 15:36:44 +00002157 e2 = IRExpr_Binop(
2158 e->Iex.Binop.op == Iop_Add32 ? Iop_Shl32 : Iop_Shl64,
2159 e->Iex.Binop.arg1, IRExpr_Const(IRConst_U8(1)));
florianf6402ab2012-01-29 02:19:43 +00002160 break;
2161 }
2162 break;
2163
sewardj1beb4332012-12-19 15:28:43 +00002164 case Iop_Sub32:
florianf6402ab2012-01-29 02:19:43 +00002165 case Iop_Sub64:
sewardj1beb4332012-12-19 15:28:43 +00002166 /* Sub32/Sub64(x,0) ==> x */
2167 if (isZeroU(e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002168 e2 = e->Iex.Binop.arg1;
2169 break;
2170 }
sewardj1beb4332012-12-19 15:28:43 +00002171 /* Sub32/Sub64(t,t) ==> 0, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002172 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00002173 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
florianf6402ab2012-01-29 02:19:43 +00002174 break;
2175 }
sewardj64d776c2010-10-01 14:06:22 +00002176 break;
sewardj36a911a2014-04-03 13:48:21 +00002177 case Iop_Sub8x16:
2178 /* Sub8x16(x,0) ==> x */
2179 if (isZeroV128(e->Iex.Binop.arg2)) {
2180 e2 = e->Iex.Binop.arg1;
2181 break;
2182 }
2183 break;
sewardj64d776c2010-10-01 14:06:22 +00002184
florian2782d212014-07-18 21:23:46 +00002185 case Iop_And8:
2186 case Iop_And16:
florianf6402ab2012-01-29 02:19:43 +00002187 case Iop_And32:
florian2782d212014-07-18 21:23:46 +00002188 case Iop_And64:
2189 /* And8/And16/And32/And64(x,1---1b) ==> x */
florian55ce7b72013-09-01 14:22:05 +00002190 if (isOnesU(e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002191 e2 = e->Iex.Binop.arg1;
2192 break;
2193 }
florian2782d212014-07-18 21:23:46 +00002194 /* And8/And16/And32/And64(1---1b,x) ==> x */
2195 if (isOnesU(e->Iex.Binop.arg1)) {
2196 e2 = e->Iex.Binop.arg2;
2197 break;
2198 }
2199 /* And8/And16/And32/And64(x,0) ==> 0 */
florian55ce7b72013-09-01 14:22:05 +00002200 if (isZeroU(e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002201 e2 = e->Iex.Binop.arg2;
2202 break;
2203 }
florian2782d212014-07-18 21:23:46 +00002204 /* And8/And16/And32/And64(0,x) ==> 0 */
florian55ce7b72013-09-01 14:22:05 +00002205 if (isZeroU(e->Iex.Binop.arg1)) {
florianf6402ab2012-01-29 02:19:43 +00002206 e2 = e->Iex.Binop.arg1;
2207 break;
2208 }
florian2782d212014-07-18 21:23:46 +00002209 /* And8/And16/And32/And64(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002210 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002211 e2 = e->Iex.Binop.arg1;
2212 break;
2213 }
2214 break;
2215
sewardj4a0bee02012-06-29 14:44:44 +00002216 case Iop_AndV128:
2217 case Iop_AndV256:
florian55ce7b72013-09-01 14:22:05 +00002218 /* And8/And16/AndV128/AndV256(t,t)
sewardj4a0bee02012-06-29 14:44:44 +00002219 ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002220 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002221 e2 = e->Iex.Binop.arg1;
2222 break;
2223 }
sewardj36a911a2014-04-03 13:48:21 +00002224 /* Deal with either arg zero. Could handle other And
2225 cases here too. */
florian1b7c4712014-07-16 20:17:49 +00002226 if (e->Iex.Binop.op == Iop_AndV256
2227 && (isZeroV256(e->Iex.Binop.arg1)
2228 || isZeroV256(e->Iex.Binop.arg2))) {
sewardjbbcf1882014-01-12 12:49:10 +00002229 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
2230 break;
sewardj36a911a2014-04-03 13:48:21 +00002231 } else if (e->Iex.Binop.op == Iop_AndV128
2232 && (isZeroV128(e->Iex.Binop.arg1)
2233 || isZeroV128(e->Iex.Binop.arg2))) {
2234 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
2235 break;
sewardjbbcf1882014-01-12 12:49:10 +00002236 }
florianf6402ab2012-01-29 02:19:43 +00002237 break;
2238
2239 case Iop_OrV128:
sewardj4a0bee02012-06-29 14:44:44 +00002240 case Iop_OrV256:
2241 /* V128/V256(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002242 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002243 e2 = e->Iex.Binop.arg1;
2244 break;
2245 }
sewardj9571dc02014-01-26 18:34:23 +00002246 /* OrV128(t,0) ==> t */
2247 if (e->Iex.Binop.op == Iop_OrV128) {
2248 if (isZeroV128(e->Iex.Binop.arg2)) {
2249 e2 = e->Iex.Binop.arg1;
2250 break;
2251 }
2252 if (isZeroV128(e->Iex.Binop.arg1)) {
2253 e2 = e->Iex.Binop.arg2;
2254 break;
2255 }
2256 }
2257 /* OrV256(t,0) ==> t */
2258 if (e->Iex.Binop.op == Iop_OrV256) {
2259 if (isZeroV256(e->Iex.Binop.arg2)) {
2260 e2 = e->Iex.Binop.arg1;
2261 break;
2262 }
2263 //Disabled because there's no known test case right now.
2264 //if (isZeroV256(e->Iex.Binop.arg1)) {
2265 // e2 = e->Iex.Binop.arg2;
2266 // break;
2267 //}
2268 }
florianf6402ab2012-01-29 02:19:43 +00002269 break;
2270
2271 case Iop_Xor8:
2272 case Iop_Xor16:
2273 case Iop_Xor32:
2274 case Iop_Xor64:
2275 case Iop_XorV128:
2276 /* Xor8/16/32/64/V128(t,t) ==> 0, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002277 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002278 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
2279 break;
2280 }
sewardjb01ff402014-08-04 08:09:23 +00002281 /* XorV128(t,0) ==> t */
2282 if (e->Iex.Binop.op == Iop_XorV128) {
2283 if (isZeroV128(e->Iex.Binop.arg2)) {
2284 e2 = e->Iex.Binop.arg1;
2285 break;
2286 }
2287 //Disabled because there's no known test case right now.
2288 //if (isZeroV128(e->Iex.Binop.arg1)) {
2289 // e2 = e->Iex.Binop.arg2;
2290 // break;
2291 //}
2292 }
florianf6402ab2012-01-29 02:19:43 +00002293 break;
2294
sewardja7e96382012-06-29 16:26:17 +00002295 case Iop_CmpNE32:
sewardj1beb4332012-12-19 15:28:43 +00002296 /* CmpNE32(t,t) ==> 0, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002297 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002298 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
2299 break;
2300 }
sewardj009230b2013-01-26 11:47:55 +00002301 /* CmpNE32(1Uto32(b), 0) ==> b */
2302 if (isZeroU32(e->Iex.Binop.arg2)) {
2303 IRExpr* a1 = chase(env, e->Iex.Binop.arg1);
2304 if (a1 && a1->tag == Iex_Unop
2305 && a1->Iex.Unop.op == Iop_1Uto32) {
2306 e2 = a1->Iex.Unop.arg;
2307 break;
2308 }
2309 }
florianf6402ab2012-01-29 02:19:43 +00002310 break;
2311
sewardja7e96382012-06-29 16:26:17 +00002312 case Iop_CmpEQ32:
sewardj64d776c2010-10-01 14:06:22 +00002313 case Iop_CmpEQ64:
2314 case Iop_CmpEQ8x8:
2315 case Iop_CmpEQ8x16:
sewardj899d1832012-07-10 21:41:01 +00002316 case Iop_CmpEQ16x8:
sewardjffccf2b2012-06-29 15:33:09 +00002317 case Iop_CmpEQ32x4:
floriancdb5fee2012-02-13 00:06:29 +00002318 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00002319 e2 = mkOnesOfPrimopResultType(e->Iex.Binop.op);
florianf6402ab2012-01-29 02:19:43 +00002320 break;
2321 }
sewardj64d776c2010-10-01 14:06:22 +00002322 break;
florianf6402ab2012-01-29 02:19:43 +00002323
sewardj64d776c2010-10-01 14:06:22 +00002324 default:
2325 break;
sewardj0033ddc2005-04-26 23:34:34 +00002326 }
sewardj84be7372004-08-18 13:59:33 +00002327 }
florian708417d2012-02-15 00:43:36 +00002328 break;
sewardj84be7372004-08-18 13:59:33 +00002329
florian99dd03e2013-01-29 03:56:06 +00002330 case Iex_ITE:
2331 /* ITE */
sewardj6c299f32009-12-31 18:00:12 +00002332 /* is the discriminant is a constant? */
florian99dd03e2013-01-29 03:56:06 +00002333 if (e->Iex.ITE.cond->tag == Iex_Const) {
sewardj6c299f32009-12-31 18:00:12 +00002334 /* assured us by the IR type rules */
florian99dd03e2013-01-29 03:56:06 +00002335 vassert(e->Iex.ITE.cond->Iex.Const.con->tag == Ico_U1);
2336 e2 = e->Iex.ITE.cond->Iex.Const.con->Ico.U1
2337 ? e->Iex.ITE.iftrue : e->Iex.ITE.iffalse;
sewardj6c299f32009-12-31 18:00:12 +00002338 }
2339 else
2340 /* are the arms identical? (pretty weedy test) */
florian99dd03e2013-01-29 03:56:06 +00002341 if (sameIRExprs(env, e->Iex.ITE.iftrue,
2342 e->Iex.ITE.iffalse)) {
2343 e2 = e->Iex.ITE.iffalse;
sewardj6c299f32009-12-31 18:00:12 +00002344 }
florian708417d2012-02-15 00:43:36 +00002345 break;
2346
2347 default:
2348 /* not considered */
2349 break;
sewardj84be7372004-08-18 13:59:33 +00002350 }
2351
sewardja7e96382012-06-29 16:26:17 +00002352 /* Show cases where we've found but not folded 'op(t,t)'. Be
2353 careful not to call sameIRExprs with values of different types,
2354 though, else it will assert (and so it should!). We can't
2355 conveniently call typeOfIRExpr on the two args without a whole
2356 bunch of extra plumbing to pass in a type env, so just use a
2357 hacky test to check the arguments are not anything that might
2358 sameIRExprs to assert. This is only OK because this kludge is
2359 only used for debug printing, not for "real" operation. For
2360 "real" operation (ie, all other calls to sameIRExprs), it is
2361 essential that the to args have the same type.
2362
2363 The "right" solution is to plumb the containing block's
2364 IRTypeEnv through to here and use typeOfIRExpr to be sure. But
2365 that's a bunch of extra parameter passing which will just slow
2366 down the normal case, for no purpose. */
2367 if (vex_control.iropt_verbosity > 0
2368 && e == e2
2369 && e->tag == Iex_Binop
2370 && !debug_only_hack_sameIRExprs_might_assert(e->Iex.Binop.arg1,
2371 e->Iex.Binop.arg2)
floriancdb5fee2012-02-13 00:06:29 +00002372 && sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj4a0bee02012-06-29 14:44:44 +00002373 vex_printf("vex iropt: fold_Expr: no ident rule for: ");
2374 ppIRExpr(e);
2375 vex_printf("\n");
sewardj64d776c2010-10-01 14:06:22 +00002376 }
2377
2378 /* Show the overall results of folding. */
sewardj088bcb42004-08-19 17:16:52 +00002379 if (DEBUG_IROPT && e2 != e) {
2380 vex_printf("FOLD: ");
sewardj84be7372004-08-18 13:59:33 +00002381 ppIRExpr(e); vex_printf(" -> ");
2382 ppIRExpr(e2); vex_printf("\n");
2383 }
2384
2385 return e2;
2386
2387 unhandled:
sewardj883b00b2004-09-11 09:30:24 +00002388# if 0
sewardj84be7372004-08-18 13:59:33 +00002389 vex_printf("\n\n");
2390 ppIRExpr(e);
2391 vpanic("fold_Expr: no rule for the above");
sewardj883b00b2004-09-11 09:30:24 +00002392# else
sewardj328b54b2005-06-13 16:30:18 +00002393 if (vex_control.iropt_verbosity > 0) {
sewardj4a0bee02012-06-29 14:44:44 +00002394 vex_printf("vex iropt: fold_Expr: no const rule for: ");
sewardj328b54b2005-06-13 16:30:18 +00002395 ppIRExpr(e);
2396 vex_printf("\n");
2397 }
sewardj883b00b2004-09-11 09:30:24 +00002398 return e2;
2399# endif
sewardj84be7372004-08-18 13:59:33 +00002400}
2401
2402
sewardj84be7372004-08-18 13:59:33 +00002403/* Apply the subst to a simple 1-level expression -- guaranteed to be
2404 1-level due to previous flattening pass. */
2405
sewardj62617ef2004-10-13 23:29:22 +00002406static IRExpr* subst_Expr ( IRExpr** env, IRExpr* ex )
sewardj84be7372004-08-18 13:59:33 +00002407{
sewardj62617ef2004-10-13 23:29:22 +00002408 switch (ex->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +00002409 case Iex_RdTmp:
2410 if (env[(Int)ex->Iex.RdTmp.tmp] != NULL) {
floriancdb5fee2012-02-13 00:06:29 +00002411 IRExpr *rhs = env[(Int)ex->Iex.RdTmp.tmp];
2412 if (rhs->tag == Iex_RdTmp)
2413 return rhs;
2414 if (rhs->tag == Iex_Const
2415 && rhs->Iex.Const.con->tag != Ico_F64i)
2416 return rhs;
sewardj62617ef2004-10-13 23:29:22 +00002417 }
floriancdb5fee2012-02-13 00:06:29 +00002418 /* not bound in env */
2419 return ex;
sewardj62617ef2004-10-13 23:29:22 +00002420
2421 case Iex_Const:
2422 case Iex_Get:
sewardj84be7372004-08-18 13:59:33 +00002423 return ex;
sewardj62617ef2004-10-13 23:29:22 +00002424
2425 case Iex_GetI:
sewardj496a58d2005-03-20 18:44:44 +00002426 vassert(isIRAtom(ex->Iex.GetI.ix));
sewardj62617ef2004-10-13 23:29:22 +00002427 return IRExpr_GetI(
2428 ex->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +00002429 subst_Expr(env, ex->Iex.GetI.ix),
sewardj62617ef2004-10-13 23:29:22 +00002430 ex->Iex.GetI.bias
2431 );
2432
florian96d7cc32012-06-01 20:41:24 +00002433 case Iex_Qop: {
2434 IRQop* qop = ex->Iex.Qop.details;
2435 vassert(isIRAtom(qop->arg1));
2436 vassert(isIRAtom(qop->arg2));
2437 vassert(isIRAtom(qop->arg3));
2438 vassert(isIRAtom(qop->arg4));
sewardj40c80262006-02-08 19:30:46 +00002439 return IRExpr_Qop(
florian96d7cc32012-06-01 20:41:24 +00002440 qop->op,
2441 subst_Expr(env, qop->arg1),
2442 subst_Expr(env, qop->arg2),
2443 subst_Expr(env, qop->arg3),
2444 subst_Expr(env, qop->arg4)
sewardj40c80262006-02-08 19:30:46 +00002445 );
florian96d7cc32012-06-01 20:41:24 +00002446 }
sewardj40c80262006-02-08 19:30:46 +00002447
florian420bfa92012-06-02 20:29:22 +00002448 case Iex_Triop: {
2449 IRTriop* triop = ex->Iex.Triop.details;
2450 vassert(isIRAtom(triop->arg1));
2451 vassert(isIRAtom(triop->arg2));
2452 vassert(isIRAtom(triop->arg3));
sewardjb183b852006-02-03 16:08:03 +00002453 return IRExpr_Triop(
florian420bfa92012-06-02 20:29:22 +00002454 triop->op,
2455 subst_Expr(env, triop->arg1),
2456 subst_Expr(env, triop->arg2),
2457 subst_Expr(env, triop->arg3)
sewardjb183b852006-02-03 16:08:03 +00002458 );
florian420bfa92012-06-02 20:29:22 +00002459 }
sewardjb183b852006-02-03 16:08:03 +00002460
sewardj62617ef2004-10-13 23:29:22 +00002461 case Iex_Binop:
sewardj496a58d2005-03-20 18:44:44 +00002462 vassert(isIRAtom(ex->Iex.Binop.arg1));
2463 vassert(isIRAtom(ex->Iex.Binop.arg2));
sewardj62617ef2004-10-13 23:29:22 +00002464 return IRExpr_Binop(
2465 ex->Iex.Binop.op,
2466 subst_Expr(env, ex->Iex.Binop.arg1),
2467 subst_Expr(env, ex->Iex.Binop.arg2)
2468 );
2469
2470 case Iex_Unop:
sewardj496a58d2005-03-20 18:44:44 +00002471 vassert(isIRAtom(ex->Iex.Unop.arg));
sewardj62617ef2004-10-13 23:29:22 +00002472 return IRExpr_Unop(
2473 ex->Iex.Unop.op,
2474 subst_Expr(env, ex->Iex.Unop.arg)
2475 );
2476
sewardjaf1ceca2005-06-30 23:31:27 +00002477 case Iex_Load:
2478 vassert(isIRAtom(ex->Iex.Load.addr));
2479 return IRExpr_Load(
2480 ex->Iex.Load.end,
2481 ex->Iex.Load.ty,
2482 subst_Expr(env, ex->Iex.Load.addr)
sewardj62617ef2004-10-13 23:29:22 +00002483 );
2484
2485 case Iex_CCall: {
2486 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +00002487 IRExpr** args2 = shallowCopyIRExprVec(ex->Iex.CCall.args);
sewardj62617ef2004-10-13 23:29:22 +00002488 for (i = 0; args2[i]; i++) {
sewardj496a58d2005-03-20 18:44:44 +00002489 vassert(isIRAtom(args2[i]));
sewardj62617ef2004-10-13 23:29:22 +00002490 args2[i] = subst_Expr(env, args2[i]);
2491 }
2492 return IRExpr_CCall(
sewardj8ea867b2004-10-30 19:03:02 +00002493 ex->Iex.CCall.cee,
sewardj62617ef2004-10-13 23:29:22 +00002494 ex->Iex.CCall.retty,
2495 args2
2496 );
sewardj84be7372004-08-18 13:59:33 +00002497 }
sewardj62617ef2004-10-13 23:29:22 +00002498
florian99dd03e2013-01-29 03:56:06 +00002499 case Iex_ITE:
2500 vassert(isIRAtom(ex->Iex.ITE.cond));
2501 vassert(isIRAtom(ex->Iex.ITE.iftrue));
2502 vassert(isIRAtom(ex->Iex.ITE.iffalse));
2503 return IRExpr_ITE(
2504 subst_Expr(env, ex->Iex.ITE.cond),
2505 subst_Expr(env, ex->Iex.ITE.iftrue),
2506 subst_Expr(env, ex->Iex.ITE.iffalse)
sewardj62617ef2004-10-13 23:29:22 +00002507 );
2508
2509 default:
2510 vex_printf("\n\n"); ppIRExpr(ex);
2511 vpanic("subst_Expr");
2512
sewardj84be7372004-08-18 13:59:33 +00002513 }
sewardj84be7372004-08-18 13:59:33 +00002514}
2515
2516
2517/* Apply the subst to stmt, then fold the result as much as possible.
sewardjd2445f62005-03-21 00:15:53 +00002518 Much simplified due to stmt being previously flattened. As a
2519 result of this, the stmt may wind up being turned into a no-op.
2520*/
sewardj62617ef2004-10-13 23:29:22 +00002521static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st )
sewardj84be7372004-08-18 13:59:33 +00002522{
2523# if 0
2524 vex_printf("\nsubst and fold stmt\n");
2525 ppIRStmt(st);
2526 vex_printf("\n");
2527# endif
2528
sewardj62617ef2004-10-13 23:29:22 +00002529 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00002530 case Ist_AbiHint:
2531 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +00002532 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +00002533 return IRStmt_AbiHint(
floriancdb5fee2012-02-13 00:06:29 +00002534 fold_Expr(env, subst_Expr(env, st->Ist.AbiHint.base)),
sewardj478646f2008-05-01 20:13:04 +00002535 st->Ist.AbiHint.len,
floriancdb5fee2012-02-13 00:06:29 +00002536 fold_Expr(env, subst_Expr(env, st->Ist.AbiHint.nia))
sewardj5a9ffab2005-05-12 17:55:01 +00002537 );
sewardj62617ef2004-10-13 23:29:22 +00002538 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00002539 vassert(isIRAtom(st->Ist.Put.data));
sewardj62617ef2004-10-13 23:29:22 +00002540 return IRStmt_Put(
2541 st->Ist.Put.offset,
floriancdb5fee2012-02-13 00:06:29 +00002542 fold_Expr(env, subst_Expr(env, st->Ist.Put.data))
sewardj62617ef2004-10-13 23:29:22 +00002543 );
sewardj84be7372004-08-18 13:59:33 +00002544
floriand6f38b32012-05-31 15:46:18 +00002545 case Ist_PutI: {
2546 IRPutI *puti, *puti2;
2547 puti = st->Ist.PutI.details;
2548 vassert(isIRAtom(puti->ix));
2549 vassert(isIRAtom(puti->data));
2550 puti2 = mkIRPutI(puti->descr,
2551 fold_Expr(env, subst_Expr(env, puti->ix)),
2552 puti->bias,
2553 fold_Expr(env, subst_Expr(env, puti->data)));
2554 return IRStmt_PutI(puti2);
2555 }
sewardjd7217032004-08-19 10:49:10 +00002556
sewardjdd40fdf2006-12-24 02:20:24 +00002557 case Ist_WrTmp:
2558 /* This is the one place where an expr (st->Ist.WrTmp.data) is
sewardj62617ef2004-10-13 23:29:22 +00002559 allowed to be more than just a constant or a tmp. */
sewardjdd40fdf2006-12-24 02:20:24 +00002560 return IRStmt_WrTmp(
2561 st->Ist.WrTmp.tmp,
floriancdb5fee2012-02-13 00:06:29 +00002562 fold_Expr(env, subst_Expr(env, st->Ist.WrTmp.data))
sewardj62617ef2004-10-13 23:29:22 +00002563 );
sewardj84be7372004-08-18 13:59:33 +00002564
sewardjaf1ceca2005-06-30 23:31:27 +00002565 case Ist_Store:
2566 vassert(isIRAtom(st->Ist.Store.addr));
2567 vassert(isIRAtom(st->Ist.Store.data));
2568 return IRStmt_Store(
2569 st->Ist.Store.end,
floriancdb5fee2012-02-13 00:06:29 +00002570 fold_Expr(env, subst_Expr(env, st->Ist.Store.addr)),
2571 fold_Expr(env, subst_Expr(env, st->Ist.Store.data))
sewardj62617ef2004-10-13 23:29:22 +00002572 );
sewardj84be7372004-08-18 13:59:33 +00002573
sewardjcfe046e2013-01-17 14:23:53 +00002574 case Ist_StoreG: {
2575 IRStoreG* sg = st->Ist.StoreG.details;
2576 vassert(isIRAtom(sg->addr));
2577 vassert(isIRAtom(sg->data));
2578 vassert(isIRAtom(sg->guard));
2579 IRExpr* faddr = fold_Expr(env, subst_Expr(env, sg->addr));
2580 IRExpr* fdata = fold_Expr(env, subst_Expr(env, sg->data));
2581 IRExpr* fguard = fold_Expr(env, subst_Expr(env, sg->guard));
2582 if (fguard->tag == Iex_Const) {
2583 /* The condition on this store has folded down to a constant. */
2584 vassert(fguard->Iex.Const.con->tag == Ico_U1);
2585 if (fguard->Iex.Const.con->Ico.U1 == False) {
2586 return IRStmt_NoOp();
2587 } else {
2588 vassert(fguard->Iex.Const.con->Ico.U1 == True);
2589 return IRStmt_Store(sg->end, faddr, fdata);
2590 }
2591 }
2592 return IRStmt_StoreG(sg->end, faddr, fdata, fguard);
2593 }
2594
2595 case Ist_LoadG: {
2596 /* This is complicated. If the guard folds down to 'false',
2597 we can replace it with an assignment 'dst := alt', but if
2598 the guard folds down to 'true', we can't conveniently
2599 replace it with an unconditional load, because doing so
2600 requires generating a new temporary, and that is not easy
2601 to do at this point. */
2602 IRLoadG* lg = st->Ist.LoadG.details;
2603 vassert(isIRAtom(lg->addr));
2604 vassert(isIRAtom(lg->alt));
2605 vassert(isIRAtom(lg->guard));
2606 IRExpr* faddr = fold_Expr(env, subst_Expr(env, lg->addr));
2607 IRExpr* falt = fold_Expr(env, subst_Expr(env, lg->alt));
2608 IRExpr* fguard = fold_Expr(env, subst_Expr(env, lg->guard));
2609 if (fguard->tag == Iex_Const) {
2610 /* The condition on this load has folded down to a constant. */
2611 vassert(fguard->Iex.Const.con->tag == Ico_U1);
2612 if (fguard->Iex.Const.con->Ico.U1 == False) {
2613 /* The load is not going to happen -- instead 'alt' is
2614 assigned to 'dst'. */
2615 return IRStmt_WrTmp(lg->dst, falt);
2616 } else {
2617 vassert(fguard->Iex.Const.con->Ico.U1 == True);
2618 /* The load is always going to happen. We want to
2619 convert to an unconditional load and assign to 'dst'
2620 (IRStmt_WrTmp). Problem is we need an extra temp to
2621 hold the loaded value, but none is available.
2622 Instead, reconstitute the conditional load (with
2623 folded args, of course) and let the caller of this
2624 routine deal with the problem. */
2625 }
2626 }
2627 return IRStmt_LoadG(lg->end, lg->cvt, lg->dst, faddr, falt, fguard);
2628 }
2629
sewardje9d8a262009-07-01 08:06:34 +00002630 case Ist_CAS: {
2631 IRCAS *cas, *cas2;
2632 cas = st->Ist.CAS.details;
2633 vassert(isIRAtom(cas->addr));
2634 vassert(cas->expdHi == NULL || isIRAtom(cas->expdHi));
2635 vassert(isIRAtom(cas->expdLo));
2636 vassert(cas->dataHi == NULL || isIRAtom(cas->dataHi));
2637 vassert(isIRAtom(cas->dataLo));
2638 cas2 = mkIRCAS(
2639 cas->oldHi, cas->oldLo, cas->end,
floriancdb5fee2012-02-13 00:06:29 +00002640 fold_Expr(env, subst_Expr(env, cas->addr)),
sewardj6399f812012-06-29 15:36:44 +00002641 cas->expdHi ? fold_Expr(env, subst_Expr(env, cas->expdHi))
2642 : NULL,
floriancdb5fee2012-02-13 00:06:29 +00002643 fold_Expr(env, subst_Expr(env, cas->expdLo)),
sewardj6399f812012-06-29 15:36:44 +00002644 cas->dataHi ? fold_Expr(env, subst_Expr(env, cas->dataHi))
2645 : NULL,
floriancdb5fee2012-02-13 00:06:29 +00002646 fold_Expr(env, subst_Expr(env, cas->dataLo))
sewardje9d8a262009-07-01 08:06:34 +00002647 );
2648 return IRStmt_CAS(cas2);
2649 }
2650
sewardje768e922009-11-26 17:17:37 +00002651 case Ist_LLSC:
2652 vassert(isIRAtom(st->Ist.LLSC.addr));
2653 if (st->Ist.LLSC.storedata)
2654 vassert(isIRAtom(st->Ist.LLSC.storedata));
2655 return IRStmt_LLSC(
2656 st->Ist.LLSC.end,
2657 st->Ist.LLSC.result,
floriancdb5fee2012-02-13 00:06:29 +00002658 fold_Expr(env, subst_Expr(env, st->Ist.LLSC.addr)),
sewardje768e922009-11-26 17:17:37 +00002659 st->Ist.LLSC.storedata
floriancdb5fee2012-02-13 00:06:29 +00002660 ? fold_Expr(env, subst_Expr(env, st->Ist.LLSC.storedata))
sewardje768e922009-11-26 17:17:37 +00002661 : NULL
2662 );
2663
sewardj62617ef2004-10-13 23:29:22 +00002664 case Ist_Dirty: {
2665 Int i;
2666 IRDirty *d, *d2;
2667 d = st->Ist.Dirty.details;
2668 d2 = emptyIRDirty();
2669 *d2 = *d;
sewardjdd40fdf2006-12-24 02:20:24 +00002670 d2->args = shallowCopyIRExprVec(d2->args);
sewardj62617ef2004-10-13 23:29:22 +00002671 if (d2->mFx != Ifx_None) {
sewardj496a58d2005-03-20 18:44:44 +00002672 vassert(isIRAtom(d2->mAddr));
floriancdb5fee2012-02-13 00:06:29 +00002673 d2->mAddr = fold_Expr(env, subst_Expr(env, d2->mAddr));
sewardjb8e75862004-08-19 17:58:45 +00002674 }
sewardj496a58d2005-03-20 18:44:44 +00002675 vassert(isIRAtom(d2->guard));
floriancdb5fee2012-02-13 00:06:29 +00002676 d2->guard = fold_Expr(env, subst_Expr(env, d2->guard));
sewardj62617ef2004-10-13 23:29:22 +00002677 for (i = 0; d2->args[i]; i++) {
sewardj74142b82013-08-08 10:28:59 +00002678 IRExpr* arg = d2->args[i];
florian90419562013-08-15 20:54:52 +00002679 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg))) {
sewardj74142b82013-08-08 10:28:59 +00002680 vassert(isIRAtom(arg));
2681 d2->args[i] = fold_Expr(env, subst_Expr(env, arg));
2682 }
sewardj62617ef2004-10-13 23:29:22 +00002683 }
2684 return IRStmt_Dirty(d2);
sewardjb8e75862004-08-19 17:58:45 +00002685 }
sewardj84be7372004-08-18 13:59:33 +00002686
sewardjf1689312005-03-16 18:19:10 +00002687 case Ist_IMark:
sewardj2f10aa62011-05-27 13:20:56 +00002688 return IRStmt_IMark(st->Ist.IMark.addr,
2689 st->Ist.IMark.len,
2690 st->Ist.IMark.delta);
sewardjf1689312005-03-16 18:19:10 +00002691
sewardjd2445f62005-03-21 00:15:53 +00002692 case Ist_NoOp:
2693 return IRStmt_NoOp();
2694
sewardjc4356f02007-11-09 21:15:04 +00002695 case Ist_MBE:
2696 return IRStmt_MBE(st->Ist.MBE.event);
sewardj3e838932005-01-07 12:09:15 +00002697
sewardj62617ef2004-10-13 23:29:22 +00002698 case Ist_Exit: {
2699 IRExpr* fcond;
sewardj496a58d2005-03-20 18:44:44 +00002700 vassert(isIRAtom(st->Ist.Exit.guard));
floriancdb5fee2012-02-13 00:06:29 +00002701 fcond = fold_Expr(env, subst_Expr(env, st->Ist.Exit.guard));
sewardj62617ef2004-10-13 23:29:22 +00002702 if (fcond->tag == Iex_Const) {
2703 /* Interesting. The condition on this exit has folded down to
2704 a constant. */
sewardjba999312004-11-15 15:21:17 +00002705 vassert(fcond->Iex.Const.con->tag == Ico_U1);
2706 if (fcond->Iex.Const.con->Ico.U1 == False) {
sewardj62617ef2004-10-13 23:29:22 +00002707 /* exit is never going to happen, so dump the statement. */
sewardjd2445f62005-03-21 00:15:53 +00002708 return IRStmt_NoOp();
sewardj62617ef2004-10-13 23:29:22 +00002709 } else {
sewardjba999312004-11-15 15:21:17 +00002710 vassert(fcond->Iex.Const.con->Ico.U1 == True);
sewardje810c192005-09-09 08:33:03 +00002711 /* Hmmm. The exit has become unconditional. Leave it
2712 as it is for now, since we'd have to truncate the BB
2713 at this point, which is tricky. Such truncation is
2714 done later by the dead-code elimination pass. */
sewardj62617ef2004-10-13 23:29:22 +00002715 /* fall out into the reconstruct-the-exit code. */
sewardj08613742004-10-25 13:01:45 +00002716 if (vex_control.iropt_verbosity > 0)
2717 /* really a misuse of vex_control.iropt_verbosity */
sewardj8c2c10b2004-10-16 20:51:52 +00002718 vex_printf("vex iropt: IRStmt_Exit became unconditional\n");
sewardj62617ef2004-10-13 23:29:22 +00002719 }
2720 }
sewardjc6f970f2012-04-02 21:54:49 +00002721 return IRStmt_Exit(fcond, st->Ist.Exit.jk,
2722 st->Ist.Exit.dst, st->Ist.Exit.offsIP);
sewardj62617ef2004-10-13 23:29:22 +00002723 }
2724
2725 default:
2726 vex_printf("\n"); ppIRStmt(st);
2727 vpanic("subst_and_fold_Stmt");
2728 }
sewardj84be7372004-08-18 13:59:33 +00002729}
2730
2731
sewardjdd40fdf2006-12-24 02:20:24 +00002732IRSB* cprop_BB ( IRSB* in )
sewardj84be7372004-08-18 13:59:33 +00002733{
sewardj62617ef2004-10-13 23:29:22 +00002734 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +00002735 IRSB* out;
sewardj62617ef2004-10-13 23:29:22 +00002736 IRStmt* st2;
2737 Int n_tmps = in->tyenv->types_used;
2738 IRExpr** env = LibVEX_Alloc(n_tmps * sizeof(IRExpr*));
sewardjcfe046e2013-01-17 14:23:53 +00002739 /* Keep track of IRStmt_LoadGs that we need to revisit after
2740 processing all the other statements. */
2741 const Int N_FIXUPS = 16;
2742 Int fixups[N_FIXUPS]; /* indices in the stmt array of 'out' */
2743 Int n_fixups = 0;
sewardj84be7372004-08-18 13:59:33 +00002744
sewardjdd40fdf2006-12-24 02:20:24 +00002745 out = emptyIRSB();
2746 out->tyenv = deepCopyIRTypeEnv( in->tyenv );
sewardj84be7372004-08-18 13:59:33 +00002747
2748 /* Set up the env with which travels forward. This holds a
floriancdb5fee2012-02-13 00:06:29 +00002749 substitution, mapping IRTemps to IRExprs. The environment
2750 is to be applied as we move along. Keys are IRTemps.
2751 Values are IRExpr*s.
sewardj84be7372004-08-18 13:59:33 +00002752 */
sewardj62617ef2004-10-13 23:29:22 +00002753 for (i = 0; i < n_tmps; i++)
2754 env[i] = NULL;
sewardj84be7372004-08-18 13:59:33 +00002755
2756 /* For each original SSA-form stmt ... */
2757 for (i = 0; i < in->stmts_used; i++) {
2758
2759 /* First apply the substitution to the current stmt. This
2760 propagates in any constants and tmp-tmp assignments
2761 accumulated prior to this point. As part of the subst_Stmt
2762 call, also then fold any constant expressions resulting. */
2763
sewardjf0e43162004-08-20 00:11:12 +00002764 st2 = in->stmts[i];
2765
2766 /* perhaps st2 is already a no-op? */
sewardj8bee6d12005-03-22 02:24:05 +00002767 if (st2->tag == Ist_NoOp) continue;
sewardjf0e43162004-08-20 00:11:12 +00002768
2769 st2 = subst_and_fold_Stmt( env, st2 );
sewardj84be7372004-08-18 13:59:33 +00002770
sewardjcfe046e2013-01-17 14:23:53 +00002771 /* Deal with some post-folding special cases. */
2772 switch (st2->tag) {
sewardjb8e75862004-08-19 17:58:45 +00002773
sewardjcfe046e2013-01-17 14:23:53 +00002774 /* If the statement has been folded into a no-op, forget
2775 it. */
2776 case Ist_NoOp:
2777 continue;
sewardj84be7372004-08-18 13:59:33 +00002778
sewardjcfe046e2013-01-17 14:23:53 +00002779 /* If the statement assigns to an IRTemp add it to the
2780 running environment. This is for the benefit of copy
2781 propagation and to allow sameIRExpr look through
2782 IRTemps. */
2783 case Ist_WrTmp: {
2784 vassert(env[(Int)(st2->Ist.WrTmp.tmp)] == NULL);
2785 env[(Int)(st2->Ist.WrTmp.tmp)] = st2->Ist.WrTmp.data;
floriancdb5fee2012-02-13 00:06:29 +00002786
sewardjcfe046e2013-01-17 14:23:53 +00002787 /* 't1 = t2' -- don't add to BB; will be optimized out */
2788 if (st2->Ist.WrTmp.data->tag == Iex_RdTmp)
2789 continue;
2790
2791 /* 't = const' && 'const != F64i' -- don't add to BB
2792 Note, we choose not to propagate const when const is an
2793 F64i, so that F64i literals can be CSE'd later. This
2794 helps x86 floating point code generation. */
2795 if (st2->Ist.WrTmp.data->tag == Iex_Const
2796 && st2->Ist.WrTmp.data->Iex.Const.con->tag != Ico_F64i) {
2797 continue;
2798 }
2799 /* else add it to the output, as normal */
2800 break;
2801 }
2802
2803 case Ist_LoadG: {
2804 IRLoadG* lg = st2->Ist.LoadG.details;
2805 IRExpr* guard = lg->guard;
2806 if (guard->tag == Iex_Const) {
2807 /* The guard has folded to a constant, and that
2808 constant must be 1:I1, since subst_and_fold_Stmt
2809 folds out the case 0:I1 by itself. */
2810 vassert(guard->Iex.Const.con->tag == Ico_U1);
2811 vassert(guard->Iex.Const.con->Ico.U1 == True);
2812 /* Add a NoOp here as a placeholder, and make a note of
2813 where it is in the output block. Afterwards we'll
2814 come back here and transform the NoOp and the LoadG
2815 into a load-convert pair. The fixups[] entry
2816 refers to the inserted NoOp, and we expect to find
2817 the relevant LoadG immediately after it. */
2818 vassert(n_fixups >= 0 && n_fixups <= N_FIXUPS);
2819 if (n_fixups < N_FIXUPS) {
2820 fixups[n_fixups++] = out->stmts_used;
2821 addStmtToIRSB( out, IRStmt_NoOp() );
2822 }
2823 }
2824 /* And always add the LoadG to the output, regardless. */
2825 break;
2826 }
2827
2828 default:
2829 break;
sewardj84be7372004-08-18 13:59:33 +00002830 }
floriancdb5fee2012-02-13 00:06:29 +00002831
2832 /* Not interesting, copy st2 into the output block. */
2833 addStmtToIRSB( out, st2 );
sewardj84be7372004-08-18 13:59:33 +00002834 }
2835
sewardjcfe046e2013-01-17 14:23:53 +00002836# if STATS_IROPT
floriancdb5fee2012-02-13 00:06:29 +00002837 vex_printf("sameIRExpr: invoked = %u/%u equal = %u/%u max_nodes = %u\n",
2838 invocation_count, recursion_count, success_count,
2839 recursion_success_count, max_nodes_visited);
sewardjcfe046e2013-01-17 14:23:53 +00002840# endif
floriancdb5fee2012-02-13 00:06:29 +00002841
sewardj84be7372004-08-18 13:59:33 +00002842 out->next = subst_Expr( env, in->next );
2843 out->jumpkind = in->jumpkind;
sewardjc6f970f2012-04-02 21:54:49 +00002844 out->offsIP = in->offsIP;
sewardjcfe046e2013-01-17 14:23:53 +00002845
2846 /* Process any leftover unconditional LoadGs that we noticed
2847 in the main pass. */
2848 vassert(n_fixups >= 0 && n_fixups <= N_FIXUPS);
2849 for (i = 0; i < n_fixups; i++) {
2850 Int ix = fixups[i];
2851 /* Carefully verify that the LoadG has the expected form. */
2852 vassert(ix >= 0 && ix+1 < out->stmts_used);
2853 IRStmt* nop = out->stmts[ix];
2854 IRStmt* lgu = out->stmts[ix+1];
2855 vassert(nop->tag == Ist_NoOp);
2856 vassert(lgu->tag == Ist_LoadG);
2857 IRLoadG* lg = lgu->Ist.LoadG.details;
2858 IRExpr* guard = lg->guard;
2859 vassert(guard->Iex.Const.con->tag == Ico_U1);
2860 vassert(guard->Iex.Const.con->Ico.U1 == True);
2861 /* Figure out the load and result types, and the implied
2862 conversion operation. */
2863 IRType cvtRes = Ity_INVALID, cvtArg = Ity_INVALID;
2864 typeOfIRLoadGOp(lg->cvt, &cvtRes, &cvtArg);
2865 IROp cvtOp = Iop_INVALID;
2866 switch (lg->cvt) {
2867 case ILGop_Ident32: break;
2868 case ILGop_8Uto32: cvtOp = Iop_8Uto32; break;
2869 case ILGop_8Sto32: cvtOp = Iop_8Sto32; break;
2870 case ILGop_16Uto32: cvtOp = Iop_16Uto32; break;
2871 case ILGop_16Sto32: cvtOp = Iop_16Sto32; break;
2872 default: vpanic("cprop_BB: unhandled ILGOp");
2873 }
2874 /* Replace the placeholder NoOp by the required unconditional
2875 load. */
2876 IRTemp tLoaded = newIRTemp(out->tyenv, cvtArg);
2877 out->stmts[ix]
2878 = IRStmt_WrTmp(tLoaded,
2879 IRExpr_Load(lg->end, cvtArg, lg->addr));
2880 /* Replace the LoadG by a conversion from the loaded value's
2881 type to the required result type. */
2882 out->stmts[ix+1]
2883 = IRStmt_WrTmp(
2884 lg->dst, cvtOp == Iop_INVALID
2885 ? IRExpr_RdTmp(tLoaded)
2886 : IRExpr_Unop(cvtOp, IRExpr_RdTmp(tLoaded)));
2887 }
2888
sewardj84be7372004-08-18 13:59:33 +00002889 return out;
2890}
2891
2892
sewardjedf4d692004-08-17 13:52:58 +00002893/*---------------------------------------------------------------*/
sewardj39e3f242004-08-18 16:54:52 +00002894/*--- Dead code (t = E) removal ---*/
2895/*---------------------------------------------------------------*/
2896
sewardje810c192005-09-09 08:33:03 +00002897/* As a side effect, also removes all code following an unconditional
2898 side exit. */
2899
sewardjea602bc2004-10-14 21:40:12 +00002900/* The type of the HashHW map is: a map from IRTemp to nothing
sewardj39e3f242004-08-18 16:54:52 +00002901 -- really just operating a set or IRTemps.
2902*/
2903
sewardjd503a322004-10-13 22:41:16 +00002904inline
2905static void addUses_Temp ( Bool* set, IRTemp tmp )
sewardj17442fe2004-09-20 14:54:28 +00002906{
sewardjd503a322004-10-13 22:41:16 +00002907 set[(Int)tmp] = True;
sewardj17442fe2004-09-20 14:54:28 +00002908}
2909
sewardjd503a322004-10-13 22:41:16 +00002910static void addUses_Expr ( Bool* set, IRExpr* e )
sewardj39e3f242004-08-18 16:54:52 +00002911{
2912 Int i;
2913 switch (e->tag) {
sewardjd7217032004-08-19 10:49:10 +00002914 case Iex_GetI:
sewardjeeac8412004-11-02 00:26:55 +00002915 addUses_Expr(set, e->Iex.GetI.ix);
sewardjd7217032004-08-19 10:49:10 +00002916 return;
florian99dd03e2013-01-29 03:56:06 +00002917 case Iex_ITE:
2918 addUses_Expr(set, e->Iex.ITE.cond);
2919 addUses_Expr(set, e->Iex.ITE.iftrue);
2920 addUses_Expr(set, e->Iex.ITE.iffalse);
sewardj39e3f242004-08-18 16:54:52 +00002921 return;
2922 case Iex_CCall:
2923 for (i = 0; e->Iex.CCall.args[i]; i++)
2924 addUses_Expr(set, e->Iex.CCall.args[i]);
2925 return;
sewardjaf1ceca2005-06-30 23:31:27 +00002926 case Iex_Load:
2927 addUses_Expr(set, e->Iex.Load.addr);
sewardj39e3f242004-08-18 16:54:52 +00002928 return;
sewardj40c80262006-02-08 19:30:46 +00002929 case Iex_Qop:
florian96d7cc32012-06-01 20:41:24 +00002930 addUses_Expr(set, e->Iex.Qop.details->arg1);
2931 addUses_Expr(set, e->Iex.Qop.details->arg2);
2932 addUses_Expr(set, e->Iex.Qop.details->arg3);
2933 addUses_Expr(set, e->Iex.Qop.details->arg4);
sewardj40c80262006-02-08 19:30:46 +00002934 return;
sewardjb183b852006-02-03 16:08:03 +00002935 case Iex_Triop:
florian420bfa92012-06-02 20:29:22 +00002936 addUses_Expr(set, e->Iex.Triop.details->arg1);
2937 addUses_Expr(set, e->Iex.Triop.details->arg2);
2938 addUses_Expr(set, e->Iex.Triop.details->arg3);
sewardjb183b852006-02-03 16:08:03 +00002939 return;
sewardj39e3f242004-08-18 16:54:52 +00002940 case Iex_Binop:
2941 addUses_Expr(set, e->Iex.Binop.arg1);
2942 addUses_Expr(set, e->Iex.Binop.arg2);
2943 return;
2944 case Iex_Unop:
2945 addUses_Expr(set, e->Iex.Unop.arg);
2946 return;
sewardjdd40fdf2006-12-24 02:20:24 +00002947 case Iex_RdTmp:
2948 addUses_Temp(set, e->Iex.RdTmp.tmp);
sewardj39e3f242004-08-18 16:54:52 +00002949 return;
2950 case Iex_Const:
2951 case Iex_Get:
2952 return;
2953 default:
2954 vex_printf("\n");
2955 ppIRExpr(e);
2956 vpanic("addUses_Expr");
2957 }
2958}
2959
sewardjd503a322004-10-13 22:41:16 +00002960static void addUses_Stmt ( Bool* set, IRStmt* st )
sewardj39e3f242004-08-18 16:54:52 +00002961{
sewardj17442fe2004-09-20 14:54:28 +00002962 Int i;
2963 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00002964 IRCAS* cas;
sewardj39e3f242004-08-18 16:54:52 +00002965 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00002966 case Ist_AbiHint:
2967 addUses_Expr(set, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +00002968 addUses_Expr(set, st->Ist.AbiHint.nia);
sewardj5a9ffab2005-05-12 17:55:01 +00002969 return;
sewardjd7217032004-08-19 10:49:10 +00002970 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +00002971 addUses_Expr(set, st->Ist.PutI.details->ix);
2972 addUses_Expr(set, st->Ist.PutI.details->data);
sewardjd7217032004-08-19 10:49:10 +00002973 return;
sewardjdd40fdf2006-12-24 02:20:24 +00002974 case Ist_WrTmp:
2975 addUses_Expr(set, st->Ist.WrTmp.data);
sewardj39e3f242004-08-18 16:54:52 +00002976 return;
2977 case Ist_Put:
sewardj6d076362004-09-23 11:06:17 +00002978 addUses_Expr(set, st->Ist.Put.data);
sewardj39e3f242004-08-18 16:54:52 +00002979 return;
sewardjaf1ceca2005-06-30 23:31:27 +00002980 case Ist_Store:
2981 addUses_Expr(set, st->Ist.Store.addr);
2982 addUses_Expr(set, st->Ist.Store.data);
sewardj39e3f242004-08-18 16:54:52 +00002983 return;
sewardjcfe046e2013-01-17 14:23:53 +00002984 case Ist_StoreG: {
2985 IRStoreG* sg = st->Ist.StoreG.details;
2986 addUses_Expr(set, sg->addr);
2987 addUses_Expr(set, sg->data);
2988 addUses_Expr(set, sg->guard);
2989 return;
2990 }
2991 case Ist_LoadG: {
2992 IRLoadG* lg = st->Ist.LoadG.details;
2993 addUses_Expr(set, lg->addr);
2994 addUses_Expr(set, lg->alt);
2995 addUses_Expr(set, lg->guard);
2996 return;
2997 }
sewardje9d8a262009-07-01 08:06:34 +00002998 case Ist_CAS:
2999 cas = st->Ist.CAS.details;
3000 addUses_Expr(set, cas->addr);
3001 if (cas->expdHi)
3002 addUses_Expr(set, cas->expdHi);
3003 addUses_Expr(set, cas->expdLo);
3004 if (cas->dataHi)
3005 addUses_Expr(set, cas->dataHi);
3006 addUses_Expr(set, cas->dataLo);
3007 return;
sewardje768e922009-11-26 17:17:37 +00003008 case Ist_LLSC:
3009 addUses_Expr(set, st->Ist.LLSC.addr);
3010 if (st->Ist.LLSC.storedata)
3011 addUses_Expr(set, st->Ist.LLSC.storedata);
3012 return;
sewardj17442fe2004-09-20 14:54:28 +00003013 case Ist_Dirty:
3014 d = st->Ist.Dirty.details;
3015 if (d->mFx != Ifx_None)
3016 addUses_Expr(set, d->mAddr);
sewardjb8385d82004-11-02 01:34:15 +00003017 addUses_Expr(set, d->guard);
sewardj74142b82013-08-08 10:28:59 +00003018 for (i = 0; d->args[i] != NULL; i++) {
3019 IRExpr* arg = d->args[i];
florian90419562013-08-15 20:54:52 +00003020 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +00003021 addUses_Expr(set, arg);
3022 }
sewardj17442fe2004-09-20 14:54:28 +00003023 return;
sewardjd2445f62005-03-21 00:15:53 +00003024 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00003025 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00003026 case Ist_MBE:
sewardj3e838932005-01-07 12:09:15 +00003027 return;
sewardj17442fe2004-09-20 14:54:28 +00003028 case Ist_Exit:
sewardj0276d4b2004-11-15 15:30:21 +00003029 addUses_Expr(set, st->Ist.Exit.guard);
sewardj17442fe2004-09-20 14:54:28 +00003030 return;
sewardj39e3f242004-08-18 16:54:52 +00003031 default:
3032 vex_printf("\n");
3033 ppIRStmt(st);
3034 vpanic("addUses_Stmt");
sewardjd503a322004-10-13 22:41:16 +00003035 }
sewardj39e3f242004-08-18 16:54:52 +00003036}
3037
3038
sewardjba999312004-11-15 15:21:17 +00003039/* Is this literally IRExpr_Const(IRConst_U1(False)) ? */
3040static Bool isZeroU1 ( IRExpr* e )
sewardjd9997882004-11-04 19:42:59 +00003041{
sewardj9d2e7692005-02-07 01:11:31 +00003042 return toBool( e->tag == Iex_Const
3043 && e->Iex.Const.con->tag == Ico_U1
3044 && e->Iex.Const.con->Ico.U1 == False );
sewardjd9997882004-11-04 19:42:59 +00003045}
3046
sewardje810c192005-09-09 08:33:03 +00003047/* Is this literally IRExpr_Const(IRConst_U1(True)) ? */
3048static Bool isOneU1 ( IRExpr* e )
3049{
3050 return toBool( e->tag == Iex_Const
3051 && e->Iex.Const.con->tag == Ico_U1
3052 && e->Iex.Const.con->Ico.U1 == True );
3053}
3054
sewardj39e3f242004-08-18 16:54:52 +00003055
sewardjdd40fdf2006-12-24 02:20:24 +00003056/* Note, this destructively modifies the given IRSB. */
sewardj39e3f242004-08-18 16:54:52 +00003057
3058/* Scan backwards through statements, carrying a set of IRTemps which
3059 are known to be used after the current point. On encountering 't =
3060 E', delete the binding if it is not used. Otherwise, add any temp
sewardje810c192005-09-09 08:33:03 +00003061 uses to the set and keep on moving backwards.
3062
3063 As an enhancement, the first (backwards) pass searches for IR exits
3064 with always-taken conditions and notes the location of the earliest
3065 one in the block. If any such are found, a second pass copies the
3066 exit destination and jump kind to the bb-end. Then, the exit and
3067 all statements following it are turned into no-ops.
3068*/
sewardj39e3f242004-08-18 16:54:52 +00003069
sewardjdd40fdf2006-12-24 02:20:24 +00003070/* notstatic */ void do_deadcode_BB ( IRSB* bb )
sewardj39e3f242004-08-18 16:54:52 +00003071{
sewardje810c192005-09-09 08:33:03 +00003072 Int i, i_unconditional_exit;
sewardjd503a322004-10-13 22:41:16 +00003073 Int n_tmps = bb->tyenv->types_used;
3074 Bool* set = LibVEX_Alloc(n_tmps * sizeof(Bool));
sewardj39e3f242004-08-18 16:54:52 +00003075 IRStmt* st;
3076
sewardjd503a322004-10-13 22:41:16 +00003077 for (i = 0; i < n_tmps; i++)
3078 set[i] = False;
3079
sewardj39e3f242004-08-18 16:54:52 +00003080 /* start off by recording IRTemp uses in the next field. */
3081 addUses_Expr(set, bb->next);
3082
sewardje810c192005-09-09 08:33:03 +00003083 /* First pass */
3084
sewardj39e3f242004-08-18 16:54:52 +00003085 /* Work backwards through the stmts */
sewardje810c192005-09-09 08:33:03 +00003086 i_unconditional_exit = -1;
sewardj39e3f242004-08-18 16:54:52 +00003087 for (i = bb->stmts_used-1; i >= 0; i--) {
3088 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003089 if (st->tag == Ist_NoOp)
sewardj84ff0652004-08-23 16:16:08 +00003090 continue;
sewardje810c192005-09-09 08:33:03 +00003091 /* take note of any unconditional exits */
3092 if (st->tag == Ist_Exit
3093 && isOneU1(st->Ist.Exit.guard))
3094 i_unconditional_exit = i;
sewardjdd40fdf2006-12-24 02:20:24 +00003095 if (st->tag == Ist_WrTmp
3096 && set[(Int)(st->Ist.WrTmp.tmp)] == False) {
sewardj39e3f242004-08-18 16:54:52 +00003097 /* it's an IRTemp which never got used. Delete it. */
sewardj088bcb42004-08-19 17:16:52 +00003098 if (DEBUG_IROPT) {
sewardj39e3f242004-08-18 16:54:52 +00003099 vex_printf("DEAD: ");
3100 ppIRStmt(st);
3101 vex_printf("\n");
3102 }
sewardjd2445f62005-03-21 00:15:53 +00003103 bb->stmts[i] = IRStmt_NoOp();
sewardjd9997882004-11-04 19:42:59 +00003104 }
3105 else
3106 if (st->tag == Ist_Dirty
3107 && st->Ist.Dirty.details->guard
sewardjba999312004-11-15 15:21:17 +00003108 && isZeroU1(st->Ist.Dirty.details->guard)) {
sewardjd2445f62005-03-21 00:15:53 +00003109 /* This is a dirty helper which will never get called.
3110 Delete it. */
3111 bb->stmts[i] = IRStmt_NoOp();
sewardjd9997882004-11-04 19:42:59 +00003112 }
3113 else {
sewardj39e3f242004-08-18 16:54:52 +00003114 /* Note any IRTemp uses made by the current statement. */
3115 addUses_Stmt(set, st);
3116 }
3117 }
sewardje810c192005-09-09 08:33:03 +00003118
3119 /* Optional second pass: if any unconditional exits were found,
3120 delete them and all following statements. */
3121
3122 if (i_unconditional_exit != -1) {
3123 if (0) vex_printf("ZAPPING ALL FORWARDS from %d\n",
3124 i_unconditional_exit);
3125 vassert(i_unconditional_exit >= 0
3126 && i_unconditional_exit < bb->stmts_used);
3127 bb->next
3128 = IRExpr_Const( bb->stmts[i_unconditional_exit]->Ist.Exit.dst );
3129 bb->jumpkind
3130 = bb->stmts[i_unconditional_exit]->Ist.Exit.jk;
sewardjc6f970f2012-04-02 21:54:49 +00003131 bb->offsIP
3132 = bb->stmts[i_unconditional_exit]->Ist.Exit.offsIP;
sewardje810c192005-09-09 08:33:03 +00003133 for (i = i_unconditional_exit; i < bb->stmts_used; i++)
3134 bb->stmts[i] = IRStmt_NoOp();
3135 }
sewardj39e3f242004-08-18 16:54:52 +00003136}
3137
sewardje810c192005-09-09 08:33:03 +00003138
sewardj84ff0652004-08-23 16:16:08 +00003139/*---------------------------------------------------------------*/
3140/*--- Specialisation of helper function calls, in ---*/
3141/*--- collaboration with the front end ---*/
3142/*---------------------------------------------------------------*/
3143
3144static
sewardjbe917912010-08-22 12:38:53 +00003145IRSB* spec_helpers_BB(
3146 IRSB* bb,
florian1ff47562012-10-21 02:09:51 +00003147 IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int)
sewardjbe917912010-08-22 12:38:53 +00003148 )
sewardj84ff0652004-08-23 16:16:08 +00003149{
sewardjb9230752004-12-29 19:25:06 +00003150 Int i;
sewardj84ff0652004-08-23 16:16:08 +00003151 IRStmt* st;
3152 IRExpr* ex;
sewardjb9230752004-12-29 19:25:06 +00003153 Bool any = False;
sewardj84ff0652004-08-23 16:16:08 +00003154
3155 for (i = bb->stmts_used-1; i >= 0; i--) {
3156 st = bb->stmts[i];
3157
sewardjdd40fdf2006-12-24 02:20:24 +00003158 if (st->tag != Ist_WrTmp
3159 || st->Ist.WrTmp.data->tag != Iex_CCall)
sewardj8bee6d12005-03-22 02:24:05 +00003160 continue;
sewardj84ff0652004-08-23 16:16:08 +00003161
sewardjdd40fdf2006-12-24 02:20:24 +00003162 ex = (*specHelper)( st->Ist.WrTmp.data->Iex.CCall.cee->name,
sewardjbe917912010-08-22 12:38:53 +00003163 st->Ist.WrTmp.data->Iex.CCall.args,
3164 &bb->stmts[0], i );
sewardj84ff0652004-08-23 16:16:08 +00003165 if (!ex)
sewardjaba4fff2004-10-08 21:37:15 +00003166 /* the front end can't think of a suitable replacement */
3167 continue;
sewardj84ff0652004-08-23 16:16:08 +00003168
3169 /* We got something better. Install it in the bb. */
sewardjb9230752004-12-29 19:25:06 +00003170 any = True;
sewardj84ff0652004-08-23 16:16:08 +00003171 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00003172 = IRStmt_WrTmp(st->Ist.WrTmp.tmp, ex);
sewardj84ff0652004-08-23 16:16:08 +00003173
3174 if (0) {
3175 vex_printf("SPEC: ");
sewardjdd40fdf2006-12-24 02:20:24 +00003176 ppIRExpr(st->Ist.WrTmp.data);
sewardj84ff0652004-08-23 16:16:08 +00003177 vex_printf(" --> ");
3178 ppIRExpr(ex);
3179 vex_printf("\n");
3180 }
3181 }
sewardjb9230752004-12-29 19:25:06 +00003182
3183 if (any)
3184 bb = flatten_BB(bb);
3185 return bb;
sewardj84ff0652004-08-23 16:16:08 +00003186}
3187
sewardj29632392004-08-22 02:38:11 +00003188
3189/*---------------------------------------------------------------*/
sewardj9b0cc582006-02-04 15:24:00 +00003190/*--- Determination of guest state aliasing relationships ---*/
3191/*---------------------------------------------------------------*/
3192
3193/* These are helper functions for CSE and GetI/PutI transformations.
3194
3195 Determine, to the extent possible, the relationship between two
3196 guest state accesses. The possible outcomes are:
3197
3198 * Exact alias. These two accesses denote precisely the same
3199 piece of the guest state.
3200
3201 * Definitely no alias. These two accesses are guaranteed not to
3202 overlap any part of the guest state.
3203
3204 * Unknown -- if neither of the above can be established.
3205
3206 If in doubt, return Unknown. */
3207
3208typedef
3209 enum { ExactAlias, NoAlias, UnknownAlias }
3210 GSAliasing;
3211
3212
3213/* Produces the alias relation between an indexed guest
3214 state access and a non-indexed access. */
3215
3216static
sewardjdd40fdf2006-12-24 02:20:24 +00003217GSAliasing getAliasingRelation_IC ( IRRegArray* descr1, IRExpr* ix1,
sewardj9b0cc582006-02-04 15:24:00 +00003218 Int offset2, IRType ty2 )
3219{
3220 UInt minoff1, maxoff1, minoff2, maxoff2;
3221
3222 getArrayBounds( descr1, &minoff1, &maxoff1 );
3223 minoff2 = offset2;
3224 maxoff2 = minoff2 + sizeofIRType(ty2) - 1;
3225
3226 if (maxoff1 < minoff2 || maxoff2 < minoff1)
3227 return NoAlias;
3228
3229 /* Could probably do better here if required. For the moment
3230 however just claim not to know anything more. */
3231 return UnknownAlias;
3232}
3233
3234
3235/* Produces the alias relation between two indexed guest state
3236 accesses. */
3237
3238static
3239GSAliasing getAliasingRelation_II (
sewardjdd40fdf2006-12-24 02:20:24 +00003240 IRRegArray* descr1, IRExpr* ix1, Int bias1,
3241 IRRegArray* descr2, IRExpr* ix2, Int bias2
sewardj9b0cc582006-02-04 15:24:00 +00003242 )
3243{
3244 UInt minoff1, maxoff1, minoff2, maxoff2;
3245 Int iters;
3246
3247 /* First try hard to show they don't alias. */
3248 getArrayBounds( descr1, &minoff1, &maxoff1 );
3249 getArrayBounds( descr2, &minoff2, &maxoff2 );
3250 if (maxoff1 < minoff2 || maxoff2 < minoff1)
3251 return NoAlias;
3252
3253 /* So the two arrays at least partially overlap. To get any
3254 further we'll have to be sure that the descriptors are
3255 identical. */
sewardjdd40fdf2006-12-24 02:20:24 +00003256 if (!eqIRRegArray(descr1, descr2))
sewardj9b0cc582006-02-04 15:24:00 +00003257 return UnknownAlias;
3258
3259 /* The descriptors are identical. Now the only difference can be
3260 in the index expressions. If they cannot be shown to be
3261 identical, we have to say we don't know what the aliasing
3262 relation will be. Now, since the IR is flattened, the index
3263 expressions should be atoms -- either consts or tmps. So that
3264 makes the comparison simple. */
3265 vassert(isIRAtom(ix1));
3266 vassert(isIRAtom(ix2));
3267 if (!eqIRAtom(ix1,ix2))
3268 return UnknownAlias;
3269
3270 /* Ok, the index expressions are identical. So now the only way
3271 they can be different is in the bias. Normalise this
3272 paranoidly, to reliably establish equality/non-equality. */
3273
3274 /* So now we know that the GetI and PutI index the same array
3275 with the same base. Are the offsets the same, modulo the
3276 array size? Do this paranoidly. */
3277 vassert(descr1->nElems == descr2->nElems);
3278 vassert(descr1->elemTy == descr2->elemTy);
3279 vassert(descr1->base == descr2->base);
3280 iters = 0;
3281 while (bias1 < 0 || bias2 < 0) {
3282 bias1 += descr1->nElems;
3283 bias2 += descr1->nElems;
3284 iters++;
3285 if (iters > 10)
3286 vpanic("getAliasingRelation: iters");
3287 }
3288 vassert(bias1 >= 0 && bias2 >= 0);
3289 bias1 %= descr1->nElems;
3290 bias2 %= descr1->nElems;
3291 vassert(bias1 >= 0 && bias1 < descr1->nElems);
3292 vassert(bias2 >= 0 && bias2 < descr1->nElems);
3293
3294 /* Finally, biasP and biasG are normalised into the range
3295 0 .. descrP/G->nElems - 1. And so we can establish
3296 equality/non-equality. */
3297
3298 return bias1==bias2 ? ExactAlias : NoAlias;
3299}
3300
3301
3302/*---------------------------------------------------------------*/
sewardj08210532004-12-29 17:09:11 +00003303/*--- Common Subexpression Elimination ---*/
3304/*---------------------------------------------------------------*/
3305
3306/* Expensive in time and space. */
3307
3308/* Uses two environments:
3309 a IRTemp -> IRTemp mapping
3310 a mapping from AvailExpr* to IRTemp
3311*/
3312
3313typedef
3314 struct {
sewardje8578042012-04-13 11:42:50 +00003315 enum { TCc, TCt } tag;
3316 union { IRTemp tmp; IRConst* con; } u;
3317 }
3318 TmpOrConst;
3319
3320static Bool eqTmpOrConst ( TmpOrConst* tc1, TmpOrConst* tc2 )
3321{
3322 if (tc1->tag != tc2->tag)
3323 return False;
3324 switch (tc1->tag) {
3325 case TCc:
3326 return eqIRConst(tc1->u.con, tc2->u.con);
3327 case TCt:
3328 return tc1->u.tmp == tc2->u.tmp;
3329 default:
3330 vpanic("eqTmpOrConst");
3331 }
3332}
3333
3334static Bool eqIRCallee ( IRCallee* cee1, IRCallee* cee2 )
3335{
3336 Bool eq = cee1->addr == cee2->addr;
3337 if (eq) {
3338 vassert(cee1->regparms == cee2->regparms);
3339 vassert(cee1->mcx_mask == cee2->mcx_mask);
3340 /* Names should be the same too, but we don't bother to
3341 check. */
3342 }
3343 return eq;
3344}
3345
3346/* Convert a NULL terminated IRExpr* vector to an array of
3347 TmpOrConsts, and a length. */
3348static void irExprVec_to_TmpOrConsts ( /*OUT*/TmpOrConst** outs,
3349 /*OUT*/Int* nOuts,
3350 IRExpr** ins )
3351{
3352 Int i, n;
3353 /* We have to make two passes, one to count, one to copy. */
3354 for (n = 0; ins[n]; n++)
3355 ;
3356 *outs = LibVEX_Alloc(n * sizeof(TmpOrConst));
3357 *nOuts = n;
3358 /* and now copy .. */
3359 for (i = 0; i < n; i++) {
3360 IRExpr* arg = ins[i];
3361 TmpOrConst* dst = &(*outs)[i];
3362 if (arg->tag == Iex_RdTmp) {
3363 dst->tag = TCt;
3364 dst->u.tmp = arg->Iex.RdTmp.tmp;
3365 }
3366 else if (arg->tag == Iex_Const) {
3367 dst->tag = TCc;
3368 dst->u.con = arg->Iex.Const.con;
3369 }
3370 else {
3371 /* Failure of this is serious; it means that the presented arg
3372 isn't an IR atom, as it should be. */
3373 vpanic("irExprVec_to_TmpOrConsts");
3374 }
3375 }
3376}
3377
3378typedef
3379 struct {
florianb05c20c2013-01-31 02:04:02 +00003380 enum { Ut, Btt, Btc, Bct, Cf64i, Ittt, Itct, Ittc, Itcc, GetIt,
florianda25edd2012-09-12 16:40:54 +00003381 CCall
3382 } tag;
sewardj08210532004-12-29 17:09:11 +00003383 union {
3384 /* unop(tmp) */
3385 struct {
3386 IROp op;
3387 IRTemp arg;
3388 } Ut;
3389 /* binop(tmp,tmp) */
3390 struct {
3391 IROp op;
3392 IRTemp arg1;
3393 IRTemp arg2;
3394 } Btt;
3395 /* binop(tmp,const) */
3396 struct {
3397 IROp op;
3398 IRTemp arg1;
3399 IRConst con2;
3400 } Btc;
3401 /* binop(const,tmp) */
3402 struct {
3403 IROp op;
3404 IRConst con1;
3405 IRTemp arg2;
3406 } Bct;
3407 /* F64i-style const */
3408 struct {
3409 ULong f64i;
3410 } Cf64i;
florian99dd03e2013-01-29 03:56:06 +00003411 /* ITE(tmp,tmp,tmp) */
sewardj9b0cc582006-02-04 15:24:00 +00003412 struct {
3413 IRTemp co;
florianb05c20c2013-01-31 02:04:02 +00003414 IRTemp e1;
sewardj9b0cc582006-02-04 15:24:00 +00003415 IRTemp e0;
florianb05c20c2013-01-31 02:04:02 +00003416 } Ittt;
florian99dd03e2013-01-29 03:56:06 +00003417 /* ITE(tmp,tmp,const) */
florianda25edd2012-09-12 16:40:54 +00003418 struct {
3419 IRTemp co;
florianb05c20c2013-01-31 02:04:02 +00003420 IRTemp e1;
florianda25edd2012-09-12 16:40:54 +00003421 IRConst con0;
florianb05c20c2013-01-31 02:04:02 +00003422 } Ittc;
florian99dd03e2013-01-29 03:56:06 +00003423 /* ITE(tmp,const,tmp) */
florianda25edd2012-09-12 16:40:54 +00003424 struct {
3425 IRTemp co;
florianb05c20c2013-01-31 02:04:02 +00003426 IRConst con1;
florianda25edd2012-09-12 16:40:54 +00003427 IRTemp e0;
florianb05c20c2013-01-31 02:04:02 +00003428 } Itct;
florian99dd03e2013-01-29 03:56:06 +00003429 /* ITE(tmp,const,const) */
florianda25edd2012-09-12 16:40:54 +00003430 struct {
3431 IRTemp co;
florianb05c20c2013-01-31 02:04:02 +00003432 IRConst con1;
florianda25edd2012-09-12 16:40:54 +00003433 IRConst con0;
florianb05c20c2013-01-31 02:04:02 +00003434 } Itcc;
sewardj9b0cc582006-02-04 15:24:00 +00003435 /* GetI(descr,tmp,bias)*/
3436 struct {
sewardjdd40fdf2006-12-24 02:20:24 +00003437 IRRegArray* descr;
3438 IRTemp ix;
3439 Int bias;
sewardj9b0cc582006-02-04 15:24:00 +00003440 } GetIt;
sewardje8578042012-04-13 11:42:50 +00003441 /* Clean helper call */
3442 struct {
3443 IRCallee* cee;
3444 TmpOrConst* args;
3445 Int nArgs;
3446 IRType retty;
3447 } CCall;
sewardj08210532004-12-29 17:09:11 +00003448 } u;
3449 }
3450 AvailExpr;
3451
3452static Bool eq_AvailExpr ( AvailExpr* a1, AvailExpr* a2 )
3453{
sewardje8578042012-04-13 11:42:50 +00003454 if (LIKELY(a1->tag != a2->tag))
sewardj08210532004-12-29 17:09:11 +00003455 return False;
3456 switch (a1->tag) {
3457 case Ut:
sewardj9d2e7692005-02-07 01:11:31 +00003458 return toBool(
3459 a1->u.Ut.op == a2->u.Ut.op
3460 && a1->u.Ut.arg == a2->u.Ut.arg);
sewardj08210532004-12-29 17:09:11 +00003461 case Btt:
sewardj9d2e7692005-02-07 01:11:31 +00003462 return toBool(
3463 a1->u.Btt.op == a2->u.Btt.op
sewardj08210532004-12-29 17:09:11 +00003464 && a1->u.Btt.arg1 == a2->u.Btt.arg1
sewardj9d2e7692005-02-07 01:11:31 +00003465 && a1->u.Btt.arg2 == a2->u.Btt.arg2);
sewardj08210532004-12-29 17:09:11 +00003466 case Btc:
sewardj9d2e7692005-02-07 01:11:31 +00003467 return toBool(
3468 a1->u.Btc.op == a2->u.Btc.op
sewardj08210532004-12-29 17:09:11 +00003469 && a1->u.Btc.arg1 == a2->u.Btc.arg1
sewardj9d2e7692005-02-07 01:11:31 +00003470 && eqIRConst(&a1->u.Btc.con2, &a2->u.Btc.con2));
sewardj08210532004-12-29 17:09:11 +00003471 case Bct:
sewardj9d2e7692005-02-07 01:11:31 +00003472 return toBool(
3473 a1->u.Bct.op == a2->u.Bct.op
sewardj08210532004-12-29 17:09:11 +00003474 && a1->u.Bct.arg2 == a2->u.Bct.arg2
sewardj9d2e7692005-02-07 01:11:31 +00003475 && eqIRConst(&a1->u.Bct.con1, &a2->u.Bct.con1));
sewardj08210532004-12-29 17:09:11 +00003476 case Cf64i:
sewardj9d2e7692005-02-07 01:11:31 +00003477 return toBool(a1->u.Cf64i.f64i == a2->u.Cf64i.f64i);
florianb05c20c2013-01-31 02:04:02 +00003478 case Ittt:
3479 return toBool(a1->u.Ittt.co == a2->u.Ittt.co
3480 && a1->u.Ittt.e1 == a2->u.Ittt.e1
3481 && a1->u.Ittt.e0 == a2->u.Ittt.e0);
3482 case Ittc:
3483 return toBool(a1->u.Ittc.co == a2->u.Ittc.co
3484 && a1->u.Ittc.e1 == a2->u.Ittc.e1
3485 && eqIRConst(&a1->u.Ittc.con0, &a2->u.Ittc.con0));
3486 case Itct:
3487 return toBool(a1->u.Itct.co == a2->u.Itct.co
3488 && eqIRConst(&a1->u.Itct.con1, &a2->u.Itct.con1)
3489 && a1->u.Itct.e0 == a2->u.Itct.e0);
3490 case Itcc:
3491 return toBool(a1->u.Itcc.co == a2->u.Itcc.co
3492 && eqIRConst(&a1->u.Itcc.con1, &a2->u.Itcc.con1)
3493 && eqIRConst(&a1->u.Itcc.con0, &a2->u.Itcc.con0));
sewardj9b0cc582006-02-04 15:24:00 +00003494 case GetIt:
sewardjdd40fdf2006-12-24 02:20:24 +00003495 return toBool(eqIRRegArray(a1->u.GetIt.descr, a2->u.GetIt.descr)
sewardj9b0cc582006-02-04 15:24:00 +00003496 && a1->u.GetIt.ix == a2->u.GetIt.ix
3497 && a1->u.GetIt.bias == a2->u.GetIt.bias);
sewardje8578042012-04-13 11:42:50 +00003498 case CCall: {
3499 Int i, n;
3500 Bool eq = a1->u.CCall.nArgs == a2->u.CCall.nArgs
3501 && eqIRCallee(a1->u.CCall.cee, a2->u.CCall.cee);
3502 if (eq) {
3503 n = a1->u.CCall.nArgs;
3504 for (i = 0; i < n; i++) {
3505 if (!eqTmpOrConst( &a1->u.CCall.args[i],
3506 &a2->u.CCall.args[i] )) {
3507 eq = False;
3508 break;
3509 }
3510 }
3511 }
3512 if (eq) vassert(a1->u.CCall.retty == a2->u.CCall.retty);
3513 return eq;
3514 }
sewardj08210532004-12-29 17:09:11 +00003515 default: vpanic("eq_AvailExpr");
3516 }
3517}
3518
3519static IRExpr* availExpr_to_IRExpr ( AvailExpr* ae )
3520{
florianb05c20c2013-01-31 02:04:02 +00003521 IRConst *con, *con0, *con1;
sewardj08210532004-12-29 17:09:11 +00003522 switch (ae->tag) {
3523 case Ut:
sewardjdd40fdf2006-12-24 02:20:24 +00003524 return IRExpr_Unop( ae->u.Ut.op, IRExpr_RdTmp(ae->u.Ut.arg) );
sewardj08210532004-12-29 17:09:11 +00003525 case Btt:
3526 return IRExpr_Binop( ae->u.Btt.op,
sewardjdd40fdf2006-12-24 02:20:24 +00003527 IRExpr_RdTmp(ae->u.Btt.arg1),
3528 IRExpr_RdTmp(ae->u.Btt.arg2) );
sewardj08210532004-12-29 17:09:11 +00003529 case Btc:
3530 con = LibVEX_Alloc(sizeof(IRConst));
3531 *con = ae->u.Btc.con2;
3532 return IRExpr_Binop( ae->u.Btc.op,
sewardjdd40fdf2006-12-24 02:20:24 +00003533 IRExpr_RdTmp(ae->u.Btc.arg1),
3534 IRExpr_Const(con) );
sewardj08210532004-12-29 17:09:11 +00003535 case Bct:
3536 con = LibVEX_Alloc(sizeof(IRConst));
3537 *con = ae->u.Bct.con1;
3538 return IRExpr_Binop( ae->u.Bct.op,
sewardjdd40fdf2006-12-24 02:20:24 +00003539 IRExpr_Const(con),
3540 IRExpr_RdTmp(ae->u.Bct.arg2) );
sewardj08210532004-12-29 17:09:11 +00003541 case Cf64i:
3542 return IRExpr_Const(IRConst_F64i(ae->u.Cf64i.f64i));
florianb05c20c2013-01-31 02:04:02 +00003543 case Ittt:
3544 return IRExpr_ITE(IRExpr_RdTmp(ae->u.Ittt.co),
3545 IRExpr_RdTmp(ae->u.Ittt.e1),
3546 IRExpr_RdTmp(ae->u.Ittt.e0));
3547 case Ittc:
florianda25edd2012-09-12 16:40:54 +00003548 con0 = LibVEX_Alloc(sizeof(IRConst));
florianb05c20c2013-01-31 02:04:02 +00003549 *con0 = ae->u.Ittc.con0;
3550 return IRExpr_ITE(IRExpr_RdTmp(ae->u.Ittc.co),
3551 IRExpr_RdTmp(ae->u.Ittc.e1),
florian99dd03e2013-01-29 03:56:06 +00003552 IRExpr_Const(con0));
florianb05c20c2013-01-31 02:04:02 +00003553 case Itct:
3554 con1 = LibVEX_Alloc(sizeof(IRConst));
3555 *con1 = ae->u.Itct.con1;
3556 return IRExpr_ITE(IRExpr_RdTmp(ae->u.Itct.co),
3557 IRExpr_Const(con1),
3558 IRExpr_RdTmp(ae->u.Itct.e0));
florian99dd03e2013-01-29 03:56:06 +00003559
florianb05c20c2013-01-31 02:04:02 +00003560 case Itcc:
florianda25edd2012-09-12 16:40:54 +00003561 con0 = LibVEX_Alloc(sizeof(IRConst));
florianb05c20c2013-01-31 02:04:02 +00003562 con1 = LibVEX_Alloc(sizeof(IRConst));
3563 *con0 = ae->u.Itcc.con0;
3564 *con1 = ae->u.Itcc.con1;
3565 return IRExpr_ITE(IRExpr_RdTmp(ae->u.Itcc.co),
3566 IRExpr_Const(con1),
florian99dd03e2013-01-29 03:56:06 +00003567 IRExpr_Const(con0));
sewardj9b0cc582006-02-04 15:24:00 +00003568 case GetIt:
3569 return IRExpr_GetI(ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003570 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00003571 ae->u.GetIt.bias);
sewardje8578042012-04-13 11:42:50 +00003572 case CCall: {
3573 Int i, n = ae->u.CCall.nArgs;
3574 vassert(n >= 0);
3575 IRExpr** vec = LibVEX_Alloc((n+1) * sizeof(IRExpr*));
3576 vec[n] = NULL;
3577 for (i = 0; i < n; i++) {
3578 TmpOrConst* tc = &ae->u.CCall.args[i];
3579 if (tc->tag == TCc) {
3580 vec[i] = IRExpr_Const(tc->u.con);
3581 }
3582 else if (tc->tag == TCt) {
3583 vec[i] = IRExpr_RdTmp(tc->u.tmp);
3584 }
3585 else vpanic("availExpr_to_IRExpr:CCall-arg");
3586 }
3587 return IRExpr_CCall(ae->u.CCall.cee,
3588 ae->u.CCall.retty,
3589 vec);
3590 }
sewardj08210532004-12-29 17:09:11 +00003591 default:
3592 vpanic("availExpr_to_IRExpr");
3593 }
3594}
3595
3596inline
3597static IRTemp subst_AvailExpr_Temp ( HashHW* env, IRTemp tmp )
3598{
3599 HWord res;
3600 /* env :: IRTemp -> IRTemp */
3601 if (lookupHHW( env, &res, (HWord)tmp ))
3602 return (IRTemp)res;
3603 else
3604 return tmp;
3605}
3606
3607static void subst_AvailExpr ( HashHW* env, AvailExpr* ae )
3608{
3609 /* env :: IRTemp -> IRTemp */
3610 switch (ae->tag) {
3611 case Ut:
3612 ae->u.Ut.arg = subst_AvailExpr_Temp( env, ae->u.Ut.arg );
3613 break;
3614 case Btt:
3615 ae->u.Btt.arg1 = subst_AvailExpr_Temp( env, ae->u.Btt.arg1 );
3616 ae->u.Btt.arg2 = subst_AvailExpr_Temp( env, ae->u.Btt.arg2 );
3617 break;
3618 case Btc:
3619 ae->u.Btc.arg1 = subst_AvailExpr_Temp( env, ae->u.Btc.arg1 );
3620 break;
3621 case Bct:
3622 ae->u.Bct.arg2 = subst_AvailExpr_Temp( env, ae->u.Bct.arg2 );
3623 break;
3624 case Cf64i:
3625 break;
florianb05c20c2013-01-31 02:04:02 +00003626 case Ittt:
3627 ae->u.Ittt.co = subst_AvailExpr_Temp( env, ae->u.Ittt.co );
3628 ae->u.Ittt.e1 = subst_AvailExpr_Temp( env, ae->u.Ittt.e1 );
3629 ae->u.Ittt.e0 = subst_AvailExpr_Temp( env, ae->u.Ittt.e0 );
sewardj9b0cc582006-02-04 15:24:00 +00003630 break;
florianb05c20c2013-01-31 02:04:02 +00003631 case Ittc:
3632 ae->u.Ittc.co = subst_AvailExpr_Temp( env, ae->u.Ittc.co );
3633 ae->u.Ittc.e1 = subst_AvailExpr_Temp( env, ae->u.Ittc.e1 );
florianda25edd2012-09-12 16:40:54 +00003634 break;
florianb05c20c2013-01-31 02:04:02 +00003635 case Itct:
3636 ae->u.Itct.co = subst_AvailExpr_Temp( env, ae->u.Itct.co );
3637 ae->u.Itct.e0 = subst_AvailExpr_Temp( env, ae->u.Itct.e0 );
florianda25edd2012-09-12 16:40:54 +00003638 break;
florianb05c20c2013-01-31 02:04:02 +00003639 case Itcc:
3640 ae->u.Itcc.co = subst_AvailExpr_Temp( env, ae->u.Itcc.co );
florianda25edd2012-09-12 16:40:54 +00003641 break;
sewardj9b0cc582006-02-04 15:24:00 +00003642 case GetIt:
3643 ae->u.GetIt.ix = subst_AvailExpr_Temp( env, ae->u.GetIt.ix );
3644 break;
sewardje8578042012-04-13 11:42:50 +00003645 case CCall: {
3646 Int i, n = ae->u.CCall.nArgs;;
3647 for (i = 0; i < n; i++) {
3648 TmpOrConst* tc = &ae->u.CCall.args[i];
3649 if (tc->tag == TCt) {
3650 tc->u.tmp = subst_AvailExpr_Temp( env, tc->u.tmp );
3651 }
3652 }
3653 break;
3654 }
sewardj08210532004-12-29 17:09:11 +00003655 default:
3656 vpanic("subst_AvailExpr");
3657 }
3658}
3659
3660static AvailExpr* irExpr_to_AvailExpr ( IRExpr* e )
3661{
3662 AvailExpr* ae;
3663
florianc1b9e392012-09-20 02:40:57 +00003664 switch (e->tag) {
3665 case Iex_Unop:
3666 if (e->Iex.Unop.arg->tag == Iex_RdTmp) {
3667 ae = LibVEX_Alloc(sizeof(AvailExpr));
3668 ae->tag = Ut;
3669 ae->u.Ut.op = e->Iex.Unop.op;
3670 ae->u.Ut.arg = e->Iex.Unop.arg->Iex.RdTmp.tmp;
3671 return ae;
3672 }
3673 break;
sewardj08210532004-12-29 17:09:11 +00003674
florianc1b9e392012-09-20 02:40:57 +00003675 case Iex_Binop:
3676 if (e->Iex.Binop.arg1->tag == Iex_RdTmp) {
3677 if (e->Iex.Binop.arg2->tag == Iex_RdTmp) {
3678 ae = LibVEX_Alloc(sizeof(AvailExpr));
3679 ae->tag = Btt;
3680 ae->u.Btt.op = e->Iex.Binop.op;
3681 ae->u.Btt.arg1 = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
3682 ae->u.Btt.arg2 = e->Iex.Binop.arg2->Iex.RdTmp.tmp;
3683 return ae;
3684 }
3685 if (e->Iex.Binop.arg2->tag == Iex_Const) {
3686 ae = LibVEX_Alloc(sizeof(AvailExpr));
3687 ae->tag = Btc;
3688 ae->u.Btc.op = e->Iex.Binop.op;
3689 ae->u.Btc.arg1 = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
3690 ae->u.Btc.con2 = *(e->Iex.Binop.arg2->Iex.Const.con);
3691 return ae;
3692 }
3693 } else if (e->Iex.Binop.arg1->tag == Iex_Const
3694 && e->Iex.Binop.arg2->tag == Iex_RdTmp) {
3695 ae = LibVEX_Alloc(sizeof(AvailExpr));
3696 ae->tag = Bct;
3697 ae->u.Bct.op = e->Iex.Binop.op;
3698 ae->u.Bct.arg2 = e->Iex.Binop.arg2->Iex.RdTmp.tmp;
3699 ae->u.Bct.con1 = *(e->Iex.Binop.arg1->Iex.Const.con);
3700 return ae;
3701 }
3702 break;
sewardj08210532004-12-29 17:09:11 +00003703
florianc1b9e392012-09-20 02:40:57 +00003704 case Iex_Const:
3705 if (e->Iex.Const.con->tag == Ico_F64i) {
3706 ae = LibVEX_Alloc(sizeof(AvailExpr));
3707 ae->tag = Cf64i;
3708 ae->u.Cf64i.f64i = e->Iex.Const.con->Ico.F64i;
3709 return ae;
3710 }
3711 break;
sewardj08210532004-12-29 17:09:11 +00003712
florian99dd03e2013-01-29 03:56:06 +00003713 case Iex_ITE:
3714 if (e->Iex.ITE.cond->tag == Iex_RdTmp) {
3715 if (e->Iex.ITE.iffalse->tag == Iex_RdTmp) {
3716 if (e->Iex.ITE.iftrue->tag == Iex_RdTmp) {
florianc1b9e392012-09-20 02:40:57 +00003717 ae = LibVEX_Alloc(sizeof(AvailExpr));
florianb05c20c2013-01-31 02:04:02 +00003718 ae->tag = Ittt;
3719 ae->u.Ittt.co = e->Iex.ITE.cond->Iex.RdTmp.tmp;
3720 ae->u.Ittt.e1 = e->Iex.ITE.iftrue->Iex.RdTmp.tmp;
3721 ae->u.Ittt.e0 = e->Iex.ITE.iffalse->Iex.RdTmp.tmp;
florianc1b9e392012-09-20 02:40:57 +00003722 return ae;
3723 }
florian99dd03e2013-01-29 03:56:06 +00003724 if (e->Iex.ITE.iftrue->tag == Iex_Const) {
florianc1b9e392012-09-20 02:40:57 +00003725 ae = LibVEX_Alloc(sizeof(AvailExpr));
florianb05c20c2013-01-31 02:04:02 +00003726 ae->tag = Itct;
3727 ae->u.Itct.co = e->Iex.ITE.cond->Iex.RdTmp.tmp;
3728 ae->u.Itct.con1 = *(e->Iex.ITE.iftrue->Iex.Const.con);
3729 ae->u.Itct.e0 = e->Iex.ITE.iffalse->Iex.RdTmp.tmp;
florianc1b9e392012-09-20 02:40:57 +00003730 return ae;
3731 }
florian99dd03e2013-01-29 03:56:06 +00003732 } else if (e->Iex.ITE.iffalse->tag == Iex_Const) {
3733 if (e->Iex.ITE.iftrue->tag == Iex_RdTmp) {
florianc1b9e392012-09-20 02:40:57 +00003734 ae = LibVEX_Alloc(sizeof(AvailExpr));
florianb05c20c2013-01-31 02:04:02 +00003735 ae->tag = Ittc;
3736 ae->u.Ittc.co = e->Iex.ITE.cond->Iex.RdTmp.tmp;
3737 ae->u.Ittc.e1 = e->Iex.ITE.iftrue->Iex.RdTmp.tmp;
3738 ae->u.Ittc.con0 = *(e->Iex.ITE.iffalse->Iex.Const.con);
florianc1b9e392012-09-20 02:40:57 +00003739 return ae;
3740 }
florian99dd03e2013-01-29 03:56:06 +00003741 if (e->Iex.ITE.iftrue->tag == Iex_Const) {
florianc1b9e392012-09-20 02:40:57 +00003742 ae = LibVEX_Alloc(sizeof(AvailExpr));
florianb05c20c2013-01-31 02:04:02 +00003743 ae->tag = Itcc;
3744 ae->u.Itcc.co = e->Iex.ITE.cond->Iex.RdTmp.tmp;
3745 ae->u.Itcc.con1 = *(e->Iex.ITE.iftrue->Iex.Const.con);
3746 ae->u.Itcc.con0 = *(e->Iex.ITE.iffalse->Iex.Const.con);
florianc1b9e392012-09-20 02:40:57 +00003747 return ae;
3748 }
3749 }
3750 }
3751 break;
sewardj08210532004-12-29 17:09:11 +00003752
florianc1b9e392012-09-20 02:40:57 +00003753 case Iex_GetI:
3754 if (e->Iex.GetI.ix->tag == Iex_RdTmp) {
3755 ae = LibVEX_Alloc(sizeof(AvailExpr));
3756 ae->tag = GetIt;
3757 ae->u.GetIt.descr = e->Iex.GetI.descr;
3758 ae->u.GetIt.ix = e->Iex.GetI.ix->Iex.RdTmp.tmp;
3759 ae->u.GetIt.bias = e->Iex.GetI.bias;
3760 return ae;
3761 }
3762 break;
sewardj08210532004-12-29 17:09:11 +00003763
florianc1b9e392012-09-20 02:40:57 +00003764 case Iex_CCall:
3765 ae = LibVEX_Alloc(sizeof(AvailExpr));
3766 ae->tag = CCall;
3767 /* Ok to share only the cee, since it is immutable. */
3768 ae->u.CCall.cee = e->Iex.CCall.cee;
3769 ae->u.CCall.retty = e->Iex.CCall.retty;
3770 /* irExprVec_to_TmpOrConsts will assert if the args are
3771 neither tmps nor constants, but that's ok .. that's all they
3772 should be. */
3773 irExprVec_to_TmpOrConsts(
3774 &ae->u.CCall.args, &ae->u.CCall.nArgs,
3775 e->Iex.CCall.args
3776 );
3777 return ae;
sewardj9b0cc582006-02-04 15:24:00 +00003778
florianc1b9e392012-09-20 02:40:57 +00003779 default:
3780 break;
sewardje8578042012-04-13 11:42:50 +00003781 }
3782
sewardj08210532004-12-29 17:09:11 +00003783 return NULL;
3784}
3785
3786
sewardj9b0cc582006-02-04 15:24:00 +00003787/* The BB is modified in-place. Returns True if any changes were
3788 made. */
sewardj08210532004-12-29 17:09:11 +00003789
sewardjdd40fdf2006-12-24 02:20:24 +00003790static Bool do_cse_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003791{
sewardj9b0cc582006-02-04 15:24:00 +00003792 Int i, j, paranoia;
sewardj08210532004-12-29 17:09:11 +00003793 IRTemp t, q;
3794 IRStmt* st;
3795 AvailExpr* eprime;
sewardj9b0cc582006-02-04 15:24:00 +00003796 AvailExpr* ae;
3797 Bool invalidate;
3798 Bool anyDone = False;
sewardj08210532004-12-29 17:09:11 +00003799
3800 HashHW* tenv = newHHW(); /* :: IRTemp -> IRTemp */
3801 HashHW* aenv = newHHW(); /* :: AvailExpr* -> IRTemp */
3802
3803 vassert(sizeof(IRTemp) <= sizeof(HWord));
3804
sewardjdd40fdf2006-12-24 02:20:24 +00003805 if (0) { ppIRSB(bb); vex_printf("\n\n"); }
sewardj08210532004-12-29 17:09:11 +00003806
3807 /* Iterate forwards over the stmts.
sewardjcfe046e2013-01-17 14:23:53 +00003808 On seeing "t = E", where E is one of the AvailExpr forms:
sewardj08210532004-12-29 17:09:11 +00003809 let E' = apply tenv substitution to E
3810 search aenv for E'
3811 if a mapping E' -> q is found,
3812 replace this stmt by "t = q"
3813 and add binding t -> q to tenv
3814 else
3815 add binding E' -> t to aenv
3816 replace this stmt by "t = E'"
sewardj9b0cc582006-02-04 15:24:00 +00003817
3818 Other statements are only interesting to the extent that they
3819 might invalidate some of the expressions in aenv. So there is
3820 an invalidate-bindings check for each statement seen.
sewardj08210532004-12-29 17:09:11 +00003821 */
3822 for (i = 0; i < bb->stmts_used; i++) {
3823 st = bb->stmts[i];
3824
sewardj9b0cc582006-02-04 15:24:00 +00003825 /* ------ BEGIN invalidate aenv bindings ------ */
3826 /* This is critical: remove from aenv any E' -> .. bindings
3827 which might be invalidated by this statement. The only
sewardjc4356f02007-11-09 21:15:04 +00003828 vulnerable kind of bindings are the GetI kind.
sewardj9b0cc582006-02-04 15:24:00 +00003829 Dirty call - dump (paranoia level -> 2)
3830 Store - dump (ditto)
3831 Put, PutI - dump unless no-overlap is proven (.. -> 1)
3832 Uses getAliasingRelation_IC and getAliasingRelation_II
3833 to do the no-overlap assessments needed for Put/PutI.
3834 */
3835 switch (st->tag) {
sewardje768e922009-11-26 17:17:37 +00003836 case Ist_Dirty: case Ist_Store: case Ist_MBE:
3837 case Ist_CAS: case Ist_LLSC:
sewardjcfe046e2013-01-17 14:23:53 +00003838 case Ist_StoreG:
sewardj9b0cc582006-02-04 15:24:00 +00003839 paranoia = 2; break;
3840 case Ist_Put: case Ist_PutI:
3841 paranoia = 1; break;
3842 case Ist_NoOp: case Ist_IMark: case Ist_AbiHint:
sewardjcfe046e2013-01-17 14:23:53 +00003843 case Ist_WrTmp: case Ist_Exit: case Ist_LoadG:
sewardj9b0cc582006-02-04 15:24:00 +00003844 paranoia = 0; break;
3845 default:
3846 vpanic("do_cse_BB(1)");
3847 }
3848
3849 if (paranoia > 0) {
3850 for (j = 0; j < aenv->used; j++) {
3851 if (!aenv->inuse[j])
3852 continue;
3853 ae = (AvailExpr*)aenv->key[j];
3854 if (ae->tag != GetIt)
3855 continue;
3856 invalidate = False;
3857 if (paranoia >= 2) {
3858 invalidate = True;
3859 } else {
3860 vassert(paranoia == 1);
3861 if (st->tag == Ist_Put) {
3862 if (getAliasingRelation_IC(
3863 ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003864 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00003865 st->Ist.Put.offset,
3866 typeOfIRExpr(bb->tyenv,st->Ist.Put.data)
3867 ) != NoAlias)
3868 invalidate = True;
3869 }
3870 else
3871 if (st->tag == Ist_PutI) {
floriand6f38b32012-05-31 15:46:18 +00003872 IRPutI *puti = st->Ist.PutI.details;
sewardj9b0cc582006-02-04 15:24:00 +00003873 if (getAliasingRelation_II(
3874 ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003875 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00003876 ae->u.GetIt.bias,
floriand6f38b32012-05-31 15:46:18 +00003877 puti->descr,
3878 puti->ix,
3879 puti->bias
sewardj9b0cc582006-02-04 15:24:00 +00003880 ) != NoAlias)
3881 invalidate = True;
3882 }
3883 else
3884 vpanic("do_cse_BB(2)");
3885 }
3886
3887 if (invalidate) {
3888 aenv->inuse[j] = False;
3889 aenv->key[j] = (HWord)NULL; /* be sure */
3890 }
3891 } /* for j */
3892 } /* paranoia > 0 */
3893
3894 /* ------ ENV invalidate aenv bindings ------ */
3895
sewardj08210532004-12-29 17:09:11 +00003896 /* ignore not-interestings */
sewardjdd40fdf2006-12-24 02:20:24 +00003897 if (st->tag != Ist_WrTmp)
sewardj08210532004-12-29 17:09:11 +00003898 continue;
3899
sewardjdd40fdf2006-12-24 02:20:24 +00003900 t = st->Ist.WrTmp.tmp;
3901 eprime = irExpr_to_AvailExpr(st->Ist.WrTmp.data);
sewardj08210532004-12-29 17:09:11 +00003902 /* ignore if not of AvailExpr form */
3903 if (!eprime)
3904 continue;
3905
3906 /* vex_printf("considering: " ); ppIRStmt(st); vex_printf("\n"); */
3907
3908 /* apply tenv */
3909 subst_AvailExpr( tenv, eprime );
3910
3911 /* search aenv for eprime, unfortunately the hard way */
3912 for (j = 0; j < aenv->used; j++)
3913 if (aenv->inuse[j] && eq_AvailExpr(eprime, (AvailExpr*)aenv->key[j]))
3914 break;
3915
3916 if (j < aenv->used) {
3917 /* A binding E' -> q was found. Replace stmt by "t = q" and
3918 note the t->q binding in tenv. */
3919 /* (this is the core of the CSE action) */
3920 q = (IRTemp)aenv->val[j];
sewardjdd40fdf2006-12-24 02:20:24 +00003921 bb->stmts[i] = IRStmt_WrTmp( t, IRExpr_RdTmp(q) );
sewardj08210532004-12-29 17:09:11 +00003922 addToHHW( tenv, (HWord)t, (HWord)q );
sewardj9b0cc582006-02-04 15:24:00 +00003923 anyDone = True;
sewardj08210532004-12-29 17:09:11 +00003924 } else {
3925 /* No binding was found, so instead we add E' -> t to our
3926 collection of available expressions, replace this stmt
3927 with "t = E'", and move on. */
sewardjdd40fdf2006-12-24 02:20:24 +00003928 bb->stmts[i] = IRStmt_WrTmp( t, availExpr_to_IRExpr(eprime) );
sewardj08210532004-12-29 17:09:11 +00003929 addToHHW( aenv, (HWord)eprime, (HWord)t );
3930 }
3931 }
3932
sewardjb183b852006-02-03 16:08:03 +00003933 /*
sewardjdd40fdf2006-12-24 02:20:24 +00003934 ppIRSB(bb);
3935 sanityCheckIRSB(bb, Ity_I32);
sewardjb183b852006-02-03 16:08:03 +00003936 vex_printf("\n\n");
3937 */
sewardj9b0cc582006-02-04 15:24:00 +00003938 return anyDone;
sewardj08210532004-12-29 17:09:11 +00003939}
3940
3941
3942/*---------------------------------------------------------------*/
3943/*--- Add32/Sub32 chain collapsing ---*/
3944/*---------------------------------------------------------------*/
3945
3946/* ----- Helper functions for Add32/Sub32 chain collapsing ----- */
3947
3948/* Is this expression "Add32(tmp,const)" or "Sub32(tmp,const)" ? If
3949 yes, set *tmp and *i32 appropriately. *i32 is set as if the
3950 root node is Add32, not Sub32. */
3951
3952static Bool isAdd32OrSub32 ( IRExpr* e, IRTemp* tmp, Int* i32 )
3953{
3954 if (e->tag != Iex_Binop)
3955 return False;
3956 if (e->Iex.Binop.op != Iop_Add32 && e->Iex.Binop.op != Iop_Sub32)
3957 return False;
sewardjdd40fdf2006-12-24 02:20:24 +00003958 if (e->Iex.Binop.arg1->tag != Iex_RdTmp)
sewardj08210532004-12-29 17:09:11 +00003959 return False;
3960 if (e->Iex.Binop.arg2->tag != Iex_Const)
3961 return False;
sewardjdd40fdf2006-12-24 02:20:24 +00003962 *tmp = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00003963 *i32 = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32);
3964 if (e->Iex.Binop.op == Iop_Sub32)
3965 *i32 = -*i32;
3966 return True;
3967}
3968
3969
3970/* Figure out if tmp can be expressed as tmp2 +32 const, for some
3971 other tmp2. Scan backwards from the specified start point -- an
3972 optimisation. */
3973
sewardjdd40fdf2006-12-24 02:20:24 +00003974static Bool collapseChain ( IRSB* bb, Int startHere,
sewardj08210532004-12-29 17:09:11 +00003975 IRTemp tmp,
3976 IRTemp* tmp2, Int* i32 )
3977{
3978 Int j, ii;
3979 IRTemp vv;
3980 IRStmt* st;
3981 IRExpr* e;
3982
3983 /* the (var, con) pair contain the current 'representation' for
3984 'tmp'. We start with 'tmp + 0'. */
3985 IRTemp var = tmp;
3986 Int con = 0;
3987
3988 /* Scan backwards to see if tmp can be replaced by some other tmp
3989 +/- a constant. */
3990 for (j = startHere; j >= 0; j--) {
3991 st = bb->stmts[j];
sewardjdd40fdf2006-12-24 02:20:24 +00003992 if (st->tag != Ist_WrTmp)
sewardj08210532004-12-29 17:09:11 +00003993 continue;
sewardjdd40fdf2006-12-24 02:20:24 +00003994 if (st->Ist.WrTmp.tmp != var)
sewardj08210532004-12-29 17:09:11 +00003995 continue;
sewardjdd40fdf2006-12-24 02:20:24 +00003996 e = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +00003997 if (!isAdd32OrSub32(e, &vv, &ii))
3998 break;
3999 var = vv;
4000 con += ii;
4001 }
4002 if (j == -1)
4003 /* no earlier binding for var .. ill-formed IR */
4004 vpanic("collapseChain");
4005
4006 /* so, did we find anything interesting? */
4007 if (var == tmp)
4008 return False; /* no .. */
4009
4010 *tmp2 = var;
4011 *i32 = con;
4012 return True;
4013}
4014
4015
4016/* ------- Main function for Add32/Sub32 chain collapsing ------ */
4017
sewardjdd40fdf2006-12-24 02:20:24 +00004018static void collapse_AddSub_chains_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00004019{
4020 IRStmt *st;
4021 IRTemp var, var2;
4022 Int i, con, con2;
4023
4024 for (i = bb->stmts_used-1; i >= 0; i--) {
4025 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00004026 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00004027 continue;
4028
4029 /* Try to collapse 't1 = Add32/Sub32(t2, con)'. */
4030
sewardjdd40fdf2006-12-24 02:20:24 +00004031 if (st->tag == Ist_WrTmp
4032 && isAdd32OrSub32(st->Ist.WrTmp.data, &var, &con)) {
sewardj08210532004-12-29 17:09:11 +00004033
4034 /* So e1 is of the form Add32(var,con) or Sub32(var,-con).
4035 Find out if var can be expressed as var2 + con2. */
4036 if (collapseChain(bb, i-1, var, &var2, &con2)) {
4037 if (DEBUG_IROPT) {
4038 vex_printf("replacing1 ");
4039 ppIRStmt(st);
4040 vex_printf(" with ");
4041 }
4042 con2 += con;
4043 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00004044 = IRStmt_WrTmp(
4045 st->Ist.WrTmp.tmp,
sewardj08210532004-12-29 17:09:11 +00004046 (con2 >= 0)
4047 ? IRExpr_Binop(Iop_Add32,
sewardjdd40fdf2006-12-24 02:20:24 +00004048 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00004049 IRExpr_Const(IRConst_U32(con2)))
4050 : IRExpr_Binop(Iop_Sub32,
sewardjdd40fdf2006-12-24 02:20:24 +00004051 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00004052 IRExpr_Const(IRConst_U32(-con2)))
4053 );
4054 if (DEBUG_IROPT) {
4055 ppIRStmt(bb->stmts[i]);
4056 vex_printf("\n");
4057 }
4058 }
4059
4060 continue;
4061 }
4062
4063 /* Try to collapse 't1 = GetI[t2, con]'. */
4064
sewardjdd40fdf2006-12-24 02:20:24 +00004065 if (st->tag == Ist_WrTmp
4066 && st->Ist.WrTmp.data->tag == Iex_GetI
4067 && st->Ist.WrTmp.data->Iex.GetI.ix->tag == Iex_RdTmp
4068 && collapseChain(bb, i-1, st->Ist.WrTmp.data->Iex.GetI.ix
4069 ->Iex.RdTmp.tmp, &var2, &con2)) {
sewardj08210532004-12-29 17:09:11 +00004070 if (DEBUG_IROPT) {
4071 vex_printf("replacing3 ");
4072 ppIRStmt(st);
4073 vex_printf(" with ");
4074 }
sewardjdd40fdf2006-12-24 02:20:24 +00004075 con2 += st->Ist.WrTmp.data->Iex.GetI.bias;
sewardj08210532004-12-29 17:09:11 +00004076 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00004077 = IRStmt_WrTmp(
4078 st->Ist.WrTmp.tmp,
4079 IRExpr_GetI(st->Ist.WrTmp.data->Iex.GetI.descr,
4080 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00004081 con2));
4082 if (DEBUG_IROPT) {
4083 ppIRStmt(bb->stmts[i]);
4084 vex_printf("\n");
4085 }
4086 continue;
4087 }
4088
4089 /* Perhaps st is PutI[t, con] ? */
floriand6f38b32012-05-31 15:46:18 +00004090 IRPutI *puti = st->Ist.PutI.details;
sewardj08210532004-12-29 17:09:11 +00004091 if (st->tag == Ist_PutI
floriand6f38b32012-05-31 15:46:18 +00004092 && puti->ix->tag == Iex_RdTmp
4093 && collapseChain(bb, i-1, puti->ix->Iex.RdTmp.tmp,
sewardj08210532004-12-29 17:09:11 +00004094 &var2, &con2)) {
4095 if (DEBUG_IROPT) {
4096 vex_printf("replacing2 ");
4097 ppIRStmt(st);
4098 vex_printf(" with ");
4099 }
floriand6f38b32012-05-31 15:46:18 +00004100 con2 += puti->bias;
sewardj08210532004-12-29 17:09:11 +00004101 bb->stmts[i]
floriand6f38b32012-05-31 15:46:18 +00004102 = IRStmt_PutI(mkIRPutI(puti->descr,
4103 IRExpr_RdTmp(var2),
4104 con2,
4105 puti->data));
sewardj08210532004-12-29 17:09:11 +00004106 if (DEBUG_IROPT) {
4107 ppIRStmt(bb->stmts[i]);
4108 vex_printf("\n");
4109 }
4110 continue;
4111 }
4112
4113 } /* for */
4114}
4115
4116
4117/*---------------------------------------------------------------*/
4118/*--- PutI/GetI transformations ---*/
4119/*---------------------------------------------------------------*/
4120
sewardj08210532004-12-29 17:09:11 +00004121/* Given the parts (descr, tmp, bias) for a GetI, scan backwards from
4122 the given starting point to find, if any, a PutI which writes
4123 exactly the same piece of guest state, and so return the expression
4124 that the PutI writes. This is the core of PutI-GetI forwarding. */
4125
4126static
sewardjdd40fdf2006-12-24 02:20:24 +00004127IRExpr* findPutI ( IRSB* bb, Int startHere,
4128 IRRegArray* descrG, IRExpr* ixG, Int biasG )
sewardj08210532004-12-29 17:09:11 +00004129{
4130 Int j;
4131 IRStmt* st;
4132 GSAliasing relation;
4133
4134 if (0) {
4135 vex_printf("\nfindPutI ");
sewardjdd40fdf2006-12-24 02:20:24 +00004136 ppIRRegArray(descrG);
sewardj08210532004-12-29 17:09:11 +00004137 vex_printf(" ");
4138 ppIRExpr(ixG);
4139 vex_printf(" %d\n", biasG);
4140 }
4141
4142 /* Scan backwards in bb from startHere to find a suitable PutI
4143 binding for (descrG, ixG, biasG), if any. */
4144
4145 for (j = startHere; j >= 0; j--) {
4146 st = bb->stmts[j];
sewardj8bee6d12005-03-22 02:24:05 +00004147 if (st->tag == Ist_NoOp)
4148 continue;
sewardj08210532004-12-29 17:09:11 +00004149
4150 if (st->tag == Ist_Put) {
4151 /* Non-indexed Put. This can't give a binding, but we do
4152 need to check it doesn't invalidate the search by
4153 overlapping any part of the indexed guest state. */
4154
4155 relation
4156 = getAliasingRelation_IC(
4157 descrG, ixG,
4158 st->Ist.Put.offset,
4159 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
4160
4161 if (relation == NoAlias) {
4162 /* we're OK; keep going */
4163 continue;
4164 } else {
4165 /* relation == UnknownAlias || relation == ExactAlias */
4166 /* If this assertion fails, we've found a Put which writes
4167 an area of guest state which is read by a GetI. Which
4168 is unlikely (although not per se wrong). */
4169 vassert(relation != ExactAlias);
4170 /* This Put potentially writes guest state that the GetI
4171 reads; we must fail. */
4172 return NULL;
4173 }
4174 }
4175
4176 if (st->tag == Ist_PutI) {
floriand6f38b32012-05-31 15:46:18 +00004177 IRPutI *puti = st->Ist.PutI.details;
sewardj08210532004-12-29 17:09:11 +00004178
4179 relation = getAliasingRelation_II(
4180 descrG, ixG, biasG,
floriand6f38b32012-05-31 15:46:18 +00004181 puti->descr,
4182 puti->ix,
4183 puti->bias
sewardj08210532004-12-29 17:09:11 +00004184 );
4185
4186 if (relation == NoAlias) {
4187 /* This PutI definitely doesn't overlap. Ignore it and
4188 keep going. */
4189 continue; /* the for j loop */
4190 }
4191
4192 if (relation == UnknownAlias) {
4193 /* We don't know if this PutI writes to the same guest
4194 state that the GetI, or not. So we have to give up. */
4195 return NULL;
4196 }
4197
4198 /* Otherwise, we've found what we're looking for. */
4199 vassert(relation == ExactAlias);
floriand6f38b32012-05-31 15:46:18 +00004200 return puti->data;
sewardj08210532004-12-29 17:09:11 +00004201
4202 } /* if (st->tag == Ist_PutI) */
4203
4204 if (st->tag == Ist_Dirty) {
4205 /* Be conservative. If the dirty call has any guest effects at
4206 all, give up. We could do better -- only give up if there
4207 are any guest writes/modifies. */
4208 if (st->Ist.Dirty.details->nFxState > 0)
4209 return NULL;
4210 }
4211
4212 } /* for */
4213
4214 /* No valid replacement was found. */
4215 return NULL;
4216}
4217
4218
4219
4220/* Assuming pi is a PutI stmt, is s2 identical to it (in the sense
4221 that it writes exactly the same piece of guest state) ? Safe
4222 answer: False. */
4223
4224static Bool identicalPutIs ( IRStmt* pi, IRStmt* s2 )
4225{
4226 vassert(pi->tag == Ist_PutI);
4227 if (s2->tag != Ist_PutI)
4228 return False;
4229
floriand6f38b32012-05-31 15:46:18 +00004230 IRPutI *p1 = pi->Ist.PutI.details;
4231 IRPutI *p2 = s2->Ist.PutI.details;
4232
sewardj9d2e7692005-02-07 01:11:31 +00004233 return toBool(
4234 getAliasingRelation_II(
floriand6f38b32012-05-31 15:46:18 +00004235 p1->descr, p1->ix, p1->bias,
4236 p2->descr, p2->ix, p2->bias
sewardj08210532004-12-29 17:09:11 +00004237 )
sewardj9d2e7692005-02-07 01:11:31 +00004238 == ExactAlias
4239 );
sewardj08210532004-12-29 17:09:11 +00004240}
4241
4242
4243/* Assuming pi is a PutI stmt, is s2 a Get/GetI/Put/PutI which might
4244 overlap it? Safe answer: True. Note, we could do a lot better
4245 than this if needed. */
4246
4247static
4248Bool guestAccessWhichMightOverlapPutI (
4249 IRTypeEnv* tyenv, IRStmt* pi, IRStmt* s2
4250 )
4251{
4252 GSAliasing relation;
4253 UInt minoffP, maxoffP;
4254
4255 vassert(pi->tag == Ist_PutI);
floriand6f38b32012-05-31 15:46:18 +00004256
4257 IRPutI *p1 = pi->Ist.PutI.details;
4258
4259 getArrayBounds(p1->descr, &minoffP, &maxoffP);
sewardj08210532004-12-29 17:09:11 +00004260 switch (s2->tag) {
4261
sewardjd2445f62005-03-21 00:15:53 +00004262 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00004263 case Ist_IMark:
4264 return False;
4265
sewardjc4356f02007-11-09 21:15:04 +00004266 case Ist_MBE:
sewardj5a9ffab2005-05-12 17:55:01 +00004267 case Ist_AbiHint:
4268 /* just be paranoid ... these should be rare. */
sewardjbb3f52d2005-01-07 14:14:50 +00004269 return True;
4270
sewardje9d8a262009-07-01 08:06:34 +00004271 case Ist_CAS:
4272 /* This is unbelievably lame, but it's probably not
4273 significant from a performance point of view. Really, a
4274 CAS is a load-store op, so it should be safe to say False.
4275 However .. */
4276 return True;
4277
sewardj08210532004-12-29 17:09:11 +00004278 case Ist_Dirty:
4279 /* If the dirty call has any guest effects at all, give up.
4280 Probably could do better. */
4281 if (s2->Ist.Dirty.details->nFxState > 0)
4282 return True;
4283 return False;
4284
4285 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00004286 vassert(isIRAtom(s2->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +00004287 relation
4288 = getAliasingRelation_IC(
floriand6f38b32012-05-31 15:46:18 +00004289 p1->descr, p1->ix,
sewardj08210532004-12-29 17:09:11 +00004290 s2->Ist.Put.offset,
4291 typeOfIRExpr(tyenv,s2->Ist.Put.data)
4292 );
4293 goto have_relation;
4294
floriand6f38b32012-05-31 15:46:18 +00004295 case Ist_PutI: {
4296 IRPutI *p2 = s2->Ist.PutI.details;
4297
4298 vassert(isIRAtom(p2->ix));
4299 vassert(isIRAtom(p2->data));
sewardj08210532004-12-29 17:09:11 +00004300 relation
4301 = getAliasingRelation_II(
floriand6f38b32012-05-31 15:46:18 +00004302 p1->descr, p1->ix, p1->bias,
4303 p2->descr, p2->ix, p2->bias
sewardj08210532004-12-29 17:09:11 +00004304 );
4305 goto have_relation;
floriand6f38b32012-05-31 15:46:18 +00004306 }
sewardj08210532004-12-29 17:09:11 +00004307
sewardjdd40fdf2006-12-24 02:20:24 +00004308 case Ist_WrTmp:
4309 if (s2->Ist.WrTmp.data->tag == Iex_GetI) {
sewardj08210532004-12-29 17:09:11 +00004310 relation
4311 = getAliasingRelation_II(
floriand6f38b32012-05-31 15:46:18 +00004312 p1->descr, p1->ix, p1->bias,
sewardjdd40fdf2006-12-24 02:20:24 +00004313 s2->Ist.WrTmp.data->Iex.GetI.descr,
4314 s2->Ist.WrTmp.data->Iex.GetI.ix,
4315 s2->Ist.WrTmp.data->Iex.GetI.bias
sewardj08210532004-12-29 17:09:11 +00004316 );
4317 goto have_relation;
4318 }
sewardjdd40fdf2006-12-24 02:20:24 +00004319 if (s2->Ist.WrTmp.data->tag == Iex_Get) {
sewardj08210532004-12-29 17:09:11 +00004320 relation
4321 = getAliasingRelation_IC(
floriand6f38b32012-05-31 15:46:18 +00004322 p1->descr, p1->ix,
sewardjdd40fdf2006-12-24 02:20:24 +00004323 s2->Ist.WrTmp.data->Iex.Get.offset,
4324 s2->Ist.WrTmp.data->Iex.Get.ty
sewardj08210532004-12-29 17:09:11 +00004325 );
4326 goto have_relation;
4327 }
4328 return False;
4329
sewardjaf1ceca2005-06-30 23:31:27 +00004330 case Ist_Store:
4331 vassert(isIRAtom(s2->Ist.Store.addr));
4332 vassert(isIRAtom(s2->Ist.Store.data));
sewardj08210532004-12-29 17:09:11 +00004333 return False;
4334
4335 default:
4336 vex_printf("\n"); ppIRStmt(s2); vex_printf("\n");
4337 vpanic("guestAccessWhichMightOverlapPutI");
4338 }
4339
4340 have_relation:
4341 if (relation == NoAlias)
4342 return False;
4343 else
4344 return True; /* ExactAlias or UnknownAlias */
4345}
4346
4347
4348
4349/* ---------- PutI/GetI transformations main functions --------- */
4350
4351/* Remove redundant GetIs, to the extent that they can be detected.
4352 bb is modified in-place. */
4353
4354static
sewardjdd40fdf2006-12-24 02:20:24 +00004355void do_redundant_GetI_elimination ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00004356{
4357 Int i;
4358 IRStmt* st;
4359
4360 for (i = bb->stmts_used-1; i >= 0; i--) {
4361 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00004362 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00004363 continue;
4364
sewardjdd40fdf2006-12-24 02:20:24 +00004365 if (st->tag == Ist_WrTmp
4366 && st->Ist.WrTmp.data->tag == Iex_GetI
4367 && st->Ist.WrTmp.data->Iex.GetI.ix->tag == Iex_RdTmp) {
4368 IRRegArray* descr = st->Ist.WrTmp.data->Iex.GetI.descr;
4369 IRExpr* ix = st->Ist.WrTmp.data->Iex.GetI.ix;
4370 Int bias = st->Ist.WrTmp.data->Iex.GetI.bias;
4371 IRExpr* replacement = findPutI(bb, i-1, descr, ix, bias);
sewardj08210532004-12-29 17:09:11 +00004372 if (replacement
sewardj496a58d2005-03-20 18:44:44 +00004373 && isIRAtom(replacement)
sewardj08210532004-12-29 17:09:11 +00004374 /* Make sure we're doing a type-safe transformation! */
4375 && typeOfIRExpr(bb->tyenv, replacement) == descr->elemTy) {
4376 if (DEBUG_IROPT) {
4377 vex_printf("rGI: ");
sewardjdd40fdf2006-12-24 02:20:24 +00004378 ppIRExpr(st->Ist.WrTmp.data);
sewardj08210532004-12-29 17:09:11 +00004379 vex_printf(" -> ");
4380 ppIRExpr(replacement);
4381 vex_printf("\n");
4382 }
sewardjdd40fdf2006-12-24 02:20:24 +00004383 bb->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, replacement);
sewardj08210532004-12-29 17:09:11 +00004384 }
4385 }
4386 }
4387
4388}
4389
4390
4391/* Remove redundant PutIs, to the extent which they can be detected.
4392 bb is modified in-place. */
4393
4394static
sewardjdd40fdf2006-12-24 02:20:24 +00004395void do_redundant_PutI_elimination ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00004396{
4397 Int i, j;
4398 Bool delete;
4399 IRStmt *st, *stj;
4400
philippe6c46bef2012-08-14 22:29:01 +00004401 vassert(vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn);
philippec8e2f982012-08-01 22:04:13 +00004402
sewardj08210532004-12-29 17:09:11 +00004403 for (i = 0; i < bb->stmts_used; i++) {
4404 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00004405 if (st->tag != Ist_PutI)
sewardj08210532004-12-29 17:09:11 +00004406 continue;
4407 /* Ok, search forwards from here to see if we can find another
4408 PutI which makes this one redundant, and dodging various
4409 hazards. Search forwards:
4410 * If conditional exit, give up (because anything after that
4411 does not postdominate this put).
4412 * If a Get which might overlap, give up (because this PutI
4413 not necessarily dead).
4414 * If a Put which is identical, stop with success.
4415 * If a Put which might overlap, but is not identical, give up.
4416 * If a dirty helper call which might write guest state, give up.
4417 * If a Put which definitely doesn't overlap, or any other
4418 kind of stmt, continue.
4419 */
4420 delete = False;
4421 for (j = i+1; j < bb->stmts_used; j++) {
4422 stj = bb->stmts[j];
sewardj8bee6d12005-03-22 02:24:05 +00004423 if (stj->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00004424 continue;
4425 if (identicalPutIs(st, stj)) {
4426 /* success! */
4427 delete = True;
4428 break;
4429 }
4430 if (stj->tag == Ist_Exit)
4431 /* give up */
4432 break;
4433 if (st->tag == Ist_Dirty)
4434 /* give up; could do better here */
4435 break;
4436 if (guestAccessWhichMightOverlapPutI(bb->tyenv, st, stj))
4437 /* give up */
4438 break;
4439 }
4440
4441 if (delete) {
4442 if (DEBUG_IROPT) {
4443 vex_printf("rPI: ");
4444 ppIRStmt(st);
4445 vex_printf("\n");
4446 }
sewardjd2445f62005-03-21 00:15:53 +00004447 bb->stmts[i] = IRStmt_NoOp();
sewardj08210532004-12-29 17:09:11 +00004448 }
4449
4450 }
4451}
4452
4453
4454/*---------------------------------------------------------------*/
4455/*--- Loop unrolling ---*/
4456/*---------------------------------------------------------------*/
4457
4458/* Adjust all tmp values (names) in e by delta. e is destructively
4459 modified. */
4460
4461static void deltaIRExpr ( IRExpr* e, Int delta )
4462{
4463 Int i;
4464 switch (e->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +00004465 case Iex_RdTmp:
4466 e->Iex.RdTmp.tmp += delta;
sewardj08210532004-12-29 17:09:11 +00004467 break;
4468 case Iex_Get:
4469 case Iex_Const:
4470 break;
4471 case Iex_GetI:
4472 deltaIRExpr(e->Iex.GetI.ix, delta);
4473 break;
sewardj1a866b42006-02-09 02:54:03 +00004474 case Iex_Qop:
florian96d7cc32012-06-01 20:41:24 +00004475 deltaIRExpr(e->Iex.Qop.details->arg1, delta);
4476 deltaIRExpr(e->Iex.Qop.details->arg2, delta);
4477 deltaIRExpr(e->Iex.Qop.details->arg3, delta);
4478 deltaIRExpr(e->Iex.Qop.details->arg4, delta);
sewardj1a866b42006-02-09 02:54:03 +00004479 break;
sewardjb183b852006-02-03 16:08:03 +00004480 case Iex_Triop:
florian420bfa92012-06-02 20:29:22 +00004481 deltaIRExpr(e->Iex.Triop.details->arg1, delta);
4482 deltaIRExpr(e->Iex.Triop.details->arg2, delta);
4483 deltaIRExpr(e->Iex.Triop.details->arg3, delta);
sewardjb183b852006-02-03 16:08:03 +00004484 break;
sewardj08210532004-12-29 17:09:11 +00004485 case Iex_Binop:
4486 deltaIRExpr(e->Iex.Binop.arg1, delta);
4487 deltaIRExpr(e->Iex.Binop.arg2, delta);
4488 break;
4489 case Iex_Unop:
4490 deltaIRExpr(e->Iex.Unop.arg, delta);
4491 break;
sewardjaf1ceca2005-06-30 23:31:27 +00004492 case Iex_Load:
4493 deltaIRExpr(e->Iex.Load.addr, delta);
sewardj08210532004-12-29 17:09:11 +00004494 break;
4495 case Iex_CCall:
4496 for (i = 0; e->Iex.CCall.args[i]; i++)
4497 deltaIRExpr(e->Iex.CCall.args[i], delta);
4498 break;
florian99dd03e2013-01-29 03:56:06 +00004499 case Iex_ITE:
4500 deltaIRExpr(e->Iex.ITE.cond, delta);
4501 deltaIRExpr(e->Iex.ITE.iftrue, delta);
4502 deltaIRExpr(e->Iex.ITE.iffalse, delta);
sewardj08210532004-12-29 17:09:11 +00004503 break;
4504 default:
4505 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4506 vpanic("deltaIRExpr");
4507 }
4508}
4509
4510/* Adjust all tmp values (names) in st by delta. st is destructively
4511 modified. */
4512
4513static void deltaIRStmt ( IRStmt* st, Int delta )
4514{
4515 Int i;
4516 IRDirty* d;
4517 switch (st->tag) {
sewardjd2445f62005-03-21 00:15:53 +00004518 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00004519 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00004520 case Ist_MBE:
sewardjf1689312005-03-16 18:19:10 +00004521 break;
sewardj5a9ffab2005-05-12 17:55:01 +00004522 case Ist_AbiHint:
4523 deltaIRExpr(st->Ist.AbiHint.base, delta);
sewardj478646f2008-05-01 20:13:04 +00004524 deltaIRExpr(st->Ist.AbiHint.nia, delta);
sewardj5a9ffab2005-05-12 17:55:01 +00004525 break;
sewardj08210532004-12-29 17:09:11 +00004526 case Ist_Put:
4527 deltaIRExpr(st->Ist.Put.data, delta);
4528 break;
4529 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +00004530 deltaIRExpr(st->Ist.PutI.details->ix, delta);
4531 deltaIRExpr(st->Ist.PutI.details->data, delta);
sewardj08210532004-12-29 17:09:11 +00004532 break;
sewardjdd40fdf2006-12-24 02:20:24 +00004533 case Ist_WrTmp:
4534 st->Ist.WrTmp.tmp += delta;
4535 deltaIRExpr(st->Ist.WrTmp.data, delta);
sewardj08210532004-12-29 17:09:11 +00004536 break;
4537 case Ist_Exit:
4538 deltaIRExpr(st->Ist.Exit.guard, delta);
4539 break;
sewardjaf1ceca2005-06-30 23:31:27 +00004540 case Ist_Store:
4541 deltaIRExpr(st->Ist.Store.addr, delta);
4542 deltaIRExpr(st->Ist.Store.data, delta);
sewardj08210532004-12-29 17:09:11 +00004543 break;
sewardjcfe046e2013-01-17 14:23:53 +00004544 case Ist_StoreG: {
4545 IRStoreG* sg = st->Ist.StoreG.details;
4546 deltaIRExpr(sg->addr, delta);
4547 deltaIRExpr(sg->data, delta);
4548 deltaIRExpr(sg->guard, delta);
4549 break;
4550 }
4551 case Ist_LoadG: {
4552 IRLoadG* lg = st->Ist.LoadG.details;
4553 lg->dst += delta;
4554 deltaIRExpr(lg->addr, delta);
4555 deltaIRExpr(lg->alt, delta);
4556 deltaIRExpr(lg->guard, delta);
4557 break;
4558 }
sewardje9d8a262009-07-01 08:06:34 +00004559 case Ist_CAS:
4560 if (st->Ist.CAS.details->oldHi != IRTemp_INVALID)
4561 st->Ist.CAS.details->oldHi += delta;
4562 st->Ist.CAS.details->oldLo += delta;
4563 deltaIRExpr(st->Ist.CAS.details->addr, delta);
4564 if (st->Ist.CAS.details->expdHi)
4565 deltaIRExpr(st->Ist.CAS.details->expdHi, delta);
4566 deltaIRExpr(st->Ist.CAS.details->expdLo, delta);
4567 if (st->Ist.CAS.details->dataHi)
4568 deltaIRExpr(st->Ist.CAS.details->dataHi, delta);
4569 deltaIRExpr(st->Ist.CAS.details->dataLo, delta);
4570 break;
sewardje768e922009-11-26 17:17:37 +00004571 case Ist_LLSC:
4572 st->Ist.LLSC.result += delta;
4573 deltaIRExpr(st->Ist.LLSC.addr, delta);
4574 if (st->Ist.LLSC.storedata)
4575 deltaIRExpr(st->Ist.LLSC.storedata, delta);
4576 break;
sewardj08210532004-12-29 17:09:11 +00004577 case Ist_Dirty:
4578 d = st->Ist.Dirty.details;
4579 deltaIRExpr(d->guard, delta);
florian2accb5e2013-09-03 21:48:02 +00004580 for (i = 0; d->args[i]; i++) {
4581 IRExpr* arg = d->args[i];
4582 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
4583 deltaIRExpr(arg, delta);
4584 }
sewardj08210532004-12-29 17:09:11 +00004585 if (d->tmp != IRTemp_INVALID)
4586 d->tmp += delta;
4587 if (d->mAddr)
4588 deltaIRExpr(d->mAddr, delta);
4589 break;
4590 default:
4591 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
4592 vpanic("deltaIRStmt");
4593 }
4594}
4595
4596
4597/* If possible, return a loop-unrolled version of bb0. The original
4598 is changed. If not possible, return NULL. */
4599
4600/* The two schemas considered are:
4601
4602 X: BODY; goto X
4603
4604 which unrolls to (eg) X: BODY;BODY; goto X
4605
4606 and
4607
4608 X: BODY; if (c) goto X; goto Y
4609 which trivially transforms to
4610 X: BODY; if (!c) goto Y; goto X;
4611 so it falls in the scope of the first case.
4612
4613 X and Y must be literal (guest) addresses.
4614*/
4615
sewardjdd40fdf2006-12-24 02:20:24 +00004616static Int calc_unroll_factor( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00004617{
4618 Int n_stmts, i;
4619
4620 n_stmts = 0;
sewardj0ddbf792005-04-04 23:12:54 +00004621 for (i = 0; i < bb->stmts_used; i++) {
4622 if (bb->stmts[i]->tag != Ist_NoOp)
4623 n_stmts++;
4624 }
sewardj08210532004-12-29 17:09:11 +00004625
4626 if (n_stmts <= vex_control.iropt_unroll_thresh/8) {
4627 if (vex_control.iropt_verbosity > 0)
4628 vex_printf("vex iropt: 8 x unrolling (%d sts -> %d sts)\n",
4629 n_stmts, 8* n_stmts);
4630 return 8;
4631 }
4632 if (n_stmts <= vex_control.iropt_unroll_thresh/4) {
4633 if (vex_control.iropt_verbosity > 0)
4634 vex_printf("vex iropt: 4 x unrolling (%d sts -> %d sts)\n",
4635 n_stmts, 4* n_stmts);
4636 return 4;
4637 }
4638
4639 if (n_stmts <= vex_control.iropt_unroll_thresh/2) {
4640 if (vex_control.iropt_verbosity > 0)
4641 vex_printf("vex iropt: 2 x unrolling (%d sts -> %d sts)\n",
4642 n_stmts, 2* n_stmts);
4643 return 2;
4644 }
4645
4646 if (vex_control.iropt_verbosity > 0)
4647 vex_printf("vex iropt: not unrolling (%d sts)\n", n_stmts);
4648
4649 return 1;
4650}
4651
4652
floriand4cc0de2015-01-02 11:44:12 +00004653static IRSB* maybe_loop_unroll_BB ( IRSB* bb0, Addr my_addr )
sewardj08210532004-12-29 17:09:11 +00004654{
4655 Int i, j, jmax, n_vars;
4656 Bool xxx_known;
4657 Addr64 xxx_value, yyy_value;
4658 IRExpr* udst;
4659 IRStmt* st;
4660 IRConst* con;
sewardjdd40fdf2006-12-24 02:20:24 +00004661 IRSB *bb1, *bb2;
sewardj08210532004-12-29 17:09:11 +00004662 Int unroll_factor;
4663
4664 if (vex_control.iropt_unroll_thresh <= 0)
4665 return NULL;
4666
4667 /* First off, figure out if we can unroll this loop. Do this
4668 without modifying bb0. */
4669
4670 if (bb0->jumpkind != Ijk_Boring)
4671 return NULL;
4672
4673 xxx_known = False;
4674 xxx_value = 0;
4675
4676 /* Extract the next-guest address. If it isn't a literal, we
4677 have to give up. */
4678
4679 udst = bb0->next;
4680 if (udst->tag == Iex_Const
4681 && (udst->Iex.Const.con->tag == Ico_U32
4682 || udst->Iex.Const.con->tag == Ico_U64)) {
4683 /* The BB ends in a jump to a literal location. */
4684 xxx_known = True;
4685 xxx_value = udst->Iex.Const.con->tag == Ico_U64
4686 ? udst->Iex.Const.con->Ico.U64
4687 : (Addr64)(udst->Iex.Const.con->Ico.U32);
4688 }
4689
4690 if (!xxx_known)
4691 return NULL;
4692
4693 /* Now we know the BB ends to a jump to a literal location. If
4694 it's a jump to itself (viz, idiom #1), move directly to the
4695 unrolling stage, first cloning the bb so the original isn't
4696 modified. */
4697 if (xxx_value == my_addr) {
4698 unroll_factor = calc_unroll_factor( bb0 );
4699 if (unroll_factor < 2)
4700 return NULL;
sewardjdd40fdf2006-12-24 02:20:24 +00004701 bb1 = deepCopyIRSB( bb0 );
sewardj08210532004-12-29 17:09:11 +00004702 bb0 = NULL;
4703 udst = NULL; /* is now invalid */
4704 goto do_unroll;
4705 }
4706
4707 /* Search for the second idiomatic form:
4708 X: BODY; if (c) goto X; goto Y
4709 We know Y, but need to establish that the last stmt
4710 is 'if (c) goto X'.
4711 */
4712 yyy_value = xxx_value;
4713 for (i = bb0->stmts_used-1; i >= 0; i--)
4714 if (bb0->stmts[i])
4715 break;
4716
4717 if (i < 0)
4718 return NULL; /* block with no stmts. Strange. */
4719
4720 st = bb0->stmts[i];
4721 if (st->tag != Ist_Exit)
4722 return NULL;
4723 if (st->Ist.Exit.jk != Ijk_Boring)
4724 return NULL;
4725
4726 con = st->Ist.Exit.dst;
4727 vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
4728
4729 xxx_value = con->tag == Ico_U64
4730 ? st->Ist.Exit.dst->Ico.U64
4731 : (Addr64)(st->Ist.Exit.dst->Ico.U32);
4732
4733 /* If this assertion fails, we have some kind of type error. */
4734 vassert(con->tag == udst->Iex.Const.con->tag);
4735
4736 if (xxx_value != my_addr)
4737 /* We didn't find either idiom. Give up. */
4738 return NULL;
4739
4740 /* Ok, we found idiom #2. Copy the BB, switch around the xxx and
4741 yyy values (which makes it look like idiom #1), and go into
4742 unrolling proper. This means finding (again) the last stmt, in
4743 the copied BB. */
4744
4745 unroll_factor = calc_unroll_factor( bb0 );
4746 if (unroll_factor < 2)
4747 return NULL;
4748
sewardjdd40fdf2006-12-24 02:20:24 +00004749 bb1 = deepCopyIRSB( bb0 );
sewardj08210532004-12-29 17:09:11 +00004750 bb0 = NULL;
4751 udst = NULL; /* is now invalid */
4752 for (i = bb1->stmts_used-1; i >= 0; i--)
4753 if (bb1->stmts[i])
4754 break;
4755
4756 /* The next bunch of assertions should be true since we already
4757 found and checked the last stmt in the original bb. */
4758
4759 vassert(i >= 0);
4760
4761 st = bb1->stmts[i];
4762 vassert(st->tag == Ist_Exit);
4763
4764 con = st->Ist.Exit.dst;
4765 vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
4766
4767 udst = bb1->next;
4768 vassert(udst->tag == Iex_Const);
4769 vassert(udst->Iex.Const.con->tag == Ico_U32
4770 || udst->Iex.Const.con->tag == Ico_U64);
4771 vassert(con->tag == udst->Iex.Const.con->tag);
4772
4773 /* switch the xxx and yyy fields around */
4774 if (con->tag == Ico_U64) {
4775 udst->Iex.Const.con->Ico.U64 = xxx_value;
4776 con->Ico.U64 = yyy_value;
4777 } else {
4778 udst->Iex.Const.con->Ico.U32 = (UInt)xxx_value;
cerion57b4c6d2005-02-22 11:07:35 +00004779 con->Ico.U32 = (UInt)yyy_value;
sewardj08210532004-12-29 17:09:11 +00004780 }
4781
4782 /* negate the test condition */
4783 st->Ist.Exit.guard
sewardjdd40fdf2006-12-24 02:20:24 +00004784 = IRExpr_Unop(Iop_Not1,deepCopyIRExpr(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +00004785
4786 /* --- The unroller proper. Both idioms are by now --- */
4787 /* --- now converted to idiom 1. --- */
4788
4789 do_unroll:
4790
4791 vassert(unroll_factor == 2
4792 || unroll_factor == 4
4793 || unroll_factor == 8);
4794
4795 jmax = unroll_factor==8 ? 3 : (unroll_factor==4 ? 2 : 1);
4796 for (j = 1; j <= jmax; j++) {
4797
4798 n_vars = bb1->tyenv->types_used;
4799
sewardjdd40fdf2006-12-24 02:20:24 +00004800 bb2 = deepCopyIRSB(bb1);
sewardj08210532004-12-29 17:09:11 +00004801 for (i = 0; i < n_vars; i++)
4802 (void)newIRTemp(bb1->tyenv, bb2->tyenv->types[i]);
4803
4804 for (i = 0; i < bb2->stmts_used; i++) {
sewardj08210532004-12-29 17:09:11 +00004805 /* deltaIRStmt destructively modifies the stmt, but
4806 that's OK since bb2 is a complete fresh copy of bb1. */
4807 deltaIRStmt(bb2->stmts[i], n_vars);
sewardjdd40fdf2006-12-24 02:20:24 +00004808 addStmtToIRSB(bb1, bb2->stmts[i]);
sewardj08210532004-12-29 17:09:11 +00004809 }
4810 }
4811
4812 if (DEBUG_IROPT) {
floriand4cc0de2015-01-02 11:44:12 +00004813 vex_printf("\nUNROLLED (%lx)\n", my_addr);
sewardjdd40fdf2006-12-24 02:20:24 +00004814 ppIRSB(bb1);
sewardj08210532004-12-29 17:09:11 +00004815 vex_printf("\n");
4816 }
4817
4818 /* Flattening; sigh. The unroller succeeds in breaking flatness
4819 by negating the test condition. This should be fixed properly.
4820 For the moment use this shotgun approach. */
4821 return flatten_BB(bb1);
4822}
4823
4824
4825/*---------------------------------------------------------------*/
sewardj29632392004-08-22 02:38:11 +00004826/*--- The tree builder ---*/
4827/*---------------------------------------------------------------*/
4828
sewardj08210532004-12-29 17:09:11 +00004829/* This isn't part of IR optimisation. Really it's a pass done prior
4830 to instruction selection, which improves the code that the
4831 instruction selector can produce. */
4832
sewardjf9517d02005-11-28 13:39:37 +00004833/* --- The 'tmp' environment is the central data structure here --- */
sewardj29632392004-08-22 02:38:11 +00004834
sewardjf9517d02005-11-28 13:39:37 +00004835/* The number of outstanding bindings we're prepared to track.
4836 The number of times the env becomes full and we have to dump
4837 the oldest binding (hence reducing code quality) falls very
4838 rapidly as the env size increases. 8 gives reasonable performance
4839 under most circumstances. */
4840#define A_NENV 10
4841
florian740da722013-09-11 17:58:32 +00004842/* An interval. Used to record the bytes in the guest state accessed
4843 by a Put[I] statement or by (one or more) Get[I] expression(s). In
4844 case of several Get[I] expressions, the lower/upper bounds are recorded.
4845 This is conservative but cheap.
4846 E.g. a Put of 8 bytes at address 100 would be recorded as [100,107].
4847 E.g. an expression that reads 8 bytes at offset 100 and 4 bytes at
4848 offset 200 would be recorded as [100,203] */
4849typedef
4850 struct {
4851 Bool present;
4852 Int low;
4853 Int high;
4854 }
4855 Interval;
4856
4857static inline Bool
4858intervals_overlap(Interval i1, Interval i2)
4859{
4860 return (i1.low >= i2.low && i1.low <= i2.high) ||
4861 (i2.low >= i1.low && i2.low <= i1.high);
4862}
4863
4864static inline void
4865update_interval(Interval *i, Int low, Int high)
4866{
4867 vassert(low <= high);
4868
4869 if (i->present) {
4870 if (low < i->low) i->low = low;
4871 if (high > i->high) i->high = high;
4872 } else {
4873 i->present = True;
4874 i->low = low;
4875 i->high = high;
4876 }
4877}
4878
4879
sewardjf9517d02005-11-28 13:39:37 +00004880/* bindee == NULL === slot is not in use
4881 bindee != NULL === slot is in use
sewardj29632392004-08-22 02:38:11 +00004882*/
sewardjf9517d02005-11-28 13:39:37 +00004883typedef
4884 struct {
4885 IRTemp binder;
4886 IRExpr* bindee;
4887 Bool doesLoad;
florian740da722013-09-11 17:58:32 +00004888 /* Record the bytes of the guest state BINDEE reads from. */
4889 Interval getInterval;
sewardj17442fe2004-09-20 14:54:28 +00004890 }
sewardjf9517d02005-11-28 13:39:37 +00004891 ATmpInfo;
sewardj17442fe2004-09-20 14:54:28 +00004892
sewardjf9517d02005-11-28 13:39:37 +00004893__attribute__((unused))
4894static void ppAEnv ( ATmpInfo* env )
sewardj29632392004-08-22 02:38:11 +00004895{
sewardj17442fe2004-09-20 14:54:28 +00004896 Int i;
sewardjf9517d02005-11-28 13:39:37 +00004897 for (i = 0; i < A_NENV; i++) {
4898 vex_printf("%d tmp %d val ", i, (Int)env[i].binder);
4899 if (env[i].bindee)
4900 ppIRExpr(env[i].bindee);
4901 else
4902 vex_printf("(null)");
4903 vex_printf("\n");
sewardj29632392004-08-22 02:38:11 +00004904 }
4905}
4906
sewardjf9517d02005-11-28 13:39:37 +00004907/* --- Tree-traversal fns --- */
sewardj29632392004-08-22 02:38:11 +00004908
sewardj37d38012004-08-24 00:37:04 +00004909/* Traverse an expr, and detect if any part of it reads memory or does
4910 a Get. Be careful ... this really controls how much the
4911 tree-builder can reorder the code, so getting it right is critical.
4912*/
florian740da722013-09-11 17:58:32 +00004913static void setHints_Expr (Bool* doesLoad, Interval* getInterval, IRExpr* e )
sewardj29632392004-08-22 02:38:11 +00004914{
sewardjc41f1fb2004-08-22 09:48:08 +00004915 Int i;
sewardj29632392004-08-22 02:38:11 +00004916 switch (e->tag) {
sewardjc41f1fb2004-08-22 09:48:08 +00004917 case Iex_CCall:
4918 for (i = 0; e->Iex.CCall.args[i]; i++)
florian740da722013-09-11 17:58:32 +00004919 setHints_Expr(doesLoad, getInterval, e->Iex.CCall.args[i]);
sewardjc41f1fb2004-08-22 09:48:08 +00004920 return;
florian99dd03e2013-01-29 03:56:06 +00004921 case Iex_ITE:
florian740da722013-09-11 17:58:32 +00004922 setHints_Expr(doesLoad, getInterval, e->Iex.ITE.cond);
4923 setHints_Expr(doesLoad, getInterval, e->Iex.ITE.iftrue);
4924 setHints_Expr(doesLoad, getInterval, e->Iex.ITE.iffalse);
sewardjc41f1fb2004-08-22 09:48:08 +00004925 return;
sewardj40c80262006-02-08 19:30:46 +00004926 case Iex_Qop:
florian740da722013-09-11 17:58:32 +00004927 setHints_Expr(doesLoad, getInterval, e->Iex.Qop.details->arg1);
4928 setHints_Expr(doesLoad, getInterval, e->Iex.Qop.details->arg2);
4929 setHints_Expr(doesLoad, getInterval, e->Iex.Qop.details->arg3);
4930 setHints_Expr(doesLoad, getInterval, e->Iex.Qop.details->arg4);
sewardj40c80262006-02-08 19:30:46 +00004931 return;
sewardjb183b852006-02-03 16:08:03 +00004932 case Iex_Triop:
florian740da722013-09-11 17:58:32 +00004933 setHints_Expr(doesLoad, getInterval, e->Iex.Triop.details->arg1);
4934 setHints_Expr(doesLoad, getInterval, e->Iex.Triop.details->arg2);
4935 setHints_Expr(doesLoad, getInterval, e->Iex.Triop.details->arg3);
sewardjb183b852006-02-03 16:08:03 +00004936 return;
sewardjc41f1fb2004-08-22 09:48:08 +00004937 case Iex_Binop:
florian740da722013-09-11 17:58:32 +00004938 setHints_Expr(doesLoad, getInterval, e->Iex.Binop.arg1);
4939 setHints_Expr(doesLoad, getInterval, e->Iex.Binop.arg2);
sewardjc41f1fb2004-08-22 09:48:08 +00004940 return;
4941 case Iex_Unop:
florian740da722013-09-11 17:58:32 +00004942 setHints_Expr(doesLoad, getInterval, e->Iex.Unop.arg);
sewardjc41f1fb2004-08-22 09:48:08 +00004943 return;
sewardjaf1ceca2005-06-30 23:31:27 +00004944 case Iex_Load:
sewardjc9ad1152004-10-14 00:08:21 +00004945 *doesLoad = True;
florian740da722013-09-11 17:58:32 +00004946 setHints_Expr(doesLoad, getInterval, e->Iex.Load.addr);
sewardjc41f1fb2004-08-22 09:48:08 +00004947 return;
florian740da722013-09-11 17:58:32 +00004948 case Iex_Get: {
4949 Int low = e->Iex.Get.offset;
4950 Int high = low + sizeofIRType(e->Iex.Get.ty) - 1;
4951 update_interval(getInterval, low, high);
sewardj29632392004-08-22 02:38:11 +00004952 return;
florian740da722013-09-11 17:58:32 +00004953 }
4954 case Iex_GetI: {
4955 IRRegArray *descr = e->Iex.GetI.descr;
4956 Int size = sizeofIRType(descr->elemTy);
4957 Int low = descr->base;
4958 Int high = low + descr->nElems * size - 1;
4959 update_interval(getInterval, low, high);
4960 setHints_Expr(doesLoad, getInterval, e->Iex.GetI.ix);
sewardjf6501992004-08-27 11:58:24 +00004961 return;
florian740da722013-09-11 17:58:32 +00004962 }
sewardjdd40fdf2006-12-24 02:20:24 +00004963 case Iex_RdTmp:
sewardjc41f1fb2004-08-22 09:48:08 +00004964 case Iex_Const:
4965 return;
sewardj29632392004-08-22 02:38:11 +00004966 default:
4967 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4968 vpanic("setHints_Expr");
4969 }
4970}
4971
4972
sewardjf9517d02005-11-28 13:39:37 +00004973/* Add a binding to the front of the env and slide all the rest
4974 backwards. It should be the case that the last slot is free. */
4975static void addToEnvFront ( ATmpInfo* env, IRTemp binder, IRExpr* bindee )
sewardj29632392004-08-22 02:38:11 +00004976{
sewardjf9517d02005-11-28 13:39:37 +00004977 Int i;
4978 vassert(env[A_NENV-1].bindee == NULL);
4979 for (i = A_NENV-1; i >= 1; i--)
4980 env[i] = env[i-1];
4981 env[0].binder = binder;
4982 env[0].bindee = bindee;
4983 env[0].doesLoad = False; /* filled in later */
florian740da722013-09-11 17:58:32 +00004984 env[0].getInterval.present = False; /* filled in later */
4985 env[0].getInterval.low = -1; /* filled in later */
4986 env[0].getInterval.high = -1; /* filled in later */
sewardjf9517d02005-11-28 13:39:37 +00004987}
sewardj29632392004-08-22 02:38:11 +00004988
sewardjf9517d02005-11-28 13:39:37 +00004989/* Given uses :: array of UShort, indexed by IRTemp
4990 Add the use-occurrences of temps in this expression
4991 to the env.
4992*/
4993static void aoccCount_Expr ( UShort* uses, IRExpr* e )
4994{
4995 Int i;
sewardj29632392004-08-22 02:38:11 +00004996
sewardjf9517d02005-11-28 13:39:37 +00004997 switch (e->tag) {
4998
sewardjdd40fdf2006-12-24 02:20:24 +00004999 case Iex_RdTmp: /* the only interesting case */
5000 uses[e->Iex.RdTmp.tmp]++;
sewardj8bee6d12005-03-22 02:24:05 +00005001 return;
sewardj29632392004-08-22 02:38:11 +00005002
florian99dd03e2013-01-29 03:56:06 +00005003 case Iex_ITE:
5004 aoccCount_Expr(uses, e->Iex.ITE.cond);
5005 aoccCount_Expr(uses, e->Iex.ITE.iftrue);
5006 aoccCount_Expr(uses, e->Iex.ITE.iffalse);
sewardjf9517d02005-11-28 13:39:37 +00005007 return;
sewardj29632392004-08-22 02:38:11 +00005008
sewardj40c80262006-02-08 19:30:46 +00005009 case Iex_Qop:
florian96d7cc32012-06-01 20:41:24 +00005010 aoccCount_Expr(uses, e->Iex.Qop.details->arg1);
5011 aoccCount_Expr(uses, e->Iex.Qop.details->arg2);
5012 aoccCount_Expr(uses, e->Iex.Qop.details->arg3);
5013 aoccCount_Expr(uses, e->Iex.Qop.details->arg4);
sewardj40c80262006-02-08 19:30:46 +00005014 return;
5015
sewardjb183b852006-02-03 16:08:03 +00005016 case Iex_Triop:
florian420bfa92012-06-02 20:29:22 +00005017 aoccCount_Expr(uses, e->Iex.Triop.details->arg1);
5018 aoccCount_Expr(uses, e->Iex.Triop.details->arg2);
5019 aoccCount_Expr(uses, e->Iex.Triop.details->arg3);
sewardjb183b852006-02-03 16:08:03 +00005020 return;
5021
sewardjf9517d02005-11-28 13:39:37 +00005022 case Iex_Binop:
5023 aoccCount_Expr(uses, e->Iex.Binop.arg1);
5024 aoccCount_Expr(uses, e->Iex.Binop.arg2);
5025 return;
sewardj29632392004-08-22 02:38:11 +00005026
sewardjf9517d02005-11-28 13:39:37 +00005027 case Iex_Unop:
5028 aoccCount_Expr(uses, e->Iex.Unop.arg);
5029 return;
5030
5031 case Iex_Load:
5032 aoccCount_Expr(uses, e->Iex.Load.addr);
5033 return;
5034
5035 case Iex_CCall:
5036 for (i = 0; e->Iex.CCall.args[i]; i++)
5037 aoccCount_Expr(uses, e->Iex.CCall.args[i]);
5038 return;
5039
5040 case Iex_GetI:
5041 aoccCount_Expr(uses, e->Iex.GetI.ix);
5042 return;
5043
5044 case Iex_Const:
5045 case Iex_Get:
5046 return;
5047
5048 default:
5049 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
5050 vpanic("aoccCount_Expr");
5051 }
sewardj29632392004-08-22 02:38:11 +00005052}
5053
5054
sewardjf9517d02005-11-28 13:39:37 +00005055/* Given uses :: array of UShort, indexed by IRTemp
5056 Add the use-occurrences of temps in this statement
5057 to the env.
5058*/
5059static void aoccCount_Stmt ( UShort* uses, IRStmt* st )
sewardj29632392004-08-22 02:38:11 +00005060{
sewardjf9517d02005-11-28 13:39:37 +00005061 Int i;
5062 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00005063 IRCAS* cas;
sewardjf9517d02005-11-28 13:39:37 +00005064 switch (st->tag) {
5065 case Ist_AbiHint:
5066 aoccCount_Expr(uses, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +00005067 aoccCount_Expr(uses, st->Ist.AbiHint.nia);
sewardjf9517d02005-11-28 13:39:37 +00005068 return;
sewardjdd40fdf2006-12-24 02:20:24 +00005069 case Ist_WrTmp:
5070 aoccCount_Expr(uses, st->Ist.WrTmp.data);
sewardjf9517d02005-11-28 13:39:37 +00005071 return;
5072 case Ist_Put:
5073 aoccCount_Expr(uses, st->Ist.Put.data);
5074 return;
5075 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +00005076 aoccCount_Expr(uses, st->Ist.PutI.details->ix);
5077 aoccCount_Expr(uses, st->Ist.PutI.details->data);
sewardjf9517d02005-11-28 13:39:37 +00005078 return;
5079 case Ist_Store:
5080 aoccCount_Expr(uses, st->Ist.Store.addr);
5081 aoccCount_Expr(uses, st->Ist.Store.data);
5082 return;
sewardjcfe046e2013-01-17 14:23:53 +00005083 case Ist_StoreG: {
5084 IRStoreG* sg = st->Ist.StoreG.details;
5085 aoccCount_Expr(uses, sg->addr);
5086 aoccCount_Expr(uses, sg->data);
5087 aoccCount_Expr(uses, sg->guard);
5088 return;
5089 }
5090 case Ist_LoadG: {
5091 IRLoadG* lg = st->Ist.LoadG.details;
5092 aoccCount_Expr(uses, lg->addr);
5093 aoccCount_Expr(uses, lg->alt);
5094 aoccCount_Expr(uses, lg->guard);
5095 return;
5096 }
sewardje9d8a262009-07-01 08:06:34 +00005097 case Ist_CAS:
5098 cas = st->Ist.CAS.details;
5099 aoccCount_Expr(uses, cas->addr);
5100 if (cas->expdHi)
5101 aoccCount_Expr(uses, cas->expdHi);
5102 aoccCount_Expr(uses, cas->expdLo);
5103 if (cas->dataHi)
5104 aoccCount_Expr(uses, cas->dataHi);
5105 aoccCount_Expr(uses, cas->dataLo);
5106 return;
sewardje768e922009-11-26 17:17:37 +00005107 case Ist_LLSC:
5108 aoccCount_Expr(uses, st->Ist.LLSC.addr);
5109 if (st->Ist.LLSC.storedata)
5110 aoccCount_Expr(uses, st->Ist.LLSC.storedata);
5111 return;
sewardjf9517d02005-11-28 13:39:37 +00005112 case Ist_Dirty:
5113 d = st->Ist.Dirty.details;
5114 if (d->mFx != Ifx_None)
5115 aoccCount_Expr(uses, d->mAddr);
5116 aoccCount_Expr(uses, d->guard);
sewardj74142b82013-08-08 10:28:59 +00005117 for (i = 0; d->args[i]; i++) {
5118 IRExpr* arg = d->args[i];
florian90419562013-08-15 20:54:52 +00005119 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +00005120 aoccCount_Expr(uses, arg);
5121 }
sewardjf9517d02005-11-28 13:39:37 +00005122 return;
5123 case Ist_NoOp:
5124 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00005125 case Ist_MBE:
sewardjf9517d02005-11-28 13:39:37 +00005126 return;
5127 case Ist_Exit:
5128 aoccCount_Expr(uses, st->Ist.Exit.guard);
5129 return;
5130 default:
5131 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
5132 vpanic("aoccCount_Stmt");
5133 }
5134}
5135
5136/* Look up a binding for tmp in the env. If found, return the bound
5137 expression, and set the env's binding to NULL so it is marked as
5138 used. If not found, return NULL. */
5139
5140static IRExpr* atbSubst_Temp ( ATmpInfo* env, IRTemp tmp )
5141{
5142 Int i;
5143 for (i = 0; i < A_NENV; i++) {
5144 if (env[i].binder == tmp && env[i].bindee != NULL) {
5145 IRExpr* bindee = env[i].bindee;
5146 env[i].bindee = NULL;
5147 return bindee;
5148 }
5149 }
5150 return NULL;
5151}
5152
5153/* Traverse e, looking for temps. For each observed temp, see if env
5154 contains a binding for the temp, and if so return the bound value.
5155 The env has the property that any binding it holds is
5156 'single-shot', so once a binding is used, it is marked as no longer
5157 available, by setting its .bindee field to NULL. */
5158
sewardjeb17e492007-08-25 23:07:44 +00005159static inline Bool is_Unop ( IRExpr* e, IROp op ) {
5160 return e->tag == Iex_Unop && e->Iex.Unop.op == op;
5161}
5162static inline Bool is_Binop ( IRExpr* e, IROp op ) {
5163 return e->tag == Iex_Binop && e->Iex.Binop.op == op;
5164}
5165
5166static IRExpr* fold_IRExpr_Binop ( IROp op, IRExpr* a1, IRExpr* a2 )
5167{
5168 switch (op) {
5169 case Iop_Or32:
5170 /* Or32( CmpwNEZ32(x), CmpwNEZ32(y) ) --> CmpwNEZ32( Or32( x, y ) ) */
5171 if (is_Unop(a1, Iop_CmpwNEZ32) && is_Unop(a2, Iop_CmpwNEZ32))
5172 return IRExpr_Unop( Iop_CmpwNEZ32,
5173 IRExpr_Binop( Iop_Or32, a1->Iex.Unop.arg,
5174 a2->Iex.Unop.arg ) );
5175 break;
florian51d26fd2011-07-23 00:23:02 +00005176
5177 case Iop_CmpNE32:
5178 /* Since X has type Ity_I1 we can simplify:
5179 CmpNE32(1Uto32(X),0)) ==> X */
5180 if (is_Unop(a1, Iop_1Uto32) && isZeroU32(a2))
5181 return a1->Iex.Unop.arg;
5182 break;
5183
sewardjeb17e492007-08-25 23:07:44 +00005184 default:
5185 break;
5186 }
5187 /* no reduction rule applies */
5188 return IRExpr_Binop( op, a1, a2 );
5189}
5190
5191static IRExpr* fold_IRExpr_Unop ( IROp op, IRExpr* aa )
5192{
5193 switch (op) {
5194 case Iop_CmpwNEZ64:
floriande6f7102013-09-06 23:13:39 +00005195 /* CmpwNEZ64( CmpwNEZ64 ( x ) ) --> CmpwNEZ64 ( x ) */
5196 if (is_Unop(aa, Iop_CmpwNEZ64))
5197 return IRExpr_Unop( Iop_CmpwNEZ64, aa->Iex.Unop.arg );
sewardjeb17e492007-08-25 23:07:44 +00005198 /* CmpwNEZ64( Or64 ( CmpwNEZ64(x), y ) ) --> CmpwNEZ64( Or64( x, y ) ) */
5199 if (is_Binop(aa, Iop_Or64)
5200 && is_Unop(aa->Iex.Binop.arg1, Iop_CmpwNEZ64))
5201 return fold_IRExpr_Unop(
5202 Iop_CmpwNEZ64,
5203 IRExpr_Binop(Iop_Or64,
5204 aa->Iex.Binop.arg1->Iex.Unop.arg,
5205 aa->Iex.Binop.arg2));
5206 /* CmpwNEZ64( Or64 ( x, CmpwNEZ64(y) ) ) --> CmpwNEZ64( Or64( x, y ) ) */
5207 if (is_Binop(aa, Iop_Or64)
5208 && is_Unop(aa->Iex.Binop.arg2, Iop_CmpwNEZ64))
5209 return fold_IRExpr_Unop(
5210 Iop_CmpwNEZ64,
5211 IRExpr_Binop(Iop_Or64,
5212 aa->Iex.Binop.arg1,
5213 aa->Iex.Binop.arg2->Iex.Unop.arg));
5214 break;
5215 case Iop_CmpNEZ64:
5216 /* CmpNEZ64( Left64(x) ) --> CmpNEZ64(x) */
5217 if (is_Unop(aa, Iop_Left64))
5218 return IRExpr_Unop(Iop_CmpNEZ64, aa->Iex.Unop.arg);
floriande6f7102013-09-06 23:13:39 +00005219 /* CmpNEZ64( 1Uto64(X) ) --> X */
5220 if (is_Unop(aa, Iop_1Uto64))
5221 return aa->Iex.Unop.arg;
sewardjeb17e492007-08-25 23:07:44 +00005222 break;
5223 case Iop_CmpwNEZ32:
5224 /* CmpwNEZ32( CmpwNEZ32 ( x ) ) --> CmpwNEZ32 ( x ) */
5225 if (is_Unop(aa, Iop_CmpwNEZ32))
5226 return IRExpr_Unop( Iop_CmpwNEZ32, aa->Iex.Unop.arg );
5227 break;
5228 case Iop_CmpNEZ32:
5229 /* CmpNEZ32( Left32(x) ) --> CmpNEZ32(x) */
5230 if (is_Unop(aa, Iop_Left32))
5231 return IRExpr_Unop(Iop_CmpNEZ32, aa->Iex.Unop.arg);
florian51d26fd2011-07-23 00:23:02 +00005232 /* CmpNEZ32( 1Uto32(X) ) --> X */
5233 if (is_Unop(aa, Iop_1Uto32))
5234 return aa->Iex.Unop.arg;
floriande6f7102013-09-06 23:13:39 +00005235 /* CmpNEZ32( 64to32( CmpwNEZ64(X) ) ) --> CmpNEZ64(X) */
5236 if (is_Unop(aa, Iop_64to32) && is_Unop(aa->Iex.Unop.arg, Iop_CmpwNEZ64))
5237 return IRExpr_Unop(Iop_CmpNEZ64, aa->Iex.Unop.arg->Iex.Unop.arg);
florian51d26fd2011-07-23 00:23:02 +00005238 break;
5239 case Iop_CmpNEZ8:
5240 /* CmpNEZ8( 1Uto8(X) ) --> X */
5241 if (is_Unop(aa, Iop_1Uto8))
5242 return aa->Iex.Unop.arg;
sewardjeb17e492007-08-25 23:07:44 +00005243 break;
5244 case Iop_Left32:
5245 /* Left32( Left32(x) ) --> Left32(x) */
5246 if (is_Unop(aa, Iop_Left32))
5247 return IRExpr_Unop( Iop_Left32, aa->Iex.Unop.arg );
5248 break;
florian854912a2013-09-01 20:17:23 +00005249 case Iop_Left64:
5250 /* Left64( Left64(x) ) --> Left64(x) */
5251 if (is_Unop(aa, Iop_Left64))
5252 return IRExpr_Unop( Iop_Left64, aa->Iex.Unop.arg );
5253 break;
sewardj0caa0c02014-08-11 14:01:00 +00005254 case Iop_ZeroHI64ofV128:
5255 /* ZeroHI64ofV128( ZeroHI64ofV128(x) ) --> ZeroHI64ofV128(x) */
5256 if (is_Unop(aa, Iop_ZeroHI64ofV128))
5257 return IRExpr_Unop( Iop_ZeroHI64ofV128, aa->Iex.Unop.arg );
5258 break;
sewardjeb17e492007-08-25 23:07:44 +00005259 case Iop_32to1:
5260 /* 32to1( 1Uto32 ( x ) ) --> x */
5261 if (is_Unop(aa, Iop_1Uto32))
5262 return aa->Iex.Unop.arg;
5263 /* 32to1( CmpwNEZ32 ( x )) --> CmpNEZ32(x) */
5264 if (is_Unop(aa, Iop_CmpwNEZ32))
5265 return IRExpr_Unop( Iop_CmpNEZ32, aa->Iex.Unop.arg );
5266 break;
5267 case Iop_64to1:
5268 /* 64to1( 1Uto64 ( x ) ) --> x */
5269 if (is_Unop(aa, Iop_1Uto64))
5270 return aa->Iex.Unop.arg;
5271 /* 64to1( CmpwNEZ64 ( x )) --> CmpNEZ64(x) */
5272 if (is_Unop(aa, Iop_CmpwNEZ64))
5273 return IRExpr_Unop( Iop_CmpNEZ64, aa->Iex.Unop.arg );
5274 break;
sewardjef425db2010-01-11 10:46:18 +00005275 case Iop_64to32:
5276 /* 64to32( 32Uto64 ( x )) --> x */
5277 if (is_Unop(aa, Iop_32Uto64))
5278 return aa->Iex.Unop.arg;
sewardjca257bc2010-09-08 08:34:52 +00005279 /* 64to32( 8Uto64 ( x )) --> 8Uto32(x) */
5280 if (is_Unop(aa, Iop_8Uto64))
5281 return IRExpr_Unop(Iop_8Uto32, aa->Iex.Unop.arg);
5282 break;
5283
5284 case Iop_32Uto64:
5285 /* 32Uto64( 8Uto32( x )) --> 8Uto64(x) */
5286 if (is_Unop(aa, Iop_8Uto32))
5287 return IRExpr_Unop(Iop_8Uto64, aa->Iex.Unop.arg);
5288 /* 32Uto64( 16Uto32( x )) --> 16Uto64(x) */
5289 if (is_Unop(aa, Iop_16Uto32))
5290 return IRExpr_Unop(Iop_16Uto64, aa->Iex.Unop.arg);
sewardjbba356d2012-04-25 16:47:53 +00005291 /* 32Uto64(64to32( Shr64( 32Uto64(64to32(x)), sh ))
5292 --> Shr64( 32Uto64(64to32(x)), sh )) */
5293 if (is_Unop(aa, Iop_64to32)
5294 && is_Binop(aa->Iex.Unop.arg, Iop_Shr64)
5295 && is_Unop(aa->Iex.Unop.arg->Iex.Binop.arg1, Iop_32Uto64)
5296 && is_Unop(aa->Iex.Unop.arg->Iex.Binop.arg1->Iex.Unop.arg,
5297 Iop_64to32)) {
5298 return aa->Iex.Unop.arg;
5299 }
5300 /* 32Uto64(64to32( Shl64( 32Uto64(64to32(x)), sh ))
5301 --> 32Uto64(64to32( Shl64( x, sh )) */
5302 if (is_Unop(aa, Iop_64to32)
5303 && is_Binop(aa->Iex.Unop.arg, Iop_Shl64)
5304 && is_Unop(aa->Iex.Unop.arg->Iex.Binop.arg1, Iop_32Uto64)
5305 && is_Unop(aa->Iex.Unop.arg->Iex.Binop.arg1->Iex.Unop.arg,
5306 Iop_64to32)) {
5307 return
5308 IRExpr_Unop(
5309 Iop_32Uto64,
5310 IRExpr_Unop(
5311 Iop_64to32,
5312 IRExpr_Binop(
5313 Iop_Shl64,
5314 aa->Iex.Unop.arg->Iex.Binop.arg1->Iex.Unop.arg->Iex.Unop.arg,
5315 aa->Iex.Unop.arg->Iex.Binop.arg2
5316 )));
5317 }
sewardjef425db2010-01-11 10:46:18 +00005318 break;
sewardj6c299f32009-12-31 18:00:12 +00005319
5320 case Iop_1Sto32:
5321 /* 1Sto32( CmpNEZ8( 32to8( 1Uto32( CmpNEZ32( x ))))) -> CmpwNEZ32(x) */
5322 if (is_Unop(aa, Iop_CmpNEZ8)
5323 && is_Unop(aa->Iex.Unop.arg, Iop_32to8)
5324 && is_Unop(aa->Iex.Unop.arg->Iex.Unop.arg, Iop_1Uto32)
5325 && is_Unop(aa->Iex.Unop.arg->Iex.Unop.arg->Iex.Unop.arg,
5326 Iop_CmpNEZ32)) {
5327 return IRExpr_Unop( Iop_CmpwNEZ32,
5328 aa->Iex.Unop.arg->Iex.Unop.arg
5329 ->Iex.Unop.arg->Iex.Unop.arg);
5330 }
5331 break;
5332
sewardjeb17e492007-08-25 23:07:44 +00005333 default:
5334 break;
5335 }
5336 /* no reduction rule applies */
5337 return IRExpr_Unop( op, aa );
5338}
5339
sewardjf9517d02005-11-28 13:39:37 +00005340static IRExpr* atbSubst_Expr ( ATmpInfo* env, IRExpr* e )
5341{
5342 IRExpr* e2;
5343 IRExpr** args2;
5344 Int i;
5345
5346 switch (e->tag) {
5347
5348 case Iex_CCall:
sewardjdd40fdf2006-12-24 02:20:24 +00005349 args2 = shallowCopyIRExprVec(e->Iex.CCall.args);
sewardjf9517d02005-11-28 13:39:37 +00005350 for (i = 0; args2[i]; i++)
5351 args2[i] = atbSubst_Expr(env,args2[i]);
5352 return IRExpr_CCall(
5353 e->Iex.CCall.cee,
5354 e->Iex.CCall.retty,
5355 args2
5356 );
sewardjdd40fdf2006-12-24 02:20:24 +00005357 case Iex_RdTmp:
5358 e2 = atbSubst_Temp(env, e->Iex.RdTmp.tmp);
sewardjf9517d02005-11-28 13:39:37 +00005359 return e2 ? e2 : e;
florian99dd03e2013-01-29 03:56:06 +00005360 case Iex_ITE:
5361 return IRExpr_ITE(
5362 atbSubst_Expr(env, e->Iex.ITE.cond),
5363 atbSubst_Expr(env, e->Iex.ITE.iftrue),
5364 atbSubst_Expr(env, e->Iex.ITE.iffalse)
sewardjf9517d02005-11-28 13:39:37 +00005365 );
sewardj40c80262006-02-08 19:30:46 +00005366 case Iex_Qop:
5367 return IRExpr_Qop(
florian96d7cc32012-06-01 20:41:24 +00005368 e->Iex.Qop.details->op,
5369 atbSubst_Expr(env, e->Iex.Qop.details->arg1),
5370 atbSubst_Expr(env, e->Iex.Qop.details->arg2),
5371 atbSubst_Expr(env, e->Iex.Qop.details->arg3),
5372 atbSubst_Expr(env, e->Iex.Qop.details->arg4)
sewardj40c80262006-02-08 19:30:46 +00005373 );
sewardjb183b852006-02-03 16:08:03 +00005374 case Iex_Triop:
5375 return IRExpr_Triop(
florian420bfa92012-06-02 20:29:22 +00005376 e->Iex.Triop.details->op,
5377 atbSubst_Expr(env, e->Iex.Triop.details->arg1),
5378 atbSubst_Expr(env, e->Iex.Triop.details->arg2),
5379 atbSubst_Expr(env, e->Iex.Triop.details->arg3)
sewardjb183b852006-02-03 16:08:03 +00005380 );
sewardjf9517d02005-11-28 13:39:37 +00005381 case Iex_Binop:
sewardjeb17e492007-08-25 23:07:44 +00005382 return fold_IRExpr_Binop(
sewardjf9517d02005-11-28 13:39:37 +00005383 e->Iex.Binop.op,
5384 atbSubst_Expr(env, e->Iex.Binop.arg1),
5385 atbSubst_Expr(env, e->Iex.Binop.arg2)
5386 );
5387 case Iex_Unop:
sewardjeb17e492007-08-25 23:07:44 +00005388 return fold_IRExpr_Unop(
sewardjf9517d02005-11-28 13:39:37 +00005389 e->Iex.Unop.op,
5390 atbSubst_Expr(env, e->Iex.Unop.arg)
5391 );
5392 case Iex_Load:
5393 return IRExpr_Load(
5394 e->Iex.Load.end,
5395 e->Iex.Load.ty,
5396 atbSubst_Expr(env, e->Iex.Load.addr)
5397 );
5398 case Iex_GetI:
5399 return IRExpr_GetI(
5400 e->Iex.GetI.descr,
5401 atbSubst_Expr(env, e->Iex.GetI.ix),
5402 e->Iex.GetI.bias
5403 );
5404 case Iex_Const:
5405 case Iex_Get:
5406 return e;
5407 default:
5408 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
5409 vpanic("atbSubst_Expr");
5410 }
5411}
5412
5413/* Same deal as atbSubst_Expr, except for stmts. */
5414
5415static IRStmt* atbSubst_Stmt ( ATmpInfo* env, IRStmt* st )
5416{
sewardje9d8a262009-07-01 08:06:34 +00005417 Int i;
5418 IRDirty *d, *d2;
5419 IRCAS *cas, *cas2;
floriand6f38b32012-05-31 15:46:18 +00005420 IRPutI *puti, *puti2;
5421
sewardjf9517d02005-11-28 13:39:37 +00005422 switch (st->tag) {
5423 case Ist_AbiHint:
5424 return IRStmt_AbiHint(
5425 atbSubst_Expr(env, st->Ist.AbiHint.base),
sewardj478646f2008-05-01 20:13:04 +00005426 st->Ist.AbiHint.len,
5427 atbSubst_Expr(env, st->Ist.AbiHint.nia)
sewardjf9517d02005-11-28 13:39:37 +00005428 );
5429 case Ist_Store:
5430 return IRStmt_Store(
5431 st->Ist.Store.end,
5432 atbSubst_Expr(env, st->Ist.Store.addr),
5433 atbSubst_Expr(env, st->Ist.Store.data)
5434 );
sewardjcfe046e2013-01-17 14:23:53 +00005435 case Ist_StoreG: {
5436 IRStoreG* sg = st->Ist.StoreG.details;
5437 return IRStmt_StoreG(sg->end,
5438 atbSubst_Expr(env, sg->addr),
5439 atbSubst_Expr(env, sg->data),
5440 atbSubst_Expr(env, sg->guard));
5441 }
5442 case Ist_LoadG: {
5443 IRLoadG* lg = st->Ist.LoadG.details;
5444 return IRStmt_LoadG(lg->end, lg->cvt, lg->dst,
5445 atbSubst_Expr(env, lg->addr),
5446 atbSubst_Expr(env, lg->alt),
5447 atbSubst_Expr(env, lg->guard));
5448 }
sewardjdd40fdf2006-12-24 02:20:24 +00005449 case Ist_WrTmp:
5450 return IRStmt_WrTmp(
5451 st->Ist.WrTmp.tmp,
5452 atbSubst_Expr(env, st->Ist.WrTmp.data)
sewardjf9517d02005-11-28 13:39:37 +00005453 );
5454 case Ist_Put:
5455 return IRStmt_Put(
5456 st->Ist.Put.offset,
5457 atbSubst_Expr(env, st->Ist.Put.data)
5458 );
5459 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +00005460 puti = st->Ist.PutI.details;
5461 puti2 = mkIRPutI(puti->descr,
5462 atbSubst_Expr(env, puti->ix),
5463 puti->bias,
5464 atbSubst_Expr(env, puti->data));
5465 return IRStmt_PutI(puti2);
sewardjf9517d02005-11-28 13:39:37 +00005466
5467 case Ist_Exit:
5468 return IRStmt_Exit(
5469 atbSubst_Expr(env, st->Ist.Exit.guard),
5470 st->Ist.Exit.jk,
sewardjc6f970f2012-04-02 21:54:49 +00005471 st->Ist.Exit.dst,
5472 st->Ist.Exit.offsIP
sewardjf9517d02005-11-28 13:39:37 +00005473 );
5474 case Ist_IMark:
sewardj2f10aa62011-05-27 13:20:56 +00005475 return IRStmt_IMark(st->Ist.IMark.addr,
5476 st->Ist.IMark.len,
5477 st->Ist.IMark.delta);
sewardjf9517d02005-11-28 13:39:37 +00005478 case Ist_NoOp:
5479 return IRStmt_NoOp();
sewardjc4356f02007-11-09 21:15:04 +00005480 case Ist_MBE:
5481 return IRStmt_MBE(st->Ist.MBE.event);
sewardje9d8a262009-07-01 08:06:34 +00005482 case Ist_CAS:
5483 cas = st->Ist.CAS.details;
5484 cas2 = mkIRCAS(
5485 cas->oldHi, cas->oldLo, cas->end,
5486 atbSubst_Expr(env, cas->addr),
5487 cas->expdHi ? atbSubst_Expr(env, cas->expdHi) : NULL,
5488 atbSubst_Expr(env, cas->expdLo),
5489 cas->dataHi ? atbSubst_Expr(env, cas->dataHi) : NULL,
5490 atbSubst_Expr(env, cas->dataLo)
5491 );
5492 return IRStmt_CAS(cas2);
sewardje768e922009-11-26 17:17:37 +00005493 case Ist_LLSC:
5494 return IRStmt_LLSC(
5495 st->Ist.LLSC.end,
5496 st->Ist.LLSC.result,
5497 atbSubst_Expr(env, st->Ist.LLSC.addr),
5498 st->Ist.LLSC.storedata
5499 ? atbSubst_Expr(env, st->Ist.LLSC.storedata) : NULL
5500 );
sewardjf9517d02005-11-28 13:39:37 +00005501 case Ist_Dirty:
5502 d = st->Ist.Dirty.details;
5503 d2 = emptyIRDirty();
5504 *d2 = *d;
5505 if (d2->mFx != Ifx_None)
5506 d2->mAddr = atbSubst_Expr(env, d2->mAddr);
5507 d2->guard = atbSubst_Expr(env, d2->guard);
sewardj74142b82013-08-08 10:28:59 +00005508 for (i = 0; d2->args[i]; i++) {
5509 IRExpr* arg = d2->args[i];
florian90419562013-08-15 20:54:52 +00005510 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +00005511 d2->args[i] = atbSubst_Expr(env, arg);
5512 }
sewardjf9517d02005-11-28 13:39:37 +00005513 return IRStmt_Dirty(d2);
5514 default:
5515 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
5516 vpanic("atbSubst_Stmt");
5517 }
5518}
5519
florian088809c2012-12-30 18:17:18 +00005520inline
5521static Bool dirty_helper_stores ( const IRDirty *d )
5522{
5523 return d->mFx == Ifx_Write || d->mFx == Ifx_Modify;
5524}
5525
5526inline
florian740da722013-09-11 17:58:32 +00005527static Interval dirty_helper_puts ( const IRDirty *d,
5528 Bool (*preciseMemExnsFn)(Int, Int),
5529 Bool *requiresPreciseMemExns )
florian088809c2012-12-30 18:17:18 +00005530{
5531 Int i;
florian740da722013-09-11 17:58:32 +00005532 Interval interval;
florian088809c2012-12-30 18:17:18 +00005533
5534 /* Passing the guest state pointer opens the door to modifying the
sewardj74142b82013-08-08 10:28:59 +00005535 guest state under the covers. It's not allowed, but let's be
florian088809c2012-12-30 18:17:18 +00005536 extra conservative and assume the worst. */
sewardj74142b82013-08-08 10:28:59 +00005537 for (i = 0; d->args[i]; i++) {
florian90419562013-08-15 20:54:52 +00005538 if (UNLIKELY(d->args[i]->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +00005539 *requiresPreciseMemExns = True;
florian740da722013-09-11 17:58:32 +00005540 /* Assume all guest state is written. */
5541 interval.present = True;
5542 interval.low = 0;
5543 interval.high = 0x7FFFFFFF;
5544 return interval;
sewardj74142b82013-08-08 10:28:59 +00005545 }
florian088809c2012-12-30 18:17:18 +00005546 }
5547
florian62140c12013-01-20 03:51:04 +00005548 /* Check the side effects on the guest state */
florian740da722013-09-11 17:58:32 +00005549 interval.present = False;
5550 interval.low = interval.high = -1;
florian62140c12013-01-20 03:51:04 +00005551 *requiresPreciseMemExns = False;
5552
5553 for (i = 0; i < d->nFxState; ++i) {
5554 if (d->fxState[i].fx != Ifx_Read) {
5555 Int offset = d->fxState[i].offset;
5556 Int size = d->fxState[i].size;
5557 Int nRepeats = d->fxState[i].nRepeats;
5558 Int repeatLen = d->fxState[i].repeatLen;
5559
sewardj74142b82013-08-08 10:28:59 +00005560 if (preciseMemExnsFn(offset,
5561 offset + nRepeats * repeatLen + size - 1)) {
florian62140c12013-01-20 03:51:04 +00005562 *requiresPreciseMemExns = True;
florian62140c12013-01-20 03:51:04 +00005563 }
florian740da722013-09-11 17:58:32 +00005564 update_interval(&interval, offset,
5565 offset + nRepeats * repeatLen + size - 1);
florian62140c12013-01-20 03:51:04 +00005566 }
5567 }
5568
florian740da722013-09-11 17:58:32 +00005569 return interval;
florian088809c2012-12-30 18:17:18 +00005570}
5571
florian740da722013-09-11 17:58:32 +00005572/* Return an interval if st modifies the guest state. Via requiresPreciseMemExns
florian62140c12013-01-20 03:51:04 +00005573 return whether or not that modification requires precise exceptions. */
florian740da722013-09-11 17:58:32 +00005574static Interval stmt_modifies_guest_state ( IRSB *bb, const IRStmt *st,
5575 Bool (*preciseMemExnsFn)(Int,Int),
5576 Bool *requiresPreciseMemExns )
florian62140c12013-01-20 03:51:04 +00005577{
florian740da722013-09-11 17:58:32 +00005578 Interval interval;
5579
florian62140c12013-01-20 03:51:04 +00005580 switch (st->tag) {
5581 case Ist_Put: {
5582 Int offset = st->Ist.Put.offset;
5583 Int size = sizeofIRType(typeOfIRExpr(bb->tyenv, st->Ist.Put.data));
5584
5585 *requiresPreciseMemExns = preciseMemExnsFn(offset, offset + size - 1);
florian740da722013-09-11 17:58:32 +00005586 interval.present = True;
5587 interval.low = offset;
5588 interval.high = offset + size - 1;
5589 return interval;
florian62140c12013-01-20 03:51:04 +00005590 }
5591
5592 case Ist_PutI: {
5593 IRRegArray *descr = st->Ist.PutI.details->descr;
5594 Int offset = descr->base;
5595 Int size = sizeofIRType(descr->elemTy);
5596
5597 /* We quietly assume here that all segments are contiguous and there
5598 are no holes. This is to avoid a loop. The assumption is conservative
5599 in the sense that we might report that precise memory exceptions are
5600 needed when in fact they are not. */
5601 *requiresPreciseMemExns =
5602 preciseMemExnsFn(offset, offset + descr->nElems * size - 1);
florian740da722013-09-11 17:58:32 +00005603 interval.present = True;
5604 interval.low = offset;
5605 interval.high = offset + descr->nElems * size - 1;
5606 return interval;
florian62140c12013-01-20 03:51:04 +00005607 }
5608
5609 case Ist_Dirty:
5610 return dirty_helper_puts(st->Ist.Dirty.details, preciseMemExnsFn,
5611 requiresPreciseMemExns);
5612
5613 default:
5614 *requiresPreciseMemExns = False;
florian740da722013-09-11 17:58:32 +00005615 interval.present = False;
5616 interval.low = -1;
5617 interval.high = -1;
5618 return interval;
florian62140c12013-01-20 03:51:04 +00005619 }
5620}
5621
floriandcd6d232015-01-02 17:32:21 +00005622/* notstatic */ Addr ado_treebuild_BB ( IRSB* bb,
5623 Bool (*preciseMemExnsFn)(Int,Int) )
sewardjf9517d02005-11-28 13:39:37 +00005624{
5625 Int i, j, k, m;
florian740da722013-09-11 17:58:32 +00005626 Bool stmtStores, invalidateMe;
5627 Interval putInterval;
sewardj29632392004-08-22 02:38:11 +00005628 IRStmt* st;
5629 IRStmt* st2;
sewardjf9517d02005-11-28 13:39:37 +00005630 ATmpInfo env[A_NENV];
sewardj29632392004-08-22 02:38:11 +00005631
sewardjc6f970f2012-04-02 21:54:49 +00005632 Bool max_ga_known = False;
floriandcd6d232015-01-02 17:32:21 +00005633 Addr max_ga = 0;
sewardjc6f970f2012-04-02 21:54:49 +00005634
sewardjc9ad1152004-10-14 00:08:21 +00005635 Int n_tmps = bb->tyenv->types_used;
sewardjf9517d02005-11-28 13:39:37 +00005636 UShort* uses = LibVEX_Alloc(n_tmps * sizeof(UShort));
sewardj29632392004-08-22 02:38:11 +00005637
5638 /* Phase 1. Scan forwards in bb, counting use occurrences of each
sewardjc6f970f2012-04-02 21:54:49 +00005639 temp. Also count occurrences in the bb->next field. Take the
5640 opportunity to also find the maximum guest address in the block,
5641 since that will be needed later for deciding when we can safely
5642 elide event checks. */
sewardj29632392004-08-22 02:38:11 +00005643
sewardjf9517d02005-11-28 13:39:37 +00005644 for (i = 0; i < n_tmps; i++)
5645 uses[i] = 0;
5646
sewardj29632392004-08-22 02:38:11 +00005647 for (i = 0; i < bb->stmts_used; i++) {
5648 st = bb->stmts[i];
sewardjc6f970f2012-04-02 21:54:49 +00005649 switch (st->tag) {
5650 case Ist_NoOp:
5651 continue;
5652 case Ist_IMark: {
floriandcd6d232015-01-02 17:32:21 +00005653 UInt len = st->Ist.IMark.len;
5654 Addr mga = st->Ist.IMark.addr + (len < 1 ? 1 : len) - 1;
sewardjc6f970f2012-04-02 21:54:49 +00005655 max_ga_known = True;
5656 if (mga > max_ga)
5657 max_ga = mga;
5658 break;
5659 }
5660 default:
5661 break;
5662 }
sewardjf9517d02005-11-28 13:39:37 +00005663 aoccCount_Stmt( uses, st );
sewardj29632392004-08-22 02:38:11 +00005664 }
sewardjf9517d02005-11-28 13:39:37 +00005665 aoccCount_Expr(uses, bb->next );
sewardj29632392004-08-22 02:38:11 +00005666
sewardjc9ad1152004-10-14 00:08:21 +00005667# if 0
sewardjf9517d02005-11-28 13:39:37 +00005668 for (i = 0; i < n_tmps; i++) {
5669 if (uses[i] == 0)
sewardj29632392004-08-22 02:38:11 +00005670 continue;
sewardjf9517d02005-11-28 13:39:37 +00005671 ppIRTemp( (IRTemp)i );
5672 vex_printf(" used %d\n", (Int)uses[i] );
sewardj29632392004-08-22 02:38:11 +00005673 }
sewardjc9ad1152004-10-14 00:08:21 +00005674# endif
sewardj29632392004-08-22 02:38:11 +00005675
sewardjf9517d02005-11-28 13:39:37 +00005676 /* Phase 2. Scan forwards in bb. For each statement in turn:
sewardj29632392004-08-22 02:38:11 +00005677
sewardjf9517d02005-11-28 13:39:37 +00005678 If the env is full, emit the end element. This guarantees
5679 there is at least one free slot in the following.
sewardj29632392004-08-22 02:38:11 +00005680
sewardjf9517d02005-11-28 13:39:37 +00005681 On seeing 't = E', occ(t)==1,
5682 let E'=env(E)
5683 delete this stmt
5684 add t -> E' to the front of the env
5685 Examine E' and set the hints for E' appropriately
sewardj29632392004-08-22 02:38:11 +00005686 (doesLoad? doesGet?)
5687
sewardjf9517d02005-11-28 13:39:37 +00005688 On seeing any other stmt,
sewardj29632392004-08-22 02:38:11 +00005689 let stmt' = env(stmt)
5690 remove from env any 't=E' binds invalidated by stmt
5691 emit the invalidated stmts
5692 emit stmt'
sewardjf9517d02005-11-28 13:39:37 +00005693 compact any holes in env
5694 by sliding entries towards the front
sewardj29632392004-08-22 02:38:11 +00005695
sewardjf9517d02005-11-28 13:39:37 +00005696 Finally, apply env to bb->next.
sewardj29632392004-08-22 02:38:11 +00005697 */
5698
sewardjf9517d02005-11-28 13:39:37 +00005699 for (i = 0; i < A_NENV; i++) {
5700 env[i].bindee = NULL;
5701 env[i].binder = IRTemp_INVALID;
5702 }
5703
sewardj29632392004-08-22 02:38:11 +00005704 /* The stmts in bb are being reordered, and we are guaranteed to
5705 end up with no more than the number we started with. Use i to
5706 be the cursor of the current stmt examined and j <= i to be that
5707 for the current stmt being written.
5708 */
5709 j = 0;
5710 for (i = 0; i < bb->stmts_used; i++) {
sewardjf9517d02005-11-28 13:39:37 +00005711
sewardj29632392004-08-22 02:38:11 +00005712 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00005713 if (st->tag == Ist_NoOp)
sewardj29632392004-08-22 02:38:11 +00005714 continue;
5715
sewardjf9517d02005-11-28 13:39:37 +00005716 /* Ensure there's at least one space in the env, by emitting
5717 the oldest binding if necessary. */
5718 if (env[A_NENV-1].bindee != NULL) {
sewardjdd40fdf2006-12-24 02:20:24 +00005719 bb->stmts[j] = IRStmt_WrTmp( env[A_NENV-1].binder,
5720 env[A_NENV-1].bindee );
sewardjf9517d02005-11-28 13:39:37 +00005721 j++;
5722 vassert(j <= i);
5723 env[A_NENV-1].bindee = NULL;
5724 }
5725
5726 /* Consider current stmt. */
sewardjdd40fdf2006-12-24 02:20:24 +00005727 if (st->tag == Ist_WrTmp && uses[st->Ist.WrTmp.tmp] <= 1) {
sewardj63327402006-01-25 03:26:27 +00005728 IRExpr *e, *e2;
sewardjf9517d02005-11-28 13:39:37 +00005729
5730 /* optional extra: dump dead bindings as we find them.
5731 Removes the need for a prior dead-code removal pass. */
sewardjdd40fdf2006-12-24 02:20:24 +00005732 if (uses[st->Ist.WrTmp.tmp] == 0) {
sewardjb183b852006-02-03 16:08:03 +00005733 if (0) vex_printf("DEAD binding\n");
sewardjf9517d02005-11-28 13:39:37 +00005734 continue; /* for (i = 0; i < bb->stmts_used; i++) loop */
sewardj29632392004-08-22 02:38:11 +00005735 }
sewardjdd40fdf2006-12-24 02:20:24 +00005736 vassert(uses[st->Ist.WrTmp.tmp] == 1);
sewardjf9517d02005-11-28 13:39:37 +00005737
5738 /* ok, we have 't = E', occ(t)==1. Do the abovementioned
5739 actions. */
sewardjdd40fdf2006-12-24 02:20:24 +00005740 e = st->Ist.WrTmp.data;
sewardj63327402006-01-25 03:26:27 +00005741 e2 = atbSubst_Expr(env, e);
sewardjdd40fdf2006-12-24 02:20:24 +00005742 addToEnvFront(env, st->Ist.WrTmp.tmp, e2);
florian740da722013-09-11 17:58:32 +00005743 setHints_Expr(&env[0].doesLoad, &env[0].getInterval, e2);
sewardjf9517d02005-11-28 13:39:37 +00005744 /* don't advance j, as we are deleting this stmt and instead
5745 holding it temporarily in the env. */
5746 continue; /* for (i = 0; i < bb->stmts_used; i++) loop */
sewardj29632392004-08-22 02:38:11 +00005747 }
5748
5749 /* we get here for any other kind of statement. */
5750 /* 'use up' any bindings required by the current statement. */
sewardjf9517d02005-11-28 13:39:37 +00005751 st2 = atbSubst_Stmt(env, st);
sewardj29632392004-08-22 02:38:11 +00005752
sewardjf9517d02005-11-28 13:39:37 +00005753 /* Now, before this stmt, dump any bindings in env that it
5754 invalidates. These need to be dumped in the order in which
5755 they originally entered env -- that means from oldest to
5756 youngest. */
sewardj3e838932005-01-07 12:09:15 +00005757
florian740da722013-09-11 17:58:32 +00005758 /* putInterval/stmtStores characterise what the stmt under
sewardje9d8a262009-07-01 08:06:34 +00005759 consideration does, or might do (sidely safe @ True). */
florian62140c12013-01-20 03:51:04 +00005760
5761 Bool putRequiresPreciseMemExns;
florian740da722013-09-11 17:58:32 +00005762 putInterval = stmt_modifies_guest_state( bb, st, preciseMemExnsFn,
5763 &putRequiresPreciseMemExns);
sewardj29632392004-08-22 02:38:11 +00005764
sewardje9d8a262009-07-01 08:06:34 +00005765 /* be True if this stmt writes memory or might do (==> we don't
5766 want to reorder other loads or stores relative to it). Also,
sewardje768e922009-11-26 17:17:37 +00005767 both LL and SC fall under this classification, since we
sewardje9d8a262009-07-01 08:06:34 +00005768 really ought to be conservative and not reorder any other
sewardje768e922009-11-26 17:17:37 +00005769 memory transactions relative to them. */
sewardje9d8a262009-07-01 08:06:34 +00005770 stmtStores
5771 = toBool( st->tag == Ist_Store
florian088809c2012-12-30 18:17:18 +00005772 || (st->tag == Ist_Dirty
5773 && dirty_helper_stores(st->Ist.Dirty.details))
sewardj0f621982012-04-12 21:05:16 +00005774 || st->tag == Ist_LLSC
5775 || st->tag == Ist_CAS );
sewardj29632392004-08-22 02:38:11 +00005776
sewardjf9517d02005-11-28 13:39:37 +00005777 for (k = A_NENV-1; k >= 0; k--) {
5778 if (env[k].bindee == NULL)
5779 continue;
5780 /* Compare the actions of this stmt with the actions of
5781 binding 'k', to see if they invalidate the binding. */
5782 invalidateMe
sewardj9d2e7692005-02-07 01:11:31 +00005783 = toBool(
5784 /* a store invalidates loaded data */
sewardjf9517d02005-11-28 13:39:37 +00005785 (env[k].doesLoad && stmtStores)
florian740da722013-09-11 17:58:32 +00005786 /* a put invalidates get'd data, if they overlap */
5787 || ((env[k].getInterval.present && putInterval.present) &&
5788 intervals_overlap(env[k].getInterval, putInterval))
florian62140c12013-01-20 03:51:04 +00005789 /* a put invalidates loaded data. That means, in essense, that
5790 a load expression cannot be substituted into a statement
5791 that follows the put. But there is nothing wrong doing so
5792 except when the put statement requries precise exceptions.
5793 Think of a load that is moved past a put where the put
5794 updates the IP in the guest state. If the load generates
5795 a segfault, the wrong address (line number) would be
5796 reported. */
florian740da722013-09-11 17:58:32 +00005797 || (env[k].doesLoad && putInterval.present &&
5798 putRequiresPreciseMemExns)
sewardjc4356f02007-11-09 21:15:04 +00005799 /* probably overly conservative: a memory bus event
sewardj3e838932005-01-07 12:09:15 +00005800 invalidates absolutely everything, so that all
5801 computation prior to it is forced to complete before
sewardjc4356f02007-11-09 21:15:04 +00005802 proceeding with the event (fence,lock,unlock). */
5803 || st->tag == Ist_MBE
sewardj5a9ffab2005-05-12 17:55:01 +00005804 /* also be (probably overly) paranoid re AbiHints */
5805 || st->tag == Ist_AbiHint
sewardj9d2e7692005-02-07 01:11:31 +00005806 );
sewardjf9517d02005-11-28 13:39:37 +00005807 if (invalidateMe) {
sewardjdd40fdf2006-12-24 02:20:24 +00005808 bb->stmts[j] = IRStmt_WrTmp( env[k].binder, env[k].bindee );
sewardjf9517d02005-11-28 13:39:37 +00005809 j++;
5810 vassert(j <= i);
5811 env[k].bindee = NULL;
5812 }
sewardj29632392004-08-22 02:38:11 +00005813 }
5814
sewardjf9517d02005-11-28 13:39:37 +00005815 /* Slide in-use entries in env up to the front */
5816 m = 0;
5817 for (k = 0; k < A_NENV; k++) {
5818 if (env[k].bindee != NULL) {
5819 env[m] = env[k];
5820 m++;
5821 }
5822 }
5823 for (m = m; m < A_NENV; m++) {
5824 env[m].bindee = NULL;
5825 }
sewardj29632392004-08-22 02:38:11 +00005826
5827 /* finally, emit the substituted statement */
5828 bb->stmts[j] = st2;
sewardjf9517d02005-11-28 13:39:37 +00005829 /* vex_printf("**2 "); ppIRStmt(bb->stmts[j]); vex_printf("\n"); */
sewardj29632392004-08-22 02:38:11 +00005830 j++;
5831
5832 vassert(j <= i+1);
5833 } /* for each stmt in the original bb ... */
5834
5835 /* Finally ... substitute the ->next field as much as possible, and
5836 dump any left-over bindings. Hmm. Perhaps there should be no
5837 left over bindings? Or any left-over bindings are
5838 by definition dead? */
sewardjf9517d02005-11-28 13:39:37 +00005839 bb->next = atbSubst_Expr(env, bb->next);
sewardj29632392004-08-22 02:38:11 +00005840 bb->stmts_used = j;
sewardjc6f970f2012-04-02 21:54:49 +00005841
floriandcd6d232015-01-02 17:32:21 +00005842 return max_ga_known ? max_ga : ~(Addr)0;
sewardj29632392004-08-22 02:38:11 +00005843}
5844
5845
sewardj695cff92004-10-13 14:50:14 +00005846/*---------------------------------------------------------------*/
sewardjedf4d692004-08-17 13:52:58 +00005847/*--- iropt main ---*/
5848/*---------------------------------------------------------------*/
5849
sewardjb183b852006-02-03 16:08:03 +00005850static Bool iropt_verbose = False; /* True; */
sewardj4345f7a2004-09-22 19:49:27 +00005851
5852
sewardj4345f7a2004-09-22 19:49:27 +00005853/* Do a simple cleanup pass on bb. This is: redundant Get removal,
5854 redundant Put removal, constant propagation, dead code removal,
5855 clean helper specialisation, and dead code removal (again).
sewardjb9230752004-12-29 19:25:06 +00005856*/
sewardj695cff92004-10-13 14:50:14 +00005857
sewardj4345f7a2004-09-22 19:49:27 +00005858
5859static
sewardjdd40fdf2006-12-24 02:20:24 +00005860IRSB* cheap_transformations (
5861 IRSB* bb,
florian1ff47562012-10-21 02:09:51 +00005862 IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int),
sewardj8d2291c2004-10-25 14:50:21 +00005863 Bool (*preciseMemExnsFn)(Int,Int)
5864 )
sewardj4345f7a2004-09-22 19:49:27 +00005865{
5866 redundant_get_removal_BB ( bb );
5867 if (iropt_verbose) {
5868 vex_printf("\n========= REDUNDANT GET\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005869 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005870 }
sewardj044a2152004-10-21 10:22:10 +00005871
philippe6c46bef2012-08-14 22:29:01 +00005872 if (vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn) {
philippec8e2f982012-08-01 22:04:13 +00005873 redundant_put_removal_BB ( bb, preciseMemExnsFn );
5874 }
sewardj4345f7a2004-09-22 19:49:27 +00005875 if (iropt_verbose) {
5876 vex_printf("\n========= REDUNDANT PUT\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005877 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005878 }
sewardj044a2152004-10-21 10:22:10 +00005879
sewardj4345f7a2004-09-22 19:49:27 +00005880 bb = cprop_BB ( bb );
5881 if (iropt_verbose) {
5882 vex_printf("\n========= CPROPD\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005883 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005884 }
5885
sewardj49651f42004-10-28 22:11:04 +00005886 do_deadcode_BB ( bb );
sewardj4345f7a2004-09-22 19:49:27 +00005887 if (iropt_verbose) {
5888 vex_printf("\n========= DEAD\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005889 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005890 }
5891
sewardjb9230752004-12-29 19:25:06 +00005892 bb = spec_helpers_BB ( bb, specHelper );
sewardj49651f42004-10-28 22:11:04 +00005893 do_deadcode_BB ( bb );
sewardj4345f7a2004-09-22 19:49:27 +00005894 if (iropt_verbose) {
5895 vex_printf("\n========= SPECd \n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005896 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005897 }
5898
5899 return bb;
5900}
5901
sewardj695cff92004-10-13 14:50:14 +00005902
5903/* Do some more expensive transformations on bb, which are aimed at
5904 optimising as much as possible in the presence of GetI and PutI. */
5905
5906static
sewardjdd40fdf2006-12-24 02:20:24 +00005907IRSB* expensive_transformations( IRSB* bb )
sewardj695cff92004-10-13 14:50:14 +00005908{
sewardj9b0cc582006-02-04 15:24:00 +00005909 (void)do_cse_BB( bb );
sewardj695cff92004-10-13 14:50:14 +00005910 collapse_AddSub_chains_BB( bb );
sewardj08210532004-12-29 17:09:11 +00005911 do_redundant_GetI_elimination( bb );
philippe6c46bef2012-08-14 22:29:01 +00005912 if (vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn) {
philippec8e2f982012-08-01 22:04:13 +00005913 do_redundant_PutI_elimination( bb );
5914 }
sewardj49651f42004-10-28 22:11:04 +00005915 do_deadcode_BB( bb );
sewardjb9230752004-12-29 19:25:06 +00005916 return bb;
sewardj695cff92004-10-13 14:50:14 +00005917}
5918
5919
sewardjb183b852006-02-03 16:08:03 +00005920/* Scan a flattened BB to look for signs that more expensive
5921 optimisations might be useful:
5922 - find out if there are any GetIs and PutIs
5923 - find out if there are any floating or vector-typed temporaries
5924*/
sewardj695cff92004-10-13 14:50:14 +00005925
sewardjb183b852006-02-03 16:08:03 +00005926static void considerExpensives ( /*OUT*/Bool* hasGetIorPutI,
5927 /*OUT*/Bool* hasVorFtemps,
sewardjdd40fdf2006-12-24 02:20:24 +00005928 IRSB* bb )
sewardj4345f7a2004-09-22 19:49:27 +00005929{
sewardje9d8a262009-07-01 08:06:34 +00005930 Int i, j;
5931 IRStmt* st;
sewardj4345f7a2004-09-22 19:49:27 +00005932 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00005933 IRCAS* cas;
sewardj4345f7a2004-09-22 19:49:27 +00005934
sewardjb183b852006-02-03 16:08:03 +00005935 *hasGetIorPutI = False;
5936 *hasVorFtemps = False;
5937
sewardj4345f7a2004-09-22 19:49:27 +00005938 for (i = 0; i < bb->stmts_used; i++) {
5939 st = bb->stmts[i];
sewardj4345f7a2004-09-22 19:49:27 +00005940 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00005941 case Ist_AbiHint:
5942 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +00005943 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +00005944 break;
sewardj4345f7a2004-09-22 19:49:27 +00005945 case Ist_PutI:
sewardjb183b852006-02-03 16:08:03 +00005946 *hasGetIorPutI = True;
5947 break;
sewardjdd40fdf2006-12-24 02:20:24 +00005948 case Ist_WrTmp:
5949 if (st->Ist.WrTmp.data->tag == Iex_GetI)
sewardjb183b852006-02-03 16:08:03 +00005950 *hasGetIorPutI = True;
sewardjdd40fdf2006-12-24 02:20:24 +00005951 switch (typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp)) {
sewardjb183b852006-02-03 16:08:03 +00005952 case Ity_I1: case Ity_I8: case Ity_I16:
5953 case Ity_I32: case Ity_I64: case Ity_I128:
5954 break;
sewardjc4530ae2012-05-21 10:18:49 +00005955 case Ity_F32: case Ity_F64: case Ity_F128:
5956 case Ity_V128: case Ity_V256:
sewardjb183b852006-02-03 16:08:03 +00005957 *hasVorFtemps = True;
5958 break;
sewardjc6bbd472012-04-02 10:20:48 +00005959 case Ity_D32: case Ity_D64: case Ity_D128:
5960 *hasVorFtemps = True;
5961 break;
sewardjb183b852006-02-03 16:08:03 +00005962 default:
5963 goto bad;
5964 }
sewardj4345f7a2004-09-22 19:49:27 +00005965 break;
5966 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00005967 vassert(isIRAtom(st->Ist.Put.data));
sewardj4345f7a2004-09-22 19:49:27 +00005968 break;
sewardjaf1ceca2005-06-30 23:31:27 +00005969 case Ist_Store:
5970 vassert(isIRAtom(st->Ist.Store.addr));
5971 vassert(isIRAtom(st->Ist.Store.data));
sewardj4345f7a2004-09-22 19:49:27 +00005972 break;
sewardjcfe046e2013-01-17 14:23:53 +00005973 case Ist_StoreG: {
5974 IRStoreG* sg = st->Ist.StoreG.details;
5975 vassert(isIRAtom(sg->addr));
5976 vassert(isIRAtom(sg->data));
5977 vassert(isIRAtom(sg->guard));
5978 break;
5979 }
5980 case Ist_LoadG: {
5981 IRLoadG* lg = st->Ist.LoadG.details;
5982 vassert(isIRAtom(lg->addr));
5983 vassert(isIRAtom(lg->alt));
5984 vassert(isIRAtom(lg->guard));
5985 break;
5986 }
sewardje9d8a262009-07-01 08:06:34 +00005987 case Ist_CAS:
5988 cas = st->Ist.CAS.details;
5989 vassert(isIRAtom(cas->addr));
5990 vassert(cas->expdHi == NULL || isIRAtom(cas->expdHi));
5991 vassert(isIRAtom(cas->expdLo));
5992 vassert(cas->dataHi == NULL || isIRAtom(cas->dataHi));
5993 vassert(isIRAtom(cas->dataLo));
5994 break;
sewardje768e922009-11-26 17:17:37 +00005995 case Ist_LLSC:
5996 vassert(isIRAtom(st->Ist.LLSC.addr));
5997 if (st->Ist.LLSC.storedata)
5998 vassert(isIRAtom(st->Ist.LLSC.storedata));
5999 break;
sewardj4345f7a2004-09-22 19:49:27 +00006000 case Ist_Dirty:
6001 d = st->Ist.Dirty.details;
sewardj496a58d2005-03-20 18:44:44 +00006002 vassert(isIRAtom(d->guard));
sewardj74142b82013-08-08 10:28:59 +00006003 for (j = 0; d->args[j]; j++) {
6004 IRExpr* arg = d->args[j];
florian90419562013-08-15 20:54:52 +00006005 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +00006006 vassert(isIRAtom(arg));
6007 }
sewardj4345f7a2004-09-22 19:49:27 +00006008 if (d->mFx != Ifx_None)
sewardj496a58d2005-03-20 18:44:44 +00006009 vassert(isIRAtom(d->mAddr));
sewardj4345f7a2004-09-22 19:49:27 +00006010 break;
sewardjd2445f62005-03-21 00:15:53 +00006011 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00006012 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00006013 case Ist_MBE:
sewardj3e838932005-01-07 12:09:15 +00006014 break;
6015 case Ist_Exit:
sewardj496a58d2005-03-20 18:44:44 +00006016 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj3e838932005-01-07 12:09:15 +00006017 break;
sewardj4345f7a2004-09-22 19:49:27 +00006018 default:
sewardjb183b852006-02-03 16:08:03 +00006019 bad:
sewardj4345f7a2004-09-22 19:49:27 +00006020 ppIRStmt(st);
sewardje768e922009-11-26 17:17:37 +00006021 vpanic("considerExpensives");
sewardj4345f7a2004-09-22 19:49:27 +00006022 }
sewardj4345f7a2004-09-22 19:49:27 +00006023 }
sewardj4345f7a2004-09-22 19:49:27 +00006024}
6025
6026
sewardj695cff92004-10-13 14:50:14 +00006027/* ---------------- The main iropt entry point. ---------------- */
6028
sewardjedf4d692004-08-17 13:52:58 +00006029/* exported from this file */
sewardj695cff92004-10-13 14:50:14 +00006030/* Rules of the game:
6031
6032 - IRExpr/IRStmt trees should be treated as immutable, as they
6033 may get shared. So never change a field of such a tree node;
6034 instead construct and return a new one if needed.
6035*/
6036
sewardj4345f7a2004-09-22 19:49:27 +00006037
sewardjbe917912010-08-22 12:38:53 +00006038IRSB* do_iropt_BB(
6039 IRSB* bb0,
florian1ff47562012-10-21 02:09:51 +00006040 IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int),
sewardjbe917912010-08-22 12:38:53 +00006041 Bool (*preciseMemExnsFn)(Int,Int),
floriand4cc0de2015-01-02 11:44:12 +00006042 Addr guest_addr,
sewardjbe917912010-08-22 12:38:53 +00006043 VexArch guest_arch
6044 )
sewardjedf4d692004-08-17 13:52:58 +00006045{
sewardj9d2e7692005-02-07 01:11:31 +00006046 static Int n_total = 0;
6047 static Int n_expensive = 0;
sewardj29632392004-08-22 02:38:11 +00006048
sewardjb183b852006-02-03 16:08:03 +00006049 Bool hasGetIorPutI, hasVorFtemps;
sewardjdd40fdf2006-12-24 02:20:24 +00006050 IRSB *bb, *bb2;
sewardj8c2c10b2004-10-16 20:51:52 +00006051
sewardj4345f7a2004-09-22 19:49:27 +00006052 n_total++;
6053
6054 /* First flatten the block out, since all other
6055 phases assume flat code. */
6056
6057 bb = flatten_BB ( bb0 );
6058
6059 if (iropt_verbose) {
6060 vex_printf("\n========= FLAT\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00006061 ppIRSB(bb);
sewardj84be7372004-08-18 13:59:33 +00006062 }
sewardjd7217032004-08-19 10:49:10 +00006063
sewardj08210532004-12-29 17:09:11 +00006064 /* If at level 0, stop now. */
6065 if (vex_control.iropt_level <= 0) return bb;
6066
sewardj695cff92004-10-13 14:50:14 +00006067 /* Now do a preliminary cleanup pass, and figure out if we also
6068 need to do 'expensive' optimisations. Expensive optimisations
6069 are deemed necessary if the block contains any GetIs or PutIs.
6070 If needed, do expensive transformations and then another cheap
6071 cleanup pass. */
sewardj4345f7a2004-09-22 19:49:27 +00006072
sewardj8d2291c2004-10-25 14:50:21 +00006073 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj695cff92004-10-13 14:50:14 +00006074
sewardjbe917912010-08-22 12:38:53 +00006075 if (guest_arch == VexArchARM) {
6076 /* Translating Thumb2 code produces a lot of chaff. We have to
6077 work extra hard to get rid of it. */
6078 bb = cprop_BB(bb);
6079 bb = spec_helpers_BB ( bb, specHelper );
philippe6c46bef2012-08-14 22:29:01 +00006080 if (vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn) {
philippec8e2f982012-08-01 22:04:13 +00006081 redundant_put_removal_BB ( bb, preciseMemExnsFn );
6082 }
sewardjd5436ce2011-05-01 18:36:51 +00006083 do_cse_BB( bb );
sewardjbe917912010-08-22 12:38:53 +00006084 do_deadcode_BB( bb );
6085 }
6086
sewardj08613742004-10-25 13:01:45 +00006087 if (vex_control.iropt_level > 1) {
sewardjb183b852006-02-03 16:08:03 +00006088
6089 /* Peer at what we have, to decide how much more effort to throw
6090 at it. */
6091 considerExpensives( &hasGetIorPutI, &hasVorFtemps, bb );
6092
sewardj9b0cc582006-02-04 15:24:00 +00006093 if (hasVorFtemps && !hasGetIorPutI) {
sewardjb183b852006-02-03 16:08:03 +00006094 /* If any evidence of FP or Vector activity, CSE, as that
6095 tends to mop up all manner of lardy code to do with
sewardj9b0cc582006-02-04 15:24:00 +00006096 rounding modes. Don't bother if hasGetIorPutI since that
6097 case leads into the expensive transformations, which do
6098 CSE anyway. */
6099 (void)do_cse_BB( bb );
sewardjb183b852006-02-03 16:08:03 +00006100 do_deadcode_BB( bb );
6101 }
6102
6103 if (hasGetIorPutI) {
sewardj9b0cc582006-02-04 15:24:00 +00006104 Bool cses;
sewardj39555aa2004-10-24 22:29:19 +00006105 n_expensive++;
sewardj39555aa2004-10-24 22:29:19 +00006106 if (DEBUG_IROPT)
6107 vex_printf("***** EXPENSIVE %d %d\n", n_total, n_expensive);
sewardj695cff92004-10-13 14:50:14 +00006108 bb = expensive_transformations( bb );
sewardj8d2291c2004-10-25 14:50:21 +00006109 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj9b0cc582006-02-04 15:24:00 +00006110 /* Potentially common up GetIs */
6111 cses = do_cse_BB( bb );
6112 if (cses)
6113 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj695cff92004-10-13 14:50:14 +00006114 }
sewardj39555aa2004-10-24 22:29:19 +00006115
6116 /* Now have a go at unrolling simple (single-BB) loops. If
6117 successful, clean up the results as much as possible. */
6118
6119 bb2 = maybe_loop_unroll_BB( bb, guest_addr );
6120 if (bb2) {
sewardj8d2291c2004-10-25 14:50:21 +00006121 bb = cheap_transformations( bb2, specHelper, preciseMemExnsFn );
sewardjb183b852006-02-03 16:08:03 +00006122 if (hasGetIorPutI) {
sewardj39555aa2004-10-24 22:29:19 +00006123 bb = expensive_transformations( bb );
sewardj8d2291c2004-10-25 14:50:21 +00006124 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj39555aa2004-10-24 22:29:19 +00006125 } else {
6126 /* at least do CSE and dead code removal */
sewardjfe1ccfc2004-11-11 02:14:45 +00006127 do_cse_BB( bb );
sewardj49651f42004-10-28 22:11:04 +00006128 do_deadcode_BB( bb );
sewardj39555aa2004-10-24 22:29:19 +00006129 }
6130 if (0) vex_printf("vex iropt: unrolled a loop\n");
6131 }
6132
sewardjd7217032004-08-19 10:49:10 +00006133 }
6134
sewardj4345f7a2004-09-22 19:49:27 +00006135 return bb;
sewardjedf4d692004-08-17 13:52:58 +00006136}
6137
6138
sewardja1a370f2004-08-17 13:31:55 +00006139/*---------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +00006140/*--- end ir_opt.c ---*/
sewardja1a370f2004-08-17 13:31:55 +00006141/*---------------------------------------------------------------*/