c4x.c
来自「gcc3.2.1源代码」· C语言 代码 · 共 2,390 行 · 第 1/5 页
C
2,390 行
/* Subroutines for assembler code output on the TMS320C[34]x Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz) and Herman Ten Brugge (Haj.Ten.Brugge@net.HCC.nl).This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. *//* Some output-actions in c4x.md need these. */#include "config.h"#include "system.h"#include "rtl.h"#include "tree.h"#include "regs.h"#include "hard-reg-set.h"#include "basic-block.h"#include "real.h"#include "insn-config.h"#include "insn-attr.h"#include "conditions.h"#include "output.h"#include "function.h"#include "expr.h"#include "optabs.h"#include "libfuncs.h"#include "flags.h"#include "loop.h"#include "recog.h"#include "c-tree.h"#include "ggc.h"#include "cpplib.h"#include "toplev.h"#include "c4x-protos.h"#include "target.h"#include "target-def.h"rtx smulhi3_libfunc;rtx umulhi3_libfunc;rtx fix_truncqfhi2_libfunc;rtx fixuns_truncqfhi2_libfunc;rtx fix_trunchfhi2_libfunc;rtx fixuns_trunchfhi2_libfunc;rtx floathiqf2_libfunc;rtx floatunshiqf2_libfunc;rtx floathihf2_libfunc;rtx floatunshihf2_libfunc;static int c4x_leaf_function;static const char *const float_reg_names[] = FLOAT_REGISTER_NAMES;/* Array of the smallest class containing reg number REGNO, indexed by REGNO. Used by REGNO_REG_CLASS in c4x.h. We assume that all these registers are available and set the class to NO_REGS for registers that the target switches say are unavailable. */enum reg_class c4x_regclass_map[FIRST_PSEUDO_REGISTER] ={ /* Reg Modes Saved. */ R0R1_REGS, /* R0 QI, QF, HF No. */ R0R1_REGS, /* R1 QI, QF, HF No. */ R2R3_REGS, /* R2 QI, QF, HF No. */ R2R3_REGS, /* R3 QI, QF, HF No. */ EXT_LOW_REGS, /* R4 QI, QF, HF QI. */ EXT_LOW_REGS, /* R5 QI, QF, HF QI. */ EXT_LOW_REGS, /* R6 QI, QF, HF QF. */ EXT_LOW_REGS, /* R7 QI, QF, HF QF. */ ADDR_REGS, /* AR0 QI No. */ ADDR_REGS, /* AR1 QI No. */ ADDR_REGS, /* AR2 QI No. */ ADDR_REGS, /* AR3 QI QI. */ ADDR_REGS, /* AR4 QI QI. */ ADDR_REGS, /* AR5 QI QI. */ ADDR_REGS, /* AR6 QI QI. */ ADDR_REGS, /* AR7 QI QI. */ DP_REG, /* DP QI No. */ INDEX_REGS, /* IR0 QI No. */ INDEX_REGS, /* IR1 QI No. */ BK_REG, /* BK QI QI. */ SP_REG, /* SP QI No. */ ST_REG, /* ST CC No. */ NO_REGS, /* DIE/IE No. */ NO_REGS, /* IIE/IF No. */ NO_REGS, /* IIF/IOF No. */ INT_REGS, /* RS QI No. */ INT_REGS, /* RE QI No. */ RC_REG, /* RC QI No. */ EXT_REGS, /* R8 QI, QF, HF QI. */ EXT_REGS, /* R9 QI, QF, HF No. */ EXT_REGS, /* R10 QI, QF, HF No. */ EXT_REGS, /* R11 QI, QF, HF No. */};enum machine_mode c4x_caller_save_map[FIRST_PSEUDO_REGISTER] ={ /* Reg Modes Saved. */ HFmode, /* R0 QI, QF, HF No. */ HFmode, /* R1 QI, QF, HF No. */ HFmode, /* R2 QI, QF, HF No. */ HFmode, /* R3 QI, QF, HF No. */ QFmode, /* R4 QI, QF, HF QI. */ QFmode, /* R5 QI, QF, HF QI. */ QImode, /* R6 QI, QF, HF QF. */ QImode, /* R7 QI, QF, HF QF. */ QImode, /* AR0 QI No. */ QImode, /* AR1 QI No. */ QImode, /* AR2 QI No. */ QImode, /* AR3 QI QI. */ QImode, /* AR4 QI QI. */ QImode, /* AR5 QI QI. */ QImode, /* AR6 QI QI. */ QImode, /* AR7 QI QI. */ VOIDmode, /* DP QI No. */ QImode, /* IR0 QI No. */ QImode, /* IR1 QI No. */ QImode, /* BK QI QI. */ VOIDmode, /* SP QI No. */ VOIDmode, /* ST CC No. */ VOIDmode, /* DIE/IE No. */ VOIDmode, /* IIE/IF No. */ VOIDmode, /* IIF/IOF No. */ QImode, /* RS QI No. */ QImode, /* RE QI No. */ VOIDmode, /* RC QI No. */ QFmode, /* R8 QI, QF, HF QI. */ HFmode, /* R9 QI, QF, HF No. */ HFmode, /* R10 QI, QF, HF No. */ HFmode, /* R11 QI, QF, HF No. */};/* Test and compare insns in c4x.md store the information needed to generate branch and scc insns here. */struct rtx_def *c4x_compare_op0 = NULL_RTX;struct rtx_def *c4x_compare_op1 = NULL_RTX;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 code_tree = NULL_TREE;tree data_tree = NULL_TREE;tree pure_tree = NULL_TREE;tree noreturn_tree = NULL_TREE;tree interrupt_tree = NULL_TREE;/* Forward declarations */static void c4x_add_gc_roots PARAMS ((void));static int c4x_isr_reg_used_p PARAMS ((unsigned int));static int c4x_leaf_function_p PARAMS ((void));static int c4x_assembler_function_p PARAMS ((void));static int c4x_immed_float_p PARAMS ((rtx));static int c4x_a_register PARAMS ((rtx));static int c4x_x_register PARAMS ((rtx));static int c4x_immed_int_constant PARAMS ((rtx));static int c4x_immed_float_constant PARAMS ((rtx));static int c4x_K_constant PARAMS ((rtx));static int c4x_N_constant PARAMS ((rtx));static int c4x_O_constant PARAMS ((rtx));static int c4x_R_indirect PARAMS ((rtx));static int c4x_S_indirect PARAMS ((rtx));static void c4x_S_address_parse PARAMS ((rtx , int *, int *, int *, int *));static int c4x_valid_operands PARAMS ((enum rtx_code, rtx *, enum machine_mode, int));static int c4x_arn_reg_operand PARAMS ((rtx, enum machine_mode, unsigned int));static int c4x_arn_mem_operand PARAMS ((rtx, enum machine_mode, unsigned int));static void c4x_check_attribute PARAMS ((const char *, tree, tree, tree *));static int c4x_r11_set_p PARAMS ((rtx));static int c4x_rptb_valid_p PARAMS ((rtx, rtx));static int c4x_label_ref_used_p PARAMS ((rtx, rtx));static tree c4x_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));const struct attribute_spec c4x_attribute_table[];static void c4x_insert_attributes PARAMS ((tree, tree *));static void c4x_asm_named_section PARAMS ((const char *, unsigned int));static int c4x_adjust_cost PARAMS ((rtx, rtx, rtx, int));/* Initialize the GCC target structure. */#undef TARGET_ASM_BYTE_OP#define TARGET_ASM_BYTE_OP "\t.word\t"#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP NULL#undef TARGET_ASM_ALIGNED_SI_OP#define TARGET_ASM_ALIGNED_SI_OP NULL#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE c4x_attribute_table#undef TARGET_INSERT_ATTRIBUTES#define TARGET_INSERT_ATTRIBUTES c4x_insert_attributes#undef TARGET_INIT_BUILTINS#define TARGET_INIT_BUILTINS c4x_init_builtins#undef TARGET_EXPAND_BUILTIN#define TARGET_EXPAND_BUILTIN c4x_expand_builtin#undef TARGET_SCHED_ADJUST_COST#define TARGET_SCHED_ADJUST_COST c4x_adjust_coststruct gcc_target targetm = TARGET_INITIALIZER;/* Called to register all of our global variables with the garbage collector. */static voidc4x_add_gc_roots (){ ggc_add_rtx_root (&c4x_compare_op0, 1); ggc_add_rtx_root (&c4x_compare_op1, 1); ggc_add_tree_root (&code_tree, 1); ggc_add_tree_root (&data_tree, 1); ggc_add_tree_root (&pure_tree, 1); ggc_add_tree_root (&noreturn_tree, 1); ggc_add_tree_root (&interrupt_tree, 1); ggc_add_rtx_root (&smulhi3_libfunc, 1); ggc_add_rtx_root (&umulhi3_libfunc, 1); ggc_add_rtx_root (&fix_truncqfhi2_libfunc, 1); ggc_add_rtx_root (&fixuns_truncqfhi2_libfunc, 1); ggc_add_rtx_root (&fix_trunchfhi2_libfunc, 1); ggc_add_rtx_root (&fixuns_trunchfhi2_libfunc, 1); ggc_add_rtx_root (&floathiqf2_libfunc, 1); ggc_add_rtx_root (&floatunshiqf2_libfunc, 1); ggc_add_rtx_root (&floathihf2_libfunc, 1); ggc_add_rtx_root (&floatunshihf2_libfunc, 1);}/* Override command line options. Called once after all options have been parsed. Mostly we process the processor type and sometimes adjust other TARGET_ options. */voidc4x_override_options (){ 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) { 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); 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; } if (TARGET_C30 || TARGET_C31 || TARGET_C32 || TARGET_C33) target_flags |= C3X_FLAG; else target_flags &= ~C3X_FLAG; /* Convert foo / 8.0 into foo * 0.125, etc. */ set_fast_math_flags(); /* We should phase out the following at some stage. This provides compatibility with the old -mno-aliases option. */ if (! TARGET_ALIASES && ! flag_argument_noalias) flag_argument_noalias = 1; /* Register global variables with the garbage collector. */ c4x_add_gc_roots ();}/* This is called before c4x_override_options. */voidc4x_optimization_options (level, size) int level ATTRIBUTE_UNUSED; int size ATTRIBUTE_UNUSED;{ /* Scheduling before register allocation can screw up global register allocation, especially for functions that use MPY||ADD instructions. The benefit we gain we get by scheduling before register allocation is probably marginal anyhow. */ flag_schedule_insns = 0;}/* Write an ASCII string. */#define C4X_ASCII_LIMIT 40voidc4x_output_ascii (stream, ptr, len) FILE *stream; const char *ptr; int len;{ char sbuf[C4X_ASCII_LIMIT + 1]; int s, l, special, first = 1, onlys; if (len) fprintf (stream, "\t.byte\t"); for (s = l = 0; len > 0; --len, ++ptr) { onlys = 0; /* Escape " and \ with a \". */ special = *ptr == '\"' || *ptr == '\\'; /* If printable - add to buff. */ if ((! TARGET_TI || ! special) && *ptr >= 0x20 && *ptr < 0x7f) { if (special) sbuf[s++] = '\\'; sbuf[s++] = *ptr; if (s < C4X_ASCII_LIMIT - 1) continue; onlys = 1; } if (s) { if (first) first = 0; else { fputc (',', stream); l++; } sbuf[s] = 0; fprintf (stream, "\"%s\"", sbuf); l += s + 2; if (TARGET_TI && l >= 80 && len > 1) { fprintf (stream, "\n\t.byte\t"); first = 1; l = 0; } s = 0; } if (onlys) continue; if (first) first = 0; else { fputc (',', stream); l++; } fprintf (stream, "%d", *ptr); l += 3; if (TARGET_TI && l >= 80 && len > 1) { fprintf (stream, "\n\t.byte\t"); first = 1; l = 0; } } if (s) { if (! first) fputc (',', stream); sbuf[s] = 0; fprintf (stream, "\"%s\"", sbuf); s = 0; } fputc ('\n', stream);}intc4x_hard_regno_mode_ok (regno, mode) unsigned int regno; enum machine_mode mode;{ switch (mode) {#if Pmode != QImode case Pmode: /* Pointer (24/32 bits). */#endif case QImode: /* Integer (32 bits). */ return IS_INT_REGNO (regno); case QFmode: /* Float, Double (32 bits). */ case HFmode: /* Long Double (40 bits). */ return IS_EXT_REGNO (regno); case CCmode: /* Condition Codes. */ case CC_NOOVmode: /* Condition Codes. */ return IS_ST_REGNO (regno); case HImode: /* Long Long (64 bits). */ /* We need two registers to store long longs. Note that it is much easier to constrain the first register to start on an even boundary. */ return IS_INT_REGNO (regno) && IS_INT_REGNO (regno + 1) && (regno & 1) == 0; default: return 0; /* We don't support these modes. */ } return 0;}/* Return non-zero if REGNO1 can be renamed to REGNO2. */intc4x_hard_regno_rename_ok (regno1, regno2) unsigned int regno1; unsigned int regno2;{ /* We can not copy call saved registers from mode QI into QF or from mode QF into QI. */ if (IS_FLOAT_CALL_SAVED_REGNO (regno1) && IS_INT_CALL_SAVED_REGNO (regno2)) return 0; if (IS_INT_CALL_SAVED_REGNO (regno1) && IS_FLOAT_CALL_SAVED_REGNO (regno2)) return 0; /* We cannot copy from an extended (40 bit) register to a standard (32 bit) register because we only set the condition codes for extended registers. */ if (IS_EXT_REGNO (regno1) && ! IS_EXT_REGNO (regno2)) return 0; if (IS_EXT_REGNO (regno2) && ! IS_EXT_REGNO (regno1))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?