blob: 95bdb28ef1791f359d1cb7d0f11aab27536680ee [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
806 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +0000807 vassert(isIRAtom(st->Ist.PutI.details->ix));
808 vassert(isIRAtom(st->Ist.PutI.details->data));
sewardj08210532004-12-29 17:09:11 +0000809 break;
810
sewardjd2445f62005-03-21 00:15:53 +0000811 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +0000812 case Ist_IMark:
813 break;
814
sewardj08210532004-12-29 17:09:11 +0000815 default:
816 vex_printf("\n");
817 ppIRStmt(st);
818 vex_printf("\n");
819 vpanic("handle_gets_Stmt");
820 }
821
822 if (memRW) {
philippe6c46bef2012-08-14 22:29:01 +0000823 /* This statement accesses memory. So we might need to dump all parts
sewardj08210532004-12-29 17:09:11 +0000824 of the environment corresponding to guest state that may not
825 be reordered with respect to memory references. That means
826 at least the stack pointer. */
philippec8e2f982012-08-01 22:04:13 +0000827 switch (vex_control.iropt_register_updates) {
828 case VexRegUpdAllregsAtMemAccess:
829 /* Precise exceptions required at mem access.
830 Flush all guest state. */
831 for (j = 0; j < env->used; j++)
sewardj08210532004-12-29 17:09:11 +0000832 env->inuse[j] = False;
philippec8e2f982012-08-01 22:04:13 +0000833 break;
philippe6c46bef2012-08-14 22:29:01 +0000834 case VexRegUpdSpAtMemAccess:
835 /* We need to dump the stack pointer
836 (needed for stack extension in m_signals.c).
837 preciseMemExnsFn will use vex_control.iropt_register_updates
838 to verify only the sp is to be checked. */
839 /* fallthrough */
philippec8e2f982012-08-01 22:04:13 +0000840 case VexRegUpdUnwindregsAtMemAccess:
841 for (j = 0; j < env->used; j++) {
842 if (!env->inuse[j])
843 continue;
844 /* Just flush the minimal amount required, as computed by
845 preciseMemExnsFn. */
846 HWord k_lo = (env->key[j] >> 16) & 0xFFFF;
847 HWord k_hi = env->key[j] & 0xFFFF;
848 if (preciseMemExnsFn( k_lo, k_hi ))
849 env->inuse[j] = False;
850 }
851 break;
852 default:
853 // VexRegUpdAllregsAtEachInsn cannot happen here.
854 // Neither any rubbish other value.
855 vassert(0);
sewardj08210532004-12-29 17:09:11 +0000856 }
857 } /* if (memRW) */
858
859}
860
861
862/* Scan backwards, building up a set of (min offset, max
863 offset) pairs, indicating those parts of the guest state
864 for which the next event is a write.
865
866 On seeing a conditional exit, empty the set.
867
868 On seeing 'Put (minoff,maxoff) = t or c', if (minoff,maxoff) is
869 completely within the set, remove the Put. Otherwise, add
870 (minoff,maxoff) to the set.
871
872 On seeing 'Get (minoff,maxoff)', remove any part of the set
sewardj98430292004-12-29 17:34:50 +0000873 overlapping (minoff,maxoff). The same has to happen for any events
874 which implicitly read parts of the guest state: dirty helper calls
875 and loads/stores.
sewardj08210532004-12-29 17:09:11 +0000876*/
877
878static void redundant_put_removal_BB (
sewardjdd40fdf2006-12-24 02:20:24 +0000879 IRSB* bb,
sewardj08210532004-12-29 17:09:11 +0000880 Bool (*preciseMemExnsFn)(Int,Int)
881 )
882{
883 Int i, j;
884 Bool isPut;
885 IRStmt* st;
886 UInt key = 0; /* keep gcc -O happy */
887
philippe6c46bef2012-08-14 22:29:01 +0000888 vassert(vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn);
philippec8e2f982012-08-01 22:04:13 +0000889
sewardj08210532004-12-29 17:09:11 +0000890 HashHW* env = newHHW();
sewardjc6f970f2012-04-02 21:54:49 +0000891
892 /* Initialise the running env with the fact that the final exit
893 writes the IP (or, whatever it claims to write. We don't
894 care.) */
895 key = mk_key_GetPut(bb->offsIP, typeOfIRExpr(bb->tyenv, bb->next));
896 addToHHW(env, (HWord)key, 0);
897
898 /* And now scan backwards through the statements. */
sewardj08210532004-12-29 17:09:11 +0000899 for (i = bb->stmts_used-1; i >= 0; i--) {
900 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +0000901
902 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +0000903 continue;
904
905 /* Deal with conditional exits. */
906 if (st->tag == Ist_Exit) {
sewardjc6f970f2012-04-02 21:54:49 +0000907 //Bool re_add;
908 /* Need to throw out from the env, any part of it which
909 doesn't overlap with the guest state written by this exit.
910 Since the exit only writes one section, it's simplest to
911 do this: (1) check whether env contains a write that
912 completely overlaps the write done by this exit; (2) empty
913 out env; and (3) if (1) was true, add the write done by
914 this exit.
915
916 To make (1) a bit simpler, merely search for a write that
917 exactly matches the one done by this exit. That's safe
918 because it will fail as often or more often than a full
919 overlap check, and failure to find an overlapping write in
920 env is the safe case (we just nuke env if that
921 happens). */
922 //vassert(isIRAtom(st->Ist.Exit.guard));
923 /* (1) */
924 //key = mk_key_GetPut(st->Ist.Exit.offsIP,
925 // typeOfIRConst(st->Ist.Exit.dst));
926 //re_add = lookupHHW(env, NULL, key);
927 /* (2) */
sewardj08210532004-12-29 17:09:11 +0000928 for (j = 0; j < env->used; j++)
929 env->inuse[j] = False;
sewardjc6f970f2012-04-02 21:54:49 +0000930 /* (3) */
931 //if (0 && re_add)
932 // addToHHW(env, (HWord)key, 0);
sewardj08210532004-12-29 17:09:11 +0000933 continue;
934 }
935
936 /* Deal with Puts */
937 switch (st->tag) {
938 case Ist_Put:
939 isPut = True;
940 key = mk_key_GetPut( st->Ist.Put.offset,
941 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
sewardj496a58d2005-03-20 18:44:44 +0000942 vassert(isIRAtom(st->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +0000943 break;
944 case Ist_PutI:
945 isPut = True;
floriand6f38b32012-05-31 15:46:18 +0000946 key = mk_key_GetIPutI( st->Ist.PutI.details->descr );
947 vassert(isIRAtom(st->Ist.PutI.details->ix));
948 vassert(isIRAtom(st->Ist.PutI.details->data));
sewardj08210532004-12-29 17:09:11 +0000949 break;
950 default:
951 isPut = False;
952 }
953 if (isPut && st->tag != Ist_PutI) {
954 /* See if any single entry in env overlaps this Put. This is
955 simplistic in that the transformation is valid if, say, two
956 or more entries in the env overlap this Put, but the use of
957 lookupHHW will only find a single entry which exactly
958 overlaps this Put. This is suboptimal but safe. */
959 if (lookupHHW(env, NULL, (HWord)key)) {
960 /* This Put is redundant because a later one will overwrite
961 it. So NULL (nop) it out. */
962 if (DEBUG_IROPT) {
963 vex_printf("rPUT: "); ppIRStmt(st);
964 vex_printf("\n");
965 }
sewardjd2445f62005-03-21 00:15:53 +0000966 bb->stmts[i] = IRStmt_NoOp();
sewardj08210532004-12-29 17:09:11 +0000967 } else {
968 /* We can't demonstrate that this Put is redundant, so add it
969 to the running collection. */
970 addToHHW(env, (HWord)key, 0);
971 }
972 continue;
973 }
974
975 /* Deal with Gets. These remove bits of the environment since
976 appearance of a Get means that the next event for that slice
sewardj98430292004-12-29 17:34:50 +0000977 of the guest state is no longer a write, but a read. Also
978 deals with implicit reads of guest state needed to maintain
979 precise exceptions. */
sewardj08210532004-12-29 17:09:11 +0000980 handle_gets_Stmt( env, st, preciseMemExnsFn );
981 }
982}
983
sewardj84be7372004-08-18 13:59:33 +0000984
985/*---------------------------------------------------------------*/
986/*--- Constant propagation and folding ---*/
987/*---------------------------------------------------------------*/
988
floriancdb5fee2012-02-13 00:06:29 +0000989#if STATS_IROPT
990/* How often sameIRExprs was invoked */
991static UInt invocation_count;
992/* How often sameIRExprs recursed through IRTemp assignments */
993static UInt recursion_count;
994/* How often sameIRExprs found identical IRExprs */
995static UInt success_count;
996/* How often recursing through assignments to IRTemps helped
997 establishing equality. */
998static UInt recursion_success_count;
999/* Whether or not recursing through an IRTemp assignment helped
1000 establishing IRExpr equality for a given sameIRExprs invocation. */
1001static Bool recursion_helped;
1002/* Whether or not a given sameIRExprs invocation recursed through an
1003 IRTemp assignment */
1004static Bool recursed;
1005/* Maximum number of nodes ever visited when comparing two IRExprs. */
1006static UInt max_nodes_visited;
1007#endif /* STATS_IROPT */
1008
1009/* Count the number of nodes visited for a given sameIRExprs invocation. */
1010static UInt num_nodes_visited;
1011
1012/* Do not visit more than NODE_LIMIT nodes when comparing two IRExprs.
1013 This is to guard against performance degradation by visiting large
1014 trees without success. */
1015#define NODE_LIMIT 30
1016
1017
sewardj62617ef2004-10-13 23:29:22 +00001018/* The env in this section is a map from IRTemp to IRExpr*,
1019 that is, an array indexed by IRTemp. */
sewardjf6501992004-08-27 11:58:24 +00001020
floriancdb5fee2012-02-13 00:06:29 +00001021/* Do both expressions compute the same value? The answer is generally
1022 conservative, i.e. it will report that the expressions do not compute
1023 the same value when in fact they do. The reason is that we do not
1024 keep track of changes in the guest state and memory. Thusly, two
1025 Get's, GetI's or Load's, even when accessing the same location, will be
1026 assumed to compute different values. After all the accesses may happen
1027 at different times and the guest state / memory can have changed in
sewardja7e96382012-06-29 16:26:17 +00001028 the meantime.
1029
1030 XXX IMPORTANT XXX the two expressions must have the same IR type.
1031 DO NOT CALL HERE WITH DIFFERENTLY-TYPED EXPRESSIONS. */
sewardjc6f970f2012-04-02 21:54:49 +00001032
1033/* JRS 20-Mar-2012: split sameIRExprs_aux into a fast inlineable
1034 wrapper that deals with the common tags-don't-match case, and a
1035 slower out of line general case. Saves a few insns. */
1036
1037__attribute__((noinline))
1038static Bool sameIRExprs_aux2 ( IRExpr** env, IRExpr* e1, IRExpr* e2 );
1039
1040inline
floriancdb5fee2012-02-13 00:06:29 +00001041static Bool sameIRExprs_aux ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
sewardjf6729012004-08-25 12:45:13 +00001042{
floriancdb5fee2012-02-13 00:06:29 +00001043 if (e1->tag != e2->tag) return False;
sewardjc6f970f2012-04-02 21:54:49 +00001044 return sameIRExprs_aux2(env, e1, e2);
1045}
sewardjf6729012004-08-25 12:45:13 +00001046
sewardjc6f970f2012-04-02 21:54:49 +00001047__attribute__((noinline))
1048static Bool sameIRExprs_aux2 ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
1049{
floriancdb5fee2012-02-13 00:06:29 +00001050 if (num_nodes_visited++ > NODE_LIMIT) return False;
sewardj6c299f32009-12-31 18:00:12 +00001051
sewardj6c299f32009-12-31 18:00:12 +00001052 switch (e1->tag) {
1053 case Iex_RdTmp:
floriancdb5fee2012-02-13 00:06:29 +00001054 if (e1->Iex.RdTmp.tmp == e2->Iex.RdTmp.tmp) return True;
1055
1056 if (env[e1->Iex.RdTmp.tmp] && env[e2->Iex.RdTmp.tmp]) {
1057 Bool same = sameIRExprs_aux(env, env[e1->Iex.RdTmp.tmp],
1058 env[e2->Iex.RdTmp.tmp]);
1059#if STATS_IROPT
1060 recursed = True;
1061 if (same) recursion_helped = True;
1062#endif
1063 return same;
1064 }
sewardj6c299f32009-12-31 18:00:12 +00001065 return False;
floriancdb5fee2012-02-13 00:06:29 +00001066
1067 case Iex_Get:
1068 case Iex_GetI:
1069 case Iex_Load:
1070 /* Guest state / memory could have changed in the meantime. */
1071 return False;
1072
1073 case Iex_Binop:
1074 return toBool( e1->Iex.Binop.op == e2->Iex.Binop.op
sewardj6399f812012-06-29 15:36:44 +00001075 && sameIRExprs_aux( env, e1->Iex.Binop.arg1,
1076 e2->Iex.Binop.arg1 )
1077 && sameIRExprs_aux( env, e1->Iex.Binop.arg2,
1078 e2->Iex.Binop.arg2 ));
floriancdb5fee2012-02-13 00:06:29 +00001079
1080 case Iex_Unop:
1081 return toBool( e1->Iex.Unop.op == e2->Iex.Unop.op
sewardj6399f812012-06-29 15:36:44 +00001082 && sameIRExprs_aux( env, e1->Iex.Unop.arg,
1083 e2->Iex.Unop.arg ));
floriancdb5fee2012-02-13 00:06:29 +00001084
1085 case Iex_Const: {
1086 IRConst *c1 = e1->Iex.Const.con;
1087 IRConst *c2 = e2->Iex.Const.con;
1088 vassert(c1->tag == c2->tag);
1089 switch (c1->tag) {
1090 case Ico_U1: return toBool( c1->Ico.U1 == c2->Ico.U1 );
1091 case Ico_U8: return toBool( c1->Ico.U8 == c2->Ico.U8 );
1092 case Ico_U16: return toBool( c1->Ico.U16 == c2->Ico.U16 );
1093 case Ico_U32: return toBool( c1->Ico.U32 == c2->Ico.U32 );
1094 case Ico_U64: return toBool( c1->Ico.U64 == c2->Ico.U64 );
1095 default: break;
1096 }
1097 return False;
1098 }
1099
florian420bfa92012-06-02 20:29:22 +00001100 case Iex_Triop: {
1101 IRTriop *tri1 = e1->Iex.Triop.details;
1102 IRTriop *tri2 = e2->Iex.Triop.details;
1103 return toBool( tri1->op == tri2->op
1104 && sameIRExprs_aux( env, tri1->arg1, tri2->arg1 )
1105 && sameIRExprs_aux( env, tri1->arg2, tri2->arg2 )
1106 && sameIRExprs_aux( env, tri1->arg3, tri2->arg3 ));
1107 }
floriancdb5fee2012-02-13 00:06:29 +00001108
florian99dd03e2013-01-29 03:56:06 +00001109 case Iex_ITE:
1110 return toBool( sameIRExprs_aux( env, e1->Iex.ITE.cond,
1111 e2->Iex.ITE.cond )
1112 && sameIRExprs_aux( env, e1->Iex.ITE.iftrue,
1113 e2->Iex.ITE.iftrue )
1114 && sameIRExprs_aux( env, e1->Iex.ITE.iffalse,
1115 e2->Iex.ITE.iffalse ));
floriancdb5fee2012-02-13 00:06:29 +00001116
1117 default:
1118 /* Not very likely to be "same". */
1119 break;
sewardj6c299f32009-12-31 18:00:12 +00001120 }
floriancdb5fee2012-02-13 00:06:29 +00001121
1122 return False;
sewardj6c299f32009-12-31 18:00:12 +00001123}
1124
sewardjc6f970f2012-04-02 21:54:49 +00001125inline
floriancdb5fee2012-02-13 00:06:29 +00001126static Bool sameIRExprs ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
1127{
1128 Bool same;
1129
1130 num_nodes_visited = 0;
1131 same = sameIRExprs_aux(env, e1, e2);
1132
1133#if STATS_IROPT
1134 ++invocation_count;
1135 if (recursed) ++recursion_count;
1136 success_count += same;
1137 if (same && recursion_helped)
1138 ++recursion_success_count;
1139 if (num_nodes_visited > max_nodes_visited)
1140 max_nodes_visited = num_nodes_visited;
1141 recursed = False; /* reset */
1142 recursion_helped = False; /* reset */
1143#endif /* STATS_IROPT */
1144
1145 return same;
1146}
1147
1148
sewardja7e96382012-06-29 16:26:17 +00001149/* Debugging-only hack (not used in production runs): make a guess
1150 whether sameIRExprs might assert due to the two args being of
1151 different types. If in doubt return False. Is only used when
1152 --vex-iropt-level > 0, that is, vex_control.iropt_verbosity > 0.
1153 Bad because it duplicates functionality from typeOfIRExpr. See
1154 comment on the single use point below for rationale. */
1155static
1156Bool debug_only_hack_sameIRExprs_might_assert ( IRExpr* e1, IRExpr* e2 )
1157{
1158 if (e1->tag != e2->tag) return False;
1159 switch (e1->tag) {
1160 case Iex_Const: {
1161 /* The only interesting case */
1162 IRConst *c1 = e1->Iex.Const.con;
1163 IRConst *c2 = e2->Iex.Const.con;
1164 return c1->tag != c2->tag;
1165 }
1166 default:
1167 break;
1168 }
1169 return False;
1170}
1171
1172
florianea7eab72011-07-21 16:21:58 +00001173/* Is this literally IRExpr_Const(IRConst_U32(0)) ? */
1174static Bool isZeroU32 ( IRExpr* e )
1175{
1176 return toBool( e->tag == Iex_Const
1177 && e->Iex.Const.con->tag == Ico_U32
1178 && e->Iex.Const.con->Ico.U32 == 0);
1179}
1180
florian40226d12014-07-16 20:29:38 +00001181/* Is this literally IRExpr_Const(IRConst_U64(0)) ?
1182 Currently unused; commented out to avoid compiler warning */
1183#if 0
sewardjbbcf1882014-01-12 12:49:10 +00001184static Bool isZeroU64 ( IRExpr* e )
1185{
1186 return toBool( e->tag == Iex_Const
1187 && e->Iex.Const.con->tag == Ico_U64
1188 && e->Iex.Const.con->Ico.U64 == 0);
1189}
florian40226d12014-07-16 20:29:38 +00001190#endif
sewardjbbcf1882014-01-12 12:49:10 +00001191
sewardj9571dc02014-01-26 18:34:23 +00001192/* Is this literally IRExpr_Const(IRConst_V128(0)) ? */
1193static Bool isZeroV128 ( IRExpr* e )
1194{
1195 return toBool( e->tag == Iex_Const
1196 && e->Iex.Const.con->tag == Ico_V128
1197 && e->Iex.Const.con->Ico.V128 == 0x0000);
1198}
1199
1200/* Is this literally IRExpr_Const(IRConst_V256(0)) ? */
1201static Bool isZeroV256 ( IRExpr* e )
1202{
1203 return toBool( e->tag == Iex_Const
1204 && e->Iex.Const.con->tag == Ico_V256
1205 && e->Iex.Const.con->Ico.V256 == 0x00000000);
1206}
1207
florianf6402ab2012-01-29 02:19:43 +00001208/* Is this an integer constant with value 0 ? */
1209static Bool isZeroU ( IRExpr* e )
1210{
1211 if (e->tag != Iex_Const) return False;
florianf6402ab2012-01-29 02:19:43 +00001212 switch (e->Iex.Const.con->tag) {
1213 case Ico_U1: return toBool( e->Iex.Const.con->Ico.U1 == 0);
1214 case Ico_U8: return toBool( e->Iex.Const.con->Ico.U8 == 0);
1215 case Ico_U16: return toBool( e->Iex.Const.con->Ico.U16 == 0);
1216 case Ico_U32: return toBool( e->Iex.Const.con->Ico.U32 == 0);
1217 case Ico_U64: return toBool( e->Iex.Const.con->Ico.U64 == 0);
1218 default: vpanic("isZeroU");
1219 }
1220}
1221
sewardjcf4be4a2012-03-26 09:44:39 +00001222/* Is this an integer constant with value 1---1b ? */
1223static Bool isOnesU ( IRExpr* e )
1224{
1225 if (e->tag != Iex_Const) return False;
1226 switch (e->Iex.Const.con->tag) {
1227 case Ico_U8: return toBool( e->Iex.Const.con->Ico.U8 == 0xFF);
1228 case Ico_U16: return toBool( e->Iex.Const.con->Ico.U16 == 0xFFFF);
1229 case Ico_U32: return toBool( e->Iex.Const.con->Ico.U32
1230 == 0xFFFFFFFF);
1231 case Ico_U64: return toBool( e->Iex.Const.con->Ico.U64
1232 == 0xFFFFFFFFFFFFFFFFULL);
1233 default: ppIRExpr(e); vpanic("isOnesU");
1234 }
1235}
1236
sewardje1d45da2004-11-12 00:13:21 +00001237static Bool notBool ( Bool b )
1238{
1239 if (b == True) return False;
1240 if (b == False) return True;
1241 vpanic("notBool");
1242}
1243
sewardj0033ddc2005-04-26 23:34:34 +00001244/* Make a zero which has the same type as the result of the given
1245 primop. */
sewardj64d776c2010-10-01 14:06:22 +00001246static IRExpr* mkZeroOfPrimopResultType ( IROp op )
sewardj0033ddc2005-04-26 23:34:34 +00001247{
1248 switch (op) {
sewardja7e96382012-06-29 16:26:17 +00001249 case Iop_CmpNE32: return IRExpr_Const(IRConst_U1(toBool(0)));
sewardj0033ddc2005-04-26 23:34:34 +00001250 case Iop_Xor8: return IRExpr_Const(IRConst_U8(0));
1251 case Iop_Xor16: return IRExpr_Const(IRConst_U16(0));
sewardjbe917912010-08-22 12:38:53 +00001252 case Iop_Sub32:
sewardj0033ddc2005-04-26 23:34:34 +00001253 case Iop_Xor32: return IRExpr_Const(IRConst_U32(0));
sewardjbbcf1882014-01-12 12:49:10 +00001254 case Iop_And64:
sewardj64d776c2010-10-01 14:06:22 +00001255 case Iop_Sub64:
sewardj0033ddc2005-04-26 23:34:34 +00001256 case Iop_Xor64: return IRExpr_Const(IRConst_U64(0));
sewardj36a911a2014-04-03 13:48:21 +00001257 case Iop_XorV128:
1258 case Iop_AndV128: return IRExpr_Const(IRConst_V128(0));
florian1b7c4712014-07-16 20:17:49 +00001259 case Iop_AndV256: return IRExpr_Const(IRConst_V256(0));
sewardj64d776c2010-10-01 14:06:22 +00001260 default: vpanic("mkZeroOfPrimopResultType: bad primop");
1261 }
1262}
1263
1264/* Make a value containing all 1-bits, which has the same type as the
1265 result of the given primop. */
1266static IRExpr* mkOnesOfPrimopResultType ( IROp op )
1267{
1268 switch (op) {
sewardja7e96382012-06-29 16:26:17 +00001269 case Iop_CmpEQ32:
sewardj64d776c2010-10-01 14:06:22 +00001270 case Iop_CmpEQ64:
1271 return IRExpr_Const(IRConst_U1(toBool(1)));
sewardjcf4be4a2012-03-26 09:44:39 +00001272 case Iop_Or8:
1273 return IRExpr_Const(IRConst_U8(0xFF));
1274 case Iop_Or16:
1275 return IRExpr_Const(IRConst_U16(0xFFFF));
1276 case Iop_Or32:
1277 return IRExpr_Const(IRConst_U32(0xFFFFFFFF));
sewardj64d776c2010-10-01 14:06:22 +00001278 case Iop_CmpEQ8x8:
sewardjcf4be4a2012-03-26 09:44:39 +00001279 case Iop_Or64:
sewardj64d776c2010-10-01 14:06:22 +00001280 return IRExpr_Const(IRConst_U64(0xFFFFFFFFFFFFFFFFULL));
1281 case Iop_CmpEQ8x16:
sewardj899d1832012-07-10 21:41:01 +00001282 case Iop_CmpEQ16x8:
sewardjffccf2b2012-06-29 15:33:09 +00001283 case Iop_CmpEQ32x4:
sewardj64d776c2010-10-01 14:06:22 +00001284 return IRExpr_Const(IRConst_V128(0xFFFF));
1285 default:
sewardjcf4be4a2012-03-26 09:44:39 +00001286 ppIROp(op);
sewardj64d776c2010-10-01 14:06:22 +00001287 vpanic("mkOnesOfPrimopResultType: bad primop");
sewardj0033ddc2005-04-26 23:34:34 +00001288 }
1289}
1290
sewardj4cba9f42011-03-07 18:34:34 +00001291/* Helpers for folding Clz32/64. */
1292static UInt fold_Clz64 ( ULong value )
1293{
1294 UInt i;
1295 vassert(value != 0ULL); /* no defined semantics for arg==0 */
1296 for (i = 0; i < 64; ++i) {
sewardj7f6330d2011-04-05 11:06:02 +00001297 if (0ULL != (value & (((ULong)1) << (63 - i)))) return i;
sewardj4cba9f42011-03-07 18:34:34 +00001298 }
1299 vassert(0);
1300 /*NOTREACHED*/
1301 return 0;
1302}
1303
1304static UInt fold_Clz32 ( UInt value )
1305{
1306 UInt i;
1307 vassert(value != 0); /* no defined semantics for arg==0 */
1308 for (i = 0; i < 32; ++i) {
sewardj7f6330d2011-04-05 11:06:02 +00001309 if (0 != (value & (((UInt)1) << (31 - i)))) return i;
sewardj4cba9f42011-03-07 18:34:34 +00001310 }
1311 vassert(0);
1312 /*NOTREACHED*/
1313 return 0;
1314}
1315
sewardj4a0bee02012-06-29 14:44:44 +00001316/* V64 holds 8 summary-constant bits in V128/V256 style. Convert to
1317 the corresponding real constant. */
1318//XXX re-check this before use
1319//static ULong de_summarise_V64 ( UChar v64 )
1320//{
1321// ULong r = 0;
1322// if (v64 & (1<<0)) r |= 0x00000000000000FFULL;
1323// if (v64 & (1<<1)) r |= 0x000000000000FF00ULL;
1324// if (v64 & (1<<2)) r |= 0x0000000000FF0000ULL;
1325// if (v64 & (1<<3)) r |= 0x00000000FF000000ULL;
1326// if (v64 & (1<<4)) r |= 0x000000FF00000000ULL;
1327// if (v64 & (1<<5)) r |= 0x0000FF0000000000ULL;
1328// if (v64 & (1<<6)) r |= 0x00FF000000000000ULL;
1329// if (v64 & (1<<7)) r |= 0xFF00000000000000ULL;
1330// return r;
1331//}
sewardj0033ddc2005-04-26 23:34:34 +00001332
sewardj009230b2013-01-26 11:47:55 +00001333/* Helper for arbitrary expression pattern matching in flat IR. If
1334 'e' is a reference to a tmp, look it up in env -- repeatedly, if
1335 necessary -- until it resolves to a non-tmp. Note that this can
1336 return NULL if it can't resolve 'e' to a new expression, which will
1337 be the case if 'e' is instead defined by an IRStmt (IRDirty or
1338 LLSC). */
1339static IRExpr* chase ( IRExpr** env, IRExpr* e )
1340{
1341 /* Why is this loop guaranteed to terminate? Because all tmps must
1342 have definitions before use, hence a tmp cannot be bound
1343 (directly or indirectly) to itself. */
1344 while (e->tag == Iex_RdTmp) {
1345 if (0) { vex_printf("chase "); ppIRExpr(e); vex_printf("\n"); }
1346 e = env[(Int)e->Iex.RdTmp.tmp];
1347 if (e == NULL) break;
1348 }
1349 return e;
1350}
1351
floriancdb5fee2012-02-13 00:06:29 +00001352static IRExpr* fold_Expr ( IRExpr** env, IRExpr* e )
sewardj84be7372004-08-18 13:59:33 +00001353{
sewardj278c44c2004-08-20 00:28:13 +00001354 Int shift;
sewardj84be7372004-08-18 13:59:33 +00001355 IRExpr* e2 = e; /* e2 is the result of folding e, if possible */
1356
florian708417d2012-02-15 00:43:36 +00001357 switch (e->tag) {
1358 case Iex_Unop:
1359 /* UNARY ops */
1360 if (e->Iex.Unop.arg->tag == Iex_Const) {
1361 switch (e->Iex.Unop.op) {
sewardjae27ab62004-10-15 21:21:46 +00001362 case Iop_1Uto8:
sewardj9d2e7692005-02-07 01:11:31 +00001363 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardjba999312004-11-15 15:21:17 +00001364 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardj9d2e7692005-02-07 01:11:31 +00001365 ? 1 : 0)));
sewardjae27ab62004-10-15 21:21:46 +00001366 break;
sewardjf4a821d2004-10-09 00:58:19 +00001367 case Iop_1Uto32:
1368 e2 = IRExpr_Const(IRConst_U32(
sewardjba999312004-11-15 15:21:17 +00001369 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardjf4a821d2004-10-09 00:58:19 +00001370 ? 1 : 0));
1371 break;
sewardj2716ff12005-05-20 19:21:45 +00001372 case Iop_1Uto64:
1373 e2 = IRExpr_Const(IRConst_U64(
1374 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
1375 ? 1 : 0));
1376 break;
sewardje6b39932004-11-06 17:01:15 +00001377
sewardj1bee5612005-11-10 18:10:58 +00001378 case Iop_1Sto8:
1379 e2 = IRExpr_Const(IRConst_U8(toUChar(
1380 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
1381 ? 0xFF : 0)));
1382 break;
sewardj68884ef2005-07-18 13:58:49 +00001383 case Iop_1Sto16:
sewardj743d8f02005-07-27 00:22:37 +00001384 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardj68884ef2005-07-18 13:58:49 +00001385 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardj743d8f02005-07-27 00:22:37 +00001386 ? 0xFFFF : 0)));
sewardj68884ef2005-07-18 13:58:49 +00001387 break;
sewardjd9997882004-11-04 19:42:59 +00001388 case Iop_1Sto32:
1389 e2 = IRExpr_Const(IRConst_U32(
sewardjba999312004-11-15 15:21:17 +00001390 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardjd9997882004-11-04 19:42:59 +00001391 ? 0xFFFFFFFF : 0));
1392 break;
sewardje6b39932004-11-06 17:01:15 +00001393 case Iop_1Sto64:
1394 e2 = IRExpr_Const(IRConst_U64(
sewardjba999312004-11-15 15:21:17 +00001395 e->Iex.Unop.arg->Iex.Const.con->Ico.U1
sewardje6b39932004-11-06 17:01:15 +00001396 ? 0xFFFFFFFFFFFFFFFFULL : 0));
1397 break;
1398
sewardj883b00b2004-09-11 09:30:24 +00001399 case Iop_8Sto32: {
1400 /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
1401 s32 <<= 24;
1402 s32 >>= 24;
1403 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
1404 break;
1405 }
sewardj7f6330d2011-04-05 11:06:02 +00001406 case Iop_16Sto32: {
1407 /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1408 s32 <<= 16;
1409 s32 >>= 16;
1410 e2 = IRExpr_Const(IRConst_U32( (UInt)s32) );
1411 break;
1412 }
sewardj291a7e82005-04-27 11:42:44 +00001413 case Iop_8Uto64:
1414 e2 = IRExpr_Const(IRConst_U64(
1415 0xFFULL & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1416 break;
1417 case Iop_16Uto64:
1418 e2 = IRExpr_Const(IRConst_U64(
1419 0xFFFFULL & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
1420 break;
sewardj84be7372004-08-18 13:59:33 +00001421 case Iop_8Uto32:
1422 e2 = IRExpr_Const(IRConst_U32(
1423 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1424 break;
sewardj7f6330d2011-04-05 11:06:02 +00001425 case Iop_8Sto16: {
1426 /* signed */ Short s16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
1427 s16 <<= 8;
1428 s16 >>= 8;
1429 e2 = IRExpr_Const(IRConst_U16( (UShort)s16) );
1430 break;
1431 }
1432 case Iop_8Uto16:
1433 e2 = IRExpr_Const(IRConst_U16(
1434 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
1435 break;
sewardj84be7372004-08-18 13:59:33 +00001436 case Iop_16Uto32:
1437 e2 = IRExpr_Const(IRConst_U32(
1438 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
1439 break;
sewardj73017432004-10-14 19:33:25 +00001440 case Iop_32to16:
sewardj9d2e7692005-02-07 01:11:31 +00001441 e2 = IRExpr_Const(IRConst_U16(toUShort(
1442 0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
sewardj73017432004-10-14 19:33:25 +00001443 break;
sewardj4345f7a2004-09-22 19:49:27 +00001444 case Iop_32to8:
sewardj9d2e7692005-02-07 01:11:31 +00001445 e2 = IRExpr_Const(IRConst_U8(toUChar(
1446 0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
sewardj4345f7a2004-09-22 19:49:27 +00001447 break;
sewardj7447b5b2004-10-16 11:30:42 +00001448 case Iop_32to1:
sewardj9d2e7692005-02-07 01:11:31 +00001449 e2 = IRExpr_Const(IRConst_U1(toBool(
1450 1 == (1 & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)
1451 )));
sewardj7447b5b2004-10-16 11:30:42 +00001452 break;
sewardj291a7e82005-04-27 11:42:44 +00001453 case Iop_64to1:
1454 e2 = IRExpr_Const(IRConst_U1(toBool(
1455 1 == (1 & e->Iex.Unop.arg->Iex.Const.con->Ico.U64)
1456 )));
1457 break;
sewardje6b39932004-11-06 17:01:15 +00001458
sewardj4a0bee02012-06-29 14:44:44 +00001459 case Iop_NotV128:
1460 e2 = IRExpr_Const(IRConst_V128(
1461 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.V128)));
1462 break;
sewardjf057afb2005-02-27 13:35:41 +00001463 case Iop_Not64:
1464 e2 = IRExpr_Const(IRConst_U64(
1465 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U64)));
1466 break;
sewardj883b00b2004-09-11 09:30:24 +00001467 case Iop_Not32:
1468 e2 = IRExpr_Const(IRConst_U32(
1469 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
1470 break;
sewardje6b39932004-11-06 17:01:15 +00001471 case Iop_Not16:
sewardj9d2e7692005-02-07 01:11:31 +00001472 e2 = IRExpr_Const(IRConst_U16(toUShort(
1473 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U16))));
sewardje6b39932004-11-06 17:01:15 +00001474 break;
sewardjd9997882004-11-04 19:42:59 +00001475 case Iop_Not8:
sewardj9d2e7692005-02-07 01:11:31 +00001476 e2 = IRExpr_Const(IRConst_U8(toUChar(
1477 ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U8))));
sewardjd9997882004-11-04 19:42:59 +00001478 break;
sewardje6b39932004-11-06 17:01:15 +00001479
sewardje1d45da2004-11-12 00:13:21 +00001480 case Iop_Not1:
sewardjba999312004-11-15 15:21:17 +00001481 e2 = IRExpr_Const(IRConst_U1(
1482 notBool(e->Iex.Unop.arg->Iex.Const.con->Ico.U1)));
sewardje1d45da2004-11-12 00:13:21 +00001483 break;
1484
sewardj291a7e82005-04-27 11:42:44 +00001485 case Iop_64to8: {
1486 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1487 w64 &= 0xFFULL;
1488 e2 = IRExpr_Const(IRConst_U8( (UChar)w64 ));
1489 break;
1490 }
1491 case Iop_64to16: {
1492 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1493 w64 &= 0xFFFFULL;
sewardje85bc402005-05-06 16:29:26 +00001494 e2 = IRExpr_Const(IRConst_U16( (UShort)w64 ));
sewardj291a7e82005-04-27 11:42:44 +00001495 break;
1496 }
sewardj1d8ce202004-12-13 14:14:16 +00001497 case Iop_64to32: {
1498 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1499 w64 &= 0x00000000FFFFFFFFULL;
1500 e2 = IRExpr_Const(IRConst_U32( (UInt)w64 ));
sewardj37010592004-12-13 10:47:15 +00001501 break;
sewardj1d8ce202004-12-13 14:14:16 +00001502 }
sewardj1d8ce202004-12-13 14:14:16 +00001503 case Iop_64HIto32: {
1504 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1505 w64 >>= 32;
1506 e2 = IRExpr_Const(IRConst_U32( (UInt)w64 ));
1507 break;
1508 }
sewardjb5710b82005-01-27 16:05:09 +00001509 case Iop_32Uto64:
1510 e2 = IRExpr_Const(IRConst_U64(
1511 0xFFFFFFFFULL
1512 & e->Iex.Unop.arg->Iex.Const.con->Ico.U32));
1513 break;
sewardj7f6330d2011-04-05 11:06:02 +00001514 case Iop_16Sto64: {
1515 /* signed */ Long s64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1516 s64 <<= 48;
1517 s64 >>= 48;
1518 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1519 break;
1520 }
sewardj287e9bb2010-07-29 16:12:41 +00001521 case Iop_32Sto64: {
1522 /* signed */ Long s64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1523 s64 <<= 32;
1524 s64 >>= 32;
1525 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1526 break;
1527 }
sewardj7f6330d2011-04-05 11:06:02 +00001528
1529 case Iop_16to8: {
1530 UShort w16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1531 w16 &= 0xFF;
1532 e2 = IRExpr_Const(IRConst_U8( (UChar)w16 ));
1533 break;
1534 }
1535 case Iop_16HIto8: {
1536 UShort w16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
1537 w16 >>= 8;
1538 w16 &= 0xFF;
1539 e2 = IRExpr_Const(IRConst_U8( (UChar)w16 ));
1540 break;
1541 }
1542
sewardj0033ddc2005-04-26 23:34:34 +00001543 case Iop_CmpNEZ8:
1544 e2 = IRExpr_Const(IRConst_U1(toBool(
1545 0 !=
1546 (0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8)
1547 )));
1548 break;
1549 case Iop_CmpNEZ32:
1550 e2 = IRExpr_Const(IRConst_U1(toBool(
1551 0 !=
1552 (0xFFFFFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U32)
1553 )));
1554 break;
1555 case Iop_CmpNEZ64:
1556 e2 = IRExpr_Const(IRConst_U1(toBool(
1557 0ULL != e->Iex.Unop.arg->Iex.Const.con->Ico.U64
1558 )));
1559 break;
1560
sewardjeb17e492007-08-25 23:07:44 +00001561 case Iop_CmpwNEZ32: {
1562 UInt w32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1563 if (w32 == 0)
1564 e2 = IRExpr_Const(IRConst_U32( 0 ));
1565 else
1566 e2 = IRExpr_Const(IRConst_U32( 0xFFFFFFFF ));
1567 break;
1568 }
1569 case Iop_CmpwNEZ64: {
1570 ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1571 if (w64 == 0)
1572 e2 = IRExpr_Const(IRConst_U64( 0 ));
1573 else
1574 e2 = IRExpr_Const(IRConst_U64( 0xFFFFFFFFFFFFFFFFULL ));
1575 break;
1576 }
1577
1578 case Iop_Left32: {
1579 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1580 Int s32 = (Int)(u32 & 0xFFFFFFFF);
1581 s32 = (s32 | (-s32));
1582 e2 = IRExpr_Const( IRConst_U32( (UInt)s32 ));
1583 break;
1584 }
1585
1586 case Iop_Left64: {
1587 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1588 Long s64 = (Long)u64;
1589 s64 = (s64 | (-s64));
1590 e2 = IRExpr_Const( IRConst_U64( (ULong)s64 ));
1591 break;
1592 }
1593
sewardj4cba9f42011-03-07 18:34:34 +00001594 case Iop_Clz32: {
1595 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1596 if (u32 != 0)
1597 e2 = IRExpr_Const(IRConst_U32(fold_Clz32(u32)));
1598 break;
1599 }
1600 case Iop_Clz64: {
1601 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1602 if (u64 != 0ULL)
1603 e2 = IRExpr_Const(IRConst_U64(fold_Clz64(u64)));
1604 break;
1605 }
1606
sewardj4a0bee02012-06-29 14:44:44 +00001607 /* For these vector ones, can't fold all cases, but at least
1608 do the most obvious one. Could do better here using
1609 summarise/desummarise of vector constants, but too
1610 difficult to verify; hence just handle the zero cases. */
1611 case Iop_32UtoV128: {
1612 UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
1613 if (0 == u32) {
1614 e2 = IRExpr_Const(IRConst_V128(0x0000));
1615 } else {
1616 goto unhandled;
1617 }
1618 break;
1619 }
1620 case Iop_V128to64: {
1621 UShort v128 = e->Iex.Unop.arg->Iex.Const.con->Ico.V128;
1622 if (0 == ((v128 >> 0) & 0xFF)) {
1623 e2 = IRExpr_Const(IRConst_U64(0));
1624 } else {
1625 goto unhandled;
1626 }
1627 break;
1628 }
1629 case Iop_V128HIto64: {
1630 UShort v128 = e->Iex.Unop.arg->Iex.Const.con->Ico.V128;
1631 if (0 == ((v128 >> 8) & 0xFF)) {
1632 e2 = IRExpr_Const(IRConst_U64(0));
1633 } else {
1634 goto unhandled;
1635 }
1636 break;
1637 }
1638 case Iop_64UtoV128: {
1639 ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
1640 if (0 == u64) {
1641 e2 = IRExpr_Const(IRConst_V128(0x0000));
1642 } else {
1643 goto unhandled;
1644 }
1645 break;
1646 }
1647
sewardjffccf2b2012-06-29 15:33:09 +00001648 /* Even stupider (although still correct ..) */
1649 case Iop_V256to64_0: case Iop_V256to64_1:
1650 case Iop_V256to64_2: case Iop_V256to64_3: {
1651 UInt v256 = e->Iex.Unop.arg->Iex.Const.con->Ico.V256;
1652 if (v256 == 0x00000000) {
1653 e2 = IRExpr_Const(IRConst_U64(0));
1654 } else {
1655 goto unhandled;
1656 }
1657 break;
1658 }
1659
sewardj84be7372004-08-18 13:59:33 +00001660 default:
1661 goto unhandled;
1662 }
florian708417d2012-02-15 00:43:36 +00001663 }
1664 break;
sewardj84be7372004-08-18 13:59:33 +00001665
florian708417d2012-02-15 00:43:36 +00001666 case Iex_Binop:
1667 /* BINARY ops */
sewardj84be7372004-08-18 13:59:33 +00001668 if (e->Iex.Binop.arg1->tag == Iex_Const
1669 && e->Iex.Binop.arg2->tag == Iex_Const) {
1670 /* cases where both args are consts */
1671 switch (e->Iex.Binop.op) {
sewardje6b39932004-11-06 17:01:15 +00001672
sewardj855dc722005-02-17 09:26:05 +00001673 /* -- Or -- */
sewardjd9997882004-11-04 19:42:59 +00001674 case Iop_Or8:
sewardj9d2e7692005-02-07 01:11:31 +00001675 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardjd9997882004-11-04 19:42:59 +00001676 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001677 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardjd9997882004-11-04 19:42:59 +00001678 break;
sewardje6b39932004-11-06 17:01:15 +00001679 case Iop_Or16:
sewardj9d2e7692005-02-07 01:11:31 +00001680 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardje6b39932004-11-06 17:01:15 +00001681 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
sewardj9d2e7692005-02-07 01:11:31 +00001682 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
sewardje6b39932004-11-06 17:01:15 +00001683 break;
1684 case Iop_Or32:
1685 e2 = IRExpr_Const(IRConst_U32(
1686 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1687 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1688 break;
sewardjf057afb2005-02-27 13:35:41 +00001689 case Iop_Or64:
1690 e2 = IRExpr_Const(IRConst_U64(
1691 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1692 | e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1693 break;
sewardj4a0bee02012-06-29 14:44:44 +00001694 case Iop_OrV128:
1695 e2 = IRExpr_Const(IRConst_V128(
1696 (e->Iex.Binop.arg1->Iex.Const.con->Ico.V128
1697 | e->Iex.Binop.arg2->Iex.Const.con->Ico.V128)));
1698 break;
sewardje6b39932004-11-06 17:01:15 +00001699
sewardj855dc722005-02-17 09:26:05 +00001700 /* -- Xor -- */
sewardj883b00b2004-09-11 09:30:24 +00001701 case Iop_Xor8:
sewardj9d2e7692005-02-07 01:11:31 +00001702 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj883b00b2004-09-11 09:30:24 +00001703 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001704 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj883b00b2004-09-11 09:30:24 +00001705 break;
sewardj82c9f2f2005-03-02 16:05:13 +00001706 case Iop_Xor16:
sewardjc7c098f2005-03-21 01:06:20 +00001707 e2 = IRExpr_Const(IRConst_U16(toUShort(
sewardj82c9f2f2005-03-02 16:05:13 +00001708 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
sewardjc7c098f2005-03-21 01:06:20 +00001709 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
sewardj82c9f2f2005-03-02 16:05:13 +00001710 break;
sewardj855dc722005-02-17 09:26:05 +00001711 case Iop_Xor32:
1712 e2 = IRExpr_Const(IRConst_U32(
1713 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1714 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1715 break;
sewardjf057afb2005-02-27 13:35:41 +00001716 case Iop_Xor64:
1717 e2 = IRExpr_Const(IRConst_U64(
1718 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1719 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1720 break;
sewardj4a0bee02012-06-29 14:44:44 +00001721 case Iop_XorV128:
1722 e2 = IRExpr_Const(IRConst_V128(
1723 (e->Iex.Binop.arg1->Iex.Const.con->Ico.V128
1724 ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.V128)));
1725 break;
sewardj855dc722005-02-17 09:26:05 +00001726
1727 /* -- And -- */
sewardj84be7372004-08-18 13:59:33 +00001728 case Iop_And8:
sewardj9d2e7692005-02-07 01:11:31 +00001729 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj84be7372004-08-18 13:59:33 +00001730 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001731 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj84be7372004-08-18 13:59:33 +00001732 break;
sewardj7f6330d2011-04-05 11:06:02 +00001733 case Iop_And16:
1734 e2 = IRExpr_Const(IRConst_U16(toUShort(
1735 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U16
1736 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U16))));
1737 break;
sewardj855dc722005-02-17 09:26:05 +00001738 case Iop_And32:
1739 e2 = IRExpr_Const(IRConst_U32(
1740 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1741 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1742 break;
1743 case Iop_And64:
1744 e2 = IRExpr_Const(IRConst_U64(
1745 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1746 & e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1747 break;
sewardj4a0bee02012-06-29 14:44:44 +00001748 case Iop_AndV128:
1749 e2 = IRExpr_Const(IRConst_V128(
1750 (e->Iex.Binop.arg1->Iex.Const.con->Ico.V128
1751 & e->Iex.Binop.arg2->Iex.Const.con->Ico.V128)));
1752 break;
sewardj855dc722005-02-17 09:26:05 +00001753
1754 /* -- Add -- */
sewardj4345f7a2004-09-22 19:49:27 +00001755 case Iop_Add8:
sewardj9d2e7692005-02-07 01:11:31 +00001756 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj4345f7a2004-09-22 19:49:27 +00001757 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
sewardj9d2e7692005-02-07 01:11:31 +00001758 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U8))));
sewardj4345f7a2004-09-22 19:49:27 +00001759 break;
sewardj855dc722005-02-17 09:26:05 +00001760 case Iop_Add32:
1761 e2 = IRExpr_Const(IRConst_U32(
1762 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1763 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1764 break;
1765 case Iop_Add64:
1766 e2 = IRExpr_Const(IRConst_U64(
1767 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1768 + e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1769 break;
1770
1771 /* -- Sub -- */
sewardj84be7372004-08-18 13:59:33 +00001772 case Iop_Sub8:
sewardj9d2e7692005-02-07 01:11:31 +00001773 e2 = IRExpr_Const(IRConst_U8(toUChar(
sewardj84be7372004-08-18 13:59:33 +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))));
sewardj84be7372004-08-18 13:59:33 +00001776 break;
sewardjd7217032004-08-19 10:49:10 +00001777 case Iop_Sub32:
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;
sewardj70a8ddf2005-02-13 02:24:26 +00001782 case Iop_Sub64:
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;
sewardjc2bcb6f2005-02-07 00:17:12 +00001787
sewardj478646f2008-05-01 20:13:04 +00001788 /* -- Max32U -- */
1789 case Iop_Max32U: {
1790 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1791 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1792 UInt res = u32a > u32b ? u32a : u32b;
1793 e2 = IRExpr_Const(IRConst_U32(res));
1794 break;
1795 }
1796
sewardj855dc722005-02-17 09:26:05 +00001797 /* -- Mul -- */
sewardjb9c5cf62004-08-24 15:10:38 +00001798 case Iop_Mul32:
1799 e2 = IRExpr_Const(IRConst_U32(
1800 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1801 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
1802 break;
sewardja34c0712005-03-30 23:19:46 +00001803 case Iop_Mul64:
1804 e2 = IRExpr_Const(IRConst_U64(
1805 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1806 * e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)));
1807 break;
1808
sewardjea6bccb2005-03-01 10:19:23 +00001809 case Iop_MullS32: {
1810 /* very paranoid */
1811 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1812 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1813 Int s32a = (Int)u32a;
1814 Int s32b = (Int)u32b;
1815 Long s64a = (Long)s32a;
1816 Long s64b = (Long)s32b;
1817 Long sres = s64a * s64b;
1818 ULong ures = (ULong)sres;
1819 e2 = IRExpr_Const(IRConst_U64(ures));
1820 break;
1821 }
sewardjb095fba2005-02-13 14:13:04 +00001822
sewardj855dc722005-02-17 09:26:05 +00001823 /* -- Shl -- */
sewardjd7217032004-08-19 10:49:10 +00001824 case Iop_Shl32:
sewardj61348472004-08-20 01:01:04 +00001825 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1826 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj29632392004-08-22 02:38:11 +00001827 if (shift >= 0 && shift <= 31)
sewardj278c44c2004-08-20 00:28:13 +00001828 e2 = IRExpr_Const(IRConst_U32(
1829 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
1830 << shift)));
sewardjd7217032004-08-19 10:49:10 +00001831 break;
sewardjb095fba2005-02-13 14:13:04 +00001832 case Iop_Shl64:
1833 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1834 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1835 if (shift >= 0 && shift <= 63)
1836 e2 = IRExpr_Const(IRConst_U64(
1837 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1838 << shift)));
1839 break;
1840
sewardj855dc722005-02-17 09:26:05 +00001841 /* -- Sar -- */
sewardj278c44c2004-08-20 00:28:13 +00001842 case Iop_Sar32: {
1843 /* paranoid ... */
1844 /*signed*/ Int s32;
sewardj61348472004-08-20 01:01:04 +00001845 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj278c44c2004-08-20 00:28:13 +00001846 s32 = (Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +00001847 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
sewardj278c44c2004-08-20 00:28:13 +00001848 if (shift >= 0 && shift <= 31) {
1849 s32 >>=/*signed*/ shift;
1850 e2 = IRExpr_Const(IRConst_U32((UInt)s32));
1851 }
1852 break;
1853 }
sewardj855dc722005-02-17 09:26:05 +00001854 case Iop_Sar64: {
1855 /* paranoid ... */
1856 /*signed*/ Long s64;
1857 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1858 s64 = (Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64);
1859 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1860 if (shift >= 0 && shift <= 63) {
1861 s64 >>=/*signed*/ shift;
1862 e2 = IRExpr_Const(IRConst_U64((ULong)s64));
1863 }
1864 break;
1865 }
1866
1867 /* -- Shr -- */
sewardj61348472004-08-20 01:01:04 +00001868 case Iop_Shr32: {
1869 /* paranoid ... */
sewardj4add7142005-02-21 08:20:22 +00001870 /*unsigned*/ UInt u32;
sewardj61348472004-08-20 01:01:04 +00001871 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj4add7142005-02-21 08:20:22 +00001872 u32 = (UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32);
sewardj61348472004-08-20 01:01:04 +00001873 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1874 if (shift >= 0 && shift <= 31) {
sewardj4add7142005-02-21 08:20:22 +00001875 u32 >>=/*unsigned*/ shift;
1876 e2 = IRExpr_Const(IRConst_U32(u32));
1877 }
1878 break;
1879 }
1880 case Iop_Shr64: {
1881 /* paranoid ... */
1882 /*unsigned*/ ULong u64;
1883 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
1884 u64 = (ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64);
1885 shift = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8);
1886 if (shift >= 0 && shift <= 63) {
1887 u64 >>=/*unsigned*/ shift;
1888 e2 = IRExpr_Const(IRConst_U64(u64));
sewardj61348472004-08-20 01:01:04 +00001889 }
1890 break;
1891 }
sewardj855dc722005-02-17 09:26:05 +00001892
1893 /* -- CmpEQ -- */
sewardjb8e75862004-08-19 17:58:45 +00001894 case Iop_CmpEQ32:
sewardj9d2e7692005-02-07 01:11:31 +00001895 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardjb8e75862004-08-19 17:58:45 +00001896 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
sewardj9d2e7692005-02-07 01:11:31 +00001897 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))));
sewardjb8e75862004-08-19 17:58:45 +00001898 break;
sewardj855dc722005-02-17 09:26:05 +00001899 case Iop_CmpEQ64:
1900 e2 = IRExpr_Const(IRConst_U1(toBool(
1901 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
1902 == e->Iex.Binop.arg2->Iex.Const.con->Ico.U64))));
1903 break;
1904
1905 /* -- CmpNE -- */
1906 case Iop_CmpNE8:
sewardje13074c2012-11-08 10:57:08 +00001907 case Iop_CasCmpNE8:
1908 case Iop_ExpCmpNE8:
sewardj855dc722005-02-17 09:26:05 +00001909 e2 = IRExpr_Const(IRConst_U1(toBool(
1910 ((0xFF & e->Iex.Binop.arg1->Iex.Const.con->Ico.U8)
1911 != (0xFF & e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)))));
1912 break;
sewardjae27ab62004-10-15 21:21:46 +00001913 case Iop_CmpNE32:
sewardje13074c2012-11-08 10:57:08 +00001914 case Iop_CasCmpNE32:
1915 case Iop_ExpCmpNE32:
sewardj9d2e7692005-02-07 01:11:31 +00001916 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardjae27ab62004-10-15 21:21:46 +00001917 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
sewardj9d2e7692005-02-07 01:11:31 +00001918 != e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))));
sewardjae27ab62004-10-15 21:21:46 +00001919 break;
sewardje6b39932004-11-06 17:01:15 +00001920 case Iop_CmpNE64:
sewardje13074c2012-11-08 10:57:08 +00001921 case Iop_CasCmpNE64:
1922 case Iop_ExpCmpNE64:
sewardj9d2e7692005-02-07 01:11:31 +00001923 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardje6b39932004-11-06 17:01:15 +00001924 (e->Iex.Binop.arg1->Iex.Const.con->Ico.U64
sewardj9d2e7692005-02-07 01:11:31 +00001925 != e->Iex.Binop.arg2->Iex.Const.con->Ico.U64))));
sewardje6b39932004-11-06 17:01:15 +00001926 break;
1927
sewardj855dc722005-02-17 09:26:05 +00001928 /* -- CmpLEU -- */
sewardj7447b5b2004-10-16 11:30:42 +00001929 case Iop_CmpLE32U:
sewardj9d2e7692005-02-07 01:11:31 +00001930 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj7447b5b2004-10-16 11:30:42 +00001931 ((UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001932 <= (UInt)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj7447b5b2004-10-16 11:30:42 +00001933 break;
sewardj7f6330d2011-04-05 11:06:02 +00001934 case Iop_CmpLE64U:
1935 e2 = IRExpr_Const(IRConst_U1(toBool(
1936 ((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1937 <= (ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1938 break;
sewardj855dc722005-02-17 09:26:05 +00001939
1940 /* -- CmpLES -- */
sewardj088e4f72004-10-19 01:25:02 +00001941 case Iop_CmpLE32S:
sewardj9d2e7692005-02-07 01:11:31 +00001942 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj088e4f72004-10-19 01:25:02 +00001943 ((Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001944 <= (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj088e4f72004-10-19 01:25:02 +00001945 break;
sewardj7f6330d2011-04-05 11:06:02 +00001946 case Iop_CmpLE64S:
1947 e2 = IRExpr_Const(IRConst_U1(toBool(
1948 ((Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1949 <= (Long)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1950 break;
sewardje1d45da2004-11-12 00:13:21 +00001951
sewardj855dc722005-02-17 09:26:05 +00001952 /* -- CmpLTS -- */
sewardj9bdd2652004-10-19 12:56:33 +00001953 case Iop_CmpLT32S:
sewardj9d2e7692005-02-07 01:11:31 +00001954 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardj9bdd2652004-10-19 12:56:33 +00001955 ((Int)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001956 < (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardj9bdd2652004-10-19 12:56:33 +00001957 break;
sewardj7f6330d2011-04-05 11:06:02 +00001958 case Iop_CmpLT64S:
1959 e2 = IRExpr_Const(IRConst_U1(toBool(
1960 ((Long)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1961 < (Long)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1962 break;
sewardj855dc722005-02-17 09:26:05 +00001963
1964 /* -- CmpLTU -- */
sewardje1d45da2004-11-12 00:13:21 +00001965 case Iop_CmpLT32U:
sewardj9d2e7692005-02-07 01:11:31 +00001966 e2 = IRExpr_Const(IRConst_U1(toBool(
sewardje1d45da2004-11-12 00:13:21 +00001967 ((UInt)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U32)
sewardj9d2e7692005-02-07 01:11:31 +00001968 < (UInt)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)))));
sewardje1d45da2004-11-12 00:13:21 +00001969 break;
sewardj7f6330d2011-04-05 11:06:02 +00001970 case Iop_CmpLT64U:
1971 e2 = IRExpr_Const(IRConst_U1(toBool(
1972 ((ULong)(e->Iex.Binop.arg1->Iex.Const.con->Ico.U64)
1973 < (ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)))));
1974 break;
sewardj7447b5b2004-10-16 11:30:42 +00001975
sewardjb51f0f42005-07-18 11:38:02 +00001976 /* -- CmpORD -- */
1977 case Iop_CmpORD32S: {
1978 /* very paranoid */
1979 UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
1980 UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1981 Int s32a = (Int)u32a;
1982 Int s32b = (Int)u32b;
1983 Int r = 0x2; /* EQ */
1984 if (s32a < s32b) {
1985 r = 0x8; /* LT */
1986 }
1987 else if (s32a > s32b) {
1988 r = 0x4; /* GT */
1989 }
1990 e2 = IRExpr_Const(IRConst_U32(r));
1991 break;
1992 }
1993
sewardj855dc722005-02-17 09:26:05 +00001994 /* -- nHLto2n -- */
sewardj088bcb42004-08-19 17:16:52 +00001995 case Iop_32HLto64:
1996 e2 = IRExpr_Const(IRConst_U64(
sewardj4a0bee02012-06-29 14:44:44 +00001997 (((ULong)(e->Iex.Binop.arg1
1998 ->Iex.Const.con->Ico.U32)) << 32)
sewardj088bcb42004-08-19 17:16:52 +00001999 | ((ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32))
2000 ));
2001 break;
sewardj3bc8a592005-05-02 10:47:22 +00002002 case Iop_64HLto128:
2003 /* We can't fold this, because there is no way to
2004 express he result in IR, but at least pretend to
2005 handle it, so as to stop getting blasted with
2006 no-rule-for-this-primop messages. */
2007 break;
sewardj4a0bee02012-06-29 14:44:44 +00002008 /* For this vector one, can't fold all cases, but at
2009 least do the most obvious one. Could do better here
2010 using summarise/desummarise of vector constants, but
2011 too difficult to verify; hence just handle the zero
2012 cases. */
2013 case Iop_64HLtoV128: {
2014 ULong argHi = e->Iex.Binop.arg1->Iex.Const.con->Ico.U64;
2015 ULong argLo = e->Iex.Binop.arg2->Iex.Const.con->Ico.U64;
2016 if (0 == argHi && 0 == argLo) {
2017 e2 = IRExpr_Const(IRConst_V128(0));
2018 } else {
2019 goto unhandled;
2020 }
2021 break;
2022 }
sewardj9571dc02014-01-26 18:34:23 +00002023 /* Same reasoning for the 256-bit version. */
2024 case Iop_V128HLtoV256: {
2025 IRExpr* argHi = e->Iex.Binop.arg1;
2026 IRExpr* argLo = e->Iex.Binop.arg2;
2027 if (isZeroV128(argHi) && isZeroV128(argLo)) {
2028 e2 = IRExpr_Const(IRConst_V256(0));
2029 } else {
2030 goto unhandled;
2031 }
2032 break;
2033 }
sewardj4a0bee02012-06-29 14:44:44 +00002034
2035 /* -- V128 stuff -- */
2036 case Iop_InterleaveLO8x16: {
2037 /* This turns up a lot in Memcheck instrumentation of
2038 Icc generated code. I don't know why. */
2039 UShort arg1 = e->Iex.Binop.arg1->Iex.Const.con->Ico.V128;
2040 UShort arg2 = e->Iex.Binop.arg2->Iex.Const.con->Ico.V128;
2041 if (0 == arg1 && 0 == arg2) {
2042 e2 = IRExpr_Const(IRConst_V128(0));
2043 } else {
2044 goto unhandled;
2045 }
2046 break;
2047 }
sewardj855dc722005-02-17 09:26:05 +00002048
sewardj607dd4f2004-09-08 18:20:19 +00002049 default:
2050 goto unhandled;
sewardjd7217032004-08-19 10:49:10 +00002051 }
sewardjf6729012004-08-25 12:45:13 +00002052
sewardj84be7372004-08-18 13:59:33 +00002053 } else {
sewardjf6729012004-08-25 12:45:13 +00002054
sewardj84be7372004-08-18 13:59:33 +00002055 /* other cases (identities, etc) */
sewardj64d776c2010-10-01 14:06:22 +00002056 switch (e->Iex.Binop.op) {
florianf6402ab2012-01-29 02:19:43 +00002057
2058 case Iop_Shl32:
2059 case Iop_Shl64:
2060 case Iop_Shr64:
2061 /* Shl32/Shl64/Shr64(x,0) ==> x */
2062 if (isZeroU(e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00002063 e2 = e->Iex.Binop.arg1;
florianf6402ab2012-01-29 02:19:43 +00002064 break;
2065 }
2066 /* Shl32/Shl64/Shr64(0,x) ==> 0 */
2067 if (isZeroU(e->Iex.Binop.arg1)) {
2068 e2 = e->Iex.Binop.arg1;
2069 break;
2070 }
sewardj64d776c2010-10-01 14:06:22 +00002071 break;
sewardjf6729012004-08-25 12:45:13 +00002072
florianf6402ab2012-01-29 02:19:43 +00002073 case Iop_Shr32:
2074 /* Shr32(x,0) ==> x */
2075 if (isZeroU(e->Iex.Binop.arg2)) {
2076 e2 = e->Iex.Binop.arg1;
2077 break;
2078 }
2079 break;
2080
2081 case Iop_Or8:
2082 case Iop_Or16:
2083 case Iop_Or32:
2084 case Iop_Or64:
2085 case Iop_Max32U:
sewardjcf4be4a2012-03-26 09:44:39 +00002086 /* Or8/Or16/Or32/Or64/Max32U(x,0) ==> x */
florianf6402ab2012-01-29 02:19:43 +00002087 if (isZeroU(e->Iex.Binop.arg2)) {
2088 e2 = e->Iex.Binop.arg1;
2089 break;
2090 }
sewardjcf4be4a2012-03-26 09:44:39 +00002091 /* Or8/Or16/Or32/Or64/Max32U(0,x) ==> x */
florianf6402ab2012-01-29 02:19:43 +00002092 if (isZeroU(e->Iex.Binop.arg1)) {
2093 e2 = e->Iex.Binop.arg2;
2094 break;
2095 }
sewardjcf4be4a2012-03-26 09:44:39 +00002096 /* Or8/Or16/Or32/Or64/Max32U(x,1---1b) ==> 1---1b */
2097 /* Or8/Or16/Or32/Or64/Max32U(1---1b,x) ==> 1---1b */
2098 if (isOnesU(e->Iex.Binop.arg1) || isOnesU(e->Iex.Binop.arg2)) {
2099 e2 = mkOnesOfPrimopResultType(e->Iex.Binop.op);
2100 break;
2101 }
2102 /* Or8/Or16/Or32/Or64/Max32U(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002103 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002104 e2 = e->Iex.Binop.arg1;
2105 break;
2106 }
2107 break;
2108
2109 case Iop_Add8:
2110 /* Add8(t,t) ==> t << 1.
2111 Memcheck doesn't understand that
2112 x+x produces a defined least significant bit, and it seems
2113 simplest just to get rid of the problem by rewriting it
2114 out, since the opportunity to do so exists. */
floriancdb5fee2012-02-13 00:06:29 +00002115 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002116 e2 = IRExpr_Binop(Iop_Shl8, e->Iex.Binop.arg1,
2117 IRExpr_Const(IRConst_U8(1)));
2118 break;
2119 }
2120 break;
2121
2122 /* NB no Add16(t,t) case yet as no known test case exists */
2123
2124 case Iop_Add32:
2125 case Iop_Add64:
2126 /* Add32/Add64(x,0) ==> x */
2127 if (isZeroU(e->Iex.Binop.arg2)) {
2128 e2 = e->Iex.Binop.arg1;
2129 break;
2130 }
2131 /* Add32/Add64(0,x) ==> x */
2132 if (isZeroU(e->Iex.Binop.arg1)) {
2133 e2 = e->Iex.Binop.arg2;
2134 break;
2135 }
2136 /* Add32/Add64(t,t) ==> t << 1. Same rationale as for Add8. */
floriancdb5fee2012-02-13 00:06:29 +00002137 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj6399f812012-06-29 15:36:44 +00002138 e2 = IRExpr_Binop(
2139 e->Iex.Binop.op == Iop_Add32 ? Iop_Shl32 : Iop_Shl64,
2140 e->Iex.Binop.arg1, IRExpr_Const(IRConst_U8(1)));
florianf6402ab2012-01-29 02:19:43 +00002141 break;
2142 }
2143 break;
2144
sewardj1beb4332012-12-19 15:28:43 +00002145 case Iop_Sub32:
florianf6402ab2012-01-29 02:19:43 +00002146 case Iop_Sub64:
sewardj1beb4332012-12-19 15:28:43 +00002147 /* Sub32/Sub64(x,0) ==> x */
2148 if (isZeroU(e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002149 e2 = e->Iex.Binop.arg1;
2150 break;
2151 }
sewardj1beb4332012-12-19 15:28:43 +00002152 /* Sub32/Sub64(t,t) ==> 0, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002153 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00002154 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
florianf6402ab2012-01-29 02:19:43 +00002155 break;
2156 }
sewardj64d776c2010-10-01 14:06:22 +00002157 break;
sewardj36a911a2014-04-03 13:48:21 +00002158 case Iop_Sub8x16:
2159 /* Sub8x16(x,0) ==> x */
2160 if (isZeroV128(e->Iex.Binop.arg2)) {
2161 e2 = e->Iex.Binop.arg1;
2162 break;
2163 }
2164 break;
sewardj64d776c2010-10-01 14:06:22 +00002165
florian2782d212014-07-18 21:23:46 +00002166 case Iop_And8:
2167 case Iop_And16:
florianf6402ab2012-01-29 02:19:43 +00002168 case Iop_And32:
florian2782d212014-07-18 21:23:46 +00002169 case Iop_And64:
2170 /* And8/And16/And32/And64(x,1---1b) ==> x */
florian55ce7b72013-09-01 14:22:05 +00002171 if (isOnesU(e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002172 e2 = e->Iex.Binop.arg1;
2173 break;
2174 }
florian2782d212014-07-18 21:23:46 +00002175 /* And8/And16/And32/And64(1---1b,x) ==> x */
2176 if (isOnesU(e->Iex.Binop.arg1)) {
2177 e2 = e->Iex.Binop.arg2;
2178 break;
2179 }
2180 /* And8/And16/And32/And64(x,0) ==> 0 */
florian55ce7b72013-09-01 14:22:05 +00002181 if (isZeroU(e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002182 e2 = e->Iex.Binop.arg2;
2183 break;
2184 }
florian2782d212014-07-18 21:23:46 +00002185 /* And8/And16/And32/And64(0,x) ==> 0 */
florian55ce7b72013-09-01 14:22:05 +00002186 if (isZeroU(e->Iex.Binop.arg1)) {
florianf6402ab2012-01-29 02:19:43 +00002187 e2 = e->Iex.Binop.arg1;
2188 break;
2189 }
florian2782d212014-07-18 21:23:46 +00002190 /* And8/And16/And32/And64(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002191 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002192 e2 = e->Iex.Binop.arg1;
2193 break;
2194 }
2195 break;
2196
sewardj4a0bee02012-06-29 14:44:44 +00002197 case Iop_AndV128:
2198 case Iop_AndV256:
florian55ce7b72013-09-01 14:22:05 +00002199 /* And8/And16/AndV128/AndV256(t,t)
sewardj4a0bee02012-06-29 14:44:44 +00002200 ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002201 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002202 e2 = e->Iex.Binop.arg1;
2203 break;
2204 }
sewardj36a911a2014-04-03 13:48:21 +00002205 /* Deal with either arg zero. Could handle other And
2206 cases here too. */
florian1b7c4712014-07-16 20:17:49 +00002207 if (e->Iex.Binop.op == Iop_AndV256
2208 && (isZeroV256(e->Iex.Binop.arg1)
2209 || isZeroV256(e->Iex.Binop.arg2))) {
sewardjbbcf1882014-01-12 12:49:10 +00002210 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
2211 break;
sewardj36a911a2014-04-03 13:48:21 +00002212 } else if (e->Iex.Binop.op == Iop_AndV128
2213 && (isZeroV128(e->Iex.Binop.arg1)
2214 || isZeroV128(e->Iex.Binop.arg2))) {
2215 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
2216 break;
sewardjbbcf1882014-01-12 12:49:10 +00002217 }
florianf6402ab2012-01-29 02:19:43 +00002218 break;
2219
2220 case Iop_OrV128:
sewardj4a0bee02012-06-29 14:44:44 +00002221 case Iop_OrV256:
2222 /* V128/V256(t,t) ==> t, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002223 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002224 e2 = e->Iex.Binop.arg1;
2225 break;
2226 }
sewardj9571dc02014-01-26 18:34:23 +00002227 /* OrV128(t,0) ==> t */
2228 if (e->Iex.Binop.op == Iop_OrV128) {
2229 if (isZeroV128(e->Iex.Binop.arg2)) {
2230 e2 = e->Iex.Binop.arg1;
2231 break;
2232 }
2233 if (isZeroV128(e->Iex.Binop.arg1)) {
2234 e2 = e->Iex.Binop.arg2;
2235 break;
2236 }
2237 }
2238 /* OrV256(t,0) ==> t */
2239 if (e->Iex.Binop.op == Iop_OrV256) {
2240 if (isZeroV256(e->Iex.Binop.arg2)) {
2241 e2 = e->Iex.Binop.arg1;
2242 break;
2243 }
2244 //Disabled because there's no known test case right now.
2245 //if (isZeroV256(e->Iex.Binop.arg1)) {
2246 // e2 = e->Iex.Binop.arg2;
2247 // break;
2248 //}
2249 }
florianf6402ab2012-01-29 02:19:43 +00002250 break;
2251
2252 case Iop_Xor8:
2253 case Iop_Xor16:
2254 case Iop_Xor32:
2255 case Iop_Xor64:
2256 case Iop_XorV128:
2257 /* Xor8/16/32/64/V128(t,t) ==> 0, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002258 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002259 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
2260 break;
2261 }
sewardjb01ff402014-08-04 08:09:23 +00002262 /* XorV128(t,0) ==> t */
2263 if (e->Iex.Binop.op == Iop_XorV128) {
2264 if (isZeroV128(e->Iex.Binop.arg2)) {
2265 e2 = e->Iex.Binop.arg1;
2266 break;
2267 }
2268 //Disabled because there's no known test case right now.
2269 //if (isZeroV128(e->Iex.Binop.arg1)) {
2270 // e2 = e->Iex.Binop.arg2;
2271 // break;
2272 //}
2273 }
florianf6402ab2012-01-29 02:19:43 +00002274 break;
2275
sewardja7e96382012-06-29 16:26:17 +00002276 case Iop_CmpNE32:
sewardj1beb4332012-12-19 15:28:43 +00002277 /* CmpNE32(t,t) ==> 0, for some IRTemp t */
floriancdb5fee2012-02-13 00:06:29 +00002278 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
florianf6402ab2012-01-29 02:19:43 +00002279 e2 = mkZeroOfPrimopResultType(e->Iex.Binop.op);
2280 break;
2281 }
sewardj009230b2013-01-26 11:47:55 +00002282 /* CmpNE32(1Uto32(b), 0) ==> b */
2283 if (isZeroU32(e->Iex.Binop.arg2)) {
2284 IRExpr* a1 = chase(env, e->Iex.Binop.arg1);
2285 if (a1 && a1->tag == Iex_Unop
2286 && a1->Iex.Unop.op == Iop_1Uto32) {
2287 e2 = a1->Iex.Unop.arg;
2288 break;
2289 }
2290 }
florianf6402ab2012-01-29 02:19:43 +00002291 break;
2292
sewardja7e96382012-06-29 16:26:17 +00002293 case Iop_CmpEQ32:
sewardj64d776c2010-10-01 14:06:22 +00002294 case Iop_CmpEQ64:
2295 case Iop_CmpEQ8x8:
2296 case Iop_CmpEQ8x16:
sewardj899d1832012-07-10 21:41:01 +00002297 case Iop_CmpEQ16x8:
sewardjffccf2b2012-06-29 15:33:09 +00002298 case Iop_CmpEQ32x4:
floriancdb5fee2012-02-13 00:06:29 +00002299 if (sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj64d776c2010-10-01 14:06:22 +00002300 e2 = mkOnesOfPrimopResultType(e->Iex.Binop.op);
florianf6402ab2012-01-29 02:19:43 +00002301 break;
2302 }
sewardj64d776c2010-10-01 14:06:22 +00002303 break;
florianf6402ab2012-01-29 02:19:43 +00002304
sewardj64d776c2010-10-01 14:06:22 +00002305 default:
2306 break;
sewardj0033ddc2005-04-26 23:34:34 +00002307 }
sewardj84be7372004-08-18 13:59:33 +00002308 }
florian708417d2012-02-15 00:43:36 +00002309 break;
sewardj84be7372004-08-18 13:59:33 +00002310
florian99dd03e2013-01-29 03:56:06 +00002311 case Iex_ITE:
2312 /* ITE */
sewardj6c299f32009-12-31 18:00:12 +00002313 /* is the discriminant is a constant? */
florian99dd03e2013-01-29 03:56:06 +00002314 if (e->Iex.ITE.cond->tag == Iex_Const) {
sewardj6c299f32009-12-31 18:00:12 +00002315 /* assured us by the IR type rules */
florian99dd03e2013-01-29 03:56:06 +00002316 vassert(e->Iex.ITE.cond->Iex.Const.con->tag == Ico_U1);
2317 e2 = e->Iex.ITE.cond->Iex.Const.con->Ico.U1
2318 ? e->Iex.ITE.iftrue : e->Iex.ITE.iffalse;
sewardj6c299f32009-12-31 18:00:12 +00002319 }
2320 else
2321 /* are the arms identical? (pretty weedy test) */
florian99dd03e2013-01-29 03:56:06 +00002322 if (sameIRExprs(env, e->Iex.ITE.iftrue,
2323 e->Iex.ITE.iffalse)) {
2324 e2 = e->Iex.ITE.iffalse;
sewardj6c299f32009-12-31 18:00:12 +00002325 }
florian708417d2012-02-15 00:43:36 +00002326 break;
2327
2328 default:
2329 /* not considered */
2330 break;
sewardj84be7372004-08-18 13:59:33 +00002331 }
2332
sewardja7e96382012-06-29 16:26:17 +00002333 /* Show cases where we've found but not folded 'op(t,t)'. Be
2334 careful not to call sameIRExprs with values of different types,
2335 though, else it will assert (and so it should!). We can't
2336 conveniently call typeOfIRExpr on the two args without a whole
2337 bunch of extra plumbing to pass in a type env, so just use a
2338 hacky test to check the arguments are not anything that might
2339 sameIRExprs to assert. This is only OK because this kludge is
2340 only used for debug printing, not for "real" operation. For
2341 "real" operation (ie, all other calls to sameIRExprs), it is
2342 essential that the to args have the same type.
2343
2344 The "right" solution is to plumb the containing block's
2345 IRTypeEnv through to here and use typeOfIRExpr to be sure. But
2346 that's a bunch of extra parameter passing which will just slow
2347 down the normal case, for no purpose. */
2348 if (vex_control.iropt_verbosity > 0
2349 && e == e2
2350 && e->tag == Iex_Binop
2351 && !debug_only_hack_sameIRExprs_might_assert(e->Iex.Binop.arg1,
2352 e->Iex.Binop.arg2)
floriancdb5fee2012-02-13 00:06:29 +00002353 && sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
sewardj4a0bee02012-06-29 14:44:44 +00002354 vex_printf("vex iropt: fold_Expr: no ident rule for: ");
2355 ppIRExpr(e);
2356 vex_printf("\n");
sewardj64d776c2010-10-01 14:06:22 +00002357 }
2358
2359 /* Show the overall results of folding. */
sewardj088bcb42004-08-19 17:16:52 +00002360 if (DEBUG_IROPT && e2 != e) {
2361 vex_printf("FOLD: ");
sewardj84be7372004-08-18 13:59:33 +00002362 ppIRExpr(e); vex_printf(" -> ");
2363 ppIRExpr(e2); vex_printf("\n");
2364 }
2365
2366 return e2;
2367
2368 unhandled:
sewardj883b00b2004-09-11 09:30:24 +00002369# if 0
sewardj84be7372004-08-18 13:59:33 +00002370 vex_printf("\n\n");
2371 ppIRExpr(e);
2372 vpanic("fold_Expr: no rule for the above");
sewardj883b00b2004-09-11 09:30:24 +00002373# else
sewardj328b54b2005-06-13 16:30:18 +00002374 if (vex_control.iropt_verbosity > 0) {
sewardj4a0bee02012-06-29 14:44:44 +00002375 vex_printf("vex iropt: fold_Expr: no const rule for: ");
sewardj328b54b2005-06-13 16:30:18 +00002376 ppIRExpr(e);
2377 vex_printf("\n");
2378 }
sewardj883b00b2004-09-11 09:30:24 +00002379 return e2;
2380# endif
sewardj84be7372004-08-18 13:59:33 +00002381}
2382
2383
sewardj84be7372004-08-18 13:59:33 +00002384/* Apply the subst to a simple 1-level expression -- guaranteed to be
2385 1-level due to previous flattening pass. */
2386
sewardj62617ef2004-10-13 23:29:22 +00002387static IRExpr* subst_Expr ( IRExpr** env, IRExpr* ex )
sewardj84be7372004-08-18 13:59:33 +00002388{
sewardj62617ef2004-10-13 23:29:22 +00002389 switch (ex->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +00002390 case Iex_RdTmp:
2391 if (env[(Int)ex->Iex.RdTmp.tmp] != NULL) {
floriancdb5fee2012-02-13 00:06:29 +00002392 IRExpr *rhs = env[(Int)ex->Iex.RdTmp.tmp];
2393 if (rhs->tag == Iex_RdTmp)
2394 return rhs;
2395 if (rhs->tag == Iex_Const
2396 && rhs->Iex.Const.con->tag != Ico_F64i)
2397 return rhs;
sewardj62617ef2004-10-13 23:29:22 +00002398 }
floriancdb5fee2012-02-13 00:06:29 +00002399 /* not bound in env */
2400 return ex;
sewardj62617ef2004-10-13 23:29:22 +00002401
2402 case Iex_Const:
2403 case Iex_Get:
sewardj84be7372004-08-18 13:59:33 +00002404 return ex;
sewardj62617ef2004-10-13 23:29:22 +00002405
2406 case Iex_GetI:
sewardj496a58d2005-03-20 18:44:44 +00002407 vassert(isIRAtom(ex->Iex.GetI.ix));
sewardj62617ef2004-10-13 23:29:22 +00002408 return IRExpr_GetI(
2409 ex->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +00002410 subst_Expr(env, ex->Iex.GetI.ix),
sewardj62617ef2004-10-13 23:29:22 +00002411 ex->Iex.GetI.bias
2412 );
2413
florian96d7cc32012-06-01 20:41:24 +00002414 case Iex_Qop: {
2415 IRQop* qop = ex->Iex.Qop.details;
2416 vassert(isIRAtom(qop->arg1));
2417 vassert(isIRAtom(qop->arg2));
2418 vassert(isIRAtom(qop->arg3));
2419 vassert(isIRAtom(qop->arg4));
sewardj40c80262006-02-08 19:30:46 +00002420 return IRExpr_Qop(
florian96d7cc32012-06-01 20:41:24 +00002421 qop->op,
2422 subst_Expr(env, qop->arg1),
2423 subst_Expr(env, qop->arg2),
2424 subst_Expr(env, qop->arg3),
2425 subst_Expr(env, qop->arg4)
sewardj40c80262006-02-08 19:30:46 +00002426 );
florian96d7cc32012-06-01 20:41:24 +00002427 }
sewardj40c80262006-02-08 19:30:46 +00002428
florian420bfa92012-06-02 20:29:22 +00002429 case Iex_Triop: {
2430 IRTriop* triop = ex->Iex.Triop.details;
2431 vassert(isIRAtom(triop->arg1));
2432 vassert(isIRAtom(triop->arg2));
2433 vassert(isIRAtom(triop->arg3));
sewardjb183b852006-02-03 16:08:03 +00002434 return IRExpr_Triop(
florian420bfa92012-06-02 20:29:22 +00002435 triop->op,
2436 subst_Expr(env, triop->arg1),
2437 subst_Expr(env, triop->arg2),
2438 subst_Expr(env, triop->arg3)
sewardjb183b852006-02-03 16:08:03 +00002439 );
florian420bfa92012-06-02 20:29:22 +00002440 }
sewardjb183b852006-02-03 16:08:03 +00002441
sewardj62617ef2004-10-13 23:29:22 +00002442 case Iex_Binop:
sewardj496a58d2005-03-20 18:44:44 +00002443 vassert(isIRAtom(ex->Iex.Binop.arg1));
2444 vassert(isIRAtom(ex->Iex.Binop.arg2));
sewardj62617ef2004-10-13 23:29:22 +00002445 return IRExpr_Binop(
2446 ex->Iex.Binop.op,
2447 subst_Expr(env, ex->Iex.Binop.arg1),
2448 subst_Expr(env, ex->Iex.Binop.arg2)
2449 );
2450
2451 case Iex_Unop:
sewardj496a58d2005-03-20 18:44:44 +00002452 vassert(isIRAtom(ex->Iex.Unop.arg));
sewardj62617ef2004-10-13 23:29:22 +00002453 return IRExpr_Unop(
2454 ex->Iex.Unop.op,
2455 subst_Expr(env, ex->Iex.Unop.arg)
2456 );
2457
sewardjaf1ceca2005-06-30 23:31:27 +00002458 case Iex_Load:
2459 vassert(isIRAtom(ex->Iex.Load.addr));
2460 return IRExpr_Load(
2461 ex->Iex.Load.end,
2462 ex->Iex.Load.ty,
2463 subst_Expr(env, ex->Iex.Load.addr)
sewardj62617ef2004-10-13 23:29:22 +00002464 );
2465
2466 case Iex_CCall: {
2467 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +00002468 IRExpr** args2 = shallowCopyIRExprVec(ex->Iex.CCall.args);
sewardj62617ef2004-10-13 23:29:22 +00002469 for (i = 0; args2[i]; i++) {
sewardj496a58d2005-03-20 18:44:44 +00002470 vassert(isIRAtom(args2[i]));
sewardj62617ef2004-10-13 23:29:22 +00002471 args2[i] = subst_Expr(env, args2[i]);
2472 }
2473 return IRExpr_CCall(
sewardj8ea867b2004-10-30 19:03:02 +00002474 ex->Iex.CCall.cee,
sewardj62617ef2004-10-13 23:29:22 +00002475 ex->Iex.CCall.retty,
2476 args2
2477 );
sewardj84be7372004-08-18 13:59:33 +00002478 }
sewardj62617ef2004-10-13 23:29:22 +00002479
florian99dd03e2013-01-29 03:56:06 +00002480 case Iex_ITE:
2481 vassert(isIRAtom(ex->Iex.ITE.cond));
2482 vassert(isIRAtom(ex->Iex.ITE.iftrue));
2483 vassert(isIRAtom(ex->Iex.ITE.iffalse));
2484 return IRExpr_ITE(
2485 subst_Expr(env, ex->Iex.ITE.cond),
2486 subst_Expr(env, ex->Iex.ITE.iftrue),
2487 subst_Expr(env, ex->Iex.ITE.iffalse)
sewardj62617ef2004-10-13 23:29:22 +00002488 );
2489
2490 default:
2491 vex_printf("\n\n"); ppIRExpr(ex);
2492 vpanic("subst_Expr");
2493
sewardj84be7372004-08-18 13:59:33 +00002494 }
sewardj84be7372004-08-18 13:59:33 +00002495}
2496
2497
2498/* Apply the subst to stmt, then fold the result as much as possible.
sewardjd2445f62005-03-21 00:15:53 +00002499 Much simplified due to stmt being previously flattened. As a
2500 result of this, the stmt may wind up being turned into a no-op.
2501*/
sewardj62617ef2004-10-13 23:29:22 +00002502static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st )
sewardj84be7372004-08-18 13:59:33 +00002503{
2504# if 0
2505 vex_printf("\nsubst and fold stmt\n");
2506 ppIRStmt(st);
2507 vex_printf("\n");
2508# endif
2509
sewardj62617ef2004-10-13 23:29:22 +00002510 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00002511 case Ist_AbiHint:
2512 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +00002513 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +00002514 return IRStmt_AbiHint(
floriancdb5fee2012-02-13 00:06:29 +00002515 fold_Expr(env, subst_Expr(env, st->Ist.AbiHint.base)),
sewardj478646f2008-05-01 20:13:04 +00002516 st->Ist.AbiHint.len,
floriancdb5fee2012-02-13 00:06:29 +00002517 fold_Expr(env, subst_Expr(env, st->Ist.AbiHint.nia))
sewardj5a9ffab2005-05-12 17:55:01 +00002518 );
sewardj62617ef2004-10-13 23:29:22 +00002519 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00002520 vassert(isIRAtom(st->Ist.Put.data));
sewardj62617ef2004-10-13 23:29:22 +00002521 return IRStmt_Put(
2522 st->Ist.Put.offset,
floriancdb5fee2012-02-13 00:06:29 +00002523 fold_Expr(env, subst_Expr(env, st->Ist.Put.data))
sewardj62617ef2004-10-13 23:29:22 +00002524 );
sewardj84be7372004-08-18 13:59:33 +00002525
floriand6f38b32012-05-31 15:46:18 +00002526 case Ist_PutI: {
2527 IRPutI *puti, *puti2;
2528 puti = st->Ist.PutI.details;
2529 vassert(isIRAtom(puti->ix));
2530 vassert(isIRAtom(puti->data));
2531 puti2 = mkIRPutI(puti->descr,
2532 fold_Expr(env, subst_Expr(env, puti->ix)),
2533 puti->bias,
2534 fold_Expr(env, subst_Expr(env, puti->data)));
2535 return IRStmt_PutI(puti2);
2536 }
sewardjd7217032004-08-19 10:49:10 +00002537
sewardjdd40fdf2006-12-24 02:20:24 +00002538 case Ist_WrTmp:
2539 /* This is the one place where an expr (st->Ist.WrTmp.data) is
sewardj62617ef2004-10-13 23:29:22 +00002540 allowed to be more than just a constant or a tmp. */
sewardjdd40fdf2006-12-24 02:20:24 +00002541 return IRStmt_WrTmp(
2542 st->Ist.WrTmp.tmp,
floriancdb5fee2012-02-13 00:06:29 +00002543 fold_Expr(env, subst_Expr(env, st->Ist.WrTmp.data))
sewardj62617ef2004-10-13 23:29:22 +00002544 );
sewardj84be7372004-08-18 13:59:33 +00002545
sewardjaf1ceca2005-06-30 23:31:27 +00002546 case Ist_Store:
2547 vassert(isIRAtom(st->Ist.Store.addr));
2548 vassert(isIRAtom(st->Ist.Store.data));
2549 return IRStmt_Store(
2550 st->Ist.Store.end,
floriancdb5fee2012-02-13 00:06:29 +00002551 fold_Expr(env, subst_Expr(env, st->Ist.Store.addr)),
2552 fold_Expr(env, subst_Expr(env, st->Ist.Store.data))
sewardj62617ef2004-10-13 23:29:22 +00002553 );
sewardj84be7372004-08-18 13:59:33 +00002554
sewardjcfe046e2013-01-17 14:23:53 +00002555 case Ist_StoreG: {
2556 IRStoreG* sg = st->Ist.StoreG.details;
2557 vassert(isIRAtom(sg->addr));
2558 vassert(isIRAtom(sg->data));
2559 vassert(isIRAtom(sg->guard));
2560 IRExpr* faddr = fold_Expr(env, subst_Expr(env, sg->addr));
2561 IRExpr* fdata = fold_Expr(env, subst_Expr(env, sg->data));
2562 IRExpr* fguard = fold_Expr(env, subst_Expr(env, sg->guard));
2563 if (fguard->tag == Iex_Const) {
2564 /* The condition on this store has folded down to a constant. */
2565 vassert(fguard->Iex.Const.con->tag == Ico_U1);
2566 if (fguard->Iex.Const.con->Ico.U1 == False) {
2567 return IRStmt_NoOp();
2568 } else {
2569 vassert(fguard->Iex.Const.con->Ico.U1 == True);
2570 return IRStmt_Store(sg->end, faddr, fdata);
2571 }
2572 }
2573 return IRStmt_StoreG(sg->end, faddr, fdata, fguard);
2574 }
2575
2576 case Ist_LoadG: {
2577 /* This is complicated. If the guard folds down to 'false',
2578 we can replace it with an assignment 'dst := alt', but if
2579 the guard folds down to 'true', we can't conveniently
2580 replace it with an unconditional load, because doing so
2581 requires generating a new temporary, and that is not easy
2582 to do at this point. */
2583 IRLoadG* lg = st->Ist.LoadG.details;
2584 vassert(isIRAtom(lg->addr));
2585 vassert(isIRAtom(lg->alt));
2586 vassert(isIRAtom(lg->guard));
2587 IRExpr* faddr = fold_Expr(env, subst_Expr(env, lg->addr));
2588 IRExpr* falt = fold_Expr(env, subst_Expr(env, lg->alt));
2589 IRExpr* fguard = fold_Expr(env, subst_Expr(env, lg->guard));
2590 if (fguard->tag == Iex_Const) {
2591 /* The condition on this load has folded down to a constant. */
2592 vassert(fguard->Iex.Const.con->tag == Ico_U1);
2593 if (fguard->Iex.Const.con->Ico.U1 == False) {
2594 /* The load is not going to happen -- instead 'alt' is
2595 assigned to 'dst'. */
2596 return IRStmt_WrTmp(lg->dst, falt);
2597 } else {
2598 vassert(fguard->Iex.Const.con->Ico.U1 == True);
2599 /* The load is always going to happen. We want to
2600 convert to an unconditional load and assign to 'dst'
2601 (IRStmt_WrTmp). Problem is we need an extra temp to
2602 hold the loaded value, but none is available.
2603 Instead, reconstitute the conditional load (with
2604 folded args, of course) and let the caller of this
2605 routine deal with the problem. */
2606 }
2607 }
2608 return IRStmt_LoadG(lg->end, lg->cvt, lg->dst, faddr, falt, fguard);
2609 }
2610
sewardje9d8a262009-07-01 08:06:34 +00002611 case Ist_CAS: {
2612 IRCAS *cas, *cas2;
2613 cas = st->Ist.CAS.details;
2614 vassert(isIRAtom(cas->addr));
2615 vassert(cas->expdHi == NULL || isIRAtom(cas->expdHi));
2616 vassert(isIRAtom(cas->expdLo));
2617 vassert(cas->dataHi == NULL || isIRAtom(cas->dataHi));
2618 vassert(isIRAtom(cas->dataLo));
2619 cas2 = mkIRCAS(
2620 cas->oldHi, cas->oldLo, cas->end,
floriancdb5fee2012-02-13 00:06:29 +00002621 fold_Expr(env, subst_Expr(env, cas->addr)),
sewardj6399f812012-06-29 15:36:44 +00002622 cas->expdHi ? fold_Expr(env, subst_Expr(env, cas->expdHi))
2623 : NULL,
floriancdb5fee2012-02-13 00:06:29 +00002624 fold_Expr(env, subst_Expr(env, cas->expdLo)),
sewardj6399f812012-06-29 15:36:44 +00002625 cas->dataHi ? fold_Expr(env, subst_Expr(env, cas->dataHi))
2626 : NULL,
floriancdb5fee2012-02-13 00:06:29 +00002627 fold_Expr(env, subst_Expr(env, cas->dataLo))
sewardje9d8a262009-07-01 08:06:34 +00002628 );
2629 return IRStmt_CAS(cas2);
2630 }
2631
sewardje768e922009-11-26 17:17:37 +00002632 case Ist_LLSC:
2633 vassert(isIRAtom(st->Ist.LLSC.addr));
2634 if (st->Ist.LLSC.storedata)
2635 vassert(isIRAtom(st->Ist.LLSC.storedata));
2636 return IRStmt_LLSC(
2637 st->Ist.LLSC.end,
2638 st->Ist.LLSC.result,
floriancdb5fee2012-02-13 00:06:29 +00002639 fold_Expr(env, subst_Expr(env, st->Ist.LLSC.addr)),
sewardje768e922009-11-26 17:17:37 +00002640 st->Ist.LLSC.storedata
floriancdb5fee2012-02-13 00:06:29 +00002641 ? fold_Expr(env, subst_Expr(env, st->Ist.LLSC.storedata))
sewardje768e922009-11-26 17:17:37 +00002642 : NULL
2643 );
2644
sewardj62617ef2004-10-13 23:29:22 +00002645 case Ist_Dirty: {
2646 Int i;
2647 IRDirty *d, *d2;
2648 d = st->Ist.Dirty.details;
2649 d2 = emptyIRDirty();
2650 *d2 = *d;
sewardjdd40fdf2006-12-24 02:20:24 +00002651 d2->args = shallowCopyIRExprVec(d2->args);
sewardj62617ef2004-10-13 23:29:22 +00002652 if (d2->mFx != Ifx_None) {
sewardj496a58d2005-03-20 18:44:44 +00002653 vassert(isIRAtom(d2->mAddr));
floriancdb5fee2012-02-13 00:06:29 +00002654 d2->mAddr = fold_Expr(env, subst_Expr(env, d2->mAddr));
sewardjb8e75862004-08-19 17:58:45 +00002655 }
sewardj496a58d2005-03-20 18:44:44 +00002656 vassert(isIRAtom(d2->guard));
floriancdb5fee2012-02-13 00:06:29 +00002657 d2->guard = fold_Expr(env, subst_Expr(env, d2->guard));
sewardj62617ef2004-10-13 23:29:22 +00002658 for (i = 0; d2->args[i]; i++) {
sewardj74142b82013-08-08 10:28:59 +00002659 IRExpr* arg = d2->args[i];
florian90419562013-08-15 20:54:52 +00002660 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg))) {
sewardj74142b82013-08-08 10:28:59 +00002661 vassert(isIRAtom(arg));
2662 d2->args[i] = fold_Expr(env, subst_Expr(env, arg));
2663 }
sewardj62617ef2004-10-13 23:29:22 +00002664 }
2665 return IRStmt_Dirty(d2);
sewardjb8e75862004-08-19 17:58:45 +00002666 }
sewardj84be7372004-08-18 13:59:33 +00002667
sewardjf1689312005-03-16 18:19:10 +00002668 case Ist_IMark:
sewardj2f10aa62011-05-27 13:20:56 +00002669 return IRStmt_IMark(st->Ist.IMark.addr,
2670 st->Ist.IMark.len,
2671 st->Ist.IMark.delta);
sewardjf1689312005-03-16 18:19:10 +00002672
sewardjd2445f62005-03-21 00:15:53 +00002673 case Ist_NoOp:
2674 return IRStmt_NoOp();
2675
sewardjc4356f02007-11-09 21:15:04 +00002676 case Ist_MBE:
2677 return IRStmt_MBE(st->Ist.MBE.event);
sewardj3e838932005-01-07 12:09:15 +00002678
sewardj62617ef2004-10-13 23:29:22 +00002679 case Ist_Exit: {
2680 IRExpr* fcond;
sewardj496a58d2005-03-20 18:44:44 +00002681 vassert(isIRAtom(st->Ist.Exit.guard));
floriancdb5fee2012-02-13 00:06:29 +00002682 fcond = fold_Expr(env, subst_Expr(env, st->Ist.Exit.guard));
sewardj62617ef2004-10-13 23:29:22 +00002683 if (fcond->tag == Iex_Const) {
2684 /* Interesting. The condition on this exit has folded down to
2685 a constant. */
sewardjba999312004-11-15 15:21:17 +00002686 vassert(fcond->Iex.Const.con->tag == Ico_U1);
2687 if (fcond->Iex.Const.con->Ico.U1 == False) {
sewardj62617ef2004-10-13 23:29:22 +00002688 /* exit is never going to happen, so dump the statement. */
sewardjd2445f62005-03-21 00:15:53 +00002689 return IRStmt_NoOp();
sewardj62617ef2004-10-13 23:29:22 +00002690 } else {
sewardjba999312004-11-15 15:21:17 +00002691 vassert(fcond->Iex.Const.con->Ico.U1 == True);
sewardje810c192005-09-09 08:33:03 +00002692 /* Hmmm. The exit has become unconditional. Leave it
2693 as it is for now, since we'd have to truncate the BB
2694 at this point, which is tricky. Such truncation is
2695 done later by the dead-code elimination pass. */
sewardj62617ef2004-10-13 23:29:22 +00002696 /* fall out into the reconstruct-the-exit code. */
sewardj08613742004-10-25 13:01:45 +00002697 if (vex_control.iropt_verbosity > 0)
2698 /* really a misuse of vex_control.iropt_verbosity */
sewardj8c2c10b2004-10-16 20:51:52 +00002699 vex_printf("vex iropt: IRStmt_Exit became unconditional\n");
sewardj62617ef2004-10-13 23:29:22 +00002700 }
2701 }
sewardjc6f970f2012-04-02 21:54:49 +00002702 return IRStmt_Exit(fcond, st->Ist.Exit.jk,
2703 st->Ist.Exit.dst, st->Ist.Exit.offsIP);
sewardj62617ef2004-10-13 23:29:22 +00002704 }
2705
2706 default:
2707 vex_printf("\n"); ppIRStmt(st);
2708 vpanic("subst_and_fold_Stmt");
2709 }
sewardj84be7372004-08-18 13:59:33 +00002710}
2711
2712
sewardjdd40fdf2006-12-24 02:20:24 +00002713IRSB* cprop_BB ( IRSB* in )
sewardj84be7372004-08-18 13:59:33 +00002714{
sewardj62617ef2004-10-13 23:29:22 +00002715 Int i;
sewardjdd40fdf2006-12-24 02:20:24 +00002716 IRSB* out;
sewardj62617ef2004-10-13 23:29:22 +00002717 IRStmt* st2;
2718 Int n_tmps = in->tyenv->types_used;
2719 IRExpr** env = LibVEX_Alloc(n_tmps * sizeof(IRExpr*));
sewardjcfe046e2013-01-17 14:23:53 +00002720 /* Keep track of IRStmt_LoadGs that we need to revisit after
2721 processing all the other statements. */
2722 const Int N_FIXUPS = 16;
2723 Int fixups[N_FIXUPS]; /* indices in the stmt array of 'out' */
2724 Int n_fixups = 0;
sewardj84be7372004-08-18 13:59:33 +00002725
sewardjdd40fdf2006-12-24 02:20:24 +00002726 out = emptyIRSB();
2727 out->tyenv = deepCopyIRTypeEnv( in->tyenv );
sewardj84be7372004-08-18 13:59:33 +00002728
2729 /* Set up the env with which travels forward. This holds a
floriancdb5fee2012-02-13 00:06:29 +00002730 substitution, mapping IRTemps to IRExprs. The environment
2731 is to be applied as we move along. Keys are IRTemps.
2732 Values are IRExpr*s.
sewardj84be7372004-08-18 13:59:33 +00002733 */
sewardj62617ef2004-10-13 23:29:22 +00002734 for (i = 0; i < n_tmps; i++)
2735 env[i] = NULL;
sewardj84be7372004-08-18 13:59:33 +00002736
2737 /* For each original SSA-form stmt ... */
2738 for (i = 0; i < in->stmts_used; i++) {
2739
2740 /* First apply the substitution to the current stmt. This
2741 propagates in any constants and tmp-tmp assignments
2742 accumulated prior to this point. As part of the subst_Stmt
2743 call, also then fold any constant expressions resulting. */
2744
sewardjf0e43162004-08-20 00:11:12 +00002745 st2 = in->stmts[i];
2746
2747 /* perhaps st2 is already a no-op? */
sewardj8bee6d12005-03-22 02:24:05 +00002748 if (st2->tag == Ist_NoOp) continue;
sewardjf0e43162004-08-20 00:11:12 +00002749
2750 st2 = subst_and_fold_Stmt( env, st2 );
sewardj84be7372004-08-18 13:59:33 +00002751
sewardjcfe046e2013-01-17 14:23:53 +00002752 /* Deal with some post-folding special cases. */
2753 switch (st2->tag) {
sewardjb8e75862004-08-19 17:58:45 +00002754
sewardjcfe046e2013-01-17 14:23:53 +00002755 /* If the statement has been folded into a no-op, forget
2756 it. */
2757 case Ist_NoOp:
2758 continue;
sewardj84be7372004-08-18 13:59:33 +00002759
sewardjcfe046e2013-01-17 14:23:53 +00002760 /* If the statement assigns to an IRTemp add it to the
2761 running environment. This is for the benefit of copy
2762 propagation and to allow sameIRExpr look through
2763 IRTemps. */
2764 case Ist_WrTmp: {
2765 vassert(env[(Int)(st2->Ist.WrTmp.tmp)] == NULL);
2766 env[(Int)(st2->Ist.WrTmp.tmp)] = st2->Ist.WrTmp.data;
floriancdb5fee2012-02-13 00:06:29 +00002767
sewardjcfe046e2013-01-17 14:23:53 +00002768 /* 't1 = t2' -- don't add to BB; will be optimized out */
2769 if (st2->Ist.WrTmp.data->tag == Iex_RdTmp)
2770 continue;
2771
2772 /* 't = const' && 'const != F64i' -- don't add to BB
2773 Note, we choose not to propagate const when const is an
2774 F64i, so that F64i literals can be CSE'd later. This
2775 helps x86 floating point code generation. */
2776 if (st2->Ist.WrTmp.data->tag == Iex_Const
2777 && st2->Ist.WrTmp.data->Iex.Const.con->tag != Ico_F64i) {
2778 continue;
2779 }
2780 /* else add it to the output, as normal */
2781 break;
2782 }
2783
2784 case Ist_LoadG: {
2785 IRLoadG* lg = st2->Ist.LoadG.details;
2786 IRExpr* guard = lg->guard;
2787 if (guard->tag == Iex_Const) {
2788 /* The guard has folded to a constant, and that
2789 constant must be 1:I1, since subst_and_fold_Stmt
2790 folds out the case 0:I1 by itself. */
2791 vassert(guard->Iex.Const.con->tag == Ico_U1);
2792 vassert(guard->Iex.Const.con->Ico.U1 == True);
2793 /* Add a NoOp here as a placeholder, and make a note of
2794 where it is in the output block. Afterwards we'll
2795 come back here and transform the NoOp and the LoadG
2796 into a load-convert pair. The fixups[] entry
2797 refers to the inserted NoOp, and we expect to find
2798 the relevant LoadG immediately after it. */
2799 vassert(n_fixups >= 0 && n_fixups <= N_FIXUPS);
2800 if (n_fixups < N_FIXUPS) {
2801 fixups[n_fixups++] = out->stmts_used;
2802 addStmtToIRSB( out, IRStmt_NoOp() );
2803 }
2804 }
2805 /* And always add the LoadG to the output, regardless. */
2806 break;
2807 }
2808
2809 default:
2810 break;
sewardj84be7372004-08-18 13:59:33 +00002811 }
floriancdb5fee2012-02-13 00:06:29 +00002812
2813 /* Not interesting, copy st2 into the output block. */
2814 addStmtToIRSB( out, st2 );
sewardj84be7372004-08-18 13:59:33 +00002815 }
2816
sewardjcfe046e2013-01-17 14:23:53 +00002817# if STATS_IROPT
floriancdb5fee2012-02-13 00:06:29 +00002818 vex_printf("sameIRExpr: invoked = %u/%u equal = %u/%u max_nodes = %u\n",
2819 invocation_count, recursion_count, success_count,
2820 recursion_success_count, max_nodes_visited);
sewardjcfe046e2013-01-17 14:23:53 +00002821# endif
floriancdb5fee2012-02-13 00:06:29 +00002822
sewardj84be7372004-08-18 13:59:33 +00002823 out->next = subst_Expr( env, in->next );
2824 out->jumpkind = in->jumpkind;
sewardjc6f970f2012-04-02 21:54:49 +00002825 out->offsIP = in->offsIP;
sewardjcfe046e2013-01-17 14:23:53 +00002826
2827 /* Process any leftover unconditional LoadGs that we noticed
2828 in the main pass. */
2829 vassert(n_fixups >= 0 && n_fixups <= N_FIXUPS);
2830 for (i = 0; i < n_fixups; i++) {
2831 Int ix = fixups[i];
2832 /* Carefully verify that the LoadG has the expected form. */
2833 vassert(ix >= 0 && ix+1 < out->stmts_used);
2834 IRStmt* nop = out->stmts[ix];
2835 IRStmt* lgu = out->stmts[ix+1];
2836 vassert(nop->tag == Ist_NoOp);
2837 vassert(lgu->tag == Ist_LoadG);
2838 IRLoadG* lg = lgu->Ist.LoadG.details;
2839 IRExpr* guard = lg->guard;
2840 vassert(guard->Iex.Const.con->tag == Ico_U1);
2841 vassert(guard->Iex.Const.con->Ico.U1 == True);
2842 /* Figure out the load and result types, and the implied
2843 conversion operation. */
2844 IRType cvtRes = Ity_INVALID, cvtArg = Ity_INVALID;
2845 typeOfIRLoadGOp(lg->cvt, &cvtRes, &cvtArg);
2846 IROp cvtOp = Iop_INVALID;
2847 switch (lg->cvt) {
2848 case ILGop_Ident32: break;
2849 case ILGop_8Uto32: cvtOp = Iop_8Uto32; break;
2850 case ILGop_8Sto32: cvtOp = Iop_8Sto32; break;
2851 case ILGop_16Uto32: cvtOp = Iop_16Uto32; break;
2852 case ILGop_16Sto32: cvtOp = Iop_16Sto32; break;
2853 default: vpanic("cprop_BB: unhandled ILGOp");
2854 }
2855 /* Replace the placeholder NoOp by the required unconditional
2856 load. */
2857 IRTemp tLoaded = newIRTemp(out->tyenv, cvtArg);
2858 out->stmts[ix]
2859 = IRStmt_WrTmp(tLoaded,
2860 IRExpr_Load(lg->end, cvtArg, lg->addr));
2861 /* Replace the LoadG by a conversion from the loaded value's
2862 type to the required result type. */
2863 out->stmts[ix+1]
2864 = IRStmt_WrTmp(
2865 lg->dst, cvtOp == Iop_INVALID
2866 ? IRExpr_RdTmp(tLoaded)
2867 : IRExpr_Unop(cvtOp, IRExpr_RdTmp(tLoaded)));
2868 }
2869
sewardj84be7372004-08-18 13:59:33 +00002870 return out;
2871}
2872
2873
sewardjedf4d692004-08-17 13:52:58 +00002874/*---------------------------------------------------------------*/
sewardj39e3f242004-08-18 16:54:52 +00002875/*--- Dead code (t = E) removal ---*/
2876/*---------------------------------------------------------------*/
2877
sewardje810c192005-09-09 08:33:03 +00002878/* As a side effect, also removes all code following an unconditional
2879 side exit. */
2880
sewardjea602bc2004-10-14 21:40:12 +00002881/* The type of the HashHW map is: a map from IRTemp to nothing
sewardj39e3f242004-08-18 16:54:52 +00002882 -- really just operating a set or IRTemps.
2883*/
2884
sewardjd503a322004-10-13 22:41:16 +00002885inline
2886static void addUses_Temp ( Bool* set, IRTemp tmp )
sewardj17442fe2004-09-20 14:54:28 +00002887{
sewardjd503a322004-10-13 22:41:16 +00002888 set[(Int)tmp] = True;
sewardj17442fe2004-09-20 14:54:28 +00002889}
2890
sewardjd503a322004-10-13 22:41:16 +00002891static void addUses_Expr ( Bool* set, IRExpr* e )
sewardj39e3f242004-08-18 16:54:52 +00002892{
2893 Int i;
2894 switch (e->tag) {
sewardjd7217032004-08-19 10:49:10 +00002895 case Iex_GetI:
sewardjeeac8412004-11-02 00:26:55 +00002896 addUses_Expr(set, e->Iex.GetI.ix);
sewardjd7217032004-08-19 10:49:10 +00002897 return;
florian99dd03e2013-01-29 03:56:06 +00002898 case Iex_ITE:
2899 addUses_Expr(set, e->Iex.ITE.cond);
2900 addUses_Expr(set, e->Iex.ITE.iftrue);
2901 addUses_Expr(set, e->Iex.ITE.iffalse);
sewardj39e3f242004-08-18 16:54:52 +00002902 return;
2903 case Iex_CCall:
2904 for (i = 0; e->Iex.CCall.args[i]; i++)
2905 addUses_Expr(set, e->Iex.CCall.args[i]);
2906 return;
sewardjaf1ceca2005-06-30 23:31:27 +00002907 case Iex_Load:
2908 addUses_Expr(set, e->Iex.Load.addr);
sewardj39e3f242004-08-18 16:54:52 +00002909 return;
sewardj40c80262006-02-08 19:30:46 +00002910 case Iex_Qop:
florian96d7cc32012-06-01 20:41:24 +00002911 addUses_Expr(set, e->Iex.Qop.details->arg1);
2912 addUses_Expr(set, e->Iex.Qop.details->arg2);
2913 addUses_Expr(set, e->Iex.Qop.details->arg3);
2914 addUses_Expr(set, e->Iex.Qop.details->arg4);
sewardj40c80262006-02-08 19:30:46 +00002915 return;
sewardjb183b852006-02-03 16:08:03 +00002916 case Iex_Triop:
florian420bfa92012-06-02 20:29:22 +00002917 addUses_Expr(set, e->Iex.Triop.details->arg1);
2918 addUses_Expr(set, e->Iex.Triop.details->arg2);
2919 addUses_Expr(set, e->Iex.Triop.details->arg3);
sewardjb183b852006-02-03 16:08:03 +00002920 return;
sewardj39e3f242004-08-18 16:54:52 +00002921 case Iex_Binop:
2922 addUses_Expr(set, e->Iex.Binop.arg1);
2923 addUses_Expr(set, e->Iex.Binop.arg2);
2924 return;
2925 case Iex_Unop:
2926 addUses_Expr(set, e->Iex.Unop.arg);
2927 return;
sewardjdd40fdf2006-12-24 02:20:24 +00002928 case Iex_RdTmp:
2929 addUses_Temp(set, e->Iex.RdTmp.tmp);
sewardj39e3f242004-08-18 16:54:52 +00002930 return;
2931 case Iex_Const:
2932 case Iex_Get:
2933 return;
2934 default:
2935 vex_printf("\n");
2936 ppIRExpr(e);
2937 vpanic("addUses_Expr");
2938 }
2939}
2940
sewardjd503a322004-10-13 22:41:16 +00002941static void addUses_Stmt ( Bool* set, IRStmt* st )
sewardj39e3f242004-08-18 16:54:52 +00002942{
sewardj17442fe2004-09-20 14:54:28 +00002943 Int i;
2944 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00002945 IRCAS* cas;
sewardj39e3f242004-08-18 16:54:52 +00002946 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00002947 case Ist_AbiHint:
2948 addUses_Expr(set, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +00002949 addUses_Expr(set, st->Ist.AbiHint.nia);
sewardj5a9ffab2005-05-12 17:55:01 +00002950 return;
sewardjd7217032004-08-19 10:49:10 +00002951 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +00002952 addUses_Expr(set, st->Ist.PutI.details->ix);
2953 addUses_Expr(set, st->Ist.PutI.details->data);
sewardjd7217032004-08-19 10:49:10 +00002954 return;
sewardjdd40fdf2006-12-24 02:20:24 +00002955 case Ist_WrTmp:
2956 addUses_Expr(set, st->Ist.WrTmp.data);
sewardj39e3f242004-08-18 16:54:52 +00002957 return;
2958 case Ist_Put:
sewardj6d076362004-09-23 11:06:17 +00002959 addUses_Expr(set, st->Ist.Put.data);
sewardj39e3f242004-08-18 16:54:52 +00002960 return;
sewardjaf1ceca2005-06-30 23:31:27 +00002961 case Ist_Store:
2962 addUses_Expr(set, st->Ist.Store.addr);
2963 addUses_Expr(set, st->Ist.Store.data);
sewardj39e3f242004-08-18 16:54:52 +00002964 return;
sewardjcfe046e2013-01-17 14:23:53 +00002965 case Ist_StoreG: {
2966 IRStoreG* sg = st->Ist.StoreG.details;
2967 addUses_Expr(set, sg->addr);
2968 addUses_Expr(set, sg->data);
2969 addUses_Expr(set, sg->guard);
2970 return;
2971 }
2972 case Ist_LoadG: {
2973 IRLoadG* lg = st->Ist.LoadG.details;
2974 addUses_Expr(set, lg->addr);
2975 addUses_Expr(set, lg->alt);
2976 addUses_Expr(set, lg->guard);
2977 return;
2978 }
sewardje9d8a262009-07-01 08:06:34 +00002979 case Ist_CAS:
2980 cas = st->Ist.CAS.details;
2981 addUses_Expr(set, cas->addr);
2982 if (cas->expdHi)
2983 addUses_Expr(set, cas->expdHi);
2984 addUses_Expr(set, cas->expdLo);
2985 if (cas->dataHi)
2986 addUses_Expr(set, cas->dataHi);
2987 addUses_Expr(set, cas->dataLo);
2988 return;
sewardje768e922009-11-26 17:17:37 +00002989 case Ist_LLSC:
2990 addUses_Expr(set, st->Ist.LLSC.addr);
2991 if (st->Ist.LLSC.storedata)
2992 addUses_Expr(set, st->Ist.LLSC.storedata);
2993 return;
sewardj17442fe2004-09-20 14:54:28 +00002994 case Ist_Dirty:
2995 d = st->Ist.Dirty.details;
2996 if (d->mFx != Ifx_None)
2997 addUses_Expr(set, d->mAddr);
sewardjb8385d82004-11-02 01:34:15 +00002998 addUses_Expr(set, d->guard);
sewardj74142b82013-08-08 10:28:59 +00002999 for (i = 0; d->args[i] != NULL; i++) {
3000 IRExpr* arg = d->args[i];
florian90419562013-08-15 20:54:52 +00003001 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +00003002 addUses_Expr(set, arg);
3003 }
sewardj17442fe2004-09-20 14:54:28 +00003004 return;
sewardjd2445f62005-03-21 00:15:53 +00003005 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00003006 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00003007 case Ist_MBE:
sewardj3e838932005-01-07 12:09:15 +00003008 return;
sewardj17442fe2004-09-20 14:54:28 +00003009 case Ist_Exit:
sewardj0276d4b2004-11-15 15:30:21 +00003010 addUses_Expr(set, st->Ist.Exit.guard);
sewardj17442fe2004-09-20 14:54:28 +00003011 return;
sewardj39e3f242004-08-18 16:54:52 +00003012 default:
3013 vex_printf("\n");
3014 ppIRStmt(st);
3015 vpanic("addUses_Stmt");
sewardjd503a322004-10-13 22:41:16 +00003016 }
sewardj39e3f242004-08-18 16:54:52 +00003017}
3018
3019
sewardjba999312004-11-15 15:21:17 +00003020/* Is this literally IRExpr_Const(IRConst_U1(False)) ? */
3021static Bool isZeroU1 ( IRExpr* e )
sewardjd9997882004-11-04 19:42:59 +00003022{
sewardj9d2e7692005-02-07 01:11:31 +00003023 return toBool( e->tag == Iex_Const
3024 && e->Iex.Const.con->tag == Ico_U1
3025 && e->Iex.Const.con->Ico.U1 == False );
sewardjd9997882004-11-04 19:42:59 +00003026}
3027
sewardje810c192005-09-09 08:33:03 +00003028/* Is this literally IRExpr_Const(IRConst_U1(True)) ? */
3029static Bool isOneU1 ( IRExpr* e )
3030{
3031 return toBool( e->tag == Iex_Const
3032 && e->Iex.Const.con->tag == Ico_U1
3033 && e->Iex.Const.con->Ico.U1 == True );
3034}
3035
sewardj39e3f242004-08-18 16:54:52 +00003036
sewardjdd40fdf2006-12-24 02:20:24 +00003037/* Note, this destructively modifies the given IRSB. */
sewardj39e3f242004-08-18 16:54:52 +00003038
3039/* Scan backwards through statements, carrying a set of IRTemps which
3040 are known to be used after the current point. On encountering 't =
3041 E', delete the binding if it is not used. Otherwise, add any temp
sewardje810c192005-09-09 08:33:03 +00003042 uses to the set and keep on moving backwards.
3043
3044 As an enhancement, the first (backwards) pass searches for IR exits
3045 with always-taken conditions and notes the location of the earliest
3046 one in the block. If any such are found, a second pass copies the
3047 exit destination and jump kind to the bb-end. Then, the exit and
3048 all statements following it are turned into no-ops.
3049*/
sewardj39e3f242004-08-18 16:54:52 +00003050
sewardjdd40fdf2006-12-24 02:20:24 +00003051/* notstatic */ void do_deadcode_BB ( IRSB* bb )
sewardj39e3f242004-08-18 16:54:52 +00003052{
sewardje810c192005-09-09 08:33:03 +00003053 Int i, i_unconditional_exit;
sewardjd503a322004-10-13 22:41:16 +00003054 Int n_tmps = bb->tyenv->types_used;
3055 Bool* set = LibVEX_Alloc(n_tmps * sizeof(Bool));
sewardj39e3f242004-08-18 16:54:52 +00003056 IRStmt* st;
3057
sewardjd503a322004-10-13 22:41:16 +00003058 for (i = 0; i < n_tmps; i++)
3059 set[i] = False;
3060
sewardj39e3f242004-08-18 16:54:52 +00003061 /* start off by recording IRTemp uses in the next field. */
3062 addUses_Expr(set, bb->next);
3063
sewardje810c192005-09-09 08:33:03 +00003064 /* First pass */
3065
sewardj39e3f242004-08-18 16:54:52 +00003066 /* Work backwards through the stmts */
sewardje810c192005-09-09 08:33:03 +00003067 i_unconditional_exit = -1;
sewardj39e3f242004-08-18 16:54:52 +00003068 for (i = bb->stmts_used-1; i >= 0; i--) {
3069 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00003070 if (st->tag == Ist_NoOp)
sewardj84ff0652004-08-23 16:16:08 +00003071 continue;
sewardje810c192005-09-09 08:33:03 +00003072 /* take note of any unconditional exits */
3073 if (st->tag == Ist_Exit
3074 && isOneU1(st->Ist.Exit.guard))
3075 i_unconditional_exit = i;
sewardjdd40fdf2006-12-24 02:20:24 +00003076 if (st->tag == Ist_WrTmp
3077 && set[(Int)(st->Ist.WrTmp.tmp)] == False) {
sewardj39e3f242004-08-18 16:54:52 +00003078 /* it's an IRTemp which never got used. Delete it. */
sewardj088bcb42004-08-19 17:16:52 +00003079 if (DEBUG_IROPT) {
sewardj39e3f242004-08-18 16:54:52 +00003080 vex_printf("DEAD: ");
3081 ppIRStmt(st);
3082 vex_printf("\n");
3083 }
sewardjd2445f62005-03-21 00:15:53 +00003084 bb->stmts[i] = IRStmt_NoOp();
sewardjd9997882004-11-04 19:42:59 +00003085 }
3086 else
3087 if (st->tag == Ist_Dirty
3088 && st->Ist.Dirty.details->guard
sewardjba999312004-11-15 15:21:17 +00003089 && isZeroU1(st->Ist.Dirty.details->guard)) {
sewardjd2445f62005-03-21 00:15:53 +00003090 /* This is a dirty helper which will never get called.
3091 Delete it. */
3092 bb->stmts[i] = IRStmt_NoOp();
sewardjd9997882004-11-04 19:42:59 +00003093 }
3094 else {
sewardj39e3f242004-08-18 16:54:52 +00003095 /* Note any IRTemp uses made by the current statement. */
3096 addUses_Stmt(set, st);
3097 }
3098 }
sewardje810c192005-09-09 08:33:03 +00003099
3100 /* Optional second pass: if any unconditional exits were found,
3101 delete them and all following statements. */
3102
3103 if (i_unconditional_exit != -1) {
3104 if (0) vex_printf("ZAPPING ALL FORWARDS from %d\n",
3105 i_unconditional_exit);
3106 vassert(i_unconditional_exit >= 0
3107 && i_unconditional_exit < bb->stmts_used);
3108 bb->next
3109 = IRExpr_Const( bb->stmts[i_unconditional_exit]->Ist.Exit.dst );
3110 bb->jumpkind
3111 = bb->stmts[i_unconditional_exit]->Ist.Exit.jk;
sewardjc6f970f2012-04-02 21:54:49 +00003112 bb->offsIP
3113 = bb->stmts[i_unconditional_exit]->Ist.Exit.offsIP;
sewardje810c192005-09-09 08:33:03 +00003114 for (i = i_unconditional_exit; i < bb->stmts_used; i++)
3115 bb->stmts[i] = IRStmt_NoOp();
3116 }
sewardj39e3f242004-08-18 16:54:52 +00003117}
3118
sewardje810c192005-09-09 08:33:03 +00003119
sewardj84ff0652004-08-23 16:16:08 +00003120/*---------------------------------------------------------------*/
3121/*--- Specialisation of helper function calls, in ---*/
3122/*--- collaboration with the front end ---*/
3123/*---------------------------------------------------------------*/
3124
3125static
sewardjbe917912010-08-22 12:38:53 +00003126IRSB* spec_helpers_BB(
3127 IRSB* bb,
florian1ff47562012-10-21 02:09:51 +00003128 IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int)
sewardjbe917912010-08-22 12:38:53 +00003129 )
sewardj84ff0652004-08-23 16:16:08 +00003130{
sewardjb9230752004-12-29 19:25:06 +00003131 Int i;
sewardj84ff0652004-08-23 16:16:08 +00003132 IRStmt* st;
3133 IRExpr* ex;
sewardjb9230752004-12-29 19:25:06 +00003134 Bool any = False;
sewardj84ff0652004-08-23 16:16:08 +00003135
3136 for (i = bb->stmts_used-1; i >= 0; i--) {
3137 st = bb->stmts[i];
3138
sewardjdd40fdf2006-12-24 02:20:24 +00003139 if (st->tag != Ist_WrTmp
3140 || st->Ist.WrTmp.data->tag != Iex_CCall)
sewardj8bee6d12005-03-22 02:24:05 +00003141 continue;
sewardj84ff0652004-08-23 16:16:08 +00003142
sewardjdd40fdf2006-12-24 02:20:24 +00003143 ex = (*specHelper)( st->Ist.WrTmp.data->Iex.CCall.cee->name,
sewardjbe917912010-08-22 12:38:53 +00003144 st->Ist.WrTmp.data->Iex.CCall.args,
3145 &bb->stmts[0], i );
sewardj84ff0652004-08-23 16:16:08 +00003146 if (!ex)
sewardjaba4fff2004-10-08 21:37:15 +00003147 /* the front end can't think of a suitable replacement */
3148 continue;
sewardj84ff0652004-08-23 16:16:08 +00003149
3150 /* We got something better. Install it in the bb. */
sewardjb9230752004-12-29 19:25:06 +00003151 any = True;
sewardj84ff0652004-08-23 16:16:08 +00003152 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00003153 = IRStmt_WrTmp(st->Ist.WrTmp.tmp, ex);
sewardj84ff0652004-08-23 16:16:08 +00003154
3155 if (0) {
3156 vex_printf("SPEC: ");
sewardjdd40fdf2006-12-24 02:20:24 +00003157 ppIRExpr(st->Ist.WrTmp.data);
sewardj84ff0652004-08-23 16:16:08 +00003158 vex_printf(" --> ");
3159 ppIRExpr(ex);
3160 vex_printf("\n");
3161 }
3162 }
sewardjb9230752004-12-29 19:25:06 +00003163
3164 if (any)
3165 bb = flatten_BB(bb);
3166 return bb;
sewardj84ff0652004-08-23 16:16:08 +00003167}
3168
sewardj29632392004-08-22 02:38:11 +00003169
3170/*---------------------------------------------------------------*/
sewardj9b0cc582006-02-04 15:24:00 +00003171/*--- Determination of guest state aliasing relationships ---*/
3172/*---------------------------------------------------------------*/
3173
3174/* These are helper functions for CSE and GetI/PutI transformations.
3175
3176 Determine, to the extent possible, the relationship between two
3177 guest state accesses. The possible outcomes are:
3178
3179 * Exact alias. These two accesses denote precisely the same
3180 piece of the guest state.
3181
3182 * Definitely no alias. These two accesses are guaranteed not to
3183 overlap any part of the guest state.
3184
3185 * Unknown -- if neither of the above can be established.
3186
3187 If in doubt, return Unknown. */
3188
3189typedef
3190 enum { ExactAlias, NoAlias, UnknownAlias }
3191 GSAliasing;
3192
3193
3194/* Produces the alias relation between an indexed guest
3195 state access and a non-indexed access. */
3196
3197static
sewardjdd40fdf2006-12-24 02:20:24 +00003198GSAliasing getAliasingRelation_IC ( IRRegArray* descr1, IRExpr* ix1,
sewardj9b0cc582006-02-04 15:24:00 +00003199 Int offset2, IRType ty2 )
3200{
3201 UInt minoff1, maxoff1, minoff2, maxoff2;
3202
3203 getArrayBounds( descr1, &minoff1, &maxoff1 );
3204 minoff2 = offset2;
3205 maxoff2 = minoff2 + sizeofIRType(ty2) - 1;
3206
3207 if (maxoff1 < minoff2 || maxoff2 < minoff1)
3208 return NoAlias;
3209
3210 /* Could probably do better here if required. For the moment
3211 however just claim not to know anything more. */
3212 return UnknownAlias;
3213}
3214
3215
3216/* Produces the alias relation between two indexed guest state
3217 accesses. */
3218
3219static
3220GSAliasing getAliasingRelation_II (
sewardjdd40fdf2006-12-24 02:20:24 +00003221 IRRegArray* descr1, IRExpr* ix1, Int bias1,
3222 IRRegArray* descr2, IRExpr* ix2, Int bias2
sewardj9b0cc582006-02-04 15:24:00 +00003223 )
3224{
3225 UInt minoff1, maxoff1, minoff2, maxoff2;
3226 Int iters;
3227
3228 /* First try hard to show they don't alias. */
3229 getArrayBounds( descr1, &minoff1, &maxoff1 );
3230 getArrayBounds( descr2, &minoff2, &maxoff2 );
3231 if (maxoff1 < minoff2 || maxoff2 < minoff1)
3232 return NoAlias;
3233
3234 /* So the two arrays at least partially overlap. To get any
3235 further we'll have to be sure that the descriptors are
3236 identical. */
sewardjdd40fdf2006-12-24 02:20:24 +00003237 if (!eqIRRegArray(descr1, descr2))
sewardj9b0cc582006-02-04 15:24:00 +00003238 return UnknownAlias;
3239
3240 /* The descriptors are identical. Now the only difference can be
3241 in the index expressions. If they cannot be shown to be
3242 identical, we have to say we don't know what the aliasing
3243 relation will be. Now, since the IR is flattened, the index
3244 expressions should be atoms -- either consts or tmps. So that
3245 makes the comparison simple. */
3246 vassert(isIRAtom(ix1));
3247 vassert(isIRAtom(ix2));
3248 if (!eqIRAtom(ix1,ix2))
3249 return UnknownAlias;
3250
3251 /* Ok, the index expressions are identical. So now the only way
3252 they can be different is in the bias. Normalise this
3253 paranoidly, to reliably establish equality/non-equality. */
3254
3255 /* So now we know that the GetI and PutI index the same array
3256 with the same base. Are the offsets the same, modulo the
3257 array size? Do this paranoidly. */
3258 vassert(descr1->nElems == descr2->nElems);
3259 vassert(descr1->elemTy == descr2->elemTy);
3260 vassert(descr1->base == descr2->base);
3261 iters = 0;
3262 while (bias1 < 0 || bias2 < 0) {
3263 bias1 += descr1->nElems;
3264 bias2 += descr1->nElems;
3265 iters++;
3266 if (iters > 10)
3267 vpanic("getAliasingRelation: iters");
3268 }
3269 vassert(bias1 >= 0 && bias2 >= 0);
3270 bias1 %= descr1->nElems;
3271 bias2 %= descr1->nElems;
3272 vassert(bias1 >= 0 && bias1 < descr1->nElems);
3273 vassert(bias2 >= 0 && bias2 < descr1->nElems);
3274
3275 /* Finally, biasP and biasG are normalised into the range
3276 0 .. descrP/G->nElems - 1. And so we can establish
3277 equality/non-equality. */
3278
3279 return bias1==bias2 ? ExactAlias : NoAlias;
3280}
3281
3282
3283/*---------------------------------------------------------------*/
sewardj08210532004-12-29 17:09:11 +00003284/*--- Common Subexpression Elimination ---*/
3285/*---------------------------------------------------------------*/
3286
3287/* Expensive in time and space. */
3288
3289/* Uses two environments:
3290 a IRTemp -> IRTemp mapping
3291 a mapping from AvailExpr* to IRTemp
3292*/
3293
3294typedef
3295 struct {
sewardje8578042012-04-13 11:42:50 +00003296 enum { TCc, TCt } tag;
3297 union { IRTemp tmp; IRConst* con; } u;
3298 }
3299 TmpOrConst;
3300
3301static Bool eqTmpOrConst ( TmpOrConst* tc1, TmpOrConst* tc2 )
3302{
3303 if (tc1->tag != tc2->tag)
3304 return False;
3305 switch (tc1->tag) {
3306 case TCc:
3307 return eqIRConst(tc1->u.con, tc2->u.con);
3308 case TCt:
3309 return tc1->u.tmp == tc2->u.tmp;
3310 default:
3311 vpanic("eqTmpOrConst");
3312 }
3313}
3314
3315static Bool eqIRCallee ( IRCallee* cee1, IRCallee* cee2 )
3316{
3317 Bool eq = cee1->addr == cee2->addr;
3318 if (eq) {
3319 vassert(cee1->regparms == cee2->regparms);
3320 vassert(cee1->mcx_mask == cee2->mcx_mask);
3321 /* Names should be the same too, but we don't bother to
3322 check. */
3323 }
3324 return eq;
3325}
3326
3327/* Convert a NULL terminated IRExpr* vector to an array of
3328 TmpOrConsts, and a length. */
3329static void irExprVec_to_TmpOrConsts ( /*OUT*/TmpOrConst** outs,
3330 /*OUT*/Int* nOuts,
3331 IRExpr** ins )
3332{
3333 Int i, n;
3334 /* We have to make two passes, one to count, one to copy. */
3335 for (n = 0; ins[n]; n++)
3336 ;
3337 *outs = LibVEX_Alloc(n * sizeof(TmpOrConst));
3338 *nOuts = n;
3339 /* and now copy .. */
3340 for (i = 0; i < n; i++) {
3341 IRExpr* arg = ins[i];
3342 TmpOrConst* dst = &(*outs)[i];
3343 if (arg->tag == Iex_RdTmp) {
3344 dst->tag = TCt;
3345 dst->u.tmp = arg->Iex.RdTmp.tmp;
3346 }
3347 else if (arg->tag == Iex_Const) {
3348 dst->tag = TCc;
3349 dst->u.con = arg->Iex.Const.con;
3350 }
3351 else {
3352 /* Failure of this is serious; it means that the presented arg
3353 isn't an IR atom, as it should be. */
3354 vpanic("irExprVec_to_TmpOrConsts");
3355 }
3356 }
3357}
3358
3359typedef
3360 struct {
florianb05c20c2013-01-31 02:04:02 +00003361 enum { Ut, Btt, Btc, Bct, Cf64i, Ittt, Itct, Ittc, Itcc, GetIt,
florianda25edd2012-09-12 16:40:54 +00003362 CCall
3363 } tag;
sewardj08210532004-12-29 17:09:11 +00003364 union {
3365 /* unop(tmp) */
3366 struct {
3367 IROp op;
3368 IRTemp arg;
3369 } Ut;
3370 /* binop(tmp,tmp) */
3371 struct {
3372 IROp op;
3373 IRTemp arg1;
3374 IRTemp arg2;
3375 } Btt;
3376 /* binop(tmp,const) */
3377 struct {
3378 IROp op;
3379 IRTemp arg1;
3380 IRConst con2;
3381 } Btc;
3382 /* binop(const,tmp) */
3383 struct {
3384 IROp op;
3385 IRConst con1;
3386 IRTemp arg2;
3387 } Bct;
3388 /* F64i-style const */
3389 struct {
3390 ULong f64i;
3391 } Cf64i;
florian99dd03e2013-01-29 03:56:06 +00003392 /* ITE(tmp,tmp,tmp) */
sewardj9b0cc582006-02-04 15:24:00 +00003393 struct {
3394 IRTemp co;
florianb05c20c2013-01-31 02:04:02 +00003395 IRTemp e1;
sewardj9b0cc582006-02-04 15:24:00 +00003396 IRTemp e0;
florianb05c20c2013-01-31 02:04:02 +00003397 } Ittt;
florian99dd03e2013-01-29 03:56:06 +00003398 /* ITE(tmp,tmp,const) */
florianda25edd2012-09-12 16:40:54 +00003399 struct {
3400 IRTemp co;
florianb05c20c2013-01-31 02:04:02 +00003401 IRTemp e1;
florianda25edd2012-09-12 16:40:54 +00003402 IRConst con0;
florianb05c20c2013-01-31 02:04:02 +00003403 } Ittc;
florian99dd03e2013-01-29 03:56:06 +00003404 /* ITE(tmp,const,tmp) */
florianda25edd2012-09-12 16:40:54 +00003405 struct {
3406 IRTemp co;
florianb05c20c2013-01-31 02:04:02 +00003407 IRConst con1;
florianda25edd2012-09-12 16:40:54 +00003408 IRTemp e0;
florianb05c20c2013-01-31 02:04:02 +00003409 } Itct;
florian99dd03e2013-01-29 03:56:06 +00003410 /* ITE(tmp,const,const) */
florianda25edd2012-09-12 16:40:54 +00003411 struct {
3412 IRTemp co;
florianb05c20c2013-01-31 02:04:02 +00003413 IRConst con1;
florianda25edd2012-09-12 16:40:54 +00003414 IRConst con0;
florianb05c20c2013-01-31 02:04:02 +00003415 } Itcc;
sewardj9b0cc582006-02-04 15:24:00 +00003416 /* GetI(descr,tmp,bias)*/
3417 struct {
sewardjdd40fdf2006-12-24 02:20:24 +00003418 IRRegArray* descr;
3419 IRTemp ix;
3420 Int bias;
sewardj9b0cc582006-02-04 15:24:00 +00003421 } GetIt;
sewardje8578042012-04-13 11:42:50 +00003422 /* Clean helper call */
3423 struct {
3424 IRCallee* cee;
3425 TmpOrConst* args;
3426 Int nArgs;
3427 IRType retty;
3428 } CCall;
sewardj08210532004-12-29 17:09:11 +00003429 } u;
3430 }
3431 AvailExpr;
3432
3433static Bool eq_AvailExpr ( AvailExpr* a1, AvailExpr* a2 )
3434{
sewardje8578042012-04-13 11:42:50 +00003435 if (LIKELY(a1->tag != a2->tag))
sewardj08210532004-12-29 17:09:11 +00003436 return False;
3437 switch (a1->tag) {
3438 case Ut:
sewardj9d2e7692005-02-07 01:11:31 +00003439 return toBool(
3440 a1->u.Ut.op == a2->u.Ut.op
3441 && a1->u.Ut.arg == a2->u.Ut.arg);
sewardj08210532004-12-29 17:09:11 +00003442 case Btt:
sewardj9d2e7692005-02-07 01:11:31 +00003443 return toBool(
3444 a1->u.Btt.op == a2->u.Btt.op
sewardj08210532004-12-29 17:09:11 +00003445 && a1->u.Btt.arg1 == a2->u.Btt.arg1
sewardj9d2e7692005-02-07 01:11:31 +00003446 && a1->u.Btt.arg2 == a2->u.Btt.arg2);
sewardj08210532004-12-29 17:09:11 +00003447 case Btc:
sewardj9d2e7692005-02-07 01:11:31 +00003448 return toBool(
3449 a1->u.Btc.op == a2->u.Btc.op
sewardj08210532004-12-29 17:09:11 +00003450 && a1->u.Btc.arg1 == a2->u.Btc.arg1
sewardj9d2e7692005-02-07 01:11:31 +00003451 && eqIRConst(&a1->u.Btc.con2, &a2->u.Btc.con2));
sewardj08210532004-12-29 17:09:11 +00003452 case Bct:
sewardj9d2e7692005-02-07 01:11:31 +00003453 return toBool(
3454 a1->u.Bct.op == a2->u.Bct.op
sewardj08210532004-12-29 17:09:11 +00003455 && a1->u.Bct.arg2 == a2->u.Bct.arg2
sewardj9d2e7692005-02-07 01:11:31 +00003456 && eqIRConst(&a1->u.Bct.con1, &a2->u.Bct.con1));
sewardj08210532004-12-29 17:09:11 +00003457 case Cf64i:
sewardj9d2e7692005-02-07 01:11:31 +00003458 return toBool(a1->u.Cf64i.f64i == a2->u.Cf64i.f64i);
florianb05c20c2013-01-31 02:04:02 +00003459 case Ittt:
3460 return toBool(a1->u.Ittt.co == a2->u.Ittt.co
3461 && a1->u.Ittt.e1 == a2->u.Ittt.e1
3462 && a1->u.Ittt.e0 == a2->u.Ittt.e0);
3463 case Ittc:
3464 return toBool(a1->u.Ittc.co == a2->u.Ittc.co
3465 && a1->u.Ittc.e1 == a2->u.Ittc.e1
3466 && eqIRConst(&a1->u.Ittc.con0, &a2->u.Ittc.con0));
3467 case Itct:
3468 return toBool(a1->u.Itct.co == a2->u.Itct.co
3469 && eqIRConst(&a1->u.Itct.con1, &a2->u.Itct.con1)
3470 && a1->u.Itct.e0 == a2->u.Itct.e0);
3471 case Itcc:
3472 return toBool(a1->u.Itcc.co == a2->u.Itcc.co
3473 && eqIRConst(&a1->u.Itcc.con1, &a2->u.Itcc.con1)
3474 && eqIRConst(&a1->u.Itcc.con0, &a2->u.Itcc.con0));
sewardj9b0cc582006-02-04 15:24:00 +00003475 case GetIt:
sewardjdd40fdf2006-12-24 02:20:24 +00003476 return toBool(eqIRRegArray(a1->u.GetIt.descr, a2->u.GetIt.descr)
sewardj9b0cc582006-02-04 15:24:00 +00003477 && a1->u.GetIt.ix == a2->u.GetIt.ix
3478 && a1->u.GetIt.bias == a2->u.GetIt.bias);
sewardje8578042012-04-13 11:42:50 +00003479 case CCall: {
3480 Int i, n;
3481 Bool eq = a1->u.CCall.nArgs == a2->u.CCall.nArgs
3482 && eqIRCallee(a1->u.CCall.cee, a2->u.CCall.cee);
3483 if (eq) {
3484 n = a1->u.CCall.nArgs;
3485 for (i = 0; i < n; i++) {
3486 if (!eqTmpOrConst( &a1->u.CCall.args[i],
3487 &a2->u.CCall.args[i] )) {
3488 eq = False;
3489 break;
3490 }
3491 }
3492 }
3493 if (eq) vassert(a1->u.CCall.retty == a2->u.CCall.retty);
3494 return eq;
3495 }
sewardj08210532004-12-29 17:09:11 +00003496 default: vpanic("eq_AvailExpr");
3497 }
3498}
3499
3500static IRExpr* availExpr_to_IRExpr ( AvailExpr* ae )
3501{
florianb05c20c2013-01-31 02:04:02 +00003502 IRConst *con, *con0, *con1;
sewardj08210532004-12-29 17:09:11 +00003503 switch (ae->tag) {
3504 case Ut:
sewardjdd40fdf2006-12-24 02:20:24 +00003505 return IRExpr_Unop( ae->u.Ut.op, IRExpr_RdTmp(ae->u.Ut.arg) );
sewardj08210532004-12-29 17:09:11 +00003506 case Btt:
3507 return IRExpr_Binop( ae->u.Btt.op,
sewardjdd40fdf2006-12-24 02:20:24 +00003508 IRExpr_RdTmp(ae->u.Btt.arg1),
3509 IRExpr_RdTmp(ae->u.Btt.arg2) );
sewardj08210532004-12-29 17:09:11 +00003510 case Btc:
3511 con = LibVEX_Alloc(sizeof(IRConst));
3512 *con = ae->u.Btc.con2;
3513 return IRExpr_Binop( ae->u.Btc.op,
sewardjdd40fdf2006-12-24 02:20:24 +00003514 IRExpr_RdTmp(ae->u.Btc.arg1),
3515 IRExpr_Const(con) );
sewardj08210532004-12-29 17:09:11 +00003516 case Bct:
3517 con = LibVEX_Alloc(sizeof(IRConst));
3518 *con = ae->u.Bct.con1;
3519 return IRExpr_Binop( ae->u.Bct.op,
sewardjdd40fdf2006-12-24 02:20:24 +00003520 IRExpr_Const(con),
3521 IRExpr_RdTmp(ae->u.Bct.arg2) );
sewardj08210532004-12-29 17:09:11 +00003522 case Cf64i:
3523 return IRExpr_Const(IRConst_F64i(ae->u.Cf64i.f64i));
florianb05c20c2013-01-31 02:04:02 +00003524 case Ittt:
3525 return IRExpr_ITE(IRExpr_RdTmp(ae->u.Ittt.co),
3526 IRExpr_RdTmp(ae->u.Ittt.e1),
3527 IRExpr_RdTmp(ae->u.Ittt.e0));
3528 case Ittc:
florianda25edd2012-09-12 16:40:54 +00003529 con0 = LibVEX_Alloc(sizeof(IRConst));
florianb05c20c2013-01-31 02:04:02 +00003530 *con0 = ae->u.Ittc.con0;
3531 return IRExpr_ITE(IRExpr_RdTmp(ae->u.Ittc.co),
3532 IRExpr_RdTmp(ae->u.Ittc.e1),
florian99dd03e2013-01-29 03:56:06 +00003533 IRExpr_Const(con0));
florianb05c20c2013-01-31 02:04:02 +00003534 case Itct:
3535 con1 = LibVEX_Alloc(sizeof(IRConst));
3536 *con1 = ae->u.Itct.con1;
3537 return IRExpr_ITE(IRExpr_RdTmp(ae->u.Itct.co),
3538 IRExpr_Const(con1),
3539 IRExpr_RdTmp(ae->u.Itct.e0));
florian99dd03e2013-01-29 03:56:06 +00003540
florianb05c20c2013-01-31 02:04:02 +00003541 case Itcc:
florianda25edd2012-09-12 16:40:54 +00003542 con0 = LibVEX_Alloc(sizeof(IRConst));
florianb05c20c2013-01-31 02:04:02 +00003543 con1 = LibVEX_Alloc(sizeof(IRConst));
3544 *con0 = ae->u.Itcc.con0;
3545 *con1 = ae->u.Itcc.con1;
3546 return IRExpr_ITE(IRExpr_RdTmp(ae->u.Itcc.co),
3547 IRExpr_Const(con1),
florian99dd03e2013-01-29 03:56:06 +00003548 IRExpr_Const(con0));
sewardj9b0cc582006-02-04 15:24:00 +00003549 case GetIt:
3550 return IRExpr_GetI(ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003551 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00003552 ae->u.GetIt.bias);
sewardje8578042012-04-13 11:42:50 +00003553 case CCall: {
3554 Int i, n = ae->u.CCall.nArgs;
3555 vassert(n >= 0);
3556 IRExpr** vec = LibVEX_Alloc((n+1) * sizeof(IRExpr*));
3557 vec[n] = NULL;
3558 for (i = 0; i < n; i++) {
3559 TmpOrConst* tc = &ae->u.CCall.args[i];
3560 if (tc->tag == TCc) {
3561 vec[i] = IRExpr_Const(tc->u.con);
3562 }
3563 else if (tc->tag == TCt) {
3564 vec[i] = IRExpr_RdTmp(tc->u.tmp);
3565 }
3566 else vpanic("availExpr_to_IRExpr:CCall-arg");
3567 }
3568 return IRExpr_CCall(ae->u.CCall.cee,
3569 ae->u.CCall.retty,
3570 vec);
3571 }
sewardj08210532004-12-29 17:09:11 +00003572 default:
3573 vpanic("availExpr_to_IRExpr");
3574 }
3575}
3576
3577inline
3578static IRTemp subst_AvailExpr_Temp ( HashHW* env, IRTemp tmp )
3579{
3580 HWord res;
3581 /* env :: IRTemp -> IRTemp */
3582 if (lookupHHW( env, &res, (HWord)tmp ))
3583 return (IRTemp)res;
3584 else
3585 return tmp;
3586}
3587
3588static void subst_AvailExpr ( HashHW* env, AvailExpr* ae )
3589{
3590 /* env :: IRTemp -> IRTemp */
3591 switch (ae->tag) {
3592 case Ut:
3593 ae->u.Ut.arg = subst_AvailExpr_Temp( env, ae->u.Ut.arg );
3594 break;
3595 case Btt:
3596 ae->u.Btt.arg1 = subst_AvailExpr_Temp( env, ae->u.Btt.arg1 );
3597 ae->u.Btt.arg2 = subst_AvailExpr_Temp( env, ae->u.Btt.arg2 );
3598 break;
3599 case Btc:
3600 ae->u.Btc.arg1 = subst_AvailExpr_Temp( env, ae->u.Btc.arg1 );
3601 break;
3602 case Bct:
3603 ae->u.Bct.arg2 = subst_AvailExpr_Temp( env, ae->u.Bct.arg2 );
3604 break;
3605 case Cf64i:
3606 break;
florianb05c20c2013-01-31 02:04:02 +00003607 case Ittt:
3608 ae->u.Ittt.co = subst_AvailExpr_Temp( env, ae->u.Ittt.co );
3609 ae->u.Ittt.e1 = subst_AvailExpr_Temp( env, ae->u.Ittt.e1 );
3610 ae->u.Ittt.e0 = subst_AvailExpr_Temp( env, ae->u.Ittt.e0 );
sewardj9b0cc582006-02-04 15:24:00 +00003611 break;
florianb05c20c2013-01-31 02:04:02 +00003612 case Ittc:
3613 ae->u.Ittc.co = subst_AvailExpr_Temp( env, ae->u.Ittc.co );
3614 ae->u.Ittc.e1 = subst_AvailExpr_Temp( env, ae->u.Ittc.e1 );
florianda25edd2012-09-12 16:40:54 +00003615 break;
florianb05c20c2013-01-31 02:04:02 +00003616 case Itct:
3617 ae->u.Itct.co = subst_AvailExpr_Temp( env, ae->u.Itct.co );
3618 ae->u.Itct.e0 = subst_AvailExpr_Temp( env, ae->u.Itct.e0 );
florianda25edd2012-09-12 16:40:54 +00003619 break;
florianb05c20c2013-01-31 02:04:02 +00003620 case Itcc:
3621 ae->u.Itcc.co = subst_AvailExpr_Temp( env, ae->u.Itcc.co );
florianda25edd2012-09-12 16:40:54 +00003622 break;
sewardj9b0cc582006-02-04 15:24:00 +00003623 case GetIt:
3624 ae->u.GetIt.ix = subst_AvailExpr_Temp( env, ae->u.GetIt.ix );
3625 break;
sewardje8578042012-04-13 11:42:50 +00003626 case CCall: {
3627 Int i, n = ae->u.CCall.nArgs;;
3628 for (i = 0; i < n; i++) {
3629 TmpOrConst* tc = &ae->u.CCall.args[i];
3630 if (tc->tag == TCt) {
3631 tc->u.tmp = subst_AvailExpr_Temp( env, tc->u.tmp );
3632 }
3633 }
3634 break;
3635 }
sewardj08210532004-12-29 17:09:11 +00003636 default:
3637 vpanic("subst_AvailExpr");
3638 }
3639}
3640
3641static AvailExpr* irExpr_to_AvailExpr ( IRExpr* e )
3642{
3643 AvailExpr* ae;
3644
florianc1b9e392012-09-20 02:40:57 +00003645 switch (e->tag) {
3646 case Iex_Unop:
3647 if (e->Iex.Unop.arg->tag == Iex_RdTmp) {
3648 ae = LibVEX_Alloc(sizeof(AvailExpr));
3649 ae->tag = Ut;
3650 ae->u.Ut.op = e->Iex.Unop.op;
3651 ae->u.Ut.arg = e->Iex.Unop.arg->Iex.RdTmp.tmp;
3652 return ae;
3653 }
3654 break;
sewardj08210532004-12-29 17:09:11 +00003655
florianc1b9e392012-09-20 02:40:57 +00003656 case Iex_Binop:
3657 if (e->Iex.Binop.arg1->tag == Iex_RdTmp) {
3658 if (e->Iex.Binop.arg2->tag == Iex_RdTmp) {
3659 ae = LibVEX_Alloc(sizeof(AvailExpr));
3660 ae->tag = Btt;
3661 ae->u.Btt.op = e->Iex.Binop.op;
3662 ae->u.Btt.arg1 = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
3663 ae->u.Btt.arg2 = e->Iex.Binop.arg2->Iex.RdTmp.tmp;
3664 return ae;
3665 }
3666 if (e->Iex.Binop.arg2->tag == Iex_Const) {
3667 ae = LibVEX_Alloc(sizeof(AvailExpr));
3668 ae->tag = Btc;
3669 ae->u.Btc.op = e->Iex.Binop.op;
3670 ae->u.Btc.arg1 = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
3671 ae->u.Btc.con2 = *(e->Iex.Binop.arg2->Iex.Const.con);
3672 return ae;
3673 }
3674 } else if (e->Iex.Binop.arg1->tag == Iex_Const
3675 && e->Iex.Binop.arg2->tag == Iex_RdTmp) {
3676 ae = LibVEX_Alloc(sizeof(AvailExpr));
3677 ae->tag = Bct;
3678 ae->u.Bct.op = e->Iex.Binop.op;
3679 ae->u.Bct.arg2 = e->Iex.Binop.arg2->Iex.RdTmp.tmp;
3680 ae->u.Bct.con1 = *(e->Iex.Binop.arg1->Iex.Const.con);
3681 return ae;
3682 }
3683 break;
sewardj08210532004-12-29 17:09:11 +00003684
florianc1b9e392012-09-20 02:40:57 +00003685 case Iex_Const:
3686 if (e->Iex.Const.con->tag == Ico_F64i) {
3687 ae = LibVEX_Alloc(sizeof(AvailExpr));
3688 ae->tag = Cf64i;
3689 ae->u.Cf64i.f64i = e->Iex.Const.con->Ico.F64i;
3690 return ae;
3691 }
3692 break;
sewardj08210532004-12-29 17:09:11 +00003693
florian99dd03e2013-01-29 03:56:06 +00003694 case Iex_ITE:
3695 if (e->Iex.ITE.cond->tag == Iex_RdTmp) {
3696 if (e->Iex.ITE.iffalse->tag == Iex_RdTmp) {
3697 if (e->Iex.ITE.iftrue->tag == Iex_RdTmp) {
florianc1b9e392012-09-20 02:40:57 +00003698 ae = LibVEX_Alloc(sizeof(AvailExpr));
florianb05c20c2013-01-31 02:04:02 +00003699 ae->tag = Ittt;
3700 ae->u.Ittt.co = e->Iex.ITE.cond->Iex.RdTmp.tmp;
3701 ae->u.Ittt.e1 = e->Iex.ITE.iftrue->Iex.RdTmp.tmp;
3702 ae->u.Ittt.e0 = e->Iex.ITE.iffalse->Iex.RdTmp.tmp;
florianc1b9e392012-09-20 02:40:57 +00003703 return ae;
3704 }
florian99dd03e2013-01-29 03:56:06 +00003705 if (e->Iex.ITE.iftrue->tag == Iex_Const) {
florianc1b9e392012-09-20 02:40:57 +00003706 ae = LibVEX_Alloc(sizeof(AvailExpr));
florianb05c20c2013-01-31 02:04:02 +00003707 ae->tag = Itct;
3708 ae->u.Itct.co = e->Iex.ITE.cond->Iex.RdTmp.tmp;
3709 ae->u.Itct.con1 = *(e->Iex.ITE.iftrue->Iex.Const.con);
3710 ae->u.Itct.e0 = e->Iex.ITE.iffalse->Iex.RdTmp.tmp;
florianc1b9e392012-09-20 02:40:57 +00003711 return ae;
3712 }
florian99dd03e2013-01-29 03:56:06 +00003713 } else if (e->Iex.ITE.iffalse->tag == Iex_Const) {
3714 if (e->Iex.ITE.iftrue->tag == Iex_RdTmp) {
florianc1b9e392012-09-20 02:40:57 +00003715 ae = LibVEX_Alloc(sizeof(AvailExpr));
florianb05c20c2013-01-31 02:04:02 +00003716 ae->tag = Ittc;
3717 ae->u.Ittc.co = e->Iex.ITE.cond->Iex.RdTmp.tmp;
3718 ae->u.Ittc.e1 = e->Iex.ITE.iftrue->Iex.RdTmp.tmp;
3719 ae->u.Ittc.con0 = *(e->Iex.ITE.iffalse->Iex.Const.con);
florianc1b9e392012-09-20 02:40:57 +00003720 return ae;
3721 }
florian99dd03e2013-01-29 03:56:06 +00003722 if (e->Iex.ITE.iftrue->tag == Iex_Const) {
florianc1b9e392012-09-20 02:40:57 +00003723 ae = LibVEX_Alloc(sizeof(AvailExpr));
florianb05c20c2013-01-31 02:04:02 +00003724 ae->tag = Itcc;
3725 ae->u.Itcc.co = e->Iex.ITE.cond->Iex.RdTmp.tmp;
3726 ae->u.Itcc.con1 = *(e->Iex.ITE.iftrue->Iex.Const.con);
3727 ae->u.Itcc.con0 = *(e->Iex.ITE.iffalse->Iex.Const.con);
florianc1b9e392012-09-20 02:40:57 +00003728 return ae;
3729 }
3730 }
3731 }
3732 break;
sewardj08210532004-12-29 17:09:11 +00003733
florianc1b9e392012-09-20 02:40:57 +00003734 case Iex_GetI:
3735 if (e->Iex.GetI.ix->tag == Iex_RdTmp) {
3736 ae = LibVEX_Alloc(sizeof(AvailExpr));
3737 ae->tag = GetIt;
3738 ae->u.GetIt.descr = e->Iex.GetI.descr;
3739 ae->u.GetIt.ix = e->Iex.GetI.ix->Iex.RdTmp.tmp;
3740 ae->u.GetIt.bias = e->Iex.GetI.bias;
3741 return ae;
3742 }
3743 break;
sewardj08210532004-12-29 17:09:11 +00003744
florianc1b9e392012-09-20 02:40:57 +00003745 case Iex_CCall:
3746 ae = LibVEX_Alloc(sizeof(AvailExpr));
3747 ae->tag = CCall;
3748 /* Ok to share only the cee, since it is immutable. */
3749 ae->u.CCall.cee = e->Iex.CCall.cee;
3750 ae->u.CCall.retty = e->Iex.CCall.retty;
3751 /* irExprVec_to_TmpOrConsts will assert if the args are
3752 neither tmps nor constants, but that's ok .. that's all they
3753 should be. */
3754 irExprVec_to_TmpOrConsts(
3755 &ae->u.CCall.args, &ae->u.CCall.nArgs,
3756 e->Iex.CCall.args
3757 );
3758 return ae;
sewardj9b0cc582006-02-04 15:24:00 +00003759
florianc1b9e392012-09-20 02:40:57 +00003760 default:
3761 break;
sewardje8578042012-04-13 11:42:50 +00003762 }
3763
sewardj08210532004-12-29 17:09:11 +00003764 return NULL;
3765}
3766
3767
sewardj9b0cc582006-02-04 15:24:00 +00003768/* The BB is modified in-place. Returns True if any changes were
3769 made. */
sewardj08210532004-12-29 17:09:11 +00003770
sewardjdd40fdf2006-12-24 02:20:24 +00003771static Bool do_cse_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00003772{
sewardj9b0cc582006-02-04 15:24:00 +00003773 Int i, j, paranoia;
sewardj08210532004-12-29 17:09:11 +00003774 IRTemp t, q;
3775 IRStmt* st;
3776 AvailExpr* eprime;
sewardj9b0cc582006-02-04 15:24:00 +00003777 AvailExpr* ae;
3778 Bool invalidate;
3779 Bool anyDone = False;
sewardj08210532004-12-29 17:09:11 +00003780
3781 HashHW* tenv = newHHW(); /* :: IRTemp -> IRTemp */
3782 HashHW* aenv = newHHW(); /* :: AvailExpr* -> IRTemp */
3783
3784 vassert(sizeof(IRTemp) <= sizeof(HWord));
3785
sewardjdd40fdf2006-12-24 02:20:24 +00003786 if (0) { ppIRSB(bb); vex_printf("\n\n"); }
sewardj08210532004-12-29 17:09:11 +00003787
3788 /* Iterate forwards over the stmts.
sewardjcfe046e2013-01-17 14:23:53 +00003789 On seeing "t = E", where E is one of the AvailExpr forms:
sewardj08210532004-12-29 17:09:11 +00003790 let E' = apply tenv substitution to E
3791 search aenv for E'
3792 if a mapping E' -> q is found,
3793 replace this stmt by "t = q"
3794 and add binding t -> q to tenv
3795 else
3796 add binding E' -> t to aenv
3797 replace this stmt by "t = E'"
sewardj9b0cc582006-02-04 15:24:00 +00003798
3799 Other statements are only interesting to the extent that they
3800 might invalidate some of the expressions in aenv. So there is
3801 an invalidate-bindings check for each statement seen.
sewardj08210532004-12-29 17:09:11 +00003802 */
3803 for (i = 0; i < bb->stmts_used; i++) {
3804 st = bb->stmts[i];
3805
sewardj9b0cc582006-02-04 15:24:00 +00003806 /* ------ BEGIN invalidate aenv bindings ------ */
3807 /* This is critical: remove from aenv any E' -> .. bindings
3808 which might be invalidated by this statement. The only
sewardjc4356f02007-11-09 21:15:04 +00003809 vulnerable kind of bindings are the GetI kind.
sewardj9b0cc582006-02-04 15:24:00 +00003810 Dirty call - dump (paranoia level -> 2)
3811 Store - dump (ditto)
3812 Put, PutI - dump unless no-overlap is proven (.. -> 1)
3813 Uses getAliasingRelation_IC and getAliasingRelation_II
3814 to do the no-overlap assessments needed for Put/PutI.
3815 */
3816 switch (st->tag) {
sewardje768e922009-11-26 17:17:37 +00003817 case Ist_Dirty: case Ist_Store: case Ist_MBE:
3818 case Ist_CAS: case Ist_LLSC:
sewardjcfe046e2013-01-17 14:23:53 +00003819 case Ist_StoreG:
sewardj9b0cc582006-02-04 15:24:00 +00003820 paranoia = 2; break;
3821 case Ist_Put: case Ist_PutI:
3822 paranoia = 1; break;
3823 case Ist_NoOp: case Ist_IMark: case Ist_AbiHint:
sewardjcfe046e2013-01-17 14:23:53 +00003824 case Ist_WrTmp: case Ist_Exit: case Ist_LoadG:
sewardj9b0cc582006-02-04 15:24:00 +00003825 paranoia = 0; break;
3826 default:
3827 vpanic("do_cse_BB(1)");
3828 }
3829
3830 if (paranoia > 0) {
3831 for (j = 0; j < aenv->used; j++) {
3832 if (!aenv->inuse[j])
3833 continue;
3834 ae = (AvailExpr*)aenv->key[j];
3835 if (ae->tag != GetIt)
3836 continue;
3837 invalidate = False;
3838 if (paranoia >= 2) {
3839 invalidate = True;
3840 } else {
3841 vassert(paranoia == 1);
3842 if (st->tag == Ist_Put) {
3843 if (getAliasingRelation_IC(
3844 ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003845 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00003846 st->Ist.Put.offset,
3847 typeOfIRExpr(bb->tyenv,st->Ist.Put.data)
3848 ) != NoAlias)
3849 invalidate = True;
3850 }
3851 else
3852 if (st->tag == Ist_PutI) {
floriand6f38b32012-05-31 15:46:18 +00003853 IRPutI *puti = st->Ist.PutI.details;
sewardj9b0cc582006-02-04 15:24:00 +00003854 if (getAliasingRelation_II(
3855 ae->u.GetIt.descr,
sewardjdd40fdf2006-12-24 02:20:24 +00003856 IRExpr_RdTmp(ae->u.GetIt.ix),
sewardj9b0cc582006-02-04 15:24:00 +00003857 ae->u.GetIt.bias,
floriand6f38b32012-05-31 15:46:18 +00003858 puti->descr,
3859 puti->ix,
3860 puti->bias
sewardj9b0cc582006-02-04 15:24:00 +00003861 ) != NoAlias)
3862 invalidate = True;
3863 }
3864 else
3865 vpanic("do_cse_BB(2)");
3866 }
3867
3868 if (invalidate) {
3869 aenv->inuse[j] = False;
3870 aenv->key[j] = (HWord)NULL; /* be sure */
3871 }
3872 } /* for j */
3873 } /* paranoia > 0 */
3874
3875 /* ------ ENV invalidate aenv bindings ------ */
3876
sewardj08210532004-12-29 17:09:11 +00003877 /* ignore not-interestings */
sewardjdd40fdf2006-12-24 02:20:24 +00003878 if (st->tag != Ist_WrTmp)
sewardj08210532004-12-29 17:09:11 +00003879 continue;
3880
sewardjdd40fdf2006-12-24 02:20:24 +00003881 t = st->Ist.WrTmp.tmp;
3882 eprime = irExpr_to_AvailExpr(st->Ist.WrTmp.data);
sewardj08210532004-12-29 17:09:11 +00003883 /* ignore if not of AvailExpr form */
3884 if (!eprime)
3885 continue;
3886
3887 /* vex_printf("considering: " ); ppIRStmt(st); vex_printf("\n"); */
3888
3889 /* apply tenv */
3890 subst_AvailExpr( tenv, eprime );
3891
3892 /* search aenv for eprime, unfortunately the hard way */
3893 for (j = 0; j < aenv->used; j++)
3894 if (aenv->inuse[j] && eq_AvailExpr(eprime, (AvailExpr*)aenv->key[j]))
3895 break;
3896
3897 if (j < aenv->used) {
3898 /* A binding E' -> q was found. Replace stmt by "t = q" and
3899 note the t->q binding in tenv. */
3900 /* (this is the core of the CSE action) */
3901 q = (IRTemp)aenv->val[j];
sewardjdd40fdf2006-12-24 02:20:24 +00003902 bb->stmts[i] = IRStmt_WrTmp( t, IRExpr_RdTmp(q) );
sewardj08210532004-12-29 17:09:11 +00003903 addToHHW( tenv, (HWord)t, (HWord)q );
sewardj9b0cc582006-02-04 15:24:00 +00003904 anyDone = True;
sewardj08210532004-12-29 17:09:11 +00003905 } else {
3906 /* No binding was found, so instead we add E' -> t to our
3907 collection of available expressions, replace this stmt
3908 with "t = E'", and move on. */
sewardjdd40fdf2006-12-24 02:20:24 +00003909 bb->stmts[i] = IRStmt_WrTmp( t, availExpr_to_IRExpr(eprime) );
sewardj08210532004-12-29 17:09:11 +00003910 addToHHW( aenv, (HWord)eprime, (HWord)t );
3911 }
3912 }
3913
sewardjb183b852006-02-03 16:08:03 +00003914 /*
sewardjdd40fdf2006-12-24 02:20:24 +00003915 ppIRSB(bb);
3916 sanityCheckIRSB(bb, Ity_I32);
sewardjb183b852006-02-03 16:08:03 +00003917 vex_printf("\n\n");
3918 */
sewardj9b0cc582006-02-04 15:24:00 +00003919 return anyDone;
sewardj08210532004-12-29 17:09:11 +00003920}
3921
3922
3923/*---------------------------------------------------------------*/
3924/*--- Add32/Sub32 chain collapsing ---*/
3925/*---------------------------------------------------------------*/
3926
3927/* ----- Helper functions for Add32/Sub32 chain collapsing ----- */
3928
3929/* Is this expression "Add32(tmp,const)" or "Sub32(tmp,const)" ? If
3930 yes, set *tmp and *i32 appropriately. *i32 is set as if the
3931 root node is Add32, not Sub32. */
3932
3933static Bool isAdd32OrSub32 ( IRExpr* e, IRTemp* tmp, Int* i32 )
3934{
3935 if (e->tag != Iex_Binop)
3936 return False;
3937 if (e->Iex.Binop.op != Iop_Add32 && e->Iex.Binop.op != Iop_Sub32)
3938 return False;
sewardjdd40fdf2006-12-24 02:20:24 +00003939 if (e->Iex.Binop.arg1->tag != Iex_RdTmp)
sewardj08210532004-12-29 17:09:11 +00003940 return False;
3941 if (e->Iex.Binop.arg2->tag != Iex_Const)
3942 return False;
sewardjdd40fdf2006-12-24 02:20:24 +00003943 *tmp = e->Iex.Binop.arg1->Iex.RdTmp.tmp;
sewardj08210532004-12-29 17:09:11 +00003944 *i32 = (Int)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32);
3945 if (e->Iex.Binop.op == Iop_Sub32)
3946 *i32 = -*i32;
3947 return True;
3948}
3949
3950
3951/* Figure out if tmp can be expressed as tmp2 +32 const, for some
3952 other tmp2. Scan backwards from the specified start point -- an
3953 optimisation. */
3954
sewardjdd40fdf2006-12-24 02:20:24 +00003955static Bool collapseChain ( IRSB* bb, Int startHere,
sewardj08210532004-12-29 17:09:11 +00003956 IRTemp tmp,
3957 IRTemp* tmp2, Int* i32 )
3958{
3959 Int j, ii;
3960 IRTemp vv;
3961 IRStmt* st;
3962 IRExpr* e;
3963
3964 /* the (var, con) pair contain the current 'representation' for
3965 'tmp'. We start with 'tmp + 0'. */
3966 IRTemp var = tmp;
3967 Int con = 0;
3968
3969 /* Scan backwards to see if tmp can be replaced by some other tmp
3970 +/- a constant. */
3971 for (j = startHere; j >= 0; j--) {
3972 st = bb->stmts[j];
sewardjdd40fdf2006-12-24 02:20:24 +00003973 if (st->tag != Ist_WrTmp)
sewardj08210532004-12-29 17:09:11 +00003974 continue;
sewardjdd40fdf2006-12-24 02:20:24 +00003975 if (st->Ist.WrTmp.tmp != var)
sewardj08210532004-12-29 17:09:11 +00003976 continue;
sewardjdd40fdf2006-12-24 02:20:24 +00003977 e = st->Ist.WrTmp.data;
sewardj08210532004-12-29 17:09:11 +00003978 if (!isAdd32OrSub32(e, &vv, &ii))
3979 break;
3980 var = vv;
3981 con += ii;
3982 }
3983 if (j == -1)
3984 /* no earlier binding for var .. ill-formed IR */
3985 vpanic("collapseChain");
3986
3987 /* so, did we find anything interesting? */
3988 if (var == tmp)
3989 return False; /* no .. */
3990
3991 *tmp2 = var;
3992 *i32 = con;
3993 return True;
3994}
3995
3996
3997/* ------- Main function for Add32/Sub32 chain collapsing ------ */
3998
sewardjdd40fdf2006-12-24 02:20:24 +00003999static void collapse_AddSub_chains_BB ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00004000{
4001 IRStmt *st;
4002 IRTemp var, var2;
4003 Int i, con, con2;
4004
4005 for (i = bb->stmts_used-1; i >= 0; i--) {
4006 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00004007 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00004008 continue;
4009
4010 /* Try to collapse 't1 = Add32/Sub32(t2, con)'. */
4011
sewardjdd40fdf2006-12-24 02:20:24 +00004012 if (st->tag == Ist_WrTmp
4013 && isAdd32OrSub32(st->Ist.WrTmp.data, &var, &con)) {
sewardj08210532004-12-29 17:09:11 +00004014
4015 /* So e1 is of the form Add32(var,con) or Sub32(var,-con).
4016 Find out if var can be expressed as var2 + con2. */
4017 if (collapseChain(bb, i-1, var, &var2, &con2)) {
4018 if (DEBUG_IROPT) {
4019 vex_printf("replacing1 ");
4020 ppIRStmt(st);
4021 vex_printf(" with ");
4022 }
4023 con2 += con;
4024 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00004025 = IRStmt_WrTmp(
4026 st->Ist.WrTmp.tmp,
sewardj08210532004-12-29 17:09:11 +00004027 (con2 >= 0)
4028 ? IRExpr_Binop(Iop_Add32,
sewardjdd40fdf2006-12-24 02:20:24 +00004029 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00004030 IRExpr_Const(IRConst_U32(con2)))
4031 : IRExpr_Binop(Iop_Sub32,
sewardjdd40fdf2006-12-24 02:20:24 +00004032 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00004033 IRExpr_Const(IRConst_U32(-con2)))
4034 );
4035 if (DEBUG_IROPT) {
4036 ppIRStmt(bb->stmts[i]);
4037 vex_printf("\n");
4038 }
4039 }
4040
4041 continue;
4042 }
4043
4044 /* Try to collapse 't1 = GetI[t2, con]'. */
4045
sewardjdd40fdf2006-12-24 02:20:24 +00004046 if (st->tag == Ist_WrTmp
4047 && st->Ist.WrTmp.data->tag == Iex_GetI
4048 && st->Ist.WrTmp.data->Iex.GetI.ix->tag == Iex_RdTmp
4049 && collapseChain(bb, i-1, st->Ist.WrTmp.data->Iex.GetI.ix
4050 ->Iex.RdTmp.tmp, &var2, &con2)) {
sewardj08210532004-12-29 17:09:11 +00004051 if (DEBUG_IROPT) {
4052 vex_printf("replacing3 ");
4053 ppIRStmt(st);
4054 vex_printf(" with ");
4055 }
sewardjdd40fdf2006-12-24 02:20:24 +00004056 con2 += st->Ist.WrTmp.data->Iex.GetI.bias;
sewardj08210532004-12-29 17:09:11 +00004057 bb->stmts[i]
sewardjdd40fdf2006-12-24 02:20:24 +00004058 = IRStmt_WrTmp(
4059 st->Ist.WrTmp.tmp,
4060 IRExpr_GetI(st->Ist.WrTmp.data->Iex.GetI.descr,
4061 IRExpr_RdTmp(var2),
sewardj08210532004-12-29 17:09:11 +00004062 con2));
4063 if (DEBUG_IROPT) {
4064 ppIRStmt(bb->stmts[i]);
4065 vex_printf("\n");
4066 }
4067 continue;
4068 }
4069
4070 /* Perhaps st is PutI[t, con] ? */
floriand6f38b32012-05-31 15:46:18 +00004071 IRPutI *puti = st->Ist.PutI.details;
sewardj08210532004-12-29 17:09:11 +00004072 if (st->tag == Ist_PutI
floriand6f38b32012-05-31 15:46:18 +00004073 && puti->ix->tag == Iex_RdTmp
4074 && collapseChain(bb, i-1, puti->ix->Iex.RdTmp.tmp,
sewardj08210532004-12-29 17:09:11 +00004075 &var2, &con2)) {
4076 if (DEBUG_IROPT) {
4077 vex_printf("replacing2 ");
4078 ppIRStmt(st);
4079 vex_printf(" with ");
4080 }
floriand6f38b32012-05-31 15:46:18 +00004081 con2 += puti->bias;
sewardj08210532004-12-29 17:09:11 +00004082 bb->stmts[i]
floriand6f38b32012-05-31 15:46:18 +00004083 = IRStmt_PutI(mkIRPutI(puti->descr,
4084 IRExpr_RdTmp(var2),
4085 con2,
4086 puti->data));
sewardj08210532004-12-29 17:09:11 +00004087 if (DEBUG_IROPT) {
4088 ppIRStmt(bb->stmts[i]);
4089 vex_printf("\n");
4090 }
4091 continue;
4092 }
4093
4094 } /* for */
4095}
4096
4097
4098/*---------------------------------------------------------------*/
4099/*--- PutI/GetI transformations ---*/
4100/*---------------------------------------------------------------*/
4101
sewardj08210532004-12-29 17:09:11 +00004102/* Given the parts (descr, tmp, bias) for a GetI, scan backwards from
4103 the given starting point to find, if any, a PutI which writes
4104 exactly the same piece of guest state, and so return the expression
4105 that the PutI writes. This is the core of PutI-GetI forwarding. */
4106
4107static
sewardjdd40fdf2006-12-24 02:20:24 +00004108IRExpr* findPutI ( IRSB* bb, Int startHere,
4109 IRRegArray* descrG, IRExpr* ixG, Int biasG )
sewardj08210532004-12-29 17:09:11 +00004110{
4111 Int j;
4112 IRStmt* st;
4113 GSAliasing relation;
4114
4115 if (0) {
4116 vex_printf("\nfindPutI ");
sewardjdd40fdf2006-12-24 02:20:24 +00004117 ppIRRegArray(descrG);
sewardj08210532004-12-29 17:09:11 +00004118 vex_printf(" ");
4119 ppIRExpr(ixG);
4120 vex_printf(" %d\n", biasG);
4121 }
4122
4123 /* Scan backwards in bb from startHere to find a suitable PutI
4124 binding for (descrG, ixG, biasG), if any. */
4125
4126 for (j = startHere; j >= 0; j--) {
4127 st = bb->stmts[j];
sewardj8bee6d12005-03-22 02:24:05 +00004128 if (st->tag == Ist_NoOp)
4129 continue;
sewardj08210532004-12-29 17:09:11 +00004130
4131 if (st->tag == Ist_Put) {
4132 /* Non-indexed Put. This can't give a binding, but we do
4133 need to check it doesn't invalidate the search by
4134 overlapping any part of the indexed guest state. */
4135
4136 relation
4137 = getAliasingRelation_IC(
4138 descrG, ixG,
4139 st->Ist.Put.offset,
4140 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
4141
4142 if (relation == NoAlias) {
4143 /* we're OK; keep going */
4144 continue;
4145 } else {
4146 /* relation == UnknownAlias || relation == ExactAlias */
4147 /* If this assertion fails, we've found a Put which writes
4148 an area of guest state which is read by a GetI. Which
4149 is unlikely (although not per se wrong). */
4150 vassert(relation != ExactAlias);
4151 /* This Put potentially writes guest state that the GetI
4152 reads; we must fail. */
4153 return NULL;
4154 }
4155 }
4156
4157 if (st->tag == Ist_PutI) {
floriand6f38b32012-05-31 15:46:18 +00004158 IRPutI *puti = st->Ist.PutI.details;
sewardj08210532004-12-29 17:09:11 +00004159
4160 relation = getAliasingRelation_II(
4161 descrG, ixG, biasG,
floriand6f38b32012-05-31 15:46:18 +00004162 puti->descr,
4163 puti->ix,
4164 puti->bias
sewardj08210532004-12-29 17:09:11 +00004165 );
4166
4167 if (relation == NoAlias) {
4168 /* This PutI definitely doesn't overlap. Ignore it and
4169 keep going. */
4170 continue; /* the for j loop */
4171 }
4172
4173 if (relation == UnknownAlias) {
4174 /* We don't know if this PutI writes to the same guest
4175 state that the GetI, or not. So we have to give up. */
4176 return NULL;
4177 }
4178
4179 /* Otherwise, we've found what we're looking for. */
4180 vassert(relation == ExactAlias);
floriand6f38b32012-05-31 15:46:18 +00004181 return puti->data;
sewardj08210532004-12-29 17:09:11 +00004182
4183 } /* if (st->tag == Ist_PutI) */
4184
4185 if (st->tag == Ist_Dirty) {
4186 /* Be conservative. If the dirty call has any guest effects at
4187 all, give up. We could do better -- only give up if there
4188 are any guest writes/modifies. */
4189 if (st->Ist.Dirty.details->nFxState > 0)
4190 return NULL;
4191 }
4192
4193 } /* for */
4194
4195 /* No valid replacement was found. */
4196 return NULL;
4197}
4198
4199
4200
4201/* Assuming pi is a PutI stmt, is s2 identical to it (in the sense
4202 that it writes exactly the same piece of guest state) ? Safe
4203 answer: False. */
4204
4205static Bool identicalPutIs ( IRStmt* pi, IRStmt* s2 )
4206{
4207 vassert(pi->tag == Ist_PutI);
4208 if (s2->tag != Ist_PutI)
4209 return False;
4210
floriand6f38b32012-05-31 15:46:18 +00004211 IRPutI *p1 = pi->Ist.PutI.details;
4212 IRPutI *p2 = s2->Ist.PutI.details;
4213
sewardj9d2e7692005-02-07 01:11:31 +00004214 return toBool(
4215 getAliasingRelation_II(
floriand6f38b32012-05-31 15:46:18 +00004216 p1->descr, p1->ix, p1->bias,
4217 p2->descr, p2->ix, p2->bias
sewardj08210532004-12-29 17:09:11 +00004218 )
sewardj9d2e7692005-02-07 01:11:31 +00004219 == ExactAlias
4220 );
sewardj08210532004-12-29 17:09:11 +00004221}
4222
4223
4224/* Assuming pi is a PutI stmt, is s2 a Get/GetI/Put/PutI which might
4225 overlap it? Safe answer: True. Note, we could do a lot better
4226 than this if needed. */
4227
4228static
4229Bool guestAccessWhichMightOverlapPutI (
4230 IRTypeEnv* tyenv, IRStmt* pi, IRStmt* s2
4231 )
4232{
4233 GSAliasing relation;
4234 UInt minoffP, maxoffP;
4235
4236 vassert(pi->tag == Ist_PutI);
floriand6f38b32012-05-31 15:46:18 +00004237
4238 IRPutI *p1 = pi->Ist.PutI.details;
4239
4240 getArrayBounds(p1->descr, &minoffP, &maxoffP);
sewardj08210532004-12-29 17:09:11 +00004241 switch (s2->tag) {
4242
sewardjd2445f62005-03-21 00:15:53 +00004243 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00004244 case Ist_IMark:
4245 return False;
4246
sewardjc4356f02007-11-09 21:15:04 +00004247 case Ist_MBE:
sewardj5a9ffab2005-05-12 17:55:01 +00004248 case Ist_AbiHint:
4249 /* just be paranoid ... these should be rare. */
sewardjbb3f52d2005-01-07 14:14:50 +00004250 return True;
4251
sewardje9d8a262009-07-01 08:06:34 +00004252 case Ist_CAS:
4253 /* This is unbelievably lame, but it's probably not
4254 significant from a performance point of view. Really, a
4255 CAS is a load-store op, so it should be safe to say False.
4256 However .. */
4257 return True;
4258
sewardj08210532004-12-29 17:09:11 +00004259 case Ist_Dirty:
4260 /* If the dirty call has any guest effects at all, give up.
4261 Probably could do better. */
4262 if (s2->Ist.Dirty.details->nFxState > 0)
4263 return True;
4264 return False;
4265
4266 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00004267 vassert(isIRAtom(s2->Ist.Put.data));
sewardj08210532004-12-29 17:09:11 +00004268 relation
4269 = getAliasingRelation_IC(
floriand6f38b32012-05-31 15:46:18 +00004270 p1->descr, p1->ix,
sewardj08210532004-12-29 17:09:11 +00004271 s2->Ist.Put.offset,
4272 typeOfIRExpr(tyenv,s2->Ist.Put.data)
4273 );
4274 goto have_relation;
4275
floriand6f38b32012-05-31 15:46:18 +00004276 case Ist_PutI: {
4277 IRPutI *p2 = s2->Ist.PutI.details;
4278
4279 vassert(isIRAtom(p2->ix));
4280 vassert(isIRAtom(p2->data));
sewardj08210532004-12-29 17:09:11 +00004281 relation
4282 = getAliasingRelation_II(
floriand6f38b32012-05-31 15:46:18 +00004283 p1->descr, p1->ix, p1->bias,
4284 p2->descr, p2->ix, p2->bias
sewardj08210532004-12-29 17:09:11 +00004285 );
4286 goto have_relation;
floriand6f38b32012-05-31 15:46:18 +00004287 }
sewardj08210532004-12-29 17:09:11 +00004288
sewardjdd40fdf2006-12-24 02:20:24 +00004289 case Ist_WrTmp:
4290 if (s2->Ist.WrTmp.data->tag == Iex_GetI) {
sewardj08210532004-12-29 17:09:11 +00004291 relation
4292 = getAliasingRelation_II(
floriand6f38b32012-05-31 15:46:18 +00004293 p1->descr, p1->ix, p1->bias,
sewardjdd40fdf2006-12-24 02:20:24 +00004294 s2->Ist.WrTmp.data->Iex.GetI.descr,
4295 s2->Ist.WrTmp.data->Iex.GetI.ix,
4296 s2->Ist.WrTmp.data->Iex.GetI.bias
sewardj08210532004-12-29 17:09:11 +00004297 );
4298 goto have_relation;
4299 }
sewardjdd40fdf2006-12-24 02:20:24 +00004300 if (s2->Ist.WrTmp.data->tag == Iex_Get) {
sewardj08210532004-12-29 17:09:11 +00004301 relation
4302 = getAliasingRelation_IC(
floriand6f38b32012-05-31 15:46:18 +00004303 p1->descr, p1->ix,
sewardjdd40fdf2006-12-24 02:20:24 +00004304 s2->Ist.WrTmp.data->Iex.Get.offset,
4305 s2->Ist.WrTmp.data->Iex.Get.ty
sewardj08210532004-12-29 17:09:11 +00004306 );
4307 goto have_relation;
4308 }
4309 return False;
4310
sewardjaf1ceca2005-06-30 23:31:27 +00004311 case Ist_Store:
4312 vassert(isIRAtom(s2->Ist.Store.addr));
4313 vassert(isIRAtom(s2->Ist.Store.data));
sewardj08210532004-12-29 17:09:11 +00004314 return False;
4315
4316 default:
4317 vex_printf("\n"); ppIRStmt(s2); vex_printf("\n");
4318 vpanic("guestAccessWhichMightOverlapPutI");
4319 }
4320
4321 have_relation:
4322 if (relation == NoAlias)
4323 return False;
4324 else
4325 return True; /* ExactAlias or UnknownAlias */
4326}
4327
4328
4329
4330/* ---------- PutI/GetI transformations main functions --------- */
4331
4332/* Remove redundant GetIs, to the extent that they can be detected.
4333 bb is modified in-place. */
4334
4335static
sewardjdd40fdf2006-12-24 02:20:24 +00004336void do_redundant_GetI_elimination ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00004337{
4338 Int i;
4339 IRStmt* st;
4340
4341 for (i = bb->stmts_used-1; i >= 0; i--) {
4342 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00004343 if (st->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00004344 continue;
4345
sewardjdd40fdf2006-12-24 02:20:24 +00004346 if (st->tag == Ist_WrTmp
4347 && st->Ist.WrTmp.data->tag == Iex_GetI
4348 && st->Ist.WrTmp.data->Iex.GetI.ix->tag == Iex_RdTmp) {
4349 IRRegArray* descr = st->Ist.WrTmp.data->Iex.GetI.descr;
4350 IRExpr* ix = st->Ist.WrTmp.data->Iex.GetI.ix;
4351 Int bias = st->Ist.WrTmp.data->Iex.GetI.bias;
4352 IRExpr* replacement = findPutI(bb, i-1, descr, ix, bias);
sewardj08210532004-12-29 17:09:11 +00004353 if (replacement
sewardj496a58d2005-03-20 18:44:44 +00004354 && isIRAtom(replacement)
sewardj08210532004-12-29 17:09:11 +00004355 /* Make sure we're doing a type-safe transformation! */
4356 && typeOfIRExpr(bb->tyenv, replacement) == descr->elemTy) {
4357 if (DEBUG_IROPT) {
4358 vex_printf("rGI: ");
sewardjdd40fdf2006-12-24 02:20:24 +00004359 ppIRExpr(st->Ist.WrTmp.data);
sewardj08210532004-12-29 17:09:11 +00004360 vex_printf(" -> ");
4361 ppIRExpr(replacement);
4362 vex_printf("\n");
4363 }
sewardjdd40fdf2006-12-24 02:20:24 +00004364 bb->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, replacement);
sewardj08210532004-12-29 17:09:11 +00004365 }
4366 }
4367 }
4368
4369}
4370
4371
4372/* Remove redundant PutIs, to the extent which they can be detected.
4373 bb is modified in-place. */
4374
4375static
sewardjdd40fdf2006-12-24 02:20:24 +00004376void do_redundant_PutI_elimination ( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00004377{
4378 Int i, j;
4379 Bool delete;
4380 IRStmt *st, *stj;
4381
philippe6c46bef2012-08-14 22:29:01 +00004382 vassert(vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn);
philippec8e2f982012-08-01 22:04:13 +00004383
sewardj08210532004-12-29 17:09:11 +00004384 for (i = 0; i < bb->stmts_used; i++) {
4385 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00004386 if (st->tag != Ist_PutI)
sewardj08210532004-12-29 17:09:11 +00004387 continue;
4388 /* Ok, search forwards from here to see if we can find another
4389 PutI which makes this one redundant, and dodging various
4390 hazards. Search forwards:
4391 * If conditional exit, give up (because anything after that
4392 does not postdominate this put).
4393 * If a Get which might overlap, give up (because this PutI
4394 not necessarily dead).
4395 * If a Put which is identical, stop with success.
4396 * If a Put which might overlap, but is not identical, give up.
4397 * If a dirty helper call which might write guest state, give up.
4398 * If a Put which definitely doesn't overlap, or any other
4399 kind of stmt, continue.
4400 */
4401 delete = False;
4402 for (j = i+1; j < bb->stmts_used; j++) {
4403 stj = bb->stmts[j];
sewardj8bee6d12005-03-22 02:24:05 +00004404 if (stj->tag == Ist_NoOp)
sewardj08210532004-12-29 17:09:11 +00004405 continue;
4406 if (identicalPutIs(st, stj)) {
4407 /* success! */
4408 delete = True;
4409 break;
4410 }
4411 if (stj->tag == Ist_Exit)
4412 /* give up */
4413 break;
4414 if (st->tag == Ist_Dirty)
4415 /* give up; could do better here */
4416 break;
4417 if (guestAccessWhichMightOverlapPutI(bb->tyenv, st, stj))
4418 /* give up */
4419 break;
4420 }
4421
4422 if (delete) {
4423 if (DEBUG_IROPT) {
4424 vex_printf("rPI: ");
4425 ppIRStmt(st);
4426 vex_printf("\n");
4427 }
sewardjd2445f62005-03-21 00:15:53 +00004428 bb->stmts[i] = IRStmt_NoOp();
sewardj08210532004-12-29 17:09:11 +00004429 }
4430
4431 }
4432}
4433
4434
4435/*---------------------------------------------------------------*/
4436/*--- Loop unrolling ---*/
4437/*---------------------------------------------------------------*/
4438
4439/* Adjust all tmp values (names) in e by delta. e is destructively
4440 modified. */
4441
4442static void deltaIRExpr ( IRExpr* e, Int delta )
4443{
4444 Int i;
4445 switch (e->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +00004446 case Iex_RdTmp:
4447 e->Iex.RdTmp.tmp += delta;
sewardj08210532004-12-29 17:09:11 +00004448 break;
4449 case Iex_Get:
4450 case Iex_Const:
4451 break;
4452 case Iex_GetI:
4453 deltaIRExpr(e->Iex.GetI.ix, delta);
4454 break;
sewardj1a866b42006-02-09 02:54:03 +00004455 case Iex_Qop:
florian96d7cc32012-06-01 20:41:24 +00004456 deltaIRExpr(e->Iex.Qop.details->arg1, delta);
4457 deltaIRExpr(e->Iex.Qop.details->arg2, delta);
4458 deltaIRExpr(e->Iex.Qop.details->arg3, delta);
4459 deltaIRExpr(e->Iex.Qop.details->arg4, delta);
sewardj1a866b42006-02-09 02:54:03 +00004460 break;
sewardjb183b852006-02-03 16:08:03 +00004461 case Iex_Triop:
florian420bfa92012-06-02 20:29:22 +00004462 deltaIRExpr(e->Iex.Triop.details->arg1, delta);
4463 deltaIRExpr(e->Iex.Triop.details->arg2, delta);
4464 deltaIRExpr(e->Iex.Triop.details->arg3, delta);
sewardjb183b852006-02-03 16:08:03 +00004465 break;
sewardj08210532004-12-29 17:09:11 +00004466 case Iex_Binop:
4467 deltaIRExpr(e->Iex.Binop.arg1, delta);
4468 deltaIRExpr(e->Iex.Binop.arg2, delta);
4469 break;
4470 case Iex_Unop:
4471 deltaIRExpr(e->Iex.Unop.arg, delta);
4472 break;
sewardjaf1ceca2005-06-30 23:31:27 +00004473 case Iex_Load:
4474 deltaIRExpr(e->Iex.Load.addr, delta);
sewardj08210532004-12-29 17:09:11 +00004475 break;
4476 case Iex_CCall:
4477 for (i = 0; e->Iex.CCall.args[i]; i++)
4478 deltaIRExpr(e->Iex.CCall.args[i], delta);
4479 break;
florian99dd03e2013-01-29 03:56:06 +00004480 case Iex_ITE:
4481 deltaIRExpr(e->Iex.ITE.cond, delta);
4482 deltaIRExpr(e->Iex.ITE.iftrue, delta);
4483 deltaIRExpr(e->Iex.ITE.iffalse, delta);
sewardj08210532004-12-29 17:09:11 +00004484 break;
4485 default:
4486 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4487 vpanic("deltaIRExpr");
4488 }
4489}
4490
4491/* Adjust all tmp values (names) in st by delta. st is destructively
4492 modified. */
4493
4494static void deltaIRStmt ( IRStmt* st, Int delta )
4495{
4496 Int i;
4497 IRDirty* d;
4498 switch (st->tag) {
sewardjd2445f62005-03-21 00:15:53 +00004499 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00004500 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00004501 case Ist_MBE:
sewardjf1689312005-03-16 18:19:10 +00004502 break;
sewardj5a9ffab2005-05-12 17:55:01 +00004503 case Ist_AbiHint:
4504 deltaIRExpr(st->Ist.AbiHint.base, delta);
sewardj478646f2008-05-01 20:13:04 +00004505 deltaIRExpr(st->Ist.AbiHint.nia, delta);
sewardj5a9ffab2005-05-12 17:55:01 +00004506 break;
sewardj08210532004-12-29 17:09:11 +00004507 case Ist_Put:
4508 deltaIRExpr(st->Ist.Put.data, delta);
4509 break;
4510 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +00004511 deltaIRExpr(st->Ist.PutI.details->ix, delta);
4512 deltaIRExpr(st->Ist.PutI.details->data, delta);
sewardj08210532004-12-29 17:09:11 +00004513 break;
sewardjdd40fdf2006-12-24 02:20:24 +00004514 case Ist_WrTmp:
4515 st->Ist.WrTmp.tmp += delta;
4516 deltaIRExpr(st->Ist.WrTmp.data, delta);
sewardj08210532004-12-29 17:09:11 +00004517 break;
4518 case Ist_Exit:
4519 deltaIRExpr(st->Ist.Exit.guard, delta);
4520 break;
sewardjaf1ceca2005-06-30 23:31:27 +00004521 case Ist_Store:
4522 deltaIRExpr(st->Ist.Store.addr, delta);
4523 deltaIRExpr(st->Ist.Store.data, delta);
sewardj08210532004-12-29 17:09:11 +00004524 break;
sewardjcfe046e2013-01-17 14:23:53 +00004525 case Ist_StoreG: {
4526 IRStoreG* sg = st->Ist.StoreG.details;
4527 deltaIRExpr(sg->addr, delta);
4528 deltaIRExpr(sg->data, delta);
4529 deltaIRExpr(sg->guard, delta);
4530 break;
4531 }
4532 case Ist_LoadG: {
4533 IRLoadG* lg = st->Ist.LoadG.details;
4534 lg->dst += delta;
4535 deltaIRExpr(lg->addr, delta);
4536 deltaIRExpr(lg->alt, delta);
4537 deltaIRExpr(lg->guard, delta);
4538 break;
4539 }
sewardje9d8a262009-07-01 08:06:34 +00004540 case Ist_CAS:
4541 if (st->Ist.CAS.details->oldHi != IRTemp_INVALID)
4542 st->Ist.CAS.details->oldHi += delta;
4543 st->Ist.CAS.details->oldLo += delta;
4544 deltaIRExpr(st->Ist.CAS.details->addr, delta);
4545 if (st->Ist.CAS.details->expdHi)
4546 deltaIRExpr(st->Ist.CAS.details->expdHi, delta);
4547 deltaIRExpr(st->Ist.CAS.details->expdLo, delta);
4548 if (st->Ist.CAS.details->dataHi)
4549 deltaIRExpr(st->Ist.CAS.details->dataHi, delta);
4550 deltaIRExpr(st->Ist.CAS.details->dataLo, delta);
4551 break;
sewardje768e922009-11-26 17:17:37 +00004552 case Ist_LLSC:
4553 st->Ist.LLSC.result += delta;
4554 deltaIRExpr(st->Ist.LLSC.addr, delta);
4555 if (st->Ist.LLSC.storedata)
4556 deltaIRExpr(st->Ist.LLSC.storedata, delta);
4557 break;
sewardj08210532004-12-29 17:09:11 +00004558 case Ist_Dirty:
4559 d = st->Ist.Dirty.details;
4560 deltaIRExpr(d->guard, delta);
florian2accb5e2013-09-03 21:48:02 +00004561 for (i = 0; d->args[i]; i++) {
4562 IRExpr* arg = d->args[i];
4563 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
4564 deltaIRExpr(arg, delta);
4565 }
sewardj08210532004-12-29 17:09:11 +00004566 if (d->tmp != IRTemp_INVALID)
4567 d->tmp += delta;
4568 if (d->mAddr)
4569 deltaIRExpr(d->mAddr, delta);
4570 break;
4571 default:
4572 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
4573 vpanic("deltaIRStmt");
4574 }
4575}
4576
4577
4578/* If possible, return a loop-unrolled version of bb0. The original
4579 is changed. If not possible, return NULL. */
4580
4581/* The two schemas considered are:
4582
4583 X: BODY; goto X
4584
4585 which unrolls to (eg) X: BODY;BODY; goto X
4586
4587 and
4588
4589 X: BODY; if (c) goto X; goto Y
4590 which trivially transforms to
4591 X: BODY; if (!c) goto Y; goto X;
4592 so it falls in the scope of the first case.
4593
4594 X and Y must be literal (guest) addresses.
4595*/
4596
sewardjdd40fdf2006-12-24 02:20:24 +00004597static Int calc_unroll_factor( IRSB* bb )
sewardj08210532004-12-29 17:09:11 +00004598{
4599 Int n_stmts, i;
4600
4601 n_stmts = 0;
sewardj0ddbf792005-04-04 23:12:54 +00004602 for (i = 0; i < bb->stmts_used; i++) {
4603 if (bb->stmts[i]->tag != Ist_NoOp)
4604 n_stmts++;
4605 }
sewardj08210532004-12-29 17:09:11 +00004606
4607 if (n_stmts <= vex_control.iropt_unroll_thresh/8) {
4608 if (vex_control.iropt_verbosity > 0)
4609 vex_printf("vex iropt: 8 x unrolling (%d sts -> %d sts)\n",
4610 n_stmts, 8* n_stmts);
4611 return 8;
4612 }
4613 if (n_stmts <= vex_control.iropt_unroll_thresh/4) {
4614 if (vex_control.iropt_verbosity > 0)
4615 vex_printf("vex iropt: 4 x unrolling (%d sts -> %d sts)\n",
4616 n_stmts, 4* n_stmts);
4617 return 4;
4618 }
4619
4620 if (n_stmts <= vex_control.iropt_unroll_thresh/2) {
4621 if (vex_control.iropt_verbosity > 0)
4622 vex_printf("vex iropt: 2 x unrolling (%d sts -> %d sts)\n",
4623 n_stmts, 2* n_stmts);
4624 return 2;
4625 }
4626
4627 if (vex_control.iropt_verbosity > 0)
4628 vex_printf("vex iropt: not unrolling (%d sts)\n", n_stmts);
4629
4630 return 1;
4631}
4632
4633
sewardjdd40fdf2006-12-24 02:20:24 +00004634static IRSB* maybe_loop_unroll_BB ( IRSB* bb0, Addr64 my_addr )
sewardj08210532004-12-29 17:09:11 +00004635{
4636 Int i, j, jmax, n_vars;
4637 Bool xxx_known;
4638 Addr64 xxx_value, yyy_value;
4639 IRExpr* udst;
4640 IRStmt* st;
4641 IRConst* con;
sewardjdd40fdf2006-12-24 02:20:24 +00004642 IRSB *bb1, *bb2;
sewardj08210532004-12-29 17:09:11 +00004643 Int unroll_factor;
4644
4645 if (vex_control.iropt_unroll_thresh <= 0)
4646 return NULL;
4647
4648 /* First off, figure out if we can unroll this loop. Do this
4649 without modifying bb0. */
4650
4651 if (bb0->jumpkind != Ijk_Boring)
4652 return NULL;
4653
4654 xxx_known = False;
4655 xxx_value = 0;
4656
4657 /* Extract the next-guest address. If it isn't a literal, we
4658 have to give up. */
4659
4660 udst = bb0->next;
4661 if (udst->tag == Iex_Const
4662 && (udst->Iex.Const.con->tag == Ico_U32
4663 || udst->Iex.Const.con->tag == Ico_U64)) {
4664 /* The BB ends in a jump to a literal location. */
4665 xxx_known = True;
4666 xxx_value = udst->Iex.Const.con->tag == Ico_U64
4667 ? udst->Iex.Const.con->Ico.U64
4668 : (Addr64)(udst->Iex.Const.con->Ico.U32);
4669 }
4670
4671 if (!xxx_known)
4672 return NULL;
4673
4674 /* Now we know the BB ends to a jump to a literal location. If
4675 it's a jump to itself (viz, idiom #1), move directly to the
4676 unrolling stage, first cloning the bb so the original isn't
4677 modified. */
4678 if (xxx_value == my_addr) {
4679 unroll_factor = calc_unroll_factor( bb0 );
4680 if (unroll_factor < 2)
4681 return NULL;
sewardjdd40fdf2006-12-24 02:20:24 +00004682 bb1 = deepCopyIRSB( bb0 );
sewardj08210532004-12-29 17:09:11 +00004683 bb0 = NULL;
4684 udst = NULL; /* is now invalid */
4685 goto do_unroll;
4686 }
4687
4688 /* Search for the second idiomatic form:
4689 X: BODY; if (c) goto X; goto Y
4690 We know Y, but need to establish that the last stmt
4691 is 'if (c) goto X'.
4692 */
4693 yyy_value = xxx_value;
4694 for (i = bb0->stmts_used-1; i >= 0; i--)
4695 if (bb0->stmts[i])
4696 break;
4697
4698 if (i < 0)
4699 return NULL; /* block with no stmts. Strange. */
4700
4701 st = bb0->stmts[i];
4702 if (st->tag != Ist_Exit)
4703 return NULL;
4704 if (st->Ist.Exit.jk != Ijk_Boring)
4705 return NULL;
4706
4707 con = st->Ist.Exit.dst;
4708 vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
4709
4710 xxx_value = con->tag == Ico_U64
4711 ? st->Ist.Exit.dst->Ico.U64
4712 : (Addr64)(st->Ist.Exit.dst->Ico.U32);
4713
4714 /* If this assertion fails, we have some kind of type error. */
4715 vassert(con->tag == udst->Iex.Const.con->tag);
4716
4717 if (xxx_value != my_addr)
4718 /* We didn't find either idiom. Give up. */
4719 return NULL;
4720
4721 /* Ok, we found idiom #2. Copy the BB, switch around the xxx and
4722 yyy values (which makes it look like idiom #1), and go into
4723 unrolling proper. This means finding (again) the last stmt, in
4724 the copied BB. */
4725
4726 unroll_factor = calc_unroll_factor( bb0 );
4727 if (unroll_factor < 2)
4728 return NULL;
4729
sewardjdd40fdf2006-12-24 02:20:24 +00004730 bb1 = deepCopyIRSB( bb0 );
sewardj08210532004-12-29 17:09:11 +00004731 bb0 = NULL;
4732 udst = NULL; /* is now invalid */
4733 for (i = bb1->stmts_used-1; i >= 0; i--)
4734 if (bb1->stmts[i])
4735 break;
4736
4737 /* The next bunch of assertions should be true since we already
4738 found and checked the last stmt in the original bb. */
4739
4740 vassert(i >= 0);
4741
4742 st = bb1->stmts[i];
4743 vassert(st->tag == Ist_Exit);
4744
4745 con = st->Ist.Exit.dst;
4746 vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
4747
4748 udst = bb1->next;
4749 vassert(udst->tag == Iex_Const);
4750 vassert(udst->Iex.Const.con->tag == Ico_U32
4751 || udst->Iex.Const.con->tag == Ico_U64);
4752 vassert(con->tag == udst->Iex.Const.con->tag);
4753
4754 /* switch the xxx and yyy fields around */
4755 if (con->tag == Ico_U64) {
4756 udst->Iex.Const.con->Ico.U64 = xxx_value;
4757 con->Ico.U64 = yyy_value;
4758 } else {
4759 udst->Iex.Const.con->Ico.U32 = (UInt)xxx_value;
cerion57b4c6d2005-02-22 11:07:35 +00004760 con->Ico.U32 = (UInt)yyy_value;
sewardj08210532004-12-29 17:09:11 +00004761 }
4762
4763 /* negate the test condition */
4764 st->Ist.Exit.guard
sewardjdd40fdf2006-12-24 02:20:24 +00004765 = IRExpr_Unop(Iop_Not1,deepCopyIRExpr(st->Ist.Exit.guard));
sewardj08210532004-12-29 17:09:11 +00004766
4767 /* --- The unroller proper. Both idioms are by now --- */
4768 /* --- now converted to idiom 1. --- */
4769
4770 do_unroll:
4771
4772 vassert(unroll_factor == 2
4773 || unroll_factor == 4
4774 || unroll_factor == 8);
4775
4776 jmax = unroll_factor==8 ? 3 : (unroll_factor==4 ? 2 : 1);
4777 for (j = 1; j <= jmax; j++) {
4778
4779 n_vars = bb1->tyenv->types_used;
4780
sewardjdd40fdf2006-12-24 02:20:24 +00004781 bb2 = deepCopyIRSB(bb1);
sewardj08210532004-12-29 17:09:11 +00004782 for (i = 0; i < n_vars; i++)
4783 (void)newIRTemp(bb1->tyenv, bb2->tyenv->types[i]);
4784
4785 for (i = 0; i < bb2->stmts_used; i++) {
sewardj08210532004-12-29 17:09:11 +00004786 /* deltaIRStmt destructively modifies the stmt, but
4787 that's OK since bb2 is a complete fresh copy of bb1. */
4788 deltaIRStmt(bb2->stmts[i], n_vars);
sewardjdd40fdf2006-12-24 02:20:24 +00004789 addStmtToIRSB(bb1, bb2->stmts[i]);
sewardj08210532004-12-29 17:09:11 +00004790 }
4791 }
4792
4793 if (DEBUG_IROPT) {
4794 vex_printf("\nUNROLLED (%llx)\n", my_addr);
sewardjdd40fdf2006-12-24 02:20:24 +00004795 ppIRSB(bb1);
sewardj08210532004-12-29 17:09:11 +00004796 vex_printf("\n");
4797 }
4798
4799 /* Flattening; sigh. The unroller succeeds in breaking flatness
4800 by negating the test condition. This should be fixed properly.
4801 For the moment use this shotgun approach. */
4802 return flatten_BB(bb1);
4803}
4804
4805
4806/*---------------------------------------------------------------*/
sewardj29632392004-08-22 02:38:11 +00004807/*--- The tree builder ---*/
4808/*---------------------------------------------------------------*/
4809
sewardj08210532004-12-29 17:09:11 +00004810/* This isn't part of IR optimisation. Really it's a pass done prior
4811 to instruction selection, which improves the code that the
4812 instruction selector can produce. */
4813
sewardjf9517d02005-11-28 13:39:37 +00004814/* --- The 'tmp' environment is the central data structure here --- */
sewardj29632392004-08-22 02:38:11 +00004815
sewardjf9517d02005-11-28 13:39:37 +00004816/* The number of outstanding bindings we're prepared to track.
4817 The number of times the env becomes full and we have to dump
4818 the oldest binding (hence reducing code quality) falls very
4819 rapidly as the env size increases. 8 gives reasonable performance
4820 under most circumstances. */
4821#define A_NENV 10
4822
florian740da722013-09-11 17:58:32 +00004823/* An interval. Used to record the bytes in the guest state accessed
4824 by a Put[I] statement or by (one or more) Get[I] expression(s). In
4825 case of several Get[I] expressions, the lower/upper bounds are recorded.
4826 This is conservative but cheap.
4827 E.g. a Put of 8 bytes at address 100 would be recorded as [100,107].
4828 E.g. an expression that reads 8 bytes at offset 100 and 4 bytes at
4829 offset 200 would be recorded as [100,203] */
4830typedef
4831 struct {
4832 Bool present;
4833 Int low;
4834 Int high;
4835 }
4836 Interval;
4837
4838static inline Bool
4839intervals_overlap(Interval i1, Interval i2)
4840{
4841 return (i1.low >= i2.low && i1.low <= i2.high) ||
4842 (i2.low >= i1.low && i2.low <= i1.high);
4843}
4844
4845static inline void
4846update_interval(Interval *i, Int low, Int high)
4847{
4848 vassert(low <= high);
4849
4850 if (i->present) {
4851 if (low < i->low) i->low = low;
4852 if (high > i->high) i->high = high;
4853 } else {
4854 i->present = True;
4855 i->low = low;
4856 i->high = high;
4857 }
4858}
4859
4860
sewardjf9517d02005-11-28 13:39:37 +00004861/* bindee == NULL === slot is not in use
4862 bindee != NULL === slot is in use
sewardj29632392004-08-22 02:38:11 +00004863*/
sewardjf9517d02005-11-28 13:39:37 +00004864typedef
4865 struct {
4866 IRTemp binder;
4867 IRExpr* bindee;
4868 Bool doesLoad;
florian740da722013-09-11 17:58:32 +00004869 /* Record the bytes of the guest state BINDEE reads from. */
4870 Interval getInterval;
sewardj17442fe2004-09-20 14:54:28 +00004871 }
sewardjf9517d02005-11-28 13:39:37 +00004872 ATmpInfo;
sewardj17442fe2004-09-20 14:54:28 +00004873
sewardjf9517d02005-11-28 13:39:37 +00004874__attribute__((unused))
4875static void ppAEnv ( ATmpInfo* env )
sewardj29632392004-08-22 02:38:11 +00004876{
sewardj17442fe2004-09-20 14:54:28 +00004877 Int i;
sewardjf9517d02005-11-28 13:39:37 +00004878 for (i = 0; i < A_NENV; i++) {
4879 vex_printf("%d tmp %d val ", i, (Int)env[i].binder);
4880 if (env[i].bindee)
4881 ppIRExpr(env[i].bindee);
4882 else
4883 vex_printf("(null)");
4884 vex_printf("\n");
sewardj29632392004-08-22 02:38:11 +00004885 }
4886}
4887
sewardjf9517d02005-11-28 13:39:37 +00004888/* --- Tree-traversal fns --- */
sewardj29632392004-08-22 02:38:11 +00004889
sewardj37d38012004-08-24 00:37:04 +00004890/* Traverse an expr, and detect if any part of it reads memory or does
4891 a Get. Be careful ... this really controls how much the
4892 tree-builder can reorder the code, so getting it right is critical.
4893*/
florian740da722013-09-11 17:58:32 +00004894static void setHints_Expr (Bool* doesLoad, Interval* getInterval, IRExpr* e )
sewardj29632392004-08-22 02:38:11 +00004895{
sewardjc41f1fb2004-08-22 09:48:08 +00004896 Int i;
sewardj29632392004-08-22 02:38:11 +00004897 switch (e->tag) {
sewardjc41f1fb2004-08-22 09:48:08 +00004898 case Iex_CCall:
4899 for (i = 0; e->Iex.CCall.args[i]; i++)
florian740da722013-09-11 17:58:32 +00004900 setHints_Expr(doesLoad, getInterval, e->Iex.CCall.args[i]);
sewardjc41f1fb2004-08-22 09:48:08 +00004901 return;
florian99dd03e2013-01-29 03:56:06 +00004902 case Iex_ITE:
florian740da722013-09-11 17:58:32 +00004903 setHints_Expr(doesLoad, getInterval, e->Iex.ITE.cond);
4904 setHints_Expr(doesLoad, getInterval, e->Iex.ITE.iftrue);
4905 setHints_Expr(doesLoad, getInterval, e->Iex.ITE.iffalse);
sewardjc41f1fb2004-08-22 09:48:08 +00004906 return;
sewardj40c80262006-02-08 19:30:46 +00004907 case Iex_Qop:
florian740da722013-09-11 17:58:32 +00004908 setHints_Expr(doesLoad, getInterval, e->Iex.Qop.details->arg1);
4909 setHints_Expr(doesLoad, getInterval, e->Iex.Qop.details->arg2);
4910 setHints_Expr(doesLoad, getInterval, e->Iex.Qop.details->arg3);
4911 setHints_Expr(doesLoad, getInterval, e->Iex.Qop.details->arg4);
sewardj40c80262006-02-08 19:30:46 +00004912 return;
sewardjb183b852006-02-03 16:08:03 +00004913 case Iex_Triop:
florian740da722013-09-11 17:58:32 +00004914 setHints_Expr(doesLoad, getInterval, e->Iex.Triop.details->arg1);
4915 setHints_Expr(doesLoad, getInterval, e->Iex.Triop.details->arg2);
4916 setHints_Expr(doesLoad, getInterval, e->Iex.Triop.details->arg3);
sewardjb183b852006-02-03 16:08:03 +00004917 return;
sewardjc41f1fb2004-08-22 09:48:08 +00004918 case Iex_Binop:
florian740da722013-09-11 17:58:32 +00004919 setHints_Expr(doesLoad, getInterval, e->Iex.Binop.arg1);
4920 setHints_Expr(doesLoad, getInterval, e->Iex.Binop.arg2);
sewardjc41f1fb2004-08-22 09:48:08 +00004921 return;
4922 case Iex_Unop:
florian740da722013-09-11 17:58:32 +00004923 setHints_Expr(doesLoad, getInterval, e->Iex.Unop.arg);
sewardjc41f1fb2004-08-22 09:48:08 +00004924 return;
sewardjaf1ceca2005-06-30 23:31:27 +00004925 case Iex_Load:
sewardjc9ad1152004-10-14 00:08:21 +00004926 *doesLoad = True;
florian740da722013-09-11 17:58:32 +00004927 setHints_Expr(doesLoad, getInterval, e->Iex.Load.addr);
sewardjc41f1fb2004-08-22 09:48:08 +00004928 return;
florian740da722013-09-11 17:58:32 +00004929 case Iex_Get: {
4930 Int low = e->Iex.Get.offset;
4931 Int high = low + sizeofIRType(e->Iex.Get.ty) - 1;
4932 update_interval(getInterval, low, high);
sewardj29632392004-08-22 02:38:11 +00004933 return;
florian740da722013-09-11 17:58:32 +00004934 }
4935 case Iex_GetI: {
4936 IRRegArray *descr = e->Iex.GetI.descr;
4937 Int size = sizeofIRType(descr->elemTy);
4938 Int low = descr->base;
4939 Int high = low + descr->nElems * size - 1;
4940 update_interval(getInterval, low, high);
4941 setHints_Expr(doesLoad, getInterval, e->Iex.GetI.ix);
sewardjf6501992004-08-27 11:58:24 +00004942 return;
florian740da722013-09-11 17:58:32 +00004943 }
sewardjdd40fdf2006-12-24 02:20:24 +00004944 case Iex_RdTmp:
sewardjc41f1fb2004-08-22 09:48:08 +00004945 case Iex_Const:
4946 return;
sewardj29632392004-08-22 02:38:11 +00004947 default:
4948 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4949 vpanic("setHints_Expr");
4950 }
4951}
4952
4953
sewardjf9517d02005-11-28 13:39:37 +00004954/* Add a binding to the front of the env and slide all the rest
4955 backwards. It should be the case that the last slot is free. */
4956static void addToEnvFront ( ATmpInfo* env, IRTemp binder, IRExpr* bindee )
sewardj29632392004-08-22 02:38:11 +00004957{
sewardjf9517d02005-11-28 13:39:37 +00004958 Int i;
4959 vassert(env[A_NENV-1].bindee == NULL);
4960 for (i = A_NENV-1; i >= 1; i--)
4961 env[i] = env[i-1];
4962 env[0].binder = binder;
4963 env[0].bindee = bindee;
4964 env[0].doesLoad = False; /* filled in later */
florian740da722013-09-11 17:58:32 +00004965 env[0].getInterval.present = False; /* filled in later */
4966 env[0].getInterval.low = -1; /* filled in later */
4967 env[0].getInterval.high = -1; /* filled in later */
sewardjf9517d02005-11-28 13:39:37 +00004968}
sewardj29632392004-08-22 02:38:11 +00004969
sewardjf9517d02005-11-28 13:39:37 +00004970/* Given uses :: array of UShort, indexed by IRTemp
4971 Add the use-occurrences of temps in this expression
4972 to the env.
4973*/
4974static void aoccCount_Expr ( UShort* uses, IRExpr* e )
4975{
4976 Int i;
sewardj29632392004-08-22 02:38:11 +00004977
sewardjf9517d02005-11-28 13:39:37 +00004978 switch (e->tag) {
4979
sewardjdd40fdf2006-12-24 02:20:24 +00004980 case Iex_RdTmp: /* the only interesting case */
4981 uses[e->Iex.RdTmp.tmp]++;
sewardj8bee6d12005-03-22 02:24:05 +00004982 return;
sewardj29632392004-08-22 02:38:11 +00004983
florian99dd03e2013-01-29 03:56:06 +00004984 case Iex_ITE:
4985 aoccCount_Expr(uses, e->Iex.ITE.cond);
4986 aoccCount_Expr(uses, e->Iex.ITE.iftrue);
4987 aoccCount_Expr(uses, e->Iex.ITE.iffalse);
sewardjf9517d02005-11-28 13:39:37 +00004988 return;
sewardj29632392004-08-22 02:38:11 +00004989
sewardj40c80262006-02-08 19:30:46 +00004990 case Iex_Qop:
florian96d7cc32012-06-01 20:41:24 +00004991 aoccCount_Expr(uses, e->Iex.Qop.details->arg1);
4992 aoccCount_Expr(uses, e->Iex.Qop.details->arg2);
4993 aoccCount_Expr(uses, e->Iex.Qop.details->arg3);
4994 aoccCount_Expr(uses, e->Iex.Qop.details->arg4);
sewardj40c80262006-02-08 19:30:46 +00004995 return;
4996
sewardjb183b852006-02-03 16:08:03 +00004997 case Iex_Triop:
florian420bfa92012-06-02 20:29:22 +00004998 aoccCount_Expr(uses, e->Iex.Triop.details->arg1);
4999 aoccCount_Expr(uses, e->Iex.Triop.details->arg2);
5000 aoccCount_Expr(uses, e->Iex.Triop.details->arg3);
sewardjb183b852006-02-03 16:08:03 +00005001 return;
5002
sewardjf9517d02005-11-28 13:39:37 +00005003 case Iex_Binop:
5004 aoccCount_Expr(uses, e->Iex.Binop.arg1);
5005 aoccCount_Expr(uses, e->Iex.Binop.arg2);
5006 return;
sewardj29632392004-08-22 02:38:11 +00005007
sewardjf9517d02005-11-28 13:39:37 +00005008 case Iex_Unop:
5009 aoccCount_Expr(uses, e->Iex.Unop.arg);
5010 return;
5011
5012 case Iex_Load:
5013 aoccCount_Expr(uses, e->Iex.Load.addr);
5014 return;
5015
5016 case Iex_CCall:
5017 for (i = 0; e->Iex.CCall.args[i]; i++)
5018 aoccCount_Expr(uses, e->Iex.CCall.args[i]);
5019 return;
5020
5021 case Iex_GetI:
5022 aoccCount_Expr(uses, e->Iex.GetI.ix);
5023 return;
5024
5025 case Iex_Const:
5026 case Iex_Get:
5027 return;
5028
5029 default:
5030 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
5031 vpanic("aoccCount_Expr");
5032 }
sewardj29632392004-08-22 02:38:11 +00005033}
5034
5035
sewardjf9517d02005-11-28 13:39:37 +00005036/* Given uses :: array of UShort, indexed by IRTemp
5037 Add the use-occurrences of temps in this statement
5038 to the env.
5039*/
5040static void aoccCount_Stmt ( UShort* uses, IRStmt* st )
sewardj29632392004-08-22 02:38:11 +00005041{
sewardjf9517d02005-11-28 13:39:37 +00005042 Int i;
5043 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00005044 IRCAS* cas;
sewardjf9517d02005-11-28 13:39:37 +00005045 switch (st->tag) {
5046 case Ist_AbiHint:
5047 aoccCount_Expr(uses, st->Ist.AbiHint.base);
sewardj478646f2008-05-01 20:13:04 +00005048 aoccCount_Expr(uses, st->Ist.AbiHint.nia);
sewardjf9517d02005-11-28 13:39:37 +00005049 return;
sewardjdd40fdf2006-12-24 02:20:24 +00005050 case Ist_WrTmp:
5051 aoccCount_Expr(uses, st->Ist.WrTmp.data);
sewardjf9517d02005-11-28 13:39:37 +00005052 return;
5053 case Ist_Put:
5054 aoccCount_Expr(uses, st->Ist.Put.data);
5055 return;
5056 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +00005057 aoccCount_Expr(uses, st->Ist.PutI.details->ix);
5058 aoccCount_Expr(uses, st->Ist.PutI.details->data);
sewardjf9517d02005-11-28 13:39:37 +00005059 return;
5060 case Ist_Store:
5061 aoccCount_Expr(uses, st->Ist.Store.addr);
5062 aoccCount_Expr(uses, st->Ist.Store.data);
5063 return;
sewardjcfe046e2013-01-17 14:23:53 +00005064 case Ist_StoreG: {
5065 IRStoreG* sg = st->Ist.StoreG.details;
5066 aoccCount_Expr(uses, sg->addr);
5067 aoccCount_Expr(uses, sg->data);
5068 aoccCount_Expr(uses, sg->guard);
5069 return;
5070 }
5071 case Ist_LoadG: {
5072 IRLoadG* lg = st->Ist.LoadG.details;
5073 aoccCount_Expr(uses, lg->addr);
5074 aoccCount_Expr(uses, lg->alt);
5075 aoccCount_Expr(uses, lg->guard);
5076 return;
5077 }
sewardje9d8a262009-07-01 08:06:34 +00005078 case Ist_CAS:
5079 cas = st->Ist.CAS.details;
5080 aoccCount_Expr(uses, cas->addr);
5081 if (cas->expdHi)
5082 aoccCount_Expr(uses, cas->expdHi);
5083 aoccCount_Expr(uses, cas->expdLo);
5084 if (cas->dataHi)
5085 aoccCount_Expr(uses, cas->dataHi);
5086 aoccCount_Expr(uses, cas->dataLo);
5087 return;
sewardje768e922009-11-26 17:17:37 +00005088 case Ist_LLSC:
5089 aoccCount_Expr(uses, st->Ist.LLSC.addr);
5090 if (st->Ist.LLSC.storedata)
5091 aoccCount_Expr(uses, st->Ist.LLSC.storedata);
5092 return;
sewardjf9517d02005-11-28 13:39:37 +00005093 case Ist_Dirty:
5094 d = st->Ist.Dirty.details;
5095 if (d->mFx != Ifx_None)
5096 aoccCount_Expr(uses, d->mAddr);
5097 aoccCount_Expr(uses, d->guard);
sewardj74142b82013-08-08 10:28:59 +00005098 for (i = 0; d->args[i]; i++) {
5099 IRExpr* arg = d->args[i];
florian90419562013-08-15 20:54:52 +00005100 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +00005101 aoccCount_Expr(uses, arg);
5102 }
sewardjf9517d02005-11-28 13:39:37 +00005103 return;
5104 case Ist_NoOp:
5105 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00005106 case Ist_MBE:
sewardjf9517d02005-11-28 13:39:37 +00005107 return;
5108 case Ist_Exit:
5109 aoccCount_Expr(uses, st->Ist.Exit.guard);
5110 return;
5111 default:
5112 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
5113 vpanic("aoccCount_Stmt");
5114 }
5115}
5116
5117/* Look up a binding for tmp in the env. If found, return the bound
5118 expression, and set the env's binding to NULL so it is marked as
5119 used. If not found, return NULL. */
5120
5121static IRExpr* atbSubst_Temp ( ATmpInfo* env, IRTemp tmp )
5122{
5123 Int i;
5124 for (i = 0; i < A_NENV; i++) {
5125 if (env[i].binder == tmp && env[i].bindee != NULL) {
5126 IRExpr* bindee = env[i].bindee;
5127 env[i].bindee = NULL;
5128 return bindee;
5129 }
5130 }
5131 return NULL;
5132}
5133
5134/* Traverse e, looking for temps. For each observed temp, see if env
5135 contains a binding for the temp, and if so return the bound value.
5136 The env has the property that any binding it holds is
5137 'single-shot', so once a binding is used, it is marked as no longer
5138 available, by setting its .bindee field to NULL. */
5139
sewardjeb17e492007-08-25 23:07:44 +00005140static inline Bool is_Unop ( IRExpr* e, IROp op ) {
5141 return e->tag == Iex_Unop && e->Iex.Unop.op == op;
5142}
5143static inline Bool is_Binop ( IRExpr* e, IROp op ) {
5144 return e->tag == Iex_Binop && e->Iex.Binop.op == op;
5145}
5146
5147static IRExpr* fold_IRExpr_Binop ( IROp op, IRExpr* a1, IRExpr* a2 )
5148{
5149 switch (op) {
5150 case Iop_Or32:
5151 /* Or32( CmpwNEZ32(x), CmpwNEZ32(y) ) --> CmpwNEZ32( Or32( x, y ) ) */
5152 if (is_Unop(a1, Iop_CmpwNEZ32) && is_Unop(a2, Iop_CmpwNEZ32))
5153 return IRExpr_Unop( Iop_CmpwNEZ32,
5154 IRExpr_Binop( Iop_Or32, a1->Iex.Unop.arg,
5155 a2->Iex.Unop.arg ) );
5156 break;
florian51d26fd2011-07-23 00:23:02 +00005157
5158 case Iop_CmpNE32:
5159 /* Since X has type Ity_I1 we can simplify:
5160 CmpNE32(1Uto32(X),0)) ==> X */
5161 if (is_Unop(a1, Iop_1Uto32) && isZeroU32(a2))
5162 return a1->Iex.Unop.arg;
5163 break;
5164
sewardjeb17e492007-08-25 23:07:44 +00005165 default:
5166 break;
5167 }
5168 /* no reduction rule applies */
5169 return IRExpr_Binop( op, a1, a2 );
5170}
5171
5172static IRExpr* fold_IRExpr_Unop ( IROp op, IRExpr* aa )
5173{
5174 switch (op) {
5175 case Iop_CmpwNEZ64:
floriande6f7102013-09-06 23:13:39 +00005176 /* CmpwNEZ64( CmpwNEZ64 ( x ) ) --> CmpwNEZ64 ( x ) */
5177 if (is_Unop(aa, Iop_CmpwNEZ64))
5178 return IRExpr_Unop( Iop_CmpwNEZ64, aa->Iex.Unop.arg );
sewardjeb17e492007-08-25 23:07:44 +00005179 /* CmpwNEZ64( Or64 ( CmpwNEZ64(x), y ) ) --> CmpwNEZ64( Or64( x, y ) ) */
5180 if (is_Binop(aa, Iop_Or64)
5181 && is_Unop(aa->Iex.Binop.arg1, Iop_CmpwNEZ64))
5182 return fold_IRExpr_Unop(
5183 Iop_CmpwNEZ64,
5184 IRExpr_Binop(Iop_Or64,
5185 aa->Iex.Binop.arg1->Iex.Unop.arg,
5186 aa->Iex.Binop.arg2));
5187 /* CmpwNEZ64( Or64 ( x, CmpwNEZ64(y) ) ) --> CmpwNEZ64( Or64( x, y ) ) */
5188 if (is_Binop(aa, Iop_Or64)
5189 && is_Unop(aa->Iex.Binop.arg2, Iop_CmpwNEZ64))
5190 return fold_IRExpr_Unop(
5191 Iop_CmpwNEZ64,
5192 IRExpr_Binop(Iop_Or64,
5193 aa->Iex.Binop.arg1,
5194 aa->Iex.Binop.arg2->Iex.Unop.arg));
5195 break;
5196 case Iop_CmpNEZ64:
5197 /* CmpNEZ64( Left64(x) ) --> CmpNEZ64(x) */
5198 if (is_Unop(aa, Iop_Left64))
5199 return IRExpr_Unop(Iop_CmpNEZ64, aa->Iex.Unop.arg);
floriande6f7102013-09-06 23:13:39 +00005200 /* CmpNEZ64( 1Uto64(X) ) --> X */
5201 if (is_Unop(aa, Iop_1Uto64))
5202 return aa->Iex.Unop.arg;
sewardjeb17e492007-08-25 23:07:44 +00005203 break;
5204 case Iop_CmpwNEZ32:
5205 /* CmpwNEZ32( CmpwNEZ32 ( x ) ) --> CmpwNEZ32 ( x ) */
5206 if (is_Unop(aa, Iop_CmpwNEZ32))
5207 return IRExpr_Unop( Iop_CmpwNEZ32, aa->Iex.Unop.arg );
5208 break;
5209 case Iop_CmpNEZ32:
5210 /* CmpNEZ32( Left32(x) ) --> CmpNEZ32(x) */
5211 if (is_Unop(aa, Iop_Left32))
5212 return IRExpr_Unop(Iop_CmpNEZ32, aa->Iex.Unop.arg);
florian51d26fd2011-07-23 00:23:02 +00005213 /* CmpNEZ32( 1Uto32(X) ) --> X */
5214 if (is_Unop(aa, Iop_1Uto32))
5215 return aa->Iex.Unop.arg;
floriande6f7102013-09-06 23:13:39 +00005216 /* CmpNEZ32( 64to32( CmpwNEZ64(X) ) ) --> CmpNEZ64(X) */
5217 if (is_Unop(aa, Iop_64to32) && is_Unop(aa->Iex.Unop.arg, Iop_CmpwNEZ64))
5218 return IRExpr_Unop(Iop_CmpNEZ64, aa->Iex.Unop.arg->Iex.Unop.arg);
florian51d26fd2011-07-23 00:23:02 +00005219 break;
5220 case Iop_CmpNEZ8:
5221 /* CmpNEZ8( 1Uto8(X) ) --> X */
5222 if (is_Unop(aa, Iop_1Uto8))
5223 return aa->Iex.Unop.arg;
sewardjeb17e492007-08-25 23:07:44 +00005224 break;
5225 case Iop_Left32:
5226 /* Left32( Left32(x) ) --> Left32(x) */
5227 if (is_Unop(aa, Iop_Left32))
5228 return IRExpr_Unop( Iop_Left32, aa->Iex.Unop.arg );
5229 break;
florian854912a2013-09-01 20:17:23 +00005230 case Iop_Left64:
5231 /* Left64( Left64(x) ) --> Left64(x) */
5232 if (is_Unop(aa, Iop_Left64))
5233 return IRExpr_Unop( Iop_Left64, aa->Iex.Unop.arg );
5234 break;
sewardj0caa0c02014-08-11 14:01:00 +00005235 case Iop_ZeroHI64ofV128:
5236 /* ZeroHI64ofV128( ZeroHI64ofV128(x) ) --> ZeroHI64ofV128(x) */
5237 if (is_Unop(aa, Iop_ZeroHI64ofV128))
5238 return IRExpr_Unop( Iop_ZeroHI64ofV128, aa->Iex.Unop.arg );
5239 break;
sewardjeb17e492007-08-25 23:07:44 +00005240 case Iop_32to1:
5241 /* 32to1( 1Uto32 ( x ) ) --> x */
5242 if (is_Unop(aa, Iop_1Uto32))
5243 return aa->Iex.Unop.arg;
5244 /* 32to1( CmpwNEZ32 ( x )) --> CmpNEZ32(x) */
5245 if (is_Unop(aa, Iop_CmpwNEZ32))
5246 return IRExpr_Unop( Iop_CmpNEZ32, aa->Iex.Unop.arg );
5247 break;
5248 case Iop_64to1:
5249 /* 64to1( 1Uto64 ( x ) ) --> x */
5250 if (is_Unop(aa, Iop_1Uto64))
5251 return aa->Iex.Unop.arg;
5252 /* 64to1( CmpwNEZ64 ( x )) --> CmpNEZ64(x) */
5253 if (is_Unop(aa, Iop_CmpwNEZ64))
5254 return IRExpr_Unop( Iop_CmpNEZ64, aa->Iex.Unop.arg );
5255 break;
sewardjef425db2010-01-11 10:46:18 +00005256 case Iop_64to32:
5257 /* 64to32( 32Uto64 ( x )) --> x */
5258 if (is_Unop(aa, Iop_32Uto64))
5259 return aa->Iex.Unop.arg;
sewardjca257bc2010-09-08 08:34:52 +00005260 /* 64to32( 8Uto64 ( x )) --> 8Uto32(x) */
5261 if (is_Unop(aa, Iop_8Uto64))
5262 return IRExpr_Unop(Iop_8Uto32, aa->Iex.Unop.arg);
5263 break;
5264
5265 case Iop_32Uto64:
5266 /* 32Uto64( 8Uto32( x )) --> 8Uto64(x) */
5267 if (is_Unop(aa, Iop_8Uto32))
5268 return IRExpr_Unop(Iop_8Uto64, aa->Iex.Unop.arg);
5269 /* 32Uto64( 16Uto32( x )) --> 16Uto64(x) */
5270 if (is_Unop(aa, Iop_16Uto32))
5271 return IRExpr_Unop(Iop_16Uto64, aa->Iex.Unop.arg);
sewardjbba356d2012-04-25 16:47:53 +00005272 /* 32Uto64(64to32( Shr64( 32Uto64(64to32(x)), sh ))
5273 --> Shr64( 32Uto64(64to32(x)), sh )) */
5274 if (is_Unop(aa, Iop_64to32)
5275 && is_Binop(aa->Iex.Unop.arg, Iop_Shr64)
5276 && is_Unop(aa->Iex.Unop.arg->Iex.Binop.arg1, Iop_32Uto64)
5277 && is_Unop(aa->Iex.Unop.arg->Iex.Binop.arg1->Iex.Unop.arg,
5278 Iop_64to32)) {
5279 return aa->Iex.Unop.arg;
5280 }
5281 /* 32Uto64(64to32( Shl64( 32Uto64(64to32(x)), sh ))
5282 --> 32Uto64(64to32( Shl64( x, sh )) */
5283 if (is_Unop(aa, Iop_64to32)
5284 && is_Binop(aa->Iex.Unop.arg, Iop_Shl64)
5285 && is_Unop(aa->Iex.Unop.arg->Iex.Binop.arg1, Iop_32Uto64)
5286 && is_Unop(aa->Iex.Unop.arg->Iex.Binop.arg1->Iex.Unop.arg,
5287 Iop_64to32)) {
5288 return
5289 IRExpr_Unop(
5290 Iop_32Uto64,
5291 IRExpr_Unop(
5292 Iop_64to32,
5293 IRExpr_Binop(
5294 Iop_Shl64,
5295 aa->Iex.Unop.arg->Iex.Binop.arg1->Iex.Unop.arg->Iex.Unop.arg,
5296 aa->Iex.Unop.arg->Iex.Binop.arg2
5297 )));
5298 }
sewardjef425db2010-01-11 10:46:18 +00005299 break;
sewardj6c299f32009-12-31 18:00:12 +00005300
5301 case Iop_1Sto32:
5302 /* 1Sto32( CmpNEZ8( 32to8( 1Uto32( CmpNEZ32( x ))))) -> CmpwNEZ32(x) */
5303 if (is_Unop(aa, Iop_CmpNEZ8)
5304 && is_Unop(aa->Iex.Unop.arg, Iop_32to8)
5305 && is_Unop(aa->Iex.Unop.arg->Iex.Unop.arg, Iop_1Uto32)
5306 && is_Unop(aa->Iex.Unop.arg->Iex.Unop.arg->Iex.Unop.arg,
5307 Iop_CmpNEZ32)) {
5308 return IRExpr_Unop( Iop_CmpwNEZ32,
5309 aa->Iex.Unop.arg->Iex.Unop.arg
5310 ->Iex.Unop.arg->Iex.Unop.arg);
5311 }
5312 break;
5313
sewardjeb17e492007-08-25 23:07:44 +00005314 default:
5315 break;
5316 }
5317 /* no reduction rule applies */
5318 return IRExpr_Unop( op, aa );
5319}
5320
sewardjf9517d02005-11-28 13:39:37 +00005321static IRExpr* atbSubst_Expr ( ATmpInfo* env, IRExpr* e )
5322{
5323 IRExpr* e2;
5324 IRExpr** args2;
5325 Int i;
5326
5327 switch (e->tag) {
5328
5329 case Iex_CCall:
sewardjdd40fdf2006-12-24 02:20:24 +00005330 args2 = shallowCopyIRExprVec(e->Iex.CCall.args);
sewardjf9517d02005-11-28 13:39:37 +00005331 for (i = 0; args2[i]; i++)
5332 args2[i] = atbSubst_Expr(env,args2[i]);
5333 return IRExpr_CCall(
5334 e->Iex.CCall.cee,
5335 e->Iex.CCall.retty,
5336 args2
5337 );
sewardjdd40fdf2006-12-24 02:20:24 +00005338 case Iex_RdTmp:
5339 e2 = atbSubst_Temp(env, e->Iex.RdTmp.tmp);
sewardjf9517d02005-11-28 13:39:37 +00005340 return e2 ? e2 : e;
florian99dd03e2013-01-29 03:56:06 +00005341 case Iex_ITE:
5342 return IRExpr_ITE(
5343 atbSubst_Expr(env, e->Iex.ITE.cond),
5344 atbSubst_Expr(env, e->Iex.ITE.iftrue),
5345 atbSubst_Expr(env, e->Iex.ITE.iffalse)
sewardjf9517d02005-11-28 13:39:37 +00005346 );
sewardj40c80262006-02-08 19:30:46 +00005347 case Iex_Qop:
5348 return IRExpr_Qop(
florian96d7cc32012-06-01 20:41:24 +00005349 e->Iex.Qop.details->op,
5350 atbSubst_Expr(env, e->Iex.Qop.details->arg1),
5351 atbSubst_Expr(env, e->Iex.Qop.details->arg2),
5352 atbSubst_Expr(env, e->Iex.Qop.details->arg3),
5353 atbSubst_Expr(env, e->Iex.Qop.details->arg4)
sewardj40c80262006-02-08 19:30:46 +00005354 );
sewardjb183b852006-02-03 16:08:03 +00005355 case Iex_Triop:
5356 return IRExpr_Triop(
florian420bfa92012-06-02 20:29:22 +00005357 e->Iex.Triop.details->op,
5358 atbSubst_Expr(env, e->Iex.Triop.details->arg1),
5359 atbSubst_Expr(env, e->Iex.Triop.details->arg2),
5360 atbSubst_Expr(env, e->Iex.Triop.details->arg3)
sewardjb183b852006-02-03 16:08:03 +00005361 );
sewardjf9517d02005-11-28 13:39:37 +00005362 case Iex_Binop:
sewardjeb17e492007-08-25 23:07:44 +00005363 return fold_IRExpr_Binop(
sewardjf9517d02005-11-28 13:39:37 +00005364 e->Iex.Binop.op,
5365 atbSubst_Expr(env, e->Iex.Binop.arg1),
5366 atbSubst_Expr(env, e->Iex.Binop.arg2)
5367 );
5368 case Iex_Unop:
sewardjeb17e492007-08-25 23:07:44 +00005369 return fold_IRExpr_Unop(
sewardjf9517d02005-11-28 13:39:37 +00005370 e->Iex.Unop.op,
5371 atbSubst_Expr(env, e->Iex.Unop.arg)
5372 );
5373 case Iex_Load:
5374 return IRExpr_Load(
5375 e->Iex.Load.end,
5376 e->Iex.Load.ty,
5377 atbSubst_Expr(env, e->Iex.Load.addr)
5378 );
5379 case Iex_GetI:
5380 return IRExpr_GetI(
5381 e->Iex.GetI.descr,
5382 atbSubst_Expr(env, e->Iex.GetI.ix),
5383 e->Iex.GetI.bias
5384 );
5385 case Iex_Const:
5386 case Iex_Get:
5387 return e;
5388 default:
5389 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
5390 vpanic("atbSubst_Expr");
5391 }
5392}
5393
5394/* Same deal as atbSubst_Expr, except for stmts. */
5395
5396static IRStmt* atbSubst_Stmt ( ATmpInfo* env, IRStmt* st )
5397{
sewardje9d8a262009-07-01 08:06:34 +00005398 Int i;
5399 IRDirty *d, *d2;
5400 IRCAS *cas, *cas2;
floriand6f38b32012-05-31 15:46:18 +00005401 IRPutI *puti, *puti2;
5402
sewardjf9517d02005-11-28 13:39:37 +00005403 switch (st->tag) {
5404 case Ist_AbiHint:
5405 return IRStmt_AbiHint(
5406 atbSubst_Expr(env, st->Ist.AbiHint.base),
sewardj478646f2008-05-01 20:13:04 +00005407 st->Ist.AbiHint.len,
5408 atbSubst_Expr(env, st->Ist.AbiHint.nia)
sewardjf9517d02005-11-28 13:39:37 +00005409 );
5410 case Ist_Store:
5411 return IRStmt_Store(
5412 st->Ist.Store.end,
5413 atbSubst_Expr(env, st->Ist.Store.addr),
5414 atbSubst_Expr(env, st->Ist.Store.data)
5415 );
sewardjcfe046e2013-01-17 14:23:53 +00005416 case Ist_StoreG: {
5417 IRStoreG* sg = st->Ist.StoreG.details;
5418 return IRStmt_StoreG(sg->end,
5419 atbSubst_Expr(env, sg->addr),
5420 atbSubst_Expr(env, sg->data),
5421 atbSubst_Expr(env, sg->guard));
5422 }
5423 case Ist_LoadG: {
5424 IRLoadG* lg = st->Ist.LoadG.details;
5425 return IRStmt_LoadG(lg->end, lg->cvt, lg->dst,
5426 atbSubst_Expr(env, lg->addr),
5427 atbSubst_Expr(env, lg->alt),
5428 atbSubst_Expr(env, lg->guard));
5429 }
sewardjdd40fdf2006-12-24 02:20:24 +00005430 case Ist_WrTmp:
5431 return IRStmt_WrTmp(
5432 st->Ist.WrTmp.tmp,
5433 atbSubst_Expr(env, st->Ist.WrTmp.data)
sewardjf9517d02005-11-28 13:39:37 +00005434 );
5435 case Ist_Put:
5436 return IRStmt_Put(
5437 st->Ist.Put.offset,
5438 atbSubst_Expr(env, st->Ist.Put.data)
5439 );
5440 case Ist_PutI:
floriand6f38b32012-05-31 15:46:18 +00005441 puti = st->Ist.PutI.details;
5442 puti2 = mkIRPutI(puti->descr,
5443 atbSubst_Expr(env, puti->ix),
5444 puti->bias,
5445 atbSubst_Expr(env, puti->data));
5446 return IRStmt_PutI(puti2);
sewardjf9517d02005-11-28 13:39:37 +00005447
5448 case Ist_Exit:
5449 return IRStmt_Exit(
5450 atbSubst_Expr(env, st->Ist.Exit.guard),
5451 st->Ist.Exit.jk,
sewardjc6f970f2012-04-02 21:54:49 +00005452 st->Ist.Exit.dst,
5453 st->Ist.Exit.offsIP
sewardjf9517d02005-11-28 13:39:37 +00005454 );
5455 case Ist_IMark:
sewardj2f10aa62011-05-27 13:20:56 +00005456 return IRStmt_IMark(st->Ist.IMark.addr,
5457 st->Ist.IMark.len,
5458 st->Ist.IMark.delta);
sewardjf9517d02005-11-28 13:39:37 +00005459 case Ist_NoOp:
5460 return IRStmt_NoOp();
sewardjc4356f02007-11-09 21:15:04 +00005461 case Ist_MBE:
5462 return IRStmt_MBE(st->Ist.MBE.event);
sewardje9d8a262009-07-01 08:06:34 +00005463 case Ist_CAS:
5464 cas = st->Ist.CAS.details;
5465 cas2 = mkIRCAS(
5466 cas->oldHi, cas->oldLo, cas->end,
5467 atbSubst_Expr(env, cas->addr),
5468 cas->expdHi ? atbSubst_Expr(env, cas->expdHi) : NULL,
5469 atbSubst_Expr(env, cas->expdLo),
5470 cas->dataHi ? atbSubst_Expr(env, cas->dataHi) : NULL,
5471 atbSubst_Expr(env, cas->dataLo)
5472 );
5473 return IRStmt_CAS(cas2);
sewardje768e922009-11-26 17:17:37 +00005474 case Ist_LLSC:
5475 return IRStmt_LLSC(
5476 st->Ist.LLSC.end,
5477 st->Ist.LLSC.result,
5478 atbSubst_Expr(env, st->Ist.LLSC.addr),
5479 st->Ist.LLSC.storedata
5480 ? atbSubst_Expr(env, st->Ist.LLSC.storedata) : NULL
5481 );
sewardjf9517d02005-11-28 13:39:37 +00005482 case Ist_Dirty:
5483 d = st->Ist.Dirty.details;
5484 d2 = emptyIRDirty();
5485 *d2 = *d;
5486 if (d2->mFx != Ifx_None)
5487 d2->mAddr = atbSubst_Expr(env, d2->mAddr);
5488 d2->guard = atbSubst_Expr(env, d2->guard);
sewardj74142b82013-08-08 10:28:59 +00005489 for (i = 0; d2->args[i]; i++) {
5490 IRExpr* arg = d2->args[i];
florian90419562013-08-15 20:54:52 +00005491 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +00005492 d2->args[i] = atbSubst_Expr(env, arg);
5493 }
sewardjf9517d02005-11-28 13:39:37 +00005494 return IRStmt_Dirty(d2);
5495 default:
5496 vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
5497 vpanic("atbSubst_Stmt");
5498 }
5499}
5500
florian088809c2012-12-30 18:17:18 +00005501inline
5502static Bool dirty_helper_stores ( const IRDirty *d )
5503{
5504 return d->mFx == Ifx_Write || d->mFx == Ifx_Modify;
5505}
5506
5507inline
florian740da722013-09-11 17:58:32 +00005508static Interval dirty_helper_puts ( const IRDirty *d,
5509 Bool (*preciseMemExnsFn)(Int, Int),
5510 Bool *requiresPreciseMemExns )
florian088809c2012-12-30 18:17:18 +00005511{
5512 Int i;
florian740da722013-09-11 17:58:32 +00005513 Interval interval;
florian088809c2012-12-30 18:17:18 +00005514
5515 /* Passing the guest state pointer opens the door to modifying the
sewardj74142b82013-08-08 10:28:59 +00005516 guest state under the covers. It's not allowed, but let's be
florian088809c2012-12-30 18:17:18 +00005517 extra conservative and assume the worst. */
sewardj74142b82013-08-08 10:28:59 +00005518 for (i = 0; d->args[i]; i++) {
florian90419562013-08-15 20:54:52 +00005519 if (UNLIKELY(d->args[i]->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +00005520 *requiresPreciseMemExns = True;
florian740da722013-09-11 17:58:32 +00005521 /* Assume all guest state is written. */
5522 interval.present = True;
5523 interval.low = 0;
5524 interval.high = 0x7FFFFFFF;
5525 return interval;
sewardj74142b82013-08-08 10:28:59 +00005526 }
florian088809c2012-12-30 18:17:18 +00005527 }
5528
florian62140c12013-01-20 03:51:04 +00005529 /* Check the side effects on the guest state */
florian740da722013-09-11 17:58:32 +00005530 interval.present = False;
5531 interval.low = interval.high = -1;
florian62140c12013-01-20 03:51:04 +00005532 *requiresPreciseMemExns = False;
5533
5534 for (i = 0; i < d->nFxState; ++i) {
5535 if (d->fxState[i].fx != Ifx_Read) {
5536 Int offset = d->fxState[i].offset;
5537 Int size = d->fxState[i].size;
5538 Int nRepeats = d->fxState[i].nRepeats;
5539 Int repeatLen = d->fxState[i].repeatLen;
5540
sewardj74142b82013-08-08 10:28:59 +00005541 if (preciseMemExnsFn(offset,
5542 offset + nRepeats * repeatLen + size - 1)) {
florian62140c12013-01-20 03:51:04 +00005543 *requiresPreciseMemExns = True;
florian62140c12013-01-20 03:51:04 +00005544 }
florian740da722013-09-11 17:58:32 +00005545 update_interval(&interval, offset,
5546 offset + nRepeats * repeatLen + size - 1);
florian62140c12013-01-20 03:51:04 +00005547 }
5548 }
5549
florian740da722013-09-11 17:58:32 +00005550 return interval;
florian088809c2012-12-30 18:17:18 +00005551}
5552
florian740da722013-09-11 17:58:32 +00005553/* Return an interval if st modifies the guest state. Via requiresPreciseMemExns
florian62140c12013-01-20 03:51:04 +00005554 return whether or not that modification requires precise exceptions. */
florian740da722013-09-11 17:58:32 +00005555static Interval stmt_modifies_guest_state ( IRSB *bb, const IRStmt *st,
5556 Bool (*preciseMemExnsFn)(Int,Int),
5557 Bool *requiresPreciseMemExns )
florian62140c12013-01-20 03:51:04 +00005558{
florian740da722013-09-11 17:58:32 +00005559 Interval interval;
5560
florian62140c12013-01-20 03:51:04 +00005561 switch (st->tag) {
5562 case Ist_Put: {
5563 Int offset = st->Ist.Put.offset;
5564 Int size = sizeofIRType(typeOfIRExpr(bb->tyenv, st->Ist.Put.data));
5565
5566 *requiresPreciseMemExns = preciseMemExnsFn(offset, offset + size - 1);
florian740da722013-09-11 17:58:32 +00005567 interval.present = True;
5568 interval.low = offset;
5569 interval.high = offset + size - 1;
5570 return interval;
florian62140c12013-01-20 03:51:04 +00005571 }
5572
5573 case Ist_PutI: {
5574 IRRegArray *descr = st->Ist.PutI.details->descr;
5575 Int offset = descr->base;
5576 Int size = sizeofIRType(descr->elemTy);
5577
5578 /* We quietly assume here that all segments are contiguous and there
5579 are no holes. This is to avoid a loop. The assumption is conservative
5580 in the sense that we might report that precise memory exceptions are
5581 needed when in fact they are not. */
5582 *requiresPreciseMemExns =
5583 preciseMemExnsFn(offset, offset + descr->nElems * size - 1);
florian740da722013-09-11 17:58:32 +00005584 interval.present = True;
5585 interval.low = offset;
5586 interval.high = offset + descr->nElems * size - 1;
5587 return interval;
florian62140c12013-01-20 03:51:04 +00005588 }
5589
5590 case Ist_Dirty:
5591 return dirty_helper_puts(st->Ist.Dirty.details, preciseMemExnsFn,
5592 requiresPreciseMemExns);
5593
5594 default:
5595 *requiresPreciseMemExns = False;
florian740da722013-09-11 17:58:32 +00005596 interval.present = False;
5597 interval.low = -1;
5598 interval.high = -1;
5599 return interval;
florian62140c12013-01-20 03:51:04 +00005600 }
5601}
5602
5603/* notstatic */ Addr64 ado_treebuild_BB ( IRSB* bb,
5604 Bool (*preciseMemExnsFn)(Int,Int) )
sewardjf9517d02005-11-28 13:39:37 +00005605{
5606 Int i, j, k, m;
florian740da722013-09-11 17:58:32 +00005607 Bool stmtStores, invalidateMe;
5608 Interval putInterval;
sewardj29632392004-08-22 02:38:11 +00005609 IRStmt* st;
5610 IRStmt* st2;
sewardjf9517d02005-11-28 13:39:37 +00005611 ATmpInfo env[A_NENV];
sewardj29632392004-08-22 02:38:11 +00005612
sewardjc6f970f2012-04-02 21:54:49 +00005613 Bool max_ga_known = False;
5614 Addr64 max_ga = 0;
5615
sewardjc9ad1152004-10-14 00:08:21 +00005616 Int n_tmps = bb->tyenv->types_used;
sewardjf9517d02005-11-28 13:39:37 +00005617 UShort* uses = LibVEX_Alloc(n_tmps * sizeof(UShort));
sewardj29632392004-08-22 02:38:11 +00005618
5619 /* Phase 1. Scan forwards in bb, counting use occurrences of each
sewardjc6f970f2012-04-02 21:54:49 +00005620 temp. Also count occurrences in the bb->next field. Take the
5621 opportunity to also find the maximum guest address in the block,
5622 since that will be needed later for deciding when we can safely
5623 elide event checks. */
sewardj29632392004-08-22 02:38:11 +00005624
sewardjf9517d02005-11-28 13:39:37 +00005625 for (i = 0; i < n_tmps; i++)
5626 uses[i] = 0;
5627
sewardj29632392004-08-22 02:38:11 +00005628 for (i = 0; i < bb->stmts_used; i++) {
5629 st = bb->stmts[i];
sewardjc6f970f2012-04-02 21:54:49 +00005630 switch (st->tag) {
5631 case Ist_NoOp:
5632 continue;
5633 case Ist_IMark: {
5634 Int len = st->Ist.IMark.len;
5635 Addr64 mga = st->Ist.IMark.addr + (len < 1 ? 1 : len) - 1;
5636 max_ga_known = True;
5637 if (mga > max_ga)
5638 max_ga = mga;
5639 break;
5640 }
5641 default:
5642 break;
5643 }
sewardjf9517d02005-11-28 13:39:37 +00005644 aoccCount_Stmt( uses, st );
sewardj29632392004-08-22 02:38:11 +00005645 }
sewardjf9517d02005-11-28 13:39:37 +00005646 aoccCount_Expr(uses, bb->next );
sewardj29632392004-08-22 02:38:11 +00005647
sewardjc9ad1152004-10-14 00:08:21 +00005648# if 0
sewardjf9517d02005-11-28 13:39:37 +00005649 for (i = 0; i < n_tmps; i++) {
5650 if (uses[i] == 0)
sewardj29632392004-08-22 02:38:11 +00005651 continue;
sewardjf9517d02005-11-28 13:39:37 +00005652 ppIRTemp( (IRTemp)i );
5653 vex_printf(" used %d\n", (Int)uses[i] );
sewardj29632392004-08-22 02:38:11 +00005654 }
sewardjc9ad1152004-10-14 00:08:21 +00005655# endif
sewardj29632392004-08-22 02:38:11 +00005656
sewardjf9517d02005-11-28 13:39:37 +00005657 /* Phase 2. Scan forwards in bb. For each statement in turn:
sewardj29632392004-08-22 02:38:11 +00005658
sewardjf9517d02005-11-28 13:39:37 +00005659 If the env is full, emit the end element. This guarantees
5660 there is at least one free slot in the following.
sewardj29632392004-08-22 02:38:11 +00005661
sewardjf9517d02005-11-28 13:39:37 +00005662 On seeing 't = E', occ(t)==1,
5663 let E'=env(E)
5664 delete this stmt
5665 add t -> E' to the front of the env
5666 Examine E' and set the hints for E' appropriately
sewardj29632392004-08-22 02:38:11 +00005667 (doesLoad? doesGet?)
5668
sewardjf9517d02005-11-28 13:39:37 +00005669 On seeing any other stmt,
sewardj29632392004-08-22 02:38:11 +00005670 let stmt' = env(stmt)
5671 remove from env any 't=E' binds invalidated by stmt
5672 emit the invalidated stmts
5673 emit stmt'
sewardjf9517d02005-11-28 13:39:37 +00005674 compact any holes in env
5675 by sliding entries towards the front
sewardj29632392004-08-22 02:38:11 +00005676
sewardjf9517d02005-11-28 13:39:37 +00005677 Finally, apply env to bb->next.
sewardj29632392004-08-22 02:38:11 +00005678 */
5679
sewardjf9517d02005-11-28 13:39:37 +00005680 for (i = 0; i < A_NENV; i++) {
5681 env[i].bindee = NULL;
5682 env[i].binder = IRTemp_INVALID;
5683 }
5684
sewardj29632392004-08-22 02:38:11 +00005685 /* The stmts in bb are being reordered, and we are guaranteed to
5686 end up with no more than the number we started with. Use i to
5687 be the cursor of the current stmt examined and j <= i to be that
5688 for the current stmt being written.
5689 */
5690 j = 0;
5691 for (i = 0; i < bb->stmts_used; i++) {
sewardjf9517d02005-11-28 13:39:37 +00005692
sewardj29632392004-08-22 02:38:11 +00005693 st = bb->stmts[i];
sewardj8bee6d12005-03-22 02:24:05 +00005694 if (st->tag == Ist_NoOp)
sewardj29632392004-08-22 02:38:11 +00005695 continue;
5696
sewardjf9517d02005-11-28 13:39:37 +00005697 /* Ensure there's at least one space in the env, by emitting
5698 the oldest binding if necessary. */
5699 if (env[A_NENV-1].bindee != NULL) {
sewardjdd40fdf2006-12-24 02:20:24 +00005700 bb->stmts[j] = IRStmt_WrTmp( env[A_NENV-1].binder,
5701 env[A_NENV-1].bindee );
sewardjf9517d02005-11-28 13:39:37 +00005702 j++;
5703 vassert(j <= i);
5704 env[A_NENV-1].bindee = NULL;
5705 }
5706
5707 /* Consider current stmt. */
sewardjdd40fdf2006-12-24 02:20:24 +00005708 if (st->tag == Ist_WrTmp && uses[st->Ist.WrTmp.tmp] <= 1) {
sewardj63327402006-01-25 03:26:27 +00005709 IRExpr *e, *e2;
sewardjf9517d02005-11-28 13:39:37 +00005710
5711 /* optional extra: dump dead bindings as we find them.
5712 Removes the need for a prior dead-code removal pass. */
sewardjdd40fdf2006-12-24 02:20:24 +00005713 if (uses[st->Ist.WrTmp.tmp] == 0) {
sewardjb183b852006-02-03 16:08:03 +00005714 if (0) vex_printf("DEAD binding\n");
sewardjf9517d02005-11-28 13:39:37 +00005715 continue; /* for (i = 0; i < bb->stmts_used; i++) loop */
sewardj29632392004-08-22 02:38:11 +00005716 }
sewardjdd40fdf2006-12-24 02:20:24 +00005717 vassert(uses[st->Ist.WrTmp.tmp] == 1);
sewardjf9517d02005-11-28 13:39:37 +00005718
5719 /* ok, we have 't = E', occ(t)==1. Do the abovementioned
5720 actions. */
sewardjdd40fdf2006-12-24 02:20:24 +00005721 e = st->Ist.WrTmp.data;
sewardj63327402006-01-25 03:26:27 +00005722 e2 = atbSubst_Expr(env, e);
sewardjdd40fdf2006-12-24 02:20:24 +00005723 addToEnvFront(env, st->Ist.WrTmp.tmp, e2);
florian740da722013-09-11 17:58:32 +00005724 setHints_Expr(&env[0].doesLoad, &env[0].getInterval, e2);
sewardjf9517d02005-11-28 13:39:37 +00005725 /* don't advance j, as we are deleting this stmt and instead
5726 holding it temporarily in the env. */
5727 continue; /* for (i = 0; i < bb->stmts_used; i++) loop */
sewardj29632392004-08-22 02:38:11 +00005728 }
5729
5730 /* we get here for any other kind of statement. */
5731 /* 'use up' any bindings required by the current statement. */
sewardjf9517d02005-11-28 13:39:37 +00005732 st2 = atbSubst_Stmt(env, st);
sewardj29632392004-08-22 02:38:11 +00005733
sewardjf9517d02005-11-28 13:39:37 +00005734 /* Now, before this stmt, dump any bindings in env that it
5735 invalidates. These need to be dumped in the order in which
5736 they originally entered env -- that means from oldest to
5737 youngest. */
sewardj3e838932005-01-07 12:09:15 +00005738
florian740da722013-09-11 17:58:32 +00005739 /* putInterval/stmtStores characterise what the stmt under
sewardje9d8a262009-07-01 08:06:34 +00005740 consideration does, or might do (sidely safe @ True). */
florian62140c12013-01-20 03:51:04 +00005741
5742 Bool putRequiresPreciseMemExns;
florian740da722013-09-11 17:58:32 +00005743 putInterval = stmt_modifies_guest_state( bb, st, preciseMemExnsFn,
5744 &putRequiresPreciseMemExns);
sewardj29632392004-08-22 02:38:11 +00005745
sewardje9d8a262009-07-01 08:06:34 +00005746 /* be True if this stmt writes memory or might do (==> we don't
5747 want to reorder other loads or stores relative to it). Also,
sewardje768e922009-11-26 17:17:37 +00005748 both LL and SC fall under this classification, since we
sewardje9d8a262009-07-01 08:06:34 +00005749 really ought to be conservative and not reorder any other
sewardje768e922009-11-26 17:17:37 +00005750 memory transactions relative to them. */
sewardje9d8a262009-07-01 08:06:34 +00005751 stmtStores
5752 = toBool( st->tag == Ist_Store
florian088809c2012-12-30 18:17:18 +00005753 || (st->tag == Ist_Dirty
5754 && dirty_helper_stores(st->Ist.Dirty.details))
sewardj0f621982012-04-12 21:05:16 +00005755 || st->tag == Ist_LLSC
5756 || st->tag == Ist_CAS );
sewardj29632392004-08-22 02:38:11 +00005757
sewardjf9517d02005-11-28 13:39:37 +00005758 for (k = A_NENV-1; k >= 0; k--) {
5759 if (env[k].bindee == NULL)
5760 continue;
5761 /* Compare the actions of this stmt with the actions of
5762 binding 'k', to see if they invalidate the binding. */
5763 invalidateMe
sewardj9d2e7692005-02-07 01:11:31 +00005764 = toBool(
5765 /* a store invalidates loaded data */
sewardjf9517d02005-11-28 13:39:37 +00005766 (env[k].doesLoad && stmtStores)
florian740da722013-09-11 17:58:32 +00005767 /* a put invalidates get'd data, if they overlap */
5768 || ((env[k].getInterval.present && putInterval.present) &&
5769 intervals_overlap(env[k].getInterval, putInterval))
florian62140c12013-01-20 03:51:04 +00005770 /* a put invalidates loaded data. That means, in essense, that
5771 a load expression cannot be substituted into a statement
5772 that follows the put. But there is nothing wrong doing so
5773 except when the put statement requries precise exceptions.
5774 Think of a load that is moved past a put where the put
5775 updates the IP in the guest state. If the load generates
5776 a segfault, the wrong address (line number) would be
5777 reported. */
florian740da722013-09-11 17:58:32 +00005778 || (env[k].doesLoad && putInterval.present &&
5779 putRequiresPreciseMemExns)
sewardjc4356f02007-11-09 21:15:04 +00005780 /* probably overly conservative: a memory bus event
sewardj3e838932005-01-07 12:09:15 +00005781 invalidates absolutely everything, so that all
5782 computation prior to it is forced to complete before
sewardjc4356f02007-11-09 21:15:04 +00005783 proceeding with the event (fence,lock,unlock). */
5784 || st->tag == Ist_MBE
sewardj5a9ffab2005-05-12 17:55:01 +00005785 /* also be (probably overly) paranoid re AbiHints */
5786 || st->tag == Ist_AbiHint
sewardj9d2e7692005-02-07 01:11:31 +00005787 );
sewardjf9517d02005-11-28 13:39:37 +00005788 if (invalidateMe) {
sewardjdd40fdf2006-12-24 02:20:24 +00005789 bb->stmts[j] = IRStmt_WrTmp( env[k].binder, env[k].bindee );
sewardjf9517d02005-11-28 13:39:37 +00005790 j++;
5791 vassert(j <= i);
5792 env[k].bindee = NULL;
5793 }
sewardj29632392004-08-22 02:38:11 +00005794 }
5795
sewardjf9517d02005-11-28 13:39:37 +00005796 /* Slide in-use entries in env up to the front */
5797 m = 0;
5798 for (k = 0; k < A_NENV; k++) {
5799 if (env[k].bindee != NULL) {
5800 env[m] = env[k];
5801 m++;
5802 }
5803 }
5804 for (m = m; m < A_NENV; m++) {
5805 env[m].bindee = NULL;
5806 }
sewardj29632392004-08-22 02:38:11 +00005807
5808 /* finally, emit the substituted statement */
5809 bb->stmts[j] = st2;
sewardjf9517d02005-11-28 13:39:37 +00005810 /* vex_printf("**2 "); ppIRStmt(bb->stmts[j]); vex_printf("\n"); */
sewardj29632392004-08-22 02:38:11 +00005811 j++;
5812
5813 vassert(j <= i+1);
5814 } /* for each stmt in the original bb ... */
5815
5816 /* Finally ... substitute the ->next field as much as possible, and
5817 dump any left-over bindings. Hmm. Perhaps there should be no
5818 left over bindings? Or any left-over bindings are
5819 by definition dead? */
sewardjf9517d02005-11-28 13:39:37 +00005820 bb->next = atbSubst_Expr(env, bb->next);
sewardj29632392004-08-22 02:38:11 +00005821 bb->stmts_used = j;
sewardjc6f970f2012-04-02 21:54:49 +00005822
5823 return max_ga_known ? max_ga : ~(Addr64)0;
sewardj29632392004-08-22 02:38:11 +00005824}
5825
5826
sewardj695cff92004-10-13 14:50:14 +00005827/*---------------------------------------------------------------*/
sewardjedf4d692004-08-17 13:52:58 +00005828/*--- iropt main ---*/
5829/*---------------------------------------------------------------*/
5830
sewardjb183b852006-02-03 16:08:03 +00005831static Bool iropt_verbose = False; /* True; */
sewardj4345f7a2004-09-22 19:49:27 +00005832
5833
sewardj4345f7a2004-09-22 19:49:27 +00005834/* Do a simple cleanup pass on bb. This is: redundant Get removal,
5835 redundant Put removal, constant propagation, dead code removal,
5836 clean helper specialisation, and dead code removal (again).
sewardjb9230752004-12-29 19:25:06 +00005837*/
sewardj695cff92004-10-13 14:50:14 +00005838
sewardj4345f7a2004-09-22 19:49:27 +00005839
5840static
sewardjdd40fdf2006-12-24 02:20:24 +00005841IRSB* cheap_transformations (
5842 IRSB* bb,
florian1ff47562012-10-21 02:09:51 +00005843 IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int),
sewardj8d2291c2004-10-25 14:50:21 +00005844 Bool (*preciseMemExnsFn)(Int,Int)
5845 )
sewardj4345f7a2004-09-22 19:49:27 +00005846{
5847 redundant_get_removal_BB ( bb );
5848 if (iropt_verbose) {
5849 vex_printf("\n========= REDUNDANT GET\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005850 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005851 }
sewardj044a2152004-10-21 10:22:10 +00005852
philippe6c46bef2012-08-14 22:29:01 +00005853 if (vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn) {
philippec8e2f982012-08-01 22:04:13 +00005854 redundant_put_removal_BB ( bb, preciseMemExnsFn );
5855 }
sewardj4345f7a2004-09-22 19:49:27 +00005856 if (iropt_verbose) {
5857 vex_printf("\n========= REDUNDANT PUT\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005858 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005859 }
sewardj044a2152004-10-21 10:22:10 +00005860
sewardj4345f7a2004-09-22 19:49:27 +00005861 bb = cprop_BB ( bb );
5862 if (iropt_verbose) {
5863 vex_printf("\n========= CPROPD\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005864 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005865 }
5866
sewardj49651f42004-10-28 22:11:04 +00005867 do_deadcode_BB ( bb );
sewardj4345f7a2004-09-22 19:49:27 +00005868 if (iropt_verbose) {
5869 vex_printf("\n========= DEAD\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005870 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005871 }
5872
sewardjb9230752004-12-29 19:25:06 +00005873 bb = spec_helpers_BB ( bb, specHelper );
sewardj49651f42004-10-28 22:11:04 +00005874 do_deadcode_BB ( bb );
sewardj4345f7a2004-09-22 19:49:27 +00005875 if (iropt_verbose) {
5876 vex_printf("\n========= SPECd \n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00005877 ppIRSB(bb);
sewardj4345f7a2004-09-22 19:49:27 +00005878 }
5879
5880 return bb;
5881}
5882
sewardj695cff92004-10-13 14:50:14 +00005883
5884/* Do some more expensive transformations on bb, which are aimed at
5885 optimising as much as possible in the presence of GetI and PutI. */
5886
5887static
sewardjdd40fdf2006-12-24 02:20:24 +00005888IRSB* expensive_transformations( IRSB* bb )
sewardj695cff92004-10-13 14:50:14 +00005889{
sewardj9b0cc582006-02-04 15:24:00 +00005890 (void)do_cse_BB( bb );
sewardj695cff92004-10-13 14:50:14 +00005891 collapse_AddSub_chains_BB( bb );
sewardj08210532004-12-29 17:09:11 +00005892 do_redundant_GetI_elimination( bb );
philippe6c46bef2012-08-14 22:29:01 +00005893 if (vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn) {
philippec8e2f982012-08-01 22:04:13 +00005894 do_redundant_PutI_elimination( bb );
5895 }
sewardj49651f42004-10-28 22:11:04 +00005896 do_deadcode_BB( bb );
sewardjb9230752004-12-29 19:25:06 +00005897 return bb;
sewardj695cff92004-10-13 14:50:14 +00005898}
5899
5900
sewardjb183b852006-02-03 16:08:03 +00005901/* Scan a flattened BB to look for signs that more expensive
5902 optimisations might be useful:
5903 - find out if there are any GetIs and PutIs
5904 - find out if there are any floating or vector-typed temporaries
5905*/
sewardj695cff92004-10-13 14:50:14 +00005906
sewardjb183b852006-02-03 16:08:03 +00005907static void considerExpensives ( /*OUT*/Bool* hasGetIorPutI,
5908 /*OUT*/Bool* hasVorFtemps,
sewardjdd40fdf2006-12-24 02:20:24 +00005909 IRSB* bb )
sewardj4345f7a2004-09-22 19:49:27 +00005910{
sewardje9d8a262009-07-01 08:06:34 +00005911 Int i, j;
5912 IRStmt* st;
sewardj4345f7a2004-09-22 19:49:27 +00005913 IRDirty* d;
sewardje9d8a262009-07-01 08:06:34 +00005914 IRCAS* cas;
sewardj4345f7a2004-09-22 19:49:27 +00005915
sewardjb183b852006-02-03 16:08:03 +00005916 *hasGetIorPutI = False;
5917 *hasVorFtemps = False;
5918
sewardj4345f7a2004-09-22 19:49:27 +00005919 for (i = 0; i < bb->stmts_used; i++) {
5920 st = bb->stmts[i];
sewardj4345f7a2004-09-22 19:49:27 +00005921 switch (st->tag) {
sewardj5a9ffab2005-05-12 17:55:01 +00005922 case Ist_AbiHint:
5923 vassert(isIRAtom(st->Ist.AbiHint.base));
sewardj478646f2008-05-01 20:13:04 +00005924 vassert(isIRAtom(st->Ist.AbiHint.nia));
sewardj5a9ffab2005-05-12 17:55:01 +00005925 break;
sewardj4345f7a2004-09-22 19:49:27 +00005926 case Ist_PutI:
sewardjb183b852006-02-03 16:08:03 +00005927 *hasGetIorPutI = True;
5928 break;
sewardjdd40fdf2006-12-24 02:20:24 +00005929 case Ist_WrTmp:
5930 if (st->Ist.WrTmp.data->tag == Iex_GetI)
sewardjb183b852006-02-03 16:08:03 +00005931 *hasGetIorPutI = True;
sewardjdd40fdf2006-12-24 02:20:24 +00005932 switch (typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp)) {
sewardjb183b852006-02-03 16:08:03 +00005933 case Ity_I1: case Ity_I8: case Ity_I16:
5934 case Ity_I32: case Ity_I64: case Ity_I128:
5935 break;
sewardjc4530ae2012-05-21 10:18:49 +00005936 case Ity_F32: case Ity_F64: case Ity_F128:
5937 case Ity_V128: case Ity_V256:
sewardjb183b852006-02-03 16:08:03 +00005938 *hasVorFtemps = True;
5939 break;
sewardjc6bbd472012-04-02 10:20:48 +00005940 case Ity_D32: case Ity_D64: case Ity_D128:
5941 *hasVorFtemps = True;
5942 break;
sewardjb183b852006-02-03 16:08:03 +00005943 default:
5944 goto bad;
5945 }
sewardj4345f7a2004-09-22 19:49:27 +00005946 break;
5947 case Ist_Put:
sewardj496a58d2005-03-20 18:44:44 +00005948 vassert(isIRAtom(st->Ist.Put.data));
sewardj4345f7a2004-09-22 19:49:27 +00005949 break;
sewardjaf1ceca2005-06-30 23:31:27 +00005950 case Ist_Store:
5951 vassert(isIRAtom(st->Ist.Store.addr));
5952 vassert(isIRAtom(st->Ist.Store.data));
sewardj4345f7a2004-09-22 19:49:27 +00005953 break;
sewardjcfe046e2013-01-17 14:23:53 +00005954 case Ist_StoreG: {
5955 IRStoreG* sg = st->Ist.StoreG.details;
5956 vassert(isIRAtom(sg->addr));
5957 vassert(isIRAtom(sg->data));
5958 vassert(isIRAtom(sg->guard));
5959 break;
5960 }
5961 case Ist_LoadG: {
5962 IRLoadG* lg = st->Ist.LoadG.details;
5963 vassert(isIRAtom(lg->addr));
5964 vassert(isIRAtom(lg->alt));
5965 vassert(isIRAtom(lg->guard));
5966 break;
5967 }
sewardje9d8a262009-07-01 08:06:34 +00005968 case Ist_CAS:
5969 cas = st->Ist.CAS.details;
5970 vassert(isIRAtom(cas->addr));
5971 vassert(cas->expdHi == NULL || isIRAtom(cas->expdHi));
5972 vassert(isIRAtom(cas->expdLo));
5973 vassert(cas->dataHi == NULL || isIRAtom(cas->dataHi));
5974 vassert(isIRAtom(cas->dataLo));
5975 break;
sewardje768e922009-11-26 17:17:37 +00005976 case Ist_LLSC:
5977 vassert(isIRAtom(st->Ist.LLSC.addr));
5978 if (st->Ist.LLSC.storedata)
5979 vassert(isIRAtom(st->Ist.LLSC.storedata));
5980 break;
sewardj4345f7a2004-09-22 19:49:27 +00005981 case Ist_Dirty:
5982 d = st->Ist.Dirty.details;
sewardj496a58d2005-03-20 18:44:44 +00005983 vassert(isIRAtom(d->guard));
sewardj74142b82013-08-08 10:28:59 +00005984 for (j = 0; d->args[j]; j++) {
5985 IRExpr* arg = d->args[j];
florian90419562013-08-15 20:54:52 +00005986 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +00005987 vassert(isIRAtom(arg));
5988 }
sewardj4345f7a2004-09-22 19:49:27 +00005989 if (d->mFx != Ifx_None)
sewardj496a58d2005-03-20 18:44:44 +00005990 vassert(isIRAtom(d->mAddr));
sewardj4345f7a2004-09-22 19:49:27 +00005991 break;
sewardjd2445f62005-03-21 00:15:53 +00005992 case Ist_NoOp:
sewardjf1689312005-03-16 18:19:10 +00005993 case Ist_IMark:
sewardjc4356f02007-11-09 21:15:04 +00005994 case Ist_MBE:
sewardj3e838932005-01-07 12:09:15 +00005995 break;
5996 case Ist_Exit:
sewardj496a58d2005-03-20 18:44:44 +00005997 vassert(isIRAtom(st->Ist.Exit.guard));
sewardj3e838932005-01-07 12:09:15 +00005998 break;
sewardj4345f7a2004-09-22 19:49:27 +00005999 default:
sewardjb183b852006-02-03 16:08:03 +00006000 bad:
sewardj4345f7a2004-09-22 19:49:27 +00006001 ppIRStmt(st);
sewardje768e922009-11-26 17:17:37 +00006002 vpanic("considerExpensives");
sewardj4345f7a2004-09-22 19:49:27 +00006003 }
sewardj4345f7a2004-09-22 19:49:27 +00006004 }
sewardj4345f7a2004-09-22 19:49:27 +00006005}
6006
6007
sewardj695cff92004-10-13 14:50:14 +00006008/* ---------------- The main iropt entry point. ---------------- */
6009
sewardjedf4d692004-08-17 13:52:58 +00006010/* exported from this file */
sewardj695cff92004-10-13 14:50:14 +00006011/* Rules of the game:
6012
6013 - IRExpr/IRStmt trees should be treated as immutable, as they
6014 may get shared. So never change a field of such a tree node;
6015 instead construct and return a new one if needed.
6016*/
6017
sewardj4345f7a2004-09-22 19:49:27 +00006018
sewardjbe917912010-08-22 12:38:53 +00006019IRSB* do_iropt_BB(
6020 IRSB* bb0,
florian1ff47562012-10-21 02:09:51 +00006021 IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int),
sewardjbe917912010-08-22 12:38:53 +00006022 Bool (*preciseMemExnsFn)(Int,Int),
6023 Addr64 guest_addr,
6024 VexArch guest_arch
6025 )
sewardjedf4d692004-08-17 13:52:58 +00006026{
sewardj9d2e7692005-02-07 01:11:31 +00006027 static Int n_total = 0;
6028 static Int n_expensive = 0;
sewardj29632392004-08-22 02:38:11 +00006029
sewardjb183b852006-02-03 16:08:03 +00006030 Bool hasGetIorPutI, hasVorFtemps;
sewardjdd40fdf2006-12-24 02:20:24 +00006031 IRSB *bb, *bb2;
sewardj8c2c10b2004-10-16 20:51:52 +00006032
sewardj4345f7a2004-09-22 19:49:27 +00006033 n_total++;
6034
6035 /* First flatten the block out, since all other
6036 phases assume flat code. */
6037
6038 bb = flatten_BB ( bb0 );
6039
6040 if (iropt_verbose) {
6041 vex_printf("\n========= FLAT\n\n" );
sewardjdd40fdf2006-12-24 02:20:24 +00006042 ppIRSB(bb);
sewardj84be7372004-08-18 13:59:33 +00006043 }
sewardjd7217032004-08-19 10:49:10 +00006044
sewardj08210532004-12-29 17:09:11 +00006045 /* If at level 0, stop now. */
6046 if (vex_control.iropt_level <= 0) return bb;
6047
sewardj695cff92004-10-13 14:50:14 +00006048 /* Now do a preliminary cleanup pass, and figure out if we also
6049 need to do 'expensive' optimisations. Expensive optimisations
6050 are deemed necessary if the block contains any GetIs or PutIs.
6051 If needed, do expensive transformations and then another cheap
6052 cleanup pass. */
sewardj4345f7a2004-09-22 19:49:27 +00006053
sewardj8d2291c2004-10-25 14:50:21 +00006054 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj695cff92004-10-13 14:50:14 +00006055
sewardjbe917912010-08-22 12:38:53 +00006056 if (guest_arch == VexArchARM) {
6057 /* Translating Thumb2 code produces a lot of chaff. We have to
6058 work extra hard to get rid of it. */
6059 bb = cprop_BB(bb);
6060 bb = spec_helpers_BB ( bb, specHelper );
philippe6c46bef2012-08-14 22:29:01 +00006061 if (vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn) {
philippec8e2f982012-08-01 22:04:13 +00006062 redundant_put_removal_BB ( bb, preciseMemExnsFn );
6063 }
sewardjd5436ce2011-05-01 18:36:51 +00006064 do_cse_BB( bb );
sewardjbe917912010-08-22 12:38:53 +00006065 do_deadcode_BB( bb );
6066 }
6067
sewardj08613742004-10-25 13:01:45 +00006068 if (vex_control.iropt_level > 1) {
sewardjb183b852006-02-03 16:08:03 +00006069
6070 /* Peer at what we have, to decide how much more effort to throw
6071 at it. */
6072 considerExpensives( &hasGetIorPutI, &hasVorFtemps, bb );
6073
sewardj9b0cc582006-02-04 15:24:00 +00006074 if (hasVorFtemps && !hasGetIorPutI) {
sewardjb183b852006-02-03 16:08:03 +00006075 /* If any evidence of FP or Vector activity, CSE, as that
6076 tends to mop up all manner of lardy code to do with
sewardj9b0cc582006-02-04 15:24:00 +00006077 rounding modes. Don't bother if hasGetIorPutI since that
6078 case leads into the expensive transformations, which do
6079 CSE anyway. */
6080 (void)do_cse_BB( bb );
sewardjb183b852006-02-03 16:08:03 +00006081 do_deadcode_BB( bb );
6082 }
6083
6084 if (hasGetIorPutI) {
sewardj9b0cc582006-02-04 15:24:00 +00006085 Bool cses;
sewardj39555aa2004-10-24 22:29:19 +00006086 n_expensive++;
sewardj39555aa2004-10-24 22:29:19 +00006087 if (DEBUG_IROPT)
6088 vex_printf("***** EXPENSIVE %d %d\n", n_total, n_expensive);
sewardj695cff92004-10-13 14:50:14 +00006089 bb = expensive_transformations( bb );
sewardj8d2291c2004-10-25 14:50:21 +00006090 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj9b0cc582006-02-04 15:24:00 +00006091 /* Potentially common up GetIs */
6092 cses = do_cse_BB( bb );
6093 if (cses)
6094 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj695cff92004-10-13 14:50:14 +00006095 }
sewardj39555aa2004-10-24 22:29:19 +00006096
6097 /* Now have a go at unrolling simple (single-BB) loops. If
6098 successful, clean up the results as much as possible. */
6099
6100 bb2 = maybe_loop_unroll_BB( bb, guest_addr );
6101 if (bb2) {
sewardj8d2291c2004-10-25 14:50:21 +00006102 bb = cheap_transformations( bb2, specHelper, preciseMemExnsFn );
sewardjb183b852006-02-03 16:08:03 +00006103 if (hasGetIorPutI) {
sewardj39555aa2004-10-24 22:29:19 +00006104 bb = expensive_transformations( bb );
sewardj8d2291c2004-10-25 14:50:21 +00006105 bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
sewardj39555aa2004-10-24 22:29:19 +00006106 } else {
6107 /* at least do CSE and dead code removal */
sewardjfe1ccfc2004-11-11 02:14:45 +00006108 do_cse_BB( bb );
sewardj49651f42004-10-28 22:11:04 +00006109 do_deadcode_BB( bb );
sewardj39555aa2004-10-24 22:29:19 +00006110 }
6111 if (0) vex_printf("vex iropt: unrolled a loop\n");
6112 }
6113
sewardjd7217032004-08-19 10:49:10 +00006114 }
6115
sewardj4345f7a2004-09-22 19:49:27 +00006116 return bb;
sewardjedf4d692004-08-17 13:52:58 +00006117}
6118
6119
sewardja1a370f2004-08-17 13:31:55 +00006120/*---------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +00006121/*--- end ir_opt.c ---*/
sewardja1a370f2004-08-17 13:31:55 +00006122/*---------------------------------------------------------------*/