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

📄 reg-stack.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 5 页
字号:
		clobber_reg[n_clobbers] = reg;		n_clobbers++;	      }	  }    }  /* Enforce rule #4: Output operands must specifically indicate which     reg an output appears in after an asm.  "=f" is not allowed: the     operand constraints must select a class with a single reg.     Also enforce rule #5: Output operands must start at the top of     the reg-stack: output operands may not "skip" a reg. */  bzero ((char *) reg_used_as_output, sizeof (reg_used_as_output));  for (i = 0; i < n_outputs; i++)    if (STACK_REG_P (operands[i]))      if (reg_class_size[(int) operand_class[i]] != 1)	{	  error_for_asm	    (insn, "Output constraint %d must specify a single register", i);	  malformed_asm = 1;	}      else	reg_used_as_output[REGNO (operands[i])] = 1;  /* Search for first non-popped reg.  */  for (i = FIRST_STACK_REG; i < LAST_STACK_REG + 1; i++)    if (! reg_used_as_output[i])      break;  /* If there are any other popped regs, that's an error.  */  for (; i < LAST_STACK_REG + 1; i++)    if (reg_used_as_output[i])      break;  if (i != LAST_STACK_REG + 1)    {      error_for_asm (insn, "Output regs must be grouped at top of stack");      malformed_asm = 1;    }  /* Enforce rule #2: All implicitly popped input regs must be closer     to the top of the reg-stack than any input that is not implicitly     popped. */  bzero ((char *) implicitly_dies, sizeof (implicitly_dies));  for (i = first_input; i < first_input + n_inputs; i++)    if (STACK_REG_P (operands[i]))      {	/* An input reg is implicitly popped if it is tied to an	   output, or if there is a CLOBBER for it. */	int j;	for (j = 0; j < n_clobbers; j++)	  if (operands_match_p (clobber_reg[j], operands[i]))	    break;	if (j < n_clobbers || operand_matches[i] >= 0)	  implicitly_dies[REGNO (operands[i])] = 1;      }  /* Search for first non-popped reg.  */  for (i = FIRST_STACK_REG; i < LAST_STACK_REG + 1; i++)    if (! implicitly_dies[i])      break;  /* If there are any other popped regs, that's an error.  */  for (; i < LAST_STACK_REG + 1; i++)    if (implicitly_dies[i])      break;  if (i != LAST_STACK_REG + 1)    {      error_for_asm (insn,		     "Implicitly popped regs must be grouped at top of stack");      malformed_asm = 1;    }  /* Enfore rule #3: If any input operand uses the "f" constraint, all     output constraints must use the "&" earlyclobber.     ???  Detect this more deterministically by having constraint_asm_operands     record any earlyclobber. */  for (i = first_input; i < first_input + n_inputs; i++)    if (operand_matches[i] == -1)      {	int j;	for (j = 0; j < n_outputs; j++)	  if (operands_match_p (operands[j], operands[i]))	    {	      error_for_asm (insn,			     "Output operand %d must use `&' constraint", j);	      malformed_asm = 1;	    }      }  if (malformed_asm)    {      /* Avoid further trouble with this insn.  */      PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);      PUT_MODE (insn, VOIDmode);      return;    }  /* Process all outputs */  for (i = 0; i < n_outputs; i++)    {      rtx op = operands[i];      if (! STACK_REG_P (op))	if (stack_regs_mentioned_p (op))	  abort ();	else	  continue;      /* Each destination is dead before this insn.  If the	 destination is not used after this insn, record this with	 REG_UNUSED.  */      if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (op)))	REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_UNUSED, op,				    REG_NOTES (insn));      CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (op));    }  /* Process all inputs */  for (i = first_input; i < first_input + n_inputs; i++)    {      if (! STACK_REG_P (operands[i]))	if (stack_regs_mentioned_p (operands[i]))	  abort ();	else	  continue;      /* If an input is dead after the insn, record a death note.	 But don't record a death note if there is already a death note,	 or if the input is also an output.  */      if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i]))	  && operand_matches[i] == -1	  && find_regno_note (insn, REG_DEAD, REGNO (operands[i])) == NULL_RTX)	REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD, operands[i],				    REG_NOTES (insn));      SET_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i]));    }}/* Scan PAT, which is part of INSN, and record registers appearing in   a SET_DEST in DEST, and other registers in SRC.   This function does not know about SET_DESTs that are both input and   output (such as ZERO_EXTRACT) - this cannot happen on a 387. */static voidrecord_reg_life_pat (pat, src, dest, douse)     rtx pat;     HARD_REG_SET *src, *dest;     int douse;{  register char *fmt;  register int i;  if (STACK_REG_P (pat)      || GET_CODE (pat) == SUBREG && STACK_REG_P (SUBREG_REG (pat)))    {      if (src)	 mark_regs_pat (pat, src);      if (dest)	 mark_regs_pat (pat, dest);      return;    }  if (GET_CODE (pat) == SET)    {      record_reg_life_pat (XEXP (pat, 0), NULL_PTR, dest, 0);      record_reg_life_pat (XEXP (pat, 1), src, NULL_PTR, 0);      return;    }  /* We don't need to consider either of these cases. */  if (GET_CODE (pat) == USE && !douse || GET_CODE (pat) == CLOBBER)    return;  fmt = GET_RTX_FORMAT (GET_CODE (pat));  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)    {      if (fmt[i] == 'E')	{	  register int j;	  for (j = XVECLEN (pat, i) - 1; j >= 0; j--)	    record_reg_life_pat (XVECEXP (pat, i, j), src, dest, 0);	}      else if (fmt[i] == 'e')	record_reg_life_pat (XEXP (pat, i), src, dest, 0);    }}/* Calculate the number of inputs and outputs in BODY, an   asm_operands.  N_OPERANDS is the total number of operands, and   N_INPUTS and N_OUTPUTS are pointers to ints into which the results are   placed. */static voidget_asm_operand_lengths (body, n_operands, n_inputs, n_outputs)     rtx body;     int n_operands;     int *n_inputs, *n_outputs;{  if (GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == ASM_OPERANDS)    *n_inputs = ASM_OPERANDS_INPUT_LENGTH (SET_SRC (body));  else if (GET_CODE (body) == ASM_OPERANDS)    *n_inputs = ASM_OPERANDS_INPUT_LENGTH (body);  else if (GET_CODE (body) == PARALLEL	   && GET_CODE (XVECEXP (body, 0, 0)) == SET)    *n_inputs = ASM_OPERANDS_INPUT_LENGTH (SET_SRC (XVECEXP (body, 0, 0)));  else if (GET_CODE (body) == PARALLEL	   && GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS)    *n_inputs = ASM_OPERANDS_INPUT_LENGTH (XVECEXP (body, 0, 0));  else    abort ();  *n_outputs = n_operands - *n_inputs;}/* Scan INSN, which is in BLOCK, and record the life & death of stack   registers in REGSTACK.  This function is called to process insns from   the last insn in a block to the first.  The actual scanning is done in   record_reg_life_pat.   If a register is live after a CALL_INSN, but is not a value return   register for that CALL_INSN, then code is emitted to initialize that   register.  The block_end[] data is kept accurate.   Existing death and unset notes for stack registers are deleted   before processing the insn. */static voidrecord_reg_life (insn, block, regstack)     rtx insn;     int block;     stack regstack;{  rtx note, *note_link;  int n_operands;  if ((GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)      || INSN_DELETED_P (insn))    return;  /* Strip death notes for stack regs from this insn */  note_link = &REG_NOTES(insn);  for (note = *note_link; note; note = XEXP (note, 1))    if (STACK_REG_P (XEXP (note, 0))	&& (REG_NOTE_KIND (note) == REG_DEAD	    || REG_NOTE_KIND (note) == REG_UNUSED))      *note_link = XEXP (note, 1);    else      note_link = &XEXP (note, 1);  /* Process all patterns in the insn. */  n_operands = asm_noperands (PATTERN (insn));  if (n_operands >= 0)    {      /* This insn is an `asm' with operands.  Decode the operands,	 decide how many are inputs, and record the life information. */      rtx operands[MAX_RECOG_OPERANDS];      rtx body = PATTERN (insn);      int n_inputs, n_outputs;      char **constraints = (char **) alloca (n_operands * sizeof (char *));      decode_asm_operands (body, operands, NULL_PTR, constraints, NULL_PTR);      get_asm_operand_lengths (body, n_operands, &n_inputs, &n_outputs);      record_asm_reg_life (insn, regstack, operands, constraints,			   n_inputs, n_outputs);      return;    }    {      HARD_REG_SET src, dest;      int regno;      CLEAR_HARD_REG_SET (src);      CLEAR_HARD_REG_SET (dest);      if (GET_CODE (insn) == CALL_INSN)	 for (note = CALL_INSN_FUNCTION_USAGE (insn);	      note;	      note = XEXP (note, 1))	   if (GET_CODE (XEXP (note, 0)) == USE)	     record_reg_life_pat (SET_DEST (XEXP (note, 0)), &src, NULL_PTR, 0);      record_reg_life_pat (PATTERN (insn), &src, &dest, 0);      for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++)	if (! TEST_HARD_REG_BIT (regstack->reg_set, regno))	  {	    if (TEST_HARD_REG_BIT (src, regno)		&& ! TEST_HARD_REG_BIT (dest, regno))	      REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,					  FP_MODE_REG (regno, DFmode),					  REG_NOTES (insn));	    else if (TEST_HARD_REG_BIT (dest, regno))	      REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_UNUSED,					  FP_MODE_REG (regno, DFmode),					  REG_NOTES (insn));	  }      if (GET_CODE (insn) == CALL_INSN)        {	  int reg;          /* There might be a reg that is live after a function call.             Initialize it to zero so that the program does not crash.  See	     comment towards the end of stack_reg_life_analysis(). */          for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++)	    if (! TEST_HARD_REG_BIT (dest, reg)	        && TEST_HARD_REG_BIT (regstack->reg_set, reg))	      {	        rtx init, pat;	        /* The insn will use virtual register numbers, and so	           convert_regs is expected to process these.  But BLOCK_NUM	           cannot be used on these insns, because they do not appear in	           block_number[]. */	        pat = gen_rtx (SET, VOIDmode, FP_MODE_REG (reg, DFmode),			       CONST0_RTX (DFmode));	        init = emit_insn_after (pat, insn);	        PUT_MODE (init, QImode);	        CLEAR_HARD_REG_BIT (regstack->reg_set, reg);	        /* If the CALL_INSN was the end of a block, move the	           block_end to point to the new insn. */	        if (block_end[block] == insn)	          block_end[block] = init;	      }	  /* Some regs do not survive a CALL */          AND_COMPL_HARD_REG_SET (regstack->reg_set, call_used_reg_set);	}      AND_COMPL_HARD_REG_SET (regstack->reg_set, dest);      IOR_HARD_REG_SET (regstack->reg_set, src);    }}/* Find all basic blocks of the function, which starts with FIRST.   For each JUMP_INSN, build the chain of LABEL_REFS on each CODE_LABEL. */static voidfind_blocks (first)     rtx first;{  register rtx insn;  register int block;  register RTX_CODE prev_code = BARRIER;  register RTX_CODE code;  rtx label_value_list = 0;  /* Record where all the blocks start and end.     Record which basic blocks control can drop in to. */  block = -1;  for (insn = first; insn; insn = NEXT_INSN (insn))    {      /* Note that this loop must select the same block boundaries	 as code in reg_to_stack, but that these are not the same	 as those selected in flow.c.  */      code = GET_CODE (insn);      if (code == CODE_LABEL	  || (prev_code != INSN	      && prev_code != CALL_INSN	      && prev_code != CODE_LABEL	      && GET_RTX_CLASS (code) == 'i'))	{	  block_begin[++block] = insn;	  block_end[block] = insn;	  block_drops_in[block] = prev_code != BARRIER;	}      else if (GET_RTX_CLASS (code) == 'i')	block_end[block] = insn;      if (GET_RTX_CLASS (code) == 'i')	{	  rtx note;	  /* Make a list of all labels referred to other than by jumps.  */	  for (note = REG_NOTES (insn); note; note = XEXP (note, 1))	    if (REG_NOTE_KIND (note) == REG_LABEL)	      label_value_list = gen_rtx (EXPR_LIST, VOIDmode, XEXP (note, 0),					  label_value_list);	}      block_number[INSN_UID (insn)] = block;      if (code != NOTE)	prev_code = code;    }  if (block + 1 != blocks)    abort ();  /* generate all label references to the corresponding jump insn */  for (block = 0; block < blocks; block++)    {      insn = block_end[block];      if (GET_CODE (insn) == JUMP_INSN)	{	  rtx pat = PATTERN (insn);	  int computed_jump = 0;	  rtx x;	  if (GET_CODE (pat) == PARALLEL)	    {	      int len = XVECLEN (pat, 0);	      int has_use_labelref = 0;	      int i;	      for (i = len - 1; i >= 0; i--)		if (GET_CODE (XVECEXP (pat, 0, i)) == USE		    && GET_CODE (XEXP (XVECEXP (pat, 0, i), 0)) == LABEL_REF)		  has_use_labelref = 1;	      if (! has_use_labelref)		for (i = len - 1; i >= 0; i--)		  if (GET_CODE (XVECEXP (pat, 0, i)) == SET		      && SET_DEST (XVECEXP (pat, 0, i)) == pc_rtx		      && uses_reg_or_mem (SET_SRC (XVECEXP (pat, 0, i))))		    computed_jump = 1;

⌨️ 快捷键说明

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