📄 cris.c
字号:
RTX_CODE code; /* Mainly stolen from refers_to_regno_p in rtlanal.c. */ code = GET_CODE (x); switch (code) { case REG: i = REGNO (x); return !call_used_regs[i]; case SUBREG: /* If this is a SUBREG of a hard reg, we can see exactly which registers are being modified. Otherwise, handle normally. */ i = REGNO (SUBREG_REG (x)); return !call_used_regs[i]; default: ; } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') { if (saved_regs_mentioned (XEXP (x, i))) return 1; } else if (fmt[i] == 'E') { int j; for (j = XVECLEN (x, i) - 1; j >=0; j--) if (saved_regs_mentioned (XEXP (x, i))) return 1; } } return 0;}/* Figure out if the insn may be put in the epilogue. */intcris_eligible_for_epilogue_delay (insn) rtx insn;{ /* First of all, it must be as slottable as for a delayed branch insn. */ if (get_attr_slottable (insn) != SLOTTABLE_YES) return 0; /* It must not refer to the stack pointer (may be valid for some cases that I can't think of). */ if (reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))) return 0; /* The frame pointer will be restored in the epilogue, before the "ret", so it can't be referred to. */ if (frame_pointer_needed && reg_mentioned_p (frame_pointer_rtx, PATTERN (insn))) return 0; /* All saved regs are restored before the delayed insn. This means that we cannot have any instructions that mention the registers that are restored by the epilogue. */ if (saved_regs_mentioned (PATTERN (insn))) return 0; /* It seems to be ok. */ return 1;}/* Return the number of delay-slots in the epilogue: return 1 if it contains "ret", else 0. */intcris_delay_slots_for_epilogue (){ /* Check if we use a return insn, which we only do for leaf functions. Else there is no slot to fill. */ if (regs_ever_live[CRIS_SRP_REGNUM] || cfun->machine->needs_return_address_on_stack != 0) return 0; /* By calling function_epilogue with the same parameters as from gcc we can get info about if the epilogue can fill the delay-slot by itself. If it is filled from the epilogue, then the corresponding string is in save_last. This depends on that the "size" argument to function_epilogue always is get_frame_size. FIXME: Kludgy. At least make it a separate function that is not misnamed or abuses the stream parameter. */ cris_target_asm_function_epilogue (NULL, get_frame_size ()); if (*save_last) return 1; return 0;}/* Textual function epilogue. When file is NULL, it serves doubly as a test for whether the epilogue can fill any "ret" delay-slots by itself by storing the delay insn in save_last. */static voidcris_target_asm_function_epilogue (file, size) FILE *file; HOST_WIDE_INT size;{ int regno; int last_movem_reg = -1; rtx insn = get_last_insn (); int argspace_offset = current_function_outgoing_args_size; int pretend = current_function_pretend_args_size; int return_address_on_stack = regs_ever_live[CRIS_SRP_REGNUM] || cfun->machine->needs_return_address_on_stack != 0; save_last[0] = 0; if (file && !TARGET_PROLOGUE_EPILOGUE) return; if (TARGET_PDEBUG && file) fprintf (file, ";;\n"); /* Align byte count of stack frame. */ if (TARGET_STACK_ALIGN) size = TARGET_ALIGN_BY_32 ? (size + 3) & ~3 : (size + 1) & ~1; /* If the last insn was a BARRIER, we don't have to write any code, then all returns were covered by "return" insns. */ if (GET_CODE (insn) == NOTE) insn = prev_nonnote_insn (insn); if (insn && (GET_CODE (insn) == BARRIER /* We must make sure that the insn really is a "return" and not a conditional branch. Try to match the return exactly, and if it doesn't match, assume it is a conditional branch (and output an epilogue). */ || (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) == RETURN))) { if (TARGET_PDEBUG && file) fprintf (file, ";;;;;\n"); return; } /* Check how many saved regs we can movem. They start at r0 and must be contiguous. */ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if ((((regs_ever_live[regno] && !call_used_regs[regno]) || (regno == (int) PIC_OFFSET_TABLE_REGNUM && (current_function_uses_pic_offset_table /* It is saved anyway, if there would be a gap. */ || (flag_pic && regs_ever_live[regno + 1] && !call_used_regs[regno + 1])))) && (regno != FRAME_POINTER_REGNUM || !frame_pointer_needed) && regno != CRIS_SRP_REGNUM) || (current_function_calls_eh_return && (regno == EH_RETURN_DATA_REGNO (0) || regno == EH_RETURN_DATA_REGNO (1) || regno == EH_RETURN_DATA_REGNO (2) || regno == EH_RETURN_DATA_REGNO (3)))) { if (regno == last_movem_reg + 1) last_movem_reg++; else break; } for (regno = FIRST_PSEUDO_REGISTER - 1; regno > last_movem_reg; regno--) if ((((regs_ever_live[regno] && !call_used_regs[regno]) || (regno == (int) PIC_OFFSET_TABLE_REGNUM && (current_function_uses_pic_offset_table /* It is saved anyway, if there would be a gap. */ || (flag_pic && regs_ever_live[regno + 1] && !call_used_regs[regno + 1])))) && (regno != FRAME_POINTER_REGNUM || !frame_pointer_needed) && regno != CRIS_SRP_REGNUM) || (current_function_calls_eh_return && (regno == EH_RETURN_DATA_REGNO (0) || regno == EH_RETURN_DATA_REGNO (1) || regno == EH_RETURN_DATA_REGNO (2) || regno == EH_RETURN_DATA_REGNO (3)))) { if (argspace_offset) { /* There is an area for outgoing parameters located before the saved registers. We have to adjust for that. */ if (file) fprintf (file, "\tAdd%s %d,$sp\n", ADDITIVE_SIZE_MODIFIER (argspace_offset), argspace_offset); /* Make sure we only do this once. */ argspace_offset = 0; } /* Flush previous non-movem:ed registers. */ if (*save_last && file) fprintf (file, save_last); sprintf (save_last, "\tPop $%s\n", reg_names[regno]); } if (last_movem_reg != -1) { if (argspace_offset) { /* Adjust for the outgoing parameters area, if that's not handled yet. */ if (*save_last && file) { fprintf (file, save_last); *save_last = 0; } if (file) fprintf (file, "\tAdd%s %d,$sp\n", ADDITIVE_SIZE_MODIFIER (argspace_offset), argspace_offset); argspace_offset = 0; } /* Flush previous non-movem:ed registers. */ else if (*save_last && file) fprintf (file, save_last); sprintf (save_last, "\tmovem [$sp+],$%s\n", reg_names[last_movem_reg]); } /* Restore frame pointer if necessary. */ if (frame_pointer_needed) { if (*save_last && file) fprintf (file, save_last); if (file) fprintf (file, "\tmove.d $%s,$sp\n", reg_names[FRAME_POINTER_REGNUM]); sprintf (save_last, "\tPop $%s\n", reg_names[FRAME_POINTER_REGNUM]); } else { /* If there was no frame-pointer to restore sp from, we must explicitly deallocate local variables. */ /* Handle space for outgoing parameters that hasn't been handled yet. */ size += argspace_offset; if (size) { if (*save_last && file) fprintf (file, save_last); sprintf (save_last, "\tadd%s %d,$sp\n", ADDITIVE_SIZE_MODIFIER (size), size); } /* If the size was not in the range for a "quick", we must flush it here. */ if (size > 63) { if (file) fprintf (file, save_last); *save_last = 0; } } /* If this function has no pushed register parameters (stdargs/varargs), and if it is not a leaf function, then we can just jump-return here. */ if (return_address_on_stack && pretend == 0) { if (*save_last && file) fprintf (file, save_last); *save_last = 0; if (file) { if (current_function_calls_eh_return) { /* The installed EH-return address is in *this* frame, so we need to pop it before we return. */ fprintf (file, "\tpop $srp\n"); fprintf (file, "\tret\n"); fprintf (file, "\tadd.d $%s,$sp\n", reg_names[CRIS_STACKADJ_REG]); } else fprintf (file, "\tJump [$sp+]\n"); /* Do a sanity check to avoid generating invalid code. */ if (current_function_epilogue_delay_list) internal_error ("allocated but unused delay list in epilogue"); } return; } /* Rather than add current_function_calls_eh_return conditions everywhere in the following code (and not be able to test it thoroughly), assert the assumption that all usage of __builtin_eh_return are handled above. */ if (current_function_calls_eh_return) internal_error ("unexpected function type needing stack adjustment for\ __builtin_eh_return"); /* If we pushed some register parameters, then adjust the stack for them. */ if (pretend) { /* Since srp is stored on the way, we need to restore it first. */ if (return_address_on_stack) { if (*save_last && file) fprintf (file, save_last); *save_last = 0; if (file) fprintf (file, "\tpop $srp\n"); } if (*save_last && file) fprintf (file, save_last); sprintf (save_last, "\tadd%s %d,$sp\n", ADDITIVE_SIZE_MODIFIER (pretend), pretend); } /* Here's where we have a delay-slot we need to fill. */ if (file && current_function_epilogue_delay_list) { /* If gcc has allocated an insn for the epilogue delay slot, but things were arranged so we now thought we could do it ourselves, don't forget to flush that insn. */ if (*save_last) fprintf (file, save_last); fprintf (file, "\tRet\n"); /* Output the delay-slot-insn the mandated way. */ final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), file, 1, -2, 1); } else if (file) { fprintf (file, "\tRet\n"); /* If the GCC did not do it, we have to use whatever insn we have, or a nop. */ if (*save_last) fprintf (file, save_last); else fprintf (file, "\tnOp\n"); }}/* The PRINT_OPERAND worker. */voidcris_print_operand (file, x, code) FILE *file; rtx x; int code;{ rtx operand = x; /* Size-strings corresponding to MULT expressions. */ static const char *const mults[] = { "BAD:0", ".b", ".w", "BAD:3", ".d" }; /* New code entries should just be added to the switch below. If handling is finished, just return. If handling was just a modification of the operand, the modified operand should be put in "operand", and then do a break to let default handling (zero-modifier) output the operand. */ switch (code) { case 'b': /* Print the unsigned supplied integer as if it was signed and < 0, i.e print 255 or 65535 as -1, 254, 65534 as -2, etc. */ if (GET_CODE (x) != CONST_INT || ! CONST_OK_FOR_LETTER_P (INTVAL (x), 'O')) LOSE_AND_RETURN ("invalid operand for 'b' modifier", x); fprintf (file, "%d", INTVAL (x)| (INTVAL (x) <= 255 ? ~255 : ~65535)); return; case 'x': /* Print assembler code for operator. */ fprintf (file, "%s", cris_op_str (operand)); return; case 'v': /* Print the operand without the PIC register. */ if (! flag_pic || ! CONSTANT_P (x) || ! cris_gotless_symbol (x)) LOSE_AND_RETURN ("invalid operand for 'v' modifier", x); cris_pic_sympart_only++; cris_output_addr_const (file, x); cris_pic_sympart_only--; return; case 'P': /* Print the PIC register. Applied to a GOT-less PIC symbol for sanity. */ if (! flag_pic || ! CONSTANT_P (x) || ! cris_gotless_symbol (x)) LOSE_AND_RETURN ("invalid operand for 'P' modifier", x); fprintf (file, "$%s", reg_names [PIC_OFFSET_TABLE_REGNUM]); return; case 'p': /* Adjust a power of two to its log2. */ if (GET_CODE (x) != CONST_INT || exact_log2 (INTVAL (x)) < 0 ) LOSE_AND_RETURN ("invalid operand for 'p' modifier", x); fprintf (file, "%d", exact_log2 (INTVAL (x))); return; case 's': /* For an integer, print 'b' or 'w' if <= 255 or <= 65535 respectively. This modifier also terminates the inhibiting effects of the 'x' modifier. */ cris_output_insn_is_bound = 0; if (GET_MODE (x) == VOIDmode && GET_CODE (x) == CONST_INT) { if (INTVAL (x) >= 0) { if (INTVAL (x) <= 255) putc ('b', file); else if (INTVAL (x) <= 65535) putc ('w', file); else putc ('d', file); } else putc ('d', file); return; } /* For a non-integer, print the size of the operand. */ putc ((GET_MODE (x) == SImode || GET_MODE (x) == SFmode) ? 'd' : GET_MODE (x) == HImode ? 'w' : GET_MODE (x) == QImode ? 'b' /* If none of the above, emit an erroneous size letter. */ : 'X', file); return; case 'z': /* Const_int: print b for -127 <= x <= 255, w for -32768 <= x <= 65535, else abort. */ if (GET_CODE (x) != CONST_INT || INTVAL (x) < -32768 || INTVAL (x) > 65535) LOSE_AND_RETURN ("invalid operand for 'z' modifier", x);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -