- 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 void
-record_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);
- }
-}
-\f
-/* 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 void
-get_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;
-}
-\f
-/* 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 void
-record_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 = ®_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);
- }
-}
-\f
-/* 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 void
-find_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);
- rtx x;
-
- if (computed_jump_p (insn))
- {
- for (x = label_value_list; x; x = XEXP (x, 1))
- record_label_references (insn,
- gen_rtx_LABEL_REF (VOIDmode,
- XEXP (x, 0)));
-
- for (x = forced_labels; x; x = XEXP (x, 1))
- record_label_references (insn,
- gen_rtx_LABEL_REF (VOIDmode,
- XEXP (x, 0)));
- }
-
- record_label_references (insn, pat);
- }
- }
-}
-
-/* If current function returns its result in an fp stack register,
- return the REG. Otherwise, return 0. */
-
-static rtx
-stack_result (decl)
- tree decl;
-{
- rtx result = DECL_RTL (DECL_RESULT (decl));
-
- if (result != 0
- && ! (GET_CODE (result) == REG
- && REGNO (result) < FIRST_PSEUDO_REGISTER))
- {
-#ifdef FUNCTION_OUTGOING_VALUE
- result
- = FUNCTION_OUTGOING_VALUE (TREE_TYPE (DECL_RESULT (decl)), decl);
-#else
- result = FUNCTION_VALUE (TREE_TYPE (DECL_RESULT (decl)), decl);
-#endif
- }
-
- return result != 0 && STACK_REG_P (result) ? result : 0;
-}
-\f
-/* 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 dead 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 void
-stack_reg_life_analysis (first, stackentry)
- rtx first;
- HARD_REG_SET *stackentry;
-{
- int reg, block;
- struct stack_def regstack;
-
- {
- rtx retvalue;
-
- if ((retvalue = stack_result (current_function_decl)))
- {
- /* Find all RETURN insns and mark them. */
-
- for (block = blocks - 1; --block >= 0;)
- if (GET_CODE (block_end[block]) == JUMP_INSN
- && GET_CODE (PATTERN (block_end[block])) == RETURN)
- mark_regs_pat (retvalue, block_out_reg_set+block);
-
- /* Mark off 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)
- mark_regs_pat (retvalue, block_out_reg_set+blocks-1);
- }
- }
-
- /* 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, ®stack);
-
- } while (insn != block_begin[block]);
-
- /* Set the state at the start of the block. Mark that no
- register mapping information known yet. */