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

📄 unroll.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 5 页
字号:
      for (j = 0; j < max_labelno; j++)	if (local_label[j])	  map->label_map[j] = gen_label_rtx ();      for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; j++)	if (local_regno[j])	  map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));      /* If loop starts with a branch to the test, then fix it so that	 it points to the test of the first unrolled copy of the loop.  */      if (i == 0 && loop_start != copy_start)	{	  insn = PREV_INSN (copy_start);	  pattern = PATTERN (insn);	  	  tem = map->label_map[CODE_LABEL_NUMBER			       (XEXP (SET_SRC (pattern), 0))];	  SET_SRC (pattern) = gen_rtx (LABEL_REF, VOIDmode, tem);	  /* Set the jump label so that it can be used by later loop unrolling	     passes.  */	  JUMP_LABEL (insn) = tem;	  LABEL_NUSES (tem)++;	}      copy_loop_body (copy_start, copy_end, map, exit_label,		      i == unroll_number - 1, unroll_type, start_label,		      loop_end, insert_before, insert_before);    }  /* Before deleting any insns, emit a CODE_LABEL immediately after the last     insn to be deleted.  This prevents any runaway delete_insn call from     more insns that it should, as it always stops at a CODE_LABEL.  */  /* Delete the compare and branch at the end of the loop if completely     unrolling the loop.  Deleting the backward branch at the end also     deletes the code label at the start of the loop.  This is done at     the very end to avoid problems with back_branch_in_range_p.  */  if (unroll_type == UNROLL_COMPLETELY)    safety_label = emit_label_after (gen_label_rtx (), last_loop_insn);  else    safety_label = emit_label_after (gen_label_rtx (), copy_end);  /* Delete all of the original loop instructions.  Don't delete the      LOOP_BEG note, or the first code label in the loop.  */  insn = NEXT_INSN (copy_start);  while (insn != safety_label)    {      if (insn != start_label)	insn = delete_insn (insn);      else	insn = NEXT_INSN (insn);    }  /* Can now delete the 'safety' label emitted to protect us from runaway     delete_insn calls.  */  if (INSN_DELETED_P (safety_label))    abort ();  delete_insn (safety_label);  /* If exit_label exists, emit it after the loop.  Doing the emit here     forces it to have a higher INSN_UID than any insn in the unrolled loop.     This is needed so that mostly_true_jump in reorg.c will treat jumps     to this loop end label correctly, i.e. predict that they are usually     not taken.  */  if (exit_label)    emit_label_after (exit_label, loop_end);}/* Return true if the loop can be safely, and profitably, preconditioned   so that the unrolled copies of the loop body don't need exit tests.   This only works if final_value, initial_value and increment can be   determined, and if increment is a constant power of 2.   If increment is not a power of 2, then the preconditioning modulo   operation would require a real modulo instead of a boolean AND, and this   is not considered `profitable'.  *//* ??? If the loop is known to be executed very many times, or the machine   has a very cheap divide instruction, then preconditioning is a win even   when the increment is not a power of 2.  Use RTX_COST to compute   whether divide is cheap.  */static intprecondition_loop_p (initial_value, final_value, increment, loop_start,		     loop_end)     rtx *initial_value, *final_value, *increment;     rtx loop_start, loop_end;{  if (loop_n_iterations > 0)    {      *initial_value = const0_rtx;      *increment = const1_rtx;      *final_value = GEN_INT (loop_n_iterations);      if (loop_dump_stream)	fprintf (loop_dump_stream,		 "Preconditioning: Success, number of iterations known, %d.\n",		 loop_n_iterations);      return 1;    }  if (loop_initial_value == 0)    {      if (loop_dump_stream)	fprintf (loop_dump_stream,		 "Preconditioning: Could not find initial value.\n");      return 0;    }  else if (loop_increment == 0)    {      if (loop_dump_stream)	fprintf (loop_dump_stream,		 "Preconditioning: Could not find increment value.\n");      return 0;    }  else if (GET_CODE (loop_increment) != CONST_INT)    {      if (loop_dump_stream)	fprintf (loop_dump_stream,		 "Preconditioning: Increment not a constant.\n");      return 0;    }  else if ((exact_log2 (INTVAL (loop_increment)) < 0)	   && (exact_log2 (- INTVAL (loop_increment)) < 0))    {      if (loop_dump_stream)	fprintf (loop_dump_stream,		 "Preconditioning: Increment not a constant power of 2.\n");      return 0;    }  /* Unsigned_compare and compare_dir can be ignored here, since they do     not matter for preconditioning.  */  if (loop_final_value == 0)    {      if (loop_dump_stream)	fprintf (loop_dump_stream,		 "Preconditioning: EQ comparison loop.\n");      return 0;    }  /* Must ensure that final_value is invariant, so call invariant_p to     check.  Before doing so, must check regno against max_reg_before_loop     to make sure that the register is in the range covered by invariant_p.     If it isn't, then it is most likely a biv/giv which by definition are     not invariant.  */  if ((GET_CODE (loop_final_value) == REG       && REGNO (loop_final_value) >= max_reg_before_loop)      || (GET_CODE (loop_final_value) == PLUS	  && REGNO (XEXP (loop_final_value, 0)) >= max_reg_before_loop)      || ! invariant_p (loop_final_value))    {      if (loop_dump_stream)	fprintf (loop_dump_stream,		 "Preconditioning: Final value not invariant.\n");      return 0;    }  /* Fail for floating point values, since the caller of this function     does not have code to deal with them.  */  if (GET_MODE_CLASS (GET_MODE (loop_final_value)) == MODE_FLOAT      || GET_MODE_CLASS (GET_MODE (loop_initial_value)) == MODE_FLOAT)    {      if (loop_dump_stream)	fprintf (loop_dump_stream,		 "Preconditioning: Floating point final or initial value.\n");      return 0;    }  /* Now set initial_value to be the iteration_var, since that may be a     simpler expression, and is guaranteed to be correct if all of the     above tests succeed.     We can not use the initial_value as calculated, because it will be     one too small for loops of the form "while (i-- > 0)".  We can not     emit code before the loop_skip_over insns to fix this problem as this     will then give a number one too large for loops of the form     "while (--i > 0)".     Note that all loops that reach here are entered at the top, because     this function is not called if the loop starts with a jump.  */  /* Fail if loop_iteration_var is not live before loop_start, since we need     to test its value in the preconditioning code.  */  if (uid_luid[regno_first_uid[REGNO (loop_iteration_var)]]      > INSN_LUID (loop_start))    {      if (loop_dump_stream)	fprintf (loop_dump_stream,		 "Preconditioning: Iteration var not live before loop start.\n");      return 0;    }  *initial_value = loop_iteration_var;  *increment = loop_increment;  *final_value = loop_final_value;  /* Success! */  if (loop_dump_stream)    fprintf (loop_dump_stream, "Preconditioning: Successful.\n");  return 1;}/* All pseudo-registers must be mapped to themselves.  Two hard registers   must be mapped, VIRTUAL_STACK_VARS_REGNUM and VIRTUAL_INCOMING_ARGS_   REGNUM, to avoid function-inlining specific conversions of these   registers.  All other hard regs can not be mapped because they may be   used with different   modes.  */static voidinit_reg_map (map, maxregnum)     struct inline_remap *map;     int maxregnum;{  int i;  for (i = maxregnum - 1; i > LAST_VIRTUAL_REGISTER; i--)    map->reg_map[i] = regno_reg_rtx[i];  /* Just clear the rest of the entries.  */  for (i = LAST_VIRTUAL_REGISTER; i >= 0; i--)    map->reg_map[i] = 0;  map->reg_map[VIRTUAL_STACK_VARS_REGNUM]    = regno_reg_rtx[VIRTUAL_STACK_VARS_REGNUM];  map->reg_map[VIRTUAL_INCOMING_ARGS_REGNUM]    = regno_reg_rtx[VIRTUAL_INCOMING_ARGS_REGNUM];}/* Strength-reduction will often emit code for optimized biv/givs which   calculates their value in a temporary register, and then copies the result   to the iv.  This procedure reconstructs the pattern computing the iv;   verifying that all operands are of the proper form.   The return value is the amount that the giv is incremented by.  */static rtxcalculate_giv_inc (pattern, src_insn, regno)     rtx pattern, src_insn;     int regno;{  rtx increment;  rtx increment_total = 0;  int tries = 0; retry:  /* Verify that we have an increment insn here.  First check for a plus     as the set source.  */  if (GET_CODE (SET_SRC (pattern)) != PLUS)    {      /* SR sometimes computes the new giv value in a temp, then copies it	 to the new_reg.  */      src_insn = PREV_INSN (src_insn);      pattern = PATTERN (src_insn);      if (GET_CODE (SET_SRC (pattern)) != PLUS)	abort ();		        /* The last insn emitted is not needed, so delete it to avoid confusing	 the second cse pass.  This insn sets the giv unnecessarily.  */      delete_insn (get_last_insn ());    }  /* Verify that we have a constant as the second operand of the plus.  */  increment = XEXP (SET_SRC (pattern), 1);  if (GET_CODE (increment) != CONST_INT)    {      /* SR sometimes puts the constant in a register, especially if it is	 too big to be an add immed operand.  */      src_insn = PREV_INSN (src_insn);      increment = SET_SRC (PATTERN (src_insn));      /* SR may have used LO_SUM to compute the constant if it is too large	 for a load immed operand.  In this case, the constant is in operand	 one of the LO_SUM rtx.  */      if (GET_CODE (increment) == LO_SUM)	increment = XEXP (increment, 1);      else if (GET_CODE (increment) == IOR	       || GET_CODE (increment) == ASHIFT)	{	  /* The rs6000 port loads some constants with IOR.	     The alpha port loads some constants with ASHIFT.  */	  rtx second_part = XEXP (increment, 1);	  enum rtx_code code = GET_CODE (increment);	  src_insn = PREV_INSN (src_insn);	  increment = SET_SRC (PATTERN (src_insn));	  /* Don't need the last insn anymore.  */	  delete_insn (get_last_insn ());	  if (GET_CODE (second_part) != CONST_INT	      || GET_CODE (increment) != CONST_INT)	    abort ();	  if (code == IOR)	    increment = GEN_INT (INTVAL (increment) | INTVAL (second_part));	  else	    increment = GEN_INT (INTVAL (increment) << INTVAL (second_part));	}      if (GET_CODE (increment) != CONST_INT)	abort ();		        /* The insn loading the constant into a register is no longer needed,	 so delete it.  */      delete_insn (get_last_insn ());    }  if (increment_total)    increment_total = GEN_INT (INTVAL (increment_total) + INTVAL (increment));  else    increment_total = increment;  /* Check that the source register is the same as the register we expected     to see as the source.  If not, something is seriously wrong.  */  if (GET_CODE (XEXP (SET_SRC (pattern), 0)) != REG      || REGNO (XEXP (SET_SRC (pattern), 0)) != regno)    {      /* Some machines (e.g. the romp), may emit two add instructions for	 certain constants, so lets try looking for another add immediately	 before this one if we have only seen one add insn so far.  */      if (tries == 0)	{	  tries++;	  src_insn = PREV_INSN (src_insn);	  pattern = PATTERN (src_insn);	  delete_insn (get_last_insn ());	  goto retry;	}      abort ();    }  return increment_total;}/* Copy REG_NOTES, except for insn references, because not all insn_map   entries are valid yet.  We do need to copy registers now though, because   the reg_map entries can change during copying.  */static rtxinitial_reg_note_copy (notes, map)     rtx notes;     struct inline_remap *map;{  rtx copy;  if (notes == 0)    return 0;  copy = rtx_alloc (GET_CODE (notes));  PUT_MODE (copy, GET_MODE (notes));  if (GET_CODE (notes) == EXPR_LIST)    XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (notes, 0), map);  else if (GET_CODE (notes) == INSN_LIST)    /* Don't substitute for these yet.  */    XEXP (copy, 0) = XEXP (notes, 0);  else    abort ();  XEXP (copy, 1) = initial_reg_note_copy (XEXP (notes, 1), map);  return copy;}/* Fixup insn references in copied REG_NOTES.  */

⌨️ 快捷键说明

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