1 /* Target Code for ft32
2    Copyright (C) 2015-2018 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
ft32_return_in_memory(const_tree type,const_tree fntype ATTRIBUTE_UNUSED)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
ft32_function_value(const_tree valtype,const_tree fntype_or_decl ATTRIBUTE_UNUSED,bool outgoing ATTRIBUTE_UNUSED)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
ft32_libcall_value(machine_mode mode,const_rtx fun ATTRIBUTE_UNUSED)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
ft32_function_value_regno_p(const unsigned int regno)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
ft32_operand_lossage(const char * msgid,rtx op)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
ft32_print_operand_address(FILE * file,rtx x)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
ft32_print_operand(FILE * file,rtx x,int code)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 *
ft32_load_immediate(rtx dst,int32_t i)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
ft32_as_bitfield(unsigned int x)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 *
ft32_init_machine_status(void)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
ft32_option_override(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 *
ft32_select_section(tree decl,int reloc,unsigned HOST_WIDE_INT align)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
ft32_compute_frame(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
must_link(void)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
ft32_expand_prologue(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
ft32_expand_epilogue(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
ft32_frame_pointer_required(void)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
ft32_can_eliminate(const int from ATTRIBUTE_UNUSED,const int to)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
ft32_initial_elimination_offset(int from,int to)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
ft32_setup_incoming_varargs(cumulative_args_t cum_v,machine_mode mode,tree type ATTRIBUTE_UNUSED,int * pretend_size,int no_rtl ATTRIBUTE_UNUSED)632 ft32_setup_incoming_varargs (cumulative_args_t cum_v,
633 			     machine_mode mode,
634 			     tree type ATTRIBUTE_UNUSED,
635 			     int *pretend_size, int no_rtl ATTRIBUTE_UNUSED)
636 {
637   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
638   int named_size =
639     GET_MODE_SIZE (SImode) * (*cum - FT32_R0) + GET_MODE_SIZE (mode);
640 
641   if (named_size < 24)
642     *pretend_size = 24 - named_size;
643   else
644     *pretend_size = 0;
645 }
646 
647 /* Return the fixed registers used for condition codes.  */
648 
649 static bool
ft32_fixed_condition_code_regs(unsigned int * p1,unsigned int * p2)650 ft32_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
651 {
652   *p1 = CC_REG;
653   *p2 = INVALID_REGNUM;
654   return true;
655 }
656 
657 /* Return the next register to be used to hold a function argument or
658    NULL_RTX if there's no more space.  */
659 
660 static rtx
ft32_function_arg(cumulative_args_t cum_v,machine_mode mode,const_tree type ATTRIBUTE_UNUSED,bool named ATTRIBUTE_UNUSED)661 ft32_function_arg (cumulative_args_t cum_v, machine_mode mode,
662                    const_tree type ATTRIBUTE_UNUSED,
663                    bool named ATTRIBUTE_UNUSED)
664 {
665   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
666 
667   if (*cum < 8)
668     return gen_rtx_REG (mode, *cum);
669   else
670     return NULL_RTX;
671 }
672 
673 #define FT32_FUNCTION_ARG_SIZE(MODE, TYPE)      \
674   ((MODE) != BLKmode ? GET_MODE_SIZE (MODE)     \
675    : (unsigned) int_size_in_bytes (TYPE))
676 
677 static void
ft32_function_arg_advance(cumulative_args_t cum_v,machine_mode mode,const_tree type,bool named ATTRIBUTE_UNUSED)678 ft32_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
679                            const_tree type, bool named ATTRIBUTE_UNUSED)
680 {
681   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
682 
683   *cum = (*cum < FT32_R6
684           ? *cum + ((3 + FT32_FUNCTION_ARG_SIZE (mode, type)) / 4) : *cum);
685 }
686 
687 /* Return non-zero if the function argument described by TYPE is to be
688    passed by reference.  */
689 
690 static bool
ft32_pass_by_reference(cumulative_args_t cum ATTRIBUTE_UNUSED,machine_mode mode,const_tree type,bool named ATTRIBUTE_UNUSED)691 ft32_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
692                         machine_mode mode, const_tree type,
693                         bool named ATTRIBUTE_UNUSED)
694 {
695   unsigned HOST_WIDE_INT size;
696 
697   if (type)
698     {
699       if (AGGREGATE_TYPE_P (type))
700         return true;
701       size = int_size_in_bytes (type);
702     }
703   else
704     size = GET_MODE_SIZE (mode);
705 
706   return size > 4 * 6;
707 }
708 
709 /* Some function arguments will only partially fit in the registers
710    that hold arguments.  Given a new arg, return the number of bytes
711    that fit in argument passing registers.  */
712 
713 static int
ft32_arg_partial_bytes(cumulative_args_t cum_v,machine_mode mode,tree type,bool named)714 ft32_arg_partial_bytes (cumulative_args_t cum_v,
715                         machine_mode mode, tree type, bool named)
716 {
717   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
718   int bytes_left, size;
719 
720   if (*cum >= 8)
721     return 0;
722 
723   if (ft32_pass_by_reference (cum_v, mode, type, named))
724     size = 4;
725   else if (type)
726     {
727       if (AGGREGATE_TYPE_P (type))
728         return 0;
729       size = int_size_in_bytes (type);
730     }
731   else
732     size = GET_MODE_SIZE (mode);
733 
734   bytes_left = (4 * 6) - ((*cum - 2) * 4);
735 
736   if (size > bytes_left)
737     return bytes_left;
738   else
739     return 0;
740 }
741 
742 /* Used by constraints.md to distinguish between GENERIC and PM
743    memory addresses.  */
744 
745 int
ft32_is_mem_pm(rtx o)746 ft32_is_mem_pm (rtx o)
747 {
748   return (MEM_P (o)
749           && !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (o)));
750 }
751 
752 /* The Global `targetm' Variable.  */
753 
754 /* Initialize the GCC target structure.  */
755 
756 #undef  TARGET_PROMOTE_PROTOTYPES
757 #define TARGET_PROMOTE_PROTOTYPES       hook_bool_const_tree_true
758 
759 #undef  TARGET_RETURN_IN_MEMORY
760 #define TARGET_RETURN_IN_MEMORY         ft32_return_in_memory
761 #undef  TARGET_MUST_PASS_IN_STACK
762 #define TARGET_MUST_PASS_IN_STACK       must_pass_in_stack_var_size
763 #undef  TARGET_PASS_BY_REFERENCE
764 #define TARGET_PASS_BY_REFERENCE        ft32_pass_by_reference
765 #undef  TARGET_ARG_PARTIAL_BYTES
766 #define TARGET_ARG_PARTIAL_BYTES        ft32_arg_partial_bytes
767 #undef  TARGET_FUNCTION_ARG
768 #define TARGET_FUNCTION_ARG             ft32_function_arg
769 #undef  TARGET_FUNCTION_ARG_ADVANCE
770 #define TARGET_FUNCTION_ARG_ADVANCE     ft32_function_arg_advance
771 
772 
773 #undef  TARGET_SETUP_INCOMING_VARARGS
774 #define TARGET_SETUP_INCOMING_VARARGS   ft32_setup_incoming_varargs
775 
776 #undef  TARGET_FIXED_CONDITION_CODE_REGS
777 #define TARGET_FIXED_CONDITION_CODE_REGS ft32_fixed_condition_code_regs
778 
779 /* Define this to return an RTX representing the place where a
780    function returns or receives a value of data type RET_TYPE, a tree
781    node representing a data type.  */
782 #undef TARGET_FUNCTION_VALUE
783 #define TARGET_FUNCTION_VALUE ft32_function_value
784 #undef TARGET_LIBCALL_VALUE
785 #define TARGET_LIBCALL_VALUE ft32_libcall_value
786 #undef TARGET_FUNCTION_VALUE_REGNO_P
787 #define TARGET_FUNCTION_VALUE_REGNO_P ft32_function_value_regno_p
788 
789 #undef TARGET_OPTION_OVERRIDE
790 #define TARGET_OPTION_OVERRIDE ft32_option_override
791 
792 #undef TARGET_ASM_SELECT_SECTION
793 #define TARGET_ASM_SELECT_SECTION  ft32_select_section
794 
795 #undef TARGET_VALID_POINTER_MODE
796 #define TARGET_VALID_POINTER_MODE ft32_valid_pointer_mode
797 static bool
ft32_valid_pointer_mode(scalar_int_mode mode)798 ft32_valid_pointer_mode (scalar_int_mode mode)
799 {
800   if (mode == SImode)
801     return 1;
802   return 0;
803 }
804 
805 #undef TARGET_ADDR_SPACE_POINTER_MODE
806 #define TARGET_ADDR_SPACE_POINTER_MODE ft32_addr_space_pointer_mode
807 static scalar_int_mode
ft32_addr_space_pointer_mode(addr_space_t addrspace ATTRIBUTE_UNUSED)808 ft32_addr_space_pointer_mode (addr_space_t addrspace ATTRIBUTE_UNUSED)
809 {
810   return Pmode;
811 }
812 
813 #undef TARGET_ADDR_SPACE_ADDRESS_MODE
814 #define TARGET_ADDR_SPACE_ADDRESS_MODE ft32_addr_space_address_mode
815 static scalar_int_mode
ft32_addr_space_address_mode(addr_space_t addrspace ATTRIBUTE_UNUSED)816 ft32_addr_space_address_mode (addr_space_t addrspace ATTRIBUTE_UNUSED)
817 {
818   return Pmode;
819 }
820 
821 #undef TARGET_ADDR_SPACE_SUBSET_P
822 #define TARGET_ADDR_SPACE_SUBSET_P ft32_addr_space_subset_p
823 static bool
ft32_addr_space_subset_p(addr_space_t subset ATTRIBUTE_UNUSED,addr_space_t superset ATTRIBUTE_UNUSED)824 ft32_addr_space_subset_p (addr_space_t subset ATTRIBUTE_UNUSED,
825                           addr_space_t superset ATTRIBUTE_UNUSED)
826 {
827   return false;
828 }
829 
830 #undef TARGET_CASE_VALUES_THRESHOLD
831 #define TARGET_CASE_VALUES_THRESHOLD ft32_target_case_values_threshold
832 
833 static unsigned int
ft32_target_case_values_threshold(void)834 ft32_target_case_values_threshold (void)
835 {
836   return 4;
837 }
838 
839 #undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
840 #define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \
841   ft32_addr_space_legitimate_address_p
842 
843 
844 // Enabling LRA gives the infamous
845 //    internal compiler error: Max. number of generated reload insns per insn is achieved (90)
846 // errors e.g. when compiling sieve.c
847 
848 static bool
ft32_lra_p(void)849 ft32_lra_p (void)
850 {
851   return ft32_lra_flag;
852 }
853 
854 #undef TARGET_LRA_P
855 #define TARGET_LRA_P ft32_lra_p
856 
857 static bool
reg_ok_for_base_p(rtx r,bool strict)858 reg_ok_for_base_p (rtx r, bool strict)
859 {
860   int NUM = REGNO (r);
861   if (strict)
862     return (HARD_REGNO_OK_FOR_BASE_P (NUM)
863             || HARD_REGNO_OK_FOR_BASE_P (reg_renumber[(NUM)]));
864   else
865     return ((NUM) >= FIRST_PSEUDO_REGISTER || HARD_REGNO_OK_FOR_BASE_P (NUM));
866 }
867 
868 static bool
ft32_addr_space_legitimate_address_p(machine_mode mode,rtx x,bool strict,addr_space_t as ATTRIBUTE_UNUSED)869 ft32_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict,
870                                       addr_space_t as ATTRIBUTE_UNUSED)
871 {
872   int max_offset = TARGET_FT32B ? 16384 : 128;
873 
874   if (mode != BLKmode)
875     {
876       if (GET_CODE (x) == PLUS)
877         {
878           rtx op1, op2;
879           op1 = XEXP (x, 0);
880           op2 = XEXP (x, 1);
881           if (GET_CODE (op1) == REG
882               && CONST_INT_P (op2)
883               && (-max_offset <= INTVAL (op2))
884               && (INTVAL (op2) < max_offset)
885               && reg_ok_for_base_p (op1, strict))
886             goto yes;
887           if (GET_CODE (op1) == SYMBOL_REF && CONST_INT_P (op2))
888             goto yes;
889         }
890       if (REG_P (x) && reg_ok_for_base_p (x, strict))
891         goto yes;
892       if (GET_CODE (x) == SYMBOL_REF
893           || GET_CODE (x) == LABEL_REF || CONST_INT_P (x))
894         goto yes;
895     }
896   else
897     {
898       if (REG_P (x) && reg_ok_for_base_p (x, strict))
899         goto yes;
900     }
901 
902   return 0;
903 yes:
904   return 1;
905 }
906 
907 #undef TARGET_ENCODE_SECTION_INFO
908 #define TARGET_ENCODE_SECTION_INFO  ft32_elf_encode_section_info
909 
910 void
ft32_elf_encode_section_info(tree decl,rtx rtl,int first)911 ft32_elf_encode_section_info (tree decl, rtx rtl, int first)
912 {
913   enum tree_code code;
914   rtx symbol;
915 
916   /* Careful not to prod global register variables.  */
917   if (!MEM_P (rtl))
918     return;
919   symbol = XEXP (rtl, 0);
920   if (GET_CODE (symbol) != SYMBOL_REF)
921     return;
922 
923   default_encode_section_info (decl, rtl, first);
924 
925   code = TREE_CODE (decl);
926   switch (TREE_CODE_CLASS (code))
927     {
928     case tcc_declaration:
929       {
930 	tree type = TREE_TYPE (decl);
931 	int is_flash = (type && TYPE_P (type)
932 			&& !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)));
933 	if ((code == VAR_DECL) && !is_flash)
934 	  SYMBOL_REF_FLAGS (symbol) |= 0x1000;
935       }
936       break;
937 
938     case tcc_constant:
939     case tcc_exceptional:
940       if (code == STRING_CST)
941 	SYMBOL_REF_FLAGS (symbol) |= 0x1000;
942       break;
943 
944     default:
945       break;
946     }
947 }
948 
949 #undef TARGET_CONSTANT_ALIGNMENT
950 #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
951 
952 struct gcc_target targetm = TARGET_INITIALIZER;
953 
954 #include "gt-ft32.h"
955