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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [config/] [pdp11/] [pdp11.c] - Blame information for rev 12

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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