📄 alpha.c
字号:
intreg_or_unaligned_mem_operand (op, mode) rtx op; enum machine_mode mode;{ return register_operand (op, mode) || unaligned_memory_operand (op, mode);}/* Return 1 if OP is any memory location. During reload a pseudo matches. */intany_memory_operand (op, mode) register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return (GET_CODE (op) == MEM || (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG) || (reload_in_progress && GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER) || (reload_in_progress && GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG && REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER));}/* Returns 1 if OP is not an eliminable register. This exists to cure a pathological abort in the s8addq (et al) patterns, long foo () { long t; bar(); return (long) &t * 26107; } which run afoul of a hack in reload to cure a (presumably) similar problem with lea-type instructions on other targets. But there is one of us and many of them, so work around the problem by selectively preventing combine from making the optimization. */intreg_not_elim_operand (op, mode) register rtx op; enum machine_mode mode;{ rtx inner = op; if (GET_CODE (op) == SUBREG) inner = SUBREG_REG (op); if (inner == frame_pointer_rtx || inner == arg_pointer_rtx) return 0; return register_operand (op, mode);}/* Return 1 is OP is a memory location that is not a reference (using an AND) to an unaligned location. Take into account what reload will do. */intnormal_memory_operand (op, mode) register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (reload_in_progress) { rtx tmp = op; if (GET_CODE (tmp) == SUBREG) tmp = SUBREG_REG (tmp); if (GET_CODE (tmp) == REG && REGNO (tmp) >= FIRST_PSEUDO_REGISTER) { op = reg_equiv_memory_loc[REGNO (tmp)]; /* This may not have been assigned an equivalent address if it will be eliminated. In that case, it doesn't matter what we do. */ if (op == 0) return 1; } } return GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) != AND;}/* Accept a register, but not a subreg of any kind. This allows us to avoid pathological cases in reload wrt data movement common in int->fp conversion. */intreg_no_subreg_operand (op, mode) register rtx op; enum machine_mode mode;{ if (GET_CODE (op) != REG) return 0; return register_operand (op, mode);}/* Recognize an addition operation that includes a constant. Used to convince reload to canonize (plus (plus reg c1) c2) during register elimination. */intaddition_operation (op, mode) register rtx op; enum machine_mode mode;{ if (GET_MODE (op) != mode && mode != VOIDmode) return 0; if (GET_CODE (op) == PLUS && register_operand (XEXP (op, 0), mode) && GET_CODE (XEXP (op, 1)) == CONST_INT && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op, 1)), 'K')) return 1; return 0;}/* Implements CONST_OK_FOR_LETTER_P. Return true if the value matches the range defined for C in [I-P]. */boolalpha_const_ok_for_letter_p (value, c) HOST_WIDE_INT value; int c;{ switch (c) { case 'I': /* An unsigned 8 bit constant. */ return (unsigned HOST_WIDE_INT) value < 0x100; case 'J': /* The constant zero. */ return value == 0; case 'K': /* A signed 16 bit constant. */ return (unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000; case 'L': /* A shifted signed 16 bit constant appropriate for LDAH. */ return ((value & 0xffff) == 0 && ((value) >> 31 == -1 || value >> 31 == 0)); case 'M': /* A constant that can be AND'ed with using a ZAP insn. */ return zap_mask (value); case 'N': /* A complemented unsigned 8 bit constant. */ return (unsigned HOST_WIDE_INT) (~ value) < 0x100; case 'O': /* A negated unsigned 8 bit constant. */ return (unsigned HOST_WIDE_INT) (- value) < 0x100; case 'P': /* The constant 1, 2 or 3. */ return value == 1 || value == 2 || value == 3; default: return false; }}/* Implements CONST_DOUBLE_OK_FOR_LETTER_P. Return true if VALUE matches for C in [GH]. */boolalpha_const_double_ok_for_letter_p (value, c) rtx value; int c;{ switch (c) { case 'G': /* The floating point zero constant. */ return (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT && value == CONST0_RTX (GET_MODE (value))); case 'H': /* A valid operand of a ZAP insn. */ return (GET_MODE (value) == VOIDmode && zap_mask (CONST_DOUBLE_LOW (value)) && zap_mask (CONST_DOUBLE_HIGH (value))); default: return false; }}/* Implements CONST_DOUBLE_OK_FOR_LETTER_P. Return true if VALUE matches for C. */boolalpha_extra_constraint (value, c) rtx value; int c;{ switch (c) { case 'Q': return normal_memory_operand (value, VOIDmode); case 'R': return direct_call_operand (value, Pmode); case 'S': return (GET_CODE (value) == CONST_INT && (unsigned HOST_WIDE_INT) INTVAL (value) < 64); case 'T': return GET_CODE (value) == HIGH; case 'U': return TARGET_ABI_UNICOSMK && symbolic_operand (value, VOIDmode); case 'W': return (GET_CODE (value) == CONST_VECTOR && value == CONST0_RTX (GET_MODE (value))); default: return false; }}/* Return 1 if this function can directly return via $26. */intdirect_return (){ return (! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK && reload_completed && alpha_sa_size () == 0 && get_frame_size () == 0 && current_function_outgoing_args_size == 0 && current_function_pretend_args_size == 0);}/* Return the ADDR_VEC associated with a tablejump insn. */rtxalpha_tablejump_addr_vec (insn) rtx insn;{ rtx tmp; tmp = JUMP_LABEL (insn); if (!tmp) return NULL_RTX; tmp = NEXT_INSN (tmp); if (!tmp) return NULL_RTX; if (GET_CODE (tmp) == JUMP_INSN && GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC) return PATTERN (tmp); return NULL_RTX;}/* Return the label of the predicted edge, or CONST0_RTX if we don't know. */rtxalpha_tablejump_best_label (insn) rtx insn;{ rtx jump_table = alpha_tablejump_addr_vec (insn); rtx best_label = NULL_RTX; /* ??? Once the CFG doesn't keep getting completely rebuilt, look there for edge frequency counts from profile data. */ if (jump_table) { int n_labels = XVECLEN (jump_table, 1); int best_count = -1; int i, j; for (i = 0; i < n_labels; i++) { int count = 1; for (j = i + 1; j < n_labels; j++) if (XEXP (XVECEXP (jump_table, 1, i), 0) == XEXP (XVECEXP (jump_table, 1, j), 0)) count++; if (count > best_count) best_count = count, best_label = XVECEXP (jump_table, 1, i); } } return best_label ? best_label : const0_rtx;}/* Return the TLS model to use for SYMBOL. */static enum tls_modeltls_symbolic_operand_type (symbol) rtx symbol;{ const char *str; if (GET_CODE (symbol) != SYMBOL_REF) return 0; str = XSTR (symbol, 0); if (str[0] == '%') { /* ??? Be prepared for -ftls-model=local-dynamic. Perhaps we shouldn't have separately encoded local-ness. On well, maybe the user will use attribute visibility next time. At least we don't crash... */ if (str[1] == 'G' || str[1] == 'D') return TLS_MODEL_GLOBAL_DYNAMIC; if (str[1] == 'I' || str[1] == 'T') return TLS_MODEL_INITIAL_EXEC; } else if (str[0] == '@') { if (str[1] == 'D') { /* Local dynamic is a waste if we're not going to combine the __tls_get_addr calls. So avoid it if not optimizing. */ if (optimize) return TLS_MODEL_LOCAL_DYNAMIC; else return TLS_MODEL_GLOBAL_DYNAMIC; } if (str[1] == 'I') return TLS_MODEL_INITIAL_EXEC; if (str[1] == 'T') { /* 64-bit local exec is the same as initial exec except without the dynamic relocation. In either case we use a got entry. */ if (alpha_tls_size == 64) return TLS_MODEL_INITIAL_EXEC; else return TLS_MODEL_LOCAL_EXEC; } } return 0;}/* Return true if the function DECL will be placed in the default text section. *//* ??? Ideally we'd be able to always move from a SYMBOL_REF back to the decl, as that would allow us to determine if two functions are in the same section, which is what we really want to know. */static booldecl_in_text_section (decl) tree decl;{ return (DECL_SECTION_NAME (decl) == NULL_TREE && ! (flag_function_sections || (targetm.have_named_sections && DECL_ONE_ONLY (decl))));}/* Return true if EXP should be placed in the small data section. */static boolalpha_in_small_data_p (exp) tree exp;{ /* We want to merge strings, so we never consider them small data. */ if (TREE_CODE (exp) == STRING_CST) return false; /* Functions are never in the small data area. Duh. */ if (TREE_CODE (exp) == FUNCTION_DECL) return false; if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) { const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp)); if (strcmp (section, ".sdata") == 0 || strcmp (section, ".sbss") == 0) return true; } else { HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); /* If this is an incomplete type with size 0, then we can't put it in sdata because it might be too big when completed. */ if (size > 0 && size <= g_switch_value) return true; } return false;}/* If we are referencing a function that is static, make the SYMBOL_REF special. We use this to see indicate we can branch to this function without setting PV or restoring GP. If this is a variable that is known to be defined locally, add "@v" to the name. If in addition the variable is to go in .sdata/.sbss, then add "@s" instead. */static voidalpha_encode_section_info (decl, first) tree decl; int first ATTRIBUTE_UNUSED;{ const char *symbol_str; bool is_local; char encoding = 0; rtx rtl, symbol; rtl = DECL_P (decl) ? DECL_RTL (decl) : TREE_CST_RTL (decl); /* Careful not to prod global register variables. */ if (GET_CODE (rtl) != MEM) return; symbol = XEXP (rtl, 0); if (GET_CODE (symbol) != SYMBOL_REF) return; if (TREE_CODE (decl) == FUNCTION_DECL) { /* We mark public functions once they are emitted; otherwise we don't know that they exist in this unit of translation. */ if (TREE_PUBLIC (decl)) return; /* Do not mark functions that are not in .text; otherwise we don't know that they are near enough for a direct branch. */ if (! decl_in_text_section (decl)) return; SYMBOL_REF_FLAG (symbol) = 1; return; } /* Early out if we're not going to do anything with this data. */ if (! TARGET_EXPLICIT_RELOCS) return; symbol_str = XSTR (symbol, 0); /* A variable is considered "local" if it is defined in this module. */ is_local = (*targetm.binds_local_p) (decl); /* Care for TLS variables. */ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl)) { switch (decl_tls_model (decl)) { case TLS_MODEL_GLOBAL_DYNAMIC: encoding = 'G'; break; case TLS_MODEL_LOCAL_DYNAMIC: encoding = 'D'; break; case TLS_MODEL_INITIAL_EXEC: encoding = 'I'; break; case TLS_MODEL_LOCAL_EXEC: encoding = 'T'; break; } } else if (is_local) { /* Determine if DECL will wind up in .sdata/.sbss. */ if (alpha_in_small_data_p (decl)) encoding = 'S'; else encoding = 'L'; } /* Finally, encode this into the symbol string. */ if (encoding) { char *newstr; size_t len; char want_prefix = (is_local ? '@' : '%'); char other_prefix = (is_local ? '%' : '@'); if (symbol_str[0] == want_prefix) { if (symbol_str[1] == encoding) return; symbol_str += 2; } else if (symbol_str[0] == other_prefix) symbol_str += 2; len = strlen (symbol_str) + 1; newstr = alloca (len + 2); newstr[0] = want_prefix; newstr[1] = encoding; memcpy (newstr + 2, symbol_str, len); XSTR (symbol, 0) = ggc_alloc_string (newstr, len + 2 - 1); }}/* Undo the effects of the above. */static const char *alpha_strip_name_encoding (str) const char *str;{ if (str[0] == '@' || str[0] == '%') str += 2; if (str[0] == '*')
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -