Bug Summary

File:src/of_peep.c
Warning:line 189, column 8
Value stored to 'idx' during its initialization 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_peep.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_peep.c
1/*****************************************************************************
2 *
3 * of_peep.c: Foam peep-hole optimizations.
4 *
5 * Copyright (c) 1990-2007 Aldor Software Organization Ltd (Aldor.org).
6 *
7 ****************************************************************************/
8
9#include "axlobs.h"
10#include "debug.h"
11#include "format.h"
12#include "of_peep.h"
13#include "of_util.h"
14#include "optfoam.h"
15#include "optinfo.h"
16#include "opttools.h"
17#include "util.h"
18#include "sexpr.h"
19
20Bool peepDebug = false((int) 0);
21#define peepDEBUGif (!peepDebug) { } else afprintf DEBUG_IF(peep)if (!peepDebug) { } else afprintf
22
23
24/*****************************************************************************
25 *
26 * :: Local function declarations
27 *
28 ****************************************************************************/
29
30localstatic Foam peepExpr (Foam, Bool *);
31localstatic void peepAux (Foam *);
32localstatic Foam peepAElt (Foam);
33localstatic Foam peepBCall (Foam);
34localstatic Foam peepCast (Foam);
35localstatic Foam peepIf (Foam);
36localstatic Foam peepSelect (Foam);
37localstatic Foam peepCCall (Foam);
38localstatic Foam peepEEnsure (Foam);
39
40#ifdef PeepEnv
41localstatic Foam peepEElt (Foam);
42localstatic Foam peepEEnv (Foam);
43#endif
44
45localstatic Foam peepIf (Foam);
46
47localstatic FoamTag peepFoamExprType (Foam);
48localstatic Bool peepFoamIsValue (FoamTag, int, Foam);
49localstatic Bool peepFoamIsPowerOf2 (Foam);
50localstatic Foam peepFoamValue (FoamTag, int);
51
52localstatic Foam peepUnaryBCall (Foam);
53localstatic Foam peepBinaryBCall (Foam);
54localstatic Foam peepNegate (Foam);
55
56static Foam peepProgram = 0;
57
58#define peepNoSideFx(foam)(!foamHasSideEffect(foam)) (!foamHasSideEffect(foam))
59
60Foam
61peepUnit(Foam unit,Bool foldfloats)
62{
63 int i;
64 Foam defs, def, rhs;
65
66 assert (foamTag(unit) == FOAM_Unit)do { if (!(((unit)->hdr.tag) == FOAM_Unit)) _do_assert(("foamTag(unit) == FOAM_Unit"
),"of_peep.c",66); } while (0)
;
67
68 if (DEBUG(peep)peepDebug) {
69 fprintf(dbOut, ">>peepUnit:\n");
70 foamPrint(dbOut, unit);
71 fnewline(dbOut);
72 }
73
74 defs = unit->foamUnit.defs;
75
76 for (i = 0; i < foamArgc(defs)((defs)->hdr.argc); i++) {
77 def = defs->foamDDef.argv[i];
78 rhs = def->foamDef.rhs;
79
80 if (foamTag(rhs)((rhs)->hdr.tag) == FOAM_Prog)
81 def->foamDef.rhs = peepProg(rhs,foldfloats);
82 }
83
84 assert(foamAudit(unit))do { if (!(foamAudit(unit))) _do_assert(("foamAudit(unit)"),"of_peep.c"
,84); } while (0)
;
85
86 if (DEBUG(peep)peepDebug) {
87 fprintf(dbOut, "<<peepUnit:\n");
88 foamPrint(dbOut, unit);
89 fnewline(dbOut);
90 }
91
92 return unit;
93}
94
95
96localstatic Foam
97peepExpr(Foam expr, Bool *changed)
98{
99 FoamTag tag = foamTag(expr)((expr)->hdr.tag);
100 Foam newExpr = expr;
101
102 foamIter(expr, arg, peepAux(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; { peepAux(arg); }; } } }; }
;
103
104 switch (tag) {
105 case FOAM_BCall:
106 newExpr = peepBCall(expr);
107 break;
108 case FOAM_Cast:
109 newExpr = peepCast(expr);
110 break;
111 case FOAM_If:
112 newExpr = peepIf(expr);
113 break;
114 case FOAM_Select:
115 newExpr = peepSelect(expr);
116 break;
117#ifdef PeepEnv
118 case FOAM_EElt:
119 newExpr = peepEElt(expr);
120 break;
121 case FOAM_EEnv:
122 newExpr = peepEEnv(expr);
123 break;
124#endif
125 case FOAM_CCall:
126 newExpr = peepCCall(expr);
127 break;
128 case FOAM_AElt:
129 newExpr = peepAElt(expr);
130 break;
131 case FOAM_EEnsure:
132 newExpr = peepEEnsure(expr);
133 break;
134 default:
135 break;
136 }
137
138 if (expr != newExpr) {
139 foamFreeNode(expr);
140 *changed = true1;
141 }
142 return newExpr;
143}
144
145localstatic void
146peepAux(Foam *arg)
147{
148 Bool subChanged;
149 Foam newArg;
150 SExpr s = sxNil;
151
152 do {
153 subChanged = false((int) 0);
154 if (DEBUG(peep)peepDebug) {
155 s = foamToSExpr(*arg);
156 }
157 newArg = peepExpr(*arg, &subChanged);
158 if (DEBUG(peep)peepDebug) {
159 if (subChanged) {
160 sxiWrite(dbOut, s, SXRW_MixedCase(1L<<0));
161 foamWrSExpr(dbOut, newArg, SXRW_MixedCase(1L<<0));
162 fprintf(dbOut, "=====\n");
163 sxiFree(s);
164 }
165 }
166 *arg = newArg;
167 } while (subChanged);
168}
169
170#define peepHasTag(type, expr)(((expr)->hdr.tag) == type) (foamTag(expr)((expr)->hdr.tag) == type)
171
172#define peepIsBCallOf(fn, expr)(((expr) && ((expr)->hdr.tag) == FOAM_BCall &&
(expr)->foamBCall.op == (fn)))
(foamIsBCallOf(expr, fn)((expr) && ((expr)->hdr.tag) == FOAM_BCall &&
(expr)->foamBCall.op == (fn))
)
173#define peepIsTheBool(val, expr)((((expr)->hdr.tag) == FOAM_Bool) && expr->foamBool
.BoolData == val)
(peepHasTag(FOAM_Bool, expr)(((expr)->hdr.tag) == FOAM_Bool) && \
174 expr->foamBool.BoolData == val)
175#define peepIsTheSInt(val, expr)((((expr)->hdr.tag) == FOAM_SInt) && expr->foamSInt
.SIntData == val)
(peepHasTag(FOAM_SInt, expr)(((expr)->hdr.tag) == FOAM_SInt) && \
176 expr->foamSInt.SIntData == val)
177#define peepIsTheBInt(val, expr)((((expr)->hdr.tag) == FOAM_BInt) && expr->foamBInt
.BIntData == val)
(peepHasTag(FOAM_BInt, expr)(((expr)->hdr.tag) == FOAM_BInt) && \
178 expr->foamBInt.BIntData == val)
179#define peepIsTheSFlo(val, expr)((((expr)->hdr.tag) == FOAM_SFlo) && expr->foamSFlo
.SFloData == val)
(peepHasTag(FOAM_SFlo, expr)(((expr)->hdr.tag) == FOAM_SFlo) && \
180 expr->foamSFlo.SFloData == val)
181localstatic Foam
182peepAElt(Foam foam)
183{
184 AInt baseType = foam->foamAElt.baseType;
185 Foam index = foam->foamAElt.index;
186 Foam expr = foam->foamAElt.expr;
187
188 if (peepHasTag(FOAM_SInt, index)(((index)->hdr.tag) == FOAM_SInt) && peepHasTag(FOAM_Arr, expr)(((expr)->hdr.tag) == FOAM_Arr)) {
189 AInt idx = index->foamSInt.SIntData;
Value stored to 'idx' during its initialization is never read
190 return foamNew(expr->foamArr.baseType, 1, expr->foamArr.eltv[index->foamSInt.SIntData]);
191 }
192
193 return foam;
194}
195
196
197localstatic Foam
198peepBCall(Foam bcall)
199{
200 FoamBValTag tag = bcall->foamBCall.op;
201 Foam *argv = bcall->foamBCall.argv;
202 Foam foam = bcall;
203 int argc = foamBCallArgc(bcall)(((bcall)->hdr.argc) - (1));
204
205 switch (tag) {
206 /* Logical expressions */
207 case FOAM_BVal_BoolFalse:
208 foam = foamNewBool(false)foamNew(FOAM_Bool, 1, (AInt)(((int) 0)));
209 break;
210 case FOAM_BVal_BoolTrue:
211 foam = foamNewBool(true)foamNew(FOAM_Bool, 1, (AInt)(1));
212 break;
213 case FOAM_BVal_BoolNot:
214 foam = peepNegate(bcall);
215 break;
216 case FOAM_BVal_BoolAnd:
217 if (peepIsTheBool(false,argv[0])((((argv[0])->hdr.tag) == FOAM_Bool) && argv[0]->
foamBool.BoolData == ((int) 0))
) {
218 if (peepNoSideFx(argv[1])(!foamHasSideEffect(argv[1])))
219 foam = foamNewBool(false)foamNew(FOAM_Bool, 1, (AInt)(((int) 0)));
220 }
221 else if (peepIsTheBool(true,argv[0])((((argv[0])->hdr.tag) == FOAM_Bool) && argv[0]->
foamBool.BoolData == 1)
)
222 foam = argv[1];
223 else if (peepIsTheBool(false,argv[1])((((argv[1])->hdr.tag) == FOAM_Bool) && argv[1]->
foamBool.BoolData == ((int) 0))
) {
224 if (peepNoSideFx(argv[0])(!foamHasSideEffect(argv[0])))
225 foam = foamNewBool(false)foamNew(FOAM_Bool, 1, (AInt)(((int) 0)));
226 }
227 else if (peepIsTheBool(true,argv[1])((((argv[1])->hdr.tag) == FOAM_Bool) && argv[1]->
foamBool.BoolData == 1)
)
228 foam = argv[0];
229 break;
230 case FOAM_BVal_BoolOr:
231 if (peepIsTheBool(true,argv[0])((((argv[0])->hdr.tag) == FOAM_Bool) && argv[0]->
foamBool.BoolData == 1)
) {
232 if (peepNoSideFx(argv[1])(!foamHasSideEffect(argv[1])))
233 foam = foamNewBool(true)foamNew(FOAM_Bool, 1, (AInt)(1));
234 }
235 else if (peepIsTheBool(false,argv[0])((((argv[0])->hdr.tag) == FOAM_Bool) && argv[0]->
foamBool.BoolData == ((int) 0))
)
236 foam = argv[1];
237 else if (peepIsTheBool(true,argv[1])((((argv[1])->hdr.tag) == FOAM_Bool) && argv[1]->
foamBool.BoolData == 1)
) {
238 if (peepNoSideFx(argv[0])(!foamHasSideEffect(argv[0])))
239 foam = foamNewBool(true)foamNew(FOAM_Bool, 1, (AInt)(1));
240 }
241 else if (peepIsTheBool(false,argv[1])((((argv[1])->hdr.tag) == FOAM_Bool) && argv[1]->
foamBool.BoolData == ((int) 0))
)
242 foam = argv[0];
243 break;
244 case FOAM_BVal_BIntToSInt:
245 /* NB: sizeof(SInt) may vary too */
246 if (foamTag(argv[0])((argv[0])->hdr.tag) == FOAM_BInt
247 && bintSmall(argv[0]->foamBInt.BIntData)
248 && bintLT(bintAbs(argv[0]->foamBInt.BIntData),
249 bintNew(1L<<24)))
250 foam = foamNewSInt(bintSmall(argv[0]->foamBInt.BIntData))foamNew(FOAM_SInt, 1, (AInt)(bintSmall(argv[0]->foamBInt.BIntData
)))
;
251 break;
252 case FOAM_BVal_SIntToBInt:
253 if (foamTag(argv[0])((argv[0])->hdr.tag) == FOAM_SInt)
254 foam = foamNewBInt(bintNew(argv[0]->foamSInt.SIntData))foamNew(FOAM_BInt, 1, (bintNew(argv[0]->foamSInt.SIntData)
))
;
255 break;
256 default:
257 break;
258 }
259 if (foam != bcall) return foam;
260
261 /* arithmetic, and similar */
262 if (argc == 1)
263 foam = peepUnaryBCall(bcall);
264 else if (argc == 2)
265 foam = peepBinaryBCall(bcall);
266
267 return foam;
268}
269
270localstatic Foam
271peepCast(Foam cast)
272{
273 FoamTag castTag = cast->foamCast.type;
274 Foam expr = cast->foamCast.expr;
275 Foam foam = cast;
276
277 if (peepHasTag(FOAM_Cast, expr)(((expr)->hdr.tag) == FOAM_Cast)) {
278 while (peepHasTag(FOAM_Cast, expr)(((expr)->hdr.tag) == FOAM_Cast)) {
279 expr = expr->foamCast.expr;
280 }
281 foam = foamNewCast(castTag, expr)foamNew(FOAM_Cast, 2, castTag, expr);
282 }
283
284 if (peepFoamExprType(expr) == castTag)
285 return expr;
286 return foam;
287}
288
289localstatic Foam
290peepIf(Foam foam)
291{
292 if (peepIsTheBool(true, foam->foamIf.test)((((foam->foamIf.test)->hdr.tag) == FOAM_Bool) &&
foam->foamIf.test->foamBool.BoolData == 1)
)
293 return foamNewGoto(foam->foamIf.label)foamNew(FOAM_Goto, 1, (AInt)(foam->foamIf.label));
294 if (peepIsTheBool(false, foam->foamIf.test)((((foam->foamIf.test)->hdr.tag) == FOAM_Bool) &&
foam->foamIf.test->foamBool.BoolData == ((int) 0))
)
295 return foamNewNOp()foamNew(FOAM_NOp, (int) 0);
296 return foam;
297}
298
299localstatic Foam
300peepSelect(Foam foam)
301{
302 if (foamTag(foam->foamSelect.op)((foam->foamSelect.op)->hdr.tag) == FOAM_SInt) {
303 int idx = foam->foamSelect.op->foamSInt.SIntData;
304 return foamNewGoto(foam->foamSelect.argv[idx])foamNew(FOAM_Goto, 1, (AInt)(foam->foamSelect.argv[idx]));
305 }
306 return foam;
307}
308
309#ifdef PeepEnv
310localstatic Foam
311peepEElt(Foam eelt)
312{
313 Foam foam = eelt;
314 Foam ienv = eelt->foamEElt.ref;
315 int level = eelt->foamEElt.level;
316
317 if (peepHasTag(FOAM_EEnv, ienv)(((ienv)->hdr.tag) == FOAM_EEnv))
318 foam = foamNewEElt(eelt->foamEElt.env,foamNew(FOAM_EElt,4,(AInt)(eelt->foamEElt.env),ienv->foamEEnv
.env,(AInt)(level + ienv->foamEnv.level),(AInt)(eelt->foamEElt
.lex))
319 ienv->foamEEnv.env,foamNew(FOAM_EElt,4,(AInt)(eelt->foamEElt.env),ienv->foamEEnv
.env,(AInt)(level + ienv->foamEnv.level),(AInt)(eelt->foamEElt
.lex))
320 level + ienv->foamEnv.level,foamNew(FOAM_EElt,4,(AInt)(eelt->foamEElt.env),ienv->foamEEnv
.env,(AInt)(level + ienv->foamEnv.level),(AInt)(eelt->foamEElt
.lex))
321 eelt->foamEElt.lex)foamNew(FOAM_EElt,4,(AInt)(eelt->foamEElt.env),ienv->foamEEnv
.env,(AInt)(level + ienv->foamEnv.level),(AInt)(eelt->foamEElt
.lex))
;
322 else if (peepHasTag(FOAM_Env, ienv)(((ienv)->hdr.tag) == FOAM_Env))
323 foam = foamNewLex(level + ienv->foamEnv.level,foamNew(FOAM_Lex, 2, (AInt)(level + ienv->foamEnv.level), (
AInt)(eelt->foamEElt.lex))
324 eelt->foamEElt.lex )foamNew(FOAM_Lex, 2, (AInt)(level + ienv->foamEnv.level), (
AInt)(eelt->foamEElt.lex))
;
325 return foam;
326}
327
328localstatic Foam
329peepEEnv(Foam eenv)
330{
331 Foam foam = eenv;
332 Foam ienv = eenv->foamEEnv.env;
333 int count = eenv->foamEEnv.level;
334
335 if (peepHasTag(FOAM_EEnv, ienv)(((ienv)->hdr.tag) == FOAM_EEnv)) {
336 int level = count + ienv->foamEEnv.level;
337 assert(level >= 0)do { if (!(level >= 0)) _do_assert(("level >= 0"),"of_peep.c"
,337); } while (0)
; /* bug 1168 */
338 foam = foamNewEEnv(level, ienv->foamEEnv.env)foamNew(FOAM_EEnv, 2, (AInt)(level), ienv->foamEEnv.env);
339 }
340 else if (peepHasTag(FOAM_Env, ienv)(((ienv)->hdr.tag) == FOAM_Env))
341 foam = foamNewEnv(count + ienv->foamEnv.level)foamNew(FOAM_Env, 1, (AInt)(count + ienv->foamEnv.level));
342
343 return foam;
344}
345#endif
346
347localstatic Foam
348peepCCall(Foam foam)
349{
350 Foam op = foam->foamCCall.op;
351 Foam new = foam;
352 int i;
353
354 if (foamTag(foam)((foam)->hdr.tag) == FOAM_Clos) {
355 new = foamNewEmpty(FOAM_OCall, foamArgc(foam)((foam)->hdr.argc) + 1);
356 new->foamOCall.type = foam->foamCCall.type;
357 new->foamOCall.op = op->foamClos.prog;
358 new->foamOCall.env = op->foamClos.env;
359 for (i=0; i<foamArgc(foam)((foam)->hdr.argc)-2; i++)
360 new->foamOCall.argv[i] = foam->foamCCall.argv[i];
361 }
362 return new;
363}
364
365localstatic Foam
366peepEEnsure(Foam foam)
367{
368 if (foamTag(foam->foamEEnsure.env)((foam->foamEEnsure.env)->hdr.tag) == FOAM_Env)
369 return foamNewNOp()foamNew(FOAM_NOp, (int) 0);
370 else
371 return foam;
372}
373
374localstatic FoamTag
375peepFoamExprType(Foam foam)
376{
377 FoamTag tag = foamTag(foam)((foam)->hdr.tag);
378
379 if (tag<FOAM_DATA_LIMIT)
380 return tag;
381
382 switch (foamTag(foam)((foam)->hdr.tag)) {
383 case FOAM_AElt:
384 return foam->foamAElt.baseType;
385 case FOAM_PCall:
386 return foam->foamPCall.type;
387 case FOAM_BCall:
388 return foamBValInfo(foam->foamBCall.op)(foamBValInfoTable[(int)(foam->foamBCall.op)-(int)FOAM_BVAL_START
])
.retType;
389 case FOAM_CCall:
390 return foam->foamCCall.type;
391 case FOAM_OCall:
392 return foam->foamOCall.type;
393 case FOAM_Loc:
394 return peepProgram->foamProg.locals
395 ->foamDDecl.argv[foam->foamLoc.index]->foamDecl.type;
396 case FOAM_Par:
397 return peepProgram->foamProg.params
398 ->foamDDecl.argv[foam->foamPar.index]->foamDecl.type;
399 default:
400 return 0;
401 }
402}
403
404localstatic Bool
405peepFoamIsValue(FoamTag type, int value, Foam foam)
406{
407 if (foamTag(foam)((foam)->hdr.tag) != type)
408 return false((int) 0);
409
410 switch(type) {
411 case FOAM_Bool:
412 return foam->foamBool.BoolData == (AInt) value;
413 case FOAM_SInt:
414 return foam->foamSInt.SIntData == (AInt) value;
415 case FOAM_HInt:
416 return foam->foamHInt.HIntData == (AInt) value;
417 case FOAM_BInt:
418 return bintEQ(foam->foamBInt.BIntData, bintNew(value));
419 case FOAM_DFlo:
420 return foam->foamDFlo.DFloData == (DFloat) value;
421 case FOAM_SFlo:
422 return foam->foamSFlo.SFloData == (SFloat) value;
423 case FOAM_Char:
424 return foam->foamChar.CharData == (AInt) value;
425 default:
426 bug("odd");
427 NotReached(return false){(void)bug("Not supposed to reach line %d in file: %s\n",427,
"of_peep.c");}
;
428 }
429}
430
431localstatic int
432peepFoamIsPowerOf2(Foam foam)
433{
434 if (peepFoamIsValue(foamTag(foam)((foam)->hdr.tag), int0((int) 0), foam))
435 return false((int) 0);
436 if (peepFoamIsValue(foamTag(foam)((foam)->hdr.tag), 1, foam))
437 return false((int) 0);
438
439 switch (foamTag(foam)((foam)->hdr.tag)) {
440 case FOAM_SInt:
441 {
442 AInt val = (AInt) foam->foamSInt.SIntData;
443 return (val & (val - 1)) == 0;
444 }
445 break;
446 case FOAM_BInt:
447 {
448 BInt val = foam->foamBInt.BIntData;
449 return bintLength(val) > bintLength(bintMinus(val, bint1));
450 }
451 break;
452 default:
453 return false((int) 0);
454 }
455 return false((int) 0);
456}
457
458localstatic Foam
459peepFoamValue(FoamTag type, int value)
460{
461 switch(type) {
462 case FOAM_Bool:
463 return foamNewBool(value)foamNew(FOAM_Bool, 1, (AInt)(value));
464 case FOAM_SInt:
465 return foamNewSInt(value)foamNew(FOAM_SInt, 1, (AInt)(value));
466 case FOAM_HInt:
467 return foamNewHInt(value)foamNew(FOAM_HInt, 1, (AInt)(value));
468 case FOAM_BInt:
469 return foamNewBInt(bintNew(value))foamNew(FOAM_BInt, 1, (bintNew(value)));
470 case FOAM_DFlo:
471 return foamNewDFlo((DFloat) value);
472 case FOAM_SFlo:
473 return foamNewSFlo((SFloat) value);
474 case FOAM_Char:
475 return foamNewChar(value)foamNew(FOAM_Char, 1, (AInt)(value));
476 default:
477 bug("odd2");
478 NotReached(return NULL){(void)bug("Not supposed to reach line %d in file: %s\n",478,
"of_peep.c");}
;
479 }
480}
481
482/*****************************************************************************
483 *
484 * :: BCalls of arithmetic functions
485 *
486 ****************************************************************************/
487
488/* Plan is to describe the arithmetic ops, and then use peepBinary/Unary
489 * to implement them
490 *
491 * To do:
492 * associativity
493 * more types
494 * use OpZero, One instead of OpFalse, OpTrue
495 */
496enum bvalOp {
497 OpNone,
498 /* Binary */
499 OpPlus,
500 OpMinus,
501 OpTimes,
502 OpDivide,
503 OpDivRem,
504 OpGCD,
505 OpEQ,
506 OpNE,
507 OpLT,
508 OpLE,
509 /* floating point careful */
510 OpFPlus,
511 OpFMinus,
512 OpFTimes,
513 OpFDivide,
514 OpFEQ,
515 OpFNE,
516 OpFLT,
517 OpFLE,
518 OpFNeg,
519 OpFIsZero,
520 OpFIsNeg,
521 OpFIsPos,
522 /* Unary */
523 OpNeg,
524 OpNext,
525 OpPrev,
526 OpIsZero,
527 OpIsNeg,
528 OpIsPos,
529 /* nullary */
530 OpZero,
531 OpOne,
532 /*-1*/ OpMOne,
533 OpTrue,
534 OpFalse,
535 /* Faked Operations */
536 OpNonZero,
537 OpNonNeg,
538 OpNonPos,
539 OpId
540};
541
542typedef enum bvalOp BValOp;
543
544typedef struct _bvalOpInfo {
545 BValOp op;
546 int arity;
547 /* "Inverse" */
548 BValOp dual;
549 /* lhs = rhs */
550 BValOp leqr;
551 /* Operations to use if arg is literal one, zero */
552 BValOp leftOne;
553 BValOp rightOne;
554 BValOp leftZero;
555 BValOp rightZero;
556} BValOps, *BValOpInfo;
557
558typedef struct {
559 FoamBValTag foamOp;
560 FoamTag type;
561 BValOp peepOp;
562} FoamBVals, *FoamBValInfo;
563
564static FoamBValInfo peepBValTbl;
565
566static FoamBVals foamBValOpInfoTableFast[] = {
567
568{ FOAM_BVal_CharEQ, FOAM_Char, OpEQ },
569{ FOAM_BVal_CharNE, FOAM_Char, OpNE },
570{ FOAM_BVal_CharLT, FOAM_Char, OpLT },
571{ FOAM_BVal_CharLE, FOAM_Char, OpLE },
572
573{ FOAM_BVal_BoolEQ, FOAM_Bool, OpEQ },
574{ FOAM_BVal_BoolNE, FOAM_Bool, OpNE },
575
576{ FOAM_BVal_SIntPlus, FOAM_SInt, OpPlus },
577{ FOAM_BVal_SIntMinus, FOAM_SInt, OpMinus },
578{ FOAM_BVal_SIntTimes, FOAM_SInt, OpTimes },
579{ FOAM_BVal_SIntGcd, FOAM_SInt, OpGCD },
580{ FOAM_BVal_SIntDivide, FOAM_SInt, OpDivRem },
581{ FOAM_BVal_SIntEQ, FOAM_SInt, OpEQ },
582{ FOAM_BVal_SIntNE, FOAM_SInt, OpNE },
583{ FOAM_BVal_SIntLT, FOAM_SInt, OpLT },
584{ FOAM_BVal_SIntLE, FOAM_SInt, OpLE },
585{ FOAM_BVal_SIntNegate, FOAM_SInt, OpNeg },
586{ FOAM_BVal_SIntNext, FOAM_SInt, OpNext },
587{ FOAM_BVal_SIntPrev, FOAM_SInt, OpPrev },
588{ FOAM_BVal_SIntIsZero, FOAM_SInt, OpIsZero },
589{ FOAM_BVal_SIntIsPos, FOAM_SInt, OpIsPos },
590
591{ FOAM_BVal_SFloPlus, FOAM_SFlo, OpPlus },
592{ FOAM_BVal_SFloMinus, FOAM_SFlo, OpMinus },
593{ FOAM_BVal_SFloTimes, FOAM_SFlo, OpTimes },
594{ FOAM_BVal_SFloDivide, FOAM_SFlo, OpDivide },
595{ FOAM_BVal_SFloEQ, FOAM_SFlo, OpEQ },
596{ FOAM_BVal_SFloNE, FOAM_SFlo, OpNE },
597{ FOAM_BVal_SFloLT, FOAM_SFlo, OpLT },
598{ FOAM_BVal_SFloLE, FOAM_SFlo, OpLE },
599{ FOAM_BVal_SFloNegate, FOAM_SFlo, OpNeg },
600{ FOAM_BVal_SFloIsZero, FOAM_SFlo, OpIsZero },
601{ FOAM_BVal_SFloIsPos, FOAM_SFlo, OpIsPos },
602{ FOAM_BVal_SFloIsNeg, FOAM_SFlo, OpIsNeg },
603
604{ FOAM_BVal_DFloPlus, FOAM_DFlo, OpPlus },
605{ FOAM_BVal_DFloMinus, FOAM_DFlo, OpMinus },
606{ FOAM_BVal_DFloTimes, FOAM_DFlo, OpTimes },
607{ FOAM_BVal_DFloDivide, FOAM_DFlo, OpDivide },
608{ FOAM_BVal_DFloEQ, FOAM_DFlo, OpEQ },
609{ FOAM_BVal_DFloNE, FOAM_DFlo, OpNE },
610{ FOAM_BVal_DFloLT, FOAM_DFlo, OpLT },
611{ FOAM_BVal_DFloLE, FOAM_DFlo, OpLE },
612{ FOAM_BVal_DFloNegate, FOAM_DFlo, OpNeg },
613{ FOAM_BVal_DFloIsZero, FOAM_DFlo, OpIsZero },
614{ FOAM_BVal_DFloIsPos, FOAM_DFlo, OpIsPos },
615{ FOAM_BVal_DFloIsNeg, FOAM_DFlo, OpIsNeg },
616
617{ FOAM_BVal_BIntPlus, FOAM_BInt, OpPlus },
618{ FOAM_BVal_BIntMinus, FOAM_BInt, OpMinus },
619{ FOAM_BVal_BIntTimes, FOAM_BInt, OpTimes },
620{ FOAM_BVal_BIntDivide, FOAM_BInt, OpDivRem },
621{ FOAM_BVal_BIntGcd, FOAM_BInt, OpGCD },
622{ FOAM_BVal_BIntEQ, FOAM_BInt, OpEQ },
623{ FOAM_BVal_BIntNE, FOAM_BInt, OpNE },
624{ FOAM_BVal_BIntLT, FOAM_BInt, OpLT },
625{ FOAM_BVal_BIntLE, FOAM_BInt, OpLE },
626{ FOAM_BVal_BIntNegate, FOAM_BInt, OpNeg },
627{ FOAM_BVal_BIntNext, FOAM_BInt, OpNext },
628{ FOAM_BVal_BIntPrev, FOAM_BInt, OpPrev },
629{ FOAM_BVal_BIntIsZero, FOAM_BInt, OpIsZero },
630{ FOAM_BVal_BIntIsPos, FOAM_BInt, OpIsPos },
631{ FOAM_BVal_BIntIsNeg, FOAM_BInt, OpIsNeg },
632
633{ FOAM_BVAL_LIMIT, FOAM_Nil, OpNone }
634};
635
636
637static FoamBVals foamBValOpInfoTableSlow[] = {
638
639{ FOAM_BVal_CharEQ, FOAM_Char, OpEQ },
640{ FOAM_BVal_CharNE, FOAM_Char, OpNE },
641{ FOAM_BVal_CharLT, FOAM_Char, OpLT },
642{ FOAM_BVal_CharLE, FOAM_Char, OpLE },
643
644{ FOAM_BVal_BoolEQ, FOAM_Bool, OpEQ },
645{ FOAM_BVal_BoolNE, FOAM_Bool, OpNE },
646
647{ FOAM_BVal_SIntPlus, FOAM_SInt, OpPlus },
648{ FOAM_BVal_SIntMinus, FOAM_SInt, OpMinus },
649{ FOAM_BVal_SIntTimes, FOAM_SInt, OpTimes },
650{ FOAM_BVal_SIntGcd, FOAM_SInt, OpGCD },
651{ FOAM_BVal_SIntDivide, FOAM_SInt, OpDivRem },
652{ FOAM_BVal_SIntEQ, FOAM_SInt, OpEQ },
653{ FOAM_BVal_SIntNE, FOAM_SInt, OpNE },
654{ FOAM_BVal_SIntLT, FOAM_SInt, OpLT },
655{ FOAM_BVal_SIntLE, FOAM_SInt, OpLE },
656{ FOAM_BVal_SIntNegate, FOAM_SInt, OpNeg },
657{ FOAM_BVal_SIntNext, FOAM_SInt, OpNext },
658{ FOAM_BVal_SIntPrev, FOAM_SInt, OpPrev },
659{ FOAM_BVal_SIntIsZero, FOAM_SInt, OpIsZero },
660{ FOAM_BVal_SIntIsPos, FOAM_SInt, OpIsPos },
661{ FOAM_BVal_SIntIsNeg, FOAM_SInt, OpIsNeg },
662
663{ FOAM_BVal_SFloPlus, FOAM_SFlo, OpFPlus },
664{ FOAM_BVal_SFloMinus, FOAM_SFlo, OpFMinus },
665{ FOAM_BVal_SFloTimes, FOAM_SFlo, OpFTimes },
666{ FOAM_BVal_SFloDivide, FOAM_SFlo, OpFDivide },
667{ FOAM_BVal_SFloEQ, FOAM_SFlo, OpFEQ },
668{ FOAM_BVal_SFloNE, FOAM_SFlo, OpFNE },
669{ FOAM_BVal_SFloLT, FOAM_SFlo, OpFLT },
670{ FOAM_BVal_SFloLE, FOAM_SFlo, OpFLE },
671{ FOAM_BVal_SFloNegate, FOAM_SFlo, OpFNeg },
672{ FOAM_BVal_SFloIsZero, FOAM_SFlo, OpFIsZero },
673{ FOAM_BVal_SFloIsPos, FOAM_SFlo, OpFIsPos },
674{ FOAM_BVal_SFloIsNeg, FOAM_SFlo, OpFIsNeg },
675
676{ FOAM_BVal_DFloPlus, FOAM_DFlo, OpFPlus },
677{ FOAM_BVal_DFloMinus, FOAM_DFlo, OpFMinus },
678{ FOAM_BVal_DFloTimes, FOAM_DFlo, OpFTimes },
679{ FOAM_BVal_DFloDivide, FOAM_DFlo, OpFDivide },
680{ FOAM_BVal_DFloEQ, FOAM_DFlo, OpFEQ },
681{ FOAM_BVal_DFloNE, FOAM_DFlo, OpFNE },
682{ FOAM_BVal_DFloLT, FOAM_DFlo, OpFLT },
683{ FOAM_BVal_DFloLE, FOAM_DFlo, OpFLE },
684{ FOAM_BVal_DFloNegate, FOAM_DFlo, OpFNeg },
685{ FOAM_BVal_DFloIsZero, FOAM_DFlo, OpFIsZero },
686{ FOAM_BVal_DFloIsPos, FOAM_DFlo, OpFIsPos },
687{ FOAM_BVal_DFloIsNeg, FOAM_DFlo, OpFIsNeg },
688
689{ FOAM_BVal_BIntPlus, FOAM_BInt, OpPlus },
690{ FOAM_BVal_BIntMinus, FOAM_BInt, OpMinus },
691{ FOAM_BVal_BIntTimes, FOAM_BInt, OpTimes },
692{ FOAM_BVal_BIntDivide, FOAM_BInt, OpDivRem },
693{ FOAM_BVal_BIntGcd, FOAM_BInt, OpGCD },
694{ FOAM_BVal_BIntEQ, FOAM_BInt, OpEQ },
695{ FOAM_BVal_BIntNE, FOAM_BInt, OpNE },
696{ FOAM_BVal_BIntLT, FOAM_BInt, OpLT },
697{ FOAM_BVal_BIntLE, FOAM_BInt, OpLE },
698{ FOAM_BVal_BIntNegate, FOAM_BInt, OpNeg },
699{ FOAM_BVal_BIntNext, FOAM_BInt, OpNext },
700{ FOAM_BVal_BIntPrev, FOAM_BInt, OpPrev },
701{ FOAM_BVal_BIntIsZero, FOAM_BInt, OpIsZero },
702{ FOAM_BVal_BIntIsPos, FOAM_BInt, OpIsPos },
703{ FOAM_BVal_BIntIsNeg, FOAM_BInt, OpIsNeg },
704
705{ FOAM_BVAL_LIMIT, FOAM_Nil, OpNone }
706};
707
708
709
710
711
712
713localstatic Foam peepMakeUnaryOp (BValOp, FoamTag, Foam);
714localstatic Foam peepMakeBinaryOp (BValOp, FoamTag, Foam, Foam);
715localstatic FoamBValInfo peepFindOpInfo (FoamBValTag);
716localstatic FoamBValTag peepFindFoamOp (BValOp, FoamTag);
717localstatic Foam peepAdditiveOp (FoamTag, BValOp, Foam, Foam);
718localstatic Foam peepTimesOp (FoamTag, BValOp, Foam, Foam);
719localstatic Foam peepPositive (Foam);
720
721/* Could warn about potential zero-divides here */
722/* NB: gcd(x,x) = x iff x>=0 */
723BValOps peepBValOpInfo[] = {
724/* op arity dual l=r l=1 r=1 l=0 r=0 */
725{ OpNone, 0, OpNone, OpNone, OpNone, OpNone, OpNone, OpNone },
726{ OpPlus, 2, OpNone, OpNone, OpNext, OpNext, OpId, OpId },
727{ OpMinus, 2, OpNone, OpZero, OpNone, OpPrev, OpNeg, OpId },
728{ OpTimes, 2, OpNone, OpNone, OpId, OpId, OpZero, OpZero },
729{ OpDivide, 2, OpNone, OpOne, OpNone, OpId, OpZero, OpNone },
730{ OpDivRem, 2, OpNone, OpNone, OpNone, OpNone, OpNone, OpNone },
731{ OpGCD, 2, OpNone, OpNone, OpOne, OpOne, OpNone, OpNone },
732
733/* Boolean ops (don't map ~(a < b) into (b <= a) as jflow can't cope) */
734{ OpEQ, 2, OpNE, OpTrue, OpNone, OpNone, OpIsZero, OpIsZero },
735{ OpNE, 2, OpEQ, OpFalse, OpNone, OpNone, OpNonZero, OpNonZero },
736{ OpLT, 2, OpNone, OpFalse, OpNone, OpNone, OpIsPos, OpIsNeg },
737{ OpLE, 2, OpLT, OpTrue, OpNone, OpNone, OpNonNeg, OpNonPos },
738
739/* floating point careful (IEEE)*/
740{ OpFPlus, 2, OpNone, OpNone, OpNone, OpNone, OpNone, OpNone },
741{ OpFMinus, 2, OpNone, OpNone, OpNone, OpNone, OpNone, OpNone },
742{ OpFTimes, 2, OpNone, OpNone, OpId, OpId, OpNone, OpNone },
743{ OpFDivide, 2, OpNone, OpNone, OpNone, OpId, OpNone, OpNone },
744{ OpFEQ, 2, OpNE, OpNone, OpNone, OpNone, OpIsZero, OpIsZero },
745{ OpFNE, 2, OpEQ, OpNone, OpNone, OpNone, OpNonZero, OpNonZero },
746{ OpFLT, 2, OpNone, OpNone, OpNone, OpNone, OpIsPos, OpIsNeg },
747{ OpFLE, 2, OpNone, OpNone, OpNone, OpNone, OpNonNeg, OpNonPos },
748{ OpFNeg, 1, OpNone, OpNone, OpNone, OpNone, OpNone, OpNone },
749{ OpFIsZero, 1, OpNone, OpNone, OpFalse, OpNone, OpNone, OpNone},
750{ OpFIsNeg, 1, OpNone, OpNone, OpFalse, OpNone, OpNone, OpNone},
751{ OpFIsPos, 1, OpNone, OpNone, OpTrue, OpNone, OpNone, OpNone},
752/* Unary operations (on lhs) */
753{ OpNeg, 1, OpNeg, OpNone, OpMOne, OpNone, OpZero, OpNone},
754{ OpNext, 1, OpPrev, OpNone, OpNone, OpNone, OpOne, OpNone},
755{ OpPrev, 1, OpNext, OpNone, OpZero, OpNone, OpMOne, OpNone},
756{ OpIsZero, 1, OpNone, OpNone, OpFalse, OpNone, OpTrue, OpNone},
757{ OpIsNeg, 1, OpNone, OpNone, OpFalse, OpNone, OpFalse, OpNone},
758{ OpIsPos, 1, OpNone, OpNone, OpTrue, OpNone, OpFalse, OpNone},
759/* faked */
760{ OpZero, 0, OpNone, OpNone, OpNone, OpNone, OpNone, OpNone},
761{ OpOne, 0, OpNone, OpNone, OpNone, OpNone, OpNone, OpNone},
762{ OpMOne, 0, OpNone, OpNone, OpNone, OpNone, OpNone, OpNone},
763{ OpTrue, 0, OpNone, OpNone, OpNone, OpNone, OpNone, OpNone},
764{ OpFalse, 0, OpNone, OpNone, OpNone, OpNone, OpNone, OpNone},
765/* Finis. */
766{ -1, 1, OpNone, OpNone, OpNone, OpNone, OpNone, OpNone}
767};
768
769
770localstatic Foam
771peepBinaryBCall(Foam bcall)
772{
773 Foam l = bcall->foamBCall.argv[0];
774 Foam r = bcall->foamBCall.argv[1];
775 Foam arg = NULL((void*)0), new;
776 FoamBValTag op = bcall->foamBCall.op;
777 FoamTag type;
778 FoamBValInfo bopInfo = peepFindOpInfo(op);
779 BValOp bop, newOp = OpNone;
780
781 if (bopInfo == NULL((void*)0))
782 return bcall;
783
784 type = bopInfo->type;
785 bop = bopInfo->peepOp;
786 assert(peepBValOpInfo[bop].op == bop)do { if (!(peepBValOpInfo[bop].op == bop)) _do_assert(("peepBValOpInfo[bop].op == bop"
),"of_peep.c",786); } while (0)
;
787
788 if (bop == OpPlus || bop == OpMinus) {
789 new = peepAdditiveOp(type, bop, l, r);
790 if (new) return new;
791 }
792 if (bop == OpTimes) {
793 new = peepTimesOp(type, bop, l, r);
794 if (new) return new;
795 }
796 if ( (!foamHasSideEffect(l)) && foamEqual(l, r)) {
797 newOp = peepBValOpInfo[bop].leqr;
798 arg = l;
799 }
800 if (peepBValOpInfo[bop].leftZero != OpNone
801 && peepFoamIsValue(type, int0((int) 0), l)) {
802 newOp = peepBValOpInfo[bop].leftZero;
803 arg = r;
804 }
805 else if (peepBValOpInfo[bop].leftOne != OpNone
806 && peepFoamIsValue(type, 1, l)) {
807 newOp = peepBValOpInfo[bop].leftOne;
808 arg = r;
809 }
810 else if (peepBValOpInfo[bop].rightZero != OpNone
811 && peepFoamIsValue(type, int0((int) 0), r)) {
812 newOp = peepBValOpInfo[bop].rightZero;
813 arg = l;
814 }
815 else if (peepBValOpInfo[bop].rightOne != OpNone
816 && peepFoamIsValue(type, 1, r)) {
817 newOp = peepBValOpInfo[bop].rightOne;
818 arg = l;
819 }
820
821 if (newOp == OpNone)
822 return bcall;
823
824 new = peepMakeUnaryOp(newOp, type, arg);
825
826 return new != NULL((void*)0) ? new : bcall;
827
828}
829
830localstatic Foam
831peepUnaryBCall(Foam bcall)
832{
833 Foam arg = bcall->foamBCall.argv[0];
834 FoamBValTag op = bcall->foamBCall.op;
835 FoamBValInfo bopInfo, inInfo;
836
837 if (foamTag(arg)((arg)->hdr.tag) != FOAM_BCall)
838 return bcall;
839
840 bopInfo = peepFindOpInfo(op);
841 inInfo = peepFindOpInfo(arg->foamBCall.op);
842
843 if (bopInfo == NULL((void*)0) || inInfo == NULL((void*)0))
844 return bcall;
845
846 /* inverse ? */
847 if (peepBValOpInfo[bopInfo->peepOp].dual == inInfo->peepOp)
848 return arg->foamBCall.argv[0];
849
850 return bcall;
851}
852
853
854localstatic Foam
855peepNegate(Foam foam)
856{
857 Foam arg = foam->foamBCall.argv[0];
858 Foam new = foam;
859 FoamBValTag op;
860 int argc;
861 FoamBValInfo bopInfo;
862
863 if (foamTag(arg)((arg)->hdr.tag) != FOAM_BCall)
864 return foam;
865
866 op = arg->foamBCall.op;
867 argc = foamBCallArgc(arg)(((arg)->hdr.argc) - (1));
868 bopInfo = peepFindOpInfo(op);
869
870 if (argc == 1 && op == FOAM_BVal_BoolNot)
871 new = arg->foamBCall.argv[0];
872 else if (bopInfo == NULL((void*)0))
873 return foam;
874 else if (argc == 2
875 && peepBValOpInfo[bopInfo->peepOp].dual != OpNone
876 && (peepNoSideFx(arg->foamBCall.argv[0])(!foamHasSideEffect(arg->foamBCall.argv[0]))
877 || peepNoSideFx(arg->foamBCall.argv[1])(!foamHasSideEffect(arg->foamBCall.argv[1])))) {
878 /* Deal with an inverse/dual relationship */
879 new = peepMakeBinaryOp(peepBValOpInfo[bopInfo->peepOp].dual,
880 bopInfo->type,
881 arg->foamBCall.argv[1],
882 arg->foamBCall.argv[0]);
883 if (!new)
884 new = foam;
885 }
886 return new;
887}
888
889
890localstatic Foam
891peepMakeUnaryOp(BValOp op, FoamTag type, Foam arg0)
892{
893 Foam new = NULL((void*)0);
894 FoamBValTag fop;
895
896 if (peepBValOpInfo[op].arity == 0 &&
897 !peepNoSideFx(arg0)(!foamHasSideEffect(arg0)))
898 return NULL((void*)0);
899
900 switch(op) {
901 case OpZero:
902 new = peepFoamValue(type, int0((int) 0));
903 break;
904 case OpOne:
905 new = peepFoamValue(type, 1);
906 break;
907 case OpMOne:
908 new = peepFoamValue(type, -1);
909 break;
910 case OpTrue:
911 new = foamNewBool(true)foamNew(FOAM_Bool, 1, (AInt)(1));
912 break;
913 case OpFalse:
914 new = foamNewBool(false)foamNew(FOAM_Bool, 1, (AInt)(((int) 0)));
915 break;
916 case OpId:
917 new = arg0;
918 break;
919 case OpNonZero:
920 if (peepFindFoamOp(OpIsZero, type))
921 new = foamNew(FOAM_BCall, 2, FOAM_BVal_BoolNot,
922 peepMakeUnaryOp(OpIsZero, type, arg0));
923 break;
924 case OpNonPos:
925 if (peepFindFoamOp(OpIsPos, type))
926 new = foamNew(FOAM_BCall, 2, FOAM_BVal_BoolNot,
927 peepMakeUnaryOp(OpIsPos, type, arg0));
928 break;
929 case OpNonNeg:
930 if (peepFindFoamOp(OpIsNeg, type))
931 new = foamNew(FOAM_BCall, 2, FOAM_BVal_BoolNot,
932 peepMakeUnaryOp(OpIsNeg, type, arg0));
933 break;
934 default:
935 fop = peepFindFoamOp(op, type);
936 if (fop)
937 new = foamNew(FOAM_BCall, 2, fop, arg0);
938 }
939 return new;
940}
941
942localstatic Foam
943peepMakeBinaryOp(BValOp op, FoamTag type, Foam arg0, Foam arg1)
944{
945 FoamBValTag fop = peepFindFoamOp(op, type);
946 Foam new;
947
948 if (!fop)
949 return NULL((void*)0);
950 new = foamNew(FOAM_BCall, 3,
951 fop, arg0, arg1);
952
953 return new;
954}
955
956localstatic FoamBValInfo
957peepFindOpInfo(FoamBValTag op)
958{
959 FoamBValInfo info = peepBValTbl;
960
961 while (info->foamOp != FOAM_BVAL_LIMIT) {
962 if (info->foamOp == op)
963 return info;
964 info++;
965 }
966 return NULL((void*)0);
967}
968
969localstatic FoamBValTag
970peepFindFoamOp(BValOp op, FoamTag type)
971{
972 FoamBValInfo info = peepBValTbl;
973
974 while (info->foamOp != FOAM_BVAL_LIMIT) {
975 if (info->peepOp == op && info->type == type)
976 return info->foamOp;
977 info++;
978 }
979 return 0;
980}
981
982localstatic Foam
983peepAdditiveOp(FoamTag type, BValOp bop, Foam lhs, Foam rhs)
984{
985 Foam tmp, pos = NULL((void*)0), new;
986
987 if (bop == OpPlus) {
988 /* (-a) + b ==> b - a */
989 pos = peepPositive(lhs);
990 if (pos) {
991 tmp = lhs;
992 lhs = rhs;
993 rhs = tmp;
994 }
995 }
996 /* a +/- (-b) ==> a -/+ b */
997 if (!pos)
998 pos = peepPositive(rhs);
999
1000 if (!pos)
1001 return NULL((void*)0);
1002
1003 new = peepMakeBinaryOp( bop == OpPlus ? OpMinus : OpPlus, type,
1004 lhs, pos);
1005
1006 return new;
1007}
1008
1009localstatic Foam
1010peepTimesOp(FoamTag tag, BValOp op, Foam l, Foam r)
1011{
1012 int shift;
1013
1014 if (tag != FOAM_BInt && tag != FOAM_SInt)
1015 return NULL((void*)0);
1016
1017 if (otIsFoamConst(l)(((l)->hdr.tag) < FOAM_DATA_LIMIT)) {
1018 Foam tmp = l;
1019 l = r;
1020 r = tmp;
1021 }
1022
1023 if (!otIsFoamConst(r)(((r)->hdr.tag) < FOAM_DATA_LIMIT))
1024 return NULL((void*)0);
1025
1026 if (!peepFoamIsPowerOf2(r))
1027 return NULL((void*)0);
1028
1029 switch (foamTag(r)((r)->hdr.tag)) {
1030 case FOAM_SInt:
1031 shift = intLength(r->foamSInt.SIntData) - 1;
1032 /* Shifting it not defined for bigger numbers */
1033 if (shift > 30) return NULL((void*)0);
1034 return foamNew(FOAM_BCall, 3, FOAM_BVal_SIntShiftUp, l,
1035 foamNewSInt(shift)foamNew(FOAM_SInt, 1, (AInt)(shift)));
1036 break;
1037 case FOAM_BInt:
1038 shift = bintLength(r->foamBInt.BIntData) - 1;
1039 return foamNew(FOAM_BCall, 3, FOAM_BVal_BIntShiftUp, l,
1040 foamNewSInt(shift)foamNew(FOAM_SInt, 1, (AInt)(shift)));
1041 break;
1042 default:
1043 break;
1044 }
1045 return NULL((void*)0);
1046}
1047
1048localstatic Foam
1049peepPositive(Foam expr)
1050{
1051 Foam new = NULL((void*)0);
1052 FoamBValInfo info;
1053
1054 switch (foamTag(expr)((expr)->hdr.tag)) {
1055 case FOAM_BCall:
1056 info = peepFindOpInfo(expr->foamBCall.op);
1057 if (info && info->peepOp == OpNeg) {
1058 new = expr->foamBCall.argv[0];
1059 }
1060 break;
1061 case FOAM_BInt:
1062 if (bintIsNeg(expr->foamBInt.BIntData))
1063 new = foamNewBInt(bintNegate(expr->foamBInt.BIntData))foamNew(FOAM_BInt, 1, (bintNegate(expr->foamBInt.BIntData)
))
;
1064 break;
1065 case FOAM_SInt:
1066 if (expr->foamSInt.SIntData < 0)
1067 new = foamNewSInt(-expr->foamSInt.SIntData)foamNew(FOAM_SInt, 1, (AInt)(-expr->foamSInt.SIntData));
1068 break;
1069 default:
1070 break;
1071 }
1072
1073 return new;
1074}
1075
1076Foam
1077peepProg(Foam prog,Bool foldfloats)
1078{
1079 int i;
1080 Bool changed = false((int) 0);
1081 Foam body = prog->foamProg.body;
1082
1083 if (foldfloats) peepBValTbl = &foamBValOpInfoTableFast[0];
1084 else peepBValTbl = &foamBValOpInfoTableSlow[0];
1085
1086 if (!optIsPeepPending(prog)(((prog)->hdr.info.opt)->optMask & (1 << 4))) return prog;
1087 optResetPeepPending(prog)(((prog)->hdr.info.opt)->optMask &= ~(1 << 4)
)
;
1088
1089 peepProgram = prog;
1090
1091 assert(foamTag(prog) == FOAM_Prog)do { if (!(((prog)->hdr.tag) == FOAM_Prog)) _do_assert(("foamTag(prog) == FOAM_Prog"
),"of_peep.c",1091); } while (0)
;
1092 assert(foamTag(body) == FOAM_Seq)do { if (!(((body)->hdr.tag) == FOAM_Seq)) _do_assert(("foamTag(body) == FOAM_Seq"
),"of_peep.c",1092); } while (0)
;
1093
1094 for(i=0; i<foamArgc(body)((body)->hdr.argc); i++)
1095 body->foamSeq.argv[i] = peepExpr(body->foamSeq.argv[i],
1096 &changed);
1097
1098 if (changed)
1099 optSetJFlowPending(prog)(((prog)->hdr.info.opt)->optMask |= (1 << 1));
1100
1101 return prog;
1102}
1103