📄 v850.c
字号:
case CC_CLOBBER: /* Insn doesn't leave CC in a usable state. */ CC_STATUS_INIT; break; }}/* Retrieve the data area that has been chosen for the given decl. */v850_data_areav850_get_data_area (tree decl){ if (lookup_attribute ("sda", DECL_ATTRIBUTES (decl)) != NULL_TREE) return DATA_AREA_SDA; if (lookup_attribute ("tda", DECL_ATTRIBUTES (decl)) != NULL_TREE) return DATA_AREA_TDA; if (lookup_attribute ("zda", DECL_ATTRIBUTES (decl)) != NULL_TREE) return DATA_AREA_ZDA; return DATA_AREA_NORMAL;}/* Store the indicated data area in the decl's attributes. */static voidv850_set_data_area (tree decl, v850_data_area data_area){ tree name; switch (data_area) { case DATA_AREA_SDA: name = get_identifier ("sda"); break; case DATA_AREA_TDA: name = get_identifier ("tda"); break; case DATA_AREA_ZDA: name = get_identifier ("zda"); break; default: return; } DECL_ATTRIBUTES (decl) = tree_cons (name, NULL, DECL_ATTRIBUTES (decl));}const struct attribute_spec v850_attribute_table[] ={ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ { "interrupt_handler", 0, 0, true, false, false, v850_handle_interrupt_attribute }, { "interrupt", 0, 0, true, false, false, v850_handle_interrupt_attribute }, { "sda", 0, 0, true, false, false, v850_handle_data_area_attribute }, { "tda", 0, 0, true, false, false, v850_handle_data_area_attribute }, { "zda", 0, 0, true, false, false, v850_handle_data_area_attribute }, { NULL, 0, 0, false, false, false, NULL }};/* Handle an "interrupt" attribute; arguments as in struct attribute_spec.handler. */static treev850_handle_interrupt_attribute (tree * node, tree name, tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, bool * no_add_attrs){ if (TREE_CODE (*node) != FUNCTION_DECL) { warning (OPT_Wattributes, "%qs attribute only applies to functions", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } return NULL_TREE;}/* Handle a "sda", "tda" or "zda" attribute; arguments as in struct attribute_spec.handler. */static treev850_handle_data_area_attribute (tree* node, tree name, tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, bool * no_add_attrs){ v850_data_area data_area; v850_data_area area; tree decl = *node; /* Implement data area attribute. */ if (is_attribute_p ("sda", name)) data_area = DATA_AREA_SDA; else if (is_attribute_p ("tda", name)) data_area = DATA_AREA_TDA; else if (is_attribute_p ("zda", name)) data_area = DATA_AREA_ZDA; else gcc_unreachable (); switch (TREE_CODE (decl)) { case VAR_DECL: if (current_function_decl != NULL_TREE) { error ("%Jdata area attributes cannot be specified for " "local variables", decl); *no_add_attrs = true; } /* Drop through. */ case FUNCTION_DECL: area = v850_get_data_area (decl); if (area != DATA_AREA_NORMAL && data_area != area) { error ("data area of %q+D conflicts with previous declaration", decl); *no_add_attrs = true; } break; default: break; } return NULL_TREE;}/* Return nonzero if FUNC is an interrupt function as specified by the "interrupt" attribute. */intv850_interrupt_function_p (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_ATTRIBUTES (func)); if (a != NULL_TREE) ret = 1; else { a = lookup_attribute ("interrupt", DECL_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;}static voidv850_encode_data_area (tree decl, rtx symbol){ int flags; /* Map explicit sections into the appropriate attribute */ if (v850_get_data_area (decl) == DATA_AREA_NORMAL) { if (DECL_SECTION_NAME (decl)) { const 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; } flags = SYMBOL_REF_FLAGS (symbol); switch (v850_get_data_area (decl)) { case DATA_AREA_ZDA: flags |= SYMBOL_FLAG_ZDA; break; case DATA_AREA_TDA: flags |= SYMBOL_FLAG_TDA; break; case DATA_AREA_SDA: flags |= SYMBOL_FLAG_SDA; break; default: gcc_unreachable (); } SYMBOL_REF_FLAGS (symbol) = flags;}static voidv850_encode_section_info (tree decl, rtx rtl, int first){ default_encode_section_info (decl, rtl, first); if (TREE_CODE (decl) == VAR_DECL && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))) v850_encode_data_area (decl, XEXP (rtl, 0));}/* 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 (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", count); return NULL; } /* Work out how many bytes to pop off the stack before retrieving registers. */ gcc_assert (GET_CODE (XVECEXP (op, 0, 1)) == SET); gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) == PLUS); gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) == CONST_INT); 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); gcc_assert (GET_CODE (vector_element) == SET); gcc_assert (GET_CODE (SET_DEST (vector_element)) == REG); gcc_assert (register_is_ok_for_epilogue (SET_DEST (vector_element), SImode)); 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; } gcc_assert (first < 32); /* Discover the last register to pop. */ if (mask & (1 << LINK_POINTER_REGNUM)) { gcc_assert (stack_bytes == 16); last = LINK_POINTER_REGNUM; } else { gcc_assert (!stack_bytes); gcc_assert (mask & (1 << 29)); 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;}/* 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 (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. */ gcc_assert (GET_CODE (XVECEXP (op, 0, 0)) == SET); gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) == PLUS); gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0)) == REG); gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) == CONST_INT); /* 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 - (TARGET_LONG_CALLS ? 3 : 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 - (TARGET_LONG_CALLS ? 2 : 1); i++) { rtx vector_element = XVECEXP (op, 0, i); gcc_assert (GET_CODE (vector_element) == SET); gcc_assert (GET_CODE (SET_SRC (vector_element)) == REG); gcc_assert (register_is_ok_for_epilogue (SET_SRC (vector_element), SImode)); 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; } gcc_assert (first < 32); /* Discover the last register to push. */ if (mask & (1 << LINK_POINTER_REGNUM)) { gcc_assert (stack_bytes == -16); last = LINK_POINTER_REGNUM; } else { gcc_assert (!stack_bytes); gcc_assert (mask & (1 << 29)); 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 * file, tree decl, const char * name, unsigned HOST_WIDE_INT size, int align){ switch (v850_get_data_area (decl)) { case DATA_AREA_ZDA: zbss_section (); break; case DATA_AREA_SDA: sbss_section (); break; case DATA_AREA_TDA: tdata_section (); default: bss_section (); break; } ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));#ifdef ASM_DECLARE_OBJECT_NAME last_assemble_variable_decl = decl; ASM_DECLARE_OBJECT_NAME (file, name, decl);#else /* Standard thing is just output label for the object. */ ASM_OUTPUT_LABEL (file, name);#endif /* ASM_DECLARE_OBJECT_NAME */ ASM_OUTPUT_SKIP (file, size ? size : 1);}/* Called via the macro ASM_OUTPUT_DECL_COMMON */voidv850_output_common (FILE * file, tree decl, const char * name, int size, int align){ if (decl == NULL_TREE) { fprintf (file, "%s", COMMON_ASM_OP); } else { switch (v850_get_data_area (decl)) { case DATA_AREA_ZDA: fprintf (file, "%s", ZCOMMON_ASM_OP); break; case DATA_AREA_SDA: fprintf (file, "%s", SCOMMON_ASM_OP); break; case DATA_AREA_TDA: fprintf (file, "%s", TCOMMON_ASM_OP); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -