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
/*
2
    Copyright (c) 1993 Open Software Foundation, Inc.
3
 
4
 
5
    All Rights Reserved
6
 
7
 
8
    Permission to use, copy, modify, and distribute this software
9
    and its documentation for any purpose and without fee is hereby
10
    granted, provided that the above copyright notice appears in all
11
    copies and that both the copyright notice and this permission
12
    notice appear in supporting documentation.
13
 
14
 
15
    OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING
16
    ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17
    PARTICULAR PURPOSE.
18
 
19
 
20
    IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
21
    CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
22
    LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
23
    NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
24
    WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25
*/
26
 
27
/*
28
    		 Crown Copyright (c) 1997
29
 
30
    This TenDRA(r) Computer Program is subject to Copyright
31
    owned by the United Kingdom Secretary of State for Defence
32
    acting through the Defence Evaluation and Research Agency
33
    (DERA).  It is made available to Recipients with a
34
    royalty-free licence for its use, reproduction, transfer
35
    to other parties and amendment for any purpose not excluding
36
    product development provided that any such use et cetera
37
    shall be deemed to be acceptance of the following conditions:-
38
 
39
        (1) Its Recipients shall ensure that this Notice is
40
        reproduced upon any copies or amended versions of it;
41
 
42
        (2) Any amended version of it shall be clearly marked to
43
        show both the nature of and the organisation responsible
44
        for the relevant amendment or amendments;
45
 
46
        (3) Its onward transfer from a recipient to another
47
        party shall be deemed to be that party's acceptance of
48
        these conditions;
49
 
50
        (4) DERA gives no warranty or assurance as to its
51
        quality or suitability for any purpose and DERA accepts
52
        no liability whatsoever in relation to any use to which
53
        it may be put.
54
*/
55
 
56
 
57
 
58
/**********************************************************************
59
$Author: release $
60
$Date: 1998/02/04 15:48:59 $
61
$Revision: 1.2 $
62
$Log: move.c,v $
63
 * Revision 1.2  1998/02/04  15:48:59  release
64
 * Added OSF copyright message.
65
 *
66
 * Revision 1.1.1.1  1998/01/17  15:55:57  release
67
 * First version to be checked into rolling release.
68
 *
69
 * Revision 1.2  1996/10/04  16:02:44  pwe
70
 * add banners and mod for PWE ownership
71
 *
72
**********************************************************************/
73
 
74
 
75
/**********************************************************************
76
		move.c
77
 
78
	The procedure move produces code to move a value from a to the
79
destination dest. This takes the form of a switch test on the parameter
80
a (type ans) which is either a reg, freg instore or bitad value. In
81
each of the three cases the ans field of the dest is similarly dealt
82
with to determine the necessary instructions for the move. Sizes and
83
alignment are taken from the ash field of the destination.
84
 
85
Delivers register used if 1-word destination is instore; otherwise NOREG.
86
 
87
**********************************************************************/
88
#include "config.h"
89
#include "memtdf.h"
90
#include "codegen.h"
91
#include "geninst.h"
92
 
93
#include "myassert.h"
94
#include "comment.h"
95
#include "proc.h"			/* for mem_temp() */
96
#include "maxminmacs.h"
97
#include "makecode.h"
98
 
99
#include "move.h"
100
 
101
 
102
#define	MAX_STEPS_INLINE_MOVE	12	/* 24 instructions */
103
 
104
 
105
#define NBITMASK(n)		((unsigned long)( (n)==32 ? ~0L : ((1<<(n))-1) ))
106
 
107
 
108
/*
109
 *	ins_sgn_pair[FALSE]		unsigned instruction
110
 *	ins_sgn_pair[TRUE]		signed instruction
111
 */
112
typedef Instruction_P ins_sgn_pair[2 /* FALSE..TRUE */ ];
113
 
114
static /* const */ ins_sgn_pair ld_ins_sz[] =
115
{
116
   /* 0 */	{&INSTRUCTION_I_NIL,    &INSTRUCTION_I_NIL},
117
   /* 8 */	{&INSTRUCTION_i_lbz,    &INSTRUCTION_i_lbz},	/* no signed byte load on POWER,
118
                                               * sign bit must be propagated after load */
119
   /* 16 */	{&INSTRUCTION_i_lhz,    &INSTRUCTION_i_lha},
120
   /* 24 */	{&INSTRUCTION_I_NIL,	&INSTRUCTION_I_NIL},
121
   /* 32 */	{&INSTRUCTION_i_l,	&INSTRUCTION_i_l},
122
   /* 40 */	{&INSTRUCTION_I_NIL,	&INSTRUCTION_I_NIL},
123
   /* 48 */	{&INSTRUCTION_I_NIL,	&INSTRUCTION_I_NIL},
124
   /* 56 */	{&INSTRUCTION_I_NIL,	&INSTRUCTION_I_NIL},
125
   /* 64 */	{&INSTRUCTION_I_NIL,	&INSTRUCTION_I_NIL}
126
};
127
 
128
static /* const */ ins_sgn_pair st_ins_sz[] =
129
{
130
   /* 0 */	{&INSTRUCTION_I_NIL,	&INSTRUCTION_I_NIL},
131
   /* 8 */	{&INSTRUCTION_i_stb,	&INSTRUCTION_i_stb},
132
   /* 16 */	{&INSTRUCTION_i_sth,	&INSTRUCTION_i_sth},
133
   /* 24 */	{&INSTRUCTION_I_NIL,	&INSTRUCTION_I_NIL},
134
   /* 32 */	{&INSTRUCTION_i_st,	&INSTRUCTION_i_st},
135
   /* 40 */	{&INSTRUCTION_I_NIL,	&INSTRUCTION_I_NIL},
136
   /* 48 */	{&INSTRUCTION_I_NIL,	&INSTRUCTION_I_NIL},
137
   /* 56 */	{&INSTRUCTION_I_NIL,	&INSTRUCTION_I_NIL},
138
   /* 64 */	{&INSTRUCTION_I_NIL,	&INSTRUCTION_I_NIL}
139
};
140
 
141
 
142
 
143
/* the ld instruction for object sized bits, and sgned or not */
144
Instruction_P i_ld_sz PROTO_N ((bits,sgned)) PROTO_T (int bits X int sgned)
145
{
146
  ASSERT((bits&7)==0);
147
  ASSERT(bits<=64);
148
  ASSERT(ld_ins_sz[(bits)/8][sgned]!=I_NIL);
149
  return ld_ins_sz[(bits)/8][sgned];
150
}
151
 
152
 
153
/* the st instruction for object sized bits */
154
Instruction_P i_st_sz PROTO_N ((bits)) PROTO_T (int bits)
155
{
156
  ASSERT((bits&7)==0);
157
  ASSERT(bits<=64);
158
  ASSERT(st_ins_sz[(bits)/8][0]!=I_NIL);
159
  return st_ins_sz[(bits)/8][0];
160
}
161
 
162
 
163
/* load address represented by is into reg */
164
void ld_addr PROTO_N ((is,reg)) PROTO_T (instore is X int reg)
165
{
166
  COMMENT1("ld_addr: adval=%d", is.adval);
167
 
168
  if (is.adval)
169
  {
170
    if (IS_FIXREG(is.b.base))
171
    {
172
      rir_ins(i_a, is.b.base, is.b.offset, reg);
173
    }
174
    else
175
    {
176
      set_ins(is.b, reg);
177
    }
178
  }
179
  else
180
  {
181
    ld_ins(i_l, is.b, reg);
182
  }
183
}
184
 
185
 
186
/* get address represented by is into a reg */
187
int addr_reg PROTO_N ((is,regs)) PROTO_T (instore is X long regs)
188
{
189
  int r;
190
 
191
  COMMENT1("addr_reg: adval=%d", is.adval);
192
 
193
  if (is.adval && IS_FIXREG(is.b.base) && is.b.offset == 0)
194
  {
195
    /* simply return base reg */
196
    return is.b.base;
197
  }
198
 
199
  /* otherwise load address into reg */
200
  r = getreg(regs);
201
  ld_addr(is, r);
202
  return r;
203
}
204
 
205
 
206
/* store, sorting out temp reg required */
207
static void store PROTO_N ((st,r,is,regs)) PROTO_T (Instruction_P st X int r X instore is X long regs)
208
{
209
  if (is.adval)		/* is the value an address? */
210
  {
211
    if (IS_FIXREG(is.b.base))
212
    {
213
      st_ro_ins(st, r, is.b);comment(NIL);
214
    }
215
    else if (IMM_SIZE(is.b.offset))
216
    {
217
      if (freeregs(regs) >= 1)
218
      {
219
	/* load base address reg, then store using offset */
220
	int addr_reg = getreg(regs);
221
	baseoff b;
222
 
223
	b.base = is.b.base;
224
	b.offset = 0;
225
	set_ins(b, addr_reg);
226
 
227
	b.base = addr_reg;
228
	b.offset = is.b.offset;
229
	st_ro_ins(st, r, b);comment(NIL);
230
      }
231
      else
232
      {
233
	/* st_ins will do this correctly with R_TMP0 using an extra instruction */
234
	st_ins(st, r, is.b);
235
      }
236
    }
237
    else
238
    {
239
      /* st_ins would need 2 tmp regs which are not available */
240
      baseoff b;
241
 
242
      b.base = getreg(regs);
243
      b.offset = 0;
244
 
245
      /* address+offset into b.base */
246
      set_ins(is.b, b.base);
247
 
248
      /* store r to [b+0] */
249
      st_ro_ins(st, r, b);comment(NIL);
250
    }
251
  }
252
  else
253
  {
254
    baseoff b;
255
 
256
    ASSERT(r!=R_TMP0);
257
#if 0
258
    b.base = R_TMP0;
259
#else 
260
    b.base = getreg(regs);
261
#endif
262
    b.offset = 0;
263
    ld_ins(i_l, is.b, b.base);
264
    st_ro_ins(st, r, b);comment(NIL);
265
  }
266
}
267
 
268
 
269
#if 0
270
/*
271
 * Copy a large inmem object with a loop.
272
 * Compact code, but slower than loopmove2() so no longer used.
273
 */
274
static void loopmove1
275
    PROTO_N ((iss,isd,bytes_per_step,no_steps,ld,st,regs))
276
    PROTO_T (instore iss X instore isd X int bytes_per_step X int no_steps X
277
	     Instruction_P ld X Instruction_P st X long regs)
278
{
279
  /*
280
   * Copy with loop.
281
   *
282
   * Currently generate:
283
   *
284
   *		!%srcptr and %destptr set
285
   *		lil	%cnt,bytes
286
   *	loop:
287
   *		ai.	%cnt,%cnt,-bytes_per_step
288
   *		lx	%tmp,[%srcptr+%cnt]
289
   *		stX	%tmp,[%destptr+%cnt]
290
   *		bnz	loop
291
   *
292
   * +++ unroll, and use two copy regs to seperate ld and st using same reg
293
   * +++ use CR
294
   * +++ use lu/stu
295
   * +++ use lsi/stsi
296
   */
297
 
298
  int srcptr_reg;
299
  int destptr_reg;
300
  int cnt_reg;
301
  int copy_reg;
302
  int loop = new_label();
303
 
304
  COMMENT("loopmove1: loop move");
305
 
306
  /* moves of addresses not handled by this long move */
307
  ASSERT(!iss.adval);
308
 
309
  ASSERT(bytes_per_step <= 4);	/* only using 1 word regs */
310
 
311
  cnt_reg = getreg(regs);
312
  regs |= RMASK(cnt_reg);
313
 
314
  ASSERT(!iss.adval);
315
  iss.adval = 1;	/* we want address of value */
316
  srcptr_reg = addr_reg(iss, regs);
317
  regs |= RMASK(srcptr_reg);
318
 
319
  destptr_reg = addr_reg(isd, regs);
320
  regs |= RMASK(destptr_reg);
321
 
322
  copy_reg = R_TMP0;
323
 
324
  ld_const_ins(bytes_per_step * no_steps, cnt_reg);
325
 
326
  set_label(loop);
327
 
328
  rir_ins(i_a_cr, cnt_reg, -bytes_per_step, cnt_reg);
329
  ld_rr_ins(ld, srcptr_reg, cnt_reg, copy_reg);
330
  st_rr_ins(st, copy_reg, destptr_reg, cnt_reg);
331
 
332
  bc_ins(i_bnz, 0, loop,LIKELY_TO_JUMP);
333
  clear_reg(cnt_reg);
334
}
335
#endif
336
 
337
 
338
/*
339
 * Copy a large inmem object with a loop, using only 2 regs and R_TMP.
340
 */
341
static void loopmove2
342
    PROTO_N ((iss,isd,bytes_per_step,no_steps,ld,st,regs))
343
    PROTO_T (instore iss X instore isd X int bytes_per_step X int no_steps X
344
	     Instruction_P ld X Instruction_P st X long regs)
345
{
346
  /*
347
   * Copy with loop, need 2 regs and R_TMP.
348
   *
349
   * Currently generate:
350
   *
351
   *		!%srcptr and %destptr set in regs that will be changed
352
   *		lil	%tmp,steps
353
   *		mtctr	%tmp
354
   *		ai	%srcptr,%srcptr,-bytes_per_step [if needed]
355
   *		ai	%dstptr,%dstptr,-bytes_per_step [if needed]
356
   *	loop:
357
   *		lXu	%tmp,[%srcptr+bytes_per_step]
358
   *		stXu	%tmp,[%destptr+bytes_per_step]
359
   *		bdn	loop
360
   *
361
   * +++ do extra plain ld/st outside loop to avoid decrements
362
   * +++ use lsi/stsi
363
   */
364
 
365
  Instruction_P ldu, stu;
366
  int srcptr_reg;
367
  int destptr_reg;
368
  baseoff src_bo;
369
  baseoff dest_bo;
370
  int copy_reg;
371
  int loop = new_label();
372
 
373
  COMMENT("loopmove2: loop move");
374
 
375
  ASSERT(bytes_per_step <= 4);	/* only using 1 word regs */
376
 
377
  switch(bytes_per_step)
378
  {
379
  case 1:	ldu = i_lbzu; stu = i_stbu; break;
380
  case 2:	ldu = i_lhzu; stu = i_sthu; break;
381
  case 4:	ldu = i_lu; stu = i_stu; break;
382
  default:	fail("bad bytes_per_step in loopmove");
383
  }
384
 
385
  ld_const_ins(no_steps, R_TMP0);
386
  mt_ins(i_mtctr, R_TMP0);
387
 
388
  /* moves of addresses not handled by this long move */
389
  ASSERT(!iss.adval);
390
  iss.adval = 1;	/* we want address of value */
391
  iss.b.offset -= bytes_per_step;
392
  srcptr_reg = getreg(regs);
393
  regs |= RMASK(srcptr_reg);
394
  ld_addr(iss, srcptr_reg);
395
 
396
  destptr_reg = getreg(regs);
397
  regs |= RMASK(destptr_reg);
398
  if (isd.adval)
399
  {
400
    isd.b.offset -= bytes_per_step;
401
    ld_addr(isd, destptr_reg);
402
  }
403
  else
404
  {
405
    ld_addr(isd, destptr_reg);
406
    rir_ins(i_a, destptr_reg, -bytes_per_step, destptr_reg);
407
  }
408
 
409
  copy_reg = R_TMP0;
410
 
411
  set_label(loop);
412
 
413
  src_bo.base = srcptr_reg;
414
  src_bo.offset = bytes_per_step;
415
  ld_ro_ins(ldu, src_bo, copy_reg);comment(NIL);
416
 
417
  dest_bo.base = destptr_reg;
418
  dest_bo.offset = bytes_per_step;
419
  st_ro_ins(stu, copy_reg, dest_bo);comment(NIL);
420
 
421
  uncond_ins(i_bdn, loop);
422
 
423
  clear_reg(srcptr_reg);
424
  clear_reg(destptr_reg);
425
}
426
 
427
 
428
/*
429
 * Copy a large inmem object with unrolled loop, using 3 regs and R_TMP.
430
 */
431
static void loopmove3
432
    PROTO_N ((iss,isd,bytes_per_step,no_steps,ld,st,regs))
433
    PROTO_T (instore iss X instore isd X int bytes_per_step X int no_steps X
434
	     Instruction_P ld X Instruction_P st X long regs)
435
{
436
  /*
437
   * Copy with unrolled loop, need 3 regs and R_TMP.
438
   *
439
   * Currently generate:
440
   *
441
   *		!%srcptr and %destptr set in regs that will be changed
442
   *		ai	%srcptr,%srcptr,-bytes_per_step [if needed]
443
   *		ai	%dstptr,%dstptr,-bytes_per_step [if needed]
444
   *		lXu	%tmp2,[%srcptr+bytes_per_step]	[if needed]
445
   *		lil	%tmp1,half_steps
446
   *		mtctr	%tmp1
447
   *		stXu	%tmp2,[%destptr+bytes_per_step]	[if needed]
448
   *	loop:
449
   *		lXu	%tmp1,[%srcptr+bytes_per_step]
450
   *		lXu	%tmp2,[%srcptr+bytes_per_step]
451
   *		stXu	%tmp1,[%destptr+bytes_per_step]
452
   *		stXu	%tmp2,[%destptr+bytes_per_step]
453
   *		bdn	loop
454
   *
455
   * +++ use lsi/stsi
456
   */
457
 
458
  int half_no_steps = no_steps/2;
459
  Instruction_P ldu, stu;
460
  int srcptr_reg;
461
  int destptr_reg;
462
  baseoff src_bo;
463
  baseoff dest_bo;
464
  int copy1_reg;
465
  int copy2_reg;
466
  bool decr_destptr_reg;
467
  int loop = new_label();
468
 
469
  COMMENT("loopmove3: loop move");
470
 
471
  ASSERT(bytes_per_step <= 4);	/* only using 1 word regs */
472
  ASSERT(half_no_steps>=1);
473
 
474
  switch(bytes_per_step)
475
  {
476
  case 1:	ldu = i_lbzu; stu = i_stbu; break;
477
  case 2:	ldu = i_lhzu; stu = i_sthu; break;
478
  case 4:	ldu = i_lu; stu = i_stu; break;
479
  default:	fail("bad bytes_per_step in loopmove");
480
  }
481
 
482
  /* moves of addresses not handled by this long move */
483
  ASSERT(!iss.adval);
484
  iss.adval = 1;	/* we want address of value */
485
  iss.b.offset -= bytes_per_step;
486
  srcptr_reg = getreg(regs);
487
  regs |= RMASK(srcptr_reg);
488
  ld_addr(iss, srcptr_reg);
489
 
490
  destptr_reg = getreg(regs);
491
  regs |= RMASK(destptr_reg);
492
  if (isd.adval)
493
  {
494
    if (2*half_no_steps == no_steps)
495
    {
496
      /* no opportunity to avoid decr later */
497
      isd.b.offset -= bytes_per_step;
498
      decr_destptr_reg = 0;
499
    }
500
    else
501
    {
502
      decr_destptr_reg = 1;
503
    }
504
    ld_addr(isd, destptr_reg);
505
  }
506
  else
507
  {
508
    ld_addr(isd, destptr_reg);
509
    decr_destptr_reg = 1;
510
  }
511
 
512
  copy1_reg = R_TMP0;
513
  copy2_reg = getreg(regs);
514
  regs |= RMASK(copy2_reg);
515
 
516
  src_bo.base = srcptr_reg;
517
  src_bo.offset = bytes_per_step;
518
 
519
  dest_bo.base = destptr_reg;
520
  dest_bo.offset = bytes_per_step;
521
 
522
  if (2*half_no_steps < no_steps)
523
    ld_ro_ins(ldu, src_bo, copy2_reg);comment(NIL);
524
 
525
  ld_const_ins(half_no_steps, copy1_reg);
526
  mt_ins(i_mtctr, copy1_reg);
527
 
528
  if (2*half_no_steps < no_steps)
529
  {
530
    if (decr_destptr_reg)
531
    {
532
      /* no need to do the decr, use plain st not stu for first step */
533
      dest_bo.offset -= bytes_per_step;
534
      st_ro_ins(st, copy2_reg, dest_bo);comment(NIL);
535
      dest_bo.offset += bytes_per_step;
536
    }
537
    else
538
    {
539
      st_ro_ins(stu, copy2_reg, dest_bo);comment(NIL);
540
    }
541
  }
542
  else
543
  {
544
    if (decr_destptr_reg)
545
      rir_ins(i_a, destptr_reg, -bytes_per_step, destptr_reg);
546
  }
547
 
548
  set_label(loop);
549
 
550
  ld_ro_ins(ldu, src_bo, copy1_reg);comment(NIL);
551
  ld_ro_ins(ldu, src_bo, copy2_reg);comment(NIL);
552
 
553
  st_ro_ins(stu, copy1_reg, dest_bo);comment(NIL);
554
  st_ro_ins(stu, copy2_reg, dest_bo);comment(NIL);
555
 
556
  uncond_ins(i_bdn, loop);
557
 
558
  clear_reg(srcptr_reg);
559
  clear_reg(destptr_reg);
560
}
561
 
562
 
563
/*
564
 * Memory to memory move.
565
 * If copy of object left in a fixed point reg, return reg, otherwise NOREG.
566
 */
567
static int moveinstore PROTO_N ((iss,isd,size,al,regs,sgned)) PROTO_T (instore iss X instore isd X int size X int al X long regs X bool sgned)
568
{
569
  int bits;
570
  int bits_per_step;
571
  int bytes_per_step;
572
  int no_steps;
573
  Instruction_P st;
574
  Instruction_P ld;
575
  bool unalign = al < 32;
576
 
577
  if (iss.b.base == isd.b.base 
578
      && iss.b.offset == isd.b.offset 
579
      && iss.adval==0 
580
      && isd.adval==1)
581
  {
582
    return NOREG;
583
  }
584
 
585
  /* we are limited by 32 bit regs */
586
  bits_per_step = min(al, 32);
587
 
588
  bytes_per_step = bits_per_step / 8;
589
 
590
  /*
591
   * .ashsize gives precise size in bits, not as rounded up as if
592
   * object is an array element. So we round up bits to convenient
593
   * size, less than alignment.
594
   */
595
  bits = (size + bits_per_step - 1) & ~(bits_per_step - 1);
596
 
597
  no_steps = (bits + bits_per_step - 1) / bits_per_step;
598
 
599
  COMMENT2("moveinstore: mem to mem size,align=%d,%d",
600
	   size, al);
601
  COMMENT4("moveinstore: mem to mem bits=%d align=%d, bytes_per_step=%d no_steps=%d",
602
	   bits, al, bytes_per_step, no_steps);
603
 
604
  if ((al % 8) != 0 || (bits % 8) != 0)
605
  {
606
    fail("moveinstore: bits mem to mem move");
607
    return NOREG;
608
  }
609
 
610
  /*
611
   * we are assuming the following, eg 8 bit object cannot have 32 bit
612
   * alignment
613
   */
614
  ASSERT((bits % al) == 0);
615
 
616
  ASSERT(bytes_per_step > 0 && bytes_per_step <= 4);
617
  ASSERT(no_steps > 0);
618
  ASSERT((no_steps * bytes_per_step) == (bits / 8));
619
 
620
  /* multi step objects by unsigned move, single step special cased below */
621
  ld = i_ld_sz(bits_per_step, 0 /* unsgned */);
622
  st = i_st_sz(bits_per_step);
623
 
624
  /* +++ use fp reg for float, except not passed free fp regs */
625
  /* +++ use actual alignment which may be better than nominal alignment */
626
 
627
  if (no_steps <= MAX_STEPS_INLINE_MOVE)
628
  {
629
    /* move in line */
630
 
631
    if (no_steps == 1)
632
    {
633
      int r = getreg(regs);	/* register for holding values
634
				 * transferred */
635
 
636
      if (iss.adval)
637
      {
638
	/* generate address of source */
639
	if (IS_FIXREG(iss.b.base))
640
	{
641
	  if (iss.b.offset == 0)
642
	  {
643
	    COMMENT("moveinstore: using adval base reg directly");
644
	    r = iss.b.base;
645
	  }
646
	  else
647
	  {
648
	    rir_ins(i_a, iss.b.base, iss.b.offset, r);
649
	  }
650
	}
651
	else
652
	  set_ins(iss.b, r);
653
      }
654
      else
655
      {
656
	/* load source */
657
	ld_ins(i_ld_sz(bits_per_step, sgned), iss.b, r);
658
	if (sgned && bits_per_step == 8)
659
	{
660
	  /* POWER has no load signed byte instruction, so propagate sign */
661
	  adjust_to_size(ulonghd,r,scharhd,r,NO_ERROR_JUMP);
662
	}
663
      }
664
 
665
      store(st, r, isd, regs);
666
 
667
      return (unalign) ? NOREG : r;
668
    }
669
    else
670
    {
671
      /*
672
       * Move using 2 regs ensuring load delay slot not occupied.
673
       */
674
      int ld_steps = no_steps;
675
      int st_steps = no_steps;
676
 
677
      int r1, r2;	/* regs used to copy object */
678
 
679
      COMMENT("moveinstore: inline move");
680
 
681
      ASSERT(ld_steps >= 2);
682
 
683
      /* moves of addresses not handled by this long move */
684
      ASSERT(!iss.adval);
685
 
686
      ASSERT(bits_per_step <= 32);	/* only using byte regs */
687
 
688
      r1 = getreg(regs);
689
      regs |= RMASK(r1);
690
 
691
      r2 = getreg(regs);
692
      regs |= RMASK(r2);
693
 
694
      if (!IS_FIXREG(iss.b.base))
695
      {
696
	/* load source ptr in reg, note R_TMP0 possibly in use for dest */
697
 
698
	int pr = getreg(regs);
699
 
700
	regs |= RMASK(pr);
701
 
702
	COMMENT("moveinstore: load ptr to source");
703
 
704
	set_ins(iss.b, pr);
705
	iss.b.base = pr;
706
	iss.b.offset = 0;
707
      }
708
 
709
      if (!isd.adval)
710
      {
711
	int pr = getreg(regs);
712
 
713
	regs |= RMASK(pr);
714
 
715
	COMMENT("moveinstore: dest !adval");
716
	ld_ins(i_l, isd.b, pr);
717
	isd.b.base = pr;
718
	isd.b.offset = 0;
719
      }
720
      else if (!IS_FIXREG(isd.b.base))
721
      {
722
	int pr = getreg(regs);
723
 
724
	regs |= RMASK(pr);
725
 
726
	COMMENT("moveinstore: load ptr to dest");
727
 
728
	set_ins(isd.b, pr);
729
	isd.b.base = pr;
730
	isd.b.offset = 0;
731
      }
732
 
733
      /* first, pre-load both regs */
734
      ld_ro_ins(ld, iss.b, r1);comment("moveinstore initial store->reg1");
735
      ld_steps--;
736
      iss.b.offset += bytes_per_step;
737
 
738
      ld_ro_ins(ld, iss.b, r2);comment("moveinstore initial store->reg2");
739
      ld_steps--;
740
      iss.b.offset += bytes_per_step;
741
 
742
      /*
743
       * now generate overlapping sequence with ld rX seperated from
744
       * following st rX
745
       *
746
       *	st	r1
747
       *	ld	r1
748
       *	st	r2
749
       *	ld	r2
750
       *
751
       * while there's still data
752
       */
753
      while (st_steps > 0)
754
      {
755
	/* st r1 */
756
	st_ro_ins(st, r1, isd.b);comment("moveinstore reg1->store");
757
	st_steps--;
758
	isd.b.offset += bytes_per_step;
759
 
760
	/* ld r1 */
761
	if (ld_steps > 0)
762
	{
763
	  ld_ro_ins(ld, iss.b, r1);comment("moveinstore store->reg1");
764
	  ld_steps--;
765
	  iss.b.offset += bytes_per_step;
766
	}
767
 
768
	/* st r2 */
769
	if (st_steps > 0)
770
	{
771
	  st_ro_ins(st, r2, isd.b);comment("moveinstore reg2->store");
772
	  st_steps--;
773
	  isd.b.offset += bytes_per_step;
774
	}
775
 
776
	/* ld r2 */
777
	if (ld_steps > 0)
778
	{
779
	  ld_ro_ins(ld, iss.b, r2);comment("moveinstore store->reg2");
780
	  ld_steps--;
781
	  iss.b.offset += bytes_per_step;
782
	}
783
      }
784
 
785
      COMMENT("moveinstore: end inline move");
786
 
787
      ASSERT(ld_steps == 0);
788
 
789
      return NOREG;
790
    }
791
  }			/* inline end */
792
  else
793
  {
794
    /*
795
     * Copy using a loop.
796
     * scan() has only reseved 2 regs (no more available sometimes),
797
     * but if more happen to be free use them for an unrolled loop.
798
     */
799
 
800
    if (freeregs(regs) < 3)
801
      loopmove2(iss, isd, bytes_per_step, no_steps, ld, st, regs);
802
    else
803
      loopmove3(iss, isd, bytes_per_step, no_steps, ld, st, regs);
804
 
805
    return NOREG;
806
  }
807
}
808
 
809
 
810
/*
811
 * Generate code to move 'a' to 'dest'.
812
 * If copy of object left in a fixed point reg, return reg, otherwise NOREG.
813
 * ans a;
814
 * a.discrim is an enumeration
815
 *  it can be inreg
816
 *            infreg
817
 *            notinreg
818
 *            bitad
819
 *            insomereg
820
 *            insomefreg
821
 * a.val is a union anstu
822
 *            this can be int regans;			 register number 
823
 *                        freg fregans;
824
 *                        instore instoreans;
825
 *                        instore bitadans;
826
 *                        somefreg somefregans;	      not yet used
827
 *                        somereg someregans;
828
 * dest.answhere is an ans
829
 * dest.ashwhere is an ash
830
 *               dest.ashwhere.ashsize is the minimum size of bits in a shape
831
 *               dest.ashwhere.ashalign is the required alignment in bits
832
 *
833
 * regs is a long with the bits masked out for which registers you cannot use
834
 */
835
int move PROTO_N ((a,dest,regs,sgned)) PROTO_T (ans a X where dest X long regs X bool sgned)
836
{
837
  int al = dest.ashwhere.ashalign; /* al is the alignment of the destination */
838
  int size = dest.ashwhere.ashsize;
839
  if(size==0)
840
    return NOREG;
841
 
842
  FULLCOMMENT4("move: %d -> %d, dest ashsize,ashalign = %d,%d",
843
	       a.discrim, dest.answhere.discrim, dest.ashwhere.ashsize, dest.ashwhere.ashalign);
844
#if 0
845
  ASSERT((dest.answhere.discrim == inreg && dest.answhere.val.regans == R_0)	/* nowhere */
846
	 || dest.ashwhere.ashsize > 0);	/* unitialised dest.ashwhere */
847
#endif
848
 
849
start:
850
 
851
  /* Switch on the source */
852
  switch (a.discrim)
853
  {
854
   case insomereg:
855
   case insomefreg:
856
    {
857
      fail("move: source somereg not specified");
858
      return NOREG;
859
    }
860
   case inreg:
861
    /* source in fixed point register */
862
    {
863
      int r = regalt(a);
864
 
865
      switch (dest.answhere.discrim)
866
      {
867
      case inreg:
868
	/* source and dest in fixed register */
869
	{
870
	  int rd = regalt(dest.answhere);
871
 
872
	  if (rd != R_0 /* nowhere */ && rd != r)
873
	  {
874
	    /* move reg r to reg rd */
875
	    mov_rr_ins(r, rd);comment(NIL);
876
	  }
877
	  return NOREG;
878
	}			/* end inreg dest */
879
 
880
       case insomereg:
881
	/* source and dest in fixed register */
882
	{
883
	  int *sr = someregalt(dest.answhere);
884
 
885
	  if (*sr != -1)
886
	  {
887
	    fail("move: somereg already set");
888
	  }
889
	  *sr = r;
890
	  return NOREG;
891
	}
892
 
893
       case infreg:
894
	/* dest in floating point register */
895
	{
896
	  freg fr;
897
 
898
	  fr = fregalt(dest.answhere);
899
	  st_ro_ins(i_st, r, mem_temp(0));comment(NIL);
900
	  if (fr.dble)
901
	  {
902
	    st_ro_ins(i_st, r + 1, mem_temp(4));comment(NIL);
903
	    ldf_ro_ins(i_lfd, mem_temp(0), fr.fr);
904
	  }
905
	  else
906
	  {
907
	    ldf_ro_ins(i_lfs, mem_temp(0), fr.fr);
908
	  }
909
	  return NOREG;
910
	}			/* end infreg dest */
911
 
912
       case notinreg:
913
	/* dest instore */
914
	{
915
	  Instruction_P st;
916
 
917
	  if(al==1)
918
	  {
919
	    if(size<=8)
920
	    {
921
	      al = 8;
922
	    }
923
	    else if(size<=16)
924
	    {
925
	      al = 16;
926
	    }
927
	    else
928
	    {
929
	      al = 32;
930
	    }
931
	  }
932
	  st = i_st_sz(al);
933
	  store(st, r, insalt(dest.answhere), regs);
934
 
935
	  return r;
936
	}			/* end notinreg dest */
937
       default:
938
	break;
939
      }				/* end switch dest */
940
    }				/* end inreg a */
941
 
942
   case infreg:
943
    /* source in floating point register */
944
    {
945
      freg fr;
946
 
947
      fr = fregalt(a);
948
      switch (dest.answhere.discrim)
949
      {
950
      case inreg:
951
	/* dest in fixed point register */
952
	{
953
	  int rd = regalt(dest.answhere);
954
 
955
	  if (rd != 0)
956
	  {
957
	    /* store and load to move to fixed reg */
958
	    if (fr.dble)
959
	    {
960
	      stf_ins(i_stfd, fr.fr, mem_temp(0));
961
	      ld_ro_ins(i_l, mem_temp(0), rd);comment(NIL);
962
	      ld_ro_ins(i_l, mem_temp(4), rd + 1);comment(NIL);
963
	    }
964
	    else
965
	    {
966
	      stf_ins(i_stfs, fr.fr, mem_temp(0));
967
	      ld_ro_ins(i_l, mem_temp(0), rd);comment(NIL);
968
	    }
969
	  }
970
	  return NOREG;
971
	}			/* end inreg dest */
972
 
973
      case insomereg:
974
	/* source in flt reg, can choose dest reg */
975
	{
976
	  int * sr = someregalt(dest.answhere);
977
 
978
	  if (*sr != -1)
979
	  {
980
	    fail("move: somereg already set");
981
	  }
982
	  *sr = getreg(regs);
983
	  setregalt(dest.answhere, *sr);
984
	  goto start;
985
	}
986
 
987
      case infreg:
988
	/* source and dest in floating point registers */
989
	{
990
	  freg frd;	frd = fregalt(dest.answhere);	/* for XLC compiler bug */
991
 
992
	  if (fr.fr != frd.fr)
993
	    rrf_ins(i_fmr, fr.fr, frd.fr);
994
 
995
	  return NOREG;
996
	}			/* end infreg dest */
997
 
998
      case notinreg:
999
	/* source in flt reg, dest instore */
1000
	{
1001
	  Instruction_P st = (fr.dble) ? i_stfd : i_stfs;
1002
	  instore is;
1003
 
1004
	  if ((dest.ashwhere.ashsize == 64 && !fr.dble) ||
1005
	      (dest.ashwhere.ashsize == 32 && fr.dble))
1006
	  {
1007
	    fail("inconsistent sizes");
1008
	  }
1009
	  is = insalt(dest.answhere);
1010
	  if (is.adval)
1011
	  {
1012
	    if (fr.dble)
1013
	    {
1014
	      stf_ins(i_stfd, fr.fr, is.b);
1015
	    }
1016
	    else
1017
	    {
1018
	      stf_ins(i_stfs, fr.fr, is.b);
1019
	    }
1020
	  }
1021
	  else
1022
	  {
1023
	    baseoff b;
1024
 
1025
	    b.base = getreg(regs);
1026
	    b.offset = 0;
1027
	    ld_ro_ins(i_l, is.b, b.base);comment(NIL);
1028
	    stf_ro_ins(st, fr.fr, b);
1029
	  };
1030
 
1031
	  return ((fr.dble) ? -(fr.fr + 32) : (fr.fr + 32));
1032
	}			/* end notinreg dest */
1033
       default:
1034
	break;
1035
      }				/* end switch dest */
1036
    }				/* end infreg a */
1037
 
1038
  case notinreg:
1039
    /* source instore */
1040
    {
1041
      /* get into register and repeat */
1042
      instore iss;
1043
 
1044
      iss = insalt(a);
1045
 
1046
      if (iss.adval)
1047
	COMMENT("move: source adval");
1048
 
1049
      if (iss.adval && iss.b.offset == 0 && IS_FIXREG(iss.b.base))
1050
      {
1051
	/* address of [base_reg+0] is base_reg */
1052
	setregalt(a, iss.b.base);
1053
	goto start;
1054
      }
1055
      if(al==1)
1056
      {
1057
	if(size<=8)
1058
	{
1059
	  al = 8;
1060
	}
1061
	else if(size<=16)
1062
	{
1063
	  al = 16;
1064
	}
1065
	else
1066
	{
1067
	  al = 32;
1068
	}
1069
      }
1070
 
1071
      /* determine which load instruction to use from al and adval */
1072
 
1073
      switch (dest.answhere.discrim)
1074
      {
1075
      case insomereg:
1076
	/* source instore, can choose dest reg */
1077
	{
1078
	  int *sr = someregalt(dest.answhere);
1079
 
1080
	  if (*sr != -1)
1081
	  {
1082
	    fail("move: somereg already set");
1083
	  }
1084
	  *sr = getreg(regs);
1085
	  setregalt(dest.answhere, *sr);
1086
	  /* and continue to next case */
1087
	}
1088
 
1089
      case inreg:
1090
	/* source instore, dest in fixpnt reg */
1091
	{
1092
	  int rd = regalt(dest.answhere);
1093
 
1094
	  if (rd != R_0 /* nowhere */ )
1095
	  {
1096
	    if (iss.adval)
1097
	    {
1098
	      /* generate address of source */
1099
	      if (IS_FIXREG(iss.b.base))
1100
		rir_ins(i_a, iss.b.base, iss.b.offset, rd);
1101
	      else
1102
		set_ins(iss.b, rd);
1103
	    }
1104
	    else
1105
	    {
1106
	      /* load source */
1107
	      ld_ins(i_ld_sz(al, sgned), iss.b, rd);
1108
	      if (sgned && al == 8)
1109
	      {
1110
		/* POWER has no load signed byte instruction, so propagate sign */
1111
		/* +++ word aligned byte: load word then sra 24 */
1112
		/* +++ halfword aligned byte: lha then sra 8 */
1113
		/* +++ 0 offset: lsi 1 byte then sra 24 */
1114
		adjust_to_size(ulonghd,rd,scharhd,rd,NO_ERROR_JUMP);
1115
	      }
1116
	    }
1117
	  }
1118
	  return NOREG;
1119
	}			/* end inreg dest */
1120
 
1121
      case infreg:
1122
	/* source instore, dest in floating pnt reg */
1123
	{
1124
	  freg frd;
1125
 
1126
	  frd = fregalt(dest.answhere);
1127
 
1128
	  ASSERT(!iss.adval);	/* address should never go to float reg */
1129
	  /* allow doubles not to be double aligned in mem, ie param */
1130
	  if (frd.dble)
1131
	  {
1132
	    ldf_ins(i_lfd, iss.b, frd.fr);
1133
	  }
1134
	  else
1135
	  {
1136
	    ldf_ins(i_lfs, iss.b, frd.fr);
1137
	  }
1138
	  return NOREG;
1139
	}			/* end infreg dest */
1140
      case notinreg:
1141
	/* source and dest instore */
1142
	{
1143
	  return moveinstore(iss, insalt(dest.answhere), dest.ashwhere.ashsize, al, regs, sgned);
1144
	}
1145
       default:
1146
	break;
1147
      }				/* end switch dest */
1148
    }				/* end notinreg a */
1149
  }				/* end switch a */
1150
 
1151
  fail("move not handled");
1152
  return NOREG;
1153
  /*NOTREACHED*/
1154
}
1155