📄 reg-stack.c
字号:
}/* Substitute new registers in PAT, which is part of INSN. REGSTACK is the current register layout. */static voidsubst_stack_regs_pat (insn, regstack, pat) rtx insn; stack regstack; rtx pat;{ rtx *dest, *src; rtx *src1 = 0, *src2; rtx src1_note, src2_note; if (GET_CODE (pat) != SET) return; dest = get_true_reg (&SET_DEST (pat)); src = get_true_reg (&SET_SRC (pat)); /* See if this is a `movM' pattern, and handle elsewhere if so. */ if (*dest != cc0_rtx && (STACK_REG_P (*src) || (STACK_REG_P (*dest) && (GET_CODE (*src) == REG || GET_CODE (*src) == MEM || GET_CODE (*src) == CONST_DOUBLE)))) move_for_stack_reg (insn, regstack, pat); else switch (GET_CODE (SET_SRC (pat))) { case COMPARE: compare_for_stack_reg (insn, regstack, pat); break; case CALL: regstack->reg[++regstack->top] = REGNO (*dest); SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest)); replace_reg (dest, FIRST_STACK_REG); break; case REG: /* This is a `tstM2' case. */ if (*dest != cc0_rtx) abort (); src1 = src; /* Fall through. */ case SQRT: case ABS: case NEG: /* These insns only operate on the top of the stack. DEST might be cc0_rtx if we're processing a tstM pattern. Also, it's possible that the tstM case results in a REG_DEAD note on the source. */ if (src1 == 0) src1 = get_true_reg (&XEXP (SET_SRC (pat), 0)); emit_swap_insn (insn, regstack, *src1, emit_insn_before); src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1)); if (STACK_REG_P (*dest)) replace_reg (dest, FIRST_STACK_REG); if (src1_note) { replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG); regstack->top--; CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1)); } replace_reg (src1, FIRST_STACK_REG); break; case MINUS: case DIV: /* On i386, reversed forms of subM3 and divM3 exist for MODE_FLOAT, so the same code that works for addM3 and mulM3 can be used. */ case MULT: case PLUS: /* These insns can accept the top of stack as a destination from a stack reg or mem, or can use the top of stack as a source and some other stack register (possibly top of stack) as a destination. */ src1 = get_true_reg (&XEXP (SET_SRC (pat), 0)); src2 = get_true_reg (&XEXP (SET_SRC (pat), 1)); /* We will fix any death note later. */ if (STACK_REG_P (*src1)) src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1)); else src1_note = 0; if (STACK_REG_P (*src2)) src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2)); else src2_note = 0; /* If either operand is not a stack register, then the dest must be top of stack. */ if (! STACK_REG_P (*src1) || ! STACK_REG_P (*src2)) emit_swap_insn (insn, regstack, *dest, emit_insn_before); else { /* Both operands are REG. If neither operand is already at the top of stack, choose to make the one that is the dest the new top of stack. ??? A later optimization here would be to look forward in the insns and see which source reg will be needed at top of stack soonest. */ int src1_hard_regnum, src2_hard_regnum; src1_hard_regnum = get_hard_regnum (regstack, *src1); src2_hard_regnum = get_hard_regnum (regstack, *src2); if (src1_hard_regnum == -1 || src2_hard_regnum == -1) abort (); if (src1_hard_regnum != FIRST_STACK_REG && src2_hard_regnum != FIRST_STACK_REG) emit_swap_insn (insn, regstack, *dest, emit_insn_before); } if (STACK_REG_P (*src1)) replace_reg (src1, get_hard_regnum (regstack, *src1)); if (STACK_REG_P (*src2)) replace_reg (src2, get_hard_regnum (regstack, *src2)); if (src1_note) { /* If the register that dies is at the top of stack, then the destination is somewhere else - merely substitute it. But if the reg that dies is not at top of stack, then move the top of stack to the dead reg, as though we had done the insn and then a store-with-pop. */ if (REGNO (XEXP (src1_note, 0)) == regstack->reg[regstack->top]) { SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest)); replace_reg (dest, get_hard_regnum (regstack, *dest)); } else { int regno = get_hard_regnum (regstack, XEXP (src1_note, 0)); SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest)); replace_reg (dest, regno); regstack->reg[regstack->top - (regno - FIRST_STACK_REG)] = regstack->reg[regstack->top]; } CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (XEXP (src1_note, 0))); replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG); regstack->top--; } else if (src2_note) { if (REGNO (XEXP (src2_note, 0)) == regstack->reg[regstack->top]) { SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest)); replace_reg (dest, get_hard_regnum (regstack, *dest)); } else { int regno = get_hard_regnum (regstack, XEXP (src2_note, 0)); SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest)); replace_reg (dest, regno); regstack->reg[regstack->top - (regno - FIRST_STACK_REG)] = regstack->reg[regstack->top]; } CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (XEXP (src2_note, 0))); replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG); regstack->top--; } else { SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest)); replace_reg (dest, get_hard_regnum (regstack, *dest)); } break; case UNSPEC: switch (XINT (SET_SRC (pat), 1)) { case 1: /* sin */ case 2: /* cos */ /* These insns only operate on the top of the stack. */ src1 = get_true_reg (&XVECEXP (SET_SRC (pat), 0, 0)); emit_swap_insn (insn, regstack, *src1, emit_insn_before); src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1)); if (STACK_REG_P (*dest)) replace_reg (dest, FIRST_STACK_REG); if (src1_note) { replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG); regstack->top--; CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1)); } replace_reg (src1, FIRST_STACK_REG); break; default: abort (); } break; default: abort (); }}/* Substitute hard regnums for any stack regs in INSN, which has N_INPUTS inputs and N_OUTPUTS outputs. REGSTACK is the stack info before the insn, and is updated with changes made here. CONSTRAINTS is an array of the constraint strings used in the asm statement. OPERANDS is an array of the operands, and OPERANDS_LOC is a parallel array of where the operands were found. The output operands all precede the input operands. There are several requirements and assumptions about the use of stack-like regs in asm statements. These rules are enforced by record_asm_stack_regs; see comments there for details. Any asm_operands left in the RTL at this point may be assume to meet the requirements, since record_asm_stack_regs removes any problem asm. */static voidsubst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints, n_inputs, n_outputs) rtx insn; stack regstack; rtx *operands, **operands_loc; char **constraints; int n_inputs, n_outputs;{ int n_operands = n_inputs + n_outputs; int first_input = n_outputs; rtx body = PATTERN (insn); int *operand_matches = (int *) alloca (n_operands * sizeof (int *)); enum reg_class *operand_class = (enum reg_class *) alloca (n_operands * sizeof (enum reg_class *)); rtx *note_reg; /* Array of note contents */ rtx **note_loc; /* Address of REG field of each note */ enum reg_note *note_kind; /* The type of each note */ rtx *clobber_reg; rtx **clobber_loc; struct stack_def temp_stack; int n_notes; int n_clobbers; rtx note; int i; /* Find out what the constraints required. If no constraint alternative matches, that is a compiler bug: we should have caught such an insn during the life analysis pass (and reload should have caught it regardless). */ i = constrain_asm_operands (n_operands, operands, constraints, operand_matches, operand_class); if (i < 0) abort (); /* Strip SUBREGs here to make the following code simpler. */ for (i = 0; i < n_operands; i++) if (GET_CODE (operands[i]) == SUBREG && GET_CODE (SUBREG_REG (operands[i])) == REG) { operands_loc[i] = & SUBREG_REG (operands[i]); operands[i] = SUBREG_REG (operands[i]); } /* Set up NOTE_REG, NOTE_LOC and NOTE_KIND. */ for (i = 0, note = REG_NOTES (insn); note; note = XEXP (note, 1)) i++; note_reg = (rtx *) alloca (i * sizeof (rtx)); note_loc = (rtx **) alloca (i * sizeof (rtx *)); note_kind = (enum reg_note *) alloca (i * sizeof (enum reg_note)); n_notes = 0; for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) { rtx reg = XEXP (note, 0); rtx *loc = & XEXP (note, 0); if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG) { loc = & SUBREG_REG (reg); reg = SUBREG_REG (reg); } if (STACK_REG_P (reg) && (REG_NOTE_KIND (note) == REG_DEAD || REG_NOTE_KIND (note) == REG_UNUSED)) { note_reg[n_notes] = reg; note_loc[n_notes] = loc; note_kind[n_notes] = REG_NOTE_KIND (note); n_notes++; } } /* Set up CLOBBER_REG and CLOBBER_LOC. */ n_clobbers = 0; if (GET_CODE (body) == PARALLEL) { clobber_reg = (rtx *) alloca (XVECLEN (body, 0) * sizeof (rtx *)); clobber_loc = (rtx **) alloca (XVECLEN (body, 0) * sizeof (rtx **)); for (i = 0; i < XVECLEN (body, 0); i++) if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER) { rtx clobber = XVECEXP (body, 0, i); rtx reg = XEXP (clobber, 0); rtx *loc = & XEXP (clobber, 0); if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG) { loc = & SUBREG_REG (reg); reg = SUBREG_REG (reg); } if (STACK_REG_P (reg)) { clobber_reg[n_clobbers] = reg; clobber_loc[n_clobbers] = loc; n_clobbers++; } } } bcopy (regstack, &temp_stack, sizeof (temp_stack)); /* Put the input regs into the desired place in TEMP_STACK. */ for (i = first_input; i < first_input + n_inputs; i++) if (STACK_REG_P (operands[i]) && reg_class_subset_p (operand_class[i], FLOAT_REGS) && operand_class[i] != FLOAT_REGS) { /* If an operand needs to be in a particular reg in FLOAT_REGS, the constraint was either 't' or 'u'. Since these constraints are for single register classes, and reload guaranteed that operand[i] is already in that class, we can just use REGNO (operands[i]) to know which actual reg this operand needs to be in. */ int regno = get_hard_regnum (&temp_stack, operands[i]); if (regno < 0) abort (); if (regno != REGNO (operands[i])) { /* operands[i] is not in the right place. Find it and swap it with whatever is already in I's place. K is where operands[i] is now. J is where it should be. */ int j, k, temp; k = temp_stack.top - (regno - FIRST_STACK_REG); j = (temp_stack.top - (REGNO (operands[i]) - FIRST_STACK_REG)); temp = temp_stack.reg[k]; temp_stack.reg[k] = temp_stack.reg[j]; temp_stack.reg[j] = temp; } } /* emit insns before INSN to make sure the reg-stack is in the right order. */ change_stack (insn, regstack, &temp_stack, emit_insn_before); /* Make the needed input register substitutions. Do death notes and clobbers too, because these are for inputs, not outputs. */ for (i = first_input; i < first_input + n_inputs; i++) if (STACK_REG_P (operands[i])) { int regnum = get_hard_regnum (regstack, operands[i]); if (regnum < 0) abort (); replace_reg (operands_loc[i], regnum); } for (i = 0; i < n_notes; i++) if (note_kind[i] == REG_DEAD) { int regnum = get_hard_regnum (regstack, note_reg[i]); if (regnum < 0) abort (); replace_reg (note_loc[i], regnum); } for (i = 0; i < n_clobbers; i++) { /* It's OK for a CLOBBER to reference a reg that is not live. Don't try to replace it in that case. */ int regnum = get_hard_regnum (regstack, clobber_reg[i]); if (regnum >= 0) { /* Sigh - clobbers always have QImode. But replace_reg knows that these regs can't be MODE_INT and will abort. Just p
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -