Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – tendra.SVN – Blame – /branches/tendra4/src/installers/common/construct/const.c – Rev 2

Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
2
    		 Crown Copyright (c) 1997
3
 
4
    This TenDRA(r) Computer Program is subject to Copyright
5
    owned by the United Kingdom Secretary of State for Defence
6
    acting through the Defence Evaluation and Research Agency
7
    (DERA).  It is made available to Recipients with a
8
    royalty-free licence for its use, reproduction, transfer
9
    to other parties and amendment for any purpose not excluding
10
    product development provided that any such use et cetera
11
    shall be deemed to be acceptance of the following conditions:-
12
 
13
        (1) Its Recipients shall ensure that this Notice is
14
        reproduced upon any copies or amended versions of it;
15
 
16
        (2) Any amended version of it shall be clearly marked to
17
        show both the nature of and the organisation responsible
18
        for the relevant amendment or amendments;
19
 
20
        (3) Its onward transfer from a recipient to another
21
        party shall be deemed to be that party's acceptance of
22
        these conditions;
23
 
24
        (4) DERA gives no warranty or assurance as to its
25
        quality or suitability for any purpose and DERA accepts
26
        no liability whatsoever in relation to any use to which
27
        it may be put.
28
*/
29
 
30
 
31
/**********************************************************************
32
$Author: pwe $
33
$Date: 1998/03/11 11:03:21 $
34
$Revision: 1.3 $
35
$Log: const.c,v $
36
 * Revision 1.3  1998/03/11  11:03:21  pwe
37
 * DWARF optimisation info
38
 *
39
 * Revision 1.2  1998/01/29  16:59:07  pwe
40
 * hold2
41
 *
42
 * Revision 1.1.1.1  1998/01/17  15:55:46  release
43
 * First version to be checked into rolling release.
44
 *
45
 * Revision 1.5  1998/01/09  09:28:40  pwe
46
 * prep restructure
47
 *
48
 * Revision 1.4  1997/10/10  18:15:21  pwe
49
 * prep ANDF-DE revision
50
 *
51
 * Revision 1.3  1996/11/04  15:15:13  currie
52
 * no err-jumps in const extraction
53
 *
54
Revision 1.2  1995/08/15 08:25:29  currie
55
Shift left + trap_tag
56
 
57
 * Revision 1.1  1995/04/06  10:44:05  currie
58
 * Initial revision
59
 *
60
***********************************************************************/
61
 
62
 
63
 
64
 
65
/************************************************************************
66
 *                         const.c
67
 *  This file defines the routines which implement the TDF-to-TDF
68
 *  optimising transformation which removes constant expressions from
69
 *  program fragments (typically loops).
70
 *
71
 *  The type maxconst returns information about the expression under
72
 *  consideration. The field self is true if the expression as a whole is
73
 *  constant within the program fragment under consideration. If the
74
 *  entire expression is not constant (self is false) then the field cont
75
 *  is a list of the sub-expressions which are constant within the
76
 *  specified region.
77
 *
78
 *  The type maxconst is defined in consttypes.h
79
 *
80
 *  The principal procedures defined here are mc_list, repeat_consts and
81
 *  return_repeats. They are described below.
82
 *
83
 *  Also used externally is intnl_to.
84
 *
85
 ************************************************************************/
86
 
87
#include "config.h"
88
#include "common_types.h"
89
#include "consttypes.h"
90
#include "constmacs.h"
91
#include "tags.h"
92
#include "expmacs.h"
93
#include "exp.h"
94
#include "check.h"
95
#include "install_fns.h"
96
#include "shapemacs.h"
97
#include "check_id.h"
98
#include "flags.h"
99
#include "externs.h"
100
#include "installglob.h"
101
#include "is_worth.h"
102
#include "flpt.h"
103
#include "flpttypes.h"
104
#include "xalloc.h"
105
#include "messages_c.h"
106
#include "basicread.h"
107
#include "me_fns.h"
108
#ifdef NEWDIAGS
109
#include "dg_aux.h"
110
#endif
111
 
112
#include "const.h"
113
 
114
/* MACROS */
115
 
116
#define false 0
117
#define true  1
118
#define MAXUSE 16
119
#define VERYBIGUSAGE 100
120
#define MEMINC 64
121
#define nilmem ((memlist *)0)
122
 
123
/* IDENTITIES */
124
 
125
static maxconst self_const = {
126
  true, nilexp
127
},
128
/* the entire expression is constant */
129
    no_consts = {
130
  false, nilexp
131
};
132
/* no part of the expression is constant */
133
 
134
/* VARIABLES */
135
/* All variables initialised */
136
 
137
typedef struct _memlist {
138
  exp dec;
139
  int res;
140
  struct _memlist *next;
141
}   memlist;
142
 
143
		/* no need to init mem and fmem */
144
static memlist *mem = nilmem,	/* current list of frequent identifiers */
145
   *fmem = nilmem;		/* list of free cells */
146
 
147
static prop cond_flag = 0;	/* pushed value */
148
/* 1 => inside cond(..);  2 => after test() in cond() */
149
 
150
static int arg_is_reff;		/* no init needed */
151
/* arg is reffield, so contents doesn't need guarding */
152
 
153
#define globmax 100
154
static int glob_index;
155
static exp glob_dest[globmax];
156
 
157
static int has_lj_dest;
158
 
159
 
160
/* PROCEDURES */
161
 
162
exp get_repeats PROTO_S ((void));
163
 
164
static int find_glob
165
    PROTO_N ( (e) )
166
    PROTO_T ( exp e )
167
{
168
  int i;
169
  for ( i = 0; i < glob_index; i++)
170
    if (glob_dest[i] == e)
171
      return 1;
172
  return 0;
173
}
174
 
175
/************************************************************************
176
 *  ret_constlist returns the elements of a constants-list
177
 ************************************************************************/
178
 
179
void ret_constlist
180
    PROTO_N ( (head) )
181
    PROTO_T ( exp head )
182
{
183
  if (head != nilexp) {
184
    exp limit = pt (head), t = son (head), n;
185
    retcell (head);
186
    while (t != limit) {
187
      n = bro (t);
188
      retcell (t);
189
      t = n;
190
    }
191
    retcell (t);
192
  }
193
  return;
194
}
195
 
196
static maxconst max_const PROTO_S ( ( exp, exp, int ) ) ;
197
/* declaration - max_const and mc_list are mutually recursive */
198
 
199
 
200
 
201
/************************************************************************
202
 *  mc_list examines a list of expressions, and for each of them
203
 *  extracts the largest expressions which are constant within the
204
 *  region of interest.
205
 *
206
 *  Parameters:
207
 *        whole   the program region under consideration
208
 *        e       the first expression in the list. Expressions are
209
 *                linked via the brother field.
210
 *        ass_ok  all assignments in this region are to simple unaliassed
211
 *                variables
212
 *        good    if this is true AND all the expressions in the list are
213
 *                constant then the value self_const is returned.
214
 ************************************************************************/
215
 
216
static maxconst mc_list
217
    PROTO_N ( (whole, e, ass_ok, good) )
218
    PROTO_T ( exp whole X exp e X int ass_ok X int good )
219
{
220
  exp t = e;
221
  int contin = true;
222
  maxconst mc, result;
223
 
224
  result.self = good;
225
  result.cont = nilexp;
226
 
227
  do {
228
    /* NB - t may be killed within max_const (offset_mult) */
229
    /* so remember next one in list */
230
    exp next_t = bro (t);
231
    if (last (t))
232
      contin = false;
233
    mc = max_const (whole, t, ass_ok);
234
 
235
    if (mc.self) {
236
      /* the whole of t is constant */
237
      /* make a list element */
238
      exp w = getexp (f_bottom, nilexp, false, t, nilexp, cond_flag,
239
		       0, 0);
240
      if (result.cont == nilexp)/* first item - start a list */
241
	result.cont = getexp (f_bottom, nilexp, false, w, w, 0,  0, 0);
242
      else {			/* add this to list */
243
	bro (pt (result.cont)) = w;
244
	pt (result.cont) = w;
245
      }
246
    } else {
247
      result.self = false;	/* some part of e is not constant */
248
      if (mc.cont != nilexp) {	/* but t has constants in it */
249
	if (result.cont != nilexp) {	/* add them to list */
250
	  bro (pt (result.cont)) = son (mc.cont);
251
	  pt (result.cont) = pt (mc.cont);
252
	  retcell (mc.cont);
253
	} else			/* list was empty - start list */
254
	  result.cont = mc.cont;
255
      }
256
    }
257
 
258
    t = next_t;
259
  }
260
  while (contin);
261
 
262
  if (result.self) {
263
    ret_constlist (result.cont);
264
    return (self_const);
265
  }
266
  return result;
267
}
268
 
269
 
270
/************************************************************************
271
 *  intnl_to returns true if part is contained in whole
272
 ************************************************************************/
273
 
274
int intnl_to
275
    PROTO_N ( (whole, part) )
276
    PROTO_T ( exp whole X exp part )
277
{
278
  exp q = part;
279
 
280
  while (q != whole && q != nilexp && name(q) != hold_tag
281
		&& name(q) != hold2_tag &&
282
	 (name (q) != ident_tag || !isglob (q)))
283
    q = father (q);
284
 
285
  return q == whole;
286
}
287
 
288
/* heavily used idents are kept in lookup list */
289
 
290
static int not_assigned_to PROTO_S ( ( exp, exp ) ) ;
291
 
292
static int not_ass2
293
    PROTO_N ( (vardec, piece) )
294
    PROTO_T ( exp vardec X exp piece )
295
{
296
  /*
297
   * this replaces used_in with stronger test - see changes in assigns_alias
298
   */
299
  exp t = pt (vardec);
300
  exp q;
301
  exp upwards = t;
302
 
303
  do {				/* test each use of the identifier */
304
    q = t;
305
    while (q != nilexp && q != piece && q != vardec &&
306
	   name (q) != rep_tag &&
307
	   (name (q) != ident_tag || !isglob (q))) {
308
      upwards = q;
309
      q = bro (q);
310
    }
311
 
312
    if (q != nilexp && q != piece && name (q) == rep_tag) {
313
      /* q has got to a repeat, so */
314
      /* scan up repeat_list structure for holder of piece */
315
      exp h = pt (q), hp = pt (piece);
316
      while (h != nilexp && h != hp)
317
	h = bro (h);
318
      if (h == hp) {
319
	/* q was within piece */
320
	q = piece;
321
	upwards = son (q);
322
	while (!last (upwards))
323
	  upwards = bro (upwards);
324
      } else
325
	q = nilexp;
326
    }
327
    /* ascend from the use until we reach either vardec or piece */
328
    if (q == piece && last (upwards)) {	/* the use was in piece */
329
      if (isreallyass(t))
330
        return false;
331
      if (!last (t) && last (bro (t)) &&
332
	  (name (bro (bro (t))) == ass_tag ||
333
	   name (bro (bro (t))) == assvol_tag))
334
	return false;		/* the use was an assignment */
335
      if (!last (t) && last (bro (t))
336
	  && name (bro (bro (t))) == ident_tag) {
337
	/* use in declaration */
338
	if (!isvar (bro (bro (t))) &&
339
	    !not_assigned_to (bro (bro (t)), bro (t))) {
340
	  return false;
341
	}
342
      } else {
343
	exp dad = father (t);
344
	if (name (dad) == addptr_tag && son (dad) == t) {
345
	  /* use in subscript .... */
346
	  if (!last (dad) && last (bro (dad)) &&
347
	       (name (bro (bro (dad))) == ass_tag ||
348
	         name (bro (bro (dad))) == assvol_tag))
349
	    return false;		/* the use was an assignment */
350
	  if (!last (dad) && last (bro (dad)) &&
351
	      name (bro (bro (dad))) == ident_tag) {
352
	    /* ... which is identified */
353
	    if (!isvar (bro (bro (dad))) &&
354
		!not_assigned_to (bro (bro (dad)), bro (dad))) {
355
	      return false;
356
	    }
357
	  }
358
	}
359
      }
360
    }
361
    t = pt (t);
362
  } while (t != nilexp);
363
  return true;
364
}
365
 
366
 
367
static int not_assigned_to
368
    PROTO_N ( (vardec, body) )
369
    PROTO_T ( exp vardec X exp body )
370
{
371
  if (no (vardec) > VERYBIGUSAGE)
372
    return false;
373
 
374
  if (no (vardec) > MAXUSE) {
375
    /* when a variable is used many times the result from not_ass2 */
376
    /* is saved in an ordered list to avoid n-squared run-times    */
377
    memlist *ptr = mem;
378
    /* is this declaration known? */
379
    /* NOTE: memory is cleared after each repeat is processed */
380
    /* so any in memory refer to the current repeat */
381
    while (ptr != nilmem && (ptr->dec) != vardec)
382
      ptr = ptr->next;
383
    if (ptr == nilmem) {
384
      memlist **pp = &mem;
385
      /* insert with heavier used decs first */
386
      while (*pp != nilmem && no ((*pp)->dec) > no (vardec))
387
	pp = &((*pp)->next);
388
      if (fmem == nilmem) {
389
	/* add some cells onto the free list */
390
	memlist **fpp = &fmem;
391
	int i;
392
	*fpp = (memlist *) xcalloc (MEMINC, sizeof (memlist));
393
	for (i = 0; i < MEMINC; ++i) {
394
	  (*fpp)->next = (*fpp) + 1;
395
	  fpp = &((*fpp)->next);
396
	}
397
	*fpp = nilmem;
398
      }
399
      /* get a cell from the free list */
400
      ptr = fmem;
401
      fmem = ptr->next;
402
      /* remember this vardec */
403
      ptr->dec = vardec;
404
      ptr->res = not_ass2 (vardec, body);
405
      /* put cell into mem list */
406
      ptr->next = *pp;
407
      *pp = ptr;
408
    }
409
    return (ptr->res);
410
  } else
411
    /* default case - identifier not heavily used */
412
    return (not_ass2 (vardec, body));
413
}
414
 
415
 
416
 
417
/************************************************************************
418
 *  max_const extracts the largest expressions which are constant within
419
 *  the region of interest.
420
 *
421
 *  Parameters:
422
 *        whole   the program region under consideration
423
 *        e       the expression under consideration
424
 *        ass_ok  all assignments in this region are to simple unaliassed
425
 *                variables
426
 ************************************************************************/
427
 
428
static maxconst max_const
429
    PROTO_N ( (whole, e, ass_ok) )
430
    PROTO_T ( exp whole X exp e X int ass_ok )
431
{
432
  switch (name (e)) {
433
  case labst_tag:
434
    return mc_list (whole, bro (son (e)), ass_ok, false);
435
 
436
  case contvol_tag:
437
  case case_tag:
438
  case goto_tag:
439
  case apply_general_tag:
440
  case tail_call_tag:
441
    return no_consts;
442
 
443
  case fdiv_tag: {
444
    maxconst mc;
445
    maxconst mct;
446
    mc = max_const(whole, bro(son(e)), ass_ok);
447
    mct = mc_list (whole, son (e), ass_ok, optop(e));
448
    if (mct.self)
449
      return mct;
450
 
451
    if (mc.self && !strict_fl_div && optop(e)) {
452
      flpt f = new_flpt();
453
      exp funit;
454
      exp temp1;
455
      exp temp2;
456
      flt_copy (flptnos[fone_no], &flptnos[f]);
457
      funit = getexp(sh(e), nilexp, 0, nilexp, nilexp,
458
			0, f, real_tag);
459
      temp1 = me_b3(sh(e), funit, bro(son(e)), fdiv_tag);
460
      temp2 = me_b3(sh(e), son(e), temp1, fmult_tag);
461
 
462
#ifdef NEWDIAGS
463
      dgf(temp2) = dgf(e);
464
#endif
465
      replace(e, temp2, temp2);
466
      return max_const(whole, temp2, ass_ok);
467
    }
468
    else
469
      return mct;
470
  };
471
 
472
 
473
  case cond_tag:{
474
      prop old_cond_flag = cond_flag;
475
      maxconst mc;
476
      if (cond_flag == 0)
477
	cond_flag = 1;
478
      mc = mc_list (whole, son (e), ass_ok, false);
479
      cond_flag = old_cond_flag;
480
      return mc;
481
    }
482
 
483
  case test_tag:{
484
      maxconst mc;
485
      mc = mc_list (whole, son (e), ass_ok, false);
486
      if (cond_flag == 1)
487
	cond_flag = 2;
488
      return mc;
489
    }
490
 
491
  case val_tag:
492
  case proc_tag:
493
  case env_offset_tag:
494
  case general_env_offset_tag:
495
    return self_const;
496
 
497
  case name_tag:
498
    if (intnl_to (whole, son (e)))
499
      return no_consts;		/* internal const - may change */
500
    else
501
      return self_const;	/* external constant */
502
 
503
  case cont_tag:
504
    if ((name (son (e)) == name_tag) && isvar (son (son (e)))) {
505
      /* so e is extracting the contents of a variable */
506
      exp var = son (son (e));
507
 
508
      if (!intnl_to (whole, var) && (not_assigned_to (var, whole))
509
	  && ass_ok) {
510
	/*
511
	 * variable declared external to whole, and NEVER assigned to in
512
	 * whole
513
	 */
514
	if (iscaonly(var))
515
	  return self_const;
516
	if (isglob(var) && !find_glob(var))
517
	  return self_const;
518
	return no_consts;
519
	}
520
      else
521
	return no_consts;
522
    } else
523
      return mc_list (whole, son (e), ass_ok, ass_ok);
524
 
525
  case plus_tag:
526
  case and_tag:
527
  case or_tag:
528
  case xor_tag:
529
  case mult_tag:{
530
      maxconst mc;
531
 
532
      mc = mc_list (whole, son (e), ass_ok, optop(e));
533
 
534
      if (mc.cont != nilexp && pt (mc.cont) != son (mc.cont) && optop(e)) {
535
	/* more than 1 item in list */
536
	exp limit = pt (mc.cont), h = son (mc.cont), arg, this, last_h;
537
	int arg_count = 0;
538
	int tot_args = 1;
539
	this = son(e);
540
	while(!last(this)) {
541
	  this = bro(this);
542
	  ++tot_args;
543
	};
544
 
545
	/* remember for which operator these are arguments */
546
	/* NB - some items may not be args of this operator */
547
	while (h != nilexp) {
548
	  this = son (h);
549
	  arg = son (e);
550
	  while (arg != nilexp && arg != this)
551
	    arg = (last (arg) ? nilexp : bro (arg));
552
	  if (arg != nilexp) {
553
	    /* it's an argument of this operator */
554
	    ++arg_count;
555
	    pt (h) = e;
556
	    last_h = h;
557
	  }
558
	  h = (h == limit ? nilexp : bro (h));
559
	}
560
	/* remove reference to operator if only 1 arg is const */
561
	if (arg_count != tot_args && arg_count > 0) {
562
	  SET(last_h);
563
	  pt (last_h) = nilexp;
564
	};
565
      }
566
      return mc;
567
    }
568
 
569
  case addptr_tag:{
570
      exp p = son (e);
571
      maxconst mc, mx;
572
 
573
      /* find the root pointer */
574
      while (name (p) == addptr_tag)
575
	p = son (p);
576
 
577
      mc = max_const (whole, p, ass_ok);
578
      ret_constlist (mc.cont);
579
 
580
      if (mc.self) {
581
	/* root pointer is constant in this context */
582
	exp c_list = nilexp, v_list = nilexp, x, cph, *list;
583
 
584
	/* construct list of ALL constant parts */
585
	/* initial list element will hold const. ptr */
586
	cph = getexp (f_bottom, nilexp, false, nilexp, nilexp,
587
		      0,  0, 0);
588
	mc.self = false;	/* assume, for moment */
589
	mc.cont = getexp (f_bottom, nilexp, false, cph, cph,
590
			  0,  0, 0);
591
 
592
	/* return up the chain, testing the offsets */
593
	while (p != e) {
594
	  mx = max_const (whole, bro (p), ass_ok);
595
	  p = bro (p);		/* p is now the offset */
596
 
597
	  /* add offset to appropriate list */
598
	  list = (mx.self) ? &c_list : &v_list;
599
	  *list = getexp (nilexp, *list, 0, p, nilexp, 0,  0, 0);
600
 
601
	  if (mx.cont != nilexp) {
602
	    /* the offset is not constant, but PARTS of it are */
603
 
604
	    /* remove any "negate(name(...))" */
605
	    exp lim = pt (mx.cont), h = son (mx.cont);
606
	    while (h != nilexp) {
607
	      if (name (son (h)) == neg_tag &&
608
		  name (son (son (h))) == name_tag)
609
		no (h) = -1;	/* set "done" flag */
610
	      h = (h == lim ? nilexp : bro (h));
611
	    }
612
 
613
	    /* add constant parts to mc */
614
	    bro (pt (mx.cont)) = son (mc.cont);
615
	    son (mc.cont) = son (mx.cont);
616
	    retcell (mx.cont);
617
	  }
618
	  p = bro (p);		/* p is now the next higher operation */
619
	}
620
 
621
	if (v_list == nilexp) {
622
	  /* whole addptr expression is constant */
623
	  /* return c_list elements */
624
	  while (c_list != nilexp) {
625
	    x = c_list;
626
	    c_list = bro (c_list);
627
	    retcell (x);
628
	  }
629
 
630
	  ret_constlist (mc.cont);
631
 
632
	  return self_const;
633
	}
634
	/* go down the chain of addptrs, rearranging offsets */
635
	/* NB - assumes addptr is strictly diadic, so "last" */
636
	/* flags are already correct		       */
637
 
638
	/* put non-constant offsets at the higher levels */
639
	while (v_list != nilexp) {
640
	  /* put next offset in 2nd argument position */
641
	  x = son (p);
642
	  bro (x) = son (v_list);
643
	  bro (bro (x)) = p;
644
	  p = x;		/* point to 1st argument */
645
	  /* traverse v_list, returning elements */
646
	  x = v_list;
647
	  v_list = bro (x);
648
	  retcell (x);
649
	}
650
 
651
	/* the rest is constant - add it to mc.cont */
652
	son (cph) = p;
653
 
654
	/* and put constant offsets at the lower levels */
655
	while (c_list != nilexp) {
656
	  /* put next offset in 2nd argument position */
657
	  x = son (p);
658
	  bro (x) = son (c_list);
659
	  bro (bro (x)) = p;
660
	  p = x;		/* point to 1st argument */
661
	  /* traverse c_list, returning elements */
662
	  x = c_list;
663
	  c_list = bro (x);
664
	  retcell (x);
665
	}
666
 
667
	return mc;
668
      } else
669
	return mc_list (whole, son (e), ass_ok, true);
670
    }
671
 
672
  case offset_mult_tag:{
673
      exp arg1 = son (e);
674
      exp arg2 = bro (arg1);
675
      maxconst mc1, mc2;
676
      shape ofsh = sh (e);
677
      mc1 = max_const (whole, arg1, ass_ok);
678
      mc2 = max_const (whole, arg2, ass_ok);
679
      if (mc1.self && mc2.self)
680
	return self_const;
681
      if (mc2.self && mc1.cont != nilexp) {
682
	/**********************************************************
683
         * the offset is const, and arg1 has some constant parts
684
         * so transform:
685
         *   offset_mult((a*b),K)
686
         * to:
687
         *   offset_mult(a,offset_mult(b,K))
688
         * rearranged so that the constant factors are grouped
689
         * with K so that the largest possible structure can be
690
         * extracted as constant
691
         *********************************************************/
692
	exp klist = nilexp, nklist = nilexp;
693
	exp *ref;
694
	exp m_res;
695
	int j;
696
	ret_constlist (mc1.cont);
697
	if (name (arg1) == mult_tag) {
698
	  exp m_arg = son (arg1);
699
	  /* sort into const and varying args */
700
	  while (m_arg != nilexp) {
701
	    mc1 = max_const (whole, m_arg, ass_ok);
702
	    if (mc1.self) {
703
	      /* add to constant operand list */
704
	      klist = getexp (nilexp, klist, false, m_arg, nilexp,
705
			      0,  0, 0);
706
	    } else {
707
	      /* add to non-constant operand list */
708
	      nklist = getexp (nilexp, nklist, false, m_arg, nilexp,
709
			       0,  0, 0);
710
	      ret_constlist (mc1.cont);
711
	    }
712
	    if (last (m_arg))
713
	      m_arg = nilexp;
714
	    else
715
	      m_arg = bro (m_arg);
716
	  }
717
	  /* build offset_mult chain with const parts innermost */
718
	  m_res = copy (arg2);
719
	  for (j = 0; j < 2; ++j) {
720
	    exp *list = (j == 0) ? &klist : &nklist;
721
	    /* use klist, and then nklist */
722
	    while (*list != nilexp) {
723
	      exp z = *list;
724
	      exp a1 = copy (son (z));
725
	      exp offmul = getexp (ofsh, nilexp, false, a1, nilexp,
726
				   0,  0, offset_mult_tag);
727
	      setbro (a1, m_res);
728
	      clearlast (a1);
729
	      setbro (m_res, offmul);
730
	      setlast (m_res);
731
	      m_res = hold_check(offmul);
732
	      *list = bro (z);
733
	      retcell (z);
734
	    }
735
	  }
736
	  /* insert m_res - kill left overs */
737
	  ref = refto (father (e), e);
738
	  if (last (*ref))
739
	    setlast (m_res);
740
	  else
741
	    clearlast (m_res);
742
	  bro (m_res) = bro (*ref);
743
	  *ref = m_res;
744
	  kill_exp (e, e);
745
	} else
746
	  m_res = e;
747
	return mc_list (whole, son (m_res), ass_ok, true);
748
      }
749
      /* default action */
750
      return mc_list (whole, son (e), ass_ok, true);
751
    }
752
 
753
  default:
754
    if (son (e) == nilexp)
755
      return self_const;
756
    else
757
      return mc_list (whole, son (e), ass_ok, is_a (name (e)) && optop(e));
758
  }
759
}
760
 
761
 
762
/************************************************************************
763
 *  do_this_k
764
 *    replaces simple and compound constants in list by uses of a
765
 *    newly declared constant.
766
 *  Parameters:
767
 *        kdec    declaration of this new constant
768
 *        patn    pattern to look for
769
 *                NB where safe_eval has NOT been used,
770
 *                   patn is son(kdec)
771
 *        list    list of constant expresion holders
772
 *        limit   last constant holder in list
773
 ************************************************************************/
774
 
775
void do_this_k
776
    PROTO_N ( (kdec, patn, list, limit) )
777
    PROTO_T ( exp kdec X exp patn X exp list X exp limit )
778
{
779
  exp t = list;
780
  int scan = true;
781
  exp arglist = nilexp, ap;
782
  int nargs = 0;
783
 
784
  if (pt (list) != nilexp) {
785
    /* build required argument list */
786
    exp p = son (patn);
787
    while (p != nilexp) {
788
      exp arg_h = getexp (nilexp, arglist, 0, p, nilexp, 0, 0, 0);
789
      arglist = arg_h;
790
      ++nargs;
791
      p = (last (p) ? nilexp : bro (p));
792
    }
793
  }
794
  while (scan) {
795
    if (no (t) == 0) {
796
 
797
      if (pt (t) == nilexp && eq_exp (son (t), patn)) {
798
	/* simple correspondence */
799
	exp e = son (t);
800
	exp f = father (e);
801
	exp tagt = getexp (sh (e), bro (e),  (int)(last (e)),
802
			   kdec, pt (kdec), 0,  0, name_tag);
803
	pt (kdec) = tagt;
804
	++no (kdec);
805
#ifdef NEWDIAGS
806
	if (diagnose)
807
	  dg_extracted (tagt, *(refto (f, e)));
808
#endif
809
	*(refto (f, e)) = tagt;
810
	no (t) = -1;		/* dealt with */
811
	kill_exp (son (t), son (t));
812
      } else
813
      if (pt (t) != nilexp && name (pt (t)) == name (patn)) {
814
	/* try for complex match - at least the operator is correct */
815
	/* check errtreat ??? */
816
	int scan2 = true;
817
	int matched = 0;
818
	exp t2 = t, op = pt (t);
819
 
820
 
821
	while (matched >= 0 && scan2) {
822
	  if (no (t2) == 0 && pt (t2) == op) {
823
	    /* find match in argument list */
824
	    ap = arglist;
825
 
826
	    while (ap != nilexp &&
827
		   (pt (ap) != nilexp || !eq_exp (son (t2), son (ap)))
828
	      )
829
	      ap = bro (ap);
830
 
831
	    if (ap == nilexp)
832
	      matched = -1;
833
	    else {
834
	      pt (ap) = t2;
835
	      ++matched;
836
	    }
837
	  }
838
	  if (t2 == limit)
839
	    scan2 = false;
840
	  else
841
	    t2 = bro (t2);
842
	}
843
 
844
	if (matched == nargs) {
845
	  exp prev_arg = nilexp, oparg = son (op), cc;
846
	  int last_arg;
847
 
848
	  cc = getexp (sh (son (kdec)), op, 1, kdec, pt (kdec), 0,
849
		        0, name_tag);
850
	  pt (kdec) = cc;
851
	  ++no (kdec);
852
 
853
	  while (oparg != nilexp) {
854
	    last_arg = (int)last (oparg);
855
	    ap = arglist;
856
	    while (ap != nilexp && son (pt (ap)) != oparg)
857
	      ap = bro (ap);
858
	    if (ap == nilexp) {
859
	      /* this is one of the other args of op */
860
	      if (prev_arg == nilexp)
861
		son (op) = oparg;
862
	      else
863
		bro (prev_arg) = oparg;
864
	      clearlast (oparg);
865
	      prev_arg = oparg;
866
	    }
867
	    oparg = (last_arg ? nilexp : bro (oparg));
868
	  }
869
 
870
	  /* now add combined constant */
871
	  bro (prev_arg) = cc;
872
 
873
	  /* mark those dealt with & clear arglist */
874
	  ap = arglist;
875
	  while (ap != nilexp) {
876
	    exp deadarg = son (pt (ap));
877
	    no (pt (ap)) = -1;
878
	    son (pt (ap)) = nilexp;
879
	    pt (ap) = nilexp;
880
	    kill_exp (deadarg, deadarg);
881
	    ap = bro (ap);
882
	  }
883
	}
884
      }
885
    }
886
    if (t == limit)
887
      scan = false;
888
    else
889
      t = bro (t);
890
  }
891
 
892
  /* return arglist */
893
  while (arglist != nilexp) {
894
    ap = bro (arglist);
895
    retcell (arglist);
896
    arglist = ap;
897
  }
898
}
899
 
900
/************************************************************************
901
 *  safe_arg
902
 *
903
 * insert run-time checks on this argument - see safe_eval
904
 *
905
 *  Parameters:
906
 *        e	argument to be tested
907
 *        esc	label: jump to this if e is:
908
 *			pointer and nil
909
 *			numeric and zero
910
 ************************************************************************/
911
 
912
static exp safe_arg
913
    PROTO_N ( (e, esc) )
914
    PROTO_T ( exp e X exp esc )
915
{
916
  exp decl = getexp (sh (e), nilexp, 0, e, nilexp,
917
		     0,  0, ident_tag);
918
  exp v1, v2, z, s, konst, tst;
919
 
920
  /* make the unsafe value for this shape */
921
  switch (name (sh (e))) {
922
  case ptrhd:
923
    konst = me_null(sh(e), ptr_null, null_tag);
924
    break;
925
  case scharhd:
926
  case ucharhd:
927
  case swordhd:
928
  case uwordhd:
929
  case slonghd:
930
  case ulonghd:
931
  case s64hd:
932
  case u64hd:
933
    konst = getexp (sh (e), nilexp, 0, nilexp, nilexp,
934
		    0,  0, val_tag);
935
    break;
936
  case shrealhd:
937
  case realhd:
938
  case doublehd:{
939
      flpt f = new_flpt ();
940
      int i;
941
      for (i = 0; i < MANT_SIZE; ++i)
942
	(flptnos[f].mant)[i] = 0;
943
      flptnos[f].exp = 0;
944
      flptnos[f].sign = 0;
945
      konst = getexp (sh (e), nilexp, 0, nilexp, nilexp,
946
		      0, f, real_tag);
947
      break;
948
    }
949
  case offsethd:
950
    konst = f_offset_zero (f_alignment (sh (e)));
951
    break;
952
  default: {
953
      SET(konst);
954
      failer (BAD_SHAPE);
955
    };
956
  }
957
 
958
  v1 = getexp (sh (e), nilexp, 0, decl, pt (decl), 0,  0, name_tag);
959
  pt (decl) = v1;
960
  ++no (decl);
961
  v2 = getexp (sh (e), nilexp, 1, decl, pt (decl), 0,  0, name_tag);
962
  pt (decl) = v2;
963
  ++no (decl);
964
 
965
  tst = getexp (f_top, nilexp, 0, v1, esc, 0,
966
		 0, test_tag);
967
  settest_number(tst, f_not_equal);
968
  ++no (son (esc));
969
  setbro (v1, konst);
970
  tst = hc (tst, konst);
971
 
972
  z = getexp (f_top, v2, 0, tst, nilexp, 0,  0, 0);
973
  setbro (tst, z);
974
  setlast (tst);
975
  s = getexp (sh (e), decl, 1, z, nilexp, 0,  0, seq_tag);
976
  setbro (e, s);
977
  clearlast (e);
978
  s = hc (s, v2);
979
 
980
  return (hc (decl, s));
981
}
982
 
983
 
984
/************************************************************************
985
 *  safe_eval	ensure that the evaluation of e cannot fail
986
 *
987
 * insert run-time checks into the evaluation of this expression - this is
988
 * only used when a constant is extracted from inside a conditional inside
989
 * a loop. Where this happens, the extraction of the constant and its
990
 * unconditional evaluation outside the loop can result in program failure
991
 * when the program would not otherwise have failed.
992
 * This should be called with "escape_route" as nilexp - this marks the
993
 * outermost call of safe_eval, and causes the contruction of a label for
994
 * the code to escape to if a "dangerous" value is encountered during
995
 * evaluation of the constant. If at the end of the outermost call the label
996
 * has been used, then there is a possibility of failure during evaluation
997
 * and code is generated to supply a "safe" value when the label is reached.
998
 *
999
 * dangerous operations are:
1000
 *	contents of NIL
1001
 *	reffield of NIL (indirectly, when its contents are taken)
1002
 *	division by zero (any variety; includes mod and rem)
1003
 * Note that checking the result of reffield for NIL is a waste of time
1004
 * since any offset from NIL will make the result different from NIL.
1005
 *
1006
 *
1007
 *  Parameters:
1008
 *        e		expression being evaluated
1009
 *        escape_route	label: jump to this if evaluation would fail
1010
 ************************************************************************/
1011
 
1012
static exp safe_eval
1013
    PROTO_N ( (e, escape_route) )
1014
    PROTO_T ( exp e X exp escape_route )
1015
{
1016
  exp esc_lab, res;
1017
 
1018
  if (escape_route == nilexp) {
1019
    /* this is outermost call - construct escape label */
1020
    exp z = getexp (f_top, nilexp, 0, nilexp, nilexp, 0,  0, clear_tag);
1021
    esc_lab = getexp (sh (e), nilexp, 0, z, nilexp,
1022
		      0,  0, labst_tag);
1023
  } else
1024
    esc_lab = escape_route;
1025
 
1026
  switch (name (e)) {
1027
  case ident_tag:
1028
  case cond_tag:
1029
  case rep_tag:
1030
  case solve_tag:
1031
  case case_tag:  {
1032
      SET(res);
1033
      failer (CONSTC_ERROR);
1034
      break;
1035
    };
1036
  case name_tag:
1037
  case env_offset_tag:
1038
  case general_env_offset_tag:
1039
  case real_tag:
1040
    res = copy (e);
1041
    break;
1042
  case div0_tag:
1043
  case div1_tag:
1044
  case div2_tag:
1045
  case fdiv_tag:
1046
  case mod_tag:
1047
  case rem2_tag:
1048
  case rem0_tag:
1049
  case offset_div_tag:
1050
  case offset_div_by_int_tag:
1051
    {
1052
      exp arg1 = safe_eval (son (e), esc_lab);
1053
      exp arg2 = safe_eval (bro (son (e)), esc_lab);
1054
      res = copyexp (e);
1055
      setson (res, arg1);
1056
      arg2 = safe_arg (arg2, esc_lab);
1057
      setbro (arg1, arg2);
1058
      clearlast (arg1);
1059
      res = hc (res, arg2);
1060
      break;
1061
    }
1062
  case cont_tag:
1063
    {
1064
      exp arg = son (e);
1065
      if (name (arg) == name_tag &&
1066
	  (isglob (son (arg)) || isvar (son (arg))))
1067
	res = copy (e);
1068
      else {
1069
	arg = safe_eval (arg, esc_lab);
1070
	if (!arg_is_reff)
1071
	  arg = safe_arg (arg, esc_lab);
1072
	res = copyexp (e);
1073
	setson (res, arg);
1074
	res = hc (res, arg);
1075
      }
1076
      break;
1077
    }
1078
  case reff_tag:
1079
    {
1080
      exp arg = son (e);
1081
      if (name (arg) == name_tag && isglob (son (arg)))
1082
	res = copy (e);
1083
      else {
1084
	arg = safe_eval (arg, esc_lab);
1085
	if (!arg_is_reff)
1086
	  arg = safe_arg (arg, esc_lab);
1087
	res = copyexp (e);
1088
	setson (res, arg);
1089
	res = hc (res, arg);
1090
      }
1091
      break;
1092
    }
1093
  default:{
1094
      exp k = copyexp (e);
1095
      exp arg = son (e);
1096
      exp p;
1097
      if (arg == nilexp) {
1098
	res = k;
1099
	break;
1100
      }
1101
      p = safe_eval (arg, esc_lab);
1102
      setson (k, p);
1103
      while (!last (arg)) {
1104
	exp safe = safe_eval (bro (arg), esc_lab);
1105
	setbro (p, safe);
1106
	clearlast (p);
1107
	p = bro (p);
1108
	arg = bro (arg);
1109
      }
1110
      res = hc (k, p);
1111
      break;
1112
    }
1113
  }
1114
 
1115
  arg_is_reff = (name (e) == reff_tag);
1116
  if (escape_route != nilexp)
1117
    return (res);		/* this was an inner call */
1118
 
1119
  if (no (son (esc_lab)) == 0) {
1120
    /* the escape route is not used - inherently safe */
1121
    retcell (son (esc_lab));
1122
    retcell (esc_lab);
1123
    return (res);
1124
  } else {
1125
    /* the escape route was used - construct conditional */
1126
    exp cond = getexp (sh (e), nilexp, 0, res, nilexp,
1127
		       0,  0, cond_tag);
1128
    exp safe;
1129
    safe = getexp (sh (e), nilexp, 1, nilexp, nilexp,
1130
		   0,  0, clear_tag);
1131
    setbro (son (esc_lab), safe);
1132
    IGNORE hc (esc_lab, safe);
1133
    setbro (res, esc_lab);
1134
    clearlast (res);
1135
    IGNORE hc (cond, esc_lab);
1136
    return (cond);
1137
  }
1138
}
1139
 
1140
 
1141
/************************************************************************
1142
 *  extract_consts
1143
 *
1144
 *  Parameters:
1145
 *        issn         loop is son(rf) else bro(rf)
1146
 *        rf           EXP holding loop
1147
 *        list_head    exp containing list of constant expressions
1148
 *                     this must not be empty
1149
 ************************************************************************/
1150
 
1151
static void look_for_caonly
1152
    PROTO_N ( (e) )
1153
    PROTO_T ( exp e )
1154
{
1155
  if (name(e) == name_tag) {
1156
    if (isvar(son(e)))
1157
      clearcaonly(son(e));
1158
    return;
1159
  }
1160
  if (name(e) == addptr_tag)
1161
    look_for_caonly(son(e));
1162
  if (name(e) == seq_tag || name(e) == ident_tag)
1163
    look_for_caonly(bro(son(e)));
1164
  return;
1165
}
1166
 
1167
static int extract_consts
1168
    PROTO_N ( (issn, rf, list_head) )
1169
    PROTO_T ( int issn X exp rf X exp list_head )
1170
{
1171
  exp val;
1172
  int changed = 0;		/* result; will be true if we make a change */
1173
  exp t = son (list_head);	/* first in list */
1174
  exp limit = pt (list_head);	/* last in list */
1175
  int contin = true;
1176
 
1177
  do {
1178
    if (issn)
1179
      val = son (rf);
1180
    else
1181
      val = bro (rf);
1182
    if (no (t) != 0)		/* this has been dealt with previously - just
1183
				 * check for end */
1184
      contin = (t != limit);
1185
    else {
1186
      /* this has not been absorbed by a previous constant */
1187
 
1188
      exp e;
1189
      int force = 0;
1190
 
1191
      if (pt (t) == nilexp) {
1192
	/* simple constant - no brothers */
1193
	exp f;
1194
	e = son (t);
1195
	f = father (e);
1196
 
1197
 
1198
 
1199
	/* ?????????????????? */
1200
	if (!last (e) && last (bro (e))
1201
	    && (name (f) == ident_tag)
1202
	    && !isvar (f)) {
1203
	  /* this is an in-register constant declaration */
1204
	  /* so remove the force register bit from f so  */
1205
	  /* that it becomes a simple renaming           */
1206
	  clearusereg (f);
1207
	  /* and set the force register bit for the      */
1208
	  /* outer declaration                           */
1209
	  force = 1;
1210
	}
1211
#ifdef NEWDIAGS
1212
	e = copy_dg_separate (e);	/* original may remain in use */
1213
#else
1214
	e = copy (e);
1215
#endif
1216
	/* so son(t) can be killed or used in declaration */
1217
      } else {
1218
	/* the next few consts are args of the same operator */
1219
	exp op = pt (t), new_c, prev = nilexp, c_arg = nilexp, t2 = t;
1220
	int scan = true;
1221
 
1222
	new_c = copyexp (op);
1223
 
1224
	while (scan) {
1225
	  if (no (t2) == 0 && pt (t2) == op) {
1226
#ifdef NEWDIAGS
1227
	    c_arg = copy_dg_separate (son (t2));
1228
					/* original may remain in use */
1229
#else
1230
	    c_arg = copy (son (t2));
1231
#endif
1232
	    if (prev == nilexp)
1233
	      son (new_c) = c_arg;
1234
	    else {
1235
	      bro (prev) = c_arg;
1236
	      clearlast (prev);
1237
	    }
1238
	    prev = c_arg;
1239
	  }
1240
	  if (t2 == limit)
1241
	    scan = false;
1242
	  else
1243
	    t2 = bro (t2);
1244
	}
1245
 
1246
	e = hc (new_c, c_arg);
1247
      }
1248
 
1249
      if (is_worth (e)) {
1250
	/* declare new constant */
1251
	exp konst;
1252
	exp newdec;
1253
	int kill_e = false;
1254
#ifdef NEWDIAGS
1255
	if (diagnose)
1256
	  strip_dg_context (e);
1257
#endif
1258
	if (props (t) > 1) {
1259
	  /* this const. is in a conditional in the loop */
1260
	  /* ensure that extraction from loop does not cause a failure */
1261
	  kill_e = true;
1262
	  konst = safe_eval (e, nilexp);
1263
	} else
1264
	  konst = e;
1265
	newdec = getexp (sh (val), bro (val),
1266
		  (int)(last (val)), konst, nilexp, 0,  0, ident_tag);
1267
	if (has_lj_dest)
1268
	  setvis(newdec);
1269
	if (force && isvis(father(e)))
1270
	  setvis(newdec);
1271
	else
1272
	if (force || ismips)
1273
	  setusereg (newdec);
1274
 
1275
	if (name(sh(konst)) == ptrhd)
1276
	  look_for_caonly(konst);
1277
 
1278
	bro (konst) = val;
1279
	clearlast (konst);
1280
	bro (val) = newdec;
1281
	setlast (val);
1282
	if (issn)
1283
	  son (rf) = newdec;
1284
	else
1285
	  bro (rf) = newdec;
1286
 
1287
#ifdef NEWDIAGS
1288
	if (diagnose) {
1289
	  make_optim_dg (DGD_EXTRACT, newdec);
1290
	}
1291
#endif
1292
	do_this_k (newdec, e, t, limit);
1293
	if (kill_e)
1294
	  kill_exp (e, e);
1295
	changed = 1;		/* have made a change */
1296
      } else
1297
	kill_exp (e, e);
1298
    }
1299
 
1300
    if (t == limit)		/* that was the last in the list */
1301
      contin = false;
1302
    else {
1303
      exp n = bro (t);
1304
      retcell (t);
1305
      t = n;
1306
    }
1307
  }
1308
  while (contin);
1309
 
1310
  retcell (t);
1311
 
1312
  retcell (list_head);
1313
  return (changed);
1314
}
1315
 
1316
 
1317
/************************************************************************
1318
 *  assigns_alias
1319
 *
1320
 *  scans e - returns true if any aliased variables are assigned to
1321
 *
1322
 *
1323
 ************************************************************************/
1324
 
1325
int named_dest
1326
    PROTO_N ( (dest) )
1327
    PROTO_T ( exp dest )
1328
{
1329
  switch (name (dest)) {
1330
  case name_tag:{
1331
      if (isvar (son (dest))) {
1332
	if (iscaonly (son (dest)))
1333
	  return true;
1334
	if (isglob(son(dest))) {
1335
	  if (find_glob(son(dest)))
1336
	    return true;
1337
	  if (glob_index == globmax)
1338
	    return false;
1339
	  glob_dest[glob_index++] = son(dest);
1340
	  return true;
1341
	};
1342
      } else if (!isvar(son(dest)) && son (son (dest)) != nilexp) {
1343
	return named_dest (son (son (dest)));
1344
      }
1345
      return false;
1346
    }
1347
  case addptr_tag:
1348
  case reff_tag:{
1349
      /* Should we look at bro son to see if it contains an assignment ??? */
1350
      return false;
1351
    }
1352
  default:
1353
    return false;
1354
  }
1355
}
1356
 
1357
int assigns_alias
1358
    PROTO_N ( (e) )
1359
    PROTO_T ( exp e )
1360
{
1361
  switch (name (e)) {
1362
  case assvol_tag:
1363
  case ass_tag:{
1364
      exp dest = son (e);
1365
 
1366
      if (!named_dest (son (e)))
1367
	return (true);		/* LHS may be aliassed */
1368
      else			/* check RHS for assignments */
1369
	return (assigns_alias (bro (dest)));
1370
    }
1371
 
1372
  case name_tag:
1373
  case env_offset_tag:
1374
  case general_env_offset_tag:
1375
    return (false);
1376
 
1377
  case case_tag:
1378
    return (assigns_alias (son (e)));
1379
    /* NB - must only look at first son */
1380
 
1381
  case bfass_tag:
1382
  case apply_tag:
1383
    return (true);		/* pessimist! */
1384
 
1385
  default:{
1386
      int aa = false;
1387
      exp s = son (e);
1388
 
1389
      while ((s != nilexp) && !aa) {
1390
	aa = assigns_alias (s);
1391
	if (aa || last (s))
1392
	  s = nilexp;
1393
	else
1394
	  s = bro (s);
1395
      }
1396
 
1397
      return (aa);
1398
    }
1399
  }
1400
}
1401
 
1402
/************************************************************************
1403
 *  scan_for_lv
1404
 *
1405
 *  scans e - returns true if any label may be long jump destination
1406
 *
1407
 *
1408
 ************************************************************************/
1409
 
1410
static int scan_for_lv
1411
    PROTO_N ( (e) )
1412
    PROTO_T ( exp e )
1413
{
1414
  switch (name (e)) {
1415
  case make_lv_tag:
1416
    return (true);
1417
 
1418
  case name_tag:
1419
  case env_offset_tag:
1420
  case general_env_offset_tag:
1421
    return (false);
1422
 
1423
  default:{
1424
      int aa = false;
1425
      exp s = son (e);
1426
 
1427
      while ((s != nilexp) && !aa) {
1428
	aa = scan_for_lv (s);
1429
	if (aa || last (s))
1430
	  s = nilexp;
1431
	else
1432
	  s = bro (s);
1433
      }
1434
 
1435
      return (aa);
1436
    }
1437
  }
1438
}
1439
 
1440
 
1441
/************************************************************************
1442
 *  repeat_consts
1443
 *
1444
 *  calls extract_consts on each element of the list of repeat loops
1445
 ************************************************************************/
1446
 
1447
void repeat_consts
1448
    PROTO_Z ()
1449
{
1450
  exp reps = get_repeats ();
1451
 
1452
  while (reps != nilexp) {
1453
    if (son (reps) != nilexp && name (son (reps)) == rep_tag
1454
	&& no (reps) < max_loop_depth) {
1455
      exp loop = son (reps);
1456
      exp sts = bro (son (loop));
1457
      int no_alias;
1458
      maxconst mx;
1459
      exp consts;
1460
 
1461
      /* put old identifier memory list into its free list */
1462
      memlist **mptr = &mem;
1463
 
1464
      glob_index = 0;
1465
      no_alias = !assigns_alias (sts);
1466
      while (*mptr != nilmem)
1467
	mptr = &((*mptr)->next);
1468
      *mptr = fmem;
1469
      fmem = mem;
1470
      mem = nilmem;
1471
 
1472
      mx = mc_list (loop, sts, no_alias, false);
1473
 
1474
      consts = mx.cont;
1475
      /* NB - false forces a list to be produced */
1476
 
1477
      if (no_alias)
1478
	set_noalias (reps);	/* preserve for forall processing */
1479
 
1480
      if (consts != nilexp) {
1481
	exp rr;
1482
	int sn;
1483
	exp fa = father (loop);
1484
	if (son (fa) == loop) {
1485
	  sn = 1;
1486
	  rr = fa;
1487
	} else {
1488
	  sn = 0;
1489
	  rr = son (fa);
1490
	  while (bro (rr) != loop && !last (rr))
1491
	    rr = bro (rr);
1492
	};
1493
	if (sn || bro (rr) == loop) {
1494
	  while (name(fa) != proc_tag && name(fa) != general_proc_tag
1495
		&& name(fa) != hold_tag && name(fa) != hold2_tag)
1496
	    fa = father(fa);
1497
	  if (name(fa) != hold_tag && name(fa) != hold2_tag) {
1498
	    if (proc_uses_crt_env(fa))
1499
	      has_lj_dest = scan_for_lv (sts);
1500
	    else
1501
	      has_lj_dest = 0;
1502
	    IGNORE extract_consts (sn, rr, consts);
1503
	  }
1504
	}
1505
      }
1506
    }
1507
    reps = pt (reps);
1508
  }
1509
}
1510
 
1511
 
1512
/************************************************************************
1513
 *  get_repeats
1514
 *
1515
 *  calculates maximum distance of every repeat from a leaf node
1516
 *  (this allows repeat processing to be restricted to inner loops)
1517
 *  returns the repeat_list
1518
 ************************************************************************/
1519
 
1520
exp get_repeats
1521
    PROTO_Z ()
1522
{
1523
  if (repeat_list != nilexp && !is_dist (repeat_list)) {
1524
    exp reps = repeat_list;
1525
 
1526
    while (reps != nilexp) {
1527
      if (no (reps) == 0) {
1528
	/* this is a leaf node */
1529
	/* no(x) is used in dexp to count directly nested loops */
1530
	int dist = 0;
1531
	exp sup = reps;
1532
	do {
1533
	  set_dist (sup);	/* no(x) is now max dist to leaf */
1534
	  no (sup) = dist;
1535
	  if (son (sup) != nilexp && name (son (sup)) == rep_tag)
1536
	    ++dist;		/* only repeats are significant */
1537
	  sup = bro (sup);	/* go to enclosing repeat */
1538
	} while (sup != nilexp && (!is_dist (sup) || no (sup) < dist));
1539
      }
1540
      reps = pt (reps);
1541
    }
1542
  }
1543
  return (repeat_list);
1544
}
1545
 
1546
 
1547
/************************************************************************
1548
 *  return_repeats
1549
 *
1550
 *  returns the storage used by repeat_list
1551
 ************************************************************************/
1552
 
1553
void return_repeats
1554
    PROTO_Z ()
1555
{
1556
  exp reps = repeat_list;
1557
 
1558
  while (reps != nilexp) {
1559
    exp next = pt (reps);
1560
    retcell (reps);
1561
    reps = next;
1562
  }
1563
  repeat_list = nilexp;
1564
}