📄 v850.c
字号:
case FUNCTION_DECL: area = v850_get_data_area (decl); if (area != DATA_AREA_NORMAL && data_area != area) error_with_decl (decl, "\data area of '%s' conflicts with previous declaration"); return 1; default: break; } 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;voidv850_encode_data_area (decl) tree decl;{ char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0); int len = strlen (str); char * newstr; /* Map explict sections into the appropriate attribute */ if (v850_get_data_area (decl) == DATA_AREA_NORMAL) { if (DECL_SECTION_NAME (decl)) { char * name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); if (streq (name, ".zdata") || streq (name, ".zbss")) v850_set_data_area (decl, DATA_AREA_ZDA); else if (streq (name, ".sdata") || streq (name, ".sbss")) v850_set_data_area (decl, DATA_AREA_SDA); else if (streq (name, ".tdata")) v850_set_data_area (decl, DATA_AREA_TDA); } /* If no attribute, support -m{zda,sda,tda}=n */ else { int size = int_size_in_bytes (TREE_TYPE (decl)); if (size <= 0) ; else if (size <= small_memory [(int) SMALL_MEMORY_TDA].max) v850_set_data_area (decl, DATA_AREA_TDA); else if (size <= small_memory [(int) SMALL_MEMORY_SDA].max) v850_set_data_area (decl, DATA_AREA_SDA); else if (size <= small_memory [(int) SMALL_MEMORY_ZDA].max) v850_set_data_area (decl, DATA_AREA_ZDA); } if (v850_get_data_area (decl) == DATA_AREA_NORMAL) return; } newstr = obstack_alloc (saveable_obstack, len + 2); strcpy (newstr + 1, str); switch (v850_get_data_area (decl)) { case DATA_AREA_ZDA: *newstr = ZDA_NAME_FLAG_CHAR; break; case DATA_AREA_TDA: *newstr = TDA_NAME_FLAG_CHAR; break; case DATA_AREA_SDA: *newstr = SDA_NAME_FLAG_CHAR; break; default: abort (); } XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;}/* 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 ATTRIBUTE_UNUSED 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 ATTRIBUTE_UNUSED 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 << LINK_POINTER_REGNUM)) { if (stack_bytes != 16) abort (); last = LINK_POINTER_REGNUM; } else { if (stack_bytes != 0) abort (); if ((mask & (1 << 29)) == 0) abort (); last = 29; } /* Note, it is possible to have gaps in the register mask. We ignore this here, and generate a JR anyway. We will be popping more registers than is strictly necessary, but it does save code space. */ if (TARGET_LONG_CALLS) { char name[40]; if (first == last) sprintf (name, "__return_%s", reg_names [first]); else sprintf (name, "__return_%s_%s", reg_names [first], reg_names [last]); sprintf (buff, "movhi hi(%s), r0, r6\n\tmovea lo(%s), r6, r6\n\tjmp r6", name, name); } else { 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 ATTRIBUTE_UNUSED 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 << LINK_POINTER_REGNUM)) { if (stack_bytes != -16) abort (); last = LINK_POINTER_REGNUM; } else { if (stack_bytes != 0) abort (); if ((mask & (1 << 29)) == 0) abort (); last = 29; } /* Note, it is possible to have gaps in the register mask. We ignore this here, and generate a JARL anyway. We will be pushing more registers than is strictly necessary, but it does save code space. */ if (TARGET_LONG_CALLS) { char name[40]; if (first == last) sprintf (name, "__save_%s", reg_names [first]); else sprintf (name, "__save_%s_%s", reg_names [first], reg_names [last]); sprintf (buff, "movhi hi(%s), r0, r11\n\tmovea lo(%s), r11, r11\n\tjarl .+4, r10\n\tadd 4, r10\n\tjmp r11", name, name); } else { 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;}extern tree last_assemble_variable_decl;extern int size_directive_output;/* A version of asm_output_aligned_bss() that copes with the special data areas of the v850. */voidv850_output_aligned_bss (file, decl, name, size, align) FILE * file; tree decl; c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -