diff options
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 190 | ||||
-rw-r--r-- | gcc/config/arm/arm.h | 103 |
3 files changed, 269 insertions, 33 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 30f0230..2e17b20 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2000-02-09 Philip Blundell <pb@futuretv.com> + + * config/arm/arm.c (legitimize_pic_address): Handle LABEL_REF + correctly. + + * config/arm/arm.h (LEGITIMATE_CONSTANT_P): Allow anything when + generating PIC. + (LEGITIMATE_PIC_OPERAND): Disallow references to labels. + 2000-02-09 Zack Weinberg <zack@wolery.cumb.org> * cpplib.c (cpp_define, cpp_undef): Make sure the stacked buffer diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index c3c5360..6560893 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -1476,6 +1476,181 @@ arm_return_in_memory (type) return 1; } +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is NULL. */ +void +arm_init_cumulative_args (pcum, fntype, libname, indirect) + CUMULATIVE_ARGS * pcum; + tree fntype; + rtx libname ATTRIBUTE_UNUSED; + int indirect ATTRIBUTE_UNUSED; +{ + /* On the ARM, the offset starts at 0. */ + pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype))) + ? 1 : 0); + + pcum->call_cookie = CALL_NORMAL; + + if (TARGET_LONG_CALLS) + pcum->call_cookie = CALL_LONG; + + /* Check for long call/short call attributes. The attributes + override any command line option. */ + if (fntype) + { + if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (fntype))) + pcum->call_cookie = CALL_SHORT; + else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype))) + pcum->call_cookie = CALL_LONG; + } +} + +/* Determine where to put an argument to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ +rtx +arm_function_arg (pcum, mode, type, named) + CUMULATIVE_ARGS * pcum; + enum machine_mode mode; + tree type ATTRIBUTE_UNUSED; + int named; +{ + if (mode == VOIDmode) + /* Compute operand 2 of the call insn. */ + return GEN_INT (pcum->call_cookie); + + if (! named || pcum->nregs >= NUM_ARG_REGS) + return NULL_RTX; + + return gen_rtx_REG (mode, pcum->nregs); +} + + +/* Return 1 if the operand is a SYMBOL_REF for a function known to be in + this file. */ +static int +current_file_function_operand (sym_ref) + rtx sym_ref; +{ + return (SYMBOL_REF_FLAG (sym_ref) + || sym_ref == XEXP (DECL_RTL (current_function_decl), 0)); +} + +/* Return non-zero if a 32 bit "long call" should be generated for this + call. + + We generate a long call if the function is not declared + __attribute__ ((short_call), + + AND: + + (1) the function is declared __attribute__ ((long_call)) + + OR + + (2) -mlong-calls is enabled and we don't know whether the target + function is declared in this file. + + This function will typically be called by C fragments in the machine + description file. CALL_REF is the matched rtl operand. CALL_COOKIE + describes the value of the long_call and short_call attributes for + the called functiion. 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 in arm.md and to 0 in the "call" and + "call_value" patterns. This is because of the difference of SYM_REFs passed + from "call_symbol" and "call" 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, VOIDmode)) + return 0; + + return (call_cookie & CALL_LONG) || TARGET_LONG_CALLS; +} + +/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific + attribute for TYPE. The attributes in ATTRIBUTES have previously been + assigned to TYPE. */ +int +arm_valid_type_attribute_p (type, attributes, identifier, args) + tree type; + tree attributes ATTRIBUTE_UNUSED; + tree identifier; + tree args; +{ + if ( TREE_CODE (type) != FUNCTION_TYPE + && TREE_CODE (type) != METHOD_TYPE + && TREE_CODE (type) != FIELD_DECL + && TREE_CODE (type) != TYPE_DECL) + return 0; + + /* Function calls made to this symbol must be done indirectly, because + it may lie outside of the 26 bit addressing range of a normal function + call. */ + if (is_attribute_p ("long_call", identifier)) + return (args == NULL_TREE); + + /* Whereas these functions are always known to reside within the 26 bit + addressing range. */ + if (is_attribute_p ("short_call", identifier)) + return (args == NULL_TREE); + + return 0; +} + +/* Return 0 if the attributes for two types are incompatible, 1 if they + are compatible, and 2 if they are nearly compatible (which causes a + warning to be generated). */ +int +arm_comp_type_attributes (type1, type2) + tree type1; + tree type2; +{ + int l1, l2, s1, s2; + /* Check for mismatch of non-default calling convention. */ + if (TREE_CODE (type1) != FUNCTION_TYPE) + return 1; + + /* Check for mismatched call attributes. */ + l1 = ! lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1)); + l2 = ! lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)); + s1 = ! lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1)); + s2 = ! lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2)); + + return ! ((l1 ^ l2) || (s1 ^s2) || (l1 | s2) || (s1 | l2)); +} + + int legitimate_pic_operand_p (x) rtx x; @@ -1590,7 +1765,20 @@ legitimize_pic_address (orig, mode, reg) return gen_rtx_PLUS (Pmode, base, offset); } else if (GET_CODE (orig) == LABEL_REF) - current_function_uses_pic_offset_table = 1; + { + current_function_uses_pic_offset_table = 1; + + if (NEED_GOT_RELOC) + { + rtx pic_ref, address = gen_reg_rtx (Pmode); + + emit_insn (gen_pic_load_addr (address, orig)); + pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, address); + + emit_move_insn (address, pic_ref); + return address; + } + } return orig; } diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 33f5932..f457f92 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -1,5 +1,5 @@ /* Definitions of target machine for GNU compiler, for ARM. - Copyright (C) 1991, 93-98, 1999 Free Software Foundation, Inc. + Copyright (C) 1991, 93, 94, 05, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) and Martin Simmons (@harleqn.co.uk). More major hacks by Richard Earnshaw (rearnsha@arm.com) @@ -48,7 +48,7 @@ Boston, MA 02111-1307, USA. */ #define TARGET_CPU_strongarm1100 0x0040 #define TARGET_CPU_arm9 0x0080 #define TARGET_CPU_arm9tdmi 0x0080 -/* Configure didn't specify */ +/* Configure didn't specify. */ #define TARGET_CPU_generic 0x8000 enum arm_cond_code @@ -365,7 +365,7 @@ Unrecognized value in TARGET_CPU_DEFAULT. "Generate re-entrant, PIC code" }, \ {"no-apcs-reentrant", -ARM_FLAG_APCS_REENT, "" }, \ {"alignment-traps", ARM_FLAG_MMU_TRAPS, \ - "The MMU will trap on unaligned accesses" },\ + "The MMU will trap on unaligned accesses" }, \ {"no-alignment-traps", -ARM_FLAG_MMU_TRAPS, "" }, \ {"short-load-bytes", ARM_FLAG_MMU_TRAPS, "" }, \ {"no-short-load-bytes", -ARM_FLAG_MMU_TRAPS, "" }, \ @@ -385,7 +385,7 @@ Unrecognized value in TARGET_CPU_DEFAULT. "Support calls between THUMB and ARM instructions sets" }, \ {"no-thumb-interwork", -ARM_FLAG_INTERWORK, "" }, \ {"abort-on-noreturn", ARM_FLAG_ABORT_NORETURN, \ - "Generate a call to abort if a noreturn function returns"}, \ + "Generate a call to abort if a noreturn function returns"},\ {"no-abort-on-noreturn", -ARM_FLAG_ABORT_NORETURN, ""}, \ {"sched-prolog", -ARM_FLAG_NO_SCHED_PRO, \ "Do not move instructions into a function's prologue" }, \ @@ -394,7 +394,7 @@ Unrecognized value in TARGET_CPU_DEFAULT. "Do not load the PIC register in function prologues" }, \ {"no-single-pic-base", -ARM_FLAG_SINGLE_PIC_BASE, "" }, \ {"long-calls", ARM_FLAG_LONG_CALLS, \ - "Generate all call instructions as indirect calls"}, \ + "Generate all call instructions as indirect calls"}, \ {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ SUBTARGET_SWITCHES \ {"", TARGET_DEFAULT, "" } \ @@ -411,7 +411,7 @@ Unrecognized value in TARGET_CPU_DEFAULT. {"fp=", & target_fp_name, \ "Specify the version of the floating point emulator" }, \ { "structure-size-boundary=", & structure_size_string, \ - "Specify the minumum bit alignment of structures" }, \ + "Specify the minimum bit alignment of structures" }, \ { "pic-register=", & arm_pic_register_string, \ "Specify the register to be used for PIC addressing" } \ } @@ -1136,6 +1136,23 @@ enum reg_class than a word, or if they contain elements offset from zero in the struct. */ #define DEFAULT_PCC_STRUCT_RETURN 0 +/* A C type for declaring a variable that is used as the first argument of + `FUNCTION_ARG' and other related values. For some target machines, the + type `int' suffices and can hold the number of bytes of argument so far. */ +typedef struct +{ + /* This is the number of argument registers scanned so far. */ + int nregs; + /* instructions on how to process this call. */ + int call_cookie; +} +CUMULATIVE_ARGS; + +/* Flags for the call_cookie field of CUMULATIVE_ARGS. */ +#define CALL_NORMAL 0 /* No special processing. */ +#define CALL_LONG 1 /* Always call indirect. */ +#define CALL_SHORT 2 /* Never call indirect. */ + /* Define where to put the arguments to a function. Value is zero to push the argument on the stack, or a hard register in which to store the argument. @@ -1154,38 +1171,29 @@ enum reg_class only in assign_parms, since SETUP_INCOMING_VARARGS is defined), say it is passed in the stack (function_prologue will indeed make it pass in the stack if necessary). */ -#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ - ((NAMED) \ - ? ((CUM) >= NUM_ARG_REGS ? 0 : gen_rtx_REG (MODE, CUM))\ - : 0) +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + arm_function_arg (&(CUM), (MODE), (TYPE), (NAMED)) /* For an arg passed partly in registers and partly in memory, this is the number of registers used. For args passed entirely in registers or entirely in memory, zero. */ #define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ - ( NUM_ARG_REGS > (CUM) \ - && (NUM_ARG_REGS < ((CUM) + NUM_REGS2 (MODE, TYPE))) \ - ? NUM_ARG_REGS - (CUM) : 0) - -/* A C type for declaring a variable that is used as the first argument of - `FUNCTION_ARG' and other related values. For some target machines, the - type `int' suffices and can hold the number of bytes of argument so far. - - On the ARM, this is the number of bytes of arguments scanned so far. */ -#define CUMULATIVE_ARGS int + ( NUM_ARG_REGS > (CUM).nregs \ + && (NUM_ARG_REGS < ((CUM).nregs + NUM_REGS2 (MODE, TYPE))) \ + ? NUM_ARG_REGS - (CUM).nregs : 0) /* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. On the ARM, the offset starts at 0. */ -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ - ((CUM) = (((FNTYPE) && aggregate_value_p (TREE_TYPE ((FNTYPE)))) ? 1 : 0)) +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ + arm_init_cumulative_args (&(CUM), (FNTYPE), (LIBNAME), (INDIRECT)) /* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. (TYPE is null for libcalls where that information may not be available.) */ #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ - (CUM) += NUM_REGS2 (MODE, TYPE) + (CUM).nregs += NUM_REGS2 (MODE, TYPE) /* 1 if N is a possible register number for function argument passing. On the ARM, r0-r3 are used to pass args. */ @@ -1209,8 +1217,8 @@ enum reg_class { \ extern int current_function_anonymous_args; \ current_function_anonymous_args = 1; \ - if ((CUM) < NUM_ARG_REGS) \ - (PRETEND_SIZE) = (NUM_ARG_REGS - (CUM)) * UNITS_PER_WORD; \ + if ((CUM).nregs < NUM_ARG_REGS) \ + (PRETEND_SIZE) = (NUM_ARG_REGS - (CUM).nregs) * UNITS_PER_WORD; \ } /* Generate assembly output for the start of a function. */ @@ -1437,8 +1445,18 @@ enum reg_class On the ARM, allow any integer (invalid ones are removed later by insn patterns), nice doubles and symbol_refs which refer to the function's - constant pool XXX. */ -#define LEGITIMATE_CONSTANT_P(X) (! label_mentioned_p (X)) + constant pool XXX. + + When generating pic allow anything. */ +#define LEGITIMATE_CONSTANT_P(X) (flag_pic || ! label_mentioned_p (X)) + +/* If we are referencing a function that is static or is known to be + in this file, make the SYMBOL_REF special. We can use this to indicate + that we can do direct call to that function. */ +#define ARM_MARK_NEARBY_FUNCTION(decl) \ + if (TREE_CODE (decl) == FUNCTION_DECL \ + && (TREE_ASM_WRITTEN (decl) || ! TREE_PUBLIC (decl))) \ + SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1; \ /* Symbols in the text segment can be accessed without indirecting via the constant pool; it may take an extra binary operation, but this is still @@ -1457,6 +1475,13 @@ enum reg_class ? TREE_CST_RTL (decl) : DECL_RTL (decl)); \ SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; \ } \ + \ + ARM_MARK_NEARBY_FUNCTION (decl) \ +} +#else +#define ENCODE_SECTION_INFO(decl) \ +{ \ + ARM_MARK_NEARBY_FUNCTION (decl) \ } #endif @@ -1875,16 +1900,30 @@ extern const char * arm_pic_register_string; /* We can't directly access anything that contains a symbol, nor can we indirect via the constant pool. */ -#define LEGITIMATE_PIC_OPERAND_P(X) \ - (! symbol_mentioned_p (X) \ - && (! CONSTANT_POOL_ADDRESS_P (X) \ - || ! symbol_mentioned_p (get_pool_constant (X)))) +#define LEGITIMATE_PIC_OPERAND_P(X) \ + ( ! symbol_mentioned_p (X) \ + && ! label_mentioned_p (X) \ + && (! CONSTANT_POOL_ADDRESS_P (X) \ + || ( ! symbol_mentioned_p (get_pool_constant (X))) \ + && ! label_mentioned_p (get_pool_constant (X)))) /* We need to know when we are making a constant pool; this determines whether data needs to be in the GOT or can be referenced via a GOT offset. */ extern int making_const_table; - + +/* If defined, a C expression whose value is nonzero if IDENTIFIER + with arguments ARGS is a valid machine specific attribute for TYPE. + The attributes in ATTRIBUTES have previously been assigned to TYPE. */ +#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, NAME, ARGS) \ + (arm_valid_type_attribute_p (TYPE, ATTRIBUTES, NAME, ARGS)) + +/* If defined, a C expression whose value is zero if the attributes on + TYPE1 and TYPE2 are incompatible, one if they are compatible, and + two if they are nearly compatible (which causes a warning to be + generated). */ +#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \ + (arm_comp_type_attributes (TYPE1, TYPE2)) /* Condition code information. */ /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, |