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 |
|