Line 3... |
Line 3... |
2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc
|
2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc
|
Copyright (C) 2010 Embecosm Limited
|
Copyright (C) 2010 Embecosm Limited
|
|
|
Contributed by Damjan Lampret <damjanl@bsemi.com> in 1999.
|
Contributed by Damjan Lampret <damjanl@bsemi.com> in 1999.
|
Major optimizations by Matjaz Breskvar <matjazb@bsemi.com> in 2005.
|
Major optimizations by Matjaz Breskvar <matjazb@bsemi.com> in 2005.
|
Updated for GCC 4.5 by Jeremy Bennett <jeremy.bennett@embecoms.com> in 2010
|
Updated for GCC 4.5 by Jeremy Bennett <jeremy.bennett@embecoms.com>
|
|
and Joern Rennecke <joern.rennecke@embecosm.com> in 2010.
|
|
|
This file is part of GNU CC.
|
This file is part of GNU CC.
|
|
|
This program is free software; you can redistribute it and/or modify it
|
This program is free software; you can redistribute it and/or modify it
|
under the terms of the GNU General Public License as published by the Free
|
under the terms of the GNU General Public License as published by the Free
|
Line 99... |
Line 100... |
|
|
|
|
/* ========================================================================== */
|
/* ========================================================================== */
|
/* Local (i.e. static) utility functions */
|
/* Local (i.e. static) utility functions */
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
/*!Must the current function save a register?
|
/*!Must the current function save a register?
|
|
|
@param[in] regno The register to consider.
|
@param[in] regno The register to consider.
|
|
|
Line 121... |
Line 121... |
if (df_regs_ever_live_p(regno) && !call_used_regs[regno])
|
if (df_regs_ever_live_p(regno) && !call_used_regs[regno])
|
return true;
|
return true;
|
|
|
/* We need to save the old frame pointer before setting up a new
|
/* We need to save the old frame pointer before setting up a new
|
one. */
|
one. */
|
if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)
|
if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
|
return true;
|
return true;
|
|
|
/* We need to save the incoming return address if it is ever clobbered
|
/* We need to save the incoming return address if it is ever clobbered
|
within the function. */
|
within the function. */
|
if (regno == LINK_REGNUM && df_regs_ever_live_p(regno))
|
if (regno == LINK_REGNUM && df_regs_ever_live_p(regno))
|
Line 133... |
Line 133... |
|
|
return false;
|
return false;
|
|
|
} /* or32_save_reg_p () */
|
} /* or32_save_reg_p () */
|
|
|
|
bool
|
|
or32_save_reg_p_cached (int regno)
|
|
{
|
|
return (frame_info.mask & ((HOST_WIDE_INT) 1 << regno)) != 0;
|
|
}
|
|
|
|
/* N.B. contrary to the ISA documentation, the stack includes the outgoing
|
|
arguments. */
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
/*!Compute full frame size and layout.
|
/*!Compute full frame size and layout.
|
|
|
Store information in "frame_info".
|
Store information in "frame_info".
|
|
|
Line 148... |
Line 156... |
or32_compute_frame_size (HOST_WIDE_INT size)
|
or32_compute_frame_size (HOST_WIDE_INT size)
|
{
|
{
|
HOST_WIDE_INT args_size;
|
HOST_WIDE_INT args_size;
|
HOST_WIDE_INT vars_size;
|
HOST_WIDE_INT vars_size;
|
HOST_WIDE_INT stack_offset;
|
HOST_WIDE_INT stack_offset;
|
|
bool interrupt_p = false;
|
|
|
int regno;
|
int regno;
|
|
|
args_size = crtl->outgoing_args_size;
|
args_size = crtl->outgoing_args_size;
|
vars_size = OR32_ALIGN (size, 4);
|
vars_size = OR32_ALIGN (size, 4);
|
Line 163... |
Line 172... |
allocating it anyway. Otherwise reclaim it here. */
|
allocating it anyway. Otherwise reclaim it here. */
|
/* FIXME: Verify this. Got if from the MIPS port. */
|
/* FIXME: Verify this. Got if from the MIPS port. */
|
if (vars_size == 0 && current_function_is_leaf)
|
if (vars_size == 0 && current_function_is_leaf)
|
args_size = 0;
|
args_size = 0;
|
|
|
stack_offset = args_size;
|
stack_offset = 0;
|
|
|
/* Save link register right after possible outgoing arguments. */
|
/* Save link register right at the bottom. */
|
if (or32_save_reg_p (LINK_REGNUM))
|
if (or32_save_reg_p (LINK_REGNUM))
|
{
|
{
|
|
stack_offset = stack_offset - UNITS_PER_WORD;
|
frame_info.lr_save_offset = stack_offset;
|
frame_info.lr_save_offset = stack_offset;
|
frame_info.save_lr_p = true;
|
frame_info.save_lr_p = true;
|
stack_offset = stack_offset + UNITS_PER_WORD;
|
|
}
|
}
|
else
|
else
|
frame_info.save_lr_p = false;
|
frame_info.save_lr_p = false;
|
|
|
/* Save frame pointer right after possible link register. */
|
/* Save frame pointer right after possible link register. */
|
if (or32_save_reg_p (FRAME_POINTER_REGNUM))
|
if (frame_pointer_needed)
|
{
|
{
|
|
stack_offset = stack_offset - UNITS_PER_WORD;
|
frame_info.fp_save_offset = stack_offset;
|
frame_info.fp_save_offset = stack_offset;
|
frame_info.save_fp_p = true;
|
frame_info.save_fp_p = true;
|
stack_offset = stack_offset + UNITS_PER_WORD;
|
|
}
|
}
|
else
|
else
|
frame_info.save_fp_p = false;
|
frame_info.save_fp_p = false;
|
|
|
frame_info.gpr_size = 0;
|
frame_info.gpr_size = 0;
|
frame_info.mask = 0;
|
frame_info.mask = 0;
|
frame_info.gpr_offset = stack_offset;
|
|
|
|
for (regno = 0; regno <= OR32_LAST_INT_REG; regno++)
|
for (regno = 0; regno <= OR32_LAST_ACTUAL_REG; regno++)
|
{
|
{
|
if (regno == LINK_REGNUM || regno == FRAME_POINTER_REGNUM)
|
if (regno == LINK_REGNUM
|
|
|| (frame_pointer_needed && regno == HARD_FRAME_POINTER_REGNUM))
|
/* These have already been saved if so needed. */
|
/* These have already been saved if so needed. */
|
continue;
|
continue;
|
|
|
if (or32_save_reg_p (regno))
|
if (or32_save_reg_p (regno))
|
{
|
{
|
frame_info.gpr_size += UNITS_PER_WORD;
|
frame_info.gpr_size += UNITS_PER_WORD;
|
frame_info.mask |= (1 << regno);
|
frame_info.mask |= ((HOST_WIDE_INT) 1 << regno);
|
}
|
}
|
}
|
}
|
|
|
frame_info.total_size = ((frame_info.save_fp_p ? UNITS_PER_WORD : 0)
|
frame_info.total_size = ((frame_info.save_fp_p ? UNITS_PER_WORD : 0)
|
+ (frame_info.save_lr_p ? UNITS_PER_WORD : 0)
|
+ (frame_info.save_lr_p ? UNITS_PER_WORD : 0)
|
+ args_size + frame_info.gpr_size + vars_size);
|
+ args_size + frame_info.gpr_size + vars_size);
|
|
gcc_assert (PROLOGUE_TMP != STATIC_CHAIN_REGNUM);
|
|
if (frame_info.total_size > 32767 && interrupt_p)
|
|
{
|
|
int n_extra
|
|
= (!!(~frame_info.mask && 1 << PROLOGUE_TMP)
|
|
+ !!(~frame_info.mask & 1 << EPILOGUE_TMP)) * UNITS_PER_WORD;
|
|
|
|
frame_info.gpr_size += n_extra;
|
|
frame_info.total_size += n_extra;
|
|
frame_info.mask |= (1 << PROLOGUE_TMP) | (1 << EPILOGUE_TMP);
|
|
}
|
|
|
|
stack_offset -= frame_info.gpr_size;
|
|
frame_info.gpr_offset = stack_offset;
|
|
|
return frame_info.total_size;
|
return frame_info.total_size;
|
|
|
} /* or32_compute_frame_size () */
|
} /* or32_compute_frame_size () */
|
|
|
Line 233... |
Line 256... |
|
|
} /* emit_frame_insn () */
|
} /* emit_frame_insn () */
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
/*!Generate the RTX for an indexed memory access
|
/* Generate a RTX for the indexed memory address based on stack_pointer_rtx
|
|
and a displacement
|
Generate a RTX for the indexed memory address based on a base address and a
|
|
displacement
|
|
|
|
@param[in] base The base address RTX
|
|
@param[in] disp The displacement
|
@param[in] disp The displacement
|
|
|
@return The RTX for the generated address. */
|
@return The RTX for the generated address. */
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
static rtx
|
static rtx
|
indexed_memory (rtx base,
|
stack_disp_mem (HOST_WIDE_INT disp)
|
HOST_WIDE_INT disp)
|
|
{
|
{
|
return gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, base, GEN_INT (disp)));
|
return gen_frame_mem (Pmode, plus_constant (stack_pointer_rtx, disp));
|
|
}
|
} /* indexed_memory () */
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
/*!Generate insn patterns to do an integer compare of operands.
|
/*!Generate insn patterns to do an integer compare of operands.
|
|
|
Line 489... |
Line 507... |
@param[in] dest Destination of the move.
|
@param[in] dest Destination of the move.
|
@param[in] src Source for the move.
|
@param[in] src Source for the move.
|
|
|
@return RTX for the move. */
|
@return RTX for the move. */
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
rtx
|
static rtx
|
or32_emit_move (rtx dest, rtx src)
|
or32_emit_move (rtx dest, rtx src)
|
{
|
{
|
return (can_create_pseudo_p ()
|
return (can_create_pseudo_p ()
|
? emit_move_insn (dest, src)
|
? emit_move_insn (dest, src)
|
: emit_move_insn_1 (dest, src));
|
: emit_move_insn_1 (dest, src));
|
Line 594... |
Line 612... |
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
void
|
void
|
or32_expand_prologue (void)
|
or32_expand_prologue (void)
|
{
|
{
|
int total_size = or32_compute_frame_size (get_frame_size ());
|
int total_size = or32_compute_frame_size (get_frame_size ());
|
rtx sp_rtx;
|
rtx insn;
|
rtx value_rtx;
|
|
|
|
if (!total_size)
|
if (!total_size)
|
/* No frame needed. */
|
/* No frame needed. */
|
return;
|
return;
|
|
|
sp_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
|
|
|
|
if (total_size > 32767)
|
|
{
|
|
value_rtx = gen_rtx_REG (Pmode, GP_ARG_RETURN);
|
|
emit_frame_insn (gen_rtx_SET (Pmode, value_rtx, GEN_INT (total_size)));
|
|
}
|
|
else
|
|
value_rtx = GEN_INT (total_size);
|
|
|
|
/* Update the stack pointer to reflect frame size. */
|
|
emit_frame_insn
|
|
(gen_rtx_SET (Pmode, stack_pointer_rtx,
|
|
gen_rtx_MINUS (Pmode, stack_pointer_rtx, value_rtx)));
|
|
|
|
if (frame_info.save_fp_p)
|
if (frame_info.save_fp_p)
|
{
|
{
|
emit_frame_insn
|
emit_frame_insn (gen_rtx_SET (Pmode,
|
(gen_rtx_SET (Pmode,
|
stack_disp_mem (frame_info.fp_save_offset),
|
indexed_memory (stack_pointer_rtx,
|
hard_frame_pointer_rtx));
|
frame_info.fp_save_offset),
|
|
frame_pointer_rtx));
|
|
|
|
emit_frame_insn
|
emit_frame_insn
|
(gen_rtx_SET (Pmode, frame_pointer_rtx,
|
(gen_add3_insn (hard_frame_pointer_rtx, stack_pointer_rtx, const0_rtx));
|
gen_rtx_PLUS (Pmode, frame_pointer_rtx, value_rtx)));
|
|
}
|
}
|
if (frame_info.save_lr_p)
|
if (frame_info.save_lr_p)
|
{
|
{
|
|
|
emit_frame_insn
|
emit_frame_insn
|
(gen_rtx_SET (Pmode,
|
(gen_rtx_SET (Pmode, stack_disp_mem (frame_info.lr_save_offset),
|
indexed_memory (stack_pointer_rtx,
|
|
frame_info.lr_save_offset),
|
|
gen_rtx_REG (Pmode, LINK_REGNUM)));
|
gen_rtx_REG (Pmode, LINK_REGNUM)));
|
}
|
}
|
if (frame_info.gpr_size)
|
if (frame_info.gpr_size)
|
{
|
{
|
int offset = 0;
|
int offset = 0;
|
int regno;
|
int regno;
|
|
|
for (regno = 0; regno <= OR32_LAST_INT_REG; regno++)
|
for (regno = 0; regno <= OR32_LAST_ACTUAL_REG; regno++)
|
{
|
{
|
HOST_WIDE_INT disp = frame_info.gpr_offset + offset;
|
if (!(frame_info.mask & ((HOST_WIDE_INT) 1 << regno)))
|
|
|
if (!(frame_info.mask & (1 << regno)))
|
|
continue;
|
continue;
|
|
|
emit_frame_insn
|
emit_frame_insn
|
(gen_rtx_SET (Pmode,
|
(gen_rtx_SET (Pmode,
|
indexed_memory (stack_pointer_rtx, disp),
|
stack_disp_mem (frame_info.gpr_offset + offset),
|
gen_rtx_REG (Pmode, regno)));
|
gen_rtx_REG (Pmode, regno)));
|
offset = offset + UNITS_PER_WORD;
|
offset = offset + UNITS_PER_WORD;
|
}
|
}
|
}
|
}
|
|
|
|
/* Update the stack pointer to reflect frame size. */
|
|
insn = gen_add2_insn (stack_pointer_rtx, GEN_INT (-total_size));
|
|
if (total_size > 32767)
|
|
{
|
|
rtx note = insn;
|
|
rtx value_rtx = gen_rtx_REG (Pmode, PROLOGUE_TMP);
|
|
|
|
or32_emit_set_const32 (value_rtx, GEN_INT (-total_size));
|
|
insn = emit_frame_insn (gen_add2_insn (stack_pointer_rtx, value_rtx));
|
|
add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
|
|
}
|
|
else
|
|
emit_frame_insn (insn);
|
|
|
} /* or32_expand_prologue () */
|
} /* or32_expand_prologue () */
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
/*!Expand an epilogue pattern.
|
/*!Expand an epilogue pattern.
|
Line 672... |
Line 682... |
first insn to prevent such scheduling.
|
first insn to prevent such scheduling.
|
|
|
For the OR32 this is currently controlled by the -mlogue option. It should
|
For the OR32 this is currently controlled by the -mlogue option. It should
|
be the default, once it is proved to work.
|
be the default, once it is proved to work.
|
|
|
@param[in] sibcall Non-zero (TRUE) if this is a sibcall return, which can
|
@param[in] sibcall The sibcall epilogue insn if this is a sibcall return,
|
benefit from tail call optimization. Zero (FALSE)
|
NULL_RTX otherwise. */
|
otherwise. */
|
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
void
|
void
|
or32_expand_epilogue (int sibcall)
|
or32_expand_epilogue (rtx sibcall)
|
{
|
{
|
int total_size = or32_compute_frame_size (get_frame_size ());
|
int total_size = or32_compute_frame_size (get_frame_size ());
|
|
int sibcall_regno = FIRST_PSEUDO_REGISTER;
|
|
|
|
if (sibcall)
|
|
{
|
|
sibcall = next_nonnote_insn (sibcall);
|
|
gcc_assert (CALL_P (sibcall) && SIBLING_CALL_P (sibcall));
|
|
sibcall = XVECEXP (PATTERN (sibcall), 0, 0);
|
|
if (GET_CODE (sibcall) == SET)
|
|
sibcall = SET_SRC (sibcall);
|
|
gcc_assert (GET_CODE (sibcall) == CALL);
|
|
sibcall = XEXP (sibcall, 0);
|
|
gcc_assert (MEM_P (sibcall));
|
|
sibcall = XEXP (sibcall, 0);
|
|
if (REG_P (sibcall))
|
|
sibcall_regno = REGNO (sibcall);
|
|
else
|
|
gcc_assert (CONSTANT_P (sibcall));
|
|
}
|
|
if (frame_info.save_fp_p)
|
|
{
|
|
emit_insn
|
|
(gen_add3_insn (stack_pointer_rtx, hard_frame_pointer_rtx, const0_rtx));
|
|
emit_insn
|
|
(gen_rtx_SET (Pmode, hard_frame_pointer_rtx,
|
|
stack_disp_mem (frame_info.fp_save_offset)));
|
|
}
|
|
else
|
|
{
|
rtx value_rtx;
|
rtx value_rtx;
|
|
|
if (total_size > 32767)
|
if (total_size > 32767)
|
{
|
{
|
value_rtx = gen_rtx_REG (Pmode, 3);
|
value_rtx = gen_rtx_REG (Pmode, EPILOGUE_TMP);
|
|
or32_emit_set_const32 (value_rtx, GEN_INT (total_size));
|
emit_insn (gen_rtx_SET (Pmode, value_rtx, GEN_INT (total_size)));
|
|
}
|
}
|
else
|
else
|
value_rtx = GEN_INT (total_size);
|
value_rtx = GEN_INT (total_size);
|
|
if (total_size)
|
|
emit_insn (gen_add2_insn (stack_pointer_rtx, value_rtx));
|
|
}
|
|
|
if (frame_info.save_lr_p)
|
if (frame_info.save_lr_p)
|
{
|
{
|
emit_insn
|
emit_insn
|
(gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, LINK_REGNUM),
|
(gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, LINK_REGNUM),
|
indexed_memory (stack_pointer_rtx,
|
stack_disp_mem (frame_info.lr_save_offset)));
|
frame_info.lr_save_offset)));
|
|
}
|
|
if (frame_info.save_fp_p)
|
|
{
|
|
emit_insn
|
|
(gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),
|
|
indexed_memory (stack_pointer_rtx,
|
|
frame_info.fp_save_offset)));
|
|
}
|
}
|
|
|
if (frame_info.gpr_size)
|
if (frame_info.gpr_size)
|
{
|
{
|
int offset = 0;
|
int offset = 0;
|
int regno;
|
int regno;
|
|
|
for (regno = 0; regno <= OR32_LAST_INT_REG; regno++)
|
for (regno = 0; regno <= OR32_LAST_ACTUAL_REG; regno++)
|
{
|
{
|
HOST_WIDE_INT disp = frame_info.gpr_offset + offset;
|
if (!(frame_info.mask & ((HOST_WIDE_INT) 1 << regno)))
|
|
|
if (!(frame_info.mask & (1 << regno)))
|
|
continue;
|
continue;
|
|
|
|
if (regno != sibcall_regno)
|
emit_insn
|
emit_insn
|
(gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, regno),
|
(gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, regno),
|
indexed_memory (stack_pointer_rtx, disp)));
|
stack_disp_mem (frame_info.gpr_offset + offset)));
|
offset = offset + UNITS_PER_WORD;
|
offset = offset + UNITS_PER_WORD;
|
}
|
}
|
}
|
}
|
|
|
if (total_size)
|
|
{
|
|
emit_insn (gen_rtx_SET (Pmode, stack_pointer_rtx,
|
|
gen_rtx_PLUS (Pmode,
|
|
stack_pointer_rtx, value_rtx)));
|
|
}
|
|
|
|
if (!sibcall)
|
if (!sibcall)
|
emit_jump_insn (gen_return_internal (gen_rtx_REG( Pmode, 9)));
|
emit_jump_insn (gen_return_internal (gen_rtx_REG( Pmode, 9)));
|
|
|
} /* or32_expand_epilogue () */
|
} /* or32_expand_epilogue () */
|
|
|
|
/* We are outputting a jump which needs JUMP_ADDRESS, which is the
|
|
register it uses as jump destination, restored,
|
|
e.g. a sibcall using a callee-saved register.
|
|
Emit the register restore as delay slot insn. */
|
|
void
|
|
or32_print_jump_restore (rtx jump_address)
|
|
{
|
|
int regno, jump_regno;
|
|
HOST_WIDE_INT offset = frame_info.gpr_offset;
|
|
|
|
gcc_assert (REG_P (jump_address));
|
|
jump_regno = REGNO (jump_address);
|
|
for (regno = 0; regno != jump_regno; regno++)
|
|
{
|
|
gcc_assert (regno <= OR32_LAST_ACTUAL_REG);
|
|
if (!(frame_info.mask & ((HOST_WIDE_INT) 1 << regno)))
|
|
continue;
|
|
offset = offset + UNITS_PER_WORD;
|
|
}
|
|
asm_fprintf (asm_out_file, "\n\tl.lwz\tr%d,"HOST_WIDE_INT_PRINT_DEC"(r1)\n",
|
|
jump_regno, offset);
|
|
}
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
/*!Generate assembler code for a movdi/movdf pattern
|
/*!Generate assembler code for a movdi/movdf pattern
|
|
|
@param[in] operands Operands to the movdx pattern.
|
@param[in] operands Operands to the movdx pattern.
|
Line 981... |
Line 1027... |
|
|
code = GET_CODE (operands[1]);
|
code = GET_CODE (operands[1]);
|
mode_calc = SELECT_CC_MODE (code, or32_compare_op0, or32_compare_op1);
|
mode_calc = SELECT_CC_MODE (code, or32_compare_op0, or32_compare_op1);
|
mode_got = GET_MODE (operands[2]);
|
mode_got = GET_MODE (operands[2]);
|
|
|
if (!TARGET_MASK_ALIGNED_JUMPS)
|
|
{
|
|
if (mode_calc != mode_got)
|
if (mode_calc != mode_got)
|
return "l.bnf\t%l0%(";
|
return "l.bnf\t%l0%(";
|
else
|
else
|
return "l.bf\t%l0%(";
|
return "l.bf\t%l0%(";
|
}
|
|
else
|
|
{
|
|
if (mode_calc != mode_got)
|
|
return ".balignl\t0x8,0x15000015,0x4\n\tl.bnf\t%l0%(";
|
|
else
|
|
return ".balignl 0x8,0x15000015,0x4;\n\tl.bf\t%l0%(";
|
|
}
|
|
} /* or32_output_bf () */
|
} /* or32_output_bf () */
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
/*!Output the assembler for a conditional move instruction.
|
/*!Output the assembler for a conditional move instruction.
|
Line 1174... |
Line 1210... |
/* If we are doing the prologue using the "prologue" pattern in the machine
|
/* If we are doing the prologue using the "prologue" pattern in the machine
|
description, do nothing more here.
|
description, do nothing more here.
|
|
|
JPB 30-Aug-10: Surely that is not correct. If this option is set, we
|
JPB 30-Aug-10: Surely that is not correct. If this option is set, we
|
should never even be called! */
|
should never even be called! */
|
if (TARGET_MASK_SCHED_LOGUE)
|
if (TARGET_SCHED_LOGUE)
|
return;
|
return;
|
|
|
if (size < 0)
|
if (size < 0)
|
abort ();
|
abort ();
|
|
|
Line 1225... |
Line 1261... |
{
|
{
|
char *l = dwarf2out_cfi_label (false);
|
char *l = dwarf2out_cfi_label (false);
|
int offset = OR32_ALIGN (crtl->outgoing_args_size, 4) + lr_save_area;
|
int offset = OR32_ALIGN (crtl->outgoing_args_size, 4) + lr_save_area;
|
|
|
fprintf (file, "\tl.sw\t%d(r%d),r%d\n", offset,
|
fprintf (file, "\tl.sw\t%d(r%d),r%d\n", offset,
|
STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM);
|
STACK_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM);
|
|
|
if (stack_size >= 0x8000)
|
if (stack_size >= 0x8000)
|
fprintf (file, "\tl.add\tr%d,r%d,r%d\n", FRAME_POINTER_REGNUM,
|
fprintf (file, "\tl.add\tr%d,r%d,r%d\n", HARD_FRAME_POINTER_REGNUM,
|
STACK_POINTER_REGNUM, GP_ARG_RETURN);
|
STACK_POINTER_REGNUM, GP_ARG_RETURN);
|
else
|
else
|
fprintf (file, "\tl.addi\tr%d,r%d,%d\n", FRAME_POINTER_REGNUM,
|
fprintf (file, "\tl.addi\tr%d,r%d,%d\n", HARD_FRAME_POINTER_REGNUM,
|
STACK_POINTER_REGNUM, stack_size);
|
STACK_POINTER_REGNUM, stack_size);
|
|
|
/* The CFA is already pointing at the start of our frame (i.e. the new
|
/* The CFA is already pointing at the start of our frame (i.e. the new
|
FP). The old FP has been saved relative to the SP, so we need to use
|
FP). The old FP has been saved relative to the SP, so we need to use
|
stack_size to work out where. */
|
stack_size to work out where. */
|
dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, offset - stack_size);
|
dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM, offset - stack_size);
|
}
|
}
|
|
|
/* Save the return address if necessary */
|
/* Save the return address if necessary */
|
if (lr_save_area)
|
if (lr_save_area)
|
{
|
{
|
Line 1252... |
Line 1288... |
LINK_REGNUM);
|
LINK_REGNUM);
|
|
|
/* The CFA is already pointing at the start of our frame (i.e. the new
|
/* The CFA is already pointing at the start of our frame (i.e. the new
|
FP). The LR has been saved relative to the SP, so we need to use
|
FP). The LR has been saved relative to the SP, so we need to use
|
stack_size to work out where. */
|
stack_size to work out where. */
|
dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, offset - stack_size);
|
dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM, offset - stack_size);
|
}
|
}
|
|
|
save_area = (OR32_ALIGN (crtl->outgoing_args_size, 4)
|
save_area = (OR32_ALIGN (crtl->outgoing_args_size, 4)
|
+ lr_save_area + fp_save_area);
|
+ lr_save_area + fp_save_area);
|
|
|
Line 1271... |
Line 1307... |
STACK_POINTER_REGNUM, regno);
|
STACK_POINTER_REGNUM, regno);
|
|
|
/* The CFA is already pointing at the start of our frame (i.e. the
|
/* The CFA is already pointing at the start of our frame (i.e. the
|
new FP). The register has been saved relative to the SP, so we
|
new FP). The register has been saved relative to the SP, so we
|
need to use stack_size to work out where. */
|
need to use stack_size to work out where. */
|
dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, save_area - stack_size);
|
dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM,
|
|
save_area - stack_size);
|
save_area += 4;
|
save_area += 4;
|
}
|
}
|
}
|
}
|
} /* or32_output_function_prologue () */
|
} /* or32_output_function_prologue () */
|
|
|
Line 1343... |
Line 1380... |
/* If we are doing the epilogue using the "epilogue" pattern in the machine
|
/* If we are doing the epilogue using the "epilogue" pattern in the machine
|
description, do nothing more here.
|
description, do nothing more here.
|
|
|
JPB 30-Aug-10: Surely that is not correct. If this option is set, we
|
JPB 30-Aug-10: Surely that is not correct. If this option is set, we
|
should never even be called! */
|
should never even be called! */
|
if (TARGET_MASK_SCHED_LOGUE)
|
if (TARGET_SCHED_LOGUE)
|
return;
|
return;
|
|
|
/* Work out the frame size */
|
/* Work out the frame size */
|
stack_size = calculate_stack_size (size, &lr_save_area, &fp_save_area,
|
stack_size = calculate_stack_size (size, &lr_save_area, &fp_save_area,
|
&gpr_save_area, &save_area);
|
&gpr_save_area, &save_area);
|
Line 1361... |
Line 1398... |
}
|
}
|
|
|
/* Restore the frame pointer if necessary */
|
/* Restore the frame pointer if necessary */
|
if (fp_save_area)
|
if (fp_save_area)
|
{
|
{
|
fprintf (file, "\tl.lwz\tr%d,%d(r%d)\n", FRAME_POINTER_REGNUM,
|
fprintf (file, "\tl.lwz\tr%d,%d(r%d)\n", HARD_FRAME_POINTER_REGNUM,
|
OR32_ALIGN (crtl->outgoing_args_size, 4)
|
OR32_ALIGN (crtl->outgoing_args_size, 4)
|
+ lr_save_area, STACK_POINTER_REGNUM);
|
+ lr_save_area, STACK_POINTER_REGNUM);
|
}
|
}
|
|
|
save_area = (OR32_ALIGN (crtl->outgoing_args_size, 4)
|
save_area = (OR32_ALIGN (crtl->outgoing_args_size, 4)
|
Line 1386... |
Line 1423... |
if (stack_size >= 0x8000)
|
if (stack_size >= 0x8000)
|
{
|
{
|
fprintf (file, "\tl.movhi\tr3,hi(%d)\n", stack_size);
|
fprintf (file, "\tl.movhi\tr3,hi(%d)\n", stack_size);
|
fprintf (file, "\tl.ori\tr3,r3,lo(%d)\n", stack_size);
|
fprintf (file, "\tl.ori\tr3,r3,lo(%d)\n", stack_size);
|
|
|
if (!TARGET_MASK_ALIGNED_JUMPS)
|
|
fprintf (file, "\tl.jr\tr%d\n", LINK_REGNUM);
|
|
else
|
|
{
|
|
fprintf (file, "\t.balignl\t0x8,0x15000015,0x4\n");
|
|
fprintf (file, "\tl.jr\tr%d\n", LINK_REGNUM);
|
fprintf (file, "\tl.jr\tr%d\n", LINK_REGNUM);
|
}
|
|
|
|
fprintf (file, "\tl.add\tr%d,r%d,r3\n", STACK_POINTER_REGNUM,
|
fprintf (file, "\tl.add\tr%d,r%d,r3\n", STACK_POINTER_REGNUM,
|
STACK_POINTER_REGNUM);
|
STACK_POINTER_REGNUM);
|
}
|
}
|
else if (stack_size > 0)
|
else if (stack_size > 0)
|
{
|
{
|
if (!TARGET_MASK_ALIGNED_JUMPS)
|
|
fprintf (file, "\tl.jr\tr%d\n", LINK_REGNUM);
|
fprintf (file, "\tl.jr\tr%d\n", LINK_REGNUM);
|
else
|
|
{
|
|
fprintf (file, "\t.balignl 0x8,0x15000015,0x4\n");
|
|
fprintf (file, "\tl.jr\tr%d\n", LINK_REGNUM);
|
|
}
|
|
|
|
fprintf (file, "\tl.addi\tr%d,r%d,%d\n", STACK_POINTER_REGNUM,
|
fprintf (file, "\tl.addi\tr%d,r%d,%d\n", STACK_POINTER_REGNUM,
|
STACK_POINTER_REGNUM, stack_size);
|
STACK_POINTER_REGNUM, stack_size);
|
}
|
}
|
else
|
else
|
{
|
{
|
if (!TARGET_MASK_ALIGNED_JUMPS)
|
|
fprintf (file, "\tl.jr\tr%d\n", LINK_REGNUM);
|
fprintf (file, "\tl.jr\tr%d\n", LINK_REGNUM);
|
else
|
|
{
|
|
fprintf (file, "\t.balignl\t0x8,0x15000015,0x4\n");
|
|
fprintf (file, "\tl.jr\tr%d\n", LINK_REGNUM);
|
|
}
|
|
|
|
fprintf (file, "\tl.nop\n"); /* Delay slot */
|
fprintf (file, "\tl.nop\n"); /* Delay slot */
|
}
|
}
|
} /* or32_output_function_epilogue () */
|
} /* or32_output_function_epilogue () */
|
|
|
Line 1503... |
Line 1522... |
compilation. The hook is used to enforce these restrictions, as the sibcall
|
compilation. The hook is used to enforce these restrictions, as the sibcall
|
md pattern can not fail, or fall over to a “normal” call. The criteria for
|
md pattern can not fail, or fall over to a “normal” call. The criteria for
|
successful sibling call optimization may vary greatly between different
|
successful sibling call optimization may vary greatly between different
|
architectures.
|
architectures.
|
|
|
For the OR32, we currently allow sibcall optimization if the -msibcall
|
For the OR32, we currently allow sibcall optimization whenever
|
argument is passed.
|
-foptimize-sibling-calls is enabled.
|
|
|
JPB 30-Aug-10: Surely we should always allow this?
|
|
|
|
@param[in] decl The function for which we may optimize
|
@param[in] decl The function for which we may optimize
|
@param[in] exp The call expression which is candidate for optimization.
|
@param[in] exp The call expression which is candidate for optimization.
|
|
|
@return Non-zero (TRUE) if sibcall optimization is permitted, zero (FALSE)
|
@return Non-zero (TRUE) if sibcall optimization is permitted, zero (FALSE)
|
Line 1518... |
Line 1535... |
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
static bool
|
static bool
|
or32_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
|
or32_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
|
tree exp ATTRIBUTE_UNUSED)
|
tree exp ATTRIBUTE_UNUSED)
|
{
|
{
|
return TARGET_MASK_SIBCALL;
|
return true;
|
|
|
} /* or32_function_ok_for_sibcall () */
|
} /* or32_function_ok_for_sibcall () */
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
/*!Should an argument be passed by reference.
|
/*!Should an argument be passed by reference.
|
Line 1558... |
Line 1574... |
return (type && (AGGREGATE_TYPE_P (type) || int_size_in_bytes (type) > 8));
|
return (type && (AGGREGATE_TYPE_P (type) || int_size_in_bytes (type) > 8));
|
|
|
} /* or32_pass_by_reference () */
|
} /* or32_pass_by_reference () */
|
|
|
|
|
|
#if 0
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
/*!Is a frame pointer required?
|
/*!Is a frame pointer required?
|
|
|
This target hook should return TRUE if a function must have and use a frame
|
This target hook should return TRUE if a function must have and use a frame
|
pointer. This target hook is called in the reload pass. If its return
|
pointer. This target hook is called in the reload pass. If its return
|
Line 1598... |
Line 1615... |
or32_frame_pointer_required (void)
|
or32_frame_pointer_required (void)
|
{
|
{
|
return 1;
|
return 1;
|
|
|
} /* or32_frame_pointer_required () */
|
} /* or32_frame_pointer_required () */
|
|
#endif
|
|
|
|
int
|
|
or32_initial_elimination_offset(int from, int to)
|
|
{
|
|
if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
|
|
return 0;
|
|
or32_compute_frame_size (get_frame_size ());
|
|
return ((from == FRAME_POINTER_REGNUM ? frame_info.gpr_offset : 0)
|
|
+ (to == STACK_POINTER_REGNUM ? frame_info.total_size : 0));
|
|
}
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
/*!How many bytes at the beginning of an argument must be put into registers.
|
/*!How many bytes at the beginning of an argument must be put into registers.
|
|
|
Line 1847... |
Line 1875... |
If the target requires any other actions, such as flushing caches or
|
If the target requires any other actions, such as flushing caches or
|
enabling stack execution, these actions should be performed after
|
enabling stack execution, these actions should be performed after
|
initializing the trampoline proper.
|
initializing the trampoline proper.
|
|
|
For the OR32, no static chain register is used. We choose to use the return
|
For the OR32, no static chain register is used. We choose to use the return
|
value (rv) register. The rvh register is used as a temporary. The code is
|
value (rv) register. The code is based on that for MIPS.
|
based on that for MIPS. The trampoline code is:
|
The trampoline code is:
|
|
|
l.movhi r12,hi(end_addr)
|
l.movhi r11,hi(end_addr)
|
l.ori r12,lo(end_addr)
|
l.ori r11,lo(end_addr)
|
l.lwz r13,4(r12)
|
l.lwz r13,4(r11)
|
l.jr r13
|
l.jr r13
|
l.lwz r11,0(r12)
|
l.lwz r11,0(r11)
|
end_addr:
|
end_addr:
|
.word <static chain>
|
.word <static chain>
|
.word <nested_function>
|
.word <nested_function>
|
|
|
@note For the OR32 we need to flush the instruction cache, which is a
|
@note For the OR32 we need to flush the instruction cache, which is a
|
Line 1901... |
Line 1929... |
addr = force_reg (Pmode, XEXP (m_tramp, 0));
|
addr = force_reg (Pmode, XEXP (m_tramp, 0));
|
end_addr = or32_force_binary (Pmode, PLUS, addr, GEN_INT (end_addr_offset));
|
end_addr = or32_force_binary (Pmode, PLUS, addr, GEN_INT (end_addr_offset));
|
|
|
/* Build up the code in TRAMPOLINE.
|
/* Build up the code in TRAMPOLINE.
|
|
|
l.movhi r12,hi(end_addr)
|
l.movhi r11,hi(end_addr)
|
l.ori r12,lo(end_addr)
|
l.ori r11,lo(end_addr)
|
l.lwz r13,4(r12)
|
l.lwz r13,4(r11)
|
l.jr r13
|
l.jr r13
|
l.lwz r11,0(r12)
|
l.lwz r11,0(r11)
|
end_addr:
|
end_addr:
|
*/
|
*/
|
|
|
i = 0;
|
i = 0;
|
|
|
Line 1918... |
Line 1946... |
NULL, false, OPTAB_WIDEN);
|
NULL, false, OPTAB_WIDEN);
|
low = convert_to_mode (SImode, gen_lowpart (HImode, end_addr), true);
|
low = convert_to_mode (SImode, gen_lowpart (HImode, end_addr), true);
|
|
|
/* Emit the l.movhi, adding an operation to OR in the high bits from the
|
/* Emit the l.movhi, adding an operation to OR in the high bits from the
|
RTX. */
|
RTX. */
|
opcode = gen_int_mode (OR32_MOVHI (12, 0), SImode);
|
opcode = gen_int_mode (OR32_MOVHI (11, 0), SImode);
|
trampoline[i++] = expand_simple_binop (SImode, IOR, opcode, high, NULL,
|
trampoline[i++] = expand_simple_binop (SImode, IOR, opcode, high, NULL,
|
false, OPTAB_WIDEN);
|
false, OPTAB_WIDEN);
|
|
|
/* Emit the l.ori, adding an operations to OR in the low bits from the
|
/* Emit the l.ori, adding an operations to OR in the low bits from the
|
RTX. */
|
RTX. */
|
opcode = gen_int_mode (OR32_ORI (12, 12, 0), SImode);
|
opcode = gen_int_mode (OR32_ORI (11, 11, 0), SImode);
|
trampoline[i++] = expand_simple_binop (SImode, IOR, opcode, low, NULL,
|
trampoline[i++] = expand_simple_binop (SImode, IOR, opcode, low, NULL,
|
false, OPTAB_WIDEN);
|
false, OPTAB_WIDEN);
|
|
|
/* Emit the l.lwz of the function address. No bits to OR in here, so we can
|
/* Emit the l.lwz of the function address. No bits to OR in here, so we can
|
do the opcode directly. */
|
do the opcode directly. */
|
trampoline[i++] =
|
trampoline[i++] =
|
gen_int_mode (OR32_LWZ (13, 12, target_function_offset - end_addr_offset),
|
gen_int_mode (OR32_LWZ (13, 11, target_function_offset - end_addr_offset),
|
SImode);
|
SImode);
|
|
|
/* Emit the l.jr of the function. No bits to OR in here, so we can do the
|
/* Emit the l.jr of the function. No bits to OR in here, so we can do the
|
opcode directly. */
|
opcode directly. */
|
trampoline[i++] = gen_int_mode (OR32_JR (13), SImode);
|
trampoline[i++] = gen_int_mode (OR32_JR (13), SImode);
|
|
|
/* Emit the l.lwz of the static chain. No bits to OR in here, so we can
|
/* Emit the l.lwz of the static chain. No bits to OR in here, so we can
|
do the opcode directly. */
|
do the opcode directly. */
|
trampoline[i++] =
|
trampoline[i++] =
|
gen_int_mode (OR32_LWZ (STATIC_CHAIN_REGNUM, 12,
|
gen_int_mode (OR32_LWZ (STATIC_CHAIN_REGNUM, 11,
|
static_chain_offset - end_addr_offset), SImode);
|
static_chain_offset - end_addr_offset), SImode);
|
|
|
/* Copy the trampoline code. Leave any padding uninitialized. */
|
/* Copy the trampoline code. Leave any padding uninitialized. */
|
for (j = 0; j < i; j++)
|
for (j = 0; j < i; j++)
|
{
|
{
|
Line 1991... |
Line 2019... |
{
|
{
|
return DW_CC_normal;
|
return DW_CC_normal;
|
|
|
} /* or32_dwarf_calling_convention () */
|
} /* or32_dwarf_calling_convention () */
|
|
|
|
/* If DELTA doesn't fit into a 16 bit signed number, emit instructions to
|
|
add the highpart to DST; return the signed-16-bit lowpart of DELTA.
|
|
TMP_REGNO is a register that may be used to load a constant. */
|
|
static HOST_WIDE_INT
|
|
or32_output_highadd (FILE *file,
|
|
const char *dst, int tmp_regno, HOST_WIDE_INT delta)
|
|
{
|
|
if (delta < -32768 || delta > 32767)
|
|
{
|
|
if (delta >= -65536 && delta < 65534)
|
|
{
|
|
asm_fprintf (file, "\tl.addi\t%s,%s,%d\n",
|
|
dst, dst, (int) (delta + 1) >> 1);
|
|
delta >>= 1;
|
|
}
|
|
else
|
|
{
|
|
const char *tmp = reg_names[tmp_regno];
|
|
HOST_WIDE_INT high = (delta + 0x8000) >> 16;
|
|
|
|
gcc_assert (call_used_regs[tmp_regno]);
|
|
asm_fprintf (file, "\tl.movhi\t%s,%d\n" "\tl.add\t%s,%s,%s\n",
|
|
tmp, (int) high,
|
|
dst, dst, tmp);
|
|
delta -= high << 16;
|
|
}
|
|
}
|
|
return delta;
|
|
}
|
|
|
|
/* Output a tailcall to FUNCTION. The caller will fill in the delay slot. */
|
|
void
|
|
or32_output_tailcall (FILE *file, tree function)
|
|
{
|
|
/* We'll need to add more code if we want to fully support PIC. */
|
|
gcc_assert (!flag_pic || (*targetm.binds_local_p) (function));
|
|
|
|
fputs ("\tl.j\t", file);
|
|
assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
|
|
fputc ('\n', file);
|
|
}
|
|
|
|
static void
|
|
or32_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
|
|
HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
|
|
tree function)
|
|
{
|
|
int this_regno
|
|
= aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 4 : 3;
|
|
const char *this_name = reg_names[this_regno];
|
|
|
|
|
|
delta = or32_output_highadd (file, this_name, PROLOGUE_TMP, delta);
|
|
if (!vcall_offset)
|
|
or32_output_tailcall (file, function);
|
|
if (delta || !vcall_offset)
|
|
asm_fprintf (file, "\tl.addi\t%s,%s,%d\n",
|
|
this_name, this_name, (int) delta);
|
|
|
|
/* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
|
|
if (vcall_offset != 0)
|
|
{
|
|
const char *tmp_name = reg_names[PROLOGUE_TMP];
|
|
|
|
/* l.lwz tmp,0(this) --> tmp = *this
|
|
l.lwz tmp,vcall_offset(tmp) --> tmp = *(*this + vcall_offset)
|
|
add this,this,tmp --> this += *(*this + vcall_offset) */
|
|
|
|
asm_fprintf (file, "\tl.lwz\t%s,0(%s)\n",
|
|
tmp_name, this_name);
|
|
vcall_offset = or32_output_highadd (file, tmp_name,
|
|
STATIC_CHAIN_REGNUM, vcall_offset);
|
|
asm_fprintf (file, "\tl.lwz\t%s,%d(%s)\n",
|
|
tmp_name, (int) vcall_offset, tmp_name);
|
|
or32_output_tailcall (file, function);
|
|
asm_fprintf (file, "\tl.add\t%s,%s,%s\n", this_name, this_name, tmp_name);
|
|
}
|
|
}
|
|
|
|
|
/* ========================================================================== */
|
/* ========================================================================== */
|
/* Target hook initialization.
|
/* Target hook initialization.
|
|
|
In most cases these use the static functions declared above. They have
|
In most cases these use the static functions declared above. They have
|
Line 2007... |
Line 2114... |
The final declaration is of the global "targetm" structure. */
|
The final declaration is of the global "targetm" structure. */
|
|
|
|
|
/* Default target_flags if no switches specified. */
|
/* Default target_flags if no switches specified. */
|
#undef TARGET_DEFAULT_TARGET_FLAGS
|
#undef TARGET_DEFAULT_TARGET_FLAGS
|
#define TARGET_DEFAULT_TARGET_FLAGS (MASK_HARD_MUL)
|
#define TARGET_DEFAULT_TARGET_FLAGS (MASK_HARD_MUL | MASK_SCHED_LOGUE)
|
|
|
/* Output assembly directives to switch to section name. The section should
|
/* Output assembly directives to switch to section name. The section should
|
have attributes as specified by flags, which is a bit mask of the SECTION_*
|
have attributes as specified by flags, which is a bit mask of the SECTION_*
|
flags defined in ‘output.h’. If decl is non-NULL, it is the VAR_DECL or
|
flags defined in ‘output.h’. If decl is non-NULL, it is the VAR_DECL or
|
FUNCTION_DECL with which this section is associated.
|
FUNCTION_DECL with which this section is associated.
|
Line 2033... |
Line 2140... |
#define TARGET_FUNCTION_OK_FOR_SIBCALL or32_function_ok_for_sibcall
|
#define TARGET_FUNCTION_OK_FOR_SIBCALL or32_function_ok_for_sibcall
|
|
|
#undef TARGET_PASS_BY_REFERENCE
|
#undef TARGET_PASS_BY_REFERENCE
|
#define TARGET_PASS_BY_REFERENCE or32_pass_by_reference
|
#define TARGET_PASS_BY_REFERENCE or32_pass_by_reference
|
|
|
#undef TARGET_FRAME_POINTER_REQUIRED
|
|
#define TARGET_FRAME_POINTER_REQUIRED or32_frame_pointer_required
|
|
|
|
#undef TARGET_ARG_PARTIAL_BYTES
|
#undef TARGET_ARG_PARTIAL_BYTES
|
#define TARGET_ARG_PARTIAL_BYTES or32_arg_partial_bytes
|
#define TARGET_ARG_PARTIAL_BYTES or32_arg_partial_bytes
|
|
|
/* This target hook returns TRUE if an argument declared in a prototype as an
|
/* This target hook returns TRUE if an argument declared in a prototype as an
|
integral type smaller than int should actually be passed as an int. In
|
integral type smaller than int should actually be passed as an int. In
|
Line 2063... |
Line 2167... |
#define TARGET_TRAMPOLINE_INIT or32_trampoline_init
|
#define TARGET_TRAMPOLINE_INIT or32_trampoline_init
|
|
|
#undef TARGET_DWARF_CALLING_CONVENTION
|
#undef TARGET_DWARF_CALLING_CONVENTION
|
#define TARGET_DWARF_CALLING_CONVENTION or32_dwarf_calling_convention
|
#define TARGET_DWARF_CALLING_CONVENTION or32_dwarf_calling_convention
|
|
|
|
#undef TARGET_ASM_OUTPUT_MI_THUNK
|
|
#define TARGET_ASM_OUTPUT_MI_THUNK or32_output_mi_thunk
|
|
|
|
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
|
|
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
|
|
|
/* Trampoline stubs are yet to be written. */
|
/* Trampoline stubs are yet to be written. */
|
/* #define TARGET_ASM_TRAMPOLINE_TEMPLATE */
|
/* #define TARGET_ASM_TRAMPOLINE_TEMPLATE */
|
/* #define TARGET_TRAMPOLINE_INIT */
|
/* #define TARGET_TRAMPOLINE_INIT */
|
|
|
/* Initialize the GCC target structure. */
|
/* Initialize the GCC target structure. */
|
struct gcc_target targetm = TARGET_INITIALIZER;
|
struct gcc_target targetm = TARGET_INITIALIZER;
|
|
|
No newline at end of file
|
No newline at end of file
|
|
/* Lay out structs with increased alignment so that they can be accessed
|
|
more efficiently. But don't increase the size of one or two byte
|
|
structs. */
|
|
int
|
|
or32_struct_alignment (tree t)
|
|
{
|
|
unsigned HOST_WIDE_INT total = 0;
|
|
tree field;
|
|
unsigned max_align
|
|
= maximum_field_alignment ? maximum_field_alignment : BIGGEST_ALIGNMENT;
|
|
bool struct_p;
|
|
|
|
switch (TREE_CODE (t))
|
|
{
|
|
case RECORD_TYPE:
|
|
struct_p = true; break;
|
|
case UNION_TYPE: case QUAL_UNION_TYPE:
|
|
struct_p = false; break;
|
|
default: gcc_unreachable ();
|
|
}
|
|
/* Skip all non field decls */
|
|
for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
|
|
{
|
|
unsigned HOST_WIDE_INT field_size;
|
|
|
|
if (TREE_CODE (field) != FIELD_DECL)
|
|
continue;
|
|
if (!host_integerp (DECL_SIZE (field), 1))
|
|
return max_align;
|
|
field_size = tree_low_cst (DECL_SIZE (field), 1);
|
|
if (field_size >= BIGGEST_ALIGNMENT)
|
|
return max_align;
|
|
if (struct_p)
|
|
total += field_size;
|
|
else
|
|
total = MAX (total, field_size);
|
|
}
|
|
|
|
return total < max_align ? (1U << ceil_log2 (total)) : max_align;
|
|
}
|
|
|
|
/* Increase the alignment of objects so that they are easier to copy.
|
|
Note that this can cause more struct copies to be inlined, so code
|
|
size might increase, but so should perfromance. */
|
|
int
|
|
or32_data_alignment (tree t, int align)
|
|
{
|
|
if (align < FASTEST_ALIGNMENT && TREE_CODE (t) == ARRAY_TYPE)
|
|
{
|
|
int size = int_size_in_bytes (t);
|
|
|
|
return (size > 0 && size < FASTEST_ALIGNMENT / BITS_PER_UNIT
|
|
? (1 << floor_log2 (size)) * BITS_PER_UNIT
|
|
: FASTEST_ALIGNMENT);
|
|
}
|
|
return align;
|
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|