📄 dsp16xx.c
字号:
/* Subroutines for assembler code output on the DSP1610. Copyright (C) 1994, 1995, 1997, 1998, 2001 Free Software Foundation, Inc. Contributed by Michael Collison (collison@isisinc.net).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 dsp1600.md need these. */#include "config.h"#include "system.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "output.h"#include "insn-attr.h"#include "tree.h"#include "expr.h"#include "function.h"#include "flags.h"#include "ggc.h"#include "toplev.h"#include "recog.h"#include "tm_p.h"#include "target.h"#include "target-def.h"const char *text_seg_name;const char *rsect_text;const char *data_seg_name;const char *rsect_data;const char *bss_seg_name;const char *rsect_bss;const char *const_seg_name;const char *rsect_const;const char *chip_name;const char *save_chip_name;/* Save the operands of a compare. The 16xx has not lt or gt, so in these cases we swap the operands and reverse the condition. */rtx dsp16xx_compare_op0;rtx dsp16xx_compare_op1;rtx (*dsp16xx_compare_gen) PARAMS (());static const char *fp;static const char *sp;static const char *rr;static const char *a1h;struct dsp16xx_frame_info current_frame_info;struct dsp16xx_frame_info zero_frame_info;rtx dsp16xx_addhf3_libcall = (rtx) 0;rtx dsp16xx_subhf3_libcall = (rtx) 0;rtx dsp16xx_mulhf3_libcall = (rtx) 0;rtx dsp16xx_divhf3_libcall = (rtx) 0;rtx dsp16xx_cmphf3_libcall = (rtx) 0;rtx dsp16xx_fixhfhi2_libcall = (rtx) 0;rtx dsp16xx_floathihf2_libcall = (rtx) 0;rtx dsp16xx_neghf2_libcall = (rtx) 0;rtx dsp16xx_mulhi3_libcall = (rtx) 0;rtx dsp16xx_udivqi3_libcall = (rtx) 0;rtx dsp16xx_udivhi3_libcall = (rtx) 0;rtx dsp16xx_divqi3_libcall = (rtx) 0;rtx dsp16xx_divhi3_libcall = (rtx) 0;rtx dsp16xx_modqi3_libcall = (rtx) 0;rtx dsp16xx_modhi3_libcall = (rtx) 0;rtx dsp16xx_umodqi3_libcall = (rtx) 0;rtx dsp16xx_umodhi3_libcall = (rtx) 0;rtx dsp16xx_ashrhi3_libcall = (rtx) 0;rtx dsp16xx_ashlhi3_libcall = (rtx) 0;rtx dsp16xx_ucmphi2_libcall = (rtx) 0;rtx dsp16xx_lshrhi3_libcall = (rtx) 0;static const char *const himode_reg_name[] = HIMODE_REGISTER_NAMES;#define SHIFT_INDEX_1 0#define SHIFT_INDEX_4 1#define SHIFT_INDEX_8 2#define SHIFT_INDEX_16 3static const char *const ashift_right_asm[] = { "%0=%0>>1", "%0=%0>>4", "%0=%0>>8", "%0=%0>>16"};static const char *const ashift_right_asm_first[] = { "%0=%1>>1", "%0=%1>>4", "%0=%1>>8", "%0=%1>>16"};static const char *const ashift_left_asm[] = { "%0=%0<<1", "%0=%0<<4", "%0=%0<<8", "%0=%0<<16"};static const char *const ashift_left_asm_first[] = { "%0=%1<<1", "%0=%1<<4", "%0=%1<<8", "%0=%1<<16"};static const char *const lshift_right_asm[] = { "%0=%0>>1\n\t%0=%b0&0x7fff", "%0=%0>>4\n\t%0=%b0&0x0fff", "%0=%0>>8\n\t%0=%b0&0x00ff", "%0=%0>>16\n\t%0=%b0&0x0000"};static const char *const lshift_right_asm_first[] = { "%0=%1>>1\n\t%0=%b0&0x7fff", "%0=%1>>4\n\t%0=%b0&0x0fff", "%0=%1>>8\n\t%0=%b0&0x00ff", "%0=%1>>16\n\t%0=%b0&0x0000"};static int reg_save_size PARAMS ((void));static void dsp16xx_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void dsp16xx_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));/* Initialize the GCC target structure. */#undef TARGET_ASM_BYTE_OP#define TARGET_ASM_BYTE_OP "\tint\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_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE dsp16xx_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE dsp16xx_output_function_epiloguestruct gcc_target targetm = TARGET_INITIALIZER;int hard_regno_mode_ok (regno, mode) int regno; enum machine_mode mode;{ switch ((int) mode) { case VOIDmode: return 1; /* We can't use the c0-c2 for QImode, since they are only 8 bits in length. */ case QImode: if (regno != REG_C0 && regno != REG_C1 && regno != REG_C2) return 1; else return 0; /* We only allow a0, a1, y, and p to be allocated for 32-bit modes. Additionally we allow the virtual ybase registers to be used for 32-bit modes. */ case HFmode: case SFmode: case DFmode: case XFmode: case HImode: case SImode: case DImode: if (regno == REG_A0 || regno == REG_A1 || regno == REG_Y || regno == REG_PROD || (IS_YBASE_REGISTER_WINDOW(regno) && ((regno & 1) == 0))) return 1; else return 0; default: return 0; }}enum reg_classdsp16xx_reg_class_from_letter (c) int c;{ switch (c) { case 'A': return ACCUM_REGS; case 'l': return A0_REG; case 'C': return A1_REG; case 'h': return ACCUM_HIGH_REGS; case 'j': return A0H_REG; case 'k': return A0L_REG; case 'q': return A1H_REG; case 'u': return A1L_REG; case 'x': return X_REG; case 'y': return YH_REG; case 'z': return YL_REG; case 't': return P_REG; case 'Z': return Y_OR_P_REGS; case 'd': return ACCUM_Y_OR_P_REGS; case 'a': return Y_ADDR_REGS; case 'B': return (TARGET_BMU ? BMU_REGS : NO_REGS); case 'Y': return YBASE_VIRT_REGS; case 'v': return PH_REG; case 'w': return PL_REG; case 'W': return J_REG; case 'e': return YBASE_ELIGIBLE_REGS; case 'b': return ACCUM_LOW_REGS; case 'c': return NON_YBASE_REGS; case 'f': return Y_REG; case 'D': return SLOW_MEM_LOAD_REGS; default: return NO_REGS; }}/* Return the class number of the smallest class containing reg number REGNO. */int regno_reg_class(regno) int regno;{ switch (regno) { case REG_A0L: return (int) A0L_REG; case REG_A1L: return (int) A1L_REG; case REG_A0: return (int) A0H_REG; case REG_A1: return (int) A1H_REG; case REG_X: return (int) X_REG; case REG_Y: return (int) YH_REG; case REG_YL: return (int) YL_REG; case REG_PROD: return (int) PH_REG; case REG_PRODL: return (int) PL_REG; case REG_R0: case REG_R1: case REG_R2: case REG_R3: return (int) Y_ADDR_REGS; case REG_J: return (int) J_REG; case REG_K: return (int) GENERAL_REGS; case REG_YBASE: return (int) GENERAL_REGS; case REG_PT: return (int) GENERAL_REGS; case REG_AR0: case REG_AR1: case REG_AR2: case REG_AR3: return (int) BMU_REGS; case REG_C0: case REG_C1: case REG_C2: return (int) GENERAL_REGS; case REG_PR: return (int) GENERAL_REGS; case REG_RB: return (int) GENERAL_REGS; case REG_YBASE0: case REG_YBASE1: case REG_YBASE2: case REG_YBASE3: case REG_YBASE4: case REG_YBASE5: case REG_YBASE6: case REG_YBASE7: case REG_YBASE8: case REG_YBASE9: case REG_YBASE10: case REG_YBASE11: case REG_YBASE12: case REG_YBASE13: case REG_YBASE14: case REG_YBASE15: case REG_YBASE16: case REG_YBASE17: case REG_YBASE18: case REG_YBASE19: case REG_YBASE20: case REG_YBASE21: case REG_YBASE22: case REG_YBASE23: case REG_YBASE24: case REG_YBASE25: case REG_YBASE26: case REG_YBASE27: case REG_YBASE28: case REG_YBASE29: case REG_YBASE30: case REG_YBASE31: return (int) YBASE_VIRT_REGS; default: return (int) NO_REGS; }}/* A C expression for the maximum number of consecutive registers of class CLASS needed to hold a value of mode MODE. */intclass_max_nregs(class, mode) enum reg_class class ATTRIBUTE_UNUSED; enum machine_mode mode;{ return (GET_MODE_SIZE(mode));}enum reg_classlimit_reload_class (mode, class) enum machine_mode mode ATTRIBUTE_UNUSED; enum reg_class class;{ return class;}intdsp16xx_register_move_cost (from, to) enum reg_class from, to;{ if (from == A0H_REG || from == A0L_REG || from == A0_REG || from == A1H_REG || from == ACCUM_HIGH_REGS || from == A1L_REG || from == ACCUM_LOW_REGS || from == A1_REG || from == ACCUM_REGS) { if (to == Y_REG || to == P_REG) return 4; else return 2; } if (to == A0H_REG || to == A0L_REG || to == A0_REG || to == A1H_REG || to == ACCUM_HIGH_REGS || to == A1L_REG || to == ACCUM_LOW_REGS || to == A1_REG || to == ACCUM_REGS) { return 2; } if (from == YBASE_VIRT_REGS) { if (to == YBASE_VIRT_REGS) return 16; if (to == X_REG || to == YH_REG || to == YL_REG || to == Y_REG || to == PL_REG || to == PH_REG || to == P_REG || to == Y_ADDR_REGS || to == YBASE_ELIGIBLE_REGS || to == Y_OR_P_REGS) { return 8; } else return 10; } if (to == YBASE_VIRT_REGS) { if (from == X_REG || from == YH_REG || from == YL_REG || from == Y_REG || from == PL_REG || from == PH_REG || from == P_REG || from == Y_ADDR_REGS || from == YBASE_ELIGIBLE_REGS || from == Y_OR_P_REGS) { return 8; } else return 10; } return 8;}/* Given an rtx X being reloaded into a reg required to be in class CLASS, return the class of reg to actually use. In general this is just CLASS; but on some machines in some cases it is preferable to use a more restrictive class. Also, we must ensure that a PLUS is reloaded either into an accumulator or an address register. */enum reg_classpreferred_reload_class (x, class) rtx x; enum reg_class class;{ /* The ybase registers cannot have constants copied directly to them. */ if (CONSTANT_P (x)) { switch ((int) class) { case YBASE_VIRT_REGS: return (!reload_in_progress ? NO_REGS : class); case ACCUM_LOW_OR_YBASE_REGS: return ACCUM_LOW_REGS; case ACCUM_OR_YBASE_REGS: return ACCUM_REGS; case X_OR_YBASE_REGS: return X_REG; case Y_OR_YBASE_REGS: return Y_REG; case ACCUM_LOW_YL_PL_OR_YBASE_REGS: return YL_OR_PL_OR_ACCUM_LOW_REGS; case P_OR_YBASE_REGS: return P_REG; case ACCUM_Y_P_OR_YBASE_REGS: return ACCUM_Y_OR_P_REGS; case Y_ADDR_OR_YBASE_REGS: return Y_ADDR_REGS; case YBASE_OR_NOHIGH_YBASE_ELIGIBLE_REGS: return NON_HIGH_YBASE_ELIGIBLE_REGS;; case YBASE_OR_YBASE_ELIGIBLE_REGS: return YBASE_ELIGIBLE_REGS; case NO_HIGH_ALL_REGS: return NOHIGH_NON_YBASE_REGS; case ALL_REGS: return NON_YBASE_REGS; default: return class; } } /* If x is not an accumulator or a ybase register, restrict the class of registers we can copy the register into. */ if (REG_P (x) && !IS_ACCUM_REG (REGNO (x)) && !IS_YBASE_REGISTER_WINDOW (REGNO (x))) { switch ((int) class) { case NO_REGS: case A0H_REG: case A0L_REG: case A0_REG: case A1H_REG: case ACCUM_HIGH_REGS: case A1L_REG: case ACCUM_LOW_REGS: case A1_REG: case ACCUM_REGS: return class; case X_REG: return (!reload_in_progress ? NO_REGS : class); case X_OR_ACCUM_LOW_REGS: return ACCUM_LOW_REGS; case X_OR_ACCUM_REGS: return ACCUM_REGS; case YH_REG: return (!reload_in_progress ? NO_REGS : class); case YH_OR_ACCUM_HIGH_REGS: return ACCUM_HIGH_REGS; case X_OR_YH_REGS: case YL_REG: return (!reload_in_progress ? NO_REGS : class); case YL_OR_ACCUM_LOW_REGS: return ACCUM_LOW_REGS; case X_OR_YL_REGS: case X_OR_Y_REGS: case Y_REG: return (!reload_in_progress ? NO_REGS : class); case ACCUM_OR_Y_REGS: return ACCUM_REGS; case PH_REG: case X_OR_PH_REGS: case PL_REG: return (!reload_in_progress ? NO_REGS : class); case PL_OR_ACCUM_LOW_REGS: return ACCUM_LOW_REGS; case X_OR_PL_REGS: return (!reload_in_progress ? NO_REGS : class); case YL_OR_PL_OR_ACCUM_LOW_REGS: return ACCUM_LOW_REGS; case P_REG: return (!reload_in_progress ? NO_REGS : class); case ACCUM_OR_P_REGS: return ACCUM_REGS; case YL_OR_P_REGS: return (!reload_in_progress ? NO_REGS : class); case ACCUM_LOW_OR_YL_OR_P_REGS: return ACCUM_LOW_REGS; case Y_OR_P_REGS: return (!reload_in_progress ? NO_REGS : class); case ACCUM_Y_OR_P_REGS: return ACCUM_REGS; case NO_FRAME_Y_ADDR_REGS: case Y_ADDR_REGS: return (!reload_in_progress ? NO_REGS : class); case ACCUM_LOW_OR_Y_ADDR_REGS: return ACCUM_LOW_REGS; case ACCUM_OR_Y_ADDR_REGS: return ACCUM_REGS; case X_OR_Y_ADDR_REGS: case Y_OR_Y_ADDR_REGS: case P_OR_Y_ADDR_REGS: return (!reload_in_progress ? NO_REGS : class); case NON_HIGH_YBASE_ELIGIBLE_REGS: return ACCUM_LOW_REGS; case YBASE_ELIGIBLE_REGS: return ACCUM_REGS; case J_REG: case J_OR_DAU_16_BIT_REGS: case BMU_REGS: return (!reload_in_progress ? NO_REGS : class); case YBASE_VIRT_REGS: if (IS_YBASE_ELIGIBLE_REG (REGNO (x))) return class; else return (!reload_in_progress ? NO_REGS : class); case ACCUM_LOW_OR_YBASE_REGS: if (IS_YBASE_ELIGIBLE_REG (REGNO (x))) return class; else return ACCUM_LOW_REGS; case ACCUM_OR_YBASE_REGS: if (IS_YBASE_ELIGIBLE_REG (REGNO (x))) return class; else return ACCUM_REGS; case X_OR_YBASE_REGS: case Y_OR_YBASE_REGS: if (IS_YBASE_ELIGIBLE_REG (REGNO (x))) return YBASE_VIRT_REGS; else return (!reload_in_progress ? NO_REGS : class); case ACCUM_LOW_YL_PL_OR_YBASE_REGS: if (IS_YBASE_ELIGIBLE_REG (REGNO (x))) return ACCUM_LOW_OR_YBASE_REGS; else return ACCUM_LOW_REGS; case P_OR_YBASE_REGS: if (IS_YBASE_ELIGIBLE_REG (REGNO (x))) return YBASE_VIRT_REGS; else return (!reload_in_progress ? NO_REGS : class); case ACCUM_Y_P_OR_YBASE_REGS: if (IS_YBASE_ELIGIBLE_REG (REGNO (x))) return ACCUM_OR_YBASE_REGS; else return ACCUM_REGS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -