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

Subversion Repositories openrisc_me

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

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

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

powered by: WebSVN 2.1.0

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