summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorYamaArashi <shadow962@live.com>2016-02-14 14:49:17 -0800
committerYamaArashi <shadow962@live.com>2016-02-14 14:49:17 -0800
commit085546bf61bf974a9fcb5c6d581a2e6bb85c3202 (patch)
treeb4988265c7eae0a445855d5b59354c793b140a59 /gcc
parentd28ac43428269276aca46f62d4822be5b5a5c343 (diff)
clean up thumb.c more
Diffstat (limited to 'gcc')
-rwxr-xr-xgcc/config/arm/thumb.c2569
1 files changed, 1182 insertions, 1387 deletions
diff --git a/gcc/config/arm/thumb.c b/gcc/config/arm/thumb.c
index 0402540..e62237b 100755
--- a/gcc/config/arm/thumb.c
+++ b/gcc/config/arm/thumb.c
@@ -1,24 +1,24 @@
/* Output routines for GCC for ARM/Thumb
Copyright (C) 1996 Cygnus Software Technologies Ltd
The basis of this contribution was generated by
- Richard Earnshaw, Advanced RISC Machines Ltd
+ Richard Earnshaw, Advanced RISC Machines Ltd
-This file is part of GNU CC.
+ This file is part of GNU CC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+ GNU CC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+ GNU CC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+ You should have received a copy of the GNU General Public License
+ along with GNU CC; see the file COPYING. If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
#include <stdio.h>
#include <string.h>
@@ -33,80 +33,72 @@ Boston, MA 02111-1307, USA. */
#include "tree.h"
#include "expr.h"
-
int current_function_anonymous_args = 0;
static int current_function_has_far_jump = 0;
/* Used to parse -mstructure_size_boundary command line option. */
-char * structure_size_string = NULL;
-int arm_structure_size_boundary = 32; /* Used to be 8 */
+char *structure_size_string = NULL;
+int arm_structure_size_boundary = 32; /* Used to be 8 */
-
/* Predicates */
int
-reload_memory_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+reload_memory_operand(rtx op, enum machine_mode mode)
{
- int regno = true_regnum (op);
+ int regno = true_regnum(op);
- return (! CONSTANT_P (op)
- && (regno == -1
- || (GET_CODE (op) == REG
- && REGNO (op) >= FIRST_PSEUDO_REGISTER)));
+ return (!CONSTANT_P(op)
+ && (regno == -1
+ || (GET_CODE(op) == REG
+ && REGNO(op) >= FIRST_PSEUDO_REGISTER)));
}
/* Return nonzero if op is suitable for the RHS of a cmp instruction. */
int
-thumb_cmp_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+thumb_cmp_operand(rtx op, enum machine_mode mode)
{
- return ((GET_CODE (op) == CONST_INT
- && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256)
- || register_operand (op, mode));
+ return ((GET_CODE(op) == CONST_INT
+ && (unsigned HOST_WIDE_INT) (INTVAL(op)) < 256)
+ || register_operand(op, mode));
}
int
-thumb_shiftable_const (val)
- HOST_WIDE_INT val;
+thumb_shiftable_const(HOST_WIDE_INT val)
{
- unsigned HOST_WIDE_INT x = val;
- unsigned HOST_WIDE_INT mask = 0xff;
- int i;
+ unsigned HOST_WIDE_INT x = val;
+ unsigned HOST_WIDE_INT mask = 0xff;
+ int i;
- for (i = 0; i < 25; i++)
- if ((val & (mask << i)) == val)
- return 1;
+ for (i = 0; i < 25; i++)
+ if ((val & (mask << i)) == val)
+ return 1;
- return 0;
+ return 0;
}
int
-thumb_trivial_epilogue ()
+thumb_trivial_epilogue()
{
- int regno;
+ int regno;
- /* ??? If this function ever returns 1, we get a function without any
- epilogue at all. It appears that the intent was to cause a "return"
- insn to be emitted, but that does not happen. */
- return 0;
+ /* ??? If this function ever returns 1, we get a function without any
+ epilogue at all. It appears that the intent was to cause a "return"
+ insn to be emitted, but that does not happen. */
+ return 0;
#if 0
- if (get_frame_size ()
- || current_function_outgoing_args_size
- || current_function_pretend_args_size)
- return 0;
+ if (get_frame_size()
+ || current_function_outgoing_args_size
+ || current_function_pretend_args_size)
+ return 0;
- for (regno = 8; regno < 13; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- return 0;
+ for (regno = 8; regno < 13; regno++)
+ if (regs_ever_live[regno] && !call_used_regs[regno])
+ return 0;
- return 1;
+ return 1;
#endif
}
-
/* Routines for handling the constant pool */
/* This is unashamedly hacked from the version in sh.c, since the problem is
extremely similar. */
@@ -116,60 +108,60 @@ thumb_trivial_epilogue ()
relative load instruction must be less than 1k infront of the instruction.
This means that we often have to dump a constant inside a function, and
generate code to branch around it.
-
+
It is important to minimize this, since the branches will slow things
down and make things bigger.
-
+
Worst case code looks like:
-
- ldr rn, L1
- b L2
- align
- L1: .long value
- L2:
- ..
-
- ldr rn, L3
- b L4
- align
- L3: .long value
- L4:
- ..
-
+
+ ldr rn, L1
+ b L2
+ align
+ L1: .long value
+ L2:
+ ..
+
+ ldr rn, L3
+ b L4
+ align
+ L3: .long value
+ L4:
+ ..
+
We fix this by performing a scan before scheduling, which notices which
instructions need to have their operands fetched from the constant table
and builds the table.
-
-
+
+
The algorithm is:
-
+
scan, find an instruction which needs a pcrel move. Look forward, find the
last barrier which is within MAX_COUNT bytes of the requirement.
If there isn't one, make one. Process all the instructions between
the find and the barrier.
-
+
In the above example, we can tell that L3 is within 1k of L1, so
the first move can be shrunk from the 2 insn+constant sequence into
just 1 insn, and the constant moved to L3 to make:
-
- ldr rn, L1
- ..
- ldr rn, L3
- b L4
- align
- L1: .long value
- L3: .long value
- L4:
-
+
+ ldr rn, L1
+ ..
+ ldr rn, L3
+ b L4
+ align
+ L1: .long value
+ L3: .long value
+ L4:
+
Then the second move becomes the target for the shortening process.
-
+
*/
-
+
typedef struct
{
- rtx value; /* Value in table */
- HOST_WIDE_INT next_offset;
- enum machine_mode mode; /* Mode of value */
+ rtx value; /* Value in table */
+ HOST_WIDE_INT next_offset;
+ enum machine_mode mode; /* Mode of value */
} pool_node;
/* The maximum number of constants that can fit into one pool, since
@@ -182,411 +174,396 @@ static int pool_size;
static rtx pool_vector_label;
/* Add a constant to the pool and return its label. */
-
+
static HOST_WIDE_INT
-add_constant (x, mode)
- rtx x;
- enum machine_mode mode;
+add_constant(rtx x, enum machine_mode mode)
{
- int i;
- rtx lab;
- HOST_WIDE_INT offset;
+ int i;
+ rtx lab;
+ HOST_WIDE_INT offset;
- if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0))
- && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
- x = get_pool_constant (XEXP (x, 0));
+ if (mode == SImode && GET_CODE(x) == MEM && CONSTANT_P(XEXP(x, 0))
+ && CONSTANT_POOL_ADDRESS_P(XEXP(x, 0)))
+ x = get_pool_constant(XEXP(x, 0));
- /* First see if we've already got it */
-
- for (i = 0; i < pool_size; i++)
+ /* First see if we've already got it */
+
+ for (i = 0; i < pool_size; i++)
{
- if (x->code == pool_vector[i].value->code
- && mode == pool_vector[i].mode)
+ if (x->code == pool_vector[i].value->code
+ && mode == pool_vector[i].mode)
{
- if (x->code == CODE_LABEL)
+ if (x->code == CODE_LABEL)
{
- if (XINT (x, 3) != XINT (pool_vector[i].value, 3))
- continue;
+ if (XINT(x, 3) != XINT(pool_vector[i].value, 3))
+ continue;
}
- if (rtx_equal_p (x, pool_vector[i].value))
- return pool_vector[i].next_offset - GET_MODE_SIZE (mode);
+ if (rtx_equal_p(x, pool_vector[i].value))
+ return pool_vector[i].next_offset - GET_MODE_SIZE(mode);
}
}
-
- /* Need a new one */
-
- pool_vector[pool_size].next_offset = GET_MODE_SIZE (mode);
- offset = 0;
- if (pool_size == 0)
- pool_vector_label = gen_label_rtx ();
- else
- pool_vector[pool_size].next_offset
- += (offset = pool_vector[pool_size - 1].next_offset);
-
- pool_vector[pool_size].value = x;
- pool_vector[pool_size].mode = mode;
- pool_size++;
- return offset;
+
+ /* Need a new one */
+
+ pool_vector[pool_size].next_offset = GET_MODE_SIZE(mode);
+ offset = 0;
+ if (pool_size == 0)
+ pool_vector_label = gen_label_rtx();
+ else
+ pool_vector[pool_size].next_offset
+ += (offset = pool_vector[pool_size - 1].next_offset);
+
+ pool_vector[pool_size].value = x;
+ pool_vector[pool_size].mode = mode;
+ pool_size++;
+ return offset;
}
-
+
/* Output the literal table */
-
-static void
-dump_table (scan)
- rtx scan;
+
+static void
+dump_table(rtx scan)
{
- int i;
+ int i;
- scan = emit_label_after (gen_label_rtx (), scan);
- scan = emit_insn_after (gen_align_4 (), scan);
- scan = emit_label_after (pool_vector_label, scan);
+ scan = emit_label_after(gen_label_rtx(), scan);
+ scan = emit_insn_after(gen_align_4(), scan);
+ scan = emit_label_after(pool_vector_label, scan);
- for (i = 0; i < pool_size; i++)
+ for (i = 0; i < pool_size; i++)
{
- pool_node *p = pool_vector + i;
-
- switch (GET_MODE_SIZE (p->mode))
- {
- case 4:
- scan = emit_insn_after (gen_consttable_4 (p->value), scan);
- break;
-
- case 8:
- scan = emit_insn_after (gen_consttable_8 (p->value), scan);
- break;
-
- default:
- abort ();
- break;
- }
+ pool_node *p = pool_vector + i;
+
+ switch (GET_MODE_SIZE(p->mode))
+ {
+ case 4:
+ scan = emit_insn_after(gen_consttable_4(p->value), scan);
+ break;
+
+ case 8:
+ scan = emit_insn_after(gen_consttable_8(p->value), scan);
+ break;
+
+ default:
+ abort();
+ break;
+ }
}
- scan = emit_insn_after (gen_consttable_end (), scan);
- scan = emit_barrier_after (scan);
- pool_size = 0;
+ scan = emit_insn_after(gen_consttable_end(), scan);
+ scan = emit_barrier_after(scan);
+ pool_size = 0;
}
/* Non zero if the src operand needs to be fixed up */
static
int
-fixit (src, mode)
- rtx src;
- enum machine_mode mode;
+fixit(rtx src, enum machine_mode mode)
{
- return ((CONSTANT_P (src)
- && (GET_CODE (src) != CONST_INT
- || ! (CONST_OK_FOR_LETTER_P (INTVAL (src), 'I')
- || CONST_OK_FOR_LETTER_P (INTVAL (src), 'J')
- || (mode != DImode
- && CONST_OK_FOR_LETTER_P (INTVAL (src), 'K')))))
- || (mode == SImode && GET_CODE (src) == MEM
- && GET_CODE (XEXP (src, 0)) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (XEXP (src, 0))));
+ return ((CONSTANT_P(src)
+ && (GET_CODE(src) != CONST_INT
+ || !(CONST_OK_FOR_LETTER_P(INTVAL(src), 'I')
+ || CONST_OK_FOR_LETTER_P(INTVAL(src), 'J')
+ || (mode != DImode
+ && CONST_OK_FOR_LETTER_P(INTVAL(src), 'K')))))
+ || (mode == SImode && GET_CODE(src) == MEM
+ && GET_CODE(XEXP(src, 0)) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P(XEXP(src, 0))));
}
/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one. */
#define MAX_COUNT_SI 1000
-
+
static rtx
-find_barrier (from)
- rtx from;
+find_barrier(rtx from)
{
- int count = 0;
- rtx found_barrier = 0;
- rtx label;
+ int count = 0;
+ rtx found_barrier = 0;
+ rtx label;
- while (from && count < MAX_COUNT_SI)
+ while (from && count < MAX_COUNT_SI)
{
- if (GET_CODE (from) == BARRIER)
- return from;
-
- /* Count the length of this insn */
- if (GET_CODE (from) == INSN
- && GET_CODE (PATTERN (from)) == SET
- && CONSTANT_P (SET_SRC (PATTERN (from)))
- && CONSTANT_POOL_ADDRESS_P (SET_SRC (PATTERN (from))))
- {
- rtx src = SET_SRC (PATTERN (from));
- count += 2;
- }
- else
- count += get_attr_length (from);
-
- from = NEXT_INSN (from);
+ if (GET_CODE(from) == BARRIER)
+ return from;
+
+ /* Count the length of this insn */
+ if (GET_CODE(from) == INSN
+ && GET_CODE(PATTERN(from)) == SET
+ && CONSTANT_P(SET_SRC(PATTERN(from)))
+ && CONSTANT_POOL_ADDRESS_P(SET_SRC(PATTERN(from))))
+ {
+ rtx src = SET_SRC(PATTERN(from));
+ count += 2;
+ }
+ else
+ count += get_attr_length(from);
+
+ from = NEXT_INSN(from);
}
- /* We didn't find a barrier in time to
- dump our stuff, so we'll make one */
- label = gen_label_rtx ();
-
- if (from)
- from = PREV_INSN (from);
- else
- from = get_last_insn ();
-
- /* Walk back to be just before any jump */
- while (GET_CODE (from) == JUMP_INSN
- || GET_CODE (from) == NOTE
- || GET_CODE (from) == CODE_LABEL)
- from = PREV_INSN (from);
-
- from = emit_jump_insn_after (gen_jump (label), from);
- JUMP_LABEL (from) = label;
- found_barrier = emit_barrier_after (from);
- emit_label_after (label, found_barrier);
- return found_barrier;
+ /* We didn't find a barrier in time to
+ dump our stuff, so we'll make one */
+ label = gen_label_rtx();
+
+ if (from)
+ from = PREV_INSN(from);
+ else
+ from = get_last_insn();
+
+ /* Walk back to be just before any jump */
+ while (GET_CODE(from) == JUMP_INSN
+ || GET_CODE(from) == NOTE
+ || GET_CODE(from) == CODE_LABEL)
+ from = PREV_INSN(from);
+
+ from = emit_jump_insn_after(gen_jump(label), from);
+ JUMP_LABEL(from) = label;
+ found_barrier = emit_barrier_after(from);
+ emit_label_after(label, found_barrier);
+ return found_barrier;
}
/* Non zero if the insn is a move instruction which needs to be fixed. */
-
+
static int
-broken_move (insn)
- rtx insn;
+broken_move(rtx insn)
{
- if (!INSN_DELETED_P (insn)
- && GET_CODE (insn) == INSN
- && GET_CODE (PATTERN (insn)) == SET)
+ if (!INSN_DELETED_P(insn)
+ && GET_CODE(insn) == INSN
+ && GET_CODE(PATTERN(insn)) == SET)
{
- rtx pat = PATTERN (insn);
- rtx src = SET_SRC (pat);
- rtx dst = SET_DEST (pat);
- enum machine_mode mode = GET_MODE (dst);
- if (dst == pc_rtx)
- return 0;
- return fixit (src, mode);
+ rtx pat = PATTERN(insn);
+ rtx src = SET_SRC(pat);
+ rtx dst = SET_DEST(pat);
+ enum machine_mode mode = GET_MODE(dst);
+ if (dst == pc_rtx)
+ return 0;
+ return fixit(src, mode);
}
- return 0;
+ return 0;
}
/* Recursively search through all of the blocks in a function
checking to see if any of the variables created in that
function match the RTX called 'orig'. If they do then
- replace them with the RTX called 'new'. */
+ replace them with the RTX called 'replacement'. */
static void
-replace_symbols_in_block (tree block, rtx orig, rtx new)
+replace_symbols_in_block(tree block, rtx orig, rtx replacement)
{
- for (; block; block = BLOCK_CHAIN (block))
+ for (; block; block = BLOCK_CHAIN(block))
{
- tree sym;
-
- if (! TREE_USED (block))
- continue;
-
- for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym))
- {
- if ( (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL)
- || DECL_IGNORED_P (sym)
- || TREE_CODE (sym) != VAR_DECL
- || DECL_EXTERNAL (sym)
- || ! rtx_equal_p (DECL_RTL (sym), orig)
- )
- continue;
-
- DECL_RTL (sym) = new;
- }
-
- replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new);
+ tree sym;
+
+ if (!TREE_USED(block))
+ continue;
+
+ for (sym = BLOCK_VARS(block); sym; sym = TREE_CHAIN(sym))
+ {
+ if ( (DECL_NAME(sym) == 0 && TREE_CODE(sym) != TYPE_DECL)
+ || DECL_IGNORED_P(sym)
+ || TREE_CODE(sym) != VAR_DECL
+ || DECL_EXTERNAL(sym)
+ || !rtx_equal_p(DECL_RTL(sym), orig)
+ )
+ continue;
+
+ DECL_RTL(sym) = replacement;
+ }
+
+ replace_symbols_in_block(BLOCK_SUBBLOCKS(block), orig, replacement);
}
}
void
-thumb_reorg (first)
- rtx first;
+thumb_reorg(rtx first)
{
- rtx insn;
- for (insn = first; insn; insn = NEXT_INSN (insn))
+ rtx insn;
+ for (insn = first; insn; insn = NEXT_INSN(insn))
{
- if (broken_move (insn))
- {
- /* This is a broken move instruction, scan ahead looking for
- a barrier to stick the constant table behind */
- rtx scan;
- rtx barrier = find_barrier (insn);
-
- /* Now find all the moves between the points and modify them */
- for (scan = insn; scan != barrier; scan = NEXT_INSN (scan))
- {
- if (broken_move (scan))
- {
- /* This is a broken move instruction, add it to the pool */
- rtx pat = PATTERN (scan);
- rtx src = SET_SRC (pat);
- rtx dst = SET_DEST (pat);
- enum machine_mode mode = GET_MODE (dst);
- HOST_WIDE_INT offset;
- rtx newinsn;
- rtx newsrc;
-
- /* If this is an HImode constant load, convert it into
- an SImode constant load. Since the register is always
- 32 bits this is safe. We have to do this, since the
- load pc-relative instruction only does a 32-bit load. */
- if (mode == HImode)
- {
- mode = SImode;
- if (GET_CODE (dst) != REG)
- abort ();
- PUT_MODE (dst, SImode);
- }
-
- offset = add_constant (src, mode);
- newsrc = gen_rtx (MEM, mode,
- plus_constant (gen_rtx (LABEL_REF,
- VOIDmode,
- pool_vector_label),
- offset));
-
- /* Build a jump insn wrapper around the move instead
- of an ordinary insn, because we want to have room for
- the target label rtx in fld[7], which an ordinary
- insn doesn't have. */
- newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode,
- dst, newsrc), scan);
- JUMP_LABEL (newinsn) = pool_vector_label;
-
- /* But it's still an ordinary insn */
- PUT_CODE (newinsn, INSN);
-
- /* If debugging information is going to be emitted
- then we must make sure that any refences to
- symbols which are removed by the above code are
- also removed in the descriptions of the
- function's variables. Failure to do this means
- that the debugging information emitted could
- refer to symbols which are not emited by
- output_constant_pool() because
- mark_constant_pool() never sees them as being
- used. */
-
-
- /* These are the tests used in
- output_constant_pool() to decide if the constant
- pool will be marked. Only necessary if debugging
- info is being emitted. Only necessary for
- references to memory whose address is given by a
- symbol. */
-
- if (optimize > 0
- && flag_expensive_optimizations
- && write_symbols != NO_DEBUG
- && GET_CODE (src) == MEM
- && GET_CODE (XEXP (src, 0)) == SYMBOL_REF)
- replace_symbols_in_block
- (DECL_INITIAL (current_function_decl), src, newsrc);
-
- /* Kill old insn */
- delete_insn (scan);
- scan = newinsn;
- }
- }
- dump_table (barrier);
- }
+ if (broken_move(insn))
+ {
+ /* This is a broken move instruction, scan ahead looking for
+ a barrier to stick the constant table behind */
+ rtx scan;
+ rtx barrier = find_barrier(insn);
+
+ /* Now find all the moves between the points and modify them */
+ for (scan = insn; scan != barrier; scan = NEXT_INSN(scan))
+ {
+ if (broken_move(scan))
+ {
+ /* This is a broken move instruction, add it to the pool */
+ rtx pat = PATTERN(scan);
+ rtx src = SET_SRC(pat);
+ rtx dst = SET_DEST(pat);
+ enum machine_mode mode = GET_MODE(dst);
+ HOST_WIDE_INT offset;
+ rtx newinsn;
+ rtx newsrc;
+
+ /* If this is an HImode constant load, convert it into
+ an SImode constant load. Since the register is always
+ 32 bits this is safe. We have to do this, since the
+ load pc-relative instruction only does a 32-bit load. */
+ if (mode == HImode)
+ {
+ mode = SImode;
+ if (GET_CODE(dst) != REG)
+ abort();
+ PUT_MODE(dst, SImode);
+ }
+
+ offset = add_constant(src, mode);
+ newsrc = gen_rtx(MEM, mode,
+ plus_constant(gen_rtx(LABEL_REF,
+ VOIDmode,
+ pool_vector_label),
+ offset));
+
+ /* Build a jump insn wrapper around the move instead
+ of an ordinary insn, because we want to have room for
+ the target label rtx in fld[7], which an ordinary
+ insn doesn't have. */
+ newinsn = emit_jump_insn_after(gen_rtx(SET, VOIDmode,
+ dst, newsrc), scan);
+ JUMP_LABEL(newinsn) = pool_vector_label;
+
+ /* But it's still an ordinary insn */
+ PUT_CODE(newinsn, INSN);
+
+ /* If debugging information is going to be emitted
+ then we must make sure that any refences to
+ symbols which are removed by the above code are
+ also removed in the descriptions of the
+ function's variables. Failure to do this means
+ that the debugging information emitted could
+ refer to symbols which are not emited by
+ output_constant_pool() because
+ mark_constant_pool() never sees them as being
+ used. */
+
+
+ /* These are the tests used in
+ output_constant_pool() to decide if the constant
+ pool will be marked. Only necessary if debugging
+ info is being emitted. Only necessary for
+ references to memory whose address is given by a
+ symbol. */
+
+ if (optimize > 0
+ && flag_expensive_optimizations
+ && write_symbols != NO_DEBUG
+ && GET_CODE(src) == MEM
+ && GET_CODE(XEXP(src, 0)) == SYMBOL_REF)
+ replace_symbols_in_block
+ (DECL_INITIAL(current_function_decl), src, newsrc);
+
+ /* Kill old insn */
+ delete_insn(scan);
+ scan = newinsn;
+ }
+ }
+ dump_table(barrier);
+ }
}
}
-
/* Routines for generating rtl */
void
-thumb_expand_movstrqi (operands)
- rtx *operands;
+thumb_expand_movstrqi(rtx *operands)
{
- rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
- rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
- HOST_WIDE_INT len = INTVAL (operands[2]);
- HOST_WIDE_INT offset = 0;
+ rtx out = copy_to_mode_reg(SImode, XEXP(operands[0], 0));
+ rtx in = copy_to_mode_reg(SImode, XEXP(operands[1], 0));
+ HOST_WIDE_INT len = INTVAL(operands[2]);
+ HOST_WIDE_INT offset = 0;
- while (len >= 12)
+ while (len >= 12)
{
- emit_insn (gen_movmem12b (out, in));
- len -= 12;
+ emit_insn(gen_movmem12b(out, in));
+ len -= 12;
}
- if (len >= 8)
+ if (len >= 8)
{
- emit_insn (gen_movmem8b (out, in));
- len -= 8;
+ emit_insn(gen_movmem8b(out, in));
+ len -= 8;
}
- if (len >= 4)
+ if (len >= 4)
{
- rtx reg = gen_reg_rtx (SImode);
- emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in)));
- emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg));
- len -= 4;
- offset += 4;
+ rtx reg = gen_reg_rtx(SImode);
+ emit_insn(gen_movsi(reg, gen_rtx(MEM, SImode, in)));
+ emit_insn(gen_movsi(gen_rtx(MEM, SImode, out), reg));
+ len -= 4;
+ offset += 4;
}
- if (len >= 2)
+ if (len >= 2)
{
- rtx reg = gen_reg_rtx (HImode);
- emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode,
- plus_constant (in, offset))));
- emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)),
- reg));
- len -= 2;
- offset += 2;
+ rtx reg = gen_reg_rtx(HImode);
+ emit_insn(gen_movhi(reg, gen_rtx(MEM, HImode,
+ plus_constant(in, offset))));
+ emit_insn(gen_movhi(gen_rtx(MEM, HImode, plus_constant(out, offset)),
+ reg));
+ len -= 2;
+ offset += 2;
}
- if (len)
+ if (len)
{
- rtx reg = gen_reg_rtx (QImode);
- emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode,
- plus_constant (in, offset))));
- emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)),
- reg));
+ rtx reg = gen_reg_rtx(QImode);
+ emit_insn(gen_movqi(reg, gen_rtx(MEM, QImode,
+ plus_constant(in, offset))));
+ emit_insn(gen_movqi(gen_rtx(MEM, QImode, plus_constant(out, offset)),
+ reg));
}
}
-
/* Routines for reloading */
void
-thumb_reload_out_si (operands)
- rtx operands;
+thumb_reload_out_si(rtx operands)
{
- abort ();
+ abort();
}
static int
-arm_naked_function_p (func)
- tree func;
+arm_naked_function_p(tree func)
{
- tree a;
+ tree a;
- if (TREE_CODE (func) != FUNCTION_DECL)
- abort ();
+ if (TREE_CODE(func) != FUNCTION_DECL)
+ abort();
- a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func));
- return a != NULL_TREE;
+ a = lookup_attribute("naked", DECL_MACHINE_ATTRIBUTES(func));
+ return a != NULL_TREE;
}
/* Routines for emitting code */
void
-final_prescan_insn(insn)
- rtx insn;
+final_prescan_insn(rtx insn)
{
- extern int *insn_addresses;
+ extern int *insn_addresses;
- if (flag_print_asm_name)
- fprintf (asm_out_file, "%s 0x%04x\n", ASM_COMMENT_START,
- insn_addresses[INSN_UID (insn)]);
+ if (flag_print_asm_name)
+ fprintf(asm_out_file, "%s 0x%04x\n", ASM_COMMENT_START,
+ insn_addresses[INSN_UID(insn)]);
}
static void thumb_pushpop ( FILE *, int, int ); /* Forward declaration. */
static inline int
-number_of_first_bit_set (mask)
- int mask;
+number_of_first_bit_set(int mask)
{
- int bit;
+ int bit;
- for (bit = 0;
- (mask & (1 << bit)) == 0;
- ++ bit)
- continue;
+ for (bit = 0;
+ (mask & (1 << bit)) == 0;
+ ++bit)
+ continue;
- return bit;
+ return bit;
}
#define ARG_1_REGISTER 0
@@ -594,779 +571,612 @@ number_of_first_bit_set (mask)
#define ARG_3_REGISTER 2
#define ARG_4_REGISTER 3
#define WORK_REGISTER 7
-#define FRAME_POINTER 11
-#define IP_REGISTER 12
-#define STACK_POINTER STACK_POINTER_REGNUM
-#define LINK_REGISTER 14
+#define FRAME_POINTER 11
+#define IP_REGISTER 12
+#define STACK_POINTER STACK_POINTER_REGNUM
+#define LINK_REGISTER 14
#define PROGRAM_COUNTER 15
-/* Generate code to return from a thumb function. If
- 'reg_containing_return_addr' is -1, then the return address is
+/* Generate code to return from a thumb function.
+ If 'reg_containing_return_addr' is -1, then the return address is
actually on the stack, at the stack pointer. */
static void
-thumb_exit (f, reg_containing_return_addr)
- FILE * f;
- int reg_containing_return_addr;
+thumb_exit(FILE *f, int reg_containing_return_addr)
{
- int regs_available_for_popping;
- int regs_to_pop;
- int pops_needed;
- int reg;
- int available;
- int required;
- int mode;
- int size;
- int restore_a4 = FALSE;
-
- /* Compute the registers we need to pop. */
- regs_to_pop = 0;
- pops_needed = 0;
-
- if (reg_containing_return_addr == -1)
- {
- regs_to_pop |= 1 << LINK_REGISTER;
- ++ pops_needed;
- }
+ int reg_available_for_popping;
+ int mode;
+ int size;
+ int restore_a4 = FALSE;
- /* If there is nothing to pop then just emit the BX instruction and return.*/
- if (pops_needed == 0)
+ if (reg_containing_return_addr != -1)
{
- asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]);
-
- return;
+ /* If the return address is in a register,
+ then just emit the BX instruction and return. */
+ asm_fprintf(f, "\tbx\t%s\n", reg_names[reg_containing_return_addr]);
+ return;
}
- /* Otherwise if we are not supporting interworking,
- then just pop the return address straight into the PC.
- */
- else if ( ! TARGET_THUMB_INTERWORK)
+ if (!TARGET_THUMB_INTERWORK)
{
- asm_fprintf (f, "\tpop\t{pc}\n" );
-
- return;
+ /* If we are not supporting interworking,
+ then just pop the return address straight into the PC. */
+ asm_fprintf(f, "\tpop\t{pc}\n" );
+ return;
}
- /* Find out how many of the (return) argument registers we can corrupt. */
- regs_available_for_popping = 0;
-
- /* If we can deduce the registers used from the function's return value.
- This is more reliable that examining regs_ever_live[] because that
- will be set if the register is ever used in the function, not just if
- the register is used to hold a return value. */
+ /* If we can deduce the registers used from the function's return value.
+ This is more reliable that examining regs_ever_live[] because that
+ will be set if the register is ever used in the function, not just if
+ the register is used to hold a return value. */
- if (current_function_return_rtx != 0)
- mode = GET_MODE (current_function_return_rtx);
- else
- mode = DECL_MODE (DECL_RESULT (current_function_decl));
+ if (current_function_return_rtx != 0)
+ mode = GET_MODE(current_function_return_rtx);
+ else
+ mode = DECL_MODE(DECL_RESULT(current_function_decl));
- size = GET_MODE_SIZE (mode);
+ size = GET_MODE_SIZE(mode);
- if (size == 0)
- {
- /* In a void function we can use any argument register.
- In a function that returns a structure on the stack
- we can use the second and third argument registers. */
- if (mode == VOIDmode)
- regs_available_for_popping =
- (1 << ARG_1_REGISTER)
- | (1 << ARG_2_REGISTER)
- | (1 << ARG_3_REGISTER);
- else
- regs_available_for_popping =
- (1 << ARG_2_REGISTER)
- | (1 << ARG_3_REGISTER);
- }
- else if (size <= 4) regs_available_for_popping =
- (1 << ARG_2_REGISTER)
- | (1 << ARG_3_REGISTER);
- else if (size <= 8) regs_available_for_popping =
- (1 << ARG_3_REGISTER);
-
- /* Match registers to be popped with registers into which we pop them. */
- for (available = regs_available_for_popping,
- required = regs_to_pop;
- required != 0 && available != 0;
- available &= ~(available & - available),
- required &= ~(required & - required))
- -- pops_needed;
-
- /* If we have any popping registers left over, remove them. */
- if (available > 0)
- regs_available_for_popping &= ~ available;
-
- /* Otherwise if we need another popping register we can use
- the fourth argument register. */
- else if (pops_needed)
+ if (size == 0)
{
- /* If we have not found any free argument registers and
- reg a4 contains the return address, we must move it. */
- if (regs_available_for_popping == 0
- && reg_containing_return_addr == ARG_4_REGISTER)
- {
- asm_fprintf (f, "\tmov\t%s, %s\n",
- reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]);
- reg_containing_return_addr = LINK_REGISTER;
- }
- else if (size > 12)
- {
- /* Register a4 is being used to hold part of the return value,
- but we have dire need of a free, low register. */
- restore_a4 = TRUE;
-
- asm_fprintf (f, "\tmov\t%s, %s\n",
- reg_names [IP_REGISTER], reg_names [ARG_4_REGISTER]);
- }
-
- if (reg_containing_return_addr != ARG_4_REGISTER)
- {
- /* The fourth argument register is available. */
- regs_available_for_popping |= 1 << ARG_4_REGISTER;
-
- -- pops_needed;
- }
+ /* In a void function we can use any argument register.
+ In a function that returns a structure on the stack
+ we can use the second and third argument registers. */
+ if (mode == VOIDmode)
+ reg_available_for_popping = ARG_1_REGISTER;
+ else
+ reg_available_for_popping = ARG_2_REGISTER;
}
-
- /* Pop as many registers as we can. */
- thumb_pushpop (f, regs_available_for_popping, FALSE);
-
- /* Process the registers we popped. */
- if (reg_containing_return_addr == -1)
+ else if (size <= 4)
{
- /* The return address was popped into the lowest numbered register. */
- regs_to_pop &= ~ (1 << LINK_REGISTER);
-
- reg_containing_return_addr =
- number_of_first_bit_set (regs_available_for_popping);
-
- /* Remove this register for the mask of available registers, so that
- the return address will not be corrupted by futher pops. */
- regs_available_for_popping &= ~ (1 << reg_containing_return_addr);
+ reg_available_for_popping = ARG_2_REGISTER;
}
-
- /* If we popped other registers then handle them here. */
- if (regs_available_for_popping)
+ else if (size <= 8)
{
- int frame_pointer;
-
- /* Work out which register currently contains the frame pointer. */
- frame_pointer = number_of_first_bit_set (regs_available_for_popping);
-
- /* Move it into the correct place. */
- asm_fprintf (f, "\tmov\tfp, %s\n", reg_names [frame_pointer]);
-
- /* (Temporarily) remove it from the mask of popped registers. */
- regs_available_for_popping &= ~ (1 << frame_pointer);
- regs_to_pop &= ~ (1 << FRAME_POINTER);
-
- if (regs_available_for_popping)
- {
- int stack_pointer;
-
- /* We popped the stack pointer as well, find the register that
- contains it.*/
- stack_pointer = number_of_first_bit_set (regs_available_for_popping);
-
- /* Move it into the stack register. */
- asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [stack_pointer]);
-
- /* At this point we have popped all necessary registers, so
- do not worry about restoring regs_available_for_popping
- to its correct value:
-
- assert (pops_needed == 0)
- assert (regs_available_for_popping == (1 << frame_pointer))
- assert (regs_to_pop == (1 << STACK_POINTER)) */
- }
- else
- {
- /* Since we have just move the popped value into the frame
- pointer, the popping register is available for reuse, and
- we know that we still have the stack pointer left to pop. */
- regs_available_for_popping |= (1 << frame_pointer);
- }
+ reg_available_for_popping = ARG_3_REGISTER;
}
-
- /* If we still have registers left on the stack, but we no longer have
- any registers into which we can pop them, then we must move the return
- address into the link register and make available the register that
- contained it. */
- if (regs_available_for_popping == 0 && pops_needed > 0)
+ else
{
- regs_available_for_popping |= 1 << reg_containing_return_addr;
-
- asm_fprintf (f, "\tmov\t%s, %s\n",
- reg_names [LINK_REGISTER],
- reg_names [reg_containing_return_addr]);
-
- reg_containing_return_addr = LINK_REGISTER;
- }
+ reg_available_for_popping = ARG_4_REGISTER;
- /* If we have registers left on the stack then pop some more.
- We know that at most we will want to pop FP and SP. */
- if (pops_needed > 0)
- {
- int popped_into;
- int move_to;
-
- thumb_pushpop (f, regs_available_for_popping, FALSE);
+ if (size > 12)
+ {
+ /* Register a4 is being used to hold part of the return value,
+ but we have dire need of a free, low register. */
+ restore_a4 = TRUE;
- /* We have popped either FP or SP.
- Move whichever one it is into the correct register. */
- popped_into = number_of_first_bit_set (regs_available_for_popping);
- move_to = number_of_first_bit_set (regs_to_pop);
+ asm_fprintf(f, "\tmov\t%s, %s\n",
+ reg_names[IP_REGISTER], reg_names[ARG_4_REGISTER]);
+ }
+ }
- asm_fprintf (f, "\tmov\t%s, %s\n",
- reg_names [move_to], reg_names [popped_into]);
+ /* Pop the return address. */
+ thumb_pushpop(f, (1 << reg_available_for_popping), FALSE);
- regs_to_pop &= ~ (1 << move_to);
+ reg_containing_return_addr = reg_available_for_popping;
- -- pops_needed;
- }
-
- /* If we still have not popped everything then we must have only
- had one register available to us and we are now popping the SP. */
- if (pops_needed > 0)
+ /* If necessary restore the a4 register. */
+ if (restore_a4)
{
- int popped_into;
-
- thumb_pushpop (f, regs_available_for_popping, FALSE);
+ asm_fprintf(f, "\tmov\t%s, %s\n",
+ reg_names[LINK_REGISTER], reg_names[ARG_4_REGISTER]);
- popped_into = number_of_first_bit_set (regs_available_for_popping);
+ reg_containing_return_addr = LINK_REGISTER;
- asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [popped_into]);
-
- /*
- assert (regs_to_pop == (1 << STACK_POINTER))
- assert (pops_needed == 1)
- */
+ asm_fprintf(f, "\tmov\t%s, %s\n",
+ reg_names[ARG_4_REGISTER], reg_names[IP_REGISTER]);
}
- /* If necessary restore the a4 register. */
- if (restore_a4)
- {
- if (reg_containing_return_addr != LINK_REGISTER)
- {
- asm_fprintf (f, "\tmov\t%s, %s\n",
- reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]);
- reg_containing_return_addr = LINK_REGISTER;
- }
-
- asm_fprintf (f, "\tmov\t%s, %s\n",
- reg_names [ARG_4_REGISTER], reg_names [IP_REGISTER]);
- }
-
- /* Return to caller. */
- asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]);
+ /* Return to caller. */
+ asm_fprintf(f, "\tbx\t%s\n", reg_names[reg_containing_return_addr]);
}
/* Emit code to push or pop registers to or from the stack. */
static void
-thumb_pushpop (f, mask, push)
- FILE * f;
- int mask;
- int push;
+thumb_pushpop(FILE *f, int mask, int push)
{
- int regno;
- int lo_mask = mask & 0xFF;
+ int regno;
+ int lo_mask = mask & 0xFF;
- if (lo_mask == 0 && ! push && (mask & (1 << 15)))
+ if (lo_mask == 0 && !push && (mask & (1 << 15)))
{
- /* Special case. Do not generate a POP PC statement here, do it in
- thumb_exit() */
-
- thumb_exit (f, -1);
- return;
+ /* Special case. Do not generate a POP PC statement here, do it in
+ thumb_exit() */
+
+ thumb_exit(f, -1);
+ return;
}
-
- asm_fprintf (f, "\t%s\t{", push ? "push" : "pop");
- /* Look at the low registers first. */
-
- for (regno = 0; regno < 8; regno ++, lo_mask >>= 1)
+ asm_fprintf(f, "\t%s\t{", push ? "push" : "pop");
+
+ /* Look at the low registers first. */
+
+ for (regno = 0; regno < 8; regno++, lo_mask >>= 1)
{
- if (lo_mask & 1)
- {
- asm_fprintf (f, reg_names[regno]);
-
- if ((lo_mask & ~1) != 0)
- asm_fprintf (f, ", ");
- }
+ if (lo_mask & 1)
+ {
+ asm_fprintf(f, reg_names[regno]);
+
+ if ((lo_mask & ~1) != 0)
+ asm_fprintf(f, ", ");
+ }
}
-
- if (push && (mask & (1 << 14)))
+
+ if (push && (mask & (1 << 14)))
{
- /* Catch pushing the LR. */
+ /* Catch pushing the LR. */
- if (mask & 0xFF)
- asm_fprintf (f, ", ");
-
- asm_fprintf (f, reg_names[14]);
+ if (mask & 0xFF)
+ asm_fprintf(f, ", ");
+
+ asm_fprintf(f, reg_names[14]);
}
- else if (!push && (mask & (1 << 15)))
+ else if (!push && (mask & (1 << 15)))
{
- /* Catch popping the PC. */
-
- if (TARGET_THUMB_INTERWORK)
- {
- /* The PC is never poped directly, instead
- it is popped into r3 and then BX is used. */
-
- asm_fprintf (f, "}\n");
-
- thumb_exit (f, -1);
-
- return;
- }
- else
- {
- if (mask & 0xFF)
- asm_fprintf (f, ", ");
-
- asm_fprintf (f, reg_names[15]);
- }
+ /* Catch popping the PC. */
+
+ if (TARGET_THUMB_INTERWORK)
+ {
+ /* The PC is never popped directly, instead
+ it is popped into r0-r3 and then BX is used. */
+
+ asm_fprintf(f, "}\n");
+
+ thumb_exit(f, -1);
+
+ return;
+ }
+ else
+ {
+ if (mask & 0xFF)
+ asm_fprintf(f, ", ");
+
+ asm_fprintf(f, reg_names[15]);
+ }
}
-
- asm_fprintf (f, "}\n");
+
+ asm_fprintf(f, "}\n");
}
/* Returns non-zero if the current function contains a far jump */
int
-far_jump_used_p (void)
+far_jump_used_p()
{
- rtx insn;
+ rtx insn;
- if (current_function_has_far_jump)
- return 1;
+ if (current_function_has_far_jump)
+ return 1;
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ for (insn = get_insns(); insn; insn = NEXT_INSN(insn))
{
- if (GET_CODE (insn) == JUMP_INSN
- /* Ignore tablejump patterns. */
- && GET_CODE (PATTERN (insn)) != ADDR_VEC
- && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
- && get_attr_far_jump (insn) == FAR_JUMP_YES)
- {
- current_function_has_far_jump = 1;
- return 1;
- }
+ if (GET_CODE(insn) == JUMP_INSN
+ /* Ignore tablejump patterns. */
+ && GET_CODE(PATTERN(insn)) != ADDR_VEC
+ && GET_CODE(PATTERN(insn)) != ADDR_DIFF_VEC
+ && get_attr_far_jump(insn) == FAR_JUMP_YES)
+ {
+ current_function_has_far_jump = 1;
+ return 1;
+ }
}
- return 0;
+ return 0;
}
static int return_used_this_function = 0;
char *
-output_return ()
+output_return()
{
- int regno;
- int live_regs_mask = 0;
+ int regno;
+ int live_regs_mask = 0;
- /* If a function is naked, don't use the "return" insn. */
- if (arm_naked_function_p (current_function_decl))
- return "";
+ /* If a function is naked, don't use the "return" insn. */
+ if (arm_naked_function_p(current_function_decl))
+ return "";
- return_used_this_function = 1;
+ return_used_this_function = 1;
- for (regno = 0; regno < 8; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- live_regs_mask |= 1 << regno;
+ for (regno = 0; regno < 8; regno++)
+ if (regs_ever_live[regno] && !call_used_regs[regno])
+ live_regs_mask |= 1 << regno;
- if (live_regs_mask == 0)
+ if (live_regs_mask == 0)
{
- if (leaf_function_p () && ! far_jump_used_p())
- {
- thumb_exit (asm_out_file, 14);
- }
- else if ( TARGET_THUMB_INTERWORK)
- {
- thumb_exit (asm_out_file, -1);
- }
- else
- asm_fprintf (asm_out_file, "\tpop\t{pc}\n");
+ if (leaf_function_p() && !far_jump_used_p())
+ {
+ thumb_exit(asm_out_file, 14);
+ }
+ else if (TARGET_THUMB_INTERWORK)
+ {
+ thumb_exit(asm_out_file, -1);
+ }
+ else
+ {
+ asm_fprintf(asm_out_file, "\tpop\t{pc}\n");
+ }
}
- else
+ else
{
- asm_fprintf (asm_out_file, "\tpop\t{");
-
- for (regno = 0; live_regs_mask; regno ++, live_regs_mask >>= 1)
- if (live_regs_mask & 1)
- {
- asm_fprintf (asm_out_file, reg_names[regno]);
- if (live_regs_mask & ~1)
- asm_fprintf (asm_out_file, ", ");
- }
-
- if ( TARGET_THUMB_INTERWORK)
- {
- asm_fprintf (asm_out_file, "}\n");
- thumb_exit (asm_out_file, -1);
- }
- else
- asm_fprintf (asm_out_file, ", pc}\n");
+ asm_fprintf(asm_out_file, "\tpop\t{");
+
+ for (regno = 0; live_regs_mask; regno++, live_regs_mask >>= 1)
+ {
+ if (live_regs_mask & 1)
+ {
+ asm_fprintf(asm_out_file, reg_names[regno]);
+ if (live_regs_mask & ~1)
+ asm_fprintf(asm_out_file, ", ");
+ }
+ }
+
+ if (TARGET_THUMB_INTERWORK)
+ {
+ asm_fprintf(asm_out_file, "}\n");
+ thumb_exit(asm_out_file, -1);
+ }
+ else
+ {
+ asm_fprintf(asm_out_file, ", pc}\n");
+ }
}
-
- return "";
+
+ return "";
}
void
-thumb_function_prologue (f, frame_size)
- FILE *f;
- int frame_size;
+thumb_function_prologue(FILE *f, int frame_size)
{
- int amount = frame_size + current_function_outgoing_args_size;
- int live_regs_mask = 0;
- int high_regs_pushed = 0;
- int store_arg_regs = 0;
- int regno;
-
- if (arm_naked_function_p (current_function_decl))
- return;
-
- if (current_function_anonymous_args && current_function_pretend_args_size)
- store_arg_regs = 1;
-
- if (current_function_pretend_args_size)
+ int amount = frame_size + current_function_outgoing_args_size;
+ int live_regs_mask = 0;
+ int high_regs_pushed = 0;
+ int store_arg_regs = 0;
+ int regno;
+
+ if (arm_naked_function_p(current_function_decl))
+ return;
+
+ if (current_function_anonymous_args && current_function_pretend_args_size)
+ store_arg_regs = 1;
+
+ if (current_function_pretend_args_size)
{
- if (store_arg_regs)
- {
- asm_fprintf (f, "\tpush\t{");
- for (regno = 4 - current_function_pretend_args_size / 4 ; regno < 4;
- regno++)
- asm_fprintf (f, "%s%s", reg_names[regno], regno == 3 ? "" : ", ");
- asm_fprintf (f, "}\n");
- }
- else
- asm_fprintf (f, "\tsub\t%Rsp, %Rsp, #%d\n",
- current_function_pretend_args_size);
+ if (store_arg_regs)
+ {
+ asm_fprintf(f, "\tpush\t{");
+ for (regno = 4 - current_function_pretend_args_size / 4; regno < 4;
+ regno++)
+ asm_fprintf(f, "%s%s", reg_names[regno], regno == 3 ? "" : ", ");
+ asm_fprintf(f, "}\n");
+ }
+ else
+ asm_fprintf(f, "\tsub\t%Rsp, %Rsp, #%d\n",
+ current_function_pretend_args_size);
}
- for (regno = 0; regno < 8; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- live_regs_mask |= 1 << regno;
+ for (regno = 0; regno < 8; regno++)
+ if (regs_ever_live[regno] && !call_used_regs[regno])
+ live_regs_mask |= 1 << regno;
- if (live_regs_mask || ! leaf_function_p () || far_jump_used_p())
- live_regs_mask |= 1 << 14;
+ if (live_regs_mask || !leaf_function_p() || far_jump_used_p())
+ live_regs_mask |= 1 << 14;
- if (live_regs_mask)
- thumb_pushpop (f, live_regs_mask, 1);
+ if (live_regs_mask)
+ thumb_pushpop(f, live_regs_mask, 1);
- for (regno = 8; regno < 13; regno++)
+ for (regno = 8; regno < 13; regno++)
{
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- high_regs_pushed++;
+ if (regs_ever_live[regno] && !call_used_regs[regno])
+ high_regs_pushed++;
}
- if (high_regs_pushed)
+ if (high_regs_pushed)
{
- int pushable_regs = 0;
- int mask = live_regs_mask & 0xff;
- int next_hi_reg;
-
- for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--)
- {
- if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg])
- break;
- }
-
- pushable_regs = mask;
-
- if (pushable_regs == 0)
- {
- /* desperation time -- this probably will never happen */
- if (regs_ever_live[3] || ! call_used_regs[3])
- asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[12], reg_names[3]);
- mask = 1 << 3;
- }
-
- while (high_regs_pushed > 0)
- {
- for (regno = 7; regno >= 0; regno--)
- {
- if (mask & (1 << regno))
- {
- asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[regno],
- reg_names[next_hi_reg]);
- high_regs_pushed--;
- if (high_regs_pushed)
- for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--)
- {
- if (regs_ever_live[next_hi_reg]
- && ! call_used_regs[next_hi_reg])
- break;
- }
- else
- {
- mask &= ~ ((1 << regno) - 1);
- break;
- }
- }
- }
- thumb_pushpop (f, mask, 1);
- }
-
- if (pushable_regs == 0 && (regs_ever_live[3] || ! call_used_regs[3]))
- asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[3], reg_names[12]);
+ int pushable_regs = 0;
+ int mask = live_regs_mask & 0xff;
+ int next_hi_reg;
+
+ for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--)
+ {
+ if (regs_ever_live[next_hi_reg] && !call_used_regs[next_hi_reg])
+ break;
+ }
+
+ pushable_regs = mask;
+
+ if (pushable_regs == 0)
+ {
+ /* desperation time -- this probably will never happen */
+ if (regs_ever_live[3] || !call_used_regs[3])
+ asm_fprintf(f, "\tmov\t%s, %s\n", reg_names[12], reg_names[3]);
+ mask = 1 << 3;
+ }
+
+ while (high_regs_pushed > 0)
+ {
+ for (regno = 7; regno >= 0; regno--)
+ {
+ if (mask & (1 << regno))
+ {
+ asm_fprintf(f, "\tmov\t%s, %s\n", reg_names[regno],
+ reg_names[next_hi_reg]);
+ high_regs_pushed--;
+ if (high_regs_pushed)
+ for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--)
+ {
+ if (regs_ever_live[next_hi_reg]
+ && !call_used_regs[next_hi_reg])
+ break;
+ }
+ else
+ {
+ mask &= ~((1 << regno) - 1);
+ break;
+ }
+ }
+ }
+ thumb_pushpop(f, mask, 1);
+ }
+
+ if (pushable_regs == 0 && (regs_ever_live[3] || !call_used_regs[3]))
+ asm_fprintf(f, "\tmov\t%s, %s\n", reg_names[3], reg_names[12]);
}
}
void
-thumb_expand_prologue ()
+thumb_expand_prologue()
{
- HOST_WIDE_INT amount = (get_frame_size ()
- + current_function_outgoing_args_size);
- int regno;
- int live_regs_mask;
-
- if (arm_naked_function_p (current_function_decl))
- return;
-
- if (amount)
+ HOST_WIDE_INT amount = (get_frame_size()
+ + current_function_outgoing_args_size);
+ int regno;
+ int live_regs_mask;
+
+ if (arm_naked_function_p(current_function_decl))
+ return;
+
+ if (amount)
{
- live_regs_mask = 0;
- for (regno = 0; regno < 8; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- live_regs_mask |= 1 << regno;
-
- if (amount < 512)
- emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (-amount)));
- else
- {
- rtx reg, spare;
-
- if ((live_regs_mask & 0xff) == 0) /* Very unlikely */
- emit_insn (gen_movsi (spare = gen_rtx (REG, SImode, 12),
- reg = gen_rtx (REG, SImode, 4)));
- else
- {
- for (regno = 0; regno < 8; regno++)
- if (live_regs_mask & (1 << regno))
- break;
- reg = gen_rtx (REG, SImode, regno);
- }
-
- emit_insn (gen_movsi (reg, GEN_INT (-amount)));
- emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
- if ((live_regs_mask & 0xff) == 0)
- emit_insn (gen_movsi (reg, spare));
- }
+ live_regs_mask = 0;
+ for (regno = 0; regno < 8; regno++)
+ if (regs_ever_live[regno] && !call_used_regs[regno])
+ live_regs_mask |= 1 << regno;
+
+ if (amount < 512)
+ emit_insn(gen_addsi3(stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT(-amount)));
+ else
+ {
+ rtx reg, spare;
+
+ if ((live_regs_mask & 0xff) == 0) /* Very unlikely */
+ emit_insn(gen_movsi(spare = gen_rtx(REG, SImode, 12),
+ reg = gen_rtx(REG, SImode, 4)));
+ else
+ {
+ for (regno = 0; regno < 8; regno++)
+ if (live_regs_mask & (1 << regno))
+ break;
+ reg = gen_rtx(REG, SImode, regno);
+ }
+
+ emit_insn(gen_movsi(reg, GEN_INT(-amount)));
+ emit_insn(gen_addsi3(stack_pointer_rtx, stack_pointer_rtx, reg));
+ if ((live_regs_mask & 0xff) == 0)
+ emit_insn(gen_movsi(reg, spare));
+ }
}
- if (frame_pointer_needed)
+ if (frame_pointer_needed)
{
- if (current_function_outgoing_args_size)
- {
- rtx offset = GEN_INT (current_function_outgoing_args_size);
-
- if (current_function_outgoing_args_size < 1024)
- emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx,
- offset));
- else
- {
- emit_insn (gen_movsi (frame_pointer_rtx, offset));
- emit_insn (gen_addsi3 (frame_pointer_rtx, frame_pointer_rtx,
- stack_pointer_rtx));
- }
- }
- else
- emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
+ if (current_function_outgoing_args_size)
+ {
+ rtx offset = GEN_INT(current_function_outgoing_args_size);
+
+ if (current_function_outgoing_args_size < 1024)
+ emit_insn(gen_addsi3(frame_pointer_rtx, stack_pointer_rtx,
+ offset));
+ else
+ {
+ emit_insn(gen_movsi(frame_pointer_rtx, offset));
+ emit_insn(gen_addsi3(frame_pointer_rtx, frame_pointer_rtx,
+ stack_pointer_rtx));
+ }
+ }
+ else
+ emit_insn(gen_movsi(frame_pointer_rtx, stack_pointer_rtx));
}
- /* if (profile_flag || profile_block_flag) */
- emit_insn (gen_blockage ());
+ /* if (profile_flag || profile_block_flag) */
+ emit_insn(gen_blockage());
}
void
-thumb_expand_epilogue ()
+thumb_expand_epilogue()
{
- HOST_WIDE_INT amount = (get_frame_size ()
- + current_function_outgoing_args_size);
- int regno;
+ HOST_WIDE_INT amount = (get_frame_size()
+ + current_function_outgoing_args_size);
+ int regno;
- if (arm_naked_function_p (current_function_decl))
- return;
+ if (arm_naked_function_p(current_function_decl))
+ return;
- if (amount)
+ if (amount)
{
- if (amount < 512)
- emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (amount)));
- else
- {
- rtx reg = gen_rtx (REG, SImode, 3); /* Always free in the epilogue */
-
- emit_insn (gen_movsi (reg, GEN_INT (amount)));
- emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
- }
- /* if (profile_flag || profile_block_flag) */
- emit_insn (gen_blockage ());
+ if (amount < 512)
+ emit_insn(gen_addsi3(stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT(amount)));
+ else
+ {
+ rtx reg = gen_rtx(REG, SImode, 3); /* Always free in the epilogue */
+
+ emit_insn(gen_movsi(reg, GEN_INT(amount)));
+ emit_insn(gen_addsi3(stack_pointer_rtx, stack_pointer_rtx, reg));
+ }
+ /* if (profile_flag || profile_block_flag) */
+ emit_insn(gen_blockage());
}
}
void
-thumb_function_epilogue (f, frame_size)
- FILE *f;
- int frame_size;
+thumb_function_epilogue(FILE *f, int frame_size)
{
- /* ??? Probably not safe to set this here, since it assumes that a
- function will be emitted as assembly immediately after we generate
- RTL for it. This does not happen for inline functions. */
- return_used_this_function = 0;
- current_function_has_far_jump = 0;
+ /* ??? Probably not safe to set this here, since it assumes that a
+ function will be emitted as assembly immediately after we generate
+ RTL for it. This does not happen for inline functions. */
+ return_used_this_function = 0;
+ current_function_has_far_jump = 0;
#if 0 /* TODO : comment not really needed */
- fprintf (f, "%s THUMB Epilogue\n", ASM_COMMENT_START);
+ fprintf(f, "%s THUMB Epilogue\n", ASM_COMMENT_START);
#endif
}
/* The bits which aren't usefully expanded as rtl. */
char *
-thumb_unexpanded_epilogue ()
+thumb_unexpanded_epilogue()
{
- int regno;
- int live_regs_mask = 0;
- int high_regs_pushed = 0;
- int leaf_function = leaf_function_p ();
- int had_to_push_lr;
+ int regno;
+ int live_regs_mask = 0;
+ int high_regs_pushed = 0;
+ int leaf_function = leaf_function_p();
+ int had_to_push_lr;
- if (return_used_this_function)
- return "";
+ if (return_used_this_function)
+ return "";
- for (regno = 0; regno < 8; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- live_regs_mask |= 1 << regno;
+ for (regno = 0; regno < 8; regno++)
+ if (regs_ever_live[regno] && !call_used_regs[regno])
+ live_regs_mask |= 1 << regno;
- for (regno = 8; regno < 13; regno++)
+ for (regno = 8; regno < 13; regno++)
{
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- high_regs_pushed ++;
+ if (regs_ever_live[regno] && !call_used_regs[regno])
+ high_regs_pushed++;
}
- /* The prolog may have pushed some high registers to use as
- work registers. eg the testuite file:
- gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c
- compiles to produce:
- push {r4, r5, r6, r7, lr}
- mov r7, r9
- mov r6, r8
- push {r6, r7}
- as part of the prolog. We have to undo that pushing here. */
-
- if (high_regs_pushed)
+ /* The prolog may have pushed some high registers to use as
+ work registers. eg the testuite file:
+ gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c
+ compiles to produce:
+ push {r4, r5, r6, r7, lr}
+ mov r7, r9
+ mov r6, r8
+ push {r6, r7}
+ as part of the prolog. We have to undo that pushing here. */
+
+ if (high_regs_pushed)
{
- int mask = live_regs_mask;
- int next_hi_reg;
- int size;
- int mode;
-
- /* If we can deduce the registers used from the function's return value.
- This is more reliable that examining regs_ever_live[] because that
- will be set if the register is ever used in the function, not just if
- the register is used to hold a return value. */
-
- if (current_function_return_rtx != 0)
- {
- mode = GET_MODE (current_function_return_rtx);
- }
- else
- {
- mode = DECL_MODE (DECL_RESULT (current_function_decl));
- }
-
- size = GET_MODE_SIZE (mode);
-
- /* Unless we are returning a type of size > 12 register r3 is available. */
- if (size < 13)
- mask |= 1 << 3;
-
- if (mask == 0)
- {
- /* Oh dear! We have no low registers into which we can pop high registers! */
-
- fatal ("No low registers available for popping high registers");
- }
-
- for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
- if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg])
- break;
-
- while (high_regs_pushed)
- {
- /* Find low register(s) into which the high register(s) can be popped. */
- for (regno = 0; regno < 8; regno++)
- {
- if (mask & (1 << regno))
- high_regs_pushed--;
- if (high_regs_pushed == 0)
- break;
- }
-
- mask &= (2 << regno) - 1; /* A noop if regno == 8 */
-
- /* Pop the values into the low register(s). */
- thumb_pushpop (asm_out_file, mask, 0);
-
- /* Move the value(s) into the high registers. */
- for (regno = 0; regno < 8; regno++)
- {
- if (mask & (1 << regno))
- {
- asm_fprintf (asm_out_file, "\tmov\t%s, %s\n",
- reg_names[next_hi_reg], reg_names[regno]);
- for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
- if (regs_ever_live[next_hi_reg] &&
- ! call_used_regs[next_hi_reg])
- break;
- }
- }
- }
+ int mask = live_regs_mask;
+ int next_hi_reg;
+ int size;
+ int mode;
+
+ /* If we can deduce the registers used from the function's return value.
+ This is more reliable that examining regs_ever_live[] because that
+ will be set if the register is ever used in the function, not just if
+ the register is used to hold a return value. */
+
+ if (current_function_return_rtx != 0)
+ {
+ mode = GET_MODE(current_function_return_rtx);
+ }
+ else
+ {
+ mode = DECL_MODE(DECL_RESULT(current_function_decl));
+ }
+
+ size = GET_MODE_SIZE(mode);
+
+ /* Unless we are returning a type of size > 12 register r3 is available. */
+ if (size < 13)
+ mask |= 1 << 3;
+
+ if (mask == 0)
+ {
+ /* Oh dear! We have no low registers into which we can pop high registers! */
+
+ fatal("No low registers available for popping high registers");
+ }
+
+ for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
+ if (regs_ever_live[next_hi_reg] && !call_used_regs[next_hi_reg])
+ break;
+
+ while (high_regs_pushed)
+ {
+ /* Find low register(s) into which the high register(s) can be popped. */
+ for (regno = 0; regno < 8; regno++)
+ {
+ if (mask & (1 << regno))
+ high_regs_pushed--;
+ if (high_regs_pushed == 0)
+ break;
+ }
+
+ mask &= (2 << regno) - 1; /* A noop if regno == 8 */
+
+ /* Pop the values into the low register(s). */
+ thumb_pushpop(asm_out_file, mask, 0);
+
+ /* Move the value(s) into the high registers. */
+ for (regno = 0; regno < 8; regno++)
+ {
+ if (mask & (1 << regno))
+ {
+ asm_fprintf(asm_out_file, "\tmov\t%s, %s\n",
+ reg_names[next_hi_reg], reg_names[regno]);
+ for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
+ if (regs_ever_live[next_hi_reg] &&
+ !call_used_regs[next_hi_reg])
+ break;
+ }
+ }
+ }
}
- had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p());
-
- if (current_function_pretend_args_size == 0)
+ had_to_push_lr = (live_regs_mask || !leaf_function || far_jump_used_p());
+
+ if (current_function_pretend_args_size == 0)
{
- if (had_to_push_lr)
- live_regs_mask |= 1 << PROGRAM_COUNTER;
-
- /* No argument registers were pushed, so just pop everything. */
-
- if (live_regs_mask)
- thumb_pushpop (asm_out_file, live_regs_mask, FALSE);
-
- /* We have either just popped the return address into the
- PC or it is was kept in LR for the entire function or
- it is still on the stack because we do not want to
- return by doing a pop {pc}. */
-
- if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0)
- thumb_exit (asm_out_file, LINK_REGISTER);
+ if (had_to_push_lr)
+ live_regs_mask |= 1 << PROGRAM_COUNTER;
+
+ /* No argument registers were pushed, so just pop everything. */
+
+ if (live_regs_mask)
+ thumb_pushpop(asm_out_file, live_regs_mask, FALSE);
+
+ /* We have either just popped the return address into the
+ PC or it is was kept in LR for the entire function or
+ it is still on the stack because we do not want to
+ return by doing a pop {pc}. */
+
+ if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0)
+ thumb_exit(asm_out_file, LINK_REGISTER);
}
- else
+ else
{
- /* Pop everything but the return address. */
- live_regs_mask &= ~ (1 << PROGRAM_COUNTER);
-
- if (live_regs_mask)
- thumb_pushpop (asm_out_file, live_regs_mask, FALSE);
-
- if (had_to_push_lr)
- {
- /* Get the return address into a temporary register. */
- thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0);
- }
-
- /* Remove the argument registers that were pushed onto the stack. */
- asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n",
- reg_names [STACK_POINTER],
- reg_names [STACK_POINTER],
- current_function_pretend_args_size);
-
- thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER);
+ /* Pop everything but the return address. */
+ live_regs_mask &= ~(1 << PROGRAM_COUNTER);
+
+ if (live_regs_mask)
+ thumb_pushpop(asm_out_file, live_regs_mask, FALSE);
+
+ if (had_to_push_lr)
+ {
+ /* Get the return address into a temporary register. */
+ thumb_pushpop(asm_out_file, 1 << ARG_4_REGISTER, 0);
+ }
+
+ /* Remove the argument registers that were pushed onto the stack. */
+ asm_fprintf(asm_out_file, "\tadd\t%s, %s, #%d\n",
+ reg_names[STACK_POINTER],
+ reg_names[STACK_POINTER],
+ current_function_pretend_args_size);
+
+ thumb_exit(asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER);
}
- return "";
+ return "";
}
/* Handle the case of a double word load into a low register from
@@ -1374,206 +1184,201 @@ thumb_unexpanded_epilogue ()
register which is overwritten by the load. */
char *
-thumb_load_double_from_address (operands)
- rtx * operands;
+thumb_load_double_from_address(rtx *operands)
{
- rtx addr;
- rtx base;
- rtx offset;
- rtx arg1;
- rtx arg2;
-
- if (GET_CODE (operands[0]) != REG)
- fatal ("thumb_load_double_from_address: destination is not a register");
-
- if (GET_CODE (operands[1]) != MEM)
- fatal ("thumb_load_double_from_address: source is not a computed memory address");
-
- /* Get the memory address. */
-
- addr = XEXP (operands[1], 0);
-
- /* Work out how the memory address is computed. */
-
- switch (GET_CODE (addr))
+ rtx addr;
+ rtx base;
+ rtx offset;
+ rtx arg1;
+ rtx arg2;
+
+ if (GET_CODE(operands[0]) != REG)
+ fatal("thumb_load_double_from_address: destination is not a register");
+
+ if (GET_CODE(operands[1]) != MEM)
+ fatal("thumb_load_double_from_address: source is not a computed memory address");
+
+ /* Get the memory address. */
+
+ addr = XEXP(operands[1], 0);
+
+ /* Work out how the memory address is computed. */
+
+ switch (GET_CODE(addr))
{
case REG:
- operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4));
-
- if (REGNO (operands[0]) == REGNO (addr))
- {
- output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands);
- output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands);
- }
- else
- {
- output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands);
- output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands);
- }
- break;
-
+ operands[2] = gen_rtx(MEM, SImode, plus_constant(XEXP(operands[1], 0), 4));
+
+ if (REGNO(operands[0]) == REGNO(addr))
+ {
+ output_asm_insn("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands);
+ output_asm_insn("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands);
+ }
+ else
+ {
+ output_asm_insn("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands);
+ output_asm_insn("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands);
+ }
+ break;
+
case CONST:
- /* Compute <address> + 4 for the high order load. */
-
- operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4));
-
- output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands);
- output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands);
- break;
-
+ /* Compute <address> + 4 for the high order load. */
+
+ operands[2] = gen_rtx(MEM, SImode, plus_constant(XEXP(operands[1], 0), 4));
+
+ output_asm_insn("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands);
+ output_asm_insn("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands);
+ break;
+
case PLUS:
- arg1 = XEXP (addr, 0);
- arg2 = XEXP (addr, 1);
-
- if (CONSTANT_P (arg1))
- base = arg2, offset = arg1;
- else
- base = arg1, offset = arg2;
-
- if (GET_CODE (base) != REG)
- fatal ("thumb_load_double_from_address: base is not a register");
-
- /* Catch the case of <address> = <reg> + <reg> */
-
- if (GET_CODE (offset) == REG)
- {
- int reg_offset = REGNO (offset);
- int reg_base = REGNO (base);
- int reg_dest = REGNO (operands[0]);
-
- /* Add the base and offset registers together into the higher destination register. */
-
- fprintf (asm_out_file, "\tadd\t%s, %s, %s\t\t%s created by thumb_load_double_from_address",
- reg_names[ reg_dest + 1 ],
- reg_names[ reg_base ],
- reg_names[ reg_offset ],
- ASM_COMMENT_START);
-
- /* Load the lower destination register from the address in the higher destination register. */
-
- fprintf (asm_out_file, "\tldr\t%s, [%s, #0]\t\t%s created by thumb_load_double_from_address",
- reg_names[ reg_dest ],
- reg_names[ reg_dest + 1],
- ASM_COMMENT_START);
-
- /* Load the higher destination register from its own address plus 4. */
-
- fprintf (asm_out_file, "\tldr\t%s, [%s, #4]\t\t%s created by thumb_load_double_from_address",
- reg_names[ reg_dest + 1 ],
- reg_names[ reg_dest + 1 ],
- ASM_COMMENT_START);
- }
- else
- {
- /* Compute <address> + 4 for the high order load. */
-
- operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4));
-
- /* If the computed address is held in the low order register
- then load the high order register first, otherwise always
- load the low order register first. */
-
- if (REGNO (operands[0]) == REGNO (base))
- {
- output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands);
- output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands);
- }
- else
- {
- output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands);
- output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands);
- }
- }
- break;
+ arg1 = XEXP(addr, 0);
+ arg2 = XEXP(addr, 1);
+
+ if (CONSTANT_P(arg1))
+ base = arg2, offset = arg1;
+ else
+ base = arg1, offset = arg2;
+
+ if (GET_CODE(base) != REG)
+ fatal("thumb_load_double_from_address: base is not a register");
+
+ /* Catch the case of <address> = <reg> + <reg> */
+
+ if (GET_CODE(offset) == REG)
+ {
+ int reg_offset = REGNO(offset);
+ int reg_base = REGNO(base);
+ int reg_dest = REGNO(operands[0]);
+
+ /* Add the base and offset registers together into the higher destination register. */
+
+ fprintf(asm_out_file, "\tadd\t%s, %s, %s\t\t%s created by thumb_load_double_from_address",
+ reg_names[ reg_dest + 1 ],
+ reg_names[ reg_base ],
+ reg_names[ reg_offset ],
+ ASM_COMMENT_START);
+
+ /* Load the lower destination register from the address in the higher destination register. */
+
+ fprintf(asm_out_file, "\tldr\t%s,[%s, #0]\t\t%s created by thumb_load_double_from_address",
+ reg_names[ reg_dest ],
+ reg_names[ reg_dest + 1],
+ ASM_COMMENT_START);
+
+ /* Load the higher destination register from its own address plus 4. */
+
+ fprintf(asm_out_file, "\tldr\t%s,[%s, #4]\t\t%s created by thumb_load_double_from_address",
+ reg_names[ reg_dest + 1 ],
+ reg_names[ reg_dest + 1 ],
+ ASM_COMMENT_START);
+ }
+ else
+ {
+ /* Compute <address> + 4 for the high order load. */
+
+ operands[2] = gen_rtx(MEM, SImode, plus_constant(XEXP(operands[1], 0), 4));
+
+ /* If the computed address is held in the low order register
+ then load the high order register first, otherwise always
+ load the low order register first. */
+
+ if (REGNO(operands[0]) == REGNO(base))
+ {
+ output_asm_insn("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands);
+ output_asm_insn("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands);
+ }
+ else
+ {
+ output_asm_insn("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands);
+ output_asm_insn("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands);
+ }
+ }
+ break;
case LABEL_REF:
- /* With no registers to worry about we can just load the value directly. */
- operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4));
-
- output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands);
- output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands);
- break;
-
+ /* With no registers to worry about we can just load the value directly. */
+ operands[2] = gen_rtx(MEM, SImode, plus_constant(XEXP(operands[1], 0), 4));
+
+ output_asm_insn("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands);
+ output_asm_insn("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands);
+ break;
+
default:
- debug_rtx (operands[1]);
- fatal ("thumb_load_double_from_address: Unhandled address calculation");
- break;
+ debug_rtx(operands[1]);
+ fatal("thumb_load_double_from_address: Unhandled address calculation");
+ break;
}
-
- return "";
+
+ return "";
}
char *
-output_move_mem_multiple (n, operands)
- int n;
- rtx *operands;
+output_move_mem_multiple(int n, rtx *operands)
{
- rtx tmp;
+ rtx tmp;
- switch (n)
+ switch (n)
{
case 2:
- if (REGNO (operands[2]) > REGNO (operands[3]))
- {
- tmp = operands[2];
- operands[2] = operands[3];
- operands[3] = tmp;
- }
- output_asm_insn ("ldmia\t%1!, {%2, %3}", operands);
- output_asm_insn ("stmia\t%0!, {%2, %3}", operands);
- break;
+ if (REGNO(operands[2]) > REGNO(operands[3]))
+ {
+ tmp = operands[2];
+ operands[2] = operands[3];
+ operands[3] = tmp;
+ }
+ output_asm_insn("ldmia\t%1!, {%2, %3}", operands);
+ output_asm_insn("stmia\t%0!, {%2, %3}", operands);
+ break;
case 3:
- if (REGNO (operands[2]) > REGNO (operands[3]))
- {
- tmp = operands[2];
- operands[2] = operands[3];
- operands[3] = tmp;
- }
- if (REGNO (operands[3]) > REGNO (operands[4]))
- {
- tmp = operands[3];
- operands[3] = operands[4];
- operands[4] = tmp;
- }
- if (REGNO (operands[2]) > REGNO (operands[3]))
- {
- tmp = operands[2];
- operands[2] = operands[3];
- operands[3] = tmp;
- }
- output_asm_insn ("ldmia\t%1!, {%2, %3, %4}", operands);
- output_asm_insn ("stmia\t%0!, {%2, %3, %4}", operands);
- break;
+ if (REGNO(operands[2]) > REGNO(operands[3]))
+ {
+ tmp = operands[2];
+ operands[2] = operands[3];
+ operands[3] = tmp;
+ }
+ if (REGNO(operands[3]) > REGNO(operands[4]))
+ {
+ tmp = operands[3];
+ operands[3] = operands[4];
+ operands[4] = tmp;
+ }
+ if (REGNO(operands[2]) > REGNO(operands[3]))
+ {
+ tmp = operands[2];
+ operands[2] = operands[3];
+ operands[3] = tmp;
+ }
+ output_asm_insn("ldmia\t%1!, {%2, %3, %4}", operands);
+ output_asm_insn("stmia\t%0!, {%2, %3, %4}", operands);
+ break;
default:
- abort ();
+ abort();
}
- return "";
+ return "";
}
-
+
int
-thumb_epilogue_size ()
+thumb_epilogue_size()
{
- return 42; /* The answer to .... */
+ return 42; /* The answer to .... */
}
static char *conds[] =
{
- "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
- "hi", "ls", "ge", "lt", "gt", "le"
+ "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
+ "hi", "ls", "ge", "lt", "gt", "le"
};
static char *
-thumb_condition_code (x, invert)
- rtx x;
- int invert;
+thumb_condition_code(rtx x, int invert)
{
- int val;
+ int val;
- switch (GET_CODE (x))
+ switch (GET_CODE(x))
{
case EQ: val = 0; break;
case NE: val = 1; break;
@@ -1586,106 +1391,103 @@ thumb_condition_code (x, invert)
case GT: val = 12; break;
case LE: val = 13; break;
default:
- abort ();
+ abort();
}
- return conds[val ^ invert];
+ return conds[val ^ invert];
}
void
-thumb_print_operand (f, x, code)
- FILE *f;
- rtx x;
- int code;
+thumb_print_operand(FILE *f, rtx x, int code)
{
- if (code)
+ if (code)
{
- switch (code)
- {
- case '@':
- fputs (ASM_COMMENT_START, f);
- return;
-
- case '_':
- fputs (user_label_prefix, f);
- return;
-
- case 'D':
- if (x)
- fputs (thumb_condition_code (x, 1), f);
- return;
-
- case 'd':
- if (x)
- fputs (thumb_condition_code (x, 0), f);
- return;
-
- /* An explanation of the 'Q', 'R' and 'H' register operands:
-
- In a pair of registers containing a DI or DF value the 'Q'
- operand returns the register number of the register containing
- the least signficant part of the value. The 'R' operand returns
- the register number of the register containing the most
- significant part of the value.
-
- The 'H' operand returns the higher of the two register numbers.
- On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the
- same as the 'Q' operand, since the most signficant part of the
- value is held in the lower number register. The reverse is true
- on systems where WORDS_BIG_ENDIAN is false.
-
- The purpose of these operands is to distinguish between cases
- where the endian-ness of the values is important (for example
- when they are added together), and cases where the endian-ness
- is irrelevant, but the order of register operations is important.
- For example when loading a value from memory into a register
- pair, the endian-ness does not matter. Provided that the value
- from the lower memory address is put into the lower numbered
- register, and the value from the higher address is put into the
- higher numbered register, the load will work regardless of whether
- the value being loaded is big-wordian or little-wordian. The
- order of the two register loads can matter however, if the address
- of the memory location is actually held in one of the registers
- being overwritten by the load. */
- case 'Q':
- if (REGNO (x) > 15)
- abort ();
- fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], f);
- return;
-
- case 'R':
- if (REGNO (x) > 15)
- abort ();
- fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], f);
- return;
-
- case 'H':
- if (REGNO (x) > 15)
- abort ();
- fputs (reg_names[REGNO (x) + 1], f);
- return;
+ switch (code)
+ {
+ case '@':
+ fputs(ASM_COMMENT_START, f);
+ return;
+
+ case '_':
+ fputs(user_label_prefix, f);
+ return;
+
+ case 'D':
+ if (x)
+ fputs(thumb_condition_code(x, 1), f);
+ return;
+
+ case 'd':
+ if (x)
+ fputs(thumb_condition_code(x, 0), f);
+ return;
+
+ /* An explanation of the 'Q', 'R' and 'H' register operands:
+
+ In a pair of registers containing a DI or DF value the 'Q'
+ operand returns the register number of the register containing
+ the least signficant part of the value. The 'R' operand returns
+ the register number of the register containing the most
+ significant part of the value.
+
+ The 'H' operand returns the higher of the two register numbers.
+ On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the
+ same as the 'Q' operand, since the most signficant part of the
+ value is held in the lower number register. The reverse is true
+ on systems where WORDS_BIG_ENDIAN is false.
+
+ The purpose of these operands is to distinguish between cases
+ where the endian-ness of the values is important (for example
+ when they are added together), and cases where the endian-ness
+ is irrelevant, but the order of register operations is important.
+ For example when loading a value from memory into a register
+ pair, the endian-ness does not matter. Provided that the value
+ from the lower memory address is put into the lower numbered
+ register, and the value from the higher address is put into the
+ higher numbered register, the load will work regardless of whether
+ the value being loaded is big-wordian or little-wordian. The
+ order of the two register loads can matter however, if the address
+ of the memory location is actually held in one of the registers
+ being overwritten by the load. */
+ case 'Q':
+ if (REGNO(x) > 15)
+ abort();
+ fputs(reg_names[REGNO(x) + (WORDS_BIG_ENDIAN ? 1 : 0)], f);
+ return;
+
+ case 'R':
+ if (REGNO(x) > 15)
+ abort();
+ fputs(reg_names[REGNO(x) + (WORDS_BIG_ENDIAN ? 0 : 1)], f);
+ return;
+
+ case 'H':
+ if (REGNO(x) > 15)
+ abort();
+ fputs(reg_names[REGNO(x) + 1], f);
+ return;
case 'c':
- /* We use 'c' operands with symbols for .vtinherit */
- if (GET_CODE (x) == SYMBOL_REF)
- output_addr_const(f, x);
- return;
-
- default:
- abort ();
- }
+ /* We use 'c' operands with symbols for .vtinherit */
+ if (GET_CODE(x) == SYMBOL_REF)
+ output_addr_const(f, x);
+ return;
+
+ default:
+ abort();
+ }
}
- if (GET_CODE (x) == REG)
- fputs (reg_names[REGNO (x)], f);
- else if (GET_CODE (x) == MEM)
- output_address (XEXP (x, 0));
- else if (GET_CODE (x) == CONST_INT)
+ if (GET_CODE(x) == REG)
+ fputs(reg_names[REGNO(x)], f);
+ else if (GET_CODE(x) == MEM)
+ output_address(XEXP(x, 0));
+ else if (GET_CODE(x) == CONST_INT)
{
- fputc ('#', f);
- output_addr_const (f, x);
+ fputc('#', f);
+ output_addr_const(f, x);
}
- else
- abort ();
+ else
+ abort();
}
/* Decide whether a type should be returned in memory (true)
@@ -1693,95 +1495,94 @@ thumb_print_operand (f, x, code)
RETURN_IN_MEMORY. */
int
-thumb_return_in_memory (type)
- tree type;
+thumb_return_in_memory(tree type)
{
- if (! AGGREGATE_TYPE_P (type))
+ if (!AGGREGATE_TYPE_P(type))
{
- /* All simple types are returned in registers. */
+ /* All simple types are returned in registers. */
- return 0;
+ return 0;
}
- else if (int_size_in_bytes (type) > 4)
+ else if (int_size_in_bytes(type) > 4)
{
- /* All structures/unions bigger than one word are returned in memory. */
-
- return 1;
+ /* All structures/unions bigger than one word are returned in memory. */
+
+ return 1;
}
- else if (TREE_CODE (type) == RECORD_TYPE)
+ else if (TREE_CODE(type) == RECORD_TYPE)
{
- tree field;
-
- /* For a struct the APCS says that we must return in a register if
- every addressable element has an offset of zero. For practical
- purposes this means that the structure can have at most one non-
- bit-field element and that this element must be the first one in
- the structure. */
-
- /* Find the first field, ignoring non FIELD_DECL things which will
- have been created by C++. */
- for (field = TYPE_FIELDS (type);
- field && TREE_CODE (field) != FIELD_DECL;
- field = TREE_CHAIN (field))
- continue;
-
- if (field == NULL)
- return 0; /* An empty structure. Allowed by an extension to ANSI C. */
-
- /* Now check the remaining fields, if any. */
- for (field = TREE_CHAIN (field); field; field = TREE_CHAIN (field))
- {
- if (TREE_CODE (field) != FIELD_DECL)
- continue;
-
- if (! DECL_BIT_FIELD_TYPE (field))
- return 1;
- }
-
- return 0;
+ tree field;
+
+ /* For a struct the APCS says that we must return in a register if
+ every addressable element has an offset of zero. For practical
+ purposes this means that the structure can have at most one non-
+ bit-field element and that this element must be the first one in
+ the structure. */
+
+ /* Find the first field, ignoring non FIELD_DECL things which will
+ have been created by C++. */
+ for (field = TYPE_FIELDS(type);
+ field && TREE_CODE(field) != FIELD_DECL;
+ field = TREE_CHAIN(field))
+ continue;
+
+ if (field == NULL)
+ return 0; /* An empty structure. Allowed by an extension to ANSI C. */
+
+ /* Now check the remaining fields, if any. */
+ for (field = TREE_CHAIN(field); field; field = TREE_CHAIN(field))
+ {
+ if (TREE_CODE(field) != FIELD_DECL)
+ continue;
+
+ if (!DECL_BIT_FIELD_TYPE(field))
+ return 1;
+ }
+
+ return 0;
}
- else if (TREE_CODE (type) == UNION_TYPE)
+ else if (TREE_CODE(type) == UNION_TYPE)
{
- tree field;
-
- /* Unions can be returned in registers if every element is
- integral, or can be returned in an integer register. */
-
- for (field = TYPE_FIELDS (type);
- field;
- field = TREE_CHAIN (field))
- {
- if (TREE_CODE (field) != FIELD_DECL)
- continue;
-
- if (RETURN_IN_MEMORY (TREE_TYPE (field)))
- return 1;
- }
-
- return 0;
+ tree field;
+
+ /* Unions can be returned in registers if every element is
+ integral, or can be returned in an integer register. */
+
+ for (field = TYPE_FIELDS(type);
+ field;
+ field = TREE_CHAIN(field))
+ {
+ if (TREE_CODE(field) != FIELD_DECL)
+ continue;
+
+ if (RETURN_IN_MEMORY(TREE_TYPE(field)))
+ return 1;
+ }
+
+ return 0;
}
- /* XXX Not sure what should be done for other aggregates, so put them in
- memory. */
- return 1;
+ /* XXX Not sure what should be done for other aggregates, so put them in
+ memory. */
+ return 1;
}
void
-thumb_override_options ()
+thumb_override_options()
{
- if (structure_size_string != NULL)
+ if (structure_size_string != NULL)
{
- int size = strtol (structure_size_string, NULL, 0);
-
- if (size == 8 || size == 32)
- arm_structure_size_boundary = size;
- else
- warning ("Structure size boundary can only be set to 8 or 32");
+ int size = strtol(structure_size_string, NULL, 0);
+
+ if (size == 8 || size == 32)
+ arm_structure_size_boundary = size;
+ else
+ warning("Structure size boundary can only be set to 8 or 32");
}
- if (flag_pic)
+ if (flag_pic)
{
- warning ("Position independent code not supported. Ignored");
- flag_pic = 0;
+ warning("Position independent code not supported. Ignored");
+ flag_pic = 0;
}
}
@@ -1793,21 +1594,17 @@ thumb_override_options ()
naked: don't output any prologue or epilogue code, the user is assumed
to do the right thing.
-*/
+ */
int
-arm_valid_machine_decl_attribute (decl, attributes, attr, args)
- tree decl;
- tree attributes;
- tree attr;
- tree args;
+arm_valid_machine_decl_attribute(tree decl, tree attributes, tree attr, tree args)
{
- if (args != NULL_TREE)
- return 0;
+ if (args != NULL_TREE)
+ return 0;
- if (is_attribute_p ("naked", attr))
- return TREE_CODE (decl) == FUNCTION_DECL;
-
- return 0;
+ if (is_attribute_p("naked", attr))
+ return TREE_CODE(decl) == FUNCTION_DECL;
+
+ return 0;
}
/* s_register_operand is the same as register_operand, but it doesn't accept
@@ -1819,20 +1616,18 @@ arm_valid_machine_decl_attribute (decl, attributes, attr, args)
reloading. */
int
-s_register_operand (op, mode)
- register rtx op;
- enum machine_mode mode;
+s_register_operand(register rtx op, enum machine_mode mode)
{
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return 0;
-
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
-
- /* We don't consider registers whose class is NO_REGS
- to be a register operand. */
- /* XXX might have to check for lo regs only for thumb ??? */
- return (GET_CODE (op) == REG
- && (REGNO (op) >= FIRST_PSEUDO_REGISTER
- || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
+ if (GET_MODE(op) != mode && mode != VOIDmode)
+ return 0;
+
+ if (GET_CODE(op) == SUBREG)
+ op = SUBREG_REG(op);
+
+ /* We don't consider registers whose class is NO_REGS
+ to be a register operand. */
+ /* XXX might have to check for lo regs only for thumb ??? */
+ return (GET_CODE(op) == REG
+ && (REGNO(op) >= FIRST_PSEUDO_REGISTER
+ || REGNO_REG_CLASS(REGNO(op)) != NO_REGS));
}