📄 bfin.c
字号:
/* If we have a BImode input, then we already have a compare result, and do not need to emit another comparison. */ if (GET_MODE (op0) == BImode) { gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx); tem = op0, code2 = code; } else { switch (code) { /* bfin has these conditions */ case EQ: case LT: case LE: case LEU: case LTU: code1 = code; code2 = NE; break; default: code1 = reverse_condition (code); code2 = EQ; break; } emit_insn (gen_rtx_SET (BImode, tem, gen_rtx_fmt_ee (code1, BImode, op0, op1))); } return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));}/* Return nonzero iff C has exactly one bit set if it is interpreted as a 32 bit constant. */intlog2constp (unsigned HOST_WIDE_INT c){ c &= 0xFFFFFFFF; return c != 0 && (c & (c-1)) == 0;}/* Returns the number of consecutive least significant zeros in the binary representation of *V. We modify *V to contain the original value arithmetically shifted right by the number of zeroes. */static intshiftr_zero (HOST_WIDE_INT *v){ unsigned HOST_WIDE_INT tmp = *v; unsigned HOST_WIDE_INT sgn; int n = 0; if (tmp == 0) return 0; sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)); while ((tmp & 0x1) == 0 && n <= 32) { tmp = (tmp >> 1) | sgn; n++; } *v = tmp; return n;}/* After reload, split the load of an immediate constant. OPERANDS are the operands of the movsi_insn pattern which we are splitting. We return nonzero if we emitted a sequence to load the constant, zero if we emitted nothing because we want to use the splitter's default sequence. */intsplit_load_immediate (rtx operands[]){ HOST_WIDE_INT val = INTVAL (operands[1]); HOST_WIDE_INT tmp; HOST_WIDE_INT shifted = val; HOST_WIDE_INT shifted_compl = ~val; int num_zero = shiftr_zero (&shifted); int num_compl_zero = shiftr_zero (&shifted_compl); unsigned int regno = REGNO (operands[0]); enum reg_class class1 = REGNO_REG_CLASS (regno); /* This case takes care of single-bit set/clear constants, which we could also implement with BITSET/BITCLR. */ if (num_zero && shifted >= -32768 && shifted < 65536 && (D_REGNO_P (regno) || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2))) { emit_insn (gen_movsi (operands[0], GEN_INT (shifted))); emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero))); return 1; } tmp = val & 0xFFFF; tmp |= -(tmp & 0x8000); /* If high word has one bit set or clear, try to use a bit operation. */ if (D_REGNO_P (regno)) { if (log2constp (val & 0xFFFF0000)) { emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF))); emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000))); return 1; } else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0) { emit_insn (gen_movsi (operands[0], GEN_INT (tmp))); emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF))); } } if (D_REGNO_P (regno)) { if (CONST_7BIT_IMM_P (tmp)) { emit_insn (gen_movsi (operands[0], GEN_INT (tmp))); emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536))); return 1; } if ((val & 0xFFFF0000) == 0) { emit_insn (gen_movsi (operands[0], const0_rtx)); emit_insn (gen_movsi_low (operands[0], operands[0], operands[1])); return 1; } 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]; int ok; /* Validate the insn again, and compute first_[dp]reg_to_save. */ ok = push_multiple_operation (PATTERN (insn), VOIDmode); gcc_assert (ok); 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]; int ok; /* Validate the insn again, and compute first_[dp]reg_to_save. */ ok = pop_multiple_operation (PATTERN (insn), VOIDmode); gcc_assert (ok); 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 SR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -