📄 m32r.c
字号:
/* See if this is an interrupt handler. Call used registers must be saved for them too. */ fn_type = m32r_compute_function_type (current_function_decl); interrupt_p = M32R_INTERRUPT_P (fn_type); /* Calculate space needed for registers. */ for (regno = 0; regno < M32R_MAX_INT_REGS; regno++) { if (MUST_SAVE_REGISTER (regno, interrupt_p)) { reg_size += UNITS_PER_WORD; gmask |= 1 << regno; } } current_frame_info.save_fp = MUST_SAVE_FRAME_POINTER; current_frame_info.save_lr = MUST_SAVE_RETURN_ADDR; reg_size += ((current_frame_info.save_fp + current_frame_info.save_lr) * UNITS_PER_WORD); total_size += reg_size; /* ??? Not sure this is necessary, and I don't think the epilogue handler will do the right thing if this changes total_size. */ total_size = M32R_STACK_ALIGN (total_size); frame_size = total_size - (pretend_size + reg_size); /* Save computed information. */ current_frame_info.total_size = total_size; current_frame_info.extra_size = extra_size; current_frame_info.pretend_size = pretend_size; current_frame_info.var_size = var_size; current_frame_info.args_size = args_size; current_frame_info.reg_size = reg_size; current_frame_info.gmask = gmask; current_frame_info.initialized = reload_completed; /* Ok, we're done. */ return total_size;}/* When the `length' insn attribute is used, this macro specifies the value to be assigned to the address of the first insn in a function. If not specified, 0 is used. */intm32r_first_insn_address (){ if (! current_frame_info.initialized) m32r_compute_frame_size (get_frame_size ()); return 0;}/* Expand the m32r prologue as a series of insns. */voidm32r_expand_prologue (){ int regno; int frame_size; unsigned int gmask; if (! current_frame_info.initialized) m32r_compute_frame_size (get_frame_size ()); gmask = current_frame_info.gmask; /* These cases shouldn't happen. Catch them now. */ if (current_frame_info.total_size == 0 && gmask) abort (); /* Allocate space for register arguments if this is a variadic function. */ if (current_frame_info.pretend_size != 0) { /* Use a HOST_WIDE_INT temporary, since negating an unsigned int gives the wrong result on a 64-bit host. */ HOST_WIDE_INT pretend_size = current_frame_info.pretend_size; emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-pretend_size))); } /* Save any registers we need to and set up fp. */ if (current_frame_info.save_fp) emit_insn (gen_movsi_push (stack_pointer_rtx, frame_pointer_rtx)); gmask &= ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK); /* Save any needed call-saved regs (and call-used if this is an interrupt handler). */ for (regno = 0; regno <= M32R_MAX_INT_REGS; ++regno) { if ((gmask & (1 << regno)) != 0) emit_insn (gen_movsi_push (stack_pointer_rtx, gen_rtx_REG (Pmode, regno))); } if (current_frame_info.save_lr) emit_insn (gen_movsi_push (stack_pointer_rtx, gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM))); /* Allocate the stack frame. */ frame_size = (current_frame_info.total_size - (current_frame_info.pretend_size + current_frame_info.reg_size)); if (frame_size == 0) ; /* nothing to do */ else if (frame_size <= 32768) emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-frame_size))); else { rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM); emit_insn (gen_movsi (tmp, GEN_INT (frame_size))); emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp)); } if (frame_pointer_needed) emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); if (current_function_profile) emit_insn (gen_blockage ());}/* Set up the stack and frame pointer (if desired) for the function. Note, if this is changed, you need to mirror the changes in m32r_compute_frame_size which calculates the prolog size. */static voidm32r_output_function_prologue (file, size) FILE * file; HOST_WIDE_INT size;{ enum m32r_function_type fn_type = m32r_compute_function_type (current_function_decl); /* If this is an interrupt handler, mark it as such. */ if (M32R_INTERRUPT_P (fn_type)) { fprintf (file, "\t%s interrupt handler\n", ASM_COMMENT_START); } if (! current_frame_info.initialized) m32r_compute_frame_size (size); /* This is only for the human reader. */ fprintf (file, "\t%s PROLOGUE, vars= %d, regs= %d, args= %d, extra= %d\n", ASM_COMMENT_START, current_frame_info.var_size, current_frame_info.reg_size / 4, current_frame_info.args_size, current_frame_info.extra_size);}/* Do any necessary cleanup after a function to restore stack, frame, and regs. */static voidm32r_output_function_epilogue (file, size) FILE * file; HOST_WIDE_INT size ATTRIBUTE_UNUSED;{ int regno; int noepilogue = FALSE; int total_size; enum m32r_function_type fn_type = m32r_compute_function_type (current_function_decl); /* This is only for the human reader. */ fprintf (file, "\t%s EPILOGUE\n", ASM_COMMENT_START); if (!current_frame_info.initialized) abort (); total_size = current_frame_info.total_size; if (total_size == 0) { rtx insn = get_last_insn (); /* If the last insn was a BARRIER, we don't have to write any code because a jump (aka return) was put there. */ if (GET_CODE (insn) == NOTE) insn = prev_nonnote_insn (insn); if (insn && GET_CODE (insn) == BARRIER) noepilogue = TRUE; } if (!noepilogue) { unsigned int var_size = current_frame_info.var_size; unsigned int args_size = current_frame_info.args_size; unsigned int gmask = current_frame_info.gmask; int can_trust_sp_p = !current_function_calls_alloca; const char * sp_str = reg_names[STACK_POINTER_REGNUM]; const char * fp_str = reg_names[FRAME_POINTER_REGNUM]; /* The first thing to do is point the sp at the bottom of the register save area. */ if (can_trust_sp_p) { unsigned int reg_offset = var_size + args_size; if (reg_offset == 0) ; /* nothing to do */ else if (reg_offset < 128) fprintf (file, "\taddi %s,%s%d\n", sp_str, IMMEDIATE_PREFIX, reg_offset); else if (reg_offset < 32768) fprintf (file, "\tadd3 %s,%s,%s%d\n", sp_str, sp_str, IMMEDIATE_PREFIX, reg_offset); else fprintf (file, "\tld24 %s,%s%d\n\tadd %s,%s\n", reg_names[PROLOGUE_TMP_REGNUM], IMMEDIATE_PREFIX, reg_offset, sp_str, reg_names[PROLOGUE_TMP_REGNUM]); } else if (frame_pointer_needed) { unsigned int reg_offset = var_size + args_size; if (reg_offset == 0) fprintf (file, "\tmv %s,%s\n", sp_str, fp_str); else if (reg_offset < 32768) fprintf (file, "\tadd3 %s,%s,%s%d\n", sp_str, fp_str, IMMEDIATE_PREFIX, reg_offset); else fprintf (file, "\tld24 %s,%s%d\n\tadd %s,%s\n", reg_names[PROLOGUE_TMP_REGNUM], IMMEDIATE_PREFIX, reg_offset, sp_str, reg_names[PROLOGUE_TMP_REGNUM]); } else abort (); if (current_frame_info.save_lr) fprintf (file, "\tpop %s\n", reg_names[RETURN_ADDR_REGNUM]); /* Restore any saved registers, in reverse order of course. */ gmask &= ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK); for (regno = M32R_MAX_INT_REGS - 1; regno >= 0; --regno) { if ((gmask & (1L << regno)) != 0) fprintf (file, "\tpop %s\n", reg_names[regno]); } if (current_frame_info.save_fp) fprintf (file, "\tpop %s\n", fp_str); /* Remove varargs area if present. */ if (current_frame_info.pretend_size != 0) fprintf (file, "\taddi %s,%s%d\n", sp_str, IMMEDIATE_PREFIX, current_frame_info.pretend_size); /* Emit the return instruction. */ if (M32R_INTERRUPT_P (fn_type)) fprintf (file, "\trte\n"); else fprintf (file, "\tjmp %s\n", reg_names[RETURN_ADDR_REGNUM]); }#if 0 /* no longer needed */ /* Ensure the function cleanly ends on a 32 bit boundary. */ fprintf (file, "\t.fillinsn\n");#endif /* Reset state info for each function. */ current_frame_info = zero_frame_info; m32r_compute_function_type (NULL_TREE);}/* Return nonzero if this function is known to have a null or 1 instruction epilogue. */intdirect_return (){ if (!reload_completed) return FALSE; if (! current_frame_info.initialized) m32r_compute_frame_size (get_frame_size ()); return current_frame_info.total_size == 0;}/* PIC *//* Emit special PIC prologues and epilogues. */voidm32r_finalize_pic (){ /* nothing to do */}/* Nested function support. *//* Emit RTL insns to initialize the variable parts of a trampoline. FNADDR is an RTX for the address of the function's pure code. CXT is an RTX for the static chain value for the function. */voidm32r_initialize_trampoline (tramp, fnaddr, cxt) rtx tramp ATTRIBUTE_UNUSED; rtx fnaddr ATTRIBUTE_UNUSED; rtx cxt ATTRIBUTE_UNUSED;{}/* Set the cpu type and print out other fancy things, at the top of the file. */voidm32r_asm_file_start (file) FILE * file;{ if (flag_verbose_asm) fprintf (file, "%s M32R/D special options: -G %d\n", ASM_COMMENT_START, g_switch_value);}/* Print operand X (an rtx) in assembler syntax to file FILE. CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. For `%' followed by punctuation, CODE is the punctuation and X is null. */voidm32r_print_operand (file, x, code) FILE * file; rtx x; int code;{ rtx addr; switch (code) { /* The 's' and 'p' codes are used by output_block_move() to indicate post-increment 's'tores and 'p're-increment loads. */ case 's': if (GET_CODE (x) == REG) fprintf (file, "@+%s", reg_names [REGNO (x)]); else output_operand_lossage ("invalid operand to %%s code"); return; case 'p': if (GET_CODE (x) == REG) fprintf (file, "@%s+", reg_names [REGNO (x)]); else output_operand_lossage ("invalid operand to %%p code"); return; case 'R' : /* Write second word of DImode or DFmode reference, register or memory. */ if (GET_CODE (x) == REG) fputs (reg_names[REGNO (x)+1], file); else if (GET_CODE (x) == MEM) { fprintf (file, "@("); /* Handle possible auto-increment. Since it is pre-increment and we have already done it, we can just use an offset of four. */ /* ??? This is taken from rs6000.c I think. I don't think it is currently necessary, but keep it around. */ if (GET_CODE (XEXP (x, 0)) == PRE_INC || GET_CODE (XEXP (x, 0)) == PRE_DEC) output_address (plus_constant (XEXP (XEXP (x, 0), 0), 4)); else output_address (plus_constant (XEXP (x, 0), 4)); fputc (')', file); } else output_operand_lossage ("invalid operand to %%R code"); return; case 'H' : /* High word */ case 'L' : /* Low word */ if (GET_CODE (x) == REG) { /* L = least significant word, H = most significant word */ if ((WORDS_BIG_ENDIAN != 0) ^ (code == 'L')) fputs (reg_names[REGNO (x)], file); else fputs (reg_names[REGNO (x)+1], file); } else if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) { rtx first, second; split_double (x, &first, &second); fprintf (file, HOST_WIDE_INT_PRINT_HEX, code == 'L' ? INTVAL (first) : INTVAL (second)); } else output_operand_lossage ("invalid operand to %%H/%%L code"); return; case 'A' : { char str[30]; if (GET_CODE (x) != CONST_DOUBLE || GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT) fatal_insn ("bad insn for 'A'", x); real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x), sizeof (str), 0, 1); fprintf (file, "%s", str); return; } case 'B' : /* Bottom half */ case 'T' : /* Top half */ /* Output the argument to a `seth' insn (sets the Top half-word). For constants output arguments to a seth/or3 pair to set Top and Bottom halves. For symbols output arguments to a seth/add3 pair to set Top and Bottom halves. The difference exists because for constants seth/or3 is more readable but for symbols we need to use the same scheme as `ld' and `st' insns (16 bit addend is signed). */ switch (GET_CODE (x)) { case CONST_INT : case CONST_DOUBLE : { rtx first, second; split_double (x, &first, &second); x = WORDS_BIG_ENDIAN ? second : first; fprintf (file,#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT "0x%x",#else "0x%lx",#endif (code == 'B' ? INTVAL (x) & 0xffff : (INTVAL (x) >> 16) & 0xffff)); } return; case CONST : case SYMBOL_REF : if (code == 'B' && small_data_operand (x, VOIDmode)) { fputs ("sda(", file); output_addr_const (file, x); fputc (')', file); return; } /* fall through */ case LABEL_REF : fputs (code == 'T' ? "shigh(" : "low(", file); output_addr_const (file, x); fputc (')', file); return; default : output_operand_lossage ("invalid operand to %%T/%%B code"); return; } break; case 'U' : /* ??? wip */ /* Output a load/store with update indicator if appropriate. */ if (GET_CODE (x) == MEM) { if (GET_CODE (XEXP (x, 0)) == PRE_INC || GET_CODE (XEXP (x, 0)) == PRE_DEC) fputs (".a", file); } else output
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -