📄 mcore.c
字号:
else if ((load_value & (load_value - 1)) == 0) output_asm_insn ("bgeni\t%0,%P1", out_operands); else if ((load_value & (load_value + 1)) == 0) output_asm_insn ("bmaski\t%0,%N1", out_operands); /* Output the constant adjustment. */ if (load_value > adjust_value) { if (cmp_t) output_asm_insn ("decf\t%0", out_operands); else output_asm_insn ("dect\t%0", out_operands); } else { if (cmp_t) output_asm_insn ("incf\t%0", out_operands); else output_asm_insn ("inct\t%0", out_operands); } return "";}/* Outputs the peephole for moving a constant that gets not'ed followed by an and (i.e. combine the not and the and into andn). BRC */const char *mcore_output_andn (insn, operands) rtx insn ATTRIBUTE_UNUSED; rtx operands[];{ int x, y; rtx out_operands[3]; const char * load_op; char buf[256]; if (try_constant_tricks (INTVAL (operands[1]), &x, &y) != 2) abort (); out_operands[0] = operands[0]; out_operands[1] = GEN_INT(x); out_operands[2] = operands[2]; if (x >= 0 && x <= 127) load_op = "movi\t%0,%1"; /* Try exact power of two. */ else if ((x & (x - 1)) == 0) load_op = "bgeni\t%0,%P1"; /* Try exact power of two - 1. */ else if ((x & (x + 1)) == 0) load_op = "bmaski\t%0,%N1"; else load_op = "BADMOVI\t%0,%1"; sprintf (buf, "%s\n\tandn\t%%2,%%0", load_op); output_asm_insn (buf, out_operands); return "";}/* Output an inline constant. */static const char *output_inline_const (mode, operands) enum machine_mode mode; rtx operands[];{ int x = 0, y = 0; int trick_no; rtx out_operands[3]; char buf[256]; char load_op[256]; const char *dst_fmt; int value; value = INTVAL (operands[1]); if ((trick_no = try_constant_tricks (value, &x, &y)) == 0) { /* lrw's are handled separately: Large inlinable constants never get turned into lrw's. Our caller uses try_constant_tricks to back off to an lrw rather than calling this routine. */ abort (); } if (trick_no == 1) x = value; /* operands: 0 = dst, 1 = load immed., 2 = immed. adjustment. */ out_operands[0] = operands[0]; out_operands[1] = GEN_INT (x); if (trick_no > 2) out_operands[2] = GEN_INT (y); /* Select dst format based on mode. */ if (mode == DImode && (! TARGET_LITTLE_END)) dst_fmt = "%R0"; else dst_fmt = "%0"; if (x >= 0 && x <= 127) sprintf (load_op, "movi\t%s,%%1", dst_fmt); /* Try exact power of two. */ else if ((x & (x - 1)) == 0) sprintf (load_op, "bgeni\t%s,%%P1", dst_fmt); /* Try exact power of two - 1. */ else if ((x & (x + 1)) == 0) sprintf (load_op, "bmaski\t%s,%%N1", dst_fmt); else sprintf (load_op, "BADMOVI\t%s,%%1", dst_fmt); switch (trick_no) { case 1: strcpy (buf, load_op); break; case 2: /* not */ sprintf (buf, "%s\n\tnot\t%s\t// %d 0x%x", load_op, dst_fmt, value, value); break; case 3: /* add */ sprintf (buf, "%s\n\taddi\t%s,%%2\t// %d 0x%x", load_op, dst_fmt, value, value); break; case 4: /* sub */ sprintf (buf, "%s\n\tsubi\t%s,%%2\t// %d 0x%x", load_op, dst_fmt, value, value); break; case 5: /* rsub */ /* Never happens unless -mrsubi, see try_constant_tricks(). */ sprintf (buf, "%s\n\trsubi\t%s,%%2\t// %d 0x%x", load_op, dst_fmt, value, value); break; case 6: /* bset */ sprintf (buf, "%s\n\tbseti\t%s,%%P2\t// %d 0x%x", load_op, dst_fmt, value, value); break; case 7: /* bclr */ sprintf (buf, "%s\n\tbclri\t%s,%%Q2\t// %d 0x%x", load_op, dst_fmt, value, value); break; case 8: /* rotl */ sprintf (buf, "%s\n\trotli\t%s,%%2\t// %d 0x%x", load_op, dst_fmt, value, value); break; case 9: /* lsl */ sprintf (buf, "%s\n\tlsli\t%s,%%2\t// %d 0x%x", load_op, dst_fmt, value, value); break; case 10: /* ixh */ sprintf (buf, "%s\n\tixh\t%s,%s\t// %d 0x%x", load_op, dst_fmt, dst_fmt, value, value); break; case 11: /* ixw */ sprintf (buf, "%s\n\tixw\t%s,%s\t// %d 0x%x", load_op, dst_fmt, dst_fmt, value, value); break; default: return ""; } output_asm_insn (buf, out_operands); return "";}/* Output a move of a word or less value. */const char *mcore_output_move (insn, operands, mode) rtx insn ATTRIBUTE_UNUSED; rtx operands[]; enum machine_mode mode ATTRIBUTE_UNUSED;{ rtx dst = operands[0]; rtx src = operands[1]; if (GET_CODE (dst) == REG) { if (GET_CODE (src) == REG) { if (REGNO (src) == CC_REG) /* r-c */ return "mvc\t%0"; else return "mov\t%0,%1"; /* r-r*/ } else if (GET_CODE (src) == MEM) { if (GET_CODE (XEXP (src, 0)) == LABEL_REF) return "lrw\t%0,[%1]"; /* a-R */ else return "ldw\t%0,%1"; /* r-m */ } else if (GET_CODE (src) == CONST_INT) { int x, y; if (CONST_OK_FOR_I (INTVAL (src))) /* r-I */ return "movi\t%0,%1"; else if (CONST_OK_FOR_M (INTVAL (src))) /* r-M */ return "bgeni\t%0,%P1\t// %1 %x1"; else if (CONST_OK_FOR_N (INTVAL (src))) /* r-N */ return "bmaski\t%0,%N1\t// %1 %x1"; else if (try_constant_tricks (INTVAL (src), &x, &y)) /* R-P */ return output_inline_const (SImode, operands); /* 1-2 insns */ else return "lrw\t%0,%x1\t// %1"; /* Get it from literal pool. */ } else return "lrw\t%0, %1"; /* Into the literal pool. */ } else if (GET_CODE (dst) == MEM) /* m-r */ return "stw\t%1,%0"; abort ();}/* Outputs a constant inline -- regardless of the cost. Useful for things where we've gotten into trouble and think we'd be doing an lrw into r15 (forbidden). This lets us get out of that pickle even after register allocation. */const char *mcore_output_inline_const_forced (insn, operands, mode) rtx insn ATTRIBUTE_UNUSED; rtx operands[]; enum machine_mode mode ATTRIBUTE_UNUSED;{ unsigned long value = INTVAL (operands[1]); unsigned long ovalue = value; struct piece { int low; int shift; } part[6]; int i; if (mcore_const_ok_for_inline (value)) return output_inline_const (SImode, operands); for (i = 0; (unsigned) i < ARRAY_SIZE (part); i++) { part[i].shift = 0; part[i].low = (value & 0x1F); value -= part[i].low; if (mcore_const_ok_for_inline (value)) break; else { value >>= 5; part[i].shift = 5; while ((value & 1) == 0) { part[i].shift++; value >>= 1; } if (mcore_const_ok_for_inline (value)) break; } } /* 5 bits per iteration, a maximum of 5 times == 25 bits and leaves 7 bits left in the constant -- which we know we can cover with a movi. The final value can't be zero otherwise we'd have stopped in the previous iteration. */ if (value == 0 || ! mcore_const_ok_for_inline (value)) abort (); /* Now, work our way backwards emitting the constant. */ /* Emit the value that remains -- it will be nonzero. */ operands[1] = GEN_INT (value); output_asm_insn (output_inline_const (SImode, operands), operands); while (i >= 0) { /* Shift anything we've already loaded. */ if (part[i].shift) { operands[2] = GEN_INT (part[i].shift); output_asm_insn ("lsli %0,%2", operands); value <<= part[i].shift; } /* Add anything we need into the low 5 bits. */ if (part[i].low != 0) { operands[2] = GEN_INT (part[i].low); output_asm_insn ("addi %0,%2", operands); value += part[i].low; } i--; } if (value != ovalue) /* sanity */ abort (); /* We've output all the instructions. */ return "";}/* Return a sequence of instructions to perform DI or DF move. Since the MCORE cannot move a DI or DF in one instruction, we have to take care when we see overlapping source and dest registers. */const char *mcore_output_movedouble (operands, mode) rtx operands[]; enum machine_mode mode ATTRIBUTE_UNUSED;{ rtx dst = operands[0]; rtx src = operands[1]; if (GET_CODE (dst) == REG) { if (GET_CODE (src) == REG) { int dstreg = REGNO (dst); int srcreg = REGNO (src); /* Ensure the second source not overwritten. */ if (srcreg + 1 == dstreg) return "mov %R0,%R1\n\tmov %0,%1"; else return "mov %0,%1\n\tmov %R0,%R1"; } else if (GET_CODE (src) == MEM) { rtx memexp = memexp = XEXP (src, 0); int dstreg = REGNO (dst); int basereg = -1; if (GET_CODE (memexp) == LABEL_REF) return "lrw\t%0,[%1]\n\tlrw\t%R0,[%R1]"; else if (GET_CODE (memexp) == REG) basereg = REGNO (memexp); else if (GET_CODE (memexp) == PLUS) { if (GET_CODE (XEXP (memexp, 0)) == REG) basereg = REGNO (XEXP (memexp, 0)); else if (GET_CODE (XEXP (memexp, 1)) == REG) basereg = REGNO (XEXP (memexp, 1)); else abort (); } else abort (); /* ??? length attribute is wrong here. */ if (dstreg == basereg) { /* Just load them in reverse order. */ return "ldw\t%R0,%R1\n\tldw\t%0,%1"; /* XXX: alternative: move basereg to basereg+1 and then fall through. */ } else return "ldw\t%0,%1\n\tldw\t%R0,%R1"; } else if (GET_CODE (src) == CONST_INT) { if (TARGET_LITTLE_END) { if (CONST_OK_FOR_I (INTVAL (src))) output_asm_insn ("movi %0,%1", operands); else if (CONST_OK_FOR_M (INTVAL (src))) output_asm_insn ("bgeni %0,%P1", operands); else if (INTVAL (src) == -1) output_asm_insn ("bmaski %0,32", operands); else if (CONST_OK_FOR_N (INTVAL (src))) output_asm_insn ("bmaski %0,%N1", operands); else abort (); if (INTVAL (src) < 0) return "bmaski %R0,32"; else return "movi %R0,0"; } else { if (CONST_OK_FOR_I (INTVAL (src))) output_asm_insn ("movi %R0,%1", operands); else if (CONST_OK_FOR_M (INTVAL (src))) output_asm_insn ("bgeni %R0,%P1", operands); else if (INTVAL (src) == -1) output_asm_insn ("bmaski %R0,32", operands); else if (CONST_OK_FOR_N (INTVAL (src))) output_asm_insn ("bmaski %R0,%N1", operands); else abort (); if (INTVAL (src) < 0) return "bmaski %0,32"; else return "movi %0,0"; } } else abort (); } else if (GET_CODE (dst) == MEM && GET_CODE (src) == REG) return "stw\t%1,%0\n\tstw\t%R1,%R0"; else abort ();}/* Predicates used by the templates. *//* Nonzero if OP can be source of a simple move operation. */intmcore_general_movsrc_operand (op, mode) rtx op; enum machine_mode mode;{ /* Any (MEM LABEL_REF) is OK. That is a pc-relative load. */ if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == LABEL_REF) return 1; return general_operand (op, mode);}/* Nonzero if OP can be destination of a simple move operation. */intmcore_general_movdst_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == REG && REGNO (op) == CC_REG) return 0; return general_operand (op, mode);}/* Nonzero if OP is a normal arithmetic register. */intmcore_arith_reg_operand (op, mode) rtx op; enum machine_mode mode;{ if (! register_operand (op, mode)) return 0; if (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); if (GET_CODE (op) == REG) return REGNO (op) != CC_REG; return 1;}/* Nonzero if OP should be recognized during reload for an ixh/ixw operand. See the ixh/ixw patterns. */intmcore_reload_operand (op, mode) rtx op; enum machine_mode mode;{ if (mcore_arith_reg_operand (op, mode)) return 1; if (! reload_in_progress) return 0; return GET_CODE (op) == MEM;}/* Nonzero if OP is a valid source operand for an arithmetic insn. */intmcore_arith_J_operand (op, mode) rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return 1; if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_J (INTVAL (op))) return 1; return 0;}/* Nonzero if OP is a valid source operand for an arithmetic insn. */intmcore_arith_K_operand (op, mode) rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return 1; if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op))) return 1; return 0;}/* Nonzero if OP is a valid source operand for a shift or rotate insn. */intmcore_arith_K_operand_not_0 (op, mode) rtx op;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -