⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 m32c.c

📁 linux下编程用 编译软件
💻 C
📖 第 1 页 / 共 5 页
字号:
   combination of registers starting there (r2r0 for longs, r3r1r2r0   for long long, r3r2r1r0 for doubles), except that that ABI   currently doesn't work because it ends up using all available   general registers and gcc often can't compile it.  So, instead, we   return anything bigger than 16 bits in "mem0" (effectively, a   memory location).  */rtxm32c_libcall_value (enum machine_mode mode){  /* return reg or parallel */#if 0  /* FIXME: GCC has difficulty returning large values in registers,     because that ties up most of the general registers and gives the     register allocator little to work with.  Until we can resolve     this, large values are returned in memory.  */  if (mode == DFmode)    {      rtx rv;      rv = gen_rtx_PARALLEL (mode, rtvec_alloc (4));      XVECEXP (rv, 0, 0) = gen_rtx_EXPR_LIST (VOIDmode,					      gen_rtx_REG (HImode,							   R0_REGNO),					      GEN_INT (0));      XVECEXP (rv, 0, 1) = gen_rtx_EXPR_LIST (VOIDmode,					      gen_rtx_REG (HImode,							   R1_REGNO),					      GEN_INT (2));      XVECEXP (rv, 0, 2) = gen_rtx_EXPR_LIST (VOIDmode,					      gen_rtx_REG (HImode,							   R2_REGNO),					      GEN_INT (4));      XVECEXP (rv, 0, 3) = gen_rtx_EXPR_LIST (VOIDmode,					      gen_rtx_REG (HImode,							   R3_REGNO),					      GEN_INT (6));      return rv;    }  if (TARGET_A24 && GET_MODE_SIZE (mode) > 2)    {      rtx rv;      rv = gen_rtx_PARALLEL (mode, rtvec_alloc (1));      XVECEXP (rv, 0, 0) = gen_rtx_EXPR_LIST (VOIDmode,					      gen_rtx_REG (mode,							   R0_REGNO),					      GEN_INT (0));      return rv;    }#endif  if (GET_MODE_SIZE (mode) > 2)    return gen_rtx_REG (mode, MEM0_REGNO);  return gen_rtx_REG (mode, R0_REGNO);}/* Implements FUNCTION_VALUE.  Functions and libcalls have the same   conventions.  */rtxm32c_function_value (tree valtype, tree func ATTRIBUTE_UNUSED){  /* return reg or parallel */  enum machine_mode mode = TYPE_MODE (valtype);  return m32c_libcall_value (mode);}/* How Large Values Are Returned *//* We return structures by pushing the address on the stack, even if   we use registers for the first few "real" arguments.  */#undef TARGET_STRUCT_VALUE_RTX#define TARGET_STRUCT_VALUE_RTX m32c_struct_value_rtxstatic rtxm32c_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED,		       int incoming ATTRIBUTE_UNUSED){  return 0;}/* Function Entry and Exit *//* Implements EPILOGUE_USES.  Interrupts restore all registers.  */intm32c_epilogue_uses (int regno ATTRIBUTE_UNUSED){  if (cfun->machine->is_interrupt)    return 1;  return 0;}/* Implementing the Varargs Macros */#undef TARGET_STRICT_ARGUMENT_NAMING#define TARGET_STRICT_ARGUMENT_NAMING m32c_strict_argument_namingstatic boolm32c_strict_argument_naming (CUMULATIVE_ARGS * ca ATTRIBUTE_UNUSED){  return 1;}/* Trampolines for Nested Functions *//*   m16c:   1 0000 75C43412              mov.w   #0x1234,a0   2 0004 FC000000              jmp.a   label   m32c:   1 0000 BC563412              mov.l:s #0x123456,a0   2 0004 CC000000              jmp.a   label*//* Implements TRAMPOLINE_SIZE.  */intm32c_trampoline_size (void){  /* Allocate extra space so we can avoid the messy shifts when we     initialize the trampoline; we just write past the end of the     opcode.  */  return TARGET_A16 ? 8 : 10;}/* Implements TRAMPOLINE_ALIGNMENT.  */intm32c_trampoline_alignment (void){  return 2;}/* Implements INITIALIZE_TRAMPOLINE.  */voidm32c_initialize_trampoline (rtx tramp, rtx function, rtx chainval){#define A0(m,i) gen_rtx_MEM (m, plus_constant (tramp, i))  if (TARGET_A16)    {      /* Note: we subtract a "word" because the moves want signed	 constants, not unsigned constants.  */      emit_move_insn (A0 (HImode, 0), GEN_INT (0xc475 - 0x10000));      emit_move_insn (A0 (HImode, 2), chainval);      emit_move_insn (A0 (QImode, 4), GEN_INT (0xfc - 0x100));      /* We use 16 bit addresses here, but store the zero to turn it	 into a 24 bit offset.  */      emit_move_insn (A0 (HImode, 5), function);      emit_move_insn (A0 (QImode, 7), GEN_INT (0x00));    }  else    {      /* Note that the PSI moves actually write 4 bytes.  Make sure we	 write stuff out in the right order, and leave room for the	 extra byte at the end.  */      emit_move_insn (A0 (QImode, 0), GEN_INT (0xbc - 0x100));      emit_move_insn (A0 (PSImode, 1), chainval);      emit_move_insn (A0 (QImode, 4), GEN_INT (0xcc - 0x100));      emit_move_insn (A0 (PSImode, 5), function);    }#undef A0}/* Addressing Modes *//* Used by GO_IF_LEGITIMATE_ADDRESS.  The r8c/m32c family supports a   wide range of non-orthogonal addressing modes, including the   ability to double-indirect on *some* of them.  Not all insns   support all modes, either, but we rely on predicates and   constraints to deal with that.  */intm32c_legitimate_address_p (enum machine_mode mode, rtx x, int strict){  int mode_adjust;  if (CONSTANT_P (x))    return 1;  /* Wide references to memory will be split after reload, so we must     ensure that all parts of such splits remain legitimate     addresses.  */  mode_adjust = GET_MODE_SIZE (mode) - 1;  /* allowing PLUS yields mem:HI(plus:SI(mem:SI(plus:SI in m32c_split_move */  if (GET_CODE (x) == PRE_DEC      || GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_MODIFY)    {      return (GET_CODE (XEXP (x, 0)) == REG	      && REGNO (XEXP (x, 0)) == SP_REGNO);    }#if 0  /* This is the double indirection detection, but it currently     doesn't work as cleanly as this code implies, so until we've had     a chance to debug it, leave it disabled.  */  if (TARGET_A24 && GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) != PLUS)    {#if DEBUG_DOUBLE      fprintf (stderr, "double indirect\n");#endif      x = XEXP (x, 0);    }#endif  encode_pattern (x);  if (RTX_IS ("r"))    {      /* Most indexable registers can be used without displacements,	 although some of them will be emitted with an explicit zero	 to please the assembler.  */      switch (REGNO (patternr[0]))	{	case A0_REGNO:	case A1_REGNO:	case SB_REGNO:	case FB_REGNO:	case SP_REGNO:	  return 1;	default:	  if (IS_PSEUDO (patternr[0], strict))	    return 1;	  return 0;	}    }  if (RTX_IS ("+ri"))    {      /* This is more interesting, because different base registers	 allow for different displacements - both range and signedness	 - and it differs from chip series to chip series too.  */      int rn = REGNO (patternr[1]);      HOST_WIDE_INT offs = INTVAL (patternr[2]);      switch (rn)	{	case A0_REGNO:	case A1_REGNO:	case SB_REGNO:	  /* The syntax only allows positive offsets, but when the	     offsets span the entire memory range, we can simulate	     negative offsets by wrapping.  */	  if (TARGET_A16)	    return (offs >= -65536 && offs <= 65535 - mode_adjust);	  if (rn == SB_REGNO)	    return (offs >= 0 && offs <= 65535 - mode_adjust);	  /* A0 or A1 */	  return (offs >= -16777216 && offs <= 16777215);	case FB_REGNO:	  if (TARGET_A16)	    return (offs >= -128 && offs <= 127 - mode_adjust);	  return (offs >= -65536 && offs <= 65535 - mode_adjust);	case SP_REGNO:	  return (offs >= -128 && offs <= 127 - mode_adjust);	default:	  if (IS_PSEUDO (patternr[1], strict))	    return 1;	  return 0;	}    }  if (RTX_IS ("+rs") || RTX_IS ("+r+si"))    {      rtx reg = patternr[1];      /* We don't know where the symbol is, so only allow base	 registers which support displacements spanning the whole	 address range.  */      switch (REGNO (reg))	{	case A0_REGNO:	case A1_REGNO:	  /* $sb needs a secondary reload, but since it's involved in	     memory address reloads too, we don't deal with it very	     well.  */	  /*    case SB_REGNO: */	  return 1;	default:	  if (IS_PSEUDO (reg, strict))	    return 1;	  return 0;	}    }  return 0;}/* Implements REG_OK_FOR_BASE_P.  */intm32c_reg_ok_for_base_p (rtx x, int strict){  if (GET_CODE (x) != REG)    return 0;  switch (REGNO (x))    {    case A0_REGNO:    case A1_REGNO:    case SB_REGNO:    case FB_REGNO:    case SP_REGNO:      return 1;    default:      if (IS_PSEUDO (x, strict))	return 1;      return 0;    }}/* Implements LEGITIMIZE_ADDRESS.  The only address we really have to   worry about is frame base offsets, as $fb has a limited   displacement range.  We deal with this by attempting to reload $fb   itself into an address register; that seems to result in the best   code.  */intm32c_legitimize_address (rtx * x ATTRIBUTE_UNUSED,			 rtx oldx ATTRIBUTE_UNUSED,			 enum machine_mode mode ATTRIBUTE_UNUSED){#if DEBUG0  fprintf (stderr, "m32c_legitimize_address for mode %s\n", mode_name[mode]);  debug_rtx (*x);  fprintf (stderr, "\n");#endif  if (GET_CODE (*x) == PLUS      && GET_CODE (XEXP (*x, 0)) == REG      && REGNO (XEXP (*x, 0)) == FB_REGNO      && GET_CODE (XEXP (*x, 1)) == CONST_INT      && (INTVAL (XEXP (*x, 1)) < -128	  || INTVAL (XEXP (*x, 1)) > (128 - GET_MODE_SIZE (mode))))    {      /* reload FB to A_REGS */      rtx foo;      rtx temp = gen_reg_rtx (Pmode);      *x = copy_rtx (*x);      foo = emit_insn (gen_rtx_SET (VOIDmode, temp, XEXP (*x, 0)));      XEXP (*x, 0) = temp;      return 1;    }  return 0;}/* Implements LEGITIMIZE_RELOAD_ADDRESS.  See comment above.  */intm32c_legitimize_reload_address (rtx * x,				enum machine_mode mode,				int opnum,				int type, int ind_levels ATTRIBUTE_UNUSED){#if DEBUG0  fprintf (stderr, "\nm32c_legitimize_reload_address for mode %s\n",	   mode_name[mode]);  debug_rtx (*x);#endif  /* At one point, this function tried to get $fb copied to an address     register, which in theory would maximize sharing, but gcc was     *also* still trying to reload the whole address, and we'd run out     of address registers.  So we let gcc do the naive (but safe)     reload instead, when the above function doesn't handle it for     us.  */  return 0;}/* Used in GO_IF_MODE_DEPENDENT_ADDRESS.  */intm32c_mode_dependent_address (rtx addr){  if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == PRE_DEC)    return 1;  return 0;}/* Implements LEGITIMATE_CONSTANT_P.  We split large constants anyway,   so we can allow anything.  */intm32c_legitimate_constant_p (rtx x ATTRIBUTE_UNUSED){  return 1;}/* Condition Code Status */#undef TARGET_FIXED_CONDITION_CODE_REGS#define TARGET_FIXED_CONDITION_CODE_REGS m32c_fixed_condition_code_regsstatic boolm32c_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2){  *p1 = FLG_REGNO;  *p2 = INVALID_REGNUM;  return true;}/* Describing Relative Costs of Operations *//* Implements REGISTER_MOVE_COST.  We make impossible moves   prohibitively expensive, like trying to put QIs in r2/r3 (there are   no opcodes to do that).  We also discourage use of mem* registers   since they're really memory.  */intm32c_register_move_cost (enum machine_mode mode, int from, int to){  int cost = COSTS_N_INSNS (3);  int cc = class_contents[from][0] | class_contents[to][0];  /* FIXME: pick real values, but not 2 for now.  */  if (mode == QImode && (cc & class_contents[R23_REGS][0]))    {      if (!(cc & ~class_contents[R23_REGS][0]))	cost = COSTS_N_INSNS (1000);      else	cost = COSTS_N_INSNS (80);    }  if (!class_can_hold_mode (from, mode) || !class_can_hold_mode (to, mode))    cost = COSTS_N_INSNS (1000);  if (classes_intersect (from, CR_REGS))    cost += COSTS_N_INSNS (5);  if (classes_intersect (to, CR_REGS))    cost += COSTS_N_INSNS (5);  if (from == MEM_REGS || to == MEM_REGS)    cost += COSTS_N_INSNS (50);  else if (classes_intersect (from, MEM_REGS)	   || classes_intersect (to, MEM_REGS))    cost += COSTS_N_INSNS (10);#if DEBUG0  fprintf (stderr, "register_move_cost %s from %s to %s = %d\n",	   mode_name[mode], class_names[from], class_names[to], cost);#endif  return cost;}/*  Implements MEMORY_MOVE_COST.  */intm32c_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,		       int reg_class ATTRIBUTE_UNUSED,		       int in ATTRIBUTE_UNUSED){  /* FIXME: pick real values.  */  return COSTS_N_INSNS (10);}/* Defining the Output Assembler Language *//* The Overall Framework of an Assembler File */#undef TARGET_HAVE_NAMED_SECTIONS#define TARGET_HAVE_NAMED_SECTIONS true/* Output of Data *//* We may have 24 bit sizes, which is the native address size.   Currently unused, but provided for completeness.  */#undef TARGET_ASM_INTEGER#define TARGET_ASM_INTEGER m32c_asm_integerstatic boolm32c_asm_integer (rtx x, unsigned int size, int aligned_p){  switch (size)    {    case 3:      fprintf (asm_out_file, "\t.3byte\t");      output_addr_const (asm_out_file, x);      fputc ('\n', asm_out_file);      return true;    case 4:      if (GET_CODE (x) == SYMBOL_REF)	{	  fprintf (asm_out_file, "\t.long\t");	  output_addr_const (asm_out_file, x);	  fputc ('\n', asm_out_file);	  return true;	}      break;    }  return default_assemble_integer (x, size, aligned_p);}/* Output of Assembler Instructions *//* We use a lookup table because the addressing modes are non-orthogonal.  */static struct{  char code;  char const *pattern;  char const *format;}const conversions[] = {  { 0, "r", "0" },  { 0, "mr", "z[1]" },  { 0, "m+ri", "3[2]" },  { 0, "m+rs", "3[2]" },  { 0, "m+r+si", "4+5[2]" },  { 0, "ms", "1" },  { 0, "mi", "1" },  { 0, "m+si", "2+3" },  { 0, "mmr", "[z[2]]" },  { 0, "mm+ri", "[4[3]]" },  { 0, "mm+rs", "[4[3]]" },  { 0, "mm+r+si", "[5+6[3]]" },  { 0, "mms", "[[2]]" },  { 0, "mmi", "[[2]]" },  { 0, "mm+si", "[4[3]]" },

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -