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: release $
33
$Date: 1998/01/17 15:55:47 $
34
$Revision: 1.1.1.1 $
35
$Log: unroll.c,v $
36
 * Revision 1.1.1.1  1998/01/17  15:55:47  release
37
 * First version to be checked into rolling release.
38
 *
39
 * Revision 1.2  1995/09/11  13:58:41  currie
40
 * gcc pedantry
41
 *
42
 * Revision 1.1  1995/04/06  10:44:05  currie
43
 * Initial revision
44
 *
45
***********************************************************************/
46
 
47
 
48
 
49
#include "config.h"
50
#include "common_types.h"
51
#include "basicread.h"
52
#include "exp.h"
53
#include "expmacs.h"
54
#include "tags.h"
55
#include "installglob.h"
56
#include "externs.h"
57
#include "check_id.h"
58
#include "check.h"
59
#include "me_fns.h"
60
#include "install_fns.h"
61
#include "shapemacs.h"
62
#include "unroll.h"
63
 
64
static int  unroll_complex PROTO_S ( ( exp, int, exp, int, exp, int ) ) ;
65
 
66
/* MACROS */
67
 
68
#define LIMIT 55
69
#define SIMPLE_LIMIT 0
70
#define UNROLL_MAX 16
71
 
72
#define UNROLL_BY 4
73
 
74
 
75
/* VARIABLES */
76
/* All variables initialised */
77
 
78
static exp names[LIMIT];	/* no init needed */ /* records the uses of the control variable */
79
static int names_index;		/* no init needed */
80
static int allow_double;	/* no init needed */ /* permit removal of internal test */
81
static int jumps_out;		/* no init needed */
82
 
83
/* PROCEDURES */
84
 
85
static int  uc_list
86
    PROTO_N ( (e, n, control, lia, ul, decr) )
87
    PROTO_T ( exp e X int n X exp control X int lia X exp ul X int decr )
88
{
89
  int   c = unroll_complex (e, n, control, lia, ul, decr);
90
  if (c < 0 || last (e))
91
    return c;
92
  return uc_list (bro (e), c, control, lia, ul, decr);
93
}
94
 
95
static int  unroll_complex
96
    PROTO_N ( (e, n, control, lia, ul, decr) )
97
    PROTO_T ( exp e X int n X exp control X int lia X exp ul X int decr )
98
{
99
  /* e = body - repeated statement less label */
100
  /* n = complexity maximum */
101
  /* control = variable declaration for control variable */
102
  /* lia = boolean, limit is aliased */
103
  /* ul = variable declaration for limit if not aliased */
104
  /* decr = unit to decrement by */
105
  if (n < 0)
106
    return - 1;	/* complexity exceeded */
107
 
108
  if (son (e) == nilexp) {
109
    if (name(e) == goto_tag)
110
      allow_double = 0;		/* prevent removal of internal test */
111
    return n;
112
  };
113
 
114
  switch (name (e)) {
115
    case test_tag:
116
    case testbit_tag:
117
      if (!isunroll(pt(e))) {	/* flag set and cleared by cond_tag below */
118
	allow_double = 0;	/* prevent removal of internal test; jump out of loop */
119
      };
120
      return uc_list (son (e), n - decr, control, lia, ul, decr);
121
    case goto_tag:
122
      if (!isunroll(pt(e))) {	/* flag set and cleared by cond_tag below */
123
	allow_double = 0;	/* prevent removal of internal test; jump out of loop */
124
      };
125
      return n-1;
126
    case cond_tag:
127
      {
128
	int t;
129
        setunroll(bro(son(e)));		/* mark internal label */
130
	if (name(sh(son(e))) == bothd) {
131
	  t = unroll_complex(son(e), n - (4*decr), control, lia, ul, 0);
132
	  t = unroll_complex(bro(son(e)), t - decr, control, lia, ul, decr);
133
	}
134
	else {
135
	  t = unroll_complex(son(e), n - decr, control, lia, ul, decr);
136
	  t = unroll_complex(bro(son(e)), t - decr, control, lia, ul, decr);
137
	};
138
	clearunroll(bro(son(e)));	/* unmark it */
139
	return t;
140
      };
141
    case ass_tag:
142
    case assvol_tag:
143
      {
144
	exp assdest = son(e);	/* destination of assignment */
145
	if (name(assdest) == name_tag && son(assdest) == ul)
146
	  allow_double = 0;	/* prevent removal of internal test; assigning to limit */
147
	if (lia) {
148
	  if (name(assdest) == name_tag && !isvar(son(assdest)))
149
	    allow_double = 0;	/* prevent removal of internal test; perhaps assigning to limit */
150
	  if (name(assdest) == name_tag && !iscaonly(son(assdest)))
151
	    allow_double = 0;	/* prevent removal of internal test; perhaps assigning to limit */
152
	};
153
        return uc_list (son (e), n - decr, control, lia, ul, decr);
154
      };
155
    case name_tag:
156
      if (son (e) == control) { /* is this the control variable? */
157
	exp t;
158
	if (!last (e) || name (bro (e)) != cont_tag)
159
	  allow_double = 0;	/* any use but contents -> no test elim */
160
	else {	/* it is a cont */
161
	  t = bro (e);
162
#if isalpha
163
	  if (!last(t) || name(bro(t)) != chvar_tag ||
164
	      last (bro(t)) || name (bro(bro (t))) != val_tag || !last (bro (bro(t))) ||
165
	      name (bro (bro (bro(t)))) != offset_mult_tag)
166
	    allow_double = 0;	/* not offset_mult -> no test elim */
167
	  else
168
	    names[names_index++] = bro(e);	/* record the use */
169
#else
170
	  if (last (t) || name (bro (t)) != val_tag || !last (bro (t)) ||
171
	      name (bro (bro (t))) != offset_mult_tag)
172
	    allow_double = 0;	/* not offset_mult -> no test elim */
173
	  else
174
	    names[names_index++] = bro(e);	/* record the use */
175
#endif
176
	};
177
      };
178
      return n - decr;
179
    case apply_tag:
180
    case solve_tag:
181
      return - 1;	/* no unroll */
182
    case case_tag:
183
      return unroll_complex (son (e), n - decr, control, lia, ul, decr);
184
    case string_tag:
185
    case env_offset_tag:
186
    case general_env_offset_tag:
187
      return n - decr;	/* decrease the complexity count */
188
    case top_tag:
189
    case prof_tag:
190
    case clear_tag:
191
      return n;
192
    case labst_tag:
193
      return unroll_complex (bro (son (e)), n, control, lia, ul, decr);
194
    case seq_tag:
195
      return uc_list (son (e), n, control, lia, ul, decr);
196
    case round_tag:
197
    case fplus_tag:
198
    case fminus_tag:
199
    case fmult_tag:
200
    case fdiv_tag:
201
    case fabs_tag:
202
    case fneg_tag:
203
    case fpower_tag:
204
    case fmax_tag:
205
    case fmin_tag:
206
    case float_tag:
207
    case chfl_tag:
208
      return uc_list (son (e), n - (16*decr), control, lia, ul, decr);	/* heavy flpt ops */
209
    default:
210
      return uc_list (son (e), n - decr, control, lia, ul, decr);	/* other ops decrease complexity by 1 */
211
  };
212
}
213
 
214
void simple_unroll
215
    PROTO_N ( (candidate, body, inc, te) )
216
    PROTO_T ( exp candidate X exp body X exp inc X exp te )
217
{
218
    /* candidate = rep_tag */
219
    /* body = repeated statement less label, assignment and test */
220
    /* inc = the single assignment to the control variable */
221
    /* te = the final test - only jump to repeat label */
222
    exp second_body = copy (body);	/* repeated statement less label, assignment and test */
223
    exp second_inc = copy (inc);	/* assignment to control */
224
    exp second_test = copy (te);
225
    exp z = getexp (f_top, te, 0, nilexp, nilexp, 0, 0, 0);
226
    exp seq = getexp (f_top, bro (son (candidate)), 1,
227
        z, nilexp, 0, 0, seq_tag);
228
    exp cond_labst;
229
    exp cl1, mt;
230
    exp cond, f;
231
    exp * point;
232
    float freq = fno(bro(son(candidate)));
233
 
234
    no (son (bro (son (candidate))))--;	/* decrease label count (increased by copy(te)) */
235
 
236
    setlast (second_inc);
237
    bro (second_inc) = z;
238
    clearlast (second_body);
239
    bro (second_body) = second_inc;
240
    clearlast (second_test);
241
    bro (second_test) = second_body;
242
    clearlast (inc);
243
    bro (inc) = second_test;
244
    clearlast (body);
245
    bro (body) = inc;
246
    son (z) = body;
247
    setlast (te);
248
    bro (te) = seq;
249
    bro (son (bro (son (candidate)))) = seq;
250
 
251
/*
252
candidate
253
	rep
254
	x	labst
255
		1 use	seq
256
 
257
			body	inc	second_test	second_body	second_inc
258
*/
259
 
260
    cond_labst = getexp (f_top, nilexp, 1, nilexp, nilexp,
261
			 0, 0, labst_tag);
262
    fno(cond_labst) = (float) (freq / 20.0);
263
    mt = getexp (f_top, cond_labst, 1, nilexp, nilexp, 0, 0, top_tag);
264
    cl1 = getexp (f_top, mt, 0, nilexp, nilexp, 0, 1, clear_tag);
265
    son (cond_labst) = cl1;
266
 
267
    pt (second_test) = cond_labst;
268
    settest_number (second_test,
269
		   (int)int_inverse_ntest[test_number (te)]);
270
 
271
    cond = getexp (f_top, bro (candidate), (int)(last (candidate)),
272
        candidate, nilexp, 0, 0, cond_tag);
273
    bro (cond_labst) = cond;
274
 
275
    f = father (candidate);
276
    point = refto (f, candidate);
277
    *point = cond;
278
 
279
    clearlast (candidate);
280
    bro (candidate) = cond_labst;
281
 
282
/*
283
cond
284
	cond
285
	rep				labst(ln)
286
	x	labst			1 use	top
287
		1 use	seq
288
 
289
			body	inc	second_test(invert, ln)	second_body	second_inc
290
 
291
*/
292
 
293
    setunrolled (candidate);
294
    return;
295
}
296
 
297
static exp inc_offset
298
    PROTO_N ( (var, sha, konst, body, i) )
299
    PROTO_T ( exp var X shape sha X exp konst X exp body X int i )
300
{
301
  exp sum, t;
302
  exp id = son(var);
303
  exp rest = pt(id);
304
  body = copy(body);
305
  if (names_index > 0) {	/* count of offset_mult uses of control variable */
306
    t = pt(id);
307
    sum = me_u3(sha, copy(var), cont_tag);
308
    sum = hold_check(me_b3(sha, sum,
309
	  		     me_shint(sha, i*no(konst)), plus_tag));	/* variable + i */
310
 
311
    for (i = 0; i < names_index; ++i) {
312
      exp q = pt(t);
313
      exp b = bro(t);
314
      replace(bro(t), copy(sum), body);	/* replace the offset_mults in body */
315
      kill_exp(b, b);
316
      t = q;
317
    };
318
    if (t != rest)
319
      failer("unroll failure");
320
 
321
    kill_exp(sum, sum);
322
  };
323
  return body;
324
}
325
 
326
void unroll_trans
327
    PROTO_N ( (candidate, body, inc, te, limit, nt, var, konst, reps, times) )
328
    PROTO_T ( exp candidate X exp body X exp inc X exp te X exp limit X
329
	      int nt X exp var X exp konst X exp reps X int times )
330
{
331
  /* candidate = rep_tag */
332
  /* body = repeated statement less label, assignment and test */
333
  /* inc = the single assignment to the control variable */
334
  /* te = the final test - only jump to repeat label */
335
  /* limit = the limit exp */
336
  /* nt = the test number */
337
  /* var = name_tag for control variable */
338
  /* konst = the value added to the control variable */
339
  /* reps = current element of the repeat list */
340
  /* times = no of times to unroll */
341
  float freq = fno(bro(son(candidate)));
342
  if (allow_double && no(konst) == 1 && 	/* allow_double==0 prevents test elimination */
343
      (nt == (int)f_greater_than || nt == (int)f_greater_than_or_equal) &&
344
		/* the permitted tests - we are counting upwards */
345
      ((name(limit) == name_tag && !isvar(son(limit))) ||
346
	 name(limit) == val_tag ||
347
	(name(limit) == cont_tag && name(son(limit)) == name_tag &&
348
	    isvar(son(son(limit)))))	/* permitted forms of limit */
349
      ) {
350
		/* unroll and remove the internal increment and test */
351
 
352
    int i;
353
    shape sha = sh(konst);
354
    exp branches [UNROLL_MAX + 2];	/* 0 - (times-2) are preliminaries
355
					   (times-1) is test out
356
					   times is the loop
357
					   (times+1) is the end */
358
    exp test_out = copy(te);		/* used to jump out after < times */
359
    exp temp, temp1, bc, repeater, lrep, res, id, temp2;
360
    exp new_c = me_shint(sha, times*no(konst));	/* used to increment the control variable */
361
 
362
    settest_number(test_out,
363
		   (int)int_inverse_ntest[test_number(test_out)]);
364
 
365
    for (i = 0; i < times + 2; ++i) {	/* set up labst for branches */
366
      exp lia = me_shint(sha, (((i > 1) && (i < (times-1))) || i >= times) ? 2: 1);
367
      exp li = getexp(f_bottom, nilexp, 0, lia, nilexp, 0, 0, labst_tag);
368
      fno(li) = (float) (freq / 20.0);
369
      name(lia) = clear_tag;
370
      clearlast(lia);
371
      branches[i] = li;
372
    };
373
    SET(branches);
374
    sh(branches[times+1]) = f_top;
375
 
376
 
377
    for (i = 0; i < times - 1; ++ i) {	/* set up preliminaries */
378
      exp sub = me_b3(f_top, copy(body), copy(inc), 0);
379
      exp seq = me_b3(f_bottom, sub,
380
		 getexp(f_bottom, nilexp, 0, nilexp, branches[i+1], 0, 0, goto_tag), seq_tag);
381
      bro(son(branches[i])) = seq;
382
      setlast(seq);
383
      bro(seq) = branches[i];
384
    };
385
 
386
    pt(test_out) = branches[times+1];
387
    temp = me_u3(f_top, test_out, 0);
388
    temp = me_b3(f_bottom, temp,
389
		 getexp(f_bottom, nilexp, 0, nilexp, branches[times], 0, 0, goto_tag), seq_tag);
390
    bro(son(branches[times-1])) = temp;
391
    setlast(temp);
392
    bro(temp) = branches[times-1];
393
 
394
    temp = copy(body);
395
    temp1 = temp;
396
    if (jumps_out) {
397
      bro(temp1) = copy(inc);
398
      clearlast(temp1);
399
      temp1 = bro(temp1);
400
    };
401
    for (i = 1; i < times - 1; ++i) {
402
      if (jumps_out)
403
	bro(temp1) = copy(body);
404
      else
405
        bro(temp1) = inc_offset(var, sha, konst, body, i);
406
      clearlast(temp1);
407
      temp1 = bro(temp1);
408
      if (jumps_out) {
409
	bro(temp1) = copy(inc);
410
        clearlast(temp1);
411
        temp1 = bro(temp1);
412
      };
413
    };
414
    bc = getexp(f_top, nilexp, 0, temp, nilexp, 0, 0, 0);
415
    setlast(temp1);
416
    bro(temp1) = bc;
417
    if (jumps_out)
418
      bc = me_b3(f_top, bc, copy(body), seq_tag);
419
    else {
420
      bc = me_b3(f_top, bc, inc_offset(var, sha, konst, body, i), seq_tag);
421
      kill_exp(body, body);
422
    };
423
 
424
    if (jumps_out)
425
      kill_exp(new_c, new_c);
426
    else
427
      replace(bro(son(bro(var))), new_c, new_c);	/* replace konst by times*konst */
428
 
429
    temp = me_b3(f_top, bc, inc, 0);
430
    temp = me_b3(f_top, temp, te, seq_tag);
431
    lrep = me_b3(f_top, me_shint(sha, 1), temp, labst_tag);
432
    fno(lrep) = freq / (float)times;
433
    name(son(lrep)) = clear_tag;
434
    repeater = me_b3(f_top, f_make_top(), lrep, rep_tag);
435
    son(reps) = repeater;
436
    pt(te) = lrep;	/* label in repeater */
437
    pt(test_out) = branches[times+1];
438
 
439
    temp = f_make_top();
440
    bro(son(branches[times+1])) = temp;
441
    setlast(temp);
442
    bro(temp) = branches[times+1];
443
 
444
    temp = me_u3(f_top, repeater, 0);
445
    temp = me_b3(f_bottom, temp,
446
		 getexp(f_bottom, nilexp, 0, nilexp, branches[times+1], 0, 0, goto_tag), seq_tag);
447
    bro(son(branches[times])) = temp;
448
    setlast(temp);
449
    bro(temp) = branches[times];
450
 
451
    temp = me_u3(sha, copy(var), cont_tag);
452
    temp1 = copy(limit);
453
    sh(temp1) = sha;
454
    temp = hold_check(me_b3(sha, temp1, temp, minus_tag));
455
    if (nt == (int)f_greater_than) {
456
      temp = hold_check(me_b3(sha, temp, me_shint(sha, 1), plus_tag));
457
    };
458
    temp = hold_check(me_b3(sha, temp,
459
				 me_shint(sha, times-1), and_tag));
460
 
461
    id = me_startid(sha, temp, 0);
462
    temp = getexp(f_top, nilexp, 0, me_obtain(id), branches[times], 0, 0, test_tag);
463
    settest_number(temp, f_not_equal);
464
    bro(son(temp)) = me_shint(sha, 0);
465
    setlast(bro(son(temp)));
466
    bro(bro(son(temp))) = temp;
467
    temp1 = temp;
468
 
469
    for (i = 1; i < (times-1); ++i) {
470
      temp2 = getexp(f_top, nilexp, 0, me_obtain(id), branches[times-i-1], 0, 0, test_tag);
471
      settest_number(temp2, f_not_equal);
472
      bro(son(temp2)) = me_shint(sha, i);
473
      setlast(bro(son(temp2)));
474
      bro(bro(son(temp2))) = temp2;
475
      settest_number(temp, f_not_equal);
476
      clearlast(temp1);
477
      bro(temp1) = temp2;
478
      temp1 = temp2;
479
    };
480
 
481
    bc = getexp(f_top, nilexp, 0, temp, nilexp, 0, 0, 0);
482
    setlast(temp1);
483
    bro(temp1) = bc;
484
    bc = me_b3(f_bottom, bc,
485
	 getexp(f_bottom, nilexp, 0, nilexp, branches[0], 0, 0, goto_tag), seq_tag);
486
    id = me_complete_id(id, bc);
487
 
488
    temp1 = id;
489
    for (i = 0; i < (times+2); ++i) {
490
      bro(temp1) = branches[i];
491
      clearlast(temp1);
492
      temp1 = bro(temp1);
493
    };
494
    res = getexp(f_top, nilexp, 0, id, nilexp, 0, 0, solve_tag);
495
    setlast(temp1);
496
    bro(temp1) = res;
497
    setunrolled(repeater);
498
 
499
    replace(candidate, res, res);
500
  }
501
#if is80x86
502
  else
503
    simple_unroll (candidate, body, inc, te);
504
#endif
505
  return;
506
}
507
 
508
void unroller
509
    PROTO_Z ()
510
{
511
  exp reps = repeat_list;
512
  exp candidate;
513
  exp labst;
514
  exp rb;
515
 
516
 
517
  while (reps != nilexp) {
518
    if (no (reps) == 0 && son (reps) != nilexp &&
519
	name (son (reps)) == rep_tag) {
520
      /* this is a leaf repeat node */
521
      candidate = son (reps);	/* this is the repeat */
522
      labst = bro (son (candidate));	/* the repeated statement */
523
      rb = bro (son (labst));	/* the repeated statement less label */
524
 
525
      if (name (son (candidate)) == top_tag &&
526
	  no (son (labst)) == 1 &&
527
	  name (rb) == seq_tag &&
528
	  name (bro (son (rb))) == seq_tag) {
529
/*
530
 
531
	rep_tag
532
	top_tag	labst_tag
533
		count		seq_tag
534
 
535
 
536
*/
537
	exp final = bro (son (rb));
538
	exp body = son (son (rb));
539
	exp ass = son (son (final));
540
	exp te = bro (son (final));
541
	if (name (ass) == ass_tag && name (te) == test_tag) {
542
/*
543
 
544
	rep_tag
545
	top_tag	labst_tag
546
		count		seq_tag
547
 
548
				body	0	test_tag = te
549
					ass_tag = ass
550
 
551
*/
552
	  exp dest = son (ass);
553
	  exp val = bro (dest);
554
	  if (name (dest) == name_tag && isvar (son (dest)) &&
555
	      iscaonly (son (dest)) && shape_size (sh (val)) == 32) {
556
/*
557
 
558
	rep_tag
559
	top_tag	labst_tag
560
		count		seq_tag
561
 
562
				body	0	test_tag = te
563
					ass_tag = ass
564
					name = dest	val (32)
565
					var & ca
566
*/
567
	    if (name (val) == plus_tag && name (son (val)) == cont_tag &&
568
		name (son (son (val))) == name_tag &&
569
		son (son (son (val))) == son (dest) &&
570
		name (bro (son (val))) == val_tag) {
571
/*
572
 
573
	rep_tag
574
	top_tag	labst_tag
575
		count		seq_tag
576
 
577
				body	0	test_tag = te
578
					ass_tag = ass
579
					name = dest	plus_tag =val (32)
580
					var & ca	cont_tag	val_tag
581
							name_tag -> dest
582
*/
583
	      exp konst = bro (son (val));
584
	      int   nt = (int)test_number (te);
585
	      if (name (son (te)) == cont_tag &&
586
		  name (son (son (te))) == name_tag &&
587
		  pt (te) == labst &&
588
		  son (son (son (te))) == son (dest)) {
589
/*
590
 
591
	rep_tag
592
	top_tag	labst_tag
593
		count	seq_tag
594
 
595
			body	0					test_tag(nt, labst) = te
596
				ass_tag = ass				cont_tag
597
				name = dest	plus_tag =val (32)	name_tag -> dest
598
				var & ca	cont_tag val_tag = konst
599
						name_tag -> dest
600
*/
601
		int   count;
602
		exp limit = bro(son(te));
603
		exp unaliased_limit = nilexp;
604
		int limit_is_aliased = 0;
605
 
606
		if (name(limit) == cont_tag &&
607
			name(son(limit)) == name_tag &&
608
			isvar(son(son(limit)))) {
609
/*
610
 
611
	rep_tag
612
	top_tag	labst_tag
613
		count	seq_tag
614
 
615
			body	0					test_tag(nt, labst) = te
616
				ass_tag = ass				cont_tag	cont_tag = limit
617
				name = dest	plus_tag =val (32)	name_tag -> dest
618
				var & ca	cont_tag val_tag = konst
619
						name_tag -> dest
620
*/
621
		  if (iscaonly(son(son(limit))))
622
		    unaliased_limit = son(son(limit));
623
		  else
624
		    limit_is_aliased = 1;
625
		};
626
 
627
		names_index = 0;
628
		allow_double = 1;
629
		jumps_out = 0;
630
		count = unroll_complex (body, LIMIT, son (dest),
631
				limit_is_aliased, unaliased_limit, 1);
632
		if (count >= 0) {
633
		  unroll_trans (candidate, body, ass, te,
634
				limit, nt, dest, konst, reps, UNROLL_BY);
635
		};
636
	      };
637
	    }
638
	    else {
639
	      int count;
640
	      names_index = 0;
641
	      allow_double = 0;
642
	      count = unroll_complex (body, SIMPLE_LIMIT, nilexp,
643
				0, nilexp, 1);
644
	      if (count >= 0) {
645
	        simple_unroll(candidate, body, ass, te);
646
	      };
647
  	    };
648
	  };
649
	}
650
      };
651
    };
652
    reps = pt (reps);
653
  };
654
  return;
655
}