Bug Summary

File:src/of_inlin.c
Warning:line 3404, column 2
Value stored to 'iRhs' 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_inlin.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_inlin.c
1/*****************************************************************************
2 *
3 * of_inlin.c: Inlining Foam functions.
4 *
5 * Copyright (c) 1990-2007 Aldor Software Organization Ltd (Aldor.org).
6 *
7 ****************************************************************************/
8
9/*
10 * This file implements Foam procedural integration.
11 *
12 * The foam unit passed to the inliner is destructively updated by
13 * inlining calls to procedures for which we have permission to inline,
14 * and which we decide are small enough to inline. We also integrate
15 * non-program constants.
16 *
17 * Inlining information is communicated though symbol meanings. During
18 * genfoam and constant folding if a symbol meaning has a constant value
19 * we put its constant number from its unit into the constNum field
20 * of the symbol meaning. Since shared symbol meanings may be held in
21 * separate Syme structures, we use the syme->defNum field and a translation
22 * table maintained by genfoam to map to the true constant number.
23 * Note that the value of the constant pointed to by the syme has slightly
24 * different meanings for program and non-program values. For programs
25 * the the consant is the FOAM_Prog part of a closure; the environment
26 * part is determined from the call. For non-programs the constant is the
27 * actual value to be inlined.
28 *
29 * We maintain two separate bounds for the maximum size of a program to be
30 * inlined. The first is used by all programs except ones with the
31 * INL_InlineMe bit set; for these programs, we use the larger limit.
32 * Currently we only set that bit for generator functions.
33 *
34 * This program also handles inlining of operation that were originally
35 * exported from domains which were parameters to other domains.
36 * For example, when we use the type Complex(DoubleFloat) we can inline
37 * all the operations from the DoubleFloat domain as well as the operation
38 * from Complex(DoubleFloat). This is done by computing substitution lists
39 * for the exporters of the operation from paramterized domains.
40 *
41 * To Do:
42 * Inline operations from default packages.
43 * To do this, we need to be able to walk up the category
44 * hierarchy at compile time, and look for default operations.
45 * We will also need to have inlining permission from every
46 * category on the way up, as well as the category with the
47 * default.
48 * Dynamically compute inlining size bounds.
49 * Currently we have hard-coded inliiner size limits which
50 * can cause problems for large programs. We should instead
51 * walk over a unit, measuring program sizes, and the sizes
52 * of programs we want to inline, and dynamically compute
53 * a bound that won't make the inlined unit to huge. There
54 * should always be a minmum size of at least 1 so that
55 * operations which are just calls to builtins will always be
56 * inlined.
57 * Inline based more on whether envirnonment merging will take place.
58 * The biggest payoff from inlining comes when we can merge
59 * the envirnomnet, and data of the function we inlined.
60 * Thus we need to give higher weight to functions which create
61 * heap storage that we can merge.
62 * Inline from Basic
63 * The scope binder should set the inline bit on syme.
64 * currently the inliner walks the inline declarations to
65 * determine when we have permission to inline, but it doesn't
66 * understand "inline from Basic".
67 ***************************************************************************
68 *
69 * !!!!!!!!!!!!!!!!!!!!!!!!!!! README !!!!!!!!!!!!!!!!!!!!!!!!
70 *
71 * 13 June 1994, PI: Part of the previous documentation is out of date.
72 * The inlining strategy has been completely redesigned. For each prog a
73 * priority queue is built to choose the best set of functions to inline.
74 * Elements that are considered assigning the priority are:
75 * - loop depth
76 * - size of the function to inline
77 * - nature of the function (generator, monostatement, ...)
78 * - expected growth of the caller after inlining
79 * - constant parameters in the call (-> good chance for the other opt.)
80 * - other
81 *
82 * Other changes regard the way in which function calls are evaluated,
83 * in the sense that all the information about size, time, nature, etc. is
84 * stored in the header of each function. The inliner doesn't need anymore
85 * to traverse a local call and -in the case of external call- to get
86 * the entire function body from the library to decide whether or not to
87 * inline.
88 * Finally, dataflow analysis and flowgraph construction has been introduced
89 * to get a safer and more powerful inlining.
90 *
91 ***************************************************************************
92 * ToDo:
93 * - Performances of the inliner can be substantially improved using
94 * flowgraph merging and local dataflow analysis. When a call is inlined,
95 * infact, the flowgraph is now converted to a prog, again to a flowgraph
96 * and usedef chains for the entire flog are recomputed. This process can
97 * greatly be simplified with some work.
98 *
99 ***************************************************************************/
100
101#include "debug.h"
102#include "flog.h"
103#include "fluid.h"
104#include "format.h"
105#include "genfoam.h"
106#include "gf_rtime.h"
107#include "inlutil.h"
108#include "loops.h"
109#include "of_inlin.h"
110#include "of_util.h"
111#include "optfoam.h"
112#include "optinfo.h"
113#include "opttools.h"
114#include "stab.h"
115#include "store.h"
116#include "util.h"
117#include "sefo.h"
118#include "lib.h"
119#include "tqual.h"
120#include "tfsat.h"
121#include "absub.h"
122#include "abpretty.h"
123#include "symbol.h"
124#include "strops.h"
125#include "fbox.h"
126
127
128/*****************************************************************************
129 *
130 * :: Local Structures declarations
131 *
132 ****************************************************************************/
133
134typedef Foam InlProgInfo; /* InlProgInfo is a foamProg without children */
135
136/*
137 * Elements of a association list of format numbers with their library of
138 * origin.
139 */
140typedef struct formatInfo {
141 Lib origin;
142 AInt extfmt;
143 AInt locfmt;
144 Hash hash;
145 Foam ddecl; /* SHARED */
146} *FmtInfo;
147
148DECLARE_LIST(FmtInfo)typedef struct FmtInfoListCons { FmtInfo first; struct FmtInfoListCons
*rest; } *FmtInfoList; struct FmtInfo_listOpsStruct { FmtInfoList
(*Cons) (FmtInfo, FmtInfoList); FmtInfoList (*Singleton) (FmtInfo
); FmtInfoList (*List) (int n, ...); FmtInfoList (*Listv) (va_list
argp); FmtInfoList (*ListNull) (FmtInfo, ...); Bool (*Equal)
(FmtInfoList, FmtInfoList, Bool (*f) (FmtInfo, FmtInfo)); FmtInfo
(*Find) (FmtInfoList, FmtInfo, Bool(*eq)(FmtInfo,FmtInfo) , int
*); FmtInfo (*Match) (FmtInfoList, void *, Bool(*match)(FmtInfo
, void *), int *); FmtInfoList (*MatchAll) (FmtInfoList, void
*, Bool(*match)(FmtInfo, void *)); FmtInfoList (*FreeCons) (
FmtInfoList); void (*Free) (FmtInfoList); FmtInfoList (*FreeTo
) (FmtInfoList, FmtInfoList); void (*FreeDeeply) (FmtInfoList
, void (*f)(FmtInfo)); FmtInfoList (*FreeDeeplyTo) (FmtInfoList
, FmtInfoList, void (*f) (FmtInfo) ); FmtInfoList (*FreeIfSat
) (FmtInfoList, void (*f)(FmtInfo), Bool (*s)(FmtInfo)); FmtInfo
(*Elt) (FmtInfoList, Length); FmtInfoList (*Drop) (FmtInfoList
, Length); FmtInfoList (*LastCons) (FmtInfoList); Length (*_Length
) (FmtInfoList); Bool (*IsLength) (FmtInfoList, Length); Bool
(*IsShorter) (FmtInfoList, Length); Bool (*IsLonger) (FmtInfoList
, Length); FmtInfoList (*Copy) (FmtInfoList); FmtInfoList (*CopyTo
) (FmtInfoList, FmtInfoList); FmtInfoList (*CopyDeeply) (FmtInfoList
, FmtInfo (*)(FmtInfo)); FmtInfoList (*CopyDeeplyTo) (FmtInfoList
, FmtInfoList, FmtInfo (*)(FmtInfo)); FmtInfoList (*Map) (FmtInfo
(*f)(FmtInfo), FmtInfoList); FmtInfoList (*NMap) (FmtInfo (*
f)(FmtInfo), FmtInfoList); FmtInfoList (*Reverse) (FmtInfoList
); FmtInfoList (*NReverse) (FmtInfoList); FmtInfoList (*Concat
) (FmtInfoList, FmtInfoList); FmtInfoList (*NConcat) (FmtInfoList
, FmtInfoList); Bool (*Memq) (FmtInfoList, FmtInfo); Bool (*Member
) (FmtInfoList, FmtInfo, Bool(*eq)(FmtInfo,FmtInfo) ); Bool (
*ContainsAllq) (FmtInfoList, FmtInfoList); Bool (*ContainsAnyq
) (FmtInfoList, FmtInfoList); Bool (*ContainsAll) (FmtInfoList
, FmtInfoList, Bool (*eq)(FmtInfo, FmtInfo)); Bool (*ContainsAny
) (FmtInfoList, FmtInfoList, Bool (*eq)(FmtInfo, FmtInfo)); int
(*Posq) (FmtInfoList, FmtInfo); int (*Position) (FmtInfoList
, FmtInfo, Bool(*eq)(FmtInfo,FmtInfo) ); FmtInfoList (*NRemove
) (FmtInfoList, FmtInfo, Bool(*eq)(FmtInfo,FmtInfo) ); void (
*FillVector) (FmtInfo *, FmtInfoList); int (*Print) (FILE *, FmtInfoList
, int (*pr)(FILE *, FmtInfo) ); int (*GPrint) (FILE *, FmtInfoList
, int (*pr)(FILE *, FmtInfo), char *l,char *m,char *r); int (
*Format) (OStream, CString, FmtInfoList); }; extern struct FmtInfo_listOpsStruct
const *FmtInfo_listPointer
;
149CREATE_LIST(FmtInfo)struct FmtInfo_listOpsStruct const *FmtInfo_listPointer = (struct
FmtInfo_listOpsStruct const *) &ptrlistOps
;
150
151/*
152 * Structure which associates constants and their library of origin
153 * with their local contant index, declaration Foam and value Foam
154 */
155typedef struct constInfo {
156 Lib origin;
157 int extConst;
158 int locConst;
159 Foam def;
160 Foam decl;
161} *ConstInfo;
162
163DECLARE_LIST(ConstInfo)typedef struct ConstInfoListCons { ConstInfo first; struct ConstInfoListCons
*rest; } *ConstInfoList; struct ConstInfo_listOpsStruct { ConstInfoList
(*Cons) (ConstInfo, ConstInfoList); ConstInfoList (*Singleton
) (ConstInfo); ConstInfoList (*List) (int n, ...); ConstInfoList
(*Listv) (va_list argp); ConstInfoList (*ListNull) (ConstInfo
, ...); Bool (*Equal) (ConstInfoList, ConstInfoList, Bool (*f
) (ConstInfo, ConstInfo)); ConstInfo (*Find) (ConstInfoList, ConstInfo
, Bool(*eq)(ConstInfo,ConstInfo) , int *); ConstInfo (*Match)
(ConstInfoList, void *, Bool(*match)(ConstInfo, void *), int
*); ConstInfoList (*MatchAll) (ConstInfoList, void *, Bool(*
match)(ConstInfo, void *)); ConstInfoList (*FreeCons) (ConstInfoList
); void (*Free) (ConstInfoList); ConstInfoList (*FreeTo) (ConstInfoList
, ConstInfoList); void (*FreeDeeply) (ConstInfoList, void (*f
)(ConstInfo)); ConstInfoList (*FreeDeeplyTo) (ConstInfoList, ConstInfoList
, void (*f) (ConstInfo) ); ConstInfoList (*FreeIfSat) (ConstInfoList
, void (*f)(ConstInfo), Bool (*s)(ConstInfo)); ConstInfo (*Elt
) (ConstInfoList, Length); ConstInfoList (*Drop) (ConstInfoList
, Length); ConstInfoList (*LastCons) (ConstInfoList); Length (
*_Length) (ConstInfoList); Bool (*IsLength) (ConstInfoList, Length
); Bool (*IsShorter) (ConstInfoList, Length); Bool (*IsLonger
) (ConstInfoList, Length); ConstInfoList (*Copy) (ConstInfoList
); ConstInfoList (*CopyTo) (ConstInfoList, ConstInfoList); ConstInfoList
(*CopyDeeply) (ConstInfoList, ConstInfo (*)(ConstInfo)); ConstInfoList
(*CopyDeeplyTo) (ConstInfoList, ConstInfoList, ConstInfo (*)
(ConstInfo)); ConstInfoList (*Map) (ConstInfo (*f)(ConstInfo)
, ConstInfoList); ConstInfoList (*NMap) (ConstInfo (*f)(ConstInfo
), ConstInfoList); ConstInfoList (*Reverse) (ConstInfoList); ConstInfoList
(*NReverse) (ConstInfoList); ConstInfoList (*Concat) (ConstInfoList
, ConstInfoList); ConstInfoList (*NConcat) (ConstInfoList, ConstInfoList
); Bool (*Memq) (ConstInfoList, ConstInfo); Bool (*Member) (ConstInfoList
, ConstInfo, Bool(*eq)(ConstInfo,ConstInfo) ); Bool (*ContainsAllq
) (ConstInfoList, ConstInfoList); Bool (*ContainsAnyq) (ConstInfoList
, ConstInfoList); Bool (*ContainsAll) (ConstInfoList, ConstInfoList
, Bool (*eq)(ConstInfo, ConstInfo)); Bool (*ContainsAny) (ConstInfoList
, ConstInfoList, Bool (*eq)(ConstInfo, ConstInfo)); int (*Posq
) (ConstInfoList, ConstInfo); int (*Position) (ConstInfoList,
ConstInfo, Bool(*eq)(ConstInfo,ConstInfo) ); ConstInfoList (
*NRemove) (ConstInfoList, ConstInfo, Bool(*eq)(ConstInfo,ConstInfo
) ); void (*FillVector) (ConstInfo *, ConstInfoList); int (*Print
) (FILE *, ConstInfoList, int (*pr)(FILE *, ConstInfo) ); int
(*GPrint) (FILE *, ConstInfoList, int (*pr)(FILE *, ConstInfo
), char *l,char *m,char *r); int (*Format) (OStream, CString,
ConstInfoList); }; extern struct ConstInfo_listOpsStruct const
*ConstInfo_listPointer
;
164CREATE_LIST(ConstInfo)struct ConstInfo_listOpsStruct const *ConstInfo_listPointer =
(struct ConstInfo_listOpsStruct const *) &ptrlistOps
;
165
166/*
167 * Structure describing every thing the inliner needs to know about the
168 * foamUnit it is inlining.
169 */
170typedef struct unitInfo {
171 Foam unit; /* Foam for the unit. */
172 FoamBox globals; /* Decls for globals in unit */
173 FmtInfoList formatRefList; /* Assoc list of libs and formats */
174 FoamBox formats; /* new format DDecls */
175 ConstInfoList constList; /* Assoc list of inlined constants */
176 int constc; /* Number of constants in unit */
177 Foam *constv; /* Array of constant values */
178 Bool changed; /* True if unit was inlined */
179 FoamBox *formatBoxes; /* FoamBox for each format */
180
181 ULong originalSize; /* Size before inlining */
182 ULong size; /* Current size for the unit */
183
184} *UnitInfo;
185
186/*
187 * Structure describing everything about the program that is begin inlined
188 * into the current program.
189 */
190typedef struct inlineeInfo {
191 Lib origin; /* Library of origin of program */
192 Foam formats; /* formats from unit of origin */
193 Foam origProg; /* pointer to the original foamProg */
194 Bool sameParent; /* true iff inlinee and inliner have
195 the same parent */
196 Bool noLocalEnv; /* True if no pushenv */
197 int returnCount; /* how many return statements */
198 Foam denv; /* prog's foamDEnv */
199 Foam env; /* prog's environment */
200 Foam parentEnv; /* Parent of this env (if available) */
201 int returnLabel; /* label for return stmt */
202 FoamList returnVals; /* holder for return value(s) */
203 Syme syme; /* Syme for prog, if known */
204 AbSub sigma; /* sublist for parameter op inlining */
205} *InlineeInfo;
206
207struct InlPriCallStruct {
208 Foam call; /* call that must be inlined */
209 Foam * stmtPtr; /* statem. containing call that must be inl.*/
210 BBlock block; /* block containing the call */
211 AInt size; /* extimated growth after inlining */
212};
213
214typedef struct InlPriCallStruct * InlPriCall;
215
216/*****************************************************************************
217 *
218 * :: Debug Stuff
219 *
220 ****************************************************************************/
221
222/* To debug priority queues building, use -WD+inlCallInfo.
223 * To trace a particolar prog, used the debugger and set
224 * inlConstTrace = (num. prog).
225 */
226int inlConstTrace = -1;
227int inlCallInfoSerial = -1;
228int inlRejectInfo;
229
230#define INL_REJ_Unknown0 0
231#define INL_REJ_NotConstSyme1 1
232#define INL_REJ_LocalFoamFail2 2
233#define INL_REJ_ExternalProgHdrFail3 3
234#define INL_REJ_LocalConstInfoFail4 4
235#define INL_REJ_NotConstClosProg5 5
236#define INL_REJ_NoPermission6 6
237#define INL_REJ_Getter7 7
238#define INL_REJ_Evil8 8
239#define INL_REJ_Fluids9 9
240#define INL_REJ_OCalls10 10
241#define INL_REJ_NoInlineInfo11 11
242#define INL_REJ_DontInlineMe12 12
243#define INL_REJ_RecursiveCall13 13
244#define INL_REJ_LocalInConst014 14
245
246extern void inlPrintRejectCause (String);
247extern void inlPrintUninlinedCalls (InlPriCall, PriQKey);
248
249/*
250 * Debug flags. lots.
251 * inline, inlCall and inlCallInfo: General 'is X inlined' questions
252 * Others give more detail on prog transforms and construction.
253 */
254
255Bool inlineDebug = false((int) 0);
256Bool inlUnitDebug = false((int) 0);
257Bool inlProgDebug = false((int) 0);
258Bool inlExprDebug = false((int) 0);
259Bool inlCallDebug = false((int) 0);
260Bool inlCallInfoDebug(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))
= false((int) 0);
261Bool inlTransDebug = false((int) 0);
262Bool inlExportDebug = false((int) 0);
263Bool inlExtendDebug = false((int) 0);
264
265localstatic Bool inlInlineGenerators = false((int) 0);
266
267#define inlineDEBUGif (!inlineDebug) { } else afprintf DEBUG_IF(inline)if (!inlineDebug) { } else afprintf
268#define inlUnitDEBUGif (!inlUnitDebug) { } else afprintf DEBUG_IF(inlUnit)if (!inlUnitDebug) { } else afprintf
269#define inlProgDEBUGif (!inlProgDebug) { } else afprintf DEBUG_IF(inlProg)if (!inlProgDebug) { } else afprintf
270#define inlExprDEBUGif (!inlExprDebug) { } else afprintf DEBUG_IF(inlExpr)if (!inlExprDebug) { } else afprintf
271#define inlCallDEBUGif (!inlCallDebug) { } else afprintf DEBUG_IF(inlCall)if (!inlCallDebug) { } else afprintf
272#define inlTransDEBUGif (!inlTransDebug) { } else afprintf DEBUG_IF(inlTrans)if (!inlTransDebug) { } else afprintf
273#define inlExportDEBUGif (!inlExportDebug) { } else afprintf DEBUG_IF(inlExport)if (!inlExportDebug) { } else afprintf
274#define inlExtendDEBUGif (!inlExtendDebug) { } else afprintf DEBUG_IF(inlExtend)if (!inlExtendDebug) { } else afprintf
275
276#define inlCallInfoDebug(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))
(inlCallInfoDebug(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))
&& \
277 (inlConstTrace == -1 || \
278 inlConstTrace == inlProg->constNum))
279#define inlCallInfoDEBUGif (!(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))) { } else afprintf
DEBUG_IF(inlCallInfo)if (!(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))) { } else
afprintf
280
281/*****************************************************************************
282 *
283 * :: Local function declarations
284 *
285 ****************************************************************************/
286
287/*
288 * Foam traversal functions
289 */
290localstatic void inlDDef (Foam);
291localstatic Foam inlProgram (Foam, int);
292localstatic void inlNewLocals (Foam);
293localstatic Foam inlExpr (Foam, Bool);
294localstatic Foam inlCall (Foam, Bool);
295localstatic Foam inlId (Foam);
296
297localstatic void inlSimplifyDDef (Foam);
298
299/*
300 * Foam inlining functions
301 */
302localstatic Foam inlInlineSymeCall (Foam, Foam *, Foam, Syme, Bool);
303localstatic Foam inlInlineOpenCall (Foam, Foam *, Foam, Foam, Bool);
304localstatic Foam inlInlineConstCall (Foam, Foam *, Foam, Foam, Bool);
305localstatic Foam inlInlineBody (Foam, Foam, Foam *, Foam, Foam, Bool);
306localstatic Foam inlInlineProg (Foam, Foam *, Foam *, Bool);
307localstatic void inlAddEnv (Foam envLoc, Foam env, Bool);
308localstatic Foam inlParentEnv (Foam envLoc, Foam env);
309
310/*
311 * Foam inlinee functions
312 */
313localstatic void inlNewInlinee (void);
314localstatic Foam inlSetInlinee (Lib, Foam);
315
316/*
317 * Foam Globals
318 */
319localstatic int inlAddGlobal (Foam);
320localstatic void inlMakeNewGlobals (Foam);
321localstatic int inlTransformGlobal (Foam);
322localstatic Bool inlIsForcer (Foam);
323
324/*
325 * Foam Formats
326 */
327localstatic FmtInfo inlNewFormatInfo (Lib, AInt, AInt, Hash, Foam);
328localstatic Bool inlIsFormatInfo (FmtInfo, Lib, AInt);
329localstatic FoamBox * inlInitFormatBoxes (Foam formats);
330localstatic int inlAddFormat (Foam);
331localstatic void inlMakeNewFormats (Foam);
332localstatic AInt inlGetFormat (AInt);
333localstatic AInt inlGetExternalFormat (Lib, AInt);
334localstatic Syme inlGetSyme (AInt, AInt);
335localstatic Syme inlGetExternalSyme (Lib, AInt, AInt);
336
337#define inlInlineeFormat(n)inlInlinee->formats->foamDFmt.argv[n] inlInlinee->formats->foamDFmt.argv[n]
338#define inlInlineeDecl(n,k)inlInlinee->formats->foamDFmt.argv[n]->foamDDecl.argv
[k]
inlInlineeFormat(n)inlInlinee->formats->foamDFmt.argv[n]->foamDDecl.argv[k]
339
340/*
341 * Foam Constants
342 */
343localstatic int inlAddConst (int);
344localstatic void inlMakeNewConsts (Foam);
345localstatic Foam inlGetLocalConstInfo (int);
346localstatic Foam inlGetLocalConst (AInt);
347localstatic Foam inlGetConstLevels (AInt);
348localstatic Foam inlGetExternalConst (Lib, AInt);
349localstatic void inlUpdateConstProg (Foam);
350localstatic void inlUpdateDDecl (Foam);
351localstatic void inlUpdateConstBody (Foam);
352
353/*
354 * Foam Code
355 */
356localstatic Foam inlGetFoam (Syme);
357localstatic Foam inlGetLocalFoam (Syme);
358localstatic Foam inlGetExternalFoam (Syme);
359localstatic InlProgInfo inlGetProgInfoFrSyme (Syme);
360localstatic InlProgInfo inlGetExternalProgHdr (Syme);
361
362/*
363 * Foam Inlinability
364 */
365localstatic Bool inlInlinable0 (Stab, Syme, Bool);
366
367localstatic Bool inlSefoIsInlinable (Stab, Sefo);
368localstatic Bool inlSymeIsInlinable (Stab, Syme);
369localstatic Bool inlTFormIsInlinable (Stab, TForm);
370localstatic Bool inlIsConstProgSyme (Syme syme);
371
372localstatic void inlGetProgInfo (Foam, int *, Bool *, Bool *);
373localstatic Foam inlTransformExpr (Foam, Foam *, Foam *);
374localstatic void inlAddStmt (Foam);
375localstatic Foam inlAddLocal (FoamTag, int);
376localstatic Foam inlAddTempLocal (FoamTag, int);
377localstatic int inlAddLex (FoamTag, int);
378localstatic int inlAddLabel (void);
379localstatic void inlAddLocalDecls (Foam, Foam *);
380localstatic void inlGetTypeFrDecl (Foam decl, FoamTag *, int *);
381localstatic Bool inlUseParam (Foam, int);
382localstatic Foam inlFoamEnvElt (Foam);
383
384localstatic void inlSimplifyDDef (Foam);
385localstatic void inlSimplifyFlog (FlowGraph);
386localstatic Foam inlSimplifySeq (Foam);
387
388localstatic Foam inlSet (Foam set);
389localstatic Foam inlSets (Foam);
390extern Bool inlUniqueValues (Foam lhs, Foam rhs);
391localstatic Foam inlReturn (Foam);
392localstatic void inlComputeEEltSyme (Foam eelt);
393localstatic Foam inlLex (Foam);
394localstatic Foam inlEnv (Foam);
395localstatic Bool inlIsSideEffecting (Foam);
396localstatic FoamTag inlExprType (Foam, AInt *);
397localstatic Bool inlSameDEnv (Foam denv1, Foam denv2);
398
399extern Bool inlIsEvil (Foam);
400/*
401 * value tracking
402 */
403localstatic Foam inlGetVarTableEnv (Foam foam, Foam cenv);
404localstatic Foam inlCanonEElt (Foam);
405localstatic Foam inlCanonEEnv (Foam);
406
407localstatic Syme inlGetSymeFrEnv (Foam);
408
409/*
410 * Parameter inlining
411 */
412localstatic Syme inlSubstitutedSyme (Syme);
413localstatic Syme inlSymeSubstSelf (Syme, TForm);
414
415static struct unitInfo inlUnitInfo;
416
417static UnitInfo inlUnit = &inlUnitInfo;
418static OptInfo inlProg;
419static InlineeInfo inlInlinee;
420static Bool inlInlineAll;
421static Bool inlInlineProgs;
422
423/* Maximum size of a program that we will automatically inline. */
424int inlSizeLimit; /* default value in optfoam.c */
425
426int inlEvilGlobal;
427
428#define inlInlineeIsLocal()(inlInlinee->origin == ((void*)0)) (inlInlinee->origin == NULL((void*)0))
429
430/*****************************************************************************
431 *
432 * :: Types definitions
433 *
434 ****************************************************************************/
435
436localstatic void inlPriqBuildFrBlock (BBlock, int loopDepth);
437
438localstatic Foam * inlPriCallStmtReset(InlPriCall priCall);
439localstatic Bool inlInlinePriCall(InlPriCall priCall, PriQKey priority);
440
441localstatic InlPriCall inlPriCallNew(Foam foam, Foam * stmtPtr, BBlock, int);
442localstatic void inlPriCallFree(InlPriCall pc);
443
444localstatic Foam inlInsertSeq(Foam foam);
445
446/*****************************************************************************
447 *
448 * :: New InlPriCall Staff (TO BE MOVED)
449 *
450 ****************************************************************************/
451
452localstatic Bool inlIsUnderLimit(AInt, AInt, int);
453
454localstatic void
455inlMakeFlatFlog(FlowGraph flog)
456{
457 flogIter(flog, bb, {{ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { bb->code = utilMakeFlatSeq(bb->code
); }; }; } }; }
458 bb->code = utilMakeFlatSeq(bb->code);{ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { bb->code = utilMakeFlatSeq(bb->code
); }; }; } }; }
459 }){ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { bb->code = utilMakeFlatSeq(bb->code
); }; }; } }; }
;
460}
461
462localstatic void
463inlBuildPriqFrProg(Foam prog)
464{
465 OptInfo iprog = foamOptInfo(prog)((prog)->hdr.info.opt);
466 int loopDepth;
467 FlowGraph flog = iprog->flog;
468
469 assert(foamTag(prog) == FOAM_Prog)do { if (!(((prog)->hdr.tag) == FOAM_Prog)) _do_assert(("foamTag(prog) == FOAM_Prog"
),"of_inlin.c",469); } while (0)
;
470 assert(iprog->flog == flog)do { if (!(iprog->flog == flog)) _do_assert(("iprog->flog == flog"
),"of_inlin.c",470); } while (0)
;
471
472 iprog->size = 0;
473
474 flogIter(flog, bb, {{ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { bb->code = inlSimplifySeq(bb->code
); iprog->size += ((bb->code)->hdr.argc); loopDepth =
bb->iextra; inlPriqBuildFrBlock(bb, loopDepth); }; }; } }
; }
475 bb->code = inlSimplifySeq(bb->code);{ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { bb->code = inlSimplifySeq(bb->code
); iprog->size += ((bb->code)->hdr.argc); loopDepth =
bb->iextra; inlPriqBuildFrBlock(bb, loopDepth); }; }; } }
; }
476
477 iprog->size += foamArgc(bb->code);{ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { bb->code = inlSimplifySeq(bb->code
); iprog->size += ((bb->code)->hdr.argc); loopDepth =
bb->iextra; inlPriqBuildFrBlock(bb, loopDepth); }; }; } }
; }
478
479 loopDepth = bb->iextra;{ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { bb->code = inlSimplifySeq(bb->code
); iprog->size += ((bb->code)->hdr.argc); loopDepth =
bb->iextra; inlPriqBuildFrBlock(bb, loopDepth); }; }; } }
; }
480
481 inlPriqBuildFrBlock(bb, loopDepth);{ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { bb->code = inlSimplifySeq(bb->code
); iprog->size += ((bb->code)->hdr.argc); loopDepth =
bb->iextra; inlPriqBuildFrBlock(bb, loopDepth); }; }; } }
; }
482
483 }){ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { bb->code = inlSimplifySeq(bb->code
); iprog->size += ((bb->code)->hdr.argc); loopDepth =
bb->iextra; inlPriqBuildFrBlock(bb, loopDepth); }; }; } }
; }
;
484}
485
486
487
488
489localstatic void
490inlInlineProgWithPriq(Foam prog)
491{
492 PriQKey priority = 0;
493 InlPriCall priCall = NULL((void*)0);
494 OptInfo optInfo = foamOptInfo(prog)((prog)->hdr.info.opt);
495 Bool underLimit = true1;
496extern int optInlineRoof;
497
498 if (!optInfo) return;
499
500 inlBuildPriqFrProg(prog);
501
502 while (priqCount(inlProg->priq)((inlProg->priq)->argc) /* &&
503 priority < inlMinimumGain */) {
504
505 /* We really don't want huge Progs, too expensive optimize and
506 * compile them.
507 * However, all calls that have priority=0 will be inlined.
508 */
509 priCall = (InlPriCall) priqExtractMin(inlProg->priq, &priority);
510
511 if (priority > 0
512 && (inlProg->size > optInlineRoof ||
513 flogBlockC(inlProg->flog)((inlProg->flog)->blocks->pos) > InlFlogCutOff2500)
514 && !genIsRuntime()(gen0IsRuntime) && !optIsMaxLevel())
515 break;
516
517 if (priority > 0 &&
518 inlSizeLimit != -1) {
519 underLimit = inlIsUnderLimit(inlProg->originalSize,
520 prog->foamProg.size + priCall->size,
521 inlSizeLimit);
522
523 if (!underLimit) break;
524 }
525
526 if (!inlInlinePriCall(priCall, priority)) break;
527
528 }
529
530 if (DEBUG(inlCallInfo)(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))
) {
531 inlPrintUninlinedCalls(priCall, priority);
532 }
533
534 flogIter(inlProg->flog, bb, {{ { int _i; BBlock bb; for (_i = 0; _i < ((inlProg->flog
)->blocks->pos); _i++) { bb = bbufBlockFn((inlProg->
flog)->blocks,_i); if (!bb) continue; { { bb->code = inlSets
(bb->code); }; }; } }; }
535 bb->code = inlSets(bb->code);{ { int _i; BBlock bb; for (_i = 0; _i < ((inlProg->flog
)->blocks->pos); _i++) { bb = bbufBlockFn((inlProg->
flog)->blocks,_i); if (!bb) continue; { { bb->code = inlSets
(bb->code); }; }; } }; }
536 }){ { int _i; BBlock bb; for (_i = 0; _i < ((inlProg->flog
)->blocks->pos); _i++) { bb = bbufBlockFn((inlProg->
flog)->blocks,_i); if (!bb) continue; { { bb->code = inlSets
(bb->code); }; }; } }; }
;
537}
538
539
540/*****************************************************************************
541 *
542 * :: Foam traversal functions
543 *
544 ****************************************************************************/
545
546/*
547 * Inline function in a Foam unit, updating the structure in-place.
548 */
549void
550inlineUnit(Foam unit, Bool inlineAll, int inlineLimit, Bool inlineProgs)
551{
552 assert (foamTag(unit) == FOAM_Unit)do { if (!(((unit)->hdr.tag) == FOAM_Unit)) _do_assert(("foamTag(unit) == FOAM_Unit"
),"of_inlin.c",552); } while (0)
;
553
554 if (DEBUG(inlUnit)inlUnitDebug) {
555 fprintf(dbOut, ">>inlUnit:\n");
556 foamPrintDb(unit);
557 fnewline(dbOut);
558 }
559
560 inlInlineAll = inlineAll;
561 inlSizeLimit = inlineLimit;
562 inlInlineProgs = inlineProgs;
563 inlUnit->unit = unit;
564 inlUnit->formatRefList = listNil(FmtInfo)((FmtInfoList) 0);
565
566 inlUnit->globals = fboxNew(foamUnitGlobals(unit)((((unit)->foamUnit.formats)->foamGen.argv)[0].code));
567 inlUnit->formats = fboxNew(unit->foamUnit.formats);
568 inlUnit->formatBoxes = inlInitFormatBoxes(unit->foamUnit.formats);
569
570 inlUnit->constList = listNil(ConstInfo)((ConstInfoList) 0);
571 inlUnit->constc = foamDDeclArgc(foamUnitConstants(unit))(((((((unit)->foamUnit.formats)->foamGen.argv)[1].code)
)->hdr.argc) - (1))
;
572 inlUnit->constv = (Foam *) stoAlloc(OB_Other0,
573 inlUnit->constc * sizeof(Foam));
574
575 inlEvilGlobal = -1;
576 foamConstvFrFoam(unit, inlUnit->constc, inlUnit->constv);
577
578 inuUnitInit(unit);
579
580 if (inlineProgs)
581 inlDDef(unit->foamUnit.defs);
582 else
583 inlSimplifyDDef(unit->foamUnit.defs);
584
585 inlMakeNewFormats(unit);
586 inlMakeNewGlobals(unit);
587 inlMakeNewConsts(unit);
588
589 inuUnitFini(unit);
590
591 if (DEBUG(inlUnit)inlUnitDebug) {
592 fprintf(dbOut, "<<inlUnit:\n");
593 foamPrintDb(unit);
594 fnewline(dbOut);
595 }
596
597 assert(foamAudit(unit))do { if (!(foamAudit(unit))) _do_assert(("foamAudit(unit)"),"of_inlin.c"
,597); } while (0)
;
598 stoFree(inlUnit->constv);
599}
600
601/*
602 * Inline the Defines from the unit.
603 */
604
605
606localstatic void
607inlDDef(Foam defs)
608{
609 int i;
610 Foam def;
611
612 assert(foamTag(defs) == FOAM_DDef)do { if (!(((defs)->hdr.tag) == FOAM_DDef)) _do_assert(("foamTag(defs) == FOAM_DDef"
),"of_inlin.c",612); } while (0)
;
613
614 for(i=0; i < foamArgc(defs)((defs)->hdr.argc); i++) {
615 def = defs->foamDDef.argv[i];
616 assert(foamTag(def) == FOAM_Def)do { if (!(((def)->hdr.tag) == FOAM_Def)) _do_assert(("foamTag(def) == FOAM_Def"
),"of_inlin.c",616); } while (0)
;
617 if (foamTag(def->foamDef.rhs)((def->foamDef.rhs)->hdr.tag) == FOAM_Prog)
618 def->foamDef.rhs = inlProgram(def->foamDef.rhs, i);
619 }
620}
621
622
623
624/*
625 * Inline a foam program.
626 */
627localstatic Foam inlProgram1(Foam prog, int n);
628
629localstatic Foam
630inlProgram(Foam prog, int n)
631{
632 Foam newProg;
633 inlProgDEBUGif (!inlProgDebug) { } else afprintf(stdoutstdout, "(Program %d %d\n", n, foamOptInfo(prog)((prog)->hdr.info.opt) == NULL((void*)0) ? -1 : foamOptInfo(prog)((prog)->hdr.info.opt)->inlState);
634 newProg = inlProgram1(prog, n);
635 inlProgDEBUGif (!inlProgDebug) { } else afprintf(stdoutstdout, " Program %d:\n%pFoam\n", n, newProg);
636 inlProgDEBUGif (!inlProgDebug) { } else afprintf(stdoutstdout, " Program %d)\n", n);
637 return newProg;
638}
639
640localstatic Foam
641inlProgram1(Foam prog, int n)
642{
643 Scope("inlProgram")String scopeName = ("inlProgram"); int fluidLevel0 = (scopeLevel
++, fluidLevel)
;
644 OptInfo fluid(inlProg)fluidSave_inlProg = ( fluidStack = (fluidLevel==fluidLimit) ?
fluidGrow() : fluidStack, fluidStack[fluidLevel].scopeName =
scopeName, fluidStack[fluidLevel].scopeLevel = scopeLevel, fluidStack
[fluidLevel].pglobal = (Pointer) &(inlProg), fluidStack[fluidLevel
].pstack = (Pointer) &fluidSave_inlProg, fluidStack[fluidLevel
].size = sizeof(inlProg), fluidLevel++, (inlProg) )
;
645 int count, maxCount = 30;
646
647
648 assert(foamTag(prog) == FOAM_Prog)do { if (!(((prog)->hdr.tag) == FOAM_Prog)) _do_assert(("foamTag(prog) == FOAM_Prog"
),"of_inlin.c",648); } while (0)
;
649
650 inlProg = foamOptInfo(prog)((prog)->hdr.info.opt);
651 if (inlProg == 0) Return(prog){ fluidUnwind(fluidLevel0, ((int) 0)); return prog;; };
652
653 assert(inlInlineProgs)do { if (!(inlInlineProgs)) _do_assert(("inlInlineProgs"),"of_inlin.c"
,653); } while (0)
;
654
655 if (inlProg->inlState == INL_Inlined ||
656 inlProg->inlState == INL_BeingInlined)
657 Return(prog){ fluidUnwind(fluidLevel0, ((int) 0)); return prog;; };
658
659 inlProg->inlState = INL_BeingInlined;
660 inlProg->constNum = n;
661 inlProg->changed = true1;
662
663 if (genIsRuntime()(gen0IsRuntime)) maxCount = 100;
664
665 inlProg->originalSize = prog->foamProg.size;
666
667 /* !! This loop probably is no more needed */
668 for (count = 0; inlProg->changed && count < maxCount; count += 1) {
669
670 inuProgUpdate(prog);
671
672 inlProg->prog = prog;
673 inlProg->seq = prog->foamProg.body;
674 inlProg->locals = vpNew(fboxNew(prog->foamProg.locals));
675 inlProg->numLabels = prog->foamProg.nLabels;
676 inlProg->denv = prog->foamProg.levels;
677 inlProg->changed = false((int) 0);
678
679 inlProg->seq = prog->foamProg.body;
680 inlProg->seqBody = listNil(Foam)((FoamList) 0);
681
682 inlProg->priq = priqNew(30);
683
684 /* the inlProg is in prog.hdr.info.opt */
685 inlInlineProgWithPriq(prog);
686
687 if (inlProg->changed)
688 inlMakeFlatFlog(inlProg->flog);
689
690 inlNewLocals(prog);
691 prog->foamProg.nLabels = inlProg->numLabels;
692
693 priqFreeDeeply(inlProg->priq, (PriQEltFreeFun) inlPriCallFree);
694
695 if (DEBUG(inlProg)inlProgDebug) {
696 if ((inlConstTrace == inlProg->constNum ||
697 inlConstTrace == -1)) {
698 if (inlProg->changed) {
699
700 fprintf(dbOut, "<<inlProg[prog:%d][step:%d]:\n", n, count);
701 flogPrint(dbOut, inlProg->flog, 1);
702 fnewline(dbOut);
703 }
704 else
705 fprintf(dbOut, "<<inlProg [step:%d] (UNCHANGED)\n", count);
706 }
707 }
708 }
709
710 inlProg->inlState = INL_Inlined;
711 prog = flogToProg(inlProg->flog);
712 inlProg->flog = NULL((void*)0);
713
714#if 0
715 /* Use this code to find inlProg->constNum for a given prog */
716 (void)fprintf(dbOut, "******************** %d ***************\n", n);
717 (void)foamPrintDb(prog);
718 (void)fprintf(dbOut, "***************************************\n\n");
719#endif
720 Return(prog){ fluidUnwind(fluidLevel0, ((int) 0)); return prog;; };
721}
722
723/******************************************************************************
724 *
725 * :: Find Priorities for Calls
726 *
727 *****************************************************************************/
728
729localstatic void
730inlPrintPriqElt(PriQKey priority, PriQElt elt)
731{
732 InlPriCall info = (InlPriCall) elt;
733 Syme syme;
734 Foam call;
735 String string;
736 call = info->call;
737
738 if (foamTag(call)((call)->hdr.tag) == FOAM_CCall && (syme = foamSyme(call->foamCCall.op)((call->foamCCall.op)->hdr.syme)) != NULL((void*)0))
739 string = symeString(syme)((((syme)->id))->str);
740 else
741 string = "<unknown>";
742
743 fprintf(dbOut,"-- %f -- %d ----- `%s' ----\n",
744 priority, (int)info->size, string);
745 foamPrintDb(call);
746}
747
748localstatic void
749inlPrintPriq()
750{
751 fprintf(dbOut,"\n------------------ Start of the queue ---------------------\n");
752 priqMap((PriQMapFn) inlPrintPriqElt, inlProg->priq);
753 fprintf(dbOut,"------------------ End of the queue ---------------------\n\n");
754}
755
756
757localstatic Foam inlGetClosFrVar(Foam op);
758
759/* Return NULL if the prog is the some that we are inlining */
760localstatic InlProgInfo
761inlGetProgInfoFrProg(Foam foam)
762{
763 Foam prog;
764
765 assert(foamTag(foam) == FOAM_Prog)do { if (!(((foam)->hdr.tag) == FOAM_Prog)) _do_assert(("foamTag(foam) == FOAM_Prog"
),"of_inlin.c",765); } while (0)
;
766
767 if (foam == inlProg->prog) {
768 inlRejectInfo = INL_REJ_RecursiveCall13;
769 return NULL((void*)0);
770 }
771
772 prog = foamCopyNode(foam);
773
774 prog->foamProg.locals = NULL((void*)0);
775 prog->foamProg.params = NULL((void*)0);
776 prog->foamProg.fluids = NULL((void*)0);
777 prog->foamProg.levels = NULL((void*)0);
778 prog->foamProg.body = NULL((void*)0);
779
780 return prog;
781}
782
783localstatic InlProgInfo
784inlPriqGetSymeCallInfo(Syme syme, Bool * isLocal)
785{
786 InlProgInfo code;
787
788 if (!inlIsConstProgSyme(syme)) {
789 inlRejectInfo = INL_REJ_NotConstSyme1;
790 return 0;
791 }
792
793
794#if INLINING_OF_DEFAULTS_IS_ALLOWED
795 /* If we aren't in runtime then check for default symes */
796 if (!genIsRuntime()(gen0IsRuntime)) {
797 Bool catsyme;
798 Syme osyme;
799
800 /*
801 * Sometimes we fail to recognise a domain definition
802 * and end up with symes from its category rather than
803 * symes from the domain. Normally this means that we
804 * fail to inline the call when we go looking for its
805 * FOAM. Unfortunately if the category has a default
806 * implementation then we inline that (bad news).
807 *
808 * However, the compiler needs to be able to inline
809 * default operations when a domain does not export
810 * an alternative. Otherwise performance plummets
811 * considerably when common operations such as <= and
812 * unary minus are left as defaults.
813 *
814 * For the time being we allow inlining of defaults
815 * even though we may accidentally get hold of the
816 * default instead of its replacement.
817 */
818 osyme = symeOriginal(syme);
819 catsyme = (symeDefnNum(osyme)((int) (SYFI_DefnNum < (8 * sizeof(int)) && !(((((
osyme)->kind == SYME_Trigger ? libGetAllSymes((osyme)->
lib) : ((void*)0)), (osyme))->hasmask) & (1 << (
SYFI_DefnNum))) ? (symeFieldInfo[SYFI_DefnNum].def) : (((((osyme
)->kind == SYME_Trigger ? libGetAllSymes((osyme)->lib) :
((void*)0)), (osyme))->locmask) & (1 << (SYFI_DefnNum
))) ? ((((((osyme)->kind == SYME_Trigger ? libGetAllSymes(
(osyme)->lib) : ((void*)0)), (osyme))->locmask) & (
1 << (SYFI_DefnNum))) ? ((osyme)->fieldv)[symeIndex(
osyme,SYFI_DefnNum)] : (symeFieldInfo[SYFI_DefnNum].def)) : symeGetFieldFn
(osyme,SYFI_DefnNum)))
== symeDefnNum(syme)((int) (SYFI_DefnNum < (8 * sizeof(int)) && !(((((
syme)->kind == SYME_Trigger ? libGetAllSymes((syme)->lib
) : ((void*)0)), (syme))->hasmask) & (1 << (SYFI_DefnNum
))) ? (symeFieldInfo[SYFI_DefnNum].def) : (((((syme)->kind
== SYME_Trigger ? libGetAllSymes((syme)->lib) : ((void*)0
)), (syme))->locmask) & (1 << (SYFI_DefnNum))) ?
((((((syme)->kind == SYME_Trigger ? libGetAllSymes((syme)
->lib) : ((void*)0)), (syme))->locmask) & (1 <<
(SYFI_DefnNum))) ? ((syme)->fieldv)[symeIndex(syme,SYFI_DefnNum
)] : (symeFieldInfo[SYFI_DefnNum].def)) : symeGetFieldFn(syme
,SYFI_DefnNum)))
);
820 if (symeHasDefault(osyme)(((((osyme)->kind == SYME_Trigger ? libGetAllSymes((osyme)
->lib) : ((void*)0)), (osyme))->bits) & (0x0080))
&& catsyme) {
821 inlRejectInfo = INL_REJ_NotConstSyme1;
822 return (InlProgInfo)0;
823 }
824 }
825#endif
826
827
828 if (symeIsLocalConst(syme)(symeConstLib(syme) == ((void*)0))) {
829 code = inlGetLocalFoam(syme);
830
831 if (!code) return NULL((void*)0);
832
833 inlProgram(code, genGetConstNum(syme));
834 code = inlGetProgInfoFrProg(code);
835
836 *isLocal = true1;
837 }
838 else {
839 code = inlGetExternalProgHdr(syme);
840 *isLocal = false((int) 0);
841 }
842
843 return code;
844}
845
846localstatic InlProgInfo
847inlPriqGetOpenCallInfo(Foam op, Bool * isLocal)
848{
849 Foam code;
850
851 if (foamTag(op)((op)->hdr.tag) != FOAM_Const) {
852 inlRejectInfo = INL_REJ_NotConstSyme1;
853 return 0;
854 }
855
856 code = inlGetLocalConstInfo(op->foamConst.index);
857 *isLocal = true1;
858
859 return code;
860}
861
862localstatic InlProgInfo
863inlPriqGetConstCallInfo(Foam op, Bool *isLocal)
864{
865 Foam code, cnst;
866
867 assert(foamTag(op) == FOAM_Clos)do { if (!(((op)->hdr.tag) == FOAM_Clos)) _do_assert(("foamTag(op) == FOAM_Clos"
),"of_inlin.c",867); } while (0)
;
868
869 cnst = op->foamClos.prog;
870
871 if (foamTag(cnst)((cnst)->hdr.tag) != FOAM_Const) {
872 inlRejectInfo = INL_REJ_NotConstClosProg5;
873 return NULL((void*)0);
874 }
875
876 code = inlGetLocalConstInfo(cnst->foamConst.index);
877
878 *isLocal = true1;
879
880 return code;
881}
882
883localstatic InlProgInfo
884inlPriqGetCallInfo(Foam call, Bool *pIsLocal)
885{
886 Foam op, val, progInfo = NULL((void*)0);
887 Syme syme = NULL((void*)0);
888 static int serialDebug = 0;
889
890 /*
891 * Why did this code save serialDbg? Perhaps we are
892 * supposed to restore serialDebug to its original
893 * value at the end of this function?
894 int serialDbg = serialDebug;
895 */
896
897 inlRejectInfo = INL_REJ_Unknown0;
898
899 assert(foamTag(call) == FOAM_CCall || foamTag(call) == FOAM_OCall)do { if (!(((call)->hdr.tag) == FOAM_CCall || ((call)->
hdr.tag) == FOAM_OCall)) _do_assert(("foamTag(call) == FOAM_CCall || foamTag(call) == FOAM_OCall"
),"of_inlin.c",899); } while (0)
;
900
901 if (foamTag(call)((call)->hdr.tag) == FOAM_CCall) {
902 op = call->foamCCall.op;
903 while (foamTag(op)((op)->hdr.tag) == FOAM_Cast)
904 op = op->foamCast.expr;
905
906 val = inlGetClosFrVar(op);
907 }
908 else {
909 op = call->foamOCall.op;
910 val = NULL((void*)0);
911 }
912
913 serialDebug += 1;
914
915 /* Inline if syme is declared inlinable. */
916 if (foamTag(op)((op)->hdr.tag) != FOAM_Clos && (syme = foamSyme(op)((op)->hdr.syme)) != NULL((void*)0)) {
917 Stab stab = inlProg->stab ? inlProg->stab : stabFile();
918 if (inlInlinable(stab, syme))
919 progInfo = inlPriqGetSymeCallInfo(syme, pIsLocal);
920 else {
921 /* Make sure we don't see this again...*/
922 foamSyme(op)((op)->hdr.syme) = NULL((void*)0);
923 }
924 }
925
926 if (DEBUG(inlCallInfo)(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))
) {
927 fprintf(dbOut, "CallInfo (prog: %d, serial: %d) - syme: ",
928 inlProg->constNum, serialDebug);
929 if (syme) {
930 /* symePrintDb(syme); */
931 fprintf(dbOut,"%s\n",symePretty(syme));
932 }
933 else
934 fprintf(dbOut, "NULL");
935 fprintf(dbOut," - Call = ");
936 foamPrintDb(call);
937 if (syme && inlRejectInfo == INL_REJ_NoPermission6)
938 fprintf(dbOut, "No permission to inline.\n");
939 }
940
941 if (progInfo)
942 ;
943
944 else if (foamTag(call)((call)->hdr.tag) == FOAM_OCall)
945 progInfo = inlPriqGetOpenCallInfo(op, pIsLocal);
946
947 else if (val && foamTag(val)((val)->hdr.tag) == FOAM_Clos)
948 progInfo = inlPriqGetConstCallInfo(val, pIsLocal);
949
950 else if (foamTag(op)((op)->hdr.tag) == FOAM_Clos)
951 progInfo = inlPriqGetConstCallInfo(op, pIsLocal);
952
953 inlCallInfoSerial = serialDebug;
954
955 if (!progInfo) return NULL((void*)0);
956
957 if (!foamProgHasInlineInfo(progInfo)((progInfo)->foamProg.infoBits & (1 << 8))) {
958 inlRejectInfo = INL_REJ_NoInlineInfo11;
959 return NULL((void*)0);
960 }
961
962 /* Don't inline getters */
963 if (foamProgIsGetter(progInfo)((progInfo)->foamProg.infoBits & (1 << 3))) {
964 inlRejectInfo = INL_REJ_Getter7;
965 return NULL((void*)0);
966 }
967
968 /* !! This could be improved: only if declare fluids */
969 if (foamProgUsesFluids(progInfo)((progInfo)->foamProg.infoBits & (1 << 5))) {
970 inlRejectInfo = INL_REJ_Fluids9;
971 return NULL((void*)0);
972 }
973
974 /* Uncomment this if, for some reason, you don't want to inline
975 * external ocalls */
976#if 0
977 if (!foamProgHasNoOCalls(progInfo)((progInfo)->foamProg.infoBits & (1 << 11)) && !*pIsLocal) {
978 inlRejectInfo = INL_REJ_OCalls10;
979 return NULL((void*)0);
980 }
981#endif
982
983 if (foamProgDontInlineMe(progInfo)((progInfo)->foamProg.infoBits & (1 << 9))) {
984 inlRejectInfo = INL_REJ_DontInlineMe12;
985 return NULL((void*)0);
986 }
987
988 return progInfo;
989}
990
991/* Give the space factor on the base of constant parameters.
992 * If return value == 0 -> must inline
993 */
994localstatic PriQKey
995inlGetSpaceFactor(Foam call, InlProgInfo progInfo)
996{
997 int constParams = 0, totParams, i;
998 Foam * parv, prog, cnst;
999
1000 if (foamTag(call)((call)->hdr.tag) == FOAM_CCall) {
1001 parv = call->foamCCall.argv;
1002 totParams = foamArgc(call)((call)->hdr.argc) - 2;
1003 }
1004 else {
1005 assert(foamTag(call) == FOAM_OCall)do { if (!(((call)->hdr.tag) == FOAM_OCall)) _do_assert(("foamTag(call) == FOAM_OCall"
),"of_inlin.c",1005); } while (0)
;
1006 parv = call->foamOCall.argv;
1007 totParams = foamArgc(call)((call)->hdr.argc) - 3;
1008 }
1009
1010 if (totParams == 0) return 1;
1011
1012 for (i = 0; i < totParams; i++) {
1013 if (otIsMovableData(parv[i])) constParams += 1;
1014
1015 /* A generator among parameters -> we win if we inline this
1016 * call. See, in example, hilbert1.
1017 */
1018 if (foamTag(parv[i])((parv[i])->hdr.tag) == FOAM_Clos) {
1019 cnst = parv[i]->foamClos.prog;
1020 if (foamTag(cnst)((cnst)->hdr.tag) == FOAM_Const) {
1021 prog= inlGetLocalConstInfo(cnst->foamConst.index);
1022 if (prog &&
1023 (foamProgInlineMe(prog)((prog)->foamProg.infoBits & (1 << 4)) ||
1024 foamProgIsGenerator(prog)((prog)->foamProg.infoBits & (1 << 2)))) {
1025 if (inlInlineGenerators)
1026 return 0;
1027 else
1028 return InlParIsGeneratorMagic0.016;
1029 }
1030 }
1031 }
1032 }
1033
1034 return InlBaseFactor1.1 - ((PriQKey) constParams) / ((PriQKey) totParams);
1035}
1036
1037/* Return -1 if the call CANNOT be inlined, its priority otherwise
1038 */
1039localstatic PriQKey
1040inlPriqGetPriority(int depth, Foam call, int * psize, Foam * pinfo)
1041{
1042 InlProgInfo progInfo;
1043 PriQKey priority, size, spaceFactor;
1044 ULong expectedCalls;
1045 PriQKey timeFactor;
1046 Bool isLocal = false((int) 0);
1047
1048 expectedCalls = 1L << (depth * InlLoopMagicNumber3);
1049 if (expectedCalls <= 0 || expectedCalls > InlInnerLoopMaxIter30000)
1050 expectedCalls = InlInnerLoopMaxIter30000;
1051
1052 *psize = 0;
1053
1054 progInfo = inlPriqGetCallInfo(call, &isLocal);
1055
1056 *pinfo = progInfo;
1057
1058 if (!progInfo)
1059 return -1;
1060
1061 if (isLocal &&
1062 inlProg->constNum == 0 &&
1063 !genIsRuntime()(gen0IsRuntime)) {
1064 inlRejectInfo = INL_REJ_LocalInConst014;
1065 return -1;
1066 }
1067
1068 if (genIsRuntime()(gen0IsRuntime)) {
1069 if (!isLocal) return 0;
1070
1071 if (foamTag(call)((call)->hdr.tag) == FOAM_CCall
1072 && (foamTag(call->foamCCall.op)((call->foamCCall.op)->hdr.tag) == FOAM_Lex
1073 || foamTag(call->foamCCall.op)((call->foamCCall.op)->hdr.tag) == FOAM_EElt))
1074 return 0;
1075 }
1076
1077 spaceFactor = inlGetSpaceFactor(call, progInfo);
1078
1079 if (spaceFactor == 0) {
1080 *psize = 0;
1081 return 0;
1082 }
1083
1084 if (foamProgIsCalledOnce(progInfo)((progInfo)->foamProg.infoBits & (1 << 13))) {
1085 inlCallInfoDEBUGif (!(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))) { } else afprintf
(dbOut,"(^Unique call^)\n");
1086 spaceFactor = InlCalledOnceFactor0.01;
1087 }
1088
1089 if (!foamProgIsGenerator(progInfo)((progInfo)->foamProg.infoBits & (1 << 2)) &&
1090 !foamProgInlineMe(progInfo)((progInfo)->foamProg.infoBits & (1 << 4))) {
1091 timeFactor = InlStandardTimeFactor1;
1092
1093/* !! The following code has been commented out because is not necessary.
1094 * I used it in the process of trimming the inliner. I didn't remove because
1095 * could be useful if we decide to trim again the inliner.
1096 */
1097#if 0
1098 if (foamProgHasConsts(progInfo)((progInfo)->foamProg.infoBits & (1 << 10)))
1099 spaceFactor += 2;
1100 if (!foamProgHasNoOCalls(progInfo)((progInfo)->foamProg.infoBits & (1 << 11)))
1101 spaceFactor += 2;
1102#endif
1103
1104 }
1105 else {
1106 timeFactor = InlInlineMeTimeFactor0.05;
1107 spaceFactor = spaceFactor / InlInlineMeSpaceFactor60;
1108
1109 if (genIsRuntime()(gen0IsRuntime) ||
1110 inlInlineGenerators) { /* -Wloops */
1111 *psize = (int) spaceFactor * progInfo->foamProg.size;
1112 return 0;
1113 }
1114 }
1115
1116 /* 3 is a random namber --- this is how much we like
1117 * programs that don't touch their environment.
1118 * In general, we love them to death.
1119 */
1120 if (foamProgHasNoEnvUse(progInfo)((progInfo)->foamProg.infoBits & (1 << 14)))
1121 spaceFactor = 3* spaceFactor/InlInlineMeSpaceFactor60;
1122
1123 *psize = (int) spaceFactor * progInfo->foamProg.size;
1124
1125 size = ((PriQKey) inlProg->prog->foamProg.size) +
1126 spaceFactor * ((PriQKey) progInfo->foamProg.size);
1127
1128/* !! This code is actually unused. What it says is that in determining the
1129 * priority of a call we should consider the estimated time-cost of the
1130 * caller and of the called function. Presently the inliner doesn't perform
1131 * such kind of analysis because the inaccuracy of estimated time-cost may
1132 * cause wrong inliner behaviour.
1133 */
1134#if 0
1135 time = ((PriQKey) inlProg->prog->foamProg.time) -
1136 ((PriQKey) expectedCalls) *
1137 ((1 - timeFactor) * ((PriQKey) progInfo->foamProg.time) +
1138 ((PriQKey) InlCallMagicNumber5));
1139
1140 if (time < 0) time = 0.01;
1141
1142 priority = size * time;
1143#endif
1144
1145 priority = (size * timeFactor) / expectedCalls;
1146
1147 if (foamProgHasSingleStmt(progInfo)((progInfo)->foamProg.infoBits & (1 << 12)) &&
1148 progInfo->foamProg.size < (foamArgc(call)((call)->hdr.argc) * InlSingleStmtMagic2))
1149 if (isLocal ||
1150 (foamProgHasNoOCalls(progInfo)((progInfo)->foamProg.infoBits & (1 << 11)) &&
1151 !foamProgHasConsts(progInfo)((progInfo)->foamProg.infoBits & (1 << 10)))) {
1152 *psize = 0;
1153 priority = genIsRuntime()(gen0IsRuntime) ? 0.0 : priority/20.0;
1154 }
1155
1156 /* Must minimize:
1157 * (inlProg->prog->foamProg.size + spaceFactor * progInfo->size) ^ 2 *
1158 * (inlProg->time - expectedCalls(depth) *
1159 * ((1 - timeFactor(progInfo)) * progInfo->time + CALL_COST))
1160 *
1161 * - To start: spaceFactor is a simple funct. of const params. in
1162 * call. Idem for timeFactor.
1163 */
1164
1165 foamFreeNode(progInfo);
1166
1167 return priority;
1168}
1169
1170localstatic void
1171inlAddCallToPriq(Foam call, Foam * stmtp, int depth, BBlock bb)
1172{
1173 Syme syme;
1174 InlPriCall inlPriCall;
1175 InlProgInfo progInfo;
1176 String string;
1177 int size;
1178
1179 PriQKey priority = inlPriqGetPriority(depth, call, &size, &progInfo);
1180
1181 if (priority != -1) {
1182
1183 inlPriCall = inlPriCallNew(call, stmtp, bb, size);
1184 priqInsert(inlProg->priq, priority, (PriQElt) inlPriCall);
1185 }
1186
1187 if (foamTag(call)((call)->hdr.tag) == FOAM_CCall && (syme = foamSyme(call->foamCCall.op)((call->foamCCall.op)->hdr.syme)) != NULL((void*)0))
1188 string = symeString(syme)((((syme)->id))->str);
1189 else
1190 string = "<unknown>";
1191
1192 if (DEBUG(inlCallInfo)(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))
) {
1193 if (priority!= -1) {
1194 fprintf(dbOut, "++++ %s (serial: %d, depth: %d, size: %d, mask: %x) ",
1195 string,
1196 inlCallInfoSerial, depth, size,
1197 (unsigned) progInfo->foamProg.infoBits);
1198 fprintf(dbOut, "Added to Queue ++++ (priority=%f)\n",
1199 priority);
1200 }
1201 else
1202 inlPrintRejectCause(string);
1203 }
1204 if (DEBUG(inlCallInfo)(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))
) {
1205 inlPrintPriq();
1206 }
1207}
1208
1209localstatic void
1210inlPriqBuildFrExpr(Foam foam, Foam * stmtp, int depth, BBlock bb)
1211{
1212 /* don't recurse into forces */
1213 if (foamTag(foam)((foam)->hdr.tag) == FOAM_CCall &&
1214 inlIsForcer((foam)->foamCCall.op))
1215 return;
1216
1217 foamIter(foam, arg, {{ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { { inlPriqBuildFrExpr(*arg, stmtp, depth, bb); }; }; }
} }; }
1218 inlPriqBuildFrExpr(*arg, stmtp, depth, bb);{ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { { inlPriqBuildFrExpr(*arg, stmtp, depth, bb); }; }; }
} }; }
1219 }){ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { { inlPriqBuildFrExpr(*arg, stmtp, depth, bb); }; }; }
} }; }
;
1220
1221 if (foamTag(foam)((foam)->hdr.tag) == FOAM_CCall ||
1222 foamTag(foam)((foam)->hdr.tag) == FOAM_OCall)
1223 inlAddCallToPriq(foam, stmtp, depth, bb);
1224}
1225
1226
1227localstatic void
1228inlPriqBuildFrBlock(BBlock bb, int depth)
1229{
1230 Foam seq = bb->code;
1231 int i;
1232
1233 assert(foamTag(seq) == FOAM_Seq)do { if (!(((seq)->hdr.tag) == FOAM_Seq)) _do_assert(("foamTag(seq) == FOAM_Seq"
),"of_inlin.c",1233); } while (0)
;
1234
1235 for (i = 0; i < foamArgc(seq)((seq)->hdr.argc); i++)
1236 inlPriqBuildFrExpr(seq->foamSeq.argv[i],
1237 seq->foamSeq.argv + i,
1238 depth, bb);
1239
1240}
1241
1242localstatic void
1243inlAddNewCallsToPriq0(Foam foam, Foam * parv, int npars, Foam * stmtp,
1244 int depth, BBlock bb)
1245{
1246 int i;
1247
1248 /* don't recurse into forces */
1249 if (foamTag(foam)((foam)->hdr.tag) == FOAM_CCall &&
1250 inlIsForcer((foam)->foamCCall.op)) {
1251 return;
1252 }
1253
1254 foamIter(foam, arg, {{ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { { inlAddNewCallsToPriq0(*arg, parv, npars, stmtp, depth
, bb); }; }; } } }; }
1255 inlAddNewCallsToPriq0(*arg, parv, npars, stmtp, depth, bb);{ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { { inlAddNewCallsToPriq0(*arg, parv, npars, stmtp, depth
, bb); }; }; } } }; }
1256 }){ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { { inlAddNewCallsToPriq0(*arg, parv, npars, stmtp, depth
, bb); }; }; } } }; }
;
1257
1258 if (foamTag(foam)((foam)->hdr.tag) != FOAM_CCall &&
1259 foamTag(foam)((foam)->hdr.tag) != FOAM_OCall) return;
1260
1261 for (i = 0; i < npars; i++)
1262 if (parv[i] == foam) return;
1263
1264 inlAddCallToPriq(foam, stmtp, depth, bb);
1265}
1266
1267/* Called after that a new seq has replaced the stmt containing and inlined
1268 * call.
1269 * "parv" is the vector of parameters and "npars" is its size. Since the new
1270 * seq may contains both new calls and old calls (parameters to the inlined
1271 * call), this procedure check that a call is really new before inserting it
1272 * in the priq.
1273 */
1274localstatic void
1275inlAddNewCallsToPriq(Foam * pfoam,Foam * parv, int npars, int depth, BBlock bb)
1276{
1277 int i;
1278 Foam * stmtp;
1279 Foam seq;
1280
1281 *pfoam = inlExpr(*pfoam, false((int) 0));
1282
1283 if (foamTag(*pfoam)((*pfoam)->hdr.tag) != FOAM_Seq) {
1284 inlAddNewCallsToPriq0(*pfoam, parv, npars, pfoam, depth, bb);
1285 return;
1286 }
1287 seq = *pfoam;
1288
1289 for (i = 0; i < foamArgc(seq)((seq)->hdr.argc); i++) {
1290 stmtp = seq->foamSeq.argv + i;
1291 inlAddNewCallsToPriq0(*stmtp, parv, npars, stmtp, depth, bb);
1292 }
1293
1294}
1295
1296localstatic Foam *
1297inlCallIsInExpr(Foam call, Foam * pfoam)
1298{
1299 foamIter(*pfoam, arg, {{ { String argf = (foamInfoTable [(int)(((*pfoam)->hdr.tag
))-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((
*pfoam)->hdr.argc); _i++, argf++) { if (*argf == '*') argf
--; if (*argf == 'C') { Foam *arg = (Foam *) ((*pfoam)->foamGen
.argv)+_i; { { Foam * res; res = inlCallIsInExpr(call, arg); if
(res) return res; }; }; } } }; }
1300 Foam * res;{ { String argf = (foamInfoTable [(int)(((*pfoam)->hdr.tag
))-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((
*pfoam)->hdr.argc); _i++, argf++) { if (*argf == '*') argf
--; if (*argf == 'C') { Foam *arg = (Foam *) ((*pfoam)->foamGen
.argv)+_i; { { Foam * res; res = inlCallIsInExpr(call, arg); if
(res) return res; }; }; } } }; }
1301 res = inlCallIsInExpr(call, arg);{ { String argf = (foamInfoTable [(int)(((*pfoam)->hdr.tag
))-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((
*pfoam)->hdr.argc); _i++, argf++) { if (*argf == '*') argf
--; if (*argf == 'C') { Foam *arg = (Foam *) ((*pfoam)->foamGen
.argv)+_i; { { Foam * res; res = inlCallIsInExpr(call, arg); if
(res) return res; }; }; } } }; }
1302 if (res) return res;{ { String argf = (foamInfoTable [(int)(((*pfoam)->hdr.tag
))-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((
*pfoam)->hdr.argc); _i++, argf++) { if (*argf == '*') argf
--; if (*argf == 'C') { Foam *arg = (Foam *) ((*pfoam)->foamGen
.argv)+_i; { { Foam * res; res = inlCallIsInExpr(call, arg); if
(res) return res; }; }; } } }; }
1303 }){ { String argf = (foamInfoTable [(int)(((*pfoam)->hdr.tag
))-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((
*pfoam)->hdr.argc); _i++, argf++) { if (*argf == '*') argf
--; if (*argf == 'C') { Foam *arg = (Foam *) ((*pfoam)->foamGen
.argv)+_i; { { Foam * res; res = inlCallIsInExpr(call, arg); if
(res) return res; }; }; } } }; }
;
1304
1305 if (call == *pfoam)
1306 return pfoam;
1307 else
1308 return (Foam *) int0((int) 0);
1309}
1310
1311localstatic Foam *
1312inlPriCallStmtReset(InlPriCall priCall)
1313{
1314 Foam * pstmt = priCall->stmtPtr;
1315 Foam call = priCall->call;
1316 int i;
1317
1318 if (foamTag(*pstmt)((*pstmt)->hdr.tag) != FOAM_Seq) {
1319 return inlCallIsInExpr(call, pstmt);
1320 }
1321
1322 for (i = 0; i < foamArgc(*pstmt)((*pstmt)->hdr.argc); i++) {
1323 Foam * pst = (*pstmt)->foamSeq.argv + i;
1324
1325 if (inlCallIsInExpr(call, pst)) {
1326 priCall->stmtPtr = pst;
1327 return inlPriCallStmtReset(priCall);
1328 }
1329 }
1330
1331 /* bug("inlPriCallStmtReset: call not found..."); */
1332
1333 return (Foam *) int0((int) 0);
1334}
1335
1336/******************************************************************************
1337 *
1338 * :: Inline Priority Calls
1339 *
1340 *****************************************************************************/
1341
1342/*
1343 * Inline a priority call.
1344 * Result = false ==> the flog must be rebuilt.
1345 */
1346localstatic Bool
1347inlInlinePriCall(InlPriCall priCall, PriQKey priority)
1348{
1349 Foam * stmtPtr;
1350 Foam * callPtr;
1351 Foam * parv;
1352 int npars;
1353 Foam inlinedCall;
1354 Syme syme = NULL((void*)0);
1355
1356 inlProg->seq = priCall->block->code;
1357
1358 callPtr = inlPriCallStmtReset(priCall);
1359
1360 if (!callPtr) {
1361 if (DEBUG(inlCallInfo)(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))
) {
1362 fprintf(dbOut, "(Already inlined: [%f] ", priority);
1363 foamPrintDb(priCall->call);
1364 }
1365 return true1;
1366 }
1367
1368 stmtPtr = priCall->stmtPtr;
1369
1370 inlProg->seqBody = listNil(Foam)((FoamList) 0);
1371
1372 assert(stmtPtr && inlCallIsInExpr(*callPtr, stmtPtr))do { if (!(stmtPtr && inlCallIsInExpr(*callPtr, stmtPtr
))) _do_assert(("stmtPtr && inlCallIsInExpr(*callPtr, stmtPtr)"
),"of_inlin.c",1372); } while (0)
;
1373 assert(*callPtr == priCall->call)do { if (!(*callPtr == priCall->call)) _do_assert(("*callPtr == priCall->call"
),"of_inlin.c",1373); } while (0)
;
1374
1375 if (foamTag(*callPtr)((*callPtr)->hdr.tag) == FOAM_CCall) {
1376 syme = foamSyme((*callPtr)->foamCCall.op)(((*callPtr)->foamCCall.op)->hdr.syme);
1377 parv = (*callPtr)->foamCCall.argv;
1378 npars = foamArgc(*callPtr)((*callPtr)->hdr.argc) - 2;
1379 }
1380 else {
1381 assert(foamTag(*callPtr) == FOAM_OCall)do { if (!(((*callPtr)->hdr.tag) == FOAM_OCall)) _do_assert
(("foamTag(*callPtr) == FOAM_OCall"),"of_inlin.c",1381); } while
(0)
;
1382 syme = foamSyme((*callPtr)->foamOCall.op)(((*callPtr)->foamOCall.op)->hdr.syme);
1383 parv = (*callPtr)->foamOCall.argv;
1384 npars = foamArgc(*callPtr)((*callPtr)->hdr.argc) - 3;
1385 }
1386
1387 if (DEBUG(inlCallInfo)(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))
) {
1388 fprintf(dbOut, "(Inlining:");
1389 if (syme) fprintf(dbOut,"%s ", symePretty(syme));
1390 fprintf(dbOut, "[%f] ", priority);
1391 foamPrintDb(*callPtr);
1392 }
1393
1394 inlinedCall = inlCall(*callPtr, stmtPtr != callPtr);
1395
1396 if (inlinedCall == *callPtr) return true1;
1397
1398 inlProg->prog->foamProg.size += priCall->size;
1399
1400 if (callPtr == stmtPtr) {
1401 if (otIsVar(inlinedCall)(((inlinedCall)->hdr.tag) == FOAM_Loc || ((inlinedCall)->
hdr.tag) == FOAM_Par || ((inlinedCall)->hdr.tag) == FOAM_Lex
|| ((inlinedCall)->hdr.tag) == FOAM_Glo)
||
1402 (foamTag(inlinedCall)((inlinedCall)->hdr.tag) == FOAM_Values &&
1403 foamArgc(inlinedCall)((inlinedCall)->hdr.argc) == 0))
1404 *callPtr = foamNewNil()foamNew(FOAM_Nil, (int) 0);
1405 else
1406 *callPtr = inlinedCall;
1407 }
1408 else
1409 *callPtr = inlinedCall;
1410
1411 *stmtPtr = inlInsertSeq(*stmtPtr);
1412
1413
1414
1415 if (DEBUG(inlCallInfo)(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))
) {
1416 if (syme)
1417 symePrintDb2(syme);
1418 fprintf(dbOut, " Inlined)\n");
1419 }
1420
1421 inlAddNewCallsToPriq(stmtPtr, parv, npars,
1422 priCall->block->iextra, priCall->block);
1423
1424 return true1;
1425}
1426
1427localstatic InlPriCall
1428inlPriCallNew(Foam call, Foam * stmtPtr, BBlock bb, int size)
1429{
1430 InlPriCall i = (InlPriCall) stoAlloc(OB_Other0, sizeof(*i));
1431
1432 i->call = call;
1433 i->stmtPtr = stmtPtr;
1434 i->block = bb;
1435 i->size = size;
1436
1437 return i;
1438}
1439
1440localstatic void
1441inlPriCallFree(InlPriCall pc)
1442{
1443 stoFree(pc);
1444}
1445
1446/* Return a (Seq S1..Sn), where S1..Sn-1 are the stmts in inl->seqBody, and
1447 * Sn is FOAM.
1448 * Side effects: inlProg->seqBody is released.
1449 */
1450localstatic Foam
1451inlInsertSeq(Foam foam)
1452{
1453 int numStmts = listLength(Foam)(Foam_listPointer->_Length)(inlProg->seqBody) + 1;
1454 Foam newSeq = foamNewEmpty(FOAM_Seq, numStmts);
1455 int i = 0;
1456
1457 if (!inlProg->seqBody) return foam;
1458
1459 inlProg->seqBody = listNReverse(Foam)(Foam_listPointer->NReverse)(inlProg->seqBody);
1460
1461 listIter(Foam, stmt, inlProg->seqBody, {{ { FoamList _l0; Foam stmt; for (_l0 = (inlProg->seqBody)
; _l0; _l0 = ((_l0)->rest)) { stmt = ((_l0)->first); { {
newSeq->foamSeq.argv[i++] = stmt; }; }; } }; }
1462 newSeq->foamSeq.argv[i++] = stmt;{ { FoamList _l0; Foam stmt; for (_l0 = (inlProg->seqBody)
; _l0; _l0 = ((_l0)->rest)) { stmt = ((_l0)->first); { {
newSeq->foamSeq.argv[i++] = stmt; }; }; } }; }
1463 }){ { FoamList _l0; Foam stmt; for (_l0 = (inlProg->seqBody)
; _l0; _l0 = ((_l0)->rest)) { stmt = ((_l0)->first); { {
newSeq->foamSeq.argv[i++] = stmt; }; }; } }; }
;
1464
1465 listFree(Foam)(Foam_listPointer->Free)(inlProg->seqBody);
1466
1467 inlProg->seqBody = listNil(Foam)((FoamList) 0);
1468
1469 newSeq->foamSeq.argv[i] = foam;
1470
1471 inlProg->changed = true1;
1472 inlProg->size += (numStmts - 1);
1473
1474 return newSeq;
1475}
1476
1477/*
1478 * Create a new locals section for a program if new locals were generated.
1479 */
1480localstatic void
1481inlNewLocals(Foam prog)
1482{
1483 prog->foamProg.locals = fboxMake(inlProg->locals->fbox);
1484}
1485
1486localstatic Foam
1487inlSets(Foam foam)
1488{
1489 foamIter(foam, arg, *arg = inlSets(*arg); ){ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { *arg = inlSets(*arg);; }; } } }; }
;
1490
1491 if (otIsDef(foam)(((foam)->hdr.tag) == FOAM_Set || ((foam)->hdr.tag) == FOAM_Def
)
)
1492 return inlSet(foam);
1493 else
1494 return foam;
1495
1496}
1497
1498/******************************************************************************
1499 *
1500 * :: Simplify Foam
1501 *
1502 *****************************************************************************/
1503
1504/*
1505 * Simplify Defines from the unit w/out inlining calls.
1506 */
1507localstatic void
1508inlSimplifyDDef(Foam defs)
1509{
1510 Scope("inlSimplifyDDef")String scopeName = ("inlSimplifyDDef"); int fluidLevel0 = (scopeLevel
++, fluidLevel)
;
1511 int i;
1512 Foam def;
1513 OptInfo fluid(inlProg)fluidSave_inlProg = ( fluidStack = (fluidLevel==fluidLimit) ?
fluidGrow() : fluidStack, fluidStack[fluidLevel].scopeName =
scopeName, fluidStack[fluidLevel].scopeLevel = scopeLevel, fluidStack
[fluidLevel].pglobal = (Pointer) &(inlProg), fluidStack[fluidLevel
].pstack = (Pointer) &fluidSave_inlProg, fluidStack[fluidLevel
].size = sizeof(inlProg), fluidLevel++, (inlProg) )
;
1514
1515 assert(foamTag(defs) == FOAM_DDef)do { if (!(((defs)->hdr.tag) == FOAM_DDef)) _do_assert(("foamTag(defs) == FOAM_DDef"
),"of_inlin.c",1515); } while (0)
;
1516
1517 for(i=0; i < foamArgc(defs)((defs)->hdr.argc); i++) {
1518 def = defs->foamDDef.argv[i];
1519
1520 assert(foamTag(def) == FOAM_Def)do { if (!(((def)->hdr.tag) == FOAM_Def)) _do_assert(("foamTag(def) == FOAM_Def"
),"of_inlin.c",1520); } while (0)
;
1521
1522 if (foamTag(def->foamDef.rhs)((def->foamDef.rhs)->hdr.tag) == FOAM_Prog) {
1523 inlProg = foamOptInfo(def->foamDef.rhs)((def->foamDef.rhs)->hdr.info.opt);
1524 assert(inlProg)do { if (!(inlProg)) _do_assert(("inlProg"),"of_inlin.c",1524
); } while (0)
;
1525
1526 inlSimplifyFlog(inlProg->flog);
1527 }
1528 }
1529
1530 ReturnNothing{ fluidUnwind(fluidLevel0, ((int) 0)); return;; };
1531}
1532
1533localstatic void
1534inlSimplifyFlog(FlowGraph flog)
1535{
1536 flogIter(flog, bb, { bb->code = inlSimplifySeq(bb->code); }){ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { bb->code = inlSimplifySeq(bb->code
); }; }; } }; }
;
1537}
1538
1539localstatic Foam
1540inlSimplifySeq(Foam seq)
1541{
1542 int i;
1543
1544 assert(foamTag(seq) == FOAM_Seq)do { if (!(((seq)->hdr.tag) == FOAM_Seq)) _do_assert(("foamTag(seq) == FOAM_Seq"
),"of_inlin.c",1544); } while (0)
;
1545
1546 for (i = 0; i < foamArgc(seq)((seq)->hdr.argc); i++)
1547 seq->foamSeq.argv[i] =
1548 inlExpr(seq->foamSeq.argv[i], false((int) 0));
1549
1550 return seq;
1551}
1552
1553/*
1554 * Simplify a general Foam expression, without inlining calls.
1555 */
1556localstatic Foam
1557inlExpr(Foam foam, Bool isDefLhs)
1558{
1559 FoamTag tag = foamTag (foam)((foam)->hdr.tag);
1560 Foam newArg;
1561 int numArg;
1562 static int serialNo = 0, depthNo = 0;
1563 int serialThis;
1564
1565 serialNo += 1;
1566 depthNo += 1;
1567 serialThis = serialNo;
1568
1569 if (DEBUG(inlExpr)inlExprDebug) {
1570 fprintf(dbOut, ">>(inlExpr %d.%d :\n",
1571 depthNo-serialThis, serialThis);
1572 foamPrint(dbOut, foam);
1573 fnewline(dbOut);
1574 }
1575
1576 /* don't recurse into forces */
1577 if (tag == FOAM_CCall && inlIsForcer(foam->foamCCall.op))
1578 return inlId(foam);
1579
1580 numArg = 0;
1581 foamIter(foam, arg, {{ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { { newArg = inlExpr(*arg, numArg == 0 && (((foam
)->hdr.tag) == FOAM_Set || ((foam)->hdr.tag) == FOAM_Def
)); if (*arg != newArg) foamFreeNode(*arg); *arg = newArg; numArg
++; }; }; } } }; }
1582 newArg = inlExpr(*arg, numArg == 0 && otIsDef(foam));{ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { { newArg = inlExpr(*arg, numArg == 0 && (((foam
)->hdr.tag) == FOAM_Set || ((foam)->hdr.tag) == FOAM_Def
)); if (*arg != newArg) foamFreeNode(*arg); *arg = newArg; numArg
++; }; }; } } }; }
1583 if (*arg != newArg) foamFreeNode(*arg);{ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { { newArg = inlExpr(*arg, numArg == 0 && (((foam
)->hdr.tag) == FOAM_Set || ((foam)->hdr.tag) == FOAM_Def
)); if (*arg != newArg) foamFreeNode(*arg); *arg = newArg; numArg
++; }; }; } } }; }
1584 *arg = newArg;{ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { { newArg = inlExpr(*arg, numArg == 0 && (((foam
)->hdr.tag) == FOAM_Set || ((foam)->hdr.tag) == FOAM_Def
)); if (*arg != newArg) foamFreeNode(*arg); *arg = newArg; numArg
++; }; }; } } }; }
1585 numArg++;{ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { { newArg = inlExpr(*arg, numArg == 0 && (((foam
)->hdr.tag) == FOAM_Set || ((foam)->hdr.tag) == FOAM_Def
)); if (*arg != newArg) foamFreeNode(*arg); *arg = newArg; numArg
++; }; }; } } }; }
1586 }){ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { { newArg = inlExpr(*arg, numArg == 0 && (((foam
)->hdr.tag) == FOAM_Set || ((foam)->hdr.tag) == FOAM_Def
)); if (*arg != newArg) foamFreeNode(*arg); *arg = newArg; numArg
++; }; }; } } }; }
;
1587
1588 switch (tag) {
1589 case FOAM_Set:
1590 case FOAM_Def:
1591 foam = inlSet(foam);
1592 break;
1593 case FOAM_CEnv:
1594 foam = inlGetVarTableEnv(foam->foamCEnv.env, foam);
1595 break;
1596 case FOAM_EEnv:
1597 foam = inlCanonEEnv(foam);
1598 break;
1599 case FOAM_EElt:
1600 foam = inlCanonEElt(foam);
1601 /* Fall through */
1602 case FOAM_Lex:
1603 if (!isDefLhs) foam = inlId(foam);
1604 break;
1605 default:
1606 break;
1607 }
1608 /*!! Free stuff ! */
1609
1610 if (DEBUG(inlExpr)inlExprDebug) {
1611 fprintf(dbOut, "<<inlExpr: (%d.%d) :\n", depthNo-serialThis, serialThis);
1612 foamPrint(dbOut, foam);
1613 fprintf(dbOut, "expr)\n");
1614 }
1615
1616 return foam;
1617}
1618
1619/*
1620 * Inline a non-program constant. e.g. small integer 0 and 1.
1621 */
1622localstatic Foam
1623inlId(Foam var)
1624{
1625 Syme syme;
1626 Foam foam, id;
1627 InlProgInfo progInfo;
1628
1629 if (foamTag(var)((var)->hdr.tag) == FOAM_CCall)
1630 id = var->foamCCall.argv[0];
1631 else
1632 id = var;
1633 syme = foamSyme(id)((id)->hdr.syme);
1634
1635 if (!syme) return var;
1636
1637 /* programs get inlined at call point. */
1638 if (tfIsAnyMap(symeType(syme))((((symeType(syme))->tag) == TF_Map) || (((symeType(syme))
->tag) == TF_PackedMap))
) return var;
1639
1640 progInfo = inlGetProgInfoFrSyme(syme);
1641
1642 if (progInfo) {
1643 foamFreeNode(progInfo);
1644 return var;
1645 }
1646
1647 foam = inlGetFoam(syme);
1648 if (!foam) return var;
1649
1650 assert(foamTag(foam) != FOAM_Prog)do { if (!(((foam)->hdr.tag) != FOAM_Prog)) _do_assert(("foamTag(foam) != FOAM_Prog"
),"of_inlin.c",1650); } while (0)
;
1651
1652 return foamCopy(foam);
1653}
1654
1655localstatic Foam
1656inlGetClosFrVar(Foam op)
1657{
1658 if (inlProg->converged)
1659 return inuGetClosFrVar(op);
1660 else
1661 return (Foam) NULL((void*)0);
1662}
1663
1664/******************************************************************************
1665 *
1666 * :: Inline Call
1667 *
1668 *****************************************************************************/
1669
1670/*
1671 * Inline a closed or open call.
1672 */
1673localstatic Foam
1674inlCall(Foam call, Bool valueMode)
1675{
1676 Foam op, *argv, env, val, ncall = call;
1677 Syme syme;
1678
1679 if (!inlInlineProgs) return call;
1680
1681 assert(foamTag(call) == FOAM_CCall || foamTag(call) == FOAM_OCall)do { if (!(((call)->hdr.tag) == FOAM_CCall || ((call)->
hdr.tag) == FOAM_OCall)) _do_assert(("foamTag(call) == FOAM_CCall || foamTag(call) == FOAM_OCall"
),"of_inlin.c",1681); } while (0)
;
1682
1683 if (foamTag(call)((call)->hdr.tag) == FOAM_CCall) {
1684 op = call->foamCCall.op;
1685 if (foamTag(op)((op)->hdr.tag) == FOAM_Cast)
1686 op = op->foamCast.expr;
1687 argv = call->foamCCall.argv;
1688 env = inlGetVarTableEnv(op, NULL((void*)0));
1689 val = inlGetClosFrVar(op);
1690 }
1691 else {
1692 op = call->foamOCall.op;
1693 argv = call->foamOCall.argv;
1694 env = call->foamOCall.env;
1695 val = NULL((void*)0);
1696 }
1697
1698 /* Inline if syme is declared inlinable. */
1699 if (foamTag(op)((op)->hdr.tag) != FOAM_Clos && (syme = foamSyme(op)((op)->hdr.syme)) != NULL((void*)0))
1700 ncall = inlInlineSymeCall(call, argv, env, syme, valueMode);
1701
1702 if (ncall != call)
1703 ;
1704
1705 /* Inline direct open calls. */
1706 else if (foamTag(call)((call)->hdr.tag) == FOAM_OCall)
1707 ncall = inlInlineOpenCall(call, argv, env, op, valueMode);
1708
1709 /* Inline direct calls to constant closure values
1710 * whose values are tracked through varTable.
1711 */
1712 else if (val && foamTag(val)((val)->hdr.tag) == FOAM_Clos)
1713 ncall = inlInlineConstCall(call, argv, env, val, valueMode);
1714
1715 /* Inline direct calls to constant closure values. */
1716 else if (foamTag(op)((op)->hdr.tag) == FOAM_Clos)
1717 ncall = inlInlineConstCall(call, argv, env, op, valueMode);
1718
1719 if (DEBUG(inlCall)inlCallDebug) {
1720 if (inlConstTrace == -1 ||
1721 inlConstTrace == inlProg->constNum) {
1722 fprintf(dbOut, "<<inlCall: ");
1723 foamPrint(dbOut, call);
1724 fprintf(dbOut, "\n ->\n");
1725 foamPrint(dbOut, ncall);
1726 fnewline(dbOut);
1727 }
1728 }
1729
1730 if (!valueMode && !foamHasSideEffect(ncall)) {
1731 foamFree(ncall);
1732 ncall = foamNewNOp()foamNew(FOAM_NOp, (int) 0);
1733 }
1734 if (ncall != call) ncall = inuPeepExpr(ncall);
1735
1736 return ncall;
1737}
1738
1739/*****************************************************************************
1740 *
1741 * :: Foam inlining functions
1742 *
1743 ****************************************************************************/
1744
1745/*
1746 * inline a call to a function for which we have a symbol meaning.
1747 * 'call' is the original call, returned if we decide not to inline it.
1748 * 'argv' holds the arguments to the call, 'env' is the environment for
1749 * the function, 'syme' is its symbol meaning.
1750 */
1751localstatic Foam
1752inlInlineSymeCall(Foam call, Foam *argv, Foam env, Syme syme, Bool valueMode)
1753{
1754 Scope("inlInlineSymeCall")String scopeName = ("inlInlineSymeCall"); int fluidLevel0 = (
scopeLevel++, fluidLevel)
;
1755 Foam code, val, envLoc;
1756 InlineeInfo fluid(inlInlinee)fluidSave_inlInlinee = ( fluidStack = (fluidLevel==fluidLimit
) ? fluidGrow() : fluidStack, fluidStack[fluidLevel].scopeName
= scopeName, fluidStack[fluidLevel].scopeLevel = scopeLevel,
fluidStack[fluidLevel].pglobal = (Pointer) &(inlInlinee)
, fluidStack[fluidLevel].pstack = (Pointer) &fluidSave_inlInlinee
, fluidStack[fluidLevel].size = sizeof(inlInlinee), fluidLevel
++, (inlInlinee) )
;
1757
1758 inlNewInlinee();
1759 inlInlinee->syme = syme;
1760
1761 code = inlGetFoam(syme);
1762 if (!code) Return(call){ fluidUnwind(fluidLevel0, ((int) 0)); return call;; };
1763
1764 if (symeIsLocalConst(syme)(symeConstLib(syme) == ((void*)0)) && foamOptInfo(code)((code)->hdr.info.opt) &&
1765 foamOptInfo(code)((code)->hdr.info.opt)->inlState != INL_Inlined)
1766 Return(call){ fluidUnwind(fluidLevel0, ((int) 0)); return call;; };
1767 if (code->foamProg.body == NULL((void*)0)) {
1768 Return(call){ fluidUnwind(fluidLevel0, ((int) 0)); return call;; };
1769 }
1770
1771 assert(!foamProgIsGetter(code))do { if (!(!((code)->foamProg.infoBits & (1 << 3
)))) _do_assert(("!foamProgIsGetter(code)"),"of_inlin.c",1771
); } while (0)
;
1772 assert(!inlIsEvil(code))do { if (!(!inlIsEvil(code))) _do_assert(("!inlIsEvil(code)")
,"of_inlin.c",1772); } while (0)
;
1773
1774 code = inlSetInlinee(symeConstLib(syme), code);
1775 envLoc = inlAddLocal(FOAM_Env, emptyFormatSlot4);
1776 val = inlInlineBody(code, call, argv, env, envLoc, valueMode);
1777
1778 assert(val != call)do { if (!(val != call)) _do_assert(("val != call"),"of_inlin.c"
,1778); } while (0)
;
1779 if (inlProg->syme) {
1780 SymeList symes = symeInlined(inlProg->syme);
1781
1782 symes = listCons(Syme)(Syme_listPointer->Cons)(syme, symes);
1783 symes = listConcat(Syme)(Syme_listPointer->Concat)(symes, symeInlined(syme));
1784
1785 symeSetInlined(inlProg->syme, symes)(symeSetFieldVal = ((AInt) (symes)), (((((inlProg->syme)->
kind == SYME_Trigger ? libGetAllSymes((inlProg->syme)->
lib) : ((void*)0)), (inlProg->syme))->locmask) & (1
<< (SYFI_Inlined))) ? (((inlProg->syme)->fieldv)
[symeIndex(inlProg->syme,SYFI_Inlined)] = (symeSetFieldVal
)) : !((inlProg->syme)->full) && symeSetFieldVal
== (symeFieldInfo[SYFI_Inlined].def) ? symeSetFieldVal : symeSetFieldFn
(inlProg->syme,SYFI_Inlined,symeSetFieldVal))
;
1786 }
1787
1788 if (inlInlinee->sigma)
1789 absFree(inlInlinee->sigma);
1790 stoFree(inlInlinee);
1791 Return(val){ fluidUnwind(fluidLevel0, ((int) 0)); return val;; };
1792}
1793
1794/*
1795 * inline an open call to a function.
1796 * 'call' is the original call, returned if we decide not to inline it.
1797 * 'argv' holds the arguments to the call, 'env' is the environment for
1798 * the function, op is the program part of the operator of the call.
1799 */
1800localstatic Foam
1801inlInlineOpenCall(Foam call, Foam *argv, Foam env, Foam op, Bool valueMode)
1802{
1803 Scope("inlInlineOpenCall")String scopeName = ("inlInlineOpenCall"); int fluidLevel0 = (
scopeLevel++, fluidLevel)
;
1804 Foam code, val, cnst, envLoc;
1805 InlineeInfo fluid(inlInlinee)fluidSave_inlInlinee = ( fluidStack = (fluidLevel==fluidLimit
) ? fluidGrow() : fluidStack, fluidStack[fluidLevel].scopeName
= scopeName, fluidStack[fluidLevel].scopeLevel = scopeLevel,
fluidStack[fluidLevel].pglobal = (Pointer) &(inlInlinee)
, fluidStack[fluidLevel].pstack = (Pointer) &fluidSave_inlInlinee
, fluidStack[fluidLevel].size = sizeof(inlInlinee), fluidLevel
++, (inlInlinee) )
;
1806
1807 assert(foamTag(op) == FOAM_Const)do { if (!(((op)->hdr.tag) == FOAM_Const)) _do_assert(("foamTag(op) == FOAM_Const"
),"of_inlin.c",1807); } while (0)
;
1808 cnst = op;
1809 assert(foamTag(cnst) == FOAM_Const)do { if (!(((cnst)->hdr.tag) == FOAM_Const)) _do_assert(("foamTag(cnst) == FOAM_Const"
),"of_inlin.c",1809); } while (0)
;
1810
1811 inlNewInlinee();
1812
1813 code = inlGetLocalConst(cnst->foamConst.index);
1814
1815 if (!code) Return(call){ fluidUnwind(fluidLevel0, ((int) 0)); return call;; };
1816
1817 envLoc = inlAddLocal(FOAM_Env, emptyFormatSlot4);
1818 val = inlInlineBody(code, call, argv, env, envLoc, valueMode);
1819
1820 assert(val != call)do { if (!(val != call)) _do_assert(("val != call"),"of_inlin.c"
,1820); } while (0)
;
1821
1822 stoFree(inlInlinee);
1823 Return(val){ fluidUnwind(fluidLevel0, ((int) 0)); return val;; };
1824}
1825
1826/*
1827 * inline an call to a constant closure. e.g. (CCall (Clos op env) ...)
1828 * 'call' is the original call, returned if we decide not to inline it.
1829 * 'argv' holds the arguments to the call, 'env' is the environment for
1830 * the function, op is the program part of the operator of the call.
1831 */
1832localstatic Foam
1833inlInlineConstCall(Foam call, Foam *argv, Foam env, Foam op,
1834 Bool valueMode)
1835{
1836 Scope("inlInlineConstCall")String scopeName = ("inlInlineConstCall"); int fluidLevel0 = (
scopeLevel++, fluidLevel)
;
1837 Foam code, val, cnst, envLoc;
1838 InlineeInfo fluid(inlInlinee)fluidSave_inlInlinee = ( fluidStack = (fluidLevel==fluidLimit
) ? fluidGrow() : fluidStack, fluidStack[fluidLevel].scopeName
= scopeName, fluidStack[fluidLevel].scopeLevel = scopeLevel,
fluidStack[fluidLevel].pglobal = (Pointer) &(inlInlinee)
, fluidStack[fluidLevel].pstack = (Pointer) &fluidSave_inlInlinee
, fluidStack[fluidLevel].size = sizeof(inlInlinee), fluidLevel
++, (inlInlinee) )
;
1839
1840 assert(foamTag(op) == FOAM_Clos)do { if (!(((op)->hdr.tag) == FOAM_Clos)) _do_assert(("foamTag(op) == FOAM_Clos"
),"of_inlin.c",1840); } while (0)
;
1841 cnst = op->foamClos.prog;
1842 assert(foamTag(cnst) == FOAM_Const)do { if (!(((cnst)->hdr.tag) == FOAM_Const)) _do_assert(("foamTag(cnst) == FOAM_Const"
),"of_inlin.c",1842); } while (0)
;
1843
1844 inlNewInlinee();
1845 inlInlinee->syme = inlGetSymeFrEnv(env);
1846
1847 code = inlGetLocalConst(cnst->foamConst.index);
1848
1849 if (!code) Return(call){ fluidUnwind(fluidLevel0, ((int) 0)); return call;; };
1850
1851 envLoc = inlAddLocal(FOAM_Env, emptyFormatSlot4);
1852 val = inlInlineBody(code, call, argv, env, envLoc, valueMode);
1853
1854 assert(val != call)do { if (!(val != call)) _do_assert(("val != call"),"of_inlin.c"
,1854); } while (0)
;
1855
1856 if (inlInlinee->sigma)
1857 absFree(inlInlinee->sigma);
1858 stoFree(inlInlinee);
1859 Return(val){ fluidUnwind(fluidLevel0, ((int) 0)); return val;; };
1860}
1861
1862/*
1863 * Inline the Foam code for the body of a function. This is the general entry
1864 * point for all inlining. 'code' is the body of the function to inline.
1865 * 'call' is the original call returned if we decide not to inline. 'argv'
1866 * holds the arguments to the call. 'env' is the envirnment of the call.
1867 * envLoc is a variable pointing to the envirnment.
1868 */
1869localstatic Foam
1870inlInlineBody(Foam code, Foam call, Foam *argv, Foam env,
1871 Foam envLoc, Bool valueMode)
1872{
1873 int i, paramArgc, localArgc, format;
1874 Bool hasOCall = false((int) 0);
1875 Bool noLocalEnv, usesInnerEnvironment = false((int) 0);
1876 int *paramCount = 0;
1877 Foam *paramArgv, *localArgv, foam;
1878 Foam parent;
1879 /* don't inline yourself */
1880 assert(inlInlinee->origProg != inlProg->prog)do { if (!(inlInlinee->origProg != inlProg->prog)) _do_assert
(("inlInlinee->origProg != inlProg->prog"),"of_inlin.c"
,1880); } while (0)
;
1881 assert(!foamProgIsGetter(code))do { if (!(!((code)->foamProg.infoBits & (1 << 3
)))) _do_assert(("!foamProgIsGetter(code)"),"of_inlin.c",1881
); } while (0)
;
1882 assert(foamArgc(code->foamProg.fluids) == 0)do { if (!(((code->foamProg.fluids)->hdr.argc) == 0)) _do_assert
(("foamArgc(code->foamProg.fluids) == 0"),"of_inlin.c",1882
); } while (0)
;
1883
1884 /* Initialize the paramter replacement vector. */
1885 paramArgc = foamDDeclArgc(code->foamProg.params)(((code->foamProg.params)->hdr.argc) - (1));
1886 paramCount = (int *) stoAlloc(OB_Other0, paramArgc * sizeof(int));
1887 paramArgv = (Foam *) stoAlloc(OB_Other0, paramArgc * sizeof(Foam));
1888 for(i=0; i<paramArgc; i++) paramCount[i] = 0;
1889 inlGetProgInfo(code->foamProg.body, paramCount, &hasOCall,
1890 &usesInnerEnvironment);
1891
1892 if (usesInnerEnvironment) {
1893 Foam denv = code->foamProg.levels;
1894 usesInnerEnvironment = false((int) 0);
1895 for (i=1; i<foamArgc(denv)((denv)->hdr.argc); i++) {
1896 if (denv->foamDEnv.argv[i] != emptyFormatSlot4)
1897 usesInnerEnvironment = true1;
1898 }
1899 }
1900
1901#if 0
1902 if (!usesInnerEnvironment)
1903 env = foamNewCast(FOAM_Env, foamNewNil())foamNew(FOAM_Cast, 2, FOAM_Env, foamNew(FOAM_Nil, (int) 0));
1904#endif
1905 /* Determine whether inliner and inlinee have the same parent. */
1906 inlInlinee->sameParent =
1907 foamOptInfo(code)((code)->hdr.info.opt) &&
1908 foamOptInfo(code)((code)->hdr.info.opt)->stab && inlProg->stab &&
1909 !foamOptInfo(code)((code)->hdr.info.opt)->isGener &&
1910 !inlProg->isGener &&
1911 cdr(foamOptInfo(code)->stab)((((code)->hdr.info.opt)->stab)->rest) == cdr(inlProg->stab)((inlProg->stab)->rest);
1912
1913 /* Push a new env if progs don't exist in the same env. */
1914 inlInlinee->denv = code->foamProg.levels;
1915
1916 noLocalEnv = (inlInlinee->denv->foamDEnv.argv[0] == emptyFormatSlot4);
1917 inlInlinee->noLocalEnv = noLocalEnv;
1918
1919 if (inlInlineeIsLocal()(inlInlinee->origin == ((void*)0))
1920 && !inlProg->isGener
1921 && inlSameDEnv(inlInlinee->denv,inlProg->denv)) {
1922 env = noLocalEnv ? foamNewEnv(1)foamNew(FOAM_Env, 1, (AInt)(1)) : foamNewEnv(int0)foamNew(FOAM_Env, 1, (AInt)(((int) 0)));
1923 } else {
1924 format = inlGetFormat(inlInlinee->denv->foamDEnv.argv[0]);
1925 fboxNth(inlUnit->formats, format)->foamDDecl.usage = FOAM_DDecl_LocalEnv;
1926 env = noLocalEnv ? foamCopy(env)
1927 : foamNewPushEnv(format, foamCopy(env))foamNew(FOAM_PushEnv,2,format,foamCopy(env));
1928 }
1929 foamSyme(env)((env)->hdr.syme) = inlInlinee->syme;
1930
1931 /* Initialize the local variable vector. */
1932 localArgc = foamDDeclArgc(code->foamProg.locals)(((code->foamProg.locals)->hdr.argc) - (1));
1933 localArgv = (Foam *) stoAlloc(OB_Other0, localArgc * sizeof(Foam));
1934
1935 /* Add the decls of any new locals in the inlinee. */
1936 if (foamDDeclArgc(code->foamProg.locals)(((code->foamProg.locals)->hdr.argc) - (1)) > 0)
1937 inlAddLocalDecls(code->foamProg.locals, localArgv);
1938
1939 /* Set up local var for environment. */
1940 inlInlinee->env = envLoc;
1941 parent = inlParentEnv(envLoc, env);
1942 if (parent) foamSyme(parent)((parent)->hdr.syme) = inlInlinee->syme;
1943 inlInlinee->parentEnv = parent;
1944 /* Compute a label offset for the labels on the labels in the prog. */
1945 inlProg->newLabel = inlProg->numLabels + code->foamProg.nLabels;
1946
1947 inlAddEnv(envLoc, env, usesInnerEnvironment);
1948 for(i=0; i< paramArgc; i++) {
1949 AInt argFmt;
1950 FoamTag argType = inlExprType(argv[i], &argFmt);
1951 Foam paramDecl = code->foamProg.params->foamDDecl.argv[i];
1952 if (argType != paramDecl->foamDecl.type) {
1953 inlineDEBUGif (!inlineDebug) { } else afprintf(dbOut, "Mismatched caller type: %s -- %pFoam\n",
1954 foamStr(argType)((foamInfoTable [(int)(argType)-(int)FOAM_START]).str), paramDecl);
1955 argv[i] = foamNewCast(paramDecl->foamDecl.type, argv[i])foamNew(FOAM_Cast, 2, paramDecl->foamDecl.type, argv[i]);
1956 }
1957 if (argFmt != paramDecl->foamDecl.format) {
1958 inlineDEBUGif (!inlineDebug) { } else afprintf(dbOut, "Mismatched caller format: %d -- %pFoam\n",
1959 argFmt, paramDecl);
1960 }
1961 }
1962 /* Initialize the variables used to hold the paramters of the call. */
1963 for(i=0; i< paramArgc; i++) {
1964 if (inlUseParam(argv[i], paramCount[i]))
1965 paramArgv[i] = argv[i];
1966 else {
1967 FoamTag type;
1968 Foam var;
1969 AInt fmt;
1970 type = code->foamProg.params->foamDDecl.argv[i]->foamDecl.type;
1971 fmt = code->foamProg.params->foamDDecl.argv[i]->foamDecl.format;
1972 var = inlAddTempLocal(type, fmt);
1973 paramArgv[i] = var;
1974 inlAddStmt(foamNewSet(foamCopy(paramArgv[i]),argv[i])foamNew(FOAM_Set, 2, foamCopy(paramArgv[i]), argv[i]));
1975 inlProg->prog->foamProg.size += 3;
1976 }
1977 }
1978
1979 /* Integrate the inlinee into the inliner. */
1980 foam = inlInlineProg(code, paramArgv, localArgv, valueMode);
1981
1982 inlProg->numLabels = inlProg->newLabel;
1983
1984 inlProg->changed = true1;
1985
1986 if (!foamProgHasNoOCalls(code)((code)->foamProg.infoBits & (1 << 11)))
1987 foamProgUnsetHasNoOCalls(inlProg->prog)((inlProg->prog)->foamProg.infoBits &= ~(1 <<
11))
;
1988
1989 if (inlProg->seqBody)
1990 foamProgUnsetHasSingleStmt(inlProg->prog)((inlProg->prog)->foamProg.infoBits &= ~(1 <<
12))
;
1991
1992 if (paramCount) {
1993 stoFree(paramCount);
1994 stoFree(paramArgv);
1995 }
1996
1997 if (inlInlinee->parentEnv) foamFree(inlInlinee->parentEnv);
1998
1999 return foam;
2000}
2001
2002localstatic Syme
2003inlGetSymeFrEnv(Foam env)
2004{
2005 if (inlProg->converged)
2006 return inuGetSymeFrEnv(env);
2007 else
2008 return NULL((void*)0);
2009}
2010
2011localstatic Bool
2012inlIsLocalEnv(Foam env)
2013{
2014 if (inlProg->converged)
2015 return inuIsLocalEnv(env);
2016 else
2017 return false((int) 0);
2018}
2019
2020localstatic void
2021inlAddEnv(Foam envLoc, Foam env, Bool usesInner)
2022{
2023 Foam parentEnv = NULL((void*)0);
2024
2025 if (foamTag(env)((env)->hdr.tag) == FOAM_PushEnv)
2026 parentEnv = env->foamPushEnv.parent;
2027 else if (inlInlinee->noLocalEnv)
2028 parentEnv = env;
2029
2030 if (parentEnv
2031 && usesInner
2032 && !inlInlinee->sameParent
2033 && foamTag(parentEnv)((parentEnv)->hdr.tag) != FOAM_Env
2034 && !inlIsLocalEnv(parentEnv)) {
2035
2036 inlAddStmt(foamNewEEnsure(foamCopy(parentEnv))foamNew(FOAM_EEnsure, 1, foamCopy(parentEnv)));
2037 inlProg->prog->foamProg.size += 1;
2038 }
2039
2040 inlAddStmt(foamNewDef(foamCopy(envLoc), env)foamNew(FOAM_Def, 2, foamCopy(envLoc), env));
2041}
2042
2043localstatic Foam
2044inlParentEnv(Foam envLoc, Foam env)
2045{
2046 Foam parent;
2047
2048 if (foamTag(env)((env)->hdr.tag) == FOAM_Env)
2049 parent = foamNewEnv(env->foamEnv.level + 1)foamNew(FOAM_Env, 1, (AInt)(env->foamEnv.level + 1));
2050 else if (foamTag(env)((env)->hdr.tag) == FOAM_PushEnv)
2051 parent = foamCopy(env->foamPushEnv.parent);
2052 else
2053 parent = NULL((void*)0);
2054 return parent;
2055}
2056
2057/******************************************************************************
2058 *
2059 * :: Get Prog Info
2060 *
2061 *****************************************************************************/
2062
2063/*
2064 * Get parameter and lexical usage information from a foam prog.
2065 */
2066localstatic void
2067inlGetProgInfo(Foam foam, int *paramCount, Bool *hasOCall,
2068 Bool *hasInnerEnv)
2069{
2070 FoamTag tag = foamTag (foam)((foam)->hdr.tag);
2071 int i;
2072
2073 foamIter(foam, arg,{ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { inlGetProgInfo(*arg, paramCount, hasOCall, hasInnerEnv
); }; } } }; }
2074 inlGetProgInfo(*arg, paramCount, hasOCall, hasInnerEnv)){ { String argf = (foamInfoTable [(int)(((foam)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((foam
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((foam)->foamGen.argv
)+_i; { inlGetProgInfo(*arg, paramCount, hasOCall, hasInnerEnv
); }; } } }; }
;
2075 switch (tag) {
2076 case FOAM_Par:
2077 i = foam->foamPar.index;
2078 if (paramCount[i] >= 0)
2079 paramCount[i]++;
2080 break;
2081 case FOAM_Set:
2082 if (foamTag(foam->foamSet.lhs)((foam->foamSet.lhs)->hdr.tag) == FOAM_Par)
2083 paramCount[foam->foamSet.lhs->foamPar.index] = -1;
2084 break;
2085 case FOAM_OCall:
2086 *hasOCall = true1;
2087 break;
2088 case FOAM_Env:
2089 /* Have to be over-conservative as (Env 0) can be
2090 * aliased and referenced deeply
2091 */
2092 *hasInnerEnv = true1;
2093 break;
2094 case FOAM_Lex:
2095 if (foam->foamLex.level > 0)
2096 *hasInnerEnv = true1;
2097 break;
2098 default:
2099 break;
2100 }
2101}
2102
2103/******************************************************************************
2104 *
2105 * :: Inline Prog
2106 *
2107 *****************************************************************************/
2108/*
2109 * Inline a program body into a prog.
2110 */
2111localstatic Foam
2112inlInlineProg(Foam code, Foam *paramArgv, Foam *localArgv, Bool valueMode)
2113{
2114 Foam body = code->foamProg.body, expr, retVal;
2115 int argc = foamArgc(body)((body)->hdr.argc), i, rc;
2116 FoamList lv;
2117
2118 assert(foamTag(body) == FOAM_Seq)do { if (!(((body)->hdr.tag) == FOAM_Seq)) _do_assert(("foamTag(body) == FOAM_Seq"
),"of_inlin.c",2118); } while (0)
;
2119
2120 /* Count the returns. */
2121 for (rc = 0, i = 0; i < argc; i++)
2122 if (foamTag(body->foamSeq.argv[i])((body->foamSeq.argv[i])->hdr.tag)==FOAM_Return) rc++;
2123
2124 if (argc == 1 && rc == 1) {
2125 expr = body->foamSeq.argv[0]->foamReturn.value;
2126 retVal = inlTransformExpr(expr, paramArgv, localArgv);
2127 }
2128 else if (rc == 0) {
2129 for (i = 0; i < argc; i++)
2130 inlAddStmt(inlTransformExpr(body->foamSeq.argv[i],
2131 paramArgv, localArgv));
2132 if (code->foamProg.retType != FOAM_NOp)
2133 retVal = foamNewNil()foamNew(FOAM_Nil, (int) 0);
2134 else {
2135 AInt format = code->foamProg.format;
2136 int nValues = foamDDeclArgc(inlInlinee->formats->foamDFmt.argv[format])(((inlInlinee->formats->foamDFmt.argv[format])->hdr.
argc) - (1))
;
2137 retVal = foamNewEmpty(FOAM_Values, nValues);
2138 for (i=0; i<nValues; i++) {
2139 retVal->foamValues.argv[i] = foamNewNil()foamNew(FOAM_Nil, (int) 0);
2140 }
2141 }
2142 }
2143 else {
2144 /* Set up communication with inlReturn. */
2145 inlInlinee->returnCount = rc;
2146 inlInlinee->returnVals = 0;
2147 inlInlinee->returnLabel = inlAddLabel();
2148
2149 /* Transform and add statements. */
2150 for (i = 0; i < argc; i++)
2151 inlAddStmt(inlTransformExpr(body->foamSeq.argv[i],
2152 paramArgv, localArgv));
2153 /* Common return point. */
2154 inlAddStmt(foamNewLabel(inlInlinee->returnLabel)foamNew(FOAM_Label, 1, (AInt)(inlInlinee->returnLabel)));
2155
2156 /* Return value: either orignal expr (if rc == 1) or temps. */
2157 lv = inlInlinee->returnVals;
2158 if (rc > 1) lv = listNMap(Foam)(Foam_listPointer->NMap)(foamCopy, lv);
2159 if (lv && !cdr(lv)((lv)->rest))
2160 retVal = car(lv)((lv)->first);
2161 else
2162 retVal = foamNewOfList(FOAM_Values, lv);
2163 listFree(Foam)(Foam_listPointer->Free)(lv);
2164 }
2165
2166 if (DEBUG(inlProg)inlProgDebug) {
2167 if (inlConstTrace == inlProg->constNum ||
2168 inlConstTrace == -1) {
2169 fprintf(dbOut, "<== Producing prog value:\n");
2170 foamPrint(dbOut, retVal);
2171 }
2172 }
2173 return retVal;
2174}
2175
2176/*****************************************************************************
2177 *
2178 * :: Foam inlinee functions
2179 *
2180 ****************************************************************************/
2181
2182/*
2183 * Create a fresh inlinee structure.
2184 */
2185localstatic void
2186inlNewInlinee()
2187{
2188 inlInlinee = (InlineeInfo) stoAlloc(OB_Other0,
2189 sizeof(struct inlineeInfo));
2190 inlInlinee->syme = NULL((void*)0);
2191 inlInlinee->sigma = NULL((void*)0);
2192 return;
2193}
2194
2195localstatic Foam
2196inlSetInlinee(Lib origin, Foam code)
2197{
2198 Foam fmts;
2199
2200 code = foamCopy(code);
2201 fmts = origin ? libGetFoamFormats(origin) :
2202 inlUnit->unit->foamUnit.formats;
2203
2204 inlInlinee->origin = origin;
2205 inlInlinee->formats = fmts;
2206 inlInlinee->returnCount = 0;
2207 inlInlinee->origProg = code;
2208
2209 return code;
2210}
2211
2212/*****************************************************************************
2213 *
2214 * :: Foam Globals
2215 *
2216 ****************************************************************************/
2217
2218/*
2219 * Add a global variable to a function being inlined.
2220 */
2221localstatic int
2222inlAddGlobal(Foam decl)
2223{
2224 int n = fboxAdd(inlUnit->globals, decl);
2225 if (strEqual(decl->foamGDecl.id, "dummyDefault"))
2226 inlEvilGlobal = n;
2227 return n;
2228}
2229
2230/*
2231 * create the decls for the new globals.
2232 */
2233localstatic void
2234inlMakeNewGlobals(Foam unit)
2235{
2236 foamUnitGlobals(unit)((((unit)->foamUnit.formats)->foamGen.argv)[0].code) = fboxMake(inlUnit->globals);
2237}
2238
2239/*
2240 * Reindex a global variable from a foreign unit, and add it to the
2241 * global assoc list.
2242 */
2243localstatic int
2244inlTransformGlobal(Foam glo)
2245{
2246 int size, i;
2247 AInt protocol, index;
2248 String name;
2249 Foam decl, decl0;
2250
2251 if (inlInlineeIsLocal()(inlInlinee->origin == ((void*)0))) return glo->foamGlo.index;
2252
2253 decl0 = inlInlineeDecl(globalsSlot, glo->foamGlo.index)inlInlinee->formats->foamDFmt.argv[0]->foamDDecl.argv
[glo->foamGlo.index]
;
2254 assert(foamTag(decl0) == FOAM_GDecl)do { if (!(((decl0)->hdr.tag) == FOAM_GDecl)) _do_assert((
"foamTag(decl0) == FOAM_GDecl"),"of_inlin.c",2254); } while (
0)
;
2255
2256 name = decl0->foamGDecl.id;
2257 protocol = decl0->foamGDecl.protocol;
2258
2259 size = fboxSize(inlUnit->globals)((inlUnit->globals)->argc);
2260
2261 for (i = 0; i < size; i++) {
2262 decl = fboxNth(inlUnit->globals, i);
2263 if (strEqual(name, decl->foamGDecl.id) &&
2264 protocol == decl->foamGDecl.protocol)
2265 return i;
2266 }
2267
2268 decl = foamCopy(decl0);
2269 decl->foamGDecl.dir = FOAM_GDecl_Import;
2270
2271 /* Fortran, C and Java PCalls use formats */
2272 switch (foamProtoBase(decl->foamGDecl.protocol)((foamProtoInfoTable[(int)(decl->foamGDecl.protocol)-(int)
FOAM_PROTO_START]).base)
) {
2273 case FOAM_Proto_Fortran: /*FALLTHROUGH*/
2274 case FOAM_Proto_C: /*FALLTHROUGH*/
2275 case FOAM_Proto_Java: /*FALLTHROUGH*/
2276 if (decl->foamGDecl.type == FOAM_Clos) {
2277 AInt fmt = inlGetFormat(decl->foamGDecl.format);
2278 decl->foamGDecl.format = fmt;
2279 }
2280 break;
2281 default:
2282 break;
2283 }
2284
2285 index = inlAddGlobal(decl);
2286
2287 assert(index == i)do { if (!(index == i)) _do_assert(("index == i"),"of_inlin.c"
,2287); } while (0)
;
2288
2289 return index;
2290}
2291
2292/*****************************************************************************
2293 *
2294 * :: Foam Formats
2295 *
2296 ****************************************************************************/
2297
2298/*
2299 * Create a new format info structure.
2300 */
2301localstatic FmtInfo
2302inlNewFormatInfo(Lib origin, AInt extfmt, AInt locfmt, Hash hash, Foam ddecl)
2303{
2304 FmtInfo new = (FmtInfo) stoAlloc(OB_Other0, sizeof(struct formatInfo));
2305 new->origin = origin;
2306 new->extfmt = extfmt;
2307 new->locfmt = locfmt;
2308 new->hash = hash;
2309 new->ddecl = ddecl;
2310 return new;
2311}
2312
2313/*
2314 * Equality between format infos.
2315 */
2316localstatic Bool
2317inlIsFormatInfo(FmtInfo info, Lib origin, AInt extfmt)
2318{
2319 return info->extfmt == extfmt && libEqual(origin, info->origin);
2320}
2321
2322/*
2323 * Create FoamBoxes for every format in a unit.
2324 */
2325localstatic FoamBox *
2326inlInitFormatBoxes(Foam formats)
2327{
2328 int i, size = foamArgc(formats)((formats)->hdr.argc);
2329 FoamBox *boxes;
2330
2331 boxes = (FoamBox *) stoAlloc(OB_Other0, size*sizeof(FoamBox *));
2332 for(i=0; i< size; i++)
2333 boxes[i] = fboxNew(formats->foamDFmt.argv[i]);
2334 return boxes;
2335}
2336
2337/*
2338 * Add a format to a function being inlined.
2339 */
2340localstatic int
2341inlAddFormat(Foam ddecl)
2342{
2343 return fboxAdd(inlUnit->formats, ddecl);
2344}
2345
2346/*
2347 * Create decls for all the formats added by inlining.
2348 */
2349localstatic void
2350inlMakeNewFormats(Foam unit)
2351{
2352 int i;
2353 for(i=0; i < foamArgc(inlUnit->formats->initial)((inlUnit->formats->initial)->hdr.argc); i++)
2354 inlUnit->formats->initial->foamDFmt.argv[i] =
2355 fboxMake(inlUnit->formatBoxes[i]);
2356 unit->foamUnit.formats = fboxMake(inlUnit->formats);
2357}
2358
2359/*
2360 * return a format number for a format from a prog being inlined.
2361 */
2362localstatic AInt
2363inlGetFormat(AInt format)
2364{
2365 if (inlInlineeIsLocal()(inlInlinee->origin == ((void*)0)))
2366 return format;
2367 else if (format == emptyFormatSlot4 || format == envUsedSlot0)
2368 return format;
2369 else
2370 return inlGetExternalFormat(inlInlinee->origin, format);
2371}
2372
2373/*
2374 * Compute a new format number for an external format. If it isn't
2375 * already in the new unit, add it.
2376 */
2377localstatic AInt
2378inlGetExternalFormat(Lib origin, AInt extfmt)
2379{
2380 FmtInfoList l;
2381 Foam ddecl, ddecl0;
2382 Hash hash, hash0;
2383 AInt locfmt;
2384 FmtInfo info;
2385
2386 ddecl = inlInlineeFormat(extfmt)inlInlinee->formats->foamDFmt.argv[extfmt];
2387 hash = foamHash(ddecl);
2388
2389 for (l = inlUnit->formatRefList; l; l = cdr(l)((l)->rest)) {
2390 if (inlIsFormatInfo(car(l)((l)->first), origin, extfmt))
2391 return car(l)((l)->first)->locfmt;
2392
2393 ddecl0 = car(l)((l)->first)->ddecl;
2394 hash0 = foamHash(ddecl0);
2395
2396 if (hash == hash0 && foamEqual(ddecl, ddecl0))
2397 return car(l)((l)->first)->locfmt;
2398 }
2399
2400 /* copy because source is a library, therefore it's shared */
2401 ddecl = foamCopy(ddecl);
2402 if (ddecl->foamDDecl.usage == FOAM_DDecl_LocalEnv)
2403 ddecl->foamDDecl.usage = FOAM_DDecl_NonLocalEnv;
2404
2405 assert(foamTag(ddecl) == FOAM_DDecl)do { if (!(((ddecl)->hdr.tag) == FOAM_DDecl)) _do_assert((
"foamTag(ddecl) == FOAM_DDecl"),"of_inlin.c",2405); } while (
0)
;
2406 foamFixed(ddecl)((ddecl)->hdr.info.fixed) = true1;
2407 locfmt = inlAddFormat(ddecl);
2408 info = inlNewFormatInfo(origin, extfmt, locfmt, hash, ddecl);
2409 listPush(FmtInfo, info, inlUnit->formatRefList)(inlUnit->formatRefList = (FmtInfo_listPointer->Cons)(info
, inlUnit->formatRefList))
;
2410
2411 /* A format can contain ref. to other formats in Rec decl.
2412 * Placed here to avoid infinite recursion if there is a loop
2413 * in the format definitions
2414 */
2415 inlUpdateDDecl(ddecl);
2416 return locfmt;
2417}
2418
2419/*
2420 * Get the syme from an index into a format.
2421 */
2422localstatic Syme
2423inlGetSyme(AInt format, AInt index)
2424{
2425 Syme syme = NULL((void*)0);
2426
2427 if (inlInlineeIsLocal()(inlInlinee->origin == ((void*)0))) {
2428 Foam ddecl;
2429 assert(format < inlUnit->formats->argc)do { if (!(format < inlUnit->formats->argc)) _do_assert
(("format < inlUnit->formats->argc"),"of_inlin.c",2429
); } while (0)
;
2430 ddecl = fboxNth(inlUnit->formats, format);
2431 assert(ddecl)do { if (!(ddecl)) _do_assert(("ddecl"),"of_inlin.c",2431); }
while (0)
;
2432 if (index < foamDDeclArgc(ddecl)(((ddecl)->hdr.argc) - (1)))
2433 syme = foamSyme(ddecl->foamDDecl.argv[index])((ddecl->foamDDecl.argv[index])->hdr.syme);
2434#if 0
2435 if (syme)
2436 fprintf(dbOut, "inlGetSyme: local syme from decl.\n");
2437#endif
2438 /*!! assert(syme == NULL); */
2439 }
2440 else
2441 syme = inlGetExternalSyme(inlInlinee->origin, format, index);
2442
2443 return syme;
2444}
2445
2446localstatic Syme
2447inlGetExternalSyme(Lib origin, AInt format, AInt index)
2448{
2449 return libGetFormatSyme(origin, format, index);
2450}
2451
2452/******************************************************************************
2453 *
2454 * :: inlIsForcer
2455 *
2456 *****************************************************************************/
2457
2458localstatic Bool
2459inlIsForcer(Foam foam)
2460{
2461 RuntimeCallInfo info;
2462 if (foamTag(foam)((foam)->hdr.tag) != FOAM_Glo)
2463 return false((int) 0);
2464 info = gen0GetRuntimeCallInfo(fboxNth(inlUnit->globals,
2465 foam->foamGlo.index));
2466 return rtCallIsForce(info)(info && ((info->flags) & (1 << 0)));
2467}
2468
2469/*****************************************************************************
2470 *
2471 * :: Foam Constants
2472 *
2473 ****************************************************************************/
2474
2475/*
2476 * Add a new constant to the unit. If it isn't already in the unit, add it.
2477 */
2478localstatic int
2479inlAddConst(int index)
2480{
2481 Lib origin = inlInlinee->origin;
2482 ConstInfoList l = inlUnit->constList;
2483 ConstInfo info;
2484 Foam code;
2485 int num;
2486
2487 for (; l; l = cdr(l)((l)->rest))
2488 if (index == car(l)((l)->first)->extConst &&
2489 libEqual(origin, car(l)((l)->first)->origin))
2490 return car(l)((l)->first)->locConst;
2491
2492 code = inlGetExternalConst(origin, index);
2493 info = (ConstInfo) stoAlloc(OB_Other0, sizeof(struct constInfo));
2494 num = inlUnit->constc++;
2495
2496 info->decl = foamCopy(inlInlineeDecl(constsSlot, index)inlInlinee->formats->foamDFmt.argv[1]->foamDDecl.argv
[index]
);
2497 info->def = foamNewDef(foamNewConst(num), code)foamNew(FOAM_Def, 2, foamNew(FOAM_Const, 1, (AInt)(num)), code
)
;
2498 info->origin = origin;
2499 info->extConst = index;
2500 info->locConst = num;
2501 inlUnit->constList = listCons(ConstInfo)(ConstInfo_listPointer->Cons)(info, inlUnit->constList);
2502 inlUpdateConstProg(code);
2503
2504 return num;
2505}
2506
2507/*
2508 * Create a new DDef section with all the new constants added by inlining.
2509 */
2510localstatic void
2511inlMakeNewConsts(Foam unit)
2512{
2513 int i, j, numNew;
2514 Foam new;
2515 ConstInfoList l;
2516 Foam constDDecl, defs;
2517
2518 if (inlUnit->constList == 0) return;
2519
2520 constDDecl = foamUnitConstants(unit)((((unit)->foamUnit.formats)->foamGen.argv)[1].code);
2521 defs = unit->foamUnit.defs;
2522
2523 inlUnit->constList = listNReverse(ConstInfo)(ConstInfo_listPointer->NReverse)(inlUnit->constList);
2524
2525 new = foamNewEmpty(FOAM_DDecl, inlUnit->constc + 1);
2526 new->foamDDecl.usage = FOAM_DDecl_Consts;
2527
2528 numNew = inlUnit->constc - foamDDeclArgc(constDDecl)(((constDDecl)->hdr.argc) - (1));
2529
2530 for(i=0; i<foamDDeclArgc(constDDecl)(((constDDecl)->hdr.argc) - (1)); i++)
2531 new->foamDDecl.argv[i] = constDDecl->foamDDecl.argv[i];
2532 for(l = inlUnit->constList; l; l = cdr(l)((l)->rest), i++)
2533 new->foamDDecl.argv[i] = car(l)((l)->first)->decl;
2534 foamUnitConstants(unit)((((unit)->foamUnit.formats)->foamGen.argv)[1].code) = new;
2535 foamFreeNode(constDDecl);
2536
2537 /* ensure non-const outer defs are last */
2538 new = foamNewEmpty(FOAM_DDef, foamArgc(defs)((defs)->hdr.argc) + numNew);
2539
2540 for (i=0;foamTag(defs->foamDDef.argv[i]->foamDef.lhs)((defs->foamDDef.argv[i]->foamDef.lhs)->hdr.tag)==FOAM_Const;i++)
2541 new->foamDDef.argv[i] = defs->foamDDef.argv[i];
2542 j=i;
2543 for(l = inlUnit->constList; l; l = cdr(l)((l)->rest), i++)
2544 new->foamDDef.argv[i] = car(l)((l)->first)->def;
2545 for ( ; j<foamArgc(defs)((defs)->hdr.argc); i++, j++)
2546 new->foamDDef.argv[i] = defs->foamDDef.argv[j];
2547
2548 unit->foamUnit.defs = new;
2549 foamFreeNode(defs);
2550
2551 listFree(ConstInfo)(ConstInfo_listPointer->Free)(inlUnit->constList);
2552}
2553
2554localstatic Foam
2555inlGetLocalConstInfo(int n)
2556{
2557 Foam code = NULL((void*)0);
2558 Foam prog;
2559 OptInfo info;
2560
2561 if (n < foamDDeclArgc(foamUnitConstants(inlUnit->unit))(((((((inlUnit->unit)->foamUnit.formats)->foamGen.argv
)[1].code))->hdr.argc) - (1))
)
2562 code = inlUnit->unit->foamUnit.defs->foamDDef.argv[n];
2563 else {
2564 ConstInfoList l = inlUnit->constList;
2565 for(; l && (code == 0); l = cdr(l)((l)->rest))
2566 if (n == car(l)((l)->first)->locConst)
2567 code = car(l)((l)->first)->def;
2568 if (code == 0) {
2569 inlRejectInfo = INL_REJ_LocalConstInfoFail4;
2570 return 0;
2571 }
2572 }
2573
2574 assert(foamTag(code) == FOAM_Def)do { if (!(((code)->hdr.tag) == FOAM_Def)) _do_assert(("foamTag(code) == FOAM_Def"
),"of_inlin.c",2574); } while (0)
;
2575 prog = code->foamDef.rhs;
2576 info = foamOptInfo(prog)((prog)->hdr.info.opt);
2577
2578 /* don't return the code if we are in the middle of inlining it. */
2579 assert(foamTag(prog) == FOAM_Prog)do { if (!(((prog)->hdr.tag) == FOAM_Prog)) _do_assert(("foamTag(prog) == FOAM_Prog"
),"of_inlin.c",2579); } while (0)
;
2580 if (info && info->inlState == INL_BeingInlined) return NULL((void*)0);
2581
2582 prog = inlProgram(prog, n);
2583
2584 prog = inlGetProgInfoFrProg(prog);
2585
2586 return prog;
2587}
2588
2589/*
2590 * Get the foam code for constant number n from the file we are inlining.
2591 */
2592localstatic Foam
2593inlGetLocalConst(AInt n)
2594{
2595 Foam code = NULL((void*)0);
2596 Foam prog;
2597 OptInfo info;
2598
2599 if (n < foamDDeclArgc(foamUnitConstants(inlUnit->unit))(((((((inlUnit->unit)->foamUnit.formats)->foamGen.argv
)[1].code))->hdr.argc) - (1))
)
2600 code = inlUnit->unit->foamUnit.defs->foamDDef.argv[n];
2601 else {
2602 ConstInfoList l = inlUnit->constList;
2603 for(; l && (code == 0); l = cdr(l)((l)->rest))
2604 if (n == car(l)((l)->first)->locConst)
2605 code = car(l)((l)->first)->def;
2606 if (code == 0) return 0;
2607 }
2608
2609 assert(foamTag(code) == FOAM_Def)do { if (!(((code)->hdr.tag) == FOAM_Def)) _do_assert(("foamTag(code) == FOAM_Def"
),"of_inlin.c",2609); } while (0)
;
2610 prog = code->foamDef.rhs;
2611 info = foamOptInfo(prog)((prog)->hdr.info.opt);
2612
2613 assert(foamTag(prog) == FOAM_Prog)do { if (!(((prog)->hdr.tag) == FOAM_Prog)) _do_assert(("foamTag(prog) == FOAM_Prog"
),"of_inlin.c",2613); } while (0)
;
2614
2615 /* don't return the code if we are in the middle of inlining it. */
2616 if (info->inlState != INL_Inlined)
2617 return NULL((void*)0);
2618 if (prog->foamProg.body == NULL((void*)0))
2619 return NULL((void*)0);
2620 return inlSetInlinee(NULL((void*)0), prog);
2621}
2622
2623/*
2624 * Get the environment levels of a local constant
2625 */
2626localstatic Foam
2627inlGetConstLevels(AInt n)
2628{
2629 Foam code = (Foam) NULL((void*)0), prog;
2630
2631 /*
2632 * External constants that have been recently localised
2633 * are stored separately from true local constants.
2634 */
2635 if (n >= foamDDeclArgc(foamUnitConstants(inlUnit->unit))(((((((inlUnit->unit)->foamUnit.formats)->foamGen.argv
)[1].code))->hdr.argc) - (1))
)
2636 {
2637 ConstInfoList l = inlUnit->constList;
2638 for(; l; l = cdr(l)((l)->rest))
2639 {
2640 ConstInfo info = car(l)((l)->first);
2641
2642 if (n == info->locConst)
2643 {
2644 code = info->def;
2645 break;
2646 }
2647 }
2648
2649 /* Hope that we never end up with NULL code */
2650 if (!code) return 0;
2651 }
2652 else
2653 code = inlUnit->unit->foamUnit.defs->foamDDef.argv[n];
2654
2655
2656 /* Extract the definition of the prog */
2657 assert(foamTag(code) == FOAM_Def)do { if (!(((code)->hdr.tag) == FOAM_Def)) _do_assert(("foamTag(code) == FOAM_Def"
),"of_inlin.c",2657); } while (0)
;
2658 prog = code->foamDef.rhs;
2659
2660
2661 /* Return the environment usage */
2662 assert(foamTag(prog) == FOAM_Prog)do { if (!(((prog)->hdr.tag) == FOAM_Prog)) _do_assert(("foamTag(prog) == FOAM_Prog"
),"of_inlin.c",2662); } while (0)
;
2663 return prog->foamProg.levels;
2664}
2665
2666
2667/*
2668 * Get the foam code for constant number n from an external library.
2669 */
2670localstatic Foam
2671inlGetExternalConst(Lib lib, AInt n)
2672{
2673 return inlSetInlinee(lib, libGetFoamConstant(lib, n));
2674}
2675
2676/*
2677 * update the body of a constant we are adding to the unit.
2678 */
2679localstatic void
2680inlUpdateConstProg(Foam prog)
2681{
2682 int i;
2683 AInt *levels;
2684 assert(foamTag(prog) == FOAM_Prog)do { if (!(((prog)->hdr.tag) == FOAM_Prog)) _do_assert(("foamTag(prog) == FOAM_Prog"
),"of_inlin.c",2684); } while (0)
;
2685 levels = prog->foamProg.levels->foamDEnv.argv;
2686 inlUpdateConstBody(prog->foamProg.body);
2687 foamOptInfo(prog)((prog)->hdr.info.opt) = optInfoNew0(NULL((void*)0), prog, NULL((void*)0), false((int) 0), true1);
2688
2689 inlUpdateDDecl(prog->foamProg.params);
2690 inlUpdateDDecl(prog->foamProg.locals);
2691
2692 for(i=0; i< foamArgc(prog->foamProg.levels)((prog->foamProg.levels)->hdr.argc); i++)
2693 levels[i] = inlGetFormat(levels[i]);
2694 if (prog->foamProg.retType == FOAM_NOp)
2695 prog->foamProg.format = inlGetFormat(prog->foamProg.format);
2696}
2697
2698/* Given a DDecl, remap all the format number for records */
2699localstatic void
2700inlUpdateDDecl(Foam ddecl)
2701{
2702 int i;
2703 Foam decl;
2704 Bool sigDecl = false((int) 0);
2705
2706 /* Function signatures are special */
2707 switch (ddecl->foamDDecl.usage) {
2708 case FOAM_DDecl_FortranSig: /*FALLTHROUGH*/
2709 case FOAM_DDecl_CSig: /*FALLTHROUGH*/
2710 case FOAM_DDecl_JavaSig: /*FALLTHROUGH*/
2711 sigDecl = true1;
2712 default:
2713 break;
2714 }
2715
2716 for(i=0; i< foamDDeclArgc(ddecl)(((ddecl)->hdr.argc) - (1)); i++) {
2717 decl = ddecl->foamDDecl.argv[i];
2718 if (decl->foamDecl.type == FOAM_Rec
2719 || decl->foamDecl.type == FOAM_TR
2720 || decl->foamDecl.type == FOAM_CObj
2721 || decl->foamDecl.type == FOAM_JavaObj)
2722 decl->foamDecl.format =
2723 inlGetFormat(decl->foamDecl.format);
2724 if (sigDecl && decl->foamDecl.type == FOAM_Clos)
2725 decl->foamDecl.format = inlGetFormat(decl->foamDecl.format);
2726 }
2727}
2728
2729/*
2730 * transform all the formats in the body of a constant we are adding to
2731 * the unit.
2732 */
2733localstatic void
2734inlUpdateConstBody(Foam body)
2735{
2736 FoamTag tag = foamTag (body)((body)->hdr.tag);
2737
2738 foamIter(body, arg, inlUpdateConstBody(*arg)){ { String argf = (foamInfoTable [(int)(((body)->hdr.tag))
-(int)FOAM_START]).argf; Length _i; for (_i = 0; _i < ((body
)->hdr.argc); _i++, argf++) { if (*argf == '*') argf--; if
(*argf == 'C') { Foam *arg = (Foam *) ((body)->foamGen.argv
)+_i; { inlUpdateConstBody(*arg); }; } } }; }
;
2739 switch(tag) {
2740 case FOAM_Const:
2741 body->foamConst.index = inlAddConst(body->foamConst.index);
2742 break;
2743 case FOAM_Glo:
2744 body->foamGlo.index = inlTransformGlobal(body);
2745 break;
2746 case FOAM_EElt:
2747 body->foamEElt.env = inlGetFormat(body->foamEElt.env);
2748 break;
2749 case FOAM_MFmt:
2750 body->foamMFmt.format = inlGetFormat(body->foamEElt.env);
2751 break;
2752 case FOAM_Rec:
2753 body->foamRec.format = inlGetFormat(body->foamRec.format);
2754 break;
2755 case FOAM_RElt:
2756 body->foamRElt.format = inlGetFormat(body->foamRElt.format);
2757 break;
2758 case FOAM_RNew:
2759 body->foamRNew.format = inlGetFormat(body->foamRNew.format);
2760 break;
2761 case FOAM_TRElt:
2762 body->foamTRElt.format = inlGetFormat(body->foamTRElt.format);
2763 break;
2764 case FOAM_IRElt:
2765 body->foamIRElt.format = inlGetFormat(body->foamIRElt.format);
2766 break;
2767 case FOAM_TRNew:
2768 body->foamTRNew.format = inlGetFormat(body->foamTRNew.format);
2769 break;
2770 case FOAM_PushEnv:
2771 body->foamPushEnv.format =
2772 inlGetFormat(body->foamPushEnv.format);
2773 break;
2774 default:
2775 break;
2776 }
2777}
2778
2779/*****************************************************************************
2780 *
2781 * :: Foam Code
2782 *
2783 ****************************************************************************/
2784
2785/*
2786 * Get the foam code to inline for a given syme.
2787 */
2788localstatic Foam
2789inlGetFoam(Syme syme)
2790{
2791 Foam code;
2792
2793 if (!inlIsConstProgSyme(syme))
2794 return NULL((void*)0);
2795
2796 if (symeIsLocalConst(syme)(symeConstLib(syme) == ((void*)0)))
2797 code = inlGetLocalFoam(syme);
2798 else
2799 code = inlGetExternalFoam(syme);
2800
2801 return code;
2802}
2803
2804/*
2805 * Get the foam code for a syme from the file we are inlining.
2806 */
2807localstatic Foam
2808inlGetLocalFoam(Syme syme)
2809{
2810 if (DEBUG(inline)inlineDebug) {
2811 fprintf(dbOut, "inlGetLocalFoam: ");
2812 symePrint(dbOut, syme);
2813 fnewline(dbOut);
2814 }
2815
2816 if (genHasConstNum(syme)) {
2817 int constNum = genGetConstNum(syme);
2818
2819 assert(constNum < inlUnit->constc)do { if (!(constNum < inlUnit->constc)) _do_assert(("constNum < inlUnit->constc"
),"of_inlin.c",2819); } while (0)
;
2820 return inlUnit->constv[constNum];
2821 }
2822 else {
2823 inlRejectInfo = INL_REJ_LocalFoamFail2;
2824 return NULL((void*)0);
2825 }
2826}
2827
2828/*
2829 * Get the foam code for a syme from an external file.
2830 */
2831localstatic Foam
2832inlGetExternalFoam(Syme syme)
2833{
2834 Foam ret;
2835 Lib origin = symeConstLib(syme);
2836
2837 inlineDEBUGif (!inlineDebug) { } else afprintf(dbOut, "(inlGetExternalFoam: %s (%s.%ld)",
2838 symeString(syme)((((syme)->id))->str), libGetFileId(origin),
2839 symeConstNum(syme)(((AInt) (SYFI_ConstInfo < (8 * sizeof(int)) && !(
((((syme)->kind == SYME_Trigger ? libGetAllSymes((syme)->
lib) : ((void*)0)), (syme))->hasmask) & (1 << (SYFI_ConstInfo
))) ? (symeFieldInfo[SYFI_ConstInfo].def) : (((((syme)->kind
== SYME_Trigger ? libGetAllSymes((syme)->lib) : ((void*)0
)), (syme))->locmask) & (1 << (SYFI_ConstInfo)))
? ((((((syme)->kind == SYME_Trigger ? libGetAllSymes((syme
)->lib) : ((void*)0)), (syme))->locmask) & (1 <<
(SYFI_ConstInfo))) ? ((syme)->fieldv)[symeIndex(syme,SYFI_ConstInfo
)] : (symeFieldInfo[SYFI_ConstInfo].def)) : symeGetFieldFn(syme
,SYFI_ConstInfo))) & 0xFFFF)
);
2840
2841 if (genHasConstNum(syme))
2842 ret = libGetFoamConstant(origin, genGetConstNum(syme));
2843 else
2844 ret = NULL((void*)0);
2845
2846 inlineDEBUGif (!inlineDebug) { } else afprintf(dbOut, "%s)\n", ret ? "OK" : "Fail");
2847
2848 return ret;
2849}
2850
2851localstatic InlProgInfo
2852inlGetProgInfoFrSyme(Syme syme)
2853{
2854 Foam code;
2855
2856 if (!syme)
2857 return NULL((void*)0);
2858
2859 if (!genHasConstNum(syme))
2860 return NULL((void*)0);
2861
2862 if (!inlIsConstProgSyme(syme))
2863 return NULL((void*)0);
2864
2865 if (symeIsLocalConst(syme)(symeConstLib(syme) == ((void*)0)))
2866 code = inlGetLocalFoam(syme);
2867 else
2868 code = inlGetExternalProgHdr(syme);
2869
2870 if (code && foamTag(code)((code)->hdr.tag) == FOAM_Prog)
2871 code = inlGetProgInfoFrProg(code);
2872 else
2873 code = NULL((void*)0);
2874
2875 return code;
2876}
2877
2878localstatic InlProgInfo
2879inlGetExternalProgHdr(Syme syme)
2880{
2881 Lib origin = symeConstLib(syme);
2882
2883 inlineDEBUGif (!inlineDebug) { } else afprintf(dbOut, "(inlGetExternalProgHdr: %s (%s.%ld)",
2884 symeString(syme)((((syme)->id))->str), libGetFileId(origin),
2885 symeConstNum(syme)(((AInt) (SYFI_ConstInfo < (8 * sizeof(int)) && !(
((((syme)->kind == SYME_Trigger ? libGetAllSymes((syme)->
lib) : ((void*)0)), (syme))->hasmask) & (1 << (SYFI_ConstInfo
))) ? (symeFieldInfo[SYFI_ConstInfo].def) : (((((syme)->kind
== SYME_Trigger ? libGetAllSymes((syme)->lib) : ((void*)0
)), (syme))->locmask) & (1 << (SYFI_ConstInfo)))
? ((((((syme)->kind == SYME_Trigger ? libGetAllSymes((syme
)->lib) : ((void*)0)), (syme))->locmask) & (1 <<
(SYFI_ConstInfo))) ? ((syme)->fieldv)[symeIndex(syme,SYFI_ConstInfo
)] : (symeFieldInfo[SYFI_ConstInfo].def)) : symeGetFieldFn(syme
,SYFI_ConstInfo))) & 0xFFFF)
);
2886
2887 /* !!Speedo fix to aviod inlining categories in libaxiom */
2888 if (strEqual(libGetFileId(origin), "axiom"))
2889 return NULL((void*)0);
2890
2891 if (genHasConstNum(syme)) {
2892 InlProgInfo res = libGetProgHdr(origin, genGetConstNum(syme));
2893 if (!res) inlRejectInfo = INL_REJ_ExternalProgHdrFail3;
2894 inlineDEBUGif (!inlineDebug) { } else afprintf(dbOut, "%s)\n", res ? "OK" : "Fail");
2895 return res;
2896 }
2897 else {
2898 inlineDEBUGif (!inlineDebug) { } else afprintf(dbOut, "Not const: Fail)\n");
2899 inlRejectInfo = INL_REJ_ExternalProgHdrFail3;
2900 return NULL((void*)0);
2901 }
2902}
2903
2904/*****************************************************************************
2905 *
2906 * :: Inlining Permission
2907 *
2908 ****************************************************************************/
2909
2910/* "limit" is the percentage limit; ex. 150 means 150%
2911 * "base" is the original value;
2912 * "value" is the new value; this function check if "value" is under
2913 * "(limit" * InlOverGrowthFactor)%
2914 * with respect to "base"
2915 */
2916localstatic Bool
2917inlIsUnderLimit(AInt base, AInt value, int limit)
2918{
2919 int overLimit = (int) ((double) limit * InlOverGrowthFactor1.4);
2920 return ((value * 100) / base) < overLimit;
2921
2922}
2923
2924/* $$ Think the possibility of using a new bit: DontInlineMe, that can be
2925 * generally used by #pragma DONT_INLINE.
2926 * Yeah, but we'd lose the fun naming convention.
2927 */
2928localstatic Bool inlIsEvilFlog(FlowGraph g);
2929localstatic Bool inlIsEvilSeq(Foam foam);
2930
2931Bool
2932inlIsEvil(Foam foam)
2933{
2934 if (foam->foamProg.body == NULL((void*)0)) {
2935 return inlIsEvilFlog(foamOptInfo(foam)((foam)->hdr.info.opt)->flog);
2936 }
2937 else {
2938 return inlIsEvilSeq(foam->foamProg.body);
2939 }
2940}
2941
2942localstatic Bool
2943inlIsEvilFlog(FlowGraph flog)
2944{
2945 flogIter(flog, bb, {{ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { if (inlIsEvilSeq(bb->code)) return 1;
}; }; } }; }
2946 if (inlIsEvilSeq(bb->code)){ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { if (inlIsEvilSeq(bb->code)) return 1;
}; }; } }; }
2947 return true;{ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { if (inlIsEvilSeq(bb->code)) return 1;
}; }; } }; }
2948 }){ { int _i; BBlock bb; for (_i = 0; _i < ((flog)->blocks
->pos); _i++) { bb = bbufBlockFn((flog)->blocks,_i); if
(!bb) continue; { { if (inlIsEvilSeq(bb->code)) return 1;
}; }; } }; }
;
2949 return false((int) 0);
2950}
2951
2952localstatic Bool
2953inlIsEvilSeq(Foam foam)
2954{
2955 int i, idx;
2956
2957 assert(foamTag(foam) == FOAM_Seq)do { if (!(((foam)->hdr.tag) == FOAM_Seq)) _do_assert(("foamTag(foam) == FOAM_Seq"
),"of_inlin.c",2957); } while (0)
;
2958 for (i=0; i<foamArgc(foam)((foam)->hdr.argc); i++) {
2959 Foam stmt = foam->foamSeq.argv[i];
2960 if (foamTag(stmt)((stmt)->hdr.tag) == FOAM_Return)
2961 stmt = stmt->foamReturn.value;
2962 if (foamTag(stmt)((stmt)->hdr.tag) == FOAM_Glo) {
2963 idx = inlTransformGlobal(stmt);
2964 if (idx == inlEvilGlobal)
2965 return true1;
2966 }
2967 }
2968 return false((int) 0);
2969}
2970
2971
2972/*
2973 * See if Syme is declared inlinable.
2974 */
2975Bool
2976inlInlinable(Stab stab, Syme syme)
2977{
2978 Bool result = inlInlinable0(stab, syme, true1);
2979
2980 if (!result) inlRejectInfo = INL_REJ_NoPermission6;
2981
2982 return result;
2983}
2984
2985/*
2986 * Inner inlinable checking function.
2987 */
2988localstatic Bool
2989inlInlinable0(Stab stab, Syme syme, Bool top)
2990{
2991 /* Anything goes with -Qinline-all */
2992 if (inlInlineAll) return true1;
2993
2994
2995 /* Okay, now check the syme a little more carefully */
2996 if ( top && !inlIsConstProgSyme(syme)) return false((int) 0);
2997 if (!top && !otIsConstSyme(syme)) return false((int) 0);
2998 if (symeIsLocalConst(syme)(symeConstLib(syme) == ((void*)0))) return true1;
2999
3000
3001 /* Looks okay but check outer scope levels */
3002 for (; stab; stab = cdr(stab)((stab)->rest))
3003 if (inlSymeIsInlinable(stab, syme)) {
3004 Bool result = true1;
3005 SymeList l;
3006
3007 /* Make sure all functions inlined are inlinable. */
3008 l = top ? symeInlined(syme) : listNil(Syme)((SymeList) 0);
3009 for (; l && result; l = cdr(l)((l)->rest))
3010 result = inlInlinable0(stab, car(l)((l)->first), false((int) 0));
3011
3012 return result;
3013 }
3014
3015 return false((int) 0);
3016}
3017
3018/*****************************************************************************
3019 *
3020 * :: inlSefoIsInlinable
3021 * :: inlSymeIsInlinable
3022 * :: inlTFormIsInlinable
3023 *
3024 ****************************************************************************/
3025
3026localstatic Bool
3027inlSefoIsInlinable(Stab stab, Sefo sefo)
3028{
3029 if (abIsLeaf(sefo)(((sefo)->abHdr.tag) < AB_NODE_START)) {
3030 if (abSyme(sefo)((sefo)->abHdr.seman ? (sefo)->abHdr.seman->syme : 0
)
)
3031 return inlSymeIsInlinable(stab,abSyme(sefo)((sefo)->abHdr.seman ? (sefo)->abHdr.seman->syme : 0
)
);
3032 }
3033 else if (abTag(sefo)((sefo)->abHdr.tag) == AB_Qualify)
3034 return inlSefoIsInlinable(stab, sefo->abQualify.origin);
3035
3036 else if (abTag(sefo)((sefo)->abHdr.tag) == AB_Apply)
3037 return inlSefoIsInlinable(stab, abApplyOp(sefo)((sefo)->abApply.op));
3038
3039 return false((int) 0);
3040}
3041
3042localstatic Bool
3043inlSymeIsInlinable(Stab stab, Syme syme)
3044{
3045 TFormUsesList tful;
3046
3047 if (symeExtension(syme))
3048 return inlSymeIsInlinable(stab, symeExtension(syme));
3049
3050 if ( (symeIsExport(syme)(((((syme)->kind == SYME_Trigger ? libGetAllSymes((syme)->
lib) : ((void*)0)), (syme))->kind) == SYME_Export)
|| symeIsExtend(syme)(((((syme)->kind == SYME_Trigger ? libGetAllSymes((syme)->
lib) : ((void*)0)), (syme))->kind) == SYME_Extend)
) &&
3051 symeLib(syme)((syme)->lib)) {
3052 Syme isyme = symeCopy(syme);
3053 TForm tf = tfLibrary(libLibrarySyme(symeLib(syme)((syme)->lib)));
3054 symeSetKind(isyme, SYME_Import)(((((isyme)->kind == SYME_Trigger ? libGetAllSymes((isyme)
->lib) : ((void*)0)), (isyme))->kind) = (SYME_Import))
;
3055 symeSetExporter(isyme, tf)(symeSetFieldVal = ((AInt) (tf)), (((((isyme)->kind == SYME_Trigger
? libGetAllSymes((isyme)->lib) : ((void*)0)), (isyme))->
locmask) & (1 << (SYFI_Exporter))) ? (((isyme)->
fieldv)[symeIndex(isyme,SYFI_Exporter)] = (symeSetFieldVal)) :
!((isyme)->full) && symeSetFieldVal == (symeFieldInfo
[SYFI_Exporter].def) ? symeSetFieldVal : symeSetFieldFn(isyme
,SYFI_Exporter,symeSetFieldVal))
;
3056 syme = isyme;
3057 }
3058
3059
3060 if (symeIsLocalConst(syme)(symeConstLib(syme) == ((void*)0)) && (symeIsExport(syme)(((((syme)->kind == SYME_Trigger ? libGetAllSymes((syme)->
lib) : ((void*)0)), (syme))->kind) == SYME_Export)
|| symeIsExtend(syme)(((((syme)->kind == SYME_Trigger ? libGetAllSymes((syme)->
lib) : ((void*)0)), (syme))->kind) == SYME_Extend)
))
3061 return true1;
3062 if (!symeIsImport(syme)(((((syme)->kind == SYME_Trigger ? libGetAllSymes((syme)->
lib) : ((void*)0)), (syme))->kind) == SYME_Import)
) return false((int) 0);
3063 for (tful = car(stab)((stab)->first)->tformsUsed.list; tful; tful = cdr(tful)((tful)->rest)) {
3064 TFormUses tfu = car(tful)((tful)->first);
3065
3066 if (tqHasImport(tfu->inlines, syme))
3067 return true1;
3068 }
3069
3070 if (inlTFormIsInlinable(stab, symeExporter(syme)))
3071 return true1;
3072
3073 return false((int) 0);
3074}
3075
3076localstatic Bool
3077inlTFormIsInlinable(Stab stab, TForm tf)
3078{
3079 tf = tfFollowSubst(tf);
3080
3081 if (tfIsArchive(tf))
3082 return false((int) 0);
3083 else if (tfIsGeneral(tf)(((tf)->tag) == TF_General))
3084 return inlSefoIsInlinable(stab, tfGetExpr(tf)((tf)->__absyn));
3085 else if (tfIsTuple(tf)(((tf)->tag) == TF_Tuple)
3086 || tfIsRecord(tf)(((tf)->tag) == TF_Record)
3087 || tfIsRawRecord(tf)(((tf)->tag) == TF_RawRecord)
3088 || tfIsUnion(tf)(((tf)->tag) == TF_Union)
3089 || tfIsEnum(tf)(((tf)->tag) == TF_Enumerate)
3090 || tfIsTrailingArray(tf)(((tf)->tag) == TF_TrailingArray)
3091 || tfIsGenerator(tf)(((tf)->tag) == TF_Generator))
3092 return inlSefoIsInlinable(stab, tfGetExpr(tf)((tf)->__absyn));
3093
3094 return false((int) 0);
3095}
3096
3097/*
3098 * Determine when we need temporary variables for parameters
3099 */
3100localstatic Bool
3101inlUseParam(Foam param, int count)
3102{
3103 /* true means don't make a local */
3104 if (count < 0) /* side effect on arg */
3105 return false((int) 0);
3106 if (otIsLocalVar(param)(((param)->hdr.tag) == FOAM_Loc || ((param)->hdr.tag) ==
FOAM_Par)
)
3107 return true1;
3108 if (otIsNonLocalVar(param)(((param)->hdr.tag) == FOAM_Lex || ((param)->hdr.tag) ==
FOAM_Glo)
)
3109 return false((int) 0);
3110 if (count > 1)
3111 return false((int) 0);
3112
3113 /*
3114 * Need to check what happens when we have a Cast for param.
3115 * If we strip the cast with foamDereferenceCast() then we
3116 * end up with bad foam sharing.
3117 */
3118 if (inlIsSideEffecting(param))
3119 return false((int) 0);
3120 else
3121 return true1;
3122}
3123
3124/*
3125 * Check whether a param is side-effecting.
3126 */
3127localstatic Bool
3128inlIsSideEffecting(Foam param)
3129{
3130 FoamTag tag;
3131 Foam op;
3132 InlProgInfo prog;
3133
3134 tag = foamTag(param)((param)->hdr.tag);
3135 switch (tag) {
3136 case FOAM_Set:
3137 return true1;
3138 case FOAM_PCall:
3139 return true1;
3140 case FOAM_OCall:
3141 op = param->foamOCall.op;
3142 break;
3143 case FOAM_CCall:
3144 op = param->foamCCall.op;
3145 break;
3146 case FOAM_BCall:
3147 return foamBValInfo(param->foamBCall.op)(foamBValInfoTable[(int)(param->foamBCall.op)-(int)FOAM_BVAL_START
])
.hasSideFx;
3148 default:
3149 return false((int) 0);
3150 }
3151 prog = inlGetProgInfoFrSyme(foamSyme(op)((op)->hdr.syme));
3152 if (!prog) return true1;
3153 return prog->foamProg.infoBits & IB_SIDE(1 << 0);
3154}
3155
3156localstatic Bool
3157inlIsConstProgSyme(Syme syme)
3158{
3159 if (otIsConstSyme(syme))
3160 return true1;
3161
3162 return otSymeIsFoamConst(syme);
3163}
3164
3165/*****************************************************************************
3166 *
3167 * :: Foam Inlining Transformations
3168 *
3169 ****************************************************************************/
3170
3171/*
3172 * Transform an expression for use in an inlined program. paramArg and
3173 * localArgv are vectors of values to use for paramters and locals.
3174 */
3175localstatic Foam
3176inlTransformExpr(Foam expr, Foam *paramArgv, Foam *localArgv)
3177{
3178 FoamTag tag = foamTag (expr)((expr)->hdr.tag);
3179 Foam nexpr = expr;
3180 static int serialNo = 0, depthNo = 0;
3181 int serialThis;
3182
3183 serialNo += 1;
3184 depthNo += 1;
3185 serialThis = serialNo;
3186 inlTransDEBUGif (!inlTransDebug) { } else afprintf(dbOut, "{inlTrans[%d][%d]\n",
3187 depthNo, serialThis);
3188
3189 /*
3190 * We miss out on some environment merging and inlining with
3191 * closures whose environment is (Env 0) and which are stored
3192 * in (Env 0). The inliner will always transform (Env 0) into
3193 * a locally created environment, creating cycles that prevent
3194 * subsequent emerging. This is particularly unfortunate if the
3195 * code part of the closure doesn't use its environment.
3196 *
3197 * Here we avoid the problem by leaving (Env 0) alone if the
3198 * closure doesn't access any outer environment levels.
3199 */
3200 if (tag == FOAM_Clos)
3201 {
3202 Foam env = expr->foamClos.env;
3203 Foam prog = expr->foamClos.prog;
3204 Bool isEnv = (foamTag(env)((env)->hdr.tag) == FOAM_Env);
3205 Bool isLocalEnv = (isEnv && !(env->foamEnv.level));
3206 Bool isConst = (foamTag(prog)((prog)->hdr.tag) == FOAM_Const);
3207
3208
3209 /* Want environment to be (Env 0) and prog to be const */
3210 if (isLocalEnv && isConst)
3211 {
3212 AInt i;
3213 Bool used;
3214 Foam denv;
3215 AInt cnum = prog->foamConst.index;
3216
3217
3218 /* Non-local constants need to be localised */
3219 if (!inlInlineeIsLocal()(inlInlinee->origin == ((void*)0)))
3220 {
3221 /* Suck across external constants */
3222 cnum = inlAddConst(cnum);
3223 prog->foamConst.index = cnum;
3224 }
3225
3226
3227 /* Get the environment levels of this constant */
3228 denv = inlGetConstLevels(cnum);
3229 assert(denv)do { if (!(denv)) _do_assert(("denv"),"of_inlin.c",3229); } while
(0)
;
3230
3231
3232 /* See if it might use its environment */
3233 used = false((int) 0);
3234 for (i = 1; i < foamArgc(denv)((denv)->hdr.argc); i++)
3235 {
3236 AInt fmt = denv->foamDEnv.argv[i];
3237
3238 /* Non-empty format means env used */
3239 if (fmt != emptyFormatSlot4)
3240 {
3241 used = true1;
3242 break;
3243 }
3244 }
3245
3246
3247 /*
3248 * If any of the outer environment levels are used
3249 * then we must transform the environment into the
3250 * local environment. Otherwise we leave it alone
3251 * because our environment will never be touched by
3252 * the code in this closure.
3253 */
3254 if (used) expr->foamClos.env = inlEnv(env);
3255
3256
3257 /* Transformation complete */
3258 return expr;
3259 }
3260
3261 /* Fall through and transform as before */
3262 }
3263
3264 if (foamTag(expr)((expr)->hdr.tag) == FOAM_EElt &&
3265 foamTag(expr->foamEElt.ref)((expr->foamEElt.ref)->hdr.tag) == FOAM_Env) {
3266 expr = foamNewLex(expr->foamEElt.level + expr->foamEElt.ref->foamEnv.level,foamNew(FOAM_Lex, 2, (AInt)(expr->foamEElt.level + expr->
foamEElt.ref->foamEnv.level), (AInt)(expr->foamEElt.lex
))
3267 expr->foamEElt.lex)foamNew(FOAM_Lex, 2, (AInt)(expr->foamEElt.level + expr->
foamEElt.ref->foamEnv.level), (AInt)(expr->foamEElt.lex
))
;
3268 tag = FOAM_Lex;
3269 }
3270
3271 /* Recursive depth-first transformation of the expression */
3272 foamIter(expr, arg, *arg = inlTransformExpr(*arg,paramArgv,localArgv)){ { 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 = inlTransformExpr(*arg,paramArgv,localArgv); };
} } }; }
;
3273
3274 switch(tag) {
3275 case FOAM_Par:
3276 nexpr = paramArgv[expr->foamPar.index];
3277 if (otIsLocalVar(nexpr)(((nexpr)->hdr.tag) == FOAM_Loc || ((nexpr)->hdr.tag) ==
FOAM_Par)
)
3278 nexpr = foamCopy(nexpr);
3279 break;
3280 case FOAM_Loc:
3281 nexpr->foamLoc.index =
3282 localArgv[expr->foamLoc.index]->foamLoc.index;
3283 break;
3284 case FOAM_Lex:
3285 nexpr = inlLex(expr);
3286 break;
3287 case FOAM_Env:
3288 nexpr = inlEnv(nexpr);
3289 break;
3290 case FOAM_Glo:
3291 expr->foamGlo.index = inlTransformGlobal(expr);
3292 break;
3293 case FOAM_Label:
3294 nexpr->foamLabel.label += inlProg->numLabels;
3295 break;
3296 case FOAM_If:
3297 nexpr->foamIf.label += inlProg->numLabels;
3298 break;
3299 case FOAM_Const:
3300 if (!inlInlineeIsLocal()(inlInlinee->origin == ((void*)0)))
3301 expr->foamConst.index =
3302 inlAddConst(expr->foamConst.index);
3303 break;
3304 case FOAM_Select: {
3305 int i;
3306 for(i=0; i< foamSelectArgc(nexpr)(((nexpr)->hdr.argc) - 1); i++)
3307 nexpr->foamSelect.argv[i] += inlProg->numLabels;
3308 break; }
3309 case FOAM_Goto:
3310 nexpr->foamGoto.label += inlProg->numLabels;
3311 break;
3312 case FOAM_GenerStep:
3313 nexpr->foamGenerStep.label += inlProg->numLabels;
3314 break;
3315 case FOAM_EElt:
3316 inlComputeEEltSyme(expr);
3317 expr->foamEElt.env = inlGetFormat(expr->foamEElt.env);
3318 break;
3319 case FOAM_Rec:
3320 expr->foamRec.format = inlGetFormat(expr->foamRec.format);
3321 break;
3322 case FOAM_RElt:
3323 expr->foamRElt.format = inlGetFormat(expr->foamRElt.format);
3324 break;
3325 case FOAM_IRElt:
3326 expr->foamIRElt.format = inlGetFormat(expr->foamIRElt.format);
3327 break;
3328 case FOAM_TRElt:
3329 expr->foamTRElt.format =
3330 inlGetFormat(expr->foamTRElt.format);
3331 break;
3332 case FOAM_RNew:
3333 expr->foamRNew.format = inlGetFormat(expr->foamRNew.format);
3334 break;
3335 case FOAM_TRNew:
3336 expr->foamTRNew.format =
3337 inlGetFormat(expr->foamTRNew.format);
3338 break;
3339 case FOAM_MFmt:
3340 expr->foamMFmt.format = inlGetFormat(expr->foamMFmt.format);
3341 break;
3342 case FOAM_PushEnv:
3343 expr->foamPushEnv.format =
3344 inlGetFormat(expr->foamPushEnv.format);
3345 break;
3346 case FOAM_Return:
3347 nexpr = inlReturn(expr);
3348 break;
3349 default:
3350 break;
3351 }
3352
3353 if (DEBUG(inlTrans)inlTransDebug) {
3354 fprintf(dbOut, "inlTrans: %d%d= ", depthNo, serialThis);
3355 foamPrint(dbOut, expr);
3356 fprintf(dbOut, "-->");
3357 foamPrint(dbOut, nexpr);
3358 fprintf(dbOut, "[%d][%d]Done}\n", depthNo, serialThis);
3359 }
3360
3361 return nexpr;
3362}
3363
3364/*
3365 * Transform sets of multiple values to a pile of sets to single values.
3366 */
3367localstatic Foam
3368inlSet(Foam set)
3369{
3370 Foam lhs = set->foamSet.lhs, rhs = set->foamSet.rhs;
3371 Foam iLhs, iRhs, newSet;
3372 int i;
3373 FoamTag tag;
3374
3375 if (foamTag(rhs)((rhs)->hdr.tag) == FOAM_MFmt)
3376 rhs = rhs->foamMFmt.value;
3377
3378 if (foamTag(rhs)((rhs)->hdr.tag) != FOAM_Values)
3379 return set;
3380
3381 assert(foamTag(lhs) == FOAM_Values)do { if (!(((lhs)->hdr.tag) == FOAM_Values)) _do_assert(("foamTag(lhs) == FOAM_Values"
),"of_inlin.c",3381); } while (0)
;
3382 assert(foamArgc(lhs) == foamArgc(rhs))do { if (!(((lhs)->hdr.argc) == ((rhs)->hdr.argc))) _do_assert
(("foamArgc(lhs) == foamArgc(rhs)"),"of_inlin.c",3382); } while
(0)
;
3383 assert(inlUniqueValues(lhs, rhs))do { if (!(inlUniqueValues(lhs, rhs))) _do_assert(("inlUniqueValues(lhs, rhs)"
),"of_inlin.c",3383); } while (0)
;
3384
3385 if (foamArgc(lhs)((lhs)->hdr.argc) == 0)
3386 return foamNewNOp()foamNew(FOAM_NOp, (int) 0);
3387 if (foamArgc(rhs)((rhs)->hdr.argc) == 0) {
3388 /* In the case where there are no RHS values, we
3389 probably had a function inlined which ended with a 'never'..
3390 in this case, just gob out a halt, and give up */
3391 inlAddStmt(foamNew(FOAM_BCall, 2,
3392 FOAM_BVal_Halt,
3393 foamNewSInt(FOAM_Halt_NeverReached)foamNew(FOAM_SInt, 1, (AInt)(FOAM_Halt_NeverReached))));
3394 return foamNewNOp()foamNew(FOAM_NOp, (int) 0);
3395 }
3396 tag = foamTag(set)((set)->hdr.tag);
3397
3398 for(i=0; i<foamArgc(lhs)((lhs)->hdr.argc)-1; i++) {
3399 iLhs = lhs->foamValues.argv[i];
3400 iRhs = rhs->foamValues.argv[i];
3401 inlAddStmt(foamNew(tag, 2, iLhs, iRhs));
3402 }
3403 iLhs = lhs->foamValues.argv[i];
3404 iRhs = rhs->foamValues.argv[i];
Value stored to 'iRhs' is never read
3405 newSet = foamNew(tag, 2, lhs->foamValues.argv[i],
3406 rhs->foamValues.argv[i]);
3407
3408 return inlInsertSeq(newSet);
3409}
3410
3411/*
3412 * Ensures that multi value sets have unique values on the left and right.
3413 */
3414Bool
3415inlUniqueValues(Foam lhs, Foam rhs)
3416{
3417 int i, j;
3418 for(i=0; i<foamArgc(lhs)((lhs)->hdr.argc); i++)
3419 for(j=0; j<foamArgc(rhs)((rhs)->hdr.argc); j++)
3420 if (i != j && foamEqual(lhs->foamValues.argv[i],
3421 rhs->foamValues.argv[j]))
3422 return false((int) 0);
3423 return true1;
3424}
3425
3426/*
3427 * Set information for generating code for returns.
3428 */
3429localstatic Foam
3430inlReturn(Foam ret)
3431{
3432 Foam rv = ret->foamReturn.value;
3433 Foam tv;
3434 FoamList lv;
3435 FoamTag type;
3436 int i;
3437 AInt fmt = emptyFormatSlot4;
3438
3439 /* If there is only one return statement, return the expression. */
3440 if (inlInlinee->returnCount == 1)
3441 inlInlinee->returnVals = listCons(Foam)(Foam_listPointer->Cons)(rv, listNil(Foam)((FoamList) 0));
3442
3443 else {
3444 /* 1st time: Generate temporaries to hold the results. */
3445 if (!inlInlinee->returnVals) {
3446 if (foamTag(rv)((rv)->hdr.tag) != FOAM_Values) {
3447 type = inlExprType(rv, &fmt);
3448 tv = inlAddLocal(type, fmt);
3449 lv = listCons(Foam)(Foam_listPointer->Cons)(tv, listNil(Foam)((FoamList) 0));
3450 }
3451 else {
3452 lv = listNil(Foam)((FoamList) 0);
3453 for (i = 0; i < foamArgc(rv)((rv)->hdr.argc); i++) {
3454 type = inlExprType(
3455 rv->foamValues.argv[i],
3456 &fmt);
3457 tv = inlAddLocal(type,
3458 fmt);
3459 lv = listCons(Foam)(Foam_listPointer->Cons)(tv, lv);
3460 }
3461 lv = listNReverse(Foam)(Foam_listPointer->NReverse)(lv);
3462 }
3463 inlInlinee->returnVals = lv;
3464 }
3465
3466 /* Each time: generate assignments to temporaries. */
3467 if (foamTag(rv)((rv)->hdr.tag) != FOAM_Values) {
3468 lv = inlInlinee->returnVals;
3469 inlAddStmt(foamNewDef(foamCopy(car(lv)), rv)foamNew(FOAM_Def, 2, foamCopy(((lv)->first)), rv));
3470 }
3471 else {
3472 lv = inlInlinee->returnVals;
3473 assert(listLength(Foam)(lv) == foamArgc(rv))do { if (!((Foam_listPointer->_Length)(lv) == ((rv)->hdr
.argc))) _do_assert(("listLength(Foam)(lv) == foamArgc(rv)"),
"of_inlin.c",3473); } while (0)
;
3474
3475 for (i = 0; i < foamArgc(rv)((rv)->hdr.argc); i++, lv = cdr(lv)((lv)->rest)) {
3476 inlAddStmt(foamNewDef(foamCopy(car(lv)),foamNew(FOAM_Def, 2, foamCopy(((lv)->first)), rv->foamValues
.argv[i])
3477 rv->foamValues.argv[i])foamNew(FOAM_Def, 2, foamCopy(((lv)->first)), rv->foamValues
.argv[i])
);
3478 }
3479
3480 }
3481 if (foamTag(rv)((rv)->hdr.tag) == FOAM_Clos &&
3482 foamTag(rv->foamClos.prog)((rv->foamClos.prog)->hdr.tag) == FOAM_Const)
3483 {
3484 foamSyme(rv)((rv)->hdr.syme) = inlInlinee->syme;
3485 }
3486 }
3487
3488 inlProg->prog->foamProg.size += 1;
3489 return foamNewGoto(inlInlinee->returnLabel)foamNew(FOAM_Goto, 1, (AInt)(inlInlinee->returnLabel));
3490}
3491
3492localstatic void
3493inlComputeEEltSyme(Foam eelt)
3494{
3495 int index = eelt->foamEElt.lex;
3496 int format = eelt->foamEElt.env;
3497 Syme syme, nsyme;
3498
3499 if (foamSyme(eelt)((eelt)->hdr.syme))
3500 syme = foamSyme(eelt)((eelt)->hdr.syme);
3501 else
3502 syme = inlGetSyme(format, index);
3503
3504 if (!syme) return;
3505
3506 nsyme = inlSubstitutedSyme(syme);
3507 if (nsyme) foamSyme(eelt)((eelt)->hdr.syme) = nsyme;
3508}
3509
3510localstatic Foam
3511inlLex(Foam lex)
3512{
3513 int level = lex->foamLex.level;
3514 int index = lex->foamLex.index;
3515 int format = inlInlinee->denv->foamDEnv.argv[level];
3516 Syme syme, nsyme;
3517
3518 if (foamSyme(lex)((lex)->hdr.syme))
3519 syme = foamSyme(lex)((lex)->hdr.syme);
3520 else
3521 syme = inlGetSyme(format, index);
3522
3523 nsyme = syme ? inlSubstitutedSyme(syme) : NULL((void*)0);
3524
3525 if (!inlInlinee->sameParent || level == 0)
3526 lex = inlFoamEnvElt(lex);
3527 else
3528 inlProg->denv->foamDEnv.argv[level] =
3529 inlInlinee->denv->foamDEnv.argv[level];
3530
3531 if (nsyme) foamSyme(lex)((lex)->hdr.syme) = nsyme;
3532
3533 return lex;
3534}
3535
3536/*
3537 * Transform a foamEnv.
3538 */
3539localstatic Foam
3540inlEnv(Foam env)
3541{
3542 int level = env->foamEnv.level;
3543
3544 if (inlInlinee->noLocalEnv)
3545 level--;
3546 assert(level >= 0)do { if (!(level >= 0)) _do_assert(("level >= 0"),"of_inlin.c"
,3546); } while (0)
;
3547
3548 if (level == 0) {
3549 env = foamCopy(inlInlinee->env);
3550 foamSyme(env)((env)->hdr.syme) = inlInlinee->syme;
3551 }
3552 else if (!inlInlinee->sameParent) {
3553 assert((int)level >= 0)do { if (!((int)level >= 0)) _do_assert(("(int)level >= 0"
),"of_inlin.c",3553); } while (0)
; /* bug 1168 */
3554 env = foamNewEEnv(level, foamCopy(inlInlinee->env))foamNew(FOAM_EEnv, 2, (AInt)(level), foamCopy(inlInlinee->
env))
;
3555 }
3556
3557 return env;
3558}
3559
3560/*
3561 * Transform a lexical reference into an environment reference
3562 */
3563localstatic Foam
3564inlFoamEnvElt(Foam lex)
3565{
3566 int format = 0;
3567 int level = lex->foamLex.level;
3568 int index = lex->foamLex.index;
3569 Foam newFoam;
3570
3571 format = inlGetFormat(inlInlinee->denv->foamDEnv.argv[level]);
3572
3573 if (inlInlinee->noLocalEnv)
3574 level--;
3575 assert(level >= 0)do { if (!(level >= 0)) _do_assert(("level >= 0"),"of_inlin.c"
,3575); } while (0)
;
3576
3577 if (foamTag(inlInlinee->env)((inlInlinee->env)->hdr.tag) == FOAM_Env)
3578 newFoam = foamNewLex(level + inlInlinee->env->foamEnv.level,foamNew(FOAM_Lex, 2, (AInt)(level + inlInlinee->env->foamEnv
.level), (AInt)(index))
3579 index)foamNew(FOAM_Lex, 2, (AInt)(level + inlInlinee->env->foamEnv
.level), (AInt)(index))
;
3580 else if (inlInlinee->parentEnv && level > 0)
3581 newFoam = foamNewEElt(format,foamNew(FOAM_EElt,4,(AInt)(format),foamCopy(inlInlinee->parentEnv
),(AInt)(level - 1),(AInt)(index))
3582 foamCopy(inlInlinee->parentEnv),foamNew(FOAM_EElt,4,(AInt)(format),foamCopy(inlInlinee->parentEnv
),(AInt)(level - 1),(AInt)(index))
3583 level - 1,foamNew(FOAM_EElt,4,(AInt)(format),foamCopy(inlInlinee->parentEnv
),(AInt)(level - 1),(AInt)(index))
3584 index)foamNew(FOAM_EElt,4,(AInt)(format),foamCopy(inlInlinee->parentEnv
),(AInt)(level - 1),(AInt)(index))
;
3585 else
3586 newFoam = foamNewEElt(format,foamNew(FOAM_EElt,4,(AInt)(format),foamCopy(inlInlinee->env
),(AInt)(level),(AInt)(index))
3587 foamCopy(inlInlinee->env),foamNew(FOAM_EElt,4,(AInt)(format),foamCopy(inlInlinee->env
),(AInt)(level),(AInt)(index))
3588 level,foamNew(FOAM_EElt,4,(AInt)(format),foamCopy(inlInlinee->env
),(AInt)(level),(AInt)(index))
3589 index)foamNew(FOAM_EElt,4,(AInt)(format),foamCopy(inlInlinee->env
),(AInt)(level),(AInt)(index))
;
3590 return newFoam;
3591}
3592
3593/*
3594 * Add a statement to the body of an inlined function.
3595 */
3596localstatic void
3597inlAddStmt(Foam stmt)
3598{
3599 if (DEBUG(inlProg)inlProgDebug) {
3600 if (inlConstTrace == inlProg->constNum ||
3601 inlConstTrace == -1) {
3602 fprintf(dbOut, "... adding statement ");
3603 foamPrint(dbOut, stmt);
3604 }
3605 }
3606 inlProg->seqBody = listCons(Foam)(Foam_listPointer->Cons)(stmt, inlProg->seqBody);
3607}
3608
3609/*
3610 * Add a label to the inlined function.
3611 */
3612localstatic int
3613inlAddLabel()
3614{
3615 return inlProg->newLabel++;
3616}
3617
3618/*
3619 * Add a local variable to a function being inlined. Will be a lex if
3620 * it needs to be.
3621 */
3622localstatic Foam
3623inlAddLocal(FoamTag type, int format)
3624{
3625 if (!inlProg->isGener) {
3626 return inlAddTempLocal(type, format);
3627 }
3628 else {
3629 int level = 2; /* level of iterator parent */
3630 int format = inlProg->denv->foamDEnv.argv[level];
3631 assert(format != emptyFormatSlot)do { if (!(format != 4)) _do_assert(("format != emptyFormatSlot"
),"of_inlin.c",3631); } while (0)
;
3632 assert(format != envUsedSlot)do { if (!(format != 0)) _do_assert(("format != envUsedSlot")
,"of_inlin.c",3632); } while (0)
;
3633 return foamNewLex(level, inlAddLex(type, format))foamNew(FOAM_Lex, 2, (AInt)(level), (AInt)(inlAddLex(type, format
)))
;
3634 }
3635}
3636
3637/*
3638 * Add a local variable to a function being inlined.
3639 */
3640localstatic Foam
3641inlAddTempLocal(FoamTag type, int format)
3642{
3643 int index = vpNewVar0(inlProg->locals, type, format);
3644 return foamNewLoc(index)foamNew(FOAM_Loc, 1, (AInt)(index));
3645}
3646
3647/*
3648 * Add a lexical variable to a function being inlined.
3649 */
3650localstatic int
3651inlAddLex(FoamTag type, int format)
3652{
3653 String name = strPrintf("%d", inlUnit->formatBoxes[format]->argc);
3654 Foam decl = foamNewDecl(type, name, emptyFormatSlot)foamNew(FOAM_Decl,4,(AInt)(type),name, (AInt) (0x7FFF), 4);
3655
3656 assert(format < inlUnit->formats->argc)do { if (!(format < inlUnit->formats->argc)) _do_assert
(("format < inlUnit->formats->argc"),"of_inlin.c",3656
); } while (0)
;
3657 assert(format > emptyFormatSlot)do { if (!(format > 4)) _do_assert(("format > emptyFormatSlot"
),"of_inlin.c",3657); } while (0)
;
3658 return fboxAdd(inlUnit->formatBoxes[format], decl);
3659}
3660
3661/*
3662 * make decls for all the locals in a prog being inlined.
3663 */
3664localstatic void
3665inlAddLocalDecls(Foam locals, Foam *localArgv)
3666{
3667 int i, format;
3668 Foam var;
3669 FoamTag type;
3670
3671 for(i= 0; i< foamDDeclArgc(locals)(((locals)->hdr.argc) - (1)); i++) {
3672 Foam decl = locals->foamDDecl.argv[i];
3673 inlGetTypeFrDecl(decl, &type, &format);
3674 var = inlAddTempLocal(type, format);
3675 localArgv[i] = var;
3676 }
3677}
3678
3679localstatic void
3680inlGetTypeFrDecl(Foam decl, FoamTag *ptype, int *pformat)
3681{
3682 FoamTag type = decl->foamDecl.type;
3683 int format = decl->foamDecl.format;
3684
3685 *ptype = type;
3686 if (type == FOAM_Rec || type == FOAM_Env || type == FOAM_TR)
3687 *pformat = inlGetFormat(format);
3688 else
3689 *pformat = format;
3690}
3691
3692
3693/*
3694 * return the Foam type of an arbitrary Foam expression.
3695 */
3696localstatic FoamTag
3697inlExprType(Foam expr, AInt *fmt)
3698{
3699 return foamExprTypeG0(expr, inlProg->prog,
3700 inlUnit->unit->foamUnit.formats,
3701 inlProg->locals->fbox,
3702 inlUnit->formats, inlUnit->globals,
3703 fmt);
3704}
3705
3706localstatic Foam
3707inlGetPushEnvFrVar(Foam env)
3708{
3709
3710 if (inlProg->converged)
3711 return inuGetPushEnvFrVar(env);
3712 else
3713 return NULL((void*)0);
3714}
3715
3716localstatic Foam
3717inlCanonEElt(Foam foam)
3718{ /* Strips EElts s.t. the index part is 0 */
3719 Foam env, next;
3720 int depth;
3721
3722 env = foam->foamEElt.ref;
3723 depth = foam->foamEElt.level;
3724
3725 while (depth > 0) {
3726 next = inlGetPushEnvFrVar(env);
3727 if (!next) break;
3728 assert(foamTag(next) == FOAM_PushEnv)do { if (!(((next)->hdr.tag) == FOAM_PushEnv)) _do_assert(
("foamTag(next) == FOAM_PushEnv"),"of_inlin.c",3728); } while
(0)
;
3729
3730 env = next->foamPushEnv.parent;
3731 depth--;
3732 }
3733
3734 if (foamTag(env)((env)->hdr.tag) == FOAM_Env) {
3735 depth = env->foamEnv.level+depth;
3736 assert(inlProg->denv->foamDEnv.argv[depth] == 0 ||do { if (!(inlProg->denv->foamDEnv.argv[depth] == 0 || inlProg
->denv->foamDEnv.argv[depth] == 4 || inlProg->denv->
foamDEnv.argv[depth] == foam->foamEElt.env)) _do_assert(("inlProg->denv->foamDEnv.argv[depth] == 0 || inlProg->denv->foamDEnv.argv[depth] == emptyFormatSlot || inlProg->denv->foamDEnv.argv[depth] == foam->foamEElt.env"
),"of_inlin.c",3738); } while (0)
3737 inlProg->denv->foamDEnv.argv[depth] == emptyFormatSlot ||do { if (!(inlProg->denv->foamDEnv.argv[depth] == 0 || inlProg
->denv->foamDEnv.argv[depth] == 4 || inlProg->denv->
foamDEnv.argv[depth] == foam->foamEElt.env)) _do_assert(("inlProg->denv->foamDEnv.argv[depth] == 0 || inlProg->denv->foamDEnv.argv[depth] == emptyFormatSlot || inlProg->denv->foamDEnv.argv[depth] == foam->foamEElt.env"
),"of_inlin.c",3738); } while (0)
3738 inlProg->denv->foamDEnv.argv[depth] == foam->foamEElt.env)do { if (!(inlProg->denv->foamDEnv.argv[depth] == 0 || inlProg
->denv->foamDEnv.argv[depth] == 4 || inlProg->denv->
foamDEnv.argv[depth] == foam->foamEElt.env)) _do_assert(("inlProg->denv->foamDEnv.argv[depth] == 0 || inlProg->denv->foamDEnv.argv[depth] == emptyFormatSlot || inlProg->denv->foamDEnv.argv[depth] == foam->foamEElt.env"
),"of_inlin.c",3738); } while (0)
;
3739 inlProg->denv->foamDEnv.argv[depth] = foam->foamEElt.env;
3740 next = foamNewLex(depth,foamNew(FOAM_Lex, 2, (AInt)(depth), (AInt)(foam->foamEElt.
lex))
3741 foam->foamEElt.lex)foamNew(FOAM_Lex, 2, (AInt)(depth), (AInt)(foam->foamEElt.
lex))
;
3742 }
3743 else if (env == foam->foamEElt.ref)
3744 return foam;
3745 else
3746 next = foamNewEElt(foam->foamEElt.env, foamCopy(env), depth,foamNew(FOAM_EElt,4,(AInt)(foam->foamEElt.env),foamCopy(env
),(AInt)(depth),(AInt)(foam->foamEElt.lex))
3747 foam->foamEElt.lex)foamNew(FOAM_EElt,4,(AInt)(foam->foamEElt.env),foamCopy(env
),(AInt)(depth),(AInt)(foam->foamEElt.lex))
;
3748
3749 foamSyme(next)((next)->hdr.syme) = foamSyme(foam)((foam)->hdr.syme);
3750 foam = next;
3751 inlProg->changed = true1;
3752 return foam;
3753}
3754
3755localstatic Foam
3756inlCanonEEnv(Foam foam)
3757{
3758 Foam env, next;
3759 int depth;
3760
3761 env = foam->foamEEnv.env;
3762 depth = foam->foamEEnv.level;
3763
3764 while (depth>0) {
3765
3766 next = inlGetPushEnvFrVar(env);
3767 if (!next) break;
3768 assert(foamTag(next) == FOAM_PushEnv)do { if (!(((next)->hdr.tag) == FOAM_PushEnv)) _do_assert(
("foamTag(next) == FOAM_PushEnv"),"of_inlin.c",3768); } while
(0)
;
3769
3770 env = next->foamPushEnv.parent;
3771 depth--;
3772 }
3773
3774 if (foamTag(env)((env)->hdr.tag) == FOAM_Env) {
3775 depth = env->foamEnv.level+depth;
3776 next = foamNewEnv(depth)foamNew(FOAM_Env, 1, (AInt)(depth));
3777 }
3778 else if (foamTag(env)((env)->hdr.tag) == FOAM_EEnv) {
3779 int level = depth + env->foamEEnv.level;
3780 assert(level >= 0)do { if (!(level >= 0)) _do_assert(("level >= 0"),"of_inlin.c"
,3780); } while (0)
; /* bug 1168 */
3781 next = foamNewEEnv(level, foamCopy(env->foamEEnv.env))foamNew(FOAM_EEnv, 2, (AInt)(level), foamCopy(env->foamEEnv
.env))
;
3782 }
3783 else if (env == foam->foamEEnv.env)
3784 return foam;
3785 else if (depth == 0)
3786 next = foamCopy(env);
3787 else {
3788 assert(depth >= 0)do { if (!(depth >= 0)) _do_assert(("depth >= 0"),"of_inlin.c"
,3788); } while (0)
; /* bug 1168 */
3789 next = foamNewEEnv(depth, foamCopy(env))foamNew(FOAM_EEnv, 2, (AInt)(depth), foamCopy(env));
3790 }
3791
3792 foamSyme(next)((next)->hdr.syme) = foamSyme(foam)((foam)->hdr.syme);
3793 foam = next;
3794 inlProg->changed = true1;
3795
3796 return foam;
3797}
3798
3799localstatic Foam
3800inlGetConstEnvFrClosVar(Foam op)
3801{
3802 if (inlProg->converged)
3803 return inuGetConstEnvFrClosVar(op);
3804 else
3805 return NULL((void*)0);
3806}
3807
3808/*
3809 * Get the environment of a variable in the value tracking table.
3810 */
3811localstatic Foam
3812inlGetVarTableEnv(Foam op, Foam cenv)
3813{
3814 Foam val, env;
3815
3816 val = inlGetConstEnvFrClosVar(op);
3817
3818 if (foamTag(op)((op)->hdr.tag) == FOAM_Clos)
3819 env = op->foamClos.env;
3820
3821 else if (val && (foamTag(val)((val)->hdr.tag) == FOAM_Loc || foamTag(val)((val)->hdr.tag) == FOAM_Lex))
3822 env = foamCopy(val);
3823
3824 else if (cenv)
3825 env = cenv;
3826
3827 else
3828 env = foamNewCEnv(foamCopy(op))foamNew(FOAM_CEnv, 1, foamCopy(op));
3829
3830 if (val) foamSyme(env)((env)->hdr.syme) = foamSyme(val)((val)->hdr.syme);
3831
3832 return env;
3833}
3834
3835/*****************************************************************************
3836 *
3837 * :: Syme substitution for paramter function inlining.
3838 *
3839 ****************************************************************************/
3840
3841/*
3842 * Substitute the type of a syme based on the exporter of the syme.
3843 */
3844localstatic Syme
3845inlSubstitutedSyme(Syme syme)
3846{
3847 TForm oldType, newType;
3848 TForm oldExporter, newExporter;
3849 Syme isyme, nsyme;
3850
3851 isyme = inlInlinee->syme;
3852
3853 if (isyme == NULL((void*)0))
3854 return NULL((void*)0);
3855
3856 if (!symeIsImport(isyme)(((((isyme)->kind == SYME_Trigger ? libGetAllSymes((isyme)
->lib) : ((void*)0)), (isyme))->kind) == SYME_Import)
)
3857 return syme;
3858
3859 if (symeIsExport(syme)(((((syme)->kind == SYME_Trigger ? libGetAllSymes((syme)->
lib) : ((void*)0)), (syme))->kind) == SYME_Export)
) {
3860 syme = inlSymeSubstSelf(syme, tfFollowFn(symeExporter(isyme)));
3861 if (!syme)
3862 return NULL((void*)0);
3863 }
3864
3865 if (inlInlinee->sigma == NULL((void*)0))
3866 inlInlinee->sigma =
3867 tfSatSubList(tfGetExpr(tfFollowFn(symeExporter(isyme)))((tfFollowFn(symeExporter(isyme)))->__absyn));
3868
3869 if (inlInlinee->sigma == absFail())
3870 return NULL((void*)0);
3871
3872 if (absIsEmpty(inlInlinee->sigma))
3873 return syme;
3874
3875 if (!symeIsImport(syme)(((((syme)->kind == SYME_Trigger ? libGetAllSymes((syme)->
lib) : ((void*)0)), (syme))->kind) == SYME_Import)
)
3876 return NULL((void*)0);
3877
3878 if (DEBUG(inlExport)inlExportDebug) {
3879 fprintf(dbOut, ">>inlSubstitutedSyme:\n");
3880 fprintf(dbOut, " syme:\n");
3881 symeType(syme);
3882 symePrint(dbOut, syme);
3883 fnewline(dbOut);
3884 fprintf(dbOut, " sigma:\n");
3885 absPrint(dbOut, inlInlinee->sigma);
3886 fnewline(dbOut);
3887 }
3888
3889 oldExporter = symeExporter(syme);
3890 /* Bail if we don't know where this came from */
3891 if (!oldExporter) return NULL((void*)0);
3892
3893 newExporter = tformSubst(inlInlinee->sigma, oldExporter);
3894 tfFollow(newExporter)((newExporter) = tfFollowFn(newExporter));
3895 tfHasSelf(newExporter)((newExporter)->hasSelf) = false((int) 0);
3896
3897 oldType = symeType(syme);
3898 newType = tformSubst(inlInlinee->sigma, oldType);
3899
3900 nsyme = tfHasDomImport(newExporter, symeId(syme)((syme)->id), newType);
3901
3902 if (DEBUG(inlExport)inlExportDebug) {
3903 fprintf(dbOut, "<<inlSubstitutedSyme:\n");
3904 fprintf(dbOut, " syme:\n");
3905 symePrint(dbOut, nsyme);
3906 fnewline(dbOut);
3907 }
3908
3909 return nsyme;
3910}
3911
3912localstatic Syme
3913inlSymeSubstSelf(Syme syme, TForm tfex)
3914{
3915 SymeList symes;
3916 Syme nsyme;
3917
3918 symes = symeListSubstSelf(stabFile(), tfex,
3919 listCons(Syme)(Syme_listPointer->Cons)(syme, listNil(Syme)((SymeList) 0)));
3920 nsyme = symes->first;
3921 nsyme = tfHasDomImport(tfex, symeId(nsyme)((nsyme)->id), symeType(nsyme));
3922
3923 return nsyme;
3924}
3925
3926/*
3927 * returns true when two denvs are exactly the same.
3928 * 0 => any format, hence not same.
3929 */
3930localstatic Bool
3931inlSameDEnv(Foam denv1, Foam denv2)
3932{
3933 int i;
3934 if (foamArgc(denv1)((denv1)->hdr.argc) != foamArgc(denv2)((denv2)->hdr.argc)) return false((int) 0);
3935 for(i=0; i<foamArgc(denv1)((denv1)->hdr.argc); i++) {
3936 if (denv1->foamDEnv.argv[i] !=
3937 denv2->foamDEnv.argv[i])
3938 return false((int) 0);
3939 if (denv1->foamDEnv.argv[i] == 0)
3940 return false((int) 0);
3941 }
3942 return true1;
3943}
3944
3945/******************************************************************************
3946 *
3947 * :: Always Inline Generators (-Wloops)
3948 *
3949 *****************************************************************************/
3950
3951void
3952inlSetGenerators()
3953{
3954 inlInlineGenerators = true1;
3955}
3956
3957/*****************************************************************************
3958 *
3959 * :: Debug Staff
3960 *
3961 ****************************************************************************/
3962
3963void
3964inlPrintRejectCause(String call)
3965{
3966 String str = ""; /* Quit warnings */
3967
3968 if (!inlCallInfoDebug(inlCallInfoDebug && (inlConstTrace == -1 || inlConstTrace
== inlProg->constNum))
) return;
3969
3970 if (inlConstTrace != -1 &&
3971 inlConstTrace != inlProg->constNum) return;
3972
3973 switch (inlRejectInfo) {
3974 case INL_REJ_Unknown0: str = "Unknown"; break;
3975 case INL_REJ_NotConstSyme1: str = "NotConstSyme"; break;
3976 case INL_REJ_LocalFoamFail2: str = "LocalFoamFail"; break;
3977 case INL_REJ_ExternalProgHdrFail3: str = "ExternalProgHdrFail"; break;
3978 case INL_REJ_LocalConstInfoFail4: str = "LocalConstInfoFail"; break;
3979 case INL_REJ_NotConstClosProg5: str = "NotConstClosProg"; break;
3980 case INL_REJ_NoPermission6: str = "NoPermission"; break;
3981 case INL_REJ_Getter7: str = "Getter"; break;
3982 case INL_REJ_Evil8: str = "Evil"; break;
3983 case INL_REJ_Fluids9: str = "Fluids"; break;
3984 case INL_REJ_OCalls10: str = "OCalls"; break;
3985 case INL_REJ_NoInlineInfo11: str = "NoInlineInfo"; break;
3986 case INL_REJ_DontInlineMe12: str = "DontInlineMe"; break;
3987 case INL_REJ_RecursiveCall13: str = "RecursiveCall"; break;
3988 case INL_REJ_LocalInConst014: str = "LocalCallInConst(0)"; break;
3989 default:
3990 bugWarning("Unknown rejection cause...");
3991 }
3992
3993 fprintf(dbOut, "****(uninlined: %s [%d]) Reason: %s ****\n",
3994 call, inlCallInfoSerial, str);
3995}
3996
3997
3998void
3999inlPrintUninlinedCalls(InlPriCall pric, PriQKey pri)
4000{
4001 PriQKey priority;
4002
4003 if (pric == NULL((void*)0)) return;
4004
4005 fprintf(dbOut, "(Over limit in prog: %d, originalSize = %d, limit = %d\n", inlProg->constNum, inlProg->originalSize, inlSizeLimit);
4006
4007 foamPrintDb(pric->call);
4008 fprintf(dbOut, "(priority = %f, size = %d)\n",
4009 pri, (int)pric->size);
4010
4011 inlPrintPriq();
4012 while (priqCount(inlProg->priq)((inlProg->priq)->argc)) {
4013 InlPriCall priCall = (InlPriCall) priqExtractMin(inlProg->priq, &priority);
4014
4015 foamPrintDb(priCall->call);
4016 fprintf(dbOut, "(priority = %f, size = %d)\n",
4017 priority, (int)priCall->size);
4018 if (foamTag(priCall->call)((priCall->call)->hdr.tag) == FOAM_CCall && foamSyme(priCall->call->foamCCall.op)((priCall->call->foamCCall.op)->hdr.syme) != NULL((void*)0)) {
4019 Syme syme = foamSyme(priCall->call->foamCCall.op)((priCall->call->foamCCall.op)->hdr.syme);
4020 afprintf(dbOut, "(syme.. %s %pTForm)\n", symeString(syme)((((syme)->id))->str), symeType(syme));
4021 }
4022 }
4023
4024 fprintf(dbOut, "limit end)\n");
4025}