📄 cris.c
字号:
instructions where it does not have any sane sense, but where other flags have meanings. (This includes shifts; the carry is not set by them). Note that there are other parallel constructs we could match, but we don't do that yet. */ if (GET_CODE (exp) == SET) { /* FIXME: Check when this happens. It looks like we should actually do a CC_STATUS_INIT here to be safe. */ if (SET_DEST (exp) == pc_rtx) return; /* Record CC0 changes, so we do not have to output multiple test insns. */ if (SET_DEST (exp) == cc0_rtx) { cc_status.value1 = SET_SRC (exp); cc_status.value2 = 0; /* Handle flags for the special btstq on one bit. */ if (GET_CODE (SET_SRC (exp)) == ZERO_EXTRACT && XEXP (SET_SRC (exp), 1) == const1_rtx) { if (GET_CODE (XEXP (SET_SRC (exp), 0)) == CONST_INT) /* Using cmpq. */ cc_status.flags = CC_INVERTED; else /* A one-bit btstq. */ cc_status.flags = CC_Z_IN_NOT_N; } else cc_status.flags = 0; if (GET_CODE (SET_SRC (exp)) == COMPARE) { if (!REG_P (XEXP (SET_SRC (exp), 0)) && XEXP (SET_SRC (exp), 1) != const0_rtx) /* For some reason gcc will not canonicalize compare operations, reversing the sign by itself if operands are in wrong order. */ /* (But NOT inverted; eq is still eq.) */ cc_status.flags = CC_REVERSED; /* This seems to be overlooked by gcc. FIXME: Check again. FIXME: Is it really safe? */ cc_status.value2 = gen_rtx_MINUS (GET_MODE (SET_SRC (exp)), XEXP (SET_SRC (exp), 0), XEXP (SET_SRC (exp), 1)); } return; } else if (REG_P (SET_DEST (exp)) || (GET_CODE (SET_DEST (exp)) == STRICT_LOW_PART && REG_P (XEXP (SET_DEST (exp), 0)))) { /* A register is set; normally CC is set to show that no test insn is needed. Catch the exceptions. */ /* If not to cc0, then no "set"s in non-natural mode give ok cc0... */ if (GET_MODE_SIZE (GET_MODE (SET_DEST (exp))) > UNITS_PER_WORD || GET_MODE_CLASS (GET_MODE (SET_DEST (exp))) == MODE_FLOAT) { /* ... except add:s and sub:s in DImode. */ if (GET_MODE (SET_DEST (exp)) == DImode && (GET_CODE (SET_SRC (exp)) == PLUS || GET_CODE (SET_SRC (exp)) == MINUS)) { cc_status.flags = 0; cc_status.value1 = SET_DEST (exp); cc_status.value2 = SET_SRC (exp); if (cris_reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) cc_status.value2 = 0; /* Add and sub may set V, which gets us unoptimizable results in "gt" and "le" condition codes. */ cc_status.flags |= CC_NO_OVERFLOW; return; } } else if (SET_SRC (exp) == const0_rtx) { /* There's no CC0 change when clearing a register or memory. Just check for overlap. */ if ((cc_status.value1 && cris_reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))) cc_status.value1 = 0; if ((cc_status.value2 && cris_reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))) cc_status.value2 = 0; return; } else { cc_status.flags = 0; cc_status.value1 = SET_DEST (exp); cc_status.value2 = SET_SRC (exp); if (cris_reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) cc_status.value2 = 0; /* Some operations may set V, which gets us unoptimizable results in "gt" and "le" condition codes. */ if (GET_CODE (SET_SRC (exp)) == PLUS || GET_CODE (SET_SRC (exp)) == MINUS || GET_CODE (SET_SRC (exp)) == NEG) cc_status.flags |= CC_NO_OVERFLOW; return; } } else if (GET_CODE (SET_DEST (exp)) == MEM || (GET_CODE (SET_DEST (exp)) == STRICT_LOW_PART && GET_CODE (XEXP (SET_DEST (exp), 0)) == MEM)) { /* When SET to MEM, then CC is not changed (except for overlap). */ if ((cc_status.value1 && cris_reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))) cc_status.value1 = 0; if ((cc_status.value2 && cris_reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))) cc_status.value2 = 0; return; } } else if (GET_CODE (exp) == PARALLEL) { if (GET_CODE (XVECEXP (exp, 0, 0)) == SET && GET_CODE (XVECEXP (exp, 0, 1)) == SET && REG_P (XEXP (XVECEXP (exp, 0, 1), 0))) { if (REG_P (XEXP (XVECEXP (exp, 0, 0), 0)) && GET_CODE (XEXP (XVECEXP (exp, 0, 0), 1)) == MEM) { /* For "move.S [rx=ry+o],rz", say CC reflects value1=rz and value2=[rx] */ cc_status.value1 = XEXP (XVECEXP (exp, 0, 0), 0); cc_status.value2 = gen_rtx_MEM (GET_MODE (XEXP (XVECEXP (exp, 0, 0), 0)), XEXP (XVECEXP (exp, 0, 1), 0)); cc_status.flags = 0; /* Huh? A side-effect cannot change the destination register. */ if (cris_reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) internal_error ("internal error: sideeffect-insn affecting main effect"); return; } else if ((REG_P (XEXP (XVECEXP (exp, 0, 0), 1)) || XEXP (XVECEXP (exp, 0, 0), 1) == const0_rtx) && GET_CODE (XEXP (XVECEXP (exp, 0, 0), 0)) == MEM) { /* For "move.S rz,[rx=ry+o]" and "clear.S [rx=ry+o]", say flags are not changed, except for overlap. */ if (cc_status.value1 && cris_reg_overlap_mentioned_p (XEXP (XVECEXP (exp, 0, 0), 0), cc_status.value1)) cc_status.value1 = 0; if (cc_status.value1 && cris_reg_overlap_mentioned_p (XEXP (XVECEXP (exp, 0, 1), 0), cc_status.value1)) cc_status.value1 = 0; if (cc_status.value2 && cris_reg_overlap_mentioned_p (XEXP (XVECEXP (exp, 0, 0), 0), cc_status.value2)) cc_status.value2 = 0; if (cc_status.value2 && cris_reg_overlap_mentioned_p (XEXP (XVECEXP (exp, 0, 1), 0), cc_status.value2)) cc_status.value2 = 0; return; } } } break; default: /* Unknown cc_attr value. */ abort (); } CC_STATUS_INIT;}/* Return != 0 if the return sequence for the current function is short, like "ret" or "jump [sp+]". Prior to reloading, we can't tell how many registers must be saved, so return 0 then. */intcris_simple_epilogue (){ int regno; int reglimit = STACK_POINTER_REGNUM; int lastreg = -1; if (! reload_completed || frame_pointer_needed || get_frame_size () != 0 || current_function_pretend_args_size || current_function_args_size || current_function_outgoing_args_size || current_function_calls_eh_return /* If we're not supposed to emit prologue and epilogue, we must not emit return-type instructions. */ || !TARGET_PROLOGUE_EPILOGUE) return 0; /* We allow a "movem [sp+],rN" to sit in front if the "jump [sp+]" or in the delay-slot of the "ret". */ for (regno = 0; regno < reglimit; regno++) if ((regs_ever_live[regno] && ! call_used_regs[regno]) || (regno == (int) PIC_OFFSET_TABLE_REGNUM && (current_function_uses_pic_offset_table /* It is saved anyway, if there would be a gap. */ || (flag_pic && regs_ever_live[regno + 1] && !call_used_regs[regno + 1])))) { if (lastreg != regno - 1) return 0; lastreg = regno; } return 1;}/* The ADDRESS_COST worker. */intcris_address_cost (x) rtx x;{ /* The metric to use for the cost-macros is unclear. The metric used here is (the number of cycles needed) / 2, where we consider equal a cycle for a word of code and a cycle to read memory. */ /* The cheapest addressing modes get 0, since nothing extra is needed. */ if (BASE_OR_AUTOINCR_P (x)) return 0; /* An indirect mem must be a DIP. This means two bytes extra for code, and 4 bytes extra for memory read, i.e. (2 + 4) / 2. */ if (GET_CODE (x) == MEM) return (2 + 4) / 2; /* Assume (2 + 4) / 2 for a single constant; a dword, since it needs an extra DIP prefix and 4 bytes of constant in most cases. For PIC and a symbol with a GOT entry, we double the cost since we add a [rPIC+...] offset. A GOT-less symbol uses a BDAP prefix equivalent to the DIP prefix for non-PIC, hence the same cost. */ if (CONSTANT_P (x)) return flag_pic && cris_got_symbol (x) ? 2 * (2 + 4) / 2 : (2 + 4) / 2; /* Handle BIAP and BDAP prefixes. */ if (GET_CODE (x) == PLUS) { rtx tem1 = XEXP (x, 0); rtx tem2 = XEXP (x, 1); /* A BIAP is 2 extra bytes for the prefix insn, nothing more. We recognize the typical MULT which is always in tem1 because of insn canonicalization. */ if ((GET_CODE (tem1) == MULT && BIAP_INDEX_P (tem1)) || REG_P (tem1)) return 2 / 2; /* A BDAP (quick) is 2 extra bytes. Any constant operand to the PLUS is always found in tem2. */ if (GET_CODE (tem2) == CONST_INT && INTVAL (tem2) < 128 && INTVAL (tem2) >= -128) return 2 / 2; /* A BDAP -32768 .. 32767 is like BDAP quick, but with 2 extra bytes. */ if (GET_CODE (tem2) == CONST_INT && CONST_OK_FOR_LETTER_P (INTVAL (tem2), 'L')) return (2 + 2) / 2; /* A BDAP with some other constant is 2 bytes extra. */ if (CONSTANT_P (tem2)) return (2 + 2 + 2) / 2; /* BDAP with something indirect should have a higher cost than BIAP with register. FIXME: Should it cost like a MEM or more? */ /* Don't need to check it, it's the only one left. FIXME: There was a REG test missing, perhaps there are others. Think more. */ return (2 + 2 + 2) / 2; } /* What else? Return a high cost. It matters only for valid addressing modes. */ return 10;}/* Check various objections to the side-effect. Used in the test-part of an anonymous insn describing an insn with a possible side-effect. Returns nonzero if the implied side-effect is ok. code : PLUS or MULT ops : An array of rtx:es. lreg, rreg, rval, The variables multop and other_op are indexes into this, or -1 if they are not applicable. lreg : The register that gets assigned in the side-effect. rreg : One register in the side-effect expression rval : The other register, or an int. multop : An integer to multiply rval with. other_op : One of the entities of the main effect, whose mode we must consider. */intcris_side_effect_mode_ok (code, ops, lreg, rreg, rval, multop, other_op) enum rtx_code code; rtx *ops; int lreg, rreg, rval, multop, other_op;{ /* Find what value to multiply with, for rx =ry + rz * n. */ int mult = multop < 0 ? 1 : INTVAL (ops[multop]); rtx reg_rtx = ops[rreg]; rtx val_rtx = ops[rval]; /* The operands may be swapped. Canonicalize them in reg_rtx and val_rtx, where reg_rtx always is a reg (for this constraint to match). */ if (! BASE_P (reg_rtx)) reg_rtx = val_rtx, val_rtx = ops[rreg]; /* Don't forget to check that reg_rtx really is a reg. If it isn't, we have no business. */ if (! BASE_P (reg_rtx)) return 0; /* Don't do this when -mno-split. */ if (!TARGET_SIDE_EFFECT_PREFIXES) return 0; /* The mult expression may be hidden in lreg. FIXME: Add more commentary about that. */ if (GET_CODE (val_rtx) == MULT) { mult = INTVAL (XEXP (val_rtx, 1)); val_rtx = XEXP (val_rtx, 0); code = MULT; } /* First check the "other operand". */ if (other_op >= 0) { if (GET_MODE_SIZE (GET_MODE (ops[other_op])) > UNITS_PER_WORD) return 0; /* Check if the lvalue register is the same as the "other operand". If so, the result is undefined and we shouldn't do this. FIXME: Check again. */ if ((BASE_P (ops[lreg]) && BASE_P (ops[other_op]) && REGNO (ops[lreg]) == REGNO (ops[other_op])) || rtx_equal_p (ops[other_op], ops[lreg])) return 0; } /* Do not accept frame_pointer_rtx as any operand. */ if (ops[lreg] == frame_pointer_rtx || ops[rreg] == frame_pointer_rtx || ops[rval] == frame_pointer_rtx || (other_op >= 0 && ops[other_op] == frame_pointer_rtx)) return 0; if (code == PLUS && ! BASE_P (val_rtx)) { /* Do not allow rx = rx + n if a normal add or sub with same size would do. */ if (rtx_equal_p (ops[lreg], reg_rtx) && GET_CODE (val_rtx) == CONST_INT && (INTVAL (val_rtx) <= 63 && INTVAL (val_rtx) >= -63)) return 0; /* Check allowed cases, like [r(+)?].[bwd] and const. A symbol is not allowed with PIC. */ if (CONSTANT_P (val_rtx)) return flag_pic == 0 || cris_symbol (val_rtx) == 0; if (GET_CODE (val_rtx) == MEM && BASE_OR_AUTOINCR_P (XEXP (val_rtx, 0))) return 1; if (GET_CODE (val_rtx) == SIGN_EXTEND && GET_CODE (XEXP (val_rtx, 0)) == MEM && BASE_OR_AUTOINCR_P (XEXP (XEXP (val_rtx, 0), 0))) return 1; /* If we got here, it's not a valid addressing mode. */ return 0; } else if (code == MULT || (code == PLUS && BASE_P (val_rtx))) { /* Do not allow rx = rx + ry.S, since it doesn't give better code. */ if (rtx_equal_p (ops[lreg], reg_rtx) || (mult == 1 && rtx_equal_p (ops[lreg], val_rtx))) return 0; /* Do not allow bad multiply-values. */ if (mult != 1 && mult != 2 && mult != 4) return 0; /* Only allow r + ... */ if (! BASE_P (reg_rtx)) return 0; /* If we got here, all seems ok. (All checks need to be done above). */ return 1; } /* If we get here, the caller got its initial tests wrong. */ internal_error ("internal error: cris_side_effect_mode_ok with bad operands");}/* The function reg_overlap_mentioned_p in CVS (still as of 2001-05-16) does not handle the case where the IN operand is strict_low_part; it does handle it for X. Test-case in Axis-20010516. This function takes care of that for THIS port. FIXME: strict_l
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -