📄 h8300.c
字号:
<args> PC FP <- fp <locals> <saved registers> <- sp This is what the stack looks like after the prolog of a function which doesn't have a frame: <args> PC <locals> <saved registers> <- sp*//* Output assembly language code for the function prologue. */static voidh8300_output_function_prologue (file, size) FILE *file; HOST_WIDE_INT size;{ int fsize = round_frame_size (size); int regno; int saved_regs; int n_regs; /* Note a function with the interrupt attribute and set interrupt_handler accordingly. */ if (h8300_interrupt_function_p (current_function_decl)) interrupt_handler = 1; /* If the current function has the OS_Task attribute set, then we have a naked prologue. */ if (h8300_os_task_function_p (current_function_decl)) { fprintf (file, ";OS_Task prologue\n"); os_task = 1; return; } if (h8300_monitor_function_p (current_function_decl)) { /* My understanding of monitor functions is they act just like interrupt functions, except the prologue must mask interrupts. */ fprintf (file, ";monitor prologue\n"); interrupt_handler = 1; monitor = 1; if (TARGET_H8300) { fprintf (file, "\tsubs\t#2,sp\n"); push (file, 0); fprintf (file, "\tstc\tccr,r0l\n"); fprintf (file, "\tmov.b\tr0l,@(2,sp)\n"); pop (file, 0); fprintf (file, "\torc\t#128,ccr\n"); } else if (TARGET_H8300H) { push (file, 0); fprintf (file, "\tstc\tccr,r0l\n"); fprintf (file, "\tmov.b\tr0l,@(4,sp)\n"); pop (file, 0); fprintf (file, "\torc\t#128,ccr\n"); } else if (TARGET_H8300S) { fprintf (file, "\tstc\texr,@-sp\n"); push (file, 0); fprintf (file, "\tstc\tccr,r0l\n"); fprintf (file, "\tmov.b\tr0l,@(6,sp)\n"); pop (file, 0); fprintf (file, "\torc\t#128,ccr\n"); } else abort (); } if (frame_pointer_needed) { /* Push fp. */ push (file, FRAME_POINTER_REGNUM); fprintf (file, "\t%s\t%s,%s\n", h8_mov_op, h8_reg_names[STACK_POINTER_REGNUM], h8_reg_names[FRAME_POINTER_REGNUM]); } /* Leave room for locals. */ dosize (file, -1, fsize); /* Push the rest of the registers in ascending order. */ saved_regs = compute_saved_regs (); for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno += n_regs) { n_regs = 1; if (saved_regs & (1 << regno)) { if (TARGET_H8300S) { /* See how many registers we can push at the same time. */ if ((regno == 0 || regno == 4) && ((saved_regs >> regno) & 0x0f) == 0x0f) n_regs = 4; else if ((regno == 0 || regno == 4) && ((saved_regs >> regno) & 0x07) == 0x07) n_regs = 3; else if ((regno == 0 || regno == 2 || regno == 4 || regno == 6) && ((saved_regs >> regno) & 0x03) == 0x03) n_regs = 2; } switch (n_regs) { case 1: push (file, regno); break; case 2: fprintf (file, "\tstm.l\t%s-%s,@-er7\n", h8_reg_names[regno], h8_reg_names[regno + 1]); break; case 3: fprintf (file, "\tstm.l\t%s-%s,@-er7\n", h8_reg_names[regno], h8_reg_names[regno + 2]); break; case 4: fprintf (file, "\tstm.l\t%s-%s,@-er7\n", h8_reg_names[regno], h8_reg_names[regno + 3]); break; default: abort (); } } }}/* Output assembly language code for the function epilogue. */static voidh8300_output_function_epilogue (file, size) FILE *file; HOST_WIDE_INT size;{ int fsize = round_frame_size (size); int regno; rtx insn = get_last_insn (); int saved_regs; int n_regs; if (os_task) { /* OS_Task epilogues are nearly naked -- they just have an rts instruction. */ fprintf (file, ";OS_task epilogue\n"); fprintf (file, "\trts\n"); goto out; } /* Monitor epilogues are the same as interrupt function epilogues. Just make a note that we're in an monitor epilogue. */ if (monitor) fprintf (file, ";monitor epilogue\n"); /* If the last insn was a BARRIER, we don't have to write any code. */ if (GET_CODE (insn) == NOTE) insn = prev_nonnote_insn (insn); if (insn && GET_CODE (insn) == BARRIER) goto out; /* Pop the saved registers in descending order. */ saved_regs = compute_saved_regs (); for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno -= n_regs) { n_regs = 1; if (saved_regs & (1 << regno)) { if (TARGET_H8300S) { /* See how many registers we can pop at the same time. */ if ((regno == 7 || regno == 3) && ((saved_regs >> (regno - 3)) & 0x0f) == 0x0f) n_regs = 4; else if ((regno == 6 || regno == 2) && ((saved_regs >> (regno - 2)) & 0x07) == 0x07) n_regs = 3; else if ((regno == 7 || regno == 5 || regno == 3 || regno == 1) && ((saved_regs >> (regno - 1)) & 0x03) == 0x03) n_regs = 2; } switch (n_regs) { case 1: pop (file, regno); break; case 2: fprintf (file, "\tldm.l\t@er7+,%s-%s\n", h8_reg_names[regno - 1], h8_reg_names[regno]); break; case 3: fprintf (file, "\tldm.l\t@er7+,%s-%s\n", h8_reg_names[regno - 2], h8_reg_names[regno]); break; case 4: fprintf (file, "\tldm.l\t@er7+,%s-%s\n", h8_reg_names[regno - 3], h8_reg_names[regno]); break; default: abort (); } } } /* Deallocate locals. */ dosize (file, 1, fsize); /* Pop frame pointer if we had one. */ if (frame_pointer_needed) pop (file, FRAME_POINTER_REGNUM); if (interrupt_handler) fprintf (file, "\trte\n"); else fprintf (file, "\trts\n"); out: interrupt_handler = 0; os_task = 0; monitor = 0; pragma_saveall = 0;}/* Output assembly code for the start of the file. */voidasm_file_start (file) FILE *file;{ fprintf (file, ";\tGCC For the Hitachi H8/300\n"); fprintf (file, ";\tBy Hitachi America Ltd and Cygnus Support\n"); if (optimize_size) fprintf (file, "; -Os\n"); else if (optimize) fprintf (file, "; -O%d\n", optimize); if (TARGET_H8300H) fprintf (file, TARGET_NORMAL_MODE ? "\n\t.h8300hn\n" : "\n\t.h8300h\n"); else if (TARGET_H8300S) fprintf (file, TARGET_NORMAL_MODE ? "\n\t.h8300sn\n" : "\n\t.h8300s\n"); else fprintf (file, "\n\n"); output_file_directive (file, main_input_filename);}/* Output assembly language code for the end of file. */voidasm_file_end (file) FILE *file;{ fprintf (file, "\t.end\n");}/* Return true if OP is a valid source operand for an integer move instruction. */intgeneral_operand_src (op, mode) rtx op; enum machine_mode mode;{ if (GET_MODE (op) == mode && GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == POST_INC) return 1; return general_operand (op, mode);}/* Return true if OP is a valid destination operand for an integer move instruction. */intgeneral_operand_dst (op, mode) rtx op; enum machine_mode mode;{ if (GET_MODE (op) == mode && GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == PRE_DEC) return 1; return general_operand (op, mode);}/* Return true if OP is a constant that contains only one 1 in its binary representation. */intsingle_one_operand (operand, mode) rtx operand; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (operand) == CONST_INT) { /* We really need to do this masking because 0x80 in QImode is represented as -128 for example. */ unsigned HOST_WIDE_INT mask = (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_WIDE_INT) ? ((unsigned HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (mode)) - 1 : ~(unsigned HOST_WIDE_INT) 0; unsigned HOST_WIDE_INT value = INTVAL (operand); if (exact_log2 (value & mask) >= 0) return 1; } return 0;}/* Return true if OP is a constant that contains only one 0 in its binary representation. */intsingle_zero_operand (operand, mode) rtx operand; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (operand) == CONST_INT) { /* We really need to do this masking because 0x80 in QImode is represented as -128 for example. */ unsigned HOST_WIDE_INT mask = (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_WIDE_INT) ? ((unsigned HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (mode)) - 1 : ~(unsigned HOST_WIDE_INT) 0; unsigned HOST_WIDE_INT value = INTVAL (operand); if (exact_log2 (~value & mask) >= 0) return 1; } return 0;}/* Return true if OP is a valid call operand. */intcall_insn_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (op) == MEM) { rtx inside = XEXP (op, 0); if (register_operand (inside, Pmode)) return 1; if (CONSTANT_ADDRESS_P (inside)) return 1; } return 0;}/* Return 1 if an addition/subtraction of a constant integer can be transformed into two consecutive adds/subs that are faster than the straightforward way. Otherwise, return 0. */inttwo_insn_adds_subs_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) { HOST_WIDE_INT value = INTVAL (op); /* Force VALUE to be positive so that we do not have to consider the negative case. */ if (value < 0) value = -value; if (TARGET_H8300H || TARGET_H8300S) { /* A constant addition/subtraction takes 2 states in QImode, 4 states in HImode, and 6 states in SImode. Thus, the only case we can win is when SImode is used, in which case, two adds/subs are used, taking 4 states. */ if (mode == SImode && (value == 2 + 1 || value == 4 + 1 || value == 4 + 2 || value == 4 + 4)) return 1; } else { /* We do not profit directly by splitting addition or subtraction of 3 and 4. However, since these are implemented as a sequence of adds or subs, they do not clobber (cc0) unlike a sequence of add.b and add.x. */ if (mode == HImode && (value == 2 + 1 || value == 2 + 2)) return 1; } } return 0;}/* Split an add of a small constant into two adds/subs insns. */voidsplit_adds_subs (mode, operands) enum machine_mode mode; rtx *operands;{ HOST_WIDE_INT val = INTVAL (operands[1]); rtx reg = operands[0]; HOST_WIDE_INT sign = 1; HOST_WIDE_INT amount; /* Force VAL to be positive so that we do not have to consider the sign. */ if (val < 0) { val = -val; sign = -1; } /* Try different amounts in descending order. */ for (amount = (TARGET_H8300H || TARGET_H8300S) ? 4 : 2; amount > 0; amount /= 2) { for (; val >= amount; val -= amount) { rtx tmp = gen_rtx_PLUS (mode, reg, GEN_INT (sign * amount)); emit_insn (gen_rtx_SET (VOIDmode, reg, tmp)); } } return;}/* Return true if OP is a valid call operand, and OP represents an operand for a small call (4 bytes instead of 6 bytes). */intsmall_call_insn_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (op) == MEM) { rtx inside = XEXP (op, 0); /* Register indirect is a small call. */ if (register_operand (inside, Pmode)) return 1; /* A call through the function vector is a small call too. */ if (GET_CODE (inside) == SYMBOL_REF && SYMBOL_REF_FLAG (inside)) return 1; } /* Otherwise it's a large call. */ return 0;}/* Return true if OP is a valid jump operand. */intjump_address_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == REG) return mode == Pmode; if (GET_CODE (op) == MEM) { rtx inside = XEXP (op, 0); if (register_operand (inside, Pmode)) return 1; if (CONSTANT_ADDRESS_P (inside)) return 1; } return 0;}/* Recognize valid operands for bit-field instructions. */extern int rtx_equal_function_value_matters;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -