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