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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [config/] [or32/] [or32.c] - Blame information for rev 820

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

Line No. Rev Author Line
1 38 julius
/* Subroutines for insn-output.c for GNU compiler.  OpenRISC 1000 version.
2
   Copyright (C) 1987, 1992, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
3
   2005  Free Software Foundation, Inc
4
   Contributed by Damjan Lampret <damjanl@bsemi.com> in 1999.
5
   Major optimizations by Matjaz Breskvar <matjazb@bsemi.com> in 2005.
6
 
7
This file is part of GNU CC.
8
 
9
GNU CC is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 1, or (at your option)
12
any later version.
13
 
14
GNU CC is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
GNU General Public License for more details.
18
 
19
You should have received a copy of the GNU General Public License
20
along with GNU CC; see the file COPYING.  If not, write to
21
the Free Software Foundation, 59 Temple Place - Suite 330,
22
Boston, MA 02111-1307, USA.  */
23
 
24
#include "config.h"
25
#include "system.h"
26
#include "coretypes.h"
27
#include "tm.h"
28
#include "rtl.h"
29
#include "tree.h"
30
#include "obstack.h"
31
#include "regs.h"
32
#include "hard-reg-set.h"
33
#include "real.h"
34
#include "insn-config.h"
35
#include "conditions.h"
36
#include "output.h"
37
#include "insn-attr.h"
38
#include "flags.h"
39
#include "reload.h"
40
#include "function.h"
41
#include "expr.h"
42
#include "optabs.h"
43
#include "toplev.h"
44
#include "recog.h"
45
#include "ggc.h"
46
#include "except.h"
47
#include "c-pragma.h"
48
#include "integrate.h"
49
#include "tm_p.h"
50
#include "target.h"
51
#include "target-def.h"
52
#include "debug.h"
53
#include "langhooks.h"
54
 
55
/* Set thist to nonzero if you want l.nop instruction in delay slot
56
   of l.jr instruction in epilogue. */
57
#define  NOP_DELAY_SLOT_FILL 0
58
 
59
/* This is the pseudo register number that holds the comparison flags */
60
 
61
#define FLAGS_REG 32
62
 
63
/* Save information from a "cmpxx" operation until the branch or scc is
64
   emitted.  */
65
rtx or32_compare_op0, or32_compare_op1;
66
 
67
/* used in function prologue/epilogue generation */
68
extern int leaf_function;
69
 
70
rtx or32_expand_compare (enum rtx_code code, rtx op0, rtx op1);
71
void output_ascii_pseudo_op (FILE *, const unsigned char *, int);
72
 
73
/* Local function prototypes */
74
static bool or32_save_reg_p (int regno);
75
HOST_WIDE_INT or32_compute_frame_size (HOST_WIDE_INT size);
76
static rtx emit_frame_insn (rtx insn);
77
static rtx indexed_memory (rtx base, HOST_WIDE_INT disp);
78
static int or32_emit_int_cmove (rtx dest, rtx op, rtx true_cond,
79
                                rtx false_cond);
80
 
81
static void or32_output_function_prologue (FILE * file, HOST_WIDE_INT vars);
82
#undef TARGET_ASM_FUNCTION_PROLOGUE
83
#define TARGET_ASM_FUNCTION_PROLOGUE or32_output_function_prologue
84
 
85
static void or32_output_function_epilogue (FILE * file, HOST_WIDE_INT vars);
86
#undef TARGET_ASM_FUNCTION_EPILOGUE
87
#define TARGET_ASM_FUNCTION_EPILOGUE or32_output_function_epilogue
88
 
89
static bool or32_function_ok_for_sibcall (tree decl, tree exp);
90
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
91
#define TARGET_FUNCTION_OK_FOR_SIBCALL or32_function_ok_for_sibcall
92
 
93
static bool or32_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);
94
#undef TARGET_PASS_BY_REFERENCE
95
#define TARGET_PASS_BY_REFERENCE or32_pass_by_reference
96
 
97
static int or32_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);
98
#undef TARGET_ARG_PARTIAL_BYTES
99
#define TARGET_ARG_PARTIAL_BYTES or32_arg_partial_bytes
100
 
101
/* Initialize the GCC target structure.  */
102
 
103
/* Define this macro if an argument declared as `char' or `short' in a
104
   prototype should actually be passed as an `int'.  In addition to
105
   avoiding errors in certain cases of mismatch, it also makes for
106
   better code on certain machines. */
107
#undef TARGET_PROMOTE_PROTOTYPES
108
#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
109
 
110
/* Define this if function arguments should also be promoted using the above
111
   procedure.  */
112
#undef TARGET_PROMOTE_FUNCTION_ARGS
113
#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
114
 
115
/* Likewise, if the function return value is promoted.  */
116
#undef TARGET_PROMOTE_FUNCTION_RETURN
117
#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
118
 
119
struct gcc_target targetm = TARGET_INITIALIZER;
120
 
121
/* Stack layout we use for pushing and poping saved registers */
122
struct or32_frame_info
123
{
124
  bool save_lr_p;
125
  int lr_save_offset;
126
  bool save_fp_p;
127
  int fp_save_offset;
128
  int gpr_size;
129
  int gpr_offset;
130
  int total_size;
131
  int vars_size;
132
  int args_size;
133
  HOST_WIDE_INT mask;
134
};
135
 
136
static struct or32_frame_info frame_info;
137
 
138
/* Add a REG_MAYBE_DEAD note to the insn.  */
139
static void
140
or32_maybe_dead (rtx insn)
141
{
142
  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
143
                                        const0_rtx, REG_NOTES (insn));
144
}
145
 
146
int
147
or32_print_operand_punct_valid_p (int code)
148
{
149
  switch (code)
150
    {
151
    case '(':                   /* idea taken from sparc; output nop for %( if
152
                                   not optimizing or the slot is not filled. */
153
    case '%':
154
      return 1;
155
    }
156
  return 0;
157
}
158
 
159
void
160
or32_print_operand_address (FILE * file, register rtx addr)
161
{
162
  register rtx reg1, reg2, breg, ireg;
163
  rtx offset;
164
 
165
  switch (GET_CODE (addr))
166
    {
167
    case MEM:
168
      if (GET_CODE (XEXP (addr, 0)) == REG)
169
        fprintf (file, "%s", reg_names[REGNO (addr)]);
170
      else
171
        abort ();
172
      break;
173
 
174
    case REG:
175
      fprintf (file, "0(%s)", reg_names[REGNO (addr)]);
176
      break;
177
 
178
    case PLUS:
179
      reg1 = 0;
180
      reg2 = 0;
181
      ireg = 0;
182
      breg = 0;
183
      offset = 0;
184
      if (GET_CODE (XEXP (addr, 0)) == REG)
185
        {
186
          offset = XEXP (addr, 1);
187
          addr = XEXP (addr, 0);
188
        }
189
      else if (GET_CODE (XEXP (addr, 1)) == REG)
190
        {
191
          offset = XEXP (addr, 0);
192
          addr = XEXP (addr, 1);
193
        }
194
      output_address (offset);
195
      fprintf (file, "(%s)", reg_names[REGNO (addr)]);
196
      break;
197
 
198
    default:
199
      /* fprintf(file, "{%d}", GET_CODE (addr)); */
200
      output_addr_const (file, addr);
201
    }
202
}
203
 
204
/* Calulcate and return stack size for current function.  */
205
static int
206
calculate_stack_size (int vars, int *lr_save_area,
207
                      int *fp_save_area, int *gpr_save_area, int *save_area)
208
{
209
  int regno;
210
 
211
  *gpr_save_area = 0;
212
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
213
    {
214
      if (regs_ever_live[regno] && !call_used_regs[regno])
215
        *gpr_save_area += 4;
216
    }
217
 
218
  *lr_save_area = (!current_function_is_leaf
219
                   || regs_ever_live[LINK_REGNUM]) ? 4 : 0;
220
  *fp_save_area = frame_pointer_needed ? 4 : 0;
221
 
222
  *save_area = (OR32_ALIGN (current_function_outgoing_args_size, 4)
223
                + *lr_save_area + *fp_save_area);
224
 
225
  return
226
    (OR32_ALIGN (current_function_outgoing_args_size, 4)
227
     + *lr_save_area + *fp_save_area + *gpr_save_area + OR32_ALIGN (vars, 4));
228
}
229
 
230
/* Set up the stack and frame pointer (if desired) for the
231
   function.  */
232
static void
233
or32_output_function_prologue (FILE * file, HOST_WIDE_INT vars)
234
{
235
  int save_area;
236
  int gpr_save_area;
237
  int lr_save_area;
238
  int fp_save_area;
239
  int stack_size;
240
  int regno;
241
 
242
  if (TARGET_MASK_SCHED_LOGUE)
243
    return;
244
 
245
#if 0
246
  save_area = 0;
247
 
248
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
249
    {
250
      if (regs_ever_live[regno] && !call_used_regs[regno])
251
        {
252
          save_area += 1;
253
        }
254
    }
255
 
256
  if (save_area != 0)
257
    fprintf (file, "\tl.nop \t0x%x\n", 0x100 + save_area);
258
 
259
  return;
260
#endif
261
 
262
  if (vars < 0)
263
    abort ();
264
 
265
  stack_size = calculate_stack_size
266
    (vars, &lr_save_area, &fp_save_area, &gpr_save_area, &save_area);
267
 
268
  fprintf (file,
269
           "\n\t# gpr_save_area %d vars %ld current_function_outgoing_args_size %d\n",
270
           gpr_save_area, vars, current_function_outgoing_args_size);
271
 
272
  if (stack_size >= 0x8000)
273
    {
274
      fprintf (file, "\tl.movhi   \tr%d,hi(%d)\n", GP_ARG_RETURN, stack_size);
275
      fprintf (file, "\tl.ori   \tr%d,r%d,lo(%d)\n", GP_ARG_RETURN,
276
               GP_ARG_RETURN, stack_size);
277
      fprintf (file, "\tl.sub   \tr%d,r%d,r%d\n", STACK_POINTER_REGNUM,
278
               STACK_POINTER_REGNUM, GP_ARG_RETURN);
279
    }
280
  else if (stack_size > 0)
281
    {
282
      fprintf (file, "\tl.addi   \tr%d,r%d,%d\n", STACK_POINTER_REGNUM,
283
               STACK_POINTER_REGNUM, -stack_size);
284
    }
285
 
286
  if (fp_save_area)
287
    {
288
      fprintf (file, "\tl.sw     \t%d(r%d),r%d\n",
289
               OR32_ALIGN (current_function_outgoing_args_size, 4)
290
               + lr_save_area, STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM);
291
      if (stack_size >= 0x8000)
292
        fprintf (file, "\tl.add   \tr%d,r%d,r%d\n", FRAME_POINTER_REGNUM,
293
                 STACK_POINTER_REGNUM, GP_ARG_RETURN);
294
      else
295
        fprintf (file, "\tl.addi   \tr%d,r%d,%d\n", FRAME_POINTER_REGNUM,
296
                 STACK_POINTER_REGNUM, stack_size);
297
    }
298
 
299
  if (lr_save_area)
300
    {
301
      fprintf (file, "\tl.sw     \t%d(r%d),r%d\n",
302
               OR32_ALIGN (current_function_outgoing_args_size, 4),
303
               STACK_POINTER_REGNUM, LINK_REGNUM);
304
    }
305
 
306
  save_area = (OR32_ALIGN (current_function_outgoing_args_size, 4)
307
               + lr_save_area + fp_save_area);
308
 
309
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
310
    {
311
      if (regs_ever_live[regno] && !call_used_regs[regno])
312
        {
313
          fprintf (file, "\tl.sw    \t%d(r%d),r%d\n", save_area,
314
                   STACK_POINTER_REGNUM, regno);
315
          save_area += 4;
316
        }
317
    }
318
}
319
 
320
/* Do any necessary cleanup after a function to restore stack, frame,
321
   and regs.  */
322
static void
323
or32_output_function_epilogue (FILE * file, HOST_WIDE_INT vars)
324
{
325
  int save_area;
326
  int gpr_save_area;
327
  int lr_save_area;
328
  int fp_save_area;
329
  int stack_size;
330
  int regno;
331
 
332
  if (TARGET_MASK_SCHED_LOGUE)
333
    return;
334
 
335
#if 0
336
  save_area = 0;
337
 
338
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
339
    {
340
      if (regs_ever_live[regno] && !call_used_regs[regno])
341
        {
342
          save_area += 1;
343
        }
344
    }
345
 
346
  fprintf (file, "\tl.nop \t0x%x\n", 0x200 + save_area);
347
  return;
348
#endif
349
 
350
  stack_size = calculate_stack_size
351
    (vars, &lr_save_area, &fp_save_area, &gpr_save_area, &save_area);
352
 
353
  if (lr_save_area)
354
    {
355
      fprintf (file, "\tl.lwz    \tr%d,%d(r%d)\n", LINK_REGNUM,
356
               OR32_ALIGN (current_function_outgoing_args_size, 4),
357
               STACK_POINTER_REGNUM);
358
    }
359
  if (fp_save_area)
360
    {
361
      fprintf (file, "\tl.lwz    \tr%d,%d(r%d)\n", FRAME_POINTER_REGNUM,
362
               OR32_ALIGN (current_function_outgoing_args_size, 4)
363
               + lr_save_area, STACK_POINTER_REGNUM);
364
    }
365
  save_area = (OR32_ALIGN (current_function_outgoing_args_size, 4)
366
               + lr_save_area + fp_save_area);
367
 
368
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
369
    {
370
      if (regs_ever_live[regno] && !call_used_regs[regno])
371
        {
372
          fprintf (file, "\tl.lwz    \tr%d,%d(r%d)\n", regno, save_area,
373
                   STACK_POINTER_REGNUM);
374
          save_area += 4;
375
        }
376
    }
377
 
378
  if (stack_size >= 0x8000)
379
    {
380
      fprintf (file, "\tl.movhi   \tr3,hi(%d)\n", stack_size);
381
      fprintf (file, "\tl.ori   \tr3,r3,lo(%d)\n", stack_size);
382
 
383
      if (!TARGET_MASK_ALIGNED_JUMPS)
384
        fprintf (file, "\tl.jr  \tr%d\n", LINK_REGNUM);
385
      else
386
        fprintf (file, "\t.balignl 0x8,0x15000015,0x4;l.jr  \tr%d\n",
387
                 LINK_REGNUM);
388
 
389
      fprintf (file, "\tl.add   \tr%d,r%d,r3\n", STACK_POINTER_REGNUM,
390
               STACK_POINTER_REGNUM);
391
    }
392
  else if (stack_size > 0)
393
    {
394
      if (!TARGET_MASK_ALIGNED_JUMPS)
395
        fprintf (file, "\tl.jr  \tr%d\n", LINK_REGNUM);
396
      else
397
        fprintf (file, "\t.balignl 0x8,0x15000015,0x4;l.jr  \tr%d\n",
398
                 LINK_REGNUM);
399
 
400
      fprintf (file, "\tl.addi   \tr%d,r%d,%d\n", STACK_POINTER_REGNUM,
401
               STACK_POINTER_REGNUM, stack_size);
402
    }
403
  else
404
    {
405
      if (!TARGET_MASK_ALIGNED_JUMPS)
406
        fprintf (file, "\tl.jr  \tr%d\n", LINK_REGNUM);
407
      else
408
        fprintf (file, "\t.balignl 0x8,0x15000015,0x4;l.jr  \tr%d\n",
409
                 LINK_REGNUM);
410
 
411
      fprintf (file, "\tl.nop\n");
412
    }
413
 
414
#if 0
415
  fprintf (file, ".endproc _%s\n", get_function_name ());
416
#endif
417
}
418
 
419
/* Compuate full frame size and layout.  SIZE is the size of the
420
   functions local variables.  Store information in FRAME_INFO and
421
   return total size of stack frame.  */
422
 
423
HOST_WIDE_INT
424
or32_compute_frame_size (HOST_WIDE_INT size)
425
{
426
  HOST_WIDE_INT args_size;
427
  HOST_WIDE_INT vars_size;
428
  HOST_WIDE_INT stack_offset;
429
  int regno;
430
 
431
  args_size = current_function_outgoing_args_size;
432
  vars_size = OR32_ALIGN (size, 4);
433
 
434
  frame_info.args_size = args_size;
435
  frame_info.vars_size = vars_size;
436
 
437
  /* If the function has local variables, we're committed to
438
     allocating it anyway.  Otherwise reclaim it here.  */
439
  /* FIXME: Verify this.  Got if from the MIPS port.  */
440
  if (vars_size == 0 && current_function_is_leaf)
441
    args_size = 0;
442
 
443
  stack_offset = args_size;
444
 
445
  /* Save link register right after possible outgoing arguments.  */
446
  if (or32_save_reg_p (LINK_REGNUM))
447
    {
448
      frame_info.lr_save_offset = stack_offset;
449
      frame_info.save_lr_p = true;
450
      stack_offset = stack_offset + UNITS_PER_WORD;
451
    }
452
  else
453
    frame_info.save_lr_p = false;
454
 
455
  /* Save frame pointer right after possible link register.  */
456
  if (or32_save_reg_p (FRAME_POINTER_REGNUM))
457
    {
458
      frame_info.fp_save_offset = stack_offset;
459
      frame_info.save_fp_p = true;
460
      stack_offset = stack_offset + UNITS_PER_WORD;
461
    }
462
  else
463
    frame_info.save_fp_p = false;
464
 
465
  frame_info.gpr_size = 0;
466
  frame_info.mask = 0;
467
  frame_info.gpr_offset = stack_offset;
468
 
469
  for (regno = 0; regno <= LAST_INT_REG; regno++)
470
    {
471
      if (regno == LINK_REGNUM || regno == FRAME_POINTER_REGNUM)
472
        /* These has already been saved if so needed.  */
473
        continue;
474
 
475
      if (or32_save_reg_p (regno))
476
        {
477
          frame_info.gpr_size += UNITS_PER_WORD;
478
          frame_info.mask |= (1 << regno);
479
        }
480
    }
481
 
482
  frame_info.total_size = ((frame_info.save_fp_p ? UNITS_PER_WORD : 0)
483
                           + (frame_info.save_lr_p ? UNITS_PER_WORD : 0)
484
                           + args_size + frame_info.gpr_size + vars_size);
485
 
486
  return frame_info.total_size;
487
}
488
 
489
 
490
/* Return true if current function must save REGNO.  */
491
static bool
492
or32_save_reg_p (int regno)
493
{
494
  /* No need to save the faked cc0 register.  */
495
  if (regno == FLAGS_REG)
496
    return false;
497
 
498
  /* Check call-saved registers.  */
499
  if (regs_ever_live[regno] && !call_used_regs[regno])
500
    return true;
501
 
502
  /* We need to save the old frame pointer before setting up a new
503
     one.  */
504
  if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)
505
    return true;
506
 
507
  /* We need to save the incoming return address if it is ever clobbered
508
     within the function.  */
509
  if (regno == LINK_REGNUM && regs_ever_live[regno])
510
    return true;
511
 
512
  return false;
513
}
514
 
515
/* Emit a frame related insn.  Same as emit_insn, but sets
516
   RTX_FRAME_RELATED_P to one.  */
517
 
518
static rtx
519
emit_frame_insn (rtx insn)
520
{
521
  insn = emit_insn (insn);
522
  RTX_FRAME_RELATED_P (insn) = 1;
523
  return (insn);
524
}
525
 
526
static rtx
527
indexed_memory (rtx base, HOST_WIDE_INT disp)
528
{
529
  return gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, base, GEN_INT (disp)));
530
}
531
 
532
/* Called after register allocation to add any instructions needed for
533
   the prologue.  Using a prologue insn is favored compared to putting
534
   all of the instructions in output_function_prologue(), since it
535
   allows the scheduler to intermix instructions with the saves of the
536
   caller saved registers.  In some cases, it might be necessary to
537
   emit a barrier instruction as the last insn to prevent such
538
   scheduling.  */
539
 
540
void
541
or32_expand_prologue (void)
542
{
543
  int total_size = or32_compute_frame_size (get_frame_size ());
544
  rtx sp_rtx;
545
  rtx value_rtx;
546
 
547
  if (!total_size)
548
    /* No frame needed.  */
549
    return;
550
 
551
  sp_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
552
 
553
  if (total_size > 32767)
554
    {
555
      value_rtx = gen_rtx_REG (Pmode, GP_ARG_RETURN);
556
      emit_frame_insn (gen_rtx_SET (Pmode, value_rtx, GEN_INT (total_size)));
557
    }
558
  else
559
    value_rtx = GEN_INT (total_size);
560
 
561
  /* Update the stack pointer to reflect frame size.  */
562
  emit_frame_insn
563
    (gen_rtx_SET (Pmode, stack_pointer_rtx,
564
                  gen_rtx_MINUS (Pmode, stack_pointer_rtx, value_rtx)));
565
 
566
  if (frame_info.save_fp_p)
567
    {
568
      emit_frame_insn
569
        (gen_rtx_SET (Pmode,
570
                      indexed_memory (stack_pointer_rtx,
571
                                      frame_info.fp_save_offset),
572
                      frame_pointer_rtx));
573
 
574
      emit_frame_insn
575
        (gen_rtx_SET (Pmode, frame_pointer_rtx,
576
                      gen_rtx_PLUS (Pmode, frame_pointer_rtx, value_rtx)));
577
    }
578
  if (frame_info.save_lr_p)
579
    {
580
 
581
      emit_frame_insn
582
        (gen_rtx_SET (Pmode,
583
                      indexed_memory (stack_pointer_rtx,
584
                                      frame_info.lr_save_offset),
585
                      gen_rtx_REG (Pmode, LINK_REGNUM)));
586
    }
587
  if (frame_info.gpr_size)
588
    {
589
      int offset = 0;
590
      int regno;
591
 
592
      for (regno = 0; regno <= LAST_INT_REG; regno++)
593
        {
594
          HOST_WIDE_INT disp = frame_info.gpr_offset + offset;
595
 
596
          if (!(frame_info.mask & (1 << regno)))
597
            continue;
598
 
599
          emit_frame_insn
600
            (gen_rtx_SET (Pmode,
601
                          indexed_memory (stack_pointer_rtx, disp),
602
                          gen_rtx_REG (Pmode, regno)));
603
          offset = offset + UNITS_PER_WORD;
604
        }
605
    }
606
}
607
 
608
/* Called after register allocation to add any instructions needed for
609
   the epilogue.  Using an epilogue insn is favored compared to
610
   putting all of the instructions in output_function_epilogue(),
611
   since it allows the scheduler to intermix instructions with the
612
   restores of the caller saved registers.  In some cases, it might be
613
   necessary to emit a barrier instruction as the first insn to
614
   prevent such scheduling.  */
615
 
616
void
617
or32_expand_epilogue (int sibcall)
618
{
619
  int total_size = or32_compute_frame_size (get_frame_size ());
620
  rtx value_rtx;
621
 
622
  if (total_size > 32767)
623
    {
624
      value_rtx = gen_rtx_REG (Pmode, 3);
625
 
626
      emit_insn (gen_rtx_SET (Pmode, value_rtx, GEN_INT (total_size)));
627
    }
628
  else
629
    value_rtx = GEN_INT (total_size);
630
 
631
  if (frame_info.save_lr_p)
632
    {
633
      or32_maybe_dead
634
        (emit_insn
635
         (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, LINK_REGNUM),
636
                       indexed_memory (stack_pointer_rtx,
637
                                       frame_info.lr_save_offset))));
638
    }
639
  if (frame_info.save_fp_p)
640
    {
641
      emit_insn
642
        (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),
643
                      indexed_memory (stack_pointer_rtx,
644
                                      frame_info.fp_save_offset)));
645
    }
646
 
647
  if (frame_info.gpr_size)
648
    {
649
      int offset = 0;
650
      int regno;
651
 
652
      for (regno = 0; regno <= LAST_INT_REG; regno++)
653
        {
654
          HOST_WIDE_INT disp = frame_info.gpr_offset + offset;
655
 
656
          if (!(frame_info.mask & (1 << regno)))
657
            continue;
658
 
659
          emit_insn
660
            (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, regno),
661
                          indexed_memory (stack_pointer_rtx, disp)));
662
          offset = offset + UNITS_PER_WORD;
663
        }
664
    }
665
 
666
  if (total_size)
667
    {
668
      emit_insn (gen_rtx_SET (Pmode, stack_pointer_rtx,
669
                              gen_rtx_PLUS (Pmode,
670
                                            stack_pointer_rtx, value_rtx)));
671
    }
672
 
673
  if (!sibcall)
674
    emit_jump_insn (gen_return_internal (gen_rtx_REG( Pmode, 9)));
675
}
676
 
677
 
678
void
679
or32_print_operand (FILE * file, rtx x, int code)
680
{
681
  if (code == 'r' && GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == REG)
682
    fprintf (file, "%s", reg_names[REGNO (XEXP (x, 0))]);
683
  else if (code == '(')
684
    {
685
      if (dbr_sequence_length ())
686
        fprintf (file, "\t# delay slot filled");
687
      else
688
        fprintf (file, "\n\tl.nop\t\t\t# nop delay slot");
689
    }
690
  else if (code == 'C')
691
    {
692
      switch (GET_CODE (x))
693
        {
694
        case EQ:
695
          fputs ("eq", file);
696
          break;
697
        case NE:
698
          fputs ("ne", file);
699
          break;
700
        case GT:
701
          fputs ("gts", file);
702
          break;
703
        case GE:
704
          fputs ("ges", file);
705
          break;
706
        case LT:
707
          fputs ("lts", file);
708
          break;
709
        case LE:
710
          fputs ("les", file);
711
          break;
712
        case GTU:
713
          fputs ("gtu", file);
714
          break;
715
        case GEU:
716
          fputs ("geu", file);
717
          break;
718
        case LTU:
719
          fputs ("ltu", file);
720
          break;
721
        case LEU:
722
          fputs ("leu", file);
723
          break;
724
        default:
725
          abort ();
726
        }
727
    }
728
  else if (code == 'H')
729
    {
730
      if (GET_CODE (x) == REG)
731
        fprintf (file, "%s", reg_names[REGNO (x) + 1]);
732
      else
733
        abort ();
734
    }
735
  else if (GET_CODE (x) == REG)
736
    fprintf (file, "%s", reg_names[REGNO (x)]);
737
  else if (GET_CODE (x) == MEM)
738
    output_address (XEXP (x, 0));
739
  else
740
    output_addr_const (file, x);
741
}
742
 
743
/* Generate assembler code for a movdi/movdf */
744
 
