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
/* 80x86/operand.c */
32
 
33
/**********************************************************************
34
$Author: pwe $
35
$Date: 1998/02/18 11:22:05 $
36
$Revision: 1.2 $
37
$Log: operand.c,v $
38
 * Revision 1.2  1998/02/18  11:22:05  pwe
39
 * test corrections
40
 *
41
 * Revision 1.1.1.1  1998/01/17  15:55:52  release
42
 * First version to be checked into rolling release.
43
 *
44
 * Revision 1.12  1996/04/19  16:14:05  pwe
45
 * simplified use of global id = id, correcting linux call problem
46
 *
47
 * Revision 1.11  1995/08/30  16:06:50  pwe
48
 * prepare exception trapping
49
 *
50
 * Revision 1.10  1995/08/23  09:42:58  pwe
51
 * track fpu control word for trap etc
52
 *
53
 * Revision 1.9  1995/08/04  08:29:41  pwe
54
 * 4.0 general procs implemented
55
 *
56
 * Revision 1.8  1995/04/05  12:35:18  pwe
57
 * operator precedence in eq_where_exp
58
 *
59
 * Revision 1.7  1995/04/03  08:30:24  pwe
60
 * invalidate regs if overlap, eg if bitfield on byte boundaries
61
 *
62
 * Revision 1.6  1995/03/24  09:21:39  pwe
63
 * global proc renaming avoided for SCO
64
 *
65
 * Revision 1.5  1995/03/03  10:12:36  pwe
66
 * makeval is legal but arbitrary operand (for C)
67
 *
68
 * Revision 1.4  1995/02/24  16:11:12  pwe
69
 * dynamic offsets, including mixed bit/byte representations
70
 *
71
 * Revision 1.3  1995/02/21  11:47:59  pwe
72
 * Corrected move(offset) for movecont
73
 *
74
 * Revision 1.2  1995/01/30  12:56:36  pwe
75
 * Ownership -> PWE, tidy banners
76
 *
77
 * Revision 1.1  1994/10/27  14:15:22  jmf
78
 * Initial revision
79
 *
80
 * Revision 1.1  1994/07/12  14:38:12  jmf
81
 * Initial revision
82
 *
83
**********************************************************************/
84
 
85
 
86
/*********************************************************************
87
                              operand.c
88
 
89
  operand outputs a 80386 operand, given a "where" and the number of
90
  bits the operand occupies.
91
 
92
 
93
 
94
*********************************************************************/
95
 
96
 
97
#include "config.h"
98
#include "common_types.h"
99
#include "tags.h"
100
#include "basicread.h"
101
#include "expmacs.h"
102
#include "exp.h"
103
#include "shapemacs.h"
104
#include "flpt.h"
105
#include "coder.h"
106
#include "instr.h"
107
#include "out.h"
108
#include "check.h"
109
#include "codermacs.h"
110
#include "externs.h"
111
#include "install_fns.h"
112
#include "table_fns.h"
113
#include "flags.h"
114
#include "instr386.h"
115
#include "machine.h"
116
#include "localflags.h"
117
#include "assembler.h"
118
#include "messages_8.h"
119
#include "diag_fns.h"
120
#include "operand.h"
121
 
122
 
123
/* VARIABLES */
124
/* All variables initialised */
125
 
126
int  crt_proc_id;	/* init by cproc */
127
int  stack_dec;		/* init by cproc */
128
			/* current stack decrement */
129
exp const_list;		/* init by init_all */
130
			/* list of constants belonging to current
131
				   procedure */
132
 
133
/* PROCEDURES */
134
 
135
/* turns an exp and an offset (in bits)
136
   into a where */
137
where mw
138
    PROTO_N ( (e, off) )
139
    PROTO_T ( exp e X int off )
140
{
141
  where w;
142
  w.where_exp = e;
143
  w.where_off = off;
144
  return (w);
145
}
146
 
147
/* compares wheres for equality of operand.
148
   This is also used by equiv_reg to detect
149
   invalidity of register copy, in which case
150
   we need to detect overlaps, this case
151
   determined by 'overlap' */
152
int eq_where_exp
153
    PROTO_N ( (a, b, first, overlap) )
154
    PROTO_T ( exp a X exp b X int first X int overlap )
155
{
156
  unsigned char  na;
157
  unsigned char  nb;
158
 
159
rept:
160
  na = name(a);
161
  nb = name(b);
162
 
163
  if (a == b)
164
    return (1);
165
  if (na == nb) {		/* same kind of operation "equal names" */
166
    if (na == val_tag && !isbigval(a) && !isbigval(b))
167
      return (no (a) == no (b));
168
    if (na == ident_tag) {
169
      int good = son(a) != nilexp && son(b) != nilexp &&
170
          bro(son(a)) != nilexp && bro(son(b)) != nilexp;
171
      if (good) {
172
        exp bsa = bro(son(a));
173
        exp bsb = bro(son(b));
174
        if (name (bsa) == name_tag && son (bsa) == a &&
175
	    name (bsb) == name_tag && son (bsb) == b) {
176
	  a = son(a);
177
	  b = son(b);
178
	  first = 0;
179
	  goto rept;
180
        };
181
        if (name (bsa) == reff_tag &&
182
	    name (bsb) == reff_tag &&
183
	    (overlap ? (no (bsa) & -32) == (no (bsb) & -32) : no (bsa) == no (bsb)) &&
184
	    name (son (bsa)) == name_tag &&
185
	    son (son (bsa)) == a &&
186
	    name (son (bsb)) == name_tag &&
187
	    son (son (bsb)) == b) {
188
	  a = son(a);
189
	  b = son(b);
190
	  first = 0;
191
	  goto rept;
192
        };
193
      };
194
      if (isglob(a) || isglob(b))
195
        return 0;
196
      return (pt (a) == pt (b) &&
197
	      (overlap ? (no (a) & -32) == (no (b) & -32) : no (a) == no (b)));
198
    };
199
    if (na == name_tag) {
200
      if ((overlap ? (no (a) & -32) != (no (b) & -32) : no (a) != no (b)) ||
201
	  (isvar (son (a)) != isvar (son (b))))
202
	return (0);
203
      a = son(a);
204
      b = son(b);
205
      first = 0;
206
      goto rept;
207
    };
208
    if (na == cont_tag || na == ass_tag) {
209
      a = son(a);
210
      b = son(b);
211
      first = 0;
212
      goto rept;
213
    };
214
    if (na == field_tag || na == reff_tag) {
215
      if (overlap ? (no (a) & -32) != (no (b) & -32) : no (a) != no (b))
216
	return (0);
217
      a = son(a);
218
      b = son(b);
219
      first = 0;
220
      goto rept;
221
    };
222
    if (na == real_tag && name (sh (a)) == name (sh (b))) {
223
      flt fa, fb;
224
      int  i;
225
      int is_zero = 1;
226
      fa = flptnos[no (a)];
227
      fb = flptnos[no (b)];
228
 
229
      for (i = 0; i < MANT_SIZE && (fa.mant)[i] == (fb.mant)[i];
230
	  i++) {
231
	if ((fa.mant)[i] != 0)
232
	  is_zero = 0;
233
      };
234
 
235
      return (i == MANT_SIZE &&
236
	  (is_zero || (fa.exp == fb.exp &&
237
	      fa.sign == fb.sign)));
238
 
239
    };
240
    return (0);
241
  };				/* end equal names */
242
 
243
 
244
  if (na == name_tag && nb == ident_tag && first) {
245
    if (overlap ? (no (a) & -32) != 0 : no (a) != 0)
246
      return (0);
247
    a = son(a);
248
    first = 0;
249
    goto rept;
250
  };
251
  if (na == ident_tag && nb == name_tag && first) {
252
    if (overlap ? (no (b) & -32) != 0 : no (b) != 0)
253
      return (0);
254
    b = son(b);
255
    first = 0;
256
    goto rept;
257
  };
258
 
259
  if (na == cont_tag && name(son(a)) == name_tag &&
260
         isvar(son(son(a))) && nb == ident_tag && first) {
261
    if (overlap ? (no (son(a)) & -32) != 0 : no (son(a)) != 0)
262
      return (0);
263
    a = son(son(a));
264
    first = 0;
265
    goto rept;
266
  };
267
  if (na == ident_tag && nb == cont_tag && name(son(b)) == name_tag
268
            && isvar(son(son(b))) && first) {
269
    if (overlap ? (no (son(b)) & -32) != 0 : no (son(b)) != 0)
270
      return (0);
271
    b = son(b);
272
    first = 0;
273
    goto rept;
274
  };
275
 
276
  if ((na == cont_tag || na == ass_tag) &&
277
      name (son (a)) == name_tag &&
278
      isvar (son (son (a))) && nb == name_tag && !isvar (son (b))) {
279
    if (overlap ? (no (son(a)) & -32) != (no (b) & -32) : no (son(a)) != no (b))
280
      return (0);
281
    a = son (son (a));
282
    b = son (b);
283
    first = 0;
284
    goto rept;
285
  };
286
  if ((nb == cont_tag || nb == ass_tag) &&
287
      name (son (b)) == name_tag &&
288
      isvar (son (son (b))) && na == name_tag && !isvar (son (a))) {
289
    if (overlap ? (no (son(b)) & -32) != (no (a) & -32) : no (son(b)) != no (a))
290
      return (0);
291
    a = son (a);
292
    b = son (son (b));
293
    first = 0;
294
    goto rept;
295
  };
296
  if ((na == ass_tag && nb == cont_tag) ||
297
      (nb == ass_tag && na == cont_tag)) {
298
    a = son(a);
299
    b = son(b);
300
    first = 0;
301
    goto rept;
302
  };
303
  return (0);
304
}
305
 
306
/* compares wheres for equality of operand */
307
int eq_where
308
    PROTO_N ( (wa, wb) )
309
    PROTO_T ( where wa X where wb )
310
{
311
  exp a = wa.where_exp;
312
  exp b = wb.where_exp;
313
  if (a == nilexp || b == nilexp)
314
     return 0;
315
  if (wa.where_off != wb.where_off)
316
    return (0);
317
  return eq_where_exp (a, b, 1, 0);
318
}
319
 
320
 
321
/* find the first register in the register bit pattern r */
322
frr first_reg
323
    PROTO_N ( (r) )
324
    PROTO_T ( int r )
325
{
326
  frr t;
327
  t.regno = 1;
328
  t.fr_no = 0;
329
  if (r == 0)
330
    failer (BAD_REGISTER);
331
  else {
332
    while (!(t.regno & r)) {
333
      t.regno = t.regno << 1;
334
      ++t.fr_no;
335
    }
336
  };
337
  return (t);
338
}
339
 
340
/* output operand,  wh is a where Note
341
   that the pt field of a declaration now
342
   hold a code for the position of the
343
   value (eg. reg_pl for in a register,
344
   local_pl for relative to sp etc.). The
345
   no field hold the location, bit pattern
346
   for register, offset (in bits) for
347
   local etc. stack_dec hold the amount
348
   the stack is decremented from its
349
   position at the start of the procedure
350
   (ie the place where no is measured
351
   from). This is to allow for push
352
   operations. b is passed to extn to
353
   control whether a bracket is output
354
   (index instructions). addr is true if
355
   we need a literal address. */
356
void operand
357
    PROTO_N ( (le, wh, b, addr) )
358
    PROTO_T ( int le X where wh X int b X int addr )
359
{
360
  exp w = wh.where_exp;
361
  int  off = wh.where_off;
362
  unsigned char  n = name (w);
363
 
364
  if (n == val_tag && !isbigval(w)) {		/* integer constant */
365
    int  k = no (w) + off;
366
    if (name(sh(w)) == offsethd && al2(sh(w)) != 1)
367
      k = k / 8;
368
    int_operand (k, le);
369
    return;
370
  };
371
 
372
  if (n == ident_tag || n == labst_tag) {/* can only be dest */
373
    switch (ptno (w)) {
374
      case local_pl: {
375
	  rel_sp ((no (w) + off - stack_dec) / 8, b);
376
	  return;
377
	};
378
      case reg_pl: {
379
	  regn (no (w), off, w, le);
380
	  return;
381
	};
382
      default: {
383
	  failer (BAD_OPND);
384
	  return;
385
	};
386
    };
387
  };
388
 
389
  if (n == name_tag) {
390
    exp ident = son (w);
391
    int  noff = no (w) + off;
392
    int  ni = no (ident);
393
 
394
    if (isglob (ident)) {
395
      if (name (sh (w)) == prokhd)	/* special treatment for procedures */
396
        {
397
          const_extn (ident, noff);
398
          return;
399
        };
400
 
401
      if (isvar (ident))
402
	const_extn (ident, noff);
403
      else
404
	extn (ident, noff, b);
405
      return;
406
    };
407
 
408
    switch (ptno (ident)) {
409
      case local_pl: {		/* local so relative to stack pointer or fp */
410
	  rel_sp ((ni + noff - stack_dec) / 8, b);
411
	  return;
412
	};
413
      case callstack_pl: {	/* caller arg so relative to stack pointer */
414
	  rel_cp ((ni + noff - stack_dec) / 8, b);
415
	  return;
416
	};
417
      case par_pl: {		/* parameter so relative to fp */
418
	  rel_ap ((ni + noff + 32) / 8, b);
419
	  return;
420
	};
421
      case reg_pl: {		/* in a register */
422
	  regn (ni, noff, w, le);
423
	  return;
424
	};
425
      case ferr_pl: {		/* relative to fp, depending on push space */
426
	  rel_ap1 ((ni + noff) / 8, b);
427
	  return;
428
	};
429
      default: {		/* doesnt happen */
430
	  failer (BAD_OPND);
431
	  return;
432
	};
433
    };
434
  };
435
 
436
  if (n == cont_tag || n == ass_tag) {
437
    exp ref = son (w);
438
    unsigned char  s = name (ref);
439
    if (addr) {
440
      operand (le, mw (son (w), 0), b, 0);
441
      return;
442
    };
443
    if (s == name_tag) {	/* content of id */
444
      if (!isvar (son (ref))) {
445
	exp ident = son (ref);
446
	if (ptno (ident) != reg_pl && off != 0) {
447
	  failer (BAD_OPND);
448
	};
449
	if (isglob (ident)) {
450
	  if (name (sh (w)) != prokhd)
451
	    failer (BAD_OPND);
452
	  else
453
           {
454
	     if (PIC_code)
455
	       proc_extn (ident, no(ref));
456
             else
457
               extn (ident, no (ref), b);
458
           };
459
	  return;
460
	};
461
	switch (ptno (ident)) {
462
	  case reg_pl: {	/* indirect from register */
463
	      ind_reg (no (ident), no (ref), off, ref, b);
464
	      return;
465
	    };
466
	  default: {
467
	      failer (BAD_OPND);
468
	      return;
469
	    };
470
	};
471
      }
472
      else {			/* variable */
473
 
474
	exp ident = son (ref);
475
	int  noff = no (ref) + off;
476
	int  ni = no (ident);
477
 
478
	if (isglob (ident)) {
479
	  extn (ident, noff, b);
480
	  return;
481
	};
482
	switch (ptno (ident)) {
483
	  case local_pl: {
484
	      /* local so relative to stack pointer or fp */
485
	      rel_sp ((ni + noff - stack_dec) / 8, b);
486
	      return;
487
	    };
488
	  case callstack_pl: {
489
	      /* caller arg so relative to stack pointer */
490
	      rel_cp ((ni + noff - stack_dec) / 8, b);
491
	      return;
492
	    };
493
	  case par_pl: {	/* parameter so relative to fp */
494
	      rel_ap ((ni + noff + 32) / 8, b);
495
	      return;
496
	    };
497
	  case reg_pl: {	/* in a register */
498
	      regn (ni, noff, ref, le);
499
	      return;
500
	    };
501
	  default: {		/* doesnt happen */
502
	      failer (BAD_OPND);
503
	      return;
504
	    };
505
	};
506
      };
507
    };				/* end of cont(name) */
508
 
509
    if (s == cont_tag && name (son (ref)) == name_tag &&
510
	isvar (son (son (ref)))) {
511
      exp ident = son (son (ref));
512
      if (ptno (ident) != reg_pl && off != 0) {
513
	failer (BAD_OPND);
514
      };
515
      if (isglob (ident)) {
516
	if (name (sh (w)) != prokhd)
517
	  failer (BAD_OPND);
518
	else
519
	  extn (ident, no (son (ref)), b);
520
	return;
521
      };
522
      switch (ptno (ident)) {
523
	case reg_pl: {		/* indirect from register */
524
	    ind_reg (no (ident), no (son (ref)), off, ref, b);
525
	    return;
526
	  };
527
	default: {
528
	    failer (BAD_OPND);
529
	    return;
530
	  };
531
      };
532
    };				/* end of cont(cont(var)) */
533
 
534
 
535
    if (s == reff_tag) {
536
      exp et = son (ref);
537
      unsigned char  t = name (et);
538
      if (t == name_tag) {
539
	if (isglob (son (et))) {
540
	  extn (son (et), no (ref), b);
541
	  return;
542
	};
543
	switch (ptno (son (et))) {
544
	  case reg_pl: {
545
	      ind_reg (no (son (et)), no (et), (no (ref) + off), et, b);
546
	      return;
547
	    };
548
	  default: {
549
	      failer (BAD_OPND);
550
	      return;
551
	    };
552
	};
553
      };			/* end of cont(reff(name)) */
554
 
555
      if (t == cont_tag) {
556
	switch (ptno (son (son (et)))) {
557
	  case reg_pl: {
558
	      ind_reg (no (son (son (et))), no (son (et)),
559
		  (no (ref) + off), son (et), b);
560
	      return;
561
	    };
562
	  default: {
563
	      failer (BAD_OPND);
564
	      return;
565
	    };
566
	};
567
      };			/* end of cont(ref(cont())) */
568
 
569
      if (t == addptr_tag) {
570
	where new_w;
571
	new_w.where_exp = et;
572
	new_w.where_off = off + no (ref);
573
	operand (le, new_w, b, 0);
574
	return;
575
      };			/* end of cont(reff(addptr())) */
576
      failer (BAD_OPND);
577
    };				/* end of cont(reff()) */
578
 
579
    if (s == addptr_tag) {
580
      exp u = bro (son (ref));
581
      exp c = getexp (f_bottom, nilexp, 0, son (ref), nilexp,
582
	  0, 0, cont_tag);
583
      where wc, wu;
584
      wc.where_exp = c;
585
      wc.where_off = off;
586
      wu.where_exp = u;
587
      wu.where_off = 0;
588
      if (name (u) == name_tag || name (u) == cont_tag) {
589
	index_opnd (wc, wu, 1);
590
	return;
591
      };			/* end of cont(addptr(-, name)) */
592
 
593
      if (name (u) == offset_mult_tag) {
594
	int  k = no (bro (son (u)))/8;	/* cannot be bitfield */
595
	wu.where_exp = son (u);
596
	index_opnd (wc, wu, k);
597
	return;
598
      };			/* end of cont(addptr(-, mult)) */
599
    };				/* end of cont(addptr()) */
600
 
601
 
602
  };				/* end of cont */
603
 
604
 
605
  if (n == reff_tag) {
606
    exp se = son (w);
607
    unsigned char  s = name (se);
608
    if (s == name_tag) {
609
      if (isglob (son (se))) {
610
	extn (son (se), no (w), b);
611
	return;
612
      };
613
      switch (ptno (son (se))) {
614
	case reg_pl: {
615
	    ind_reg (no (son (se)), no (son (se)), no (w), se, b);
616
	    return;
617
	  };
618
	default: {
619
	    failer (BAD_OPND);
620
	    return;
621
	  };
622
      };
623
    };				/* end of reff(name)  */
624
 
625
    if (s == cont_tag) {
626
      if (isglob (son (son (se)))) {
627
	extn (son (son (se)), no (w), b);
628
	return;
629
      };
630
      switch (ptno (son (son (se)))) {
631
	case reg_pl: {
632
	    ind_reg (no (son (son (se))), no (son (se)),
633
		no (w), son (se), b);
634
	    return;
635
	  };
636
	default: {
637
	    failer (BAD_OPND);
638
	    return;
639
	  };
640
      };
641
    };				/* end of reff(cont()) */
642
 
643
    if (s == addptr_tag) {
644
      where ww;
645
      ww.where_exp = se;
646
      ww.where_off = off + no (w);
647
      operand (le, ww, b, 0);
648
      return;
649
    };				/* end of reff(addptr()) */
650
  };				/* end of reff() */
651
 
652
  if (n == addptr_tag) {
653
    exp u = bro (son (w));
654
    exp c = getexp (f_bottom, nilexp, 0, son (w), nilexp, 0, 0, cont_tag);
655
    where wc, wu;
656
    wc.where_exp = c;
657
    wc.where_off = off;
658
    wu.where_exp = u;
659
    wu.where_off = 0;
660
    if (name (u) == name_tag || name (u) == cont_tag) {
661
      index_opnd (wc, wu, 1);
662
      return;
663
    };				/* end of addptr(-, name)  */
664
 
665
    if (name (u) == offset_mult_tag) {
666
      int  k = no (bro (son (u)))/8;	/* cannot be bitfield */
667
      wu.where_exp = son (u);
668
      index_opnd (wc, wu, k);
669
      return;
670
    };				/* end of addptr(-, mult) */
671
  };				/* end of addptr() */
672
 
673
  if (n == real_tag || n == val_tag || n == string_tag ||
674
	n == proc_tag || n == general_proc_tag) {
675
    int  ln;
676
    if (off == 0 || addr) {
677
      ln = next_lab ();
678
      const_list = getexp (f_bottom, const_list, 0, w, nilexp, 0, ln, 0);
679
      const_intnl ((addr || n == proc_tag || n == general_proc_tag), ln, 0);
680
      return;
681
    };
682
    /* assumes this is only used just after using the first part of the
683
       constant */
684
    const_intnl (0, no (const_list), off);
685
    return;
686
  };
687
 
688
  if (n == res_tag) {
689
    const_intnl (0, no (w), off);
690
    return;
691
  };
692
 
693
  if (n == null_tag) {
694
    int_operand (no(w), le);
695
    return;
696
  };
697
 
698
  if (n == field_tag) {
699
    operand (le, mw (son (w), off + no (w)), b, addr);
700
    return;
701
  };
702
 
703
  if (n == make_lv_tag) {
704
    label_operand(w);
705
    return;
706
  };
707
 
708
  if (n == current_env_tag) {
709
    outbp();
710
    return;
711
  };
712
 
713
  if (n == env_offset_tag) {
714
    if (name(son(w))==0) {	/* must be caller arg with var_callees */
715
      int_operand(no(son(w))/8, le);
716
      return;
717
    }
718
    outs("$");
719
    envoff_operand(son(w), no(w));
720
    return;
721
  };
722
 
723
  if (n == env_size_tag) {
724
    outs("$");
725
    envsize_operand(son(son(w)));
726
    return;
727
  };
728
 
729
  if (n == local_free_all_tag) {
730
    ldisp();
731
    return;
732
  };
733
 
734
  if (n == clear_tag) {
735
	/* any legal operand will do! */
736
    if (name(sh(w)) >= shrealhd && name(sh(w)) <= doublehd) {
737
      outs("%st");
738
      return;
739
    }
740
    switch (shape_size(sh(w))) {
741
      case 8:
742
	outs("%al");
743
	return;
744
      case 16:
745
	outs("%ax");
746
	return;
747
      default:
748
	outs("%eax");
749
	return;
750
    };
751
  };
752
 
753
  failer (BAD_OPND);
754
 
755
  return;
756
}
757