📄 v850.c
字号:
/* If no epilog save function is available, restore the registers the old fashioned way (one by one). */ if (!restore_all) { /* If the stack is large, we need to cut it down in 2 pieces. */ if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize)) init_stack_free = 4 * num_restore; else init_stack_free = actual_fsize; /* Deallocate the rest of the stack if it is > 32K or if extra stack was allocated for an interrupt handler that makes a call. */ if (actual_fsize > init_stack_free || (interrupt_handler && actual_fsize)) { int diff = actual_fsize - ((interrupt_handler) ? 0 : init_stack_free); if (CONST_OK_FOR_K (diff)) emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (diff))); else { rtx reg = gen_rtx (REG, Pmode, 12); emit_move_insn (reg, GEN_INT (diff)); emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); } } /* Special case interrupt functions that save all registers for a call. */ if (interrupt_handler && ((1L << 31) & reg_saved) != 0) emit_insn (gen_restore_all_interrupt ()); else { /* Restore registers from the beginning of the stack frame */ offset = init_stack_free - 4; /* Restore the return pointer first. */ if (num_restore > 0 && REGNO (restore_regs[num_restore-1]) == 31) { emit_move_insn (restore_regs[--num_restore], gen_rtx (MEM, SImode, plus_constant (stack_pointer_rtx, offset))); offset -= 4; } for (i = 0; i < num_restore; i++) { emit_move_insn (restore_regs[i], gen_rtx (MEM, SImode, plus_constant (stack_pointer_rtx, offset))); offset -= 4; } /* Cut back the remainder of the stack. */ if (init_stack_free) emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (init_stack_free))); } /* And return or use reti for interrupt handlers. */ if (interrupt_handler) emit_jump_insn (gen_restore_interrupt ()); else if (actual_fsize) emit_jump_insn (gen_return_internal ()); else emit_jump_insn (gen_return ()); } current_function_anonymous_args = 0; v850_interrupt_cache_p = FALSE; v850_interrupt_p = FALSE;}/* Update the condition code from the insn. */voidnotice_update_cc (body, insn) rtx body; rtx insn;{ switch (get_attr_cc (insn)) { case CC_NONE: /* Insn does not affect CC at all. */ break; case CC_NONE_0HIT: /* Insn does not change CC, but the 0'th operand has been changed. */ if (cc_status.value1 != 0 && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1)) cc_status.value1 = 0; break; case CC_SET_ZN: /* Insn sets the Z,N flags of CC to recog_operand[0]. V,C is in an unusable state. */ CC_STATUS_INIT; cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY; cc_status.value1 = recog_operand[0]; break; case CC_SET_ZNV: /* Insn sets the Z,N,V flags of CC to recog_operand[0]. C is in an unusable state. */ CC_STATUS_INIT; cc_status.flags |= CC_NO_CARRY; 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_CLOBBER: /* Insn doesn't leave CC in a usable state. */ CC_STATUS_INIT; break; }}/* Return nonzero if ATTR is a valid attribute for DECL. ATTRIBUTES are any existing attributes and ARGS are the arguments supplied with ATTR. Supported attributes: interrupt_handler or interrupt: output a prologue and epilogue suitable for an interrupt handler. */intv850_valid_machine_decl_attribute (decl, attributes, attr, args) tree decl; tree attributes; tree attr; tree args;{ if (args != NULL_TREE) return 0; if (is_attribute_p ("interrupt_handler", attr) || is_attribute_p ("interrupt", attr)) return TREE_CODE (decl) == FUNCTION_DECL; return 0;}/* Return nonzero if FUNC is an interrupt function as specified by the "interrupt" attribute. */intv850_interrupt_function_p (func) tree func;{ tree a; int ret = 0; if (v850_interrupt_cache_p) return v850_interrupt_p; if (TREE_CODE (func) != FUNCTION_DECL) return 0; a = lookup_attribute ("interrupt_handler", DECL_MACHINE_ATTRIBUTES (func)); if (a != NULL_TREE) ret = 1; else { a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func)); ret = a != NULL_TREE; } /* Its not safe to trust global variables until after function inlining has been done. */ if (reload_completed | reload_in_progress) v850_interrupt_p = ret; return ret;}extern struct obstack *saveable_obstack;v850_encode_data_area (decl) tree decl;{ char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0); int len = strlen (str); char *newstr; /* In the Cygnus sources we actually do something; this is just here to make merges easier. */ return;}/* Return true if the given RTX is a register which can be restored by a function epilogue. */intregister_is_ok_for_epilogue (op, mode) rtx op; enum machine_mode mode;{ /* The save/restore routines can only cope with registers 2, and 20 - 31 */ return (GET_CODE (op) == REG) && (((REGNO (op) >= 20) && REGNO (op) <= 31) || REGNO (op) == 2);}/* Return non-zero if the given RTX is suitable for collapsing into jump to a function epilogue. */intpattern_is_ok_for_epilogue (op, mode) rtx op; enum machine_mode mode;{ int count = XVECLEN (op, 0); int i; /* If there are no registers to restore then the function epilogue is not suitable. */ if (count <= 2) return 0; /* The pattern matching has already established that we are performing a function epilogue and that we are popping at least one register. We must now check the remaining entries in the vector to make sure that they are also register pops. There is no good reason why there should ever be anything else in this vector, but being paranoid always helps... The test below performs the C equivalent of this machine description pattern match: (set (match_operand:SI n "register_is_ok_for_epilogue" "r") (mem:SI (plus:SI (reg:SI 3) (match_operand:SI n "immediate_operand" "i")))) */ for (i = 3; i < count; i++) { rtx vector_element = XVECEXP (op, 0, i); rtx dest; rtx src; rtx plus; if (GET_CODE (vector_element) != SET) return 0; dest = SET_DEST (vector_element); src = SET_SRC (vector_element); if (GET_CODE (dest) != REG || GET_MODE (dest) != SImode || ! register_is_ok_for_epilogue (dest, SImode) || GET_CODE (src) != MEM || GET_MODE (src) != SImode) return 0; plus = XEXP (src, 0); if (GET_CODE (plus) != PLUS || GET_CODE (XEXP (plus, 0)) != REG || GET_MODE (XEXP (plus, 0)) != SImode || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM || GET_CODE (XEXP (plus, 1)) != CONST_INT) return 0; } return 1;}/* Construct a JR instruction to a routine that will perform the equivalent of the RTL passed in as an argument. This RTL is a function epilogue that pops registers off the stack and possibly releases some extra stack space as well. The code has already verified that the RTL matches these requirements. */char *construct_restore_jr (op) rtx op;{ int count = XVECLEN (op, 0); int stack_bytes; unsigned long int mask; unsigned long int first; unsigned long int last; int i; static char buff [100]; /* XXX */ if (count <= 2) { error ("Bogus JR construction: %d\n", count); return NULL; } /* Work out how many bytes to pop off the stack before retrieving registers. */ if (GET_CODE (XVECEXP (op, 0, 1)) != SET) abort (); if (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) != PLUS) abort (); if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) != CONST_INT) abort (); stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)); /* Each pop will remove 4 bytes from the stack... */ stack_bytes -= (count - 2) * 4; /* Make sure that the amount we are popping either 0 or 16 bytes. */ if (stack_bytes != 0 && stack_bytes != 16) { error ("Bad amount of stack space removal: %d", stack_bytes); return NULL; } /* Now compute the bit mask of registers to push. */ mask = 0; for (i = 2; i < count; i++) { rtx vector_element = XVECEXP (op, 0, i); if (GET_CODE (vector_element) != SET) abort (); if (GET_CODE (SET_DEST (vector_element)) != REG) abort (); if (! register_is_ok_for_epilogue (SET_DEST (vector_element), SImode)) abort (); mask |= 1 << REGNO (SET_DEST (vector_element)); } /* Scan for the first register to pop. */ for (first = 0; first < 32; first++) { if (mask & (1 << first)) break; } if (first >= 32) abort (); /* Discover the last register to pop. */ if (mask & (1 << 31)) { if (stack_bytes != 16) abort (); last = 31; } else { if (stack_bytes != 0) abort (); if ((mask & (1 << 29)) == 0) abort (); last = 29; } /* Paranoia */ for (i = (first == 2 ? 20 : first + 1); i < 29; i++) if ((mask & (1 << i)) == 0) abort (); if (first == last) sprintf (buff, "jr __return_%s", reg_names [first]); else sprintf (buff, "jr __return_%s_%s", reg_names [first], reg_names [last]); return buff;}/* Return non-zero if the given RTX is suitable for collapsing into a jump to a function prologue. */intpattern_is_ok_for_prologue (op, mode) rtx op; enum machine_mode mode;{ int count = XVECLEN (op, 0); int i; rtx vector_element; /* If there are no registers to save then the function prologue is not suitable. */ if (count <= 2) return 0; /* The pattern matching has already established that we are adjusting the stack and pushing at least one register. We must now check that the remaining entries in the vector to make sure that they are also register pushes, except for the last entry which should be a CLOBBER of r10. The test below performs the C equivalent of this machine description pattern match: (set (mem:SI (plus:SI (reg:SI 3) (match_operand:SI 2 "immediate_operand" "i"))) (match_operand:SI 3 "register_is_ok_for_epilogue" "r")) */ for (i = 2; i < count - 1; i++) { rtx dest; rtx src; rtx plus; vector_element = XVECEXP (op, 0, i); if (GET_CODE (vector_element) != SET) return 0; dest = SET_DEST (vector_element); src = SET_SRC (vector_element); if (GET_CODE (dest) != MEM || GET_MODE (dest) != SImode || GET_CODE (src) != REG || GET_MODE (src) != SImode || ! register_is_ok_for_epilogue (src, SImode)) return 0; plus = XEXP (dest, 0); if ( GET_CODE (plus) != PLUS || GET_CODE (XEXP (plus, 0)) != REG || GET_MODE (XEXP (plus, 0)) != SImode || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM || GET_CODE (XEXP (plus, 1)) != CONST_INT) return 0; /* If the register is being pushed somewhere other than the stack space just acquired by the first operand then abandon this quest. Note: the test is <= because both values are negative. */ if (INTVAL (XEXP (plus, 1)) <= INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1))) { return 0; } } /* Make sure that the last entry in the vector is a clobber. */ vector_element = XVECEXP (op, 0, i); if (GET_CODE (vector_element) != CLOBBER || GET_CODE (XEXP (vector_element, 0)) != REG || REGNO (XEXP (vector_element, 0)) != 10) return 0; return 1;}/* Construct a JARL instruction to a routine that will perform the equivalent of the RTL passed as a parameter. This RTL is a function prologue that saves some of the registers r20 - r31 onto the stack, and possibly acquires some stack space as well. The code has already verified that the RTL matches these requirements. */char *construct_save_jarl (op) rtx op;{ int count = XVECLEN (op, 0); int stack_bytes; unsigned long int mask; unsigned long int first; unsigned long int last; int i; static char buff [100]; /* XXX */ if (count <= 2) { error ("Bogus JARL construction: %d\n", count); return NULL; } /* Paranoia. */ if (GET_CODE (XVECEXP (op, 0, 0)) != SET) abort (); if (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != PLUS) abort (); if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0)) != REG) abort (); if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) != CONST_INT) abort (); /* Work out how many bytes to push onto the stack after storing the registers. */ stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)); /* Each push will put 4 bytes from the stack... */ stack_bytes += (count - 2) * 4; /* Make sure that the amount we are popping either 0 or 16 bytes. */ if (stack_bytes != 0 && stack_bytes != -16) { error ("Bad amount of stack space removal: %d", stack_bytes); return NULL; } /* Now compute the bit mask of registers to push. */ mask = 0; for (i = 1; i < count - 1; i++) { rtx vector_element = XVECEXP (op, 0, i); if (GET_CODE (vector_element) != SET) abort (); if (GET_CODE (SET_SRC (vector_element)) != REG) abort (); if (! register_is_ok_for_epilogue (SET_SRC (vector_element), SImode)) abort (); mask |= 1 << REGNO (SET_SRC (vector_element)); } /* Scan for the first register to push. */ for (first = 0; first < 32; first++) { if (mask & (1 << first)) break; } if (first >= 32) abort (); /* Discover the last register to push. */ if (mask & (1 << 31)) { if (stack_bytes != -16) abort(); last = 31; } else { if (stack_bytes != 0) abort (); if ((mask & (1 << 29)) == 0) abort (); last = 29; } /* Paranoia */ for (i = (first == 2 ? 20 : first + 1); i < 29; i++) if ((mask & (1 << i)) == 0) abort (); if (first == last) sprintf (buff, "jarl __save_%s, r10", reg_names [first]); else sprintf (buff, "jarl __save_%s_%s, r10", reg_names [first], reg_names [last]); return buff;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -