From cffb2a26c44c682185b6bb405d48fcbe1fbc0b37 Mon Sep 17 00:00:00 2001 From: rearnsha Date: Sat, 8 Apr 2000 14:29:53 +0000 Subject: [PATCH] Merge changes from merged-arm-thumb-backend-branch onto trunk. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@33028 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 397 +++ gcc/config/arm/aout.h | 67 +- gcc/config/arm/arm-protos.h | 356 +-- gcc/config/arm/arm.c | 3476 +++++++++++++++++++--- gcc/config/arm/arm.h | 1543 ++++++---- gcc/config/arm/arm.md | 4304 +++++++++++++++++++--------- gcc/config/arm/coff.h | 82 +- gcc/config/arm/elf.h | 88 +- gcc/config/arm/lib1funcs.asm | 595 +++- gcc/config/arm/lib1thumb.asm | 749 ----- gcc/config/arm/linux-elf.h | 17 +- gcc/config/arm/linux-telf.h | 202 -- gcc/config/arm/linux-tgas.h | 84 - gcc/config/arm/netbsd.h | 6 +- gcc/config/arm/pe.c | 143 +- gcc/config/arm/pe.h | 55 +- gcc/config/arm/semi.h | 23 +- gcc/config/arm/strongarm-coff.h | 31 + gcc/config/arm/strongarm-elf.h | 31 + gcc/config/arm/{t-pe-thumb => t-arm-aout} | 18 +- gcc/config/arm/{t-thumb-elf => t-arm-coff} | 17 +- gcc/config/arm/t-arm-elf | 17 +- gcc/config/arm/t-bare | 32 - gcc/config/arm/t-netbsd | 2 + gcc/config/arm/t-pe | 5 +- gcc/config/arm/t-semiaof | 1 + gcc/config/arm/t-thumb | 32 - gcc/config/arm/t-thumb-linux | 42 - gcc/config/arm/tcoff.h | 187 -- gcc/config/arm/telf.h | 469 --- gcc/config/arm/thumb.c | 2426 ---------------- gcc/config/arm/thumb.h | 1305 --------- gcc/config/arm/tpe.h | 425 --- gcc/config/arm/uclinux-telf.h | 40 - gcc/config/arm/unknown-elf.h | 77 +- gcc/config/arm/xm-thumb.h | 1 - gcc/configure | 63 +- gcc/configure.in | 71 +- 38 files changed, 8506 insertions(+), 8973 deletions(-) rewrite gcc/config/arm/arm-protos.h (80%) delete mode 100644 gcc/config/arm/lib1thumb.asm delete mode 100644 gcc/config/arm/linux-telf.h delete mode 100644 gcc/config/arm/linux-tgas.h create mode 100644 gcc/config/arm/strongarm-coff.h create mode 100644 gcc/config/arm/strongarm-elf.h rename gcc/config/arm/{t-pe-thumb => t-arm-aout} (64%) rename gcc/config/arm/{t-thumb-elf => t-arm-coff} (56%) delete mode 100644 gcc/config/arm/t-bare delete mode 100644 gcc/config/arm/t-thumb delete mode 100644 gcc/config/arm/t-thumb-linux delete mode 100644 gcc/config/arm/tcoff.h delete mode 100644 gcc/config/arm/telf.h delete mode 100644 gcc/config/arm/thumb.c delete mode 100644 gcc/config/arm/thumb.h delete mode 100644 gcc/config/arm/tpe.h delete mode 100644 gcc/config/arm/uclinux-telf.h delete mode 100644 gcc/config/arm/xm-thumb.h diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 47fccd140bf..4bf2d76ed19 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,400 @@ +2000-04-08 Richard Earnshaw (rearnsha@arm.com) + + Merge changes from merged-arm-thumb-backend-branch onto trunk. + + 2000-04-08 Richard Earnshaw (rearnsha@arm.com) + + * Merge trunk code from tag merged-arm-thumb-backend-merge_20000408 + into branch. + + * arm.md (nop): Use the standard RTL expression. Don't code as a + define_expand. + (*arm_nop, *thumb_nop): Delete. + + * arm.c (const_ok_for_arm): Don't use ANSI extensions for defining + constants. Use casts instead. + (arm_gen_constant, arm_rtx_costs, arm_reload_in_hi, arm_reload_out_hi, + output_multi_immediate, arm_poke_function_name): Likewise. + * arm.h (ARM_LEGITIIMIZE_RELOAD_ADDRESS, ARM_SIGN_EXTEND, + MASK_RETURN_ADDDR): Likewise. + + 2000-03-31 Richard Earnshaw (rearnsha@arm.com) + + * Merge trunk code from tag merged-arm-thumb-backend-merge_20000325 + into branch. + + * arm.md (eh_epilogue): New function. + * arm.h (struct machine_function): Move to here ... + * arm.c: ... from here. + (arm_output_epilogue): Support epilogues for __builtin_eh_return. + (thumb_exit): Extra parameter eh_ofs. All callers changed. + Handle epilogues for __builtin_eh_return. Make bit-fields unsigned. + + 2000-03-30 Nick Clifton + + * config/arm/semi.h (ASM_SPEC): Restore definition. + (SUBTARGET_EXTRA_ASM_SPEC): Define if not already defined. + + * config/arm/elf.h (ASM_SPEC): Restore definition. + (SUBTARGET_EXTRA_ASM_SPEC): Define if not already defined. + + * config/arm/arm.h (ASM_SPEC): Remove definition. + (SUBTARGET_EXTRA_ASM_SPEC): Remove definition. + + 2000-03-26 Bernd Schmidt + + * config/arm/arm.c: Disable -fschedule-insns for Thumb. + + 2000-03-24 Nick Clifton + + Various formating tidyups, elimination of compile time + warnings and synchronisation with internal sources: + + * config/arm/arm-protos.h (assemble_align): Add prototype. + (gen_rotated_half_load): Rename to arm_gen_rotated_half_load. + (gen_comapre_reg): Rename to arm_gen_compare_reg. + (arm_return_addr_rtx): Rename to arm_return_addr. + + * config/arm/arm.c: Include except.h. + Define shorter typenames for strict minipool_node and struct + minipool_fix. + (arm_return_in_memory): For WinCE return all structures <= 32 bits + in memory. + (gen_rotated_half_load): Rename to arm_gen_rotated_half_load. + (gen_comapre_reg): Rename to arm_gen_compare_reg. + + * config/arm/arm.h (SUBTARGET_EXTRA_ASM_SPEC): Define if not + already defined. + (ASM_SPEC): Define if not already defined. + (ASM_OUTPUT_DEF_FROM_DECLS): Define. + + * config/arm/arm.md: Rename references to gen_rotated_half_load to + arm_gen_rotated_half_load, and references to gen_comapre_reg to + arm_gen_compare_reg. + (indirect_jump): Only accept register operands. + (load_indirect_jump): Keep this pattern since combine can generate + it. + + * config/arm/coff.h: Include aout.h. + (MULTILIB_DEFAULTS): Only define if not already defined. + + * config/arm/elf.h (ASM_OUTPUT_DEF_FROM_DECLS): Move definition + into arm.h (so that COFF ports can support thumb based aliases). + (ASM_SPEC): Move definition into arm.h + + * config/arm/linux-elf.h (SUBTARGET_EXTRA_ASM_SPEC): Remove + redundant apcs spec. + (ASM_SPEC): Move definition to arm.h + + * config/arm/semi.h (ASM_SPEC): Move definition to arm.h + + * config/arm/unknown-elf.h (ASM_OUTPUT_SECTION_NAME): Add support + for entries in the .bss section + + 2000-03-23 Nick Clifton + + * config/arm/arm.h (THUMB_INITIAL_ELIMINATION_OFFSET): Pass 0 + to thumb_far_jump_used_p. + + * config/arm/arm-protos.h (thumb_far_jump_used_p): Take a + single integer parameter. + + * config/arm/arm.c (struct machine_function): Add two new + fields, 'far_jump_used' and 'arg_pointer_live'. + (thumb_far_jump_used_p): Once the decision has been made that + far jumps might be used, always return true. + If being called from the initial elimination offset macro then + do not bother to perform the test if the arg pointer is not + being used. + (thumb_unexpand_epilogue): Pass 1 to thumb_far_jump_used_p(). + (output_thumb_prologue): Pass 1 to thumb_far_jump_used_p(). + + 2000-03-23 Richard Earnshaw (rearnsha@arm.com) + + * arm.c (output_return_instruction): Handle more cases where we can + return from a function with an ldr instruction. + (arm_output_epilogue): Likewise. + + * arm.c (thumb_expand_prologue): Don't clobber the frame pointer + if we need to push a large stack frame and there are no callee-saved + registers. + + * arm.c (arm_debugger_arg_offset): An offset of 0 is also valid + in ARM code if the frame pointer has been eliminated. + + * arm.md (epilogue, *epilogue_insns, consttable_*, align_4): Renumber + unspec_volatile arguments to avoid duplicates. + (consttable_1, consttable_2): Fixes for big-endian mode. + + * arm.md (all ARM-mode load insns): Add neg_pool_range attribute + as appropriate. + + Re-write constant pool code. + * arm.c (minipool_node, minipool_fix): New types. + (minifix): Delete type. + (arm_add_minipool_constant): Delete. + (arm_compute_minipool_offsets, arm_find_barrier, + arm_find_minipool_constant, fixup_compare, sort_fixups): Likewise. + (get_jump_table_size): Now returns HOST_WIDE_INT. + (move_minipool_fix_forward_ref, add_minipool_forward_ref): New + functions. + (move_minipool_fix_backward_ref, add_minipool_backward_ref): Likewise. + (assign_minipool_offsets, arm_print_value): Likewise. + (dump_minipool): Rewrite. + (arm_barrier_cost): New function. + (create_fix_barrier): New function. + (push_minipool_barrier): New function. + (push_minipool_fix): Record additional information about the fixup + required. + (note_invalid_constants): Remove push for (UNSPEC 3). Don't + check the mode of what needs fixing. + (arm_reorg): Rewrite. + + 2000-03-08 Nick Clifton + + * config/arm/arm.md (indirect_jump): Force constant addresses into + a register. + + 2000-03-01 Bernd Schmidt + + * config/arm/arm.md: Add splitter to turn SF moves into SI moves. + + 2000-02-24 Nick Clifton + + * config/arm/arm.c (thumb_expand_prologue): Make sure that stack + adjust is word aligned. + (thumb_expand_epilogue): Make sure that stack adjust is word + aligned. + + * config/arm/elf.h (ASM_FILE_START): Fix type of version string. + + 2000-02-24 Bernd Schmidt + + * config/arm/arm.h (THUMB_GO_IF_LEGITIMATE_ADDRESS): Allow frame + pointer relative addresses. + + 2000-02-10 Richard Earnshaw + + * arm.c (find_barrier): Find the last barrier within the allowed + range. + + 2000-02-09 Nick Clifton + + * config/arm/arm-protos.h: Replace PROTO with PARAMS. + + 2000-02-09 Nick Clifton + + * config/arm/linux-elf.h (FUNCTION_PROFILER): Rename to + ARM_FUNCTION_PROFILER. + + * config/arm/netbsd.h (FUNCTION_PROFILER): Rename to + ARM_FUNCTION_PROFILER. + + * config/arm/linux-oldld.h: Imported from mainline sources. + + 2000-02-07 Nick Clifton + + * config/arm/lib1funcs.asm: Merge in thumb functions from + lib1thumb.asm. + + * config/arm/lib1thumb.asm: Delete. + + 2000-02-04 Nick Clifton + + * config/arm/arm.c: Sychronised with current Red hat local + sources. + * config/arm/arm.h: Ditto. + * config/arm/arm-protos.h: Ditto. + + 2000-02-02 Bernd Schmidt + + * arm.c (soft_df_operand): Reject SUBREGs containing a constant. + + * arm.c (arm_gen_movstrqi): Generate halfword stores rather than two + byte stores. + + 2000-02-02 Nick Clifton + + * config/arm/thumb.c (thumb_exit): Additional fix for same bug. + + * config/arm/arm.md (epilogue): Fix rtl checking abort because + (return) was emited using an emit_insn() call. + + 2000-01-31 Nick Clifton + + * config/arm/arm.c (output_thumb_prologue): Fix bug generating + thumb stack frame. + (thumb_exit): Move frame pointer back into hard frame pointer + register if backtracing is being used. + + 2000-01-13 Richard Earnshaw (rearnsha@arm.com) + + * Merge trunk code from tag merged-arm-thumb-backend-merge_20000113 + into branch. + + 1999-12-15 Bernd Schmidt + + * config/arm/arm.md (neg_pool_offset): Provide default for new + attribute. + (arm_movsi_insn): Add neg_pool_offset attribute. + * config/arm/arm.c (arm_find_barrier): Replace arg FIX with an + rtx for the insn that starts the scan and an unsigned long for its + address. Add MIN_OFFSET and PINSERTED args. All callers changed. + Change scan to ignore insns before MIN_OFFSET. Store size of inserted + instructions in *PINSERTED. + (struct minipool_fixup): Add MIN_ADDRESS elt. + (sort_fixups): Compute it. + (arm_reorg): Changes to support inserting pools before the insn to be + fixed up. + + 1999-12-08 Bernd Schmidt + + * config/arm/elf.h (MULTILIB_DEFAULTS): Add "marm". + * config/arm/linux-elf.h (MULTILIB_DEFAULTS): Add "marm". + * config/arm/coff.h (MULTILIB_DEFAULTS): Add "marm". + + Wed Nov 3 10:04:07 1999 Nick Clifton + + * config/arm/semi.h (TARGET_VERSION): Do not define if already + defined. + (TARGET_DEFAULT): Do not define if already defined. + + Tue Nov 2 10:37:25 1999 Nick Clifton + + * config/arm/arm.md (anddi3): Allow disjoint source operands. + (iordi3): Allow disjoint source operands. + (xordi3): Allow disjoint source operands. + (negdi2): Permit construction for ARM and Thumb. + (arm_negdi2): Renamed version of old negdi2 pattern. + (thumb_negdi2): New pattern: Only permit non-overlapping + source and destination. + + Fri Oct 29 18:52:38 1999 Nick Clifton + + * config/arm/arm.c (thumb_expand_prologue): Emit a USE of the + scratch low register so that it will not be deleted. + + Fri Oct 29 15:23:48 1999 Nick Clifton + + * config/arm/pe.h (ARM_PE): Define. + + * config/arm/arm.c (arm_valid_machine_decl_attribute): Allow + interfacearm attribute if this is a PE toolchain. + (output_return_instruction): Do not emit anything if the function + has the naked attribute set. + (is_called_in_ARM_mode): If the function has the interfacearm + attribute then return true. + (thumb_expand_prologue): Do not generate a prologue for naked + functions. + (thumb_expand_epilogue): Do not generate an epilogie for a naked + function. + (output_thumb_prologue): Do not bother if the function is naked. + Strip PE encoding from function name before emitting. + + Thu Oct 28 11:05:13 1999 Richard Earnshaw + + * arm.md (pic_load_addr): Fix constraints. + + * arm.md (casesi_insn): Fix mis-applied patch. + + * arm.md ("core" function unit): Add rules for single- and + multi-cycle insns. + (All TARGET_THUMB patterns): Add "type" attribute information + where needed. + * arm.c (arm_adjust_cost): Reduce the cost of a data dependency if + the following insn is a CALL. + + * arm.c (thumb_expand_epilogue): Add a use of the adjusted stack + pointer. + * arm.h (CONDITIONAL_REGISTER_USAGE): Nail down the + ARM_HARD_FRAME_POINTER_REGNUM when TARGET_APCS_FRAME. + (FRAME_POINTER_REQUIRED): Only check TARGET_APCS_FRAME if TARGET_ARM. + + Wed Oct 27 14:40:48 1999 Nick Clifton + + * config/arm/linux-gas.h: oops - this file was missed out when the + branch was created... + + Tue Oct 26 17:07:38 1999 Richard Earnshaw + + * thumb.c: Deleted. Move contents to ... + * arm.c: ... here. + * t-arm-aout, t-arm-coff, t-arm-elf, t-linux, t-netbsd, t-semi: Remove + rule for thumb.o + * configure.in (arm*-*-*): Remove thumb.o from extra_objs list. + * configure: Regen. + + * arm-protos.h: Use RTX_CODE and tidy up long lines. Don't + declare a prototype for asm_output_align(); + + * arm.c (thumb_condition_code): Delete. + (arm_print_operand): Always use arm_condition_code array. + + * arm.c (thumb_return_addr_rtx): Delete. + (arm_save_machine_status, arm_restore_machine_status): Delete. + (arm_init_machine_status, arm_mark_machine_status): New functions. + (arm_init_expanders): Update accordingly. + (arm_return_addr): Renamed from arm_return_addr_rtx. Rewrite. + (thumb_expand_prologue): Delete code referencing thumb_return_addr_rtx. + * arm.h (RETURN_ADDR_RTX): Call arm_return_addr(). + + Tue Oct 26 13:24:16 1999 Nick Clifton + + * configure.in : Fix arm-*-aout target to use new t-arm-aout + script. + * config/arm/t-arm-aout: New file: Makefile script for arm-*-aout + targets. + + Tue Oct 26 11:27:12 1999 Nick Clifton + + * config/arm/thumb.c (output_thumb_prologue): Fix bug creating + stack backtrace structure. + + * config/arm/arm-protos.h: Add prototypes for functions defined in + arm/pe.h. + + * config/arm/arm.c (arm_override_options): Fix selection of + attributes of default processor. + + * config/arm/coff.h: Delete needless #include. + + * config/arm/pe.c: Delete unused code. + + * config/arm/pe.h (CPP_DEFINES): Delete + (SUBTARGET_CPP_SPEC): Define. + (ASM_DECLARE_FUNCTION_NAME): Use ARM_DECLARE_FUNCTION_NAME. + + * config/arm/t-pe: Add -DInhibit_libc to allof libgcc.a to build. + + Mon Oct 25 15:42:09 1999 Richard Earnshaw (rearnsha@arm.com) + + * arm.h (TARGET_APCS_FRAME): Renamed from TARGET_APCS -- all uses + updated. + (CAN_DEBUG_WITHOUT_FP): Define. + (FIXED_REGISTERS): Make r11 call-saved. + (CALL_USED_REGISTERS): Likewise. + (CONDITIONAL_REGISTER_USAGE): Fix r11 if TARGET_APCS_FRAME. + (FRAME_POINTER_REQUIRED): Correct logic for determining when a + frame-pointer is required. + (TARGET_DEFAULT): Make default setting include ARM_FLAG_APCS_FRAME. + * arm.c (arm_override_options): Warn about -mno-apcs-frame and -g + if the target normally needs a stack frame in non-leaf functions. + (use_return_insn): Correct logic for determining when a return + instruction can be used. + (output_return_instruction): Handle the frame-pointer register as + a normal register when not TARGET_APCS_FRAME. + (arm_output_prologue): Likewise. + (arm_output_epilogue): Likewise. + (output_func_epilogue): Likewise. + (arm_expand_prologue): Likewise. + * netbsd.h semi.h (TARGET_DEFAULT): Add ARM_FLAG_APCS_FRAME. + + * arm.c (use_return_insn): No need to check floating point regs if + TARGET_SOFT_FLOAT. + (arm_find_minipool_constant): Correct typo; use GET_CODE to get + the code of value stored in the minipool array. + (arm_add_minipool_constant): Likewise. + 2000-04-08 Kaveh R. Ghazi * basic-block.h (conflict_graph_enum_fn): K&R fix. diff --git a/gcc/config/arm/aout.h b/gcc/config/arm/aout.h index 850a681e0ff..9dc1a041b2c 100644 --- a/gcc/config/arm/aout.h +++ b/gcc/config/arm/aout.h @@ -1,5 +1,5 @@ /* Definitions of target machine for GNU compiler, for ARM with a.out - Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1995 - 1999 Free Software Foundation, Inc. Contributed by Richard Earnshaw (rearnsha@armltd.co.uk). This file is part of GNU CC. @@ -25,20 +25,24 @@ Boston, MA 02111-1307, USA. */ /* The text to go at the start of the assembler file */ #ifndef ASM_FILE_START -#define ASM_FILE_START(STREAM) \ -{ \ - fprintf (STREAM,"%srfp\t.req\t%sr9\n", REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf (STREAM,"%ssl\t.req\t%sr10\n", REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf (STREAM,"%sfp\t.req\t%sr11\n", REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf (STREAM,"%sip\t.req\t%sr12\n", REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf (STREAM,"%ssp\t.req\t%sr13\n", REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf (STREAM,"%slr\t.req\t%sr14\n", REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf (STREAM,"%spc\t.req\t%sr15\n", REGISTER_PREFIX, REGISTER_PREFIX); \ +#define ASM_FILE_START(STREAM) \ +{ \ + asm_fprintf (STREAM,"%Rrfp\t.req\t%Rr9\n"); \ + asm_fprintf (STREAM,"%Rsl\t.req\t%Rr10\n"); \ + asm_fprintf (STREAM,"%Rfp\t.req\t%Rr11\n"); \ + asm_fprintf (STREAM,"%Rip\t.req\t%Rr12\n"); \ + asm_fprintf (STREAM,"%Rsp\t.req\t%Rr13\n"); \ + asm_fprintf (STREAM,"%Rlr\t.req\t%Rr14\n"); \ + asm_fprintf (STREAM,"%Rpc\t.req\t%Rr15\n"); \ } #endif -#define ASM_APP_ON " " -#define ASM_APP_OFF " " +#ifndef ASM_APP_ON +#define ASM_APP_ON "" +#endif +#ifndef ASM_APP_OFF +#define ASM_APP_OFF "" +#endif /* Switch to the text or data segment. */ #define TEXT_SECTION_ASM_OP ".text" @@ -68,7 +72,7 @@ Boston, MA 02111-1307, USA. */ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", \ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ - "cc", "sfp", "afp" \ + "cc", "sfp", "afp" \ } #endif @@ -185,16 +189,17 @@ Boston, MA 02111-1307, USA. */ the riscix assembler doesn't understand (it also makes cross-assembling less likely to fail). */ -#define ASM_OUTPUT_LONG_DOUBLE(STREAM, VALUE) \ - do \ - { \ - char dstr[30]; \ - long l[3]; \ - REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ - fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n", \ - l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ - } \ +#define ASM_OUTPUT_LONG_DOUBLE(STREAM, VALUE) \ + do \ + { \ + char dstr[30]; \ + long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + asm_fprintf (STREAM, \ + "\t.long 0x%lx,0x%lx,0x%lx\t%@ long double %s\n", \ + l[0], l[1], l[2], dstr); \ + } \ while (0) #define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ @@ -204,8 +209,8 @@ Boston, MA 02111-1307, USA. */ long l[2]; \ REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ - fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ - l[1], ASM_COMMENT_START, dstr); \ + asm_fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%@ double %s\n", l[0],\ + l[1], dstr); \ } \ while (0) @@ -216,8 +221,8 @@ Boston, MA 02111-1307, USA. */ long l; \ REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ - fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ - ASM_COMMENT_START, dstr); \ + asm_fprintf (STREAM, "\t.word 0x%lx\t%@ float %s\n", l, \ + dstr); \ } \ while (0) @@ -280,8 +285,8 @@ Boston, MA 02111-1307, USA. */ { \ fprintf (STREAM, "\t.comm\t"); \ assemble_name (STREAM, NAME); \ - fprintf (STREAM, ", %d\t%s %d\n", ROUNDED, \ - ASM_COMMENT_START, SIZE); \ + asm_fprintf (STREAM, ", %d\t%@ %d\n", \ + ROUNDED, SIZE); \ } \ while (0) #endif @@ -314,7 +319,7 @@ Boston, MA 02111-1307, USA. */ /* Output a #ident directive. */ #ifndef ASM_OUTPUT_IDENT #define ASM_OUTPUT_IDENT(STREAM,STRING) \ - fprintf (STREAM, "%s - - - ident %s\n", ASM_COMMENT_START, STRING) + asm_fprintf (STREAM, "%@ - - - ident %s\n", STRING) #endif /* The assembler's parentheses characters. */ @@ -328,4 +333,4 @@ Boston, MA 02111-1307, USA. */ /* This works for GAS and some other assemblers. */ #define SET_ASM_OP ".set" -#include "arm/arm.h" +#include "arm.h" diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h dissimilarity index 80% index 141400354c0..5b021248b39 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -1,161 +1,195 @@ -/* Prototypes for exported functions defined in arm.c and pe.c - Copyright (C) 1999, 2000 Free Software Foundation, Inc. - Contributed by Richard Earnshaw (rearnsha@arm.com) - Minor hacks by Nick Clifton (nickc@cygnus.com) - -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 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. */ - -extern void arm_expand_prologue PARAMS ((void)); -extern void arm_finalize_pic PARAMS ((void)); -extern char * arm_output_epilogue PARAMS ((void)); -extern void arm_override_options PARAMS ((void)); -extern void arm_poke_function_name PARAMS ((FILE *, char *)); -extern int arm_process_pragma PARAMS ((int (*)(void), void (*) (int), char *)); -extern int arm_regno_class PARAMS ((int)); -extern int arm_volatile_func PARAMS ((void)); -extern int const_ok_for_arm PARAMS ((HOST_WIDE_INT)); -extern void output_arm_prologue PARAMS ((FILE *, int)); -extern void output_ascii_pseudo_op PARAMS ((FILE *, const unsigned char *, int)); -extern void output_func_epilogue PARAMS ((int)); -extern void output_func_prologue PARAMS ((FILE *, int)); -extern int use_return_insn PARAMS ((int)); -extern const char * arm_strip_name_encoding PARAMS ((const char *)); -#if defined AOF_ASSEMBLER -extern void aof_add_import PARAMS ((char *)); -extern char * aof_data_section PARAMS ((void)); -extern void aof_delete_import PARAMS ((char *)); -extern void aof_dump_imports PARAMS ((FILE *)); -extern void aof_dump_pic_table PARAMS ((FILE *)); -extern char * aof_text_section PARAMS ((void)); -#endif /* AOF_ASSEMBLER */ -/* Defined in pe.c */ -extern int arm_dllexport_name_p PARAMS ((const char *)); -extern int arm_dllimport_name_p PARAMS ((const char *)); - -#define Mmode enum machine_mode - -#ifdef TREE_CODE -extern int arm_comp_type_attributes PARAMS ((tree, tree)); -extern int arm_return_in_memory PARAMS ((tree)); -extern int arm_valid_machine_decl_attribute PARAMS ((tree, tree, tree)); -extern int arm_valid_type_attribute_p PARAMS ((tree, tree, tree, tree)); -/* Defined in pe.c */ -extern int arm_dllexport_p PARAMS ((tree)); -extern int arm_dllimport_p PARAMS ((tree)); -extern void arm_mark_dllexport PARAMS ((tree)); -extern void arm_mark_dllimport PARAMS ((tree)); -extern void arm_pe_encode_section_info PARAMS ((tree)); -extern tree arm_pe_merge_machine_decl_attributes PARAMS ((tree, tree)); -extern void arm_pe_unique_section PARAMS ((tree, int)); -extern int arm_pe_valid_machine_decl_attribute PARAMS ((tree, tree, tree, tree)); -extern void arm_set_default_type_attributes PARAMS ((tree)); -extern void arm_encode_call_attribute PARAMS ((tree, char)); -extern int arm_pe_return_in_memory PARAMS ((tree)); -#endif - -#ifdef RTX_CODE -extern int adjacent_mem_locations PARAMS ((rtx, rtx)); -extern char * arithmetic_instr PARAMS ((rtx, int)); -extern int arm_adjust_cost PARAMS ((rtx, rtx, rtx, int)); -extern RTX_CODE arm_canonicalize_comparison PARAMS ((RTX_CODE, rtx *)); -extern int arm_debugger_arg_offset PARAMS ((int, rtx)); -extern void arm_final_prescan_insn PARAMS ((rtx)); -extern rtx arm_gen_load_multiple PARAMS ((int, int, rtx, int, int, int, int, int)); -extern int arm_gen_movstrqi PARAMS ((rtx *)); -extern rtx arm_gen_store_multiple PARAMS ((int, int, rtx, int, int, int, int, int)); -extern void arm_print_operand PARAMS ((FILE *, rtx, int)); -extern void arm_reload_in_hi PARAMS ((rtx *)); -extern void arm_reload_out_hi PARAMS ((rtx *)); -extern void arm_reorg PARAMS ((rtx)); -extern int arm_rtx_costs PARAMS ((rtx, RTX_CODE)); -extern Mmode arm_select_cc_mode PARAMS ((RTX_CODE, rtx, rtx)); -extern int const_double_rtx_ok_for_fpu PARAMS ((rtx)); -extern int const_ok_for_arm PARAMS ((HOST_WIDE_INT)); -extern char * emit_ldm_seq PARAMS ((rtx *, int)); -extern char * emit_stm_seq PARAMS ((rtx *, int)); -extern char * fp_immediate_constant PARAMS ((rtx)); -extern rtx gen_compare_reg PARAMS ((RTX_CODE, rtx, rtx)); -extern rtx gen_rotated_half_load PARAMS ((rtx)); -extern int is_pic PARAMS ((rtx)); -extern int label_mentioned_p PARAMS ((rtx)); -extern int legitimate_pic_operand_p PARAMS ((rtx)); -extern int load_multiple_sequence PARAMS ((rtx *, int, int *, int *, HOST_WIDE_INT *)); -extern RTX_CODE minmax_code PARAMS ((rtx)); -extern int neg_const_double_rtx_ok_for_fpu PARAMS ((rtx)); -extern char * output_add_immediate PARAMS ((rtx *)); -extern char * output_call PARAMS ((rtx *)); -extern char * output_call_mem PARAMS ((rtx *)); -extern char * output_mov_double_arm_from_fpu PARAMS ((rtx *)); -extern char * output_mov_double_fpu_from_arm PARAMS ((rtx *)); -extern char * output_mov_immediate PARAMS ((rtx *)); -extern char * output_mov_long_double_arm_from_arm PARAMS ((rtx *)); -extern char * output_mov_long_double_arm_from_fpu PARAMS ((rtx *)); -extern char * output_mov_long_double_fpu_from_arm PARAMS ((rtx *)); -extern char * output_move_double PARAMS ((rtx *)); -extern char * output_return_instruction PARAMS ((rtx, int, int)); -extern int store_multiple_sequence PARAMS ((rtx *, int, int *, int *, HOST_WIDE_INT *)); -extern int symbol_mentioned_p PARAMS ((rtx)); -extern int arm_is_longcall_p PARAMS ((rtx, int, int)); -#if defined AOF_ASSEMBLER -extern rtx aof_pic_entry PARAMS ((rtx)); -#endif /* AOF_ASSEMBLER */ - -#ifdef HAVE_MACHINE_MODES -extern int alignable_memory_operand PARAMS ((rtx, Mmode)); -extern int arm_add_operand PARAMS ((rtx, Mmode)); -extern int arm_go_if_legitimate_address PARAMS ((Mmode, rtx)); -extern int arm_not_operand PARAMS ((rtx, Mmode)); -extern int arm_reload_memory_operand PARAMS ((rtx, Mmode)); -extern int arm_rhs_operand PARAMS ((rtx, Mmode)); -extern int arm_rhsm_operand PARAMS ((rtx, Mmode)); -extern Mmode arm_select_cc_mode PARAMS ((RTX_CODE, rtx, rtx)); -extern int arm_split_constant PARAMS ((RTX_CODE, Mmode, HOST_WIDE_INT, rtx, rtx, int)); -extern int bad_signed_byte_operand PARAMS ((rtx, Mmode)); -extern int cc_register PARAMS ((rtx, Mmode)); -extern int const_shift_operand PARAMS ((rtx, Mmode)); -extern int di_operand PARAMS ((rtx, Mmode)); -extern int dominant_cc_register PARAMS ((rtx, Mmode)); -extern int equality_operator PARAMS ((rtx, Mmode)); -extern int f_register_operand PARAMS ((rtx, Mmode)); -extern int fpu_add_operand PARAMS ((rtx, Mmode)); -extern int fpu_rhs_operand PARAMS ((rtx, Mmode)); -extern int index_operand PARAMS ((rtx, Mmode)); -extern rtx legitimize_pic_address PARAMS ((rtx, Mmode, rtx)); -extern int load_multiple_operation PARAMS ((rtx, Mmode)); -extern int logical_binary_operator PARAMS ((rtx, Mmode)); -extern int minmax_operator PARAMS ((rtx, Mmode)); -extern int multi_register_push PARAMS ((rtx, Mmode)); -extern int nonimmediate_di_operand PARAMS ((rtx, Mmode)); -extern int nonimmediate_soft_df_operand PARAMS ((rtx, Mmode)); -extern int offsettable_memory_operand PARAMS ((rtx, Mmode)); -extern int power_of_two_operand PARAMS ((rtx, Mmode)); -extern int reg_or_int_operand PARAMS ((rtx, Mmode)); -extern int s_register_operand PARAMS ((rtx, Mmode)); -extern int shift_operator PARAMS ((rtx, Mmode)); -extern int shiftable_operator PARAMS ((rtx, Mmode)); -extern int soft_df_operand PARAMS ((rtx, Mmode)); -extern int store_multiple_operation PARAMS ((rtx, Mmode)); - -#if defined TREE_CODE -extern rtx arm_function_arg PARAMS ((CUMULATIVE_ARGS *, Mmode, tree, int)); -extern void arm_init_cumulative_args PARAMS ((CUMULATIVE_ARGS *, tree, rtx, int)); -#endif /* TREE_CODE */ -#endif /* HAVE_MACHINE_MODES */ -#endif /* RTX_CODE */ - -#undef Mmode +/* Prototypes for exported functions defined in arm.c and pe.c + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + Contributed by Richard Earnshaw (rearnsha@arm.com) + Minor hacks by Nick Clifton (nickc@cygnus.com) + +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 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. */ + +extern void arm_override_options PARAMS ((void)); +extern int use_return_insn PARAMS ((int)); +extern int arm_regno_class PARAMS ((int)); +extern int arm_process_pragma PARAMS ((int (*)(void), void (*) (int), + char *)); +extern void arm_finalize_pic PARAMS ((void)); +extern int arm_volatile_func PARAMS ((void)); +extern char * arm_output_epilogue PARAMS ((void)); +extern void output_func_epilogue PARAMS ((int)); +extern void arm_expand_prologue PARAMS ((void)); +/* Used in arm.md, but defined in output.c. */ +extern void assemble_align PARAMS ((int)); +extern const char * arm_strip_name_encoding PARAMS ((const char *)); + +#ifdef TREE_CODE +extern int arm_return_in_memory PARAMS ((tree)); +extern int arm_valid_machine_decl_attribute PARAMS ((tree, tree, tree)); +extern int arm_comp_type_attributes PARAMS ((tree, tree)); +extern int arm_valid_type_attribute_p PARAMS ((tree, tree, tree, tree)); +extern void arm_set_default_type_attributes PARAMS ((tree)); +extern void arm_encode_call_attribute PARAMS ((tree, char)); +#endif +#ifdef RTX_CODE +extern int const_ok_for_arm PARAMS ((HOST_WIDE_INT)); +extern int arm_split_constant PARAMS ((RTX_CODE, enum machine_mode, + HOST_WIDE_INT, rtx, rtx, int)); +extern RTX_CODE arm_canonicalize_comparison PARAMS ((RTX_CODE, rtx *)); +extern int legitimate_pic_operand_p PARAMS ((rtx)); +extern rtx legitimize_pic_address PARAMS ((rtx, enum machine_mode, rtx)); +extern int is_pic PARAMS ((rtx)); +extern int arm_rtx_costs PARAMS ((rtx, RTX_CODE, RTX_CODE)); +extern int arm_adjust_cost PARAMS ((rtx, rtx, rtx, int)); +extern int const_double_rtx_ok_for_fpu PARAMS ((rtx)); +extern int neg_const_double_rtx_ok_for_fpu PARAMS ((rtx)); + +/* Predicates. */ +extern int s_register_operand PARAMS ((rtx, enum machine_mode)); +extern int f_register_operand PARAMS ((rtx, enum machine_mode)); +extern int reg_or_int_operand PARAMS ((rtx, enum machine_mode)); +extern int arm_reload_memory_operand PARAMS ((rtx, enum machine_mode)); +extern int arm_rhs_operand PARAMS ((rtx, enum machine_mode)); +extern int arm_rhsm_operand PARAMS ((rtx, enum machine_mode)); +extern int arm_add_operand PARAMS ((rtx, enum machine_mode)); +extern int arm_not_operand PARAMS ((rtx, enum machine_mode)); +extern int offsettable_memory_operand PARAMS ((rtx, enum machine_mode)); +extern int alignable_memory_operand PARAMS ((rtx, enum machine_mode)); +extern int bad_signed_byte_operand PARAMS ((rtx, enum machine_mode)); +extern int fpu_rhs_operand PARAMS ((rtx, enum machine_mode)); +extern int fpu_add_operand PARAMS ((rtx, enum machine_mode)); +extern int power_of_two_operand PARAMS ((rtx, enum machine_mode)); +extern int nonimmediate_di_operand PARAMS ((rtx, enum machine_mode)); +extern int di_operand PARAMS ((rtx, enum machine_mode)); +extern int nonimmediate_soft_df_operand PARAMS ((rtx, enum machine_mode)); +extern int soft_df_operand PARAMS ((rtx, enum machine_mode)); +extern int index_operand PARAMS ((rtx, enum machine_mode)); +extern int const_shift_operand PARAMS ((rtx, enum machine_mode)); +extern int shiftable_operator PARAMS ((rtx, enum machine_mode)); +extern int shift_operator PARAMS ((rtx, enum machine_mode)); +extern int equality_operator PARAMS ((rtx, enum machine_mode)); +extern int minmax_operator PARAMS ((rtx, enum machine_mode)); +extern int cc_register PARAMS ((rtx, enum machine_mode)); +extern int dominant_cc_register PARAMS ((rtx, enum machine_mode)); +extern int logical_binary_operator PARAMS ((rtx, enum machine_mode)); +extern int multi_register_push PARAMS ((rtx, enum machine_mode)); +extern int load_multiple_operation PARAMS ((rtx, enum machine_mode)); +extern int store_multiple_operation PARAMS ((rtx, enum machine_mode)); + +extern int symbol_mentioned_p PARAMS ((rtx)); +extern int label_mentioned_p PARAMS ((rtx)); +extern RTX_CODE minmax_code PARAMS ((rtx)); +extern int adjacent_mem_locations PARAMS ((rtx, rtx)); +extern int load_multiple_sequence PARAMS ((rtx *, int, int *, int *, + HOST_WIDE_INT *)); +extern char * emit_ldm_seq PARAMS ((rtx *, int)); +extern int store_multiple_sequence PARAMS ((rtx *, int, int *, int *, + HOST_WIDE_INT *)); +extern char * emit_stm_seq PARAMS ((rtx *, int)); +extern rtx arm_gen_load_multiple PARAMS ((int, int, rtx, int, int, int, + int, int)); +extern rtx arm_gen_store_multiple PARAMS ((int, int, rtx, int, int, int, + int, int)); +extern int arm_gen_movstrqi PARAMS ((rtx *)); +extern rtx arm_gen_rotated_half_load PARAMS ((rtx)); +extern enum machine_mode arm_select_cc_mode PARAMS ((RTX_CODE, rtx, rtx)); +extern rtx arm_gen_compare_reg PARAMS ((RTX_CODE, rtx, rtx)); +extern void arm_reload_in_hi PARAMS ((rtx *)); +extern void arm_reload_out_hi PARAMS ((rtx *)); +extern void arm_reorg PARAMS ((rtx)); +extern char * fp_immediate_constant PARAMS ((rtx)); +extern char * output_call PARAMS ((rtx *)); +extern char * output_call_mem PARAMS ((rtx *)); +extern char * output_mov_long_double_fpu_from_arm PARAMS ((rtx *)); +extern char * output_mov_long_double_arm_from_fpu PARAMS ((rtx *)); +extern char * output_mov_long_double_arm_from_arm PARAMS ((rtx *)); +extern char * output_mov_double_fpu_from_arm PARAMS ((rtx *)); +extern char * output_mov_double_arm_from_fpu PARAMS ((rtx *)); +extern char * output_move_double PARAMS ((rtx *)); +extern char * output_mov_immediate PARAMS ((rtx *)); +extern char * output_add_immediate PARAMS ((rtx *)); +extern char * arithmetic_instr PARAMS ((rtx, int)); +extern void output_ascii_pseudo_op PARAMS ((FILE *, const unsigned char *, int)); +extern char * output_return_instruction PARAMS ((rtx, int, int)); +extern void arm_poke_function_name PARAMS ((FILE *, char *)); +extern void output_arm_prologue PARAMS ((FILE *, int)); +extern void arm_print_operand PARAMS ((FILE *, rtx, int)); +extern void arm_final_prescan_insn PARAMS ((rtx)); +extern int arm_go_if_legitimate_address PARAMS ((enum machine_mode, rtx)); +extern int arm_debugger_arg_offset PARAMS ((int, rtx)); +extern int arm_is_longcall_p PARAMS ((rtx, int, int)); + +#if defined TREE_CODE +extern rtx arm_function_arg PARAMS ((CUMULATIVE_ARGS *, + enum machine_mode, tree, int)); +extern void arm_init_cumulative_args PARAMS ((CUMULATIVE_ARGS *, tree, rtx, + int)); +#endif + +#if defined AOF_ASSEMBLER +extern rtx aof_pic_entry PARAMS ((rtx)); +extern void aof_dump_pic_table PARAMS ((FILE *)); +extern char * aof_text_section PARAMS ((void)); +extern char * aof_data_section PARAMS ((void)); +extern void aof_add_import PARAMS ((char *)); +extern void aof_delete_import PARAMS ((char *)); +extern void aof_dump_imports PARAMS ((FILE *)); +#endif /* AOF_ASSEMBLER */ + +#endif /* RTX_CODE */ + +/* Thumb functions. */ +extern void arm_init_expanders PARAMS ((void)); +extern int thumb_far_jump_used_p PARAMS ((int)); +extern char * thumb_unexpanded_epilogue PARAMS ((void)); +extern void thumb_expand_prologue PARAMS ((void)); +extern void thumb_expand_epilogue PARAMS ((void)); +#ifdef TREE_CODE +extern int is_called_in_ARM_mode PARAMS ((tree)); +#endif +#ifdef RTX_CODE +extern int thumb_shiftable_const PARAMS ((unsigned HOST_WIDE_INT)); +extern void thumb_final_prescan_insn PARAMS ((rtx)); +extern char * thumb_load_double_from_address + PARAMS ((rtx *)); +extern void output_thumb_prologue PARAMS ((FILE *)); +extern char * thumb_output_move_mem_multiple + PARAMS ((int, rtx *)); +extern void thumb_expand_movstrqi PARAMS ((rtx *)); +extern int thumb_cmp_operand PARAMS ((rtx, enum machine_mode)); +extern rtx * thumb_legitimize_pic_address + PARAMS ((rtx, enum machine_mode, rtx)); +extern int thumb_go_if_legitimate_address + PARAMS ((enum machine_mode, rtx)); +extern rtx arm_return_addr PARAMS ((int, rtx)); +extern void thumb_reload_out_hi PARAMS ((rtx *)); +extern void thumb_reload_in_hi PARAMS ((rtx *)); +#endif + +/* Defined in pe.c. */ +extern int arm_dllexport_name_p PARAMS ((char *)); +extern int arm_dllimport_name_p PARAMS ((char *)); + +#ifdef TREE_CODE +extern int arm_pe_valid_machine_decl_attribute + PARAMS ((tree, tree, tree, tree)); +extern tree arm_pe_merge_machine_decl_attributes + PARAMS ((tree, tree)); +extern void arm_pe_unique_section PARAMS ((tree, int)); +extern void arm_pe_encode_section_info PARAMS ((tree)); +extern int arm_dllexport_p PARAMS ((tree)); +extern int arm_dllimport_p PARAMS ((tree)); +extern void arm_mark_dllexport PARAMS ((tree)); +extern void arm_mark_dllimport PARAMS ((tree)); +#endif diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 7bf05363b77..3a4acd79846 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -24,6 +24,8 @@ Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" #include "rtl.h" +#include "tree.h" +#include "tm_p.h" #include "regs.h" #include "hard-reg-set.h" #include "real.h" @@ -34,41 +36,69 @@ Boston, MA 02111-1307, USA. */ #include "insn-attr.h" #include "flags.h" #include "reload.h" -#include "tree.h" #include "function.h" #include "expr.h" #include "toplev.h" #include "recog.h" #include "ggc.h" +#include "except.h" #include "tm_p.h" -#ifndef Mmode -#define Mmode enum machine_mode -#endif - -/* Some function declarations. */ -static HOST_WIDE_INT int_log2 PARAMS ((HOST_WIDE_INT)); -static char * output_multi_immediate PARAMS ((rtx *, char *, char *, int, HOST_WIDE_INT)); -static int arm_gen_constant PARAMS ((enum rtx_code, Mmode, HOST_WIDE_INT, rtx, rtx, int, int)); -static int arm_naked_function_p PARAMS ((tree)); -static void init_fpa_table PARAMS ((void)); -static enum machine_mode select_dominance_cc_mode PARAMS ((rtx, rtx, HOST_WIDE_INT)); -static HOST_WIDE_INT add_minipool_constant PARAMS ((rtx, Mmode)); -static void dump_minipool PARAMS ((rtx)); -static rtx find_barrier PARAMS ((rtx, int)); -static void push_minipool_fix PARAMS ((rtx, int, rtx *, Mmode, rtx)); -static void push_minipool_barrier PARAMS ((rtx, int)); -static void note_invalid_constants PARAMS ((rtx, int)); -static char * fp_const_from_val PARAMS ((REAL_VALUE_TYPE *)); -static int eliminate_lr2ip PARAMS ((rtx *)); -static char * shift_op PARAMS ((rtx, HOST_WIDE_INT *)); -static int pattern_really_clobbers_lr PARAMS ((rtx)); -static int function_really_clobbers_lr PARAMS ((rtx)); -static rtx emit_multi_reg_push PARAMS ((int)); -static rtx emit_sfm PARAMS ((int, int)); -static enum arm_cond_code get_arm_condition_code PARAMS ((rtx)); -static int const_ok_for_op PARAMS ((HOST_WIDE_INT, enum rtx_code)); -static void arm_add_gc_roots PARAMS ((void)); +/* Forward definitions of types. */ +typedef struct minipool_node Mnode; +typedef struct minipool_fixup Mfix; + +/* In order to improve the layout of the prototypes below + some short type abbreviations are defined here. */ +#define Hint HOST_WIDE_INT +#define Mmode enum machine_mode +#define Ulong unsigned long + +/* Forward function declarations. */ +static void arm_add_gc_roots PARAMS ((void)); +static int arm_gen_constant PARAMS ((enum rtx_code, Mmode, Hint, rtx, rtx, int, int)); +static int arm_naked_function_p PARAMS ((tree)); +static Ulong bit_count PARAMS ((signed int)); +static int const_ok_for_op PARAMS ((Hint, enum rtx_code)); +static int eliminate_lr2ip PARAMS ((rtx *)); +static rtx emit_multi_reg_push PARAMS ((int)); +static rtx emit_sfm PARAMS ((int, int)); +static char * fp_const_from_val PARAMS ((REAL_VALUE_TYPE *)); +static int function_really_clobbers_lr PARAMS ((rtx)); +static arm_cc get_arm_condition_code PARAMS ((rtx)); +static void init_fpa_table PARAMS ((void)); +static Hint int_log2 PARAMS ((Hint)); +static rtx is_jump_table PARAMS ((rtx)); +static char * output_multi_immediate PARAMS ((rtx *, char *, char *, int, Hint)); +static int pattern_really_clobbers_lr PARAMS ((rtx)); +static void print_multi_reg PARAMS ((FILE *, char *, int, int, int)); +static Mmode select_dominance_cc_mode PARAMS ((rtx, rtx, Hint)); +static char * shift_op PARAMS ((rtx, Hint *)); +static void arm_init_machine_status PARAMS ((struct function *)); +static void arm_mark_machine_status PARAMS ((struct function *)); +static int number_of_first_bit_set PARAMS ((int)); +static void replace_symbols_in_block PARAMS ((tree, rtx, rtx)); +static void thumb_exit PARAMS ((FILE *, int, rtx)); +static void thumb_pushpop PARAMS ((FILE *, int, int)); +static char * thumb_condition_code PARAMS ((rtx, int)); +static rtx is_jump_table PARAMS ((rtx)); +static Hint get_jump_table_size PARAMS ((rtx)); +static Mnode * move_minipool_fix_forward_ref PARAMS ((Mnode *, Mnode *, Hint)); +static Mnode * add_minipool_forward_ref PARAMS ((Mfix *)); +static Mnode * move_minipool_fix_backward_ref PARAMS ((Mnode *, Mnode *, Hint)); +static Mnode * add_minipool_backward_ref PARAMS ((Mfix *)); +static void assign_minipool_offsets PARAMS ((Mfix *)); +static void arm_print_value PARAMS ((FILE *, rtx)); +static void dump_minipool PARAMS ((rtx)); +static int arm_barrier_cost PARAMS ((rtx)); +static Mfix * create_fix_barrier PARAMS ((Mfix *, Hint)); +static void push_minipool_barrier PARAMS ((rtx, Hint)); +static void push_minipool_fix PARAMS ((rtx, Hint, rtx *, Mmode, rtx)); +static void note_invalid_constants PARAMS ((rtx, Hint)); + +#undef Hint +#undef Mmode +#undef Ulong /* The maximum number of insns skipped which will be conditionalised if possible. */ @@ -110,9 +140,10 @@ int arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY; #define FL_LDSCHED (1 << 7) /* Load scheduling necessary */ #define FL_STRONG (1 << 8) /* StrongARM */ -/* The bits in this mask specify which instructions we are allowed to - generate. */ +/* The bits in this mask specify which instructions we are + allowed to generate. */ static int insn_flags = 0; + /* The bits in this mask specify which instruction scheduling options should be used. Note - there is an overlap with the FL_FAST_MULT. For some hardware we want to be able to generate the multiply instructions, but to @@ -158,7 +189,7 @@ int lr_save_eliminated; /* Set to 1 when a return insn is output, this means that the epilogue is not needed. */ -static int return_used_this_function; +int return_used_this_function; /* Set to 1 after arm_reorg has started. Reset to start at the start of the next function. */ @@ -180,8 +211,6 @@ char * arm_condition_codes[] = "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" }; -static enum arm_cond_code get_arm_condition_code (); - #define streq(string1, string2) (strcmp (string1, string2) == 0) /* Initialization code. */ @@ -208,7 +237,7 @@ static struct processors all_cores[] = {"arm620", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, {"arm7", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, /* arm7m doesn't exist on its own, but only with D, (and I), but - those don't alter the code, so arm7m is sometimes used. */ + those don't alter the code, so arm7m is sometimes used. */ {"arm7m", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, {"arm7d", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, {"arm7dm", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, @@ -267,11 +296,11 @@ struct arm_cpu_select arm_select[] = }; /* Return the number of bits set in value' */ -static unsigned int +static unsigned long bit_count (value) signed int value; { - unsigned int count = 0; + unsigned long count = 0; while (value) { @@ -375,23 +404,22 @@ arm_override_options () switch that require certain abilities from the cpu. */ sought = 0; - if (TARGET_INTERWORK) + if (TARGET_INTERWORK || TARGET_THUMB) { sought |= (FL_THUMB | FL_MODE32); /* Force apcs-32 to be used for interworking. */ target_flags |= ARM_FLAG_APCS_32; - /* There are no ARM processor that supports both APCS-26 and + /* There are no ARM processors that support both APCS-26 and interworking. Therefore we force FL_MODE26 to be removed from insn_flags here (if it was set), so that the search below will always be able to find a compatible processor. */ insn_flags &= ~ FL_MODE26; } - - if (! TARGET_APCS_32) + else if (! TARGET_APCS_32) sought |= FL_MODE26; - + if (sought != 0 && ((sought & insn_flags) != sought)) { /* Try to locate a CPU type that supports all of the abilities @@ -471,6 +499,30 @@ arm_override_options () target_flags &= ~ARM_FLAG_INTERWORK; } + if (TARGET_THUMB && !(insn_flags & FL_THUMB)) + { + warning ("target CPU does not supoport THUMB instructions."); + target_flags &= ~ARM_FLAG_THUMB; + } + + if (TARGET_APCS_FRAME && TARGET_THUMB) + { + /* warning ("ignoring -mapcs-frame because -mthumb was used."); */ + target_flags &= ~ARM_FLAG_APCS_FRAME; + } + + /* TARGET_BACKTRACE calls leaf_function_p, which causes a crash if done + from here where no function is being compiled currently. */ + if ((target_flags & (THUMB_FLAG_LEAF_BACKTRACE | THUMB_FLAG_BACKTRACE)) + && TARGET_ARM) + warning ("enabling backtrace support is only meaningful when compiling for the Thumb."); + + if (TARGET_ARM && TARGET_CALLEE_INTERWORKING) + warning ("enabling callee interworking support is only meaningful when compiling for the Thumb."); + + if (TARGET_ARM && TARGET_CALLER_INTERWORKING) + warning ("enabling caller interworking support is only meaningful when compiling for the Thumb."); + /* If interworking is enabled then APCS-32 must be selected as well. */ if (TARGET_INTERWORK) { @@ -479,7 +531,7 @@ arm_override_options () target_flags |= ARM_FLAG_APCS_32; } - if (TARGET_APCS_STACK && ! TARGET_APCS) + if (TARGET_APCS_STACK && ! TARGET_APCS_FRAME) { warning ("-mapcs-stack-check incompatible with -mno-apcs-frame"); target_flags |= ARM_FLAG_APCS_FRAME; @@ -494,8 +546,13 @@ arm_override_options () if (TARGET_APCS_REENT) warning ("APCS reentrant code not supported. Ignored"); - if (write_symbols != NO_DEBUG && flag_omit_frame_pointer) - warning ("-g with -fomit-frame-pointer may not give sensible debugging"); + /* If this target is normally configured to use APCS frames, warn if they + are turned off and debugging is turned on. */ + if (TARGET_ARM + && write_symbols != NO_DEBUG + && ! TARGET_APCS_FRAME + && (TARGET_DEFAULT & ARM_FLAG_APCS_FRAME)) + warning ("-g with -mno-apcs-frame may not give sensible debugging"); /* If stack checking is disabled, we can use r10 as the PIC register, which keeps r9 available. */ @@ -512,8 +569,8 @@ arm_override_options () arm_ld_sched = (tune_flags & FL_LDSCHED) != 0; arm_is_strong = (tune_flags & FL_STRONG) != 0; - arm_is_6_or_7 = ((tune_flags & (FL_MODE26 | FL_MODE32)) - && !(tune_flags & FL_ARCH4)) != 0; + arm_is_6_or_7 = (((tune_flags & (FL_MODE26 | FL_MODE32)) + && !(tune_flags & FL_ARCH4))) != 0; /* Default value for floating point code... if no co-processor bus, then schedule for emulated floating point. Otherwise, @@ -574,7 +631,13 @@ arm_override_options () else arm_pic_register = pic_register; } - + + if (TARGET_THUMB && flag_schedule_insns) + { + /* Don't warn since it's on by default in -O2. */ + flag_schedule_insns = 0; + } + /* If optimizing for space, don't synthesize constants. For processors with load scheduling, it never costs more than 2 cycles to load a constant, and the load scheduler may well reduce that to 1. */ @@ -602,7 +665,6 @@ arm_add_gc_roots () ggc_add_rtx_root (&arm_target_insn, 1); /* Not sure this is really a root */ /* XXX: What about the minipool tables? */ } - /* Return 1 if it is possible to return using a single instruction. */ int @@ -611,11 +673,16 @@ use_return_insn (iscond) { int regno; - if (!reload_completed + /* Never use a return instruction before reload has run. */ + if (! reload_completed + /* Or if the function is variadic. */ || current_function_pretend_args_size || current_function_anonymous_args + /* Of if the function calls __builtin_eh_return () */ + || cfun->machine->eh_epilogue_sp_ofs != NULL + /* Or if there is no frame pointer and there is a stack adjustment. */ || ((get_frame_size () + current_function_outgoing_args_size != 0) - && !(TARGET_APCS && frame_pointer_needed))) + && ! frame_pointer_needed)) return 0; /* Can't be done if interworking with Thumb, and any registers have been @@ -623,10 +690,11 @@ use_return_insn (iscond) if they aren't taken and registers have been stacked. */ if (iscond && arm_is_strong && frame_pointer_needed) return 0; + if ((iscond && arm_is_strong) || TARGET_INTERWORK) { - for (regno = 0; regno < 16; regno++) + for (regno = 0; regno <= LAST_ARM_REGNUM; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) return 0; @@ -636,9 +704,10 @@ use_return_insn (iscond) /* Can't be done if any of the FPU regs are pushed, since this also requires an insn. */ - for (regno = 16; regno < 24; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - return 0; + if (TARGET_HARD_FLOAT) + for (regno = FIRST_ARM_FP_REGNUM; regno <= LAST_ARM_FP_REGNUM; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + return 0; /* If a function is naked, don't use the "return" insn. */ if (arm_naked_function_p (current_function_decl)) @@ -657,10 +726,10 @@ const_ok_for_arm (i) /* For machines with >32 bit HOST_WIDE_INT, the bits above bit 31 must be all zero, or all one. */ - if ((i & ~(unsigned HOST_WIDE_INT) 0xffffffffUL) != 0 - && ((i & ~(unsigned HOST_WIDE_INT) 0xffffffffUL) + if ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0 + && ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) != ((~(unsigned HOST_WIDE_INT) 0) - & ~(unsigned HOST_WIDE_INT) 0xffffffffUL))) + & ~(unsigned HOST_WIDE_INT) 0xffffffff))) return FALSE; /* Fast return for 0 and powers of 2 */ @@ -669,11 +738,11 @@ const_ok_for_arm (i) do { - if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffffUL) == 0) + if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0) return TRUE; mask = - (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffffUL) - >> (32 - 2)) | ~((unsigned HOST_WIDE_INT) 0xffffffffUL); + (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff) + >> (32 - 2)) | ~((unsigned HOST_WIDE_INT) 0xffffffff); } while (mask != ~(unsigned HOST_WIDE_INT) 0xFF); return FALSE; @@ -758,7 +827,7 @@ arm_split_constant (code, mode, val, target, source, subtargets) have subtraction of a constant. */ if (code == MINUS) emit_insn (gen_rtx_SET (VOIDmode, target, - gen_rtx (code, mode, temp, source))); + gen_rtx_MINUS (mode, temp, source))); else emit_insn (gen_rtx_SET (VOIDmode, target, gen_rtx (code, mode, source, temp))); @@ -772,7 +841,7 @@ arm_split_constant (code, mode, val, target, source, subtargets) /* As above, but extra parameter GENERATE which, if clear, suppresses RTL generation. */ -int +static int arm_gen_constant (code, mode, val, target, source, subtargets, generate) enum rtx_code code; enum machine_mode mode; @@ -794,9 +863,9 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate) int set_zero_bit_copies = 0; int insns = 0; unsigned HOST_WIDE_INT temp1, temp2; - unsigned HOST_WIDE_INT remainder = val & 0xffffffffUL; + unsigned HOST_WIDE_INT remainder = val & (unsigned HOST_WIDE_INT)0xffffffff; - /* find out which operations are safe for a given CODE. Also do a quick + /* Find out which operations are safe for a given CODE. Also do a quick check for degenerate cases; these can occur when DImode operations are split. */ switch (code) @@ -813,7 +882,7 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate) break; case IOR: - if (remainder == 0xffffffffUL) + if (remainder == (unsigned HOST_WIDE_INT)0xffffffff) { if (generate) emit_insn (gen_rtx_SET (VOIDmode, target, @@ -837,7 +906,7 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate) emit_insn (gen_rtx_SET (VOIDmode, target, const0_rtx)); return 1; } - if (remainder == 0xffffffffUL) + if (remainder == (unsigned HOST_WIDE_INT)0xffffffff) { if (reload_completed && rtx_equal_p (target, source)) return 0; @@ -857,7 +926,7 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate) emit_insn (gen_rtx_SET (VOIDmode, target, source)); return 1; } - if (remainder == 0xffffffffUL) + if (remainder == (unsigned HOST_WIDE_INT)0xffffffff) { if (generate) emit_insn (gen_rtx_SET (VOIDmode, target, @@ -985,15 +1054,16 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate) word. We only look for the simplest cases, to do more would cost too much. Be careful, however, not to generate this when the alternative would take fewer insns. */ - if (val & 0xffff0000UL) + if (val & (unsigned HOST_WIDE_INT)0xffff0000) { - temp1 = remainder & 0xffff0000UL; + temp1 = remainder & (unsigned HOST_WIDE_INT)0xffff0000; temp2 = remainder & 0x0000ffff; /* Overlaps outside this range are best done using other methods. */ for (i = 9; i < 24; i++) { - if ((((temp2 | (temp2 << i)) & 0xffffffffUL) == remainder) + if ((((temp2 | (temp2 << i)) + & (unsigned HOST_WIDE_INT)0xffffffff) == remainder) && ! const_ok_for_arm (temp2)) { rtx new_src = (subtargets @@ -1131,11 +1201,11 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate) /* See if two shifts will do 2 or more insn's worth of work. */ if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24) { - HOST_WIDE_INT shift_mask = ((0xffffffffUL + HOST_WIDE_INT shift_mask = ((((unsigned HOST_WIDE_INT)0xffffffff) << (32 - clear_sign_bit_copies)) - & 0xffffffffUL); + & (unsigned HOST_WIDE_INT)0xffffffff); - if ((remainder | shift_mask) != 0xffffffffUL) + if ((remainder | shift_mask) != (unsigned HOST_WIDE_INT)0xffffffff) { if (generate) { @@ -1168,7 +1238,7 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate) { HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1; - if ((remainder | shift_mask) != 0xffffffffUL) + if ((remainder | shift_mask) != (unsigned HOST_WIDE_INT)0xffffffff) { if (generate) { @@ -1210,9 +1280,9 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate) num_bits_set++; if (code == AND || (can_invert && num_bits_set > 16)) - remainder = (~remainder) & 0xffffffffUL; + remainder = (~remainder) & (unsigned HOST_WIDE_INT)0xffffffff; else if (code == PLUS && num_bits_set > 16) - remainder = (-remainder) & 0xffffffffUL; + remainder = (-remainder) & (unsigned HOST_WIDE_INT)0xffffffff; else { can_invert = 0; @@ -1392,11 +1462,15 @@ arm_return_in_memory (type) if (! AGGREGATE_TYPE_P (type)) /* All simple types are returned in registers. */ return 0; - + + /* For the arm-wince targets we choose to be compitable with Microsoft's + ARM and Thumb compilers, which always return aggregates in memory. */ +#ifndef ARM_WINCE + if (int_size_in_bytes (type) > 4) /* All structures/unions bigger than one word are returned in memory. */ return 1; - + if (TREE_CODE (type) == RECORD_TYPE) { tree field; @@ -1417,13 +1491,17 @@ arm_return_in_memory (type) if (field == NULL) return 0; /* An empty structure. Allowed by an extension to ANSI C. */ - /* Check that the first field is valid for returning in a register... */ + /* Check that the first field is valid for returning in a register. */ + + /* ... Floats are not allowed */ if (FLOAT_TYPE_P (TREE_TYPE (field))) return 1; + /* ... Aggregates that are not themselves valid for returning in + a register are not allowed. */ if (RETURN_IN_MEMORY (TREE_TYPE (field))) return 1; - + /* Now check the remaining fields, if any. Only bitfields are allowed, since they are not addressable. */ for (field = TREE_CHAIN (field); @@ -1462,8 +1540,9 @@ arm_return_in_memory (type) return 0; } +#endif /* not ARM_WINCE */ - /* Put other aggregates in memory. */ + /* Return all other types in memory. */ return 1; } @@ -1622,20 +1701,6 @@ arm_comp_type_attributes (type1, type2) return 1; } -/* Check the ARM specific attributes on the given function decl. - If any of them would prevent the function from being inlined, - return a tesxtual description of why not. Otherwise return NULL. */ -const char * -arm_function_attribute_inlineable_p (fndecl) - tree fndecl; -{ - if (lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (fndecl))) - return "naked functions cannot be inlined"; - - /* Allow functions with short_call and long_call attributes to be inlined. */ - return NULL; -} - /* Encode long_call or short_call attribute by prefixing symbol name in DECL with a special character FLAG. */ void @@ -1771,7 +1836,8 @@ int legitimate_pic_operand_p (x) rtx x; { - if (CONSTANT_P (x) && flag_pic + if (CONSTANT_P (x) + && flag_pic && (GET_CODE (x) == SYMBOL_REF || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS @@ -1884,15 +1950,15 @@ legitimize_pic_address (orig, mode, reg) current_function_uses_pic_offset_table = 1; if (NEED_GOT_RELOC) - { - rtx pic_ref, address = gen_reg_rtx (Pmode); - - emit_insn (gen_pic_load_addr (address, orig)); - pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, address); - - emit_move_insn (address, pic_ref); - return address; - } + { + rtx pic_ref, address = gen_reg_rtx (Pmode); + + emit_insn (gen_pic_load_addr (address, orig)); + pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, address); + + emit_move_insn (address, pic_ref); + return address; + } } return orig; @@ -1927,8 +1993,8 @@ arm_finalize_pic () global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); /* On the ARM the PC register contains 'dot + 8' at the time of the - addition. */ - pic_tmp = plus_constant (gen_rtx_LABEL_REF (Pmode, l1), 8); + addition, on the Thumb it is 'dot + 4'. */ + pic_tmp = plus_constant (gen_rtx_LABEL_REF (Pmode, l1), TARGET_ARM ? 8 : 4); if (GOT_PCREL) pic_tmp2 = gen_rtx_CONST (VOIDmode, gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx)); @@ -1938,7 +2004,10 @@ arm_finalize_pic () pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp)); emit_insn (gen_pic_load_addr (pic_offset_table_rtx, pic_rtx)); - emit_insn (gen_pic_add_dot_plus_eight (pic_offset_table_rtx, l1)); + if (TARGET_ARM) + emit_insn (gen_pic_add_dot_plus_eight (pic_offset_table_rtx, l1)); + else + emit_insn (gen_pic_add_dot_plus_four (pic_offset_table_rtx, l1)); seq = gen_sequence (); end_sequence (); @@ -1957,19 +2026,144 @@ arm_finalize_pic () #define REG_OR_SUBREG_RTX(X) \ (GET_CODE (X) == REG ? (X) : SUBREG_REG (X)) -#define ARM_FRAME_RTX(X) \ - ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ - || (X) == arg_pointer_rtx) +#ifndef COSTS_N_INSNS +#define COSTS_N_INSNS(N) ((N) * 4 - 2) +#endif int -arm_rtx_costs (x, code) +arm_rtx_costs (x, code, outer) rtx x; enum rtx_code code; + enum rtx_code outer; { enum machine_mode mode = GET_MODE (x); enum rtx_code subcode; int extra_cost; + if (TARGET_THUMB) + { + switch (code) + { + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + case ROTATERT: + case PLUS: + case MINUS: + case COMPARE: + case NEG: + case NOT: + return COSTS_N_INSNS (1); + + case MULT: + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + { + int cycles = 0; + unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1)); + + while (i) + { + i >>= 2; + cycles ++; + } + return COSTS_N_INSNS (2) + cycles; + } + return COSTS_N_INSNS (1) + 16; + + case SET: + return (COSTS_N_INSNS (1) + + 4 * ((GET_CODE (SET_SRC (x)) == MEM) + + GET_CODE (SET_DEST (x)) == MEM)); + + case CONST_INT: + if (outer == SET) + { + if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256) + return 0; + if (thumb_shiftable_const (INTVAL (x))) + return COSTS_N_INSNS (2); + return COSTS_N_INSNS (3); + } + else if (outer == PLUS + && INTVAL (x) < 256 && INTVAL (x) > -256) + return 0; + else if (outer == COMPARE + && (unsigned HOST_WIDE_INT) INTVAL (x) < 256) + return 0; + else if (outer == ASHIFT || outer == ASHIFTRT + || outer == LSHIFTRT) + return 0; + return COSTS_N_INSNS (2); + + case CONST: + case CONST_DOUBLE: + case LABEL_REF: + case SYMBOL_REF: + return COSTS_N_INSNS (3); + + case UDIV: + case UMOD: + case DIV: + case MOD: + return 100; + + case TRUNCATE: + return 99; + + case AND: + case XOR: + case IOR: + /* XXX guess. */ + return 8; + + case ADDRESSOF: + case MEM: + /* XXX another guess. */ + /* Memory costs quite a lot for the first word, but subsequent words + load at the equivalent of a single insn each. */ + return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD) + + (CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0)); + + case IF_THEN_ELSE: + /* XXX a guess. */ + if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC) + return 14; + return 2; + + case ZERO_EXTEND: + /* XXX still guessing. */ + switch (GET_MODE (XEXP (x, 0))) + { + case QImode: + return (1 + (mode == DImode ? 4 : 0) + + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); + + case HImode: + return (4 + (mode == DImode ? 4 : 0) + + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); + + case SImode: + return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); + + default: + return 99; + } + + default: + return 99; +#if 0 + case FFS: + case FLOAT: + case FIX: + case UNSIGNED_FIX: + /* XXX guess */ + fprintf (stderr, "unexpected code for thumb in rtx_costs: %s\n", + rtx_name[code]); + abort (); +#endif + } + } + switch (code) { case MEM: @@ -2112,7 +2306,7 @@ arm_rtx_costs (x, code) if (GET_CODE (XEXP (x, 1)) == CONST_INT) { unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1)) - & (unsigned HOST_WIDE_INT) 0xffffffffUL); + & (unsigned HOST_WIDE_INT) 0xffffffff); int add_cost = const_ok_for_arm (i) ? 4 : 8; int j; @@ -2188,6 +2382,32 @@ arm_rtx_costs (x, code) } abort (); + case CONST_INT: + if (const_ok_for_arm (INTVAL (x))) + return outer == SET ? 2 : -1; + else if (outer == AND + && const_ok_for_arm (~ INTVAL (x))) + return -1; + else if ((outer == COMPARE + || outer == PLUS || outer == MINUS) + && const_ok_for_arm (- INTVAL (x))) + return -1; + else + return 5; + + case CONST: + case LABEL_REF: + case SYMBOL_REF: + return 6; + + case CONST_DOUBLE: + if (const_double_rtx_ok_for_fpu (x)) + return outer == SET ? 2 : -1; + else if ((outer == COMPARE || outer == PLUS) + && neg_const_double_rtx_ok_for_fpu (x)) + return -1; + return 7; + default: return 99; } @@ -2203,10 +2423,15 @@ arm_adjust_cost (insn, link, dep, cost) rtx i_pat, d_pat; /* XXX This is not strictly true for the FPA. */ - if (REG_NOTE_KIND(link) == REG_DEP_ANTI - || REG_NOTE_KIND(link) == REG_DEP_OUTPUT) + if (REG_NOTE_KIND (link) == REG_DEP_ANTI + || REG_NOTE_KIND (link) == REG_DEP_OUTPUT) return 0; + /* Call insns don't incur a stall, even if they follow a load. */ + if (REG_NOTE_KIND (link) == 0 + && GET_CODE (insn) == CALL_INSN) + return 1; + if ((i_pat = single_set (insn)) != NULL && GET_CODE (SET_SRC (i_pat)) == MEM && (d_pat = single_set (dep)) != NULL @@ -2325,6 +2550,7 @@ s_register_operand (op, mode) /* 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)); @@ -2356,7 +2582,7 @@ reg_or_int_operand (op, mode) /* Return 1 if OP is an item in memory, given that we are in reload. */ int -reload_memory_operand (op, mode) +arm_reload_memory_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED; { @@ -2369,13 +2595,21 @@ reload_memory_operand (op, mode) } /* Return 1 if OP is a valid memory address, but not valid for a signed byte - memory access (architecture V4) */ + memory access (architecture V4). + MODE is QImode if called when computing contraints, or VOIDmode when + emitting patterns. In this latter case we cannot use memory_operand() + because it will fail on badly formed MEMs, which is precisly what we are + trying to catch. */ int bad_signed_byte_operand (op, mode) rtx op; - enum machine_mode mode; + enum machine_mode mode ATTRIBUTE_UNUSED; { - if (! memory_operand (op, mode) || GET_CODE (op) != MEM) +#if 0 + if ((mode == QImode && ! memory_operand (op, mode)) || GET_CODE (op) != MEM) + return 0; +#endif + if (GET_CODE (op) != MEM) return 0; op = XEXP (op, 0); @@ -2429,6 +2663,9 @@ arm_add_operand (op, mode) rtx op; enum machine_mode mode; { + if (TARGET_THUMB) + return thumb_cmp_operand (op, mode); + return (s_register_operand (op, mode) || (GET_CODE (op) == CONST_INT && (const_ok_for_arm (INTVAL (op)) @@ -2556,7 +2793,7 @@ power_of_two_operand (op, mode) { if (GET_CODE (op) == CONST_INT) { - HOST_WIDE_INT value = INTVAL(op); + HOST_WIDE_INT value = INTVAL (op); return value != 0 && (value & (value - 1)) == 0; } return FALSE; @@ -2595,6 +2832,27 @@ di_operand (op, mode) } } +/* Like di_operand, but don't accept constants. */ +int +nonimmediate_di_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (s_register_operand (op, mode)) + return TRUE; + + if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode) + return FALSE; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + if (GET_CODE (op) == MEM) + return memory_address_p (DImode, XEXP (op, 0)); + + return FALSE; +} + /* Return TRUE for a valid operand of a DFmode operation when -msoft-float. Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address). Note that this disallows MEM(REG+REG), but allows @@ -2630,16 +2888,36 @@ soft_df_operand (op, mode) } } -/* Return TRUE for valid index operands. */ +/* Like soft_df_operand, but don't accept constants. */ +int +nonimmediate_soft_df_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (s_register_operand (op, mode)) + return TRUE; + + if (mode != VOIDmode && GET_MODE (op) != mode) + return FALSE; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + if (GET_CODE (op) == MEM) + return memory_address_p (DFmode, XEXP (op, 0)); + return FALSE; +} +/* Return TRUE for valid index operands. */ int index_operand (op, mode) rtx op; enum machine_mode mode; { - return (s_register_operand(op, mode) + return (s_register_operand (op, mode) || (immediate_operand (op, mode) - && INTVAL (op) < 4096 && INTVAL (op) > -4096)); + && (GET_CODE (op) != CONST_INT + || (INTVAL (op) < 4096 && INTVAL (op) > -4096)))); } /* Return TRUE for valid shifts by a constant. This also accepts any @@ -2653,7 +2931,8 @@ const_shift_operand (op, mode) { return (power_of_two_operand (op, mode) || (immediate_operand (op, mode) - && (INTVAL (op) < 32 && INTVAL (op) > 0))); + && (GET_CODE (op) != CONST_INT + || (INTVAL (op) < 32 && INTVAL (op) > 0)))); } /* Return TRUE for arithmetic operators which can be combined with a multiply @@ -2746,11 +3025,14 @@ cc_register (x, mode) if (mode == VOIDmode) { mode = GET_MODE (x); + if (GET_MODE_CLASS (mode) != MODE_CC) return FALSE; } - if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24) + if ( GET_MODE (x) == mode + && GET_CODE (x) == REG + && REGNO (x) == CC_REGNUM) return TRUE; return FALSE; @@ -2767,21 +3049,19 @@ dominant_cc_register (x, mode) if (mode == VOIDmode) { mode = GET_MODE (x); + if (GET_MODE_CLASS (mode) != MODE_CC) return FALSE; } - if (mode != CC_DNEmode && mode != CC_DEQmode + if ( mode != CC_DNEmode && mode != CC_DEQmode && mode != CC_DLEmode && mode != CC_DLTmode && mode != CC_DGEmode && mode != CC_DGTmode && mode != CC_DLEUmode && mode != CC_DLTUmode && mode != CC_DGEUmode && mode != CC_DGTUmode) return FALSE; - if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24) - return TRUE; - - return FALSE; + return cc_register (x, mode); } /* Return TRUE if X references a SYMBOL_REF. */ @@ -2796,6 +3076,7 @@ symbol_mentioned_p (x) return 1; fmt = GET_RTX_FORMAT (GET_CODE (x)); + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) { if (fmt[i] == 'E') @@ -2896,7 +3177,6 @@ adjacent_mem_locations (a, b) /* Return 1 if OP is a load multiple operation. It is known to be parallel and the first section will be tested. */ - int load_multiple_operation (op, mode) rtx op; @@ -3061,7 +3341,7 @@ load_multiple_sequence (operands, nops, regs, base, load_offset) /* Convert a subreg of a mem into the mem itself. */ if (GET_CODE (operands[nops + i]) == SUBREG) - operands[nops + i] = alter_subreg(operands[nops + i]); + operands[nops + i] = alter_subreg (operands[nops + i]); if (GET_CODE (operands[nops + i]) != MEM) abort (); @@ -3086,7 +3366,7 @@ load_multiple_sequence (operands, nops, regs, base, load_offset) { if (i == 0) { - base_reg = REGNO(reg); + base_reg = REGNO (reg); unsorted_regs[0] = (GET_CODE (operands[i]) == REG ? REGNO (operands[i]) : REGNO (SUBREG_REG (operands[i]))); @@ -3296,7 +3576,7 @@ store_multiple_sequence (operands, nops, regs, base, load_offset) /* Convert a subreg of a mem into the mem itself. */ if (GET_CODE (operands[nops + i]) == SUBREG) - operands[nops + i] = alter_subreg(operands[nops + i]); + operands[nops + i] = alter_subreg (operands[nops + i]); if (GET_CODE (operands[nops + i]) != MEM) abort (); @@ -3462,7 +3742,6 @@ multi_register_push (op, mode) return 1; } - /* Routines for use with attributes. */ @@ -3472,9 +3751,14 @@ multi_register_push (op, mode) Supported attributes: - naked: don't output any prologue or epilogue code, - the user is assumed to do the right thing. -*/ + naked: + don't output any prologue or epilogue code, the user is assumed + to do the right thing. + + interfacearm: + Always assume that this function will be entered in ARM mode, + not Thumb mode, and that the caller wishes to be returned to in + ARM mode. */ int arm_valid_machine_decl_attribute (decl, attr, args) tree decl; @@ -3486,11 +3770,16 @@ arm_valid_machine_decl_attribute (decl, attr, args) if (is_attribute_p ("naked", attr)) return TREE_CODE (decl) == FUNCTION_DECL; + +#ifdef ARM_PE + if (is_attribute_p ("interfacearm", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; +#endif /* ARM_PE */ + return 0; } /* Return non-zero if FUNC is a naked function. */ - static int arm_naked_function_p (func) tree func; @@ -3626,7 +3915,7 @@ arm_gen_movstrqi (operands) fin_dst = dst = copy_to_mode_reg (SImode, st_dst); fin_src = src = copy_to_mode_reg (SImode, st_src); - in_words_to_go = (INTVAL (operands[2]) + 3) / 4; + in_words_to_go = NUM_INTS (INTVAL (operands[2])); out_words_to_go = INTVAL (operands[2]) / 4; last_bytes = INTVAL (operands[2]) & 3; @@ -3712,13 +4001,13 @@ arm_gen_movstrqi (operands) part_bytes_reg = copy_to_mode_reg (SImode, mem); } + if (last_bytes && part_bytes_reg == NULL) + abort (); + if (BYTES_BIG_ENDIAN && last_bytes) { rtx tmp = gen_reg_rtx (SImode); - if (part_bytes_reg == NULL) - abort (); - /* The bytes we want are in the top end of the word. */ emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8 * (4 - last_bytes)))); @@ -3743,26 +4032,32 @@ arm_gen_movstrqi (operands) } else { - while (last_bytes) + if (last_bytes > 1) { - if (part_bytes_reg == NULL) - abort (); - - mem = gen_rtx_MEM (QImode, dst); + mem = gen_rtx_MEM (HImode, dst); RTX_UNCHANGING_P (mem) = dst_unchanging_p; MEM_IN_STRUCT_P (mem) = dst_in_struct_p; MEM_SCALAR_P (mem) = dst_scalar_p; - emit_move_insn (mem, gen_rtx_SUBREG (QImode, part_bytes_reg, 0)); - - if (--last_bytes) + emit_move_insn (mem, gen_rtx_SUBREG (HImode, part_bytes_reg, 0)); + last_bytes -= 2; + if (last_bytes) { rtx tmp = gen_reg_rtx (SImode); - emit_insn (gen_addsi3 (dst, dst, const1_rtx)); - emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8))); + emit_insn (gen_addsi3 (dst, dst, GEN_INT (2))); + emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (16))); part_bytes_reg = tmp; } } + + if (last_bytes) + { + mem = gen_rtx_MEM (QImode, dst); + RTX_UNCHANGING_P (mem) = dst_unchanging_p; + MEM_IN_STRUCT_P (mem) = dst_in_struct_p; + MEM_SCALAR_P (mem) = dst_scalar_p; + emit_move_insn (mem, gen_rtx_SUBREG (QImode, part_bytes_reg, 0)); + } } return 1; @@ -3772,7 +4067,7 @@ arm_gen_movstrqi (operands) into the top 16 bits of the word. We can assume that the address is known to be alignable and of the form reg, or plus (reg, const). */ rtx -gen_rotated_half_load (memref) +arm_gen_rotated_half_load (memref) rtx memref; { HOST_WIDE_INT offset = 0; @@ -3987,12 +4282,12 @@ arm_select_cc_mode (op, x, y) floating point compare: I don't think that it is needed on the arm. */ rtx -gen_compare_reg (code, x, y) +arm_gen_compare_reg (code, x, y) enum rtx_code code; rtx x, y; { enum machine_mode mode = SELECT_CC_MODE (code, x, y); - rtx cc_reg = gen_rtx_REG (mode, 24); + rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM); emit_insn (gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y))); @@ -4065,9 +4360,9 @@ arm_reload_in_hi (operands) if (lo == 4095) lo &= 0x7ff; - hi = ((((offset - lo) & (HOST_WIDE_INT) 0xFFFFFFFFUL) - ^ (HOST_WIDE_INT) 0x80000000UL) - - (HOST_WIDE_INT) 0x80000000UL); + hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff) + ^ (HOST_WIDE_INT) 0x80000000) + - (HOST_WIDE_INT) 0x80000000); if (hi + lo != offset) abort (); @@ -4211,9 +4506,9 @@ arm_reload_out_hi (operands) if (lo == 4095) lo &= 0x7ff; - hi = ((((offset - lo) & (HOST_WIDE_INT) 0xFFFFFFFFUL) - ^ (HOST_WIDE_INT) 0x80000000UL) - - (HOST_WIDE_INT) 0x80000000UL); + hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff) + ^ (HOST_WIDE_INT) 0x80000000) + - (HOST_WIDE_INT) 0x80000000); if (hi + lo != offset) abort (); @@ -4280,6 +4575,54 @@ arm_reload_out_hi (operands) } } +/* Print a symbolic form of X to the debug file, F. */ +static void +arm_print_value (f, x) + FILE * f; + rtx x; +{ + switch (GET_CODE (x)) + { + case CONST_INT: + fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (x)); + return; + + case CONST_DOUBLE: + fprintf (f, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3)); + return; + + case CONST_STRING: + fprintf (f, "\"%s\"", XSTR (x, 0)); + return; + + case SYMBOL_REF: + fprintf (f, "`%s'", XSTR (x, 0)); + return; + + case LABEL_REF: + fprintf (f, "L%d", INSN_UID (XEXP (x, 0))); + return; + + case CONST: + arm_print_value (f, XEXP (x, 0)); + return; + + case PLUS: + arm_print_value (f, XEXP (x, 0)); + fprintf (f, "+"); + arm_print_value (f, XEXP (x, 1)); + return; + + case PC: + fprintf (f, "pc"); + return; + + default: + fprintf (f, "????"); + return; + } +} + /* Routines for manipulation of the constant pool. */ /* Arm instructions cannot load a large constant directly into a @@ -4334,202 +4677,674 @@ arm_reload_out_hi (operands) Possible enhancements to the algorithm (not implemented) are: - 1) ARM instructions (but not Thumb) can use negative offsets, so we - could reference back to a previous pool rather than forwards to a - new one. For large functions this may reduce the number of pools - required. - - 2) For some processors and object formats, there may be benefit in + 1) For some processors and object formats, there may be benefit in aligning the pools to the start of cache lines; this alignment would need to be taken into account when calculating addressability of a pool. */ -typedef struct +/* These typedefs are located at the start of this file, so that + they can be used in the prototypes there. This comment is to + remind readers of that fact so that the following structures + can be understood more easily. + + typedef struct minipool_node Mnode; + typedef struct minipool_fixup Mfix; */ + +struct minipool_node +{ + /* Doubly linked chain of entries. */ + Mnode * next; + Mnode * prev; + /* The maximum offset into the code that this entry can be placed. While + pushing fixes for forward references, all entries are sorted in order + of increasing max_address. */ + HOST_WIDE_INT max_address; + /* Similarly for a entry inserted for a backwards ref. */ + HOST_WIDE_INT min_address; + /* The number of fixes referencing this entry. This can become zero + if we "unpush" an entry. In this case we ignore the entry when we + come to emit the code. */ + int refcount; + /* The offset from the start of the minipool. */ + HOST_WIDE_INT offset; + /* The value in table. */ + rtx value; + /* The mode of value. */ + enum machine_mode mode; + int fix_size; +}; + +struct minipool_fixup { - rtx value; /* Value in table */ - HOST_WIDE_INT next_offset; - enum machine_mode mode; /* Mode of value */ -} minipool_node; + Mfix * next; + rtx insn; + HOST_WIDE_INT address; + rtx * loc; + enum machine_mode mode; + int fix_size; + rtx value; + Mnode * minipool; + HOST_WIDE_INT forwards; + HOST_WIDE_INT backwards; +}; -/* The maximum number of constants that can fit into one pool, since - the pc relative range is 0...4092 bytes and constants are at least 4 - bytes long. */ -#define MAX_MINIPOOL_SIZE (4092/4) -static minipool_node minipool_vector[MAX_MINIPOOL_SIZE]; -static int minipool_size; -static rtx minipool_vector_label; +/* Fixes less than a word need padding out to a word boundary. */ +#define MINIPOOL_FIX_SIZE(mode) \ + (GET_MODE_SIZE ((mode)) >= 4 ? GET_MODE_SIZE ((mode)) : 4) -/* Add a constant to the pool and return its offset within the current - pool. +static Mnode * minipool_vector_head; +static Mnode * minipool_vector_tail; +static rtx minipool_vector_label; - X is the rtx we want to replace. MODE is its mode. On return, - ADDRESS_ONLY will be non-zero if we really want the address of such - a constant, not the constant itself. */ -static HOST_WIDE_INT -add_minipool_constant (x, mode) - rtx x; - enum machine_mode mode; +/* The linked list of all minipool fixes required for this function. */ +Mfix * minipool_fix_head; +Mfix * minipool_fix_tail; +/* The fix entry for the current minipool, once it has been placed. */ +Mfix * minipool_barrier; + +/* Determines if INSN is the start of a jump table. Returns the end + of the TABLE or NULL_RTX. */ +static rtx +is_jump_table (insn) + rtx insn; { - int i; - HOST_WIDE_INT offset; + rtx table; - /* First, see if we've already got it. */ - for (i = 0; i < minipool_size; i++) - { - if (GET_CODE (x) == minipool_vector[i].value->code - && mode == minipool_vector[i].mode) - { - if (GET_CODE (x) == CODE_LABEL) - { - if (XINT (x, 3) != XINT (minipool_vector[i].value, 3)) - continue; - } - if (rtx_equal_p (x, minipool_vector[i].value)) - return minipool_vector[i].next_offset - GET_MODE_SIZE (mode); - } - } - - /* Need a new one. */ - minipool_vector[minipool_size].next_offset = GET_MODE_SIZE (mode); - offset = 0; - if (minipool_size == 0) - minipool_vector_label = gen_label_rtx (); - else - minipool_vector[minipool_size].next_offset - += (offset = minipool_vector[minipool_size - 1].next_offset); - - minipool_vector[minipool_size].value = x; - minipool_vector[minipool_size].mode = mode; - minipool_size++; - return offset; + if (GET_CODE (insn) == JUMP_INSN + && JUMP_LABEL (insn) != NULL + && ((table = next_real_insn (JUMP_LABEL (insn))) + == next_real_insn (insn)) + && table != NULL + && GET_CODE (table) == JUMP_INSN + && (GET_CODE (PATTERN (table)) == ADDR_VEC + || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC)) + return table; + + return NULL_RTX; } -/* Output the literal table. */ -static void -dump_minipool (scan) - rtx scan; +static HOST_WIDE_INT +get_jump_table_size (insn) + rtx insn; { - int i; + rtx body = PATTERN (insn); + int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0; - scan = emit_label_after (gen_label_rtx (), scan); - scan = emit_insn_after (gen_align_4 (), scan); - scan = emit_label_after (minipool_vector_label, scan); + return GET_MODE_SIZE (GET_MODE (body)) * XVECLEN (body, elt); +} - for (i = 0; i < minipool_size; i++) +/* Move a minipool fix MP from its current location to before MAX_MP. + If MAX_MP is NULL, then MP doesn't need moving, but the addressing + contrains may need updating. */ +static Mnode * +move_minipool_fix_forward_ref (mp, max_mp, max_address) + Mnode * mp; + Mnode * max_mp; + HOST_WIDE_INT max_address; +{ + /* This should never be true and the code below assumes these are + different. */ + if (mp == max_mp) + abort (); + + if (max_mp == NULL) + { + if (max_address < mp->max_address) + mp->max_address = max_address; + } + else { - minipool_node *p = minipool_vector + i; + if (max_address > max_mp->max_address - mp->fix_size) + mp->max_address = max_mp->max_address - mp->fix_size; + else + mp->max_address = max_address; - switch (GET_MODE_SIZE (p->mode)) - { - case 4: - scan = emit_insn_after (gen_consttable_4 (p->value), scan); - break; + /* Unlink MP from its current position. Since max_mp is non-null, + mp->prev must be non-null. */ + mp->prev->next = mp->next; + if (mp->next != NULL) + mp->next->prev = mp->prev; + else + minipool_vector_tail = mp->prev; - case 8: - scan = emit_insn_after (gen_consttable_8 (p->value), scan); - break; + /* Re-insert it before MAX_MP. */ + mp->next = max_mp; + mp->prev = max_mp->prev; + max_mp->prev = mp; + + if (mp->prev != NULL) + mp->prev->next = mp; + else + minipool_vector_head = mp; + } - default: - abort (); - break; - } + /* Save the new entry. */ + max_mp = mp; + + /* Scan over the preceeding entries and adjust their addresses as + required. */ + while (mp->prev != NULL + && mp->prev->max_address > mp->max_address - mp->prev->fix_size) + { + mp->prev->max_address = mp->max_address - mp->prev->fix_size; + mp = mp->prev; } - scan = emit_insn_after (gen_consttable_end (), scan); - scan = emit_barrier_after (scan); - minipool_size = 0; + return max_mp; } -/* Find the last barrier less than MAX_COUNT bytes from FROM, or - create one. */ -static rtx -find_barrier (from, max_count) - rtx from; - int max_count; -{ - int count = 0; - rtx found_barrier = 0; - rtx last = from; - - while (from && count < max_count) - { - rtx tmp; - - if (GET_CODE (from) == BARRIER) - found_barrier = from; +/* Add a constant to the minipool for a forward reference. Returns the + node added or NULL if the constant will not fit in this pool. */ +static Mnode * +add_minipool_forward_ref (fix) + Mfix * fix; +{ + /* If set, max_mp is the first pool_entry that has a lower + constraint than the one we are trying to add. */ + Mnode * max_mp = NULL; + HOST_WIDE_INT max_address = fix->address + fix->forwards; + Mnode * mp; + + /* If this fix's address is greater than the address of the first + entry, then we can't put the fix in this pool. We subtract the + size of the current fix to ensure that if the table is fully + packed we still have enough room to insert this value by suffling + the other fixes forwards. */ + if (minipool_vector_head && + fix->address >= minipool_vector_head->max_address - fix->fix_size) + return NULL; - /* Count the length of this insn. */ - if (GET_CODE (from) == JUMP_INSN - && JUMP_LABEL (from) != 0 - && ((tmp = next_real_insn (JUMP_LABEL (from))) - == next_real_insn (from)) - && tmp != NULL - && GET_CODE (tmp) == JUMP_INSN - && (GET_CODE (PATTERN (tmp)) == ADDR_VEC - || GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC)) - { - int elt = GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC ? 1 : 0; - count += (get_attr_length (from) - + GET_MODE_SIZE (SImode) * XVECLEN (PATTERN (tmp), elt)); - /* Continue after the dispatch table. */ - last = from; - from = NEXT_INSN (tmp); - continue; + /* Scan the pool to see if a constant with the same value has + already been added. While we are doing this, also note the + location where we must insert the constant if it doesn't already + exist. */ + for (mp = minipool_vector_head; mp != NULL; mp = mp->next) + { + if (GET_CODE (fix->value) == GET_CODE (mp->value) + && fix->mode == mp->mode + && (GET_CODE (fix->value) != CODE_LABEL + || (CODE_LABEL_NUMBER (fix->value) + == CODE_LABEL_NUMBER (mp->value))) + && rtx_equal_p (fix->value, mp->value)) + { + /* More than one fix references this entry. */ + mp->refcount++; + return move_minipool_fix_forward_ref (mp, max_mp, max_address); + } + + /* Note the insertion point if necessary. */ + if (max_mp == NULL + && mp->max_address > max_address) + max_mp = mp; + } + + /* The value is not currently in the minipool, so we need to create + a new entry for it. If MAX_MP is NULL, the entry will be put on + the end of the list since the placement is less constrained than + any existing entry. Otherwise, we insert the new fix before + MAX_MP and, if neceesary, adjust the constraints on the other + entries. */ + mp = xmalloc (sizeof (* mp)); + mp->fix_size = fix->fix_size; + mp->mode = fix->mode; + mp->value = fix->value; + mp->refcount = 1; + /* Not yet required for a backwards ref. */ + mp->min_address = -65536; + + if (max_mp == NULL) + { + mp->max_address = max_address; + mp->next = NULL; + mp->prev = minipool_vector_tail; + + if (mp->prev == NULL) + { + minipool_vector_head = mp; + minipool_vector_label = gen_label_rtx (); } else - count += get_attr_length (from); + mp->prev->next = mp; - last = from; - from = NEXT_INSN (from); + minipool_vector_tail = mp; + } + else + { + if (max_address > max_mp->max_address - mp->fix_size) + mp->max_address = max_mp->max_address - mp->fix_size; + else + mp->max_address = max_address; + + mp->next = max_mp; + mp->prev = max_mp->prev; + max_mp->prev = mp; + if (mp->prev != NULL) + mp->prev->next = mp; + else + minipool_vector_head = mp; + } + + /* Save the new entry. */ + max_mp = mp; + + /* Scan over the preceeding entries and adjust their addresses as + required. */ + while (mp->prev != NULL + && mp->prev->max_address > mp->max_address - mp->prev->fix_size) + { + mp->prev->max_address = mp->max_address - mp->prev->fix_size; + mp = mp->prev; } - if (! found_barrier) + return max_mp; +} + +static Mnode * +move_minipool_fix_backward_ref (mp, min_mp, min_address) + Mnode * mp; + Mnode * min_mp; + HOST_WIDE_INT min_address; +{ + HOST_WIDE_INT offset; + + /* This should never be true, and the code below assumes these are + different. */ + if (mp == min_mp) + abort (); + + if (min_mp == NULL) { - /* We didn't find a barrier in time to - dump our stuff, so we'll make one. */ - rtx label = gen_label_rtx (); - - if (from) - from = PREV_INSN (last); + if (min_address > mp->min_address) + mp->min_address = min_address; + } + else + { + /* We will adjust this below if it is too loose. */ + mp->min_address = min_address; + + /* Unlink MP from its current position. Since min_mp is non-null, + mp->next must be non-null. */ + mp->next->prev = mp->prev; + if (mp->prev != NULL) + mp->prev->next = mp->next; + else + minipool_vector_head = mp->next; + + /* Reinsert it after MIN_MP. */ + mp->prev = min_mp; + mp->next = min_mp->next; + min_mp->next = mp; + if (mp->next != NULL) + mp->next->prev = mp; else - from = get_last_insn (); + minipool_vector_tail = mp; + } + + min_mp = mp; + + offset = 0; + for (mp = minipool_vector_head; mp != NULL; mp = mp->next) + { + mp->offset = offset; + if (mp->refcount > 0) + offset += mp->fix_size; + + if (mp->next && mp->next->min_address < mp->min_address + mp->fix_size) + mp->next->min_address = mp->min_address + mp->fix_size; + } + + return min_mp; +} + +/* Add a constant to the minipool for a backward reference. Returns the + node added or NULL if the constant will not fit in this pool. + + Note that the code for insertion for a backwards reference can be + somewhat confusing because the calculated offsets for each fix do + not take into account the size of the pool (which is still under + construction. */ +static Mnode * +add_minipool_backward_ref (fix) + Mfix * fix; +{ + /* If set, min_mp is the last pool_entry that has a lower constraint + than the one we are trying to add. */ + Mnode * min_mp = NULL; + /* This can be negative, since it is only a constraint. */ + HOST_WIDE_INT min_address = fix->address - fix->backwards; + Mnode * mp; + + /* If we can't reach the current pool from this insn, or if we can't + insert this entry at the end of the pool without pushing other + fixes out of range, then we don't try. This ensures that we + can't fail later on. */ + if (min_address >= minipool_barrier->address + || (minipool_vector_tail->min_address + fix->fix_size + >= minipool_barrier->address)) + return NULL; + + /* Scan the pool to see if a constant with the same value has + already been added. While we are doing this, also note the + location where we must insert the constant if it doesn't already + exist. */ + for (mp = minipool_vector_tail; mp != NULL; mp = mp->prev) + { + if (GET_CODE (fix->value) == GET_CODE (mp->value) + && fix->mode == mp->mode + && (GET_CODE (fix->value) != CODE_LABEL + || (CODE_LABEL_NUMBER (fix->value) + == CODE_LABEL_NUMBER (mp->value))) + && rtx_equal_p (fix->value, mp->value) + /* Check that there is enough slack to move this entry to the + end of the table (this is conservative). */ + && (mp->max_address + > (minipool_barrier->address + + minipool_vector_tail->offset + + minipool_vector_tail->fix_size))) + { + mp->refcount++; + return move_minipool_fix_backward_ref (mp, min_mp, min_address); + } + + if (min_mp != NULL) + mp->min_address += fix->fix_size; + else + { + /* Note the insertion point if necessary. */ + if (mp->min_address < min_address) + min_mp = mp; + else if (mp->max_address + < minipool_barrier->address + mp->offset + fix->fix_size) + { + /* Inserting before this entry would push the fix beyond + its maximum address (which can happen if we have + re-located a forwards fix); force the new fix to come + after it. */ + min_mp = mp; + min_address = mp->min_address + fix->fix_size; + } + } + } + + /* We need to create a new entry. */ + mp = xmalloc (sizeof (* mp)); + mp->fix_size = fix->fix_size; + mp->mode = fix->mode; + mp->value = fix->value; + mp->refcount = 1; + mp->max_address = minipool_barrier->address + 65536; + + mp->min_address = min_address; + + if (min_mp == NULL) + { + mp->prev = NULL; + mp->next = minipool_vector_head; + + if (mp->next == NULL) + { + minipool_vector_tail = mp; + minipool_vector_label = gen_label_rtx (); + } + else + mp->next->prev = mp; + + minipool_vector_head = mp; + } + else + { + mp->next = min_mp->next; + mp->prev = min_mp; + min_mp->next = mp; - /* 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); + if (mp->next != NULL) + mp->next->prev = mp; + else + minipool_vector_tail = mp; + } + + /* Save the new entry. */ + min_mp = mp; + + if (mp->prev) + mp = mp->prev; + else + mp->offset = 0; + + /* Scan over the following entries and adjust their offsets. */ + while (mp->next != NULL) + { + if (mp->next->min_address < mp->min_address + mp->fix_size) + mp->next->min_address = mp->min_address + mp->fix_size; + + if (mp->refcount) + mp->next->offset = mp->offset + mp->fix_size; + else + mp->next->offset = mp->offset; + + mp = mp->next; + } + + return min_mp; +} + +static void +assign_minipool_offsets (barrier) + Mfix * barrier; +{ + HOST_WIDE_INT offset = 0; + Mnode * mp; + + minipool_barrier = barrier; + + for (mp = minipool_vector_head; mp != NULL; mp = mp->next) + { + mp->offset = offset; - 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); + if (mp->refcount > 0) + offset += mp->fix_size; + } +} + +/* Output the literal table */ +static void +dump_minipool (scan) + rtx scan; +{ + Mnode * mp; + Mnode * nmp; + + if (rtl_dump_file) + fprintf (rtl_dump_file, + ";; Emitting minipool after insn %u; address %ld\n", + INSN_UID (scan), (unsigned long) minipool_barrier->address); + + scan = emit_label_after (gen_label_rtx (), scan); + scan = emit_insn_after (gen_align_4 (), scan); + scan = emit_label_after (minipool_vector_label, scan); + + for (mp = minipool_vector_head; mp != NULL; mp = nmp) + { + if (mp->refcount > 0) + { + if (rtl_dump_file) + { + fprintf (rtl_dump_file, + ";; Offset %u, min %ld, max %ld ", + (unsigned) mp->offset, (unsigned long) mp->min_address, + (unsigned long) mp->max_address); + arm_print_value (rtl_dump_file, mp->value); + fputc ('\n', rtl_dump_file); + } + + switch (mp->fix_size) + { +#ifdef HAVE_consttable_1 + case 1: + scan = emit_insn_after (gen_consttable_1 (mp->value), scan); + break; + +#endif +#ifdef HAVE_consttable_2 + case 2: + scan = emit_insn_after (gen_consttable_2 (mp->value), scan); + break; + +#endif +#ifdef HAVE_consttable_4 + case 4: + scan = emit_insn_after (gen_consttable_4 (mp->value), scan); + break; + +#endif +#ifdef HAVE_consttable_8 + case 8: + scan = emit_insn_after (gen_consttable_8 (mp->value), scan); + break; + +#endif + default: + abort (); + break; + } + } + + nmp = mp->next; + free (mp); } - return found_barrier; + minipool_vector_head = minipool_vector_tail = NULL; + scan = emit_insn_after (gen_consttable_end (), scan); + scan = emit_barrier_after (scan); } -struct minipool_fixup +/* Return the cost of forcibly inserting a barrier after INSN. */ +static int +arm_barrier_cost (insn) + rtx insn; { - struct minipool_fixup *next; - rtx insn; - int address; - rtx *loc; - enum machine_mode mode; - rtx value; - int range; -}; - -struct minipool_fixup *minipool_fix_head; -struct minipool_fixup *minipool_fix_tail; + /* Basing the location of the pool on the loop depth is preferable, + but at the moment, the basic block information seems to be + corrupt by this stage of the compilation. */ + int base_cost = 50; + rtx next = next_nonnote_insn (insn); + + if (next != NULL && GET_CODE (next) == CODE_LABEL) + base_cost -= 20; + + switch (GET_CODE (insn)) + { + case CODE_LABEL: + /* It will always be better to place the table before the label, rather + than after it. */ + return 50; + case INSN: + case CALL_INSN: + return base_cost; + + case JUMP_INSN: + return base_cost - 10; + + default: + return base_cost + 10; + } +} + +/* Find the best place in the insn stream in the range + (FIX->address,MAX_ADDRESS) to forcibly insert a minipool barrier. + Create the barrier by inserting a jump and add a new fix entry for + it. */ +static Mfix * +create_fix_barrier (fix, max_address) + Mfix * fix; + HOST_WIDE_INT max_address; +{ + HOST_WIDE_INT count = 0; + rtx barrier; + rtx from = fix->insn; + rtx selected = from; + int selected_cost; + HOST_WIDE_INT selected_address; + Mfix * new_fix; + HOST_WIDE_INT max_count = max_address - fix->address; + rtx label = gen_label_rtx (); + + selected_cost = arm_barrier_cost (from); + selected_address = fix->address; + + while (from && count < max_count) + { + rtx tmp; + int new_cost; + + /* This code shouldn't have been called if there was a natural barrier + within range. */ + if (GET_CODE (from) == BARRIER) + abort (); + + /* Count the length of this insn. */ + count += get_attr_length (from); + + /* If there is a jump table, add its length. */ + tmp = is_jump_table (from); + if (tmp != NULL) + { + count += get_jump_table_size (tmp); + + /* Jump tables aren't in a basic block, so base the cost on + the dispatch insn. If we select this location, we will + still put the pool after the table. */ + new_cost = arm_barrier_cost (from); + + if (count < max_count && new_cost <= selected_cost) + { + selected = tmp; + selected_cost = new_cost; + selected_address = fix->address + count; + } + + /* Continue after the dispatch table. */ + from = NEXT_INSN (tmp); + continue; + } + + new_cost = arm_barrier_cost (from); + + if (count < max_count && new_cost <= selected_cost) + { + selected = from; + selected_cost = new_cost; + selected_address = fix->address + count; + } + + from = NEXT_INSN (from); + } + + /* Create a new JUMP_INSN that branches around a barrier. */ + from = emit_jump_insn_after (gen_jump (label), selected); + JUMP_LABEL (from) = label; + barrier = emit_barrier_after (from); + emit_label_after (label, barrier); + + /* Create a minipool barrier entry for the new barrier. */ + new_fix = (Mfix *) oballoc (sizeof (* new_fix)); + new_fix->insn = barrier; + new_fix->address = selected_address; + new_fix->next = fix->next; + fix->next = new_fix; + + return new_fix; +} + +/* Record that there is a natural barrier in the insn stream at + ADDRESS. */ static void push_minipool_barrier (insn, address) rtx insn; - int address; + HOST_WIDE_INT address; { - struct minipool_fixup *fix - = (struct minipool_fixup *) oballoc (sizeof (struct minipool_fixup)); + Mfix * fix = (Mfix *) oballoc (sizeof (* fix)); fix->insn = insn; fix->address = address; @@ -4543,21 +5358,26 @@ push_minipool_barrier (insn, address) minipool_fix_tail = fix; } +/* Record INSN, which will need fixing up to load a value from the + minipool. ADDRESS is the offset of the insn since the start of the + function; LOC is a pointer to the part of the insn which requires + fixing; VALUE is the constant that must be loaded, which is of type + MODE. */ static void push_minipool_fix (insn, address, loc, mode, value) rtx insn; - int address; - rtx *loc; + HOST_WIDE_INT address; + rtx * loc; enum machine_mode mode; rtx value; { - struct minipool_fixup *fix - = (struct minipool_fixup *) oballoc (sizeof (struct minipool_fixup)); + Mfix * fix = (Mfix *) oballoc (sizeof (* fix)); #ifdef AOF_ASSEMBLER /* PIC symbol refereneces need to be converted into offsets into the based area. */ - if (flag_pic && GET_MODE == SYMBOL_REF) + /* XXX This shouldn't be done here. */ + if (flag_pic && GET_CODE (value) == SYMBOL_REF) value = aof_pic_entry (value); #endif /* AOF_ASSEMBLER */ @@ -4565,17 +5385,32 @@ push_minipool_fix (insn, address, loc, mode, value) fix->address = address; fix->loc = loc; fix->mode = mode; + fix->fix_size = MINIPOOL_FIX_SIZE (mode); fix->value = value; - fix->range = get_attr_pool_range (insn); + fix->forwards = get_attr_pool_range (insn); + fix->backwards = get_attr_neg_pool_range (insn); + fix->minipool = NULL; /* If an insn doesn't have a range defined for it, then it isn't expecting to be reworked by this code. Better to abort now than to generate duff assembly code. */ - if (fix->range == 0) + if (fix->forwards == 0 && fix->backwards == 0) abort (); + if (rtl_dump_file) + { + fprintf (rtl_dump_file, + ";; %smode fixup for i%d; addr %lu, range (%ld,%ld): ", + GET_MODE_NAME (mode), + INSN_UID (insn), (unsigned long) address, + -1 * (long)fix->backwards, (long)fix->forwards); + arm_print_value (rtl_dump_file, fix->value); + fprintf (rtl_dump_file, "\n"); + } + /* Add it to the chain of fixes. */ fix->next = NULL; + if (minipool_fix_head != NULL) minipool_fix_tail->next = fix; else @@ -4584,21 +5419,21 @@ push_minipool_fix (insn, address, loc, mode, value) minipool_fix_tail = fix; } +/* Scan INSN and note any of its operands that need fixing. */ static void note_invalid_constants (insn, address) rtx insn; - int address; + HOST_WIDE_INT address; { int opno; - /* Extract the operands of the insn. */ - extract_insn(insn); + extract_insn (insn); - /* Find the alternative selected. */ if (! constrain_operands (1)) fatal_insn_not_found (insn); - /* Preprocess the constraints, to extract some useful information. */ + /* Fill in recog_op_alt with information about the constraints of this + insn. */ preprocess_constraints (); for (opno = 0; opno < recog_data.n_operands; opno++) @@ -4618,14 +5453,18 @@ note_invalid_constants (insn, address) if (CONSTANT_P (op)) push_minipool_fix (insn, address, recog_data.operand_loc[opno], recog_data.operand_mode[opno], op); +#if 0 + /* RWE: Now we look correctly at the operands for the insn, + this shouldn't be needed any more. */ #ifndef AOF_ASSEMBLER + /* XXX Is this still needed? */ else if (GET_CODE (op) == UNSPEC && XINT (op, 1) == 3) push_minipool_fix (insn, address, recog_data.operand_loc[opno], recog_data.operand_mode[opno], XVECEXP (op, 0, 0)); #endif - else if (recog_data.operand_mode[opno] == SImode - && GET_CODE (op) == MEM +#endif + else if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (XEXP (op, 0))) push_minipool_fix (insn, address, recog_data.operand_loc[opno], @@ -4640,8 +5479,8 @@ arm_reorg (first) rtx first; { rtx insn; - int address = 0; - struct minipool_fixup *fix; + HOST_WIDE_INT address = 0; + Mfix * fix; minipool_fix_head = minipool_fix_tail = NULL; @@ -4655,7 +5494,7 @@ arm_reorg (first) { if (GET_CODE (insn) == BARRIER) - push_minipool_barrier(insn, address); + push_minipool_barrier (insn, address); else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) { @@ -4663,104 +5502,121 @@ arm_reorg (first) note_invalid_constants (insn, address); address += get_attr_length (insn); + /* If the insn is a vector jump, add the size of the table and skip the table. */ - if (GET_CODE (insn) == JUMP_INSN - && JUMP_LABEL (insn) != NULL - && ((table = next_real_insn (JUMP_LABEL (insn))) - == next_real_insn (insn)) - && table != NULL - && GET_CODE (table) == JUMP_INSN - && (GET_CODE (PATTERN (table)) == ADDR_VEC - || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC)) + if ((table = is_jump_table (insn)) != NULL) { - int elt = GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC ? 1 : 0; - - address += GET_MODE_SIZE (SImode) * XVECLEN (PATTERN (table), - elt); + address += get_jump_table_size (table); insn = table; } } } + fix = minipool_fix_head; + /* Now scan the fixups and perform the required changes. */ - for (fix = minipool_fix_head; fix; fix = fix->next) + while (fix) { - struct minipool_fixup *ftmp; - struct minipool_fixup *last_barrier = NULL; - int max_range; - rtx barrier; - struct minipool_fixup *this_fix; - int new_minipool_size = 0; + Mfix * ftmp; + Mfix * fdel; + Mfix * last_added_fix; + Mfix * last_barrier = NULL; + Mfix * this_fix; /* Skip any further barriers before the next fix. */ while (fix && GET_CODE (fix->insn) == BARRIER) fix = fix->next; + /* No more fixes. */ if (fix == NULL) break; - ftmp = fix; - max_range = fix->address + fix->range; + last_added_fix = NULL; - /* Find all the other fixes that can live in the same pool. */ - while (ftmp->next && ftmp->next->address < max_range - && (GET_CODE (ftmp->next->insn) == BARRIER - /* Ensure we can reach the constant inside the pool. */ - || ftmp->next->range > new_minipool_size)) + for (ftmp = fix; ftmp; ftmp = ftmp->next) { - ftmp = ftmp->next; if (GET_CODE (ftmp->insn) == BARRIER) - last_barrier = ftmp; - else { - /* Does this fix constrain the range we can search? */ - if (ftmp->address + ftmp->range - new_minipool_size < max_range) - max_range = ftmp->address + ftmp->range - new_minipool_size; + if (ftmp->address >= minipool_vector_head->max_address) + break; - new_minipool_size += GET_MODE_SIZE (ftmp->mode); + last_barrier = ftmp; } + else if ((ftmp->minipool = add_minipool_forward_ref (ftmp)) == NULL) + break; + + last_added_fix = ftmp; /* Keep track of the last fix added. */ } - /* If we found a barrier, drop back to that; any fixes that we could - have reached but come after the barrier will now go in the next - mini-pool. */ + /* If we found a barrier, drop back to that; any fixes that we + could have reached but come after the barrier will now go in + the next mini-pool. */ if (last_barrier != NULL) { - barrier = last_barrier->insn; + /* Reduce the refcount for those fixes that won't go into this + pool after all. */ + for (fdel = last_barrier->next; + fdel && fdel != ftmp; + fdel = fdel->next) + { + fdel->minipool->refcount--; + fdel->minipool = NULL; + } + ftmp = last_barrier; } - /* ftmp is last fix that we can fit into this pool and we - failed to find a barrier that we could use. Insert a new - barrier in the code and arrange to jump around it. */ else { + /* ftmp is first fix that we can't fit into this pool and + there no natural barriers that we could use. Insert a + new barrier in the code somewhere between the previous + fix and this one, and arrange to jump around it. */ + HOST_WIDE_INT max_address; + + /* The last item on the list of fixes must be a barrier, so + we can never run off the end of the list of fixes without + last_barrier being set. */ + if (ftmp == NULL) + abort (); + + max_address = minipool_vector_head->max_address; /* Check that there isn't another fix that is in range that we couldn't fit into this pool because the pool was already too large: we need to put the pool before such an instruction. */ - if (ftmp->next && ftmp->next->address < max_range) - max_range = ftmp->address; + if (ftmp->address < max_address) + max_address = ftmp->address; + + last_barrier = create_fix_barrier (last_added_fix, max_address); + } + + assign_minipool_offsets (last_barrier); + + while (ftmp) + { + if (GET_CODE (ftmp->insn) != BARRIER + && ((ftmp->minipool = add_minipool_backward_ref (ftmp)) + == NULL)) + break; - barrier = find_barrier (ftmp->insn, max_range - ftmp->address); + ftmp = ftmp->next; } /* Scan over the fixes we have identified for this pool, fixing them up and adding the constants to the pool itself. */ - for (this_fix = fix; this_fix && ftmp->next != this_fix; + for (this_fix = fix; this_fix && ftmp != this_fix; this_fix = this_fix->next) if (GET_CODE (this_fix->insn) != BARRIER) { - int offset = add_minipool_constant (this_fix->value, - this_fix->mode); rtx addr = plus_constant (gen_rtx_LABEL_REF (VOIDmode, minipool_vector_label), - offset); + this_fix->minipool->offset); *this_fix->loc = gen_rtx_MEM (this_fix->mode, addr); } - dump_minipool (barrier); + dump_minipool (last_barrier->insn); fix = ftmp; } @@ -4769,7 +5625,6 @@ arm_reorg (first) instruction generation. */ after_arm_reorg = 1; } - /* Routines to output assembly language. */ @@ -4816,7 +5671,7 @@ fp_const_from_val (r) INSTR is the possibly suffixed base register. HAT unequals zero if a hat must follow the register list. */ -void +static void print_multi_reg (stream, instr, reg, mask, hat) FILE * stream; char * instr; @@ -4831,7 +5686,7 @@ print_multi_reg (stream, instr, reg, mask, hat) asm_fprintf (stream, instr, reg); fputs (", {", stream); - for (i = 0; i < 16; i++) + for (i = 0; i <= LAST_ARM_REGNUM; i++) if (mask & (1 << i)) { if (not_first) @@ -5094,8 +5949,8 @@ output_move_double (operands) bcopy ((char *) &CONST_DOUBLE_LOW (operands[1]), (char *) &u, sizeof (u)); REAL_VALUE_TO_TARGET_DOUBLE (u.d, l); - otherops[1] = GEN_INT(l[1]); - operands[1] = GEN_INT(l[0]); + otherops[1] = GEN_INT (l[1]); + operands[1] = GEN_INT (l[0]); } else if (GET_MODE (operands[1]) != VOIDmode) abort (); @@ -5324,11 +6179,10 @@ output_mov_immediate (operands) n_ones++; if (n_ones > 16) /* Shorter to use MVN with BIC in this case. */ - output_multi_immediate(operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1, - ~n); + output_multi_immediate (operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1, + ~n); else - output_multi_immediate(operands, "mov%?\t%0, %1", "orr%?\t%0, %0, %1", 1, - n); + output_multi_immediate (operands, "mov%?\t%0, %1", "orr%?\t%0, %0, %1", 1, n); return ""; } @@ -5373,7 +6227,7 @@ output_multi_immediate (operands, instr1, instr2, immed_op, n) HOST_WIDE_INT n; { #if HOST_BITS_PER_WIDE_INT > 32 - n &= 0xffffffff; + n &= (unsigned HOST_WIDE_INT)0xffffffff; #endif if (n == 0) @@ -5739,6 +6593,7 @@ function_really_clobbers_lr (first) if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == USE && (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) + && (GET_CODE (XEXP (PATTERN (next), 0)) == REG) && (REGNO (SET_DEST (XVECEXP (PATTERN (insn), 0, 0))) == REGNO (XEXP (PATTERN (next), 0)))) if ((next = next_nonnote_insn (next)) == NULL) @@ -5768,8 +6623,12 @@ output_return_instruction (operand, really_return, reverse) int reg, live_regs = 0; int volatile_func = arm_volatile_func (); + /* 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; - + if (TARGET_ABORT_NORETURN && volatile_func) { /* If this function was declared non-returning, and we have found a tail @@ -5791,11 +6650,17 @@ output_return_instruction (operand, really_return, reverse) if (current_function_calls_alloca && ! really_return) abort (); - + for (reg = 0; reg <= 10; reg++) if (regs_ever_live[reg] && ! call_used_regs[reg]) live_regs++; + if (! TARGET_APCS_FRAME + && ! frame_pointer_needed + && regs_ever_live[HARD_FRAME_POINTER_REGNUM] + && ! call_used_regs[HARD_FRAME_POINTER_REGNUM]) + live_regs++; + if (flag_pic && ! TARGET_SINGLE_PIC_BASE && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) live_regs++; @@ -5814,10 +6679,14 @@ output_return_instruction (operand, really_return, reverse) /* FIXME: We ought to handle the case TARGET_APCS_32 is true, really_return is true, and only the PC needs restoring. */ && ! really_return) - { - output_asm_insn (reverse ? "ldr%?%D0\t%|lr, [%|sp], #4" - : "ldr%?%d0\t%|lr, [%|sp], #4", &operand); - } + output_asm_insn (reverse ? "ldr%?%D0\t%|lr, [%|sp], #4" + : "ldr%?%d0\t%|lr, [%|sp], #4", &operand); + else if (live_regs == 1 + && regs_ever_live[LR_REGNUM] + && ! lr_save_eliminated + && TARGET_APCS_32) + output_asm_insn (reverse ? "ldr%?%D0\t%|pc, [%|sp], #4" + : "ldr%?%d0\t%|pc, [%|sp], #4", &operand); else if (live_regs) { if (lr_save_eliminated || ! regs_ever_live[LR_REGNUM]) @@ -5856,12 +6725,23 @@ output_return_instruction (operand, really_return, reverse) } else { + if (! TARGET_APCS_FRAME + && regs_ever_live[HARD_FRAME_POINTER_REGNUM] + && ! call_used_regs[HARD_FRAME_POINTER_REGNUM]) + { + strcat (instr, "%|"); + strcat (instr, reg_names[HARD_FRAME_POINTER_REGNUM]); + strcat (instr, ", "); + } + strcat (instr, "%|"); + if (TARGET_INTERWORK && really_return) strcat (instr, reg_names[IP_REGNUM]); else strcat (instr, really_return ? reg_names[PC_REGNUM] : reg_names[LR_REGNUM]); } + strcat (instr, (TARGET_APCS_32 || !really_return) ? "}" : "}^"); output_asm_insn (instr, &operand); @@ -5938,12 +6818,12 @@ arm_poke_function_name (stream, name) unsigned long length; rtx x; - length = strlen (name) + 1; - alignlength = (length + 3) & ~3; + length = strlen (name) + 1; + alignlength = ROUND_UP (length); ASM_OUTPUT_ASCII (stream, name, length); ASM_OUTPUT_ALIGN (stream, 2); - x = GEN_INT (0xff000000UL + alignlength); + x = GEN_INT (((unsigned HOST_WIDE_INT)0xff000000) + alignlength); ASM_OUTPUT_INT (stream, x); } @@ -5956,7 +6836,7 @@ arm_poke_function_name (stream, name) lr is not clobbered in any other way, then there is no need to push lr onto the stack. */ void -output_func_prologue (f, frame_size) +output_arm_prologue (f, frame_size) FILE * f; int frame_size; { @@ -5993,6 +6873,12 @@ output_func_prologue (f, frame_size) if (regs_ever_live[reg] && ! call_used_regs[reg]) live_regs_mask |= (1 << reg); + if (! TARGET_APCS_FRAME + && ! frame_pointer_needed + && regs_ever_live[HARD_FRAME_POINTER_REGNUM] + && ! call_used_regs[HARD_FRAME_POINTER_REGNUM]) + live_regs_mask |= (1 << HARD_FRAME_POINTER_REGNUM); + if (flag_pic && ! TARGET_SINGLE_PIC_BASE && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) live_regs_mask |= (1 << PIC_OFFSET_TABLE_REGNUM); @@ -6037,8 +6923,11 @@ arm_output_epilogue () int floats_offset = 12; rtx operands[3]; int frame_size = get_frame_size (); - FILE *f = asm_out_file; - int volatile_func = arm_volatile_func (); + rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs; + FILE * f = asm_out_file; + int volatile_func = (optimize > 0 + && TREE_THIS_VOLATILE (current_function_decl)); + int return_regnum; if (use_return_insn (FALSE) && return_used_this_function) return ""; @@ -6047,6 +6936,10 @@ arm_output_epilogue () if (arm_naked_function_p (current_function_decl)) return ""; + /* If we are throwing an exception, the address we want to jump to is in + R1; otherwise, it's in LR. */ + return_regnum = eh_ofs ? 2 : LR_REGNUM; + /* A volatile function should never return. Call abort. */ if (TARGET_ABORT_NORETURN && volatile_func) { @@ -6064,6 +6957,16 @@ arm_output_epilogue () floats_offset += 4; } + /* Handle the frame pointer as a special case. */ + if (! TARGET_APCS_FRAME + && ! frame_pointer_needed + && regs_ever_live[HARD_FRAME_POINTER_REGNUM] + && ! call_used_regs[HARD_FRAME_POINTER_REGNUM]) + { + live_regs_mask |= (1 << HARD_FRAME_POINTER_REGNUM); + floats_offset += 4; + } + /* If we aren't loading the PIC register, don't stack it even though it may be live. */ if (flag_pic && ! TARGET_SINGLE_PIC_BASE @@ -6077,7 +6980,7 @@ arm_output_epilogue () { if (arm_fpu_arch == FP_SOFT2) { - for (reg = 23; reg > 15; reg--) + for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--) if (regs_ever_live[reg] && ! call_used_regs[reg]) { floats_offset += 12; @@ -6087,9 +6990,9 @@ arm_output_epilogue () } else { - int start_reg = 23; + int start_reg = LAST_ARM_FP_REGNUM; - for (reg = 23; reg > 15; reg--) + for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--) { if (regs_ever_live[reg] && ! call_used_regs[reg]) { @@ -6124,7 +7027,20 @@ arm_output_epilogue () { live_regs_mask |= 0x6800; print_multi_reg (f, "ldmea\t%r", FP_REGNUM, live_regs_mask, FALSE); - asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM); + if (eh_ofs) + asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM, + REGNO (eh_ofs)); + asm_fprintf (f, "\tbx\t%r\n", return_regnum); + } + else if (eh_ofs) + { + live_regs_mask |= 0x6800; + print_multi_reg (f, "ldmea\t%r", FP_REGNUM, live_regs_mask, FALSE); + asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM, + REGNO (eh_ofs)); + /* Even in 26-bit mode we do a mov (rather than a movs) because + we don't have the PSR bits set in the address. */ + asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum); } else { @@ -6146,16 +7062,16 @@ arm_output_epilogue () if (arm_fpu_arch == FP_SOFT2) { - for (reg = 16; reg < 24; reg++) + for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++) if (regs_ever_live[reg] && ! call_used_regs[reg]) asm_fprintf (f, "\tldfe\t%r, [%r], #12\n", reg, SP_REGNUM); } else { - int start_reg = 16; + int start_reg = FIRST_ARM_FP_REGNUM; - for (reg = 16; reg < 24; reg++) + for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++) { if (regs_ever_live[reg] && ! call_used_regs[reg]) { @@ -6190,17 +7106,48 @@ arm_output_epilogue () if (! lr_save_eliminated) live_regs_mask |= 1 << LR_REGNUM; - if (live_regs_mask != 0) - print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, live_regs_mask, FALSE); - - asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM); + /* Handle LR on its own. */ + if (live_regs_mask == (1 << LR_REGNUM)) + { + if (eh_ofs) + asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, + SP_REGNUM); + else + asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, + SP_REGNUM); + } + else if (live_regs_mask != 0) + print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, live_regs_mask, + FALSE); + + if (eh_ofs) + asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM, + REGNO (eh_ofs)); + + asm_fprintf (f, "\tbx\t%r\n", return_regnum); } else if (lr_save_eliminated) - asm_fprintf (f, + asm_fprintf (f, TARGET_APCS_32 ? "\tmov\t%r, %r\n" : "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM); + else if (eh_ofs) + { + if (live_regs_mask == 0) + asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM); + else + print_multi_reg (f, "\tldmfd\t%r!", SP_REGNUM, + live_regs_mask | (1 << LR_REGNUM), FALSE); + + asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM, + REGNO (eh_ofs)); + /* Jump to the target; even in 26-bit mode. */ + asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum); + } + else if (TARGET_APCS_32 && live_regs_mask == 0) + asm_fprintf (f, "\tldr\t%r, [%r], #4\n", PC_REGNUM, SP_REGNUM); else - print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, live_regs_mask | 0x8000, + print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, + live_regs_mask | (1 << PC_REGNUM), TARGET_APCS_32 ? FALSE : TRUE); } else @@ -6211,8 +7158,18 @@ arm_output_epilogue () if (! lr_save_eliminated) live_regs_mask |= 1 << LR_REGNUM; - if (live_regs_mask != 0) - print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, live_regs_mask, FALSE); + if (live_regs_mask == (1 << LR_REGNUM)) + { + if (eh_ofs) + asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, + SP_REGNUM); + else + asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, + SP_REGNUM); + } + else if (live_regs_mask != 0) + print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, live_regs_mask, + FALSE); } if (current_function_pretend_args_size) @@ -6222,13 +7179,18 @@ arm_output_epilogue () operands[2] = GEN_INT (current_function_pretend_args_size); output_add_immediate (operands); } + + if (eh_ofs) + asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM, + REGNO (eh_ofs)); + /* And finally, go home. */ if (TARGET_INTERWORK) - asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM); - else if (TARGET_APCS_32) - asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM); + asm_fprintf (f, "\tbx\t%r\n", return_regnum); + else if (TARGET_APCS_32 || eh_ofs) + asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum); else - asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM); + asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, return_regnum); } } @@ -6239,14 +7201,25 @@ void output_func_epilogue (frame_size) int frame_size; { - if (use_return_insn (FALSE) && return_used_this_function - && (frame_size + current_function_outgoing_args_size) != 0 - && ! (frame_pointer_needed && TARGET_APCS)) - abort (); + if (TARGET_THUMB) + { + /* ??? 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; + } + else + { + if (use_return_insn (FALSE) + && return_used_this_function + && (frame_size + current_function_outgoing_args_size) != 0 + && ! frame_pointer_needed) + abort (); - /* Reset the ARM-specific per-function variables. */ - current_function_anonymous_args = 0; - after_arm_reorg = 0; + /* Reset the ARM-specific per-function variables. */ + current_function_anonymous_args = 0; + after_arm_reorg = 0; + } } /* Generate and emit an insn that we will recognize as a push_multi. @@ -6263,9 +7236,9 @@ emit_multi_reg_push (mask) rtx dwarf; rtx tmp, reg; - for (i = 0; i < 16; i++) + for (i = 0; i <= LAST_ARM_REGNUM; i++) if (mask & (1 << i)) - num_regs++; + num_regs ++; if (num_regs == 0 || num_regs > 16) abort (); @@ -6274,7 +7247,7 @@ emit_multi_reg_push (mask) dwarf = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs)); RTX_FRAME_RELATED_P (dwarf) = 1; - for (i = 0; i < 16; i++) + for (i = 0; i <= LAST_ARM_REGNUM; i++) { if (mask & (1 << i)) { @@ -6404,6 +7377,12 @@ arm_expand_prologue () if (regs_ever_live[reg] && ! call_used_regs[reg]) live_regs_mask |= 1 << reg; + if (! TARGET_APCS_FRAME + && ! frame_pointer_needed + && regs_ever_live[HARD_FRAME_POINTER_REGNUM] + && ! call_used_regs[HARD_FRAME_POINTER_REGNUM]) + live_regs_mask |= 1 << HARD_FRAME_POINTER_REGNUM; + if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) live_regs_mask |= 1 << PIC_OFFSET_TABLE_REGNUM; @@ -6440,12 +7419,13 @@ arm_expand_prologue () RTX_FRAME_RELATED_P (insn) = 1; } - /* And now the floating point regs. */ + /* For now the integer regs are still pushed in output_arm_epilogue (). */ + if (! volatile_func) { if (arm_fpu_arch == FP_SOFT2) { - for (reg = 23; reg > 15; reg--) + for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg --) if (regs_ever_live[reg] && ! call_used_regs[reg]) { insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx); @@ -6457,9 +7437,9 @@ arm_expand_prologue () } else { - int start_reg = 23; + int start_reg = LAST_ARM_FP_REGNUM; - for (reg = 23; reg > 15; reg--) + for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg --) { if (regs_ever_live[reg] && ! call_used_regs[reg]) { @@ -6541,6 +7521,10 @@ arm_print_operand (stream, x, code) fputs (ASM_COMMENT_START, stream); return; + case '_': + fputs (user_label_prefix, stream); + return; + case '|': fputs (REGISTER_PREFIX, stream); return; @@ -6600,44 +7584,84 @@ arm_print_operand (stream, x, code) } 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) + if (REGNO (x) > LAST_ARM_REGNUM) abort (); - fputs (REGISTER_PREFIX, stream); - fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], stream); + asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)); return; case 'R': - if (REGNO (x) > 15) + if (REGNO (x) > LAST_ARM_REGNUM) abort (); - fputs (REGISTER_PREFIX, stream); - fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], stream); + asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)); + return; + + case 'H': + if (REGNO (x) > LAST_ARM_REGNUM) + abort (); + asm_fprintf (stream, "%r", REGNO (x) + 1); return; case 'm': - fputs (REGISTER_PREFIX, stream); - if (GET_CODE (XEXP (x, 0)) == REG) - fputs (reg_names[REGNO (XEXP (x, 0))], stream); - else - fputs (reg_names[REGNO (XEXP (XEXP (x, 0), 0))], stream); + asm_fprintf (stream, "%r", + GET_CODE (XEXP (x, 0)) == REG + ? REGNO (XEXP (x, 0)) : REGNO (XEXP (XEXP (x, 0), 0))); return; case 'M': asm_fprintf (stream, "{%r-%r}", - REGNO (x), REGNO (x) + NUM_REGS (GET_MODE (x)) - 1); + REGNO (x), + REGNO (x) + NUM_REGS (GET_MODE (x)) - 1); return; case 'd': - if (x) + if (! x) + return; + + if (TARGET_ARM) fputs (arm_condition_codes[get_arm_condition_code (x)], stream); + else + fputs (thumb_condition_code (x, 0), stream); return; case 'D': - if (x) - fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE - (get_arm_condition_code (x))], + if (! x) + return; + + if (TARGET_ARM) + fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE + (get_arm_condition_code (x))], stream); + else + fputs (thumb_condition_code (x, 1), stream); return; default: @@ -6645,10 +7669,7 @@ arm_print_operand (stream, x, code) abort (); if (GET_CODE (x) == REG) - { - fputs (REGISTER_PREFIX, stream); - fputs (reg_names[REGNO (x)], stream); - } + asm_fprintf (stream, "%r", REGNO (x)); else if (GET_CODE (x) == MEM) { output_memory_reference_mode = GET_MODE (x); @@ -7136,7 +8157,7 @@ arm_final_prescan_insn (insn) if (reverse || then_not_else) arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); } - + /* Restore recog_data (getting the attributes of other insns can destroy this array, but final.c assumes that it remains intact across this call; since the insn has been recognized already we @@ -7145,6 +8166,1547 @@ arm_final_prescan_insn (insn) } } +int +arm_regno_class (regno) + int regno; +{ + if (TARGET_THUMB) + { + if (regno == STACK_POINTER_REGNUM) + return STACK_REG; + if (regno == CC_REGNUM) + return CC_REG; + if (regno < 8) + return LO_REGS; + return HI_REGS; + } + + if ( regno <= LAST_ARM_REGNUM + || regno == FRAME_POINTER_REGNUM + || regno == ARG_POINTER_REGNUM) + return GENERAL_REGS; + + if (regno == CC_REGNUM) + return NO_REGS; + + return FPU_REGS; +} + +/* Handle a special case when computing the offset + of an argument from the frame pointer. */ +int +arm_debugger_arg_offset (value, addr) + int value; + rtx addr; +{ + rtx insn; + + /* We are only interested if dbxout_parms() failed to compute the offset. */ + if (value != 0) + return 0; + + /* We can only cope with the case where the address is held in a register. */ + if (GET_CODE (addr) != REG) + return 0; + + /* If we are using the frame pointer to point at the argument, then + an offset of 0 is correct. */ + if (REGNO (addr) == HARD_FRAME_POINTER_REGNUM) + return 0; + + /* If we are using the stack pointer to point at the + argument, then an offset of 0 is correct. */ + if ((TARGET_THUMB || ! frame_pointer_needed) + && REGNO (addr) == SP_REGNUM) + return 0; + + /* Oh dear. The argument is pointed to by a register rather + than being held in a register, or being stored at a known + offset from the frame pointer. Since GDB only understands + those two kinds of argument we must translate the address + held in the register into an offset from the frame pointer. + We do this by searching through the insns for the function + looking to see where this register gets its value. If the + register is initialised from the frame pointer plus an offset + then we are in luck and we can continue, otherwise we give up. + + This code is exercised by producing debugging information + for a function with arguments like this: + + double func (double a, double b, int c, double d) {return d;} + + Without this code the stab for parameter 'd' will be set to + an offset of 0 from the frame pointer, rather than 8. */ + + /* The if() statement says: + + If the insn is a normal instruction + and if the insn is setting the value in a register + and if the register being set is the register holding the address of the argument + and if the address is computing by an addition + that involves adding to a register + which is the frame pointer + a constant integer + + then... */ + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if ( GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET + && REGNO (XEXP (PATTERN (insn), 0)) == REGNO (addr) + && GET_CODE (XEXP (PATTERN (insn), 1)) == PLUS + && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 0)) == REG + && REGNO (XEXP (XEXP (PATTERN (insn), 1), 0)) == HARD_FRAME_POINTER_REGNUM + && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 1)) == CONST_INT + ) + { + value = INTVAL (XEXP (XEXP (PATTERN (insn), 1), 1)); + + break; + } + } + + if (value == 0) + { + debug_rtx (addr); + warning ("Unable to compute real location of stacked parameter"); + value = 8; /* XXX magic hack */ + } + + return value; +} + + +/* 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'. */ + +static void +replace_symbols_in_block (block, orig, new) + tree block; + rtx orig; + rtx new; +{ + 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); + } +} + +/* Return the number (counting from 0) of the least significant set + bit in MASK. */ +#ifdef __GNUC__ +inline +#endif +static int +number_of_first_bit_set (mask) + int mask; +{ + int bit; + + for (bit = 0; + (mask & (1 << bit)) == 0; + ++ bit) + continue; + + return bit; +} + +/* 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, eh_ofs) + FILE * f; + int reg_containing_return_addr; + rtx eh_ofs; +{ + unsigned regs_available_for_popping; + unsigned regs_to_pop; + int pops_needed; + unsigned available; + unsigned required; + int mode; + int size; + int restore_a4 = FALSE; + + /* Compute the registers we need to pop. */ + regs_to_pop = 0; + pops_needed = 0; + + /* There is an assumption here, that if eh_ofs is not NULL, the + normal return address will have been pushed. */ + if (reg_containing_return_addr == -1 || eh_ofs) + { + /* When we are generating a return for __builtin_eh_return, + reg_containing_return_addr must specify the return regno. */ + if (eh_ofs && reg_containing_return_addr == -1) + abort (); + + regs_to_pop |= 1 << LR_REGNUM; + ++ pops_needed; + } + + if (TARGET_BACKTRACE) + { + /* Restore the (ARM) frame pointer and stack pointer. */ + regs_to_pop |= (1 << ARM_HARD_FRAME_POINTER_REGNUM) | (1 << SP_REGNUM); + pops_needed += 2; + } + + /* If there is nothing to pop then just emit the BX instruction and + return. */ + if (pops_needed == 0) + { + if (eh_ofs) + asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs)); + + asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr); + return; + } + /* Otherwise if we are not supporting interworking and we have not created + a backtrace structure and the function was not entered in ARM mode then + just pop the return address straight into the PC. */ + else if ( ! TARGET_INTERWORK + && ! TARGET_BACKTRACE + && ! is_called_in_ARM_mode (current_function_decl)) + { + if (eh_ofs) + { + asm_fprintf (f, "\tadd\t%r, #4\n", SP_REGNUM); + asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs)); + asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr); + } + else + asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM); + + return; + } + + /* Find out how many of the (return) argument registers we can corrupt. */ + regs_available_for_popping = 0; + + /* If returning via __builtin_eh_return, the bottom three registers + all contain information needed for the return. */ + if (eh_ofs) + size = 12; + else + { +#ifdef RTX_CODE + /* 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 +#endif + mode = DECL_MODE (DECL_RESULT (current_function_decl)); + + 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_REGISTER (1)) + | (1 << ARG_REGISTER (2)) + | (1 << ARG_REGISTER (3)); + else + regs_available_for_popping = + (1 << ARG_REGISTER (2)) + | (1 << ARG_REGISTER (3)); + } + else if (size <= 4) + regs_available_for_popping = + (1 << ARG_REGISTER (2)) + | (1 << ARG_REGISTER (3)); + else if (size <= 8) + regs_available_for_popping = + (1 << ARG_REGISTER (3)); + } + + /* 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 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 == LAST_ARG_REGNUM) + { + asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM); + reg_containing_return_addr = LR_REGNUM; + } + 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%r, %r\n",IP_REGNUM, LAST_ARG_REGNUM); + } + + if (reg_containing_return_addr != LAST_ARG_REGNUM) + { + /* The fourth argument register is available. */ + regs_available_for_popping |= 1 << LAST_ARG_REGNUM; + + -- pops_needed; + } + } + + /* 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) + { + /* The return address was popped into the lowest numbered register. */ + regs_to_pop &= ~ (1 << LR_REGNUM); + + 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); + } + + /* If we popped other registers then handle them here. */ + if (regs_available_for_popping) + { + 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\t%r, %r\n", + ARM_HARD_FRAME_POINTER_REGNUM, frame_pointer); + + /* (Temporarily) remove it from the mask of popped registers. */ + regs_available_for_popping &= ~ (1 << frame_pointer); + regs_to_pop &= ~ (1 << ARM_HARD_FRAME_POINTER_REGNUM); + + 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\t%r, %r\n", SP_REGNUM, 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); + } + } + + /* 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) + { + regs_available_for_popping |= 1 << reg_containing_return_addr; + + asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, + reg_containing_return_addr); + + reg_containing_return_addr = LR_REGNUM; + } + + /* 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); + + /* 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%r, %r\n", move_to, popped_into); + + regs_to_pop &= ~ (1 << move_to); + + -- 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) + { + int popped_into; + + thumb_pushpop (f, regs_available_for_popping, FALSE); + + popped_into = number_of_first_bit_set (regs_available_for_popping); + + asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, popped_into); + /* + assert (regs_to_pop == (1 << STACK_POINTER)) + assert (pops_needed == 1) + */ + } + + /* If necessary restore the a4 register. */ + if (restore_a4) + { + if (reg_containing_return_addr != LR_REGNUM) + { + asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM); + reg_containing_return_addr = LR_REGNUM; + } + + asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM); + } + + if (eh_ofs) + asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs)); + + /* Return to caller. */ + asm_fprintf (f, "\tbx\t%r\n", 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; +{ + int regno; + int lo_mask = mask & 0xFF; + + 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, NULL_RTX); + return; + } + + fprintf (f, "\t%s\t{", push ? "push" : "pop"); + + /* Look at the low registers first. */ + for (regno = 0; regno <= LAST_LO_REGNUM; regno ++, lo_mask >>= 1) + { + if (lo_mask & 1) + { + asm_fprintf (f, "%r", regno); + + if ((lo_mask & ~1) != 0) + fprintf (f, ", "); + } + } + + if (push && (mask & (1 << LR_REGNUM))) + { + /* Catch pushing the LR. */ + if (mask & 0xFF) + fprintf (f, ", "); + + asm_fprintf (f, "%r", LR_REGNUM); + } + else if (!push && (mask & (1 << PC_REGNUM))) + { + /* Catch popping the PC. */ + if (TARGET_INTERWORK || TARGET_BACKTRACE) + { + /* The PC is never poped directly, instead + it is popped into r3 and then BX is used. */ + fprintf (f, "}\n"); + + thumb_exit (f, -1, NULL_RTX); + + return; + } + else + { + if (mask & 0xFF) + fprintf (f, ", "); + + asm_fprintf (f, "%r", PC_REGNUM); + } + } + + fprintf (f, "}\n"); +} + +void +thumb_final_prescan_insn (insn) + rtx insn; +{ + extern int * insn_addresses; + + if (flag_print_asm_name) + asm_fprintf (asm_out_file, "%@ 0x%04x\n", insn_addresses[INSN_UID (insn)]); +} + +int +thumb_shiftable_const (val) + unsigned HOST_WIDE_INT val; +{ + unsigned HOST_WIDE_INT mask = 0xff; + int i; + + if (val == 0) /* XXX */ + return 0; + + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + return 1; + + return 0; +} + +/* Returns non-zero if the current function contains, + or might contain a far jump. */ +int +thumb_far_jump_used_p (int in_prologue) +{ + rtx insn; + + /* This test is only important for leaf functions. */ + /* assert (! leaf_function_p ()); */ + + /* If we have already decided that far jumps may be used, + do not bother checking again, and always return true even if + it turns out that they are not being used. Once we have made + the decision that far jumps are present (and that hence the link + register will be pushed onto the stack) we cannot go back on it. */ + if (cfun->machine->far_jump_used) + return 1; + + /* If this function is not being called from the prologue/epilogue + generation code then it must be being called from the + INITIAL_ELIMINATION_OFFSET macro. */ + if (! in_prologue) + { + /* In this case we know that we are being asked about the elimination + of the arg pointer register. If that register is not being used, + then there are no arguments on the stack, and we do not have to + worry that a far jump might force the prologue to push the link + register, changing the stack offsets. In this case we can just + return false, since the presence of far jumps in the function will + not affect stack offsets. + + If the arg pointer is live (or if it was live, but has now been + eliminated and so set to dead) then we do have to test to see if + the function might contain a far jump. This test can lead to some + false negatives, since before reload is completed, then length of + branch instructions is not known, so gcc defaults to returning their + longest length, which in turn sets the far jump attribute to true. + + A false negative will not result in bad code being generated, but it + will result in a needless push and pop of the link register. We + hope that this does not occur too often. */ + if (regs_ever_live [ARG_POINTER_REGNUM]) + cfun->machine->arg_pointer_live = 1; + else if (! cfun->machine->arg_pointer_live) + return 0; + } + + /* Check to see if the function contains a branch + insn with the far jump attribute set. */ + 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 + ) + { + /* Record the fact that we have decied that + the function does use far jumps. */ + cfun->machine->far_jump_used = 1; + return 1; + } + } + + return 0; +} + +/* Return non-zero if FUNC must be entered in ARM mode. */ +int +is_called_in_ARM_mode (func) + tree func; +{ + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + /* Ignore the problem about functions whoes address is taken. */ + if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func)) + return TRUE; + +#ifdef ARM_PE + return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; +#else + return FALSE; +#endif +} + +/* The bits which aren't usefully expanded as rtl. */ +char * +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; + rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs; + + if (return_used_this_function) + return ""; + + for (regno = 0; regno <= LAST_LO_REGNUM; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno] + && ! (TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register))) + live_regs_mask |= 1 << regno; + + for (regno = 8; regno < 13; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno] + && ! (TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register))) + 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; + +#ifdef RTX_CODE + /* 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 +#endif + 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] + && ! (TARGET_SINGLE_PIC_BASE && (next_hi_reg == arm_pic_register))) + break; + + while (high_regs_pushed) + { + /* Find lo register(s) into which the high register(s) can + be popped. */ + for (regno = 0; regno <= LAST_LO_REGNUM; 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 <= LAST_LO_REGNUM; regno++) + { + if (mask & (1 << regno)) + { + asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", next_hi_reg, + 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] + && ! (TARGET_SINGLE_PIC_BASE + && (next_hi_reg == arm_pic_register))) + break; + } + } + } + } + + had_to_push_lr = (live_regs_mask || ! leaf_function + || thumb_far_jump_used_p (1)); + + if (TARGET_BACKTRACE + && ((live_regs_mask & 0xFF) == 0) + && regs_ever_live [LAST_ARG_REGNUM] != 0) + { + /* The stack backtrace structure creation code had to + push R7 in order to get a work register, so we pop + it now. */ + live_regs_mask |= (1 << LAST_LO_REGNUM); + } + + if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) + { + if (had_to_push_lr + && ! is_called_in_ARM_mode (current_function_decl) + && ! eh_ofs) + live_regs_mask |= 1 << PC_REGNUM; + + /* Either no argument registers were pushed or a backtrace + structure was created which includes an adjusted stack + pointer, so just pop everything. */ + if (live_regs_mask) + thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + + if (eh_ofs) + thumb_exit (asm_out_file, 2, eh_ofs); + /* 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}. */ + else if ((live_regs_mask & (1 << PC_REGNUM)) == 0) + thumb_exit (asm_out_file, + (had_to_push_lr + && is_called_in_ARM_mode (current_function_decl)) ? + -1 : LR_REGNUM, NULL_RTX); + } + else + { + /* Pop everything but the return address. */ + live_regs_mask &= ~ (1 << PC_REGNUM); + + 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 << LAST_ARG_REGNUM, 0); + + /* Remove the argument registers that were pushed onto the stack. */ + asm_fprintf (asm_out_file, "\tadd\t%r, %r, #%d\n", + SP_REGNUM, SP_REGNUM, + current_function_pretend_args_size); + + if (eh_ofs) + thumb_exit (asm_out_file, 2, eh_ofs); + else + thumb_exit (asm_out_file, + had_to_push_lr ? LAST_ARG_REGNUM : LR_REGNUM, NULL_RTX); + } + + return ""; +} + +/* Functions to save and restore machine-specific function data. */ + +static void +arm_mark_machine_status (p) + struct function * p; +{ + struct machine_function *machine = p->machine; + + ggc_mark_rtx (machine->ra_rtx); + ggc_mark_rtx (machine->eh_epilogue_sp_ofs); +} + +static void +arm_init_machine_status (p) + struct function * p; +{ + p->machine = + (struct machine_function *) xcalloc (1, sizeof (struct machine_function)); +} + +/* Return an RTX indicating where the return address to the + calling function can be found. */ +rtx +arm_return_addr (count, frame) + int count; + rtx frame ATTRIBUTE_UNUSED; +{ + rtx reg; + + if (count != 0) + return NULL_RTX; + + reg = cfun->machine->ra_rtx; + + if (reg == NULL) + { + rtx init; + + /* No rtx yet. Invent one, and initialize it for r14 (lr) in + the prologue. */ + reg = gen_reg_rtx (Pmode); + cfun->machine->ra_rtx = reg; + + if (! TARGET_APCS_32) + init = gen_rtx_AND (Pmode, gen_rtx_REG (Pmode, LR_REGNUM), + GEN_INT (RETURN_ADDR_MASK26)); + else + init = gen_rtx_REG (Pmode, LR_REGNUM); + + init = gen_rtx_SET (VOIDmode, reg, init); + + /* Emit the insn to the prologue with the other argument copies. */ + push_topmost_sequence (); + emit_insn_after (init, get_insns ()); + pop_topmost_sequence (); + } + + return reg; +} + +/* Do anything needed before RTL is emitted for each function. */ +void +arm_init_expanders () +{ + /* Arrange to initialize and mark the machine per-function status. */ + init_machine_status = arm_init_machine_status; + mark_machine_status = arm_mark_machine_status; +} + +/* Generate the rest of a function's prologue. */ +void +thumb_expand_prologue () +{ + HOST_WIDE_INT amount = (get_frame_size () + + current_function_outgoing_args_size); + + /* Naked functions don't have prologues. */ + if (arm_naked_function_p (current_function_decl)) + return; + + if (frame_pointer_needed) + emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx)); + + if (amount) + { + amount = ROUND_UP (amount); + + if (amount < 512) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- amount))); + else + { + int regno; + rtx reg; + + /* The stack decrement is too big for an immediate value in a single + insn. In theory we could issue multiple subtracts, but after + three of them it becomes more space efficient to place the full + value in the constant pool and load into a register. (Also the + ARM debugger really likes to see only one stack decrement per + function). So instead we look for a scratch register into which + we can load the decrement, and then we subtract this from the + stack pointer. Unfortunately on the thumb the only available + scratch registers are the argument registers, and we cannot use + these as they may hold arguments to the function. Instead we + attempt to locate a call preserved register which is used by this + function. If we can find one, then we know that it will have + been pushed at the start of the prologue and so we can corrupt + it now. */ + for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++) + if (regs_ever_live[regno] + && ! call_used_regs[regno] /* Paranoia */ + && ! (TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)) + && ! (frame_pointer_needed + && (regno == THUMB_HARD_FRAME_POINTER_REGNUM))) + break; + + if (regno > LAST_LO_REGNUM) /* Very unlikely */ + { + rtx spare = gen_rtx (REG, SImode, IP_REGNUM); + + /* Choose an arbitary, non-argument low register. */ + reg = gen_rtx (REG, SImode, LAST_LO_REGNUM); + + /* Save it by copying it into a high, scratch register. */ + emit_insn (gen_movsi (spare, reg)); + + /* Decrement the stack. */ + emit_insn (gen_movsi (reg, GEN_INT (- amount))); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + reg)); + + /* Restore the low register's original value. */ + emit_insn (gen_movsi (reg, spare)); + + /* Emit a USE of the restored scratch register, so that flow + analysis will not consider the restore redundant. The + register won't be used again in this function and isn't + restored by the epilogue. */ + emit_insn (gen_rtx_USE (VOIDmode, reg)); + } + else + { + 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 (profile_flag || profile_block_flag || TARGET_NO_SCHED_PRO) + emit_insn (gen_blockage ()); +} + +void +thumb_expand_epilogue () +{ + HOST_WIDE_INT amount = (get_frame_size () + + current_function_outgoing_args_size); + + /* Naked functions don't have epilogues. */ + if (arm_naked_function_p (current_function_decl)) + return; + + if (frame_pointer_needed) + emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx)); + else if (amount) + { + amount = ROUND_UP (amount); + + if (amount < 512) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (amount))); + else + { + /* r3 is always free in the epilogue. */ + rtx reg = gen_rtx (REG, SImode, LAST_ARG_REGNUM); + + emit_insn (gen_movsi (reg, GEN_INT (amount))); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); + } + } + + /* Emit a USE (stack_pointer_rtx), so that + the stack adjustment will not be deleted. */ + emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); + + if (profile_flag || profile_block_flag || TARGET_NO_SCHED_PRO) + emit_insn (gen_blockage ()); +} + +void +output_thumb_prologue (f) + FILE * f; +{ + 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 (is_called_in_ARM_mode (current_function_decl)) + { + const char * name; + + if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) + abort (); + if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) + abort (); + name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + + /* Generate code sequence to switch us into Thumb mode. */ + /* The .code 32 directive has already been emitted by + ASM_DECLARE_FUNCITON_NAME */ + asm_fprintf (f, "\torr\t%r, %r, #1\n", IP_REGNUM, PC_REGNUM); + asm_fprintf (f, "\tbx\t%r\n", IP_REGNUM); + + /* Generate a label, so that the debugger will notice the + change in instruction sets. This label is also used by + the assembler to bypass the ARM code when this function + is called from a Thumb encoded function elsewhere in the + same file. Hence the definition of STUB_NAME here must + agree with the definition in gas/config/tc-arm.c */ + +#define STUB_NAME ".real_start_of" + + asm_fprintf (f, "\t.code\t16\n"); +#ifdef ARM_PE + if (arm_dllexport_name_p (name)) + name = ARM_STRIP_NAME_ENCODING (name); +#endif + asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); + asm_fprintf (f, "\t.thumb_func\n"); + asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); + } + + if (current_function_anonymous_args && current_function_pretend_args_size) + store_arg_regs = 1; + + if (current_function_pretend_args_size) + { + if (store_arg_regs) + { + int num_pushes; + + asm_fprintf (f, "\tpush\t{"); + + num_pushes = NUM_INTS (current_function_pretend_args_size); + + for (regno = LAST_ARG_REGNUM + 1 - num_pushes; + regno <= LAST_ARG_REGNUM; + regno ++) + asm_fprintf (f, "%r%s", regno, + regno == LAST_ARG_REGNUM ? "" : ", "); + + asm_fprintf (f, "}\n"); + } + else + asm_fprintf (f, "\tsub\t%r, %r, #%d\n", + SP_REGNUM, SP_REGNUM, + current_function_pretend_args_size); + } + + for (regno = 0; regno <= LAST_LO_REGNUM; regno ++) + if (regs_ever_live[regno] && ! call_used_regs[regno] + && ! (TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register))) + live_regs_mask |= 1 << regno; + + if (live_regs_mask || ! leaf_function_p () || thumb_far_jump_used_p (1)) + live_regs_mask |= 1 << LR_REGNUM; + + if (TARGET_BACKTRACE) + { + int offset; + int work_register = 0; + int wr; + + /* We have been asked to create a stack backtrace structure. + The code looks like this: + + 0 .align 2 + 0 func: + 0 sub SP, #16 Reserve space for 4 registers. + 2 push {R7} Get a work register. + 4 add R7, SP, #20 Get the stack pointer before the push. + 6 str R7, [SP, #8] Store the stack pointer (before reserving the space). + 8 mov R7, PC Get hold of the start of this code plus 12. + 10 str R7, [SP, #16] Store it. + 12 mov R7, FP Get hold of the current frame pointer. + 14 str R7, [SP, #4] Store it. + 16 mov R7, LR Get hold of the current return address. + 18 str R7, [SP, #12] Store it. + 20 add R7, SP, #16 Point at the start of the backtrace structure. + 22 mov FP, R7 Put this value into the frame pointer. */ + + if ((live_regs_mask & 0xFF) == 0) + { + /* See if the a4 register is free. */ + + if (regs_ever_live [LAST_ARG_REGNUM] == 0) + work_register = LAST_ARG_REGNUM; + else /* We must push a register of our own */ + live_regs_mask |= (1 << LAST_LO_REGNUM); + } + + if (work_register == 0) + { + /* Select a register from the list that will be pushed to + use as our work register. */ + for (work_register = (LAST_LO_REGNUM + 1); work_register--;) + if ((1 << work_register) & live_regs_mask) + break; + } + + asm_fprintf + (f, "\tsub\t%r, %r, #16\t%@ Create stack backtrace structure\n", + SP_REGNUM, SP_REGNUM); + + if (live_regs_mask) + thumb_pushpop (f, live_regs_mask, 1); + + for (offset = 0, wr = 1 << 15; wr != 0; wr >>= 1) + if (wr & live_regs_mask) + offset += 4; + + asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM, + offset + 16 + current_function_pretend_args_size); + + asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM, + offset + 4); + + /* Make sure that the instruction fetching the PC is in the right place + to calculate "start of backtrace creation code + 12". */ + if (live_regs_mask) + { + asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM); + asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM, + offset + 12); + asm_fprintf (f, "\tmov\t%r, %r\n", work_register, + ARM_HARD_FRAME_POINTER_REGNUM); + asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM, + offset); + } + else + { + asm_fprintf (f, "\tmov\t%r, %r\n", work_register, + ARM_HARD_FRAME_POINTER_REGNUM); + asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM, + offset); + asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM); + asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM, + offset + 12); + } + + asm_fprintf (f, "\tmov\t%r, %r\n", work_register, LR_REGNUM); + asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM, + offset + 8); + asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM, + offset + 12); + asm_fprintf (f, "\tmov\t%r, %r\t\t%@ Backtrace structure created\n", + ARM_HARD_FRAME_POINTER_REGNUM, work_register); + } + else if (live_regs_mask) + thumb_pushpop (f, live_regs_mask, 1); + + for (regno = 8; regno < 13; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno] + && ! (TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register))) + 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 > LAST_LO_REGNUM; next_hi_reg--) + { + if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg] + && ! (TARGET_SINGLE_PIC_BASE + && (next_hi_reg == arm_pic_register))) + break; + } + + pushable_regs = mask; + + if (pushable_regs == 0) + { + /* Desperation time -- this probably will never happen. */ + if (regs_ever_live[LAST_ARG_REGNUM] + || ! call_used_regs[LAST_ARG_REGNUM]) + asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, LAST_ARG_REGNUM); + mask = 1 << LAST_ARG_REGNUM; + } + + while (high_regs_pushed > 0) + { + for (regno = LAST_LO_REGNUM; regno >= 0; regno--) + { + if (mask & (1 << regno)) + { + asm_fprintf (f, "\tmov\t%r, %r\n", regno, next_hi_reg); + + high_regs_pushed --; + + if (high_regs_pushed) + for (next_hi_reg--; next_hi_reg > LAST_LO_REGNUM; + next_hi_reg--) + { + if (regs_ever_live[next_hi_reg] + && ! call_used_regs[next_hi_reg] + && ! (TARGET_SINGLE_PIC_BASE + && (next_hi_reg == arm_pic_register))) + break; + } + else + { + mask &= ~ ((1 << regno) - 1); + break; + } + } + } + + thumb_pushpop (f, mask, 1); + } + + if (pushable_regs == 0 + && (regs_ever_live[LAST_ARG_REGNUM] + || ! call_used_regs[LAST_ARG_REGNUM])) + asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM); + } +} + +/* Handle the case of a double word load into a low register from + a computed memory address. The computed address may involve a + register which is overwritten by the load. */ + +char * +thumb_load_double_from_address (operands) + 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) + { + debug_rtx (operands[1]); + 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", operands); + output_asm_insn ("ldr\t%0, %1", operands); + } + else + { + output_asm_insn ("ldr\t%0, %1", operands); + output_asm_insn ("ldr\t%H0, %2", operands); + } + break; + + case CONST: + /* Compute
+ 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", operands); + output_asm_insn ("ldr\t%H0, %2", 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
= + */ + 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. */ + asm_fprintf (asm_out_file, "\tadd\t%r, %r, %r", + reg_dest + 1, reg_base, reg_offset); + + /* Load the lower destination register from the address in + the higher destination register. */ + asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #0]", + reg_dest, reg_dest + 1); + + /* Load the higher destination register from its own address + plus 4. */ + asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #4]", + reg_dest + 1, reg_dest + 1); + } + else + { + /* Compute
+ 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", operands); + output_asm_insn ("ldr\t%0, %1", operands); + } + else + { + output_asm_insn ("ldr\t%0, %1", operands); + output_asm_insn ("ldr\t%H0, %2", 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", operands); + output_asm_insn ("ldr\t%0, %1", operands); + break; + + default: + debug_rtx (operands[1]); + fatal ("thumb_load_double_from_address: Unhandled address calculation"); + break; + } + + return ""; +} + + +char * +thumb_output_move_mem_multiple (n, operands) + int n; + rtx * operands; +{ + rtx tmp; + + 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; + + 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; + + default: + abort (); + } + + return ""; +} + +/* Routines for generating rtl */ + +void +thumb_expand_movstrqi (operands) + 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; + + while (len >= 12) + { + emit_insn (gen_movmem12b (out, in)); + len -= 12; + } + + if (len >= 8) + { + emit_insn (gen_movmem8b (out, in)); + len -= 8; + } + + 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; + } + + 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; + } + + 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)); + } +} + +int +thumb_cmp_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return ((GET_CODE (op) == CONST_INT + && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256) + || register_operand (op, mode)); +} + +static char * +thumb_condition_code (x, invert) + rtx x; + int invert; +{ + static char * conds[] = + { + "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le" + }; + int val; + + switch (GET_CODE (x)) + { + case EQ: val = 0; break; + case NE: val = 1; break; + case GEU: val = 2; break; + case LTU: val = 3; break; + case GTU: val = 8; break; + case LEU: val = 9; break; + case GE: val = 10; break; + case LT: val = 11; break; + case GT: val = 12; break; + case LE: val = 13; break; + default: + abort (); + } + + return conds[val ^ invert]; +} + +/* Handle storing a half-word to memory during reload. */ +void +thumb_reload_out_hi (operands) + rtx * operands; +{ + emit_insn (gen_thumb_movhi_clobber (operands[0], operands[1], operands[2])); +} + +/* Handle storing a half-word to memory during reload. */ +void +thumb_reload_in_hi (operands) + rtx * operands ATTRIBUTE_UNUSED; +{ + abort (); +} + /* Return the length of a function name prefix that starts with the character 'c'. */ static int @@ -7194,7 +9756,7 @@ aof_pic_entry (x) /* We mark this here and not in arm_add_gc_roots() to avoid polluting even more code with ifdefs, and because it never contains anything useful until we assign to it here. */ - ggc_add_rtx_root (&aof_pic_label, 1); + ggc_add_rtx_root (& aof_pic_label, 1); /* This needs to persist throughout the compilation. */ end_temporary_allocation (); aof_pic_label = gen_rtx_SYMBOL_REF (Pmode, "x$adcons"); diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 002f8e957d3..268f1c58d7d 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -51,16 +51,17 @@ Boston, MA 02111-1307, USA. */ /* Configure didn't specify. */ #define TARGET_CPU_generic 0x8000 -enum arm_cond_code +typedef enum arm_cond_code { ARM_EQ = 0, ARM_NE, ARM_CS, ARM_CC, ARM_MI, ARM_PL, ARM_VS, ARM_VC, ARM_HI, ARM_LS, ARM_GE, ARM_LT, ARM_GT, ARM_LE, ARM_AL, ARM_NV -}; +} +arm_cc; -extern enum arm_cond_code arm_current_cc; +extern arm_cc arm_current_cc; extern char * arm_condition_codes[]; -#define ARM_INVERSE_CONDITION_CODE(X) ((enum arm_cond_code) (((int)X) ^ 1)) +#define ARM_INVERSE_CONDITION_CODE(X) ((arm_cc) (((int)X) ^ 1)) extern int arm_target_label; extern int arm_ccfsm_state; @@ -72,7 +73,18 @@ extern int frame_pointer_needed; extern int target_flags; /* The floating point instruction architecture, can be 2 or 3 */ extern const char * target_fp_name; - +/* Define the information needed to generate branch insns. This is + stored from the compare operation. Note that we can't use "rtx" here + since it hasn't been defined! */ +extern struct rtx_def * arm_compare_op0; +extern struct rtx_def * arm_compare_op1; +/* The label of the current constant pool. */ +extern struct rtx_def * pool_vector_label; +/* Set to 1 when a return insn is output, this means that the epilogue + is not needed. */ +extern int return_used_this_function; +/* Nonzero if the prologue must setup `fp'. */ +extern int current_function_anonymous_args; /* Just in case configure has failed to define anything. */ #ifndef TARGET_CPU_DEFAULT @@ -113,12 +125,14 @@ Unrecognized value in TARGET_CPU_DEFAULT. #endif #ifndef CPP_PREDEFINES -#define CPP_PREDEFINES "-Darm -Acpu(arm) -Amachine(arm)" +#define CPP_PREDEFINES "-Acpu(arm) -Amachine(arm)" #endif #define CPP_SPEC "\ %(cpp_cpu_arch) %(cpp_apcs_pc) %(cpp_float) \ -%(cpp_endian) %(subtarget_cpp_spec)" +%(cpp_endian) %(subtarget_cpp_spec) %(cpp_isa)" + +#define CPP_ISA_SPEC "%{mthumb:-Dthumb -D__thumb__} %{!mthumb:-Darm -D__arm__}" /* Set the architecture define -- if -march= is set, then it overrides the -mcpu= setting. */ @@ -156,6 +170,9 @@ Unrecognized value in TARGET_CPU_DEFAULT. %{march=armv4:-D__ARM_ARCH_4__} \ %{march=armv4t:-D__ARM_ARCH_4T__} \ %{march=armv5:-D__ARM_ARCH_5__} \ +%{march=armv5t:-D__ARM_ARCH_5T__} \ +%{march=armv5e:-D__ARM_ARCH_5E__} \ +%{march=armv5te:-D__ARM_ARCH_5TE__} \ %{!march=*: \ %{mcpu=arm2:-D__ARM_ARCH_2__} \ %{mcpu=arm250:-D__ARM_ARCH_2__} \ @@ -212,12 +229,13 @@ Unrecognized value in TARGET_CPU_DEFAULT. %{mbig-endian: \ %{mlittle-endian: \ %e-mbig-endian and -mlittle-endian may not be used together} \ - -D__ARMEB__ %{mwords-little-endian:-D__ARMWEL__}} \ + -D__ARMEB__ %{mwords-little-endian:-D__ARMWEL__} %{mthumb:-D__THUMBEB__}}\ +%{mlittle-endian:-D__ARMEL__ %{mthumb:-D__THUMBEL__}} \ %{!mlittle-endian:%{!mbig-endian:%(cpp_endian_default)}} \ " -/* Default is little endian, which doesn't define anything. */ -#define CPP_ENDIAN_DEFAULT_SPEC "-D__ARMEL__" +/* Default is little endian. */ +#define CPP_ENDIAN_DEFAULT_SPEC "-D__ARMEL__ %{mthumb:-D__THUMBEL__}" #define CC1_SPEC "" @@ -239,6 +257,7 @@ Unrecognized value in TARGET_CPU_DEFAULT. { "cpp_float_default", CPP_FLOAT_DEFAULT_SPEC }, \ { "cpp_endian", CPP_ENDIAN_SPEC }, \ { "cpp_endian_default", CPP_ENDIAN_DEFAULT_SPEC }, \ + { "cpp_isa", CPP_ISA_SPEC }, \ { "subtarget_cpp_spec", SUBTARGET_CPP_SPEC }, \ SUBTARGET_EXTRA_SPECS @@ -319,8 +338,27 @@ Unrecognized value in TARGET_CPU_DEFAULT. /* Nonzero if all call instructions should be indirect. */ #define ARM_FLAG_LONG_CALLS (1 << 15) + +/* Nonzero means that the target ISA is the THUMB, not the ARM. */ +#define ARM_FLAG_THUMB (1 << 16) + +/* Set if a TPCS style stack frame should be generated, for non-leaf + functions, even if they do not need one. */ +#define THUMB_FLAG_BACKTRACE (1 << 17) -#define TARGET_APCS (target_flags & ARM_FLAG_APCS_FRAME) +/* Set if a TPCS style stack frame should be generated, for leaf + functions, even if they do not need one. */ +#define THUMB_FLAG_LEAF_BACKTRACE (1 << 18) + +/* Set if externally visible functions should assume that they + might be called in ARM mode, from a non-thumb aware code. */ +#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING (1 << 19) + +/* Set if calls via function pointers should assume that their + destination is non-Thumb aware. */ +#define THUMB_FLAG_CALLER_SUPER_INTERWORKING (1 << 20) + +#define TARGET_APCS_FRAME (target_flags & ARM_FLAG_APCS_FRAME) #define TARGET_POKE_FUNCTION_NAME (target_flags & ARM_FLAG_POKE) #define TARGET_FPE (target_flags & ARM_FLAG_FPE) #define TARGET_APCS_32 (target_flags & ARM_FLAG_APCS_32) @@ -337,6 +375,14 @@ Unrecognized value in TARGET_CPU_DEFAULT. #define TARGET_ABORT_NORETURN (target_flags & ARM_FLAG_ABORT_NORETURN) #define TARGET_SINGLE_PIC_BASE (target_flags & ARM_FLAG_SINGLE_PIC_BASE) #define TARGET_LONG_CALLS (target_flags & ARM_FLAG_LONG_CALLS) +#define TARGET_THUMB (target_flags & ARM_FLAG_THUMB) +#define TARGET_ARM (! TARGET_THUMB) +#define TARGET_EITHER 1 /* (TARGET_ARM | TARGET_THUMB) */ +#define TARGET_CALLEE_INTERWORKING (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING) +#define TARGET_CALLER_INTERWORKING (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING) +#define TARGET_BACKTRACE (leaf_function_p () \ + ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ + : (target_flags & THUMB_FLAG_BACKTRACE)) /* SUBTARGET_SWITCHES is used to add flags on a per-config basis. Bit 31 is reserved. See riscix.h. */ @@ -388,7 +434,7 @@ Unrecognized value in TARGET_CPU_DEFAULT. {"no-thumb-interwork", -ARM_FLAG_INTERWORK, "" }, \ {"abort-on-noreturn", ARM_FLAG_ABORT_NORETURN, \ "Generate a call to abort if a noreturn function returns"},\ - {"no-abort-on-noreturn", -ARM_FLAG_ABORT_NORETURN, ""}, \ + {"no-abort-on-noreturn", -ARM_FLAG_ABORT_NORETURN, "" }, \ {"sched-prolog", -ARM_FLAG_NO_SCHED_PRO, \ "Do not move instructions into a function's prologue" }, \ {"no-sched-prolog", ARM_FLAG_NO_SCHED_PRO, "" }, \ @@ -396,10 +442,28 @@ Unrecognized value in TARGET_CPU_DEFAULT. "Do not load the PIC register in function prologues" }, \ {"no-single-pic-base", -ARM_FLAG_SINGLE_PIC_BASE, "" }, \ {"long-calls", ARM_FLAG_LONG_CALLS, \ - "Generate call insns as indirect calls, if necessary"}, \ - {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ - SUBTARGET_SWITCHES \ - {"", TARGET_DEFAULT, "" } \ + "Generate call insns as indirect calls, if necessary" }, \ + {"no-long-calls", -ARM_FLAG_LONG_CALLS, "" }, \ + {"thumb", ARM_FLAG_THUMB, \ + "Compile for the Thumb not the ARM" }, \ + {"no-thumb", -ARM_FLAG_THUMB, "" }, \ + {"arm", -ARM_FLAG_THUMB, "" }, \ + {"tpcs-frame", THUMB_FLAG_BACKTRACE, \ + "Thumb: Generate (non-leaf) stack frames even if not needed" }, \ + {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE, "" }, \ + {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE, \ + "Thumb: Generate (leaf) stack frames even if not needed" }, \ + {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE, "" }, \ + {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING, \ + "Thumb: Assume non-static functions may be called from ARM code" }, \ + {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING, \ + ""}, \ + {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING, \ + "Thumb: Assume function pointers may go to non-Thumb aware code" }, \ + {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING, \ + "" }, \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT, "" } \ } #define TARGET_OPTIONS \ @@ -483,13 +547,12 @@ extern int arm_is_strong; extern int arm_is_6_or_7; #ifndef TARGET_DEFAULT -#define TARGET_DEFAULT 0 +#define TARGET_DEFAULT (ARM_FLAG_APCS_FRAME) #endif /* The frame pointer register used in gcc has nothing to do with debugging; that is controlled by the APCS-FRAME option. */ -/* Not fully implemented yet. */ -/* #define CAN_DEBUG_WITHOUT_FP 1 */ +#define CAN_DEBUG_WITHOUT_FP #define TARGET_MEM_FUNCTIONS 1 @@ -705,15 +768,12 @@ extern const char * structure_size_string; [| saved f4 value |] three words r0-r3 are not normally saved in a C function. */ -/* The number of hard registers is 16 ARM + 8 FPU + 1 CC + 1 SFP. */ -#define FIRST_PSEUDO_REGISTER 27 - /* 1 for registers that have pervasive standard uses and are not available for the register allocator. */ #define FIXED_REGISTERS \ { \ 0,0,0,0,0,0,0,0, \ - 0,0,0,1,0,1,0,1, \ + 0,0,0,0,0,1,0,1, \ 0,0,0,0,0,0,0,0, \ 1,1,1 \ } @@ -729,7 +789,7 @@ extern const char * structure_size_string; #define CALL_USED_REGISTERS \ { \ 1,1,1,1,0,0,0,0, \ - 0,0,0,1,1,1,1,1, \ + 0,0,0,0,1,1,1,1, \ 1,1,1,1,0,0,0,0, \ 1,1,1 \ } @@ -738,27 +798,33 @@ extern const char * structure_size_string; #define SUBTARGET_CONDITIONAL_REGISTER_USAGE #endif -#define CONDITIONAL_REGISTER_USAGE \ -{ \ - if (TARGET_SOFT_FLOAT) \ - { \ - int regno; \ - for (regno = 16; regno < 24; ++regno) \ - fixed_regs[regno] = call_used_regs[regno] = 1; \ - } \ - if (flag_pic) \ - { \ - fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ - call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ - } \ - else if (TARGET_APCS_STACK) \ - { \ - fixed_regs[10] = 1; \ - call_used_regs[10] = 1; \ - } \ - SUBTARGET_CONDITIONAL_REGISTER_USAGE \ +#define CONDITIONAL_REGISTER_USAGE \ +{ \ + if (TARGET_SOFT_FLOAT || TARGET_THUMB) \ + { \ + int regno; \ + for (regno = FIRST_ARM_FP_REGNUM; \ + regno <= LAST_ARM_FP_REGNUM; ++regno) \ + fixed_regs[regno] = call_used_regs[regno] = 1; \ + } \ + if (flag_pic) \ + { \ + fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + } \ + else if (TARGET_APCS_STACK) \ + { \ + fixed_regs[10] = 1; \ + call_used_regs[10] = 1; \ + } \ + if (TARGET_APCS_FRAME) \ + { \ + fixed_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1; \ + call_used_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1; \ + } \ + SUBTARGET_CONDITIONAL_REGISTER_USAGE \ } - + /* These are a couple of extensions to the formats accecpted by asm_fprintf: %@ prints out ASM_COMMENT_START @@ -773,6 +839,9 @@ extern const char * structure_size_string; fputs (reg_names [va_arg (ARGS, int)], FILE); \ break; +/* Round X up to the nearest word. */ +#define ROUND_UP(X) (((X) + 3) & ~3) + /* Convert fron bytes to ints. */ #define NUM_INTS(X) (((X) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) @@ -782,71 +851,85 @@ extern const char * structure_size_string; /* The number of (integer) registers required to hold a quantity of TYPE MODE. */ #define NUM_REGS2(MODE, TYPE) \ - NUM_INTS ((MODE) == BLKmode ? int_size_in_bytes (TYPE) : GET_MODE_SIZE (MODE)) + NUM_INTS ((MODE) == BLKmode ? \ + int_size_in_bytes (TYPE) : GET_MODE_SIZE (MODE)) /* The number of (integer) argument register available. */ -#define NUM_ARG_REGS 4 +#define NUM_ARG_REGS 4 /* Return the regiser number of the N'th (integer) argument. */ -#define ARG_REGISTER(N) (N - 1) +#define ARG_REGISTER(N) (N - 1) -/* The number of the last argument register. */ -#define LAST_ARG_REGNUM ARG_REGISTER (NUM_ARG_REGS) +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM ARG_REGISTER (1) -/* Return number of consecutive hard regs needed starting at reg REGNO - to hold something of mode MODE. - This is ordinarily the length in words of a value of mode MODE - but can be less for certain modes in special long registers. +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ - On the ARM regs are UNITS_PER_WORD bits wide; FPU regs can hold any FP - mode. */ -#define HARD_REGNO_NREGS(REGNO, MODE) \ - (( REGNO >= 16 \ - && REGNO != FRAME_POINTER_REGNUM \ - && REGNO != ARG_POINTER_REGNUM) \ - ? 1 : NUM_REGS (MODE)) +/* The number of the last argument register. */ +#define LAST_ARG_REGNUM ARG_REGISTER (NUM_ARG_REGS) -/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. - This is TRUE for ARM regs since they can hold anything, and TRUE for FPU - regs holding FP. */ -#define HARD_REGNO_MODE_OK(REGNO, MODE) \ - ((GET_MODE_CLASS (MODE) == MODE_CC) ? (REGNO == CC_REGNUM) : \ - ((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ - || REGNO == ARG_POINTER_REGNUM \ - || GET_MODE_CLASS (MODE) == MODE_FLOAT)) +/* The number of the last "lo" register (thumb). */ +#define LAST_LO_REGNUM 7 -/* Value is 1 if it is a good idea to tie two pseudo registers - when one has mode MODE1 and one has mode MODE2. - If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, - for any hard reg, then this must be 0 for correct output. */ -#define MODES_TIEABLE_P(MODE1, MODE2) \ - (GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2)) +/* The native (Norcroft) Pascal compiler for the ARM passes the static chain + as an invisible last argument (possible since varargs don't exist in + Pascal), so the following is not true. */ +#define STATIC_CHAIN_REGNUM (TARGET_ARM ? 8 : 9) -/* Specify the registers used for certain standard purposes. - The values of these macros are register numbers. */ +/* Define this to be where the real frame pointer is if it is not possible to + work out the offset between the frame pointer and the automatic variables + until after register allocation has taken place. FRAME_POINTER_REGNUM + should point to a special register that we will make sure is eliminated. + + For the Thumb we have another problem. The TPCS defines the frame pointer + as r11, and GCC belives that it is always possible to use the frame pointer + as base register for addressing purposes. (See comments in + find_reloads_address()). But - the Thumb does not allow high registers, + including r11, to be used as base address registers. Hence our problem. + + The solution used here, and in the old thumb port is to use r7 instead of + r11 as the hard frame pointer and to have special code to generate + backtrace structures on the stack (if required to do so via a command line + option) using r11. This is the only 'user visable' use of r11 as a frame + pointer. */ +#define ARM_HARD_FRAME_POINTER_REGNUM 11 +#define THUMB_HARD_FRAME_POINTER_REGNUM 7 +#define HARD_FRAME_POINTER_REGNUM (TARGET_ARM ? ARM_HARD_FRAME_POINTER_REGNUM : THUMB_HARD_FRAME_POINTER_REGNUM) +#define FP_REGNUM HARD_FRAME_POINTER_REGNUM -/* Define this if the program counter is overloaded on a register. */ -#define PC_REGNUM 15 +/* Scratch register - used in all kinds of places, eg trampolines. */ +#define IP_REGNUM 12 /* Register to use for pushing function arguments. */ #define STACK_POINTER_REGNUM 13 #define SP_REGNUM STACK_POINTER_REGNUM +/* Register which holds return address from a subroutine call. */ +#define LR_REGNUM 14 + +/* Define this if the program counter is overloaded on a register. */ +#define PC_REGNUM 15 + +/* The number of the last ARM (integer) register. */ +#define LAST_ARM_REGNUM 15 + +/* ARM floating pointer registers. */ +#define FIRST_ARM_FP_REGNUM 16 +#define LAST_ARM_FP_REGNUM 23 + +/* Internal, so that we don't need to refer to a raw number */ +#define CC_REGNUM 24 + /* Base register for access to local variables of the function. */ #define FRAME_POINTER_REGNUM 25 -/* Define this to be where the real frame pointer is if it is not possible to - work out the offset between the frame pointer and the automatic variables - until after register allocation has taken place. FRAME_POINTER_REGNUM - should point to a special register that we will make sure is eliminated. */ -#define HARD_FRAME_POINTER_REGNUM 11 -#define FP_REGNUM HARD_FRAME_POINTER_REGNUM - -/* Register which holds return address from a subroutine call. */ -#define LR_REGNUM 14 +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 26 -/* Scratch register - used in all kinds of places, eg trampolines. */ -#define IP_REGNUM 12 +/* The number of hard registers is 16 ARM + 8 FPU + 1 CC + 1 SFP. */ +#define FIRST_PSEUDO_REGISTER 27 /* Value should be nonzero if functions must have frame pointers. Zero means the frame pointer need not be set up (and parms may be accessed @@ -854,31 +937,55 @@ extern const char * structure_size_string; If we have to have a frame pointer we might as well make use of it. APCS says that the frame pointer does not need to be pushed in leaf functions, or simple tail call functions. */ -#define FRAME_POINTER_REQUIRED \ - (current_function_has_nonlocal_label || (TARGET_APCS && !leaf_function_p ())) +#define FRAME_POINTER_REQUIRED \ + (current_function_has_nonlocal_label \ + || (TARGET_ARM && TARGET_APCS_FRAME && ! leaf_function_p ())) -/* Base register for access to arguments of the function. */ -#define ARG_POINTER_REGNUM 26 +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. -/* The native (Norcroft) Pascal compiler for the ARM passes the static chain - as an invisible last argument (possible since varargs don't exist in - Pascal), so the following is not true. */ -#define STATIC_CHAIN_REGNUM 8 + On the ARM regs are UNITS_PER_WORD bits wide; FPU regs can hold any FP + mode. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((TARGET_ARM \ + && REGNO >= FIRST_ARM_FP_REGNUM \ + && REGNO != FRAME_POINTER_REGNUM \ + && REGNO != ARG_POINTER_REGNUM) \ + ? 1 : NUM_REGS (MODE)) -/* Register in which address to store a structure value - is passed to a function. */ -#define STRUCT_VALUE_REGNUM 0 +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + This is TRUE for ARM regs since they can hold anything, and TRUE for FPU + regs holding FP. + For the Thumb we only allow values bigger than SImode in registers 0 - 6, + so that there is always a second lo register available to hold the upper + part of the value. Probably we ought to ensure that the register is the + start of an even numbered register pair. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (TARGET_ARM ? \ + ((GET_MODE_CLASS (MODE) == MODE_CC) ? (REGNO == CC_REGNUM) : \ + ( REGNO <= LAST_ARM_REGNUM \ + || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM \ + || GET_MODE_CLASS (MODE) == MODE_FLOAT)) \ + : \ + ((GET_MODE_CLASS (MODE) == MODE_CC) ? (REGNO == CC_REGNUM) : \ + (NUM_REGS (MODE) < 2 || REGNO < LAST_LO_REGNUM))) -/* Internal, so that we don't need to refer to a raw number */ -#define CC_REGNUM 24 +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2)) /* The order in which register should be allocated. It is good to use ip since no saving is required (though calls clobber it) and it never contains function parameters. It is quite good to use lr since other calls may clobber it anyway. Allocate r0 through r3 in reverse order since r3 is least likely to contain a function parameter; in addition results are - returned in r0. - */ + returned in r0. */ #define REG_ALLOC_ORDER \ { \ 3, 2, 1, 0, 12, 14, 4, 5, \ @@ -889,11 +996,17 @@ extern const char * structure_size_string; /* Register and constant classes. */ -/* Register classes: all ARM regs or all FPU regs---simple! */ +/* Register classes: used to be simple, just all ARM regs or all FPU regs + Now that the Thumb is involved it has become more compilcated. */ enum reg_class { NO_REGS, FPU_REGS, + LO_REGS, + STACK_REG, + BASE_REGS, + HI_REGS, + CC_REG, GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES @@ -906,6 +1019,11 @@ enum reg_class { \ "NO_REGS", \ "FPU_REGS", \ + "LO_REGS", \ + "STACK_REG", \ + "BASE_REGS", \ + "HI_REGS", \ + "CC_REG", \ "GENERAL_REGS", \ "ALL_REGS", \ } @@ -917,28 +1035,43 @@ enum reg_class { \ { 0x0000000 }, /* NO_REGS */ \ { 0x0FF0000 }, /* FPU_REGS */ \ + { 0x00000FF }, /* LO_REGS */ \ + { 0x0002000 }, /* STACK_REG */ \ + { 0x00020FF }, /* BASE_REGS */ \ + { 0x000FF00 }, /* HI_REGS */ \ + { 0x1000000 }, /* CC_REG */ \ { 0x200FFFF }, /* GENERAL_REGS */ \ { 0x2FFFFFF } /* ALL_REGS */ \ } - + /* The same information, inverted: Return the class number of the smallest class containing reg number REGNO. This could be a conditional expression or could index an array. */ -#define REGNO_REG_CLASS(REGNO) \ - (((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ - || REGNO == ARG_POINTER_REGNUM) \ - ? GENERAL_REGS : (REGNO) == CC_REGNUM \ - ? NO_REGS : FPU_REGS) +#define REGNO_REG_CLASS(REGNO) arm_regno_class (REGNO) /* The class value for index registers, and the one for base regs. */ -#define INDEX_REG_CLASS GENERAL_REGS -#define BASE_REG_CLASS GENERAL_REGS +#define INDEX_REG_CLASS (TARGET_THUMB ? LO_REGS : GENERAL_REGS) +#define BASE_REG_CLASS (TARGET_THUMB ? BASE_REGS : GENERAL_REGS) + +/* When SMALL_REGISTER_CLASSES is nonzero, the compiler allows + registers explicitly used in the rtl to be used as spill registers + but prevents the compiler from extending the lifetime of these + registers. */ +#define SMALL_REGISTER_CLASSES TARGET_THUMB /* Get reg_class from a letter such as appears in the machine description. - We only need constraint `f' for FPU_REGS (`r' == GENERAL_REGS). */ -#define REG_CLASS_FROM_LETTER(C) \ - ((C)=='f' ? FPU_REGS : NO_REGS) + We only need constraint `f' for FPU_REGS (`r' == GENERAL_REGS) for the + ARM, but several more letters for the Thumb. */ +#define REG_CLASS_FROM_LETTER(C) \ + ( (C) == 'f' ? FPU_REGS \ + : (C) == 'l' ? (TARGET_ARM ? GENERAL_REGS : LO_REGS) \ + : TARGET_ARM ? NO_REGS \ + : (C) == 'h' ? HI_REGS \ + : (C) == 'b' ? BASE_REGS \ + : (C) == 'k' ? STACK_REG \ + : (C) == 'c' ? CC_REG \ + : NO_REGS) /* The letters I, J, K, L and M in a register constraint string can be used to stand for particular ranges of immediate operands. @@ -950,7 +1083,7 @@ enum reg_class K: ~value ok in rhs argument of data operand. L: -value ok in rhs argument of data operand. M: 0..32, or a power of 2 (for shifts, or mult done by shift). */ -#define CONST_OK_FOR_LETTER_P(VALUE, C) \ +#define CONST_OK_FOR_ARM_LETTER(VALUE, C) \ ((C) == 'I' ? const_ok_for_arm (VALUE) : \ (C) == 'J' ? ((VALUE) < 4096 && (VALUE) > -4096) : \ (C) == 'K' ? (const_ok_for_arm (~(VALUE))) : \ @@ -959,46 +1092,94 @@ enum reg_class || (((VALUE) & ((VALUE) - 1)) == 0)) \ : 0) +#define CONST_OK_FOR_THUMB_LETTER(VAL, C) \ + ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VAL) < 256 : \ + (C) == 'J' ? (VAL) > -256 && (VAL) < 0 : \ + (C) == 'K' ? thumb_shiftable_const (VAL) : \ + (C) == 'L' ? (VAL) > -8 && (VAL) < 8 : \ + (C) == 'M' ? ((unsigned HOST_WIDE_INT) (VAL) < 1024 \ + && ((VAL) & 3) == 0) : \ + (C) == 'N' ? ((unsigned HOST_WIDE_INT) (VAL) < 32) : \ + (C) == 'O' ? ((VAL) >= -508 && (VAL) <= 508) \ + : 0) + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + (TARGET_ARM ? \ + CONST_OK_FOR_ARM_LETTER (VALUE, C) : CONST_OK_FOR_THUMB_LETTER (VALUE, C)) + +/* Constant letter 'G' for the FPU immediate constants. + 'H' means the same constant negated. */ +#define CONST_DOUBLE_OK_FOR_ARM_LETTER(X, C) \ + ((C) == 'G' ? const_double_rtx_ok_for_fpu (X) : \ + (C) == 'H' ? neg_const_double_rtx_ok_for_fpu (X) : 0) + +#define CONST_DOUBLE_OK_FOR_LETTER_P(X, C) \ + (TARGET_ARM ? \ + CONST_DOUBLE_OK_FOR_ARM_LETTER (X, C) : 0) + /* For the ARM, `Q' means that this is a memory operand that is just an offset from a register. `S' means any symbol that has the SYMBOL_REF_FLAG set or a CONSTANT_POOL address. This means that the symbol is in the text segment and can be accessed without using a load. */ -#define EXTRA_CONSTRAINT(OP, C) \ - ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG \ - : (C) == 'R' ? (GET_CODE (OP) == MEM \ - && GET_CODE (XEXP (OP, 0)) == SYMBOL_REF \ - && CONSTANT_POOL_ADDRESS_P (XEXP (OP, 0))) \ - : (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP)) \ +#define EXTRA_CONSTRAINT_ARM(OP, C) \ + ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG : \ + (C) == 'R' ? (GET_CODE (OP) == MEM \ + && GET_CODE (XEXP (OP, 0)) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (XEXP (OP, 0))) : \ + (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP)) \ : 0) -/* Constant letter 'G' for the FPU immediate constants. - 'H' means the same constant negated. */ -#define CONST_DOUBLE_OK_FOR_LETTER_P(X,C) \ - ((C) == 'G' ? const_double_rtx_ok_for_fpu (X) \ - : (C) == 'H' ? neg_const_double_rtx_ok_for_fpu (X) : 0) +#define EXTRA_CONSTRAINT_THUMB(X, C) \ + ((C) == 'Q' ? (GET_CODE (X) == MEM \ + && GET_CODE (XEXP (X, 0)) == LABEL_REF) : 0) + +#define EXTRA_CONSTRAINT(X, C) \ + (TARGET_ARM ? \ + EXTRA_CONSTRAINT_ARM (X, C) : EXTRA_CONSTRAINT_THUMB (X, C)) /* Given an rtx X being reloaded into a reg required to be in class CLASS, return the class of reg to actually use. - In general this is just CLASS; but on some machines - in some cases it is preferable to use a more restrictive class. */ -#define PREFERRED_RELOAD_CLASS(X, CLASS) (CLASS) + In general this is just CLASS, but for the Thumb we prefer + a LO_REGS class or a subset. */ +#define PREFERRED_RELOAD_CLASS(X, CLASS) \ + (TARGET_ARM ? (CLASS) : \ + ((CLASS) == BASE_REGS ? (CLASS) : LO_REGS)) + +/* Must leave BASE_REGS reloads alone */ +#define THUMB_SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X) \ + ((CLASS) != LO_REGS && (CLASS) != BASE_REGS \ + ? ((true_regnum (X) == -1 ? LO_REGS \ + : (true_regnum (X) + HARD_REGNO_NREGS (0, MODE) > 8) ? LO_REGS \ + : NO_REGS)) \ + : NO_REGS) + +#define THUMB_SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X) \ + ((CLASS) != LO_REGS \ + ? ((true_regnum (X) == -1 ? LO_REGS \ + : (true_regnum (X) + HARD_REGNO_NREGS (0, MODE) > 8) ? LO_REGS \ + : NO_REGS)) \ + : NO_REGS) /* Return the register class of a scratch register needed to copy IN into or out of a register in CLASS in MODE. If it can be done directly, NO_REGS is returned. */ -#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,X) \ - (((MODE) == HImode && ! arm_arch4 && true_regnum (X) == -1) \ - ? GENERAL_REGS : NO_REGS) - +#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X) \ + (TARGET_ARM ? \ + (((MODE) == HImode && ! arm_arch4 && true_regnum (X) == -1) \ + ? GENERAL_REGS : NO_REGS) \ + : THUMB_SECONDARY_OUTPUT_RELOAD_CLASS (CLASS, MODE, X)) + /* If we need to load shorts byte-at-a-time, then we need a scratch. */ -#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,X) \ - (((MODE) == HImode && ! arm_arch4 && TARGET_MMU_TRAPS \ - && (GET_CODE (X) == MEM \ - || ((GET_CODE (X) == REG || GET_CODE (X) == SUBREG) \ - && true_regnum (X) == -1))) \ - ? GENERAL_REGS : NO_REGS) +#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X) \ + (TARGET_ARM ? \ + (((MODE) == HImode && ! arm_arch4 && TARGET_MMU_TRAPS \ + && (GET_CODE (X) == MEM \ + || ((GET_CODE (X) == REG || GET_CODE (X) == SUBREG) \ + && true_regnum (X) == -1))) \ + ? GENERAL_REGS : NO_REGS) \ + : THUMB_SECONDARY_INPUT_RELOAD_CLASS (CLASS, MODE, X)) /* Try a machine-dependent way of reloading an illegitimate address operand. If we find one, push the reload and jump to WIN. This @@ -1006,55 +1187,89 @@ enum reg_class For the ARM, we wish to handle large displacements off a base register by splitting the addend across a MOV and the mem insn. - This can cut the number of reloads needed. */ -#define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN) \ - do \ - { \ - if (GET_CODE (X) == PLUS \ - && GET_CODE (XEXP (X, 0)) == REG \ - && REGNO (XEXP (X, 0)) < FIRST_PSEUDO_REGISTER \ - && REG_MODE_OK_FOR_BASE_P (XEXP (X, 0), MODE) \ - && GET_CODE (XEXP (X, 1)) == CONST_INT) \ - { \ - HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ - HOST_WIDE_INT low, high; \ - \ - if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \ - low = ((val & 0xf) ^ 0x8) - 0x8; \ - else if (MODE == SImode \ - || (MODE == SFmode && TARGET_SOFT_FLOAT) \ - || ((MODE == HImode || MODE == QImode) && ! arm_arch4)) \ - /* Need to be careful, -4096 is not a valid offset */ \ - low = val >= 0 ? (val & 0xfff) : -((-val) & 0xfff); \ - else if ((MODE == HImode || MODE == QImode) && arm_arch4) \ - /* Need to be careful, -256 is not a valid offset */ \ - low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); \ - else if (GET_MODE_CLASS (MODE) == MODE_FLOAT \ - && TARGET_HARD_FLOAT) \ - /* Need to be careful, -1024 is not a valid offset */ \ - low = val >= 0 ? (val & 0x3ff) : -((-val) & 0x3ff); \ - else \ - break; \ - \ - high = ((((val - low) & 0xffffffffUL) ^ 0x80000000UL) - 0x80000000UL);\ - /* Check for overflow or zero */ \ - if (low == 0 || high == 0 || (high + low != val)) \ - break; \ - \ - /* Reload the high part into a base reg; leave the low part \ - in the mem. */ \ - X = gen_rtx_PLUS (GET_MODE (X), \ - gen_rtx_PLUS (GET_MODE (X), XEXP (X, 0), \ - GEN_INT (high)), \ - GEN_INT (low)); \ - push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \ - BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \ - OPNUM, TYPE); \ - goto WIN; \ - } \ - } \ + This can cut the number of reloads needed. */ +#define ARM_LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND, WIN) \ + do \ + { \ + if (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) < FIRST_PSEUDO_REGISTER \ + && REG_MODE_OK_FOR_BASE_P (XEXP (X, 0), MODE) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ + HOST_WIDE_INT low, high; \ + \ + if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \ + low = ((val & 0xf) ^ 0x8) - 0x8; \ + else if (MODE == SImode \ + || (MODE == SFmode && TARGET_SOFT_FLOAT) \ + || ((MODE == HImode || MODE == QImode) && ! arm_arch4)) \ + /* Need to be careful, -4096 is not a valid offset. */ \ + low = val >= 0 ? (val & 0xfff) : -((-val) & 0xfff); \ + else if ((MODE == HImode || MODE == QImode) && arm_arch4) \ + /* Need to be careful, -256 is not a valid offset. */ \ + low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); \ + else if (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + && TARGET_HARD_FLOAT) \ + /* Need to be careful, -1024 is not a valid offset. */ \ + low = val >= 0 ? (val & 0x3ff) : -((-val) & 0x3ff); \ + else \ + break; \ + \ + high = ((((val - low) & (unsigned long)0xffffffff) \ + ^ (unsigned long)0x80000000) \ + - (unsigned long)0x80000000); \ + /* Check for overflow or zero */ \ + if (low == 0 || high == 0 || (high + low != val)) \ + break; \ + \ + /* Reload the high part into a base reg; leave the low part \ + in the mem. */ \ + X = gen_rtx_PLUS (GET_MODE (X), \ + gen_rtx_PLUS (GET_MODE (X), XEXP (X, 0), \ + GEN_INT (high)), \ + GEN_INT (low)); \ + push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \ + BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \ + OPNUM, TYPE); \ + goto WIN; \ + } \ + } \ while (0) +/* ??? If an HImode FP+large_offset address is converted to an HImode + SP+large_offset address, then reload won't know how to fix it. It sees + only that SP isn't valid for HImode, and so reloads the SP into an index + register, but the resulting address is still invalid because the offset + is too big. We fix it here instead by reloading the entire address. */ +/* We could probably achieve better results by defining PROMOTE_MODE to help + cope with the variances between the Thumb's signed and unsigned byte and + halfword load instructions. */ +#define THUMB_LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN) \ +{ \ + if (GET_CODE (X) == PLUS \ + && GET_MODE_SIZE (MODE) < 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && XEXP (X, 0) == stack_pointer_rtx \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ! LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ + { \ + rtx orig_X = X; \ + X = copy_rtx (X); \ + push_reload (orig_X, NULL_RTX, &X, NULL_PTR, \ + BASE_REG_CLASS, \ + Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \ + goto WIN; \ + } \ +} + +#define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN) \ + if (TARGET_ARM) \ + ARM_LEGITIMIZE_RELOAD_ADDRESS (X, MODE, OPNUM, TYPE, IND_LEVELS, WIN); \ + else \ + THUMB_LEGITIMIZE_RELOAD_ADDRESS (X, MODE, OPNUM, TYPE, IND_LEVELS, WIN) + /* Return the maximum number of consecutive registers needed to represent mode MODE in a register of class CLASS. ARM regs are UNITS_PER_WORD bits while FPU regs can hold any FP mode */ @@ -1062,10 +1277,12 @@ enum reg_class ((CLASS) == FPU_REGS ? 1 : NUM_REGS (MODE)) /* Moves between FPU_REGS and GENERAL_REGS are two memory insns. */ -#define REGISTER_MOVE_COST(CLASS1, CLASS2) \ - ((((CLASS1) == FPU_REGS && (CLASS2) != FPU_REGS) \ - || ((CLASS2) == FPU_REGS && (CLASS1) != FPU_REGS)) \ - ? 20 : 2) +#define REGISTER_MOVE_COST(FROM, TO) \ + (TARGET_ARM ? \ + ((FROM) == FPU_REGS && (TO) != FPU_REGS ? 20 : \ + (FROM) != FPU_REGS && (TO) == FPU_REGS ? 20 : 2) \ + : \ + ((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2) /* Stack layout; function entry, exit and calling. */ @@ -1087,8 +1304,9 @@ enum reg_class /* If we generate an insn to push BYTES bytes, this says how many the stack pointer really advances by. */ -/* The push insns do not do this rounding implicitly. So don't define this. */ -/* #define PUSH_ROUNDING(NPUSHED) (((NPUSHED) + 3) & ~3) */ +/* The push insns do not do this rounding implicitly. + So don't define this. */ +/* #define PUSH_ROUNDING(NPUSHED) ROUND_UP (NPUSHED) */ /* Define this if the maximum size of all the outgoing args is to be accumulated and pushed during the prologue. The amount can be @@ -1096,7 +1314,7 @@ enum reg_class #define ACCUMULATE_OUTGOING_ARGS 1 /* Offset of first parameter from the argument pointer register value. */ -#define FIRST_PARM_OFFSET(FNDECL) 4 +#define FIRST_PARM_OFFSET(FNDECL) (TARGET_ARM ? 4 : 0) /* Value is the number of byte of arguments automatically popped when returning from a subroutine call. @@ -1112,21 +1330,22 @@ enum reg_class /* Define how to find the value returned by a library function assuming the value has mode MODE. */ #define LIBCALL_VALUE(MODE) \ - (GET_MODE_CLASS (MODE) == MODE_FLOAT && TARGET_HARD_FLOAT \ - ? gen_rtx_REG (MODE, 16) \ - : gen_rtx_REG (MODE, 0)) + (TARGET_ARM && TARGET_HARD_FLOAT && GET_MODE_CLASS (MODE) == MODE_FLOAT \ + ? gen_rtx_REG (MODE, FIRST_ARM_FP_REGNUM) \ + : gen_rtx_REG (MODE, ARG_REGISTER (1))) /* Define how to find the value returned by a function. VALTYPE is the data type of the value (as a tree). If the precise function being called is known, FUNC is its FUNCTION_DECL; otherwise, FUNC is 0. */ -#define FUNCTION_VALUE(VALTYPE, FUNC) \ +#define FUNCTION_VALUE(VALTYPE, FUNC) \ LIBCALL_VALUE (TYPE_MODE (VALTYPE)) /* 1 if N is a possible register number for a function value. On the ARM, only r0 and f0 can return results. */ #define FUNCTION_VALUE_REGNO_P(REGNO) \ - ((REGNO) == 0 || (((REGNO) == 16) && TARGET_HARD_FLOAT)) + ((REGNO) == ARG_REGISTER (1) \ + || (TARGET_ARM && ((REGNO) == FIRST_ARM_FP_REGNUM) && TARGET_HARD_FLOAT)) /* How large values are returned */ /* A C expression which can inhibit the returning of certain function values @@ -1138,22 +1357,35 @@ enum reg_class than a word, or if they contain elements offset from zero in the struct. */ #define DEFAULT_PCC_STRUCT_RETURN 0 +/* Flags for the call/call_value rtl operations set up by function_arg. */ +#define CALL_NORMAL 0x00000000 /* No special processing. */ +#define CALL_LONG 0x00000001 /* Always call indirect. */ +#define CALL_SHORT 0x00000002 /* Never call indirect. */ + +/* A C structure for machine-specific, per-function data. This is added + to the cfun structure. */ +struct machine_function +{ + /* Records __builtin_return address. */ + struct rtx_def *ra_rtx; + /* Additionsl stack adjustment in __builtin_eh_throw. */ + struct rtx_def *eh_epilogue_sp_ofs; + /* Records if LR has to be saved for far jumps. */ + int far_jump_used; + /* Records if ARG_POINTER was ever live. */ + int arg_pointer_live; +}; + /* A C type for declaring a variable that is used as the first argument of `FUNCTION_ARG' and other related values. For some target machines, the type `int' suffices and can hold the number of bytes of argument so far. */ typedef struct { - /* This is the number of argument registers scanned so far. */ + /* This is the number of registers of arguments scanned so far. */ int nregs; - /* instructions on how to process this call. */ + /* One of CALL_NORMAL, CALL_LONG or CALL_SHORT . */ int call_cookie; -} -CUMULATIVE_ARGS; - -/* Flags for the call_cookie field of CUMULATIVE_ARGS. */ -#define CALL_NORMAL 0 /* No special processing. */ -#define CALL_LONG 1 /* Always call indirect. */ -#define CALL_SHORT 2 /* Never call indirect. */ +} CUMULATIVE_ARGS; /* Define where to put the arguments to a function. Value is zero to push the argument on the stack, @@ -1224,8 +1456,15 @@ CUMULATIVE_ARGS; } /* Generate assembly output for the start of a function. */ -#define FUNCTION_PROLOGUE(STREAM, SIZE) \ - output_func_prologue ((STREAM), (SIZE)) +#define FUNCTION_PROLOGUE(STREAM, SIZE) \ + do \ + { \ + if (TARGET_ARM) \ + output_arm_prologue (STREAM, SIZE); \ + else \ + output_thumb_prologue (STREAM); \ + } \ + while (0) /* If your target environment doesn't prefix user functions with an underscore, you may wish to re-define this to prevent any conflicts. @@ -1250,13 +1489,13 @@ CUMULATIVE_ARGS; The ``mov ip,lr'' seems like a good idea to stick with cc convention. ``prof'' doesn't seem to mind about this! */ -#define FUNCTION_PROFILER(STREAM, LABELNO) \ +#define ARM_FUNCTION_PROFILER(STREAM, LABELNO) \ { \ char temp[20]; \ rtx sym; \ \ asm_fprintf (STREAM, "\tmov\t%r, %r\n\tbl\t", \ - IP_REGNUM, LR_REGNUM); \ + IP_REGNUM, LR_REGNUM); \ assemble_name (STREAM, ARM_MCOUNT_NAME); \ fputc ('\n', STREAM); \ ASM_GENERATE_INTERNAL_LABEL (temp, "LP", LABELNO); \ @@ -1264,6 +1503,19 @@ CUMULATIVE_ARGS; ASM_OUTPUT_INT (STREAM, sym); \ } +#define THUMB_FUNCTION_PROFILER(STREAM, LABELNO) \ +{ \ + fprintf (STREAM, "\tmov\\tip, lr\n"); \ + fprintf (STREAM, "\tbl\tmcount\n"); \ + fprintf (STREAM, "\t.word\tLP%d\n", LABELNO); \ +} + +#define FUNCTION_PROFILER(STREAM, LABELNO) \ + if (TARGET_ARM) \ + ARM_FUNCTION_PROFILER (STREAM, LABELNO) \ + else \ + THUMB_FUNCTION_PROFILER (STREAM, LABELNO) + /* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, the stack pointer does not matter. The value is tested only in functions that have frame pointers. @@ -1274,12 +1526,13 @@ CUMULATIVE_ARGS; #define EXIT_IGNORE_STACK 1 /* Generate the assembly code for function exit. */ -#define FUNCTION_EPILOGUE(STREAM, SIZE) \ +#define FUNCTION_EPILOGUE(STREAM, SIZE) \ output_func_epilogue (SIZE) /* Determine if the epilogue should be output as RTL. You should override this if you define FUNCTION_EXTRA_EPILOGUE. */ -#define USE_RETURN_INSN(ISCOND) use_return_insn (ISCOND) +#define USE_RETURN_INSN(ISCOND) \ + (TARGET_ARM ? use_return_insn (ISCOND) : 0) /* Definitions for register eliminations. @@ -1292,27 +1545,36 @@ CUMULATIVE_ARGS; arg pointer register can often be eliminated in favor of the stack pointer register. Secondly, the pseudo frame pointer register can always be eliminated; it is replaced with either the stack or the real frame - pointer. */ + pointer. Note we have to use {ARM|THUMB}_HARD_FRAME_POINTER_REGNUM + because the defintion of HARD_FRAME_POINTER_REGNUM is not a constant. */ -#define ELIMINABLE_REGS \ -{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ - { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }, \ - { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ - { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }} +#define ELIMINABLE_REGS \ +{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM },\ + { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM },\ + { ARG_POINTER_REGNUM, ARM_HARD_FRAME_POINTER_REGNUM },\ + { ARG_POINTER_REGNUM, THUMB_HARD_FRAME_POINTER_REGNUM },\ + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM },\ + { FRAME_POINTER_REGNUM, ARM_HARD_FRAME_POINTER_REGNUM },\ + { FRAME_POINTER_REGNUM, THUMB_HARD_FRAME_POINTER_REGNUM }} -/* Given FROM and TO register numbers, say whether this elimination is allowed. - Frame pointer elimination is automatically handled. +/* Given FROM and TO register numbers, say whether this elimination is + allowed. Frame pointer elimination is automatically handled. All eliminations are permissible. Note that ARG_POINTER_REGNUM and HARD_FRAME_POINTER_REGNUM are in fact the same thing. If we need a frame pointer, we must eliminate FRAME_POINTER_REGNUM into - HARD_FRAME_POINTER_REGNUM and not into STACK_POINTER_REGNUM. */ -#define CAN_ELIMINATE(FROM, TO) \ - (((TO) == STACK_POINTER_REGNUM && frame_pointer_needed) ? 0 : 1) - -/* Define the offset between two registers, one to be eliminated, and the other - its replacement, at the start of a routine. */ -#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + HARD_FRAME_POINTER_REGNUM and not into STACK_POINTER_REGNUM or + ARG_POINTER_REGNUM. */ +#define CAN_ELIMINATE(FROM, TO) \ + (((TO) == FRAME_POINTER_REGNUM && (FROM) == ARG_POINTER_REGNUM) ? 0 : \ + ((TO) == STACK_POINTER_REGNUM && frame_pointer_needed) ? 0 : \ + ((TO) == ARM_HARD_FRAME_POINTER_REGNUM && TARGET_THUMB) ? 0 : \ + ((TO) == THUMB_HARD_FRAME_POINTER_REGNUM && TARGET_ARM) ? 0 : \ + 1) + +/* Define the offset between two registers, one to be eliminated, and the + other its replacement, at the start of a routine. */ +#define ARM_INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ { \ int volatile_func = arm_volatile_func (); \ if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\ @@ -1320,7 +1582,7 @@ CUMULATIVE_ARGS; else if ((FROM) == FRAME_POINTER_REGNUM \ && (TO) == STACK_POINTER_REGNUM) \ (OFFSET) = current_function_outgoing_args_size \ - + ((get_frame_size () + 3) & ~3); \ + + ROUND_UP (get_frame_size ()); \ else \ { \ int regno; \ @@ -1332,15 +1594,21 @@ CUMULATIVE_ARGS; for (regno = 0; regno <= 10; regno++) \ if (regs_ever_live[regno] && ! call_used_regs[regno]) \ saved_hard_reg = 1, offset += 4; \ + if (! TARGET_APCS_FRAME \ + && ! frame_pointer_needed \ + && regs_ever_live[HARD_FRAME_POINTER_REGNUM] \ + && ! call_used_regs[HARD_FRAME_POINTER_REGNUM]) \ + saved_hard_reg = 1, offset += 4; \ /* PIC register is a fixed reg, so call_used_regs set. */ \ if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) \ saved_hard_reg = 1, offset += 4; \ - for (regno = 16; regno <=23; regno++) \ + for (regno = FIRST_ARM_FP_REGNUM; \ + regno <= LAST_ARM_FP_REGNUM; regno++) \ if (regs_ever_live[regno] && ! call_used_regs[regno]) \ offset += 12; \ } \ if ((FROM) == FRAME_POINTER_REGNUM) \ - (OFFSET) = -offset; \ + (OFFSET) = - offset; \ else \ { \ if (! frame_pointer_needed) \ @@ -1349,11 +1617,58 @@ CUMULATIVE_ARGS; && (regs_ever_live[LR_REGNUM] || saved_hard_reg)) \ offset += 4; \ offset += current_function_outgoing_args_size; \ - (OFFSET) = ((get_frame_size () + 3) & ~3) + offset; \ + (OFFSET) = ROUND_UP (get_frame_size ()) + offset; \ } \ } \ } +/* Note: This macro must match the code in thumb_function_prologue(). */ +#define THUMB_INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ +{ \ + (OFFSET) = 0; \ + if ((FROM) == ARG_POINTER_REGNUM) \ + { \ + int count_regs = 0; \ + int regno; \ + for (regno = 8; regno < 13; regno ++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + count_regs ++; \ + if (count_regs) \ + (OFFSET) += 4 * count_regs; \ + count_regs = 0; \ + for (regno = 0; regno <= LAST_LO_REGNUM; regno ++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + count_regs ++; \ + if (count_regs || ! leaf_function_p () || thumb_far_jump_used_p (0))\ + (OFFSET) += 4 * (count_regs + 1); \ + if (TARGET_BACKTRACE) \ + { \ + if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0)) \ + (OFFSET) += 20; \ + else \ + (OFFSET) += 16; \ + } \ + } \ + if ((TO) == STACK_POINTER_REGNUM) \ + { \ + (OFFSET) += current_function_outgoing_args_size; \ + (OFFSET) += ROUND_UP (get_frame_size ()); \ + } \ +} + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + if (TARGET_ARM) \ + ARM_INITIAL_ELIMINATION_OFFSET (FROM, TO, OFFSET) \ + else \ + THUMB_INITIAL_ELIMINATION_OFFSET (FROM, TO, OFFSET) + +/* Special case handling of the location of arguments passed on the stack. */ +#define DEBUGGER_ARG_OFFSET(value, addr) value ? value : arm_debugger_arg_offset (value, addr) + +/* Initialize data used by insn expanders. This is called from insn_emit, + once for every function before code is generated. */ +#define INIT_EXPANDERS arm_init_expanders () + /* Output assembler code for a block containing the constant parts of a trampoline, leaving space for the variable parts. @@ -1364,20 +1679,47 @@ CUMULATIVE_ARGS; .word static chain value .word function's address ??? FIXME: When the trampoline returns, r8 will be clobbered. */ -#define TRAMPOLINE_TEMPLATE(FILE) \ -{ \ - fprintf ((FILE), "\tldr\t%s%s, [%s%s, #0]\n", \ - REGISTER_PREFIX, reg_names[STATIC_CHAIN_REGNUM], \ - REGISTER_PREFIX, reg_names[PC_REGNUM]); \ - fprintf ((FILE), "\tldr\t%s%s, [%s%s, #0]\n", \ - REGISTER_PREFIX, reg_names[PC_REGNUM], \ - REGISTER_PREFIX, reg_names[PC_REGNUM]); \ - ASM_OUTPUT_INT ((FILE), const0_rtx); \ - ASM_OUTPUT_INT ((FILE), const0_rtx); \ +#define ARM_TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + asm_fprintf (FILE, "\tldr\t%r, [%r, #0]\n", \ + STATIC_CHAIN_REGNUM, PC_REGNUM); \ + asm_fprintf (FILE, "\tldr\t%r, [%r, #0]\n", \ + PC_REGNUM, PC_REGNUM); \ + ASM_OUTPUT_INT (FILE, const0_rtx); \ + ASM_OUTPUT_INT (FILE, const0_rtx); \ +} + +/* On the Thumb we always switch into ARM mode to execute the trampoline. + Why - because it is easier. This code will always be branched to via + a BX instruction and since the compiler magically generates the address + of the function the linker has no opportunity to ensure that the + bottom bit is set. Thus the processor will be in ARM mode when it + reaches this code. So we duplicate the ARM trampoline code and add + a switch into Thumb mode as well. */ +#define THUMB_TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf (FILE, "\t.code 32\n"); \ + fprintf (FILE, ".Ltrampoline_start:\n"); \ + asm_fprintf (FILE, "\tldr\t%r, [%r, #8]\n", \ + STATIC_CHAIN_REGNUM, PC_REGNUM); \ + asm_fprintf (FILE, "\tldr\t%r, [%r, #8]\n", \ + IP_REGNUM, PC_REGNUM); \ + asm_fprintf (FILE, "\torr\t%r, %r, #1\n", \ + IP_REGNUM, IP_REGNUM); \ + asm_fprintf (FILE, "\tbx\t%r\n", IP_REGNUM); \ + fprintf (FILE, "\t.word\t0\n"); \ + fprintf (FILE, "\t.word\t0\n"); \ + fprintf (FILE, "\t.code 16\n"); \ } +#define TRAMPOLINE_TEMPLATE(FILE) \ + if (TARGET_ARM) \ + ARM_TRAMPOLINE_TEMPLATE (FILE) \ + else \ + THUMB_TRAMPOLINE_TEMPLATE (FILE) + /* Length in units of the trampoline for entering a nested function. */ -#define TRAMPOLINE_SIZE 16 +#define TRAMPOLINE_SIZE (TARGET_ARM ? 16 : 24) /* Alignment required for a trampoline in units. */ #define TRAMPOLINE_ALIGN 4 @@ -1385,21 +1727,20 @@ CUMULATIVE_ARGS; /* Emit RTL insns to initialize the variable parts of a trampoline. FNADDR is an RTX for the address of the function's pure code. CXT is an RTX for the static chain value for the function. */ -#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ -{ \ - emit_move_insn (gen_rtx_MEM (SImode, plus_constant ((TRAMP), 8)), \ - (CXT)); \ - emit_move_insn (gen_rtx_MEM (SImode, plus_constant ((TRAMP), 12)), \ - (FNADDR)); \ +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ +{ \ + emit_move_insn \ + (gen_rtx_MEM (SImode, plus_constant (TRAMP, TARGET_ARM ? 8 : 16)), CXT); \ + emit_move_insn \ + (gen_rtx_MEM (SImode, plus_constant (TRAMP, TARGET_ARM ? 12 : 20)), FNADDR); \ } /* Addressing modes, and classification of registers for them. */ - #define HAVE_POST_INCREMENT 1 -#define HAVE_PRE_INCREMENT 1 -#define HAVE_POST_DECREMENT 1 -#define HAVE_PRE_DECREMENT 1 +#define HAVE_PRE_INCREMENT TARGET_ARM +#define HAVE_POST_DECREMENT TARGET_ARM +#define HAVE_PRE_DECREMENT TARGET_ARM /* Macros to check register numbers against specific register classes. */ @@ -1407,21 +1748,33 @@ CUMULATIVE_ARGS; They give nonzero only if REGNO is a hard reg of the suitable class or a pseudo reg currently allocated to a suitable hard reg. Since they use reg_renumber, they are safe only once reg_renumber - has been allocated, which happens in local-alloc.c. - - On the ARM, don't allow the pc to be used. */ -#define REGNO_OK_FOR_BASE_P(REGNO) \ - ((REGNO) < 15 || (REGNO) == FRAME_POINTER_REGNUM \ - || (REGNO) == ARG_POINTER_REGNUM \ - || (unsigned) reg_renumber[(REGNO)] < 15 \ - || (unsigned) reg_renumber[(REGNO)] == FRAME_POINTER_REGNUM \ - || (unsigned) reg_renumber[(REGNO)] == ARG_POINTER_REGNUM) -#define REGNO_OK_FOR_INDEX_P(REGNO) \ - REGNO_OK_FOR_BASE_P(REGNO) + has been allocated, which happens in local-alloc.c. */ +#define TEST_REGNO(R, TEST, VALUE) \ + ((R TEST VALUE) || ((unsigned) reg_renumber[R] TEST VALUE)) + +/* On the ARM, don't allow the pc to be used. */ +#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ + (TARGET_THUMB ? \ + ( TEST_REGNO (REGNO, <=, LAST_LO_REGNUM) \ + || (GET_MODE_SIZE (MODE) >= 4 \ + && TEST_REGNO (REGNO, ==, STACK_POINTER_REGNUM))) \ + :( \ + TEST_REGNO (REGNO, <, PC_REGNUM) \ + || TEST_REGNO (REGNO, ==, FRAME_POINTER_REGNUM) \ + || TEST_REGNO (REGNO, ==, ARG_POINTER_REGNUM))) + +/* This is like REGNO_MODE_OF_FOR_BASE_P, except that in Thumb mode + the stack pointer is always acceptable, hence the passing of SImode */ +#define REGNO_OK_FOR_BASE_P(REGNO) \ + REGNO_MODE_OK_FOR_BASE_P (REGNO, SImode) + +/* We play tricks with REGNO_MODE_OK... here, so that for ARM the macros + are the same, but for Thumb only registers 0 - 7 are OK. */ +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + REGNO_MODE_OK_FOR_BASE_P (REGNO, QImode) /* Maximum number of registers that can appear in a valid memory address. Shifts in addresses can't be by a register. */ - #define MAX_REGS_PER_ADDRESS 2 /* Recognize any constant value that is a valid address. */ @@ -1430,15 +1783,14 @@ CUMULATIVE_ARGS; #ifdef AOF_ASSEMBLER #define CONSTANT_ADDRESS_P(X) \ - (GET_CODE (X) == SYMBOL_REF \ - && CONSTANT_POOL_ADDRESS_P (X)) + (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X)) #else #define CONSTANT_ADDRESS_P(X) \ (GET_CODE (X) == SYMBOL_REF \ && (CONSTANT_POOL_ADDRESS_P (X) \ - || (optimize > 0 && SYMBOL_REF_FLAG (X)))) + || (TARGET_ARM && optimize > 0 && SYMBOL_REF_FLAG (X)))) #endif /* AOF_ASSEMBLER */ @@ -1447,11 +1799,19 @@ CUMULATIVE_ARGS; On the ARM, allow any integer (invalid ones are removed later by insn patterns), nice doubles and symbol_refs which refer to the function's - constant pool XXX. + constant pool XXX. When generating pic allow anything. */ -#define LEGITIMATE_CONSTANT_P(X) (flag_pic || ! label_mentioned_p (X)) - +#define ARM_LEGITIMATE_CONSTANT_P(X) (flag_pic || ! label_mentioned_p (X)) + +#define THUMB_LEGITIMATE_CONSTANT_P(X) \ + ( GET_CODE (X) == CONST_INT \ + || GET_CODE (X) == CONST_DOUBLE \ + || CONSTANT_ADDRESS_P (X)) + +#define LEGITIMATE_CONSTANT_P(X) \ + (TARGET_ARM ? ARM_LEGITIMATE_CONSTANT_P (X) : THUMB_LEGITIMATE_CONSTANT_P (X)) + /* Special characters prefixed to function names in order to encode attribute like information. Note, '@' and '*' have already been taken. */ @@ -1475,7 +1835,6 @@ CUMULATIVE_ARGS; #define ARM_NAME_ENCODING_LENGTHS \ case SHORT_CALL_FLAG_CHAR: return 1; \ case LONG_CALL_FLAG_CHAR: return 1; \ - case '*': return 1; \ SUBTARGET_NAME_ENCODING_LENGTHS /* This has to be handled by a function because more than part of the @@ -1538,22 +1897,36 @@ CUMULATIVE_ARGS; The symbol REG_OK_STRICT causes the latter definition to be used. */ #ifndef REG_OK_STRICT +#define REG_MODE_OK_FOR_BASE_P(X, MODE) \ + (TARGET_THUMB ? \ + ( REGNO (X) <= LAST_LO_REGNUM \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || (GET_MODE_SIZE (MODE) >= 4 \ + && (REGNO (X) == STACK_POINTER_REGNUM \ + || (X) == hard_frame_pointer_rtx \ + || (X) == arg_pointer_rtx))) \ + :( \ + REGNO (X) <= LAST_ARM_REGNUM \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM \ + || REGNO (X) == ARG_POINTER_REGNUM)) + /* Nonzero if X is a hard reg that can be used as a base reg or if it is a pseudo reg. */ #define REG_OK_FOR_BASE_P(X) \ - (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ - || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + REG_MODE_OK_FOR_BASE_P (X, SImode) /* Nonzero if X is a hard reg that can be used as an index - or if it is a pseudo reg. */ + or if it is a pseudo reg. On the Thumb, the stack pointer + is not suitable. */ #define REG_OK_FOR_INDEX_P(X) \ - REG_OK_FOR_BASE_P(X) + REG_MODE_OK_FOR_BASE_P (X, QImode) -#define REG_OK_FOR_PRE_POST_P(X) \ - (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ - || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) +/* Just like REG_OK_FOR_BASE_P except that we also allow the PC. */ +#define REG_OK_FOR_PRE_POST_P(X) \ + (REG_OK_FOR_BASE_P (X) || REGNO(X) == PC_REGNUM) -#else +#else /* REG_OK_STRICT */ /* Nonzero if X is a hard reg that can be used as a base reg. */ #define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) @@ -1561,20 +1934,20 @@ CUMULATIVE_ARGS; /* Nonzero if X is a hard reg that can be used as an index. */ #define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) -#define REG_OK_FOR_PRE_POST_P(X) \ - (REGNO (X) < 16 || (unsigned) reg_renumber[REGNO (X)] < 16 \ - || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM \ - || (unsigned) reg_renumber[REGNO (X)] == FRAME_POINTER_REGNUM \ - || (unsigned) reg_renumber[REGNO (X)] == ARG_POINTER_REGNUM) +/* Just like REG_OK_FOR_BASE_P except that we also allow the PC. */ +#define REG_OK_FOR_PRE_POST_P(X) \ + (REG_OK_FOR_BASE_P (X) || TEST_REGNO (REGNO (X), ==, PC_REGNUM)) -#endif +#endif /* REG_OK_STRICT */ /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression that is a valid memory address for an instruction. The MODE argument is the machine mode for the MEM expression that wants to use this address. - The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ + +/* --------------------------------arm version----------------------------- */ #define BASE_REGISTER_RTX_P(X) \ (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) @@ -1640,7 +2013,7 @@ CUMULATIVE_ARGS; INDEX+REG, REG-INDEX, and non floating SYMBOL_REF to the constant pool. Allow REG-only and AUTINC-REG if handling TImode or HImode. Other symbol refs must be forced though a static cell to ensure addressability. */ -#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ +#define ARM_GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ { \ if (BASE_REGISTER_RTX_P (X)) \ goto LABEL; \ @@ -1669,8 +2042,8 @@ CUMULATIVE_ARGS; } \ else if (GET_CODE (X) == PLUS) \ { \ - rtx xop0 = XEXP(X,0); \ - rtx xop1 = XEXP(X,1); \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ \ if (BASE_REGISTER_RTX_P (xop0)) \ GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop0), xop1, LABEL); \ @@ -1698,6 +2071,119 @@ CUMULATIVE_ARGS; && REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \ goto LABEL; \ } + +/* ---------------------thumb version----------------------------------*/ +#define LEGITIMATE_OFFSET(MODE, VAL) \ + (GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ + : GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \ + && ((VAL) & 1) == 0) \ + : ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \ + && ((VAL) & 3) == 0)) + +/* The AP may be eliminated to either the SP or the FP, so we use the + least common denominator, e.g. SImode, and offsets from 0 to 64. */ + +/* ??? Verify whether the above is the right approach. */ + +/* ??? Also, the FP may be eliminated to the SP, so perhaps that + needs special handling also. */ + +/* ??? Look at how the mips16 port solves this problem. It probably uses + better ways to solve some of these problems. */ + +/* Although it is not incorrect, we don't accept QImode and HImode + addresses based on the frame pointer or arg pointer until the reload pass starts. + This is so that eliminating such addresses into stack based ones + won't produce impossible code. */ +#define THUMB_GO_IF_LEGITIMATE_ADDRESS(MODE, X, WIN) \ +{ \ +/* ??? Not clear if this is right. Experiment. */ \ + if (GET_MODE_SIZE (MODE) < 4 \ + && ! (reload_in_progress || reload_completed) \ + && ( reg_mentioned_p (frame_pointer_rtx, X) \ + || reg_mentioned_p (arg_pointer_rtx, X) \ + || reg_mentioned_p (virtual_incoming_args_rtx, X) \ + || reg_mentioned_p (virtual_outgoing_args_rtx, X) \ + || reg_mentioned_p (virtual_stack_dynamic_rtx, X) \ + || reg_mentioned_p (virtual_stack_vars_rtx, X))) \ + ; \ + /* Accept any base register. SP only in SImode or larger. */ \ + else if (GET_CODE (X) == REG && REG_MODE_OK_FOR_BASE_P (X, MODE)) \ + goto WIN; \ + /* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \ + else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \ + && CONSTANT_POOL_ADDRESS_P (X) && ! flag_pic) \ + goto WIN; \ + /* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \ + else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ + && (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST \ + && GET_CODE (XEXP (X, 0)) == PLUS \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \ + && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \ + goto WIN; \ + /* Post-inc indexing only supported for SImode and larger. */ \ + else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ + goto WIN; \ + else if (GET_CODE (X) == PLUS) \ + { \ + /* REG+REG address can be any two index registers. */ \ + /* We disallow FRAME+REG addressing since we know that FRAME \ + will be replaced with STACK, and SP relative addressing only \ + permits SP+OFFSET. */ \ + if (GET_MODE_SIZE (MODE) <= 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && GET_CODE (XEXP (X, 1)) == REG \ + && XEXP (X, 0) != frame_pointer_rtx \ + && XEXP (X, 1) != frame_pointer_rtx \ + && XEXP (X, 0) != virtual_stack_vars_rtx \ + && XEXP (X, 1) != virtual_stack_vars_rtx \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ + goto WIN; \ + /* REG+const has 5-7 bit offset for non-SP registers. */ \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && (REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + || XEXP (X, 0) == arg_pointer_rtx) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ + goto WIN; \ + /* REG+const has 10 bit offset for SP, but only SImode and \ + larger is supported. */ \ + /* ??? Should probably check for DI/DFmode overflow here \ + just like GO_IF_LEGITIMATE_OFFSET does. */ \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \ + && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) \ + + GET_MODE_SIZE (MODE)) <= 1024 \ + && (INTVAL (XEXP (X, 1)) & 3) == 0) \ + goto WIN; \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) == FRAME_POINTER_REGNUM \ + && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (INTVAL (XEXP (X, 1)) & 3) == 0) \ + goto WIN; \ + } \ + else if (GET_MODE_CLASS (MODE) != MODE_FLOAT \ + && GET_CODE (X) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (X) \ + && ! (flag_pic \ + && symbol_mentioned_p (get_pool_constant (X)))) \ + goto WIN; \ +} + +/* ------------------------------------------------------------------- */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, WIN) \ + if (TARGET_ARM) \ + ARM_GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN) \ + else /* if (TARGET_THUMB) */ \ + THUMB_GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN) +/* ------------------------------------------------------------------- */ /* Try machine-dependent ways of modifying an illegitimate address to be legitimate. If we find one, return the new, valid address. @@ -1715,7 +2201,7 @@ CUMULATIVE_ARGS; On the ARM, try to convert [REG, #BIGCONST] into ADD BASE, REG, #UPPERCONST and [BASE, #VALIDCONST], where VALIDCONST == 0 in case of TImode. */ -#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ +#define ARM_LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ { \ if (GET_CODE (X) == PLUS) \ { \ @@ -1776,18 +2262,34 @@ CUMULATIVE_ARGS; goto WIN; \ } +#define THUMB_LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ + if (flag_pic) \ + (X) = legitimize_pic_address (OLDX, MODE, NULL_RTX); + +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ + if (TARGET_ARM) \ + ARM_LEGITIMIZE_ADDRESS (X, OLDX, MODE, WIN) \ + else \ + THUMB_LEGITIMIZE_ADDRESS (X, OLDX, MODE, WIN) + /* Go to LABEL if ADDR (a legitimate address expression) has an effect that depends on the machine mode it is used for. */ -#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ +#define ARM_GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ { \ - if (GET_CODE(ADDR) == PRE_DEC || GET_CODE(ADDR) == POST_DEC \ - || GET_CODE(ADDR) == PRE_INC || GET_CODE(ADDR) == POST_INC) \ + if ( GET_CODE (ADDR) == PRE_DEC || GET_CODE (ADDR) == POST_DEC \ + || GET_CODE (ADDR) == PRE_INC || GET_CODE (ADDR) == POST_INC) \ goto LABEL; \ } + +/* Nothing helpful to do for the Thumb */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ + if (TARGET_ARM) \ + ARM_GO_IF_MODE_DEPENDENT_ADDRESS (ADDR, LABEL) + /* Specify the machine mode that this machine uses for the index in the tablejump instruction. */ -#define CASE_VECTOR_MODE SImode +#define CASE_VECTOR_MODE Pmode /* Define as C expression which evaluates to nonzero if the tablejump instruction expects the table to contain offsets from the address of the @@ -1823,8 +2325,9 @@ CUMULATIVE_ARGS; be the code that says which one of the two operations is implicitly done, NIL if none. */ #define LOAD_EXTEND_OP(MODE) \ - ((arm_arch4 || (MODE) == QImode) ? ZERO_EXTEND \ - : ((BYTES_BIG_ENDIAN && (MODE) == HImode) ? SIGN_EXTEND : NIL)) + (TARGET_THUMB ? ZERO_EXTEND : \ + ((arm_arch4 || (MODE) == QImode) ? ZERO_EXTEND \ + : ((BYTES_BIG_ENDIAN && (MODE) == HImode) ? SIGN_EXTEND : NIL))) /* Define this if zero-extension is slow (more than one real instruction). On the ARM, it is more than one instruction only if not fetching from @@ -1834,6 +2337,8 @@ CUMULATIVE_ARGS; /* Nonzero if access to memory by bytes is slow and undesirable. */ #define SLOW_BYTE_ACCESS 0 +#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) 1 + /* Immediate shift counts are truncated by the output routines (or was it the assembler?). Shift counts in a register are truncated by ARM. Note that the native compiler puts too large (> 32) immediate shift counts @@ -1846,7 +2351,7 @@ CUMULATIVE_ARGS; /* #define SHIFT_COUNT_TRUNCATED 1 */ /* All integers have the same format so truncation is easy. */ -#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 /* Calling from registers is a massive pain. */ #define NO_FUNCTION_CSE 1 @@ -1858,52 +2363,24 @@ CUMULATIVE_ARGS; #define Pmode SImode #define FUNCTION_MODE Pmode -/* The structure type of the machine dependent info field of insns - No uses for this yet. */ -/* #define INSN_MACHINE_INFO struct machine_info */ - -/* The relative costs of various types of constants. Note that cse.c defines - REG = 1, SUBREG = 2, any node = (2 + sum of subnodes). */ -#define CONST_COSTS(RTX, CODE, OUTER_CODE) \ - case CONST_INT: \ - if (const_ok_for_arm (INTVAL (RTX))) \ - return (OUTER_CODE) == SET ? 2 : -1; \ - else if (OUTER_CODE == AND \ - && const_ok_for_arm (~INTVAL (RTX))) \ - return -1; \ - else if ((OUTER_CODE == COMPARE \ - || OUTER_CODE == PLUS || OUTER_CODE == MINUS) \ - && const_ok_for_arm (-INTVAL (RTX))) \ - return -1; \ - else \ - return 5; \ - case CONST: \ - case LABEL_REF: \ - case SYMBOL_REF: \ - return 6; \ - case CONST_DOUBLE: \ - if (const_double_rtx_ok_for_fpu (RTX)) \ - return (OUTER_CODE) == SET ? 2 : -1; \ - else if (((OUTER_CODE) == COMPARE || (OUTER_CODE) == PLUS) \ - && neg_const_double_rtx_ok_for_fpu (RTX)) \ - return -1; \ - return(7); - -#define ARM_FRAME_RTX(X) \ - ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ +#define ARM_FRAME_RTX(X) \ + ( (X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ || (X) == arg_pointer_rtx) #define DEFAULT_RTX_COSTS(X, CODE, OUTER_CODE) \ - return arm_rtx_costs (X, CODE); + return arm_rtx_costs (X, CODE, OUTER_CODE); /* Moves to and from memory are quite expensive */ -#define MEMORY_MOVE_COST(MODE,CLASS,IN) 10 - +#define MEMORY_MOVE_COST(M, CLASS, IN) \ + (TARGET_ARM ? 10 : \ + ((GET_MODE_SIZE (M) < 4 ? 8 : 2 * GET_MODE_SIZE (M)) \ + * (CLASS == LO_REGS ? 1 : 2))) + /* All address computations that can be done are free, but rtx cost returns the same for practically all of them. So we weight the different types of address here in the order (most pref first): PRE/POST_INC/DEC, SHIFT or NON-INT sum, INT sum, REG, MEM or LABEL. */ -#define ADDRESS_COST(X) \ +#define ARM_ADDRESS_COST(X) \ (10 - ((GET_CODE (X) == MEM || GET_CODE (X) == LABEL_REF \ || GET_CODE (X) == SYMBOL_REF) \ ? 0 \ @@ -1918,10 +2395,20 @@ CUMULATIVE_ARGS; || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == 'c') \ ? 1 : 0)) \ : 4))))) - + +#define THUMB_ADDRESS_COST(X) \ + ((GET_CODE (X) == REG \ + || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \ + && GET_CODE (XEXP (X, 1)) == CONST_INT)) \ + ? 1 : 2) + +#define ADDRESS_COST(X) \ + (TARGET_ARM ? ARM_ADDRESS_COST (X) : THUMB_ADDRESS_COST (X)) + /* Try to generate sequences that don't involve branches, we can then use conditional instructions */ -#define BRANCH_COST 4 +#define BRANCH_COST \ + (TARGET_ARM ? 4 : (optimize > 1 ? 1 : 0)) /* A C statement to update the variable COST based on the relationship between INSN that is dependent on DEP through dependence LINK. */ @@ -1987,25 +2474,25 @@ extern int making_const_table; CC_Zmode should be used if only the Z flag is set correctly CCmode should be used otherwise. */ -#define EXTRA_CC_MODES \ - CC(CC_NOOVmode, "CC_NOOV") \ - CC(CC_Zmode, "CC_Z") \ - CC(CC_SWPmode, "CC_SWP") \ - CC(CCFPmode, "CCFP") \ - CC(CCFPEmode, "CCFPE") \ - CC(CC_DNEmode, "CC_DNE") \ - CC(CC_DEQmode, "CC_DEQ") \ - CC(CC_DLEmode, "CC_DLE") \ - CC(CC_DLTmode, "CC_DLT") \ - CC(CC_DGEmode, "CC_DGE") \ - CC(CC_DGTmode, "CC_DGT") \ - CC(CC_DLEUmode, "CC_DLEU") \ - CC(CC_DLTUmode, "CC_DLTU") \ - CC(CC_DGEUmode, "CC_DGEU") \ - CC(CC_DGTUmode, "CC_DGTU") \ - CC(CC_Cmode, "CC_C") - -#define SELECT_CC_MODE(OP,X,Y) arm_select_cc_mode ((OP), (X), (Y)) +#define EXTRA_CC_MODES \ + CC(CC_NOOVmode, "CC_NOOV") \ + CC(CC_Zmode, "CC_Z") \ + CC(CC_SWPmode, "CC_SWP") \ + CC(CCFPmode, "CCFP") \ + CC(CCFPEmode, "CCFPE") \ + CC(CC_DNEmode, "CC_DNE") \ + CC(CC_DEQmode, "CC_DEQ") \ + CC(CC_DLEmode, "CC_DLE") \ + CC(CC_DLTmode, "CC_DLT") \ + CC(CC_DGEmode, "CC_DGE") \ + CC(CC_DGTmode, "CC_DGT") \ + CC(CC_DLEUmode, "CC_DLEU") \ + CC(CC_DLTUmode, "CC_DLTU") \ + CC(CC_DGEUmode, "CC_DGEU") \ + CC(CC_DGTUmode, "CC_DGTU") \ + CC(CC_Cmode, "CC_C") + +#define SELECT_CC_MODE(OP, X, Y) arm_select_cc_mode (OP, X, Y) #define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode) @@ -2025,49 +2512,17 @@ extern int making_const_table; #define STORE_FLAG_VALUE 1 -/* Define the information needed to generate branch insns. This is - stored from the compare operation. Note that we can't use "rtx" here - since it hasn't been defined! */ - -extern struct rtx_def * arm_compare_op0; -extern struct rtx_def * arm_compare_op1; - -/* Define the codes that are matched by predicates in arm.c */ -#define PREDICATE_CODES \ - {"s_register_operand", {SUBREG, REG}}, \ - {"f_register_operand", {SUBREG, REG}}, \ - {"arm_add_operand", {SUBREG, REG, CONST_INT}}, \ - {"fpu_add_operand", {SUBREG, REG, CONST_DOUBLE}}, \ - {"arm_rhs_operand", {SUBREG, REG, CONST_INT}}, \ - {"fpu_rhs_operand", {SUBREG, REG, CONST_DOUBLE}}, \ - {"arm_not_operand", {SUBREG, REG, CONST_INT}}, \ - {"offsettable_memory_operand", {MEM}}, \ - {"bad_signed_byte_operand", {MEM}}, \ - {"alignable_memory_operand", {MEM}}, \ - {"shiftable_operator", {PLUS, MINUS, AND, IOR, XOR}}, \ - {"minmax_operator", {SMIN, SMAX, UMIN, UMAX}}, \ - {"shift_operator", {ASHIFT, ASHIFTRT, LSHIFTRT, ROTATERT, MULT}}, \ - {"di_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE, MEM}}, \ - {"soft_df_operand", {SUBREG, REG, CONST_DOUBLE, MEM}}, \ - {"load_multiple_operation", {PARALLEL}}, \ - {"store_multiple_operation", {PARALLEL}}, \ - {"equality_operator", {EQ, NE}}, \ - {"arm_rhsm_operand", {SUBREG, REG, CONST_INT, MEM}}, \ - {"const_shift_operand", {CONST_INT}}, \ - {"index_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_int_operand", {SUBREG, REG, CONST_INT}}, \ - {"multi_register_push", {PARALLEL}}, \ - {"cc_register", {REG}}, \ - {"logical_binary_operator", {AND, IOR, XOR}}, \ - {"dominant_cc_register", {REG}}, - /* Gcc puts the pool in the wrong place for ARM, since we can only load addresses a limited distance around the pc. We do some special munging to move the constant pool values to the correct point in the code. */ -#define MACHINE_DEPENDENT_REORG(INSN) arm_reorg ((INSN)) +#define MACHINE_DEPENDENT_REORG(INSN) \ + arm_reorg (INSN); \ + +#undef ASM_APP_OFF +#define ASM_APP_OFF (TARGET_THUMB ? "\t.code\t16\n" : "") /* Output an internal label definition. */ #ifndef ASM_OUTPUT_INTERNAL_LABEL @@ -2089,20 +2544,67 @@ extern struct rtx_def * arm_compare_op1; #endif /* Output a push or a pop instruction (only used when profiling). */ -#define ASM_OUTPUT_REG_PUSH(STREAM, REGNO) \ - asm_fprintf (STREAM,"\tstmfd\t%r!,{%r}\n", SP_REGNUM, REGNO) - -#define ASM_OUTPUT_REG_POP(STREAM, REGNO) \ - asm_fprintf (STREAM,"\tldmfd\t%r!,{%r}\n", SP_REGNUM, REGNO) +#define ASM_OUTPUT_REG_PUSH(STREAM, REGNO) \ + if (TARGET_ARM) \ + asm_fprintf (STREAM,"\tstmfd\t%r!,{%r}\n", \ + STACK_POINTER_REGNUM, REGNO); \ + else \ + asm_fprintf (STREAM, "\tpush {%r}\n", REGNO) + + +#define ASM_OUTPUT_REG_POP(STREAM, REGNO) \ + if (TARGET_ARM) \ + asm_fprintf (STREAM, "\tldmfd\t%r!,{%r}\n", \ + STACK_POINTER_REGNUM, REGNO); \ + else \ + asm_fprintf (STREAM, "\tpop {%r}\n", REGNO) + +/* This is how to output a label which precedes a jumptable. Since + Thumb instructions are 2 bytes, we may need explicit alignment here. */ +#define ASM_OUTPUT_CASE_LABEL(FILE, PREFIX, NUM, JUMPTABLE) \ + do \ + { \ + if (TARGET_THUMB) \ + ASM_OUTPUT_ALIGN (FILE, 2); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \ + } \ + while (0) #define ARM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \ do \ { \ + if (TARGET_THUMB) \ + { \ + if (is_called_in_ARM_mode (DECL)) \ + fprintf (STREAM, "\t.code 32\n") ; \ + else \ + fprintf (STREAM, "\t.thumb_func\n") ; \ + } \ if (TARGET_POKE_FUNCTION_NAME) \ arm_poke_function_name (STREAM, (char *) NAME); \ } \ while (0) +/* For aliases of functions we use .thumb_set instead. */ +#define ASM_OUTPUT_DEF_FROM_DECLS(FILE, DECL1, DECL2) \ + do \ + { \ + char * LABEL1 = XSTR (XEXP (DECL_RTL (decl), 0), 0); \ + char * LABEL2 = IDENTIFIER_POINTER (DECL2); \ + \ + if (TARGET_THUMB && TREE_CODE (DECL1) == FUNCTION_DECL) \ + { \ + fprintf (FILE, "\t.thumb_set "); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, ","); \ + assemble_name (FILE, LABEL2); \ + fprintf (FILE, "\n"); \ + } \ + else \ + ASM_OUTPUT_DEF (FILE, LABEL1, LABEL2); \ + } \ + while (0) + /* Target characters. */ #define TARGET_BELL 007 #define TARGET_BS 010 @@ -2114,101 +2616,135 @@ extern struct rtx_def * arm_compare_op1; /* Only perform branch elimination (by making instructions conditional) if we're optimising. Otherwise it's of no use anyway. */ -#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \ - if (optimize) \ - arm_final_prescan_insn (INSN) +#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \ + if (TARGET_ARM && optimize) \ + arm_final_prescan_insn (INSN); \ + else if (TARGET_THUMB) \ + thumb_final_prescan_insn (INSN) #define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ - ((CODE) == '?' || (CODE) == '|' || (CODE) == '@') + (CODE == '@' || CODE == '|' \ + || (TARGET_ARM && (CODE == '?')) \ + || (TARGET_THUMB && (CODE == '_'))) + /* Output an operand of an instruction. */ #define PRINT_OPERAND(STREAM, X, CODE) \ arm_print_operand (STREAM, X, CODE) #define ARM_SIGN_EXTEND(x) ((HOST_WIDE_INT) \ (HOST_BITS_PER_WIDE_INT <= 32 ? (x) \ - : (((x) & (unsigned HOST_WIDE_INT) 0xffffffffUL) | \ - (((x) & (unsigned HOST_WIDE_INT) 0x80000000UL) \ + : (((x) & (unsigned HOST_WIDE_INT) 0xffffffff) | \ + (((x) & (unsigned HOST_WIDE_INT) 0x80000000) \ ? ((~ (HOST_WIDE_INT) 0) \ - & ~ (unsigned HOST_WIDE_INT) 0xffffffffUL) \ + & ~ (unsigned HOST_WIDE_INT) 0xffffffff) \ : 0)))) /* Output the address of an operand. */ -#define PRINT_OPERAND_ADDRESS(STREAM,X) \ -{ \ - int is_minus = GET_CODE (X) == MINUS; \ - \ - if (GET_CODE (X) == REG) \ - asm_fprintf (STREAM, "[%r, #0]", REGNO (X)); \ - else if (GET_CODE (X) == PLUS || is_minus) \ - { \ - rtx base = XEXP (X, 0); \ - rtx index = XEXP (X, 1); \ - int base_reg; \ - HOST_WIDE_INT offset = 0; \ - if (GET_CODE (base) != REG) \ - { \ - /* Ensure that BASE is a register (one of them must be). */ \ - rtx temp = base; \ - base = index; \ - index = temp; \ - } \ - base_reg = REGNO (base); \ - switch (GET_CODE (index)) \ - { \ - case CONST_INT: \ - offset = INTVAL (index); \ - if (is_minus) \ - offset = -offset; \ - asm_fprintf (STREAM, "[%r, #%d]", base_reg, offset); \ - break; \ - \ - case REG: \ - asm_fprintf (STREAM, "[%r, %s%r]", base_reg, \ - is_minus ? "-" : "", REGNO (index)); \ - break; \ - \ - case MULT: \ - case ASHIFTRT: \ - case LSHIFTRT: \ - case ASHIFT: \ - case ROTATERT: \ - { \ - asm_fprintf (STREAM, "[%r, %s%r", base_reg, \ - is_minus ? "-" : "", REGNO (XEXP (index, 0))); \ - arm_print_operand (STREAM, index, 'S'); \ - fputs ("]", STREAM); \ - break; \ - } \ - \ - default: \ - abort(); \ - } \ - } \ - else if (GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_INC \ - || GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_DEC) \ - { \ - extern int output_memory_reference_mode; \ - \ - if (GET_CODE (XEXP (X, 0)) != REG) \ - abort (); \ - \ - if (GET_CODE (X) == PRE_DEC || GET_CODE (X) == PRE_INC) \ - asm_fprintf (STREAM, "[%r, #%s%d]!", \ - REGNO (XEXP (X, 0)), \ - GET_CODE (X) == PRE_DEC ? "-" : "", \ - GET_MODE_SIZE (output_memory_reference_mode)); \ - else \ - asm_fprintf (STREAM, "[%r], #%s%d", \ - REGNO (XEXP (X, 0)), \ - GET_CODE (X) == POST_DEC ? "-" : "", \ - GET_MODE_SIZE (output_memory_reference_mode)); \ - } \ - else output_addr_const (STREAM, X); \ +#define ARM_PRINT_OPERAND_ADDRESS(STREAM, X) \ +{ \ + int is_minus = GET_CODE (X) == MINUS; \ + \ + if (GET_CODE (X) == REG) \ + asm_fprintf (STREAM, "[%r, #0]", REGNO (X)); \ + else if (GET_CODE (X) == PLUS || is_minus) \ + { \ + rtx base = XEXP (X, 0); \ + rtx index = XEXP (X, 1); \ + HOST_WIDE_INT offset = 0; \ + if (GET_CODE (base) != REG) \ + { \ + /* Ensure that BASE is a register */ \ + /* (one of them must be). */ \ + rtx temp = base; \ + base = index; \ + index = temp; \ + } \ + switch (GET_CODE (index)) \ + { \ + case CONST_INT: \ + offset = INTVAL (index); \ + if (is_minus) \ + offset = -offset; \ + asm_fprintf (STREAM, "[%r, #%d]", \ + REGNO (base), offset); \ + break; \ + \ + case REG: \ + asm_fprintf (STREAM, "[%r, %s%r]", \ + REGNO (base), is_minus ? "-" : "", \ + REGNO (index)); \ + break; \ + \ + case MULT: \ + case ASHIFTRT: \ + case LSHIFTRT: \ + case ASHIFT: \ + case ROTATERT: \ + { \ + asm_fprintf (STREAM, "[%r, %s%r", \ + REGNO (base), is_minus ? "-" : "", \ + REGNO (XEXP (index, 0))); \ + arm_print_operand (STREAM, index, 'S'); \ + fputs ("]", STREAM); \ + break; \ + } \ + \ + default: \ + abort(); \ + } \ + } \ + else if ( GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_INC\ + || GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_DEC)\ + { \ + extern int output_memory_reference_mode; \ + \ + if (GET_CODE (XEXP (X, 0)) != REG) \ + abort (); \ + \ + if (GET_CODE (X) == PRE_DEC || GET_CODE (X) == PRE_INC) \ + asm_fprintf (STREAM, "[%r, #%s%d]!", \ + REGNO (XEXP (X, 0)), \ + GET_CODE (X) == PRE_DEC ? "-" : "", \ + GET_MODE_SIZE (output_memory_reference_mode));\ + else \ + asm_fprintf (STREAM, "[%r], #%s%d", \ + REGNO (XEXP (X, 0)), \ + GET_CODE (X) == POST_DEC ? "-" : "", \ + GET_MODE_SIZE (output_memory_reference_mode));\ + } \ + else output_addr_const (STREAM, X); \ } +#define THUMB_PRINT_OPERAND_ADDRESS(STREAM, X) \ +{ \ + if (GET_CODE (X) == REG) \ + asm_fprintf (STREAM, "[%r]", REGNO (X)); \ + else if (GET_CODE (X) == POST_INC) \ + asm_fprintf (STREAM, "%r!", REGNO (XEXP (X, 0))); \ + else if (GET_CODE (X) == PLUS) \ + { \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ + asm_fprintf (STREAM, "[%r, #%d]", \ + REGNO (XEXP (X, 0)), \ + (int) INTVAL (XEXP (X, 1))); \ + else \ + asm_fprintf (STREAM, "[%r, %r]", \ + REGNO (XEXP (X, 0)), \ + REGNO (XEXP (X, 1))); \ + } \ + else \ + output_addr_const (STREAM, X); \ +} + +#define PRINT_OPERAND_ADDRESS(STREAM, X) \ + if (TARGET_ARM) \ + ARM_PRINT_OPERAND_ADDRESS (STREAM, X) \ + else \ + THUMB_PRINT_OPERAND_ADDRESS (STREAM, X) + /* Handles PIC addr specially */ -#define OUTPUT_INT_ADDR_CONST(STREAM,X) \ +#define OUTPUT_INT_ADDR_CONST(STREAM, X) \ { \ if (flag_pic && GET_CODE (X) == CONST && is_pic (X)) \ { \ @@ -2217,7 +2753,8 @@ extern struct rtx_def * arm_compare_op1; output_addr_const (STREAM, XEXP (XEXP (XEXP (X, 0), 1), 0)); \ fputs (")", STREAM); \ } \ - else output_addr_const (STREAM, X); \ + else \ + output_addr_const (STREAM, X); \ \ /* Mark symbols as position independent. We only do this in the \ .text segment, not in the .data segment. */ \ @@ -2269,10 +2806,12 @@ extern struct rtx_def * arm_compare_op1; /* A C expression whose value is RTL representing the value of the return address for the frame COUNT steps up from the current frame. */ -#define RETURN_ADDR_RTX(COUNT, FRAME) \ - ((COUNT == 0) \ - ? gen_rtx_MEM (Pmode, plus_constant (FRAME, -4)) \ - : NULL_RTX) +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + arm_return_addr (COUNT, FRAME) + +/* Mask of the bits in the PC that contain the real return address + when running in 26-bit mode. */ +#define RETURN_ADDR_MASK26 (0x03fffffc) /* Pick up the return address upon entry to a procedure. Used for dwarf2 unwind information. This also enables the table driven @@ -2288,6 +2827,40 @@ extern struct rtx_def * arm_compare_op1; in 26 bit mode, the condition codes must be masked out of the \ return address. This does not apply to ARM6 and later processors \ when running in 32 bit mode. */ \ - ((!TARGET_APCS_32) ? (GEN_INT (0x03fffffc)) : (GEN_INT (0xffffffff))) + ((!TARGET_APCS_32) ? (GEN_INT (RETURN_ADDR_MASK26)) \ + : (GEN_INT ((unsigned long)0xffffffff))) + + +/* Define the codes that are matched by predicates in arm.c */ +#define PREDICATE_CODES \ + {"s_register_operand", {SUBREG, REG}}, \ + {"f_register_operand", {SUBREG, REG}}, \ + {"arm_add_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_add_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"fpu_rhs_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_rhs_operand", {SUBREG, REG, CONST_INT}}, \ + {"arm_not_operand", {SUBREG, REG, CONST_INT}}, \ + {"reg_or_int_operand", {SUBREG, REG, CONST_INT}}, \ + {"index_operand", {SUBREG, REG, CONST_INT}}, \ + {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, \ + {"offsettable_memory_operand", {MEM}}, \ + {"bad_signed_byte_operand", {MEM}}, \ + {"alignable_memory_operand", {MEM}}, \ + {"shiftable_operator", {PLUS, MINUS, AND, IOR, XOR}}, \ + {"minmax_operator", {SMIN, SMAX, UMIN, UMAX}}, \ + {"shift_operator", {ASHIFT, ASHIFTRT, LSHIFTRT, ROTATERT, MULT}}, \ + {"di_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE, MEM}}, \ + {"nonimmediate_di_operand", {SUBREG, REG, MEM}}, \ + {"soft_df_operand", {SUBREG, REG, CONST_DOUBLE, MEM}}, \ + {"nonimmediate_soft_df_operand", {SUBREG, REG, MEM}}, \ + {"load_multiple_operation", {PARALLEL}}, \ + {"store_multiple_operation", {PARALLEL}}, \ + {"equality_operator", {EQ, NE}}, \ + {"arm_rhsm_operand", {SUBREG, REG, CONST_INT, MEM}}, \ + {"const_shift_operand", {CONST_INT}}, \ + {"multi_register_push", {PARALLEL}}, \ + {"cc_register", {REG}}, \ + {"logical_binary_operator", {AND, IOR, XOR}}, \ + {"dominant_cc_register", {REG}}, #endif /* __ARM_H__ */ diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 314beac05d9..e67f133fcef 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -40,6 +40,8 @@ ;; Attributes +(define_attr "is_thumb" "no,yes" (const (symbol_ref "TARGET_ARM"))) + ; PROG_MODE attribute is used to determine whether condition codes are ; clobbered by a call insn: they are if in prog32 mode. This is controlled ; by the -mapcs-{32,26} flag, and possibly the -mcpu=... option. @@ -59,15 +61,14 @@ ; POOL_RANGE is how far away from a constant pool entry that this insn ; can be placed. If the distance is zero, then this insn will never ; reference the pool. +; NEG_POOL_RANGE is nonzero for insns that can reference a constant pool entry +; before its address. (define_attr "pool_range" "" (const_int 0)) +(define_attr "neg_pool_range" "" (const_int 0)) ; An assembler sequence may clobber the condition codes without us knowing -; If such an insn references the pool, then we have no way of knowing how, -; so use the most conservative value for pool_range. (define_asm_attributes - [(set_attr "conds" "clob") - (set_attr "length" "4") - (set_attr "pool_range" "250")]) + [(set_attr "conds" "clob")]) ; TYPE attribute is used to detect floating point instructions which, if ; running on a co-processor can run in parallel with other, basic instructions @@ -154,6 +155,11 @@ (const_string "single") (const_string "multi"))) +;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a +;; distant label. +(define_attr "far_jump" "yes,no" (const_string "no")) + + ; The write buffer on some of the arm6 processors is hard to model exactly. ; There is room in the buffer for up to two addresses and up to eight words ; of memory, but the two needn't be split evenly. When writing the two @@ -245,6 +251,8 @@ ;; Core unit ;;-------------------------------------------------------------------- ;; Everything must spend at least one cycle in the core unit +(define_function_unit "core" 1 0 (eq_attr "core_cycles" "single") 1 1) + (define_function_unit "core" 1 0 (and (eq_attr "ldsched" "yes") (eq_attr "type" "store1")) 1 1) @@ -282,6 +290,10 @@ (define_function_unit "core" 1 0 (eq_attr "type" "store3") 4 4) (define_function_unit "core" 1 0 (eq_attr "type" "store4") 5 5) + +(define_function_unit "core" 1 0 + (and (eq_attr "core_cycles" "multi") + (eq_attr "type" "!mult,load,store1,store2,store3,store4")) 32 32) ;; Note: For DImode insns, there is normally no reason why operands should ;; not be in the same register, what we don't want is for something being @@ -294,7 +306,7 @@ (plus:DI (match_operand:DI 1 "s_register_operand" "") (match_operand:DI 2 "s_register_operand" ""))) (clobber (reg:CC 24))] - "reload_completed" + "TARGET_ARM && reload_completed" [(parallel [(set (reg:CC_C 24) (compare:CC_C (plus:SI (match_dup 1) (match_dup 2)) (match_dup 1))) @@ -321,7 +333,7 @@ (match_operand:SI 2 "s_register_operand" "")) (match_operand:DI 1 "s_register_operand" ""))) (clobber (reg:CC 24))] - "reload_completed" + "TARGET_ARM && reload_completed" [(parallel [(set (reg:CC_C 24) (compare:CC_C (plus:SI (match_dup 1) (match_dup 2)) (match_dup 1))) @@ -349,7 +361,7 @@ (match_operand:SI 2 "s_register_operand" "")) (match_operand:DI 1 "s_register_operand" ""))) (clobber (reg:CC 24))] - "reload_completed" + "TARGET_ARM && reload_completed" [(parallel [(set (reg:CC_C 24) (compare:CC_C (plus:SI (match_dup 1) (match_dup 2)) (match_dup 1))) @@ -367,23 +379,56 @@ ;; Addition insns. -(define_insn "adddi3" - [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") - (plus:DI (match_operand:DI 1 "s_register_operand" "%0,0") - (match_operand:DI 2 "s_register_operand" "r,0"))) - (clobber (reg:CC 24))] - "" +(define_expand "adddi3" + [(parallel + [(set (match_operand:DI 0 "s_register_operand" "") + (plus:DI (match_operand:DI 1 "s_register_operand" "") + (match_operand:DI 2 "s_register_operand" ""))) + (clobber (reg:CC 24)) + ])] + "TARGET_EITHER" + " + if (TARGET_THUMB) + { + if (GET_CODE (operands[1]) != REG) + operands[1] = force_reg (SImode, operands[1]); + if (GET_CODE (operands[2]) != REG) + operands[2] = force_reg (SImode, operands[2]); + } + " +) + +(define_insn "*thumb_adddi3" + [(set (match_operand:DI 0 "register_operand" "=l") + (plus:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "register_operand" "l"))) + (clobber (reg:CC 24)) + ] + "TARGET_THUMB" + "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" + [(set_attr "length" "4")] +) + +(define_insn "*arm_adddi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (plus:DI (match_operand:DI 1 "s_register_operand" "%0,0") + (match_operand:DI 2 "s_register_operand" "r,0"))) + (clobber (reg:CC 24)) + ] + "TARGET_ARM" "#" -[(set_attr "conds" "clob") - (set_attr "length" "8")]) + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) (define_insn "*adddi_sesidi_di" [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (plus:DI (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "r,0"))) - (clobber (reg:CC 24))] - "" + (clobber (reg:CC 24)) + ] + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "8")]) @@ -393,19 +438,21 @@ (plus:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "r,0"))) - (clobber (reg:CC 24))] - "" + (clobber (reg:CC 24)) + ] + "TARGET_ARM" "#" -[(set_attr "conds" "clob") - (set_attr "length" "8")]) + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) (define_expand "addsi3" - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (plus:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "reg_or_int_operand" "")))] - "" + "TARGET_EITHER" " - if (GET_CODE (operands[2]) == CONST_INT) + if (TARGET_ARM && GET_CODE (operands[2]) == CONST_INT) { arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], operands[1], @@ -413,14 +460,16 @@ : preserve_subexpressions_p ())); DONE; } -") + " +) (define_split - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (plus:SI (match_operand:SI 1 "s_register_operand" "") - (match_operand:SI 2 "const_int_operand" "")))] - "! (const_ok_for_arm (INTVAL (operands[2])) - || const_ok_for_arm (-INTVAL (operands[2])))" + (match_operand:SI 2 "const_int_operand" "")))] + "TARGET_ARM && + (! (const_ok_for_arm (INTVAL (operands[2])) + || const_ok_for_arm (-INTVAL (operands[2]))))" [(clobber (const_int 0))] " arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], @@ -428,38 +477,112 @@ DONE; ") -(define_insn "*addsi3_insn" - [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") +(define_insn "*arm_addsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") (plus:SI (match_operand:SI 1 "s_register_operand" "r,r,r") (match_operand:SI 2 "reg_or_int_operand" "rI,L,?n")))] - "" + "TARGET_ARM" "@ add%?\\t%0, %1, %2 sub%?\\t%0, %1, #%n2 #" -[(set_attr "length" "4,4,16")]) + [(set_attr "length" "4,4,16")] +) + +;; Register group 'k' is a single register group containing only the stack +;; register. Trying to reload it will always fail catastrophically, +;; so never allow those alternatives to match if reloading is needed. + +(define_insn "*thumb_addsi3" + [(set (match_operand:SI 0 "register_operand" "=l,l,l,*r,*h,l,!k") + (plus:SI (match_operand:SI 1 "register_operand" "%0,0,l,*0,*0,!k,!k") + (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] + "TARGET_THUMB" + "* + static char * asms[] = + { + \"add\\t%0, %0, %2\", + \"sub\\t%0, %0, #%n2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %1, %2\" + }; + if ((which_alternative == 2 || which_alternative == 6) + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) + return \"sub\\t%0, %1, #%n2\"; + return asms[which_alternative]; + " + [(set_attr "length" "2")] +) + +;; Reloading and elimination of the frame pointer can +;; sometimes cause this optimization to be missed. +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=l") + (match_operand:SI 1 "const_int_operand" "M")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] + "TARGET_THUMB + && REGNO (operands[2]) == STACK_POINTER_REGNUM + && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 + && (INTVAL (operands[1]) & 3) == 0" + "add\\t%0, %2, %1" + [(set_attr "length" "2")] +) (define_insn "*addsi3_compare0" [(set (reg:CC_NOOV 24) (compare:CC_NOOV (plus:SI (match_operand:SI 1 "s_register_operand" "r,r") - (match_operand:SI 2 "arm_add_operand" "rI,L")) + (match_operand:SI 2 "arm_add_operand" "rI,L")) (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (plus:SI (match_dup 1) (match_dup 2)))] - "" + "TARGET_ARM" "@ add%?s\\t%0, %1, %2 sub%?s\\t%0, %1, #%n2" -[(set_attr "conds" "set")]) + [(set_attr "conds" "set")] +) (define_insn "*addsi3_compare0_scratch" [(set (reg:CC_NOOV 24) (compare:CC_NOOV (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") - (match_operand:SI 1 "arm_add_operand" "rI,L")) + (match_operand:SI 1 "arm_add_operand" "rI,L")) (const_int 0)))] - "" + "TARGET_ARM" + "@ + cmn%?\\t%0, %1 + cmp%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +;; These patterns are the same ones as the two regular addsi3_compare0 +;; patterns, except we write them slightly different - the combiner +;; tends to generate them this way. +(define_insn "*addsi3_compare0_for_combiner" + [(set (reg:CC 24) + (compare:CC + (match_operand:SI 1 "s_register_operand" "r,r") + (neg:SI (match_operand:SI 2 "arm_add_operand" "rI,L")))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_ARM" + "@ + add%?s\\t%0, %1, %2 + sub%?s\\t%0, %1, #%n2" + [(set_attr "conds" "set")] +) + +(define_insn "*addsi3_compare0_scratch_for_combiner" + [(set (reg:CC 24) + (compare:CC + (match_operand:SI 0 "s_register_operand" "r,r") + (neg:SI (match_operand:SI 1 "arm_add_operand" "rI,L"))))] + "TARGET_ARM" "@ cmn%?\\t%0, %1 cmp%?\\t%0, #%n1" @@ -477,7 +600,7 @@ (match_dup 1))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (plus:SI (match_dup 1) (match_dup 2)))] - "" + "TARGET_ARM" "@ add%?s\\t%0, %1, %2 sub%?s\\t%0, %1, #%n2" @@ -491,7 +614,7 @@ (match_dup 2))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (plus:SI (match_dup 1) (match_dup 2)))] - "" + "TARGET_ARM" "@ add%?s\\t%0, %1, %2 sub%?s\\t%0, %1, #%n2" @@ -503,7 +626,7 @@ (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") (match_operand:SI 1 "arm_add_operand" "rI,L")) (match_dup 0)))] - "" + "TARGET_ARM" "@ cmn%?\\t%0, %1 cmp%?\\t%0, #%n1" @@ -515,7 +638,7 @@ (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") (match_operand:SI 1 "arm_add_operand" "rI,L")) (match_dup 1)))] - "" + "TARGET_ARM" "@ cmn%?\\t%0, %1 cmp%?\\t%0, #%n1" @@ -526,9 +649,10 @@ (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0)) (plus:SI (match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "arm_rhs_operand" "rI"))))] - "" + "TARGET_ARM" "adc%?\\t%0, %1, %2" -[(set_attr "conds" "use")]) + [(set_attr "conds" "use")] +) (define_insn "*addsi3_carryin_shift" [(set (match_operand:SI 0 "s_register_operand" "") @@ -538,7 +662,7 @@ [(match_operand:SI 3 "s_register_operand" "") (match_operand:SI 4 "reg_or_int_operand" "")]) (match_operand:SI 1 "s_register_operand" ""))))] - "" + "TARGET_ARM" "adc%?\\t%0, %1, %3%S2" [(set_attr "conds" "use")] ) @@ -548,16 +672,17 @@ (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "arm_rhs_operand" "rI")) (ltu:SI (reg:CC_C 24) (const_int 0))))] - "" + "TARGET_ARM" "adc%?\\t%0, %1, %2" -[(set_attr "conds" "use")]) + [(set_attr "conds" "use")] +) (define_insn "*addsi3_carryin_alt2" [(set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0)) (match_operand:SI 1 "s_register_operand" "r")) (match_operand:SI 2 "arm_rhs_operand" "rI")))] - "" + "TARGET_ARM" "adc%?\\t%0, %1, %2" [(set_attr "conds" "use")]) @@ -566,16 +691,17 @@ (plus:SI (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0)) (match_operand:SI 2 "arm_rhs_operand" "rI")) (match_operand:SI 1 "s_register_operand" "r")))] - "" + "TARGET_ARM" "adc%?\\t%0, %1, %2" -[(set_attr "conds" "use")]) + [(set_attr "conds" "use")] +) (define_insn "incscc" [(set (match_operand:SI 0 "s_register_operand" "=r,r") (plus:SI (match_operator:SI 2 "comparison_operator" - [(match_operand 3 "cc_register" "") (const_int 0)]) + [(match_operand:CC 3 "cc_register" "") (const_int 0)]) (match_operand:SI 1 "s_register_operand" "0,?r")))] - "" + "TARGET_ARM" "@ add%d2\\t%0, %1, #1 mov%D2\\t%0, %1\;add%d2\\t%0, %1, #1" @@ -587,11 +713,12 @@ ; able to merge it with an add, but it depends on the exact value. (define_split - [(set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_operand:SI 1 "s_register_operand" "r") - (match_operand:SI 2 "const_int_operand" "n")))] - "!(const_ok_for_arm (INTVAL (operands[2])) - || const_ok_for_arm (-INTVAL (operands[2])))" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "const_int_operand" "n")))] + "TARGET_ARM + && (! (const_ok_for_arm (INTVAL (operands[2])) + || const_ok_for_arm (-INTVAL (operands[2]))))" [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))] " @@ -600,8 +727,8 @@ int i; unsigned int temp; - /* this code is similar to the approach followed in movsi, but it must - generate exactly two insns */ + /* This code is similar to the approach followed in movsi, + but it must generate exactly two insns. */ for (i = 30; i >= 0; i -= 2) { @@ -614,7 +741,7 @@ val &= 255 << i; break; } - /* we might be able to do this as (larger number - small number) */ + /* We might be able to do this as (larger number - small number). */ temp = ((val >> i) & 255) + 1; if (temp > 255 && i < 24) { @@ -631,176 +758,242 @@ FAIL; } } - /* if we got here, we have found a way of doing it in two instructions. - the two constants are in val and temp */ - operands[2] = GEN_INT ((int)val); - operands[3] = GEN_INT ((int)temp); + /* If we got here, we have found a way of doing it in two instructions. + the two constants are in val and temp. */ + operands[2] = GEN_INT ((int) val); + operands[3] = GEN_INT ((int) temp); } ") (define_insn "addsf3" - [(set (match_operand:SF 0 "s_register_operand" "=f,f") - (plus:SF (match_operand:SF 1 "s_register_operand" "f,f") - (match_operand:SF 2 "fpu_add_operand" "fG,H")))] - "TARGET_HARD_FLOAT" + [(set (match_operand:SF 0 "s_register_operand" "=f,f") + (plus:SF (match_operand:SF 1 "s_register_operand" "f,f") + (match_operand:SF 2 "fpu_add_operand" "fG,H")))] + "TARGET_ARM && TARGET_HARD_FLOAT" "@ adf%?s\\t%0, %1, %2 suf%?s\\t%0, %1, #%N2" -[(set_attr "type" "farith")]) + [(set_attr "type" "farith")] +) (define_insn "adddf3" - [(set (match_operand:DF 0 "s_register_operand" "=f,f") - (plus:DF (match_operand:DF 1 "s_register_operand" "f,f") - (match_operand:DF 2 "fpu_add_operand" "fG,H")))] - "TARGET_HARD_FLOAT" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (plus:DF (match_operand:DF 1 "s_register_operand" "f,f") + (match_operand:DF 2 "fpu_add_operand" "fG,H")))] + "TARGET_ARM && TARGET_HARD_FLOAT" "@ adf%?d\\t%0, %1, %2 suf%?d\\t%0, %1, #%N2" -[(set_attr "type" "farith")]) + [(set_attr "type" "farith")] +) (define_insn "*adddf_esfdf_df" - [(set (match_operand:DF 0 "s_register_operand" "=f,f") + [(set (match_operand:DF 0 "s_register_operand" "=f,f") (plus:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f,f")) - (match_operand:DF 2 "fpu_add_operand" "fG,H")))] - "TARGET_HARD_FLOAT" + (match_operand:SF 1 "s_register_operand" "f,f")) + (match_operand:DF 2 "fpu_add_operand" "fG,H")))] + "TARGET_ARM && TARGET_HARD_FLOAT" "@ adf%?d\\t%0, %1, %2 suf%?d\\t%0, %1, #%N2" -[(set_attr "type" "farith")]) + [(set_attr "type" "farith")] +) (define_insn "*adddf_df_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (plus:DF (match_operand:DF 1 "s_register_operand" "f") + [(set (match_operand:DF 0 "s_register_operand" "=f") + (plus:DF (match_operand:DF 1 "s_register_operand" "f") (float_extend:DF - (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_ARM && TARGET_HARD_FLOAT" "adf%?d\\t%0, %1, %2" -[(set_attr "type" "farith")]) + [(set_attr "type" "farith")] +) (define_insn "*adddf_esfdf_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") + [(set (match_operand:DF 0 "s_register_operand" "=f") (plus:DF (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")) (float_extend:DF (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "adf%?d\\t%0, %1, %2" -[(set_attr "type" "farith")]) + [(set_attr "type" "farith")] +) (define_insn "addxf3" - [(set (match_operand:XF 0 "s_register_operand" "=f,f") - (plus:XF (match_operand:XF 1 "s_register_operand" "f,f") - (match_operand:XF 2 "fpu_add_operand" "fG,H")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + [(set (match_operand:XF 0 "s_register_operand" "=f,f") + (plus:XF (match_operand:XF 1 "s_register_operand" "f,f") + (match_operand:XF 2 "fpu_add_operand" "fG,H")))] + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "@ adf%?e\\t%0, %1, %2 suf%?e\\t%0, %1, #%N2" -[(set_attr "type" "farith")]) + [(set_attr "type" "farith")] +) -(define_insn "subdi3" - [(set (match_operand:DI 0 "s_register_operand" "=&r,&r,&r") +(define_expand "subdi3" + [(parallel + [(set (match_operand:DI 0 "s_register_operand" "") + (minus:DI (match_operand:DI 1 "s_register_operand" "") + (match_operand:DI 2 "s_register_operand" ""))) + (clobber (reg:CC 24)) + ]) + ] + "TARGET_EITHER" + " + if (TARGET_THUMB) + { + if (GET_CODE (operands[1]) != REG) + operands[1] = force_reg (SImode, operands[1]); + if (GET_CODE (operands[2]) != REG) + operands[2] = force_reg (SImode, operands[2]); + } + " +) + +(define_insn "*arm_subdi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r,&r") (minus:DI (match_operand:DI 1 "s_register_operand" "0,r,0") (match_operand:DI 2 "s_register_operand" "r,0,0"))) - (clobber (reg:CC 24))] - "" + (clobber (reg:CC 24)) + ] + "TARGET_ARM" "subs\\t%Q0, %Q1, %Q2\;sbc\\t%R0, %R1, %R2" -[(set_attr "conds" "clob") - (set_attr "length" "8")]) + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) + +(define_insn "*thumb_subdi3" + [(set (match_operand:DI 0 "register_operand" "=l") + (minus:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "register_operand" "l"))) + (clobber (reg:CC 24)) + ] + "TARGET_THUMB" + "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" + [(set_attr "length" "4")] +) (define_insn "*subdi_di_zesidi" - [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") - (minus:DI (match_operand:DI 1 "s_register_operand" "?r,0") + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (match_operand:DI 1 "s_register_operand" "?r,0") (zero_extend:DI - (match_operand:SI 2 "s_register_operand" "r,r")))) - (clobber (reg:CC 24))] - "" + (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24)) + ] + "TARGET_ARM" "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, #0" -[(set_attr "conds" "clob") - (set_attr "length" "8")]) + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) (define_insn "*subdi_di_sesidi" - [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") - (minus:DI (match_operand:DI 1 "s_register_operand" "r,0") + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (match_operand:DI 1 "s_register_operand" "r,0") (sign_extend:DI - (match_operand:SI 2 "s_register_operand" "r,r")))) - (clobber (reg:CC 24))] - "" + (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24)) + ] + "TARGET_ARM" "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, %2, asr #31" -[(set_attr "conds" "clob") - (set_attr "length" "8")]) + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) (define_insn "*subdi_zesidi_di" - [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (minus:DI (zero_extend:DI - (match_operand:SI 2 "s_register_operand" "r,r")) - (match_operand:DI 1 "s_register_operand" "?r,0"))) - (clobber (reg:CC 24))] - "" + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0"))) + (clobber (reg:CC 24)) + ] + "TARGET_ARM" "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, #0" -[(set_attr "conds" "clob") - (set_attr "length" "8")]) + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) (define_insn "*subdi_sesidi_di" - [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (minus:DI (sign_extend:DI - (match_operand:SI 2 "s_register_operand" "r,r")) - (match_operand:DI 1 "s_register_operand" "?r,0"))) - (clobber (reg:CC 24))] - "" + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0"))) + (clobber (reg:CC 24)) + ] + "TARGET_ARM" "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, %2, asr #31" -[(set_attr "conds" "clob") - (set_attr "length" "8")]) + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) (define_insn "*subdi_zesidi_zesidi" - [(set (match_operand:DI 0 "s_register_operand" "=r") + [(set (match_operand:DI 0 "s_register_operand" "=r") (minus:DI (zero_extend:DI - (match_operand:SI 1 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r")) (zero_extend:DI - (match_operand:SI 2 "s_register_operand" "r")))) - (clobber (reg:CC 24))] - "" + (match_operand:SI 2 "s_register_operand" "r")))) + (clobber (reg:CC 24)) + ] + "TARGET_ARM" "subs\\t%Q0, %1, %2\;rsc\\t%R0, %1, %1" -[(set_attr "conds" "clob") - (set_attr "length" "8")]) + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) (define_expand "subsi3" - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (minus:SI (match_operand:SI 1 "reg_or_int_operand" "") (match_operand:SI 2 "s_register_operand" "")))] - "" + "TARGET_EITHER" " if (GET_CODE (operands[1]) == CONST_INT) { - arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0], - operands[2], - (reload_in_progress || reload_completed ? 0 - : preserve_subexpressions_p ())); - DONE; + if (TARGET_ARM) + { + arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0], + operands[2], + (reload_in_progress || reload_completed ? 0 + : preserve_subexpressions_p ())); + DONE; + } + else /* TARGET_THUMB */ + operands[1] = force_reg (SImode, operands[1]); } -") + " +) -(define_insn "*subsi3_insn" - [(set (match_operand:SI 0 "s_register_operand" "=r,r") +(define_insn "*thumb_subsi3_insn" + [(set (match_operand:SI 0 "register_operand" "=l") + (minus:SI (match_operand:SI 1 "register_operand" "l") + (match_operand:SI 2 "register_operand" "l")))] + "TARGET_THUMB" + "sub\\t%0, %1, %2" + [(set_attr "length" "2")] +) + +(define_insn "*arm_subsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") (minus:SI (match_operand:SI 1 "reg_or_int_operand" "rI,?n") (match_operand:SI 2 "s_register_operand" "r,r")))] - "" + "TARGET_ARM" "@ rsb%?\\t%0, %2, %1 #" -[(set_attr "length" "4,16")]) + [(set_attr "length" "4,16")] +) (define_split - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (minus:SI (match_operand:SI 1 "const_int_operand" "") (match_operand:SI 2 "s_register_operand" "")))] - "! const_ok_for_arm (INTVAL (operands[1]))" + "TARGET_ARM && (! const_ok_for_arm (INTVAL (operands[1])))" [(clobber (const_int 0))] " arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0], operands[2], 0); DONE; -") + " +) (define_insn "*subsi3_compare0" [(set (reg:CC_NOOV 24) @@ -809,63 +1002,69 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (minus:SI (match_dup 1) (match_dup 2)))] - "" + "TARGET_ARM" "@ sub%?s\\t%0, %1, %2 rsb%?s\\t%0, %2, %1" -[(set_attr "conds" "set")]) + [(set_attr "conds" "set")] +) (define_insn "decscc" - [(set (match_operand:SI 0 "s_register_operand" "=r,r") - (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r") + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r") (match_operator:SI 2 "comparison_operator" - [(match_operand 3 "cc_register" "") (const_int 0)])))] - "" + [(match_operand 3 "cc_register" "") (const_int 0)])))] + "TARGET_ARM" "@ sub%d2\\t%0, %1, #1 mov%D2\\t%0, %1\;sub%d2\\t%0, %1, #1" -[(set_attr "conds" "use") - (set_attr "length" "*,8")]) + [(set_attr "conds" "use") + (set_attr "length" "*,8")] +) (define_insn "subsf3" [(set (match_operand:SF 0 "s_register_operand" "=f,f") (minus:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G") (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "@ suf%?s\\t%0, %1, %2 rsf%?s\\t%0, %2, %1" -[(set_attr "type" "farith")]) + [(set_attr "type" "farith")] +) (define_insn "subdf3" - [(set (match_operand:DF 0 "s_register_operand" "=f,f") - (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") - (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))] - "TARGET_HARD_FLOAT" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") + (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_ARM && TARGET_HARD_FLOAT" "@ suf%?d\\t%0, %1, %2 rsf%?d\\t%0, %2, %1" -[(set_attr "type" "farith")]) + [(set_attr "type" "farith")] +) (define_insn "*subdf_esfdf_df" - [(set (match_operand:DF 0 "s_register_operand" "=f") + [(set (match_operand:DF 0 "s_register_operand" "=f") (minus:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f")) - (match_operand:DF 2 "fpu_rhs_operand" "fG")))] - "TARGET_HARD_FLOAT" + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_ARM && TARGET_HARD_FLOAT" "suf%?d\\t%0, %1, %2" -[(set_attr "type" "farith")]) + [(set_attr "type" "farith")] +) (define_insn "*subdf_df_esfdf" [(set (match_operand:DF 0 "s_register_operand" "=f,f") (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") (float_extend:DF (match_operand:SF 2 "s_register_operand" "f,f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "@ suf%?d\\t%0, %1, %2 rsf%?d\\t%0, %2, %1" -[(set_attr "type" "farith")]) + [(set_attr "type" "farith")] +) (define_insn "*subdf_esfdf_esfdf" [(set (match_operand:DF 0 "s_register_operand" "=f") @@ -873,30 +1072,61 @@ (match_operand:SF 1 "s_register_operand" "f")) (float_extend:DF (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "suf%?d\\t%0, %1, %2" -[(set_attr "type" "farith")]) + [(set_attr "type" "farith")] +) (define_insn "subxf3" - [(set (match_operand:XF 0 "s_register_operand" "=f,f") - (minus:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G") - (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + [(set (match_operand:XF 0 "s_register_operand" "=f,f") + (minus:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G") + (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "@ suf%?e\\t%0, %1, %2 rsf%?e\\t%0, %2, %1" -[(set_attr "type" "farith")]) + [(set_attr "type" "farith")] +) ;; Multiplication insns +(define_expand "mulsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (mult:SI (match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 1 "s_register_operand" "")))] + "TARGET_EITHER" + "" +) + ;; Use `&' and then `0' to prevent the operands 0 and 1 being the same -(define_insn "mulsi3" - [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") +(define_insn "*arm_mulsi3" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") (mult:SI (match_operand:SI 2 "s_register_operand" "r,r") (match_operand:SI 1 "s_register_operand" "%?r,0")))] - "" + "TARGET_ARM" "mul%?\\t%0, %2, %1" -[(set_attr "type" "mult")]) + [(set_attr "type" "mult")] +) + +;; Unfortunately with the Thumb the '&'/'0' trick can fails when operands 1 and 2 +;; are the same, because reload will make operand 0 match operand 1 without +;; realizing that this conflicts with operand 2. We fix this by adding another +;; alternative to match this case, and then `reload' it ourselves. This +;; alternative must come first. +(define_insn "*thumb_mulsi3" + [(set (match_operand:SI 0 "register_operand" "=&l,&l,&l") + (mult:SI (match_operand:SI 1 "register_operand" "%l,*h,0") + (match_operand:SI 2 "register_operand" "l,l,l")))] + "TARGET_THUMB" + "* + if (which_alternative < 2) + return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; + else + return \"mul\\t%0, %0, %2\"; + " + [(set_attr "length" "4,4,2") + (set_attr "type" "mult")] +) (define_insn "*mulsi3_compare0" [(set (reg:CC_NOOV 24) @@ -906,10 +1136,11 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=&r,&r") (mult:SI (match_dup 2) (match_dup 1)))] - "" + "TARGET_ARM" "mul%?s\\t%0, %2, %1" -[(set_attr "conds" "set") - (set_attr "type" "mult")]) + [(set_attr "conds" "set") + (set_attr "type" "mult")] +) (define_insn "*mulsi_compare0_scratch" [(set (reg:CC_NOOV 24) @@ -918,10 +1149,11 @@ (match_operand:SI 1 "s_register_operand" "%?r,0")) (const_int 0))) (clobber (match_scratch:SI 0 "=&r,&r"))] - "" + "TARGET_ARM" "mul%?s\\t%0, %2, %1" -[(set_attr "conds" "set") - (set_attr "type" "mult")]) + [(set_attr "conds" "set") + (set_attr "type" "mult")] +) ;; Unnamed templates to match MLA instruction. @@ -931,7 +1163,7 @@ (mult:SI (match_operand:SI 2 "s_register_operand" "r,r,r,r") (match_operand:SI 1 "s_register_operand" "%r,0,r,0")) (match_operand:SI 3 "s_register_operand" "?r,r,0,0")))] - "" + "TARGET_ARM" "mla%?\\t%0, %2, %1, %3" [(set_attr "type" "mult")]) @@ -946,7 +1178,7 @@ (set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r") (plus:SI (mult:SI (match_dup 2) (match_dup 1)) (match_dup 3)))] - "" + "TARGET_ARM" "mla%?s\\t%0, %2, %1, %3" [(set_attr "conds" "set") (set_attr "type" "mult")]) @@ -960,10 +1192,11 @@ (match_operand:SI 3 "s_register_operand" "?r,r,0,0")) (const_int 0))) (clobber (match_scratch:SI 0 "=&r,&r,&r,&r"))] - "" + "TARGET_ARM" "mla%?s\\t%0, %2, %1, %3" -[(set_attr "conds" "set") - (set_attr "type" "mult")]) + [(set_attr "conds" "set") + (set_attr "type" "mult")] +) ;; Unnamed template to match long long multiply-accumlate (smlal) @@ -975,7 +1208,7 @@ (sign_extend:DI (match_operand:SI 1 "s_register_operand" "%r,r,r"))) (match_dup 0)))] - "arm_fast_multiply" + "TARGET_ARM && arm_fast_multiply" "smlal%?\\t%Q0, %R0, %1, %2" [(set_attr "type" "mult")]) @@ -985,7 +1218,7 @@ (match_operand:SI 1 "s_register_operand" "%r")) (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))] - "arm_fast_multiply" + "TARGET_ARM && arm_fast_multiply" "smull%?\\t%Q0, %R0, %1, %2" [(set_attr "type" "mult")]) @@ -995,7 +1228,7 @@ (match_operand:SI 1 "s_register_operand" "%r")) (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))] - "arm_fast_multiply" + "TARGET_ARM && arm_fast_multiply" "umull%?\\t%Q0, %R0, %1, %2" [(set_attr "type" "mult")]) @@ -1009,7 +1242,7 @@ (zero_extend:DI (match_operand:SI 1 "s_register_operand" "%r,r,r"))) (match_dup 0)))] - "arm_fast_multiply" + "TARGET_ARM && arm_fast_multiply" "umlal%?\\t%Q0, %R0, %1, %2" [(set_attr "type" "mult")]) @@ -1023,9 +1256,10 @@ (match_operand:SI 2 "s_register_operand" "r,r"))) (const_int 32)))) (clobber (match_scratch:SI 3 "=&r,&r"))] - "arm_fast_multiply" + "TARGET_ARM && arm_fast_multiply" "smull%?\\t%3, %0, %2, %1" -[(set_attr "type" "mult")]) + [(set_attr "type" "mult")] +) (define_insn "umulsi3_highpart" [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") @@ -1037,15 +1271,16 @@ (match_operand:SI 2 "s_register_operand" "r,r"))) (const_int 32)))) (clobber (match_scratch:SI 3 "=&r,&r"))] - "arm_fast_multiply" + "TARGET_ARM && arm_fast_multiply" "umull%?\\t%3, %0, %2, %1" -[(set_attr "type" "mult")]) + [(set_attr "type" "mult")] +) (define_insn "mulsf3" [(set (match_operand:SF 0 "s_register_operand" "=f") (mult:SF (match_operand:SF 1 "s_register_operand" "f") (match_operand:SF 2 "fpu_rhs_operand" "fG")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "fml%?s\\t%0, %1, %2" [(set_attr "type" "ffmul")]) @@ -1053,7 +1288,7 @@ [(set (match_operand:DF 0 "s_register_operand" "=f") (mult:DF (match_operand:DF 1 "s_register_operand" "f") (match_operand:DF 2 "fpu_rhs_operand" "fG")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "muf%?d\\t%0, %1, %2" [(set_attr "type" "fmul")]) @@ -1062,7 +1297,7 @@ (mult:DF (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")) (match_operand:DF 2 "fpu_rhs_operand" "fG")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "muf%?d\\t%0, %1, %2" [(set_attr "type" "fmul")]) @@ -1071,7 +1306,7 @@ (mult:DF (match_operand:DF 1 "s_register_operand" "f") (float_extend:DF (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "muf%?d\\t%0, %1, %2" [(set_attr "type" "fmul")]) @@ -1081,7 +1316,7 @@ (match_operand:SF 1 "s_register_operand" "f")) (float_extend:DF (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "muf%?d\\t%0, %1, %2" [(set_attr "type" "fmul")]) @@ -1089,7 +1324,7 @@ [(set (match_operand:XF 0 "s_register_operand" "=f") (mult:XF (match_operand:XF 1 "s_register_operand" "f") (match_operand:XF 2 "fpu_rhs_operand" "fG")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "muf%?e\\t%0, %1, %2" [(set_attr "type" "fmul")]) @@ -1099,7 +1334,7 @@ [(set (match_operand:SF 0 "s_register_operand" "=f,f") (div:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G") (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "@ fdv%?s\\t%0, %1, %2 frd%?s\\t%0, %2, %1" @@ -1109,7 +1344,7 @@ [(set (match_operand:DF 0 "s_register_operand" "=f,f") (div:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "@ dvf%?d\\t%0, %1, %2 rdf%?d\\t%0, %2, %1" @@ -1120,7 +1355,7 @@ (div:DF (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")) (match_operand:DF 2 "fpu_rhs_operand" "fG")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "dvf%?d\\t%0, %1, %2" [(set_attr "type" "fdivd")]) @@ -1129,7 +1364,7 @@ (div:DF (match_operand:DF 1 "fpu_rhs_operand" "fG") (float_extend:DF (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "rdf%?d\\t%0, %2, %1" [(set_attr "type" "fdivd")]) @@ -1139,7 +1374,7 @@ (match_operand:SF 1 "s_register_operand" "f")) (float_extend:DF (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "dvf%?d\\t%0, %1, %2" [(set_attr "type" "fdivd")]) @@ -1147,7 +1382,7 @@ [(set (match_operand:XF 0 "s_register_operand" "=f,f") (div:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G") (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "@ dvf%?e\\t%0, %1, %2 rdf%?e\\t%0, %2, %1" @@ -1159,7 +1394,7 @@ [(set (match_operand:SF 0 "s_register_operand" "=f") (mod:SF (match_operand:SF 1 "s_register_operand" "f") (match_operand:SF 2 "fpu_rhs_operand" "fG")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "rmf%?s\\t%0, %1, %2" [(set_attr "type" "fdivs")]) @@ -1167,7 +1402,7 @@ [(set (match_operand:DF 0 "s_register_operand" "=f") (mod:DF (match_operand:DF 1 "s_register_operand" "f") (match_operand:DF 2 "fpu_rhs_operand" "fG")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "rmf%?d\\t%0, %1, %2" [(set_attr "type" "fdivd")]) @@ -1176,7 +1411,7 @@ (mod:DF (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")) (match_operand:DF 2 "fpu_rhs_operand" "fG")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "rmf%?d\\t%0, %1, %2" [(set_attr "type" "fdivd")]) @@ -1185,7 +1420,7 @@ (mod:DF (match_operand:DF 1 "s_register_operand" "f") (float_extend:DF (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "rmf%?d\\t%0, %1, %2" [(set_attr "type" "fdivd")]) @@ -1195,7 +1430,7 @@ (match_operand:SF 1 "s_register_operand" "f")) (float_extend:DF (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "rmf%?d\\t%0, %1, %2" [(set_attr "type" "fdivd")]) @@ -1218,7 +1453,7 @@ (match_operator:DI 6 "logical_binary_operator" [(match_operand:DI 1 "s_register_operand" "") (match_operand:DI 2 "s_register_operand" "")]))] - "reload_completed" + "TARGET_ARM && reload_completed" [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)])) (set (match_dup 3) (match_op_dup:SI 6 [(match_dup 4) (match_dup 5)]))] " @@ -1234,7 +1469,7 @@ (define_split [(set (match_operand:DI 0 "s_register_operand" "") (not:DI (match_operand:DI 1 "s_register_operand" "")))] - "reload_completed" + "TARGET_ARM && reload_completed" [(set (match_dup 0) (not:SI (match_dup 1))) (set (match_dup 2) (not:SI (match_dup 3)))] " @@ -1250,7 +1485,7 @@ (and:DI (not:DI (match_operand:DI 1 "s_register_operand" "")) (match_operand:DI 2 "s_register_operand" "")))] - "reload_completed" + "TARGET_ARM && reload_completed" [(set (match_dup 0) (and:SI (not:SI (match_dup 1)) (match_dup 2))) (set (match_dup 3) (and:SI (not:SI (match_dup 4)) (match_dup 5)))] " @@ -1268,7 +1503,7 @@ (match_operator:DI 6 "logical_binary_operator" [(sign_extend:DI (match_operand:SI 2 "s_register_operand" "")) (match_operand:DI 1 "s_register_operand" "")]))] - "reload_completed" + "TARGET_ARM && reload_completed" [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)])) (set (match_dup 3) (match_op_dup:SI 6 [(ashiftrt:SI (match_dup 2) (const_int 31)) @@ -1288,7 +1523,7 @@ (and:DI (not:DI (sign_extend:DI (match_operand:SI 2 "s_register_operand" ""))) (match_operand:DI 1 "s_register_operand" "")))] - "reload_completed" + "TARGET_ARM && reload_completed" [(set (match_dup 0) (and:SI (not:SI (match_dup 1)) (match_dup 2))) (set (match_dup 3) (and:SI (not:SI (ashiftrt:SI (match_dup 2) (const_int 31))) @@ -1309,7 +1544,7 @@ (and:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "")) (match_operand:DI 1 "s_register_operand" "")))] - "reload_completed" + "TARGET_ARM && reload_completed" [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2))) (set (match_dup 3) (const_int 0))] " @@ -1326,7 +1561,7 @@ (ior:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "")) (match_operand:DI 1 "s_register_operand" "")))] - "operands[0] != operands[1] && reload_completed" + "TARGET_ARM && operands[0] != operands[1] && reload_completed" [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 2))) (set (match_dup 3) (match_dup 4))] " @@ -1344,7 +1579,7 @@ (xor:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "")) (match_operand:DI 1 "s_register_operand" "")))] - "operands[0] != operands[1] && reload_completed" + "TARGET_ARM && operands[0] != operands[1] && reload_completed" [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 2))) (set (match_dup 3) (match_dup 4))] " @@ -1362,7 +1597,7 @@ (and:DI (not:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" ""))) (match_operand:DI 1 "s_register_operand" "")))] - "operands[0] != operands[1] && reload_completed" + "TARGET_ARM && operands[0] != operands[1] && reload_completed" [(set (match_dup 0) (and:SI (not:SI (match_dup 1)) (match_dup 2))) (set (match_dup 3) (match_dup 4))] " @@ -1375,10 +1610,10 @@ }") (define_insn "anddi3" - [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") - (and:DI (match_operand:DI 1 "s_register_operand" "%0,0") - (match_operand:DI 2 "s_register_operand" "r,0")))] - "" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (match_operand:DI 1 "s_register_operand" "%0,r") + (match_operand:DI 2 "s_register_operand" "r,r")))] + "TARGET_ARM" "#" [(set_attr "length" "8")]) @@ -1387,52 +1622,107 @@ (and:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "?r,0")))] - "" + "TARGET_ARM" "#" [(set_attr "length" "8")]) (define_insn "*anddi_sesdi_di" - [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (and:DI (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) - (match_operand:DI 1 "s_register_operand" "?r,0")))] - "" + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "TARGET_ARM" "#" -[(set_attr "length" "8")]) + [(set_attr "length" "8")] +) (define_expand "andsi3" - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (and:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "reg_or_int_operand" "")))] - "" + "TARGET_EITHER" " - if (GET_CODE (operands[2]) == CONST_INT) + if (TARGET_ARM) { - arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0], - operands[1], - (reload_in_progress || reload_completed - ? 0 : preserve_subexpressions_p ())); - DONE; + if (GET_CODE (operands[2]) == CONST_INT) + { + arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0], + operands[1], + (reload_in_progress || reload_completed + ? 0 : preserve_subexpressions_p ())); + DONE; + } } -") + else /* TARGET_THUMB */ + { + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = force_reg (SImode, operands[2]); + else + { + int i; + + if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) + { + operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); + + emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); + + DONE; + } -(define_insn "*andsi3_insn" - [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + for (i = 9; i <= 31; i++) + { + if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) + { + emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), + const0_rtx)); + DONE; + } + else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) + { + rtx shift = GEN_INT (i); + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_lshrsi3 (reg, operands[1], shift)); + emit_insn (gen_ashlsi3 (operands[0], reg, shift)); + + DONE; + } + } + + operands[2] = force_reg (SImode, operands[2]); + } + }" +) + +(define_insn "*arm_andsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") (and:SI (match_operand:SI 1 "s_register_operand" "r,r,r") (match_operand:SI 2 "reg_or_int_operand" "rI,K,?n")))] - "" + "TARGET_ARM" "@ and%?\\t%0, %1, %2 bic%?\\t%0, %1, #%B2 #" -[(set_attr "length" "4,4,16")]) + [(set_attr "length" "4,4,16")] +) + +(define_insn "*thumb_andsi3_insn" + [(set (match_operand:SI 0 "register_operand" "=l") + (and:SI (match_operand:SI 1 "register_operand" "%0") + (match_operand:SI 2 "register_operand" "l")))] + "TARGET_THUMB" + "and\\t%0, %0, %2" + [(set_attr "length" "2")] +) (define_split - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (and:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] - "! (const_ok_for_arm (INTVAL (operands[2])) - || const_ok_for_arm (~ INTVAL (operands[2])))" + "TARGET_ARM + && (! (const_ok_for_arm ( INTVAL (operands[2])) + || const_ok_for_arm (~ INTVAL (operands[2]))))" [(clobber (const_int 0))] " arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0], @@ -1446,13 +1736,14 @@ (and:SI (match_operand:SI 1 "s_register_operand" "r,r") (match_operand:SI 2 "arm_not_operand" "rI,K")) (const_int 0))) - (set (match_operand:SI 0 "s_register_operand" "=r,r") + (set (match_operand:SI 0 "s_register_operand" "=r,r") (and:SI (match_dup 1) (match_dup 2)))] - "" + "TARGET_ARM" "@ and%?s\\t%0, %1, %2 bic%?s\\t%0, %1, #%B2" -[(set_attr "conds" "set")]) + [(set_attr "conds" "set")] +) (define_insn "*andsi3_compare0_scratch" [(set (reg:CC_NOOV 24) @@ -1461,7 +1752,7 @@ (match_operand:SI 1 "arm_not_operand" "rI,K")) (const_int 0))) (clobber (match_scratch:SI 3 "=X,r"))] - "" + "TARGET_ARM" "@ tst%?\\t%0, %1 bic%?s\\t%3, %0, #%B1" @@ -1474,10 +1765,11 @@ (match_operand 1 "const_int_operand" "n") (match_operand 2 "const_int_operand" "n")) (const_int 0)))] - "INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32 - && INTVAL (operands[1]) > 0 - && INTVAL (operands[1]) + (INTVAL (operands[2]) & 1) <= 8 - && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32" + "TARGET_ARM + && (INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32 + && INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) + (INTVAL (operands[2]) & 1) <= 8 + && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32)" "* operands[1] = GEN_INT (((1 << INTVAL (operands[1])) - 1) << INTVAL (operands[2])); @@ -1493,10 +1785,11 @@ (match_operand:SI 2 "const_int_operand" "n") (match_operand:SI 3 "const_int_operand" "n")) (const_int 0)))] - "INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32 - && INTVAL (operands[2]) > 0 - && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8 - && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32" + "TARGET_ARM + && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32 + && INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8 + && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)" "* operands[2] = GEN_INT (((1 << INTVAL (operands[2])) - 1) << INTVAL (operands[3])); @@ -1520,7 +1813,7 @@ (match_operand:SI 1 "general_operand" "") (match_operand:SI 2 "general_operand" "")) (match_operand:SI 3 "nonmemory_operand" ""))] - "" + "TARGET_ARM" " { int start_bit = INTVAL (operands[2]); @@ -1572,9 +1865,8 @@ rtx op1 = gen_reg_rtx (SImode); emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width))); - emit_insn (gen_iorsi3 (op1, gen_rtx_LSHIFTRT (SImode, operands[0], - operands[1]), - op0)); + emit_insn (gen_lshrsi3 (op1, operands[0], operands[1])); + emit_insn (gen_iorsi3 (op1, op1, op0)); emit_insn (gen_rotlsi3 (subtarget, op1, operands[1])); } else if ((width + start_bit == 32) @@ -1588,9 +1880,8 @@ emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width))); emit_insn (gen_ashlsi3 (op1, operands[0], operands[1])); - emit_insn (gen_iorsi3 (subtarget, - gen_rtx_LSHIFTRT (SImode, op1, operands[1]), - op0)); + emit_insn (gen_lshrsi3 (op1, op1, operands[1])); + emit_insn (gen_iorsi3 (subtarget, op1, op0)); } else { @@ -1627,13 +1918,13 @@ } if (start_bit != 0) - op0 = gen_rtx_ASHIFT (SImode, op0, operands[2]); + emit_insn (gen_ashlsi3 (op0, op0, operands[2])); emit_insn (gen_andsi_notsi_si (op2, operands[0], op0)); } if (start_bit != 0) - op1 = gen_rtx_ASHIFT (SImode, op1, operands[2]); + emit_insn (gen_ashlsi3 (op1, op1, operands[2])); emit_insn (gen_iorsi3 (subtarget, op1, op2)); } @@ -1657,7 +1948,7 @@ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (and:DI (not:DI (match_operand:DI 2 "s_register_operand" "r,0")) (match_operand:DI 1 "s_register_operand" "0,r")))] - "" + "TARGET_ARM" "#" [(set_attr "length" "8")]) @@ -1666,7 +1957,7 @@ (and:DI (not:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r"))) (match_operand:DI 1 "s_register_operand" "0,?r")))] - "" + "TARGET_ARM" "@ bic%?\\t%Q0, %Q1, %2 #" @@ -1677,7 +1968,7 @@ (and:DI (not:DI (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r"))) (match_operand:DI 1 "s_register_operand" "?r,0")))] - "" + "TARGET_ARM" "#" [(set_attr "length" "8")]) @@ -1685,16 +1976,25 @@ [(set (match_operand:SI 0 "s_register_operand" "=r") (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r")) (match_operand:SI 1 "s_register_operand" "r")))] - "" + "TARGET_ARM" "bic%?\\t%0, %1, %2") +(define_insn "bicsi3" + [(set (match_operand:SI 0 "register_operand" "=l") + (and:SI (not:SI (match_operand:SI 1 "register_operand" "l")) + (match_operand:SI 2 "register_operand" "0")))] + "TARGET_THUMB" + "bic\\t%0, %0, %1" + [(set_attr "length" "2")] +) + (define_insn "andsi_not_shiftsi_si" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (and:SI (not:SI (match_operator:SI 4 "shift_operator" - [(match_operand:SI 2 "s_register_operand" "r") - (match_operand:SI 3 "arm_rhs_operand" "rM")])) - (match_operand:SI 1 "s_register_operand" "r")))] - "" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (not:SI (match_operator:SI 4 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rM")])) + (match_operand:SI 1 "s_register_operand" "r")))] + "TARGET_ARM" "bic%?\\t%0, %1, %2%S4" ) @@ -1706,7 +2006,7 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r") (and:SI (not:SI (match_dup 2)) (match_dup 1)))] - "" + "TARGET_ARM" "bic%?s\\t%0, %1, %2" [(set_attr "conds" "set")]) @@ -1717,69 +2017,88 @@ (match_operand:SI 1 "s_register_operand" "r")) (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] - "" + "TARGET_ARM" "bic%?s\\t%0, %1, %2" [(set_attr "conds" "set")]) (define_insn "iordi3" - [(set (match_operand:DI 0 "s_register_operand" "=&r") - (ior:DI (match_operand:DI 1 "s_register_operand" "%0") - (match_operand:DI 2 "s_register_operand" "r")))] - "" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (ior:DI (match_operand:DI 1 "s_register_operand" "%0,r") + (match_operand:DI 2 "s_register_operand" "r,r")))] + "TARGET_ARM" "#" -[(set_attr "length" "8")]) + [(set_attr "length" "8")] +) (define_insn "*iordi_zesidi_di" [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (ior:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "0,?r")))] - "" + "TARGET_ARM" "@ orr%?\\t%Q0, %Q1, %2 #" -[(set_attr "length" "4,8")]) + [(set_attr "length" "4,8")] +) (define_insn "*iordi_sesidi_di" [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (ior:DI (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "?r,0")))] - "" + "TARGET_ARM" "#" -[(set_attr "length" "8")]) + [(set_attr "length" "8")] +) (define_expand "iorsi3" - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (ior:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "reg_or_int_operand" "")))] - "" + "TARGET_EITHER" " if (GET_CODE (operands[2]) == CONST_INT) { - arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0], - operands[1], - (reload_in_progress || reload_completed - ? 0 : preserve_subexpressions_p ())); - DONE; + if (TARGET_ARM) + { + arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0], + operands[1], + (reload_in_progress || reload_completed + ? 0 : preserve_subexpressions_p ())); + DONE; + } + else /* TARGET_THUMB */ + operands [2] = force_reg (SImode, operands [2]); } -") + " +) -(define_insn "*iorsi3_insn" - [(set (match_operand:SI 0 "s_register_operand" "=r,r") +(define_insn "*arm_iorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") (ior:SI (match_operand:SI 1 "s_register_operand" "r,r") (match_operand:SI 2 "reg_or_int_operand" "rI,?n")))] - "" + "TARGET_ARM" "@ orr%?\\t%0, %1, %2 #" -[(set_attr "length" "4,16")]) + [(set_attr "length" "4,16")] +) + +(define_insn "*thumb_iorsi3" + [(set (match_operand:SI 0 "register_operand" "=l") + (ior:SI (match_operand:SI 1 "register_operand" "%0") + (match_operand:SI 2 "register_operand" "l")))] + "TARGET_THUMB" + "orr\\t%0, %0, %2" + [(set_attr "length" "2")] +) (define_split - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (ior:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] - "! const_ok_for_arm (INTVAL (operands[2]))" + "TARGET_ARM && (! const_ok_for_arm (INTVAL (operands[2])))" [(clobber (const_int 0))] " arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0], @@ -1794,9 +2113,10 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r") (ior:SI (match_dup 1) (match_dup 2)))] - "" + "TARGET_ARM" "orr%?s\\t%0, %1, %2" -[(set_attr "conds" "set")]) + [(set_attr "conds" "set")] +) (define_insn "*iorsi3_compare0_scratch" [(set (reg:CC_NOOV 24) @@ -1804,44 +2124,68 @@ (match_operand:SI 2 "arm_rhs_operand" "rI")) (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] - "" + "TARGET_ARM" "orr%?s\\t%0, %1, %2" [(set_attr "conds" "set")]) (define_insn "xordi3" - [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") - (xor:DI (match_operand:DI 1 "s_register_operand" "%0,0") - (match_operand:DI 2 "s_register_operand" "r,0")))] - "" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (xor:DI (match_operand:DI 1 "s_register_operand" "%0,r") + (match_operand:DI 2 "s_register_operand" "r,r")))] + "TARGET_ARM" "#" -[(set_attr "length" "8")]) + [(set_attr "length" "8")] +) (define_insn "*xordi_zesidi_di" [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (xor:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "0,?r")))] - "" + "TARGET_ARM" "@ eor%?\\t%Q0, %Q1, %2 #" -[(set_attr "length" "4,8")]) + [(set_attr "length" "4,8")] +) (define_insn "*xordi_sesidi_di" [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (xor:DI (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "?r,0")))] - "" + "TARGET_ARM" "#" -[(set_attr "length" "8")]) + [(set_attr "length" "8")] +) -(define_insn "xorsi3" - [(set (match_operand:SI 0 "s_register_operand" "=r") +(define_expand "xorsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (xor:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "TARGET_EITHER" + "if (TARGET_THUMB) + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = force_reg (SImode, operands[2]); + " +) + +(define_insn "*arm_xorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r") (xor:SI (match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "arm_rhs_operand" "rI")))] - "" - "eor%?\\t%0, %1, %2") + "TARGET_ARM" + "eor%?\\t%0, %1, %2" +) + +(define_insn "*thumb_xorsi3" + [(set (match_operand:SI 0 "register_operand" "=l") + (xor:SI (match_operand:SI 1 "register_operand" "%0") + (match_operand:SI 2 "register_operand" "l")))] + "TARGET_THUMB" + "eor\\t%0, %0, %2" + [(set_attr "length" "2")] +) (define_insn "*xorsi3_compare0" [(set (reg:CC_NOOV 24) @@ -1850,7 +2194,7 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r") (xor:SI (match_dup 1) (match_dup 2)))] - "" + "TARGET_ARM" "eor%?s\\t%0, %1, %2" [(set_attr "conds" "set")]) @@ -1859,9 +2203,10 @@ (compare:CC_NOOV (xor:SI (match_operand:SI 0 "s_register_operand" "r") (match_operand:SI 1 "arm_rhs_operand" "rI")) (const_int 0)))] - "" + "TARGET_ARM" "teq%?\\t%0, %1" -[(set_attr "conds" "set")]) + [(set_attr "conds" "set")] +) ;; by splitting (IOR (AND (NOT A) (NOT B)) C) as D = AND (IOR A B) (NOT C), ;; (NOT D) we can sometimes merge the final NOT into one of the following @@ -1873,7 +2218,7 @@ (not:SI (match_operand:SI 2 "arm_rhs_operand" "rI"))) (match_operand:SI 3 "arm_rhs_operand" "rI"))) (clobber (match_operand:SI 4 "s_register_operand" "=r"))] - "" + "TARGET_ARM" [(set (match_dup 4) (and:SI (ior:SI (match_dup 1) (match_dup 2)) (not:SI (match_dup 3)))) (set (match_dup 0) (not:SI (match_dup 4)))] @@ -1885,33 +2230,35 @@ (and:SI (ior:SI (match_operand:SI 1 "s_register_operand" "r,r,0") (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")) (not:SI (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI"))))] - "" + "TARGET_ARM" "orr%?\\t%0, %1, %2\;bic%?\\t%0, %0, %3" -[(set_attr "length" "8")]) + [(set_attr "length" "8")] +) ;; Minimum and maximum insns (define_insn "smaxsi3" - [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") - (smax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") - (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (smax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "@ cmp\\t%1, %2\;movlt\\t%0, %2 cmp\\t%1, %2\;movge\\t%0, %1 cmp\\t%1, %2\;movge\\t%0, %1\;movlt\\t%0, %2" -[(set_attr "conds" "clob") - (set_attr "length" "8,8,12")]) + [(set_attr "conds" "clob") + (set_attr "length" "8,8,12")] +) (define_insn "sminsi3" [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") (smin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "@ cmp\\t%1, %2\;movge\\t%0, %2 cmp\\t%1, %2\;movlt\\t%0, %1 @@ -1924,7 +2271,7 @@ (umax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "@ cmp\\t%1, %2\;movcc\\t%0, %2 cmp\\t%1, %2\;movcs\\t%0, %1 @@ -1937,7 +2284,7 @@ (umin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "@ cmp\\t%1, %2\;movcs\\t%0, %2 cmp\\t%1, %2\;movcc\\t%0, %1 @@ -1951,7 +2298,7 @@ [(match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "s_register_operand" "r")])) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "* operands[3] = gen_rtx (minmax_code (operands[3]), SImode, operands[1], operands[2]); @@ -1974,9 +2321,10 @@ (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]) (match_operand:SI 1 "s_register_operand" "0,?r")])) (clobber (reg:CC 24))] - "GET_CODE (operands[1]) != REG - || (REGNO(operands[1]) != FRAME_POINTER_REGNUM - && REGNO(operands[1]) != ARG_POINTER_REGNUM)" + "TARGET_ARM + && (GET_CODE (operands[1]) != REG + || (REGNO(operands[1]) != FRAME_POINTER_REGNUM + && REGNO(operands[1]) != ARG_POINTER_REGNUM))" "* { enum rtx_code code = GET_CODE (operands[4]); @@ -1998,10 +2346,10 @@ ;; Shift and rotation insns (define_expand "ashlsi3" - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (ashift:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "arm_rhs_operand" "")))] - "" + "TARGET_EITHER" " if (GET_CODE (operands[2]) == CONST_INT && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) @@ -2009,24 +2357,44 @@ emit_insn (gen_movsi (operands[0], const0_rtx)); DONE; } -") + " +) + +(define_insn "*thumb_ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (ashift:SI (match_operand:SI 1 "register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "TARGET_THUMB" + "lsl\\t%0, %1, %2" + [(set_attr "length" "2")] +) (define_expand "ashrsi3" - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "arm_rhs_operand" "")))] - "" + "TARGET_EITHER" " if (GET_CODE (operands[2]) == CONST_INT && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) operands[2] = GEN_INT (31); -") + " +) + +(define_insn "*thumb_ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "TARGET_THUMB" + "asr\\t%0, %1, %2" + [(set_attr "length" "2")] +) (define_expand "lshrsi3" - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "arm_rhs_operand" "")))] - "" + "TARGET_EITHER" " if (GET_CODE (operands[2]) == CONST_INT && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) @@ -2034,13 +2402,23 @@ emit_insn (gen_movsi (operands[0], const0_rtx)); DONE; } -") + " +) + +(define_insn "*thumb_lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "TARGET_THUMB" + "lsr\\t%0, %1, %2" + [(set_attr "length" "2")] +) (define_expand "rotlsi3" - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (rotatert:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "reg_or_int_operand" "")))] - "" + "TARGET_ARM" " if (GET_CODE (operands[2]) == CONST_INT) operands[2] = GEN_INT ((32 - INTVAL (operands[2])) % 32); @@ -2050,25 +2428,44 @@ emit_insn (gen_subsi3 (reg, GEN_INT (32), operands[2])); operands[2] = reg; } -") + " +) (define_expand "rotrsi3" - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (rotatert:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "arm_rhs_operand" "")))] - "" + "TARGET_EITHER" " - if (GET_CODE (operands[2]) == CONST_INT - && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) - operands[2] = GEN_INT (INTVAL (operands[2]) % 32); -") + if (TARGET_ARM) + { + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + operands[2] = GEN_INT (INTVAL (operands[2]) % 32); + } + else /* TARGET_THUMB */ + { + if (GET_CODE (operands [2]) == CONST_INT) + operands [2] = force_reg (SImode, operands[2]); + } + " +) -(define_insn "*shiftsi3" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (match_operator:SI 3 "shift_operator" - [(match_operand:SI 1 "s_register_operand" "r") +(define_insn "*thumb_rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=l") + (rotatert:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "register_operand" "l")))] + "TARGET_THUMB" + "ror\\t%0, %0, %2" + [(set_attr "length" "2")] +) + +(define_insn "*arm_shiftsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "reg_or_int_operand" "rM")]))] - "" + "TARGET_ARM" "mov%?\\t%0, %1%S3" ) @@ -2080,7 +2477,7 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r") (match_op_dup 3 [(match_dup 1) (match_dup 2)]))] - "" + "TARGET_ARM" "mov%?s\\t%0, %1%S3" [(set_attr "conds" "set") ]) @@ -2092,7 +2489,7 @@ (match_operand:SI 2 "arm_rhs_operand" "rM")]) (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] - "" + "TARGET_ARM" "mov%?s\\t%0, %1%S3" [(set_attr "conds" "set") ]) @@ -2102,9 +2499,10 @@ (not:SI (match_operator:SI 3 "shift_operator" [(match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "arm_rhs_operand" "rM")])))] - "" + "TARGET_ARM" "mvn%?\\t%0, %1%S3" -) + [(set_attr "conds" "set") +]) (define_insn "*notsi_shiftsi_compare0" [(set (reg:CC_NOOV 24) @@ -2114,7 +2512,7 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r") (not:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])))] - "" + "TARGET_ARM" "mvn%?s\\t%0, %1%S3" [(set_attr "conds" "set") ]) @@ -2126,39 +2524,119 @@ (match_operand:SI 2 "arm_rhs_operand" "rM")])) (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] - "" + "TARGET_ARM" "mvn%?s\\t%0, %1%S3" [(set_attr "conds" "set") ]) +;; We don't really have extzv, but defining this using shifts helps +;; to reduce register pressure later on. + +(define_expand "extzv" + [(set (match_dup 4) + (ashift:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "const_int_operand" ""))) + (set (match_operand:SI 0 "register_operand" "") + (lshiftrt:SI (match_dup 4) + (match_operand:SI 3 "const_int_operand" ""))) + ] + "TARGET_THUMB" + " + { + HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); + HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); + + operands[3] = GEN_INT (rshift); + + if (lshift == 0) + { + emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); + DONE; + } + + operands[2] = GEN_INT (lshift); + operands[4] = gen_reg_rtx (SImode); + } + " +) + ;; Unary arithmetic insns -(define_insn "negdi2" - [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") - (neg:DI (match_operand:DI 1 "s_register_operand" "?r,0")))] - "" +(define_expand "negdi2" + [(parallel + [(set (match_operand:DI 0 "s_register_operand" "") + (neg:DI (match_operand:DI 1 "s_register_operand" ""))) + (clobber (reg:CC 24)) + ]) + ] + "TARGET_EITHER" + " + if (TARGET_THUMB) + { + if (GET_CODE (operands[1]) != REG) + operands[1] = force_reg (SImode, operands[1]); + } + " +) + +;; The constraints here are to prevent a *partial* overlap (where %Q0 == %R1). +;; The second alternative is to allow the common case of a *full* overlap. +(define_insn "*arm_negdi2" + [(set (match_operand:DI 0 "s_register_operand" "=&r,r") + (neg:DI (match_operand:DI 1 "s_register_operand" "?r,0"))) + (clobber (reg:CC 24)) + ] + "TARGET_ARM" "rsbs\\t%Q0, %Q1, #0\;rsc\\t%R0, %R1, #0" -[(set_attr "conds" "clob") - (set_attr "length" "8")]) + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) -(define_insn "negsi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (neg:SI (match_operand:SI 1 "s_register_operand" "r")))] +(define_insn "*thumb_negdi2" + [(set (match_operand:DI 0 "register_operand" "=&l") + (neg:DI (match_operand:DI 1 "register_operand" "l"))) + (clobber (reg:CC 24)) + ] + "TARGET_THUMB" + "mov\\t%R0, #0\;neg\\t%Q0, %Q1\;sbc\\t%R0, %R1" + [(set_attr "length" "6")] +) + +(define_expand "negsi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (neg:SI (match_operand:SI 1 "s_register_operand" "")))] + "TARGET_EITHER" "" - "rsb%?\\t%0, %1, #0") +) + +(define_insn "*arm_negsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (neg:SI (match_operand:SI 1 "s_register_operand" "r")))] + "TARGET_ARM" + "rsb%?\\t%0, %1, #0" +) + +(define_insn "*thumb_negsi2" + [(set (match_operand:SI 0 "register_operand" "=l") + (neg:SI (match_operand:SI 1 "register_operand" "l")))] + "TARGET_THUMB" + "neg\\t%0, %1" + [(set_attr "length" "2")] +) (define_insn "negsf2" [(set (match_operand:SF 0 "s_register_operand" "=f") (neg:SF (match_operand:SF 1 "s_register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "mnf%?s\\t%0, %1" -[(set_attr "type" "ffarith")]) + [(set_attr "type" "ffarith")] +) (define_insn "negdf2" [(set (match_operand:DF 0 "s_register_operand" "=f") (neg:DF (match_operand:DF 1 "s_register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "mnf%?d\\t%0, %1" [(set_attr "type" "ffarith")]) @@ -2166,14 +2644,14 @@ [(set (match_operand:DF 0 "s_register_operand" "=f") (neg:DF (float_extend:DF (match_operand:SF 1 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "mnf%?d\\t%0, %1" [(set_attr "type" "ffarith")]) (define_insn "negxf2" [(set (match_operand:XF 0 "s_register_operand" "=f") (neg:XF (match_operand:XF 1 "s_register_operand" "f")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "mnf%?e\\t%0, %1" [(set_attr "type" "ffarith")]) @@ -2186,35 +2664,37 @@ [(set (match_operand:SI 0 "s_register_operand" "=r,&r") (abs:SI (match_operand:SI 1 "s_register_operand" "0,r"))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "@ cmp\\t%0, #0\;rsblt\\t%0, %0, #0 eor%?\\t%0, %1, %1, asr #31\;sub%?\\t%0, %0, %1, asr #31" -[(set_attr "conds" "clob,*") - (set_attr "length" "8")]) + [(set_attr "conds" "clob,*") + (set_attr "length" "8")] +) (define_insn "*neg_abssi2" [(set (match_operand:SI 0 "s_register_operand" "=r,&r") (neg:SI (abs:SI (match_operand:SI 1 "s_register_operand" "0,r")))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "@ cmp\\t%0, #0\;rsbgt\\t%0, %0, #0 eor%?\\t%0, %1, %1, asr #31\;rsb%?\\t%0, %0, %1, asr #31" -[(set_attr "conds" "clob,*") - (set_attr "length" "8")]) + [(set_attr "conds" "clob,*") + (set_attr "length" "8")] +) (define_insn "abssf2" [(set (match_operand:SF 0 "s_register_operand" "=f") (abs:SF (match_operand:SF 1 "s_register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "abs%?s\\t%0, %1" [(set_attr "type" "ffarith")]) (define_insn "absdf2" [(set (match_operand:DF 0 "s_register_operand" "=f") (abs:DF (match_operand:DF 1 "s_register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "abs%?d\\t%0, %1" [(set_attr "type" "ffarith")]) @@ -2222,28 +2702,28 @@ [(set (match_operand:DF 0 "s_register_operand" "=f") (abs:DF (float_extend:DF (match_operand:SF 1 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "abs%?d\\t%0, %1" [(set_attr "type" "ffarith")]) (define_insn "absxf2" [(set (match_operand:XF 0 "s_register_operand" "=f") (abs:XF (match_operand:XF 1 "s_register_operand" "f")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "abs%?e\\t%0, %1" [(set_attr "type" "ffarith")]) (define_insn "sqrtsf2" [(set (match_operand:SF 0 "s_register_operand" "=f") (sqrt:SF (match_operand:SF 1 "s_register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "sqt%?s\\t%0, %1" [(set_attr "type" "float_em")]) (define_insn "sqrtdf2" [(set (match_operand:DF 0 "s_register_operand" "=f") (sqrt:DF (match_operand:DF 1 "s_register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "sqt%?d\\t%0, %1" [(set_attr "type" "float_em")]) @@ -2251,14 +2731,14 @@ [(set (match_operand:DF 0 "s_register_operand" "=f") (sqrt:DF (float_extend:DF (match_operand:SF 1 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "sqt%?d\\t%0, %1" [(set_attr "type" "float_em")]) (define_insn "sqrtxf2" [(set (match_operand:XF 0 "s_register_operand" "=f") (sqrt:XF (match_operand:XF 1 "s_register_operand" "f")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "sqt%?e\\t%0, %1" [(set_attr "type" "float_em")]) @@ -2267,14 +2747,14 @@ ;(define_insn "sinsf2" ; [(set (match_operand:SF 0 "s_register_operand" "=f") ; (unspec:SF [(match_operand:SF 1 "s_register_operand" "f")] 0))] -; "TARGET_HARD_FLOAT" +; "TARGET_ARM && TARGET_HARD_FLOAT" ; "sin%?s\\t%0, %1" ;[(set_attr "type" "float_em")]) ; ;(define_insn "sindf2" ; [(set (match_operand:DF 0 "s_register_operand" "=f") ; (unspec:DF [(match_operand:DF 1 "s_register_operand" "f")] 0))] -; "TARGET_HARD_FLOAT" +; "TARGET_ARM && TARGET_HARD_FLOAT" ; "sin%?d\\t%0, %1" ;[(set_attr "type" "float_em")]) ; @@ -2282,28 +2762,28 @@ ; [(set (match_operand:DF 0 "s_register_operand" "=f") ; (unspec:DF [(float_extend:DF ; (match_operand:SF 1 "s_register_operand" "f"))] 0))] -; "TARGET_HARD_FLOAT" +; "TARGET_ARM && TARGET_HARD_FLOAT" ; "sin%?d\\t%0, %1" ;[(set_attr "type" "float_em")]) ; ;(define_insn "sinxf2" ; [(set (match_operand:XF 0 "s_register_operand" "=f") ; (unspec:XF [(match_operand:XF 1 "s_register_operand" "f")] 0))] -; "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" +; "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" ; "sin%?e\\t%0, %1" ;[(set_attr "type" "float_em")]) ; ;(define_insn "cossf2" ; [(set (match_operand:SF 0 "s_register_operand" "=f") ; (unspec:SF [(match_operand:SF 1 "s_register_operand" "f")] 1))] -; "TARGET_HARD_FLOAT" +; "TARGET_ARM && TARGET_HARD_FLOAT" ; "cos%?s\\t%0, %1" ;[(set_attr "type" "float_em")]) ; ;(define_insn "cosdf2" ; [(set (match_operand:DF 0 "s_register_operand" "=f") ; (unspec:DF [(match_operand:DF 1 "s_register_operand" "f")] 1))] -; "TARGET_HARD_FLOAT" +; "TARGET_ARM && TARGET_HARD_FLOAT" ; "cos%?d\\t%0, %1" ;[(set_attr "type" "float_em")]) ; @@ -2311,29 +2791,46 @@ ; [(set (match_operand:DF 0 "s_register_operand" "=f") ; (unspec:DF [(float_extend:DF ; (match_operand:SF 1 "s_register_operand" "f"))] 1))] -; "TARGET_HARD_FLOAT" +; "TARGET_ARM && TARGET_HARD_FLOAT" ; "cos%?d\\t%0, %1" ;[(set_attr "type" "float_em")]) ; ;(define_insn "cosxf2" ; [(set (match_operand:XF 0 "s_register_operand" "=f") ; (unspec:XF [(match_operand:XF 1 "s_register_operand" "f")] 1))] -; "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" +; "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" ; "cos%?e\\t%0, %1" ;[(set_attr "type" "float_em")]) (define_insn "one_cmpldi2" [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (not:DI (match_operand:DI 1 "s_register_operand" "?r,0")))] - "" + "TARGET_ARM" "#" -[(set_attr "length" "8")]) + [(set_attr "length" "8")] +) -(define_insn "one_cmplsi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (not:SI (match_operand:SI 1 "s_register_operand" "r")))] +(define_expand "one_cmplsi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (not:SI (match_operand:SI 1 "s_register_operand" "")))] + "TARGET_EITHER" "" - "mvn%?\\t%0, %1") +) + +(define_insn "*arm_one_cmplsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_operand:SI 1 "s_register_operand" "r")))] + "TARGET_ARM" + "mvn%?\\t%0, %1" +) + +(define_insn "*thumb_one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=l") + (not:SI (match_operand:SI 1 "register_operand" "l")))] + "TARGET_THUMB" + "mvn\\t%0, %1" + [(set_attr "length" "2")] +) (define_insn "*notsi_compare0" [(set (reg:CC_NOOV 24) @@ -2341,60 +2838,62 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r") (not:SI (match_dup 1)))] - "" + "TARGET_ARM" "mvn%?s\\t%0, %1" -[(set_attr "conds" "set")]) + [(set_attr "conds" "set")] +) (define_insn "*notsi_compare0_scratch" [(set (reg:CC_NOOV 24) (compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r")) (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] - "" + "TARGET_ARM" "mvn%?s\\t%0, %1" -[(set_attr "conds" "set")]) + [(set_attr "conds" "set")] +) ;; Fixed <--> Floating conversion insns (define_insn "floatsisf2" [(set (match_operand:SF 0 "s_register_operand" "=f") (float:SF (match_operand:SI 1 "s_register_operand" "r")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "flt%?s\\t%0, %1" [(set_attr "type" "r_2_f")]) (define_insn "floatsidf2" [(set (match_operand:DF 0 "s_register_operand" "=f") (float:DF (match_operand:SI 1 "s_register_operand" "r")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "flt%?d\\t%0, %1" [(set_attr "type" "r_2_f")]) (define_insn "floatsixf2" [(set (match_operand:XF 0 "s_register_operand" "=f") (float:XF (match_operand:SI 1 "s_register_operand" "r")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "flt%?e\\t%0, %1" [(set_attr "type" "r_2_f")]) (define_insn "fix_truncsfsi2" [(set (match_operand:SI 0 "s_register_operand" "=r") (fix:SI (match_operand:SF 1 "s_register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "fix%?z\\t%0, %1" [(set_attr "type" "f_2_r")]) (define_insn "fix_truncdfsi2" [(set (match_operand:SI 0 "s_register_operand" "=r") (fix:SI (match_operand:DF 1 "s_register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "fix%?z\\t%0, %1" [(set_attr "type" "f_2_r")]) (define_insn "fix_truncxfsi2" [(set (match_operand:SI 0 "s_register_operand" "=r") (fix:SI (match_operand:XF 1 "s_register_operand" "f")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "fix%?z\\t%0, %1" [(set_attr "type" "f_2_r")]) @@ -2404,7 +2903,7 @@ [(set (match_operand:SF 0 "s_register_operand" "=f") (float_truncate:SF (match_operand:DF 1 "s_register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "mvf%?s\\t%0, %1" [(set_attr "type" "ffarith")]) @@ -2412,7 +2911,7 @@ [(set (match_operand:SF 0 "s_register_operand" "=f") (float_truncate:SF (match_operand:XF 1 "s_register_operand" "f")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "mvf%?s\\t%0, %1" [(set_attr "type" "ffarith")]) @@ -2420,7 +2919,7 @@ [(set (match_operand:DF 0 "s_register_operand" "=f") (float_truncate:DF (match_operand:XF 1 "s_register_operand" "f")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "mvf%?d\\t%0, %1" [(set_attr "type" "ffarith")]) @@ -2429,7 +2928,7 @@ (define_insn "zero_extendsidi2" [(set (match_operand:DI 0 "s_register_operand" "=r") (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")))] - "" + "TARGET_ARM" "* if (REGNO (operands[1]) != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0)) output_asm_insn (\"mov%?\\t%Q0, %1\", operands); @@ -2438,74 +2937,158 @@ [(set_attr "length" "8")]) (define_insn "zero_extendqidi2" - [(set (match_operand:DI 0 "s_register_operand" "=r,r") + [(set (match_operand:DI 0 "s_register_operand" "=r,r") (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] - "" + "TARGET_ARM" "@ and%?\\t%Q0, %1, #255\;mov%?\\t%R0, #0 ldr%?b\\t%Q0, %1\;mov%?\\t%R0, #0" -[(set_attr "length" "8") - (set_attr "type" "*,load") - (set_attr "pool_range" "*,4096")]) + [(set_attr "length" "8") + (set_attr "type" "*,load") + (set_attr "pool_range" "*,4092") + (set_attr "neg_pool_range" "*,4084")] +) (define_insn "extendsidi2" [(set (match_operand:DI 0 "s_register_operand" "=r") (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")))] - "" + "TARGET_ARM" "* if (REGNO (operands[1]) != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0)) output_asm_insn (\"mov%?\\t%Q0, %1\", operands); return \"mov%?\\t%R0, %Q0, asr #31\"; -" -[(set_attr "length" "8")]) + " + [(set_attr "length" "8") +]) (define_expand "zero_extendhisi2" - [(set (match_dup 2) (ashift:SI (match_operand:HI 1 "nonimmediate_operand" "") - (const_int 16))) + [(set (match_dup 2) + (ashift:SI (match_operand:HI 1 "nonimmediate_operand" "") (const_int 16))) (set (match_operand:SI 0 "s_register_operand" "") (lshiftrt:SI (match_dup 2) (const_int 16)))] - "" + "TARGET_EITHER" " -{ - if (arm_arch4 && GET_CODE (operands[1]) == MEM) - { - /* Note: We do not have to worry about TARGET_MMU_TRAPS - here because the insn below will generate an LDRH instruction - rather than an LDR instruction, so we cannot get an unaligned - word access. */ - emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_ZERO_EXTEND (SImode, operands[1]))); - DONE; - } - if (TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM) + { + if (TARGET_ARM) + { + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + /* Note: We do not have to worry about TARGET_MMU_TRAPS + here because the insn below will generate an LDRH instruction + rather than an LDR instruction, so we cannot get an unaligned + word access. */ + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_ZERO_EXTEND (SImode, operands[1]))); + DONE; + } + if (TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_movhi_bytes (operands[0], operands[1])); + DONE; + } + if (! s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); + } + else /* TARGET_THUMB */ + { + if (GET_CODE (operands[1]) == MEM) + { + rtx tmp; + + tmp = gen_rtx_ZERO_EXTEND (SImode, operands[1]); + tmp = gen_rtx_SET (VOIDmode, operands[0], tmp); + emit_insn (tmp); + } + else + { + rtx ops[3]; + + if (! s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); + + ops[0] = operands[2]; + ops[1] = operands[1]; + ops[2] = GEN_INT (16); + + emit_insn (gen_rtx_SET (VOIDmode, ops[0], gen_rtx_ASHIFT (SImode, ops[1], ops[2]))); + + ops[0] = operands[0]; + ops[1] = operands[2]; + ops[2] = GEN_INT (16); + + emit_insn (gen_rtx_SET (VOIDmode, ops[0], gen_rtx_LSHIFTRT (SImode, ops[1], ops[2]))); + } + DONE; + } + }" +) + +(define_insn "*thumb_zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=l") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "TARGET_THUMB" + "* + rtx mem = XEXP (operands[1], 0); + + if (GET_CODE (mem) == CONST) + mem = XEXP (mem, 0); + + if (GET_CODE (mem) == LABEL_REF) + return \"ldr\\t%0, %1\"; + + if (GET_CODE (mem) == PLUS) { - emit_insn (gen_movhi_bytes (operands[0], operands[1])); - DONE; + rtx a = XEXP (mem, 0); + rtx b = XEXP (mem, 1); + + /* This can happen due to bugs in reload. */ + if (GET_CODE (a) == REG && REGNO (a) == SP_REGNUM) + { + rtx ops[2]; + ops[0] = operands[0]; + ops[1] = a; + + output_asm_insn (\"mov %0, %1\", ops); + + XEXP (mem, 0) = operands[0]; + } + + else if ( GET_CODE (a) == LABEL_REF + && GET_CODE (b) == CONST_INT) + return \"ldr\\t%0, %1\"; } - if (! s_register_operand (operands[1], HImode)) - operands[1] = copy_to_mode_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); -}") + + return \"ldrh\\t%0, %1\"; + " + [(set_attr "length" "4") + (set_attr "type" "load") + (set_attr "pool_range" "60")] +) -(define_insn "*zero_extendhisi_insn" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] - "arm_arch4" +(define_insn "*arm_zero_extendhisi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "TARGET_ARM && arm_arch4" "ldr%?h\\t%0, %1" -[(set_attr "type" "load") - (set_attr "pool_range" "256")]) + [(set_attr "type" "load") + (set_attr "pool_range" "256") + (set_attr "neg_pool_range" "244")] +) (define_split [(set (match_operand:SI 0 "s_register_operand" "") (zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))) (clobber (match_operand:SI 2 "s_register_operand" ""))] - "! arm_arch4" + "TARGET_ARM && (! arm_arch4)" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (lshiftrt:SI (match_dup 2) (const_int 16)))] " { - if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL) FAIL; }") @@ -2515,55 +3098,91 @@ [(zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")) (match_operand:SI 4 "s_register_operand" "")])) (clobber (match_operand:SI 2 "s_register_operand" ""))] - "! arm_arch4" + "TARGET_ARM && (! arm_arch4)" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (match_op_dup 3 [(lshiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))] " { - if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL) FAIL; }") (define_expand "zero_extendqisi2" - [(set (match_operand:SI 0 "s_register_operand" "=r,r") - (zero_extend:SI - (match_operand:QI 1 "nonimmediate_operand" "r,m")))] - "" + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "TARGET_EITHER" " if (GET_CODE (operands[1]) != MEM) { - emit_insn (gen_andsi3 (operands[0], gen_lowpart (SImode, operands[1]), - GEN_INT (255))); + if (TARGET_ARM) + { + emit_insn (gen_andsi3 (operands[0], gen_lowpart (SImode, operands[1]), + GEN_INT (255))); + } + else /* TARGET_THUMB */ + { + rtx temp = gen_reg_rtx (SImode); + rtx ops[3]; + + operands[1] = copy_to_mode_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + + ops[0] = temp; + ops[1] = operands[1]; + ops[2] = GEN_INT (24); + + emit_insn (gen_rtx_SET (VOIDmode, ops[0], gen_rtx_ASHIFT (SImode, ops[1], ops[2]))); + + ops[0] = operands[0]; + ops[1] = temp; + ops[2] = GEN_INT (24); + + emit_insn (gen_rtx_SET (VOIDmode, ops[0], gen_rtx_LSHIFTRT (SImode, ops[1], ops[2]))); + } DONE; } ") -(define_insn "*load_extendqisi" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] - "" +(define_insn "*thumb_zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=l") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "TARGET_THUMB" + "ldrb\\t%0, %1" + [(set_attr "length" "2") + (set_attr "type" "load") + (set_attr "pool_range" "32")] +) + +(define_insn "*arm_zero_extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "TARGET_ARM" "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2" -[(set_attr "type" "load") - (set_attr "pool_range" "4096")]) + [(set_attr "type" "load") + (set_attr "pool_range" "4096") + (set_attr "neg_pool_range" "4084")] +) (define_split [(set (match_operand:SI 0 "s_register_operand" "") (zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 0))) (clobber (match_operand:SI 2 "s_register_operand" ""))] - "GET_CODE (operands[1]) != MEM" + "TARGET_ARM && (GET_CODE (operands[1]) != MEM)" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (and:SI (match_dup 2) (const_int 255)))] - "") + "" +) (define_insn "*compareqi_eq0" [(set (reg:CC_Z 24) (compare:CC_Z (match_operand:QI 0 "s_register_operand" "r") (const_int 0)))] - "" + "TARGET_ARM" "tst\\t%0, #255" -[(set_attr "conds" "set")]) + [(set_attr "conds" "set")] +) (define_expand "extendhisi2" [(set (match_dup 2) @@ -2572,30 +3191,108 @@ (set (match_operand:SI 0 "s_register_operand" "") (ashiftrt:SI (match_dup 2) (const_int 16)))] - "" + "TARGET_EITHER" " -{ - if (arm_arch4 && GET_CODE (operands[1]) == MEM) - { - /* Note: We do not have to worry about TARGET_MMU_TRAPS - here because the insn below will generate an LDRH instruction - rather than an LDR instruction, so we cannot get an unaligned - word access. */ - emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_SIGN_EXTEND (SImode, operands[1]))); - DONE; - } + { + if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM) + { + /* Note: We do not have to worry about TARGET_MMU_TRAPS + here because the insn below will generate an LDRH instruction + rather than an LDR instruction, so we cannot get an unaligned + word access. */ + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_SIGN_EXTEND (SImode, operands[1]))); + DONE; + } - if (TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM) - { - emit_insn (gen_extendhisi2_mem (operands[0], operands[1])); - DONE; - } - if (! s_register_operand (operands[1], HImode)) - operands[1] = copy_to_mode_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); -}") + if (TARGET_ARM && TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_extendhisi2_mem (operands[0], operands[1])); + DONE; + } + if (! s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); + + if (TARGET_THUMB) + { + rtx ops[3]; + + ops[0] = operands[2]; + ops[1] = operands[1]; + ops[2] = GEN_INT (16); + + emit_insn (gen_rtx_SET (VOIDmode, ops[0], gen_rtx_ASHIFT (SImode, ops[1], ops[2]))); + + ops[0] = operands[0]; + ops[1] = operands[2]; + ops[2] = GEN_INT (16); + + emit_insn (gen_rtx_SET (VOIDmode, ops[0], gen_rtx_ASHIFTRT (SImode, ops[1], ops[2]))); + + DONE; + } + }" +) + +(define_insn "*thumb_extendhisi2_insn" + [(set (match_operand:SI 0 "register_operand" "=l") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) + (clobber (match_scratch:SI 2 "=&l"))] + "TARGET_THUMB" + "* + { + rtx ops[4]; + rtx mem = XEXP (operands[1], 0); + + /* This code used to try to use 'V', and fix the address only if it was + offsettable, but this fails for e.g. REG+48 because 48 is outside the + range of QImode offsets, and offsettable_address_p does a QImode + address check. */ + + if (GET_CODE (mem) == CONST) + mem = XEXP (mem, 0); + + if (GET_CODE (mem) == LABEL_REF) + return \"ldr\\t%0, %1\"; + + if (GET_CODE (mem) == PLUS) + { + rtx a = XEXP (mem, 0); + rtx b = XEXP (mem, 1); + + if (GET_CODE (a) == LABEL_REF + && GET_CODE (b) == CONST_INT) + return \"ldr\\t%0, %1\"; + + if (GET_CODE (b) == REG) + return \"ldrsh\\t%0, %1\"; + + ops[1] = a; + ops[2] = b; + } + else + { + ops[1] = mem; + ops[2] = const0_rtx; + } + + if (GET_CODE (ops[1]) != REG) + { + debug_rtx (ops[1]); + abort (); + } + + ops[0] = operands[0]; + ops[3] = operands[2]; + output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); + return \"\"; + }" + [(set_attr "length" "4") + (set_attr "type" "load") + (set_attr "pool_range" "1020")] +) (define_expand "extendhisi2_mem" [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" ""))) @@ -2604,7 +3301,7 @@ (set (match_dup 6) (ashift:SI (match_dup 4) (const_int 24))) (set (match_operand:SI 0 "" "") (ior:SI (ashiftrt:SI (match_dup 6) (const_int 16)) (match_dup 5)))] - "" + "TARGET_ARM" " { rtx mem1, mem2; @@ -2636,43 +3333,44 @@ } ") -(define_insn "*extendhisi_insn" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] - "arm_arch4" +(define_insn "*arm_extendhisi_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "TARGET_ARM && arm_arch4" "ldr%?sh\\t%0, %1" -[(set_attr "type" "load") - (set_attr "pool_range" "256")]) + [(set_attr "type" "load") + (set_attr "pool_range" "256") + (set_attr "neg_pool_range" "244")] +) (define_split - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "") (sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))) - (clobber (match_operand:SI 2 "s_register_operand" ""))] - "! arm_arch4" + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "TARGET_ARM && (! arm_arch4)" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (ashiftrt:SI (match_dup 2) (const_int 16)))] " -{ - if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL) FAIL; -}") + " +) (define_split - [(set (match_operand:SI 0 "s_register_operand" "") - (match_operator:SI 3 "shiftable_operator" + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 3 "shiftable_operator" [(sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")) - (match_operand:SI 4 "s_register_operand" "")])) - (clobber (match_operand:SI 2 "s_register_operand" ""))] - "! arm_arch4" + (match_operand:SI 4 "s_register_operand" "")])) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "TARGET_ARM && (! arm_arch4)" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (match_op_dup 3 [(ashiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))] + "if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL) + FAIL; " -{ - if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) - FAIL; -}") +) (define_expand "extendqihi2" [(set (match_dup 2) @@ -2681,7 +3379,7 @@ (set (match_operand:HI 0 "s_register_operand" "") (ashiftrt:SI (match_dup 2) (const_int 24)))] - "" + "TARGET_ARM" " { if (arm_arch4 && GET_CODE (operands[1]) == MEM) @@ -2701,23 +3399,25 @@ ; Rather than restricting all byte accesses to memory addresses that ldrsb ; can handle, we fix up the ones that ldrsb can't grok with a split. (define_insn "*extendqihi_insn" - [(set (match_operand:HI 0 "s_register_operand" "=r") - (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] - "arm_arch4" + [(set (match_operand:HI 0 "s_register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] + "TARGET_ARM && arm_arch4" "* /* If the address is invalid, this will split the instruction into two. */ - if (bad_signed_byte_operand (operands[1], QImode)) + if (bad_signed_byte_operand (operands[1], VOIDmode)) return \"#\"; return \"ldr%?sb\\t%0, %1\"; -" -[(set_attr "type" "load") - (set_attr "length" "8") - (set_attr "pool_range" "256")]) + " + [(set_attr "type" "load") + (set_attr "length" "8") + (set_attr "pool_range" "256") + (set_attr "neg_pool_range" "244")] +) (define_split [(set (match_operand:HI 0 "s_register_operand" "") (sign_extend:HI (match_operand:QI 1 "bad_signed_byte_operand" "")))] - "arm_arch4 && reload_completed" + "TARGET_ARM && arm_arch4 && reload_completed" [(set (match_dup 3) (match_dup 1)) (set (match_dup 0) (sign_extend:HI (match_dup 2)))] " @@ -2756,42 +3456,64 @@ (set (match_operand:SI 0 "s_register_operand" "") (ashiftrt:SI (match_dup 2) (const_int 24)))] - "" + "TARGET_EITHER" " -{ - if (arm_arch4 && GET_CODE (operands[1]) == MEM) - { - emit_insn (gen_rtx_SET (VOIDmode, - operands[0], - gen_rtx_SIGN_EXTEND (SImode, operands[1]))); - DONE; - } - if (! s_register_operand (operands[1], QImode)) - operands[1] = copy_to_mode_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); -}") + { + if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_SIGN_EXTEND (SImode, operands[1]))); + DONE; + } + if (! s_register_operand (operands[1], QImode)) + operands[1] = copy_to_mode_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); + + if (TARGET_THUMB) + { + rtx ops[3]; + + ops[0] = operands[2]; + ops[1] = operands[1]; + ops[2] = GEN_INT (24); + + emit_insn (gen_rtx_SET (VOIDmode, ops[0], gen_rtx_ASHIFT (SImode, ops[1], ops[2]))); + + ops[0] = operands[0]; + ops[1] = operands[2]; + ops[2] = GEN_INT (24); + + emit_insn (gen_rtx_SET (VOIDmode, ops[0], gen_rtx_ASHIFTRT (SImode, ops[1], ops[2]))); + + DONE; + } + }" +) ; Rather than restricting all byte accesses to memory addresses that ldrsb ; can handle, we fix up the ones that ldrsb can't grok with a split. -(define_insn "*extendqisi_insn" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] - "arm_arch4" +(define_insn "*arm_extendqisi_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "TARGET_ARM && arm_arch4" "* /* If the address is invalid, this will split the instruction into two. */ - if (bad_signed_byte_operand (operands[1], QImode)) + if (bad_signed_byte_operand (operands[1], VOIDmode)) return \"#\"; return \"ldr%?sb\\t%0, %1\"; -" -[(set_attr "type" "load") - (set_attr "length" "8") - (set_attr "pool_range" "256")]) + " + [(set_attr "type" "load") + (set_attr "length" "8") + (set_attr "pool_range" "256") + (set_attr "neg_pool_range" "244")] +) (define_split [(set (match_operand:SI 0 "s_register_operand" "") (sign_extend:SI (match_operand:QI 1 "bad_signed_byte_operand" "")))] - "arm_arch4 && reload_completed" + "TARGET_ARM && arm_arch4 && reload_completed" [(set (match_dup 0) (match_dup 1)) (set (match_dup 0) (sign_extend:SI (match_dup 2)))] " @@ -2822,24 +3544,93 @@ } ") +(define_insn "*thumb_extendqisi2_insn" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] + "TARGET_THUMB" + "* + { + rtx ops[3]; + rtx mem = XEXP (operands[1], 0); + + if (GET_CODE (mem) == CONST) + mem = XEXP (mem, 0); + + if (GET_CODE (mem) == LABEL_REF) + return \"ldr\\t%0, %1\"; + + if (GET_CODE (mem) == PLUS + && GET_CODE (XEXP (mem, 0)) == LABEL_REF) + return \"ldr\\t%0, %1\"; + + if (which_alternative == 0) + return \"ldrsb\\t%0, %1\"; + + ops[0] = operands[0]; + + if (GET_CODE (mem) == PLUS) + { + rtx a = XEXP (mem, 0); + rtx b = XEXP (mem, 1); + + ops[1] = a; + ops[2] = b; + + if (GET_CODE (a) == REG) + { + if (GET_CODE (b) == REG) + output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); + else if (REGNO (a) == REGNO (ops[0])) + output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + else if (GET_CODE (b) != REG) + abort (); + else + { + if (REGNO (b) == REGNO (ops[0])) + output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + } + else if (GET_CODE (mem) == REG && REGNO (ops[0]) == REGNO (mem)) + { + output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + } + else + { + ops[1] = mem; + ops[2] = const0_rtx; + + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + return \"\"; + }" + [(set_attr "length" "2,6") + (set_attr "type" "load,load") + (set_attr "pool_range" "32,32")] +) + (define_insn "extendsfdf2" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")))] - "TARGET_HARD_FLOAT" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_ARM && TARGET_HARD_FLOAT" "mvf%?d\\t%0, %1" [(set_attr "type" "ffarith")]) (define_insn "extendsfxf2" [(set (match_operand:XF 0 "s_register_operand" "=f") (float_extend:XF (match_operand:SF 1 "s_register_operand" "f")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "mvf%?e\\t%0, %1" [(set_attr "type" "ffarith")]) (define_insn "extenddfxf2" [(set (match_operand:XF 0 "s_register_operand" "=f") (float_extend:XF (match_operand:DF 1 "s_register_operand" "f")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "mvf%?e\\t%0, %1" [(set_attr "type" "ffarith")]) @@ -2905,35 +3696,108 @@ ;; return \"\"; ;; }") +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "TARGET_EITHER" + " + if (TARGET_THUMB) + { + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DImode, operands[1]); + } + } + " +) -(define_insn "movdi" - [(set (match_operand:DI 0 "di_operand" "=r,r,o<>") +(define_insn "*arm_movdi" + [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r,r,o<>") (match_operand:DI 1 "di_operand" "rIK,mi,r"))] - "" + "TARGET_ARM" "* return (output_move_double (operands)); -" -[(set_attr "length" "8,8,8") - (set_attr "type" "*,load,store2") - (set_attr "pool_range" "0,1020,0")]) + " + [(set_attr "length" "8") + (set_attr "type" "*,load,store2") + (set_attr "pool_range" "*,1020,*") + (set_attr "neg_pool_range" "*,1012,*")] +) + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdf_insn pattern. +;;; ??? The 'i' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*thumb_movdi_insn" + [(set (match_operand:DI 0 "nonimmediate_operand" "=l,l,l,l,>,l,m,*r") + (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] + "TARGET_THUMB + && ( register_operand (operands[0], DImode) + || register_operand (operands[1], DImode))" + "* + { + switch (which_alternative) + { + default: + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; + case 2: + operands[1] = GEN_INT (- INTVAL (operands[1])); + return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; + case 3: + return \"ldmia\\t%1, {%0, %H0}\"; + case 4: + return \"stmia\\t%0, {%1, %H1}\"; + case 5: + return thumb_load_double_from_address (operands); + case 6: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 7: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } + }" + [(set_attr "length" "4,4,6,2,2,6,4,4") + (set_attr "type" "*,*,*,load,store2,load,store2,*") + (set_attr "pool_range" "*,*,*,*,*,1020,*,*")] +) (define_expand "movsi" [(set (match_operand:SI 0 "general_operand" "") (match_operand:SI 1 "general_operand" ""))] - "" + "TARGET_EITHER" " - /* Everything except mem = const or mem = mem can be done easily */ - if (GET_CODE (operands[0]) == MEM) - operands[1] = force_reg (SImode, operands[1]); - if (GET_CODE (operands[1]) == CONST_INT - && !(const_ok_for_arm (INTVAL (operands[1])) - || const_ok_for_arm (~INTVAL (operands[1])))) + if (TARGET_ARM) { - arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0], - NULL_RTX, - (reload_in_progress || reload_completed ? 0 - : preserve_subexpressions_p ())); - DONE; + /* Everything except mem = const or mem = mem can be done easily */ + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (SImode, operands[1]); + if (GET_CODE (operands[1]) == CONST_INT + && !(const_ok_for_arm (INTVAL (operands[1])) + || const_ok_for_arm (~INTVAL (operands[1])))) + { + arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0], + NULL_RTX, + (reload_in_progress || reload_completed ? 0 + : preserve_subexpressions_p ())); + DONE; + } + } + else /* TARGET_THUMB.... */ + { + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SImode, operands[1]); + } } if (flag_pic @@ -2946,24 +3810,28 @@ ? operands[0] : 0)); ") -(define_insn "*movsi_insn" - [(set (match_operand:SI 0 "general_operand" "=r,r,r,m") +(define_insn "*arm_movsi_insn" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,m") (match_operand:SI 1 "general_operand" "rI,K,mi,r"))] - "register_operand (operands[0], SImode) - || register_operand (operands[1], SImode)" + "TARGET_ARM + && ( register_operand (operands[0], SImode) + || register_operand (operands[1], SImode))" "@ mov%?\\t%0, %1 mvn%?\\t%0, #%B1 ldr%?\\t%0, %1 str%?\\t%1, %0" -[(set_attr "type" "*,*,load,store1") - (set_attr "pool_range" "*,*,4096,*")]) + [(set_attr "type" "*,*,load,store1") + (set_attr "pool_range" "*,*,4096,*") + (set_attr "neg_pool_range" "*,*,4084,*")] +) (define_split [(set (match_operand:SI 0 "s_register_operand" "") (match_operand:SI 1 "const_int_operand" ""))] - "! (const_ok_for_arm (INTVAL (operands[1])) - || const_ok_for_arm (~INTVAL (operands[1])))" + "TARGET_ARM + && (! ( const_ok_for_arm (INTVAL (operands[1])) + || const_ok_for_arm (~INTVAL (operands[1]))))" [(clobber (const_int 0))] " arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0], @@ -2971,22 +3839,79 @@ DONE; ") +(define_insn "*thumb_movsi_insn" + [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*lh") + (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*lh"))] + "TARGET_THUMB + && ( register_operand (operands[0], SImode) + || register_operand (operands[1], SImode))" + "@ + mov %0, %1 + mov %0, %1 + # + # + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1" + [(set_attr "length" "2,2,4,4,2,2,2,2,2") + (set_attr "type" "*,*,*,*,load,store1,load,store1,*") + (set_attr "pool_range" "*,*,*,*,*,*,1020,*,*")] +) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "TARGET_THUMB && CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'J')" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (neg:SI (match_dup 0)))] + "operands[1] = GEN_INT (- INTVAL (operands[1]));" +) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "TARGET_THUMB && CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'K')" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] + " + { + unsigned HOST_WIDE_INT val = INTVAL (operands[1]); + unsigned HOST_WIDE_INT mask = 0xff; + int i; + + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + break; + + if (i == 0) + FAIL; + + operands[1] = GEN_INT (val >> i); + operands[2] = GEN_INT (i); + }" +) + (define_expand "movaddr" [(set (match_operand:SI 0 "s_register_operand" "") (match_operand:DI 1 "address_operand" ""))] + "TARGET_ARM" "" - "") +) (define_insn "*movaddr_insn" [(set (match_operand:SI 0 "s_register_operand" "=r") (match_operand:DI 1 "address_operand" "p"))] - "reload_completed + "TARGET_ARM + && reload_completed && (GET_CODE (operands[1]) == LABEL_REF || (GET_CODE (operands[1]) == CONST && GET_CODE (XEXP (operands[1], 0)) == PLUS && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT))" - "adr%?\\t%0, %a1") + "adr%?\\t%0, %a1" +) ;; When generating pic, we need to load the symbol offset into a register. ;; So that the optimizer does not confuse this with a normal symbol load @@ -3000,58 +3925,92 @@ (define_insn "pic_load_addr" [(set (match_operand:SI 0 "s_register_operand" "=r") (unspec:SI [(match_operand:SI 1 "" "mX")] 3))] - "flag_pic" + "TARGET_EITHER && flag_pic" "ldr%?\\t%0, %1" - [(set_attr "type" "load") - (set_attr "pool_range" "4096")]) + [(set_attr "type" "load") + (set (attr "pool_range") + (if_then_else (eq_attr "is_thumb" "yes") + (const_int 1024) + (const_int 4096))) + (set (attr "neg_pool_range") + (if_then_else (eq_attr "is_thumb" "yes") + (const_int 0) + (const_int 4084)))] +) ;; This variant is used for AOF assembly, since it needs to mention the ;; pic register in the rtl. (define_expand "pic_load_addr_based" [(set (match_operand:SI 0 "s_register_operand" "=r") (unspec:SI [(match_operand 1 "" "") (match_dup 2)] 3))] - "flag_pic" - "operands[2] = pic_offset_table_rtx;") + "TARGET_ARM && flag_pic" + "operands[2] = pic_offset_table_rtx;" +) (define_insn "*pic_load_addr_based_insn" [(set (match_operand:SI 0 "s_register_operand" "=r") (unspec:SI [(match_operand 1 "" "") (match_operand 2 "s_register_operand" "r")] 3))] - "flag_pic && operands[2] == pic_offset_table_rtx" + "TARGET_EITHER && flag_pic && operands[2] == pic_offset_table_rtx" "* #ifdef AOF_ASSEMBLER operands[1] = aof_pic_entry (operands[1]); #endif output_asm_insn (\"ldr%?\\t%0, %a1\", operands); return \"\"; -" -[(set_attr "type" "load") - (set_attr "pool_range" "4096")]) + " + [(set_attr "type" "load") + (set (attr "pool_range") + (if_then_else (eq_attr "is_thumb" "yes") + (const_int 1024) + (const_int 4096))) + (set (attr "neg_pool_range") + (if_then_else (eq_attr "is_thumb" "yes") + (const_int 0) + (const_int 4084)))] +) + +(define_insn "pic_add_dot_plus_four" + [(set (match_operand:SI 0 "register_operand" "+r") + (plus:SI (match_dup 0) (const (plus:SI (pc) (const_int 4))))) + (use (label_ref (match_operand 1 "" "")))] + "TARGET_THUMB && flag_pic" + "* + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + CODE_LABEL_NUMBER (operands[1])); + return \"add\\t%0, %|pc\"; + " + [(set_attr "length" "2")] +) (define_insn "pic_add_dot_plus_eight" [(set (match_operand:SI 0 "register_operand" "+r") (plus:SI (match_dup 0) (const (plus:SI (pc) (const_int 8))))) (use (label_ref (match_operand 1 "" "")))] - "flag_pic" + "TARGET_ARM && flag_pic" "* ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (operands[1])); return \"add%?\\t%0, %|pc, %0\"; -") + " +) ;; If copying one reg to another we can set the condition codes according to ;; its value. Such a move is common after a return from subroutine and the ;; result is being tested against zero. (define_insn "*movsi_compare0" - [(set (reg:CC 24) (compare:CC (match_operand:SI 1 "s_register_operand" "0,r") - (const_int 0))) - (set (match_operand:SI 0 "s_register_operand" "=r,r") (match_dup 1))] - "" + [(set (reg:CC 24) + (compare:CC (match_operand:SI 1 "s_register_operand" "0,r") + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (match_dup 1))] + "TARGET_ARM" "@ cmp%?\\t%0, #0 sub%?s\\t%0, %1, #0" -[(set_attr "conds" "set")]) + [(set_attr "conds" "set")] +) ;; Subroutine to store a half word from a register into memory. ;; Operand 0 is the source register (HImode) @@ -3069,7 +4028,7 @@ (ashiftrt:SI (match_operand 0 "" "") (const_int 8))) ;; store the high byte (set (match_dup 4) (subreg:QI (match_dup 2) 0))] ;explicit subreg safe - "" + "TARGET_ARM" " { rtx addr = XEXP (operands[1], 0); @@ -3092,7 +4051,7 @@ (set (match_dup 2) (ashiftrt:SI (match_operand 0 "" "") (const_int 8))) (set (match_operand 1 "" "") (subreg:QI (match_dup 2) 0))] - "" + "TARGET_ARM" " { rtx addr = XEXP (operands[1], 0); @@ -3115,7 +4074,7 @@ [(set (match_operand 0 "" "") (subreg:QI (match_operand 1 "" "") 0)) (set (match_dup 3) (subreg:QI (match_dup 2) 0))] - "" + "TARGET_ARM" " { HOST_WIDE_INT value = INTVAL (operands[1]); @@ -3158,7 +4117,7 @@ (define_expand "storehi_single_op" [(set (match_operand:HI 0 "memory_operand" "") (match_operand:HI 1 "general_operand" ""))] - "arm_arch4" + "TARGET_ARM && arm_arch4" " if (! s_register_operand (operands[1], HImode)) operands[1] = copy_to_mode_reg (HImode, operands[1]); @@ -3167,161 +4126,247 @@ (define_expand "movhi" [(set (match_operand:HI 0 "general_operand" "") (match_operand:HI 1 "general_operand" ""))] - "" + "TARGET_EITHER" " -{ - if (! (reload_in_progress || reload_completed)) + if (TARGET_ARM) { - if (GET_CODE (operands[0]) == MEM) - { - if (arm_arch4) - { - emit_insn (gen_storehi_single_op (operands[0], operands[1])); - DONE; - } - if (GET_CODE (operands[1]) == CONST_INT) - emit_insn (gen_storeinthi (operands[0], operands[1])); - else + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) == MEM) { - if (GET_CODE (operands[1]) == MEM) - operands[1] = force_reg (HImode, operands[1]); - if (BYTES_BIG_ENDIAN) - emit_insn (gen_storehi_bigend (operands[1], operands[0])); + if (arm_arch4) + { + emit_insn (gen_storehi_single_op (operands[0], operands[1])); + DONE; + } + if (GET_CODE (operands[1]) == CONST_INT) + emit_insn (gen_storeinthi (operands[0], operands[1])); else - emit_insn (gen_storehi (operands[1], operands[0])); + { + if (GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (HImode, operands[1]); + if (BYTES_BIG_ENDIAN) + emit_insn (gen_storehi_bigend (operands[1], operands[0])); + else + emit_insn (gen_storehi (operands[1], operands[0])); + } + DONE; } - DONE; - } - /* Sign extend a constant, and keep it in an SImode reg. */ - else if (GET_CODE (operands[1]) == CONST_INT) - { - rtx reg = gen_reg_rtx (SImode); - HOST_WIDE_INT val = INTVAL (operands[1]) & 0xffff; - - /* If the constant is already valid, leave it alone. */ - if (! const_ok_for_arm (val)) + /* Sign extend a constant, and keep it in an SImode reg. */ + else if (GET_CODE (operands[1]) == CONST_INT) { - /* If setting all the top bits will make the constant - loadable in a single instruction, then set them. - Otherwise, sign extend the number. */ - - if (const_ok_for_arm (~ (val | ~0xffff))) - val |= ~0xffff; - else if (val & 0x8000) - val |= ~0xffff; + rtx reg = gen_reg_rtx (SImode); + HOST_WIDE_INT val = INTVAL (operands[1]) & 0xffff; + + /* If the constant is already valid, leave it alone. */ + if (! const_ok_for_arm (val)) + { + /* If setting all the top bits will make the constant + loadable in a single instruction, then set them. + Otherwise, sign extend the number. */ + + if (const_ok_for_arm (~ (val | ~0xffff))) + val |= ~0xffff; + else if (val & 0x8000) + val |= ~0xffff; + } + + emit_insn (gen_movsi (reg, GEN_INT (val))); + operands[1] = gen_rtx_SUBREG (HImode, reg, 0); } - - emit_insn (gen_movsi (reg, GEN_INT (val))); - operands[1] = gen_rtx_SUBREG (HImode, reg, 0); - } - else if (! arm_arch4) - { - /* Note: We do not have to worry about TARGET_MMU_TRAPS - for v4 and up architectures because LDRH instructions will - be used to access the HI values, and these cannot generate - unaligned word access faults in the MMU. */ - if (GET_CODE (operands[1]) == MEM) + else if (! arm_arch4) { - if (TARGET_MMU_TRAPS) - { - rtx base; - rtx offset = const0_rtx; - rtx reg = gen_reg_rtx (SImode); - - if ((GET_CODE (base = XEXP (operands[1], 0)) == REG - || (GET_CODE (base) == PLUS - && GET_CODE (offset = XEXP (base, 1)) == CONST_INT - && ((INTVAL(offset) & 1) != 1) - && GET_CODE (base = XEXP (base, 0)) == REG)) - && REGNO_POINTER_ALIGN (REGNO (base)) >= 4) - { - HOST_WIDE_INT new_offset = INTVAL (offset) & ~3; - rtx new; - - new = gen_rtx_MEM (SImode, - plus_constant (base, new_offset)); - MEM_COPY_ATTRIBUTES (new, operands[1]); - RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (operands[1]); - emit_insn (gen_movsi (reg, new)); - if (((INTVAL (offset) & 2) != 0) - ^ (BYTES_BIG_ENDIAN ? 1 : 0)) - { - rtx reg2 = gen_reg_rtx (SImode); - - emit_insn (gen_lshrsi3 (reg2, reg, GEN_INT (16))); - reg = reg2; - } - } - else - emit_insn (gen_movhi_bytes (reg, operands[1])); - - operands[1] = gen_lowpart (HImode, reg); - } - else if (BYTES_BIG_ENDIAN) - { - rtx base; - rtx offset = const0_rtx; - - if ((GET_CODE (base = XEXP (operands[1], 0)) == REG - || (GET_CODE (base) == PLUS - && GET_CODE (offset = XEXP (base, 1)) == CONST_INT - && GET_CODE (base = XEXP (base, 0)) == REG)) - && REGNO_POINTER_ALIGN (REGNO (base)) >= 4) + /* Note: We do not have to worry about TARGET_MMU_TRAPS + for v4 and up architectures because LDRH instructions will + be used to access the HI values, and these cannot generate + unaligned word access faults in the MMU. */ + if (GET_CODE (operands[1]) == MEM) + { + if (TARGET_MMU_TRAPS) { + rtx base; + rtx offset = const0_rtx; rtx reg = gen_reg_rtx (SImode); - rtx new; - - if ((INTVAL (offset) & 2) == 2) - { - HOST_WIDE_INT new_offset = INTVAL (offset) ^ 2; - new = gen_rtx_MEM (SImode, - plus_constant (base, new_offset)); - MEM_COPY_ATTRIBUTES (new, operands[1]); - RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (operands[1]); - emit_insn (gen_movsi (reg, new)); - } - else - { - new = gen_rtx_MEM (SImode, XEXP (operands[1], 0)); + + if ((GET_CODE (base = XEXP (operands[1], 0)) == REG + || (GET_CODE (base) == PLUS + && GET_CODE (offset = XEXP (base, 1)) == CONST_INT + && ((INTVAL(offset) & 1) != 1) + && GET_CODE (base = XEXP (base, 0)) == REG)) + && REGNO_POINTER_ALIGN (REGNO (base)) >= 4) + { + HOST_WIDE_INT new_offset = INTVAL (offset) & ~3; + rtx new; + + new = gen_rtx_MEM (SImode, + plus_constant (base, new_offset)); MEM_COPY_ATTRIBUTES (new, operands[1]); - RTX_UNCHANGING_P (new) - = RTX_UNCHANGING_P (operands[1]); - emit_insn (gen_rotated_loadsi (reg, new)); - } + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (operands[1]); + emit_insn (gen_movsi (reg, new)); + if (((INTVAL (offset) & 2) != 0) + ^ (BYTES_BIG_ENDIAN ? 1 : 0)) + { + rtx reg2 = gen_reg_rtx (SImode); + + emit_insn (gen_lshrsi3 (reg2, reg, GEN_INT (16))); + reg = reg2; + } + } + else + emit_insn (gen_movhi_bytes (reg, operands[1])); operands[1] = gen_lowpart (HImode, reg); } - else + else if (BYTES_BIG_ENDIAN) { - emit_insn (gen_movhi_bigend (operands[0], operands[1])); - DONE; + rtx base; + rtx offset = const0_rtx; + + if ((GET_CODE (base = XEXP (operands[1], 0)) == REG + || (GET_CODE (base) == PLUS + && GET_CODE (offset = XEXP (base, 1)) == CONST_INT + && GET_CODE (base = XEXP (base, 0)) == REG)) + && REGNO_POINTER_ALIGN (REGNO (base)) >= 4) + { + rtx reg = gen_reg_rtx (SImode); + rtx new; + + if ((INTVAL (offset) & 2) == 2) + { + HOST_WIDE_INT new_offset = INTVAL (offset) ^ 2; + new = gen_rtx_MEM (SImode, + plus_constant (base, new_offset)); + MEM_COPY_ATTRIBUTES (new, operands[1]); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (operands[1]); + emit_insn (gen_movsi (reg, new)); + } + else + { + new = gen_rtx_MEM (SImode, XEXP (operands[1], 0)); + MEM_COPY_ATTRIBUTES (new, operands[1]); + RTX_UNCHANGING_P (new) + = RTX_UNCHANGING_P (operands[1]); + emit_insn (gen_rotated_loadsi (reg, new)); + } + + operands[1] = gen_lowpart (HImode, reg); + } + else + { + emit_insn (gen_movhi_bigend (operands[0], operands[1])); + DONE; + } } - } + } + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! const_ok_for_arm (INTVAL (operands[1])) + && ! const_ok_for_arm (~INTVAL (operands[1]))) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } + } + else /* TARGET_THUMB */ + { + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (HImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); } - } + + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } } - /* Handle loading a large integer during reload */ - else if (GET_CODE (operands[1]) == CONST_INT - && ! const_ok_for_arm (INTVAL (operands[1])) - && ! const_ok_for_arm (~INTVAL (operands[1]))) + " +) + +(define_insn "*thumb_movhi_insn" + [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:HI 1 "general_operand" "l,mn,l,*h,*r,I"))] + "TARGET_THUMB + && ( register_operand (operands[0], HImode) + || register_operand (operands[1], HImode))" + "* + switch (which_alternative) { - /* Writing a constant to memory needs a scratch, which should - be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); + case 0: return \"add %0, %1, #0\"; + case 2: return \"strh %1, %0\"; + case 3: return \"mov %0, %1\"; + case 4: return \"mov %0, %1\"; + case 5: return \"mov %0, %1\"; + default: abort (); + case 1: + /* The stack pointer can end up being taken as an index register. + Catch this case here and deal with it. */ + if (GET_CODE (XEXP (operands[1], 0)) == PLUS + && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == REG + && REGNO (XEXP (XEXP (operands[1], 0), 0)) == SP_REGNUM) + { + rtx ops[2]; + ops[0] = operands[0]; + ops[1] = XEXP (XEXP (operands[1], 0), 0); + + output_asm_insn (\"mov %0, %1\", ops); + + XEXP (XEXP (operands[1], 0), 0) = operands[0]; + + } + return \"ldrh %0, %1\"; + }" + [(set_attr "length" "2,4,2,2,2,2") + (set_attr "type" "*,load,store1,*,*,*") + (set_attr "pool_range" "*,64,*,*,*,*")] +) - operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0); - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } -} -") (define_insn "rotated_loadsi" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "=r") (rotate:SI (match_operand:SI 1 "offsettable_memory_operand" "o") (const_int 16)))] - "! TARGET_MMU_TRAPS" + "TARGET_ARM && (! TARGET_MMU_TRAPS)" "* { rtx ops[2]; @@ -3330,8 +4375,9 @@ ops[1] = gen_rtx_MEM (SImode, plus_constant (XEXP (operands[1], 0), 2)); output_asm_insn (\"ldr%?\\t%0, %1\\t%@ load-rotate\", ops); return \"\"; -}" -[(set_attr "type" "load")]) + }" + [(set_attr "type" "load")] +) (define_expand "movhi_bytes" [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" ""))) @@ -3339,7 +4385,7 @@ (zero_extend:SI (match_dup 6))) (set (match_operand:SI 0 "" "") (ior:SI (ashift:SI (match_dup 4) (const_int 8)) (match_dup 5)))] - "" + "TARGET_ARM" " { rtx mem1, mem2; @@ -3378,7 +4424,7 @@ (ashiftrt:SI (match_dup 2) (const_int 16))) (set (match_operand:HI 0 "s_register_operand" "") (subreg:HI (match_dup 3) 0))] - "" + "TARGET_ARM" " operands[2] = gen_reg_rtx (SImode); operands[3] = gen_reg_rtx (SImode); @@ -3386,24 +4432,28 @@ ;; Pattern to recognise insn generated default case above (define_insn "*movhi_insn_arch4" - [(set (match_operand:HI 0 "general_operand" "=r,r,r,m") - (match_operand:HI 1 "general_operand" "rI,K,m,r"))] - "arm_arch4 + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,r") + (match_operand:HI 1 "general_operand" "rI,K,r,m"))] + "TARGET_ARM + && arm_arch4 && (GET_CODE (operands[1]) != CONST_INT || const_ok_for_arm (INTVAL (operands[1])) || const_ok_for_arm (~INTVAL (operands[1])))" "@ mov%?\\t%0, %1\\t%@ movhi mvn%?\\t%0, #%B1\\t%@ movhi - ldr%?h\\t%0, %1\\t%@ movhi - str%?h\\t%1, %0\\t%@ movhi" -[(set_attr "type" "*,*,load,store1") - (set_attr "pool_range" "*,*,256,*")]) + str%?h\\t%1, %0\\t%@ movhi + ldr%?h\\t%0, %1\\t%@ movhi" + [(set_attr "type" "*,*,store1,load") + (set_attr "pool_range" "*,*,*,256") + (set_attr "neg_pool_range" "*,*,*,244")] +) (define_insn "*movhi_insn_littleend" [(set (match_operand:HI 0 "s_register_operand" "=r,r,r") (match_operand:HI 1 "general_operand" "rI,K,m"))] - "! arm_arch4 + "TARGET_ARM + && ! arm_arch4 && ! BYTES_BIG_ENDIAN && ! TARGET_MMU_TRAPS && (GET_CODE (operands[1]) != CONST_INT @@ -3413,13 +4463,16 @@ mov%?\\t%0, %1\\t%@ movhi mvn%?\\t%0, #%B1\\t%@ movhi ldr%?\\t%0, %1\\t%@ movhi" -[(set_attr "type" "*,*,load") - (set_attr "pool_range" "4096")]) + [(set_attr "type" "*,*,load") + (set_attr "pool_range" "4096") + (set_attr "neg_pool_range" "4084")] +) (define_insn "*movhi_insn_bigend" [(set (match_operand:HI 0 "s_register_operand" "=r,r,r") - (match_operand:HI 1 "general_operand" "rI,K,m"))] - "! arm_arch4 + (match_operand:HI 1 "general_operand" "rI,K,m"))] + "TARGET_ARM + && ! arm_arch4 && BYTES_BIG_ENDIAN && ! TARGET_MMU_TRAPS && (GET_CODE (operands[1]) != CONST_INT @@ -3429,98 +4482,213 @@ mov%?\\t%0, %1\\t%@ movhi mvn%?\\t%0, #%B1\\t%@ movhi ldr%?\\t%0, %1\\t%@ movhi_bigend\;mov%?\\t%0, %0, asr #16" -[(set_attr "type" "*,*,load") - (set_attr "length" "4,4,8") - (set_attr "pool_range" "*,*,4092")]) + [(set_attr "type" "*,*,load") + (set_attr "length" "4,4,8") + (set_attr "pool_range" "*,*,4092") + (set_attr "neg_pool_range" "*,*,4084")] +) (define_insn "*loadhi_si_bigend" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0) + [(set (match_operand:SI 0 "s_register_operand" "=r") + (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0) (const_int 16)))] - "BYTES_BIG_ENDIAN + "TARGET_ARM + && BYTES_BIG_ENDIAN && ! TARGET_MMU_TRAPS" "ldr%?\\t%0, %1\\t%@ movhi_bigend" -[(set_attr "type" "load") - (set_attr "pool_range" "4096")]) + [(set_attr "type" "load") + (set_attr "pool_range" "4096") + (set_attr "neg_pool_range" "4084")] +) (define_insn "*movhi_bytes" [(set (match_operand:HI 0 "s_register_operand" "=r,r") (match_operand:HI 1 "arm_rhs_operand" "rI,K"))] - "TARGET_MMU_TRAPS" + "TARGET_ARM && TARGET_MMU_TRAPS" "@ mov%?\\t%0, %1\\t%@ movhi mvn%?\\t%0, #%B1\\t%@ movhi") +(define_insn "thumb_movhi_clobber" + [(set (match_operand:HI 0 "memory_operand" "=m") + (match_operand:HI 1 "register_operand" "l")) + (clobber (match_operand:SI 2 "register_operand" "=&l"))] + "TARGET_THUMB" + "Hi Nick" +) + ;; We use a DImode scratch because we may occasionally need an additional ;; temporary if the address isn't offsettable -- push_reload doesn't seem ;; to take any notice of the "o" constraints on reload_memory_operand operand. (define_expand "reload_outhi" - [(parallel [(match_operand:HI 0 "reload_memory_operand" "=o") - (match_operand:HI 1 "s_register_operand" "r") - (match_operand:DI 2 "s_register_operand" "=&r")])] - "" - " - arm_reload_out_hi (operands); + [(parallel [(match_operand:HI 0 "arm_reload_memory_operand" "=o") + (match_operand:HI 1 "s_register_operand" "r") + (match_operand:DI 2 "s_register_operand" "=&l")])] + "TARGET_EITHER" + "if (TARGET_ARM) + arm_reload_out_hi (operands); + else + thumb_reload_out_hi (operands); DONE; -") + " +) (define_expand "reload_inhi" [(parallel [(match_operand:HI 0 "s_register_operand" "=r") - (match_operand:HI 1 "reload_memory_operand" "o") + (match_operand:HI 1 "arm_reload_memory_operand" "o") (match_operand:DI 2 "s_register_operand" "=&r")])] - "TARGET_MMU_TRAPS" + "TARGET_THUMB || (TARGET_ARM && TARGET_MMU_TRAPS)" " - arm_reload_in_hi (operands); + if (TARGET_ARM) + arm_reload_in_hi (operands); + else + thumb_reload_out_hi (operands); DONE; ") (define_expand "movqi" [(set (match_operand:QI 0 "general_operand" "") (match_operand:QI 1 "general_operand" ""))] - "" + "TARGET_EITHER" " - /* Everything except mem = const or mem = mem can be done easily */ - - if (!(reload_in_progress || reload_completed)) + if (TARGET_ARM) { - if (GET_CODE (operands[1]) == CONST_INT) - { - rtx reg = gen_reg_rtx (SImode); + /* Everything except mem = const or mem = mem can be done easily */ - emit_insn (gen_movsi (reg, operands[1])); - operands[1] = gen_rtx_SUBREG (QImode, reg, 0); - } - if (GET_CODE (operands[0]) == MEM) - operands[1] = force_reg (QImode, operands[1]); + if (!(reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[1]) == CONST_INT) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (reg, operands[1])); + operands[1] = gen_rtx_SUBREG (QImode, reg, 0); + } + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (QImode, operands[1]); + } } -") + else /* TARGET_THUMB */ + { + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (QImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } + } + " +) -(define_insn "*movqi_insn" - [(set (match_operand:QI 0 "general_operand" "=r,r,r,m") +(define_insn "*arm_movqi_insn" + [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m") (match_operand:QI 1 "general_operand" "rI,K,m,r"))] - "register_operand (operands[0], QImode) - || register_operand (operands[1], QImode)" + "TARGET_ARM + && ( register_operand (operands[0], QImode) + || register_operand (operands[1], QImode))" "@ mov%?\\t%0, %1 mvn%?\\t%0, #%B1 ldr%?b\\t%0, %1 str%?b\\t%1, %0" -[(set_attr "type" "*,*,load,store1")]) + [(set_attr "type" "*,*,load,store1")] +) + +(define_insn "*thumb_movqi_insn" + [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] + "TARGET_THUMB + && ( register_operand (operands[0], QImode) + || register_operand (operands[1], QImode))" + "@ + add\\t%0, %1, #0 + ldrb\\t%0, %1 + strb\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1" + [(set_attr "length" "2") + (set_attr "type" "*,load,store1,*,*,*") + (set_attr "pool_range" "*,32,*,*,*,*")] +) (define_expand "movsf" [(set (match_operand:SF 0 "general_operand" "") (match_operand:SF 1 "general_operand" ""))] - "" + "TARGET_EITHER" " - if (GET_CODE (operands[0]) == MEM) - operands[1] = force_reg (SFmode, operands[1]); + if (TARGET_ARM) + { + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (SFmode, operands[1]); + } + else /* TARGET_THUMB */ + { + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SFmode, operands[1]); + } + } + " +) + +(define_split + [(set (match_operand:SF 0 "nonimmediate_operand" "") + (match_operand:SF 1 "immediate_operand" ""))] + "TARGET_ARM + && ! TARGET_HARD_FLOAT + && reload_completed + && GET_CODE (operands[1]) == CONST_DOUBLE" + [(set (match_dup 2) (match_dup 3))] + " + operands[2] = gen_lowpart (SImode, operands[0]); + operands[3] = gen_lowpart (SImode, operands[1]); + if (operands[2] == 0 || operands[3] == 0) + FAIL; ") -(define_insn "*movsf_hard_insn" - [(set (match_operand:SF 0 "general_operand" "=f,f,f,m,f,r,r,r,m") +(define_insn "*arm_movsf_hard_insn" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,f,r,r,r,m") (match_operand:SF 1 "general_operand" "fG,H,mE,f,r,f,r,mE,r"))] - "TARGET_HARD_FLOAT + "TARGET_ARM + && TARGET_HARD_FLOAT && (GET_CODE (operands[0]) != MEM || register_operand (operands[1], SFmode))" "@ mvf%?s\\t%0, %1 @@ -3532,44 +4700,81 @@ mov%?\\t%0, %1 ldr%?\\t%0, %1\\t%@ float str%?\\t%1, %0\\t%@ float" -[(set_attr "length" "4,4,4,4,8,8,4,4,4") - (set_attr "type" + [(set_attr "length" "4,4,4,4,8,8,4,4,4") + (set_attr "type" "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*,load,store1") - (set_attr "pool_range" "*,*,1024,*,*,*,*,4096,*")]) + (set_attr "pool_range" "*,*,1024,*,*,*,*,4096,*") + (set_attr "neg_pool_range" "*,*,1012,*,*,*,*,4084,*")] +) ;; Exactly the same as above, except that all `f' cases are deleted. ;; This is necessary to prevent reload from ever trying to use a `f' reg ;; when -msoft-float. -(define_insn "*movsf_soft_insn" - [(set (match_operand:SF 0 "general_operand" "=r,r,m") - (match_operand:SF 1 "general_operand" "r,mE,r"))] - "TARGET_SOFT_FLOAT +(define_insn "*arm_movsf_soft_insn" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m") + (match_operand:SF 1 "general_operand" "r,mE,r"))] + "TARGET_ARM + && TARGET_SOFT_FLOAT && (GET_CODE (operands[0]) != MEM || register_operand (operands[1], SFmode))" "@ mov%?\\t%0, %1 ldr%?\\t%0, %1\\t%@ float str%?\\t%1, %0\\t%@ float" -[(set_attr "length" "4,4,4") - (set_attr "type" "*,load,store1") - (set_attr "pool_range" "*,4096,*")]) + [(set_attr "length" "4,4,4") + (set_attr "type" "*,load,store1") + (set_attr "pool_range" "*,4096,*") + (set_attr "neg_pool_range" "*,4084,*")] +) + +;;; ??? This should have alternatives for constants. +(define_insn "*thumb_movsf_insn" + [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") + (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] + "TARGET_THUMB + && ( register_operand (operands[0], SFmode) + || register_operand (operands[1], SFmode))" + "@ + add\\t%0, %1, #0 + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1" + [(set_attr "length" "2") + (set_attr "type" "*,load,store1,load,store1,*,*") + (set_attr "pool_range" "*,*,*,1020,*,*,*")] +) (define_expand "movdf" [(set (match_operand:DF 0 "general_operand" "") (match_operand:DF 1 "general_operand" ""))] - "" + "TARGET_EITHER" " - if (GET_CODE (operands[0]) == MEM) - operands[1] = force_reg (DFmode, operands[1]); -") + if (TARGET_ARM) + { + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (DFmode, operands[1]); + } + else /* TARGET_THUMB */ + { + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DFmode, operands[1]); + } + } + " +) ;; Reloading a df mode value stored in integer regs to memory can require a ;; scratch reg. (define_expand "reload_outdf" - [(match_operand:DF 0 "reload_memory_operand" "=o") + [(match_operand:DF 0 "arm_reload_memory_operand" "=o") (match_operand:DF 1 "s_register_operand" "r") (match_operand:SI 2 "s_register_operand" "=&r")] - "" + "TARGET_ARM" " { enum rtx_code code = GET_CODE (XEXP (operands[0], 0)); @@ -3606,13 +4811,14 @@ ") (define_insn "*movdf_hard_insn" - [(set (match_operand:DF 0 "general_operand" "=r,Q,r,m,r,f,f,f,m,!f,!r") + [(set (match_operand:DF 0 "nonimmediate_operand" "=r,Q,r,m,r,f,f,f,m,!f,!r") (match_operand:DF 1 "general_operand" "Q,r,r,r,mF,fG,H,mF,f,r,f"))] - "TARGET_HARD_FLOAT + "TARGET_ARM + && TARGET_HARD_FLOAT && (GET_CODE (operands[0]) != MEM || register_operand (operands[1], DFmode))" "* -{ + { switch (which_alternative) { default: @@ -3626,39 +4832,83 @@ case 9: return output_mov_double_fpu_from_arm (operands); case 10: return output_mov_double_arm_from_fpu (operands); } -} -" -[(set_attr "length" "4,4,8,8,8,4,4,4,4,8,8") - (set_attr "type" -"load,store2,*,store2,load,ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r") - (set_attr "pool_range" "*,*,*,*,252,*,*,1024,*,*,*")]) + } + " + [(set_attr "length" "4,4,8,8,8,4,4,4,4,8,8") + (set_attr "type" + "load,store2,*,store2,load,ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r") + (set_attr "pool_range" "*,*,*,*,252,*,*,1024,*,*,*") + (set_attr "neg_pool_range" "*,*,*,*,244,*,*,1012,*,*,*")] +) ;; Software floating point version. This is essentially the same as movdi. ;; Do not use `f' as a constraint to prevent reload from ever trying to use ;; an `f' reg. (define_insn "*movdf_soft_insn" - [(set (match_operand:DF 0 "soft_df_operand" "=r,r,m") + [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=r,r,m") (match_operand:DF 1 "soft_df_operand" "r,mF,r"))] - "TARGET_SOFT_FLOAT" + "TARGET_ARM && TARGET_SOFT_FLOAT" "* return output_move_double (operands);" -[(set_attr "length" "8,8,8") - (set_attr "type" "*,load,store2") - (set_attr "pool_range" "252")]) + [(set_attr "length" "8,8,8") + (set_attr "type" "*,load,store2") + (set_attr "pool_range" "252") + (set_attr "neg_pool_range" "244")] +) + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdi_insn pattern. +;;; ??? The 'F' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*thumb_movdf_insn" + [(set (match_operand:DF 0 "nonimmediate_operand" "=l,l,>,l,m,*r") + (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] + "TARGET_THUMB + && ( register_operand (operands[0], DFmode) + || register_operand (operands[1], DFmode))" + "* + switch (which_alternative) + { + default: + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"ldmia\\t%1, {%0, %H0}\"; + case 2: + return \"stmia\\t%0, {%1, %H1}\"; + case 3: + return thumb_load_double_from_address (operands); + case 4: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 5: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } + " + [(set_attr "length" "4,2,2,6,4,4") + (set_attr "type" "*,load,store2,load,store2,*") + (set_attr "pool_range" "*,*,*,1020,*,*")] +) + (define_expand "movxf" [(set (match_operand:XF 0 "general_operand" "") (match_operand:XF 1 "general_operand" ""))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "") ;; Even when the XFmode patterns aren't enabled, we enable this after ;; reloading so that we can push floating point registers in the prologue. (define_insn "*movxf_hard_insn" - [(set (match_operand:XF 0 "general_operand" "=f,f,f,m,f,r,r") + [(set (match_operand:XF 0 "nonimmediate_operand" "=f,f,f,m,f,r,r") (match_operand:XF 1 "general_operand" "fG,H,m,f,r,f,r"))] - "TARGET_HARD_FLOAT && (ENABLE_XF_PATTERNS || reload_completed)" + "TARGET_ARM && TARGET_HARD_FLOAT && (ENABLE_XF_PATTERNS || reload_completed)" "* switch (which_alternative) { @@ -3671,10 +4921,12 @@ case 5: return output_mov_long_double_arm_from_fpu (operands); case 6: return output_mov_long_double_arm_from_arm (operands); } -" -[(set_attr "length" "4,4,4,4,8,8,12") - (set_attr "type" "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*") - (set_attr "pool_range" "*,*,1024,*,*,*,*")]) + " + [(set_attr "length" "4,4,4,4,8,8,12") + (set_attr "type" "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*") + (set_attr "pool_range" "*,*,1024,*,*,*,*") + (set_attr "neg_pool_range" "*,*,1012,*,*,*,*")] +) ;; load- and store-multiple insns @@ -3685,7 +4937,7 @@ [(match_par_dup 3 [(set (match_operand:SI 0 "" "") (match_operand:SI 1 "" "")) (use (match_operand:SI 2 "" ""))])] - "" + "TARGET_ARM" " /* Support only fixed point registers */ if (GET_CODE (operands[2]) != CONST_INT @@ -3714,7 +4966,7 @@ (match_operand:SI 2 "const_int_operand" "n"))) (set (match_operand:SI 3 "s_register_operand" "=r") (mem:SI (match_dup 1)))])] - "(INTVAL (operands[2]) == 4 * (XVECLEN (operands[0], 0) - 2))" + "TARGET_ARM && (INTVAL (operands[2]) == 4 * (XVECLEN (operands[0], 0) - 2))" "* { rtx ops[3]; @@ -3736,7 +4988,7 @@ [(match_parallel 0 "load_multiple_operation" [(set (match_operand:SI 1 "s_register_operand" "=r") (mem:SI (match_operand:SI 2 "s_register_operand" "r")))])] - "" + "TARGET_ARM" "* { rtx ops[3]; @@ -3756,7 +5008,7 @@ [(match_par_dup 3 [(set (match_operand:SI 0 "" "") (match_operand:SI 1 "" "")) (use (match_operand:SI 2 "" ""))])] - "" + "TARGET_ARM" " /* Support only fixed point registers */ if (GET_CODE (operands[2]) != CONST_INT @@ -3785,26 +5037,27 @@ (match_operand:SI 2 "const_int_operand" "n"))) (set (mem:SI (match_dup 1)) (match_operand:SI 3 "s_register_operand" "r"))])] - "(INTVAL (operands[2]) == 4 * (XVECLEN (operands[0], 0) - 2))" + "TARGET_ARM && (INTVAL (operands[2]) == 4 * (XVECLEN (operands[0], 0) - 2))" "* -{ - rtx ops[3]; - int count = XVECLEN (operands[0], 0); + { + rtx ops[3]; + int count = XVECLEN (operands[0], 0); - ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0); - ops[1] = SET_SRC (XVECEXP (operands[0], 0, 1)); - ops[2] = SET_SRC (XVECEXP (operands[0], 0, count - 2)); + ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_SRC (XVECEXP (operands[0], 0, 1)); + ops[2] = SET_SRC (XVECEXP (operands[0], 0, count - 2)); - output_asm_insn (\"stm%?ia\\t%0!, {%1-%2}\\t%@ str multiple\", ops); - return \"\"; -} -" -[(set (attr "type") - (cond [(eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 4)) - (const_string "store2") - (eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 5)) - (const_string "store3")] - (const_string "store4")))]) + output_asm_insn (\"stm%?ia\\t%0!, {%1-%2}\\t%@ str multiple\", ops); + return \"\"; + } + " + [(set (attr "type") + (cond [(eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 4)) + (const_string "store2") + (eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 5)) + (const_string "store3")] + (const_string "store4")))] +) ;; Ordinary store multiple @@ -3812,26 +5065,27 @@ [(match_parallel 0 "store_multiple_operation" [(set (mem:SI (match_operand:SI 2 "s_register_operand" "r")) (match_operand:SI 1 "s_register_operand" "r"))])] - "" + "TARGET_ARM" "* -{ - rtx ops[3]; - int count = XVECLEN (operands[0], 0); + { + rtx ops[3]; + int count = XVECLEN (operands[0], 0); - ops[0] = XEXP (SET_DEST (XVECEXP (operands[0], 0, 0)), 0); - ops[1] = SET_SRC (XVECEXP (operands[0], 0, 0)); - ops[2] = SET_SRC (XVECEXP (operands[0], 0, count - 1)); + ops[0] = XEXP (SET_DEST (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_SRC (XVECEXP (operands[0], 0, 0)); + ops[2] = SET_SRC (XVECEXP (operands[0], 0, count - 1)); - output_asm_insn (\"stm%?ia\\t%0, {%1-%2}\\t%@ str multiple\", ops); - return \"\"; -} -" -[(set (attr "type") - (cond [(eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 3)) - (const_string "store2") - (eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 4)) - (const_string "store3")] - (const_string "store4")))]) + output_asm_insn (\"stm%?ia\\t%0, {%1-%2}\\t%@ str multiple\", ops); + return \"\"; + } + " + [(set (attr "type") + (cond [(eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 3)) + (const_string "store2") + (eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 4)) + (const_string "store3")] + (const_string "store4")))] +) ;; Move a block of memory if it is word aligned and MORE than 2 words long. ;; We could let this apply for blocks of less than this, but it clobbers so @@ -3842,32 +5096,157 @@ (match_operand:BLK 1 "general_operand" "") (match_operand:SI 2 "const_int_operand" "") (match_operand:SI 3 "const_int_operand" "")] - "" + "TARGET_EITHER" " - if (arm_gen_movstrqi (operands)) - DONE; - FAIL; -") + if (TARGET_ARM) + { + if (arm_gen_movstrqi (operands)) + DONE; + FAIL; + } + else /* TARGET_THUMB */ + { + if ( INTVAL (operands[3]) != 4 + || INTVAL (operands[2]) > 48) + FAIL; + + thumb_expand_movstrqi (operands); + DONE; + } + " +) + +;; Block-move insns + +(define_insn "movmem12b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l")) + (clobber (match_scratch:SI 4 "=&l"))] + "TARGET_THUMB" + "* return thumb_output_move_mem_multiple (3, operands);" + [(set_attr "length" "4") +;; This isn't entirely accurate... It loads as well, but in terms of +;; scheduling the following insn it is better to consider it as a store + (set_attr "type" "store3")] +) + +(define_insn "movmem8b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l"))] + "TARGET_THUMB" + "* return thumb_output_move_mem_multiple (2, operands);" + [(set_attr "length" "4") +;; This isn't entirely accurate... It loads as well, but in terms of +;; scheduling the following insn it is better to consider it as a store + (set_attr "type" "store2")] +) + +;; Comapre & branch insns + +(define_insn "cbranchsi4" + [(set (pc) + (if_then_else + (match_operator 0 "comparison_operator" + [(match_operand:SI 1 "register_operand" "l,r") + (match_operand:SI 2 "nonmemory_operand" "rI,r")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_THUMB" + "* + output_asm_insn (\"cmp\\t%1, %2\", operands); + switch (get_attr_length (insn)) + { + case 4: return \"b%d0\\t%l3\"; + case 6: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; + } + " + [(set (attr "far_jump") + (if_then_else + (eq_attr "length" "8") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -250)) + (le (minus (match_dup 3) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) + (le (minus (match_dup 3) (pc)) (const_int 2054))) + (const_int 6) + (const_int 8))))] +) + +(define_insn "*negated_cbranchsi4" + [(set (pc) + (if_then_else + (match_operator 0 "comparison_operator" + [(match_operand:SI 1 "register_operand" "l") + (neg:SI (match_operand:SI 2 "nonmemory_operand" "l"))]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_THUMB" + "* + output_asm_insn (\"cmn\\t%1, %2\", operands); + switch (get_attr_length (insn)) + { + case 4: return \"b%d0\\t%l3\"; + case 6: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; + } + " + [(set (attr "far_jump") + (if_then_else + (eq_attr "length" "8") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -250)) + (le (minus (match_dup 3) (pc)) (const_int 254))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -2044)) + (le (minus (match_dup 3) (pc)) (const_int 2044))) + (const_int 6) + (const_int 8))))] +) + + ;; Comparison and test insns (define_expand "cmpsi" [(match_operand:SI 0 "s_register_operand" "") (match_operand:SI 1 "arm_add_operand" "")] - "" - " -{ - arm_compare_op0 = operands[0]; - arm_compare_op1 = operands[1]; - DONE; -} -") + "TARGET_ARM" + "{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + DONE; + }" +) (define_expand "cmpsf" [(match_operand:SF 0 "s_register_operand" "") (match_operand:SF 1 "fpu_rhs_operand" "")] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" " { arm_compare_op0 = operands[0]; @@ -3879,7 +5258,7 @@ (define_expand "cmpdf" [(match_operand:DF 0 "s_register_operand" "") (match_operand:DF 1 "fpu_rhs_operand" "")] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" " { arm_compare_op0 = operands[0]; @@ -3891,32 +5270,32 @@ (define_expand "cmpxf" [(match_operand:XF 0 "s_register_operand" "") (match_operand:XF 1 "fpu_rhs_operand" "")] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - " -{ - arm_compare_op0 = operands[0]; - arm_compare_op1 = operands[1]; - DONE; -} -") + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + DONE; + }" +) -(define_insn "*cmpsi_insn" +(define_insn "*arm_cmpsi_insn" [(set (reg:CC 24) (compare:CC (match_operand:SI 0 "s_register_operand" "r,r") - (match_operand:SI 1 "arm_add_operand" "rI,L")))] - "" + (match_operand:SI 1 "arm_add_operand" "rI,L")))] + "TARGET_ARM" "@ cmp%?\\t%0, %1 cmn%?\\t%0, #%n1" -[(set_attr "conds" "set")]) + [(set_attr "conds" "set")] +) (define_insn "*cmpsi_shiftsi" [(set (reg:CC 24) - (compare:CC (match_operand:SI 0 "s_register_operand" "r") - (match_operator:SI 3 "shift_operator" + (compare:CC (match_operand:SI 0 "s_register_operand" "r") + (match_operator:SI 3 "shift_operator" [(match_operand:SI 1 "s_register_operand" "r") - (match_operand:SI 2 "arm_rhs_operand" "rM")])))] - "" + (match_operand:SI 2 "arm_rhs_operand" "rM")])))] + "TARGET_ARM" "cmp%?\\t%0, %1%S3" [(set_attr "conds" "set") ]) @@ -3927,7 +5306,7 @@ [(match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "reg_or_int_operand" "rM")]) (match_operand:SI 0 "s_register_operand" "r")))] - "" + "TARGET_ARM" "cmp%?\\t%0, %1%S3" [(set_attr "conds" "set") ]) @@ -3938,7 +5317,7 @@ (neg:SI (match_operator:SI 3 "shift_operator" [(match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "arm_rhs_operand" "rM")]))))] - "" + "TARGET_ARM" "cmn%?\\t%0, %1%S3" [(set_attr "conds" "set") ]) @@ -3947,7 +5326,7 @@ [(set (reg:CCFP 24) (compare:CCFP (match_operand:SF 0 "s_register_operand" "f,f") (match_operand:SF 1 "fpu_add_operand" "fG,H")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "@ cmf%?\\t%0, %1 cnf%?\\t%0, #%N1" @@ -3958,7 +5337,7 @@ [(set (reg:CCFP 24) (compare:CCFP (match_operand:DF 0 "s_register_operand" "f,f") (match_operand:DF 1 "fpu_add_operand" "fG,H")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "@ cmf%?\\t%0, %1 cnf%?\\t%0, #%N1" @@ -3970,7 +5349,7 @@ (compare:CCFP (float_extend:DF (match_operand:SF 0 "s_register_operand" "f,f")) (match_operand:DF 1 "fpu_add_operand" "fG,H")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "@ cmf%?\\t%0, %1 cnf%?\\t%0, #%N1" @@ -3982,7 +5361,7 @@ (compare:CCFP (match_operand:DF 0 "s_register_operand" "f") (float_extend:DF (match_operand:SF 1 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "cmf%?\\t%0, %1" [(set_attr "conds" "set") (set_attr "type" "f_2_r")]) @@ -3991,7 +5370,7 @@ [(set (reg:CCFP 24) (compare:CCFP (match_operand:XF 0 "s_register_operand" "f,f") (match_operand:XF 1 "fpu_add_operand" "fG,H")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "@ cmf%?\\t%0, %1 cnf%?\\t%0, #%N1" @@ -4002,7 +5381,7 @@ [(set (reg:CCFPE 24) (compare:CCFPE (match_operand:SF 0 "s_register_operand" "f,f") (match_operand:SF 1 "fpu_add_operand" "fG,H")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "@ cmf%?e\\t%0, %1 cnf%?e\\t%0, #%N1" @@ -4013,7 +5392,7 @@ [(set (reg:CCFPE 24) (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f,f") (match_operand:DF 1 "fpu_add_operand" "fG,H")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "@ cmf%?e\\t%0, %1 cnf%?e\\t%0, #%N1" @@ -4025,7 +5404,7 @@ (compare:CCFPE (float_extend:DF (match_operand:SF 0 "s_register_operand" "f,f")) (match_operand:DF 1 "fpu_add_operand" "fG,H")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "@ cmf%?e\\t%0, %1 cnf%?e\\t%0, #%N1" @@ -4037,7 +5416,7 @@ (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f") (float_extend:DF (match_operand:SF 1 "s_register_operand" "f"))))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "cmf%?e\\t%0, %1" [(set_attr "conds" "set") (set_attr "type" "f_2_r")]) @@ -4046,7 +5425,7 @@ [(set (reg:CCFPE 24) (compare:CCFPE (match_operand:XF 0 "s_register_operand" "f,f") (match_operand:XF 1 "fpu_add_operand" "fG,H")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" "@ cmf%?e\\t%0, %1 cnf%?e\\t%0, #%N1" @@ -4061,10 +5440,11 @@ (define_insn "*deleted_compare" [(set (match_operand 0 "cc_register" "") (match_dup 0))] - "" + "TARGET_ARM" "\\t%@ deleted compare" -[(set_attr "conds" "set") - (set_attr "length" "0")]) + [(set_attr "conds" "set") + (set_attr "length" "0")] +) ;; Conditional branch insns @@ -4074,162 +5454,129 @@ (if_then_else (eq (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1);" +) (define_expand "bne" [(set (pc) (if_then_else (ne (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (NE, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (NE, arm_compare_op0, arm_compare_op1);" +) (define_expand "bgt" [(set (pc) (if_then_else (gt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (GT, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (GT, arm_compare_op0, arm_compare_op1);" +) (define_expand "ble" [(set (pc) (if_then_else (le (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (LE, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (LE, arm_compare_op0, arm_compare_op1);" +) (define_expand "bge" [(set (pc) (if_then_else (ge (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (GE, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (GE, arm_compare_op0, arm_compare_op1);" +) (define_expand "blt" [(set (pc) (if_then_else (lt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (LT, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (LT, arm_compare_op0, arm_compare_op1);" +) (define_expand "bgtu" [(set (pc) (if_then_else (gtu (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1);" +) (define_expand "bleu" [(set (pc) (if_then_else (leu (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1);" +) (define_expand "bgeu" [(set (pc) (if_then_else (geu (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1);" +) (define_expand "bltu" [(set (pc) (if_then_else (ltu (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1);" +) ;; patterns to match conditional branch insns -(define_insn "*condbranch" +(define_insn "*arm_cond_branch" [(set (pc) (if_then_else (match_operator 1 "comparison_operator" [(match_operand 2 "cc_register" "") (const_int 0)]) (label_ref (match_operand 0 "" "")) (pc)))] - "" + "TARGET_ARM" "* -{ - extern int arm_ccfsm_state; - if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) - { - arm_ccfsm_state += 2; - return \"\"; - } + { + arm_ccfsm_state += 2; + return \"\"; + } return \"b%d1\\t%l0\"; -}" -[(set_attr "conds" "use")]) + " + [(set_attr "conds" "use")] +) -(define_insn "*condbranch_reversed" +(define_insn "*arm_cond_branch_reversed" [(set (pc) (if_then_else (match_operator 1 "comparison_operator" [(match_operand 2 "cc_register" "") (const_int 0)]) (pc) (label_ref (match_operand 0 "" ""))))] - "" + "TARGET_ARM" "* -{ - extern int arm_ccfsm_state; - if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) - { - arm_ccfsm_state += 2; - return \"\"; - } + { + arm_ccfsm_state += 2; + return \"\"; + } return \"b%D1\\t%l0\"; -}" -[(set_attr "conds" "use")]) + " + [(set_attr "conds" "use")] +) + ; scc insns @@ -4237,129 +5584,102 @@ (define_expand "seq" [(set (match_operand:SI 0 "s_register_operand" "=r") (eq:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1);" +) (define_expand "sne" [(set (match_operand:SI 0 "s_register_operand" "=r") (ne:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (NE, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (NE, arm_compare_op0, arm_compare_op1);" +) (define_expand "sgt" [(set (match_operand:SI 0 "s_register_operand" "=r") (gt:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (GT, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (GT, arm_compare_op0, arm_compare_op1);" +) (define_expand "sle" [(set (match_operand:SI 0 "s_register_operand" "=r") (le:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (LE, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (LE, arm_compare_op0, arm_compare_op1);" +) (define_expand "sge" [(set (match_operand:SI 0 "s_register_operand" "=r") (ge:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (GE, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (GE, arm_compare_op0, arm_compare_op1);" +) (define_expand "slt" [(set (match_operand:SI 0 "s_register_operand" "=r") (lt:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (LT, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (LT, arm_compare_op0, arm_compare_op1);" +) (define_expand "sgtu" [(set (match_operand:SI 0 "s_register_operand" "=r") (gtu:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1);" +) (define_expand "sleu" [(set (match_operand:SI 0 "s_register_operand" "=r") (leu:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1);" +) (define_expand "sgeu" [(set (match_operand:SI 0 "s_register_operand" "=r") (geu:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1);" +) (define_expand "sltu" [(set (match_operand:SI 0 "s_register_operand" "=r") (ltu:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1); -} -") + "TARGET_ARM" + "operands[1] = arm_gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1);" +) (define_insn "*mov_scc" [(set (match_operand:SI 0 "s_register_operand" "=r") (match_operator:SI 1 "comparison_operator" [(match_operand 2 "cc_register" "") (const_int 0)]))] - "" + "TARGET_ARM" "mov%D1\\t%0, #0\;mov%d1\\t%0, #1" -[(set_attr "conds" "use") - (set_attr "length" "8")]) + [(set_attr "conds" "use") + (set_attr "length" "8")] +) (define_insn "*mov_negscc" [(set (match_operand:SI 0 "s_register_operand" "=r") (neg:SI (match_operator:SI 1 "comparison_operator" [(match_operand 2 "cc_register" "") (const_int 0)])))] - "" + "TARGET_ARM" "mov%D1\\t%0, #0\;mvn%d1\\t%0, #0" -[(set_attr "conds" "use") - (set_attr "length" "8")]) + [(set_attr "conds" "use") + (set_attr "length" "8")] +) (define_insn "*mov_notscc" [(set (match_operand:SI 0 "s_register_operand" "=r") (not:SI (match_operator:SI 1 "comparison_operator" [(match_operand 2 "cc_register" "") (const_int 0)])))] - "" + "TARGET_ARM" "mov%D1\\t%0, #0\;mvn%d1\\t%0, #1" -[(set_attr "conds" "use") - (set_attr "length" "8")]) + [(set_attr "conds" "use") + (set_attr "length" "8")] +) ;; Conditional move insns @@ -4369,11 +5689,11 @@ (if_then_else:SI (match_operand 1 "comparison_operator" "") (match_operand:SI 2 "arm_not_operand" "") (match_operand:SI 3 "arm_not_operand" "")))] - "" + "TARGET_ARM" " { enum rtx_code code = GET_CODE (operands[1]); - rtx ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1); + rtx ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1); operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); }") @@ -4383,7 +5703,7 @@ (if_then_else:SF (match_operand 1 "comparison_operator" "") (match_operand:SF 2 "s_register_operand" "") (match_operand:SF 3 "nonmemory_operand" "")))] - "" + "TARGET_ARM" " { enum rtx_code code = GET_CODE (operands[1]); @@ -4395,7 +5715,7 @@ || (! fpu_add_operand (operands[3], SFmode))) operands[3] = force_reg (SFmode, operands[3]); - ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1); + ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1); operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); }") @@ -4405,11 +5725,11 @@ (if_then_else:DF (match_operand 1 "comparison_operator" "") (match_operand:DF 2 "s_register_operand" "") (match_operand:DF 3 "fpu_add_operand" "")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" " { enum rtx_code code = GET_CODE (operands[1]); - rtx ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1); + rtx ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1); operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); }") @@ -4421,7 +5741,7 @@ [(match_operand 4 "cc_register" "") (const_int 0)]) (match_operand:SI 1 "arm_not_operand" "0,0,rI,K,rI,rI,K,K") (match_operand:SI 2 "arm_not_operand" "rI,K,0,0,rI,K,rI,K")))] - "" + "TARGET_ARM" "@ mov%D3\\t%0, %2 mvn%D3\\t%0, #%B2 @@ -4441,7 +5761,7 @@ [(match_operand 4 "cc_register" "") (const_int 0)]) (match_operand:SF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H") (match_operand:SF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "@ mvf%D3s\\t%0, %2 mnf%D3s\\t%0, #%N2 @@ -4461,7 +5781,7 @@ [(match_operand 4 "cc_register" "") (const_int 0)]) (match_operand:SF 1 "s_register_operand" "0,r") (match_operand:SF 2 "s_register_operand" "r,0")))] - "TARGET_SOFT_FLOAT" + "TARGET_ARM && TARGET_SOFT_FLOAT" "@ mov%D3\\t%0, %2 mov%d3\\t%0, %1" @@ -4474,7 +5794,7 @@ [(match_operand 4 "cc_register" "") (const_int 0)]) (match_operand:DF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H") (match_operand:DF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))] - "TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT" "@ mvf%D3d\\t%0, %2 mnf%D3d\\t%0, #%N2 @@ -4490,14 +5810,19 @@ ;; Jump and linkage insns -(define_insn "jump" +(define_expand "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] + "TARGET_EITHER" "" +) + +(define_insn "*arm_jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "TARGET_ARM" "* { - extern int arm_ccfsm_state; - if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) { arm_ccfsm_state += 2; @@ -4506,12 +5831,34 @@ return \"b%?\\t%l0\"; }") +(define_insn "*thumb_jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "TARGET_THUMB" + "* + if (get_attr_length (insn) == 2) + return \"b\\t%l0\"; + return \"bl\\t%l0\\t%@ far jump\"; + " + [(set (attr "far_jump") + (if_then_else + (eq_attr "length" "4") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 2) + (const_int 4)))] +) + (define_expand "call" [(parallel [(call (match_operand 0 "memory_operand" "") (match_operand 1 "general_operand" "")) - (use (match_operand 2 "" "")) + (use (match_operand 2 "" "")) (clobber (reg:SI 14))])] - "" + "TARGET_EITHER" " { rtx callee; @@ -4540,36 +5887,71 @@ (define_insn "*call_reg" [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r")) - (match_operand 1 "" "g")) - (use (match_operand:SI 2 "immediate_operand" "n")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) (clobber (reg:SI 14))] - "" + "TARGET_ARM" "* return output_call (operands); -" -;; length is worst case, normally it is only two -[(set_attr "length" "12") - (set_attr "type" "call")]) + " + ;; length is worst case, normally it is only two + [(set_attr "length" "12") + (set_attr "type" "call")] +) (define_insn "*call_mem" [(call (mem:SI (match_operand:SI 0 "memory_operand" "m")) - (match_operand 1 "general_operand" "g")) - (use (match_operand:SI 2 "" "")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) (clobber (reg:SI 14))] - "" + "TARGET_ARM" "* return output_call_mem (operands); -" -[(set_attr "length" "12") - (set_attr "type" "call")]) + " + [(set_attr "length" "12") + (set_attr "type" "call")] +) + +(define_insn "*call_indirect" + [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (clobber (reg:SI 14))] + "TARGET_THUMB" + "* + { + if (TARGET_CALLER_INTERWORKING) + return \"bl\\t%__interwork_call_via_%0\"; + else + return \"bl\\t%__call_via_%0\"; + }" + [(set_attr "type" "call")] +) + +(define_insn "*call_value_indirect" + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (reg:SI 14))] + "TARGET_THUMB" + "* + { + if (TARGET_CALLER_INTERWORKING) + return \"bl\\t%__interwork_call_via_%1\"; + else + return \"bl\\t%__call_via_%1\"; + }" + [(set_attr "type" "call")] +) (define_expand "call_value" - [(parallel [(set (match_operand 0 "" "=rf") + [(parallel [(set (match_operand 0 "" "=rf") (call (match_operand 1 "memory_operand" "m") (match_operand 2 "general_operand" "g"))) - (use (match_operand:SI 3 "" "")) + (use (match_operand 3 "" "")) (clobber (reg:SI 14))])] - "" + "TARGET_EITHER" " { rtx callee = XEXP (operands[1], 0); @@ -4588,44 +5970,48 @@ (define_insn "*call_value_reg" [(set (match_operand 0 "" "=rf") (call (mem:SI (match_operand:SI 1 "s_register_operand" "r")) - (match_operand 2 "general_operand" "g"))) + (match_operand 2 "" ""))) (use (match_operand 3 "" "")) (clobber (reg:SI 14))] - "" + "TARGET_ARM" "* - return output_call (&operands[1]); -" -[(set_attr "length" "12") - (set_attr "type" "call")]) + return output_call (& operands[1]); + " + [(set_attr "length" "12") + (set_attr "type" "call")] +) (define_insn "*call_value_mem" [(set (match_operand 0 "" "=rf") - (call (mem:SI (match_operand 1 "memory_operand" "m")) - (match_operand 2 "general_operand" "g"))) + (call (mem:SI (match_operand:SI 1 "memory_operand" "m")) + (match_operand 2 "" ""))) (use (match_operand 3 "" "")) (clobber (reg:SI 14))] - "! CONSTANT_ADDRESS_P (XEXP (operands[1], 0))" + "TARGET_ARM && (! CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))" "* - return output_call_mem (&operands[1]); -" -[(set_attr "length" "12") - (set_attr "type" "call")]) + return output_call_mem (& operands[1]); + " + [(set_attr "length" "12") + (set_attr "type" "call")] +) ;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses ;; The 'a' causes the operand to be treated as an address, i.e. no '#' output. (define_insn "*call_symbol" [(call (mem:SI (match_operand:SI 0 "" "X")) - (match_operand:SI 1 "general_operand" "g")) + (match_operand 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI 14))] - "(GET_CODE (operands[0]) == SYMBOL_REF) + "TARGET_ARM + && (GET_CODE (operands[0]) == SYMBOL_REF) && ! arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)" "* { return NEED_PLT_RELOC ? \"bl%?\\t%a0(PLT)\" : \"bl%?\\t%a0\"; }" -[(set_attr "type" "call")]) + [(set_attr "type" "call")] +) (define_insn "*call_value_symbol" [(set (match_operand 0 "s_register_operand" "=rf") @@ -4633,30 +6019,54 @@ (match_operand:SI 2 "general_operand" "g"))) (use (match_operand 3 "" "")) (clobber (reg:SI 14))] - "(GET_CODE (operands[1]) == SYMBOL_REF) + "TARGET_ARM + && (GET_CODE (operands[1]) == SYMBOL_REF) && ! arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)" "* { return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\"; }" -[(set_attr "type" "call")]) + [(set_attr "type" "call")] +) + +(define_insn "*call_insn" + [(call (mem:SI (match_operand:SI 0 "" "X")) + (match_operand:SI 1 "" "")) + (use (match_operand 2 "" "")) + (clobber (reg:SI 14))] + "TARGET_THUMB && operands[2] == const0_rtx && (GET_CODE (operands[0]) == SYMBOL_REF)" + "bl\\t%a0" + [(set_attr "length" "4") + (set_attr "type" "call")] +) + +(define_insn "*call_value_insn" + [(set (match_operand 0 "register_operand" "=l") + (call (mem:SI (match_operand 1 "" "X")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (reg:SI 14))] + "TARGET_THUMB && operands[3] == const0_rtx && (GET_CODE (operands[1]) == SYMBOL_REF)" + "bl\\t%a1" + [(set_attr "length" "4") + (set_attr "type" "call")] +) ;; Often the return insn will be the same as loading from memory, so set attr (define_insn "return" [(return)] - "USE_RETURN_INSN (FALSE)" + "TARGET_ARM && USE_RETURN_INSN (FALSE)" "* -{ - extern int arm_ccfsm_state; - - if (arm_ccfsm_state == 2) { - arm_ccfsm_state += 2; - return \"\"; - } - return output_return_instruction (NULL, TRUE, FALSE); -}" -[(set_attr "type" "load")]) + if (arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return output_return_instruction (NULL, TRUE, FALSE); + }" + [(set_attr "type" "load")] +) (define_insn "*cond_return" [(set (pc) @@ -4664,16 +6074,14 @@ [(match_operand 1 "cc_register" "") (const_int 0)]) (return) (pc)))] - "USE_RETURN_INSN (TRUE)" + "TARGET_ARM && USE_RETURN_INSN (TRUE)" "* { - extern int arm_ccfsm_state; - if (arm_ccfsm_state == 2) - { - arm_ccfsm_state += 2; - return \"\"; - } + { + arm_ccfsm_state += 2; + return \"\"; + } return output_return_instruction (operands[0], TRUE, FALSE); }" [(set_attr "conds" "use") @@ -4685,16 +6093,14 @@ [(match_operand 1 "cc_register" "") (const_int 0)]) (pc) (return)))] - "USE_RETURN_INSN (TRUE)" + "TARGET_ARM && USE_RETURN_INSN (TRUE)" "* { - extern int arm_ccfsm_state; - if (arm_ccfsm_state == 2) - { - arm_ccfsm_state += 2; - return \"\"; - } + { + arm_ccfsm_state += 2; + return \"\"; + } return output_return_instruction (operands[0], TRUE, TRUE); }" [(set_attr "conds" "use") @@ -4707,7 +6113,7 @@ (const_int 0)) (match_operand 1 "" "") (match_operand 2 "" "")])] - "" + "TARGET_ARM" " { int i; @@ -4734,10 +6140,11 @@ (define_insn "blockage" [(unspec_volatile [(const_int 0)] 0)] + "TARGET_EITHER" "" - "" -[(set_attr "length" "0") - (set_attr "type" "block")]) + [(set_attr "length" "0") + (set_attr "type" "block")] +) (define_expand "casesi" [(match_operand:SI 0 "s_register_operand" "") ; index to jump on @@ -4745,7 +6152,7 @@ (match_operand:SI 2 "const_int_operand" "") ; total range (match_operand:SI 3 "" "") ; table label (match_operand:SI 4 "" "")] ; Out of range label - "" + "TARGET_ARM" " { rtx reg; @@ -4777,34 +6184,65 @@ (label_ref (match_operand 3 "" "")))) (clobber (reg:CC 24)) (use (label_ref (match_dup 2)))])] - "" + "TARGET_ARM" "* if (flag_pic) return \"cmp\\t%0, %1\;addls\\t%|pc, %|pc, %0, asl #2\;b\\t%l3\"; - return \"cmp\\t%0, %1\;ldrls\\t%|pc, [%|pc, %0, asl #2]\;b\\t%l3\"; + return \"cmp\\t%0, %1\;ldrls\\t%|pc, [%|pc, %0, asl #2]\;b\\t%l3\"; " [(set_attr "conds" "clob") (set_attr "length" "12")]) -(define_insn "indirect_jump" +(define_expand "indirect_jump" [(set (pc) - (match_operand:SI 0 "s_register_operand" "r"))] + (match_operand:SI 0 "s_register_operand" ""))] + "TARGET_EITHER" "" - "mov%?\\t%|pc, %0\\t%@ indirect jump") +) + +(define_insn "*arm_indirect_jump" + [(set (pc) + (match_operand:SI 0 "s_register_operand" "r"))] + "TARGET_ARM" + "mov%?\\t%|pc, %0\\t%@ indirect register jump" +) +;; Although not supported by the define_expand above, +;; cse/combine may generate this form. (define_insn "*load_indirect_jump" [(set (pc) (match_operand:SI 0 "memory_operand" "m"))] - "" - "ldr%?\\t%|pc, %0\\t%@ indirect jump" -[(set_attr "type" "load")]) + "TARGET_ARM" + "ldr%?\\t%|pc, %0\\t%@ indirect memory jump" + [(set_attr "type" "load")] +) + +(define_insn "*thumb_indirect_jump" + [(set (pc) + (match_operand:SI 0 "register_operand" "l*r"))] + "TARGET_THUMB" + "mov\\tpc, %0" + [(set_attr "conds" "clob") + (set_attr "length" "2")] +) + ;; Misc insns (define_insn "nop" [(const_int 0)] - "" - "mov%?\\t%|r0, %|r0\\t%@ nop") + "TARGET_EITHER" + "* + if (TARGET_ARM) + return \"mov%?\\t%|r0, %|r0\\t%@ nop\"; + return \"mov\\tr8, r8\"; + " + [(set (attr "length") + (if_then_else (eq_attr "is_thumb" "yes") + (const_int 2) + (const_int 4)))] +) + ;; Patterns to allow combination of arithmetic, cond code and shifts @@ -4815,7 +6253,7 @@ [(match_operand:SI 4 "s_register_operand" "r") (match_operand:SI 5 "reg_or_int_operand" "rI")]) (match_operand:SI 2 "s_register_operand" "r")]))] - "" + "TARGET_ARM" "%i1%?\\t%0, %2, %4%S3" ) @@ -4830,7 +6268,7 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (match_op_dup 1 [(match_op_dup 3 [(match_dup 4) (match_dup 5)]) (match_dup 2)]))] - "" + "TARGET_ARM" "%i1%?s\\t%0, %2, %4%S3" [(set_attr "conds" "set") ]) @@ -4844,7 +6282,7 @@ (match_operand:SI 2 "s_register_operand" "r")]) (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] - "" + "TARGET_ARM" "%i1%?s\\t%0, %2, %4%S3" [(set_attr "conds" "set") ]) @@ -4855,7 +6293,7 @@ (match_operator:SI 2 "shift_operator" [(match_operand:SI 3 "s_register_operand" "r") (match_operand:SI 4 "reg_or_int_operand" "rM")])))] - "" + "TARGET_ARM" "sub%?\\t%0, %1, %3%S2" ) @@ -4870,7 +6308,7 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) (match_dup 4)])))] - "" + "TARGET_ARM" "sub%?s\\t%0, %1, %3%S2" [(set_attr "conds" "set") ]) @@ -4884,7 +6322,7 @@ (match_operand:SI 4 "reg_or_int_operand" "rM")])) (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] - "" + "TARGET_ARM" "sub%?s\\t%0, %1, %3%S2" [(set_attr "conds" "set") ]) @@ -4904,7 +6342,7 @@ (match_operand:SI 4 "" "rM")]) (match_operand:SI 2 "" "r")) (match_operand:SI 1 "const_int_operand" "n")))] - "reload_in_progress" + "TARGET_ARM && reload_in_progress" "* output_asm_insn (\"add%?\\t%0, %2, %3%S5\", operands); operands[2] = operands[1]; @@ -4928,7 +6366,7 @@ (plus:SI (plus:SI (match_op_dup 5 [(match_dup 3) (match_dup 4)]) (match_dup 1)) (match_dup 2)))] - "reload_in_progress" + "TARGET_ARM && reload_in_progress" "* output_add_immediate (operands); return \"add%?s\\t%0, %0, %3%S5\"; @@ -4947,7 +6385,7 @@ (match_operand:SI 2 "const_int_operand" "n")) (const_int 0))) (clobber (match_scratch:SI 0 "=&r"))] - "reload_in_progress" + "TARGET_ARM && reload_in_progress" "* output_add_immediate (operands); return \"add%?s\\t%0, %0, %3%S5\"; @@ -4964,7 +6402,7 @@ (match_operand:SI 2 "" "r,r")) (match_operand:SI 3 "" "r,r")) (match_operand:SI 4 "const_int_operand" "n,n")))] - "reload_in_progress" + "TARGET_ARM && reload_in_progress" "* output_asm_insn (\"mla%?\\t%0, %2, %1, %3\", operands); operands[2] = operands[4]; @@ -4985,7 +6423,7 @@ (set (match_operand:SI 0 "" "=&r") (plus:SI (plus:SI (mult:SI (match_dup 3) (match_dup 4)) (match_dup 1)) (match_dup 2)))] - "reload_in_progress" + "TARGET_ARM && reload_in_progress" "* output_add_immediate (operands); output_asm_insn (\"mla%?s\\t%0, %3, %4, %0\", operands); @@ -5004,7 +6442,7 @@ (match_operand:SI 2 "const_int_operand" "n")) (const_int 0))) (clobber (match_scratch:SI 0 "=&r"))] - "reload_in_progress" + "TARGET_ARM && reload_in_progress" "* output_add_immediate (operands); return \"mla%?s\\t%0, %3, %4, %0\"; @@ -5020,7 +6458,7 @@ (and:SI (match_operator 1 "comparison_operator" [(match_operand 3 "cc_register" "") (const_int 0)]) (match_operand:SI 2 "s_register_operand" "r")))] - "" + "TARGET_ARM" "mov%D1\\t%0, #0\;and%d1\\t%0, %2, #1" [(set_attr "conds" "use") (set_attr "length" "8")]) @@ -5030,7 +6468,7 @@ (ior:SI (match_operator 2 "comparison_operator" [(match_operand 3 "cc_register" "") (const_int 0)]) (match_operand:SI 1 "s_register_operand" "0,?r")))] - "" + "TARGET_ARM" "@ orr%d2\\t%0, %1, #1 mov%D2\\t%0, %1\;orr%d2\\t%0, %1, #1" @@ -5039,11 +6477,11 @@ (define_insn "*compare_scc" [(set (match_operand:SI 0 "s_register_operand" "=r,r") - (match_operator 1 "comparison_operator" + (match_operator:SI 1 "comparison_operator" [(match_operand:SI 2 "s_register_operand" "r,r") (match_operand:SI 3 "arm_add_operand" "rI,L")])) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "* if (GET_CODE (operands[1]) == LT && operands[3] == const0_rtx) return \"mov\\t%0, %2, lsr #31\"; @@ -5074,7 +6512,7 @@ (const_int 0)]) (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI") (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))] - "" + "TARGET_ARM" "* if (GET_CODE (operands[3]) == NE) { @@ -5101,7 +6539,7 @@ (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]) (match_operand:SI 1 "s_register_operand" "0,?r")])) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "* if (GET_CODE (operands[4]) == LT && operands[3] == const0_rtx) return \"%i5\\t%0, %1, %2, lsr #31\"; @@ -5125,7 +6563,7 @@ [(match_operand:SI 2 "s_register_operand" "r,r") (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "* output_asm_insn (\"cmp\\t%2, %3\", operands); if (which_alternative != 0) @@ -5136,7 +6574,7 @@ (set_attr "length" "8,12")]) (define_insn "*cmp_ite0" - [(set (match_operand:CC 6 "dominant_cc_register" "") + [(set (match_operand 6 "dominant_cc_register" "") (compare (if_then_else:SI (match_operator 4 "comparison_operator" @@ -5147,10 +6585,10 @@ (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]) (const_int 0)) (const_int 0)))] - "" + "TARGET_ARM" "* { - char* opcodes[4][2] = + char * opcodes[4][2] = { {\"cmp\\t%2, %3\;cmp%d5\\t%0, %1\",\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\"}, {\"cmp\\t%2, %3\;cmn%d5\\t%0, #%n1\", \"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\"}, @@ -5168,7 +6606,7 @@ (set_attr "length" "8")]) (define_insn "*cmp_ite1" - [(set (match_operand:CC 6 "dominant_cc_register" "") + [(set (match_operand 6 "dominant_cc_register" "") (compare (if_then_else:SI (match_operator 4 "comparison_operator" @@ -5179,10 +6617,10 @@ (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]) (const_int 1)) (const_int 0)))] - "" + "TARGET_ARM" "* { - char* opcodes[4][2] = + char * opcodes[4][2] = { {\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\", \"cmp\\t%2, %3\;cmp%D5\\t%0, %1\"}, {\"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\", \"cmp\\t%2, %3\;cmn%D5\\t%0, #%n1\"}, @@ -5206,7 +6644,7 @@ [(match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "arm_rhs_operand" "rI")]))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "* if (GET_CODE (operands[3]) == LT && operands[3] == const0_rtx) return \"mov\\t%0, %1, asr #31\"; @@ -5233,7 +6671,7 @@ (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI") (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "* if (GET_CODE (operands[5]) == LT && (operands[4] == const0_rtx)) @@ -5296,7 +6734,7 @@ (match_operand:SI 3 "arm_add_operand" "rIL,rIL")) (match_operand:SI 1 "arm_rhs_operand" "0,?rI"))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "8,12")]) @@ -5310,7 +6748,7 @@ (match_operand:SI 2 "s_register_operand" "r,r,r,r") (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L")) (match_operand:SI 1 "arm_rhs_operand" "0,0,?rI,?rI")))] - "" + "TARGET_ARM" "@ add%d4\\t%0, %2, %3 sub%d4\\t%0, %2, #%n3 @@ -5330,7 +6768,7 @@ (match_operand:SI 2 "s_register_operand" "r,r") (match_operand:SI 3 "arm_add_operand" "rIL,rIL")))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "8,12")]) @@ -5344,7 +6782,7 @@ (plus:SI (match_operand:SI 2 "s_register_operand" "r,r,r,r") (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L"))))] - "" + "TARGET_ARM" "@ add%D4\\t%0, %2, %3 sub%D4\\t%0, %2, #%n3 @@ -5366,7 +6804,7 @@ [(match_operand:SI 3 "s_register_operand" "r") (match_operand:SI 4 "arm_rhs_operand" "rI")]))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "12")]) @@ -5381,7 +6819,7 @@ (match_operator:SI 7 "shiftable_operator" [(match_operand:SI 3 "s_register_operand" "r") (match_operand:SI 4 "arm_rhs_operand" "rI")])))] - "" + "TARGET_ARM" "%I6%d5\\t%0, %1, %2\;%I7%D5\\t%0, %3, %4" [(set_attr "conds" "use") (set_attr "length" "8")]) @@ -5396,7 +6834,7 @@ (match_operand:SI 5 "arm_rhs_operand" "rI,rI")]) (match_operand:SI 1 "arm_rhs_operand" "0,?rI"))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "* /* If we have an operation where (op x 0) is the identity operation and the conditional operator is LT or GE and we are comparing against zero and @@ -5434,7 +6872,7 @@ [(match_operand:SI 2 "s_register_operand" "r,r") (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]) (match_operand:SI 1 "arm_rhs_operand" "0,?rI")))] - "" + "TARGET_ARM" "@ %I5%d4\\t%0, %2, %3 %I5%d4\\t%0, %2, %3\;mov%D4\\t%0, %1" @@ -5452,7 +6890,7 @@ [(match_operand:SI 2 "s_register_operand" "r,r") (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "* /* If we have an operation where (op x 0) is the identity operation and the conditional operator is LT or GE and we are comparing against zero and @@ -5492,7 +6930,7 @@ (match_operator:SI 5 "shiftable_operator" [(match_operand:SI 2 "s_register_operand" "r,r") (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])))] - "" + "TARGET_ARM" "@ %I5%D4\\t%0, %2, %3 %I5%D4\\t%0, %2, %3\;mov%d4\\t%0, %1" @@ -5510,7 +6948,7 @@ (not:SI (match_operand:SI 2 "s_register_operand" "r,r")))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "8,12")]) @@ -5522,7 +6960,7 @@ [(match_operand 3 "cc_register" "") (const_int 0)]) (match_operand:SI 1 "arm_not_operand" "0,?rI,K") (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))] - "" + "TARGET_ARM" "@ mvn%D4\\t%0, %2 mov%d4\\t%0, %1\;mvn%D4\\t%0, %2 @@ -5540,7 +6978,7 @@ (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "8,12")]) @@ -5552,7 +6990,7 @@ [(match_operand 3 "cc_register" "") (const_int 0)]) (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r")) (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] - "" + "TARGET_ARM" "@ mvn%d4\\t%0, %2 mov%D4\\t%0, %1\;mvn%d4\\t%0, %2 @@ -5571,7 +7009,7 @@ (match_operand:SI 3 "arm_rhs_operand" "rM,rM")]) (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "8,12")]) @@ -5585,7 +7023,7 @@ [(match_operand:SI 2 "s_register_operand" "r,r,r") (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")]) (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] - "" + "TARGET_ARM" "@ mov%d5\\t%0, %2%S4 mov%D5\\t%0, %1\;mov%d5\\t%0, %2%S4 @@ -5604,7 +7042,7 @@ [(match_operand:SI 2 "s_register_operand" "r,r") (match_operand:SI 3 "arm_rhs_operand" "rM,rM")]))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "8,12")]) @@ -5618,7 +7056,7 @@ (match_operator:SI 4 "shift_operator" [(match_operand:SI 2 "s_register_operand" "r,r,r") (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")])))] - "" + "TARGET_ARM" "@ mov%D5\\t%0, %2%S4 mov%d5\\t%0, %1\;mov%D5\\t%0, %2%S4 @@ -5639,7 +7077,7 @@ [(match_operand:SI 3 "s_register_operand" "r") (match_operand:SI 4 "arm_rhs_operand" "rM")]))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "12")]) @@ -5655,7 +7093,7 @@ (match_operator:SI 7 "shift_operator" [(match_operand:SI 3 "s_register_operand" "r") (match_operand:SI 4 "arm_rhs_operand" "rM")])))] - "" + "TARGET_ARM" "mov%d5\\t%0, %1%S6\;mov%D5\\t%0, %3%S7" [(set_attr "conds" "use") (set_attr "length" "8")]) @@ -5671,7 +7109,7 @@ [(match_operand:SI 2 "s_register_operand" "r") (match_operand:SI 3 "arm_rhs_operand" "rI")]))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "12")]) @@ -5685,7 +7123,7 @@ (match_operator:SI 6 "shiftable_operator" [(match_operand:SI 2 "s_register_operand" "r") (match_operand:SI 3 "arm_rhs_operand" "rI")])))] - "" + "TARGET_ARM" "mvn%d5\\t%0, %1\;%I6%D5\\t%0, %2, %3" [(set_attr "conds" "use") (set_attr "length" "8")]) @@ -5701,7 +7139,7 @@ (match_operand:SI 3 "arm_rhs_operand" "rI")]) (not:SI (match_operand:SI 1 "s_register_operand" "r")))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "12")]) @@ -5715,7 +7153,7 @@ [(match_operand:SI 2 "s_register_operand" "r") (match_operand:SI 3 "arm_rhs_operand" "rI")]) (not:SI (match_operand:SI 1 "s_register_operand" "r"))))] - "" + "TARGET_ARM" "mvn%D5\\t%0, %1\;%I6%d5\\t%0, %2, %3" [(set_attr "conds" "use") (set_attr "length" "8")]) @@ -5729,7 +7167,7 @@ (neg:SI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "8,12")]) @@ -5741,7 +7179,7 @@ [(match_operand 3 "cc_register" "") (const_int 0)]) (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r")) (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] - "" + "TARGET_ARM" "@ rsb%d4\\t%0, %2, #0 mov%D4\\t%0, %1\;rsb%d4\\t%0, %2, #0 @@ -5758,7 +7196,7 @@ (match_operand:SI 1 "arm_not_operand" "0,?rIK") (neg:SI (match_operand:SI 2 "s_register_operand" "r,r")))) (clobber (reg:CC 24))] - "" + "TARGET_ARM" "#" [(set_attr "conds" "clob") (set_attr "length" "8,12")]) @@ -5770,7 +7208,7 @@ [(match_operand 3 "cc_register" "") (const_int 0)]) (match_operand:SI 1 "arm_not_operand" "0,?rI,K") (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))] - "" + "TARGET_ARM" "@ rsb%D4\\t%0, %2, #0 mov%d4\\t%0, %1\;rsb%D4\\t%0, %2, #0 @@ -5784,7 +7222,7 @@ [(match_operand:SI 2 "memory_operand" "m") (match_operand:SI 3 "memory_operand" "m")])) (clobber (match_scratch:SI 4 "=r"))] - "adjacent_mem_locations (operands[2], operands[3])" + "TARGET_ARM && adjacent_mem_locations (operands[2], operands[3])" "* { rtx ldm[3]; @@ -5868,7 +7306,8 @@ (match_operand:QI 3 "s_register_operand" "r")) (set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (match_dup 1) (match_dup 2)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" @@ -5881,7 +7320,8 @@ (match_operand:QI 3 "s_register_operand" "r")) (set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (match_dup 1) (match_dup 2)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" @@ -5894,7 +7334,8 @@ (match_operand:SI 2 "index_operand" "rJ")))) (set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (match_dup 1) (match_dup 2)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" @@ -5907,7 +7348,8 @@ (match_operand:SI 2 "s_register_operand" "r")))) (set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (match_dup 1) (match_dup 2)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" @@ -5921,7 +7363,8 @@ (match_operand:SI 2 "index_operand" "rJ"))))) (set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (match_dup 1) (match_dup 2)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" @@ -5935,7 +7378,8 @@ (match_operand:SI 2 "s_register_operand" "r"))))) (set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (match_dup 1) (match_dup 2)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" @@ -5948,7 +7392,8 @@ (match_operand:SI 3 "s_register_operand" "r")) (set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (match_dup 1) (match_dup 2)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" @@ -5961,7 +7406,8 @@ (match_operand:SI 3 "s_register_operand" "r")) (set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (match_dup 1) (match_dup 2)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" @@ -5974,7 +7420,8 @@ (match_operand:SI 2 "index_operand" "rJ")))) (set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (match_dup 1) (match_dup 2)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" @@ -5987,7 +7434,8 @@ (match_operand:SI 2 "s_register_operand" "r")))) (set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (match_dup 1) (match_dup 2)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" @@ -6000,7 +7448,8 @@ (match_operand:SI 2 "index_operand" "rJ")))) (set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (match_dup 1) (match_dup 2)))] - "(! BYTES_BIG_ENDIAN) + "TARGET_ARM + && (! BYTES_BIG_ENDIAN) && ! TARGET_MMU_TRAPS && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM @@ -6015,7 +7464,8 @@ (match_operand:SI 2 "s_register_operand" "r")))) (set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (match_dup 1) (match_dup 2)))] - "(!BYTES_BIG_ENDIAN) + "TARGET_ARM + && (!BYTES_BIG_ENDIAN) && ! TARGET_MMU_TRAPS && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM @@ -6033,7 +7483,8 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) (match_dup 1)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && REGNO (operands[3]) != FRAME_POINTER_REGNUM" "str%?b\\t%5, [%0, %3%S2]!" @@ -6048,7 +7499,8 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) (match_dup 4)])))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && REGNO (operands[3]) != FRAME_POINTER_REGNUM" "str%?b\\t%5, [%0, -%3%S2]!" @@ -6063,7 +7515,8 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) (match_dup 1)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && REGNO (operands[3]) != FRAME_POINTER_REGNUM" "ldr%?b\\t%5, [%0, %3%S2]!" @@ -6078,7 +7531,8 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) (match_dup 4)])))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && REGNO (operands[3]) != FRAME_POINTER_REGNUM" "ldr%?b\\t%5, [%0, -%3%S2]!" @@ -6093,7 +7547,8 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) (match_dup 1)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && REGNO (operands[3]) != FRAME_POINTER_REGNUM" "str%?\\t%5, [%0, %3%S2]!" @@ -6108,7 +7563,8 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) (match_dup 4)])))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && REGNO (operands[3]) != FRAME_POINTER_REGNUM" "str%?\\t%5, [%0, -%3%S2]!" @@ -6123,7 +7579,8 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) (match_dup 1)))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && REGNO (operands[3]) != FRAME_POINTER_REGNUM" "ldr%?\\t%5, [%0, %3%S2]!" @@ -6138,7 +7595,8 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) (match_dup 4)])))] - "REGNO (operands[0]) != FRAME_POINTER_REGNUM + "TARGET_ARM + && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM && REGNO (operands[3]) != FRAME_POINTER_REGNUM" "ldr%?\\t%5, [%0, -%3%S2]!" @@ -6153,7 +7611,8 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) (match_dup 1)))] - "(! BYTES_BIG_ENDIAN) + "TARGET_ARM + && (! BYTES_BIG_ENDIAN) && ! TARGET_MMU_TRAPS && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM @@ -6170,7 +7629,8 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) (match_dup 4)])))] - "(! BYTES_BIG_ENDIAN) + "TARGET_ARM + && (! BYTES_BIG_ENDIAN) && ! TARGET_MMU_TRAPS && REGNO (operands[0]) != FRAME_POINTER_REGNUM && REGNO (operands[1]) != FRAME_POINTER_REGNUM @@ -6191,7 +7651,7 @@ (match_operand:QI 2 "s_register_operand" "r")) (set (match_dup 0) (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))] - "" + "TARGET_ARM" "str%?b\\t%2, [%0], %1") (define_peephole @@ -6199,7 +7659,7 @@ (mem:QI (match_operand:SI 1 "s_register_operand" "+r"))) (set (match_dup 1) (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] - "REGNO(operands[0]) != REGNO(operands[1]) + "TARGET_ARM && REGNO(operands[0]) != REGNO(operands[1]) && (GET_CODE (operands[2]) != REG || REGNO(operands[0]) != REGNO (operands[2]))" "ldr%?b\\t%0, [%1], %2") @@ -6209,7 +7669,7 @@ (match_operand:SI 2 "s_register_operand" "r")) (set (match_dup 0) (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))] - "" + "TARGET_ARM" "str%?\\t%2, [%0], %1") (define_peephole @@ -6217,7 +7677,8 @@ (mem:HI (match_operand:SI 1 "s_register_operand" "+r"))) (set (match_dup 1) (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] - "(! BYTES_BIG_ENDIAN) + "TARGET_ARM + && (! BYTES_BIG_ENDIAN) && ! TARGET_MMU_TRAPS && REGNO(operands[0]) != REGNO(operands[1]) && (GET_CODE (operands[2]) != REG @@ -6229,7 +7690,8 @@ (mem:SI (match_operand:SI 1 "s_register_operand" "+r"))) (set (match_dup 1) (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] - "REGNO(operands[0]) != REGNO(operands[1]) + "TARGET_ARM + && REGNO(operands[0]) != REGNO(operands[1]) && (GET_CODE (operands[2]) != REG || REGNO(operands[0]) != REGNO (operands[2]))" "ldr%?\\t%0, [%1], %2") @@ -6239,7 +7701,7 @@ (match_operand:SI 1 "index_operand" "rJ"))) (match_operand:QI 2 "s_register_operand" "r")) (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))] - "" + "TARGET_ARM" "str%?b\\t%2, [%0, %1]!") (define_peephole @@ -6250,7 +7712,7 @@ (match_operand:QI 3 "s_register_operand" "r")) (set (match_dup 2) (plus:SI (match_op_dup 4 [(match_dup 0) (match_dup 1)]) (match_dup 2)))] - "" + "TARGET_ARM" "str%?b\\t%3, [%2, %0%S4]!") ; This pattern is never tried by combine, so do it as a peephole @@ -6260,7 +7722,7 @@ (match_operand:SI 1 "s_register_operand" "r")) (set (reg:CC 24) (compare:CC (match_dup 1) (const_int 0)))] - "" + "TARGET_ARM" "sub%?s\\t%0, %1, #0" [(set_attr "conds" "set")]) @@ -6276,7 +7738,7 @@ (match_operand:SI 6 "memory_operand" "m")) (set (match_operand:SI 3 "s_register_operand" "=r") (match_operand:SI 7 "memory_operand" "m"))] - "load_multiple_sequence (operands, 4, NULL, NULL, NULL)" + "TARGET_ARM && load_multiple_sequence (operands, 4, NULL, NULL, NULL)" "* return emit_ldm_seq (operands, 4); ") @@ -6288,7 +7750,7 @@ (match_operand:SI 4 "memory_operand" "m")) (set (match_operand:SI 2 "s_register_operand" "=r") (match_operand:SI 5 "memory_operand" "m"))] - "load_multiple_sequence (operands, 3, NULL, NULL, NULL)" + "TARGET_ARM && load_multiple_sequence (operands, 3, NULL, NULL, NULL)" "* return emit_ldm_seq (operands, 3); ") @@ -6298,7 +7760,7 @@ (match_operand:SI 2 "memory_operand" "m")) (set (match_operand:SI 1 "s_register_operand" "=r") (match_operand:SI 3 "memory_operand" "m"))] - "load_multiple_sequence (operands, 2, NULL, NULL, NULL)" + "TARGET_ARM && load_multiple_sequence (operands, 2, NULL, NULL, NULL)" "* return emit_ldm_seq (operands, 2); ") @@ -6312,7 +7774,7 @@ (match_operand:SI 2 "s_register_operand" "r")) (set (match_operand:SI 7 "memory_operand" "=m") (match_operand:SI 3 "s_register_operand" "r"))] - "store_multiple_sequence (operands, 4, NULL, NULL, NULL)" + "TARGET_ARM && store_multiple_sequence (operands, 4, NULL, NULL, NULL)" "* return emit_stm_seq (operands, 4); ") @@ -6324,7 +7786,7 @@ (match_operand:SI 1 "s_register_operand" "r")) (set (match_operand:SI 5 "memory_operand" "=m") (match_operand:SI 2 "s_register_operand" "r"))] - "store_multiple_sequence (operands, 3, NULL, NULL, NULL)" + "TARGET_ARM && store_multiple_sequence (operands, 3, NULL, NULL, NULL)" "* return emit_stm_seq (operands, 3); ") @@ -6334,7 +7796,7 @@ (match_operand:SI 0 "s_register_operand" "r")) (set (match_operand:SI 3 "memory_operand" "=m") (match_operand:SI 1 "s_register_operand" "r"))] - "store_multiple_sequence (operands, 2, NULL, NULL, NULL)" + "TARGET_ARM && store_multiple_sequence (operands, 2, NULL, NULL, NULL)" "* return emit_stm_seq (operands, 2); ") @@ -6356,24 +7818,22 @@ (define_peephole [(parallel [(call (mem:SI (match_operand:SI 0 "" "X")) (match_operand:SI 1 "general_operand" "g")) - (use (match_operand:SI 2 "" "")) + (use (match_operand 2 "" "")) (clobber (reg:SI 14))]) (return)] - "(GET_CODE (operands[0]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) + "TARGET_ARM + && (GET_CODE (operands[0]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) && !get_frame_size () && !current_function_calls_alloca && !frame_pointer_needed && !current_function_args_size)" "* { - extern rtx arm_target_insn; - extern int arm_ccfsm_state; - if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) - { - arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); - output_return_instruction (NULL, TRUE, FALSE); - arm_ccfsm_state = 0; - arm_target_insn = NULL; - } + { + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + output_return_instruction (NULL, TRUE, FALSE); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + } output_return_instruction (NULL, FALSE, FALSE); return NEED_PLT_RELOC ? \"b%?\\t%a0(PLT)\" : \"b%?\\t%a0\"; @@ -6385,24 +7845,21 @@ [(parallel [(set (match_operand 0 "s_register_operand" "=rf") (call (mem:SI (match_operand:SI 1 "" "X")) (match_operand:SI 2 "general_operand" "g"))) - (use (match_operand:SI 3 "" "")) + (use (match_operand 3 "" "")) (clobber (reg:SI 14))]) (return)] - "(GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) + "TARGET_ARM && (GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) && !get_frame_size () && !current_function_calls_alloca && !frame_pointer_needed && !current_function_args_size)" "* { - extern rtx arm_target_insn; - extern int arm_ccfsm_state; - if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) - { - arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); - output_return_instruction (NULL, TRUE, FALSE); - arm_ccfsm_state = 0; - arm_target_insn = NULL; - } + { + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + output_return_instruction (NULL, TRUE, FALSE); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + } output_return_instruction (NULL, FALSE, FALSE); return NEED_PLT_RELOC ? \"b%?\\t%a1(PLT)\" : \"b%?\\t%a1\"; @@ -6417,25 +7874,23 @@ [(parallel [(set (match_operand 0 "s_register_operand" "=rf") (call (mem:SI (match_operand:SI 1 "" "X")) (match_operand:SI 2 "general_operand" "g"))) - (use (match_operand:SI 3 "" "")) + (use (match_operand 3 "" "")) (clobber (reg:SI 14))]) (use (match_dup 0)) (return)] - "(GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) + "TARGET_ARM + && (GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) && !get_frame_size () && !current_function_calls_alloca && !frame_pointer_needed && !current_function_args_size)" "* { - extern rtx arm_target_insn; - extern int arm_ccfsm_state; - if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) - { - arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); - output_return_instruction (NULL, TRUE, FALSE); - arm_ccfsm_state = 0; - arm_target_insn = NULL; - } + { + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + output_return_instruction (NULL, TRUE, FALSE); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + } output_return_instruction (NULL, FALSE, FALSE); return \"b%?\\t%a1\"; @@ -6451,7 +7906,7 @@ [(match_operand:SI 3 "s_register_operand" "") (match_operand:SI 4 "arm_rhs_operand" "")])))) (clobber (match_operand:SI 5 "s_register_operand" ""))] - "" + "TARGET_ARM" [(set (match_dup 5) (not:SI (ashiftrt:SI (match_dup 1) (const_int 31)))) (set (match_dup 0) (and:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) (match_dup 5)))] @@ -6468,8 +7923,9 @@ (const_int 24)) (match_operand 1 "const_int_operand" ""))) (clobber (match_scratch:SI 2 ""))] - "((unsigned HOST_WIDE_INT) INTVAL (operands[1])) - == (((unsigned HOST_WIDE_INT) INTVAL (operands[1])) >> 24) << 24" + "TARGET_ARM + && (((unsigned HOST_WIDE_INT) INTVAL (operands[1])) + == (((unsigned HOST_WIDE_INT) INTVAL (operands[1])) >> 24) << 24)" [(set (match_dup 2) (zero_extend:SI (match_dup 0))) (set (reg:CC 24) (compare:CC (match_dup 2) (match_dup 1)))] " @@ -6478,32 +7934,63 @@ (define_expand "prologue" [(clobber (const_int 0))] - "" - " - arm_expand_prologue (); + "TARGET_EITHER" + "if (TARGET_ARM) + arm_expand_prologue (); + else + thumb_expand_prologue (); DONE; -") + " +) (define_expand "epilogue" - [(unspec_volatile [(return)] 6)] - "" + [(unspec_volatile [(return)] 1)] + "TARGET_EITHER" " - if (USE_RETURN_INSN (FALSE)) + if (TARGET_THUMB) + thumb_expand_epilogue (); + else if (USE_RETURN_INSN (FALSE)) { emit_jump_insn (gen_return ()); DONE; } -") + emit_jump_insn (gen_rtx_UNSPEC_VOLATILE (VOIDmode, + gen_rtvec (1, + gen_rtx_RETURN (VOIDmode)), + 1)); + DONE; + " +) -(define_insn "*epilogue_insn" - [(unspec_volatile [(return)] 6)] - "" +(define_insn "*epilogue_insns" + [(unspec_volatile [(return)] 1)] + "TARGET_EITHER" "* - return arm_output_epilogue (); -" + if (TARGET_ARM) + return arm_output_epilogue (); + else /* TARGET_THUMB */ + return thumb_unexpanded_epilogue (); + " ;; Length is absolute worst case -[(set_attr "length" "44") - (set_attr "type" "block")]) + [(set_attr "length" "44") + (set_attr "type" "block")] +) + +(define_expand "eh_epilogue" + [(use (match_operand:SI 0 "register_operand" "r")) + (use (match_operand:SI 1 "register_operand" "r")) + (use (match_operand:SI 2 "register_operand" "r"))] + "TARGET_EITHER" + " +{ + cfun->machine->eh_epilogue_sp_ofs = operands[1]; + if (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != 2) + { + rtx ra = gen_rtx_REG (Pmode, 2); + emit_move_insn (ra, operands[2]); + operands[2] = ra; + } +}") ;; This split is only used during output to reduce the number of patterns ;; that need assembler instructions adding to them. We allowed the setting @@ -6519,7 +8006,7 @@ (match_operand 4 "" "") (match_operand 5 "" ""))) (clobber (reg:CC 24))] - "reload_completed" + "TARGET_ARM && reload_completed" [(set (match_dup 6) (match_dup 7)) (set (match_dup 0) (if_then_else:SI (match_op_dup 1 [(match_dup 6) (const_int 0)]) @@ -6535,6 +8022,45 @@ } ") +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "arm_add_operand" "")]) + (match_operand:SI 4 "arm_rhs_operand" "") + (not:SI + (match_operand:SI 5 "s_register_operand" "")))) + (clobber (reg:CC 24))] + "TARGET_ARM && reload_completed" + [(set (match_dup 6) (match_dup 7)) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(match_dup 6) (const_int 0)]) + (match_dup 4) + (not:SI (match_dup 5))))] + " +{ + enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], + operands[3]); + + operands[6] = gen_rtx_REG (mode, 24); + operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]); +} +") + +(define_insn "*cond_move_not" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_rhs_operand" "0,?rI") + (not:SI + (match_operand:SI 2 "s_register_operand" "r,r"))))] + "TARGET_ARM" + "@ + mvn%D4\\t%0, %2 + mov%d4\\t%0, %1\;mvn%D4\\t%0, %2" +[(set_attr "conds" "use") + (set_attr "length" "4,8")]) + ;; The next two patterns occur when an AND operation is followed by a ;; scc insn sequence @@ -6543,7 +8069,7 @@ (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r") (const_int 1) (match_operand:SI 2 "const_int_operand" "n")))] - "" + "TARGET_ARM" "* operands[2] = GEN_INT (1 << INTVAL (operands[2])); output_asm_insn (\"ands\\t%0, %1, %2\", operands); @@ -6558,7 +8084,7 @@ (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r") (const_int 1) (match_operand:SI 2 "const_int_operand" "n"))))] - "" + "TARGET_ARM" "* operands[2] = GEN_INT (1 << INTVAL (operands[2])); output_asm_insn (\"tst\\t%1, %2\", operands); @@ -6575,18 +8101,18 @@ [(match_parallel 2 "multi_register_push" [(set (match_operand:BLK 0 "memory_operand" "=m") (unspec:BLK [(match_operand:SI 1 "s_register_operand" "r")] 2))])] - "" + "TARGET_ARM" "* { extern int lr_save_eliminated; int num_saves = XVECLEN (operands[2], 0); - if (lr_save_eliminated) + if (lr_save_eliminated) { if (num_saves > 1) abort (); } - /* For the StrongARM at least it is faster to + /* For the StrongARM at least it is faster to use STR to store only a single register. */ else if (num_saves == 1) output_asm_insn (\"str\\t%1, [%m0, #-4]!\", operands); @@ -6610,7 +8136,7 @@ strcat (pattern, \"}\"); output_asm_insn (pattern, operands); } - + return \"\"; }" [(set_attr "type" "store4")]) @@ -6620,7 +8146,7 @@ [(match_parallel 2 "multi_register_push" [(set (match_operand:BLK 0 "memory_operand" "=m") (unspec:BLK [(match_operand:XF 1 "f_register_operand" "f")] 2))])] - "" + "TARGET_ARM" "* { char pattern[100]; @@ -6633,64 +8159,102 @@ ;; Special patterns for dealing with the constant pool -(define_insn "consttable_4" - [(unspec_volatile [(match_operand 0 "" "")] 2)] - "" +(define_insn "align_4" + [(unspec_volatile [(const_int 0)] 2)] + "TARGET_EITHER" "* -{ - making_const_table = TRUE; - switch (GET_MODE_CLASS (GET_MODE (operands[0]))) - { - case MODE_FLOAT: - { - union real_extract u; - bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); - assemble_real (u.d, GET_MODE (operands[0])); - break; - } - default: - assemble_integer (operands[0], 4, 1); - break; - } + assemble_align (32); return \"\"; -}" -[(set_attr "length" "4")]) + " +) -(define_insn "consttable_8" - [(unspec_volatile [(match_operand 0 "" "")] 3)] - "" +(define_insn "consttable_end" + [(unspec_volatile [(const_int 0)] 3)] + "TARGET_EITHER" "* -{ - making_const_table = TRUE; - switch (GET_MODE_CLASS (GET_MODE (operands[0]))) - { - case MODE_FLOAT: - { - union real_extract u; - bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); - assemble_real (u.d, GET_MODE (operands[0])); - break; - } - default: - assemble_integer (operands[0], 8, 1); - break; - } + making_const_table = FALSE; return \"\"; -}" -[(set_attr "length" "8")]) + " +) -(define_insn "consttable_end" - [(unspec_volatile [(const_int 0)] 4)] - "" +(define_insn "consttable_1" + [(unspec_volatile [(match_operand 0 "" "")] 4)] + "TARGET_THUMB" "* - making_const_table = FALSE; + making_const_table = TRUE; + assemble_integer (operands[0], 1, 1); + assemble_zeros (3); return \"\"; -") + " + [(set_attr "length" "4")] +) -(define_insn "align_4" - [(unspec_volatile [(const_int 0)] 5)] - "" +(define_insn "consttable_2" + [(unspec_volatile [(match_operand 0 "" "")] 5)] + "TARGET_THUMB" "* - assemble_align (32); + making_const_table = TRUE; + assemble_integer (operands[0], 2, 1); + assemble_zeros (2); return \"\"; -") + " + [(set_attr "length" "4")] +) + +(define_insn "consttable_4" + [(unspec_volatile [(match_operand 0 "" "")] 6)] + "TARGET_EITHER" + "* + { + making_const_table = TRUE; + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 4, 1); + break; + } + return \"\"; + }" + [(set_attr "length" "4")] +) + +(define_insn "consttable_8" + [(unspec_volatile [(match_operand 0 "" "")] 7)] + "TARGET_EITHER" + "* + { + making_const_table = TRUE; + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 8, 1); + break; + } + return \"\"; + }" + [(set_attr "length" "8")] +) + +;; Miscellaneous Thumb patterns + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "l*r")) + (use (label_ref (match_operand 1 "" "")))] + "TARGET_THUMB" + "mov pc, %0" + [(set_attr "length" "2")] +) diff --git a/gcc/config/arm/coff.h b/gcc/config/arm/coff.h index f98674bc36a..a083be903ac 100644 --- a/gcc/config/arm/coff.h +++ b/gcc/config/arm/coff.h @@ -1,7 +1,7 @@ -/* Definitions of target machine for GNU compiler, - for ARM with COFF obj format. - Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. - Contributed by Doug Evans (dje@cygnus.com). +/* Definitions of target machine for GNU compiler. + For ARM with COFF object format. + Copyright (C) 1995 - 1999 Free Software Foundation, Inc. + Contributed by Doug Evans (devans@cygnus.com). This file is part of GNU CC. @@ -20,8 +20,8 @@ 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 "arm/semi.h" -#include "arm/aout.h" +#include "semi.h" +#include "aout.h" /* Note - it is important that this definition matches the one in tcoff.h */ #undef USER_LABEL_PREFIX @@ -33,9 +33,12 @@ Boston, MA 02111-1307, USA. */ #define TARGET_VERSION fputs (" (ARM/coff)", stderr) #undef TARGET_DEFAULT -#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32) +#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME) -#define MULTILIB_DEFAULTS { "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork" } +#ifndef MULTILIB_DEFAULTS +#define MULTILIB_DEFAULTS \ + { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork" } +#endif /* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS is a valid machine specific attribute for DECL. @@ -70,16 +73,13 @@ Boston, MA 02111-1307, USA. */ fprintf (STREAM, "%s Generated by gcc %s for ARM/coff\n", \ ASM_COMMENT_START, version_string); \ fprintf (STREAM, ASM_APP_OFF); \ - if (write_symbols == SDB_DEBUG) \ - output_file_directive (STREAM, main_input_filename); \ } \ while (0) -/* A C statement to output something to the assembler file to switch to section - NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or +/* A C statement to output something to the assembler file to switch to + section NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or NULL_TREE. Some target formats do not support arbitrary sections. Do not define this macro in such cases. */ -#undef ASM_OUTPUT_SECTION_NAME #define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ do \ { \ @@ -130,36 +130,36 @@ Boston, MA 02111-1307, USA. */ #define SUBTARGET_EXTRA_SECTION_FUNCTIONS #define RDATA_SECTION_FUNCTION \ -void \ -rdata_section () \ -{ \ - if (in_section != in_rdata) \ - { \ - fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ - in_section = in_rdata; \ - } \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ } #define CTORS_SECTION_FUNCTION \ -void \ -ctors_section () \ -{ \ - if (in_section != in_ctors) \ - { \ - fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ - in_section = in_ctors; \ - } \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ } #define DTORS_SECTION_FUNCTION \ -void \ -dtors_section () \ -{ \ - if (in_section != in_dtors) \ - { \ - fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ - in_section = in_dtors; \ - } \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ } /* Support the ctors/dtors sections for g++. */ @@ -198,6 +198,14 @@ dtors_section () \ #undef DO_GLOBAL_CTORS_BODY #undef DO_GLOBAL_DTORS_BODY +/* If you don't define HAVE_ATEXIT, and the object file format/OS/whatever + does not support constructors/destructors, then gcc implements destructors + by defining its own exit function, which calls the destructors. This gcc + exit function overrides the C library's exit function, and this can cause + all kinds of havoc if the C library has a non-trivial exit function. You + really don't want to use the exit function in libgcc2.c. */ +#define HAVE_ATEXIT + /* The ARM development system defines __main. */ #define NAME__MAIN "__gccmain" #define SYMBOL__MAIN __gccmain diff --git a/gcc/config/arm/elf.h b/gcc/config/arm/elf.h index 893350f04a1..44ce9131376 100644 --- a/gcc/config/arm/elf.h +++ b/gcc/config/arm/elf.h @@ -1,6 +1,6 @@ -/* Definitions of target machine for GNU compiler, - for ARM with ELF obj format. - Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. +/* Definitions of target machine for GNU compiler. + For ARM with ELF obj format. + Copyright (C) 1995 - 1999 Free Software Foundation, Inc. Contributed by Philip Blundell and Catherine Moore @@ -36,6 +36,22 @@ Boston, MA 02111-1307, USA. */ #define SUBTARGET_CPP_SPEC "-Darm_elf -D__ELF__" #endif +#ifndef SUBTARGET_EXTRA_ASM_SPEC +#define SUBTARGET_EXTRA_ASM_SPEC +#endif + +#ifndef ASM_SPEC +#define ASM_SPEC "\ +%{mbig-endian:-EB} \ +%{mcpu=*:-m%*} \ +%{march=*:-m%*} \ +%{mapcs-*:-mapcs-%*} \ +%{mapcs-float:-mfloat} \ +%{msoft-float:-mno-fpu} \ +%{mthumb-interwork:-mthumb-interwork} \ +" SUBTARGET_EXTRA_ASM_SPEC +#endif + /* The following macro defines the format used to output the second operand of the .type assembler directive. Different svr4 assemblers expect various different forms for this operand. The one given here @@ -151,11 +167,6 @@ Boston, MA 02111-1307, USA. */ Otherwise, the readonly data section is used. */ #define JUMP_TABLES_IN_TEXT_SECTION 1 -#ifndef ASM_SPEC -#define ASM_SPEC "%{mbig-endian:-EB} %{mcpu=*:-m%*} %{march=*:-m%*} \ - %{mapcs-*:-mapcs-%*} %{mthumb-interwork:-mthumb-interwork} %{mapcs-float:mfloat}" -#endif - #ifndef LINK_SPEC #define LINK_SPEC "%{mbig-endian:-EB} -X" #endif @@ -166,11 +177,12 @@ Boston, MA 02111-1307, USA. */ #endif #ifndef TARGET_DEFAULT -#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32) +#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME) #endif #ifndef MULTILIB_DEFAULTS -#define MULTILIB_DEFAULTS { "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork" } +#define MULTILIB_DEFAULTS \ + { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" } #endif /* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS @@ -275,30 +287,48 @@ Boston, MA 02111-1307, USA. */ #endif #ifndef CTORS_SECTION_FUNCTION -#define CTORS_SECTION_FUNCTION \ -void \ -ctors_section () \ -{ \ - if (in_section != in_ctors) \ - { \ - fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ - in_section = in_ctors; \ - } \ +#define CTORS_SECTION_FUNCTION \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ } #endif #ifndef DTORS_SECTION_FUNCTION -#define DTORS_SECTION_FUNCTION \ -void \ -dtors_section () \ -{ \ - if (in_section != in_dtors) \ - { \ - fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ - in_section = in_dtors; \ - } \ +#define DTORS_SECTION_FUNCTION \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ } #endif + +/* A C statement to output something to the assembler file to switch to + section NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL + or NULL_TREE. */ +#undef ASM_OUTPUT_SECTION_NAME +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ + do \ + { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"ax\",%%progbits\n", NAME); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"a\"\n", NAME); \ + else if (! strncmp (NAME, ".bss", 4)) \ + fprintf (STREAM, "\t.section %s,\"aw\",%%nobits\n", NAME); \ + else \ + fprintf (STREAM, "\t.section %s,\"aw\"\n", NAME); \ + } \ + while (0) /* Support the ctors/dtors sections for g++. */ #ifndef INT_ASM_OP @@ -367,4 +397,4 @@ dtors_section () \ } \ while (0) -#include "arm/aout.h" +#include "aout.h" diff --git a/gcc/config/arm/lib1funcs.asm b/gcc/config/arm/lib1funcs.asm index 07b50a71fc4..07f69b55785 100644 --- a/gcc/config/arm/lib1funcs.asm +++ b/gcc/config/arm/lib1funcs.asm @@ -1,7 +1,7 @@ @ libgcc1 routines for ARM cpu. @ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) -/* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996, 1998, 1999, 2000 Free Software Foundation, Inc. This file is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -34,12 +34,12 @@ Boston, MA 02111-1307, USA. */ the executable file might be covered by the GNU General Public License. */ #ifdef __APCS_26__ -#define RET movs -#define RETc(x) mov##x##s +#define RET movs pc, lr +#define RETc(x) mov##x##s pc, lr #define RETCOND ^ #else -#define RET mov -#define RETc(x) mov##x +#define RET mov pc, lr +#define RETc(x) mov##x pc, lr #define RETCOND #endif @@ -57,7 +57,11 @@ Boston, MA 02111-1307, USA. */ #define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) #ifdef __ELF__ +#ifdef __thumb__ +#define __PLT__ /* Not supported in thumb assembler (for now). */ +#else #define __PLT__ (PLT) +#endif #define TYPE(x) .type SYM(x),function #define SIZE(x) .size SYM(x), . - SYM(x) #else @@ -66,6 +70,28 @@ Boston, MA 02111-1307, USA. */ #define SIZE(x) #endif +#ifdef __thumb__ +#define THUMB_FUNC .thumb_func +#define THUMB_CODE .force_thumb +#else +#define THUMB_FUNC +#define THUMB_CODE +#endif + + +.macro FUNC_START name + .text + .globl SYM (__\name) + TYPE (__\name) + .align 0 + THUMB_CODE + THUMB_FUNC +SYM (__\name): +.endm + +/* Used for Thumb code. */ +work .req r4 @ XXXX is this safe ? + #ifdef L_udivsi3 dividend .req r0 @@ -77,12 +103,99 @@ sp .req r13 lr .req r14 pc .req r15 - .text - .globl SYM (__udivsi3) - TYPE (__udivsi3) - .align 0 + FUNC_START udivsi3 + +#ifdef __thumb__ -SYM (__udivsi3): + cmp divisor, #0 + beq Ldiv0 + mov curbit, #1 + mov result, #0 + + push { work } + cmp dividend, divisor + bcc Lgot_result + + @ Load the constant 0x10000000 into our work register + mov work, #1 + lsl work, #28 +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + bcs Lbignum + cmp divisor, dividend + bcs Lbignum + lsl divisor, #4 + lsl curbit, #4 + b Loop1 + +Lbignum: + @ Set work to 0x80000000 + lsl work, #3 +Loop2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, work + bcs Loop3 + cmp divisor, dividend + bcs Loop3 + lsl divisor, #1 + lsl curbit, #1 + b Loop2 + +Loop3: + @ Test for possible subtractions, and note which bits + @ are done in the result. On the final pass, this may subtract + @ too much from the dividend, but the result will be ok, since the + @ "bit" will have been shifted out at the bottom. + cmp dividend, divisor + bcc Over1 + sub dividend, dividend, divisor + orr result, result, curbit +Over1: + lsr work, divisor, #1 + cmp dividend, work + bcc Over2 + sub dividend, dividend, work + lsr work, curbit, #1 + orr result, work +Over2: + lsr work, divisor, #2 + cmp dividend, work + bcc Over3 + sub dividend, dividend, work + lsr work, curbit, #2 + orr result, work +Over3: + lsr work, divisor, #3 + cmp dividend, work + bcc Over4 + sub dividend, dividend, work + lsr work, curbit, #3 + orr result, work +Over4: + cmp dividend, #0 @ Early termination? + beq Lgot_result + lsr curbit, #4 @ No, any more bits to do? + beq Lgot_result + lsr divisor, #4 + b Loop3 +Lgot_result: + mov r0, result + pop { work } + RET + +Ldiv0: + push { lr } + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + pop { pc } + +#else /* arm version */ + cmp divisor, #0 beq Ldiv0 mov curbit, #1 @@ -132,7 +245,7 @@ Loop3: bne Loop3 Lgot_result: mov r0, result - RET pc, lr + RET Ldiv0: str lr, [sp, #-4]! @@ -140,7 +253,9 @@ Ldiv0: mov r0, #0 @ about as wrong as it could be ldmia sp!, {pc}RETCOND - SIZE (__udivsi3) +#endif /* arm version */ + + SIZE (__udivsi3) #endif /* L_udivsi3 */ @@ -155,17 +270,147 @@ sp .req r13 lr .req r14 pc .req r15 - .text - .globl SYM (__umodsi3) - TYPE (__umodsi3) - .align 0 + FUNC_START umodsi3 + +#ifdef __thumb__ -SYM (__umodsi3): cmp divisor, #0 beq Ldiv0 mov curbit, #1 cmp dividend, divisor - RETc(cc) pc, lr + bcs Over1 + RET + +Over1: + @ Load the constant 0x10000000 into our work register + push { work } + mov work, #1 + lsl work, #28 +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + bcs Lbignum + cmp divisor, dividend + bcs Lbignum + lsl divisor, #4 + lsl curbit, #4 + b Loop1 +Lbignum: + @ Set work to 0x80000000 + lsl work, #3 +Loop2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, work + bcs Loop3 + cmp divisor, dividend + bcs Loop3 + lsl divisor, #1 + lsl curbit, #1 + b Loop2 +Loop3: + @ Test for possible subtractions. On the final pass, this may + @ subtract too much from the dividend, so keep track of which + @ subtractions are done, we can fix them up afterwards... + mov overdone, #0 + cmp dividend, divisor + bcc Over2 + sub dividend, dividend, divisor +Over2: + lsr work, divisor, #1 + cmp dividend, work + bcc Over3 + sub dividend, dividend, work + mov ip, curbit + mov work, #1 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over3: + lsr work, divisor, #2 + cmp dividend, work + bcc Over4 + sub dividend, dividend, work + mov ip, curbit + mov work, #2 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over4: + lsr work, divisor, #3 + cmp dividend, work + bcc Over5 + sub dividend, dividend, work + mov ip, curbit + mov work, #3 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over5: + mov ip, curbit + cmp dividend, #0 @ Early termination? + beq Over6 + lsr curbit, #4 @ No, any more bits to do? + beq Over6 + lsr divisor, #4 + b Loop3 +Over6: + @ Any subtractions that we should not have done will be recorded in + @ the top three bits of "overdone". Exactly which were not needed + @ are governed by the position of the bit, stored in ip. + @ If we terminated early, because dividend became zero, + @ then none of the below will match, since the bit in ip will not be + @ in the bottom nibble. + + mov work, #0xe + lsl work, #28 + and overdone, work + bne Over7 + pop { work } + RET @ No fixups needed +Over7: + mov curbit, ip + mov work, #3 + ror curbit, work + tst overdone, curbit + beq Over8 + lsr work, divisor, #3 + add dividend, dividend, work +Over8: + mov curbit, ip + mov work, #2 + ror curbit, work + tst overdone, curbit + beq Over9 + lsr work, divisor, #2 + add dividend, dividend, work +Over9: + mov curbit, ip + mov work, #1 + ror curbit, work + tst overdone, curbit + beq Over10 + lsr work, divisor, #1 + add dividend, dividend, work +Over10: + pop { work } + RET +Ldiv0: + push { lr } + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + pop { pc } + +#else /* arm version */ + + cmp divisor, #0 + beq Ldiv0 + mov curbit, #1 + cmp dividend, divisor + RETc(cc) Loop1: @ Unless the divisor is very big, shift it up in multiples of @ four bits, since this is the amount of unwinding in the main @@ -215,14 +460,14 @@ Loop3: @ then none of the below will match, since the bit in ip will not be @ in the bottom nibble. ands overdone, overdone, #0xe0000000 - RETc(eq) pc, lr @ No fixups needed + RETc(eq) @ No fixups needed tst overdone, ip, ror #3 addne dividend, dividend, divisor, lsr #3 tst overdone, ip, ror #2 addne dividend, dividend, divisor, lsr #2 tst overdone, ip, ror #1 addne dividend, dividend, divisor, lsr #1 - RET pc, lr + RET Ldiv0: str lr, [sp, #-4]! @@ -230,7 +475,9 @@ Ldiv0: mov r0, #0 @ about as wrong as it could be ldmia sp!, {pc}RETCOND - SIZE (__umodsi3) +#endif /* arm version */ + + SIZE (__umodsi3) #endif /* L_umodsi3 */ @@ -244,13 +491,114 @@ ip .req r12 sp .req r13 lr .req r14 pc .req r15 + + FUNC_START divsi3 + +#ifdef __thumb__ + cmp divisor, #0 + beq Ldiv0 - .text - .globl SYM (__divsi3) - TYPE (__divsi3) - .align 0 + push { work } + mov work, dividend + eor work, divisor @ Save the sign of the result. + mov ip, work + mov curbit, #1 + mov result, #0 + cmp divisor, #0 + bpl Over1 + neg divisor, divisor @ Loops below use unsigned. +Over1: + cmp dividend, #0 + bpl Over2 + neg dividend, dividend +Over2: + cmp dividend, divisor + bcc Lgot_result + + mov work, #1 + lsl work, #28 +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + Bcs Lbignum + cmp divisor, dividend + Bcs Lbignum + lsl divisor, #4 + lsl curbit, #4 + b Loop1 + +Lbignum: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + lsl work, #3 +Loop2: + cmp divisor, work + Bcs Loop3 + cmp divisor, dividend + Bcs Loop3 + lsl divisor, #1 + lsl curbit, #1 + b Loop2 + +Loop3: + @ Test for possible subtractions, and note which bits + @ are done in the result. On the final pass, this may subtract + @ too much from the dividend, but the result will be ok, since the + @ "bit" will have been shifted out at the bottom. + cmp dividend, divisor + Bcc Over3 + sub dividend, dividend, divisor + orr result, result, curbit +Over3: + lsr work, divisor, #1 + cmp dividend, work + Bcc Over4 + sub dividend, dividend, work + lsr work, curbit, #1 + orr result, work +Over4: + lsr work, divisor, #2 + cmp dividend, work + Bcc Over5 + sub dividend, dividend, work + lsr work, curbit, #2 + orr result, result, work +Over5: + lsr work, divisor, #3 + cmp dividend, work + Bcc Over6 + sub dividend, dividend, work + lsr work, curbit, #3 + orr result, result, work +Over6: + cmp dividend, #0 @ Early termination? + Beq Lgot_result + lsr curbit, #4 @ No, any more bits to do? + Beq Lgot_result + lsr divisor, #4 + b Loop3 + +Lgot_result: + mov r0, result + mov work, ip + cmp work, #0 + Bpl Over7 + neg r0, r0 +Over7: + pop { work } + RET -SYM (__divsi3): +Ldiv0: + push { lr } + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + pop { pc } + +#else /* arm version */ + eor ip, dividend, divisor @ Save the sign of the result. mov curbit, #1 mov result, #0 @@ -307,7 +655,7 @@ Lgot_result: mov r0, result cmp ip, #0 rsbmi r0, r0, #0 - RET pc, lr + RET Ldiv0: str lr, [sp, #-4]! @@ -315,7 +663,9 @@ Ldiv0: mov r0, #0 @ about as wrong as it could be ldmia sp!, {pc}RETCOND - SIZE (__divsi3) +#endif /* arm version */ + + SIZE (__divsi3) #endif /* L_divsi3 */ @@ -330,12 +680,155 @@ sp .req r13 lr .req r14 pc .req r15 - .text - .globl SYM (__modsi3) - TYPE (__modsi3) - .align 0 + FUNC_START modsi3 + +#ifdef __thumb__ -SYM (__modsi3): + mov curbit, #1 + cmp divisor, #0 + beq Ldiv0 + Bpl Over1 + neg divisor, divisor @ Loops below use unsigned. +Over1: + push { work } + @ Need to save the sign of the dividend, unfortunately, we need + @ ip later on. Must do this after saving the original value of + @ the work register, because we will pop this value off first. + push { dividend } + cmp dividend, #0 + Bpl Over2 + neg dividend, dividend +Over2: + cmp dividend, divisor + bcc Lgot_result + mov work, #1 + lsl work, #28 +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + bcs Lbignum + cmp divisor, dividend + bcs Lbignum + lsl divisor, #4 + lsl curbit, #4 + b Loop1 + +Lbignum: + @ Set work to 0x80000000 + lsl work, #3 +Loop2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, work + bcs Loop3 + cmp divisor, dividend + bcs Loop3 + lsl divisor, #1 + lsl curbit, #1 + b Loop2 + +Loop3: + @ Test for possible subtractions. On the final pass, this may + @ subtract too much from the dividend, so keep track of which + @ subtractions are done, we can fix them up afterwards... + mov overdone, #0 + cmp dividend, divisor + bcc Over3 + sub dividend, dividend, divisor +Over3: + lsr work, divisor, #1 + cmp dividend, work + bcc Over4 + sub dividend, dividend, work + mov ip, curbit + mov work, #1 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over4: + lsr work, divisor, #2 + cmp dividend, work + bcc Over5 + sub dividend, dividend, work + mov ip, curbit + mov work, #2 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over5: + lsr work, divisor, #3 + cmp dividend, work + bcc Over6 + sub dividend, dividend, work + mov ip, curbit + mov work, #3 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over6: + mov ip, curbit + cmp dividend, #0 @ Early termination? + beq Over7 + lsr curbit, #4 @ No, any more bits to do? + beq Over7 + lsr divisor, #4 + b Loop3 + +Over7: + @ Any subtractions that we should not have done will be recorded in + @ the top three bits of "overdone". Exactly which were not needed + @ are governed by the position of the bit, stored in ip. + @ If we terminated early, because dividend became zero, + @ then none of the below will match, since the bit in ip will not be + @ in the bottom nibble. + mov work, #0xe + lsl work, #28 + and overdone, work + beq Lgot_result + + mov curbit, ip + mov work, #3 + ror curbit, work + tst overdone, curbit + beq Over8 + lsr work, divisor, #3 + add dividend, dividend, work +Over8: + mov curbit, ip + mov work, #2 + ror curbit, work + tst overdone, curbit + beq Over9 + lsr work, divisor, #2 + add dividend, dividend, work +Over9: + mov curbit, ip + mov work, #1 + ror curbit, work + tst overdone, curbit + beq Lgot_result + lsr work, divisor, #1 + add dividend, dividend, work +Lgot_result: + pop { work } + cmp work, #0 + bpl Over10 + neg dividend, dividend +Over10: + pop { work } + RET + +Ldiv0: + push { lr } + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + pop { pc } + +#else /* arm version */ + mov curbit, #1 cmp divisor, #0 rsbmi divisor, divisor, #0 @ Loops below use unsigned. @@ -408,7 +901,7 @@ Lgot_result: ldr ip, [sp], #4 cmp ip, #0 rsbmi dividend, dividend, #0 - RET pc, lr + RET Ldiv0: str lr, [sp, #-4]! @@ -416,19 +909,19 @@ Ldiv0: mov r0, #0 @ about as wrong as it could be ldmia sp!, {pc}RETCOND - SIZE (__modsi3) +#endif /* arm version */ + + SIZE (__modsi3) #endif /* L_modsi3 */ #ifdef L_dvmd_tls - .globl SYM (__div0) - TYPE (__div0) - .align 0 -SYM (__div0): - RET pc, lr + FUNC_START div0 - SIZE (__div0) + RET + + SIZE (__div0) #endif /* L_divmodsi_tools */ @@ -439,10 +932,8 @@ SYM (__div0): #define SIGFPE 8 @ cant use as it @ contains too much C rubbish - .globl SYM (__div0) - TYPE (__div0) - .align 0 -SYM (__div0): + FUNC_START div0 + stmfd sp!, {r1, lr} swi __NR_getpid cmn r0, #1000 @@ -451,7 +942,7 @@ SYM (__div0): swi __NR_kill ldmfd sp!, {r1, pc}RETCOND - SIZE (__div0) + SIZE (__div0) #endif /* L_dvmd_lnx */ @@ -459,7 +950,10 @@ SYM (__div0): assembler because their presence allows interworked code to be linked even when the GCC library is this one. */ -#ifdef L_call_via_rX +/* Do not build the interworking functions when the target cpu + is the arm v3 architecture. (This is one of the multilib + options). */ +#if defined L_call_via_rX && ! defined __ARM_ARCH_3__ /* These labels & instructions are used by the Arm/Thumb interworking code. The address of function to be called is loaded into a register and then @@ -499,8 +993,11 @@ SYM (_call_via_\register): #endif /* L_call_via_rX */ -#ifdef L_interwork_call_via_rX - +/* Do not build the interworking functions when the target cpu + is the arm v3 architecture. (This is one of the multilib + options). */ +#if defined L_interwork_call_via_rX && ! defined __ARM_ARCH_3__ + /* These labels & instructions are used by the Arm/Thumb interworking code, when the target address is in an unknown instruction set. The address of function to be called is loaded into a register and then one of these diff --git a/gcc/config/arm/lib1thumb.asm b/gcc/config/arm/lib1thumb.asm deleted file mode 100644 index daf8361097b..00000000000 --- a/gcc/config/arm/lib1thumb.asm +++ /dev/null @@ -1,749 +0,0 @@ -@ libgcc1 routines for ARM cpu. -@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) - -/* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. - -This file 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. - -In addition to the permissions in the GNU General Public License, the -Free Software Foundation gives you unlimited permission to link the -compiled version of this file with other programs, and to distribute -those programs without any restriction coming from the use of this -file. (The General Public License restrictions do apply in other -respects; for example, they cover modification of the file, and -distribution when not linked into another program.) - -This file 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 this program; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* As a special exception, if you link this library with other files, - some of which are compiled with GCC, to produce an executable, - this library does not by itself cause the resulting executable - to be covered by the GNU General Public License. - This exception does not however invalidate any other reasons why - the executable file might be covered by the GNU General Public License. */ - - .code 16 - -#ifndef __USER_LABEL_PREFIX__ -#error __USER_LABEL_PREFIX__ not defined -#endif - -#ifdef __elf__ -#define __PLT__ (PLT) -#define TYPE(x) .type SYM(x),function -#define SIZE(x) .size SYM(x), . - SYM(x) -#else -#define __PLT__ -#define TYPE(x) -#define SIZE(x) -#endif - -#define RET mov pc, lr - -/* ANSI concatenation macros. */ - -#define CONCAT1(a, b) CONCAT2(a, b) -#define CONCAT2(a, b) a ## b - -/* Use the right prefix for global labels. */ - -#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) - -work .req r4 @ XXXX is this safe ? - -#ifdef L_udivsi3 - -dividend .req r0 -divisor .req r1 -result .req r2 -curbit .req r3 -ip .req r12 -sp .req r13 -lr .req r14 -pc .req r15 - - .text - .globl SYM (__udivsi3) - TYPE (__udivsi3) - .align 0 - .thumb_func -SYM (__udivsi3): - cmp divisor, #0 - beq Ldiv0 - mov curbit, #1 - mov result, #0 - - push { work } - cmp dividend, divisor - bcc Lgot_result - - @ Load the constant 0x10000000 into our work register - mov work, #1 - lsl work, #28 -Loop1: - @ Unless the divisor is very big, shift it up in multiples of - @ four bits, since this is the amount of unwinding in the main - @ division loop. Continue shifting until the divisor is - @ larger than the dividend. - cmp divisor, work - bcs Lbignum - cmp divisor, dividend - bcs Lbignum - lsl divisor, #4 - lsl curbit, #4 - b Loop1 - -Lbignum: - @ Set work to 0x80000000 - lsl work, #3 -Loop2: - @ For very big divisors, we must shift it a bit at a time, or - @ we will be in danger of overflowing. - cmp divisor, work - bcs Loop3 - cmp divisor, dividend - bcs Loop3 - lsl divisor, #1 - lsl curbit, #1 - b Loop2 - -Loop3: - @ Test for possible subtractions, and note which bits - @ are done in the result. On the final pass, this may subtract - @ too much from the dividend, but the result will be ok, since the - @ "bit" will have been shifted out at the bottom. - cmp dividend, divisor - bcc Over1 - sub dividend, dividend, divisor - orr result, result, curbit -Over1: - lsr work, divisor, #1 - cmp dividend, work - bcc Over2 - sub dividend, dividend, work - lsr work, curbit, #1 - orr result, work -Over2: - lsr work, divisor, #2 - cmp dividend, work - bcc Over3 - sub dividend, dividend, work - lsr work, curbit, #2 - orr result, work -Over3: - lsr work, divisor, #3 - cmp dividend, work - bcc Over4 - sub dividend, dividend, work - lsr work, curbit, #3 - orr result, work -Over4: - cmp dividend, #0 @ Early termination? - beq Lgot_result - lsr curbit, #4 @ No, any more bits to do? - beq Lgot_result - lsr divisor, #4 - b Loop3 -Lgot_result: - mov r0, result - pop { work } - RET - -Ldiv0: - push { lr } - bl SYM (__div0) __PLT__ - mov r0, #0 @ about as wrong as it could be - pop { pc } - - SIZE (__udivsi3) - -#endif /* L_udivsi3 */ - -#ifdef L_umodsi3 - -dividend .req r0 -divisor .req r1 -overdone .req r2 -curbit .req r3 -ip .req r12 -sp .req r13 -lr .req r14 -pc .req r15 - - .text - .globl SYM (__umodsi3) - TYPE (__umodsi3) - .align 0 - .thumb_func -SYM (__umodsi3): - cmp divisor, #0 - beq Ldiv0 - mov curbit, #1 - cmp dividend, divisor - bcs Over1 - RET - -Over1: - @ Load the constant 0x10000000 into our work register - push { work } - mov work, #1 - lsl work, #28 -Loop1: - @ Unless the divisor is very big, shift it up in multiples of - @ four bits, since this is the amount of unwinding in the main - @ division loop. Continue shifting until the divisor is - @ larger than the dividend. - cmp divisor, work - bcs Lbignum - cmp divisor, dividend - bcs Lbignum - lsl divisor, #4 - lsl curbit, #4 - b Loop1 - -Lbignum: - @ Set work to 0x80000000 - lsl work, #3 -Loop2: - @ For very big divisors, we must shift it a bit at a time, or - @ we will be in danger of overflowing. - cmp divisor, work - bcs Loop3 - cmp divisor, dividend - bcs Loop3 - lsl divisor, #1 - lsl curbit, #1 - b Loop2 - -Loop3: - @ Test for possible subtractions. On the final pass, this may - @ subtract too much from the dividend, so keep track of which - @ subtractions are done, we can fix them up afterwards... - mov overdone, #0 - cmp dividend, divisor - bcc Over2 - sub dividend, dividend, divisor -Over2: - lsr work, divisor, #1 - cmp dividend, work - bcc Over3 - sub dividend, dividend, work - mov ip, curbit - mov work, #1 - ror curbit, work - orr overdone, curbit - mov curbit, ip -Over3: - lsr work, divisor, #2 - cmp dividend, work - bcc Over4 - sub dividend, dividend, work - mov ip, curbit - mov work, #2 - ror curbit, work - orr overdone, curbit - mov curbit, ip -Over4: - lsr work, divisor, #3 - cmp dividend, work - bcc Over5 - sub dividend, dividend, work - mov ip, curbit - mov work, #3 - ror curbit, work - orr overdone, curbit - mov curbit, ip -Over5: - mov ip, curbit - cmp dividend, #0 @ Early termination? - beq Over6 - lsr curbit, #4 @ No, any more bits to do? - beq Over6 - lsr divisor, #4 - b Loop3 - -Over6: - @ Any subtractions that we should not have done will be recorded in - @ the top three bits of "overdone". Exactly which were not needed - @ are governed by the position of the bit, stored in ip. - @ If we terminated early, because dividend became zero, - @ then none of the below will match, since the bit in ip will not be - @ in the bottom nibble. - - mov work, #0xe - lsl work, #28 - and overdone, work - bne Over7 - pop { work } - RET @ No fixups needed -Over7: - mov curbit, ip - mov work, #3 - ror curbit, work - tst overdone, curbit - beq Over8 - lsr work, divisor, #3 - add dividend, dividend, work -Over8: - mov curbit, ip - mov work, #2 - ror curbit, work - tst overdone, curbit - beq Over9 - lsr work, divisor, #2 - add dividend, dividend, work -Over9: - mov curbit, ip - mov work, #1 - ror curbit, work - tst overdone, curbit - beq Over10 - lsr work, divisor, #1 - add dividend, dividend, work -Over10: - pop { work } - RET - -Ldiv0: - push { lr } - bl SYM (__div0) __PLT__ - mov r0, #0 @ about as wrong as it could be - pop { pc } - - SIZE (__umodsi3) - -#endif /* L_umodsi3 */ - -#ifdef L_divsi3 - -dividend .req r0 -divisor .req r1 -result .req r2 -curbit .req r3 -ip .req r12 -sp .req r13 -lr .req r14 -pc .req r15 - - .text - .globl SYM (__divsi3) - TYPE (__divsi3) - .align 0 - .thumb_func -SYM (__divsi3): - cmp divisor, #0 - beq Ldiv0 - - push { work } - mov work, dividend - eor work, divisor @ Save the sign of the result. - mov ip, work - mov curbit, #1 - mov result, #0 - cmp divisor, #0 - bpl Over1 - neg divisor, divisor @ Loops below use unsigned. -Over1: - cmp dividend, #0 - bpl Over2 - neg dividend, dividend -Over2: - cmp dividend, divisor - bcc Lgot_result - - mov work, #1 - lsl work, #28 -Loop1: - @ Unless the divisor is very big, shift it up in multiples of - @ four bits, since this is the amount of unwinding in the main - @ division loop. Continue shifting until the divisor is - @ larger than the dividend. - cmp divisor, work - Bcs Lbignum - cmp divisor, dividend - Bcs Lbignum - lsl divisor, #4 - lsl curbit, #4 - b Loop1 - -Lbignum: - @ For very big divisors, we must shift it a bit at a time, or - @ we will be in danger of overflowing. - lsl work, #3 -Loop2: - cmp divisor, work - Bcs Loop3 - cmp divisor, dividend - Bcs Loop3 - lsl divisor, #1 - lsl curbit, #1 - b Loop2 - -Loop3: - @ Test for possible subtractions, and note which bits - @ are done in the result. On the final pass, this may subtract - @ too much from the dividend, but the result will be ok, since the - @ "bit" will have been shifted out at the bottom. - cmp dividend, divisor - Bcc Over3 - sub dividend, dividend, divisor - orr result, result, curbit -Over3: - lsr work, divisor, #1 - cmp dividend, work - Bcc Over4 - sub dividend, dividend, work - lsr work, curbit, #1 - orr result, work -Over4: - lsr work, divisor, #2 - cmp dividend, work - Bcc Over5 - sub dividend, dividend, work - lsr work, curbit, #2 - orr result, result, work -Over5: - lsr work, divisor, #3 - cmp dividend, work - Bcc Over6 - sub dividend, dividend, work - lsr work, curbit, #3 - orr result, result, work -Over6: - cmp dividend, #0 @ Early termination? - Beq Lgot_result - lsr curbit, #4 @ No, any more bits to do? - Beq Lgot_result - lsr divisor, #4 - b Loop3 - -Lgot_result: - mov r0, result - mov work, ip - cmp work, #0 - Bpl Over7 - neg r0, r0 -Over7: - pop { work } - RET - -Ldiv0: - push { lr } - bl SYM (__div0) __PLT__ - mov r0, #0 @ about as wrong as it could be - pop { pc } - - SIZE (__divsi3) - -#endif /* L_divsi3 */ - -#ifdef L_modsi3 - -dividend .req r0 -divisor .req r1 -overdone .req r2 -curbit .req r3 -ip .req r12 -sp .req r13 -lr .req r14 -pc .req r15 - - .text - .globl SYM (__modsi3) - TYPE (__modsi3) - .align 0 - .thumb_func -SYM (__modsi3): - mov curbit, #1 - cmp divisor, #0 - beq Ldiv0 - Bpl Over1 - neg divisor, divisor @ Loops below use unsigned. -Over1: - push { work } - @ Need to save the sign of the dividend, unfortunately, we need - @ ip later on. Must do this after saving the original value of - @ the work register, because we will pop this value off first. - push { dividend } - cmp dividend, #0 - Bpl Over2 - neg dividend, dividend -Over2: - cmp dividend, divisor - bcc Lgot_result - mov work, #1 - lsl work, #28 -Loop1: - @ Unless the divisor is very big, shift it up in multiples of - @ four bits, since this is the amount of unwinding in the main - @ division loop. Continue shifting until the divisor is - @ larger than the dividend. - cmp divisor, work - bcs Lbignum - cmp divisor, dividend - bcs Lbignum - lsl divisor, #4 - lsl curbit, #4 - b Loop1 - -Lbignum: - @ Set work to 0x80000000 - lsl work, #3 -Loop2: - @ For very big divisors, we must shift it a bit at a time, or - @ we will be in danger of overflowing. - cmp divisor, work - bcs Loop3 - cmp divisor, dividend - bcs Loop3 - lsl divisor, #1 - lsl curbit, #1 - b Loop2 - -Loop3: - @ Test for possible subtractions. On the final pass, this may - @ subtract too much from the dividend, so keep track of which - @ subtractions are done, we can fix them up afterwards... - mov overdone, #0 - cmp dividend, divisor - bcc Over3 - sub dividend, dividend, divisor -Over3: - lsr work, divisor, #1 - cmp dividend, work - bcc Over4 - sub dividend, dividend, work - mov ip, curbit - mov work, #1 - ror curbit, work - orr overdone, curbit - mov curbit, ip -Over4: - lsr work, divisor, #2 - cmp dividend, work - bcc Over5 - sub dividend, dividend, work - mov ip, curbit - mov work, #2 - ror curbit, work - orr overdone, curbit - mov curbit, ip -Over5: - lsr work, divisor, #3 - cmp dividend, work - bcc Over6 - sub dividend, dividend, work - mov ip, curbit - mov work, #3 - ror curbit, work - orr overdone, curbit - mov curbit, ip -Over6: - mov ip, curbit - cmp dividend, #0 @ Early termination? - beq Over7 - lsr curbit, #4 @ No, any more bits to do? - beq Over7 - lsr divisor, #4 - b Loop3 - -Over7: - @ Any subtractions that we should not have done will be recorded in - @ the top three bits of "overdone". Exactly which were not needed - @ are governed by the position of the bit, stored in ip. - @ If we terminated early, because dividend became zero, - @ then none of the below will match, since the bit in ip will not be - @ in the bottom nibble. - mov work, #0xe - lsl work, #28 - and overdone, work - beq Lgot_result - - mov curbit, ip - mov work, #3 - ror curbit, work - tst overdone, curbit - beq Over8 - lsr work, divisor, #3 - add dividend, dividend, work -Over8: - mov curbit, ip - mov work, #2 - ror curbit, work - tst overdone, curbit - beq Over9 - lsr work, divisor, #2 - add dividend, dividend, work -Over9: - mov curbit, ip - mov work, #1 - ror curbit, work - tst overdone, curbit - beq Lgot_result - lsr work, divisor, #1 - add dividend, dividend, work -Lgot_result: - pop { work } - cmp work, #0 - bpl Over10 - neg dividend, dividend -Over10: - pop { work } - RET - -Ldiv0: - push { lr } - bl SYM (__div0) __PLT__ - mov r0, #0 @ about as wrong as it could be - pop { pc } - - SIZE (__modsi3) - -#endif /* L_modsi3 */ - -#ifdef L_dvmd_tls - - .globl SYM (__div0) - TYPE (__div0) - .align 0 - .thumb_func -SYM (__div0): - RET - - SIZE (__div0) - -#endif /* L_divmodsi_tools */ - - -#ifdef L_call_via_rX - -/* These labels & instructions are used by the Arm/Thumb interworking code. - The address of function to be called is loaded into a register and then - one of these labels is called via a BL instruction. This puts the - return address into the link register with the bottom bit set, and the - code here switches to the correct mode before executing the function. */ - - .text - .align 0 - -.macro call_via register - .globl SYM (_call_via_\register) - TYPE (_call_via_\register) - .thumb_func -SYM (_call_via_\register): - bx \register - nop - - SIZE (_call_via_\register) -.endm - - call_via r0 - call_via r1 - call_via r2 - call_via r3 - call_via r4 - call_via r5 - call_via r6 - call_via r7 - call_via r8 - call_via r9 - call_via sl - call_via fp - call_via ip - call_via sp - call_via lr - -#endif /* L_call_via_rX */ - -#ifdef L_interwork_call_via_rX - -/* These labels & instructions are used by the Arm/Thumb interworking code, - when the target address is in an unknown instruction set. The address - of function to be called is loaded into a register and then one of these - labels is called via a BL instruction. This puts the return address - into the link register with the bottom bit set, and the code here - switches to the correct mode before executing the function. Unfortunately - the target code cannot be relied upon to return via a BX instruction, so - instead we have to store the resturn address on the stack and allow the - called function to return here instead. Upon return we recover the real - return address and use a BX to get back to Thumb mode. */ - - .text - .align 0 - - .code 32 - .globl _arm_return -_arm_return: - ldmia r13!, {r12} - bx r12 - -.macro interwork register - .code 16 - - .globl SYM (_interwork_call_via_\register) - TYPE (_interwork_call_via_\register) - .thumb_func -SYM (_interwork_call_via_\register): - bx pc - nop - - .code 32 - .globl .Lchange_\register -.Lchange_\register: - tst \register, #1 - stmeqdb r13!, {lr} - adreq lr, _arm_return - bx \register - - SIZE (_interwork_call_via_\register) -.endm - - interwork r0 - interwork r1 - interwork r2 - interwork r3 - interwork r4 - interwork r5 - interwork r6 - interwork r7 - interwork r8 - interwork r9 - interwork sl - interwork fp - interwork ip - interwork sp - - /* The lr case has to be handled a little differently...*/ - .code 16 - .globl SYM (_interwork_call_via_lr) - TYPE (_interwork_call_via_lr) - .thumb_func -SYM (_interwork_call_via_lr): - bx pc - nop - - .code 32 - .globl .Lchange_lr -.Lchange_lr: - tst lr, #1 - stmeqdb r13!, {lr} - mov ip, lr - adreq lr, _arm_return - bx ip - - SIZE (_interwork_call_via_lr) - -#endif /* L_interwork_call_via_rX */ - - diff --git a/gcc/config/arm/linux-elf.h b/gcc/config/arm/linux-elf.h index 598d1c93a06..f357d67e4d1 100644 --- a/gcc/config/arm/linux-elf.h +++ b/gcc/config/arm/linux-elf.h @@ -38,7 +38,7 @@ Boston, MA 02111-1307, USA. */ # define SUBTARGET_EXTRA_ASM_SPEC \ " %{mapcs-26:-mapcs-26} %{!mapcs-26:-mapcs-32}" # define MULTILIB_DEFAULTS \ - { "mlittle-endian", "mhard-float", "mapcs-32", "mno-thumb-interwork" } + { "marm", "mlittle-endian", "mhard-float", "mapcs-32", "mno-thumb-interwork" } # define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" #else /* default is APCS-26 */ # define TARGET_DEFAULT (ARM_FLAG_MMU_TRAPS) @@ -52,7 +52,7 @@ Boston, MA 02111-1307, USA. */ # define SUBTARGET_EXTRA_ASM_SPEC \ " %{mapcs-32:-mapcs-32} %{!mapcs-32:-mapcs-26}" # define MULTILIB_DEFAULTS \ - { "mlittle-endian", "mhard-float", "mapcs-26", "mno-thumb-interwork" } + { "marm", "mlittle-endian", "mhard-float", "mapcs-26", "mno-thumb-interwork" } #endif /* This was defined in linux.h. Define it here also. */ @@ -103,13 +103,6 @@ Boston, MA 02111-1307, USA. */ %{mbig-endian:-EB}" \ SUBTARGET_EXTRA_LINK_SPEC -#define ASM_SPEC "%{mbig-endian:-EB} \ - %{mcpu=*:-m%*} %{march=*:-m%*} \ - %{mthumb-interwork:-mthumb-interwork} \ - %{msoft-float:-mno-fpu} \ - %{mapcs-float:-mfloat}" \ - SUBTARGET_EXTRA_ASM_SPEC - #undef CPP_PREDEFINES #define CPP_PREDEFINES \ "-Dunix -D__arm__ -Dlinux -D__ELF__ \ @@ -166,6 +159,8 @@ do { \ definition in the target-specific file which includes this file. */ #define SUBTARGET_EXTRA_SECTION_FUNCTIONS CONST_SECTION_FUNCTION +extern void text_section (); + #define CONST_SECTION_ASM_OP ".section\t.rodata" #define CONST_SECTION_FUNCTION \ @@ -302,8 +297,8 @@ const_section () \ #define FP_DEFAULT FP_SOFT3 /* Call the function profiler with a given profile label. */ -#undef FUNCTION_PROFILER -#define FUNCTION_PROFILER(STREAM, LABELNO) \ +#undef ARM_FUNCTION_PROFILER +#define ARM_FUNCTION_PROFILER(STREAM, LABELNO) \ { \ fprintf (STREAM, "\tbl\tmcount%s\n", NEED_PLT_RELOC ? "(PLT)" : ""); \ } diff --git a/gcc/config/arm/linux-telf.h b/gcc/config/arm/linux-telf.h deleted file mode 100644 index dd730d86472..00000000000 --- a/gcc/config/arm/linux-telf.h +++ /dev/null @@ -1,202 +0,0 @@ -/* Definitions for Thumb running Linux-based GNU systems using ELF - Copyright (C) 1999 Free Software Foundation, Inc. - Contributed by Philip Blundell - -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 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 this program; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#define SUBTARGET_EXTRA_ASM_SPEC \ - " %{fPIC:-k} %{fpic:-k}" - -/* This was defined in linux.h. Define it here also. */ -#undef DEFAULT_VTABLE_THUNKS -#define DEFAULT_VTABLE_THUNKS 1 - -/* Handle #pragma weak and #pragma pack. */ -#define HANDLE_SYSV_PRAGMA - -/* Now we define the strings used to build the spec file. */ -#define LIB_SPEC \ - "%{shared: -lc} \ - %{!shared: %{pthread:-lpthread} \ - %{profile:-lc_p} %{!profile: -lc}}" - -/* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add - the GNU/Linux magical crtbegin.o file (see crtstuff.c) which - provides part of the support for getting C++ file-scope static - object constructed before entering `main'. */ - -#define STARTFILE_SPEC \ - "%{!shared: \ - %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} \ - %{!p:%{profile:gcrt1.o%s} \ - %{!profile:crt1.o%s}}}} \ - crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}" - -/* Provide a ENDFILE_SPEC appropriate for GNU/Linux. Here we tack on - the GNU/Linux magical crtend.o file (see crtstuff.c) which - provides part of the support for getting C++ file-scope static - object constructed before entering `main', followed by a normal - GNU/Linux "finalizer" file, `crtn.o'. */ - -#define ENDFILE_SPEC \ - "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s" - -#define LINK_SPEC "%{h*} %{version:-v} \ - %{b} %{Wl,*:%*} \ - %{static:-Bstatic} \ - %{shared:-shared} \ - %{symbolic:-Bsymbolic} \ - %{rdynamic:-export-dynamic} \ - %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ - -X -mno-fpu -p \ - %{mbig-endian:-EB} \ - -m armelf_linux" - -#define CPP_PREDEFINES \ - "-Dunix -Dthumb -D__thumb -Dlinux \ --Asystem(unix) -Asystem(posix) -Acpu(arm) \ --Amachine(arm) -D__ELF__" - -/* Allow #sccs in preprocessor. */ -#define SCCS_DIRECTIVE - -#define USER_LABEL_PREFIX "" /* For ELF the default is no underscores */ -#define LOCAL_LABEL_PREFIX "." - -/* Attach a special .ident directive to the end of the file to identify - the version of GCC which compiled this code. */ -#define IDENT_ASM_OP ".ident" - -/* Output #ident as a .ident. */ -#define ASM_OUTPUT_IDENT(FILE, NAME) \ - fprintf (FILE, "\t%s\t\"%s\"\n", IDENT_ASM_OP, NAME); - -#ifdef IDENTIFY_WITH_IDENT -#define ASM_IDENTIFY_GCC(FILE) /* nothing */ -#define ASM_IDENTIFY_LANGUAGE(FILE) \ - fprintf (FILE, "\t%s \"GCC (%s) %s\"\n", IDENT_ASM_OP, \ - lang_identify (), version_string) -#else -#define ASM_FILE_END(FILE) \ - do \ - { \ - if (!flag_no_ident) \ - fprintf (FILE, "\t%s\t\"GCC: (GNU) %s\"\n", \ - IDENT_ASM_OP, version_string); \ - } \ - while (0) -#endif - -/* Support const sections and the ctors and dtors sections for g++. - Note that there appears to be two different ways to support const - sections at the moment. You can either #define the symbol - READONLY_DATA_SECTION (giving it some code which switches to the - readonly data section) or else you can #define the symbols - EXTRA_SECTIONS, EXTRA_SECTION_FUNCTIONS, SELECT_SECTION, and - SELECT_RTX_SECTION. We do both here just to be on the safe side. */ -#define USE_CONST_SECTION 1 - -/* Support for Constructors and Destructors. */ -#define READONLY_DATA_SECTION() const_section () - -/* A default list of other sections which we might be "in" at any given - time. For targets that use additional sections (e.g. .tdesc) you - should override this definition in the target-specific file which - includes this file. */ -#define SUBTARGET_EXTRA_SECTIONS in_const, - -/* A default list of extra section function definitions. For targets - that use additional sections (e.g. .tdesc) you should override this - definition in the target-specific file which includes this file. */ -#define SUBTARGET_EXTRA_SECTION_FUNCTIONS CONST_SECTION_FUNCTION - -#define CONST_SECTION_ASM_OP ".section\t.rodata" - -#define CONST_SECTION_FUNCTION \ -void \ -const_section () \ -{ \ - if (!USE_CONST_SECTION) \ - text_section (); \ - else if (in_section != in_const) \ - { \ - fprintf (asm_out_file, "%s\n", CONST_SECTION_ASM_OP); \ - in_section = in_const; \ - } \ -} - -/* A C statement or statements to switch to the appropriate - section for output of DECL. DECL is either a `VAR_DECL' node - or a constant of some sort. RELOC indicates whether forming - the initial value of DECL requires link-time relocations. */ -#define SELECT_SECTION(DECL, RELOC) \ -{ \ - if (TREE_CODE (DECL) == STRING_CST) \ - { \ - if (! flag_writable_strings) \ - const_section (); \ - else \ - data_section (); \ - } \ - else if (TREE_CODE (DECL) == VAR_DECL) \ - { \ - if ((flag_pic && RELOC) \ - || !TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL) \ - || !DECL_INITIAL (DECL) \ - || (DECL_INITIAL (DECL) != error_mark_node \ - && !TREE_CONSTANT (DECL_INITIAL (DECL)))) \ - data_section (); \ - else \ - const_section (); \ - } \ - else \ - const_section (); \ -} - -/* A C statement or statements to switch to the appropriate - section for output of RTX in mode MODE. RTX is some kind - of constant in RTL. The argument MODE is redundant except - in the case of a `const_int' rtx. Currently, these always - go into the const section. */ -#define SELECT_RTX_SECTION(MODE, RTX) const_section () - -/* On svr4, we *do* have support for the .init and .fini sections, and we - can put stuff in there to be executed before and after `main'. We let - crtstuff.c and other files know this by defining the following symbols. - The definitions say how to change sections to the .init and .fini - sections. This is the same for all known svr4 assemblers. */ -#define INIT_SECTION_ASM_OP ".section\t.init" -#define FINI_SECTION_ASM_OP ".section\t.fini" - - -/* This is how we tell the assembler that a symbol is weak. */ -#define ASM_WEAKEN_LABEL(FILE, NAME) \ - do \ - { \ - fputs ("\t.weak\t", FILE); \ - assemble_name (FILE, NAME); \ - fputc ('\n', FILE); \ - } \ - while (0) - -#include "arm/telf.h" -#include "arm/linux-tgas.h" - -/* Run-time Target Specification. */ -#undef TARGET_VERSION -#define TARGET_VERSION fputs (" (Thumb GNU/Linux)", stderr); diff --git a/gcc/config/arm/linux-tgas.h b/gcc/config/arm/linux-tgas.h deleted file mode 100644 index 5ca370a4021..00000000000 --- a/gcc/config/arm/linux-tgas.h +++ /dev/null @@ -1,84 +0,0 @@ -/* Definitions of target machine for GNU compiler. - Thumb Linux-based GNU systems version. - Copyright (C) 1999 Free Software Foundation, Inc. - Contributed by Russell King . - -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 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 this program; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* We are using GAS, so stabs should work. */ -#ifndef DBX_DEBUGGING_INFO -#define DBX_DEBUGGING_INFO 1 -#endif - -/* This is how we tell the assembler that a symbol is weak. - GAS always supports weak symbols. */ -#define ASM_WEAKEN_LABEL(FILE, NAME) \ - do \ - { \ - fputs ("\t.weak\t", FILE); \ - assemble_name (FILE, NAME); \ - fputc ('\n', FILE); \ - } \ - while (0) - -/* This is used in ASM_FILE_START */ -#undef ARM_OS_NAME -#define ARM_OS_NAME "Linux" - -/* Unsigned chars produces much better code than signed. */ -#define DEFAULT_SIGNED_CHAR 0 - -#undef SUBTARGET_CPP_SPEC -#define SUBTARGET_CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__}" - -#undef SIZE_TYPE -#define SIZE_TYPE "unsigned int" - -#undef PTRDIFF_TYPE -#define PTRDIFF_TYPE "int" - -#undef WCHAR_TYPE -#define WCHAR_TYPE "long int" - -#undef WCHAR_TYPE_SIZE -#define WCHAR_TYPE_SIZE BITS_PER_WORD - -/* Emit code to set up a trampoline and synchronise the caches. */ -#undef INITIALIZE_TRAMPOLINE -#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ -{ \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 8)), \ - CXT); \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 12)), \ - FNADDR); \ - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), \ - 0, VOIDmode, 2, TRAMP, Pmode, \ - plus_constant (TRAMP, TRAMPOLINE_SIZE), Pmode); \ -} - -#if 0 -/* Clear the instruction cache from `beg' to `end'. This makes an - inline system call to SYS_cacheflush. */ -#define CLEAR_INSN_CACHE(BEG, END) \ -{ \ - register unsigned long _beg __asm ("a1") = (unsigned long) (BEG); \ - register unsigned long _end __asm ("a2") = (unsigned long) (END); \ - register unsigned long _flg __asm ("a3") = 0; \ - __asm __volatile ("swi 0x9f0002"); \ -} -#endif diff --git a/gcc/config/arm/netbsd.h b/gcc/config/arm/netbsd.h index 4c8ce4094fc..d368f68d629 100644 --- a/gcc/config/arm/netbsd.h +++ b/gcc/config/arm/netbsd.h @@ -37,7 +37,7 @@ Boston, MA 02111-1307, USA. */ #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 /* Default is to use APCS-32 mode. */ -#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_SOFT_FLOAT) +#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_FRAME) #include "arm/aout.h" @@ -105,8 +105,8 @@ Boston, MA 02111-1307, USA. */ compiling the profiling functions. Since we break Acorn CC compatibility below a little more won't hurt. */ -#undef FUNCTION_PROFILER -#define FUNCTION_PROFILER(STREAM,LABELNO) \ +#undef ARM_FUNCTION_PROFILER +#define ARM_FUNCTION_PROFILER(STREAM,LABELNO) \ { \ fprintf(STREAM, "\tmov\t%sip, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX); \ fprintf(STREAM, "\tbl\tmcount\n"); \ diff --git a/gcc/config/arm/pe.c b/gcc/config/arm/pe.c index 80fdd048b31..55b4668fc6a 100644 --- a/gcc/config/arm/pe.c +++ b/gcc/config/arm/pe.c @@ -27,7 +27,7 @@ Boston, MA 02111-1307, USA. */ #include "tree.h" #include "expr.h" #include "toplev.h" -#include "arm-protos.h" +#include "tm_p.h" extern int current_function_anonymous_args; @@ -59,6 +59,7 @@ arm_pe_valid_machine_decl_attribute (decl, attributes, attr, args) if (is_attribute_p ("dllexport", attr)) return 1; + if (is_attribute_p ("dllimport", attr)) return 1; @@ -118,45 +119,6 @@ arm_pe_merge_machine_decl_attributes (old, new) return a; } -#if 0 -/* Check a type that has a virtual table, and see if any virtual methods are - marked for import or export, and if so, arrange for the vtable to - be imported or exported. */ - -static int -arm_check_vtable_importexport (type) - tree type; -{ - tree methods = TYPE_METHODS (type); - tree fndecl; - - if (TREE_CODE (methods) == FUNCTION_DECL) - fndecl = methods; - else if (TREE_VEC_ELT (methods, 0) != NULL_TREE) - fndecl = TREE_VEC_ELT (methods, 0); - else - fndecl = TREE_VEC_ELT (methods, 1); - - while (fndecl) - { - if (DECL_VIRTUAL_P (fndecl) || DECL_VINDEX (fndecl) != NULL_TREE) - { - tree exp = lookup_attribute ("dllimport", - DECL_MACHINE_ATTRIBUTES (fndecl)); - if (exp == 0) - exp = lookup_attribute ("dllexport", - DECL_MACHINE_ATTRIBUTES (fndecl)); - if (exp) - return 1; - } - - fndecl = TREE_CHAIN (fndecl); - } - - return 0; -} -#endif - /* Return non-zero if DECL is a dllexport'd object. */ tree current_class_type; /* FIXME */ @@ -174,23 +136,6 @@ arm_dllexport_p (decl) if (exp) return 1; -#if 0 /* This was a hack to get vtable's exported or imported since only one - copy of them is ever output. Disabled pending better solution. */ - /* For C++, the vtables might have to be marked. */ - if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl)) - { - if (TREE_PUBLIC (decl) - && DECL_EXTERNAL (decl) == 0 - && (DECL_CONTEXT (decl) - ? arm_check_vtable_importexport (DECL_CONTEXT (decl)) - : current_class_type - ? arm_check_vtable_importexport (current_class_type) - : 0) - ) - return 1; - } -#endif - return 0; } @@ -213,23 +158,6 @@ arm_dllimport_p (decl) if (imp) return 1; -#if 0 /* This was a hack to get vtable's exported or imported since only one - copy of them is ever output. Disabled pending better solution. */ - /* For C++, the vtables might have to be marked. */ - if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl)) - { - if (TREE_PUBLIC (decl) - && DECL_EXTERNAL (decl) - && (DECL_CONTEXT (decl) - ? arm_check_vtable_importexport (DECL_CONTEXT (decl)) - : current_class_type - ? arm_check_vtable_importexport (current_class_type) - : 0) - ) - return 1; - } -#endif - return 0; } @@ -437,70 +365,3 @@ arm_pe_unique_section (decl, reloc) DECL_SECTION_NAME (decl) = build_string (len, string); } - -/* This is to better conform to the ARM PCS. - Richard Earnshaw hasn't put this into FSF sources yet so it's here. */ - -int -arm_pe_return_in_memory (type) - tree type; -{ - if (TREE_CODE (type) == RECORD_TYPE) - { - tree field; - int num_fields = 0; - - /* For a record containing just a single element, we can be a little - less restrictive. */ - for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) == FIELD_DECL && ! TREE_STATIC (field)) - { - if ((AGGREGATE_TYPE_P (TREE_TYPE (field)) - && RETURN_IN_MEMORY (TREE_TYPE (field))) - || FLOAT_TYPE_P (TREE_TYPE (field))) - return 1; - num_fields++; - } - } - - if (num_fields == 1) - return 0; - - /* For a struct, we can return in a register if every element was a - bit-field and it all fits in one word. */ - for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) == FIELD_DECL - && ! TREE_STATIC (field) - && (! DECL_BIT_FIELD_TYPE (field) - || (host_integerp (DECL_SIZE (field), 1) - && host_integerp (bit_position (field), 1) - && 32 < (int_bit_position (field) - + tree_low_cst (DECL_SIZE (field), 1))))) - return 1; - } - return 0; - } - else if (TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == QUAL_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 - && ! TREE_STATIC (field) - && ((AGGREGATE_TYPE_P (TREE_TYPE (field)) - && RETURN_IN_MEMORY (TREE_TYPE (field))) - || FLOAT_TYPE_P (TREE_TYPE (field)))) - return 1; - } - return 0; - } - /* XXX Not sure what should be done for other aggregates, so put them in - memory. */ - return 1; -} diff --git a/gcc/config/arm/pe.h b/gcc/config/arm/pe.h index dfa5d4d08b4..d950abd32d1 100644 --- a/gcc/config/arm/pe.h +++ b/gcc/config/arm/pe.h @@ -19,6 +19,9 @@ 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. */ +/* Enable PE specific code. */ +#define ARM_PE 1 + #define ARM_PE_FLAG_CHAR '@' /* Ensure that @x. will be stripped from the function name. */ @@ -42,11 +45,9 @@ Boston, MA 02111-1307, USA. */ say __declspec__, and passing args to it. The problem with that approach is that args are not accumulated: each new appearance would clobber any existing args. */ -#undef CPP_PREDEFINES -#define CPP_PREDEFINES "\ --Darm -D__pe__ -Acpu(arm) -Amachine(arm) \ --D__declspec(x)=__attribute__((x)) \ -" +#undef SUBTARGET_CPP_SPEC +#define SUBTARGET_CPP_SPEC "-D__pe__ -D__declspec(x)=__attribute__((x))" + /* Experimental addition for pr 7885. Ignore dllimport for functions. */ @@ -88,13 +89,6 @@ Boston, MA 02111-1307, USA. */ 1,1,1,1,0,0,0,0, \ 1,1,1 \ } - -/* This is to better conform to the ARM PCS. - Richard Earnshaw hasn't put this into FSF sources yet so it's here. */ -#undef RETURN_IN_MEMORY -#define RETURN_IN_MEMORY(TYPE) \ - ((TYPE_MODE ((TYPE)) == BLKmode && ! TYPE_NO_FORCE_BLK (TYPE)) \ - || (AGGREGATE_TYPE_P ((TYPE)) && arm_pe_return_in_memory ((TYPE)))) /* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS is a valid machine specific attribute for DECL. @@ -121,13 +115,7 @@ Boston, MA 02111-1307, USA. */ to handle vtables - the first pass won't do anything because DECL_CONTEXT (DECL) will be 0 so arm_dll{ex,im}port_p will return 0. It's also used to handle dllimport override semantics. */ -#if 0 -#define REDO_SECTION_INFO_P(DECL) \ -((DECL_MACHINE_ATTRIBUTES (DECL) != NULL_TREE) \ - || (TREE_CODE (DECL) == VAR_DECL && DECL_VIRTUAL_P (DECL))) -#else #define REDO_SECTION_INFO_P(DECL) 1 -#endif /* Define this macro if in some cases global symbols from one translation unit may not be bound to undefined symbols in another translation unit @@ -180,24 +168,25 @@ Boston, MA 02111-1307, USA. */ /* Output a reference to a label. */ #undef ASM_OUTPUT_LABELREF #define ASM_OUTPUT_LABELREF(STREAM, NAME) \ - fprintf (STREAM, "%s%s", USER_LABEL_PREFIX, arm_strip_name_encoding (NAME)) + asm_fprintf (STREAM, "%U%s", arm_strip_name_encoding (NAME)) /* Output a function definition label. */ #undef ASM_DECLARE_FUNCTION_NAME -#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \ - do \ - { \ - if (arm_dllexport_name_p (NAME)) \ - { \ - drectve_section (); \ - fprintf (STREAM, "\t.ascii \" -export:%s\"\n",\ - arm_strip_name_encoding (NAME)); \ - function_section (DECL); \ - } \ - if (TARGET_POKE_FUNCTION_NAME) \ - arm_poke_function_name ((STREAM), (NAME)); \ - ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ - } \ +#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \ + do \ + { \ + if (arm_dllexport_name_p (NAME)) \ + { \ + drectve_section (); \ + fprintf (STREAM, "\t.ascii \" -export:%s\"\n", \ + arm_strip_name_encoding (NAME)); \ + function_section (DECL); \ + } \ + ARM_DECLARE_FUNCTION_NAME (STREAM, NAME, DECL); \ + if (TARGET_THUMB) \ + fprintf (STREAM, "\t.code 16\n"); \ + ASM_OUTPUT_LABEL (STREAM, NAME); \ + } \ while (0) /* Output a common block. */ diff --git a/gcc/config/arm/semi.h b/gcc/config/arm/semi.h index c19e857c687..081b4c18663 100644 --- a/gcc/config/arm/semi.h +++ b/gcc/config/arm/semi.h @@ -23,10 +23,7 @@ Boston, MA 02111-1307, USA. */ #define LIB_SPEC "-lc" -#define CPP_PREDEFINES \ - "-Darm -D__semi__ -Acpu(arm) -Amachine(arm)" - -#define ASM_SPEC "%{mbig-endian:-EB}" +#define SUBTARGET_CPP_SPEC "-D__semi__" #define LINK_SPEC "%{mbig-endian:-EB} -X" @@ -35,7 +32,23 @@ Boston, MA 02111-1307, USA. */ #endif #ifndef TARGET_DEFAULT -#define TARGET_DEFAULT ARM_FLAG_APCS_32 +#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME) +#endif + +#ifndef SUBTARGET_EXTRA_ASM_SPEC +#define SUBTARGET_EXTRA_ASM_SPEC +#endif + +#ifndef ASM_SPEC +#define ASM_SPEC "\ +%{mbig-endian:-EB} \ +%{mcpu=*:-m%*} \ +%{march=*:-m%*} \ +%{mapcs-*:-mapcs-%*} \ +%{mapcs-float:-mfloat} \ +%{msoft-float:-mno-fpu} \ +%{mthumb-interwork:-mthumb-interwork} \ +" SUBTARGET_EXTRA_ASM_SPEC #endif #include "arm/aout.h" diff --git a/gcc/config/arm/strongarm-coff.h b/gcc/config/arm/strongarm-coff.h new file mode 100644 index 00000000000..39613109566 --- /dev/null +++ b/gcc/config/arm/strongarm-coff.h @@ -0,0 +1,31 @@ +/* Definitions for StrongARM systems using COFF + Copyright (C) 1999 Free Software Foundation, Inc. + Contributed by Catherine Moore + +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 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 this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Run-time Target Specification. */ +#ifndef SUBTARGET_CPU_DEFAULT +#define SUBTARGET_CPU_DEFAULT TARGET_CPU_strongarm +#endif + +#include "coff.h" + +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (StrongARM/COFF)", stderr); + diff --git a/gcc/config/arm/strongarm-elf.h b/gcc/config/arm/strongarm-elf.h new file mode 100644 index 00000000000..79ba96113ff --- /dev/null +++ b/gcc/config/arm/strongarm-elf.h @@ -0,0 +1,31 @@ +/* Definitions for non-Linux based StrongARM systems using ELF + Copyright (C) 1999 Free Software Foundation, Inc. + Contributed by Catherine Moore + +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 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 this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Run-time Target Specification. */ +#ifndef TARGET_VERSION +#define TARGET_VERSION fputs (" (StrongARM/ELF non-Linux)", stderr); +#endif + +#ifndef SUBTARGET_CPU_DEFAULT +#define SUBTARGET_CPU_DEFAULT TARGET_CPU_strongarm +#endif + +#include "unknown-elf.h" diff --git a/gcc/config/arm/t-pe-thumb b/gcc/config/arm/t-arm-aout similarity index 64% rename from gcc/config/arm/t-pe-thumb rename to gcc/config/arm/t-arm-aout index d12beadc598..811b2c2ae1a 100644 --- a/gcc/config/arm/t-pe-thumb +++ b/gcc/config/arm/t-arm-aout @@ -1,9 +1,6 @@ -# Makefile fragment -# Copyright (c) 1998 Free Software Foundation - CROSS_LIBGCC1 = libgcc1-asm.a -LIB1ASMSRC = arm/lib1thumb.asm -LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX +LIB1ASMSRC = arm/lib1funcs.asm +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX # We want fine grained libraries, so use the new code to build the # floating point emulation libraries. @@ -24,13 +21,10 @@ dp-bit.c: $(srcdir)/config/fp-bit.c echo '#endif' >> dp-bit.c cat $(srcdir)/config/fp-bit.c >> dp-bit.c -# Rule to build Psion specific GCC functions. -pe.o: $(srcdir)/config/arm/pe.c - $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/arm/pe.c - -# Avoid building a duplicate set of libraries for the default endian-ness. -MULTILIB_OPTIONS = mthumb-interwork -MULTILIB_DIRNAMES = interwork +# MULTILIB_OPTIONS = mhard-float/msoft-float mapcs-32/mapcs-26 mno-thumb-interwork/mthumb-interwork arm/thumb +# MULTILIB_DIRNAMES = le be fpu soft 32bit 26bit normal interwork arm thumb +# MULTILIB_MATCHES = +# MULTILIB_EXCEPTIONS = *mapcs-26/*mthumb-interwork* *mpacs-26/*mthumb* LIBGCC = stmp-multilib INSTALL_LIBGCC = install-multilib diff --git a/gcc/config/arm/t-thumb-elf b/gcc/config/arm/t-arm-coff similarity index 56% rename from gcc/config/arm/t-thumb-elf rename to gcc/config/arm/t-arm-coff index 302a20be1ab..5422257eb3b 100644 --- a/gcc/config/arm/t-thumb-elf +++ b/gcc/config/arm/t-arm-coff @@ -1,7 +1,6 @@ CROSS_LIBGCC1 = libgcc1-asm.a -LIB1ASMSRC = arm/lib1thumb.asm -LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX -# adddi3/subdi3 added to machine description +LIB1ASMSRC = arm/lib1funcs.asm +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _bb_init_func _call_via_rX _interwork_call_via_rX # We want fine grained libraries, so use the new code to build the # floating point emulation libraries. @@ -22,13 +21,15 @@ dp-bit.c: $(srcdir)/config/fp-bit.c echo '#endif' >> dp-bit.c cat $(srcdir)/config/fp-bit.c >> dp-bit.c -# Avoid building a duplicate set of libraries for the default endian-ness. -MULTILIB_OPTIONS = mlittle-endian/mbig-endian mno-thumb-interwork/mthumb-interwork fno-leading-underscore/fleading-underscore -MULTILIB_DIRNAMES = le be normal interwork elf under -MULTILIB_MATCHES = mbig-endian=mbe mlittle-endian=mle +MULTILIB_OPTIONS = mlittle-endian/mbig-endian mhard-float/msoft-float marm/mthumb mno-thumb-interwork/mthumb-interwork +MULTILIB_DIRNAMES = le be fpu soft arm thumb normal interwork +MULTILIB_MATCHES = EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o LIBGCC = stmp-multilib INSTALL_LIBGCC = install-multilib -TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc +# Currently there is a bug somwehere in GCC's alias analysis +# or scheduling code that is breaking _fpmul_parts in libgcc1.c. +# Disabling function inlining is a workaround for this problem. +TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc -fno-inline diff --git a/gcc/config/arm/t-arm-elf b/gcc/config/arm/t-arm-elf index 76beab3eb4d..a576d6f32e6 100644 --- a/gcc/config/arm/t-arm-elf +++ b/gcc/config/arm/t-arm-elf @@ -1,6 +1,6 @@ CROSS_LIBGCC1 = libgcc1-asm.a -LIB1ASMSRC = arm/lib1funcs.asm -LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX +LIB1ASMSRC = arm/lib1funcs.asm +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _bb_init_func _call_via_rX _interwork_call_via_rX # We want fine grained libraries, so use the new code to build the # floating point emulation libraries. @@ -67,7 +67,16 @@ dp-bit.c: $(srcdir)/config/fp-bit.c # LIBGCC = stmp-multilib # INSTALL_LIBGCC = install-multilib +MULTILIB_MATCHES = mbig-endian=mbe mlittle-endian=mle +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o + # If EXTRA_MULTILIB_PARTS is not defined above then define EXTRA_PARTS here -EXTRA_PARTS = crtbegin.o crtend.o +# EXTRA_PARTS = crtbegin.o crtend.o + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib -TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc +# Currently there is a bug somewhere in GCC's alias analysis +# or scheduling code that is breaking _fpmul_parts in libgcc1.c. +# Disabling function inlining is a workaround for this problem. +TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc -fno-inline diff --git a/gcc/config/arm/t-bare b/gcc/config/arm/t-bare deleted file mode 100644 index ba799d829ea..00000000000 --- a/gcc/config/arm/t-bare +++ /dev/null @@ -1,32 +0,0 @@ -CROSS_LIBGCC1 = libgcc1-asm.a -LIB1ASMSRC = arm/lib1funcs.asm -LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX - -# We want fine grained libraries, so use the new code to build the -# floating point emulation libraries. -FPBIT = fp-bit.c -DPBIT = dp-bit.c - -fp-bit.c: $(srcdir)/config/fp-bit.c - echo '#define FLOAT' > fp-bit.c - echo '#ifndef __ARMEB__' >> fp-bit.c - echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c - echo '#endif' >> fp-bit.c - cat $(srcdir)/config/fp-bit.c >> fp-bit.c - -dp-bit.c: $(srcdir)/config/fp-bit.c - echo '#ifndef __ARMEB__' > dp-bit.c - echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c - echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c - echo '#endif' >> dp-bit.c - cat $(srcdir)/config/fp-bit.c >> dp-bit.c - -# Avoid building a duplicate set of libraries for the default endian-ness. -MULTILIB_OPTIONS = mlittle-endian/mbig-endian mhard-float -MULTILIB_DIRNAMES = le be fpu -MULTILIB_MATCHES = - -LIBGCC = stmp-multilib -INSTALL_LIBGCC = install-multilib - - diff --git a/gcc/config/arm/t-netbsd b/gcc/config/arm/t-netbsd index 6a61e9c40fa..6c59cc9705b 100644 --- a/gcc/config/arm/t-netbsd +++ b/gcc/config/arm/t-netbsd @@ -5,3 +5,5 @@ LIBGCC2_DEBUG_CFLAGS = -g0 # Don't build enquire ENQUIRE= + + diff --git a/gcc/config/arm/t-pe b/gcc/config/arm/t-pe index 0ffcfffaab3..7d71f5ccf7e 100644 --- a/gcc/config/arm/t-pe +++ b/gcc/config/arm/t-pe @@ -24,8 +24,9 @@ dp-bit.c: $(srcdir)/config/fp-bit.c pe.o: $(srcdir)/config/arm/pe.c $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/arm/pe.c -MULTILIB_OPTIONS = mhard-float -MULTILIB_DIRNAMES = fpu +MULTILIB_OPTIONS = mhard-float mthumb +MULTILIB_DIRNAMES = fpu thumb LIBGCC = stmp-multilib INSTALL_LIBGCC = install-multilib +TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc diff --git a/gcc/config/arm/t-semiaof b/gcc/config/arm/t-semiaof index eeb03fdf2fd..22887939655 100644 --- a/gcc/config/arm/t-semiaof +++ b/gcc/config/arm/t-semiaof @@ -64,3 +64,4 @@ libgcc1-atest: libgcc1-test.o native $(GCC_PARTS) $(EXTRA_PARTS) @echo "Testing libgcc1. Ignore linker warning messages." $(GCC_FOR_TARGET) $(GCC_CFLAGS) libgcc1-test.o -o libgcc1-test \ -v + diff --git a/gcc/config/arm/t-thumb b/gcc/config/arm/t-thumb deleted file mode 100644 index eb3e0111a8d..00000000000 --- a/gcc/config/arm/t-thumb +++ /dev/null @@ -1,32 +0,0 @@ -CROSS_LIBGCC1 = libgcc1-asm.a -LIB1ASMSRC = arm/lib1thumb.asm -LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX -# adddi3/subdi3 added to machine description -#LIB1ASMFUNCS = _adddi3 _subdi3 _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls - -# We want fine grained libraries, so use the new code to build the -# floating point emulation libraries. -FPBIT = fp-bit.c -DPBIT = dp-bit.c - -fp-bit.c: $(srcdir)/config/fp-bit.c - echo '#define FLOAT' > fp-bit.c - echo '#ifndef __ARMEB__' >> fp-bit.c - echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c - echo '#endif' >> fp-bit.c - cat $(srcdir)/config/fp-bit.c >> fp-bit.c - -dp-bit.c: $(srcdir)/config/fp-bit.c - echo '#ifndef __ARMEB__' > dp-bit.c - echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c - echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c - echo '#endif' >> dp-bit.c - cat $(srcdir)/config/fp-bit.c >> dp-bit.c - -# Avoid building a duplicate set of libraries for the default endian-ness. -MULTILIB_OPTIONS = mlittle-endian/mbig-endian mno-thumb-interwork/mthumb-interwork -MULTILIB_DIRNAMES = le be normal interwork -MULTILIB_MATCHES = mbig-endian=mbe mlittle-endian=mle - -LIBGCC = stmp-multilib -INSTALL_LIBGCC = install-multilib diff --git a/gcc/config/arm/t-thumb-linux b/gcc/config/arm/t-thumb-linux deleted file mode 100644 index e028ac04c4e..00000000000 --- a/gcc/config/arm/t-thumb-linux +++ /dev/null @@ -1,42 +0,0 @@ -# Just for these, we omit the frame pointer since it makes such a big -# difference. It is then pointless adding debugging. -TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC -LIBGCC2_DEBUG_CFLAGS = -g0 - -# Don't build enquire -ENQUIRE= - -# Since libgcc1 is an assembler file, we can build it automatically for the -# cross-compiler. -CROSS_LIBGCC1 = libgcc1-asm.a -LIBGCC1 = libgcc1-asm.a -LIB1ASMSRC = arm/lib1thumb.asm -LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX - -MULTILIB_OPTIONS = mlittle-endian/mbig-endian -MULTILIB_DIRNAMES = le be -MULTILIB_MATCHES = mbig-endian=mbe mlittle-endian=mle -EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o - -LIBGCC = stmp-multilib -INSTALL_LIBGCC = install-multilib - -# We want fine grained libraries, so use the new code to build the -# floating point emulation libraries. -FPBIT = fp-bit.c -DPBIT = dp-bit.c - -fp-bit.c: $(srcdir)/config/fp-bit.c - echo '#define FLOAT' > fp-bit.c - echo '#ifndef __ARMEB__' >> fp-bit.c - echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c - echo '#endif' >> fp-bit.c - cat $(srcdir)/config/fp-bit.c >> fp-bit.c - -dp-bit.c: $(srcdir)/config/fp-bit.c - echo '#ifndef __ARMEB__' > dp-bit.c - echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c - echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c - echo '#endif' >> dp-bit.c - cat $(srcdir)/config/fp-bit.c >> dp-bit.c - diff --git a/gcc/config/arm/tcoff.h b/gcc/config/arm/tcoff.h deleted file mode 100644 index 37870022d1e..00000000000 --- a/gcc/config/arm/tcoff.h +++ /dev/null @@ -1,187 +0,0 @@ -/* Definitions of target machine for GNU compiler, - for Thumb with COFF obj format. - Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc. - Derived from arm/coff.h originally by Doug Evans (dje@cygnus.com). - -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 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. */ - -#include "arm/thumb.h" - -/* Run-time Target Specification. */ -#undef TARGET_VERSION -#define TARGET_VERSION fputs (" (Thumb/coff)", stderr) - -#define MULTILIB_DEFAULTS { "mlittle-endian" } - -/* Setting this to 32 produces more efficient code, but the value set in previous - versions of this toolchain was 8, which produces more compact structures. The - command line option -mstructure_size_boundary= can be used to change this - value. */ -#undef STRUCTURE_SIZE_BOUNDARY -#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary - -extern int arm_structure_size_boundary; - -/* This is COFF, but prefer stabs. */ -#define SDB_DEBUGGING_INFO - -#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG - -#include "dbxcoff.h" - -#undef LOCAL_LABEL_PREFIX -#define LOCAL_LABEL_PREFIX "." - -/* Note - it is important that this definition matches the one in coff.h */ -#undef USER_LABEL_PREFIX -#define USER_LABEL_PREFIX "_" - -/* A C statement to output assembler commands which will identify the - object file as having been compiled with GNU CC (or another GNU - compiler). */ -#define ASM_IDENTIFY_GCC(STREAM) \ - fprintf (STREAM, "%sgcc2_compiled.:\n", LOCAL_LABEL_PREFIX ) - -#undef ASM_FILE_START -#define ASM_FILE_START(STREAM) \ -do { \ - fprintf ((STREAM), "%s Generated by gcc %s for Thumb/coff\n", \ - ASM_COMMENT_START, version_string); \ - fprintf ((STREAM), ASM_APP_OFF); \ -} while (0) - -/* A C statement to output something to the assembler file to switch to section - NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or - NULL_TREE. Some target formats do not support arbitrary sections. Do not - define this macro in such cases. */ -#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ -do { \ - if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ - fprintf (STREAM, "\t.section %s,\"x\"\n", (NAME)); \ - else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ - fprintf (STREAM, "\t.section %s,\"\"\n", (NAME)); \ - else \ - fprintf (STREAM, "\t.section %s,\"w\"\n", (NAME)); \ -} while (0) - -/* Support the ctors/dtors and other sections. */ - -#undef INIT_SECTION_ASM_OP - -/* Define this macro if jump tables (for `tablejump' insns) should be - output in the text section, along with the assembler instructions. - Otherwise, the readonly data section is used. */ -#define JUMP_TABLES_IN_TEXT_SECTION 1 - -#undef READONLY_DATA_SECTION -#define READONLY_DATA_SECTION rdata_section -#undef RDATA_SECTION_ASM_OP -#define RDATA_SECTION_ASM_OP "\t.section .rdata" - -#undef CTORS_SECTION_ASM_OP -#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"x\"" -#undef DTORS_SECTION_ASM_OP -#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"x\"" - -/* A list of other sections which the compiler might be "in" at any - given time. */ - -#undef EXTRA_SECTIONS -#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_rdata, in_ctors, in_dtors - -#define SUBTARGET_EXTRA_SECTIONS - -/* A list of extra section function definitions. */ - -#undef EXTRA_SECTION_FUNCTIONS -#define EXTRA_SECTION_FUNCTIONS \ - RDATA_SECTION_FUNCTION \ - CTORS_SECTION_FUNCTION \ - DTORS_SECTION_FUNCTION \ - SUBTARGET_EXTRA_SECTION_FUNCTIONS - -#define SUBTARGET_EXTRA_SECTION_FUNCTIONS - -#define RDATA_SECTION_FUNCTION \ -void \ -rdata_section () \ -{ \ - if (in_section != in_rdata) \ - { \ - fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ - in_section = in_rdata; \ - } \ -} - -#define CTORS_SECTION_FUNCTION \ -void \ -ctors_section () \ -{ \ - if (in_section != in_ctors) \ - { \ - fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ - in_section = in_ctors; \ - } \ -} - -#define DTORS_SECTION_FUNCTION \ -void \ -dtors_section () \ -{ \ - if (in_section != in_dtors) \ - { \ - fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ - in_section = in_dtors; \ - } \ -} - -/* Support the ctors/dtors sections for g++. */ - -#define INT_ASM_OP ".word" - -/* A C statement (sans semicolon) to output an element in the table of - global constructors. */ -#undef ASM_OUTPUT_CONSTRUCTOR -#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ -do { \ - ctors_section (); \ - fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ - assemble_name (STREAM, NAME); \ - fprintf (STREAM, "\n"); \ -} while (0) - -/* A C statement (sans semicolon) to output an element in the table of - global destructors. */ -#undef ASM_OUTPUT_DESTRUCTOR -#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ -do { \ - dtors_section (); \ - fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ - assemble_name (STREAM, NAME); \ - fprintf (STREAM, "\n"); \ -} while (0) - -/* __CTOR_LIST__ and __DTOR_LIST__ must be defined by the linker script. */ -#define CTOR_LISTS_DEFINED_EXTERNALLY - -#undef DO_GLOBAL_CTORS_BODY -#undef DO_GLOBAL_DTORS_BODY - -/* The ARM development system defines __main. */ -#define NAME__MAIN "__gccmain" -#define SYMBOL__MAIN __gccmain diff --git a/gcc/config/arm/telf.h b/gcc/config/arm/telf.h deleted file mode 100644 index e1a5cb1be66..00000000000 --- a/gcc/config/arm/telf.h +++ /dev/null @@ -1,469 +0,0 @@ -/* Definitions of target machine for GNU compiler, - for Thumb with ELF obj format. - Copyright (C) 1995, 1996, 1999, 2000 Free Software Foundation, Inc. - -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 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. */ - -#define OBJECT_FORMAT_ELF - -#ifndef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dthumb -Dthumbelf -D__thumb -Acpu(arm) -Amachine(arm)" -#endif - -#include "arm/thumb.h" - -/* Run-time Target Specification. */ -#undef TARGET_VERSION -#define TARGET_VERSION fputs (" (Thumb/elf)", stderr) - -#define MULTILIB_DEFAULTS { "mlittle-endian" } - -/* Setting this to 32 produces more efficient code, but the value set in previous - versions of this toolchain was 8, which produces more compact structures. The - command line option -mstructure_size_boundary= can be used to change this - value. */ -#undef STRUCTURE_SIZE_BOUNDARY -#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary - -extern int arm_structure_size_boundary; - -/* Debug */ -#define DWARF_DEBUGGING_INFO -#define DWARF2_DEBUGGING_INFO -#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG - -/* Get the standard ELF stabs definitions. */ -#include "dbxelf.h" - -/* Note - it is important that these definitions match those in semi.h for the ARM port. */ -#undef LOCAL_LABEL_PREFIX -#define LOCAL_LABEL_PREFIX "." - - -/* A C statement to output assembler commands which will identify the - object file as having been compiled with GNU CC (or another GNU - compiler). */ -#ifndef ASM_IDENTIFY_GCC -#define ASM_IDENTIFY_GCC(STREAM) \ - fprintf (STREAM, "%sgcc2_compiled.:\n", LOCAL_LABEL_PREFIX ) -#endif - -#undef ASM_FILE_START -#define ASM_FILE_START(STREAM) \ - do \ - { \ - fprintf ((STREAM), "%s Generated by gcc %s for Thumb/elf\n", \ - ASM_COMMENT_START, version_string); \ - fprintf ((STREAM), ASM_APP_OFF); \ - } \ - while (0) - -/* A C statement to output something to the assembler file to switch to section - NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or - NULL_TREE. Some target formats do not support arbitrary sections. Do not - define this macro in such cases. */ -#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ - do \ - { \ - if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ - fprintf (STREAM, "\t.section %s,\"ax\",%%progbits\n", NAME); \ - else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ - fprintf (STREAM, "\t.section %s,\"a\"\n", NAME); \ - else if (! strncmp (NAME, ".bss", 4)) \ - fprintf (STREAM, "\t.section %s,\"aw\",%%nobits\n", NAME); \ - else \ - fprintf (STREAM, "\t.section %s,\"aw\"\n", NAME); \ - } \ - while (0) - -/* Support the ctors/dtors and other sections. */ - -#undef INIT_SECTION_ASM_OP - -/* Define this macro if jump tables (for `tablejump' insns) should be - output in the text section, along with the assembler instructions. - Otherwise, the readonly data section is used. */ -#define JUMP_TABLES_IN_TEXT_SECTION 1 - -#undef READONLY_DATA_SECTION -#define READONLY_DATA_SECTION rdata_section -#undef RDATA_SECTION_ASM_OP -#define RDATA_SECTION_ASM_OP "\t.section .rodata" - -#undef CTORS_SECTION_ASM_OP -#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"aw\"" -#undef DTORS_SECTION_ASM_OP -#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"aw\"" - -#define USER_LABEL_PREFIX "" - -/* If defined, a C expression whose value is a string containing the - assembler operation to identify the following data as - uninitialized global data. If not defined, and neither - `ASM_OUTPUT_BSS' nor `ASM_OUTPUT_ALIGNED_BSS' are defined, - uninitialized global data will be output in the data section if - `-fno-common' is passed, otherwise `ASM_OUTPUT_COMMON' will be - used. */ -#ifndef BSS_SECTION_ASM_OP -#define BSS_SECTION_ASM_OP ".section\t.bss" -#endif - -/* Like `ASM_OUTPUT_BSS' except takes the required alignment as a - separate, explicit argument. If you define this macro, it is used - in place of `ASM_OUTPUT_BSS', and gives you more flexibility in - handling the required alignment of the variable. The alignment is - specified as the number of bits. - - Try to use function `asm_output_aligned_bss' defined in file - `varasm.c' when defining this macro. */ -#ifndef ASM_OUTPUT_ALIGNED_BSS -#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ - asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) -#endif - -/* Don't know how to order these. UNALIGNED_WORD_ASM_OP is in - dwarf2.out. */ -#define UNALIGNED_WORD_ASM_OP ".4byte" - -#define ASM_OUTPUT_DWARF2_ADDR_CONST(FILE,ADDR) \ - if (((ADDR)[0] == '.') && ((ADDR)[1] == 'L')) \ - fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, (ADDR)); \ - else \ - fprintf ((FILE), "\t%s\t%s", \ - UNALIGNED_WORD_ASM_OP, (ADDR)) - -#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ - do \ - { \ - fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ - output_addr_const ((FILE), (RTX)); \ - fputc ('\n', (FILE)); \ - } \ - while (0) - -/* This is how to equate one symbol to another symbol. The syntax used is - `SYM1=SYM2'. Note that this is different from the way equates are done - with most svr4 assemblers, where the syntax is `.set SYM1,SYM2'. */ - -#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \ - do \ - { \ - fprintf ((FILE), "\t"); \ - assemble_name (FILE, LABEL1); \ - fprintf (FILE, " = "); \ - assemble_name (FILE, LABEL2); \ - fprintf (FILE, "\n"); \ - } \ - while (0) - -/* For aliases of functions we use .thumb_set instead. */ -#define ASM_OUTPUT_DEF_FROM_DECLS(FILE,DECL1,DECL2) \ - do \ - { \ - const char * LABEL1 = XSTR (XEXP (DECL_RTL (decl), 0), 0);\ - const char * LABEL2 = IDENTIFIER_POINTER (DECL2); \ - \ - if (TREE_CODE (DECL1) == FUNCTION_DECL) \ - { \ - fprintf (FILE, "\t.thumb_set "); \ - assemble_name (FILE, LABEL1); \ - fprintf (FILE, ","); \ - assemble_name (FILE, LABEL2); \ - fprintf (FILE, "\n"); \ - } \ - else \ - ASM_OUTPUT_DEF (FILE, LABEL1, LABEL2); \ - } \ - while (0) - -/* A list of other sections which the compiler might be "in" at any - given time. */ -#undef EXTRA_SECTIONS -#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_rdata, in_ctors, in_dtors - -#ifndef SUBTARGET_EXTRA_SECTIONS -#define SUBTARGET_EXTRA_SECTIONS -#endif - -/* A list of extra section function definitions. */ - -#undef EXTRA_SECTION_FUNCTIONS -#define EXTRA_SECTION_FUNCTIONS \ - RDATA_SECTION_FUNCTION \ - CTORS_SECTION_FUNCTION \ - DTORS_SECTION_FUNCTION \ - SUBTARGET_EXTRA_SECTION_FUNCTIONS - -#ifndef SUBTARGET_EXTRA_SECTION_FUNCTIONS -#define SUBTARGET_EXTRA_SECTION_FUNCTIONS -#endif - -#define RDATA_SECTION_FUNCTION \ -void \ -rdata_section () \ -{ \ - if (in_section != in_rdata) \ - { \ - fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ - in_section = in_rdata; \ - } \ -} - -#define CTOR_LIST_BEGIN \ -asm (CTORS_SECTION_ASM_OP); \ -func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) } - -#define CTOR_LIST_END \ -asm (CTORS_SECTION_ASM_OP); \ -func_ptr __CTOR_END__[1] = { (func_ptr) 0 }; - -#define DTOR_LIST_BEGIN \ -asm (DTORS_SECTION_ASM_OP); \ -func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) } - -#define DTOR_LIST_END \ -asm (DTORS_SECTION_ASM_OP); \ -func_ptr __DTOR_END__[1] = { (func_ptr) 0 }; - -#define CTORS_SECTION_FUNCTION \ -void \ -ctors_section () \ -{ \ - if (in_section != in_ctors) \ - { \ - fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ - in_section = in_ctors; \ - } \ -} - -#define DTORS_SECTION_FUNCTION \ -void \ -dtors_section () \ -{ \ - if (in_section != in_dtors) \ - { \ - fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ - in_section = in_dtors; \ - } \ -} - -/* Support the ctors/dtors sections for g++. */ - -#define INT_ASM_OP ".word" - -#define INVOKE__main - -#undef STARTFILE_SPEC -#define STARTFILE_SPEC "crtbegin%O%s crt0%O%s" - -#undef ENDFILE_SPEC -#define ENDFILE_SPEC "crtend%O%s" - -/* A C statement (sans semicolon) to output an element in the table of - global constructors. */ -#undef ASM_OUTPUT_CONSTRUCTOR -#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ - do \ - { \ - ctors_section (); \ - fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ - assemble_name (STREAM, NAME); \ - fprintf (STREAM, "\n"); \ - } \ - while (0) - -/* A C statement (sans semicolon) to output an element in the table of - global destructors. */ -#undef ASM_OUTPUT_DESTRUCTOR -#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ - do \ - { \ - dtors_section (); \ - fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ - assemble_name (STREAM, NAME); \ - fprintf (STREAM, "\n"); \ - } \ - while (0) - -/* The ARM development system defines __main. */ -#define NAME__MAIN "__gccmain" -#define SYMBOL__MAIN __gccmain - -#define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1) -#define UNIQUE_SECTION_P(DECL) (DECL_ONE_ONLY (DECL)) -#define UNIQUE_SECTION(DECL,RELOC) \ - do \ - { \ - int len; \ - char * name, * string, * prefix; \ - \ - name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \ - \ - if (! DECL_ONE_ONLY (DECL)) \ - { \ - prefix = "."; \ - if (TREE_CODE (DECL) == FUNCTION_DECL) \ - prefix = ".text."; \ - else if (DECL_READONLY_SECTION (DECL, RELOC)) \ - prefix = ".rodata."; \ - else \ - prefix = ".data."; \ - } \ - else if (TREE_CODE (DECL) == FUNCTION_DECL) \ - prefix = ".gnu.linkonce.t."; \ - else if (DECL_READONLY_SECTION (DECL, RELOC)) \ - prefix = ".gnu.linkonce.r."; \ - else \ - prefix = ".gnu.linkonce.d."; \ - \ - len = strlen (name) + strlen (prefix); \ - string = alloca (len + 1); \ - sprintf (string, "%s%s", prefix, name); \ - \ - DECL_SECTION_NAME (DECL) = build_string (len, string); \ - } \ - while (0) - -/* This is how we tell the assembler that a symbol is weak. */ -#ifndef ASM_WEAKEN_LABEL -#define ASM_WEAKEN_LABEL(FILE, NAME) \ - do \ - { \ - fputs ("\t.weak\t", FILE); \ - assemble_name (FILE, NAME); \ - fputc ('\n', FILE); \ - } \ - while (0) -#endif - -#ifndef TYPE_ASM_OP - -/* These macros generate the special .type and .size directives which - are used to set the corresponding fields of the linker symbol table - entries in an ELF object file under SVR4. These macros also output - the starting labels for the relevant functions/objects. */ -#define TYPE_ASM_OP ".type" -#define SIZE_ASM_OP ".size" - -/* The following macro defines the format used to output the second - operand of the .type assembler directive. Different svr4 assemblers - expect various different forms for this operand. The one given here - is just a default. You may need to override it in your machine- - specific tm.h file (depending upon the particulars of your assembler). */ -#define TYPE_OPERAND_FMT "%s" - -/* Write the extra assembler code needed to declare a function's result. - Most svr4 assemblers don't require any special declaration of the - result value, but there are exceptions. */ -#ifndef ASM_DECLARE_RESULT -#define ASM_DECLARE_RESULT(FILE, RESULT) -#endif - -/* Write the extra assembler code needed to declare a function properly. - Some svr4 assemblers need to also have something extra said about the - function's return value. We allow for that here. */ -#undef ASM_DECLARE_FUNCTION_NAME -#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ - do \ - { \ - fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ - assemble_name (FILE, NAME); \ - putc (',', FILE); \ - fprintf (FILE, TYPE_OPERAND_FMT, "function"); \ - putc ('\n', FILE); \ - ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \ - if (! is_called_in_ARM_mode (decl)) \ - fprintf (FILE, "\t.thumb_func\n") ; \ - else \ - fprintf (FILE, "\t.code\t32\n") ; \ - ASM_OUTPUT_LABEL(FILE, NAME); \ - } \ - while (0) - -/* Write the extra assembler code needed to declare an object properly. */ -#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ - do \ - { \ - fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ - assemble_name (FILE, NAME); \ - putc (',', FILE); \ - fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ - putc ('\n', FILE); \ - size_directive_output = 0; \ - if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ - { \ - size_directive_output = 1; \ - fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ - assemble_name (FILE, NAME); \ - putc (',', FILE); \ - fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \ - int_size_in_bytes (TREE_TYPE (DECL))); \ - fputc ('\n', FILE); \ - } \ - ASM_OUTPUT_LABEL(FILE, NAME); \ - } \ - while (0) - -/* Output the size directive for a decl in rest_of_decl_compilation - in the case where we did not do so before the initializer. - Once we find the error_mark_node, we know that the value of - size_directive_output was set - by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */ -#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END)\ - do \ - { \ - const char * name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ - if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \ - && ! AT_END && TOP_LEVEL \ - && DECL_INITIAL (DECL) == error_mark_node \ - && !size_directive_output) \ - { \ - size_directive_output = 1; \ - fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ - assemble_name (FILE, name); \ - putc (',', FILE); \ - fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \ - int_size_in_bytes (TREE_TYPE (DECL))); \ - fputc ('\n', FILE); \ - } \ - } \ - while (0) - -/* This is how to declare the size of a function. */ -#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ - do \ - { \ - if (!flag_inhibit_size_directive) \ - { \ - char label[256]; \ - static int labelno; \ - labelno ++; \ - ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ - ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \ - fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ - assemble_name (FILE, (FNAME)); \ - fprintf (FILE, ","); \ - assemble_name (FILE, label); \ - fprintf (FILE, "-"); \ - assemble_name (FILE, (FNAME)); \ - putc ('\n', FILE); \ - } \ - } \ - while (0) - -#endif /* TYPE_ASM_OP */ diff --git a/gcc/config/arm/thumb.c b/gcc/config/arm/thumb.c deleted file mode 100644 index 79de0b6ca2d..00000000000 --- a/gcc/config/arm/thumb.c +++ /dev/null @@ -1,2426 +0,0 @@ -/* Output routines for GCC for ARM/Thumb - Copyright (C) 1996, 2000 Cygnus Software Technologies Ltd - The basis of this contribution was generated by - Richard Earnshaw, Advanced RISC Machines Ltd - -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 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. */ - -#include "config.h" -#include "system.h" -#include "rtl.h" -#include "hard-reg-set.h" -#include "regs.h" -#include "output.h" -#include "insn-flags.h" -#include "insn-attr.h" -#include "flags.h" -#include "tree.h" -#include "function.h" -#include "expr.h" -#include "insn-config.h" -#include "recog.h" -#include "toplev.h" -#include "thumb-protos.h" - - -int current_function_anonymous_args = 0; - -/* Used to parse -mstructure_size_boundary command line option. */ -const char * structure_size_string = NULL; -int arm_structure_size_boundary = 32; /* Used to be 8 */ - -/* The register number to be used for the PIC offset register. */ -const char * thumb_pic_register_string = NULL; -int thumb_pic_register = 10; - -/* True if we are currently building a constant table. */ -int making_const_table; - - -/* Predicates */ -int -reload_memory_operand (op, mode) - rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED ; -{ - int regno = true_regnum (op); - - 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; -{ - 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; -{ - HOST_WIDE_INT mask = 0xff; - int i; - - for (i = 0; i < 25; i++) - if ((val & (mask << i)) == val) - return 1; - - return 0; -} - -int -thumb_trivial_epilogue () -{ - /* ??? 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; - - for (regno = 8; regno < 13; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - return 0; - - return 1; -#endif -} - - -/* Return TRUE if X references a SYMBOL_REF. */ -int -thumb_symbol_mentioned_p (x) - rtx x; -{ - register const char * fmt; - register int i; - - if (GET_CODE (x) == SYMBOL_REF) - return 1; - - fmt = GET_RTX_FORMAT (GET_CODE (x)); - for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) - { - if (fmt[i] == 'E') - { - register int j; - - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - if (thumb_symbol_mentioned_p (XVECEXP (x, i, j))) - return 1; - } - else if (fmt[i] == 'e' && thumb_symbol_mentioned_p (XEXP (x, i))) - return 1; - } - - return 0; -} - -/* Return TRUE if X references a LABEL_REF. */ -int -label_mentioned_p (x) - rtx x; -{ - register const char * fmt; - register int i; - - if (GET_CODE (x) == LABEL_REF) - return 1; - - fmt = GET_RTX_FORMAT (GET_CODE (x)); - for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) - { - if (fmt[i] == 'E') - { - register int j; - - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - if (label_mentioned_p (XVECEXP (x, i, j))) - return 1; - } - else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i))) - return 1; - } - - return 0; -} - -rtx -legitimize_pic_address (orig, mode, reg) - rtx orig; - enum machine_mode mode; - rtx reg; -{ - if (GET_CODE (orig) == SYMBOL_REF) - { - rtx pic_ref, address; - rtx insn; - int subregs = 0; - - if (reg == 0) - { - if (reload_in_progress || reload_completed) - abort (); - else - reg = gen_reg_rtx (Pmode); - - subregs = 1; - } - -#ifdef AOF_ASSEMBLER - /* The AOF assembler can generate relocations for these directly, and - understands that the PIC register has to be added into the offset. - */ - insn = emit_insn (gen_pic_load_addr_based (reg, orig)); -#else - if (subregs) - address = gen_reg_rtx (Pmode); - else - address = reg; - - emit_insn (gen_pic_load_addr (address, orig)); - - pic_ref = gen_rtx_MEM (Pmode, - gen_rtx_PLUS (Pmode, pic_offset_table_rtx, - address)); - RTX_UNCHANGING_P (pic_ref) = 1; - insn = emit_move_insn (reg, pic_ref); -#endif - current_function_uses_pic_offset_table = 1; - /* Put a REG_EQUAL note on this insn, so that it can be optimized - by loop. */ - REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig, - REG_NOTES (insn)); - return reg; - } - else if (GET_CODE (orig) == CONST) - { - rtx base, offset; - - if (GET_CODE (XEXP (orig, 0)) == PLUS - && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) - return orig; - - if (reg == 0) - { - if (reload_in_progress || reload_completed) - abort (); - else - reg = gen_reg_rtx (Pmode); - } - - if (GET_CODE (XEXP (orig, 0)) == PLUS) - { - base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); - offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, - base == reg ? 0 : reg); - } - else - abort (); - - if (GET_CODE (offset) == CONST_INT) - { - /* The base register doesn't really matter, we only want to - test the index for the appropriate mode. */ - if (INDEX_REGISTER_RTX_P (offset) && GET_MODE_SIZE (mode) <= 4) - goto win; - - if (! reload_in_progress && ! reload_completed) - offset = force_reg (Pmode, offset); - else - abort (); - - win: - if (GET_CODE (offset) == CONST_INT) - return plus_constant_for_output (base, INTVAL (offset)); - } - - if (GET_MODE_SIZE (mode) > 4) - { - emit_insn (gen_addsi3 (reg, base, offset)); - return reg; - } - - return gen_rtx_PLUS (Pmode, base, offset); - } - else if (GET_CODE (orig) == LABEL_REF) - current_function_uses_pic_offset_table = 1; - - return orig; -} - -static rtx pic_rtx; - -int -is_pic (x) - rtx x; -{ - if (x == pic_rtx) - return 1; - return 0; -} - -void -thumb_finalize_pic () -{ -#ifndef AOF_ASSEMBLER - rtx l1, pic_tmp, pic_tmp2, seq; - rtx global_offset_table; - - if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE) - return; - - if (! flag_pic) - abort (); - - start_sequence (); - l1 = gen_label_rtx (); - - global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); - /* On the Thumb the PC register contains 'dot + 4' at the time of the - addition. XXX Is this true? */ - pic_tmp = plus_constant (gen_rtx_LABEL_REF (Pmode, l1), 4); - if (GOT_PCREL) - pic_tmp2 = gen_rtx_CONST (VOIDmode, - gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx)); - else - pic_tmp2 = gen_rtx_CONST (VOIDmode, global_offset_table); - - pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp)); - - emit_insn (gen_pic_load_addr (pic_offset_table_rtx, pic_rtx)); - emit_insn (gen_pic_add_dot_plus_four (pic_offset_table_rtx, l1)); - - seq = gen_sequence (); - end_sequence (); - emit_insn_after (seq, get_insns ()); - - /* Need to emit this whether or not we obey regdecls, - since setjmp/longjmp can cause life info to screw up. */ - emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx)); -#endif /* AOF_ASSEMBLER */ -} - - -/* Routines for handling the constant pool */ -/* This is unashamedly hacked from the version in sh.c, since the problem is - extremely similar. */ - -/* Thumb instructions cannot load a large constant into a register, - constants have to come from a pc relative load. The reference of a pc - 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: - .. - - 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: - - 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 */ -} pool_node; - -/* The maximum number of constants that can fit into one pool, since - the pc relative range is 0...1020 bytes and constants are at least 4 - bytes long */ - -#define MAX_POOL_SIZE (1020/4) -static pool_node pool_vector[MAX_POOL_SIZE]; -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; -{ - int i; - 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)); -#ifndef AOF_ASSEMBLER - else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == 3) - x = XVECEXP (x, 0, 0); -#endif - - /* 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 == CODE_LABEL) - { - 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); - } - } - - /* 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; -{ - 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); - - 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; - } - } - - 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; -{ -#ifndef AOF_ASSEMBLER - if (GET_CODE (src) == UNSPEC && XINT (src, 1) == 3) - return 1; -#endif - 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; -{ - int count = 0; - rtx found_barrier = 0; - rtx label; - - 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)))) - 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; -} - -/* Non zero if the insn is a move instruction which needs to be fixed. */ -static int -broken_move (insn) - rtx insn; -{ - 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); - } - 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'. */ - -static void -replace_symbols_in_block (tree block, rtx orig, rtx new) -{ - 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); - } -} - -void -thumb_reorg (first) - rtx first; -{ - 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); - } - } -} - - -/* Routines for generating rtl. */ -void -thumb_expand_movstrqi (operands) - 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; - - while (len >= 12) - { - emit_insn (gen_movmem12b (out, in)); - len -= 12; - } - if (len >= 8) - { - emit_insn (gen_movmem8b (out, in)); - len -= 8; - } - 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; - } - 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; - } - 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)); - } -} - - -/* Routines for reloading */ - -void -thumb_reload_out_si (operands) - rtx operands ATTRIBUTE_UNUSED; -{ - abort (); -} - - -#ifdef THUMB_PE -/* Return non-zero if FUNC is a naked function. */ - -static int -arm_naked_function_p (func) - tree func; -{ - tree a; - - if (TREE_CODE (func) != FUNCTION_DECL) - abort (); - - a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); - return a != NULL_TREE; -} -#endif - -/* Return non-zero if FUNC must be entered in ARM mode. */ -int -is_called_in_ARM_mode (func) - tree func; -{ - if (TREE_CODE (func) != FUNCTION_DECL) - abort (); - - /* Ignore the problem about functions whoes address is taken. */ - if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func)) - return TRUE; - -#ifdef THUMB_PE - return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; -#else - return FALSE; -#endif -} - - -/* Routines for emitting code */ - -void -thumb_final_prescan_insn (insn) - rtx insn; -{ - 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)]); -} - - -static void thumb_pushpop ( FILE *, int, int ); /* Forward declaration. */ - -#ifdef __GNUC__ -inline -#endif -static int -number_of_first_bit_set (mask) - int mask; -{ - int bit; - - for (bit = 0; - (mask & (1 << bit)) == 0; - ++ bit) - continue; - - return bit; -} - -#define ARG_1_REGISTER 0 -#define ARG_2_REGISTER 1 -#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 PROGRAM_COUNTER 15 - -/* 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; -{ - int regs_available_for_popping; - int regs_to_pop; - int pops_needed; - 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; - } - - if (TARGET_BACKTRACE) - { - /* Restore frame pointer and stack pointer. */ - regs_to_pop |= (1 << FRAME_POINTER) | (1 << STACK_POINTER); - pops_needed += 2; - } - - /* If there is nothing to pop then just emit the BX instruction and return. */ - if (pops_needed == 0) - { - asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); - - return; - } - - /* Otherwise if we are not supporting interworking and we have not created - a backtrace structure and the function was not entered in ARM mode then - just pop the return address straight into the PC. */ - else if ( ! TARGET_THUMB_INTERWORK - && ! TARGET_BACKTRACE - && ! is_called_in_ARM_mode (current_function_decl)) - { - 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; - -#ifdef RTX_CODE - /* 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 -#endif - mode = DECL_MODE (DECL_RESULT (current_function_decl)); - - 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 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; - } - } - - /* 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) - { - /* 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); - } - - /* If we popped other registers then handle them here. */ - if (regs_available_for_popping) - { - 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); - } - } - - /* 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) - { - 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; - } - - /* 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); - - /* 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 [move_to], reg_names [popped_into]); - - regs_to_pop &= ~ (1 << move_to); - - -- 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) - { - int popped_into; - - thumb_pushpop (f, regs_available_for_popping, FALSE); - - popped_into = number_of_first_bit_set (regs_available_for_popping); - - asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [popped_into]); - - /* - assert (regs_to_pop == (1 << STACK_POINTER)) - assert (pops_needed == 1) - */ - } - - /* 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]); -} - -/* 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; -{ - int regno; - int lo_mask = mask & 0xFF; - - 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; - } - - 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 (push && (mask & (1 << 14))) - { - /* Catch pushing the LR. */ - - if (mask & 0xFF) - asm_fprintf (f, ", "); - - asm_fprintf (f, reg_names[14]); - } - else if (!push && (mask & (1 << 15))) - { - /* Catch popping the PC. */ - - if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) - { - /* 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]); - } - } - - asm_fprintf (f, "}\n"); -} - -/* Returns non-zero if the current function contains a far jump */ - -int -far_jump_used_p (void) -{ - rtx 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) - return 1; - } - - return 0; -} - -static int return_used_this_function = 0; - -char * -output_return () -{ - int regno; - int live_regs_mask = 0; - -#ifdef THUMB_PE - /* If a function is naked, don't use the "return" insn. */ - if (arm_naked_function_p (current_function_decl)) - return ""; -#endif - - return_used_this_function = 1; - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno] - && ! (TARGET_SINGLE_PIC_BASE && (regno == thumb_pic_register))) - live_regs_mask |= 1 << regno; - - if (live_regs_mask == 0) - { - if (leaf_function_p () && ! far_jump_used_p()) - { - thumb_exit (asm_out_file, 14); - } - else if ( TARGET_THUMB_INTERWORK - || TARGET_BACKTRACE - || is_called_in_ARM_mode (current_function_decl)) - { - thumb_exit (asm_out_file, -1); - } - else - asm_fprintf (asm_out_file, "\tpop\t{pc}\n"); - } - 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 - || TARGET_BACKTRACE - || is_called_in_ARM_mode (current_function_decl)) - { - asm_fprintf (asm_out_file, "}\n"); - thumb_exit (asm_out_file, -1); - } - else - asm_fprintf (asm_out_file, ", pc}\n"); - } - - return ""; -} - -void -thumb_function_prologue (f, frame_size) - FILE * f; - int frame_size ATTRIBUTE_UNUSED; -{ - int live_regs_mask = 0; - int high_regs_pushed = 0; - int store_arg_regs = 0; - int regno; - -#ifdef THUMB_PE - if (arm_naked_function_p (current_function_decl)) - return; -#endif - - if (is_called_in_ARM_mode (current_function_decl)) - { - const char * name; - - if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) - abort(); - if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) - abort(); - name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); - - /* Generate code sequence to switch us into Thumb mode. */ - /* The .code 32 directive has already been emitted by - ASM_DECLARE_FUNCITON_NAME */ - asm_fprintf (f, "\torr\tr12, pc, #1\n"); - asm_fprintf (f, "\tbx\tr12\n"); - - /* Generate a label, so that the debugger will notice the - change in instruction sets. This label is also used by - the assembler to bypass the ARM code when this function - is called from a Thumb encoded function elsewhere in the - same file. Hence the definition of STUB_NAME here must - agree with the definition in gas/config/tc-arm.c */ - -#define STUB_NAME ".real_start_of" - - asm_fprintf (f, "\t.code\t16\n"); - -#ifdef THUMB_PE - if (arm_dllexport_name_p (name)) - name = ARM_STRIP_NAME_ENCODING (name); -#endif - - asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); - asm_fprintf (f, "\t.thumb_func\n"); - asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); - } - - 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); - } - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno] - && ! (TARGET_SINGLE_PIC_BASE && (regno == thumb_pic_register))) - live_regs_mask |= 1 << regno; - - if (live_regs_mask || ! leaf_function_p () || far_jump_used_p ()) - live_regs_mask |= 1 << 14; - - if (TARGET_BACKTRACE) - { - const char * name; - int offset; - int work_register = 0; - - /* We have been asked to create a stack backtrace structure. - The code looks like this: - - 0 .align 2 - 0 func: - 0 sub SP, #16 Reserve space for 4 registers. - 2 push {R7} Get a work register. - 4 add R7, SP, #20 Get the stack pointer before the push. - 6 str R7, [SP, #8] Store the stack pointer (before reserving the space). - 8 mov R7, PC Get hold of the start of this code plus 12. - 10 str R7, [SP, #16] Store it. - 12 mov R7, FP Get hold of the current frame pointer. - 14 str R7, [SP, #4] Store it. - 16 mov R7, LR Get hold of the current return address. - 18 str R7, [SP, #12] Store it. - 20 add R7, SP, #16 Point at the start of the backtrace structure. - 22 mov FP, R7 Put this value into the frame pointer. */ - - if ((live_regs_mask & 0xFF) == 0) - { - /* See if the a4 register is free. */ - - if (regs_ever_live [3] == 0) - work_register = 3; - else /* We must push a register of our own */ - live_regs_mask |= (1 << 7); - } - - if (work_register == 0) - { - /* Select a register from the list that will be pushed to use as our work register. */ - - for (work_register = 8; work_register--;) - if ((1 << work_register) & live_regs_mask) - break; - } - - name = reg_names [work_register]; - - asm_fprintf (f, "\tsub\tsp, sp, #16\t@ Create stack backtrace structure\n"); - - if (live_regs_mask) - thumb_pushpop (f, live_regs_mask, 1); - - for (offset = 0, work_register = 1 << 15; work_register; work_register >>= 1) - if (work_register & live_regs_mask) - offset += 4; - - asm_fprintf (f, "\tadd\t%s, sp, #%d\n", - name, offset + 16 + current_function_pretend_args_size); - - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 4); - - /* Make sure that the instruction fetching the PC is in the right place - to calculate "start of backtrace creation code + 12". */ - - if (live_regs_mask) - { - asm_fprintf (f, "\tmov\t%s, pc\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); - asm_fprintf (f, "\tmov\t%s, fp\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); - } - else - { - asm_fprintf (f, "\tmov\t%s, fp\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); - asm_fprintf (f, "\tmov\t%s, pc\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); - } - - asm_fprintf (f, "\tmov\t%s, lr\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 8); - asm_fprintf (f, "\tadd\t%s, sp, #%d\n", name, offset + 12); - asm_fprintf (f, "\tmov\tfp, %s\t\t@ Backtrace structure created\n", name); - } - else if (live_regs_mask) - thumb_pushpop (f, live_regs_mask, 1); - - for (regno = 8; regno < 13; regno++) - { - if (regs_ever_live[regno] && ! call_used_regs[regno] - && ! (TARGET_SINGLE_PIC_BASE && (regno == thumb_pic_register))) - 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] - && ! (TARGET_SINGLE_PIC_BASE && (next_hi_reg == thumb_pic_register))) - 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] - && ! (TARGET_SINGLE_PIC_BASE - && (next_hi_reg == thumb_pic_register))) - 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]); - } -} - -/* Functions to save and restore thumb_return_addr_rtx. */ -static rtx thumb_return_addr_rtx = NULL_RTX; - -struct machine_function -{ - rtx ra_rtx; -}; - -static void -thumb_save_machine_status (p) - struct function * p; -{ - struct machine_function * machine = - (struct machine_function *) xmalloc (sizeof (* machine)); - - p->machine = machine; - machine->ra_rtx = thumb_return_addr_rtx; -} - -static void -thumb_restore_machine_status (p) - struct function * p; -{ - struct machine_function * machine = p->machine; - - thumb_return_addr_rtx = machine->ra_rtx; - - free (machine); - - p->machine = (struct machine_function *) NULL; -} - -/* Return an RTX indicating where the return address to the - calling function can be found. */ -rtx -thumb_return_addr (count) - int count; -{ - if (count != 0) - return NULL_RTX; - - if (thumb_return_addr_rtx == NULL_RTX) - { - rtx init; - - thumb_return_addr_rtx = gen_reg_rtx (Pmode); - - init = gen_rtx_REG (Pmode, 14); - - init = gen_rtx_SET (VOIDmode, thumb_return_addr_rtx, init); - - /* Emit the insn to the prologue with the other argument copies. */ - push_topmost_sequence (); - emit_insn_after (init, get_insns ()); - pop_topmost_sequence (); - } - - return thumb_return_addr_rtx; -} - -/* Do anything needed before RTL is emitted for each function. */ -void -thumb_init_expanders () -{ - thumb_return_addr_rtx = NULL_RTX; - - /* Arrange to save and restore machine status around nested functions. */ - save_machine_status = thumb_save_machine_status; - restore_machine_status = thumb_restore_machine_status; -} - -void -thumb_expand_prologue () -{ - HOST_WIDE_INT amount = (get_frame_size () - + current_function_outgoing_args_size); -#ifdef THUMB_PE - /* Naked functions don't have prologues. */ - if (arm_naked_function_p (current_function_decl)) - return; -#endif - - if (amount) - { - if (amount < 512) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (- amount))); - else - { - int regno; - rtx reg; - - /* The stack decrement is too big for an immediate value in a single - insn. In theory we could issue multiple subtracts, but after - three of them it becomes more space efficient to place the full - value in the constant pool and load into a register. (Also the - ARM debugger really likes to see only one stack decrement per - function). So instead we look for a scratch register into which - we can load the decrement, and then we subtract this from the - stack pointer. Unfortunately on the thumb the only available - scratch registers are the argument registers, and we cannot use - these as they may hold arguments to the function. Instead we - attempt to locate a call preserved register which is used by this - function. If we can find one, then we know that it will have - been pushed at the start of the prologue and so we can corrupt - it now. */ - for (regno = 4; regno < 8; regno++) - if (regs_ever_live[regno] - && ! call_used_regs[regno] /* Paranoia */ - && ! (TARGET_SINGLE_PIC_BASE && (regno == thumb_pic_register))) - break; - - if (regno == 8) /* Very unlikely */ - { - rtx spare = gen_rtx (REG, SImode, 12); - - /* Choose an arbitary, non-argument low register. */ - reg = gen_rtx (REG, SImode, 4); - - /* Save it by copying it into a high, scratch register. */ - emit_insn (gen_movsi (spare, reg)); - - /* Decrement the stack. */ - emit_insn (gen_movsi (reg, GEN_INT (- amount))); - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - reg)); - - /* Restore the low register's original value. */ - emit_insn (gen_movsi (reg, spare)); - - /* Emit a USE of the restored scratch register, so that flow - analysis will not consider the restore redundant. The - register won't be used again in this function and isn't - restored by the epilogue. */ - emit_insn (gen_rtx_USE (VOIDmode, reg)); - } - else - { - 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)); - } - } - } - - /* This should only happen with optimisation disabled. Emit the copy - *after* the stack adjust, as the unoptimised code will attempt to store - local variables at positive offsets from the frame pointer. */ - 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 (profile_flag || profile_block_flag) - emit_insn (gen_blockage ()); -} - -void -thumb_expand_epilogue () -{ - HOST_WIDE_INT amount = (get_frame_size () - + current_function_outgoing_args_size); -#ifdef THUMB_PE - /* Naked functions don't have epilogues. */ - if (arm_naked_function_p (current_function_decl)) - return; -#endif - - 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)); - } - } - - /* Emit a USE (stack_pointer_rtx), so that - the stack adjustment will not be deleted. */ - emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); - - if (profile_flag || profile_block_flag) - emit_insn (gen_blockage ()); -} - -void -thumb_function_epilogue (f, frame_size) - FILE * f ATTRIBUTE_UNUSED; - int frame_size ATTRIBUTE_UNUSED; -{ - /* ??? 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; -#if 0 /* TODO : comment not really needed */ - fprintf (f, "%s THUMB Epilogue\n", ASM_COMMENT_START); -#endif -} - -/* The bits which aren't usefully expanded as rtl. */ -char * -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; - - if (return_used_this_function) - return ""; - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno] - && ! (TARGET_SINGLE_PIC_BASE && (regno == thumb_pic_register))) - live_regs_mask |= 1 << regno; - - for (regno = 8; regno < 13; regno++) - { - if (regs_ever_live[regno] && ! call_used_regs[regno] - && ! (TARGET_SINGLE_PIC_BASE && (regno == thumb_pic_register))) - 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; - -#ifdef RTX_CODE - /* 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 -#endif - 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] - && ! (TARGET_SINGLE_PIC_BASE && (next_hi_reg == thumb_pic_register))) - 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] - && ! (TARGET_SINGLE_PIC_BASE - && (next_hi_reg == thumb_pic_register))) - break; - } - } - } - } - - had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); - - if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) - /* The stack backtrace structure creation code had to - push R7 in order to get a work register, so we pop - it now. */ - live_regs_mask |= (1 << WORK_REGISTER); - - if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) - { - if (had_to_push_lr - && ! is_called_in_ARM_mode (current_function_decl)) - live_regs_mask |= 1 << PROGRAM_COUNTER; - - /* Either no argument registers were pushed or a backtrace - structure was created which includes an adjusted stack - pointer, 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, - (had_to_push_lr - && is_called_in_ARM_mode (current_function_decl)) ? - -1 : LINK_REGISTER); - } - 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); - } - - return ""; -} - -/* Handle the case of a double word load into a low register from - a computed memory address. The computed address may involve a - register which is overwritten by the load. */ - -char * -thumb_load_double_from_address (operands) - 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)) - { - 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; - - case CONST: - /* Compute
+ 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
= + */ - - 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
+ 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; - - default: - debug_rtx (operands[1]); - fatal ("thumb_load_double_from_address: Unhandled address calculation"); - break; - } - - return ""; -} - -char * -output_move_mem_multiple (n, operands) - int n; - rtx *operands; -{ - rtx tmp; - - 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; - - 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; - - default: - abort (); - } - - return ""; -} - - -int -thumb_epilogue_size () -{ - return 42; /* The answer to .... */ -} - -static char *conds[] = -{ - "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; -{ - int val; - - switch (GET_CODE (x)) - { - case EQ: val = 0; break; - case NE: val = 1; break; - case GEU: val = 2; break; - case LTU: val = 3; break; - case GTU: val = 8; break; - case LEU: val = 9; break; - case GE: val = 10; break; - case LT: val = 11; break; - case GT: val = 12; break; - case LE: val = 13; break; - default: - abort (); - } - - return conds[val ^ invert]; -} - -void -thumb_print_operand (f, x, code) - FILE *f; - rtx x; - int code; -{ - if (code) - { - switch (code) - { - case '@': - fputs (ASM_COMMENT_START, f); - return; - - case '|': - /* fputs (REGISTER_PREFIX, 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; - - 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) - { - fputc ('#', f); - output_addr_const (f, x); - } - else - abort (); -} - -#ifdef AOF_ASSEMBLER -int arm_text_section_count = 1; - -char * -aof_text_section (in_readonly) - int in_readonly; -{ - static char buf[100]; - if (in_readonly) - return ""; - sprintf (buf, "\tCODE16\n\tAREA |C$$code%d|, CODE, READONLY", - arm_text_section_count++); - return buf; -} - -static int arm_data_section_count = 1; - -char * -aof_data_section () -{ - static char buf[100]; - sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++); - return buf; -} - -/* The AOF thumb assembler is religiously strict about declarations of - imported and exported symbols, so that it is impossible to declare a - function as imported near the begining of the file, and then to export - it later on. It is, however, possible to delay the decision until all - the functions in the file have been compiled. To get around this, we - maintain a list of the imports and exports, and delete from it any that - are subsequently defined. At the end of compilation we spit the - remainder of the list out before the END directive. */ - -struct import -{ - struct import *next; - char *name; -}; - -static struct import *imports_list = NULL; - -void -thumb_aof_add_import (name) - char *name; -{ - struct import *new; - - for (new = imports_list; new; new = new->next) - if (new->name == name) - return; - - new = (struct import *) xmalloc (sizeof (struct import)); - new->next = imports_list; - imports_list = new; - new->name = name; -} - -void -thumb_aof_delete_import (name) - char *name; -{ - struct import **old; - - for (old = &imports_list; *old; old = & (*old)->next) - { - if ((*old)->name == name) - { - *old = (*old)->next; - return; - } - } -} - -void -thumb_aof_dump_imports (f) - FILE *f; -{ - while (imports_list) - { - fprintf (f, "\tIMPORT\t"); - assemble_name (f, imports_list->name); - fputc ('\n', f); - imports_list = imports_list->next; - } -} -#endif - -/* Decide whether a type should be returned in memory (true) - or in a register (false). This is called by the macro - RETURN_IN_MEMORY. */ - -int -thumb_return_in_memory (type) - tree type; -{ - if (! AGGREGATE_TYPE_P (type)) - { - /* All simple types are returned in registers. */ - - return 0; - } - else if (int_size_in_bytes (type) > 4) - { - /* All structures/unions bigger than one word are returned in memory. */ - - return 1; - } - 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; - } - 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; - } - /* XXX Not sure what should be done for other aggregates, so put them in - memory. */ - return 1; -} - -void -thumb_override_options () -{ - 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"); - } - - if (thumb_pic_register_string != NULL) - { - int pic_register; - - if (! flag_pic) - warning ("-mpic-register= is useless without -fpic"); - - pic_register = decode_reg_name (thumb_pic_register_string); - - /* Prevent the user from choosing an obviously stupid PIC register. */ - if (pic_register < 0 || call_used_regs[pic_register] - || pic_register == HARD_FRAME_POINTER_REGNUM - || pic_register == STACK_POINTER_REGNUM - || pic_register >= PC_REGNUM) - error ("Unable to use '%s' for PIC register", thumb_pic_register_string); - else - thumb_pic_register = pic_register; - } -} - -#ifdef THUMB_PE -/* Return nonzero if ATTR is a valid attribute for DECL. - ATTRIBUTES are any existing attributes and ARGS are the arguments - supplied with ATTR. - - Supported attributes: - - naked: don't output any prologue or epilogue code, the user is assumed - to do the right thing. - - interfacearm: Always assume that this function will be entered in ARM - mode, not Thumb mode, and that the caller wishes to be returned to in - ARM mode. */ -int -arm_valid_machine_decl_attribute (decl, attr, args) - tree decl; - tree attr; - tree args; -{ - if (args != NULL_TREE) - return 0; - - if (is_attribute_p ("naked", attr)) - if (TREE_CODE (decl) == FUNCTION_DECL) - return 1; - - if (is_attribute_p ("interfacearm", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; - - return 0; -} -#endif /* THUMB_PE */ - diff --git a/gcc/config/arm/thumb.h b/gcc/config/arm/thumb.h deleted file mode 100644 index 4837504a3cf..00000000000 --- a/gcc/config/arm/thumb.h +++ /dev/null @@ -1,1305 +0,0 @@ -/* Definitions of target machine for GNU compiler, for ARM/Thumb. - Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. - The basis of this contribution was generated by - Richard Earnshaw, Advanced RISC Machines Ltd - -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 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. */ - -/* ??? The files thumb.{c,h,md} are all seriously lacking comments. */ - -/* ??? The files thumb.{c,h,md} need to be reviewed by an experienced - gcc hacker in their entirety. */ - -/* ??? The files thumb.{c,h,md} and tcoff.h are all separate from the arm - files, which will lead to many maintenance problems. These files are - likely missing all bug fixes made to the arm port since they diverged. */ - -/* ??? Many patterns in the md file accept operands that will require a - reload. These should be eliminated if possible by tightening the - predicates and/or constraints. This will give faster/smaller code. */ - -/* ??? There is no pattern for the TST instuction. Check for other unsupported - instructions. */ - -/* Run Time Target Specifications */ -#ifndef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dthumb -D__thumb -Acpu(arm) -Amachine(arm)" -#endif - -#ifndef CPP_SPEC -#define CPP_SPEC "\ -%{mbig-endian:-D__ARMEB__ -D__THUMBEB__} \ -%{mbe:-D__ARMEB__ -D__THUMBEB__} \ -%{!mbe: %{!mbig-endian:-D__ARMEL__ -D__THUMBEL__}} \ -" -#endif - -#define ASM_SPEC "-marm7tdmi %{mthumb-interwork:-mthumb-interwork} %{mbig-endian:-EB}" -#ifndef LINK_SPEC -#define LINK_SPEC "%{mbig-endian:-EB} -X" -#endif - -#define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr); - -/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ -#define THUMB_FLAG_BIG_END 0x0001 -#define THUMB_FLAG_BACKTRACE 0x0002 -#define THUMB_FLAG_LEAF_BACKTRACE 0x0004 -#define ARM_FLAG_THUMB 0x1000 /* same as in arm.h */ -#define THUMB_FLAG_SINGLE_PIC_BASE 0x4000 /* same as in arm.h */ -#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING 0x40000 -#define THUMB_FLAG_CALLER_SUPER_INTERWORKING 0x80000 - - -/* Run-time compilation parameters selecting different hardware/software subsets. */ -extern int target_flags; -#define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */ -#define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END) -#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) -#define TARGET_BACKTRACE (leaf_function_p() \ - ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ - : (target_flags & THUMB_FLAG_BACKTRACE)) -#define TARGET_SINGLE_PIC_BASE (target_flags & THUMB_FLAG_SINGLE_PIC_BASE) - -#ifndef GOT_PCREL -#define GOT_PCREL 0 -#endif - -#ifndef NEED_GOT_RELOC -#define NEED_GOT_RELOC 1 -#endif - -/* Set if externally visible functions should assume that they - might be called in ARM mode, from a non-thumb aware code. */ -#define TARGET_CALLEE_INTERWORKING \ - (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING) - -/* Set if calls via function pointers should assume that their - destination is non-Thumb aware. */ -#define TARGET_CALLER_INTERWORKING \ - (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING) - -/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */ -#ifndef SUBTARGET_SWITCHES -#define SUBTARGET_SWITCHES -#endif - -#define TARGET_SWITCHES \ -{ \ - {"big-endian", THUMB_FLAG_BIG_END, ""}, \ - {"little-endian", -THUMB_FLAG_BIG_END, ""}, \ - {"thumb-interwork", ARM_FLAG_THUMB, ""}, \ - {"no-thumb-interwork", -ARM_FLAG_THUMB, ""}, \ - {"tpcs-frame", THUMB_FLAG_BACKTRACE, ""}, \ - {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE, ""}, \ - {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE, ""}, \ - {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE, ""}, \ - {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING, ""}, \ - {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING, ""}, \ - {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING, ""}, \ - {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING, ""}, \ - {"single-pic-base", THUMB_FLAG_SINGLE_PIC_BASE, \ - "Do not load the PIC register in function prologues" }, \ - {"no-single-pic-base", -THUMB_FLAG_SINGLE_PIC_BASE, ""}, \ - SUBTARGET_SWITCHES \ - {"", TARGET_DEFAULT, ""} \ -} - -#define TARGET_OPTIONS \ -{ \ - { "structure-size-boundary=", & structure_size_string, \ - "Specify the structure aligment: 8 or 32 bits" }, \ - { "pic-register=", & thumb_pic_register_string, \ - "Specify the register to be used for PIC addressing" } \ -} - -#define REGISTER_PREFIX "" - -#define CAN_DEBUG_WITHOUT_FP 1 - -#define ASM_APP_ON "" -#define ASM_APP_OFF "\t.code\t16\n" - -/* Output a gap. In fact we fill it with nulls. */ -#define ASM_OUTPUT_SKIP(STREAM, NBYTES) \ - fprintf ((STREAM), "\t.space\t%u\n", (NBYTES)) - -/* This is how to output an assembler line that says to advance the - location counter to a multiple of 2**LOG bytes. Advancing to the - nearest 1 byte boundary is redundant, and anyway the assembler would - treat it as meaning "advance to nearest 4 byte boundary", which we do - not want. */ -#define ASM_OUTPUT_ALIGN(STREAM,LOG) \ - do \ - { \ - if ((LOG) > 0) \ - fprintf (STREAM, "\t.align\t%d\n", LOG); \ - } \ - while (0) - -/* Output a common block */ -#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ - (fprintf ((STREAM), "\t.comm\t"), \ - assemble_name ((STREAM), (NAME)), \ - fprintf((STREAM), ", %d\t%s %d\n", (ROUNDED), (ASM_COMMENT_START), (SIZE))) - -#define ASM_GENERATE_INTERNAL_LABEL(STRING,PREFIX,NUM) \ - sprintf ((STRING), "*%s%s%d", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) - -/* This is how to output an internal numbered label where - PREFIX is the class of label and NUM is the number within the class. */ -#define ASM_OUTPUT_INTERNAL_LABEL(STREAM,PREFIX,NUM) \ - fprintf ((STREAM), "%s%s%d:\n", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) - -/* This is how to output a label which precedes a jumptable. Since - instructions are 2 bytes, we need explicit alignment here. */ - -#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ - do { \ - ASM_OUTPUT_ALIGN (FILE, 2); \ - ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \ - } while (0) - -/* This says how to define a local common symbol (ie, not visible to - linker). */ -#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ - (fprintf((STREAM),"\n\t.lcomm\t"), \ - assemble_name((STREAM),(NAME)), \ - fprintf((STREAM),",%u\n",(SIZE))) - -/* Output a reference to a label. */ -#define ASM_OUTPUT_LABELREF(STREAM,NAME) \ - fprintf ((STREAM), "%s%s", user_label_prefix, (NAME)) - -/* This is how to output an assembler line for a numeric constant byte. */ -#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ - fprintf ((STREAM), "\t.byte\t0x%x\n", (VALUE)) - -#define ASM_OUTPUT_INT(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.word\t"); \ - OUTPUT_INT_ADDR_CONST (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.short\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.byte\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ -do { char dstr[30]; \ - long l[3]; \ - REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ - fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n", \ - l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ - } while (0) - -#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ -do { char dstr[30]; \ - long l[2]; \ - REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ - fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ - l[1], ASM_COMMENT_START, dstr); \ - } while (0) - -#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ -do { char dstr[30]; \ - long l; \ - REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ - fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ - ASM_COMMENT_START, dstr); \ - } while (0); - -/* Define results of standard character escape sequences. */ -#define TARGET_BELL 007 -#define TARGET_BS 010 -#define TARGET_TAB 011 -#define TARGET_NEWLINE 012 -#define TARGET_VT 013 -#define TARGET_FF 014 -#define TARGET_CR 015 - -/* This is how to output a string. */ -#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ -do { \ - register int i, c, len = (LEN), cur_pos = 17; \ - register const unsigned char *string = (const unsigned char *)(STRING); \ - fprintf ((STREAM), "\t.ascii\t\""); \ - for (i = 0; i < len; i++) \ - { \ - register int c = string[i]; \ - \ - switch (c) \ - { \ - case '\"': \ - case '\\': \ - putc ('\\', (STREAM)); \ - putc (c, (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_NEWLINE: \ - fputs ("\\n", (STREAM)); \ - if (i+1 < len \ - && (((c = string[i+1]) >= '\040' && c <= '~') \ - || c == TARGET_TAB)) \ - cur_pos = 32767; /* break right here */ \ - else \ - cur_pos += 2; \ - break; \ - \ - case TARGET_TAB: \ - fputs ("\\t", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_FF: \ - fputs ("\\f", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_BS: \ - fputs ("\\b", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_CR: \ - fputs ("\\r", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - default: \ - if (c >= ' ' && c < 0177) \ - { \ - putc (c, (STREAM)); \ - cur_pos++; \ - } \ - else \ - { \ - fprintf ((STREAM), "\\%03o", c); \ - cur_pos += 4; \ - } \ - } \ - \ - if (cur_pos > 72 && i+1 < len) \ - { \ - cur_pos = 17; \ - fprintf ((STREAM), "\"\n\t.ascii\t\""); \ - } \ - } \ - fprintf ((STREAM), "\"\n"); \ -} while (0) - -/* Output and Generation of Labels */ -#define ASM_OUTPUT_LABEL(STREAM,NAME) \ - (assemble_name ((STREAM), (NAME)), \ - fprintf ((STREAM), ":\n")) - -#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ - (fprintf ((STREAM), "\t.globl\t"), \ - assemble_name ((STREAM), (NAME)), \ - fputc ('\n', (STREAM))) - -/* Construct a private name. */ -#define ASM_FORMAT_PRIVATE_NAME(OUTVAR,NAME,NUMBER) \ - ((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \ - sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) - -/* Switch to the text or data segment. */ -#define TEXT_SECTION_ASM_OP ".text" -#define DATA_SECTION_ASM_OP ".data" -#define BSS_SECTION_ASM_OP ".bss" - -/* The assembler's names for the registers. */ -#ifndef REGISTER_NAMES -#define REGISTER_NAMES \ -{ \ - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ - "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", "ap" \ -} -#endif - -#ifndef ADDITIONAL_REGISTER_NAMES -#define ADDITIONAL_REGISTER_NAMES \ -{ \ - {"a1", 0}, \ - {"a2", 1}, \ - {"a3", 2}, \ - {"a4", 3}, \ - {"v1", 4}, \ - {"v2", 5}, \ - {"v3", 6}, \ - {"v4", 7}, \ - {"v5", 8}, \ - {"v6", 9}, \ - {"sb", 9}, \ - {"v7", 10}, \ - {"r10", 10}, /* sl */ \ - {"r11", 11}, /* fp */ \ - {"r12", 12}, /* ip */ \ - {"r13", 13}, /* sp */ \ - {"r14", 14}, /* lr */ \ - {"r15", 15} /* pc */ \ -} -#endif - -/* The assembler's parentheses characters. */ -#define ASM_OPEN_PAREN "(" -#define ASM_CLOSE_PAREN ")" - -#ifndef ASM_COMMENT_START -#define ASM_COMMENT_START "@" -#endif - -/* Output an element of a dispatch table. */ -#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ - fprintf (STREAM, "\t.word\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) - -#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ - fprintf (STREAM, "\tb\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) - -/* Storage Layout */ - -/* Define this is most significant bit is lowest numbered in - instructions that operate on numbered bit-fields. */ -#define BITS_BIG_ENDIAN 0 - -/* Define this if most significant byte of a word is the lowest - numbered. */ -#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) - -#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN) - -/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based - on processor pre-defineds when compiling libgcc2.c. */ -#if defined(__THUMBEB__) && !defined(__THUMBEL__) -#define LIBGCC2_WORDS_BIG_ENDIAN 1 -#else -#define LIBGCC2_WORDS_BIG_ENDIAN 0 -#endif - -#define FLOAT_WORDS_BIG_ENDIAN 1 - -#define BITS_PER_UNIT 8 -#define BITS_PER_WORD 32 - -#define UNITS_PER_WORD 4 - -#define POINTER_SIZE 32 - -#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ -{ \ - if (GET_MODE_CLASS (MODE) == MODE_INT \ - && GET_MODE_SIZE (MODE) < 4) \ - { \ - (UNSIGNEDP) = 1; \ - (MODE) = SImode; \ - } \ -} - -#define PARM_BOUNDARY 32 -#define STACK_BOUNDARY 32 - -#define FUNCTION_BOUNDARY 32 -#define BIGGEST_ALIGNMENT 32 - -/* Make strings word-aligned so strcpy from constants will be faster. */ -#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ - (TREE_CODE (EXP) == STRING_CST \ - && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) - -#define EMPTY_FIELD_BOUNDARY 32 - -#define STRUCTURE_SIZE_BOUNDARY 32 - -/* Used when parsing command line option -mstructure_size_boundary. */ -extern const char * structure_size_string; - -#define STRICT_ALIGNMENT 1 - -#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT - - -/* Layout of Source Language Data Types */ - -#define DEFAULT_SIGNED_CHAR 0 - -#define TARGET_BELL 007 -#define TARGET_BS 010 -#define TARGET_TAB 011 -#define TARGET_NEWLINE 012 -#define TARGET_VT 013 -#define TARGET_FF 014 -#define TARGET_CR 015 - - -/* Register Usage */ - -/* Note there are 16 hard registers on the Thumb. We invent a 17th register - which is assigned to ARG_POINTER_REGNUM, but this is later removed by - elimination passes in the compiler. */ -#define FIRST_PSEUDO_REGISTER 17 - -/* ??? This is questionable. */ -#define FIXED_REGISTERS \ -{ \ - 0,0,0,0, \ - 0,0,0,0, \ - 0,0,0,1, \ - 0,1,1,1,1 \ -} - -/* ??? This is questionable. */ -#define CALL_USED_REGISTERS \ -{ \ - 1,1,1,1, \ - 0,0,0,0, \ - 0,0,0,1, \ - 1,1,1,1,1 \ -} - -#define HARD_REGNO_NREGS(REGNO,MODE) \ - ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ - / UNITS_PER_WORD) - -/* ??? Probably should only allow DImode/DFmode in even numbered registers. */ -#define HARD_REGNO_MODE_OK(REGNO,MODE) ((GET_MODE_SIZE (MODE) > UNITS_PER_WORD) ? (REGNO < 7) : 1) - -#define MODES_TIEABLE_P(MODE1,MODE2) 1 - -/* The NOARG_LO_REGS class is the set of LO_REGS that are not used for passing - arguments to functions. These are the registers that are available for - spilling during reload. The code in reload1.c:init_reload() will detect this - class and place it into 'reload_address_base_reg_class'. */ - -enum reg_class -{ - NO_REGS, - NONARG_LO_REGS, - LO_REGS, - STACK_REG, - BASE_REGS, - HI_REGS, - ALL_REGS, - LIM_REG_CLASSES -}; - -#define GENERAL_REGS ALL_REGS - -#define N_REG_CLASSES (int) LIM_REG_CLASSES - -#define REG_CLASS_NAMES \ -{ \ - "NO_REGS", \ - "NONARG_LO_REGS", \ - "LO_REGS", \ - "STACK_REG", \ - "BASE_REGS", \ - "HI_REGS", \ - "ALL_REGS" \ -} - -#define REG_CLASS_CONTENTS \ -{ \ - { 0x00000 }, \ - { 0x000f0 }, \ - { 0x000ff }, \ - { 0x02000 }, \ - { 0x020ff }, \ - { 0x0ff00 }, \ - { 0x1ffff }, \ -} - -#define REGNO_REG_CLASS(REGNO) \ - ((REGNO) == STACK_POINTER_REGNUM ? STACK_REG \ - : (REGNO) < 8 ? ((REGNO) < 4 ? LO_REGS \ - : NONARG_LO_REGS) \ - : HI_REGS) - -#define BASE_REG_CLASS BASE_REGS - -#define INDEX_REG_CLASS LO_REGS - -/* When SMALL_REGISTER_CLASSES is nonzero, the compiler allows - registers explicitly used in the rtl to be used as spill registers - but prevents the compiler from extending the lifetime of these - registers. */ - -#define SMALL_REGISTER_CLASSES 1 - -#define REG_CLASS_FROM_LETTER(C) \ - ((C) == 'l' ? LO_REGS \ - : (C) == 'h' ? HI_REGS \ - : (C) == 'b' ? BASE_REGS \ - : (C) == 'k' ? STACK_REG \ - : NO_REGS) - -#define REGNO_OK_FOR_BASE_P(REGNO) \ - ((REGNO) < 8 \ - || (REGNO) == STACK_POINTER_REGNUM \ - || (unsigned) reg_renumber[REGNO] < 8 \ - || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM) - -#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ - ((REGNO) < 8 \ - || (unsigned) reg_renumber[REGNO] < 8 \ - || (GET_MODE_SIZE (MODE) >= 4 \ - && ((REGNO) == STACK_POINTER_REGNUM \ - || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM))) - -#define REGNO_OK_FOR_INDEX_P(REGNO) \ - ((REGNO) < 8 \ - || (unsigned) reg_renumber[REGNO] < 8) - -#define INDEX_REGISTER_RTX_P(X) \ - (GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) - -/* ??? This looks suspiciously wrong. */ -/* We need to leave BASE_REGS reloads alone, in order to avoid caller_save - lossage. Caller_saves requests a BASE_REGS reload (caller_save_spill_class) - and then later we verify that one was allocated. If PREFERRED_RELOAD_CLASS - says to allocate a LO_REGS spill instead, then this mismatch gives an - abort. Alternatively, this could be fixed by modifying BASE_REG_CLASS - to be LO_REGS instead of BASE_REGS. It is not clear what affect this - change would have. */ -/* ??? This looks even more suspiciously wrong. PREFERRED_RELOAD_CLASS - must always return a strict subset of the input class. Just blindly - returning LO_REGS is safe only if the input class is a superset of LO_REGS, - but there is no check for this. Added another exception for NONARG_LO_REGS - because it is not a superset of LO_REGS. */ -/* ??? We now use NONARG_LO_REGS for caller_save_spill_class, so the - comments about BASE_REGS are now obsolete. */ -#define PREFERRED_RELOAD_CLASS(X,CLASS) \ - ((CLASS) == BASE_REGS || (CLASS) == NONARG_LO_REGS ? (CLASS) \ - : LO_REGS) -/* - ((CONSTANT_P ((X)) && GET_CODE ((X)) != CONST_INT \ - && ! CONSTANT_POOL_ADDRESS_P((X))) ? NO_REGS \ - : (GET_CODE ((X)) == CONST_INT \ - && (unsigned HOST_WIDE_INT) INTVAL ((X)) > 255) ? NO_REGS \ - : LO_REGS) */ - -/* Must leave BASE_REGS and NONARG_LO_REGS reloads alone, see comment - above. */ -#define SECONDARY_RELOAD_CLASS(CLASS,MODE,X) \ - ((CLASS) != LO_REGS && (CLASS) != BASE_REGS && (CLASS) != NONARG_LO_REGS \ - ? ((true_regnum (X) == -1 ? LO_REGS \ - : (true_regnum (X) + HARD_REGNO_NREGS (0, MODE) > 8) ? LO_REGS \ - : NO_REGS)) \ - : NO_REGS) - -#define CLASS_MAX_NREGS(CLASS,MODE) HARD_REGNO_NREGS(0,(MODE)) - -int thumb_shiftable_const (); - -#define CONST_OK_FOR_LETTER_P(VAL,C) \ - ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VAL) < 256 \ - : (C) == 'J' ? (VAL) > -256 && (VAL) <= 0 \ - : (C) == 'K' ? thumb_shiftable_const (VAL) \ - : (C) == 'L' ? (VAL) > -8 && (VAL) < 8 \ - : (C) == 'M' ? ((unsigned HOST_WIDE_INT) (VAL) < 1024 \ - && ((VAL) & 3) == 0) \ - : (C) == 'N' ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ - : (C) == 'O' ? ((VAL) >= -508 && (VAL) <= 508) \ - : 0) - -#define CONST_DOUBLE_OK_FOR_LETTER_P(VAL,C) 0 - -#define EXTRA_CONSTRAINT(X,C) \ - ((C) == 'Q' ? (GET_CODE (X) == MEM \ - && GET_CODE (XEXP (X, 0)) == LABEL_REF) : 0) - -/* Stack Layout and Calling Conventions */ - -#define STACK_GROWS_DOWNWARD 1 - -/* #define FRAME_GROWS_DOWNWARD 1 */ - -/* #define ARGS_GROW_DOWNWARD 1 */ - -#define STARTING_FRAME_OFFSET 0 - -#define FIRST_PARM_OFFSET(FNDECL) 0 - -/* Registers that address the stack frame */ - -#define STACK_POINTER_REGNUM 13 /* Defined by the TPCS. */ - -#define FRAME_POINTER_REGNUM 7 /* TPCS defines this as 11 but it does not really mean it. */ - -#define ARG_POINTER_REGNUM 16 /* A fake hard register that is eliminated later on. */ - -#define STATIC_CHAIN_REGNUM 9 - -/* Define this if the program counter is overloaded on a register. */ -#define PC_REGNUM 15 - -#define FRAME_POINTER_REQUIRED 0 - -#define ELIMINABLE_REGS \ -{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ - {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ - {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} - -/* On the Thumb we always want to perform the eliminations as we - actually only have one real register pointing to the stashed - variables: the stack pointer, and we never use the frame pointer. */ -#define CAN_ELIMINATE(FROM,TO) 1 - -/* Note: This macro must match the code in thumb_function_prologue() in thumb.c. */ -#define INITIAL_ELIMINATION_OFFSET(FROM,TO,OFFSET) \ -{ \ - (OFFSET) = 0; \ - if ((FROM) == ARG_POINTER_REGNUM) \ - { \ - int count_regs = 0; \ - int regno; \ - (OFFSET) += get_frame_size (); \ - for (regno = 8; regno < 13; regno++) \ - if (regs_ever_live[regno] && ! call_used_regs[regno]) \ - count_regs++; \ - if (count_regs) \ - (OFFSET) += 4 * count_regs; \ - count_regs = 0; \ - for (regno = 0; regno < 8; regno++) \ - if (regs_ever_live[regno] && ! call_used_regs[regno]) \ - count_regs++; \ - if (count_regs || ! leaf_function_p () || far_jump_used_p()) \ - (OFFSET) += 4 * (count_regs + 1); \ - if (TARGET_BACKTRACE) { \ - if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0)) \ - (OFFSET) += 20; \ - else \ - (OFFSET) += 16; } \ - } \ - if ((TO) == STACK_POINTER_REGNUM) \ - (OFFSET) += current_function_outgoing_args_size; \ -} - -/* A C expression whose value is RTL representing the value of the return - address for the frame COUNT steps up from the current frame. */ - -#define RETURN_ADDR_RTX(COUNT, FRAME) \ - thumb_return_addr (COUNT) -/* Passing Arguments on the stack */ - -/* Initialize data used by insn expanders. This is called from insn_emit, - once for every function before code is generated. */ -#define INIT_EXPANDERS thumb_init_expanders () - -#define PROMOTE_PROTOTYPES 1 - -#define ACCUMULATE_OUTGOING_ARGS 1 - -#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 - -#define FUNCTION_ARG(CUM,MODE,TYPE,NAMED) \ - ((NAMED) ? ((CUM) >= 16 ? 0 : gen_rtx (REG, (MODE), (CUM) / 4)) \ - : 0) - -#define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) \ - (((CUM) < 16 && (CUM) + (((MODE) == BLKmode) \ - ? int_size_in_bytes (TYPE) \ - : HARD_REGNO_NREGS (0, (MODE)) * 4) > 16) \ - ? 4 - (CUM) / 4 : 0) - -#define CUMULATIVE_ARGS int - -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ - ((CUM) = ((FNTYPE) && aggregate_value_p (TREE_TYPE (FNTYPE))) ? 4 : 0) - -#define FUNCTION_ARG_ADVANCE(CUM,MODE,TYPE,NAMED) \ - (CUM) += ((((MODE) == BLKmode) \ - ? int_size_in_bytes (TYPE) \ - : GET_MODE_SIZE (MODE)) + 3) & ~3 - -#define FUNCTION_ARG_REGNO_P(REGNO) \ - ((REGNO) >=0 && (REGNO) <= 3) - -#define FUNCTION_VALUE(VALTYPE,FUNC) gen_rtx (REG, TYPE_MODE (VALTYPE), 0) - -#define LIBCALL_VALUE(MODE) gen_rtx (REG, (MODE), 0) - -#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == 0) - - /* How large values are returned */ -/* A C expression which can inhibit the returning of certain function values - in registers, based on the type of value. */ -#define RETURN_IN_MEMORY(TYPE) thumb_return_in_memory (TYPE) - -/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return - values must be in memory. On the ARM, they need only do so if larger - than a word, or if they contain elements offset from zero in the struct. */ -#define DEFAULT_PCC_STRUCT_RETURN 0 - - -#define STRUCT_VALUE_REGNUM 0 - -#define FUNCTION_PROLOGUE(FILE,SIZE) thumb_function_prologue((FILE),(SIZE)) - -#define FUNCTION_EPILOGUE(FILE,SIZE) thumb_function_epilogue((FILE),(SIZE)) - -/* Generating code for profiling */ -#define FUNCTION_PROFILER(STREAM,LABELNO) \ -{ \ - fprintf ((STREAM), "\tmov\\tip, lr\n"); \ - fprintf ((STREAM), "\tbl\tmcount\n"); \ - fprintf ((STREAM), "\t.word\tLP%d\n", (LABELNO)); \ -} - -/* Implementing the Varargs Macros */ - -#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ -{ \ - extern int current_function_anonymous_args; \ - current_function_anonymous_args = 1; \ - if ((CUM) < 16) \ - (PRETEND_SIZE) = 16 - (CUM); \ -} - -/* Trampolines for nested functions */ - -/* Output assembler code for a block containing the constant parts of - a trampoline, leaving space for the variable parts. - - On the Thumb we always switch into ARM mode to execute the trampoline. - Why - because it is easier. This code will always be branched to via - a BX instruction and since the compiler magically generates the address - of the function the linker has no opportunity to ensure that the - bottom bit is set. Thus the processor will be in ARM mode when it - reaches this code. So we duplicate the ARM trampoline code and add - a switch into Thumb mode as well. - - On the ARM, (if r8 is the static chain regnum, and remembering that - referencing pc adds an offset of 8) the trampoline looks like: - ldr r8, [pc, #0] - ldr pc, [pc] - .word static chain value - .word function's address - ??? FIXME: When the trampoline returns, r8 will be clobbered. */ -#define TRAMPOLINE_TEMPLATE(FILE) \ -{ \ - fprintf ((FILE), "\t.code 32\n"); \ - fprintf ((FILE), ".Ltrampoline_start:\n"); \ - fprintf ((FILE), "\tldr\t%s, [%spc, #8]\n", \ - reg_names[STATIC_CHAIN_REGNUM], REGISTER_PREFIX); \ - fprintf ((FILE), "\tldr\t%sip, [%spc, #8]\n", \ - REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf ((FILE), "\torr\t%sip, %sip, #1\n", \ - REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf ((FILE), "\tbx\t%sip\n", REGISTER_PREFIX); \ - fprintf ((FILE), "\t.word\t0\n"); \ - fprintf ((FILE), "\t.word\t0\n"); \ - fprintf ((FILE), "\t.code 16\n"); \ -} - -/* Length in units of the trampoline for entering a nested function. */ -#define TRAMPOLINE_SIZE 24 - -/* Alignment required for a trampoline in units. */ -#define TRAMPOLINE_ALIGN 4 - -#define INITIALIZE_TRAMPOLINE(ADDR,FNADDR,CHAIN) \ -{ \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 16)), \ - (CHAIN)); \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 20)), \ - (FNADDR)); \ -} - - -/* Position Independent Code. */ -/* We decide which register to use based on the compilation options and - the assembler in use. @@@ Actually, we don't currently for Thumb. */ -extern int thumb_pic_register; - -/* The register number of the register used to address a table of static - data addresses in memory. */ -#define PIC_OFFSET_TABLE_REGNUM thumb_pic_register - -#define FINALIZE_PIC thumb_finalize_pic () - -/* We can't directly access anything that contains a symbol, - nor can we indirect via the constant pool. */ -#define LEGITIMATE_PIC_OPERAND_P(X) \ - (! thumb_symbol_mentioned_p (X) \ - && (! CONSTANT_POOL_ADDRESS_P (X) \ - || ! thumb_symbol_mentioned_p (get_pool_constant (X)))) - -/* We need to know when we are making a constant pool; this determines - whether data needs to be in the GOT or can be referenced via a GOT - offset. */ -extern int making_const_table; - -#define CONDITIONAL_REGISTER_USAGE \ -{ \ - if (flag_pic) \ - { \ - fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ - call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0; \ - } \ -} - - -/* Implicit Calls to Library Routines */ - -#define TARGET_MEM_FUNCTIONS 1 - -#define OVERRIDE_OPTIONS thumb_override_options () - - -/* Addressing Modes */ - -#define HAVE_POST_INCREMENT 1 - -#define CONSTANT_ADDRESS_P(X) \ - (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X)) - -#define MAX_REGS_PER_ADDRESS 2 - -#ifdef REG_OK_STRICT - -#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) -#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) - -#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ - REGNO_MODE_OK_FOR_BASE_P (REGNO (X), MODE) - -#else /* REG_OK_STRICT */ - -#define REG_OK_FOR_BASE_P(X) \ - (REGNO (X) < 8 || REGNO (X) == STACK_POINTER_REGNUM \ - || (X) == arg_pointer_rtx \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER) - -#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ - (REGNO (X) < 8 \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER \ - || (GET_MODE_SIZE (MODE) >= 4 \ - && (REGNO (X) == STACK_POINTER_REGNUM \ - || (X) == arg_pointer_rtx))) - -#define REG_OK_FOR_INDEX_P(X) \ - (REGNO (X) < 8 \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER) - -#endif /* REG_OK_STRICT */ - -/* In a REG+REG address, both must be INDEX registers. */ -#define REG_OK_FOR_INDEXED_BASE_P(X) REG_OK_FOR_INDEX_P(X) - -#define LEGITIMATE_OFFSET(MODE,VAL) \ -(GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ - : GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \ - && ((VAL) & 1) == 0) \ - : ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \ - && ((VAL) & 3) == 0)) - -/* The AP may be eliminated to either the SP or the FP, so we use the - least common denominator, e.g. SImode, and offsets from 0 to 64. */ - -/* ??? Verify whether the above is the right approach. */ - -/* ??? Also, the FP may be eliminated to the SP, so perhaps that - needs special handling also. */ - -/* ??? Look at how the mips16 port solves this problem. It probably uses - better ways to solve some of these problems. */ - -/* Although it is not incorrect, we don't accept QImode and HImode - addresses based on the frame pointer or arg pointer until the reload pass starts. - This is so that eliminating such addresses into stack based ones - won't produce impossible code. */ -#define GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \ -{ \ - /* ??? Not clear if this is right. Experiment. */ \ - if (GET_MODE_SIZE (MODE) < 4 \ - && ! (reload_in_progress || reload_completed) \ - && (reg_mentioned_p (frame_pointer_rtx, X) \ - || reg_mentioned_p (arg_pointer_rtx, X) \ - || reg_mentioned_p (virtual_incoming_args_rtx, X) \ - || reg_mentioned_p (virtual_outgoing_args_rtx, X) \ - || reg_mentioned_p (virtual_stack_dynamic_rtx, X) \ - || reg_mentioned_p (virtual_stack_vars_rtx, X))) \ - ; \ - /* Accept any base register. SP only in SImode or larger. */ \ - else if (GET_CODE (X) == REG && REG_MODE_OK_FOR_BASE_P(X, MODE)) \ - goto WIN; \ - /* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \ - else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \ - && CONSTANT_POOL_ADDRESS_P (X) && ! flag_pic) \ - goto WIN; \ - /* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \ - else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ - && (GET_CODE (X) == LABEL_REF \ - || (GET_CODE (X) == CONST \ - && GET_CODE (XEXP (X, 0)) == PLUS \ - && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \ - && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \ - goto WIN; \ - /* Post-inc indexing only supported for SImode and larger. */ \ - else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \ - && GET_CODE (XEXP (X, 0)) == REG \ - && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ - goto WIN; \ - else if (GET_CODE (X) == PLUS) \ - { \ - /* REG+REG address can be any two index registers. */ \ - /* ??? REG+REG addresses have been completely disabled before \ - reload completes, because we do not have enough available \ - reload registers. We only have 3 guaranteed reload registers \ - (NONARG_LO_REGS - the frame pointer), but we need at least 4 \ - to support REG+REG addresses. We have left them enabled after \ - reload completes, in the hope that reload_cse_regs and related \ - routines will be able to create them after the fact. It is \ - probably possible to support REG+REG addresses with additional \ - reload work, but I do not not have enough time to attempt such \ - a change at this time. */ \ - /* ??? Normally checking the mode here is wrong, since it isn't \ - impossible to use REG+REG with DFmode. However, the movdf \ - pattern requires offsettable addresses, and REG+REG is not \ - offsettable, so it must be rejected somehow. Trying to use \ - 'o' fails, because offsettable_address_p does a QImode check. \ - QImode is not valid for stack addresses, and has a smaller \ - range for non-stack bases, and this causes valid addresses \ - to be rejected. So we just eliminate REG+REG here by checking \ - the mode. */ \ - /* We also disallow FRAME+REG addressing since we know that FRAME \ - will be replaced with STACK, and SP relative addressing only \ - permits SP+OFFSET. */ \ - if (GET_MODE_SIZE (MODE) <= 4 \ - /* ??? See comment above. */ \ - && reload_completed \ - && GET_CODE (XEXP (X, 0)) == REG \ - && GET_CODE (XEXP (X, 1)) == REG \ - && XEXP (X, 0) != frame_pointer_rtx \ - && XEXP (X, 1) != frame_pointer_rtx \ - && XEXP (X, 0) != virtual_stack_vars_rtx \ - && XEXP (X, 1) != virtual_stack_vars_rtx \ - && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ - && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ - goto WIN; \ - /* REG+const has 5-7 bit offset for non-SP registers. */ \ - else if (GET_CODE (XEXP (X, 0)) == REG \ - && (REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ - || XEXP (X, 0) == arg_pointer_rtx) \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ - goto WIN; \ - /* REG+const has 10 bit offset for SP, but only SImode and \ - larger is supported. */ \ - /* ??? Should probably check for DI/DFmode overflow here \ - just like GO_IF_LEGITIMATE_OFFSET does. */ \ - else if (GET_CODE (XEXP (X, 0)) == REG \ - && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \ - && GET_MODE_SIZE (MODE) >= 4 \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) \ - + GET_MODE_SIZE (MODE)) <= 1024 \ - && (INTVAL (XEXP (X, 1)) & 3) == 0) \ - goto WIN; \ - } \ - else if (GET_MODE_CLASS (MODE) != MODE_FLOAT \ - && GET_CODE (X) == SYMBOL_REF \ - && CONSTANT_POOL_ADDRESS_P (X) \ - && ! (flag_pic \ - && thumb_symbol_mentioned_p (get_pool_constant (X)))) \ - goto WIN; \ -} - -/* ??? If an HImode FP+large_offset address is converted to an HImode - SP+large_offset address, then reload won't know how to fix it. It sees - only that SP isn't valid for HImode, and so reloads the SP into an index - register, but the resulting address is still invalid because the offset - is too big. We fix it here instead by reloading the entire address. */ -/* We could probably achieve better results by defining PROMOTE_MODE to help - cope with the variances between the Thumb's signed and unsigned byte and - halfword load instructions. */ -#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ -{ \ - if (GET_CODE (X) == PLUS \ - && GET_MODE_SIZE (MODE) < 4 \ - && GET_CODE (XEXP (X, 0)) == REG \ - && XEXP (X, 0) == stack_pointer_rtx \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && ! LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ - { \ - rtx orig_X = X; \ - X = copy_rtx (X); \ - push_reload (orig_X, NULL_RTX, &X, NULL_PTR, \ - BASE_REG_CLASS, \ - Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \ - goto WIN; \ - } \ -} - -#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) - -extern struct rtx_def * legitimize_pic_address (); -#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ - if (flag_pic) \ - (X) = legitimize_pic_address (OLDX, MODE, NULL_RTX); - -#define LEGITIMATE_CONSTANT_P(X) \ - (GET_CODE (X) == CONST_INT \ - || GET_CODE (X) == CONST_DOUBLE \ - || CONSTANT_ADDRESS_P (X)) - - -/* Condition Code Status */ - -#define NOTICE_UPDATE_CC(EXP,INSN) \ -{ \ - if (get_attr_conds ((INSN)) != CONDS_UNCHANGED) \ - CC_STATUS_INIT; \ -} - - -/* Describing Relative Costs of Operations */ - -#define SLOW_BYTE_ACCESS 0 - -#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) 1 - -#define NO_FUNCTION_CSE 1 - -#define NO_RECURSIVE_FUNCTION_CSE 1 - -#define REGISTER_MOVE_COST(FROM,TO) \ - (((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2) - -#define MEMORY_MOVE_COST(M,CLASS,IN) \ - ((GET_MODE_SIZE(M) < 4 ? 8 : 2 * GET_MODE_SIZE(M)) * (CLASS == LO_REGS ? 1 : 2)) - -/* This will allow better space optimization when compiling with -O */ -#define BRANCH_COST (optimize > 1 ? 1 : 0) - -#define RTX_COSTS(X,CODE,OUTER) \ - case MULT: \ - if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ - { \ - int cycles = 0; \ - unsigned HOST_WIDE_INT i = INTVAL (XEXP (X, 1)); \ - while (i) \ - { \ - i >>= 2; \ - cycles++; \ - } \ - return COSTS_N_INSNS (2) + cycles; \ - } \ - return COSTS_N_INSNS (1) + 16; \ - case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATERT: \ - case PLUS: case MINUS: case COMPARE: case NEG: case NOT: \ - return COSTS_N_INSNS (1); \ - case SET: \ - return (COSTS_N_INSNS (1) \ - + 4 * ((GET_CODE (SET_SRC (X)) == MEM) \ - + GET_CODE (SET_DEST (X)) == MEM)) - -#define CONST_COSTS(X,CODE,OUTER) \ - case CONST_INT: \ - if ((OUTER) == SET) \ - { \ - if ((unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ - return 0; \ - if (thumb_shiftable_const (INTVAL (X))) \ - return COSTS_N_INSNS (2); \ - return COSTS_N_INSNS (3); \ - } \ - else if (OUTER == PLUS \ - && INTVAL (X) < 256 && INTVAL (X) > -256) \ - return 0; \ - else if (OUTER == COMPARE \ - && (unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ - return 0; \ - else if (OUTER == ASHIFT || OUTER == ASHIFTRT \ - || OUTER == LSHIFTRT) \ - return 0; \ - return COSTS_N_INSNS (2); \ - case CONST: \ - case CONST_DOUBLE: \ - case LABEL_REF: \ - case SYMBOL_REF: \ - return COSTS_N_INSNS(3); - -#define ADDRESS_COST(X) \ - ((GET_CODE (X) == REG \ - || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \ - && GET_CODE (XEXP (X, 1)) == CONST_INT)) \ - ? 1 : 2) - - -/* Position Independent Code */ - -extern const char * thumb_pic_register_string; -extern int thumb_pic_register; - -/* The register number of the register used to address a table of static - data addresses in memory. */ -#define PIC_OFFSET_TABLE_REGNUM thumb_pic_register - -#define FINALIZE_PIC thumb_finalize_pic () - -/* We can't directly access anything that contains a symbol, - nor can we indirect via the constant pool. */ -#define LEGITIMATE_PIC_OPERAND_P(X) \ - (! thumb_symbol_mentioned_p (X) \ - && (! CONSTANT_POOL_ADDRESS_P (X) \ - || ! thumb_symbol_mentioned_p (get_pool_constant (X)))) - -/* We need to know when we are making a constant pool; this determines - whether data needs to be in the GOT or can be referenced via a GOT - offset. */ -extern int making_const_table; - - -#define PRINT_OPERAND(STREAM,X,CODE) \ - thumb_print_operand((STREAM), (X), (CODE)) - -#define PRINT_OPERAND_ADDRESS(STREAM,X) \ -{ \ - if (GET_CODE ((X)) == REG) \ - fprintf ((STREAM), "[%s]", reg_names[REGNO ((X))]); \ - else if (GET_CODE ((X)) == POST_INC) \ - fprintf ((STREAM), "%s!", reg_names[REGNO (XEXP (X, 0))]); \ - else if (GET_CODE ((X)) == PLUS) \ - { \ - if (GET_CODE (XEXP ((X), 1)) == CONST_INT) \ - fprintf ((STREAM), "[%s, #%d]", \ - reg_names[REGNO (XEXP ((X), 0))], \ - (int) INTVAL (XEXP ((X), 1))); \ - else \ - fprintf ((STREAM), "[%s, %s]", \ - reg_names[REGNO (XEXP ((X), 0))], \ - reg_names[REGNO (XEXP ((X), 1))]); \ - } \ - else \ - output_addr_const ((STREAM), (X)); \ -} - -/* Handles PIC addr specially */ -#define OUTPUT_INT_ADDR_CONST(STREAM,X) \ - { \ - if (flag_pic && GET_CODE(X) == CONST && is_pic(X)) \ - { \ - output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 0), 0)); \ - fputs(" - (", STREAM); \ - output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 1), 0)); \ - fputs(")", STREAM); \ - } \ - else output_addr_const(STREAM, X); \ - \ - /* Mark symbols as position independent. We only do this in the \ - .text segment, not in the .data segment. */ \ - if (NEED_GOT_RELOC && flag_pic && making_const_table && \ - (GET_CODE(X) == SYMBOL_REF || GET_CODE(X) == LABEL_REF)) \ - { \ - if (GET_CODE(X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P(X)) \ - fprintf(STREAM, "(GOTOFF)"); \ - else if (GET_CODE (X) == LABEL_REF) \ - fprintf(STREAM, "(GOTOFF)"); \ - else \ - fprintf(STREAM, "(GOT)"); \ - } \ - } - -#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_') || ((CODE) == '|')) - -/* Emit a special directive when defining a function name. - This is used by the assembler to assit with interworking. */ -#define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ - if (! is_called_in_ARM_mode (decl)) \ - fprintf (file, "\t.thumb_func\n") ; \ - else \ - fprintf (file, "\t.code\t32\n") ; \ - ASM_OUTPUT_LABEL (file, name) - -#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ - asm_fprintf ((STREAM), "\tpush {%R%s}\n", reg_names[(REGNO)]) - -#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ - asm_fprintf ((STREAM), "\tpop {%R%s}\n", reg_names[(REGNO)]) - -#define FINAL_PRESCAN_INSN(INSN,OPVEC,NOPERANDS) \ - thumb_final_prescan_insn (INSN) - -/* Controlling Debugging Information Format */ -#define DBX_REGISTER_NUMBER(REGNO) (REGNO) - -/* Specific options for DBX Output */ - -#define DEFAULT_GDB_EXTENSIONS 1 - - -/* Cross Compilation and Floating Point */ - -#define REAL_ARITHMETIC - - -/* Miscellaneous Parameters */ - -#define PREDICATE_CODES \ - {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, - -#define CASE_VECTOR_MODE Pmode - -#define WORD_REGISTER_OPERATIONS - -#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND - -#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR - -#define EASY_DIV_EXPR TRUNC_DIV_EXPR - -#define MOVE_MAX 4 - -#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 - -#define STORE_FLAG_VALUE 1 - -#define Pmode SImode - -#define FUNCTION_MODE SImode - -#define DOLLARS_IN_IDENTIFIERS 0 - -#define NO_DOLLAR_IN_LABEL 1 - -/* The literal pool needs to reside in the text area due to the - limited PC addressing range: */ -#define MACHINE_DEPENDENT_REORG(INSN) thumb_reorg (INSN) - - -/* Options specific to Thumb */ - -/* True if a return instruction can be used in this function. */ -#define USE_RETURN (reload_completed && thumb_trivial_epilogue ()) - diff --git a/gcc/config/arm/tpe.h b/gcc/config/arm/tpe.h deleted file mode 100644 index c7f0683d8ee..00000000000 --- a/gcc/config/arm/tpe.h +++ /dev/null @@ -1,425 +0,0 @@ -/* Definitions of target machine for GNU compiler, - for Thumb with PE object format. - Copyright (C) 1998, 1999 Free Software Foundation, Inc. - Derived from arm/coff.h and arm/pe.h originally by Doug Evans (evans@cygnus.com). - -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 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. */ - -#include "arm/thumb.h" - -#define THUMB_PE 1 - -/* Run-time Target Specification. */ -#undef TARGET_VERSION -#define TARGET_VERSION fputs (" (Thumb/pe)", stderr) - -/* Support the __declspec keyword by turning them into attributes. - We currently only support: naked, dllimport, and dllexport. - Note that the current way we do this may result in a collision with - predefined attributes later on. This can be solved by using one attribute, - say __declspec__, and passing args to it. The problem with that approach - is that args are not accumulated: each new appearance would clobber any - existing args. */ -#undef CPP_PREDEFINES -#define CPP_PREDEFINES "\ --Dthumb -D__thumb -D__pe__ -Acpu(arm) -Amachine(arm) \ --D__declspec(x)=__attribute__((x)) \ -" - -/* Experimental addition for pr 7885. - Ignore dllimport for functions. */ -#define ARM_FLAG_NOP_FUN_IMPORT 0x20000 -#define TARGET_NOP_FUN_DLLIMPORT (target_flags & ARM_FLAG_NOP_FUN_IMPORT) - -#undef SUBTARGET_SWITCHES -#define SUBTARGET_SWITCHES \ -{ "nop-fun-dllimport", ARM_FLAG_NOP_FUN_IMPORT, "Ignore dllimport attribute for functions" }, \ -{ "no-nop-fun-dllimport", -ARM_FLAG_NOP_FUN_IMPORT, "" }, - -#undef TARGET_DEFAULT -#define TARGET_DEFAULT ARM_FLAG_NOP_FUN_IMPORT - -#undef WCHAR_TYPE -#define WCHAR_TYPE "short unsigned int" -#undef WCHAR_TYPE_SIZE -#define WCHAR_TYPE_SIZE 16 - -/* Setting this to 32 produces more efficient code, but the value set in previous - versions of this toolchain was 8, which produces more compact structures. The - command line option -mstructure_size_boundary= can be used to change this - value. */ -#undef STRUCTURE_SIZE_BOUNDARY -#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary - -extern int arm_structure_size_boundary; - -/* This is COFF, but prefer stabs. */ -#define SDB_DEBUGGING_INFO - -#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG - -#include "dbxcoff.h" - -/* Note - it is important that these definitions match those in semi.h for the ARM port. */ -#undef LOCAL_LABEL_PREFIX -#define LOCAL_LABEL_PREFIX "." - -#undef USER_LABEL_PREFIX -#define USER_LABEL_PREFIX "_" - -/* A C statement to output assembler commands which will identify the - object file as having been compiled with GNU CC (or another GNU - compiler). */ -#define ASM_IDENTIFY_GCC(STREAM) \ - fprintf (STREAM, "%sgcc2_compiled.:\n%s", LOCAL_LABEL_PREFIX, ASM_APP_OFF ) - -#undef ASM_FILE_START -#define ASM_FILE_START(STREAM) \ -do { \ - fprintf ((STREAM), "%s Generated by gcc %s for Thumb/coff\n", \ - ASM_COMMENT_START, version_string); \ - fprintf ((STREAM), ASM_APP_OFF); \ -} while (0) - -/* A C statement to output something to the assembler file to switch to section - NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or - NULL_TREE. Some target formats do not support arbitrary sections. Do not - define this macro in such cases. */ -#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ -do { \ - if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ - fprintf (STREAM, "\t.section %s,\"x\"\n", (NAME)); \ - else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ - fprintf (STREAM, "\t.section %s,\"\"\n", (NAME)); \ - else \ - fprintf (STREAM, "\t.section %s,\"w\"\n", (NAME)); \ -} while (0) - -/* Support the ctors/dtors and other sections. */ - -#undef INIT_SECTION_ASM_OP - -/* Define this macro if jump tables (for `tablejump' insns) should be - output in the text section, along with the assembler instructions. - Otherwise, the readonly data section is used. */ -#define JUMP_TABLES_IN_TEXT_SECTION 1 - -#undef READONLY_DATA_SECTION -#define READONLY_DATA_SECTION rdata_section -#undef RDATA_SECTION_ASM_OP -#define RDATA_SECTION_ASM_OP "\t.section .rdata" - -#undef CTORS_SECTION_ASM_OP -#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"x\"" -#undef DTORS_SECTION_ASM_OP -#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"x\"" - -/* A list of other sections which the compiler might be "in" at any - given time. */ - -#undef EXTRA_SECTIONS -#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_rdata, in_ctors, in_dtors - -#define SUBTARGET_EXTRA_SECTIONS - -/* A list of extra section function definitions. */ - -#undef EXTRA_SECTION_FUNCTIONS -#define EXTRA_SECTION_FUNCTIONS \ - RDATA_SECTION_FUNCTION \ - CTORS_SECTION_FUNCTION \ - DTORS_SECTION_FUNCTION \ - SUBTARGET_EXTRA_SECTION_FUNCTIONS - -#define SUBTARGET_EXTRA_SECTION_FUNCTIONS - -#define RDATA_SECTION_FUNCTION \ -void \ -rdata_section () \ -{ \ - if (in_section != in_rdata) \ - { \ - fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ - in_section = in_rdata; \ - } \ -} - -#define CTORS_SECTION_FUNCTION \ -void \ -ctors_section () \ -{ \ - if (in_section != in_ctors) \ - { \ - fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ - in_section = in_ctors; \ - } \ -} - -#define DTORS_SECTION_FUNCTION \ -void \ -dtors_section () \ -{ \ - if (in_section != in_dtors) \ - { \ - fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ - in_section = in_dtors; \ - } \ -} - -/* Support the ctors/dtors sections for g++. */ - -#define INT_ASM_OP ".word" - -/* A C statement (sans semicolon) to output an element in the table of - global constructors. */ -#undef ASM_OUTPUT_CONSTRUCTOR -#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ -do { \ - ctors_section (); \ - fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ - assemble_name (STREAM, NAME); \ - fprintf (STREAM, "\n"); \ -} while (0) - -/* A C statement (sans semicolon) to output an element in the table of - global destructors. */ -#undef ASM_OUTPUT_DESTRUCTOR -#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ -do { \ - dtors_section (); \ - fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ - assemble_name (STREAM, NAME); \ - fprintf (STREAM, "\n"); \ -} while (0) - -/* __CTOR_LIST__ and __DTOR_LIST__ must be defined by the linker script. */ -#define CTOR_LISTS_DEFINED_EXTERNALLY - -#undef DO_GLOBAL_CTORS_BODY -#undef DO_GLOBAL_DTORS_BODY - -/* The ARM development system defines __main. */ -#define NAME__MAIN "__gccmain" -#define SYMBOL__MAIN __gccmain - -/* This is to better conform to the ARM PCS. - Richard Earnshaw hasn't put this into FSF sources yet so it's here. */ -#undef RETURN_IN_MEMORY -#define RETURN_IN_MEMORY(TYPE) \ - ((TYPE_MODE ((TYPE)) == BLKmode && ! TYPE_NO_FORCE_BLK (TYPE)) \ - || (AGGREGATE_TYPE_P ((TYPE)) && arm_pe_return_in_memory ((TYPE)))) -extern int arm_pe_return_in_memory (); - -/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS - is a valid machine specific attribute for DECL. - The attributes in ATTRIBUTES have previously been assigned to DECL. */ -extern int arm_pe_valid_machine_decl_attribute (); -#undef VALID_MACHINE_DECL_ATTRIBUTE -#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ - arm_pe_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) - -extern union tree_node * arm_pe_merge_machine_decl_attributes (); -#define MERGE_MACHINE_DECL_ATTRIBUTES(OLD, NEW) \ - arm_pe_merge_machine_decl_attributes ((OLD), (NEW)) - -/* In addition to the stuff done in arm.h, we must mark dll symbols specially. - Definitions of dllexport'd objects install some info in the .drectve - section. References to dllimport'd objects are fetched indirectly via - __imp_. If both are declared, dllexport overrides. - This is also needed to implement one-only vtables: they go into their own - section and we need to set DECL_SECTION_NAME so we do that here. - Note that we can be called twice on the same decl. */ -extern void arm_pe_encode_section_info (); -#undef ENCODE_SECTION_INFO -#define ENCODE_SECTION_INFO(DECL) \ - arm_pe_encode_section_info (DECL) - -#define REDO_SECTION_INFO_P(DECL) 1 - - /* Utility used only in this file. */ -#define ARM_STRIP_NAME_ENCODING(SYM_NAME) \ -((SYM_NAME) + ((SYM_NAME)[0] == '@' ? 3 : 0)) - -/* Strip any text from SYM_NAME added by ENCODE_SECTION_INFO and store - the result in VAR. */ -#undef STRIP_NAME_ENCODING -#define STRIP_NAME_ENCODING(VAR, SYM_NAME) \ -(VAR) = ARM_STRIP_NAME_ENCODING (SYM_NAME) - -/* Define this macro if in some cases global symbols from one translation - unit may not be bound to undefined symbols in another translation unit - without user intervention. For instance, under Microsoft Windows - symbols must be explicitly imported from shared libraries (DLLs). */ -#define MULTIPLE_SYMBOL_SPACES - -#define UNIQUE_SECTION_P(DECL) DECL_ONE_ONLY (DECL) -extern void arm_pe_unique_section (); -#define UNIQUE_SECTION(DECL,RELOC) arm_pe_unique_section (DECL, RELOC) - -#define SUPPORTS_ONE_ONLY 1 - -/* A C statement to output something to the assembler file to switch to section - NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or - NULL_TREE. Some target formats do not support arbitrary sections. Do not - define this macro in such cases. */ -#undef ASM_OUTPUT_SECTION_NAME -#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ -do { \ - if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ - fprintf (STREAM, "\t.section %s,\"x\"\n", (NAME)); \ - else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ - fprintf (STREAM, "\t.section %s,\"\"\n", (NAME)); \ - else \ - fprintf (STREAM, "\t.section %s,\"w\"\n", (NAME)); \ - /* Functions may have been compiled at various levels of \ - optimization so we can't use `same_size' here. Instead, \ - have the linker pick one. */ \ - if ((DECL) && DECL_ONE_ONLY (DECL)) \ - fprintf (STREAM, "\t.linkonce %s\n", \ - TREE_CODE (DECL) == FUNCTION_DECL \ - ? "discard" : "same_size"); \ -} while (0) - -/* This outputs a lot of .req's to define alias for various registers. - Let's try to avoid this. */ -#undef ASM_FILE_START -#define ASM_FILE_START(STREAM) \ -do { \ - fprintf (STREAM, "%s Generated by gcc %s for ARM/pe\n", \ - ASM_COMMENT_START, version_string); \ - output_file_directive ((STREAM), main_input_filename); \ -} while (0) - -/* Output a reference to a label. */ -#undef ASM_OUTPUT_LABELREF -#define ASM_OUTPUT_LABELREF(STREAM, NAME) \ -fprintf (STREAM, "%s%s", USER_LABEL_PREFIX, ARM_STRIP_NAME_ENCODING (NAME)) - -/* Output a function definition label. */ -#undef ASM_DECLARE_FUNCTION_NAME -#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \ -do { \ - if (arm_dllexport_name_p (NAME)) \ - { \ - drectve_section (); \ - fprintf (STREAM, "\t.ascii \" -export:%s\"\n", \ - ARM_STRIP_NAME_ENCODING (NAME)); \ - function_section (DECL); \ - } \ - if (! is_called_in_ARM_mode (decl)) \ - fprintf (STREAM, "\t.thumb_func\n") ; \ - else \ - fprintf (STREAM, "\t.code\t32\n") ; \ - ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ -} while (0) - -/* Output a common block. */ -#undef ASM_OUTPUT_COMMON -#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ -do { \ - if (arm_dllexport_name_p (NAME)) \ - { \ - drectve_section (); \ - fprintf ((STREAM), "\t.ascii \" -export:%s\"\n", \ - ARM_STRIP_NAME_ENCODING (NAME)); \ - } \ - if (! arm_dllimport_name_p (NAME)) \ - { \ - fprintf ((STREAM), "\t.comm\t"); \ - assemble_name ((STREAM), (NAME)); \ - fprintf ((STREAM), ", %d\t%s %d\n", \ - (ROUNDED), ASM_COMMENT_START, (SIZE)); \ - } \ -} while (0) - -/* Output the label for an initialized variable. */ -#undef ASM_DECLARE_OBJECT_NAME -#define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \ -do { \ - if (arm_dllexport_name_p (NAME)) \ - { \ - enum in_section save_section = in_section; \ - drectve_section (); \ - fprintf (STREAM, "\t.ascii \" -export:%s\"\n", \ - ARM_STRIP_NAME_ENCODING (NAME)); \ - switch_to_section (save_section, (DECL)); \ - } \ - ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ -} while (0) - -/* Support the ctors/dtors and other sections. */ - -#define DRECTVE_SECTION_ASM_OP "\t.section .drectve" - -/* A list of other sections which the compiler might be "in" at any - given time. */ - -#undef SUBTARGET_EXTRA_SECTIONS -#define SUBTARGET_EXTRA_SECTIONS in_drectve, - -/* A list of extra section function definitions. */ - -#undef SUBTARGET_EXTRA_SECTION_FUNCTIONS -#define SUBTARGET_EXTRA_SECTION_FUNCTIONS \ - DRECTVE_SECTION_FUNCTION \ - SWITCH_TO_SECTION_FUNCTION - -#define DRECTVE_SECTION_FUNCTION \ -void \ -drectve_section () \ -{ \ - if (in_section != in_drectve) \ - { \ - fprintf (asm_out_file, "%s\n", DRECTVE_SECTION_ASM_OP); \ - in_section = in_drectve; \ - } \ -} - -/* Switch to SECTION (an `enum in_section'). - - ??? This facility should be provided by GCC proper. - The problem is that we want to temporarily switch sections in - ASM_DECLARE_OBJECT_NAME and then switch back to the original section - afterwards. */ -#define SWITCH_TO_SECTION_FUNCTION \ -void \ -switch_to_section (section, decl) \ - enum in_section section; \ - tree decl; \ -{ \ - switch (section) \ - { \ - case in_text: text_section (); break; \ - case in_data: data_section (); break; \ - case in_named: named_section (decl, NULL, 0); break; \ - case in_rdata: rdata_section (); break; \ - case in_ctors: ctors_section (); break; \ - case in_dtors: dtors_section (); break; \ - case in_drectve: drectve_section (); break; \ - default: abort (); break; \ - } \ -} - - - -extern int thumb_pe_valid_machine_decl_attribute (); -extern int arm_dllexport_p (); -extern int arm_dllimport_p (); -extern int arm_dllexport_name_p (); -extern int arm_dllimport_name_p (); -extern int arm_pe_return_in_memory (); diff --git a/gcc/config/arm/uclinux-telf.h b/gcc/config/arm/uclinux-telf.h deleted file mode 100644 index de2afdc6c96..00000000000 --- a/gcc/config/arm/uclinux-telf.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Definitions for Thumb running ucLinux using ELF - Copyright (C) 1999 Free Software Foundation, Inc. - Contributed by Philip Blundell - -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 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 this program; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#include "arm/linux-telf.h" - -#undef TARGET_VERSION -#define TARGET_VERSION fputs (" (Thumb/ELF ucLinux)", stderr); - -#undef TARGET_DEFAULT -#define TARGET_DEFAULT (THUMB_FLAG_SINGLE_PIC_BASE) - -/* We don't want a PLT. */ -#undef NEED_PLT_RELOC -#define NEED_PLT_RELOC 0 - -/* On svr4, we *do* have support for the .init and .fini sections, and we - can put stuff in there to be executed before and after `main'. We let - crtstuff.c and other files know this by defining the following symbols. - The definitions say how to change sections to the .init and .fini - sections. This is the same for all known svr4 assemblers. */ -#define INIT_SECTION_ASM_OP ".section\t.init" -#define FINI_SECTION_ASM_OP ".section\t.fini" diff --git a/gcc/config/arm/unknown-elf.h b/gcc/config/arm/unknown-elf.h index 9308d16c1a8..ba5d1edbb4b 100644 --- a/gcc/config/arm/unknown-elf.h +++ b/gcc/config/arm/unknown-elf.h @@ -24,9 +24,17 @@ Boston, MA 02111-1307, USA. */ #define TARGET_VERSION fputs (" (ARM/ELF non-Linux)", stderr); #endif +/* If you don't define HAVE_ATEXIT, and the object file format/OS/whatever + does not support constructors/destructors, then gcc implements destructors + by defining its own exit function, which calls the destructors. This gcc + exit function overrides the C library's exit function, and this can cause + all kinds of havoc if the C library has a non-trivial exit function. You + really don't want to use the exit function in libgcc2.c. */ +#define HAVE_ATEXIT + /* Default to using APCS-32 and software floating point. */ #ifndef TARGET_DEFAULT -#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32) +#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME) #endif /* Now we define the strings used to build the spec file. */ @@ -70,36 +78,36 @@ rdata_section () \ } #define CTOR_LIST_BEGIN \ -asm (CTORS_SECTION_ASM_OP); \ -func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) } + asm (CTORS_SECTION_ASM_OP); \ + func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) } #define CTOR_LIST_END \ -asm (CTORS_SECTION_ASM_OP); \ -func_ptr __CTOR_END__[1] = { (func_ptr) 0 }; + asm (CTORS_SECTION_ASM_OP); \ + func_ptr __CTOR_END__[1] = { (func_ptr) 0 }; #define DTOR_LIST_BEGIN \ -asm (DTORS_SECTION_ASM_OP); \ -func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) } + asm (DTORS_SECTION_ASM_OP); \ + func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) } #define DTOR_LIST_END \ -asm (DTORS_SECTION_ASM_OP); \ -func_ptr __DTOR_END__[1] = { (func_ptr) 0 }; + asm (DTORS_SECTION_ASM_OP); \ + func_ptr __DTOR_END__[1] = { (func_ptr) 0 }; /* A C statement to output something to the assembler file to switch to section NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or NULL_TREE. Some target formats do not support arbitrary sections. Do not define this macro in such cases. */ -#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ do \ - { \ - if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ - fprintf (STREAM, "\t.section %s,\"ax\",%%progbits\n", NAME); \ - else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ - fprintf (STREAM, "\t.section %s,\"a\"\n", NAME); \ + { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"ax\",@progbits\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"a\"\n", (NAME)); \ else if (! strncmp (NAME, ".bss", 4)) \ - fprintf (STREAM, "\t.section %s,\"aw\",%%nobits\n", NAME); \ - else \ - fprintf (STREAM, "\t.section %s,\"aw\"\n", NAME); \ + fprintf (STREAM, "\t.section %s,\"aw\",@nobits\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"aw\"\n", (NAME)); \ } \ while (0) @@ -108,14 +116,16 @@ func_ptr __DTOR_END__[1] = { (func_ptr) 0 }; #define UNALIGNED_WORD_ASM_OP ".4byte" #define ASM_OUTPUT_DWARF2_ADDR_CONST(FILE,ADDR) \ - fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, ADDR) + fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, ADDR) -#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ -do { \ - fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ - output_addr_const ((FILE), (RTX)); \ - fputc ('\n', (FILE)); \ -} while (0) +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ + do \ + { \ + fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ + output_addr_const ((FILE), (RTX)); \ + fputc ('\n', (FILE)); \ + } \ + while (0) /* The ARM development system defines __main. */ @@ -127,20 +137,19 @@ do { \ ((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \ && DECL_SECTION_NAME (DECL) != NULL_TREE) - #define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1) - + #define UNIQUE_SECTION_P(DECL) (DECL_ONE_ONLY (DECL) || flag_data_sections) - + #define UNIQUE_SECTION(DECL, RELOC) \ do \ { \ int len; \ int sec; \ - char *name; \ - char *string; \ - char *prefix; \ - static char *prefixes[4][2] = \ + const char * name; \ + char * string; \ + char * prefix; \ + static char * prefixes[4][2] = \ { \ { ".text.", ".gnu.linkonce.t." }, \ { ".rodata.", ".gnu.linkonce.r." }, \ @@ -214,6 +223,6 @@ do { \ #ifndef SUBTARGET_CPU_DEFAULT #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm7tdmi #endif - + /* Now get the routine arm-elf definitions. */ -#include "arm/elf.h" +#include "elf.h" diff --git a/gcc/config/arm/xm-thumb.h b/gcc/config/arm/xm-thumb.h deleted file mode 100644 index 3356ae2bc7d..00000000000 --- a/gcc/config/arm/xm-thumb.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/gcc/configure b/gcc/configure index d123c9f0bee..969317281cc 100755 --- a/gcc/configure +++ b/gcc/configure @@ -3452,11 +3452,11 @@ for machine in $build $host $target; do ;; arm-*-coff* | armel-*-coff*) tm_file=arm/coff.h - tmake_file=arm/t-bare + tmake_file=arm/t-arm-coff ;; arm-*-vxworks*) tm_file=arm/vxarm.h - tmake_file=arm/t-bare + tmake_file=arm/t-arm-coff thread_file='vxworks' ;; arm-*-riscix1.[01]*) # Acorn RISC machine (early versions) @@ -3536,11 +3536,11 @@ for machine in $build $host $target; do ;; arm*-*-aout) tm_file=arm/aout.h - tmake_file=arm/t-bare + tmake_file=arm/t-arm-aout ;; arm*-*-ecos-elf) tm_file=arm/ecos-elf.h - tmake_file=arm/t-elf + tmake_file=arm/t-arm-elf ;; arm*-*-elf) tm_file=arm/unknown-elf.h @@ -6039,56 +6039,13 @@ for machine in $build $host $target; do # ;; # tahoe-*-bsd*) # tahoe running BSD # ;; - thumb-*-coff* | thumbel-*-coff*) - tm_file=arm/tcoff.h - out_file=arm/thumb.c - xm_file=arm/xm-thumb.h - md_file=arm/thumb.md - tmake_file=arm/t-thumb - tm_p_file=arm/thumb-protos.h - ;; - thumb-*-elf* | thumbel-*-elf*) - tm_file=arm/telf.h - out_file=arm/thumb.c - xm_file=arm/xm-thumb.h - md_file=arm/thumb.md - tmake_file=arm/t-thumb-elf - tm_p_file=arm/thumb-protos.h - ;; - thumb-*-linux-gnu*) - tm_file=arm/linux-telf.h - out_file=arm/thumb.c - xm_file=arm/xm-thumb.h - md_file=arm/thumb.md - tmake_file=arm/t-thumb-linux - tm_p_file=arm/thumb-protos.h - ;; - thumb-*-uclinux*) - tm_file=arm/uclinux-telf.h - out_file=arm/thumb.c - md_file=arm/thumb.md - tmake_file=arm/t-thumb-linux - xm_file=arm/xm-thumb.h - tm_p_file=arm/thumb-protos.h - ;; - thumb-wrs-vxworks) - tm_file=arm/tcoff.h - out_file=arm/thumb.c - xm_file=arm/xm-thumb.h - md_file=arm/thumb.md - tmake_file=arm/t-thumb - thread_file='vxworks' - tm_p_file=arm/thumb-protos.h - ;; - thumb-*-pe) - tm_file=arm/tpe.h - out_file=arm/thumb.c - xm_file=arm/xm-thumb.h - md_file=arm/thumb.md - tmake_file=arm/t-pe-thumb - extra_objs=pe.o - tm_p_file=arm/thumb-protos.h + thumb*-*-*) + { echo "configure: error: +*** The Thumb targets have been depreciated. The equivalent +*** ARM based toolchain can now generated Thumb instructions +*** when the -mthumb switch is given to the compiler." 1>&2; exit 1; } ;; + # This hasn't been upgraded to GCC 2. # tron-*-*) # cpu_type=gmicro diff --git a/gcc/configure.in b/gcc/configure.in index cb96c560615..b9e147df2ad 100644 --- a/gcc/configure.in +++ b/gcc/configure.in @@ -727,11 +727,11 @@ changequote([,])dnl ;; arm-*-coff* | armel-*-coff*) tm_file=arm/coff.h - tmake_file=arm/t-bare + tmake_file=arm/t-arm-coff ;; arm-*-vxworks*) tm_file=arm/vxarm.h - tmake_file=arm/t-bare + tmake_file=arm/t-arm-coff thread_file='vxworks' ;; changequote(,)dnl @@ -813,11 +813,11 @@ changequote([,])dnl ;; arm*-*-aout) tm_file=arm/aout.h - tmake_file=arm/t-bare + tmake_file=arm/t-arm-aout ;; arm*-*-ecos-elf) tm_file=arm/ecos-elf.h - tmake_file=arm/t-elf + tmake_file=arm/t-arm-elf ;; arm*-*-elf) tm_file=arm/unknown-elf.h @@ -834,7 +834,7 @@ changequote([,])dnl arm-*-pe*) tm_file=arm/pe.h tmake_file=arm/t-pe - extra_objs=pe.o + extra_objs="pe.o" ;; avr-*-*) ;; @@ -3126,6 +3126,12 @@ changequote([,])dnl then tmake_file=rs6000/t-xnewas else + tmake_file=rs6000/t-newas + fi + if test "$gnu_ld" = yes + then + xmake_file=rs6000/x-aix41-gld + else tmake_file="rs6000/t-newas rs6000/t-aix41" fi xmake_file=rs6000/x-aix41 @@ -3450,55 +3456,12 @@ changequote([,])dnl # ;; # tahoe-*-bsd*) # tahoe running BSD # ;; - thumb-*-coff* | thumbel-*-coff*) - tm_file=arm/tcoff.h - out_file=arm/thumb.c - xm_file=arm/xm-thumb.h - md_file=arm/thumb.md - tmake_file=arm/t-thumb - tm_p_file=arm/thumb-protos.h - ;; - thumb-*-elf* | thumbel-*-elf*) - tm_file=arm/telf.h - out_file=arm/thumb.c - xm_file=arm/xm-thumb.h - md_file=arm/thumb.md - tmake_file=arm/t-thumb-elf - tm_p_file=arm/thumb-protos.h - ;; - thumb-*-linux-gnu*) - tm_file=arm/linux-telf.h - out_file=arm/thumb.c - xm_file=arm/xm-thumb.h - md_file=arm/thumb.md - tmake_file=arm/t-thumb-linux - tm_p_file=arm/thumb-protos.h - ;; - thumb-*-uclinux*) - tm_file=arm/uclinux-telf.h - out_file=arm/thumb.c - md_file=arm/thumb.md - tmake_file=arm/t-thumb-linux - xm_file=arm/xm-thumb.h - tm_p_file=arm/thumb-protos.h - ;; - thumb-wrs-vxworks) - tm_file=arm/tcoff.h - out_file=arm/thumb.c - xm_file=arm/xm-thumb.h - md_file=arm/thumb.md - tmake_file=arm/t-thumb - thread_file='vxworks' - tm_p_file=arm/thumb-protos.h - ;; - thumb-*-pe) - tm_file=arm/tpe.h - out_file=arm/thumb.c - xm_file=arm/xm-thumb.h - md_file=arm/thumb.md - tmake_file=arm/t-pe-thumb - extra_objs=pe.o - tm_p_file=arm/thumb-protos.h + + thumb*-*-*) + AC_MSG_ERROR([ +*** The Thumb targets have been depreciated. The equivalent +*** ARM based toolchain can now generated Thumb instructions +*** when the -mthumb switch is given to the compiler.]) ;; # This hasn't been upgraded to GCC 2. # tron-*-*) -- 2.11.4.GIT