#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;
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 3
static 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));
#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_epilogue
struct 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;
case QImode:
if (regno != REG_C0 && regno != REG_C1 && regno != REG_C2)
return 1;
else
return 0;
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_class
dsp16xx_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;
}
}
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;
}
}
int
class_max_nregs(class, mode)
enum reg_class class ATTRIBUTE_UNUSED;
enum machine_mode mode;
{
return (GET_MODE_SIZE(mode));
}
enum reg_class
limit_reload_class (mode, class)
enum machine_mode mode ATTRIBUTE_UNUSED;
enum reg_class class;
{
return class;
}
int
dsp16xx_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;
}
enum reg_class
preferred_reload_class (x, class)
rtx x;
enum reg_class class;
{
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 (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;
case Y_ADDR_OR_YBASE_REGS:
if (IS_YBASE_ELIGIBLE_REG (REGNO (x)))
return YBASE_VIRT_REGS;
else
return (!reload_in_progress ? NO_REGS : class);
case YBASE_OR_NOHIGH_YBASE_ELIGIBLE_REGS:
if (IS_YBASE_ELIGIBLE_REG (REGNO (x)))
return ACCUM_LOW_OR_YBASE_REGS;
else
return ACCUM_LOW_REGS;
case YBASE_OR_YBASE_ELIGIBLE_REGS:
if (IS_YBASE_ELIGIBLE_REG (REGNO (x)))
return ACCUM_OR_YBASE_REGS;
else
return ACCUM_REGS;
case NO_HIGH_ALL_REGS:
if (IS_YBASE_ELIGIBLE_REG (REGNO (x)))
return ACCUM_LOW_OR_YBASE_REGS;
else
return ACCUM_LOW_REGS;
case ALL_REGS:
if (IS_YBASE_ELIGIBLE_REG (REGNO (x)))
return ACCUM_OR_YBASE_REGS;
else
return ACCUM_REGS;
case NOHIGH_NON_ADDR_REGS:
return ACCUM_LOW_REGS;
case NON_ADDR_REGS:
case SLOW_MEM_LOAD_REGS:
return ACCUM_REGS;
case NOHIGH_NON_YBASE_REGS:
return ACCUM_LOW_REGS;
case NO_ACCUM_NON_YBASE_REGS:
return (!reload_in_progress ? NO_REGS : class);
case NON_YBASE_REGS:
return ACCUM_REGS;
default:
return class;
}
}
if (REG_P (x) && !TARGET_RESERVE_YBASE
&& 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: case X_REG:
case X_OR_ACCUM_LOW_REGS: case X_OR_ACCUM_REGS:
case YH_REG: case YH_OR_ACCUM_HIGH_REGS:
case X_OR_YH_REGS: case YL_REG:
case YL_OR_ACCUM_LOW_REGS: case X_OR_YL_REGS:
case X_OR_Y_REGS: case Y_REG:
case ACCUM_OR_Y_REGS: case PH_REG:
case X_OR_PH_REGS: case PL_REG:
case PL_OR_ACCUM_LOW_REGS: case X_OR_PL_REGS:
case YL_OR_PL_OR_ACCUM_LOW_REGS: case P_REG:
case ACCUM_OR_P_REGS: case YL_OR_P_REGS:
case ACCUM_LOW_OR_YL_OR_P_REGS: case Y_OR_P_REGS:
case ACCUM_Y_OR_P_REGS: case NO_FRAME_Y_ADDR_REGS:
case Y_ADDR_REGS: case ACCUM_LOW_OR_Y_ADDR_REGS:
case ACCUM_OR_Y_ADDR_REGS: case X_OR_Y_ADDR_REGS:
case Y_OR_Y_ADDR_REGS: case P_OR_Y_ADDR_REGS:
case NON_HIGH_YBASE_ELIGIBLE_REGS: case YBASE_ELIGIBLE_REGS:
default:
return class;
case J_REG:
return (!reload_in_progress ? NO_REGS : class);
case J_OR_DAU_16_BIT_REGS:
return ACCUM_HIGH_REGS;
case BMU_REGS:
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 NON_HIGH_YBASE_ELIGIBLE_REGS;
case ALL_REGS:
return YBASE_ELIGIBLE_REGS;
case NOHIGH_NON_ADDR_REGS:
return ACCUM_LOW_OR_YL_OR_P_REGS;
case NON_ADDR_REGS:
return ACCUM_Y_OR_P_REGS;
case SLOW_MEM_LOAD_REGS:
return ACCUM_OR_Y_ADDR_REGS;
case NOHIGH_NON_YBASE_REGS:
return NON_HIGH_YBASE_ELIGIBLE_REGS;
case NO_ACCUM_NON_YBASE_REGS:
return Y_ADDR_REGS;
case NON_YBASE_REGS:
return YBASE_ELIGIBLE_REGS;
}
}
if (GET_CODE (x) == PLUS)
{
if (GET_MODE (x) == QImode
&& REG_P (XEXP (x,0))
&& (XEXP (x,0) == frame_pointer_rtx
|| XEXP (x,0) == stack_pointer_rtx)
&& (GET_CODE (XEXP (x,1)) == CONST_INT))
{
if (class == ACCUM_HIGH_REGS)
return class;
#if 0
if (!reg_class_subset_p (ACCUM_REGS, class))
return (!reload_in_progress ? NO_REGS : class);
#endif
if (reg_class_subset_p (ACCUM_HIGH_REGS, class))
return ACCUM_HIGH_REGS;
else if (class == ACCUM_LOW_REGS)
return A1L_REG;
else if (class == A0L_REG)
return NO_REGS;
else
return class;
}
if (class == NON_YBASE_REGS || class == YBASE_ELIGIBLE_REGS)
return Y_ADDR_REGS;
else
return class;
}
else if (GET_CODE (x) == MEM)
{
if (reg_class_subset_p(YBASE_VIRT_REGS, class))
{
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;
}
}
else
return class;
}
else
return class;
}
enum reg_class
secondary_reload_class (class, mode, in)
enum reg_class class;
enum machine_mode mode;
rtx in;
{
int regno = -1;
if (GET_CODE (in) == REG || GET_CODE (in) == SUBREG)
regno = true_regnum (in);
if (class == ACCUM_HIGH_REGS
|| class == A1H_REG
|| class == A0H_REG)
{
if (GET_CODE (in) == PLUS && mode == QImode)
return ACCUM_LOW_REGS;
}
if (class == ACCUM_HIGH_REGS
|| class == ACCUM_LOW_REGS
|| class == A1L_REG
|| class == A0L_REG
|| class == A1H_REG
|| class == A0H_REG)
{
if (GET_CODE (in) == PLUS && mode == QImode)
{
rtx addr0 = XEXP (in, 0);
rtx addr1 = XEXP (in, 1);
if (REG_P (addr0) && REG_P (addr1))
return NO_REGS;
}
}
if ((class == ACCUM_REGS || class == ACCUM_HIGH_REGS ||
class == ACCUM_LOW_REGS || class == A0H_REG || class == A0L_REG ||
class == A1H_REG || class == A1_REG) ||
(regno >= REG_A0 && regno < REG_A1L + 1))
return NO_REGS;
if (class == ACCUM_OR_YBASE_REGS && REG_P(in)
&& IS_YBASE_ELIGIBLE_REG(regno))
{
return NO_REGS;
}
if (!TARGET_RESERVE_YBASE && IS_YBASE_REGISTER_WINDOW(regno))
{
switch ((int) class)
{
case (int) X_REG:
case (int) X_OR_ACCUM_LOW_REGS:
case (int) X_OR_ACCUM_REGS:
case (int) YH_REG:
case (int) YH_OR_ACCUM_HIGH_REGS:
case (int) X_OR_YH_REGS:
case (int) YL_REG:
case (int) YL_OR_ACCUM_LOW_REGS:
case (int) X_OR_Y_REGS:
case (int) X_OR_YL_REGS:
case (int) Y_REG:
case (int) ACCUM_OR_Y_REGS:
case (int) PH_REG:
case (int) X_OR_PH_REGS:
case (int) PL_REG:
case (int) PL_OR_ACCUM_LOW_REGS:
case (int) X_OR_PL_REGS:
case (int) YL_OR_PL_OR_ACCUM_LOW_REGS:
case (int) P_REG:
case (int) ACCUM_OR_P_REGS:
case (int) YL_OR_P_REGS:
case (int) ACCUM_LOW_OR_YL_OR_P_REGS:
case (int) Y_OR_P_REGS:
case (int) ACCUM_Y_OR_P_REGS:
case (int) Y_ADDR_REGS:
case (int) ACCUM_LOW_OR_Y_ADDR_REGS:
case (int) ACCUM_OR_Y_ADDR_REGS:
case (int) X_OR_Y_ADDR_REGS:
case (int) Y_OR_Y_ADDR_REGS:
case (int) P_OR_Y_ADDR_REGS:
case (int) YBASE_ELIGIBLE_REGS:
return NO_REGS;
default:
return ACCUM_HIGH_REGS;
}
}
if (!TARGET_RESERVE_YBASE && regno != -1)
{
switch (regno)
{
case REG_A0:
case REG_A0L:
case REG_A1:
case REG_A1L:
case REG_X:
case REG_Y:
case REG_YL:
case REG_PROD:
case REG_PRODL:
case REG_R0:
case REG_R1:
case REG_R2:
case REG_R3:
if (class == YBASE_VIRT_REGS)
return NO_REGS;
else
{
switch ((int) class)
{
case (int) X_REG:
case (int) X_OR_ACCUM_LOW_REGS:
case (int) X_OR_ACCUM_REGS:
case (int) YH_REG:
case (int) YH_OR_ACCUM_HIGH_REGS:
case (int) X_OR_YH_REGS:
case (int) YL_REG:
case (int) YL_OR_ACCUM_LOW_REGS:
case (int) X_OR_Y_REGS:
case (int) X_OR_YL_REGS:
case (int) Y_REG:
case (int) ACCUM_OR_Y_REGS:
case (int) PH_REG:
case (int) X_OR_PH_REGS:
case (int) PL_REG:
case (int) PL_OR_ACCUM_LOW_REGS:
case (int) X_OR_PL_REGS:
case (int) YL_OR_PL_OR_ACCUM_LOW_REGS:
case (int) P_REG:
case (int) ACCUM_OR_P_REGS:
case (int) YL_OR_P_REGS:
case (int) ACCUM_LOW_OR_YL_OR_P_REGS:
case (int) Y_OR_P_REGS:
case (int) ACCUM_Y_OR_P_REGS:
case (int) Y_ADDR_REGS:
case (int) ACCUM_LOW_OR_Y_ADDR_REGS:
case (int) ACCUM_OR_Y_ADDR_REGS:
case (int) X_OR_Y_ADDR_REGS:
case (int) Y_OR_Y_ADDR_REGS:
case (int) P_OR_Y_ADDR_REGS:
case (int) YBASE_ELIGIBLE_REGS:
return YBASE_VIRT_REGS;
default:
break;
}
}
}
}
if (regno == -1 && GET_CODE(in) != PLUS)
{
if (class == YBASE_VIRT_REGS)
return NON_YBASE_REGS;
else
return NO_REGS;
}
if (GET_CODE (in) == PLUS && mode == QImode)
{
rtx addr0 = XEXP (in, 0);
rtx addr1 = XEXP (in, 1);
if (REG_P (addr0) && REG_P (addr1))
return ACCUM_LOW_REGS;
}
#if 0
if (REG_P(in))
return ACCUM_REGS;
#endif
return ACCUM_HIGH_REGS;
}
int
symbolic_address_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (symbolic_address_p (op));
}
int
symbolic_address_p (op)
rtx op;
{
switch (GET_CODE (op))
{
case SYMBOL_REF:
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT
&& INTVAL (XEXP (op,1)) < 0x20);
default:
return 0;
}
}
int
Y_address_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (memory_address_p (mode, op) && !symbolic_address_p (op));
}
int
sp_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == PLUS
&& (XEXP (op, 0) == stack_pointer_rtx
|| XEXP (op, 0) == frame_pointer_rtx)
&& GET_CODE (XEXP (op,1)) == CONST_INT);
}
int
sp_operand2 (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if ((GET_CODE (op) == PLUS
&& (XEXP (op, 0) == stack_pointer_rtx
|| XEXP (op, 0) == frame_pointer_rtx)
&& (REG_P (XEXP (op,1))
&& IS_ADDRESS_REGISTER (REGNO (XEXP(op, 1))))))
return 1;
else if ((GET_CODE (op) == PLUS
&& (XEXP (op, 1) == stack_pointer_rtx
|| XEXP (op, 1) == frame_pointer_rtx)
&& (REG_P (XEXP (op,0))
&& IS_ADDRESS_REGISTER (REGNO (XEXP(op, 1))))))
return 1;
else
return 0;
}
int
nonmemory_arith_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (immediate_operand (op, mode) || arith_reg_operand (op, mode));
}
int
arith_reg_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (register_operand (op, mode)
&& (GET_CODE (op) != REG
|| REGNO (op) >= FIRST_PSEUDO_REGISTER
|| (!(IS_YBASE_REGISTER_WINDOW (REGNO (op)))
&& REGNO (op) != FRAME_POINTER_REGNUM)));
}
int
call_address_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (symbolic_address_p (op) || REG_P(op))
{
return 1;
}
return 0;
}
int
dsp16xx_comparison_operator (op, mode)
register rtx op;
enum machine_mode mode;
{
return ((mode == VOIDmode || GET_MODE (op) == mode)
&& GET_RTX_CLASS (GET_CODE (op)) == '<'
&& (GET_CODE(op) != GE && GET_CODE (op) != LT &&
GET_CODE (op) != GEU && GET_CODE (op) != LTU));
}
void
notice_update_cc(exp)
rtx exp;
{
if (GET_CODE (exp) == SET)
{
if (SET_DEST (exp) == pc_rtx)
return;
if (REG_P (SET_DEST (exp))
&& (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM))
{
if (cc_status.value1
&& reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
cc_status.value1 = 0;
if (cc_status.value2
&& reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
cc_status.value2 = 0;
return;
}
if (GET_CODE (SET_DEST (exp)) == MEM && REG_P (SET_SRC (exp)))
{
if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM)
cc_status.value1 = 0;
if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM)
cc_status.value2 = 0;
return;
}
else if (GET_CODE (SET_SRC (exp)) == CALL)
{
CC_STATUS_INIT;
return;
}
else if (SET_DEST (exp) == cc0_rtx)
{
CC_STATUS_INIT;
cc_status.value1 = SET_SRC (exp);
return;
}
else if (GET_MODE_CLASS (GET_MODE (SET_SRC (exp))) == MODE_INT)
switch (GET_CODE (SET_SRC (exp)))
{
case PLUS:
case MINUS:
if (REG_P (SET_DEST (exp)))
{
if (IS_ADDRESS_REGISTER (REGNO (SET_DEST (exp))))
{
CC_STATUS_INIT;
break;
}
}
case ASHIFTRT:
case LSHIFTRT:
case ASHIFT:
case AND:
case IOR:
case XOR:
case MULT:
case NEG:
case NOT:
cc_status.value1 = SET_SRC (exp);
cc_status.value2 = SET_DEST (exp);
break;
default:
CC_STATUS_INIT;
}
else
{
CC_STATUS_INIT;
}
}
else if (GET_CODE (exp) == PARALLEL
&& GET_CODE (XVECEXP (exp, 0, 0)) == SET)
{
if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
return;
if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
{
CC_STATUS_INIT;
cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
return;
}
CC_STATUS_INIT;
}
else
{
CC_STATUS_INIT;
}
}
int
dsp16xx_makes_calls ()
{
rtx insn;
for (insn = get_insns (); insn; insn = next_insn (insn))
if (GET_CODE (insn) == CALL_INSN)
return (1);
return 0;
}
long
compute_frame_size (size)
int size;
{
long total_size;
long var_size;
long args_size;
long extra_size;
long reg_size;
current_frame_info.function_makes_calls = !leaf_function_p ();
reg_size = 0;
extra_size = 0;
var_size = size;
args_size = current_function_outgoing_args_size;
reg_size = reg_save_size ();
total_size = var_size + args_size + extra_size + reg_size;
current_frame_info.total_size = total_size;
current_frame_info.var_size = var_size;
current_frame_info.args_size = args_size;
current_frame_info.extra_size = extra_size;
current_frame_info.reg_size = reg_size;
current_frame_info.initialized = reload_completed;
current_frame_info.reg_size = reg_size / UNITS_PER_WORD;
if (reg_size)
{
unsigned long offset = args_size + var_size + reg_size;
current_frame_info.sp_save_offset = offset;
current_frame_info.fp_save_offset = offset - total_size;
}
return total_size;
}
int
dsp16xx_call_saved_register (regno)
int regno;
{
#if 0
if (regno == REG_PR && current_frame_info.function_makes_calls)
return 1;
#endif
return (regs_ever_live[regno] && !call_used_regs[regno] &&
!IS_YBASE_REGISTER_WINDOW(regno));
}
int
ybase_regs_ever_used ()
{
int regno;
int live = 0;
for (regno = REG_YBASE0; regno <= REG_YBASE31; regno++)
if (regs_ever_live[regno])
{
live = 1;
break;
}
return live;
}
static void
dsp16xx_output_function_prologue (file, size)
FILE *file;
HOST_WIDE_INT size;
{
int regno;
long total_size;
fp = reg_names[FRAME_POINTER_REGNUM];
sp = reg_names[STACK_POINTER_REGNUM];
rr = reg_names[RETURN_ADDRESS_REGNUM];
a1h = reg_names[REG_A1];
total_size = compute_frame_size (size);
fprintf (file, "\t/* FUNCTION PROLOGUE: */\n");
fprintf (file, "\t/* total=%ld, vars= %ld, regs= %d, args=%d, extra= %ld */\n",
current_frame_info.total_size,
current_frame_info.var_size,
current_frame_info.reg_size,
current_function_outgoing_args_size,
current_frame_info.extra_size);
fprintf (file, "\t/* fp save offset= %ld, sp save_offset= %ld */\n\n",
current_frame_info.fp_save_offset,
current_frame_info.sp_save_offset);
if (ybase_regs_ever_used())
{
fprintf (file, "\t%s=%s\n", a1h, reg_names[REG_YBASE]);
if (TARGET_YBASE_HIGH)
fprintf (file, "\t%s=%sh-32\n", reg_names[REG_A1], a1h);
else
fprintf (file, "\t%s=%sh+32\n", reg_names[REG_A1], a1h);
fprintf (file, "\t%s=%s\n", reg_names[REG_YBASE], a1h);
}
if (current_frame_info.var_size)
{
if (current_frame_info.var_size == 1)
fprintf (file, "\t*%s++\n", sp);
else
{
if (SMALL_INTVAL(current_frame_info.var_size) && ((current_frame_info.var_size & 0x8000) == 0))
fprintf (file, "\t%s=%ld\n\t*%s++%s\n", reg_names[REG_J], current_frame_info.var_size, sp, reg_names[REG_J]);
else
fatal_error ("stack size > 32k");
}
}
for(regno = 0; regno < FIRST_PSEUDO_REGISTER; ++ regno)
if (dsp16xx_call_saved_register (regno))
{
fprintf (file, "\tpush(*%s)=%s\n", sp, reg_names[regno]);
}
if (current_frame_info.function_makes_calls)
fprintf (file, "\tpush(*%s)=%s\n", sp, reg_names[RETURN_ADDRESS_REGNUM]);
if (current_frame_info.args_size)
{
if (current_frame_info.args_size == 1)
fprintf (file, "\t*%s++\n", sp);
else
error ("stack size > 32k");
}
if (frame_pointer_needed)
{
fprintf (file, "\t%s=%s\n", a1h, sp);
fprintf (file, "\t%s=%s\n", fp, a1h);
fprintf (file, "\t%s=%ld\n", reg_names[REG_J], -total_size);
fprintf (file, "\t*%s++%s\n", fp, reg_names[REG_J]);
}
fprintf (file, "\t/* END FUNCTION PROLOGUE: */\n\n");
}
void
init_emulation_routines ()
{
dsp16xx_addhf3_libcall = (rtx) 0;
dsp16xx_subhf3_libcall = (rtx) 0;
dsp16xx_mulhf3_libcall = (rtx) 0;
dsp16xx_divhf3_libcall = (rtx) 0;
dsp16xx_cmphf3_libcall = (rtx) 0;
dsp16xx_fixhfhi2_libcall = (rtx) 0;
dsp16xx_floathihf2_libcall = (rtx) 0;
dsp16xx_neghf2_libcall = (rtx) 0;
dsp16xx_mulhi3_libcall = (rtx) 0;
dsp16xx_udivqi3_libcall = (rtx) 0;
dsp16xx_udivhi3_libcall = (rtx) 0;
dsp16xx_divqi3_libcall = (rtx) 0;
dsp16xx_divhi3_libcall = (rtx) 0;
dsp16xx_modqi3_libcall = (rtx) 0;
dsp16xx_modhi3_libcall = (rtx) 0;
dsp16xx_umodqi3_libcall = (rtx) 0;
dsp16xx_umodhi3_libcall = (rtx) 0;
dsp16xx_ashrhi3_libcall = (rtx) 0;
dsp16xx_ashlhi3_libcall = (rtx) 0;
dsp16xx_ucmphi2_libcall = (rtx) 0;
dsp16xx_lshrhi3_libcall = (rtx) 0;
}
static void
dsp16xx_output_function_epilogue (file, size)
FILE *file;
HOST_WIDE_INT size ATTRIBUTE_UNUSED;
{
int regno;
fp = reg_names[FRAME_POINTER_REGNUM];
sp = reg_names[STACK_POINTER_REGNUM];
rr = reg_names[RETURN_ADDRESS_REGNUM];
a1h = reg_names[REG_A1];
fprintf (file, "\n\t/* FUNCTION EPILOGUE: */\n");
if (current_frame_info.args_size)
{
if (current_frame_info.args_size == 1)
fprintf (file, "\t*%s--\n", sp);
else
{
fprintf (file, "\t%s=%ld\n\t*%s++%s\n",
reg_names[REG_J], -current_frame_info.args_size, sp, reg_names[REG_J]);
}
}
if (ybase_regs_ever_used())
{
fprintf (file, "\t%s=%s\n", a1h, reg_names[REG_YBASE]);
if (TARGET_YBASE_HIGH)
fprintf (file, "\t%s=%sh+32\n", reg_names[REG_A1], a1h);
else
fprintf (file, "\t%s=%sh-32\n", reg_names[REG_A1], a1h);
fprintf (file, "\t%s=%s\n", reg_names[REG_YBASE], a1h);
}
if (current_frame_info.function_makes_calls)
fprintf (file, "\t%s=pop(*%s)\n", reg_names[RETURN_ADDRESS_REGNUM], sp);
for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; --regno)
if (dsp16xx_call_saved_register(regno))
{
fprintf (file, "\t%s=pop(*%s)\n", reg_names[regno], sp);
}
if (current_frame_info.var_size)
{
if (current_frame_info.var_size == 1)
fprintf (file, "\t*%s--\n", sp);
else
{
fprintf (file, "\t%s=%ld\n\t*%s++%s\n",
reg_names[REG_J], -current_frame_info.var_size, sp, reg_names[REG_J]);
}
}
fprintf (file, "\treturn\n");
current_frame_info = zero_frame_info;
init_emulation_routines ();
}
int
emit_move_sequence (operands, mode)
rtx *operands;
enum machine_mode mode;
{
register rtx operand0 = operands[0];
register rtx operand1 = operands[1];
if (GET_CODE (operand0) == MEM && GET_CODE (operand1) != REG)
operands[1] = force_reg (mode, operand1);
return 0;
}
void
double_reg_from_memory (operands)
rtx operands[];
{
rtx xoperands[4];
if (GET_CODE(XEXP(operands[1],0)) == POST_INC)
{
output_asm_insn ("%u0=%1", operands);
output_asm_insn ("%w0=%1", operands);
}
else if (GET_CODE(XEXP(operands[1],0)) == POST_DEC)
{
xoperands[1] = XEXP (XEXP (operands[1], 0), 0);
xoperands[0] = operands[0];
output_asm_insn ("%u0=*%1++\n\t%w0=*%1--\n\t*%1--\n\t*%1--", xoperands);
}
else if (GET_CODE(XEXP(operands[1],0)) == PLUS)
{
rtx addr;
int offset = 0;
output_asm_insn ("%u0=%1", operands);
addr = XEXP (operands[1], 0);
if (GET_CODE (XEXP(addr,0)) == CONST_INT)
offset = INTVAL(XEXP(addr,0)) + 1;
else if (GET_CODE (XEXP(addr,1)) == CONST_INT)
offset = INTVAL(XEXP(addr,1)) + 1;
fprintf (asm_out_file, "\t%s=*(%d)\n", reg_names[REGNO(operands[0]) + 1], offset + 31);
}
else
{
xoperands[1] = XEXP(operands[1],0);
xoperands[0] = operands[0];
output_asm_insn ("%u0=*%1++\n\t%w0=*%1--", xoperands);
}
}
void
double_reg_to_memory (operands)
rtx operands[];
{
rtx xoperands[4];
if (GET_CODE(XEXP(operands[0],0)) == POST_INC)
{
output_asm_insn ("%0=%u1", operands);
output_asm_insn ("%0=%w1", operands);
}
else if (GET_CODE(XEXP(operands[0],0)) == POST_DEC)
{
xoperands[0] = XEXP (XEXP (operands[0], 0), 0);
xoperands[1] = operands[1];
output_asm_insn ("*%0++=%u1\n\t*%0--=%w1\n\t*%0--\n\t*%0--", xoperands);
}
else if (GET_CODE(XEXP(operands[0],0)) == PLUS)
{
rtx addr;
int offset = 0;
output_asm_insn ("%0=%u1", operands);
addr = XEXP (operands[0], 0);
if (GET_CODE (XEXP(addr,0)) == CONST_INT)
offset = INTVAL(XEXP(addr,0)) + 1;
else if (GET_CODE (XEXP(addr,1)) == CONST_INT)
offset = INTVAL(XEXP(addr,1)) + 1;
else
fatal_error ("invalid addressing mode");
fprintf (asm_out_file, "\t*(%d)=%s\n", offset + 31, reg_names[REGNO(operands[1]) + 1]);
}
else
{
xoperands[0] = XEXP(operands[0],0);
xoperands[1] = operands[1];
output_asm_insn ("*%0++=%u1\n\t*%0--=%w1", xoperands);
}
}
void
override_options ()
{
if (chip_name == (char *) 0)
chip_name = DEFAULT_CHIP_NAME;
if (text_seg_name == (char *) 0)
text_seg_name = DEFAULT_TEXT_SEG_NAME;
if (data_seg_name == (char *) 0)
data_seg_name = DEFAULT_DATA_SEG_NAME;
if (bss_seg_name == (char *) 0)
bss_seg_name = DEFAULT_BSS_SEG_NAME;
if (const_seg_name == (char *) 0)
const_seg_name = DEFAULT_CONST_SEG_NAME;
save_chip_name = xstrdup (chip_name);
rsect_text = concat (".rsect \"", text_seg_name, "\"", NULL);
rsect_data = concat (".rsect \"", data_seg_name, "\"", NULL);
rsect_bss = concat (".rsect \"", bss_seg_name, "\"", NULL);
rsect_const = concat (".rsect \"", const_seg_name, "\"", NULL);
}
int
next_cc_user_unsigned (insn)
rtx insn;
{
switch (next_cc_user_code (insn))
{
case GTU:
case GEU:
case LTU:
case LEU:
return 1;
default:
return 0;
}
}
enum rtx_code
next_cc_user_code (insn)
rtx insn;
{
if (!(insn = next_cc0_user (insn)))
return (enum rtx_code) 0;
else if (GET_CODE (insn) == JUMP_INSN
&& GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
return GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 0));
else if (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SET
&& comparison_operator (SET_SRC (PATTERN (insn)), VOIDmode))
return GET_CODE (SET_SRC (PATTERN (insn)));
else
abort ();
}
void
print_operand(file, op, letter)
FILE *file;
rtx op;
int letter;
{
enum rtx_code code;
code = GET_CODE(op);
switch (letter)
{
case 'I':
code = reverse_condition (code);
case 'C':
if (code == EQ)
{
fputs ("eq", file);
return;
}
else if (code == NE)
{
fputs ("ne", file);
return;
}
else if (code == GT || code == GTU)
{
fputs ("gt", file);
return;
}
else if (code == LT || code == LTU)
{
fputs ("mi", file);
return;
}
else if (code == GE || code == GEU)
{
fputs ("pl", file);
return;
}
else if (code == LE || code == LEU)
{
fputs ("le", file);
return;
}
else
abort ();
break;
default:
break;
}
if (code == REG)
{
if (letter == 'w')
fprintf (file, "%s", reg_names[REGNO (op) + 1]);
else if (letter == 'u' || !letter)
fprintf (file, "%s", reg_names[REGNO (op)]);
else if (letter == 'b')
fprintf (file, "%sh", reg_names[REGNO (op)]);
else if (letter == 'm')
fprintf (file, "%s", himode_reg_name[REGNO (op)]);
else
output_operand_lossage ("bad register extension code");
}
else if (code == MEM)
output_address (XEXP(op,0));
else if (code == CONST_INT)
{
HOST_WIDE_INT val = INTVAL (op);
if (letter == 'H')
fprintf (file, HOST_WIDE_INT_PRINT_HEX, val & 0xffff);
else if (letter == 'h')
fprintf (file, HOST_WIDE_INT_PRINT_DEC, val);
else if (letter == 'U')
fprintf (file, HOST_WIDE_INT_PRINT_HEX, (val >> 16) & 0xffff);
else
output_addr_const(file, op);
}
else if (code == CONST_DOUBLE && GET_MODE(op) != DImode)
{
long l;
REAL_VALUE_TYPE r;
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
REAL_VALUE_TO_TARGET_SINGLE (r, l);
fprintf (file, "0x%lx", l);
}
else if (code == CONST)
{
rtx addr = XEXP (op, 0);
if (GET_CODE (addr) != PLUS)
{
output_addr_const(file, op);
return;
}
if ((GET_CODE (XEXP (addr, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (addr, 0)) == LABEL_REF)
&& (GET_CODE (XEXP (addr, 1)) == CONST_INT))
{
int n = INTVAL (XEXP(addr, 1));
output_addr_const (file, XEXP (addr, 0));
if (n >= 0)
fprintf (file, "+");
n = (int) (short) n;
fprintf (file, "%d", n);
}
else if ((GET_CODE (XEXP (addr, 1)) == SYMBOL_REF
|| GET_CODE (XEXP (addr, 1)) == LABEL_REF)
&& (GET_CODE (XEXP (addr, 0)) == CONST_INT))
{
int n = INTVAL (XEXP(addr, 0));
output_addr_const (file, XEXP (addr, 1));
if (n >= 0)
fprintf (file, "+");
n = (int) (short) n;
fprintf (file, "%d", n);
}
else
output_addr_const(file, op);
}
else
output_addr_const (file, op);
}
void
print_operand_address(file, addr)
FILE *file;
rtx addr;
{
rtx base;
int offset = 0;;
switch (GET_CODE (addr))
{
case REG:
fprintf (file, "*%s", reg_names[REGNO (addr)]);
break;
case POST_DEC:
fprintf (file, "*%s--", reg_names[REGNO (XEXP (addr, 0))]);
break;
case POST_INC:
fprintf (file, "*%s++", reg_names[REGNO (XEXP (addr, 0))]);
break;
case PLUS:
if (GET_CODE (XEXP(addr,0)) == CONST_INT)
offset = INTVAL(XEXP(addr,0)), base = XEXP(addr,1);
else if (GET_CODE (XEXP(addr,1)) == CONST_INT)
offset = INTVAL(XEXP(addr,1)), base = XEXP(addr,0);
else
abort();
if (GET_CODE (base) == REG && REGNO(base) == STACK_POINTER_REGNUM)
{
if (offset >= -31 && offset <= 0)
offset = 31 + offset;
else
fatal_error ("invalid offset in ybase addressing");
}
else
fatal_error ("invalid register in ybase addressing");
fprintf (file, "*(%d)", offset);
break;
default:
if (FITS_5_BITS (addr))
fprintf (file, "*(0x%x)", (INTVAL (addr) & 0x20));
else
output_addr_const (file, addr);
}
}
void
output_dsp16xx_float_const (operands)
rtx *operands;
{
rtx src = operands[1];
REAL_VALUE_TYPE d;
long value;
REAL_VALUE_FROM_CONST_DOUBLE (d, src);
REAL_VALUE_TO_TARGET_SINGLE (d, value);
operands[1] = GEN_INT (value);
output_asm_insn ("%u0=%U1\n\t%w0=%H1", operands);
}
static int
reg_save_size ()
{
int reg_save_size = 0;
int regno;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (dsp16xx_call_saved_register (regno))
{
reg_save_size += UNITS_PER_WORD;
}
if (current_frame_info.function_makes_calls)
reg_save_size += 1;
return (reg_save_size);
}
#if 0
int
dsp16xx_starting_frame_offset()
{
int reg_save_size = 0;
int regno;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (dsp16xx_call_saved_register (regno))
{
reg_save_size += UNITS_PER_WORD;
}
return (reg_save_size);
}
#endif
int
initial_frame_pointer_offset()
{
int offset = 0;
offset = compute_frame_size (get_frame_size());
#ifdef STACK_GROWS_DOWNWARD
return (offset);
#else
return (-offset);
#endif
}
#if 0
void
emit_1600_core_shift (shift_op, operands, shift_amount, mode)
enum rtx_code shift_op;
rtx *operands;
int shift_amount;
enum machine_mode mode;
{
int quotient;
int i;
int first_shift_emitted = 0;
while (shift_amount != 0)
{
if (shift_amount/16)
{
quotient = shift_amount/16;
shift_amount = shift_amount - (quotient * 16);
for (i = 0; i < quotient; i++)
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (shift_op, mode,
first_shift_emitted
? operands[0] : operands[1],
GEN_INT (16))));
first_shift_emitted = 1;
}
else if (shift_amount/8)
{
quotient = shift_amount/8;
shift_amount = shift_amount - (quotient * 8);
for (i = 0; i < quotient; i++)
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (shift_op, mode,
first_shift_emitted
? operands[0] : operands[1],
GEN_INT (8))));
first_shift_emitted = 1;
}
else if (shift_amount/4)
{
quotient = shift_amount/4;
shift_amount = shift_amount - (quotient * 4);
for (i = 0; i < quotient; i++)
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (shift_op, mode,
first_shift_emitted
? operands[0] : operands[1],
GEN_INT (4))));
first_shift_emitted = 1;
}
else if (shift_amount/1)
{
quotient = shift_amount/1;
shift_amount = shift_amount - (quotient * 1);
for (i = 0; i < quotient; i++)
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (shift_op, mode,
first_shift_emitted
? operands[0] : operands[1],
GEN_INT (1))));
first_shift_emitted = 1;
}
}
}
#else
void
emit_1600_core_shift (shift_op, operands, shift_amount)
enum rtx_code shift_op;
rtx *operands;
int shift_amount;
{
int quotient;
int i;
int first_shift_emitted = 0;
const char * const *shift_asm_ptr;
const char * const *shift_asm_ptr_first;
if (shift_op == ASHIFT)
{
shift_asm_ptr = ashift_left_asm;
shift_asm_ptr_first = ashift_left_asm_first;
}
else if (shift_op == ASHIFTRT)
{
shift_asm_ptr = ashift_right_asm;
shift_asm_ptr_first = ashift_right_asm_first;
}
else if (shift_op == LSHIFTRT)
{
shift_asm_ptr = lshift_right_asm;
shift_asm_ptr_first = lshift_right_asm_first;
}
else
fatal_error ("invalid shift operator in emit_1600_core_shift");
while (shift_amount != 0)
{
if (shift_amount/16)
{
quotient = shift_amount/16;
shift_amount = shift_amount - (quotient * 16);
for (i = 0; i < quotient; i++)
output_asm_insn ((first_shift_emitted ? shift_asm_ptr[SHIFT_INDEX_16]
: shift_asm_ptr_first[SHIFT_INDEX_16]), operands);
first_shift_emitted = 1;
}
else if (shift_amount/8)
{
quotient = shift_amount/8;
shift_amount = shift_amount - (quotient * 8);
for (i = 0; i < quotient; i++)
output_asm_insn ((first_shift_emitted ? shift_asm_ptr[SHIFT_INDEX_8]
: shift_asm_ptr_first[SHIFT_INDEX_8]), operands);
first_shift_emitted = 1;
}
else if (shift_amount/4)
{
quotient = shift_amount/4;
shift_amount = shift_amount - (quotient * 4);
for (i = 0; i < quotient; i++)
output_asm_insn ((first_shift_emitted ? shift_asm_ptr[SHIFT_INDEX_4]
: shift_asm_ptr_first[SHIFT_INDEX_4]), operands);
first_shift_emitted = 1;
}
else if (shift_amount/1)
{
quotient = shift_amount/1;
shift_amount = shift_amount - (quotient * 1);
for (i = 0; i < quotient; i++)
output_asm_insn ((first_shift_emitted ? shift_asm_ptr[SHIFT_INDEX_1]
: shift_asm_ptr_first[SHIFT_INDEX_1]), operands);
first_shift_emitted = 1;
}
}
}
#endif
int
num_1600_core_shifts (shift_amount)
int shift_amount;
{
int quotient;
int i;
int first_shift_emitted = 0;
int num_shifts = 0;
while (shift_amount != 0)
{
if (shift_amount/16)
{
quotient = shift_amount/16;
shift_amount = shift_amount - (quotient * 16);
for (i = 0; i < quotient; i++)
num_shifts++;
first_shift_emitted = 1;
}
else if (shift_amount/8)
{
quotient = shift_amount/8;
shift_amount = shift_amount - (quotient * 8);
for (i = 0; i < quotient; i++)
num_shifts++;
first_shift_emitted = 1;
}
else if (shift_amount/4)
{
quotient = shift_amount/4;
shift_amount = shift_amount - (quotient * 4);
for (i = 0; i < quotient; i++)
num_shifts++;
first_shift_emitted = 1;
}
else if (shift_amount/1)
{
quotient = shift_amount/1;
shift_amount = shift_amount - (quotient * 1);
for (i = 0; i < quotient; i++)
num_shifts++;
first_shift_emitted = 1;
}
}
return num_shifts;
}
void
asm_output_common(file, name, size, rounded)
FILE *file;
const char *name;
int size ATTRIBUTE_UNUSED;
int rounded;
{
bss_section ();
(*targetm.asm_out.globalize_label) (file, name);
assemble_name (file, name);
fputs (":", file);
if (rounded > 1)
fprintf (file, "%d * int\n", rounded);
else
fprintf (file, "int\n");
}
void
asm_output_local(file, name, size, rounded)
FILE *file;
const char *name;
int size ATTRIBUTE_UNUSED;
int rounded;
{
bss_section ();
assemble_name (file, name);
fputs (":", file);
if (rounded > 1)
fprintf (file, "%d * int\n", rounded);
else
fprintf (file, "int\n");
}
int
dsp16xx_address_cost (addr)
rtx addr;
{
switch (GET_CODE (addr))
{
default:
break;
case REG:
return 1;
case CONST:
{
rtx offset = const0_rtx;
addr = eliminate_constant_term (addr, &offset);
if (GET_CODE (addr) == LABEL_REF)
return 2;
if (GET_CODE (addr) != SYMBOL_REF)
return 4;
if (INTVAL (offset) == 0)
return 2;
}
case POST_INC: case POST_DEC:
return (GET_MODE (addr) == QImode ? 1 : 2);
case SYMBOL_REF: case LABEL_REF:
return 2;
case PLUS:
{
register rtx plus0 = XEXP (addr, 0);
register rtx plus1 = XEXP (addr, 1);
if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG)
{
plus0 = XEXP (addr, 1);
plus1 = XEXP (addr, 0);
}
if (GET_CODE (plus0) != REG)
break;
switch (GET_CODE (plus1))
{
default:
break;
case CONST_INT:
return 4;
case CONST:
case SYMBOL_REF:
case LABEL_REF:
return dsp16xx_address_cost (plus1) + 1;
}
}
}
return 4;
}
struct rtx_def *
dsp16xx_function_arg (args_so_far, mode, type, named)
CUMULATIVE_ARGS args_so_far;
enum machine_mode mode;
tree type;
int named;
{
if (TARGET_REGPARM)
{
if ((args_so_far & 1) != 0
&& (mode == HImode || GET_MODE_CLASS(mode) == MODE_FLOAT))
args_so_far++;
if (type == void_type_node)
return (struct rtx_def *) 0;
if (named && args_so_far < 4 && !MUST_PASS_IN_STACK (mode,type))
return gen_rtx_REG (mode, args_so_far + FIRST_REG_FOR_FUNCTION_ARG);
else
return (struct rtx_def *) 0;
}
else
return (struct rtx_def *) 0;
}
void
dsp16xx_function_arg_advance (cum, mode, type, named)
CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named ATTRIBUTE_UNUSED;
{
if (TARGET_REGPARM)
{
if ((*cum & 1) != 0
&& (mode == HImode || GET_MODE_CLASS(mode) == MODE_FLOAT))
*cum += 1;
if (mode != BLKmode)
*cum += GET_MODE_SIZE (mode);
else
*cum += int_size_in_bytes (type);
}
}
void
coff_dsp16xx_file_start (file)
FILE *file;
{
fprintf (file, "#include <%s.h>\n", save_chip_name);
}
void
luxworks_dsp16xx_file_start (file)
FILE *file;
{
char *temp_filename;
int len, err_code;
fprintf (file, "\t.debug ");
err_code = (TARGET_DEBUG) ? fprintf (file, "yes, ") : fprintf (file, "no, ");
err_code = (TARGET_SAVE_TEMPS) ? fprintf (file, "asm, ") : fprintf (file, "temp, ");
len = strlen (main_input_filename);
temp_filename = (char *) xmalloc (len + 2);
strcpy (temp_filename, main_input_filename);
#ifdef __CYGWIN32__
p = temp_filename;
while (*p != '\0') {
if (*p == '\\')
*p = '/';
p++;
}
#endif
fprintf (file, "\"%s\"\n", temp_filename);
fprintf (file, "#include <%s.h>\n", save_chip_name);
fprintf (file, "\t.rsect \".text\" , nodelete\n");
fprintf (file, "\t.rsect \".data\" , nodelete\n");
fprintf (file, "\t.rsect \".const\" , nodelete\n");
fprintf (file, "\t.rsect \".bss\" , nodelete\n");
}
rtx
gen_tst_reg (x)
rtx x;
{
enum machine_mode mode;
mode = GET_MODE (x);
if (mode == QImode)
emit_insn (gen_rtx_PARALLEL
(VOIDmode,
gen_rtvec (2, gen_rtx_SET (VOIDmode, cc0_rtx, x),
gen_rtx_CLOBBER (VOIDmode,
gen_rtx_SCRATCH (QImode)))));
else if (mode == HImode)
emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx, x));
else
fatal_error ("invalid mode for gen_tst_reg");
return cc0_rtx;
}
rtx
gen_compare_reg (code, x, y)
enum rtx_code code;
rtx x, y;
{
enum machine_mode mode;
mode = GET_MODE (x);
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
return cc0_rtx;
if (mode == QImode)
{
if (code == GTU || code == GEU
|| code == LTU || code == LEU)
{
emit_insn (gen_rtx_PARALLEL
(VOIDmode,
gen_rtvec (3,
gen_rtx_SET (VOIDmode, cc0_rtx,
gen_rtx_COMPARE (mode, x, y)),
gen_rtx_CLOBBER (VOIDmode,
gen_rtx_SCRATCH (QImode)),
gen_rtx_CLOBBER (VOIDmode,
gen_rtx_SCRATCH (QImode)))));
}
else
{
emit_insn (gen_rtx_PARALLEL
(VOIDmode,
gen_rtvec (3, gen_rtx_SET (VOIDmode, cc0_rtx,
gen_rtx_COMPARE (mode, x, y)),
gen_rtx_CLOBBER (VOIDmode,
gen_rtx_SCRATCH (QImode)),
gen_rtx_CLOBBER (VOIDmode,
gen_rtx_SCRATCH (QImode)))));
}
}
else if (mode == HImode)
{
if (code == GTU || code == GEU
|| code == LTU || code == LEU)
{
emit_insn (gen_rtx_PARALLEL
(VOIDmode,
gen_rtvec (5,
gen_rtx_SET (VOIDmode, cc0_rtx,
gen_rtx_COMPARE (VOIDmode, x, y)),
gen_rtx_CLOBBER (VOIDmode,
gen_rtx_SCRATCH (QImode)),
gen_rtx_CLOBBER (VOIDmode,
gen_rtx_SCRATCH (QImode)),
gen_rtx_CLOBBER (VOIDmode,
gen_rtx_SCRATCH (QImode)),
gen_rtx_CLOBBER (VOIDmode,
gen_rtx_SCRATCH (QImode)))));
}
else
emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
gen_rtx_COMPARE (VOIDmode,
force_reg (HImode, x),
force_reg (HImode,y))));
}
else
fatal_error ("invalid mode for integer comparison in gen_compare_reg");
return cc0_rtx;
}
const char *
output_block_move (operands)
rtx operands[];
{
int loop_count = INTVAL(operands[2]);
rtx xoperands[4];
fprintf (asm_out_file, "\tdo %d {\n", loop_count);
xoperands[0] = operands[4];
xoperands[1] = operands[1];
output_asm_insn ("%0=*%1++", xoperands);
xoperands[0] = operands[0];
xoperands[1] = operands[4];
output_asm_insn ("*%0++=%1", xoperands);
fprintf (asm_out_file, "\t}\n");
return "";
}
int
uns_comparison_operator (op, mode)
rtx op;
enum machine_mode mode;
{
if (mode == VOIDmode || GET_MODE (op) == mode)
{
enum rtx_code code;
code = GET_CODE(op);
if (code == LEU || code == LTU || code == GEU
|| code == GTU)
{
return 1;
}
else
return 0;
}
return 0;
}
int
signed_comparison_operator (op, mode)
rtx op;
enum machine_mode mode;
{
if (mode == VOIDmode || GET_MODE (op) == mode)
{
enum rtx_code code;
code = GET_CODE(op);
if (!(code == LEU || code == LTU || code == GEU
|| code == GTU))
{
return 1;
}
else
return 0;
}
return 0;
}