📄 m32r.c
字号:
/* 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]); } /* 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 (void){ 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. */intm32r_legitimate_pic_operand_p (rtx x){ if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) return 0; if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF) && (GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)) return 0; return 1;}rtxm32r_legitimize_pic_address (rtx orig, rtx reg){#ifdef DEBUG_PIC printf("m32r_legitimize_pic_address()\n");#endif if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF) { rtx pic_ref, address; rtx insn; int subregs = 0; if (reg == 0) { if (reload_in_progress || reload_completed) abort (); else reg = gen_reg_rtx (Pmode); subregs = 1; } if (subregs) address = gen_reg_rtx (Pmode); else address = reg; current_function_uses_pic_offset_table = 1; if (GET_CODE (orig) == LABEL_REF || (GET_CODE (orig) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (orig))) { emit_insn (gen_gotoff_load_addr (reg, orig)); emit_insn (gen_addsi3 (reg, reg, pic_offset_table_rtx)); return reg; } emit_insn (gen_pic_load_addr (address, orig)); emit_insn (gen_addsi3 (address, address, pic_offset_table_rtx)); pic_ref = gen_const_mem (Pmode, address); insn = emit_move_insn (reg, pic_ref);#if 0 /* Put a REG_EQUAL note on this insn, so that it can be optimized by loop. */ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig, REG_NOTES (insn));#endif return reg; } else if (GET_CODE (orig) == CONST) { rtx base, offset; if (GET_CODE (XEXP (orig, 0)) == PLUS && XEXP (XEXP (orig, 0), 1) == pic_offset_table_rtx) return orig; if (reg == 0) { if (reload_in_progress || reload_completed) abort (); else reg = gen_reg_rtx (Pmode); } if (GET_CODE (XEXP (orig, 0)) == PLUS) { base = m32r_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), reg); if (base == reg) offset = m32r_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), NULL_RTX); else offset = m32r_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), reg); } else return orig; if (GET_CODE (offset) == CONST_INT) { if (INT16_P (INTVAL (offset))) return plus_constant (base, INTVAL (offset)); else if (! reload_in_progress && ! reload_completed) offset = force_reg (Pmode, offset); else /* If we reach here, then something is seriously wrong. */ abort (); } return gen_rtx_PLUS (Pmode, base, offset); } return orig;}/* Emit special PIC prologues and epilogues. */voidm32r_finalize_pic (void){ current_function_uses_pic_offset_table |= current_function_profile;}/* 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 (rtx tramp ATTRIBUTE_UNUSED, rtx fnaddr ATTRIBUTE_UNUSED, rtx cxt ATTRIBUTE_UNUSED){}static voidm32r_file_start (void){ default_file_start (); if (flag_verbose_asm) fprintf (asm_out_file, "%s M32R/D special options: -G " HOST_WIDE_INT_PRINT_UNSIGNED "\n", ASM_COMMENT_START, g_switch_value); if (TARGET_LITTLE_ENDIAN) fprintf (asm_out_file, "\t.little\n");}/* 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 * 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, HOST_WIDE_INT_PRINT_HEX, (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_operand_lossage ("invalid operand to %%U code"); return; case 'N' : /* Print a constant value negated. */ if (GET_CODE (x) == CONST_INT) output_addr_const (file, GEN_INT (- INTVAL (x))); else output_operand_lossage ("invalid operand to %%N code"); return; case 'X' : /* Print a const_int in hex. Used in comments. */ if (GET_CODE (x) == CONST_INT) fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (x)); return; case '#' : fputs (IMMEDIATE_PREFIX, file); return; case 0 : /* Do nothing special. */ break; default : /* Unknown flag. */ output_operand_lossage ("invalid operand output code"); } switch (GET_CODE (x)) { case REG : fputs (reg_names[REGNO (x)], file); break; case MEM : addr = XEXP (x, 0); if (GET_CODE (addr) == PRE_INC) { if (GET_CODE (XEXP (addr, 0)) != REG) fatal_insn ("pre-increment address is not a register", x); fprintf (file, "@+%s", reg_names[REGNO (XEXP (addr, 0))]); } else if (GET_CODE (addr) == PRE_DEC) { if (GET_CODE (XEXP (addr, 0)) != REG) fatal_insn ("pre-decrement address is not a register", x); fprintf (file, "@-%s", reg_names[REGNO (XEXP (addr, 0))]); } else if (GET_CODE (addr) == POST_INC) { if (GET_CODE (XEXP (addr, 0)) != REG) fatal_insn ("post-increment address is not a register", x); fprintf (file, "@%s+", reg_names[REGNO (XEXP (addr, 0))]); } else { fputs ("@(", file); output_address (XEXP (x, 0)); fputc (')', file); } break; case CONST_DOUBLE : /* We handle
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -