📄 c4x.c
字号:
/* 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 "tm_p.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. */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 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 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));static void c4x_encode_section_info PARAMS ((tree, int));static void c4x_globalize_label PARAMS ((FILE *, const char *));/* 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_cost#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO c4x_encode_section_info#undef TARGET_ASM_GLOBALIZE_LABEL#define TARGET_ASM_GLOBALIZE_LABEL c4x_globalize_labelstruct gcc_target targetm = TARGET_INITIALIZER;/* 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 (1); /* 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; /* We're C4X floating point, not IEEE floating point. */ memset (real_format_for_mode, 0, sizeof real_format_for_mode); real_format_for_mode[QFmode - QFmode] = &c4x_single_format; real_format_for_mode[HFmode - QFmode] = &c4x_extended_format;}/* 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 nonzero 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)) return 0; return 1;}/* The TI C3x C compiler register argument runtime model uses 6 registers, AR2, R2, R3, RC, RS, RE. The first two floating point arguments (float, double, long double) that are found scanning from left to right are assigned to R2 and R3. The remaining integer (char, short, int, long) or pointer arguments are assigned to the remaining registers in the order AR2, R2, R3, RC, RS, RE when scanning left to right, except for the last named argument prior to an ellipsis denoting variable number of arguments. We don't have to worry about the latter condition since function.c treats the last named argument as anonymous (unnamed). All arguments that cannot be passed in registers are pushed onto
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -