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

📄 sh.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 4 页
字号:
output_far_jump (insn, op)     rtx insn;     rtx op;{  rtx thislab = gen_label_rtx ();  /* Output the delay slot insn first if any.  */  if (dbr_sequence_length ())    print_slot (final_sequence);  output_asm_insn ("mov.l	r13,@-r15", 0);  output_asm_insn ("mov.l	%O0,r13", &thislab);  output_asm_insn ("jmp	@r13", 0);  output_asm_insn ("mov.l	@r15+,r13", 0);  output_asm_insn (".align	2", 0);  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (thislab));  output_asm_insn (".long	%O0", &op);  return "";}/* Local label counter, used for constants in the pool and inside   pattern branches.  */static int lf = 100;/* Output code for ordinary branches.  */char *output_branch (logic, insn, operands)     int logic;     rtx insn;     rtx *operands;{  int label = lf++;  switch (get_attr_length (insn))    {    case 2:      /* A branch with an unfilled delay slot.  */    case 4:      /* Simple branch in range -252..+258 bytes */      return logic ? "bt%.	%l0" : "bf%.	%l0";    case 6:      /* A branch with an unfilled delay slot.  */    case 8:      /* Branch in range -4092..+4098 bytes.  */      {	/* The call to print_slot will clobber the operands.  */	rtx op0 = operands[0];	/* If the instruction in the delay slot is annulled (true), then	   there is no delay slot where we can put it now.  The only safe	   place for it is after the label.  */	if (final_sequence)	  {	    fprintf (asm_out_file, "\tb%c%s\tLF%d\n", logic ? 'f' : 't',		     INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))		     ? "" : ".s", label);	    if (! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))	      print_slot (final_sequence);	  }	else	  fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label);	output_asm_insn ("bra	%l0", &op0);	fprintf (asm_out_file, "\tnop\n");	fprintf (asm_out_file, "LF%d:\n", label);	if (final_sequence	    && INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))	  print_slot (final_sequence);      }      return "";    case 16:      /* A branch with an unfilled delay slot.  */    case 18:      /* Branches a long way away.  */      {	/* The call to print_slot will clobber the operands.  */	rtx op0 = operands[0];	/* If the instruction in the delay slot is annulled (true), then	   there is no delay slot where we can put it now.  The only safe	   place for it is after the label.  */	if (final_sequence)	  {	    fprintf (asm_out_file, "\tb%c%s\tLF%d\n", logic ? 'f' : 't',		     INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))		     ? "" : ".s", label);	    if (! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))	      print_slot (final_sequence);	  }	else	  fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label);	output_far_jump (insn, op0);	fprintf (asm_out_file, "LF%d:\n", label);	if (final_sequence	    && INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))	  print_slot (final_sequence);      }      return "";    }  return "bad";}/* A copy of the option structure defined in toplev.c.  */struct option{  char *string;  int *variable;  int on_value;};/* Output a single output option string NAME to FILE, without generating   lines longer than MAX.  */static intoutput_option (file, sep, type, name, indent, pos, max)     FILE *file;     char *sep;     char *type;     char *name;     char *indent;     int pos;     int max;{  if (strlen (sep) + strlen (type) + strlen (name) + pos > max)    {      fprintf (file, indent);      return fprintf (file, "%s%s", type, name);    }  return pos + fprintf (file, "%s%s%s", sep, type, name);}/* A copy of the target_switches variable in toplev.c.  */static struct{  char *name;  int value;} m_options[] = TARGET_SWITCHES;/* Output all options to the assembly language file.  */static voidoutput_options (file, f_options, f_len, W_options, W_len,		pos, max, sep, indent, term)     FILE *file;     struct option *f_options;     struct option *W_options;     int f_len, W_len;     int pos;     int max;     char *sep;     char *indent;     char *term;{  register int j;  if (optimize)    pos = output_option (file, sep, "-O", "", indent, pos, max);  if (write_symbols != NO_DEBUG)    pos = output_option (file, sep, "-g", "", indent, pos, max);  if (profile_flag)    pos = output_option (file, sep, "-p", "", indent, pos, max);  if (profile_block_flag)    pos = output_option (file, sep, "-a", "", indent, pos, max);  for (j = 0; j < f_len; j++)    if (*f_options[j].variable == f_options[j].on_value)      pos = output_option (file, sep, "-f", f_options[j].string,			   indent, pos, max);  for (j = 0; j < W_len; j++)    if (*W_options[j].variable == W_options[j].on_value)      pos = output_option (file, sep, "-W", W_options[j].string,			   indent, pos, max);  for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++)    if (m_options[j].name[0] != '\0'	&& m_options[j].value > 0	&& ((m_options[j].value & target_flags)	    == m_options[j].value))      pos = output_option (file, sep, "-m", m_options[j].name,			   indent, pos, max);  fprintf (file, term);}/* Output to FILE the start of the assembler file.  */voidoutput_file_start (file, f_options, f_len, W_options, W_len)     FILE *file;     struct option *f_options;     struct option *W_options;     int f_len, W_len;{  register int pos;  output_file_directive (file, main_input_filename);  /* Switch to the data section so that the coffsem symbol and the     gcc2_compiled. symbol aren't in the text section.  */  data_section ();  pos = fprintf (file, "\n! Hitachi SH cc1 (%s) arguments:", version_string);  output_options (file, f_options, f_len, W_options, W_len,		  pos, 75, " ", "\n! ", "\n\n");  if (TARGET_LITTLE_ENDIAN)    fprintf (file, "\t.little\n");}/* Actual number of instructions used to make a shift by N.  */static char ashiftrt_insns[] =  { 0,1,2,3,4,5,8,8,8,8,8,8,8,8,8,8,2,3,4,5,8,8,8,8,8,8,8,8,8,8,8,2};/* Left shift and logical right shift are the same.  */static char shift_insns[]    =  { 0,1,1,2,2,3,3,4,1,2,2,3,3,4,3,3,1,2,2,3,3,4,3,3,2,3,3,4,4,4,3,3};/* Individual shift amounts needed to get the above length sequences.   One bit right shifts clobber the T bit, so when possible, put one bit   shifts in the middle of the sequence, so the ends are eligible for   branch delay slots.  */static short shift_amounts[32][5] = {  {0}, {1}, {2}, {2, 1},  {2, 2}, {2, 1, 2}, {2, 2, 2}, {2, 2, 1, 2},  {8}, {8, 1}, {8, 2}, {8, 1, 2},  {8, 2, 2}, {8, 2, 1, 2}, {8, -2, 8}, {8, -1, 8},  {16}, {16, 1}, {16, 2}, {16, 1, 2},  {16, 2, 2}, {16, 2, 1, 2}, {16, -2, 8}, {16, -1, 8},  {16, 8}, {16, 1, 8}, {16, 8, 2}, {16, 8, 1, 2},  {16, 8, 2, 2}, {16, -1, -2, 16}, {16, -2, 16}, {16, -1, 16}};/* This is used in length attributes in sh.md to help compute the length   of arbitrary constant shift instructions.  */intshift_insns_rtx (insn)     rtx insn;{  rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));  int shift_count = INTVAL (XEXP (set_src, 1));  enum rtx_code shift_code = GET_CODE (set_src);  switch (shift_code)    {    case ASHIFTRT:      return ashiftrt_insns[shift_count];    case LSHIFTRT:    case ASHIFT:      return shift_insns[shift_count];    default:      abort();    }}/* Return the cost of a shift.  */intshiftcosts (x)     rtx x;{  int value = INTVAL (XEXP (x, 1));  /* If shift by a non constant, then this will be expensive.  */  if (GET_CODE (XEXP (x, 1)) != CONST_INT)    {      if (TARGET_SH3)	return 2;      /* If not an sh3 then we don't even have an instruction for it.  */      return 20;    }  /* Otherwise, return the true cost in instructions.  */  if (GET_CODE (x) == ASHIFTRT)    return ashiftrt_insns[value];  else    return shift_insns[value];}/* Return the cost of an AND operation.  */intandcosts (x)     rtx x;{  int i;  /* Anding with a register is a single cycle and instruction.  */  if (GET_CODE (XEXP (x, 1)) != CONST_INT)    return 1;  i = INTVAL (XEXP (x, 1));  /* These constants are single cycle extu.[bw] instructions.  */  if (i == 0xff || i == 0xffff)    return 1;  /* Constants that can be used in an and immediate instruction is a single     cycle, but this requires r0, so make it a little more expensive.  */  if (CONST_OK_FOR_L (i))    return 2;  /* Constants that can be loaded with a mov immediate and an and.     This case is probably unnecessary.  */  if (CONST_OK_FOR_I (i))    return 2;  /* Any other constants requires a 2 cycle pc-relative load plus an and.     This case is probably unnecessary.  */  return 3;}/* Return the cost of a multiply.  */intmultcosts (x)     rtx x;{  if (TARGET_SH2)    {      /* We have a mul insn, so we can never take more than the mul and the	 read of the mac reg, but count more because of the latency and extra	 reg usage.  */      if (TARGET_SMALLCODE)	return 2;      return 3;    }  /* If we're aiming at small code, then just count the number of     insns in a multiply call sequence.  */  if (TARGET_SMALLCODE)    return 5;  /* Otherwise count all the insns in the routine we'd be calling too.  */  return 20;}/* Code to expand a shift.  */voidgen_ashift (type, n, reg)     int type;     int n;     rtx reg;{  /* Negative values here come from the shift_amounts array.  */  if (n < 0)    {      if (type == ASHIFT)	type = LSHIFTRT;      else	type = ASHIFT;      n = -n;    }  switch (type)    {    case ASHIFTRT:      emit_insn (gen_ashrsi3_k (reg, reg, GEN_INT (n)));      break;    case LSHIFTRT:      if (n == 1)	emit_insn (gen_lshrsi3_m (reg, reg, GEN_INT (n)));      else	emit_insn (gen_lshrsi3_k (reg, reg, GEN_INT (n)));      break;    case ASHIFT:      emit_insn (gen_ashlsi3_k (reg, reg, GEN_INT (n)));      break;    }}/* Output RTL to split a constant shift into its component SH constant   shift instructions.  */   /* ??? For SH3, should reject constant shifts when slower than loading the   shift count into a register?  */intgen_shifty_op (code, operands)     int code;     rtx *operands;{  int value = INTVAL (operands[2]);  int max, i;  if (value == 31)    {      if (code == LSHIFTRT)	{	  emit_insn (gen_rotlsi3_1 (operands[0], operands[0]));	  emit_insn (gen_movt (operands[0]));	  return;	}      else if (code == ASHIFT)	{	  /* There is a two instruction sequence for 31 bit left shifts,	     but it requires r0.  */	  if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 0)	    {	      emit_insn (gen_andsi3 (operands[0], operands[0], const1_rtx));	      emit_insn (gen_rotlsi3_31 (operands[0], operands[0]));	      return;	    }	}    }  max = shift_insns[value];  for (i = 0; i < max; i++)    gen_ashift (code, shift_amounts[value][i], operands[0]);}/* Output RTL for an arithmetic right shift.  *//* ??? Rewrite to use super-optimizer sequences.  */intexpand_ashiftrt (operands)     rtx *operands;{  rtx wrk;  char func[18];  tree func_name;  int value;  if (TARGET_SH3 && GET_CODE (operands[2]) != CONST_INT)    {      rtx count = copy_to_mode_reg (SImode, operands[2]);      emit_insn (gen_negsi2 (count, count));      emit_insn (gen_ashrsi3_d (operands[0], operands[1], count));      return 1;    }  if (GET_CODE (operands[2]) != CONST_INT)    return 0;  value = INTVAL (operands[2]);  if (value == 31)    {      emit_insn (gen_ashrsi2_31 (operands[0], operands[1]));      return 1;    }  else if (value >= 16 && value <= 19)    {      wrk = gen_reg_rtx (SImode);      emit_insn (gen_ashrsi2_16 (wrk, operands[1]));      value -= 16;      while (value--)	gen_ashift (ASHIFTRT, 1, wrk);      emit_move_insn (operands[0], wrk);      return 1;    }  /* Expand a short sequence inline, longer call a magic routine.  */  else if (value <= 5)    {      wrk = gen_reg_rtx (SImode);      emit_move_insn (wrk, operands[1]);      while (value--)	gen_ashift (ASHIFTRT, 1, wrk);      emit_move_insn (operands[0], wrk);      return 1;    }  wrk = gen_reg_rtx (Pmode);  /* Load the value into an arg reg and call a helper.  */  emit_move_insn (gen_rtx (REG, SImode, 4), operands[1]);  sprintf (func, "__ashiftrt_r4_%d", value);  func_name = get_identifier (func);  emit_move_insn (wrk, gen_rtx (SYMBOL_REF, Pmode,				IDENTIFIER_POINTER (func_name)));  emit_insn (gen_ashrsi3_n (GEN_INT (value), wrk));  emit_move_insn (operands[0], gen_rtx (REG, SImode, 4));  return 1;}/* The SH cannot load a large constant into a register, constants have to   come from a pc relative load.  The reference of a pc relative load   instruction must be less than 1k infront of the instruction.  This   means that we often have to dump a constant inside a function, and   generate code to branch around it.   It is important to minimize this, since the branches will slow things   down and make things bigger.

⌨️ 快捷键说明

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