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) 1996
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/general_proc.c,v 1.1.1.1 1998/01/17 15:55:49 release Exp $
35
--------------------------------------------------------------------------
36
$Log: general_proc.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.4  1997/11/09 14:08:39  ma
41
Added preseve stack.
42
 
43
Revision 1.3  1997/10/29 10:22:14  ma
44
Replaced use_alloca with has_alloca.
45
 
46
Revision 1.2  1997/10/17 12:13:57  ma
47
Cleaned up.
48
 
49
Revision 1.1.1.1  1997/10/13 12:42:52  ma
50
First version.
51
 
52
Revision 1.6  1997/10/13 11:43:36  ma
53
Declared scan2.h
54
 
55
Revision 1.5  1997/10/13 08:49:29  ma
56
Made all pl_tests for general proc & exception handling pass.
57
 
58
Revision 1.4  1997/09/25 06:45:05  ma
59
All general_proc tests passed
60
 
61
Revision 1.3  1997/06/24 10:56:02  ma
62
Added changes for "Plumhall Patch"
63
 
64
Revision 1.2  1997/06/18 10:09:31  ma
65
Checking in before merging with Input Baseline changes.
66
 
67
--------------------------------------------------------------------------
68
*/
69
 
70
 
71
#include "config.h"
72
#include <limits.h>
73
#include "common_types.h"
74
#include "check.h"
75
#include "exp.h"
76
#include "expmacs.h"
77
#include "flags.h"
78
#include "shapemacs.h"
79
#include "externs.h"
80
#include "install_fns.h"
81
#include "spec.h"
82
#include "mach.h"
83
#include "where.h"
84
#include "tags.h"
85
#include "codec.h"
86
#include "coder.h"
87
#include "operations.h"
88
#include "ops_shared.h"
89
#include "mach_ins.h"
90
#include "mach_op.h"
91
#include "instr.h"
92
#include "codex.h"
93
#include "output.h"
94
#include "instrs.h"
95
#include "peephole.h"
96
#include "szs_als.h"
97
#include "tests.h"
98
#include "utility.h"
99
#include "weights.h"
100
#include "translate.h"
101
#include "general_proc.h"
102
#include "68k_globals.h"
103
#include "installglob.h"
104
#include "special_exps.h"
105
 
106
/* externals */
107
 
108
void scan2 PROTO_S ( ( bool sto, exp to, exp e ) ) ;
109
extern bool just_ret ;
110
extern mach_ins *prologue_ins ;
111
 
112
static void code_postlude PROTO_S ((exp postlude, exp callers, ash stack, long post_offset)) ;
113
static bool test_push_args PROTO_S ((exp args, ash* args_size )) ;
114
static void push_args PROTO_S ((where w, ash stack, exp args )) ;
115
static void place_arguments PROTO_S ((exp args, ash stack, long start )) ;
116
 
117
/************************************************************************
118
    GCPROC
119
 
120
    This routine encodes a procedure call.  The procedure is named pname
121
    with oname as an alternative (used with diagnostics).  The actual
122
    body of the procedure is p.
123
 ************************************************************************/
124
 
125
/* coder.c & codex.c */
126
extern ast add_shape_to_stack PROTO_S ((ash stack, shape s ));
127
extern void prologue PROTO_S ((void));
128
extern void out_profile PROTO_S (( bool save_a1 ));
129
extern int do_peephole ;
130
extern int do_pic ;
131
 
132
void gcproc
133
    PROTO_N ( ( p, pname, cname, is_ext, reg_res, di) )
134
    PROTO_T ( exp p X char *pname X long cname X int is_ext X int reg_res X diag_global *di )
135
{
136
  exp t ;
137
  ash stack ;
138
  ash param_pos ;
139
 
140
  mach_op *op1, *op2 ;
141
  static long crt_proc_no = 0 ;
142
 
143
  bool has_callers = 0;
144
  bool has_checkstack = 0;
145
  bool uses_callers_pointer = 0;
146
  cur_proc_callees_size = 0;
147
 
148
  /* find out if the call has tail_call or same_callees constructs */
149
  cur_proc_has_tail_call = 0;
150
  cur_proc_use_same_callees = 0;
151
  scan2(1, p, p);
152
  comp_weights ( p ) ;
153
 
154
  /* Set up flags, register masks, stack etc. */
155
  has_alloca = proc_has_alloca(p);
156
  must_use_bp = has_alloca || proc_has_lv(p) || proc_uses_crt_env (p) ;
157
  bigregs = 0 ;
158
  crt_ret_lab = next_lab () ;
159
  extra_stack = 0 ;
160
  have_cond = 0 ;
161
  max_stack = 0 ;
162
  no_calls = 0 ;
163
  regsinproc = 0 ;
164
  regsinuse = 0 ;
165
  reuseables = 0 ;
166
  regsindec = 0 ;
167
  stack = 0 ;
168
  special_no = crt_proc_no++ ;
169
  stack_dec = 0 ;
170
  stack_size = 0 ;
171
  used_ldisp = 0 ;
172
  used_stack = do_profile || diagnose || must_use_bp ;
173
 
174
  /* Mark procedure body */
175
  ptno ( p ) = par_pl ;
176
  no ( p ) = 0 ;
177
 
178
  /* Mark procedure parameters */
179
  param_pos = 0 ;
180
 
181
  /* the callees are encoded first. Scan to first callee if any */
182
 
183
  t = son ( p ) ;
184
  while ( name ( t ) == ident_tag && isparam ( t ) &&
185
          name ( son ( t ) ) != formal_callee_tag ) {
186
    t = bro(son(t)) ;
187
    has_callers = 1 ;
188
  }
189
 
190
  cur_proc_has_vcallees = proc_has_vcallees(p) ;
191
  uses_callers_pointer = cur_proc_has_vcallees && has_callers ;
192
 
193
  if (uses_callers_pointer) {
194
    /* ok callers are accessed by use of a5 */
195
    regsinproc |= regmsk ( REG_A5 ) ;
196
    regsinuse  |= regmsk ( REG_A5 ) ;
197
  }
198
 
199
 
200
  /* do we have any callees? */
201
  if (name(t) == ident_tag && name(son(t)) == formal_callee_tag) {
202
    while(name(t) == ident_tag && name(son(t)) == formal_callee_tag) {
203
      ast a ;
204
      a = add_shape_to_stack ( param_pos, sh ( son ( t ) ) ) ;
205
      no ( t ) = a.astoff + a.astadj + (cur_proc_has_vcallees ? 4*8 : 0);
206
      param_pos = a.astash ;
207
      ptno ( t ) = par_pl ;
208
 
209
      make_visible( t ) ;
210
 
211
      t = bro ( son ( t ) ) ;
212
    }
213
    cur_proc_callees_size = param_pos ;
214
  }
215
 
216
 
217
  /* encode the caller parameters */
218
  {
219
    exp caller = son ( p ) ;
220
    int location_id = par_pl ;
221
    if ( uses_callers_pointer ) {
222
      location_id = par2_pl ;
223
      param_pos = 0 ;
224
    }
225
    while (name(caller) == ident_tag && isparam (caller) &&
226
           name(son(caller)) != formal_callee_tag ) {
227
 
228
      ast a;
229
      a = add_shape_to_stack ( param_pos, sh ( son ( caller ) ) ) ;
230
      ptno ( caller ) = location_id ;
231
      no ( caller ) = a.astoff + a.astadj ;
232
      param_pos = a.astash ;
233
 
234
      make_visible( caller ) ;
235
 
236
      caller = bro ( son ( caller ) ) ;
237
    }
238
  }
239
 
240
  /* calculate callers size */
241
  cur_proc_callers_size = param_pos ;
242
  if ( ! uses_callers_pointer )
243
  cur_proc_callers_size -= cur_proc_callees_size ;
244
 
245
  /* Output procedure name(s) */
246
  area ( ptext ) ;
247
  make_instr ( m_as_align4, null, null, 0 ) ;
248
  if ( is_ext && pname ) {
249
     if ( strcmp ( pname, "_cmppt" ) == 0 ) {
250
        /* Hack to get alignments right */
251
      make_instr ( m_nop, null, null, 0 ) ;
252
      make_instr ( m_nop, null, null, 0 ) ;
253
    }
254
    op1 = make_extern_data ( pname, 0 ) ;
255
    make_instr ( m_as_global, op1, null, 0 ) ;
256
  }
257
  if ( cname == -1 ) {
258
    make_external_label ( pname ) ;
259
  } else {
260
     make_label ( cname ) ;
261
  }
262
 
263
  if (! strcmp (pname, "_main")) {
264
     make_comment("Do Dynamic Initialization");
265
     op1 = make_extern_ind("___TDF_main",0);
266
     make_instr(m_call,op1,null,0);
267
  }
268
 
269
  /* Output profiling information if required */
270
  if ( do_profile ) {
271
    out_profile ( !reg_res ) ;
272
    used_stack = 1 ;
273
  }
274
 
275
  if ( proc_has_checkstack(p) ) {
276
     /* check that there is room for env_size(<this proc>) */
277
     /* since callers, callees & return address are pushed */
278
     /* we only check for the rest */
279
     long already_allocated = cur_proc_callers_size + cur_proc_callees_size + 32 ;
280
     where w;
281
     w = mw (get_env_size(cur_proc_dec), - already_allocated);
282
     checkalloc_stack (w, 0);
283
     has_checkstack = 1 ;
284
  }
285
 
286
 
287
  /* Set up procedure prologue */
288
  prologue () ;
289
 
290
  /* Diagnostics for start of procedure */
291
#if have_diagnostics
292
  if ( di ) xdb_diag_proc_begin ( di, p, pname, cname, is_ext ) ;
293
#endif
294
 
295
  /* Allow for procedures which return compound results */
296
  if ( !reg_res ) {
297
    /* Save A1 on the stack */
298
    ast newstack ;
299
    newstack = add_shape_to_stack ( stack, slongsh ) ;
300
    stack = newstack.astash ;
301
    max_stack = 32 ;
302
    used_stack = 1 ;
303
    op1 = make_register ( REG_A1 ) ;
304
    op2 = make_indirect ( REG_AP, -4 ) ;
305
    make_instr ( m_movl, op1, op2, 0 ) ;
306
  }
307
  need_preserve_stack = 0;
308
 
309
  if (proc_uses_crt_env(p) && proc_has_lv(p) && has_alloca) {
310
     need_preserve_stack = 1 ;
311
     stack += 32 ;
312
     max_stack += 32 ;
313
     save_stack () ;
314
  };
315
 
316
 
317
  /* Encode the procedure body */
318
#if have_diagnostics
319
  if ( diagnose ) {
320
    dnt_begin () ;
321
    coder ( zero, stack, t ) ;
322
    dnt_end () ;
323
  } else
324
#endif
325
    coder ( zero, stack, t ) ;
326
 
327
  /* Output the procedure epilogue */
328
  general_epilogue (uses_callers_pointer, has_checkstack) ;
329
 
330
  /* Apply peephole optimizations and return */
331
  if ( do_peephole ) peephole () ;
332
 
333
  /* Diagnostics for end of procedure */
334
#if have_diagnostics
335
  if ( di ) xdb_diag_proc_end ( di ) ;
336
#endif
337
 
338
  return  ;
339
}
340
 
341
 
342
/************************************************************************
343
  restore_regs_subsribers is used by restore_regs.
344
  It is a list of places to put insructions to restore registers.
345
I If untidy is true, it means that sp shall not be restored.
346
*/
347
 
348
typedef struct rrs_tag {
349
  mach_ins* ins ;
350
  restore_type_t restore_type  ;
351
  struct rrs_tag* next ;
352
} rrs;
353
 
354
rrs* restore_regs_subsribers = 0 ;
355
 
356
 
357
/************************************************************************
358
 RESTORE_REGS
359
 
360
 Subscribe on code to restore registers. See restore_regs_output below.
361
 Restore_type is one of: ALL, NOT_SP, NOT_A6_OR_SP
362
 ************************************************************************/
363
 
364
void restore_regs
365
    PROTO_N ( ( typ ) )
366
    PROTO_T ( restore_type_t typ )
367
{
368
  rrs* p = (rrs*) xmalloc(sizeof(rrs)) ;
369
  p->ins  = current_ins ;
370
  p->next = restore_regs_subsribers ;
371
  p->restore_type = typ ;
372
  restore_regs_subsribers = p ;
373
}
374
/************************************************************************/
375
/* used by restore_regs_output below */
376
 
377
rrs* pop_restore_regs_subsriber
378
    PROTO_Z ()
379
{
380
   rrs* p = restore_regs_subsribers ;
381
 
382
   if (p != 0) {
383
      restore_regs_subsribers = p->next ;
384
   }
385
 
386
   return p ;
387
}
388
 
389
/************************************************************************
390
  RESTORE_REGS_OUTPUT
391
 
392
  Output instructions to restore registers.
393
  This is done in all places where the restore_regs call has been made.
394
 
395
  This procedure is called by epilogue after installing the body of a
396
  General Procedure. First then we know which registers to restore.
397
 
398
  rmsk is the set of normal regs to restore from AP - st
399
  fmsk is the set of floating point regs to restore from AP - st1
400
 
401
  side effect: current_ins is changed
402
 ************************************************************************/
403
 
404
void restore_regs_output
405
    PROTO_N ( ( rmsk, fmsk, st, st1, uses_link ) )
406
    PROTO_T ( bitpattern rmsk X bitpattern fmsk X long st X long st1 X bool uses_link )
407
{
408
   rrs* p ;
409
   while ( ( p = pop_restore_regs_subsriber () ) ) {
410
      mach_op *op1, *op2 ;
411
      current_ins = p->ins ;
412
 
413
      make_comment("Restore Registers") ;
414
 
415
      /* Restore floating-point registers from the stack */
416
      if ( fmsk ) {
417
         just_ret = 0 ;
418
         op1 = make_indirect ( REG_AP, -st1 ) ;
419
         op2 = make_hex_value ( fmsk ) ;
420
         make_instr ( m_fmovemx, op1, op2, fmsk ) ;
421
      }
422
 
423
      /* Restore registers from the stack */
424
      if ( rmsk ) {
425
         just_ret = 0 ;
426
         if ( must_use_bp ) {
427
            op1 = make_indirect ( REG_AP, -st ) ;
428
         } else {
429
            op1 = make_indirect ( REG_SP, 0 ) ;
430
         }
431
         op2 = make_hex_value ( rmsk ) ;
432
         make_instr ( m_moveml, op1, op2, rmsk ) ;
433
      }
434
 
435
      if ( uses_link ) {
436
         just_ret = 0 ;
437
 
438
         switch ( p->restore_type ){
439
         case ALL:
440
            /* Output unlink instruction */
441
            op1 = make_register ( REG_AP ) ;
442
            make_instr ( m_unlk, op1, null, regmsk ( REG_AP ) ) ;
443
            break;
444
         case NOT_SP:
445
            make_comment("untidy return => Restore A6, but not SP");
446
            op1 = make_indirect ( REG_AP, 0 ) ;
447
            op2 = make_register ( REG_AP ) ;
448
            make_instr ( m_movl, op1, op2, regmsk ( REG_AP ) ) ;
449
            break;
450
         case NOT_A6_OR_SP:
451
            make_comment("exit with long jump => Don't restore A6 or SP");
452
            break;
453
         default:
454
            error("wrong restore type");
455
         }
456
      }
457
   }
458
}
459
 
460
/************************************************************************
461
  CLEANUP_BT
462
 
463
  Cleanup before a tail call is performed. Used by tail_call.
464
  Restore registers and frees callees stack room and return address.
465
  ************************************************************************/
466
 
467
void cleanup_bt
468
    PROTO_N ( ( save_ret, rg ) )
469
    PROTO_T ( bool save_ret X int rg )
470
{
471
   mach_op *op1, *op2 ;
472
 
473
   make_comment ( "Cleanup before tail call ..." );
474
 
475
   /* save callees size in scratch register if needed */
476
   if (cur_proc_has_vcallees) {
477
      make_comment ( "save old callees size" );
478
      op1 = make_indirect ( REG_AP, 8 ) ;
479
      op2 = make_register ( REG_D0 ) ;
480
      make_instr ( m_movl, op1, op2, regmsk ( REG_D0 ) ) ;
481
   }
482
 
483
   /* subscribe on code to restore registers */
484
   restore_regs(ALL) ;
485
 
486
   if ( save_ret ) {
487
      make_comment ( "save return address in register" );
488
      op1 = make_indirect ( REG_SP, 0 ) ;
489
      op2 = make_register ( rg ) ;
490
      make_instr ( m_movl, op1, op2, regmsk ( rg ) ) ;
491
   }
492
 
493
   if ( cur_proc_has_vcallees ) {
494
      make_comment("cleanup variable callees and return address");
495
      op1 = make_register ( REG_D0 ) ;
496
      op2 = make_register ( REG_SP );
497
      make_instr ( m_addl, op1, op2, regmsk ( REG_SP ) );
498
 
499
      op1 = make_value ( 8 ) ;  /* size of callers pointer & ret.addr. */
500
      op2 = make_register ( REG_SP );
501
      make_instr ( m_addl, op1, op2, regmsk ( REG_SP ) );
502
   }
503
   else {
504
      make_comment("cleanup static callees and return address");
505
      op1 = make_value ( cur_proc_callees_size / 8 + 4 ) ;
506
      op2 = make_register ( REG_SP );
507
      make_instr ( m_addl, op1, op2, regmsk ( REG_SP ) );
508
   }
509
   make_comment ( "Cleanup before tail call done" );
510
}
511
 
512
/************************************************************************
513
  CLEANUP
514
 
515
  Restore registers and frees callees stack room, just before return from
516
  a procedure. Used by general_epilogue.
517
  The return address is restored.
518
  ************************************************************************/
519
 
520
void cleanup
521
    PROTO_Z ()
522
{
523
   mach_op *op1, *op2 ;
524
   bool callees_to_clean = cur_proc_has_vcallees || cur_proc_callees_size ;
525
 
526
   make_comment ( "Cleanup before return ..." );
527
 
528
   /* save callees size in scratch register if needed */
529
   if ( cur_proc_has_vcallees ) {
530
      make_comment ( "save callees size" );
531
      op1 = make_indirect ( REG_AP, 8 ) ;
532
      op2 = make_register ( REG_A0 ) ;
533
      make_instr ( m_movl, op1, op2, regmsk ( REG_A0 ) ) ;
534
   }
535
 
536
   /* subscribe on code to restore registers */
537
   restore_regs(ALL) ;
538
 
539
   if ( callees_to_clean ) {
540
      make_comment ( "save return address in register" );
541
      op1 = make_indirect ( REG_SP, 0 ) ;
542
      op2 = make_register ( REG_A1 ) ;
543
      make_instr ( m_movl, op1, op2, regmsk ( REG_A1 ) ) ;
544
 
545
      if ( cur_proc_has_vcallees ) {
546
         make_comment("cleanup variable callees and return address");
547
         op1 = make_register ( REG_A0 ) ;
548
         op2 = make_register ( REG_SP );
549
         make_instr ( m_addl, op1, op2, regmsk ( REG_SP ) );
550
 
551
         op1 = make_value ( 4 ) ; /* size of callers pointer */
552
         op2 = make_register ( REG_SP );
553
         make_instr ( m_addl, op1, op2, regmsk ( REG_SP ) );
554
      }
555
      else {
556
         make_comment("cleanup static callees");
557
         op1 = make_value ( cur_proc_callees_size / 8 ) ;
558
         op2 = make_register ( REG_SP );
559
         make_instr ( m_addl, op1, op2, regmsk ( REG_SP ) );
560
      }
561
 
562
      make_comment("put return address back on the stack");
563
      op1 = make_register ( REG_A1 ) ;
564
      op2 = make_indirect ( REG_SP, 0 ) ;
565
      make_instr ( m_movl, op1, op2, 0 ) ;
566
   }
567
   make_comment ( "Cleanup before return done" );
568
}
569
 
570
/************************************************************************
571
  PUSH_RANGE
572
 
573
  Push memory in the range [start, end] on the stack. (start > end).
574
  (modifies start, end, SP)
575
  ************************************************************************/
576
 
577
void push_range
578
    PROTO_N ( ( start, end ) )
579
    PROTO_T ( int start X int end )
580
{
581
   mach_op *op1, *op2 ;
582
   long lb ;
583
 
584
   make_comment("Push range");
585
 
586
   lb = next_lab () ;
587
   make_label ( lb ) ;
588
 
589
   op1 = make_predec ( start ) ;
590
   op2 = make_dec_sp () ;
591
   make_instr ( m_movw, op1, op2, regmsk ( REG_SP ) ) ;
592
 
593
   op1 = make_register ( start ) ;
594
   op2 = make_register ( end ) ;
595
   make_instr ( m_cmpl, op1, op2, 0 ) ;
596
 
597
   make_jump ( m_bne, lb ) ;
598
}
599
 
600
/************************************************************************
601
  MAKE_CALLEES_SIZE
602
 
603
  Returns an operand specifying the size of the callees for
604
  the current procedure.
605
  ************************************************************************/
606
 
607
mach_op* make_callees_size
608
    PROTO_Z ()
609
{
610
   /* Is it a run time value ? */
611
   if ( cur_proc_has_vcallees )
612
   return make_indirect ( REG_AP, 8 ) ;
613
 
614
   /* or compile time value ? */
615
   return make_value ( cur_proc_callees_size / 8 ) ;
616
}
617
 
618
/************************************************************************
619
  PUSH_SAME_CALLEES
620
 
621
  Used by apply_general_proc to push the same callees
622
  (modifies A0,D0,D1,SP)
623
  ************************************************************************/
624
 
625
void push_same_callees
626
    PROTO_N ( ( var_callees ) )
627
    PROTO_T ( bool var_callees )
628
{
629
   mach_op *op1, *op2 ;
630
 
631
   /* do we have any callees to push ? */
632
   if ( cur_proc_has_vcallees || cur_proc_callees_size ) {
633
      make_comment("Push same callees");
634
      make_comment("end of callees");
635
      op1 = make_register ( REG_AP ) ;
636
      op2 = make_register ( REG_D1 ) ;
637
      make_instr ( m_movl, op1, op2, regmsk ( REG_D1 ) ) ;
638
 
639
      /* add sizeof(ret-addr)+sizeof(preincrement) ?+sizeof(callees size)? */
640
      op1 = make_value( ( cur_proc_has_vcallees )? 12 : 8 ) ;
641
      op2 = make_register ( REG_D1 ) ;
642
      make_instr ( m_addl, op1, op2, regmsk ( REG_D1 ) ) ;
643
 
644
      make_comment("start of callees");
645
      op1 = make_register ( REG_D1 ) ;
646
      op2 = make_register ( REG_A0 ) ;
647
      make_instr ( m_movl, op1, op2, regmsk ( REG_A0 ) ) ;
648
 
649
      op1 = make_callees_size() ;
650
      op2 = make_register ( REG_A0 ) ;
651
      make_instr ( m_addl, op1, op2, regmsk ( REG_A0 ) ) ;
652
 
653
      push_range ( REG_A0, REG_D1 ) ;
654
   }
655
 
656
   if (var_callees) {
657
      make_comment("push size of callees on the stack");
658
      op1 = make_callees_size () ;
659
      op2 = make_dec_sp();
660
      make_instr ( m_movl, op1, op2, regmsk ( REG_SP )) ;
661
 
662
      stack_size -= 32 ;
663
   }
664
}
665
 
666
/************************************************************************
667
  PUSH_DYNAMIC_CALLEES
668
 
669
  Used by apply_general_proc to push dynamic callees
670
  Callees size is available in D1 afterwards.
671
  (modifies A0,D0,D1,SP)
672
  ************************************************************************/
673
 
674
void push_dynamic_callees
675
    PROTO_N ( ( pcallees, stack ) )
676
    PROTO_T ( exp pcallees X ash stack )
677
{
678
   mach_op *op1, *op2 ;
679
   exp ptr = son ( pcallees ) ;
680
   exp sze = bro ( ptr ) ;
681
   exp ident, ident_def ;
682
   bool const_compound_shape = 0 ;
683
   long total_size = 0 ;
684
 
685
   make_comment("Push dynamic callees");
686
 
687
   coder ( A1, stack, ptr ) ;
688
   coder ( D1, stack, sze ) ;
689
 
690
   /* are callees of compond shape ? */
691
   if ( name ( ptr ) == name_tag) {
692
      ident = son ( ptr ) ;
693
      ident_def = son ( ident ) ;
694
      if ( name ( ident_def ) == compound_tag ) {
695
         const_compound_shape = ! ( isvar ( ident ) ) ;
696
      }
697
   }
698
 
699
   if ( const_compound_shape ) {
700
      long value ;
701
      exp pair = son ( ident_def ) ;
702
      if ( pair ) for (;;) {
703
         pair = bro ( pair ) ;
704
         value = no ( pair ) ;
705
 
706
         op1 = make_value ( value ) ;
707
         op2 = make_dec_sp () ;
708
         make_instr ( m_movl, op1, op2, regmsk ( REG_SP ) ) ;
709
         total_size += 4 ;
710
 
711
         if ( last ( pair ) ) break ;
712
         pair = bro ( pair ) ;
713
      }
714
   }
715
   else {
716
      /* Let A0 point to end of callees */
717
      op1 = make_register ( REG_A1 ) ;
718
      op2 = make_register ( REG_A0 ) ;
719
      make_instr ( m_movl, op1, op2, regmsk ( REG_A0 ) ) ;
720
 
721
      op1 = make_register ( REG_D1 ) ;
722
      op2 = make_register ( REG_A0 ) ;
723
      make_instr ( m_addl, op1, op2, regmsk ( REG_A0 ) ) ;
724
 
725
      push_range ( REG_A0, REG_A1 ) ;
726
   }
727
 
728
   if ( call_has_vcallees(pcallees) ) {
729
      make_comment("push size of dynamic callees on the stack");
730
      if ( const_compound_shape ) {
731
         op1 = make_value ( total_size ) ;
732
      }
733
      else {
734
         op1 = make_register ( REG_D1 ) ;
735
      }
736
      op2 = make_dec_sp();
737
      make_instr ( m_movl, op1, op2, regmsk ( REG_SP )) ;
738
 
739
      stack_size -= 32 ;
740
   }
741
   else {
742
       debug_warning("call with dynamic callees requires var_callees PROCPROPS");
743
   }
744
}
745
 
746
/************************************************************************
747
  PUSH_DYNAMIC_CALLEES_BT
748
 
749
  Used by tail_call to push dynamic callees
750
  (modifies A0,A1,D0,D1,SP)
751
  ************************************************************************/
752
 
753
void push_dynamic_callees_bt
754
    PROTO_N ( ( pcallees, stack ) )
755
    PROTO_T ( exp pcallees X ash stack )
756
{
757
   mach_op *op1, *op2 ;
758
 
759
   push_dynamic_callees ( pcallees, stack );
760
 
761
   make_comment("push return address");
762
   op1 = make_indirect ( REG_AP, 4 ) ;
763
   op2 = make_dec_sp();
764
   make_instr ( m_movl, op1, op2, regmsk ( REG_SP ) ) ;
765
 
766
   make_comment("put end of callees, size & return address in A1");
767
   op1 = make_register ( REG_SP ) ;
768
   op2 = make_register ( REG_A1 ) ;
769
   make_instr ( m_movl, op1, op2, regmsk ( REG_A1 ) ) ;
770
 
771
   make_comment("put start of callees in A0");
772
   op1 = make_register ( REG_A1 ) ;
773
   op2 = make_register ( REG_A0 ) ;
774
   make_instr ( m_movl, op1, op2, regmsk ( REG_A0 ) ) ;
775
 
776
   /* add size of callee from D1 */
777
   op1 = make_register ( REG_D1 ) ;
778
   op2 = make_register ( REG_A0 ) ;
779
   make_instr ( m_addl, op1, op2, regmsk ( REG_A0 ) ) ;
780
 
781
   /* add size of return address and size of callees size if needed */
782
   op1 = make_value ((call_has_vcallees(pcallees)) ? 8 : 4) ;
783
   op2 = make_register ( REG_A0 ) ;
784
   make_instr ( m_addl, op1, op2, regmsk ( REG_A0 ) ) ;
785
 
786
   cleanup_bt (0, 0) ;
787
 
788
   push_range ( REG_A0, REG_A1 ) ;
789
}
790
 
791
/************************************************************************
792
  A1_RESULT_POINTER
793
 
794
  For results which do not fit into registers a pointer to
795
  where the result is to be put is passed in A1
796
  ************************************************************************/
797
 
798
void A1_result_pointer
799
    PROTO_N ( ( comp_size, longs, start_stack, dest ) )
800
    PROTO_T ( long comp_size X long longs X long start_stack X where dest )
801
{
802
   if ( comp_size ) {
803
      /* Find the space allocated for unwanted results */
804
      where w ;
805
      w = mnw ( longs / 8 ) ;
806
      make_comment("let A1 point to unwanted compund result") ;
807
      add ( slongsh, SP, w, A1 ) ;
808
   } else {
809
      long doff ;
810
      /* Find the address of where the result is to be put */
811
      tmp_reg_prefer = REG_A1 ;
812
      if ( apply_tag_flag ) {
813
         /* For recursive use of apply_proc or apply_general
814
            we need to be very careful if the result is itself
815
            to be a procedure argument to get the right stack offset. */
816
 
817
         /* push old value */
818
         long ex = extra_stack ;
819
         extra_stack += start_stack ;
820
 
821
         if ( (dest.wh_exp == SP_p.wh_exp) && (dest.wh_is == SP_p.wh_is) ) {
822
            /* Careful! */
823
 
824
            /* push where offset */
825
            doff = dest.wh_off ;
826
 
827
            dest.wh_off = doff + extra_stack ;
828
 
829
            make_comment("let A1 point to compund result used as procedure argument") ;
830
            mova ( dest, A1 ) ;
831
 
832
            /* pop where offset */
833
            dest.wh_off = doff ;
834
 
835
         } else {
836
            /* Easy */
837
            make_comment("let A1 point to compund result from eval. of call par.") ;
838
            mova ( dest, A1 ) ;
839
         }
840
 
841
         /* pop value after call */
842
         extra_stack = ex  ;
843
      }
844
      else {
845
         /* Otherwise (easy) ... */
846
         make_comment("let A1 point to compund result") ;
847
         mova ( dest, A1 ) ;
848
      }
849
   }
850
   /* Make sure we don't reuse A1 accidently */
851
   avoid_tmp_reg ( REG_A1 ) ;
852
   regsinproc |= regmsk ( REG_A1 ) ;
853
}
854
 
855
/************************************************************************
856
  POSTLUDE_HAS_CODE
857
 
858
  Returns true if postlude has code
859
  ************************************************************************/
860
 
861
static bool postlude_has_code
862
    PROTO_N ( ( postlude ) )
863
    PROTO_T ( exp postlude )
864
{
865
   while ( name( postlude ) == ident_tag && name(son( postlude )) == caller_name_tag) {
866
      postlude = bro( son( postlude ) );
867
   }
868
   return ( name( postlude ) != top_tag ) ;
869
}
870
 
871
 
872
/************************************************************************
873
  APPLY_GENERAL_PROC
874
 
875
  Code a General Procedure Call.
876
  ************************************************************************/
877
 
878
void apply_general_proc
879
    PROTO_N ( ( e, dest, stack ) )
880
    PROTO_T ( exp e X where dest X ash stack )
881
{
882
 
883
   /* Procedure applications */
884
   exp t ;
885
   ash st ;
886
   where tmp_dest;
887
   mach_op *op1, *op2 ;
888
   long comp_size = 0 ;
889
   long longs = 0, stkdec ;
890
   long start_stack = stack_dec ;
891
   long callers_size = 0, callees_size = 0 ; /* size of parameters on the stack */
892
   long size_size = 0 ;                      /* size of callees size */
893
   long callees_size_total = 0 ;             /* size of callees and callees size */
894
   long result_size = 0 ;                    /* size of result */
895
 
896
   bool push_result = 0, use_push = 1, reg_res ;
897
   bool has_postlude = 0, has_checkstack = 0, is_untidy = 0 ;
898
 
899
   exp proc, caller_args, pcallees = 0, postlude = 0, callee_args = 0 ;
900
 
901
   make_comment("Apply Proc");
902
 
903
   /* Find the procedure and the arguments */
904
 
905
   tmp_dest = dest ;
906
   proc = son ( e ) ;
907
   caller_args = (!last(proc)) ? bro (proc) : nilexp;
908
 
909
   if ( name(e) == apply_general_tag) {
910
      pcallees     = bro ( caller_args ) ;
911
      postlude    = bro ( pcallees );
912
      callee_args = son ( pcallees ) ;
913
      caller_args = son ( caller_args );
914
 
915
      is_untidy = call_is_untidy(e);
916
      has_checkstack = call_has_checkstack(e);
917
      has_postlude = postlude_has_code( postlude ) ;
918
   }
919
 
920
   /* calculate length of callers and see if we can push them */
921
 
922
   if (! test_push_args(caller_args, &callers_size) ) use_push = 0;
923
 
924
   if ( pcallees ) {
925
      if ( name( pcallees ) == make_callee_list_tag ) {
926
         /* calculate length of callees and see if we can push them */
927
         if (! test_push_args(callee_args, &callees_size) ) use_push = 0;
928
      }
929
      size_size = ( ( call_has_vcallees(pcallees) )?32:0 ) ;
930
      callees_size_total = callees_size + size_size ;
931
   }
932
 
933
   /* total parameter space */
934
   longs = callers_size + callees_size_total ;
935
 
936
   /* Does the result go into a register? */
937
   reg_res = result_in_reg ( sh ( e ) ) ;
938
   if ( !reg_res ) {
939
      if ( eq_where ( dest, zero ) ) {
940
         /* Calculate size of ignored compound result */
941
         comp_size = round ( shape_size ( sh ( e ) ), param_align ) ;
942
      }
943
   }
944
 
945
   /* Find total amount of stack decrease */
946
   stkdec = longs + comp_size ;
947
 
948
   if ( has_checkstack ) {
949
      /* check if there is room for parameters and return address on the stack */
950
      checkalloc_stack( mnw( stkdec / 8 + 4 ), 0);
951
   }
952
 
953
   /* Put arguments onto stack */
954
   if ( use_push ) {
955
      if ( comp_size ) {
956
         /* Make room for unwanted compound result */
957
         dec_stack ( comp_size ) ;
958
         stack_dec -= comp_size ;
959
      }
960
 
961
      if ( caller_args ) {
962
         make_comment("Push callers");
963
         push_args ( zw ( e ), stack, caller_args ) ;
964
      }
965
 
966
      if ( pcallees ) {
967
         if ( name(pcallees) == make_dynamic_callee_tag ) {
968
            push_dynamic_callees ( pcallees, stack ) ;
969
            stack_dec -= callees_size_total ;
970
         }
971
         else if ( name(pcallees) == same_callees_tag ) {
972
            push_same_callees(call_has_vcallees(pcallees)) ;
973
            stack_dec -= callees_size_total ;
974
         }
975
         else {
976
            if ( callee_args ) {
977
               make_comment("Push static callees");
978
               push_args ( zw ( e ), stack, callee_args ) ;
979
            }
980
            if ( call_has_vcallees(pcallees) ) {
981
               make_comment("push size of callees on the stack");
982
               stack_dec -= 32 ;
983
               stack_size -= 32 ;
984
 
985
               op1 = make_value ( callees_size / 8 ) ;
986
               op2 = make_dec_sp();
987
               make_instr ( m_movl, op1, op2, regmsk ( REG_SP )) ;
988
            }
989
         }
990
      }
991
   }
992
   else {
993
      /* Can't just use push => Decrease stack instead */
994
      dec_stack ( stkdec ) ;
995
      stack_dec -= stkdec ;
996
 
997
      if ( caller_args ) {
998
         make_comment("Place callers on the stack");
999
         place_arguments(caller_args, stack, callees_size_total);
1000
      }
1001
      if ( pcallees ) {
1002
         if ( name(pcallees) == make_dynamic_callee_tag ) {
1003
            push_dynamic_callees ( pcallees, stack ) ;
1004
         }
1005
         else if ( name(pcallees) == same_callees_tag ) {
1006
            push_same_callees(call_has_vcallees(pcallees)) ;
1007
         }
1008
         else {
1009
            if ( callee_args ) {
1010
               make_comment("Place static callees on the stack");
1011
               place_arguments(callee_args, stack, size_size);
1012
            }
1013
            if ( call_has_vcallees(pcallees) ) {
1014
               make_comment("push size of callees on the stack");
1015
               op1 = make_value ( callees_size / 8 ) ;
1016
               op2 = make_indirect ( REG_SP, 0 ) ;
1017
               make_instr ( m_movl, op1, op2, regmsk ( REG_SP )) ;
1018
            }
1019
         }
1020
      }
1021
   }
1022
 
1023
   start_stack -= stack_dec ;
1024
 
1025
   if ( !reg_res )
1026
   A1_result_pointer(comp_size, longs, start_stack, dest) ;
1027
 
1028
   /* Output the call instruction */
1029
   callins ( 0, proc ) ;
1030
 
1031
   if ( is_untidy ) {
1032
      stack_dec = 0; /* We can't keep track of it any longer */
1033
      if (need_preserve_stack)
1034
      save_stack ();
1035
   }
1036
   else {
1037
      /* callees has now been cleaned up by called proc. */
1038
      stack_dec += callees_size_total ;
1039
      stack_size += callees_size_total ;
1040
   }
1041
 
1042
   /* can we cleanup callers now ? */
1043
   if ( ! ( has_postlude || is_untidy ) ) {
1044
      /* Clean up of callers and room for ignored compund result. */
1045
      stack_dec += callers_size + comp_size ;
1046
      dec_stack ( - callers_size - comp_size );
1047
   }
1048
 
1049
   /* Move the result into place */
1050
   if ( comp_size ) {
1051
      make_comment("(unwanted compound result)");
1052
   }
1053
   else
1054
   if ( eq_where ( dest, zero ) ) {
1055
      make_comment("(unwanted simple result)");
1056
   }
1057
   else {
1058
      /* ok the result is needed */
1059
      if ( has_postlude ) {
1060
         /* we need to preserve result on stack */
1061
         result_size = rounder (shape_size(sh(e)), param_align);
1062
         dec_stack ( result_size ) ;
1063
         stack_dec -= result_size;
1064
         tmp_dest = SP_p ;
1065
         push_result = 1 ;
1066
      }
1067
      if ( reg_res ) {
1068
         if ( shape_size ( sh ( e ) ) <= 32 ) {
1069
            /* Small register results are in D0 */
1070
            move ( sh ( e ), D0, tmp_dest ) ;
1071
         } else {
1072
            /* Larger register results are in D0 and D1 */
1073
#ifdef SYSV_ABI
1074
            move ( sh ( e ), FP0, tmp_dest ) ;
1075
#else
1076
            move ( sh ( e ), D0_D1, tmp_dest ) ;
1077
            regsinproc |= regmsk ( REG_D1 ) ;
1078
#endif
1079
         }
1080
      } else {
1081
         make_comment("(compound result)");
1082
         if ( has_postlude ) {
1083
            make_comment("save compound result before postlude...") ;
1084
            move ( sh ( e ), dest, tmp_dest ) ;
1085
            make_comment("save compound result before postlude done") ;
1086
         }
1087
 
1088
         /* Compound results should already have been copied to
1089
            the position pointed to by A1 by the called procedure
1090
            and returned by it in D0, so no further action should
1091
            be required by the calling procedure.  Unfortunately
1092
            cc doesn't always get this right for union results. */
1093
#ifdef OLD_SPEC
1094
         if ( cc_conventions && name ( sh ( e ) ) == unhd ) {
1095
            regsinproc |= regmsk ( REG_A0 ) ;
1096
            move ( slongsh, D0, A0 ) ;
1097
            move ( sh ( e ), A0_p, dest ) ;
1098
         }
1099
#endif
1100
      }
1101
   }
1102
 
1103
   if ( has_postlude ) {
1104
      code_postlude(postlude, caller_args, stack, result_size ) ;
1105
 
1106
      /* put return value back in register */
1107
      if ( push_result ) {
1108
         make_comment("restore result after postlude...") ;
1109
         move(sh(e), SP_p, dest);
1110
         make_comment("restore result after postlude done") ;
1111
         dec_stack ( -result_size ) ;
1112
         stack_dec += result_size;
1113
      }
1114
 
1115
      /* Delayed clean up of callers and room for ignored compund result.
1116
         callees are cleaned by the called proc. */
1117
      if ( ! is_untidy ) {
1118
         stack_dec += callers_size + comp_size ;
1119
         dec_stack ( - callers_size - comp_size );
1120
      }
1121
   }
1122
}
1123
 
1124
/************************************************************************
1125
  TEST_PUSH_ARGS
1126
 
1127
  The total stack space requiered by the arguments is returned in args_size.
1128
 
1129
  Returns true if all arguments (args) can be pushed to the stack.
1130
 
1131
  The args_size is also used if false is returned.
1132
 
1133
  ************************************************************************/
1134
 
1135
static bool test_push_args
1136
    PROTO_N ( (args, args_size) )
1137
    PROTO_T ( exp args X ash* args_size )
1138
{
1139
 
1140
   /* See if we can push all the arguments */
1141
 
1142
   bool use_push = 1 ;
1143
   exp arg = args, formal ;
1144
   ash stack = 0 ;
1145
   ast stack_add_res;
1146
 
1147
   while ( arg != nilexp ) {
1148
      formal = ( name ( arg ) == caller_tag) ? son ( arg ) : arg ;
1149
 
1150
      if ( cpd_param ( sh ( formal ) ) ) use_push = 0 ;
1151
      if ((name(sh(formal)) == s64hd) || (name(sh(formal)) == u64hd)) use_push = 0;
1152
      if (! push_arg ( formal ) ) use_push = 0 ;
1153
 
1154
      stack_add_res = add_shape_to_stack ( stack, sh ( formal ) ) ;
1155
      stack = stack_add_res.astash ;
1156
 
1157
      /* information used by code_postlude */
1158
      if ( name ( arg ) == caller_tag)
1159
      no ( arg ) = stack_add_res.astoff + stack_add_res.astadj ;
1160
 
1161
      arg = ( last ( arg ) ? nilexp : bro ( arg ) ) ;
1162
   }
1163
 
1164
   (* args_size) = stack ;
1165
 
1166
 
1167
   return use_push ;
1168
}
1169
 
1170
 
1171
/************************************************************************
1172
  PLACE_ARGUMENTS
1173
 
1174
  Encodes procedure arguments on the stack.
1175
  ************************************************************************/
1176
 
1177
static void place_arguments
1178
    PROTO_N ( (args, stack, start) )
1179
    PROTO_T ( exp args X ash stack X long start )
1180
{
1181
   exp arg = args ;
1182
   ast stack_add_res ;
1183
   where stack_pointer ;
1184
   long adj ;
1185
   long st = start ;
1186
 
1187
   /* Indicate recursive calls */
1188
   apply_tag_flag ++ ;
1189
 
1190
   /* Encode the arguments onto the stack */
1191
   while (arg != nilexp) {
1192
      exp formal = ( name ( arg ) == caller_tag) ? son ( arg ) : arg ;
1193
 
1194
      char nc = name ( sh ( formal ) ) ;
1195
      if ( nc == scharhd || nc == ucharhd ) adj = 24 ;
1196
      else
1197
      if ( nc == swordhd || nc == uwordhd ) adj = 16 ;
1198
      else adj = 0 ;
1199
 
1200
      stack_pointer = mw ( SP_p.wh_exp, st + adj ) ;
1201
      coder ( stack_pointer, stack, formal ) ;
1202
      stack_add_res = add_shape_to_stack ( st, sh ( formal ) ) ;
1203
      st = stack_add_res.astash ;
1204
 
1205
      arg = ( last ( arg ) ? nilexp : bro ( arg ) ) ;
1206
   }
1207
 
1208
   apply_tag_flag -- ;
1209
}
1210
 
1211
/************************************************************************
1212
  PUSH A SET OF PROCEDURE ARGUMENTS
1213
 
1214
  The arguments are given by a bro-list t.
1215
  They are coded in reverse order.
1216
  ************************************************************************/
1217
 
1218
static void push_args
1219
    PROTO_N ( ( w, stack, args ) )
1220
    PROTO_T ( where w X ash stack X exp args )
1221
{
1222
   long sz = shape_size ( sh ( args ) ) ;
1223
   exp formal ;
1224
 
1225
   if ( last ( args ) ) {
1226
      /* Code last argument */
1227
      formal = ( name ( args ) == caller_tag) ? son ( args ) : args ;
1228
      coder ( w, stack, formal ) ;
1229
      stack_dec -= rounder ( sz, param_align ) ;
1230
   } else {
1231
      /* Code the following arguments */
1232
      push_args ( w, stack, bro ( args ) ) ;
1233
      /* And then this one */
1234
      formal = ( name ( args ) == caller_tag) ? son ( args ) : args ;
1235
      coder ( w, stack, formal ) ;
1236
      stack_dec -= rounder ( sz, param_align  ) ;
1237
   }
1238
   return ;
1239
}
1240
 
1241
/************************************************************************
1242
  TAIL_CALL
1243
 
1244
  Code a tail call.
1245
  ************************************************************************/
1246
 
1247
void tail_call
1248
    PROTO_N ( ( e, dest, stack ) )
1249
    PROTO_T ( exp e X where dest X ash stack )
1250
{
1251
   exp proc        = son ( e );
1252
   exp pcallees     = bro( proc );
1253
   exp callee_args = son ( pcallees );
1254
   int longs;
1255
   mach_op *op1, *op2 ;
1256
   long new_callees_size ;
1257
   bool use_push = 1 ;
1258
 
1259
   make_comment("Tail Call");
1260
 
1261
   update_stack() ;
1262
 
1263
   if ( name(pcallees) == make_dynamic_callee_tag ) {
1264
      /* A0 and A1 are used by cleanup. We are just about to make the tail
1265
         call with shape bottom, so they are free */
1266
      push_dynamic_callees_bt ( pcallees, stack ) ;
1267
      jmpins(proc) ;
1268
      return ;
1269
   }
1270
 
1271
   /* same callees ? */
1272
 
1273
   if ( name(pcallees) == same_callees_tag ) {
1274
      restore_regs(ALL) ;
1275
 
1276
      if ( ! cur_proc_has_vcallees  && call_has_vcallees(pcallees) ) {
1277
         make_comment("push size of same static callees and ret.addr. on the stack");
1278
         op1 = make_indirect ( REG_SP, 0 ) ;
1279
         op2 = make_register ( REG_D0 );
1280
         make_instr ( m_movl, op1, op2, regmsk ( REG_SP )) ;
1281
 
1282
         op1 = make_callees_size () ;
1283
         op2 = make_indirect ( REG_SP, 0 ) ;
1284
         make_instr ( m_movl, op1, op2, regmsk ( REG_SP )) ;
1285
 
1286
         op1 = make_register ( REG_D0 );
1287
         op2 = make_dec_sp () ;
1288
         make_instr ( m_movl, op1, op2, regmsk ( REG_SP )) ;
1289
      }
1290
      else if ( cur_proc_has_vcallees  && ! call_has_vcallees(pcallees) ) {
1291
         make_comment("remove size of same static callees from the stack");
1292
         op1 = make_inc_sp () ;
1293
         op2 = make_indirect ( REG_SP, 0 ) ;
1294
         make_instr ( m_movl, op1, op2, regmsk ( REG_SP )) ;
1295
      }
1296
      jmpins(proc) ;
1297
      return ;
1298
   }
1299
 
1300
   /* nothing more than same calleers ? */
1301
 
1302
   if (! (callee_args || cur_proc_has_vcallees || call_has_vcallees(pcallees))) {
1303
      restore_regs(ALL) ;
1304
      jmpins(proc) ;
1305
      return ;
1306
   }
1307
 
1308
   /* no callees ? */
1309
 
1310
   if ( ! callee_args ) {
1311
      make_comment("save return address");
1312
      op1 = make_indirect ( REG_AP, 4 ) ;
1313
      op2 = make_register ( REG_A1 ) ;
1314
      make_instr ( m_movl, op1, op2, regmsk ( REG_D0 ) ) ;
1315
 
1316
      cleanup_bt(0,0);
1317
 
1318
      if ( call_has_vcallees( pcallees ) ) {
1319
         make_comment("push zero size of callees on the stack");
1320
         op1 = make_value ( 0 ) ;
1321
         op2 = make_dec_sp();
1322
         make_instr ( m_movl, op1, op2, regmsk ( REG_SP )) ;
1323
      }
1324
 
1325
      make_comment("push return address back");
1326
      op1 = make_register ( REG_A1 ) ;
1327
      op2 = make_dec_sp();
1328
      make_instr ( m_movl, op1, op2, regmsk ( REG_SP )) ;
1329
 
1330
      jmpins(proc) ;
1331
      return ;
1332
   }
1333
 
1334
   /* new callees ! */
1335
 
1336
   if (! test_push_args(callee_args, &new_callees_size) ) use_push = 0;
1337
 
1338
   if ( use_push ) {
1339
      make_comment("Push callees");
1340
      push_args ( zw ( e ), stack, callee_args ) ;
1341
   }
1342
   else {
1343
      /* Decrease stack */
1344
      dec_stack ( new_callees_size ) ;
1345
      stack_dec -= new_callees_size ;
1346
      place_arguments(callee_args, stack, 0) ;
1347
   }
1348
 
1349
   if ( call_has_vcallees(pcallees) ) {
1350
      make_comment("push size of new callees on the stack");
1351
      op1 = make_value ( new_callees_size / 8 ) ;
1352
      op2 = make_dec_sp();
1353
      make_instr ( m_movl, op1, op2, regmsk ( REG_SP )) ;
1354
   }
1355
 
1356
   make_comment("push return address");
1357
   op1 = make_indirect ( REG_AP, 4 ) ;
1358
   op2 = make_dec_sp();
1359
   make_instr ( m_movl, op1, op2, regmsk ( REG_SP ) ) ;
1360
 
1361
   /*
1362
      Setup source, dest and end mark for push_range
1363
      We will use D1 & A0.
1364
      */
1365
 
1366
   make_comment("save end of new callees and return address");
1367
   op1 = make_register ( REG_SP ) ;
1368
   op2 = make_register ( REG_D1 ) ;
1369
   make_instr ( m_movl, op1, op2, regmsk ( REG_D1 ) ) ;
1370
 
1371
   make_comment("save start of new callees and return address");
1372
   op1 = make_register ( REG_SP ) ;
1373
   op2 = make_register ( REG_A0 ) ;
1374
   make_instr ( m_movl, op1, op2, regmsk ( REG_A0 ) ) ;
1375
 
1376
   /* add sizeof(new calless) sizeof(ret-addr) + ?+sizeof(callees size)? */
1377
   op1 = make_value(new_callees_size/8+4+(call_has_vcallees(pcallees)?4:0));
1378
   op2 = make_register ( REG_A0 ) ;
1379
   make_instr ( m_addl, op1, op2, regmsk ( REG_A0 ) ) ;
1380
 
1381
   cleanup_bt(0,0) ;
1382
 
1383
   make_comment("push the new callees");
1384
   push_range ( REG_A0, REG_D1 ) ;
1385
 
1386
   /* make the jump instruction */
1387
   jmpins(proc) ;
1388
}
1389
 
1390
 
1391
/************************************************************************
1392
  GENERAL PURPOSE PROCEDURE EPILOGUE
1393
 
1394
  The registers used in the procedure and the space used on the stack
1395
  are analysed and used to form the procedure epilogue.
1396
  There is some testing to see if D1, A0, A1 and FP1 can be put to
1397
  better use.
1398
  ************************************************************************/
1399
 
1400
void general_epilogue
1401
    PROTO_N ( ( uses_callers_pointer, has_checkstack ) )
1402
    PROTO_T ( bool uses_callers_pointer X bool has_checkstack )
1403
{
1404
   int r, instruction_id ;
1405
   bitpattern m ;
1406
   long st, st1 ;
1407
   mach_op *op1, *op2 ;
1408
   mach_ins * save_ins_pointer ;
1409
 
1410
   int tmp_d1 = -1, tmp_a0 = -1, tmp_a1 = -1 ;
1411
 
1412
   bitpattern rmsk = regs ( regsinproc & save_msk ) ;
1413
   bitpattern smsk = rmsk ;
1414
   bitpattern cmsk = 0 ;
1415
   bitpattern fmsk = 0 ;
1416
   bitpattern fsmsk = fregs ( regsinproc & save_msk ) ;
1417
   bool d1_free ;
1418
   bool save_d1 = 0 ;
1419
   bool uses_link = 0 ;
1420
 
1421
   make_comment("Epilogue");
1422
 
1423
   /* restore the default floating point rounding mode */
1424
   reset_round_mode();
1425
 
1426
   for ( r = REG_FP7, m = 1 ; r >= REG_FP2 ; r--, m <<= 1 ) {
1427
      if ( regsinproc & regmsk ( r ) ) fmsk |= m ;
1428
   }
1429
 
1430
   /* any calls? */
1431
   if ( no_calls > 0 ) {
1432
      if (uses_callers_pointer) {
1433
         /* Variable number of calles => A5 used as pointer to first caller */
1434
         smsk &= ~regmsk ( REG_A5 ) ;
1435
      }
1436
 
1437
      smsk &= ~bigregs ;
1438
      fsmsk &= ~bigregs ;
1439
   }
1440
 
1441
   make_label ( crt_ret_lab ) ;
1442
 
1443
#if have_diagnostics
1444
   if ( diagnose ) xdb_diag_proc_return () ;
1445
#endif
1446
 
1447
   d1_free = !( regsinproc & regmsk ( REG_D1 ) ) ;
1448
 
1449
   /* Use D1 if not already used */
1450
   if ( d1_free ) {
1451
      m = smsk & dreg_msk ;     /* m = set of D'regs */
1452
      if ( m ) {
1453
         /* Replace a used D-register by D1 */
1454
         r = reg ( m ) ;        /* get the first free register number in the set */
1455
         reg_names [r] = reg_names [ REG_D1 ] ;
1456
         rmsk &= ~regmsk ( r ) ;
1457
         smsk &= ~regmsk ( r ) ;
1458
         cmsk |= regmsk ( r ) ;
1459
         d1_free = 0 ;
1460
      }
1461
   }
1462
 
1463
   /* Use A0 if not already used */
1464
   if ( !( regsinproc & regmsk ( REG_A0 ) ) ) {
1465
      m = smsk & areg_msk ;
1466
      if ( m ) {
1467
         /* Replace a used A-register by A0 */
1468
         r = reg ( m ) ;
1469
         reg_names [r] = reg_names [ REG_A0 ] ;
1470
         rmsk &= ~regmsk ( r ) ;
1471
         smsk &= ~regmsk ( r ) ;
1472
         cmsk |= regmsk ( r ) ;
1473
      } else if ( no_calls == 0 ) {
1474
         m = rmsk & dreg_msk ;
1475
         if ( m ) {
1476
            /* Move a used D-register into A0 */
1477
            tmp_a0 = reg ( m ) ;
1478
            rmsk &= ~regmsk ( tmp_a0 ) ;
1479
            smsk = rmsk ;
1480
            op1 = make_register ( REG_A0 ) ;
1481
            op2 = make_register ( tmp_a0 ) ;
1482
            make_instr ( m_movl, op1, op2, regmsk ( tmp_a0 ) ) ;
1483
            just_ret = 0 ;
1484
         }
1485
      }
1486
   }
1487
 
1488
   /* Use A1 if not already used */
1489
   if ( !( regsinproc & regmsk ( REG_A1 ) ) ) {
1490
      m = smsk & areg_msk ;
1491
      if ( m ) {
1492
         /* Replace a used A-register by A1 */
1493
         r = reg ( m ) ;
1494
         reg_names [r] = reg_names [ REG_A1 ] ;
1495
         rmsk &= ~regmsk ( r ) ;
1496
         smsk &= ~regmsk ( r ) ;
1497
         cmsk |= regmsk ( r ) ;
1498
      } else if ( no_calls == 0 ) {
1499
         m = rmsk & dreg_msk ;
1500
         if ( m ) {
1501
            /* Move a used D-register into A1 */
1502
            tmp_a1 = reg ( m ) ;
1503
            rmsk &= ~regmsk ( tmp_a1 ) ;
1504
            smsk = rmsk ;
1505
            op1 = make_register ( REG_A1 ) ;
1506
            op2 = make_register ( tmp_a1 ) ;
1507
            make_instr ( m_movl, op1, op2, regmsk ( tmp_a1 ) ) ;
1508
            just_ret = 0 ;
1509
         }
1510
      }
1511
   }
1512
 
1513
   /* Use FP1 if not already used */
1514
   if ( fsmsk && !( regsinproc & regmsk ( REG_FP1 ) ) ) {
1515
      for ( r = REG_FP7, m = 1 ; r >= REG_FP2 ; r--, m <<= 1 ) {
1516
         if ( fsmsk & regmsk ( r ) ) {
1517
            reg_names [r] = reg_names [ REG_FP1 ] ;
1518
            fmsk &= ~m ;
1519
            fsmsk &= ~regmsk ( r ) ;
1520
            cmsk |= regmsk ( r ) ;
1521
            r = REG_FP1 ;
1522
         }
1523
      }
1524
   }
1525
 
1526
   if ( d1_free && no_calls == 0 ) {
1527
      m = rmsk & areg_msk ;
1528
      if ( m ) {
1529
         /* Move a used A-register into D1 */
1530
         tmp_d1 = reg ( m ) ;
1531
         rmsk &= ~regmsk ( tmp_d1 ) ;
1532
         op1 = make_register ( REG_D1 ) ;
1533
         op2 = make_register ( tmp_d1 ) ;
1534
         make_instr ( m_movl, op1, op2, regmsk ( tmp_d1 ) ) ;
1535
         just_ret = 0 ;
1536
      }
1537
   }
1538
 
1539
   /* Calculate stack displacements */
1540
   st1 = round ( max_stack, 32 ) / 8 + 16 * bits_in ( fmsk ) ;
1541
   st = st1 + 4 * bits_in ( rmsk ) ;
1542
 
1543
   if ( st1 || st || used_stack || must_use_bp || cur_proc_has_vcallees ) uses_link = 1 ;
1544
 
1545
   cleanup() ;
1546
 
1547
   /* Output return instruction */
1548
   make_instr ( m_rts, null, null, 0 ) ;
1549
 
1550
   /* Output instructions to restore registers */
1551
   save_ins_pointer = current_ins ;
1552
   restore_regs_output(rmsk, fmsk, st, st1, uses_link) ;
1553
 
1554
   /* Go back to the prologue position */
1555
   current_ins = prologue_ins ;
1556
 
1557
   /* Calculate the offset between procedure args and sp */
1558
   ldisp = (uses_link ? st + 4 : st ) ;
1559
 
1560
   /* Calculate env_size ( ldisp + sizeof(return address) + sizeof(params) )*/
1561
   cur_proc_env_size = ldisp + 4 + (cur_proc_callers_size + cur_proc_callees_size)/8 ;
1562
#if 0
1563
   if ( has_checkstack )
1564
   cur_proc_env_size += 1024 ; /* room for exception handler */
1565
#endif
1566
 
1567
   if ( uses_link ) {
1568
      /* Output link instruction */
1569
      /* push AP; AP = SP; sp=sp-st */
1570
      instruction_id = ( -st > 0x7fff ? m_linkl : m_linkw ) ;
1571
      op1 = make_register ( REG_AP ) ;
1572
      op2 = make_value ( -st ) ;
1573
      make_instr ( instruction_id, op1, op2, regmsk ( REG_AP ) | regmsk ( REG_SP ) ) ;
1574
   }
1575
 
1576
   /* Save register in D1 if necessary */
1577
   if ( tmp_d1 >= 0 ) {
1578
      op1 = make_register ( tmp_d1 ) ;
1579
      op2 = make_register ( REG_D1 ) ;
1580
      make_instr ( m_movl, op1, op2, regmsk ( REG_D1 ) ) ;
1581
   }
1582
 
1583
   /* Save register in A0 if necessary */
1584
   if ( tmp_a0 >= 0 ) {
1585
      op1 = make_register ( tmp_a0 ) ;
1586
      op2 = make_register ( REG_A0 ) ;
1587
      make_instr ( m_movl, op1, op2, regmsk ( REG_A0 ) ) ;
1588
   }
1589
 
1590
   /* Save register in A1 if necessary */
1591
   if ( tmp_a1 >= 0 ) {
1592
      op1 = make_register ( tmp_a1 ) ;
1593
      op2 = make_register ( REG_A1 ) ;
1594
      make_instr ( m_movl, op1, op2, regmsk ( REG_A1 ) ) ;
1595
   }
1596
 
1597
   /* Put registers onto the stack */
1598
   if ( rmsk ) {
1599
      op1 = make_hex_value ( rmsk ) ;
1600
      op2 = make_indirect ( REG_SP, 0 ) ;
1601
      make_instr ( m_moveml, op1, op2, 0 ) ;
1602
   }
1603
 
1604
   /* Put floating-point registers onto the stack */
1605
   if ( fmsk ) {
1606
      op1 = make_hex_value ( fmsk ) ;
1607
      op2 = make_indirect ( REG_AP, -st1 ) ;
1608
      make_instr ( m_fmovemx, op1, op2, 0 ) ;
1609
   }
1610
 
1611
   if (uses_callers_pointer){
1612
      make_comment("Variable callees => Get address of first caller");
1613
 
1614
      regsinproc |= regmsk ( REG_A5 ) ;
1615
 
1616
      op1 = make_register ( REG_AP ) ;
1617
      op2 = make_register ( REG_A5 ) ;
1618
      make_instr ( m_movl, op1, op2, regmsk ( REG_A5 ) ) ;
1619
 
1620
      /* A5 = AP + cur_proc_callees_size */
1621
      /* AP points to the first parameter, callees size is before */
1622
      op1 = make_callees_size () ;
1623
      op2 = make_register ( REG_A5 ) ;
1624
      make_instr ( m_addl, op1, op2, regmsk ( REG_A5 ) ) ;
1625
 
1626
      op1 = make_value ( 12 ) ;
1627
      op2 = make_register ( REG_A5 ) ;
1628
      make_instr ( m_addl, op1, op2, regmsk ( REG_A5 ) ) ;
1629
   }
1630
 
1631
 
1632
   /* Return to previous position */
1633
   current_ins = save_ins_pointer ;
1634
 
1635
   callmsk = cmsk ;
1636
   have_cond = 0 ;
1637
   return ;
1638
}
1639
 
1640
/************************************************************************
1641
  CODE_POSTLUDE
1642
  The postlude parameters positions on the stack are setup, and coder
1643
  is called with the postlude body.
1644
 
1645
  ************************************************************************/
1646
static void code_postlude
1647
    PROTO_N ( ( postlude, callers, stack, post_offset ) )
1648
    PROTO_T ( exp postlude X exp callers X ash stack X long post_offset )
1649
{
1650
   make_comment("Postlude ...");
1651
 
1652
   /* mark parameters by use of the values calculated by gcproc */
1653
   while ( name( postlude ) == ident_tag && name(son( postlude )) == caller_name_tag) {
1654
      int n = no(son( postlude ));
1655
      exp a = callers;
1656
      while (n != 0) {
1657
         a = bro(a);
1658
         n--;
1659
      }
1660
      if (name(a) != caller_tag)
1661
      error("Bad postlude") ;
1662
 
1663
      ptno( postlude ) = par3_pl;
1664
      no( postlude ) = no(a) + stack_dec + post_offset ;
1665
 
1666
      postlude = bro( son( postlude ) );
1667
   }
1668
 
1669
   /* code the postlude */
1670
   coder ( zero, stack, postlude ) ;
1671
 
1672
   make_comment("Postlude done");
1673
}
1674
 
1675
/************************************************************************
1676
  Makes code for untidy return
1677
  ************************************************************************/
1678
 
1679
void untidy_return
1680
    PROTO_Z ()
1681
{
1682
   mach_op *op1, *op2 ;
1683
 
1684
   make_comment("untidy return") ;
1685
 
1686
   make_comment("push return address");
1687
   op1 = make_indirect ( REG_AP, 4 ) ;
1688
   op2 = make_dec_sp();
1689
   make_instr ( m_movl, op1, op2, regmsk ( REG_SP ) ) ;
1690
 
1691
   restore_regs(NOT_SP) ;
1692
   /* Output return instruction */
1693
   make_instr ( m_rts, null, null, 0 ) ;
1694
}
1695
 
1696
/************************************************************************
1697
  Make a label with named after the address of e and the value of the
1698
  env offset from e (an ident_tag) to the application pointer.
1699
  ************************************************************************/
1700
 
1701
void make_visible
1702
    PROTO_N ( ( e ) )
1703
    PROTO_T ( exp e )
1704
{
1705
   mach_op *op1, *op2 ;
1706
   long offval ;
1707
 
1708
   /* Does it need to be visible? */
1709
 
1710
   if (! ((isvis(e)) || (isenvoff(e))) ) return ;
1711
 
1712
   setismarked(e) ;
1713
 
1714
   switch ( ptno( e ) ) {
1715
   case var_pl:
1716
      offval = -no(e)/8;
1717
      break;
1718
   case par2_pl:
1719
      offval = no(e)/8;
1720
      break;
1721
   case par3_pl:
1722
   case par_pl:
1723
   default:
1724
      offval = no(e)/8 + 4;
1725
      if(used_stack) offval += 4;
1726
   }
1727
   op1 = make_lab_data ((long)e, 0) ;
1728
   op2 = make_int_data (offval) ;
1729
   make_instr_aux ( m_as_assign, op1, op2, 0, 0 ) ;
1730
}
1731
 
1732
 
1733
/************************************************************************
1734
  If a caller parameter is accessed from a framepointer with variable
1735
  callees we need to transform the pointer in the addptr expression to
1736
  callers pointer.
1737
  ************************************************************************/
1738
 
1739
void fix_addptr
1740
    PROTO_N ( ( addptr ) )
1741
    PROTO_T ( exp addptr )
1742
{
1743
   exp pointer  = son ( addptr ) ;
1744
   exp offset   = bro ( pointer ) ;
1745
   exp E1,E2,E3,E4,E5;
1746
   shape pc_sh;
1747
 
1748
   /* access of a caller param. relative to an environment with variable? */
1749
 
1750
   if (! ((frame_al_of_ptr(sh(pointer)) & al_includes_vcallees) &&
1751
          (frame_al1_of_offset(sh(offset)) & al_includes_caller_args)) ) return;
1752
 
1753
 
1754
   /*
1755
      exchange application pointer with callers pointer:
1756
 
1757
      addptr(pointer, offset) --> addptr(pointer2, offset)
1758
      where pointer2 = reff(addptr( pointer, cont( reff( pointer, 8*8) ) ), 12*8)
1759
 
1760
 
1761
                         addptr
1762
                           |
1763
                           |(son)   bro(son)
1764
                           |-------------|
1765
                     E5  reff(8*8)     offset
1766
                           |(son)
1767
                           |
1768
                     E4  addptr
1769
                           |(son)   bro(son)
1770
                           |----------|
1771
                        pointer  E3  cont
1772
                                      |(son)
1773
                                      |
1774
                                 E2  reff(12*8)
1775
                                      |(son)
1776
                                      |
1777
                                 E1  pointer (copy)
1778
 
1779
 
1780
      */
1781
 
1782
   pc_sh = f_pointer(f_callers_alignment(0));
1783
 
1784
   E1 = copyexp(pointer) ;
1785
   E2 = getexp (pc_sh, 0, 0, E1, 0, 0, 8*8, reff_tag);
1786
   E3 = getexp (pc_sh, 0, 0, E2, 0, 0, 0, cont_tag);
1787
   E4 = getexp (pc_sh, 0, 0, pointer, 0, 0, 0, addptr_tag);
1788
   E5 = getexp (pc_sh, 0, 0, E4, 0, 0, 12*8, reff_tag);
1789
   son(addptr) = E5;
1790
 
1791
   /* Terminate each bro list */
1792
   setfather (E2, E1);
1793
   setfather (E3, E2);
1794
   setfather (E4, E3);
1795
   setfather (E5, E4);
1796
 
1797
   bro (pointer) = E3;
1798
   bro (E5) = offset;
1799
}
1800
 
1801
/************************************************************************
1802
  Transforms an entire exp recursively.
1803
  ************************************************************************/
1804
static void transform
1805
    PROTO_N ( ( e ) )
1806
    PROTO_T ( exp e )
1807
{
1808
   exp s = son(e) ;
1809
 
1810
   /* Transform the childs (if any) */
1811
   if ( s && (name(e) != name_tag) && (name(e) != env_offset_tag) && (name(e) != case_tag) )
1812
   for (; s && s!=e; s=bro(s)) {
1813
      transform(s);
1814
   }
1815
 
1816
   /* Transform this one */
1817
   switch ( name( e ) ) {
1818
   case addptr_tag:
1819
      fix_addptr(e);
1820
      break;
1821
   default:
1822
      /* nothing to do */
1823
      break;
1824
   }
1825
}
1826
 
1827
/************************************************************************
1828
  Scan through the declarations and apply transform
1829
  called from trans.
1830
  ************************************************************************/
1831
void make_transformations
1832
    PROTO_Z ()
1833
{
1834
   dec *d = top_def ;
1835
 
1836
   while ( d ) {
1837
      exp e = son ( d->dec_u.dec_val.dec_exp ) ;
1838
      if ( e ) transform ( e ) ;
1839
      d = d->def_next ;
1840
   }
1841
}
1842
/************************************************************************
1843
  Make a label with:
1844
  value: env_size ( proc )
1845
  name:  L<value of procedure declaration pointer)
1846
  ************************************************************************/
1847
 
1848
void output_env_size
1849
    PROTO_N ( ( proc, envsize ) )
1850
    PROTO_T ( dec* proc X long envsize )
1851
{
1852
   mach_op *op1, *op2 ;
1853
   long offval ;
1854
 
1855
   make_comment("env_size comes here:");
1856
   op1 = make_lab_data ((long)proc, 0) ;
1857
   op2 = make_int_data (envsize) ;
1858
   make_instr_aux ( m_as_assign, op1, op2, 0, 0 ) ;
1859
}
1860