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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [config/] [moxie/] [moxie.c] - Blame information for rev 757

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

Line No. Rev Author Line
1 709 jeremybenn
/* Target Code for moxie
2
   Copyright (C) 2008, 2009, 2010, 2011  Free Software Foundation
3
   Contributed by Anthony Green.
4
 
5
   This file is part of GCC.
6
 
7
   GCC is free software; you can redistribute it and/or modify it
8
   under the terms of the GNU General Public License as published
9
   by the Free Software Foundation; either version 3, or (at your
10
   option) any later version.
11
 
12
   GCC is distributed in the hope that it will be useful, but WITHOUT
13
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15
   License for more details.
16
 
17
   You should have received a copy of the GNU General Public License
18
   along with GCC; see the file COPYING3.  If not see
19
   <http://www.gnu.org/licenses/>.  */
20
 
21
#include "config.h"
22
#include "system.h"
23
#include "coretypes.h"
24
#include "tm.h"
25
#include "rtl.h"
26
#include "regs.h"
27
#include "hard-reg-set.h"
28
#include "insn-config.h"
29
#include "conditions.h"
30
#include "insn-flags.h"
31
#include "output.h"
32
#include "insn-attr.h"
33
#include "flags.h"
34
#include "recog.h"
35
#include "reload.h"
36
#include "diagnostic-core.h"
37
#include "obstack.h"
38
#include "tree.h"
39
#include "expr.h"
40
#include "optabs.h"
41
#include "except.h"
42
#include "function.h"
43
#include "ggc.h"
44
#include "target.h"
45
#include "target-def.h"
46
#include "tm_p.h"
47
#include "langhooks.h"
48
#include "df.h"
49
 
50
#define LOSE_AND_RETURN(msgid, x)               \
51
  do                                            \
52
    {                                           \
53
      moxie_operand_lossage (msgid, x);         \
54
      return;                                   \
55
    } while (0)
56
 
57
/* Worker function for TARGET_RETURN_IN_MEMORY.  */
58
 
59
static bool
60
moxie_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
61
{
62
  const HOST_WIDE_INT size = int_size_in_bytes (type);
63
  return (size == -1 || size > 2 * UNITS_PER_WORD);
64
}
65
 
66
/* Define how to find the value returned by a function.
67
   VALTYPE is the data type of the value (as a tree).
68
   If the precise function being called is known, FUNC is its
69
   FUNCTION_DECL; otherwise, FUNC is 0.
70
 
71
   We always return values in register $r0 for moxie.  */
72
 
73
static rtx
74
moxie_function_value (const_tree valtype,
75
                      const_tree fntype_or_decl ATTRIBUTE_UNUSED,
76
                      bool outgoing ATTRIBUTE_UNUSED)
77
{
78
  return gen_rtx_REG (TYPE_MODE (valtype), MOXIE_R0);
79
}
80
 
81
/* Define how to find the value returned by a library function.
82
 
83
   We always return values in register $r0 for moxie.  */
84
 
85
static rtx
86
moxie_libcall_value (enum machine_mode mode,
87
                     const_rtx fun ATTRIBUTE_UNUSED)
88
{
89
  return gen_rtx_REG (mode, MOXIE_R0);
90
}
91
 
92
/* Handle TARGET_FUNCTION_VALUE_REGNO_P.
93
 
94
   We always return values in register $r0 for moxie.  */
95
 
96
static bool
97
moxie_function_value_regno_p (const unsigned int regno)
98
{
99
  return (regno == MOXIE_R0);
100
}
101
 
102
/* Emit an error message when we're in an asm, and a fatal error for
103
   "normal" insns.  Formatted output isn't easily implemented, since we
104
   use output_operand_lossage to output the actual message and handle the
105
   categorization of the error.  */
106
 
107
static void
108
moxie_operand_lossage (const char *msgid, rtx op)
109
{
110
  debug_rtx (op);
111
  output_operand_lossage ("%s", msgid);
112
}
113
 
114
/* The PRINT_OPERAND_ADDRESS worker.  */
115
 
116
void
117
moxie_print_operand_address (FILE *file, rtx x)
118
{
119
  switch (GET_CODE (x))
120
    {
121
    case REG:
122
      fprintf (file, "(%s)", reg_names[REGNO (x)]);
123
      break;
124
 
125
    case PLUS:
126
      switch (GET_CODE (XEXP (x, 1)))
127
        {
128
        case CONST_INT:
129
          fprintf (file, "%ld(%s)",
130
                   INTVAL(XEXP (x, 1)), reg_names[REGNO (XEXP (x, 0))]);
131
          break;
132
        case SYMBOL_REF:
133
          output_addr_const (file, XEXP (x, 1));
134
          fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
135
          break;
136
        case CONST:
137
          {
138
            rtx plus = XEXP (XEXP (x, 1), 0);
139
            if (GET_CODE (XEXP (plus, 0)) == SYMBOL_REF
140
                && CONST_INT_P (XEXP (plus, 1)))
141
              {
142
                output_addr_const(file, XEXP (plus, 0));
143
                fprintf (file,"+%ld(%s)", INTVAL (XEXP (plus, 1)),
144
                         reg_names[REGNO (XEXP (x, 0))]);
145
              }
146
            else
147
              abort();
148
          }
149
          break;
150
        default:
151
          abort();
152
        }
153
      break;
154
 
155
    default:
156
      output_addr_const (file, x);
157
      break;
158
    }
159
}
160
 
161
/* The PRINT_OPERAND worker.  */
162
 
163
void
164
moxie_print_operand (FILE *file, rtx x, int code)
165
{
166
  rtx operand = x;
167
 
168
  /* New code entries should just be added to the switch below.  If
169
     handling is finished, just return.  If handling was just a
170
     modification of the operand, the modified operand should be put in
171
     "operand", and then do a break to let default handling
172
     (zero-modifier) output the operand.  */
173
 
174
  switch (code)
175
    {
176
    case 0:
177
      /* No code, print as usual.  */
178
      break;
179
 
180
    default:
181
      LOSE_AND_RETURN ("invalid operand modifier letter", x);
182
    }
183
 
184
  /* Print an operand as without a modifier letter.  */
185
  switch (GET_CODE (operand))
186
    {
187
    case REG:
188
      if (REGNO (operand) > MOXIE_R13)
189
        internal_error ("internal error: bad register: %d", REGNO (operand));
190
      fprintf (file, "%s", reg_names[REGNO (operand)]);
191
      return;
192
 
193
    case MEM:
194
      output_address (XEXP (operand, 0));
195
      return;
196
 
197
    default:
198
      /* No need to handle all strange variants, let output_addr_const
199
         do it for us.  */
200
      if (CONSTANT_P (operand))
201
        {
202
          output_addr_const (file, operand);
203
          return;
204
        }
205
 
206
      LOSE_AND_RETURN ("unexpected operand", x);
207
    }
208
}
209
 
210
/* Per-function machine data.  */
211
struct GTY(()) machine_function
212
 {
213
   /* Number of bytes saved on the stack for callee saved registers.  */
214
   int callee_saved_reg_size;
215
 
216
   /* Number of bytes saved on the stack for local variables.  */
217
   int local_vars_size;
218
 
219
   /* The sum of 2 sizes: locals vars and padding byte for saving the
220
    * registers.  Used in expand_prologue () and expand_epilogue().  */
221
   int size_for_adjusting_sp;
222
 };
223
 
224
/* Zero initialization is OK for all current fields.  */
225
 
226
static struct machine_function *
227
moxie_init_machine_status (void)
228
{
229
  return ggc_alloc_cleared_machine_function ();
230
}
231
 
232
 
233
/* The TARGET_OPTION_OVERRIDE worker.
234
   All this curently does is set init_machine_status.  */
235
static void
236
moxie_option_override (void)
237
{
238
  /* Set the per-function-data initializer.  */
239
  init_machine_status = moxie_init_machine_status;
240
}
241
 
242
/* Compute the size of the local area and the size to be adjusted by the
243
 * prologue and epilogue.  */
244
 
245
static void
246
moxie_compute_frame (void)
247
{
248
  /* For aligning the local variables.  */
249
  int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
250
  int padding_locals;
251
  int regno;
252
 
253
  /* Padding needed for each element of the frame.  */
254
  cfun->machine->local_vars_size = get_frame_size ();
255
 
256
  /* Align to the stack alignment.  */
257
  padding_locals = cfun->machine->local_vars_size % stack_alignment;
258
  if (padding_locals)
259
    padding_locals = stack_alignment - padding_locals;
260
 
261
  cfun->machine->local_vars_size += padding_locals;
262
 
263
  cfun->machine->callee_saved_reg_size = 0;
264
 
265
  /* Save callee-saved registers.  */
266
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
267
    if (df_regs_ever_live_p (regno) && (! call_used_regs[regno]))
268
      cfun->machine->callee_saved_reg_size += 4;
269
 
270
  cfun->machine->size_for_adjusting_sp =
271
    crtl->args.pretend_args_size
272
    + cfun->machine->local_vars_size
273
    + (ACCUMULATE_OUTGOING_ARGS ? crtl->outgoing_args_size : 0);
274
}
275
 
276
void
277
moxie_expand_prologue (void)
278
{
279
  int regno;
280
  rtx insn;
281
 
282
  moxie_compute_frame ();
283
 
284
  /* Save callee-saved registers.  */
285
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
286
    {
287
      if (!fixed_regs[regno] && df_regs_ever_live_p (regno) && !call_used_regs[regno])
288
        {
289
          insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno)));
290
          RTX_FRAME_RELATED_P (insn) = 1;
291
        }
292
    }
293
 
294
  if (cfun->machine->size_for_adjusting_sp > 0)
295
    {
296
      int i = cfun->machine->size_for_adjusting_sp;
297
      while (i > 255)
298
        {
299
          insn = emit_insn (gen_subsi3 (stack_pointer_rtx,
300
                                        stack_pointer_rtx,
301
                                        GEN_INT (255)));
302
          RTX_FRAME_RELATED_P (insn) = 1;
303
          i -= 255;
304
        }
305
      if (i > 0)
306
        {
307
          insn = emit_insn (gen_subsi3 (stack_pointer_rtx,
308
                                        stack_pointer_rtx,
309
                                        GEN_INT (i)));
310
          RTX_FRAME_RELATED_P (insn) = 1;
311
        }
312
    }
313
}
314
 
315
void
316
moxie_expand_epilogue (void)
317
{
318
  int regno;
319
  rtx reg;
320
 
321
  if (cfun->machine->callee_saved_reg_size != 0)
322
    {
323
      reg = gen_rtx_REG (Pmode, MOXIE_R5);
324
      if (cfun->machine->callee_saved_reg_size <= 255)
325
        {
326
          emit_move_insn (reg, hard_frame_pointer_rtx);
327
          emit_insn (gen_subsi3
328
                     (reg, reg,
329
                      GEN_INT (cfun->machine->callee_saved_reg_size)));
330
        }
331
      else
332
        {
333
          emit_move_insn (reg,
334
                          GEN_INT (-cfun->machine->callee_saved_reg_size));
335
          emit_insn (gen_addsi3 (reg, reg, hard_frame_pointer_rtx));
336
        }
337
      for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0; )
338
        if (!fixed_regs[regno] && !call_used_regs[regno]
339
            && df_regs_ever_live_p (regno))
340
          {
341
            rtx preg = gen_rtx_REG (Pmode, regno);
342
            emit_insn (gen_movsi_pop (reg, preg));
343
          }
344
    }
345
 
346
  emit_jump_insn (gen_returner ());
347
}
348
 
349
/* Implements the macro INITIAL_ELIMINATION_OFFSET, return the OFFSET.  */
350
 
351
int
352
moxie_initial_elimination_offset (int from, int to)
353
{
354
  int ret;
355
 
356
  if ((from) == FRAME_POINTER_REGNUM && (to) == HARD_FRAME_POINTER_REGNUM)
357
    {
358
      /* Compute this since we need to use cfun->machine->local_vars_size.  */
359
      moxie_compute_frame ();
360
      ret = -cfun->machine->callee_saved_reg_size;
361
    }
362
  else if ((from) == ARG_POINTER_REGNUM && (to) == HARD_FRAME_POINTER_REGNUM)
363
    ret = 0x00;
364
  else
365
    abort ();
366
 
367
  return ret;
368
}
369
 
370
/* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
371
 
372
static void
373
moxie_setup_incoming_varargs (cumulative_args_t cum_v,
374
                              enum machine_mode mode ATTRIBUTE_UNUSED,
375
                              tree type ATTRIBUTE_UNUSED,
376
                              int *pretend_size, int no_rtl)
377
{
378
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
379
  int regno;
380
  int regs = 8 - *cum;
381
 
382
  *pretend_size = regs < 0 ? 0 : GET_MODE_SIZE (SImode) * regs;
383
 
384
  if (no_rtl)
385
    return;
386
 
387
  for (regno = *cum; regno < 8; regno++)
388
    {
389
      rtx reg = gen_rtx_REG (SImode, regno);
390
      rtx slot = gen_rtx_PLUS (Pmode,
391
                               gen_rtx_REG (SImode, ARG_POINTER_REGNUM),
392
                               GEN_INT (UNITS_PER_WORD * (3 + (regno-2))));
393
 
394
      emit_move_insn (gen_rtx_MEM (SImode, slot), reg);
395
    }
396
}
397
 
398
 
399
/* Return the fixed registers used for condition codes.  */
400
 
401
static bool
402
moxie_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
403
{
404
  *p1 = CC_REG;
405
  *p2 = INVALID_REGNUM;
406
  return true;
407
}
408
 
409
/* Return the next register to be used to hold a function argument or
410
   NULL_RTX if there's no more space.  */
411
 
412
static rtx
413
moxie_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
414
                    const_tree type ATTRIBUTE_UNUSED,
415
                    bool named ATTRIBUTE_UNUSED)
416
{
417
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
418
 
419
  if (*cum < 8)
420
    return gen_rtx_REG (mode, *cum);
421
  else
422
    return NULL_RTX;
423
}
424
 
425
#define MOXIE_FUNCTION_ARG_SIZE(MODE, TYPE)     \
426
  ((MODE) != BLKmode ? GET_MODE_SIZE (MODE)     \
427
   : (unsigned) int_size_in_bytes (TYPE))
428
 
429
static void
430
moxie_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
431
                            const_tree type, bool named ATTRIBUTE_UNUSED)
432
{
433
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
434
 
435
  *cum = (*cum < MOXIE_R6
436
          ? *cum + ((3 + MOXIE_FUNCTION_ARG_SIZE (mode, type)) / 4)
437
          : *cum);
438
}
439
 
440
/* Return non-zero if the function argument described by TYPE is to be
441
   passed by reference.  */
442
 
443
static bool
444
moxie_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
445
                         enum machine_mode mode, const_tree type,
446
                         bool named ATTRIBUTE_UNUSED)
447
{
448
  unsigned HOST_WIDE_INT size;
449
 
450
  if (type)
451
    {
452
      if (AGGREGATE_TYPE_P (type))
453
        return true;
454
      size = int_size_in_bytes (type);
455
    }
456
  else
457
    size = GET_MODE_SIZE (mode);
458
 
459
  return size > 4*6;
460
}
461
 
462
/* Some function arguments will only partially fit in the registers
463
   that hold arguments.  Given a new arg, return the number of bytes
464
   that fit in argument passing registers.  */
465
 
466
static int
467
moxie_arg_partial_bytes (cumulative_args_t cum_v,
468
                         enum machine_mode mode,
469
                         tree type, bool named)
470
{
471
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
472
  int bytes_left, size;
473
 
474
  if (*cum >= 8)
475
    return 0;
476
 
477
  if (moxie_pass_by_reference (cum_v, mode, type, named))
478
    size = 4;
479
  else if (type)
480
    {
481
      if (AGGREGATE_TYPE_P (type))
482
        return 0;
483
      size = int_size_in_bytes (type);
484
    }
485
  else
486
    size = GET_MODE_SIZE (mode);
487
 
488
  bytes_left = (4 * 6) - ((*cum - 2) * 4);
489
 
490
  if (size > bytes_left)
491
    return bytes_left;
492
  else
493
    return 0;
494
}
495
 
496
/* Worker function for TARGET_STATIC_CHAIN.  */
497
 
498
static rtx
499
moxie_static_chain (const_tree fndecl, bool incoming_p)
500
{
501
  rtx addr, mem;
502
 
503
  if (!DECL_STATIC_CHAIN (fndecl))
504
    return NULL;
505
 
506
  if (incoming_p)
507
    addr = plus_constant (arg_pointer_rtx, 2 * UNITS_PER_WORD);
508
  else
509
    addr = plus_constant (stack_pointer_rtx, -UNITS_PER_WORD);
510
 
511
  mem = gen_rtx_MEM (Pmode, addr);
512
  MEM_NOTRAP_P (mem) = 1;
513
 
514
  return mem;
515
}
516
 
517
/* Worker function for TARGET_ASM_TRAMPOLINE_TEMPLATE.  */
518
 
519
static void
520
moxie_asm_trampoline_template (FILE *f)
521
{
522
  fprintf (f, "\tpush  $sp, $r0\n");
523
  fprintf (f, "\tldi.l $r0, 0x0\n");
524
  fprintf (f, "\tsto.l 0x8($fp), $r0\n");
525
  fprintf (f, "\tpop   $sp, $r0\n");
526
  fprintf (f, "\tnop\n");
527
  fprintf (f, "\tjmpa  0x0\n");
528
}
529
 
530
/* Worker function for TARGET_TRAMPOLINE_INIT.  */
531
 
532
static void
533
moxie_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
534
{
535
  rtx mem, fnaddr = XEXP (DECL_RTL (fndecl), 0);
536
 
537
  emit_block_move (m_tramp, assemble_trampoline_template (),
538
                   GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
539
 
540
  mem = adjust_address (m_tramp, SImode, 4);
541
  emit_move_insn (mem, chain_value);
542
  mem = adjust_address (m_tramp, SImode, 20);
543
  emit_move_insn (mem, fnaddr);
544
}
545
 
546
/* The Global `targetm' Variable.  */
547
 
548
/* Initialize the GCC target structure.  */
549
 
550
#undef  TARGET_PROMOTE_PROTOTYPES
551
#define TARGET_PROMOTE_PROTOTYPES       hook_bool_const_tree_true
552
 
553
#undef  TARGET_RETURN_IN_MEMORY
554
#define TARGET_RETURN_IN_MEMORY         moxie_return_in_memory
555
#undef  TARGET_MUST_PASS_IN_STACK
556
#define TARGET_MUST_PASS_IN_STACK       must_pass_in_stack_var_size
557
#undef  TARGET_PASS_BY_REFERENCE
558
#define TARGET_PASS_BY_REFERENCE        moxie_pass_by_reference
559
#undef  TARGET_ARG_PARTIAL_BYTES
560
#define TARGET_ARG_PARTIAL_BYTES        moxie_arg_partial_bytes
561
#undef  TARGET_FUNCTION_ARG
562
#define TARGET_FUNCTION_ARG             moxie_function_arg
563
#undef  TARGET_FUNCTION_ARG_ADVANCE
564
#define TARGET_FUNCTION_ARG_ADVANCE     moxie_function_arg_advance
565
 
566
 
567
#undef  TARGET_SETUP_INCOMING_VARARGS
568
#define TARGET_SETUP_INCOMING_VARARGS   moxie_setup_incoming_varargs
569
 
570
#undef  TARGET_FIXED_CONDITION_CODE_REGS
571
#define TARGET_FIXED_CONDITION_CODE_REGS moxie_fixed_condition_code_regs
572
 
573
/* Define this to return an RTX representing the place where a
574
   function returns or receives a value of data type RET_TYPE, a tree
575
   node node representing a data type.  */
576
#undef TARGET_FUNCTION_VALUE
577
#define TARGET_FUNCTION_VALUE moxie_function_value
578
#undef TARGET_LIBCALL_VALUE
579
#define TARGET_LIBCALL_VALUE moxie_libcall_value
580
#undef TARGET_FUNCTION_VALUE_REGNO_P
581
#define TARGET_FUNCTION_VALUE_REGNO_P moxie_function_value_regno_p
582
 
583
#undef TARGET_FRAME_POINTER_REQUIRED
584
#define TARGET_FRAME_POINTER_REQUIRED hook_bool_void_true
585
 
586
#undef TARGET_STATIC_CHAIN
587
#define TARGET_STATIC_CHAIN moxie_static_chain
588
#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
589
#define TARGET_ASM_TRAMPOLINE_TEMPLATE moxie_asm_trampoline_template
590
#undef TARGET_TRAMPOLINE_INIT
591
#define TARGET_TRAMPOLINE_INIT moxie_trampoline_init
592
 
593
#undef TARGET_OPTION_OVERRIDE
594
#define TARGET_OPTION_OVERRIDE moxie_option_override
595
 
596
struct gcc_target targetm = TARGET_INITIALIZER;
597
 
598
#include "gt-moxie.h"

powered by: WebSVN 2.1.0

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