xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/lm32/lm32.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
136ac495dSmrg /* Subroutines used for code generation on the Lattice Mico32 architecture.
236ac495dSmrg    Contributed by Jon Beniston <jon@beniston.com>
336ac495dSmrg 
4*8feb0f0bSmrg    Copyright (C) 2009-2020 Free Software Foundation, Inc.
536ac495dSmrg 
636ac495dSmrg    This file is part of GCC.
736ac495dSmrg 
836ac495dSmrg    GCC is free software; you can redistribute it and/or modify it
936ac495dSmrg    under the terms of the GNU General Public License as published
1036ac495dSmrg    by the Free Software Foundation; either version 3, or (at your
1136ac495dSmrg    option) any later version.
1236ac495dSmrg 
1336ac495dSmrg    GCC is distributed in the hope that it will be useful, but WITHOUT
1436ac495dSmrg    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1536ac495dSmrg    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
1636ac495dSmrg    License for more details.
1736ac495dSmrg 
1836ac495dSmrg    You should have received a copy of the GNU General Public License
1936ac495dSmrg    along with GCC; see the file COPYING3.  If not see
2036ac495dSmrg    <http://www.gnu.org/licenses/>.  */
2136ac495dSmrg 
22a2dc1f3fSmrg #define IN_TARGET_CODE 1
23a2dc1f3fSmrg 
2436ac495dSmrg #include "config.h"
2536ac495dSmrg #include "system.h"
2636ac495dSmrg #include "coretypes.h"
2736ac495dSmrg #include "backend.h"
2836ac495dSmrg #include "target.h"
2936ac495dSmrg #include "rtl.h"
3036ac495dSmrg #include "tree.h"
31a2dc1f3fSmrg #include "stringpool.h"
32a2dc1f3fSmrg #include "attribs.h"
3336ac495dSmrg #include "df.h"
3436ac495dSmrg #include "memmodel.h"
3536ac495dSmrg #include "tm_p.h"
3636ac495dSmrg #include "optabs.h"
3736ac495dSmrg #include "regs.h"
3836ac495dSmrg #include "emit-rtl.h"
3936ac495dSmrg #include "recog.h"
4036ac495dSmrg #include "output.h"
4136ac495dSmrg #include "calls.h"
4236ac495dSmrg #include "alias.h"
4336ac495dSmrg #include "explow.h"
4436ac495dSmrg #include "expr.h"
4536ac495dSmrg #include "tm-constrs.h"
4636ac495dSmrg #include "builtins.h"
4736ac495dSmrg 
4836ac495dSmrg /* This file should be included last.  */
4936ac495dSmrg #include "target-def.h"
5036ac495dSmrg 
5136ac495dSmrg struct lm32_frame_info
5236ac495dSmrg {
5336ac495dSmrg   HOST_WIDE_INT total_size;	/* number of bytes of entire frame.  */
5436ac495dSmrg   HOST_WIDE_INT callee_size;	/* number of bytes to save callee saves.  */
5536ac495dSmrg   HOST_WIDE_INT pretend_size;	/* number of bytes we pretend caller did.  */
5636ac495dSmrg   HOST_WIDE_INT args_size;	/* number of bytes for outgoing arguments.  */
5736ac495dSmrg   HOST_WIDE_INT locals_size;	/* number of bytes for local variables.  */
5836ac495dSmrg   unsigned int reg_save_mask;	/* mask of saved registers.  */
5936ac495dSmrg };
6036ac495dSmrg 
6136ac495dSmrg /* Prototypes for static functions.  */
6236ac495dSmrg static rtx emit_add (rtx dest, rtx src0, rtx src1);
6336ac495dSmrg static void expand_save_restore (struct lm32_frame_info *info, int op);
6436ac495dSmrg static void stack_adjust (HOST_WIDE_INT amount);
6536ac495dSmrg static bool lm32_in_small_data_p (const_tree);
6636ac495dSmrg static void lm32_setup_incoming_varargs (cumulative_args_t cum,
67*8feb0f0bSmrg 					 const function_arg_info &,
6836ac495dSmrg 					 int *pretend_size, int no_rtl);
6936ac495dSmrg static bool lm32_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno,
7036ac495dSmrg 			    int *total, bool speed);
7136ac495dSmrg static bool lm32_can_eliminate (const int, const int);
7236ac495dSmrg static bool
7336ac495dSmrg lm32_legitimate_address_p (machine_mode mode, rtx x, bool strict);
7436ac495dSmrg static HOST_WIDE_INT lm32_compute_frame_size (int size);
7536ac495dSmrg static void lm32_option_override (void);
76*8feb0f0bSmrg static rtx lm32_function_arg (cumulative_args_t, const function_arg_info &);
7736ac495dSmrg static void lm32_function_arg_advance (cumulative_args_t cum,
78*8feb0f0bSmrg 				       const function_arg_info &);
79a2dc1f3fSmrg static bool lm32_hard_regno_mode_ok (unsigned int, machine_mode);
80a2dc1f3fSmrg static bool lm32_modes_tieable_p (machine_mode, machine_mode);
81a2dc1f3fSmrg static HOST_WIDE_INT lm32_starting_frame_offset (void);
8236ac495dSmrg 
8336ac495dSmrg #undef TARGET_OPTION_OVERRIDE
8436ac495dSmrg #define TARGET_OPTION_OVERRIDE lm32_option_override
8536ac495dSmrg #undef TARGET_ADDRESS_COST
8636ac495dSmrg #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
8736ac495dSmrg #undef TARGET_RTX_COSTS
8836ac495dSmrg #define TARGET_RTX_COSTS lm32_rtx_costs
8936ac495dSmrg #undef TARGET_IN_SMALL_DATA_P
9036ac495dSmrg #define TARGET_IN_SMALL_DATA_P lm32_in_small_data_p
9136ac495dSmrg #undef TARGET_PROMOTE_FUNCTION_MODE
9236ac495dSmrg #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
9336ac495dSmrg #undef TARGET_SETUP_INCOMING_VARARGS
9436ac495dSmrg #define TARGET_SETUP_INCOMING_VARARGS lm32_setup_incoming_varargs
9536ac495dSmrg #undef TARGET_FUNCTION_ARG
9636ac495dSmrg #define TARGET_FUNCTION_ARG lm32_function_arg
9736ac495dSmrg #undef TARGET_FUNCTION_ARG_ADVANCE
9836ac495dSmrg #define TARGET_FUNCTION_ARG_ADVANCE lm32_function_arg_advance
9936ac495dSmrg #undef TARGET_PROMOTE_PROTOTYPES
10036ac495dSmrg #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
10136ac495dSmrg #undef TARGET_MIN_ANCHOR_OFFSET
10236ac495dSmrg #define TARGET_MIN_ANCHOR_OFFSET -0x8000
10336ac495dSmrg #undef TARGET_MAX_ANCHOR_OFFSET
10436ac495dSmrg #define TARGET_MAX_ANCHOR_OFFSET 0x7fff
10536ac495dSmrg #undef TARGET_CAN_ELIMINATE
10636ac495dSmrg #define TARGET_CAN_ELIMINATE lm32_can_eliminate
10736ac495dSmrg #undef TARGET_LRA_P
10836ac495dSmrg #define TARGET_LRA_P hook_bool_void_false
10936ac495dSmrg #undef TARGET_LEGITIMATE_ADDRESS_P
11036ac495dSmrg #define TARGET_LEGITIMATE_ADDRESS_P lm32_legitimate_address_p
111a2dc1f3fSmrg #undef TARGET_HARD_REGNO_MODE_OK
112a2dc1f3fSmrg #define TARGET_HARD_REGNO_MODE_OK lm32_hard_regno_mode_ok
113a2dc1f3fSmrg #undef TARGET_MODES_TIEABLE_P
114a2dc1f3fSmrg #define TARGET_MODES_TIEABLE_P lm32_modes_tieable_p
115a2dc1f3fSmrg 
116a2dc1f3fSmrg #undef TARGET_CONSTANT_ALIGNMENT
117a2dc1f3fSmrg #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
118a2dc1f3fSmrg 
119a2dc1f3fSmrg #undef TARGET_STARTING_FRAME_OFFSET
120a2dc1f3fSmrg #define TARGET_STARTING_FRAME_OFFSET lm32_starting_frame_offset
12136ac495dSmrg 
12236ac495dSmrg struct gcc_target targetm = TARGET_INITIALIZER;
12336ac495dSmrg 
12436ac495dSmrg /* Current frame information calculated by lm32_compute_frame_size.  */
12536ac495dSmrg static struct lm32_frame_info current_frame_info;
12636ac495dSmrg 
12736ac495dSmrg /* Return non-zero if the given return type should be returned in memory.  */
12836ac495dSmrg 
12936ac495dSmrg int
lm32_return_in_memory(tree type)13036ac495dSmrg lm32_return_in_memory (tree type)
13136ac495dSmrg {
13236ac495dSmrg   HOST_WIDE_INT size;
13336ac495dSmrg 
13436ac495dSmrg   if (!AGGREGATE_TYPE_P (type))
13536ac495dSmrg     {
13636ac495dSmrg       /* All simple types are returned in registers.  */
13736ac495dSmrg       return 0;
13836ac495dSmrg     }
13936ac495dSmrg 
14036ac495dSmrg   size = int_size_in_bytes (type);
14136ac495dSmrg   if (size >= 0 && size <= UNITS_PER_WORD)
14236ac495dSmrg     {
14336ac495dSmrg       /* If it can fit in one register.  */
14436ac495dSmrg       return 0;
14536ac495dSmrg     }
14636ac495dSmrg 
14736ac495dSmrg   return 1;
14836ac495dSmrg }
14936ac495dSmrg 
15036ac495dSmrg /* Generate an emit a word sized add instruction.  */
15136ac495dSmrg 
15236ac495dSmrg static rtx
emit_add(rtx dest,rtx src0,rtx src1)15336ac495dSmrg emit_add (rtx dest, rtx src0, rtx src1)
15436ac495dSmrg {
15536ac495dSmrg   rtx insn;
15636ac495dSmrg   insn = emit_insn (gen_addsi3 (dest, src0, src1));
15736ac495dSmrg   return insn;
15836ac495dSmrg }
15936ac495dSmrg 
16036ac495dSmrg /* Generate the code to compare (and possibly branch) two integer values
16136ac495dSmrg    TEST_CODE is the comparison code we are trying to emulate
16236ac495dSmrg      (or implement directly)
16336ac495dSmrg    RESULT is where to store the result of the comparison,
16436ac495dSmrg      or null to emit a branch
16536ac495dSmrg    CMP0 CMP1 are the two comparison operands
16636ac495dSmrg    DESTINATION is the destination of the branch, or null to only compare
16736ac495dSmrg    */
16836ac495dSmrg 
16936ac495dSmrg static void
gen_int_relational(enum rtx_code code,rtx result,rtx cmp0,rtx cmp1,rtx destination)17036ac495dSmrg gen_int_relational (enum rtx_code code,
17136ac495dSmrg 		    rtx result,
17236ac495dSmrg 		    rtx cmp0,
17336ac495dSmrg 		    rtx cmp1,
17436ac495dSmrg 		    rtx destination)
17536ac495dSmrg {
17636ac495dSmrg   machine_mode mode;
17736ac495dSmrg   int branch_p;
17836ac495dSmrg 
17936ac495dSmrg   mode = GET_MODE (cmp0);
18036ac495dSmrg   if (mode == VOIDmode)
18136ac495dSmrg     mode = GET_MODE (cmp1);
18236ac495dSmrg 
18336ac495dSmrg   /* Is this a branch or compare.  */
18436ac495dSmrg   branch_p = (destination != 0);
18536ac495dSmrg 
18636ac495dSmrg   /* Instruction set doesn't support LE or LT, so swap operands and use
18736ac495dSmrg      GE, GT.  */
18836ac495dSmrg   switch (code)
18936ac495dSmrg     {
19036ac495dSmrg     case LE:
19136ac495dSmrg     case LT:
19236ac495dSmrg     case LEU:
19336ac495dSmrg     case LTU:
19436ac495dSmrg       {
19536ac495dSmrg 	rtx temp;
19636ac495dSmrg 
19736ac495dSmrg 	code = swap_condition (code);
19836ac495dSmrg 	temp = cmp0;
19936ac495dSmrg 	cmp0 = cmp1;
20036ac495dSmrg 	cmp1 = temp;
20136ac495dSmrg 	break;
20236ac495dSmrg       }
20336ac495dSmrg     default:
20436ac495dSmrg       break;
20536ac495dSmrg     }
20636ac495dSmrg 
20736ac495dSmrg   if (branch_p)
20836ac495dSmrg     {
20936ac495dSmrg       rtx insn, cond, label;
21036ac495dSmrg 
21136ac495dSmrg       /* Operands must be in registers.  */
21236ac495dSmrg       if (!register_operand (cmp0, mode))
21336ac495dSmrg 	cmp0 = force_reg (mode, cmp0);
21436ac495dSmrg       if (!register_operand (cmp1, mode))
21536ac495dSmrg 	cmp1 = force_reg (mode, cmp1);
21636ac495dSmrg 
21736ac495dSmrg       /* Generate conditional branch instruction.  */
21836ac495dSmrg       cond = gen_rtx_fmt_ee (code, mode, cmp0, cmp1);
21936ac495dSmrg       label = gen_rtx_LABEL_REF (VOIDmode, destination);
22036ac495dSmrg       insn = gen_rtx_SET (pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode,
22136ac495dSmrg 							cond, label, pc_rtx));
22236ac495dSmrg       emit_jump_insn (insn);
22336ac495dSmrg     }
22436ac495dSmrg   else
22536ac495dSmrg     {
22636ac495dSmrg       /* We can't have const_ints in cmp0, other than 0.  */
22736ac495dSmrg       if ((GET_CODE (cmp0) == CONST_INT) && (INTVAL (cmp0) != 0))
22836ac495dSmrg 	cmp0 = force_reg (mode, cmp0);
22936ac495dSmrg 
23036ac495dSmrg       /* If the comparison is against an int not in legal range
23136ac495dSmrg          move it into a register.  */
23236ac495dSmrg       if (GET_CODE (cmp1) == CONST_INT)
23336ac495dSmrg 	{
23436ac495dSmrg 	  switch (code)
23536ac495dSmrg 	    {
23636ac495dSmrg 	    case EQ:
23736ac495dSmrg 	    case NE:
23836ac495dSmrg 	    case LE:
23936ac495dSmrg 	    case LT:
24036ac495dSmrg 	    case GE:
24136ac495dSmrg 	    case GT:
24236ac495dSmrg 	      if (!satisfies_constraint_K (cmp1))
24336ac495dSmrg 		cmp1 = force_reg (mode, cmp1);
24436ac495dSmrg 	      break;
24536ac495dSmrg 	    case LEU:
24636ac495dSmrg 	    case LTU:
24736ac495dSmrg 	    case GEU:
24836ac495dSmrg 	    case GTU:
24936ac495dSmrg 	      if (!satisfies_constraint_L (cmp1))
25036ac495dSmrg 		cmp1 = force_reg (mode, cmp1);
25136ac495dSmrg 	      break;
25236ac495dSmrg 	    default:
25336ac495dSmrg 	      gcc_unreachable ();
25436ac495dSmrg 	    }
25536ac495dSmrg 	}
25636ac495dSmrg 
25736ac495dSmrg       /* Generate compare instruction.  */
25836ac495dSmrg       emit_move_insn (result, gen_rtx_fmt_ee (code, mode, cmp0, cmp1));
25936ac495dSmrg     }
26036ac495dSmrg }
26136ac495dSmrg 
26236ac495dSmrg /* Try performing the comparison in OPERANDS[1], whose arms are OPERANDS[2]
26336ac495dSmrg    and OPERAND[3].  Store the result in OPERANDS[0].  */
26436ac495dSmrg 
26536ac495dSmrg void
lm32_expand_scc(rtx operands[])26636ac495dSmrg lm32_expand_scc (rtx operands[])
26736ac495dSmrg {
26836ac495dSmrg   rtx target = operands[0];
26936ac495dSmrg   enum rtx_code code = GET_CODE (operands[1]);
27036ac495dSmrg   rtx op0 = operands[2];
27136ac495dSmrg   rtx op1 = operands[3];
27236ac495dSmrg 
27336ac495dSmrg   gen_int_relational (code, target, op0, op1, NULL_RTX);
27436ac495dSmrg }
27536ac495dSmrg 
27636ac495dSmrg /* Compare OPERANDS[1] with OPERANDS[2] using comparison code
27736ac495dSmrg    CODE and jump to OPERANDS[3] if the condition holds.  */
27836ac495dSmrg 
27936ac495dSmrg void
lm32_expand_conditional_branch(rtx operands[])28036ac495dSmrg lm32_expand_conditional_branch (rtx operands[])
28136ac495dSmrg {
28236ac495dSmrg   enum rtx_code code = GET_CODE (operands[0]);
28336ac495dSmrg   rtx op0 = operands[1];
28436ac495dSmrg   rtx op1 = operands[2];
28536ac495dSmrg   rtx destination = operands[3];
28636ac495dSmrg 
28736ac495dSmrg   gen_int_relational (code, NULL_RTX, op0, op1, destination);
28836ac495dSmrg }
28936ac495dSmrg 
29036ac495dSmrg /* Generate and emit RTL to save or restore callee save registers.  */
29136ac495dSmrg static void
expand_save_restore(struct lm32_frame_info * info,int op)29236ac495dSmrg expand_save_restore (struct lm32_frame_info *info, int op)
29336ac495dSmrg {
29436ac495dSmrg   unsigned int reg_save_mask = info->reg_save_mask;
29536ac495dSmrg   int regno;
29636ac495dSmrg   HOST_WIDE_INT offset;
29736ac495dSmrg   rtx insn;
29836ac495dSmrg 
29936ac495dSmrg   /* Callee saves are below locals and above outgoing arguments.  */
30036ac495dSmrg   offset = info->args_size + info->callee_size;
30136ac495dSmrg   for (regno = 0; regno <= 31; regno++)
30236ac495dSmrg     {
30336ac495dSmrg       if ((reg_save_mask & (1 << regno)) != 0)
30436ac495dSmrg 	{
30536ac495dSmrg 	  rtx offset_rtx;
30636ac495dSmrg 	  rtx mem;
30736ac495dSmrg 
30836ac495dSmrg 	  offset_rtx = GEN_INT (offset);
30936ac495dSmrg 	  if (satisfies_constraint_K (offset_rtx))
31036ac495dSmrg 	    {
31136ac495dSmrg               mem = gen_rtx_MEM (word_mode,
31236ac495dSmrg                                  gen_rtx_PLUS (Pmode,
31336ac495dSmrg                                                stack_pointer_rtx,
31436ac495dSmrg                                                offset_rtx));
31536ac495dSmrg             }
31636ac495dSmrg           else
31736ac495dSmrg             {
31836ac495dSmrg               /* r10 is caller saved so it can be used as a temp reg.  */
31936ac495dSmrg               rtx r10;
32036ac495dSmrg 
32136ac495dSmrg               r10 = gen_rtx_REG (word_mode, 10);
32236ac495dSmrg               insn = emit_move_insn (r10, offset_rtx);
32336ac495dSmrg               if (op == 0)
32436ac495dSmrg                 RTX_FRAME_RELATED_P (insn) = 1;
32536ac495dSmrg               insn = emit_add (r10, r10, stack_pointer_rtx);
32636ac495dSmrg               if (op == 0)
32736ac495dSmrg                 RTX_FRAME_RELATED_P (insn) = 1;
32836ac495dSmrg               mem = gen_rtx_MEM (word_mode, r10);
32936ac495dSmrg             }
33036ac495dSmrg 
33136ac495dSmrg 	  if (op == 0)
33236ac495dSmrg 	    insn = emit_move_insn (mem, gen_rtx_REG (word_mode, regno));
33336ac495dSmrg 	  else
33436ac495dSmrg 	    insn = emit_move_insn (gen_rtx_REG (word_mode, regno), mem);
33536ac495dSmrg 
33636ac495dSmrg 	  /* only prologue instructions which set the sp fp or save a
33736ac495dSmrg 	     register should be marked as frame related.  */
33836ac495dSmrg 	  if (op == 0)
33936ac495dSmrg 	    RTX_FRAME_RELATED_P (insn) = 1;
34036ac495dSmrg 	  offset -= UNITS_PER_WORD;
34136ac495dSmrg 	}
34236ac495dSmrg     }
34336ac495dSmrg }
34436ac495dSmrg 
34536ac495dSmrg static void
stack_adjust(HOST_WIDE_INT amount)34636ac495dSmrg stack_adjust (HOST_WIDE_INT amount)
34736ac495dSmrg {
34836ac495dSmrg   rtx insn;
34936ac495dSmrg 
35036ac495dSmrg   if (!IN_RANGE (amount, -32776, 32768))
35136ac495dSmrg     {
35236ac495dSmrg       /* r10 is caller saved so it can be used as a temp reg.  */
35336ac495dSmrg       rtx r10;
35436ac495dSmrg       r10 = gen_rtx_REG (word_mode, 10);
35536ac495dSmrg       insn = emit_move_insn (r10, GEN_INT (amount));
35636ac495dSmrg       if (amount < 0)
35736ac495dSmrg 	RTX_FRAME_RELATED_P (insn) = 1;
35836ac495dSmrg       insn = emit_add (stack_pointer_rtx, stack_pointer_rtx, r10);
35936ac495dSmrg       if (amount < 0)
36036ac495dSmrg 	RTX_FRAME_RELATED_P (insn) = 1;
36136ac495dSmrg     }
36236ac495dSmrg   else
36336ac495dSmrg     {
36436ac495dSmrg       insn = emit_add (stack_pointer_rtx,
36536ac495dSmrg 		       stack_pointer_rtx, GEN_INT (amount));
36636ac495dSmrg       if (amount < 0)
36736ac495dSmrg 	RTX_FRAME_RELATED_P (insn) = 1;
36836ac495dSmrg     }
36936ac495dSmrg }
37036ac495dSmrg 
37136ac495dSmrg 
37236ac495dSmrg /* Create and emit instructions for a functions prologue.  */
37336ac495dSmrg void
lm32_expand_prologue(void)37436ac495dSmrg lm32_expand_prologue (void)
37536ac495dSmrg {
37636ac495dSmrg   rtx insn;
37736ac495dSmrg 
37836ac495dSmrg   lm32_compute_frame_size (get_frame_size ());
37936ac495dSmrg 
38036ac495dSmrg   if (current_frame_info.total_size > 0)
38136ac495dSmrg     {
38236ac495dSmrg       /* Add space on stack new frame.  */
38336ac495dSmrg       stack_adjust (-current_frame_info.total_size);
38436ac495dSmrg 
38536ac495dSmrg       /* Save callee save registers.  */
38636ac495dSmrg       if (current_frame_info.reg_save_mask != 0)
38736ac495dSmrg 	expand_save_restore (&current_frame_info, 0);
38836ac495dSmrg 
38936ac495dSmrg       /* Setup frame pointer if it's needed.  */
39036ac495dSmrg       if (frame_pointer_needed == 1)
39136ac495dSmrg 	{
39236ac495dSmrg 	  /* Move sp to fp.  */
39336ac495dSmrg 	  insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
39436ac495dSmrg 	  RTX_FRAME_RELATED_P (insn) = 1;
39536ac495dSmrg 
39636ac495dSmrg 	  /* Add offset - Don't use total_size, as that includes pretend_size,
39736ac495dSmrg              which isn't part of this frame?  */
39836ac495dSmrg 	  insn = emit_add (frame_pointer_rtx,
39936ac495dSmrg 			   frame_pointer_rtx,
40036ac495dSmrg 			   GEN_INT (current_frame_info.args_size +
40136ac495dSmrg 				    current_frame_info.callee_size +
40236ac495dSmrg 				    current_frame_info.locals_size));
40336ac495dSmrg 	  RTX_FRAME_RELATED_P (insn) = 1;
40436ac495dSmrg 	}
40536ac495dSmrg 
40636ac495dSmrg       /* Prevent prologue from being scheduled into function body.  */
40736ac495dSmrg       emit_insn (gen_blockage ());
40836ac495dSmrg     }
40936ac495dSmrg }
41036ac495dSmrg 
41136ac495dSmrg /* Create an emit instructions for a functions epilogue.  */
41236ac495dSmrg void
lm32_expand_epilogue(void)41336ac495dSmrg lm32_expand_epilogue (void)
41436ac495dSmrg {
41536ac495dSmrg   rtx ra_rtx = gen_rtx_REG (Pmode, RA_REGNUM);
41636ac495dSmrg 
41736ac495dSmrg   lm32_compute_frame_size (get_frame_size ());
41836ac495dSmrg 
41936ac495dSmrg   if (current_frame_info.total_size > 0)
42036ac495dSmrg     {
42136ac495dSmrg       /* Prevent stack code from being reordered.  */
42236ac495dSmrg       emit_insn (gen_blockage ());
42336ac495dSmrg 
42436ac495dSmrg       /* Restore callee save registers.  */
42536ac495dSmrg       if (current_frame_info.reg_save_mask != 0)
42636ac495dSmrg 	expand_save_restore (&current_frame_info, 1);
42736ac495dSmrg 
42836ac495dSmrg       /* Deallocate stack.  */
42936ac495dSmrg       stack_adjust (current_frame_info.total_size);
43036ac495dSmrg 
43136ac495dSmrg       /* Return to calling function.  */
43236ac495dSmrg       emit_jump_insn (gen_return_internal (ra_rtx));
43336ac495dSmrg     }
43436ac495dSmrg   else
43536ac495dSmrg     {
43636ac495dSmrg       /* Return to calling function.  */
43736ac495dSmrg       emit_jump_insn (gen_return_internal (ra_rtx));
43836ac495dSmrg     }
43936ac495dSmrg }
44036ac495dSmrg 
44136ac495dSmrg /* Return the bytes needed to compute the frame pointer from the current
44236ac495dSmrg    stack pointer.  */
44336ac495dSmrg static HOST_WIDE_INT
lm32_compute_frame_size(int size)44436ac495dSmrg lm32_compute_frame_size (int size)
44536ac495dSmrg {
44636ac495dSmrg   int regno;
44736ac495dSmrg   HOST_WIDE_INT total_size, locals_size, args_size, pretend_size, callee_size;
44836ac495dSmrg   unsigned int reg_save_mask;
44936ac495dSmrg 
45036ac495dSmrg   locals_size = size;
45136ac495dSmrg   args_size = crtl->outgoing_args_size;
45236ac495dSmrg   pretend_size = crtl->args.pretend_args_size;
45336ac495dSmrg   callee_size = 0;
45436ac495dSmrg   reg_save_mask = 0;
45536ac495dSmrg 
45636ac495dSmrg   /* Build mask that actually determines which regsiters we save
45736ac495dSmrg      and calculate size required to store them in the stack.  */
45836ac495dSmrg   for (regno = 1; regno < SP_REGNUM; regno++)
45936ac495dSmrg     {
460*8feb0f0bSmrg       if (df_regs_ever_live_p (regno) && !call_used_or_fixed_reg_p (regno))
46136ac495dSmrg 	{
46236ac495dSmrg 	  reg_save_mask |= 1 << regno;
46336ac495dSmrg 	  callee_size += UNITS_PER_WORD;
46436ac495dSmrg 	}
46536ac495dSmrg     }
46636ac495dSmrg   if (df_regs_ever_live_p (RA_REGNUM) || ! crtl->is_leaf
46736ac495dSmrg       || !optimize)
46836ac495dSmrg     {
46936ac495dSmrg       reg_save_mask |= 1 << RA_REGNUM;
47036ac495dSmrg       callee_size += UNITS_PER_WORD;
47136ac495dSmrg     }
47236ac495dSmrg   if (!(reg_save_mask & (1 << FP_REGNUM)) && frame_pointer_needed)
47336ac495dSmrg     {
47436ac495dSmrg       reg_save_mask |= 1 << FP_REGNUM;
47536ac495dSmrg       callee_size += UNITS_PER_WORD;
47636ac495dSmrg     }
47736ac495dSmrg 
47836ac495dSmrg   /* Compute total frame size.  */
47936ac495dSmrg   total_size = pretend_size + args_size + locals_size + callee_size;
48036ac495dSmrg 
48136ac495dSmrg   /* Align frame to appropriate boundary.  */
48236ac495dSmrg   total_size = (total_size + 3) & ~3;
48336ac495dSmrg 
48436ac495dSmrg   /* Save computed information.  */
48536ac495dSmrg   current_frame_info.total_size = total_size;
48636ac495dSmrg   current_frame_info.callee_size = callee_size;
48736ac495dSmrg   current_frame_info.pretend_size = pretend_size;
48836ac495dSmrg   current_frame_info.locals_size = locals_size;
48936ac495dSmrg   current_frame_info.args_size = args_size;
49036ac495dSmrg   current_frame_info.reg_save_mask = reg_save_mask;
49136ac495dSmrg 
49236ac495dSmrg   return total_size;
49336ac495dSmrg }
49436ac495dSmrg 
49536ac495dSmrg void
lm32_print_operand(FILE * file,rtx op,int letter)49636ac495dSmrg lm32_print_operand (FILE * file, rtx op, int letter)
49736ac495dSmrg {
49836ac495dSmrg   enum rtx_code code;
49936ac495dSmrg 
50036ac495dSmrg   code = GET_CODE (op);
50136ac495dSmrg 
50236ac495dSmrg   if (code == SIGN_EXTEND)
50336ac495dSmrg     op = XEXP (op, 0), code = GET_CODE (op);
50436ac495dSmrg   else if (code == REG || code == SUBREG)
50536ac495dSmrg     {
50636ac495dSmrg       int regnum;
50736ac495dSmrg 
50836ac495dSmrg       if (code == REG)
50936ac495dSmrg 	regnum = REGNO (op);
51036ac495dSmrg       else
51136ac495dSmrg 	regnum = true_regnum (op);
51236ac495dSmrg 
51336ac495dSmrg       fprintf (file, "%s", reg_names[regnum]);
51436ac495dSmrg     }
51536ac495dSmrg   else if (code == HIGH)
51636ac495dSmrg     output_addr_const (file, XEXP (op, 0));
51736ac495dSmrg   else if (code == MEM)
51836ac495dSmrg     output_address (GET_MODE (op), XEXP (op, 0));
51936ac495dSmrg   else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
52036ac495dSmrg     fprintf (file, "%s", reg_names[0]);
52136ac495dSmrg   else if (GET_CODE (op) == CONST_DOUBLE)
52236ac495dSmrg     {
52336ac495dSmrg       if ((CONST_DOUBLE_LOW (op) != 0) || (CONST_DOUBLE_HIGH (op) != 0))
52436ac495dSmrg 	output_operand_lossage ("only 0.0 can be loaded as an immediate");
52536ac495dSmrg       else
52636ac495dSmrg 	fprintf (file, "0");
52736ac495dSmrg     }
52836ac495dSmrg   else if (code == EQ)
52936ac495dSmrg     fprintf (file, "e  ");
53036ac495dSmrg   else if (code == NE)
53136ac495dSmrg     fprintf (file, "ne ");
53236ac495dSmrg   else if (code == GT)
53336ac495dSmrg     fprintf (file, "g  ");
53436ac495dSmrg   else if (code == GTU)
53536ac495dSmrg     fprintf (file, "gu ");
53636ac495dSmrg   else if (code == LT)
53736ac495dSmrg     fprintf (file, "l  ");
53836ac495dSmrg   else if (code == LTU)
53936ac495dSmrg     fprintf (file, "lu ");
54036ac495dSmrg   else if (code == GE)
54136ac495dSmrg     fprintf (file, "ge ");
54236ac495dSmrg   else if (code == GEU)
54336ac495dSmrg     fprintf (file, "geu");
54436ac495dSmrg   else if (code == LE)
54536ac495dSmrg     fprintf (file, "le ");
54636ac495dSmrg   else if (code == LEU)
54736ac495dSmrg     fprintf (file, "leu");
54836ac495dSmrg   else
54936ac495dSmrg     output_addr_const (file, op);
55036ac495dSmrg }
55136ac495dSmrg 
55236ac495dSmrg /* A C compound statement to output to stdio stream STREAM the
55336ac495dSmrg    assembler syntax for an instruction operand that is a memory
55436ac495dSmrg    reference whose address is ADDR.  ADDR is an RTL expression.
55536ac495dSmrg 
55636ac495dSmrg    On some machines, the syntax for a symbolic address depends on
55736ac495dSmrg    the section that the address refers to.  On these machines,
55836ac495dSmrg    define the macro `ENCODE_SECTION_INFO' to store the information
55936ac495dSmrg    into the `symbol_ref', and then check for it here.  */
56036ac495dSmrg 
56136ac495dSmrg void
lm32_print_operand_address(FILE * file,rtx addr)56236ac495dSmrg lm32_print_operand_address (FILE * file, rtx addr)
56336ac495dSmrg {
56436ac495dSmrg   switch (GET_CODE (addr))
56536ac495dSmrg     {
56636ac495dSmrg     case REG:
56736ac495dSmrg       fprintf (file, "(%s+0)", reg_names[REGNO (addr)]);
56836ac495dSmrg       break;
56936ac495dSmrg 
57036ac495dSmrg     case MEM:
57136ac495dSmrg       output_address (VOIDmode, XEXP (addr, 0));
57236ac495dSmrg       break;
57336ac495dSmrg 
57436ac495dSmrg     case PLUS:
57536ac495dSmrg       {
57636ac495dSmrg 	rtx arg0 = XEXP (addr, 0);
57736ac495dSmrg 	rtx arg1 = XEXP (addr, 1);
57836ac495dSmrg 
57936ac495dSmrg 	if (GET_CODE (arg0) == REG && CONSTANT_P (arg1))
58036ac495dSmrg 	  {
58136ac495dSmrg 	    if (GET_CODE (arg1) == CONST_INT)
58236ac495dSmrg 	      fprintf (file, "(%s+%ld)", reg_names[REGNO (arg0)],
58336ac495dSmrg 		       INTVAL (arg1));
58436ac495dSmrg 	    else
58536ac495dSmrg 	      {
58636ac495dSmrg 		fprintf (file, "(%s+", reg_names[REGNO (arg0)]);
58736ac495dSmrg 		output_addr_const (file, arg1);
58836ac495dSmrg 		fprintf (file, ")");
58936ac495dSmrg 	      }
59036ac495dSmrg 	  }
59136ac495dSmrg 	else if (CONSTANT_P (arg0) && CONSTANT_P (arg1))
59236ac495dSmrg 	  output_addr_const (file, addr);
59336ac495dSmrg 	else
59436ac495dSmrg 	  fatal_insn ("bad operand", addr);
59536ac495dSmrg       }
59636ac495dSmrg       break;
59736ac495dSmrg 
59836ac495dSmrg     case SYMBOL_REF:
59936ac495dSmrg       if (SYMBOL_REF_SMALL_P (addr))
60036ac495dSmrg 	{
60136ac495dSmrg 	  fprintf (file, "gp(");
60236ac495dSmrg 	  output_addr_const (file, addr);
60336ac495dSmrg 	  fprintf (file, ")");
60436ac495dSmrg 	}
60536ac495dSmrg       else
60636ac495dSmrg 	fatal_insn ("can't use non gp relative absolute address", addr);
60736ac495dSmrg       break;
60836ac495dSmrg 
60936ac495dSmrg     default:
61036ac495dSmrg       fatal_insn ("invalid addressing mode", addr);
61136ac495dSmrg       break;
61236ac495dSmrg     }
61336ac495dSmrg }
61436ac495dSmrg 
61536ac495dSmrg /* Determine where to put an argument to a function.
61636ac495dSmrg    Value is zero to push the argument on the stack,
61736ac495dSmrg    or a hard register in which to store the argument.
61836ac495dSmrg 
61936ac495dSmrg    CUM is a variable of type CUMULATIVE_ARGS which gives info about
62036ac495dSmrg     the preceding args and about the function being called.
621*8feb0f0bSmrg    ARG is a description of the argument.  */
62236ac495dSmrg 
62336ac495dSmrg static rtx
lm32_function_arg(cumulative_args_t cum_v,const function_arg_info & arg)624*8feb0f0bSmrg lm32_function_arg (cumulative_args_t cum_v, const function_arg_info &arg)
62536ac495dSmrg {
62636ac495dSmrg   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
62736ac495dSmrg 
628*8feb0f0bSmrg   if (arg.end_marker_p ())
62936ac495dSmrg     /* Compute operand 2 of the call insn.  */
63036ac495dSmrg     return GEN_INT (0);
63136ac495dSmrg 
632*8feb0f0bSmrg   if (targetm.calls.must_pass_in_stack (arg))
63336ac495dSmrg     return NULL_RTX;
63436ac495dSmrg 
635*8feb0f0bSmrg   if (!arg.named
636*8feb0f0bSmrg       || *cum + LM32_NUM_REGS2 (arg.mode, arg.type) > LM32_NUM_ARG_REGS)
63736ac495dSmrg     return NULL_RTX;
63836ac495dSmrg 
639*8feb0f0bSmrg   return gen_rtx_REG (arg.mode, *cum + LM32_FIRST_ARG_REG);
64036ac495dSmrg }
64136ac495dSmrg 
64236ac495dSmrg static void
lm32_function_arg_advance(cumulative_args_t cum,const function_arg_info & arg)643*8feb0f0bSmrg lm32_function_arg_advance (cumulative_args_t cum,
644*8feb0f0bSmrg 			   const function_arg_info &arg)
64536ac495dSmrg {
646*8feb0f0bSmrg   *get_cumulative_args (cum) += LM32_NUM_REGS2 (arg.mode, arg.type);
64736ac495dSmrg }
64836ac495dSmrg 
64936ac495dSmrg HOST_WIDE_INT
lm32_compute_initial_elimination_offset(int from,int to)65036ac495dSmrg lm32_compute_initial_elimination_offset (int from, int to)
65136ac495dSmrg {
65236ac495dSmrg   HOST_WIDE_INT offset = 0;
65336ac495dSmrg 
65436ac495dSmrg   switch (from)
65536ac495dSmrg     {
65636ac495dSmrg     case ARG_POINTER_REGNUM:
65736ac495dSmrg       switch (to)
65836ac495dSmrg 	{
65936ac495dSmrg 	case FRAME_POINTER_REGNUM:
66036ac495dSmrg 	  offset = 0;
66136ac495dSmrg 	  break;
66236ac495dSmrg 	case STACK_POINTER_REGNUM:
66336ac495dSmrg 	  offset =
66436ac495dSmrg 	    lm32_compute_frame_size (get_frame_size ()) -
66536ac495dSmrg 	    current_frame_info.pretend_size;
66636ac495dSmrg 	  break;
66736ac495dSmrg 	default:
66836ac495dSmrg 	  gcc_unreachable ();
66936ac495dSmrg 	}
67036ac495dSmrg       break;
67136ac495dSmrg     default:
67236ac495dSmrg       gcc_unreachable ();
67336ac495dSmrg     }
67436ac495dSmrg 
67536ac495dSmrg   return offset;
67636ac495dSmrg }
67736ac495dSmrg 
67836ac495dSmrg static void
lm32_setup_incoming_varargs(cumulative_args_t cum_v,const function_arg_info & arg,int * pretend_size,int no_rtl)679*8feb0f0bSmrg lm32_setup_incoming_varargs (cumulative_args_t cum_v,
680*8feb0f0bSmrg 			     const function_arg_info &arg,
681*8feb0f0bSmrg 			     int *pretend_size, int no_rtl)
68236ac495dSmrg {
68336ac495dSmrg   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
68436ac495dSmrg   int first_anon_arg;
68536ac495dSmrg   tree fntype;
68636ac495dSmrg 
68736ac495dSmrg   fntype = TREE_TYPE (current_function_decl);
68836ac495dSmrg 
68936ac495dSmrg   if (stdarg_p (fntype))
69036ac495dSmrg     first_anon_arg = *cum + LM32_FIRST_ARG_REG;
69136ac495dSmrg   else
69236ac495dSmrg     {
69336ac495dSmrg       /* this is the common case, we have been passed details setup
69436ac495dSmrg 	 for the last named argument, we want to skip over the
695*8feb0f0bSmrg 	 registers, if any used in passing this named parameter in
69636ac495dSmrg 	 order to determine which is the first registers used to pass
69736ac495dSmrg 	 anonymous arguments.  */
698*8feb0f0bSmrg       int size = arg.promoted_size_in_bytes ();
69936ac495dSmrg 
70036ac495dSmrg       first_anon_arg =
70136ac495dSmrg 	*cum + LM32_FIRST_ARG_REG +
70236ac495dSmrg 	((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
70336ac495dSmrg     }
70436ac495dSmrg 
70536ac495dSmrg   if ((first_anon_arg < (LM32_FIRST_ARG_REG + LM32_NUM_ARG_REGS)) && !no_rtl)
70636ac495dSmrg     {
70736ac495dSmrg       int first_reg_offset = first_anon_arg;
70836ac495dSmrg       int size = LM32_FIRST_ARG_REG + LM32_NUM_ARG_REGS - first_anon_arg;
70936ac495dSmrg       rtx regblock;
71036ac495dSmrg 
71136ac495dSmrg       regblock = gen_rtx_MEM (BLKmode,
71236ac495dSmrg 			      plus_constant (Pmode, arg_pointer_rtx,
71336ac495dSmrg 					     FIRST_PARM_OFFSET (0)));
71436ac495dSmrg       move_block_from_reg (first_reg_offset, regblock, size);
71536ac495dSmrg 
71636ac495dSmrg       *pretend_size = size * UNITS_PER_WORD;
71736ac495dSmrg     }
71836ac495dSmrg }
71936ac495dSmrg 
72036ac495dSmrg /* Override command line options.  */
72136ac495dSmrg static void
lm32_option_override(void)72236ac495dSmrg lm32_option_override (void)
72336ac495dSmrg {
72436ac495dSmrg   /* We must have sign-extend enabled if barrel-shift isn't.  */
72536ac495dSmrg   if (!TARGET_BARREL_SHIFT_ENABLED && !TARGET_SIGN_EXTEND_ENABLED)
72636ac495dSmrg     target_flags |= MASK_SIGN_EXTEND_ENABLED;
72736ac495dSmrg }
72836ac495dSmrg 
72936ac495dSmrg /* Return nonzero if this function is known to have a null epilogue.
73036ac495dSmrg    This allows the optimizer to omit jumps to jumps if no stack
73136ac495dSmrg    was created.  */
73236ac495dSmrg int
lm32_can_use_return(void)73336ac495dSmrg lm32_can_use_return (void)
73436ac495dSmrg {
73536ac495dSmrg   if (!reload_completed)
73636ac495dSmrg     return 0;
73736ac495dSmrg 
73836ac495dSmrg   if (df_regs_ever_live_p (RA_REGNUM) || crtl->profile)
73936ac495dSmrg     return 0;
74036ac495dSmrg 
74136ac495dSmrg   if (lm32_compute_frame_size (get_frame_size ()) != 0)
74236ac495dSmrg     return 0;
74336ac495dSmrg 
74436ac495dSmrg   return 1;
74536ac495dSmrg }
74636ac495dSmrg 
74736ac495dSmrg /* Support function to determine the return address of the function
74836ac495dSmrg    'count' frames back up the stack.  */
74936ac495dSmrg rtx
lm32_return_addr_rtx(int count,rtx frame)75036ac495dSmrg lm32_return_addr_rtx (int count, rtx frame)
75136ac495dSmrg {
75236ac495dSmrg   rtx r;
75336ac495dSmrg   if (count == 0)
75436ac495dSmrg     {
75536ac495dSmrg       if (!df_regs_ever_live_p (RA_REGNUM))
75636ac495dSmrg 	r = gen_rtx_REG (Pmode, RA_REGNUM);
75736ac495dSmrg       else
75836ac495dSmrg 	{
75936ac495dSmrg 	  r = gen_rtx_MEM (Pmode,
76036ac495dSmrg 			   gen_rtx_PLUS (Pmode, frame,
76136ac495dSmrg 					 GEN_INT (-2 * UNITS_PER_WORD)));
76236ac495dSmrg 	  set_mem_alias_set (r, get_frame_alias_set ());
76336ac495dSmrg 	}
76436ac495dSmrg     }
76536ac495dSmrg   else if (flag_omit_frame_pointer)
76636ac495dSmrg     r = NULL_RTX;
76736ac495dSmrg   else
76836ac495dSmrg     {
76936ac495dSmrg       r = gen_rtx_MEM (Pmode,
77036ac495dSmrg 		       gen_rtx_PLUS (Pmode, frame,
77136ac495dSmrg 				     GEN_INT (-2 * UNITS_PER_WORD)));
77236ac495dSmrg       set_mem_alias_set (r, get_frame_alias_set ());
77336ac495dSmrg     }
77436ac495dSmrg   return r;
77536ac495dSmrg }
77636ac495dSmrg 
77736ac495dSmrg /* Return true if EXP should be placed in the small data section.  */
77836ac495dSmrg 
77936ac495dSmrg static bool
lm32_in_small_data_p(const_tree exp)78036ac495dSmrg lm32_in_small_data_p (const_tree exp)
78136ac495dSmrg {
78236ac495dSmrg   /* We want to merge strings, so we never consider them small data.  */
78336ac495dSmrg   if (TREE_CODE (exp) == STRING_CST)
78436ac495dSmrg     return false;
78536ac495dSmrg 
78636ac495dSmrg   /* Functions are never in the small data area.  Duh.  */
78736ac495dSmrg   if (TREE_CODE (exp) == FUNCTION_DECL)
78836ac495dSmrg     return false;
78936ac495dSmrg 
79036ac495dSmrg   if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
79136ac495dSmrg     {
79236ac495dSmrg       const char *section = DECL_SECTION_NAME (exp);
79336ac495dSmrg       if (strcmp (section, ".sdata") == 0 || strcmp (section, ".sbss") == 0)
79436ac495dSmrg 	return true;
79536ac495dSmrg     }
79636ac495dSmrg   else
79736ac495dSmrg     {
79836ac495dSmrg       HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
79936ac495dSmrg 
80036ac495dSmrg       /* If this is an incomplete type with size 0, then we can't put it
80136ac495dSmrg          in sdata because it might be too big when completed.  */
80236ac495dSmrg       if (size > 0 && size <= g_switch_value)
80336ac495dSmrg 	return true;
80436ac495dSmrg     }
80536ac495dSmrg 
80636ac495dSmrg   return false;
80736ac495dSmrg }
80836ac495dSmrg 
80936ac495dSmrg /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
81036ac495dSmrg    Assume that the areas do not overlap.  */
81136ac495dSmrg 
81236ac495dSmrg static void
lm32_block_move_inline(rtx dest,rtx src,HOST_WIDE_INT length,HOST_WIDE_INT alignment)81336ac495dSmrg lm32_block_move_inline (rtx dest, rtx src, HOST_WIDE_INT length,
81436ac495dSmrg 			HOST_WIDE_INT alignment)
81536ac495dSmrg {
81636ac495dSmrg   HOST_WIDE_INT offset, delta;
81736ac495dSmrg   unsigned HOST_WIDE_INT bits;
81836ac495dSmrg   int i;
81936ac495dSmrg   machine_mode mode;
82036ac495dSmrg   rtx *regs;
82136ac495dSmrg 
82236ac495dSmrg   /* Work out how many bits to move at a time.  */
82336ac495dSmrg   switch (alignment)
82436ac495dSmrg     {
82536ac495dSmrg     case 1:
82636ac495dSmrg       bits = 8;
82736ac495dSmrg       break;
82836ac495dSmrg     case 2:
82936ac495dSmrg       bits = 16;
83036ac495dSmrg       break;
83136ac495dSmrg     default:
83236ac495dSmrg       bits = 32;
83336ac495dSmrg       break;
83436ac495dSmrg     }
83536ac495dSmrg 
836a2dc1f3fSmrg   mode = int_mode_for_size (bits, 0).require ();
83736ac495dSmrg   delta = bits / BITS_PER_UNIT;
83836ac495dSmrg 
83936ac495dSmrg   /* Allocate a buffer for the temporary registers.  */
84036ac495dSmrg   regs = XALLOCAVEC (rtx, length / delta);
84136ac495dSmrg 
84236ac495dSmrg   /* Load as many BITS-sized chunks as possible.  */
84336ac495dSmrg   for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
84436ac495dSmrg     {
84536ac495dSmrg       regs[i] = gen_reg_rtx (mode);
84636ac495dSmrg       emit_move_insn (regs[i], adjust_address (src, mode, offset));
84736ac495dSmrg     }
84836ac495dSmrg 
84936ac495dSmrg   /* Copy the chunks to the destination.  */
85036ac495dSmrg   for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
85136ac495dSmrg     emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
85236ac495dSmrg 
85336ac495dSmrg   /* Mop up any left-over bytes.  */
85436ac495dSmrg   if (offset < length)
85536ac495dSmrg     {
85636ac495dSmrg       src = adjust_address (src, BLKmode, offset);
85736ac495dSmrg       dest = adjust_address (dest, BLKmode, offset);
85836ac495dSmrg       move_by_pieces (dest, src, length - offset,
859c0a68be4Smrg 		      MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), RETURN_BEGIN);
86036ac495dSmrg     }
86136ac495dSmrg }
86236ac495dSmrg 
86336ac495dSmrg /* Expand string/block move operations.
86436ac495dSmrg 
86536ac495dSmrg    operands[0] is the pointer to the destination.
86636ac495dSmrg    operands[1] is the pointer to the source.
86736ac495dSmrg    operands[2] is the number of bytes to move.
86836ac495dSmrg    operands[3] is the alignment.  */
86936ac495dSmrg 
87036ac495dSmrg int
lm32_expand_block_move(rtx * operands)87136ac495dSmrg lm32_expand_block_move (rtx * operands)
87236ac495dSmrg {
87336ac495dSmrg   if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) <= 32))
87436ac495dSmrg     {
87536ac495dSmrg       lm32_block_move_inline (operands[0], operands[1], INTVAL (operands[2]),
87636ac495dSmrg 			      INTVAL (operands[3]));
87736ac495dSmrg       return 1;
87836ac495dSmrg     }
87936ac495dSmrg   return 0;
88036ac495dSmrg }
88136ac495dSmrg 
88236ac495dSmrg /* Return TRUE if X references a SYMBOL_REF or LABEL_REF whose symbol
88336ac495dSmrg    isn't protected by a PIC unspec.  */
88436ac495dSmrg int
nonpic_symbol_mentioned_p(rtx x)88536ac495dSmrg nonpic_symbol_mentioned_p (rtx x)
88636ac495dSmrg {
88736ac495dSmrg   const char *fmt;
88836ac495dSmrg   int i;
88936ac495dSmrg 
89036ac495dSmrg   if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF
89136ac495dSmrg       || GET_CODE (x) == PC)
89236ac495dSmrg     return 1;
89336ac495dSmrg 
89436ac495dSmrg   /* We don't want to look into the possible MEM location of a
89536ac495dSmrg      CONST_DOUBLE, since we're not going to use it, in general.  */
89636ac495dSmrg   if (GET_CODE (x) == CONST_DOUBLE)
89736ac495dSmrg     return 0;
89836ac495dSmrg 
89936ac495dSmrg   if (GET_CODE (x) == UNSPEC)
90036ac495dSmrg     return 0;
90136ac495dSmrg 
90236ac495dSmrg   fmt = GET_RTX_FORMAT (GET_CODE (x));
90336ac495dSmrg   for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
90436ac495dSmrg     {
90536ac495dSmrg       if (fmt[i] == 'E')
90636ac495dSmrg 	{
90736ac495dSmrg 	  int j;
90836ac495dSmrg 
90936ac495dSmrg 	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
91036ac495dSmrg 	    if (nonpic_symbol_mentioned_p (XVECEXP (x, i, j)))
91136ac495dSmrg 	      return 1;
91236ac495dSmrg 	}
91336ac495dSmrg       else if (fmt[i] == 'e' && nonpic_symbol_mentioned_p (XEXP (x, i)))
91436ac495dSmrg 	return 1;
91536ac495dSmrg     }
91636ac495dSmrg 
91736ac495dSmrg   return 0;
91836ac495dSmrg }
91936ac495dSmrg 
92036ac495dSmrg /* Compute a (partial) cost for rtx X.  Return true if the complete
92136ac495dSmrg    cost has been computed, and false if subexpressions should be
92236ac495dSmrg    scanned.  In either case, *TOTAL contains the cost result.  */
92336ac495dSmrg 
92436ac495dSmrg static bool
lm32_rtx_costs(rtx x,machine_mode mode,int outer_code,int opno ATTRIBUTE_UNUSED,int * total,bool speed)92536ac495dSmrg lm32_rtx_costs (rtx x, machine_mode mode, int outer_code,
92636ac495dSmrg 		int opno ATTRIBUTE_UNUSED, int *total, bool speed)
92736ac495dSmrg {
92836ac495dSmrg   int code = GET_CODE (x);
92936ac495dSmrg   bool small_mode;
93036ac495dSmrg 
93136ac495dSmrg   const int arithmetic_latency = 1;
93236ac495dSmrg   const int shift_latency = 1;
93336ac495dSmrg   const int compare_latency = 2;
93436ac495dSmrg   const int multiply_latency = 3;
93536ac495dSmrg   const int load_latency = 3;
93636ac495dSmrg   const int libcall_size_cost = 5;
93736ac495dSmrg 
93836ac495dSmrg   /* Determine if we can handle the given mode size in a single instruction.  */
93936ac495dSmrg   small_mode = (mode == QImode) || (mode == HImode) || (mode == SImode);
94036ac495dSmrg 
94136ac495dSmrg   switch (code)
94236ac495dSmrg     {
94336ac495dSmrg 
94436ac495dSmrg     case PLUS:
94536ac495dSmrg     case MINUS:
94636ac495dSmrg     case AND:
94736ac495dSmrg     case IOR:
94836ac495dSmrg     case XOR:
94936ac495dSmrg     case NOT:
95036ac495dSmrg     case NEG:
95136ac495dSmrg       if (!speed)
95236ac495dSmrg 	*total = COSTS_N_INSNS (LM32_NUM_REGS (mode));
95336ac495dSmrg       else
95436ac495dSmrg 	*total =
95536ac495dSmrg 	  COSTS_N_INSNS (arithmetic_latency + (LM32_NUM_REGS (mode) - 1));
95636ac495dSmrg       break;
95736ac495dSmrg 
95836ac495dSmrg     case COMPARE:
95936ac495dSmrg       if (small_mode)
96036ac495dSmrg 	{
96136ac495dSmrg 	  if (!speed)
96236ac495dSmrg 	    *total = COSTS_N_INSNS (1);
96336ac495dSmrg 	  else
96436ac495dSmrg 	    *total = COSTS_N_INSNS (compare_latency);
96536ac495dSmrg 	}
96636ac495dSmrg       else
96736ac495dSmrg 	{
96836ac495dSmrg 	  /* FIXME. Guessing here.  */
96936ac495dSmrg 	  *total = COSTS_N_INSNS (LM32_NUM_REGS (mode) * (2 + 3) / 2);
97036ac495dSmrg 	}
97136ac495dSmrg       break;
97236ac495dSmrg 
97336ac495dSmrg     case ASHIFT:
97436ac495dSmrg     case ASHIFTRT:
97536ac495dSmrg     case LSHIFTRT:
97636ac495dSmrg       if (TARGET_BARREL_SHIFT_ENABLED && small_mode)
97736ac495dSmrg 	{
97836ac495dSmrg 	  if (!speed)
97936ac495dSmrg 	    *total = COSTS_N_INSNS (1);
98036ac495dSmrg 	  else
98136ac495dSmrg 	    *total = COSTS_N_INSNS (shift_latency);
98236ac495dSmrg 	}
98336ac495dSmrg       else if (TARGET_BARREL_SHIFT_ENABLED)
98436ac495dSmrg 	{
98536ac495dSmrg 	  /* FIXME: Guessing here.  */
98636ac495dSmrg 	  *total = COSTS_N_INSNS (LM32_NUM_REGS (mode) * 4);
98736ac495dSmrg 	}
98836ac495dSmrg       else if (small_mode && GET_CODE (XEXP (x, 1)) == CONST_INT)
98936ac495dSmrg 	{
99036ac495dSmrg 	  *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1)));
99136ac495dSmrg 	}
99236ac495dSmrg       else
99336ac495dSmrg 	{
99436ac495dSmrg 	  /* Libcall.  */
99536ac495dSmrg 	  if (!speed)
99636ac495dSmrg 	    *total = COSTS_N_INSNS (libcall_size_cost);
99736ac495dSmrg 	  else
99836ac495dSmrg 	    *total = COSTS_N_INSNS (100);
99936ac495dSmrg 	}
100036ac495dSmrg       break;
100136ac495dSmrg 
100236ac495dSmrg     case MULT:
100336ac495dSmrg       if (TARGET_MULTIPLY_ENABLED && small_mode)
100436ac495dSmrg 	{
100536ac495dSmrg 	  if (!speed)
100636ac495dSmrg 	    *total = COSTS_N_INSNS (1);
100736ac495dSmrg 	  else
100836ac495dSmrg 	    *total = COSTS_N_INSNS (multiply_latency);
100936ac495dSmrg 	}
101036ac495dSmrg       else
101136ac495dSmrg 	{
101236ac495dSmrg 	  /* Libcall.  */
101336ac495dSmrg 	  if (!speed)
101436ac495dSmrg 	    *total = COSTS_N_INSNS (libcall_size_cost);
101536ac495dSmrg 	  else
101636ac495dSmrg 	    *total = COSTS_N_INSNS (100);
101736ac495dSmrg 	}
101836ac495dSmrg       break;
101936ac495dSmrg 
102036ac495dSmrg     case DIV:
102136ac495dSmrg     case MOD:
102236ac495dSmrg     case UDIV:
102336ac495dSmrg     case UMOD:
102436ac495dSmrg       if (TARGET_DIVIDE_ENABLED && small_mode)
102536ac495dSmrg 	{
102636ac495dSmrg 	  if (!speed)
102736ac495dSmrg 	    *total = COSTS_N_INSNS (1);
102836ac495dSmrg 	  else
102936ac495dSmrg 	    {
103036ac495dSmrg 	      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
103136ac495dSmrg 		{
103236ac495dSmrg 		  int cycles = 0;
103336ac495dSmrg 		  unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
103436ac495dSmrg 
103536ac495dSmrg 		  while (i)
103636ac495dSmrg 		    {
103736ac495dSmrg 		      i >>= 2;
103836ac495dSmrg 		      cycles++;
103936ac495dSmrg 		    }
104036ac495dSmrg 		  if (IN_RANGE (i, 0, 65536))
104136ac495dSmrg 		    *total = COSTS_N_INSNS (1 + 1 + cycles);
104236ac495dSmrg 		  else
104336ac495dSmrg 		    *total = COSTS_N_INSNS (2 + 1 + cycles);
104436ac495dSmrg 		  return true;
104536ac495dSmrg 		}
104636ac495dSmrg 	      else if (GET_CODE (XEXP (x, 1)) == REG)
104736ac495dSmrg 		{
104836ac495dSmrg 		  *total = COSTS_N_INSNS (1 + GET_MODE_SIZE (mode) / 2);
104936ac495dSmrg 		  return true;
105036ac495dSmrg 		}
105136ac495dSmrg 	      else
105236ac495dSmrg 		{
105336ac495dSmrg 		  *total = COSTS_N_INSNS (1 + GET_MODE_SIZE (mode) / 2);
105436ac495dSmrg 		  return false;
105536ac495dSmrg 		}
105636ac495dSmrg 	    }
105736ac495dSmrg 	}
105836ac495dSmrg       else
105936ac495dSmrg 	{
106036ac495dSmrg 	  /* Libcall.  */
106136ac495dSmrg 	  if (!speed)
106236ac495dSmrg 	    *total = COSTS_N_INSNS (libcall_size_cost);
106336ac495dSmrg 	  else
106436ac495dSmrg 	    *total = COSTS_N_INSNS (100);
106536ac495dSmrg 	}
106636ac495dSmrg       break;
106736ac495dSmrg 
106836ac495dSmrg     case HIGH:
106936ac495dSmrg     case LO_SUM:
107036ac495dSmrg       if (!speed)
107136ac495dSmrg 	*total = COSTS_N_INSNS (1);
107236ac495dSmrg       else
107336ac495dSmrg 	*total = COSTS_N_INSNS (arithmetic_latency);
107436ac495dSmrg       break;
107536ac495dSmrg 
107636ac495dSmrg     case ZERO_EXTEND:
107736ac495dSmrg       if (MEM_P (XEXP (x, 0)))
107836ac495dSmrg 	*total = COSTS_N_INSNS (0);
107936ac495dSmrg       else if (small_mode)
108036ac495dSmrg 	{
108136ac495dSmrg 	  if (!speed)
108236ac495dSmrg 	    *total = COSTS_N_INSNS (1);
108336ac495dSmrg 	  else
108436ac495dSmrg 	    *total = COSTS_N_INSNS (arithmetic_latency);
108536ac495dSmrg 	}
108636ac495dSmrg       else
108736ac495dSmrg 	*total = COSTS_N_INSNS (LM32_NUM_REGS (mode) / 2);
108836ac495dSmrg       break;
108936ac495dSmrg 
109036ac495dSmrg     case CONST_INT:
109136ac495dSmrg       {
109236ac495dSmrg 	switch (outer_code)
109336ac495dSmrg 	  {
109436ac495dSmrg 	  case HIGH:
109536ac495dSmrg 	  case LO_SUM:
109636ac495dSmrg 	    *total = COSTS_N_INSNS (0);
109736ac495dSmrg 	    return true;
109836ac495dSmrg 
109936ac495dSmrg 	  case AND:
110036ac495dSmrg 	  case XOR:
110136ac495dSmrg 	  case IOR:
110236ac495dSmrg 	  case ASHIFT:
110336ac495dSmrg 	  case ASHIFTRT:
110436ac495dSmrg 	  case LSHIFTRT:
110536ac495dSmrg 	  case ROTATE:
110636ac495dSmrg 	  case ROTATERT:
110736ac495dSmrg 	    if (satisfies_constraint_L (x))
110836ac495dSmrg 	      *total = COSTS_N_INSNS (0);
110936ac495dSmrg 	    else
111036ac495dSmrg 	      *total = COSTS_N_INSNS (2);
111136ac495dSmrg 	    return true;
111236ac495dSmrg 
111336ac495dSmrg 	  case SET:
111436ac495dSmrg 	  case PLUS:
111536ac495dSmrg 	  case MINUS:
111636ac495dSmrg 	  case COMPARE:
111736ac495dSmrg 	    if (satisfies_constraint_K (x))
111836ac495dSmrg 	      *total = COSTS_N_INSNS (0);
111936ac495dSmrg 	    else
112036ac495dSmrg 	      *total = COSTS_N_INSNS (2);
112136ac495dSmrg 	    return true;
112236ac495dSmrg 
112336ac495dSmrg 	  case MULT:
112436ac495dSmrg 	    if (TARGET_MULTIPLY_ENABLED)
112536ac495dSmrg 	      {
112636ac495dSmrg 	        if (satisfies_constraint_K (x))
112736ac495dSmrg 	         *total = COSTS_N_INSNS (0);
112836ac495dSmrg 	        else
112936ac495dSmrg 	          *total = COSTS_N_INSNS (2);
113036ac495dSmrg 		return true;
113136ac495dSmrg 	      }
113236ac495dSmrg 	    /* Fall through.  */
113336ac495dSmrg 
113436ac495dSmrg 	  default:
113536ac495dSmrg             if (satisfies_constraint_K (x))
113636ac495dSmrg 	      *total = COSTS_N_INSNS (1);
113736ac495dSmrg 	    else
113836ac495dSmrg 	      *total = COSTS_N_INSNS (2);
113936ac495dSmrg 	    return true;
114036ac495dSmrg 	  }
114136ac495dSmrg       }
114236ac495dSmrg 
114336ac495dSmrg     case SYMBOL_REF:
114436ac495dSmrg     case CONST:
114536ac495dSmrg       switch (outer_code)
114636ac495dSmrg 	{
114736ac495dSmrg 	case HIGH:
114836ac495dSmrg 	case LO_SUM:
114936ac495dSmrg 	  *total = COSTS_N_INSNS (0);
115036ac495dSmrg 	  return true;
115136ac495dSmrg 
115236ac495dSmrg 	case MEM:
115336ac495dSmrg 	case SET:
115436ac495dSmrg 	  if (g_switch_value)
115536ac495dSmrg 	    {
115636ac495dSmrg 	      *total = COSTS_N_INSNS (0);
115736ac495dSmrg 	      return true;
115836ac495dSmrg 	    }
115936ac495dSmrg 	  break;
116036ac495dSmrg 	}
116136ac495dSmrg       /* Fall through.  */
116236ac495dSmrg 
116336ac495dSmrg     case LABEL_REF:
116436ac495dSmrg     case CONST_DOUBLE:
116536ac495dSmrg       *total = COSTS_N_INSNS (2);
116636ac495dSmrg       return true;
116736ac495dSmrg 
116836ac495dSmrg     case SET:
116936ac495dSmrg       *total = COSTS_N_INSNS (1);
117036ac495dSmrg       break;
117136ac495dSmrg 
117236ac495dSmrg     case MEM:
117336ac495dSmrg       if (!speed)
117436ac495dSmrg 	*total = COSTS_N_INSNS (1);
117536ac495dSmrg       else
117636ac495dSmrg 	*total = COSTS_N_INSNS (load_latency);
117736ac495dSmrg       break;
117836ac495dSmrg 
117936ac495dSmrg     }
118036ac495dSmrg 
118136ac495dSmrg   return false;
118236ac495dSmrg }
118336ac495dSmrg 
118436ac495dSmrg /* Implemenent TARGET_CAN_ELIMINATE.  */
118536ac495dSmrg 
118636ac495dSmrg bool
lm32_can_eliminate(const int from ATTRIBUTE_UNUSED,const int to)118736ac495dSmrg lm32_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
118836ac495dSmrg {
118936ac495dSmrg   return (to == STACK_POINTER_REGNUM && frame_pointer_needed) ? false : true;
119036ac495dSmrg }
119136ac495dSmrg 
119236ac495dSmrg /* Implement TARGET_LEGITIMATE_ADDRESS_P.  */
119336ac495dSmrg 
119436ac495dSmrg static bool
lm32_legitimate_address_p(machine_mode mode ATTRIBUTE_UNUSED,rtx x,bool strict)119536ac495dSmrg lm32_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x, bool strict)
119636ac495dSmrg {
119736ac495dSmrg    /* (rM) */
119836ac495dSmrg   if (strict && REG_P (x) && STRICT_REG_OK_FOR_BASE_P (x))
119936ac495dSmrg     return true;
120036ac495dSmrg   if (!strict && REG_P (x) && NONSTRICT_REG_OK_FOR_BASE_P (x))
120136ac495dSmrg     return true;
120236ac495dSmrg 
120336ac495dSmrg   /* (rM)+literal) */
120436ac495dSmrg   if (GET_CODE (x) == PLUS
120536ac495dSmrg      && REG_P (XEXP (x, 0))
120636ac495dSmrg      && ((strict && STRICT_REG_OK_FOR_BASE_P (XEXP (x, 0)))
120736ac495dSmrg          || (!strict && NONSTRICT_REG_OK_FOR_BASE_P (XEXP (x, 0))))
120836ac495dSmrg      && GET_CODE (XEXP (x, 1)) == CONST_INT
120936ac495dSmrg      && satisfies_constraint_K (XEXP ((x), 1)))
121036ac495dSmrg     return true;
121136ac495dSmrg 
121236ac495dSmrg   /* gp(sym)  */
121336ac495dSmrg   if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_SMALL_P (x))
121436ac495dSmrg     return true;
121536ac495dSmrg 
121636ac495dSmrg   return false;
121736ac495dSmrg }
121836ac495dSmrg 
121936ac495dSmrg /* Check a move is not memory to memory.  */
122036ac495dSmrg 
122136ac495dSmrg bool
lm32_move_ok(machine_mode mode,rtx operands[2])122236ac495dSmrg lm32_move_ok (machine_mode mode, rtx operands[2]) {
122336ac495dSmrg   if (memory_operand (operands[0], mode))
122436ac495dSmrg     return register_or_zero_operand (operands[1], mode);
122536ac495dSmrg   return true;
122636ac495dSmrg }
1227a2dc1f3fSmrg 
1228a2dc1f3fSmrg /* Implement TARGET_HARD_REGNO_MODE_OK.  */
1229a2dc1f3fSmrg 
1230a2dc1f3fSmrg static bool
lm32_hard_regno_mode_ok(unsigned int regno,machine_mode)1231a2dc1f3fSmrg lm32_hard_regno_mode_ok (unsigned int regno, machine_mode)
1232a2dc1f3fSmrg {
1233a2dc1f3fSmrg   return G_REG_P (regno);
1234a2dc1f3fSmrg }
1235a2dc1f3fSmrg 
1236a2dc1f3fSmrg /* Implement TARGET_MODES_TIEABLE_P.  */
1237a2dc1f3fSmrg 
1238a2dc1f3fSmrg static bool
lm32_modes_tieable_p(machine_mode mode1,machine_mode mode2)1239a2dc1f3fSmrg lm32_modes_tieable_p (machine_mode mode1, machine_mode mode2)
1240a2dc1f3fSmrg {
1241a2dc1f3fSmrg   return (GET_MODE_CLASS (mode1) == MODE_INT
1242a2dc1f3fSmrg 	  && GET_MODE_CLASS (mode2) == MODE_INT
1243a2dc1f3fSmrg 	  && GET_MODE_SIZE (mode1) <= UNITS_PER_WORD
1244a2dc1f3fSmrg 	  && GET_MODE_SIZE (mode2) <= UNITS_PER_WORD);
1245a2dc1f3fSmrg }
1246a2dc1f3fSmrg 
1247a2dc1f3fSmrg /* Implement TARGET_STARTING_FRAME_OFFSET.  */
1248a2dc1f3fSmrg 
1249a2dc1f3fSmrg static HOST_WIDE_INT
lm32_starting_frame_offset(void)1250a2dc1f3fSmrg lm32_starting_frame_offset (void)
1251a2dc1f3fSmrg {
1252a2dc1f3fSmrg   return UNITS_PER_WORD;
1253a2dc1f3fSmrg }
1254