745
const char *
746
or32_output_move_double (rtx * operands)
747
{
748
  rtx xoperands[3];
749
 
750
  switch (GET_CODE (operands[0]))
751
    {
752
    case REG:
753
      if (GET_CODE (operands[1]) == REG)
754
        {
755
          if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
756
            {
757
              output_asm_insn ("\tl.or    \t%H0, %H1, r0", operands);
758
              output_asm_insn ("\tl.or    \t%0, %1, r0", operands);
759
              return "";
760
            }
761
          else
762
            {
763
              output_asm_insn ("\tl.or    \t%0, %1, r0", operands);
764
              output_asm_insn ("\tl.or    \t%H0, %H1, r0", operands);
765
              return "";
766
            }
767
        }
768
      else if (GET_CODE (operands[1]) == MEM)
769
        {
770
          xoperands[1] = XEXP (operands[1], 0);
771
          if (GET_CODE (xoperands[1]) == REG)
772
            {
773
              xoperands[0] = operands[0];
774
              if (REGNO (xoperands[0]) == REGNO (xoperands[1]))
775
                {
776
                  output_asm_insn ("\tl.lwz   \t%H0, 4(%1)", xoperands);
777
                  output_asm_insn ("\tl.lwz   \t%0, 0(%1)", xoperands);
778
                  return "";
779
                }
780
              else
781
                {
782
                  output_asm_insn ("\tl.lwz   \t%0, 0(%1)", xoperands);
783
                  output_asm_insn ("\tl.lwz   \t%H0, 4(%1)", xoperands);
784
                  return "";
785
                }
786
            }
787
          else if (GET_CODE (xoperands[1]) == PLUS)
788
            {
789
              if (GET_CODE (xoperands[2] = XEXP (xoperands[1], 1)) == REG)
790
                {
791
                  xoperands[0] = operands[0];
792
                  xoperands[1] = XEXP (xoperands[1], 0);
793
                  if (REGNO (xoperands[0]) == REGNO (xoperands[2]))
794
                    {
795
                      output_asm_insn ("\tl.lwz   \t%H0, %1+4(%2)",
796
                                       xoperands);
797
                      output_asm_insn ("\tl.lwz   \t%0, %1(%2)", xoperands);
798
                      return "";
799
                    }
800
                  else
801
                    {
802
                      output_asm_insn ("\tl.lwz   \t%0, %1(%2)", xoperands);
803
                      output_asm_insn ("\tl.lwz   \t%H0, %1+4(%2)",
804
                                       xoperands);
805
                      return "";
806
                    }
807
                }
808
              else if (GET_CODE (xoperands[2] = XEXP (xoperands[1], 0)) ==
809
                       REG)
810
                {
811
                  xoperands[0] = operands[0];
812
                  xoperands[1] = XEXP (xoperands[1], 1);
813
                  if (REGNO (xoperands[0]) == REGNO (xoperands[2]))
814
                    {
815
                      output_asm_insn ("\tl.lwz   \t%H0, %1+4(%2)",
816
                                       xoperands);
817
                      output_asm_insn ("\tl.lwz   \t%0, %1(%2)", xoperands);
818
                      return "";
819
                    }
820
                  else
821
                    {
822
                      output_asm_insn ("\tl.lwz   \t%0, %1(%2)", xoperands);
823
                      output_asm_insn ("\tl.lwz   \t%H0, %1+4(%2)",
824
                                       xoperands);
825
                      return "";
826
                    }
827
                }
828
              else
829
                abort ();
830
            }
831
          else
832
            abort ();
833
        }
834
      else if (GET_CODE (operands[1]) == CONST_INT)
835
        {
836
          if (INTVAL (operands[1]) < 0)
837
            output_asm_insn ("\tl.addi  \t%0, r0, -1", operands);
838
          else
839
            output_asm_insn ("\tl.or    \t%0, r0, r0", operands);
840
          output_asm_insn ("\tl.movhi \t%H0, hi(%1)", operands);
841
          output_asm_insn ("\tl.ori   \t%H0, %H0, lo(%1)", operands);
842
          return "";
843
        }
844
      else
845
        abort ();
846
    case MEM:
847
      xoperands[0] = XEXP (operands[0], 0);
848
      if (GET_CODE (xoperands[0]) == REG)
849
        {
850
          xoperands[1] = operands[1];
851
          output_asm_insn ("\tl.sw    \t0(%0), %1", xoperands);
852
          output_asm_insn ("\tl.sw    \t4(%0), %H1", xoperands);
853
          return "";
854
        }
855
      else if (GET_CODE (xoperands[0]) == PLUS)
856
        {
857
          if (GET_CODE (xoperands[1] = XEXP (xoperands[0], 1)) == REG)
858
            {
859
              xoperands[0] = XEXP (xoperands[0], 0);
860
              xoperands[2] = operands[1];
861
              output_asm_insn ("\tl.sw    \t%0(%1), %2", xoperands);
862
              output_asm_insn ("\tl.sw    \t%0+4(%1), %H2", xoperands);
863
              return "";
864
            }
865
          else if (GET_CODE (xoperands[1] = XEXP (xoperands[0], 0)) == REG)
866
            {
867
              xoperands[0] = XEXP (xoperands[0], 1);
868
              xoperands[2] = operands[1];
869
              output_asm_insn ("\tl.sw    \t%0(%1), %2", xoperands);
870
              output_asm_insn ("\tl.sw    \t%0+4(%1), %H2", xoperands);
871
              return "";
872
            }
873
          else
874
            abort ();
875
        }
876
      else
877
        abort ();
878
    default:
879
      abort ();
880
    }
881
}
882
 
883
enum rtx_code
884
or32_reverse_condition (enum machine_mode mode ATTRIBUTE_UNUSED,
885
                        enum rtx_code code)
886
{
887
  return reverse_condition (code);
888
}
889
 
890
enum machine_mode
891
or32_cc_mode (enum rtx_code code,
892
              rtx op0 ATTRIBUTE_UNUSED, rtx op1 ATTRIBUTE_UNUSED)
893
{
894
 
895
  switch (code)
896
    {
897
    case EQ:
898
      return CCEQmode;
899
    case NE:
900
      return CCNEmode;
901
    case GEU:
902
      return CCGEUmode;
903
    case GTU:
904
      return CCGTUmode;
905
    case LTU:
906
      return CCLTUmode;
907
    case LEU:
908
      return CCLEUmode;
909
    case GE:
910
      return CCGEmode;
911
    case LT:
912
      return CCLTmode;
913
    case GT:
914
      return CCGTmode;
915
    case LE:
916
      return CCLEmode;
917
 
918
    default:
919
      abort ();
920
    }
921
}
922
 
923
/* Generate insn patterns to do an integer compare of OPERANDS.  */
924
 
925
static rtx
926
or32_expand_int_compare (enum rtx_code code, rtx op0, rtx op1)
927
{
928
  enum machine_mode cmpmode;
929
  rtx tmp, flags;
930
 
931
  cmpmode = SELECT_CC_MODE (code, op0, op1);
932
  flags = gen_rtx_REG (cmpmode, FLAGS_REG);
933
 
934
  /* This is very simple, but making the interface the same as in the
935
     FP case makes the rest of the code easier.  */
936
  tmp = gen_rtx_COMPARE (cmpmode, op0, op1);
937
  emit_insn (gen_rtx_SET (VOIDmode, flags, tmp));
938
 
939
  /* Return the test that should be put into the flags user, i.e.
940
     the bcc, scc, or cmov instruction.  */
941
  return gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
942
}
943
 
944
rtx
945
or32_expand_compare (enum rtx_code code, rtx op0, rtx op1)
946
{
947
  return or32_expand_int_compare (code, op0, op1);
948
}
949
 
950
void
951
or32_expand_branch (enum rtx_code code, rtx label)
952
{
953
  rtx tmp;
954
 
955
  switch (GET_MODE (or32_compare_op0))
956
    {
957
    case SImode:
958
      tmp = or32_expand_compare (code, or32_compare_op0, or32_compare_op1);
959
      tmp = gen_rtx_IF_THEN_ELSE (VOIDmode,
960
                                  tmp,
961
                                  gen_rtx_LABEL_REF (VOIDmode, label),
962
                                  pc_rtx);
963
      emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
964
      return;
965 133 jeremybenn
 
966
    case SFmode:
967
      tmp = or32_expand_compare (code, or32_compare_op0, or32_compare_op1);
968
      tmp = gen_rtx_IF_THEN_ELSE (VOIDmode,
969
                                  tmp,
970
                                  gen_rtx_LABEL_REF (VOIDmode, label),
971
                                  pc_rtx);
972
      emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
973
      return;
974
 
975 38 julius
    default:
976
      abort ();
977
    }
978
 
979
}
980
 
981
static int
982
or32_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
983
{
984
  rtx condition_rtx, cr;
985
 
986
  if ((GET_MODE (or32_compare_op0) != SImode) &&
987
      (GET_MODE (or32_compare_op0) != HImode) &&
988
      (GET_MODE (or32_compare_op0) != QImode))
989
    return 0;
990
 
991
  /* We still have to do the compare, because cmov doesn't do a
992
     compare, it just looks at the FLAG bit set by a previous compare
993
     instruction.  */
994
 
995
  condition_rtx = or32_expand_compare (GET_CODE (op),
996
                                       or32_compare_op0, or32_compare_op1);
997
 
998
  cr = XEXP (condition_rtx, 0);
999
 
1000
  emit_insn (gen_cmov (dest, condition_rtx, true_cond, false_cond, cr));
1001
 
1002
  return 1;
1003
}
1004
 
1005
 
1006
/* Emit a conditional move: move TRUE_COND to DEST if OP of the
1007
   operands of the last comparison is nonzero/true, FALSE_COND if it
1008
   is zero/false.  Return 0 if the hardware has no such operation.  */
1009
 
1010
int
1011
or32_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
1012
{
1013
  enum machine_mode result_mode = GET_MODE (dest);
1014
 
1015
  if (GET_MODE (true_cond) != result_mode)
1016
    return 0;
1017
 
1018
  if (GET_MODE (false_cond) != result_mode)
1019
    return 0;
1020
 
1021
  /* First, work out if the hardware can do this at all */
1022
  return or32_emit_int_cmove (dest, op, true_cond, false_cond);
1023
}
1024
 
1025
const char *
1026
or32_output_bf (rtx * operands)
1027
{
1028
  enum rtx_code code;
1029
  enum machine_mode mode_calc, mode_got;
1030
 
1031
  code = GET_CODE (operands[1]);
1032
  mode_calc = SELECT_CC_MODE (code, or32_compare_op0, or32_compare_op1);
1033
  mode_got = GET_MODE (operands[2]);
1034
 
1035
  if (!TARGET_MASK_ALIGNED_JUMPS)
1036
    {
1037
      if (mode_calc != mode_got)
1038
        return "l.bnf   \t%l0%(";
1039
      else
1040
        return "l.bf    \t%l0%(";
1041
    }
1042
  else
1043
    {
1044
      if (mode_calc != mode_got)
1045
        return "\t.balignl 0x8,0x15000015,0x4;l.bnf   \t%l0%(";
1046
      else
1047
        return "\t.balignl 0x8,0x15000015,0x4;l.bf    \t%l0%(";
1048
    }
1049
}
1050
 
1051
const char *
1052
or32_output_cmov (rtx * operands)
1053
{
1054
  enum rtx_code code;
1055
  enum machine_mode mode_calc, mode_got;
1056
 
1057
  code = GET_CODE (operands[1]);
1058
  mode_calc = SELECT_CC_MODE (code, or32_compare_op0, or32_compare_op1);
1059
  mode_got = GET_MODE (operands[4]);
1060
 
1061
  if (mode_calc != mode_got)
1062
    return "l.cmov  \t%0,%3,%2";        /* reversed */
1063
  else
1064
    return "l.cmov  \t%0,%2,%3";
1065
}
1066
 
1067
/* Any function is ok for sibcall optimization if we allow this optimization
1068
 */
1069
static bool
1070
or32_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
1071
                              tree exp ATTRIBUTE_UNUSED)
1072
{
1073
  return TARGET_MASK_SIBCALL;
1074
}
1075
 
1076
/* All aggregates and arguments greater than 8 bytes are passed this way.  */
1077
static bool
1078
or32_pass_by_reference (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED,
1079
                        enum machine_mode mode ATTRIBUTE_UNUSED,
1080
                                          tree type, bool named ATTRIBUTE_UNUSED)
1081
{
1082
  return (type && (AGGREGATE_TYPE_P (type) || int_size_in_bytes (type) > 8));
1083
}
1084
 
1085
static int
1086
or32_arg_partial_bytes (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED,
1087
                        enum machine_mode mode ATTRIBUTE_UNUSED,
1088
                        tree type ATTRIBUTE_UNUSED,
1089
                        bool named ATTRIBUTE_UNUSED)
1090
{
1091
  return 0;
1092
}
1093
 
1094
/* For now this is very simple way for sibcall support */
1095
 
1096
void
1097
or32_expand_sibcall (rtx result ATTRIBUTE_UNUSED, rtx addr, rtx args_size)
1098
{
1099
  emit_call_insn (gen_sibcall_internal (addr, args_size));
1100
}
1101
 
1102
 
1103
/* We know it can't be done in one insn when we get here,
1104
   the movsi expander guarantees this.  */
1105
void
1106
or32_emit_set_const32 (rtx op0, rtx op1)
1107
{
1108
  enum machine_mode mode = GET_MODE (op0);
1109
  rtx temp;
1110
 
1111
 
1112
  if (GET_CODE (op1) == CONST_INT)
1113
    {
1114
      if (CONST_OK_FOR_LETTER_P (INTVAL (op1) & GET_MODE_MASK (mode), 'K') ||
1115
                CONST_OK_FOR_LETTER_P (INTVAL (op1), 'M') ||
1116
                CONST_OK_FOR_LETTER_P (INTVAL (op1), 'I'))
1117
        abort ();
1118
    }
1119
 
1120
 
1121
  /* Full 2-insn decomposition is needed.  */
1122
  if (reload_in_progress || reload_completed)
1123
    temp = op0;
1124
  else
1125
    temp = gen_reg_rtx (mode);
1126
 
1127
  if (GET_CODE (op1) == CONST_INT)
1128
    {
1129
      /* Emit them as real moves instead of a HIGH/LO_SUM,
1130
         this way CSE can see everything and reuse intermediate
1131
         values if it wants.  */
1132
      emit_insn (gen_rtx_SET (VOIDmode, temp,
1133
                              GEN_INT (INTVAL (op1)
1134
                                       & ~(HOST_WIDE_INT) 0xffff)));
1135
 
1136
      emit_insn (gen_rtx_SET (VOIDmode,
1137
                              op0,
1138
                              gen_rtx_IOR (mode, temp,
1139
                                           GEN_INT (INTVAL (op1) & 0xffff))));
1140
    }
1141
  else
1142
    {
1143
 
1144
#if 0
1145
      /* A symbol, emit in the traditional way.  */
1146
 
1147
      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_HIGH (mode, op1)));
1148
      emit_insn (gen_rtx_SET (VOIDmode,
1149
                              op0, gen_rtx_LO_SUM (mode, temp, op1)));
1150
#else
1151
      /* since or32 bfd can not deal with relocs that are not of type
1152
         OR32_CONSTH_RELOC + OR32_CONST_RELOC (ie move high must be
1153
         followed by exactly one lo_sum)
1154
       */
1155
      emit_insn (gen_movsi_insn_big (op0, op1));
1156
#endif
1157
    }
1158
}
1159
 
1160
 
1161
/* Functions returning costs and making code size/performance tradeoffs */
1162
 
1163
int
1164
or32_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
1165
                         enum reg_class from ATTRIBUTE_UNUSED,
1166
                         enum reg_class to ATTRIBUTE_UNUSED)
1167
{
1168
  return 2;
1169
}
1170
 
1171
/* A C expressions returning the cost of moving data of MODE from a register to
1172
   or from memory.  */
1173
 
1174
int
1175
or32_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
1176
                       enum reg_class class ATTRIBUTE_UNUSED,
1177
                       int in ATTRIBUTE_UNUSED)
1178
{
1179
  return 2;
1180
}
1181
 
1182
/* Specify the cost of a branch insn; roughly the number of extra insns that
1183
   should be added to avoid a branch.
1184
 
1185
   Set this to 3 on the or32 since that is roughly the average cost of an
1186
   unscheduled conditional branch.
1187
 
1188
   Cost of 2 and 3 give equal and ~0.7% bigger binaries
1189
 
1190
*/
1191
int
1192
or32_branch_cost (void)
1193
{
1194
  return 2;
1195
}
1196
 
1197
/* Stolen from ../arm/arm.c */
1198
#define MAX_ASCII_LEN 51
1199
 
1200
void
1201
output_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
1202
{
1203
  int i;
1204
  int len_so_far = 0;
1205
 
1206
  fputs ("\t.ascii\t\"", stream);
1207
 
1208
  for (i = 0; i < len; i++)
1209
    {
1210
      int c = p[i];
1211
 
1212
      if (len_so_far >= MAX_ASCII_LEN)
1213
        {
1214
          fputs ("\"\n\t.ascii\t\"", stream);
1215
          len_so_far = 0;
1216
        }
1217
 
1218
      if (ISPRINT (c))
1219
        {
1220
          if (c == '\\' || c == '\"')
1221
            {
1222
              putc ('\\', stream);
1223
              len_so_far++;
1224
            }
1225
          putc (c, stream);
1226
          len_so_far++;
1227
        }
1228
      else
1229
        {
1230
          fprintf (stream, "\\%03o", c);
1231
          len_so_far += 4;
1232
        }
1233
    }
1234
 
1235
  fputs ("\"\n", stream);
1236
}

powered by: WebSVN 2.1.0

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