Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – tendra.SVN – Blame – /branches/tendra4/src/installers/680x0/common/codex.c – Rev 2

Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
2
    		 Crown Copyright (c) 1997
3
 
4
    This TenDRA(r) Computer Program is subject to Copyright
5
    owned by the United Kingdom Secretary of State for Defence
6
    acting through the Defence Evaluation and Research Agency
7
    (DERA).  It is made available to Recipients with a
8
    royalty-free licence for its use, reproduction, transfer
9
    to other parties and amendment for any purpose not excluding
10
    product development provided that any such use et cetera
11
    shall be deemed to be acceptance of the following conditions:-
12
 
13
        (1) Its Recipients shall ensure that this Notice is
14
        reproduced upon any copies or amended versions of it;
15
 
16
        (2) Any amended version of it shall be clearly marked to
17
        show both the nature of and the organisation responsible
18
        for the relevant amendment or amendments;
19
 
20
        (3) Its onward transfer from a recipient to another
21
        party shall be deemed to be that party's acceptance of
22
        these conditions;
23
 
24
        (4) DERA gives no warranty or assurance as to its
25
        quality or suitability for any purpose and DERA accepts
26
        no liability whatsoever in relation to any use to which
27
        it may be put.
28
*/
29
/*
30
			    VERSION INFORMATION
31
			    ===================
32
 
33
--------------------------------------------------------------------------
34
$Header: /u/g/release/CVSROOT/Source/src/installers/680x0/common/codex.c,v 1.1.1.1 1998/01/17 15:55:49 release Exp $
35
--------------------------------------------------------------------------
36
$Log: codex.c,v $
37
 * Revision 1.1.1.1  1998/01/17  15:55:49  release
38
 * First version to be checked into rolling release.
39
 *
40
Revision 1.2  1997/10/29 10:22:08  ma
41
Replaced use_alloca with has_alloca.
42
 
43
Revision 1.1.1.1  1997/10/13 12:42:49  ma
44
First version.
45
 
46
Revision 1.6  1997/10/13 08:49:04  ma
47
Made all pl_tests for general proc & exception handling pass.
48
 
49
Revision 1.5  1997/09/25 06:44:55  ma
50
All general_proc tests passed
51
 
52
Revision 1.4  1997/06/18 12:04:50  ma
53
Merged with Input Baseline changes.
54
 
55
Revision 1.3  1997/06/18 10:09:26  ma
56
Checking in before merging with Input Baseline changes.
57
 
58
Revision 1.2  1997/04/20 11:30:21  ma
59
Introduced gcproc.c & general_proc.[ch].
60
Added cases for apply_general_proc next to apply_proc in all files.
61
 
62
Revision 1.1.1.1  1997/03/14 07:50:11  ma
63
Imported from DRA
64
 
65
 * Revision 1.1.1.1  1996/09/20  10:56:53  john
66
 *
67
 * Revision 1.2  1996/07/05  14:18:40  john
68
 * Changes for spec 3.1
69
 *
70
 * Revision 1.1.1.1  1996/03/26  15:45:09  john
71
 *
72
 * Revision 1.3  94/02/21  15:56:50  15:56:50  ra (Robert Andrews)
73
 * A couple of flags which used to be bool are now int.
74
 *
75
 * Revision 1.2  93/05/24  15:54:51  15:54:51  ra (Robert Andrews)
76
 * Don't recognise alloca by its tag name, but by its token name.
77
 *
78
 * Revision 1.1  93/02/22  17:15:25  17:15:25  ra (Robert Andrews)
79
 * Initial revision
80
 *
81
--------------------------------------------------------------------------
82
*/
83
 
84
 
85
#include "config.h"
86
#include "common_types.h"
87
#include "assembler.h"
88
#include "basicread.h"
89
#include "check.h"
90
#include "expmacs.h"
91
#include "exptypes.h"
92
#include "exp.h"
93
#include "flags.h"
94
#include "instrs.h"
95
#include "installglob.h"
96
#include "shapemacs.h"
97
#include "flpt.h"
98
#include "evaluate.h"
99
#include "externs.h"
100
#include "install_fns.h"
101
#include "mach.h"
102
#include "mach_ins.h"
103
#include "mach_op.h"
104
#include "peephole.h"
105
#include "codex.h"
106
#include "output.h"
107
#include "tags.h"
108
#include "tests.h"
109
#include "utility.h"
110
#include "where.h"
111
#include "coder.h"
112
#include "operations.h"
113
#include "ops_shared.h"
114
#include "translate.h"
115
#include "codec.h"
116
#include "install_fns.h"
117
#if have_diagnostics
118
#include "xdb_basics.h"
119
#include "xdb_types.h"
120
#include "xdb_output.h"
121
#endif
122
#ifndef tdf3
123
#include "general_proc.h"
124
#include "68k_globals.h"
125
#endif
126
extern bool have_cond ;
127
extern int do_peephole ;
128
extern int do_pic ;
129
extern ast add_shape_to_stack PROTO_S ( ( ash, shape ) ) ;
130
 
131
 
132
/*
133
    SELECT BYTE, WORD OR LONG INSTRUCTION
134
 
135
    opb, opw and opl give the byte, word and long versions of an instruction.
136
    The appropriate instruction for size sz is returned.
137
*/
138
 
139
int ins
140
    PROTO_N ( ( sz, opb, opw, opl ) )
141
    PROTO_T ( long sz X int opb X int opw X int opl )
142
{
143
    if ( sz <= 8 ) return ( opb ) ;
144
    if ( sz <= 16 ) return ( opw ) ;
145
    if ( sz <= 32 ) return ( opl ) ;
146
    error ( "Illegal instruction size" ) ;
147
    return ( opl ) ;
148
}
149
 
150
 
151
/*
152
    SELECT SINGLE OR DOUBLE FLOATING-POINT INSTRUCTION
153
 
154
    ops and opd give the single and double precision versions of an
155
    instruction.  The appropriate instruction for size sz is returned.
156
*/
157
 
158
int insf
159
    PROTO_N ( ( sz, ops, opd, opx ) )
160
    PROTO_T ( long sz X int ops X int opd X int opx )
161
{
162
    if ( sz == 32 ) return ( ops ) ;
163
    if ( sz == 64 ) return ( opd ) ;
164
    error ( "Illegal instruction size" ) ;
165
    return ( opx ) ;
166
}
167
 
168
 
169
/*
170
    ADD A CONSTANT TO AN ADDRESS REGISTER
171
 
172
    This routine is used primarily for updating the stack.  It adds d
173
    to the A-register with number r.
174
*/
175
 
176
void add_to_reg
177
    PROTO_N ( ( r, d ) )
178
    PROTO_T ( int r X long d )
179
{
180
    if ( d ) {
181
	int instr ;
182
	mach_op *op1 ;
183
	mach_op *op2 = make_register ( r ) ;
184
	if ( d > 0 && d <= 8 ) {
185
	    instr = m_addql ;
186
	    op1 = make_value ( d ) ;
187
	} else if ( d < 0 && d >= -8 ) {
188
	    instr = m_subql ;
189
	    op1 = make_value ( -d ) ;
190
	} else {
191
	    instr = m_lea ;
192
	    op1 = make_indirect ( r, d ) ;
193
	}
194
	make_instr ( instr, op1, op2, regmsk ( r ) ) ;
195
	have_cond = 0 ;
196
    }
197
    return ;
198
}
199
 
200
 
201
/*
202
    CHECK RESERVED NAMES
203
 
204
    This routine returns 1 if nm is a name reserved by the linker.
205
*/
206
 
207
bool reserved
208
    PROTO_N ( ( nm ) )
209
    PROTO_T ( char *nm )
210
{
211
    int i ;
212
    static char *rn [] = {
213
	"_edata", "_etext", "_end", "__edata", "__etext", "__end"
214
    } ;
215
    for ( i = 0 ; i < array_size ( rn ) ; i++ ) {
216
	if ( eq ( nm, rn [i] ) ) return ( 1 ) ;
217
    }
218
    return ( 0 ) ;
219
}
220
 
221
 
222
/*
223
    LOOK FOR SPECIAL FUNCTIONS
224
 
225
    An expression is examined to see if it is a recognised special
226
    function.  The functions recognised are : strcpy of a constant
227
    string (which is turned into a move instruction), and alloca
228
    (which is inlined).
229
*/
230
 
231
speci special_fn
232
    PROTO_N ( ( a1, a2, s ) )
233
    PROTO_T ( exp a1 X exp a2 X shape s )
234
{
235
    speci spec_fn ;
236
    dec *d = brog ( son ( a1 ) ) ;
237
    char *id = d->dec_u.dec_val.dec_id ;
238
    spec_fn.is_special = 0 ;
239
 
240
    if ( id == null ) return ( spec_fn ) ;
241
 
242
    if ( eq ( id, "_setjmp" ) ) has_setjmp = 1 ;
243
    if ( eq ( id, "_longjmp" ) ) has_setjmp = 1 ;
244
 
245
    if ( !do_alloca ) return ( spec_fn ) ;
246
 
247
    if ( ( /* eq ( id, "_alloca" ) || */ eq ( id, "___builtin_alloca" ) ) &&
248
	 a2 != nilexp && last ( a2 ) ) {
249
	exp r = getexp ( s, nilexp, 0, a2, nilexp, 0, L0, alloca_tag ) ;
250
	setfather ( r, son ( r ) ) ;
251
	has_alloca = 1 ;
252
	spec_fn.is_special = 1 ;
253
	spec_fn.special_exp = r ;
254
	kill_exp ( a1, a1 ) ;
255
	return ( spec_fn ) ;
256
    }
257
 
258
    return ( spec_fn ) ;
259
}
260
 
261
 
262
/*
263
    STACK INFORMATION
264
 
265
    A number of variable are used to represent the state of the stack.
266
    used_stack is true to indicate that space has been allocated for
267
    variables on the stack or that alloca is used in the current
268
    procedure (the latter is also indicated by has_alloca) or that
269
    we are in diagnostics mode.  It forces the use of the application
270
    pointer instead of the stack pointer.  max_stack gives the amount
271
    of space allocated on the stack.
272
 
273
    stack_dec and stack_size are both used to keep track of changes
274
    to the stack pointer due to pushes and pops etc.
275
 
276
    extra_stack is used in coder for working out the position of
277
    procedure arguments which are compound results of procedure calls.
278
 
279
    ldisp is the extra value which needs to be added to the stack pointer
280
    to reference procedure arguments.  Its value is not known until the
281
    entire procedure has been coded, so a special label is used to
282
    represent its value during the procedure coding.  used_ldisp is
283
    true to indicate that this special label has been used.
284
*/
285
 
286
bool used_stack = 0 ;
287
long max_stack = 0 ;
288
long stack_dec = 0 ;
289
long stack_size = 0 ;
290
long extra_stack = 0 ;
291
bool used_ldisp = 0 ;
292
long ldisp = 0 ;
293
 
294
 
295
/*
296
    PENDING STACK DISPLACEMENT
297
 
298
    Consecutive changes to the stack pointer are combined whenever
299
    possible.  stack_change gives the current amount of change which
300
    has not been output as an instruction.
301
*/
302
 
303
long stack_change = 0 ;
304
int stack_direction = 0 ;
305
 
306
 
307
/*
308
    DECREASE THE STACK
309
 
310
    This routine decreases the stack pointer by d bits.
311
*/
312
 
313
void dec_stack
314
    PROTO_N ( ( d ) )
315
    PROTO_T ( long d )
316
{
317
    if ( d ) {
318
	stack_change -= d ;
319
	stack_direction = ( d > 0 ? 1 : 0 ) ;
320
	have_cond = 0 ;
321
#ifdef EBUG
322
        update_stack() ;
323
#endif
324
    }
325
    return ;
326
}
327
 
328
 
329
/*
330
    OUTPUT STACK DISPLACEMENT
331
 
332
    This routine outputs any accummulated stack changes.
333
*/
334
 
335
void update_stack
336
    PROTO_Z ()
337
{
338
    if ( stack_change ) {
339
	long d = stack_change / 8 ;
340
	stack_size += stack_change ;
341
	stack_change = 0 ;
342
	add_to_reg ( REG_SP, d ) ;
343
    }
344
    return ;
345
}
346
 
347
 
348
/*
349
    CHANGE DATA AREA
350
 
351
    This routine changes the current address area.  p can be one of
352
    the values ptext, pdata or pbss given in codex.h.
353
*/
354
 
355
void area
356
    PROTO_N ( ( p ) )
357
    PROTO_T ( int p )
358
{
359
    static int current_area = -1 ;
360
    static int previous_area = -1 ;
361
    if ( p == plast ) p = previous_area ;
362
    if ( p != current_area ) {
363
	int i ;
364
	switch ( p ) {
365
	    case ptext : i = m_as_text ; break ;
366
	    case pdata : i = m_as_data ; break ;
367
	    case pbss : i = m_as_bss ; break ;
368
	    default : i = m_dont_know ; break ;
369
	}
370
	make_instr ( i, null, null, 0 ) ;
371
	previous_area = current_area ;
372
	current_area = p ;
373
    } else {
374
	previous_area = current_area ;
375
    }
376
    return ;
377
}
378
 
379
 
380
/*
381
    OUTPUT A LIBRARY CALL
382
 
383
    A call of the library routine with name nm is output.
384
*/
385
 
386
void libcall
387
    PROTO_N ( ( nm ) )
388
    PROTO_T ( char *nm )
389
{
390
    int lab;
391
    mach_op *p = make_extern_data ( nm, 0 ) ;
392
#if 0 /*float_to_unsigned*/
393
    if((have_overflow() || have_continue())&& !strcmp(nm,float_to_unsigned)) {
394
      /* we need to ensure that the value in %fp0 is not outside the valid
395
	 range for an unsigned int, otherwise there will be a floating
396
	 point exception in the library routine. */
397
      bool sw;
398
      exp e = getexp(ulongsh,nilexp,0,nilexp,nilexp,0,1333788672,val_tag);
399
      exp loc = sim_exp(shrealsh,FP1);
400
      lab = (have_continue())?next_lab() : overflow_jump;
401
      ins2(m_fmoves,shape_size(shrealsh),shape_size(shrealsh),zw(e),zw(loc));
402
      /*move(ulongsh,zw(e),zw(loc));  */
403
      sw = cmp(shrealsh,FP0,FP1,tst_gr);
404
 
405
      make_jump(branch_ins(tst_gr,sw,0,1),lab);
406
      kill_exp(e,e);
407
    }
408
#endif
409
 
410
    make_instr ( m_call, p, null, ~save_msk ) ;
411
    no_calls++ ;
412
#if 0
413
    if(have_continue() && !strcmp(nm,float_to_unsigned)) {
414
      make_label(lab);
415
    }
416
#endif
417
    have_cond = 0 ;
418
    return ;
419
}
420
 
421
 
422
/*
423
    REGISTER MASKS
424
 
425
    regsinuse gives all the registers which are currented allocated
426
    values.  regsinproc is a cummulative record of all the registers
427
    which have been used in the current procedure.  reuseables is
428
    the record of all the current active reuseable registers.  bigregs
429
    records all registers in the current procedure which span procedure
430
    calls.
431
*/
432
 
433
bitpattern regsinuse ;
434
bitpattern regsinproc ;
435
bitpattern reuseables ;
436
bitpattern regsindec ;
437
bitpattern bigregs ;
438
 
439
 
440
/*
441
    OTHER VARIABLES
442
 
443
    crt_ret_lab is a label number assigned to the return sequence of
444
    the current procedure.  just_ret is set to be true if the return
445
    sequence just consists of a single rts instruction.  no_calls
446
    records the number of procedure calls in the current procedure.
447
*/
448
 
449
long crt_ret_lab = 0 ;
450
bool just_ret = 0 ;
451
int no_calls = 0 ;
452
 
453
 
454
/*
455
    PROLOGUE POSITIONS
456
 
457
    This records the position of the prologue of the current procedure.
458
*/
459
 
460
mach_ins *prologue_ins ;
461
 
462
 
463
/*
464
    GENERAL PURPOSE PROCEDURE PROLOGUE
465
 
466
    There are two cases.  If output_immediately is false then the
467
    prologue is not inserted until the end of the procedure.  Otherwise
468
    a number of special labels are used to represent values which will
469
    not be known until the end of the procedure.
470
*/
471
 
472
void prologue
473
    PROTO_Z ()
474
{
475
    mach_op *op1, *op2 ;
476
    have_cond = 0 ;
477
    just_ret = 1 ;
478
    if ( !output_immediately ) {
479
	/* Just record position in this case */
480
	prologue_ins = current_ins ;
481
	return ;
482
    }
483
    /* Output generalized link and push instructions */
484
    op1 = make_register ( REG_AP ) ;
485
    op2 = make_special ( "PA" ) ;
486
    make_instr ( m_linkl, op1, op2, 0 ) ;
487
    op1 = make_special ( "PB" ) ;
488
    op2 = make_indirect ( REG_SP, 0 ) ;
489
    make_instr ( m_moveml, op1, op2, 0 ) ;
490
    op1 = make_special ( "PC" ) ;
491
    op2 = make_indirect ( REG_AP, 0 ) ;
492
    op2->of->plus = make_special ( "PD" ) ;
493
    make_instr ( m_fmovemx, op1, op2, 0 ) ;
494
    return ;
495
}
496
 
497
 
498
/*
499
    GENERAL PURPOSE PROCEDURE EPILOGUE
500
 
501
    The registers used in the procedure and the space used on the stack
502
    are analysed and used to form the procedure epilogue.  If
503
    output_immediately is false then we go back and fill in the
504
    prologue.  Otherwise the values of the special labels used in the
505
    prologue are output.  There is some testing to see if D1, A0, A1
506
    and FP1 can be put to better use.
507
*/
508
 
509
void epilogue
510
    PROTO_N ( ( restore_only ) )
511
    PROTO_T ( int restore_only )
512
{
513
    int r ;
514
    bitpattern m ;
515
    long st, st1 ;
516
    mach_op *op1, *op2 ;
517
 
518
    int push_all = 0, use_link = 0 ;
519
    int tmp_d1 = -1, tmp_a0 = -1, tmp_a1 = -1 ;
520
 
521
    bitpattern rmsk = regs ( regsinproc & save_msk ) ;
522
    bitpattern smsk = rmsk ;
523
    bitpattern cmsk = 0 ;
524
    bitpattern fmsk = 0 ;
525
    bitpattern fsmsk = fregs ( regsinproc & save_msk ) ;
526
 
527
    reset_round_mode();  /* restore the default floating point rounding mode */
528
 
529
    for ( r = REG_FP7, m = 1 ; r >= REG_FP2 ; r--, m <<= 1 ) {
530
	if ( regsinproc & regmsk ( r ) ) fmsk |= m ;
531
    }
532
 
533
    if ( no_calls ) {
534
	smsk &= ~bigregs ;
535
	fsmsk &= ~bigregs ;
536
    }
537
    if(!restore_only) {
538
      make_label ( crt_ret_lab ) ;
539
    }
540
 
541
#if have_diagnostics
542
    if ( diagnose ) xdb_diag_proc_return () ;
543
#endif
544
 
545
    if ( !output_immediately ) {
546
	bool d1_free = 0 ;
547
 
548
	/* Use D1 if not already used */
549
	if ( !( regsinproc & regmsk ( REG_D1 ) ) ) {
550
	    m = smsk & dreg_msk ;
551
	    if ( m ) {
552
		/* Replace a used D-register by D1 */
553
		r = reg ( m ) ;
554
		reg_names [r] = reg_names [ REG_D1 ] ;
555
		rmsk &= ~regmsk ( r ) ;
556
		smsk &= ~regmsk ( r ) ;
557
		cmsk |= regmsk ( r ) ;
558
	    } else {
559
		d1_free = 1 ;
560
	    }
561
	}
562
 
563
	/* Use A0 if not already used */
564
	if ( !( regsinproc & regmsk ( REG_A0 ) ) ) {
565
	    m = smsk & areg_msk ;
566
	    if ( m ) {
567
		/* Replace a used A-register by A0 */
568
		r = reg ( m ) ;
569
		reg_names [r] = reg_names [ REG_A0 ] ;
570
		rmsk &= ~regmsk ( r ) ;
571
		smsk &= ~regmsk ( r ) ;
572
		cmsk |= regmsk ( r ) ;
573
	    } else if ( no_calls == 0 ) {
574
		m = rmsk & dreg_msk ;
575
		if ( m ) {
576
		    /* Move a used D-register into A0 */
577
		    tmp_a0 = reg ( m ) ;
578
		    rmsk &= ~regmsk ( tmp_a0 ) ;
579
		    smsk = rmsk ;
580
		    op1 = make_register ( REG_A0 ) ;
581
		    op2 = make_register ( tmp_a0 ) ;
582
		    make_instr ( m_movl, op1, op2, regmsk ( tmp_a0 ) ) ;
583
		    just_ret = 0 ;
584
		}
585
	    }
586
	}
587
 
588
	/* Use A1 if not already used */
589
	if ( !( regsinproc & regmsk ( REG_A1 ) ) ) {
590
	    m = smsk & areg_msk ;
591
	    if ( m ) {
592
		/* Replace a used A-register by A1 */
593
		r = reg ( m ) ;
594
		reg_names [r] = reg_names [ REG_A1 ] ;
595
		rmsk &= ~regmsk ( r ) ;
596
		smsk &= ~regmsk ( r ) ;
597
		cmsk |= regmsk ( r ) ;
598
	    } else if ( no_calls == 0 ) {
599
		m = rmsk & dreg_msk ;
600
		if ( m ) {
601
		    /* Move a used D-register into A1 */
602
		    tmp_a1 = reg ( m ) ;
603
		    rmsk &= ~regmsk ( tmp_a1 ) ;
604
		    smsk = rmsk ;
605
		    op1 = make_register ( REG_A1 ) ;
606
		    op2 = make_register ( tmp_a1 ) ;
607
		    make_instr ( m_movl, op1, op2, regmsk ( tmp_a1 ) ) ;
608
		    just_ret = 0 ;
609
		}
610
	    }
611
	}
612
 
613
	/* Use FP1 if not already used */
614
	if ( !( regsinproc & regmsk ( REG_FP1 ) ) ) {
615
	    for ( r = REG_FP7, m = 1 ; r >= REG_FP2 ; r--, m <<= 1 ) {
616
		if ( fsmsk & regmsk ( r ) ) {
617
		    reg_names [r] = reg_names [ REG_FP1 ] ;
618
		    fmsk &= ~m ;
619
		    fsmsk &= ~regmsk ( r ) ;
620
		    cmsk |= regmsk ( r ) ;
621
		    r = REG_FP1 ;
622
		}
623
	    }
624
	}
625
 
626
	if ( d1_free && no_calls == 0 ) {
627
	    m = rmsk & areg_msk ;
628
	    if ( m ) {
629
		/* Move a used A-register into D1 */
630
		tmp_d1 = reg ( m ) ;
631
		rmsk &= ~regmsk ( tmp_d1 ) ;
632
		op1 = make_register ( REG_D1 ) ;
633
		op2 = make_register ( tmp_d1 ) ;
634
		make_instr ( m_movl, op1, op2, regmsk ( tmp_d1 ) ) ;
635
		just_ret = 0 ;
636
	    }
637
	}
638
 
639
    }
640
 
641
    /* Calculate stack displacements */
642
/* todo use symbol instead of number */
643
    st1 = round ( max_stack, 32 ) / 8 + 16 * bits_in ( fmsk ) ;
644
    st = st1 + 4 * bits_in ( rmsk ) ;
645
    if ( st1 || used_stack || !push_all || output_immediately ) use_link = 1 ;
646
 
647
    /* Remove floating-point registers from the stack */
648
    if ( fmsk ) {
649
	just_ret = 0 ;
650
	op1 = make_indirect ( REG_AP, -st1 ) ;
651
	op2 = make_hex_value ( fmsk ) ;
652
	make_instr ( m_fmovemx, op1, op2, 0 ) ;
653
    }
654
 
655
    /* Remove registers from the stack */
656
    if ( rmsk ) {
657
	just_ret = 0 ;
658
	if ( push_all ) {
659
	    for ( r = REG_AP - 1 ; r > REG_D1 ; r-- ) {
660
		if ( rmsk & regmsk ( r ) ) {
661
		    op1 = make_inc_sp () ;
662
		    op2 = make_register ( r ) ;
663
		    make_instr ( m_movl, op1, op2, regmsk ( r ) ) ;
664
		}
665
	    }
666
	} else {
667
	    if ( must_use_bp ) {
668
		op1 = make_indirect ( REG_AP, -st ) ;
669
	    } else {
670
		op1 = make_indirect ( REG_SP, 0 ) ;
671
	    }
672
	    op2 = make_hex_value ( rmsk ) ;
673
	    make_instr ( m_moveml, op1, op2, rmsk ) ;
674
	    just_ret = 0 ;
675
	}
676
    }
677
 
678
    /* Output unlink instruction */
679
    if ( use_link ) {
680
	just_ret = 0 ;
681
	op1 = make_register ( REG_AP ) ;
682
	make_instr ( m_unlk, op1, null, 0 ) ;
683
    }
684
    if(!restore_only) {
685
      /* Output return instruction */
686
      make_instr ( m_rts, null, null, 0 ) ;
687
    }
688
 
689
    if ( output_immediately ) {
690
 
691
	/* Output stack displacement value */
692
	if ( used_ldisp ) {
693
	    op1 = make_int_data ( use_link ? st + 4 : st ) ;
694
	    set_special ( "S", op1 ) ;
695
	}
696
 
697
	/* Output values used in prologue */
698
	just_ret = 0 ;
699
	op1 = make_int_data ( -st ) ;
700
	set_special ( "PA", op1 ) ;
701
	op1 = make_hex_data ( rmsk ) ;
702
	set_special ( "PB", op1 ) ;
703
	op1 = make_hex_data ( fmsk ) ;
704
	set_special ( "PC", op1 ) ;
705
	op1 = make_int_data ( -st1 ) ;
706
	set_special ( "PD", op1 ) ;
707
 
708
    } else if(!restore_only){
709
 
710
	/* Go back to the prologue position */
711
	mach_ins *p = current_ins ;
712
	current_ins = prologue_ins ;
713
 
714
        cur_proc_env_size = ldisp = ( use_link ? st + 4 : st ) ;
715
 
716
	/* Output link instruction */
717
	if ( use_link ) {
718
	    long c = ( push_all ? -st1 : -st ) ;
719
	    int i = ( c < -0x7fff ? m_linkl : m_linkw ) ;
720
	    op1 = make_register ( REG_AP ) ;
721
	    op2 = make_value ( c ) ;
722
	    make_instr ( i, op1, op2, 0 ) ;
723
	}
724
 
725
	/* Save register in D1 if necessary */
726
	if ( tmp_d1 >= 0 ) {
727
	    op1 = make_register ( tmp_d1 ) ;
728
	    op2 = make_register ( REG_D1 ) ;
729
	    make_instr ( m_movl, op1, op2, regmsk ( REG_D1 ) ) ;
730
	}
731
 
732
	/* Save register in A0 if necessary */
733
	if ( tmp_a0 >= 0 ) {
734
	    op1 = make_register ( tmp_a0 ) ;
735
	    op2 = make_register ( REG_A0 ) ;
736
	    make_instr ( m_movl, op1, op2, regmsk ( REG_A0 ) ) ;
737
	}
738
 
739
	/* Save register in A1 if necessary */
740
	if ( tmp_a1 >= 0 ) {
741
	    op1 = make_register ( tmp_a1 ) ;
742
	    op2 = make_register ( REG_A1 ) ;
743
	    make_instr ( m_movl, op1, op2, regmsk ( REG_A1 ) ) ;
744
	}
745
 
746
	/* Put registers onto the stack */
747
	if ( rmsk ) {
748
	    if ( push_all ) {
749
		for ( r = REG_D1 + 1 ; r < REG_AP ; r++ ) {
750
		    if ( rmsk & regmsk ( r ) ) {
751
			op1 = make_register ( r ) ;
752
			op2 = make_dec_sp () ;
753
			make_instr ( m_movl, op1, op2, 0 ) ;
754
		    }
755
		}
756
	    } else {
757
		op1 = make_hex_value ( rmsk ) ;
758
		op2 = make_indirect ( REG_SP, 0 ) ;
759
		make_instr ( m_moveml, op1, op2, 0 ) ;
760
	    }
761
	}
762
 
763
	/* Put floating-point registers onto the stack */
764
	if ( fmsk ) {
765
	    op1 = make_hex_value ( fmsk ) ;
766
	    op2 = make_indirect ( REG_AP, -st1 ) ;
767
	    make_instr ( m_fmovemx, op1, op2, 0 ) ;
768
	}
769
 
770
	/* Return to previous position */
771
	current_ins = p ;
772
    }
773
    callmsk = cmsk ;
774
    have_cond = 0 ;
775
    return ;
776
}
777
 
778
 
779
/*
780
    PROFILING
781
 
782
    In order for prof and gprof to work, we need to associate four bytes
783
    of data with each procedure and make the first two lines of the
784
    procedure move the address of these bytes into the A0 register and
785
    call mcount.  Unfortunately mcount uses A1 so, if the procedure returns
786
    a complex result, the address where we are meant to put it, which was
787
    in A1, is lost.  cc doesn't take account of this, and so can go
788
    wrong under these circumstances.  I instead call a dummy routine,
789
    Lmcount, given below, which stores the value of A1 and then jumps to
790
    mcount, and restore the value of A1 afterwards.
791
 
792
			text
793
		Lmcount:
794
			mov.l	%a1, Lmstore
795
			jmp.l	mcount
796
			data
797
		Lmstore:
798
			long	0
799
 
800
    The flag used_my_mcount is set to be true if Lmcount is used.
801
*/
802
 
803
static bool used_my_mcount = 0 ;
804
 
805
 
806
/*
807
    OUTPUT PROFILING DATA
808
 
809
    This routine outputs the profiling data for a procedure.  If save_a1
810
    is true, the alternative profiling routine is used.
811
*/
812
 
813
void out_profile
814
    PROTO_N ( ( save_a1 ) )
815
    PROTO_T ( bool save_a1 )
816
{
817
    exp z ;
818
    mach_op *op1, *op2 ;
819
    /* Make a new label */
820
    long lb = next_lab () ;
821
 
822
    if ( profiling_uses_lea ) {
823
	op1 = make_lab_data ( lb, 0 ) ;
824
	op2 = make_register ( profiling_reg ) ;
825
	make_instr ( m_lea, op1, op2, regmsk ( profiling_reg ) ) ;
826
    } else {
827
	op1 = make_lab ( lb, 0 ) ;
828
	op2 = make_register ( profiling_reg ) ;
829
	make_instr ( m_movl, op1, op2, regmsk ( profiling_reg ) ) ;
830
    }
831
 
832
    if ( save_a1 ) {
833
	/* Call dummy version of mcount - see below */
834
	libcall ( "Lmcount" ) ;
835
	/* Restore the value of A1 */
836
	op1 = make_extern_ind ( "Lmstore", 0 ) ;
837
	op2 = make_register ( REG_A1 ) ;
838
	make_instr ( m_movl, op1, op2, regmsk ( REG_A1 ) ) ;
839
	used_my_mcount = 1 ;
840
    } else {
841
	/* Call mcount */
842
	libcall ( profiling_routine ) ;
843
    }
844
 
845
    /* Set up the label to point to 0 */
846
    z = simple_exp ( val_tag ) ;
847
    sh ( z ) = slongsh ;
848
    make_constant ( lb, z ) ;
849
    return ;
850
}
851
 
852
 
853
/*
854
    OUTPUT ALTERNATIVE PROFILING ROUTINE
855
 
856
    This routine outputs the alternative profiling routine Lmcount
857
    described above if it is required.
858
*/
859
 
860
void profile_hack
861
    PROTO_Z ()
862
{
863
    mach_op *op1, *op2 ;
864
    if ( !used_my_mcount ) return ;
865
    area ( ptext ) ;
866
    make_external_label ( "Lmcount" ) ;
867
    op1 = make_register ( REG_A1 ) ;
868
    op2 = make_extern_ind ( "Lmstore", 0 ) ;
869
    make_instr ( m_movl, op1, op2, 0 ) ;
870
    op1 = make_extern_data ( profiling_routine, 0 ) ;
871
    make_instr ( m_jmp, op1, null, 0 ) ;
872
    area ( pdata ) ;
873
    make_external_label ( "Lmstore" ) ;
874
    op1 = make_int_data ( 0 ) ;
875
    make_instr ( m_as_long, op1, null, 0 ) ;
876
    return ;
877
}
878
 
879
#if 0
880
/*
881
    ENCODE A PROCEDURE
882
 
883
    This routine encodes a procedure call.  The procedure is named pname
884
    with oname as an alternative (used with diagnostics).  The actual
885
    body of the procedure is p.
886
*/
887
 
888
void cproc
889
    PROTO_N ( ( p, pname, cname, is_ext, reg_res, di ) )
890
    PROTO_T ( exp p X char *pname X long cname X int is_ext X int reg_res X diag_global *di )
891
{
892
    exp t ;
893
    ash stack ;
894
    ash param_pos ;
895
    mach_op *op1, *op2 ;
896
    static long crt_proc_no = 0 ;
897
 
898
#ifndef tdf3
899
    cur_proc_has_tail_call = 0;
900
    cur_proc_use_same_callees = 0;
901
    scan2(1, p, p);
902
    comp_weights ( p ) ;
903
#endif
904
 
905
    /* Set up flags, register masks, stack etc. */
906
    bigregs = 0 ;
907
    crt_ret_lab = next_lab () ;
908
    extra_stack = 0 ;
909
    have_cond = 0 ;
910
    max_stack = 0 ;
911
    no_calls = 0 ;
912
    regsinproc = 0 ;
913
    regsinuse = 0 ;
914
    reuseables = 0 ;
915
    regsindec = 0 ;
916
    stack = 0 ;
917
    special_no = crt_proc_no++ ;
918
    stack_dec = 0 ;
919
    stack_size = 0 ;
920
    used_ldisp = 0 ;
921
    used_stack = diagnose || must_use_bp ;
922
 
923
    /* Mark procedure body */
924
    ptno ( p ) = par_pl ;
925
    no ( p ) = 0 ;
926
 
927
    /* Mark procedure parameters */
928
    param_pos = 0 ;
929
    t = son ( p ) ;
930
    while ( name ( t ) == ident_tag && isparam ( t ) ) {
931
	ast a ;
932
	a = add_shape_to_stack ( param_pos, sh ( son ( t ) ) ) ;
933
	ptno ( t ) = par_pl ;
934
	no ( t ) = a.astoff + a.astadj ;
935
	param_pos = a.astash ;
936
 
937
        make_visible( t ) ;
938
 
939
	t = bro ( son ( t ) ) ;
940
    }
941
 
942
    /* Output procedure name(s) */
943
    area ( ptext ) ;
944
#ifndef no_align_directives
945
    make_instr ( m_as_align4, null, null, 0 ) ;
946
#endif
947
    if ( is_ext && pname ) {
948
	if ( strcmp ( pname, "_cmppt" ) == 0 ) {
949
	    /* Hack to get alignments right */
950
	    make_instr ( m_nop, null, null, 0 ) ;
951
	    make_instr ( m_nop, null, null, 0 ) ;
952
	}
953
	op1 = make_extern_data ( pname, 0 ) ;
954
	make_instr ( m_as_global, op1, null, 0 ) ;
955
    }
956
    if ( cname == -1 ) {
957
	make_external_label ( pname ) ;
958
    } else {
959
	make_label ( cname ) ;
960
    }
961
 
962
    /* Output profiling information if required */
963
    if ( do_profile ) {
964
	out_profile ( !reg_res ) ;
965
	used_stack = 1 ;
966
    }
967
 
968
    /* Set up procedure prologue */
969
    prologue () ;
970
 
971
    /* Output PIC prologue if necessary */
972
    if ( do_pic && proc_uses_external ( p ) ) {
973
	regsinproc |= regmsk ( REG_A5 ) ;
974
	regsinuse |= regmsk ( REG_A5 ) ;
975
	bigregs |= regmsk ( REG_A5 ) ;
976
	op1 = make_indirect ( REG_PC, 0 ) ;
977
	op1->of->plus = make_extern_data ( "_GLOBAL_OFFSET_TABLE_@GOTPC", 0 ) ;
978
	op2 = make_register ( REG_A5 ) ;
979
	make_instr ( m_lea, op1, op2, regmsk ( REG_A5 ) ) ;
980
    }
981
 
982
    /* Diagnostics for start of procedure */
983
#if have_diagnostics
984
    if ( di ) xdb_diag_proc_begin ( di, p, pname, cname, is_ext ) ;
985
#endif
986
 
987
    /* Allow for procedures which return compound results */
988
    if ( !reg_res ) {
989
	/* Save A1 on the stack */
990
	ast newstack ;
991
	newstack = add_shape_to_stack ( stack, slongsh ) ;
992
	stack = newstack.astash ;
993
	max_stack = 32 ;
994
	used_stack = 1 ;
995
	op1 = make_register ( REG_A1 ) ;
996
	op2 = make_indirect ( REG_AP, -4 ) ;
997
	make_instr ( m_movl, op1, op2, 0 ) ;
998
    }
999
 
1000
    /* Encode the procedure body */
1001
#if have_diagnostics
1002
    if ( diagnose ) {
1003
	dnt_begin () ;
1004
	coder ( zero, stack, t ) ;
1005
	dnt_end () ;
1006
    } else
1007
#endif
1008
    coder ( zero, stack, t ) ;
1009
 
1010
    /* Output the procedure epilogue */
1011
#ifndef tdf3
1012
    general_epilogue ( 0, 0 );
1013
#else
1014
    epilogue (0) ;
1015
#endif
1016
    /* Apply peephole optimizations and return */
1017
    if ( do_peephole ) peephole () ;
1018
 
1019
    /* Diagnostics for end of procedure */
1020
#if have_diagnostics
1021
    if ( di ) xdb_diag_proc_end ( di ) ;
1022
#endif
1023
    return ;
1024
}
1025
 
1026
#endif
1027