aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Earnshaw <erich@gnu.org>1994-06-01 17:09:29 +0000
committerRichard Earnshaw <erich@gnu.org>1994-06-01 17:09:29 +0000
commitf3bb6135f6a5cd960e40c8e2febfa22c6b90347f (patch)
tree5ad810a2dba592bd029710106d8511ed42adc46c /gcc
parenta1dc0475d64bbb2e432a6b145a5902e355430c99 (diff)
downloadgcc-f3bb6135f6a5cd960e40c8e2febfa22c6b90347f.zip
gcc-f3bb6135f6a5cd960e40c8e2febfa22c6b90347f.tar.gz
gcc-f3bb6135f6a5cd960e40c8e2febfa22c6b90347f.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/arm/arm.c820
1 files changed, 432 insertions, 388 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index dae7f98..0e8d7d7 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 <stdio.h>
+#include <string.h>
#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 */