📄 cris.c
字号:
operation. Currently a jumble of the old peek-inside-the-insn and the newer check-cc-attribute methods. */voidcris_notice_update_cc (rtx exp, rtx insn){ /* Check if user specified "-mcc-init" as a bug-workaround. FIXME: TARGET_CCINIT does not work; we must set CC_REVERSED as below. Several testcases will otherwise fail, for example gcc.c-torture/execute/20000217-1.c -O0 and -O1. */ if (TARGET_CCINIT) { CC_STATUS_INIT; return; } /* Slowly, we're converting to using attributes to control the setting of condition-code status. */ switch (get_attr_cc (insn)) { case CC_NONE: /* Even if it is "none", a setting may clobber a previous cc-value, so check. */ if (GET_CODE (exp) == SET) { if (cc_status.value1 && modified_in_p (cc_status.value1, insn)) cc_status.value1 = 0; if (cc_status.value2 && modified_in_p (cc_status.value2, insn)) cc_status.value2 = 0; } return; case CC_CLOBBER: CC_STATUS_INIT; break; case CC_NORMAL: /* Which means, for: (set (cc0) (...)): CC is (...). (set (reg) (...)): CC is (reg) and (...) - unless (...) is 0, then CC does not change. CC_NO_OVERFLOW unless (...) is reg or mem. (set (mem) (...)): CC does not change. (set (pc) (...)): CC does not change. (parallel (set (reg1) (mem (bdap/biap))) (set (reg2) (bdap/biap))): CC is (reg1) and (mem (reg2)) (parallel (set (mem (bdap/biap)) (reg1)) [or 0] (set (reg2) (bdap/biap))): CC does not change. (where reg and mem includes strict_low_parts variants thereof) For all others, assume CC is clobbered. Note that we do not have to care about setting CC_NO_OVERFLOW, since the overflow flag is set to 0 (i.e. right) for 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 && modified_in_p (cc_status.value1, insn)) cc_status.value1 = 0; if (cc_status.value2 && modified_in_p (cc_status.value2, insn)) 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 && modified_in_p (cc_status.value1, insn)) cc_status.value1 = 0; if (cc_status.value2 && modified_in_p (cc_status.value2, insn)) 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 = replace_equiv_address (XEXP (XVECEXP (exp, 0, 0), 1), 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 && modified_in_p (cc_status.value1, insn)) cc_status.value1 = 0; if (cc_status.value2 && modified_in_p (cc_status.value2, insn)) 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 (void){ 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;}/* Compute a (partial) cost for rtx X. Return true if the complete cost has been computed, and false if subexpressions should be scanned. In either case, *TOTAL contains the cost result. */static boolcris_rtx_costs (rtx x, int code, int outer_code, int *total){ switch (code) { case CONST_INT: { HOST_WIDE_INT val = INTVAL (x); if (val == 0) *total = 0; else if (val < 32 && val >= -32) *total = 1; /* Eight or 16 bits are a word and cycle more expensive. */ else if (val <= 32767 && val >= -32768) *total = 2; /* A 32 bit constant (or very seldom, unsigned 16 bits) costs another word. FIXME: This isn't linear to 16 bits. */ else *total = 4; return true; } case LABEL_REF: *total = 6; return true; case CONST: case SYMBOL_REF: /* For PIC, we need a prefix (if it isn't already there), and the PIC register. For a global PIC symbol, we also need a read of the GOT. */ if (flag_pic) { if (cris_got_symbol (x)) *total = 2 + 4 + 6; else *total = 2 + 6; } else *total = 6; return true; case CONST_DOUBLE: if (x != CONST0_RTX (GET_MODE (x) == VOIDmode ? DImode : GET_MODE (x))) *total = 12; else /* Make 0.0 cheap, else test-insns will not be used. */ *total = 0; return true; case MULT: /* Identify values that are no powers of two. Powers of 2 are taken care of already and those values should not be changed. */ if (GET_CODE (XEXP (x, 1)) != CONST_INT || exact_log2 (INTVAL (XEXP (x, 1)) < 0)) { /* If we have a multiply insn, then the cost is between 1 and 2 "fast" instructions. */ if (TARGET_HAS_MUL_INSNS) { *total = COSTS_N_INSNS (1) + COSTS_N_INSNS (1) / 2; return true; } /* Estimate as 4 + 4 * #ofbits. */ *total = COSTS_N_INSNS (132); return true; } return false; case UDIV: case MOD: case UMOD: case DIV: if (GET_CODE (XEXP (x, 1)) != CONST_INT || exact_log2 (INTVAL (XEXP (x, 1)) < 0)) { /* Estimate this as 4 + 8 * #of bits. */ *total = COSTS_N_INSNS (260); return true; } return false; case AND: if (GET_CODE (XEXP (x, 1)) == CONST_INT /* Two constants may actually happen before optimization. */ && GET_CODE (XEXP (x, 0)) != CONST_INT && !CONST_OK_FOR_LETTER_P (INTVAL (XEXP (x, 1)), 'I')) { *total = (rtx_cost (XEXP (x, 0), outer_code) + 2 + 2 * GET_MODE_NUNITS (GET_MODE (XEXP (x, 0)))); return true; } return false; case ZERO_EXTEND: case SIGN_EXTEND: *total = rtx_cost (XEXP (x, 0), outer_code); return true; default: return false; }}/* The ADDRESS_COST worker. */static intcris_address_cost (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 c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -