Subversion Repositories tendra.SVN

Rev

Rev 2 | 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
    Copyright (c) 1993 Open Software Foundation, Inc.
33
 
34
 
35
    All Rights Reserved
36
 
37
 
38
    Permission to use, copy, modify, and distribute this software
39
    and its documentation for any purpose and without fee is hereby
40
    granted, provided that the above copyright notice appears in all
41
    copies and that both the copyright notice and this permission
42
    notice appear in supporting documentation.
43
 
44
 
45
    OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING
46
    ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
47
    PARTICULAR PURPOSE.
48
 
49
 
50
    IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
51
    CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
52
    LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
53
    NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
54
    WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
55
*/
56
 
57
/*
58
    		 Crown Copyright (c) 1997
7 7u83 59
 
2 7u83 60
    This TenDRA(r) Computer Program is subject to Copyright
61
    owned by the United Kingdom Secretary of State for Defence
62
    acting through the Defence Evaluation and Research Agency
63
    (DERA).  It is made available to Recipients with a
64
    royalty-free licence for its use, reproduction, transfer
65
    to other parties and amendment for any purpose not excluding
66
    product development provided that any such use et cetera
67
    shall be deemed to be acceptance of the following conditions:-
7 7u83 68
 
2 7u83 69
        (1) Its Recipients shall ensure that this Notice is
70
        reproduced upon any copies or amended versions of it;
7 7u83 71
 
2 7u83 72
        (2) Any amended version of it shall be clearly marked to
73
        show both the nature of and the organisation responsible
74
        for the relevant amendment or amendments;
7 7u83 75
 
2 7u83 76
        (3) Its onward transfer from a recipient to another
77
        party shall be deemed to be that party's acceptance of
78
        these conditions;
7 7u83 79
 
2 7u83 80
        (4) DERA gives no warranty or assurance as to its
81
        quality or suitability for any purpose and DERA accepts
82
        no liability whatsoever in relation to any use to which
83
        it may be put.
84
*/
85
 
86
 
87
 
88
/**********************************************************************
89
$Author: release $
90
$Date: 1998/02/04 15:49:04 $
91
$Revision: 1.2 $
92
$Log: proc.c,v $
93
 * Revision 1.2  1998/02/04  15:49:04  release
94
 * Added OSF copyright message.
95
 *
96
 * Revision 1.1.1.1  1998/01/17  15:55:57  release
97
 * First version to be checked into rolling release.
98
 *
99
 * Revision 1.3  1996/10/11  08:36:59  pwe
100
 * permit unpadded size in dynamic callees
101
 *
102
 * Revision 1.2  1996/10/04  16:03:30  pwe
103
 * add banners and mod for PWE ownership
104
 *
105
**********************************************************************/
106
 
107
 
108
#include "config.h"
109
#include <signal.h>
110
#include "memtdf.h"
111
#include "codegen.h"
112
#include "geninst.h"
113
#include "translat.h"
114
#include "makecode.h"
115
#include "machine.h"
116
#include "flags.h"
117
#include "myassert.h"
118
#include "comment.h"
119
#include "proc.h"
120
#include "stack.h"
121
#include "mem_copy.h"
122
#include "xalloc.h"
123
#include "parameter.h"
124
#include "error.h"
125
#include "dynamic_init.h"
7 7u83 126
space do_callers(int,exp,space);
127
void do_function_call(exp,space);
128
void do_general_function_call(exp,space);
129
makeans move_result_to_dest(exp,space,where,int);
130
void restore_callers(int);
131
void restore_callees(void);
132
static exp find_ote(exp,int);
2 7u83 133
 
134
typedef struct postl_ {exp pl; struct postl_ * outer; } postl_chain;
135
static postl_chain * old_pls;
136
 
7 7u83 137
void update_plc(postl_chain * ch, int ma)
138
{
2 7u83 139
	while (ch != (postl_chain*)0) {
140
	  exp pl= ch->pl;
7 7u83 141
	  while (name(pl) ==ident_tag && name(son(pl)) ==caller_name_tag) {
142
		no(pl) += (ma<<6);
2 7u83 143
		pl = bro(son(pl));
144
	  }
145
	  ch = ch->outer;
146
	}
147
}
148
/*
149
 * Temp location in stack frame callee param save area that can be used
150
 * in short instruction sequence, such as move between float and fixed regs.
151
 * Initialised at procedure prelude, for that procedure.
152
 */
7 7u83 153
baseoff mem_temp(int byte_offset)
2 7u83 154
{
155
  baseoff b;
156
 
157
  b.base = R_SP;
158
  b.offset = -8;
7 7u83 159
 
2 7u83 160
  /*
161
   * Only 2 words of temp allocated
162
   */
163
  ASSERT(byte_offset >= 0 && byte_offset < 8);
164
  b.offset += byte_offset;
165
 
166
  return b;
167
}
168
 
169
 
170
/*
171
 * Implement -p option, by calling mcount with static location address as param.
172
 */
7 7u83 173
static void call_mcount(void)
2 7u83 174
{
175
  static int p_lab = 0;
176
 
177
  p_lab++;
178
 
179
  /* generate .toc entry */
180
  fprintf(as_file, "\t.toc\n");
181
  fprintf(as_file, "T.P.%d:\t.tc\tP.%d[TC],P.%d\n", p_lab, p_lab, p_lab);
182
 
183
  /* mcount counter */
184
  fprintf(as_file, "\t.lcomm\tP.%d,%d\n", p_lab, 4);
185
 
186
  /* reset to default text segment */
187
  fprintf(as_file, "\t.csect\t[PR]\n");
188
 
189
  /* call mcount */
190
  fprintf(as_file, "\t%s\t%d,T.P.%d(%d)\n", get_instruction(i_l), R_FIRST_PARAM, p_lab, R_TOC);
191
#ifdef TDF_MCOUNT
192
  extj_special_ins(i_bl, ".TDF_mcount");
193
#else
194
  extj_special_ins(i_bl, ".mcount");
195
#endif
196
  clear_all();
197
}
198
 
199
 
200
/* is param ident e the last param, or for a proc no params? */
7 7u83 201
bool last_caller_param(exp e)
2 7u83 202
{
203
  exp next;
204
 
205
  ASSERT(IS_A_PROC(e) || (name(e) == ident_tag && isparam(e)));
206
  /* Look at the body of the ident for another param */
207
  if (IS_A_PROC(e))
208
  {
209
    next = son(e);
210
  }
211
  else
212
  {
213
    next = bro(son(e));
214
  }
215
 
216
  /* Skip diagnose_tag which may be before next param */
7 7u83 217
  while (name(next) == diagnose_tag)
2 7u83 218
  {
219
    next = son(next);
220
  }
7 7u83 221
 
222
  if (name(next) == ident_tag
223
      && isparam(next)
2 7u83 224
      && name(son(next))!=formal_callee_tag)
225
  {
226
    return 0;			/* another caller param */
227
  }
228
  else
229
  {
230
    return 1;			/* anything else means e was last param */
231
  }
232
}
233
 
234
 
235
/*
236
 * The following functions generate code for various procedure related
237
 * constructs.  They put the result in dest using t-regs given by sp.
238
 * If non-zero, exitlab is the label of where the code is to continue.
239
 * These functions are called by make_code(), the code selection switch.
240
 */
241
 
242
 
243
/* procedure definition */
7 7u83 244
void make_proc_tag_code(exp e, space sp)
2 7u83 245
{
246
  procrec *pr = &procrecs[no(e)];
247
  long pprops = pr->needsproc.propsneeds;
248
 
249
  clear_all();
7 7u83 250
 
2 7u83 251
  suspected_varargs = 0;
7 7u83 252
 
2 7u83 253
  old_pls = (postl_chain *)0;
7 7u83 254
 
2 7u83 255
  p_current = e;
7 7u83 256
 
2 7u83 257
  initialise_procedure(pr);
258
 
259
  generate_procedure_prologue();
7 7u83 260
 
2 7u83 261
  output_parameters(e);
262
#ifdef DO_DYNAMIC_INITIALISATION
263
  if (proc_is_main(e))
264
  {
265
    call__main();
266
  }
267
#endif
268
  /*
269
   * Profiling info
270
   */
271
  if (do_profile && !p_leaf)
272
  {/* In the event of the procedure having no parameters, mcount would not
273
      have been called,so we call it here */
274
    call_mcount();
275
  }
7 7u83 276
 
2 7u83 277
  /*
278
   * Setup p_result
279
   */
280
  if ((pprops & realresult_bit) != 0)	/* proc has real result */
281
  {
282
    freg frg;
7 7u83 283
 
2 7u83 284
    frg.fr = FR_RESULT;
7 7u83 285
    frg.dble = (pprops & longrealresult_bit)? 1 : 0;
2 7u83 286
    setfregalt(p_result, frg);
287
  }
7 7u83 288
  else if ((pprops & has_result_bit)!= 0)
2 7u83 289
  {
290
    setregalt(p_result, R_RESULT);
291
  }
292
  else
293
  {
294
    setregalt(p_result, R_0);		/* no result */
295
  }
296
  p_return_label = 0;
297
 
298
  init_proc_errors(e);
7 7u83 299
 
2 7u83 300
  make_code(son(e), sp, nowhere, 0);
301
 
302
  output_error_labels();
7 7u83 303
 
2 7u83 304
  /* epilogue created at make_res_tag_code */
305
  return;
306
}
307
 
308
 
309
/* ident/param definition within proc */
7 7u83 310
makeans make_ident_tag_code(exp e, space sp, where dest, int exitlab)
2 7u83 311
{
312
  exp init_exp = son(e);			/* initialisation exp */
313
  int ident_size = shape_size(sh(init_exp));
314
  int ident_align = shape_align(sh(init_exp));
315
  int ident_no = no(e);
316
  where placew;
317
  int r = R_NO_REG;
318
  bool remember = 0;
319
  makeans mka;
7 7u83 320
 
2 7u83 321
  if (props(e) & defer_bit)
322
  {
323
    return make_code(bro(init_exp), sp, dest, exitlab);
324
  }
325
 
326
  /**************Is it an identification of a caller in a postlude?***********/
7 7u83 327
  if (name(init_exp) ==caller_name_tag)
2 7u83 328
  {
329
    exp ote = find_ote(e,no(init_exp));
7 7u83 330
    long caller_disp = no(ote) >>3;
331
 
332
    no(e) = ENCODE_FOR_BOFF(caller_disp , OUTPUT_CALLER_PARAMETER);
2 7u83 333
    set_coded_caller(ote); /* Used in apply_general*/
334
 
7 7u83 335
    ASSERT((props(e) & inanyreg) ==0);
2 7u83 336
    /* Should not have been allocated a register by regalloc or scan */
337
    placew = nowhere;
338
  }
339
  /**************Is it in a fixed point register?***************/
7 7u83 340
  else if (props(e) &inreg_bits)
2 7u83 341
  {
342
    if (ident_no==R_NO_REG)	/* Need to allocate a t-reg */
343
    {
344
      int s = sp.fixed;
345
 
346
      if (props(e) & notparreg)
347
      {
348
	s |= PARAM_TREGS;
349
      }
350
      if (props(e) & notresreg)
351
      {
352
	s |= RMASK(R_RESULT);
353
      }
354
      ident_no = getreg(s);
355
      no(e) = ident_no;
356
    }
357
    setregalt(placew.answhere,ident_no);
358
  }
359
  /**************Is it in a floating point register?***************/
360
  else if (props(e) & infreg_bits)
361
  {
362
    freg frg;
363
    if (ident_no==FR_NO_REG)	/* Need to allocate a t-reg */
364
    {
365
      int s = sp.flt;
7 7u83 366
 
2 7u83 367
      if (props(e) & notparreg)
368
      {
369
	s |= PARAM_FLT_TREGS;
370
      }
371
      if (props(e) & notresreg)
372
      {
373
	s |= RMASK(FR_RESULT);
374
      }
375
      ident_no = getfreg(s);
376
      no(e) = ident_no;
377
    }
378
    frg.fr = ident_no;
379
    frg.dble = (ident_size==64);
380
    setfregalt(placew.answhere, frg);
381
  }
382
  /**************Is it a parameter on the stack?***************/
383
  else if (isparam(e))
384
  {
385
    instore is;
7 7u83 386
 
387
    if (name(init_exp)!= formal_callee_tag)
2 7u83 388
    {
389
      /* Caller parameter living on stack */
7 7u83 390
      long caller_offset = no(init_exp) >>3;
391
      no(e) = ENCODE_FOR_BOFF(caller_offset , INPUT_CALLER_PARAMETER);
2 7u83 392
      if (isvarargparam(e))
393
      {
394
	if (ident_size == 0)
395
	{
396
	  /* void from <varargs.h> */
397
	  ident_size = 32;
398
	  ident_align = 32;
399
	}
400
      }
401
    }
7 7u83 402
    else
2 7u83 403
    {
404
      /* Callee parameter living on stack */
7 7u83 405
      long callee_offset = no(init_exp) >>3;
406
      no(e) = ENCODE_FOR_BOFF(callee_offset , INPUT_CALLEE_PARAMETER);
2 7u83 407
    }
408
    is.b = boff(e);
409
    is.adval = 1;
410
    setinsalt(placew.answhere, is);
411
  }
412
  /**************Allocate on the stack?***************/
413
  else
414
  {
415
    /* It is a local living on the stack */
416
    instore is;
7 7u83 417
 
2 7u83 418
    is.b = boff(e);
419
    is.adval = 1;
420
    setinsalt(placew.answhere, is);
421
    remember = 1;
422
  }
7 7u83 423
 
2 7u83 424
  placew.ashwhere.ashsize  = ident_size;
425
  placew.ashwhere.ashalign = ident_align;
426
 
7 7u83 427
  if (isparam(e))
2 7u83 428
  {
7 7u83 429
    if (name(init_exp) ==formal_callee_tag && (props(e) & inanyreg))
2 7u83 430
    {
431
      instore is;
432
      ans aa;
433
      ASSERT(p_has_fp);
434
      is.b.base = R_FP;
7 7u83 435
      is.b.offset = EXTRA_CALLEE_BYTES + (no(init_exp) >>3);
2 7u83 436
      is.adval = 0;
437
      setinsalt(aa,is);
438
      move(aa,placew,sp.fixed,is_signed(sh(init_exp)));
439
    }
440
  }
441
  else
442
  {
443
    r = code_here(init_exp, sp, placew);
444
  }
7 7u83 445
 
446
  COMMENT1("make_ident_tag_code end_init: no(e) =%d", no(e));
447
 
448
  if (remember && r != R_NO_REG && pt(e)!= nilexp
2 7u83 449
      && keep_eq_size(sh(init_exp), sh(pt(e))))
450
  {
451
    /* It was temporarily in a register, track it to optimise future access */
452
    if (isvar(e))
453
    {
454
      keepcont(pt(e), r);
455
    }
456
    else
457
    {
458
      keepreg(pt(e), r);
459
    }
460
  }
461
 
462
  /* and evaluate the body of the declaration */
463
  mka = make_code(bro(init_exp), guard(placew, sp), dest, exitlab);
464
 
7 7u83 465
  COMMENT1("make_ident_tag_code end_range: no(e) =%d", no(e));
2 7u83 466
 
467
  return mka;
468
}
469
 
470
 
7 7u83 471
/*
2 7u83 472
 * Delivers the procedure result
473
 * with either a normal or an untidy return
474
 */
7 7u83 475
void make_res_tag_code(exp e, space sp)
2 7u83 476
{
477
  where w;
7 7u83 478
  bool untidy = (name(e) ==untidy_return_tag)? 1 : 0;
479
 
2 7u83 480
  w.answhere = p_result;
481
  w.ashwhere = ashof(sh(son(e)));
7 7u83 482
 
2 7u83 483
  code_here(son(e), sp, w);	/* Evaluation of result value */
7 7u83 484
 
485
 
486
  if (p_leaf
2 7u83 487
      && p_sreg_first_save == R_NO_REG
488
      && p_sfreg_first_save == FR_NO_REG)
489
  {
490
    /* Short return sequence so generate everytime */
7 7u83 491
    if (untidy)
2 7u83 492
    {
493
      generate_untidy_procedure_epilogue();
494
    }
495
    else
496
    {
497
      generate_procedure_epilogue();
498
    }
499
  }
500
  else
501
  {
502
    /* jump to the end of proc for long return sequence */
7 7u83 503
    if (p_return_label == 0)
2 7u83 504
    {
505
      /* For diagnostics always produce return code */
506
      if (p_no_of_returns>1 && !diagnose)
507
      {
508
	p_return_label = new_label();
509
	set_label(p_return_label);
510
      }
7 7u83 511
      if (untidy)
2 7u83 512
      {
513
	generate_untidy_procedure_epilogue();
514
      }
515
      else
516
      {
517
	generate_procedure_epilogue();
518
      }
519
    }
520
    else
521
    {
522
      /* jump to the return sequence at first return */
523
      uncond_ins(i_b, p_return_label);
524
    }
525
  }
7 7u83 526
 
527
  clear_all();
2 7u83 528
  return;
529
}
530
 
531
 
532
/* procedure call */
7 7u83 533
makeans make_apply_tag_code(exp e, space sp, where dest, int exitlab)
2 7u83 534
{
535
  exp fn = son(e);		/* Function */
536
  exp par = bro(fn);		/* Parameters list */
537
  space nsp;
538
  nsp=sp;
7 7u83 539
 
2 7u83 540
  /* Structure results are assumed to be transformed */
541
  ASSERT(redo_structfns);
542
  ASSERT(reg_result(sh(e)));
7 7u83 543
 
2 7u83 544
  /* Callers evaluated to usual place relative to sp */
7 7u83 545
  if (!last(fn)) {nsp = do_callers(PROC_PARAM_REGS,par,nsp);}
546
 
2 7u83 547
  /* Function call */
7 7u83 548
 (void) do_function_call(fn,nsp);
549
 
2 7u83 550
  /* Clear all treg associations */
551
  clear_all();
7 7u83 552
 
2 7u83 553
  /* Move the result to correct destination */
554
  return move_result_to_dest(e,sp,dest,exitlab);
555
}
556
 
7 7u83 557
makeans make_apply_general_tag_code(exp e, space sp, where dest, int exitlab)
2 7u83 558
{
559
  exp fn = son(e);
560
  exp cers = bro(fn);
561
  exp cees = bro(cers);
562
  exp pl = bro(cees);
563
  space nsp;
564
  makeans mka;
565
  nsp = sp;
566
 
567
  /* Callers evaluated to usual place relative to sp */
568
  /* Any params with caller_tag are marked with offset */
7 7u83 569
  if (no(cers)!=0) { nsp = do_callers(GENERAL_PROC_PARAM_REGS,son(cers),sp);}
2 7u83 570
 
571
  /* Callees */
7 7u83 572
 (void)make_code(cees,nsp,nowhere,0);
2 7u83 573
 
574
  /* Function */
7 7u83 575
 (void) do_general_function_call(fn,nsp);
2 7u83 576
 
7 7u83 577
 
578
  /* This code works on the assumption that the stack pointer is returned to
579
     where it was initially
2 7u83 580
     i.e no untidy returns from the general_proc */
7 7u83 581
  /* The postlude also works on the assumption that no calls to alloca are
2 7u83 582
     done within it */
583
 
584
  /* clear all register associations */
585
  clear_all();
7 7u83 586
 
2 7u83 587
  /* move the result to the destination */
588
  mka = move_result_to_dest(e,sp,dest,exitlab);
589
 
590
  /* Possibility here that the function is untidy
7 7u83 591
   * In this case we must ensure that there is room to construct
2 7u83 592
   * subsequent parameter lists within this procedure
593
   * The only way to guarantee this is to pull down the stack pointer by
594
   * an extra p_args_and_link_size
595
   */
596
  if (call_is_untidy(cees))
597
  {
598
    rir_ins(i_a,R_SP,-p_args_and_link_size,R_SP);
599
    if (p_has_saved_sp)
600
    {
601
      save_sp_on_stack();
602
    }
603
  }
7 7u83 604
 
2 7u83 605
  if (postlude_has_call(e))
606
  {
607
    exp x = son(cers);
608
    postl_chain p;
7 7u83 609
    for (;x != nilexp;)
2 7u83 610
    {
7 7u83 611
      if (name(x) ==caller_tag)
2 7u83 612
      {
613
	no(x) += p_args_and_link_size<<3;
614
      }
7 7u83 615
      if (last(x))
2 7u83 616
      {
617
	break;
618
      }
619
      x=bro(x);
620
    }
621
    update_plc(old_pls, p_args_and_link_size);
622
    p.pl = pl;
623
    p.outer = old_pls;
624
    old_pls = &p;
625
 
7 7u83 626
    rir_ins(i_a,R_SP,-p_args_and_link_size,R_SP);
627
   (void)make_code(pl,sp,nowhere,0);
2 7u83 628
    rir_ins(i_a,R_SP,p_args_and_link_size,R_SP);
629
 
630
    old_pls = p.outer;
631
    update_plc(old_pls, -p_args_and_link_size);
632
    mka.regmove = R_NO_REG; /* The result reg is corrupted */
633
  }
634
  else
635
  {
7 7u83 636
   (void)make_code(pl,sp,nowhere,0);
2 7u83 637
  }
638
  return mka;
639
}
7 7u83 640
void make_return_to_label_tag_code(exp e, space sp)
2 7u83 641
{
642
  int r = reg_operand(son(e),sp);
643
 
7 7u83 644
  mt_ins(i_mtlr,r);
2 7u83 645
  /* See generate_procedure_epilogue in stack.c for similarity */
646
  if (p_frame_size != 0)
647
  {
648
    if (p_has_fp)
649
    {
650
      /* Use the frame pointer to collapse the frame */
651
      mov_rr_ins(R_FP,R_SP);comment("collapse frame using FP");
652
    }
7 7u83 653
    else if (p_has_back_chain)
2 7u83 654
    {
655
      /* Use the back chain to collapse the stack frame */
656
      baseoff back_chain;
657
      back_chain.base = R_SP;
658
      back_chain.offset = 0;
659
      ld_ro_ins(i_l, back_chain, R_SP);comment("collapse frame using back chain");
660
    }
661
    else
662
    {
663
      /* Use the frame size to collapse the stack frame */
664
      rir_ins(i_a,R_SP,p_frame_size, R_SP);
665
    }
666
  }
667
  /* At this point the stack pointer is collapsed to where the s-regs are
668
     stored */
669
  if (p_has_tp)
670
  {
671
    mov_rr_ins(R_TP,R_TEMP_TP);comment("copy TP to TEMP_TP");
672
    restore_sregs(R_SP,0);
673
    mov_rr_ins(R_TEMP_TP,R_SP);comment("collapse frame using TEMP_TP");
674
  }
675
  else
676
  {
677
    restore_sregs(R_SP,0);
678
  }
679
  /* At this point the stack pointer is in its return position */
680
  /* Now we move r to the link register */
681
 
682
  z_ins(i_br);
683
  return;
684
}
685
 
7 7u83 686
void make_tail_call_tag_code(exp e, space sp)
2 7u83 687
{
688
  exp fn =son(e);
689
  exp cees = bro(fn);
690
  baseoff callee_pointer;
7 7u83 691
  bool direct_call = (name(fn) == name_tag
2 7u83 692
		      && name(son(fn)) == ident_tag
693
		      && (son(son(fn)) == nilexp || IS_A_PROC(son(son(fn)))));
694
  static int identification = 0;
695
  identification++;
696
  fprintf(as_file,"# Begin tail call no %d\n",identification);
7 7u83 697
 
698
 
2 7u83 699
  callee_pointer.base = R_SP;
700
  callee_pointer.offset = 0;
701
  ASSERT(p_has_fp);
702
 
7 7u83 703
 
704
  if (name(cees) ==make_callee_list_tag || name(cees) ==make_dynamic_callee_tag)
2 7u83 705
  {
706
    /* +++ This is a bit of a long winded way to do the tail call for
707
       make_dynamic_callee_tag since the callees are copied twice. */
708
    code_here(cees,sp,nowhere);
709
    if (direct_call==0)
710
    {
711
      /* dynamic call */
712
      int desc_base = reg_operand(fn,sp);
713
      baseoff b;
7 7u83 714
 
2 7u83 715
      b.base = desc_base;
716
      b.offset = 0;
717
      ld_ro_ins(i_l,b,R_TMP0);comment(NIL);
718
      b.base = R_SP;
719
      b.offset = 4;
720
      st_ro_ins(i_st,R_TMP0,b);comment(NIL);
721
    }
722
    restore_link_register();
723
    restore_callers(GENERAL_PROC_PARAM_REGS);
724
    /* Set up R_TEMP_TP and R_TEMP_FP */
725
    if (p_has_tp)
726
    {
727
      mov_rr_ins(R_TP,R_TEMP_TP);comment("copy TP to TEMP_TP");
728
    }
729
    else
730
    {
731
      /* This only happens with a tail call in a normal proc */
732
      mov_rr_ins(R_FP,R_TEMP_TP);comment("copy FP to TEMP_TP");
733
    }
734
    mov_rr_ins(R_FP,R_TEMP_FP);comment("copy FP to TEMP_FP");
735
    restore_sregs(R_TEMP_FP,0);
736
 
737
    /* At this point R_TP is R_TEMP_TP and R_FP is R_TEMP_FP */
7 7u83 738
 
2 7u83 739
    /* Pull down R_TEMP_TP by the size of the callees */
7 7u83 740
    if (name(cees) ==make_callee_list_tag)
2 7u83 741
    {
7 7u83 742
      int size_of_callee_list=ALIGNNEXT((no(cees) >>3) +EXTRA_CALLEE_BYTES , 8);
2 7u83 743
      st_ro_ins(i_st,R_TEMP_TP,callee_pointer);comment(NIL);
7 7u83 744
 
2 7u83 745
      mov_rr_ins(R_SP,R_TEMP_FP);comment(NIL);
7 7u83 746
      rir_ins(i_a,R_TEMP_TP,- (long)(size_of_callee_list),R_TEMP_TP);
2 7u83 747
      reverse_static_memory_copy(R_TEMP_FP,R_TEMP_TP,size_of_callee_list);
748
      mov_rr_ins(R_TEMP_TP,R_SP);comment(NIL);
749
    }
750
    else
751
    {
752
 
753
      ld_ro_ins(i_l,callee_pointer,R_TMP0);comment(NIL);
754
      rrr_ins(i_s,R_TMP0,R_SP,R_TMP0);
755
      /* R_TMP0 should now contain the callee size */
756
      st_ro_ins(i_st,R_TEMP_TP,callee_pointer);comment(NIL);
757
      rrr_ins(i_s,R_TEMP_TP,R_TMP0,R_TEMP_TP);
758
      mov_rr_ins(R_SP,R_TEMP_FP);comment(NIL);
759
      reverse_dynamic_word_memory_copy(R_TEMP_FP,R_TEMP_TP,R_TMP0);
760
      mov_rr_ins(R_TEMP_TP,R_SP);comment(NIL);
761
    }
762
    /* The memory copy does not corrupt R_TEMP_TP or R_TEMP_FP */
763
    /* Finally put the stack pointer at the bottom of the callees */
764
 
765
  }
7 7u83 766
  else if (name(cees) ==same_callees_tag)
2 7u83 767
  {
7 7u83 768
    if (name(p_current) ==general_proc_tag)
2 7u83 769
    {
770
      if (direct_call ==0)
771
      {
772
	/* dynamic call */
773
	int desc_base = reg_operand(fn,sp);
774
	baseoff b;
7 7u83 775
 
2 7u83 776
	b.base = desc_base;
777
	b.offset = 0;
778
	ld_ro_ins(i_l,b,R_TMP0);comment(NIL);
779
	b.base = R_FP;
780
	b.offset = 4;
781
	st_ro_ins(i_st,R_TMP0,b);comment(NIL);
782
      }
783
      restore_link_register();
784
      restore_callees();
785
      restore_callers(GENERAL_PROC_PARAM_REGS);
786
      mov_rr_ins(R_FP,R_TEMP_FP);comment("copy FP to TEMP_FP");
787
      restore_sregs(R_TEMP_FP,0);
788
      mov_rr_ins(R_TEMP_FP,R_SP);comment("collapse frame using TEMP_FP");
789
    }
790
    else
791
    {
792
      /* This should only occur in the initialisation required for dynamic
793
	 initialisation of globals as required for c++ */
794
      ASSERT(p_has_fp);
795
      restore_link_register();
796
      restore_callers(PROC_PARAM_REGS);
797
      mov_rr_ins(R_FP,R_TEMP_FP);comment("copy FP to TEMP_FP");
798
      restore_sregs(R_TEMP_FP,0);
799
      mov_rr_ins(R_TEMP_FP,R_SP);comment("collapse frame using TEMP_FP");
800
    }
801
  }
7 7u83 802
 
2 7u83 803
  /* Function */
804
  if (direct_call)
805
  {
806
    baseoff b;
807
    b = boff(son(fn));
808
    extj_ins(i_b, b);
809
    /* Link register is set up to be the previous stack frames */
810
  }
811
  else
812
  {
813
    /* Link register is set up to be the previous stack frames */
814
    /* Count register is set up to be the target address */
815
    baseoff b;
816
    b.base = R_SP;
817
    b.offset = 4;
818
    ld_ro_ins(i_l,b,R_TMP0);comment(NIL);
819
    mt_ins(i_mtctr,R_TMP0);
820
    z_ins(i_bctr);
821
  }
822
  fprintf(as_file,"# End tail call no %d\n",identification);
823
  return;
824
}
825
 
7 7u83 826
void make_same_callees_tag_code(exp e, space sp)
2 7u83 827
{
828
  int roldsp;
829
  int rfrom;
830
  int rto;
831
  space nsp;
832
  baseoff callee_pointer;
833
  nsp = sp;
834
  callee_pointer.base = R_SP;
835
  callee_pointer.offset = 0;
836
 
7 7u83 837
  ASSERT(name(p_current) ==general_proc_tag);
838
 
2 7u83 839
  rfrom = getreg(nsp.fixed);nsp = guardreg(rfrom,nsp);
840
  rto = getreg(nsp.fixed);nsp = guardreg(rto,nsp);
841
  roldsp = getreg(nsp.fixed);nsp = guardreg(roldsp,nsp);
842
 
843
  restore_callees();
844
  mov_rr_ins(R_FP,rfrom);comment(NIL);
845
  mov_rr_ins(R_SP,roldsp);comment(NIL);
7 7u83 846
 
2 7u83 847
  if (p_has_vcallees)
848
  {  /* We use the difference between R_TP and R_FP to
849
     calculate the size of the vcallees and then pulls the
850
     stack pointer down by this amount and copies the callees
851
     onto the bottom of the stack.
852
     Finally it sets up the callee pointer which points to
853
     the top of the newly constructed callee list */
854
    int rsize;
855
    rsize = getreg(nsp.fixed);nsp = guardreg(rsize,nsp);
856
 
7 7u83 857
 
2 7u83 858
    rrr_ins(i_s,R_TP,R_FP,rsize);
859
    rrr_ins(i_s,R_SP,rsize,R_SP);
860
    mov_rr_ins(R_SP,rto);comment(NIL);
7 7u83 861
 
2 7u83 862
    dynamic_word_memory_copy(rfrom,rto,rsize); /* copy the callees */
863
  }
864
  else
865
  {
866
    /* We can do slightly better since we know the size of the callees */
867
    long csize = ALIGNNEXT(p_callee_size + EXTRA_CALLEE_BYTES,8);
7 7u83 868
 
2 7u83 869
    rir_ins(i_a,R_SP,-csize,R_SP);
870
    mov_rr_ins(R_SP,rto);comment(NIL);
871
    static_memory_copy(rfrom,rto,csize);
872
  }
873
  st_ro_ins(i_st,roldsp,callee_pointer);comment(NIL);
874
  return;
875
}
876
 
877
 
878
 
7 7u83 879
 
880
void make_callee_list_tag_code(exp e, space sp)
2 7u83 881
{
7 7u83 882
  long x;
2 7u83 883
  exp list = son(e);
884
  long disp;
885
  where w;
886
  instore is;
887
  baseoff new_stackpos;
7 7u83 888
 
889
  /* This is an explicit creation of the callee list on the bottom
2 7u83 890
     of the stack. no(e) contains the total size in bits required
7 7u83 891
     to create the callee list.  The EXTRA_CALLEE_BYTES are the
2 7u83 892
     bytes needed to store the extra info on the bottom of the callee
893
     list. At present only 4 bytes are required to hold a pointer which
894
     points to the top of the list.*/
7 7u83 895
 
896
  x = ALIGNNEXT((no(e) >>3) + EXTRA_CALLEE_BYTES  , 8);
2 7u83 897
  new_stackpos.base = R_SP;
898
  new_stackpos.offset = -x;
899
  st_ro_ins(i_stu , R_SP , new_stackpos);comment(NIL);
7 7u83 900
 
2 7u83 901
  disp = EXTRA_CALLEE_BYTES * 8;/* start coding them here */
902
  update_plc(old_pls,x);
7 7u83 903
  if (no(e)!=0)
2 7u83 904
  {
7 7u83 905
    for (;;)
2 7u83 906
    {
907
      ash ap;
7 7u83 908
 
2 7u83 909
      ap = ashof(sh(list));
910
      disp = ALIGNNEXT(disp, ap.ashalign);
911
      is.b.offset = disp>>3;
912
      is.b.base = R_SP;
913
      is.adval = 1;
914
      w.ashwhere = ap;
915
      setinsalt(w.answhere,is);
916
      code_here(list,sp,w);
917
      disp = ALIGNNEXT(disp + ap.ashsize,32);
7 7u83 918
      if (last(list))
2 7u83 919
	break;
920
      list = bro(list);
921
    }
922
  }
923
  update_plc(old_pls,-x);
7 7u83 924
  return;
2 7u83 925
}
926
 
7 7u83 927
void make_dynamic_callee_tag_code(exp e, space sp)
2 7u83 928
{
929
  int rfrom;
930
  int rto;
931
  int rsize;
932
  int rsize_adjusted;
933
  baseoff callee_pointer;
934
  space nsp;
935
 
936
  callee_pointer.base = R_SP;
937
  callee_pointer.offset = 0;
7 7u83 938
 
2 7u83 939
  rfrom = reg_operand(son(e),sp);nsp = guardreg(rfrom,sp);
940
  rsize = reg_operand(bro(son(e)),nsp);nsp = guardreg(rsize,nsp);
941
  if (al2(sh(bro(son(e)))) < 32)
942
  {	/* shouldn't happen for correct ANDF? */
943
    rir_ins(i_a, rsize, 3, rsize);
944
    rir_ins(i_and, rsize, ~3, rsize);
945
  }
7 7u83 946
 
2 7u83 947
  rto = getreg(nsp.fixed);nsp = guardreg(rto,nsp);
948
  rsize_adjusted = getreg(nsp.fixed);nsp = guardreg(rsize_adjusted,nsp);
7 7u83 949
 
950
 
2 7u83 951
  rir_ins(i_a,rsize , EXTRA_CALLEE_BYTES + 7 , rsize_adjusted);
7 7u83 952
  rir_ins(i_and ,rsize_adjusted ,~7 , rsize_adjusted);
2 7u83 953
  /* Pull down the stack frame by rsize_adjusted bytes */
954
  rrr_ins(i_s, R_SP, rsize_adjusted , R_SP);
7 7u83 955
 
2 7u83 956
  rir_ins(i_a, R_SP , EXTRA_CALLEE_BYTES , rto); /* copy to here */
957
  /* copy rsize bytes from rfrom to rto */
958
  /* +++ Can we do this word at a time */
959
 
960
  reverse_dynamic_word_memory_copy(rfrom,rto,rsize);
961
  /* the memory copy preserves rfrom,rto and rsize */
962
  rrr_ins(i_a,rsize_adjusted,R_SP,R_TMP0);
963
  st_ro_ins(i_st,R_TMP0,callee_pointer);comment(NIL);
964
  return;
965
}
966
 
7 7u83 967
space do_callers(int n, exp list, space sp)
2 7u83 968
{
7 7u83 969
  /* Evaluates parameters into fixed registers or float registers or stack
2 7u83 970
   according to the calling convention */
971
  int disp = 0;
972
  int param_reg = R_FIRST_PARAM;
973
  int last_param_reg = R_FIRST_PARAM;
974
  int fr_param_reg = FR_FIRST_PARAM;
975
  space nsp;
976
  int final_param = n + R_FIRST_PARAM - 1;
977
  nsp =sp;
7 7u83 978
 
2 7u83 979
  for (;;)
980
  {
7 7u83 981
    exp par = name(list) ==caller_tag ?son(list):list;
2 7u83 982
    shape par_shape = sh(par);
983
    ash ap;
984
    where w;
985
    ap = ashof(sh(par));
986
    w.ashwhere = ap;
7 7u83 987
 
2 7u83 988
    if (is_floating(name(par_shape)) && param_reg <= final_param)
989
    {
990
      bool dble = is_double_precision(par_shape);
991
      instore is;
992
      freg frg;
7 7u83 993
 
2 7u83 994
      is.b = boff_location(ENCODE_FOR_BOFF((disp>>3),OUTPUT_CALLER_PARAMETER));
995
      is.adval = 1;
7 7u83 996
 
997
      frg.fr= (fr_param_reg<=FR_LAST_PARAM?fr_param_reg:getfreg(nsp.flt));
2 7u83 998
      frg.dble = dble;
999
      setfregalt(w.answhere, frg);
1000
 
1001
      /* The floating parameter is evaluated into a floating parameter t-reg
1002
	 (If we have not filled them all up ) else a spare t-reg */
1003
      code_here(par, nsp, w);
7 7u83 1004
 
2 7u83 1005
      if (frg.fr == fr_param_reg)
1006
      {
1007
	/* The floatind paramter is in a floating parameter t-reg so
1008
	   we must guard it */
1009
	nsp = guardfreg(frg.fr, nsp);
1010
      }
1011
      /* Copy it onto the stack at its correct position */
1012
      stf_ro_ins((dble ? i_stfd : i_stfs), frg.fr, is.b);
1013
 
1014
      /* load it into the fixed parameter t-reg */
1015
      ld_ro_ins(i_l, is.b, param_reg);comment("load float-param from stack into param reg");
1016
      nsp = guardreg(param_reg, nsp);
1017
 
1018
      param_reg++;
1019
      last_param_reg = param_reg;
7 7u83 1020
 
2 7u83 1021
      if (dble && param_reg <= final_param)
1022
      {
1023
	/* Double whose second half can be loaded into fixed param t-reg */
1024
	is.b.offset += 4;
7 7u83 1025
	ld_ro_ins(i_l, is.b, param_reg);comment("it was a double so we load other half");
2 7u83 1026
	nsp = guardreg(param_reg, nsp);
1027
	param_reg++;
1028
	last_param_reg = param_reg;
1029
      }
1030
      fr_param_reg++;
1031
    }
1032
    else if (valregable(sh(par)) && param_reg <= final_param)
1033
    {
1034
      /* valregable ensures that we can evaluate it into a register so we
1035
	 evaluate it into a param_reg*/
1036
      ans ansr;
1037
      setregalt(ansr,param_reg);
1038
      w.answhere = ansr;
1039
      code_here(par,nsp,w);
1040
      nsp = guardreg(param_reg, nsp);
1041
      param_reg++;
1042
      last_param_reg = param_reg;
1043
    }
1044
    else
1045
    {
1046
      /* stack parameter */
1047
      int param_size = ap.ashsize;
1048
      instore is;
1049
      is.adval = 1;
7 7u83 1050
 
2 7u83 1051
      is.b= boff_location(ENCODE_FOR_BOFF((disp >> 3),OUTPUT_CALLER_PARAMETER));
1052
      if (param_size == 0)
1053
      {
1054
	/* from fake <varargs.h> param, nothing to do */
1055
	/* Could be something of shape top which needs evaluating */
1056
	/* Fix for avs suite FlowControl/apply_proc*/
1057
	code_here(par,sp,nowhere);
1058
      }
1059
      else if (is_floating(name(par_shape)))
1060
      {
1061
	freg frg;
1062
	/* store floating parameter on the stack */
7 7u83 1063
	frg.fr= (fr_param_reg<=FR_LAST_PARAM ? fr_param_reg : getfreg(nsp.flt));
1064
 
1065
	frg.dble = name(par_shape)!= shrealhd;
2 7u83 1066
	setfregalt(w.answhere, frg);
1067
	code_here(par, nsp, w);
7 7u83 1068
 
2 7u83 1069
	if (frg.fr == fr_param_reg)
1070
	{
1071
	  nsp = guardfreg(frg.fr, nsp);
1072
	}
7 7u83 1073
 
2 7u83 1074
	stf_ro_ins((frg.dble ? i_stfd : i_stfs), frg.fr, is.b);
7 7u83 1075
 
2 7u83 1076
	fr_param_reg++;
1077
      }
1078
      else if (param_reg <= final_param)
1079
      {
7 7u83 1080
	/* By elimination it must be an aggregrate whose
2 7u83 1081
	   whole or part is to be passed in regs */
1082
	int last_ld_reg;
1083
	int r;
1084
	bool allinreg;
1085
	int dolastoffset;
1086
 
7 7u83 1087
	last_ld_reg = param_reg + (ALIGNNEXT(param_size, 32) /32) - 1;
2 7u83 1088
	if (last_ld_reg > final_param)
1089
	{
1090
	  last_ld_reg = final_param;
1091
	  allinreg = 0;
1092
	}
1093
	else
1094
	{
1095
	  allinreg = 1;
1096
	}
7 7u83 1097
 
2 7u83 1098
	if (allinreg && name(par) == cont_tag)
1099
	{
1100
	  /* a small simple ident, which we can load easily */
1101
	  where w;
1102
	  w = locate(par, nsp, sh(par), 0);
7 7u83 1103
 
2 7u83 1104
	  ASSERT(w.answhere.discrim==notinreg);
7 7u83 1105
 
2 7u83 1106
	  is = insalt(w.answhere);
7 7u83 1107
 
2 7u83 1108
	  COMMENT3("apply: simple aggregate parameter: adval=%d reg=%d off=%d",
1109
		   is.adval, is.b.base, is.b.offset);
1110
	  ASSERT(!is.adval);
1111
	  /* it is already lying about */
1112
	  if (!IS_FIXREG(is.b.base))
1113
	  {
1114
	    /* make addressable */
1115
	    set_ins(is.b, last_ld_reg);
1116
	    is.b.base = last_ld_reg;
1117
	    is.b.offset = 0;
1118
	  }
7 7u83 1119
 
2 7u83 1120
	}
1121
	else
1122
	{
1123
	  /* evaluate aggregate to stack location for param, then move to regs */
1124
	  /* +++ do better for aggregate passed partially in regs */
1125
	  setinsalt(w.answhere, is);
1126
	  /* Get that horrible thing written directly into the stack */
1127
	  code_here(par, nsp, w);
1128
	}
7 7u83 1129
 
2 7u83 1130
	/* now load as many regs as required */
7 7u83 1131
 
2 7u83 1132
	dolastoffset = -1;
7 7u83 1133
 
2 7u83 1134
	for (r = param_reg; r <= last_ld_reg; r++)
1135
	{
1136
	  if (r == is.b.base)
1137
	  {
1138
	    /* clash with base reg, do it later */
1139
	    dolastoffset = is.b.offset;
1140
	  }
1141
	  else
1142
	  {
1143
	    ld_ro_ins(i_l, is.b, r);comment("copy struct param from stack into param regs");
1144
	  }
7 7u83 1145
 
2 7u83 1146
	  nsp = guardreg(r, nsp);
1147
	  is.b.offset += 4;
1148
	}
7 7u83 1149
 
2 7u83 1150
	if (dolastoffset != -1)
1151
	{
1152
	  /* do ld that clashed with base reg */
1153
	  is.b.offset = dolastoffset;
1154
	  ld_ro_ins(i_l, is.b, is.b.base);comment("copy the last part of the structure due to clash of regs");
1155
	}
1156
      }
1157
      else
1158
      {
1159
	setinsalt(w.answhere, is);
1160
	code_here(par, nsp, w);
1161
      }
7 7u83 1162
 
2 7u83 1163
      /* move param_reg on by size */
1164
      param_reg += (param_size + 31) / 32;
1165
    }
7 7u83 1166
 
1167
    if (name(list) ==caller_tag)
2 7u83 1168
    {
7 7u83 1169
      no(list) =disp;
2 7u83 1170
    }
7 7u83 1171
 
2 7u83 1172
    if (last(list))
1173
      break;
1174
    list = bro(list);
7 7u83 1175
 
2 7u83 1176
    disp = ALIGNNEXT(disp + ap.ashsize, 32);
1177
  }				/* end for */
1178
 
1179
  ASSERT(last_param_reg >= R_FIRST_PARAM && last_param_reg <= final_param + 1);
1180
  return nsp;
7 7u83 1181
 
2 7u83 1182
}
7 7u83 1183
void do_function_call(exp fn, space sp)
2 7u83 1184
{
7 7u83 1185
  if (name(fn) == name_tag
2 7u83 1186
      && name(son(fn)) == ident_tag
7 7u83 1187
      && (son(son(fn)) == nilexp || IS_A_PROC(son(son(fn))))
1188
     )
2 7u83 1189
  {
1190
    /* direct call */
1191
    baseoff b;
1192
    b = boff(son(fn));
1193
    extj_ins(i_bl, b);
1194
  }
1195
  else
1196
  {
1197
    /* proc ptr call */
1198
    int desc_base = reg_operand(fn, sp);
1199
    baseoff b;
7 7u83 1200
 
2 7u83 1201
    COMMENT("proc ptr call");
7 7u83 1202
 
2 7u83 1203
    b.base = desc_base;
1204
    b.offset = 0;
1205
    ld_ro_ins(i_l, b, R_TMP0);comment("load function address to R_TMP0");
1206
    mt_ins(i_mtlr, R_TMP0);
1207
    /* +++ use scan() so we can do this in proc prelude */
1208
    b.base = R_SP;
1209
    b.offset = STACK_SAVED_TOC;
1210
    st_ro_ins(i_st, R_TOC, b);comment("save toc pointer for this function");
1211
    b.base = desc_base;
1212
    b.offset = 4;
1213
    ld_ro_ins(i_l, b, R_TOC);comment("load up toc pointer for function");
1214
    /* +++ load env ptr from descriptor */
1215
    z_ins(i_brl);
1216
    b.base = R_SP;
1217
    b.offset = STACK_SAVED_TOC;
1218
    ld_ro_ins(i_l, b, R_TOC);comment("restore toc pointer");
1219
  }
1220
}
7 7u83 1221
void do_general_function_call(exp fn, space sp)
2 7u83 1222
{
7 7u83 1223
  if (name(fn) == name_tag
2 7u83 1224
      && name(son(fn)) == ident_tag
7 7u83 1225
      && (son(son(fn)) == nilexp || IS_A_PROC(son(son(fn))))
1226
     )
2 7u83 1227
  {
1228
    /* direct call */
1229
    baseoff b;
1230
    b = boff(son(fn));
1231
    extj_ins(i_bl, b);
1232
  }
1233
  else
1234
  {
1235
    /* proc ptr call */
1236
    int desc_base = reg_operand(fn, sp);
1237
    baseoff b;
1238
    baseoff saved_toc;
1239
    int r;
7 7u83 1240
 
2 7u83 1241
    COMMENT("proc ptr call");
1242
    r = getreg(guardreg(desc_base,sp).fixed);
7 7u83 1243
 
2 7u83 1244
    b.base = desc_base;
1245
    b.offset = 0;
1246
    ld_ro_ins(i_l, b, R_TMP0);comment("load function address to R_TMP0");
1247
    mt_ins(i_mtlr, R_TMP0);
1248
    saved_toc.base = R_SP;
1249
    saved_toc.offset = 0;
1250
    ld_ro_ins(i_l , saved_toc ,r);comment("load up top of callees");
1251
    saved_toc.base = r;
1252
    saved_toc.offset = STACK_SAVED_TOC;
1253
    st_ro_ins(i_st, R_TOC, saved_toc);comment("save toc pointer");
1254
    b.base = desc_base;
1255
    b.offset = 4;
1256
    ld_ro_ins(i_l, b, R_TOC);comment("load up toc pointer for function");
1257
    /* +++ load env ptr from descriptor */
1258
    z_ins(i_brl);
1259
    /* on return from a general proc, R_SP is returned to top of callees */
1260
    b.base = R_SP;
1261
    b.offset = STACK_SAVED_TOC;
1262
    ld_ro_ins(i_l, b, R_TOC);comment("restore toc pointer");
1263
  }
1264
}
7 7u83 1265
makeans move_result_to_dest(exp e, space sp, where dest, int exitlab)
2 7u83 1266
{
1267
  makeans mka;
1268
  int hda = name(sh(e));	/* Shape of result */
1269
  ans aa;
1270
  mka.regmove=R_NO_REG;
1271
  mka.lab = exitlab;
7 7u83 1272
 
2 7u83 1273
  /* move result of application to destination */
1274
  if (is_floating(hda))
1275
  {
1276
    freg frg;
7 7u83 1277
 
2 7u83 1278
    frg.fr = FR_RESULT;
1279
    frg.dble = (hda != shrealhd);
1280
    setfregalt(aa, frg);
1281
    COMMENT1("apply: is_floating result, dble=%d", frg.dble);
1282
    move(aa, dest, sp.fixed, 1);
1283
  }
1284
  else
1285
  {
1286
    setregalt(aa, R_RESULT);
1287
    mka.regmove = R_RESULT;
1288
    if (dest.answhere.discrim == inreg)
1289
    {
1290
      int r = regalt(dest.answhere);
1291
 
1292
      if (r == R_0)
1293
      {
1294
	COMMENT("apply: void result");
1295
      }
1296
      else if (r != R_RESULT)
1297
      {
1298
	COMMENT("apply: dest inreg, move from R_RESULT");
1299
	move(aa, dest, sp.fixed, 1);
1300
      }
1301
      else
1302
      {
1303
	COMMENT("apply: dest R_RESULT, no move");
1304
      }
7 7u83 1305
    }
2 7u83 1306
    else if (dest.answhere.discrim == insomereg)
1307
    {
1308
      int *dr = someregalt(dest.answhere);
1309
      COMMENT("apply: dest insomereg set to R_RESULT");
7 7u83 1310
      if (*dr != -1)
2 7u83 1311
      {
1312
	fail("somereg been set up");
1313
      }
1314
      *dr = R_RESULT;
1315
    }
1316
    else
1317
    {
1318
      COMMENT("apply: dest not inreg or insomereg");
1319
      move(aa, dest, sp.fixed, 1);
1320
    }
1321
  }
1322
  return mka;
7 7u83 1323
}
1324
void restore_callers(int n)
2 7u83 1325
{
1326
  /* finds all the callers and puts them into there correct register */
1327
  exp bdy = son(p_current);
1328
  int final_param = n + R_FIRST_PARAM - 1;
7 7u83 1329
 
2 7u83 1330
  COMMENT("restore callers");
7 7u83 1331
  while (name(bdy) ==diagnose_tag)
2 7u83 1332
  {
1333
    bdy = son(bdy);
1334
  }
7 7u83 1335
  while (name(bdy) ==ident_tag && isparam(bdy)
1336
	 && name(son(bdy))!=formal_callee_tag)
2 7u83 1337
  {
1338
    exp sbdy = son(bdy);
1339
    baseoff parampos;
7 7u83 1340
    bool ident_in_register = (props(bdy) & inanyreg)!=0;
2 7u83 1341
    bool is_aggregate = IS_AGGREGATE(sh(sbdy));
1342
    int param_reg = props(sbdy);
1343
    int ident_size = shape_size(sh(sbdy));
7 7u83 1344
 
2 7u83 1345
    if (p_has_tp)
1346
    {
1347
      parampos.base = R_TP;
1348
    }
1349
    else
1350
    {
1351
      /* Non general proc */
1352
      parampos.base = R_FP;
1353
    }
7 7u83 1354
 
1355
    parampos.offset = (no(sbdy) >>3) + STACK_ARG_AREA;
1356
 
1357
 
1358
    if (param_reg==0 && ident_in_register)
2 7u83 1359
    {
1360
      /* Parameter which was passed by stack and allocated into
1361
	 a register */
1362
      ASSERT(!is_aggregate);/* +++ allow 32 bit aggregates */
7 7u83 1363
      if (isvar(bdy))
2 7u83 1364
      {
1365
	/* somebody has assigned to it so it must be reloaded */
7 7u83 1366
	if (is_floating(name(sh(sbdy))))
2 7u83 1367
	{
1368
	  bool dble = is_double_precision(sh(sbdy));
1369
	  stf_ro_ins(dble ? i_stfd :i_stfs,no(bdy),parampos);
1370
	}
1371
	else
1372
	{
1373
	  st_ro_ins(i_st,no(bdy),parampos);comment(NIL);
1374
	}
1375
      }
1376
    }
7 7u83 1377
    else if (param_reg != 0 && ! ident_in_register)
2 7u83 1378
    {
1379
      /* should be in reg is in store */
7 7u83 1380
      if (is_aggregate)
2 7u83 1381
      {
1382
	/* this is an aggregate which was passed partially or
1383
	   totally in register
1384
	   */
1385
	int last_st_reg = param_reg + (ALIGNNEXT(ident_size,32)) -1;
1386
	int r;
1387
	baseoff bo;
1388
	bo = boff(bdy);
7 7u83 1389
 
2 7u83 1390
	if (last_st_reg > final_param)
1391
	  last_st_reg = final_param;
7 7u83 1392
 
2 7u83 1393
	for (r = param_reg;r<=last_st_reg;r++)
1394
	{
1395
	  ld_ro_ins(i_l,bo,r);comment("restore struct into caller param regs");
1396
	  bo.offset +=4;
1397
	}
1398
      }
1399
      else if (is_floating(name(sh(sbdy))))
1400
      {
1401
	bool dble = is_double_precision(sh(sbdy));
1402
	ldf_ro_ins(dble ? i_lfd:i_lfs,parampos,param_reg);
1403
      }
1404
      else
1405
      {
1406
	ld_ro_ins(i_l,parampos,param_reg);comment("restore param reg from stack");
1407
      }
1408
    }
1409
    else if (props(sbdy)!=0 && props(sbdy)!=no(bdy))
1410
    {
1411
      /* in wrong register */
7 7u83 1412
      if (is_floating(name(sh(sbdy))))
2 7u83 1413
      {
1414
	rrf_ins(i_fmr,no(bdy),param_reg);
1415
      }
1416
      else
1417
      {
1418
	mov_rr_ins(no(bdy),param_reg);comment("restore param reg from reg");
1419
      }
1420
    }
1421
    bdy = bro(sbdy);
1422
  }
7 7u83 1423
  if (suspected_varargs)
2 7u83 1424
  {
7 7u83 1425
    baseoff v;
2 7u83 1426
    int r;
1427
    if (p_has_tp)
1428
    {
1429
      v.base = R_TP;
1430
    }
1431
    else
1432
    {
1433
      v.base = R_FP;
1434
    }
1435
    v.offset = saved_varargs_offset;
7 7u83 1436
    for (r = saved_varargs_register; r<= final_param ;r++)
2 7u83 1437
    {
1438
      ld_ro_ins(i_l,v,r);comment("restore all params since varargs");
1439
      v.offset += 4;
1440
    }
1441
  }
1442
  return;
1443
}
7 7u83 1444
void restore_callees(void)
2 7u83 1445
{
1446
  /* It is possible that callees are allocated s-regs in which case they must
1447
     be moved back on to their proper place on the stack */
1448
  exp bdy = son(p_current);
1449
  COMMENT("restore callees");
7 7u83 1450
 
1451
  while (name(bdy) ==diagnose_tag)
2 7u83 1452
  {
1453
    bdy = son(bdy);
7 7u83 1454
  }
1455
  while (name(bdy) ==ident_tag && isparam(bdy)
1456
	 && name(son(bdy))!=formal_callee_tag)
2 7u83 1457
  {
1458
    bdy = bro(son(bdy));
1459
  }
7 7u83 1460
  while (name(bdy) ==ident_tag && isparam(bdy))
2 7u83 1461
  {
1462
    exp sbdy = son(bdy);
1463
    baseoff stackpos;
1464
    stackpos.base = R_FP;
7 7u83 1465
    stackpos.offset = EXTRA_CALLEE_BYTES + (no(sbdy) >>3);
2 7u83 1466
    if (props(bdy) & infreg_bits)
1467
    {
1468
      bool dble = is_double_precision(sh(sbdy));
1469
      ASSERT(IS_FLT_SREG(no(bdy)));
1470
      stf_ro_ins(dble?i_stfd:i_stfs,no(bdy),stackpos);
1471
    }
1472
    else if (props(bdy) & inreg_bits)
1473
    {
1474
      ASSERT(IS_SREG(no(bdy)));
1475
      st_ro_ins(i_st,no(bdy),stackpos);comment(NIL);
1476
    }
1477
    bdy = bro(sbdy);
1478
  }
1479
  return;
1480
}
7 7u83 1481
static exp find_ote(exp e, int n)
2 7u83 1482
{
1483
  exp d = father(e);
7 7u83 1484
  while (name(d)!=apply_general_tag)d = father(d);
2 7u83 1485
  d = son(bro(son(d))); /* list otagexps */
7 7u83 1486
  while (n !=0) { d = bro(d); n--;}
1487
  ASSERT(name(d) ==caller_tag);
2 7u83 1488
  return d;
7 7u83 1489
}