1 /*
2  * Copyright (c) 1993-2019, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 /** \file
19  * \brief Expander utility routines
20  */
21 
22 #include "exputil.h"
23 #include "expreg.h"
24 #include "dinit.h"
25 #include "dinitutl.h"
26 #include "dtypeutl.h"
27 #include "llassem.h"
28 #include "ilm.h"
29 #include "ilmtp.h"
30 #include "fih.h"
31 #include "ili.h"
32 #include "iliutil.h"
33 #define EXPANDER_DECLARE_INTERNAL
34 #include "expand.h"
35 #include "machar.h"
36 #include "regutil.h"
37 #include "machreg.h"
38 #include "symfun.h"
39 
40 static void propagate_bihflags(void);
41 static void flsh_saveili(void);
42 
43 #define DO_PFO (XBIT(148, 0x1000) && !XBIT(148, 0x4000))
44 
45 #ifdef __cplusplus
getSptr_bnd_con(ISZ_T i)46 inline SPTR getSptr_bnd_con(ISZ_T i) {
47   return static_cast<SPTR>(get_bnd_con(i));
48 }
49 #else
50 #define getSptr_bnd_con get_bnd_con
51 #endif
52 
53 /** \brief Make an argument list
54  *
55  *  Create a compiler generated array temporary for an argument list.
56  *  its size is cnt and its dtype is dt.  NOTE that the caller may modify
57  *  the size of this array (a target may require alignment other than int).
58  *  mkarglist guarantees reuse as long as expb.arglcnt.next is reset
59  *  to expb.arglcnt.start.
60  */
61 void
mkarglist(int cnt,DTYPE dt)62 mkarglist(int cnt, DTYPE dt)
63 {
64 
65   DTYPE dtype;
66   ADSC *ad;
67   static INT ival[2];
68 
69   ival[1] = cnt;
70   expb.arglist = getccsym('a', expb.arglcnt.next++, ST_ARRAY);
71   dtype = DTYPEG(expb.arglist);
72   if (dtype) {
73     ad = AD_DPTR(dtype);
74     if (ival[1] > ad_val_of(AD_NUMELM(ad)))
75       AD_NUMELM(ad) = AD_UPBD(ad, 0) = getSptr_bnd_con(ival[1]);
76   } else {
77     SCP(expb.arglist, SC_AUTO);
78     STYPEP(expb.arglist, ST_ARRAY);
79     dtype = get_array_dtype(1, dt);
80     DTYPEP(expb.arglist, dtype);
81 
82     ad = AD_DPTR(dtype);
83     AD_MLPYR(ad, 0) = stb.i1;
84     AD_LWBD(ad, 0) = stb.i1;
85     AD_UPBD(ad, 0) = getSptr_bnd_con(ival[1]);
86     AD_NUMDIM(ad) = 1;
87     AD_SCHECK(ad) = 0;
88     AD_ZBASE(ad) = stb.i1;
89     AD_NUMELM(ad) = AD_UPBD(ad, 0); /* numelm must be set ater numdim */
90   }
91 
92   if (expb.arglcnt.max < expb.arglcnt.next)
93     expb.arglcnt.max = expb.arglcnt.next;
94 }
95 
96 /** \brief Create a block during expand
97  */
98 void
cr_block(void)99 cr_block(void)
100 {
101   expb.curbih = exp_addbih(expb.curbih);
102   BIH_LINENO(expb.curbih) = expb.curlin ? expb.curlin : gbl.lineno;
103   BIH_GUARDEE(expb.curbih) = expb.isguarded >= 1 ? 1 : 0;
104   expb.flags.bits.noblock = 0;
105   ILT_NEXT(0) = 0;
106   ILT_PREV(0) = 0;
107   if (expb.curlin && expb.flags.bits.dbgline) {
108     expb.curilt =
109         addilt(0, ad2ili(IL_QJSR, mkfunc("dbg_i_line"), ad1ili(IL_NULL, 0)));
110     ILT_DBGLINE(expb.curilt) = 1;
111   } else
112     expb.curilt = 0;
113   expb.curlin = 0;
114   if (EXPDBG(8, 32))
115     fprintf(gbl.dbgfil, "---cr_block: bih %d, ILM line %d\n", expb.curbih,
116             gbl.lineno);
117 }
118 
119 /** \brief Write a block during expand
120  */
121 void
wr_block(void)122 wr_block(void)
123 {
124   int iltx, opc = 0;
125 
126   if (EXPDBG(8, 64))
127     fprintf(gbl.dbgfil, "%6d ilm words in block %6d\n", expb.ilm_words,
128             expb.curbih);
129   expb.ilm_words = 0;
130   iltx = ILT_PREV(0);
131   if (iltx != 0)
132     opc = ILI_OPC(ILT_ILIP(iltx));
133   if (iltx == 0 || !ILT_BR(iltx) || (opc != IL_JMP && opc != IL_QSWITCH &&
134                                      opc != IL_JMPMK &&
135                                      opc != IL_JMPM))
136     BIH_FT(expb.curbih) = 1;
137 
138   propagate_bihflags();
139 
140   expb.flags.bits.callfg |= bihb.callfg;
141   wrilts(expb.curbih); /* wrilts zeros bihb.callfg & qjsrfg */
142 #ifdef BIH_ASM
143   bihb.gasm = 0;
144 #endif
145   if (EXPDBG(8, 32))
146     fprintf(gbl.dbgfil, "---wr_block: bih %d, ILM line %d\n", expb.curbih,
147             gbl.lineno);
148   expb.flags.bits.noblock = 1;
149 }
150 
151 static void
propagate_bihflags(void)152 propagate_bihflags(void)
153 {
154   /* Set of flags for which it's necessary to propagate from iltb
155    * to bihb to BIH because the write of an ilt may be deferred.
156    */
157   BIH_EX(expb.curbih) = bihb.callfg;
158   BIH_LDVOL(expb.curbih) = bihb.ldvol;
159   BIH_STVOL(expb.curbih) = bihb.stvol;
160   BIH_QJSR(expb.curbih) = bihb.qjsrfg;
161 #ifdef BIH_ASM
162   BIH_ASM(expb.curbih) = bihb.gasm;
163 #endif
164 
165   /*
166    * Set of flags where it's known that a block has been created
167    * because of the context implied by the flags.
168    */
169   BIH_PAR(expb.curbih) |= bihb.parfg;
170   BIH_CS(expb.curbih) |= bihb.csfg;
171   BIH_PARSECT(expb.curbih) |= bihb.parsectfg;
172   BIH_TASK(expb.curbih) |= bihb.taskfg;
173 }
174 
175 /** \brief Close current block and write out.
176  */
177 void
flsh_block(void)178 flsh_block(void)
179 {
180   flsh_saveili();
181   wr_block();
182 }
183 
184 /** \brief Put out expb.saveili if necesssary.
185  *
186  * May be an unadded ili if expb.flags.bits.waitlbl is set
187  */
188 static void
flsh_saveili(void)189 flsh_saveili(void)
190 {
191   int savefg;  /* save for the ilt call flag	 */
192   char ldvol;  /* save for the ilt ldvol flag	 */
193   char stvol;  /* save for the ilt stvol flag	 */
194   bool qjsrfg; /* save for the ilt qjsrfg flag	 */
195 
196   if (expb.flags.bits.waitlbl) {
197 
198     /*
199      * waiting for a label ilm; curilt will become the end of the current
200      * block if the opt level is not 1 -- i.e., the current block is
201      * written out and a new block is created.  And, the ilt for saveili
202      * becomes the first ilt of this block.  For opt level 1, an ilt for
203      * saveili is added to the current block
204      *
205      * NOTE:  this does not happen at opt=0 -- this flag is not set (see the
206      * end of this routine)
207      */
208 
209     expb.flags.bits.waitlbl = 0;
210     if (flg.opt != 1) {
211       if (EXPDBG(8, 32))
212         fprintf(gbl.dbgfil, "---flsh_saveili: wait end, curilt %d\n",
213                 expb.curilt);
214 
215       /* write out the block with curilt as its last ilt */
216 
217       wr_block();
218 
219       /*
220        * create a new block - saveili will be the first ilt of the new
221        * block
222        */
223       cr_block();
224     }
225     /* append the ilt to the current block  */
226 
227     if (EXPDBG(8, 32))
228       fprintf(gbl.dbgfil, "---flsh_saveili: wait add, curilt %d, saveili %d\n",
229               expb.curilt, expb.saveili);
230     savefg = iltb.callfg;
231     ldvol = iltb.ldvol;
232     stvol = iltb.stvol;
233     qjsrfg = iltb.qjsrfg;
234     iltb.callfg = 0;
235     iltb.ldvol = 0;
236     iltb.stvol = 0;
237     iltb.qjsrfg = false;
238     expb.curilt = addilt(expb.curilt, expb.saveili);
239     iltb.callfg = savefg;
240     iltb.ldvol = ldvol;
241     iltb.stvol = stvol;
242     iltb.qjsrfg = qjsrfg;
243   }
244 }
245 
246 /** \brief Check for end of ILT block
247  *
248  * Check if the current block is at its end. newili locates an
249  * ili tree which represents an ili statement.
250  */
251 void
chk_block(int newili)252 chk_block(int newili)
253 {
254   int ili;     /* ili of the current ilt	 */
255   ILI_OP opc;  /* ili opcode of the current ilt */
256   int c_noprs; /* # of operands for conditional branch */
257   int c_lb;    /* label of conditional branch  */
258   int u_lb;    /* label of unconditional branch */
259   int old_lastilt;
260 
261   if (newili == 0)
262     /* seems odd that newili is 0, but this can happen if one is adding
263      * a branch ili -- iliutil could change the branch into a nop.
264      * The caller could check the ili first -- there are many cases
265      * where we do -- but it's something that can be easily overlooked.
266      */
267     return;
268 
269   flsh_saveili(); /* write out saveili  if waitlbl is set. (see
270                    * below) */
271 
272   if (!ILT_BR(expb.curilt) && (flg.opt < 2 || !ILT_CAN_THROW(expb.curilt))) {
273 
274     /* The current end of the block is not a branch and [at -O2] cannot throw.
275      * Just create a new ilt and add it to the block.  Note that if the block
276      * is null (expb.curilt is zero), the flags of ilt 0 are zero.
277      */
278     if (EXPDBG(8, 32))
279       fprintf(gbl.dbgfil, "---chk_block: curilt %d not br, add newili %d\n",
280               expb.curilt, newili);
281     old_lastilt = expb.curilt;
282     expb.curilt = addilt(expb.curilt, newili);
283     /* addilt does not update BIH_ILTLAST().  We need to do it here: */
284     if (expb.curbih && BIH_ILTLAST(expb.curbih) == old_lastilt) {
285       BIH_ILTLAST(expb.curbih) = expb.curilt;
286     }
287     return;
288   }
289   /* the current end of the block is some sort of branch,
290      call that can throw, or store of result of a call
291      that can throw. */
292 
293   ili = ILT_ILIP(expb.curilt);
294   opc = ILI_OPC(ili);
295   if (opc == IL_JMP) {
296 
297     /*
298      * the current end of the block is an unconditional branch. newili is
299      * unreachable, don't add it
300      */
301     opc = ILI_OPC(newili);
302     if (IL_TYPE(opc) == ILTY_BRANCH &&
303         IL_OPRFLAG(opc, ilis[opc].oprs) == ILIO_SYM)
304       RFCNTD(ILI_OPND(newili, ilis[opc].oprs));
305     iltb.callfg = 0;
306     if (EXPDBG(8, 32))
307       fprintf(gbl.dbgfil, "---chk_block: newili %d not reached\n", newili);
308     return;
309   }
310   /* the current end of the block is a conditional branch,
311      or something that can throw. */
312 
313   if (ILI_OPC(newili) != IL_JMP || ILT_CAN_THROW(expb.curilt)) {
314 
315     /* the new ili is not an unconditional branch, or the new ili is
316        an IL_JMP just past a potential throw point. */
317 
318     if (flg.opt == 1 && !XBIT(137, 1) && !XBIT(163, 1))
319       /* create an extended basic block -- add a new ilt  */
320 
321       expb.curilt = addilt(expb.curilt, newili);
322     else {
323 
324       /*
325        * the current block is at its end; write it out, create a new
326        * block with its first ilt locating newili
327        */
328       wr_block();
329       cr_block();
330       expb.curilt = addilt(expb.curilt, newili);
331     }
332     if (EXPDBG(8, 32))
333       fprintf(gbl.dbgfil, "---chk_block: add newili %d\n", newili);
334     return;
335   }
336   /*
337    * the current end of the block is a conditional branch and the new ili
338    * is an unconditional branch
339    */
340   c_noprs = ilis[opc].oprs;
341   c_lb = ILI_OPND(ili, c_noprs);
342   u_lb = ILI_OPND(newili, 1);
343   if (opc != IL_JMPM &&
344       opc != IL_JMPA &&
345       opc != IL_JMPMK &&
346       u_lb == c_lb) {
347 
348     /*
349      * the labels are the same; search the current ilt and create new
350      * ilts for any procedures found.  These ilts are added before the
351      * current ilt
352      */
353     (void)reduce_ilt((int)ILT_PREV(expb.curilt), ili);
354 
355     /*
356      * the current ilt is changed to be the unconditional branch; the
357      * label's reference count is also decremented
358      */
359     if (EXPDBG(8, 32))
360       fprintf(gbl.dbgfil,
361               "---chk_block: uncond/cond, newili %d, to same label\n", newili);
362     ILT_ILIP(expb.curilt) = newili;
363     RFCNTD(ILI_OPND(newili, 1));
364     return;
365   }
366   /*
367    * the current end of the block is a conditional branch and the new ili
368    * is an unconditional branch whose labels are different. the checking of
369    * this block is delayed just in case a label ilm is processed before any
370    * other ilt producing ilms.  This is done to catch cases of the form:
371    *     if <cond> goto x;
372    *     goto y;
373    *  x: --- NOTE:  this does not happen at opt 0;
374    * the current block is written out (with previlt as the last ilt) and
375    * previlt becomes the first ilt of the new block.
376    */
377   if (flg.opt != 0) {
378     if (EXPDBG(8, 32))
379       fprintf(gbl.dbgfil,
380               "---chk_block: uncond/cond, newili %d, to diff label\n", newili);
381     if (opc != IL_JMPM &&
382         opc != IL_JMPA &&
383         opc != IL_JMPMK &&
384         ILIBLKG(c_lb) == 0 && ILIBLKG(u_lb)) {
385       /* conditional branch is a forward branch; unconditional branch
386        * is a backward branch
387        */
388       ILT_ILIP(expb.curilt) = compl_br(ili, u_lb);
389       newili = ad1ili(IL_JMP, c_lb);
390       if (EXPDBG(8, 32))
391         fprintf(gbl.dbgfil, "---chk_block: swap lbls %d %d, c_br %d, u_br %d\n",
392                 c_lb, u_lb, (int)ILT_ILIP(expb.curilt), newili);
393     }
394     expb.flags.bits.waitlbl = 1;
395     expb.saveili = newili;
396 
397   } else {
398     wr_block(); /* the current block		 */
399     cr_block();
400     expb.curilt = addilt(expb.curilt, newili);
401   }
402 }
403 
404 /** \brief Like chk_block, but suppress CAN_THROW flag.
405  *
406  * When a call can throw and defines two result registers, we have an ad-hoc
407  * rule that only the second store is marked as "can throw".  This utility
408  * is useful for ensuring that the first store is not marked "can throw".
409  */
410 void
chk_block_suppress_throw(int newili)411 chk_block_suppress_throw(int newili)
412 {
413   chk_block(newili);
414   ILT_SET_CAN_THROW(expb.curilt, 0);
415 }
416 
417 /** \brief Check an ILM which has been evaluated
418  *
419  * This routine checks an ILM which has already been evaluated
420  * (i.e., the ILM is referenced again).  Depending on the type
421  * of the ili which defines this ILM, certain actions may occur
422  * to "redefine" the ILM (i.e., create a new ILI for the ILM).
423  *
424  * \param ilmx -- ILM index of the ILM evaluated
425  * \param ilix -- ILI index of the ILI for the ILM
426  */
427 int
check_ilm(int ilmx,int ilix)428 check_ilm(int ilmx, int ilix)
429 {
430   int cse;    /* cse ILI                                */
431   SPTR sym;   /* symbol table index                     */
432   int base,   /* address ILI                            */
433       nme,    /* names entry                            */
434       blk,    /* bih index                              */
435       iltx;   /* ilt index                              */
436   ILI_OP opc; /* opcode of ilix                         */
437 
438   int saveilix = ilix;
439   switch (IL_TYPE(opc = ILI_OPC(ilix))) {
440 
441   case ILTY_CONS:
442     /* a constant ILI is okay to re-use  */
443     if (EXPDBG(8, 2))
444       fprintf(gbl.dbgfil, "check_ilm, ILM const: ilm %d, result ili %d\n", ilmx,
445               ilix);
446     return ilix;
447 
448   case ILTY_ARTH:
449   case ILTY_LOAD:
450   case ILTY_DEFINE:
451   case ILTY_MOVE:
452 /*
453  * these results represent an expression which may contain
454  * side-effect operations.  The new result is a CSE ILI of ilix
455  */
456     /* assertion: for fortran the only side-effects which may occur are
457      * those due to function calls;  however, there are cases where
458      * it's necessary that several ili statements "belong" to the
459      * statement.  To represent this, the sequence will begin with
460      * a pseudo store, followed by statements which have cse uses.
461      * For this case, the assertion (fortran-only) is that this
462      * will only occur for pseudo stores and stores.
463      */
464     cse = ilix;
465     if (EXPDBG(8, 2))
466       fprintf(gbl.dbgfil,
467               "check_ilm, ILM expr: ilm %d, old ili %d, cse ili %d\n", ilmx,
468               ilix, cse);
469     /*
470      * no longer have:
471      *   !BIH_QJSR(expb.curbih) &&
472      * leader block may not yet be created
473      */
474     if (!iltb.qjsrfg && qjsr_in(ilix)) {
475       iltb.qjsrfg = true;
476       if (EXPDBG(8, 2))
477         fprintf(gbl.dbgfil, "check_ilm - qjsr_in(%d)\n", ilix);
478     }
479     return cse;
480 
481   case ILTY_OTHER:
482 #ifdef ILTY_PSTORE
483   case ILTY_PSTORE:
484 #endif
485 #ifdef ILTY_PLOAD
486   case ILTY_PLOAD:
487 #endif
488     /* handle FREEIR... ili with ILTY_STORE */
489     if (!is_freeili_opcode(opc)) {
490       /* not a FREE ili */
491       return ilix;
492     }
493     goto like_store;
494 
495   case ILTY_STORE:
496 /*
497  * assertion: for fortran the only side-effects which may occur are
498  * those due to function calls;  however, there are cases where
499  * it's necessary that several ili statements "belong" to the
500  * statement.  To represent this, the sequence will begin with
501  * a pseudo store, followed by statements which have cse uses.
502  * For this case, the assertion (fortran-only) is that this
503  * will only occur for pseudo stores and stores.
504  */
505 
506   like_store:
507     /*** __OLDCSE ***/
508 
509     cse = ad_cse((int)ILI_OPND(ilix, 1));
510 
511     if ((blk = ILM_BLOCK(ilmx)) == expb.curbih) {
512       if (ILM_OPC((ILM *)(ilmb.ilm_base + ilmx)) == IM_PSEUDOST) {
513         /* We generate a pseudo store for postfix expressions.
514          * If the value prior to incrementing/decrementing is needed
515          * later by an arithmetic op, then we cannot safely CSE it.
516          * For example (from PH lang test): i++ != 2 ? 0 : i; In
517          * this case, a comparison followed by a branch needs the
518          * old value.
519          */
520         int len, opc2, i, found_use, found_arth;
521         int use = ILM_OPND((ILM *)(ilmb.ilm_base + ilmx), 2);
522         int ilmx2 = ilmx + ilms[IM_PSEUDOST].oprs + 1;
523         for (found_use = 0, found_arth = 0; ilmx2 < expb.nilms; ilmx2 += len) {
524           opc2 = ILM_OPC((ILM *)(ilmb.ilm_base + ilmx2));
525           len = ilms[opc2].oprs + 1;
526           if (IM_VAR(opc2))
527             len += ILM_OPND((ILM *)(ilmb.ilm_base + ilmx2), 1);
528           for (i = 1; i < len; ++i) {
529             if (IM_OPRFLAG(opc2, i) == OPR_LNK &&
530                 ILM_OPND((ILM *)(ilmb.ilm_base + ilmx2), i) == use) {
531               found_use = 1;
532             } else if (found_use && IM_OPRFLAG(opc2, i) == OPR_LNK &&
533                        ILM_OPND((ILM *)(ilmb.ilm_base + ilmx2), i) == ilmx) {
534               /* Convert the pseudo store to a real
535                * store on comparisons and other artimetics only.
536                */
537               if (IM_TYPE(opc2) != IMTY_ARTH) {
538                 found_arth = 0;
539                 goto break_out;
540               }
541               found_arth = 1;
542             }
543           }
544         }
545       break_out:
546         if (found_arth)
547           goto conv_pseudo_st;
548 
549       } /* end if (ILM_OPC(...) == IM_PSEUDOST) */
550 
551       /* reference is in the current block  */
552 
553       if (EXPDBG(8, 2))
554         fprintf(gbl.dbgfil,
555                 "check_ilm, store re-used: ilm %d, old ili %d, cse ili %d\n",
556                 ilmx, ilix, cse);
557       return cse;
558     } else {
559       /* The reference is in the current block if we jumped here
560        * from above (see the lines after "break_out:"), otherwise
561        * it's across block boundaries.
562        */
563       int save_iltb_callfg, save_iltb_ldvol, save_iltb_stvol;
564       bool save_iltb_qjsrfg;
565 
566     conv_pseudo_st:
567       /* JHM (8 Dec 2011) bug-fix:
568        * This is quite complicated so I'll explain the logic in
569        * full detail.  We're about to read in the ILTs of a
570        * block 'blk' (which may be 'expb.curbih' itself or a
571        * different block), then possibly add a new store ILT to
572        * it, then read in the ILTs of 'expb.curbih' again.
573        * Before doing this we must do the following:
574        *
575        * (1) Save the values of 'iltb.{x}', where {x} = {callfg,
576        * ldvol, stvol, qjsrfg}, to be restored later.
577        *
578        * (2) Set bihb.{x} |= iltb.{x}
579        *
580        * (3) Call 'propagate_bihflags()' to copy each bihb.{x}
581        * value to the corresponding BIH_{X}( expb.curbih ) field.
582        *
583        * Then at the end, after reading in 'expb.curbih's ILTs again:
584        *
585        * (4) Copy the saved values back to 'iltb.{x}'.
586        *
587        * Normally (2) would be performed by the next call to
588        * 'addilt()' and (3) by the next call to 'wr_block()'.
589        * However, because we call 'rdilts( blk )' and possibly
590        * add an ILT to 'blk', the above fields may be over-written
591        * before these actions can take place, as follows:
592        *
593        * -- 'rdilts( blk )' sets:
594        *    bihb.{x} = BIH_{X}( blk )
595        * thus (potentially) over-writing the current values of bihb.{x}.
596        *
597        * -- Then 'addilt()' (if it's called) sets:
598        *    bihb.{x} |= iltb.{x}
599        *    iltb.{x} = 0
600        * thus over-writing the current values of iltb.{x}.
601        *
602        * -- Finally 'rdilts( expb.curbih )' sets:
603        *    bihb.{x} = BIH_{X}( expb.curbih )
604        * which is only correct if BIH_{X}( expb.curbih ) contains
605        * the correct values, i.e. if actions (2) and (3) above
606        * have already been performed.
607        *
608        * By performing actions (2) and (3) we ensure that
609        * bihb.{x} and BIH_{X}( expb.curbih ) are correct at the
610        * end of this code, and (1) and (4) ensure that the
611        * current values are restored to 'iltb.{x}'.
612        */
613       bihb.callfg |= (save_iltb_callfg = iltb.callfg);
614       bihb.ldvol |= (save_iltb_ldvol = iltb.ldvol);
615       bihb.stvol |= (save_iltb_stvol = iltb.stvol);
616       bihb.qjsrfg |= (save_iltb_qjsrfg = iltb.qjsrfg);
617 
618       iltb.callfg = 0; /* ...it's used by 'addilt()' to set ILT_EX() */
619       propagate_bihflags();
620       fihb.currfindex = BIH_FINDEX(expb.curbih);
621       fihb.currftag = BIH_FTAG(expb.curbih);
622       wrilts(expb.curbih); /* write out the current block	and	 */
623       rdilts(blk);         /* read in the block of the store	 */
624 
625       sym = mkrtemp_sc(cse, expb.sc);
626       base = ad_acon(sym, (INT)0);
627       nme = addnme(NT_VAR, sym, 0, (INT)0);
628 
629       for (iltx = ILT_PREV(0); iltx != 0; iltx = ILT_PREV(iltx)) {
630         if (ILT_ILIP(iltx) == ilix) {
631           switch (opc) {
632           case IL_ST:
633             ilix = ad4ili(IL_ST, cse, base, nme, ILI_OPND(ilix, 4));
634             break;
635           case IL_FREEIR:
636             ilix = ad4ili(IL_ST, cse, base, nme, MSZ_WORD);
637             break;
638           case IL_STKR:
639             ilix = ad4ili(IL_STKR, cse, base, nme, ILI_OPND(ilix, 4));
640             break;
641           case IL_FREEKR:
642             ilix = ad4ili(IL_STKR, cse, base, nme, MSZ_I8);
643             break;
644           case IL_STA:
645           case IL_FREEAR:
646             ilix = ad3ili(IL_STA, cse, base, nme);
647             ILM_NME(ilmx) = addnme(NT_IND, SPTR_NULL, nme, (INT)0);
648             break;
649           case IL_STSP:
650           case IL_FREESP:
651             ilix = ad4ili(IL_STSP, cse, base, nme, MSZ_F4);
652             break;
653           case IL_STDP:
654           case IL_FREEDP:
655             ilix = ad4ili(IL_STDP, cse, base, nme, MSZ_F8);
656             break;
657           case IL_STSCMPLX:
658           case IL_FREECS:
659             ilix = ad4ili(IL_STSCMPLX, cse, base, nme, MSZ_F8);
660             break;
661           case IL_STDCMPLX:
662           case IL_FREECD:
663             ilix = ad4ili(IL_STDCMPLX, cse, base, nme, MSZ_F16);
664             break;
665 #ifdef LONG_DOUBLE_FLOAT128
666           case IL_FLOAT128ST:
667           case IL_FLOAT128FREE:
668             ilix = ad4ili(IL_FLOAT128ST, cse, base, nme, MSZ_F16);
669             break;
670 #endif /* LONG_DOUBLE_FLOAT128 */
671           default:
672             interr("check_ilm: illegal store", ilix, ERR_Severe);
673             goto wr_out;
674           }
675           ADDRCAND(ilix, nme);
676           iltx = addilt(iltx, ilix);
677           ilix = ad_load(ilix);
678           if (ilix) {
679             if (EXPDBG(8, 2))
680               fprintf(gbl.dbgfil,
681                       "check_ilm: store across block, ilm %d, ilt %d, ili %d\n",
682                       ilmx, iltx, ilix);
683             ADDRCAND(ilix, nme);
684           } else {
685             ilix = ILT_ILIP(iltx);
686             interr("check_ilm: illegal store1", ilix, ERR_Severe);
687           }
688           goto wr_out;
689         }
690       }
691 
692       /* no store found; just use cse as the result  */
693 
694       ilix = cse;
695       if (EXPDBG(8, 2))
696         fprintf(gbl.dbgfil,
697                 "check_ilm: store not found, ilm %d, ilt %d, ili %d\n", ilmx,
698                 iltx, ilix);
699 
700     wr_out:
701       wrilts(blk);         /* write out the modified block */
702       rdilts(expb.curbih); /* read back in the current block */
703 
704       iltb.callfg = save_iltb_callfg;
705       iltb.ldvol = save_iltb_ldvol;
706       iltb.stvol = save_iltb_stvol;
707       iltb.qjsrfg = save_iltb_qjsrfg;
708     }
709     return ilix;
710 
711   default:
712     if (EXPDBG(8, 2))
713       fprintf(gbl.dbgfil,
714               "check_ilm: bad reference, ilm %d(%s), ili %d, iliopc %d\n", ilmx,
715               ilms[ILM_OPC((ILM *)(ilmb.ilm_base + ilmx))].name, ilix, opc);
716     interr("check_ilm: bad reference", ilmx, ERR_Severe);
717   }
718 
719   return saveilix;
720 }
721 
722 /***************************************************************/
723 
724 #if defined(DINIT_FUNCCOUNT)
725 void
put_funccount(void)726 put_funccount(void)
727 {
728   dinit_put(DINIT_FUNCCOUNT, gbl.func_count);
729 } /* put_funccount */
730 #endif
731 
732 /** \brief Make a switch list for the intrinsic
733  *
734  * The switch list consists of the number of cases which occurred, the
735  * default label, and followed by the pairs (in sorted order based on
736  * case values) of case values and their respective case labels.
737  */
738 int
mk_swlist(INT n,SWEL * swhdr,int doinit)739 mk_swlist(INT n, SWEL *swhdr, int doinit)
740 {
741   SPTR sym;
742   int i;
743   SWEL *swel;
744   DTYPE dtype;
745 
746   sym = getccsym('J', expb.swtcnt++, ST_ARRAY); /* get switch array */
747   SCP(sym, SC_STATIC);
748   i = dtype = get_type(3, TY_ARRAY, DT_INT);
749   DTYPEP(sym, dtype);
750   DTySetArrayDesc(dtype, get_bnd_con(2 * (n + 1)));
751 
752   if (doinit) {
753     /* initialized this array with the switch list  */
754     DINITP(sym, 1);
755 
756 #if defined(DINIT_FUNCCOUNT)
757       put_funccount();
758 #endif
759     dinit_put(DINIT_LOC, sym);
760 
761     dinit_put(DT_INT, n); /* number of cases */
762     dinit_put(DINIT_LABEL, (INT)swhdr->clabel); /* default label   */
763     i = swhdr->next;
764     do {
765       swel = switch_base + i;
766       dinit_put(DT_INT, swel->val);              /* case value */
767       dinit_put(DINIT_LABEL, (INT)swel->clabel); /* case label */
768       i = swel->next;
769     } while (i != 0);
770   }
771 
772   return ad_acon(sym, 0);
773 }
774 
775 int
access_swtab_base_label(int base_label,int sptr,int flag)776 access_swtab_base_label(int base_label, int sptr, int flag)
777 {
778 
779   /* Store a list of jump table sptr's and their branch label. Used
780    * on the ST100 for the enhanced method 3 scheme.
781    * if flag == -2 then we are just access the routine's mode (GP16/GP32).
782    * if flag == -1 then we are just accessing the routine sptr
783    * If flag ==  1 then we are just accessing the value.
784    * If flag ==  0 then we are adding a new value.
785    * If flag ==  2 then we are also removing the record from the list.
786    * Returns 0 if not found, else branch_label_sptr.
787    */
788 
789   typedef struct swtab_branch_label {
790     int branch_label;
791     int sptr_swtab;
792     int sptr_routine;
793     int mode;
794     struct swtab_branch_label *next;
795   } swtab_branch_label;
796 
797   int branch_label_sptr = 0, mode = 0, routine_sptr = 0;
798 
799   static swtab_branch_label swtab_info = {0, 0, 0, 0, 0};
800 
801   swtab_branch_label *curr, *prev;
802 
803   if (flag != 0) {
804 
805     prev = &swtab_info;
806     for (curr = swtab_info.next; curr; curr = curr->next) {
807 
808       if (curr->sptr_swtab == sptr) {
809 
810         branch_label_sptr = curr->branch_label;
811         mode = curr->mode;
812         routine_sptr = curr->sptr_routine;
813         if (flag == 2) {
814           /* Remove record from list */
815           prev->next = curr->next;
816           FREE(curr);
817         }
818 
819         if (flag == -1) {
820           return routine_sptr;
821         } else if (flag == -2) {
822           return mode;
823         } else {
824           return branch_label_sptr;
825         }
826       }
827       prev = curr;
828     }
829 
830   } else {
831     NEW(curr, swtab_branch_label, sizeof(swtab_branch_label));
832     curr->branch_label = base_label;
833     curr->sptr_swtab = sptr;
834     curr->sptr_routine = gbl.currsub;
835     curr->mode = 0;
836     curr->next = swtab_info.next;
837     swtab_info.next = curr;
838     branch_label_sptr = base_label;
839   }
840 
841   return branch_label_sptr;
842 }
843 
844 int
access_swtab_case_label(int case_label,int * case_val,int sptr,int flag)845 access_swtab_case_label(int case_label, int *case_val, int sptr, int flag)
846 {
847   /* Store a list of jump table sptr's and their case labels. Used
848    * on the ST100 for the constant time method (an inline jump table).
849    * If flag == 1 then we are just accessing the value.
850    * If flag == 0 then we are adding a new value.
851    * If flag == 2 then we are also removing the record from the list.
852    * Returns 0 if not found, else case_label_sptr.
853    */
854 
855   typedef struct swtab_case_label {
856     int case_label;
857     int case_val;
858     int sptr_swtab;
859     struct swtab_case_label *next;
860   } swtab_case_label;
861 
862   int case_label_sptr = 0;
863 
864   static swtab_case_label swtab_info = {0, 0, 0, 0};
865 
866   swtab_case_label *curr, *prev;
867 
868   if (flag) {
869 
870     prev = &swtab_info;
871     for (curr = swtab_info.next; curr; curr = curr->next) {
872 
873       if (curr->sptr_swtab == sptr) {
874 
875         case_label_sptr = curr->case_label;
876         *case_val = curr->case_val;
877         if (flag == 2) {
878           /* Remove record from list */
879           prev->next = curr->next;
880           FREE(curr);
881         }
882         return case_label_sptr;
883       }
884       prev = curr;
885     }
886 
887   } else {
888     NEW(curr, swtab_case_label, sizeof(swtab_case_label));
889     curr->case_label = case_label;
890     curr->sptr_swtab = sptr;
891     curr->next = swtab_info.next;
892     curr->case_val = *case_val;
893     swtab_info.next = curr;
894     case_label_sptr = case_label;
895   }
896 
897   return case_label_sptr;
898 }
899 
900 
901 #define DINITSWTAB_put(c, s)
902 #define DINITSWTAB_put2(c, s, t)
903 
904 /** \brief Make a switch address table
905  */
906 int
mk_swtab(INT n,SWEL * swhdr,int deflab,int doinit)907 mk_swtab(INT n, SWEL *swhdr, int deflab, int doinit)
908 {
909   int sym;
910   int i;
911   INT case_val;
912   SWEL *swel;
913   DTYPE tabdtype = DT_CPTR;
914 
915   sym = getccsym('J', expb.swtcnt++, ST_PLIST); /* get switch array */
916   DTYPEP(sym, tabdtype);
917   SCP(sym, SC_STATIC);
918   PLLENP(sym, n);
919 
920   /* initialize this array with the switch table  */
921 
922   SWELP(sym, swhdr - switch_base);
923   DEFLABP(sym, deflab);
924   if (doinit) {
925 /*
926  * generate the entry for the default label.
927  */
928       DINITSWTAB_put(DINIT_LOC, sym);
929 
930     if (deflab) {
931       /*
932        * If the default label is passed, then it will not appear in the
933        * switch list.  Just make sure that swel locates the first case.
934        */
935       swel = swhdr;
936     } else {
937       /*
938        * Since the default label is not passed, then the switch list
939        * contains the default label.  Extract it and make sure that it
940        * gets added to the initialization of the switch array.
941        */
942       deflab = swhdr->clabel;
943       DINITSWTAB_put(DINIT_LABEL, (INT)deflab);
944       swel = switch_base + swhdr->next;
945     }
946 
947     case_val = swel->val; /* start with first case value */
948     do {
949       /*
950        * generate the remainder of the label table -- if there are
951        * holes, the default label is generated.  case_val denotes
952        * the expected case value.
953        */
954       for (case_val = swel->val - case_val; case_val; case_val--) {
955         DINITSWTAB_put(DINIT_LABEL, deflab); /* default */
956         RFCNTI((int)swhdr->clabel);
957 #if DEBUG
958         interr("mk_swtab: CGOTO has holes, swidx", swhdr - switch_base, ERR_Warning);
959 #endif
960       }
961       DINITSWTAB_put(DINIT_LABEL, (INT)swel->clabel); /* case label */
962       case_val = swel->val + 1;
963       i = swel->next;
964       swel = switch_base + i;
965     } while (i != 0);
966   }
967 
968   return sym;
969 }
970 
971 int
mk_swtab_ll(INT n,SWEL * swhdr,int deflab,int doinit)972 mk_swtab_ll(INT n, SWEL *swhdr, int deflab, int doinit)
973 {
974   int sym;
975   int i;
976   INT case_val[2];
977   SWEL *swel;
978   static INT one[2] = {0, 1};
979   static INT zero[2] = {0, 0};
980   INT vv[2];
981 
982   sym = getccsym('J', expb.swtcnt++, ST_PLIST); /* get switch array */
983   DTYPEP(sym, DT_INT8);
984   SCP(sym, SC_STATIC);
985   PLLENP(sym, n);
986 
987   /* initialize this array with the switch table  */
988 
989   SWELP(sym, swhdr - switch_base);
990   DEFLABP(sym, deflab);
991   if (doinit) {
992     DINITP(sym, 1);
993 /*
994  * generate the entry for the default label.
995  */
996       dinit_put(DINIT_LOC, sym);
997     if (deflab)
998       /*
999        * If the default label is passed, then it will not appear in the
1000        * switch list.  Just make sure that swel locates the first case.
1001        */
1002       swel = swhdr;
1003     else {
1004       /*
1005        * Since the default label is not passed, then the switch list
1006        * contains the default label.  Extract it and make sure that it
1007        * gets added to the initialization of the switch array.
1008        */
1009       deflab = swhdr->clabel;
1010       dinit_put(DINIT_LABEL, (INT)deflab);
1011       swel = switch_base + swhdr->next;
1012     }
1013     case_val[0] = CONVAL1G(swel->val); /* start with first case value */
1014     case_val[1] = CONVAL2G(swel->val);
1015     do {
1016       /*
1017        * generate the remainder of the label table -- if there are
1018        * holes, the default label is generated.  case_val denotes
1019        * the expected case value.
1020        */
1021       vv[0] = CONVAL1G(swel->val);
1022       vv[1] = CONVAL2G(swel->val);
1023       sub64(vv, case_val, case_val);
1024       /*for (case_val = swel->val - case_val; case_val; case_val--)*/
1025       while (true) {
1026         if (cmp64(case_val, zero) == 0)
1027           break;
1028         dinit_put(DINIT_LABEL, deflab); /* default */
1029         RFCNTI((int)swhdr->clabel);
1030 #if DEBUG
1031         interr("mk_swtab: CGOTO has holes, swidx", swhdr - switch_base, ERR_Warning);
1032 #endif
1033         sub64(case_val, one, case_val);
1034       }
1035       dinit_put(DINIT_LABEL, (INT)swel->clabel); /* case label */
1036       /*case_val = swel->val + 1;*/
1037       vv[0] = CONVAL1G(swel->val);
1038       vv[1] = CONVAL2G(swel->val);
1039       add64(vv, one, case_val);
1040       i = swel->next;
1041       swel = switch_base + i;
1042     } while (i != 0);
1043   }
1044 
1045   return sym;
1046 }
1047 
1048 /** \brief Make a sym for an arg's address
1049  */
1050 SPTR
mk_argasym(int sptr)1051 mk_argasym(int sptr)
1052 {
1053   SPTR asym;
1054   asym = getccsym('c', sptr, ST_VAR);
1055   IS_PROC_DESCRP(asym, IS_PROC_DESCRG(sptr));
1056   DESCARRAYP(asym, DESCARRAYG(sptr));
1057   CLASSP(asym, CLASSG(sptr));
1058   SDSCP(asym, SDSCG(sptr));
1059   if (gbl.internal == 1 && CLASSG(asym) && DESCARRAYG(asym)) {
1060     /* Do not set lscope on class arguments within host subroutines */
1061     LSCOPEP(asym, 0);
1062   }
1063   SCP(asym, SCG(sptr));
1064   DTYPEP(asym, DT_CPTR);
1065   REDUCP(asym, 1);     /* mark sym --> no further indirection */
1066   MIDNUMP(asym, sptr); /* link indirection temp to formal */
1067   QALNP(asym, QALNG(sptr));
1068   NOCONFLICTP(asym, 1);
1069   GSCOPEP(asym, GSCOPEG(sptr));
1070   if (INTERNREFG(sptr)) {
1071     INTERNREFP(asym, 1);
1072     ADDRESSP(asym, ADDRESSG(sptr));
1073     MEMARGP(asym, MEMARGG(sptr));
1074   }
1075   if (UPLEVELG(sptr)) {
1076     /* Currently in an internal procedure and the argument is from
1077      * the host; need to propagate a few flags to the indirection
1078      * temp.
1079      */
1080     UPLEVELP(asym, 1);
1081     ADDRESSP(asym, ADDRESSG(sptr));
1082     MEMARGP(asym, MEMARGG(sptr));
1083   }
1084   return asym;
1085 }
1086 
1087 /*
1088  * is there an indirection symbol for this dummy?
1089  */
1090 SPTR
find_argasym(int sptr)1091 find_argasym(int sptr)
1092 {
1093   char name[16];
1094   SPTR asym;
1095   sprintf(name, ".%c%04d", 'c', sptr);
1096   asym = lookupsym(name, strlen(name));
1097   if (asym && DTYPEG(asym) == DT_CPTR && MIDNUMG(asym) == sptr)
1098     return asym;
1099   return SPTR_NULL;
1100 } /* find_argasym */
1101 
1102 /***************************************************************/
1103 
1104 int
mk_impsym(SPTR sptr)1105 mk_impsym(SPTR sptr)
1106 {
1107   char bf[3 * MAXIDLEN + 10]; /* accommodate "__imp_" and possibly mod name
1108                                * as prefixes
1109                                */
1110   int impsym;
1111 
1112   switch (STYPEG(sptr)) {
1113   case ST_ENTRY:
1114   case ST_PROC:
1115     if (INMODULEG(sptr)) {
1116       sprintf(bf, "__imp_%s_%s", SYMNAME(INMODULEG(sptr)), SYMNAME(sptr));
1117       break;
1118     }
1119   /*****  else FALLTHRU  *****/
1120   default:
1121 #if defined(PGFTN) && defined(TARGET_WIN_X8664)
1122     sprintf(bf, "__imp_%s", getsname2(sptr));
1123 #else
1124     sprintf(bf, "__imp_%s", getsname(sptr));
1125 #endif
1126   }
1127 
1128   impsym = getsymbol(bf);
1129 
1130   if (SCG(impsym) == SC_NONE) {
1131     STYPEP(impsym, ST_VAR);
1132     SCP(impsym, SC_EXTERN);
1133     DTYPEP(impsym, __POINT_T);
1134   }
1135   return impsym;
1136 }
1137 
1138 /***************************************************************/
1139 
1140 SPTR
mkfunc_cncall(const char * nmptr)1141 mkfunc_cncall(const char *nmptr)
1142 {
1143   SPTR sptr;
1144   sptr = mkfunc(nmptr);
1145   CNCALLP(sptr, 1);
1146   return sptr;
1147 }
1148 
1149 /***************************************************************/
1150 
1151 static const char *
skipws(const char * q)1152 skipws(const char *q)
1153 {
1154   while (*q <= ' ' && *q != '\0')
1155     ++q;
1156   return q;
1157 }
1158 
1159 SPTR
mkfunc_sflags(const char * nmptr,const char * flags)1160 mkfunc_sflags(const char *nmptr, const char *flags)
1161 {
1162   SPTR sptr;
1163   const char *p;
1164   sptr = mkfunc(nmptr);
1165   p = flags;
1166   while (true) {
1167     p = skipws(p);
1168     if (*p == '\0')
1169       break;
1170     if (strncmp(p, "cncall", 6) == 0) {
1171       CNCALLP(sptr, 1);
1172       p += 6;
1173     } else if (strncmp(p, "xmmsafe", 7) == 0) {
1174       if (!XBIT(7, 0x4000))
1175         XMMSAFEP(sptr, 1);
1176       p += 7;
1177     }
1178 #if DEBUG
1179     else {
1180       interr("mkfunc_sflags(): urecognized flag", sptr, ERR_Severe);
1181       break;
1182     }
1183 #endif
1184   }
1185   return sptr;
1186 }
1187 
1188 void
exp_add_copy(SPTR lhssptr,SPTR rhssptr)1189 exp_add_copy(SPTR lhssptr, SPTR rhssptr)
1190 {
1191   int rhsacon, lhsacon, rhsnme, lhsnme, rhsld, lhsst, sz;
1192   ILI_OP rhsopc, lhsopc;
1193   MSZ msz;
1194   if (lhssptr == rhssptr)
1195     return;
1196   rhsacon = ad_acon(rhssptr, 0);
1197   sz = size_of(DTYPEG(rhssptr));
1198   if (sz == 8) {
1199     rhsopc = IL_LDKR;
1200     lhsopc = IL_STKR;
1201     msz = MSZ_I8;
1202   } else if (sz == 4) {
1203     rhsopc = IL_LD;
1204     lhsopc = IL_ST;
1205     msz = MSZ_WORD;
1206   } else if (sz == 2) {
1207     rhsopc = IL_LD;
1208     lhsopc = IL_ST;
1209     msz = MSZ_SHWORD;
1210   } else if (sz == 1) {
1211     rhsopc = IL_LD;
1212     lhsopc = IL_ST;
1213     msz = MSZ_BYTE;
1214   }
1215   rhsnme = addnme(NT_VAR, rhssptr, 0, 0);
1216   rhsld = ad3ili(rhsopc, rhsacon, rhsnme, msz);
1217   lhsacon = ad_acon(lhssptr, 0);
1218   lhsnme = addnme(NT_VAR, lhssptr, 0, 0);
1219   lhsst = ad4ili(lhsopc, rhsld, lhsacon, lhsnme, msz);
1220   chk_block(lhsst);
1221 }
1222 
1223 SPTR
get_byval_local(int argsptr)1224 get_byval_local(int argsptr)
1225 {
1226   char *new_name;
1227   SPTR newsptr;
1228   int new_length;
1229 
1230   newsptr = MIDNUMG(argsptr);
1231   if (newsptr > SPTR_NULL)
1232     return newsptr;
1233   new_name = SYMNAME(argsptr);
1234   new_name += 3; /* move past appended _V_ */
1235   new_length = strlen(new_name);
1236   newsptr = getsymbol(new_name);
1237   for (; newsptr; newsptr = HASHLKG(newsptr)) {
1238     if (strncmp(new_name, SYMNAME(newsptr), new_length) != 0 ||
1239         *(SYMNAME(newsptr) + new_length) != '\0')
1240       continue;
1241     if (STYPEG(newsptr) == STYPEG(argsptr)) {
1242       if (SCG(newsptr) == SC_LOCAL)
1243         return newsptr;
1244     }
1245   }
1246   newsptr = getsymbol(new_name); /* OH OH -- ICE */
1247   return newsptr;
1248 }
1249 
1250 /** \brief Add a register argument
1251  *
1252  * Add argument expression argili to existing argument list, arglist,
1253  * using registers. If arglist = 0, begin a new list.
1254  */
1255 int
add_reg_arg_ili(int arglist,int argili,int nmex,DTYPE dtype)1256 add_reg_arg_ili(int arglist, int argili, int nmex, DTYPE dtype)
1257 {
1258   int rg, ilix;
1259   ILI_OP opc;
1260   static int avail_ireg; /* next available integer register for jsr */
1261   static int avail_freg; /* next available floating point register for jsr */
1262 
1263   if (arglist == 0) {
1264     arglist = ad1ili(IL_NULL, 0);
1265     avail_ireg = 0;
1266     avail_freg = 0;
1267   }
1268   if (DTY(dtype) == TY_PTR) {
1269     rg = IR(avail_ireg++);
1270     opc = IL_DAAR;
1271   } else if (DT_ISINT(dtype)) {
1272     rg = IR(avail_ireg++);
1273     opc = IL_RES(ILI_OPC(argili)) != ILIA_KR ? IL_DAIR : IL_DAKR;
1274   } else {
1275     if (DTY(dtype) == TY_DBLE && (avail_freg & 1))
1276       avail_freg++;
1277     rg = SP(avail_freg);
1278     avail_freg++;
1279     if (DTY(dtype) == TY_DBLE) {
1280       opc = IL_DADP;
1281       avail_freg++;
1282     } else {
1283       opc = IL_DASP;
1284     }
1285   }
1286 
1287   ilix = ad3ili(opc, argili, rg, arglist);
1288   return ilix;
1289 } /* add_reg_arg_ili */
1290 
1291 #if DEBUG
1292 void
expdumpilms()1293 expdumpilms()
1294 {
1295   int i, bsize;
1296   ilmb.ilm_base[BOS_SIZE - 1] = ilmb.ilmavl;
1297   if (gbl.dbgfil == NULL)
1298     gbl.dbgfil = stderr;
1299 
1300   if (ilmb.ilm_base[0] != IM_BOS) {
1301     fprintf(gbl.dbgfil, "expdumpilms: no IM_BOS (ilm_base[0]==%d)\n", ilmb.ilm_base[0]);
1302   }
1303 
1304   fprintf(gbl.dbgfil, "\n----- lineno: %d"
1305                       " ----- global ILM index %d:%d"
1306                       "\n",
1307           ilmb.ilm_base[1] , ilmb.globalilmstart, ilmb.globalilmcount
1308           );
1309   bsize = ilmb.ilm_base[BOS_SIZE - 1]; /* number of words in this ILM block */
1310 
1311   i = 0;
1312   do { /* loop once for each ILM opcode: */
1313     int _dumponeilm(ILM_T *, int, int check);
1314     int j = i;
1315     i = _dumponeilm(ilmb.ilm_base, i, 0);
1316     if (ILM_RESULT(j))
1317       fprintf(gbl.dbgfil, "  result:%d", ILM_RESULT(j));
1318     if (ILM_IRESULT(j))
1319       fprintf(gbl.dbgfil, "  iresult/clen:%d", ILM_IRESULT(j));
1320     if (ILM_RESTYPE(j))
1321       fprintf(gbl.dbgfil, "  restype:%d", ILM_RESTYPE(j));
1322     if (ILM_NME(j))
1323       fprintf(gbl.dbgfil, "  nme:%d", ILM_NME(j));
1324     if (ILM_BLOCK(j))
1325       fprintf(gbl.dbgfil, "  block:%d", ILM_BLOCK(j));
1326     if (ILM_SCALE(j))
1327       fprintf(gbl.dbgfil, "  scale:%d", ILM_SCALE(j));
1328     if (ILM_MXLEN(j))
1329       fprintf(gbl.dbgfil, "  mxlen/clen:%d", ILM_MXLEN(j));
1330     if (ILM_EXPANDED_FOR(j))
1331       fprintf(gbl.dbgfil, "  expanded_for:%d", ILM_EXPANDED_FOR(j));
1332 
1333     fprintf(gbl.dbgfil, "\n");
1334     if (i > bsize) {
1335       fprintf(gbl.dbgfil, "BAD BLOCK LENGTH: %d\n", bsize);
1336     }
1337   } while (i < bsize);
1338 } /* expdumpilms */
1339 #endif
1340