Subversion Repositories tendra.SVN

Rev

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

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