-/* Copyright (C) 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2006, 2007 Free Software Foundation, Inc.
This file 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
static unsigned char spu_function_ok_for_sibcall (tree decl, tree exp);
static void spu_init_libfuncs (void);
static bool spu_return_in_memory (tree type, tree fntype);
+static void fix_range (const char *);
+static void spu_encode_section_info (tree, rtx, int);
+static tree spu_builtin_mul_widen_even (tree);
+static tree spu_builtin_mul_widen_odd (tree);
+static tree spu_builtin_mask_for_load (void);
extern const char *reg_names[];
rtx spu_compare_op0, spu_compare_op1;
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY spu_return_in_memory
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO spu_encode_section_info
+
+#undef TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN
+#define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN spu_builtin_mul_widen_even
+
+#undef TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD
+#define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD spu_builtin_mul_widen_odd
+
+#undef TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD
+#define TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD spu_builtin_mask_for_load
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Sometimes certain combinations of command options do not make sense
void
spu_override_options (void)
{
-
/* Override some of the default param values. With so many registers
larger values are better for these params. */
if (MAX_UNROLLED_INSNS == 100)
if (align_functions < 8)
align_functions = 8;
+
+ if (spu_fixed_range_string)
+ fix_range (spu_fixed_range_string);
}
\f
/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
{
if (flag_stack_check)
{
- /* We compare agains total_size-1 because
+ /* We compare against total_size-1 because
($sp >= total_size) <=> ($sp > total_size-1) */
rtx scratch_v4si = gen_rtx_REG (V4SImode, REGNO (scratch_reg_0));
rtx sp_v4si = gen_rtx_REG (V4SImode, STACK_POINTER_REGNUM);
{
/* In this case we save the back chain first. */
insn = frame_emit_store (STACK_POINTER_REGNUM, sp_reg, -total_size);
- RTX_FRAME_RELATED_P (insn) = 1;
insn =
frame_emit_add_imm (sp_reg, sp_reg, -total_size, scratch_reg_0);
}
else if (satisfies_constraint_K (GEN_INT (-total_size)))
{
insn = emit_move_insn (scratch_reg_0, sp_reg);
- RTX_FRAME_RELATED_P (insn) = 1;
insn =
emit_insn (gen_addsi3 (sp_reg, sp_reg, GEN_INT (-total_size)));
}
else
{
insn = emit_move_insn (scratch_reg_0, sp_reg);
- RTX_FRAME_RELATED_P (insn) = 1;
insn =
frame_emit_add_imm (sp_reg, sp_reg, -total_size, scratch_reg_1);
}
{
/* Save the back chain ptr */
insn = frame_emit_store (REGNO (scratch_reg_0), sp_reg, 0);
- RTX_FRAME_RELATED_P (insn) = 1;
}
if (frame_pointer_needed)
HOST_WIDE_INT fp_offset = STACK_POINTER_OFFSET
+ current_function_outgoing_args_size;
/* Set the new frame_pointer */
- frame_emit_add_imm (fp_reg, sp_reg, fp_offset, scratch_reg_0);
+ insn = frame_emit_add_imm (fp_reg, sp_reg, fp_offset, scratch_reg_0);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ real = gen_addsi3 (fp_reg, sp_reg, GEN_INT (fp_offset));
+ REG_NOTES (insn) =
+ gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+ real, REG_NOTES (insn));
}
}
if (total_size > 0)
{
if (current_function_calls_alloca)
- /* Load it from the back chain because our save_stack_block and
- restore_stack_block do nothing. */
frame_emit_load (STACK_POINTER_REGNUM, sp_reg, 0);
else
frame_emit_add_imm (sp_reg, sp_reg, total_size, scratch_reg_0);
jump_insn. We adjust here so higher cost insns will get scheduled
earlier. */
if (GET_CODE (insn) == JUMP_INSN && REG_NOTE_KIND (link) == REG_DEP_ANTI)
- return INSN_COST (dep_insn) - 3;
+ return insn_cost (dep_insn) - 3;
return cost;
}
\f
else
cpat = 0;
}
- if (cpat)
+ if (cpat && (run || size < 16))
{
if (run == 0)
run = 1;
}
/* OP is a CONSTANT_P. Determine what instructions can be used to load
- it into a regiser. MODE is only valid when OP is a CONST_INT. */
+ it into a register. MODE is only valid when OP is a CONST_INT. */
static enum immediate_class
classify_immediate (rtx op, enum machine_mode mode)
{
return NULL_TREE;
}
-/* Return non-zero if FUNC is a naked function. */
+/* Return nonzero if FUNC is a naked function. */
static int
spu_naked_function_p (tree func)
{
return 0;
}
+/* Encode symbol attributes (local vs. global, tls model) of a SYMBOL_REF
+ into its SYMBOL_REF_FLAGS. */
+static void
+spu_encode_section_info (tree decl, rtx rtl, int first)
+{
+ default_encode_section_info (decl, rtl, first);
+
+ /* If a variable has a forced alignment to < 16 bytes, mark it with
+ SYMBOL_FLAG_ALIGN1. */
+ if (TREE_CODE (decl) == VAR_DECL
+ && DECL_USER_ALIGN (decl) && DECL_ALIGN (decl) < 128)
+ SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_ALIGN1;
+}
+
/* Return TRUE if we are certain the mem refers to a complete object
which is both 16-byte aligned and padded to a 16-byte boundary. This
would make it safe to store with a single instruction.
return 0;
}
+/* Parse the -mfixed-range= option string. */
+static void
+fix_range (const char *const_str)
+{
+ int i, first, last;
+ char *str, *dash, *comma;
+
+ /* str must be of the form REG1'-'REG2{,REG1'-'REG} where REG1 and
+ REG2 are either register names or register numbers. The effect
+ of this option is to mark the registers in the range from REG1 to
+ REG2 as ``fixed'' so they won't be used by the compiler. */
+
+ i = strlen (const_str);
+ str = (char *) alloca (i + 1);
+ memcpy (str, const_str, i + 1);
+
+ while (1)
+ {
+ dash = strchr (str, '-');
+ if (!dash)
+ {
+ warning (0, "value of -mfixed-range must have form REG1-REG2");
+ return;
+ }
+ *dash = '\0';
+ comma = strchr (dash + 1, ',');
+ if (comma)
+ *comma = '\0';
+
+ first = decode_reg_name (str);
+ if (first < 0)
+ {
+ warning (0, "unknown register name: %s", str);
+ return;
+ }
+
+ last = decode_reg_name (dash + 1);
+ if (last < 0)
+ {
+ warning (0, "unknown register name: %s", dash + 1);
+ return;
+ }
+
+ *dash = '-';
+
+ if (first > last)
+ {
+ warning (0, "%s-%s is an empty range", str, dash + 1);
+ return;
+ }
+
+ for (i = first; i <= last; ++i)
+ fixed_regs[i] = call_used_regs[i] = 1;
+
+ if (!comma)
+ break;
+
+ *comma = ',';
+ str = comma + 1;
+ }
+}
+
int
spu_valid_move (rtx * ops)
{
d->fndecl =
add_builtin_function (name, p, END_BUILTINS + i, BUILT_IN_MD,
NULL, NULL_TREE);
+ if (d->fcode == SPU_MASK_FOR_LOAD)
+ TREE_READONLY (d->fndecl) = 1;
}
}
+void
+spu_restore_stack_block (rtx op0 ATTRIBUTE_UNUSED, rtx op1)
+{
+ static unsigned char arr[16] =
+ { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 };
+
+ rtx temp = gen_reg_rtx (Pmode);
+ rtx temp2 = gen_reg_rtx (V4SImode);
+ rtx temp3 = gen_reg_rtx (V4SImode);
+ rtx pat = gen_reg_rtx (TImode);
+ rtx sp = gen_rtx_REG (V4SImode, STACK_POINTER_REGNUM);
+
+ emit_move_insn (pat, array_to_constant (TImode, arr));
+
+ /* Restore the sp. */
+ emit_move_insn (temp, op1);
+ emit_move_insn (temp2, gen_frame_mem (V4SImode, stack_pointer_rtx));
+
+ /* Compute available stack size for sp. */
+ emit_insn (gen_subsi3 (temp, temp, stack_pointer_rtx));
+ emit_insn (gen_shufb (temp3, temp, temp, pat));
+
+ emit_insn (gen_addv4si3 (sp, sp, temp3));
+ emit_move_insn (gen_frame_mem (V4SImode, stack_pointer_rtx), temp2);
+}
+
int
spu_safe_dma (HOST_WIDE_INT channel)
{
i++;
}
+ if (d->fcode == SPU_MASK_FOR_LOAD)
+ {
+ enum machine_mode mode = insn_data[icode].operand[1].mode;
+ tree arg;
+ rtx addr, op, pat;
+
+ /* get addr */
+ arg = TREE_VALUE (arglist);
+ gcc_assert (TREE_CODE (TREE_TYPE (arg)) == POINTER_TYPE);
+ op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+ addr = memory_address (mode, op);
+
+ /* negate addr */
+ op = gen_reg_rtx (GET_MODE (addr));
+ emit_insn (gen_rtx_SET (VOIDmode, op,
+ gen_rtx_NEG (GET_MODE (addr), addr)));
+ op = gen_rtx_MEM (mode, op);
+
+ pat = GEN_FCN (icode) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+ return target;
+ }
+
/* Ignore align_hint, but still expand it's args in case they have
side effects. */
if (icode == CODE_FOR_spu_align_hint)
abort ();
}
+/* Implement targetm.vectorize.builtin_mul_widen_even. */
+static tree
+spu_builtin_mul_widen_even (tree type)
+{
+ switch (TYPE_MODE (type))
+ {
+ case V8HImode:
+ if (TYPE_UNSIGNED (type))
+ return spu_builtins[SPU_MULE_0].fndecl;
+ else
+ return spu_builtins[SPU_MULE_1].fndecl;
+ break;
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* Implement targetm.vectorize.builtin_mul_widen_odd. */
+static tree
+spu_builtin_mul_widen_odd (tree type)
+{
+ switch (TYPE_MODE (type))
+ {
+ case V8HImode:
+ if (TYPE_UNSIGNED (type))
+ return spu_builtins[SPU_MULO_1].fndecl;
+ else
+ return spu_builtins[SPU_MULO_0].fndecl;
+ break;
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* Implement targetm.vectorize.builtin_mask_for_load. */
+static tree
+spu_builtin_mask_for_load (void)
+{
+ struct spu_builtin_description *d = &spu_builtins[SPU_MASK_FOR_LOAD];
+ gcc_assert (d);
+ return d->fndecl;
+}