OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.2.2/] [gcc/] [config/] [pdp11/] [pdp11.c] - Blame information for rev 242

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 38 julius
/* Subroutines for gcc2 for pdp11.
2
   Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2004, 2005,
3
   2007 Free Software Foundation, Inc.
4
   Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).
5
 
6
This file is part of GCC.
7
 
8
GCC is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 3, or (at your option)
11
any later version.
12
 
13
GCC is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
GNU General Public License for more details.
17
 
18
You should have received a copy of the GNU General Public License
19
along with GCC; see the file COPYING3.  If not see
20
<http://www.gnu.org/licenses/>.  */
21
 
22
#include "config.h"
23
#include "system.h"
24
#include "coretypes.h"
25
#include "tm.h"
26
#include "rtl.h"
27
#include "regs.h"
28
#include "hard-reg-set.h"
29
#include "real.h"
30
#include "insn-config.h"
31
#include "conditions.h"
32
#include "function.h"
33
#include "output.h"
34
#include "insn-attr.h"
35
#include "flags.h"
36
#include "recog.h"
37
#include "tree.h"
38
#include "expr.h"
39
#include "toplev.h"
40
#include "tm_p.h"
41
#include "target.h"
42
#include "target-def.h"
43
 
44
/*
45
#define FPU_REG_P(X)    ((X)>=8 && (X)<14)
46
#define CPU_REG_P(X)    ((X)>=0 && (X)<8)
47
*/
48
 
49
/* this is the current value returned by the macro FIRST_PARM_OFFSET
50
   defined in tm.h */
51
int current_first_parm_offset;
52
 
53
/* Routines to encode/decode pdp11 floats */
54
static void encode_pdp11_f (const struct real_format *fmt,
55
                            long *, const REAL_VALUE_TYPE *);
56
static void decode_pdp11_f (const struct real_format *,
57
                            REAL_VALUE_TYPE *, const long *);
58
static void encode_pdp11_d (const struct real_format *fmt,
59
                            long *, const REAL_VALUE_TYPE *);
60
static void decode_pdp11_d (const struct real_format *,
61
                            REAL_VALUE_TYPE *, const long *);
62
 
63
/* These two are taken from the corresponding vax descriptors
64
   in real.c, changing only the encode/decode routine pointers.  */
65
const struct real_format pdp11_f_format =
66
  {
67
    encode_pdp11_f,
68
    decode_pdp11_f,
69
    2,
70
    1,
71
    24,
72
    24,
73
    -127,
74
    127,
75
    15,
76
    false,
77
    false,
78
    false,
79
    false,
80
    false
81
  };
82
 
83
const struct real_format pdp11_d_format =
84
  {
85
    encode_pdp11_d,
86
    decode_pdp11_d,
87
    2,
88
    1,
89
    56,
90
    56,
91
    -127,
92
    127,
93
    15,
94
    false,
95
    false,
96
    false,
97
    false,
98
    false
99
  };
100
 
101
static void
102
encode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
103
                const REAL_VALUE_TYPE *r)
104
{
105
  (*vax_f_format.encode) (fmt, buf, r);
106
  buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
107
}
108
 
109
static void
110
decode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED,
111
                REAL_VALUE_TYPE *r, const long *buf)
112
{
113
  long tbuf;
114
  tbuf = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
115
  (*vax_f_format.decode) (fmt, r, &tbuf);
116
}
117
 
118
static void
119
encode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
120
                const REAL_VALUE_TYPE *r)
121
{
122
  (*vax_d_format.encode) (fmt, buf, r);
123
  buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
124
  buf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16);
125
}
126
 
127
static void
128
decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
129
                REAL_VALUE_TYPE *r, const long *buf)
130
{
131
  long tbuf[2];
132
  tbuf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
133
  tbuf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16);
134
  (*vax_d_format.decode) (fmt, r, tbuf);
135
}
136
 
137
/* This is where the condition code register lives.  */
138
/* rtx cc0_reg_rtx; - no longer needed? */
139
 
140
static bool pdp11_handle_option (size_t, const char *, int);
141
static rtx find_addr_reg (rtx);
142
static const char *singlemove_string (rtx *);
143
static bool pdp11_assemble_integer (rtx, unsigned int, int);
144
static void pdp11_output_function_prologue (FILE *, HOST_WIDE_INT);
145
static void pdp11_output_function_epilogue (FILE *, HOST_WIDE_INT);
146
static bool pdp11_rtx_costs (rtx, int, int, int *);
147
static bool pdp11_return_in_memory (tree, tree);
148
 
149
/* Initialize the GCC target structure.  */
150
#undef TARGET_ASM_BYTE_OP
151
#define TARGET_ASM_BYTE_OP NULL
152
#undef TARGET_ASM_ALIGNED_HI_OP
153
#define TARGET_ASM_ALIGNED_HI_OP NULL
154
#undef TARGET_ASM_ALIGNED_SI_OP
155
#define TARGET_ASM_ALIGNED_SI_OP NULL
156
#undef TARGET_ASM_INTEGER
157
#define TARGET_ASM_INTEGER pdp11_assemble_integer
158
 
159
#undef TARGET_ASM_FUNCTION_PROLOGUE
160
#define TARGET_ASM_FUNCTION_PROLOGUE pdp11_output_function_prologue
161
#undef TARGET_ASM_FUNCTION_EPILOGUE
162
#define TARGET_ASM_FUNCTION_EPILOGUE pdp11_output_function_epilogue
163
 
164
#undef TARGET_ASM_OPEN_PAREN
165
#define TARGET_ASM_OPEN_PAREN "["
166
#undef TARGET_ASM_CLOSE_PAREN
167
#define TARGET_ASM_CLOSE_PAREN "]"
168
 
169
#undef TARGET_DEFAULT_TARGET_FLAGS
170
#define TARGET_DEFAULT_TARGET_FLAGS \
171
  (MASK_FPU | MASK_45 | MASK_ABSHI_BUILTIN | TARGET_UNIX_ASM_DEFAULT)
172
#undef TARGET_HANDLE_OPTION
173
#define TARGET_HANDLE_OPTION pdp11_handle_option
174
 
175
#undef TARGET_RTX_COSTS
176
#define TARGET_RTX_COSTS pdp11_rtx_costs
177
 
178
#undef TARGET_RETURN_IN_MEMORY
179
#define TARGET_RETURN_IN_MEMORY pdp11_return_in_memory
180
 
181
struct gcc_target targetm = TARGET_INITIALIZER;
182
 
183
/* Implement TARGET_HANDLE_OPTION.  */
184
 
185
static bool
186
pdp11_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
187
                     int value ATTRIBUTE_UNUSED)
188
{
189
  switch (code)
190
    {
191
    case OPT_m10:
192
      target_flags &= ~(MASK_40 | MASK_45);
193
      return true;
194
 
195
    default:
196
      return true;
197
    }
198
}
199
 
200
/* Nonzero if OP is a valid second operand for an arithmetic insn.  */
201
 
202
int
203
arith_operand (rtx op, enum machine_mode mode)
204
{
205
  return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
206
}
207
 
208
int
209
const_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
210
{
211
  return (GET_CODE (op) == CONST_INT);
212
}
213
 
214
int
215
immediate15_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
216
{
217
    return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
218
}
219
 
220
int
221
expand_shift_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
222
{
223
    return (GET_CODE (op) == CONST_INT
224
            && abs (INTVAL(op)) > 1
225
            && abs (INTVAL(op)) <= 4);
226
}
227
 
228
/*
229
   stream is a stdio stream to output the code to.
230
   size is an int: how many units of temporary storage to allocate.
231
   Refer to the array `regs_ever_live' to determine which registers
232
   to save; `regs_ever_live[I]' is nonzero if register number I
233
   is ever used in the function.  This macro is responsible for
234
   knowing which registers should not be saved even if used.
235
*/
236
 
237
#ifdef TWO_BSD
238
 
239
static void
240
pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
241
{
242
  fprintf (stream, "\tjsr       r5, csv\n");
243
  if (size)
244
    {
245
      fprintf (stream, "\t/*abuse empty parameter slot for locals!*/\n");
246
      if (size > 2)
247
        asm_fprintf (stream, "\tsub $%#wo, sp\n", size - 2);
248
 
249
    }
250
}
251
 
252
#else  /* !TWO_BSD */
253
 
254
static void
255
pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
256
{
257
    HOST_WIDE_INT fsize = ((size) + 1) & ~1;
258
    int regno;
259
    int via_ac = -1;
260
 
261
    fprintf (stream,
262
             "\n\t;     /* function prologue %s*/\n",
263
             current_function_name ());
264
 
265
    /* if we are outputting code for main,
266
       the switch FPU to right mode if TARGET_FPU */
267
    if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU)
268
    {
269
        fprintf(stream,
270
                "\t;/* switch cpu to double float, single integer */\n");
271
        fprintf(stream, "\tsetd\n");
272
        fprintf(stream, "\tseti\n\n");
273
    }
274
 
275
    if (frame_pointer_needed)
276
    {
277
        fprintf(stream, "\tmov r5, -(sp)\n");
278
        fprintf(stream, "\tmov sp, r5\n");
279
    }
280
    else
281
    {
282
        /* DON'T SAVE FP */
283
    }
284
 
285
    /* make frame */
286
    if (fsize)
287
        asm_fprintf (stream, "\tsub $%#wo, sp\n", fsize);
288
 
289
    /* save CPU registers  */
290
    for (regno = 0; regno < 8; regno++)
291
        if (regs_ever_live[regno] && ! call_used_regs[regno])
292
            if (! ((regno == FRAME_POINTER_REGNUM)
293
                   && frame_pointer_needed))
294
                fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);
295
    /* fpu regs saving */
296
 
297
    /* via_ac specifies the ac to use for saving ac4, ac5 */
298
    via_ac = -1;
299
 
300
    for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++)
301
    {
302
        /* ac0 - ac3 */
303
        if (LOAD_FPU_REG_P(regno)
304
            && regs_ever_live[regno]
305
            && ! call_used_regs[regno])
306
        {
307
            fprintf (stream, "\tstd %s, -(sp)\n", reg_names[regno]);
308
            via_ac = regno;
309
        }
310
 
311
        /* maybe make ac4, ac5 call used regs?? */
312
        /* ac4 - ac5 */
313
        if (NO_LOAD_FPU_REG_P(regno)
314
            && regs_ever_live[regno]
315
            && ! call_used_regs[regno])
316
        {
317
          gcc_assert (via_ac != -1);
318
          fprintf (stream, "\tldd %s, %s\n",
319
                   reg_names[regno], reg_names[via_ac]);
320
          fprintf (stream, "\tstd %s, -(sp)\n", reg_names[via_ac]);
321
        }
322
    }
323
 
324
    fprintf (stream, "\t;/* end of prologue */\n\n");
325
}
326
 
327
#endif /* !TWO_BSD */
328
 
329
/*
330
   The function epilogue should not depend on the current stack pointer!
331
   It should use the frame pointer only.  This is mandatory because
332
   of alloca; we also take advantage of it to omit stack adjustments
333
   before returning.  */
334
 
335
/* maybe we can make leaf functions faster by switching to the
336
   second register file - this way we don't have to save regs!
337
   leaf functions are ~ 50% of all functions (dynamically!)
338
 
339
   set/clear bit 11 (dec. 2048) of status word for switching register files -
340
   but how can we do this? the pdp11/45 manual says bit may only
341
   be set (p.24), but not cleared!
342
 
343
   switching to kernel is probably more expensive, so we'll leave it
344
   like this and not use the second set of registers...
345
 
346
   maybe as option if you want to generate code for kernel mode? */
347
 
348
#ifdef TWO_BSD
349
 
350
static void
351
pdp11_output_function_epilogue (FILE *stream,
352
                                HOST_WIDE_INT size ATTRIBUTE_UNUSED)
353
{
354
  fprintf (stream, "\t/* SP ignored by cret? */\n");
355
  fprintf (stream, "\tjmp cret\n");
356
}
357
 
358
#else  /* !TWO_BSD */
359
 
360
static void
361
pdp11_output_function_epilogue (FILE *stream, HOST_WIDE_INT size)
362
{
363
    HOST_WIDE_INT fsize = ((size) + 1) & ~1;
364
    int i, j, k;
365
 
366
    int via_ac;
367
 
368
    fprintf (stream, "\n\t;     /*function epilogue */\n");
369
 
370
    if (frame_pointer_needed)
371
    {
372
        /* hope this is safe - m68k does it also .... */
373
        regs_ever_live[FRAME_POINTER_REGNUM] = 0;
374
 
375
        for (i =7, j = 0 ; i >= 0 ; i--)
376
            if (regs_ever_live[i] && ! call_used_regs[i])
377
                j++;
378
 
379
        /* remember # of pushed bytes for CPU regs */
380
        k = 2*j;
381
 
382
        /* change fp -> r5 due to the compile error on libgcc2.c */
383
        for (i =7 ; i >= 0 ; i--)
384
            if (regs_ever_live[i] && ! call_used_regs[i])
385
                fprintf(stream, "\tmov %#o(r5), %s\n",(-fsize-2*j--)&0xffff, reg_names[i]);
386
 
387
        /* get ACs */
388
        via_ac = FIRST_PSEUDO_REGISTER -1;
389
 
390
        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
391
            if (regs_ever_live[i] && ! call_used_regs[i])
392
            {
393
                via_ac = i;
394
                k += 8;
395
            }
396
 
397
        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
398
        {
399
            if (LOAD_FPU_REG_P(i)
400
                && regs_ever_live[i]
401
                && ! call_used_regs[i])
402
            {
403
                fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[i]);
404
                k -= 8;
405
            }
406
 
407
            if (NO_LOAD_FPU_REG_P(i)
408
                && regs_ever_live[i]
409
                && ! call_used_regs[i])
410
            {
411
                gcc_assert (LOAD_FPU_REG_P(via_ac));
412
 
413
                fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[via_ac]);
414
                fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
415
                k -= 8;
416
            }
417
        }
418
 
419
        fprintf(stream, "\tmov r5, sp\n");
420
        fprintf (stream, "\tmov (sp)+, r5\n");
421
    }
422
    else
423
    {
424
        via_ac = FIRST_PSEUDO_REGISTER -1;
425
 
426
        /* get ACs */
427
        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
428
            if (regs_ever_live[i] && call_used_regs[i])
429
                via_ac = i;
430
 
431
        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
432
        {
433
            if (LOAD_FPU_REG_P(i)
434
                && regs_ever_live[i]
435
                && ! call_used_regs[i])
436
              fprintf(stream, "\tldd (sp)+, %s\n", reg_names[i]);
437
 
438
            if (NO_LOAD_FPU_REG_P(i)
439
                && regs_ever_live[i]
440
                && ! call_used_regs[i])
441
            {
442
                gcc_assert (LOAD_FPU_REG_P(via_ac));
443
 
444
                fprintf(stream, "\tldd (sp)+, %s\n", reg_names[via_ac]);
445
                fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
446
            }
447
        }
448
 
449
        for (i=7; i >= 0; i--)
450
            if (regs_ever_live[i] && !call_used_regs[i])
451
                fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);
452
 
453
        if (fsize)
454
            fprintf((stream), "\tadd $%#o, sp\n", (fsize)&0xffff);
455
    }
456
 
457
    fprintf (stream, "\trts pc\n");
458
    fprintf (stream, "\t;/* end of epilogue*/\n\n\n");
459
}
460
 
461
#endif /* !TWO_BSD */
462
 
463
/* Return the best assembler insn template
464
   for moving operands[1] into operands[0] as a fullword.  */
465
static const char *
466
singlemove_string (rtx *operands)
467
{
468
  if (operands[1] != const0_rtx)
469
    return "mov %1,%0";
470
 
471
  return "clr %0";
472
}
473
 
474
 
475
/* Output assembler code to perform a doubleword move insn
476
   with operands OPERANDS.  */
477
 
478
const char *
479
output_move_double (rtx *operands)
480
{
481
  enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
482
  rtx latehalf[2];
483
  rtx addreg0 = 0, addreg1 = 0;
484
 
485
  /* First classify both operands.  */
486
 
487
  if (REG_P (operands[0]))
488
    optype0 = REGOP;
489
  else if (offsettable_memref_p (operands[0]))
490
    optype0 = OFFSOP;
491
  else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
492
    optype0 = POPOP;
493
  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
494
    optype0 = PUSHOP;
495
  else if (GET_CODE (operands[0]) == MEM)
496
    optype0 = MEMOP;
497
  else
498
    optype0 = RNDOP;
499
 
500
  if (REG_P (operands[1]))
501
    optype1 = REGOP;
502
  else if (CONSTANT_P (operands[1])
503
#if 0
504
           || GET_CODE (operands[1]) == CONST_DOUBLE
505
#endif
506
           )
507
    optype1 = CNSTOP;
508
  else if (offsettable_memref_p (operands[1]))
509
    optype1 = OFFSOP;
510
  else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
511
    optype1 = POPOP;
512
  else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
513
    optype1 = PUSHOP;
514
  else if (GET_CODE (operands[1]) == MEM)
515
    optype1 = MEMOP;
516
  else
517
    optype1 = RNDOP;
518
 
519
  /* Check for the cases that the operand constraints are not
520
     supposed to allow to happen.  Abort if we get one,
521
     because generating code for these cases is painful.  */
522
 
523
  gcc_assert (optype0 != RNDOP && optype1 != RNDOP);
524
 
525
  /* If one operand is decrementing and one is incrementing
526
     decrement the former register explicitly
527
     and change that operand into ordinary indexing.  */
528
 
529
  if (optype0 == PUSHOP && optype1 == POPOP)
530
    {
531
      operands[0] = XEXP (XEXP (operands[0], 0), 0);
532
      output_asm_insn ("sub $4,%0", operands);
533
      operands[0] = gen_rtx_MEM (SImode, operands[0]);
534
      optype0 = OFFSOP;
535
    }
536
  if (optype0 == POPOP && optype1 == PUSHOP)
537
    {
538
      operands[1] = XEXP (XEXP (operands[1], 0), 0);
539
      output_asm_insn ("sub $4,%1", operands);
540
      operands[1] = gen_rtx_MEM (SImode, operands[1]);
541
      optype1 = OFFSOP;
542
    }
543
 
544
  /* If an operand is an unoffsettable memory ref, find a register
545
     we can increment temporarily to make it refer to the second word.  */
546
 
547
  if (optype0 == MEMOP)
548
    addreg0 = find_addr_reg (XEXP (operands[0], 0));
549
 
550
  if (optype1 == MEMOP)
551
    addreg1 = find_addr_reg (XEXP (operands[1], 0));
552
 
553
  /* Ok, we can do one word at a time.
554
     Normally we do the low-numbered word first,
555
     but if either operand is autodecrementing then we
556
     do the high-numbered word first.
557
 
558
     In either case, set up in LATEHALF the operands to use
559
     for the high-numbered word and in some cases alter the
560
     operands in OPERANDS to be suitable for the low-numbered word.  */
561
 
562
  if (optype0 == REGOP)
563
    latehalf[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
564
  else if (optype0 == OFFSOP)
565
    latehalf[0] = adjust_address (operands[0], HImode, 2);
566
  else
567
    latehalf[0] = operands[0];
568
 
569
  if (optype1 == REGOP)
570
    latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
571
  else if (optype1 == OFFSOP)
572
    latehalf[1] = adjust_address (operands[1], HImode, 2);
573
  else if (optype1 == CNSTOP)
574
    {
575
        if (CONSTANT_P (operands[1]))
576
        {
577
            /* now the mess begins, high word is in lower word???
578
 
579
               that's what ashc makes me think, but I don't remember :-( */
580
            latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16);
581
            operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff);
582
        }
583
        else
584
          /* immediate 32 bit values not allowed */
585
          gcc_assert (GET_CODE (operands[1]) != CONST_DOUBLE);
586
    }
587
  else
588
    latehalf[1] = operands[1];
589
 
590
  /* If insn is effectively movd N(sp),-(sp) then we will do the
591
     high word first.  We should use the adjusted operand 1 (which is N+4(sp))
592
     for the low word as well, to compensate for the first decrement of sp.  */
593
  if (optype0 == PUSHOP
594
      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
595
      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
596
    operands[1] = latehalf[1];
597
 
598
  /* If one or both operands autodecrementing,
599
     do the two words, high-numbered first.  */
600
 
601
  /* Likewise,  the first move would clobber the source of the second one,
602
     do them in the other order.  This happens only for registers;
603
     such overlap can't happen in memory unless the user explicitly
604
     sets it up, and that is an undefined circumstance.  */
605
 
606
  if (optype0 == PUSHOP || optype1 == PUSHOP
607
      || (optype0 == REGOP && optype1 == REGOP
608
          && REGNO (operands[0]) == REGNO (latehalf[1])))
609
    {
610
      /* Make any unoffsettable addresses point at high-numbered word.  */
611
      if (addreg0)
612
        output_asm_insn ("add $2,%0", &addreg0);
613
      if (addreg1)
614
        output_asm_insn ("add $2,%0", &addreg1);
615
 
616
      /* Do that word.  */
617
      output_asm_insn (singlemove_string (latehalf), latehalf);
618
 
619
      /* Undo the adds we just did.  */
620
      if (addreg0)
621
        output_asm_insn ("sub $2,%0", &addreg0);
622
      if (addreg1)
623
        output_asm_insn ("sub $2,%0", &addreg1);
624
 
625
      /* Do low-numbered word.  */
626
      return singlemove_string (operands);
627
    }
628
 
629
  /* Normal case: do the two words, low-numbered first.  */
630
 
631
  output_asm_insn (singlemove_string (operands), operands);
632
 
633
  /* Make any unoffsettable addresses point at high-numbered word.  */
634
  if (addreg0)
635
    output_asm_insn ("add $2,%0", &addreg0);
636
  if (addreg1)
637
    output_asm_insn ("add $2,%0", &addreg1);
638
 
639
  /* Do that word.  */
640
  output_asm_insn (singlemove_string (latehalf), latehalf);
641
 
642
  /* Undo the adds we just did.  */
643
  if (addreg0)
644
    output_asm_insn ("sub $2,%0", &addreg0);
645
  if (addreg1)
646
    output_asm_insn ("sub $2,%0", &addreg1);
647
 
648
  return "";
649
}
650
/* Output assembler code to perform a quadword move insn
651
   with operands OPERANDS.  */
652
 
653
const char *
654
output_move_quad (rtx *operands)
655
{
656
  enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
657
  rtx latehalf[2];
658
  rtx addreg0 = 0, addreg1 = 0;
659
 
660
  output_asm_insn(";/* movdi/df: %1 -> %0 */", operands);
661
 
662
  if (REG_P (operands[0]))
663
    optype0 = REGOP;
664
  else if (offsettable_memref_p (operands[0]))
665
    optype0 = OFFSOP;
666
  else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
667
    optype0 = POPOP;
668
  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
669
    optype0 = PUSHOP;
670
  else if (GET_CODE (operands[0]) == MEM)
671
    optype0 = MEMOP;
672
  else
673
    optype0 = RNDOP;
674
 
675
  if (REG_P (operands[1]))
676
    optype1 = REGOP;
677
  else if (CONSTANT_P (operands[1])
678
           || GET_CODE (operands[1]) == CONST_DOUBLE)
679
    optype1 = CNSTOP;
680
  else if (offsettable_memref_p (operands[1]))
681
    optype1 = OFFSOP;
682
  else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
683
    optype1 = POPOP;
684
  else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
685
    optype1 = PUSHOP;
686
  else if (GET_CODE (operands[1]) == MEM)
687
    optype1 = MEMOP;
688
  else
689
    optype1 = RNDOP;
690
 
691
  /* Check for the cases that the operand constraints are not
692
     supposed to allow to happen.  Abort if we get one,
693
     because generating code for these cases is painful.  */
694
 
695
  gcc_assert (optype0 != RNDOP && optype1 != RNDOP);
696
 
697
  /* check if we move a CPU reg to an FPU reg, or vice versa! */
698
  if (optype0 == REGOP && optype1 == REGOP)
699
      /* bogus - 64 bit cannot reside in CPU! */
700
      gcc_assert (!CPU_REG_P(REGNO(operands[0]))
701
                  && !CPU_REG_P (REGNO(operands[1])));
702
 
703
  if (optype0 == REGOP || optype1 == REGOP)
704
  {
705
      /* check for use of clrd????
706
         if you ever allow ac4 and ac5 (now we require secondary load)
707
         you must check whether
708
         you want to load into them or store from them -
709
         then dump ac0 into $help$ movce ac4/5 to ac0, do the
710
         store from ac0, and restore ac0 - if you can find
711
         an unused ac[0-3], use that and you save a store and a load!*/
712
 
713
      if (FPU_REG_P(REGNO(operands[0])))
714
      {
715
          if (GET_CODE(operands[1]) == CONST_DOUBLE)
716
          {
717
              REAL_VALUE_TYPE r;
718
              REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
719
 
720
              if (REAL_VALUES_EQUAL (r, dconst0))
721
                  return "{clrd|clrf} %0";
722
          }
723
 
724
          return "{ldd|movf} %1, %0";
725
      }
726
 
727
      if (FPU_REG_P(REGNO(operands[1])))
728
          return "{std|movf} %1, %0";
729
  }
730
 
731
  /* If one operand is decrementing and one is incrementing
732
     decrement the former register explicitly
733
     and change that operand into ordinary indexing.  */
734
 
735
  if (optype0 == PUSHOP && optype1 == POPOP)
736
    {
737
      operands[0] = XEXP (XEXP (operands[0], 0), 0);
738
      output_asm_insn ("sub $8,%0", operands);
739
      operands[0] = gen_rtx_MEM (DImode, operands[0]);
740
      optype0 = OFFSOP;
741
    }
742
  if (optype0 == POPOP && optype1 == PUSHOP)
743
    {
744
      operands[1] = XEXP (XEXP (operands[1], 0), 0);
745
      output_asm_insn ("sub $8,%1", operands);
746
      operands[1] = gen_rtx_MEM (SImode, operands[1]);
747
      optype1 = OFFSOP;
748
    }
749
 
750
  /* If an operand is an unoffsettable memory ref, find a register
751
     we can increment temporarily to make it refer to the second word.  */
752
 
753
  if (optype0 == MEMOP)
754
    addreg0 = find_addr_reg (XEXP (operands[0], 0));
755
 
756
  if (optype1 == MEMOP)
757
    addreg1 = find_addr_reg (XEXP (operands[1], 0));
758
 
759
  /* Ok, we can do one word at a time.
760
     Normally we do the low-numbered word first,
761
     but if either operand is autodecrementing then we
762
     do the high-numbered word first.
763
 
764
     In either case, set up in LATEHALF the operands to use
765
     for the high-numbered word and in some cases alter the
766
     operands in OPERANDS to be suitable for the low-numbered word.  */
767
 
768
  if (optype0 == REGOP)
769
    latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
770
  else if (optype0 == OFFSOP)
771
    latehalf[0] = adjust_address (operands[0], SImode, 4);
772
  else
773
    latehalf[0] = operands[0];
774
 
775
  if (optype1 == REGOP)
776
    latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
777
  else if (optype1 == OFFSOP)
778
    latehalf[1] = adjust_address (operands[1], SImode, 4);
779
  else if (optype1 == CNSTOP)
780
    {
781
      if (GET_CODE (operands[1]) == CONST_DOUBLE)
782
        {
783
          REAL_VALUE_TYPE r;
784
          long dval[2];
785
          REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
786
          REAL_VALUE_TO_TARGET_DOUBLE (r, dval);
787
          latehalf[1] = GEN_INT (dval[1]);
788
          operands[1] = GEN_INT (dval[0]);
789
        }
790
      else if (GET_CODE(operands[1]) == CONST_INT)
791
        {
792
          latehalf[1] = const0_rtx;
793
        }
794
      else
795
        gcc_unreachable ();
796
    }
797
  else
798
    latehalf[1] = operands[1];
799
 
800
  /* If insn is effectively movd N(sp),-(sp) then we will do the
801
     high word first.  We should use the adjusted operand 1 (which is N+4(sp))
802
     for the low word as well, to compensate for the first decrement of sp.  */
803
  if (optype0 == PUSHOP
804
      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
805
      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
806
    operands[1] = latehalf[1];
807
 
808
  /* If one or both operands autodecrementing,
809
     do the two words, high-numbered first.  */
810
 
811
  /* Likewise,  the first move would clobber the source of the second one,
812
     do them in the other order.  This happens only for registers;
813
     such overlap can't happen in memory unless the user explicitly
814
     sets it up, and that is an undefined circumstance.  */
815
 
816
  if (optype0 == PUSHOP || optype1 == PUSHOP
817
      || (optype0 == REGOP && optype1 == REGOP
818
          && REGNO (operands[0]) == REGNO (latehalf[1])))
819
    {
820
      /* Make any unoffsettable addresses point at high-numbered word.  */
821
      if (addreg0)
822
        output_asm_insn ("add $4,%0", &addreg0);
823
      if (addreg1)
824
        output_asm_insn ("add $4,%0", &addreg1);
825
 
826
      /* Do that word.  */
827
      output_asm_insn(output_move_double(latehalf), latehalf);
828
 
829
      /* Undo the adds we just did.  */
830
      if (addreg0)
831
        output_asm_insn ("sub $4,%0", &addreg0);
832
      if (addreg1)
833
        output_asm_insn ("sub $4,%0", &addreg1);
834
 
835
      /* Do low-numbered word.  */
836
      return output_move_double (operands);
837
    }
838
 
839
  /* Normal case: do the two words, low-numbered first.  */
840
 
841
  output_asm_insn (output_move_double (operands), operands);
842
 
843
  /* Make any unoffsettable addresses point at high-numbered word.  */
844
  if (addreg0)
845
    output_asm_insn ("add $4,%0", &addreg0);
846
  if (addreg1)
847
    output_asm_insn ("add $4,%0", &addreg1);
848
 
849
  /* Do that word.  */
850
  output_asm_insn (output_move_double (latehalf), latehalf);
851
 
852
  /* Undo the adds we just did.  */
853
  if (addreg0)
854
    output_asm_insn ("sub $4,%0", &addreg0);
855
  if (addreg1)
856
    output_asm_insn ("sub $4,%0", &addreg1);
857
 
858
  return "";
859
}
860
 
861
 
862
/* Return a REG that occurs in ADDR with coefficient 1.
863
   ADDR can be effectively incremented by incrementing REG.  */
864
 
865
static rtx
866
find_addr_reg (rtx addr)
867
{
868
  while (GET_CODE (addr) == PLUS)
869
    {
870
      if (GET_CODE (XEXP (addr, 0)) == REG)
871
        addr = XEXP (addr, 0);
872
      if (GET_CODE (XEXP (addr, 1)) == REG)
873
        addr = XEXP (addr, 1);
874
      if (CONSTANT_P (XEXP (addr, 0)))
875
        addr = XEXP (addr, 1);
876
      if (CONSTANT_P (XEXP (addr, 1)))
877
        addr = XEXP (addr, 0);
878
    }
879
  if (GET_CODE (addr) == REG)
880
    return addr;
881
  return 0;
882
}
883
 
884
/* Output an ascii string.  */
885
void
886
output_ascii (FILE *file, const char *p, int size)
887
{
888
  int i;
889
 
890
  /* This used to output .byte "string", which doesn't work with the UNIX
891
     assembler and I think not with DEC ones either.  */
892
  fprintf (file, "\t.byte ");
893
 
894
  for (i = 0; i < size; i++)
895
    {
896
      register int c = p[i];
897
      if (c < 0)
898
        c += 256;
899
      fprintf (file, "%#o", c);
900
      if (i < size - 1)
901
        putc (',', file);
902
    }
903
  putc ('\n', file);
904
}
905
 
906
 
907
/* --- stole from out-vax, needs changes */
908
 
909
void
910
print_operand_address (FILE *file, register rtx addr)
911
{
912
  register rtx reg1, reg2, breg, ireg;
913
  rtx offset;
914
 
915
 retry:
916
 
917
  switch (GET_CODE (addr))
918
    {
919
    case MEM:
920
      if (TARGET_UNIX_ASM)
921
        fprintf (file, "*");
922
      else
923
        fprintf (file, "@");
924
      addr = XEXP (addr, 0);
925
      goto retry;
926
 
927
    case REG:
928
      fprintf (file, "(%s)", reg_names[REGNO (addr)]);
929
      break;
930
 
931
    case PRE_MODIFY:
932
    case PRE_DEC:
933
      fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
934
      break;
935
 
936
    case POST_MODIFY:
937
    case POST_INC:
938
      fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
939
      break;
940
 
941
    case PLUS:
942
      reg1 = 0;  reg2 = 0;
943
      ireg = 0;  breg = 0;
944
      offset = 0;
945
      if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
946
          || GET_CODE (XEXP (addr, 0)) == MEM)
947
        {
948
          offset = XEXP (addr, 0);
949
          addr = XEXP (addr, 1);
950
        }
951
      else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
952
               || GET_CODE (XEXP (addr, 1)) == MEM)
953
        {
954
          offset = XEXP (addr, 1);
955
          addr = XEXP (addr, 0);
956
        }
957
      if (GET_CODE (addr) != PLUS)
958
        ;
959
      else if (GET_CODE (XEXP (addr, 0)) == MULT)
960
        {
961
          reg1 = XEXP (addr, 0);
962
          addr = XEXP (addr, 1);
963
        }
964
      else if (GET_CODE (XEXP (addr, 1)) == MULT)
965
        {
966
          reg1 = XEXP (addr, 1);
967
          addr = XEXP (addr, 0);
968
        }
969
      else if (GET_CODE (XEXP (addr, 0)) == REG)
970
        {
971
          reg1 = XEXP (addr, 0);
972
          addr = XEXP (addr, 1);
973
        }
974
      else if (GET_CODE (XEXP (addr, 1)) == REG)
975
        {
976
          reg1 = XEXP (addr, 1);
977
          addr = XEXP (addr, 0);
978
        }
979
      if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
980
        {
981
          if (reg1 == 0)
982
            reg1 = addr;
983
          else
984
            reg2 = addr;
985
          addr = 0;
986
        }
987
      if (offset != 0)
988
        {
989
          gcc_assert (addr == 0);
990
          addr = offset;
991
        }
992
      if (reg1 != 0 && GET_CODE (reg1) == MULT)
993
        {
994
          breg = reg2;
995
          ireg = reg1;
996
        }
997
      else if (reg2 != 0 && GET_CODE (reg2) == MULT)
998
        {
999
          breg = reg1;
1000
          ireg = reg2;
1001
        }
1002
      else if (reg2 != 0 || GET_CODE (addr) == MEM)
1003
        {
1004
          breg = reg2;
1005
          ireg = reg1;
1006
        }
1007
      else
1008
        {
1009
          breg = reg1;
1010
          ireg = reg2;
1011
        }
1012
      if (addr != 0)
1013
        output_address (addr);
1014
      if (breg != 0)
1015
        {
1016
          gcc_assert (GET_CODE (breg) == REG);
1017
          fprintf (file, "(%s)", reg_names[REGNO (breg)]);
1018
        }
1019
      if (ireg != 0)
1020
        {
1021
          if (GET_CODE (ireg) == MULT)
1022
            ireg = XEXP (ireg, 0);
1023
          gcc_assert (GET_CODE (ireg) == REG);
1024
          gcc_unreachable(); /* ??? */
1025
          fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
1026
        }
1027
      break;
1028
 
1029
    default:
1030
      output_addr_const_pdp11 (file, addr);
1031
    }
1032
}
1033
 
1034
/* Target hook to assemble integer objects.  We need to use the
1035
   pdp-specific version of output_addr_const.  */
1036
 
1037
static bool
1038
pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p)
1039
{
1040
  if (aligned_p)
1041
    switch (size)
1042
      {
1043
      case 1:
1044
        fprintf (asm_out_file, "\t.byte\t");
1045
        output_addr_const_pdp11 (asm_out_file, x);
1046
        fprintf (asm_out_file, " /* char */\n");
1047
        return true;
1048
 
1049
      case 2:
1050
        fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t");
1051
        output_addr_const_pdp11 (asm_out_file, x);
1052
        fprintf (asm_out_file, " /* short */\n");
1053
        return true;
1054
      }
1055
  return default_assemble_integer (x, size, aligned_p);
1056
}
1057
 
1058
 
1059
/* register move costs, indexed by regs */
1060
 
1061
static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] =
1062
{
1063
             /* NO  MUL  GEN  LFPU  NLFPU FPU ALL */
1064
 
1065
/* NO */     {  0,   0,   0,    0,    0,    0,   0},
1066
/* MUL */    {  0,   2,   2,   10,   22,   22,  22},
1067
/* GEN */    {  0,   2,   2,   10,   22,   22,  22},
1068
/* LFPU */   {  0,  10,  10,    2,    2,    2,  10},
1069
/* NLFPU */  {  0,  22,  22,    2,    2,    2,  22},
1070
/* FPU */    {  0,  22,  22,    2,    2,    2,  22},
1071
/* ALL */    {  0,  22,  22,   10,   22,   22,  22}
1072
}  ;
1073
 
