diff options
author | YamaArashi <shadow962@live.com> | 2016-02-14 14:49:17 -0800 |
---|---|---|
committer | YamaArashi <shadow962@live.com> | 2016-02-14 14:49:17 -0800 |
commit | 085546bf61bf974a9fcb5c6d581a2e6bb85c3202 (patch) | |
tree | b4988265c7eae0a445855d5b59354c793b140a59 /gcc | |
parent | d28ac43428269276aca46f62d4822be5b5a5c343 (diff) |
clean up thumb.c more
Diffstat (limited to 'gcc')
-rwxr-xr-x | gcc/config/arm/thumb.c | 2569 |
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)); } |