From: Richard Earnshaw Date: Wed, 1 Jun 1994 17:09:29 +0000 (+0000) Subject: General tidy up. X-Git-Tag: misc/cutover-egcs-0~6527 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f3bb6135f6a5cd960e40c8e2febfa22c6b90347f;p=thirdparty%2Fgcc.git General tidy up. #include . Declare some prototypes. (output_memory_reference_mode): Change type to enum machine_mode. (arm_const_nmoves): Delete. (adjacent_mem_locations, {load,store}_multiple_operation): Explicitly declare to return int. ({load,store}_multiple_operation): Change type of 'count', 'base' and 'i' to HOST_WIDE_INT. (output_add_immediate): Change type of 'n' to HOST_WIDE_INT. (output_multi_immediate): Change type of Argument 'n' to HOST_WIDE_INT, if wider than 32 bits, mask out the high bits. (output_arithmetic_with_immediate_multiply): Change type of 'shift' to HOST_WIDE_INT. (output_func_{prologue,epilogue}): Renamed from output_{prologue,epilogue}. Check all registers to see if they are live, but only push/pop them if they are not in call_used_regs. (const_pool_offset): New function. (get_prologue_size): New function. (output_func_prologue): Eliminate variable code_size. (output_func_epilogue): Only call arm_increase_location when optimizing; also add the size of the function just compiled, and the size of the prologue. (arm_output_asm_insn): Delete. All callers changed to use output_asm_insn. (arm_output_llc): Delete. (output_load_symbol): New first parameter 'insn'. Rewrite so that assembler can detect whether we made a mistake. From-SVN: r7416 --- diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index dae7f9825bce..0e8d7d7b6bb2 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -21,6 +21,7 @@ along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include +#include #include "assert.h" #include "config.h" #include "rtl.h" @@ -42,9 +43,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Some function declarations. */ extern FILE *asm_out_file; extern char *output_multi_immediate (); -extern char *arm_output_asm_insn (); extern void arm_increase_location (); +HOST_WIDE_INT int_log2 PROTO ((HOST_WIDE_INT)); +static int get_prologue_size PROTO ((void)); + /* Define the information needed to generate branch insns. This is stored from the compare operation. */ @@ -58,7 +61,7 @@ enum processor_type arm_cpu; /* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we must report the mode of the memory reference from PRINT_OPERAND to PRINT_OPERAND_ADDRESS. */ -int output_memory_reference_mode; +enum machine_mode output_memory_reference_mode; /* Nonzero if the prologue must setup `fp'. */ int current_function_anonymous_args; @@ -115,24 +118,6 @@ use_return_insn () return 1; } -/* Return the number of mov instructions needed to get the constant VALUE into - a register. */ - -int -arm_const_nmoves (value) - register int value; -{ - register int i; - - if (value == 0) - return (1); - for (i = 0; value; i++, value &= ~0xff) - while ((value & 3) == 0) - value = (value >> 2) | ((value & 3) << 30); - return (i); -} /* arm_const_nmoves */ - - /* Return TRUE if int I is a valid immediate ARM constant. */ int @@ -144,14 +129,14 @@ const_ok_for_arm (i) do { if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0) - return(TRUE); + return TRUE; mask = (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff) >> (32 - 2)) | ~((unsigned HOST_WIDE_INT) 0xffffffff); } while (mask != ~0xFF); - return (FALSE); -} /* const_ok_for_arm */ + return FALSE; +} /* This code has been fixed for cross compilation. */ @@ -181,6 +166,7 @@ init_fpa_table () r = REAL_VALUE_ATOF (strings_fpa[i], DFmode); values_fpa[i] = r; } + fpa_consts_inited = 1; } @@ -199,11 +185,13 @@ const_double_rtx_ok_for_fpu (x) REAL_VALUE_FROM_CONST_DOUBLE (r, x); if (REAL_VALUE_MINUS_ZERO (r)) return 0; + for (i = 0; i < 8; i++) if (REAL_VALUES_EQUAL (r, values_fpa[i])) return 1; + return 0; -} /* const_double_rtx_ok_for_fpu */ +} /* Return TRUE if rtx X is a valid immediate FPU constant. */ @@ -221,11 +209,13 @@ neg_const_double_rtx_ok_for_fpu (x) r = REAL_VALUE_NEGATE (r); if (REAL_VALUE_MINUS_ZERO (r)) return 0; + for (i = 0; i < 8; i++) if (REAL_VALUES_EQUAL (r, values_fpa[i])) return 1; + return 0; -} /* neg_const_double_rtx_ok_for_fpu */ +} /* Predicates for `match_operand' and `match_operator'. */ @@ -241,9 +231,7 @@ s_register_operand (op, mode) return 0; if (GET_CODE (op) == SUBREG) - { - op = SUBREG_REG (op); - } + op = SUBREG_REG (op); /* We don't consider registers whose class is NO_REGS to be a register operand. */ @@ -276,7 +264,7 @@ arm_rhs_operand (op, mode) { return (s_register_operand (op, mode) || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))); -} /* arm_rhs_operand */ +} /* Return TRUE for valid operands for the rhs of an ARM instruction, or a load. */ @@ -289,7 +277,7 @@ arm_rhsm_operand (op, mode) return (s_register_operand (op, mode) || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))) || memory_operand (op, mode)); -} /* arm_rhs_operand */ +} /* Return TRUE for valid operands for the rhs of an ARM instruction, or if a constant that is valid when negated. */ @@ -303,7 +291,7 @@ arm_add_operand (op, mode) || (GET_CODE (op) == CONST_INT && (const_ok_for_arm (INTVAL (op)) || const_ok_for_arm (-INTVAL (op))))); -} /* arm_rhs_operand */ +} int arm_not_operand (op, mode) @@ -314,7 +302,7 @@ arm_not_operand (op, mode) || (GET_CODE (op) == CONST_INT && (const_ok_for_arm (INTVAL (op)) || const_ok_for_arm (~INTVAL (op))))); -} /* arm_rhs_operand */ +} /* Return TRUE for valid operands for the rhs of an FPU instruction. */ @@ -324,11 +312,12 @@ fpu_rhs_operand (op, mode) enum machine_mode mode; { if (s_register_operand (op, mode)) - return(TRUE); + return TRUE; else if (GET_CODE (op) == CONST_DOUBLE) return (const_double_rtx_ok_for_fpu (op)); - else return (FALSE); -} /* fpu_rhs_operand */ + + return FALSE; +} int fpu_add_operand (op, mode) @@ -336,11 +325,12 @@ fpu_add_operand (op, mode) enum machine_mode mode; { if (s_register_operand (op, mode)) - return(TRUE); + return TRUE; else if (GET_CODE (op) == CONST_DOUBLE) - return const_double_rtx_ok_for_fpu (op) - || neg_const_double_rtx_ok_for_fpu (op); - return (FALSE); + return (const_double_rtx_ok_for_fpu (op) + || neg_const_double_rtx_ok_for_fpu (op)); + + return FALSE; } /* Return nonzero if OP is a constant power of two. */ @@ -352,11 +342,11 @@ power_of_two_operand (op, mode) { if (GET_CODE (op) == CONST_INT) { - int value = INTVAL(op); - return (value != 0 && (value & (value-1)) == 0); + HOST_WIDE_INT value = INTVAL(op); + return value != 0 && (value & (value - 1)) == 0; } - return (FALSE); -} /* power_of_two_operand */ + return FALSE; +} /* Return TRUE for a valid operand of a DImode operation. Either: REG, CONST_DOUBLE or MEM(DImode_address). @@ -369,19 +359,21 @@ di_operand (op, mode) enum machine_mode mode; { if (s_register_operand (op, mode)) - return (TRUE); + return TRUE; switch (GET_CODE (op)) { case CONST_DOUBLE: case CONST_INT: - return (TRUE); + return TRUE; + case MEM: - return (memory_address_p (DImode, XEXP (op, 0))); + return memory_address_p (DImode, XEXP (op, 0)); + default: - return (FALSE); + return FALSE; } -} /* di_operand */ +} /* Return TRUE for valid index operands. */ @@ -393,7 +385,7 @@ index_operand (op, mode) return (s_register_operand(op, mode) || (immediate_operand (op, mode) && INTVAL (op) < 4096 && INTVAL (op) > -4096)); -} /* index_operand */ +} /* Return TRUE for valid shifts by a constant. This also accepts any power of two on the (somewhat overly relaxed) assumption that the @@ -407,7 +399,7 @@ const_shift_operand (op, mode) return (power_of_two_operand (op, mode) || (immediate_operand (op, mode) && (INTVAL (op) < 32 && INTVAL (op) > 0))); -} /* const_shift_operand */ +} /* Return TRUE for arithmetic operators which can be combined with a multiply (shift). */ @@ -426,7 +418,7 @@ shiftable_operator (x, mode) return (code == PLUS || code == MINUS || code == IOR || code == XOR || code == AND); } -} /* shiftable_operator */ +} /* Return TRUE for shift operators. */ @@ -443,15 +435,16 @@ shift_operator (x, mode) if (code == MULT) return power_of_two_operand (XEXP (x, 1)); + return (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT); } -} /* shift_operator */ +} int equality_operator (x, mode) -rtx x; -enum machine_mode mode; + rtx x; + enum machine_mode mode; { - return (GET_CODE (x) == EQ || GET_CODE (x) == NE); + return GET_CODE (x) == EQ || GET_CODE (x) == NE; } /* Return TRUE for SMIN SMAX UMIN UMAX operators. */ @@ -465,8 +458,9 @@ minmax_operator (x, mode) if (GET_MODE (x) != mode) return FALSE; + return code == SMIN || code == SMAX || code == UMIN || code == UMAX; -} /* minmax_operator */ +} /* return TRUE if x is EQ or NE */ @@ -475,8 +469,8 @@ minmax_operator (x, mode) int cc_register (x, mode) -rtx x; -enum machine_mode mode; + rtx x; + enum machine_mode mode; { if (mode == VOIDmode) { @@ -484,30 +478,34 @@ enum machine_mode mode; if (GET_MODE_CLASS (mode) != MODE_CC) return FALSE; } + if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24) return TRUE; + return FALSE; } enum rtx_code minmax_code (x) -rtx x; + rtx x; { enum rtx_code code = GET_CODE (x); if (code == SMAX) return GE; - if (code == SMIN) + else if (code == SMIN) return LE; - if (code == UMIN) + else if (code == UMIN) return LEU; - if (code == UMAX) + else if (code == UMAX) return GEU; + abort (); } /* Return 1 if memory locations are adjacent */ +int adjacent_mem_locations (a, b) rtx a, b; { @@ -543,14 +541,15 @@ adjacent_mem_locations (a, b) /* Return 1 if OP is a load multiple operation. It is known to be parallel and the first section will be tested. */ +int load_multiple_operation (op, mode) rtx op; enum machine_mode mode; { - int count = XVECLEN (op, 0); + HOST_WIDE_INT count = XVECLEN (op, 0); int dest_regno; rtx src_addr; - int i = 1, base = 0; + HOST_WIDE_INT i = 1, base = 0; rtx elt; if (count <= 1 @@ -574,6 +573,7 @@ load_multiple_operation (op, mode) || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0)) != REGNO (SET_DEST (elt))) return 0; + count--; } @@ -610,14 +610,15 @@ load_multiple_operation (op, mode) /* Return 1 if OP is a store multiple operation. It is known to be parallel and the first section will be tested. */ +int store_multiple_operation (op, mode) rtx op; enum machine_mode mode; { - int count = XVECLEN (op, 0); + HOST_WIDE_INT count = XVECLEN (op, 0); int src_regno; rtx dest_addr; - int i = 1, base = 0; + HOST_WIDE_INT i = 1, base = 0; rtx elt; if (count <= 1 @@ -641,6 +642,7 @@ store_multiple_operation (op, mode) || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0)) != REGNO (SET_DEST (elt))) return 0; + count--; } @@ -674,9 +676,19 @@ store_multiple_operation (op, mode) return 1; } +/* Routines for use with attributes */ + +int +const_pool_offset (symbol) + rtx (symbol); +{ + return get_pool_offset (symbol) - get_pool_size () - get_prologue_size (); +} + /* Routines for use in generating RTL */ -rtx arm_gen_load_multiple (base_regno, count, from, up, write_back) +rtx +arm_gen_load_multiple (base_regno, count, from, up, write_back) int base_regno; int count; rtx from; @@ -690,27 +702,30 @@ rtx arm_gen_load_multiple (base_regno, count, from, up, write_back) result = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (count + (write_back ? 2 : 0))); if (write_back) - { + { XVECEXP (result, 0, 0) - = gen_rtx (SET, GET_MODE (from), from, - plus_constant (from, count * 4 * sign)); + = gen_rtx (SET, GET_MODE (from), from, + plus_constant (from, count * 4 * sign)); i = 1; count++; - } + } + for (j = 0; i < count; i++, j++) - { + { XVECEXP (result, 0, i) - = gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, base_regno + j), - gen_rtx (MEM, SImode, - plus_constant (from, j * 4 * sign))); - } + = gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, base_regno + j), + gen_rtx (MEM, SImode, + plus_constant (from, j * 4 * sign))); + } + if (write_back) XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, from); return result; } -rtx arm_gen_store_multiple (base_regno, count, to, up, write_back) +rtx +arm_gen_store_multiple (base_regno, count, to, up, write_back) int base_regno; int count; rtx to; @@ -724,20 +739,22 @@ rtx arm_gen_store_multiple (base_regno, count, to, up, write_back) result = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (count + (write_back ? 2 : 0))); if (write_back) - { + { XVECEXP (result, 0, 0) - = gen_rtx (SET, GET_MODE (to), to, - plus_constant (to, count * 4 * sign)); + = gen_rtx (SET, GET_MODE (to), to, + plus_constant (to, count * 4 * sign)); i = 1; count++; - } + } + for (j = 0; i < count; i++, j++) - { + { XVECEXP (result, 0, i) - = gen_rtx (SET, VOIDmode, - gen_rtx (MEM, SImode, plus_constant (to, j * 4 * sign)), - gen_rtx (REG, SImode, base_regno + j)); - } + = gen_rtx (SET, VOIDmode, + gen_rtx (MEM, SImode, plus_constant (to, j * 4 * sign)), + gen_rtx (REG, SImode, base_regno + j)); + } + if (write_back) XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, to); @@ -762,8 +779,9 @@ gen_compare_reg (code, x, y, fp) return cc_reg; } +void arm_reload_out_hi (operands) -rtx operands[]; + rtx *operands; { rtx base = find_replacement (&XEXP (operands[0], 0)); @@ -785,16 +803,16 @@ rtx operands[]; int arm_backwards_branch (from, to) -int from, to; + int from, to; { - return (insn_addresses[to] <= insn_addresses[from]); + return insn_addresses[to] <= insn_addresses[from]; } /* Check to see if a branch is within the distance that can be done using an arithmetic expression. */ int short_branch (from, to) -int from, to; + int from, to; { int delta = insn_addresses[from] + 8 - insn_addresses[to]; @@ -805,7 +823,7 @@ int from, to; code */ int arm_insn_not_targeted (insn) -rtx insn; + rtx insn; { return insn != arm_target_insn; } @@ -813,13 +831,12 @@ rtx insn; /* Routines to output assembly language. */ -/* fp_immediate_constant - if the rtx is the correct value then return the string of the number. +/* If the rtx is the correct value then return the string of the number. In this way we can ensure that valid double constants are generated even when cross compiling. */ char * fp_immediate_constant (x) -rtx (x); + rtx (x); { REAL_VALUE_TYPE r; int i; @@ -831,6 +848,7 @@ rtx (x); for (i = 0; i < 8; i++) if (REAL_VALUES_EQUAL (r, values_fpa[i])) return strings_fpa[i]; + abort (); } @@ -858,30 +876,31 @@ print_multi_reg (stream, instr, mask, hat) fprintf (stream, "%s", reg_names[i]); not_first = TRUE; } + fprintf (stream, "}%s\n", hat ? "^" : ""); -} /* print_multi_reg */ +} /* Output a 'call' insn. */ char * output_call (operands) - rtx operands[]; + rtx *operands; { /* Handle calls to lr using ip (which may be clobbered in subr anyway). */ if (REGNO (operands[0]) == 14) { operands[0] = gen_rtx (REG, SImode, 12); - arm_output_asm_insn ("mov\t%0, lr", operands); + output_asm_insn ("mov\t%0, lr", operands); } - arm_output_asm_insn ("mov\tlr, pc", operands); - arm_output_asm_insn ("mov\tpc, %0", operands); - return (""); -} /* output_call */ + output_asm_insn ("mov\tlr, pc", operands); + output_asm_insn ("mov\tpc, %0", operands); + return ""; +} static int eliminate_lr2ip (x) -rtx *x; + rtx *x; { int something_changed = 0; rtx x0 = *x; @@ -915,17 +934,18 @@ rtx *x; char * output_call_mem (operands) - rtx operands[]; + rtx *operands; { operands[0] = copy_rtx (operands[0]); /* Be ultra careful */ /* Handle calls using lr by using ip (which may be clobbered in subr anyway). */ if (eliminate_lr2ip (&operands[0])) - arm_output_asm_insn ("mov\tip, lr", operands); - arm_output_asm_insn ("mov\tlr, pc", operands); - arm_output_asm_insn ("ldr\tpc, %0", operands); - return (""); -} /* output_call */ + output_asm_insn ("mov\tip, lr", operands); + + output_asm_insn ("mov\tlr, pc", operands); + output_asm_insn ("ldr\tpc, %0", operands); + return ""; +} /* Output a move from arm registers to an fpu registers. @@ -934,21 +954,22 @@ output_call_mem (operands) char * output_mov_long_double_fpu_from_arm (operands) - rtx operands[]; + rtx *operands; { int arm_reg0 = REGNO (operands[1]); rtx ops[3]; if (arm_reg0 == 12) abort(); + ops[0] = gen_rtx (REG, SImode, arm_reg0); ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0); - arm_output_asm_insn ("stmfd\tsp!, {%0, %1, %2}", ops); - arm_output_asm_insn ("ldfe\t%0, [sp], #12", operands); - return (""); -} /* output_mov_long_double_fpu_from_arm */ + output_asm_insn ("stmfd\tsp!, {%0, %1, %2}", ops); + output_asm_insn ("ldfe\t%0, [sp], #12", operands); + return ""; +} /* Output a move from an fpu register to arm registers. OPERANDS[0] is the first registers of an arm register pair. @@ -956,28 +977,29 @@ output_mov_long_double_fpu_from_arm (operands) char * output_mov_long_double_arm_from_fpu (operands) - rtx operands[]; + rtx *operands; { int arm_reg0 = REGNO (operands[0]); rtx ops[3]; if (arm_reg0 == 12) abort(); + ops[0] = gen_rtx (REG, SImode, arm_reg0); ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0); - arm_output_asm_insn ("stfe\t%1, [sp, #-12]!", operands); - arm_output_asm_insn ("ldmfd\tsp!, {%0, %1, %2}", ops); - return(""); -} /* output_mov_long_double_arm_from_fpu */ + output_asm_insn ("stfe\t%1, [sp, #-12]!", operands); + output_asm_insn ("ldmfd\tsp!, {%0, %1, %2}", ops); + return ""; +} /* Output a move from arm registers to arm registers of a long double OPERANDS[0] is the destination. OPERANDS[1] is the source. */ char * output_mov_long_double_arm_from_arm (operands) -rtx operands[]; + rtx *operands; { /* We have to be careful here because the two might overlap */ int dest_start = REGNO (operands[0]); @@ -991,7 +1013,7 @@ rtx operands[]; { ops[0] = gen_rtx (REG, SImode, dest_start + i); ops[1] = gen_rtx (REG, SImode, src_start + i); - arm_output_asm_insn ("mov\t%0, %1", ops); + output_asm_insn ("mov\t%0, %1", ops); } } else @@ -1000,9 +1022,10 @@ rtx operands[]; { ops[0] = gen_rtx (REG, SImode, dest_start + i); ops[1] = gen_rtx (REG, SImode, src_start + i); - arm_output_asm_insn ("mov\t%0, %1", ops); + output_asm_insn ("mov\t%0, %1", ops); } } + return ""; } @@ -1013,7 +1036,7 @@ rtx operands[]; char * output_mov_double_fpu_from_arm (operands) - rtx operands[]; + rtx *operands; { int arm_reg0 = REGNO (operands[1]); rtx ops[2]; @@ -1022,10 +1045,10 @@ output_mov_double_fpu_from_arm (operands) abort(); ops[0] = gen_rtx (REG, SImode, arm_reg0); ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); - arm_output_asm_insn ("stmfd\tsp!, {%0, %1}", ops); - arm_output_asm_insn ("ldfd\t%0, [sp], #8", operands); - return (""); -} /* output_mov_double_fpu_from_arm */ + output_asm_insn ("stmfd\tsp!, {%0, %1}", ops); + output_asm_insn ("ldfd\t%0, [sp], #8", operands); + return ""; +} /* Output a move from an fpu register to arm registers. OPERANDS[0] is the first registers of an arm register pair. @@ -1033,19 +1056,20 @@ output_mov_double_fpu_from_arm (operands) char * output_mov_double_arm_from_fpu (operands) - rtx operands[]; + rtx *operands; { int arm_reg0 = REGNO (operands[0]); rtx ops[2]; if (arm_reg0 == 12) abort(); + ops[0] = gen_rtx (REG, SImode, arm_reg0); ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); - arm_output_asm_insn ("stfd\t%1, [sp, #-8]!", operands); - arm_output_asm_insn ("ldmfd\tsp!, {%0, %1}", ops); - return(""); -} /* output_mov_double_arm_from_fpu */ + output_asm_insn ("stfd\t%1, [sp, #-8]!", operands); + output_asm_insn ("ldmfd\tsp!, {%0, %1}", ops); + return ""; +} /* Output a move between double words. It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM @@ -1053,7 +1077,7 @@ output_mov_double_arm_from_fpu (operands) char * output_move_double (operands) - rtx operands[]; + rtx *operands; { enum rtx_code code0 = GET_CODE (operands[0]); enum rtx_code code1 = GET_CODE (operands[1]); @@ -1069,18 +1093,19 @@ output_move_double (operands) int reg1 = REGNO (operands[1]); if (reg1 == 12) abort(); + otherops[1] = gen_rtx (REG, SImode, 1 + reg1); /* Ensure the second source is not overwritten */ if (reg0 == 1 + reg1) { - arm_output_asm_insn("mov\t%0, %1", otherops); - arm_output_asm_insn("mov\t%0, %1", operands); + output_asm_insn("mov\t%0, %1", otherops); + output_asm_insn("mov\t%0, %1", operands); } else { - arm_output_asm_insn("mov\t%0, %1", operands); - arm_output_asm_insn("mov\t%0, %1", otherops); + output_asm_insn("mov\t%0, %1", operands); + output_asm_insn("mov\t%0, %1", otherops); } } else if (code1 == CONST_DOUBLE) @@ -1099,9 +1124,9 @@ output_move_double (operands) /* Note: output_mov_immediate may clobber operands[1], so we put this out first */ if (INTVAL (operands[1]) < 0) - arm_output_asm_insn ("mvn\t%0, %1", otherops); + output_asm_insn ("mvn\t%0, %1", otherops); else - arm_output_asm_insn ("mov\t%0, %1", otherops); + output_asm_insn ("mov\t%0, %1", otherops); output_mov_immediate (operands, FALSE, ""); } else if (code1 == MEM) @@ -1112,39 +1137,39 @@ output_move_double (operands) /* Handle the simple case where address is [r, #0] more efficient. */ operands[1] = XEXP (operands[1], 0); - arm_output_asm_insn ("ldmia\t%1, %M0", operands); + output_asm_insn ("ldmia\t%1, %M0", operands); break; case PRE_INC: operands[1] = XEXP (XEXP (operands[1], 0), 0); - arm_output_asm_insn ("add\t%1, %1, #8", operands); - arm_output_asm_insn ("ldmia\t%1, %M0", operands); + output_asm_insn ("add\t%1, %1, #8", operands); + output_asm_insn ("ldmia\t%1, %M0", operands); break; case PRE_DEC: operands[1] = XEXP (XEXP (operands[1], 0), 0); - arm_output_asm_insn ("sub\t%1, %1, #8", operands); - arm_output_asm_insn ("ldmia\t%1, %M0", operands); + output_asm_insn ("sub\t%1, %1, #8", operands); + output_asm_insn ("ldmia\t%1, %M0", operands); break; case POST_INC: operands[1] = XEXP (XEXP (operands[1], 0), 0); - arm_output_asm_insn ("ldmia\t%1!, %M0", operands); + output_asm_insn ("ldmia\t%1!, %M0", operands); break; case POST_DEC: operands[1] = XEXP (XEXP (operands[1], 0), 0); - arm_output_asm_insn ("ldmia\t%1, %M0", operands); - arm_output_asm_insn ("sub\t%1, %1, #8", operands); + output_asm_insn ("ldmia\t%1, %M0", operands); + output_asm_insn ("sub\t%1, %1, #8", operands); break; default: otherops[1] = adj_offsettable_operand (operands[1], 4); /* Take care of overlapping base/data reg. */ if (reg_mentioned_p (operands[0], operands[1])) { - arm_output_asm_insn ("ldr\t%0, %1", otherops); - arm_output_asm_insn ("ldr\t%0, %1", operands); + output_asm_insn ("ldr\t%0, %1", otherops); + output_asm_insn ("ldr\t%0, %1", operands); } else { - arm_output_asm_insn ("ldr\t%0, %1", operands); - arm_output_asm_insn ("ldr\t%0, %1", otherops); + output_asm_insn ("ldr\t%0, %1", operands); + output_asm_insn ("ldr\t%0, %1", otherops); } } } @@ -1158,32 +1183,32 @@ output_move_double (operands) { case REG: operands[0] = XEXP (operands[0], 0); - arm_output_asm_insn ("stmia\t%0, %M1", operands); + output_asm_insn ("stmia\t%0, %M1", operands); break; case PRE_INC: operands[0] = XEXP (XEXP (operands[0], 0), 0); - arm_output_asm_insn ("add\t%0, %0, #8", operands); - arm_output_asm_insn ("stmia\t%0, %M1", operands); + output_asm_insn ("add\t%0, %0, #8", operands); + output_asm_insn ("stmia\t%0, %M1", operands); break; case PRE_DEC: operands[0] = XEXP (XEXP (operands[0], 0), 0); - arm_output_asm_insn ("sub\t%0, %0, #8", operands); - arm_output_asm_insn ("stmia\t%0, %M1", operands); + output_asm_insn ("sub\t%0, %0, #8", operands); + output_asm_insn ("stmia\t%0, %M1", operands); break; case POST_INC: operands[0] = XEXP (XEXP (operands[0], 0), 0); - arm_output_asm_insn ("stmia\t%0!, %M1", operands); + output_asm_insn ("stmia\t%0!, %M1", operands); break; case POST_DEC: operands[0] = XEXP (XEXP (operands[0], 0), 0); - arm_output_asm_insn ("stmia\t%0, %M1", operands); - arm_output_asm_insn ("sub\t%0, %0, #8", operands); + output_asm_insn ("stmia\t%0, %M1", operands); + output_asm_insn ("sub\t%0, %0, #8", operands); break; default: otherops[0] = adj_offsettable_operand (operands[0], 4); otherops[1] = gen_rtx (REG, SImode, 1 + REGNO (operands[1])); - arm_output_asm_insn ("str\t%1, %0", operands); - arm_output_asm_insn ("str\t%1, %0", otherops); + output_asm_insn ("str\t%1, %0", operands); + output_asm_insn ("str\t%1, %0", otherops); } } else abort(); /* Constraints should prevent this */ @@ -1197,23 +1222,25 @@ output_move_double (operands) char * output_mov_immediate (operands) - rtx operands[2]; + rtx *operands; { - int n = INTVAL (operands[1]); + HOST_WIDE_INT n = INTVAL (operands[1]); int n_ones = 0; int i; /* Try to use one MOV */ - if (const_ok_for_arm (n)) - return (arm_output_asm_insn ("mov\t%0, %1", operands)); + { + output_asm_insn ("mov\t%0, %1", operands); + return ""; + } /* Try to use one MVN */ - - if (const_ok_for_arm(~n)) + if (const_ok_for_arm (~n)) { - operands[1] = gen_rtx (CONST_INT, VOIDmode, ~n); - return (arm_output_asm_insn ("mvn\t%0, %1", operands)); + operands[1] = GEN_INT (~n); + output_asm_insn ("mvn\t%0, %1", operands); + return ""; } /* If all else fails, make it out of ORRs or BICs as appropriate. */ @@ -1226,8 +1253,9 @@ output_mov_immediate (operands) output_multi_immediate(operands, "mvn\t%0, %1", "bic\t%0, %0, %1", 1, ~n); else output_multi_immediate(operands, "mov\t%0, %1", "orr\t%0, %0, %1", 1, n); - return(""); -} /* output_mov_immediate */ + + return ""; +} /* Output an ADD r, s, #n where n may be too big for one instruction. If @@ -1235,9 +1263,9 @@ output_mov_immediate (operands) char * output_add_immediate (operands) - rtx operands[3]; + rtx *operands; { - int n = INTVAL (operands[2]); + HOST_WIDE_INT n = INTVAL (operands[2]); if (n != 0 || REGNO (operands[0]) != REGNO (operands[1])) { @@ -1248,8 +1276,9 @@ output_add_immediate (operands) output_multi_immediate (operands, "add\t%0, %1, %2", "add\t%0, %0, %2", 2, n); } - return(""); -} /* output_add_immediate */ + + return ""; +} /* Output a multiple immediate operation. @@ -1261,14 +1290,19 @@ output_add_immediate (operands) char * output_multi_immediate (operands, instr1, instr2, immed_op, n) - rtx operands[]; + rtx *operands; char *instr1, *instr2; - int immed_op, n; + int immed_op; + HOST_WIDE_INT n; { +#if HOST_BITS_PER_WIDE_INT > 32 + n &= 0xffffffff; +#endif + if (n == 0) { operands[immed_op] = const0_rtx; - arm_output_asm_insn (instr1, operands); /* Quick and easy output */ + output_asm_insn (instr1, operands); /* Quick and easy output */ } else { @@ -1276,20 +1310,18 @@ output_multi_immediate (operands, instr1, instr2, immed_op, n) char *instr = instr1; /* Note that n is never zero here (which would give no output) */ - for (i = 0; i < 32; i += 2) { if (n & (3 << i)) { - operands[immed_op] = gen_rtx (CONST_INT, VOIDmode, - n & (255 << i)); - arm_output_asm_insn (instr, operands); + operands[immed_op] = GEN_INT (n & (255 << i)); + output_asm_insn (instr, operands); instr = instr2; i += 6; } } } - return (""); + return ""; } /* output_multi_immediate */ @@ -1301,27 +1333,29 @@ output_multi_immediate (operands, instr1, instr2, immed_op, n) char * arithmetic_instr (op, shift_first_arg) rtx op; + int shift_first_arg; { switch (GET_CODE(op)) { case PLUS: - return ("add"); + return "add"; + case MINUS: - if (shift_first_arg) - return ("rsb"); - else - return ("sub"); + return shift_first_arg ? "rsb" : "sub"; + case IOR: - return ("orr"); + return "orr"; + case XOR: - return ("eor"); + return "eor"; + case AND: - return ("and"); + return "and"; + default: - abort(); + abort (); } - return (""); /* stupid cc */ -} /* arithmetic_instr */ +} /* Ensure valid constant shifts and return the appropriate shift mnemonic @@ -1343,20 +1377,23 @@ shift_instr (op, shift_ptr) case ASHIFT: mnem = "asl"; break; + case ASHIFTRT: mnem = "asr"; max_shift = 32; break; + case LSHIFTRT: mnem = "lsr"; max_shift = 32; break; + case MULT: - *shift_ptr = gen_rtx (CONST_INT, VOIDmode, - int_log2 (INTVAL (*shift_ptr))); - return ("asl"); + *shift_ptr = GEN_INT (int_log2 (INTVAL (*shift_ptr))); + return "asl"; + default: - abort(); + abort (); } if (GET_CODE (*shift_ptr) == CONST_INT) @@ -1374,20 +1411,21 @@ shift_instr (op, shift_ptr) /* Obtain the shift from the POWER of two. */ -int +HOST_WIDE_INT int_log2 (power) - unsigned int power; + HOST_WIDE_INT power; { - int shift = 0; + HOST_WIDE_INT shift = 0; while (((1 << shift) & power) == 0) { if (shift > 31) - abort(); + abort (); shift++; } - return (shift); -} /* int_log2 */ + + return shift; +} /* Output an arithmetic instruction which may set the condition code. @@ -1400,7 +1438,7 @@ int_log2 (power) char * output_arithmetic (operands, const_first_arg, set_cond) - rtx operands[4]; + rtx *operands; int const_first_arg; int set_cond; { @@ -1408,8 +1446,9 @@ output_arithmetic (operands, const_first_arg, set_cond) char *instr = arithmetic_instr (operands[1], const_first_arg); sprintf (mnemonic, "%s%s\t%%0, %%2, %%3", instr, set_cond ? "s" : ""); - return (arm_output_asm_insn (mnemonic, operands)); -} /* output_arithmetic */ + output_asm_insn (mnemonic, operands); + return ""; +} /* Output an arithmetic instruction with a shift. @@ -1424,7 +1463,7 @@ output_arithmetic (operands, const_first_arg, set_cond) char * output_arithmetic_with_shift (operands, shift_first_arg, set_cond) - rtx operands[6]; + rtx *operands; int shift_first_arg; int set_cond; { @@ -1434,9 +1473,9 @@ output_arithmetic_with_shift (operands, shift_first_arg, set_cond) char *shift = shift_instr (GET_CODE (operands[3]), &operands[5]); sprintf (mnemonic, "%s%s\t%%0, %%2, %%4, %s %%5", instr, condbit, shift); - return (arm_output_asm_insn (mnemonic, operands)); -} /* output_arithmetic_with_shift */ - + output_asm_insn (mnemonic, operands); + return ""; +} /* Output an arithmetic instruction with a power of two multiplication. OPERANDS[0] is the destination register. @@ -1448,16 +1487,17 @@ output_arithmetic_with_shift (operands, shift_first_arg, set_cond) char * output_arithmetic_with_immediate_multiply (operands, shift_first_arg) - rtx operands[5]; + rtx *operands; int shift_first_arg; { char mnemonic[80]; char *instr = arithmetic_instr (operands[1], shift_first_arg); - int shift = int_log2 (INTVAL (operands[4])); + HOST_WIDE_INT shift = int_log2 (INTVAL (operands[4])); - sprintf (mnemonic, "%s\t%%0, %%2, %%3, asl#%d", instr, shift); - return (arm_output_asm_insn (mnemonic, operands)); -} /* output_arithmetic_with_immediate_multiply */ + sprintf (mnemonic, "%s\t%%0, %%2, %%3, asl#%d", instr, (int) shift); + output_asm_insn (mnemonic, operands); + return ""; +} /* Output a move with a shift. @@ -1469,7 +1509,7 @@ output_arithmetic_with_immediate_multiply (operands, shift_first_arg) char * output_shifted_move (op, operands) enum rtx_code op; - rtx operands[2]; + rtx *operands; { char mnemonic[80]; @@ -1478,13 +1518,15 @@ output_shifted_move (op, operands) else sprintf (mnemonic, "mov\t%%0, %%1, %s %%2", shift_instr (op, &operands[2])); - return (arm_output_asm_insn (mnemonic, operands)); -} /* output_shifted_move */ + + output_asm_insn (mnemonic, operands); + return ""; +} char * output_shift_compare (operands, neg) -rtx *operands; -int neg; + rtx *operands; + int neg; { char buf[80]; @@ -1494,8 +1536,9 @@ int neg; else sprintf (buf, "cmp\t%%1, %%3, %s %%4", shift_instr (GET_CODE (operands[2]), &operands[4])); - return arm_output_asm_insn (buf, operands); -} /* output_shift_compare */ + output_asm_insn (buf, operands); + return ""; +} /* Output a .ascii pseudo-op, keeping track of lengths. This is because /bin/as is horribly restrictive. */ @@ -1529,6 +1572,7 @@ output_ascii_pseudo_op (stream, p, len) putc('\\', stream); len_so_far++; } + if (c >= ' ' && c < 0177) { putc (c, stream); @@ -1539,11 +1583,13 @@ output_ascii_pseudo_op (stream, p, len) fprintf (stream, "\\%03o", c); len_so_far +=4; } + chars_so_far++; } + fputs ("\"\n", stream); arm_increase_location (chars_so_far); -} /* output_ascii_pseudo_op */ +} /* Try to determine whether a pattern really clobbers the link register. @@ -1556,7 +1602,7 @@ output_ascii_pseudo_op (stream, p, len) static int pattern_really_clobbers_lr (x) -rtx x; + rtx x; { int i; @@ -1567,34 +1613,43 @@ rtx x; { case REG: return REGNO (SET_DEST (x)) == 14; + case SUBREG: if (GET_CODE (XEXP (SET_DEST (x), 0)) == REG) return REGNO (XEXP (SET_DEST (x), 0)) == 14; + if (GET_CODE (XEXP (SET_DEST (x), 0)) == MEM) return 0; abort (); + default: return 0; } + case PARALLEL: for (i = 0; i < XVECLEN (x, 0); i++) if (pattern_really_clobbers_lr (XVECEXP (x, 0, i))) return 1; return 0; + case CLOBBER: switch (GET_CODE (XEXP (x, 0))) { case REG: return REGNO (XEXP (x, 0)) == 14; + case SUBREG: if (GET_CODE (XEXP (XEXP (x, 0), 0)) == REG) return REGNO (XEXP (XEXP (x, 0), 0)) == 14; abort (); + default: return 0; } + case UNSPEC: return 1; + default: return 0; } @@ -1602,7 +1657,7 @@ rtx x; static int function_really_clobbers_lr (first) -rtx first; + rtx first; { rtx insn, next; @@ -1616,15 +1671,18 @@ rtx first; case JUMP_INSN: /* Jump insns only change the PC (and conds) */ case INLINE_HEADER: break; + case INSN: if (pattern_really_clobbers_lr (PATTERN (insn))) return 1; break; + case CALL_INSN: /* Don't yet know how to handle those calls that are not to a SYMBOL_REF */ if (GET_CODE (PATTERN (insn)) != PARALLEL) abort (); + switch (GET_CODE (XVECEXP (PATTERN (insn), 0, 0))) { case CALL: @@ -1632,15 +1690,18 @@ rtx first; != SYMBOL_REF) return 1; break; + case SET: if (GET_CODE (XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (insn), 0, 0)), 0), 0)) != SYMBOL_REF) return 1; break; + default: /* Don't recognize it, be safe */ return 1; } + /* A call can be made (by peepholing) not to clobber lr iff it is followed by a return. There may, however, be a use insn iff we are returning the result of the call. @@ -1650,40 +1711,44 @@ rtx first; must reject this. (Can this be fixed by adding our own insn?) */ if ((next = next_nonnote_insn (insn)) == NULL) return 1; + if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == USE && (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) && (REGNO (SET_DEST (XVECEXP (PATTERN (insn), 0, 0))) == REGNO (XEXP (PATTERN (next), 0)))) if ((next = next_nonnote_insn (next)) == NULL) return 1; + if (GET_CODE (next) == JUMP_INSN && GET_CODE (PATTERN (next)) == RETURN) break; return 1; + default: abort (); } } + /* We have reached the end of the chain so lr was _not_ clobbered */ return 0; } char * output_return_instruction (operand, really_return) -rtx operand; -int really_return; + rtx operand; + int really_return; { char instr[100]; int reg, live_regs = 0; - if (current_function_calls_alloca && !really_return) + if (current_function_calls_alloca && ! really_return) abort(); - for (reg = 4; reg < 10; reg++) - if (regs_ever_live[reg]) + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) live_regs++; - if (live_regs || (regs_ever_live[14] && !lr_save_eliminated)) + if (live_regs || (regs_ever_live[14] && ! lr_save_eliminated)) live_regs++; if (frame_pointer_needed) @@ -1691,19 +1756,22 @@ int really_return; if (live_regs) { - if (lr_save_eliminated || !regs_ever_live[14]) + if (lr_save_eliminated || ! regs_ever_live[14]) live_regs++; + if (frame_pointer_needed) strcpy (instr, "ldm%d0ea\tfp, {"); else strcpy (instr, "ldm%d0fd\tsp!, {"); - for (reg = 4; reg < 10; reg++) - if (regs_ever_live[reg]) + + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) { strcat (instr, reg_names[reg]); if (--live_regs) strcat (instr, ", "); } + if (frame_pointer_needed) { strcat (instr, reg_names[11]); @@ -1715,17 +1783,61 @@ int really_return; else strcat (instr, really_return ? reg_names[15] : reg_names[14]); strcat (instr, (TARGET_6 || !really_return) ? "}" : "}^"); - arm_output_asm_insn (instr, &operand); + output_asm_insn (instr, &operand); } else if (really_return) { strcpy (instr, TARGET_6 ? "mov%d0\tpc, lr" : "mov%d0s\tpc, lr"); - arm_output_asm_insn (instr, &operand); + output_asm_insn (instr, &operand); } + return_used_this_function = 1; return ""; } +/* Return the size of the prologue. It's not too bad if we slightly + over-estimate. */ + +static int +get_prologue_size () +{ + int amount = 0; + int regno; + + /* Until we know which registers are really used return the maximum. */ + if (! reload_completed) + return 24; + + /* Look for integer regs that have to be saved. */ + for (regno = 0; regno < 15; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + { + amount = 4; + break; + } + + /* Clobbering lr when none of the other regs have been saved also requires + a save. */ + if (regs_ever_live[14]) + amount = 4; + + /* If we need to push a stack frame then there is an extra instruction to + preserve the current value of the stack pointer. */ + if (frame_pointer_needed) + amount = 8; + + /* Now look for floating-point regs that need saving. We need an + instruction per register. */ + for (regno = 16; regno < 24; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + amount += 4; + + if (current_function_anonymous_args && current_function_pretend_args_size) + amount += 4; + + return amount; +} + /* The amount of stack adjustment that happens here, in output_return and in output_epilogue must be exactly the same as was calculated during reload, or things will point to the wrong place. The only time we can safely @@ -1736,11 +1848,11 @@ int really_return; onto the stack. */ void -output_prologue (f, frame_size) +output_func_prologue (f, frame_size) FILE *f; int frame_size; { - int reg, live_regs_mask = 0, code_size = 0; + int reg, live_regs_mask = 0; rtx operands[3]; /* Nonzero if we must stuff some register arguments onto the stack as if @@ -1762,20 +1874,19 @@ output_prologue (f, frame_size) if (current_function_anonymous_args && current_function_pretend_args_size) store_arg_regs = 1; - for (reg = 4; reg < 10; reg++) - if (regs_ever_live[reg]) + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) live_regs_mask |= (1 << reg); if (frame_pointer_needed) { live_regs_mask |= 0xD800; fputs ("\tmov\tip, sp\n", f); - code_size += 4; } else if (regs_ever_live[14]) { if (! current_function_args_size - && !function_really_clobbers_lr (get_insns ())) + && ! function_really_clobbers_lr (get_insns ())) { fprintf (f,"\t@ I don't think this function clobbers lr\n"); lr_save_eliminated = 1; @@ -1798,7 +1909,6 @@ output_prologue (f, frame_size) arg_size > 0; reg--, arg_size -= 4) mask |= (1 << reg); print_multi_reg (f, "stmfd\tsp!", mask, FALSE); - code_size += 4; } else { @@ -1818,16 +1928,14 @@ output_prologue (f, frame_size) live_regs_mask |= 0x4000; lr_save_eliminated = 0; + + /* Now push all the call-saved regs onto the stack */ print_multi_reg (f, "stmfd\tsp!", live_regs_mask, FALSE); - code_size += 4; } - for (reg = 23; reg > 19; reg--) - if (regs_ever_live[reg]) - { - fprintf (f, "\tstfe\t%s, [sp, #-12]!\n", reg_names[reg]); - code_size += 4; - } + for (reg = 23; reg > 15; reg--) + if (regs_ever_live[reg] && !call_used_regs[reg]) + fprintf (f, "\tstfe\t%s, [sp, #-12]!\n", reg_names[reg]); if (frame_pointer_needed) { @@ -1835,24 +1943,21 @@ output_prologue (f, frame_size) operands[0] = gen_rtx (REG, SImode, HARD_FRAME_POINTER_REGNUM); operands[1] = gen_rtx (REG, SImode, 12); - operands[2] = gen_rtx (CONST_INT, VOIDmode, - - (4 + current_function_pretend_args_size)); + operands[2] = GEN_INT ( - (4 + current_function_pretend_args_size)); output_add_immediate (operands); } if (frame_size) { operands[0] = operands[1] = stack_pointer_rtx; - operands[2] = gen_rtx (CONST_INT, VOIDmode, -frame_size); + operands[2] = GEN_INT (-frame_size); output_add_immediate (operands); } - - arm_increase_location (code_size); -} /* output_prologue */ +} void -output_epilogue (f, frame_size) +output_func_epilogue (f, frame_size) FILE *f; int frame_size; { @@ -1867,21 +1972,20 @@ output_epilogue (f, frame_size) { abort (); } - return; + goto epilogue_done; } - for (reg = 4; reg <= 10; reg++) - if (regs_ever_live[reg]) + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) { live_regs_mask |= (1 << reg); floats_offset += 4; } - if (frame_pointer_needed) { - for (reg = 23; reg >= 20; reg--) - if (regs_ever_live[reg]) + for (reg = 23; reg > 15; reg--) + if (regs_ever_live[reg] && ! call_used_regs[reg]) { fprintf (f, "\tldfe\t%s, [fp, #-%d]\n", reg_names[reg], floats_offset); @@ -1904,8 +2008,8 @@ output_epilogue (f, frame_size) output_add_immediate (operands); } - for (reg = 20; reg < 24; reg++) - if (regs_ever_live[reg]) + for (reg = 16; reg < 24; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) { fprintf (f, "\tldfe\t%s, [sp], #12\n", reg_names[reg]); code_size += 4; @@ -1935,9 +2039,18 @@ output_epilogue (f, frame_size) code_size += 4; } } - arm_increase_location (code_size); + + epilogue_done: + + /* insn_addresses isn't allocated when not optimizing */ + + if (optimize > 0) + arm_increase_location (code_size + + insn_addresses[INSN_UID (get_last_insn ())] + + get_prologue_size ()); + current_function_anonymous_args = 0; -} /* output_epilogue */ +} /* Increase the `arm_text_location' by AMOUNT if we're in the text segment. */ @@ -1948,26 +2061,7 @@ arm_increase_location (amount) { if (in_text_section ()) arm_text_location += amount; -} /* arm_increase_location */ - - -/* Like output_asm_insn (), but also increases the arm_text_location (if in - the .text segment, of course, even though this will always be true). - Returns the empty string. */ - -char * -arm_output_asm_insn (template, operands) - char *template; - rtx *operands; -{ - extern FILE *asm_out_file; - - output_asm_insn (template, operands); - if (in_text_section ()) - arm_text_location += 4; - fflush (asm_out_file); - return (""); -} /* arm_output_asm_insn */ +} /* Output a label definition. If this label is within the .text segment, it @@ -2003,91 +2097,38 @@ arm_asm_output_label (stream, name) } for (s = real_name; *s; s++) hash += *s; + hash = hash % LABEL_HASH_SIZE; cur = (struct label_offset *) xmalloc (sizeof (struct label_offset)); cur->name = real_name; cur->offset = arm_text_location; cur->cdr = offset_table[hash]; offset_table[hash] = cur; -} /* arm_asm_output_label */ - - -/* Output the instructions needed to perform what Martin's /bin/as called - llc: load an SImode thing from the function's constant pool. +} - XXX This could be enhanced in that we do not really need a pointer in the - constant pool pointing to the real thing. If we can address this pointer, - we can also address what it is pointing at, in fact, anything in the text - segment which has been defined already within this .s file. */ +/* Load a symbol that is known to be in the text segment into a register. + This should never be called when not optimizing. */ char * -arm_output_llc (operands) +output_load_symbol (insn, operands) + rtx insn; rtx *operands; { - char *s, *name = XSTR (XEXP (operands[1], 0), 0); - struct label_offset *he; - int hash = 0, conditional = (arm_ccfsm_state == 3 || arm_ccfsm_state == 4); - - if (*name != '*') - abort (); - - for (s = &name[1]; *s; s++) - hash += *s; - hash = hash % LABEL_HASH_SIZE; - he = offset_table[hash]; - while (he && strcmp (he->name, &name[1])) - he = he->cdr; - - if (!he) - abort (); - - if (arm_text_location + 8 - he->offset < 4095) - { - fprintf (asm_out_file, "\tldr%s\t%s, [pc, #%s - . - 8]\n", - conditional ? arm_condition_codes[arm_current_cc] : "", - reg_names[REGNO (operands[0])], &name[1]); - arm_increase_location (4); - return (""); - } - else - { - int offset = - (arm_text_location + 8 - he->offset); - char *reg_name = reg_names[REGNO (operands[0])]; - - /* ??? This is a hack, assuming the constant pool never is more than - (1 + 255) * 4096 == 1Meg away from the PC. */ - - if (offset > 1000000) - abort (); - - fprintf (asm_out_file, "\tsub%s\t%s, pc, #(8 + . - %s) & ~4095\n", - conditional ? arm_condition_codes[arm_current_cc] : "", - reg_name, &name[1]); - fprintf (asm_out_file, "\tldr%s\t%s, [%s, #- ((4 + . - %s) & 4095)]\n", - conditional ? arm_condition_codes[arm_current_cc] : "", - reg_name, reg_name, &name[1]); - arm_increase_location (8); - } - return (""); -} /* arm_output_llc */ - -/* output_load_symbol () - load a symbol that is known to be in the text segment into a register */ - -char * -output_load_symbol (operands) -rtx *operands; -{ - char *s, *name = XSTR (operands[1], 0); + char *s; + char *name = XSTR (operands[1], 0); struct label_offset *he; int hash = 0; int offset; - - if (*name != '*') + unsigned int mask, never_mask = 0xffffffff; + int shift, inst; + char buffer[100]; + + if (optimize == 0 || *name != '*') abort (); for (s = &name[1]; *s; s++) hash += *s; + hash = hash % LABEL_HASH_SIZE; he = offset_table[hash]; while (he && strcmp (he->name, &name[1])) @@ -2096,45 +2137,48 @@ rtx *operands; if (!he) abort (); - offset = (arm_text_location + 8 - he->offset); + offset = (arm_text_location + insn_addresses[INSN_UID (insn)] + + get_prologue_size () + 8 - he->offset); if (offset < 0) abort (); + /* When generating the instructions, we never mask out the bits that we + think will be always zero, then if a mistake has occureed somewhere, the + assembler will spot it and generate an error. */ + /* If the symbol is word aligned then we might be able to reduce the - number of loads */ - if ((offset & 3) == 0) + number of loads. */ + shift = ((offset & 3) == 0) ? 2 : 0; + + /* Clear the bits from NEVER_MASK that will be orred in with the individual + instructions. */ + for (; shift < 32; shift += 8) { - arm_output_asm_insn ("sub\t%0, pc, #(8 + . -%a1) & 1023", operands); - if (offset > 0x3ff) - { - arm_output_asm_insn ("sub\t%0, %0, #(4 + . -%a1) & 261120", - operands); - if (offset > 0x3ffff) - { - arm_output_asm_insn ("sub\t%0, %0, #(. -%a1) & 66846720", - operands); - if (offset > 0x3ffffff) - arm_output_asm_insn ("sub\t%0, %0, #(. - 4 -%a1) & -67108864", - operands); - } - } + mask = 0xff << shift; + if ((offset & mask) || ((unsigned) offset) > mask) + never_mask &= ~mask; } - else + + inst = 8; + mask = 0xff << (shift - 32); + + while (mask && (never_mask & mask) == 0) { - arm_output_asm_insn ("sub\t%0, pc, #(8 + . -%a1) & 255", operands); - if (offset > 0x0ff) - { - arm_output_asm_insn ("sub\t%0, %0, #(4 + . -%a1) & 65280", operands); - if (offset > 0x0ffff) - { - arm_output_asm_insn ("sub\t%0, %0, #(. -%a1) & 16711680", - operands); - if (offset > 0x0ffffff) - arm_output_asm_insn ("sub\t%0, %0, #(. - 4 -%a1) & -16777216", - operands); - } - } + if (inst == 8) + { + strcpy (buffer, "sub\t%0, pc, #(8 + . -%a1)"); + if ((never_mask | mask) != 0xffffffff) + sprintf (buffer + strlen (buffer), " & 0x%x", mask | never_mask); + } + else + sprintf (buffer, "sub\t%%0, %%0, #(%d + . -%%a1) & 0x%x", + inst, mask | never_mask); + + output_asm_insn (buffer, operands); + mask <<= 8; + inst -= 4; } + return ""; } @@ -2158,7 +2202,7 @@ output_lcomm_directive (stream, name, size, rounded) fputs ("\n\t.text\n", stream); else fputs ("\n\t.data\n", stream); -} /* output_lcomm_directive */ +} /* A finite state machine takes care of noticing whether or not instructions can be conditionally executed, and thus decrease execution time and code @@ -2224,7 +2268,7 @@ get_arm_condition_code (comparison) } /*NOTREACHED*/ return (42); -} /* get_arm_condition_code */ +} void @@ -2526,6 +2570,6 @@ final_prescan_insn (insn, opvec, noperands) call recog direct). */ recog (PATTERN (insn), insn, NULL_PTR); } -} /* final_prescan_insn */ +} /* EOF */