Commit f3bb6135 by Richard Earnshaw

General tidy up.

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