📄 h8300.c
字号:
{ "shlr %z0\t; shlr.l\n\trotxr %y0\n\trotxr %x0\n\trotxr %w0\t; end shlr.l", 0 } },/* SHIFT_ASHIFTRT */ { { "shar %X0", 1 }, { "shar %t0\t; shar.w\n\trotxr %s0\t; end shar.w", 0 }, { "shar %z0\t; shar.l\n\trotxr %y0\n\trotxr %x0\n\trotxr %w0\t; end shar.l", 0 } } },/* H8/300H */ {/* SHIFT_ASHIFT */ { { "shal.b %X0", 1 }, { "shal.w %T0", 1 }, { "shal.l %S0", 1 } },/* SHIFT_LSHIFTRT */ { { "shlr.b %X0", 1 }, { "shlr.w %T0", 1 }, { "shlr.l %S0", 1 } },/* SHIFT_ASHIFTRT */ { { "shar.b %X0", 1 }, { "shar.w %T0", 1 }, { "shar.l %S0", 1 } } }};/* Rotates are organized by which shift they'll be used in implementing. There's no need to record whether the cc is valid afterwards because it is the AND insn that will decide this. */static const char *const rotate_one[2][3][3] ={/* H8/300 */ {/* SHIFT_ASHIFT */ { "rotr %X0", "shlr %t0\t; rotr.w\n\trotxr %s0\n\tbst #7,%t0\t; end rotr.w", 0 },/* SHIFT_LSHIFTRT */ { "rotl %X0", "shll %s0\t; rotl.w\n\trotxl %t0\n\tbst #0,%s0\t; end rotl.w", 0 },/* SHIFT_ASHIFTRT */ { "rotl %X0", "shll %s0\t; rotl.w\n\trotxl %t0\n\tbst #0,%s0\t; end rotl.w", 0 } },/* H8/300H */ {/* SHIFT_ASHIFT */ { "rotr.b %X0", "rotr.w %T0", "rotr.l %S0" },/* SHIFT_LSHIFTRT */ { "rotl.b %X0", "rotl.w %T0", "rotl.l %S0" },/* SHIFT_ASHIFTRT */ { "rotl.b %X0", "rotl.w %T0", "rotl.l %S0" } }};/* Given CPU, MODE, SHIFT_TYPE, and shift count COUNT, determine the best algorithm for doing the shift. The assembler code is stored in ASSEMBLER. We don't achieve maximum efficiency in all cases, but the hooks are here to do so. For now we just use lots of switch statements. Since we don't even come close to supporting all the cases, this is simplest. If this function ever gets too big, perhaps resort to a more table based lookup. Of course, at this point you may just wish to do it all in rtl. WARNING: The constraints on insns shiftbyn_QI/HI/SI assume shifts of 1,2,3,4 will be inlined (1,2 for SI). */static enum shift_algget_shift_alg (cpu, shift_type, mode, count, assembler_p, cc_valid_p) enum attr_cpu cpu; enum shift_type shift_type; enum machine_mode mode; int count; const char **assembler_p; int *cc_valid_p;{ /* The default is to loop. */ enum shift_alg alg = SHIFT_LOOP; enum shift_mode shift_mode; /* We don't handle negative shifts or shifts greater than the word size, they should have been handled already. */ if (count < 0 || count > GET_MODE_BITSIZE (mode)) abort (); switch (mode) { case QImode: shift_mode = QIshift; break; case HImode: shift_mode = HIshift; break; case SImode: shift_mode = SIshift; break; default: abort (); } /* Assume either SHIFT_LOOP or SHIFT_INLINE. It is up to the caller to know that looping clobbers cc. */ *assembler_p = shift_one[cpu][shift_type][shift_mode].assembler; *cc_valid_p = shift_one[cpu][shift_type][shift_mode].cc_valid; /* Now look for cases we want to optimize. */ switch (shift_mode) { case QIshift: if (count <= 4) return SHIFT_INLINE; else if (count <= 6) { if (shift_type == SHIFT_ASHIFTRT) { return SHIFT_LOOP; } else { *assembler_p = rotate_one[cpu][shift_type][shift_mode]; *cc_valid_p = 0; return SHIFT_ROT_AND; } } else if (count == 7) { if (shift_type == SHIFT_ASHIFTRT) { *assembler_p = "shll %X0\t; shar.b(7)\n\tsubx %X0,%X0\t; end shar.b(7)"; *cc_valid_p = 0; return SHIFT_SPECIAL; } else { *assembler_p = rotate_one[cpu][shift_type][shift_mode]; *cc_valid_p = 0; return SHIFT_ROT_AND; } } break; case HIshift: if (count <= 4) return SHIFT_INLINE; else if (count == 8) { switch (shift_type) { case SHIFT_ASHIFT: *assembler_p = "mov.b %s0,%t0\t; shal.w(8)\n\tsub.b %s0,%s0\t; end shal.w(8)"; *cc_valid_p = 0; return SHIFT_SPECIAL; case SHIFT_LSHIFTRT: *assembler_p = "mov.b %t0,%s0\t; shlr.w(8)\n\tsub.b %t0,%t0\t; end shlr.w(8)"; *cc_valid_p = 0; return SHIFT_SPECIAL; case SHIFT_ASHIFTRT: if (cpu == CPU_H8300) *assembler_p = "mov.b %t0,%s0\t; shar.w(8)\n\tshll %t0\n\tsubx %t0,%t0\t; end shar.w(8)"; else *assembler_p = "mov.b %t0,%s0\t; shar.w(8)\n\texts.w %T0\t; end shar.w(8)"; *cc_valid_p = 0; return SHIFT_SPECIAL; } abort (); } else if (count == 15) { if (shift_type == SHIFT_ASHIFTRT) { *assembler_p = "shll %t0,%t0\t; shar.w(15)\n\tsubx %t0,%t0\n\tmov.b %t0,%s0\t; end shar.w(15)"; *cc_valid_p = 0; return SHIFT_SPECIAL; } else { *assembler_p = rotate_one[cpu][shift_type][shift_mode]; *cc_valid_p = 0; return SHIFT_ROT_AND; } } break; case SIshift: if (count <= (cpu == CPU_H8300 ? 2 : 4)) return SHIFT_INLINE; else if (count == 8) { if (cpu == CPU_H8300) { switch (shift_type) { case SHIFT_ASHIFT: *assembler_p = "mov.b %y0,%z0\t; shal.l(8)\n\tmov.b %x0,%y0\n\tmov.b %w0,%x0\n\tsub.b %w0,%w0\t; end shal.l(8)"; *cc_valid_p = 0; return SHIFT_SPECIAL; case SHIFT_LSHIFTRT: *assembler_p = "mov.b %x0,%w0\t; shlr.l(8)\n\tmov.b %y0,%x0\n\tmov.b %z0,%y0\n\tsub.b %z0,%z0\t; end shlr.l(8)"; *cc_valid_p = 0; return SHIFT_SPECIAL; case SHIFT_ASHIFTRT: *assembler_p = "mov.b %x0,%w0\t; shar.l(8)\n\tmov.b %y0,%x0\n\tmov.b %z0,%y0\n\tshll %z0\n\tsubx %z0,%z0; end shar.l(8)"; *cc_valid_p = 0; return SHIFT_SPECIAL; } } else /* CPU_H8300H */ /* We don't have byte level access to the high word so this isn't easy to do. For now, just loop. */ ; } else if (count == 16) { switch (shift_type) { case SHIFT_ASHIFT: *assembler_p = "mov.w %f0,%e0\t; shal.l(16)\n\tsub.w %f0,%f0\t; end shal.l(16)"; *cc_valid_p = 0; return SHIFT_SPECIAL; case SHIFT_LSHIFTRT: *assembler_p = "mov.w %e0,%f0\t; shlr.l(16)\n\tsub.w %e0,%e0\t; end shlr.l(16)"; *cc_valid_p = 0; return SHIFT_SPECIAL; case SHIFT_ASHIFTRT: if (cpu == CPU_H8300) *assembler_p = "mov.w %e0,%f0\t; shar.l(16)\n\tshll %z0\n\tsubx %z0,%z0\n\tmov.b %z0,%y0\t; end shar.l(16)"; else *assembler_p = "mov.w %e0,%f0\t; shar.l(16)\n\texts.l %S0\t; end shar.l(16)"; *cc_valid_p = 0; return SHIFT_SPECIAL; } } else if (count >= 28 && count <= 30) { if (shift_type == SHIFT_ASHIFTRT) { return SHIFT_LOOP; } else { if (cpu == CPU_H8300) return SHIFT_LOOP; else { *assembler_p = rotate_one[cpu][shift_type][shift_mode]; *cc_valid_p = 0; return SHIFT_ROT_AND; } } } else if (count == 31) { if (shift_type == SHIFT_ASHIFTRT) { if (cpu == CPU_H8300) *assembler_p = "shll %z0\t; shar.l(31)\n\tsubx %w0,%w0\n\tmov.b %w0,%x0\n\tmov.w %f0,%e0\t; end shar.l(31)"; else *assembler_p = "shll %e0\t; shar.l(31)\n\tsubx %w0,%w0\n\tmov.b %w0,%x0\n\tmov.w %f0,%e0\t; end shar.l(31)"; *cc_valid_p = 0; return SHIFT_SPECIAL; } else { if (cpu == CPU_H8300) { if (shift_type == SHIFT_ASHIFT) *assembler_p = "sub.w %e0,%e0\t; shal.l(31)\n\tshlr %w0\n\tmov.w %e0,%f0\n\trotxr %z0\t; end shal.l(31)"; else *assembler_p = "sub.w %f0,%f0\t; shlr.l(31)\n\tshll %z0\n\tmov.w %f0,%e0\n\trotxl %w0\t; end shlr.l(31)"; *cc_valid_p = 0; return SHIFT_SPECIAL; } else { *assembler_p = rotate_one[cpu][shift_type][shift_mode]; *cc_valid_p = 0; return SHIFT_ROT_AND; } } } break; default: abort (); } return alg;}/* Emit the assembler code for doing shifts. */char *emit_a_shift (insn, operands) rtx insn; rtx *operands;{ static int loopend_lab; char *assembler; int cc_valid; rtx inside = PATTERN (insn); rtx shift = operands[3]; enum machine_mode mode = GET_MODE (shift); enum rtx_code code = GET_CODE (shift); enum shift_type shift_type; enum shift_mode shift_mode; loopend_lab++; switch (mode) { case QImode: shift_mode = QIshift; break; case HImode: shift_mode = HIshift; break; case SImode: shift_mode = SIshift; break; default: abort (); } switch (code) { case ASHIFTRT: shift_type = SHIFT_ASHIFTRT; break; case LSHIFTRT: shift_type = SHIFT_LSHIFTRT; break; case ASHIFT: shift_type = SHIFT_ASHIFT; break; default: abort (); } if (GET_CODE (operands[2]) != CONST_INT) { /* Indexing by reg, so have to loop and test at top */ output_asm_insn ("mov.b %X2,%X4", operands); fprintf (asm_out_file, "\tble .Lle%d\n", loopend_lab); /* Get the assembler code to do one shift. */ get_shift_alg (cpu_type, shift_type, mode, 1, &assembler, &cc_valid); } else { int n = INTVAL (operands[2]); enum shift_alg alg; /* If the count is negative, make it 0. */ if (n < 0) n = 0; /* If the count is too big, truncate it. ANSI says shifts of GET_MODE_BITSIZE are undefined - we choose to do the intuitive thing. */ else if (n > GET_MODE_BITSIZE (mode)) n = GET_MODE_BITSIZE (mode); alg = get_shift_alg (cpu_type, shift_type, mode, n, &assembler, &cc_valid); switch (alg) { case SHIFT_INLINE: while (--n >= 0) output_asm_insn (assembler, operands); if (cc_valid) cc_status.value1 = operands[0]; return ""; case SHIFT_ROT_AND: { int m = GET_MODE_BITSIZE (mode) - n; int mask = (shift_type == SHIFT_ASHIFT ? ((1 << GET_MODE_BITSIZE (mode) - n) - 1) << n : (1 << GET_MODE_BITSIZE (mode) - n) - 1); char insn_buf[200]; /* Not all possibilities of rotate are supported. They shouldn't be generated, but let's watch for 'em. */ if (assembler == 0) abort (); while (--m >= 0) output_asm_insn (assembler, operands); if (TARGET_H8300) { switch (mode) { case QImode: sprintf (insn_buf, "and #%d,%%X0\t; end shift %d via rotate+and", mask, n); cc_status.value1 = operands[0]; break; case HImode: sprintf (insn_buf, "and #%d,%%s0\n\tand #%d,%%t0\t; end shift %d via rotate+and", mask & 255, mask >> 8, n); break; case SImode: abort (); } } else { sprintf (insn_buf, "and.%c #%d,%%%c0", "bwl"[shift_mode], mask, mode == QImode ? 'X' : mode == HImode ? 'T' : 'S'); cc_status.value1 = operands[0]; } output_asm_insn (insn_buf, operands); return ""; } case SHIFT_SPECIAL: output_asm_insn (assembler, operands); return ""; } /* Need a loop, move limit to tmp reg */ fprintf (asm_out_file, "\tmov.b #%d,%sl\n", n, names_big[REGNO (operands[4])]); } fprintf (asm_out_file, ".Llt%d:\n", loopend_lab); output_asm_insn (assembler, operands); output_asm_insn ("add #0xff,%X4", operands); fprintf (asm_out_file, "\tbne .Llt%d\n", loopend_lab); fprintf (asm_out_file, ".Lle%d:\n", loopend_lab); return "";}/* Fix the operands of a gen_xxx so that it could become a bit operating insn. */intfix_bit_operand (operands, what, type) rtx *operands; char what; enum rtx_code type;{ /* The bit_operand predicate accepts any memory during RTL generation, but only 'U' memory afterwards, so if this is a MEM operand, we must force it to be valid for 'U' by reloading the address. */ if (GET_CODE (operands[2]) == CONST_INT) { if (CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), what)) { /* Ok to have a memory dest. */ if (GET_CODE (operands[0]) == MEM && !EXTRA_CONSTRAINT (operands[0], 'U')) { rtx mem; mem = gen_rtx (MEM, GET_MODE (operands[0]), copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[0]); MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[0]); MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[0]); operands[0] = mem; } if (GET_CODE (operands[1]) == MEM && !EXTRA_CONSTRAINT (operands[1], 'U')) { rtx mem; mem = gen_rtx (MEM, GET_MODE (operands[1]), copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[1]); MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[1]); MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[1]); operands[1] = mem; } return 0; } } /* Dest and src op must be register. */ operands[1] = force_reg (QImode, operands[1]); { rtx res = gen_reg_rtx (QImode); emit_insn (gen_rtx (SET, VOIDmode, res, gen_rtx (type, QImode, operands[1], operands[2]))); emit_insn (gen_rtx (SET, VOIDmode, operands[0], res)); } return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -