Subversion Repositories tendra.SVN

Rev

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

Rev Author Line No. Line
6 7u83 1
/*
2
 * Copyright (c) 2002-2006 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
 */
2 7u83 31
 
32
/*
33
    		 Crown Copyright (c) 1997
34
 
35
    This TenDRA(r) Computer Program is subject to Copyright
36
    owned by the United Kingdom Secretary of State for Defence
37
    acting through the Defence Evaluation and Research Agency
38
    (DERA).  It is made available to Recipients with a
39
    royalty-free licence for its use, reproduction, transfer
40
    to other parties and amendment for any purpose not excluding
41
    product development provided that any such use et cetera
42
    shall be deemed to be acceptance of the following conditions:-
43
 
44
        (1) Its Recipients shall ensure that this Notice is
45
        reproduced upon any copies or amended versions of it;
46
 
47
        (2) Any amended version of it shall be clearly marked to
48
        show both the nature of and the organisation responsible
49
        for the relevant amendment or amendments;
50
 
51
        (3) Its onward transfer from a recipient to another
52
        party shall be deemed to be that party's acceptance of
53
        these conditions;
54
 
55
        (4) DERA gives no warranty or assurance as to its
56
        quality or suitability for any purpose and DERA accepts
57
        no liability whatsoever in relation to any use to which
58
        it may be put.
59
*/
60
/*
61
			    VERSION INFORMATION
62
			    ===================
63
 
64
--------------------------------------------------------------------------
65
$Header: /u/g/release/CVSROOT/Source/src/installers/680x0/common/ops_misc.c,v 1.1.1.1 1998/01/17 15:55:49 release Exp $
66
--------------------------------------------------------------------------
67
$Log: ops_misc.c,v $
68
 * Revision 1.1.1.1  1998/01/17  15:55:49  release
69
 * First version to be checked into rolling release.
70
 *
71
Revision 1.5  1997/11/13 08:27:16  ma
72
All avs test passed (except add_to_ptr).
73
 
74
Revision 1.4  1997/11/10 15:38:09  ma
75
.
76
 
77
Revision 1.3  1997/11/09 14:22:51  ma
78
Now is_signed is used instead of issigned. Added clear for 64 bit shapes.
79
 
80
Revision 1.2  1997/10/29 10:22:27  ma
81
Replaced use_alloca with has_alloca.
82
 
83
Revision 1.1.1.1  1997/10/13 12:42:57  ma
84
First version.
85
 
86
Revision 1.6  1997/10/13 08:49:52  ma
87
Made all pl_tests for general proc & exception handling pass.
88
 
89
Revision 1.5  1997/09/25 06:45:28  ma
90
All general_proc tests passed
91
 
92
Revision 1.4  1997/06/24 10:56:07  ma
93
Added changes for "Plumhall Patch"
94
 
95
Revision 1.3  1997/06/18 10:09:43  ma
96
Checking in before merging with Input Baseline changes.
97
 
98
Revision 1.2  1997/04/20 11:30:36  ma
99
Introduced gcproc.c & general_proc.[ch].
100
Added cases for apply_general_proc next to apply_proc in all files.
101
 
102
Revision 1.1.1.1  1997/03/14 07:50:16  ma
103
Imported from DRA
104
 
105
 * Revision 1.1.1.1  1996/09/20  10:56:57  john
106
 *
107
 * Revision 1.3  1996/07/30  16:31:50  john
108
 * Removed offset conversion
109
 *
110
 * Revision 1.2  1996/07/05  14:24:52  john
111
 * Changes for spec 3.1
112
 *
113
 * Revision 1.1.1.1  1996/03/26  15:45:16  john
114
 *
115
 * Revision 1.4  94/06/29  14:24:51  14:24:51  ra (Robert Andrews)
116
 * Need to be more careful about bitfields in change_variety.
117
 *
118
 * Revision 1.3  94/02/21  16:02:15  16:02:15  ra (Robert Andrews)
119
 * Clear up a couple of int-long confusions.
120
 *
121
 * Revision 1.2  93/03/03  14:49:46  14:49:46  ra (Robert Andrews)
122
 * Added error treatment processing routine, jump_overflow.
123
 *
124
 * Revision 1.1  93/02/22  17:16:26  17:16:26  ra (Robert Andrews)
125
 * Initial revision
126
 *
127
--------------------------------------------------------------------------
128
*/
129
 
130
 
131
#include "config.h"
132
#include "common_types.h"
133
#include "assembler.h"
134
#include "basicread.h"
135
#include "check.h"
136
#include "exp.h"
137
#include "expmacs.h"
138
#include "externs.h"
139
#include "install_fns.h"
140
#include "shapemacs.h"
141
#include "tags.h"
142
#include "mach.h"
143
#include "mach_ins.h"
144
#include "where.h"
145
#include "mach_op.h"
146
#include "instr.h"
147
#include "codex.h"
148
#include "instrs.h"
149
#include "coder.h"
150
#include "tests.h"
151
#include "operations.h"
152
#include "evaluate.h"
153
#include "utility.h"
154
#include "translate.h"
155
#include "ops_shared.h"
156
#include "special_exps.h"
157
 
158
/************************************************************************
159
  SET_OVERFLOW
160
  If the expression e has a long_jump error treatment then
161
  the global variable overflow_jump is set the the corresponding label.
162
  If e has the error treatment trap overflow_jump is set to -1 instead.
163
  The previous value of overflow_jump is returned, so it can be restored.
164
 ************************************************************************/
165
 
6 7u83 166
int
167
set_overflow(exp e)
2 7u83 168
{
6 7u83 169
	int prev_overflow_jump = overflow_jump;
2 7u83 170
 
6 7u83 171
	if (! optop(e)) {
172
		if (pt(e)) {
173
			/* error jump on overflow */
174
			overflow_jump = no(son(pt(e)));
175
			overflow_jump = ptno(pt(son(pt(e))));
176
			overflow_jump = e->ptf.expr->sonf.expr->ptf.expr->ptf.l;
2 7u83 177
 
6 7u83 178
		} else {
179
			overflow_jump = -1 ; /* trap on overflow */
180
		}
181
	}
2 7u83 182
 
6 7u83 183
	return prev_overflow_jump;
2 7u83 184
}
185
 
186
/************************************************************************
187
  CLEAR_OVERFLOW
188
  Restore the global variable overflow_jump with a previous value.
189
 ************************************************************************/
190
 
6 7u83 191
void
192
clear_overflow(int prev_overflow_jump)
2 7u83 193
{
6 7u83 194
	overflow_jump = prev_overflow_jump;
2 7u83 195
}
196
 
197
/************************************************************************
198
  HAVE_OVERFLOW
199
  Used to test if overflow_jump has been set (we have an error treatment)
200
 ************************************************************************/
201
 
6 7u83 202
int
203
have_overflow(void)
2 7u83 204
{
6 7u83 205
	return overflow_jump;
2 7u83 206
}
207
 
208
/************************************************************************
209
  TRAP_INS
210
  Calls the error handler with ec as argument
211
 ************************************************************************/
212
 
6 7u83 213
void
214
trap_ins(int ec)
2 7u83 215
{
6 7u83 216
	push(slongsh, L32, mnw(ec));
217
	callins(0, get_error_handler());
2 7u83 218
}
219
 
220
/*
221
    OVERFLOW JUMP LABEL
222
 
223
    This is 0 to denote that overflows should be ignored.  Otherwise
224
    it gives the label to be jumped to.
225
*/
226
 
6 7u83 227
int overflow_jump = 0;
2 7u83 228
 
229
int err_continue = 0;
230
 
231
/************************************************************************
232
  TEST_OVERFLOW2
233
 
234
  If an error_treatment is specified and the previous instruction
235
  overflowed then either a trap or a jump is takken.
236
 
237
  The test condition is specified by br_ins
238
  ************************************************************************/
239
 
6 7u83 240
void
241
test_overflow2(int br_ins)
2 7u83 242
{
6 7u83 243
	if (overflow_jump == -1) {
244
		ins0(bra2trap(br_ins));
245
	} else if (overflow_jump) {
246
		make_jump(br_ins, overflow_jump);
247
	}
2 7u83 248
}
249
 
250
 
251
/************************************************************************
252
  TEST_OVERFLOW
253
 
254
  If an error_treatment is specified and the previous instruction
255
  overflowed then either a trap or a jump is takken.
256
 
257
  This function finds the right test condition based on overflow_type
258
  ************************************************************************/
259
 
6 7u83 260
void
261
test_overflow(overflow_type typ)
2 7u83 262
{
6 7u83 263
	int instr;
2 7u83 264
 
6 7u83 265
	if (! have_overflow()) {
266
		return;
267
	}
2 7u83 268
 
6 7u83 269
	switch (typ) {
270
	case UNCONDITIONAL:
271
		instr = m_bra;
272
		break;
273
	case ON_OVERFLOW:
274
		instr = m_bvs;
275
		break;
276
	case ON_CARRY:
277
		instr = m_bcs;
278
		break;
279
	case ON_FP_OVERFLOW:
280
	case ON_FP_CARRY:
281
		ins2(m_fmovel, L32, L32, register(REG_FPSR), D0, 1);
282
		ins2h(m_andl, 0x00001c00, L32, D0, 1);
283
		instr = m_bne;
284
		break;
285
	case ON_FP_OPERAND_ERROR:
286
		ins2(m_fmovel, L32, L32, register(REG_FPSR), D0, 1);
287
		ins2h(m_andl, 0x00002000, L32, D0, 1);
288
		instr = m_bne;
289
		break;
290
	default:
291
		error("invalid overflow test");
292
		return;
293
	}
2 7u83 294
 
6 7u83 295
	test_overflow2(instr);
2 7u83 296
}
297
 
298
/************************************************************************
299
  CHECKALLOC_STACK
300
 
301
  Checks if it is possible to allocate sz bytes on the stack.
302
  If it is not possible an exception is generated.
303
  else if do_alloc is TRUE, the allocation is done.
304
 
305
  ************************************************************************/
306
 
6 7u83 307
void
308
checkalloc_stack(where sz, int do_alloc)
2 7u83 309
{
6 7u83 310
	int erlab = next_lab();
311
	int cnlab = next_lab();
312
	make_comment("check for stack overflow ...");
313
	ins2(m_movl, 32, 32, SP, D0, 1);
314
	ins2(m_subl, 32, 32, sz, D0, 1);
315
	make_jump(m_bcs, erlab);
316
	ins2(m_cmpl, 32, 32, mw(get_stack_limit(), 0), D0, 0);
317
	make_jump(m_bcc, cnlab);
318
	make_label(erlab);
319
	trap_ins(f_stack_overflow);
320
	make_label(cnlab);
321
	if (do_alloc) {
322
		ins2(m_movl, 32, 32, D0, SP, 1);
323
	}
324
	make_comment("check for stack overflow done");
2 7u83 325
}
326
 
327
/*
328
    MARK D1 AS SPECIAL
329
 
330
    This flag is used to indicate that the D1 regsiter is being used
331
    as a special register and should be treated with care.
332
*/
333
 
6 7u83 334
bool D1_is_special = 0;
2 7u83 335
 
336
 
337
/*
338
    OUTPUT A CALL INSTRUCTION
339
 
340
    The procedure call given by fn is output.  A temporary A-register
341
    needs to be used when fn is not a simple procedure name.  The
342
    stack is then increased by longs to overwrite the procedure arguments.
343
*/
344
 
6 7u83 345
void
346
callins(long longs, exp fn)
2 7u83 347
{
6 7u83 348
	mach_op *op;
349
	exp s = son(fn), call_exp, fn_exp;
350
	bool simple_proc = 0;
351
	fn_exp = fn;
2 7u83 352
 
6 7u83 353
	/* Let's see if we have the procedure at compilation time */
354
	if (name(fn) == name_tag && ! isvar(s) && isglob(s)) {
355
		exp def = son ( s ) ; /* Definition of Identify construct */
356
		if (!def || name(def) == proc_tag ||
357
		    name(def) == general_proc_tag) {
358
			simple_proc = 1;
359
		}
360
	}
2 7u83 361
 
6 7u83 362
	/* If this is not a straight call, put the name into an A register */
363
	if (! simple_proc) {
364
		where w;
365
		w = zw(fn);
366
		if (whereis(w)!= Areg) {
367
			int r = next_tmp_reg();
368
			regsinproc |= regmsk(r);
369
			move(slongsh, w, register(r));
370
			fn_exp = register(r).wh_exp;
371
		}
2 7u83 372
	}
6 7u83 373
	/* Now output the call instruction */
374
	call_exp = getexp(proksh, nilexp, 0, fn_exp, nilexp, 0, L0, cont_tag);
375
	op = operand(L32, zw(call_exp));
376
	make_instr(m_call, op, null, ~save_msk);
377
	no_calls++;
378
	retcell(call_exp);
379
	dec_stack(-longs);
380
	have_cond = 0;
381
	return;
2 7u83 382
}
383
 
384
/************************************************************************
385
    OUTPUT A JMP INSTRUCTION
386
 
387
    The jump to the procedure given by fn is output.  A temporary A-register
388
    needs to be used when fn is not a simple procedure name.
389
 
390
 ************************************************************************/
391
 
6 7u83 392
void
393
jmpins(exp fn)
2 7u83 394
{
6 7u83 395
	mach_op *op;
396
	exp s = son(fn), jmp_exp, fn_exp;
397
	fn_exp = fn;
398
	/* If this is not a straight jmp, put the name into an A register */
399
	if (name(fn)!= name_tag || isvar(s) || !isglob(s)) {
400
		where w;
401
		w = zw(fn);
402
		if (whereis(w)!= Areg) {
403
			int r = next_tmp_reg();
404
			regsinproc |= regmsk(r);
405
			move(slongsh, w, register(r));
406
			fn_exp = register(r).wh_exp;
407
		}
2 7u83 408
	}
6 7u83 409
	/* Now output the jmp instruction */
410
	jmp_exp = getexp(proksh, nilexp, 0, fn_exp, nilexp, 0, L0, cont_tag);
411
	op = operand(L32, zw(jmp_exp));
412
	make_instr(m_jmp, op, null, ~save_msk);
413
	retcell(jmp_exp);
414
	have_cond = 0;
415
	return;
2 7u83 416
}
417
 
418
 
419
 
420
/*
421
    CONDITION CODES STATUS
422
 
423
    Many comparison instructions are unnecessary because the previous
424
    instruction has set the appropriate condition flags.  The flag
425
    have_cond deals with this.  A value of 0 indicates that we have
426
    no information on the flag values.  A value of 1 indicates that
427
    the last instruction set the flags appropriate to the where
428
    last_cond of size last_cond_sz.  A value of 2 is used immediately
429
    after a cmp instruction, the two arguments of the cmp being
430
    last_cond and last_cond2.  Finally a value of 3 is used immediately
431
    after certain move instructions to indicate that the flags are
432
    appropriate to either of the arguments, last_cond or last_cond_alt.
433
*/
434
 
6 7u83 435
bool have_cond = 0;
436
where last_cond;
437
where last_cond2;
438
where last_cond_alt;
439
long last_cond_sz;
2 7u83 440
 
441
 
442
/*
443
    COMPARE WITH ZERO
444
 
445
    The value a (of shape sha and size sz) is compared with 0.  The
446
    cases when have_cond is 1 or 3 are dealt with by this routine.
447
*/
448
 
6 7u83 449
void
450
cmp_zero(shape sha, long sz, where a)
2 7u83 451
{
6 7u83 452
	long w;
453
	/* Check existing condition codes */
454
	if (have_cond == 1 && last_cond_sz == sz) {
455
		if (eq_where(last_cond, a)) {
456
			return;
457
		}
458
	}
459
	if (have_cond == 3 && last_cond_sz == sz) {
460
		if (eq_where(last_cond, a)) {
461
			return;
462
		}
463
		if (eq_where(last_cond_alt, a)) {
464
			return;
465
		}
466
	}
467
	w = whereis(a);
468
	if (w == Areg) {
469
		/* This does work, despite the manual */
470
		int instr = ins(sz, ml_tst);
471
		ins1(instr, sz, a, 0);
472
	} else if (w == Freg || (w == External && name(sha) == prokhd)) {
473
		/* Moving to D0 sets the flags */
474
		move(sha, a, D0);
475
	} else {
476
		if (sz == 64) {
477
			where w;
478
			w = a;
479
			ins1(m_tstl, 32, w, 0);
480
			w.wh_off += 32;
481
			ins1(m_tstl, 32, w, 0);
482
		} else {
483
			int instr = ins(sz, ml_tst);
484
			ins1(instr, sz, a, 0);
485
		}
486
	}
487
	/* Set new condition codes */
488
	set_cond(a, sz);
489
	return;
2 7u83 490
}
491
 
492
 
493
/*
494
    AUXILIARY COMPARISON ROUTINE
495
 
496
    The values a and b of size sz are compared.
497
*/
498
 
6 7u83 499
static bool
500
cmp_aux(long sz, where a, where b)
2 7u83 501
{
6 7u83 502
	where d;
503
	if (whereis(a) == Freg) {
504
		if (whereis(b) == Freg) {
505
			move(slongsh, a, D0);
506
			move(slongsh, b, D1);
507
			regsinproc |= regmsk(REG_D1);
508
			return (cmp_aux(sz, D1, D0));
509
		}
510
		if (eq_where(b, D0)) {
511
			d = D1;
512
			regsinproc |= regmsk(REG_D1);
513
		} else {
514
			d = D0;
515
		}
516
		move(slongsh, a, d);
517
		return (cmp_aux(sz, b, d));
2 7u83 518
	}
6 7u83 519
	if (whereis(b) == Freg) {
520
		if (eq_where(a, D0)) {
521
			d = D1;
522
			regsinproc |= regmsk(REG_D1);
523
		} else {
524
			d = D0;
525
		}
526
		move(slongsh, b, d);
527
		return (cmp_aux(sz, a, d));
2 7u83 528
	}
6 7u83 529
	ins2_cmp(ins(sz, ml_cmp), sz, sz, a, b, 0);
530
	have_cond = 2;
531
	last_cond = a;
532
	last_cond2 = b;
533
	last_cond_sz = sz;
534
	return (1);
2 7u83 535
}
536
 
537
 
538
/*
539
    COMPARE WITH A CONSTANT
540
 
541
    The value a is compared with the constant value c, the type of the
542
    comparison being given by ntst.  The value returned by this routine
543
    has the same meaning as that returned by cmp.
544
*/
545
 
6 7u83 546
static bool
547
cmp_const(shape sha, long sz, where c, where a, long ntst)
2 7u83 548
{
6 7u83 549
	bool sw;
550
	long v = nw(c);
551
	if (is_offset(c.wh_exp)) {
552
		v /= 8;
2 7u83 553
	}
6 7u83 554
	if (v == 0) {
555
		if (!is_signed(sha) && ntst != tst_neq && ntst != tst_eq) {
556
			/* Force an actual comparison in these cases */
557
			have_cond = 0;
558
		}
559
		cmp_zero(sha, sz, a);
560
		return (1);
561
	}
2 7u83 562
 
6 7u83 563
	if (v < -128 || v > 127) {
564
		sw = cmp_aux(sz, c, a);
565
		return (sw);
566
	}
2 7u83 567
 
6 7u83 568
	if (interfere(a, D0)) {
569
		sw = cmp_aux(sz, c, a);
570
		return (sw);
571
	}
2 7u83 572
 
573
#ifdef REJECT
6 7u83 574
	if (!output_immediately) {
575
		mach_ins *p = current_ins;
576
		if (p && p->ins_no == m_moveq && p->op1->def.num == v) {
577
			sw = cmp_aux(sz, a, register(p->op2->def.num));
578
			last_cond2 = c;
579
			return (!sw);
580
		}
2 7u83 581
	}
582
#endif
583
 
6 7u83 584
	move(slongsh, c, D0);
585
	sw = cmp_aux(sz, a, D0);
586
	last_cond2 = c;
587
	return (!sw);
2 7u83 588
}
589
 
590
 
591
/*
592
    MAIN COMPARISON ROUTINE
593
 
594
    The values var and limit of shape sha are compared for the test
595
    indicated by ntst.  Depending on the addressing modes of var and
596
    limit we may do "cmp var,limit" or "cmp limit,var".  In the first
597
    case we return 1 and in the second 0.  The case when have_cond is
598
    2 is dealt with by this routine.
599
*/
600
 
6 7u83 601
bool
602
cmp(shape sha, where var, where limit, long ntst)
2 7u83 603
{
6 7u83 604
	bool sw;
605
	long sz = shape_size(sha);
606
	long rt = shtype(sha);
2 7u83 607
 
6 7u83 608
	long whv = whereis(var);
609
	long whl = whereis(limit);
2 7u83 610
 
611
#if 0
6 7u83 612
	if (name(sha) == ptrhd) {
613
		make_comment("HACK shape size");
614
		shape_size(sha) = 32;
615
		sz = 32;
616
	}
2 7u83 617
#endif
6 7u83 618
	if (rt == Freg) {
619
		/* Floating point comparisons are never swapped */
620
		where rv, rl;
621
		have_cond = 0;
622
		if (whv == Freg && last_use(var)) {
623
			rv = var;
624
		} else {
625
			if (eq_where(limit, FP0)) {
626
				rv = FP1;
627
				regsinproc |= regmsk(REG_FP1);
628
			} else {
629
				rv = FP0;
630
			}
631
		}
632
		if (whl == Freg && last_use(limit)) {
633
			rl = limit;
634
		} else {
635
			if (eq_where(rv, FP0)) {
636
				rl = FP1;
637
				regsinproc |= regmsk(REG_FP1);
638
			} else {
639
				rl = FP0;
640
			}
641
		}
642
		if (whv == Freg) {
643
			push_float(sz, var);
644
			pop_float(sz, rv);
645
		} else {
646
			move(sha, var, rv);
647
		}
648
		if (whl == Freg) {
649
			push_float(sz, limit);
650
			pop_float(sz, rl);
651
		} else {
652
			move(sha, limit, rl);
653
		}
654
		ins2_cmp(m_fcmpx, sz, sz, rl, rv, 0);
655
		return (1);
2 7u83 656
	}
6 7u83 657
 
658
	/* Check existing condition codes */
659
	if (have_cond == 2 && last_cond_sz == sz) {
660
		if (eq_where(last_cond, var) && eq_where(last_cond2, limit)) {
661
			return (0);
662
		}
663
		if (eq_where(last_cond, limit) && eq_where(last_cond2, var)) {
664
			return (1);
665
		}
2 7u83 666
	}
6 7u83 667
 
668
	if (whl == Value) {
669
		sw = cmp_const(sha, sz, limit, var, ntst);
670
		return (sw);
2 7u83 671
	}
6 7u83 672
 
673
	if (whv == Value) {
674
		sw = cmp_const(sha, sz, var, limit, ntst);
675
		return (!sw);
2 7u83 676
	}
677
 
6 7u83 678
	if (whl == Dreg || whl == Areg) {
679
		sw = cmp_aux(sz, var, limit);
680
		return (!sw);
681
	}
2 7u83 682
 
6 7u83 683
	if (whv == Dreg || whv == Areg) {
684
		sw = cmp_aux(sz, limit, var);
685
		return (sw);
686
	}
2 7u83 687
 
688
#if 0
6 7u83 689
	if (name(var.wh_exp) == name_tag && name(sha) == prokhd &&
690
	    ((son(son(var.wh_exp)) ==nilexp) ||
691
	     (name(son(son(var.wh_exp))) == proc_tag))) {
692
		exp proc_cont = getexp(sha, nilexp, 0, var.wh_exp, nilexp, 0,
693
				       0, cont_tag);
694
		var.wh_exp = proc_cont;
695
	}
2 7u83 696
#endif
697
 
6 7u83 698
	if (!interfere(var, D0)) {
699
		move(sha, limit, D0);
700
		sw = cmp_aux(sz, var, D0);
701
		last_cond2 = limit;
702
		return (!sw);
703
	}
2 7u83 704
 
6 7u83 705
	if (!interfere(limit, D0)) {
706
		move(sha, var, D0);
707
		sw = cmp_aux(sz, limit, D0);
708
		last_cond2 = var;
709
		return (sw);
710
	}
2 7u83 711
 
6 7u83 712
	move(sha, limit, D1);
713
	sw = cmp_aux(sz, var, D1);
714
	regsinproc |= regmsk(REG_D1);
715
	last_cond2 = limit;
716
	return (!sw);
2 7u83 717
}
718
 
719
 
720
/*
721
    OUTPUT A PUSH INSTRUCTION
722
 
723
    The value wh of shape sha and size sz is pushed onto the stack.
724
*/
725
 
6 7u83 726
void
727
push(shape sha, long sz, where wh)
2 7u83 728
{
6 7u83 729
	long s;
730
	mach_op *op1, *op2;
731
	bool real_push = 1;
732
	if (sz != 32) {
733
		if (is_signed(sha) && (whereis(wh) == Dreg)) {
734
			change_var_sh(slongsh, sha, wh, wh);
735
			push(slongsh, L32, wh);
736
		} else {
737
			change_var_sh(slongsh, sha, wh, D0);
738
			push(slongsh, L32, D0);
739
		}
740
		have_cond = 0;
741
		return;
742
	}
743
	if (stack_change) {
744
		stack_change -= 32;
745
		real_push = 0;
746
		if (stack_direction) {
747
			update_stack();
748
		}
749
		s = stack_change;
750
		stack_change = 0;
751
	}
752
	op1 = operand(sz, wh);
753
	if (real_push) {
754
		op2 = make_dec_sp();
2 7u83 755
	} else {
6 7u83 756
		op2 = make_indirect(REG_SP, s / 8);
2 7u83 757
	}
6 7u83 758
	make_instr(m_movl, op1, op2, 0);
759
	have_cond = 0;
760
	if (real_push) {
761
		stack_size -= 32;
762
	} else {
763
		stack_change = s;
764
	}
765
	return;
2 7u83 766
}
767
 
768
 
769
/*
770
    PUSH A FLOATING POINT REGISTER
771
 
772
    The floating-point register wh of size sz is pushed onto the stack.
773
*/
774
 
6 7u83 775
void
776
push_float(long sz, where wh)
2 7u83 777
{
6 7u83 778
	mach_op *op1 = operand(sz, wh);
779
	mach_op *op2 = make_dec_sp();
780
	int instr = insf(sz, ml_fmove);
781
	make_instr(instr, op1, op2, 0);
782
	stack_size -= sz;
783
	have_cond = 0;
784
	return;
2 7u83 785
}
786
 
787
 
788
/*
789
    OUTPUT A POP OPERATION
790
 
791
    A value of shape sha and size sz is popped from the stack into wh.
792
*/
793
 
6 7u83 794
void
795
pop(shape sha, long sz, where wh)
2 7u83 796
{
6 7u83 797
	mach_op *op1, *op2;
798
	if (sz != 32) {
799
		if (whereis(wh) == Dreg) {
800
			pop(slongsh, L32, wh);
801
			change_var_sh(sha, slongsh, wh, wh);
802
		} else {
803
			pop(slongsh, L32, D0);
804
			change_var_sh(sha, slongsh, D0, wh);
805
		}
806
		have_cond = 0;
807
		return;
2 7u83 808
	}
6 7u83 809
	op1 = make_inc_sp();
810
	op2 = operand(sz, wh);
811
	make_instr(m_movl, op1, op2, 0);
812
	have_cond = 0;
813
	stack_size += sz;
814
	return;
2 7u83 815
}
816
 
817
 
818
/*
819
    POP A FLOATING POINT REGISTER
820
 
821
    A value of size sz is popped from the stack into the floating-point
822
    register wh.
823
*/
824
 
6 7u83 825
void
826
pop_float(long sz, where wh)
2 7u83 827
{
6 7u83 828
	mach_op *op1 = make_inc_sp();
829
	mach_op *op2 = operand(sz, wh);
830
	int instr = insf(sz, ml_fmove);
831
	make_instr(instr, op1, op2, 0);
832
	have_cond = 0;
833
	stack_size += sz;
834
	return;
2 7u83 835
}
836
 
837
 
838
/*
839
    MOVE AN ADDRESS INTO A TEMPORARY REGISTER
840
 
841
    The effective address of wh is loaded into a temporary register and
842
    the register number is returned.  By default, register r is used,
843
    but if try is true we see if we can do better.
844
*/
845
 
6 7u83 846
static int
847
tmp_mova(where wh, int r, bool try)
2 7u83 848
{
6 7u83 849
	tmp_reg_prefer = r;
850
	mova(wh, register(r));
851
	if (try && !output_immediately && current_ins) {
852
		int i = current_ins->ins_no;
853
		if (i == m_lea || i == m_movl) {
854
			mach_op *op1 = current_ins->op1;
855
			mach_op *op2 = current_ins->op2;
856
			if (op2->type == MACH_REG && op2->def.num == r) {
857
				int t = r;
858
				if (i == m_lea) {
859
					if (op1->type == MACH_CONT) {
860
						op1 = op1->of;
861
						if (op1->type == MACH_REG &&
862
						    op1->plus == null) {
863
							t = op1->def.num;
864
						}
865
					}
866
				} else {
867
					if (op1->type == MACH_REG) {
868
						t = op1->def.num;
869
					}
870
				}
871
				if (t != r) {
872
					current_ins->ins_no = m_ignore_ins;
873
					op2->def.num = t;
874
					r = t;
875
				}
2 7u83 876
			}
877
		}
878
	}
6 7u83 879
	regsinproc |= regmsk(r);
880
	return (r);
2 7u83 881
}
882
 
883
 
884
/*
885
    MOVE A CONSTANT VALUE
886
 
887
    The constant value c is assigned to the where to (of shape sha and
888
    size sz).
889
*/
890
 
6 7u83 891
void
892
move_const(shape sha, long sz, long c, where to)
2 7u83 893
{
6 7u83 894
	int instr;
895
	int whto = whereis(to);
2 7u83 896
 
6 7u83 897
	if (c == 0) {
898
		/* Clearing is a special case */
899
		if (whto == Dreg) {
900
			ins2n(m_moveq, 0, L32, to, 1);
901
			set_cond(to, sz);
902
			return;
903
		}
904
		if (whto == Areg) {
905
			ins2(m_subl, L32, L32, to, to, 1);
906
			have_cond = 0;
907
			return;
908
		}
909
		if (sz == 64) {
910
			where w;
911
			w = to;
912
			ins1(m_clrl, 32, w, 0);
913
			w.wh_off += 32;
914
			ins1(m_clrl, 32, w, 0);
915
		} else {
916
			instr = ins(sz, ml_clr);
917
			ins1(instr, sz, to, 1);
918
			set_cond(to, sz);
919
		}
920
		return;
2 7u83 921
	}
6 7u83 922
 
923
	instr = ins(sz, ml_mov);
924
 
925
	if (sz == 8) {
926
		c &= 0xff;
2 7u83 927
	}
6 7u83 928
	if (sz == 16) {
929
		c &= 0xffff;
930
	}
931
	if (c >= -128 && c <= 127) {
932
		/* Look for quick moves */
933
		if (whto == Dreg) {
934
			ins2n(m_moveq, c, L32, to, 1);
935
			set_cond(to, sz);
936
			return;
937
		} else {
938
			ins2n(m_moveq, c, L32, D0, 1);
939
			if (whto == Areg) {
940
				instr = m_movl;
941
			}
942
			ins2(instr, sz, sz, D0, to, 1);
943
			if (whto == Areg) {
944
				have_cond = 0;
945
			} else {
946
				set_cond(to, sz);
947
			}
948
			return;
949
		}
950
	}
2 7u83 951
 
6 7u83 952
	if (whto == Areg && sz == 8) {
953
		ins2n(instr, c, sz, D0, 1);
954
		ins2(m_movl, L32, L32, D0, to, 1);
2 7u83 955
	} else {
6 7u83 956
		ins2n(instr, c, sz, to, 1);
2 7u83 957
	}
6 7u83 958
	if (whto == Areg) {
959
		have_cond = 0;
960
	} else {
961
		set_cond(to, sz);
962
	}
963
	return;
2 7u83 964
}
965
 
966
 
967
/*
968
    MOVE FROM A FLOATING-POINT REGISTER
969
 
970
    The value in the floating-point register from (of size sz) is moved
971
    into to.
972
*/
973
 
6 7u83 974
static void
975
move_from_freg(long sz, where from, where to)
2 7u83 976
{
6 7u83 977
	int instr = insf(sz, ml_fmove);
978
	switch (whereis(to)) {
979
	case Dreg:
980
		ins2(m_fmoves, sz, sz, from, to, 1);
981
		have_cond = 0;
982
		return;
983
	case Freg:
984
		ins2(m_fmovex, sz, sz, from, to, 1);
985
		have_cond = 0;
986
		return;
987
	case RegPair: {
988
		exp te = to.wh_exp;
989
		if (sz != 64) {
990
			error("Wrong floating variety");
991
		}
992
		push_float(sz, from);
993
		pop(slongsh, L32, zw(son(te)));
994
		pop(slongsh, L32, zw(bro(te)));
995
		have_cond = 0;
996
		return;
2 7u83 997
	}
6 7u83 998
	default:
999
		ins2(instr, sz, sz, from, to, 1);
1000
		have_cond = 0;
1001
		return;
2 7u83 1002
	}
1003
}
1004
 
1005
 
1006
/*
1007
    MOVE TO A FLOATING-POINT REGISTER
1008
 
1009
    The value in from (of size sz) is moved into the floating-point
1010
    register to.
1011
*/
1012
 
6 7u83 1013
static void
1014
move_to_freg(long sz, where from, where to)
2 7u83 1015
{
6 7u83 1016
	int instr = insf(sz, ml_fmove);
1017
	switch (whereis(from)) {
1018
	case Dreg:
1019
		ins2(m_fmoves, sz, sz, from, to, 1);
1020
		have_cond = 0;
1021
		return;
1022
	case Areg:
1023
		move(slongsh, from, D0);
1024
		ins2(m_fmoves, sz, sz, D0, to, 1);
1025
		have_cond = 0;
1026
		return;
1027
	case Freg:
1028
		ins2(m_fmovex, sz, sz, from, to, 1);
1029
		have_cond = 0;
1030
		return;
1031
	case RegPair: {
1032
		exp fe = from.wh_exp;
1033
		if (sz != 64) {
1034
			error("Wrong floating variety");
1035
		}
1036
		push(slongsh, L32, zw(bro(fe)));
1037
		push(slongsh, L32, zw(son(fe)));
1038
		pop_float(sz, to);
1039
		have_cond = 0;
1040
		return;
2 7u83 1041
	}
6 7u83 1042
	default:
1043
		ins2(instr, sz, sz, from, to, 1);
1044
		have_cond = 0;
1045
		return;
2 7u83 1046
	}
1047
}
1048
 
1049
 
1050
/*
1051
    TEST AN EXTERNAL FOR SIMPLE CONTENTS/ASSIGN
1052
 
1053
    The expression e of external storage type is checked for simple
1054
    operand type.
1055
*/
1056
 
6 7u83 1057
static bool
1058
ca_extern(exp e)
2 7u83 1059
{
6 7u83 1060
	char n = name(e);
1061
	if (n != cont_tag && n != ass_tag) {
1062
		return (0);
1063
	}
1064
	return (name(son(e)) == name_tag ? 1 : 0);
2 7u83 1065
}
1066
 
1067
 
1068
/*
1069
    MOVE LARGE OBJECTS
1070
 
1071
    sz bits are copied from from to to.  down can be 0 (start at the
1072
    top), 1 (start at the bottom) or 2 (don't care).
1073
*/
1074
 
6 7u83 1075
void
1076
move_bytes(long sz, where from, where to, int down)
2 7u83 1077
{
6 7u83 1078
	long off;
1079
	int instr;
2 7u83 1080
 
6 7u83 1081
	exp fe = from.wh_exp;
1082
	exp te = to.wh_exp;
1083
	long fof = from.wh_off;
1084
	long tof = to.wh_off;
2 7u83 1085
 
6 7u83 1086
	long whfrom = whereis(from);
1087
	long whto = whereis(to);
2 7u83 1088
 
6 7u83 1089
	/* Set up move types */
1090
	int r1 = REG_A0;
1091
	int r2 = REG_A1;
1092
	int s1 = 0;
1093
	int s2 = 0;
2 7u83 1094
 
6 7u83 1095
	if (whfrom == External && ca_extern(fe)) {
1096
		s1 = 3;
1097
	}
1098
	if (name(te) == apply_tag || name(te) == apply_general_tag ||
1099
	    name(te) == tail_call_tag) {
1100
		s2 = 1;
1101
	}
1102
	if (whto == External && ca_extern(te)) {
1103
		s2 = 3;
1104
	}
2 7u83 1105
 
6 7u83 1106
	if (whfrom == Variable || whfrom == Parameter || whfrom == RegInd) {
1107
		s1 = 3;
1108
	}
1109
	if (whto == Variable || whto == Parameter || whto == RegInd) {
1110
		s2 = 3;
1111
	}
1112
	if (whfrom == RegPair) {
1113
		s1 = 4;
1114
	}
1115
	if (whto == RegPair) {
1116
		s2 = 4;
1117
	}
2 7u83 1118
 
6 7u83 1119
	if (sz > 12 * 32 && s2 != 1 && down != 1) {
1120
		mach_op *op1, *op2;
1121
		long lab = next_lab();
1122
		long longs = (sz / 32);
1123
		sz -= 32 * longs;
1124
		r1 = REG_A0;
1125
		r2 = REG_A1;
1126
		s1 = 0;
1127
		s2 = 0;
1128
		tmp_mova(from, r1, 0);
1129
		tmp_mova(to, r2, 0);
1130
		move(slongsh, mnw(longs - 1), D0);
1131
		make_label(lab);
1132
		op1 = make_postinc(r1);
1133
		op2 = make_postinc(r2);
1134
		make_instr(m_movl, op1, op2, regmsk(r1) | regmsk(r2));
1135
		op1 = make_register(REG_D0);
1136
		op2 = make_lab_data(lab, 0);
1137
		make_instr(m_dbf, op1, op2, regmsk(REG_D0));
2 7u83 1138
	} else {
6 7u83 1139
		if (s1 == 0) {
1140
			int r = tmp_mova(from, r1, 1);
1141
			if (r != r1) {
1142
				if (s2 == 0) {
1143
					r2 = tmp_mova(to, r1, 1);
1144
				}
1145
				r1 = r;
1146
			} else {
1147
				if (s2 == 0) {
1148
					r2 = tmp_mova(to, r2, 1);
1149
				}
1150
			}
1151
		} else {
1152
			if (s2 == 0) {
1153
				r2 = tmp_mova(to, REG_A1, 1);
1154
			}
1155
		}
2 7u83 1156
	}
1157
 
6 7u83 1158
	off = 0;
1159
	while (sz) {
1160
		mach_op *op1, *op2;
1161
		long b = ((sz >= 32)? 32 :((sz >= 16)? 16 : 8));
1162
		sz -= b;
1163
		if (down != 0) {
1164
			off = sz;
1165
		}
1166
		instr = ins(b, ml_mov);
1167
		switch (s1) {
1168
		case 0:
1169
			op1 = make_indirect(r1, off / 8);
1170
			break;
1171
		case 2:
1172
			op1 = make_lab_ind(r1, off / 8);
1173
			break;
1174
		case 3:
1175
			op1 = operand(L32, mw(fe, fof + off));
1176
			break;
1177
		case 4:
1178
			op1 = operand(L32, zw(sz ? bro(fe) : son(fe)));
1179
			break;
1180
		}
1181
		switch (s2) {
1182
		case 0:
1183
			op2 = make_indirect(r2, off / 8);
1184
			break;
1185
		case 1:
1186
			op2 = make_dec_sp();
1187
			break;
1188
		case 3:
1189
			op2 = operand(L32, mw(te, tof + off));
1190
			break;
1191
		case 4: {
1192
			op2 = operand(L32, zw(sz ? bro(te) : son(te)));
1193
			break;
1194
		}
1195
		}
1196
		make_instr(instr, op1, op2, 0);
1197
		if (s2 == 1) {
1198
			stack_size -= b;
1199
		}
1200
		off += b;
2 7u83 1201
	}
6 7u83 1202
	have_cond = 0;
1203
	return;
2 7u83 1204
}
1205
 
1206
 
1207
/*
1208
    MAIN MOVE ROUTINE
1209
 
1210
    A value of shape sha is moved from from into to.  There are several
1211
    main subcases : floating-point values, values of sizes 8, 16 and 32,
1212
    and all other cases.
1213
*/
1214
 
6 7u83 1215
void
1216
move(shape sha, where from, where to)
2 7u83 1217
{
6 7u83 1218
	int instr;
1219
	long sz = shape_size(sha);
1220
	long rt = shtype(sha);
1221
	where from1, from2;
2 7u83 1222
 
6 7u83 1223
	exp fe = from.wh_exp;
1224
	exp te = to.wh_exp;
1225
	long fof = from.wh_off;
1226
	long tof = to.wh_off;
2 7u83 1227
 
6 7u83 1228
	long whfrom = whereis(from);
1229
	long whto = whereis(to);
2 7u83 1230
 
6 7u83 1231
	if (sz == 0 || eq_where(from, to) || eq_where(to,zero)) {
1232
		return;
1233
	}
1234
	sz = round(sz, shape_align(sha));
2 7u83 1235
 
6 7u83 1236
	if (name(sha) == bitfhd && sz != 8 && sz != 16) {
1237
		sz = 32;
1238
	}
2 7u83 1239
 
6 7u83 1240
	if (rt == Freg || whfrom == Freg || whto == Freg) {
1241
		if (name(fe) == real_tag) {
1242
			whfrom = Value;
2 7u83 1243
		}
6 7u83 1244
		if (name(te) == apply_tag || name(te) == apply_general_tag ||
1245
		    name(te) == tail_call_tag) {
1246
			switch (whfrom) {
1247
			case Dreg:
1248
			case Areg:
1249
				from1 = from;
1250
				break;
1251
			case Freg:
1252
				push_float(sz, from);
1253
				return;
1254
			case Value: {
1255
				long *p = realrep(fe);
1256
				if (p) {
1257
					from1 = mnw(p[0]);
1258
					if (sz > 32) {
1259
						from2 = mnw(p[1]);
1260
					}
1261
				} else {
1262
					long lb = next_lab();
1263
					exp t = simple_exp(internal_tag);
1264
					make_constant(lb, fe);
1265
					no(t) = lb;
1266
					from1 = mw(t, fof);
1267
					from2 = mw(t, fof + 32);
1268
				}
1269
				break;
1270
			}
1271
			case RegPair:
1272
				from1 = zw(son(fe));
1273
				from2 = zw(bro(fe));
1274
				break;
1275
			case Variable:
1276
				from1 = mw(fe, fof);
1277
				if (sz > 32) {
1278
					from2 = mw(fe, fof + 32);
1279
				}
1280
				break;
1281
			case External:
1282
				if (ca_extern(fe)) {
1283
					from1 = mw(fe, fof);
1284
					if (sz > 32)from2 = mw(fe, fof + 32);
1285
				} else {
1286
					tmp_mova(from, REG_A0, 0);
1287
					from1 = A0_p;
1288
					if (sz > 32)from2 = mw(A0_p.wh_exp, 32);
1289
				}
1290
				break;
1291
			default:
1292
				tmp_mova(from, REG_A0, 0);
1293
				from1 = A0_p;
1294
				if (sz > 32) {
1295
					from2 = mw(A0_p.wh_exp, 32);
1296
				}
1297
				break;
1298
			}
1299
			if (sz > 32) {
1300
				move(slongsh, from2, to);
1301
			}
1302
			move(slongsh, from1, to);
1303
			have_cond = 0;
1304
			return;
2 7u83 1305
		}
6 7u83 1306
		if (whfrom == Freg) {
1307
			move_from_freg(sz, from, to);
1308
			return;
2 7u83 1309
		}
6 7u83 1310
		if (whto == Freg) {
1311
			move_to_freg(sz, from, to);
1312
			return;
2 7u83 1313
		}
6 7u83 1314
		if (whfrom == Value) {
1315
			if (sz == 32) {
1316
				long *p = realrep(fe);
1317
				if (p) {
1318
					from1 = mnw(p[0]);
1319
					ins2(m_movl, L32, L32, from1, to, 1);
1320
				} else {
1321
					ins2(m_movl, L32, L32, from, to, 1);
1322
				}
1323
				have_cond = 0;
1324
				return;
1325
			} else {
1326
				long *p = realrep(fe);
1327
				if (p) {
1328
					from1 = mnw(p[0]);
1329
					from2 = mnw(p[1]);
1330
				} else {
1331
					long lb = next_lab();
1332
					exp t = simple_exp(internal_tag);
1333
					make_constant(lb, fe);
1334
					no(t) = lb;
1335
					from1 = mw(t, fof);
1336
					from2 = mw(t, fof + 32);
1337
				}
1338
				if (whto == RegPair) {
1339
					ins2(m_movl, L32, L32, from1,
1340
					     zw(son(te)), 1);
1341
					ins2(m_movl, L32, L32, from2,
1342
					     zw(bro(te)), 1);
1343
					have_cond = 0;
1344
					return;
1345
				}
1346
				ins2(m_movl, L32, L32, from2, mw(te, tof + 32),
1347
				     1);
1348
				ins2(m_movl, L32, L32, from1, to, 1);
1349
				have_cond = 0;
1350
				return;
1351
			}
2 7u83 1352
		}
6 7u83 1353
		if (whfrom == RegPair) {
1354
			if (sz != 64) {
1355
				error("Wrong floating variety");
1356
			}
1357
			ins2(m_movl, L32, L32, zw(bro(fe)),
1358
			     mw(te, tof + 32), 1);
1359
			ins2(m_movl, L32, L32, zw(son(fe)), to, 1);
1360
			have_cond = 0;
1361
			return;
2 7u83 1362
		}
6 7u83 1363
		if (whto == RegPair) {
1364
			if (sz != 64) {
1365
				error("Wrong floating variety");
1366
			}
1367
			ins2(m_movl, L32, L32, from, zw(son(te)), 1);
1368
			ins2(m_movl, L32, L32, mw(fe, fof + 32),
1369
			     zw(bro(te)), 1);
1370
			have_cond = 0;
1371
			return;
2 7u83 1372
		}
6 7u83 1373
		/* Fall through otherwise */
2 7u83 1374
	}
6 7u83 1375
 
1376
	/* Move things of size 8, 16 or 32 */
1377
	if (sz <= 32 && sz != 24) {
1378
		if (name(te) == apply_tag || name(te) == apply_general_tag ||
1379
		    name(te) == tail_call_tag) {
1380
			if (whfrom == Value) {
1381
				mach_op *op1, *op2;
1382
				long v = nw(from);
1383
				if (is_offset(from.wh_exp)) {
1384
					v /= 8;
1385
				}
1386
				if (v == 0 && stack_change == 0) {
1387
					op1 = make_dec_sp();
1388
					make_instr(m_clrl, op1, null, 0);
1389
					have_cond = 0;
1390
					stack_size -= 32;
1391
					return;
1392
				}
1393
				if (v >= -128 && v <= 127) {
1394
					long s = stack_change;
1395
					stack_change = 0;
1396
					op1 = make_value(v);
1397
					op2 = make_register(REG_D0);
1398
					make_instr(m_moveq, op1, op2,
1399
						   regmsk(REG_D0));
1400
					stack_change = s;
1401
					push(sha, L32, D0);
1402
					return;
1403
				}
1404
				if (stack_change) {
1405
					push(sha, L32, from);
1406
					return;
1407
				}
1408
				op1 = make_int_data(v);
1409
				make_instr(m_pea, op1, null, 0);
1410
				have_cond = 0;
1411
				stack_size -= 32;
1412
				return;
1413
			}
1414
			push(sha, sz, from);
1415
			return;
2 7u83 1416
		}
6 7u83 1417
 
1418
		if (name(fe) == null_tag) {
1419
			move_const(sha, sz, L0, to);
1420
			return;
2 7u83 1421
		}
6 7u83 1422
 
1423
		if (whfrom == Value) {
1424
			long v = nw(from);
1425
			if (is_offset(from.wh_exp)) {
1426
				v /= 8;
1427
			}
1428
			move_const(sha, sz, v, to);
1429
			return;
2 7u83 1430
		}
1431
 
6 7u83 1432
		if (sz == 8) {
1433
			if (whfrom == Areg) {
1434
				move(slongsh, from, D0);
1435
				move(sha, D0, to);
1436
				return;
1437
			}
1438
			if (whto == Areg) {
1439
				move(sha, from, D0);
1440
				move(slongsh, D0, to);
1441
				return;
1442
			}
1443
		}
2 7u83 1444
 
6 7u83 1445
		if (whfrom == Other && whto == Other) {
1446
			move(sha, from, D0);
1447
			move(sha, D0, to);
1448
			return;
2 7u83 1449
		}
6 7u83 1450
# if 0
1451
		if ((name(sha) == prokhd) && (whfrom == External) &&
1452
		    (whto == Dreg)) {
1453
			/* We need the contents of this address */
1454
			move(sha,from,A0);
1455
			move(sha,A0_p,D0);
1456
			move(sha,D0,to);
1457
			return;
2 7u83 1458
		}
6 7u83 1459
#endif
1460
		instr = ins(sz, ml_mov);
1461
		ins2(instr, sz, sz, from, to, 1);
1462
		if (whto == Areg) {
1463
			have_cond = 0;
1464
		} else {
1465
			set_cond(to, sz);
1466
			if (whfrom == Dreg || whfrom == Areg) {
1467
				set_cond_alt(from);
1468
			}
2 7u83 1469
		}
6 7u83 1470
		return;
2 7u83 1471
	}
1472
 
6 7u83 1473
	if (name(fe) == null_tag) {
1474
		move_const(sha, sz, L0, to);
1475
		return;
2 7u83 1476
	}
1477
 
6 7u83 1478
	/* Other cases are dealt with by move_bytes */
1479
	move_bytes(sz, from, to, 2);
1480
	return;
2 7u83 1481
}
1482
 
1483
 
1484
/*
1485
    MOVE ADDRESS ROUTINE
1486
 
1487
    The effective address of from is loaded into to.
1488
*/
1489
 
6 7u83 1490
void
1491
mova(where from, where to)
2 7u83 1492
{
6 7u83 1493
	int r;
1494
	exp fe = from.wh_exp;
1495
	char nf = name(fe);
1496
	char nt = name(to.wh_exp);
2 7u83 1497
 
6 7u83 1498
	if (nf == reff_tag) {
1499
		exp s = son(from.wh_exp);
1500
		mova(mw(s, nw(from)), to);
1501
		return;
1502
	}
2 7u83 1503
 
6 7u83 1504
	if (nt == apply_tag || nt == apply_general_tag ||
1505
	    nt == tail_call_tag) {
1506
		exp s = son(from.wh_exp);
1507
		if (nf == cont_tag) {
1508
			ins1(m_pea, L32, zw(s), 0);
1509
		} else {
1510
			ins1(m_pea, L32, from, 0);
1511
		}
1512
		stack_size -= 32;
1513
		have_cond = 0;
1514
		return;
2 7u83 1515
	}
1516
 
6 7u83 1517
	switch (nf) {
1518
	case val_tag:
1519
		move(slongsh, from, to);
1520
		return;
1521
	case cont_tag:
1522
	case ass_tag: {
1523
		exp s = son(from.wh_exp);
1524
		if (from.wh_off == 0 && name(s) == name_tag) {
1525
			exp ss = son(s);
1526
			if (!isvar(ss) && !isglob(ss)) {
1527
				move(slongsh, zw(s), to);
1528
				return;
1529
			}
1530
		}
1531
		break;
2 7u83 1532
	}
6 7u83 1533
	}
2 7u83 1534
 
6 7u83 1535
	if (whereis(to) == Areg) {
1536
		/*
1537
		   if (nf == name_tag && isvar (son (fe))) {
1538
		   	move (slongsh, from, to);
1539
		   	return;
1540
		   }
1541
		 */
1542
		if (nf == name_tag && !isvar(son(fe)) &&
1543
		    ptno(son(fe)) == reg_pl) {
1544
			add(slongsh, mw(fe, 0), mw(zeroe, from.wh_off / 8),
1545
			    to);
1546
		} else {
1547
			ins2(m_lea, L32, L32, from, to, 1);
1548
			have_cond = 0;
2 7u83 1549
		}
6 7u83 1550
		return;
2 7u83 1551
	}
1552
 
1553
 
6 7u83 1554
	r = next_tmp_reg();
1555
	regsinproc |= regmsk(r);
1556
	ins2(m_lea, L32, L32, from, register(r), 1);
1557
	have_cond = 0;
1558
	tmp_reg_status = 1;
1559
	move(slongsh, register(r), to);
1560
	return;
2 7u83 1561
}
1562
 
1563
 
1564
 
6 7u83 1565
long
1566
range_max(shape shp)
2 7u83 1567
{
6 7u83 1568
	switch (name(shp)) {
1569
	case scharhd:
1570
		return 0x7f;
1571
	case swordhd:
1572
		return 0x7fff;
1573
	case slonghd:
1574
		return 0x7fffffff;
1575
	case ucharhd:
1576
		return 0xff;
1577
	case uwordhd:
1578
		return 0xffff;
1579
	case ulonghd:
1580
		return 0xffffffff;
1581
	default:
1582
		fprintf(stderr, "Illegal shape in comparison");
1583
	}
1584
	return 0;
2 7u83 1585
}
1586
 
6 7u83 1587
long
1588
range_min(shape shp)
2 7u83 1589
{
6 7u83 1590
	switch (name(shp)) {
1591
	case scharhd:
1592
		return -0x80;
1593
	case swordhd:
1594
		return -0x8000;
1595
	case slonghd:
1596
		return -0x80000000;
1597
	case ucharhd:
1598
	case uwordhd:
1599
	case ulonghd:
1600
		return 0;
1601
	default:
1602
		fprintf(stderr, "Illegal shape in comparison");
1603
	}
1604
	return 0;
2 7u83 1605
}
1606
 
1607
 
1608
/*
1609
    AUXILIARY CHANGE VARIETY ROUTINE
1610
 
1611
    The value from of shape shf is converted to a value of shape sht and
1612
    moved into to.
1613
*/
1614
 
6 7u83 1615
void
1616
change_var_sh(shape sht, shape shf, where from, where to)
2 7u83 1617
{
6 7u83 1618
	int instr;
2 7u83 1619
 
6 7u83 1620
	long szf = shape_size(shf);
1621
	long szt = shape_size(sht);
1622
	bool sgf = is_signed(shf);
1623
	bool sgt = is_signed(sht);
2 7u83 1624
 
6 7u83 1625
	long whf = whereis(from);
1626
	long wht = whereis(to);
2 7u83 1627
 
6 7u83 1628
	if (have_overflow()) {
1629
		if (whf == Value) {
1630
			if (((nw(from) < 0) && !is_signed(sht)) ||
1631
			    ((nw(from)) < 0 &&
1632
			     (is_signed(sht) && name(shf) ==ulonghd))) {
1633
				test_overflow(UNCONDITIONAL);
1634
			}
1635
			if (is_signed(sht)) {
1636
				if ((nw(from) < range_min(sht)) ||
1637
				    (nw(from) > range_max(sht))) {
1638
					test_overflow(UNCONDITIONAL);
1639
				}
1640
			} else {
1641
				if ((nw(from) < (unsigned)range_min(sht)) ||
1642
				    (nw(from) > (unsigned)range_max(sht))) {
1643
					test_overflow(UNCONDITIONAL);
1644
				}
1645
			}
1646
		}
2 7u83 1647
	}
6 7u83 1648
 
1649
	if (whf == Value) {
1650
		long v = dochvar(nw(from), sht);
1651
		move(sht, mnw(v), to);
1652
		return;
2 7u83 1653
	}
1654
 
6 7u83 1655
	if (name(sht) == bitfhd) {
1656
		sgt = is_signed(sht);
1657
		switch (szt) {
1658
		case 8:
1659
			sht = (sgt ? scharsh : ucharsh);
1660
			break;
1661
		case 16:
1662
			sht = (sgt ? swordsh : uwordsh);
1663
			break;
1664
		default:
1665
			szt = L32;
1666
			sht = (sgt ? slongsh : ulongsh);
1667
			break;
1668
		}
2 7u83 1669
	}
1670
 
6 7u83 1671
	if (name(shf) == bitfhd) {
1672
		sgf = is_signed(shf);
1673
		switch (szf) {
1674
		case 8:
1675
			shf = (sgf ? scharsh : ucharsh);
1676
			break;
1677
		case 16:
1678
			shf = (sgf ? swordsh : uwordsh);
1679
			break;
1680
		default:
1681
			szf = L32;
1682
			shf = (sgf ? slongsh : ulongsh);
1683
			break;
1684
		}
2 7u83 1685
	}
1686
 
6 7u83 1687
	if (have_overflow()) {
1688
		bool sw;
1689
		int br_ins;
2 7u83 1690
 
6 7u83 1691
		/*move(shf,from,D0);*/
2 7u83 1692
 
6 7u83 1693
		if (is_signed(shf) && !is_signed(sht)) {
1694
			/* if signed -> unsigned, test lt 0.  */
2 7u83 1695
 
6 7u83 1696
			exp zero_exp = getexp(shf, nilexp, 0, nilexp, nilexp,
1697
					      0, 0, val_tag);
1698
			sw = cmp(shf, from, zw(zero_exp), tst_ls);
1699
			br_ins = branch_ins(tst_ls, sw, 1,
1700
					    is_floating(name(shf)));
1701
			test_overflow2(br_ins);
1702
			kill_exp(zero_exp, zero_exp);
1703
		}
2 7u83 1704
 
6 7u83 1705
		if (is_signed(sht) && (name(shf) == ulonghd)) {
1706
			/*
1707
			 * Treat the unsigned value as signed and check .lt.
1708
			 * zero.
1709
			 */
1710
			int br_ins;
1711
			exp zero_exp = getexp(slongsh, nilexp, 0, nilexp,
1712
					      nilexp, 0, 0, val_tag);
1713
			sw = cmp(slongsh, from, zw(zero_exp), tst_ls);
1714
			br_ins = branch_ins(tst_ls, sw, 1,
1715
					    is_floating(name(shf)));
1716
			test_overflow2(br_ins);
1717
			kill_exp(zero_exp, zero_exp);
1718
		}
2 7u83 1719
 
6 7u83 1720
		if(name(sht) <= name(shf)) {
1721
			/* shortening variety */
1722
			exp max_val = getexp(sht, nilexp, 0, nilexp, nilexp, 0,
1723
					     range_max(sht), val_tag);
1724
			exp min_val = getexp(sht, nilexp, 0, nilexp, nilexp, 0,
1725
					     range_min(sht), val_tag);
2 7u83 1726
 
6 7u83 1727
			int br_ins;
2 7u83 1728
 
6 7u83 1729
			if (whf != Dreg) {
1730
				move(shf, from, D0);
1731
				from = D0;
1732
				whf = Dreg;
1733
			}
2 7u83 1734
 
6 7u83 1735
			/*
1736
			 * If value is a char or word we must sign-extend it,
1737
			 * as the checks are done using long arithmetic.
1738
			 */
1739
			if (is_signed(shf) && (szf < 32)) {
1740
				ins1((szf == 16) ? m_extl : m_extbl, 32, from,
1741
				     1);
1742
			}
2 7u83 1743
 
6 7u83 1744
			sw = cmp(is_signed(sht) ?slongsh : ulongsh, from,
1745
				 zw(max_val), tst_gr);
1746
			br_ins = branch_ins(tst_gr, sw, is_signed(sht),
1747
					    is_floating(name(sht)));
1748
			test_overflow2(br_ins);
1749
			sw = cmp(is_signed(sht) ? slongsh : ulongsh, from,
1750
				 zw(min_val), tst_ls);
1751
			br_ins = branch_ins(tst_ls, sw, is_signed(sht),
1752
					    is_floating(name(sht)));
1753
			test_overflow2(br_ins);
2 7u83 1754
 
6 7u83 1755
			kill_exp(max_val, max_val);
1756
			kill_exp(min_val, min_val);
1757
		}
2 7u83 1758
	}
1759
 
6 7u83 1760
	if (szt <= szf) {
1761
		if (whf == Parameter) {
1762
			where adj;
1763
			adj = mw(from.wh_exp, from.wh_off + szf - szt);
1764
			move(sht, adj, to);
1765
			return;
1766
		}
1767
		if (szt == szf || whf == Dreg) {
1768
			move(sht, from, to);
1769
			return;
1770
		}
1771
		if (wht == Dreg) {
1772
			move(shf, from, to);
1773
			return;
1774
		}
1775
		move(shf, from, D0);
1776
		move(sht, D0, to);
1777
		return;
2 7u83 1778
	}
1779
 
6 7u83 1780
	if (sgf && sgt && szf == 16 && szt == 32) {
1781
		/*
1782
		 * The instruction "mov.w <ea>, %an" automatically sign
1783
		 * extends.
1784
		 */
1785
		if (wht == Areg) {
1786
			move(shf, from, to);
1787
			return;
1788
		}
1789
		if (wht != Dreg) {
1790
			int r = next_tmp_reg();
1791
			move(shf, from, register(r));
1792
			tmp_reg_status = 1;
1793
			move(sht, register(r), to);
1794
			regsinproc |= regmsk(r);
1795
			return;
1796
		}
2 7u83 1797
	}
1798
 
6 7u83 1799
	if (sgf) {
1800
		bool d;
1801
		where dest;
1802
		if (wht == Dreg) {
1803
			dest = to;
1804
			move(shf, from, dest);
1805
			d = 0;
1806
		} else {
1807
			if (whf == Dreg) {
1808
				/* Extension is non-intrusive */
1809
				dest = from;
1810
			} else {
1811
				dest = D0;
1812
				move(shf, from, dest);
1813
			}
1814
			d = 1;
1815
		}
1816
		if (szf == 8) {
1817
			instr = (szt == 16 ? m_extw : m_extbl);
1818
		} else {
1819
			instr = m_extl;
1820
		}
1821
		ins1(instr, szt, dest, 1);
1822
		set_cond(dest, szt);
1823
		if (d) {
1824
			move(sht, dest, to);
1825
		}
2 7u83 1826
	} else {
6 7u83 1827
		if (wht == Dreg) {
1828
			if (eq_where(to, from)) {
1829
				long v = (szf == 8 ? 0xff : 0xffff);
1830
				if (!eq_where(to, D0)) {
1831
					and(slongsh, mnw(v), to, to);
1832
				}
1833
				return;
1834
			}
1835
		}
1836
		move(slongsh, zero, D0);
1837
		move(shf, from, D0);
1838
		move(sht, D0, to);
1839
		return;
2 7u83 1840
	}
6 7u83 1841
	return;
2 7u83 1842
}
1843
 
1844
 
1845
/*
1846
    MAIN CHANGE VARIETY ROUTINE
1847
 
1848
    The value from is converted to a value of shape sha and moved into to.
1849
*/
1850
 
6 7u83 1851
void
1852
change_var(shape sha, where from, where to)
2 7u83 1853
{
6 7u83 1854
	shape shf = sh(from.wh_exp);
1855
	change_var_sh(sha, shf, from, to);
1856
	return;
2 7u83 1857
}
1858
 
1859
/*
1860
    FIND APPROPRIATE BRANCH INSTRUCTION TYPE
1861
 
1862
    This routine returns the appropriate branch instruction for test number
1863
    test_no, which should be switched if sw is 0.  sf indicates whether
1864
    a floating-point instruction should be used.  If not, sg indicates
1865
    whether a signed or unsigned instruction should be used.
1866
*/
1867
 
6 7u83 1868
int
1869
branch_ins(long test_no, int sw, int sg, int sf)
2 7u83 1870
{
6 7u83 1871
	int r = test_no;
1872
	if (!sw) {
1873
		switch (r) {
1874
		case tst_le:
1875
			r = tst_ge;
1876
			break;
1877
		case tst_ls:
1878
			r = tst_gr;
1879
			break;
1880
		case tst_ge:
1881
			r = tst_le;
1882
			break;
1883
		case tst_gr:
1884
			r = tst_ls;
1885
			break;
1886
		case tst_ngr:
1887
			r = tst_nls;
1888
			break;
1889
		case tst_nge:
1890
			r = tst_nle;
1891
			break;
1892
		case tst_nls:
1893
			r = tst_ngr;
1894
			break;
1895
		case tst_nle:
1896
			r = tst_nge;
1897
			break;
1898
		}
2 7u83 1899
	}
6 7u83 1900
	switch (r) {
1901
	case tst_eq:
1902
		/* Equal */
1903
		return (sf ? m_fbeq : m_beq);
1904
	case tst_neq:
1905
		/* Not equal */
1906
		return (sf ? m_fbne : m_bne);
1907
	case tst_le:
1908
		/* Less than or equals */
1909
		if (sf) {
1910
			return (m_fble);
1911
		}
1912
		return (sg ? m_ble : m_bls);
1913
	case tst_ls:
1914
		/* Less than */
1915
		if (sf) {
1916
			return (m_fblt);
1917
		}
1918
		return (sg ? m_blt : m_bcs);
1919
	case tst_ge:
1920
		/* Greater than or equals */
1921
		if (sf) {
1922
			return (m_fbge);
1923
		}
1924
		return (sg ? m_bge : m_bcc);
1925
	case tst_gr:
1926
		/* Greater than */
1927
		if (sf) {
1928
			return (m_fbgt);
1929
		}
1930
		return (sg ? m_bgt : m_bhi);
1931
	case tst_ngr:
1932
		/* Not greater than */
1933
		if (sf) {
1934
			return (m_fbngt);
1935
		}
1936
		return (sg ? m_ble : m_bls);
1937
	case tst_nge:
1938
		/* Not greater than or equals */
1939
		if (sf) {
1940
			return (m_fbnge);
1941
		}
1942
		return (sg ? m_blt : m_bcs);
1943
	case tst_nls:
1944
		/* Not less than */
1945
		if (sf) {
1946
			return (m_fbnlt);
1947
		}
1948
		return (sg ? m_bge : m_bcc);
1949
	case tst_nle:
1950
		/* Not less than or equals */
1951
		if (sf) {
1952
			return (m_fbnle);
1953
		}
1954
		return (sg ? m_bgt : m_bhi);
2 7u83 1955
	}
6 7u83 1956
	error("Illegal test");
1957
	return (m_dont_know);
2 7u83 1958
}
1959
 
1960
 
1961
/*
1962
    OUTPUT CONDITIONAL JUMP
1963
 
1964
    A jump to the label indicated by jr is output.  test_no, sw, sg and sf
1965
    have the same meanings as in branch_ins.
1966
*/
1967
 
6 7u83 1968
void
1969
branch(long test_no, exp jr, int sg, int sw, int sf)
2 7u83 1970
{
6 7u83 1971
	make_jump(branch_ins(test_no, sw, sg, sf), ptno(jr));
1972
	return;
2 7u83 1973
}