e9eb4d4d70bea4ee6f04e4f843f97277348887fd
[platform/upstream/gcc.git] / gcc / config / ft32 / ft32.c
1 /* Target Code for ft32
2    Copyright (C) 2015-2019 Free Software Foundation, Inc.
3    Contributed by FTDI <support@ftdi.com>
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 #define IN_TARGET_CODE 1
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "backend.h"
27 #include "target.h"
28 #include "rtl.h"
29 #include "tree.h"
30 #include "stringpool.h"
31 #include "attribs.h"
32 #include "df.h"
33 #include "memmodel.h"
34 #include "tm_p.h"
35 #include "regs.h"
36 #include "emit-rtl.h"
37 #include "diagnostic-core.h"
38 #include "output.h"
39 #include "stor-layout.h"
40 #include "calls.h"
41 #include "expr.h"
42 #include "builtins.h"
43 #include "print-tree.h"
44
45 /* This file should be included last.  */
46 #include "target-def.h"
47
48 #include <stdint.h>
49
50 #define LOSE_AND_RETURN(msgid, x)               \
51   do                                            \
52     {                                           \
53       ft32_operand_lossage (msgid, x);            \
54       return;                                   \
55     } while (0)
56
57 /* Worker function for TARGET_RETURN_IN_MEMORY.  */
58
59 static bool
60 ft32_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 ft32.  */
72
73 static rtx
74 ft32_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), FT32_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 ft32.  */
84
85 static rtx
86 ft32_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
87 {
88   return gen_rtx_REG (mode, FT32_R0);
89 }
90
91 /* Handle TARGET_FUNCTION_VALUE_REGNO_P.
92
93    We always return values in register $r0 for ft32.  */
94
95 static bool
96 ft32_function_value_regno_p (const unsigned int regno)
97 {
98   return (regno == FT32_R0);
99 }
100
101 /* Emit an error message when we're in an asm, and a fatal error for
102    "normal" insns.  Formatted output isn't easily implemented, since we
103    use output_operand_lossage to output the actual message and handle the
104    categorization of the error.  */
105
106 static void
107 ft32_operand_lossage (const char *msgid, rtx op)
108 {
109   debug_rtx (op);
110   output_operand_lossage ("%s", msgid);
111 }
112
113 /* The PRINT_OPERAND_ADDRESS worker.  */
114
115 void
116 ft32_print_operand_address (FILE * file, rtx x)
117 {
118   switch (GET_CODE (x))
119     {
120     case REG:
121       fprintf (file, "%s,0", reg_names[REGNO (x)]);
122       break;
123
124     case PLUS:
125       switch (GET_CODE (XEXP (x, 1)))
126         {
127         case CONST_INT:
128           fprintf (file, "%s,%ld",
129                    reg_names[REGNO (XEXP (x, 0))], INTVAL (XEXP (x, 1)));
130           break;
131         case SYMBOL_REF:
132           output_addr_const (file, XEXP (x, 1));
133           fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
134           break;
135         case CONST:
136           {
137             rtx plus = XEXP (XEXP (x, 1), 0);
138             if (GET_CODE (XEXP (plus, 0)) == SYMBOL_REF
139                 && CONST_INT_P (XEXP (plus, 1)))
140               {
141                 output_addr_const (file, XEXP (plus, 0));
142                 fprintf (file, "+%ld(%s)", INTVAL (XEXP (plus, 1)),
143                          reg_names[REGNO (XEXP (x, 0))]);
144               }
145             else
146               abort ();
147           }
148           break;
149         default:
150           abort ();
151         }
152       break;
153
154     default:
155       output_addr_const (file, x);
156       break;
157     }
158 }
159
160 /* The PRINT_OPERAND worker.  */
161
162 void
163 ft32_print_operand (FILE * file, rtx x, int code)
164 {
165   rtx operand = x;
166
167   /* New code entries should just be added to the switch below.  If
168      handling is finished, just return.  If handling was just a
169      modification of the operand, the modified operand should be put in
170      "operand", and then do a break to let default handling
171      (zero-modifier) output the operand.  */
172
173   switch (code)
174     {
175     case 0:
176       /* No code, print as usual.  */
177       break;
178
179     case 'h':
180       if (GET_CODE (operand) != REG)
181         internal_error ("%<h%> applied to non-register operand");
182       fprintf (file, "%s", reg_names[REGNO (operand) + 1]);
183       return;
184
185     case 'm':
186       fprintf (file, "%ld", (long) (- INTVAL(x)));
187       return;
188
189     case 'd':                   // a DW spec, from an integer alignment (for BLKmode insns)
190       {
191         int i = INTVAL (x);
192         char dwspec;
193         switch (i)
194           {
195           case 1:
196             dwspec = 'b';
197             break;
198           case 2:
199             dwspec = 's';
200             break;
201           case 4:
202             dwspec = 'l';
203             break;
204           default:
205             if ((i % 4) != 0)
206               internal_error ("bad alignment: %d", i);
207             else
208               dwspec = 'l';
209             break;
210           }
211         fprintf (file, "%c", dwspec);
212         return;
213       }
214
215     case 'f':
216       {
217         int bf = ft32_as_bitfield (INTVAL (x));
218         fprintf (file, "512|(%d<<5)|%d", bf >> 5, bf & 31);
219         return;
220       }
221
222     case 'g':
223       {
224         int bf = ft32_as_bitfield (0xffffffff ^ INTVAL (x));
225         fprintf (file, "(%d<<5)|%d", bf >> 5, bf & 31);
226         return;
227       }
228
229     case 'b':
230       {
231         ft32_print_operand (file, XEXP (x, 0), 0);
232         return;
233       }
234
235     default:
236       LOSE_AND_RETURN ("invalid operand modifier letter", x);
237     }
238
239   /* Print an operand as without a modifier letter.  */
240   switch (GET_CODE (operand))
241     {
242     case REG:
243       fprintf (file, "%s", reg_names[REGNO (operand)]);
244       return;
245
246     case MEM:
247       output_address (GET_MODE (XEXP (operand, 0)), XEXP (operand, 0));
248       return;
249
250     default:
251       /* No need to handle all strange variants, let output_addr_const
252          do it for us.  */
253       if (CONSTANT_P (operand))
254         {
255           output_addr_const (file, operand);
256           return;
257         }
258
259       LOSE_AND_RETURN ("unexpected operand", x);
260     }
261 }
262
263 const char *
264 ft32_load_immediate (rtx dst, int32_t i)
265 {
266   char pattern[100];
267
268   if (i >= -524288 && i <= 524287)
269     {
270       sprintf (pattern, "ldk.l  %%0,%d", i);
271       output_asm_insn (pattern, &dst);
272     }
273   else if (i >= -536870912 && i <= 536870911)
274     {
275       ft32_load_immediate (dst, i >> 10);
276       sprintf (pattern, "ldl.l  %%0,%%0,%d", i & 1023);
277       output_asm_insn (pattern, &dst);
278     }
279   else
280     {
281       int rd;                   // rotate distance
282       uint32_t u = i;
283       for (rd = 1; rd < 32; rd++)
284         {
285           u = ((u >> 31) & 1) | (u << 1);
286           if ((int32_t) u >= -524288 && (int32_t) u <= 524287)
287             {
288               ft32_load_immediate (dst, (int32_t) u);
289               sprintf (pattern, "ror.l  %%0,%%0,%d", rd);
290               output_asm_insn (pattern, &dst);
291               return "";
292             }
293         }
294       ft32_load_immediate (dst, i >> 10);
295       sprintf (pattern, "ldl.l  %%0,%%0,%d", i & 1023);
296       output_asm_insn (pattern, &dst);
297     }
298
299   return "";
300 }
301
302 // x is a bit mask, for example:
303 //    00000000000000000000001111111110
304 // If x contains a single bit mask, return the bitfield spec.
305 // in the above case it returns ((9 << 5) | 1)
306 // Otherwise return -1.
307 //
308
309 #define NBITS(n)  ((1U << (n)) - 1U)
310
311 int
312 ft32_as_bitfield (unsigned int x)
313 {
314   int lobit, hibit;
315
316   if (x == 0)
317     return -1;
318
319   for (lobit = 0; lobit < 32; lobit++)
320     if (x & (1 << lobit))
321       break;
322   for (hibit = 31; hibit >= 0; hibit--)
323     if (x & (1 << hibit))
324       break;
325
326   int width = 1 + hibit - lobit;
327   if (width > 16)
328     return -1;
329
330   if (x != (NBITS (width) << lobit))
331     return -1;                  // not a clean bitfield
332
333   return ((width & 15) << 5) | lobit;
334 }
335
336 /* Per-function machine data.  */
337 struct GTY (()) machine_function
338 {
339   /* Number of bytes saved on the stack for callee saved registers.  */
340   int callee_saved_reg_size;
341
342   /* Number of bytes saved on the stack for local variables.  */
343   int local_vars_size;
344
345   /* The sum of 2 sizes: locals vars and padding byte for saving the
346    * registers.  Used in expand_prologue () and expand_epilogue ().  */
347   int size_for_adjusting_sp;
348 };
349
350 /* Zero initialization is OK for all current fields.  */
351
352 static struct machine_function *
353 ft32_init_machine_status (void)
354 {
355   return ggc_cleared_alloc < machine_function > ();
356 }
357
358
359 /* The TARGET_OPTION_OVERRIDE worker.
360    All this curently does is set init_machine_status.  */
361 static void
362 ft32_option_override (void)
363 {
364   /* Set the per-function-data initializer.  */
365   init_machine_status = ft32_init_machine_status;
366 }
367
368 /* Implement targetm.select_section.  */
369 static section *
370 ft32_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
371 {
372   /* Variables and constants defined in the __ea address space
373      go into a special section named "._ea".  */
374   if (TREE_TYPE (decl) != error_mark_node
375       && TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_PM)
376     {
377       /* We might get called with string constants, but get_named_section
378          doesn't like them as they are not DECLs.  Also, we need to set
379          flags in that case.  */
380       if (!DECL_P (decl))
381         return get_section ("._pm", SECTION_WRITE | SECTION_DEBUG, NULL);
382
383       return get_named_section (decl, "._pm", reloc);
384     }
385
386   return default_elf_select_section (decl, reloc, align);
387 }
388
389 /* Compute the size of the local area and the size to be adjusted by the
390  * prologue and epilogue.  */
391
392 static void
393 ft32_compute_frame (void)
394 {
395   /* For aligning the local variables.  */
396   int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
397   int padding_locals;
398   int regno;
399
400   /* Padding needed for each element of the frame.  */
401   cfun->machine->local_vars_size = get_frame_size ();
402
403   /* Align to the stack alignment.  */
404   padding_locals = cfun->machine->local_vars_size % stack_alignment;
405   if (padding_locals)
406     padding_locals = stack_alignment - padding_locals;
407
408   cfun->machine->local_vars_size += padding_locals;
409
410   cfun->machine->callee_saved_reg_size = 0;
411
412   /* Save callee-saved registers.  */
413   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
414     if (df_regs_ever_live_p (regno) && (!call_used_regs[regno]))
415       cfun->machine->callee_saved_reg_size += 4;
416
417   cfun->machine->size_for_adjusting_sp =
418     0 // crtl->args.pretend_args_size
419     + cfun->machine->local_vars_size
420     + (ACCUMULATE_OUTGOING_ARGS
421        ? (HOST_WIDE_INT) crtl->outgoing_args_size : 0);
422 }
423
424 // Must use LINK/UNLINK when...
425 // the frame is bigger than 512 bytes so cannot just "SUB" from SP
426 // the function actually uses $fp
427
428 static int
429 must_link (void)
430 {
431   int bigframe = (cfun->machine->size_for_adjusting_sp >= 512);
432   return (bigframe || frame_pointer_needed || df_regs_ever_live_p (FT32_FP)
433           || df_regs_ever_live_p (FT32_FP));
434 }
435
436 void
437 ft32_expand_prologue (void)
438 {
439   int regno;
440   rtx insn;
441
442   ft32_compute_frame ();
443
444   int args_to_push = crtl->args.pretend_args_size;
445   if (args_to_push)
446     {
447       int i;
448
449       insn = emit_insn (gen_movsi_pop ((gen_rtx_REG (Pmode, FT32_R29))));
450
451       for (i = 0; i < (args_to_push / 4); i++)
452         {
453           insn =
454             emit_insn (gen_movsi_push ((gen_rtx_REG (Pmode, FT32_R5 - i))));
455           RTX_FRAME_RELATED_P (insn) = 1;
456         }
457
458       insn = emit_insn (gen_movsi_push ((gen_rtx_REG (Pmode, FT32_R29))));
459     }
460
461   if (flag_stack_usage_info)
462     current_function_static_stack_size = cfun->machine->size_for_adjusting_sp;
463
464   if (!must_link () && (cfun->machine->callee_saved_reg_size == 4))
465     {
466       insn =
467         emit_insn (gen_link
468                    (gen_rtx_REG (Pmode, FT32_R13),
469                     GEN_INT (-cfun->machine->size_for_adjusting_sp)));
470       RTX_FRAME_RELATED_P (insn) = 1;
471       return;
472     }
473   /* Save callee-saved registers.  */
474   if (optimize_size)
475     {
476       for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0;)
477         {
478           if (!fixed_regs[regno] && !call_used_regs[regno]
479               && df_regs_ever_live_p (regno))
480             {
481               rtx preg = gen_rtx_REG (Pmode, regno);
482               emit_insn (gen_call_prolog (preg));
483               break;
484             }
485         }
486     }
487   else
488     {
489       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
490         {
491           if (!fixed_regs[regno] && df_regs_ever_live_p (regno)
492               && !call_used_regs[regno])
493             {
494               insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno)));
495               RTX_FRAME_RELATED_P (insn) = 1;
496             }
497         }
498     }
499
500   if (cfun->machine->size_for_adjusting_sp >= 65536)
501     {
502       error ("stack frame must be smaller than 64K");
503       return;
504     }
505   if (must_link ())
506     {
507       insn =
508         emit_insn (gen_link
509                    (gen_rtx_REG (Pmode, FT32_FP),
510                     GEN_INT (-cfun->machine->size_for_adjusting_sp)));
511       RTX_FRAME_RELATED_P (insn) = 1;
512     }
513   else if (cfun->machine->size_for_adjusting_sp > 0)
514     {
515       int adj = cfun->machine->size_for_adjusting_sp;
516       insn = emit_insn (gen_addsi3 (gen_rtx_REG (SImode, FT32_SP),
517                                     gen_rtx_REG (SImode, FT32_SP),
518                                     GEN_INT (-adj)));
519       RTX_FRAME_RELATED_P (insn) = 1;
520     }
521 }
522
523 void
524 ft32_expand_epilogue (void)
525 {
526   int regno;
527   int pretend = crtl->args.pretend_args_size;
528
529   if (!must_link ()
530       && (cfun->machine->size_for_adjusting_sp == 24)
531       && (cfun->machine->callee_saved_reg_size == 0))
532     {
533       emit_jump_insn (gen_returner24 ());
534       return;
535     }
536
537   // Set when the epilog code will also add 24 to $sp
538   int epilog24 = (!must_link ()
539                   && (cfun->machine->size_for_adjusting_sp == 24)
540                   && optimize_size);
541
542   if (must_link ())
543     {
544       emit_insn (gen_unlink ());
545     }
546   else if (!epilog24 && (cfun->machine->size_for_adjusting_sp > 0))
547     {
548       emit_insn (gen_addsi3 (gen_rtx_REG (SImode, FT32_SP),
549                              gen_rtx_REG (SImode, FT32_SP),
550                              GEN_INT (cfun->machine->size_for_adjusting_sp)));
551     }
552
553   if (cfun->machine->callee_saved_reg_size != 0)
554     {
555       for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0;)
556         {
557           if (!fixed_regs[regno] && !call_used_regs[regno]
558               && df_regs_ever_live_p (regno))
559             {
560               rtx preg = gen_rtx_REG (Pmode, regno);
561               if (optimize_size && (pretend == 0))
562                 {
563                   if (epilog24)
564                     emit_insn (gen_jump_epilog24 (preg));
565                   else
566                     emit_insn (gen_jump_epilog (preg));
567                   return;
568                 }
569               emit_insn (gen_movsi_pop (preg));
570             }
571         }
572     }
573
574   if (pretend != 0)
575     emit_jump_insn (gen_pretend_returner (GEN_INT (pretend)));
576   else
577     emit_jump_insn (gen_returner ());
578 }
579
580 #undef TARGET_FRAME_POINTER_REQUIRED
581 #define TARGET_FRAME_POINTER_REQUIRED ft32_frame_pointer_required
582 static bool
583 ft32_frame_pointer_required (void)
584 {
585   return cfun->calls_alloca;
586 }
587
588 #undef  TARGET_CAN_ELIMINATE
589 #define TARGET_CAN_ELIMINATE ft32_can_eliminate
590
591 /* Return true if register FROM can be eliminated via register TO.  */
592
593 static bool
594 ft32_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
595 {
596   return 1;
597   return (to == FRAME_POINTER_REGNUM) || !ft32_frame_pointer_required ();
598 }
599
600 /* Implements the macro INITIAL_ELIMINATION_OFFSET, return the OFFSET.  */
601
602 int
603 ft32_initial_elimination_offset (int from, int to)
604 {
605   ft32_compute_frame ();
606
607   if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
608     {
609       return cfun->machine->callee_saved_reg_size + 2 * UNITS_PER_WORD;
610     }
611
612   if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
613     {
614       int arg_offset;
615       arg_offset = must_link ()? 2 : 1;
616       return ((cfun->machine->callee_saved_reg_size
617                + arg_offset * UNITS_PER_WORD)
618               + cfun->machine->size_for_adjusting_sp);
619     }
620
621   if ((from == FRAME_POINTER_REGNUM) && (to == STACK_POINTER_REGNUM))
622     {
623       return cfun->machine->size_for_adjusting_sp;
624     }
625
626   gcc_unreachable ();
627 }
628
629 /* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
630
631 static void
632 ft32_setup_incoming_varargs (cumulative_args_t cum_v,
633                              const function_arg_info &arg,
634                              int *pretend_size, int no_rtl ATTRIBUTE_UNUSED)
635 {
636   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
637   int named_size =
638     GET_MODE_SIZE (SImode) * (*cum - FT32_R0) + GET_MODE_SIZE (arg.mode);
639
640   if (named_size < 24)
641     *pretend_size = 24 - named_size;
642   else
643     *pretend_size = 0;
644 }
645
646 /* Return the fixed registers used for condition codes.  */
647
648 static bool
649 ft32_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
650 {
651   *p1 = CC_REG;
652   *p2 = INVALID_REGNUM;
653   return true;
654 }
655
656 /* Return the next register to be used to hold a function argument or
657    NULL_RTX if there's no more space.  */
658
659 static rtx
660 ft32_function_arg (cumulative_args_t cum_v, const function_arg_info &arg)
661 {
662   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
663
664   if (*cum < 8)
665     return gen_rtx_REG (arg.mode, *cum);
666   else
667     return NULL_RTX;
668 }
669
670 #define FT32_FUNCTION_ARG_SIZE(MODE, TYPE)      \
671   ((MODE) != BLKmode ? GET_MODE_SIZE (MODE)     \
672    : (unsigned) int_size_in_bytes (TYPE))
673
674 static void
675 ft32_function_arg_advance (cumulative_args_t cum_v,
676                            const function_arg_info &arg)
677 {
678   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
679
680   *cum = (*cum < FT32_R6
681           ? *cum + ((3 + FT32_FUNCTION_ARG_SIZE (arg.mode, arg.type)) / 4)
682           : *cum);
683 }
684
685 /* Return non-zero if the function argument described by ARG is to be
686    passed by reference.  */
687
688 static bool
689 ft32_pass_by_reference (cumulative_args_t, const function_arg_info &arg)
690 {
691   if (arg.aggregate_type_p ())
692     return true;
693   unsigned HOST_WIDE_INT size = arg.type_size_in_bytes ();
694   return size > 4 * 6;
695 }
696
697 /* Some function arguments will only partially fit in the registers
698    that hold arguments.  Given a new arg, return the number of bytes
699    that fit in argument passing registers.  */
700
701 static int
702 ft32_arg_partial_bytes (cumulative_args_t cum_v, const function_arg_info &arg)
703 {
704   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
705   int bytes_left, size;
706
707   if (*cum >= 8)
708     return 0;
709
710   if (ft32_pass_by_reference (cum_v, arg))
711     size = 4;
712   else if (arg.type)
713     {
714       if (AGGREGATE_TYPE_P (arg.type))
715         return 0;
716       size = int_size_in_bytes (arg.type);
717     }
718   else
719     size = GET_MODE_SIZE (arg.mode);
720
721   bytes_left = (4 * 6) - ((*cum - 2) * 4);
722
723   if (size > bytes_left)
724     return bytes_left;
725   else
726     return 0;
727 }
728
729 /* Used by constraints.md to distinguish between GENERIC and PM
730    memory addresses.  */
731
732 int
733 ft32_is_mem_pm (rtx o)
734 {
735   return (MEM_P (o)
736           && !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (o)));
737 }
738
739 /* The Global `targetm' Variable.  */
740
741 /* Initialize the GCC target structure.  */
742
743 #undef  TARGET_PROMOTE_PROTOTYPES
744 #define TARGET_PROMOTE_PROTOTYPES       hook_bool_const_tree_true
745
746 #undef  TARGET_RETURN_IN_MEMORY
747 #define TARGET_RETURN_IN_MEMORY         ft32_return_in_memory
748 #undef  TARGET_MUST_PASS_IN_STACK
749 #define TARGET_MUST_PASS_IN_STACK       must_pass_in_stack_var_size
750 #undef  TARGET_PASS_BY_REFERENCE
751 #define TARGET_PASS_BY_REFERENCE        ft32_pass_by_reference
752 #undef  TARGET_ARG_PARTIAL_BYTES
753 #define TARGET_ARG_PARTIAL_BYTES        ft32_arg_partial_bytes
754 #undef  TARGET_FUNCTION_ARG
755 #define TARGET_FUNCTION_ARG             ft32_function_arg
756 #undef  TARGET_FUNCTION_ARG_ADVANCE
757 #define TARGET_FUNCTION_ARG_ADVANCE     ft32_function_arg_advance
758
759
760 #undef  TARGET_SETUP_INCOMING_VARARGS
761 #define TARGET_SETUP_INCOMING_VARARGS   ft32_setup_incoming_varargs
762
763 #undef  TARGET_FIXED_CONDITION_CODE_REGS
764 #define TARGET_FIXED_CONDITION_CODE_REGS ft32_fixed_condition_code_regs
765
766 /* Define this to return an RTX representing the place where a
767    function returns or receives a value of data type RET_TYPE, a tree
768    node representing a data type.  */
769 #undef TARGET_FUNCTION_VALUE
770 #define TARGET_FUNCTION_VALUE ft32_function_value
771 #undef TARGET_LIBCALL_VALUE
772 #define TARGET_LIBCALL_VALUE ft32_libcall_value
773 #undef TARGET_FUNCTION_VALUE_REGNO_P
774 #define TARGET_FUNCTION_VALUE_REGNO_P ft32_function_value_regno_p
775
776 #undef TARGET_OPTION_OVERRIDE
777 #define TARGET_OPTION_OVERRIDE ft32_option_override
778
779 #undef TARGET_ASM_SELECT_SECTION
780 #define TARGET_ASM_SELECT_SECTION  ft32_select_section
781
782 #undef TARGET_VALID_POINTER_MODE
783 #define TARGET_VALID_POINTER_MODE ft32_valid_pointer_mode
784 static bool
785 ft32_valid_pointer_mode (scalar_int_mode mode)
786 {
787   if (mode == SImode)
788     return 1;
789   return 0;
790 }
791
792 #undef TARGET_ADDR_SPACE_POINTER_MODE
793 #define TARGET_ADDR_SPACE_POINTER_MODE ft32_addr_space_pointer_mode
794 static scalar_int_mode
795 ft32_addr_space_pointer_mode (addr_space_t addrspace ATTRIBUTE_UNUSED)
796 {
797   return Pmode;
798 }
799
800 #undef TARGET_ADDR_SPACE_ADDRESS_MODE
801 #define TARGET_ADDR_SPACE_ADDRESS_MODE ft32_addr_space_address_mode
802 static scalar_int_mode
803 ft32_addr_space_address_mode (addr_space_t addrspace ATTRIBUTE_UNUSED)
804 {
805   return Pmode;
806 }
807
808 #undef TARGET_ADDR_SPACE_SUBSET_P
809 #define TARGET_ADDR_SPACE_SUBSET_P ft32_addr_space_subset_p
810 static bool
811 ft32_addr_space_subset_p (addr_space_t subset ATTRIBUTE_UNUSED,
812                           addr_space_t superset ATTRIBUTE_UNUSED)
813 {
814   return false;
815 }
816
817 #undef TARGET_CASE_VALUES_THRESHOLD
818 #define TARGET_CASE_VALUES_THRESHOLD ft32_target_case_values_threshold
819
820 static unsigned int
821 ft32_target_case_values_threshold (void)
822 {
823   return 4;
824 }
825
826 #undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
827 #define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \
828   ft32_addr_space_legitimate_address_p
829
830
831 // Enabling LRA gives the infamous
832 //    internal compiler error: Max. number of generated reload insns per insn is achieved (90)
833 // errors e.g. when compiling sieve.c
834
835 static bool
836 ft32_lra_p (void)
837 {
838   return ft32_lra_flag;
839 }
840
841 #undef TARGET_LRA_P
842 #define TARGET_LRA_P ft32_lra_p
843
844 static bool
845 reg_ok_for_base_p (rtx r, bool strict)
846 {
847   int NUM = REGNO (r);
848   if (strict)
849     return (HARD_REGNO_OK_FOR_BASE_P (NUM)
850             || HARD_REGNO_OK_FOR_BASE_P (reg_renumber[(NUM)]));
851   else
852     return ((NUM) >= FIRST_PSEUDO_REGISTER || HARD_REGNO_OK_FOR_BASE_P (NUM));
853 }
854
855 static bool
856 ft32_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict,
857                                       addr_space_t as ATTRIBUTE_UNUSED)
858 {
859   int max_offset = TARGET_FT32B ? 16384 : 128;
860
861   if (mode != BLKmode)
862     {
863       if (GET_CODE (x) == PLUS)
864         {
865           rtx op1, op2;
866           op1 = XEXP (x, 0);
867           op2 = XEXP (x, 1);
868           if (GET_CODE (op1) == REG
869               && CONST_INT_P (op2)
870               && (-max_offset <= INTVAL (op2))
871               && (INTVAL (op2) < max_offset)
872               && reg_ok_for_base_p (op1, strict))
873             goto yes;
874           if (GET_CODE (op1) == SYMBOL_REF && CONST_INT_P (op2))
875             goto yes;
876         }
877       if (REG_P (x) && reg_ok_for_base_p (x, strict))
878         goto yes;
879       if (GET_CODE (x) == SYMBOL_REF
880           || GET_CODE (x) == LABEL_REF || CONST_INT_P (x))
881         goto yes;
882     }
883   else
884     {
885       if (REG_P (x) && reg_ok_for_base_p (x, strict))
886         goto yes;
887     }
888
889   return 0;
890 yes:
891   return 1;
892 }
893
894 #undef TARGET_ENCODE_SECTION_INFO
895 #define TARGET_ENCODE_SECTION_INFO  ft32_elf_encode_section_info
896
897 void
898 ft32_elf_encode_section_info (tree decl, rtx rtl, int first)
899 {
900   enum tree_code code;
901   rtx symbol;
902
903   /* Careful not to prod global register variables.  */
904   if (!MEM_P (rtl))
905     return;
906   symbol = XEXP (rtl, 0);
907   if (GET_CODE (symbol) != SYMBOL_REF)
908     return;
909
910   default_encode_section_info (decl, rtl, first);
911
912   code = TREE_CODE (decl);
913   switch (TREE_CODE_CLASS (code))
914     {
915     case tcc_declaration:
916       {
917         tree type = TREE_TYPE (decl);
918         int is_flash = (type && TYPE_P (type)
919                         && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)));
920         if ((code == VAR_DECL) && !is_flash)
921           SYMBOL_REF_FLAGS (symbol) |= 0x1000;
922       }
923       break;
924
925     case tcc_constant:
926     case tcc_exceptional:
927       if (code == STRING_CST)
928         SYMBOL_REF_FLAGS (symbol) |= 0x1000;
929       break;
930
931     default:
932       break;
933     }
934 }
935
936 #undef TARGET_CONSTANT_ALIGNMENT
937 #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
938
939 struct gcc_target targetm = TARGET_INITIALIZER;
940
941 #include "gt-ft32.h"