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
$Log: locate.c,v $
33
 * Revision 1.1.1.1  1998/01/17  15:56:03  release
34
 * First version to be checked into rolling release.
35
 *
36
 * Revision 1.2  1995/12/18  13:11:48  wfs
37
 * Put hppatrans uder cvs control. Major Changes made since last release
38
 * include:
39
 * (i) PIC code generation.
40
 * (ii) Profiling.
41
 * (iii) Dynamic Initialization.
42
 * (iv) Debugging of Exception Handling and Diagnostics.
43
 *
44
 * Revision 5.1  1995/09/15  12:38:58  wfs
45
 * Minor changes to stop gcc compiler from complaining.
46
 *
47
 * Revision 5.0  1995/08/25  13:42:58  wfs
48
 * Preperation for August 25 Glue release
49
 *
50
 * Revision 3.4  1995/08/25  09:48:02  wfs
51
 * register synonyms changed. additional cases in "boff" to deal
52
 * with the offsets of callees
53
 *
54
 * Revision 3.4  1995/08/25  09:48:02  wfs
55
 * register synonyms changed. additional cases in "boff" to deal
56
 * with the offsets of callees
57
 *
58
 * Revision 3.1  95/04/10  16:27:08  16:27:08  wfs (William Simmonds)
59
 * Apr95 tape version.
60
 * 
61
 * Revision 3.0  95/03/30  11:18:03  11:18:03  wfs (William Simmonds)
62
 * Mar95 tape version with CRCR95_178 bug fix.
63
 * 
64
 * Revision 2.0  95/03/15  15:27:51  15:27:51  wfs (William Simmonds)
65
 * spec 3.1 changes implemented, tests outstanding.
66
 * 
67
 * Revision 1.2  95/01/17  17:26:13  17:26:13  wfs (William Simmonds)
68
 * Changed name of an included header file
69
 * 
70
 * Revision 1.1  95/01/11  13:11:08  13:11:08  wfs (William Simmonds)
71
 * Initial revision
72
 * 
73
*/
74
 
75
 
76
#define HPPATRANS_CODE
77
/* locate.c
78
     discovers "where" an "exp" is;
79
     The where coding of an address tells one whether the result of
80
      evaluating an exp is in a register or directly or literally in store,
81
*/
82
 
83
#include "config.h"
84
#include "myassert.h"
85
#include "addrtypes.h"
86
#include "expmacs.h"
87
#include "tags.h"
88
#include "inst_fmt.h"
89
#include "regmacs.h"
90
#include "hppains.h"
91
#include "bitsmacs.h"
92
#include "exp.h"
93
#include "procrec.h"
94
#include "guard.h"
95
#include "eval.h"
96
#include "regexps.h"
97
#include "shapemacs.h"
98
#include "comment.h"
99
#include "getregs.h"
100
#include "move.h"
101
#include "regable.h"
102
#include "codehere.h"
103
#include "proc.h"
104
#include "frames.h"
105
 
106
#include "common_types.h"
107
 
108
#include "locate.h"
109
 
110
 
111
/* decodes x to give a baseoff suitable for xxxx_ins functions */
112
baseoff boff 
113
    PROTO_N ( ( e ) )
114
    PROTO_T ( exp e )
115
{
116
 
117
  int n = no(e);
118
  int b = n & 0x3f;
119
  baseoff an;
120
 
121
  if (isglob(e))
122
  {
123
    /* bro() is index in main_globals */
124
    dec *gl = brog(e);
125
    long sno = gl->dec_u.dec_val.sym_number;
126
    an.base = -(sno + 1);
127
    an.offset = 0;
128
  }
129
  else if (name(son(e))==caller_name_tag)
130
  {
131
     int n = no(e);
132
     an.base = SP;
133
     an.offset = -(n>>3);
134
  }
135
  else if (isparam(e))
136
  {
137
     /* parameter */
138
     assert(name(son(e)) == clear_tag);
139
     if (Has_vcallees)
140
     {
141
	an.base = FP;
142
     }
143
     else
144
     {
145
	an.base = EP;
146
     }
147
     if (name(son(e))==formal_callee_tag)
148
     {
149
	an.offset=(no(son(e))-callees_offset)>>3;/* outermost ()'s for gcc */
150
     }
151
     else
152
     {
153
	an.offset=(-no(son(e))-params_offset)>>3;/* outermost ()'s for gcc */
154
     }
155
  }
156
  else if (b == GR17)
157
  {
158
     /* locally declared */
159
     an.base = EP; 
160
     an.offset = ((n-b)>>4)-(locals_offset>>3); 
161
  }
162
  else if (b == EP)
163
  {
164
    /* on stack temps (should not happen) */
165
    an.base = EP;
166
    an.offset = (n - b) >> 4;
167
  }
168
  else if (b <= 31)
169
  {
170
    /* other base reg and offset */
171
    an.base = b;
172
    an.offset = ((n - b) >> 4);
173
  }
174
#if 1
175
  /* +++ obsolete */
176
  else if (b == 32)
177
  {
178
    /* global names */
179
    an.base = -((n - b) >> 6);
180
    an.offset = 0;
181
  }
182
  else if (b == 33)
183
  {
184
    /* local data label: LDNNNN */
185
    an.base = (n - b) >> 6;
186
    an.offset = 0;
187
  }
188
#endif
189
  else
190
  {
191
    comment3("baseoff: n=%lx, b=%d, n>>4=%ld", n, b, n >> 4);
192
    fail("not a baseoff in boff");
193
  }
194
  FULLCOMMENT2("baseoff: base=%d off=%d", an.base, an.offset);
195
  return an;
196
}
197
 
198
 
199
 /*
200
  * locate differs from locate1 only in that it looks to see e has already
201
  * been evaluated somehow
202
  */
203
where locate PROTO_S ( ( exp, space, shape, int ) ) ;
204
 
205
 
206
 /*
207
  * finds the address of e using shape s; sp gives available t-regs for any
208
  * inner evaluation. dreg is historical.
209
  */
210
where locate1 
211
    PROTO_N ( ( e, sp, s, dreg ) )
212
    PROTO_T ( exp e X space sp X shape s X int dreg )
213
{
214
  ash a;
215
  ans aa;
216
  where wans;
217
#if 0				/* causes core dump spec/espresso/set.c */
218
  FULLCOMMENT3("locate1: %s, %s, dreg=%d", (int)tag_name(name(e)), (int)sh_name(name(s)), dreg);
219
  FULLCOMMENT4("        space=(%ld,%ld) no(e)=%d no(son(e))=%d", sp.fixed, sp.flt, no(e), no(son(e)));
220
#endif
221
 
222
  a = ashof(s);
223
 
224
/*
225
  while (name(e) == diag_tag || name(e) == fscope_tag || name(e) == cscope_tag)
226
  {
227
    e = son(e);
228
  }
229
*/
230
  switch (name(e))
231
  {
232
  case name_tag:
233
    {
234
      exp dc = son(e);
235
      bool var = isvar(dc);
236
 
237
      /* this a locally declared name ... */
238
      if (props(dc) & defer_bit)
239
      {
240
 
241
	/*
242
	 * ... it has been identified with a simple expression which is better
243
	 * evaluated every time
244
	 */
245
	where w;
246
 
247
	FULLCOMMENT("locate1: name_tag: defer_bit");
248
 
249
	w = locate(son(dc), sp, sh(son(dc)), dreg);
250
 
251
	if (no(e) == 0)
252
	{
253
	  aa = w.answhere;
254
	}
255
	else
256
	{
257
	  instore is;
258
 
259
	  switch ( discrim ( w.answhere ) )
260
	  {
261
	  case notinreg:
262
	    {
263
	      is = insalt(w.answhere);
264
	      is.b.offset += (no(e) / 8);
265
	      break;
266
	    }
267
	  default:
268
	    fail("name not deferable");
269
	  }
270
 
271
	  setinsalt(aa, is);
272
	}
273
      }
274
      else if (props(dc) & inreg_bits)
275
      {
276
	/* ... it has been allocated in a fixed point reg */
277
 
278
	FULLCOMMENT1("locate1: name_tag: fixed point reg%s", (int) (var?" var":""));
279
 
280
	if (var)
281
	{
282
	  setregalt(aa, no(dc));
283
	}
284
	else
285
	{
286
	  instore b;
287
 
288
	  b.b.base = no(dc);
289
	  b.b.offset = 0;
290
	  b.adval = 1;
291
	  setinsalt(aa, b);
292
	}
293
      }
294
      else if (props(dc) & infreg_bits)
295
      {
296
	/* ... it has been allocated in a floating point reg */
297
 
298
	freg fr;
299
 
300
	FULLCOMMENT("locate1: name_tag: fixed point reg");
301
 
302
	fr.fr = no(dc);
303
	fr.dble = ( a.ashsize==64 ? 1 : 0 );
304
	setfregalt(aa, fr);
305
      }
306
      else
307
      {
308
	/* ... it is in memory */
309
	instore is;
310
 
311
	if ( var || (name(sh(e)) == prokhd &&
312
		    (son(dc) == nilexp || IS_A_PROC(son(dc)) )))
313
	{
314
	  is.adval = 1;
315
	}
316
	else
317
	{
318
	  is.adval = 0;
319
	}
320
	is.b = boff(dc);
321
#if USE_BITAD
322
	if (a.ashalign == 1 && (var || name(sh(e)) != ptrhd))
323
	  /* some bit field */
324
	{
325
	  is.b.offset = (is.b.offset << 3) + no(e);
326
	  setbitadalt(aa, is);
327
	}
328
	else
329
#endif
330
	{
331
	  is.b.offset += (no(e) / 8);
332
	  setinsalt(aa, is);
333
	}
334
      }
335
      wans.answhere = aa;
336
      wans.ashwhere = a;
337
      return wans;
338
    }
339
 
340
  case addptr_tag:
341
    {
342
      exp sum = son(e);
343
      where wsum;
344
      int addend;
345
      space nsp;
346
      int reg;
347
      int ind = R_NO_REG;
348
      instore is;
349
      ans asum;
350
      int shift;
351
 
352
      wsum = locate(sum, sp, sh(sum), 0);
353
      asum = wsum.answhere;
354
 
355
      /*
356
       * answer is going to be wsum displaced by integer result of evaluating
357
       * bro(sum)
358
       */
359
 
360
      switch (discrim ( asum ) )
361
      {
362
      case notinreg:
363
	{
364
	  is = insalt(asum);
365
	  if (is.adval)
366
	  {
367
	    /* wsum is a literal address in store ... */
368
	    baseoff b;
369
 
370
	    b = is.b;
371
	    if (!IS_FIXREG(b.base))
372
	    {
373
	      /* ... it is not a base-offset , so make it one */
374
 
375
	      reg = getreg(sp.fixed);
376
	      set_ins("",b, reg);
377
	      keepreg(sum, reg);
378
	      b.base = reg;
379
	      b.offset = 0;
380
 
381
	    }
382
 
383
	    nsp = guardreg(b.base, sp);
384
 
385
	    shift=no(bro(son(bro(sum))));
386
	    if ( name(bro(sum))==offset_mult_tag && name(bro(son(bro(sum))))==val_tag && ( shift==0 || shift==2 || shift==4 ) )
387
	    {
388
	       addend=reg_operand(son(bro(sum)),nsp);
389
	       if (dreg == 0)
390
		  dreg = getreg(nsp.fixed);
391
	       rrr_ins(shift==0 ? i_add : (shift==2 ? i_sh1add : i_sh2add),                           c_,addend,b.base,dreg);
392
	    }
393
	    else
394
	    {
395
	       addend = reg_operand(bro(sum), nsp);
396
	       /* evaluate the displacement ... */
397
	       if (dreg == 0)
398
		  dreg = getreg(nsp.fixed);
399
	       rrr_ins(i_add,c_,b.base,addend,dreg);
400
	    }
401
 
402
	    clear_reg(dreg);
403
 
404
	    /* ... add it to the base register into new reg */
405
	    b.base = dreg;
406
	    is.b = b;
407
	    setinsalt(aa, is);
408
	    wans.answhere = aa;
409
	    wans.ashwhere = a;
410
 
411
	    /* ...and use it as base a literal base-offset result */
412
	    keepexp(e, aa);
413
	    return wans;
414
	  }
415
	  else
416
	  {
417
	     /* wsum represents an actual pointer in store... */
418
	     /* ... so load it into a good register */
419
	     ind = getreg(sp.fixed);
420
	     ld_ins(i_lw,1,is.b,ind);
421
	  }
422
	  break;
423
	}			/* end notinreg */
424
 
425
      case inreg:
426
	{
427
	  /* wsum is already in reg */
428
	  ind = regalt(asum);
429
	  break;
430
	}
431
 
432
      default:
433
	{
434
	  fail("locate ? reg");
435
	}
436
      }				/* end case */
437
 
438
      /* register ind contains the evaluation of 1st operand of addptr */
439
      nsp = guardreg(ind, sp);
440
      /* evaluate displacement, add it to ind in new reg */
441
      if (name(bro(sum)) == env_offset_tag ||
442
	  name(bro(sum)) == general_env_offset_tag)
443
      {
444
	  is.b.base = ind;
445
	  is.b.offset = frame_offset(son(bro(sum)));
446
      } 
447
      else
448
      {
449
	 shift=no(bro(son(bro(sum))));
450
	 if ( name(bro(sum))==offset_mult_tag && name(bro(son(bro(sum))))==val_tag && ( shift==0 || shift==2 || shift==4 ) )
451
	 {
452
	    addend=reg_operand(son(bro(sum)),nsp);
453
	    if (dreg == 0)
454
	       dreg = getreg(nsp.fixed);
455
	    rrr_ins(shift==0 ? i_add : (shift==2 ? i_sh1add : i_sh2add),                           c_,addend,ind,dreg);
456
	 }
457
	 else
458
	 {
459
	    addend = reg_operand(bro(sum), nsp);
460
 
461
	    if (dreg == 0)
462
	       dreg = getreg(nsp.fixed);
463
	    rrr_ins(i_add,c_,ind,addend,dreg);
464
	 }
465
	 is.b.base = dreg;
466
	 is.b.offset = 0;
467
      }
468
      is.adval = 1;
469
      setinsalt(aa, is);
470
      wans.answhere = aa;
471
      wans.ashwhere = a;
472
      /* ... and deliver literal base_offset */
473
      keepexp(e, aa);
474
      return wans;
475
    }				/* end add_ptr */
476
 
477
  case subptr_tag:		/* this is nugatory - previous transforms make
478
				 * it into addptr or reff */
479
    {
480
      exp sum = son(e);
481
      int ind = reg_operand(sum, sp);
482
      instore isa;
483
 
484
      isa.adval = 1;
485
      sum = bro(sum);
486
      if (name(sum) == val_tag)
487
      {
488
	instore isa;
489
 
490
	isa.b.base = ind;
491
	isa.b.offset = -no(e);
492
	setinsalt(aa, isa);
493
      }
494
      else
495
      {
496
	if (dreg == 0)
497
	   dreg = getreg(sp.fixed);
498
	rrr_ins(i_sub,c_,ind,reg_operand(sum,guardreg(ind,sp)),dreg);
499
	isa.b.base = dreg;
500
	isa.b.offset = 0;
501
      }
502
      setinsalt(aa, isa);
503
      wans.answhere = aa;
504
      wans.ashwhere = a;
505
      keepexp(e, aa);
506
      return wans;
507
    }				/* end subptr */
508
 
509
  case reff_tag:
510
    {
511
      instore isa;
512
#if USE_BITAD
513
      bool bitfield = 0;
514
#endif
515
 
516
      /* answer is going to be wans displaced by no(e) */
517
      wans = locate(son(e), sp, sh(son(e)), 0);
518
 
519
#if USE_BITAD
520
      bitfield = ((name(sh(e)) == ptrhd) && (al1(sh(e)) == 1));
521
#endif
522
      switch ( discrim ( wans.answhere ) )
523
      {
524
      case notinreg:
525
	{
526
	  isa = insalt(wans.answhere);
527
	  if (!isa.adval)
528
	  {
529
 
530
	    /*
531
	     * wans is an actual pointer  in store, so make it into a literal
532
	     * address....
533
	     */
534
	    int reg = getreg(sp.fixed);
535
 
536
	    ld_ins(i_lw,0,isa.b,reg);
537
	    isa.b.offset = 0;
538
	    isa.b.base = reg;
539
	    isa.adval = 1;
540
	  }
541
 
542
	  /*  ... and add appropriate displacement to give result  */
543
 
544
#if USE_BITAD
545
	  if (bitfield)
546
	  {
547
	    isa.b.offset <<= 3;
548
	    isa.b.offset += no(e);
549
	    setbitadalt(wans.answhere, isa);
550
	  }
551
	  else
552
#endif
553
	  {
554
	    isa.b.offset += no(e) / 8;
555
	    setinsalt(wans.answhere, isa);
556
	    keepexp(e, wans.answhere);
557
	  }
558
       	  break ;
559
	}
560
#if USE_BITAD
561
      case bitad:
562
	{
563
	  isa = bitadalt(wans.answhere);
564
	  if (!isa.adval)
565
	  {
566
	    fail("no var bit selection");
567
	  }
568
	  /* wans is a literal bit address */
569
	  isa.b.offset += no(e);
570
	  setbitadalt(wans.answhere, isa);
571
	  break;
572
	}
573
#endif
574
      case inreg:
575
	{
576
	  /* wans is a pointer in a register */
577
	  isa.b.base = regalt(wans.answhere);
578
	  isa.adval = 1;
579
#if USE_BITAD
580
	  if (bitfield)
581
	  {
582
	    isa.b.offset = no(e);
583
	    setbitadalt(wans.answhere, isa);
584
	  }
585
	  else
586
#endif
587
	  {
588
	    isa.b.offset = BITS2BYTES(no(e));
589
	    setinsalt(wans.answhere, isa);
590
	  }
591
	  break;
592
	}
593
      default:
594
	{
595
	  fail("locate ? reg ");
596
	}
597
      }
598
      wans.ashwhere = a;
599
      return wans;
600
    }				/* end reff */
601
 
602
  case cont_tag:
603
  case contvol_tag:
604
    {
605
      exp s = son(e);
606
      ans ason;
607
      instore isa;
608
      int reg;
609
      where fc;
610
 
611
      fc = locate(s, sp, sh(e), 0);
612
      ason = fc.answhere;
613
 
614
      /*
615
       * answer is going to be the contents of address represented by fc
616
       */
617
 
618
      FULLCOMMENT1("locate1: cont[vol]_tag: %s", (int)ANSDISCRIM_NAME( discrim ( ason ) ));
619
 
620
      switch ( discrim ( ason ) )
621
      {
622
      case notinreg:
623
	{
624
	  isa = insalt(ason);
625
	  if (isa.adval)
626
	  {
627
	    /* literal store address, so make it into a direct one */
628
	    FULLCOMMENT("locate1: cont[vol]_tag: literal store address");
629
	    isa.adval = 0;
630
	    setinsalt(aa, isa);
631
	  }
632
	  else
633
	  {
634
 
635
	    /*
636
	     * actual pointer in store so load it into reg and deliver direct
637
	     * base-offset (reg,0)
638
	     */
639
	    FULLCOMMENT("locate1: cont[vol]_tag: ptr in store");
640
	    reg = getreg(sp.fixed);
641
	    ld_ins(i_lw,1,isa.b,reg);
642
	    isa.b.base = reg;
643
	    isa.b.offset = 0;
644
	    setinsalt(aa, isa);
645
	    if (name(e) != contvol_tag && fc.ashwhere.ashalign != 1)
646
	      keepexp(e, aa);
647
	  }
648
#if USE_BITAD
649
	  if (fc.ashwhere.ashalign == 1)	/* ... adjust for bit contents */
650
	  {
651
	    isa.b.offset <<= 3;
652
	    setbitadalt(aa, isa);
653
	  }
654
#endif
655
	  goto breakson;
656
 
657
	}			/* end notinrg */
658
 
659
      case inreg:
660
 
661
	/*
662
	 * this one is fraught - it depends on only being used in lh-value
663
	 * positions from vars - take care
664
	 */
665
	{
666
	  isa.b.base = regalt(ason);
667
	  isa.b.offset = 0;
668
	  isa.adval = 1;
669
#if USE_BITAD
670
	  if (a.ashalign == 1)
671
	  {
672
	    setbitadalt(aa, isa);
673
	  }
674
	  else
675
#endif
676
	  {
677
	    setinsalt(aa, isa);
678
	  }
679
	  /* fc is in register, so deliver literal(!? ) base-offset */
680
	  goto breakson;
681
	}
682
 
683
      case infreg:		/* ditto caveat above */
684
	{
685
	  aa = ason;
686
	  goto breakson;
687
	}
688
 
689
#if USE_BITAD
690
      case bitad:
691
	{
692
	  isa = bitadalt(ason);
693
	  if (!isa.adval)
694
	  {
695
	    fail("no ptr bits");
696
	  }
697
	  /* fc is a literal address of bits, so make it direct */
698
	  isa.adval = 0;
699
	  setbitadalt(aa, isa);
700
	  goto breakson;
701
	}
702
#endif
703
      default:
704
	{
705
	  fail("locate ? reg");
706
	}
707
      }
708
  breakson:
709
      wans.answhere = aa;
710
      wans.ashwhere = a;
711
      return wans;
712
 
713
    }				/* end cont */
714
 
715
  case top_tag:		/* does this ever happen ? */
716
    {
717
      setregalt(aa, 0);
718
      wans.answhere = aa;
719
      wans.ashwhere = a;
720
      return wans;
721
    }				/* end top */
722
 
723
  case field_tag:
724
    {
725
      instore isa;
726
 
727
      wans = locate(son(e), sp, sh(son(e)), 0);
728
 
729
      /*
730
       * answer is wans displace literally by no(e); it should always be a
731
       * literal store address
732
       */
733
 
734
      switch ( discrim ( wans.answhere ) )
735
      {
736
      case notinreg:
737
	{
738
	  isa = insalt(wans.answhere);
739
#if USE_BITAD
740
	  if (a.ashalign == 1)
741
	  {
742
	    isa.b.offset += no(e);
743
	    setbitadalt(wans.answhere, isa);
744
	  }
745
	  else
746
#endif
747
	  {
748
	    isa.b.offset += no(e) / 8;
749
	    setinsalt(wans.answhere, isa);
750
	  }
751
	  break;
752
	}
753
#if USE_BITAD
754
      case bitad:
755
	{
756
	  wans.answhere.val.instoreans.b.offset += no(e);
757
	  FULLCOMMENT1("locate field_tag: adjusting bitad offset to %d", wans.answhere.val.instoreans.b.offset);
758
	  break;
759
	}
760
#endif
761
      default:
762
	fail("field should be transformed");
763
      }
764
      wans.ashwhere = a;
765
      return wans;
766
    }				/* end field */
767
  default:
768
    {
769
 
770
      /*
771
       * general catch all; evaluate e into register and deliver it as a
772
       * literal store address
773
       */
774
      int r = reg_operand(e, sp);
775
      instore is;
776
 
777
      if (r == RET0)		/* guard possible result from proc - can do
778
				 * better */
779
      {
780
	FULLCOMMENT("guarding possible result");	/* +++ remove */
781
	r = getreg(sp.fixed);
782
	if (r != RET0)
783
	  rr_ins(i_copy,RET0,r);
784
      }
785
      is.b.base = r;
786
      is.b.offset = 0;
787
      is.adval = 1;
788
      setinsalt(aa, is);
789
      wans.answhere = aa;
790
      wans.ashwhere = a;
791
      return wans;
792
    }
793
  }
794
}
795
 
796
where locate 
797
    PROTO_N ( ( e, sp, s, dreg ) )
798
    PROTO_T ( exp e X space sp X shape s X int dreg )
799
{
800
  ans ak;
801
  where w;
802
 
803
  ak = iskept(e);
804
  if ( discrim ( ak ) == inreg && (regalt(ak) == 0))
805
  {
806
    w = locate1(e, sp, s, dreg);
807
  }
808
  else
809
  {
810
    FULLCOMMENT("locate: iskept() found value");
811
    w.answhere = ak;
812
    w.ashwhere = ashof(s);
813
  }
814
  return w;
815
}
816
 
817
 
818
 
819
 
820
 
821
 
822
 
823
 
824
 
825
 
826
 
827
 
828
 
829
 
830