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