Subversion Repositories tendra.SVN

Rev

Rev 6 | Details | Compare with Previous | Last modification | View Log | RSS feed

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