*************** *** 2103,2105 **** } #endif /* THUMB_PE */ /* END CYGNUS LOCAL nickc/thumb-pe */ --- 2103,2264 ---- } #endif /* THUMB_PE */ /* END CYGNUS LOCAL nickc/thumb-pe */ + + /* Return nonzero if ATTR is a valid attribute for TYPE. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + short_call: assume the offset from the caller to the callee is small. + + long_call: don't assume the offset is small. */ + + int + arm_valid_machine_type_attribute (type, attributes, attr, args) + tree type; + tree attributes; + tree attr; + tree args; + { + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("long_call", attr)) + return 1; + + if (is_attribute_p ("short_call", attr)) + return 1; + + return 0; + } + + /* Encode long_call or short_call attribute by prefixing + symbol name in DECL with a special character FLAG. */ + + void + arm_encode_call_attribute (decl, flag) + tree decl; + int flag; + { + const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0); + int len = strlen (str); + char * newstr; + + /* Do not allow weak functions to be treated as short call. */ + if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR) + return; + + if (ENCODED_SHORT_CALL_ATTR_P (str) + || ENCODED_LONG_CALL_ATTR_P (str)) + return; + + newstr = malloc (len + 2); + newstr[0] = flag; + strcpy (newstr + 1, str); + + XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr; + } + + /* Return the length of a function name prefix + that starts with the character 'c'. */ + + static int + arm_get_strip_length (char c) + { + switch (c) + { + ARM_NAME_ENCODING_LENGTHS + default: return 0; + } + } + + /* Return a pointer to a function's name with any + and all prefix encodings stripped from it. */ + + char * + arm_strip_name_encoding (char * name) + { + int skip; + + while ((skip = arm_get_strip_length (* name))) + name += skip; + + return name; + } + + /* Return 1 if the operand is a SYMBOL_REF for a function known to be + defined within the current compilation unit. If this caanot be + determined, then 0 is returned. */ + + static int + current_file_function_operand (sym_ref) + rtx sym_ref; + { + /* This is a bit of a fib. A function will have a short call flag + applied to its name if it has the short call attribute, or it has + already been defined within the current compilation unit. */ + if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0))) + return 1; + + /* The current function is always defined within the current compilation + unit. if it s a weak definition however, then this may not be the real + definition of the function, and so we have to say no. */ + if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0) + && !DECL_WEAK (current_function_decl)) + return 1; + + /* We cannot make the determination - default to returning 0. */ + return 0; + } + + /* Return non-zero if a 32 bit "long_call" should be generated for + this call. We generate a long_call if the function: + + a. has an __attribute__((long call)) + or b. the -mlong-calls command line switch has been specified + + However we do not generate a long call if the function: + + c. has an __attribute__ ((short_call)) + or d. has an __attribute__ ((section)) + or e. is defined within the current compilation unit. + + This function will be called by C fragments contained in the machine + description file. CALL_REF and CALL_COOKIE correspond to the matched + rtl operands. CALL_SYMBOL is used to distinguish between + two different callers of the function. It is set to 1 in the + "call_symbol" and "call_symbol_value" patterns and to 0 in the "call" + and "call_value" patterns. This is because of the difference in the + SYM_REFs passed by these patterns. */ + + int + arm_is_longcall_p (sym_ref, call_cookie, call_symbol) + rtx sym_ref; + int call_cookie; + int call_symbol; + { + if (!call_symbol) + { + if (GET_CODE (sym_ref) != MEM) + return 0; + + sym_ref = XEXP (sym_ref, 0); + } + + if (GET_CODE (sym_ref) != SYMBOL_REF) + return 0; + + if (call_cookie & CALL_SHORT) + return 0; + + if (TARGET_LONG_CALLS && flag_function_sections) + return 1; + + if (current_file_function_operand (sym_ref)) + return 0; + + return (call_cookie & CALL_LONG) + || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0)) + || TARGET_LONG_CALLS; + }