Subversion Repositories tendra.SVN

Rev

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

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