Subversion Repositories tendra.SVN

Rev

Rev 2 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
2
    		 Crown Copyright (c) 1996
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
			    VERSION INFORMATION
31
			    ===================
32
 
33
--------------------------------------------------------------------------
34
$Header: /u/g/release/CVSROOT/Source/src/installers/680x0/common/codec.c,v 1.1.1.1 1998/01/17 15:55:49 release Exp $
35
--------------------------------------------------------------------------
36
$Log: codec.c,v $
37
 * Revision 1.1.1.1  1998/01/17  15:55:49  release
38
 * First version to be checked into rolling release.
39
 *
40
Revision 1.3  1997/11/13 08:27:09  ma
41
All avs test passed (except add_to_ptr).
42
 
43
Revision 1.2  1997/11/09 14:06:53  ma
44
Rounding mode represented with names.
45
 
46
Revision 1.1.1.1  1997/10/13 12:42:47  ma
47
First version.
48
 
49
Revision 1.5  1997/10/13 08:48:58  ma
50
Made all pl_tests for general proc & exception handling pass.
51
 
52
Revision 1.4  1997/09/25 06:44:49  ma
53
All general_proc tests passed
54
 
55
Revision 1.3  1997/06/18 10:09:22  ma
56
Checking in before merging with Input Baseline changes.
57
 
58
Revision 1.2  1997/04/20 11:30:17  ma
59
Introduced gcproc.c & general_proc.[ch].
60
Added cases for apply_general_proc next to apply_proc in all files.
61
 
62
Revision 1.1.1.1  1997/03/14 07:50:10  ma
63
Imported from DRA
64
 
65
 * Revision 1.1.1.1  1996/09/20  10:56:52  john
66
 *
67
 * Revision 1.3  1996/07/30  16:29:34  john
68
 * Fixed bug, discarding side-effecting operations
69
 *
70
 * Revision 1.2  1996/07/05  14:16:20  john
71
 * Changes for spec 3.1
72
 *
73
 * Revision 1.1.1.1  1996/03/26  15:45:08  john
74
 *
75
 * Revision 1.5  94/11/16  10:36:02  10:36:02  ra (Robert Andrews)
76
 * Added integer absolute construct.
77
 * -
78
 *
79
 * Revision 1.4  94/06/29  14:18:00  14:18:00  ra (Robert Andrews)
80
 * Added div0, rem0, max and min for TDF 3.0.
81
 *
82
 * Revision 1.3  93/11/19  16:14:42  16:14:42  ra (Robert Andrews)
83
 * Corrected order of arguments in offset_subtract.
84
 *
85
 * Revision 1.2  93/03/03  14:46:05  14:46:05  ra (Robert Andrews)
86
 * Added error handling routines.
87
 *
88
 * Revision 1.1  93/02/22  17:15:17  17:15:17  ra (Robert Andrews)
89
 * Initial revision
90
 *
91
--------------------------------------------------------------------------
92
*/
93
 
94
 
95
#include "config.h"
96
#include "common_types.h"
97
#include "exp.h"
98
#include "expmacs.h"
99
#include "flags.h"
100
#include "shapemacs.h"
101
#include "install_fns.h"
102
#include "tags.h"
103
#include "mach.h"
104
#include "where.h"
105
#include "codec.h"
106
#include "coder.h"
107
#include "operations.h"
108
#include "utility.h"
109
#include "mach.h"
110
#include "instr.h"
111
#include "codex.h"
112
#include "instrs.h"
113
#include "f64.h"
114
#include "me_fns.h"
115
#include "evaluate.h"
116
#include "ops_shared.h"
117
#include "mach_ins.h"
118
 
119
extern bool have_cond ;
120
 
121
 
122
/*
123
    CONSTRUCT A SIMILAR EXP
124
 
125
    This routine, given a where, copies the corresponding exp, and sets
126
    its sh equal to the given shape.
127
*/
128
 
129
exp sim_exp
130
    PROTO_N ( ( sha, w ) )
131
    PROTO_T ( shape sha X where w )
132
{
133
    exp e = copyexp ( w.wh_exp ) ;
134
    sh ( e ) = sha ;
135
    return ( e ) ;
136
}
137
 
138
 
139
/*
140
    PROCESS A UNARY OPERATION
141
 
142
    This routine processes the unary operation described by the routine
143
    op.  The operand is given by a and the result, which is of shape
144
    sha, is put into dest.  The stack argument describes the current
145
    state of the stack.
146
*/
147
 
148
static void uop
149
    PROTO_N ( ( op, sha, a, dest, stack ) )
150
    PROTO_T ( void ( *op ) PROTO_S ( ( shape, where, where ) ) X
151
	      shape sha X exp a X where dest X ash stack )
152
{
153
    int old_rmode ;
154
    if ( !is_o ( name ( a ) ) ) {
155
	/* If a is not an operand, we need to calculate its value first */
156
	if ( whereis ( dest ) == Dreg ) {
157
	    /* If dest is in a D register, code a into dest */
158
	    old_rmode = crt_rmode ;
159
	    coder ( dest, stack, a ) ;
160
	    crt_rmode = old_rmode ;
161
	    /* Now apply op to dest */
162
	    ( *op ) ( sha, dest, dest ) ;
163
	    return ;
164
	} else {
165
	    /* Code a into D1 */
166
	    where w ;
167
	    exp e = sim_exp ( sha, D1 ) ;
168
	    w = zw ( e ) ;
169
	    regsinproc |= regmsk ( REG_D1 ) ;
170
	    old_rmode = crt_rmode ;
171
	    coder ( w, stack, a ) ;
172
	    crt_rmode = old_rmode ;
173
	    /* Apply op to D1 */
174
	    ( *op ) ( sha, w, dest ) ;
175
	    retcell ( e ) ;
176
	    if ( have_cond == 3 ) have_cond = 1 ;
177
	    return ;
178
	}
179
    }
180
    /* If a is an operand, apply op directly to a */
181
    ( *op ) ( sha, zw ( a ), dest ) ;
182
    return ;
183
}
184
 
185
 
186
/*
187
    PROCESS A BINARY OPERATION
188
 
189
    This routine processes the binary operation described by the routine
190
    op.  The operands are given by a and b and the result, which is of
191
    shape sha, is put into dest.  The stack argument describes the current
192
    state of the stack.
193
*/
194
 
195
static void bop
196
    PROTO_N ( ( op, sha, a, b, dest, stack ) )
197
    PROTO_T ( void ( *op ) PROTO_S ( ( shape, where, where, where ) ) X
198
	      shape sha X exp a X exp b X where dest X ash stack )
199
{
200
    where w, t ;
201
    bool noa = !is_o ( name ( a ) ) ;
202
    bool nob = !is_o ( name ( b ) ) ;
203
    if ( noa ) {
204
	/* If a is not an operand, we need to calculate its value first */
205
	if ( nob ) {
206
	    /* a and b cannot both not be operands */
207
	    error ( "Illegal binary operation" ) ;
208
	}
209
	t = zw ( b ) ;
210
	if ( whereis ( dest ) == Dreg && !interfere ( dest, t ) ) {
211
	    /* If dest is in a D register which is not used in b,
212
	       code a into dest */
213
	    coder ( dest, stack, a ) ;
214
	    /* Apply op to dest and b */
215
	    ( *op ) ( sha, dest, t, dest ) ;
216
	    return ;
217
	} else {
218
	    /* Code a into D1 */
219
	    exp e = sim_exp ( sha, D1 ) ;
220
	    w = zw ( e ) ;
221
	    regsinproc |= regmsk ( REG_D1 ) ;
222
	    coder ( w, stack, a ) ;
223
	    /* Apply op to D1 and b */
224
	    ( *op ) ( sha, w, t, dest ) ;
225
	    retcell ( e ) ;
226
	    if ( have_cond == 3 ) have_cond = 1 ;
227
	    return ;
228
	}
229
    }
230
    if ( nob ) {
231
	/* If b is not an operand, we need to calculate its value first */
232
	t = zw ( a ) ;
233
	if ( whereis ( dest ) == Dreg && !interfere ( dest, t ) ) {
234
	    /* If dest is in a D register which is not used in a,
235
	       code b into dest */
236
	    coder ( dest, stack, b ) ;
237
	    /* Apply op to a and dest */
238
	    ( *op ) ( sha, t, dest, dest ) ;
239
	    return ;
240
	} else {
241
	    /* Code b into D1 */
242
	    exp e = sim_exp ( sha, D1 ) ;
243
	    w = zw ( e ) ;
244
	    regsinproc |= regmsk ( REG_D1 ) ;
245
	    coder ( w, stack, b ) ;
246
	    /* Apply op to a and D1 */
247
	    ( *op ) ( sha, t, w, dest ) ;
248
	    retcell ( e ) ;
249
	    if ( have_cond == 3 ) have_cond = 1 ;
250
	    return ;
251
	}
252
    }
253
    /* If a and b are both operands, apply op directly */
254
    ( *op ) ( sha, zw ( a ), zw ( b ), dest ) ;
255
    return ;
256
}
257
 
258
 
259
/*
260
    PROCESS A LOGICAL OPERATION
261
 
262
    This routine processes the logical operation described by the routine
263
    op.  This operation will be binary, commutative and associative.  The
264
    operands are given by the bro-list starting at the son of e.  The
265
    result is put into dest.  The stack argument describes the current
266
    state of the stack.
267
*/
268
 
269
static void logop
270
    PROTO_N ( ( op, e, dest, stack ) )
271
    PROTO_T ( void ( *op ) PROTO_S ( ( shape, where, where, where ) ) X
272
	      exp e X where dest X ash stack )
273
{
274
    exp arg1 = son ( e ) ;	/* First argument */
275
    exp arg2 = bro ( arg1 ) ;	/* Second argument */
276
    exp t, u, v ;
277
    where w ;
278
 
279
    if ( last ( arg1 ) ) {
280
	/* If there is of one argument, code it into dest */
281
	coder ( dest, stack, arg1 ) ;
282
	return ;
283
    }
284
 
285
    if ( last ( arg2 ) ) {
286
	/* If there are two arguments, use bop */
287
	bop ( op, sh ( e ), arg1, arg2, dest, stack ) ;
288
	return ;
289
    }
290
 
291
    /* Three or more arguments : need to take care about overlap between
292
       dest and args, so use D1. */
293
 
294
    regsinproc |= regmsk ( REG_D1 ) ;
295
    v = sim_exp ( sh ( e ), D1 ) ;
296
    w = zw ( v ) ;
297
    t = arg1 ;
298
 
299
    /* Scan the arguments.  t will hold either the first non-operand,
300
       or nilexp if all the arguments are operands.  There should be
301
       at most one non-operand.  */
302
 
303
    while ( 1 ) {
304
	if ( !is_o ( name ( t ) ) ) break ;
305
	if ( last ( t ) ) {
306
	    t = nilexp ;
307
	    break ;
308
	}
309
	t = bro ( t ) ;
310
    }
311
 
312
    /*
313
       Deal with the case where all the arguments are operands.  This
314
       does :
315
		D1 = op ( arg1, arg2 )
316
		D1 = op ( arg3, D1 )
317
		D1 = op ( arg4, D1 )
318
		....................
319
		dest = op ( argn, D1 )
320
    */
321
 
322
    if ( t == nilexp ) {
323
	/* Process the first two terms */
324
	( *op ) ( sh ( e ), zw ( arg1 ), zw ( arg2 ), w ) ;
325
	t = bro ( arg2 ) ;
326
	while ( !last ( t ) ) {
327
	    /* Process the third, fourth, ... terms */
328
	    ( *op ) ( sh ( e ), zw ( t ), w, w ) ;
329
	    t = bro ( t ) ;
330
	}
331
	/* Process the last term */
332
	reuseables |= regmsk ( REG_D1 ) ;
333
	( *op ) ( sh ( e ), zw ( t ), w, dest ) ;
334
	reuseables &= ~regmsk ( REG_D1 ) ;
335
	retcell ( v ) ;
336
	if ( have_cond == 3 ) have_cond = 1 ;
337
	return ;
338
    }
339
 
340
    /*
341
	Deal with the case where one argument, say arg2, is a non-operand.
342
	This does :
343
		D1 = arg2
344
		D1 = op ( arg1, D1 )
345
		D1 = op ( arg3, D1 )
346
		....................
347
		dest = op ( argn, D1 )
348
    */
349
 
350
    coder ( w, stack, t ) ;
351
    u = arg1 ;
352
    while ( 1 ) {
353
	if ( t != u ) {
354
	    if ( last ( u ) || ( bro ( u ) == t && last ( bro ( u ) ) ) ) {
355
		( *op ) ( sh ( e ), zw ( u ), w, dest ) ;
356
	    } else {
357
		( *op ) ( sh ( e ), zw ( u ), w, w ) ;
358
	    }
359
	}
360
	if ( last ( u ) ) break ;
361
	u = bro ( u ) ;
362
    }
363
    retcell ( v ) ;
364
    if ( have_cond == 3 ) have_cond = 1 ;
365
    return ;
366
}
367
 
368
 
369
/*
370
  PROCESS ADD AND SUBTRACT
371
 
372
  This routine processes the binary operation add.  It does dest = b + a.
373
  The second argument, a, may be of the form neg ( a1 ), in which case
374
  we use sub.
375
*/
376
 
377
static void addsub
378
    PROTO_N ( ( sha, a, b, dest, stack ) )
379
    PROTO_T ( shape sha X where a X where b X where dest X ash stack )
380
{
381
    exp e = a.wh_exp ;
382
    if ( name ( e ) == neg_tag ) {
383
      bop ( sub, sha, son ( e ), b.wh_exp, dest, stack ) ;
384
    }
385
    else {
386
      bop ( add, sha, e, b.wh_exp, dest, stack ) ;
387
    }
388
    return ;
389
}
390
 
391
 
392
/*
393
  Some constructs only set the overflow bit for 32 bit results.
394
  This checks values of other varieties to determine whether or not an
395
  overflow has occured
396
*/
397
void check_unset_overflow
398
    PROTO_N ( (dest,shp) )
399
    PROTO_T ( where dest X shape shp )
400
{
401
  exp max_val = getexp(shp,nilexp,0,nilexp,nilexp,0,range_max(shp),
402
		       val_tag);
403
  exp min_val = getexp(shp,nilexp,0,nilexp,nilexp,0,range_min(shp),
404
		       val_tag);
405
  bool sw;
406
  move(shp,dest,D0);
407
  if(is_signed(shp) && (shape_size(shp) < 32)) {
408
    ins1((shape_size(shp) == 16)?m_extl : m_extbl,32,D0,1);
409
  }
410
  sw = cmp(is_signed(shp)?slongsh:ulongsh,D0,zw(max_val),tst_gr);
411
  test_overflow2(branch_ins(tst_gr,sw,is_signed(shp),is_floating(name(shp))));
412
 
413
  sw = cmp(is_signed(shp)?slongsh:ulongsh,D0,zw(min_val),tst_ls);
414
  test_overflow2(branch_ins(tst_ls,sw,is_signed(shp), is_floating(name(shp))));
415
 
416
  kill_exp(max_val,max_val);
417
  kill_exp(min_val,min_val);
418
  return;
419
}
420
 
421
 
422
/*
423
  MAIN OPERATION CODING ROUTINE
424
 
425
  This routine creates code to evaluate e, putting the result into dest.
426
  The stack argument describes the current stack position.
427
*/
428
 
429
void codec
430
    PROTO_N ( ( dest, stack, e ) )
431
    PROTO_T ( where dest X ash stack X exp e )
432
{
433
    if ( e == nilexp ) {
434
	error ( "Internal coding error" ) ;
435
	return ;
436
    }
437
 
438
    switch ( name ( e ) ) {
439
 
440
	case plus_tag : {
441
	    /*
442
	       Addition is treated similarly to logical operations -
443
	       see the routine logop above.  It takes a variable number
444
	       of arguments in the form of a bro-list starting with
445
	       the son of e.  Each argument may be of the form
446
	       neg ( x ).
447
	    */
448
	    exp arg1 = son ( e ) ;	/* First argument */
449
	    exp arg2 = bro ( arg1 ) ;	/* Second argument */
450
	    exp s, t, u, v ;
451
	    where w ;
452
            int prev_ov ;
453
 
454
	    if ( last ( arg1 ) ) {
455
		/* One argument */
456
		coder ( dest, stack, arg1 ) ;
457
		return ;
458
	    }
459
 
460
	    prev_ov = set_overflow ( e ) ;
461
 
462
	    if ( last ( arg2 ) ) {
463
		/* Two arguments */
464
		addsub ( sh ( e ), zw ( arg2 ), zw ( arg1 ), dest, stack ) ;
465
		clear_overflow ( prev_ov ) ;
466
		return ;
467
	    }
468
 
469
	    /* Three or more arguments - use D1 */
470
	    t = arg1 ;
471
	    regsinproc |= regmsk ( REG_D1 ) ;
472
	    s = sim_exp ( sh ( e ), D1 ) ;
473
	    w = zw ( s ) ;
474
 
475
	    /* Look for the non-operand if there is one */
476
	    while ( 1 ) {
477
		if ( !is_o ( name ( t ) ) &&
478
		     ( name ( t ) != neg_tag ||
479
		       !is_o ( name ( son ( t ) ) ) ) ) break ;
480
		if ( last( t ) ) {
481
		    t = nilexp ;
482
		    break ;
483
		}
484
		t = bro( t ) ;
485
	    }
486
	    if ( t == nilexp && name ( arg1 ) == neg_tag &&
487
		 name ( arg2 ) == neg_tag ) t = arg1 ;
488
 
489
	    /* Deal with the case where all the arguments are operands */
490
	    if ( t == nilexp ) {
491
		t = bro ( arg2 ) ;
492
		/* Deal with the first two arguments */
493
		if ( name ( arg1 ) == neg_tag ) {
494
		    addsub ( sh ( e ), zw ( arg1 ), zw ( arg2 ),
495
			     ( ( t == e ) ? dest : w ), stack ) ;
496
		} else {
497
		    addsub ( sh ( e ), zw ( arg2 ), zw ( arg1 ),
498
			     ( ( t == e ) ? dest : w ), stack ) ;
499
		}
500
		if ( t == e ) {
501
		    clear_overflow ( prev_ov ) ;
502
		    return ;
503
		}
504
		/* Deal with the third, fourth, ... arguments */
505
		while ( !last ( t ) ) {
506
		    u = bro ( t ) ;
507
		    addsub ( sh ( e ), zw ( t ), w, w, stack ) ;
508
		    t = u ;
509
		}
510
		/* Deal with the last argument */
511
		addsub ( sh ( e ), zw ( t ), w, dest, stack ) ;
512
		retcell ( s ) ;
513
		if ( have_cond == 3 ) have_cond = 1 ;
514
		clear_overflow ( prev_ov ) ;
515
		return ;
516
	    }
517
 
518
	    /* Deal with the case where one argument is a non-operand */
519
	    coder ( w, stack, t ) ;
520
	    u = arg1 ;
521
	    while ( 1 ) {
522
		v = bro ( u ) ;
523
		if ( t != u ) {
524
		    if ( last ( u ) || ( v == t && last ( v ) ) ) {
525
			addsub ( sh ( e ), zw ( u ), w, dest, stack ) ;
526
		    } else {
527
			addsub ( sh ( e ), zw ( u ), w, w, stack ) ;
528
		    }
529
		}
530
		if ( last ( u ) ) break ;
531
		u = v ;
532
	    }
533
	    retcell ( s ) ;
534
	    if ( have_cond == 3 ) have_cond = 1 ;
535
	    clear_overflow ( prev_ov ) ;
536
	    return ;
537
	}
538
 
539
#ifndef tdf3
540
 
541
          case addptr_tag : {
542
             exp pointer = son ( e ) ;
543
             exp offset  = son ( pointer ) ;
544
 
545
             make_comment("addptr_tag ...") ;
546
             mova ( zw ( e ), dest ) ;
547
             make_comment("addptr_tag done") ;
548
             return ;
549
          }
550
#endif
551
	case chvar_tag : {
552
	    /* Change variety, the son of e, a, gives the argument */
553
	    exp a = son ( e ) ;
554
	    int prev_ov = set_overflow(e);
555
	    if ( !is_o ( name ( a ) ) ) {
556
		/* If a is not an operand */
557
		if ( whereis ( dest ) != Dreg ) {
558
		    /* If dest is not a D register, code a into D1 */
559
		    where w ;
560
		    exp s = sim_exp ( sh ( a ), D1 ) ;
561
		    w = zw ( s ) ;
562
		    regsinproc |= regmsk ( REG_D1 ) ;
563
		    coder ( w, stack, a ) ;
564
		    /* Preform the change variety on D1 */
565
		    change_var ( sh ( e ), w, dest ) ;
566
		    retcell ( s ) ;
567
		    if ( have_cond == 3 ) have_cond = 1 ;
568
		    clear_overflow ( prev_ov ) ;
569
		    return ;
570
		}
571
		/* If dest is a D register, code a into dest */
572
		coder ( dest, stack, a ) ;
573
		/* Preform the change variety on dest */
574
		change_var_sh ( sh ( e ), sh ( a ), dest, dest ) ;
575
		clear_overflow ( prev_ov ) ;
576
		return ;
577
	    }
578
	    /* If a is an operand, call change_var directly */
579
	    change_var ( sh ( e ), zw ( a ), dest ) ;
580
	    clear_overflow ( prev_ov ) ;
581
	    return ;
582
	}
583
 
584
	case minus_tag : {
585
	    /* Minus, subtract pointer etc are binary operations */
586
	    int prev_ov = set_overflow ( e ) ;
587
	    bop ( sub, sh ( e ), bro ( son ( e ) ), son ( e ),
588
		  dest, stack ) ;
589
	    clear_overflow ( prev_ov ) ;
590
	    return ;
591
	}
592
#ifndef tdf3
593
        case make_stack_limit_tag :
594
#endif
595
	case subptr_tag :
596
	case minptr_tag : {
597
	    /* Minus, subtract pointer etc are binary operations */
598
	    bop ( sub, sh ( e ), bro ( son ( e ) ), son ( e ),
599
		  dest, stack ) ;
600
	    return ;
601
	}
602
 
603
	case mult_tag : {
604
	    /* Multiply is treated as a logical operation */
605
	    int prev_ov = set_overflow ( e ) ;
606
	    logop ( mult, e, dest, stack ) ;
607
	    if (!optop(e)&&(name(sh(e))!=slonghd)&&(name(sh(e))!=ulonghd)) {
608
	      check_unset_overflow(dest,sh(e));
609
	    }
610
	    clear_overflow ( prev_ov ) ;
611
	    return ;
612
	}
613
 
614
	case div0_tag :
615
	case div2_tag : {
616
	    /* Division is a binary operation */
617
	  int prev_ov = set_overflow(e);
618
	  bop ( div2, sh ( e ), bro ( son ( e ) ), son ( e ),
619
		  dest, stack ) ;
620
	  if (!optop(e)&&(name(sh(e))!=slonghd)&&(name(sh(e))!=ulonghd)) {
621
	    check_unset_overflow(dest,sh(e));
622
	  }
623
	  clear_overflow( prev_ov );
624
	  return ;
625
	}
626
 
627
	case div1_tag : {
628
	    /* Division is a binary operation */
629
	  int prev_ov = set_overflow(e);
630
	  bop ( div1, sh ( e ), bro ( son ( e ) ), son ( e ),
631
		  dest, stack ) ;
632
	  if (!optop(e)&&(name(sh(e))!=slonghd)&&(name(sh(e))!=ulonghd)) {
633
	    check_unset_overflow(dest,sh(e));
634
	  }
635
	  clear_overflow( prev_ov );
636
	  return ;
637
	}
638
 
639
	case neg_tag : {
640
	    /* Negation is a unary operation */
641
	    int prev_ov = set_overflow ( e ) ;
642
	    uop ( negate, sh ( e ), son ( e ), dest, stack ) ;
643
	    clear_overflow ( prev_ov ) ;
644
	    return ;
645
	}
646
 
647
	case abs_tag : {
648
           /* Abs is a unary operation */
649
           int prev_ov = set_overflow(e);
650
           uop ( absop, sh ( e ), son ( e ), dest, stack ) ;
651
           clear_overflow( prev_ov ) ;
652
           return ;
653
	}
654
 
655
	case shl_tag : {
656
	    /* Shifting left is a binary operation */
657
	    int prev_ov = set_overflow ( e ) ;
658
	    bop ( shift, sh ( e ), bro ( son ( e ) ), son ( e ),
659
		  dest, stack ) ;
660
	    clear_overflow ( prev_ov ) ;
661
	    return ;
662
	}
663
 
664
	case shr_tag : {
665
	    /* Shifting right is a binary operation */
666
	    bop ( rshift, sh ( e ), bro ( son ( e ) ), son ( e ),
667
		  dest, stack ) ;
668
	    return ;
669
	}
670
 
671
	case mod_tag : {
672
	    /* Remainder is a binary operation */
673
	    int prev_ov = set_overflow ( e ) ;
674
	    bop ( rem1, sh ( e ), bro ( son ( e ) ), son ( e ),
675
		  dest, stack ) ;
676
	    clear_overflow ( prev_ov ) ;
677
	    return ;
678
	}
679
 
680
	case rem0_tag :
681
	case rem2_tag : {
682
	    /* Remainder is a binary operation */
683
	    int prev_ov = set_overflow ( e ) ;
684
	    bop ( rem2, sh ( e ), bro ( son ( e ) ), son ( e ),
685
		  dest, stack ) ;
686
	    clear_overflow ( prev_ov ) ;
687
	    return ;
688
	}
689
 
690
	case round_tag : {
691
	    /* Rounding a floating point number is a unary operation */
692
	    int prev_ov = set_overflow ( e ) ;
693
	    set_continue(e);
694
	    crt_rmode = round_number ( e ) ;
695
	    uop ( round_float, sh ( e ), son ( e ), dest, stack ) ;
696
	    clear_overflow ( prev_ov ) ;
697
	    clear_continue(e);
698
	    return ;
699
	}
700
 
701
	case fmult_tag : {
702
	    /* Floating multiplication is a floating binary operation */
703
	    exp f1 = son ( e ) ;
704
	    exp f2 = bro ( f1 ) ;
705
	    int prev_ov = set_overflow ( e ) ;
706
	    if(last(f2)) {
707
	      /* two arguments */
708
	      fl_binop ( fmult_tag, sh ( e ), zw ( f1 ), zw ( f2 ), dest ) ;
709
	    }
710
	    else {
711
	      /* more than two arguments; use %fp1.  Assumes that all
712
	       parameters are operands */
713
	      where w;
714
	      exp s = sim_exp(sh(e), FP1);
715
	      regsinproc |= regmsk(REG_FP1);
716
	      w = zw(s);
717
 
718
	      fl_binop(fmult_tag,sh(e),zw(f1),zw(f2),w);
719
	      while(!last(f2)) {
720
		f2 = bro(f2);
721
		fl_binop(fmult_tag,sh(e),w,zw(f2),(last(f2)?dest:w));
722
	      }
723
	    }
724
 
725
	    clear_overflow ( prev_ov ) ;
726
	    return ;
727
	}
728
 
729
	case fminus_tag : {
730
	    /* Floating subtraction is a floating binary operation */
731
	    exp f1 = son ( e ) ;
732
	    exp f2 = bro ( f1 ) ;
733
	    int prev_ov = set_overflow ( e ) ;
734
	    fl_binop ( fminus_tag, sh ( e ), zw ( f2 ), zw ( f1 ), dest ) ;
735
	    clear_overflow ( prev_ov ) ;
736
	    return ;
737
	}
738
 
739
	case fdiv_tag : {
740
	    /* Floating division is a floating binary operation */
741
	    exp f1 = son ( e ) ;
742
	    exp f2 = bro ( f1 ) ;
743
	    int prev_ov = set_overflow ( e ) ;
744
	    fl_binop ( fdiv_tag, sh ( e ), zw ( f2 ), zw ( f1 ), dest ) ;
745
	    clear_overflow ( prev_ov ) ;
746
	    return ;
747
	}
748
 
749
	case fneg_tag : {
750
	    /* Floating negation is simple */
751
	    int prev_ov = set_overflow ( e ) ;
752
	    negate_float ( sh ( e ), zw ( son ( e ) ), dest ) ;
753
	    clear_overflow ( prev_ov ) ;
754
	    return ;
755
	}
756
 
757
	case fabs_tag : {
758
	    /* Floating absolute value is simple */
759
	    int prev_ov = set_overflow ( e ) ;
760
	    abs_float ( sh ( e ), zw ( son ( e ) ), dest ) ;
761
	    clear_overflow ( prev_ov ) ;
762
	    return ;
763
	}
764
 
765
	case float_tag : {
766
	    /* Casting to a floating point number is simple */
767
	    int prev_ov = set_overflow ( e ) ;
768
	    int_to_float ( sh ( e ), zw ( son ( e ) ), dest ) ;
769
	    clear_overflow ( prev_ov ) ;
770
	    return ;
771
	}
772
 
773
	case chfl_tag : {
774
	    /* Changing a floating variety is simple */
775
	    int prev_ov = set_overflow ( e ) ;
776
	    change_flvar ( sh ( e ), zw ( son ( e ) ), dest ) ;
777
	    clear_overflow ( prev_ov ) ;
778
	    return ;
779
	}
780
 
781
	case and_tag : {
782
	    /* And is a logical operation */
783
	    logop ( and, e, dest, stack ) ;
784
	    return ;
785
	}
786
 
787
	case or_tag : {
788
	    /* Or is a logical operation */
789
	    logop ( or, e, dest, stack ) ;
790
	    return ;
791
	}
792
 
793
	case xor_tag : {
794
	    /* Xor is a logical operation */
795
	    logop ( xor, e, dest, stack ) ;
796
	    return ;
797
	}
798
 
799
	case not_tag : {
800
	    /* Not is a unary operation */
801
	    uop ( not, sh ( e ), son ( e ), dest, stack ) ;
802
	    return ;
803
	}
804
 
805
	case absbool_tag : {
806
	    /* The setcc instruction is not used */
807
	    error ( "Not implemented" ) ;
808
	    return ;
809
	}
810
 
811
	case fplus_tag : {
812
	    /* Floating addition is similar to integer addition */
813
	    exp f1 = son ( e ) ;	/* First argument */
814
	    exp f2 = bro ( f1 ) ;	/* Second argument */
815
	    exp t ;
816
	    long count_dest = 2 ;
817
	    exp de = dest.wh_exp ;
818
 
819
	    int prev_ov = set_overflow ( e ) ;
820
 
821
	    if ( last ( f1 ) ) {
822
		/* If there is only one argument things are simple */
823
		move ( sh ( e ), zw ( f1 ), dest ) ;
824
		clear_overflow ( prev_ov ) ;
825
		return ;
826
	    }
827
 
828
	    if ( last ( f2 ) ) {
829
		/* If there are two arguments code directly */
830
		if ( name ( f2 ) == fneg_tag ) {
831
		    f2 = son ( f2 ) ;
832
		    fl_binop ( fminus_tag, sh ( e ), zw ( f2 ),
833
			       zw ( f1 ), dest ) ;
834
		} else {
835
		    fl_binop ( fplus_tag, sh ( e ), zw ( f1 ),
836
			       zw ( f2 ), dest ) ;
837
		}
838
		clear_overflow ( prev_ov ) ;
839
		return ;
840
	    }
841
 
842
	    if ( last ( bro ( f2 ) ) &&
843
		 name ( bro ( f2 ) ) == real_tag &&
844
		 name ( dest.wh_exp ) != apply_tag
845
              && name ( dest.wh_exp ) != tail_call_tag
846
              && name ( dest.wh_exp ) != apply_general_tag ) {
847
		/* If there are 3 arguments, the last of which is constant */
848
		if ( name ( f2 ) == fneg_tag ) {
849
		    f2 = son ( f2 ) ;
850
		    fl_binop ( fminus_tag, sh ( e ), zw ( f2 ),
851
			       zw ( f1 ), dest ) ;
852
		    fl_binop ( fplus_tag, sh ( e ), zw ( bro ( f2 ) ),
853
			       dest, dest ) ;
854
		} else {
855
		    fl_binop ( fplus_tag, sh ( e ), zw ( f1 ),
856
			       zw ( f2 ), dest ) ;
857
		    fl_binop ( fplus_tag, sh ( e ), zw ( bro ( f2 ) ),
858
			       dest, dest ) ;
859
		}
860
		clear_overflow ( prev_ov ) ;
861
		return ;
862
	    }
863
 
864
	    if ( name ( de ) == ass_tag &&
865
		 name ( son ( de ) ) == name_tag &&
866
		 ( ( props ( son ( son ( de ) ) ) & 0x9 ) == 0x9 ) ) {
867
		count_dest = 0 ;
868
		t = f1 ;
869
		if ( eq_where ( dest, zw ( t ) ) ) count_dest++ ;
870
		while ( !last ( t ) ) {
871
		    t = bro ( t ) ;
872
		    if ( name ( t ) == fneg_tag ) {
873
			if ( eq_where ( zw ( son ( t ) ), dest ) )
874
			    count_dest = 2 ;
875
		    } else {
876
			if ( eq_where ( zw ( t ), dest ) ) count_dest++ ;
877
		    }
878
		}
879
	    }
880
 
881
	    if ( count_dest < 2 && (name ( dest.wh_exp ) != apply_tag
882
                                &&  name ( dest.wh_exp ) != tail_call_tag
883
                                &&  name ( dest.wh_exp ) != apply_general_tag) ) {
884
		if ( count_dest == 1 ) {
885
		    t = f1 ;
886
		} else {
887
		    if ( name ( f2 ) == fneg_tag ) {
888
			exp m = son ( f2 ) ;
889
			fl_binop ( fminus_tag, sh ( e ), zw ( m ),
890
				   zw ( f1 ), dest ) ;
891
		    } else {
892
			fl_binop ( fplus_tag, sh ( e ), zw ( f1 ),
893
				   zw ( f2 ), dest ) ;
894
		    }
895
		    t = bro ( f2 ) ;
896
		}
897
 
898
		for ( ; ; ) {
899
		    where tw ;
900
		    if ( name ( t ) == fneg_tag ) {
901
			tw = zw ( son ( t ) ) ;
902
			if ( !eq_where ( dest, tw ) ) {
903
			    fl_binop ( fminus_tag, sh ( e ), tw, dest, dest ) ;
904
			}
905
		    } else {
906
			tw = zw ( t ) ;
907
			if ( !eq_where ( dest, tw ) ) {
908
			    fl_binop ( fplus_tag, sh ( e ), tw, dest, dest ) ;
909
			}
910
		    }
911
		    if ( last ( t ) ) break ;
912
		    t = bro ( t ) ;
913
		}
914
	    } else {
915
		if ( name ( f2 ) == fneg_tag ) {
916
		    fl_binop ( fminus_tag, sh ( e ), zw ( son ( f2 ) ),
917
			       zw ( f1 ), FP0 ) ;
918
		} else {
919
		    fl_binop ( fplus_tag, sh ( e ), zw ( f1 ),
920
			       zw ( f2 ), FP0 ) ;
921
		}
922
		t = bro ( f2 ) ;
923
		while ( !last ( t ) ) {
924
		    if ( name ( t ) == fneg_tag ) {
925
			fl_binop ( fminus_tag, sh ( e ), zw ( son ( t ) ),
926
				   FP0, FP0 ) ;
927
		    } else {
928
			fl_binop ( fplus_tag, sh ( e ), zw ( t ), FP0, FP0 ) ;
929
		    }
930
		    t = bro ( t ) ;
931
		}
932
		if ( name ( t ) == fneg_tag ) {
933
		    fl_binop ( fminus_tag, sh ( e ), zw ( son ( t ) ),
934
			       FP0, dest ) ;
935
		} else {
936
		    fl_binop ( fplus_tag, sh ( e ), zw ( t ), FP0, dest ) ;
937
		}
938
	    }
939
	    clear_overflow ( prev_ov ) ;
940
	    return ;
941
	}
942
 
943
	/*
944
	     Note : in the following offset operations I have put the
945
	     shape as slongsh rather than sh ( e ).  This is because
946
	     the system stddef.h wrongly says that ptrdiff_t is unsigned
947
	     and I don't trust people to put it right when making up
948
	     TDF libraries.  If this was right sh ( e ) would be slongsh.
949
	*/
950
 
951
	case offset_add_tag : {
952
           make_comment("offset_add_tag...");
953
	    /* Offset addition is a binary operation */
954
	    bop ( add, slongsh, son ( e ), bro ( son ( e ) ), dest, stack ) ;
955
           make_comment("offset_add_tag done");
956
	    return ;
957
	}
958
 
959
	case offset_subtract_tag : {
960
	    /* Offset subtraction is a binary operation */
961
	    bop ( sub, slongsh, bro ( son ( e ) ), son ( e ), dest, stack ) ;
962
	    return ;
963
	}
964
 
965
	case offset_mult_tag : {
966
           make_comment("offset_mult_tag...");
967
	    /* Offset multiplication is a binary operation */
968
	    bop ( mult, slongsh, son ( e ), bro ( son ( e ) ), dest, stack ) ;
969
           make_comment("offset_mult_tag done");
970
	    return ;
971
	}
972
 
973
	case offset_negate_tag : {
974
	    /* Offset negation is a unary operation */
975
	    uop ( negate, slongsh, son ( e ), dest, stack ) ;
976
	    return ;
977
	}
978
 
979
	case offset_div_tag :
980
        case offset_div_by_int_tag : {
981
	  /* Offset division is a binary operation */
982
	  if(name(sh(bro(son(e)))) < slonghd){
983
	    exp changer = me_u3(slongsh,bro(son(e)),chvar_tag);
984
	    bro(son(e)) = changer;
985
	  }
986
	  bop ( div2, slongsh, bro ( son ( e ) ), son ( e ), dest, stack ) ;
987
	  return ;
988
	}
989
 
990
	case offset_pad_tag : {
991
           /* Pad an operand */
992
           exp  cur_offset = son ( e ) ;
993
           long cur_align  = al2 ( sh ( cur_offset ) ) ;
994
           long next_align = al2 ( sh ( e ) ) ;
995
 
996
           make_comment("offset_pad ...") ;
997
 
998
           /* does current alignment include next alignment? */
999
 
1000
           if ( cur_align  >= next_align ) {
1001
 
1002
	      if( ( next_align !=1 ) || ( cur_align ==1 ) ) {
1003
                 coder ( dest, stack, cur_offset ) ;
1004
	      }
1005
	      else {
1006
                 /* left shift */
1007
                 shift( sh(e), mnw(3), zw(cur_offset),dest);
1008
	      }
1009
 
1010
           } else {
1011
              /* cur_align  < next_align */
1012
              where r ;
1013
              if ( whereis ( dest ) == Dreg ) {
1014
                 r = dest ;
1015
              } else {
1016
                 r = D1 ;
1017
                 regsinproc |= regmsk ( REG_D1 ) ;
1018
              }
1019
              codec ( r, stack, cur_offset ) ;
1020
 
1021
              if( cur_align == 1){
1022
                 add ( slongsh, mnw ( next_align - 1 ), r, r ) ;
1023
                 and ( slongsh, mnw ( -next_align ), r, dest ) ;
1024
                 rshift(sh(e),mnw(3),dest,dest);
1025
              }
1026
              else {
1027
                 long al = next_align / 8 ;
1028
                 add ( slongsh, mnw ( al - 1 ), r, r ) ;
1029
                 and ( slongsh, mnw ( -al ), r, dest ) ;
1030
              }
1031
           }
1032
           make_comment("offset_pad done") ;
1033
           return ;
1034
	}
1035
 
1036
	case bitf_to_int_tag : {
1037
	    if ( whereis ( dest ) == Dreg ) {
1038
		coder ( dest, stack, son ( e ) ) ;
1039
		change_var_sh ( sh ( e ), sh ( son ( e ) ), dest, dest ) ;
1040
	    } else {
1041
		regsinproc |= regmsk ( REG_D1 ) ;
1042
		coder ( D1, stack, son ( e ) ) ;
1043
		change_var_sh ( sh ( e ), sh ( son ( e ) ), D1, dest ) ;
1044
	    }
1045
	    return ;
1046
	}
1047
 
1048
	case int_to_bitf_tag : {
1049
	    where r ;
1050
	    long nbits = shape_size ( sh ( e ) ) ;
1051
	    long mask = lo_bits [ nbits ] ;
1052
	    r = ( whereis ( dest ) == Dreg ? dest : D0 ) ;
1053
	    move ( slongsh, zw ( son ( e ) ), r ) ;
1054
	    and ( slongsh, mnw ( mask ), r, dest ) ;
1055
	    return ;
1056
	}
1057
	case offset_max_tag :
1058
	case max_tag : {
1059
	    /* Maximum */
1060
	    bop ( maxop, sh ( e ), son ( e ), bro ( son ( e ) ), dest, stack ) ;
1061
	    return ;
1062
	}
1063
 
1064
	case min_tag : {
1065
	    /* Minimum */
1066
	    bop ( minop, sh ( e ), son ( e ), bro ( son ( e ) ), dest, stack ) ;
1067
	    return ;
1068
	}
1069
 
1070
	case cont_tag : {
1071
           make_comment("cont_tag ...") ;
1072
 
1073
           if ( name ( sh ( e ) ) == bitfhd ) {
1074
              bitf_to_int ( e, sh ( e ), dest, stack ) ;
1075
              return ;
1076
           }
1077
 
1078
           move ( sh ( e ), zw ( e ), dest ) ;
1079
 
1080
           make_comment("cont_tag done") ;
1081
           return ;
1082
	}
1083
 
1084
	default : {
1085
 
1086
	    if ( !is_o ( name ( e ) ) ) {
1087
		/* If e is not an operand, code e into a register */
1088
		exp s ;
1089
		where w ;
1090
		if (   name ( e ) == apply_tag
1091
                    || name ( e ) == apply_general_tag
1092
                    || name ( e ) == tail_call_tag ) {
1093
		    s = sim_exp ( sh ( e ), D0 ) ;
1094
		} else {
1095
		    if ( whereis ( dest ) == Dreg ) {
1096
/*			error ( "Untested optimization" ) ;*/
1097
			s = sim_exp ( sh ( e ), dest ) ;
1098
		    } else {
1099
			regsinproc |= regmsk ( REG_D1 ) ;
1100
			s = sim_exp ( sh ( e ), D1 ) ;
1101
		    }
1102
		}
1103
		w = zw ( s ) ;
1104
 
1105
		coder ( w, stack, e ) ;
1106
 
1107
		/* Move the value of this register into dest */
1108
		move ( sh ( e ), w, dest ) ;
1109
		retcell ( s ) ;
1110
		if ( have_cond == 3 ) have_cond = 1 ;
1111
		return ;
1112
	    }
1113
 
1114
	    if ( name ( e ) == reff_tag && shape_size ( sh ( e ) ) != 32 ) {
1115
		/* Deal with pointers to bitfields */
1116
                exp s ;
1117
		where d ;
1118
/*                s = sim_exp ( sh ( e ), D0 ) ; */
1119
		d = mw ( dest.wh_exp, dest.wh_off + 32 ) ;
1120
		if ( shape_size ( sh ( son ( e ) ) ) == 32 ) {
1121
                    make_comment("Pointer to bitfield (32) ...") ;
1122
		    coder ( dest, stack, son ( e ) ) ;
1123
		    move ( slongsh, mnw ( no ( e ) ), d ) ;
1124
                    make_comment("Pointer to bitfield (32) done") ;
1125
		    return ;
1126
		}
1127
		make_comment("Pointer to bitfield ...") ;
1128
		coder ( dest, stack, son ( e ) ) ;
1129
		add ( slongsh, mnw ( no ( e ) ), d, d ) ;
1130
		make_comment("Pointer to bitfield done") ;
1131
		return ;
1132
	    }
1133
 
1134
	    if ( name ( e ) == reff_tag &&
1135
		 ( name ( son ( e ) ) == name_tag ||
1136
		 ( name ( son ( e ) ) == cont_tag &&
1137
		   name ( son ( son ( e ) ) ) == name_tag ) ) ) {
1138
		/* Deal with pointers with offsets */
1139
		long off = no ( e ) / 8 ;
1140
                make_comment("reff_tag ...");
1141
		add ( slongsh, zw ( son ( e ) ), mnw ( off ), dest ) ;
1142
                make_comment("reff_tag done");
1143
		return ;
1144
	    }
1145
 
1146
	    if ( ( name ( e ) == name_tag && isvar ( son ( e ) ) ) ||
1147
		 name ( e ) == reff_tag){
1148
	      /* Deal with pointers */
1149
	      mova ( zw ( e ), dest ) ;
1150
	      return ;
1151
	    }
1152
 
1153
	    if ( name ( e ) == clear_tag ) {
1154
		/* Deal with clear shapes */
1155
		char sn = name ( sh ( e ) ) ;
1156
		if ( sn >= shrealhd && sn <= doublehd ) {
1157
		    move ( sh ( e ), fzero, dest ) ;
1158
		}
1159
#ifndef tdf3
1160
                if(name (dest.wh_exp) == apply_tag ||
1161
                   name (dest.wh_exp) == apply_general_tag ||
1162
                   name (dest.wh_exp) == tail_call_tag ) {
1163
                   move ( sh ( e ), zero, dest ) ;
1164
                }
1165
#endif
1166
		return ;
1167
	    }
1168
 
1169
	    if (name(e) == val_tag && ((name(sh(e)) == s64hd) ||
1170
				      name(sh(e)) == u64hd)){
1171
	      flt64 bval;
1172
	      where w;
1173
	      bval = exp_to_f64(e);
1174
              if ( eq_where ( dest, D0_D1 ) ) {
1175
                 move_const(slongsh,32,bval.big, D1);
1176
                 move_const(slongsh,32,bval.small, D0);
1177
              }
1178
              else {
1179
                 w = dest;
1180
                 move_const(sh(e),32,bval.small,w);
1181
                 w.wh_off += 32;
1182
                 move_const(sh(e),32,bval.big,w);
1183
              }
1184
	      return;
1185
	    }
1186
 
1187
 
1188
	    /* If all else fails, use move */
1189
	    if ( name ( e ) == top_tag ) return ;
1190
 
1191
	    move ( sh ( e ), zw ( e ), dest ) ;
1192
	    return ;
1193
	}
1194
    }
1195
}