1074
 
1075
/* -- note that some moves are tremendously expensive,
1076
   because they require lots of tricks! do we have to
1077
   charge the costs incurred by secondary reload class
1078
   -- as we do here with 22 -- or not ? */
1079
 
1080
int
1081
register_move_cost(c1, c2)
1082
  enum reg_class c1, c2;
1083
{
1084
    return move_costs[(int)c1][(int)c2];
1085
}
1086
 
1087
static bool
1088
pdp11_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
1089
{
1090
  switch (code)
1091
    {
1092
    case CONST_INT:
1093
      if (INTVAL (x) == 0 || INTVAL (x) == -1 || INTVAL (x) == 1)
1094
        {
1095
          *total = 0;
1096
          return true;
1097
        }
1098
      /* FALLTHRU */
1099
 
1100
    case CONST:
1101
    case LABEL_REF:
1102
    case SYMBOL_REF:
1103
      /* Twice as expensive as REG.  */
1104
      *total = 2;
1105
      return true;
1106
 
1107
    case CONST_DOUBLE:
1108
      /* Twice (or 4 times) as expensive as 16 bit.  */
1109
      *total = 4;
1110
      return true;
1111
 
1112
    case MULT:
1113
      /* ??? There is something wrong in MULT because MULT is not
1114
         as cheap as total = 2 even if we can shift!  */
1115
      /* If optimizing for size make mult etc cheap, but not 1, so when
1116
         in doubt the faster insn is chosen.  */
1117
      if (optimize_size)
1118
        *total = COSTS_N_INSNS (2);
1119
      else
1120
        *total = COSTS_N_INSNS (11);
1121
      return false;
1122
 
1123
    case DIV:
1124
      if (optimize_size)
1125
        *total = COSTS_N_INSNS (2);
1126
      else
1127
        *total = COSTS_N_INSNS (25);
1128
      return false;
1129
 
1130
    case MOD:
1131
      if (optimize_size)
1132
        *total = COSTS_N_INSNS (2);
1133
      else
1134
        *total = COSTS_N_INSNS (26);
1135
      return false;
1136
 
1137
    case ABS:
1138
      /* Equivalent to length, so same for optimize_size.  */
1139
      *total = COSTS_N_INSNS (3);
1140
      return false;
1141
 
1142
    case ZERO_EXTEND:
1143
      /* Only used for qi->hi.  */
1144
      *total = COSTS_N_INSNS (1);
1145
      return false;
1146
 
1147
    case SIGN_EXTEND:
1148
      if (GET_MODE (x) == HImode)
1149
        *total = COSTS_N_INSNS (1);
1150
      else if (GET_MODE (x) == SImode)
1151
        *total = COSTS_N_INSNS (6);
1152
      else
1153
        *total = COSTS_N_INSNS (2);
1154
      return false;
1155
 
1156
    case ASHIFT:
1157
    case LSHIFTRT:
1158
    case ASHIFTRT:
1159
      if (optimize_size)
1160
        *total = COSTS_N_INSNS (1);
1161
      else if (GET_MODE (x) ==  QImode)
1162
        {
1163
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
1164
            *total = COSTS_N_INSNS (8); /* worst case */
1165
          else
1166
            *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1)));
1167
        }
1168
      else if (GET_MODE (x) == HImode)
1169
        {
1170
          if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1171
            {
1172
              if (abs (INTVAL (XEXP (x, 1))) == 1)
1173
                *total = COSTS_N_INSNS (1);
1174
              else
1175
                *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
1176
            }
1177
          else
1178
            *total = COSTS_N_INSNS (10); /* worst case */
1179
        }
1180
      else if (GET_MODE (x) == SImode)
1181
        {
1182
          if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1183
            *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
1184
          else /* worst case */
1185
            *total = COSTS_N_INSNS (18);
1186
        }
1187
      return false;
1188
 
1189
    default:
1190
      return false;
1191
    }
1192
}
1193
 
1194
const char *
1195
output_jump (const char *pos, const char *neg, int length)
1196
{
1197
    static int x = 0;
1198
 
1199
    static char buf[1000];
1200
 
1201
#if 0
1202
/* currently we don't need this, because the tstdf and cmpdf
1203
   copy the condition code immediately, and other float operations are not
1204
   yet recognized as changing the FCC - if so, then the length-cost of all
1205
   jump insns increases by one, because we have to potentially copy the
1206
   FCC! */
1207
    if (cc_status.flags & CC_IN_FPU)
1208
        output_asm_insn("cfcc", NULL);
1209
#endif
1210
 
1211
    switch (length)
1212
    {
1213
      case 1:
1214
 
1215
        strcpy(buf, pos);
1216
        strcat(buf, " %l0");
1217
 
1218
        return buf;
1219
 
1220
      case 3:
1221
 
1222
        sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
1223
 
1224
        x++;
1225
 
1226
        return buf;
1227
 
1228
      default:
1229
 
1230
        gcc_unreachable ();
1231
    }
1232
 
1233
}
1234
 
1235
void
1236
notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED)
1237
{
1238
    if (GET_CODE (SET_DEST (exp)) == CC0)
1239
    {
1240
        cc_status.flags = 0;
1241
        cc_status.value1 = SET_DEST (exp);
1242
        cc_status.value2 = SET_SRC (exp);
1243
 
1244
/*
1245
        if (GET_MODE(SET_SRC(exp)) == DFmode)
1246
            cc_status.flags |= CC_IN_FPU;
1247
*/
1248
    }
1249
    else if ((GET_CODE (SET_DEST (exp)) == REG
1250
              || GET_CODE (SET_DEST (exp)) == MEM)
1251
             && GET_CODE (SET_SRC (exp)) != PC
1252
             && (GET_MODE (SET_DEST(exp)) == HImode
1253
                 || GET_MODE (SET_DEST(exp)) == QImode)
1254
                && (GET_CODE (SET_SRC(exp)) == PLUS
1255
                    || GET_CODE (SET_SRC(exp)) == MINUS
1256
                    || GET_CODE (SET_SRC(exp)) == AND
1257
                    || GET_CODE (SET_SRC(exp)) == IOR
1258
                    || GET_CODE (SET_SRC(exp)) == XOR
1259
                    || GET_CODE (SET_SRC(exp)) == NOT
1260
                    || GET_CODE (SET_SRC(exp)) == NEG
1261
                        || GET_CODE (SET_SRC(exp)) == REG
1262
                    || GET_CODE (SET_SRC(exp)) == MEM))
1263
    {
1264
        cc_status.flags = 0;
1265
        cc_status.value1 = SET_SRC (exp);
1266
        cc_status.value2 = SET_DEST (exp);
1267
 
1268
        if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
1269
            && cc_status.value2
1270
            && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1271
            cc_status.value2 = 0;
1272
        if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
1273
            && cc_status.value2
1274
            && GET_CODE (cc_status.value2) == MEM)
1275
            cc_status.value2 = 0;
1276
    }
1277
    else if (GET_CODE (SET_SRC (exp)) == CALL)
1278
    {
1279
        CC_STATUS_INIT;
1280
    }
1281
    else if (GET_CODE (SET_DEST (exp)) == REG)
1282
        /* what's this ? */
1283
    {
1284
        if ((cc_status.value1
1285
             && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)))
1286
            cc_status.value1 = 0;
1287
        if ((cc_status.value2
1288
             && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)))
1289
            cc_status.value2 = 0;
1290
    }
1291
    else if (SET_DEST(exp) == pc_rtx)
1292
    {
1293
        /* jump */
1294
    }
1295
    else /* if (GET_CODE (SET_DEST (exp)) == MEM)       */
1296
    {
1297
        /* the last else is a bit paranoiac, but since nearly all instructions
1298
           play with condition codes, it's reasonable! */
1299
 
1300
        CC_STATUS_INIT; /* paranoia*/
1301
    }
1302
}
1303
 
1304
 
1305
int
1306
simple_memory_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1307
{
1308
    rtx addr;
1309
 
1310
    /* Eliminate non-memory operations */
1311
    if (GET_CODE (op) != MEM)
1312
        return FALSE;
1313
 
1314
#if 0
1315
    /* dword operations really put out 2 instructions, so eliminate them.  */
1316
    if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
1317
        return FALSE;
1318
#endif
1319
 
1320
    /* Decode the address now.  */
1321
 
1322
  indirection:
1323
 
1324
    addr = XEXP (op, 0);
1325
 
1326
    switch (GET_CODE (addr))
1327
    {
1328
      case REG:
1329
        /* (R0) - no extra cost */
1330
        return 1;
1331
 
1332
      case PRE_DEC:
1333
      case POST_INC:
1334
        /* -(R0), (R0)+ - cheap! */
1335
        return 0;
1336
 
1337
      case MEM:
1338
        /* cheap - is encoded in addressing mode info!
1339
 
1340
           -- except for @(R0), which has to be @0(R0) !!! */
1341
 
1342
        if (GET_CODE (XEXP (addr, 0)) == REG)
1343
            return 0;
1344
 
1345
        op=addr;
1346
        goto indirection;
1347
 
1348
      case CONST_INT:
1349
      case LABEL_REF:
1350
      case CONST:
1351
      case SYMBOL_REF:
1352
        /* @#address - extra cost */
1353
        return 0;
1354
 
1355
      case PLUS:
1356
        /* X(R0) - extra cost */
1357
        return 0;
1358
 
1359
      default:
1360
        break;
1361
    }
1362
 
1363
    return FALSE;
1364
}
1365
 
1366
 
1367
/*
1368
 * output a block move:
1369
 *
1370
 * operands[0]  ... to
1371
 * operands[1]  ... from
1372
 * operands[2]  ... length
1373
 * operands[3]  ... alignment
1374
 * operands[4]  ... scratch register
1375
 */
1376
 
1377
 
1378
const char *
1379
output_block_move(rtx *operands)
1380
{
1381
    static int count = 0;
1382
    char buf[200];
1383
 
1384
    if (GET_CODE(operands[2]) == CONST_INT
1385
        && ! optimize_size)
1386
    {
1387
        if (INTVAL(operands[2]) < 16
1388
            && INTVAL(operands[3]) == 1)
1389
        {
1390
            register int i;
1391
 
1392
            for (i = 1; i <= INTVAL(operands[2]); i++)
1393
                output_asm_insn("movb (%1)+, (%0)+", operands);
1394
 
1395
            return "";
1396
        }
1397
        else if (INTVAL(operands[2]) < 32)
1398
        {
1399
            register int i;
1400
 
1401
            for (i = 1; i <= INTVAL(operands[2])/2; i++)
1402
                output_asm_insn("mov (%1)+, (%0)+", operands);
1403
 
1404
            /* may I assume that moved quantity is
1405
               multiple of alignment ???
1406
 
1407
               I HOPE SO !
1408
            */
1409
 
1410
            return "";
1411
        }
1412
 
1413
 
1414
        /* can do other clever things, maybe... */
1415
    }
1416
 
1417
    if (CONSTANT_P(operands[2]) )
1418
    {
1419
        /* just move count to scratch */
1420
        output_asm_insn("mov %2, %4", operands);
1421
    }
1422
    else
1423
    {
1424
        /* just clobber the register */
1425
        operands[4] = operands[2];
1426
    }
1427
 
1428
 
1429
    /* switch over alignment */
1430
    switch (INTVAL(operands[3]))
1431
    {
1432
      case 1:
1433
 
1434
        /*
1435
          x:
1436
          movb (%1)+, (%0)+
1437
 
1438
          if (TARGET_45)
1439
             sob %4,x
1440
          else
1441
             dec %4
1442
             bgt x
1443
 
1444
        */
1445
 
1446
        sprintf(buf, "\nmovestrhi%d:", count);
1447
        output_asm_insn(buf, NULL);
1448
 
1449
        output_asm_insn("movb (%1)+, (%0)+", operands);
1450
 
1451
        if (TARGET_45)
1452
        {
1453
            sprintf(buf, "sob %%4, movestrhi%d", count);
1454
            output_asm_insn(buf, operands);
1455
        }
1456
        else
1457
        {
1458
            output_asm_insn("dec %4", operands);
1459
 
1460
            sprintf(buf, "bgt movestrhi%d", count);
1461
            output_asm_insn(buf, NULL);
1462
        }
1463
 
1464
        count ++;
1465
        break;
1466
 
1467
      case 2:
1468
 
1469
        /*
1470
           asr %4
1471
 
1472
           x:
1473
 
1474
           mov (%1)+, (%0)+
1475
 
1476
           if (TARGET_45)
1477
             sob %4, x
1478
           else
1479
             dec %4
1480
             bgt x
1481
        */
1482
 
1483
      generate_compact_code:
1484
 
1485
        output_asm_insn("asr %4", operands);
1486
 
1487
        sprintf(buf, "\nmovestrhi%d:", count);
1488
        output_asm_insn(buf, NULL);
1489
 
1490
        output_asm_insn("mov (%1)+, (%0)+", operands);
1491
 
1492
        if (TARGET_45)
1493
        {
1494
            sprintf(buf, "sob %%4, movestrhi%d", count);
1495
            output_asm_insn(buf, operands);
1496
        }
1497
        else
1498
        {
1499
            output_asm_insn("dec %4", operands);
1500
 
1501
            sprintf(buf, "bgt movestrhi%d", count);
1502
            output_asm_insn(buf, NULL);
1503
        }
1504
 
1505
        count ++;
1506
        break;
1507
 
1508
      case 4:
1509
 
1510
        /*
1511
 
1512
           asr %4
1513
           asr %4
1514
 
1515
           x:
1516
 
1517
           mov (%1)+, (%0)+
1518
           mov (%1)+, (%0)+
1519
 
1520
           if (TARGET_45)
1521
             sob %4, x
1522
           else
1523
             dec %4
1524
             bgt x
1525
        */
1526
 
1527
        if (optimize_size)
1528
            goto generate_compact_code;
1529
 
1530
        output_asm_insn("asr %4", operands);
1531
        output_asm_insn("asr %4", operands);
1532
 
1533
        sprintf(buf, "\nmovestrhi%d:", count);
1534
        output_asm_insn(buf, NULL);
1535
 
1536
        output_asm_insn("mov (%1)+, (%0)+", operands);
1537
        output_asm_insn("mov (%1)+, (%0)+", operands);
1538
 
1539
        if (TARGET_45)
1540
        {
1541
            sprintf(buf, "sob %%4, movestrhi%d", count);
1542
            output_asm_insn(buf, operands);
1543
        }
1544
        else
1545
        {
1546
            output_asm_insn("dec %4", operands);
1547
 
1548
            sprintf(buf, "bgt movestrhi%d", count);
1549
            output_asm_insn(buf, NULL);
1550
        }
1551
 
1552
        count ++;
1553
        break;
1554
 
1555
      default:
1556
 
1557
        /*
1558
 
1559
           asr %4
1560
           asr %4
1561
           asr %4
1562
 
1563
           x:
1564
 
1565
           mov (%1)+, (%0)+
1566
           mov (%1)+, (%0)+
1567
           mov (%1)+, (%0)+
1568
           mov (%1)+, (%0)+
1569
 
1570
           if (TARGET_45)
1571
             sob %4, x
1572
           else
1573
             dec %4
1574
             bgt x
1575
        */
1576
 
1577
 
1578
        if (optimize_size)
1579
            goto generate_compact_code;
1580
 
1581
        output_asm_insn("asr %4", operands);
1582
        output_asm_insn("asr %4", operands);
1583
        output_asm_insn("asr %4", operands);
1584
 
1585
        sprintf(buf, "\nmovestrhi%d:", count);
1586
        output_asm_insn(buf, NULL);
1587
 
1588
        output_asm_insn("mov (%1)+, (%0)+", operands);
1589
        output_asm_insn("mov (%1)+, (%0)+", operands);
1590
        output_asm_insn("mov (%1)+, (%0)+", operands);
1591
        output_asm_insn("mov (%1)+, (%0)+", operands);
1592
 
1593
        if (TARGET_45)
1594
        {
1595
            sprintf(buf, "sob %%4, movestrhi%d", count);
1596
            output_asm_insn(buf, operands);
1597
        }
1598
        else
1599
        {
1600
            output_asm_insn("dec %4", operands);
1601
 
1602
            sprintf(buf, "bgt movestrhi%d", count);
1603
            output_asm_insn(buf, NULL);
1604
        }
1605
 
1606
        count ++;
1607
        break;
1608
 
1609
        ;
1610
 
1611
    }
1612
 
1613
    return "";
1614
}
1615
 
