Bug Summary

File:src/of_emerg.c
Warning:line 1283, column 2
Value stored to 'isCircular' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name of_emerg.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/kfp/aldor/aldor/aldor/src -fcoverage-compilation-dir=/home/kfp/aldor/aldor/aldor/src -resource-dir /usr/local/lib/clang/18 -D PACKAGE_NAME="aldor" -D PACKAGE_TARNAME="aldor" -D PACKAGE_VERSION="1.4.0" -D PACKAGE_STRING="aldor 1.4.0" -D PACKAGE_BUGREPORT="aldor@xinutec.org" -D PACKAGE_URL="" -D PACKAGE="aldor" -D VERSION="1.4.0" -D YYTEXT_POINTER=1 -D HAVE_STDIO_H=1 -D HAVE_STDLIB_H=1 -D HAVE_STRING_H=1 -D HAVE_INTTYPES_H=1 -D HAVE_STDINT_H=1 -D HAVE_STRINGS_H=1 -D HAVE_SYS_STAT_H=1 -D HAVE_SYS_TYPES_H=1 -D HAVE_UNISTD_H=1 -D STDC_HEADERS=1 -D HAVE_LIBREADLINE=1 -D HAVE_READLINE_READLINE_H=1 -D HAVE_READLINE_HISTORY=1 -D HAVE_READLINE_HISTORY_H=1 -D USE_GLOOP_SHELL=1 -D GENERATOR_COROUTINES=0 -D HAVE_DLFCN_H=1 -D LT_OBJDIR=".libs/" -I . -D VCSVERSION="2c53e759f1e00e345f8b172e7139debda72fda13" -internal-isystem /usr/local/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-empty-body -Wno-enum-compare -Wno-missing-field-initializers -Wno-unused -Wno-unused-parameter -Wno-error=format -Wno-error=type-limits -Wno-error=strict-aliasing -Wno-sign-compare -Wno-error=shift-negative-value -Wno-error=clobbered -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2026-01-15-223856-845667-1 -x c of_emerg.c
1/*****************************************************************************
2 *
3 * of_emerg.c: Environment merging.
4 *
5 * Copyright (c) 1990-2007 Aldor Software Organization Ltd (Aldor.org).
6 *
7 ****************************************************************************/
8
9/*
10 * This file implements data structure merging.
11 *
12 * Environment merging destructively modifies a foam unit by replacing
13 * heap allocated storage by stack allocated storage when it can.
14 *
15 * emerge knows about four ways of creating new storage:
16 * FOAM_RNew -- create a new record.
17 * FOAM_PushEnv -- create a new lexical environment level.
18 * FOAM_ANew -- create a new array.
19 * procedure entry -- create a new lexical environment level.
20 *
21 * and one way of explicitly releasing allocated storage:
22 * FOAM_Free
23 *
24 * For each of these types of storage we analyze whether or not it escapes.
25 * A piece of storage is deemed to escape if we pass it to another function,
26 * it is returned from the function or it is pointed to by another structure
27 * which escapes.
28 *
29 * [Actually we don't mind if it is returned from a function]
30 *
31 * Once we determine that a structure does not escape (and for arrays that
32 * it indexed only by constant values), then we replace all the elements
33 * of the structure with local variables. We make sure that all local
34 * variables that are aliased to non-escaping storage get expanded too.
35 *
36 * To Do:
37 * Get rid of -Wemerge-noalias option
38 * New environments: FOAM_TRNew, FOAM_IRElt, FOAM_TRElt
39 * Better flow anlysis.
40 * [ More acurately determine when variables alias each other.
41 * The analysis is currently too conservative, and will not merge
42 * variables which are multiply aliased, but these can be merged
43 * if they are not side-effected. ] TTT does not think we need
44 * better flow analysis here. If we do the expanding properly
45 * (which TTT thinks we do), other later optimisations will clean
46 * up after us.
47 */
48
49#include "debug.h"
50#include "of_deadv.h"
51#include "of_util.h"
52#include "store.h"
53#include "syme.h"
54#include "sexpr.h"
55
56Bool emergeDebug = false((int) 0);
57#define emergeDEBUGif (!emergeDebug) { } else afprintf DEBUG_IF(emerge)if (!emergeDebug) { } else afprintf
58
59typedef enum emUsageState {
60 EM_DontKnow, /* what we start with */
61 EM_NotEnv, /* Not a candidate for merging */
62 EM_EscapingEnv, /* A candidate, but environment escapes */
63 EM_NonEscapingEnv, /* A candidate which doesn't escape */
64 EM_AliasNonEsc /* is used as an alias of non-escaping env */
65} EmUsageState;
66
67typedef struct emUsage {
68 EmUsageState used; /* Usage flag */
69 int format; /* format of env (size of array) */
70 Foam type; /* Foam instruction creating env */
71 Foam decl; /* Foam decl for this variable */
72 Foam *remap; /* Vector of remaps to locals */
73 BPack(Bool)UByte mark; /* mark for detecting circular links */
74 BPack(Bool)UByte isSet; /* has an assignment been seen? */
75 struct emUsage *link; /* for following aliases of locals */
76} *EmUsage;
77
78localstatic void emMergeDefs (Foam defs);
79localstatic void emMergeProg (Foam prog);
80localstatic EmUsage emMakeUsageVec (Foam ddecl);
81localstatic void emMarkUsage (Foam expr);
82localstatic void emMarkLocal (Foam loc);
83localstatic void emMarkDef (Foam def);
84localstatic void emMarkParents (Foam);
85localstatic void emMarkCallArgs (Length argc, Foam *argv);
86localstatic void emMarkClos (Foam clos);
87localstatic void emMarkGener (Foam gener);
88localstatic void emMarkAElt (Foam aelt);
89localstatic void emMarkRElt (Foam aelt);
90localstatic void emMarkRRElt (Foam aelt);
91localstatic Bool emCheckRElt (Foam relt, int fmt);
92localstatic void emComputeRemap (Foam prog);
93localstatic void emRemapEnv0 (EmUsage, EmUsage);
94localstatic void emMergeEnv (int n, Bool);
95localstatic void emMergeArray (int n, Foam, Bool);
96localstatic Foam emNewBody (void);
97localstatic void emAddStmt (Foam stmt);
98localstatic void emMakeNewLocals (Foam prog);
99localstatic void emMergeEnvs (Foam prog);
100localstatic Foam emMergeDef (Foam def);
101localstatic Foam emNewEnvSet (Foam def, Foam lhs, Foam rhs);
102localstatic Foam emMergeExpr (Foam expr);
103localstatic Foam emMergeRElt (Foam expr, Foam env, int index);
104localstatic Foam emMergeEElt (Foam expr, Foam env, int index);
105localstatic Foam emMergeLex (Foam lex);
106localstatic Foam emMergeEEnv (Foam eenv);
107localstatic Foam emMergeFree (Foam foam);
108localstatic Foam emMergeReturn (Foam expr);
109localstatic Foam emMergeYield (Foam expr);
110localstatic Foam emMergeAElt (Foam aelt);
111localstatic EmUsage emUsageAliasing (Foam loc);
112localstatic EmUsage emUsage (Foam foam);
113localstatic EmUsage emUsageFromLocalIndexAliasing (long index);
114localstatic EmUsage emUsageFromLocalIndex(long index);
115localstatic long emIndexFromUsage (EmUsage u);
116
117localstatic void emCopyUsedTagsTo (EmUsageState *arr);
118localstatic Bool emUsedTagsChanged (EmUsageState *arr);
119localstatic void emNormaliseUsage (void);
120localstatic void emCleanTypeUsage (void);
121localstatic void emNewParentTable (void);
122localstatic void emFreeParentTable (void);
123localstatic void emSetParent (Foam child, Foam parent);
124localstatic Foam emGetParent (Foam child);
125localstatic Foam emGetNthParent (Foam child, int *level);
126localstatic Foam emUnEEnv (Foam foam);
127
128Bool emChanged; /* True iff the unit changed. */
129EmUsage emLocalUsage; /* Local usage vector for a prog. */
130int emNumLocals; /* Number of locals in the prog */
131int emOrigNumLocals; /* Number of locals before merging */
132FoamList emNewLocals; /* Decls of locals added to prog. */
133FoamList emStmtList; /* Statements added to prog. */
134Foam *emFormats; /* Formats for the unit. */
135int emCount; /* how many times are we merging */
136int emDefNo; /* the current definition index being processed */
137
138Bool emNoAlias = false((int) 0); /* Avoid alias code for non-envs */
139
140
141/*****************************************************************************
142 *
143 * :: Macros
144 *
145 ****************************************************************************/
146
147#define emIsArray(foam)((foam) && ((foam)->hdr.tag) == FOAM_ANew) ((foam) && foamTag(foam)((foam)->hdr.tag) == FOAM_ANew)
148
149#define emOldLocal(i)(((i)->hdr.tag) != FOAM_Loc || ((i)->foamLoc.index <
emOrigNumLocals))
(foamTag(i)((i)->hdr.tag) != FOAM_Loc || \
150 ((i)->foamLoc.index < emOrigNumLocals))
151
152/*****************************************************************************
153 *
154 * :: Main code
155 *
156 ****************************************************************************/
157
158void
159emSetNoAlias()
160{
161 emNoAlias = true1;
162}
163
164
165/*
166 * Merge environments until no more merging is possible.
167 * We use emCount
168 */
169void
170emMergeUnit(Foam unit)
171{
172 assert(foamTag(unit) == FOAM_Unit)do { if (!(((unit)->hdr.tag) == FOAM_Unit)) _do_assert(("foamTag(unit) == FOAM_Unit"
),"of_emerg.c",172); } while (0)
;
173 emFormats = unit->foamUnit.formats->foamDFmt.argv;
174 emChanged = true1;
175
176 for (emCount = 0; emChanged && emCount < 10 ; emCount++) {
177 dvElim(unit);
178 emChanged = false((int) 0);
179 emMergeDefs(unit->foamUnit.defs);
180 }
181
182 assert(foamAudit(unit))do { if (!(foamAudit(unit))) _do_assert(("foamAudit(unit)"),"of_emerg.c"
,182); } while (0)
;
183}
184
185/*
186 * For each program definition in a unit, merge it.
187 */
188
189int emDebugDefNo = -1; /* this is useful when debugging a perticular prog */
190
191localstatic void
192emMergeDefs(Foam defs)
193{
194
195 for(emDefNo =0; emDefNo<foamArgc(defs)((defs)->hdr.argc); emDefNo++) {
196 Foam def = defs->foamDDef.argv[emDefNo];
197 Foam prog;
198
199/* #if 0*/ /* enable this if you want to see in-out foam when debugging */
200 if (DEBUG(emerge)emergeDebug) {
201 if (emDebugDefNo == -1 || emDefNo == emDebugDefNo) {
202 fprintf(dbOut, "Prog--index%d--count%d<<\n",emDefNo,emCount);
203 foamPrintDb(def);
204 }
205 }
206/* #endif */
207 assert(foamTag(def) == FOAM_Def)do { if (!(((def)->hdr.tag) == FOAM_Def)) _do_assert(("foamTag(def) == FOAM_Def"
),"of_emerg.c",207); } while (0)
;
208 prog = def->foamDef.rhs;
209 if (foamTag(prog)((prog)->hdr.tag) == FOAM_Prog)
210 emMergeProg(prog);
211
212/* #if 0*/ /* enable this if you want to see in-out foam when debugging */
213 if (DEBUG(emerge)emergeDebug) {
214 if (emDebugDefNo == -1 || emDefNo == emDebugDefNo) {
215 fprintf(dbOut, "Prog--index%d--count%d>>\n",emDefNo,emCount);
216 foamPrintDb(def);
217 }
218 }
219/* #endif */
220 }
221}
222
223
224/*
225 * Merge the environments for a single program.
226 */
227localstatic void
228emMergeProg(Foam prog)
229{
230 int emMarkCount = 1 ;
231 EmUsageState * usedArray;
232 emLocalUsage = emMakeUsageVec(prog->foamProg.locals);
233 emOrigNumLocals = foamDDeclArgc(prog->foamProg.locals)(((prog->foamProg.locals)->hdr.argc) - (1));
234
235 /* previously on ER ... , no seriously, this keeps all the used
236 tags from the previous marking run */
237 usedArray = (EmUsageState *) stoAlloc(OB_Other0, (emOrigNumLocals+1) * sizeof(EmUsageState));
238
239 emLocalUsage->format = prog->foamProg.levels->foamDEnv.argv[0];
240 emNewParentTable();
241
242 emMarkUsage(prog->foamProg.body); /*first time */
243 emCopyUsedTagsTo(usedArray);
244
245 for ( ; emMarkCount<10 ;emMarkCount++) {
246 emCleanTypeUsage();
247 emMarkUsage(prog->foamProg.body);
248 if ( ! emUsedTagsChanged(usedArray) ) break;
249 emCopyUsedTagsTo(usedArray);
250 }
251
252 emComputeRemap(prog);
253
254#if 0 /* enable this if you want to see in-out sets when debugging */
255 emergeDEBUGif (!emergeDebug) { } else afprintf(dbOut, "Pass:%2d Prog:%2d #locals:(%3d -> %3d)\n",
256 emCount, emDefNo,emOrigNumLocals, emNumLocals);
257#endif
258 if (!emChanged) return;
259
260 /* now that the marking is done we can get rid of all links
261 except to non-escaped storage */
262 emNormaliseUsage();
263
264 emMergeEnvs(prog);
265
266 if (emLocalUsage->used == EM_NonEscapingEnv)
267 prog->foamProg.levels->foamDEnv.argv[0] = emptyFormatSlot4;
268 emFreeParentTable();
269}
270
271
272/*
273 * Make an empty usage vector for the locals in a program.
274 */
275localstatic EmUsage
276emMakeUsageVec(Foam ddecl)
277{
278 int i, size;
279 EmUsage emu;
280
281 assert(foamTag(ddecl) == FOAM_DDecl)do { if (!(((ddecl)->hdr.tag) == FOAM_DDecl)) _do_assert((
"foamTag(ddecl) == FOAM_DDecl"),"of_emerg.c",281); } while (0
)
;
282 size = foamDDeclArgc(ddecl)(((ddecl)->hdr.argc) - (1)) + 1; /* +1 for Env(0) */
283 emu = (EmUsage) stoAlloc(OB_Other0, size*sizeof(struct emUsage));
284
285 for(i=0; i < size; i++ ) {
286 emu[i].used = EM_DontKnow;
287 emu[i].remap = 0;
288 emu[i].link = 0;
289 emu[i].mark = 0;
290 emu[i].type = 0;
291 emu[i].decl = NULL((void*)0);
292 emu[i].isSet = false((int) 0);
293 emu[i].format = emptyFormatSlot4;
294 }
295 emu[0].used = EM_NonEscapingEnv; /* for Env(0) */
296 emu[0].decl = NULL((void*)0);
297 for (i=0; i<foamDDeclArgc(ddecl)(((ddecl)->hdr.argc) - (1)); i++) {
298 emu[i+1].decl = ddecl->foamDDecl.argv[i];
299 }
300 return emu;
301}
302
303
304/*
305 * Traverse an arbitrary Foam expression, looking for environment usage,
306 * and marking escaping environments.
307 */
308localstatic void
309emMarkUsage(Foam expr)
310{
311 Foam *argv;
312 int argc;
313
314 foamIter(expr, arg, emMarkUsage(*arg)){ { String argf = (foamInfoTable [(int)(((expr)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((expr
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((expr)->foamGen.argv
)+_i; { emMarkUsage(*arg); }; } } }; }
;
315
316 switch(foamTag(expr)((expr)->hdr.tag)) {
317 case FOAM_Set:
318 case FOAM_Def:
319 emMarkDef(expr);
320 return;
321 case FOAM_AElt:
322 emMarkAElt(expr);
323 return;
324 case FOAM_RElt:
325 emMarkRElt(expr);
326 return;
327 case FOAM_RRElt:
328 emMarkRRElt(expr);
329 return;
330 case FOAM_OCall: {
331 Foam env = expr->foamOCall.env;
332 emMarkLocal(env);
333 argv = expr->foamOCall.argv;
334 argc = foamOCallArgc(expr)(((expr)->hdr.argc) - (3));
335 break; }
336 case FOAM_CCall:
337 argv = expr->foamCCall.argv;
338 argc = foamCCallArgc(expr)(((expr)->hdr.argc) - (2) );
339 break;
340 case FOAM_PCall:
341 argv = expr->foamPCall.argv;
342 argc = foamPCallArgc(expr)(((expr)->hdr.argc) - (3));
343 break;
344 case FOAM_BCall:
345 argv = expr->foamBCall.argv;
346 argc = foamBCallArgc(expr)(((expr)->hdr.argc) - (1));
347 break;
348 case FOAM_Clos:
349 emMarkClos(expr);
350 return;
351 case FOAM_Gener:
352 emMarkGener(expr);
353 return;
354 case FOAM_Yield:
355 emMarkLocal(expr->foamYield.value);
356 return;
357 case FOAM_Return:
358 /*!! need to write a copy on returner! */
359 emMarkLocal(expr->foamReturn.value);
360 return;
361 default:
362 return;
363 }
364 emMarkCallArgs(argc, argv);
365}
366
367#define emIsMergeable(x)(((x)->hdr.tag) == FOAM_Loc || (((x)->hdr.tag) == FOAM_Env
&& (x)->foamEnv.level == 0))
\
368 (foamTag(x)((x)->hdr.tag) == FOAM_Loc || (foamTag(x)((x)->hdr.tag) == FOAM_Env && \
369 (x)->foamEnv.level == 0))
370
371/*
372 * Mark a local as an escaping environment, traversing alias links.
373 */
374localstatic void
375emMarkLocal(Foam var)
376{
377 Foam nvar;
378 EmUsage u;
379
380 foamDereferenceCast(var)while (((var)->hdr.tag) == FOAM_Cast) (var) = (var)->foamCast
.expr;
;
381
382 if (foamTag(var)((var)->hdr.tag) == FOAM_Values) {
383 int i;
384 for(i=0; i<foamArgc(var)((var)->hdr.argc); i++)
385 emMarkLocal(var->foamValues.argv[i]);
386 return;
387 }
388
389 nvar = emUnEEnv(var);
390 if (nvar != var) emChanged = true1;
391
392 do {
393 foamDereferenceCast(nvar)while (((nvar)->hdr.tag) == FOAM_Cast) (nvar) = (nvar)->
foamCast.expr;
;
394
395 if (emIsMergeable(nvar)(((nvar)->hdr.tag) == FOAM_Loc || (((nvar)->hdr.tag) ==
FOAM_Env && (nvar)->foamEnv.level == 0))
) {
396 /* modify the used field of the actual storage */
397 u = emUsageAliasing(nvar);
398 u->used = EM_EscapingEnv;
399 }
400 nvar = emGetParent(nvar);
401 } while(nvar);
402}
403
404/*
405 * Predicate identifying the foam instructions which create environmnets.
406 */
407#define emIsMergingCandidate(foam)(((foam)->hdr.tag) == FOAM_RNew || ((foam)->hdr.tag) ==
FOAM_PushEnv || (((foam)->hdr.tag) == FOAM_ANew &&
(((foam->foamANew.size)->hdr.tag) == FOAM_SInt || (((foam
->foamANew.size)->hdr.tag) == FOAM_Cast && ((foam
->foamANew.size->foamCast.expr)->hdr.tag) == FOAM_SInt
))))
(foamTag(foam)((foam)->hdr.tag) == FOAM_RNew || \
408 foamTag(foam)((foam)->hdr.tag) == FOAM_PushEnv || \
409 (foamTag(foam)((foam)->hdr.tag) == FOAM_ANew && \
410 emIsSInt(foam->foamANew.size)(((foam->foamANew.size)->hdr.tag) == FOAM_SInt || (((foam
->foamANew.size)->hdr.tag) == FOAM_Cast && ((foam
->foamANew.size->foamCast.expr)->hdr.tag) == FOAM_SInt
))
))
411
412#define emIsSInt(foam)(((foam)->hdr.tag) == FOAM_SInt || (((foam)->hdr.tag) ==
FOAM_Cast && ((foam->foamCast.expr)->hdr.tag) ==
FOAM_SInt))
\
413 (foamTag(foam)((foam)->hdr.tag) == FOAM_SInt || \
414 (foamTag(foam)((foam)->hdr.tag) == FOAM_Cast \
415 && foamTag(foam->foamCast.expr)((foam->foamCast.expr)->hdr.tag) == FOAM_SInt))
416
417#define emSIntValue(foam)(((foam)->hdr.tag) == FOAM_SInt ? foam->foamSInt.SIntData
: foam->foamCast.expr->foamSInt.SIntData)
\
418 (foamTag(foam)((foam)->hdr.tag) == FOAM_SInt ? foam->foamSInt.SIntData : \
419 foam->foamCast.expr->foamSInt.SIntData)
420
421/*
422 * Check a definition for usage. This function finds the creation
423 * of new environments and keeps track of local variable aliases.
424 * The logic could be cleaned up a bit.
425 */
426localstatic void
427emMarkDef(Foam def)
428{
429 Foam lhs = def->foamDef.lhs;
430 Foam rhs = def->foamDef.rhs;
431 Foam rhs0 = rhs;
432 FoamTag ltag = foamTag(lhs)((lhs)->hdr.tag), rtag = foamTag(rhs)((rhs)->hdr.tag);
433 EmUsage usage;
434 Bool wasSet = 999;
435
436 assert(foamTag(def) == FOAM_Set || foamTag(def) == FOAM_Def)do { if (!(((def)->hdr.tag) == FOAM_Set || ((def)->hdr.
tag) == FOAM_Def)) _do_assert(("foamTag(def) == FOAM_Set || foamTag(def) == FOAM_Def"
),"of_emerg.c",436); } while (0)
;
437
438 if (rtag == FOAM_PushEnv)
439 emSetParent(lhs, rhs->foamPushEnv.parent);
440
441 if (ltag == FOAM_Loc) {
442 /* Update the root usage for this local */
443 usage = emUsage(lhs);
444 wasSet = usage->isSet;
445 usage->isSet = true1;
446 if (emIsMergingCandidate(rhs)(((rhs)->hdr.tag) == FOAM_RNew || ((rhs)->hdr.tag) == FOAM_PushEnv
|| (((rhs)->hdr.tag) == FOAM_ANew && (((rhs->foamANew
.size)->hdr.tag) == FOAM_SInt || (((rhs->foamANew.size)
->hdr.tag) == FOAM_Cast && ((rhs->foamANew.size
->foamCast.expr)->hdr.tag) == FOAM_SInt))))
) {
447 /*
448 * What is the actual usage of this local
449 * taking into account aliasing etc.
450 */
451 usage = emUsageAliasing(lhs);
452
453
454 /* Check for reuse of locals */
455 if (usage->type) {
456 /*
457 * This local has already been allocated
458 * heap storage and we are now allocating
459 * some more. Since the new structure may
460 * be of a different type or size we have
461 * to mark it as escaping.
462 */
463 emMarkLocal(lhs);
464 return;
465 }
466
467
468 /* Has this local escaped already? */
469 if (usage->used != EM_EscapingEnv) {
470 if (rtag == FOAM_PushEnv)
471 usage->format =rhs->foamPushEnv.format;
472 else if (rtag == FOAM_RNew) {
473 if (emCheckRElt(lhs, rhs->foamRNew.format))
474 usage->format = rhs->foamRNew.format;
475 else
476 emMarkLocal(lhs);
477 }
478 else
479 usage->format =
480 emSIntValue(rhs->foamANew.size)(((rhs->foamANew.size)->hdr.tag) == FOAM_SInt ? rhs->
foamANew.size->foamSInt.SIntData : rhs->foamANew.size->
foamCast.expr->foamSInt.SIntData)
;
481 usage->used = EM_NonEscapingEnv;
482 usage->type = rhs;
483 }
484 return;
485 }
486 }
487 else
488 emMarkParents(lhs);
489
490 foamDereferenceCast(rhs0)while (((rhs0)->hdr.tag) == FOAM_Cast) (rhs0) = (rhs0)->
foamCast.expr;
;
491
492 if (foamTag(rhs0)((rhs0)->hdr.tag) == FOAM_Loc) {
493 if (ltag == FOAM_Loc) {
494 if (emUsageAliasing(lhs)->used ==
495 EM_EscapingEnv) {
496 emMarkLocal(rhs0);
497 emMarkLocal(lhs);
498 }
499 else if (emUsage(lhs)->link == 0 && !wasSet &&
500 emUsage(rhs0)->type &&
501 foamTag(emUsage(rhs0)->type)((emUsage(rhs0)->type)->hdr.tag)
502 == FOAM_PushEnv) {
503 Foam parent = emGetParent(rhs0);
504 emUsage(lhs)->link = emUsage(rhs0);
505 if (parent)
506 emSetParent(lhs, parent);
507 }
508 else if (!emNoAlias && emUsage(lhs)->link == 0) {
509 Foam parent = emGetParent(rhs0);
510 emUsage(lhs)->link = emUsageAliasing(rhs0);
511 if (parent)
512 emSetParent(lhs, parent);
513 }
514 else {
515 /* the lhs is already associated with another link */
516 assert(emUsage(lhs)->link)do { if (!(emUsage(lhs)->link)) _do_assert(("emUsage(lhs)->link"
),"of_emerg.c",516); } while (0)
;
517 assert(emUsageAliasing(lhs)->used == EM_NonEscapingEnv ||do { if (!(emUsageAliasing(lhs)->used == EM_NonEscapingEnv
|| emUsageAliasing(lhs)->used == EM_DontKnow)) _do_assert
(("emUsageAliasing(lhs)->used == EM_NonEscapingEnv || emUsageAliasing(lhs)->used == EM_DontKnow"
),"of_emerg.c",518); } while (0)
518 emUsageAliasing(lhs)->used == EM_DontKnow)do { if (!(emUsageAliasing(lhs)->used == EM_NonEscapingEnv
|| emUsageAliasing(lhs)->used == EM_DontKnow)) _do_assert
(("emUsageAliasing(lhs)->used == EM_NonEscapingEnv || emUsageAliasing(lhs)->used == EM_DontKnow"
),"of_emerg.c",518); } while (0)
;
519 if (emUsageAliasing(lhs)->used == EM_DontKnow)
520 emUsageAliasing(lhs)->link = emUsageAliasing(rhs0);
521 emUsage(lhs)->link = emUsageAliasing(rhs0);
522 /* emMarkLocal(rhs0); */
523 }
524 }
525 else
526 emMarkLocal(rhs);
527 }
528 else if (foamTag(rhs0)((rhs0)->hdr.tag) == FOAM_Env) {
529 emSetParent(lhs, foamNewEnv(rhs0->foamEnv.level + 1)foamNew(FOAM_Env, 1, (AInt)(rhs0->foamEnv.level + 1)));
530 if (rhs0->foamEnv.level == 0) {
531 emUsage(lhs)->link = emUsage(rhs0);
532 }
533 }
534 else if (foamTag(rhs0)((rhs0)->hdr.tag) == FOAM_MFmt) {
535 /*
536 * Strictly speaking we ought to always mark the lhs
537 * of a multi-valued set as escaping or at least we
538 * ought to check both sides of the definition. For
539 * now we don't because it always seems to work out
540 * okay except when the rhs is a catch expression.
541 */
542 Foam mval = rhs0->foamMFmt.value;
543
544
545 /* Check for a catch on the rhs */
546 if (foamTag(mval)((mval)->hdr.tag) == FOAM_Catch)
547 {
548 /* Mark the lhs (a FOAM_Values hopefully) */
549 emMarkLocal(lhs);
550 }
551 }
552}
553
554/*
555 * Mark a local variable and its parents as escaping.
556 */
557localstatic void
558emMarkParents(Foam foam)
559{
560 do {
561 if (emIsMergeable(foam)(((foam)->hdr.tag) == FOAM_Loc || (((foam)->hdr.tag) ==
FOAM_Env && (foam)->foamEnv.level == 0))
)
562 emMarkLocal(foam);
563 foam = emGetParent(foam);
564 } while (foam);
565}
566
567/*
568 * Mark the arguments of a function call as escaping.
569 */
570localstatic void
571emMarkCallArgs(Length argc, Foam *argv)
572{
573 int i;
574 for(i=0; i<argc; i++)
575 emMarkLocal(argv[i]);
576}
577
578/*
579 * Mark closure environments as escaping.
580 */
581localstatic void
582emMarkClos(Foam clos)
583{
584 Foam env = clos->foamClos.env;
585
586 emMarkLocal(env);
587}
588
589localstatic void
590emMarkGener(Foam gener)
591{
592 Foam env = gener->foamGener.env;
593
594 emMarkLocal(env);
595}
596
597/*
598 * Mark an array elt.
599 */
600localstatic void
601emMarkAElt(Foam aelt)
602{
603 Foam index = aelt->foamAElt.index;
604 Foam array = aelt->foamAElt.expr;
605
606 foamDereferenceCast(array)while (((array)->hdr.tag) == FOAM_Cast) (array) = (array)->
foamCast.expr;
;
607
608 if (foamTag(array)((array)->hdr.tag) != FOAM_Loc) return;
609 if (!emIsSInt(index)(((index)->hdr.tag) == FOAM_SInt || (((index)->hdr.tag)
== FOAM_Cast && ((index->foamCast.expr)->hdr.tag
) == FOAM_SInt))
)
610 emMarkLocal(array);
611 else if (emSIntValue(index)(((index)->hdr.tag) == FOAM_SInt ? index->foamSInt.SIntData
: index->foamCast.expr->foamSInt.SIntData)
>= emUsageAliasing(array)->format)
612 emUsageAliasing(array)->format = emSIntValue(index)(((index)->hdr.tag) == FOAM_SInt ? index->foamSInt.SIntData
: index->foamCast.expr->foamSInt.SIntData)
+1;
613 return;
614}
615
616/*
617 * Mark a raw-record as escaping
618 */
619localstatic void
620emMarkRRElt(Foam rrelt)
621{
622 emMarkLocal(rrelt->foamRRElt.data);
623 return;
624}
625
626/*
627 * Mark a record element
628 * [actually just check that the record format is the same]
629 */
630localstatic void
631emMarkRElt(Foam relt)
632{
633 Foam var = relt->foamRElt.expr;
634
635 if (!emCheckRElt(var, relt->foamRElt.format))
636 emMarkLocal(var);
637}
638
639localstatic Bool
640emCheckRElt(Foam var, int fmt)
641{
642 foamDereferenceCast(var)while (((var)->hdr.tag) == FOAM_Cast) (var) = (var)->foamCast
.expr;
;
643
644 if (foamTag(var)((var)->hdr.tag) != FOAM_Loc) return false((int) 0);
645
646 if (emUsageAliasing(var)->format == fmt)
647 return true1;
648 if (emUsageAliasing(var)->format == emptyFormatSlot4)
649 return true1;
650 if (foamEqual(emFormats[emUsageAliasing(var)->format],
651 emFormats[fmt]))
652 return true1;
653
654 return false((int) 0);
655}
656
657
658/*
659 * compute the environment locals variable remap vector.
660 */
661localstatic void
662emComputeRemap(Foam prog)
663{
664 long i;
665 EmUsage env0 = &emLocalUsage[0];
666
667 emNumLocals = foamDDeclArgc(prog->foamProg.locals)(((prog->foamProg.locals)->hdr.argc) - (1));
668
669
670 emNewLocals = listNil(Foam)((FoamList) 0);
671 if (env0->used == EM_NonEscapingEnv)
672 emMergeEnv((int)0,false((int) 0));
673 if (env0->link && (env0->link->used == EM_NonEscapingEnv))
674 emMergeEnv((int)0,true1);
675
676 for (i =0 ; i < emOrigNumLocals ; i++) {
677 EmUsage alias;
678 EmUsage loc = emUsageFromLocalIndex(i);
679
680 /* make locals for the heap allocated object */
681 if (loc->used == EM_NonEscapingEnv)
682 emMergeEnv(i+1,false((int) 0));
683
684 /* make locals for an "alias" of a non-escaping object */
685 alias = emUsageFromLocalIndexAliasing(i);
686 if (loc->link && (alias->used == EM_NonEscapingEnv))
687 {
688 loc->link = alias;
689
690
691 /* Careful with (Env 0) remap */
692 if (alias == env0)
693 emRemapEnv0(env0, loc);
694 else
695 emMergeEnv(i+1,true1);
696 }
697 }
698
699 emMakeNewLocals(prog);
700}
701
702
703/*
704 * Ensure that locals for EElts of aliases of (Env 0) all map
705 * to the same local. We assume that all aliases of (Env 0)
706 * always point to (Env 0) and are never reassigned to other
707 * records of the same format.
708 */
709localstatic void
710emRemapEnv0(EmUsage env0, EmUsage usage)
711{
712 int size, format, i;
713
714
715 /* Check the format */
716 format = env0->format;
717
718
719 /* Unused environments can't be emerged */
720 if (format == emptyFormatSlot4) return;
721
722
723 /* How many elements are there in the environment? */
724 size = foamDDeclArgc(emFormats[format])(((emFormats[format])->hdr.argc) - (1));
725
726
727 /* Create a new remap vector */
728 usage->remap = (Foam *)stoAlloc(OB_Other0, size*sizeof(Foam));
729
730
731 /* Copy the mappings for (Env 0) */
732 for (i = 0;i < size; i++)
733 usage->remap[i] = foamCopy(env0->remap[i]);
734}
735
736
737/*
738 * Create the locals for the nth local environment.
739 */
740localstatic void
741emMergeEnv(int n, Bool isAlias)
742{
743 int size, format, i;
744 Foam ddecl, type;
745
746 type = isAlias ? emUsageFromLocalIndexAliasing(n-1)->type :
747 emLocalUsage[n].type;
748
749 if (emIsArray(type)((type) && ((type)->hdr.tag) == FOAM_ANew)) {
750 emMergeArray(n, type, isAlias);
751 return;
752 }
753
754 format = isAlias ? emUsageFromLocalIndexAliasing(n-1)->format :
755 emLocalUsage[n].format;
756 if (format == emptyFormatSlot4) return;
757
758 ddecl = emFormats[format];
759 size = foamDDeclArgc(ddecl)(((ddecl)->hdr.argc) - (1));
760 emLocalUsage[n].remap = (Foam *)stoAlloc(OB_Other0, size*sizeof(Foam));
761
762 for(i=0; i < size; i++) {
763 Foam decl = foamCopy(ddecl->foamDDecl.argv[i]);
764
765 emNewLocals = listCons(Foam)(Foam_listPointer->Cons)(decl, emNewLocals);
766 emLocalUsage[n].remap[i] = foamNewLoc(emNumLocals++)foamNew(FOAM_Loc, 1, (AInt)(emNumLocals++));
767 emChanged = true1;
768 }
769}
770
771/*
772 * Create locals for an array
773 */
774localstatic void
775emMergeArray(int n, Foam type, Bool isAlias)
776{
777 int size, i, eltType;
778 Foam decl;
779
780 assert(foamTag(type) == FOAM_ANew)do { if (!(((type)->hdr.tag) == FOAM_ANew)) _do_assert(("foamTag(type) == FOAM_ANew"
),"of_emerg.c",780); } while (0)
;
781 assert(emIsSInt(type->foamANew.size))do { if (!((((type->foamANew.size)->hdr.tag) == FOAM_SInt
|| (((type->foamANew.size)->hdr.tag) == FOAM_Cast &&
((type->foamANew.size->foamCast.expr)->hdr.tag) == FOAM_SInt
)))) _do_assert(("emIsSInt(type->foamANew.size)"),"of_emerg.c"
,781); } while (0)
;
782
783 size = emUsageFromLocalIndexAliasing(n-1)->format;
784 eltType = type->foamANew.eltType;
785 decl = foamNewDecl(eltType, strCopy(""), emptyFormatSlot)foamNew(FOAM_Decl,4,(AInt)(eltType),strCopy(""), (AInt) (0x7FFF
), 4)
;
786
787 emLocalUsage[n].remap = (Foam *) stoAlloc(OB_Other0, size*sizeof(Foam));
788
789 for(i = 0; i < size; i++) {
790 emNewLocals = listCons(Foam)(Foam_listPointer->Cons)(foamCopy(decl), emNewLocals);
791 emLocalUsage[n].remap[i] = foamNewLoc(emNumLocals++)foamNew(FOAM_Loc, 1, (AInt)(emNumLocals++));
792 emChanged = true1;
793 }
794}
795
796/*
797 * Create new locals for the merged environment.
798 */
799localstatic void
800emMakeNewLocals(Foam prog)
801{
802 int i;
803 Foam newFoam, locals;
804 FoamList l;
805
806 locals = prog->foamProg.locals;
807 newFoam = foamNewEmpty(FOAM_DDecl, emNumLocals + 1);
808 newFoam->foamDDecl.usage = locals->foamDDecl.usage;
809
810 for(i=0; i<foamDDeclArgc(locals)(((locals)->hdr.argc) - (1)); i++)
811 newFoam->foamDDecl.argv[i] = locals->foamDDecl.argv[i];
812 emNewLocals = listNReverse(Foam)(Foam_listPointer->NReverse)(emNewLocals);
813 for(l = emNewLocals, i = foamDDeclArgc(locals)(((locals)->hdr.argc) - (1)); l; l = cdr(l)((l)->rest), i++)
814 newFoam->foamDDecl.argv[i] = car(l)((l)->first);
815 stoFree(locals);
816 listFree(Foam)(Foam_listPointer->Free)(emNewLocals);
817 prog->foamProg.locals = newFoam;
818}
819
820
821/*
822 * Add a statement to the current function being merged.
823 */
824localstatic void
825emAddStmt(Foam stmt)
826{
827 emStmtList = listCons(Foam)(Foam_listPointer->Cons)(stmt, emStmtList);
828}
829
830/*
831 * Transform the statements in a function body to merged environments.
832 */
833localstatic void
834emMergeEnvs(Foam prog)
835{
836 Foam body = prog->foamProg.body;
837 int argc = foamArgc(body)((body)->hdr.argc), i;
838
839 assert(foamTag(body) == FOAM_Seq)do { if (!(((body)->hdr.tag) == FOAM_Seq)) _do_assert(("foamTag(body) == FOAM_Seq"
),"of_emerg.c",839); } while (0)
;
840 emStmtList = listNil(Foam)((FoamList) 0);
841 for(i=0; i<argc; i++)
842 emAddStmt(emMergeExpr(body->foamSeq.argv[i]));
843 foamFreeNode(body);
844 prog->foamProg.body = emNewBody();
845}
846
847/*
848 * Create a new function body from the statement list.
849 */
850localstatic Foam
851emNewBody()
852{
853 Foam newFoam;
854 FoamList l;
855 int i;
856
857 newFoam = foamNewEmpty(FOAM_Seq, listLength(Foam)(Foam_listPointer->_Length)(emStmtList));
858 emStmtList = listNReverse(Foam)(Foam_listPointer->NReverse)(emStmtList);
859 for(i=0, l = emStmtList; l; l = cdr(l)((l)->rest), i++) {
860 newFoam->foamSeq.argv[i] = car(l)((l)->first);
861 }
862 listFree(Foam)(Foam_listPointer->Free)(emStmtList);
863 return newFoam;
864}
865
866/*
867 * transform a foam expression to merge non-escaping environments.
868 */
869localstatic Foam
870emMergeExpr(Foam expr)
871{
872 Foam nexpr = expr, env;
873 int index;
874
875 foamIter(expr, arg, *arg = emMergeExpr(*arg)){ { String argf = (foamInfoTable [(int)(((expr)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((expr
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((expr)->foamGen.argv
)+_i; { *arg = emMergeExpr(*arg); }; } } }; }
;
876
877 switch(foamTag(expr)((expr)->hdr.tag)) {
878 case FOAM_Set:
879 case FOAM_Def:
880 nexpr = emMergeDef(expr);
881 break;
882 case FOAM_EEnv:
883 nexpr = emMergeEEnv(expr);
884 break;
885 case FOAM_EElt:
886 index = expr->foamEElt.lex;
887 env = expr->foamEElt.ref;
888 nexpr = emMergeEElt(expr, env, index);
889 break;
890 case FOAM_RElt:
891 index = expr->foamRElt.field;
892 env = expr->foamRElt.expr;
893 nexpr = emMergeRElt(expr, env, index);
894 break;
895 case FOAM_Return:
896 nexpr = emMergeReturn(expr);
897 break;
898 case FOAM_Yield:
899 nexpr = emMergeYield(expr);
900 break;
901 case FOAM_AElt:
902 nexpr = emMergeAElt(expr);
903 break;
904 case FOAM_Lex:
905 nexpr = emMergeLex(expr);
906 break;
907 case FOAM_Free:
908 nexpr = emMergeFree(expr);
909 break;
910 default:
911 break;
912 }
913 /* if (expr != nexpr) foamFreeNode(expr); */
914 return nexpr;
915}
916
917
918/*
919 * Transform an assignment.
920 */
921localstatic Foam
922emMergeDef(Foam def)
923{
924 Foam lhs = def->foamDef.lhs;
925 Foam rhs = def->foamDef.rhs;
926 FoamTag ltag = foamTag(lhs)((lhs)->hdr.tag), rtag = foamTag(rhs)((rhs)->hdr.tag);
927
928 if (rtag == FOAM_PushEnv) {
929 emSetParent(lhs, rhs->foamPushEnv.parent);
930 return def;
931 }
932
933 if (rtag == FOAM_Loc && ltag == FOAM_Loc && emOldLocal(rhs)(((rhs)->hdr.tag) != FOAM_Loc || ((rhs)->foamLoc.index <
emOrigNumLocals))
&& emOldLocal(lhs)(((lhs)->hdr.tag) != FOAM_Loc || ((lhs)->foamLoc.index <
emOrigNumLocals))
) {
934 if (emUsage(lhs)->remap) {
935 if (emUsage(rhs)->remap == 0) {
936 assert(0 && "lhs is remapped and rhs isn't")do { if (!(0 && "lhs is remapped and rhs isn't")) _do_assert
(("0 && \"lhs is remapped and rhs isn't\""),"of_emerg.c"
,936); } while (0)
;
937 }
938 }
939 else {
940 if (emUsage(rhs)->remap) {
941 assert (0 && "rhs is remapped and lhs isn't")do { if (!(0 && "rhs is remapped and lhs isn't")) _do_assert
(("0 && \"rhs is remapped and lhs isn't\""),"of_emerg.c"
,941); } while (0)
;
942 }
943 }
944 }
945
946 if (ltag == FOAM_Loc) {
947 if (!emOldLocal(lhs)(((lhs)->hdr.tag) != FOAM_Loc || ((lhs)->foamLoc.index <
emOrigNumLocals))
) return def;
948 return emNewEnvSet(def, lhs, rhs);
949 }
950
951 return def;
952}
953
954/*
955 * Transform an assignment.
956 */
957localstatic Foam
958emNewEnvSet(Foam def, Foam lhs, Foam rhs)
959{
960 int format, i, size, rtag;
961 Foam ddecl;
962 EmUsage aliasLhs;
963 Bool isArray;
964 FoamTag arrType = FOAM_NOp; /* Quit warnings */
965
966 assert (emOldLocal(lhs))do { if (!((((lhs)->hdr.tag) != FOAM_Loc || ((lhs)->foamLoc
.index < emOrigNumLocals)))) _do_assert(("emOldLocal(lhs)"
),"of_emerg.c",966); } while (0)
;
967
968 foamDereferenceCast(rhs)while (((rhs)->hdr.tag) == FOAM_Cast) (rhs) = (rhs)->foamCast
.expr;
;
969
970 rtag = foamTag(rhs)((rhs)->hdr.tag);
971
972 aliasLhs = emUsageAliasing(lhs);
973
974
975 if (aliasLhs->used != EM_NonEscapingEnv) return def;
976
977 /* we are setting a non-escaped or an alias */
978
979 format = aliasLhs->format;
980 if (emIsArray(aliasLhs->type)((aliasLhs->type) && ((aliasLhs->type)->hdr.
tag) == FOAM_ANew)
) {
981 isArray = true1;
982 size = format;
983 arrType = (aliasLhs->type)->foamANew.eltType;
984 }
985 else {
986 isArray = false((int) 0);
987 ddecl = emFormats[format];
988 size = foamDDeclArgc(ddecl)(((ddecl)->hdr.argc) - (1));
989 }
990
991 if (rtag == FOAM_Loc && emOldLocal(rhs)(((rhs)->hdr.tag) != FOAM_Loc || ((rhs)->foamLoc.index <
emOrigNumLocals))
&& emUsage(rhs)->remap) {
992 for(i=0; i<size; i++)
993 emAddStmt(foamNewSet(foamCopy(emUsage(lhs)-> remap[i]),foamNew(FOAM_Set, 2, foamCopy(emUsage(lhs)-> remap[i]), foamCopy
(emUsage(rhs)-> remap[i]))
994 foamCopy(emUsage(rhs)-> remap[i]))foamNew(FOAM_Set, 2, foamCopy(emUsage(lhs)-> remap[i]), foamCopy
(emUsage(rhs)-> remap[i]))
);
995 emChanged = true1;
996 return foamNewNOp()foamNew(FOAM_NOp, (int) 0);
997 }
998 if ( rtag == FOAM_PushEnv || rtag == FOAM_Env || rtag == FOAM_RNew || rtag == FOAM_ANew) {
999 assert(rtag != FOAM_PushEnv)do { if (!(rtag != FOAM_PushEnv)) _do_assert(("rtag != FOAM_PushEnv"
),"of_emerg.c",999); } while (0)
; /* has been dealt in emMergeDef */
1000 if (emUsage(lhs)->used == EM_NonEscapingEnv) return foamNewNOp()foamNew(FOAM_NOp, (int) 0);
1001 return def;
1002 }
1003
1004 emAddStmt(def);
1005
1006 if (isArray) {
1007 for(i=0; i<size; i++)
1008 emAddStmt(foamNewSet(foamCopy(emUsage(lhs)->remap[i]),foamNew(FOAM_Set, 2, foamCopy(emUsage(lhs)->remap[i]), foamNew
(FOAM_AElt,3,(AInt)(arrType),foamNew(FOAM_SInt, 1, (AInt)(i))
,foamCopy(lhs)))
1009 foamNewAElt(arrType,foamNew(FOAM_Set, 2, foamCopy(emUsage(lhs)->remap[i]), foamNew
(FOAM_AElt,3,(AInt)(arrType),foamNew(FOAM_SInt, 1, (AInt)(i))
,foamCopy(lhs)))
1010 foamNewSInt(i),foamNew(FOAM_Set, 2, foamCopy(emUsage(lhs)->remap[i]), foamNew
(FOAM_AElt,3,(AInt)(arrType),foamNew(FOAM_SInt, 1, (AInt)(i))
,foamCopy(lhs)))
1011 foamCopy(lhs)))foamNew(FOAM_Set, 2, foamCopy(emUsage(lhs)->remap[i]), foamNew
(FOAM_AElt,3,(AInt)(arrType),foamNew(FOAM_SInt, 1, (AInt)(i))
,foamCopy(lhs)))
);
1012
1013 }
1014 else {
1015 Foam decl = emUsage(lhs)->decl;
1016 Foam typedLhs;
1017 typedLhs = (decl->foamDecl.type == FOAM_Rec) ? foamCopy(lhs) : foamNewCast(FOAM_Rec, foamCopy(lhs))foamNew(FOAM_Cast, 2, FOAM_Rec, foamCopy(lhs));
1018 for(i=0; i<size; i++)
1019 emAddStmt(foamNewSet(foamCopy(emUsage(lhs)->remap[i]),foamNew(FOAM_Set, 2, foamCopy(emUsage(lhs)->remap[i]), foamNew
(FOAM_RElt,3,(AInt)(format),foamCopy(typedLhs),(AInt)(i)))
1020 foamNewRElt(format,foamNew(FOAM_Set, 2, foamCopy(emUsage(lhs)->remap[i]), foamNew
(FOAM_RElt,3,(AInt)(format),foamCopy(typedLhs),(AInt)(i)))
1021 foamCopy(typedLhs), i))foamNew(FOAM_Set, 2, foamCopy(emUsage(lhs)->remap[i]), foamNew
(FOAM_RElt,3,(AInt)(format),foamCopy(typedLhs),(AInt)(i)))
);
1022 foamFree(typedLhs);
1023 }
1024
1025 emChanged = true1;
1026 return foamNewNOp()foamNew(FOAM_NOp, (int) 0);
1027}
1028
1029
1030/*
1031 * Transfor a record elt.
1032 */
1033localstatic Foam
1034emMergeRElt(Foam expr, Foam env, int index)
1035{
1036 foamDereferenceCast(env)while (((env)->hdr.tag) == FOAM_Cast) (env) = (env)->foamCast
.expr;
;
1037
1038 if (foamTag(env)((env)->hdr.tag) != FOAM_Loc) return expr;
1039
1040 if (!emOldLocal(env)(((env)->hdr.tag) != FOAM_Loc || ((env)->foamLoc.index <
emOrigNumLocals))
) return expr;
1041
1042 if (emUsageAliasing(env)->used != EM_NonEscapingEnv) return expr;
1043
1044 emChanged = true1;
1045
1046 /* assert (expr->foamRElt.format == emUsageAliasing(env)->format);
1047 no, because there may be a cast so the records don't have to be identical
1048 */
1049 assert (emUsage(env)->remap)do { if (!(emUsage(env)->remap)) _do_assert(("emUsage(env)->remap"
),"of_emerg.c",1049); } while (0)
;
1050
1051 return foamCopy(emUsage(env)->remap[index]);
1052}
1053
1054/*
1055 * transform an environment elt.
1056 */
1057localstatic Foam
1058emMergeEElt(Foam eelt, Foam env, int index)
1059{
1060 int format = eelt->foamEElt.env;
1061 int level = eelt->foamEElt.level;
1062 int oindex = eelt->foamEElt.lex;
1063 EmUsage usage;
1064
1065 foamDereferenceCast(env)while (((env)->hdr.tag) == FOAM_Cast) (env) = (env)->foamCast
.expr;
;
1066
1067 env = emGetNthParent(env, &level);
1068 if (level == eelt->foamEElt.level && level > 0)
1069 return eelt;
1070
1071 emChanged = true1;
1072
1073 if (level > 0)
1074 return foamNewEElt(format, foamCopy(env), level, oindex)foamNew(FOAM_EElt,4,(AInt)(format),foamCopy(env),(AInt)(level
),(AInt)(oindex))
;
1075
1076 if (!emIsMergeable(env)(((env)->hdr.tag) == FOAM_Loc || (((env)->hdr.tag) == FOAM_Env
&& (env)->foamEnv.level == 0))
)
1077 return foamNewEElt(format, foamCopy(env), level, oindex)foamNew(FOAM_EElt,4,(AInt)(format),foamCopy(env),(AInt)(level
),(AInt)(oindex))
;
1078
1079 if (!emOldLocal(env)(((env)->hdr.tag) != FOAM_Loc || ((env)->foamLoc.index <
emOrigNumLocals))
)
1080 return foamNewEElt(format, foamCopy(env), level, oindex)foamNew(FOAM_EElt,4,(AInt)(format),foamCopy(env),(AInt)(level
),(AInt)(oindex))
;
1081
1082 usage = emUsageAliasing(env);
1083
1084 if (usage->used != EM_NonEscapingEnv)
1085 return foamNewEElt(format, foamCopy(env), level, oindex)foamNew(FOAM_EElt,4,(AInt)(format),foamCopy(env),(AInt)(level
),(AInt)(oindex))
;
1086
1087 assert(emUsage(env)->remap)do { if (!(emUsage(env)->remap)) _do_assert(("emUsage(env)->remap"
),"of_emerg.c",1087); } while (0)
;
1088 return foamCopy(emUsage(env)->remap[index]);
1089}
1090
1091localstatic Foam
1092emMergeLex(Foam lex)
1093{
1094 if (lex->foamLex.level != 0)
1095 return lex;
1096 if (emLocalUsage->used != EM_NonEscapingEnv)
1097 return lex;
1098 emChanged = true1;
1099 return foamCopy(emLocalUsage->remap[lex->foamLex.index]);
1100}
1101
1102/*
1103 * Transform an environment parent instruction.
1104 */
1105localstatic Foam
1106emMergeEEnv(Foam eenv)
1107{
1108 Foam env = eenv->foamEEnv.env;
1109 int level = eenv->foamEEnv.level;
1110
1111 foamDereferenceCast(env)while (((env)->hdr.tag) == FOAM_Cast) (env) = (env)->foamCast
.expr;
;
1112
1113 env = emGetNthParent(env, &level);
1114 if (level == eenv->foamEEnv.level)
1115 return eenv;
1116
1117 emChanged = true1;
1118 env = foamCopy(env);
1119 assert((int)level >= 0)do { if (!((int)level >= 0)) _do_assert(("(int)level >= 0"
),"of_emerg.c",1119); } while (0)
; /* bug 1168 */
1120 return level == 0 ? env : foamNewEEnv(level, env)foamNew(FOAM_EEnv, 2, (AInt)(level), env);
1121}
1122
1123/*
1124 * Remove the `(Free x)' statement if x is no more heap-allocated.
1125 */
1126localstatic Foam
1127emMergeFree(Foam foam)
1128{
1129 Foam expr, newFoam;
1130
1131 expr = foam->foamFree.place;
1132
1133 foamDereferenceCast(expr)while (((expr)->hdr.tag) == FOAM_Cast) (expr) = (expr)->
foamCast.expr;
;
1134
1135 if (foamTag(expr)((expr)->hdr.tag) != FOAM_Loc) return foam;
1136
1137 if (!emOldLocal(expr)(((expr)->hdr.tag) != FOAM_Loc || ((expr)->foamLoc.index
< emOrigNumLocals))
) return foam;
1138 if (emUsageAliasing(expr)->used != EM_NonEscapingEnv) return foam;
1139
1140 newFoam = foamNewNOp()foamNew(FOAM_NOp, (int) 0);
1141
1142 return newFoam;
1143}
1144
1145/*
1146 * create a new record object for returning.
1147 */
1148localstatic Foam
1149emMergeReturn(Foam ret)
1150{
1151 int size, format, i;
1152 Foam newFoam, expr;
1153
1154 foamDereferenceCast(ret)while (((ret)->hdr.tag) == FOAM_Cast) (ret) = (ret)->foamCast
.expr;
;
1155
1156 expr = ret->foamReturn.value;
1157 if (foamTag(expr)((expr)->hdr.tag) != FOAM_Loc) return ret;
1158
1159 if (!emOldLocal(expr)(((expr)->hdr.tag) != FOAM_Loc || ((expr)->foamLoc.index
< emOrigNumLocals))
) return ret;
1160 if (emUsageAliasing(expr)->used != EM_NonEscapingEnv) return ret;
1161
1162 format = emUsageAliasing(expr)->format;
1163 size = foamDDeclArgc(emFormats[format])(((emFormats[format])->hdr.argc) - (1));
1164 newFoam = foamNewEmpty(FOAM_Rec, size+1);
1165 newFoam->foamRec.format = format;
1166 for(i=0; i<size; i++)
1167 newFoam->foamRec.eltv[i+1] =
1168 foamCopy(emUsageAliasing(expr)->remap[i]);
1169 emChanged = true1;
1170
1171 return newFoam;
1172}
1173
1174/*
1175 * create a new record object for yield
1176 */
1177localstatic Foam
1178emMergeYield(Foam yld)
1179{
1180 int size, format, i;
1181 Foam newFoam, expr;
1182
1183 foamDereferenceCast(yld)while (((yld)->hdr.tag) == FOAM_Cast) (yld) = (yld)->foamCast
.expr;
;
1184
1185 expr = yld->foamYield.value;
1186 if (foamTag(expr)((expr)->hdr.tag) != FOAM_Loc) return yld;
1187
1188 if (!emOldLocal(expr)(((expr)->hdr.tag) != FOAM_Loc || ((expr)->foamLoc.index
< emOrigNumLocals))
) return yld;
1189 if (emUsageAliasing(expr)->used != EM_NonEscapingEnv) return yld;
1190
1191 format = emUsageAliasing(expr)->format;
1192 size = foamDDeclArgc(emFormats[format])(((emFormats[format])->hdr.argc) - (1));
1193 newFoam = foamNewEmpty(FOAM_Rec, size+1);
1194 newFoam->foamRec.format = format;
1195 for(i=0; i<size; i++)
1196 newFoam->foamRec.eltv[i+1] =
1197 foamCopy(emUsageAliasing(expr)->remap[i]);
1198 emChanged = true1;
1199
1200 return newFoam;
1201}
1202
1203/*
1204 * Merge an array reference.
1205 */
1206localstatic Foam
1207emMergeAElt(Foam aelt)
1208{
1209 Foam index = aelt->foamAElt.index;
1210 Foam array = aelt->foamAElt.expr;
1211 EmUsage usage;
1212 int i;
1213
1214 foamDereferenceCast(array)while (((array)->hdr.tag) == FOAM_Cast) (array) = (array)->
foamCast.expr;
;
1215
1216 if (foamTag(array)((array)->hdr.tag) != FOAM_Loc) return aelt;
1217 if (!emOldLocal(array)(((array)->hdr.tag) != FOAM_Loc || ((array)->foamLoc.index
< emOrigNumLocals))
) return aelt;
1218
1219 usage = emUsageAliasing(array);
1220 if (usage->used != EM_NonEscapingEnv) return aelt;
1221
1222 assert (emIsSInt(index))do { if (!((((index)->hdr.tag) == FOAM_SInt || (((index)->
hdr.tag) == FOAM_Cast && ((index->foamCast.expr)->
hdr.tag) == FOAM_SInt)))) _do_assert(("emIsSInt(index)"),"of_emerg.c"
,1222); } while (0)
;
1223 i = emSIntValue(index)(((index)->hdr.tag) == FOAM_SInt ? index->foamSInt.SIntData
: index->foamCast.expr->foamSInt.SIntData)
;
1224 return foamCopy(usage->remap[i]);
1225}
1226
1227/*
1228 * Return the representative usage descriptor for an environment.
1229 */
1230localstatic EmUsage
1231emUsageAliasing(Foam foam)
1232{
1233 EmUsage orig, val;
1234 Bool isCircular ;
1235
1236 isCircular = 0;
1237
1238 if (foamTag(foam)((foam)->hdr.tag) == FOAM_Loc)
1239 val = emUsageFromLocalIndex(foam->foamLoc.index);
1240 else {
1241 assert(foamTag(foam) == FOAM_Env)do { if (!(((foam)->hdr.tag) == FOAM_Env)) _do_assert(("foamTag(foam) == FOAM_Env"
),"of_emerg.c",1241); } while (0)
;
1242 val = emLocalUsage; /* for Env(0) */
1243 }
1244
1245 orig = val;
1246 while (val->link) {
1247 if (val->mark == 1) {
1248 isCircular =1 ; /* oops , must be a circular link */
1249 break;
1250 }
1251 val->mark = 1;
1252 val = val->link;
1253
1254 }
1255 while (orig->link) {
1256 if (orig->mark == 0) break;
1257 orig->mark = 0;
1258 orig = orig->link;
1259 }
1260 return val;
1261}
1262
1263
1264localstatic EmUsage
1265emUsage(Foam foam)
1266{
1267 assert(foam!=NULL)do { if (!(foam!=((void*)0))) _do_assert(("foam!=NULL"),"of_emerg.c"
,1267); } while (0)
;
1268 if (foamTag(foam)((foam)->hdr.tag) == FOAM_Loc)
1269 return emUsageFromLocalIndex(foam->foamLoc.index);
1270 else {
1271 assert(foamTag(foam) == FOAM_Env)do { if (!(((foam)->hdr.tag) == FOAM_Env)) _do_assert(("foamTag(foam) == FOAM_Env"
),"of_emerg.c",1271); } while (0)
;
1272 return emLocalUsage; /* for Env(0) */
1273 }
1274}
1275
1276
1277localstatic EmUsage
1278emUsageFromLocalIndexAliasing(long index)
1279{
1280 EmUsage orig, val;
1281 Bool isCircular ;
1282
1283 isCircular = 0;
Value stored to 'isCircular' is never read
1284
1285 val = emUsageFromLocalIndex(index);
1286
1287 orig = val;
1288 /* follow the links all the way , marking as we go */
1289 while (val->link) {
1290 if (val->mark == 1) {
1291 isCircular =1 ; /* oops , must be a circular link */
1292 break;
1293 }
1294 val->mark = 1;
1295 val = val->link;
1296
1297 }
1298 /* restore the marks */
1299 while (orig->link) {
1300 if (orig->mark == 0) break;
1301 orig->mark = 0;
1302 orig = orig->link;
1303 }
1304 return val;
1305}
1306
1307localstatic EmUsage
1308emUsageFromLocalIndex(long index)
1309{
1310 /* Loc 0 => index 0 => array[1] */
1311 return &(emLocalUsage[index + 1]);
1312}
1313
1314localstatic long
1315emIndexFromUsage(EmUsage u)
1316{
1317 return (u - &emLocalUsage[1]);
1318}
1319
1320Table emParentTable;
1321
1322/*
1323 * Create a hash table for tracking environment parents.
1324 */
1325localstatic void
1326emNewParentTable()
1327{
1328 emParentTable = tblNew((TblHashFun) foamHash, (TblEqFun) foamEqual);
1329}
1330
1331/*
1332 * Free the table.
1333 */
1334localstatic void
1335emFreeParentTable()
1336{
1337 tblFree(emParentTable);
1338}
1339
1340/*
1341 * Set an environment's parent
1342 */
1343localstatic void
1344emSetParent(Foam child, Foam parent)
1345{
1346 Foam newParent;
1347 newParent = emUnEEnv(parent);
1348
1349 /* Strip aliases out where poss */
1350 if (parent != newParent) {
1351 if (DEBUG(emerge)emergeDebug) {
1352 fprintf(dbOut, "child:"); foamWrSExpr(dbOut, child,SXRW_Default((1L<<1) | (1L<<3)));
1353 fprintf(dbOut, "parent:"); foamWrSExpr(dbOut, parent,SXRW_Default((1L<<1) | (1L<<3)));
1354 fprintf(dbOut, "newParent:"); foamWrSExpr(dbOut, newParent,SXRW_Default((1L<<1) | (1L<<3)));
1355 }
1356 emChanged = true1;
1357 }
1358
1359 tblSetElt(emParentTable, (TblKey) child, (TblElt) newParent);
1360}
1361
1362
1363localstatic Foam
1364emUnEEnv(Foam foam)
1365{
1366 int lvl;
1367 Foam env;
1368
1369 if (foamTag(foam)((foam)->hdr.tag) != FOAM_EEnv)
1370 return foam;
1371
1372 lvl = foam->foamEEnv.level;
1373 env = foam->foamEEnv.env;
1374
1375 while (lvl > 0) {
1376 Foam nextEnv = emGetParent(env);
1377 if (!nextEnv)
1378 return foam;
1379 env = nextEnv;
1380 lvl--;
1381 }
1382 return env;
1383}
1384
1385/*
1386 * Query an environment's parent.
1387 */
1388localstatic Foam
1389emGetParent(Foam child)
1390{
1391 return (Foam) tblElt(emParentTable, (TblKey) child, (TblElt) 0);
1392}
1393
1394localstatic Foam
1395emGetNthParent(Foam child, int *level)
1396{
1397 Foam parent;
1398
1399 while (*level > 0 && (parent = emGetParent(child)) != NULL((void*)0)) {
1400 child = parent;
1401 *level -= 1;
1402 }
1403
1404 return child;
1405}
1406
1407
1408localstatic void
1409emCleanTypeUsage()
1410{
1411 int i;
1412 for (i = 0 ; i < emOrigNumLocals ;i++) {
1413 emUsageFromLocalIndex((long)i)->type = (Foam) 0 ;
1414 }
1415
1416}
1417
1418
1419localstatic void
1420emNormaliseUsage()
1421{
1422 int i;
1423 emergeDEBUGif (!emergeDebug) { } else afprintf(dbOut, "--------------------\n");
1424 for (i = 0 ; i < emOrigNumLocals ;i++){
1425 EmUsage use = emUsageFromLocalIndex((long)i);
1426
1427 /* If non-escaping and not root link ... */
1428 if (use->link) {
1429 if (use->link->used != EM_NonEscapingEnv) {
1430 /* assert(use->link->link == 0); */
1431 use->link = 0; /* MUST clobber this */
1432 }
1433 else {
1434 use->used = EM_AliasNonEsc;
1435 assert(use->remap)do { if (!(use->remap)) _do_assert(("use->remap"),"of_emerg.c"
,1435); } while (0)
;
1436 emergeDEBUGif (!emergeDebug) { } else afprintf(dbOut, "%3ld is aliased to %3ld\n",
1437 emIndexFromUsage(use), emIndexFromUsage(use->link));
1438 }
1439
1440 }
1441 }
1442
1443}
1444
1445
1446
1447localstatic void
1448emCopyUsedTagsTo(EmUsageState * arr)
1449{
1450 int i;
1451 for (i = 0 ; i < (emOrigNumLocals + 1) ;i++){
1452 arr[i] = emLocalUsage[i].used;
1453 }
1454}
1455
1456localstatic Bool
1457emUsedTagsChanged(EmUsageState *arr)
1458{
1459 int i;
1460 for (i = 0 ; i < (emOrigNumLocals + 1) ;i++){
1461 if (arr[i] != emLocalUsage[i].used) {
1462 emergeDEBUGif (!emergeDebug) { } else afprintf(dbOut, "emLocalUsage[%3d].used has changed!\n", i);
1463 return true1;
1464 }
1465 }
1466 return false((int) 0);
1467}
1468
1469