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 (¤t_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 (¤t_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