OSDN Git Service

3991ceeefeaa4953cef74338cb0faf6c2a6144fa
[pf3gnuchains/gcc-fork.git] / gcc / config / moxie / moxie.c
1 /* Target Code for moxie
2    Copyright (C) 2008, 2009  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 "real.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "insn-flags.h"
32 #include "output.h"
33 #include "insn-attr.h"
34 #include "flags.h"
35 #include "recog.h"
36 #include "reload.h"
37 #include "toplev.h"
38 #include "obstack.h"
39 #include "tree.h"
40 #include "expr.h"
41 #include "optabs.h"
42 #include "except.h"
43 #include "function.h"
44 #include "ggc.h"
45 #include "target.h"
46 #include "target-def.h"
47 #include "tm_p.h"
48 #include "langhooks.h"
49 #include "df.h"
50
51 #define LOSE_AND_RETURN(msgid, x)               \
52   do                                            \
53     {                                           \
54       moxie_operand_lossage (msgid, x);         \
55       return;                                   \
56     } while (0)
57
58 /* Worker function for TARGET_RETURN_IN_MEMORY.  */
59
60 static bool
61 moxie_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
62 {
63   const HOST_WIDE_INT size = int_size_in_bytes (type);
64   return (size == -1 || size > 2 * UNITS_PER_WORD);
65 }
66
67 /* Define how to find the value returned by a function.
68    VALTYPE is the data type of the value (as a tree).
69    If the precise function being called is known, FUNC is its
70    FUNCTION_DECL; otherwise, FUNC is 0.  
71
72    We always return values in register $r0 for moxie.  */
73
74 rtx
75 moxie_function_value (tree valtype, 
76                       tree fntype_or_decl ATTRIBUTE_UNUSED,
77                       bool outgoing ATTRIBUTE_UNUSED)
78 {
79   return gen_rtx_REG (TYPE_MODE (valtype), MOXIE_R0);
80 }
81
82 /* Emit an error message when we're in an asm, and a fatal error for
83    "normal" insns.  Formatted output isn't easily implemented, since we
84    use output_operand_lossage to output the actual message and handle the
85    categorization of the error.  */
86
87 static void
88 moxie_operand_lossage (const char *msgid, rtx op)
89 {
90   debug_rtx (op);
91   output_operand_lossage ("%s", msgid);
92 }
93
94 /* The PRINT_OPERAND_ADDRESS worker.  */
95
96 void
97 moxie_print_operand_address (FILE *file, rtx x)
98 {
99   switch (GET_CODE (x))
100     {
101     case REG:
102       fprintf (file, "(%s)", reg_names[REGNO (x)]);
103       break;
104       
105     case PLUS:
106       switch (GET_CODE (XEXP (x, 1)))
107         {
108         case CONST_INT:
109           fprintf (file, "%ld(%s)", 
110                    INTVAL(XEXP (x, 1)), reg_names[REGNO (XEXP (x, 0))]);
111           break;
112         case SYMBOL_REF:
113           output_addr_const (file, XEXP (x, 1));
114           fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
115           break;
116         case CONST:
117           {
118             rtx plus = XEXP (XEXP (x, 1), 0);
119             if (GET_CODE (XEXP (plus, 0)) == SYMBOL_REF 
120                 && CONST_INT_P (XEXP (plus, 1)))
121               {
122                 output_addr_const(file, XEXP (plus, 0));
123                 fprintf (file,"+%ld(%s)", INTVAL (XEXP (plus, 1)),
124                          reg_names[REGNO (XEXP (x, 0))]);
125               }
126             else
127               abort();
128           }
129           break;
130         default:
131           abort();
132         }
133       break;
134
135     default:
136       output_addr_const (file, x);
137       break;
138     }
139 }
140
141 /* The PRINT_OPERAND worker.  */
142
143 void
144 moxie_print_operand (FILE *file, rtx x, int code)
145 {
146   rtx operand = x;
147
148   /* New code entries should just be added to the switch below.  If
149      handling is finished, just return.  If handling was just a
150      modification of the operand, the modified operand should be put in
151      "operand", and then do a break to let default handling
152      (zero-modifier) output the operand.  */
153
154   switch (code)
155     {
156     case 0:
157       /* No code, print as usual.  */
158       break;
159
160     default:
161       LOSE_AND_RETURN ("invalid operand modifier letter", x);
162     }
163
164   /* Print an operand as without a modifier letter.  */
165   switch (GET_CODE (operand))
166     {
167     case REG:
168       if (REGNO (operand) > MOXIE_R13)
169         internal_error ("internal error: bad register: %d", REGNO (operand));
170       fprintf (file, "%s", reg_names[REGNO (operand)]);
171       return;
172
173     case MEM:
174       output_address (XEXP (operand, 0));
175       return;
176
177     default:
178       /* No need to handle all strange variants, let output_addr_const
179          do it for us.  */
180       if (CONSTANT_P (operand))
181         {
182           output_addr_const (file, operand);
183           return;
184         }
185
186       LOSE_AND_RETURN ("unexpected operand", x);
187     }
188 }
189
190 /* Per-function machine data.  */
191 struct GTY(()) machine_function
192  {
193    /* Number of bytes saved on the stack for callee saved registers.  */
194    int callee_saved_reg_size;
195
196    /* Number of bytes saved on the stack for local variables.  */
197    int local_vars_size;
198
199    /* The sum of 2 sizes: locals vars and padding byte for saving the
200     * registers.  Used in expand_prologue () and expand_epilogue().  */
201    int size_for_adjusting_sp;
202  };
203
204 /* Zero initialization is OK for all current fields.  */
205
206 static struct machine_function *
207 moxie_init_machine_status (void)
208 {
209   return GGC_CNEW (struct machine_function);
210 }
211
212
213 /* The OVERRIDE_OPTIONS worker.
214    All this curently does is set init_machine_status.  */
215 void
216 moxie_override_options (void)
217 {
218   /* Set the per-function-data initializer.  */
219   init_machine_status = moxie_init_machine_status;
220 }
221
222 /* Compute the size of the local area and the size to be adjusted by the
223  * prologue and epilogue.  */
224
225 static void
226 moxie_compute_frame (void)
227 {
228   /* For aligning the local variables.  */
229   int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
230   int padding_locals;
231   int regno;
232
233   /* Padding needed for each element of the frame.  */
234   cfun->machine->local_vars_size = get_frame_size ();
235
236   /* Align to the stack alignment.  */
237   padding_locals = cfun->machine->local_vars_size % stack_alignment;
238   if (padding_locals)
239     padding_locals = stack_alignment - padding_locals;
240
241   cfun->machine->local_vars_size += padding_locals;
242
243   cfun->machine->callee_saved_reg_size = 0;
244
245   /* Save callee-saved registers.  */
246   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
247     if (df_regs_ever_live_p (regno) && (! call_used_regs[regno]))
248       cfun->machine->callee_saved_reg_size += 4;
249
250   cfun->machine->size_for_adjusting_sp = 
251     crtl->args.pretend_args_size
252     + cfun->machine->local_vars_size 
253     + (ACCUMULATE_OUTGOING_ARGS ? crtl->outgoing_args_size : 0);
254 }
255
256 void
257 moxie_expand_prologue (void)
258 {
259   int regno;
260   rtx insn;
261
262   moxie_compute_frame ();
263
264   /* Save callee-saved registers.  */
265   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
266     {
267       if (!fixed_regs[regno] && df_regs_ever_live_p (regno) && !call_used_regs[regno])
268         {
269           insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno)));
270           RTX_FRAME_RELATED_P (insn) = 1;
271         }
272     }
273
274   if (cfun->machine->size_for_adjusting_sp > 0)
275     {
276       insn = 
277         emit_insn (gen_movsi (gen_rtx_REG (Pmode, MOXIE_R12), 
278                               GEN_INT (-cfun->machine->size_for_adjusting_sp)));
279       RTX_FRAME_RELATED_P (insn) = 1;
280       insn = emit_insn (gen_addsi3 (stack_pointer_rtx, 
281                                     stack_pointer_rtx, 
282                                     gen_rtx_REG (Pmode, MOXIE_R12)));
283       RTX_FRAME_RELATED_P (insn) = 1;
284     }
285 }
286
287 void
288 moxie_expand_epilogue (void)
289 {
290   int regno;
291   rtx insn, reg, cfa_restores = NULL;
292
293   if (cfun->machine->callee_saved_reg_size != 0)
294     {
295       reg = gen_rtx_REG (Pmode, MOXIE_R12);
296       emit_move_insn (reg,
297                       GEN_INT (-cfun->machine->callee_saved_reg_size));
298       emit_insn (gen_addsi3 (reg, reg, hard_frame_pointer_rtx));
299       insn = emit_move_insn (stack_pointer_rtx, reg);
300       RTX_FRAME_RELATED_P (insn) = 1;
301       add_reg_note (insn, REG_CFA_DEF_CFA,
302                     plus_constant (stack_pointer_rtx,
303                                    cfun->machine->callee_saved_reg_size));
304       for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0; )
305         if (!fixed_regs[regno] && !call_used_regs[regno]
306             && df_regs_ever_live_p (regno))
307           {
308             reg = gen_rtx_REG (Pmode, regno);
309             insn = emit_insn (gen_movsi_pop (reg));
310             RTX_FRAME_RELATED_P (insn) = 1;
311             add_reg_note (insn, REG_CFA_ADJUST_CFA,
312                           gen_rtx_SET (VOIDmode, stack_pointer_rtx,
313                                        plus_constant (stack_pointer_rtx,
314                                                       UNITS_PER_WORD)));
315             add_reg_note (insn, REG_CFA_RESTORE, reg);
316           }
317     }
318
319   emit_jump_insn (gen_returner ());
320 }
321
322 /* Implements the macro INITIAL_ELIMINATION_OFFSET, return the OFFSET.  */
323
324 int
325 moxie_initial_elimination_offset (int from, int to)
326 {
327   int ret;
328   
329   if ((from) == FRAME_POINTER_REGNUM && (to) == HARD_FRAME_POINTER_REGNUM)
330     {
331       /* Compute this since we need to use cfun->machine->local_vars_size.  */
332       moxie_compute_frame ();
333       ret = -cfun->machine->callee_saved_reg_size;
334     }
335   else if ((from) == ARG_POINTER_REGNUM && (to) == HARD_FRAME_POINTER_REGNUM)
336     ret = 0x00;
337   else
338     abort ();
339
340   return ret;
341 }
342
343 /* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
344
345 static void
346 moxie_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
347                               enum machine_mode mode ATTRIBUTE_UNUSED,
348                               tree type ATTRIBUTE_UNUSED,
349                               int *pretend_size, int no_rtl)
350 {
351   int regno;
352   int regs = 4 - *cum;
353   
354   *pretend_size = regs < 0 ? 0 : GET_MODE_SIZE (SImode) * regs;
355   
356   if (no_rtl)
357     return;
358   
359   for (regno = *cum; regno < 4; regno++)
360     {
361       rtx reg = gen_rtx_REG (SImode, regno);
362       rtx slot = gen_rtx_PLUS (Pmode,
363                                gen_rtx_REG (SImode, ARG_POINTER_REGNUM),
364                                GEN_INT (UNITS_PER_WORD * (3 + (regno-2))));
365       
366       emit_move_insn (gen_rtx_MEM (SImode, slot), reg);
367     }
368 }
369
370
371 /* Return the fixed registers used for condition codes.  */
372
373 static bool
374 moxie_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
375 {
376   *p1 = CC_REG;
377   *p2 = INVALID_REGNUM;
378   return true;
379 }
380
381 /* Return the next register to be used to hold a function argument or
382    NULL_RTX if there's no more space.  */
383
384 rtx
385 moxie_function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode,
386                     tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
387 {
388   if (cum < 4)
389     return gen_rtx_REG (mode, cum);
390   else 
391     return NULL_RTX;
392 }
393
394 /* Return non-zero if the function argument described by TYPE is to be
395    passed by reference.  */
396
397 static bool
398 moxie_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
399                          enum machine_mode mode, const_tree type,
400                          bool named ATTRIBUTE_UNUSED)
401 {
402   unsigned HOST_WIDE_INT size;
403
404   if (type)
405     {
406       if (AGGREGATE_TYPE_P (type))
407         return true;
408       size = int_size_in_bytes (type);
409     }
410   else
411     size = GET_MODE_SIZE (mode);
412
413   return size > 8;
414 }
415
416 /* Some function arguments will only partially fit in the registers
417    that hold arguments.  Given a new arg, return the number of bytes
418    that fit in argument passing registers.  */
419
420 static int
421 moxie_arg_partial_bytes (CUMULATIVE_ARGS *cum,
422                          enum machine_mode mode,
423                          tree type, bool named)
424 {
425   int bytes_left, size;
426
427   if (*cum >= 4)
428     return 0;
429
430   if (moxie_pass_by_reference (cum, mode, type, named))
431     size = 4;
432   else if (type)
433     {
434       if (AGGREGATE_TYPE_P (type))
435         return 0;
436       size = int_size_in_bytes (type);
437     }
438   else
439     size = GET_MODE_SIZE (mode);
440
441   bytes_left = 8 - ((*cum - 2) * 4);
442
443   if (size > bytes_left)
444     return bytes_left;
445   else
446     return 0;
447 }
448
449 /* The Global `targetm' Variable.  */
450
451 /* Initialize the GCC target structure.  */
452
453 #undef  TARGET_PROMOTE_PROTOTYPES
454 #define TARGET_PROMOTE_PROTOTYPES       hook_bool_const_tree_true
455
456 #undef  TARGET_RETURN_IN_MEMORY
457 #define TARGET_RETURN_IN_MEMORY         moxie_return_in_memory
458 #undef  TARGET_MUST_PASS_IN_STACK
459 #define TARGET_MUST_PASS_IN_STACK       must_pass_in_stack_var_size
460 #undef  TARGET_PASS_BY_REFERENCE
461 #define TARGET_PASS_BY_REFERENCE        moxie_pass_by_reference
462 #undef  TARGET_ARG_PARTIAL_BYTES
463 #define TARGET_ARG_PARTIAL_BYTES        moxie_arg_partial_bytes
464
465
466 #undef  TARGET_SETUP_INCOMING_VARARGS
467 #define TARGET_SETUP_INCOMING_VARARGS   moxie_setup_incoming_varargs
468
469 #undef  TARGET_FIXED_CONDITION_CODE_REGS
470 #define TARGET_FIXED_CONDITION_CODE_REGS moxie_fixed_condition_code_regs
471
472 /* Define this to return an RTX representing the place where a
473    function returns or receives a value of data type RET_TYPE, a tree
474    node node representing a data type.  */
475 #undef TARGET_FUNCTION_VALUE
476 #define TARGET_FUNCTION_VALUE moxie_function_value
477
478 #undef TARGET_FRAME_POINTER_REQUIRED
479 #define TARGET_FRAME_POINTER_REQUIRED hook_bool_void_true
480
481 struct gcc_target targetm = TARGET_INITIALIZER;
482
483 #include "gt-moxie.h"