/* Subroutines used for code generation on picoChip processors.
- Copyright (C) 2001,2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by picoChip Designs Ltd. (http://www.picochip.com)
Maintained by Daniel Towner (daniel.towner@picochip.com) and
Hariharan Sandanagobalane (hariharan@picochip.com)
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
-#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-attr.h"
#include "output.h"
#include "basic-block.h"
#include "integrate.h"
+#include "diagnostic-core.h"
#include "toplev.h"
#include "ggc.h"
#include "hashtab.h"
int picochip_arg_partial_bytes (CUMULATIVE_ARGS * p_cum,
enum machine_mode mode,
tree type, bool named);
+rtx picochip_function_arg (CUMULATIVE_ARGS * p_cum,
+ enum machine_mode mode,
+ const_tree type, bool named);
+rtx picochip_incoming_function_arg (CUMULATIVE_ARGS * p_cum,
+ enum machine_mode mode,
+ const_tree type, bool named);
+void picochip_arg_advance (CUMULATIVE_ARGS * p_cum, enum machine_mode mode,
+ const_tree type, bool named);
int picochip_sched_lookahead (void);
int picochip_sched_issue_rate (void);
bool picochip_return_in_memory(const_tree type,
const_tree fntype ATTRIBUTE_UNUSED);
bool picochip_legitimate_address_p (enum machine_mode, rtx, bool);
+rtx picochip_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+ enum machine_mode mode);
+int picochip_legitimize_reload_address (rtx *x, enum machine_mode mode,
+ int opnum, int type, int ind_levels);
rtx picochip_struct_value_rtx(tree fntype ATTRIBUTE_UNUSED, int incoming ATTRIBUTE_UNUSED);
rtx picochip_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED,
bool outgoing ATTRIBUTE_UNUSED);
-enum reg_class
+reg_class_t
picochip_secondary_reload (bool in_p,
- rtx x ATTRIBUTE_UNUSED,
- enum reg_class cla ATTRIBUTE_UNUSED,
- enum machine_mode mode,
- secondary_reload_info *sri);
+ rtx x ATTRIBUTE_UNUSED,
+ reg_class_t cla ATTRIBUTE_UNUSED,
+ enum machine_mode mode,
+ secondary_reload_info *sri);
void
picochip_asm_named_section (const char *name,
unsigned int flags ATTRIBUTE_UNUSED,
static rtx picochip_static_chain (const_tree, bool);
+static void picochip_option_override (void);
+
/* Lookup table mapping a register number to the earliest containing
class. Used by REGNO_REG_CLASS. */
const enum reg_class picochip_regno_reg_class[FIRST_PSEUDO_REGISTER] =
/* Determine which ALU to use for the instruction in
picochip_current_prescan_insn. */
static char picochip_get_vliw_alu_id (void);
+
+/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
+static const struct default_options picochip_option_optimization_table[] =
+ {
+ { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
+ { OPT_LEVELS_NONE, 0, NULL, 0 }
+ };
\f
/* Initialize the GCC target structure. */
#undef TARGET_ARG_PARTIAL_BYTES
#define TARGET_ARG_PARTIAL_BYTES picochip_arg_partial_bytes
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG picochip_function_arg
+
+#undef TARGET_FUNCTION_INCOMING_ARG
+#define TARGET_FUNCTION_INCOMING_ARG picochip_incoming_function_arg
+
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE picochip_arg_advance
+
#undef TARGET_PROMOTE_FUNCTION_MODE
#define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
#undef TARGET_PROMOTE_PROTOTYPES
#undef TARGET_LEGITIMATE_ADDRESS_P
#define TARGET_LEGITIMATE_ADDRESS_P picochip_legitimate_address_p
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS picochip_legitimize_address
+
/* Loading and storing QImode values to and from memory
usually requires a scratch register. */
#undef TARGET_SECONDARY_RELOAD
#undef TARGET_STATIC_CHAIN
#define TARGET_STATIC_CHAIN picochip_static_chain
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE picochip_option_override
+
+#undef TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE
+#define TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE picochip_option_override
+
+#undef TARGET_OPTION_OPTIMIZATION_TABLE
+#define TARGET_OPTION_OPTIMIZATION_TABLE picochip_option_optimization_table
+
+#undef TARGET_EXCEPT_UNWIND_INFO
+#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
return ((unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 4);
}
-/* Allow certain command options to be overriden. */
-void
-picochip_override_options (void)
+/* Allow some options to be overriden. In particular, the 2nd
+ scheduling pass option is switched off, and a machine dependent
+ reorganisation ensures that it is run later on, after the second
+ jump optimisation. */
+
+static void
+picochip_option_override (void)
{
/* If we are optimizing for stack, dont let inliner to inline functions
that could potentially increase stack size.*/
if (flag_conserve_stack)
- {
- PARAM_VALUE (PARAM_LARGE_STACK_FRAME) = 0;
- PARAM_VALUE (PARAM_STACK_FRAME_GROWTH) = 0;
- }
+ {
+ maybe_set_param_value (PARAM_LARGE_STACK_FRAME, 0,
+ global_options.x_param_values,
+ global_options_set.x_param_values);
+ maybe_set_param_value (PARAM_STACK_FRAME_GROWTH, 0,
+ global_options.x_param_values,
+ global_options_set.x_param_values);
+ }
/* Turn off the elimination of unused types. The elaborator
generates various interesting types to represent constants,
flag_schedule_insns_after_reload = 0;
if (picochip_flag_schedule_insns2)
{
-
if (optimize_size)
picochip_schedule_type = DFA_TYPE_SPACE;
else
picochip_schedule_type = DFA_TYPE_SPEED;
flag_delayed_branch = 0;
}
-
}
else
picochip_schedule_type = DFA_TYPE_NONE;
set_optab_libfunc (add_optab, DImode, "_adddi3");
set_optab_libfunc (sub_optab, DImode, "_subdi3");
}
+
+/* Memcpy function */
+int
+picochip_expand_movmemhi (rtx *operands)
+{
+ rtx src_addr_reg, dst_addr_reg, count_reg, src_mem, dst_mem, tmp_reg;
+ rtx start_label;
+ int align, size;
+ src_addr_reg = gen_reg_rtx(HImode);
+ dst_addr_reg = gen_reg_rtx(HImode);
+ count_reg = gen_reg_rtx(HImode);
+ emit_insn (gen_movhi (count_reg, operands[2]));
+ emit_insn (gen_movqi (src_addr_reg, XEXP(operands[1], 0)));
+ emit_insn (gen_movqi (dst_addr_reg, XEXP(operands[0], 0)));
+ gcc_assert (GET_CODE(count_reg) == REG);
+ start_label = gen_label_rtx ();
+ emit_label (start_label);
+
+ /* We can specialise the code for different alignments */
+ align = INTVAL(operands[3]);
+ size = INTVAL(operands[2]);
+ gcc_assert(align >= 0 && size >= 0);
+ if (size != 0)
+ {
+ if (size % 4 == 0 && align % 4 == 0)
+ {
+ src_mem = gen_rtx_MEM(SImode, src_addr_reg);
+ dst_mem = gen_rtx_MEM(SImode, dst_addr_reg);
+ tmp_reg = gen_reg_rtx(SImode);
+ emit_insn (gen_movsi (tmp_reg, src_mem));
+ emit_insn (gen_movsi (dst_mem, tmp_reg));
+ emit_insn (gen_addhi3 (dst_addr_reg, dst_addr_reg, GEN_INT(4)));
+ emit_insn (gen_addhi3 (src_addr_reg, src_addr_reg, GEN_INT(4)));
+ emit_insn (gen_addhi3 (count_reg, count_reg, GEN_INT(-4)));
+ /* The sub instruction above generates cc, but we cannot just emit the branch.*/
+ emit_cmp_and_jump_insns (count_reg, const0_rtx, GT, 0, HImode, 0, start_label);
+ }
+ else if (size % 2 == 0 && align % 2 == 0)
+ {
+ src_mem = gen_rtx_MEM(HImode, src_addr_reg);
+ dst_mem = gen_rtx_MEM(HImode, dst_addr_reg);
+ tmp_reg = gen_reg_rtx(HImode);
+ emit_insn (gen_movhi (tmp_reg, src_mem));
+ emit_insn (gen_movhi (dst_mem, tmp_reg));
+ emit_insn (gen_addhi3 (dst_addr_reg, dst_addr_reg, const2_rtx));
+ emit_insn (gen_addhi3 (src_addr_reg, src_addr_reg, const2_rtx));
+ emit_insn (gen_addhi3 (count_reg, count_reg, GEN_INT(-2)));
+ /* The sub instruction above generates cc, but we cannot just emit the branch.*/
+ emit_cmp_and_jump_insns (count_reg, const0_rtx, GT, 0, HImode, 0, start_label);
+ }
+ else
+ {
+ src_mem = gen_rtx_MEM(QImode, src_addr_reg);
+ dst_mem = gen_rtx_MEM(QImode, dst_addr_reg);
+ tmp_reg = gen_reg_rtx(QImode);
+ emit_insn (gen_movqi (tmp_reg, src_mem));
+ emit_insn (gen_movqi (dst_mem, tmp_reg));
+ emit_insn (gen_addhi3 (dst_addr_reg, dst_addr_reg, const1_rtx));
+ emit_insn (gen_addhi3 (src_addr_reg, src_addr_reg, const1_rtx));
+ emit_insn (gen_addhi3 (count_reg, count_reg, GEN_INT(-1)));
+ /* The sub instruction above generates cc, but we cannot just emit the branch.*/
+ emit_cmp_and_jump_insns (count_reg, const0_rtx, GT, 0, HImode, 0, start_label);
+ }
+ }
+ return 1;
+}
+
\f
/* Return the register class for letter C. */
enum reg_class
picochip_return_addr_rtx(int count, rtx frameaddr ATTRIBUTE_UNUSED)
{
if (count==0)
- return gen_rtx_REG (Pmode, LINK_REGNUM);
+ return gen_rtx_REG (Pmode, LINK_REGNUM);
else
- return NULL_RTX;
+ return NULL_RTX;
}
so that the correct Dwarf information is generated (see documention
for RTX_FRAME_RELATED_P for more details). */
RTX_FRAME_RELATED_P (insn) = 1;
- REG_NOTES (insn) =
- gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_rtx_SET (VOIDmode, stack_pointer_reg,
- gen_rtx_PLUS (Pmode, stack_pointer_reg,
- GEN_INT (-adjustment))),
- REG_NOTES (insn));
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode, stack_pointer_reg,
+ gen_rtx_PLUS (Pmode, stack_pointer_reg,
+ GEN_INT (-adjustment))));
}
gen_rtx_REG (HImode, REGNO (reg) + 1));
RTX_FRAME_RELATED_P (RTVEC_ELT (p, 1)) = 1;
- REG_NOTES (insn) =
- gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_rtx_PARALLEL (VOIDmode, p),
- REG_NOTES (insn));
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_PARALLEL (VOIDmode, p));
}
break;
static void
picochip_emit_restore_register (rtx reg, int offset)
{
- rtx stack_pointer, address, mem, insn;
+ rtx stack_pointer, address, mem;
stack_pointer = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
mem = gen_rtx_MEM (GET_MODE (reg), address);
- insn = emit_move_insn (reg, mem);
+ emit_move_insn (reg, mem);
}
/* Compute the size of an argument in units. */
static int
-picochip_compute_arg_size (tree type, enum machine_mode mode)
+picochip_compute_arg_size (const_tree type, enum machine_mode mode)
{
int type_size_in_units = 0;
/* Determine where the next outgoing arg should be placed. */
rtx
-picochip_function_arg (CUMULATIVE_ARGS cum, int mode, tree type,
- int named ATTRIBUTE_UNUSED)
+picochip_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ const_tree type, bool named ATTRIBUTE_UNUSED)
{
int reg = 0;
int type_align_in_units = 0;
/* Compute the correct offset (i.e., ensure that the offset meets
the alignment requirements). */
- offset_overflow = cum % type_align_in_units;
+ offset_overflow = *cum % type_align_in_units;
if (offset_overflow == 0)
- new_offset = cum;
+ new_offset = *cum;
else
- new_offset = (cum - offset_overflow) + type_align_in_units;
+ new_offset = (*cum - offset_overflow) + type_align_in_units;
if (TARGET_DEBUG)
{
printf ("Function arg:\n");
printf (" Type valid: %s\n", (type ? "yes" : "no"));
- printf (" Cumulative Value: %d\n", cum);
+ printf (" Cumulative Value: %d\n", *cum);
printf (" Mode: %s\n", GET_MODE_NAME (mode));
printf (" Type size: %i units\n", type_size_in_units);
printf (" Alignment: %i units\n", type_align_in_units);
case CSImode:
case SCmode:
case CQImode:
- return gen_rtx_REG ((enum machine_mode) mode, reg);
+ return gen_rtx_REG (mode, reg);
case BLKmode:
{
passed in registers, which are then pushed onto the stack by the
function prologue). */
rtx
-picochip_incoming_function_arg (CUMULATIVE_ARGS cum, int mode,
- tree type, int named)
+picochip_incoming_function_arg (CUMULATIVE_ARGS *cum,
+ enum machine_mode mode,
+ const_tree type, bool named)
{
if (cfun->stdarg)
}
-/* Advance the cumulative args counter, returning the new counter. */
-CUMULATIVE_ARGS
-picochip_arg_advance (const CUMULATIVE_ARGS cum, int mode,
- tree type, int named ATTRIBUTE_UNUSED)
+/* Advance the cumulative args counter CUM. */
+void
+picochip_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ const_tree type, bool named ATTRIBUTE_UNUSED)
{
int type_align_in_units = 0;
int type_size_in_units;
/* VOIDmode is passed when computing the second argument to a `call'
pattern. This can be ignored. */
if (mode == VOIDmode)
- return 0;
+ return;
/* Compute the alignment and size of the parameter. */
type_align_in_units =
/* Compute the correct offset (i.e., ensure that the offset meets
the alignment requirements). */
- offset_overflow = cum % type_align_in_units;
+ offset_overflow = *cum % type_align_in_units;
if (offset_overflow == 0)
- new_offset = cum;
+ new_offset = *cum;
else
- new_offset = (cum - offset_overflow) + type_align_in_units;
+ new_offset = (*cum - offset_overflow) + type_align_in_units;
/* Advance past the last argument. */
new_offset += type_size_in_units;
- return new_offset;
-
+ *cum = new_offset;
}
/* Determine whether a register needs saving/restoring. It does if it
}
int
-picochip_class_max_nregs (int class, int mode)
+picochip_class_max_nregs (int reg_class, int mode)
{
int size = ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
- if (class == ACC_REGS)
+ if (reg_class == ACC_REGS)
return 1;
if (GET_MODE_CLASS (mode) == MODE_CC)
{
rtx base = XEXP (x, 0);
rtx offset = XEXP (x, 1);
+ if (strict && !REGNO_OK_FOR_BASE_P (REGNO(base)))
+ {
+ valid = 0;
+ break;
+ }
valid = (REG == GET_CODE (base) &&
- REGNO_OK_FOR_BASE_P (REGNO(base)) &&
picochip_legitimate_address_register (base, strict) &&
CONST_INT == GET_CODE (offset) &&
picochip_const_ok_for_base (mode, REGNO (base),
}
+/* For all memory operations, picochip allows a uconst4 offset value. It
+ is hence beneficial to turn an
+ addr = <reg + long_const>
+ ld/st addr
+
+ into
+
+ X = reg + long_const & FFF0
+ diff = long_const - (long_const & FFF0)
+ ld/st <X + diff>
+
+ X can be reused in subsequent memory operations.
+ */
+rtx
+picochip_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+ enum machine_mode mode)
+{
+ unsigned mask_val;
+
+ if (!optimize)
+ return x;
+
+ /* Depending on mode, the offsets allowed are either 16/32/64.*/
+ switch (mode)
+ {
+ case QImode:
+ mask_val = 0xFFF0;
+ break;
+ case HImode:
+ mask_val = 0xFFE0;
+ break;
+ case SImode:
+ mask_val = 0xFFC0;
+ break;
+ default:
+ return x;
+ }
+
+ if (GET_CODE (x) == PLUS
+ && GET_CODE (XEXP (x, 0)) == REG
+ && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ int high_val, low_val, offset;
+ offset = INTVAL (XEXP (x, 1));
+ /* Ignore cases with negative offsets. */
+ if (offset < 0)
+ return x;
+ high_val = offset & mask_val;
+ low_val = offset - high_val;
+ if (high_val != 0)
+ {
+ rtx temp_reg = force_reg (Pmode, gen_rtx_PLUS (Pmode, XEXP (x, 0), GEN_INT(high_val)));
+ x = gen_rtx_PLUS (Pmode, temp_reg, GEN_INT(low_val));
+ return x;
+ }
+ }
+ return x;
+}
+
+/* For all memory operations, picochip allows a uconst4 offset value. It
+ is hence beneficial to turn an
+ addr = <reg + long_const>
+ ld/st addr
+
+ into
+
+ X = reg + long_const & FFF0
+ diff = long_const - (long_const & FFF0)
+ ld/st <X + diff>
+
+ X can be reused in subsequent memory operations.
+ */
+int
+picochip_legitimize_reload_address (rtx *x,
+ enum machine_mode mode,
+ int opnum, int type,
+ int ind_levels ATTRIBUTE_UNUSED)
+{
+ unsigned mask_val;
+
+ if (picochip_symbol_offset(*x))
+ {
+ *x = gen_rtx_CONST(mode, *x);
+ return 0;
+ }
+ if (!optimize)
+ return 0;
+
+ /* We should recognise addresses that we created.*/
+ if (GET_CODE (*x) == PLUS
+ && GET_CODE (XEXP (*x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (*x, 0), 0)) == REG
+ && GET_CODE (XEXP (XEXP (*x, 0), 1)) == CONST_INT
+ && GET_CODE (XEXP (*x, 1)) == CONST_INT)
+ {
+ push_reload (XEXP (*x, 0), NULL_RTX, &XEXP (*x, 0), NULL,
+ BASE_REG_CLASS, GET_MODE (*x), VOIDmode, 0, 0,
+ opnum, (enum reload_type)type);
+ return 1;
+ }
+
+ /* Depending on mode, the offsets allowed are either 16/32/64. */
+ switch (mode)
+ {
+ case QImode:
+ mask_val = 0xFFF0;
+ break;
+ case HImode:
+ mask_val = 0xFFE0;
+ break;
+ case SImode:
+ mask_val = 0xFFC0;
+ break;
+ default:
+ return 0;
+ }
+
+ if (GET_CODE (*x) == PLUS
+ && GET_CODE (XEXP (*x, 0)) == REG
+ && GET_CODE (XEXP (*x, 1)) == CONST_INT)
+ {
+ int high_val, low_val, offset;
+ offset = INTVAL (XEXP (*x, 1));
+ /* Ignore cases with negative offsets. */
+ if (offset < 0)
+ return 0;
+ high_val = offset & mask_val;
+ low_val = offset - high_val;
+ if (high_val != 0)
+ {
+ rtx temp_reg = gen_rtx_PLUS (Pmode, XEXP (*x, 0), GEN_INT(high_val));
+ *x = gen_rtx_PLUS (Pmode, temp_reg, GEN_INT(low_val));
+ push_reload (XEXP (*x, 0), NULL_RTX, &XEXP (*x, 0), NULL,
+ BASE_REG_CLASS, GET_MODE (*x), VOIDmode, 0, 0,
+ opnum, (enum reload_type)type);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/* Detect an rtx which matches (plus (symbol_ref) (const_int)). */
int
picochip_symbol_offset (rtx operand)
sprintf (picochip_current_vliw_state.lm_label_name,
"picoMark_%s%ld", prefix, num);
}
+ else if (picochip_schedule_type == DFA_TYPE_SPEED &&
+ (strcmp (prefix, "LCFI")) == 0 && picochip_vliw_continuation)
+ {
+ if (picochip_current_vliw_state.num_cfi_labels_deferred == 2)
+ {
+ internal_error ("LCFI labels have already been deferred.");
+ }
+ sprintf(picochip_current_vliw_state.cfi_label_name[
+ picochip_current_vliw_state.num_cfi_labels_deferred],
+ "picoMark_%s%ld", prefix, num);
+ picochip_current_vliw_state.num_cfi_labels_deferred++;
+ }
else
{
/* Marker label. */
for (i = 0; i < length; ++i)
{
- fprintf (file, "16#%hhx# ", (char) (str[i]));
+ fprintf (file, "16#%x# ", (char) (str[i]));
}
fprintf (file, " ; ");
/* Variable tracking should be run after all optimizations which change order
of insns. It also needs a valid CFG. This can't be done in
- picochip_override_options, because flag_var_tracking is finalized after
+ picochip_option_override, because flag_var_tracking is finalized after
that. */
picochip_flag_var_tracking = flag_var_tracking;
flag_var_tracking = 0;
int isRealShortBranch = (get_attr_length(insn) == SHORT_BRANCH_LENGTH);
return (isRealShortBranch ||
- (!isRealShortBranch &&
- picochip_current_vliw_state.num_insns_in_packet > 1));
+ picochip_current_vliw_state.num_insns_in_packet > 1);
}
/* Output a compare-and-branch instruction (matching the cbranch
const char *
picochip_output_compare (rtx operands[])
{
+ int code;
if (HImode != GET_MODE (operands[1]) ||
(HImode != GET_MODE (operands[2]) &&
__FUNCTION__);
}
+ code = GET_CODE (operands[0]);
/* Use the type of comparison to output the appropriate condition
test. */
- int code = GET_CODE (operands[0]);
switch (code)
{
case NE:
reorder_var_tracking_notes (void)
{
basic_block bb;
+
FOR_EACH_BB (bb)
{
- rtx insn, next;
+ rtx insn, next, last_insn = NULL_RTX;
rtx queue = NULL_RTX;
- for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
- {
- next = NEXT_INSN (insn);
-
- if (NONDEBUG_INSN_P (insn))
- {
- /* Emit queued up notes before the first instruction of a bundle. */
- if (GET_MODE (insn) == TImode)
- {
- while (queue)
- {
- rtx next_queue = PREV_INSN (queue);
- NEXT_INSN (PREV_INSN(insn)) = queue;
- PREV_INSN (queue) = PREV_INSN(insn);
- PREV_INSN (insn) = queue;
- NEXT_INSN (queue) = insn;
- queue = next_queue;
- }
- }
- }
- else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
- {
- rtx prev = PREV_INSN (insn);
- PREV_INSN (next) = prev;
- NEXT_INSN (prev) = next;
+ /* Iterate through the bb and find the last non-debug insn */
+ for (insn = BB_HEAD (bb); insn != NEXT_INSN(BB_END (bb)); insn = NEXT_INSN(insn))
+ {
+ if (NONDEBUG_INSN_P(insn))
+ last_insn = insn;
+ }
+
+ /* In all normal cases, queue up notes and emit them just before a TImode
+ instruction. For the last instruction, emit the queued notes just after
+ the last instruction. */
+ for (insn = BB_HEAD (bb); insn != NEXT_INSN(BB_END (bb)); insn = next)
+ {
+ next = NEXT_INSN (insn);
+
+ if (insn == last_insn)
+ {
+ while (queue)
+ {
+ rtx next_queue = PREV_INSN (queue);
+ PREV_INSN (NEXT_INSN(insn)) = queue;
+ NEXT_INSN(queue) = NEXT_INSN(insn);
+ PREV_INSN(queue) = insn;
+ NEXT_INSN(insn) = queue;
+ queue = next_queue;
+ }
+ /* There is no more to do for this bb. break*/
+ break;
+ }
+ else if (NONDEBUG_INSN_P (insn))
+ {
+ /* Emit queued up notes before the first instruction of a bundle. */
+ if (GET_MODE (insn) == TImode)
+ {
+ while (queue)
+ {
+ rtx next_queue = PREV_INSN (queue);
+ NEXT_INSN (PREV_INSN(insn)) = queue;
+ PREV_INSN (queue) = PREV_INSN(insn);
+ PREV_INSN (insn) = queue;
+ NEXT_INSN (queue) = insn;
+ queue = next_queue;
+ }
+ }
+ }
+ else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
+ {
+ rtx prev = PREV_INSN (insn);
+ PREV_INSN (next) = prev;
+ NEXT_INSN (prev) = next;
PREV_INSN (insn) = queue;
- queue = insn;
- }
- }
+ queue = insn;
+ }
+ }
+ /* Make sure we are not dropping debug instructions.*/
+ gcc_assert (queue == NULL_RTX);
}
}
for (insn = get_insns (); insn; insn = next_insn (insn))
{
/* The prologue end must be moved to the end of the VLIW packet. */
- if (NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END)
+ if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END)
{
prologue_end_note = insn;
break;
if (last_insn_in_packet != NULL)
{
- rtx tmp_note = emit_note_after (NOTE_KIND(prologue_end_note), last_insn_in_packet);
+ rtx tmp_note
+ = emit_note_after ((enum insn_note) NOTE_KIND (prologue_end_note),
+ last_insn_in_packet);
memcpy(&NOTE_DATA (tmp_note), &NOTE_DATA(prologue_end_note), sizeof(NOTE_DATA(prologue_end_note)));
delete_insn (prologue_end_note);
}
{
int offset1=0,offset2=0;
rtx reg;
+ rtx address;
if (GET_CODE(XEXP(opnd1,0)) == PLUS && GET_CODE(XEXP(XEXP(opnd1,0),1)) == CONST_INT)
{
offset1 = INTVAL(XEXP(XEXP(opnd1,0),1));
{
offset2 = INTVAL(XEXP(XEXP(opnd2,0),1));
}
- rtx address = gen_rtx_PLUS (HImode, reg, GEN_INT(minimum(offset1,offset2)));
+ address = gen_rtx_PLUS (HImode, reg, GEN_INT(minimum(offset1,offset2)));
return gen_rtx_MEM(SImode,address);
}
/* Given a builtin function taking 2 operands (i.e., target + source),
emit the RTL for the underlying instruction. */
static rtx
-picochip_expand_builtin_2op (enum insn_code icode, tree arglist, rtx target)
+picochip_expand_builtin_2op (enum insn_code icode, tree call, rtx target)
{
tree arg0;
rtx op0, pat;
enum machine_mode tmode, mode0;
/* Grab the incoming argument and emit its RTL. */
- arg0 = TREE_VALUE (arglist);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ arg0 = CALL_EXPR_ARG (call, 0);
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
/* Determine the modes of the instruction operands. */
tmode = insn_data[icode].operand[0].mode;
/* Given a builtin function taking 3 operands (i.e., target + two
source), emit the RTL for the underlying instruction. */
static rtx
-picochip_expand_builtin_3op (enum insn_code icode, tree arglist, rtx target)
+picochip_expand_builtin_3op (enum insn_code icode, tree call, rtx target)
{
tree arg0, arg1;
rtx op0, op1, pat;
enum machine_mode tmode, mode0, mode1;
/* Grab the function's arguments. */
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ arg0 = CALL_EXPR_ARG (call, 0);
+ arg1 = CALL_EXPR_ARG (call, 1);
/* Emit rtl sequences for the function arguments. */
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
/* Get the mode's of each of the instruction operands. */
tmode = insn_data[icode].operand[0].mode;
/* Expand a builtin function which takes two arguments, and returns a void. */
static rtx
-picochip_expand_builtin_2opvoid (enum insn_code icode, tree arglist)
+picochip_expand_builtin_2opvoid (enum insn_code icode, tree call)
{
tree arg0, arg1;
rtx op0, op1, pat;
enum machine_mode mode0, mode1;
/* Grab the function's arguments. */
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ arg0 = CALL_EXPR_ARG (call, 0);
+ arg1 = CALL_EXPR_ARG (call, 1);
/* Emit rtl sequences for the function arguments. */
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
/* Get the mode's of each of the instruction operands. */
mode0 = insn_data[icode].operand[0].mode;
/* Expand an array get into the corresponding RTL. */
static rtx
-picochip_expand_array_get (tree arglist, rtx target)
+picochip_expand_array_get (tree call, rtx target)
{
tree arg0, arg1, arg2;
rtx op0, op1, op2, pat;
/* Grab the function's arguments. */
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ arg0 = CALL_EXPR_ARG (call, 0);
+ arg1 = CALL_EXPR_ARG (call, 1);
+ arg2 = CALL_EXPR_ARG (call, 2) ;
/* Emit rtl sequences for the function arguments. */
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
- op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op2 = expand_expr (arg2, NULL_RTX, VOIDmode, EXPAND_NORMAL);
/* The second and third operands must be constant. Nothing else will
do. */
/* Expand an array put into the corresponding RTL. */
static rtx
-picochip_expand_array_put (tree arglist, rtx target)
+picochip_expand_array_put (tree call, rtx target)
{
tree arg0, arg1, arg2, arg3;
rtx op0, op1, op2, op3, pat;
/* Grab the function's arguments. */
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (arglist->common.chain);
- arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
- arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
+ arg0 = CALL_EXPR_ARG (call, 0);
+ arg1 = CALL_EXPR_ARG (call, 1);
+ arg2 = CALL_EXPR_ARG (call, 2);
+ arg3 = CALL_EXPR_ARG (call, 3);
/* Emit rtl sequences for the function arguments. */
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
- op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
- op3 = expand_expr (arg3, NULL_RTX, VOIDmode, 0);
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op2 = expand_expr (arg2, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op3 = expand_expr (arg3, NULL_RTX, VOIDmode, EXPAND_NORMAL);
/* The first operand must be an SImode register. */
if (GET_MODE (op0) != SImode || REG != GET_CODE (op0))
/* Expand an array testport into the corresponding RTL. */
static rtx
-picochip_expand_array_testport (tree arglist, rtx target)
+picochip_expand_array_testport (tree call, rtx target)
{
tree arg0, arg1, arg2;
rtx op0, op1, op2, pat;
/* Grab the function's arguments. */
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ arg0 = CALL_EXPR_ARG (call, 0);
+ arg1 = CALL_EXPR_ARG (call, 1);
+ arg2 = CALL_EXPR_ARG (call, 2);
/* Emit rtl sequences for the function arguments. */
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
- op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op2 = expand_expr (arg2, NULL_RTX, VOIDmode, EXPAND_NORMAL);
/* The first operand must be a HImode register, or a constant. If it
isn't, force it into a HImode register. */
picochip_generate_halt (void)
{
static int currentId = 0;
+ rtx insns;
rtx id = GEN_INT (currentId);
currentId += 1;
it has to continue execution after the HALT.*/
emit_barrier ();
- rtx insns = get_insns();
+ insns = get_insns();
end_sequence();
emit_insn (insns);
void
picochip_init_builtins (void)
{
+ tree noreturn;
tree endlink = void_list_node;
tree int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink);
tree unsigned_endlink = tree_cons (NULL_TREE, unsigned_type_node, endlink);
tree_cons (NULL_TREE, integer_type_node, int_int_endlink);
tree int_long_endlink =
tree_cons (NULL_TREE, integer_type_node, long_endlink);
- tree pchar_type_node = build_pointer_type (char_type_node);
tree long_int_int_int_endlink =
tree_cons (NULL_TREE, long_integer_type_node, int_int_int_endlink);
- tree int_ftype_void, int_ftype_int, int_ftype_int_int, void_ftype_pchar;
- tree long_ftype_int, long_ftype_int_int, long_ftype_int_int_int;
+ tree int_ftype_int, int_ftype_int_int;
+ tree long_ftype_int, long_ftype_int_int_int;
tree void_ftype_int_long, int_ftype_int_int_int,
void_ftype_long_int_int_int;
- tree void_ftype_void, void_ftype_int, unsigned_ftype_unsigned;
+ tree void_ftype_void, unsigned_ftype_unsigned;
/* void func (void) */
void_ftype_void = build_function_type (void_type_node, endlink);
- /* void func (void *) */
- void_ftype_pchar
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, pchar_type_node, endlink));
-
- /* int func (void) */
- int_ftype_void = build_function_type (integer_type_node, endlink);
-
- /* void func (int) */
- void_ftype_int = build_function_type (void_type_node, int_endlink);
-
/* int func (int) */
int_ftype_int = build_function_type (integer_type_node, int_endlink);
/* long func(int) */
long_ftype_int = build_function_type (long_integer_type_node, int_endlink);
- /* long func(int, int) */
- long_ftype_int_int
- = build_function_type (long_integer_type_node, int_int_endlink);
-
/* long func(int, int, int) */
long_ftype_int_int_int
= build_function_type (long_integer_type_node, int_int_int_endlink);
/* Halt instruction. Note that the builtin function is marked as
having the attribute `noreturn' so that the compiler realises
that the halt stops the program dead. */
- tree noreturn = tree_cons (get_identifier ("noreturn"), NULL, NULL);
+ noreturn = tree_cons (get_identifier ("noreturn"), NULL, NULL);
add_builtin_function ("__builtin_halt", void_ftype_void,
PICOCHIP_BUILTIN_HALT, BUILT_IN_MD, NULL,
noreturn);
int ignore ATTRIBUTE_UNUSED)
{
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
- tree arglist = CALL_EXPR_ARGS(exp);
int fcode = DECL_FUNCTION_CODE (fndecl);
switch (fcode)
{
case PICOCHIP_BUILTIN_ASRI:
- return picochip_expand_builtin_3op (CODE_FOR_builtin_asri, arglist,
+ return picochip_expand_builtin_3op (CODE_FOR_builtin_asri, exp,
target);
case PICOCHIP_BUILTIN_ADDS:
- return picochip_expand_builtin_3op (CODE_FOR_sataddhi3, arglist,
+ return picochip_expand_builtin_3op (CODE_FOR_sataddhi3, exp,
target);
case PICOCHIP_BUILTIN_SUBS:
- return picochip_expand_builtin_3op (CODE_FOR_satsubhi3, arglist,
+ return picochip_expand_builtin_3op (CODE_FOR_satsubhi3, exp,
target);
case PICOCHIP_BUILTIN_SBC:
- return picochip_expand_builtin_2op (CODE_FOR_sbc, arglist, target);
+ return picochip_expand_builtin_2op (CODE_FOR_sbc, exp, target);
case PICOCHIP_BUILTIN_BREV:
- return picochip_expand_builtin_2op (CODE_FOR_brev, arglist, target);
+ return picochip_expand_builtin_2op (CODE_FOR_brev, exp, target);
case PICOCHIP_BUILTIN_BYTESWAP:
- return picochip_expand_builtin_2op (CODE_FOR_bswaphi2, arglist, target);
+ return picochip_expand_builtin_2op (CODE_FOR_bswaphi2, exp, target);
case PICOCHIP_BUILTIN_GET:
- return picochip_expand_builtin_2op (CODE_FOR_commsGet, arglist, target);
+ return picochip_expand_builtin_2op (CODE_FOR_commsGet, exp, target);
case PICOCHIP_BUILTIN_PUT:
- return picochip_expand_builtin_2opvoid (CODE_FOR_commsPut, arglist);
+ return picochip_expand_builtin_2opvoid (CODE_FOR_commsPut, exp);
case PICOCHIP_BUILTIN_TESTPORT:
- return picochip_expand_builtin_2op (CODE_FOR_commsTestPort, arglist,
+ return picochip_expand_builtin_2op (CODE_FOR_commsTestPort, exp,
target);
case PICOCHIP_BUILTIN_PUT_ARRAY:
- return picochip_expand_array_put (arglist, target);
+ return picochip_expand_array_put (exp, target);
case PICOCHIP_BUILTIN_GET_ARRAY:
- return picochip_expand_array_get (arglist, target);
+ return picochip_expand_array_get (exp, target);
case PICOCHIP_BUILTIN_TESTPORT_ARRAY:
- return picochip_expand_array_testport (arglist, target);
+ return picochip_expand_array_testport (exp, target);
case PICOCHIP_BUILTIN_HALT:
return picochip_generate_halt ();
choice of two registers to choose from, so that we a guaranteed to
get at least one register which is different to the output
register. This trick is taken from the alpha implementation. */
-enum reg_class
+reg_class_t
picochip_secondary_reload (bool in_p,
- rtx x ATTRIBUTE_UNUSED,
- enum reg_class cla ATTRIBUTE_UNUSED,
- enum machine_mode mode,
- secondary_reload_info *sri)
+ rtx x ATTRIBUTE_UNUSED,
+ reg_class_t cla ATTRIBUTE_UNUSED,
+ enum machine_mode mode,
+ secondary_reload_info *sri)
{
if (mode == QImode && !TARGET_HAS_BYTE_ACCESS)
{
handled using logical operations (e.g., SIreg != 0 when low ||
high). Need to find test cases to provoke this though (fixunssfdi
in libgcc does, but is complicated). */
- if (GET_MODE (branch_op_0) != HImode ||
- !(register_operand (branch_op_0, GET_MODE (branch_op_0))))
+ if (register_operand(branch_op_0, GET_MODE(branch_op_0)) &&
+ GET_MODE(branch_op_0) != HImode)
return 0;
- if (GET_MODE (branch_op_1) != HImode ||
- !(picochip_comparison_operand (branch_op_1, GET_MODE (branch_op_1))))
+ if (register_operand(branch_op_1, GET_MODE(branch_op_1)) &&
+ GET_MODE(branch_op_1) != HImode)
return 0;
return 1;