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

📄 reg-stack.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
	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])))	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. */voidrecord_reg_life_pat (pat, src, dest)     rtx pat;     HARD_REG_SET *src, *dest;{  register char *fmt;  register int i;  if (STACK_REG_P (pat))    {      if (src)	SET_HARD_REG_BIT (*src, REGNO (pat));      if (dest)	SET_HARD_REG_BIT (*dest, REGNO (pat));      return;    }  if (GET_CODE (pat) == SET)    {      record_reg_life_pat (XEXP (pat, 0), NULL_PTR, dest);      record_reg_life_pat (XEXP (pat, 1), src, NULL_PTR);      return;    }  /* We don't need to consider either of these cases. */  if (GET_CODE (pat) == USE || 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);	}      else if (fmt[i] == 'e')	record_reg_life_pat (XEXP (pat, i), src, dest);    }}/* 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;    }  /* An insn referencing a stack reg has a mode of QImode. */  if (GET_MODE (insn) == QImode)    {      HARD_REG_SET src, dest;      int regno;      CLEAR_HARD_REG_SET (src);      CLEAR_HARD_REG_SET (dest);      record_reg_life_pat (PATTERN (insn), &src, &dest);      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][(int) 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][(int) DFmode],					  REG_NOTES (insn));	  }      AND_COMPL_HARD_REG_SET (regstack->reg_set, dest);      IOR_HARD_REG_SET (regstack->reg_set, src);    }  /* 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(). */  if (GET_CODE (insn) == CALL_INSN)    {      int reg = FIRST_FLOAT_REG;      /* If a stack reg is mentioned in a CALL_INSN, it must be as the	 return value.  */      if (stack_regs_mentioned_p (PATTERN (insn)))	reg++;      for (; reg <= LAST_STACK_REG; reg++)	if (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][(int) 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);    }}/* 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;  /* 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. */      code = GET_CODE (insn);      if (code == CODE_LABEL	  || (prev_code != INSN	      && prev_code != CALL_INSN	      && prev_code != CODE_LABEL	      && (code == INSN || code == CALL_INSN || code == JUMP_INSN)))	{	  block_begin[++block] = insn;	  block_end[block] = insn;	  block_drops_in[block] = prev_code != BARRIER;	}      else if (code == INSN || code == CALL_INSN || code == JUMP_INSN)	block_end[block] = insn;      BLOCK_NUM (insn) = block;      if (code == CODE_LABEL)	LABEL_REFS (insn) = insn; /* delete old chain */      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)	record_label_references (insn, PATTERN (insn));    }}/* Determine the which registers are live at the start of each basic   block of the function whose first insn is FIRST.   First, if the function returns a real_type, mark the function   return type as live at each return point, as the RTL may not give any   hint that the register is live.   Then, start with the last block and work back to the first block.   Similarly, work backwards within each block, insn by insn, recording   which regs are die and which are used (and therefore live) in the   hard reg set of block_stack_in[].   After processing each basic block, if there is a label at the start   of the block, propagate the live registers to all jumps to this block.   As a special case, if there are regs live in this block, that are   not live in a block containing a jump to this label, and the block   containing the jump has already been processed, we must propagate this   block's entry register life back to the block containing the jump, and   restart life analysis from there.   In the worst case, this function may traverse the insns   REG_STACK_SIZE times.  This is necessary, since a jump towards the end   of the insns may not know that a reg is live at a target that is early   in the insns.  So we back up and start over with the new reg live.   If there are registers that are live at the start of the function,   insns are emitted to initialize these registers.  Something similar is   done after CALL_INSNs in record_reg_life. */static voidstack_reg_life_analysis (first)     rtx first;{  int reg, block;  struct stack_def regstack;  if (current_function_returns_real      && STACK_REG_P (DECL_RTL (DECL_RESULT (current_function_decl))))    {      /* Find all RETURN insns and mark them. */      int value_regno = REGNO (DECL_RTL (DECL_RESULT (current_function_decl)));      for (block = blocks - 1; block >= 0; block--)	if (GET_CODE (block_end[block]) == JUMP_INSN	    && GET_CODE (PATTERN (block_end[block])) == RETURN)	  SET_HARD_REG_BIT (block_out_reg_set[block], value_regno);      /* Mark of the end of last block if we "fall off" the end of the	 function into the epilogue. */      if (GET_CODE (block_end[blocks-1]) != JUMP_INSN	  || GET_CODE (PATTERN (block_end[blocks-1])) == RETURN)	SET_HARD_REG_BIT (block_out_reg_set[blocks-1], value_regno);    }  /* now scan all blocks backward for stack register use */  block = blocks - 1;  while (block >= 0)    {      register rtx insn, prev;      /* current register status at last instruction */      COPY_HARD_REG_SET (regstack.reg_set, block_out_reg_set[block]);      prev = block_end[block];      do	{	  insn = prev;	  prev = PREV_INSN (insn);	  /* If the insn is a CALL_INSN, we need to ensure that	     everything dies.  But otherwise don't process unless there	     are some stack regs present. */	  if (GET_MODE (insn) == QImode || GET_CODE (insn) == CALL_INSN)	    record_reg_life (insn, block, &regstack);	} while (insn != block_begin[block]);      /* Set the state at the start of the block.  Mark that no	 register mapping information known yet. */      COPY_HARD_REG_SET (block_stack_in[block].reg_set, regstack.reg_set);      block_stack_in[block].top = -2;      /* If there is a label, propagate our register life to all jumps	 to this label. */      if (GET_CODE (insn) == CODE_LABEL)	{	  register rtx label;	  int must_restart = 0;	  for (label = LABEL_REFS (insn); label != insn;	       label = LABEL_NEXTREF (label))	    {	      int jump_block = BLOCK_NUM (CONTAINING_INSN (label));	      if (jump_block < block)		IOR_HARD_REG_SET (block_out_reg_set[jump_block],				  block_stack_in[block].reg_set);	      else		{		  /* The block containing the jump has already been		     processed.  If there are registers that were not known		     to be live then, but are live now, we must back up		     and restart life analysis from that point with the new		     life information. */		  GO_IF_HARD_REG_SUBSET (block_stack_in[block].reg_set,					 block_out_reg_set[jump_block],

⌨️ 快捷键说明

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