1616
int
1617
legitimate_address_p (enum machine_mode mode, rtx address)
1618
{
1619
/* #define REG_OK_STRICT */
1620
    GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
1621
 
1622
    return 0;
1623
 
1624
  win:
1625
    return 1;
1626
 
1627
/* #undef REG_OK_STRICT */
1628
}
1629
 
1630
/* This function checks whether a real value can be encoded as
1631
   a literal, i.e., addressing mode 27.  In that mode, real values
1632
   are one word values, so the remaining 48 bits have to be zero.  */
1633
int
1634
legitimate_const_double_p (rtx address)
1635
{
1636
  REAL_VALUE_TYPE r;
1637
  long sval[2];
1638
  REAL_VALUE_FROM_CONST_DOUBLE (r, address);
1639
  REAL_VALUE_TO_TARGET_DOUBLE (r, sval);
1640
  if ((sval[0] & 0xffff) == 0 && sval[1] == 0)
1641
    return 1;
1642
  return 0;
1643
}
1644
 
1645
/* A copy of output_addr_const modified for pdp11 expression syntax.
1646
   output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
1647
   use, and for debugging output, which we don't support with this port either.
1648
   So this copy should get called whenever needed.
1649
*/
1650
void
1651
output_addr_const_pdp11 (FILE *file, rtx x)
1652
{
1653
  char buf[256];
1654
 
1655
 restart:
1656
  switch (GET_CODE (x))
1657
    {
1658
    case PC:
1659
      gcc_assert (flag_pic);
1660
      putc ('.', file);
1661
      break;
1662
 
1663
    case SYMBOL_REF:
1664
      assemble_name (file, XSTR (x, 0));
1665
      break;
1666
 
1667
    case LABEL_REF:
1668
      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
1669
      assemble_name (file, buf);
1670
      break;
1671
 
1672
    case CODE_LABEL:
1673
      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
1674
      assemble_name (file, buf);
1675
      break;
1676
 
1677
    case CONST_INT:
1678
      /* Should we check for constants which are too big?  Maybe cutting
1679
         them off to 16 bits is OK?  */
1680
      fprintf (file, "%#ho", (unsigned short) INTVAL (x));
1681
      break;
1682
 
1683
    case CONST:
1684
      /* This used to output parentheses around the expression,
1685
         but that does not work on the 386 (either ATT or BSD assembler).  */
1686
      output_addr_const_pdp11 (file, XEXP (x, 0));
1687
      break;
1688
 
1689
    case CONST_DOUBLE:
1690
      if (GET_MODE (x) == VOIDmode)
1691
        {
1692
          /* We can use %o if the number is one word and positive.  */
1693
          gcc_assert (!CONST_DOUBLE_HIGH (x));
1694
          fprintf (file, "%#ho", (unsigned short) CONST_DOUBLE_LOW (x));
1695
        }
1696
      else
1697
        /* We can't handle floating point constants;
1698
           PRINT_OPERAND must handle them.  */
1699
        output_operand_lossage ("floating constant misused");
1700
      break;
1701
 
1702
    case PLUS:
1703
      /* Some assemblers need integer constants to appear last (e.g. masm).  */
1704
      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
1705
        {
1706
          output_addr_const_pdp11 (file, XEXP (x, 1));
1707
          if (INTVAL (XEXP (x, 0)) >= 0)
1708
            fprintf (file, "+");
1709
          output_addr_const_pdp11 (file, XEXP (x, 0));
1710
        }
1711
      else
1712
        {
1713
          output_addr_const_pdp11 (file, XEXP (x, 0));
1714
          if (INTVAL (XEXP (x, 1)) >= 0)
1715
            fprintf (file, "+");
1716
          output_addr_const_pdp11 (file, XEXP (x, 1));
1717
        }
1718
      break;
1719
 
1720
    case MINUS:
1721
      /* Avoid outputting things like x-x or x+5-x,
1722
         since some assemblers can't handle that.  */
1723
      x = simplify_subtraction (x);
1724
      if (GET_CODE (x) != MINUS)
1725
        goto restart;
1726
 
1727
      output_addr_const_pdp11 (file, XEXP (x, 0));
1728
      fprintf (file, "-");
1729
      if (GET_CODE (XEXP (x, 1)) == CONST_INT
1730
          && INTVAL (XEXP (x, 1)) < 0)
1731
        {
1732
          fprintf (file, targetm.asm_out.open_paren);
1733
          output_addr_const_pdp11 (file, XEXP (x, 1));
1734
          fprintf (file, targetm.asm_out.close_paren);
1735
        }
1736
      else
1737
        output_addr_const_pdp11 (file, XEXP (x, 1));
1738
      break;
1739
 
1740
    case ZERO_EXTEND:
1741
    case SIGN_EXTEND:
1742
      output_addr_const_pdp11 (file, XEXP (x, 0));
1743
      break;
1744
 
1745
    default:
1746
      output_operand_lossage ("invalid expression as operand");
1747
    }
1748
}
1749
 
1750
/* Worker function for TARGET_RETURN_IN_MEMORY.  */
1751
 
1752
static bool
1753
pdp11_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
1754
{
1755
  /* Should probably return DImode and DFmode in memory, lest
1756
     we fill up all regs!
1757
 
1758
     have to, else we crash - exception: maybe return result in
1759
     ac0 if DFmode and FPU present - compatibility problem with
1760
     libraries for non-floating point....  */
1761
  return (TYPE_MODE (type) == DImode
1762
          || (TYPE_MODE (type) == DFmode && ! TARGET_AC0));
1763
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.