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