/* Subroutines for assembler code output on the TMS320C[34]x
- Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003,
+ 2004, 2005
Free Software Foundation, Inc.
Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz)
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* Some output-actions in c4x.md need these. */
#include "config.h"
#include "optabs.h"
#include "libfuncs.h"
#include "flags.h"
-#include "loop.h"
#include "recog.h"
#include "ggc.h"
#include "cpplib.h"
rtx c4x_compare_op0;
rtx c4x_compare_op1;
-const char *c4x_rpts_cycles_string;
-int c4x_rpts_cycles = 0; /* Max. cycles for RPTS. */
-const char *c4x_cpu_version_string;
int c4x_cpu_version = 40; /* CPU version C30/31/32/33/40/44. */
/* Pragma definitions. */
tree naked_tree = NULL_TREE;
/* Forward declarations */
+static bool c4x_handle_option (size_t, const char *, int);
static int c4x_isr_reg_used_p (unsigned int);
static int c4x_leaf_function_p (void);
static int c4x_naked_function_p (void);
-static int c4x_immed_float_p (rtx);
-static int c4x_a_register (rtx);
-static int c4x_x_register (rtx);
static int c4x_immed_int_constant (rtx);
static int c4x_immed_float_constant (rtx);
-static int c4x_K_constant (rtx);
-static int c4x_N_constant (rtx);
-static int c4x_O_constant (rtx);
static int c4x_R_indirect (rtx);
-static int c4x_S_indirect (rtx);
static void c4x_S_address_parse (rtx , int *, int *, int *, int *);
static int c4x_valid_operands (enum rtx_code, rtx *, enum machine_mode, int);
static int c4x_arn_reg_operand (rtx, enum machine_mode, unsigned int);
static tree c4x_handle_fntype_attribute (tree *, tree, tree, int, bool *);
const struct attribute_spec c4x_attribute_table[];
static void c4x_insert_attributes (tree, tree *);
-static void c4x_asm_named_section (const char *, unsigned int);
+static void c4x_asm_named_section (const char *, unsigned int, tree);
static int c4x_adjust_cost (rtx, rtx, rtx, int);
static void c4x_globalize_label (FILE *, const char *);
static bool c4x_rtx_costs (rtx, int, int, int *);
#undef TARGET_ASM_EXTERNAL_LIBCALL
#define TARGET_ASM_EXTERNAL_LIBCALL c4x_external_libcall
+/* Play safe, not the fastest code. */
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS (MASK_ALIASES | MASK_PARALLEL \
+ | MASK_PARALLEL_MPY | MASK_RPTB)
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION c4x_handle_option
+
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE c4x_attribute_table
struct gcc_target targetm = TARGET_INITIALIZER;
\f
-/* Override command line options.
- Called once after all options have been parsed.
- Mostly we process the processor
- type and sometimes adjust other TARGET_ options. */
+/* Implement TARGET_HANDLE_OPTION. */
-void
-c4x_override_options (void)
+static bool
+c4x_handle_option (size_t code, const char *arg, int value)
{
- if (c4x_rpts_cycles_string)
- c4x_rpts_cycles = atoi (c4x_rpts_cycles_string);
- else
- c4x_rpts_cycles = 0;
-
- if (TARGET_C30)
- c4x_cpu_version = 30;
- else if (TARGET_C31)
- c4x_cpu_version = 31;
- else if (TARGET_C32)
- c4x_cpu_version = 32;
- else if (TARGET_C33)
- c4x_cpu_version = 33;
- else if (TARGET_C40)
- c4x_cpu_version = 40;
- else if (TARGET_C44)
- c4x_cpu_version = 44;
- else
- c4x_cpu_version = 40;
-
- /* -mcpu=xx overrides -m40 etc. */
- if (c4x_cpu_version_string)
+ switch (code)
{
- const char *p = c4x_cpu_version_string;
-
- /* Also allow -mcpu=c30 etc. */
- if (*p == 'c' || *p == 'C')
- p++;
- c4x_cpu_version = atoi (p);
- }
-
- target_flags &= ~(C30_FLAG | C31_FLAG | C32_FLAG | C33_FLAG |
- C40_FLAG | C44_FLAG);
+ case OPT_m30: c4x_cpu_version = 30; return true;
+ case OPT_m31: c4x_cpu_version = 31; return true;
+ case OPT_m32: c4x_cpu_version = 32; return true;
+ case OPT_m33: c4x_cpu_version = 33; return true;
+ case OPT_m40: c4x_cpu_version = 40; return true;
+ case OPT_m44: c4x_cpu_version = 44; return true;
+
+ case OPT_mcpu_:
+ if (arg[0] == 'c' || arg[0] == 'C')
+ arg++;
+ value = atoi (arg);
+ switch (value)
+ {
+ case 30: case 31: case 32: case 33: case 40: case 44:
+ c4x_cpu_version = value;
+ return true;
+ }
+ return false;
- switch (c4x_cpu_version)
- {
- case 30: target_flags |= C30_FLAG; break;
- case 31: target_flags |= C31_FLAG; break;
- case 32: target_flags |= C32_FLAG; break;
- case 33: target_flags |= C33_FLAG; break;
- case 40: target_flags |= C40_FLAG; break;
- case 44: target_flags |= C44_FLAG; break;
default:
- warning ("unknown CPU version %d, using 40.\n", c4x_cpu_version);
- c4x_cpu_version = 40;
- target_flags |= C40_FLAG;
+ return true;
}
+}
- if (TARGET_C30 || TARGET_C31 || TARGET_C32 || TARGET_C33)
- target_flags |= C3X_FLAG;
- else
- target_flags &= ~C3X_FLAG;
+/* Override command line options.
+ Called once after all options have been parsed.
+ Mostly we process the processor
+ type and sometimes adjust other TARGET_ options. */
+void
+c4x_override_options (void)
+{
/* Convert foo / 8.0 into foo * 0.125, etc. */
set_fast_math_flags (1);
This provides compatibility with the old -mno-aliases option. */
if (! TARGET_ALIASES && ! flag_argument_noalias)
flag_argument_noalias = 1;
+
+ if (!TARGET_C3X)
+ target_flags |= MASK_MPYI | MASK_DB;
+
+ if (optimize < 2)
+ target_flags &= ~(MASK_RPTB | MASK_PARALLEL);
+
+ if (!TARGET_PARALLEL)
+ target_flags &= ~MASK_PARALLEL_MPY;
}
if (indirect)
type = build_pointer_type (type);
- t = build (PREDECREMENT_EXPR, TREE_TYPE (valist), valist,
- build_int_cst (NULL_TREE, int_size_in_bytes (type), 0));
+ t = build2 (PREDECREMENT_EXPR, TREE_TYPE (valist), valist,
+ build_int_cst (NULL_TREE, int_size_in_bytes (type)));
t = fold_convert (build_pointer_type (type), t);
- t = build_fold_indirect_ref (t);
+ t = build_va_arg_indirect_ref (t);
if (indirect)
- t = build_fold_indirect_ref (t);
+ t = build_va_arg_indirect_ref (t);
return t;
}
/* Return nonzero if the floating point operand will fit
in the immediate field. */
-static int
+int
c4x_immed_float_p (rtx op)
{
long convval[2];
}
-static int
+int
c4x_a_register (rtx op)
{
return REG_P (op) && IS_ADDR_OR_PSEUDO_REG (op);
}
-static int
+int
c4x_x_register (rtx op)
{
return REG_P (op) && IS_INDEX_OR_PSEUDO_REG (op);
}
-static int
+int
c4x_K_constant (rtx op)
{
if (TARGET_C3X || ! c4x_immed_int_constant (op))
}
-static int
+int
c4x_N_constant (rtx op)
{
return c4x_immed_int_constant (op) && IS_NOT_UINT16_CONST (INTVAL (op));
}
-static int
+int
c4x_O_constant (rtx op)
{
return c4x_immed_int_constant (op) && IS_HIGH_CONST (INTVAL (op));
}
-static int
+int
c4x_S_indirect (rtx op)
{
enum machine_mode mode = GET_MODE (op);
}
-/* Match any operand. */
-
-int
-any_operand (register rtx op ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return 1;
-}
-
-
-/* Nonzero if OP is a floating point value with value 0.0. */
-
-int
-fp_zero_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- REAL_VALUE_TYPE r;
-
- if (GET_CODE (op) != CONST_DOUBLE)
- return 0;
- REAL_VALUE_FROM_CONST_DOUBLE (r, op);
- return REAL_VALUES_EQUAL (r, dconst0);
-}
-
-
-int
-const_operand (register rtx op, register enum machine_mode mode)
-{
- switch (mode)
- {
- case QFmode:
- case HFmode:
- if (GET_CODE (op) != CONST_DOUBLE
- || GET_MODE (op) != mode
- || GET_MODE_CLASS (mode) != MODE_FLOAT)
- return 0;
-
- return c4x_immed_float_p (op);
-
-#if Pmode != QImode
- case Pmode:
-#endif
- case QImode:
- if (GET_CODE (op) != CONST_INT
- || (GET_MODE (op) != VOIDmode && GET_MODE (op) != mode)
- || GET_MODE_CLASS (mode) != MODE_INT)
- return 0;
-
- return IS_HIGH_CONST (INTVAL (op)) || IS_INT16_CONST (INTVAL (op));
-
- case HImode:
- return 0;
-
- default:
- return 0;
- }
-}
-
-
-int
-stik_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return c4x_K_constant (op);
-}
-
-
-int
-not_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return c4x_N_constant (op);
-}
-
-
-int
-reg_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == SUBREG
- && GET_MODE (op) == QFmode)
- return 0;
- return register_operand (op, mode);
-}
-
-
int
mixed_subreg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
}
-/* Extended precision register R0-R1. */
-
-int
-r0r1_reg_operand (rtx op, enum machine_mode mode)
-{
- if (! reg_operand (op, mode))
- return 0;
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
- return REG_P (op) && IS_R0R1_OR_PSEUDO_REG (op);
-}
-
-
-/* Extended precision register R2-R3. */
-
-int
-r2r3_reg_operand (rtx op, enum machine_mode mode)
-{
- if (! reg_operand (op, mode))
- return 0;
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
- return REG_P (op) && IS_R2R3_OR_PSEUDO_REG (op);
-}
-
-
-/* Low extended precision register R0-R7. */
-
-int
-ext_low_reg_operand (rtx op, enum machine_mode mode)
-{
- if (! reg_operand (op, mode))
- return 0;
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
- return REG_P (op) && IS_EXT_LOW_OR_PSEUDO_REG (op);
-}
-
-
-/* Extended precision register. */
-
-int
-ext_reg_operand (rtx op, enum machine_mode mode)
-{
- if (! reg_operand (op, mode))
- return 0;
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
- if (! REG_P (op))
- return 0;
- return IS_EXT_OR_PSEUDO_REG (op);
-}
-
-
-/* Standard precision register. */
-
-int
-std_reg_operand (rtx op, enum machine_mode mode)
-{
- if (! reg_operand (op, mode))
- return 0;
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
- return REG_P (op) && IS_STD_OR_PSEUDO_REG (op);
-}
-
-/* Standard precision or normal register. */
-
-int
-std_or_reg_operand (rtx op, enum machine_mode mode)
-{
- if (reload_in_progress)
- return std_reg_operand (op, mode);
- return reg_operand (op, mode);
-}
-
-/* Address register. */
-
-int
-addr_reg_operand (rtx op, enum machine_mode mode)
-{
- if (! reg_operand (op, mode))
- return 0;
- return c4x_a_register (op);
-}
-
-
-/* Index register. */
-
-int
-index_reg_operand (rtx op, enum machine_mode mode)
-{
- if (! reg_operand (op, mode))
- return 0;
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
- return c4x_x_register (op);
-}
-
-
-/* DP register. */
-
-int
-dp_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return REG_P (op) && IS_DP_OR_PSEUDO_REG (op);
-}
-
-
-/* SP register. */
-
-int
-sp_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return REG_P (op) && IS_SP_OR_PSEUDO_REG (op);
-}
-
-
-/* ST register. */
-
-int
-st_reg_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return REG_P (op) && IS_ST_OR_PSEUDO_REG (op);
-}
-
-
-/* RC register. */
-
-int
-rc_reg_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return REG_P (op) && IS_RC_OR_PSEUDO_REG (op);
-}
-
-
-int
-call_address_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return (REG_P (op) || symbolic_address_operand (op, mode));
-}
-
-
-/* Symbolic address operand. */
-
-int
-symbolic_address_operand (register rtx op,
- enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- switch (GET_CODE (op))
- {
- case CONST:
- case SYMBOL_REF:
- case LABEL_REF:
- return 1;
- default:
- return 0;
- }
-}
-
-
-/* Check dst operand of a move instruction. */
-
-int
-dst_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == SUBREG
- && mixed_subreg_operand (op, mode))
- return 0;
-
- if (REG_P (op))
- return reg_operand (op, mode);
-
- return nonimmediate_operand (op, mode);
-}
-
-
-/* Check src operand of two operand arithmetic instructions. */
-
-int
-src_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == SUBREG
- && mixed_subreg_operand (op, mode))
- return 0;
-
- if (REG_P (op))
- return reg_operand (op, mode);
-
- if (mode == VOIDmode)
- mode = GET_MODE (op);
-
- if (GET_CODE (op) == CONST_INT)
- return (mode == QImode || mode == Pmode || mode == HImode)
- && c4x_I_constant (op);
-
- /* We don't like CONST_DOUBLE integers. */
- if (GET_CODE (op) == CONST_DOUBLE)
- return c4x_H_constant (op);
-
- /* Disallow symbolic addresses. Only the predicate
- symbolic_address_operand will match these. */
- if (GET_CODE (op) == SYMBOL_REF
- || GET_CODE (op) == LABEL_REF
- || GET_CODE (op) == CONST)
- return 0;
-
- /* If TARGET_LOAD_DIRECT_MEMS is nonzero, disallow direct memory
- access to symbolic addresses. These operands will get forced
- into a register and the movqi expander will generate a
- HIGH/LO_SUM pair if TARGET_EXPOSE_LDP is nonzero. */
- if (GET_CODE (op) == MEM
- && ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
- || GET_CODE (XEXP (op, 0)) == LABEL_REF
- || GET_CODE (XEXP (op, 0)) == CONST)))
- return !TARGET_EXPOSE_LDP &&
- ! TARGET_LOAD_DIRECT_MEMS && GET_MODE (op) == mode;
-
- return general_operand (op, mode);
-}
-
-
-int
-src_hi_operand (rtx op, enum machine_mode mode)
-{
- if (c4x_O_constant (op))
- return 1;
- return src_operand (op, mode);
-}
-
-
-/* Check src operand of two operand logical instructions. */
-
-int
-lsrc_operand (rtx op, enum machine_mode mode)
-{
- if (mode == VOIDmode)
- mode = GET_MODE (op);
-
- if (mode != QImode && mode != Pmode)
- fatal_insn ("mode not QImode", op);
-
- if (GET_CODE (op) == CONST_INT)
- return c4x_L_constant (op) || c4x_J_constant (op);
-
- return src_operand (op, mode);
-}
-
-
-/* Check src operand of two operand tricky instructions. */
-
-int
-tsrc_operand (rtx op, enum machine_mode mode)
-{
- if (mode == VOIDmode)
- mode = GET_MODE (op);
-
- if (mode != QImode && mode != Pmode)
- fatal_insn ("mode not QImode", op);
-
- if (GET_CODE (op) == CONST_INT)
- return c4x_L_constant (op) || c4x_N_constant (op) || c4x_J_constant (op);
-
- return src_operand (op, mode);
-}
-
-
-/* Check src operand of two operand non immedidate instructions. */
-
-int
-nonimmediate_src_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE)
- return 0;
-
- return src_operand (op, mode);
-}
-
-
-/* Check logical src operand of two operand non immedidate instructions. */
-
-int
-nonimmediate_lsrc_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE)
- return 0;
-
- return lsrc_operand (op, mode);
-}
-
-
-int
-reg_or_const_operand (rtx op, enum machine_mode mode)
-{
- return reg_operand (op, mode) || const_operand (op, mode);
-}
-
-
-/* Check for indirect operands allowable in parallel instruction. */
-
-int
-par_ind_operand (rtx op, enum machine_mode mode)
-{
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
-
- return c4x_S_indirect (op);
-}
-
-
-/* Check for operands allowable in parallel instruction. */
-
-int
-parallel_operand (rtx op, enum machine_mode mode)
-{
- return ext_low_reg_operand (op, mode) || par_ind_operand (op, mode);
-}
-
-
static void
c4x_S_address_parse (rtx op, int *base, int *incdec, int *index, int *disp)
{
static void
c4x_file_start (void)
{
- int dspversion = 0;
- if (TARGET_C30) dspversion = 30;
- if (TARGET_C31) dspversion = 31;
- if (TARGET_C32) dspversion = 32;
- if (TARGET_C33) dspversion = 33;
- if (TARGET_C40) dspversion = 40;
- if (TARGET_C44) dspversion = 44;
-
default_file_start ();
- fprintf (asm_out_file, "\t.version\t%d\n", dspversion);
+ fprintf (asm_out_file, "\t.version\t%d\n", c4x_cpu_version);
fputs ("\n\t.data\ndata_sec:\n", asm_out_file);
}
{
if (TREE_CODE (*node) != FUNCTION_TYPE)
{
- warning ("`%s' attribute only applies to functions",
+ warning (OPT_Wattributes, "%qs attribute only applies to functions",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
where they are and print a warning. We should
probably move these insns before the repeat block insn. */
if (TARGET_DEBUG)
- fatal_insn("c4x_rptb_rpts_p: Repeat block top label moved\n",
- insn);
+ fatal_insn ("c4x_rptb_rpts_p: Repeat block top label moved",
+ insn);
return 0;
}
}
static void
-c4x_asm_named_section (const char *name, unsigned int flags ATTRIBUTE_UNUSED)
+c4x_asm_named_section (const char *name, unsigned int flags ATTRIBUTE_UNUSED,
+ tree decl ATTRIBUTE_UNUSED)
{
fprintf (asm_out_file, "\t.sect\t\"%s\"\n", name);
}