📄 h8300.c
字号:
x = adj_offsettable_operand (x, 2); print_operand (file, x, 0); break; case CONST_INT: fprintf (file, "#%d", INTVAL (x) & 0xffff); break; default: abort (); } break; case 'g': switch (GET_CODE (x)) { case NE: fprintf (file, "bcc"); break; case EQ: fprintf (file, "bcs"); break; default: abort (); } break; case 'j': asm_fprintf (file, cond_string (GET_CODE (x))); break; case 'k': asm_fprintf (file, cond_string (reverse_condition (GET_CODE (x)))); break; case 's': if (GET_CODE (x) == CONST_INT) fprintf (file, "#%d", (INTVAL (x)) & 0xff); else fprintf (file, "%s", byte_reg (x, 0)); break; case 't': if (GET_CODE (x) == CONST_INT) fprintf (file, "#%d", (INTVAL (x) >> 8) & 0xff); else fprintf (file, "%s", byte_reg (x, 1)); break; case 'u': if (GET_CODE (x) != CONST_INT) abort (); fprintf (file, "%d", INTVAL (x)); break; case 'w': if (GET_CODE (x) == CONST_INT) fprintf (file, "#%d", INTVAL (x) & 0xff); else fprintf (file, "%s", byte_reg (x, TARGET_H8300 ? 2 : 0)); break; case 'x': if (GET_CODE (x) == CONST_INT) fprintf (file, "#%d", (INTVAL (x) >> 8) & 0xff); else fprintf (file, "%s", byte_reg (x, TARGET_H8300 ? 3 : 1)); break; case 'y': if (GET_CODE (x) == CONST_INT) fprintf (file, "#%d", (INTVAL (x) >> 16) & 0xff); else fprintf (file, "%s", byte_reg (x, 0)); break; case 'z': if (GET_CODE (x) == CONST_INT) fprintf (file, "#%d", (INTVAL (x) >> 24) & 0xff); else fprintf (file, "%s", byte_reg (x, 1)); break; default: def: switch (GET_CODE (x)) { case REG: switch (GET_MODE (x)) { case QImode:#if 0 /* Is it asm ("mov.b %0,r2l", ...) */ fprintf (file, "%s", byte_reg (x, 0));#else /* ... or is it asm ("mov.b %0l,r2l", ...) */ fprintf (file, "%s", names_big[REGNO (x)]);#endif break; case HImode: fprintf (file, "%s", names_big[REGNO (x)]); break; case SImode: case SFmode: fprintf (file, "%s", names_extended[REGNO (x)]); break; default: abort (); } break; case MEM: fprintf (file, "@"); output_address (XEXP (x, 0)); break; case CONST_INT: case SYMBOL_REF: case CONST: case LABEL_REF: fprintf (file, "#"); print_operand_address (file, x); break; } }}/* Output assembly language output for the address ADDR to FILE. */voidprint_operand_address (file, addr) FILE *file; rtx addr;{ switch (GET_CODE (addr)) { case REG: fprintf (file, "%s", h8_reg_names[REGNO (addr)]); break; case PRE_DEC: fprintf (file, "-%s", h8_reg_names[REGNO (XEXP (addr, 0))]); break; case POST_INC: fprintf (file, "%s+", h8_reg_names[REGNO (XEXP (addr, 0))]); break; case PLUS: fprintf (file, "("); if (GET_CODE (XEXP (addr, 0)) == REG) { /* reg,foo */ print_operand_address (file, XEXP (addr, 1)); fprintf (file, ","); print_operand_address (file, XEXP (addr, 0)); } else { /* foo+k */ print_operand_address (file, XEXP (addr, 0)); fprintf (file, "+"); print_operand_address (file, XEXP (addr, 1)); } fprintf (file, ")"); break; case CONST_INT: { /* Since the h8/300 only has 16 bit pointers, negative values are also those >= 32768. This happens for example with pointer minus a constant. We don't want to turn (char *p - 2) into (char *p + 65534) because loop unrolling can build upon this (IE: char *p + 131068). */ int n = INTVAL (addr); if (TARGET_H8300) n = (int) (short) n; if (n < 0) /* ??? Why the special case for -ve values? */ fprintf (file, "-%d", -n); else fprintf (file, "%d", n); break; } default: output_addr_const (file, addr); break; }}/* Output all insn addresses and their sizes into the assembly language output file. This is helpful for debugging whether the length attributes in the md file are correct. This is not meant to be a user selectable option. */voidfinal_prescan_insn (insn, operand, num_operands) rtx insn, *operand; int num_operands;{ /* This holds the last insn address. */ static int last_insn_address = 0; int uid = INSN_UID (insn); if (TARGET_RTL_DUMP) { fprintf (asm_out_file, "\n****************"); print_rtl (asm_out_file, PATTERN (insn)); fprintf (asm_out_file, "\n"); } if (TARGET_ADDRESSES) { fprintf (asm_out_file, "; 0x%x %d\n", insn_addresses[uid], insn_addresses[uid] - last_insn_address); last_insn_address = insn_addresses[uid]; }}/* Prepare for an SI sized move. */intdo_movsi (operands) rtx operands[];{ rtx src = operands[1]; rtx dst = operands[0]; if (!reload_in_progress && !reload_completed) { if (!register_operand (dst, GET_MODE (dst))) { rtx tmp = gen_reg_rtx (GET_MODE (dst)); emit_move_insn (tmp, src); operands[1] = tmp; } } return 0;}/* Function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). Define the offset between two registers, one to be eliminated, and the other its replacement, at the start of a routine. */intinitial_offset (from, to){ int offset = 0; if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) offset = UNITS_PER_WORD + frame_pointer_needed * UNITS_PER_WORD; else { int regno; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if ((regs_ever_live[regno] && (!call_used_regs[regno] || regno == FRAME_POINTER_REGNUM))) offset += UNITS_PER_WORD; /* See the comments for get_frame_size. We need to round it up to STACK_BOUNDARY. */ offset += ((get_frame_size () + STACK_BOUNDARY / BITS_PER_UNIT - 1) & ~(STACK_BOUNDARY / BITS_PER_UNIT - 1)); if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) offset += UNITS_PER_WORD; /* Skip saved PC */ } return offset;}/* Update the condition code from the insn. */intnotice_update_cc (body, insn) rtx body; rtx insn;{ switch (get_attr_cc (insn)) { case CC_NONE: /* Insn does not affect the CC at all */ break; case CC_NONE_0HIT: /* Insn does not change the CC, but the 0't operand has been changed. */ if (cc_status.value1 != 0 && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1)) cc_status.value1 = 0; if (cc_status.value2 != 0 && reg_overlap_mentioned_p (recog_operand[0], cc_status.value2)) cc_status.value2 = 0; break; case CC_SET: /* Insn sets CC to recog_operand[0], but overflow is impossible. */ CC_STATUS_INIT; cc_status.flags |= CC_NO_OVERFLOW; cc_status.value1 = recog_operand[0]; break; case CC_COMPARE: /* The insn is a compare instruction */ CC_STATUS_INIT; cc_status.value1 = SET_SRC (body); break; case CC_CBIT: CC_STATUS_INIT; cc_status.flags |= CC_DONE_CBIT; cc_status.value1 = 0; break; case CC_WHOOPS: case CC_CLOBBER: /* Insn clobbers CC. */ CC_STATUS_INIT; break; }}/* Recognize valid operators for bit instructions */intbit_operator (x, mode) rtx x; enum machine_mode mode;{ enum rtx_code code = GET_CODE (x); return (code == XOR || code == AND || code == IOR);}/* Shifts. We devote a fair bit of code to getting efficient shifts since we can only shift one bit at a time. See the .md file for more comments. Here are some thoughts on what the absolutely positively best code is. "Best" here means some rational trade-off between code size and speed, where speed is more preferred but not at the expense of generating 20 insns. H8/300 QImode shifts 1-4 - do them inline 5-6 - ASHIFT | LSHIFTRT: rotate, mask off other bits ASHIFTRT: loop 7 - ASHIFT | LSHIFTRT: rotate, mask off other bits ASHIFTRT: shll, subx (propagate carry bit to all bits) H8/300 HImode shifts 1-4 - do them inline 5-6 - loop 7 - shift other way once, move byte into place, move carry bit into place 8 - move byte, zero (ASHIFT | LSHIFTRT) or sign extend other (ASHIFTRT) 9 - inline shift 1-4, move byte, set other byte 13-14 - ASHIFT | LSHIFTRT: rotate 3/2, mask, move byte, set other byte to 0 - ASHIFTRT: loop 15 - ASHIFT | LSHIFTRT: rotate 1, mask, move byte, set other byte to 0 - ASHIFTRT: shll, subx, set other byte H8/300 SImode shifts 1-2 - do them inline 3-6 - loop 7 - shift other way once, move bytes into place, move carry into place (possibly with sign extension) 8 - move bytes into place, zero or sign extend other 9-14 - loop 15 - shift other way once, move word into place, move carry into place 16 - move word, zero or sign extend other 17-23 - loop 24 - move bytes into place, zero or sign extend other 25-27 - loop 28-30 - ASHIFT | LSHIFTRT: rotate top byte, mask, move byte into place, zero others ASHIFTRT: loop 31 - ASHIFT | LSHIFTRT: rotate top byte, mask, byte byte into place, zero others ASHIFTRT: shll top byte, subx, copy to other bytes H8/300H QImode shifts - same as H8/300 H8/300H HImode shifts - same as H8/300 H8/300H SImode shifts (These are complicated by the fact that we don't have byte level access to the top word.) A word is: bytes 3,2,1,0 (msb -> lsb), word 1,0 (msw -> lsw) 1-4 - do them inline 5-14 - loop 15 - shift other way once, move word into place, move carry into place (with sign extension for ASHIFTRT) 16 - move word into place, zero or sign extend other 17-23 - loop 24 - ASHIFT: move byte 0(msb) to byte 1, zero byte 0, move word 0 to word 1, zero word 0 LSHIFTRT: move word 1 to word 0, move byte 1 to byte 0, zero word 1, zero byte 1 ASHIFTRT: move word 1 to word 0, move byte 1 to byte 0, sign extend byte 0, sign extend word 0 25-27 - either loop, or do 24 bit shift, inline rest 28-30 - ASHIFT: rotate 4/3/2, mask LSHIFTRT: rotate 4/3/2, mask ASHIFTRT: loop 31 - shll, subx byte 0, sign extend byte 0, sign extend word 0 Don't Panic!!! All of these haven't been implemented. I've just documented them and provided hooks so they can be.*/intnshift_operator (x, mode) rtx x; enum machine_mode mode;{ switch (GET_CODE (x)) { case ASHIFTRT: case LSHIFTRT: case ASHIFT: return 1; default: return 0; }}/* Called from the .md file to emit code to do shifts. Returns a boolean indicating success (currently this is always TRUE). */intexpand_a_shift (mode, code, operands) enum machine_mode mode; int code; rtx operands[];{ extern int rtx_equal_function_value_matters; emit_move_insn (operands[0], operands[1]); /* need a loop to get all the bits we want - we generate the code at emit time, but need to allocate a scratch reg now */ emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, gen_rtx (SET, VOIDmode, operands[0], gen_rtx (code, mode, operands[0], operands[2])), gen_rtx (CLOBBER, VOIDmode, gen_rtx (SCRATCH, QImode, 0))))); return 1;}/* Shift algorithm determination. There are various ways of doing a shift: SHIFT_INLINE: If the amount is small enough, just generate as many one-bit shifts as we need. SHIFT_ROT_AND: If the amount is large but close to either end, rotate the necessary bits into position and then set the rest to zero. SHIFT_SPECIAL: Hand crafted assembler. SHIFT_LOOP: If the above methods fail, just loop. */enum shift_alg{ SHIFT_INLINE, SHIFT_ROT_AND, SHIFT_SPECIAL, SHIFT_LOOP, SHIFT_MAX};/* Symbols of the various shifts which can be used as indices. */enum shift_type { SHIFT_ASHIFT, SHIFT_LSHIFTRT, SHIFT_ASHIFTRT };/* Symbols of the various modes which can be used as indices. */enum shift_mode { QIshift, HIshift, SIshift };/* For single bit shift insns, record assembler and whether the condition code is valid afterwards. */struct shift_insn{ char *assembler; int cc_valid;};/* Assembler instruction shift table. These tables are used to look up the basic shifts. They are indexed by cpu, shift_type, and mode.*/static const struct shift_insn shift_one[2][3][3] ={/* H8/300 */ {/* SHIFT_ASHIFT */ { { "shal %X0", 1 }, { "add.w %T0,%T0\t; shal.w", 1 }, { "add.w %f0,%f0\t; shal.l\n\taddx %y0,%y0\n\taddx %z0,%z0\t; end shal.l", 0 } },/* SHIFT_LSHIFTRT */ { { "shlr %X0", 1 }, { "shlr %t0\t; shlr.w\n\trotxr %s0\t; end shlr.w", 0 },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -