📄 bfin.c
字号:
} if ((val & 0xFFFF0000) == 0xFFFF0000) { emit_insn (gen_movsi (operands[0], constm1_rtx)); emit_insn (gen_movsi_low (operands[0], operands[0], operands[1])); return 1; } } /* Need DREGs for the remaining case. */ if (regno > REG_R7) return 0; if (optimize_size && num_compl_zero && CONST_7BIT_IMM_P (shifted_compl)) { /* If optimizing for size, generate a sequence that has more instructions but is shorter. */ emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl))); emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_compl_zero))); emit_insn (gen_one_cmplsi2 (operands[0], operands[0])); return 1; } return 0;}/* Return true if the legitimate memory address for a memory operand of mode MODE. Return false if not. */static boolbfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value){ unsigned HOST_WIDE_INT v = value > 0 ? value : -value; int sz = GET_MODE_SIZE (mode); int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2; /* The usual offsettable_memref machinery doesn't work so well for this port, so we deal with the problem here. */ unsigned HOST_WIDE_INT mask = sz == 8 ? 0x7ffe : 0x7fff; return (v & ~(mask << shift)) == 0;}static boolbfin_valid_reg_p (unsigned int regno, int strict){ return ((strict && REGNO_OK_FOR_BASE_STRICT_P (regno)) || (!strict && REGNO_OK_FOR_BASE_NONSTRICT_P (regno)));}boolbfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict){ switch (GET_CODE (x)) { case REG: if (bfin_valid_reg_p (REGNO (x), strict)) return true; break; case PLUS: if (REG_P (XEXP (x, 0)) && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict) && (GET_CODE (XEXP (x, 1)) == UNSPEC || (GET_CODE (XEXP (x, 1)) == CONST_INT && bfin_valid_add (mode, INTVAL (XEXP (x, 1)))))) return true; break; case POST_INC: case POST_DEC: if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode) && REG_P (XEXP (x, 0)) && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict)) return true; case PRE_DEC: if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode) && XEXP (x, 0) == stack_pointer_rtx && REG_P (XEXP (x, 0)) && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict)) return true; break; default: break; } return false;}static boolbfin_rtx_costs (rtx x, int code, int outer_code, int *total){ int cost2 = COSTS_N_INSNS (1); switch (code) { case CONST_INT: if (outer_code == SET || outer_code == PLUS) *total = CONST_7BIT_IMM_P (INTVAL (x)) ? 0 : cost2; else if (outer_code == AND) *total = log2constp (~INTVAL (x)) ? 0 : cost2; else if (outer_code == LE || outer_code == LT || outer_code == EQ) *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2; else if (outer_code == LEU || outer_code == LTU) *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2; else if (outer_code == MULT) *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2; else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2)) *total = 0; else if (outer_code == ASHIFT || outer_code == ASHIFTRT || outer_code == LSHIFTRT) *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2; else if (outer_code == IOR || outer_code == XOR) *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2; else *total = cost2; return true; case CONST: case LABEL_REF: case SYMBOL_REF: case CONST_DOUBLE: *total = COSTS_N_INSNS (2); return true; case PLUS: if (GET_MODE (x) == Pmode) { if (GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) { HOST_WIDE_INT val = INTVAL (XEXP (XEXP (x, 0), 1)); if (val == 2 || val == 4) { *total = cost2; *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code); *total += rtx_cost (XEXP (x, 1), outer_code); return true; } } } /* fall through */ case MINUS: case ASHIFT: case ASHIFTRT: case LSHIFTRT: if (GET_MODE (x) == DImode) *total = 6 * cost2; return false; case AND: case IOR: case XOR: if (GET_MODE (x) == DImode) *total = 2 * cost2; return false; case MULT: if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD) *total = COSTS_N_INSNS (3); return false; default: return false; }}static voidbfin_internal_label (FILE *stream, const char *prefix, unsigned long num){ fprintf (stream, "%s%s$%ld:\n", LOCAL_LABEL_PREFIX, prefix, num);}/* Used for communication between {push,pop}_multiple_operation (which we use not only as a predicate) and the corresponding output functions. */static int first_preg_to_save, first_dreg_to_save;intpush_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ int lastdreg = 8, lastpreg = 6; int i, group; first_preg_to_save = lastpreg; first_dreg_to_save = lastdreg; for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++) { rtx t = XVECEXP (op, 0, i); rtx src, dest; int regno; if (GET_CODE (t) != SET) return 0; src = SET_SRC (t); dest = SET_DEST (t); if (GET_CODE (dest) != MEM || ! REG_P (src)) return 0; dest = XEXP (dest, 0); if (GET_CODE (dest) != PLUS || ! REG_P (XEXP (dest, 0)) || REGNO (XEXP (dest, 0)) != REG_SP || GET_CODE (XEXP (dest, 1)) != CONST_INT || INTVAL (XEXP (dest, 1)) != -i * 4) return 0; regno = REGNO (src); if (group == 0) { if (D_REGNO_P (regno)) { group = 1; first_dreg_to_save = lastdreg = regno - REG_R0; } else if (regno >= REG_P0 && regno <= REG_P7) { group = 2; first_preg_to_save = lastpreg = regno - REG_P0; } else return 0; continue; } if (group == 1) { if (regno >= REG_P0 && regno <= REG_P7) { group = 2; first_preg_to_save = lastpreg = regno - REG_P0; } else if (regno != REG_R0 + lastdreg + 1) return 0; else lastdreg++; } else if (group == 2) { if (regno != REG_P0 + lastpreg + 1) return 0; lastpreg++; } } return 1;}intpop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ int lastdreg = 8, lastpreg = 6; int i, group; for (i = 1, group = 0; i < XVECLEN (op, 0); i++) { rtx t = XVECEXP (op, 0, i); rtx src, dest; int regno; if (GET_CODE (t) != SET) return 0; src = SET_SRC (t); dest = SET_DEST (t); if (GET_CODE (src) != MEM || ! REG_P (dest)) return 0; src = XEXP (src, 0); if (i == 1) { if (! REG_P (src) || REGNO (src) != REG_SP) return 0; } else if (GET_CODE (src) != PLUS || ! REG_P (XEXP (src, 0)) || REGNO (XEXP (src, 0)) != REG_SP || GET_CODE (XEXP (src, 1)) != CONST_INT || INTVAL (XEXP (src, 1)) != (i - 1) * 4) return 0; regno = REGNO (dest); if (group == 0) { if (regno == REG_R7) { group = 1; lastdreg = 7; } else if (regno != REG_P0 + lastpreg - 1) return 0; else lastpreg--; } else if (group == 1) { if (regno != REG_R0 + lastdreg - 1) return 0; else lastdreg--; } } first_dreg_to_save = lastdreg; first_preg_to_save = lastpreg; return 1;}/* Emit assembly code for one multi-register push described by INSN, with operands in OPERANDS. */voidoutput_push_multiple (rtx insn, rtx *operands){ char buf[80]; /* Validate the insn again, and compute first_[dp]reg_to_save. */ if (! push_multiple_operation (PATTERN (insn), VOIDmode)) abort (); if (first_dreg_to_save == 8) sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save); else if (first_preg_to_save == 6) sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save); else sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n", first_dreg_to_save, first_preg_to_save); output_asm_insn (buf, operands);}/* Emit assembly code for one multi-register pop described by INSN, with operands in OPERANDS. */voidoutput_pop_multiple (rtx insn, rtx *operands){ char buf[80]; /* Validate the insn again, and compute first_[dp]reg_to_save. */ if (! pop_multiple_operation (PATTERN (insn), VOIDmode)) abort (); if (first_dreg_to_save == 8) sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save); else if (first_preg_to_save == 6) sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save); else sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n", first_dreg_to_save, first_preg_to_save); output_asm_insn (buf, operands);}/* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */static voidsingle_move_for_strmov (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset){ rtx scratch = gen_reg_rtx (mode); rtx srcmem, dstmem; srcmem = adjust_address_nv (src, mode, offset); dstmem = adjust_address_nv (dst, mode, offset); emit_move_insn (scratch, srcmem); emit_move_insn (dstmem, scratch);}/* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with alignment ALIGN_EXP. Return true if successful, false if we should fall back on a different method. */boolbfin_expand_strmov (rtx dst, rtx src, rtx count_exp, rtx align_exp){ rtx srcreg, destreg, countreg; HOST_WIDE_INT align = 0; unsigned HOST_WIDE_INT count = 0; if (GET_CODE (align_exp) == CONST_INT) align = INTVAL (align_exp); if (GET_CODE (count_exp) == CONST_INT) { count = INTVAL (count_exp);#if 0 if (!TARGET_INLINE_ALL_STRINGOPS && count > 64) return false;#endif } /* If optimizing for size, only do single copies inline. */ if (optimize_size) { if (count == 2 && align < 2) return false; if (count == 4 && align < 4) return false; if (count != 1 && count != 2 && count != 4) return false; } if (align < 2 && count != 1) return false; destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0)); if (destreg != XEXP (dst, 0)) dst = replace_equiv_address_nv (dst, destreg); srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0)); if (srcreg != XEXP (src, 0)) src = replace_equiv_address_nv (src, srcreg); if (count != 0 && align >= 2) { unsigned HOST_WIDE_INT offset = 0; if (align >= 4) { if ((count & ~3) == 4) { single_move_for_strmov (dst, src, SImode, offset); offset = 4; } else if (count & ~3) { HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1; countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count)); emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg)); } } else { if ((count & ~1) == 2) { single_move_for_strmov (dst, src, HImode, offset); offset = 2; } else if (count & ~1) { HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1; countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count)); emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg)); } } if (count & 2) { single_move_for_strmov (dst, src, HImode, offset); offset += 2; } if (count & 1) { single_move_for_strmov (dst, src, QImode, offset); } return true; } return false;}static intbfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost){ enum attr_type insn_type, dep_insn_type; int dep_insn_code_number; /* Anti and output dependencies have zero cost. */ if (REG_NOTE_KIND (link) != 0) return 0; dep_insn_code_number = recog_memoized (dep_insn); /* If we can't recognize the insns, we can't really do anything. */ if (dep_insn_code_number < 0 || recog_memoized (insn) < 0) return cost; insn_type = get_attr_type (insn); dep_insn_type = get_attr_type (dep_insn); if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD) { rtx pat = PATTERN (dep_insn); rtx dest = SET_DEST (pat); rtx src = SET_SRC (pat); if (! ADDRESS_REGNO_P (REGNO (dest)) || ! D_REGNO_P (REGNO (src))) return cost; return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3); } return cost;}/* We use the machine specific reorg pass for emitting CSYNC instructions after conditional branches as needed. The Blackfin is unusual in that a code sequence like if cc jump label r0 = (p0) may speculatively perform the load even if the condition isn't true. This happ
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -