diff options
Diffstat (limited to 'gcc/config')
47 files changed, 3 insertions, 27398 deletions
diff --git a/gcc/config/alpha/gnu.h b/gcc/config/alpha/gnu.h deleted file mode 100644 index ca719803906..00000000000 --- a/gcc/config/alpha/gnu.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Configuration for an Alpha running GNU with ELF as the target machine. - -Copyright (C) 2002, 2003, 2004, 2010 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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 3, or (at your option) any later -version. - -GCC 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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -<http://www.gnu.org/licenses/>. */ - -#undef TARGET_VERSION -#define TARGET_VERSION fprintf (stderr, " (Alpha GNU)"); - -#undef TARGET_OS_CPP_BUILTINS /* config.gcc includes alpha/linux.h. */ -#define TARGET_OS_CPP_BUILTINS() \ - do { \ - LINUX_TARGET_OS_CPP_BUILTINS(); \ - builtin_define ("_LONGLONG"); \ - } while (0) - -#undef ELF_DYNAMIC_LINKER -#define ELF_DYNAMIC_LINKER "/lib/ld.so" - -#undef STARTFILE_SPEC -#define STARTFILE_SPEC \ - "%{!shared: \ - %{!static: \ - %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}} \ - %{static:crt0.o%s}} \ - crti.o%s \ - %{!static:%{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}}" - -/* FIXME: Is a Hurd-specific fallback mechanism necessary? */ -#undef MD_UNWIND_SUPPORT diff --git a/gcc/config/arc/arc-modes.def b/gcc/config/arc/arc-modes.def deleted file mode 100644 index c2d2ceaf82f..00000000000 --- a/gcc/config/arc/arc-modes.def +++ /dev/null @@ -1,24 +0,0 @@ -/* Definitions of target machine for GNU compiler, Argonaut ARC cpu. - Copyright (C) 2002, 2007 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -/* Some insns set all condition code flags, some only set the ZNC flags, and - some only set the ZN flags. */ - -CC_MODE (CCZNC); -CC_MODE (CCZN); diff --git a/gcc/config/arc/arc-protos.h b/gcc/config/arc/arc-protos.h deleted file mode 100644 index 5550ebfbe2c..00000000000 --- a/gcc/config/arc/arc-protos.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Definitions of target machine for GNU compiler, Argonaut ARC cpu. - Copyright (C) 2000, 2004, 2007, 2010 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#ifdef RTX_CODE -extern enum machine_mode arc_select_cc_mode (enum rtx_code, rtx, rtx); - -/* Define the function that build the compare insn for scc and bcc. */ -extern struct rtx_def *gen_compare_reg (enum rtx_code, rtx, rtx); -#endif - -/* Declarations for various fns used in the .md file. */ -extern const char *output_shift (rtx *); - -extern int symbolic_operand (rtx, enum machine_mode); -extern int arc_double_limm_p (rtx); -extern int arc_eligible_for_epilogue_delay (rtx, int); -extern void arc_initialize_trampoline (rtx, rtx, rtx); -extern void arc_print_operand (FILE *, rtx, int); -extern void arc_print_operand_address (FILE *, rtx); -extern void arc_final_prescan_insn (rtx, rtx *, int); -extern int call_address_operand (rtx, enum machine_mode); -extern int call_operand (rtx, enum machine_mode); -extern int symbolic_memory_operand (rtx, enum machine_mode); -extern int short_immediate_operand (rtx, enum machine_mode); -extern int long_immediate_operand (rtx, enum machine_mode); -extern int long_immediate_loadstore_operand (rtx, enum machine_mode); -extern int move_src_operand (rtx, enum machine_mode); -extern int move_double_src_operand (rtx, enum machine_mode); -extern int move_dest_operand (rtx, enum machine_mode); -extern int load_update_operand (rtx, enum machine_mode); -extern int store_update_operand (rtx, enum machine_mode); -extern int nonvol_nonimm_operand (rtx, enum machine_mode); -extern int const_sint32_operand (rtx, enum machine_mode); -extern int const_uint32_operand (rtx, enum machine_mode); -extern int proper_comparison_operator (rtx, enum machine_mode); -extern int shift_operator (rtx, enum machine_mode); - -extern enum arc_function_type arc_compute_function_type (tree); - - -extern unsigned int arc_compute_frame_size (int); -extern void arc_save_restore (FILE *, const char *, unsigned int, - unsigned int, const char *); -extern int arc_delay_slots_for_epilogue (void); -extern void arc_ccfsm_at_label (const char *, int); -extern int arc_ccfsm_branch_deleted_p (void); -extern void arc_ccfsm_record_branch_deleted (void); diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c deleted file mode 100644 index fa92ccf7479..00000000000 --- a/gcc/config/arc/arc.c +++ /dev/null @@ -1,2493 +0,0 @@ -/* Subroutines used for code generation on the Argonaut ARC cpu. - Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -/* ??? This is an old port, and is undoubtedly suffering from bit rot. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "tree.h" -#include "rtl.h" -#include "regs.h" -#include "hard-reg-set.h" -#include "insn-config.h" -#include "conditions.h" -#include "output.h" -#include "insn-attr.h" -#include "flags.h" -#include "function.h" -#include "expr.h" -#include "recog.h" -#include "diagnostic-core.h" -#include "df.h" -#include "tm_p.h" -#include "target.h" -#include "target-def.h" - -/* Which cpu we're compiling for. */ -int arc_cpu_type; - -/* Name of mangle string to add to symbols to separate code compiled for each - cpu (or NULL). */ -const char *arc_mangle_cpu; - -/* Name of text, data, and rodata sections used in varasm.c. */ -const char *arc_text_section; -const char *arc_data_section; -const char *arc_rodata_section; - -/* Array of valid operand punctuation characters. */ -char arc_punct_chars[256]; - -/* Variables used by arc_final_prescan_insn to implement conditional - execution. */ -static int arc_ccfsm_state; -static int arc_ccfsm_current_cc; -static rtx arc_ccfsm_target_insn; -static int arc_ccfsm_target_label; - -/* The maximum number of insns skipped which will be conditionalised if - possible. */ -#define MAX_INSNS_SKIPPED 3 - -/* A nop is needed between a 4 byte insn that sets the condition codes and - a branch that uses them (the same isn't true for an 8 byte insn that sets - the condition codes). Set by arc_final_prescan_insn. Used by - arc_print_operand. */ -static int last_insn_set_cc_p; -static int current_insn_set_cc_p; -static bool arc_handle_option (size_t, const char *, int); -static void record_cc_ref (rtx); -static void arc_init_reg_tables (void); -static int get_arc_condition_code (rtx); -static tree arc_handle_interrupt_attribute (tree *, tree, tree, int, bool *); -static bool arc_assemble_integer (rtx, unsigned int, int); -static void arc_output_function_prologue (FILE *, HOST_WIDE_INT); -static void arc_output_function_epilogue (FILE *, HOST_WIDE_INT); -static void arc_file_start (void); -static void arc_internal_label (FILE *, const char *, unsigned long); -static void arc_va_start (tree, rtx); -static void arc_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, - tree, int *, int); -static bool arc_rtx_costs (rtx, int, int, int *, bool); -static int arc_address_cost (rtx, bool); -static void arc_external_libcall (rtx); -static bool arc_return_in_memory (const_tree, const_tree); -static bool arc_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, - const_tree, bool); -static rtx arc_function_arg (CUMULATIVE_ARGS *, enum machine_mode, - const_tree, bool); -static void arc_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, - const_tree, bool); -static unsigned int arc_function_arg_boundary (enum machine_mode, const_tree); -static void arc_trampoline_init (rtx, tree, rtx); -static void arc_option_override (void); -static void arc_conditional_register_usage (void); - - -/* ARC specific attributs. */ - -static const struct attribute_spec arc_attribute_table[] = -{ - /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, - affects_type_identity } */ - { "interrupt", 1, 1, true, false, false, arc_handle_interrupt_attribute, - false }, - { NULL, 0, 0, false, false, false, NULL, false } -}; - -/* Initialize the GCC target structure. */ -#undef TARGET_ASM_ALIGNED_HI_OP -#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t" -#undef TARGET_ASM_ALIGNED_SI_OP -#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" -#undef TARGET_ASM_INTEGER -#define TARGET_ASM_INTEGER arc_assemble_integer - -#undef TARGET_ASM_FUNCTION_PROLOGUE -#define TARGET_ASM_FUNCTION_PROLOGUE arc_output_function_prologue -#undef TARGET_ASM_FUNCTION_EPILOGUE -#define TARGET_ASM_FUNCTION_EPILOGUE arc_output_function_epilogue -#undef TARGET_ASM_FILE_START -#define TARGET_ASM_FILE_START arc_file_start -#undef TARGET_ATTRIBUTE_TABLE -#define TARGET_ATTRIBUTE_TABLE arc_attribute_table -#undef TARGET_ASM_INTERNAL_LABEL -#define TARGET_ASM_INTERNAL_LABEL arc_internal_label -#undef TARGET_ASM_EXTERNAL_LIBCALL -#define TARGET_ASM_EXTERNAL_LIBCALL arc_external_libcall - -#undef TARGET_HANDLE_OPTION -#define TARGET_HANDLE_OPTION arc_handle_option - -#undef TARGET_OPTION_OVERRIDE -#define TARGET_OPTION_OVERRIDE arc_option_override - -#undef TARGET_RTX_COSTS -#define TARGET_RTX_COSTS arc_rtx_costs -#undef TARGET_ADDRESS_COST -#define TARGET_ADDRESS_COST arc_address_cost - -#undef TARGET_PROMOTE_FUNCTION_MODE -#define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote -#undef TARGET_PROMOTE_PROTOTYPES -#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true - -#undef TARGET_RETURN_IN_MEMORY -#define TARGET_RETURN_IN_MEMORY arc_return_in_memory -#undef TARGET_PASS_BY_REFERENCE -#define TARGET_PASS_BY_REFERENCE arc_pass_by_reference -#undef TARGET_FUNCTION_ARG -#define TARGET_FUNCTION_ARG arc_function_arg -#undef TARGET_FUNCTION_ARG_ADVANCE -#define TARGET_FUNCTION_ARG_ADVANCE arc_function_arg_advance -#undef TARGET_FUNCTION_ARG_BOUNDARY -#define TARGET_FUNCTION_ARG_BOUNDARY arc_function_arg_boundary -#undef TARGET_CALLEE_COPIES -#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true - -#undef TARGET_SETUP_INCOMING_VARARGS -#define TARGET_SETUP_INCOMING_VARARGS arc_setup_incoming_varargs - -#undef TARGET_EXPAND_BUILTIN_VA_START -#define TARGET_EXPAND_BUILTIN_VA_START arc_va_start - -#undef TARGET_TRAMPOLINE_INIT -#define TARGET_TRAMPOLINE_INIT arc_trampoline_init - -#undef TARGET_CONDITIONAL_REGISTER_USAGE -#define TARGET_CONDITIONAL_REGISTER_USAGE arc_conditional_register_usage - -struct gcc_target targetm = TARGET_INITIALIZER; - -/* Implement TARGET_HANDLE_OPTION. */ - -static bool -arc_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED) -{ - switch (code) - { - case OPT_mcpu_: - return strcmp (arg, "base") == 0 || ARC_EXTENSION_CPU (arg); - - default: - return true; - } -} - -/* Implement TARGET_OPTION_OVERRIDE. - These need to be done at start up. It's convenient to do them here. */ - -static void -arc_option_override (void) -{ - char *tmp; - - /* Set the pseudo-ops for the various standard sections. */ - arc_text_section = tmp = XNEWVEC (char, strlen (arc_text_string) + sizeof (ARC_SECTION_FORMAT) + 1); - sprintf (tmp, ARC_SECTION_FORMAT, arc_text_string); - arc_data_section = tmp = XNEWVEC (char, strlen (arc_data_string) + sizeof (ARC_SECTION_FORMAT) + 1); - sprintf (tmp, ARC_SECTION_FORMAT, arc_data_string); - arc_rodata_section = tmp = XNEWVEC (char, strlen (arc_rodata_string) + sizeof (ARC_SECTION_FORMAT) + 1); - sprintf (tmp, ARC_SECTION_FORMAT, arc_rodata_string); - - arc_init_reg_tables (); - - /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */ - memset (arc_punct_chars, 0, sizeof (arc_punct_chars)); - arc_punct_chars['#'] = 1; - arc_punct_chars['*'] = 1; - arc_punct_chars['?'] = 1; - arc_punct_chars['!'] = 1; - arc_punct_chars['~'] = 1; -} - -/* The condition codes of the ARC, and the inverse function. */ -static const char *const arc_condition_codes[] = -{ - "al", 0, "eq", "ne", "p", "n", "c", "nc", "v", "nv", - "gt", "le", "ge", "lt", "hi", "ls", "pnz", 0 -}; - -#define ARC_INVERSE_CONDITION_CODE(X) ((X) ^ 1) - -/* Returns the index of the ARC condition code string in - `arc_condition_codes'. COMPARISON should be an rtx like - `(eq (...) (...))'. */ - -static int -get_arc_condition_code (rtx comparison) -{ - switch (GET_CODE (comparison)) - { - case EQ : return 2; - case NE : return 3; - case GT : return 10; - case LE : return 11; - case GE : return 12; - case LT : return 13; - case GTU : return 14; - case LEU : return 15; - case LTU : return 6; - case GEU : return 7; - default : gcc_unreachable (); - } - /*NOTREACHED*/ - return (42); -} - -/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, - return the mode to be used for the comparison. */ - -enum machine_mode -arc_select_cc_mode (enum rtx_code op, - rtx x ATTRIBUTE_UNUSED, - rtx y ATTRIBUTE_UNUSED) -{ - switch (op) - { - case EQ : - case NE : - return CCZNmode; - default : - switch (GET_CODE (x)) - { - case AND : - case IOR : - case XOR : - case SIGN_EXTEND : - case ZERO_EXTEND : - return CCZNmode; - case ASHIFT : - case ASHIFTRT : - case LSHIFTRT : - return CCZNCmode; - default: - break; - } - } - return CCmode; -} - -/* Vectors to keep interesting information about registers where it can easily - be got. We use to use the actual mode value as the bit number, but there - is (or may be) more than 32 modes now. Instead we use two tables: one - indexed by hard register number, and one indexed by mode. */ - -/* The purpose of arc_mode_class is to shrink the range of modes so that - they all fit (as bit numbers) in a 32-bit word (again). Each real mode is - mapped into one arc_mode_class mode. */ - -enum arc_mode_class { - C_MODE, - S_MODE, D_MODE, T_MODE, O_MODE, - SF_MODE, DF_MODE, TF_MODE, OF_MODE -}; - -/* Modes for condition codes. */ -#define C_MODES (1 << (int) C_MODE) - -/* Modes for single-word and smaller quantities. */ -#define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE)) - -/* Modes for double-word and smaller quantities. */ -#define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE)) - -/* Modes for quad-word and smaller quantities. */ -#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE)) - -/* Value is 1 if register/mode pair is acceptable on arc. */ - -const unsigned int arc_hard_regno_mode_ok[] = { - T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, - T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, - T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, D_MODES, - D_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, - - /* ??? Leave these as S_MODES for now. */ - S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, - S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, - S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, - S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, C_MODES -}; - -unsigned int arc_mode_class [NUM_MACHINE_MODES]; - -enum reg_class arc_regno_reg_class[FIRST_PSEUDO_REGISTER]; - -static void -arc_init_reg_tables (void) -{ - int i; - - for (i = 0; i < NUM_MACHINE_MODES; i++) - { - switch (GET_MODE_CLASS (i)) - { - case MODE_INT: - case MODE_PARTIAL_INT: - case MODE_COMPLEX_INT: - if (GET_MODE_SIZE (i) <= 4) - arc_mode_class[i] = 1 << (int) S_MODE; - else if (GET_MODE_SIZE (i) == 8) - arc_mode_class[i] = 1 << (int) D_MODE; - else if (GET_MODE_SIZE (i) == 16) - arc_mode_class[i] = 1 << (int) T_MODE; - else if (GET_MODE_SIZE (i) == 32) - arc_mode_class[i] = 1 << (int) O_MODE; - else - arc_mode_class[i] = 0; - break; - case MODE_FLOAT: - case MODE_COMPLEX_FLOAT: - if (GET_MODE_SIZE (i) <= 4) - arc_mode_class[i] = 1 << (int) SF_MODE; - else if (GET_MODE_SIZE (i) == 8) - arc_mode_class[i] = 1 << (int) DF_MODE; - else if (GET_MODE_SIZE (i) == 16) - arc_mode_class[i] = 1 << (int) TF_MODE; - else if (GET_MODE_SIZE (i) == 32) - arc_mode_class[i] = 1 << (int) OF_MODE; - else - arc_mode_class[i] = 0; - break; - case MODE_CC: - arc_mode_class[i] = 1 << (int) C_MODE; - break; - default: - arc_mode_class[i] = 0; - break; - } - } - - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - { - if (i < 60) - arc_regno_reg_class[i] = GENERAL_REGS; - else if (i == 60) - arc_regno_reg_class[i] = LPCOUNT_REG; - else if (i == 61) - arc_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */; - else - arc_regno_reg_class[i] = NO_REGS; - } -} - -/* ARC specific attribute support. - - The ARC has these attributes: - interrupt - for interrupt functions -*/ - -/* Handle an "interrupt" attribute; arguments as in - struct attribute_spec.handler. */ -static tree -arc_handle_interrupt_attribute (tree *node ATTRIBUTE_UNUSED, - tree name, - tree args, - int flags ATTRIBUTE_UNUSED, - bool *no_add_attrs) -{ - tree value = TREE_VALUE (args); - - if (TREE_CODE (value) != STRING_CST) - { - warning (OPT_Wattributes, - "argument of %qE attribute is not a string constant", - name); - *no_add_attrs = true; - } - else if (strcmp (TREE_STRING_POINTER (value), "ilink1") - && strcmp (TREE_STRING_POINTER (value), "ilink2")) - { - warning (OPT_Wattributes, - "argument of %qE attribute is not \"ilink1\" or \"ilink2\"", - name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - - -/* Acceptable arguments to the call insn. */ - -int -call_address_operand (rtx op, enum machine_mode mode) -{ - return (symbolic_operand (op, mode) - || (GET_CODE (op) == CONST_INT && LEGITIMATE_CONSTANT_P (op)) - || (GET_CODE (op) == REG)); -} - -int -call_operand (rtx op, enum machine_mode mode) -{ - if (GET_CODE (op) != MEM) - return 0; - op = XEXP (op, 0); - return call_address_operand (op, mode); -} - -/* Returns 1 if OP is a symbol reference. */ - -int -symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - switch (GET_CODE (op)) - { - case SYMBOL_REF: - case LABEL_REF: - case CONST : - return 1; - default: - return 0; - } -} - -/* Return truth value of statement that OP is a symbolic memory - operand of mode MODE. */ - -int -symbolic_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - if (GET_CODE (op) != MEM) - return 0; - op = XEXP (op, 0); - return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST - || GET_CODE (op) == LABEL_REF); -} - -/* Return true if OP is a short immediate (shimm) value. */ - -int -short_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - if (GET_CODE (op) != CONST_INT) - return 0; - return SMALL_INT (INTVAL (op)); -} - -/* Return true if OP will require a long immediate (limm) value. - This is currently only used when calculating length attributes. */ - -int -long_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - switch (GET_CODE (op)) - { - case SYMBOL_REF : - case LABEL_REF : - case CONST : - return 1; - case CONST_INT : - return !SMALL_INT (INTVAL (op)); - case CONST_DOUBLE : - /* These can happen because large unsigned 32-bit constants are - represented this way (the multiplication patterns can cause these - to be generated). They also occur for SFmode values. */ - return 1; - default: - break; - } - return 0; -} - -/* Return true if OP is a MEM that when used as a load or store address will - require an 8 byte insn. - Load and store instructions don't allow the same possibilities but they're - similar enough that this one function will do. - This is currently only used when calculating length attributes. */ - -int -long_immediate_loadstore_operand (rtx op, - enum machine_mode mode ATTRIBUTE_UNUSED) -{ - if (GET_CODE (op) != MEM) - return 0; - - op = XEXP (op, 0); - switch (GET_CODE (op)) - { - case SYMBOL_REF : - case LABEL_REF : - case CONST : - return 1; - case CONST_INT : - /* This must be handled as "st c,[limm]". Ditto for load. - Technically, the assembler could translate some possibilities to - "st c,[limm/2 + limm/2]" if limm/2 will fit in a shimm, but we don't - assume that it does. */ - return 1; - case CONST_DOUBLE : - /* These can happen because large unsigned 32-bit constants are - represented this way (the multiplication patterns can cause these - to be generated). They also occur for SFmode values. */ - return 1; - case REG : - return 0; - case PLUS : - if (GET_CODE (XEXP (op, 1)) == CONST_INT - && !SMALL_INT (INTVAL (XEXP (op, 1)))) - return 1; - return 0; - default: - break; - } - return 0; -} - -/* Return true if OP is an acceptable argument for a single word - move source. */ - -int -move_src_operand (rtx op, enum machine_mode mode) -{ - switch (GET_CODE (op)) - { - case SYMBOL_REF : - case LABEL_REF : - case CONST : - return 1; - case CONST_INT : - return (LARGE_INT (INTVAL (op))); - case CONST_DOUBLE : - /* We can handle DImode integer constants in SImode if the value - (signed or unsigned) will fit in 32 bits. This is needed because - large unsigned 32-bit constants are represented as CONST_DOUBLEs. */ - if (mode == SImode) - return arc_double_limm_p (op); - /* We can handle 32-bit floating point constants. */ - if (mode == SFmode) - return GET_MODE (op) == SFmode; - return 0; - case REG : - return register_operand (op, mode); - case SUBREG : - /* (subreg (mem ...) ...) can occur here if the inner part was once a - pseudo-reg and is now a stack slot. */ - if (GET_CODE (SUBREG_REG (op)) == MEM) - return address_operand (XEXP (SUBREG_REG (op), 0), mode); - else - return register_operand (op, mode); - case MEM : - return address_operand (XEXP (op, 0), mode); - default : - return 0; - } -} - -/* Return true if OP is an acceptable argument for a double word - move source. */ - -int -move_double_src_operand (rtx op, enum machine_mode mode) -{ - switch (GET_CODE (op)) - { - case REG : - return register_operand (op, mode); - case SUBREG : - /* (subreg (mem ...) ...) can occur here if the inner part was once a - pseudo-reg and is now a stack slot. */ - if (GET_CODE (SUBREG_REG (op)) == MEM) - return move_double_src_operand (SUBREG_REG (op), mode); - else - return register_operand (op, mode); - case MEM : - /* Disallow auto inc/dec for now. */ - if (GET_CODE (XEXP (op, 0)) == PRE_DEC - || GET_CODE (XEXP (op, 0)) == PRE_INC) - return 0; - return address_operand (XEXP (op, 0), mode); - case CONST_INT : - case CONST_DOUBLE : - return 1; - default : - return 0; - } -} - -/* Return true if OP is an acceptable argument for a move destination. */ - -int -move_dest_operand (rtx op, enum machine_mode mode) -{ - switch (GET_CODE (op)) - { - case REG : - return register_operand (op, mode); - case SUBREG : - /* (subreg (mem ...) ...) can occur here if the inner part was once a - pseudo-reg and is now a stack slot. */ - if (GET_CODE (SUBREG_REG (op)) == MEM) - return address_operand (XEXP (SUBREG_REG (op), 0), mode); - else - return register_operand (op, mode); - case MEM : - return address_operand (XEXP (op, 0), mode); - default : - return 0; - } -} - -/* Return true if OP is valid load with update operand. */ - -int -load_update_operand (rtx op, enum machine_mode mode) -{ - if (GET_CODE (op) != MEM - || GET_MODE (op) != mode) - return 0; - op = XEXP (op, 0); - if (GET_CODE (op) != PLUS - || GET_MODE (op) != Pmode - || !register_operand (XEXP (op, 0), Pmode) - || !nonmemory_operand (XEXP (op, 1), Pmode)) - return 0; - return 1; -} - -/* Return true if OP is valid store with update operand. */ - -int -store_update_operand (rtx op, enum machine_mode mode) -{ - if (GET_CODE (op) != MEM - || GET_MODE (op) != mode) - return 0; - op = XEXP (op, 0); - if (GET_CODE (op) != PLUS - || GET_MODE (op) != Pmode - || !register_operand (XEXP (op, 0), Pmode) - || !(GET_CODE (XEXP (op, 1)) == CONST_INT - && SMALL_INT (INTVAL (XEXP (op, 1))))) - return 0; - return 1; -} - -/* Return true if OP is a non-volatile non-immediate operand. - Volatile memory refs require a special "cache-bypass" instruction - and only the standard movXX patterns are set up to handle them. */ - -int -nonvol_nonimm_operand (rtx op, enum machine_mode mode) -{ - if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op)) - return 0; - return nonimmediate_operand (op, mode); -} - -/* Accept integer operands in the range -0x80000000..0x7fffffff. We have - to check the range carefully since this predicate is used in DImode - contexts. */ - -int -const_sint32_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - /* All allowed constants will fit a CONST_INT. */ - return (GET_CODE (op) == CONST_INT - && (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff)); -} - -/* Accept integer operands in the range 0..0xffffffff. We have to check the - range carefully since this predicate is used in DImode contexts. Also, we - need some extra crud to make it work when hosted on 64-bit machines. */ - -int -const_uint32_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ -#if HOST_BITS_PER_WIDE_INT > 32 - /* All allowed constants will fit a CONST_INT. */ - return (GET_CODE (op) == CONST_INT - && (INTVAL (op) >= 0 && INTVAL (op) <= 0xffffffffL)); -#else - return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0) - || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0)); -#endif -} - -/* Return 1 if OP is a comparison operator valid for the mode of CC. - This allows the use of MATCH_OPERATOR to recognize all the branch insns. - - Some insns only set a few bits in the condition code. So only allow those - comparisons that use the bits that are valid. */ - -int -proper_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - enum rtx_code code; - if (!COMPARISON_P (op)) - return 0; - - code = GET_CODE (op); - if (GET_MODE (XEXP (op, 0)) == CCZNmode) - return (code == EQ || code == NE); - if (GET_MODE (XEXP (op, 0)) == CCZNCmode) - return (code == EQ || code == NE - || code == LTU || code == GEU || code == GTU || code == LEU); - return 1; -} - -/* Misc. utilities. */ - -/* X and Y are two things to compare using CODE. Return the rtx - for the cc reg in the proper mode. */ - -rtx -gen_compare_reg (enum rtx_code code, rtx x, rtx y) -{ - enum machine_mode mode = SELECT_CC_MODE (code, x, y); - return gen_rtx_REG (mode, 61); -} - -/* Return 1 if VALUE, a const_double, will fit in a limm (4 byte number). - We assume the value can be either signed or unsigned. */ - -int -arc_double_limm_p (rtx value) -{ - HOST_WIDE_INT low, high; - - gcc_assert (GET_CODE (value) == CONST_DOUBLE); - - low = CONST_DOUBLE_LOW (value); - high = CONST_DOUBLE_HIGH (value); - - if (low & 0x80000000) - { - return (((unsigned HOST_WIDE_INT) low <= 0xffffffff && high == 0) - || (((low & - (unsigned HOST_WIDE_INT) 0x80000000) - == - (unsigned HOST_WIDE_INT) 0x80000000) - && high == -1)); - } - else - { - return (unsigned HOST_WIDE_INT) low <= 0x7fffffff && high == 0; - } -} - -/* Do any needed setup for a variadic function. For the ARC, we must - create a register parameter block, and then copy any anonymous arguments - in registers to memory. - - CUM has not been updated for the last named argument which has type TYPE - and mode MODE, and we rely on this fact. - - We do things a little weird here. We're supposed to only allocate space - for the anonymous arguments. However we need to keep the stack eight byte - aligned. So we round the space up if necessary, and leave it to va_start - to compensate. */ - -static void -arc_setup_incoming_varargs (CUMULATIVE_ARGS *cum, - enum machine_mode mode, - tree type ATTRIBUTE_UNUSED, - int *pretend_size, - int no_rtl) -{ - int first_anon_arg; - - /* All BLKmode values are passed by reference. */ - gcc_assert (mode != BLKmode); - - first_anon_arg = *cum + ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) - / UNITS_PER_WORD); - - if (first_anon_arg < MAX_ARC_PARM_REGS && !no_rtl) - { - /* Note that first_reg_offset < MAX_ARC_PARM_REGS. */ - int first_reg_offset = first_anon_arg; - /* Size in words to "pretend" allocate. */ - int size = MAX_ARC_PARM_REGS - first_reg_offset; - /* Extra slop to keep stack eight byte aligned. */ - int align_slop = size & 1; - rtx regblock; - - regblock = gen_rtx_MEM (BLKmode, - plus_constant (arg_pointer_rtx, - FIRST_PARM_OFFSET (0) - + align_slop * UNITS_PER_WORD)); - set_mem_alias_set (regblock, get_varargs_alias_set ()); - set_mem_align (regblock, BITS_PER_WORD); - move_block_from_reg (first_reg_offset, regblock, - MAX_ARC_PARM_REGS - first_reg_offset); - - *pretend_size = ((MAX_ARC_PARM_REGS - first_reg_offset + align_slop) - * UNITS_PER_WORD); - } -} - -/* Cost functions. */ - -/* Compute a (partial) cost for rtx X. Return true if the complete - cost has been computed, and false if subexpressions should be - scanned. In either case, *TOTAL contains the cost result. */ - -static bool -arc_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total, - bool speed ATTRIBUTE_UNUSED) -{ - switch (code) - { - /* Small integers are as cheap as registers. 4 byte values can - be fetched as immediate constants - let's give that the cost - of an extra insn. */ - case CONST_INT: - if (SMALL_INT (INTVAL (x))) - { - *total = 0; - return true; - } - /* FALLTHRU */ - - case CONST: - case LABEL_REF: - case SYMBOL_REF: - *total = COSTS_N_INSNS (1); - return true; - - case CONST_DOUBLE: - { - rtx high, low; - split_double (x, &high, &low); - *total = COSTS_N_INSNS (!SMALL_INT (INTVAL (high)) - + !SMALL_INT (INTVAL (low))); - return true; - } - - /* Encourage synth_mult to find a synthetic multiply when reasonable. - If we need more than 12 insns to do a multiply, then go out-of-line, - since the call overhead will be < 10% of the cost of the multiply. */ - case ASHIFT: - case ASHIFTRT: - case LSHIFTRT: - if (TARGET_SHIFTER) - *total = COSTS_N_INSNS (1); - else if (GET_CODE (XEXP (x, 1)) != CONST_INT) - *total = COSTS_N_INSNS (16); - else - *total = COSTS_N_INSNS (INTVAL (XEXP ((x), 1))); - return false; - - default: - return false; - } -} - - -/* Provide the costs of an addressing mode that contains ADDR. - If ADDR is not a valid address, its cost is irrelevant. */ - -static int -arc_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED) -{ - switch (GET_CODE (addr)) - { - case REG : - return 1; - - case LABEL_REF : - case SYMBOL_REF : - case CONST : - return 2; - - case PLUS : - { - register rtx plus0 = XEXP (addr, 0); - register rtx plus1 = XEXP (addr, 1); - - if (GET_CODE (plus0) != REG) - break; - - switch (GET_CODE (plus1)) - { - case CONST_INT : - return SMALL_INT (INTVAL (plus1)) ? 1 : 2; - case CONST : - case SYMBOL_REF : - case LABEL_REF : - return 2; - default: - break; - } - break; - } - default: - break; - } - - return 4; -} - -/* Function prologue/epilogue handlers. */ - -/* ARC stack frames look like: - - Before call After call - +-----------------------+ +-----------------------+ - | | | | - high | local variables, | | local variables, | - mem | reg save area, etc. | | reg save area, etc. | - | | | | - +-----------------------+ +-----------------------+ - | | | | - | arguments on stack. | | arguments on stack. | - | | | | - SP+16->+-----------------------+FP+48->+-----------------------+ - | 4 word save area for | | reg parm save area, | - | return addr, prev %fp | | only created for | - SP+0->+-----------------------+ | variable argument | - | functions | - FP+16->+-----------------------+ - | 4 word save area for | - | return addr, prev %fp | - FP+0->+-----------------------+ - | | - | local variables | - | | - +-----------------------+ - | | - | register save area | - | | - +-----------------------+ - | | - | alloca allocations | - | | - +-----------------------+ - | | - | arguments on stack | - | | - SP+16->+-----------------------+ - low | 4 word save area for | - memory | return addr, prev %fp | - SP+0->+-----------------------+ - -Notes: -1) The "reg parm save area" does not exist for non variable argument fns. - The "reg parm save area" can be eliminated completely if we created our - own va-arc.h, but that has tradeoffs as well (so it's not done). */ - -/* Structure to be filled in by arc_compute_frame_size with register - save masks, and offsets for the current function. */ -struct arc_frame_info -{ - unsigned int total_size; /* # bytes that the entire frame takes up. */ - unsigned int extra_size; /* # bytes of extra stuff. */ - unsigned int pretend_size; /* # bytes we push and pretend caller did. */ - unsigned int args_size; /* # bytes that outgoing arguments take up. */ - unsigned int reg_size; /* # bytes needed to store regs. */ - unsigned int var_size; /* # bytes that variables take up. */ - unsigned int reg_offset; /* Offset from new sp to store regs. */ - unsigned int gmask; /* Mask of saved gp registers. */ - int initialized; /* Nonzero if frame size already calculated. */ -}; - -/* Current frame information calculated by arc_compute_frame_size. */ -static struct arc_frame_info current_frame_info; - -/* Zero structure to initialize current_frame_info. */ -static struct arc_frame_info zero_frame_info; - -/* Type of function DECL. - - The result is cached. To reset the cache at the end of a function, - call with DECL = NULL_TREE. */ - -enum arc_function_type -arc_compute_function_type (tree decl) -{ - tree a; - /* Cached value. */ - static enum arc_function_type fn_type = ARC_FUNCTION_UNKNOWN; - /* Last function we were called for. */ - static tree last_fn = NULL_TREE; - - /* Resetting the cached value? */ - if (decl == NULL_TREE) - { - fn_type = ARC_FUNCTION_UNKNOWN; - last_fn = NULL_TREE; - return fn_type; - } - - if (decl == last_fn && fn_type != ARC_FUNCTION_UNKNOWN) - return fn_type; - - /* Assume we have a normal function (not an interrupt handler). */ - fn_type = ARC_FUNCTION_NORMAL; - - /* Now see if this is an interrupt handler. */ - for (a = DECL_ATTRIBUTES (current_function_decl); - a; - a = TREE_CHAIN (a)) - { - tree name = TREE_PURPOSE (a), args = TREE_VALUE (a); - - if (name == get_identifier ("__interrupt__") - && list_length (args) == 1 - && TREE_CODE (TREE_VALUE (args)) == STRING_CST) - { - tree value = TREE_VALUE (args); - - if (!strcmp (TREE_STRING_POINTER (value), "ilink1")) - fn_type = ARC_FUNCTION_ILINK1; - else if (!strcmp (TREE_STRING_POINTER (value), "ilink2")) - fn_type = ARC_FUNCTION_ILINK2; - else - gcc_unreachable (); - break; - } - } - - last_fn = decl; - return fn_type; -} - -#define ILINK1_REGNUM 29 -#define ILINK2_REGNUM 30 -#define RETURN_ADDR_REGNUM 31 -#define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM)) -#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM)) - -/* Tell prologue and epilogue if register REGNO should be saved / restored. - The return address and frame pointer are treated separately. - Don't consider them here. */ -#define MUST_SAVE_REGISTER(regno, interrupt_p) \ -((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \ - && (df_regs_ever_live_p (regno) && (!call_used_regs[regno] || interrupt_p))) - -#define MUST_SAVE_RETURN_ADDR (df_regs_ever_live_p (RETURN_ADDR_REGNUM)) - -/* Return the bytes needed to compute the frame pointer from the current - stack pointer. - - SIZE is the size needed for local variables. */ - -unsigned int -arc_compute_frame_size (int size /* # of var. bytes allocated. */) -{ - int regno; - unsigned int total_size, var_size, args_size, pretend_size, extra_size; - unsigned int reg_size, reg_offset; - unsigned int gmask; - enum arc_function_type fn_type; - int interrupt_p; - - var_size = size; - args_size = crtl->outgoing_args_size; - pretend_size = crtl->args.pretend_args_size; - extra_size = FIRST_PARM_OFFSET (0); - total_size = extra_size + pretend_size + args_size + var_size; - reg_offset = FIRST_PARM_OFFSET(0) + crtl->outgoing_args_size; - reg_size = 0; - gmask = 0; - - /* See if this is an interrupt handler. Call used registers must be saved - for them too. */ - fn_type = arc_compute_function_type (current_function_decl); - interrupt_p = ARC_INTERRUPT_P (fn_type); - - /* Calculate space needed for registers. - ??? We ignore the extension registers for now. */ - - for (regno = 0; regno <= 31; regno++) - { - if (MUST_SAVE_REGISTER (regno, interrupt_p)) - { - reg_size += UNITS_PER_WORD; - gmask |= 1 << regno; - } - } - - total_size += reg_size; - - /* If the only space to allocate is the fp/blink save area this is an - empty frame. However, if we'll be making a function call we need to - allocate a stack frame for our callee's fp/blink save area. */ - if (total_size == extra_size - && !MUST_SAVE_RETURN_ADDR) - total_size = extra_size = 0; - - total_size = ARC_STACK_ALIGN (total_size); - - /* Save computed information. */ - current_frame_info.total_size = total_size; - current_frame_info.extra_size = extra_size; - current_frame_info.pretend_size = pretend_size; - current_frame_info.var_size = var_size; - current_frame_info.args_size = args_size; - current_frame_info.reg_size = reg_size; - current_frame_info.reg_offset = reg_offset; - current_frame_info.gmask = gmask; - current_frame_info.initialized = reload_completed; - - /* Ok, we're done. */ - return total_size; -} - -/* Common code to save/restore registers. */ - -void -arc_save_restore (FILE *file, - const char *base_reg, - unsigned int offset, - unsigned int gmask, - const char *op) -{ - int regno; - - if (gmask == 0) - return; - - for (regno = 0; regno <= 31; regno++) - { - if ((gmask & (1L << regno)) != 0) - { - fprintf (file, "\t%s %s,[%s,%d]\n", - op, reg_names[regno], base_reg, offset); - offset += UNITS_PER_WORD; - } - } -} - -/* Target hook to assemble an integer object. The ARC version needs to - emit a special directive for references to labels and function - symbols. */ - -static bool -arc_assemble_integer (rtx x, unsigned int size, int aligned_p) -{ - if (size == UNITS_PER_WORD && aligned_p - && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x)) - || GET_CODE (x) == LABEL_REF)) - { - fputs ("\t.word\t%st(", asm_out_file); - output_addr_const (asm_out_file, x); - fputs (")\n", asm_out_file); - return true; - } - return default_assemble_integer (x, size, aligned_p); -} - -/* Set up the stack and frame pointer (if desired) for the function. */ - -static void -arc_output_function_prologue (FILE *file, HOST_WIDE_INT size) -{ - const char *sp_str = reg_names[STACK_POINTER_REGNUM]; - const char *fp_str = reg_names[FRAME_POINTER_REGNUM]; - unsigned int gmask = current_frame_info.gmask; - enum arc_function_type fn_type = arc_compute_function_type (current_function_decl); - - /* If this is an interrupt handler, set up our stack frame. - ??? Optimize later. */ - if (ARC_INTERRUPT_P (fn_type)) - { - fprintf (file, "\t%s interrupt handler\n", - ASM_COMMENT_START); - fprintf (file, "\tsub %s,%s,16\n", sp_str, sp_str); - } - - /* This is only for the human reader. */ - fprintf (file, "\t%s BEGIN PROLOGUE %s vars= %d, regs= %d, args= %d, extra= %d\n", - ASM_COMMENT_START, ASM_COMMENT_START, - current_frame_info.var_size, - current_frame_info.reg_size / 4, - current_frame_info.args_size, - current_frame_info.extra_size); - - size = ARC_STACK_ALIGN (size); - size = (! current_frame_info.initialized - ? arc_compute_frame_size (size) - : current_frame_info.total_size); - - /* These cases shouldn't happen. Catch them now. */ - gcc_assert (size || !gmask); - - /* Allocate space for register arguments if this is a variadic function. */ - if (current_frame_info.pretend_size != 0) - fprintf (file, "\tsub %s,%s,%d\n", - sp_str, sp_str, current_frame_info.pretend_size); - - /* The home-grown ABI says link register is saved first. */ - if (MUST_SAVE_RETURN_ADDR) - fprintf (file, "\tst %s,[%s,%d]\n", - reg_names[RETURN_ADDR_REGNUM], sp_str, UNITS_PER_WORD); - - /* Set up the previous frame pointer next (if we need to). */ - if (frame_pointer_needed) - { - fprintf (file, "\tst %s,[%s]\n", fp_str, sp_str); - fprintf (file, "\tmov %s,%s\n", fp_str, sp_str); - } - - /* ??? We don't handle the case where the saved regs are more than 252 - bytes away from sp. This can be handled by decrementing sp once, saving - the regs, and then decrementing it again. The epilogue doesn't have this - problem as the `ld' insn takes reg+limm values (though it would be more - efficient to avoid reg+limm). */ - - /* Allocate the stack frame. */ - if (size - current_frame_info.pretend_size > 0) - fprintf (file, "\tsub %s,%s," HOST_WIDE_INT_PRINT_DEC "\n", - sp_str, sp_str, size - current_frame_info.pretend_size); - - /* Save any needed call-saved regs (and call-used if this is an - interrupt handler). */ - arc_save_restore (file, sp_str, current_frame_info.reg_offset, - /* The zeroing of these two bits is unnecessary, - but leave this in for clarity. */ - gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), - "st"); - - fprintf (file, "\t%s END PROLOGUE\n", ASM_COMMENT_START); -} - -/* Do any necessary cleanup after a function to restore stack, frame, - and regs. */ - -static void -arc_output_function_epilogue (FILE *file, HOST_WIDE_INT size) -{ - rtx epilogue_delay = crtl->epilogue_delay_list; - int noepilogue = FALSE; - enum arc_function_type fn_type = arc_compute_function_type (current_function_decl); - - /* This is only for the human reader. */ - fprintf (file, "\t%s EPILOGUE\n", ASM_COMMENT_START); - - size = ARC_STACK_ALIGN (size); - size = (!current_frame_info.initialized - ? arc_compute_frame_size (size) - : current_frame_info.total_size); - - if (size == 0 && epilogue_delay == 0) - { - rtx insn = get_last_insn (); - - /* If the last insn was a BARRIER, we don't have to write any code - because a jump (aka return) was put there. */ - if (GET_CODE (insn) == NOTE) - insn = prev_nonnote_insn (insn); - if (insn && GET_CODE (insn) == BARRIER) - noepilogue = TRUE; - } - - if (!noepilogue) - { - unsigned int pretend_size = current_frame_info.pretend_size; - unsigned int frame_size = size - pretend_size; - int restored, fp_restored_p; - int can_trust_sp_p = !cfun->calls_alloca; - const char *sp_str = reg_names[STACK_POINTER_REGNUM]; - const char *fp_str = reg_names[FRAME_POINTER_REGNUM]; - - /* ??? There are lots of optimizations that can be done here. - EG: Use fp to restore regs if it's closer. - Maybe in time we'll do them all. For now, always restore regs from - sp, but don't restore sp if we don't have to. */ - - if (!can_trust_sp_p) - { - gcc_assert (frame_pointer_needed); - fprintf (file,"\tsub %s,%s,%d\t\t%s sp not trusted here\n", - sp_str, fp_str, frame_size, ASM_COMMENT_START); - } - - /* Restore any saved registers. */ - arc_save_restore (file, sp_str, current_frame_info.reg_offset, - /* The zeroing of these two bits is unnecessary, - but leave this in for clarity. */ - current_frame_info.gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), - "ld"); - - if (MUST_SAVE_RETURN_ADDR) - fprintf (file, "\tld %s,[%s,%d]\n", - reg_names[RETURN_ADDR_REGNUM], - frame_pointer_needed ? fp_str : sp_str, - UNITS_PER_WORD + (frame_pointer_needed ? 0 : frame_size)); - - /* Keep track of how much of the stack pointer we've restored. - It makes the following a lot more readable. */ - restored = 0; - fp_restored_p = 0; - - /* We try to emit the epilogue delay slot insn right after the load - of the return address register so that it can execute with the - stack intact. Secondly, loads are delayed. */ - /* ??? If stack intactness is important, always emit now. */ - if (MUST_SAVE_RETURN_ADDR && epilogue_delay != NULL_RTX) - { - final_scan_insn (XEXP (epilogue_delay, 0), file, 1, 1, NULL); - epilogue_delay = NULL_RTX; - } - - if (frame_pointer_needed) - { - /* Try to restore the frame pointer in the delay slot. We can't, - however, if any of these is true. */ - if (epilogue_delay != NULL_RTX - || !SMALL_INT (frame_size) - || pretend_size - || ARC_INTERRUPT_P (fn_type)) - { - /* Note that we restore fp and sp here! */ - fprintf (file, "\tld.a %s,[%s,%d]\n", fp_str, sp_str, frame_size); - restored += frame_size; - fp_restored_p = 1; - } - } - else if (!SMALL_INT (size /* frame_size + pretend_size */) - || ARC_INTERRUPT_P (fn_type)) - { - fprintf (file, "\tadd %s,%s,%d\n", sp_str, sp_str, frame_size); - restored += frame_size; - } - - /* These must be done before the return insn because the delay slot - does the final stack restore. */ - if (ARC_INTERRUPT_P (fn_type)) - { - if (epilogue_delay) - { - final_scan_insn (XEXP (epilogue_delay, 0), file, 1, 1, NULL); - } - } - - /* Emit the return instruction. */ - { - static const int regs[4] = { - 0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM - }; - - /* Update the flags, if returning from an interrupt handler. */ - if (ARC_INTERRUPT_P (fn_type)) - fprintf (file, "\tj.d.f %s\n", reg_names[regs[fn_type]]); - else - fprintf (file, "\tj.d %s\n", reg_names[regs[fn_type]]); - } - - /* If the only register saved is the return address, we need a - nop, unless we have an instruction to put into it. Otherwise - we don't since reloading multiple registers doesn't reference - the register being loaded. */ - - if (ARC_INTERRUPT_P (fn_type)) - fprintf (file, "\tadd %s,%s,16\n", sp_str, sp_str); - else if (epilogue_delay != NULL_RTX) - { - gcc_assert (!frame_pointer_needed || fp_restored_p); - gcc_assert (restored >= size); - final_scan_insn (XEXP (epilogue_delay, 0), file, 1, 1, NULL); - } - else if (frame_pointer_needed && !fp_restored_p) - { - gcc_assert (SMALL_INT (frame_size)); - /* Note that we restore fp and sp here! */ - fprintf (file, "\tld.a %s,[%s,%d]\n", fp_str, sp_str, frame_size); - } - else if (restored < size) - { - gcc_assert (SMALL_INT (size - restored)); - fprintf (file, "\tadd %s,%s," HOST_WIDE_INT_PRINT_DEC "\n", - sp_str, sp_str, size - restored); - } - else - fprintf (file, "\tnop\n"); - } - - /* Reset state info for each function. */ - current_frame_info = zero_frame_info; - arc_compute_function_type (NULL_TREE); -} - -/* Define the number of delay slots needed for the function epilogue. - - Interrupt handlers can't have any epilogue delay slots (it's always needed - for something else, I think). For normal functions, we have to worry about - using call-saved regs as they'll be restored before the delay slot insn. - Functions with non-empty frames already have enough choices for the epilogue - delay slot so for now we only consider functions with empty frames. */ - -int -arc_delay_slots_for_epilogue (void) -{ - if (arc_compute_function_type (current_function_decl) != ARC_FUNCTION_NORMAL) - return 0; - if (!current_frame_info.initialized) - (void) arc_compute_frame_size (get_frame_size ()); - if (current_frame_info.total_size == 0) - return 1; - return 0; -} - -/* Return true if TRIAL is a valid insn for the epilogue delay slot. - Any single length instruction which doesn't reference the stack or frame - pointer or any call-saved register is OK. SLOT will always be 0. */ - -int -arc_eligible_for_epilogue_delay (rtx trial, int slot) -{ - gcc_assert (!slot); - - if (get_attr_length (trial) == 1 - /* If registers where saved, presumably there's more than enough - possibilities for the delay slot. The alternative is something - more complicated (of course, if we expanded the epilogue as rtl - this problem would go away). */ - /* ??? Note that this will always be true since only functions with - empty frames have epilogue delay slots. See - arc_delay_slots_for_epilogue. */ - && current_frame_info.gmask == 0 - && ! reg_mentioned_p (stack_pointer_rtx, PATTERN (trial)) - && ! reg_mentioned_p (frame_pointer_rtx, PATTERN (trial))) - return 1; - return 0; -} - -/* Return true if OP is a shift operator. */ - -int -shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - switch (GET_CODE (op)) - { - case ASHIFTRT: - case LSHIFTRT: - case ASHIFT: - return 1; - default: - return 0; - } -} - -/* Output the assembler code for doing a shift. - We go to a bit of trouble to generate efficient code as the ARC only has - single bit shifts. This is taken from the h8300 port. We only have one - mode of shifting and can't access individual bytes like the h8300 can, so - this is greatly simplified (at the expense of not generating hyper- - efficient code). - - This function is not used if the variable shift insns are present. */ - -/* ??? We assume the output operand is the same as operand 1. - This can be optimized (deleted) in the case of 1 bit shifts. */ -/* ??? We use the loop register here. We don't use it elsewhere (yet) and - using it here will give us a chance to play with it. */ - -const char * -output_shift (rtx *operands) -{ - rtx shift = operands[3]; - enum machine_mode mode = GET_MODE (shift); - enum rtx_code code = GET_CODE (shift); - const char *shift_one; - - gcc_assert (mode == SImode); - - switch (code) - { - case ASHIFT: shift_one = "asl %0,%0"; break; - case ASHIFTRT: shift_one = "asr %0,%0"; break; - case LSHIFTRT: shift_one = "lsr %0,%0"; break; - default: gcc_unreachable (); - } - - if (GET_CODE (operands[2]) != CONST_INT) - { - if (optimize) - { - output_asm_insn ("sub.f 0,%2,0", operands); - output_asm_insn ("mov lp_count,%2", operands); - output_asm_insn ("bz 2f", operands); - } - else - output_asm_insn ("mov %4,%2", operands); - goto shiftloop; - } - else - { - int n; - - /* If the count is negative, make it 0. */ - n = INTVAL (operands[2]); - if (n < 0) - n = 0; - /* If the count is too big, truncate it. - ANSI says shifts of GET_MODE_BITSIZE are undefined - we choose to - do the intuitive thing. */ - else if (n > GET_MODE_BITSIZE (mode)) - n = GET_MODE_BITSIZE (mode); - - /* First see if we can do them inline. */ - if (n <= 8) - { - while (--n >= 0) - output_asm_insn (shift_one, operands); - } - /* See if we can use a rotate/and. */ - else if (n == BITS_PER_WORD - 1) - { - switch (code) - { - case ASHIFT : - output_asm_insn ("and %0,%0,1\n\tror %0,%0", operands); - break; - case ASHIFTRT : - /* The ARC doesn't have a rol insn. Use something else. */ - output_asm_insn ("asl.f 0,%0\n\tsbc %0,0,0", operands); - break; - case LSHIFTRT : - /* The ARC doesn't have a rol insn. Use something else. */ - output_asm_insn ("asl.f 0,%0\n\tadc %0,0,0", operands); - break; - default: - break; - } - } - /* Must loop. */ - else - { - char buf[100]; - - if (optimize) - output_asm_insn ("mov lp_count,%c2", operands); - else - output_asm_insn ("mov %4,%c2", operands); - shiftloop: - if (optimize) - { - if (flag_pic) - sprintf (buf, "lr %%4,[status]\n\tadd %%4,%%4,6\t%s single insn loop start", - ASM_COMMENT_START); - else - sprintf (buf, "mov %%4,%%%%st(1f)\t%s (single insn loop start) >> 2", - ASM_COMMENT_START); - output_asm_insn (buf, operands); - output_asm_insn ("sr %4,[lp_start]", operands); - output_asm_insn ("add %4,%4,1", operands); - output_asm_insn ("sr %4,[lp_end]", operands); - output_asm_insn ("nop\n\tnop", operands); - if (flag_pic) - fprintf (asm_out_file, "\t%s single insn loop\n", - ASM_COMMENT_START); - else - fprintf (asm_out_file, "1:\t%s single insn loop\n", - ASM_COMMENT_START); - output_asm_insn (shift_one, operands); - fprintf (asm_out_file, "2:\t%s end single insn loop\n", - ASM_COMMENT_START); - } - else - { - fprintf (asm_out_file, "1:\t%s begin shift loop\n", - ASM_COMMENT_START); - output_asm_insn ("sub.f %4,%4,1", operands); - output_asm_insn ("nop", operands); - output_asm_insn ("bn.nd 2f", operands); - output_asm_insn (shift_one, operands); - output_asm_insn ("b.nd 1b", operands); - fprintf (asm_out_file, "2:\t%s end shift loop\n", - ASM_COMMENT_START); - } - } - } - - return ""; -} - -/* Nested function support. */ - -/* 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. */ - -void -arc_initialize_trampoline (rtx tramp ATTRIBUTE_UNUSED, - rtx fnaddr ATTRIBUTE_UNUSED, - rtx cxt ATTRIBUTE_UNUSED) -{ -} - -/* Set the cpu type and print out other fancy things, - at the top of the file. */ - -static void -arc_file_start (void) -{ - default_file_start (); - fprintf (asm_out_file, "\t.cpu %s\n", arc_cpu_string); -} - -/* Print operand X (an rtx) in assembler syntax to file FILE. - CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. - For `%' followed by punctuation, CODE is the punctuation and X is null. */ - -void -arc_print_operand (FILE *file, rtx x, int code) -{ - switch (code) - { - case '#' : - /* Conditional branches. For now these are equivalent. */ - case '*' : - /* Unconditional branches. Output the appropriate delay slot suffix. */ - if (!final_sequence || XVECLEN (final_sequence, 0) == 1) - { - /* There's nothing in the delay slot. */ - fputs (".nd", file); - } - else - { - rtx jump = XVECEXP (final_sequence, 0, 0); - rtx delay = XVECEXP (final_sequence, 0, 1); - if (INSN_ANNULLED_BRANCH_P (jump)) - fputs (INSN_FROM_TARGET_P (delay) ? ".jd" : ".nd", file); - else - fputs (".d", file); - } - return; - case '?' : /* with leading "." */ - case '!' : /* without leading "." */ - /* This insn can be conditionally executed. See if the ccfsm machinery - says it should be conditionalized. */ - if (arc_ccfsm_state == 3 || arc_ccfsm_state == 4) - { - /* Is this insn in a delay slot? */ - if (final_sequence && XVECLEN (final_sequence, 0) == 2) - { - rtx insn = XVECEXP (final_sequence, 0, 1); - - /* If the insn is annulled and is from the target path, we need - to inverse the condition test. */ - if (INSN_ANNULLED_BRANCH_P (insn)) - { - if (INSN_FROM_TARGET_P (insn)) - fprintf (file, "%s%s", - code == '?' ? "." : "", - arc_condition_codes[ARC_INVERSE_CONDITION_CODE (arc_ccfsm_current_cc)]); - else - fprintf (file, "%s%s", - code == '?' ? "." : "", - arc_condition_codes[arc_ccfsm_current_cc]); - } - else - { - /* This insn is executed for either path, so don't - conditionalize it at all. */ - ; /* nothing to do */ - } - } - else - { - /* This insn isn't in a delay slot. */ - fprintf (file, "%s%s", - code == '?' ? "." : "", - arc_condition_codes[arc_ccfsm_current_cc]); - } - } - return; - case '~' : - /* Output a nop if we're between a set of the condition codes, - and a conditional branch. */ - if (last_insn_set_cc_p) - fputs ("nop\n\t", file); - return; - case 'd' : - fputs (arc_condition_codes[get_arc_condition_code (x)], file); - return; - case 'D' : - fputs (arc_condition_codes[ARC_INVERSE_CONDITION_CODE - (get_arc_condition_code (x))], - file); - return; - case 'R' : - /* Write second word of DImode or DFmode reference, - register or memory. */ - if (GET_CODE (x) == REG) - fputs (reg_names[REGNO (x)+1], file); - else if (GET_CODE (x) == MEM) - { - fputc ('[', file); - /* Handle possible auto-increment. Since it is pre-increment and - we have already done it, we can just use an offset of four. */ - /* ??? This is taken from rs6000.c I think. I don't think it is - currently necessary, but keep it around. */ - if (GET_CODE (XEXP (x, 0)) == PRE_INC - || GET_CODE (XEXP (x, 0)) == PRE_DEC) - output_address (plus_constant (XEXP (XEXP (x, 0), 0), 4)); - else - output_address (plus_constant (XEXP (x, 0), 4)); - fputc (']', file); - } - else - output_operand_lossage ("invalid operand to %%R code"); - return; - case 'S' : - if ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x)) - || GET_CODE (x) == LABEL_REF) - { - fprintf (file, "%%st("); - output_addr_const (file, x); - fprintf (file, ")"); - return; - } - break; - case 'H' : - case 'L' : - if (GET_CODE (x) == REG) - { - /* L = least significant word, H = most significant word */ - if ((TARGET_BIG_ENDIAN != 0) ^ (code == 'L')) - fputs (reg_names[REGNO (x)], file); - else - fputs (reg_names[REGNO (x)+1], file); - } - else if (GET_CODE (x) == CONST_INT - || GET_CODE (x) == CONST_DOUBLE) - { - rtx first, second; - - split_double (x, &first, &second); - fprintf (file, "0x%08lx", - (long)(code == 'L' ? INTVAL (first) : INTVAL (second))); - } - else - output_operand_lossage ("invalid operand to %%H/%%L code"); - return; - case 'A' : - { - char str[30]; - - gcc_assert (GET_CODE (x) == CONST_DOUBLE - && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT); - - real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x), sizeof (str), 0, 1); - fprintf (file, "%s", str); - return; - } - case 'U' : - /* Output a load/store with update indicator if appropriate. */ - if (GET_CODE (x) == MEM) - { - if (GET_CODE (XEXP (x, 0)) == PRE_INC - || GET_CODE (XEXP (x, 0)) == PRE_DEC) - fputs (".a", file); - } - else - output_operand_lossage ("invalid operand to %%U code"); - return; - case 'V' : - /* Output cache bypass indicator for a load/store insn. Volatile memory - refs are defined to use the cache bypass mechanism. */ - if (GET_CODE (x) == MEM) - { - if (MEM_VOLATILE_P (x)) - fputs (".di", file); - } - else - output_operand_lossage ("invalid operand to %%V code"); - return; - case 0 : - /* Do nothing special. */ - break; - default : - /* Unknown flag. */ - output_operand_lossage ("invalid operand output code"); - } - - switch (GET_CODE (x)) - { - case REG : - fputs (reg_names[REGNO (x)], file); - break; - case MEM : - fputc ('[', file); - if (GET_CODE (XEXP (x, 0)) == PRE_INC) - output_address (plus_constant (XEXP (XEXP (x, 0), 0), - GET_MODE_SIZE (GET_MODE (x)))); - else if (GET_CODE (XEXP (x, 0)) == PRE_DEC) - output_address (plus_constant (XEXP (XEXP (x, 0), 0), - - GET_MODE_SIZE (GET_MODE (x)))); - else - output_address (XEXP (x, 0)); - fputc (']', file); - break; - case CONST_DOUBLE : - /* We handle SFmode constants here as output_addr_const doesn't. */ - if (GET_MODE (x) == SFmode) - { - REAL_VALUE_TYPE d; - long l; - - REAL_VALUE_FROM_CONST_DOUBLE (d, x); - REAL_VALUE_TO_TARGET_SINGLE (d, l); - fprintf (file, "0x%08lx", l); - break; - } - /* Fall through. Let output_addr_const deal with it. */ - default : - output_addr_const (file, x); - break; - } -} - -/* Print a memory address as an operand to reference that memory location. */ - -void -arc_print_operand_address (FILE *file, rtx addr) -{ - register rtx base, index = 0; - int offset = 0; - - switch (GET_CODE (addr)) - { - case REG : - fputs (reg_names[REGNO (addr)], file); - break; - case SYMBOL_REF : - if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr)) - { - fprintf (file, "%%st("); - output_addr_const (file, addr); - fprintf (file, ")"); - } - else - output_addr_const (file, addr); - break; - case PLUS : - if (GET_CODE (XEXP (addr, 0)) == CONST_INT) - offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1); - else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) - offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0); - else - base = XEXP (addr, 0), index = XEXP (addr, 1); - gcc_assert (GET_CODE (base) == REG); - fputs (reg_names[REGNO (base)], file); - if (index == 0) - { - if (offset != 0) - fprintf (file, ",%d", offset); - } - else - { - switch (GET_CODE (index)) - { - case REG: - fprintf (file, ",%s", reg_names[REGNO (index)]); - break; - case SYMBOL_REF: - fputc (',', file), output_addr_const (file, index); - break; - default: - gcc_unreachable (); - } - } - break; - case PRE_INC : - case PRE_DEC : - /* We shouldn't get here as we've lost the mode of the memory object - (which says how much to inc/dec by. */ - gcc_unreachable (); - break; - default : - output_addr_const (file, addr); - break; - } -} - -/* Update compare/branch separation marker. */ - -static void -record_cc_ref (rtx insn) -{ - last_insn_set_cc_p = current_insn_set_cc_p; - - switch (get_attr_cond (insn)) - { - case COND_SET : - case COND_SET_ZN : - case COND_SET_ZNC : - if (get_attr_length (insn) == 1) - current_insn_set_cc_p = 1; - else - current_insn_set_cc_p = 0; - break; - default : - current_insn_set_cc_p = 0; - break; - } -} - -/* Conditional execution support. - - This is based on the ARM port but for now is much simpler. - - A finite state machine takes care of noticing whether or not instructions - can be conditionally executed, and thus decrease execution time and code - size by deleting branch instructions. The fsm is controlled by - final_prescan_insn, and controls the actions of PRINT_OPERAND. The patterns - in the .md file for the branch insns also have a hand in this. */ - -/* The state of the fsm controlling condition codes are: - 0: normal, do nothing special - 1: don't output this insn - 2: don't output this insn - 3: make insns conditional - 4: make insns conditional - - State transitions (state->state by whom, under what condition): - 0 -> 1 final_prescan_insn, if insn is conditional branch - 0 -> 2 final_prescan_insn, if the `target' is an unconditional branch - 1 -> 3 branch patterns, after having not output the conditional branch - 2 -> 4 branch patterns, after having not output the conditional branch - 3 -> 0 (*targetm.asm_out.internal_label), if the `target' label is reached - (the target label has CODE_LABEL_NUMBER equal to - arc_ccfsm_target_label). - 4 -> 0 final_prescan_insn, if `target' unconditional branch is reached - - If the jump clobbers the conditions then we use states 2 and 4. - - A similar thing can be done with conditional return insns. - - We also handle separating branches from sets of the condition code. - This is done here because knowledge of the ccfsm state is required, - we may not be outputting the branch. */ - -void -arc_final_prescan_insn (rtx insn, - rtx *opvec ATTRIBUTE_UNUSED, - int noperands ATTRIBUTE_UNUSED) -{ - /* BODY will hold the body of INSN. */ - register rtx body = PATTERN (insn); - - /* This will be 1 if trying to repeat the trick (i.e.: do the `else' part of - an if/then/else), and things need to be reversed. */ - int reverse = 0; - - /* If we start with a return insn, we only succeed if we find another one. */ - int seeking_return = 0; - - /* START_INSN will hold the insn from where we start looking. This is the - first insn after the following code_label if REVERSE is true. */ - rtx start_insn = insn; - - /* Update compare/branch separation marker. */ - record_cc_ref (insn); - - /* Allow -mdebug-ccfsm to turn this off so we can see how well it does. - We can't do this in macro FINAL_PRESCAN_INSN because its called from - final_scan_insn which has `optimize' as a local. */ - if (optimize < 2 || TARGET_NO_COND_EXEC) - return; - - /* If in state 4, check if the target branch is reached, in order to - change back to state 0. */ - if (arc_ccfsm_state == 4) - { - if (insn == arc_ccfsm_target_insn) - { - arc_ccfsm_target_insn = NULL; - arc_ccfsm_state = 0; - } - return; - } - - /* If in state 3, it is possible to repeat the trick, if this insn is an - unconditional branch to a label, and immediately following this branch - is the previous target label which is only used once, and the label this - branch jumps to is not too far off. Or in other words "we've done the - `then' part, see if we can do the `else' part." */ - if (arc_ccfsm_state == 3) - { - if (simplejump_p (insn)) - { - start_insn = next_nonnote_insn (start_insn); - if (GET_CODE (start_insn) == BARRIER) - { - /* ??? Isn't this always a barrier? */ - start_insn = next_nonnote_insn (start_insn); - } - if (GET_CODE (start_insn) == CODE_LABEL - && CODE_LABEL_NUMBER (start_insn) == arc_ccfsm_target_label - && LABEL_NUSES (start_insn) == 1) - reverse = TRUE; - else - return; - } - else if (GET_CODE (body) == RETURN) - { - start_insn = next_nonnote_insn (start_insn); - if (GET_CODE (start_insn) == BARRIER) - start_insn = next_nonnote_insn (start_insn); - if (GET_CODE (start_insn) == CODE_LABEL - && CODE_LABEL_NUMBER (start_insn) == arc_ccfsm_target_label - && LABEL_NUSES (start_insn) == 1) - { - reverse = TRUE; - seeking_return = 1; - } - else - return; - } - else - return; - } - - if (GET_CODE (insn) != JUMP_INSN) - return; - - /* This jump might be paralleled with a clobber of the condition codes, - the jump should always come first. */ - if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0) - body = XVECEXP (body, 0, 0); - - if (reverse - || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC - && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE)) - { - int insns_skipped = 0, fail = FALSE, succeed = FALSE; - /* Flag which part of the IF_THEN_ELSE is the LABEL_REF. */ - int then_not_else = TRUE; - /* Nonzero if next insn must be the target label. */ - int next_must_be_target_label_p; - rtx this_insn = start_insn, label = 0; - - /* Register the insn jumped to. */ - if (reverse) - { - if (!seeking_return) - label = XEXP (SET_SRC (body), 0); - } - else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF) - label = XEXP (XEXP (SET_SRC (body), 1), 0); - else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF) - { - label = XEXP (XEXP (SET_SRC (body), 2), 0); - then_not_else = FALSE; - } - else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN) - seeking_return = 1; - else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN) - { - seeking_return = 1; - then_not_else = FALSE; - } - else - gcc_unreachable (); - - /* See how many insns this branch skips, and what kind of insns. If all - insns are okay, and the label or unconditional branch to the same - label is not too far away, succeed. */ - for (insns_skipped = 0, next_must_be_target_label_p = FALSE; - !fail && !succeed && insns_skipped < MAX_INSNS_SKIPPED; - insns_skipped++) - { - rtx scanbody; - - this_insn = next_nonnote_insn (this_insn); - if (!this_insn) - break; - - if (next_must_be_target_label_p) - { - if (GET_CODE (this_insn) == BARRIER) - continue; - if (GET_CODE (this_insn) == CODE_LABEL - && this_insn == label) - { - arc_ccfsm_state = 1; - succeed = TRUE; - } - else - fail = TRUE; - break; - } - - scanbody = PATTERN (this_insn); - - switch (GET_CODE (this_insn)) - { - case CODE_LABEL: - /* Succeed if it is the target label, otherwise fail since - control falls in from somewhere else. */ - if (this_insn == label) - { - arc_ccfsm_state = 1; - succeed = TRUE; - } - else - fail = TRUE; - break; - - case BARRIER: - /* Succeed if the following insn is the target label. - Otherwise fail. - If return insns are used then the last insn in a function - will be a barrier. */ - next_must_be_target_label_p = TRUE; - break; - - case CALL_INSN: - /* Can handle a call insn if there are no insns after it. - IE: The next "insn" is the target label. We don't have to - worry about delay slots as such insns are SEQUENCE's inside - INSN's. ??? It is possible to handle such insns though. */ - if (get_attr_cond (this_insn) == COND_CANUSE) - next_must_be_target_label_p = TRUE; - else - fail = TRUE; - break; - - case JUMP_INSN: - /* If this is an unconditional branch to the same label, succeed. - If it is to another label, do nothing. If it is conditional, - fail. */ - /* ??? Probably, the test for the SET and the PC are unnecessary. */ - - if (GET_CODE (scanbody) == SET - && GET_CODE (SET_DEST (scanbody)) == PC) - { - if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF - && XEXP (SET_SRC (scanbody), 0) == label && !reverse) - { - arc_ccfsm_state = 2; - succeed = TRUE; - } - else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE) - fail = TRUE; - } - else if (GET_CODE (scanbody) == RETURN - && seeking_return) - { - arc_ccfsm_state = 2; - succeed = TRUE; - } - else if (GET_CODE (scanbody) == PARALLEL) - { - if (get_attr_cond (this_insn) != COND_CANUSE) - fail = TRUE; - } - break; - - case INSN: - /* We can only do this with insns that can use the condition - codes (and don't set them). */ - if (GET_CODE (scanbody) == SET - || GET_CODE (scanbody) == PARALLEL) - { - if (get_attr_cond (this_insn) != COND_CANUSE) - fail = TRUE; - } - /* We can't handle other insns like sequences. */ - else - fail = TRUE; - break; - - default: - break; - } - } - - if (succeed) - { - if ((!seeking_return) && (arc_ccfsm_state == 1 || reverse)) - arc_ccfsm_target_label = CODE_LABEL_NUMBER (label); - else - { - gcc_assert (seeking_return || arc_ccfsm_state == 2); - while (this_insn && GET_CODE (PATTERN (this_insn)) == USE) - { - this_insn = next_nonnote_insn (this_insn); - gcc_assert (!this_insn - || (GET_CODE (this_insn) != BARRIER - && GET_CODE (this_insn) != CODE_LABEL)); - } - if (!this_insn) - { - /* Oh dear! we ran off the end, give up. */ - extract_insn_cached (insn); - arc_ccfsm_state = 0; - arc_ccfsm_target_insn = NULL; - return; - } - arc_ccfsm_target_insn = this_insn; - } - - /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from - what it was. */ - if (!reverse) - arc_ccfsm_current_cc = get_arc_condition_code (XEXP (SET_SRC (body), - 0)); - - if (reverse || then_not_else) - arc_ccfsm_current_cc = ARC_INVERSE_CONDITION_CODE (arc_ccfsm_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. */ - extract_insn_cached (insn); - } -} - -/* Record that we are currently outputting label NUM with prefix PREFIX. - It it's the label we're looking for, reset the ccfsm machinery. - - Called from (*targetm.asm_out.internal_label). */ - -void -arc_ccfsm_at_label (const char *prefix, int num) -{ - if (arc_ccfsm_state == 3 && arc_ccfsm_target_label == num - && !strcmp (prefix, "L")) - { - arc_ccfsm_state = 0; - arc_ccfsm_target_insn = NULL_RTX; - } -} - -/* See if the current insn, which is a conditional branch, is to be - deleted. */ - -int -arc_ccfsm_branch_deleted_p (void) -{ - if (arc_ccfsm_state == 1 || arc_ccfsm_state == 2) - return 1; - return 0; -} - -/* Record a branch isn't output because subsequent insns can be - conditionalized. */ - -void -arc_ccfsm_record_branch_deleted (void) -{ - /* Indicate we're conditionalizing insns now. */ - arc_ccfsm_state += 2; - - /* If the next insn is a subroutine call, we still need a nop between the - cc setter and user. We need to undo the effect of calling record_cc_ref - for the just deleted branch. */ - current_insn_set_cc_p = last_insn_set_cc_p; -} - -static void -arc_va_start (tree valist, rtx nextarg) -{ - /* See arc_setup_incoming_varargs for reasons for this oddity. */ - if (crtl->args.info < 8 - && (crtl->args.info & 1)) - nextarg = plus_constant (nextarg, UNITS_PER_WORD); - - std_expand_builtin_va_start (valist, nextarg); -} - -/* This is how to output a definition of an internal numbered label where - PREFIX is the class of label and NUM is the number within the class. */ - -static void -arc_internal_label (FILE *stream, const char *prefix, unsigned long labelno) -{ - arc_ccfsm_at_label (prefix, labelno); - default_internal_label (stream, prefix, labelno); -} - -/* Worker function for TARGET_ASM_EXTERNAL_LIBCALL. */ - -static void -arc_external_libcall (rtx fun ATTRIBUTE_UNUSED) -{ -#if 0 -/* On the ARC we want to have libgcc's for multiple cpus in one binary. - We can't use `assemble_name' here as that will call ASM_OUTPUT_LABELREF - and we'll get another suffix added on if -mmangle-cpu. */ - if (TARGET_MANGLE_CPU_LIBGCC) - { - fprintf (FILE, "\t.rename\t_%s, _%s%s\n", - XSTR (SYMREF, 0), XSTR (SYMREF, 0), - arc_mangle_suffix); - } -#endif -} - -/* Worker function for TARGET_RETURN_IN_MEMORY. */ - -static bool -arc_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) -{ - if (AGGREGATE_TYPE_P (type)) - return true; - else - { - HOST_WIDE_INT size = int_size_in_bytes (type); - return (size == -1 || size > 8); - } -} - -/* For ARC, All aggregates and arguments greater than 8 bytes are - passed by reference. */ - -static bool -arc_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED, - enum machine_mode mode, const_tree type, - bool named ATTRIBUTE_UNUSED) -{ - unsigned HOST_WIDE_INT size; - - if (type) - { - if (AGGREGATE_TYPE_P (type)) - return true; - size = int_size_in_bytes (type); - } - else - size = GET_MODE_SIZE (mode); - - return size > 8; -} - -/* Round SIZE up to a word boundary. */ -#define ROUND_ADVANCE(SIZE) \ -(((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) - -/* Round arg MODE/TYPE up to the next word boundary. */ -#define ROUND_ADVANCE_ARG(MODE, TYPE) \ -((MODE) == BLKmode \ - ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \ - : ROUND_ADVANCE (GET_MODE_SIZE (MODE))) - -/* Round CUM up to the necessary point for argument MODE/TYPE. */ -#define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \ -((((MODE) == BLKmode ? TYPE_ALIGN (TYPE) : GET_MODE_BITSIZE (MODE)) \ - > BITS_PER_WORD) \ - ? (((CUM) + 1) & ~1) \ - : (CUM)) - -/* Return boolean indicating arg of type TYPE and mode MODE will be passed in - a reg. This includes arguments that have to be passed by reference as the - pointer to them is passed in a reg if one is available (and that is what - we're given). */ -#define PASS_IN_REG_P(CUM, MODE, TYPE) \ -((CUM) < MAX_ARC_PARM_REGS \ - && ((ROUND_ADVANCE_CUM ((CUM), (MODE), (TYPE)) \ - + ROUND_ADVANCE_ARG ((MODE), (TYPE)) \ - <= MAX_ARC_PARM_REGS))) - -/* Determine where to put an argument to a function. - Value is zero to push the argument on the stack, - or a hard register in which to store the argument. - - MODE is the argument's machine mode. - TYPE is the data type of the argument (as a tree). - This is null for libcalls where that information may - not be available. - CUM is a variable of type CUMULATIVE_ARGS which gives info about - the preceding args and about the function being called. - NAMED is nonzero if this argument is a named parameter - (otherwise it is an extra parameter matching an ellipsis). */ -/* On the ARC the first MAX_ARC_PARM_REGS args are normally in registers - and the rest are pushed. */ - -static rtx -arc_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, - const_tree type, bool named ATTRIBUTE_UNUSED) -{ - return (PASS_IN_REG_P (*cum, mode, type) - ? gen_rtx_REG (mode, ROUND_ADVANCE_CUM (*cum, mode, type)) - : NULL_RTX); -} - -/* Worker function for TARGET_FUNCTION_ARG_ADVANCE. */ - -static void -arc_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, - const_tree type, bool named ATTRIBUTE_UNUSED) -{ - *cum = (ROUND_ADVANCE_CUM (*cum, mode, type) - + ROUND_ADVANCE_ARG (mode, type)); -} - -/* Worker function for TARGET_FUNCTION_ARG_BOUNDARY. */ - -static unsigned int -arc_function_arg_boundary (enum machine_mode mode, const_tree type) -{ - return (type != NULL_TREE - ? TYPE_ALIGN (type) - : (GET_MODE_BITSIZE (mode) <= PARM_BOUNDARY - ? PARM_BOUNDARY - : 2 * PARM_BOUNDARY)); -} - -/* Trampolines. */ -/* ??? This doesn't work yet because GCC will use as the address of a nested - function the address of the trampoline. We need to use that address - right shifted by 2. It looks like we'll need PSImode after all. :-( - - ??? The above comment sounds like it's doable via - TARGET_TRAMPOLINE_ADJUST_ADDRESS; no PSImode needed. - - On the ARC, the trampoline is quite simple as we have 32-bit immediate - constants. - - mov r24,STATIC - j.nd FUNCTION -*/ - -static void -arc_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) -{ - rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); - rtx mem; - - mem = adjust_address (m_tramp, SImode, 0); - emit_move_insn (mem, GEN_INT (0x631f7c00)); - - mem = adjust_address (m_tramp, SImode, 4); - emit_move_insn (mem, chain_value); - - mem = adjust_address (m_tramp, SImode, 8); - emit_move_insn (mem, GEN_INT (0x381f0000)); - - mem = adjust_address (m_tramp, SImode, 12); - emit_move_insn (mem, fnaddr); - - emit_insn (gen_flush_icache (m_tramp)); -} - -/* Worker function for TARGET_CONDITIONAL_REGISTER_USAGE. */ - -static void -arc_conditional_register_usage (void) -{ - if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM) - { - fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; - call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; - } -} - diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h deleted file mode 100644 index 0f2b99c199c..00000000000 --- a/gcc/config/arc/arc.h +++ /dev/null @@ -1,935 +0,0 @@ -/* Definitions of target machine for GNU compiler, Argonaut ARC cpu. - Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, - 2007, 2008, 2009, 2010 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -/* ??? This is an old port, and is undoubtedly suffering from bit rot. */ - -/* Things to do: - - - incscc, decscc? - - print active compiler options in assembler output -*/ - - -#undef ASM_SPEC -#undef LINK_SPEC -#undef LIB_SPEC -#undef STARTFILE_SPEC -#undef ENDFILE_SPEC -#undef SIZE_TYPE -#undef PTRDIFF_TYPE -#undef WCHAR_TYPE -#undef WCHAR_TYPE_SIZE -#undef ASM_OUTPUT_LABELREF - -/* Print subsidiary information on the compiler version in use. */ -#define TARGET_VERSION fprintf (stderr, " (arc)") - -/* Names to predefine in the preprocessor for this target machine. */ -#define TARGET_CPU_CPP_BUILTINS() \ - do \ - { \ - builtin_define ("__arc__"); \ - if (TARGET_BIG_ENDIAN) \ - builtin_define ("__big_endian__"); \ - if (arc_cpu_type == 0) \ - builtin_define ("__base__"); \ - builtin_assert ("cpu=arc"); \ - builtin_assert ("machine=arc"); \ - } while (0) - -/* Pass -mmangle-cpu if we get -mcpu=*. - Doing it this way lets one have it on as default with -mcpu=*, - but also lets one turn it off with -mno-mangle-cpu. */ -#define CC1_SPEC "\ -%{mcpu=*:-mmangle-cpu} \ -%{EB:%{EL:%emay not use both -EB and -EL}} \ -%{EB:-mbig-endian} %{EL:-mlittle-endian} \ -" - -#define ASM_SPEC "%{EB} %{EL}" - -#define LINK_SPEC "%{v} %{EB} %{EL}" - -#define LIB_SPEC "-lc" - -#define STARTFILE_SPEC "%{!shared:crt0.o%s} crtinit.o%s" - -#define ENDFILE_SPEC "crtfini.o%s" - -/* Instruction set characteristics. - These are internal macros, set by the appropriate -mcpu= option. */ - -/* Nonzero means the cpu has a barrel shifter. */ -#define TARGET_SHIFTER 0 - -/* Which cpu we're compiling for. */ -extern int arc_cpu_type; - -/* Check if CPU is an extension and set `arc_cpu_type' and `arc_mangle_cpu' - appropriately. The result should be nonzero if the cpu is recognized, - otherwise zero. This is intended to be redefined in a cover file. - This is used by arc_handle_option. */ -#define ARC_EXTENSION_CPU(cpu) 0 - - -/* Target machine storage layout. */ - -/* Define this if most significant bit is lowest numbered - in instructions that operate on numbered bit-fields. */ -#define BITS_BIG_ENDIAN 1 - -/* Define this if most significant byte of a word is the lowest numbered. */ -#define BYTES_BIG_ENDIAN (TARGET_BIG_ENDIAN) - -/* Define this if most significant word of a multiword number is the lowest - numbered. */ -#define WORDS_BIG_ENDIAN (TARGET_BIG_ENDIAN) - -/* Width of a word, in units (bytes). */ -#define UNITS_PER_WORD 4 - -/* Define this macro if it is advisable to hold scalars in registers - in a wider mode than that declared by the program. In such cases, - the value is constrained to be within the bounds of the declared - type, but kept valid in the wider mode. The signedness of the - extension may differ from that of the type. */ -#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ -if (GET_MODE_CLASS (MODE) == MODE_INT \ - && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \ -{ \ - (MODE) = SImode; \ -} - -/* Allocation boundary (in *bits*) for storing arguments in argument list. */ -#define PARM_BOUNDARY 32 - -/* Boundary (in *bits*) on which stack pointer should be aligned. */ -#define STACK_BOUNDARY 64 - -/* ALIGN FRAMES on word boundaries */ -#define ARC_STACK_ALIGN(LOC) (((LOC)+7) & ~7) - -/* Allocation boundary (in *bits*) for the code of a function. */ -#define FUNCTION_BOUNDARY 32 - -/* Alignment of field after `int : 0' in a structure. */ -#define EMPTY_FIELD_BOUNDARY 32 - -/* Every structure's size must be a multiple of this. */ -#define STRUCTURE_SIZE_BOUNDARY 8 - -/* A bit-field declared as `int' forces `int' alignment for the struct. */ -#define PCC_BITFIELD_TYPE_MATTERS 1 - -/* No data type wants to be aligned rounder than this. */ -/* This is bigger than currently necessary for the ARC. If 8 byte floats are - ever added it's not clear whether they'll need such alignment or not. For - now we assume they will. We can always relax it if necessary but the - reverse isn't true. */ -#define BIGGEST_ALIGNMENT 64 - -/* The best alignment to use in cases where we have a choice. */ -#define FASTEST_ALIGNMENT 32 - -/* Make strings word-aligned so strcpy from constants will be faster. */ -#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ - ((TREE_CODE (EXP) == STRING_CST \ - && (ALIGN) < FASTEST_ALIGNMENT) \ - ? FASTEST_ALIGNMENT : (ALIGN)) - -/* Make arrays of chars word-aligned for the same reasons. */ -#define DATA_ALIGNMENT(TYPE, ALIGN) \ - (TREE_CODE (TYPE) == ARRAY_TYPE \ - && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \ - && (ALIGN) < FASTEST_ALIGNMENT ? FASTEST_ALIGNMENT : (ALIGN)) - -/* Set this nonzero if move instructions will actually fail to work - when given unaligned data. */ -/* On the ARC the lower address bits are masked to 0 as necessary. The chip - won't croak when given an unaligned address, but the insn will still fail - to produce the correct result. */ -#define STRICT_ALIGNMENT 1 - -/* Layout of source language data types. */ - -#define SHORT_TYPE_SIZE 16 -#define INT_TYPE_SIZE 32 -#define LONG_TYPE_SIZE 32 -#define LONG_LONG_TYPE_SIZE 64 -#define FLOAT_TYPE_SIZE 32 -#define DOUBLE_TYPE_SIZE 64 -#define LONG_DOUBLE_TYPE_SIZE 64 - -/* Define this as 1 if `char' should by default be signed; else as 0. */ -#define DEFAULT_SIGNED_CHAR 1 - -#define SIZE_TYPE "long unsigned int" -#define PTRDIFF_TYPE "long int" -#define WCHAR_TYPE "short unsigned int" -#define WCHAR_TYPE_SIZE 16 - -/* Standard register usage. */ - -/* Number of actual hardware registers. - The hardware registers are assigned numbers for the compiler - from 0 to just below FIRST_PSEUDO_REGISTER. - All registers that the compiler knows about must be given numbers, - even those that are not normally considered general registers. */ -/* Registers 61, 62, and 63 are not really registers and we needn't treat - them as such. We still need a register for the condition code. */ -#define FIRST_PSEUDO_REGISTER 62 - -/* 1 for registers that have pervasive standard uses - and are not available for the register allocator. - - 0-28 - general purpose registers - 29 - ilink1 (interrupt link register) - 30 - ilink2 (interrupt link register) - 31 - blink (branch link register) - 32-59 - reserved for extensions - 60 - LP_COUNT - 61 - condition code - - For doc purposes: - 61 - short immediate data indicator (setting flags) - 62 - long immediate data indicator - 63 - short immediate data indicator (not setting flags). - - The general purpose registers are further broken down into: - 0-7 - arguments/results - 8-15 - call used - 16-23 - call saved - 24 - call used, static chain pointer - 25 - call used, gptmp - 26 - global pointer - 27 - frame pointer - 28 - stack pointer - - By default, the extension registers are not available. */ - -#define FIXED_REGISTERS \ -{ 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 1, 1, 1, 1, 0, \ - \ - 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1 } - -/* 1 for registers not available across function calls. - These must include the FIXED_REGISTERS and also any - registers that can be used without being saved. - The latter must include the registers where values are returned - and the register where structure-value addresses are passed. - Aside from that, you can include as many other registers as you like. */ - -#define CALL_USED_REGISTERS \ -{ 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 1, 1, 1, 1, 1, 1, 1, 1, \ - \ - 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1 } - -/* If defined, an initializer for a vector of integers, containing the - numbers of hard registers in the order in which GCC should - prefer to use them (from most preferred to least). */ -#define REG_ALLOC_ORDER \ -{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, \ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 31, \ - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, \ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, \ - 27, 28, 29, 30 } - -/* 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. */ -#define HARD_REGNO_NREGS(REGNO, MODE) \ -((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) - -/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ -extern const unsigned int arc_hard_regno_mode_ok[]; -extern unsigned int arc_mode_class[]; -#define HARD_REGNO_MODE_OK(REGNO, MODE) \ -((arc_hard_regno_mode_ok[REGNO] & arc_mode_class[MODE]) != 0) - -/* A C expression that is nonzero if it is desirable to choose - register allocation so as to avoid move instructions between a - value of mode MODE1 and a value of mode MODE2. - - If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R, - MODE2)' are ever different for any R, then `MODES_TIEABLE_P (MODE1, - MODE2)' must be zero. */ - -/* Tie QI/HI/SI modes together. */ -#define MODES_TIEABLE_P(MODE1, MODE2) \ -(GET_MODE_CLASS (MODE1) == MODE_INT \ - && GET_MODE_CLASS (MODE2) == MODE_INT \ - && GET_MODE_SIZE (MODE1) <= UNITS_PER_WORD \ - && GET_MODE_SIZE (MODE2) <= UNITS_PER_WORD) - -/* Register classes and constants. */ - -/* Define the classes of registers for register constraints in the - machine description. Also define ranges of constants. - - One of the classes must always be named ALL_REGS and include all hard regs. - If there is more than one class, another class must be named NO_REGS - and contain no registers. - - The name GENERAL_REGS must be the name of a class (or an alias for - another name such as ALL_REGS). This is the class of registers - that is allowed by "g" or "r" in a register constraint. - Also, registers outside this class are allocated only when - instructions express preferences for them. - - The classes must be numbered in nondecreasing order; that is, - a larger-numbered class must never be contained completely - in a smaller-numbered class. - - For any two classes, it is very desirable that there be another - class that represents their union. - - It is important that any condition codes have class NO_REGS. - See `register_operand'. */ - -enum reg_class { - NO_REGS, LPCOUNT_REG, GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES -}; - -#define N_REG_CLASSES (int) LIM_REG_CLASSES - -/* Give names of register classes as strings for dump file. */ -#define REG_CLASS_NAMES \ -{ "NO_REGS", "LPCOUNT_REG", "GENERAL_REGS", "ALL_REGS" } - -/* Define which registers fit in which classes. - This is an initializer for a vector of HARD_REG_SET - of length N_REG_CLASSES. */ - -#define REG_CLASS_CONTENTS \ -{ {0, 0}, {0, 0x10000000}, {0xffffffff, 0xfffffff}, \ - {0xffffffff, 0x1fffffff} } - -/* 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. */ -extern enum reg_class arc_regno_reg_class[FIRST_PSEUDO_REGISTER]; -#define REGNO_REG_CLASS(REGNO) \ -(arc_regno_reg_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 - -/* Get reg_class from a letter such as appears in the machine description. */ -#define REG_CLASS_FROM_LETTER(C) \ -((C) == 'l' ? LPCOUNT_REG /* ??? needed? */ \ - : NO_REGS) - -/* These assume that REGNO is a hard or pseudo reg number. - 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. */ -#define REGNO_OK_FOR_BASE_P(REGNO) \ -((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) -#define REGNO_OK_FOR_INDEX_P(REGNO) \ -((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) - -/* Return the maximum number of consecutive registers - needed to represent mode MODE in a register of class CLASS. */ -#define CLASS_MAX_NREGS(CLASS, MODE) \ -((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) - -/* The letters I, J, K, L, M, N, O, P in a register constraint string - can be used to stand for particular ranges of immediate operands. - This macro defines what the ranges are. - C is the letter, and VALUE is a constant value. - Return 1 if VALUE is in the range specified by C. */ -/* 'I' is used for short immediates (always signed). - 'J' is used for long immediates. - 'K' is used for any constant up to 64 bits (for 64x32 situations?). */ - -/* local to this file */ -#define SMALL_INT(X) ((unsigned) ((X) + 0x100) < 0x200) -/* local to this file */ -#define LARGE_INT(X) \ -((X) >= (-(HOST_WIDE_INT) 0x7fffffff - 1) \ - && (unsigned HOST_WIDE_INT)(X) <= (unsigned HOST_WIDE_INT) 0xffffffff) - -#define CONST_OK_FOR_LETTER_P(VALUE, C) \ -((C) == 'I' ? SMALL_INT (VALUE) \ - : (C) == 'J' ? LARGE_INT (VALUE) \ - : (C) == 'K' ? 1 \ - : 0) - -/* Similar, but for floating constants, and defining letters G and H. - Here VALUE is the CONST_DOUBLE rtx itself. */ -/* 'G' is used for integer values for the multiplication insns where the - operands are extended from 4 bytes to 8 bytes. - 'H' is used when any 64-bit constant is allowed. */ -#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ -((C) == 'G' ? arc_double_limm_p (VALUE) \ - : (C) == 'H' ? 1 \ - : 0) - -/* A C expression that defines the optional machine-dependent constraint - letters that can be used to segregate specific types of operands, - usually memory references, for the target machine. It should return 1 if - VALUE corresponds to the operand type represented by the constraint letter - C. If C is not defined as an extra constraint, the value returned should - be 0 regardless of VALUE. */ -/* ??? This currently isn't used. Waiting for PIC. */ -#if 0 -#define EXTRA_CONSTRAINT(VALUE, C) \ -((C) == 'R' ? (SYMBOL_REF_FUNCTION_P (VALUE) || GET_CODE (VALUE) == LABEL_REF) \ - : 0) -#endif - -/* Stack layout and stack pointer usage. */ - -/* Define this macro if pushing a word onto the stack moves the stack - pointer to a smaller address. */ -#define STACK_GROWS_DOWNWARD - -/* Define this to nonzero if the nominal address of the stack frame - is at the high-address end of the local variables; - that is, each additional local variable allocated - goes at a more negative offset in the frame. */ -#define FRAME_GROWS_DOWNWARD 1 - -/* Offset within stack frame to start allocating local variables at. - If FRAME_GROWS_DOWNWARD, this is the offset to the END of the - first local allocated. Otherwise, it is the offset to the BEGINNING - of the first local allocated. */ -#define STARTING_FRAME_OFFSET 0 - -/* Offset from the stack pointer register to the first location at which - outgoing arguments are placed. */ -#define STACK_POINTER_OFFSET FIRST_PARM_OFFSET (0) - -/* Offset of first parameter from the argument pointer register value. */ -/* 4 bytes for each of previous fp, return address, and previous gp. - 4 byte reserved area for future considerations. */ -#define FIRST_PARM_OFFSET(FNDECL) 16 - -/* A C expression whose value is RTL representing the address in a - stack frame where the pointer to the caller's frame is stored. - Assume that FRAMEADDR is an RTL expression for the address of the - stack frame itself. - - If you don't define this macro, the default is to return the value - of FRAMEADDR--that is, the stack frame address is also the address - of the stack word that points to the previous frame. */ -/* ??? unfinished */ -/*define DYNAMIC_CHAIN_ADDRESS (FRAMEADDR)*/ - -/* A C expression whose value is RTL representing the value of the - return address for the frame COUNT steps up from the current frame. - FRAMEADDR is the frame pointer of the COUNT frame, or the frame - pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' - is defined. */ -/* The current return address is in r31. The return address of anything - farther back is at [%fp,4]. */ -#if 0 /* The default value should work. */ -#define RETURN_ADDR_RTX(COUNT, FRAME) \ -(((COUNT) == -1) \ - ? gen_rtx_REG (Pmode, 31) \ - : copy_to_reg (gen_rtx_MEM (Pmode, \ - memory_address (Pmode, \ - plus_constant ((FRAME), \ - UNITS_PER_WORD))))) -#endif - -/* Register to use for pushing function arguments. */ -#define STACK_POINTER_REGNUM 28 - -/* Base register for access to local variables of the function. */ -#define FRAME_POINTER_REGNUM 27 - -/* Base register for access to arguments of the function. */ -#define ARG_POINTER_REGNUM FRAME_POINTER_REGNUM - -/* Register in which static-chain is passed to a function. This must - not be a register used by the prologue. */ -#define STATIC_CHAIN_REGNUM 24 - -/* C statement to store the difference between the frame pointer - and the stack pointer values immediately after the function prologue. */ -#define INITIAL_FRAME_POINTER_OFFSET(VAR) \ -((VAR) = arc_compute_frame_size (get_frame_size ())) - -/* Function argument passing. */ - -/* If defined, the maximum amount of space required for outgoing - arguments will be computed and placed into the variable - `crtl->outgoing_args_size'. No space will be pushed - onto the stack for each call; instead, the function prologue should - increase the stack frame size by this amount. */ -#define ACCUMULATE_OUTGOING_ARGS 1 - -/* Define a data type for recording info about an argument list - during the scan of that argument list. This data type should - hold all necessary information about the function itself - and about the args processed so far, enough to enable macros - such as FUNCTION_ARG to determine where the next arg should go. */ -#define CUMULATIVE_ARGS int - -/* Initialize a variable CUM of type CUMULATIVE_ARGS - for a call to a function whose data type is FNTYPE. - For a library call, FNTYPE is 0. */ -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \ -((CUM) = 0) - -/* The number of registers used for parameter passing. Local to this file. */ -#define MAX_ARC_PARM_REGS 8 - -/* 1 if N is a possible register number for function argument passing. */ -#define FUNCTION_ARG_REGNO_P(N) \ -((unsigned) (N) < MAX_ARC_PARM_REGS) - - -/* Function results. */ - -/* 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) gen_rtx_REG (TYPE_MODE (VALTYPE), 0) - -/* Define how to find the value returned by a library function - assuming the value has mode MODE. */ -#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, 0) - -/* 1 if N is a possible register number for a function value - as seen by the caller. */ -/* ??? What about r1 in DI/DF values. */ -#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) - -/* Tell GCC to use TARGET_RETURN_IN_MEMORY. */ -#define DEFAULT_PCC_STRUCT_RETURN 0 - -/* 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. - No definition is equivalent to always zero. */ -#define EXIT_IGNORE_STACK 0 - -/* Epilogue delay slots. */ -#define DELAY_SLOTS_FOR_EPILOGUE arc_delay_slots_for_epilogue () - -#define ELIGIBLE_FOR_EPILOGUE_DELAY(TRIAL, SLOTS_FILLED) \ -arc_eligible_for_epilogue_delay (TRIAL, SLOTS_FILLED) - -/* Output assembler code to FILE to increment profiler label # LABELNO - for profiling a function entry. */ -#define FUNCTION_PROFILER(FILE, LABELNO) - -#define TRAMPOLINE_ALIGNMENT 32 -#define TRAMPOLINE_SIZE 16 - -/* Addressing modes, and classification of registers for them. */ - -/* Maximum number of registers that can appear in a valid memory address. */ -/* The `ld' insn allows 2, but the `st' insn only allows 1. */ -#define MAX_REGS_PER_ADDRESS 1 - -/* We have pre inc/dec (load/store with update). */ -#define HAVE_PRE_INCREMENT 1 -#define HAVE_PRE_DECREMENT 1 - -/* Recognize any constant value that is a valid address. */ -#define CONSTANT_ADDRESS_P(X) \ -(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \ - || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST) - -/* Nonzero if the constant value X is a legitimate general operand. - We can handle any 32- or 64-bit constant. */ -/* "1" should work since the largest constant should be a 64 bit critter. */ -/* ??? Not sure what to do for 64x32 compiler. */ -#define LEGITIMATE_CONSTANT_P(X) 1 - -/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx - and check its validity for a certain class. - We have two alternate definitions for each of them. - The usual definition accepts all pseudo regs; the other rejects - them unless they have been allocated suitable hard regs. - The symbol REG_OK_STRICT causes the latter definition to be used. - - Most source files want to accept pseudo regs in the hope that - they will get allocated to the class that the insn wants them to be in. - Source files for reload pass need to be strict. - After reload, it makes no difference, since pseudo regs have - been eliminated by then. */ - -#ifndef REG_OK_STRICT - -/* Nonzero if X is a hard reg that can be used as an index - or if it is a pseudo reg. */ -#define REG_OK_FOR_INDEX_P(X) \ -((unsigned) REGNO (X) - 32 >= FIRST_PSEUDO_REGISTER - 32) -/* 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) \ -((unsigned) REGNO (X) - 32 >= FIRST_PSEUDO_REGISTER - 32) - -#else - -/* 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)) -/* 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)) - -#endif - -/* 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 `ld' insn allows [reg],[reg+shimm],[reg+limm],[reg+reg],[limm] - but the `st' insn only allows [reg],[reg+shimm],[limm]. - The only thing we can do is only allow the most strict case `st' and hope - other parts optimize out the restrictions for `ld'. */ - -/* local to this file */ -#define RTX_OK_FOR_BASE_P(X) \ -(REG_P (X) && REG_OK_FOR_BASE_P (X)) - -/* local to this file */ -#define RTX_OK_FOR_INDEX_P(X) \ -(0 && /*???*/ REG_P (X) && REG_OK_FOR_INDEX_P (X)) - -/* local to this file */ -/* ??? Loads can handle any constant, stores can only handle small ones. */ -#define RTX_OK_FOR_OFFSET_P(X) \ -(GET_CODE (X) == CONST_INT && SMALL_INT (INTVAL (X))) - -#define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \ -(GET_CODE (X) == PLUS \ - && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \ - && (RTX_OK_FOR_INDEX_P (XEXP (X, 1)) \ - || RTX_OK_FOR_OFFSET_P (XEXP (X, 1)))) - -#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ -{ if (RTX_OK_FOR_BASE_P (X)) \ - goto ADDR; \ - if (LEGITIMATE_OFFSET_ADDRESS_P ((MODE), (X))) \ - goto ADDR; \ - if (GET_CODE (X) == CONST_INT && LARGE_INT (INTVAL (X))) \ - goto ADDR; \ - if (GET_CODE (X) == SYMBOL_REF \ - || GET_CODE (X) == LABEL_REF \ - || GET_CODE (X) == CONST) \ - goto ADDR; \ - if ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == PRE_INC) \ - /* We're restricted here by the `st' insn. */ \ - && RTX_OK_FOR_BASE_P (XEXP ((X), 0))) \ - goto ADDR; \ -} - -/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, - return the mode to be used for the comparison. */ -#define SELECT_CC_MODE(OP, X, Y) \ -arc_select_cc_mode (OP, X, Y) - -/* Return nonzero if SELECT_CC_MODE will never return MODE for a - floating point inequality comparison. */ -#define REVERSIBLE_CC_MODE(MODE) 1 /*???*/ - -/* Costs. */ - -/* Compute extra cost of moving data between one register class - and another. */ -#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) 2 - -/* Compute the cost of moving data between registers and memory. */ -/* Memory is 3 times as expensive as registers. - ??? Is that the right way to look at it? */ -#define MEMORY_MOVE_COST(MODE,CLASS,IN) \ -(GET_MODE_SIZE (MODE) <= UNITS_PER_WORD ? 6 : 12) - -/* The cost of a branch insn. */ -/* ??? What's the right value here? Branches are certainly more - expensive than reg->reg moves. */ -#define BRANCH_COST(speed_p, predictable_p) 2 - -/* Nonzero if access to memory by bytes is slow and undesirable. - For RISC chips, it means that access to memory by bytes is no - better than access by words when possible, so grab a whole word - and maybe make use of that. */ -#define SLOW_BYTE_ACCESS 1 - -/* Define this macro if it is as good or better to call a constant - function address than to call an address kept in a register. */ -/* On the ARC, calling through registers is slow. */ -#define NO_FUNCTION_CSE - -/* Section selection. */ -/* WARNING: These section names also appear in dwarfout.c. */ - -/* The names of the text, data, and readonly-data sections are runtime - selectable. */ - -#define ARC_SECTION_FORMAT "\t.section %s" -#define ARC_DEFAULT_TEXT_SECTION ".text" -#define ARC_DEFAULT_DATA_SECTION ".data" -#define ARC_DEFAULT_RODATA_SECTION ".rodata" - -extern const char *arc_text_section, *arc_data_section, *arc_rodata_section; - -/* initfini.c uses this in an asm. */ -#if defined (CRT_INIT) || defined (CRT_FINI) -#define TEXT_SECTION_ASM_OP "\t.section .text" -#else -#define TEXT_SECTION_ASM_OP arc_text_section -#endif -#define DATA_SECTION_ASM_OP arc_data_section - -#undef READONLY_DATA_SECTION_ASM_OP -#define READONLY_DATA_SECTION_ASM_OP arc_rodata_section - -#define BSS_SECTION_ASM_OP "\t.section .bss" - -/* 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. - This macro is irrelevant if there is no separate readonly data section. */ -/*#define JUMP_TABLES_IN_TEXT_SECTION*/ - -/* For DWARF. Marginally different than default so output is "prettier" - (and consistent with above). */ -#define PUSHSECTION_ASM_OP "\t.section " - -/* Tell crtstuff.c we're using ELF. */ -#define OBJECT_FORMAT_ELF - -/* PIC */ - -/* The register number of the register used to address a table of static - data addresses in memory. In some cases this register is defined by a - processor's ``application binary interface'' (ABI). When this macro - is defined, RTL is generated for this register once, as with the stack - pointer and frame pointer registers. If this macro is not defined, it - is up to the machine-dependent files to allocate such a register (if - necessary). */ -#define PIC_OFFSET_TABLE_REGNUM (flag_pic ? 26 : INVALID_REGNUM) - -/* Define this macro if the register defined by PIC_OFFSET_TABLE_REGNUM is - clobbered by calls. Do not define this macro if PIC_OFFSET_TABLE_REGNUM - is not defined. */ -/* This register is call-saved on the ARC. */ -/*#define PIC_OFFSET_TABLE_REG_CALL_CLOBBERED*/ - -/* A C expression that is nonzero if X is a legitimate immediate - operand on the target machine when generating position independent code. - You can assume that X satisfies CONSTANT_P, so you need not - check this. You can also assume `flag_pic' is true, so you need not - check it either. You need not define this macro if all constants - (including SYMBOL_REF) can be immediate operands when generating - position independent code. */ -/*#define LEGITIMATE_PIC_OPERAND_P(X)*/ - -/* Control the assembler format that we output. */ - -/* A C string constant describing how to begin a comment in the target - assembler language. The compiler assumes that the comment will - end at the end of the line. */ -#define ASM_COMMENT_START ";" - -/* Output to assembler file text saying following lines - may contain character constants, extra white space, comments, etc. */ -#define ASM_APP_ON "" - -/* Output to assembler file text saying following lines - no longer contain unusual constructs. */ -#define ASM_APP_OFF "" - -/* Globalizing directive for a label. */ -#define GLOBAL_ASM_OP "\t.global\t" - -/* This is how to output a reference to a user-level label named NAME. - `assemble_name' uses this. */ -/* We mangle all user labels to provide protection from linking code - compiled for different cpus. */ -/* We work around a dwarfout.c deficiency by watching for labels from it and - not adding the '_' prefix nor the cpu suffix. There is a comment in - dwarfout.c that says it should be using (*targetm.asm_out.internal_label). */ -extern const char *arc_mangle_cpu; -#define ASM_OUTPUT_LABELREF(FILE, NAME) \ -do { \ - if ((NAME)[0] == '.' && (NAME)[1] == 'L') \ - fprintf (FILE, "%s", NAME); \ - else \ - { \ - fputc ('_', FILE); \ - if (TARGET_MANGLE_CPU && arc_mangle_cpu != NULL) \ - fprintf (FILE, "%s_", arc_mangle_cpu); \ - fprintf (FILE, "%s", NAME); \ - } \ -} while (0) - -/* Assembler pseudo-op to equate one value with another. */ -/* ??? This is needed because dwarfout.c provides a default definition too - late for defaults.h (which contains the default definition of ASM_OUTPUT_DEF - that we use). */ -#define SET_ASM_OP "\t.set\t" - -/* How to refer to registers in assembler output. - This sequence is indexed by compiler's hard-register-number (see above). */ -#define REGISTER_NAMES \ -{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \ - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", \ - "r24", "r25", "r26", "fp", "sp", "ilink1", "ilink2", "blink", \ - "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39", \ - "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", \ - "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55", \ - "r56", "r57", "r58", "r59", "lp_count", "cc"} - -/* Entry to the insn conditionalizer. */ -#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \ -arc_final_prescan_insn (INSN, OPVEC, NOPERANDS) - -/* A C expression which evaluates to true if CODE is a valid - punctuation character for use in the `PRINT_OPERAND' macro. */ -extern char arc_punct_chars[256]; -#define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \ -arc_punct_chars[(unsigned char) (CHAR)] - -/* Print operand X (an rtx) in assembler syntax to file FILE. - CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. - For `%' followed by punctuation, CODE is the punctuation and X is null. */ -#define PRINT_OPERAND(FILE, X, CODE) \ -arc_print_operand (FILE, X, CODE) - -/* A C compound statement to output to stdio stream STREAM the - assembler syntax for an instruction operand that is a memory - reference whose address is ADDR. ADDR is an RTL expression. */ -#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ -arc_print_operand_address (FILE, ADDR) - -/* This is how to output an element of a case-vector that is absolute. */ -#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ -do { \ - char label[30]; \ - ASM_GENERATE_INTERNAL_LABEL (label, "L", VALUE); \ - fprintf (FILE, "\t.word %%st("); \ - assemble_name (FILE, label); \ - fprintf (FILE, ")\n"); \ -} while (0) - -/* This is how to output an element of a case-vector that is relative. */ -#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ -do { \ - char label[30]; \ - ASM_GENERATE_INTERNAL_LABEL (label, "L", VALUE); \ - fprintf (FILE, "\t.word %%st("); \ - assemble_name (FILE, label); \ - fprintf (FILE, "-"); \ - ASM_GENERATE_INTERNAL_LABEL (label, "L", REL); \ - assemble_name (FILE, label); \ - fprintf (FILE, ")\n"); \ -} while (0) - -/* The desired alignment for the location counter at the beginning - of a loop. */ -/* On the ARC, align loops to 32 byte boundaries (cache line size) - if -malign-loops. */ -#define LOOP_ALIGN(LABEL) (TARGET_ALIGN_LOOPS ? 5 : 0) - -/* This is how to output an assembler line - that says to advance the location counter - to a multiple of 2**LOG bytes. */ -#define ASM_OUTPUT_ALIGN(FILE,LOG) \ -do { if ((LOG) != 0) fprintf (FILE, "\t.align %d\n", 1 << (LOG)); } while (0) - -/* Debugging information. */ - -/* Generate DBX and DWARF debugging information. */ -#define DBX_DEBUGGING_INFO 1 - -/* Prefer STABS (for now). */ -#undef PREFERRED_DEBUGGING_TYPE -#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG - -/* Turn off splitting of long stabs. */ -#define DBX_CONTIN_LENGTH 0 - -/* Miscellaneous. */ - -/* Specify the machine mode that this machine uses - for the index in the tablejump instruction. */ -#define CASE_VECTOR_MODE Pmode - -/* Define if operations between registers always perform the operation - on the full register even if a narrower mode is specified. */ -#define WORD_REGISTER_OPERATIONS - -/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD - will either zero-extend or sign-extend. The value of this macro should - be the code that says which one of the two operations is implicitly - done, UNKNOWN if none. */ -#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND - -/* Max number of bytes we can move from memory to memory - in one reasonably fast instruction. */ -#define MOVE_MAX 4 - -/* Define this to be nonzero if shift instructions ignore all but the low-order - few bits. */ -#define SHIFT_COUNT_TRUNCATED 1 - -/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits - is done just by pretending it is already truncated. */ -#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 - -/* Specify the machine mode that pointers have. - After generation of rtl, the compiler makes no further distinction - between pointers and any other objects of this machine mode. */ -/* ??? The arc doesn't have full 32-bit pointers, but making this PSImode has - its own problems (you have to add extendpsisi2 and trucnsipsi2 but how does - one do it without getting excess code?). Try to avoid it. */ -#define Pmode SImode - -/* A function address in a call instruction. */ -#define FUNCTION_MODE SImode - -/* alloca should avoid clobbering the old register save area. */ -/* ??? Not defined in tm.texi. */ -#define SETJMP_VIA_SAVE_AREA - -/* ARC function types. */ -enum arc_function_type { - ARC_FUNCTION_UNKNOWN, ARC_FUNCTION_NORMAL, - /* These are interrupt handlers. The name corresponds to the register - name that contains the return address. */ - ARC_FUNCTION_ILINK1, ARC_FUNCTION_ILINK2 -}; -#define ARC_INTERRUPT_P(TYPE) \ -((TYPE) == ARC_FUNCTION_ILINK1 || (TYPE) == ARC_FUNCTION_ILINK2) -/* Compute the type of a function from its DECL. */ diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md deleted file mode 100644 index 09e47daf1d1..00000000000 --- a/gcc/config/arc/arc.md +++ /dev/null @@ -1,1376 +0,0 @@ -;; Machine description of the Argonaut ARC cpu for GNU C compiler -;; Copyright (C) 1994, 1997, 1998, 1999, 2000, 2004, 2005, 2007, 2008 -;; Free Software Foundation, Inc. - -;; This file is part of GCC. - -;; GCC 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 3, or (at your option) -;; any later version. - -;; GCC 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 GCC; see the file COPYING3. If not see -;; <http://www.gnu.org/licenses/>. - -;; See file "rtl.def" for documentation on define_insn, match_*, et. al. - -;; ??? This is an old port, and is undoubtedly suffering from bit rot. - -;; Insn type. Used to default other attribute values. - -(define_attr "type" - "move,load,store,cmove,unary,binary,compare,shift,mul,uncond_branch,branch,call,call_no_delay_slot,multi,misc" - (const_string "binary")) - -;; Length (in # of insns, long immediate constants counted too). -;; ??? There's a nasty interaction between the conditional execution fsm -;; and insn lengths: insns with shimm values cannot be conditionally executed. -(define_attr "length" "" - (cond [(eq_attr "type" "load") - (if_then_else (match_operand 1 "long_immediate_loadstore_operand" "") - (const_int 2) (const_int 1)) - - (eq_attr "type" "store") - (if_then_else (match_operand 0 "long_immediate_loadstore_operand" "") - (const_int 2) (const_int 1)) - - (eq_attr "type" "move,unary,compare") - (if_then_else (match_operand 1 "long_immediate_operand" "") - (const_int 2) (const_int 1)) - - (eq_attr "type" "binary,mul") - (if_then_else (match_operand 2 "long_immediate_operand" "") - (const_int 2) (const_int 1)) - - (eq_attr "type" "cmove") - (if_then_else (match_operand 2 "register_operand" "") - (const_int 1) (const_int 2)) - - (eq_attr "type" "multi") (const_int 2) - ] - - (const_int 1))) - -;; The length here is the length of a single asm. Unfortunately it might be -;; 1 or 2 so we must allow for 2. That's ok though. How often will users -;; lament asm's not being put in delay slots? -(define_asm_attributes - [(set_attr "length" "2") - (set_attr "type" "multi")]) - -;; Condition codes: this one is used by final_prescan_insn to speed up -;; conditionalizing instructions. It saves having to scan the rtl to see if -;; it uses or alters the condition codes. - -;; USE: This insn uses the condition codes (e.g.: a conditional branch). -;; CANUSE: This insn can use the condition codes (for conditional execution). -;; SET: All condition codes are set by this insn. -;; SET_ZN: the Z and N flags are set by this insn. -;; SET_ZNC: the Z, N, and C flags are set by this insn. -;; CLOB: The condition codes are set to unknown values by this insn. -;; NOCOND: This insn can't use and doesn't affect the condition codes. - -(define_attr "cond" "use,canuse,set,set_zn,set_znc,clob,nocond" - (cond [(and (eq_attr "type" "unary,binary,move") - (eq_attr "length" "1")) - (const_string "canuse") - - (eq_attr "type" "compare") - (const_string "set") - - (eq_attr "type" "cmove,branch") - (const_string "use") - - (eq_attr "type" "multi,misc") - (const_string "clob") - ] - - (const_string "nocond"))) - -;; Delay slots. - -(define_attr "in_delay_slot" "false,true" - (cond [(eq_attr "type" "uncond_branch,branch,call,call_no_delay_slot,multi") - (const_string "false") - ] - - (if_then_else (eq_attr "length" "1") - (const_string "true") - (const_string "false")))) - -(define_delay (eq_attr "type" "call") - [(eq_attr "in_delay_slot" "true") - (eq_attr "in_delay_slot" "true") - (eq_attr "in_delay_slot" "true")]) - -(define_delay (eq_attr "type" "branch,uncond_branch") - [(eq_attr "in_delay_slot" "true") - (eq_attr "in_delay_slot" "true") - (eq_attr "in_delay_slot" "true")]) - -;; Scheduling description for the ARC - -(define_cpu_unit "branch") - -(define_insn_reservation "any_insn" 1 (eq_attr "type" "!load,compare,branch") - "nothing") - -;; 1) A conditional jump cannot immediately follow the insn setting the flags. -;; This isn't a complete solution as it doesn't come with guarantees. That -;; is done in the branch patterns and in arc_print_operand. This exists to -;; avoid inserting a nop when we can. - -(define_insn_reservation "compare" 1 (eq_attr "type" "compare") - "nothing,branch") - -(define_insn_reservation "branch" 1 (eq_attr "type" "branch") - "branch") - -;; 2) References to loaded registers should wait a cycle. - -;; Memory with load-delay of 1 (i.e., 2 cycle load). - -(define_insn_reservation "memory" 2 (eq_attr "type" "load") - "nothing") - -;; Move instructions. - -(define_expand "movqi" - [(set (match_operand:QI 0 "general_operand" "") - (match_operand:QI 1 "general_operand" ""))] - "" - " -{ - /* Everything except mem = const or mem = mem can be done easily. */ - - if (GET_CODE (operands[0]) == MEM) - operands[1] = force_reg (QImode, operands[1]); -}") - -(define_insn "*movqi_insn" - [(set (match_operand:QI 0 "move_dest_operand" "=r,r,r,m") - (match_operand:QI 1 "move_src_operand" "rI,Ji,m,r"))] -;; ??? Needed? - "register_operand (operands[0], QImode) - || register_operand (operands[1], QImode)" - "@ - mov%? %0,%1 - mov%? %0,%1 - ldb%U1%V1 %0,%1 - stb%U0%V0 %1,%0" - [(set_attr "type" "move,move,load,store")]) - -;; ??? This may never match since there's no cmpqi insn. - -(define_insn "*movqi_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (sign_extend:SI (match_operand:QI 1 "move_src_operand" "rIJi")) - (const_int 0))) - (set (match_operand:QI 0 "move_dest_operand" "=r") - (match_dup 1))] - "" - "mov%?.f %0,%1" - [(set_attr "type" "move") - (set_attr "cond" "set_zn")]) - -(define_expand "movhi" - [(set (match_operand:HI 0 "general_operand" "") - (match_operand:HI 1 "general_operand" ""))] - "" - " -{ - /* Everything except mem = const or mem = mem can be done easily. */ - - if (GET_CODE (operands[0]) == MEM) - operands[1] = force_reg (HImode, operands[1]); -}") - -(define_insn "*movhi_insn" - [(set (match_operand:HI 0 "move_dest_operand" "=r,r,r,m") - (match_operand:HI 1 "move_src_operand" "rI,Ji,m,r"))] - "register_operand (operands[0], HImode) - || register_operand (operands[1], HImode)" - "@ - mov%? %0,%1 - mov%? %0,%1 - ldw%U1%V1 %0,%1 - stw%U0%V0 %1,%0" - [(set_attr "type" "move,move,load,store")]) - -;; ??? Will this ever match? - -(define_insn "*movhi_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (sign_extend:SI (match_operand:HI 1 "move_src_operand" "rIJi")) - (const_int 0))) - (set (match_operand:HI 0 "move_dest_operand" "=r") - (match_dup 1))] -;; ??? Needed? - "register_operand (operands[0], HImode) - || register_operand (operands[1], HImode)" - "mov%?.f %0,%1" - [(set_attr "type" "move") - (set_attr "cond" "set_zn")]) - -(define_expand "movsi" - [(set (match_operand:SI 0 "general_operand" "") - (match_operand:SI 1 "general_operand" ""))] - "" - " -{ - /* Everything except mem = const or mem = mem can be done easily. */ - - if (GET_CODE (operands[0]) == MEM) - operands[1] = force_reg (SImode, operands[1]); -}") - -(define_insn "*movsi_insn" - [(set (match_operand:SI 0 "move_dest_operand" "=r,r,r,m") - (match_operand:SI 1 "move_src_operand" "rI,GJi,m,r"))] - "register_operand (operands[0], SImode) - || register_operand (operands[1], SImode)" - "@ - mov%? %0,%1 - mov%? %0,%S1 - ld%U1%V1 %0,%1 - st%U0%V0 %1,%0" - [(set_attr "type" "move,move,load,store")]) - -(define_insn "*movsi_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (match_operand:SI 1 "move_src_operand" "rIJi") - (const_int 0))) - (set (match_operand:SI 0 "move_dest_operand" "=r") - (match_dup 1))] - "register_operand (operands[0], SImode) - || register_operand (operands[1], SImode)" - "mov%?.f %0,%S1" - [(set_attr "type" "move") - (set_attr "cond" "set_zn")]) - -(define_expand "movdi" - [(set (match_operand:DI 0 "general_operand" "") - (match_operand:DI 1 "general_operand" ""))] - "" - " -{ - /* Everything except mem = const or mem = mem can be done easily. */ - - if (GET_CODE (operands[0]) == MEM) - operands[1] = force_reg (DImode, operands[1]); -}") - -(define_insn "*movdi_insn" - [(set (match_operand:DI 0 "move_dest_operand" "=r,r,r,m") - (match_operand:DI 1 "move_double_src_operand" "r,HK,m,r"))] - "register_operand (operands[0], DImode) - || register_operand (operands[1], DImode)" - "* -{ - switch (which_alternative) - { - case 0 : - /* We normally copy the low-numbered register first. However, if - the first register operand 0 is the same as the second register of - operand 1, we must copy in the opposite order. */ - if (REGNO (operands[0]) == REGNO (operands[1]) + 1) - return \"mov %R0,%R1\;mov %0,%1\"; - else - return \"mov %0,%1\;mov %R0,%R1\"; - case 1 : - return \"mov %0,%L1\;mov %R0,%H1\"; - case 2 : - /* If the low-address word is used in the address, we must load it - last. Otherwise, load it first. Note that we cannot have - auto-increment in that case since the address register is known to be - dead. */ - if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1, - operands [1], 0)) - return \"ld%V1 %R0,%R1\;ld%V1 %0,%1\"; - else - return \"ld%V1 %0,%1\;ld%V1 %R0,%R1\"; - case 3 : - return \"st%V0 %1,%0\;st%V0 %R1,%R0\"; - default: - gcc_unreachable (); - } -}" - [(set_attr "type" "move,move,load,store") - ;; ??? The ld/st values could be 4 if it's [reg,bignum]. - (set_attr "length" "2,4,2,2")]) - -;(define_expand "movdi" -; [(set (match_operand:DI 0 "general_operand" "") -; (match_operand:DI 1 "general_operand" ""))] -; "" -; " -;{ -; /* Flow doesn't understand that this is effectively a DFmode move. -; It doesn't know that all of `operands[0]' is set. */ -; emit_clobber (operands[0]); -; -; /* Emit insns that movsi_insn can handle. */ -; emit_insn (gen_movsi (operand_subword (operands[0], 0, 0, DImode), -; operand_subword (operands[1], 0, 0, DImode))); -; emit_insn (gen_movsi (operand_subword (operands[0], 1, 0, DImode), -; operand_subword (operands[1], 1, 0, DImode))); -; DONE; -;}") - -;; Floating point move insns. - -(define_expand "movsf" - [(set (match_operand:SF 0 "general_operand" "") - (match_operand:SF 1 "general_operand" ""))] - "" - " -{ - /* Everything except mem = const or mem = mem can be done easily. */ - if (GET_CODE (operands[0]) == MEM) - operands[1] = force_reg (SFmode, operands[1]); -}") - -(define_insn "*movsf_insn" - [(set (match_operand:SF 0 "move_dest_operand" "=r,r,r,m") - (match_operand:SF 1 "move_src_operand" "r,E,m,r"))] - "register_operand (operands[0], SFmode) - || register_operand (operands[1], SFmode)" - "@ - mov%? %0,%1 - mov%? %0,%1 ; %A1 - ld%U1%V1 %0,%1 - st%U0%V0 %1,%0" - [(set_attr "type" "move,move,load,store")]) - -(define_expand "movdf" - [(set (match_operand:DF 0 "general_operand" "") - (match_operand:DF 1 "general_operand" ""))] - "" - " -{ - /* Everything except mem = const or mem = mem can be done easily. */ - if (GET_CODE (operands[0]) == MEM) - operands[1] = force_reg (DFmode, operands[1]); -}") - -(define_insn "*movdf_insn" - [(set (match_operand:DF 0 "move_dest_operand" "=r,r,r,m") - (match_operand:DF 1 "move_double_src_operand" "r,E,m,r"))] - "register_operand (operands[0], DFmode) - || register_operand (operands[1], DFmode)" - "* -{ - switch (which_alternative) - { - case 0 : - /* We normally copy the low-numbered register first. However, if - the first register operand 0 is the same as the second register of - operand 1, we must copy in the opposite order. */ - if (REGNO (operands[0]) == REGNO (operands[1]) + 1) - return \"mov %R0,%R1\;mov %0,%1\"; - else - return \"mov %0,%1\;mov %R0,%R1\"; - case 1 : - return \"mov %0,%L1\;mov %R0,%H1 ; %A1\"; - case 2 : - /* If the low-address word is used in the address, we must load it - last. Otherwise, load it first. Note that we cannot have - auto-increment in that case since the address register is known to be - dead. */ - if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1, - operands [1], 0)) - return \"ld%V1 %R0,%R1\;ld%V1 %0,%1\"; - else - return \"ld%V1 %0,%1\;ld%V1 %R0,%R1\"; - case 3 : - return \"st%V0 %1,%0\;st%V0 %R1,%R0\"; - default: - gcc_unreachable (); - } -}" - [(set_attr "type" "move,move,load,store") - ;; ??? The ld/st values could be 4 if it's [reg,bignum]. - (set_attr "length" "2,4,2,2")]) - -;(define_expand "movdf" -; [(set (match_operand:DF 0 "general_operand" "") -; (match_operand:DF 1 "general_operand" ""))] -; "" -; " -;{ -; /* Flow doesn't understand that this is effectively a DFmode move. -; It doesn't know that all of `operands[0]' is set. */ -; emit_clobber (operands[0]); -; -; /* Emit insns that movsi_insn can handle. */ -; emit_insn (gen_movsi (operand_subword (operands[0], 0, 0, DFmode), -; operand_subword (operands[1], 0, 0, DFmode))); -; emit_insn (gen_movsi (operand_subword (operands[0], 1, 0, DFmode), -; operand_subword (operands[1], 1, 0, DFmode))); -; DONE; -;}") - -;; Load/Store with update instructions. -;; -;; Some of these we can get by using pre-decrement or pre-increment, but the -;; hardware can also do cases where the increment is not the size of the -;; object. -;; -;; In all these cases, we use operands 0 and 1 for the register being -;; incremented because those are the operands that local-alloc will -;; tie and these are the pair most likely to be tieable (and the ones -;; that will benefit the most). -;; -;; We use match_operator here because we need to know whether the memory -;; object is volatile or not. - -(define_insn "*loadqi_update" - [(set (match_operand:QI 3 "register_operand" "=r,r") - (match_operator:QI 4 "load_update_operand" - [(match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "rI,J")])) - (set (match_operand:SI 0 "register_operand" "=r,r") - (plus:SI (match_dup 1) (match_dup 2)))] - "" - "ldb.a%V4 %3,[%0,%2]" - [(set_attr "type" "load,load") - (set_attr "length" "1,2")]) - -(define_insn "*load_zeroextendqisi_update" - [(set (match_operand:SI 3 "register_operand" "=r,r") - (zero_extend:SI (match_operator:QI 4 "load_update_operand" - [(match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "rI,J")]))) - (set (match_operand:SI 0 "register_operand" "=r,r") - (plus:SI (match_dup 1) (match_dup 2)))] - "" - "ldb.a%V4 %3,[%0,%2]" - [(set_attr "type" "load,load") - (set_attr "length" "1,2")]) - -(define_insn "*load_signextendqisi_update" - [(set (match_operand:SI 3 "register_operand" "=r,r") - (sign_extend:SI (match_operator:QI 4 "load_update_operand" - [(match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "rI,J")]))) - (set (match_operand:SI 0 "register_operand" "=r,r") - (plus:SI (match_dup 1) (match_dup 2)))] - "" - "ldb.x.a%V4 %3,[%0,%2]" - [(set_attr "type" "load,load") - (set_attr "length" "1,2")]) - -(define_insn "*storeqi_update" - [(set (match_operator:QI 4 "store_update_operand" - [(match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "short_immediate_operand" "I")]) - (match_operand:QI 3 "register_operand" "r")) - (set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (match_dup 1) (match_dup 2)))] - "" - "stb.a%V4 %3,[%0,%2]" - [(set_attr "type" "store") - (set_attr "length" "1")]) - -(define_insn "*loadhi_update" - [(set (match_operand:HI 3 "register_operand" "=r,r") - (match_operator:HI 4 "load_update_operand" - [(match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "rI,J")])) - (set (match_operand:SI 0 "register_operand" "=r,r") - (plus:SI (match_dup 1) (match_dup 2)))] - "" - "ldw.a%V4 %3,[%0,%2]" - [(set_attr "type" "load,load") - (set_attr "length" "1,2")]) - -(define_insn "*load_zeroextendhisi_update" - [(set (match_operand:SI 3 "register_operand" "=r,r") - (zero_extend:SI (match_operator:HI 4 "load_update_operand" - [(match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "rI,J")]))) - (set (match_operand:SI 0 "register_operand" "=r,r") - (plus:SI (match_dup 1) (match_dup 2)))] - "" - "ldw.a%V4 %3,[%0,%2]" - [(set_attr "type" "load,load") - (set_attr "length" "1,2")]) - -(define_insn "*load_signextendhisi_update" - [(set (match_operand:SI 3 "register_operand" "=r,r") - (sign_extend:SI (match_operator:HI 4 "load_update_operand" - [(match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "rI,J")]))) - (set (match_operand:SI 0 "register_operand" "=r,r") - (plus:SI (match_dup 1) (match_dup 2)))] - "" - "ldw.x.a%V4 %3,[%0,%2]" - [(set_attr "type" "load,load") - (set_attr "length" "1,2")]) - -(define_insn "*storehi_update" - [(set (match_operator:HI 4 "store_update_operand" - [(match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "short_immediate_operand" "I")]) - (match_operand:HI 3 "register_operand" "r")) - (set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (match_dup 1) (match_dup 2)))] - "" - "stw.a%V4 %3,[%0,%2]" - [(set_attr "type" "store") - (set_attr "length" "1")]) - -(define_insn "*loadsi_update" - [(set (match_operand:SI 3 "register_operand" "=r,r") - (match_operator:SI 4 "load_update_operand" - [(match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "rI,J")])) - (set (match_operand:SI 0 "register_operand" "=r,r") - (plus:SI (match_dup 1) (match_dup 2)))] - "" - "ld.a%V4 %3,[%0,%2]" - [(set_attr "type" "load,load") - (set_attr "length" "1,2")]) - -(define_insn "*storesi_update" - [(set (match_operator:SI 4 "store_update_operand" - [(match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "short_immediate_operand" "I")]) - (match_operand:SI 3 "register_operand" "r")) - (set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (match_dup 1) (match_dup 2)))] - "" - "st.a%V4 %3,[%0,%2]" - [(set_attr "type" "store") - (set_attr "length" "1")]) - -(define_insn "*loadsf_update" - [(set (match_operand:SF 3 "register_operand" "=r,r") - (match_operator:SF 4 "load_update_operand" - [(match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "rI,J")])) - (set (match_operand:SI 0 "register_operand" "=r,r") - (plus:SI (match_dup 1) (match_dup 2)))] - "" - "ld.a%V4 %3,[%0,%2]" - [(set_attr "type" "load,load") - (set_attr "length" "1,2")]) - -(define_insn "*storesf_update" - [(set (match_operator:SF 4 "store_update_operand" - [(match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "short_immediate_operand" "I")]) - (match_operand:SF 3 "register_operand" "r")) - (set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (match_dup 1) (match_dup 2)))] - "" - "st.a%V4 %3,[%0,%2]" - [(set_attr "type" "store") - (set_attr "length" "1")]) - -;; Conditional move instructions. - -(define_expand "movsicc" - [(set (match_operand:SI 0 "register_operand" "") - (if_then_else:SI (match_operand 1 "comparison_operator" "") - (match_operand:SI 2 "nonmemory_operand" "") - (match_operand:SI 3 "register_operand" "")))] - "" - " -{ - enum rtx_code code = GET_CODE (operands[1]); - rtx cc_reg = gen_compare_reg (code, XEXP (operands[1], 0), - XEXP (operands[1], 1)); - operands[1] = gen_rtx_fmt_ee (code, VOIDmode, cc_reg, const0_rtx); -}") - -(define_expand "movsfcc" - [(set (match_operand:SF 0 "register_operand" "") - (if_then_else:SF (match_operand 1 "comparison_operator" "") - (match_operand:SF 2 "nonmemory_operand" "") - (match_operand:SF 3 "register_operand" "")))] - "" - " -{ - enum rtx_code code = GET_CODE (operands[1]); - rtx cc_reg = gen_compare_reg (code, XEXP (operands[1], 0), - XEXP (operands[1], 1)); - operands[1] = gen_rtx_fmt_ee (code, VOIDmode, cc_reg, const0_rtx); -}") - -(define_insn "*movsicc_insn" - [(set (match_operand:SI 0 "register_operand" "=r") - (if_then_else:SI (match_operand 1 "comparison_operator" "") - (match_operand:SI 2 "nonmemory_operand" "rJi") - (match_operand:SI 3 "register_operand" "0")))] - "" - "mov.%d1 %0,%S2" - [(set_attr "type" "cmove")]) - -(define_insn "*movsfcc_insn" - [(set (match_operand:SF 0 "register_operand" "=r,r") - (if_then_else:SF (match_operand 1 "comparison_operator" "") - (match_operand:SF 2 "nonmemory_operand" "r,E") - (match_operand:SF 3 "register_operand" "0,0")))] - "" - "@ - mov.%d1 %0,%2 - mov.%d1 %0,%2 ; %A2" - [(set_attr "type" "cmove,cmove")]) - - -;; Zero extension instructions. -;; ??? We don't support volatile memrefs here, but I'm not sure why. - -(define_insn "zero_extendqihi2" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (zero_extend:HI (match_operand:QI 1 "nonvol_nonimm_operand" "r,m")))] - "" - "@ - extb%? %0,%1 - ldb%U1 %0,%1" - [(set_attr "type" "unary,load")]) - -(define_insn "*zero_extendqihi2_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (zero_extend:SI (match_operand:QI 1 "register_operand" "r")) - (const_int 0))) - (set (match_operand:HI 0 "register_operand" "=r") - (zero_extend:HI (match_dup 1)))] - "" - "extb%?.f %0,%1" - [(set_attr "type" "unary") - (set_attr "cond" "set_zn")]) - -(define_insn "zero_extendqisi2" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (zero_extend:SI (match_operand:QI 1 "nonvol_nonimm_operand" "r,m")))] - "" - "@ - extb%? %0,%1 - ldb%U1 %0,%1" - [(set_attr "type" "unary,load")]) - -(define_insn "*zero_extendqisi2_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (zero_extend:SI (match_operand:QI 1 "register_operand" "r")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (zero_extend:SI (match_dup 1)))] - "" - "extb%?.f %0,%1" - [(set_attr "type" "unary") - (set_attr "cond" "set_zn")]) - -(define_insn "zero_extendhisi2" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (zero_extend:SI (match_operand:HI 1 "nonvol_nonimm_operand" "r,m")))] - "" - "@ - extw%? %0,%1 - ldw%U1 %0,%1" - [(set_attr "type" "unary,load")]) - -(define_insn "*zero_extendhisi2_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (zero_extend:SI (match_operand:HI 1 "register_operand" "r")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (zero_extend:SI (match_dup 1)))] - "" - "extw%?.f %0,%1" - [(set_attr "type" "unary") - (set_attr "cond" "set_zn")]) - -;; Sign extension instructions. - -(define_insn "extendqihi2" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (sign_extend:HI (match_operand:QI 1 "nonvol_nonimm_operand" "r,m")))] - "" - "@ - sexb%? %0,%1 - ldb.x%U1 %0,%1" - [(set_attr "type" "unary,load")]) - -(define_insn "*extendqihi2_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (sign_extend:SI (match_operand:QI 1 "register_operand" "r")) - (const_int 0))) - (set (match_operand:HI 0 "register_operand" "=r") - (sign_extend:HI (match_dup 1)))] - "" - "sexb%?.f %0,%1" - [(set_attr "type" "unary") - (set_attr "cond" "set_zn")]) - -(define_insn "extendqisi2" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (sign_extend:SI (match_operand:QI 1 "nonvol_nonimm_operand" "r,m")))] - "" - "@ - sexb%? %0,%1 - ldb.x%U1 %0,%1" - [(set_attr "type" "unary,load")]) - -(define_insn "*extendqisi2_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (sign_extend:SI (match_operand:QI 1 "register_operand" "r")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (sign_extend:SI (match_dup 1)))] - "" - "sexb%?.f %0,%1" - [(set_attr "type" "unary") - (set_attr "cond" "set_zn")]) - -(define_insn "extendhisi2" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (sign_extend:SI (match_operand:HI 1 "nonvol_nonimm_operand" "r,m")))] - "" - "@ - sexw%? %0,%1 - ldw.x%U1 %0,%1" - [(set_attr "type" "unary,load")]) - -(define_insn "*extendhisi2_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (sign_extend:SI (match_operand:HI 1 "register_operand" "r")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (sign_extend:SI (match_dup 1)))] - "" - "sexw%?.f %0,%1" - [(set_attr "type" "unary") - (set_attr "cond" "set_zn")]) - -;; Arithmetic instructions. - -(define_insn "addsi3" - [(set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (match_operand:SI 1 "register_operand" "%r") - (match_operand:SI 2 "nonmemory_operand" "rIJ")))] - "" - "add%? %0,%1,%2") - -(define_insn "*addsi3_set_cc_insn" - [(set (reg:CC 61) (compare:CC - (plus:SI (match_operand:SI 1 "register_operand" "%r") - (match_operand:SI 2 "nonmemory_operand" "rIJ")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (match_dup 1) - (match_dup 2)))] - "" - "add%?.f %0,%1,%2" - [(set_attr "cond" "set")]) - -(define_insn "adddi3" - [(set (match_operand:DI 0 "register_operand" "=r") - (plus:DI (match_operand:DI 1 "nonmemory_operand" "%r") - (match_operand:DI 2 "nonmemory_operand" "ri"))) - (clobber (reg:CC 61))] - "" - "* -{ - rtx op2 = operands[2]; - - if (GET_CODE (op2) == CONST_INT) - { - int sign = INTVAL (op2); - if (sign < 0) - return \"add.f %L0,%L1,%2\;adc %H0,%H1,-1\"; - else - return \"add.f %L0,%L1,%2\;adc %H0,%H1,0\"; - } - else - return \"add.f %L0,%L1,%L2\;adc %H0,%H1,%H2\"; -}" - [(set_attr "length" "2")]) - -(define_insn "subsi3" - [(set (match_operand:SI 0 "register_operand" "=r") - (minus:SI (match_operand:SI 1 "register_operand" "r") - (match_operand:SI 2 "nonmemory_operand" "rIJ")))] - "" - "sub%? %0,%1,%2") - -(define_insn "*subsi3_set_cc_insn" - [(set (reg:CC 61) (compare:CC - (minus:SI (match_operand:SI 1 "register_operand" "%r") - (match_operand:SI 2 "nonmemory_operand" "rIJ")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (minus:SI (match_dup 1) - (match_dup 2)))] - "" - "sub%?.f %0,%1,%2" - [(set_attr "cond" "set")]) - -(define_insn "subdi3" - [(set (match_operand:DI 0 "register_operand" "=r") - (minus:DI (match_operand:DI 1 "nonmemory_operand" "r") - (match_operand:DI 2 "nonmemory_operand" "ri"))) - (clobber (reg:CC 61))] - "" - "* -{ - rtx op2 = operands[2]; - - if (GET_CODE (op2) == CONST_INT) - { - int sign = INTVAL (op2); - if (sign < 0) - return \"sub.f %L0,%L1,%2\;sbc %H0,%H1,-1\"; - else - return \"sub.f %L0,%L1,%2\;sbc %H0,%H1,0\"; - } - else - return \"sub.f %L0,%L1,%L2\;sbc %H0,%H1,%H2\"; -}" - [(set_attr "length" "2")]) - -;; Boolean instructions. -;; -;; We don't define the DImode versions as expand_binop does a good enough job. - -(define_insn "andsi3" - [(set (match_operand:SI 0 "register_operand" "=r") - (and:SI (match_operand:SI 1 "register_operand" "%r") - (match_operand:SI 2 "nonmemory_operand" "rIJ")))] - "" - "and%? %0,%1,%2") - -(define_insn "*andsi3_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (and:SI (match_operand:SI 1 "register_operand" "%r") - (match_operand:SI 2 "nonmemory_operand" "rIJ")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (and:SI (match_dup 1) - (match_dup 2)))] - "" - "and%?.f %0,%1,%2" - [(set_attr "cond" "set_zn")]) - -(define_insn "*bicsi3_insn" - [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") - (and:SI (match_operand:SI 1 "nonmemory_operand" "r,r,I,J") - (not:SI (match_operand:SI 2 "nonmemory_operand" "rI,J,r,r"))))] - "" - "bic%? %0,%1,%2" - [(set_attr "length" "1,2,1,2")]) - -(define_insn "*bicsi3_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (and:SI (match_operand:SI 1 "register_operand" "%r") - (not:SI (match_operand:SI 2 "nonmemory_operand" "rIJ"))) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (and:SI (match_dup 1) - (not:SI (match_dup 2))))] - "" - "bic%?.f %0,%1,%2" - [(set_attr "cond" "set_zn")]) - -(define_insn "iorsi3" - [(set (match_operand:SI 0 "register_operand" "=r") - (ior:SI (match_operand:SI 1 "register_operand" "%r") - (match_operand:SI 2 "nonmemory_operand" "rIJ")))] - "" - "or%? %0,%1,%2") - -(define_insn "*iorsi3_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (ior:SI (match_operand:SI 1 "register_operand" "%r") - (match_operand:SI 2 "nonmemory_operand" "rIJ")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (ior:SI (match_dup 1) - (match_dup 2)))] - "" - "or%?.f %0,%1,%2" - [(set_attr "cond" "set_zn")]) - -(define_insn "xorsi3" - [(set (match_operand:SI 0 "register_operand" "=r") - (xor:SI (match_operand:SI 1 "register_operand" "%r") - (match_operand:SI 2 "nonmemory_operand" "rIJ")))] - "" - "xor%? %0,%1,%2") - -(define_insn "*xorsi3_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (xor:SI (match_operand:SI 1 "register_operand" "%r") - (match_operand:SI 2 "nonmemory_operand" "rIJ")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (xor:SI (match_dup 1) - (match_dup 2)))] - "" - "xor%?.f %0,%1,%2" - [(set_attr "cond" "set_zn")]) - -(define_insn "negsi2" - [(set (match_operand:SI 0 "register_operand" "=r") - (neg:SI (match_operand:SI 1 "register_operand" "r")))] - "" - "sub%? %0,0,%1" - [(set_attr "type" "unary")]) - -(define_insn "*negsi2_set_cc_insn" - [(set (reg:CC 61) (compare:CC - (neg:SI (match_operand:SI 1 "register_operand" "r")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (neg:SI (match_dup 1)))] - "" - "sub%?.f %0,0,%1" - [(set_attr "type" "unary") - (set_attr "cond" "set")]) - -(define_insn "negdi2" - [(set (match_operand:DI 0 "register_operand" "=r") - (neg:DI (match_operand:DI 1 "register_operand" "r"))) - (clobber (reg:SI 61))] - "" - "sub.f %L0,0,%L1\;sbc %H0,0,%H1" - [(set_attr "type" "unary") - (set_attr "length" "2")]) - -(define_insn "one_cmplsi2" - [(set (match_operand:SI 0 "register_operand" "=r") - (not:SI (match_operand:SI 1 "register_operand" "r")))] - "" - "xor%? %0,%1,-1" - [(set_attr "type" "unary")]) - -(define_insn "*one_cmplsi2_set_cc_insn" - [(set (reg:CCZN 61) (compare:CCZN - (not:SI (match_operand:SI 1 "register_operand" "r")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (not:SI (match_dup 1)))] - "" - "xor%?.f %0,%1,-1" - [(set_attr "type" "unary") - (set_attr "cond" "set_zn")]) - -;; Shift instructions. - -(define_expand "ashlsi3" - [(set (match_operand:SI 0 "register_operand" "") - (ashift:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "nonmemory_operand" "")))] - "" - " -{ - if (! TARGET_SHIFTER) - { - emit_insn (gen_rtx_PARALLEL - (VOIDmode, - gen_rtvec (2, - gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_ASHIFT (SImode, operands[1], - operands[2])), - gen_rtx_CLOBBER (VOIDmode, - gen_rtx_SCRATCH (SImode))))); - DONE; - } -}") - -(define_expand "ashrsi3" - [(set (match_operand:SI 0 "register_operand" "") - (ashiftrt:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "nonmemory_operand" "")))] - "" - " -{ - if (! TARGET_SHIFTER) - { - emit_insn (gen_rtx_PARALLEL - (VOIDmode, - gen_rtvec (2, - gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_ASHIFTRT (SImode, - operands[1], - operands[2])), - gen_rtx_CLOBBER (VOIDmode, - gen_rtx_SCRATCH (SImode))))); - DONE; - } -}") - -(define_expand "lshrsi3" - [(set (match_operand:SI 0 "register_operand" "") - (lshiftrt:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "nonmemory_operand" "")))] - "" - " -{ - if (! TARGET_SHIFTER) - { - emit_insn (gen_rtx_PARALLEL - (VOIDmode, - gen_rtvec (2, - gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_LSHIFTRT (SImode, - operands[1], - operands[2])), - gen_rtx_CLOBBER (VOIDmode, - gen_rtx_SCRATCH (SImode))))); - DONE; - } -}") - -(define_insn "*ashlsi3_insn" - [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") - (ashift:SI (match_operand:SI 1 "nonmemory_operand" "r,r,I,J") - (match_operand:SI 2 "nonmemory_operand" "rI,J,r,r")))] - "TARGET_SHIFTER" - "asl%? %0,%1,%2" - [(set_attr "type" "shift") - (set_attr "length" "1,2,1,2")]) - -(define_insn "*ashrsi3_insn" - [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") - (ashiftrt:SI (match_operand:SI 1 "nonmemory_operand" "r,r,I,J") - (match_operand:SI 2 "nonmemory_operand" "rI,J,r,r")))] - "TARGET_SHIFTER" - "asr%? %0,%1,%2" - [(set_attr "type" "shift") - (set_attr "length" "1,2,1,2")]) - -(define_insn "*lshrsi3_insn" - [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") - (lshiftrt:SI (match_operand:SI 1 "nonmemory_operand" "r,r,I,J") - (match_operand:SI 2 "nonmemory_operand" "rI,J,r,r")))] - "TARGET_SHIFTER" - "lsr%? %0,%1,%2" - [(set_attr "type" "shift") - (set_attr "length" "1,2,1,2")]) - -(define_insn "*shift_si3" - [(set (match_operand:SI 0 "register_operand" "=r") - (match_operator:SI 3 "shift_operator" - [(match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "nonmemory_operand" "rIJ")])) - (clobber (match_scratch:SI 4 "=&r"))] - "! TARGET_SHIFTER" - "* return output_shift (operands);" - [(set_attr "type" "shift") - (set_attr "length" "8")]) - -;; Compare instructions. -;; This controls RTL generation and register allocation. - -;; ??? We may be able to relax this a bit by adding a new constant 'K' for 0. -;; This assumes sub.f 0,symbol,0 is a valid insn. -;; Note that "sub.f 0,r0,1" is an 8 byte insn. To avoid unnecessarily -;; creating 8 byte insns we duplicate %1 in the destination reg of the insn -;; if it's a small constant. - -(define_insn "*cmpsi_cc_insn" - [(set (reg:CC 61) - (compare:CC (match_operand:SI 0 "register_operand" "r,r,r") - (match_operand:SI 1 "nonmemory_operand" "r,I,J")))] - "" - "@ - sub.f 0,%0,%1 - sub.f %1,%0,%1 - sub.f 0,%0,%1" - [(set_attr "type" "compare,compare,compare")]) - -(define_insn "*cmpsi_cczn_insn" - [(set (reg:CCZN 61) - (compare:CCZN (match_operand:SI 0 "register_operand" "r,r,r") - (match_operand:SI 1 "nonmemory_operand" "r,I,J")))] - "" - "@ - sub.f 0,%0,%1 - sub.f %1,%0,%1 - sub.f 0,%0,%1" - [(set_attr "type" "compare,compare,compare")]) - -(define_insn "*cmpsi_ccznc_insn" - [(set (reg:CCZNC 61) - (compare:CCZNC (match_operand:SI 0 "register_operand" "r,r,r") - (match_operand:SI 1 "nonmemory_operand" "r,I,J")))] - "" - "@ - sub.f 0,%0,%1 - sub.f %1,%0,%1 - sub.f 0,%0,%1" - [(set_attr "type" "compare,compare,compare")]) - -;; Next come the scc insn and its expander. - -(define_expand "cstoresi4" - [(set (match_dup 4) - (match_op_dup 5 - [(match_operand:SI 2 "register_operand" "") - (match_operand:SI 3 "nonmemory_operand" "")])) - (set (match_operand:SI 0 "register_operand") - (match_operator:SI 1 "ordered_comparison_operator" - [(match_dup 4) - (const_int 0)]))] - "" - " -{ - operands[4] = gen_compare_reg (GET_CODE (operands[1]), - operands[2], operands[3]); - operands[5] = gen_rtx_fmt_ee (COMPARE, - GET_MODE (operands[4]), - operands[2], operands[3]); -}") - -(define_insn "*scc_insn" - [(set (match_operand:SI 0 "register_operand" "=r") - (match_operator:SI 1 "comparison_operator" [(reg 61) (const_int 0)]))] - "" - "mov %0,1\;sub.%D1 %0,%0,%0" - [(set_attr "type" "unary") - (set_attr "length" "2")]) - -;; ??? Look up negscc insn. See pa.md for example. -(define_insn "*neg_scc_insn" - [(set (match_operand:SI 0 "register_operand" "=r") - (neg:SI (match_operator:SI 1 "comparison_operator" - [(reg 61) (const_int 0)])))] - "" - "mov %0,-1\;sub.%D1 %0,%0,%0" - [(set_attr "type" "unary") - (set_attr "length" "2")]) - -(define_insn "*not_scc_insn" - [(set (match_operand:SI 0 "register_operand" "=r") - (not:SI (match_operator:SI 1 "comparison_operator" - [(reg 61) (const_int 0)])))] - "" - "mov %0,1\;sub.%d1 %0,%0,%0" - [(set_attr "type" "unary") - (set_attr "length" "2")]) - -;; These control RTL generation for conditional jump insns - -(define_expand "cbranchsi4" - [(set (match_dup 4) - (match_op_dup 5 - [(match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "nonmemory_operand" "")])) - (set (pc) - (if_then_else - (match_operator 0 "ordered_comparison_operator" - [(match_dup 4) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "" - " -{ - operands[4] = gen_compare_reg (GET_CODE (operands[0]), - operands[1], operands[2]); - operands[5] = gen_rtx_fmt_ee (COMPARE, - GET_MODE (operands[4]), - operands[1], operands[2]); -}") - -;; Now match both normal and inverted jump. - -(define_insn "*branch_insn" - [(set (pc) - (if_then_else (match_operator 1 "proper_comparison_operator" - [(reg 61) (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "* -{ - if (arc_ccfsm_branch_deleted_p ()) - { - arc_ccfsm_record_branch_deleted (); - return \"; branch deleted, next insns conditionalized\"; - } - else - return \"%~b%d1%# %l0\"; -}" - [(set_attr "type" "branch")]) - -(define_insn "*rev_branch_insn" - [(set (pc) - (if_then_else (match_operator 1 "proper_comparison_operator" - [(reg 61) (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "REVERSIBLE_CC_MODE (GET_MODE (XEXP (operands[1], 0)))" - "* -{ - if (arc_ccfsm_branch_deleted_p ()) - { - arc_ccfsm_record_branch_deleted (); - return \"; branch deleted, next insns conditionalized\"; - } - else - return \"%~b%D1%# %l0\"; -}" - [(set_attr "type" "branch")]) - -;; Unconditional and other jump instructions. - -(define_insn "jump" - [(set (pc) (label_ref (match_operand 0 "" "")))] - "" - "b%* %l0" - [(set_attr "type" "uncond_branch")]) - -(define_insn "indirect_jump" - [(set (pc) (match_operand:SI 0 "address_operand" "p"))] - "" - "j%* %a0" - [(set_attr "type" "uncond_branch")]) - -;; Implement a switch statement. -;; This wouldn't be necessary in the non-pic case if we could distinguish -;; label refs of the jump table from other label refs. The problem is that -;; label refs are output as "%st(.LL42)" but we don't want the %st - we want -;; the real address since it's the address of the table. - -(define_expand "casesi" - [(set (match_dup 5) - (minus:SI (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "nonmemory_operand" ""))) - (set (reg:CC 61) - (compare:CC (match_dup 5) - (match_operand:SI 2 "nonmemory_operand" ""))) - (set (pc) - (if_then_else (gtu (reg:CC 61) - (const_int 0)) - (label_ref (match_operand 4 "" "")) - (pc))) - (parallel - [(set (pc) - (mem:SI (plus:SI (mult:SI (match_dup 5) - (const_int 4)) - (label_ref (match_operand 3 "" ""))))) - (clobber (match_scratch:SI 6 "")) - (clobber (match_scratch:SI 7 ""))])] - "" - " -{ - operands[5] = gen_reg_rtx (SImode); -}") - -(define_insn "*casesi_insn" - [(set (pc) - (mem:SI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "r") - (const_int 4)) - (label_ref (match_operand 1 "" ""))))) - (clobber (match_scratch:SI 2 "=r")) - (clobber (match_scratch:SI 3 "=r"))] - "" - "* -{ - output_asm_insn (\"mov %2,%1\", operands); - if (TARGET_SHIFTER) - output_asm_insn (\"asl %3,%0,2\", operands); - else - output_asm_insn (\"asl %3,%0\;asl %3,%3\", operands); - output_asm_insn (\"ld %2,[%2,%3]\", operands); - output_asm_insn (\"j.nd %a2\", operands); - return \"\"; -}" - [(set_attr "type" "uncond_branch") - (set_attr "length" "6")]) - -(define_insn "tablejump" - [(set (pc) (match_operand:SI 0 "address_operand" "p")) - (use (label_ref (match_operand 1 "" "")))] - "0 /* disabled -> using casesi now */" - "j%* %a0" - [(set_attr "type" "uncond_branch")]) - -(define_expand "call" - ;; operands[1] is stack_size_rtx - ;; operands[2] is next_arg_register - [(parallel [(call (match_operand:SI 0 "call_operand" "") - (match_operand 1 "" "")) - (clobber (reg:SI 31))])] - "" - "") - -(define_insn "*call_via_reg" - [(call (mem:SI (match_operand:SI 0 "register_operand" "r")) - (match_operand 1 "" "")) - (clobber (reg:SI 31))] - "" - "lr blink,[status]\;j.d %0\;add blink,blink,2" - [(set_attr "type" "call_no_delay_slot") - (set_attr "length" "3")]) - -(define_insn "*call_via_label" - [(call (mem:SI (match_operand:SI 0 "call_address_operand" "")) - (match_operand 1 "" "")) - (clobber (reg:SI 31))] - "" - ; The %~ is necessary in case this insn gets conditionalized and the previous - ; insn is the cc setter. - "%~bl%!%* %0" - [(set_attr "type" "call") - (set_attr "cond" "canuse")]) - -(define_expand "call_value" - ;; operand 2 is stack_size_rtx - ;; operand 3 is next_arg_register - [(parallel [(set (match_operand 0 "register_operand" "=r") - (call (match_operand:SI 1 "call_operand" "") - (match_operand 2 "" ""))) - (clobber (reg:SI 31))])] - "" - "") - -(define_insn "*call_value_via_reg" - [(set (match_operand 0 "register_operand" "=r") - (call (mem:SI (match_operand:SI 1 "register_operand" "r")) - (match_operand 2 "" ""))) - (clobber (reg:SI 31))] - "" - "lr blink,[status]\;j.d %1\;add blink,blink,2" - [(set_attr "type" "call_no_delay_slot") - (set_attr "length" "3")]) - -(define_insn "*call_value_via_label" - [(set (match_operand 0 "register_operand" "=r") - (call (mem:SI (match_operand:SI 1 "call_address_operand" "")) - (match_operand 2 "" ""))) - (clobber (reg:SI 31))] - "" - ; The %~ is necessary in case this insn gets conditionalized and the previous - ; insn is the cc setter. - "%~bl%!%* %1" - [(set_attr "type" "call") - (set_attr "cond" "canuse")]) - -(define_insn "nop" - [(const_int 0)] - "" - "nop" - [(set_attr "type" "misc")]) - -;; Special pattern to flush the icache. -;; ??? Not sure what to do here. Some ARC's are known to support this. - -(define_insn "flush_icache" - [(unspec_volatile [(match_operand 0 "memory_operand" "m")] 0)] - "" - "* return \"\";" - [(set_attr "type" "misc")]) - -;; Split up troublesome insns for better scheduling. - -;; Peepholes go at the end. diff --git a/gcc/config/arc/arc.opt b/gcc/config/arc/arc.opt deleted file mode 100644 index e5381f95afc..00000000000 --- a/gcc/config/arc/arc.opt +++ /dev/null @@ -1,60 +0,0 @@ -; Options for the Argonaut ARC port of the compiler -; -; Copyright (C) 2005, 2007, 2011 Free Software Foundation, Inc. -; -; This file is part of GCC. -; -; GCC 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 3, or (at your option) any later -; version. -; -; GCC 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 GCC; see the file COPYING3. If not see -; <http://www.gnu.org/licenses/>. - -EB -Driver - -EL -Driver - -malign-loops -Target Undocumented Report Mask(ALIGN_LOOPS) - -mbig-endian -Target Undocumented Report RejectNegative Mask(BIG_ENDIAN) - -mlittle-endian -Target Undocumented Report RejectNegative InverseMask(BIG_ENDIAN) - -mmangle-cpu -Target Report Mask(MANGLE_CPU) -Prepend the name of the cpu to all public symbol names - -; mmangle-cpu-libgcc -; Target Undocumented Mask(MANGLE_CPU_LIBGC) - -mno-cond-exec -Target Undocumented Report RejectNegative Mask(NO_COND_EXEC) - -mcpu= -Target RejectNegative Joined Var(arc_cpu_string) Init("base") --mcpu=CPU Compile code for ARC variant CPU - -mtext= -Target RejectNegative Joined Var(arc_text_string) Init(ARC_DEFAULT_TEXT_SECTION) --mtext=SECTION Put functions in SECTION - -mdata= -Target RejectNegative Joined Var(arc_data_string) Init(ARC_DEFAULT_DATA_SECTION) --mdata=SECTION Put data in SECTION - -mrodata= -Target RejectNegative Joined Var(arc_rodata_string) Init(ARC_DEFAULT_RODATA_SECTION) --mrodata=SECTION Put read-only data in SECTION diff --git a/gcc/config/arc/initfini.c b/gcc/config/arc/initfini.c deleted file mode 100644 index d7514133a36..00000000000 --- a/gcc/config/arc/initfini.c +++ /dev/null @@ -1,155 +0,0 @@ -/* .init/.fini section handling + C++ global constructor/destructor handling. - This file is based on crtstuff.c, sol2-crti.asm, sol2-crtn.asm. - -Copyright (C) 1995, 1997, 1998, 2009 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -<http://www.gnu.org/licenses/>. */ - -/* Declare a pointer to void function type. */ -typedef void (*func_ptr) (void); - -#ifdef CRT_INIT - -/* NOTE: In order to be able to support SVR4 shared libraries, we arrange - to have one set of symbols { __CTOR_LIST__, __DTOR_LIST__, __CTOR_END__, - __DTOR_END__ } per root executable and also one set of these symbols - per shared library. So in any given whole process image, we may have - multiple definitions of each of these symbols. In order to prevent - these definitions from conflicting with one another, and in order to - ensure that the proper lists are used for the initialization/finalization - of each individual shared library (respectively), we give these symbols - only internal (i.e. `static') linkage, and we also make it a point to - refer to only the __CTOR_END__ symbol in crtfini.o and the __DTOR_LIST__ - symbol in crtinit.o, where they are defined. */ - -static func_ptr __CTOR_LIST__[1] __attribute__ ((section (".ctors"))) - = { (func_ptr) (-1) }; - -static func_ptr __DTOR_LIST__[1] __attribute__ ((section (".dtors"))) - = { (func_ptr) (-1) }; - -/* Run all the global destructors on exit from the program. */ - -/* Some systems place the number of pointers in the first word of the - table. On SVR4 however, that word is -1. In all cases, the table is - null-terminated. On SVR4, we start from the beginning of the list and - invoke each per-compilation-unit destructor routine in order - until we find that null. - - Note that this function MUST be static. There will be one of these - functions in each root executable and one in each shared library, but - although they all have the same code, each one is unique in that it - refers to one particular associated `__DTOR_LIST__' which belongs to the - same particular root executable or shared library file. */ - -static void __do_global_dtors (void) -asm ("__do_global_dtors") __attribute__ ((section (".text"))); - -static void -__do_global_dtors (void) -{ - func_ptr *p; - for (p = __DTOR_LIST__ + 1; *p; p++) - (*p) (); -} - -/* .init section start. - This must appear at the start of the .init section. */ - -asm ("\n\ - .section .init\n\ - .global init\n\ - .word 0\n\ -init:\n\ - st blink,[sp,4]\n\ - st fp,[sp]\n\ - mov fp,sp\n\ - sub sp,sp,16\n\ -"); - -/* .fini section start. - This must appear at the start of the .init section. */ - -asm ("\n\ - .section .fini\n\ - .global fini\n\ - .word 0\n\ -fini:\n\ - st blink,[sp,4]\n\ - st fp,[sp]\n\ - mov fp,sp\n\ - sub sp,sp,16\n\ - bl.nd __do_global_dtors\n\ -"); - -#endif /* CRT_INIT */ - -#ifdef CRT_FINI - -/* Put a word containing zero at the end of each of our two lists of function - addresses. Note that the words defined here go into the .ctors and .dtors - sections of the crtend.o file, and since that file is always linked in - last, these words naturally end up at the very ends of the two lists - contained in these two sections. */ - -static func_ptr __CTOR_END__[1] __attribute__ ((section (".ctors"))) - = { (func_ptr) 0 }; - -static func_ptr __DTOR_END__[1] __attribute__ ((section (".dtors"))) - = { (func_ptr) 0 }; - -/* Run all global constructors for the program. - Note that they are run in reverse order. */ - -static void __do_global_ctors (void) -asm ("__do_global_ctors") __attribute__ ((section (".text"))); - -static void -__do_global_ctors (void) -{ - func_ptr *p; - for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--) - (*p) (); -} - -/* .init section end. - This must live at the end of the .init section. */ - -asm ("\n\ - .section .init\n\ - bl.nd __do_global_ctors\n\ - ld blink,[fp,4]\n\ - j.d blink\n\ - ld.a fp,[sp,16]\n\ -"); - -/* .fini section end. - This must live at the end of the .fini section. */ - -asm ("\n\ - .section .fini\n\ - ld blink,[fp,4]\n\ - j.d blink\n\ - ld.a fp,[sp,16]\n\ -"); - -#endif /* CRT_FINI */ diff --git a/gcc/config/arc/lib1funcs.asm b/gcc/config/arc/lib1funcs.asm deleted file mode 100644 index c61f39a5ca7..00000000000 --- a/gcc/config/arc/lib1funcs.asm +++ /dev/null @@ -1,266 +0,0 @@ -; libgcc routines for ARC cpu. - -/* Copyright (C) 1995, 1997,2004, 2009 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 3, or (at your option) any -later version. - -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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -<http://www.gnu.org/licenses/>. */ - -#ifdef L_mulsi3 - .section .text - .align 4 - -#ifdef __base__ - .cpu base - .global ___mulsi3 -___mulsi3: - -/* This the simple version. - - while (a) - { - if (a & 1) - r += b; - a >>= 1; - b <<= 1; - } -*/ - mov r2,0 ; Accumulate result here. -.Lloop: - sub.f 0,r0,0 ; while (a) - nop - beq.nd .Ldone - and.f 0,r0,1 ; if (a & 1) - add.nz r2,r2,r1 ; r += b - lsr r0,r0 ; a >>= 1 - b.d .Lloop - lsl r1,r1 ; b <<= 1 -.Ldone: - j.d blink - mov r0,r2 -#endif - -#endif /* L_mulsi3 */ - -#ifdef L_umulsidi3 - .section .text - .align 4 - -#ifdef __base__ - .cpu base - .global ___umulsidi3 -___umulsidi3: - -/* This the simple version. - - while (a) - { - if (a & 1) - r += b; - a >>= 1; - b <<= 1; - } -*/ - mov r2,0 ; Top part of b. - mov r3,0 ; Accumulate result here. - mov r4,0 -.Lloop: - sub.f 0,r0,0 ; while (a) - nop - beq.nd .Ldone - and.f 0,r0,1 ; if (a & 1) - sub.f 0,r0,0 - nop - beq .Ldontadd - add.f r4,r4,r1 ; r += b - adc r3,r3,r2 -.Ldontadd: - lsr r0,r0 ; a >>= 1 - lsl.f r1,r1 ; b <<= 1 - b.d .Lloop - rlc r2,r2 -.Ldone: -#ifdef __big_endian__ - mov r1,r4 - j.d blink - mov r0,r3 -#else - mov r0,r4 - j.d blink - mov r1,r3 -#endif -#endif - -#endif /* L_umulsidi3 */ - -#ifdef L_divmod_tools - -; Utilities used by all routines. - - .section .text - .align 4 - -; inputs: r0 = numerator, r1 = denominator -; outputs: positive r0/r1, -; r6.bit1 = sign of numerator, r6.bit0 = sign of result - - .global ___divnorm -___divnorm: - mov r6,0 ; keep sign in r6 - sub.f 0,r0,0 ; is numerator -ve? - sub.lt r0,0,r0 ; negate numerator - mov.lt r6,3 ; sign is -ve - sub.f 0,r1,0 ; is denominator -ve? - sub.lt r1,0,r1 ; negate denominator - xor.lt r6,r6,1 ; toggle sign - j.nd blink - -/* -unsigned long -udivmodsi4(int modwanted, unsigned long num, unsigned long den) -{ - unsigned long bit = 1; - unsigned long res = 0; - - while (den < num && bit && !(den & (1L<<31))) - { - den <<=1; - bit <<=1; - } - while (bit) - { - if (num >= den) - { - num -= den; - res |= bit; - } - bit >>=1; - den >>=1; - } - if (modwanted) return num; - return res; -} -*/ - -; inputs: r0 = numerator, r1 = denominator -; outputs: r0 = quotient, r1 = remainder, r2/r3 trashed - - .global ___udivmodsi4 -___udivmodsi4: - mov r2,1 ; bit = 1 - mov r3,0 ; res = 0 -.Lloop1: - sub.f 0,r1,r0 ; while (den < num - nop - bnc.nd .Lloop2 - sub.f 0,r2,0 ; && bit - nop - bz.nd .Lloop2 - lsl.f 0,r1 ; && !(den & (1<<31)) - nop - bc.nd .Lloop2 - lsl r1,r1 ; den <<= 1 - b.d .Lloop1 - lsl r2,r2 ; bit <<= 1 -.Lloop2: - sub.f 0,r2,0 ; while (bit) - nop - bz.nd .Ldivmodend - sub.f 0,r0,r1 ; if (num >= den) - nop - bc.nd .Lshiftdown - sub r0,r0,r1 ; num -= den - or r3,r3,r2 ; res |= bit -.Lshiftdown: - lsr r2,r2 ; bit >>= 1 - b.d .Lloop2 - lsr r1,r1 ; den >>= 1 -.Ldivmodend: - mov r1,r0 ; r1 = mod - j.d blink - mov r0,r3 ; r0 = res - -#endif - -#ifdef L_udivsi3 - .section .text - .align 4 - -#ifdef __base__ - .cpu base - .global ___udivsi3 -___udivsi3: - mov r7,blink - bl.nd ___udivmodsi4 - j.nd r7 -#endif - -#endif /* L_udivsi3 */ - -#ifdef L_divsi3 - .section .text - .align 4 - -#ifdef __base__ - .cpu base - .global ___divsi3 -___divsi3: - mov r7,blink - bl.nd ___divnorm - bl.nd ___udivmodsi4 - and.f 0,r6,1 - sub.nz r0,0,r0 ; cannot go in delay slot, has limm value - j.nd r7 -#endif - -#endif /* L_divsi3 */ - -#ifdef L_umodsi3 - .section .text - .align 4 - -#ifdef __base__ - .cpu base - .global ___umodsi3 -___umodsi3: - mov r7,blink - bl.nd ___udivmodsi4 - j.d r7 - mov r0,r1 -#endif - -#endif /* L_umodsi3 */ - -#ifdef L_modsi3 - .section .text - .align 4 - -#ifdef __base__ - .cpu base - .global ___modsi3 -___modsi3: - mov r7,blink - bl.nd ___divnorm - bl.nd ___udivmodsi4 - and.f 0,r6,2 - sub.nz r1,0,r1 - j.d r7 - mov r0,r1 -#endif - -#endif /* L_modsi3 */ diff --git a/gcc/config/arc/t-arc b/gcc/config/arc/t-arc deleted file mode 100644 index a923479ca09..00000000000 --- a/gcc/config/arc/t-arc +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright (C) 1997, 1998, 1999, 2001, 2002, 2003, -# 2004 Free Software Foundation, Inc. -# -# This file is part of GCC. -# -# GCC 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 3, or (at your option) -# any later version. -# -# GCC 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 GCC; see the file COPYING3. If not see -# <http://www.gnu.org/licenses/>. - -LIB1ASMSRC = arc/lib1funcs.asm -LIB1ASMFUNCS = _mulsi3 _umulsidi3 _udivsi3 _divsi3 _umodsi3 _modsi3 _divmod_tools - -# We need libgcc routines to be mangled according to which cpu they -# were compiled for. -# ??? -mmangle-cpu passed by default for now. -#LIBGCC2_CFLAGS = -g1 -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) -mmangle-cpu - -# 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 - -dp-bit.c: $(srcdir)/config/fp-bit.c - echo '#ifndef __big_endian__' > dp-bit.c - echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c - echo '#endif' >> dp-bit.c - cat $(srcdir)/config/fp-bit.c >> dp-bit.c - -fp-bit.c: $(srcdir)/config/fp-bit.c - echo '#define FLOAT' > fp-bit.c - echo '#ifndef __big_endian__' >> 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 - -# .init/.fini section routines - -$(T)crtinit.o: $(srcdir)/config/arc/initfini.c $(GCC_PASSES) $(CONFIG_H) - $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(CRTSTUFF_T_CFLAGS) \ - $(MULTILIB_CFLAGS) -DCRT_INIT -finhibit-size-directive -fno-inline-functions \ - -g0 -c $(srcdir)/config/arc/initfini.c -o $(T)crtinit.o - -$(T)crtfini.o: $(srcdir)/config/arc/initfini.c $(GCC_PASSES) $(CONFIG_H) - $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(CRTSTUFF_T_CFLAGS) \ - -DCRT_FINI $(MULTILIB_CFLAGS) -finhibit-size-directive -fno-inline-functions \ - -g0 -c $(srcdir)/config/arc/initfini.c -o $(T)crtfini.o - -MULTILIB_OPTIONS = EB -MULTILIB_DIRNAMES = be -EXTRA_MULTILIB_PARTS = crtinit.o crtfini.o diff --git a/gcc/config/arm/netbsd.h b/gcc/config/arm/netbsd.h deleted file mode 100644 index 4a1adbae991..00000000000 --- a/gcc/config/arm/netbsd.h +++ /dev/null @@ -1,150 +0,0 @@ -/* NetBSD/arm a.out version. - Copyright (C) 1993, 1994, 1997, 1998, 2003, 2004, 2005, 2007, 2008, 2010 - Free Software Foundation, Inc. - Contributed by Mark Brinicombe (amb@physig.ph.kcl.ac.uk) - - This file is part of GCC. - - GCC 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 3, or (at your - option) any later version. - - GCC 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 GCC; see the file COPYING3. If not see - <http://www.gnu.org/licenses/>. */ - -/* Run-time Target Specification. */ -#undef TARGET_VERSION -#define TARGET_VERSION fputs (" (ARM/NetBSD)", stderr); - -/* Unsigned chars produces much better code than signed. */ -#define DEFAULT_SIGNED_CHAR 0 - -/* Since we always use GAS as our assembler we support stabs. */ -#define DBX_DEBUGGING_INFO 1 - -/*#undef ASM_DECLARE_FUNCTION_NAME*/ - -/* ARM6 family default cpu. */ -#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 - -#undef TARGET_DEFAULT -#define TARGET_DEFAULT (MASK_APCS_FRAME) - -/* Some defines for CPP. - arm32 is the NetBSD port name, so we always define arm32 and __arm32__. */ -#define TARGET_OS_CPP_BUILTINS() \ - do { \ - NETBSD_OS_CPP_BUILTINS_AOUT(); \ - builtin_define_std ("arm32"); \ - builtin_define_std ("unix"); \ - builtin_define_std ("riscbsd"); \ - } while (0) - -#undef SUBTARGET_EXTRA_SPECS -#define SUBTARGET_EXTRA_SPECS \ - { "netbsd_cpp_spec", NETBSD_CPP_SPEC }, \ - { "netbsd_link_spec", NETBSD_LINK_SPEC_AOUT }, - -#undef CPP_SPEC -#define CPP_SPEC "\ -%(cpp_cpu_arch) %(cpp_float) %(cpp_endian) %(netbsd_cpp_spec) \ -" - -/* Because TARGET_DEFAULT sets MASK_SOFT_FLOAT */ -#undef CPP_FLOAT_DEFAULT_SPEC -#define CPP_FLOAT_DEFAULT_SPEC "-D__SOFTFP__" - -/* Pass -X to the linker so that it will strip symbols starting with 'L' */ -#undef LINK_SPEC -#define LINK_SPEC "-X %(netbsd_link_spec)" - -#undef SIZE_TYPE -#define SIZE_TYPE "unsigned int" - -#undef PTRDIFF_TYPE -#define PTRDIFF_TYPE "int" - -/* We don't have any limit on the length as out debugger is GDB. */ -#undef DBX_CONTIN_LENGTH - -/* NetBSD does its profiling differently to the Acorn compiler. We - don't need a word following the mcount call; and to skip it - requires either an assembly stub or use of fomit-frame-pointer when - compiling the profiling functions. Since we break Acorn CC - compatibility below a little more won't hurt. */ - -#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"); \ -} - -/* On the ARM `@' introduces a comment, so we must use something else - for .type directives. */ -#undef TYPE_OPERAND_FMT -#define TYPE_OPERAND_FMT "%%%s" - -/* NetBSD uses the old PCC style aggregate returning conventions. */ -#undef DEFAULT_PCC_STRUCT_RETURN -#define DEFAULT_PCC_STRUCT_RETURN 1 - -/* Although not normally relevant (since by default, all aggregates - are returned in memory) compiling some parts of libc requires - non-APCS style struct returns. */ -#undef TARGET_RETURN_IN_MEMORY - -/* VERY BIG NOTE : Change of structure alignment for RiscBSD. - There are consequences you should be aware of... - - Normally GCC/arm uses a structure alignment of 32 for compatibility - with armcc. This means that structures are padded to a word - boundary. However this causes problems with bugged NetBSD kernel - code (possibly userland code as well - I have not checked every - binary). The nature of this bugged code is to rely on sizeof() - returning the correct size of various structures rounded to the - nearest byte (SCSI and ether code are two examples, the vm system - is another). This code breaks when the structure alignment is 32 - as sizeof() will report a word=rounded size. By changing the - structure alignment to 8. GCC will conform to what is expected by - NetBSD. - - This has several side effects that should be considered. - 1. Structures will only be aligned to the size of the largest member. - i.e. structures containing only bytes will be byte aligned. - structures containing shorts will be half word aligned. - structures containing ints will be word aligned. - - This means structures should be padded to a word boundary if - alignment of 32 is required for byte structures etc. - - 2. A potential performance penalty may exist if strings are no longer - word aligned. GCC will not be able to use word load/stores to copy - short strings. - - This modification is not encouraged but with the present state of the - NetBSD source tree it is currently the only solution that meets the - requirements. */ -#undef DEFAULT_STRUCTURE_SIZE_BOUNDARY -#define DEFAULT_STRUCTURE_SIZE_BOUNDARY 8 - -/* Clear the instruction cache from `BEG' to `END'. This makes a - call to the ARM32_SYNC_ICACHE architecture specific syscall. */ -#define CLEAR_INSN_CACHE(BEG, END) \ -{ \ - extern int sysarch(int number, void *args); \ - struct { \ - unsigned int addr; \ - int len; \ - } s; \ - s.addr = (unsigned int)(BEG); \ - s.len = (END) - (BEG); \ - (void)sysarch(0, &s); \ -} diff --git a/gcc/config/arm/t-pe b/gcc/config/arm/t-pe deleted file mode 100644 index 626b1d29a12..00000000000 --- a/gcc/config/arm/t-pe +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, 2008, 2009, -# 2010 -# Free Software Foundation, Inc. -# -# This file is part of GCC. -# -# GCC 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 3, or (at your option) -# any later version. -# -# GCC 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 GCC; see the file COPYING3. If not see -# <http://www.gnu.org/licenses/>. - -LIB1ASMFUNCS += _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX _clzsi2 _clzdi2 - -# 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 - -pe.o: $(srcdir)/config/arm/pe.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) output.h flags.h $(TREE_H) expr.h $(TM_P_H) - $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ - $(srcdir)/config/arm/pe.c - -MULTILIB_OPTIONS = mhard-float mthumb -MULTILIB_DIRNAMES = fpu thumb - -LIBGCC = stmp-multilib -INSTALL_LIBGCC = install-multilib -TARGET_LIBGCC2_CFLAGS = diff --git a/gcc/config/crx/crx-protos.h b/gcc/config/crx/crx-protos.h deleted file mode 100644 index aeb4bdd594a..00000000000 --- a/gcc/config/crx/crx-protos.h +++ /dev/null @@ -1,79 +0,0 @@ -/* Prototypes for exported functions defined in crx.c - Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2007, 2010 Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your - option) any later version. - - GCC 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 GCC; see the file COPYING3. If not see - <http://www.gnu.org/licenses/>. */ - -#ifndef GCC_CRX_PROTOS_H -#define GCC_CRX_PROTOS_H - - -/* Register usage. */ -extern enum reg_class crx_regno_reg_class (int); -extern int crx_hard_regno_mode_ok (int regno, enum machine_mode); -#ifdef RTX_CODE -extern enum reg_class crx_secondary_reload_class (enum reg_class, enum machine_mode, rtx); -#endif /* RTX_CODE */ - -/* Passing function arguments. */ -extern int crx_function_arg_regno_p (int); -#ifdef TREE_CODE -#ifdef RTX_CODE -extern void crx_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx); -#endif /* RTX_CODE */ -#endif /* TREE_CODE */ - -#ifdef RTX_CODE -/* Addressing Modes. */ -struct crx_address -{ - rtx base, index, disp, side_effect; - int scale; -}; - -enum crx_addrtype -{ - CRX_INVALID, CRX_REG_REL, CRX_POST_INC, CRX_SCALED_INDX, CRX_ABSOLUTE -}; - -extern enum crx_addrtype crx_decompose_address (rtx addr, struct crx_address *out); - -extern int crx_const_double_ok (rtx op); - -/* Instruction output. */ -extern void crx_print_operand (FILE *, rtx, int); -extern void crx_print_operand_address (FILE *, rtx); - -/* Misc functions called from crx.md. */ -extern void crx_expand_movmem_single (rtx, rtx, rtx, rtx, rtx, unsigned HOST_WIDE_INT *); -extern int crx_expand_movmem (rtx, rtx, rtx, rtx); -#endif /* RTX_CODE */ - -/* Routines to compute costs. */ -extern int crx_memory_move_cost (enum machine_mode, enum reg_class, int); - -/* Prologue/Epilogue functions. */ -extern int crx_initial_elimination_offset (int, int); -extern char *crx_prepare_push_pop_string (int); -extern void crx_expand_prologue (void); -extern void crx_expand_epilogue (void); - - -/* Handling the "interrupt" attribute */ -extern int crx_interrupt_function_p (void); - -#endif /* GCC_CRX_PROTOS_H */ diff --git a/gcc/config/crx/crx.c b/gcc/config/crx/crx.c deleted file mode 100644 index 8f635d5a171..00000000000 --- a/gcc/config/crx/crx.c +++ /dev/null @@ -1,1466 +0,0 @@ -/* Output routines for GCC for CRX. - Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your - option) any later version. - - GCC 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 GCC; see the file COPYING3. If not see - <http://www.gnu.org/licenses/>. */ - -/*****************************************************************************/ -/* HEADER INCLUDES */ -/*****************************************************************************/ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "rtl.h" -#include "tree.h" -#include "tm_p.h" -#include "regs.h" -#include "hard-reg-set.h" -#include "insn-config.h" -#include "conditions.h" -#include "output.h" -#include "insn-codes.h" -#include "insn-attr.h" -#include "flags.h" -#include "except.h" -#include "function.h" -#include "recog.h" -#include "expr.h" -#include "optabs.h" -#include "diagnostic-core.h" -#include "basic-block.h" -#include "df.h" -#include "target.h" -#include "target-def.h" - -/*****************************************************************************/ -/* DEFINITIONS */ -/*****************************************************************************/ - -/* Maximum number of register used for passing parameters. */ -#define MAX_REG_FOR_PASSING_ARGS 6 - -/* Minimum number register used for passing parameters. */ -#define MIN_REG_FOR_PASSING_ARGS 2 - -/* The maximum count of words supported in the assembly of the architecture in - * a push/pop instruction. */ -#define MAX_COUNT 8 - -/* Predicate is true if the current function is a 'noreturn' function, i.e. it - * is qualified as volatile. */ -#define FUNC_IS_NORETURN_P(decl) (TREE_THIS_VOLATILE (decl)) - -/* The following macros are used in crx_decompose_address () */ - -/* Returns the factor of a scaled index address or -1 if invalid. */ -#define SCALE_FOR_INDEX_P(X) \ - (GET_CODE (X) == CONST_INT ? \ - (INTVAL (X) == 1 ? 1 : \ - INTVAL (X) == 2 ? 2 : \ - INTVAL (X) == 4 ? 4 : \ - INTVAL (X) == 8 ? 8 : \ - -1) : \ - -1) - -/* Nonzero if the rtx X is a signed const int of n bits */ -#define RTX_SIGNED_INT_FITS_N_BITS(X,n) \ - ((GET_CODE (X) == CONST_INT \ - && SIGNED_INT_FITS_N_BITS (INTVAL (X), n)) ? 1 : 0) - -/* Nonzero if the rtx X is an unsigned const int of n bits. */ -#define RTX_UNSIGNED_INT_FITS_N_BITS(X, n) \ - ((GET_CODE (X) == CONST_INT \ - && UNSIGNED_INT_FITS_N_BITS (INTVAL (X), n)) ? 1 : 0) - -/*****************************************************************************/ -/* STATIC VARIABLES */ -/*****************************************************************************/ - -/* Nonzero if the last param processed is passed in a register. */ -static int last_parm_in_reg; - -/* Will hold the number of the last register the prologue saves, -1 if no - * register is saved. */ -static int last_reg_to_save; - -/* Each object in the array is a register number. Mark 1 for registers that - * need to be saved. */ -static int save_regs[FIRST_PSEUDO_REGISTER]; - -/* Number of bytes saved on the stack for non-scratch registers */ -static int sum_regs = 0; - -/* Number of bytes saved on the stack for local variables. */ -static int local_vars_size; - -/* The sum of 2 sizes: locals vars and padding byte for saving the registers. - * Used in expand_prologue () and expand_epilogue (). */ -static int size_for_adjusting_sp; - -/* In case of a POST_INC or POST_DEC memory reference, we must report the mode - * of the memory reference from PRINT_OPERAND to PRINT_OPERAND_ADDRESS. */ -static enum machine_mode output_memory_reference_mode; - -/*****************************************************************************/ -/* TARGETM FUNCTION PROTOTYPES */ -/*****************************************************************************/ - -static bool crx_fixed_condition_code_regs (unsigned int *, unsigned int *); -static rtx crx_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, - int incoming ATTRIBUTE_UNUSED); -static bool crx_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED); -static int crx_address_cost (rtx, bool); -static bool crx_legitimate_address_p (enum machine_mode, rtx, bool); -static bool crx_can_eliminate (const int, const int); -static rtx crx_function_arg (CUMULATIVE_ARGS *, enum machine_mode, - const_tree, bool); -static void crx_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, - const_tree, bool); - -/*****************************************************************************/ -/* RTL VALIDITY */ -/*****************************************************************************/ - -#undef TARGET_LEGITIMATE_ADDRESS_P -#define TARGET_LEGITIMATE_ADDRESS_P crx_legitimate_address_p - -#undef TARGET_CAN_ELIMINATE -#define TARGET_CAN_ELIMINATE crx_can_eliminate - -/*****************************************************************************/ -/* STACK LAYOUT AND CALLING CONVENTIONS */ -/*****************************************************************************/ - -#undef TARGET_FIXED_CONDITION_CODE_REGS -#define TARGET_FIXED_CONDITION_CODE_REGS crx_fixed_condition_code_regs - -#undef TARGET_STRUCT_VALUE_RTX -#define TARGET_STRUCT_VALUE_RTX crx_struct_value_rtx - -#undef TARGET_RETURN_IN_MEMORY -#define TARGET_RETURN_IN_MEMORY crx_return_in_memory - -/*****************************************************************************/ -/* PASSING FUNCTION ARGUMENTS */ -/*****************************************************************************/ - -#undef TARGET_FUNCTION_ARG -#define TARGET_FUNCTION_ARG crx_function_arg - -#undef TARGET_FUNCTION_ARG_ADVANCE -#define TARGET_FUNCTION_ARG_ADVANCE crx_function_arg_advance - -/*****************************************************************************/ -/* RELATIVE COSTS OF OPERATIONS */ -/*****************************************************************************/ - -#undef TARGET_ADDRESS_COST -#define TARGET_ADDRESS_COST crx_address_cost - -/*****************************************************************************/ -/* TARGET-SPECIFIC USES OF `__attribute__' */ -/*****************************************************************************/ - -#undef TARGET_ATTRIBUTE_TABLE -#define TARGET_ATTRIBUTE_TABLE crx_attribute_table - -static const struct attribute_spec crx_attribute_table[] = { - /* ISRs have special prologue and epilogue requirements. */ - {"interrupt", 0, 0, false, true, true, NULL, false}, - {NULL, 0, 0, false, false, false, NULL, false} -}; - -/* Option handling. */ - -#undef TARGET_OPTION_OPTIMIZATION_TABLE -#define TARGET_OPTION_OPTIMIZATION_TABLE crx_option_optimization_table - -static const struct default_options crx_option_optimization_table[] = - { - /* Put each function in its own section so that PAGE-instruction - relaxation can do its best. */ - { OPT_LEVELS_1_PLUS, OPT_ffunction_sections, NULL, 1 }, - { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 }, - { OPT_LEVELS_NONE, 0, NULL, 0 } - }; - -/* Initialize 'targetm' variable which contains pointers to functions and data - * relating to the target machine. */ - -struct gcc_target targetm = TARGET_INITIALIZER; - - -/*****************************************************************************/ -/* TARGET HOOK IMPLEMENTATIONS */ -/*****************************************************************************/ - -/* Return the fixed registers used for condition codes. */ - -static bool -crx_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2) -{ - *p1 = CC_REGNUM; - *p2 = INVALID_REGNUM; - return true; -} - -/* Implements hook TARGET_STRUCT_VALUE_RTX. */ - -static rtx -crx_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, - int incoming ATTRIBUTE_UNUSED) -{ - return gen_rtx_REG (Pmode, CRX_STRUCT_VALUE_REGNUM); -} - -/* Implements hook TARGET_RETURN_IN_MEMORY. */ - -static bool -crx_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) -{ - if (TYPE_MODE (type) == BLKmode) - { - HOST_WIDE_INT size = int_size_in_bytes (type); - return (size == -1 || size > 8); - } - else - return false; -} - - -/*****************************************************************************/ -/* MACRO IMPLEMENTATIONS */ -/*****************************************************************************/ - -/* STACK LAYOUT AND CALLING CONVENTIONS ROUTINES */ -/* --------------------------------------------- */ - -/* Return nonzero if the current function being compiled is an interrupt - * function as specified by the "interrupt" attribute. */ - -int -crx_interrupt_function_p (void) -{ - tree attributes; - - attributes = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); - return lookup_attribute ("interrupt", attributes) != NULL_TREE; -} - -/* Compute values for the array save_regs and the variable sum_regs. The index - * of save_regs is numbers of register, each will get 1 if we need to save it - * in the current function, 0 if not. sum_regs is the total sum of the - * registers being saved. */ - -static void -crx_compute_save_regs (void) -{ - unsigned int regno; - - /* initialize here so in case the function is no-return it will be -1. */ - last_reg_to_save = -1; - - /* No need to save any registers if the function never returns. */ - if (FUNC_IS_NORETURN_P (current_function_decl)) - return; - - /* Initialize the number of bytes to be saved. */ - sum_regs = 0; - - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - { - if (fixed_regs[regno]) - { - save_regs[regno] = 0; - continue; - } - - /* If this reg is used and not call-used (except RA), save it. */ - if (crx_interrupt_function_p ()) - { - if (!current_function_is_leaf && call_used_regs[regno]) - /* this is a volatile reg in a non-leaf interrupt routine - save it - * for the sake of its sons. */ - save_regs[regno] = 1; - - else if (df_regs_ever_live_p (regno)) - /* This reg is used - save it. */ - save_regs[regno] = 1; - else - /* This reg is not used, and is not a volatile - don't save. */ - save_regs[regno] = 0; - } - else - { - /* If this reg is used and not call-used (except RA), save it. */ - if (df_regs_ever_live_p (regno) - && (!call_used_regs[regno] || regno == RETURN_ADDRESS_REGNUM)) - save_regs[regno] = 1; - else - save_regs[regno] = 0; - } - } - - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if (save_regs[regno] == 1) - { - last_reg_to_save = regno; - sum_regs += UNITS_PER_WORD; - } -} - -/* Compute the size of the local area and the size to be adjusted by the - * prologue and epilogue. */ - -static void -crx_compute_frame (void) -{ - /* For aligning the local variables. */ - int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT; - int padding_locals; - - /* Padding needed for each element of the frame. */ - local_vars_size = get_frame_size (); - - /* Align to the stack alignment. */ - padding_locals = local_vars_size % stack_alignment; - if (padding_locals) - padding_locals = stack_alignment - padding_locals; - - local_vars_size += padding_locals; - - size_for_adjusting_sp = local_vars_size + (ACCUMULATE_OUTGOING_ARGS ? - crtl->outgoing_args_size : 0); -} - -/* Worker function for TARGET_CAN_ELIMINATE. */ - -bool -crx_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) -{ - return (to == STACK_POINTER_REGNUM ? ! frame_pointer_needed : true); -} - -/* Implements the macro INITIAL_ELIMINATION_OFFSET, return the OFFSET. */ - -int -crx_initial_elimination_offset (int from, int to) -{ - /* Compute this since we need to use sum_regs. */ - crx_compute_save_regs (); - - /* Compute this since we need to use local_vars_size. */ - crx_compute_frame (); - - if ((from) == FRAME_POINTER_REGNUM && (to) == STACK_POINTER_REGNUM) - return (ACCUMULATE_OUTGOING_ARGS ? - crtl->outgoing_args_size : 0); - else if ((from) == ARG_POINTER_REGNUM && (to) == FRAME_POINTER_REGNUM) - return (sum_regs + local_vars_size); - else if ((from) == ARG_POINTER_REGNUM && (to) == STACK_POINTER_REGNUM) - return (sum_regs + local_vars_size + - (ACCUMULATE_OUTGOING_ARGS ? - crtl->outgoing_args_size : 0)); - else - abort (); -} - -/* REGISTER USAGE */ -/* -------------- */ - -/* Return the class number of the smallest class containing reg number REGNO. - * This could be a conditional expression or could index an array. */ - -enum reg_class -crx_regno_reg_class (int regno) -{ - if (regno >= 0 && regno < SP_REGNUM) - return NOSP_REGS; - - if (regno == SP_REGNUM) - return GENERAL_REGS; - - if (regno == LO_REGNUM) - return LO_REGS; - if (regno == HI_REGNUM) - return HI_REGS; - - return NO_REGS; -} - -/* Transfer between HILO_REGS and memory via secondary reloading. */ - -enum reg_class -crx_secondary_reload_class (enum reg_class rclass, - enum machine_mode mode ATTRIBUTE_UNUSED, - rtx x ATTRIBUTE_UNUSED) -{ - if (reg_classes_intersect_p (rclass, HILO_REGS) - && true_regnum (x) == -1) - return GENERAL_REGS; - - return NO_REGS; -} - -/* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */ - -int -crx_hard_regno_mode_ok (int regno, enum machine_mode mode) -{ - /* CC can only hold CCmode values. */ - if (regno == CC_REGNUM) - return GET_MODE_CLASS (mode) == MODE_CC; - if (GET_MODE_CLASS (mode) == MODE_CC) - return 0; - /* HILO registers can only hold SImode and DImode */ - if (HILO_REGNO_P (regno)) - return mode == SImode || mode == DImode; - return 1; -} - -/* PASSING FUNCTION ARGUMENTS */ -/* -------------------------- */ - -/* If enough param regs are available for passing the param of type TYPE return - * the number of registers needed else 0. */ - -static int -enough_regs_for_param (CUMULATIVE_ARGS * cum, const_tree type, - enum machine_mode mode) -{ - int type_size; - int remaining_size; - - if (mode != BLKmode) - type_size = GET_MODE_BITSIZE (mode); - else - type_size = int_size_in_bytes (type) * BITS_PER_UNIT; - - remaining_size = - BITS_PER_WORD * (MAX_REG_FOR_PASSING_ARGS - - (MIN_REG_FOR_PASSING_ARGS + cum->ints) + 1); - - /* Any variable which is too big to pass in two registers, will pass on - * stack. */ - if ((remaining_size >= type_size) && (type_size <= 2 * BITS_PER_WORD)) - return (type_size + BITS_PER_WORD - 1) / BITS_PER_WORD; - - return 0; -} - -/* Implements TARGET_FUNCTION_ARG. */ - -static rtx -crx_function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode, - const_tree type, bool named ATTRIBUTE_UNUSED) -{ - last_parm_in_reg = 0; - - /* Function_arg () is called with this type just after all the args have had - * their registers assigned. The rtx that function_arg returns from this type - * is supposed to pass to 'gen_call' but currently it is not implemented (see - * macro GEN_CALL). */ - if (type == void_type_node) - return NULL_RTX; - - if (targetm.calls.must_pass_in_stack (mode, type) || (cum->ints < 0)) - return NULL_RTX; - - if (mode == BLKmode) - { - /* Enable structures that need padding bytes at the end to pass to a - * function in registers. */ - if (enough_regs_for_param (cum, type, mode) != 0) - { - last_parm_in_reg = 1; - return gen_rtx_REG (mode, MIN_REG_FOR_PASSING_ARGS + cum->ints); - } - } - - if (MIN_REG_FOR_PASSING_ARGS + cum->ints > MAX_REG_FOR_PASSING_ARGS) - return NULL_RTX; - else - { - if (enough_regs_for_param (cum, type, mode) != 0) - { - last_parm_in_reg = 1; - return gen_rtx_REG (mode, MIN_REG_FOR_PASSING_ARGS + cum->ints); - } - } - - return NULL_RTX; -} - -/* Implements the macro INIT_CUMULATIVE_ARGS defined in crx.h. */ - -void -crx_init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype, - rtx libfunc ATTRIBUTE_UNUSED) -{ - tree param, next_param; - - cum->ints = 0; - - /* Determine if this function has variable arguments. This is indicated by - * the last argument being 'void_type_mode' if there are no variable - * arguments. Change here for a different vararg. */ - for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; - param != (tree) 0; param = next_param) - { - next_param = TREE_CHAIN (param); - if (next_param == (tree) 0 && TREE_VALUE (param) != void_type_node) - { - cum->ints = -1; - return; - } - } -} - -/* Implements TARGET_FUNCTION_ARG_ADVANCE. */ - -static void -crx_function_arg_advance (CUMULATIVE_ARGS * cum, enum machine_mode mode, - const_tree type, bool named ATTRIBUTE_UNUSED) -{ - /* l holds the number of registers required */ - int l = GET_MODE_BITSIZE (mode) / BITS_PER_WORD; - - /* If the parameter isn't passed on a register don't advance cum. */ - if (!last_parm_in_reg) - return; - - if (targetm.calls.must_pass_in_stack (mode, type) || (cum->ints < 0)) - return; - - if (mode == SImode || mode == HImode || mode == QImode || mode == DImode) - { - if (l <= 1) - cum->ints += 1; - else - cum->ints += l; - } - else if (mode == SFmode || mode == DFmode) - cum->ints += l; - else if ((mode) == BLKmode) - { - if ((l = enough_regs_for_param (cum, type, mode)) != 0) - cum->ints += l; - } - -} - -/* Implements the macro FUNCTION_ARG_REGNO_P defined in crx.h. Return nonzero - * if N is a register used for passing parameters. */ - -int -crx_function_arg_regno_p (int n) -{ - return (n <= MAX_REG_FOR_PASSING_ARGS && n >= MIN_REG_FOR_PASSING_ARGS); -} - -/* ADDRESSING MODES */ -/* ---------------- */ - -/* Implements the hook for TARGET_LEGITIMATE_ADDRESS_P defined in crx.h. - * The following addressing modes are supported on CRX: - * - * Relocations --> const | symbol_ref | label_ref - * Absolute address --> 32-bit absolute - * Post increment --> reg + 12-bit disp. - * Post modify --> reg + 12-bit disp. - * Register relative --> reg | 32-bit disp. + reg | 4 bit + reg - * Scaled index --> reg + reg | 22-bit disp. + reg + reg | - * 22-disp. + reg + reg + (2 | 4 | 8) */ - -static rtx -crx_addr_reg (rtx addr_reg) -{ - if (GET_MODE (addr_reg) != Pmode) - return NULL_RTX; - - if (REG_P (addr_reg)) - return addr_reg; - else if (GET_CODE (addr_reg) == SUBREG - && REG_P (SUBREG_REG (addr_reg)) - && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (addr_reg))) - <= UNITS_PER_WORD)) - return SUBREG_REG (addr_reg); - else - return NULL_RTX; -} - -enum crx_addrtype -crx_decompose_address (rtx addr, struct crx_address *out) -{ - rtx base = NULL_RTX, index = NULL_RTX, disp = NULL_RTX; - rtx scale_rtx = NULL_RTX, side_effect = NULL_RTX; - int scale = -1; - - enum crx_addrtype retval = CRX_INVALID; - - switch (GET_CODE (addr)) - { - case CONST_INT: - /* Absolute address (known at compile time) */ - retval = CRX_ABSOLUTE; - disp = addr; - if (!UNSIGNED_INT_FITS_N_BITS (INTVAL (disp), GET_MODE_BITSIZE (Pmode))) - return CRX_INVALID; - break; - - case CONST: - case SYMBOL_REF: - case LABEL_REF: - /* Absolute address (known at link time) */ - retval = CRX_ABSOLUTE; - disp = addr; - break; - - case REG: - case SUBREG: - /* Register relative address */ - retval = CRX_REG_REL; - base = addr; - break; - - case PLUS: - switch (GET_CODE (XEXP (addr, 0))) - { - case REG: - case SUBREG: - if (REG_P (XEXP (addr, 1))) - { - /* Scaled index with scale = 1 and disp. = 0 */ - retval = CRX_SCALED_INDX; - base = XEXP (addr, 1); - index = XEXP (addr, 0); - scale = 1; - } - else if (RTX_SIGNED_INT_FITS_N_BITS (XEXP (addr, 1), 28)) - { - /* Register relative address and <= 28-bit disp. */ - retval = CRX_REG_REL; - base = XEXP (addr, 0); - disp = XEXP (addr, 1); - } - else - return CRX_INVALID; - break; - - case PLUS: - /* Scaled index and <= 22-bit disp. */ - retval = CRX_SCALED_INDX; - base = XEXP (XEXP (addr, 0), 1); - disp = XEXP (addr, 1); - if (!RTX_SIGNED_INT_FITS_N_BITS (disp, 22)) - return CRX_INVALID; - switch (GET_CODE (XEXP (XEXP (addr, 0), 0))) - { - case REG: - /* Scaled index with scale = 0 and <= 22-bit disp. */ - index = XEXP (XEXP (addr, 0), 0); - scale = 1; - break; - - case MULT: - /* Scaled index with scale >= 0 and <= 22-bit disp. */ - index = XEXP (XEXP (XEXP (addr, 0), 0), 0); - scale_rtx = XEXP (XEXP (XEXP (addr, 0), 0), 1); - if ((scale = SCALE_FOR_INDEX_P (scale_rtx)) == -1) - return CRX_INVALID; - break; - - default: - return CRX_INVALID; - } - break; - - case MULT: - /* Scaled index with scale >= 0 */ - retval = CRX_SCALED_INDX; - base = XEXP (addr, 1); - index = XEXP (XEXP (addr, 0), 0); - scale_rtx = XEXP (XEXP (addr, 0), 1); - /* Scaled index with scale >= 0 and <= 22-bit disp. */ - if ((scale = SCALE_FOR_INDEX_P (scale_rtx)) == -1) - return CRX_INVALID; - break; - - default: - return CRX_INVALID; - } - break; - - case POST_INC: - case POST_DEC: - /* Simple post-increment */ - retval = CRX_POST_INC; - base = XEXP (addr, 0); - side_effect = addr; - break; - - case POST_MODIFY: - /* Generic post-increment with <= 12-bit disp. */ - retval = CRX_POST_INC; - base = XEXP (addr, 0); - side_effect = XEXP (addr, 1); - if (base != XEXP (side_effect, 0)) - return CRX_INVALID; - switch (GET_CODE (side_effect)) - { - case PLUS: - case MINUS: - disp = XEXP (side_effect, 1); - if (!RTX_SIGNED_INT_FITS_N_BITS (disp, 12)) - return CRX_INVALID; - break; - - default: - /* CRX only supports PLUS and MINUS */ - return CRX_INVALID; - } - break; - - default: - return CRX_INVALID; - } - - if (base) - { - base = crx_addr_reg (base); - if (!base) - return CRX_INVALID; - } - if (index) - { - index = crx_addr_reg (index); - if (!index) - return CRX_INVALID; - } - - out->base = base; - out->index = index; - out->disp = disp; - out->scale = scale; - out->side_effect = side_effect; - - return retval; -} - -bool -crx_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, - rtx addr, bool strict) -{ - enum crx_addrtype addrtype; - struct crx_address address; - - if (TARGET_DEBUG_ADDR) - { - fprintf (stderr, - "\n======\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n", - GET_MODE_NAME (mode), strict); - debug_rtx (addr); - } - - addrtype = crx_decompose_address (addr, &address); - - if (addrtype == CRX_POST_INC && GET_MODE_SIZE (mode) > UNITS_PER_WORD) - return FALSE; - - if (TARGET_DEBUG_ADDR) - { - const char *typestr; - switch (addrtype) - { - case CRX_INVALID: - typestr = "Invalid"; - break; - case CRX_REG_REL: - typestr = "Register relative"; - break; - case CRX_POST_INC: - typestr = "Post-increment"; - break; - case CRX_SCALED_INDX: - typestr = "Scaled index"; - break; - case CRX_ABSOLUTE: - typestr = "Absolute"; - break; - default: - abort (); - } - fprintf (stderr, "CRX Address type: %s\n", typestr); - } - - if (addrtype == CRX_INVALID) - return FALSE; - - if (strict) - { - if (address.base && !REGNO_OK_FOR_BASE_P (REGNO (address.base))) - { - if (TARGET_DEBUG_ADDR) - fprintf (stderr, "Base register not strict\n"); - return FALSE; - } - if (address.index && !REGNO_OK_FOR_INDEX_P (REGNO (address.index))) - { - if (TARGET_DEBUG_ADDR) - fprintf (stderr, "Index register not strict\n"); - return FALSE; - } - } - - return TRUE; -} - -/* ROUTINES TO COMPUTE COSTS */ -/* ------------------------- */ - -/* Return cost of the memory address x. */ - -static int -crx_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED) -{ - enum crx_addrtype addrtype; - struct crx_address address; - - int cost = 2; - - addrtype = crx_decompose_address (addr, &address); - - gcc_assert (addrtype != CRX_INVALID); - - /* An absolute address causes a 3-word instruction */ - if (addrtype == CRX_ABSOLUTE) - cost+=2; - - /* Post-modifying addresses are more powerful. */ - if (addrtype == CRX_POST_INC) - cost-=2; - - /* Attempt to minimize number of registers in the address. */ - if (address.base) - cost++; - - if (address.index && address.scale == 1) - cost+=5; - - if (address.disp && !INT_CST4 (INTVAL (address.disp))) - cost+=2; - - if (TARGET_DEBUG_ADDR) - { - fprintf (stderr, "\n======\nTARGET_ADDRESS_COST = %d\n", cost); - debug_rtx (addr); - } - - return cost; -} - -/* Return the cost of moving data of mode MODE between a register of class - * RCLASS and memory; IN is zero if the value is to be written to memory, - * nonzero if it is to be read in. This cost is relative to those in - * REGISTER_MOVE_COST. */ - -int -crx_memory_move_cost (enum machine_mode mode, - enum reg_class rclass ATTRIBUTE_UNUSED, - int in ATTRIBUTE_UNUSED) -{ - /* One LD or ST takes twice the time of a simple reg-reg move */ - if (reg_classes_intersect_p (rclass, GENERAL_REGS)) - { - /* printf ("GENERAL_REGS LD/ST = %d\n", 4 * HARD_REGNO_NREGS (0, mode));*/ - return 4 * HARD_REGNO_NREGS (0, mode); - } - else if (reg_classes_intersect_p (rclass, HILO_REGS)) - { - /* HILO to memory and vice versa */ - /* printf ("HILO_REGS %s = %d\n", in ? "LD" : "ST", - (REGISTER_MOVE_COST (mode, - in ? GENERAL_REGS : HILO_REGS, - in ? HILO_REGS : GENERAL_REGS) + 4) - * HARD_REGNO_NREGS (0, mode)); */ - return (REGISTER_MOVE_COST (mode, - in ? GENERAL_REGS : HILO_REGS, - in ? HILO_REGS : GENERAL_REGS) + 4) - * HARD_REGNO_NREGS (0, mode); - } - else /* default (like in i386) */ - { - /* printf ("ANYREGS = 100\n"); */ - return 100; - } -} - -/* INSTRUCTION OUTPUT */ -/* ------------------ */ - -/* Check if a const_double is ok for crx store-immediate instructions */ - -int -crx_const_double_ok (rtx op) -{ - if (GET_MODE (op) == DFmode) - { - REAL_VALUE_TYPE r; - long l[2]; - REAL_VALUE_FROM_CONST_DOUBLE (r, op); - REAL_VALUE_TO_TARGET_DOUBLE (r, l); - return (UNSIGNED_INT_FITS_N_BITS (l[0], 4) && - UNSIGNED_INT_FITS_N_BITS (l[1], 4)) ? 1 : 0; - } - - if (GET_MODE (op) == SFmode) - { - REAL_VALUE_TYPE r; - long l; - REAL_VALUE_FROM_CONST_DOUBLE (r, op); - REAL_VALUE_TO_TARGET_SINGLE (r, l); - return UNSIGNED_INT_FITS_N_BITS (l, 4) ? 1 : 0; - } - - return (UNSIGNED_INT_FITS_N_BITS (CONST_DOUBLE_LOW (op), 4) && - UNSIGNED_INT_FITS_N_BITS (CONST_DOUBLE_HIGH (op), 4)) ? 1 : 0; -} - -/* Implements the macro PRINT_OPERAND defined in crx.h. */ - -void -crx_print_operand (FILE * file, rtx x, int code) -{ - switch (code) - { - case 'p' : - if (GET_CODE (x) == REG) { - if (GET_MODE (x) == DImode || GET_MODE (x) == DFmode) - { - int regno = REGNO (x); - if (regno + 1 >= SP_REGNUM) abort (); - fprintf (file, "{%s, %s}", reg_names[regno], reg_names[regno + 1]); - return; - } - else - { - if (REGNO (x) >= SP_REGNUM) abort (); - fprintf (file, "%s", reg_names[REGNO (x)]); - return; - } - } - - case 'd' : - { - const char *crx_cmp_str; - switch (GET_CODE (x)) - { /* MD: compare (reg, reg or imm) but CRX: cmp (reg or imm, reg) - * -> swap all non symmetric ops */ - case EQ : crx_cmp_str = "eq"; break; - case NE : crx_cmp_str = "ne"; break; - case GT : crx_cmp_str = "lt"; break; - case GTU : crx_cmp_str = "lo"; break; - case LT : crx_cmp_str = "gt"; break; - case LTU : crx_cmp_str = "hi"; break; - case GE : crx_cmp_str = "le"; break; - case GEU : crx_cmp_str = "ls"; break; - case LE : crx_cmp_str = "ge"; break; - case LEU : crx_cmp_str = "hs"; break; - default : abort (); - } - fprintf (file, "%s", crx_cmp_str); - return; - } - - case 'H': - /* Print high part of a double precision value. */ - switch (GET_CODE (x)) - { - case CONST_DOUBLE: - if (GET_MODE (x) == SFmode) abort (); - if (GET_MODE (x) == DFmode) - { - /* High part of a DF const. */ - REAL_VALUE_TYPE r; - long l[2]; - - REAL_VALUE_FROM_CONST_DOUBLE (r, x); - REAL_VALUE_TO_TARGET_DOUBLE (r, l); - - fprintf (file, "$0x%lx", l[1]); - return; - } - - /* -- Fallthrough to handle DI consts -- */ - - case CONST_INT: - { - rtx high, low; - split_double (x, &low, &high); - putc ('$', file); - output_addr_const (file, high); - return; - } - - case REG: - if (REGNO (x) + 1 >= FIRST_PSEUDO_REGISTER) abort (); - fprintf (file, "%s", reg_names[REGNO (x) + 1]); - return; - - case MEM: - /* Adjust memory address to high part. */ - { - rtx adj_mem = x; - adj_mem = adjust_address (adj_mem, GET_MODE (adj_mem), 4); - - output_memory_reference_mode = GET_MODE (adj_mem); - output_address (XEXP (adj_mem, 0)); - return; - } - - default: - abort (); - } - - case 'L': - /* Print low part of a double precision value. */ - switch (GET_CODE (x)) - { - case CONST_DOUBLE: - if (GET_MODE (x) == SFmode) abort (); - if (GET_MODE (x) == DFmode) - { - /* High part of a DF const. */ - REAL_VALUE_TYPE r; - long l[2]; - - REAL_VALUE_FROM_CONST_DOUBLE (r, x); - REAL_VALUE_TO_TARGET_DOUBLE (r, l); - - fprintf (file, "$0x%lx", l[0]); - return; - } - - /* -- Fallthrough to handle DI consts -- */ - - case CONST_INT: - { - rtx high, low; - split_double (x, &low, &high); - putc ('$', file); - output_addr_const (file, low); - return; - } - - case REG: - fprintf (file, "%s", reg_names[REGNO (x)]); - return; - - case MEM: - output_memory_reference_mode = GET_MODE (x); - output_address (XEXP (x, 0)); - return; - - default: - abort (); - } - - case 0 : /* default */ - switch (GET_CODE (x)) - { - case REG: - fprintf (file, "%s", reg_names[REGNO (x)]); - return; - - case MEM: - output_memory_reference_mode = GET_MODE (x); - output_address (XEXP (x, 0)); - return; - - case CONST_DOUBLE: - { - REAL_VALUE_TYPE r; - long l; - - /* Always use H and L for double precision - see above */ - gcc_assert (GET_MODE (x) == SFmode); - - REAL_VALUE_FROM_CONST_DOUBLE (r, x); - REAL_VALUE_TO_TARGET_SINGLE (r, l); - - fprintf (file, "$0x%lx", l); - return; - } - - default: - putc ('$', file); - output_addr_const (file, x); - return; - } - - default: - output_operand_lossage ("invalid %%xn code"); - } - - abort (); -} - -/* Implements the macro PRINT_OPERAND_ADDRESS defined in crx.h. */ - -void -crx_print_operand_address (FILE * file, rtx addr) -{ - enum crx_addrtype addrtype; - struct crx_address address; - - int offset; - - addrtype = crx_decompose_address (addr, &address); - - if (address.disp) - offset = INTVAL (address.disp); - else - offset = 0; - - switch (addrtype) - { - case CRX_REG_REL: - fprintf (file, "%d(%s)", offset, reg_names[REGNO (address.base)]); - return; - - case CRX_POST_INC: - switch (GET_CODE (address.side_effect)) - { - case PLUS: - break; - case MINUS: - offset = -offset; - break; - case POST_INC: - offset = GET_MODE_SIZE (output_memory_reference_mode); - break; - case POST_DEC: - offset = -GET_MODE_SIZE (output_memory_reference_mode); - break; - default: - abort (); - } - fprintf (file, "%d(%s)+", offset, reg_names[REGNO (address.base)]); - return; - - case CRX_SCALED_INDX: - fprintf (file, "%d(%s, %s, %d)", offset, reg_names[REGNO (address.base)], - reg_names[REGNO (address.index)], address.scale); - return; - - case CRX_ABSOLUTE: - output_addr_const (file, address.disp); - return; - - default: - abort (); - } -} - - -/*****************************************************************************/ -/* MACHINE DESCRIPTION HELPER-FUNCTIONS */ -/*****************************************************************************/ - -void crx_expand_movmem_single (rtx src, rtx srcbase, rtx dst, rtx dstbase, - rtx tmp_reg, unsigned HOST_WIDE_INT *offset_p) -{ - rtx addr, mem; - unsigned HOST_WIDE_INT offset = *offset_p; - - /* Load */ - addr = plus_constant (src, offset); - mem = adjust_automodify_address (srcbase, SImode, addr, offset); - emit_move_insn (tmp_reg, mem); - - /* Store */ - addr = plus_constant (dst, offset); - mem = adjust_automodify_address (dstbase, SImode, addr, offset); - emit_move_insn (mem, tmp_reg); - - *offset_p = offset + 4; -} - -int -crx_expand_movmem (rtx dstbase, rtx srcbase, rtx count_exp, rtx align_exp) -{ - unsigned HOST_WIDE_INT count = 0, offset, si_moves, i; - HOST_WIDE_INT align = 0; - - rtx src, dst; - rtx tmp_reg; - - if (GET_CODE (align_exp) == CONST_INT) - { /* Only if aligned */ - align = INTVAL (align_exp); - if (align & 3) - return 0; - } - - if (GET_CODE (count_exp) == CONST_INT) - { /* No more than 16 SImode moves */ - count = INTVAL (count_exp); - if (count > 64) - return 0; - } - - tmp_reg = gen_reg_rtx (SImode); - - /* Create psrs for the src and dest pointers */ - dst = copy_to_mode_reg (Pmode, XEXP (dstbase, 0)); - if (dst != XEXP (dstbase, 0)) - dstbase = replace_equiv_address_nv (dstbase, dst); - src = copy_to_mode_reg (Pmode, XEXP (srcbase, 0)); - if (src != XEXP (srcbase, 0)) - srcbase = replace_equiv_address_nv (srcbase, src); - - offset = 0; - - /* Emit SImode moves */ - si_moves = count >> 2; - for (i = 0; i < si_moves; i++) - crx_expand_movmem_single (src, srcbase, dst, dstbase, tmp_reg, &offset); - - /* Special cases */ - if (count & 3) - { - offset = count - 4; - crx_expand_movmem_single (src, srcbase, dst, dstbase, tmp_reg, &offset); - } - - gcc_assert (offset == count); - - return 1; -} - -static void -mpushpop_str (char *stringbuffer, const char *mnemonic, char *mask) -{ - if (strlen (mask) > 2 || crx_interrupt_function_p ()) /* needs 2-word instr. */ - sprintf (stringbuffer, "\n\t%s\tsp, {%s}", mnemonic, mask); - else /* single word instruction */ - sprintf (stringbuffer, "\n\t%s\t%s", mnemonic, mask); -} - -/* Called from crx.md. The return value depends on the parameter push_or_pop: - * When push_or_pop is zero -> string for push instructions of prologue. - * When push_or_pop is nonzero -> string for pop/popret/retx in epilogue. - * Relies on the assumptions: - * 1. RA is the last register to be saved. - * 2. The maximal value of the counter is MAX_COUNT. */ - -char * -crx_prepare_push_pop_string (int push_or_pop) -{ - /* j is the number of registers being saved, takes care that there won't be - * more than 8 in one push/pop instruction */ - - /* For the register mask string */ - static char mask_str[50]; - - /* i is the index of save_regs[], going from 0 until last_reg_to_save */ - int i = 0; - - int ra_in_bitmask = 0; - - char *return_str; - - /* For reversing on the push instructions if there are more than one. */ - char *temp_str; - - return_str = (char *) xmalloc (120); - temp_str = (char *) xmalloc (120); - - /* Initialize */ - memset (return_str, 0, 3); - - while (i <= last_reg_to_save) - { - /* Prepare mask for one instruction. */ - mask_str[0] = 0; - - if (i <= SP_REGNUM) - { /* Add regs unit full or SP register reached */ - int j = 0; - while (j < MAX_COUNT && i <= SP_REGNUM) - { - if (save_regs[i]) - { - /* TODO to use ra_in_bitmask for detecting last pop is not - * smart it prevents things like: popret r5 */ - if (i == RETURN_ADDRESS_REGNUM) ra_in_bitmask = 1; - if (j > 0) strcat (mask_str, ", "); - strcat (mask_str, reg_names[i]); - ++j; - } - ++i; - } - } - else - { - /* Handle hi/lo savings */ - while (i <= last_reg_to_save) - { - if (save_regs[i]) - { - strcat (mask_str, "lo, hi"); - i = last_reg_to_save + 1; - break; - } - ++i; - } - } - - if (strlen (mask_str) == 0) continue; - - if (push_or_pop == 1) - { - if (crx_interrupt_function_p ()) - mpushpop_str (temp_str, "popx", mask_str); - else - { - if (ra_in_bitmask) - { - mpushpop_str (temp_str, "popret", mask_str); - ra_in_bitmask = 0; - } - else mpushpop_str (temp_str, "pop", mask_str); - } - - strcat (return_str, temp_str); - } - else - { - /* push - We need to reverse the order of the instructions if there - * are more than one. (since the pop will not be reversed in the - * epilogue */ - if (crx_interrupt_function_p ()) - mpushpop_str (temp_str, "pushx", mask_str); - else - mpushpop_str (temp_str, "push", mask_str); - strcat (temp_str, return_str); - strcpy (strcat (return_str, "\t"), temp_str); - } - - } - - if (push_or_pop == 1) - { - /* pop */ - if (crx_interrupt_function_p ()) - strcat (return_str, "\n\tretx\n"); - - else if (!FUNC_IS_NORETURN_P (current_function_decl) - && !save_regs[RETURN_ADDRESS_REGNUM]) - strcat (return_str, "\n\tjump\tra\n"); - } - - /* Skip the newline and the tab in the start of return_str. */ - return_str += 2; - return return_str; -} - -/* CompactRISC CRX Architecture stack layout: - - 0 +--------------------- - | - . - . - | - +==================== Sp(x)=Ap(x+1) - A | Args for functions - | | called by X and Dynamically - | | Dynamic allocations allocated and - | | (alloca, variable deallocated - Stack | length arrays). - grows +-------------------- Fp(x) - down| | Local variables of X - ward| +-------------------- - | | Regs saved for X-1 - | +==================== Sp(x-1)=Ap(x) - | Args for func X - | pushed by X-1 - +-------------------- Fp(x-1) - | - | - V - -*/ - -void -crx_expand_prologue (void) -{ - crx_compute_frame (); - crx_compute_save_regs (); - - /* If there is no need in push and adjustment to sp, return. */ - if (size_for_adjusting_sp + sum_regs == 0) - return; - - if (last_reg_to_save != -1) - /* If there are registers to push. */ - emit_insn (gen_push_for_prologue (GEN_INT (sum_regs))); - - if (size_for_adjusting_sp > 0) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (-size_for_adjusting_sp))); - - if (frame_pointer_needed) - /* Initialize the frame pointer with the value of the stack pointer - * pointing now to the locals. */ - emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); -} - -/* Generate insn that updates the stack for local variables and padding for - * registers we save. - Generate the appropriate return insn. */ - -void -crx_expand_epilogue (void) -{ - /* Nonzero if we need to return and pop only RA. This will generate a - * different insn. This differentiate is for the peepholes for call as last - * statement in function. */ - int only_popret_RA = (save_regs[RETURN_ADDRESS_REGNUM] - && (sum_regs == UNITS_PER_WORD)); - - if (frame_pointer_needed) - /* Restore the stack pointer with the frame pointers value */ - emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); - - if (size_for_adjusting_sp > 0) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (size_for_adjusting_sp))); - - if (crx_interrupt_function_p ()) - emit_jump_insn (gen_interrupt_return ()); - else if (last_reg_to_save == -1) - /* Nothing to pop */ - /* Don't output jump for interrupt routine, only retx. */ - emit_jump_insn (gen_indirect_jump_return ()); - else if (only_popret_RA) - emit_jump_insn (gen_popret_RA_return ()); - else - emit_jump_insn (gen_pop_and_popret_return (GEN_INT (sum_regs))); -} diff --git a/gcc/config/crx/crx.h b/gcc/config/crx/crx.h deleted file mode 100644 index da6e263ca52..00000000000 --- a/gcc/config/crx/crx.h +++ /dev/null @@ -1,478 +0,0 @@ -/* Definitions of target machine for GNU compiler, for CRX. - Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your - option) any later version. - - GCC 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 GCC; see the file COPYING3. If not see - <http://www.gnu.org/licenses/>. */ - -#ifndef GCC_CRX_H -#define GCC_CRX_H - -/*****************************************************************************/ -/* CONTROLLING THE DRIVER */ -/*****************************************************************************/ - -#define CC1PLUS_SPEC "%{!frtti:-fno-rtti} \ - %{!fenforce-eh-specs:-fno-enforce-eh-specs} \ - %{!fexceptions:-fno-exceptions} \ - %{!fthreadsafe-statics:-fno-threadsafe-statics}" - -#undef STARTFILE_SPEC -#define STARTFILE_SPEC "crti.o%s crtbegin.o%s" - -#undef ENDFILE_SPEC -#define ENDFILE_SPEC "crtend.o%s crtn.o%s" - -#undef MATH_LIBRARY -#define MATH_LIBRARY "" - -/*****************************************************************************/ -/* RUN-TIME TARGET SPECIFICATION */ -/*****************************************************************************/ - -#ifndef TARGET_CPU_CPP_BUILTINS -#define TARGET_CPU_CPP_BUILTINS() \ -do { \ - builtin_define("__CRX__"); \ - builtin_define("__CR__"); \ -} while (0) -#endif - -#define TARGET_VERSION fputs (" (CRX/ELF)", stderr); - -/*****************************************************************************/ -/* STORAGE LAYOUT */ -/*****************************************************************************/ - -#define BITS_BIG_ENDIAN 0 - -#define BYTES_BIG_ENDIAN 0 - -#define WORDS_BIG_ENDIAN 0 - -#define UNITS_PER_WORD 4 - -#define POINTER_SIZE 32 - -#define PARM_BOUNDARY 32 - -#define STACK_BOUNDARY 32 - -#define FUNCTION_BOUNDARY 32 - -#define STRUCTURE_SIZE_BOUNDARY 32 - -#define BIGGEST_ALIGNMENT 32 - -/* In CRX arrays of chars are word-aligned, so strcpy() will be faster. */ -#define DATA_ALIGNMENT(TYPE, ALIGN) \ - (TREE_CODE (TYPE) == ARRAY_TYPE && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \ - && (ALIGN) < BITS_PER_WORD \ - ? (BITS_PER_WORD) : (ALIGN)) - -/* In CRX strings are word-aligned so strcpy from constants will be faster. */ -#define CONSTANT_ALIGNMENT(CONSTANT, ALIGN) \ - (TREE_CODE (CONSTANT) == STRING_CST && (ALIGN) < BITS_PER_WORD \ - ? (BITS_PER_WORD) : (ALIGN)) - -#define STRICT_ALIGNMENT 0 - -#define PCC_BITFIELD_TYPE_MATTERS 1 - -/*****************************************************************************/ -/* LAYOUT OF SOURCE LANGUAGE DATA TYPES */ -/*****************************************************************************/ - -#define INT_TYPE_SIZE 32 - -#define SHORT_TYPE_SIZE 16 - -#define LONG_TYPE_SIZE 32 - -#define LONG_LONG_TYPE_SIZE 64 - -#define FLOAT_TYPE_SIZE 32 - -#define DOUBLE_TYPE_SIZE 64 - -#define LONG_DOUBLE_TYPE_SIZE 64 - -#define DEFAULT_SIGNED_CHAR 1 - -#define SIZE_TYPE "unsigned int" - -#define PTRDIFF_TYPE "int" - -/*****************************************************************************/ -/* REGISTER USAGE. */ -/*****************************************************************************/ - -#define FIRST_PSEUDO_REGISTER 19 - -/* On the CRX, only the stack pointer (r15) is such. */ -#define FIXED_REGISTERS \ - { \ - /* r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 */ \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - /* r11 r12 r13 ra sp r16 r17 cc */ \ - 0, 0, 0, 0, 1, 0, 0, 1 \ - } - -/* On the CRX, calls clobbers r0-r6 (scratch registers), ra (the return address) - * and sp - (the stack pointer which is fixed). */ -#define CALL_USED_REGISTERS \ - { \ - /* r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 */ \ - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \ - /* r11 r12 r13 ra sp r16 r17 cc */ \ - 0, 0, 0, 1, 1, 1, 1, 1 \ - } - -#define HARD_REGNO_NREGS(REGNO, MODE) \ - ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) - -/* On the CRX architecture, HILO regs can only hold SI mode. */ -#define HARD_REGNO_MODE_OK(REGNO, MODE) crx_hard_regno_mode_ok(REGNO, MODE) - -/* So far no patterns for moving CCMODE data are available */ -#define AVOID_CCMODE_COPIES - -/* Interrupt functions can only use registers that have already been saved by - * the prologue, even if they would normally be call-clobbered. */ -#define HARD_REGNO_RENAME_OK(SRC, DEST) \ - (!crx_interrupt_function_p () || df_regs_ever_live_p (DEST)) - -#define MODES_TIEABLE_P(MODE1, MODE2) 1 - -enum reg_class -{ - NO_REGS, - LO_REGS, - HI_REGS, - HILO_REGS, - NOSP_REGS, - GENERAL_REGS, - ALL_REGS, - LIM_REG_CLASSES -}; - -#define N_REG_CLASSES (int) LIM_REG_CLASSES - -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, LIM_REG_CLASSES \ -} - -#define REG_CLASS_NAMES \ - { \ - "NO_REGS", \ - "LO_REGS", \ - "HI_REGS", \ - "HILO_REGS", \ - "NOSP_REGS", \ - "GENERAL_REGS", \ - "ALL_REGS" \ - } - -#define REG_CLASS_CONTENTS \ - { \ - {0x00000000}, /* NO_REGS */ \ - {0x00010000}, /* LO_REGS : 16 */ \ - {0x00020000}, /* HI_REGS : 17 */ \ - {0x00030000}, /* HILO_REGS : 16, 17 */ \ - {0x00007fff}, /* NOSP_REGS : 0 - 14 */ \ - {0x0000ffff}, /* GENERAL_REGS : 0 - 15 */ \ - {0x0007ffff} /* ALL_REGS : 0 - 18 */ \ - } - -#define REGNO_REG_CLASS(REGNO) crx_regno_reg_class(REGNO) - -#define BASE_REG_CLASS GENERAL_REGS - -#define INDEX_REG_CLASS GENERAL_REGS - -#define REG_CLASS_FROM_LETTER(C) \ - ((C) == 'b' ? NOSP_REGS : \ - (C) == 'l' ? LO_REGS : \ - (C) == 'h' ? HI_REGS : \ - (C) == 'k' ? HILO_REGS : \ - NO_REGS) - -#define REGNO_OK_FOR_BASE_P(REGNO) \ - ((REGNO) < 16 \ - || (reg_renumber && (unsigned)reg_renumber[REGNO] < 16)) - -#define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P(REGNO) - -#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X) \ - crx_secondary_reload_class (CLASS, MODE, X) - -#define CLASS_MAX_NREGS(CLASS, MODE) \ - (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD - -#define SIGNED_INT_FITS_N_BITS(imm, N) \ - ((((imm) < ((long long)1<<((N)-1))) && ((imm) >= -((long long)1<<((N)-1)))) ? 1 : 0) - -#define UNSIGNED_INT_FITS_N_BITS(imm, N) \ - (((imm) < ((long long)1<<(N)) && (imm) >= (long long)0) ? 1 : 0) - -#define HILO_REGNO_P(regno) \ - (reg_classes_intersect_p(REGNO_REG_CLASS(regno), HILO_REGS)) - -#define INT_CST4(VALUE) \ - (((VALUE) >= -1 && (VALUE) <= 4) || (VALUE) == -4 \ - || (VALUE) == 7 || (VALUE) == 8 || (VALUE) == 16 || (VALUE) == 32 \ - || (VALUE) == 20 || (VALUE) == 12 || (VALUE) == 48) - -#define CONST_OK_FOR_LETTER_P(VALUE, C) \ - /* Legal const for store immediate instructions */ \ - ((C) == 'I' ? UNSIGNED_INT_FITS_N_BITS(VALUE, 3) : \ - (C) == 'J' ? UNSIGNED_INT_FITS_N_BITS(VALUE, 4) : \ - (C) == 'K' ? UNSIGNED_INT_FITS_N_BITS(VALUE, 5) : \ - (C) == 'L' ? INT_CST4(VALUE) : \ - 0) - -#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ - ((C) == 'G' ? crx_const_double_ok (VALUE) : \ - 0) - -/*****************************************************************************/ -/* STACK LAYOUT AND CALLING CONVENTIONS. */ -/*****************************************************************************/ - -#define STACK_GROWS_DOWNWARD - -#define STARTING_FRAME_OFFSET 0 - -#define STACK_POINTER_REGNUM 15 - -#define FRAME_POINTER_REGNUM 13 - -#define ARG_POINTER_REGNUM 12 - -#define STATIC_CHAIN_REGNUM 1 - -#define RETURN_ADDRESS_REGNUM 14 - -#define FIRST_PARM_OFFSET(FNDECL) 0 - -#define ELIMINABLE_REGS \ - { \ - { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ - { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ - { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM} \ - } - -#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ - do { \ - (OFFSET) = crx_initial_elimination_offset ((FROM), (TO)); \ - } while (0) - -/*****************************************************************************/ -/* PASSING FUNCTION ARGUMENTS */ -/*****************************************************************************/ - -#define ACCUMULATE_OUTGOING_ARGS (TARGET_NO_PUSH_ARGS) - -#define PUSH_ARGS (!TARGET_NO_PUSH_ARGS) - -#define PUSH_ROUNDING(BYTES) (((BYTES) + 3) & ~3) - -#ifndef CUMULATIVE_ARGS -struct cumulative_args -{ - int ints; -}; - -#define CUMULATIVE_ARGS struct cumulative_args -#endif - -/* On the CRX architecture, Varargs routines should receive their parameters on - * the stack. */ - -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ - crx_init_cumulative_args(&(CUM), (FNTYPE), (LIBNAME)) - -#define FUNCTION_ARG_REGNO_P(REGNO) crx_function_arg_regno_p(REGNO) - -/*****************************************************************************/ -/* RETURNING FUNCTION VALUE */ -/*****************************************************************************/ - -/* On the CRX, the return value is in R0 */ - -#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(N) ((N) == 0) - -#define CRX_STRUCT_VALUE_REGNUM 0 - -/*****************************************************************************/ -/* GENERATING CODE FOR PROFILING - NOT IMPLEMENTED */ -/*****************************************************************************/ - -#undef FUNCTION_PROFILER -#define FUNCTION_PROFILER(STREAM, LABELNO) \ -{ \ - sorry ("profiler support for CRX"); \ -} - -/*****************************************************************************/ -/* TRAMPOLINES FOR NESTED FUNCTIONS - NOT SUPPORTED */ -/*****************************************************************************/ - -#define TRAMPOLINE_SIZE 32 - -/*****************************************************************************/ -/* ADDRESSING MODES */ -/*****************************************************************************/ - -#define CONSTANT_ADDRESS_P(X) \ - (GET_CODE (X) == LABEL_REF \ - || GET_CODE (X) == SYMBOL_REF \ - || GET_CODE (X) == CONST \ - || GET_CODE (X) == CONST_INT) - -#define MAX_REGS_PER_ADDRESS 2 - -#define HAVE_POST_INCREMENT 1 -#define HAVE_POST_DECREMENT 1 -#define HAVE_POST_MODIFY_DISP 1 -#define HAVE_POST_MODIFY_REG 0 - -#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)) -#else -#define REG_OK_FOR_BASE_P(X) 1 -#define REG_OK_FOR_INDEX_P(X) 1 -#endif /* REG_OK_STRICT */ - -#define LEGITIMATE_CONSTANT_P(X) 1 - -/*****************************************************************************/ -/* CONDITION CODE STATUS */ -/*****************************************************************************/ - -/*****************************************************************************/ -/* RELATIVE COSTS OF OPERATIONS */ -/*****************************************************************************/ - -#define MEMORY_MOVE_COST(MODE, CLASS, IN) crx_memory_move_cost(MODE, CLASS, IN) -/* Moving to processor register flushes pipeline - thus asymmetric */ -#define REGISTER_MOVE_COST(MODE, FROM, TO) ((TO != GENERAL_REGS) ? 8 : 2) -/* Assume best case (branch predicted) */ -#define BRANCH_COST(speed_p, predictable_p) 2 - -#define SLOW_BYTE_ACCESS 1 - -/*****************************************************************************/ -/* DIVIDING THE OUTPUT INTO SECTIONS */ -/*****************************************************************************/ - -#define TEXT_SECTION_ASM_OP "\t.section\t.text" - -#define DATA_SECTION_ASM_OP "\t.section\t.data" - -#define BSS_SECTION_ASM_OP "\t.section\t.bss" - -/*****************************************************************************/ -/* POSITION INDEPENDENT CODE */ -/*****************************************************************************/ - -#define PIC_OFFSET_TABLE_REGNUM 12 - -#define LEGITIMATE_PIC_OPERAND_P(X) 1 - -/*****************************************************************************/ -/* ASSEMBLER FORMAT */ -/*****************************************************************************/ - -#define GLOBAL_ASM_OP "\t.globl\t" - -#undef USER_LABEL_PREFIX -#define USER_LABEL_PREFIX "_" - -#undef ASM_OUTPUT_LABELREF -#define ASM_OUTPUT_LABELREF(STREAM, NAME) \ - asm_fprintf (STREAM, "%U%s", (*targetm.strip_name_encoding) (NAME)); - -#undef ASM_APP_ON -#define ASM_APP_ON "#APP\n" - -#undef ASM_APP_OFF -#define ASM_APP_OFF "#NO_APP\n" - -/*****************************************************************************/ -/* INSTRUCTION OUTPUT */ -/*****************************************************************************/ - -#define REGISTER_NAMES \ - { \ - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ - "r8", "r9", "r10", "r11", "r12", "r13", "ra", "sp", \ - "lo", "hi", "cc" \ - } - -#define PRINT_OPERAND(STREAM, X, CODE) \ - crx_print_operand(STREAM, X, CODE) - -#define PRINT_OPERAND_ADDRESS(STREAM, ADDR) \ - crx_print_operand_address(STREAM, ADDR) - -/*****************************************************************************/ -/* OUTPUT OF DISPATCH TABLES */ -/*****************************************************************************/ - -#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \ - asm_fprintf ((STREAM), "\t.long\t.L%d\n", (VALUE)) - -/*****************************************************************************/ -/* ALIGNMENT IN ASSEMBLER FILE */ -/*****************************************************************************/ - -#define ASM_OUTPUT_ALIGN(STREAM, POWER) \ - asm_fprintf ((STREAM), "\t.align\t%d\n", 1 << (POWER)) - -/*****************************************************************************/ -/* MISCELLANEOUS PARAMETERS */ -/*****************************************************************************/ - -#define CASE_VECTOR_MODE Pmode - -#define MOVE_MAX 4 - -#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 - -#define STORE_FLAG_VALUE 1 - -#define Pmode SImode - -#define FUNCTION_MODE QImode - -#endif /* ! GCC_CRX_H */ diff --git a/gcc/config/crx/crx.md b/gcc/config/crx/crx.md deleted file mode 100644 index 229e345d32f..00000000000 --- a/gcc/config/crx/crx.md +++ /dev/null @@ -1,899 +0,0 @@ -;; GCC machine description for CRX. -;; Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -;; 2001, 2002, 2003, 2004, 2007 -;; Free Software Foundation, Inc. -;; -;; This file is part of GCC. -;; -;; GCC 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 3, or (at your option) -;; any later version. -;; -;; GCC 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 GCC; see the file COPYING3. If not see -;; <http://www.gnu.org/licenses/>. */ - -;; Register numbers - -(define_constants - [(SP_REGNUM 15) ; Stack pointer - (RA_REGNUM 14) ; Return address - (LO_REGNUM 16) ; LO register - (HI_REGNUM 17) ; HI register - (CC_REGNUM 18) ; Condition code register - ] -) - -(define_attr "length" "" ( const_int 6 )) - -(define_asm_attributes - [(set_attr "length" "6")] -) - -;; Predicates - -(define_predicate "u4bits_operand" - (match_code "const_int,const_double") - { - if (GET_CODE (op) == CONST_DOUBLE) - return crx_const_double_ok (op); - return (UNSIGNED_INT_FITS_N_BITS(INTVAL(op), 4)) ? 1 : 0; - } -) - -(define_predicate "cst4_operand" - (and (match_code "const_int") - (match_test "INT_CST4(INTVAL(op))"))) - -(define_predicate "reg_or_u4bits_operand" - (ior (match_operand 0 "u4bits_operand") - (match_operand 0 "register_operand"))) - -(define_predicate "reg_or_cst4_operand" - (ior (match_operand 0 "cst4_operand") - (match_operand 0 "register_operand"))) - -(define_predicate "reg_or_sym_operand" - (ior (match_code "symbol_ref") - (match_operand 0 "register_operand"))) - -(define_predicate "cc_reg_operand" - (and (match_code "reg") - (match_test "REGNO (op) == CC_REGNUM"))) - -(define_predicate "nosp_reg_operand" - (and (match_operand 0 "register_operand") - (match_test "REGNO (op) != SP_REGNUM"))) - -(define_predicate "store_operand" - (and (match_operand 0 "memory_operand") - (not (match_operand 0 "push_operand")))) - -;; Mode Macro Definitions - -(define_mode_iterator ALLMT [QI HI SI SF DI DF]) -(define_mode_iterator CRXMM [QI HI SI SF]) -(define_mode_iterator CRXIM [QI HI SI]) -(define_mode_iterator DIDFM [DI DF]) -(define_mode_iterator SISFM [SI SF]) -(define_mode_iterator SHORT [QI HI]) - -(define_mode_attr tIsa [(QI "b") (HI "w") (SI "d") (SF "d")]) -(define_mode_attr lImmArith [(QI "4") (HI "4") (SI "6")]) -(define_mode_attr lImmRotl [(QI "2") (HI "2") (SI "4")]) -(define_mode_attr IJK [(QI "I") (HI "J") (SI "K")]) -(define_mode_attr iF [(QI "i") (HI "i") (SI "i") (DI "i") (SF "F") (DF "F")]) -(define_mode_attr JG [(QI "J") (HI "J") (SI "J") (DI "J") (SF "G") (DF "G")]) -; In HI or QI mode we push 4 bytes. -(define_mode_attr pushCnstr [(QI "X") (HI "X") (SI "<") (SF "<") (DI "<") (DF "<")]) -(define_mode_attr tpush [(QI "") (HI "") (SI "") (SF "") (DI "sp, ") (DF "sp, ")]) -(define_mode_attr lpush [(QI "2") (HI "2") (SI "2") (SF "2") (DI "4") (DF "4")]) - - -;; Code Macro Definitions - -(define_code_iterator sz_xtnd [sign_extend zero_extend]) -(define_code_attr sIsa [(sign_extend "") (zero_extend "u")]) -(define_code_attr sPat [(sign_extend "s") (zero_extend "u")]) -(define_code_attr szPat [(sign_extend "") (zero_extend "zero_")]) -(define_code_attr szIsa [(sign_extend "s") (zero_extend "z")]) - -(define_code_iterator sh_oprnd [ashift ashiftrt lshiftrt]) -(define_code_attr shIsa [(ashift "ll") (ashiftrt "ra") (lshiftrt "rl")]) -(define_code_attr shPat [(ashift "ashl") (ashiftrt "ashr") (lshiftrt "lshr")]) - -(define_code_iterator mima_oprnd [smax umax smin umin]) -(define_code_attr mimaIsa [(smax "maxs") (umax "maxu") (smin "mins") (umin "minu")]) - -;; Addition Instructions - -(define_insn "adddi3" - [(set (match_operand:DI 0 "register_operand" "=r,r") - (plus:DI (match_operand:DI 1 "register_operand" "%0,0") - (match_operand:DI 2 "nonmemory_operand" "r,i"))) - (clobber (reg:CC CC_REGNUM))] - "" - "addd\t%L2, %L1\;addcd\t%H2, %H1" - [(set_attr "length" "4,12")] -) - -(define_insn "add<mode>3" - [(set (match_operand:CRXIM 0 "register_operand" "=r,r") - (plus:CRXIM (match_operand:CRXIM 1 "register_operand" "%0,0") - (match_operand:CRXIM 2 "nonmemory_operand" "r,i"))) - (clobber (reg:CC CC_REGNUM))] - "" - "add<tIsa>\t%2, %0" - [(set_attr "length" "2,<lImmArith>")] -) - -;; Subtract Instructions - -(define_insn "subdi3" - [(set (match_operand:DI 0 "register_operand" "=r,r") - (minus:DI (match_operand:DI 1 "register_operand" "0,0") - (match_operand:DI 2 "nonmemory_operand" "r,i"))) - (clobber (reg:CC CC_REGNUM))] - "" - "subd\t%L2, %L1\;subcd\t%H2, %H1" - [(set_attr "length" "4,12")] -) - -(define_insn "sub<mode>3" - [(set (match_operand:CRXIM 0 "register_operand" "=r,r") - (minus:CRXIM (match_operand:CRXIM 1 "register_operand" "0,0") - (match_operand:CRXIM 2 "nonmemory_operand" "r,i"))) - (clobber (reg:CC CC_REGNUM))] - "" - "sub<tIsa>\t%2, %0" - [(set_attr "length" "2,<lImmArith>")] -) - -;; Multiply Instructions - -(define_insn "mul<mode>3" - [(set (match_operand:CRXIM 0 "register_operand" "=r,r") - (mult:CRXIM (match_operand:CRXIM 1 "register_operand" "%0,0") - (match_operand:CRXIM 2 "nonmemory_operand" "r,i"))) - (clobber (reg:CC CC_REGNUM))] - "" - "mul<tIsa>\t%2, %0" - [(set_attr "length" "2,<lImmArith>")] -) - -;; Widening-multiplication Instructions - -(define_insn "<sIsa>mulsidi3" - [(set (match_operand:DI 0 "register_operand" "=k") - (mult:DI (sz_xtnd:DI (match_operand:SI 1 "register_operand" "%r")) - (sz_xtnd:DI (match_operand:SI 2 "register_operand" "r")))) - (clobber (reg:CC CC_REGNUM))] - "" - "mull<sPat>d\t%2, %1" - [(set_attr "length" "4")] -) - -(define_insn "<sIsa>mulhisi3" - [(set (match_operand:SI 0 "register_operand" "=r") - (mult:SI (sz_xtnd:SI (match_operand:HI 1 "register_operand" "%0")) - (sz_xtnd:SI (match_operand:HI 2 "register_operand" "r")))) - (clobber (reg:CC CC_REGNUM))] - "" - "mul<sPat>wd\t%2, %0" - [(set_attr "length" "4")] -) - -(define_insn "<sIsa>mulqihi3" - [(set (match_operand:HI 0 "register_operand" "=r") - (mult:HI (sz_xtnd:HI (match_operand:QI 1 "register_operand" "%0")) - (sz_xtnd:HI (match_operand:QI 2 "register_operand" "r")))) - (clobber (reg:CC CC_REGNUM))] - "" - "mul<sPat>bw\t%2, %0" - [(set_attr "length" "4")] -) - -;; Logical Instructions - and - -(define_insn "and<mode>3" - [(set (match_operand:CRXIM 0 "register_operand" "=r,r") - (and:CRXIM (match_operand:CRXIM 1 "register_operand" "%0,0") - (match_operand:CRXIM 2 "nonmemory_operand" "r,i"))) - (clobber (reg:CC CC_REGNUM))] - "" - "and<tIsa>\t%2, %0" - [(set_attr "length" "2,<lImmArith>")] -) - -;; Logical Instructions - or - -(define_insn "ior<mode>3" - [(set (match_operand:CRXIM 0 "register_operand" "=r,r") - (ior:CRXIM (match_operand:CRXIM 1 "register_operand" "%0,0") - (match_operand:CRXIM 2 "nonmemory_operand" "r,i"))) - (clobber (reg:CC CC_REGNUM))] - "" - "or<tIsa>\t%2, %0" - [(set_attr "length" "2,<lImmArith>")] -) - -;; Logical Instructions - xor - -(define_insn "xor<mode>3" - [(set (match_operand:CRXIM 0 "register_operand" "=r,r") - (xor:CRXIM (match_operand:CRXIM 1 "register_operand" "%0,0") - (match_operand:CRXIM 2 "nonmemory_operand" "r,i"))) - (clobber (reg:CC CC_REGNUM))] - "" - "xor<tIsa>\t%2, %0" - [(set_attr "length" "2,<lImmArith>")] -) - -;; Sign and Zero Extend Instructions - -(define_insn "<szPat>extendhisi2" - [(set (match_operand:SI 0 "register_operand" "=r") - (sz_xtnd:SI (match_operand:HI 1 "register_operand" "r"))) - (clobber (reg:CC CC_REGNUM))] - "" - "<szIsa>extwd\t%1, %0" - [(set_attr "length" "4")] -) - -(define_insn "<szPat>extendqisi2" - [(set (match_operand:SI 0 "register_operand" "=r") - (sz_xtnd:SI (match_operand:QI 1 "register_operand" "r"))) - (clobber (reg:CC CC_REGNUM))] - "" - "<szIsa>extbd\t%1, %0" - [(set_attr "length" "4")] -) - -(define_insn "<szPat>extendqihi2" - [(set (match_operand:HI 0 "register_operand" "=r") - (sz_xtnd:HI (match_operand:QI 1 "register_operand" "r"))) - (clobber (reg:CC CC_REGNUM))] - "" - "<szIsa>extbw\t%1, %0" - [(set_attr "length" "4")] -) - -;; Negation Instructions - -(define_insn "neg<mode>2" - [(set (match_operand:CRXIM 0 "register_operand" "=r") - (neg:CRXIM (match_operand:CRXIM 1 "register_operand" "r"))) - (clobber (reg:CC CC_REGNUM))] - "" - "neg<tIsa>\t%1, %0" - [(set_attr "length" "4")] -) - -;; Absolute Instructions - -(define_insn "abs<mode>2" - [(set (match_operand:CRXIM 0 "register_operand" "=r") - (abs:CRXIM (match_operand:CRXIM 1 "register_operand" "r"))) - (clobber (reg:CC CC_REGNUM))] - "" - "abs<tIsa>\t%1, %0" - [(set_attr "length" "4")] -) - -;; Max and Min Instructions - -(define_insn "<code><mode>3" - [(set (match_operand:CRXIM 0 "register_operand" "=r") - (mima_oprnd:CRXIM (match_operand:CRXIM 1 "register_operand" "%0") - (match_operand:CRXIM 2 "register_operand" "r")))] - "" - "<mimaIsa><tIsa>\t%2, %0" - [(set_attr "length" "4")] -) - -;; One's Complement - -(define_insn "one_cmpl<mode>2" - [(set (match_operand:CRXIM 0 "register_operand" "=r") - (not:CRXIM (match_operand:CRXIM 1 "register_operand" "0"))) - (clobber (reg:CC CC_REGNUM))] - "" - "xor<tIsa>\t$-1, %0" - [(set_attr "length" "2")] -) - -;; Rotate Instructions - -(define_insn "rotl<mode>3" - [(set (match_operand:CRXIM 0 "register_operand" "=r,r") - (rotate:CRXIM (match_operand:CRXIM 1 "register_operand" "0,0") - (match_operand:CRXIM 2 "nonmemory_operand" "r,<IJK>"))) - (clobber (reg:CC CC_REGNUM))] - "" - "@ - rotl<tIsa>\t%2, %0 - rot<tIsa>\t%2, %0" - [(set_attr "length" "4,<lImmRotl>")] -) - -(define_insn "rotr<mode>3" - [(set (match_operand:CRXIM 0 "register_operand" "=r") - (rotatert:CRXIM (match_operand:CRXIM 1 "register_operand" "0") - (match_operand:CRXIM 2 "register_operand" "r"))) - (clobber (reg:CC CC_REGNUM))] - "" - "rotr<tIsa>\t%2, %0" - [(set_attr "length" "4")] -) - -;; Arithmetic Left and Right Shift Instructions - -(define_insn "<shPat><mode>3" - [(set (match_operand:CRXIM 0 "register_operand" "=r,r") - (sh_oprnd:CRXIM (match_operand:CRXIM 1 "register_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "r,<IJK>"))) - (clobber (reg:CC CC_REGNUM))] - "" - "s<shIsa><tIsa>\t%2, %0" - [(set_attr "length" "2,2")] -) - -;; Bit Set Instructions - -(define_insn "extv" - [(set (match_operand:SI 0 "register_operand" "=r") - (sign_extract:SI (match_operand:SI 1 "register_operand" "r") - (match_operand:SI 2 "const_int_operand" "n") - (match_operand:SI 3 "const_int_operand" "n")))] - "" - { - static char buf[100]; - int strpntr; - int size = INTVAL (operands[2]); - int pos = INTVAL (operands[3]); - strpntr = sprintf (buf, "ram\t$%d, $31, $%d, %%1, %%0\;", - BITS_PER_WORD - (size + pos), BITS_PER_WORD - size); - sprintf (buf + strpntr, "srad\t$%d, %%0", BITS_PER_WORD - size); - return buf; - } - [(set_attr "length" "6")] -) - -(define_insn "extzv" - [(set (match_operand:SI 0 "register_operand" "=r") - (zero_extract:SI (match_operand:SI 1 "register_operand" "r") - (match_operand:SI 2 "const_int_operand" "n") - (match_operand:SI 3 "const_int_operand" "n")))] - "" - { - static char buf[40]; - int size = INTVAL (operands[2]); - int pos = INTVAL (operands[3]); - sprintf (buf, "ram\t$%d, $%d, $0, %%1, %%0", - (BITS_PER_WORD - pos) % BITS_PER_WORD, size - 1); - return buf; - } - [(set_attr "length" "4")] -) - -(define_insn "insv" - [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") - (match_operand:SI 1 "const_int_operand" "n") - (match_operand:SI 2 "const_int_operand" "n")) - (match_operand:SI 3 "register_operand" "r"))] - "" - { - static char buf[40]; - int size = INTVAL (operands[1]); - int pos = INTVAL (operands[2]); - sprintf (buf, "rim\t$%d, $%d, $%d, %%3, %%0", - pos, size + pos - 1, pos); - return buf; - } - [(set_attr "length" "4")] -) - -;; Move Instructions - -(define_expand "mov<mode>" - [(set (match_operand:ALLMT 0 "nonimmediate_operand" "") - (match_operand:ALLMT 1 "general_operand" ""))] - "" - { - if (!(reload_in_progress || reload_completed)) - { - if (!register_operand (operands[0], <MODE>mode)) - { - if (push_operand (operands[0], <MODE>mode) ? - !nosp_reg_operand (operands[1], <MODE>mode) : - !reg_or_u4bits_operand (operands[1], <MODE>mode)) - { - operands[1] = copy_to_mode_reg (<MODE>mode, operands[1]); - } - } - } - } -) - -(define_insn "push<mode>_internal" - [(set (match_operand:ALLMT 0 "push_operand" "=<pushCnstr>") - (match_operand:ALLMT 1 "nosp_reg_operand" "b"))] - "" - "push\t<tpush>%p1" - [(set_attr "length" "<lpush>")] -) - -(define_insn "mov<mode>_regs" - [(set (match_operand:SISFM 0 "register_operand" "=r, r, r, k") - (match_operand:SISFM 1 "nonmemory_operand" "r, <iF>, k, r"))] - "" - "@ - movd\t%1, %0 - movd\t%1, %0 - mfpr\t%1, %0 - mtpr\t%1, %0" - [(set_attr "length" "2,6,4,4")] -) - -(define_insn "mov<mode>_regs" - [(set (match_operand:DIDFM 0 "register_operand" "=r, r, r, k") - (match_operand:DIDFM 1 "nonmemory_operand" "r, <iF>, k, r"))] - "" - { - switch (which_alternative) - { - case 0: if (REGNO (operands[0]) > REGNO (operands[1])) - return "movd\t%H1, %H0\;movd\t%L1, %L0"; - else - return "movd\t%L1, %L0\;movd\t%H1, %H0"; - case 1: return "movd\t%H1, %H0\;movd\t%L1, %L0"; - case 2: return "mfpr\t%H1, %H0\;mfpr\t%L1, %L0"; - case 3: return "mtpr\t%H1, %H0\;mtpr\t%L1, %L0"; - default: gcc_unreachable (); - } - } - [(set_attr "length" "4,12,8,8")] -) - -(define_insn "mov<mode>_regs" ; no HI/QI mode in HILO regs - [(set (match_operand:SHORT 0 "register_operand" "=r, r") - (match_operand:SHORT 1 "nonmemory_operand" "r, i"))] - "" - "mov<tIsa>\t%1, %0" - [(set_attr "length" "2,<lImmArith>")] -) - -(define_insn "mov<mode>_load" - [(set (match_operand:CRXMM 0 "register_operand" "=r") - (match_operand:CRXMM 1 "memory_operand" "m"))] - "" - "load<tIsa>\t%1, %0" - [(set_attr "length" "6")] -) - -(define_insn "mov<mode>_load" - [(set (match_operand:DIDFM 0 "register_operand" "=r") - (match_operand:DIDFM 1 "memory_operand" "m"))] - "" - { - rtx first_dest_reg = gen_rtx_REG (SImode, REGNO (operands[0])); - if (reg_overlap_mentioned_p (first_dest_reg, operands[1])) - return "loadd\t%H1, %H0\;loadd\t%L1, %L0"; - return "loadd\t%L1, %L0\;loadd\t%H1, %H0"; - } - [(set_attr "length" "12")] -) - -(define_insn "mov<mode>_store" - [(set (match_operand:CRXMM 0 "store_operand" "=m, m") - (match_operand:CRXMM 1 "reg_or_u4bits_operand" "r, <JG>"))] - "" - "stor<tIsa>\t%1, %0" - [(set_attr "length" "6")] -) - -(define_insn "mov<mode>_store" - [(set (match_operand:DIDFM 0 "store_operand" "=m, m") - (match_operand:DIDFM 1 "reg_or_u4bits_operand" "r, <JG>"))] - "" - "stord\t%H1, %H0\;stord\t%L1, %L0" - [(set_attr "length" "12")] -) - -;; Movmem Instruction - -(define_expand "movmemsi" - [(use (match_operand:BLK 0 "memory_operand" "")) - (use (match_operand:BLK 1 "memory_operand" "")) - (use (match_operand:SI 2 "nonmemory_operand" "")) - (use (match_operand:SI 3 "const_int_operand" ""))] - "" - { - if (crx_expand_movmem (operands[0], operands[1], operands[2], operands[3])) - DONE; - else - FAIL; - } -) - -;; Compare and Branch Instructions - -(define_insn "cbranchcc4" - [(set (pc) - (if_then_else (match_operator 0 "ordered_comparison_operator" - [(match_operand:CC 1 "cc_reg_operand" "r") - (match_operand 2 "cst4_operand" "L")]) - (label_ref (match_operand 3 "")) - (pc)))] - "" - "b%d0\t%l3" - [(set_attr "length" "6")] -) - -(define_insn "cbranch<mode>4" - [(set (pc) - (if_then_else (match_operator 0 "ordered_comparison_operator" - [(match_operand:CRXIM 1 "register_operand" "r") - (match_operand:CRXIM 2 "reg_or_cst4_operand" "rL")]) - (label_ref (match_operand 3 "" "")) - (pc))) - (clobber (reg:CC CC_REGNUM))] - "" - "cmpb%d0<tIsa>\t%2, %1, %l3" - [(set_attr "length" "6")] -) - - -;; Scond Instructions - -(define_expand "cstore<mode>4" - [(set (reg:CC CC_REGNUM) - (compare:CC (match_operand:CRXIM 2 "register_operand" "") - (match_operand:CRXIM 3 "nonmemory_operand" ""))) - (set (match_operand:SI 0 "register_operand") - (match_operator:SI 1 "ordered_comparison_operator" - [(reg:CC CC_REGNUM) (const_int 0)]))] - "" - "" -) - -(define_insn "cmp<mode>_internal" - [(set (reg:CC CC_REGNUM) - (compare:CC (match_operand:CRXIM 0 "register_operand" "r,r") - (match_operand:CRXIM 1 "nonmemory_operand" "r,i")))] - "" - "cmp<tIsa>\t%1, %0" - [(set_attr "length" "2,<lImmArith>")] -) - -(define_insn "sCOND_internal" - [(set (match_operand:SI 0 "register_operand" "=r") - (match_operator:SI 1 "ordered_comparison_operator" - [(reg:CC CC_REGNUM) (const_int 0)]))] - "" - "s%d1\t%0" - [(set_attr "length" "2")] -) - -;; Jumps and Branches - -(define_insn "indirect_jump_return" - [(parallel - [(set (pc) - (reg:SI RA_REGNUM)) - (return)]) - ] - "reload_completed" - "jump\tra" - [(set_attr "length" "2")] -) - -(define_insn "indirect_jump" - [(set (pc) - (match_operand:SI 0 "reg_or_sym_operand" "r,i"))] - "" - "@ - jump\t%0 - br\t%a0" - [(set_attr "length" "2,6")] -) - -(define_insn "interrupt_return" - [(parallel - [(unspec_volatile [(const_int 0)] 0) - (return)])] - "" - { - return crx_prepare_push_pop_string (1); - } - [(set_attr "length" "14")] -) - -(define_insn "jump_to_imm" - [(set (pc) - (match_operand 0 "immediate_operand" "i"))] - "" - "br\t%c0" - [(set_attr "length" "6")] -) - -(define_insn "jump" - [(set (pc) - (label_ref (match_operand 0 "" "")))] - "" - "br\t%l0" - [(set_attr "length" "6")] -) - -;; Function Prologue and Epilogue - -(define_expand "prologue" - [(const_int 0)] - "" - { - crx_expand_prologue (); - DONE; - } -) - -(define_insn "push_for_prologue" - [(parallel - [(set (reg:SI SP_REGNUM) - (minus:SI (reg:SI SP_REGNUM) - (match_operand:SI 0 "immediate_operand" "i")))])] - "reload_completed" - { - return crx_prepare_push_pop_string (0); - } - [(set_attr "length" "4")] -) - -(define_expand "epilogue" - [(return)] - "" - { - crx_expand_epilogue (); - DONE; - } -) - -(define_insn "pop_and_popret_return" - [(parallel - [(set (reg:SI SP_REGNUM) - (plus:SI (reg:SI SP_REGNUM) - (match_operand:SI 0 "immediate_operand" "i"))) - (use (reg:SI RA_REGNUM)) - (return)]) - ] - "reload_completed" - { - return crx_prepare_push_pop_string (1); - } - [(set_attr "length" "4")] -) - -(define_insn "popret_RA_return" - [(parallel - [(use (reg:SI RA_REGNUM)) - (return)]) - ] - "reload_completed" - "popret\tra" - [(set_attr "length" "2")] -) - -;; Table Jump - -(define_insn "tablejump" - [(set (pc) - (match_operand:SI 0 "register_operand" "r")) - (use (label_ref:SI (match_operand 1 "" "" )))] - "" - "jump\t%0" - [(set_attr "length" "2")] -) - -;; Call Instructions - -(define_expand "call" - [(call (match_operand:QI 0 "memory_operand" "") - (match_operand 1 "" ""))] - "" - { - emit_call_insn (gen_crx_call (operands[0], operands[1])); - DONE; - } -) - -(define_expand "crx_call" - [(parallel - [(call (match_operand:QI 0 "memory_operand" "") - (match_operand 1 "" "")) - (clobber (reg:SI RA_REGNUM))])] - "" - "" -) - -(define_insn "crx_call_insn_branch" - [(call (mem:QI (match_operand:SI 0 "immediate_operand" "i")) - (match_operand 1 "" "")) - (clobber (match_operand:SI 2 "register_operand" "+r"))] - "" - "bal\tra, %a0" - [(set_attr "length" "6")] -) - -(define_insn "crx_call_insn_jump" - [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) - (match_operand 1 "" "")) - (clobber (match_operand:SI 2 "register_operand" "+r"))] - "" - "jal\t%0" - [(set_attr "length" "2")] -) - -(define_insn "crx_call_insn_jalid" - [(call (mem:QI (mem:SI (plus:SI - (match_operand:SI 0 "register_operand" "r") - (match_operand:SI 1 "register_operand" "r")))) - (match_operand 2 "" "")) - (clobber (match_operand:SI 3 "register_operand" "+r"))] - "" - "jalid\t%0, %1" - [(set_attr "length" "4")] -) - -;; Call Value Instructions - -(define_expand "call_value" - [(set (match_operand 0 "general_operand" "") - (call (match_operand:QI 1 "memory_operand" "") - (match_operand 2 "" "")))] - "" - { - emit_call_insn (gen_crx_call_value (operands[0], operands[1], operands[2])); - DONE; - } -) - -(define_expand "crx_call_value" - [(parallel - [(set (match_operand 0 "general_operand" "") - (call (match_operand 1 "memory_operand" "") - (match_operand 2 "" ""))) - (clobber (reg:SI RA_REGNUM))])] - "" - "" -) - -(define_insn "crx_call_value_insn_branch" - [(set (match_operand 0 "" "=g") - (call (mem:QI (match_operand:SI 1 "immediate_operand" "i")) - (match_operand 2 "" ""))) - (clobber (match_operand:SI 3 "register_operand" "+r"))] - "" - "bal\tra, %a1" - [(set_attr "length" "6")] -) - -(define_insn "crx_call_value_insn_jump" - [(set (match_operand 0 "" "=g") - (call (mem:QI (match_operand:SI 1 "register_operand" "r")) - (match_operand 2 "" ""))) - (clobber (match_operand:SI 3 "register_operand" "+r"))] - "" - "jal\t%1" - [(set_attr "length" "2")] -) - -(define_insn "crx_call_value_insn_jalid" - [(set (match_operand 0 "" "=g") - (call (mem:QI (mem:SI (plus:SI - (match_operand:SI 1 "register_operand" "r") - (match_operand:SI 2 "register_operand" "r")))) - (match_operand 3 "" ""))) - (clobber (match_operand:SI 4 "register_operand" "+r"))] - "" - "jalid\t%0, %1" - [(set_attr "length" "4")] -) - -;; Nop - -(define_insn "nop" - [(const_int 0)] - "" - "" -) - -;; Multiply and Accumulate Instructions - -(define_insn "<sPat>madsidi3" - [(set (match_operand:DI 0 "register_operand" "+k") - (plus:DI - (mult:DI (sz_xtnd:DI (match_operand:SI 1 "register_operand" "%r")) - (sz_xtnd:DI (match_operand:SI 2 "register_operand" "r"))) - (match_dup 0))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_MAC" - "mac<sPat>d\t%2, %1" - [(set_attr "length" "4")] -) - -(define_insn "<sPat>madhisi3" - [(set (match_operand:SI 0 "register_operand" "+l") - (plus:SI - (mult:SI (sz_xtnd:SI (match_operand:HI 1 "register_operand" "%r")) - (sz_xtnd:SI (match_operand:HI 2 "register_operand" "r"))) - (match_dup 0))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_MAC" - "mac<sPat>w\t%2, %1" - [(set_attr "length" "4")] -) - -(define_insn "<sPat>madqihi3" - [(set (match_operand:HI 0 "register_operand" "+l") - (plus:HI - (mult:HI (sz_xtnd:HI (match_operand:QI 1 "register_operand" "%r")) - (sz_xtnd:HI (match_operand:QI 2 "register_operand" "r"))) - (match_dup 0))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_MAC" - "mac<sPat>b\t%2, %1" - [(set_attr "length" "4")] -) - -;; Loop Instructions - -(define_expand "doloop_end" - [(use (match_operand 0 "" "")) ; loop pseudo - (use (match_operand 1 "" "")) ; iterations; zero if unknown - (use (match_operand 2 "" "")) ; max iterations - (use (match_operand 3 "" "")) ; loop level - (use (match_operand 4 "" ""))] ; label - "" - { - if (INTVAL (operands[3]) > crx_loop_nesting) - FAIL; - switch (GET_MODE (operands[0])) - { - case SImode: - emit_jump_insn (gen_doloop_end_si (operands[4], operands[0])); - break; - case HImode: - emit_jump_insn (gen_doloop_end_hi (operands[4], operands[0])); - break; - case QImode: - emit_jump_insn (gen_doloop_end_qi (operands[4], operands[0])); - break; - default: - FAIL; - } - DONE; - } -) - -; CRX dbnz[bwd] used explicitly (see above) but also by the combiner. - -(define_insn "doloop_end_<mode>" - [(set (pc) - (if_then_else (ne (match_operand:CRXIM 1 "register_operand" "+r,!m") - (const_int 1)) - (label_ref (match_operand 0 "" "")) - (pc))) - (set (match_dup 1) (plus:CRXIM (match_dup 1) (const_int -1))) - (clobber (match_scratch:CRXIM 2 "=X,r")) - (clobber (reg:CC CC_REGNUM))] - "" - "@ - dbnz<tIsa>\t%1, %l0 - load<tIsa>\t%1, %2\;add<tIsa>\t$-1, %2\;stor<tIsa>\t%2, %1\;bne\t%l0" - [(set_attr "length" "6, 12")] -) diff --git a/gcc/config/crx/crx.opt b/gcc/config/crx/crx.opt deleted file mode 100644 index 7ff0be0e3a9..00000000000 --- a/gcc/config/crx/crx.opt +++ /dev/null @@ -1,34 +0,0 @@ -; Options for the National Semiconductor CRX port of the compiler. - -; Copyright (C) 2005, 2007 Free Software Foundation, Inc. -; -; This file is part of GCC. -; -; GCC 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 3, or (at your option) any later -; version. -; -; GCC 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 GCC; see the file COPYING3. If not see -; <http://www.gnu.org/licenses/>. - -mmac -Target Report Mask(MAC) -Support multiply accumulate instructions - -mno-push-args -Target Report RejectNegative Mask(NO_PUSH_ARGS) -Do not use push to store function arguments - -mloop-nesting= -Common RejectNegative Joined UInteger Var(crx_loop_nesting) Init(12) -Restrict doloop to the given nesting level - -mdebug-addr -Target RejectNegative Var(TARGET_DEBUG_ADDR) Undocumented diff --git a/gcc/config/crx/t-crx b/gcc/config/crx/t-crx deleted file mode 100644 index 8bb62c6525f..00000000000 --- a/gcc/config/crx/t-crx +++ /dev/null @@ -1,37 +0,0 @@ -# CRX Target Makefile -# -# Copyright (C) 2005 Free Software Foundation, Inc. -# -# This file is part of GCC. -# -# GCC 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 3, or (at your option) -# any later version. -# -# GCC 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 GCC; see the file COPYING3. If not see -# <http://www.gnu.org/licenses/>. - -# Mingw specific compilation fixes -USE_COLLECT2 = -STMP_FIXINC = - -# Software emulation for integer div and mod -LIB2FUNCS_EXTRA = $(srcdir)/config/udivmodsi4.c $(srcdir)/config/udivmod.c $(srcdir)/config/divmod.c - -# 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 - cat $(srcdir)/config/fp-bit.c >> fp-bit.c - -dp-bit.c: $(srcdir)/config/fp-bit.c - cat $(srcdir)/config/fp-bit.c > dp-bit.c diff --git a/gcc/config/i386/netbsd.h b/gcc/config/i386/netbsd.h deleted file mode 100644 index 318951a770a..00000000000 --- a/gcc/config/i386/netbsd.h +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2004 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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 3, or (at your option) any later -version. - -GCC 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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -<http://www.gnu.org/licenses/>. */ - -#define TARGET_OS_CPP_BUILTINS() \ - do \ - { \ - NETBSD_OS_CPP_BUILTINS_AOUT(); \ - } \ - while (0) - -#define TARGET_VERSION fprintf (stderr, " (NetBSD/i386 a.out)"); - -/* This goes away when the math-emulator is fixed */ -#undef TARGET_SUBTARGET_DEFAULT -#define TARGET_SUBTARGET_DEFAULT \ - (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_NO_FANCY_MATH_387) - -#undef SUBTARGET_EXTRA_SPECS -#define SUBTARGET_EXTRA_SPECS \ - { "netbsd_cpp_spec", NETBSD_CPP_SPEC }, - -#undef CPP_SPEC -#define CPP_SPEC "%(netbsd_cpp_spec)" - - -#undef SIZE_TYPE -#define SIZE_TYPE "unsigned int" - -#undef PTRDIFF_TYPE -#define PTRDIFF_TYPE "int" - -#undef ASM_APP_ON -#define ASM_APP_ON "#APP\n" - -#undef ASM_APP_OFF -#define ASM_APP_OFF "#NO_APP\n" - -/* Don't default to pcc-struct-return, because gcc is the only compiler, and - we want to retain compatibility with older gcc versions. */ -#define DEFAULT_PCC_STRUCT_RETURN 0 - -/* i386 netbsd still uses old binutils that don't insert nops by default - when the .align directive demands to insert extra space in the text - segment. */ -#undef ASM_OUTPUT_ALIGN -#define ASM_OUTPUT_ALIGN(FILE,LOG) \ - if ((LOG)!=0) fprintf ((FILE), "\t.align %d,0x90\n", (LOG)) - -/* Profiling routines, partially copied from i386/osfrose.h. */ - -/* Redefine this to use %eax instead of %edx. */ -#undef FUNCTION_PROFILER -#define FUNCTION_PROFILER(FILE, LABELNO) \ -{ \ - if (flag_pic) \ - { \ - fprintf (FILE, "\tcall mcount@PLT\n"); \ - } \ - else \ - { \ - fprintf (FILE, "\tcall mcount\n"); \ - } \ -} - -/* Until they use ELF or something that handles dwarf2 unwinds - and initialization stuff better. */ -#define DWARF2_UNWIND_INFO 0 - -/* Redefine this so that it becomes "_GLOBAL_OFFSET_TABLE_" when the label - prefix is added. */ -#undef GOT_SYMBOL_NAME -#define GOT_SYMBOL_NAME "GLOBAL_OFFSET_TABLE_" - -/* Attempt to enable execute permissions on the stack. */ -#define ENABLE_EXECUTE_STACK NETBSD_ENABLE_EXECUTE_STACK diff --git a/gcc/config/m68hc11/larith.asm b/gcc/config/m68hc11/larith.asm deleted file mode 100644 index 09f946cbf90..00000000000 --- a/gcc/config/m68hc11/larith.asm +++ /dev/null @@ -1,1333 +0,0 @@ -/* libgcc routines for M68HC11 & M68HC12. - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2008, 2009 - Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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 3, or (at your option) any -later version. - -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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -<http://www.gnu.org/licenses/>. */ - -#ifdef __HAVE_SHORT_INT__ - .mode mshort -#else - .mode mlong -#endif - - .macro declare_near name - .globl \name - .type \name,@function - .size \name,.Lend-\name -\name: - .endm - -#if defined(__USE_RTC__) -# define ARG(N) N+1 - - .macro ret -#if defined(mc68hc12) - rtc -#else - jmp __return_32 -#endif - .endm - - .macro declare name - .globl \name - .type \name,@function - .size \name,.Lend-\name - .far \name -\name: - .endm - - .macro farsym name - .far NAME - .endm - -#else -# define ARG(N) N - - .macro ret - rts - .endm - - .macro farsym name - .endm - - .macro declare name - .globl \name - .type \name,@function - .size \name,.Lend-\name -\name: - .endm - -#endif - - .sect .text - - -#define REG(NAME) \ -NAME: .dc.w 1; \ - .type NAME,@object ; \ - .size NAME,2 - -#ifdef L_regs_min -/* Pseudo hard registers used by gcc. - They should be located in page0. */ - - .sect .softregs - .globl _.tmp - .globl _.z,_.xy -REG(_.tmp) -REG(_.z) -REG(_.xy) - -#endif - -#ifdef L_regs_frame - .sect .softregs - .globl _.frame -REG(_.frame) -#endif - -#ifdef L_regs_d1_2 - .sect .softregs - .globl _.d1,_.d2 -REG(_.d1) -REG(_.d2) -#endif - -#ifdef L_regs_d3_4 - .sect .softregs - .globl _.d3,_.d4 -REG(_.d3) -REG(_.d4) -#endif - -#ifdef L_regs_d5_6 - .sect .softregs - .globl _.d5,_.d6 -REG(_.d5) -REG(_.d6) -#endif - -#ifdef L_regs_d7_8 - .sect .softregs - .globl _.d7,_.d8 -REG(_.d7) -REG(_.d8) -#endif - -#ifdef L_regs_d9_16 -/* Pseudo hard registers used by gcc. - They should be located in page0. */ - .sect .softregs - .globl _.d9,_.d10,_.d11,_.d12,_.d13,_.d14 - .globl _.d15,_.d16 -REG(_.d9) -REG(_.d10) -REG(_.d11) -REG(_.d12) -REG(_.d13) -REG(_.d14) -REG(_.d15) -REG(_.d16) - -#endif - -#ifdef L_regs_d17_32 -/* Pseudo hard registers used by gcc. - They should be located in page0. */ - .sect .softregs - .globl _.d17,_.d18,_.d19,_.d20,_.d21,_.d22 - .globl _.d23,_.d24,_.d25,_.d26,_.d27,_.d28 - .globl _.d29,_.d30,_.d31,_.d32 -REG(_.d17) -REG(_.d18) -REG(_.d19) -REG(_.d20) -REG(_.d21) -REG(_.d22) -REG(_.d23) -REG(_.d24) -REG(_.d25) -REG(_.d26) -REG(_.d27) -REG(_.d28) -REG(_.d29) -REG(_.d30) -REG(_.d31) -REG(_.d32) -#endif - -#ifdef L_premain -;; -;; Specific initialization for 68hc11 before the main. -;; Nothing special for a generic routine; Just enable interrupts. -;; - declare_near __premain - clra - tap ; Clear both I and X. - rts -#endif - -#ifdef L__exit -;; -;; Exit operation. Just loop forever and wait for interrupts. -;; (no other place to go) -;; This operation is split in several pieces collected together by -;; the linker script. This allows to support destructors at the -;; exit stage while not impacting program sizes when there is no -;; destructors. -;; -;; _exit: -;; *(.fini0) /* Beginning of finish code (_exit symbol). */ -;; *(.fini1) /* Place holder for applications. */ -;; *(.fini2) /* C++ destructors. */ -;; *(.fini3) /* Place holder for applications. */ -;; *(.fini4) /* Runtime exit. */ -;; - .sect .fini0,"ax",@progbits - .globl _exit - .globl exit - .weak exit - farsym exit - farsym _exit -exit: -_exit: - - .sect .fini4,"ax",@progbits -fatal: - cli - wai - bra fatal -#endif - -#ifdef L_abort -;; -;; Abort operation. This is defined for the GCC testsuite. -;; - declare abort - - ldd #255 ; -#ifdef mc68hc12 - trap #0x30 -#else - .byte 0xCD ; Generate an illegal instruction trap - .byte 0x03 ; The simulator catches this and stops. -#endif - jmp _exit -#endif - -#ifdef L_cleanup -;; -;; Cleanup operation used by exit(). -;; - declare _cleanup - - ret -#endif - -;----------------------------------------- -; required gcclib code -;----------------------------------------- -#ifdef L_memcpy - declare memcpy - declare __memcpy - - .weak memcpy -;;; -;;; void* memcpy(void*, const void*, size_t) -;;; -;;; D = dst Pmode -;;; 2,sp = src Pmode -;;; 4,sp = size HImode (size_t) -;;; -#ifdef mc68hc12 - ldx ARG(2),sp - ldy ARG(4),sp - pshd - xgdy - lsrd - bcc Start - movb 1,x+,1,y+ -Start: - beq Done -Loop: - movw 2,x+,2,y+ - dbne d,Loop -Done: - puld - ret -#else - xgdy - tsx - ldd ARG(4),x - ldx ARG(2),x ; SRC = X, DST = Y - cpd #0 - beq End - pshy - inca ; Correction for the deca below -L0: - psha ; Save high-counter part -L1: - ldaa 0,x ; Copy up to 256 bytes - staa 0,y - inx - iny - decb - bne L1 - pula - deca - bne L0 - puly ; Restore Y to return the DST -End: - xgdy - ret -#endif -#endif - -#ifdef L_memset - declare memset - declare __memset -;;; -;;; void* memset(void*, int value, size_t) -;;; -#ifndef __HAVE_SHORT_INT__ -;;; D = dst Pmode -;;; 2,sp = src SImode -;;; 6,sp = size HImode (size_t) - val = ARG(5) - size = ARG(6) -#else -;;; D = dst Pmode -;;; 2,sp = src SImode -;;; 6,sp = size HImode (size_t) - val = ARG(3) - size = ARG(4) -#endif -#ifdef mc68hc12 - xgdx - ldab val,sp - ldy size,sp - pshx - beq End -Loop: - stab 1,x+ - dbne y,Loop -End: - puld - ret -#else - xgdx - tsy - ldab val,y - ldy size,y ; DST = X, CNT = Y - beq End - pshx -L0: - stab 0,x ; Fill up to 256 bytes - inx - dey - bne L0 - pulx ; Restore X to return the DST -End: - xgdx - ret -#endif -#endif - -#ifdef L_adddi3 - declare ___adddi3 - - tsx - xgdy - ldd ARG(8),x ; Add LSB - addd ARG(16),x - std 6,y ; Save (carry preserved) - - ldd ARG(6),x - adcb ARG(15),x - adca ARG(14),x - std 4,y - - ldd ARG(4),x - adcb ARG(13),x - adca ARG(12),x - std 2,y - - ldd ARG(2),x - adcb ARG(11),x ; Add MSB - adca ARG(10),x - std 0,y - - xgdy - ret -#endif - -#ifdef L_subdi3 - declare ___subdi3 - - tsx - xgdy - ldd ARG(8),x ; Subtract LSB - subd ARG(16),x - std 6,y ; Save, borrow preserved - - ldd ARG(6),x - sbcb ARG(15),x - sbca ARG(14),x - std 4,y - - ldd ARG(4),x - sbcb ARG(13),x - sbca ARG(12),x - std 2,y - - ldd ARG(2),x ; Subtract MSB - sbcb ARG(11),x - sbca ARG(10),x - std 0,y - - xgdy ; - ret -#endif - -#ifdef L_notdi2 - declare ___notdi2 - - tsy - xgdx - ldd ARG(8),y - coma - comb - std 6,x - - ldd ARG(6),y - coma - comb - std 4,x - - ldd ARG(4),y - coma - comb - std 2,x - - ldd ARG(2),y - coma - comb - std 0,x - xgdx - ret -#endif - -#ifdef L_negsi2 - declare_near ___negsi2 - - comb - coma - xgdx - comb - coma - inx - xgdx - bne done - inx -done: - rts -#endif - -#ifdef L_one_cmplsi2 - declare_near ___one_cmplsi2 - - comb - coma - xgdx - comb - coma - xgdx - rts -#endif - -#ifdef L_ashlsi3 - declare_near ___ashlsi3 - - xgdy - clra - andb #0x1f - xgdy - beq Return -Loop: - lsld - xgdx - rolb - rola - xgdx - dey - bne Loop -Return: - rts -#endif - -#ifdef L_ashrsi3 - declare_near ___ashrsi3 - - xgdy - clra - andb #0x1f - xgdy - beq Return -Loop: - xgdx - asra - rorb - xgdx - rora - rorb - dey - bne Loop -Return: - rts -#endif - -#ifdef L_lshrsi3 - declare_near ___lshrsi3 - - xgdy - clra - andb #0x1f - xgdy - beq Return -Loop: - xgdx - lsrd - xgdx - rora - rorb - dey - bne Loop -Return: - rts -#endif - -#ifdef L_lshrhi3 - declare_near ___lshrhi3 - - cpx #16 - bge Return_zero - cpx #0 - beq Return -Loop: - lsrd - dex - bne Loop -Return: - rts -Return_zero: - clra - clrb - rts -#endif - -#ifdef L_lshlhi3 - declare_near ___lshlhi3 - - cpx #16 - bge Return_zero - cpx #0 - beq Return -Loop: - lsld - dex - bne Loop -Return: - rts -Return_zero: - clra - clrb - rts -#endif - -#ifdef L_rotrhi3 - declare_near ___rotrhi3 - -___rotrhi3: - xgdx - clra - andb #0x0f - xgdx - beq Return -Loop: - tap - rorb - rora - dex - bne Loop -Return: - rts -#endif - -#ifdef L_rotlhi3 - declare_near ___rotlhi3 - -___rotlhi3: - xgdx - clra - andb #0x0f - xgdx - beq Return -Loop: - asrb - rolb - rola - rolb - dex - bne Loop -Return: - rts -#endif - -#ifdef L_ashrhi3 - declare_near ___ashrhi3 - - cpx #16 - bge Return_minus_1_or_zero - cpx #0 - beq Return -Loop: - asra - rorb - dex - bne Loop -Return: - rts -Return_minus_1_or_zero: - clrb - tsta - bpl Return_zero - comb -Return_zero: - tba - rts -#endif - -#ifdef L_ashrqi3 - declare_near ___ashrqi3 - - cmpa #8 - bge Return_minus_1_or_zero - tsta - beq Return -Loop: - asrb - deca - bne Loop -Return: - rts -Return_minus_1_or_zero: - clrb - tstb - bpl Return_zero - coma -Return_zero: - tab - rts -#endif - -#ifdef L_lshlqi3 - declare_near ___lshlqi3 - - cmpa #8 - bge Return_zero - tsta - beq Return -Loop: - lslb - deca - bne Loop -Return: - rts -Return_zero: - clrb - rts -#endif - -#ifdef L_divmodhi4 -#ifndef mc68hc12 -/* 68HC12 signed divisions are generated inline (idivs). */ - - declare_near __divmodhi4 - -; -;; D = numerator -;; X = denominator -;; -;; Result: D = D / X -;; X = D % X -;; - tsta - bpl Numerator_pos - comb ; D = -D <=> D = (~D) + 1 - coma - xgdx - inx - tsta - bpl Numerator_neg_denominator_pos -Numerator_neg_denominator_neg: - comb ; X = -X - coma - addd #1 - xgdx - idiv - coma - comb - xgdx ; Remainder <= 0 and result >= 0 - inx - rts - -Numerator_pos_denominator_pos: - xgdx - idiv - xgdx ; Both values are >= 0 - rts - -Numerator_pos: - xgdx - tsta - bpl Numerator_pos_denominator_pos -Numerator_pos_denominator_neg: - coma ; X = -X - comb - xgdx - inx - idiv - xgdx ; Remainder >= 0 but result <= 0 - coma - comb - addd #1 - rts - -Numerator_neg_denominator_pos: - xgdx - idiv - coma ; One value is > 0 and the other < 0 - comb ; Change the sign of result and remainder - xgdx - inx - coma - comb - addd #1 - rts -#endif /* !mc68hc12 */ -#endif - -#ifdef L_mulqi3 - declare_near ___mulqi3 - -; -; short __mulqi3(signed char a, signed char b); -; -; signed char a -> register A -; signed char b -> register B -; -; returns the signed result of A * B in register D. -; - tsta - bmi A_neg - tstb - bmi B_neg - mul - rts -B_neg: - negb - bra A_or_B_neg -A_neg: - nega - tstb - bmi AB_neg -A_or_B_neg: - mul - coma - comb - addd #1 - rts -AB_neg: - negb - mul - rts -#endif - -#ifdef L_mulhi3 - declare_near ___mulhi3 - -; -; -; unsigned short ___mulhi3(unsigned short a, unsigned short b) -; -; a = register D -; b = register X -; -#ifdef mc68hc12 - pshx ; Preserve X - exg x,y - emul - exg x,y - pulx - rts -#else -#ifdef NO_TMP - ; - ; 16-bit multiplication without temp memory location. - ; (smaller but slower) - ; - pshx ; (4) - ins ; (3) - pshb ; (3) - psha ; (3) - pshx ; (4) - pula ; (4) - pulx ; (5) - mul ; (10) B.high * A.low - xgdx ; (3) - mul ; (10) B.low * A.high - abx ; (3) - pula ; (4) - pulb ; (4) - mul ; (10) B.low * A.low - pshx ; (4) - tsx ; (3) - adda 1,x ; (4) - pulx ; (5) - rts ; (5) 20 bytes - ; --- - ; 91 cycles -#else - stx *_.tmp ; (4) - pshb ; (3) - ldab *_.tmp+1 ; (3) - mul ; (10) A.high * B.low - ldaa *_.tmp ; (3) - stab *_.tmp ; (3) - pulb ; (4) - pshb ; (4) - mul ; (10) A.low * B.high - addb *_.tmp ; (4) - stab *_.tmp ; (3) - ldaa *_.tmp+1 ; (3) - pulb ; (4) - mul ; (10) A.low * B.low - adda *_.tmp ; (4) - rts ; (5) 24/32 bytes - ; 77/85 cycles -#endif -#endif -#endif - -#ifdef L_mulhi32 - -; -; -; unsigned long __mulhi32(unsigned short a, unsigned short b) -; -; a = register D -; b = value on stack -; -; +---------------+ -; | B low | <- 7,x -; +---------------+ -; | B high | <- 6,x -; +---------------+ -; | PC low | -; +---------------+ -; | PC high | -; +---------------+ -; | Tmp low | -; +---------------+ -; | Tmp high | -; +---------------+ -; | A low | -; +---------------+ -; | A high | -; +---------------+ <- 0,x -; -; -; <B-low> 5,x -; <B-high> 4,x -; <ret> 2,x -; <A-low> 1,x -; <A-high> 0,x -; - declare_near __mulhi32 - -#ifdef mc68hc12 - ldy 2,sp - emul - exg x,y - rts -#else - pshx ; Room for temp value - pshb - psha - tsx - ldab 6,x - mul - xgdy ; A.high * B.high - ldab 7,x - pula - mul ; A.high * B.low - std 2,x - ldaa 1,x - ldab 6,x - mul ; A.low * B.high - addd 2,x - stab 2,x - tab - aby - bcc N - ldab #0xff - aby - iny -N: - ldab 7,x - pula - mul ; A.low * B.low - adda 2,x - pulx ; Drop temp location - pshy ; Put high part in X - pulx - bcc Ret - inx -Ret: - rts -#endif -#endif - -#ifdef L_mulsi3 - -; -; <B-low> 8,y -; <B-high> 6,y -; <ret> 4,y -; <tmp> 2,y -; <A-low> 0,y -; -; D,X -> A -; Stack -> B -; -; The result is: -; -; (((A.low * B.high) + (A.high * B.low)) << 16) + (A.low * B.low) -; -; -; - - declare __mulsi3 - -#ifdef mc68hc12 - pshd ; Save A.low - ldy ARG(4),sp - emul ; A.low * B.high - ldy ARG(6),sp - exg x,d - emul ; A.high * B.low - leax d,x - ldy ARG(6),sp - puld - emul ; A.low * B.low - exg d,y - leax d,x - exg d,y - ret -#else -B_low = ARG(8) -B_high = ARG(6) -A_low = 0 -A_high = 2 - pshx - pshb - psha - tsy -; -; If B.low is 0, optimize into: (A.low * B.high) << 16 -; - ldd B_low,y - beq B_low_zero -; -; If A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low) -; - cpx #0 - beq A_high_zero - bsr ___mulhi3 ; A.high * B.low -; -; If A.low is 0, optimize into: (A.high * B.low) << 16 -; - ldx A_low,y - beq A_low_zero ; X = 0, D = A.high * B.low - std 2,y -; -; If B.high is 0, we can avoid the (A.low * B.high) << 16 term. -; - ldd B_high,y - beq B_high_zero - bsr ___mulhi3 ; A.low * B.high - addd 2,y - std 2,y -; -; Here, we know that A.low and B.low are not 0. -; -B_high_zero: - ldd B_low,y ; A.low is on the stack - bsr __mulhi32 ; A.low * B.low - xgdx - tsy ; Y was clobbered, get it back - addd 2,y -A_low_zero: ; See A_low_zero_non_optimized below - xgdx -Return: - ins - ins - ins - ins - ret -; -; -; A_low_zero_non_optimized: -; -; At this step, X = 0 and D = (A.high * B.low) -; Optimize into: (A.high * B.low) << 16 -; -; xgdx -; clra ; Since X was 0, clearing D is superfuous. -; clrb -; bra Return -; ---------------- -; B.low == 0, the result is: (A.low * B.high) << 16 -; -; At this step: -; D = B.low = 0 -; X = A.high ? -; A.low is at A_low,y ? -; B.low is at B_low,y ? -; -B_low_zero: - ldd A_low,y - beq Zero1 - ldx B_high,y - beq Zero2 - bsr ___mulhi3 -Zero1: - xgdx -Zero2: - clra - clrb - bra Return -; ---------------- -; A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low) -; -; At this step: -; D = B.low != 0 -; X = A.high = 0 -; A.low is at A_low,y ? -; B.low is at B_low,y ? -; -A_high_zero: - ldd A_low,y ; A.low - beq Zero1 - ldx B_high,y ; B.high - beq A_low_B_low - bsr ___mulhi3 - std 2,y - bra B_high_zero ; Do the (A.low * B.low) and the add. - -; ---------------- -; A.high and B.high are 0 optimize into: (A.low * B.low) -; -; At this step: -; D = B.high = 0 -; X = A.low != 0 -; A.low is at A_low,y != 0 -; B.high is at B_high,y = 0 -; -A_low_B_low: - ldd B_low,y ; A.low is on the stack - bsr __mulhi32 - bra Return -#endif -#endif - -#ifdef L_map_data - - .sect .install2,"ax",@progbits - .globl __map_data_section - .globl __data_image -#ifdef mc68hc12 - .globl __data_section_size -#endif -__map_data_section: -#ifdef mc68hc12 - ldx #__data_image - ldy #__data_section_start - ldd #__data_section_size - beq Done -Loop: - movb 1,x+,1,y+ - dbne d,Loop -#else - ldx #__data_image - ldy #__data_section_start - bra Start_map -Loop: - ldaa 0,x - staa 0,y - inx - iny -Start_map: - cpx #__data_image_end - blo Loop -#endif -Done: - -#endif - -#ifdef L_init_bss - - .sect .install2,"ax",@progbits - .globl __init_bss_section - -__init_bss_section: - ldd #__bss_size - beq Done - ldx #__bss_start -Loop: -#ifdef mc68hc12 - clr 1,x+ - dbne d,Loop -#else - clr 0,x - inx - subd #1 - bne Loop -#endif -Done: - -#endif - -#ifdef L_ctor - -; End of constructor table - .sect .install3,"ax",@progbits - .globl __do_global_ctors - -__do_global_ctors: - ; Start from the end - sizeof(void*) - ldx #__CTOR_END__-2 -ctors_loop: - cpx #__CTOR_LIST__ - blo ctors_done - pshx - ldx 0,x - jsr 0,x - pulx - dex - dex - bra ctors_loop -ctors_done: - -#endif - -#ifdef L_dtor - - .sect .fini3,"ax",@progbits - .globl __do_global_dtors - -;; -;; This piece of code is inserted in the _exit() code by the linker. -;; -__do_global_dtors: - pshb ; Save exit code - psha - ldx #__DTOR_LIST__ -dtors_loop: - cpx #__DTOR_END__ - bhs dtors_done - pshx - ldx 0,x - jsr 0,x - pulx - inx - inx - bra dtors_loop -dtors_done: - pula ; Restore exit code - pulb - -#endif - -#ifdef L_far_tramp -#ifdef mc68hc12 - .sect .tramp,"ax",@progbits - .globl __far_trampoline - -;; This is a trampoline used by the linker to invoke a function -;; using rtc to return and being called with jsr/bsr. -;; The trampoline generated is: -;; -;; foo_tramp: -;; ldy #foo -;; call __far_trampoline,page(foo) -;; -;; The linker transforms: -;; -;; jsr foo -;; -;; into -;; jsr foo_tramp -;; -;; The linker generated trampoline and _far_trampoline must be in -;; non-banked memory. -;; -__far_trampoline: - movb 0,sp, 2,sp ; Copy page register below the caller's return - leas 2,sp ; address. - jmp 0,y ; We have a 'call/rtc' stack layout now - ; and can jump to the far handler - ; (whose memory bank is mapped due to the - ; call to the trampoline). -#endif - -#ifdef mc68hc11 - .sect .tramp,"ax",@progbits - .globl __far_trampoline - -;; Trampoline generated by gcc for 68HC11: -;; -;; pshb -;; ldab #%page(func) -;; ldy #%addr(func) -;; jmp __far_trampoline -;; -__far_trampoline: - psha ; (2) Save function parameter (high) - ;; <Read current page in A> - psha ; (2) - ;; <Set currenge page from B> - pshx ; (4) - tsx ; (3) - ldab 4,x ; (4) Restore function parameter (low) - ldaa 2,x ; (4) Get saved page number - staa 4,x ; (4) Save it below return PC - pulx ; (5) - pula ; (3) - pula ; (3) Restore function parameter (high) - jmp 0,y ; (4) -#endif -#endif - -#ifdef L_call_far -#ifdef mc68hc11 - .sect .tramp,"ax",@progbits - .globl __call_a16 - .globl __call_a32 -;; -;; The call methods are used for 68HC11 to support memory bank switching. -;; Every far call is redirected to these call methods. Its purpose is to: -;; -;; 1/ Save the current page on the stack (1 byte to follow 68HC12 call frame) -;; 2/ Install the new page -;; 3/ Jump to the real function -;; -;; The page switching (get/save) is board dependent. The default provided -;; here does nothing (just create the appropriate call frame). -;; -;; Call sequence (10 bytes, 13 cycles): -;; -;; ldx #page ; (3) -;; ldy #func ; (4) -;; jsr __call_a16 ; (6) -;; -;; Call trampoline (11 bytes, 19 cycles): -;; -__call_a16: - ;; xgdx ; (3) - ;; <Read current page in A> ; (3) ldaa _current_page - psha ; (2) - ;; <Set current page from B> ; (4) staa _current_page - ;; xgdx ; (3) - jmp 0,y ; (4) - -;; -;; Call sequence (10 bytes, 14 cycles): -;; -;; pshb ; (2) -;; ldab #page ; (2) -;; ldy #func ; (4) -;; jsr __call_a32 ; (6) -;; -;; Call trampoline (87 bytes, 57 cycles): -;; -__call_a32: - pshx ; (4) - psha ; (2) - ;; <Read current page in A> ; (3) ldaa _current_page - psha ; (2) - ;; <Set current page from B> ; (4) staa _current_page - tsx ; (3) - ldab 6,x ; (4) Restore function parameter - ldaa 5,x ; (4) Move PC return at good place - staa 6,x ; (4) - ldaa 4,x ; (4) - staa 5,x ; (4) - pula ; (3) - staa 4,x ; (4) - pula ; (3) - pulx ; (5) - jmp 0,y ; (4) -#endif -#endif - -#ifdef L_return_far -#ifdef mc68hc11 - .sect .tramp,"ax",@progbits - .globl __return_void - .globl __return_16 - .globl __return_32 - -__return_void: - ;; pulb - ;; <Set current page from B> (Board specific) - ;; rts -__return_16: - ;; xgdx - ;; pulb - ;; <Set current page from B> (Board specific) - ;; xgdx - ;; rts -__return_32: - ;; xgdy - ;; pulb - ;; <Set current page from B> (Board specific) - ;; xgdy - ;; rts - ins - rts -#endif -#endif -.Lend: -;----------------------------------------- -; end required gcclib code -;----------------------------------------- diff --git a/gcc/config/m68hc11/m68hc11-crt0.S b/gcc/config/m68hc11/m68hc11-crt0.S deleted file mode 100644 index 429ab0f270d..00000000000 --- a/gcc/config/m68hc11/m68hc11-crt0.S +++ /dev/null @@ -1,86 +0,0 @@ -/* Startup code for M68HC11. - Copyright (C) 1999, 2000, 2002, 2008, 2009 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 3, or (at your option) any -later version. - -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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -<http://www.gnu.org/licenses/>. */ - -;----------------------------------------- -; startup code -;----------------------------------------- - -#ifdef __HAVE_SHORT_INT__ - .mode mshort -#else - .mode mlong -#endif - -#if defined(__USE_RTC__) && defined(mc68hc12) - .macro jsr name - call \name - .endm -#endif -;; -;; -;; The linker concatenate the .install* sections in the following order: -;; -;; .install0 Setup the stack pointer -;; .install1 Place holder for applications -;; .install2 Optional installation of data section in memory -;; .install3 Place holder for applications -;; .install4 Invokes the main -;; - .sect .install0,"ax",@progbits - .globl _start - -_start: -;; -;; At this step, the stack is not initialized and interrupts are masked. -;; Applications only have 64 cycles to initialize some registers. -;; -;; To have a generic/configurable startup, initialize the stack to -;; the end of some memory region. The _stack symbol is defined by -;; the linker. -;; - lds #_stack - - .sect .install2,"ax",@progbits -;; -;; Call a specific initialization operation. The default is empty. -;; It can be overridden by applications. It is intended to initialize -;; the 68hc11 registers. Function prototype is: -;; -;; int __premain(void); -;; - jsr __premain - -;; -;; -;; - .sect .install4,"ax",@progbits - jsr main -fatal: - jsr exit - bra fatal - -;----------------------------------------- -; end startup code -;----------------------------------------- -;; Force loading of data section mapping and bss clear - .2byte __map_data_section - .2byte __init_bss_section diff --git a/gcc/config/m68hc11/m68hc11-protos.h b/gcc/config/m68hc11/m68hc11-protos.h deleted file mode 100644 index 76b6659379e..00000000000 --- a/gcc/config/m68hc11/m68hc11-protos.h +++ /dev/null @@ -1,109 +0,0 @@ -/* Prototypes for exported functions defined in m68hc11.c - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2009, 2010 - Free Software Foundation, Inc. - Contributed by Stephane Carrez (stcarrez@nerim.fr) - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - - -extern int hard_regno_mode_ok (int, enum machine_mode); -extern int m68hc11_hard_regno_rename_ok (int, int); - -extern int m68hc11_total_frame_size (void); -extern int m68hc11_initial_frame_pointer_offset (void); -extern int m68hc11_initial_elimination_offset (int, int); - -extern void expand_prologue (void); -extern void expand_epilogue (void); - -#ifdef RTX_CODE -extern int m68hc11_auto_inc_p (rtx); - -extern rtx m68hc11_expand_compare_and_branch (enum rtx_code, rtx, rtx, rtx); -extern enum reg_class preferred_reload_class (rtx, enum reg_class); - -extern void m68hc11_notice_update_cc (rtx, rtx); -extern void m68hc11_notice_keep_cc (rtx); - -extern void m68hc11_gen_movqi (rtx, rtx*); -extern void m68hc11_gen_movhi (rtx, rtx*); -extern void m68hc11_gen_rotate (enum rtx_code, rtx, rtx*); - -extern void m68hc11_output_swap (rtx, rtx*); - -extern int next_insn_test_reg (rtx, rtx); - -extern int m68hc11_reload_operands (rtx*); - -extern int dead_register_here (rtx, rtx); - -extern int push_pop_operand_p (rtx); -extern void m68hc11_split_move (rtx, rtx, rtx); -extern void m68hc11_split_compare_and_branch (enum rtx_code, - rtx, rtx, rtx); - -extern rtx m68hc11_gen_lowpart (enum machine_mode, rtx); -extern rtx m68hc11_gen_highpart (enum machine_mode, rtx); - -#ifdef HAVE_MACHINE_MODES -extern int m68hc11_memory_move_cost (enum machine_mode, enum reg_class, int); -extern int m68hc11_register_move_cost (enum machine_mode, - enum reg_class, enum reg_class); - -extern void m68hc11_emit_libcall (const char*, enum rtx_code, - enum machine_mode, enum machine_mode, - int, rtx*); -extern int m68hc11_small_indexed_indirect_p (rtx, enum machine_mode); -extern int m68hc11_symbolic_p (rtx, enum machine_mode); -extern int m68hc11_indirect_p (rtx, enum machine_mode); -extern int go_if_legitimate_address2 (rtx, enum machine_mode, int); - -extern int reg_or_indexed_operand (rtx,enum machine_mode); -extern int memory_indexed_operand (rtx, enum machine_mode); - -#ifdef RTX_CODE -extern void m68hc11_split_logical (enum machine_mode, enum rtx_code, rtx*); -#endif - -extern int m68hc11_register_indirect_p (rtx, enum machine_mode); -extern int m68hc11_valid_addressing_p (rtx, enum machine_mode, int); - -extern int symbolic_memory_operand (rtx, enum machine_mode); - -extern int memory_reload_operand (rtx, enum machine_mode); -extern int arith_src_operand (rtx, enum machine_mode); -extern int soft_reg_operand (rtx, enum machine_mode); - -extern void m68hc11_init_cumulative_args (CUMULATIVE_ARGS*, tree, rtx); - -#ifdef ARGS_SIZE_RTX -extern enum direction m68hc11_function_arg_padding (enum machine_mode, - const_tree); -#endif - -extern void m68hc11_function_epilogue (FILE*,int); - -extern int m68hc11_is_far_symbol (rtx); -extern int m68hc11_is_trap_symbol (rtx); -extern int m68hc11_page0_symbol_p (rtx x); - -extern HOST_WIDE_INT m68hc11_min_offset; -extern HOST_WIDE_INT m68hc11_max_offset; -extern int m68hc11_addr_mode; - -#endif /* HAVE_MACHINE_MODES */ -#endif /* RTX_CODE */ diff --git a/gcc/config/m68hc11/m68hc11.c b/gcc/config/m68hc11/m68hc11.c deleted file mode 100644 index 1e414102c3f..00000000000 --- a/gcc/config/m68hc11/m68hc11.c +++ /dev/null @@ -1,5588 +0,0 @@ -/* Subroutines for code generation on Motorola 68HC11 and 68HC12. - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - 2009, 2010 Free Software Foundation, Inc. - Contributed by Stephane Carrez (stcarrez@nerim.fr) - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. - -Note: - A first 68HC11 port was made by Otto Lind (otto@coactive.com) - on gcc 2.6.3. I have used it as a starting point for this port. - However, this new port is a complete re-write. Its internal - design is completely different. The generated code is not - compatible with the gcc 2.6.3 port. - - The gcc 2.6.3 port is available at: - - ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz - -*/ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "rtl.h" -#include "tree.h" -#include "expr.h" -#include "tm_p.h" -#include "regs.h" -#include "hard-reg-set.h" -#include "insn-config.h" -#include "conditions.h" -#include "output.h" -#include "insn-attr.h" -#include "flags.h" -#include "recog.h" -#include "expr.h" -#include "libfuncs.h" -#include "diagnostic-core.h" -#include "basic-block.h" -#include "function.h" -#include "ggc.h" -#include "reload.h" -#include "target.h" -#include "target-def.h" -#include "df.h" - -static void m68hc11_option_override (void); -static void emit_move_after_reload (rtx, rtx, rtx); -static rtx simplify_logical (enum machine_mode, int, rtx, rtx *); -static void m68hc11_emit_logical (enum machine_mode, enum rtx_code, rtx *); -static void m68hc11_reorg (void); -static bool m68hc11_legitimate_address_p_1 (enum machine_mode, rtx, bool); -static bool m68hc11_legitimate_address_p (enum machine_mode, rtx, bool); -static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx); -static int must_parenthesize (rtx); -static int m68hc11_address_cost (rtx, bool); -static int m68hc11_shift_cost (enum machine_mode, rtx, int); -static int m68hc11_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code); -static bool m68hc11_rtx_costs (rtx, int, int, int *, bool); -static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *); -static tree m68hc11_handle_page0_attribute (tree *, tree, tree, int, bool *); -static bool m68hc11_class_likely_spilled_p (reg_class_t); - -void create_regs_rtx (void); - -static void asm_print_register (FILE *, int); -static void m68hc11_print_operand (FILE *, rtx, int); -static void m68hc11_print_operand_address (FILE *, rtx); -static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT); -static void m68hc11_asm_out_constructor (rtx, int); -static void m68hc11_asm_out_destructor (rtx, int); -static void m68hc11_file_start (void); -static void m68hc11_encode_section_info (tree, rtx, int); -static const char *m68hc11_strip_name_encoding (const char* str); -static unsigned int m68hc11_section_type_flags (tree, const char*, int); -static int autoinc_mode (rtx); -static int m68hc11_make_autoinc_notes (rtx *, void *); -static void m68hc11_init_libfuncs (void); -static rtx m68hc11_struct_value_rtx (tree, int); -static bool m68hc11_return_in_memory (const_tree, const_tree); -static bool m68hc11_can_eliminate (const int, const int); -static void m68hc11_conditional_register_usage (void); -static void m68hc11_trampoline_init (rtx, tree, rtx); - -static rtx m68hc11_function_arg (CUMULATIVE_ARGS*, enum machine_mode, - const_tree, bool); -static void m68hc11_function_arg_advance (CUMULATIVE_ARGS*, enum machine_mode, - const_tree, bool); - -/* Must be set to 1 to produce debug messages. */ -int debug_m6811 = 0; - -extern FILE *asm_out_file; - -rtx ix_reg; -rtx iy_reg; -rtx d_reg; -rtx m68hc11_soft_tmp_reg; -static GTY(()) rtx stack_push_word; -static GTY(()) rtx stack_pop_word; -static GTY(()) rtx z_reg; -static GTY(()) rtx z_reg_qi; -static int regs_inited = 0; - -/* Set to 1 by expand_prologue() when the function is an interrupt handler. */ -int current_function_interrupt; - -/* Set to 1 by expand_prologue() when the function is a trap handler. */ -int current_function_trap; - -/* Set to 1 when the current function is placed in 68HC12 banked - memory and must return with rtc. */ -int current_function_far; - -/* Min offset that is valid for the indirect addressing mode. */ -HOST_WIDE_INT m68hc11_min_offset = 0; - -/* Max offset that is valid for the indirect addressing mode. */ -HOST_WIDE_INT m68hc11_max_offset = 256; - -/* The class value for base registers. */ -enum reg_class m68hc11_base_reg_class = A_REGS; - -/* The class value for index registers. This is NO_REGS for 68HC11. */ -enum reg_class m68hc11_index_reg_class = NO_REGS; - -enum reg_class m68hc11_tmp_regs_class = NO_REGS; - -/* Tables that tell whether a given hard register is valid for - a base or an index register. It is filled at init time depending - on the target processor. */ -unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER]; -unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER]; - -/* A correction offset which is applied to the stack pointer. - This is 1 for 68HC11 and 0 for 68HC12. */ -int m68hc11_sp_correction; - -int m68hc11_addr_mode; -int m68hc11_mov_addr_mode; - - -const struct processor_costs *m68hc11_cost; - -/* Costs for a 68HC11. */ -static const struct processor_costs m6811_cost = { - /* add */ - COSTS_N_INSNS (2), - /* logical */ - COSTS_N_INSNS (2), - /* non-constant shift */ - COSTS_N_INSNS (20), - /* shiftQI const */ - { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2), - COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3), - COSTS_N_INSNS (2), COSTS_N_INSNS (1) }, - - /* shiftHI const */ - { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4), - COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6), - COSTS_N_INSNS (4), COSTS_N_INSNS (2), - COSTS_N_INSNS (2), COSTS_N_INSNS (4), - COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10), - COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4) - }, - /* mulQI */ - COSTS_N_INSNS (20), - /* mulHI */ - COSTS_N_INSNS (20 * 4), - /* mulSI */ - COSTS_N_INSNS (20 * 16), - /* divQI */ - COSTS_N_INSNS (20), - /* divHI */ - COSTS_N_INSNS (80), - /* divSI */ - COSTS_N_INSNS (100) -}; - -/* Costs for a 68HC12. */ -static const struct processor_costs m6812_cost = { - /* add */ - COSTS_N_INSNS (2), - /* logical */ - COSTS_N_INSNS (2), - /* non-constant shift */ - COSTS_N_INSNS (20), - /* shiftQI const */ - { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2), - COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3), - COSTS_N_INSNS (2), COSTS_N_INSNS (1) }, - - /* shiftHI const */ - { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4), - COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6), - COSTS_N_INSNS (4), COSTS_N_INSNS (2), - COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6), - COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8), - COSTS_N_INSNS (6), COSTS_N_INSNS (4) - }, - /* mulQI */ - COSTS_N_INSNS (3), - /* mulHI */ - COSTS_N_INSNS (3), - /* mulSI */ - COSTS_N_INSNS (3 * 4), - /* divQI */ - COSTS_N_INSNS (12), - /* divHI */ - COSTS_N_INSNS (12), - /* divSI */ - COSTS_N_INSNS (100) -}; - -/* M68HC11 specific attributes. */ - -static const struct attribute_spec m68hc11_attribute_table[] = -{ - /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, - affects_type_identity } */ - { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute, - false }, - { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute, - false }, - { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute, - false }, - { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute, - false }, - { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute, - false }, - { NULL, 0, 0, false, false, false, NULL, false } -}; - -/* Initialize the GCC target structure. */ -#undef TARGET_ATTRIBUTE_TABLE -#define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table - -#undef TARGET_ASM_ALIGNED_HI_OP -#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" - -#undef TARGET_PRINT_OPERAND -#define TARGET_PRINT_OPERAND m68hc11_print_operand -#undef TARGET_PRINT_OPERAND_ADDRESS -#define TARGET_PRINT_OPERAND_ADDRESS m68hc11_print_operand_address - -#undef TARGET_ASM_FUNCTION_EPILOGUE -#define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue - -#undef TARGET_ASM_FILE_START -#define TARGET_ASM_FILE_START m68hc11_file_start -#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE -#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true - -#undef TARGET_DEFAULT_TARGET_FLAGS -#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT - -#undef TARGET_ENCODE_SECTION_INFO -#define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info - -#undef TARGET_SECTION_TYPE_FLAGS -#define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags - -#undef TARGET_RTX_COSTS -#define TARGET_RTX_COSTS m68hc11_rtx_costs -#undef TARGET_ADDRESS_COST -#define TARGET_ADDRESS_COST m68hc11_address_cost - -#undef TARGET_MACHINE_DEPENDENT_REORG -#define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg - -#undef TARGET_INIT_LIBFUNCS -#define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs - -#undef TARGET_FUNCTION_ARG -#define TARGET_FUNCTION_ARG m68hc11_function_arg -#undef TARGET_FUNCTION_ARG_ADVANCE -#define TARGET_FUNCTION_ARG_ADVANCE m68hc11_function_arg_advance - -#undef TARGET_STRUCT_VALUE_RTX -#define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx -#undef TARGET_RETURN_IN_MEMORY -#define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory -#undef TARGET_CALLEE_COPIES -#define TARGET_CALLEE_COPIES hook_callee_copies_named - -#undef TARGET_STRIP_NAME_ENCODING -#define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding - -#undef TARGET_LEGITIMATE_ADDRESS_P -#define TARGET_LEGITIMATE_ADDRESS_P m68hc11_legitimate_address_p - -#undef TARGET_CAN_ELIMINATE -#define TARGET_CAN_ELIMINATE m68hc11_can_eliminate - -#undef TARGET_CONDITIONAL_REGISTER_USAGE -#define TARGET_CONDITIONAL_REGISTER_USAGE m68hc11_conditional_register_usage - -#undef TARGET_CLASS_LIKELY_SPILLED_P -#define TARGET_CLASS_LIKELY_SPILLED_P m68hc11_class_likely_spilled_p - -#undef TARGET_TRAMPOLINE_INIT -#define TARGET_TRAMPOLINE_INIT m68hc11_trampoline_init - -#undef TARGET_OPTION_OVERRIDE -#define TARGET_OPTION_OVERRIDE m68hc11_option_override - -struct gcc_target targetm = TARGET_INITIALIZER; - -static void -m68hc11_option_override (void) -{ - memset (m68hc11_reg_valid_for_index, 0, - sizeof (m68hc11_reg_valid_for_index)); - memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base)); - - /* Compilation with -fpic generates a wrong code. */ - if (flag_pic) - { - warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)", - (flag_pic > 1) ? "PIC" : "pic"); - flag_pic = 0; - } - - /* Do not enable -fweb because it breaks the 32-bit shift patterns - by breaking the match_dup of those patterns. The shift patterns - will no longer be recognized after that. */ - flag_web = 0; - - /* Configure for a 68hc11 processor. */ - if (TARGET_M6811) - { - target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX); - m68hc11_cost = &m6811_cost; - m68hc11_min_offset = 0; - m68hc11_max_offset = 256; - m68hc11_index_reg_class = NO_REGS; - m68hc11_base_reg_class = A_REGS; - m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1; - m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1; - m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1; - m68hc11_sp_correction = 1; - m68hc11_tmp_regs_class = D_REGS; - m68hc11_addr_mode = ADDR_OFFSET; - m68hc11_mov_addr_mode = 0; - if (m68hc11_soft_reg_count < 0) - m68hc11_soft_reg_count = 4; - } - - /* Configure for a 68hc12 processor. */ - if (TARGET_M6812) - { - m68hc11_cost = &m6812_cost; - m68hc11_min_offset = -65536; - m68hc11_max_offset = 65536; - m68hc11_index_reg_class = D_REGS; - m68hc11_base_reg_class = A_OR_SP_REGS; - m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1; - m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1; - m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1; - m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1; - m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1; - m68hc11_sp_correction = 0; - m68hc11_tmp_regs_class = TMP_REGS; - m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST - | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0); - m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST - | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0); - target_flags |= MASK_NO_DIRECT_MODE; - if (m68hc11_soft_reg_count < 0) - m68hc11_soft_reg_count = 0; - - if (TARGET_LONG_CALLS) - current_function_far = 1; - } -} - - -/* The soft-registers are disabled or enabled according to the - -msoft-reg-count=<n> option. */ - -static void -m68hc11_conditional_register_usage (void) -{ - int i; - - if (m68hc11_soft_reg_count > SOFT_REG_LAST - SOFT_REG_FIRST) - m68hc11_soft_reg_count = SOFT_REG_LAST - SOFT_REG_FIRST; - - for (i = SOFT_REG_FIRST + m68hc11_soft_reg_count; i < SOFT_REG_LAST; i++) - { - fixed_regs[i] = 1; - call_used_regs[i] = 1; - } - - /* For 68HC12, the Z register emulation is not necessary when the - frame pointer is not used. The frame pointer is eliminated and - replaced by the stack register (which is a BASE_REG_CLASS). */ - if (TARGET_M6812 && flag_omit_frame_pointer && optimize) - { - fixed_regs[HARD_Z_REGNUM] = 1; - } -} - - -/* Reload and register operations. */ - - -void -create_regs_rtx (void) -{ - /* regs_inited = 1; */ - ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM); - iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM); - d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM); - m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); - - stack_push_word = gen_rtx_MEM (HImode, - gen_rtx_PRE_DEC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM))); - stack_pop_word = gen_rtx_MEM (HImode, - gen_rtx_POST_INC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM))); - -} - -/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. - - 8-bit values are stored anywhere (except the SP register). - - 16-bit values can be stored in any register whose mode is 16 - - 32-bit values can be stored in D, X registers or in a soft register - (except the last one because we need 2 soft registers) - - Values whose size is > 32 bit are not stored in real hard - registers. They may be stored in soft registers if there are - enough of them. */ -int -hard_regno_mode_ok (int regno, enum machine_mode mode) -{ - switch (GET_MODE_SIZE (mode)) - { - case 8: - return S_REGNO_P (regno) && m68hc11_soft_reg_count >= 4; - - case 4: - return (X_REGNO_P (regno) - || (S_REGNO_P (regno) && m68hc11_soft_reg_count >= 2)); - - case 2: - return G_REGNO_P (regno); - - case 1: - /* We have to accept a QImode in X or Y registers. Otherwise, the - reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined - in the insns. Reload fails if the insn rejects the register class 'a' - as well as if it accepts it. Patterns that failed were - zero_extend_qihi2 and iorqi3. */ - - return G_REGNO_P (regno) && !SP_REGNO_P (regno); - - default: - return 0; - } -} - -int -m68hc11_hard_regno_rename_ok (int reg1, int reg2) -{ - /* Don't accept renaming to Z register. We will replace it to - X,Y or D during machine reorg pass. */ - if (reg2 == HARD_Z_REGNUM) - return 0; - - /* Don't accept renaming D,X to Y register as the code will be bigger. */ - if (TARGET_M6811 && reg2 == HARD_Y_REGNUM - && (D_REGNO_P (reg1) || X_REGNO_P (reg1))) - return 0; - - return 1; -} - -enum reg_class -preferred_reload_class (rtx operand, enum reg_class rclass) -{ - enum machine_mode mode; - - mode = GET_MODE (operand); - - if (debug_m6811) - { - printf ("Preferred reload: (class=%s): ", reg_class_names[rclass]); - } - - if (rclass == D_OR_A_OR_S_REGS && SP_REG_P (operand)) - return m68hc11_base_reg_class; - - if (rclass >= S_REGS && (GET_CODE (operand) == MEM - || GET_CODE (operand) == CONST_INT)) - { - /* S_REGS class must not be used. The movhi template does not - work to move a memory to a soft register. - Restrict to a hard reg. */ - switch (rclass) - { - default: - case G_REGS: - case D_OR_A_OR_S_REGS: - rclass = A_OR_D_REGS; - break; - case A_OR_S_REGS: - rclass = A_REGS; - break; - case D_OR_SP_OR_S_REGS: - rclass = D_OR_SP_REGS; - break; - case D_OR_Y_OR_S_REGS: - rclass = D_OR_Y_REGS; - break; - case D_OR_X_OR_S_REGS: - rclass = D_OR_X_REGS; - break; - case SP_OR_S_REGS: - rclass = SP_REGS; - break; - case Y_OR_S_REGS: - rclass = Y_REGS; - break; - case X_OR_S_REGS: - rclass = X_REGS; - break; - case D_OR_S_REGS: - rclass = D_REGS; - } - } - else if (rclass == Y_REGS && GET_CODE (operand) == MEM) - { - rclass = Y_REGS; - } - else if (rclass == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4) - { - rclass = D_OR_X_REGS; - } - else if (rclass >= S_REGS && S_REG_P (operand)) - { - switch (rclass) - { - default: - case G_REGS: - case D_OR_A_OR_S_REGS: - rclass = A_OR_D_REGS; - break; - case A_OR_S_REGS: - rclass = A_REGS; - break; - case D_OR_SP_OR_S_REGS: - rclass = D_OR_SP_REGS; - break; - case D_OR_Y_OR_S_REGS: - rclass = D_OR_Y_REGS; - break; - case D_OR_X_OR_S_REGS: - rclass = D_OR_X_REGS; - break; - case SP_OR_S_REGS: - rclass = SP_REGS; - break; - case Y_OR_S_REGS: - rclass = Y_REGS; - break; - case X_OR_S_REGS: - rclass = X_REGS; - break; - case D_OR_S_REGS: - rclass = D_REGS; - } - } - else if (rclass >= S_REGS) - { - if (debug_m6811) - { - printf ("Class = %s for: ", reg_class_names[rclass]); - fflush (stdout); - debug_rtx (operand); - } - } - - if (debug_m6811) - { - printf (" => class=%s\n", reg_class_names[rclass]); - fflush (stdout); - debug_rtx (operand); - } - - return rclass; -} - -/* Implement TARGET_CLASS_LIKELY_SPILLED_P. */ - -static bool -m68hc11_class_likely_spilled_p (reg_class_t rclass) -{ - switch (rclass) - { - case D_REGS: - case X_REGS: - case Y_REGS: - case A_REGS: - case SP_REGS: - case D_OR_X_REGS: - case D_OR_Y_REGS: - case X_OR_SP_REGS: - case Y_OR_SP_REGS: - case D_OR_SP_REGS: - return true; - - default: - break; - } - - return false; -} - -/* Return 1 if the operand is a valid indexed addressing mode. - For 68hc11: n,r with n in [0..255] and r in A_REGS class - For 68hc12: n,r no constraint on the constant, r in A_REGS class. */ -int -m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode) -{ - rtx base, offset; - - switch (GET_CODE (operand)) - { - case MEM: - if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2) - return m68hc11_valid_addressing_p (XEXP (operand, 0), mode, - addr_mode & (ADDR_STRICT | ADDR_OFFSET)); - return 0; - - case POST_INC: - case PRE_INC: - case POST_DEC: - case PRE_DEC: - if (addr_mode & ADDR_INCDEC) - return m68hc11_valid_addressing_p (XEXP (operand, 0), mode, - addr_mode & ADDR_STRICT); - return 0; - - case PLUS: - base = XEXP (operand, 0); - if (GET_CODE (base) == MEM) - return 0; - - offset = XEXP (operand, 1); - if (GET_CODE (offset) == MEM) - return 0; - - /* Indexed addressing mode with 2 registers. */ - if (GET_CODE (base) == REG && GET_CODE (offset) == REG) - { - if (!(addr_mode & ADDR_INDEXED)) - return 0; - - addr_mode &= ADDR_STRICT; - if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode) - && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode)) - return 1; - - if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode) - && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode)) - return 1; - - return 0; - } - - if (!(addr_mode & ADDR_OFFSET)) - return 0; - - if (GET_CODE (base) == REG) - { - if (!VALID_CONSTANT_OFFSET_P (offset, mode)) - return 0; - - if (!(addr_mode & ADDR_STRICT)) - return 1; - - return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1); - } - - if (GET_CODE (offset) == REG) - { - if (!VALID_CONSTANT_OFFSET_P (base, mode)) - return 0; - - if (!(addr_mode & ADDR_STRICT)) - return 1; - - return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1); - } - return 0; - - case REG: - return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT); - - case CONST_INT: - if (addr_mode & ADDR_CONST) - return VALID_CONSTANT_OFFSET_P (operand, mode); - return 0; - - default: - return 0; - } -} - -/* Returns 1 if the operand fits in a 68HC11 indirect mode or in - a 68HC12 1-byte index addressing mode. */ -int -m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode) -{ - rtx base, offset; - int addr_mode; - - if (GET_CODE (operand) == REG && reload_in_progress - && REGNO (operand) >= FIRST_PSEUDO_REGISTER - && reg_equiv_memory_loc[REGNO (operand)]) - { - operand = reg_equiv_memory_loc[REGNO (operand)]; - operand = eliminate_regs (operand, VOIDmode, NULL_RTX); - } - - if (GET_CODE (operand) != MEM) - return 0; - - operand = XEXP (operand, 0); - if (CONSTANT_ADDRESS_P (operand)) - return 1; - - if (PUSH_POP_ADDRESS_P (operand)) - return 1; - - addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0); - if (!m68hc11_valid_addressing_p (operand, mode, addr_mode)) - return 0; - - if (TARGET_M6812 && GET_CODE (operand) == PLUS - && (reload_completed | reload_in_progress)) - { - base = XEXP (operand, 0); - offset = XEXP (operand, 1); - - /* The offset can be a symbol address and this is too big - for the operand constraint. */ - if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT) - return 0; - - if (GET_CODE (base) == CONST_INT) - offset = base; - - switch (GET_MODE_SIZE (mode)) - { - case 8: - if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6) - return 0; - break; - - case 4: - if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2) - return 0; - break; - - default: - if (INTVAL (offset) < -16 || INTVAL (offset) > 15) - return 0; - break; - } - } - return 1; -} - -int -m68hc11_register_indirect_p (rtx operand, enum machine_mode mode) -{ - int addr_mode; - - if (GET_CODE (operand) == REG && reload_in_progress - && REGNO (operand) >= FIRST_PSEUDO_REGISTER - && reg_equiv_memory_loc[REGNO (operand)]) - { - operand = reg_equiv_memory_loc[REGNO (operand)]; - operand = eliminate_regs (operand, VOIDmode, NULL_RTX); - } - if (GET_CODE (operand) != MEM) - return 0; - - operand = XEXP (operand, 0); - addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0); - return m68hc11_valid_addressing_p (operand, mode, addr_mode); -} - -static bool -m68hc11_legitimate_address_p_1 (enum machine_mode mode, rtx operand, - bool strict) -{ - int addr_mode; - - if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812) - { - /* Reject the global variables if they are too wide. This forces - a load of their address in a register and generates smaller code. */ - if (GET_MODE_SIZE (mode) == 8) - return 0; - - return 1; - } - addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0); - if (m68hc11_valid_addressing_p (operand, mode, addr_mode)) - { - return 1; - } - if (PUSH_POP_ADDRESS_P (operand)) - { - return 1; - } - if (symbolic_memory_operand (operand, mode)) - { - return 1; - } - return 0; -} - -bool -m68hc11_legitimate_address_p (enum machine_mode mode, rtx operand, - bool strict) -{ - int result; - - if (debug_m6811) - { - printf ("Checking: "); - fflush (stdout); - debug_rtx (operand); - } - - result = m68hc11_legitimate_address_p_1 (mode, operand, strict); - - if (debug_m6811) - { - printf (" -> %s\n", result == 0 ? "NO" : "YES"); - } - - if (result == 0) - { - if (debug_m6811) - { - printf ("go_if_legitimate%s, ret 0: %d:", - (strict ? "_strict" : ""), mode); - fflush (stdout); - debug_rtx (operand); - } - } - return result; -} - - -int -m68hc11_reload_operands (rtx operands[]) -{ - enum machine_mode mode; - - if (regs_inited == 0) - create_regs_rtx (); - - mode = GET_MODE (operands[1]); - - /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */ - if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode)) - { - rtx big_offset = XEXP (XEXP (operands[1], 0), 1); - rtx base = XEXP (XEXP (operands[1], 0), 0); - - if (GET_CODE (base) != REG) - { - rtx tmp = base; - base = big_offset; - big_offset = tmp; - } - - /* If the offset is out of range, we have to compute the address - with a separate add instruction. We try to do this with an 8-bit - add on the A register. This is possible only if the lowest part - of the offset (i.e., big_offset % 256) is a valid constant offset - with respect to the mode. If it's not, we have to generate a - 16-bit add on the D register. From: - - (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000))))) - - we generate: - - [(SET (REG D) (REG X)) (SET (REG X) (REG D))] - (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256))) - [(SET (REG D) (REG X)) (SET (REG X) (REG D))] - (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))) - - (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256))) - (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))) - - */ - if (!VALID_CONSTANT_OFFSET_P (big_offset, mode)) - { - int vh, vl; - rtx reg = operands[0]; - rtx offset; - int val = INTVAL (big_offset); - - - /* We use the 'operands[0]' as a scratch register to compute the - address. Make sure 'base' is in that register. */ - if (!rtx_equal_p (base, operands[0])) - { - emit_move_insn (reg, base); - } - - if (val > 0) - { - vh = val >> 8; - vl = val & 0x0FF; - } - else - { - vh = (val >> 8) & 0x0FF; - vl = val & 0x0FF; - } - - /* Create the lowest part offset that still remains to be added. - If it's not a valid offset, do a 16-bit add. */ - offset = GEN_INT (vl); - if (!VALID_CONSTANT_OFFSET_P (offset, mode)) - { - emit_insn (gen_rtx_SET (VOIDmode, reg, - gen_rtx_PLUS (HImode, reg, big_offset))); - offset = const0_rtx; - } - else - { - emit_insn (gen_rtx_SET (VOIDmode, reg, - gen_rtx_PLUS (HImode, reg, - GEN_INT (vh << 8)))); - } - emit_move_insn (operands[0], - gen_rtx_MEM (GET_MODE (operands[1]), - gen_rtx_PLUS (Pmode, reg, offset))); - return 1; - } - } - - /* Use the normal gen_movhi pattern. */ - return 0; -} - -void -m68hc11_emit_libcall (const char *name, enum rtx_code code, - enum machine_mode dmode, enum machine_mode smode, - int noperands, rtx *operands) -{ - rtx ret; - rtx insns; - rtx libcall; - rtx equiv; - - start_sequence (); - libcall = gen_rtx_SYMBOL_REF (Pmode, name); - switch (noperands) - { - case 2: - ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST, - dmode, 1, operands[1], smode); - equiv = gen_rtx_fmt_e (code, dmode, operands[1]); - break; - - case 3: - ret = emit_library_call_value (libcall, NULL_RTX, - LCT_CONST, dmode, 2, - operands[1], smode, operands[2], - smode); - equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]); - break; - - default: - gcc_unreachable (); - } - - insns = get_insns (); - end_sequence (); - emit_libcall_block (insns, operands[0], ret, equiv); -} - -/* Returns true if X is a PRE/POST increment decrement - (same as auto_inc_p() in rtlanal.c but do not take into - account the stack). */ -int -m68hc11_auto_inc_p (rtx x) -{ - return GET_CODE (x) == PRE_DEC - || GET_CODE (x) == POST_INC - || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC; -} - - -/* Predicates for machine description. */ - -int -memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return GET_CODE (operand) == MEM - && GET_CODE (XEXP (operand, 0)) == PLUS - && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG - && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT) - || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG - && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT)); -} - -int -m68hc11_symbolic_p (rtx operand, enum machine_mode mode) -{ - if (GET_CODE (operand) == MEM) - { - rtx op = XEXP (operand, 0); - - if (symbolic_memory_operand (op, mode)) - return 1; - } - return 0; -} - -int -m68hc11_indirect_p (rtx operand, enum machine_mode mode) -{ - if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode) - { - rtx op = XEXP (operand, 0); - int addr_mode; - - if (m68hc11_page0_symbol_p (op)) - return 1; - - if (symbolic_memory_operand (op, mode)) - return TARGET_M6812; - - if (reload_in_progress) - return 1; - - operand = XEXP (operand, 0); - addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0); - return m68hc11_valid_addressing_p (operand, mode, addr_mode); - } - return 0; -} - -int -memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - if (GET_CODE (operand) != MEM) - return 0; - - operand = XEXP (operand, 0); - if (GET_CODE (operand) == PLUS) - { - if (GET_CODE (XEXP (operand, 0)) == REG) - operand = XEXP (operand, 0); - else if (GET_CODE (XEXP (operand, 1)) == REG) - operand = XEXP (operand, 1); - } - return GET_CODE (operand) == REG - && (REGNO (operand) >= FIRST_PSEUDO_REGISTER - || A_REGNO_P (REGNO (operand))); -} - -int -push_pop_operand_p (rtx operand) -{ - if (GET_CODE (operand) != MEM) - { - return 0; - } - operand = XEXP (operand, 0); - return PUSH_POP_ADDRESS_P (operand); -} - -/* Returns 1 if OP is either a symbol reference or a sum of a symbol - reference and a constant. */ - -int -symbolic_memory_operand (rtx op, enum machine_mode mode) -{ - switch (GET_CODE (op)) - { - case SYMBOL_REF: - case LABEL_REF: - return 1; - - case CONST: - op = XEXP (op, 0); - return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF - || GET_CODE (XEXP (op, 0)) == LABEL_REF) - && GET_CODE (XEXP (op, 1)) == CONST_INT); - - /* ??? This clause seems to be irrelevant. */ - case CONST_DOUBLE: - return GET_MODE (op) == mode; - - case PLUS: - return symbolic_memory_operand (XEXP (op, 0), mode) - && symbolic_memory_operand (XEXP (op, 1), mode); - - default: - return 0; - } -} - -/* Emit the code to build the trampoline used to call a nested function. - - 68HC11 68HC12 - - ldy #&CXT movw #&CXT,*_.d1 - sty *_.d1 jmp FNADDR - jmp FNADDR - -*/ -static void -m68hc11_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt) -{ - const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM]; - rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); - rtx mem; - - /* Skip the '*'. */ - if (*static_chain_reg == '*') - static_chain_reg++; - if (TARGET_M6811) - { - mem = adjust_address (m_tramp, HImode, 0); - emit_move_insn (mem, GEN_INT (0x18ce)); - mem = adjust_address (m_tramp, HImode, 2); - emit_move_insn (mem, cxt); - mem = adjust_address (m_tramp, HImode, 4); - emit_move_insn (mem, GEN_INT (0x18df)); - mem = adjust_address (m_tramp, QImode, 6); - emit_move_insn (mem, - gen_rtx_CONST (QImode, - gen_rtx_SYMBOL_REF (Pmode, - static_chain_reg))); - mem = adjust_address (m_tramp, QImode, 7); - emit_move_insn (mem, GEN_INT (0x7e)); - mem = adjust_address (m_tramp, HImode, 8); - emit_move_insn (mem, fnaddr); - } - else - { - mem = adjust_address (m_tramp, HImode, 0); - emit_move_insn (mem, GEN_INT (0x1803)); - mem = adjust_address (m_tramp, HImode, 2); - emit_move_insn (mem, cxt); - mem = adjust_address (m_tramp, HImode, 4); - emit_move_insn (mem, - gen_rtx_CONST (HImode, - gen_rtx_SYMBOL_REF (Pmode, - static_chain_reg))); - mem = adjust_address (m_tramp, QImode, 6); - emit_move_insn (mem, GEN_INT (0x06)); - mem = adjust_address (m_tramp, HImode, 7); - emit_move_insn (mem, fnaddr); - } -} - -/* Declaration of types. */ - -/* Handle an "tiny_data" attribute; arguments as in - struct attribute_spec.handler. */ -static tree -m68hc11_handle_page0_attribute (tree *node, tree name, - tree args ATTRIBUTE_UNUSED, - int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) -{ - tree decl = *node; - - if (TREE_STATIC (decl) || DECL_EXTERNAL (decl)) - { - DECL_SECTION_NAME (decl) = build_string (6, ".page0"); - } - else - { - warning (OPT_Wattributes, "%qE attribute ignored", - name); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Keep track of the symbol which has a `trap' attribute and which uses - the `swi' calling convention. Since there is only one trap, we only - record one such symbol. If there are several, a warning is reported. */ -static rtx trap_handler_symbol = 0; - -/* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL; - arguments as in struct attribute_spec.handler. */ -static tree -m68hc11_handle_fntype_attribute (tree *node, tree name, - tree args ATTRIBUTE_UNUSED, - int flags ATTRIBUTE_UNUSED, - bool *no_add_attrs) -{ - if (TREE_CODE (*node) != FUNCTION_TYPE - && TREE_CODE (*node) != METHOD_TYPE - && TREE_CODE (*node) != FIELD_DECL - && TREE_CODE (*node) != TYPE_DECL) - { - warning (OPT_Wattributes, "%qE attribute only applies to functions", - name); - *no_add_attrs = true; - } - - return NULL_TREE; -} -/* Undo the effects of the above. */ - -static const char * -m68hc11_strip_name_encoding (const char *str) -{ - return str + (*str == '*' || *str == '@' || *str == '&'); -} - -static void -m68hc11_encode_label (tree decl) -{ - const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0); - int len = strlen (str); - char *newstr = XALLOCAVEC (char, len + 2); - - newstr[0] = '@'; - strcpy (&newstr[1], str); - - XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1); -} - -/* Return 1 if this is a symbol in page0 */ -int -m68hc11_page0_symbol_p (rtx x) -{ - switch (GET_CODE (x)) - { - case SYMBOL_REF: - return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@'; - - case CONST: - return m68hc11_page0_symbol_p (XEXP (x, 0)); - - case PLUS: - if (!m68hc11_page0_symbol_p (XEXP (x, 0))) - return 0; - - return GET_CODE (XEXP (x, 1)) == CONST_INT - && INTVAL (XEXP (x, 1)) < 256 - && INTVAL (XEXP (x, 1)) >= 0; - - default: - return 0; - } -} - -/* We want to recognize trap handlers so that we handle calls to traps - in a special manner (by issuing the trap). This information is stored - in SYMBOL_REF_FLAG. */ - -static void -m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED) -{ - tree func_attr; - int trap_handler; - int is_far = 0; - - if (TREE_CODE (decl) == VAR_DECL) - { - if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0) - m68hc11_encode_label (decl); - return; - } - - if (TREE_CODE (decl) != FUNCTION_DECL) - return; - - func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl)); - - - if (lookup_attribute ("far", func_attr) != NULL_TREE) - is_far = 1; - else if (lookup_attribute ("near", func_attr) == NULL_TREE) - is_far = TARGET_LONG_CALLS != 0; - - trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE; - if (trap_handler && is_far) - { - warning (OPT_Wattributes, "%<trap%> and %<far%> attributes are " - "not compatible, ignoring %<far%>"); - trap_handler = 0; - } - if (trap_handler) - { - if (trap_handler_symbol != 0) - warning (OPT_Wattributes, "%<trap%> attribute is already used"); - else - trap_handler_symbol = XEXP (rtl, 0); - } - SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far; -} - -static unsigned int -m68hc11_section_type_flags (tree decl, const char *name, int reloc) -{ - unsigned int flags = default_section_type_flags (decl, name, reloc); - - if (strncmp (name, ".eeprom", 7) == 0) - { - flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE; - } - - return flags; -} - -int -m68hc11_is_far_symbol (rtx sym) -{ - if (GET_CODE (sym) == MEM) - sym = XEXP (sym, 0); - - return SYMBOL_REF_FLAG (sym); -} - -int -m68hc11_is_trap_symbol (rtx sym) -{ - if (GET_CODE (sym) == MEM) - sym = XEXP (sym, 0); - - return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym); -} - - -/* Argument support functions. */ - -/* Given FROM and TO register numbers, say whether this elimination is - allowed. Frame pointer elimination is automatically handled. - - All other eliminations are valid. */ - -bool -m68hc11_can_eliminate (const int from, const int to) -{ - return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM - ? ! frame_pointer_needed - : true); -} - -/* Define the offset between two registers, one to be eliminated, and the - other its replacement, at the start of a routine. */ -int -m68hc11_initial_elimination_offset (int from, int to) -{ - int trap_handler; - tree func_attr; - int size; - int regno; - - /* For a trap handler, we must take into account the registers which - are pushed on the stack during the trap (except the PC). */ - func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); - current_function_interrupt = lookup_attribute ("interrupt", - func_attr) != NULL_TREE; - trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE; - - if (lookup_attribute ("far", func_attr) != 0) - current_function_far = 1; - else if (lookup_attribute ("near", func_attr) != 0) - current_function_far = 0; - else - current_function_far = (TARGET_LONG_CALLS != 0 - && !current_function_interrupt - && !trap_handler); - - if (trap_handler && from == ARG_POINTER_REGNUM) - size = 7; - - /* For a function using 'call/rtc' we must take into account the - page register which is pushed in the call. */ - else if (current_function_far && from == ARG_POINTER_REGNUM) - size = 1; - else - size = 0; - - if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) - { - /* 2 is for the saved frame. - 1 is for the 'sts' correction when creating the frame. */ - return get_frame_size () + 2 + m68hc11_sp_correction + size; - } - - if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) - { - return m68hc11_sp_correction; - } - - /* Push any 2 byte pseudo hard registers that we need to save. */ - for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++) - { - if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) - { - size += 2; - } - } - - if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM) - { - return get_frame_size () + size; - } - - if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM) - { - return size; - } - return 0; -} - -/* Initialize a variable CUM of type CUMULATIVE_ARGS - for a call to a function whose data type is FNTYPE. - For a library call, FNTYPE is 0. */ - -void -m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname) -{ - tree ret_type; - - z_replacement_completed = 0; - cum->words = 0; - cum->nregs = 0; - - /* For a library call, we must find out the type of the return value. - When the return value is bigger than 4 bytes, it is returned in - memory. In that case, the first argument of the library call is a - pointer to the memory location. Because the first argument is passed in - register D, we have to identify this, so that the first function - parameter is not passed in D either. */ - if (fntype == 0) - { - const char *name; - size_t len; - - if (libname == 0 || GET_CODE (libname) != SYMBOL_REF) - return; - - /* If the library ends in 'di' or in 'df', we assume it's - returning some DImode or some DFmode which are 64-bit wide. */ - name = XSTR (libname, 0); - len = strlen (name); - if (len > 3 - && ((name[len - 2] == 'd' - && (name[len - 1] == 'f' || name[len - 1] == 'i')) - || (name[len - 3] == 'd' - && (name[len - 2] == 'i' || name[len - 2] == 'f')))) - { - /* We are in. Mark the first parameter register as already used. */ - cum->words = 1; - cum->nregs = 1; - } - return; - } - - ret_type = TREE_TYPE (fntype); - - if (ret_type && aggregate_value_p (ret_type, fntype)) - { - cum->words = 1; - cum->nregs = 1; - } -} - -/* Update the data in CUM to advance over an argument - of mode MODE and data type TYPE. - (TYPE is null for libcalls where that information may not be available.) */ - -static void -m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, - const_tree type, bool named ATTRIBUTE_UNUSED) -{ - if (mode != BLKmode) - { - if (cum->words == 0 && GET_MODE_SIZE (mode) == 4) - { - cum->nregs = 2; - cum->words = GET_MODE_SIZE (mode); - } - else - { - cum->words += GET_MODE_SIZE (mode); - if (cum->words <= HARD_REG_SIZE) - cum->nregs = 1; - } - } - else - { - cum->words += int_size_in_bytes (type); - } - return; -} - -/* Define where to put the arguments to a function. - Value is zero to push the argument on the stack, - or a hard register in which to store the argument. - - MODE is the argument's machine mode. - TYPE is the data type of the argument (as a tree). - This is null for libcalls where that information may - not be available. - CUM is a variable of type CUMULATIVE_ARGS which gives info about - the preceding args and about the function being called. - NAMED is nonzero if this argument is a named parameter - (otherwise it is an extra parameter matching an ellipsis). */ - -static rtx -m68hc11_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, - const_tree type ATTRIBUTE_UNUSED, - bool named ATTRIBUTE_UNUSED) -{ - if (cum->words != 0) - { - return NULL_RTX; - } - - if (mode != BLKmode) - { - if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE) - return gen_rtx_REG (mode, HARD_X_REGNUM); - - if (GET_MODE_SIZE (mode) > HARD_REG_SIZE) - { - return NULL_RTX; - } - return gen_rtx_REG (mode, HARD_D_REGNUM); - } - return NULL_RTX; -} - -/* If defined, a C expression which determines whether, and in which direction, - to pad out an argument with extra space. The value should be of type - `enum direction': either `upward' to pad above the argument, - `downward' to pad below, or `none' to inhibit padding. - - Structures are stored left shifted in their argument slot. */ -enum direction -m68hc11_function_arg_padding (enum machine_mode mode, const_tree type) -{ - if (type != 0 && AGGREGATE_TYPE_P (type)) - return upward; - - /* Fall back to the default. */ - return DEFAULT_FUNCTION_ARG_PADDING (mode, type); -} - - -/* Function prologue and epilogue. */ - -/* Emit a move after the reload pass has completed. This is used to - emit the prologue and epilogue. */ -static void -emit_move_after_reload (rtx to, rtx from, rtx scratch) -{ - rtx insn; - - if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from)) - { - insn = emit_move_insn (to, from); - } - else - { - emit_move_insn (scratch, from); - insn = emit_move_insn (to, scratch); - } - - /* Put a REG_INC note to tell the flow analysis that the instruction - is necessary. */ - if (IS_STACK_PUSH (to)) - add_reg_note (insn, REG_INC, XEXP (XEXP (to, 0), 0)); - else if (IS_STACK_POP (from)) - add_reg_note (insn, REG_INC, XEXP (XEXP (from, 0), 0)); - - /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg - to think that sp == _.frame and later replace a x = sp with x = _.frame. - The problem is that we are lying to gcc and use `txs' for x = sp - (which is not really true because txs is really x = sp + 1). */ - else if (TARGET_M6811 && SP_REG_P (from)) - add_reg_note (insn, REG_INC, from); -} - -int -m68hc11_total_frame_size (void) -{ - int size; - int regno; - - size = get_frame_size (); - if (current_function_interrupt) - { - size += 3 * HARD_REG_SIZE; - } - if (frame_pointer_needed) - size += HARD_REG_SIZE; - - for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++) - if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) - size += HARD_REG_SIZE; - - return size; -} - -static void -m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED, - HOST_WIDE_INT size ATTRIBUTE_UNUSED) -{ - /* We catch the function epilogue generation to have a chance - to clear the z_replacement_completed flag. */ - z_replacement_completed = 0; -} - -void -expand_prologue (void) -{ - tree func_attr; - int size; - int regno; - rtx scratch; - - gcc_assert (reload_completed == 1); - - size = get_frame_size (); - - create_regs_rtx (); - - /* Generate specific prologue for interrupt handlers. */ - func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); - current_function_interrupt = lookup_attribute ("interrupt", - func_attr) != NULL_TREE; - current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE; - if (lookup_attribute ("far", func_attr) != NULL_TREE) - current_function_far = 1; - else if (lookup_attribute ("near", func_attr) != NULL_TREE) - current_function_far = 0; - else - current_function_far = (TARGET_LONG_CALLS != 0 - && !current_function_interrupt - && !current_function_trap); - - /* Get the scratch register to build the frame and push registers. - If the first argument is a 32-bit quantity, the D+X registers - are used. Use Y to compute the frame. Otherwise, X is cheaper. - For 68HC12, this scratch register is not used. */ - if (crtl->args.info.nregs == 2) - scratch = iy_reg; - else - scratch = ix_reg; - - /* Save current stack frame. */ - if (frame_pointer_needed) - emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch); - - /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy. - Other soft registers in page0 need not to be saved because they - will be restored by C functions. For a trap handler, we don't - need to preserve these registers because this is a synchronous call. */ - if (current_function_interrupt) - { - emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch); - emit_move_after_reload (stack_push_word, - gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch); - emit_move_after_reload (stack_push_word, - gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM), - scratch); - } - - /* Allocate local variables. */ - if (TARGET_M6812 && (size > 4 || size == 3)) - { - emit_insn (gen_addhi3 (stack_pointer_rtx, - stack_pointer_rtx, GEN_INT (-size))); - } - else if ((!optimize_size && size > 8) || (optimize_size && size > 10)) - { - rtx insn; - - insn = gen_rtx_PARALLEL - (VOIDmode, - gen_rtvec (2, - gen_rtx_SET (VOIDmode, - stack_pointer_rtx, - gen_rtx_PLUS (HImode, - stack_pointer_rtx, - GEN_INT (-size))), - gen_rtx_CLOBBER (VOIDmode, scratch))); - emit_insn (insn); - } - else - { - int i; - - /* Allocate by pushing scratch values. */ - for (i = 2; i <= size; i += 2) - emit_move_after_reload (stack_push_word, ix_reg, 0); - - if (size & 1) - emit_insn (gen_addhi3 (stack_pointer_rtx, - stack_pointer_rtx, constm1_rtx)); - } - - /* Create the frame pointer. */ - if (frame_pointer_needed) - emit_move_after_reload (hard_frame_pointer_rtx, - stack_pointer_rtx, scratch); - - /* Push any 2 byte pseudo hard registers that we need to save. */ - for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++) - { - if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) - { - emit_move_after_reload (stack_push_word, - gen_rtx_REG (HImode, regno), scratch); - } - } -} - -void -expand_epilogue (void) -{ - int size; - register int regno; - int return_size; - rtx scratch; - - gcc_assert (reload_completed == 1); - - size = get_frame_size (); - - /* If we are returning a value in two registers, we have to preserve the - X register and use the Y register to restore the stack and the saved - registers. Otherwise, use X because it's faster (and smaller). */ - if (crtl->return_rtx == 0) - return_size = 0; - else if (GET_CODE (crtl->return_rtx) == MEM) - return_size = HARD_REG_SIZE; - else - return_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx)); - - if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE) - scratch = iy_reg; - else - scratch = ix_reg; - - /* Pop any 2 byte pseudo hard registers that we saved. */ - for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--) - { - if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) - { - emit_move_after_reload (gen_rtx_REG (HImode, regno), - stack_pop_word, scratch); - } - } - - /* de-allocate auto variables */ - if (TARGET_M6812 && (size > 4 || size == 3)) - { - emit_insn (gen_addhi3 (stack_pointer_rtx, - stack_pointer_rtx, GEN_INT (size))); - } - else if ((!optimize_size && size > 8) || (optimize_size && size > 10)) - { - rtx insn; - - insn = gen_rtx_PARALLEL - (VOIDmode, - gen_rtvec (2, - gen_rtx_SET (VOIDmode, - stack_pointer_rtx, - gen_rtx_PLUS (HImode, - stack_pointer_rtx, - GEN_INT (size))), - gen_rtx_CLOBBER (VOIDmode, scratch))); - emit_insn (insn); - } - else - { - int i; - - for (i = 2; i <= size; i += 2) - emit_move_after_reload (scratch, stack_pop_word, scratch); - if (size & 1) - emit_insn (gen_addhi3 (stack_pointer_rtx, - stack_pointer_rtx, const1_rtx)); - } - - /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */ - if (current_function_interrupt) - { - emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM), - stack_pop_word, scratch); - emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM), - stack_pop_word, scratch); - emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch); - } - - /* Restore previous frame pointer. */ - if (frame_pointer_needed) - emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch); - - /* If the trap handler returns some value, copy the value - in D, X onto the stack so that the rti will pop the return value - correctly. */ - else if (current_function_trap && return_size != 0) - { - rtx addr_reg = stack_pointer_rtx; - - if (!TARGET_M6812) - { - emit_move_after_reload (scratch, stack_pointer_rtx, 0); - addr_reg = scratch; - } - emit_move_after_reload (gen_rtx_MEM (HImode, - gen_rtx_PLUS (HImode, addr_reg, - const1_rtx)), d_reg, 0); - if (return_size > HARD_REG_SIZE) - emit_move_after_reload (gen_rtx_MEM (HImode, - gen_rtx_PLUS (HImode, addr_reg, - GEN_INT (3))), ix_reg, 0); - } - - emit_jump_insn (gen_return ()); -} - - -/* Low and High part extraction for 68HC11. These routines are - similar to gen_lowpart and gen_highpart but they have been - fixed to work for constants and 68HC11 specific registers. */ - -rtx -m68hc11_gen_lowpart (enum machine_mode mode, rtx x) -{ - /* We assume that the low part of an auto-inc mode is the same with - the mode changed and that the caller split the larger mode in the - correct order. */ - if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0))) - { - return gen_rtx_MEM (mode, XEXP (x, 0)); - } - - /* Note that a CONST_DOUBLE rtx could represent either an integer or a - floating-point constant. A CONST_DOUBLE is used whenever the - constant requires more than one word in order to be adequately - represented. */ - if (GET_CODE (x) == CONST_DOUBLE) - { - long l[2]; - - if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) - { - REAL_VALUE_TYPE r; - - if (GET_MODE (x) == SFmode) - { - REAL_VALUE_FROM_CONST_DOUBLE (r, x); - REAL_VALUE_TO_TARGET_SINGLE (r, l[0]); - } - else - { - rtx first, second; - - split_double (x, &first, &second); - return second; - } - if (mode == SImode) - return GEN_INT (l[0]); - - return gen_int_mode (l[0], HImode); - } - else - { - l[0] = CONST_DOUBLE_LOW (x); - } - switch (mode) - { - case SImode: - return GEN_INT (l[0]); - case HImode: - gcc_assert (GET_MODE (x) == SFmode); - return gen_int_mode (l[0], HImode); - default: - gcc_unreachable (); - } - } - - if (mode == QImode && D_REG_P (x)) - return gen_rtx_REG (mode, HARD_B_REGNUM); - - /* gen_lowpart crashes when it is called with a SUBREG. */ - if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0) - { - switch (mode) - { - case SImode: - return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4); - case HImode: - return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2); - default: - gcc_unreachable (); - } - } - x = gen_lowpart (mode, x); - - /* Return a different rtx to avoid to share it in several insns - (when used by a split pattern). Sharing addresses within - a MEM breaks the Z register replacement (and reloading). */ - if (GET_CODE (x) == MEM) - x = copy_rtx (x); - return x; -} - -rtx -m68hc11_gen_highpart (enum machine_mode mode, rtx x) -{ - /* We assume that the high part of an auto-inc mode is the same with - the mode changed and that the caller split the larger mode in the - correct order. */ - if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0))) - { - return gen_rtx_MEM (mode, XEXP (x, 0)); - } - - /* Note that a CONST_DOUBLE rtx could represent either an integer or a - floating-point constant. A CONST_DOUBLE is used whenever the - constant requires more than one word in order to be adequately - represented. */ - if (GET_CODE (x) == CONST_DOUBLE) - { - long l[2]; - - if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) - { - REAL_VALUE_TYPE r; - - if (GET_MODE (x) == SFmode) - { - REAL_VALUE_FROM_CONST_DOUBLE (r, x); - REAL_VALUE_TO_TARGET_SINGLE (r, l[1]); - } - else - { - rtx first, second; - - split_double (x, &first, &second); - return first; - } - if (mode == SImode) - return GEN_INT (l[1]); - - return gen_int_mode ((l[1] >> 16), HImode); - } - else - { - l[1] = CONST_DOUBLE_HIGH (x); - } - - switch (mode) - { - case SImode: - return GEN_INT (l[1]); - case HImode: - gcc_assert (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT); - return gen_int_mode ((l[0] >> 16), HImode); - default: - gcc_unreachable (); - } - } - if (GET_CODE (x) == CONST_INT) - { - HOST_WIDE_INT val = INTVAL (x); - - if (mode == QImode) - { - return gen_int_mode (val >> 8, QImode); - } - else if (mode == HImode) - { - return gen_int_mode (val >> 16, HImode); - } - else if (mode == SImode) - { - return gen_int_mode ((val >> 16) >> 16, SImode); - } - } - if (mode == QImode && D_REG_P (x)) - return gen_rtx_REG (mode, HARD_A_REGNUM); - - /* There is no way in GCC to represent the upper part of a word register. - To obtain the 8-bit upper part of a soft register, we change the - reg into a mem rtx. This is possible because they are physically - located in memory. There is no offset because we are big-endian. */ - if (mode == QImode && S_REG_P (x)) - { - int pos; - - /* Avoid the '*' for direct addressing mode when this - addressing mode is disabled. */ - pos = TARGET_NO_DIRECT_MODE ? 1 : 0; - return gen_rtx_MEM (QImode, - gen_rtx_SYMBOL_REF (Pmode, - ®_names[REGNO (x)][pos])); - } - - /* gen_highpart crashes when it is called with a SUBREG. */ - switch (GET_CODE (x)) - { - case SUBREG: - return gen_rtx_SUBREG (mode, XEXP (x, 0), XINT (x, 1)); - case REG: - if (REGNO (x) < FIRST_PSEUDO_REGISTER) - return gen_rtx_REG (mode, REGNO (x)); - else - return gen_rtx_SUBREG (mode, x, 0); - case MEM: - x = change_address (x, mode, 0); - - /* Return a different rtx to avoid to share it in several insns - (when used by a split pattern). Sharing addresses within - a MEM breaks the Z register replacement (and reloading). */ - if (GET_CODE (x) == MEM) - x = copy_rtx (x); - return x; - - default: - gcc_unreachable (); - } -} - - -/* Obscure register manipulation. */ - -/* Finds backward in the instructions to see if register 'reg' is - dead. This is used when generating code to see if we can use 'reg' - as a scratch register. This allows us to choose a better generation - of code when we know that some register dies or can be clobbered. */ - -int -dead_register_here (rtx x, rtx reg) -{ - rtx x_reg; - rtx p; - - if (D_REG_P (reg)) - x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM); - else - x_reg = 0; - - for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p)) - if (INSN_P (p)) - { - rtx body; - - body = PATTERN (p); - - if (GET_CODE (body) == CALL_INSN) - break; - if (GET_CODE (body) == JUMP_INSN) - break; - - if (GET_CODE (body) == SET) - { - rtx dst = XEXP (body, 0); - - if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg)) - break; - if (x_reg && rtx_equal_p (dst, x_reg)) - break; - - if (find_regno_note (p, REG_DEAD, REGNO (reg))) - return 1; - } - else if (reg_mentioned_p (reg, p) - || (x_reg && reg_mentioned_p (x_reg, p))) - break; - } - - /* Scan forward to see if the register is set in some insns and never - used since then. */ - for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p)) - { - rtx body; - - if (GET_CODE (p) == CODE_LABEL - || GET_CODE (p) == JUMP_INSN - || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER) - break; - - if (GET_CODE (p) != INSN) - continue; - - body = PATTERN (p); - if (GET_CODE (body) == SET) - { - rtx src = XEXP (body, 1); - rtx dst = XEXP (body, 0); - - if (GET_CODE (dst) == REG - && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src)) - return 1; - } - - /* Register is used (may be in source or in dest). */ - if (reg_mentioned_p (reg, p) - || (x_reg != 0 && GET_MODE (p) == SImode - && reg_mentioned_p (x_reg, p))) - break; - } - return p == 0 ? 1 : 0; -} - - -/* Code generation operations called from machine description file. */ - -/* Print the name of register 'regno' in the assembly file. */ -static void -asm_print_register (FILE *file, int regno) -{ - const char *name = reg_names[regno]; - - if (TARGET_NO_DIRECT_MODE && name[0] == '*') - name++; - - fprintf (file, "%s", name); -} - -/* A C compound statement to output to stdio stream STREAM the - assembler syntax for an instruction operand X. X is an RTL - expression. - - CODE is a value that can be used to specify one of several ways - of printing the operand. It is used when identical operands - must be printed differently depending on the context. CODE - comes from the `%' specification that was used to request - printing of the operand. If the specification was just `%DIGIT' - then CODE is 0; if the specification was `%LTR DIGIT' then CODE - is the ASCII code for LTR. - - If X is a register, this macro should print the register's name. - The names can be found in an array `reg_names' whose type is - `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'. - - When the machine description has a specification `%PUNCT' (a `%' - followed by a punctuation character), this macro is called with - a null pointer for X and the punctuation character for CODE. - - The M68HC11 specific codes are: - - 'b' for the low part of the operand. - 'h' for the high part of the operand - The 'b' or 'h' modifiers have no effect if the operand has - the QImode and is not a S_REG_P (soft register). If the - operand is a hard register, these two modifiers have no effect. - 't' generate the temporary scratch register. The operand is - ignored. - 'T' generate the low-part temporary scratch register. The operand is - ignored. */ - -static void -m68hc11_print_operand (FILE *file, rtx op, int letter) -{ - if (letter == 't') - { - asm_print_register (file, SOFT_TMP_REGNUM); - return; - } - else if (letter == 'T') - { - asm_print_register (file, SOFT_TMP_REGNUM); - fprintf (file, "+1"); - return; - } - else if (letter == '#') - { - asm_fprintf (file, "%I"); - } - - if (GET_CODE (op) == REG) - { - if (letter == 'b' && S_REG_P (op)) - { - asm_print_register (file, REGNO (op)); - fprintf (file, "+1"); - } - else if (letter == 'b' && D_REG_P (op)) - { - asm_print_register (file, HARD_B_REGNUM); - } - else - { - asm_print_register (file, REGNO (op)); - } - return; - } - - if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h')) - { - if (letter == 'b') - asm_fprintf (file, "%I%%lo("); - else - asm_fprintf (file, "%I%%hi("); - - output_addr_const (file, op); - fprintf (file, ")"); - return; - } - - /* Get the low or high part of the operand when 'b' or 'h' modifiers - are specified. If we already have a QImode, there is nothing to do. */ - if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode) - { - if (letter == 'b') - { - op = m68hc11_gen_lowpart (QImode, op); - } - else if (letter == 'h') - { - op = m68hc11_gen_highpart (QImode, op); - } - } - - if (GET_CODE (op) == MEM) - { - rtx base = XEXP (op, 0); - switch (GET_CODE (base)) - { - case PRE_DEC: - gcc_assert (TARGET_M6812); - fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op))); - asm_print_register (file, REGNO (XEXP (base, 0))); - break; - - case POST_DEC: - gcc_assert (TARGET_M6812); - fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op))); - asm_print_register (file, REGNO (XEXP (base, 0))); - fprintf (file, "-"); - break; - - case POST_INC: - gcc_assert (TARGET_M6812); - fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op))); - asm_print_register (file, REGNO (XEXP (base, 0))); - fprintf (file, "+"); - break; - - case PRE_INC: - gcc_assert (TARGET_M6812); - fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op))); - asm_print_register (file, REGNO (XEXP (base, 0))); - break; - - case MEM: - gcc_assert (TARGET_M6812); - fprintf (file, "["); - m68hc11_print_operand_address (file, XEXP (base, 0)); - fprintf (file, "]"); - break; - - default: - if (m68hc11_page0_symbol_p (base)) - fprintf (file, "*"); - - output_address (base); - break; - } - } - else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode) - { - REAL_VALUE_TYPE r; - long l; - - REAL_VALUE_FROM_CONST_DOUBLE (r, op); - REAL_VALUE_TO_TARGET_SINGLE (r, l); - asm_fprintf (file, "%I0x%lx", l); - } - else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode) - { - char dstr[30]; - - real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op), - sizeof (dstr), 0, 1); - asm_fprintf (file, "%I0r%s", dstr); - } - else - { - int need_parenthesize = 0; - - if (letter != 'i') - asm_fprintf (file, "%I"); - else - need_parenthesize = must_parenthesize (op); - - if (need_parenthesize) - fprintf (file, "("); - - output_addr_const (file, op); - if (need_parenthesize) - fprintf (file, ")"); - } -} - -/* Returns true if the operand 'op' must be printed with parenthesis - around it. This must be done only if there is a symbol whose name - is a processor register. */ -static int -must_parenthesize (rtx op) -{ - const char *name; - - switch (GET_CODE (op)) - { - case SYMBOL_REF: - name = XSTR (op, 0); - /* Avoid a conflict between symbol name and a possible - register. */ - return (strcasecmp (name, "a") == 0 - || strcasecmp (name, "b") == 0 - || strcasecmp (name, "d") == 0 - || strcasecmp (name, "x") == 0 - || strcasecmp (name, "y") == 0 - || strcasecmp (name, "ix") == 0 - || strcasecmp (name, "iy") == 0 - || strcasecmp (name, "pc") == 0 - || strcasecmp (name, "sp") == 0 - || strcasecmp (name, "ccr") == 0) ? 1 : 0; - - case PLUS: - case MINUS: - return must_parenthesize (XEXP (op, 0)) - || must_parenthesize (XEXP (op, 1)); - - case MEM: - case CONST: - case ZERO_EXTEND: - case SIGN_EXTEND: - return must_parenthesize (XEXP (op, 0)); - - case CONST_DOUBLE: - case CONST_INT: - case LABEL_REF: - case CODE_LABEL: - default: - return 0; - } -} - -/* A C compound statement to output to stdio stream STREAM the - assembler syntax for an instruction operand that is a memory - reference whose address is ADDR. ADDR is an RTL expression. */ - -static void -m68hc11_print_operand_address (FILE *file, rtx addr) -{ - rtx base; - rtx offset; - int need_parenthesis = 0; - - switch (GET_CODE (addr)) - { - case REG: - gcc_assert (REG_P (addr) && REG_OK_FOR_BASE_STRICT_P (addr)); - - fprintf (file, "0,"); - asm_print_register (file, REGNO (addr)); - break; - - case MEM: - base = XEXP (addr, 0); - switch (GET_CODE (base)) - { - case PRE_DEC: - gcc_assert (TARGET_M6812); - fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr))); - asm_print_register (file, REGNO (XEXP (base, 0))); - break; - - case POST_DEC: - gcc_assert (TARGET_M6812); - fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr))); - asm_print_register (file, REGNO (XEXP (base, 0))); - fprintf (file, "-"); - break; - - case POST_INC: - gcc_assert (TARGET_M6812); - fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr))); - asm_print_register (file, REGNO (XEXP (base, 0))); - fprintf (file, "+"); - break; - - case PRE_INC: - gcc_assert (TARGET_M6812); - fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr))); - asm_print_register (file, REGNO (XEXP (base, 0))); - break; - - default: - need_parenthesis = must_parenthesize (base); - if (need_parenthesis) - fprintf (file, "("); - - output_addr_const (file, base); - if (need_parenthesis) - fprintf (file, ")"); - break; - } - break; - - case PLUS: - base = XEXP (addr, 0); - offset = XEXP (addr, 1); - if (!G_REG_P (base) && G_REG_P (offset)) - { - base = XEXP (addr, 1); - offset = XEXP (addr, 0); - } - if (CONSTANT_ADDRESS_P (base)) - { - need_parenthesis = must_parenthesize (addr); - - gcc_assert (CONSTANT_ADDRESS_P (offset)); - if (need_parenthesis) - fprintf (file, "("); - - output_addr_const (file, base); - fprintf (file, "+"); - output_addr_const (file, offset); - if (need_parenthesis) - fprintf (file, ")"); - } - else - { - gcc_assert (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base)); - if (REG_P (offset)) - { - gcc_assert (TARGET_M6812); - asm_print_register (file, REGNO (offset)); - fprintf (file, ","); - asm_print_register (file, REGNO (base)); - } - else - { - need_parenthesis = must_parenthesize (offset); - if (need_parenthesis) - fprintf (file, "("); - - output_addr_const (file, offset); - if (need_parenthesis) - fprintf (file, ")"); - fprintf (file, ","); - asm_print_register (file, REGNO (base)); - } - } - break; - - default: - if (GET_CODE (addr) == CONST_INT - && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000) - { - fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr)); - } - else - { - need_parenthesis = must_parenthesize (addr); - if (need_parenthesis) - fprintf (file, "("); - - output_addr_const (file, addr); - if (need_parenthesis) - fprintf (file, ")"); - } - break; - } -} - - -/* Splitting of some instructions. */ - -static rtx -m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1) -{ - rtx ret = 0; - - gcc_assert (GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT); - emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx, - gen_rtx_COMPARE (VOIDmode, op0, op1))); - ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx); - - return ret; -} - -rtx -m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1, - rtx label) -{ - rtx tmp; - - switch (GET_MODE (op0)) - { - case QImode: - case HImode: - tmp = m68hc11_expand_compare (code, op0, op1); - tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, - gen_rtx_LABEL_REF (VOIDmode, label), - pc_rtx); - emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); - return 0; -#if 0 - - /* SCz: from i386.c */ - case SFmode: - case DFmode: - /* Don't expand the comparison early, so that we get better code - when jump or whoever decides to reverse the comparison. */ - { - rtvec vec; - int use_fcomi; - - code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0, - &m68hc11_compare_op1); - - tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code), - m68hc11_compare_op0, m68hc11_compare_op1); - tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, - gen_rtx_LABEL_REF (VOIDmode, label), - pc_rtx); - tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp); - - use_fcomi = ix86_use_fcomi_compare (code); - vec = rtvec_alloc (3 + !use_fcomi); - RTVEC_ELT (vec, 0) = tmp; - RTVEC_ELT (vec, 1) - = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18)); - RTVEC_ELT (vec, 2) - = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17)); - if (!use_fcomi) - RTVEC_ELT (vec, 3) - = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode)); - - emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec)); - return; - } -#endif - - case SImode: - /* Expand SImode branch into multiple compare+branch. */ - { - rtx lo[2], hi[2], label2; - enum rtx_code code1, code2, code3; - - if (CONSTANT_P (op0) && !CONSTANT_P (op1)) - { - tmp = op0; - op0 = op1; - op1 = tmp; - code = swap_condition (code); - } - lo[0] = m68hc11_gen_lowpart (HImode, op0); - lo[1] = m68hc11_gen_lowpart (HImode, op1); - hi[0] = m68hc11_gen_highpart (HImode, op0); - hi[1] = m68hc11_gen_highpart (HImode, op1); - - /* Otherwise, if we are doing less-than, op1 is a constant and the - low word is zero, then we can just examine the high word. */ - - if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx - && (code == LT || code == LTU)) - { - return m68hc11_expand_compare_and_branch (code, hi[0], hi[1], - label); - } - - /* Otherwise, we need two or three jumps. */ - - label2 = gen_label_rtx (); - - code1 = code; - code2 = swap_condition (code); - code3 = unsigned_condition (code); - - switch (code) - { - case LT: - case GT: - case LTU: - case GTU: - break; - - case LE: - code1 = LT; - code2 = GT; - break; - case GE: - code1 = GT; - code2 = LT; - break; - case LEU: - code1 = LTU; - code2 = GTU; - break; - case GEU: - code1 = GTU; - code2 = LTU; - break; - - case EQ: - code1 = UNKNOWN; - code2 = NE; - break; - case NE: - code2 = UNKNOWN; - break; - - default: - gcc_unreachable (); - } - - /* - * a < b => - * if (hi(a) < hi(b)) goto true; - * if (hi(a) > hi(b)) goto false; - * if (lo(a) < lo(b)) goto true; - * false: - */ - if (code1 != UNKNOWN) - m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label); - if (code2 != UNKNOWN) - m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2); - - m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label); - - if (code2 != UNKNOWN) - emit_label (label2); - return 0; - } - - default: - gcc_unreachable (); - } - return 0; -} - -/* Return the increment/decrement mode of a MEM if it is such. - Return CONST if it is anything else. */ -static int -autoinc_mode (rtx x) -{ - if (GET_CODE (x) != MEM) - return CONST; - - x = XEXP (x, 0); - if (GET_CODE (x) == PRE_INC - || GET_CODE (x) == PRE_DEC - || GET_CODE (x) == POST_INC - || GET_CODE (x) == POST_DEC) - return GET_CODE (x); - - return CONST; -} - -static int -m68hc11_make_autoinc_notes (rtx *x, void *data) -{ - rtx insn; - - switch (GET_CODE (*x)) - { - case PRE_DEC: - case PRE_INC: - case POST_DEC: - case POST_INC: - insn = (rtx) data; - REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0), - REG_NOTES (insn)); - return -1; - - default: - return 0; - } -} - -/* Split a DI, SI or HI move into several smaller move operations. - The scratch register 'scratch' is used as a temporary to load - store intermediate values. It must be a hard register. */ -void -m68hc11_split_move (rtx to, rtx from, rtx scratch) -{ - rtx low_to, low_from; - rtx high_to, high_from; - rtx insn; - enum machine_mode mode; - int offset = 0; - int autoinc_from = autoinc_mode (from); - int autoinc_to = autoinc_mode (to); - - mode = GET_MODE (to); - - /* If the TO and FROM contain autoinc modes that are not compatible - together (one pop and the other a push), we must change one to - an offsetable operand and generate an appropriate add at the end. */ - if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2) - { - rtx reg; - int code; - - /* The source uses an autoinc mode which is not compatible with - a split (this would result in a word swap). */ - if (autoinc_from == PRE_INC || autoinc_from == POST_DEC) - { - code = GET_CODE (XEXP (from, 0)); - reg = XEXP (XEXP (from, 0), 0); - offset = GET_MODE_SIZE (GET_MODE (from)); - if (code == POST_DEC) - offset = -offset; - - if (code == PRE_INC) - emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); - - m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch); - if (code == POST_DEC) - emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); - return; - } - - /* Likewise for destination. */ - if (autoinc_to == PRE_INC || autoinc_to == POST_DEC) - { - code = GET_CODE (XEXP (to, 0)); - reg = XEXP (XEXP (to, 0), 0); - offset = GET_MODE_SIZE (GET_MODE (to)); - if (code == POST_DEC) - offset = -offset; - - if (code == PRE_INC) - emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); - - m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch); - if (code == POST_DEC) - emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); - return; - } - - /* The source and destination auto increment modes must be compatible - with each other: same direction. */ - if ((autoinc_to != autoinc_from - && autoinc_to != CONST && autoinc_from != CONST) - /* The destination address register must not be used within - the source operand because the source address would change - while doing the copy. */ - || (autoinc_to != CONST - && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from) - && !IS_STACK_PUSH (to))) - { - /* Must change the destination. */ - code = GET_CODE (XEXP (to, 0)); - reg = XEXP (XEXP (to, 0), 0); - offset = GET_MODE_SIZE (GET_MODE (to)); - if (code == PRE_DEC || code == POST_DEC) - offset = -offset; - - if (code == PRE_DEC || code == PRE_INC) - emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); - m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch); - if (code == POST_DEC || code == POST_INC) - emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); - - return; - } - - /* Likewise, the source address register must not be used within - the destination operand. */ - if (autoinc_from != CONST - && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to) - && !IS_STACK_PUSH (to)) - { - /* Must change the source. */ - code = GET_CODE (XEXP (from, 0)); - reg = XEXP (XEXP (from, 0), 0); - offset = GET_MODE_SIZE (GET_MODE (from)); - if (code == PRE_DEC || code == POST_DEC) - offset = -offset; - - if (code == PRE_DEC || code == PRE_INC) - emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); - m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch); - if (code == POST_DEC || code == POST_INC) - emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); - - return; - } - } - - if (GET_MODE_SIZE (mode) == 8) - mode = SImode; - else if (GET_MODE_SIZE (mode) == 4) - mode = HImode; - else - mode = QImode; - - if (TARGET_M6812 - && IS_STACK_PUSH (to) - && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from)) - { - if (mode == SImode) - { - offset = 4; - } - else if (mode == HImode) - { - offset = 2; - } - else - offset = 0; - } - - low_to = m68hc11_gen_lowpart (mode, to); - high_to = m68hc11_gen_highpart (mode, to); - - low_from = m68hc11_gen_lowpart (mode, from); - high_from = m68hc11_gen_highpart (mode, from); - - if (offset) - { - high_from = adjust_address (high_from, mode, offset); - low_from = high_from; - } - - /* When copying with a POST_INC mode, we must copy the - high part and then the low part to guarantee a correct - 32/64-bit copy. */ - if (TARGET_M6812 - && GET_MODE_SIZE (mode) >= 2 - && autoinc_from != autoinc_to - && (autoinc_from == POST_INC || autoinc_to == POST_INC)) - { - rtx swap; - - swap = low_to; - low_to = high_to; - high_to = swap; - - swap = low_from; - low_from = high_from; - high_from = swap; - } - if (mode == SImode) - { - m68hc11_split_move (low_to, low_from, scratch); - m68hc11_split_move (high_to, high_from, scratch); - } - else if (H_REG_P (to) || H_REG_P (from) - || (low_from == const0_rtx - && high_from == const0_rtx - && ! push_operand (to, GET_MODE (to)) - && ! H_REG_P (scratch)) - || (TARGET_M6812 - && (!m68hc11_register_indirect_p (from, GET_MODE (from)) - || m68hc11_small_indexed_indirect_p (from, - GET_MODE (from))) - && (!m68hc11_register_indirect_p (to, GET_MODE (to)) - || m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))) - { - insn = emit_move_insn (low_to, low_from); - for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); - - insn = emit_move_insn (high_to, high_from); - for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); - } - else - { - insn = emit_move_insn (scratch, low_from); - for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); - insn = emit_move_insn (low_to, scratch); - for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); - - insn = emit_move_insn (scratch, high_from); - for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); - insn = emit_move_insn (high_to, scratch); - for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); - } -} - -static rtx -simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result) -{ - int val; - int mask; - - *result = 0; - if (GET_CODE (operand) != CONST_INT) - return operand; - - if (mode == HImode) - mask = 0x0ffff; - else - mask = 0x0ff; - - val = INTVAL (operand); - switch (code) - { - case IOR: - if ((val & mask) == 0) - return 0; - if ((val & mask) == mask) - *result = constm1_rtx; - break; - - case AND: - if ((val & mask) == 0) - *result = const0_rtx; - if ((val & mask) == mask) - return 0; - break; - - case XOR: - if ((val & mask) == 0) - return 0; - break; - } - return operand; -} - -static void -m68hc11_emit_logical (enum machine_mode mode, enum rtx_code code, rtx *operands) -{ - rtx result; - int need_copy; - - need_copy = (rtx_equal_p (operands[0], operands[1]) - || rtx_equal_p (operands[0], operands[2])) ? 0 : 1; - - operands[1] = simplify_logical (mode, code, operands[1], &result); - operands[2] = simplify_logical (mode, code, operands[2], &result); - - if (result && GET_CODE (result) == CONST_INT) - { - if (!H_REG_P (operands[0]) && operands[3] - && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0]))) - { - emit_move_insn (operands[3], result); - emit_move_insn (operands[0], operands[3]); - } - else - { - emit_move_insn (operands[0], result); - } - } - else if (operands[1] != 0 && operands[2] != 0) - { - if (!H_REG_P (operands[0]) && operands[3]) - { - emit_move_insn (operands[3], operands[1]); - emit_insn (gen_rtx_SET (mode, - operands[3], - gen_rtx_fmt_ee (code, mode, - operands[3], operands[2]))); - emit_move_insn (operands[0], operands[3]); - } - else - { - emit_insn (gen_rtx_SET (mode, operands[0], - gen_rtx_fmt_ee (code, mode, - operands[0], operands[2]))); - } - } - - /* The logical operation is similar to a copy. */ - else if (need_copy) - { - rtx src; - - if (GET_CODE (operands[1]) == CONST_INT) - src = operands[2]; - else - src = operands[1]; - - if (!H_REG_P (operands[0]) && !H_REG_P (src)) - { - emit_move_insn (operands[3], src); - emit_move_insn (operands[0], operands[3]); - } - else - { - emit_move_insn (operands[0], src); - } - } -} - -void -m68hc11_split_logical (enum machine_mode mode, enum rtx_code code, - rtx *operands) -{ - rtx low[4]; - rtx high[4]; - - low[0] = m68hc11_gen_lowpart (mode, operands[0]); - low[1] = m68hc11_gen_lowpart (mode, operands[1]); - low[2] = m68hc11_gen_lowpart (mode, operands[2]); - - high[0] = m68hc11_gen_highpart (mode, operands[0]); - high[1] = m68hc11_gen_highpart (mode, operands[1]); - high[2] = m68hc11_gen_highpart (mode, operands[2]); - - low[3] = operands[3]; - high[3] = operands[3]; - if (mode == SImode) - { - m68hc11_split_logical (HImode, code, low); - m68hc11_split_logical (HImode, code, high); - return; - } - - m68hc11_emit_logical (mode, code, low); - m68hc11_emit_logical (mode, code, high); -} - - -/* Code generation. */ - -void -m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[]) -{ - /* We have to be careful with the cc_status. An address register swap - is generated for some comparison. The comparison is made with D - but the branch really uses the address register. See the split - pattern for compare. The xgdx/xgdy preserve the flags but after - the exchange, the flags will reflect to the value of X and not D. - Tell this by setting the cc_status according to the cc_prev_status. */ - if (X_REG_P (operands[1]) || X_REG_P (operands[0])) - { - if (cc_prev_status.value1 != 0 - && (D_REG_P (cc_prev_status.value1) - || X_REG_P (cc_prev_status.value1))) - { - cc_status = cc_prev_status; - if (D_REG_P (cc_status.value1)) - cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1), - HARD_X_REGNUM); - else - cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1), - HARD_D_REGNUM); - } - else - CC_STATUS_INIT; - - output_asm_insn ("xgdx", operands); - } - else - { - if (cc_prev_status.value1 != 0 - && (D_REG_P (cc_prev_status.value1) - || Y_REG_P (cc_prev_status.value1))) - { - cc_status = cc_prev_status; - if (D_REG_P (cc_status.value1)) - cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1), - HARD_Y_REGNUM); - else - cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1), - HARD_D_REGNUM); - } - else - CC_STATUS_INIT; - - output_asm_insn ("xgdy", operands); - } -} - -/* Returns 1 if the next insn after 'insn' is a test of the register 'reg'. - This is used to decide whether a move that set flags should be used - instead. */ -int -next_insn_test_reg (rtx insn, rtx reg) -{ - rtx body; - - insn = next_nonnote_insn (insn); - if (GET_CODE (insn) != INSN) - return 0; - - body = PATTERN (insn); - if (sets_cc0_p (body) != 1) - return 0; - - if (rtx_equal_p (XEXP (body, 1), reg) == 0) - return 0; - - return 1; -} - -/* Generate the code to move a 16-bit operand into another one. */ - -void -m68hc11_gen_movhi (rtx insn, rtx *operands) -{ - int reg; - - /* Move a register or memory to the same location. - This is possible because such insn can appear - in a non-optimizing mode. */ - if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1])) - { - cc_status = cc_prev_status; - return; - } - - if (TARGET_M6812) - { - rtx from = operands[1]; - rtx to = operands[0]; - - if (IS_STACK_PUSH (to) && H_REG_P (from)) - { - cc_status = cc_prev_status; - switch (REGNO (from)) - { - case HARD_X_REGNUM: - case HARD_Y_REGNUM: - case HARD_D_REGNUM: - output_asm_insn ("psh%1", operands); - break; - case HARD_SP_REGNUM: - output_asm_insn ("sts\t2,-sp", operands); - break; - default: - gcc_unreachable (); - } - return; - } - if (IS_STACK_POP (from) && H_REG_P (to)) - { - cc_status = cc_prev_status; - switch (REGNO (to)) - { - case HARD_X_REGNUM: - case HARD_Y_REGNUM: - case HARD_D_REGNUM: - output_asm_insn ("pul%0", operands); - break; - default: - gcc_unreachable (); - } - return; - } - if (H_REG_P (operands[0]) && H_REG_P (operands[1])) - { - m68hc11_notice_keep_cc (operands[0]); - output_asm_insn ("tfr\t%1,%0", operands); - } - else if (H_REG_P (operands[0])) - { - if (SP_REG_P (operands[0])) - output_asm_insn ("lds\t%1", operands); - else - output_asm_insn ("ld%0\t%1", operands); - } - else if (H_REG_P (operands[1])) - { - if (SP_REG_P (operands[1])) - output_asm_insn ("sts\t%0", operands); - else - output_asm_insn ("st%1\t%0", operands); - } - - /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw - instruction. We have to use a scratch register as temporary location. - Trying to use a specific pattern or constrain failed. */ - else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM) - { - rtx ops[4]; - - ops[0] = to; - ops[2] = from; - ops[3] = 0; - if (dead_register_here (insn, d_reg)) - ops[1] = d_reg; - else if (dead_register_here (insn, ix_reg)) - ops[1] = ix_reg; - else if (dead_register_here (insn, iy_reg)) - ops[1] = iy_reg; - else - { - ops[1] = d_reg; - ops[3] = d_reg; - output_asm_insn ("psh%3", ops); - } - - ops[0] = to; - ops[2] = from; - output_asm_insn ("ld%1\t%2", ops); - output_asm_insn ("st%1\t%0", ops); - if (ops[3]) - output_asm_insn ("pul%3", ops); - } - - /* Use movw for non-null constants or when we are clearing - a volatile memory reference. However, this is possible - only if the memory reference has a small offset or is an - absolute address. */ - else if (GET_CODE (from) == CONST_INT - && INTVAL (from) == 0 - && (MEM_VOLATILE_P (to) == 0 - || m68hc11_small_indexed_indirect_p (to, HImode) == 0)) - { - output_asm_insn ("clr\t%h0", operands); - output_asm_insn ("clr\t%b0", operands); - } - else - { - if ((m68hc11_register_indirect_p (from, GET_MODE (from)) - && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from))) - || (m68hc11_register_indirect_p (to, GET_MODE (to)) - && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))) - { - rtx ops[3]; - - if (operands[2]) - { - ops[0] = operands[2]; - ops[1] = from; - ops[2] = 0; - m68hc11_gen_movhi (insn, ops); - ops[0] = to; - ops[1] = operands[2]; - m68hc11_gen_movhi (insn, ops); - return; - } - else - { - /* !!!! SCz wrong here. */ - fatal_insn ("move insn not handled", insn); - } - } - else - { - m68hc11_notice_keep_cc (operands[0]); - output_asm_insn ("movw\t%1,%0", operands); - } - } - return; - } - - if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0])) - { - cc_status = cc_prev_status; - switch (REGNO (operands[0])) - { - case HARD_X_REGNUM: - case HARD_Y_REGNUM: - output_asm_insn ("pul%0", operands); - break; - case HARD_D_REGNUM: - output_asm_insn ("pula", operands); - output_asm_insn ("pulb", operands); - break; - default: - gcc_unreachable (); - } - return; - } - /* Some moves to a hard register are special. Not all of them - are really supported and we have to use a temporary - location to provide them (either the stack of a temp var). */ - if (H_REG_P (operands[0])) - { - switch (REGNO (operands[0])) - { - case HARD_D_REGNUM: - if (X_REG_P (operands[1])) - { - if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)) - { - m68hc11_output_swap (insn, operands); - } - else if (next_insn_test_reg (insn, operands[0])) - { - output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands); - } - else - { - m68hc11_notice_keep_cc (operands[0]); - output_asm_insn ("pshx\n\tpula\n\tpulb", operands); - } - } - else if (Y_REG_P (operands[1])) - { - if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)) - { - m68hc11_output_swap (insn, operands); - } - else - { - /* %t means *ZTMP scratch register. */ - output_asm_insn ("sty\t%t1", operands); - output_asm_insn ("ldd\t%t1", operands); - } - } - else if (SP_REG_P (operands[1])) - { - CC_STATUS_INIT; - if (ix_reg == 0) - create_regs_rtx (); - if (optimize == 0 || dead_register_here (insn, ix_reg) == 0) - output_asm_insn ("xgdx", operands); - output_asm_insn ("tsx", operands); - output_asm_insn ("xgdx", operands); - } - else if (IS_STACK_POP (operands[1])) - { - output_asm_insn ("pula\n\tpulb", operands); - } - else if (GET_CODE (operands[1]) == CONST_INT - && INTVAL (operands[1]) == 0) - { - output_asm_insn ("clra\n\tclrb", operands); - } - else - { - output_asm_insn ("ldd\t%1", operands); - } - break; - - case HARD_X_REGNUM: - if (D_REG_P (operands[1])) - { - if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM)) - { - m68hc11_output_swap (insn, operands); - } - else if (next_insn_test_reg (insn, operands[0])) - { - output_asm_insn ("std\t%t0\n\tldx\t%t0", operands); - } - else - { - m68hc11_notice_keep_cc (operands[0]); - output_asm_insn ("pshb", operands); - output_asm_insn ("psha", operands); - output_asm_insn ("pulx", operands); - } - } - else if (Y_REG_P (operands[1])) - { - /* When both D and Y are dead, use the sequence xgdy, xgdx - to move Y into X. The D and Y registers are modified. */ - if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM) - && dead_register_here (insn, d_reg)) - { - output_asm_insn ("xgdy", operands); - output_asm_insn ("xgdx", operands); - CC_STATUS_INIT; - } - else if (!optimize_size) - { - output_asm_insn ("sty\t%t1", operands); - output_asm_insn ("ldx\t%t1", operands); - } - else - { - CC_STATUS_INIT; - output_asm_insn ("pshy", operands); - output_asm_insn ("pulx", operands); - } - } - else if (SP_REG_P (operands[1])) - { - /* tsx, tsy preserve the flags */ - cc_status = cc_prev_status; - output_asm_insn ("tsx", operands); - } - else - { - output_asm_insn ("ldx\t%1", operands); - } - break; - - case HARD_Y_REGNUM: - if (D_REG_P (operands[1])) - { - if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM)) - { - m68hc11_output_swap (insn, operands); - } - else - { - output_asm_insn ("std\t%t1", operands); - output_asm_insn ("ldy\t%t1", operands); - } - } - else if (X_REG_P (operands[1])) - { - /* When both D and X are dead, use the sequence xgdx, xgdy - to move X into Y. The D and X registers are modified. */ - if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM) - && dead_register_here (insn, d_reg)) - { - output_asm_insn ("xgdx", operands); - output_asm_insn ("xgdy", operands); - CC_STATUS_INIT; - } - else if (!optimize_size) - { - output_asm_insn ("stx\t%t1", operands); - output_asm_insn ("ldy\t%t1", operands); - } - else - { - CC_STATUS_INIT; - output_asm_insn ("pshx", operands); - output_asm_insn ("puly", operands); - } - } - else if (SP_REG_P (operands[1])) - { - /* tsx, tsy preserve the flags */ - cc_status = cc_prev_status; - output_asm_insn ("tsy", operands); - } - else - { - output_asm_insn ("ldy\t%1", operands); - } - break; - - case HARD_SP_REGNUM: - if (D_REG_P (operands[1])) - { - m68hc11_notice_keep_cc (operands[0]); - output_asm_insn ("xgdx", operands); - output_asm_insn ("txs", operands); - output_asm_insn ("xgdx", operands); - } - else if (X_REG_P (operands[1])) - { - /* tys, txs preserve the flags */ - cc_status = cc_prev_status; - output_asm_insn ("txs", operands); - } - else if (Y_REG_P (operands[1])) - { - /* tys, txs preserve the flags */ - cc_status = cc_prev_status; - output_asm_insn ("tys", operands); - } - else - { - /* lds sets the flags but the des does not. */ - CC_STATUS_INIT; - output_asm_insn ("lds\t%1", operands); - output_asm_insn ("des", operands); - } - break; - - default: - fatal_insn ("invalid register in the move instruction", insn); - break; - } - return; - } - if (SP_REG_P (operands[1]) && REG_P (operands[0]) - && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM) - { - output_asm_insn ("sts\t%0", operands); - return; - } - - if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1])) - { - cc_status = cc_prev_status; - switch (REGNO (operands[1])) - { - case HARD_X_REGNUM: - case HARD_Y_REGNUM: - output_asm_insn ("psh%1", operands); - break; - case HARD_D_REGNUM: - output_asm_insn ("pshb", operands); - output_asm_insn ("psha", operands); - break; - default: - gcc_unreachable (); - } - return; - } - - /* Operand 1 must be a hard register. */ - if (!H_REG_P (operands[1])) - { - fatal_insn ("invalid operand in the instruction", insn); - } - - reg = REGNO (operands[1]); - switch (reg) - { - case HARD_D_REGNUM: - output_asm_insn ("std\t%0", operands); - break; - - case HARD_X_REGNUM: - output_asm_insn ("stx\t%0", operands); - break; - - case HARD_Y_REGNUM: - output_asm_insn ("sty\t%0", operands); - break; - - case HARD_SP_REGNUM: - if (ix_reg == 0) - create_regs_rtx (); - - if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM) - { - output_asm_insn ("pshx", operands); - output_asm_insn ("tsx", operands); - output_asm_insn ("inx", operands); - output_asm_insn ("inx", operands); - output_asm_insn ("stx\t%0", operands); - output_asm_insn ("pulx", operands); - } - - else if (reg_mentioned_p (ix_reg, operands[0])) - { - output_asm_insn ("sty\t%t0", operands); - output_asm_insn ("tsy", operands); - output_asm_insn ("sty\t%0", operands); - output_asm_insn ("ldy\t%t0", operands); - } - else - { - output_asm_insn ("stx\t%t0", operands); - output_asm_insn ("tsx", operands); - output_asm_insn ("stx\t%0", operands); - output_asm_insn ("ldx\t%t0", operands); - } - CC_STATUS_INIT; - break; - - default: - fatal_insn ("invalid register in the move instruction", insn); - break; - } -} - -void -m68hc11_gen_movqi (rtx insn, rtx *operands) -{ - /* Move a register or memory to the same location. - This is possible because such insn can appear - in a non-optimizing mode. */ - if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1])) - { - cc_status = cc_prev_status; - return; - } - - if (TARGET_M6812) - { - - if (H_REG_P (operands[0]) && H_REG_P (operands[1])) - { - m68hc11_notice_keep_cc (operands[0]); - output_asm_insn ("tfr\t%1,%0", operands); - } - else if (H_REG_P (operands[0])) - { - if (IS_STACK_POP (operands[1])) - output_asm_insn ("pul%b0", operands); - else if (Q_REG_P (operands[0])) - output_asm_insn ("lda%0\t%b1", operands); - else if (D_REG_P (operands[0])) - output_asm_insn ("ldab\t%b1", operands); - else - goto m6811_move; - } - else if (H_REG_P (operands[1])) - { - if (Q_REG_P (operands[1])) - output_asm_insn ("sta%1\t%b0", operands); - else if (D_REG_P (operands[1])) - output_asm_insn ("stab\t%b0", operands); - else - goto m6811_move; - } - else - { - rtx from = operands[1]; - rtx to = operands[0]; - - if ((m68hc11_register_indirect_p (from, GET_MODE (from)) - && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from))) - || (m68hc11_register_indirect_p (to, GET_MODE (to)) - && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))) - { - rtx ops[3]; - - if (operands[2]) - { - ops[0] = operands[2]; - ops[1] = from; - ops[2] = 0; - m68hc11_gen_movqi (insn, ops); - ops[0] = to; - ops[1] = operands[2]; - m68hc11_gen_movqi (insn, ops); - } - else - { - /* !!!! SCz wrong here. */ - fatal_insn ("move insn not handled", insn); - } - } - else - { - if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0) - { - output_asm_insn ("clr\t%b0", operands); - } - else - { - m68hc11_notice_keep_cc (operands[0]); - output_asm_insn ("movb\t%b1,%b0", operands); - } - } - } - return; - } - - m6811_move: - if (H_REG_P (operands[0])) - { - switch (REGNO (operands[0])) - { - case HARD_B_REGNUM: - case HARD_D_REGNUM: - if (X_REG_P (operands[1])) - { - if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)) - { - m68hc11_output_swap (insn, operands); - } - else - { - output_asm_insn ("stx\t%t1", operands); - output_asm_insn ("ldab\t%T0", operands); - } - } - else if (Y_REG_P (operands[1])) - { - if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)) - { - m68hc11_output_swap (insn, operands); - } - else - { - output_asm_insn ("sty\t%t1", operands); - output_asm_insn ("ldab\t%T0", operands); - } - } - else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1]) - && !DA_REG_P (operands[1])) - { - output_asm_insn ("ldab\t%b1", operands); - } - else if (DA_REG_P (operands[1])) - { - output_asm_insn ("tab", operands); - } - else - { - cc_status = cc_prev_status; - return; - } - break; - - case HARD_A_REGNUM: - if (X_REG_P (operands[1])) - { - output_asm_insn ("stx\t%t1", operands); - output_asm_insn ("ldaa\t%T0", operands); - } - else if (Y_REG_P (operands[1])) - { - output_asm_insn ("sty\t%t1", operands); - output_asm_insn ("ldaa\t%T0", operands); - } - else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1]) - && !DA_REG_P (operands[1])) - { - output_asm_insn ("ldaa\t%b1", operands); - } - else if (!DA_REG_P (operands[1])) - { - output_asm_insn ("tba", operands); - } - else - { - cc_status = cc_prev_status; - } - break; - - case HARD_X_REGNUM: - if (D_REG_P (operands[1])) - { - if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM)) - { - m68hc11_output_swap (insn, operands); - } - else - { - output_asm_insn ("stab\t%T1", operands); - output_asm_insn ("ldx\t%t1", operands); - } - CC_STATUS_INIT; - } - else if (Y_REG_P (operands[1])) - { - output_asm_insn ("sty\t%t0", operands); - output_asm_insn ("ldx\t%t0", operands); - } - else if (GET_CODE (operands[1]) == CONST_INT) - { - output_asm_insn ("ldx\t%1", operands); - } - else if (dead_register_here (insn, d_reg)) - { - output_asm_insn ("ldab\t%b1", operands); - output_asm_insn ("xgdx", operands); - } - else if (!reg_mentioned_p (operands[0], operands[1])) - { - output_asm_insn ("xgdx", operands); - output_asm_insn ("ldab\t%b1", operands); - output_asm_insn ("xgdx", operands); - } - else - { - output_asm_insn ("pshb", operands); - output_asm_insn ("ldab\t%b1", operands); - output_asm_insn ("stab\t%T1", operands); - output_asm_insn ("ldx\t%t1", operands); - output_asm_insn ("pulb", operands); - CC_STATUS_INIT; - } - break; - - case HARD_Y_REGNUM: - if (D_REG_P (operands[1])) - { - output_asm_insn ("stab\t%T1", operands); - output_asm_insn ("ldy\t%t1", operands); - CC_STATUS_INIT; - } - else if (X_REG_P (operands[1])) - { - output_asm_insn ("stx\t%t1", operands); - output_asm_insn ("ldy\t%t1", operands); - CC_STATUS_INIT; - } - else if (GET_CODE (operands[1]) == CONST_INT) - { - output_asm_insn ("ldy\t%1", operands); - } - else if (dead_register_here (insn, d_reg)) - { - output_asm_insn ("ldab\t%b1", operands); - output_asm_insn ("xgdy", operands); - } - else if (!reg_mentioned_p (operands[0], operands[1])) - { - output_asm_insn ("xgdy", operands); - output_asm_insn ("ldab\t%b1", operands); - output_asm_insn ("xgdy", operands); - } - else - { - output_asm_insn ("pshb", operands); - output_asm_insn ("ldab\t%b1", operands); - output_asm_insn ("stab\t%T1", operands); - output_asm_insn ("ldy\t%t1", operands); - output_asm_insn ("pulb", operands); - CC_STATUS_INIT; - } - break; - - default: - fatal_insn ("invalid register in the instruction", insn); - break; - } - } - else if (H_REG_P (operands[1])) - { - switch (REGNO (operands[1])) - { - case HARD_D_REGNUM: - case HARD_B_REGNUM: - output_asm_insn ("stab\t%b0", operands); - break; - - case HARD_A_REGNUM: - output_asm_insn ("staa\t%b0", operands); - break; - - case HARD_X_REGNUM: - output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands); - break; - - case HARD_Y_REGNUM: - output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands); - break; - - default: - fatal_insn ("invalid register in the move instruction", insn); - break; - } - return; - } - else - { - fatal_insn ("operand 1 must be a hard register", insn); - } -} - -/* Generate the code for a ROTATE or ROTATERT on a QI or HI mode. - The source and destination must be D or A and the shift must - be a constant. */ -void -m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[]) -{ - int val; - - if (GET_CODE (operands[2]) != CONST_INT - || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0]))) - fatal_insn ("invalid rotate insn", insn); - - val = INTVAL (operands[2]); - if (code == ROTATERT) - val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val; - - if (GET_MODE (operands[0]) != QImode) - CC_STATUS_INIT; - - /* Rotate by 8-bits if the shift is within [5..11]. */ - if (val >= 5 && val <= 11) - { - if (TARGET_M6812) - output_asm_insn ("exg\ta,b", operands); - else - { - output_asm_insn ("psha", operands); - output_asm_insn ("tba", operands); - output_asm_insn ("pulb", operands); - } - val -= 8; - } - - /* If the shift is big, invert the rotation. */ - else if (val >= 12) - { - val = val - 16; - } - - if (val > 0) - { - while (--val >= 0) - { - /* Set the carry to bit-15, but don't change D yet. */ - if (GET_MODE (operands[0]) != QImode) - { - output_asm_insn ("asra", operands); - output_asm_insn ("rola", operands); - } - - /* Rotate B first to move the carry to bit-0. */ - if (D_REG_P (operands[0])) - output_asm_insn ("rolb", operands); - - if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0])) - output_asm_insn ("rola", operands); - } - } - else - { - while (++val <= 0) - { - /* Set the carry to bit-8 of D. */ - if (GET_MODE (operands[0]) != QImode) - output_asm_insn ("tap", operands); - - /* Rotate B first to move the carry to bit-7. */ - if (D_REG_P (operands[0])) - output_asm_insn ("rorb", operands); - - if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0])) - output_asm_insn ("rora", operands); - } - } -} - - - -/* Store in cc_status the expressions that the condition codes will - describe after execution of an instruction whose pattern is EXP. - Do not alter them if the instruction would not alter the cc's. */ - -void -m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED) -{ - /* recognize SET insn's. */ - if (GET_CODE (exp) == SET) - { - /* Jumps do not alter the cc's. */ - if (SET_DEST (exp) == pc_rtx) - ; - - /* NOTE: most instructions don't affect the carry bit, but the - bhi/bls/bhs/blo instructions use it. This isn't mentioned in - the conditions.h header. */ - - /* Function calls clobber the cc's. */ - else if (GET_CODE (SET_SRC (exp)) == CALL) - { - CC_STATUS_INIT; - } - - /* Tests and compares set the cc's in predictable ways. */ - else if (SET_DEST (exp) == cc0_rtx) - { - cc_status.flags = 0; - cc_status.value1 = XEXP (exp, 0); - if (GET_CODE (XEXP (exp, 1)) == COMPARE - && XEXP (XEXP (exp, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp, 1), 0)))) - cc_status.value2 = XEXP (XEXP (exp, 1), 0); - else - cc_status.value2 = XEXP (exp, 1); - } - else - { - /* All other instructions affect the condition codes. */ - cc_status.flags = 0; - cc_status.value1 = XEXP (exp, 0); - cc_status.value2 = XEXP (exp, 1); - } - } - else - { - /* Default action if we haven't recognized something - and returned earlier. */ - CC_STATUS_INIT; - } - - if (cc_status.value2 != 0) - switch (GET_CODE (cc_status.value2)) - { - /* These logical operations can generate several insns. - The flags are setup according to what is generated. */ - case IOR: - case XOR: - case AND: - break; - - /* The (not ...) generates several 'com' instructions for - non QImode. We have to invalidate the flags. */ - case NOT: - if (GET_MODE (cc_status.value2) != QImode) - CC_STATUS_INIT; - break; - - case PLUS: - case MINUS: - case MULT: - case DIV: - case UDIV: - case MOD: - case UMOD: - case NEG: - if (GET_MODE (cc_status.value2) != VOIDmode) - cc_status.flags |= CC_NO_OVERFLOW; - break; - - /* The asl sets the overflow bit in such a way that this - makes the flags unusable for a next compare insn. */ - case ASHIFT: - case ROTATE: - case ROTATERT: - if (GET_MODE (cc_status.value2) != VOIDmode) - cc_status.flags |= CC_NO_OVERFLOW; - break; - - /* A load/store instruction does not affect the carry. */ - case MEM: - case SYMBOL_REF: - case REG: - case CONST_INT: - cc_status.flags |= CC_NO_OVERFLOW; - break; - - default: - break; - } - if (cc_status.value1 && GET_CODE (cc_status.value1) == REG - && cc_status.value2 - && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) - cc_status.value2 = 0; - - else if (cc_status.value1 && side_effects_p (cc_status.value1)) - cc_status.value1 = 0; - - else if (cc_status.value2 && side_effects_p (cc_status.value2)) - cc_status.value2 = 0; -} - -/* The current instruction does not affect the flags but changes - the register 'reg'. See if the previous flags can be kept for the - next instruction to avoid a comparison. */ -void -m68hc11_notice_keep_cc (rtx reg) -{ - if (reg == 0 - || cc_prev_status.value1 == 0 - || rtx_equal_p (reg, cc_prev_status.value1) - || (cc_prev_status.value2 - && reg_mentioned_p (reg, cc_prev_status.value2))) - CC_STATUS_INIT; - else - cc_status = cc_prev_status; -} - - - -/* Machine Specific Reorg. */ - -/* Z register replacement: - - GCC treats the Z register as an index base address register like - X or Y. In general, it uses it during reload to compute the address - of some operand. This helps the reload pass to avoid to fall into the - register spill failure. - - The Z register is in the A_REGS class. In the machine description, - the 'A' constraint matches it. The 'x' or 'y' constraints do not. - - It can appear everywhere an X or Y register can appear, except for - some templates in the clobber section (when a clobber of X or Y is asked). - For a given instruction, the template must ensure that no more than - 2 'A' registers are used. Otherwise, the register replacement is not - possible. - - To replace the Z register, the algorithm is not terrific: - 1. Insns that do not use the Z register are not changed - 2. When a Z register is used, we scan forward the insns to see - a potential register to use: either X or Y and sometimes D. - We stop when a call, a label or a branch is seen, or when we - detect that both X and Y are used (probably at different times, but it does - not matter). - 3. The register that will be used for the replacement of Z is saved - in a .page0 register or on the stack. If the first instruction that - used Z, uses Z as an input, the value is loaded from another .page0 - register. The replacement register is pushed on the stack in the - rare cases where a compare insn uses Z and we couldn't find if X/Y - are dead. - 4. The Z register is replaced in all instructions until we reach - the end of the Z-block, as detected by step 2. - 5. If we detect that Z is still alive, its value is saved. - If the replacement register is alive, its old value is loaded. - - The Z register can be disabled with -ffixed-z. -*/ - -struct replace_info -{ - rtx first; - rtx replace_reg; - int need_save_z; - int must_load_z; - int must_save_reg; - int must_restore_reg; - rtx last; - int regno; - int x_used; - int y_used; - int can_use_d; - int found_call; - int z_died; - int z_set_count; - rtx z_value; - int must_push_reg; - int save_before_last; - int z_loaded_with_sp; -}; - -static int m68hc11_check_z_replacement (rtx, struct replace_info *); -static void m68hc11_find_z_replacement (rtx, struct replace_info *); -static void m68hc11_z_replacement (rtx); -static void m68hc11_reassign_regs (rtx); - -int z_replacement_completed = 0; - -/* Analyze the insn to find out which replacement register to use and - the boundaries of the replacement. - Returns 0 if we reached the last insn to be replaced, 1 if we can - continue replacement in next insns. */ - -static int -m68hc11_check_z_replacement (rtx insn, struct replace_info *info) -{ - int this_insn_uses_ix; - int this_insn_uses_iy; - int this_insn_uses_z; - int this_insn_uses_z_in_dst; - int this_insn_uses_d; - rtx body; - int z_dies_here; - - /* A call is said to clobber the Z register, we don't need - to save the value of Z. We also don't need to restore - the replacement register (unless it is used by the call). */ - if (GET_CODE (insn) == CALL_INSN) - { - body = PATTERN (insn); - - info->can_use_d = 0; - - /* If the call is an indirect call with Z, we have to use the - Y register because X can be used as an input (D+X). - We also must not save Z nor restore Y. */ - if (reg_mentioned_p (z_reg, body)) - { - insn = NEXT_INSN (insn); - info->x_used = 1; - info->y_used = 0; - info->found_call = 1; - info->must_restore_reg = 0; - info->last = NEXT_INSN (insn); - } - info->need_save_z = 0; - return 0; - } - if (GET_CODE (insn) == CODE_LABEL - || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT) - return 0; - - if (GET_CODE (insn) == JUMP_INSN) - { - if (reg_mentioned_p (z_reg, insn) == 0) - return 0; - - info->can_use_d = 0; - info->must_save_reg = 0; - info->must_restore_reg = 0; - info->need_save_z = 0; - info->last = NEXT_INSN (insn); - return 0; - } - if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN) - { - return 1; - } - - /* Z register dies here. */ - z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL; - - body = PATTERN (insn); - if (GET_CODE (body) == SET) - { - rtx src = XEXP (body, 1); - rtx dst = XEXP (body, 0); - - /* Condition code is set here. We have to restore the X/Y and - save into Z before any test/compare insn because once we save/restore - we can change the condition codes. When the compare insn uses Z and - we can't use X/Y, the comparison is made with the *ZREG soft register - (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */ - if (dst == cc0_rtx) - { - if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM) - || (GET_CODE (src) == COMPARE && - ((rtx_equal_p (XEXP (src, 0), z_reg) - && H_REG_P (XEXP (src, 1))) - || (rtx_equal_p (XEXP (src, 1), z_reg) - && H_REG_P (XEXP (src, 0)))))) - { - if (insn == info->first) - { - info->must_load_z = 0; - info->must_save_reg = 0; - info->must_restore_reg = 0; - info->need_save_z = 0; - info->found_call = 1; - info->regno = SOFT_Z_REGNUM; - info->last = NEXT_INSN (insn); - } - return 0; - } - if (reg_mentioned_p (z_reg, src) == 0) - { - info->can_use_d = 0; - return 0; - } - - if (insn != info->first) - return 0; - - /* Compare insn which uses Z. We have to save/restore the X/Y - register without modifying the condition codes. For this - we have to use a push/pop insn. */ - info->must_push_reg = 1; - info->last = insn; - } - - /* Z reg is set to something new. We don't need to load it. */ - if (Z_REG_P (dst)) - { - if (!reg_mentioned_p (z_reg, src)) - { - /* Z reg is used before being set. Treat this as - a new sequence of Z register replacement. */ - if (insn != info->first) - { - return 0; - } - info->must_load_z = 0; - } - info->z_set_count++; - info->z_value = src; - if (SP_REG_P (src)) - info->z_loaded_with_sp = 1; - } - else if (reg_mentioned_p (z_reg, dst)) - info->can_use_d = 0; - - this_insn_uses_d = reg_mentioned_p (d_reg, src) - | reg_mentioned_p (d_reg, dst); - this_insn_uses_ix = reg_mentioned_p (ix_reg, src) - | reg_mentioned_p (ix_reg, dst); - this_insn_uses_iy = reg_mentioned_p (iy_reg, src) - | reg_mentioned_p (iy_reg, dst); - this_insn_uses_z = reg_mentioned_p (z_reg, src); - - /* If z is used as an address operand (like (MEM (reg z))), - we can't replace it with d. */ - if (this_insn_uses_z && !Z_REG_P (src) - && !(m68hc11_arith_operator (src, GET_MODE (src)) - && Z_REG_P (XEXP (src, 0)) - && !reg_mentioned_p (z_reg, XEXP (src, 1)) - && insn == info->first - && dead_register_here (insn, d_reg))) - info->can_use_d = 0; - - this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst); - if (TARGET_M6812 && !z_dies_here - && ((this_insn_uses_z && side_effects_p (src)) - || (this_insn_uses_z_in_dst && side_effects_p (dst)))) - { - info->need_save_z = 1; - info->z_set_count++; - } - this_insn_uses_z |= this_insn_uses_z_in_dst; - - if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy) - { - fatal_insn ("registers IX, IY and Z used in the same INSN", insn); - } - - if (this_insn_uses_d) - info->can_use_d = 0; - - /* IX and IY are used at the same time, we have to restore - the value of the scratch register before this insn. */ - if (this_insn_uses_ix && this_insn_uses_iy) - { - return 0; - } - - if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode) - info->can_use_d = 0; - - if (info->x_used == 0 && this_insn_uses_ix) - { - if (info->y_used) - { - /* We have a (set (REG:HI X) (REG:HI Z)). - Since we use Z as the replacement register, this insn - is no longer necessary. We turn it into a note. We must - not reload the old value of X. */ - if (X_REG_P (dst) && rtx_equal_p (src, z_reg)) - { - if (z_dies_here) - { - info->need_save_z = 0; - info->z_died = 1; - } - info->must_save_reg = 0; - info->must_restore_reg = 0; - info->found_call = 1; - info->can_use_d = 0; - SET_INSN_DELETED (insn); - info->last = NEXT_INSN (insn); - return 0; - } - - if (X_REG_P (dst) - && (rtx_equal_p (src, z_reg) - || (z_dies_here && !reg_mentioned_p (ix_reg, src)))) - { - if (z_dies_here) - { - info->need_save_z = 0; - info->z_died = 1; - } - info->last = NEXT_INSN (insn); - info->must_save_reg = 0; - info->must_restore_reg = 0; - } - else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src) - && !reg_mentioned_p (ix_reg, src)) - { - if (z_dies_here) - { - info->z_died = 1; - info->need_save_z = 0; - } - else if (TARGET_M6812 && side_effects_p (src)) - { - info->last = 0; - info->must_restore_reg = 0; - return 0; - } - else - { - info->save_before_last = 1; - } - info->must_restore_reg = 0; - info->last = NEXT_INSN (insn); - } - else if (info->can_use_d) - { - info->last = NEXT_INSN (insn); - info->x_used = 1; - } - return 0; - } - info->x_used = 1; - if (z_dies_here && !reg_mentioned_p (ix_reg, src) - && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM) - { - info->need_save_z = 0; - info->z_died = 1; - info->last = NEXT_INSN (insn); - info->regno = HARD_X_REGNUM; - info->must_save_reg = 0; - info->must_restore_reg = 0; - return 0; - } - if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg)) - { - info->regno = HARD_X_REGNUM; - info->must_restore_reg = 0; - info->must_save_reg = 0; - return 0; - } - } - if (info->y_used == 0 && this_insn_uses_iy) - { - if (info->x_used) - { - if (Y_REG_P (dst) && rtx_equal_p (src, z_reg)) - { - if (z_dies_here) - { - info->need_save_z = 0; - info->z_died = 1; - } - info->must_save_reg = 0; - info->must_restore_reg = 0; - info->found_call = 1; - info->can_use_d = 0; - SET_INSN_DELETED (insn); - info->last = NEXT_INSN (insn); - return 0; - } - - if (Y_REG_P (dst) - && (rtx_equal_p (src, z_reg) - || (z_dies_here && !reg_mentioned_p (iy_reg, src)))) - { - if (z_dies_here) - { - info->z_died = 1; - info->need_save_z = 0; - } - info->last = NEXT_INSN (insn); - info->must_save_reg = 0; - info->must_restore_reg = 0; - } - else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src) - && !reg_mentioned_p (iy_reg, src)) - { - if (z_dies_here) - { - info->z_died = 1; - info->need_save_z = 0; - } - else if (TARGET_M6812 && side_effects_p (src)) - { - info->last = 0; - info->must_restore_reg = 0; - return 0; - } - else - { - info->save_before_last = 1; - } - info->must_restore_reg = 0; - info->last = NEXT_INSN (insn); - } - else if (info->can_use_d) - { - info->last = NEXT_INSN (insn); - info->y_used = 1; - } - - return 0; - } - info->y_used = 1; - if (z_dies_here && !reg_mentioned_p (iy_reg, src) - && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM) - { - info->need_save_z = 0; - info->z_died = 1; - info->last = NEXT_INSN (insn); - info->regno = HARD_Y_REGNUM; - info->must_save_reg = 0; - info->must_restore_reg = 0; - return 0; - } - if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg)) - { - info->regno = HARD_Y_REGNUM; - info->must_restore_reg = 0; - info->must_save_reg = 0; - return 0; - } - } - if (z_dies_here) - { - info->need_save_z = 0; - info->z_died = 1; - if (info->last == 0) - info->last = NEXT_INSN (insn); - return 0; - } - return info->last != NULL_RTX ? 0 : 1; - } - if (GET_CODE (body) == PARALLEL) - { - int i; - char ix_clobber = 0; - char iy_clobber = 0; - char z_clobber = 0; - this_insn_uses_iy = 0; - this_insn_uses_ix = 0; - this_insn_uses_z = 0; - - for (i = XVECLEN (body, 0) - 1; i >= 0; i--) - { - rtx x; - int uses_ix, uses_iy, uses_z; - - x = XVECEXP (body, 0, i); - - if (info->can_use_d && reg_mentioned_p (d_reg, x)) - info->can_use_d = 0; - - uses_ix = reg_mentioned_p (ix_reg, x); - uses_iy = reg_mentioned_p (iy_reg, x); - uses_z = reg_mentioned_p (z_reg, x); - if (GET_CODE (x) == CLOBBER) - { - ix_clobber |= uses_ix; - iy_clobber |= uses_iy; - z_clobber |= uses_z; - } - else - { - this_insn_uses_ix |= uses_ix; - this_insn_uses_iy |= uses_iy; - this_insn_uses_z |= uses_z; - } - if (uses_z && GET_CODE (x) == SET) - { - rtx dst = XEXP (x, 0); - - if (Z_REG_P (dst)) - info->z_set_count++; - } - if (TARGET_M6812 && uses_z && side_effects_p (x)) - info->need_save_z = 1; - - if (z_clobber) - info->need_save_z = 0; - } - if (debug_m6811) - { - printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n", - this_insn_uses_ix, this_insn_uses_iy, - this_insn_uses_z, ix_clobber, iy_clobber, z_clobber); - debug_rtx (insn); - } - if (this_insn_uses_z) - info->can_use_d = 0; - - if (z_clobber && info->first != insn) - { - info->need_save_z = 0; - info->last = insn; - return 0; - } - if (z_clobber && info->x_used == 0 && info->y_used == 0) - { - if (this_insn_uses_z == 0 && insn == info->first) - { - info->must_load_z = 0; - } - if (dead_register_here (insn, d_reg)) - { - info->regno = HARD_D_REGNUM; - info->must_save_reg = 0; - info->must_restore_reg = 0; - } - else if (dead_register_here (insn, ix_reg)) - { - info->regno = HARD_X_REGNUM; - info->must_save_reg = 0; - info->must_restore_reg = 0; - } - else if (dead_register_here (insn, iy_reg)) - { - info->regno = HARD_Y_REGNUM; - info->must_save_reg = 0; - info->must_restore_reg = 0; - } - if (info->regno >= 0) - { - info->last = NEXT_INSN (insn); - return 0; - } - if (this_insn_uses_ix == 0) - { - info->regno = HARD_X_REGNUM; - info->must_save_reg = 1; - info->must_restore_reg = 1; - } - else if (this_insn_uses_iy == 0) - { - info->regno = HARD_Y_REGNUM; - info->must_save_reg = 1; - info->must_restore_reg = 1; - } - else - { - info->regno = HARD_D_REGNUM; - info->must_save_reg = 1; - info->must_restore_reg = 1; - } - info->last = NEXT_INSN (insn); - return 0; - } - - if (((info->x_used || this_insn_uses_ix) && iy_clobber) - || ((info->y_used || this_insn_uses_iy) && ix_clobber)) - { - if (this_insn_uses_z) - { - if (info->y_used == 0 && iy_clobber) - { - info->regno = HARD_Y_REGNUM; - info->must_save_reg = 0; - info->must_restore_reg = 0; - } - if (info->first != insn - && ((info->y_used && ix_clobber) - || (info->x_used && iy_clobber))) - info->last = insn; - else - info->last = NEXT_INSN (insn); - info->save_before_last = 1; - } - return 0; - } - if (this_insn_uses_ix && this_insn_uses_iy) - { - if (this_insn_uses_z) - { - fatal_insn ("cannot do z-register replacement", insn); - } - return 0; - } - if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber)) - { - if (info->y_used) - { - return 0; - } - info->x_used = 1; - if (iy_clobber || z_clobber) - { - info->last = NEXT_INSN (insn); - info->save_before_last = 1; - return 0; - } - } - - if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber)) - { - if (info->x_used) - { - return 0; - } - info->y_used = 1; - if (ix_clobber || z_clobber) - { - info->last = NEXT_INSN (insn); - info->save_before_last = 1; - return 0; - } - } - if (z_dies_here) - { - info->z_died = 1; - info->need_save_z = 0; - } - return 1; - } - if (GET_CODE (body) == CLOBBER) - { - rtx dst = XEXP (body, 0); - - this_insn_uses_ix = reg_mentioned_p (ix_reg, dst); - this_insn_uses_iy = reg_mentioned_p (iy_reg, dst); - - /* IX and IY are used at the same time, we have to restore - the value of the scratch register before this insn. */ - if (this_insn_uses_ix && this_insn_uses_iy) - { - return 0; - } - if (info->x_used == 0 && this_insn_uses_ix) - { - if (info->y_used) - { - return 0; - } - info->x_used = 1; - } - if (info->y_used == 0 && this_insn_uses_iy) - { - if (info->x_used) - { - return 0; - } - info->y_used = 1; - } - return 1; - } - return 1; -} - -static void -m68hc11_find_z_replacement (rtx insn, struct replace_info *info) -{ - int reg; - - info->replace_reg = NULL_RTX; - info->must_load_z = 1; - info->need_save_z = 1; - info->must_save_reg = 1; - info->must_restore_reg = 1; - info->first = insn; - info->x_used = 0; - info->y_used = 0; - info->can_use_d = TARGET_M6811 ? 1 : 0; - info->found_call = 0; - info->z_died = 0; - info->last = 0; - info->regno = -1; - info->z_set_count = 0; - info->z_value = NULL_RTX; - info->must_push_reg = 0; - info->save_before_last = 0; - info->z_loaded_with_sp = 0; - - /* Scan the insn forward to find an address register that is not used. - Stop when: - - the flow of the program changes, - - when we detect that both X and Y are necessary, - - when the Z register dies, - - when the condition codes are set. */ - - for (; insn && info->z_died == 0; insn = NEXT_INSN (insn)) - { - if (m68hc11_check_z_replacement (insn, info) == 0) - break; - } - - /* May be we can use Y or X if they contain the same value as Z. - This happens very often after the reload. */ - if (info->z_set_count == 1) - { - rtx p = info->first; - rtx v = 0; - - if (info->x_used) - { - v = find_last_value (iy_reg, &p, insn, 1); - } - else if (info->y_used) - { - v = find_last_value (ix_reg, &p, insn, 1); - } - if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value)) - { - if (info->x_used) - info->regno = HARD_Y_REGNUM; - else - info->regno = HARD_X_REGNUM; - info->must_load_z = 0; - info->must_save_reg = 0; - info->must_restore_reg = 0; - info->found_call = 1; - } - } - if (info->z_set_count == 0) - info->need_save_z = 0; - - if (insn == 0) - info->need_save_z = 0; - - if (info->last == 0) - info->last = insn; - - if (info->regno >= 0) - { - reg = info->regno; - info->replace_reg = gen_rtx_REG (HImode, reg); - } - else if (info->can_use_d) - { - reg = HARD_D_REGNUM; - info->replace_reg = d_reg; - } - else if (info->x_used) - { - reg = HARD_Y_REGNUM; - info->replace_reg = iy_reg; - } - else - { - reg = HARD_X_REGNUM; - info->replace_reg = ix_reg; - } - info->regno = reg; - - if (info->must_save_reg && info->must_restore_reg) - { - if (insn && dead_register_here (insn, info->replace_reg)) - { - info->must_save_reg = 0; - info->must_restore_reg = 0; - } - } -} - -/* The insn uses the Z register. Find a replacement register for it - (either X or Y) and replace it in the insn and the next ones until - the flow changes or the replacement register is used. Instructions - are emitted before and after the Z-block to preserve the value of - Z and of the replacement register. */ - -static void -m68hc11_z_replacement (rtx insn) -{ - rtx replace_reg_qi; - rtx replace_reg; - struct replace_info info; - - /* Find trivial case where we only need to replace z with the - equivalent soft register. */ - if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET) - { - rtx body = PATTERN (insn); - rtx src = XEXP (body, 1); - rtx dst = XEXP (body, 0); - - if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src))) - { - XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM); - return; - } - else if (Z_REG_P (src) - && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx)) - { - XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM); - return; - } - else if (D_REG_P (dst) - && m68hc11_arith_operator (src, GET_MODE (src)) - && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1))) - { - XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM); - return; - } - else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT - && INTVAL (src) == 0) - { - XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM); - /* Force it to be re-recognized. */ - INSN_CODE (insn) = -1; - return; - } - } - - m68hc11_find_z_replacement (insn, &info); - - replace_reg = info.replace_reg; - replace_reg_qi = NULL_RTX; - - /* Save the X register in a .page0 location. */ - if (info.must_save_reg && !info.must_push_reg) - { - rtx dst; - - if (info.must_push_reg && 0) - dst = gen_rtx_MEM (HImode, - gen_rtx_PRE_DEC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM))); - else - dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM); - - emit_insn_before (gen_movhi (dst, - gen_rtx_REG (HImode, info.regno)), insn); - } - if (info.must_load_z && !info.must_push_reg) - { - emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno), - gen_rtx_REG (HImode, SOFT_Z_REGNUM)), - insn); - } - - - /* Replace all occurrence of Z by replace_reg. - Stop when the last instruction to replace is reached. - Also stop when we detect a change in the flow (but it's not - necessary; just safeguard). */ - - for (; insn && insn != info.last; insn = NEXT_INSN (insn)) - { - rtx body; - - if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER) - break; - - if (GET_CODE (insn) != INSN - && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN) - continue; - - body = PATTERN (insn); - if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL - || GET_CODE (body) == ASM_OPERANDS - || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) - { - rtx note; - - if (debug_m6811 && reg_mentioned_p (replace_reg, body)) - { - printf ("Reg mentioned here...:\n"); - fflush (stdout); - debug_rtx (insn); - } - - /* Stack pointer was decremented by 2 due to the push. - Correct that by adding 2 to the destination. */ - if (info.must_push_reg - && info.z_loaded_with_sp && GET_CODE (body) == SET) - { - rtx src, dst; - - src = SET_SRC (body); - dst = SET_DEST (body); - if (SP_REG_P (src) && Z_REG_P (dst)) - emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn); - } - - /* Replace any (REG:HI Z) occurrence by either X or Y. */ - if (!validate_replace_rtx (z_reg, replace_reg, insn)) - { - INSN_CODE (insn) = -1; - if (!validate_replace_rtx (z_reg, replace_reg, insn)) - fatal_insn ("cannot do z-register replacement", insn); - } - - /* Likewise for (REG:QI Z). */ - if (reg_mentioned_p (z_reg, insn)) - { - if (replace_reg_qi == NULL_RTX) - replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg)); - validate_replace_rtx (z_reg_qi, replace_reg_qi, insn); - } - - /* If there is a REG_INC note on Z, replace it with a - REG_INC note on the replacement register. This is necessary - to make sure that the flow pass will identify the change - and it will not remove a possible insn that saves Z. */ - for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) - { - if (REG_NOTE_KIND (note) == REG_INC - && GET_CODE (XEXP (note, 0)) == REG - && REGNO (XEXP (note, 0)) == REGNO (z_reg)) - { - XEXP (note, 0) = replace_reg; - } - } - } - if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) - break; - } - - /* Save Z before restoring the old value. */ - if (insn && info.need_save_z && !info.must_push_reg) - { - rtx save_pos_insn = insn; - - /* If Z is clobber by the last insn, we have to save its value - before the last instruction. */ - if (info.save_before_last) - save_pos_insn = PREV_INSN (save_pos_insn); - - emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM), - gen_rtx_REG (HImode, info.regno)), - save_pos_insn); - } - - if (info.must_push_reg && info.last) - { - rtx new_body, body; - - body = PATTERN (info.last); - new_body = gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (3, body, - gen_rtx_USE (VOIDmode, - replace_reg), - gen_rtx_USE (VOIDmode, - gen_rtx_REG (HImode, - SOFT_Z_REGNUM)))); - PATTERN (info.last) = new_body; - - /* Force recognition on insn since we changed it. */ - INSN_CODE (insn) = -1; - - if (!validate_replace_rtx (z_reg, replace_reg, info.last)) - { - fatal_insn ("invalid Z register replacement for insn", insn); - } - insn = NEXT_INSN (info.last); - } - - /* Restore replacement register unless it was died. */ - if (insn && info.must_restore_reg && !info.must_push_reg) - { - rtx dst; - - if (info.must_push_reg && 0) - dst = gen_rtx_MEM (HImode, - gen_rtx_POST_INC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM))); - else - dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM); - - emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno), - dst), insn); - } - -} - - -/* Scan all the insn and re-affects some registers - - The Z register (if it was used), is affected to X or Y depending - on the instruction. */ - -static void -m68hc11_reassign_regs (rtx first) -{ - rtx insn; - - ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM); - iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM); - z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM); - z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM); - - /* Scan all insns to replace Z by X or Y preserving the old value - of X/Y and restoring it afterward. */ - - for (insn = first; insn; insn = NEXT_INSN (insn)) - { - rtx body; - - if (GET_CODE (insn) == CODE_LABEL - || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER) - continue; - - if (!INSN_P (insn)) - continue; - - body = PATTERN (insn); - if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE) - continue; - - if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT - || GET_CODE (body) == ASM_OPERANDS - || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE) - continue; - - if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL - || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) - { - - /* If Z appears in this insn, replace it in the current insn - and the next ones until the flow changes or we have to - restore back the replacement register. */ - - if (reg_mentioned_p (z_reg, body)) - { - m68hc11_z_replacement (insn); - } - } - else - { - printf ("insn not handled by Z replacement:\n"); - fflush (stdout); - debug_rtx (insn); - } - } -} - - -/* Machine-dependent reorg pass. - Specific optimizations are defined here: - - this pass changes the Z register into either X or Y - (it preserves X/Y previous values in a memory slot in page0). - - When this pass is finished, the global variable - 'z_replacement_completed' is set to 2. */ - -static void -m68hc11_reorg (void) -{ - int split_done = 0; - rtx first; - - z_replacement_completed = 0; - z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM); - first = get_insns (); - - /* Some RTX are shared at this point. This breaks the Z register - replacement, unshare everything. */ - unshare_all_rtl_again (first); - - /* Force a split of all splittable insn. This is necessary for the - Z register replacement mechanism because we end up with basic insns. */ - split_all_insns_noflow (); - split_done = 1; - - z_replacement_completed = 1; - m68hc11_reassign_regs (first); - - if (optimize) - compute_bb_for_insn (); - - /* After some splitting, there are some opportunities for CSE pass. - This happens quite often when 32-bit or above patterns are split. */ - if (optimize > 0 && split_done) - { - reload_cse_regs (first); - } - - /* Re-create the REG_DEAD notes. These notes are used in the machine - description to use the best assembly directives. */ - if (optimize) - { - df_note_add_problem (); - df_analyze (); - df_remove_problem (df_note); - } - - z_replacement_completed = 2; - - /* If optimizing, then go ahead and split insns that must be - split after Z register replacement. This gives more opportunities - for peephole (in particular for consecutives xgdx/xgdy). */ - if (optimize > 0) - split_all_insns_noflow (); - - /* Once insns are split after the z_replacement_completed == 2, - we must not re-run the life_analysis. The xgdx/xgdy patterns - are not recognized and the life_analysis pass removes some - insns because it thinks some (SETs) are noops or made to dead - stores (which is false due to the swap). - - Do a simple pass to eliminate the noop set that the final - split could generate (because it was easier for split definition). */ - { - rtx insn; - - for (insn = first; insn; insn = NEXT_INSN (insn)) - { - rtx body; - - if (INSN_DELETED_P (insn)) - continue; - if (!INSN_P (insn)) - continue; - - /* Remove the (set (R) (R)) insns generated by some splits. */ - body = PATTERN (insn); - if (GET_CODE (body) == SET - && rtx_equal_p (SET_SRC (body), SET_DEST (body))) - { - SET_INSN_DELETED (insn); - continue; - } - } - } -} - -/* Override memcpy */ - -static void -m68hc11_init_libfuncs (void) -{ - memcpy_libfunc = init_one_libfunc ("__memcpy"); - memcmp_libfunc = init_one_libfunc ("__memcmp"); - memset_libfunc = init_one_libfunc ("__memset"); -} - - - -/* Cost functions. */ - -/* Cost of moving memory. */ -int -m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class rclass, - int in ATTRIBUTE_UNUSED) -{ - if (rclass <= H_REGS && rclass > NO_REGS) - { - if (GET_MODE_SIZE (mode) <= 2) - return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress); - else - return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress); - } - else - { - if (GET_MODE_SIZE (mode) <= 2) - return COSTS_N_INSNS (3); - else - return COSTS_N_INSNS (4); - } -} - - -/* Cost of moving data from a register of class 'from' to on in class 'to'. - Reload does not check the constraint of set insns when the two registers - have a move cost of 2. Setting a higher cost will force reload to check - the constraints. */ -int -m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from, - enum reg_class to) -{ - /* All costs are symmetric, so reduce cases by putting the - lower number class as the destination. */ - if (from < to) - { - enum reg_class tmp = to; - to = from, from = tmp; - } - if (to >= S_REGS) - return m68hc11_memory_move_cost (mode, S_REGS, 0); - else if (from <= S_REGS) - return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress); - else - return COSTS_N_INSNS (2); -} - - -/* Provide the costs of an addressing mode that contains ADDR. - If ADDR is not a valid address, its cost is irrelevant. */ - -static int -m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED) -{ - int cost = 4; - - switch (GET_CODE (addr)) - { - case REG: - /* Make the cost of hard registers and specially SP, FP small. */ - if (REGNO (addr) < FIRST_PSEUDO_REGISTER) - cost = 0; - else - cost = 1; - break; - - case SYMBOL_REF: - cost = 8; - break; - - case LABEL_REF: - case CONST: - cost = 0; - break; - - case PLUS: - { - register rtx plus0 = XEXP (addr, 0); - register rtx plus1 = XEXP (addr, 1); - - if (GET_CODE (plus0) != REG) - break; - - switch (GET_CODE (plus1)) - { - case CONST_INT: - if (INTVAL (plus1) >= 2 * m68hc11_max_offset - || INTVAL (plus1) < m68hc11_min_offset) - cost = 3; - else if (INTVAL (plus1) >= m68hc11_max_offset) - cost = 2; - else - cost = 1; - if (REGNO (plus0) < FIRST_PSEUDO_REGISTER) - cost += 0; - else - cost += 1; - break; - - case SYMBOL_REF: - cost = 8; - break; - - case CONST: - case LABEL_REF: - cost = 0; - break; - - default: - break; - } - break; - } - case PRE_DEC: - case PRE_INC: - if (SP_REG_P (XEXP (addr, 0))) - cost = 1; - break; - - default: - break; - } - if (debug_m6811) - { - printf ("Address cost: %d for :", cost); - fflush (stdout); - debug_rtx (addr); - } - - return cost; -} - -static int -m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift) -{ - int total; - - total = rtx_cost (x, SET, !optimize_size); - if (mode == QImode) - total += m68hc11_cost->shiftQI_const[shift % 8]; - else if (mode == HImode) - total += m68hc11_cost->shiftHI_const[shift % 16]; - else if (shift == 8 || shift == 16 || shift == 32) - total += m68hc11_cost->shiftHI_const[8]; - else if (shift != 0 && shift != 16 && shift != 32) - { - total += m68hc11_cost->shiftHI_const[1] * shift; - } - - /* For SI and others, the cost is higher. */ - if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0) - total *= GET_MODE_SIZE (mode) / 2; - - /* When optimizing for size, make shift more costly so that - multiplications are preferred. */ - if (optimize_size && (shift % 8) != 0) - total *= 2; - - return total; -} - -static int -m68hc11_rtx_costs_1 (rtx x, enum rtx_code code, - enum rtx_code outer_code ATTRIBUTE_UNUSED) -{ - enum machine_mode mode = GET_MODE (x); - int extra_cost = 0; - int total; - - switch (code) - { - case ROTATE: - case ROTATERT: - case ASHIFT: - case LSHIFTRT: - case ASHIFTRT: - if (GET_CODE (XEXP (x, 1)) == CONST_INT) - { - return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1))); - } - - total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size); - total += m68hc11_cost->shift_var; - return total; - - case AND: - case XOR: - case IOR: - total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size); - total += m68hc11_cost->logical; - - /* Logical instructions are byte instructions only. */ - total *= GET_MODE_SIZE (mode); - return total; - - case MINUS: - case PLUS: - total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size); - total += m68hc11_cost->add; - if (GET_MODE_SIZE (mode) > 2) - { - total *= GET_MODE_SIZE (mode) / 2; - } - return total; - - case UDIV: - case DIV: - case MOD: - total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size); - switch (mode) - { - case QImode: - total += m68hc11_cost->divQI; - break; - - case HImode: - total += m68hc11_cost->divHI; - break; - - case SImode: - default: - total += m68hc11_cost->divSI; - break; - } - return total; - - case MULT: - /* mul instruction produces 16-bit result. */ - if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND - && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND) - return m68hc11_cost->multQI - + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size) - + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size); - - /* emul instruction produces 32-bit result for 68HC12. */ - if (TARGET_M6812 && mode == SImode - && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND - && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND) - return m68hc11_cost->multHI - + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size) - + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size); - - total = rtx_cost (XEXP (x, 0), code, !optimize_size) - + rtx_cost (XEXP (x, 1), code, !optimize_size); - switch (mode) - { - case QImode: - total += m68hc11_cost->multQI; - break; - - case HImode: - total += m68hc11_cost->multHI; - break; - - case SImode: - default: - total += m68hc11_cost->multSI; - break; - } - return total; - - case NEG: - case SIGN_EXTEND: - extra_cost = COSTS_N_INSNS (2); - - /* Fall through */ - case NOT: - case COMPARE: - case ABS: - case ZERO_EXTEND: - case ZERO_EXTRACT: - total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size); - if (mode == QImode) - { - return total + COSTS_N_INSNS (1); - } - if (mode == HImode) - { - return total + COSTS_N_INSNS (2); - } - if (mode == SImode) - { - return total + COSTS_N_INSNS (4); - } - return total + COSTS_N_INSNS (8); - - case IF_THEN_ELSE: - if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC) - return COSTS_N_INSNS (1); - - return COSTS_N_INSNS (1); - - default: - return COSTS_N_INSNS (4); - } -} - -static bool -m68hc11_rtx_costs (rtx x, int codearg, int outer_code_arg, int *total, - bool speed ATTRIBUTE_UNUSED) -{ - enum rtx_code code = (enum rtx_code) codearg; - enum rtx_code outer_code = (enum rtx_code) outer_code_arg; - - switch (code) - { - /* Constants are cheap. Moving them in registers must be avoided - because most instructions do not handle two register operands. */ - case CONST_INT: - case CONST: - case LABEL_REF: - case SYMBOL_REF: - case CONST_DOUBLE: - /* Logical and arithmetic operations with a constant operand are - better because they are not supported with two registers. */ - /* 'clr' is slow */ - if (outer_code == SET && x == const0_rtx) - /* After reload, the reload_cse pass checks the cost to change - a SET into a PLUS. Make const0 cheap then. */ - *total = 1 - reload_completed; - else - *total = 0; - return true; - - case ZERO_EXTRACT: - if (outer_code != COMPARE) - return false; - - case ROTATE: - case ROTATERT: - case ASHIFT: - case LSHIFTRT: - case ASHIFTRT: - case MINUS: - case PLUS: - case AND: - case XOR: - case IOR: - case UDIV: - case DIV: - case MOD: - case MULT: - case NEG: - case SIGN_EXTEND: - case NOT: - case COMPARE: - case ZERO_EXTEND: - case IF_THEN_ELSE: - *total = m68hc11_rtx_costs_1 (x, code, outer_code); - return true; - - default: - return false; - } -} - - -/* Worker function for TARGET_ASM_FILE_START. */ - -static void -m68hc11_file_start (void) -{ - default_file_start (); - - fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong"); -} - - -/* Worker function for TARGET_ASM_CONSTRUCTOR. */ - -static void -m68hc11_asm_out_constructor (rtx symbol, int priority) -{ - default_ctor_section_asm_out_constructor (symbol, priority); - fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n"); -} - -/* Worker function for TARGET_ASM_DESTRUCTOR. */ - -static void -m68hc11_asm_out_destructor (rtx symbol, int priority) -{ - default_dtor_section_asm_out_destructor (symbol, priority); - fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n"); -} - -/* Worker function for TARGET_STRUCT_VALUE_RTX. */ - -static rtx -m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, - int incoming ATTRIBUTE_UNUSED) -{ - return gen_rtx_REG (Pmode, HARD_D_REGNUM); -} - -/* Return true if type TYPE should be returned in memory. - Blocks and data types largers than 4 bytes cannot be returned - in the register (D + X = 4). */ - -static bool -m68hc11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) -{ - if (TYPE_MODE (type) == BLKmode) - { - HOST_WIDE_INT size = int_size_in_bytes (type); - return (size == -1 || size > 4); - } - else - return GET_MODE_SIZE (TYPE_MODE (type)) > 4; -} - -#include "gt-m68hc11.h" diff --git a/gcc/config/m68hc11/m68hc11.h b/gcc/config/m68hc11/m68hc11.h deleted file mode 100644 index 8f6d06867ee..00000000000 --- a/gcc/config/m68hc11/m68hc11.h +++ /dev/null @@ -1,1382 +0,0 @@ -/* Definitions of target machine for GNU compiler. - Motorola 68HC11 and 68HC12. - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. - Contributed by Stephane Carrez (stcarrez@nerim.fr) - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. - -Note: - A first 68HC11 port was made by Otto Lind (otto@coactive.com) - on gcc 2.6.3. I have used it as a starting point for this port. - However, this new port is a complete re-write. Its internal - design is completely different. The generated code is not - compatible with the gcc 2.6.3 port. - - The gcc 2.6.3 port is available at: - - ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz - -*/ - -/***************************************************************************** -** -** Controlling the Compilation Driver, `gcc' -** -*****************************************************************************/ - -#undef ENDFILE_SPEC - -/* Compile and assemble for a 68hc11 unless there is a -m68hc12 option. */ -#ifndef ASM_SPEC -#define ASM_SPEC \ -"%{m68hc12:-m68hc12}" \ -"%{m68hcs12:-m68hcs12}" \ -"%{!m68hc12:%{!m68hcs12:-m68hc11}} " \ -"%{mshort:-mshort}%{!mshort:-mlong} " \ -"%{fshort-double:-mshort-double}%{!fshort-double:-mlong-double}" -#endif - -/* We need to tell the linker the target elf format. Just pass an - emulation option. This can be overridden by -Wl option of gcc. */ -#ifndef LINK_SPEC -#define LINK_SPEC \ -"%{m68hc12:-m m68hc12elf}" \ -"%{m68hcs12:-m m68hc12elf}" \ -"%{!m68hc12:%{!m68hcs12:-m m68hc11elf}} " \ -"%{!mnorelax:%{!m68hc12:%{!m68hcs12:-relax}}}" -#endif - -#ifndef LIB_SPEC -#define LIB_SPEC "" -#endif - -#ifndef CC1_SPEC -#define CC1_SPEC "" -#endif - -#ifndef CPP_SPEC -#define CPP_SPEC \ -"%{mshort:-D__HAVE_SHORT_INT__ -D__INT__=16}\ - %{!mshort:-D__INT__=32}\ - %{m68hc12:-Dmc6812 -DMC6812 -Dmc68hc12}\ - %{m68hcs12:-Dmc6812 -DMC6812 -Dmc68hcs12}\ - %{!m68hc12:%{!m68hcs12:-Dmc6811 -DMC6811 -Dmc68hc11}}\ - %{fshort-double:-D__HAVE_SHORT_DOUBLE__}\ - %{mlong-calls:-D__USE_RTC__}" -#endif - -#undef STARTFILE_SPEC -#define STARTFILE_SPEC "crt1%O%s" - -/* Names to predefine in the preprocessor for this target machine. */ -#define TARGET_CPU_CPP_BUILTINS() \ - do \ - { \ - builtin_define_std ("mc68hc1x"); \ - } \ - while (0) - -/* As an embedded target, we have no libc. */ -#ifndef inhibit_libc -# define inhibit_libc -#endif - -/* Forward type declaration for prototypes definitions. - rtx_ptr is equivalent to rtx. Can't use the same name. */ -struct rtx_def; -typedef struct rtx_def *rtx_ptr; - -union tree_node; -typedef union tree_node *tree_ptr; - -/* We can't declare enum machine_mode forward nor include 'machmode.h' here. - Prototypes defined here will use an int instead. It's better than no - prototype at all. */ -typedef int enum_machine_mode; - -/***************************************************************************** -** -** Run-time Target Specification -** -*****************************************************************************/ - -/* Run-time compilation parameters selecting different hardware subsets. */ - -extern short *reg_renumber; /* def in local_alloc.c */ - -#define TARGET_OP_TIME (optimize && optimize_size == 0) -#define TARGET_RELAX (TARGET_NO_DIRECT_MODE) - -/* Default target_flags if no switches specified. */ -#ifndef TARGET_DEFAULT -# define TARGET_DEFAULT 0 -#endif - -/* Define this macro as a C expression for the initializer of an - array of string to tell the driver program which options are - defaults for this target and thus do not need to be handled - specially when using `MULTILIB_OPTIONS'. */ -#ifndef MULTILIB_DEFAULTS -# if TARGET_DEFAULT & MASK_M6811 -# define MULTILIB_DEFAULTS { "m68hc11" } -# else -# define MULTILIB_DEFAULTS { "m68hc12" } -# endif -#endif - -/* Print subsidiary information on the compiler version in use. */ -#define TARGET_VERSION fprintf (stderr, " (MC68HC11/MC68HC12/MC68HCS12)") - - -/* Define cost parameters for a given processor variant. */ -struct processor_costs { - const int add; /* cost of an add instruction */ - const int logical; /* cost of a logical instruction */ - const int shift_var; - const int shiftQI_const[8]; - const int shiftHI_const[16]; - const int multQI; - const int multHI; - const int multSI; - const int divQI; - const int divHI; - const int divSI; -}; - -/* Costs for the current processor. */ -extern const struct processor_costs *m68hc11_cost; - - -/* target machine storage layout */ - -/* Define this if most significant byte of a word is the lowest numbered. */ -#define BYTES_BIG_ENDIAN 1 - -/* Define this if most significant bit is lowest numbered - in instructions that operate on numbered bit-fields. */ -#define BITS_BIG_ENDIAN 0 - -/* Define this if most significant word of a multiword number is numbered. */ -#define WORDS_BIG_ENDIAN 1 - -/* Width of a word, in units (bytes). */ -#define UNITS_PER_WORD 2 - -/* Definition of size_t. This is really an unsigned short as the - 68hc11 only handles a 64K address space. */ -#define SIZE_TYPE "short unsigned int" - -/* A C expression for a string describing the name of the data type - to use for the result of subtracting two pointers. The typedef - name `ptrdiff_t' is defined using the contents of the string. - The 68hc11 only has a 64K address space. */ -#define PTRDIFF_TYPE "short int" - -/* Allocation boundary (bits) for storing pointers in memory. */ -#define POINTER_BOUNDARY 8 - -/* Normal alignment required for function parameters on the stack, in bits. - This can't be less than BITS_PER_WORD */ -#define PARM_BOUNDARY (BITS_PER_WORD) - -/* Boundary (bits) on which stack pointer should be aligned. */ -#define STACK_BOUNDARY 8 - -/* Allocation boundary (bits) for the code of a function. */ -#define FUNCTION_BOUNDARY 8 - -#define BIGGEST_ALIGNMENT 8 - -/* Alignment of field after `int : 0' in a structure. */ -#define EMPTY_FIELD_BOUNDARY 8 - -/* Every structure's size must be a multiple of this. */ -#define STRUCTURE_SIZE_BOUNDARY 8 - -/* Define this if instructions will fail to work if given data not - on the nominal alignment. If instructions will merely go slower - in that case, do not define this macro. */ -#define STRICT_ALIGNMENT 0 - -/* An integer expression for the size in bits of the largest integer - machine mode that should actually be used. All integer machine modes of - this size or smaller can be used for structures and unions with the - appropriate sizes. */ -#define MAX_FIXED_MODE_SIZE 64 - -/* target machine storage layout */ - -/* Size (bits) of the type "int" on target machine - (If undefined, default is BITS_PER_WORD). */ -#define INT_TYPE_SIZE (TARGET_SHORT ? 16 : 32) - -/* Size (bits) of the type "short" on target machine */ -#define SHORT_TYPE_SIZE 16 - -/* Size (bits) of the type "long" on target machine */ -#define LONG_TYPE_SIZE 32 - -/* Size (bits) of the type "long long" on target machine */ -#define LONG_LONG_TYPE_SIZE 64 - -/* A C expression for the size in bits of the type `float' on the - target machine. If you don't define this, the default is one word. - Don't use default: a word is only 16. */ -#define FLOAT_TYPE_SIZE 32 - -/* A C expression for the size in bits of the type double on the target - machine. If you don't define this, the default is two words. - Be IEEE compliant. */ -#define DOUBLE_TYPE_SIZE 64 - -#define LONG_DOUBLE_TYPE_SIZE 64 - -/* Define this as 1 if `char' should by default be signed; else as 0. */ -#define DEFAULT_SIGNED_CHAR 0 - -/* Define these to avoid dependence on meaning of `int'. - Note that WCHAR_TYPE_SIZE is used in cexp.y, - where TARGET_SHORT is not available. */ -#define WCHAR_TYPE "short int" -#define WCHAR_TYPE_SIZE 16 - - -/* Standard register usage. */ - -#define HARD_REG_SIZE (UNITS_PER_WORD) - -/* Assign names to real MC68HC11 registers. - A and B registers are not really used (A+B = D) - X register is first so that GCC allocates X+D for 32-bit integers and - the lowpart of that integer will be D. Having the lower part in D is - better for 32<->16bit conversions and for many arithmetic operations. */ -#define HARD_X_REGNUM 0 -#define HARD_D_REGNUM 1 -#define HARD_Y_REGNUM 2 -#define HARD_SP_REGNUM 3 -#define HARD_PC_REGNUM 4 -#define HARD_A_REGNUM 5 -#define HARD_B_REGNUM 6 -#define HARD_CCR_REGNUM 7 - -/* The Z register does not really exist in the 68HC11. This a fake register - for GCC. It is treated exactly as an index register (X or Y). It is only - in the A_REGS class, which is the BASE_REG_CLASS for GCC. Defining this - register helps the reload pass of GCC. Otherwise, the reload often dies - with register spill failures. - - The Z register is replaced by either X or Y during the machine specific - reorg (m68hc11_reorg). It is saved in the SOFT_Z_REGNUM soft-register - when this is necessary. - - It's possible to tell GCC not to use this register with -ffixed-z. */ -#define HARD_Z_REGNUM 8 - -/* The frame pointer is a soft-register. It's treated as such by GCC: - it is not and must not be part of the BASE_REG_CLASS. */ -#define DEFAULT_HARD_FP_REGNUM (9) -#define HARD_FP_REGNUM (9) -#define HARD_AP_REGNUM (HARD_FP_REGNUM) - -/* Temporary soft-register used in some cases when an operand came - up into a bad register class (D, X, Y, SP) and gcc failed to - recognize this. This register is never allocated by GCC. */ -#define SOFT_TMP_REGNUM 10 - -/* The soft-register which is used to save the Z register - (see Z register replacement notes in m68hc11.c). */ -#define SOFT_Z_REGNUM 11 - -/* The soft-register which is used to save either X or Y. */ -#define SOFT_SAVED_XY_REGNUM 12 - -/* A fake clobber register for 68HC12 patterns. */ -#define FAKE_CLOBBER_REGNUM (13) - -/* Define 32 soft-registers of 16-bit each. By default, - only 12 of them are enabled and can be used by GCC. The - -msoft-reg-count=<n> option allows to control the number of valid - soft-registers. GCC can put 32-bit values in them - by allocating consecutive registers. The first 3 soft-registers - are never allocated by GCC. They are used in case the insn template needs - a temporary register, or for the Z register replacement. */ - -#define MAX_SOFT_REG_COUNT (32) -#define SOFT_REG_FIXED 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1 -#define SOFT_REG_USED 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1 -#define SOFT_REG_ORDER \ -SOFT_REG_FIRST, SOFT_REG_FIRST+1,SOFT_REG_FIRST+2,SOFT_REG_FIRST+3,\ -SOFT_REG_FIRST+4, SOFT_REG_FIRST+5,SOFT_REG_FIRST+6,SOFT_REG_FIRST+7,\ -SOFT_REG_FIRST+8, SOFT_REG_FIRST+9,SOFT_REG_FIRST+10,SOFT_REG_FIRST+11,\ -SOFT_REG_FIRST+12, SOFT_REG_FIRST+13,SOFT_REG_FIRST+14,SOFT_REG_FIRST+15,\ -SOFT_REG_FIRST+16, SOFT_REG_FIRST+17,SOFT_REG_FIRST+18,SOFT_REG_FIRST+19,\ -SOFT_REG_FIRST+20, SOFT_REG_FIRST+21,SOFT_REG_FIRST+22,SOFT_REG_FIRST+23,\ -SOFT_REG_FIRST+24, SOFT_REG_FIRST+25,SOFT_REG_FIRST+26,SOFT_REG_FIRST+27,\ -SOFT_REG_FIRST+28, SOFT_REG_FIRST+29,SOFT_REG_FIRST+30,SOFT_REG_FIRST+31 - -#define SOFT_REG_NAMES \ -"*_.d1", "*_.d2", "*_.d3", "*_.d4", \ -"*_.d5", "*_.d6", "*_.d7", "*_.d8", \ -"*_.d9", "*_.d10", "*_.d11", "*_.d12", \ -"*_.d13", "*_.d14", "*_.d15", "*_.d16", \ -"*_.d17", "*_.d18", "*_.d19", "*_.d20", \ -"*_.d21", "*_.d22", "*_.d23", "*_.d24", \ -"*_.d25", "*_.d26", "*_.d27", "*_.d28", \ -"*_.d29", "*_.d30", "*_.d31", "*_.d32" - -/* First available soft-register for GCC. */ -#define SOFT_REG_FIRST (SOFT_SAVED_XY_REGNUM+2) - -/* Last available soft-register for GCC. */ -#define SOFT_REG_LAST (SOFT_REG_FIRST+MAX_SOFT_REG_COUNT) -#define SOFT_FP_REGNUM (SOFT_REG_LAST) -#define SOFT_AP_REGNUM (SOFT_FP_REGNUM+1) - -/* Number of actual hardware registers. The hardware registers are assigned - numbers for the compiler from 0 to just below FIRST_PSEUDO_REGISTER. - All registers that the compiler knows about must be given numbers, even - those that are not normally considered general registers. */ -#define FIRST_PSEUDO_REGISTER (SOFT_REG_LAST+2) - -/* 1 for registers that have pervasive standard uses and are not available - for the register allocator. */ -#define FIXED_REGISTERS \ - {0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1,1, 1, SOFT_REG_FIXED, 1, 1} -/* X, D, Y, SP,PC,A, B, CCR, Z, FP,ZTMP,ZR,XYR, FK, D1 - D32, SOFT-FP, AP */ - -/* 1 for registers not available across function calls. For our pseudo - registers, all are available. */ -#define CALL_USED_REGISTERS \ - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, SOFT_REG_USED, 1, 1} -/* X, D, Y, SP,PC,A, B, CCR, Z, FP, ZTMP,ZR,XYR, D1 - 32, SOFT-FP, AP */ - - -/* List the order in which to allocate registers. Each register must be - listed once, even those in FIXED_REGISTERS. */ -#define REG_ALLOC_ORDER \ -{ HARD_D_REGNUM, HARD_X_REGNUM, HARD_Y_REGNUM, \ - SOFT_REG_ORDER, HARD_Z_REGNUM, HARD_PC_REGNUM, HARD_A_REGNUM, \ - HARD_B_REGNUM, HARD_CCR_REGNUM, HARD_FP_REGNUM, SOFT_FP_REGNUM, \ - HARD_SP_REGNUM, SOFT_TMP_REGNUM, SOFT_Z_REGNUM, SOFT_SAVED_XY_REGNUM, \ - SOFT_AP_REGNUM, FAKE_CLOBBER_REGNUM } - -/* A C expression for the number of consecutive hard registers, - starting at register number REGNO, required to hold a value of - mode MODE. */ -#define HARD_REGNO_NREGS(REGNO, MODE) \ -((Q_REGNO_P (REGNO)) ? (GET_MODE_SIZE (MODE)) : \ - ((GET_MODE_SIZE (MODE) + HARD_REG_SIZE - 1) / HARD_REG_SIZE)) - -/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. - - 8-bit values are stored anywhere (except the SP register). - - 16-bit values can be stored in any register whose mode is 16 - - 32-bit values can be stored in D, X registers or in a soft register - (except the last one because we need 2 soft registers) - - Values whose size is > 32 bit are not stored in real hard - registers. They may be stored in soft registers if there are - enough of them. */ -#define HARD_REGNO_MODE_OK(REGNO, MODE) \ - hard_regno_mode_ok (REGNO,MODE) - -/* 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. - - All modes are tieable except QImode. */ -#define MODES_TIEABLE_P(MODE1, MODE2) \ - (((MODE1) == (MODE2)) \ - || ((MODE1) != QImode && (MODE2) != QImode)) - - -/* Define the classes of registers for register constraints in the - machine description. Also define ranges of constants. - - One of the classes must always be named ALL_REGS and include all hard regs. - If there is more than one class, another class must be named NO_REGS - and contain no registers. - - The name GENERAL_REGS must be the name of a class (or an alias for - another name such as ALL_REGS). This is the class of registers - that is allowed by "g" or "r" in a register constraint. - Also, registers outside this class are allocated only when - instructions express preferences for them. - - The classes must be numbered in nondecreasing order; that is, - a larger-numbered class must never be contained completely - in a smaller-numbered class. - - For any two classes, it is very desirable that there be another - class that represents their union. */ - -/* The M68hc11 has so few registers that it's not possible for GCC to - do any register allocation without breaking. We extend the processor - registers by having soft registers. These registers are treated as - hard registers by GCC but they are located in memory and accessed by page0 - accesses (IND mode). */ -enum reg_class -{ - NO_REGS, - D_REGS, /* 16-bit data register */ - X_REGS, /* 16-bit X register */ - Y_REGS, /* 16-bit Y register */ - SP_REGS, /* 16-bit stack pointer */ - DA_REGS, /* 8-bit A reg. */ - DB_REGS, /* 8-bit B reg. */ - Z_REGS, /* 16-bit fake Z register */ - D8_REGS, /* 8-bit A or B reg. */ - Q_REGS, /* 8-bit (byte (QI)) data (A, B or D) */ - D_OR_X_REGS, /* D or X register */ - D_OR_Y_REGS, /* D or Y register */ - D_OR_SP_REGS, /* D or SP register */ - X_OR_Y_REGS, /* IX or Y register */ - A_REGS, /* 16-bit address register (X, Y, Z) */ - X_OR_SP_REGS, /* X or SP register */ - Y_OR_SP_REGS, /* Y or SP register */ - X_OR_Y_OR_D_REGS, /* X, Y or D */ - A_OR_D_REGS, /* X, Y, Z or D */ - A_OR_SP_REGS, /* X, Y, Z or SP */ - H_REGS, /* 16-bit hard register (D, X, Y, Z, SP) */ - S_REGS, /* 16-bit soft register */ - D_OR_S_REGS, /* 16-bit soft register or D register */ - X_OR_S_REGS, /* 16-bit soft register or X register */ - Y_OR_S_REGS, /* 16-bit soft register or Y register */ - Z_OR_S_REGS, /* 16-bit soft register or Z register */ - SP_OR_S_REGS, /* 16-bit soft register or SP register */ - D_OR_X_OR_S_REGS, /* 16-bit soft register or D or X register */ - D_OR_Y_OR_S_REGS, /* 16-bit soft register or D or Y register */ - D_OR_SP_OR_S_REGS, /* 16-bit soft register or D or SP register */ - A_OR_S_REGS, /* 16-bit soft register or X, Y registers */ - D_OR_A_OR_S_REGS, /* 16-bit soft register or D, X, Y registers */ - TMP_REGS, /* 16-bit fake scratch register */ - D_OR_A_OR_TMP_REGS, /* General scratch register */ - G_REGS, /* 16-bit general register - (H_REGS + soft registers) */ - ALL_REGS, - LIM_REG_CLASSES -}; - -/* alias GENERAL_REGS to G_REGS. */ -#define GENERAL_REGS G_REGS - -#define N_REG_CLASSES (int) LIM_REG_CLASSES - -/* Give names of register classes as strings for dump file. */ -#define REG_CLASS_NAMES \ -{ "NO_REGS", \ - "D_REGS", \ - "X_REGS", \ - "Y_REGS", \ - "SP_REGS", \ - "DA_REGS", \ - "DB_REGS", \ - "D8_REGS", \ - "Z_REGS", \ - "Q_REGS", \ - "D_OR_X_REGS", \ - "D_OR_Y_REGS", \ - "D_OR_SP_REGS", \ - "X_OR_Y_REGS", \ - "A_REGS", \ - "X_OR_SP_REGS", \ - "Y_OR_SP_REGS", \ - "X_OR_Y_OR_D_REGS", \ - "A_OR_D_REGS", \ - "A_OR_SP_REGS", \ - "H_REGS", \ - "S_REGS", \ - "D_OR_S_REGS", \ - "X_OR_S_REGS", \ - "Y_OR_S_REGS", \ - "Z_OR_S_REGS", \ - "SP_OR_S_REGS", \ - "D_OR_X_OR_S_REGS", \ - "D_OR_Y_OR_S_REGS", \ - "D_OR_SP_OR_S_REGS", \ - "A_OR_S_REGS", \ - "D_OR_A_OR_S_REGS", \ - "TMP_REGS", \ - "D_OR_A_OR_TMP_REGS", \ - "G_REGS", \ - "ALL_REGS" } - -/* An initializer containing the contents of the register classes, - as integers which are bit masks. The Nth integer specifies the - contents of class N. The way the integer MASK is interpreted is - that register R is in the class if `MASK & (1 << R)' is 1. */ - -/*-------------------------------------------------------------- - X 0x00000001 - D 0x00000002 - Y 0x00000004 - SP 0x00000008 - PC 0x00000010 - A 0x00000020 - B 0x00000040 - CCR 0x00000080 - Z 0x00000100 - FRAME 0x00000200 - ZTMP 0x00000400 - ZREG 0x00000800 - XYREG 0x00001000 - FAKE 0x00002000 - Di 0xFFFFc000, 0x03FFF - SFRAME 0x00000000, 0x04000 - AP 0x00000000, 0x08000 - - D_OR_X_REGS represents D+X. It is used for 32-bits numbers. - A_REGS represents a valid base register for indexing. It represents - X,Y and the Z register. - S_REGS represents the soft-registers. This includes the hard frame - and soft frame registers. ---------------------------------------------------------------*/ - -#define REG_CLASS_CONTENTS \ -/* NO_REGS */ {{ 0x00000000, 0x00000000 }, \ -/* D_REGS */ { 0x00000002, 0x00000000 }, /* D */ \ -/* X_REGS */ { 0x00000001, 0x00000000 }, /* X */ \ -/* Y_REGS */ { 0x00000004, 0x00000000 }, /* Y */ \ -/* SP_REGS */ { 0x00000008, 0x00000000 }, /* SP */ \ -/* DA_REGS */ { 0x00000020, 0x00000000 }, /* A */ \ -/* DB_REGS */ { 0x00000040, 0x00000000 }, /* B */ \ -/* Z_REGS */ { 0x00000100, 0x00000000 }, /* Z */ \ -/* D8_REGS */ { 0x00000060, 0x00000000 }, /* A B */ \ -/* Q_REGS */ { 0x00000062, 0x00000000 }, /* A B D */ \ -/* D_OR_X_REGS */ { 0x00000003, 0x00000000 }, /* D X */ \ -/* D_OR_Y_REGS */ { 0x00000006, 0x00000000 }, /* D Y */ \ -/* D_OR_SP_REGS */ { 0x0000000A, 0x00000000 }, /* D SP */ \ -/* X_OR_Y_REGS */ { 0x00000005, 0x00000000 }, /* X Y */ \ -/* A_REGS */ { 0x00000105, 0x00000000 }, /* X Y Z */ \ -/* X_OR_SP_REGS */ { 0x00000009, 0x00000000 }, /* X SP */ \ -/* Y_OR_SP_REGS */ { 0x0000000C, 0x00000000 }, /* Y SP */ \ -/* X_OR_Y_OR_D_REGS */ { 0x00000007, 0x00000000 }, /* D X Y */ \ -/* A_OR_D_REGS */ { 0x00000107, 0x00000000 }, /* D X Y Z */ \ -/* A_OR_SP_REGS */ { 0x0000010D, 0x00000000 }, /* X Y SP */ \ -/* H_REGS */ { 0x0000010F, 0x00000000 }, /* D X Y SP */ \ -/* S_REGS */ { 0xFFFFDE00, 0x00007FFF }, /* _.D,..,FP,Z* */ \ -/* D_OR_S_REGS */ { 0xFFFFDE02, 0x00007FFF }, /* D _.D */ \ -/* X_OR_S_REGS */ { 0xFFFFDE01, 0x00007FFF }, /* X _.D */ \ -/* Y_OR_S_REGS */ { 0xFFFFDE04, 0x00007FFF }, /* Y _.D */ \ -/* Z_OR_S_REGS */ { 0xFFFFDF00, 0x00007FFF }, /* Z _.D */ \ -/* SP_OR_S_REGS */ { 0xFFFFDE08, 0x00007FFF }, /* SP _.D */ \ -/* D_OR_X_OR_S_REGS */ { 0xFFFFDE03, 0x00007FFF }, /* D X _.D */ \ -/* D_OR_Y_OR_S_REGS */ { 0xFFFFDE06, 0x00007FFF }, /* D Y _.D */ \ -/* D_OR_SP_OR_S_REGS */ { 0xFFFFDE0A, 0x00007FFF }, /* D SP _.D */ \ -/* A_OR_S_REGS */ { 0xFFFFDF05, 0x00007FFF }, /* X Y _.D */ \ -/* D_OR_A_OR_S_REGS */ { 0xFFFFDF07, 0x00007FFF }, /* D X Y _.D */ \ -/* TMP_REGS */ { 0x00002000, 0x00000000 }, /* FAKE */ \ -/* D_OR_A_OR_TMP_REGS*/ { 0x00002107, 0x00000000 }, /* D X Y Z Fake */ \ -/* G_REGS */ { 0xFFFFFF1F, 0x00007FFF }, /* ? _.D D X Y */ \ -/* ALL_REGS*/ { 0xFFFFFFFF, 0x00007FFF }} - - -/* set up a C expression whose value is a register class containing hard - register REGNO */ -#define Q_REGNO_P(REGNO) ((REGNO) == HARD_A_REGNUM \ - || (REGNO) == HARD_B_REGNUM) -#define Q_REG_P(X) (REG_P (X) && Q_REGNO_P (REGNO (X))) - -#define D_REGNO_P(REGNO) ((REGNO) == HARD_D_REGNUM) -#define D_REG_P(X) (REG_P (X) && D_REGNO_P (REGNO (X))) - -#define DB_REGNO_P(REGNO) ((REGNO) == HARD_B_REGNUM) -#define DB_REG_P(X) (REG_P (X) && DB_REGNO_P (REGNO (X))) -#define DA_REGNO_P(REGNO) ((REGNO) == HARD_A_REGNUM) -#define DA_REG_P(X) (REG_P (X) && DA_REGNO_P (REGNO (X))) - -#define X_REGNO_P(REGNO) ((REGNO) == HARD_X_REGNUM) -#define X_REG_P(X) (REG_P (X) && X_REGNO_P (REGNO (X))) - -#define Y_REGNO_P(REGNO) ((REGNO) == HARD_Y_REGNUM) -#define Y_REG_P(X) (REG_P (X) && Y_REGNO_P (REGNO (X))) - -#define Z_REGNO_P(REGNO) ((REGNO) == HARD_Z_REGNUM) -#define Z_REG_P(X) (REG_P (X) && Z_REGNO_P (REGNO (X))) - -#define SP_REGNO_P(REGNO) ((REGNO) == HARD_SP_REGNUM) -#define SP_REG_P(X) (REG_P (X) && SP_REGNO_P (REGNO (X))) - -/* Address register. */ -#define A_REGNO_P(REGNO) ((REGNO) == HARD_X_REGNUM \ - || (REGNO) == HARD_Y_REGNUM \ - || (REGNO) == HARD_Z_REGNUM) -#define A_REG_P(X) (REG_P (X) && A_REGNO_P (REGNO (X))) - -/* M68hc11 hard registers. */ -#define H_REGNO_P(REGNO) (D_REGNO_P (REGNO) || A_REGNO_P (REGNO) \ - || SP_REGNO_P (REGNO) || Q_REGNO_P (REGNO)) -#define H_REG_P(X) (REG_P (X) && H_REGNO_P (REGNO (X))) - -#define FAKE_REGNO_P(REGNO) ((REGNO) == FAKE_CLOBBER_REGNUM) -#define FAKE_REG_P(X) (REG_P (X) && FAKE_REGNO_P (REGNO (X))) - -/* Soft registers (or register emulation for gcc). The temporary register - used by insn template must be part of the S_REGS class so that it - matches the 'u' constraint. */ -#define S_REGNO_P(REGNO) ((REGNO) >= SOFT_TMP_REGNUM \ - && (REGNO) <= SOFT_REG_LAST \ - && (REGNO) != FAKE_CLOBBER_REGNUM) -#define S_REG_P(X) (REG_P (X) && S_REGNO_P (REGNO (X))) - -#define Z_REGNO_P(REGNO) ((REGNO) == HARD_Z_REGNUM) -#define Z_REG_P(X) (REG_P (X) && Z_REGNO_P (REGNO (X))) - -/* General register. */ -#define G_REGNO_P(REGNO) (H_REGNO_P (REGNO) || S_REGNO_P (REGNO) \ - || ((REGNO) == HARD_PC_REGNUM) \ - || ((REGNO) == HARD_FP_REGNUM) \ - || ((REGNO) == SOFT_FP_REGNUM) \ - || ((REGNO) == FAKE_CLOBBER_REGNUM) \ - || ((REGNO) == SOFT_AP_REGNUM)) - -#define G_REG_P(X) (REG_P (X) && G_REGNO_P (REGNO (X))) - -#define REGNO_REG_CLASS(REGNO) \ - (D_REGNO_P (REGNO) ? D_REGS : \ - (X_REGNO_P (REGNO) ? X_REGS : \ - (Y_REGNO_P (REGNO) ? Y_REGS : \ - (SP_REGNO_P (REGNO) ? SP_REGS : \ - (Z_REGNO_P (REGNO) ? Z_REGS : \ - (H_REGNO_P (REGNO) ? H_REGS : \ - (FAKE_REGNO_P (REGNO) ? TMP_REGS : \ - (S_REGNO_P (REGNO) ? S_REGS : \ - (DA_REGNO_P (REGNO) ? DA_REGS: \ - (DB_REGNO_P (REGNO) ? DB_REGS: \ - (G_REGNO_P (REGNO) ? G_REGS : ALL_REGS))))))))))) - - -/* Get reg_class from a letter in the machine description. */ - -extern enum reg_class m68hc11_tmp_regs_class; -#define REG_CLASS_FROM_LETTER(C) \ - ((C) == 'a' ? DA_REGS : \ - (C) == 'A' ? A_REGS : \ - (C) == 'b' ? DB_REGS : \ - (C) == 'B' ? X_OR_Y_REGS : \ - (C) == 'd' ? D_REGS : \ - (C) == 'D' ? D_OR_X_REGS : \ - (C) == 'q' ? Q_REGS : \ - (C) == 'h' ? H_REGS : \ - (C) == 't' ? TMP_REGS : \ - (C) == 'u' ? S_REGS : \ - (C) == 'v' ? m68hc11_tmp_regs_class : \ - (C) == 'w' ? SP_REGS : \ - (C) == 'x' ? X_REGS : \ - (C) == 'y' ? Y_REGS : \ - (C) == 'z' ? Z_REGS : NO_REGS) - -#define PREFERRED_RELOAD_CLASS(X,CLASS) preferred_reload_class(X,CLASS) - -#define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P hook_bool_mode_true - -/* A C expression that is nonzero if hard register number REGNO2 can be - considered for use as a rename register for REGNO1 */ - -#define HARD_REGNO_RENAME_OK(REGNO1,REGNO2) \ - m68hc11_hard_regno_rename_ok ((REGNO1), (REGNO2)) - -/* Return the maximum number of consecutive registers needed to represent - mode MODE in a register of class CLASS. */ -#define CLASS_MAX_NREGS(CLASS, MODE) \ -(((CLASS) == DA_REGS || (CLASS) == DB_REGS \ - || (CLASS) == D8_REGS || (CLASS) == Q_REGS) ? GET_MODE_SIZE (MODE) \ - : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) - -/* The letters I, J, K, L and M in a register constraint string - can be used to stand for particular ranges of immediate operands. - This macro defines what the ranges are. - C is the letter, and VALUE is a constant value. - Return 1 if VALUE is in the range specified by C. - - `K' is for 0. - `L' is for range -65536 to 65536 - `M' is for values whose 16-bit low part is 0 - 'N' is for +1 or -1. - 'O' is for 16 (for rotate using swap). - 'P' is for range -8 to 2 (used by addhi_sp) - - 'I', 'J' are not used. */ - -#define CONST_OK_FOR_LETTER_P(VALUE, C) \ - ((C) == 'K' ? (VALUE) == 0 : \ - (C) == 'L' ? ((VALUE) >= -65536 && (VALUE) <= 65535) : \ - (C) == 'M' ? ((VALUE) & 0x0ffffL) == 0 : \ - (C) == 'N' ? ((VALUE) == 1 || (VALUE) == -1) : \ - (C) == 'I' ? ((VALUE) >= -2 && (VALUE) <= 2) : \ - (C) == 'O' ? (VALUE) == 16 : \ - (C) == 'P' ? ((VALUE) <= 2 && (VALUE) >= -8) : 0) - -/* Similar, but for floating constants, and defining letters G and H. - - `G' is for 0.0. */ -#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ - ((C) == 'G' ? (GET_MODE_CLASS (GET_MODE (VALUE)) == MODE_FLOAT \ - && VALUE == CONST0_RTX (GET_MODE (VALUE))) : 0) - -/* 'U' represents certain kind of memory indexed operand for 68HC12. - and any memory operand for 68HC11. - 'R' represents indexed addressing mode or access to page0 for 68HC11. - For 68HC12, it represents any memory operand. */ -#define EXTRA_CONSTRAINT(OP, C) \ -((C) == 'U' ? m68hc11_small_indexed_indirect_p (OP, GET_MODE (OP)) \ - : (C) == 'Q' ? m68hc11_symbolic_p (OP, GET_MODE (OP)) \ - : (C) == 'R' ? m68hc11_indirect_p (OP, GET_MODE (OP)) \ - : (C) == 'S' ? (memory_operand (OP, GET_MODE (OP)) \ - && non_push_operand (OP, GET_MODE (OP))) : 0) - - -/* Stack layout; function entry, exit and calling. */ - -/* Define this if pushing a word on the stack - makes the stack pointer a smaller address. */ -#define STACK_GROWS_DOWNWARD - -/* Define this to nonzero if the nominal address of the stack frame - is at the high-address end of the local variables; - that is, each additional local variable allocated - goes at a more negative offset in the frame. - - Define to 0 for 68HC11, the frame pointer is the bottom - of local variables. */ -#define FRAME_GROWS_DOWNWARD 0 - -/* Define this if successive arguments to a function occupy decreasing - addresses in the stack. */ -/* #define ARGS_GROW_DOWNWARD */ - -/* Offset within stack frame to start allocating local variables at. - If FRAME_GROWS_DOWNWARD, this is the offset to the END of the - first local allocated. Otherwise, it is the offset to the BEGINNING - of the first local allocated. */ -#define STARTING_FRAME_OFFSET 0 - -/* Offset of first parameter from the argument pointer register value. */ - -#define FIRST_PARM_OFFSET(FNDECL) 2 - -/* After the prologue, RA is at 0(AP) in the current frame. */ -#define RETURN_ADDR_RTX(COUNT, FRAME) \ - ((COUNT) == 0 \ - ? gen_rtx_MEM (Pmode, arg_pointer_rtx) \ - : 0) - -/* Before the prologue, the top of the frame is at 2(sp). */ -#define INCOMING_FRAME_SP_OFFSET 2 - -/* Define this if functions should assume that stack space has been - allocated for arguments even when their values are passed in - registers. - - The value of this macro is the size, in bytes, of the area reserved for - arguments passed in registers. - - This space can either be allocated by the caller or be a part of the - machine-dependent stack frame: `OUTGOING_REG_PARM_STACK_SPACE' - says which. */ -/* #define REG_PARM_STACK_SPACE(FNDECL) 2 */ - -/* Define this macro if REG_PARM_STACK_SPACE is defined but stack - parameters don't skip the area specified by REG_PARM_STACK_SPACE. - Normally, when a parameter is not passed in registers, it is placed on - the stack beyond the REG_PARM_STACK_SPACE area. Defining this macro - suppresses this behavior and causes the parameter to be passed on the - stack in its natural location. */ -/* #define STACK_PARMS_IN_REG_PARM_AREA */ - -/* Register to use for pushing function arguments. */ -#define STACK_POINTER_REGNUM HARD_SP_REGNUM - -/* Base register for access to local variables of the function. */ -#define FRAME_POINTER_REGNUM SOFT_FP_REGNUM - -#define HARD_FRAME_POINTER_REGNUM HARD_FP_REGNUM - -/* Base register for access to arguments of the function. */ -#define ARG_POINTER_REGNUM SOFT_AP_REGNUM - -/* Register in which static-chain is passed to a function. */ -#define STATIC_CHAIN_REGNUM SOFT_Z_REGNUM - - -/* Definitions for register eliminations. - - This is an array of structures. Each structure initializes one pair - of eliminable registers. The "from" register number is given first, - followed by "to". Eliminations of the same "from" register are listed - in order of preference. - - We have two registers that are eliminated on the 6811. The pseudo arg - pointer and pseudo frame pointer registers can always be eliminated; - they are replaced with either the stack or the real frame pointer. */ - -#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 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) \ - { OFFSET = m68hc11_initial_elimination_offset (FROM, TO); } - - -/* Passing Function Arguments on the Stack. */ - -/* If we generate an insn to push BYTES bytes, this says how many the - stack pointer really advances by. No rounding or alignment needed - for MC6811. */ -#define PUSH_ROUNDING(BYTES) (BYTES) - -/* Passing Arguments in Registers. */ - -/* Define a data type for recording info about an argument list - during the scan of that argument list. This data type should - hold all necessary information about the function itself - and about the args processed so far, enough to enable macros - such as FUNCTION_ARG to determine where the next arg should go. */ - -typedef struct m68hc11_args -{ - int words; - int nregs; -} CUMULATIVE_ARGS; - -/* If defined, a C expression which determines whether, and in which direction, - to pad out an argument with extra space. The value should be of type - `enum direction': either `upward' to pad above the argument, - `downward' to pad below, or `none' to inhibit padding. - - Structures are stored left shifted in their argument slot. */ -#define FUNCTION_ARG_PADDING(MODE, TYPE) \ - m68hc11_function_arg_padding ((MODE), (TYPE)) - -#undef PAD_VARARGS_DOWN -#define PAD_VARARGS_DOWN \ - (m68hc11_function_arg_padding (TYPE_MODE (type), type) == downward) - -/* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a - function whose data type is FNTYPE. For a library call, FNTYPE is 0. */ -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \ - (m68hc11_init_cumulative_args (&CUM, FNTYPE, LIBNAME)) - -/* Define the profitability of saving registers around calls. - - Disable this because the saving instructions generated by - caller-save need a reload and the way it is implemented, - it forbids all spill registers at that point. Enabling - caller saving results in spill failure. */ -#define CALLER_SAVE_PROFITABLE(REFS,CALLS) 0 - -/* 1 if N is a possible register number for function argument passing. - D is for 16-bit values, X is for 32-bit (X+D). */ -#define FUNCTION_ARG_REGNO_P(N) \ - (((N) == HARD_D_REGNUM) || ((N) == HARD_X_REGNUM)) - -/* All return values are in the D or X+D registers: - - 8 and 16-bit values are returned in D. - BLKmode are passed in D as pointer. - - 32-bit values are returned in X + D. - The high part is passed in X and the low part in D. - For GCC, the register number must be HARD_X_REGNUM. */ -#define FUNCTION_VALUE(VALTYPE, FUNC) \ - gen_rtx_REG (TYPE_MODE (VALTYPE), \ - ((TYPE_MODE (VALTYPE) == BLKmode \ - || GET_MODE_SIZE (TYPE_MODE (VALTYPE)) <= 2) \ - ? HARD_D_REGNUM : HARD_X_REGNUM)) - -#define LIBCALL_VALUE(MODE) \ - gen_rtx_REG (MODE, \ - (((MODE) == BLKmode || GET_MODE_SIZE (MODE) <= 2) \ - ? HARD_D_REGNUM : HARD_X_REGNUM)) - -/* 1 if N is a possible register number for a function value. */ -#define FUNCTION_VALUE_REGNO_P(N) \ - ((N) == HARD_D_REGNUM || (N) == HARD_X_REGNUM) - -/* 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. No definition is equivalent to always zero. */ -#define EXIT_IGNORE_STACK 0 - - -/* Generating Code for Profiling. */ - -/* Output assembler code to FILE to increment profiler label # LABELNO - for profiling a function entry. */ -#define FUNCTION_PROFILER(FILE, LABELNO) \ - fprintf (FILE, "\tldy\t.LP%d\n\tjsr mcount\n", (LABELNO)) - -/* Length in units of the trampoline for entering a nested function. */ -#define TRAMPOLINE_SIZE (TARGET_M6811 ? 11 : 9) - - -/* Addressing modes, and classification of registers for them. */ - -#define ADDR_STRICT 0x01 /* Accept only registers in class A_REGS */ -#define ADDR_INCDEC 0x02 /* Post/Pre inc/dec */ -#define ADDR_INDEXED 0x04 /* D-reg index */ -#define ADDR_OFFSET 0x08 -#define ADDR_INDIRECT 0x10 /* Accept (mem (mem ...)) for [n,X] */ -#define ADDR_CONST 0x20 /* Accept const and symbol_ref */ - -/* The 68HC12 has all the post/pre increment/decrement modes. */ -#define HAVE_POST_INCREMENT (TARGET_M6812 && TARGET_AUTO_INC_DEC) -#define HAVE_PRE_INCREMENT (TARGET_M6812 && TARGET_AUTO_INC_DEC) -#define HAVE_POST_DECREMENT (TARGET_M6812 && TARGET_AUTO_INC_DEC) -#define HAVE_PRE_DECREMENT (TARGET_M6812 && TARGET_AUTO_INC_DEC) - -/* The class value for base registers. This depends on the target: - A_REGS for 68HC11 and A_OR_SP_REGS for 68HC12. The class value - is stored at init time. */ -extern enum reg_class m68hc11_base_reg_class; -#define BASE_REG_CLASS m68hc11_base_reg_class - -/* The class value for index registers. This is NO_REGS for 68HC11. */ - -extern enum reg_class m68hc11_index_reg_class; -#define INDEX_REG_CLASS m68hc11_index_reg_class - -/* These assume that REGNO is a hard or pseudo reg number. 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. */ - - -extern unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER]; -#define REG_VALID_FOR_BASE_P(REGNO) \ - ((REGNO) < FIRST_PSEUDO_REGISTER \ - && m68hc11_reg_valid_for_base[REGNO]) - -/* Internal macro, return 1 if REGNO is a valid index register. */ -extern unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER]; -#define REG_VALID_FOR_INDEX_P(REGNO) \ - ((REGNO) < FIRST_PSEUDO_REGISTER \ - && m68hc11_reg_valid_for_index[REGNO]) - -/* Internal macro, the nonstrict definition for REGNO_OK_FOR_BASE_P. */ -#define REGNO_OK_FOR_BASE_NONSTRICT_P(REGNO) \ - ((REGNO) >= FIRST_PSEUDO_REGISTER \ - || REG_VALID_FOR_BASE_P (REGNO) \ - || (REGNO) == FRAME_POINTER_REGNUM \ - || (REGNO) == HARD_FRAME_POINTER_REGNUM \ - || (REGNO) == ARG_POINTER_REGNUM \ - || (reg_renumber && REG_VALID_FOR_BASE_P (reg_renumber[REGNO]))) - -/* Internal macro, the nonstrict definition for REGNO_OK_FOR_INDEX_P. */ -#define REGNO_OK_FOR_INDEX_NONSTRICT_P(REGNO) \ - (TARGET_M6812 \ - && ((REGNO) >= FIRST_PSEUDO_REGISTER \ - || REG_VALID_FOR_INDEX_P (REGNO) \ - || (reg_renumber && REG_VALID_FOR_INDEX_P (reg_renumber[REGNO])))) - -/* Internal macro, the strict definition for REGNO_OK_FOR_BASE_P. */ -#define REGNO_OK_FOR_BASE_STRICT_P(REGNO) \ - ((REGNO) < FIRST_PSEUDO_REGISTER ? REG_VALID_FOR_BASE_P (REGNO) \ - : (reg_renumber && REG_VALID_FOR_BASE_P (reg_renumber[REGNO]))) - -/* Internal macro, the strict definition for REGNO_OK_FOR_INDEX_P. */ -#define REGNO_OK_FOR_INDEX_STRICT_P(REGNO) \ - (TARGET_M6812 \ - && ((REGNO) < FIRST_PSEUDO_REGISTER ? REG_VALID_FOR_INDEX_P (REGNO) \ - : (reg_renumber && REG_VALID_FOR_INDEX_P (reg_renumber[REGNO])))) - -#define REGNO_OK_FOR_BASE_P2(REGNO,STRICT) \ - ((STRICT) ? (REGNO_OK_FOR_BASE_STRICT_P (REGNO)) \ - : (REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO))) - -#define REGNO_OK_FOR_INDEX_P2(REGNO,STRICT) \ - ((STRICT) ? (REGNO_OK_FOR_INDEX_STRICT_P (REGNO)) \ - : (REGNO_OK_FOR_INDEX_NONSTRICT_P (REGNO))) - -#define REGNO_OK_FOR_BASE_P(REGNO) REGNO_OK_FOR_BASE_STRICT_P (REGNO) -#define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_INDEX_STRICT_P (REGNO) - -#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_STRICT_P (REGNO (X)) -#define REG_OK_FOR_BASE_NONSTRICT_P(X) REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (X)) -#define REG_OK_FOR_INDEX_STRICT_P(X) REGNO_OK_FOR_INDEX_STRICT_P (REGNO (X)) -#define REG_OK_FOR_INDEX_NONSTRICT_P(X) REGNO_OK_FOR_INDEX_NONSTRICT_P (REGNO (X)) - -/* see PUSH_POP_ADDRESS_P() below for an explanation of this. */ -#define IS_STACK_PUSH(operand) \ - ((GET_CODE (operand) == MEM) \ - && (GET_CODE (XEXP (operand, 0)) == PRE_DEC) \ - && (SP_REG_P (XEXP (XEXP (operand, 0), 0)))) - -#define IS_STACK_POP(operand) \ - ((GET_CODE (operand) == MEM) \ - && (GET_CODE (XEXP (operand, 0)) == POST_INC) \ - && (SP_REG_P (XEXP (XEXP (operand, 0), 0)))) - -/* Maximum number of registers that can appear in a valid memory address */ -#define MAX_REGS_PER_ADDRESS 2 - -/* TARGET_LEGITIMATE_ADDRESS_P 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. */ - -/*-------------------------------------------------------------- - Valid addresses are either direct or indirect (MEM) versions - of the following forms: - constant N - register ,X - indexed N,X ---------------------------------------------------------------*/ - -/* The range of index that is allowed by indirect addressing. */ - -#define VALID_MIN_OFFSET m68hc11_min_offset -#define VALID_MAX_OFFSET m68hc11_max_offset - -/* The offset values which are allowed by the n,x and n,y addressing modes. - Take into account the size of the mode because we may have to add - a mode offset to access the lowest part of the data. - (For example, for an SImode, the last valid offset is 252.) */ -#define VALID_CONSTANT_OFFSET_P(X,MODE) \ -(((GET_CODE (X) == CONST_INT) && \ - ((INTVAL (X) >= VALID_MIN_OFFSET) \ - && ((INTVAL (X) <= VALID_MAX_OFFSET \ - - (HOST_WIDE_INT) (GET_MODE_SIZE (MODE) + 1))))) \ -|| (TARGET_M6812 \ - && ((GET_CODE (X) == SYMBOL_REF) \ - || GET_CODE (X) == LABEL_REF \ - || GET_CODE (X) == CONST))) - -/* This is included to allow stack push/pop operations. Special hacks in the - md and m6811.c files exist to support this. */ -#define PUSH_POP_ADDRESS_P(X) \ - (((GET_CODE (X) == PRE_DEC) || (GET_CODE (X) == POST_INC)) \ - && SP_REG_P (XEXP (X, 0))) - -/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx and check its - validity for a certain class. We have two alternate definitions for each - of them. The usual definition accepts all pseudo regs; the other rejects - them unless they have been allocated suitable hard regs. The symbol - REG_OK_STRICT causes the latter definition to be used. - - Most source files want to accept pseudo regs in the hope that they will - get allocated to the class that the insn wants them to be in. Source files - for reload pass need to be strict. After reload, it makes no difference, - since pseudo regs have been eliminated by then. */ - -#ifndef 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) REG_OK_FOR_BASE_NONSTRICT_P(X) - -/* Nonzero if X is a hard reg that can be used as an index. */ -#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_NONSTRICT_P(X) -#else -#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P(X) -#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_STRICT_P(X) -#endif - - -/* Nonzero if the constant value X is a legitimate general operand. - It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ - -#define LEGITIMATE_CONSTANT_P(X) 1 - - -/* Tell final.c how to eliminate redundant test instructions. */ - -#define NOTICE_UPDATE_CC(EXP, INSN) \ - m68hc11_notice_update_cc ((EXP), (INSN)) - -/* Move costs between classes of registers */ -#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \ - (m68hc11_register_move_cost (MODE, CLASS1, CLASS2)) - -/* Move cost between register and memory. - - Move to a 16-bit register is reasonable, - - Move to a soft register can be expensive. */ -#define MEMORY_MOVE_COST(MODE,CLASS,IN) \ - m68hc11_memory_move_cost ((MODE),(CLASS),(IN)) - -/* A C expression for the cost of a branch instruction. A value of 1 - is the default; other values are interpreted relative to that. - - Pretend branches are cheap because GCC generates sub-optimal code - for the default value. */ -#define BRANCH_COST(speed_p, predictable_p) 0 - -/* Nonzero if access to memory by bytes is slow and undesirable. */ -#define SLOW_BYTE_ACCESS 0 - -/* It is as good to call a constant function address as to call an address - kept in a register. */ -#define NO_FUNCTION_CSE - -/* Try a machine-dependent way of reloading an illegitimate address - operand. If we find one, push the reload and jump to WIN. This - macro is used in only one place: `find_reloads_address' in reload.c. - - For M68HC11, we handle large displacements of a base register - by splitting the addend across an addhi3 insn. - - For M68HC12, the 64K offset range is available. - */ - -#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ -do { \ - /* We must recognize output that we have already generated ourselves. */ \ - if (GET_CODE (X) == PLUS \ - && GET_CODE (XEXP (X, 0)) == PLUS \ - && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \ - && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT \ - && GET_CODE (XEXP (X, 1)) == CONST_INT) \ - { \ - push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL, \ - BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \ - OPNUM, TYPE); \ - goto WIN; \ - } \ - if (GET_CODE (X) == PLUS \ - && GET_CODE (XEXP (X, 0)) == REG \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && !VALID_CONSTANT_OFFSET_P (XEXP (X, 1), MODE)) \ - { \ - HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ - HOST_WIDE_INT low, high; \ - high = val & (~0x0FF); \ - low = val & 0x00FF; \ - if (low >= 256-15) { high += 16; low -= 16; } \ - /* Reload the high part into a base reg; leave the low part \ - in the mem directly. */ \ - \ - X = gen_rtx_PLUS (Pmode, \ - gen_rtx_PLUS (Pmode, XEXP (X, 0), \ - GEN_INT (high)), \ - GEN_INT (low)); \ - \ - push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL, \ - BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \ - OPNUM, TYPE); \ - goto WIN; \ - } \ -} while (0) - - -/* Defining the Output Assembler Language. */ - -/* 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. */ - -/* Output before read-only data. */ -#define TEXT_SECTION_ASM_OP ("\t.sect\t.text") - -/* Output before writable data. */ -#define DATA_SECTION_ASM_OP ("\t.sect\t.data") - -/* Output before uninitialized data. */ -#define BSS_SECTION_ASM_OP ("\t.sect\t.bss") - -/* Define the pseudo-ops used to switch to the .ctors and .dtors sections. - - Same as config/elfos.h but don't mark these section SHF_WRITE since - there is no shared library problem. */ -#undef CTORS_SECTION_ASM_OP -#define CTORS_SECTION_ASM_OP "\t.section\t.ctors,\"a\"" - -#undef DTORS_SECTION_ASM_OP -#define DTORS_SECTION_ASM_OP "\t.section\t.dtors,\"a\"" - -#define TARGET_ASM_CONSTRUCTOR m68hc11_asm_out_constructor -#define TARGET_ASM_DESTRUCTOR m68hc11_asm_out_destructor - -/* Comment character */ -#define ASM_COMMENT_START ";" - -/* Output to assembler file text saying following lines - may contain character constants, extra white space, comments, etc. */ -#define ASM_APP_ON "; Begin inline assembler code\n#APP\n" - -/* Output to assembler file text saying following lines - no longer contain unusual constructs. */ -#define ASM_APP_OFF "; End of inline assembler code\n#NO_APP\n" - -/* 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. - - For 68HC12 we mark functions that return with 'rtc'. The linker - will ensure that a 'call' is really made (instead of 'jsr'). - The debugger needs this information to correctly compute the stack frame. - - For 68HC11/68HC12 we also mark interrupt handlers for gdb to - compute the correct stack frame. */ - -#undef ASM_DECLARE_FUNCTION_NAME -#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ - do \ - { \ - fprintf (FILE, "%s", TYPE_ASM_OP); \ - assemble_name (FILE, NAME); \ - putc (',', FILE); \ - fprintf (FILE, TYPE_OPERAND_FMT, "function"); \ - putc ('\n', FILE); \ - \ - if (current_function_far) \ - { \ - fprintf (FILE, "\t.far\t"); \ - assemble_name (FILE, NAME); \ - putc ('\n', FILE); \ - } \ - else if (current_function_interrupt \ - || current_function_trap) \ - { \ - fprintf (FILE, "\t.interrupt\t"); \ - assemble_name (FILE, NAME); \ - putc ('\n', FILE); \ - } \ - ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \ - ASM_OUTPUT_LABEL(FILE, NAME); \ - } \ - while (0) - -/* Output #ident as a .ident. */ - -/* output external reference */ -#undef ASM_OUTPUT_EXTERNAL -#define ASM_OUTPUT_EXTERNAL(FILE,DECL,NAME) \ - {fputs ("\t; extern\t", FILE); \ - assemble_name (FILE, NAME); \ - fputs ("\n", FILE);} - -/* How to refer to registers in assembler output. This sequence is indexed - by compiler's hard-register-number (see above). */ -#define REGISTER_NAMES \ -{ "x", "d", "y", "sp", "pc", "a", "b", "ccr", "z", \ - "*_.frame", "*_.tmp", "*_.z", "*_.xy", "*fake clobber", \ - SOFT_REG_NAMES, "*sframe", "*ap"} - -/* This is how to output an insn to push/pop a register on the stack. - It need not be very fast code. - - Don't define because we don't know how to handle that with - the STATIC_CHAIN_REGNUM (soft register). Saving the static - chain must be made inside FUNCTION_PROFILER. */ - -#undef ASM_OUTPUT_REG_PUSH -#undef ASM_OUTPUT_REG_POP - -/* This is how to output an element of a case-vector that is relative. */ - -#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ - fprintf (FILE, "\t%s\tL%d-L%d\n", integer_asm_op (2, TRUE), VALUE, REL) - -/* This is how to output an element of a case-vector that is absolute. */ -#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ - fprintf (FILE, "\t%s\t.L%d\n", integer_asm_op (2, TRUE), VALUE) - -/* This is how to output an assembler line that says to advance the - location counter to a multiple of 2**LOG bytes. */ -#define ASM_OUTPUT_ALIGN(FILE,LOG) \ - do { \ - if ((LOG) > 1) \ - fprintf ((FILE), "%s\n", ALIGN_ASM_OP); \ - } while (0) - - -/* Assembler Commands for Exception Regions. */ - -/* Default values provided by GCC should be ok. Assuming that DWARF-2 - frame unwind info is ok for this platform. */ - -#undef PREFERRED_DEBUGGING_TYPE -#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG - -/* For the support of memory banks we need addresses that indicate - the page number. */ -#define DWARF2_ADDR_SIZE 4 - -/* SCz 2003-07-08: Don't use as dwarf2 .file/.loc directives because - the linker is doing relaxation and it does not adjust the debug_line - sections when it shrinks the code. This results in invalid addresses - when debugging. This does not bless too much the HC11/HC12 as most - applications are embedded and small, hence a reasonable debug info. - This problem is known for binutils 2.13, 2.14 and mainline. */ -#undef HAVE_AS_DWARF2_DEBUG_LINE - -/* The prefix for local labels. You should be able to define this as - an empty string, or any arbitrary string (such as ".", ".L%", etc) - without having to make any other changes to account for the specific - definition. Note it is a string literal, not interpreted by printf - and friends. */ -#define LOCAL_LABEL_PREFIX "." - -/* The prefix for immediate operands. */ -#define IMMEDIATE_PREFIX "#" -#define GLOBAL_ASM_OP "\t.globl\t" - - -/* Miscellaneous Parameters. */ - -/* Specify the machine mode that this machine uses - for the index in the tablejump instruction. */ -#define CASE_VECTOR_MODE Pmode - -/* This flag, if defined, says the same insns that convert to a signed fixnum - also convert validly to an unsigned one. */ -#define FIXUNS_TRUNC_LIKE_FIX_TRUNC - -/* Max number of bytes we can move from memory to memory in one - reasonably fast instruction. */ -#define MOVE_MAX 2 - -/* MOVE_RATIO is the number of move instructions that is better than a - block move. Make this small on 6811, since the code size grows very - large with each move. */ -#define MOVE_RATIO(speed) 3 - -/* Define if shifts truncate the shift count which implies one can omit - a sign-extension or zero-extension of a shift count. */ -#define SHIFT_COUNT_TRUNCATED 1 - -/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits - is done just by pretending it is already truncated. */ -#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 - -/* Specify the machine mode that pointers have. After generation of rtl, the - compiler makes no further distinction between pointers and any other - objects of this machine mode. */ -#define Pmode HImode - -/* A function address in a call instruction is a byte address (for indexing - purposes) so give the MEM rtx a byte's mode. */ -#define FUNCTION_MODE QImode - -extern int debug_m6811; -extern int z_replacement_completed; -extern int current_function_interrupt; -extern int current_function_trap; -extern int current_function_far; - -extern GTY(()) rtx m68hc11_soft_tmp_reg; -extern GTY(()) rtx ix_reg; -extern GTY(()) rtx iy_reg; -extern GTY(()) rtx d_reg; diff --git a/gcc/config/m68hc11/m68hc11.md b/gcc/config/m68hc11/m68hc11.md deleted file mode 100644 index f4ff3ebbb4c..00000000000 --- a/gcc/config/m68hc11/m68hc11.md +++ /dev/null @@ -1,7579 +0,0 @@ -;;- Machine description file for Motorola 68HC11 and 68HC12. -;;- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 -;;- Free Software Foundation, Inc. -;;- Contributed by Stephane Carrez (stcarrez@nerim.fr) - -;; This file is part of GCC. - -;; GCC 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 3, or (at your option) -;; any later version. - -;; GCC 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 GCC; see the file COPYING3. If not see -;; <http://www.gnu.org/licenses/>. - -;; Note: -;; A first 68HC11 port was made by Otto Lind (otto@coactive.com) -;; on gcc 2.6.3. I have used it as a starting point for this port. -;; However, this new port is a complete re-write. Its internal -;; design is completely different. The generated code is not -;; compatible with the gcc 2.6.3 port. -;; -;; The gcc 2.6.3 port is available at: -;; -;; ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz -;; - -;;- Instruction patterns. When multiple patterns apply, -;;- the first one in the file is chosen. -;;- -;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. -;;- -;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code -;;- updates for most instructions. - -;; -;; The following constraints are used: -;; -;; Single pair registers: -;; a register 'a' 8-bit -;; b register 'b' 8-bit -;; d register 'd' 16-bit -;; t pseudo soft register 'TMP' 16-bit -;; v register 'd' for 68hc11, 16-bit -;; NO_REG for 68hc12 -;; (used for scratch register) -;; w register 'sp' 16-bit -;; x register 'x' 16-bit -;; y register 'y' 16-bit -;; z register 'z' 16-bit (fake r for 68HC11 and 68HC12) -;; D register 'd+x' 32-bit -;; -;; Group of registers: -;; q register 'a' or 'b' or 'd' 8-bit -;; u pseudo soft register 16-bit -;; A register 'x', 'y', 'z' 16-bit -;; B register 'x', 'y' 16-bit -;; h register 'd', 'x', 'y', 'z' 16-bit -;; -;; Other constraints: -;; -;; Q an operand which is in memory but whose address is constant -;; (i.e., a (MEM (SYMBOL_REF x))). This constraint is used by -;; bset/bclr instructions together with linker relaxation. The -;; operand can be translated to a page0 addressing mode if the -;; symbol address is in page0 (0..255). -;; -;; R an operand which is in memory and whose address is expressed -;; with 68HC11/68HC12 indexed addressing mode. In general this -;; is any valid (MEM) except a (MEM (SYMBOL_REF x)). -;; -;; U an operand which is in memory and if it uses the 68HC12 indexed -;; addressing mode, the offset is in the range -16..+15. This is -;; used by 68HC12 movb/movw instructions since they do not accept -;; the full 16-bit offset range (as other insn do). -;; -;; -;; Immediate integer operand constraints: -;; `L' is for range -65536 to 65536 -;; `M' is for values whose 16-bit low part is 0 -;; 'N' is for +1 or -1. -;; 'O' is for 16 (for rotate using swap). -;; 'P' is for range -8 to 2 (used by addhi_sp) -;; -;; In many cases, it's not possible to use the 'g' or 'r' constraints. -;; -;; Operands modifiers: -;; -;; %b Get the low part of the operand (to obtain a QImode) -;; This modifier must always be used for QImode operations -;; because a correction must be applied when the operand -;; is a soft register (ex: *ZD1). Otherwise, we generate -;; *ZD1 and this is the high part of the register. For other -;; kinds of operands, if the operand is already QImode, no -;; additional correction is made. -;; %h Get the high part of the operand (to obtain a QImode) -;; %t Represents the temporary/scratch register *_.tmp -;; The scratch register is used in some cases when GCC puts -;; some values in bad registers. -;; -;; 32/64-bit Patterns: -;; The 68HC11 does not support 32/64-bit operations. Most of the -;; 32/64-bit patterns are defined to split the instruction in -;; 16-bits patterns. Providing split patterns generates better code -;; than letting GCC implement the 32/64-bit operation itself. -;; -;; -;; Notes: -;; -;; o For iorqi3, andqi3, xorqi3 patterns, we must accept the 'A' constraint -;; otherwise some insn are not satisfied. -;; -;; o Split patterns that create a swap_areg pattern (xgdx or xgdy) must -;; be valid only when z_replacement_completed == 2 because once these -;; swap instructions are generated, a flow/cse pass fails to handle -;; them correctly (it would treat the X, Y or D register as dead sometimes). -;; -;; o Some split pattern generate instructions that operate on 'a' or 'b' -;; register directly (high part and low part of D respectively). -;; Such split pattern must also be valid when z_replacement_completed == 2 -;; because flow/cse is not aware that D is composed of {a, b}. -;; -;; o Split patterns that generate a (mem:QI (symbol_reg _.dx)) to access -;; the high part of a soft register must be expanded after z_replacement -;; pass. -;; -;;--------------------------------------------------------------------------- -;; Constants - -(define_constants [ - ;; Register numbers - (X_REGNUM 0) ; Index X register - (D_REGNUM 1) ; Data register - (Y_REGNUM 2) ; Index Y register - (SP_REGNUM 3) ; Stack pointer - (PC_REGNUM 4) ; Program counter - (A_REGNUM 5) ; A (high part of D) - (B_REGNUM 6) ; B (low part of D) - (CC_REGNUM 7) ; Condition code register - (SOFT_TMP_REGNUM 10) ; TMP soft register - (SOFT_Z_REGNUM 11) ; Z soft register - (SOFT_XY_REGNUM 12) ; XY soft register -]) - -(include "predicates.md") - -;;-------------------------------------------------------------------- -;;- Test -;;-------------------------------------------------------------------- -;; -;; The test and compare insn must not accept a memory operand with -;; an auto-inc mode. If we do this, the reload can emit move insns -;; after the test or compare. Such move will set the flags and therefore -;; break the comparison. This can happen if the auto-inc register -;; does not happen to be a hard register (i.e., reloading occurs). -;; An offsetable memory operand should be ok. The 'tst_operand' and -;; 'cmp_operand' predicates take care of this rule. -;; - -(define_insn "tsthi_1" - [(set (cc0) - (compare (match_operand:HI 0 "tst_operand" "dx,*y") - (const_int 0)))] - "" - "* -{ - if (D_REG_P (operands[0]) && !TARGET_M6812) - return \"std\\t%t0\"; - else - return \"cp%0\\t#0\"; -}") - -;; -;; Split pattern for (tst:QI) on an address register. -;; -(define_split - [(set (cc0) - (compare (match_operand:QI 0 "hard_addr_reg_operand" "") - (const_int 0)))] - "z_replacement_completed == 2 && GET_MODE (operands[0]) == QImode" - [(parallel [(set (reg:HI D_REGNUM) (match_dup 1)) - (set (match_dup 1) (reg:HI D_REGNUM))]) - (set (cc0) (compare (reg:QI D_REGNUM) - (const_int 0))) - (parallel [(set (reg:HI D_REGNUM) (match_dup 1)) - (set (match_dup 1) (reg:HI D_REGNUM))])] - "operands[1] = gen_rtx_REG (HImode, REGNO (operands[0]));") - -(define_insn "tstqi_1" - [(set (cc0) - (compare (match_operand:QI 0 "tst_operand" "m,d,*A,!u") - (const_int 0)))] - "" - "* -{ - if (A_REG_P (operands[0])) - return \"#\"; - - else if (D_REG_P (operands[0])) - return \"tstb\"; - - else if (dead_register_here (insn, d_reg)) - return \"ldab\\t%b0\"; - - else - return \"tst\\t%b0\"; -}") - -;; -;; tstqi_z_used, cmpqi_z_used and cmphi_z_used are patterns generated -;; during the Z register replacement. They are used when an operand -;; uses the Z register as an index register (i.e., (MEM:QI (REG:HI Z))). -;; In that case, we have to preserve the values of the replacement -;; register (as well as the CC0 since the insns are compare insns). -;; To do this, the replacement register is pushed on the stack and -;; restored after the real compare. A pattern+split is defined to -;; avoid problems with the flow+cse register pass which are made -;; after Z register replacement. -;; -(define_insn_and_split "tstqi_z_used" - [(set (cc0) (compare (match_operand:QI 0 "tst_operand" "m") - (const_int 0))) - (use (match_operand:HI 1 "hard_reg_operand" "dxy")) - (use (reg:HI SOFT_Z_REGNUM))] - "" - "#" - "z_replacement_completed == 2" - [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 1)) - (set (match_dup 1) (match_dup 2)) - (set (cc0) (compare (match_dup 0) - (const_int 0))) - (set (match_dup 1) (mem:HI (post_inc:HI (reg:HI SP_REGNUM))))] - "operands[2] = gen_rtx_REG (HImode, SOFT_Z_REGNUM);") - - -;;-------------------------------------------------------------------- -;;- Compare -;;-------------------------------------------------------------------- - -;; -;; Comparison of a hard register with another one is provided because -;; it helps GCC to avoid to spill a pseudo hard register. -;; We use a temporary in page 0, this is equivalent to a pseudo hard reg. -;; (except that we loose the information that the value is saved in it). -;; -;; The split pattern transforms the comparison into a save of one hard -;; register and a comparison with the temporary. -;; -(define_split - [(set (cc0) - (compare (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "hard_reg_operand" "")))] - "TARGET_M6811 - && reload_completed && !(Z_REG_P (operands[0]) || Z_REG_P (operands[1]))" - [(set (match_dup 2) (match_dup 1)) - (set (cc0) - (compare (match_dup 0) (match_dup 2)))] - "operands[2] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);") - -(define_split - [(set (cc0) - (compare (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "hard_reg_operand" "")))] - "0 && TARGET_M6812 - && reload_completed && !(Z_REG_P (operands[0]) || Z_REG_P (operands[1]))" - [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 1)) - (set (cc0) - (compare (match_dup 0) (mem:HI (post_inc:HI (reg:HI SP_REGNUM)))))] - "") - -(define_insn "cmphi_1_hc12" - [(set (cc0) - (compare (match_operand:HI 0 "tst_operand" - "d,?xy,xyd,?xy,d,m,!u,dxy,dxy") - (match_operand:HI 1 "general_operand" - "i,i,!u,m,m,dxy,dxy,?*d*A,!*w")))] - "TARGET_M6812" - "* -{ - if (H_REG_P (operands[1]) && !H_REG_P (operands[0])) - { - cc_status.flags |= CC_REVERSED; - return \"cp%1\\t%0\"; - } - else if (SP_REG_P (operands[1])) - return \"sts\\t2,-sp\n\\tcp%0\\t2,sp+\"; - else if (H_REG_P (operands[1])) - return \"psh%1\n\\tcp%0\\t2,sp+\"; - else - return \"cp%0\\t%1\"; -}") - -(define_insn "cmphi_1_hc11" - [(set (cc0) - (compare (match_operand:HI 0 "tst_operand" - "dx,y,xyd,?xy,d,m,m,dxy,dxy,?u*z,dxy,*z") - (match_operand:HI 1 "cmp_operand" - "i,i,!u,m,m,?xy,d,?*d*A,?u,dxy,!*w,i")))] - "TARGET_M6811" - "* -{ - if (H_REG_P (operands[1]) && !H_REG_P (operands[0])) - { - cc_status.flags |= CC_REVERSED; - return \"cp%1\\t%0\"; - } - else if (H_REG_P (operands[1])) - return \"#\"; - else - return \"cp%0\\t%1\"; -}") - -(define_insn_and_split "cmphi_z_used" - [(set (cc0) - (compare (match_operand:HI 0 "tst_operand" "dxy,m") - (match_operand:HI 1 "cmp_operand" "mi,dxy"))) - (use (match_operand:HI 2 "hard_reg_operand" "dxy,dxy")) - (use (reg:HI SOFT_Z_REGNUM))] - "" - "#" - "z_replacement_completed == 2" - [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 2)) - (set (match_dup 2) (match_dup 3)) - (set (cc0) (compare (match_dup 0) (match_dup 1))) - (set (match_dup 2) (mem:HI (post_inc:HI (reg:HI SP_REGNUM))))] - "operands[3] = gen_rtx_REG (HImode, SOFT_Z_REGNUM);") - -;; -;; 8-bit comparison with address register. -;; There is no such comparison instruction, we have to temporarily switch -;; the address register and the D register and do the comparison with D. -;; The xgdx and xgdy instructions preserve the flags. -;; -(define_split - [(set (cc0) - (compare (match_operand:QI 0 "hard_addr_reg_operand" "") - (match_operand:QI 1 "cmp_operand" "")))] - "z_replacement_completed == 2 && GET_MODE (operands[0]) == QImode" - [(parallel [(set (reg:HI D_REGNUM) (match_dup 3)) - (set (match_dup 3) (reg:HI D_REGNUM))]) - (set (cc0) - (compare (reg:QI D_REGNUM) (match_dup 1))) - (parallel [(set (reg:HI D_REGNUM) (match_dup 3)) - (set (match_dup 3) (reg:HI D_REGNUM))])] - "operands[3] = gen_rtx_REG (HImode, REGNO (operands[0]));") - -(define_split - [(set (cc0) - (compare (match_operand:QI 0 "hard_reg_operand" "") - (match_operand:QI 1 "hard_reg_operand" "")))] - "reload_completed" - [(set (match_dup 3) (match_dup 4)) - (set (cc0) - (compare (match_dup 0) (match_dup 2)))] - "operands[2] = gen_rtx_REG (QImode, SOFT_TMP_REGNUM); - operands[3] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); - operands[4] = gen_rtx_REG (HImode, REGNO (operands[1]));") - -(define_insn "bitcmpqi" - [(set (cc0) - (compare (and:QI (match_operand:QI 0 "tst_operand" "d,d,d,m,!u") - (match_operand:QI 1 "cmp_operand" "im,*B,u,d,d")) - (const_int 0)))] - "" - "@ - bitb\\t%b1 - # - bitb\\t%b1 - bitb\\t%b0 - bitb\\t%b0") - -(define_split /* "bitcmpqi" */ - [(set (cc0) - (compare (and:QI (match_operand:QI 0 "tst_operand" "") - (match_operand:QI 1 "hard_addr_reg_operand" "")) - (const_int 0)))] - "z_replacement_completed == 2" - [(set (match_dup 3) (match_dup 2)) - (set (cc0) (and:QI (match_dup 0) (match_dup 4)))] - "operands[2] = gen_rtx_REG (HImode, REGNO (operands[1])); - operands[3] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); - operands[4] = gen_rtx_REG (QImode, SOFT_TMP_REGNUM);") - -(define_insn_and_split "bitcmpqi_z_used" - [(set (cc0) - (compare (and:QI (match_operand:QI 0 "tst_operand" "d,m") - (match_operand:QI 1 "cmp_operand" "m,d")) - (const_int 0))) - (use (match_operand:HI 2 "hard_reg_operand" "xy,xy")) - (use (reg:HI SOFT_Z_REGNUM))] - "" - "#" - "z_replacement_completed == 2" - [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 2)) - (set (match_dup 2) (match_dup 3)) - (set (cc0) (and:QI (match_dup 0) (match_dup 1))) - (set (match_dup 2) (mem:HI (post_inc:HI (reg:HI SP_REGNUM))))] - "operands[3] = gen_rtx_REG (HImode, SOFT_Z_REGNUM);") - -(define_insn "bitcmphi" - [(set (cc0) - (compare (and:HI (match_operand:HI 0 "tst_operand" "d") - (match_operand:HI 1 "const_int_operand" "i")) - (const_int 0)))] - "(INTVAL (operands[1]) & 0x0ff) == 0 - || (INTVAL (operands[1]) & 0x0ff00) == 0" - "* -{ - if ((INTVAL (operands[1]) & 0x0ff) == 0) - return \"bita\\t%h1\"; - else - return \"bitb\\t%1\"; -}") - -(define_insn "bitcmpqi_12" - [(set (cc0) - (compare (zero_extract:HI (match_operand:HI 0 "tst_operand" "d") - (match_operand:HI 1 "const_int_operand" "i") - (match_operand:HI 2 "const_int_operand" "i")) - (const_int 0)))] - "(unsigned) (INTVAL (operands[2]) + INTVAL (operands[1])) <= 8 - || (((unsigned) (INTVAL (operands[2]) + INTVAL (operands[1])) <= 16) - && (unsigned) INTVAL (operands[2]) >= 8)" - "* -{ - rtx ops[1]; - int mask; - int startpos = INTVAL (operands[2]); - int bitsize = INTVAL (operands[1]); - - if (startpos >= 8) - { - startpos -= 8; - mask = (1 << (startpos + bitsize)) - 1; - mask &= ~((1 << startpos) - 1); - - ops[0] = GEN_INT (mask); - output_asm_insn (\"bita\\t%0\", ops); - } - else - { - mask = (1 << (startpos + bitsize)) - 1; - mask &= ~((1 << startpos) - 1); - - ops[0] = GEN_INT (mask); - output_asm_insn (\"bitb\\t%0\", ops); - } - return \"\"; -}") - -(define_insn "cmpqi_1" - [(set (cc0) - (compare (match_operand:QI 0 "tst_operand" "d,m,d,!u,*B,d*B") - (match_operand:QI 1 "cmp_operand" "im,d,!u,d,dim*A,*u")))] - "" - "* -{ - if (A_REG_P (operands[0]) || A_REG_P (operands[1])) - { - return \"#\"; - } - else if (D_REG_P (operands[0])) - { - return \"cmpb\\t%b1\"; - } - cc_status.flags |= CC_REVERSED; - return \"cmpb\\t%b0\"; -}") - -(define_insn_and_split "cmpqi_z_used" - [(set (cc0) - (compare (match_operand:QI 0 "tst_operand" "dxy,m") - (match_operand:QI 1 "cmp_operand" "m,dxy"))) - (use (match_operand:HI 2 "hard_reg_operand" "dxy,dxy")) - (use (reg:HI SOFT_Z_REGNUM))] - "" - "#" - "z_replacement_completed == 2" - [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 2)) - (set (match_dup 2) (match_dup 3)) - (set (cc0) (compare (match_dup 0) (match_dup 1))) - (set (match_dup 2) (mem:HI (post_inc:HI (reg:HI SP_REGNUM))))] - "operands[3] = gen_rtx_REG (HImode, SOFT_Z_REGNUM);") - -;;-------------------------------------------------------------------- -;;- Move strict_low_part -;;-------------------------------------------------------------------- -;; -;; The (strict_low_part ...) patterns are replaced by normal (set) patterns. -;; The replacement must be made at the very end because we loose the -;; (strict_low_part ...) information. This is correct for our machine -;; description but not for GCC optimization passes. -;; -(define_insn_and_split "movstrictsi" - [(set (strict_low_part (match_operand:SI 0 "non_push_operand" "+um,D,D")) - (match_operand:SI 1 "general_operand" "D,Dim,uD"))] - "" - "#" - "z_replacement_completed == 2" - [(set (match_dup 0) (match_dup 1))] - "") - -(define_insn_and_split "movstricthi" - [(set (strict_low_part (match_operand:HI 0 "non_push_operand" "+um,dA,dA")) - (match_operand:HI 1 "general_operand" "dA,dAim,u"))] - "" - "#" - "z_replacement_completed == 2" - [(set (match_dup 0) (match_dup 1))] - "") - -(define_insn_and_split "movstrictqi" - [(set (strict_low_part (match_operand:QI 0 "non_push_operand" "+mu,!dA")) - (match_operand:QI 1 "general_operand" "d,imudA"))] - "" - "#" - "z_replacement_completed == 2" - [(set (match_dup 0) (match_dup 1))] - "") - -;;-------------------------------------------------------------------- -;;- 64-bit Move Operations. -;; The movdi and movdf patterns are identical except for the mode. -;; They are also very similar to those for movsi and movsf. -;; -;; For 68HC11, we need a scratch register (either D, X, Y) -;; because there is no memory->memory moves. It must be defined with -;; earlyclobber (&) so that it does not appear in the source or destination -;; address. Providing patterns for movdi/movdf allows GCC to generate -;; better code. [Until now, the scratch register is limited to D because -;; otherwise we can run out of registers in the A_REGS class for reload]. -;; -;; For 68HC12, the scratch register is not necessary. To use the same -;; pattern and same split, we use the 'v' constraint. This tells the -;; reload to use the _.tmp register (which is not used at all). -;; The insn will be split in one or several memory moves (movw). -;; [SCz: this does not work ?? So, I switched temporary to 'd' reg] -;;-------------------------------------------------------------------- -(define_expand "movdi" - [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "") - (match_operand:DI 1 "general_operand" "")) - (clobber (match_scratch:HI 2 ""))])] - "" - " - /* For push/pop, emit a REG_INC note to make sure the reload - inheritance and reload CSE pass notice the change of the stack - pointer. */ - if (IS_STACK_PUSH (operands[0]) || IS_STACK_POP (operands[1])) - { - rtx insn; - - insn = emit_insn (gen_movdi_internal (operands[0], operands[1])); - REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, - stack_pointer_rtx, - REG_NOTES (insn)); - DONE; - } -") - -;; Separate push from normal moves to avoid reloading problems -;; The 'clr' is not able to push on 68HC11 so we really need a scratch. -;; We can also accept more scratch registers. -(define_insn_and_split "*pushdi_internal" - [(set (match_operand:DI 0 "push_operand" "=<,<,<,<") - (match_operand:DI 1 "general_operand" "i,U,m,!u")) - (clobber (match_scratch:HI 2 "=&dA,&d,&d,&dA"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_move (operands[0], operands[1], operands[2]); - DONE;") - -(define_insn_and_split "movdi_internal" - [(set (match_operand:DI 0 "non_push_operand" "=m!u,U,!u,U,m,m,!u") - (match_operand:DI 1 "general_operand" "K,iU,iU,!u,mi,!u,!mu")) - (clobber (match_scratch:HI 2 "=X,&d,&d,&d,&d,&d,&d"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_move (operands[0], operands[1], operands[2]); - DONE;") - -(define_expand "movdf" - [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "") - (match_operand:DF 1 "general_operand" "")) - (clobber (match_scratch:HI 2 ""))])] - "" - "/* For push/pop, emit a REG_INC note to make sure the reload - inheritance and reload CSE pass notice the change of the stack - pointer. */ - if (IS_STACK_PUSH (operands[0]) || IS_STACK_POP (operands[1])) - { - rtx insn; - - insn = emit_insn (gen_movdf_internal (operands[0], operands[1])); - REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, - stack_pointer_rtx, - REG_NOTES (insn)); - DONE; - } -") - -;; See pushdi_internal -(define_insn_and_split "*pushdf_internal" - [(set (match_operand:DF 0 "push_operand" "=<,<,<,<") - (match_operand:DF 1 "general_operand" "i,U,m,!u")) - (clobber (match_scratch:HI 2 "=&dA,&d,&d,&dA"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_move (operands[0], operands[1], operands[2]); - DONE;") - -(define_insn_and_split "movdf_internal" - [(set (match_operand:DF 0 "non_push_operand" "=mu,U,m,!u,U,m,!u") - (match_operand:DF 1 "general_operand" "G,iU,mi,iU,!u,!u,!mu")) - (clobber (match_scratch:HI 2 "=X,&d,&d,&d,&d,&d,&d"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_move (operands[0], operands[1], operands[2]); - DONE;") - -;;-------------------------------------------------------------------- -;;- 32-bit Move Operations. -;; The movsi and movsf patterns are identical except for the mode. -;; When we move to/from a hard register (d+x), we don't need a scratch. -;; Otherwise, a scratch register is used as intermediate register for -;; the move. The '&' constraint is necessary to make sure the reload -;; pass does not give us a register that dies in the insn and is used -;; for input/output operands. -;;-------------------------------------------------------------------- -(define_expand "movsi" - [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "") - (match_operand:SI 1 "general_operand" "")) - (clobber (match_scratch:HI 2 ""))])] - "" - "/* For push/pop, emit a REG_INC note to make sure the reload - inheritance and reload CSE pass notice the change of the stack - pointer. */ - if (IS_STACK_PUSH (operands[0]) || IS_STACK_POP (operands[1])) - { - rtx insn; - - insn = emit_insn (gen_movsi_internal (operands[0], operands[1])); - REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, - stack_pointer_rtx, - REG_NOTES (insn)); - DONE; - } -") - -(define_insn_and_split "*pushsi_internal" - [(set (match_operand:SI 0 "push_operand" "=<,<,<,<,<") - (match_operand:SI 1 "general_operand" "!D,i,U,m,!u")) - (clobber (match_scratch:HI 2 "=X,&dA,&d,&d,&dA"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_move (operands[0], operands[1], operands[2]); - DONE;") - -(define_insn_and_split "movsi_internal" - [(set (match_operand:SI 0 "nonimmediate_operand" "=mu,mu,?D,m,?D,?u,?u,!u,D") - (match_operand:SI 1 "general_operand" "K,imu,im,?D,!u,?D,mi,!u,!D")) - (clobber (match_scratch:HI 2 "=X,&d,X,X,X,X,&d,&d,X"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_move (operands[0], operands[1], operands[2]); - DONE;") - -(define_expand "movsf" - [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "") - (match_operand:SF 1 "general_operand" "")) - (clobber (match_scratch:HI 2 ""))])] - "" - "/* For push/pop, emit a REG_INC note to make sure the reload - inheritance and reload CSE pass notice the change of the stack - pointer. */ - if (IS_STACK_PUSH (operands[0]) || IS_STACK_POP (operands[1])) - { - rtx insn; - - insn = emit_insn (gen_movsf_internal (operands[0], operands[1])); - REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, - stack_pointer_rtx, - REG_NOTES (insn)); - DONE; - } -") - -(define_insn_and_split "*pushsf_internal" - [(set (match_operand:SF 0 "push_operand" "=<,<,<,<,<") - (match_operand:SF 1 "general_operand" "!D,i,U,m,!u")) - (clobber (match_scratch:HI 2 "=X,&dA,&d,&d,&dA"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_move (operands[0], operands[1], operands[2]); - DONE;") - -(define_insn_and_split "movsf_internal" - [(set (match_operand:SF 0 "nonimmediate_operand" "=m!u,m,D,m,D,!u,!u,!u,D") - (match_operand:SF 1 "general_operand" "G,im,im,D,!u,D,mi,!u,!D")) - (clobber (match_scratch:HI 2 "=X,&d,X,X,X,X,&d,&d,X"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_move (operands[0], operands[1], operands[2]); - DONE;") - - -;;-------------------------------------------------------------------- -;;- 16-bit Move Operations. -;; We don't need a scratch register. -;;-------------------------------------------------------------------- - -(define_insn "*movhi2_push" - [(set (match_operand:HI 0 "push_operand" "=<,<,<") - (match_operand:HI 1 "general_operand" "xy,?d,!z"))] - "TARGET_M6811 && !TARGET_M6812" - "* -{ - cc_status = cc_prev_status; - if (D_REG_P (operands[1])) - { - output_asm_insn (\"pshb\", operands); - return \"psha\"; - } - else if (X_REG_P (operands[1])) - { - return \"pshx\"; - } - else if (Y_REG_P (operands[1])) - { - return \"pshy\"; - } - fatal_insn (\"Invalid register in the instruction\", insn); -}") - -(define_insn "*movhi2_pop" - [(set (match_operand:HI 0 "nonimmediate_operand" "=xy,d") - (match_operand:HI 1 "pop_operand" ">,>"))] - "TARGET_M6811" - "* -{ - cc_status = cc_prev_status; - if (D_REG_P (operands[0])) - { - output_asm_insn (\"pula\", operands); - return \"pulb\"; - } - else if (X_REG_P (operands[0])) - { - return \"pulx\"; - } - else if (Y_REG_P (operands[0])) - { - return \"puly\"; - } - fatal_insn (\"Invalid register in the instruction\", insn); -}") - -(define_expand "movhi" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (match_operand:HI 1 "general_operand" ""))] - "" - " -{ - if (reload_in_progress) - { - if (m68hc11_reload_operands (operands)) - { - DONE; - } - } - if (TARGET_M6811 && (reload_in_progress | reload_completed) == 0) - { - if (GET_CODE (operands[0]) == MEM && - (GET_CODE (operands[1]) == MEM - || GET_CODE (operands[1]) == CONST_INT)) - { - operands[1] = force_reg (HImode, operands[1]); - } - else if (IS_STACK_PUSH (operands[0]) - && GET_CODE (operands[1]) != REG) - { - operands[1] = force_reg (HImode, operands[1]); - } - } - /* For push/pop, emit a REG_INC note to make sure the reload - inheritance and reload CSE pass notice the change of the stack - pointer. */ - if (IS_STACK_PUSH (operands[0]) || IS_STACK_POP (operands[1])) - { - rtx insn; - - insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1])); - REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, - stack_pointer_rtx, - REG_NOTES (insn)); - DONE; - } -}") - -(define_insn "*movhi_68hc12" - [(set (match_operand:HI 0 "nonimmediate_operand" "=U,dAw,dAw,m,U,U,m,!u") - (match_operand:HI 1 "general_operand" "U,dAwim,!u,K,dAwi,!u,dAw,riU"))] - "TARGET_M6812" - "* -{ - m68hc11_gen_movhi (insn, operands); - return \"\"; -}") - -(define_insn "movhi_const0" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,A,um") - (const_int 0))] - "TARGET_M6811" - "@ - clra\\n\\tclrb - ld%0\\t#0 - clr\\t%b0\\n\\tclr\\t%h0") - -(define_insn "*movhi_m68hc11" - [(set (match_operand:HI 0 "nonimmediate_operand" "=dAw,!u,m,m,dAw,!*u") - (match_operand:HI 1 "general_operand" "dAwim,dAw,dA,?Aw,!*u,dAw"))] - "TARGET_M6811" - "* -{ - m68hc11_gen_movhi (insn, operands); - return \"\"; -}") - -;;-------------------------------------------------------------------- -;;- 8-bit Move Operations. -;; We don't need a scratch register. -;;-------------------------------------------------------------------- -;; -;; The *a alternative also clears the high part of the register. -;; This should be ok since this is not the (strict_low_part) set. -;; -(define_insn "movqi_const0" - [(set (match_operand:QI 0 "non_push_operand" "=d,m,!u,*A,!*q") - (const_int 0))] - "" - "@ - clrb - clr\\t%b0 - clr\\t%b0 - ld%0\\t#0 - clr%0") - -;; -;; 8-bit operations on address registers. -;; -;; Switch temporary to the D register and load the value in B. -;; This is possible as long as the address register does not -;; appear in the source operand. -;; -(define_split - [(set (match_operand:QI 0 "hard_addr_reg_operand" "") - (match_operand:QI 1 "general_operand" ""))] - "z_replacement_completed == 2 - && !reg_mentioned_p (operands[0], operands[1]) - && !(D_REG_P (operands[1]) || Q_REG_P (operands[1]))" - [(parallel [(set (reg:HI D_REGNUM) (match_dup 2)) - (set (match_dup 2) (reg:HI D_REGNUM))]) - (set (reg:QI D_REGNUM) (match_dup 1)) - (parallel [(set (reg:HI D_REGNUM) (match_dup 2)) - (set (match_dup 2) (reg:HI D_REGNUM))])] - "operands[2] = gen_rtx_REG (HImode, REGNO (operands[0]));") - -;; -;; 8-bit operations on address registers. -;; -(define_split - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (match_operand:QI 1 "hard_addr_reg_operand" ""))] - "z_replacement_completed == 2 - && !reg_mentioned_p (operands[1], operands[0]) - && !(D_REG_P (operands[0]) || Q_REG_P (operands[0]))" - [(parallel [(set (reg:HI D_REGNUM) (match_dup 2)) - (set (match_dup 2) (reg:HI D_REGNUM))]) - (set (match_dup 0) (reg:QI D_REGNUM)) - (parallel [(set (reg:HI D_REGNUM) (match_dup 2)) - (set (match_dup 2) (reg:HI D_REGNUM))])] - "operands[2] = gen_rtx_REG (HImode, REGNO (operands[1]));") - -(define_insn "*movqi2_push" - [(set (match_operand:QI 0 "push_operand" "=<,<") - (match_operand:QI 1 "general_operand" "d,!*A"))] - "" - "* -{ - if (A_REG_P (operands[1])) - return \"#\"; - - cc_status = cc_prev_status; - return \"pshb\"; -}") - - -(define_expand "movqi" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (match_operand:QI 1 "general_operand" ""))] - "" - " -{ - if (reload_in_progress) - { - if (m68hc11_reload_operands (operands)) - { - DONE; - } - } - if (TARGET_M6811 && (reload_in_progress | reload_completed) == 0) - { - if (GET_CODE (operands[0]) == MEM - && (GET_CODE (operands[1]) == MEM - || GET_CODE (operands[1]) == CONST_INT)) - { - operands[1] = force_reg (QImode, operands[1]); - } - else if (IS_STACK_PUSH (operands[0]) - && GET_CODE (operands[1]) != REG) - { - operands[1] = force_reg (QImode, operands[1]); - } - } - /* For push/pop, emit a REG_INC note to make sure the reload - inheritance and reload CSE pass notice the change of the stack - pointer. */ - if (IS_STACK_PUSH (operands[0]) || IS_STACK_POP (operands[1])) - { - rtx insn; - - insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1])); - REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, - stack_pointer_rtx, - REG_NOTES (insn)); - DONE; - } -}") - -(define_insn "*movqi_68hc12" - [(set (match_operand:QI 0 "nonimmediate_operand" - "=U,d*AU*q,d*A*qU,d*A*q,m,?*u,m") - (match_operand:QI 1 "general_operand" - "U,*ri*q,U,m,d*q,*ri*qU,!*A"))] - "TARGET_M6812" - "* -{ - m68hc11_gen_movqi (insn, operands); - return \"\"; -}") - -(define_insn "*movqi_m68hc11" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d*A*q,m,m,d*A*q,*u") - (match_operand:QI 1 "general_operand" "d*Aim*q,d*q,!*A,*u,d*A*q"))] - "TARGET_M6811" - "* -{ - m68hc11_gen_movqi (insn, operands); - return \"\"; -}") - -;;-------------------------------------------------------------------- -;;- Swap registers -;;-------------------------------------------------------------------- -;; Swapping registers is used for split patterns. -(define_insn "swap_areg" - [(set (match_operand:HI 0 "hard_reg_operand" "=d,A") - (match_operand:HI 1 "hard_reg_operand" "=A,d")) - (set (match_dup 1) (match_dup 0))] - "" - "* -{ - m68hc11_output_swap (insn, operands); - return \"\"; -}") - -;;-------------------------------------------------------------------- -;;- Truncation insns. -;;-------------------------------------------------------------------- -;; -;; Truncation are not necessary because GCC knows how to truncate, -;; specially when values lie in consecutive registers. -;; - -(define_expand "floatunssisf2" - [(set (match_operand:SF 0 "nonimmediate_operand" "") - (unsigned_float:SF (match_operand:SI 1 "general_operand" "")))] - "" - "m68hc11_emit_libcall (\"__floatunsisf\", UNSIGNED_FLOAT, - SFmode, SImode, 2, operands); - DONE;") - -(define_expand "floatunssidf2" - [(set (match_operand:DF 0 "nonimmediate_operand" "") - (unsigned_float:DF (match_operand:SI 1 "general_operand" "")))] - "" - "m68hc11_emit_libcall (\"__floatunsidf\", UNSIGNED_FLOAT, - DFmode, SImode, 2, operands); - DONE;") - -;;-------------------------------------------------------------------- -;;- Zero extension insns. -;;-------------------------------------------------------------------- - -;; -;; 64-bit extend. The insn will be split into 16-bit instructions just -;; before the final pass. We need a scratch register for the split. -;; The final value can be generated on the stack directly. This is more -;; efficient and useful for conversions made during parameter passing rules. -;; -(define_insn "zero_extendqidi2" - [(set (match_operand:DI 0 "nonimmediate_operand" "=m,!u,m,!u") - (zero_extend:DI - (match_operand:QI 1 "nonimmediate_operand" "m,dmu,*B,*B"))) - (clobber (match_scratch:HI 2 "=&d,&dB,&d,&dB"))] - "" - "#") - -(define_split - [(set (match_operand:DI 0 "push_operand" "") - (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:HI 2 "=&dB"))] - "z_replacement_completed == 2" - [(const_int 0)] - " -{ - rtx low = m68hc11_gen_lowpart (SImode, operands[0]); - rtx push = m68hc11_gen_lowpart (HImode, low); - rtx src = operands[1]; - - /* Source operand must be in a hard register. */ - if (!H_REG_P (src)) - { - src = gen_rtx_REG (QImode, REGNO (operands[2])); - emit_move_insn (src, operands[1]); - } - - /* Source is in D, we can push B then one word of 0 and we do - a correction on the stack pointer. */ - if (D_REG_P (src)) - { - emit_move_insn (m68hc11_gen_lowpart (QImode, push), src); - emit_move_insn (operands[2], const0_rtx); - if (D_REG_P (operands[2])) - { - emit_move_insn (m68hc11_gen_lowpart (QImode, push), src); - } - else - { - emit_move_insn (push, operands[2]); - emit_insn (gen_addhi3 (gen_rtx_REG (HImode, HARD_SP_REGNUM), - gen_rtx_REG (HImode, HARD_SP_REGNUM), - const1_rtx)); - } - } - else - { - /* Source is in X or Y. It's better to push the 16-bit register - and then to some stack adjustment. */ - src = gen_rtx_REG (HImode, REGNO (src)); - emit_move_insn (push, src); - emit_move_insn (operands[2], const0_rtx); - emit_insn (gen_addhi3 (gen_rtx_REG (HImode, HARD_SP_REGNUM), - gen_rtx_REG (HImode, HARD_SP_REGNUM), - const1_rtx)); - emit_move_insn (push, operands[2]); - emit_insn (gen_addhi3 (gen_rtx_REG (HImode, HARD_SP_REGNUM), - gen_rtx_REG (HImode, HARD_SP_REGNUM), - const1_rtx)); - } - emit_move_insn (push, operands[2]); - emit_move_insn (push, operands[2]); - emit_move_insn (push, operands[2]); - DONE; -}") - -(define_split - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:HI 2 "=&dB"))] - "z_replacement_completed == 2" - [(const_int 0)] - " -{ - rtx low = m68hc11_gen_lowpart (SImode, operands[0]); - rtx low2 = m68hc11_gen_lowpart (HImode, low); - rtx src = operands[1]; - - /* Source operand must be in a hard register. */ - if (!H_REG_P (src)) - { - src = gen_rtx_REG (QImode, REGNO (operands[2])); - emit_move_insn (src, operands[1]); - } - - emit_move_insn (m68hc11_gen_lowpart (QImode, low2), src); - emit_move_insn (operands[2], const0_rtx); - src = gen_rtx_REG (QImode, REGNO (operands[2])); - emit_move_insn (m68hc11_gen_highpart (QImode, low2), src); - - emit_move_insn (m68hc11_gen_highpart (HImode, low), operands[2]); - low = m68hc11_gen_highpart (SImode, operands[0]); - emit_move_insn (m68hc11_gen_lowpart (HImode, low), operands[2]); - emit_move_insn (m68hc11_gen_highpart (HImode, low), operands[2]); - DONE; -}") - -(define_insn "zero_extendhidi2" - [(set (match_operand:DI 0 "non_push_operand" "=m,m,m,m,!u,!u") - (zero_extend:DI - (match_operand:HI 1 "nonimmediate_operand" "m,d,A,!u,dmA,!u"))) - (clobber (match_scratch:HI 2 "=&d,&B,&d,&dB,&dB,&dB"))] - "" - "#") - -(define_split - [(set (match_operand:DI 0 "non_push_operand" "") - (zero_extend:DI - (match_operand:HI 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:HI 2 ""))] - "z_replacement_completed == 2" - [(const_int 0)] - " -{ - rtx low = m68hc11_gen_lowpart (SImode, operands[0]); - rtx high = m68hc11_gen_highpart (SImode, operands[0]); - rtx src = operands[1]; - - /* Make sure the source is in a hard register. */ - if (!H_REG_P (src)) - { - src = operands[2]; - emit_move_insn (src, operands[1]); - } - - /* Move the low part first for the push. */ - emit_move_insn (m68hc11_gen_lowpart (HImode, low), src); - - /* Now, use the scratch register to fill in the zeros. */ - emit_move_insn (operands[2], const0_rtx); - emit_move_insn (m68hc11_gen_highpart (HImode, low), operands[2]); - emit_move_insn (m68hc11_gen_lowpart (HImode, high), operands[2]); - emit_move_insn (m68hc11_gen_highpart (HImode, high), operands[2]); - DONE; -}") - -(define_insn "zero_extendsidi2" - [(set (match_operand:DI 0 "nonimmediate_operand" "=m,m,!u,!u") - (zero_extend:DI - (match_operand:SI 1 "nonimmediate_operand" "m,Du,m,Du"))) - (clobber (match_scratch:HI 2 "=d,d,d,d"))] - "" - "#") - -(define_split - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (zero_extend:DI - (match_operand:SI 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:HI 2 ""))] - "z_replacement_completed == 2" - [(const_int 0)] - " -{ - rtx low = m68hc11_gen_lowpart (SImode, operands[0]); - rtx high = m68hc11_gen_highpart (SImode, operands[0]); - - /* Move the low part first so that this is ok for a push. */ - m68hc11_split_move (low, operands[1], operands[2]); - - /* Use the scratch register to clear the high part of the destination. */ - emit_move_insn (operands[2], const0_rtx); - emit_move_insn (m68hc11_gen_lowpart (HImode, high), operands[2]); - emit_move_insn (m68hc11_gen_highpart (HImode, high), operands[2]); - DONE; -}") - -;; -;; For 16->32bit unsigned extension, we don't allow generation on the stack -;; because it's less efficient. -;; -(define_insn "zero_extendhisi2" - [(set (match_operand:SI 0 "non_push_operand" "=D,m,u,m,m,!u,!u") - (zero_extend:SI - (match_operand:HI 1 "nonimmediate_operand" "dAmu,dA,dA,m,!u,m,!u"))) - (clobber (match_scratch:HI 2 "=X,X,X,&d,&dB,&dB,&dB"))] - "" - "#") - -(define_split - [(set (match_operand:SI 0 "non_push_operand" "") - (zero_extend:SI - (match_operand:HI 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:HI 2 ""))] - "reload_completed" - [(const_int 0)] - " -{ - rtx src = operands[1]; - - if (!H_REG_P (src) && !H_REG_P (operands[0])) - { - src = operands[2]; - emit_move_insn (src, operands[1]); - } - emit_move_insn (m68hc11_gen_lowpart (HImode, operands[0]), src); - emit_move_insn (m68hc11_gen_highpart (HImode, operands[0]), const0_rtx); - DONE; -}") - -(define_insn "zero_extendqisi2" - [(set (match_operand:SI 0 "non_push_operand" "=D,D,m,m,u") - (zero_extend:SI - (match_operand:QI 1 "nonimmediate_operand" "dmu,xy,d,xy,dxy")))] - "" - "#") - -(define_split - [(set (match_operand:SI 0 "non_push_operand" "") - (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] - "reload_completed && !X_REG_P (operands[0])" - [(set (match_dup 2) (zero_extend:HI (match_dup 1))) - (set (match_dup 3) (const_int 0))] - " - operands[2] = m68hc11_gen_lowpart (HImode, operands[0]); - operands[3] = m68hc11_gen_highpart (HImode, operands[0]);") - -(define_split - [(set (match_operand:SI 0 "hard_reg_operand" "") - (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] - "z_replacement_completed == 2 && X_REG_P (operands[0])" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 4) (const_int 0)) - (set (match_dup 5) (zero_extend:HI (match_dup 6)))] - " - if (X_REG_P (operands[1])) - { - emit_insn (gen_swap_areg (gen_rtx_REG (HImode, HARD_D_REGNUM), - gen_rtx_REG (HImode, HARD_X_REGNUM))); - emit_insn (gen_zero_extendqihi2 (gen_rtx_REG (HImode, HARD_D_REGNUM), - gen_rtx_REG (QImode, HARD_D_REGNUM))); - emit_move_insn (gen_rtx_REG (HImode, HARD_X_REGNUM), - const0_rtx); - DONE; - } - - if (reg_mentioned_p (gen_rtx_REG (HImode, HARD_X_REGNUM), operands[1])) - { - emit_insn (gen_zero_extendqihi2 (m68hc11_gen_lowpart (HImode, - operands[0]), - operands[1])); - emit_move_insn (gen_rtx_REG (HImode, HARD_X_REGNUM), const0_rtx); - DONE; - } - operands[4] = m68hc11_gen_highpart (HImode, operands[0]); - operands[5] = m68hc11_gen_lowpart (HImode, operands[0]); - if (A_REG_P (operands[1])) - { - operands[2] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); - operands[3] = gen_rtx_REG (HImode, REGNO (operands[1])); - operands[6] = gen_rtx_REG (QImode, SOFT_TMP_REGNUM); - } - else - { - operands[5] = operands[2] = - operands[3] = gen_rtx_REG (HImode, HARD_D_REGNUM); - operands[6] = operands[1]; - } -") - -(define_insn "zero_extendqihi2" - [(set (match_operand:HI 0 "non_push_operand" "=dm,d,*A,!*u,d,m,!*u") - (zero_extend:HI - (match_operand:QI 1 "nonimmediate_operand" "d,*A,d*Am,d,!um,*A,*A")))] - "" - "* -{ - if (A_REG_P (operands[0])) - return \"#\"; - - if (H_REG_P (operands[0])) - { - output_asm_insn (\"clra\", operands); - if (operands[0] != operands[1] - && !(D_REG_P (operands[0]) && D_REG_P (operands[1]))) - { - if (X_REG_P (operands[1]) - || (D_REG_P (operands[1]) && X_REG_P (operands[0]))) - { - output_asm_insn (\"stx\\t%t1\", operands); - output_asm_insn (\"ldab\\t%T0\", operands); - } - else if (Y_REG_P (operands[1]) - || (D_REG_P (operands[1]) && Y_REG_P (operands[0]))) - { - output_asm_insn (\"sty\\t%t1\", operands); - output_asm_insn (\"ldab\\t%T0\", operands); - } - else - { - output_asm_insn (\"ldab\\t%b1\", operands); - } - cc_status.flags |= CC_NOT_NEGATIVE; - } - else - { - /* Status refers to the clra insn. Status is ok for others - * since we have loaded the value in B. - */ - CC_STATUS_INIT; - } - return \"\"; - } - - if (A_REG_P (operands[1])) - { - output_asm_insn (\"st%1\\t%0\", operands); - output_asm_insn (\"clr\\t%h0\", operands); - CC_STATUS_INIT; - } - else - { - output_asm_insn (\"clr\\t%h0\", operands); - output_asm_insn (\"stab\\t%b0\", operands); - cc_status.flags |= CC_NOT_NEGATIVE; - } - - return \"\"; -}") - - -;;-------------------------------------------------------------------- -;;- Sign extension insns. -;;-------------------------------------------------------------------- - -(define_insn "extendqisi2" - [(set (match_operand:SI 0 "nonimmediate_operand" "=D,m,u") - (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "dmux,d,d")))] - "" - "* -{ - rtx ops[3]; - int need_tst = 0; - - /* The 68HC12 has a sign-extension instruction. Use it when the - destination is the register (X,D). First sign-extend the low - part and fill X with the sign-extension of the high part. */ - if (TARGET_M6812 && X_REG_P (operands[0])) - { - if (!D_REG_P (operands[1])) - { - ops[0] = gen_rtx_REG (QImode, HARD_D_REGNUM); - ops[1] = operands[1]; - m68hc11_gen_movqi (insn, ops); - } - return \"sex\\tb,d\\n\\tsex\\ta,x\"; - } - - ops[2] = gen_label_rtx (); - - if (X_REG_P (operands[1])) - { - output_asm_insn (\"xgdx\", operands); - need_tst = 1; - } - else if (X_REG_P (operands[0])) - { - /* X can be used as an indexed addressing in the source. - Get the value before clearing it. */ - if (reg_mentioned_p (ix_reg, operands[1])) - { - output_asm_insn (\"ldab\\t%b1\", operands); - need_tst = 1; - } - output_asm_insn (\"ldx\\t#0\", operands); - } - - output_asm_insn (\"clra\", operands); - if (!X_REG_P (operands[0])) - { - ops[0] = m68hc11_gen_lowpart (HImode, operands[0]); - ops[1] = m68hc11_gen_lowpart (QImode, ops[0]); - - if (IS_STACK_PUSH (operands[0])) - { - output_asm_insn (\"pshb\", ops); - output_asm_insn (\"tstb\", ops); - } - else - { - output_asm_insn (\"stab\\t%b1\", ops); - } - } - else if (D_REG_P (operands[1]) || need_tst) - { - output_asm_insn (\"tstb\", operands); - } - else - { - output_asm_insn (\"ldab\\t%b1\", operands); - } - output_asm_insn (\"bpl\\t%l2\", ops); - output_asm_insn (\"deca\", operands); - if (X_REG_P (operands[0])) - output_asm_insn (\"dex\", operands); - - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", CODE_LABEL_NUMBER (ops[2])); - - if (!X_REG_P (operands[0])) - { - if (IS_STACK_PUSH (operands[0])) - { - output_asm_insn (\"psha\", ops); - output_asm_insn (\"psha\", ops); - output_asm_insn (\"psha\", ops); - } - else - { - output_asm_insn (\"staa\\t%h0\", ops); - - ops[0] = m68hc11_gen_highpart (HImode, operands[0]); - if (dead_register_here (insn, d_reg)) - { - output_asm_insn (\"tab\", ops); - output_asm_insn (\"std\\t%0\", ops); - } - else - { - output_asm_insn (\"staa\\t%b0\", ops); - output_asm_insn (\"staa\\t%h0\", ops); - } - } - } - - CC_STATUS_INIT; - return \"\"; -}") - - -(define_insn "extendqihi2" - [(set (match_operand:HI 0 "non_push_operand" "=d,*x*ym,u") - (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "dum,0,0")))] - "" - "* -{ - rtx ops[2]; - - if (A_REG_P (operands[0])) - return \"#\"; - - ops[0] = gen_label_rtx (); - if (D_REG_P (operands[0])) - { - if (TARGET_M6812) - { - if (!D_REG_P (operands[1])) - { - ops[0] = gen_rtx_REG (QImode, HARD_D_REGNUM); - ops[1] = operands[1]; - m68hc11_gen_movqi (insn, ops); - } - return \"sex\\tb,d\"; - } - output_asm_insn (\"clra\", operands); - if (H_REG_P (operands[1])) - { - output_asm_insn (\"tstb\", operands); - } - else - { - output_asm_insn (\"ldab\\t%b1\", operands); - } - output_asm_insn (\"bpl\\t%l0\", ops); - output_asm_insn (\"deca\", operands); - - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (ops[0])); - } - else - { - output_asm_insn (\"clr\\t%h0\", operands); - if (m68hc11_register_indirect_p (operands[1], HImode)) - { - ops[1] = operands[1]; - output_asm_insn (\"brclr\\t%b1 #0x80 %l0\", ops); - CC_STATUS_INIT; - } - else - { - output_asm_insn (\"tst\\t%b1\", operands); - output_asm_insn (\"bpl\\t%l0\", ops); - } - output_asm_insn (\"dec\\t%h0\", operands); - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (ops[0])); - } - - return \"\"; -}") - -;; -;; Split the special case where the source of the sign extend is -;; either Y or Z. In that case, we can't move the source in the D -;; register directly. The movhi pattern handles this move by using -;; a temporary scratch memory location. -;; -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (sign_extend:SI (match_operand:HI 1 "register_operand" "")))] - "reload_completed && (Y_REG_P (operands[1]) || Z_REG_P (operands[1]))" - [(set (reg:HI D_REGNUM) (match_dup 1)) - (set (match_dup 0) (sign_extend:SI (reg:HI D_REGNUM)))] - "") - -(define_insn "extendhisi2" - [(set (match_operand:SI 0 "register_operand" "=D,D,D") - (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "m,!r,dA")))] - "" - "* -{ - rtx ops[2]; - int x_reg_used; - - if (Y_REG_P (operands[1])) - return \"#\"; - - if (X_REG_P (operands[1])) - { - output_asm_insn (\"xgdx\", operands); - x_reg_used = 1; - } - else - { - /* X can be used as an indexed addressing in the source. - Get the value before clearing it. */ - x_reg_used = reg_mentioned_p (ix_reg, operands[1]); - if (x_reg_used) - { - ops[0] = gen_rtx_REG (HImode, HARD_D_REGNUM); - ops[1] = operands[1]; - m68hc11_gen_movhi (insn, ops); - } - } - - CC_STATUS_INIT; - if (TARGET_M6812 && 0) - { - /* This sequence of code is larger than the one for 68HC11. - Don't use it; keep it for documentation. */ - if (!D_REG_P (operands[1]) && !x_reg_used) - { - ops[0] = gen_rtx_REG (HImode, HARD_D_REGNUM); - ops[1] = operands[1]; - m68hc11_gen_movhi (insn, ops); - } - output_asm_insn (\"sex\\ta,x\", operands); - output_asm_insn (\"xgdx\", operands); - output_asm_insn (\"sex\\ta,d\", operands); - return \"xgdx\"; - } - - output_asm_insn (\"ldx\\t#0\", operands); - if (D_REG_P (operands[1]) || x_reg_used) - { - output_asm_insn (\"tsta\", operands); - } - else - { - ops[0] = gen_rtx_REG (HImode, HARD_D_REGNUM); - ops[1] = operands[1]; - m68hc11_gen_movhi (insn, ops); - } - - ops[0] = gen_label_rtx (); - output_asm_insn (\"bpl\\t%l0\", ops); - output_asm_insn (\"dex\", operands); - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", CODE_LABEL_NUMBER (ops[0])); - - return \"\"; -}") - - -;;-------------------------------------------------------------------- -;;- Min and Max instructions (68HC12). -;;-------------------------------------------------------------------- -(define_insn "uminqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,m") - (umin:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") - (match_operand:QI 2 "general_operand" "m,d")))] - "TARGET_M6812 && TARGET_MIN_MAX" - "* -{ - /* Flags are set according to (sub:QI (operand 1) (operand2)). - The mina/minm use A as the source or destination. This is the - high part of D. There is no way to express that in the pattern - so we must use 'exg a,b' to put the operand in the good register. */ - CC_STATUS_INIT; - if (D_REG_P (operands[0])) - { - return \"exg\\ta,b\\n\\tmina\\t%2\\n\\texg\\ta,b\"; - } - else - { - return \"exg\\ta,b\\n\\tminm\\t%0\\n\\texg\\ta,b\"; - } -}") - -(define_insn "umaxqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,m") - (umax:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") - (match_operand:QI 2 "general_operand" "m,d")))] - "TARGET_M6812 && TARGET_MIN_MAX" - "* -{ - /* Flags are set according to (sub:QI (operand 1) (operand2)). - The maxa/maxm use A as the source or destination. This is the - high part of D. There is no way to express that in the pattern - so we must use 'exg a,b' to put the operand in the good register. */ - CC_STATUS_INIT; - if (D_REG_P (operands[0])) - { - return \"exg\\ta,b\\n\\tmaxa\\t%2\\n\\texg\\ta,b\"; - } - else - { - return \"exg\\ta,b\\n\\tmaxm\\t%0\\n\\texg\\ta,b\"; - } -}") - -(define_insn "uminhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,m") - (umin:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") - (match_operand:HI 2 "general_operand" "m,d")))] - "TARGET_M6812 && TARGET_MIN_MAX" - "* -{ - /* Flags are set according to (sub:HI (operand 1) (operand2)). */ - CC_STATUS_INIT; - if (D_REG_P (operands[0])) - { - return \"emind\\t%2\"; - } - else - { - return \"eminm\\t%0\"; - } -}") - -(define_insn "umaxhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,m") - (umax:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") - (match_operand:HI 2 "general_operand" "m,d")))] - "TARGET_M6812 && TARGET_MIN_MAX" - "* -{ - /* Flags are set according to (sub:HI (operand 1) (operand2)). */ - CC_STATUS_INIT; - if (D_REG_P (operands[0])) - { - return \"emaxd\\t%2\"; - } - else - { - return \"emaxm\\t%0\"; - } -}") - - -;;-------------------------------------------------------------------- -;;- Add instructions. -;;-------------------------------------------------------------------- -;; 64-bit: Use a library call because what GCC generates is huge. -;; -(define_expand "adddi3" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (plus:DI (match_operand:DI 1 "general_operand" "") - (match_operand:DI 2 "general_operand" "")))] - "" - "m68hc11_emit_libcall (\"___adddi3\", PLUS, DImode, DImode, 3, operands); - DONE;") - -;; -;; - 32-bit Add. -;; -(define_expand "addsi3" - [(parallel [(set (match_operand:SI 0 "register_operand" "") - (plus:SI (match_operand:SI 1 "general_operand" "") - (match_operand:SI 2 "general_operand" ""))) - (clobber (match_scratch:HI 3 ""))])] - "" - "") - -(define_insn "*addsi3_zero_extendhi" - [(set (match_operand:SI 0 "register_operand" "=D,D,D,D") - (plus:SI (zero_extend:SI - (match_operand:HI 1 "general_operand" "dxi,!u,mdxi,!u")) - (match_operand:SI 2 "general_operand" "mi,mi,D?u,!Du"))) - (clobber (match_scratch:HI 3 "=X,X,X,X"))] - "" - "* -{ - rtx ops[3]; - - if (X_REG_P (operands[2])) - { - ops[0] = operands[1]; - } - else - { - if (X_REG_P (operands[1])) - { - output_asm_insn (\"xgdx\", ops); - } - else if (!D_REG_P (operands[1])) - { - ops[0] = gen_rtx_REG (HImode, HARD_D_REGNUM); - ops[1] = operands[1]; - m68hc11_gen_movhi (insn, ops); - } - ops[0] = m68hc11_gen_lowpart (HImode, operands[2]); - ops[1] = m68hc11_gen_highpart (HImode, operands[2]); - } - ops[2] = gen_label_rtx (); - - /* ldx preserves the carry, propagate it by incrementing X directly. */ - output_asm_insn (\"addd\\t%0\", ops); - if (!X_REG_P (operands[2])) - output_asm_insn (\"ldx\\t%1\", ops); - - output_asm_insn (\"bcc\\t%l2\", ops); - output_asm_insn (\"inx\", ops); - - CC_STATUS_INIT; - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", CODE_LABEL_NUMBER (ops[2])); - return \"\"; -}") - - -(define_split /* "*addsi3_zero_extendqi" */ - [(set (match_operand:SI 0 "register_operand" "") - (plus:SI (zero_extend:SI - (match_operand:QI 1 "general_operand" "")) - (match_operand:SI 2 "memory_operand" ""))) - (clobber (match_scratch:HI 3 "=X,X"))] - "reload_completed" - [(set (reg:HI D_REGNUM) (zero_extend:HI (match_dup 1))) - (parallel [(set (match_dup 0) - (plus:SI (zero_extend:SI (reg:HI D_REGNUM)) (match_dup 2))) - (clobber (match_dup 3))])] - "") - -(define_insn "*addsi3_zero_extendqi" - [(set (match_operand:SI 0 "register_operand" "=D,D") - (plus:SI (zero_extend:SI - (match_operand:QI 1 "general_operand" "dAmi,!dAmiu")) - (match_operand:SI 2 "general_operand" "miD,!muiD"))) - (clobber (match_scratch:HI 3 "=X,X"))] - "" - "* -{ - rtx ops[4]; - - if (GET_CODE (operands[2]) == MEM) - return \"#\"; - - if (X_REG_P (operands[2])) - { - if (H_REG_P (operands[1])) - { - ops[0] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); - ops[1] = gen_rtx_REG (HImode, REGNO (operands[1])); - m68hc11_gen_movhi (insn, ops); - } - else - { - ops[0] = operands[1]; - } - ops[1] = const0_rtx; - } - else - { - if (X_REG_P (operands[1])) - { - output_asm_insn (\"xgdx\", ops); - } - else if (!D_REG_P (operands[1])) - { - ops[0] = gen_rtx_REG (QImode, HARD_D_REGNUM); - ops[1] = operands[1]; - m68hc11_gen_movqi (insn, ops); - } - - ops[0] = m68hc11_gen_lowpart (HImode, operands[2]); - ops[1] = ops[0]; - ops[2] = m68hc11_gen_highpart (HImode, operands[2]); - output_asm_insn (\"clra\", ops); - } - - /* ldx preserves the carry, propagate it by incrementing X directly. */ - output_asm_insn (\"addb\\t%b0\", ops); - output_asm_insn (\"adca\\t%h1\", ops); - if (!X_REG_P (operands[2])) - output_asm_insn (\"ldx\\t%2\", ops); - - /* If the above adca was adding some constant, we don't need to propagate - the carry unless the constant was 0xff. */ - if (X_REG_P (operands[2]) - || GET_CODE (ops[1]) != CONST_INT - || ((INTVAL (ops[1]) & 0x0ff00) == 0x0ff00)) - { - ops[3] = gen_label_rtx (); - - output_asm_insn (\"bcc\\t%l3\", ops); - output_asm_insn (\"inx\", ops); - - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (ops[3])); - } - CC_STATUS_INIT; - return \"\"; -}") - -(define_insn "*addsi3" - [(set (match_operand:SI 0 "non_push_operand" "=o,D,!u,?D,D") - (plus:SI (match_operand:SI 1 "non_push_operand" "%0,0,0,0,0") - (match_operand:SI 2 "general_operand" "ML,i,ML,?D,?oiu"))) - (clobber (match_scratch:HI 3 "=d,X,d,X,X"))] - "" - "* -{ - rtx ops[3]; - const char* add_insn; - const char* inc_insn; - const char* incb_mem; - const char* inch_mem; - HOST_WIDE_INT val; - - if (which_alternative > 2) - { - return \"#\"; - } - - val = INTVAL (operands[2]); - if ((val & 0x0ffffL) == 0) - { - if (!H_REG_P (operands[0])) - { - ops[0] = m68hc11_gen_highpart (HImode, operands[0]); - ops[1] = m68hc11_gen_highpart (HImode, operands[2]); - output_asm_insn (\"ldd\\t%0\", ops); - output_asm_insn (\"addd\\t%1\", ops); - output_asm_insn (\"std\\t%0\", ops); - return \"\"; - } - else if (val == 1) - { - return \"inx\"; - } - else - { - return \"#\"; - } - } - if ((val & 0xffff0000L) != 0 && (val & 0xffff0000L) != 0xffff0000L) - { - return \"#\"; - } - - if (val >= 0) - { - ops[1] = operands[2]; - add_insn = \"addd\\t%1\"; - inc_insn = \"inx\\t\"; - incb_mem = \"inc\\t%b1\"; - inch_mem = \"inc\\t%h1\"; - } - else - { - ops[1] = GEN_INT (- val); - add_insn = \"subd\\t%1\"; - inc_insn = \"dex\"; - incb_mem = \"dec\\t%b1\"; - inch_mem = \"dec\\t%h1\"; - } - - ops[2] = gen_label_rtx (); - if (!H_REG_P (operands[0])) - { - ops[0] = m68hc11_gen_lowpart (HImode, operands[0]); - output_asm_insn (\"ldd\\t%0\", ops); - } - output_asm_insn (add_insn, ops); - if (!H_REG_P (operands[0])) - { - output_asm_insn (\"std\\t%0\", ops); - } - output_asm_insn (\"bcc\\t%l2\", ops); - if (H_REG_P (operands[0])) - { - output_asm_insn (inc_insn, ops); - } - else - { - ops[0] = m68hc11_gen_highpart (HImode, operands[0]); - ops[1] = ops[0]; - if (INTVAL (operands[2]) < 0) - { - output_asm_insn (\"ldd\\t%1\", ops); - output_asm_insn (\"addd\\t#-1\", ops); - output_asm_insn (\"std\\t%1\", ops); - } - else - { - output_asm_insn (incb_mem, ops); - output_asm_insn (\"bne\\t%l2\", ops); - output_asm_insn (inch_mem, ops); - } - } - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", CODE_LABEL_NUMBER (ops[2])); - - CC_STATUS_INIT; - return \"\"; -}") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (plus:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "const_int_operand" ""))) - (clobber (match_scratch:HI 3 ""))] - "reload_completed && z_replacement_completed == 2 - && ((INTVAL (operands[2]) & 0x0FFFF) == 0)" - [(set (match_dup 5) (match_dup 6)) - (set (reg:HI 0) (plus:HI (reg:HI 0) (match_dup 4))) - (set (match_dup 6) (match_dup 5))] - "operands[4] = m68hc11_gen_highpart (HImode, operands[2]); - if (X_REG_P (operands[0])) - { - operands[5] = operands[6] = gen_rtx_REG (HImode, HARD_D_REGNUM); - } - else - { - operands[6] = m68hc11_gen_highpart (HImode, operands[1]); - operands[5] = operands[3]; - } - ") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (plus:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "general_operand" ""))) - (clobber (match_scratch:HI 3 "=X"))] - "reload_completed && z_replacement_completed == 2 - && (GET_CODE (operands[2]) != CONST_INT || - (!(INTVAL (operands[2]) >= -65536 && INTVAL (operands[2]) <= 65535)))" - [(set (reg:HI D_REGNUM) (plus:HI (reg:HI D_REGNUM) (match_dup 3))) - (parallel [(set (reg:HI D_REGNUM) (reg:HI X_REGNUM)) - (set (reg:HI X_REGNUM) (reg:HI D_REGNUM))]) - (set (reg:QI B_REGNUM) (plus:QI (plus:QI (reg:QI CC_REGNUM) (reg:QI B_REGNUM)) (match_dup 4))) - (set (reg:QI A_REGNUM) (plus:QI (plus:QI (reg:QI CC_REGNUM) (reg:QI A_REGNUM)) (match_dup 5))) - (parallel [(set (reg:HI D_REGNUM) (reg:HI X_REGNUM)) - (set (reg:HI X_REGNUM) (reg:HI D_REGNUM))])] - "operands[3] = m68hc11_gen_lowpart (HImode, operands[2]); - operands[4] = m68hc11_gen_highpart (HImode, operands[2]); - operands[5] = m68hc11_gen_highpart (QImode, operands[4]); - operands[4] = m68hc11_gen_lowpart (QImode, operands[4]);") - -;; -;; Instruction generated to propagate the carry of a 16-bit add -;; to the upper 16-bit part (in register X). -;; -(define_insn "*addsi_carry" - [(set (match_operand:HI 0 "register_operand" "=x") - (plus:HI (plus:HI (match_operand:HI 1 "register_operand" "0") - (const_int 0)) - (reg:HI CC_REGNUM)))] - "" - "* -{ - rtx ops[2]; - - ops[0] = gen_label_rtx (); - output_asm_insn (\"bcc\\t%l0\", ops); - output_asm_insn (\"in%0\", operands); - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", CODE_LABEL_NUMBER (ops[0])); - CC_STATUS_INIT; - return \"\"; -}") - -;; -;; - 16-bit Add. -;; -(define_expand "addhi3" - [(set (match_operand:HI 0 "register_operand" "") - (plus:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" "")))] - "" - " -{ - if (TARGET_M6811 && SP_REG_P (operands[0])) - { - emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, - gen_rtx_SET (VOIDmode, - operand0, - gen_rtx_PLUS (HImode, - operand1, operand2)), - gen_rtx_CLOBBER (VOIDmode, - gen_rtx_SCRATCH (HImode))))); - DONE; - } -}") - -(define_insn "*addhi3_68hc12" - [(set (match_operand:HI 0 "register_operand" "=d*A,d,xy*A*w,xy*A*w,xy*A") - (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,xy*Aw,0") - (match_operand:HI 2 "general_operand" "i,m*A*wu,id,id,!mu*A")))] - "TARGET_M6812" - "* -{ - int val; - const char* insn_code; - - if (which_alternative >= 4) - { - if (A_REG_P (operands[2])) - { - CC_STATUS_INIT; - output_asm_insn (\"xgd%2\", operands); - output_asm_insn (\"lea%0 d,%0\", operands); - return \"xgd%2\"; - } - return \"#\"; - } - - if (D_REG_P (operands[0])) - { - if (X_REG_P (operands[2])) - { - m68hc11_notice_keep_cc (operands[0]); - output_asm_insn (\"xgdx\", operands); - output_asm_insn (\"leax\\td,%2\", operands); - return \"xgdx\"; - } - else if (Y_REG_P (operands[2])) - { - m68hc11_notice_keep_cc (operands[0]); - output_asm_insn (\"xgdy\", operands); - output_asm_insn (\"leay\\td,%2\", operands); - return \"xgdy\"; - } - else if (SP_REG_P (operands[2])) - { - output_asm_insn (\"sts\\t%t0\", operands); - return \"addd\\t%t0\"; - } - return \"addd\\t%2\"; - } - - if (GET_CODE (operands[2]) == CONST_INT) - val = INTVAL (operands[2]); - else - val = 1000; - - if ((val != -1 && val != 1) || !rtx_equal_p (operands[0], operands[1])) - { - m68hc11_notice_keep_cc (operands[0]); - switch (REGNO (operands[0])) - { - case HARD_X_REGNUM: - return \"leax\\t%i2,%1\"; - - case HARD_Y_REGNUM: - return \"leay\\t%i2,%1\"; - - case HARD_SP_REGNUM: - return \"leas\\t%i2,%1\"; - - default: - fatal_insn (\"Invalid operands in the instruction\", insn); - } - } - if (val > 0) - { - insn_code = X_REG_P (operands[0]) ? \"inx\" - : Y_REG_P (operands[0]) ? \"iny\" : \"ins\"; - } - else - { - val = -val; - insn_code = X_REG_P (operands[0]) ? \"dex\" - : Y_REG_P (operands[0]) ? \"dey\" : \"des\"; - } - - /* For X and Y increment, the flags are not complete. Only the Z flag - is updated. For SP increment, flags are not changed. */ - if (SP_REG_P (operands[0])) - { - cc_status = cc_prev_status; - if (INTVAL (operands[2]) < 0) - { - while (val > 2) - { - output_asm_insn (\"pshx\", operands); - val -= 2; - } - if (val == 0) - return \"\"; - } - } - else - { - CC_STATUS_INIT; - } - - while (val) - { - output_asm_insn (insn_code, operands); - val--; - } - return \"\"; -}") - -;; -;; Specific pattern to add to the stack pointer. -;; We also take care of the clobbering of the IY register. -;; -(define_insn "addhi_sp" - [(set (match_operand:HI 0 "stack_register_operand" "=w,w,w,w") - (plus:HI (match_operand:HI 1 "stack_register_operand" "%0,0,0,0") - (match_operand:HI 2 "general_operand" "P,im,u,im"))) - (clobber (match_scratch:HI 3 "=X,&y,&y,!&x"))] - "!TARGET_M6812" - "* -{ - HOST_WIDE_INT val; - - if (optimize && Y_REG_P (operands[3]) - && dead_register_here (insn, gen_rtx_REG (HImode, HARD_X_REGNUM))) - operands[3] = gen_rtx_REG (HImode, HARD_X_REGNUM); - - if (GET_CODE (operands[2]) == CONST_INT - && (val = INTVAL (operands[2])) != 0 - && (CONST_OK_FOR_LETTER_P (val, 'P') - || (val > 0 && val <= 8))) - { - while (val > 1 || val < -1) - { - if (val > 0) - { - if (!H_REG_P (operands[3])) - break; - - output_asm_insn (\"pul%3\", operands); - val -= 2; - } - else - { - output_asm_insn (\"pshx\", operands); - val += 2; - } - } - while (val != 0) - { - if (val > 0) - { - output_asm_insn (\"ins\", operands); - val--; - } - else - { - output_asm_insn (\"des\", operands); - val++; - } - } - cc_status = cc_prev_status; - return \"\"; - } - - /* Need to transfer to SP to X/Y and then to D register. - Register X/Y is lost, this is specified by the (clobber) statement. */ - output_asm_insn (\"ts%3\", operands); - if (GET_CODE (operands[2]) == CONST_INT - && ((val = INTVAL (operands[2])) >= 0 && val < 0x100) - && dead_register_here (insn, gen_rtx_REG (HImode, HARD_D_REGNUM))) - { - output_asm_insn (\"ldab\\t%2\", operands); - output_asm_insn (\"ab%3\", operands); - CC_STATUS_INIT; - } - else - { - output_asm_insn (\"xgd%3\", operands); - output_asm_insn (\"addd\\t%2\", operands); - output_asm_insn (\"xgd%3\", operands); - } - - /* The status flags correspond to the addd. xgdy and tys do not - modify the flags. */ - return \"t%3s\"; -}") - -(define_insn "*addhi3" - [(set (match_operand:HI 0 "hard_reg_operand" "=A,dA,d,!A,d*A,d,!d*A") - (plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0,0,0,0") - (match_operand:HI 2 "general_operand" "N,I,i,I,mi*A*d,*u,!u*d*w")))] - "TARGET_M6811" - "* -{ - const char* insn_code; - int val; - - if (D_REG_P (operands[0]) && SP_REG_P (operands[2])) - { - output_asm_insn (\"sts\\t%t0\", operands); - output_asm_insn (\"addd\\t%t0\", operands); - return \"addd\\t#1\"; - } - if (GET_CODE (operands[2]) != CONST_INT) - { - /* Adding to an address register or with another/same register - is not possible. This must be replaced. */ - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - - return \"addd\\t%2\"; - } - val = INTVAL (operands[2]); - if (!SP_REG_P (operands[0])) - { - if (D_REG_P (operands[0])) - { - if ((val & 0x0ff) == 0 && !next_insn_test_reg (insn, operands[0])) - { - CC_STATUS_INIT; - return \"adda\\t%h2\"; - } - else - { - return \"addd\\t%2\"; - } - } - else if (GET_CODE (operands[2]) != CONST_INT - || INTVAL (operands[2]) < -4 - || INTVAL (operands[2]) > 4) - return \"#\"; - } - if (val > 0) - { - insn_code = X_REG_P (operands[0]) ? \"inx\" - : Y_REG_P (operands[0]) ? \"iny\" : \"ins\"; - } - else - { - val = -val; - insn_code = X_REG_P (operands[0]) ? \"dex\" - : Y_REG_P (operands[0]) ? \"dey\" : \"des\"; - } - - /* For X and Y increment, the flags are not complete. Only the Z flag - is updated. For SP increment, flags are not changed. */ - if (SP_REG_P (operands[0])) - { - cc_status = cc_prev_status; - if (INTVAL (operands[2]) < 0) - { - while (val >= 2) - { - output_asm_insn (\"pshx\", operands); - val -= 2; - } - } - else if (optimize && dead_register_here (insn, ix_reg)) - { - while (val >= 2) - { - output_asm_insn (\"pulx\", operands); - val -= 2; - } - } - } - else - { - CC_STATUS_INIT; - } - - while (val) - { - output_asm_insn (insn_code, operands); - val--; - } - return \"\"; -}") - -(define_insn "*addhi3_zext" - [(set (match_operand:HI 0 "hard_reg_operand" "=A,d") - (plus:HI (zero_extend:HI - (match_operand:QI 1 "nonimmediate_operand" "d,um*A")) - (match_operand:HI 2 "general_operand" "0,0")))] - "" - "* -{ - CC_STATUS_INIT; - if (A_REG_P (operands[0])) - return \"ab%0\"; - else if (A_REG_P (operands[1])) - return \"st%1\\t%t0\\n\\taddb\\t%T0\\n\\tadca\\t#0\"; - else - return \"addb\\t%b1\\n\\tadca\\t#0\"; -}") - -;; -;; Translate d = d + d into d = << 1 -;; We have to do this because adding a register to itself is not possible. -;; ??? It's not clear whether this is really necessary. -;; -(define_split - [(set (match_operand:QI 0 "hard_reg_operand" "") - (plus:QI (match_dup 0) - (match_dup 0)))] - "0 && reload_completed" - [(set (match_dup 0) (ashift:QI (match_dup 0) (const_int 1)))] - "") - -(define_insn "addqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "=!d*rm,dq,!*A") - (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:QI 2 "general_operand" "N,ium*A*d,ium*A*d")))] - "" - "* -{ - if (GET_CODE (operands[2]) == CONST_INT) - { - if (INTVAL (operands[2]) == 1) - { - if (DA_REG_P (operands[0])) - { - return \"inca\"; - } - else if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - { - return \"incb\"; - - } - else if (A_REG_P (operands[0])) - { - /* This applies on the 16-bit register. This should be ok since - this is not a strict_low_part increment. */ - return \"in%0\"; - } - else - { - return \"inc\\t%b0\"; - } - } - else if (INTVAL (operands[2]) == -1) - { - if (DA_REG_P (operands[0])) - { - return \"deca\"; - } - else if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - { - return \"decb\"; - } - else if (A_REG_P (operands[0])) - { - /* This applies on the 16-bit register. This should be ok since - this is not a strict_low_part decrement. */ - return \"de%0\"; - } - else - { - return \"dec\\t%b0\"; - } - } - } - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - else if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - return \"addb\\t%b2\"; - else - return \"adda\\t%b2\"; -}") - -;; -;; add with carry is used for 32-bit add. -;; -(define_insn "*adcq" - [(set (match_operand:QI 0 "register_operand" "=q") - (plus:QI (plus:QI (reg:QI CC_REGNUM) - (match_operand:QI 1 "register_operand" "%0")) - (match_operand:QI 2 "general_operand" "ium")))] - "" - "adc%0\\t%b2") - -;;-------------------------------------------------------------------- -;;- Subtract instructions. -;;-------------------------------------------------------------------- - -(define_expand "subdi3" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (minus:DI (match_operand:DI 1 "nonimmediate_operand" "") - (match_operand:DI 2 "general_operand" "")))] - "" - "m68hc11_emit_libcall (\"___subdi3\", MINUS, DImode, DImode, 3, operands); - DONE;") - -;; -;; 32-bit Subtract (see addsi3) -;; Subtract with a constant are handled by addsi3. -;; -;; -;; - 32-bit Add. -;; -(define_expand "subsi3" - [(parallel [(set (match_operand:SI 0 "register_operand" "") - (minus:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "general_operand" ""))) - (clobber (match_scratch:HI 3 ""))])] - "" - "") - -(define_insn "*subsi3" - [(set (match_operand:SI 0 "register_operand" "=D,D,D,D,!u") - (minus:SI (match_operand:SI 1 "general_operand" "0,oi,0,!u,0") - (match_operand:SI 2 "general_operand" "oi,D,!u,D,!oui"))) - (clobber (match_scratch:HI 3 "=X,X,X,X,d"))] - "" - "#") - -(define_insn "*subsi3_zero_extendhi" - [(set (match_operand:SI 0 "register_operand" "=D") - (minus:SI (match_operand:SI 1 "register_operand" "0") - (zero_extend:SI (match_operand:HI 2 "general_operand" "dmui*A")))) - (clobber (match_scratch:HI 3 "=X"))] - "" - "* -{ - rtx ops[2]; - - if (A_REG_P (operands[2])) - { - if (TARGET_M6812) - ops[0] = gen_rtx_MEM (HImode, - gen_rtx_PRE_DEC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM))); - else - ops[0] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); - - ops[1] = operands[2]; - m68hc11_gen_movhi (insn, ops); - if (TARGET_M6812) - operands[2] = gen_rtx_MEM (HImode, - gen_rtx_POST_INC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM))); - else - operands[2] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); - } - ops[0] = gen_label_rtx (); - output_asm_insn (\"subd\\t%2\", operands); - output_asm_insn (\"bcc\\t%l0\", ops); - output_asm_insn (\"dex\", ops); - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", CODE_LABEL_NUMBER (ops[0])); - CC_STATUS_INIT; - return \"\"; -}") - -(define_insn "*subsi3_zero_extendqi" - [(set (match_operand:SI 0 "register_operand" "=D") - (minus:SI (match_operand:SI 1 "register_operand" "0") - (zero_extend:SI (match_operand:QI 2 "general_operand" "dmui*A")))) - (clobber (match_scratch:HI 3 "=X"))] - "" - "* -{ - rtx ops[2]; - - if (A_REG_P (operands[2])) - { - ops[0] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); - ops[1] = operands[2]; - m68hc11_gen_movhi (insn, ops); - operands[2] = gen_rtx_REG (QImode, SOFT_TMP_REGNUM); - } - ops[0] = gen_label_rtx (); - output_asm_insn (\"subb\\t%b2\", operands); - output_asm_insn (\"sbca\\t#0\", operands); - output_asm_insn (\"bcc\\t%l0\", ops); - output_asm_insn (\"dex\", ops); - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", CODE_LABEL_NUMBER (ops[0])); - CC_STATUS_INIT; - return \"\"; -}") - -;; -;; reg:HI 1 -> d reg:QI 6 -> B -;; reg:QI 7 -> ccr reg:QI 5 -> A -;; -(define_split /* "*subsi3" */ - [(set (match_operand:SI 0 "register_operand" "") - (minus:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "general_operand" ""))) - (clobber (match_scratch:HI 3 "=X"))] - "reload_completed && z_replacement_completed == 2 - && X_REG_P (operands[1])" - [(set (reg:HI D_REGNUM) (minus:HI (reg:HI D_REGNUM) (match_dup 3))) - (parallel [(set (reg:HI X_REGNUM) (reg:HI D_REGNUM)) - (set (reg:HI D_REGNUM) (reg:HI X_REGNUM))]) - (set (reg:QI B_REGNUM) (minus:QI (minus:QI (reg:QI CC_REGNUM) (reg:QI B_REGNUM)) (match_dup 4))) - (set (reg:QI A_REGNUM) (minus:QI (minus:QI (reg:QI CC_REGNUM) (reg:QI A_REGNUM)) (match_dup 5))) - (parallel [(set (reg:HI X_REGNUM) (reg:HI D_REGNUM)) - (set (reg:HI D_REGNUM) (reg:HI X_REGNUM))])] - "operands[3] = m68hc11_gen_lowpart (HImode, operands[2]); - operands[4] = m68hc11_gen_highpart (HImode, operands[2]); - operands[5] = m68hc11_gen_highpart (QImode, operands[4]); - operands[4] = m68hc11_gen_lowpart (QImode, operands[4]);") - -(define_split /* "*subsi3" */ - [(set (match_operand:SI 0 "register_operand" "") - (minus:SI (match_operand:SI 1 "general_operand" "") - (match_operand:SI 2 "register_operand" ""))) - (clobber (match_scratch:HI 3 "=X"))] - "reload_completed && z_replacement_completed == 2 - && X_REG_P (operands[2])" - [(set (reg:HI D_REGNUM) (minus:HI (reg:HI D_REGNUM) (match_dup 3))) - (parallel [(set (reg:HI X_REGNUM) (reg:HI D_REGNUM)) - (set (reg:HI D_REGNUM) (reg:HI X_REGNUM))]) - (set (reg:QI B_REGNUM) (minus:QI (minus:QI (reg:QI CC_REGNUM) (reg:QI B_REGNUM)) (match_dup 4))) - (set (reg:QI A_REGNUM) (minus:QI (minus:QI (reg:QI CC_REGNUM) (reg:QI A_REGNUM)) (match_dup 5))) - (parallel [(set (reg:HI X_REGNUM) (reg:HI D_REGNUM)) - (set (reg:HI D_REGNUM) (reg:HI X_REGNUM))]) - (set (reg:SI 0) (neg:SI (reg:SI 0)))] - "operands[3] = m68hc11_gen_lowpart (HImode, operands[1]); - operands[4] = m68hc11_gen_highpart (HImode, operands[1]); - operands[5] = m68hc11_gen_highpart (QImode, operands[4]); - operands[4] = m68hc11_gen_lowpart (QImode, operands[4]);") - -(define_split /* "*subsi3" */ - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (minus:SI (match_operand:SI 1 "general_operand" "") - (match_operand:SI 2 "general_operand" ""))) - (clobber (match_scratch:HI 3 "=d"))] - "reload_completed && z_replacement_completed == 2 - && !X_REG_P (operands[0])" - [(set (match_dup 3) (match_dup 4)) - (set (match_dup 3) (minus:HI (match_dup 3) (match_dup 5))) - (set (match_dup 4) (match_dup 3)) - (set (match_dup 3) (match_dup 6)) - (set (reg:QI 6) (minus:QI (minus:QI (reg:QI 7) (reg:QI 6)) (match_dup 7))) - (set (reg:QI 5) (minus:QI (minus:QI (reg:QI 7) (reg:QI 5)) (match_dup 8))) - (set (match_dup 6) (match_dup 3))] - "operands[4] = m68hc11_gen_lowpart (HImode, operands[1]); - operands[5] = m68hc11_gen_lowpart (HImode, operands[2]); - operands[6] = m68hc11_gen_highpart (HImode, operands[1]); - operands[7] = m68hc11_gen_highpart (HImode, operands[2]); - operands[8] = m68hc11_gen_highpart (QImode, operands[7]); - operands[7] = m68hc11_gen_lowpart (QImode, operands[7]);") - -;; -;; - 16-bit Subtract. -;; -(define_expand "subhi3" - [(set (match_operand:HI 0 "register_operand" "=r") - (minus:HI (match_operand:HI 1 "register_operand" "0") - (match_operand:HI 2 "general_operand" "g")))] - "" - "") - -;; -;; Subtract from stack. This is better if we provide a pattern. -;; -(define_insn "*subhi3_sp" - [(set (match_operand:HI 0 "stack_register_operand" "=w,w") - (minus:HI (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "general_operand" "im*d,!u*A"))) - (clobber (match_scratch:HI 3 "=A*d,A*d"))] - "" - "* -{ - if (X_REG_P (operands[2])) - { - operands[2] = m68hc11_soft_tmp_reg; - output_asm_insn (\"stx\\t%2\", operands); - } - else if (Y_REG_P (operands[2])) - { - operands[2] = m68hc11_soft_tmp_reg; - output_asm_insn (\"sty\\t%2\", operands); - } - else if (D_REG_P (operands[2])) - { - operands[2] = m68hc11_soft_tmp_reg; - output_asm_insn (\"std\\t%2\", operands); - } - - if (D_REG_P (operands[3])) - { - int save_x; - - save_x = !dead_register_here (insn, ix_reg); - if (save_x) - output_asm_insn (\"xgdx\", operands); - output_asm_insn (\"tsx\", operands); - output_asm_insn (\"xgdx\", operands); - output_asm_insn (\"subd\\t%2\", operands); - output_asm_insn (\"xgdx\", operands); - - /* The status flags correspond to the addd. xgdx/y and tx/ys do not - modify the flags. */ - output_asm_insn (\"txs\", operands); - if (save_x) - return \"xgdx\"; - else - return \"\"; - } - - /* Need to transfer to SP to X,Y and then to D register. - Register X,Y is lost, this is specified by the (clobber) statement. */ - output_asm_insn (\"ts%3\", operands); - output_asm_insn (\"xgd%3\", operands); - output_asm_insn (\"subd\\t%2\", operands); - output_asm_insn (\"xgd%3\", operands); - - /* The status flags correspond to the addd. xgdx/y and tx/ys do not - modify the flags. */ - return \"t%3s\"; -}") - - -(define_insn "*subhi3" - [(set (match_operand:HI 0 "register_operand" "=d,*A,d,*A") - (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0") - (match_operand:HI 2 "general_operand" "im*A*d,im*d*A,u,!u")))] - "" - "* -{ - /* Adding to an address register or with another/same register - is not possible. This must be replaced. */ - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - - return \"subd\\t%2\"; -}") - -(define_insn "*subhi3_zext" - [(set (match_operand:HI 0 "hard_reg_operand" "=d,d") - (minus:HI (match_operand:HI 1 "general_operand" "0,0") - (zero_extend:HI (match_operand:QI 2 "general_operand" "mi*A,!u"))))] - "" - "* -{ - CC_STATUS_INIT; - if (A_REG_P (operands[2])) - { - rtx ops[2]; - - ops[0] = gen_rtx_REG (QImode, SOFT_TMP_REGNUM); - ops[1] = operands[2]; - m68hc11_gen_movqi (insn, ops); - return \"subb\\t%T0\\n\\tsbca\\t#0\"; - } - return \"subb\\t%b2\\n\\tsbca\\t#0\"; -}") - -(define_insn "subqi3" - [(set (match_operand:QI 0 "hard_reg_operand" "=dq,!*x*y") - (minus:QI (match_operand:QI 1 "general_operand" "0,0") - (match_operand:QI 2 "general_operand" "uim*A*d,uim*A*d")))] - "" - "* -{ - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - else if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - return \"subb\\t%b2\"; - else - return \"suba\\t%b2\"; -}") - -;; -;; subtract with carry is used for 32-bit subtract. -;; -(define_insn "*subcq" - [(set (match_operand:QI 0 "register_operand" "=q") - (minus:QI (minus:QI (reg:QI CC_REGNUM) - (match_operand:QI 1 "register_operand" "0")) - (match_operand:QI 2 "general_operand" "ium")))] - "" - "sbc%0\\t%b2") - -;;-------------------------------------------------------------------- -;;- Multiply instructions. -;;-------------------------------------------------------------------- -;; -;; 32 and 64-bit multiply are handled by the library -;; - -(define_expand "mulsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (mult:SI (match_operand:SI 1 "general_operand" "") - (match_operand:SI 2 "general_operand" "")))] - "" - "m68hc11_emit_libcall (\"__mulsi3\", MULT, SImode, SImode, 3, operands); - DONE;") - -(define_expand "mulhi3" - [(parallel [(set (match_operand:HI 0 "register_operand" "") - (mult:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "register_operand" ""))) - (clobber (match_scratch:HI 3 ""))])] - "" - "") - -(define_insn "mulhi3_m68hc11" - [(set (match_operand:HI 0 "register_operand" "=d") - (mult:HI (match_operand:HI 1 "register_operand" "%0") - (match_operand:HI 2 "register_operand" "x"))) - (clobber (match_scratch:HI 3 "=X"))] - "TARGET_M6811" - "* -{ - CC_STATUS_INIT; - /* D * X -> D (X and Y are preserved by this function call). */ - return \"jsr\\t___mulhi3\"; -}") - -(define_insn "mulhi3_m68hc12" - [(set (match_operand:HI 0 "register_operand" "=d,d") - (mult:HI (match_operand:HI 1 "register_operand" "%0,0") - (match_operand:HI 2 "register_operand" "y,x"))) - (clobber (match_scratch:HI 3 "=2,2"))] - "TARGET_M6812" - "* -{ - CC_STATUS_INIT; - if (X_REG_P (operands[2])) - return \"exg\\tx,y\\n\\temul\\n\\texg\\tx,y\"; - else - return \"emul\"; -}") - -(define_insn "umulhisi3" - [(set (match_operand:SI 0 "register_operand" "=D,D") - (mult:SI (zero_extend:SI - (match_operand:HI 1 "register_operand" "%d,d")) - (zero_extend:SI - (match_operand:HI 2 "register_operand" "y,x")))) - (clobber (match_scratch:HI 3 "=2,X"))] - "TARGET_M6812" - "* -{ - if (X_REG_P (operands [2])) - output_asm_insn (\"exg\\tx,y\", operands); - - /* Can't use the carry after that; other flags are ok when testing - the 32-bit result. */ - cc_status.flags |= CC_NO_OVERFLOW; - return \"emul\\n\\texg\\tx,y\"; -}") - -(define_insn "mulhisi3" - [(set (match_operand:SI 0 "register_operand" "=D,D") - (mult:SI (sign_extend:SI - (match_operand:HI 1 "register_operand" "%d,d")) - (sign_extend:SI - (match_operand:HI 2 "register_operand" "y,x")))) - (clobber (match_scratch:HI 3 "=2,X"))] - "TARGET_M6812" - "* -{ - if (X_REG_P (operands [2])) - output_asm_insn (\"exg\\tx,y\", operands); - - /* Can't use the carry after that; other flags are ok when testing - the 32-bit result. */ - cc_status.flags |= CC_NO_OVERFLOW; - return \"emuls\\n\\texg\\tx,y\"; -}") - -(define_insn "umulqihi3" - [(set (match_operand:HI 0 "register_operand" "=d") - (mult:HI (zero_extend:HI - (match_operand:QI 1 "nonimmediate_operand" "dm*u")) - (zero_extend:HI - (match_operand:QI 2 "nonimmediate_operand" "dm*u*A"))))] - "" - "* -{ - if (D_REG_P (operands[1]) && D_REG_P (operands[2])) - { - output_asm_insn (\"tba\", operands); - } - else - { - rtx ops[2]; - - if (D_REG_P (operands[2])) - { - rtx temp = operands[2]; - operands[2] = operands[1]; - operands[1] = temp; - } - - ops[0] = gen_rtx_REG (QImode, HARD_A_REGNUM); - ops[1] = operands[2]; - m68hc11_gen_movqi (insn, ops); - - if (!D_REG_P (operands[1])) - { - output_asm_insn (\"ldab\\t%b1\", operands); - } - } - - CC_STATUS_INIT; - return \"mul\"; -}") - -(define_insn "mulqi3" - [(set (match_operand:QI 0 "register_operand" "=d,*x,*y") - (mult:QI (match_operand:QI 1 "general_operand" "%di*um,0,0") - (match_operand:QI 2 "general_operand" "di*um,*xium,*yium")))] - "" - "* -{ - if (A_REG_P (operands[0])) - return \"#\"; - - if (D_REG_P (operands[1]) && D_REG_P (operands[2])) - { - output_asm_insn (\"tba\", operands); - } - else - { - if (D_REG_P (operands[2])) - { - rtx temp = operands[2]; - operands[2] = operands[1]; - operands[1] = temp; - } - - output_asm_insn (\"ldaa\\t%b2\", operands); - - if (!D_REG_P (operands[1])) - { - output_asm_insn (\"ldab\\t%b1\", operands); - } - } - - CC_STATUS_INIT; - return \"mul\"; -}") - -(define_split - [(set (match_operand:QI 0 "hard_addr_reg_operand" "") - (mult:QI (match_operand:QI 1 "general_operand" "") - (match_operand:QI 2 "general_operand" "")))] - "z_replacement_completed == 2" - [(parallel [(set (reg:HI D_REGNUM) (match_dup 3)) - (set (match_dup 3) (reg:HI D_REGNUM))]) - (set (reg:QI D_REGNUM) (mult:QI (match_dup 5) (match_dup 6))) - (parallel [(set (reg:HI D_REGNUM) (match_dup 3)) - (set (match_dup 3) (reg:HI D_REGNUM))])] - " - operands[3] = gen_rtx_REG (HImode, REGNO (operands[0])); - if (A_REG_P (operands[1])) - operands[5] = gen_rtx_REG (QImode, HARD_D_REGNUM); - else - operands[5] = operands[1]; - if (A_REG_P (operands[2])) - operands[6] = gen_rtx_REG (QImode, HARD_D_REGNUM); - else - operands[6] = operands[2]; - ") - -(define_insn "mulqihi3" - [(set (match_operand:HI 0 "register_operand" "=d,d,d") - (mult:HI (sign_extend:HI - (match_operand:QI 1 "register_operand" "%0,0,0")) - (sign_extend:HI - (match_operand:QI 2 "general_operand" "mi*u,*A,0"))))] - "" - "* -{ - CC_STATUS_INIT; - - /* Special case when multiplying the register with itself. */ - if (D_REG_P (operands[2])) - { - output_asm_insn (\"tba\", operands); - return \"mul\"; - } - - if (!H_REG_P (operands[2])) - { - output_asm_insn (\"ldaa\\t%b2\", operands); - } - else - { - rtx ops[2]; - - ops[0] = gen_rtx_REG (QImode, HARD_A_REGNUM); - ops[1] = operands[2]; - m68hc11_gen_movqi (insn, ops); - } - return \"jsr\\t___mulqi3\"; -}") - -;;-------------------------------------------------------------------- -;;- Divide instructions. -;;-------------------------------------------------------------------- - -(define_insn "divmodhi4" - [(set (match_operand:HI 0 "register_operand" "=d,d") - (div:HI (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "general_operand" "A,ium"))) - (set (match_operand:HI 3 "register_operand" "=&x,&x") - (mod:HI (match_dup 1) (match_dup 2)))] - "" - "* -{ - if (!X_REG_P (operands[2])) - { - if (Y_REG_P (operands[2])) - { - output_asm_insn (\"sty\\t%t1\", operands); - output_asm_insn (\"ldx\\t%t1\", operands); - } - else - { - output_asm_insn (\"ldx\\t%2\", operands); - } - } - if (TARGET_M6812) - { - /* Flags are ok after that. */ - return \"idivs\\n\\txgdx\"; - } - else - { - CC_STATUS_INIT; - return \"bsr\\t__divmodhi4\"; - } -}") - -(define_insn "udivmodhi4" - [(set (match_operand:HI 0 "register_operand" "=d,d") - (udiv:HI (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "general_operand" "A,ium"))) - (set (match_operand:HI 3 "register_operand" "=x,x") - (umod:HI (match_dup 1) (match_dup 2)))] - "" - "* -{ - if (!X_REG_P (operands[2])) - { - if (Y_REG_P (operands[2])) - { - output_asm_insn (\"sty\\t%t1\", operands); - output_asm_insn (\"ldx\\t%t1\", operands); - } - else - { - output_asm_insn (\"ldx\\t%2\", operands); - } - } - - /* Z V and C flags are set but N is unchanged. - Since this is an unsigned divide, we can probably keep the flags - and indicate this. */ - cc_status.flags |= CC_NOT_NEGATIVE; - return \"idiv\\n\\txgdx\"; -}") - -;;-------------------------------------------------------------------- -;;- and instructions. -;;-------------------------------------------------------------------- - -(define_insn_and_split "anddi3" - [(set (match_operand:DI 0 "reg_or_some_mem_operand" "=m,u") - (and:DI (match_operand:DI 1 "reg_or_some_mem_operand" "%imu,imu") - (match_operand:DI 2 "general_operand" "imu,imu"))) - (clobber (match_scratch:HI 3 "=d,d"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_logical (SImode, AND, operands); - DONE;") - -(define_insn_and_split "andsi3" - [(set (match_operand:SI 0 "register_operand" "=D,!u") - (and:SI (match_operand:SI 1 "register_operand" "%0,0") - (match_operand:SI 2 "general_operand" "Dimu,imu"))) - (clobber (match_scratch:HI 3 "=X,d"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_logical (HImode, AND, operands); - DONE;") - -(define_expand "andhi3" - [(set (match_operand:HI 0 "register_operand" "") - (and:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" "")))] - "" - "") - -(define_insn "*andhi3_mem" - [(set (match_operand:HI 0 "memory_operand" "=R,Q") - (and:HI (match_dup 0) - (match_operand:HI 1 "immediate_operand" "i,i"))) - (clobber (match_scratch:HI 2 "=X,xy"))] - "TARGET_RELAX && !TARGET_M6812" - "* -{ - int val = INTVAL (operands[1]) & 0x0FFFF; - - if (val == 0x0ffff) - { - cc_status = cc_prev_status; - return \"\"; - } - - CC_STATUS_INIT; - - /* The bclr instruction uses an inverted mask. */ - operands[1] = GEN_INT ((~val) & 0x0FFFF); - - /* When destination is a global variable, generate a .relax instruction - and load the address in the clobber register. That load can be - eliminated by the linker if the address is in page0. */ - if (which_alternative == 1) - { - rtx ops[3]; - - ops[0] = operands[2]; - ops[1] = XEXP (operands[0], 0); - ops[2] = gen_label_rtx (); - output_asm_insn (\".relax\\t%l2\", ops); - m68hc11_gen_movhi (insn, ops); - if ((val & 0x0FF) != 0x0FF) - output_asm_insn (\"bclr\\t1,%2, %b1\", operands); - - if ((val & 0x0FF00) != 0x0FF00) - output_asm_insn (\"bclr\\t0,%2, %h1\", operands); - - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (ops[2])); - return \"\"; - } - - if ((val & 0x0FF) != 0x0FF) - output_asm_insn (\"bclr\\t%b0, %b1\", operands); - - if ((val & 0x0FF00) != 0x0FF00) - output_asm_insn (\"bclr\\t%h0, %h1\", operands); - - return \"\"; -}") - -(define_insn "*andhi3_const" - [(set (match_operand:HI 0 "reg_or_some_mem_operand" "=R,d,?*A") - (and:HI (match_operand:HI 1 "reg_or_some_mem_operand" "%0,0,0") - (match_operand:HI 2 "const_int_operand" "")))] - "" - "* -{ - int val = INTVAL (operands[2]) & 0x0FFFF; - int lowpart_zero = 0; - int highpart_zero = 0; - int lowpart_unknown = 0; - int highpart_unknown = 0; - - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - - if (val == 0x0ffff) - { - cc_status = cc_prev_status; - return \"\"; - } - - /* First, try to clear the low and high part. - If that's possible, the second 'and' will give - the good status flags and we can avoid a tsthi. */ - if ((val & 0x0FF) == 0) - { - if (D_REG_P (operands[0])) - output_asm_insn (\"clrb\", operands); - else - output_asm_insn (\"clr\\t%b0\", operands); - lowpart_zero = 1; - } - if ((val & 0x0FF00) == 0) - { - if (D_REG_P (operands[0])) - output_asm_insn (\"clra\", operands); - else - output_asm_insn (\"clr\\t%h0\", operands); - highpart_zero = 1; - } - - if ((val & 0x0FF) == 0x0FF) - { - lowpart_unknown = 1; - } - else if ((val & 0x0FF) != 0 && !H_REG_P (operands[0])) - { - rtx ops[2]; - - ops[0] = operands[0]; - ops[1] = GEN_INT ((~val) & 0x0FF); - output_asm_insn (\"bclr\\t%b0, %1\", ops); - } - else if ((val & 0x0FF) != 0) - { - output_asm_insn (\"andb\\t%b2\", operands); - } - - if ((val & 0x0FF00) == 0x0FF00) - { - highpart_unknown = 1; - } - else if (((val & 0x0FF00) != 0) && !H_REG_P (operands[0])) - { - rtx ops[2]; - - ops[0] = operands[0]; - ops[1] = GEN_INT (((~val) & 0x0FF00) >> 8); - output_asm_insn (\"bclr\\t%h0, %1\", ops); - } - else if ((val & 0x0FF00) != 0) - { - output_asm_insn (\"anda\\t%h2\", operands); - } - - if (highpart_unknown || lowpart_unknown) - CC_STATUS_INIT; - else if (highpart_zero == 0 && lowpart_zero == 0) - CC_STATUS_INIT; - - return \"\"; -}") - -(define_insn "*andhi3_gen" - [(set (match_operand:HI 0 "register_operand" "=d,d,!*A") - (and:HI (match_operand:HI 1 "splitable_operand" "%0,0,0") - (match_operand:HI 2 "splitable_operand" "mi,!u*A,!um*Ai")))] - "" - "* -{ - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - - CC_STATUS_INIT; - return \"anda\\t%h2\\n\\tandb\\t%b2\"; -}") - -(define_expand "andqi3" - [(set (match_operand:QI 0 "register_operand" "") - (and:QI (match_operand:QI 1 "register_operand" "") - (match_operand:QI 2 "general_operand" "")))] - "" - "") - -(define_insn "*andqi3_mem" - [(set (match_operand:QI 0 "memory_operand" "=R,Q") - (and:QI (match_dup 0) - (match_operand:QI 1 "const_int_operand" "i,i"))) - (clobber (match_scratch:HI 2 "=X,xy"))] - "TARGET_RELAX && !TARGET_M6812" - "* -{ - int val = INTVAL (operands[1]) & 0x0FF; - - if (val == 0x0ff) - { - cc_status = cc_prev_status; - return \"\"; - } - - /* The bclr instruction uses an inverted mask. */ - operands[1] = GEN_INT ((~val) & 0x0FF); - - /* When destination is a global variable, generate a .relax instruction - and load the address in the clobber register. That load can be - eliminated by the linker if the address is in page0. */ - if (which_alternative == 1) - { - rtx ops[3]; - - ops[0] = operands[2]; - ops[1] = XEXP (operands[0], 0); - ops[2] = gen_label_rtx (); - output_asm_insn (\".relax\\t%l2\", ops); - m68hc11_gen_movhi (insn, ops); - output_asm_insn (\"bclr\\t0,%2, %1\", operands); - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (ops[2])); - return \"\"; - } - return \"bclr\\t%b0, %1\"; -}") - -(define_insn "*andqi3_const" - [(set (match_operand:QI 0 "reg_or_some_mem_operand" "=R,d,?*A*q") - (and:QI (match_operand:QI 1 "reg_or_some_mem_operand" "%0,0,0") - (match_operand:QI 2 "const_int_operand" "")))] - "" - "* -{ - int val = INTVAL (operands[2]) & 0x0FF; - - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - - if (val == 0x0ff) - { - cc_status = cc_prev_status; - return \"\"; - } - if (!H_REG_P (operands[0])) - { - rtx ops[2]; - - ops[0] = operands[0]; - ops[1] = GEN_INT ((~val) & 0x0FF); - output_asm_insn (\"bclr\\t%b0, %b1\", ops); - return \"\"; - } - if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - return \"andb\\t%b2\"; - else if (DA_REG_P (operands[0])) - return \"anda\\t%b2\"; - else - fatal_insn (\"Invalid operand in the instruction\", insn); -}") - -(define_insn "*andqi3_gen" - [(set (match_operand:QI 0 "register_operand" "=d,d,d,?*A,?*A,!*q") - (and:QI (match_operand:QI 1 "general_operand" "%0,0,0,0,0,0") - (match_operand:QI 2 "general_operand" "mi,!*u,?*A,!*um,?*A*d,!*um*A")))] - "" - "* -{ - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - - if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - return \"andb\\t%b2\"; - else if (DA_REG_P (operands[0])) - return \"anda\\t%b2\"; - else - fatal_insn (\"Invalid operand in the instruction\", insn); -}") - -;;-------------------------------------------------------------------- -;;- Bit set or instructions. -;;-------------------------------------------------------------------- - -(define_insn_and_split "iordi3" - [(set (match_operand:DI 0 "reg_or_some_mem_operand" "=m,u") - (ior:DI (match_operand:DI 1 "reg_or_some_mem_operand" "%imu,imu") - (match_operand:DI 2 "general_operand" "imu,imu"))) - (clobber (match_scratch:HI 3 "=d,d"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_logical (SImode, IOR, operands); - DONE;") - -(define_insn_and_split "iorsi3" - [(set (match_operand:SI 0 "register_operand" "=D,!u") - (ior:SI (match_operand:SI 1 "register_operand" "%0,0") - (match_operand:SI 2 "general_operand" "Dimu,imu"))) - (clobber (match_scratch:HI 3 "=X,d"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_logical (HImode, IOR, operands); - DONE;") - -(define_expand "iorhi3" - [(set (match_operand:HI 0 "register_operand" "") - (ior:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "splitable_operand" "")))] - "" - "") - -(define_insn "*iorhi3_mem" - [(set (match_operand:HI 0 "memory_operand" "=R,Q") - (ior:HI (match_dup 0) - (match_operand:HI 1 "const_int_operand" ""))) - (clobber (match_scratch:HI 2 "=X,xy"))] - "TARGET_RELAX && !TARGET_M6812" - "* -{ - int val = INTVAL (operands[1]) & 0x0FFFF; - - if (val == 0) - { - cc_status = cc_prev_status; - return \"\"; - } - CC_STATUS_INIT; - if (which_alternative == 1) - { - rtx ops[3]; - - ops[0] = operands[2]; - ops[1] = XEXP (operands[0], 0); - ops[2] = gen_label_rtx (); - output_asm_insn (\".relax\\t%l2\", ops); - m68hc11_gen_movhi (insn, ops); - if ((val & 0x0FF) != 0) - output_asm_insn (\"bset\\t1,%2, %b1\", operands); - - if ((val & 0x0FF00) != 0) - output_asm_insn (\"bset\\t0,%2, %h1\", operands); - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (ops[2])); - return \"\"; - } - - if ((val & 0x0FF) != 0) - output_asm_insn (\"bset\\t%b0, %b1\", operands); - - if ((val & 0x0FF00) != 0) - output_asm_insn (\"bset\\t%h0, %h1\", operands); - - return \"\"; -}") - -(define_insn "*iorhi3_const" - [(set (match_operand:HI 0 "reg_or_some_mem_operand" "=R,d,?*A") - (ior:HI (match_operand:HI 1 "reg_or_some_mem_operand" "%0,0,0") - (match_operand:HI 2 "const_int_operand" "")))] - "" - "* -{ - int val = INTVAL (operands[2]) & 0x0FFFF; - - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - - if (val == 0) - { - cc_status = cc_prev_status; - return \"\"; - } - - if ((val & 0x0FF) != 0) - { - if (!H_REG_P (operands[0])) - output_asm_insn (\"bset\\t%b0, %b2\", operands); - else - output_asm_insn (\"orab\\t%b2\", operands); - } - - if ((val & 0x0FF00) != 0) - { - if (!H_REG_P (operands[0])) - output_asm_insn (\"bset\\t%h0, %h2\", operands); - else - output_asm_insn (\"oraa\\t%h2\", operands); - } - - CC_STATUS_INIT; - return \"\"; -}") - -(define_insn "*iorhi3_gen" - [(set (match_operand:HI 0 "register_operand" "=d,d,!*A") - (ior:HI (match_operand:HI 1 "splitable_operand" "%0,0,0") - (match_operand:HI 2 "splitable_operand" "mi,!u*A,!um*Ai")))] - "" - "* -{ - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - - CC_STATUS_INIT; - return \"oraa\\t%h2\\n\\torab\\t%b2\"; -}") - -(define_expand "iorqi3" - [(set (match_operand:QI 0 "register_operand" "") - (ior:QI (match_operand:QI 1 "register_operand" "") - (match_operand:QI 2 "general_operand" "")))] - "" - "") - -(define_insn "*iorqi3_mem" - [(set (match_operand:QI 0 "memory_operand" "=R,Q") - (ior:QI (match_dup 0) - (match_operand:QI 1 "const_int_operand" ""))) - (clobber (match_scratch:HI 2 "=X,xy"))] - "TARGET_RELAX && !TARGET_M6812" - "* -{ - int val = INTVAL (operands[1]) & 0x0FF; - - if (val == 0) - { - cc_status = cc_prev_status; - return \"\"; - } - if (which_alternative == 1) - { - rtx ops[3]; - - ops[0] = operands[2]; - ops[1] = XEXP (operands[0], 0); - ops[2] = gen_label_rtx (); - output_asm_insn (\".relax\\t%l2\", ops); - m68hc11_gen_movhi (insn, ops); - output_asm_insn (\"bset\\t0,%2, %1\", operands); - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (ops[2])); - return \"\"; - } - return \"bset\\t%b0, %1\"; -}") - -(define_insn "*iorqi3_const" - [(set (match_operand:QI 0 "reg_or_some_mem_operand" "=R,d,?*A*q") - (ior:QI (match_operand:QI 1 "reg_or_some_mem_operand" "%0,0,0") - (match_operand:QI 2 "const_int_operand" "")))] - "" - "* -{ - int val = INTVAL (operands[2]) & 0x0FF; - - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - - if (val == 0) - { - cc_status = cc_prev_status; - return \"\"; - } - if (!H_REG_P (operands[0])) - { - return \"bset\\t%b0, %2\"; - } - - if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - return \"orab\\t%b2\"; - else if (DA_REG_P (operands[0])) - return \"oraa\\t%b2\"; - else - fatal_insn (\"Invalid operand in the instruction\", insn); -}") - -(define_insn "*iorqi3_gen" - [(set (match_operand:QI 0 "register_operand" "=d,d,d,?*A,?*A,!*q") - (ior:QI (match_operand:QI 1 "general_operand" "%0,0,0,0,0,0") - (match_operand:QI 2 "general_operand" "mi,!*u,!*A,!*um,?*A*d,!*um*A")))] - "" - "* -{ - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - - if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - return \"orab\\t%b2\"; - else if (DA_REG_P (operands[0])) - return \"oraa\\t%b2\"; - else - fatal_insn (\"Invalid operand in the instruction\", insn); -}") - - -;;-------------------------------------------------------------------- -;;- xor instructions. -;;-------------------------------------------------------------------- - -(define_insn_and_split "xordi3" - [(set (match_operand:DI 0 "reg_or_some_mem_operand" "=m,u") - (xor:DI (match_operand:DI 1 "reg_or_some_mem_operand" "%imu,imu") - (match_operand:DI 2 "general_operand" "imu,imu"))) - (clobber (match_scratch:HI 3 "=d,d"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_logical (SImode, XOR, operands); - DONE;") - -(define_insn_and_split "xorsi3" - [(set (match_operand:SI 0 "register_operand" "=D,!u") - (xor:SI (match_operand:SI 1 "register_operand" "%0,0") - (match_operand:SI 2 "general_operand" "Dimu,imu"))) - (clobber (match_scratch:HI 3 "=X,d"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_logical (HImode, XOR, operands); - DONE;") - -(define_insn "xorhi3" - [(set (match_operand:HI 0 "register_operand" "=d,d,!*A") - (xor:HI (match_operand:HI 1 "splitable_operand" "%0,0,0") - (match_operand:HI 2 "splitable_operand" "im,!u*A,!ium*A")))] - "" - "* -{ - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - - if (GET_CODE (operands[2]) == CONST_INT) - { - int val = INTVAL (operands[2]) & 0x0FFFF; - - if (val == 0) - { - cc_status = cc_prev_status; - return \"\"; - } - if ((val & 0x0FF) != 0) - { - output_asm_insn (\"eorb\\t%b2\", operands); - } - else if ((val & 0x0FF) == 0x0FF) - { - output_asm_insn (\"comb\", operands); - } - - if ((val & 0x0FF00) != 0) - { - output_asm_insn (\"eora\\t%h2\", operands); - } - else if ((val & 0x0FF00) == 0x0FF00) - { - output_asm_insn (\"coma\", operands); - } - - CC_STATUS_INIT; - return \"\"; - } - - CC_STATUS_INIT; - return \"eora\\t%h2\\n\\teorb\\t%b2\"; -}") - -(define_insn "xorqi3" - [(set (match_operand:QI 0 "register_operand" "=d,d,d,?*A,?*A,!*q") - (xor:QI (match_operand:QI 1 "general_operand" "%0,0,0,0,0,0") - (match_operand:QI 2 "general_operand" "im,!*u,!*A,!i*um,?*A*d,!i*um*A")))] - "" - "* -{ - if (A_REG_P (operands[0]) || H_REG_P (operands[2])) - return \"#\"; - - if (GET_CODE (operands[2]) == CONST_INT) - { - int val = INTVAL (operands[2]) & 0x0FF; - - if (val == 0) - { - cc_status = cc_prev_status; - return \"\"; - } - if (val == 0x0FF) - { - if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - return \"comb\"; - else - return \"coma\"; - } - } - if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - return \"eorb\\t%b2\"; - else if (DA_REG_P (operands[0])) - return \"eora\\t%b2\"; - else - fatal_insn (\"Invalid operand in the instruction\", insn); -}") - -;;-------------------------------------------------------------------- -;;- Bit set or instructions. -;;-------------------------------------------------------------------- - -(define_insn_and_split "*logicalsi3_zexthi" - [(set (match_operand:SI 0 "register_operand" "=D") - (match_operator:SI 3 "m68hc11_logical_operator" - [(zero_extend:SI - (match_operand:HI 1 "general_operand" "imudA")) - (match_operand:SI 2 "general_operand" "Dimu")]))] - "" - "#" - "reload_completed" - [(set (reg:HI D_REGNUM) (match_dup 4)) - (set (reg:HI D_REGNUM) (match_op_dup 3 [(reg:HI D_REGNUM) (match_dup 5)])) - (set (reg:HI X_REGNUM) (match_dup 6))] - "PUT_MODE (operands[3], HImode); - if (X_REG_P (operands[2])) - { - operands[5] = operands[1]; - /* Make all the (set (REG:x) (REG:y)) a nop set. */ - operands[4] = gen_rtx_REG (HImode, HARD_D_REGNUM); - operands[6] = gen_rtx_REG (HImode, HARD_X_REGNUM); - } - else - { - operands[4] = operands[1]; - operands[5] = m68hc11_gen_lowpart (HImode, operands[2]); - operands[6] = m68hc11_gen_highpart (HImode, operands[2]); - } - /* For an AND, make sure the high 16-bit part is cleared. */ - if (GET_CODE (operands[3]) == AND) - { - operands[6] = const0_rtx; - } - ") - -(define_insn_and_split "*logicalsi3_zextqi" - [(set (match_operand:SI 0 "register_operand" "=D,D,D") - (match_operator:SI 3 "m68hc11_logical_operator" - [(zero_extend:SI - (match_operand:QI 1 "general_operand" "d,*A,imu")) - (match_operand:SI 2 "general_operand" "imu,imu,0")]))] - "" - "#" - "z_replacement_completed == 2" - [(set (reg:QI A_REGNUM) (match_dup 4)) - (set (reg:QI D_REGNUM) (match_dup 7)) - (set (reg:QI B_REGNUM) (match_op_dup 3 [(reg:QI B_REGNUM) (match_dup 5)])) - (set (reg:HI X_REGNUM) (match_dup 6))] - "PUT_MODE (operands[3], QImode); - if (X_REG_P (operands[2])) - { - operands[5] = operands[1]; - /* Make all the (set (REG:x) (REG:y)) a nop set. */ - operands[4] = gen_rtx_REG (QImode, HARD_A_REGNUM); - operands[7] = gen_rtx_REG (QImode, HARD_D_REGNUM); - operands[6] = gen_rtx_REG (HImode, HARD_X_REGNUM); - } - else - { - operands[4] = m68hc11_gen_lowpart (HImode, operands[2]); - operands[7] = operands[1]; - operands[5] = m68hc11_gen_lowpart (QImode, operands[4]); - operands[4] = m68hc11_gen_highpart (QImode, operands[4]); - operands[6] = m68hc11_gen_highpart (HImode, operands[2]); - } - /* For an AND, make sure the high 24-bit part is cleared. */ - if (GET_CODE (operands[3]) == AND) - { - operands[4] = const0_rtx; - operands[6] = const0_rtx; - } - ") - -(define_insn_and_split "*logicalhi3_zexthi_ashift8" - [(set (match_operand:HI 0 "register_operand" "=d") - (match_operator:HI 3 "m68hc11_logical_operator" - [(zero_extend:HI - (match_operand:QI 1 "general_operand" "imud*A")) - (ashift:HI - (match_operand:HI 2 "general_operand" "imud*A") - (const_int 8))]))] - "" - "#" - "z_replacement_completed == 2" - [(set (reg:QI A_REGNUM) (match_dup 4)) - (set (reg:QI B_REGNUM) (match_dup 5))] - " - if (GET_CODE (operands[3]) == AND) - { - emit_insn (gen_movhi (operands[0], const0_rtx)); - DONE; - } - else - { - operands[5] = operands[1]; - if (D_REG_P (operands[2])) - { - operands[4] = gen_rtx_REG (QImode, HARD_B_REGNUM); - } - else - { - operands[4] = m68hc11_gen_lowpart (QImode, operands[2]); - } - } - ") - -(define_insn_and_split "*logicalhi3_zexthi" - [(set (match_operand:HI 0 "register_operand" "=d,d") - (match_operator:HI 3 "m68hc11_logical_operator" - [(zero_extend:HI - (match_operand:QI 1 "general_operand" "imd*A,?u")) - (match_operand:HI 2 "general_operand" "dim,?dimu")]))] - "" - "#" - "z_replacement_completed == 2" - [(set (reg:QI B_REGNUM) (match_dup 6)) - (set (reg:QI A_REGNUM) (match_dup 4)) - (set (reg:QI B_REGNUM) (match_op_dup 3 [(reg:QI B_REGNUM) (match_dup 5)]))] - " - PUT_MODE (operands[3], QImode); - if (D_REG_P (operands[2])) - { - operands[4] = gen_rtx_REG (QImode, HARD_A_REGNUM); - operands[5] = operands[1]; - operands[6] = gen_rtx_REG (QImode, HARD_B_REGNUM); - } - else - { - operands[4] = m68hc11_gen_highpart (QImode, operands[2]); - operands[5] = m68hc11_gen_lowpart (QImode, operands[2]); - if (D_REG_P (operands[1])) - operands[6] = gen_rtx_REG (QImode, HARD_B_REGNUM); - else - operands[6] = operands[1]; - } - /* For an AND, make sure the high 8-bit part is cleared. */ - if (GET_CODE (operands[3]) == AND) - { - operands[4] = const0_rtx; - } - ") - - -(define_insn_and_split "*logicalsi3_silshr16" - [(set (match_operand:SI 0 "register_operand" "=D,D,D,?D") - (match_operator:SI 3 "m68hc11_logical_operator" - [(lshiftrt:SI - (match_operand:SI 1 "general_operand" "uim,uim,0,0") - (const_int 16)) - (match_operand:SI 2 "general_operand" "uim,0,uim,0")]))] - "" - "#" - "reload_completed" - [(set (reg:HI D_REGNUM) (match_dup 4)) - (set (reg:HI D_REGNUM) (match_op_dup 3 [(reg:HI D_REGNUM) (match_dup 5)])) - (set (reg:HI X_REGNUM) (match_dup 6))] - "operands[5] = m68hc11_gen_highpart (HImode, operands[1]); - if (X_REG_P (operands[2])) - { - operands[4] = gen_rtx_REG (HImode, HARD_D_REGNUM); - operands[6] = gen_rtx_REG (HImode, HARD_X_REGNUM); - } - else - { - operands[4] = m68hc11_gen_lowpart (HImode, operands[2]); - operands[6] = m68hc11_gen_highpart (HImode, operands[2]); - } - PUT_MODE (operands[3], HImode); - - /* For an AND, make sure the high 16-bit part is cleared. */ - if (GET_CODE (operands[3]) == AND) - { - operands[6] = const0_rtx; - } -") - -(define_insn_and_split "*logicalsi3_silshl16" - [(set (match_operand:SI 0 "register_operand" "=D,D") - (match_operator:SI 3 "m68hc11_logical_operator" - [(ashift:SI - (match_operand:SI 1 "general_operand" "uim,?D") - (const_int 16)) - (match_operand:SI 2 "general_operand" "0,0")]))] - "" - "#" - "z_replacement_completed == 2" - [(set (reg:HI X_REGNUM) (match_op_dup 3 [(reg:HI X_REGNUM) (match_dup 4)])) - (set (reg:HI D_REGNUM) (match_dup 5))] - "operands[4] = m68hc11_gen_lowpart (HImode, operands[1]); - PUT_MODE (operands[3], HImode); - - if (GET_CODE (operands[3]) == AND) - operands[5] = const0_rtx; - else - operands[5] = gen_rtx_REG (HImode, HARD_D_REGNUM); - ") - -(define_insn_and_split "*logicalsi3_silshl16_zext" - [(set (match_operand:SI 0 "register_operand" "=D,D,D") - (match_operator:SI 3 "m68hc11_logical_operator" - [(ashift:SI - (zero_extend:SI - (match_operand:HI 1 "general_operand" "uim,udA,!dA")) - (const_int 16)) - (zero_extend:SI (match_operand:HI 2 "general_operand" "uidA,um,!dA"))]))] - "" - "#" - ;; Must split before z register replacement - "reload_completed" - [(set (match_dup 4) (match_dup 5)) - (set (match_dup 6) (match_dup 7))] - " - /* set (X_REGNUM) (d), set (D_REGNUM) (1) */ - if (GET_CODE (operands[1]) == HARD_D_REGNUM - && GET_CODE (operands[3]) != AND) - { - /* This particular case is too early to be split before - Z register replacement because the cse-reg pass we do - does not recognize the 'swap_areg'. It is ok to handle - this case after. */ - if (z_replacement_completed != 2) - { - FAIL; - } - emit_move_insn (gen_rtx_REG (HImode, HARD_X_REGNUM), operands[2]); - emit_insn (gen_swap_areg (gen_rtx_REG (HImode, HARD_D_REGNUM), - gen_rtx_REG (HImode, HARD_X_REGNUM))); - } - operands[4] = gen_rtx_REG (HImode, HARD_D_REGNUM); - operands[6] = gen_rtx_REG (HImode, HARD_X_REGNUM); - operands[5] = operands[2]; - operands[7] = operands[1]; - - if (GET_CODE (operands[3]) == AND) - operands[5] = operands[7] = const0_rtx; - ") - -;;-------------------------------------------------------------------- -;; 16-bit Arithmetic and logical operations on X and Y: -;; -;; PLUS MINUS AND IOR XOR ASHIFT ASHIFTRT LSHIFTRT ROTATE ROTATERT -;; -;; Operations on X or Y registers are split here. Instructions are -;; changed into: -;; - xgdx/xgdy instruction pattern, -;; - The same operation on register D, -;; - xgdx/xgdy instruction pattern. -;; This should allow the peephole to merge consecutive xgdx/xgdy instructions. -;; We also handle the case were the address register is used in both source -;; operands, such as: -;; -;; (set (REG:HI X) (PLUS:HI (REG:HI X) (mem:HI (REG:HI X)))) -;; or -;; (set (REG:HI X) (PLUS:HI (REG:HI X) (REG:HI X))) -;; -;; -(define_split - [(set (match_operand:HI 0 "hard_addr_reg_operand" "") - (match_operator:HI 3 "m68hc11_arith_operator" - [(match_operand:HI 1 "hard_addr_reg_operand" "") - (match_operand:HI 2 "general_operand" "")]))] - "z_replacement_completed == 2 - /* If we are adding a small constant to X or Y, it's - better to use one or several inx/iny instructions. */ - && !(GET_CODE (operands[3]) == PLUS - && ((TARGET_M6812 - && (immediate_operand (operands[2], HImode) - || hard_reg_operand (operands[2], HImode))) - || (GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) >= -4 - && INTVAL (operands[2]) <= 4)))" - [(set (match_dup 9) (match_dup 0)) - (set (match_dup 4) (match_dup 5)) - (set (match_dup 8) (match_dup 7)) - (set (match_dup 0) (match_dup 1)) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))]) - (set (reg:HI D_REGNUM) (match_op_dup 3 [(reg:HI D_REGNUM) (match_dup 6)])) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))])] - " - operands[9] = operands[0]; - /* For 68HC12, push the value on the stack and do the operation - with a pop. */ - if (TARGET_M6812 - && m68hc11_non_shift_operator (operands[3], HImode) - && (H_REG_P (operands[2]) - || (m68hc11_small_indexed_indirect_p (operands[2], HImode) - && reg_mentioned_p (operands[0], operands[2])))) - { - operands[4] = gen_rtx_MEM (HImode, - gen_rtx_PRE_DEC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM))); - operands[6] = gen_rtx_MEM (HImode, - gen_rtx_POST_INC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM))); - operands[5] = operands[2]; - operands[8] = operands[7] = operands[0]; - } - /* Save the operand2 in a temporary location and use it. */ - else if ((H_REG_P (operands[2]) - || reg_mentioned_p (operands[0], operands[2])) - && !(SP_REG_P (operands[2]) && GET_CODE (operands[3]) == PLUS)) - { - if (GET_CODE (operands[3]) == MINUS - && reg_mentioned_p (operands[0], operands[2])) - { - operands[9] = gen_rtx_MEM (HImode, - gen_rtx_PRE_DEC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM))); - operands[1] = gen_rtx_MEM (HImode, - gen_rtx_POST_INC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM))); - operands[8] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); - operands[4] = operands[7] = operands[0]; - operands[6] = operands[8]; - operands[5] = operands[2]; - } - else - { - operands[4] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); - operands[6] = operands[4]; - if (!H_REG_P (operands[2])) - { - operands[5] = operands[0]; - operands[7] = operands[2]; - operands[8] = operands[0]; - } - else - { - operands[5] = operands[2]; - operands[8] = operands[7] = operands[0]; - } - } - } - else - { - operands[4] = operands[5] = operands[0]; - operands[6] = operands[2]; - operands[8] = operands[7] = operands[0]; - } - ") - -(define_split - [(set (match_operand:HI 0 "hard_addr_reg_operand" "") - (match_operator:HI 3 "m68hc11_arith_operator" - [(match_operand:HI 1 "general_operand" "") - (match_operand:HI 2 "general_operand" "")]))] - "z_replacement_completed == 2 - /* If we are adding a small constant to X or Y, it's - better to use one or several inx/iny instructions. */ - && !(GET_CODE (operands[3]) == PLUS - && ((TARGET_M6812 - && (immediate_operand (operands[2], HImode) - || hard_reg_operand (operands[2], HImode))) - || (GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) >= -4 - && INTVAL (operands[2]) <= 4)))" - [(set (match_dup 0) (match_dup 1)) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))]) - (set (reg:HI D_REGNUM) (match_op_dup 3 [(reg:HI D_REGNUM) (match_dup 2)])) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))])] - " - ") - -;; -;; Next split handles the logical operations on D register with -;; another hard register for the second operand. For this, we -;; have to save the second operand in a scratch location and use -;; it instead. This must be supported because in some (rare) cases -;; the second operand can come in a hard register and the reload -;; pass doesn't know how to reload it in a memory location. -;; -;; PLUS MINUS AND IOR XOR -;; -;; The shift operators are special and must not appear here. -;; -(define_split - [(set (match_operand:HI 0 "d_register_operand" "") - (match_operator:HI 3 "m68hc11_non_shift_operator" - [(match_operand:HI 1 "d_register_operand" "") - (match_operand:HI 2 "hard_reg_operand" "")]))] - "TARGET_M6811 - && z_replacement_completed == 2 && !SP_REG_P (operands[2])" - [(set (match_dup 4) (match_dup 2)) - (set (match_dup 0) (match_op_dup 3 [(match_dup 0) (match_dup 4)]))] - "operands[4] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);") - -;; -;; For 68HC12, push the operand[2] value on the stack and do the -;; logical/arithmetic operation with a pop. -;; -(define_split - [(set (match_operand:HI 0 "d_register_operand" "") - (match_operator:HI 3 "m68hc11_non_shift_operator" - [(match_operand:HI 1 "d_register_operand" "") - (match_operand:HI 2 "hard_reg_operand" "")]))] - "TARGET_M6812 - && z_replacement_completed == 2 && !SP_REG_P (operands[2])" - [(set (match_dup 4) (match_dup 2)) - (set (match_dup 0) (match_op_dup 3 [(match_dup 0) (match_dup 5)]))] - "operands[4] = gen_rtx_MEM (HImode, - gen_rtx_PRE_DEC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM))); - operands[5] = gen_rtx_MEM (HImode, - gen_rtx_POST_INC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM))); - ") - -;;-------------------------------------------------------------------- -;; 16-bit Unary operations on X and Y: -;; -;; NOT NEG -;; -;; Operations on X or Y registers are split here. Instructions are -;; changed into: -;; - xgdx/xgdy instruction pattern, -;; - The same operation on register D, -;; - xgdx/xgdy instruction pattern. -;; This should allow the peephole to merge consecutive xgdx/xgdy instructions. -;; We also handle the case were the address register is used in both source -;; operands, such as: -;; -;; (set (REG:HI X) (PLUS:HI (REG:HI X) (mem:HI (REG:HI X)))) -;; or -;; (set (REG:HI X) (PLUS:HI (REG:HI X) (REG:HI X))) -;; -(define_split - [(set (match_operand:HI 0 "hard_addr_reg_operand" "") - (match_operator:HI 2 "m68hc11_unary_operator" - [(match_operand 1 "general_operand" "")]))] - "z_replacement_completed == 2" - [(set (match_dup 4) (match_dup 5)) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))]) - (set (reg:HI D_REGNUM) (match_op_dup 2 [(match_dup 3)])) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))])] - " -{ - if ((H_REG_P (operands[1]) - && !rtx_equal_p (operands[0], operands[1])) - || reg_mentioned_p (operands[0], operands[1])) - { - /* Move to the destination register, before the xgdx. */ - operands[4] = gen_rtx_REG (GET_MODE (operands[1]), - REGNO (operands[0])); - operands[5] = operands[1]; - - /* Apply the operation on D. */ - operands[3] = gen_rtx_REG (GET_MODE (operands[1]), HARD_D_REGNUM); - } - else - { - /* Generate a copy to same register (nop). */ - operands[4] = operands[5] = operands[0]; - operands[3] = operands[1]; - } -}") - -;; -;; 8-bit operations on address registers. -;; -;; We have to take care that the address register is not used for the -;; source of operand2. If operand2 is the D register, we have to save -;; that register in a temporary location. -;; -;; AND OR XOR PLUS MINUS ASHIFT ASHIFTRT LSHIFTRT ROTATE ROTATERT -;; -(define_split - [(set (match_operand:QI 0 "hard_addr_reg_operand" "") - (match_operator:QI 3 "m68hc11_arith_operator" - [(match_operand:QI 1 "hard_addr_reg_operand" "") - (match_operand:QI 2 "general_operand" "")]))] - "z_replacement_completed == 2 - /* Reject a (plus:QI (reg:QI X) (const_int 1|-1)) because the - incqi pattern generates a better code. */ - && !(GET_CODE (operands[3]) == PLUS - && GET_CODE (operands[2]) == CONST_INT - && (INTVAL (operands[2]) == 1 || INTVAL (operands[2]) == -1))" - [(set (match_dup 5) (match_dup 6)) - (parallel [(set (reg:HI D_REGNUM) (match_dup 4)) - (set (match_dup 4) (reg:HI D_REGNUM))]) - (set (reg:QI D_REGNUM) (match_op_dup 3 [(reg:QI D_REGNUM) (match_dup 7)])) - (parallel [(set (reg:HI D_REGNUM) (match_dup 4)) - (set (match_dup 4) (reg:HI D_REGNUM))])] - "operands[4] = gen_rtx_REG (HImode, REGNO (operands[0])); - - /* For the second operand is a hard register or if the address - register appears in the source, we have to save the operand[2] - value in a temporary location and then use that temp. - Otherwise, it's ok and we generate a (set (D) (D)) that - will result in a nop. */ - if (H_REG_P (operands[2])) - { - operands[5] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); - operands[6] = gen_rtx_REG (HImode, REGNO (operands[2])); - operands[7] = gen_rtx_REG (QImode, SOFT_TMP_REGNUM); - } - else if (reg_mentioned_p (operands[0], operands[2])) - { - operands[5] = gen_rtx_REG (QImode, SOFT_TMP_REGNUM); - operands[6] = operands[2]; - operands[7] = operands[5]; - } - else - { - operands[5] = operands[6] = gen_rtx_REG (QImode, HARD_D_REGNUM); - operands[7] = operands[2]; - } - ") - -;; -;; Next split handles the logical operations on D register with -;; another hard register for the second operand. For this, we -;; have to save the second operand in a scratch location and use -;; it instead. This must be supported because in some (rare) cases -;; the second operand can come in a hard register and the reload -;; pass doesn't know how to reload it in a memory location. -;; -;; PLUS MINUS AND IOR XOR -;; -;; The shift operators are special and must not appear here. -;; -(define_split - [(set (match_operand:QI 0 "d_register_operand" "") - (match_operator:QI 3 "m68hc11_non_shift_operator" - [(match_operand:QI 1 "d_register_operand" "") - (match_operand:QI 2 "hard_reg_operand" "")]))] - "reload_completed" - [(set (match_dup 5) (match_dup 6)) - (set (match_dup 0) (match_op_dup 3 [(match_dup 0) (match_dup 4)]))] - "operands[4] = gen_rtx_REG (QImode, SOFT_TMP_REGNUM); - operands[5] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); - operands[6] = gen_rtx_REG (HImode, REGNO (operands[2]));") - -;;-------------------------------------------------------------------- -;; 8-bit Unary operations on X and Y: -;; -;; NOT NEG -;; -;; Operations on X or Y registers are split here. Instructions are -;; changed into: -;; - xgdx/xgdy instruction pattern, -;; - The same operation on register D, -;; - xgdx/xgdy instruction pattern. -;; This should allow the peephole to merge consecutive xgdx/xgdy instructions. -;; We also handle the case were the address register is used in both source -;; operands, such as: -;; -;; (set (REG:HI X) (PLUS:HI (REG:HI X) (mem:HI (REG:HI X)))) -;; or -;; (set (REG:HI X) (PLUS:HI (REG:HI X) (REG:HI X))) -;; -(define_split - [(set (match_operand:QI 0 "hard_addr_reg_operand" "") - (match_operator:QI 2 "m68hc11_unary_operator" - [(match_operand:QI 1 "general_operand" "")]))] - "z_replacement_completed == 2" - [(set (match_dup 4) (match_dup 5)) - (parallel [(set (reg:HI D_REGNUM) (match_dup 3)) - (set (match_dup 3) (reg:HI D_REGNUM))]) - (set (reg:QI D_REGNUM) (match_op_dup 2 [(match_dup 6)])) - (parallel [(set (reg:HI D_REGNUM) (match_dup 3)) - (set (match_dup 3) (reg:HI D_REGNUM))])] - " -{ - operands[3] = gen_rtx_REG (HImode, REGNO (operands[0])); - if ((H_REG_P (operands[1]) - && !rtx_equal_p (operands[0], operands[1])) - || reg_mentioned_p (operands[0], operands[1])) - { - /* Move to the destination register, before the xgdx. */ - operands[4] = operands[0]; - operands[5] = operands[1]; - - /* Apply the operation on D. */ - operands[6] = gen_rtx_REG (QImode, HARD_D_REGNUM); - } - else - { - operands[4] = operands[5] = operands[0]; - operands[6] = operands[1]; - } -}") - - -;;-------------------------------------------------------------------- -;;- Complements -;;-------------------------------------------------------------------- - -(define_expand "negdi2" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (neg:DI (match_operand:DI 1 "general_operand" "")))] - "" - "m68hc11_emit_libcall (\"__negdi2\", NEG, DImode, DImode, 2, operands); - DONE;") - - -(define_insn "negsi2" - [(set (match_operand:SI 0 "register_operand" "=D") - (neg:SI (match_operand:SI 1 "general_operand" "0")))] - "" - "* -{ - rtx ops[1]; - - CC_STATUS_INIT; - - /* With -Os or without -O, use a special library call. */ - if (optimize_size || optimize == 0) - return \"bsr\\t___negsi2\"; - - ops[0] = gen_label_rtx (); - - /* 32-bit complement and add 1. */ - output_asm_insn (\"comb\\n\\tcoma\\n\\txgdx\", operands); - output_asm_insn (\"comb\\n\\tcoma\\n\\tinx\\n\\txgdx\", operands); - output_asm_insn (\"bne\\t%l0\", ops); - output_asm_insn (\"inx\", operands); - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", CODE_LABEL_NUMBER (ops[0])); - return \"\"; -}") - -(define_insn "neghi2" - [(set (match_operand:HI 0 "register_operand" "=d,d,x*y") - (neg:HI (match_operand:HI 1 "general_operand" "0,!duim,0")))] - "" - "@ - coma\\n\\tcomb\\n\\taddd\\t#1 - clra\\n\\tclrb\\n\\tsubd\\t%1 - xgd%0\\n\\tcoma\\n\\tcomb\\n\\txgd%0\\n\\tin%0") - -(define_insn "negqi2" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,m,!u,!*A") - (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0,0,0,0")))] - "" - "@ - negb - neg\\t%b0 - neg\\t%b0 - #") - -;; -;; - 32-bit complement. GCC knows how to translate them but providing a -;; pattern generates better/smaller code. -;; -(define_expand "one_cmpldi2" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (not:DI (match_operand:DI 1 "general_operand" "")))] - "" - "m68hc11_emit_libcall (\"___notdi2\", NOT, DImode, DImode, 2, operands); - DONE;") - -(define_insn "one_cmplsi2" - [(set (match_operand:SI 0 "non_push_operand" "=D,m,!u") - (not:SI (match_operand:SI 1 "general_operand" "0,m,0"))) - (clobber (match_scratch:HI 2 "=X,d,X"))] - "" - "@ - bsr\\t___one_cmplsi2 - # - #") - -(define_insn "one_cmplhi2" - [(set (match_operand:HI 0 "non_push_operand" "=d,m,*A,u") - (not:HI (match_operand:HI 1 "general_operand" "0,0,0,0")))] - "" - "@ - comb\\n\\tcoma - com\\t%b0\\n\\tcom\\t%h0 - # - com\\t%b0\\n\\tcom\\t%h0") - -(define_insn "one_cmplqi2" - [(set (match_operand:QI 0 "non_push_operand" "=d,m,*A,u") - (not:QI (match_operand:QI 1 "general_operand" "0,0,0,0")))] - "" - "@ - comb - com\\t%b0 - # - com\\t%b0") - -(define_split /* "*one_cmplsi2" */ - [(set (match_operand:SI 0 "non_push_operand" "") - (not:SI (match_dup 0))) - (clobber (match_scratch:HI 1 ""))] - "z_replacement_completed == 2 - && (!X_REG_P (operands[0]) || (optimize && optimize_size == 0))" - [(set (match_dup 2) (not:HI (match_dup 2))) - (set (match_dup 3) (not:HI (match_dup 3)))] - "operands[2] = m68hc11_gen_lowpart (HImode, operands[0]); - operands[3] = m68hc11_gen_highpart (HImode, operands[0]);") - -(define_split /* "*one_cmplsi2" */ - [(set (match_operand:SI 0 "non_push_operand" "") - (not:SI (match_operand:SI 1 "non_push_operand" ""))) - (clobber (match_operand:HI 2 "d_register_operand" ""))] - "z_replacement_completed == 2 - && (!X_REG_P (operands[0]) || (optimize && optimize_size == 0))" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 2) (not:HI (match_dup 2))) - (set (match_dup 4) (match_dup 2)) - (set (match_dup 2) (match_dup 5)) - (set (match_dup 2) (not:HI (match_dup 2))) - (set (match_dup 6) (match_dup 2))] - "operands[3] = m68hc11_gen_lowpart (HImode, operands[1]); - operands[5] = m68hc11_gen_highpart (HImode, operands[1]); - operands[4] = m68hc11_gen_lowpart (HImode, operands[0]); - operands[6] = m68hc11_gen_highpart (HImode, operands[0]);") - -;;-------------------------------------------------------------------- -;;- arithmetic shifts -;;-------------------------------------------------------------------- -;; -;; Provide some 64-bit shift patterns. -(define_expand "ashldi3" - [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "") - (ashift:DI (match_operand:DI 1 "general_operand" "") - (match_operand:HI 2 "general_operand" ""))) - (clobber (match_scratch:HI 3 ""))])] - "" - " -{ - if (GET_CODE (operands[2]) != CONST_INT - || (INTVAL (operands[2]) != 32 && INTVAL (operands[2]) != 1)) - { - FAIL; - } -}") - -(define_insn_and_split "*ashldi3_const32" - [(set (match_operand:DI 0 "nonimmediate_operand" "=<,m,u") - (ashift:DI (match_operand:DI 1 "general_operand" "umi,umi,umi") - (const_int 32))) - (clobber (match_scratch:HI 2 "=&A,d,d"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "/* Move the lowpart in the highpart first in case the shift - is applied on the source. */ - if (IS_STACK_PUSH (operands[0])) - { - m68hc11_split_move (m68hc11_gen_lowpart (SImode, operands[0]), - const0_rtx, operands[2]); - - /* Adjust first operand if it uses SP so that we take into - account the above push. Can occur only for 68HC12. */ - if (reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), - operands[1])) - operands[1] = adjust_address (operands[1], - GET_MODE (operands[0]), 4); - } - m68hc11_split_move (m68hc11_gen_highpart (SImode, operands[0]), - m68hc11_gen_lowpart (SImode, operands[1]), - operands[2]); - if (!IS_STACK_PUSH (operands[0])) - { - m68hc11_split_move (m68hc11_gen_lowpart (SImode, operands[0]), - const0_rtx, operands[2]); - } - DONE;") - -(define_insn_and_split "*ashldi3_const1" - [(set (match_operand:DI 0 "non_push_operand" "=m,m,u") - (ashift:DI (match_operand:DI 1 "general_operand" "mi,u,umi") - (const_int 1))) - (clobber (match_scratch:HI 2 "=d,d,d"))] - "" - "#" - "z_replacement_completed == 2" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 2) (ashift:HI (match_dup 2) (const_int 1))) - (set (match_dup 4) (match_dup 2)) - - (set (match_dup 2) (match_dup 5)) - (parallel [(set (match_dup 2) - (rotate:HI (match_dup 2) (const_int 1))) - (clobber (reg:HI CC_REGNUM))]) - (set (match_dup 6) (match_dup 2)) - - (set (match_dup 2) (match_dup 7)) - (parallel [(set (match_dup 2) - (rotate:HI (match_dup 2) (const_int 1))) - (clobber (reg:HI CC_REGNUM))]) - (set (match_dup 8) (match_dup 2)) - - (set (match_dup 2) (match_dup 9)) - (parallel [(set (match_dup 2) - (rotate:HI (match_dup 2) (const_int 1))) - (clobber (reg:HI CC_REGNUM))]) - (set (match_dup 10) (match_dup 2))] - "operands[3] = m68hc11_gen_lowpart (SImode, operands[1]); - operands[5] = m68hc11_gen_highpart (HImode, operands[3]); - operands[3] = m68hc11_gen_lowpart (HImode, operands[3]); - - operands[4] = m68hc11_gen_lowpart (SImode, operands[0]); - operands[6] = m68hc11_gen_highpart (HImode, operands[4]); - operands[4] = m68hc11_gen_lowpart (HImode, operands[4]); - - operands[7] = m68hc11_gen_highpart (SImode, operands[1]); - operands[9] = m68hc11_gen_highpart (HImode, operands[7]); - operands[7] = m68hc11_gen_lowpart (HImode, operands[7]); - - operands[8] = m68hc11_gen_highpart (SImode, operands[0]); - operands[10] = m68hc11_gen_highpart (HImode, operands[8]); - operands[8] = m68hc11_gen_lowpart (HImode, operands[8]);") - -(define_insn "addsi_silshr16" - [(set (match_operand:SI 0 "register_operand" "=D,D,!D") - (plus:SI (lshiftrt:SI (match_operand:SI 1 "general_operand" "!*uim,0,0") - (const_int 16)) - (match_operand:SI 2 "general_operand" "0,m!*u,0")))] - "" - "#") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (plus:SI (lshiftrt:SI (match_operand:SI 1 "general_operand" "") - (const_int 16)) - (match_operand:SI 2 "general_operand" "")))] - "z_replacement_completed == 2 && !X_REG_P (operands[1])" - [(set (reg:HI D_REGNUM) (plus:HI (reg:HI D_REGNUM) (match_dup 3))) - (set (reg:HI X_REGNUM) (plus:HI (plus:HI (reg:HI X_REGNUM) - (const_int 0)) - (reg:HI CC_REGNUM)))] - "operands[3] = m68hc11_gen_highpart (HImode, operands[1]);") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (plus:SI (lshiftrt:SI (match_operand:SI 1 "general_operand" "") - (const_int 16)) - (match_operand:SI 2 "general_operand" "")))] - "z_replacement_completed == 2 && X_REG_P (operands[1])" - [(set (reg:HI D_REGNUM) (match_dup 5)) - (set (reg:HI X_REGNUM) (match_dup 3)) - (set (reg:HI D_REGNUM) (plus:HI (reg:HI D_REGNUM) (match_dup 4))) - (set (reg:HI X_REGNUM) (plus:HI (plus:HI (reg:HI X_REGNUM) - (const_int 0)) - (reg:HI CC_REGNUM)))] - "operands[3] = m68hc11_gen_highpart (HImode, operands[2]); - if (X_REG_P (operands[2])) - { - operands[4] = gen_rtx_REG (HImode, HARD_X_REGNUM); - operands[5] = gen_rtx_REG (HImode, HARD_D_REGNUM); - } - else - { - operands[4] = m68hc11_gen_lowpart (HImode, operands[2]); - operands[5] = gen_rtx_REG (HImode, HARD_X_REGNUM); - } -") - -(define_insn "addsi_ashift16" - [(set (match_operand:SI 0 "register_operand" "=D") - (plus:SI - (mult:SI (match_operand:SI 2 "general_operand" "uim") - (const_int 65536)) - (match_operand:SI 1 "general_operand" "0"))) - (clobber (match_scratch:HI 3 "=X"))] - "0" - "#") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (plus:SI - (mult:SI (match_operand:SI 2 "general_operand" "") - (const_int 65536)) - (match_operand:SI 1 "general_operand" ""))) - (clobber (match_scratch:HI 3 "=X"))] - "0 && reload_completed && z_replacement_completed == 2" - [(set (reg:HI X_REGNUM) (plus:HI (reg:HI X_REGNUM) (match_dup 4)))] - " -{ - operands[4] = m68hc11_gen_lowpart (HImode, operands[2]); -}") - -(define_insn_and_split "addsi_andshr16" - [(set (match_operand:SI 0 "register_operand" "=D") - (plus:SI (and:SI (match_operand:SI 1 "general_operand" "%uim") - (const_int 65535)) - (match_operand:SI 2 "general_operand" "0")))] - "" - "#" - "z_replacement_completed == 2" - [(set (reg:HI D_REGNUM) (plus:HI (reg:HI D_REGNUM) (match_dup 3))) - (set (reg:HI X_REGNUM) (plus:HI (plus:HI (reg:HI X_REGNUM) (const_int 0)) (reg:HI CC_REGNUM)))] - "operands[3] = m68hc11_gen_lowpart (HImode, operands[1]);") - -;; -;; 32-bit shifts are made by a small library routine that uses -;; a specific passing convention for parameters (for efficiency reasons). -;; -;; [D + X] -> Value to be shifted -;; Y -> Shift count -;; -;; The shift count is clobbered by the routine. -;; -(define_expand "ashlsi3" - [(parallel - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "general_operand" "")) - (clobber (scratch:HI))]) - (parallel - [(set (match_dup 0) (ashift:SI (match_dup 0) - (match_operand:HI 2 "nonmemory_operand" ""))) - (clobber (scratch:HI))])] - "" - "") - -(define_split - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (ashift:SI (match_operand:SI 1 "general_operand" "") - (const_int 16))) - (clobber (match_scratch:HI 3 ""))] - "" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 4) (const_int 0))] - "operands[2] = m68hc11_gen_highpart (HImode, operands[0]); - operands[4] = m68hc11_gen_lowpart (HImode, operands[0]); - operands[3] = m68hc11_gen_lowpart (HImode, operands[1]);") - -(define_insn "*ashlsi3_const16" - [(set (match_operand:SI 0 "nonimmediate_operand" "=D,m,*u") - (ashift:SI (match_operand:SI 1 "general_operand" "Duim,D,D") - (const_int 16))) - (clobber (match_scratch:HI 2 "=X,X,X"))] - "" - "#") - -(define_insn_and_split "*ashlsi3_const16_zexthi" - [(set (match_operand:SI 0 "nonimmediate_operand" "=D") - (ashift:SI (zero_extend:HI - (match_operand:HI 1 "general_operand" "duim*A")) - (const_int 16))) - (clobber (match_scratch:HI 2 "=X"))] - "" - "#" - "reload_completed" - [(set (reg:HI X_REGNUM) (match_dup 1)) - (set (reg:HI D_REGNUM) (const_int 0))] - "") - -(define_insn "*ashlsi3_const1" - [(set (match_operand:SI 0 "non_push_operand" "=D,D,D,m,*u,*u") - (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0,m,*u,m,*u,m") - (const_int 1))) - (clobber (match_scratch:HI 2 "=X,X,X,&d,&d,&d"))] - "" - "* -{ - CC_STATUS_INIT; - if (X_REG_P (operands[1])) - { - return \"lsld\\n\\txgdx\\n\\trolb\\n\\trola\\n\\txgdx\"; - } - else - { - rtx ops[2]; - - ops[1] = m68hc11_gen_lowpart (HImode, operands[1]); - ops[0] = gen_rtx_REG (HImode, HARD_D_REGNUM); - m68hc11_gen_movhi (insn, ops); - output_asm_insn (\"lsld\", ops); - if (!X_REG_P (operands[0])) - { - ops[1] = ops[0]; - ops[0] = m68hc11_gen_lowpart (HImode, operands[0]); - m68hc11_gen_movhi (insn, ops); - ops[0] = ops[1]; - ops[1] = m68hc11_gen_highpart (HImode, operands[1]); - m68hc11_gen_movhi (insn, ops); - } - else - { - /* Load the high part in X in case the source operand - uses X as a memory pointer. */ - ops[0] = gen_rtx_REG (HImode, HARD_X_REGNUM); - ops[1] = m68hc11_gen_highpart (HImode, operands[1]); - m68hc11_gen_movhi (insn, ops); - output_asm_insn (\"xgdx\", ops); - } - output_asm_insn (\"rolb\", ops); - output_asm_insn (\"rola\", ops); - if (!X_REG_P (operands[0])) - { - ops[1] = ops[0]; - ops[0] = m68hc11_gen_highpart (HImode, operands[0]); - m68hc11_gen_movhi (insn, ops); - } - else - { - output_asm_insn (\"xgdx\", ops); - } - return \"\"; - } -}") - -(define_insn "*ashlsi3_const" - [(set (match_operand:SI 0 "register_operand" "+D") - (ashift:SI (match_dup 0) - (match_operand:HI 1 "const_int_operand" ""))) - (clobber (match_scratch:HI 2 "=y"))] - "TARGET_M6811 /* See *ashlsi3 note. */" - "* -{ - CC_STATUS_INIT; - return \"ldy\\t%1\\n\\tbsr\\t___ashlsi3\"; -}") - -(define_insn "*ashlsi3" - [(set (match_operand:SI 0 "register_operand" "+D,D") - (ashift:SI (match_dup 0) - (match_operand:HI 1 "general_operand" "y,mi"))) - (clobber (match_scratch:HI 2 "=1,X"))] - "" - "* -{ - CC_STATUS_INIT; - - /* There is a reload problem if we don't accept 'm' for the shift value. - A RELOAD_OTHER reload can be generated for operand 0 (class A_REGS) - and this conflicts with all reloads. Since X, Y, Z are used there - is not enough register in class A_REGS. - - Assuming that 'operands[1]' does not refer to the stack (which - is true for 68hc11 only, we save temporary the value of Y. - - For 68HC12 we must also accept a constant because Z register is - disabled when compiling with -fomit-frame-pointer. We can come up - with a reload problem and the *lshrsi3_const pattern was disabled - for that reason. */ - if (!Y_REG_P (operands[2])) - { - rtx ops[1]; - int y_dead = dead_register_here (insn, iy_reg); - - ops[0] = operands[1]; - if (y_dead == 0) - { - output_asm_insn (\"pshy\", operands); - if (reg_mentioned_p (stack_pointer_rtx, operands[1])) - ops[0] = adjust_address (operands[1], GET_MODE (operands[1]), 2); - } - output_asm_insn (\"ldy\\t%0\", ops); - output_asm_insn (\"bsr\\t___ashlsi3\", operands); - return y_dead == 0 ? \"puly\" : \"\"; - } - return \"bsr\\t___ashlsi3\"; -}") - -(define_expand "ashlhi3" - [(set (match_operand:HI 0 "register_operand" "") - (ashift:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" "")))] - "" - " -{ - if (GET_CODE (operands[2]) != CONST_INT) - { - rtx scratch = gen_reg_rtx (HImode); - emit_move_insn (scratch, operands[2]); - emit_insn (gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, gen_rtx_SET (VOIDmode, - operand0, - gen_rtx_ASHIFT (HImode, - operand1, scratch)), - gen_rtx_CLOBBER (VOIDmode, scratch)))); - DONE; - } -}") - -(define_insn "*ashlhi3_const1" - [(set (match_operand:HI 0 "non_push_operand" "=dm,!*u*A") - (ashift:HI (match_operand:HI 1 "non_push_operand" "0,0") - (const_int 1)))] - "" - "* -{ - if (A_REG_P (operands[0])) - return \"#\"; - - if (D_REG_P (operands[0])) - { - return \"asld\"; - } - - output_asm_insn (\"asl\\t%b0\", operands); - output_asm_insn (\"rol\\t%h0\", operands); - CC_STATUS_INIT; - return \"\"; -}") - - -(define_insn "*ashlhi3_2" - [(set (match_operand:HI 0 "register_operand" "=d,*x") - (ashift:HI (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "register_operand" "+x,+d"))) - (clobber (match_dup 2))] - "" - "* -{ - if (A_REG_P (operands[0])) - return \"#\"; - - CC_STATUS_INIT; - return \"bsr\\t___lshlhi3\"; -}") - -(define_insn "*ashlhi3" - [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) - (ashift:HI (match_dup 0) - (match_operand:HI 1 "register_operand" "+x"))) - (clobber (match_dup 1))] - "" - "* -{ - CC_STATUS_INIT; - return \"bsr\\t___lshlhi3\"; -}") - -(define_insn "*ashlhi3" - [(set (match_operand:HI 0 "register_operand" "=d,!*A") - (ashift:HI (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "const_int_operand" "")))] - "" - "* -{ - int i; - - if (A_REG_P (operands[0])) - return \"#\"; - - i = INTVAL (operands[2]); - if (i >= 8) - { - CC_STATUS_INIT; - output_asm_insn (\"tba\", operands); - if (i == 15) - { - output_asm_insn (\"rora\", operands); - output_asm_insn (\"anda\\t#0\", operands); - output_asm_insn (\"rora\", operands); - } - else - while (i != 8 ) - { - output_asm_insn (\"asla\", operands); - i--; - } - return \"clrb\"; - } - for (i = 0; i < INTVAL (operands[2]) - 1; i++) - { - output_asm_insn (\"asld\", operands); - } - return \"asld\"; -}") - -(define_expand "ashlqi3" - [(set (match_operand:QI 0 "register_operand" "") - (ashift:QI (match_operand:QI 1 "register_operand" "") - (match_operand:QI 2 "general_operand" "")))] - "" - "") - -(define_insn "*ashlqi3_const1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,m,!u,!*q,!*A") - (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0,0,0,0") - (const_int 1)))] - "" - "@ - aslb - asl\\t%b0 - asl\\t%b0 - asl%0 - #") - -(define_insn "*ashlqi3_const" - [(set (match_operand:QI 0 "register_operand" "=d,!*q,!*A") - (ashift:QI (match_operand:QI 1 "register_operand" "0,0,0") - (match_operand:QI 2 "const_int_operand" "")))] - "" - "* -{ - int i; - const char* insn_code; - - if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - insn_code = \"aslb\"; - else if (DA_REG_P (operands[0])) - insn_code = \"asla\"; - else - return \"#\"; - - i = INTVAL (operands[2]); - if (i >= 8) - { - if (DA_REG_P (operands[0])) - return \"clra\"; - else - return \"clrb\"; - } - else if (i == 7) - { - if (DA_REG_P (operands[0])) - { - output_asm_insn (\"rora\", operands); - output_asm_insn (\"ldaa\\t#0\", operands); - return \"rora\"; - } - else - { - output_asm_insn (\"rorb\", operands); - output_asm_insn (\"ldab\\t#0\", operands); - return \"rorb\"; - } - } - else if (i == 6) - { - if (DA_REG_P (operands[0])) - { - output_asm_insn (\"rora\", operands); - output_asm_insn (\"rora\", operands); - output_asm_insn (\"rora\", operands); - return \"anda\\t#0xC0\"; - } - else - { - output_asm_insn (\"rorb\", operands); - output_asm_insn (\"rorb\", operands); - output_asm_insn (\"rorb\", operands); - return \"andb\\t#0xC0\"; - } - } - while (--i >= 0) - { - output_asm_insn (insn_code, operands); - } - return \"\"; -}") - -(define_insn "*ashlqi3" - [(set (match_operand:QI 0 "register_operand" "=d,!*q,!*A") - (ashift:QI (match_operand:QI 1 "register_operand" "0,0,0") - (match_operand:QI 2 "nonimmediate_operand" - "m*u*d*A,m*u*d*A,m*u")))] - "" - "* -{ - rtx ops[2]; - - if (!D_REG_P (operands[0]) && !Q_REG_P (operands[0])) - return \"#\"; - - ops[0] = gen_rtx_REG (QImode, HARD_A_REGNUM); - ops[1] = operands[2]; - m68hc11_gen_movqi (insn, ops); - - CC_STATUS_INIT; - return \"bsr\\t___lshlqi3\"; -}") - -(define_expand "ashrhi3" - [(set (match_operand:HI 0 "register_operand" "") - (ashiftrt:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" "")))] - "" - " -{ - if (GET_CODE (operands[2]) != CONST_INT) - { - rtx scratch = gen_reg_rtx (HImode); - - emit_move_insn (scratch, operands[2]); - emit_insn (gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, gen_rtx_SET (VOIDmode, - operand0, - gen_rtx_ASHIFTRT (HImode, - operand1, scratch)), - gen_rtx_CLOBBER (VOIDmode, scratch)))); - DONE; - } -}") - -(define_insn "*ashrhi3_const1" - [(set (match_operand:HI 0 "non_push_operand" "=dm,!*u*A") - (ashiftrt:HI (match_operand:HI 1 "non_push_operand" "0,0") - (const_int 1)))] - "" - "* -{ - if (A_REG_P (operands[0])) - return \"#\"; - - CC_STATUS_INIT; - if (D_REG_P (operands[0])) - { - return \"asra\\n\\trorb\"; - } - - output_asm_insn (\"asr\\t%h0\", operands); - output_asm_insn (\"ror\\t%b0\", operands); - return \"\"; -}") - - -(define_insn "*ashrhi3_const" - [(set (match_operand:HI 0 "register_operand" "=d,!*A") - (ashiftrt:HI (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "const_int_operand" "")))] - "" - "* -{ - rtx ops[2]; - int val = INTVAL (operands[2]); - - if (A_REG_P (operands[0])) - return \"#\"; - - if (val >= 15) - { - ops[0] = gen_label_rtx (); - - output_asm_insn (\"clrb\", operands); - output_asm_insn (\"rola\", operands); - - /* Clear A without clearing the carry flag. */ - output_asm_insn (\"tba\", operands); - output_asm_insn (\"bcc\\t%l0\", ops); - output_asm_insn (\"coma\", operands); - output_asm_insn (\"comb\", operands); - - CC_STATUS_INIT; - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (ops[0])); - return \"\"; - } - if (val >= 8) - { - ops[0] = gen_label_rtx (); - - output_asm_insn (\"tab\", operands); - output_asm_insn (\"clra\", operands); - output_asm_insn (\"tstb\", operands); - output_asm_insn (\"bge\\t%l0\", ops); - output_asm_insn (\"deca\", operands); - - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (ops[0])); - - val -= 8; - - while (val > 0) - { - output_asm_insn (\"asrb\", operands); - val--; - } - /* Status is ok. */ - return \"\"; - } - if (val == 7) - { - ops[0] = gen_label_rtx (); - output_asm_insn (\"rolb\", operands); - output_asm_insn (\"rola\", operands); - output_asm_insn (\"tab\", operands); - output_asm_insn (\"anda\\t#0\", operands); - output_asm_insn (\"bcc\\t%l0\", ops); - output_asm_insn (\"coma\", ops); - - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (ops[0])); - return \"\"; - } - while (val > 0) - { - output_asm_insn (\"asra\", operands); - output_asm_insn (\"rorb\", operands); - val--; - } - CC_STATUS_INIT; - - return \"\"; -}") - -(define_insn "*ashrhi3" - [(set (match_operand:HI 0 "register_operand" "=d,*x") - (ashiftrt:HI (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "register_operand" "+x,+d"))) - (clobber (match_dup 2))] - "" - "* -{ - if (A_REG_P (operands[0])) - return \"#\"; - - output_asm_insn (\"bsr\\t___ashrhi3\", operands); - return \"\"; -}") - -(define_expand "ashrsi3" - [(parallel - [(set (match_dup 0) (match_operand:SI 1 "general_operand" "")) - (clobber (scratch:HI))]) - (parallel - [(set (match_operand:SI 0 "register_operand" "") - (ashiftrt:SI (match_dup 0) - (match_operand:HI 2 "general_operand" ""))) - (clobber (scratch:HI))])] - "" - "") - -(define_insn "*ashrsi3_const" - [(set (match_operand:SI 0 "register_operand" "+D") - (ashiftrt:SI (match_dup 0) - (match_operand:HI 1 "const_int_operand" ""))) - (clobber (match_scratch:HI 2 "=y"))] - "TARGET_M6811 /* See *ashrsi3 note. */" - "* -{ - CC_STATUS_INIT; - return \"ldy\\t%1\\n\\tbsr\\t___ashrsi3\"; -}") - -(define_insn "*ashrsi3" - [(set (match_operand:SI 0 "register_operand" "+D,D") - (ashiftrt:SI (match_dup 0) - (match_operand:HI 1 "general_operand" "y,mi"))) - (clobber (match_scratch:HI 2 "=1,X"))] - "" - "* -{ - CC_STATUS_INIT; - /* There is a reload problem if we don't accept 'm' for the shift value. - A RELOAD_OTHER reload can be generated for operand 0 (class A_REGS) - and this conflicts with all reloads. Since X, Y, Z are used there - is not enough register in class A_REGS. - - Assuming that 'operands[1]' does not refer to the stack (which - is true for 68hc11 only, we save temporary the value of Y. - - For 68HC12 we must also accept a constant because Z register is - disabled when compiling with -fomit-frame-pointer. We can come up - with a reload problem and the *lshrsi3_const pattern was disabled - for that reason. */ - if (!Y_REG_P (operands[2])) - { - rtx ops[1]; - int y_dead = dead_register_here (insn, iy_reg); - - ops[0] = operands[1]; - if (y_dead == 0) - { - output_asm_insn (\"pshy\", operands); - if (reg_mentioned_p (stack_pointer_rtx, operands[1])) - ops[0] = adjust_address (operands[1], GET_MODE (operands[1]), 2); - } - output_asm_insn (\"ldy\\t%0\", ops); - output_asm_insn (\"bsr\\t___ashrsi3\", operands); - return y_dead == 0 ? \"puly\" : \"\"; - } - return \"bsr\\t___ashrsi3\"; -}") - -(define_expand "ashrqi3" - [(set (match_operand:QI 0 "register_operand" "") - (ashiftrt:QI (match_operand:QI 1 "register_operand" "") - (match_operand:QI 2 "general_operand" "")))] - "" - "") - -(define_insn "*ashrqi3_const1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,m,!u,!*q,!*A") - (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0,0,0,0") - (const_int 1)))] - "" - "@ - asrb - asr\\t%b0 - asr\\t%b0 - asr%0 - #") - -(define_insn "*ashrqi3_const" - [(set (match_operand:QI 0 "register_operand" "=d,!*q,!*A") - (ashiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0") - (match_operand:QI 2 "const_int_operand" "")))] - "" - "* -{ - int i; - const char* insn_code; - - if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - insn_code = \"asrb\"; - else if (DA_REG_P (operands[0])) - insn_code = \"asra\"; - else - return \"#\"; - - i = INTVAL (operands[2]); - if (i > 8) - i = 8; - while (--i >= 0) - { - output_asm_insn (insn_code, operands); - } - return \"\"; -}") - -(define_insn "*ashrqi3" - [(set (match_operand:QI 0 "register_operand" "=d,!*q,!*A") - (ashiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0") - (match_operand:QI 2 "nonimmediate_operand" - "m*u*d*A,m*u*d*A,m*u")))] - "" - "* -{ - rtx ops[2]; - - if (!D_REG_P (operands[0]) && !Q_REG_P (operands[0])) - return \"#\"; - - ops[0] = gen_rtx_REG (QImode, HARD_A_REGNUM); - ops[1] = operands[2]; - m68hc11_gen_movqi (insn, ops); - - CC_STATUS_INIT; - return \"bsr\\t___ashrqi3\"; -}") - -;;-------------------------------------------------------------------- -;; logical shift instructions -;;-------------------------------------------------------------------- -(define_expand "lshrdi3" - [(parallel [(set (match_operand:DI 0 "general_operand" "") - (lshiftrt:DI (match_operand:DI 1 "general_operand" "") - (match_operand:HI 2 "general_operand" ""))) - (clobber (match_scratch:HI 3 ""))])] - "" - " -{ - if (GET_CODE (operands[2]) != CONST_INT - || (INTVAL (operands[2]) != 32 && INTVAL (operands[2]) < 48 - && INTVAL (operands[2]) != 1)) - { - FAIL; - } -}") - -(define_insn_and_split "*lshrdi3_const32" - [(set (match_operand:DI 0 "nonimmediate_operand" "=<,m,u") - (lshiftrt:DI (match_operand:DI 1 "general_operand" "umi,umi,umi") - (const_int 32))) - (clobber (match_scratch:HI 2 "=&A,d,d"))] - "" - "#" - "reload_completed" - [(const_int 0)] - "m68hc11_split_move (m68hc11_gen_lowpart (SImode, operands[0]), - m68hc11_gen_highpart (SImode, operands[1]), - operands[2]); - m68hc11_split_move (m68hc11_gen_highpart (SImode, operands[0]), - const0_rtx, operands[2]); - DONE;") - -(define_insn "*lshrdi3_const63" - [(set (match_operand:DI 0 "nonimmediate_operand" "=m,u") - (lshiftrt:DI (match_operand:DI 1 "general_operand" "umi,umi") - (match_operand:DI 2 "const_int_operand" ""))) - (clobber (match_scratch:HI 3 "=d,d"))] - "INTVAL (operands[2]) >= 48" - "#") - -(define_split - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (lshiftrt:DI (match_operand:DI 1 "general_operand" "") - (match_operand:DI 2 "const_int_operand" ""))) - (clobber (match_scratch:HI 3 "=d"))] - "z_replacement_completed && INTVAL (operands[2]) >= 56" - [(set (reg:QI D_REGNUM) (match_dup 9)) - (set (reg:QI D_REGNUM) (lshiftrt:QI (reg:QI D_REGNUM) (match_dup 8))) - (set (reg:HI D_REGNUM) (zero_extend:HI (reg:QI D_REGNUM))) - (set (match_dup 4) (reg:HI D_REGNUM)) - (set (reg:QI D_REGNUM) (const_int 0)) - (set (match_dup 5) (reg:HI D_REGNUM)) - (set (match_dup 6) (reg:HI D_REGNUM)) - (set (match_dup 7) (reg:HI D_REGNUM))] - "operands[8] = GEN_INT (INTVAL (operands[2]) - 56); - operands[4] = m68hc11_gen_lowpart (SImode, operands[0]); - operands[5] = m68hc11_gen_highpart (HImode, operands[4]); - operands[4] = m68hc11_gen_lowpart (HImode, operands[4]); - - operands[9] = m68hc11_gen_highpart (SImode, operands[1]); - operands[9] = m68hc11_gen_highpart (HImode, operands[9]); - operands[9] = m68hc11_gen_highpart (QImode, operands[9]); - - operands[6] = m68hc11_gen_highpart (SImode, operands[0]); - operands[7] = m68hc11_gen_highpart (HImode, operands[6]); - operands[6] = m68hc11_gen_lowpart (HImode, operands[6]);") - -(define_split - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (lshiftrt:DI (match_operand:DI 1 "general_operand" "") - (match_operand:DI 2 "const_int_operand" ""))) - (clobber (match_scratch:HI 3 "=d"))] - "z_replacement_completed && INTVAL (operands[2]) >= 48 - && INTVAL (operands[2]) < 56" - [(set (reg:HI D_REGNUM) (match_dup 9)) - (set (reg:HI D_REGNUM) (lshiftrt:HI (reg:HI D_REGNUM) (match_dup 8))) - (set (match_dup 4) (reg:HI D_REGNUM)) - (set (reg:HI D_REGNUM) (const_int 0)) - (set (match_dup 5) (reg:HI D_REGNUM)) - (set (match_dup 6) (reg:HI D_REGNUM)) - (set (match_dup 7) (reg:HI D_REGNUM))] - "operands[8] = GEN_INT (INTVAL (operands[2]) - 48); - operands[4] = m68hc11_gen_lowpart (SImode, operands[0]); - operands[5] = m68hc11_gen_highpart (HImode, operands[4]); - operands[4] = m68hc11_gen_lowpart (HImode, operands[4]); - - operands[9] = m68hc11_gen_highpart (SImode, operands[1]); - operands[9] = m68hc11_gen_highpart (HImode, operands[1]); - operands[6] = m68hc11_gen_highpart (SImode, operands[0]); - operands[7] = m68hc11_gen_highpart (HImode, operands[6]); - operands[6] = m68hc11_gen_lowpart (HImode, operands[6]);") - -(define_insn_and_split "*lshrdi_const1" - [(set (match_operand:DI 0 "non_push_operand" "=m,u") - (lshiftrt:DI (match_operand:DI 1 "general_operand" "umi,umi") - (const_int 1))) - (clobber (match_scratch:HI 2 "=d,d"))] - "" - "#" - "z_replacement_completed == 2" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 2) (lshiftrt:HI (match_dup 2) (const_int 1))) - (set (match_dup 4) (match_dup 2)) - - (set (match_dup 2) (match_dup 5)) - (parallel [(set (match_dup 2) (rotatert:HI (match_dup 2) (const_int 1))) - (clobber (reg:HI CC_REGNUM))]) - (set (match_dup 6) (match_dup 2)) - - (set (match_dup 2) (match_dup 7)) - (parallel [(set (match_dup 2) (rotatert:HI (match_dup 2) (const_int 1))) - (clobber (reg:HI CC_REGNUM))]) - (set (match_dup 8) (match_dup 2)) - - (set (match_dup 2) (match_dup 9)) - (parallel [(set (match_dup 2) (rotatert:HI (match_dup 2) (const_int 1))) - (clobber (reg:HI CC_REGNUM))]) - (set (match_dup 10) (match_dup 2))] - "operands[3] = m68hc11_gen_highpart (SImode, operands[1]); - operands[5] = m68hc11_gen_lowpart (HImode, operands[3]); - operands[3] = m68hc11_gen_highpart (HImode, operands[3]); - - operands[4] = m68hc11_gen_highpart (SImode, operands[0]); - operands[6] = m68hc11_gen_lowpart (HImode, operands[4]); - operands[4] = m68hc11_gen_highpart (HImode, operands[4]); - - operands[7] = m68hc11_gen_lowpart (SImode, operands[1]); - operands[9] = m68hc11_gen_lowpart (HImode, operands[7]); - operands[7] = m68hc11_gen_highpart (HImode, operands[7]); - - operands[8] = m68hc11_gen_lowpart (SImode, operands[0]); - operands[10] = m68hc11_gen_lowpart (HImode, operands[8]); - operands[8] = m68hc11_gen_highpart (HImode, operands[8]);") - -(define_expand "lshrsi3" - [(parallel - [(set (match_dup 0) (match_operand:SI 1 "general_operand" "")) - (clobber (scratch:HI))]) - (parallel - [(set (match_operand:SI 0 "register_operand" "") - (lshiftrt:SI (match_dup 0) - (match_operand:HI 2 "general_operand" ""))) - (clobber (scratch:HI))])] - "" - "") - -(define_split - [(set (match_operand:SI 0 "non_push_operand" "") - (lshiftrt:SI (match_operand:SI 1 "general_operand" "") - (const_int 16))) - (clobber (match_scratch:HI 3 ""))] - "reload_completed && !(X_REG_P (operands[0]) && X_REG_P (operands[1]))" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 4) (const_int 0))] - "operands[4] = m68hc11_gen_highpart (HImode, operands[0]); - operands[2] = m68hc11_gen_lowpart (HImode, operands[0]); - operands[3] = m68hc11_gen_highpart (HImode, operands[1]);") - -(define_insn "*lshrsi3_const16" - [(set (match_operand:SI 0 "non_push_operand" "=D,D,m,u") - (lshiftrt:SI (match_operand:SI 1 "general_operand" "uim,0,D,D") - (const_int 16))) - (clobber (match_scratch:HI 2 "=X,X,X,X"))] - "" - "@ - # - xgdx\\n\\tldx\\t#0 - # - #") - -(define_insn "*lshrsi3_const1" - [(set (match_operand:SI 0 "non_push_operand" "=D,D,D,m,*u,*u") - (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,m,*u,m,*u,m") - (const_int 1))) - (clobber (match_scratch:HI 2 "=X,X,X,&d,&d,&d"))] - "" - "* -{ - CC_STATUS_INIT; - if (X_REG_P (operands[1])) - { - return \"xgdx\\n\\tlsrd\\n\\txgdx\\n\\trora\\n\\trorb\"; - } - else - { - rtx ops[2]; - - ops[1] = m68hc11_gen_highpart (HImode, operands[1]); - ops[0] = gen_rtx_REG (HImode, HARD_D_REGNUM); - m68hc11_gen_movhi (insn, ops); - output_asm_insn (\"lsrd\", ops); - if (!X_REG_P (operands[0])) - { - ops[1] = ops[0]; - ops[0] = m68hc11_gen_highpart (HImode, operands[0]); - m68hc11_gen_movhi (insn, ops); - ops[0] = ops[1]; - ops[1] = m68hc11_gen_lowpart (HImode, operands[1]); - m68hc11_gen_movhi (insn, ops); - } - else - { - /* Load the lowpart in X in case the operands is some N,x. */ - ops[0] = gen_rtx_REG (HImode, HARD_X_REGNUM); - ops[1] = m68hc11_gen_lowpart (HImode, operands[1]); - m68hc11_gen_movhi (insn, ops); - output_asm_insn (\"xgdx\", ops); - } - output_asm_insn (\"rora\", ops); - output_asm_insn (\"rorb\", ops); - if (!X_REG_P (operands[0])) - { - ops[1] = ops[0]; - ops[0] = m68hc11_gen_lowpart (HImode, operands[0]); - m68hc11_gen_movhi (insn, ops); - } - return \"\"; - } -}") - -(define_insn "*lshrsi3_const" - [(set (match_operand:SI 0 "register_operand" "+D") - (lshiftrt:SI (match_dup 0) - (match_operand:HI 1 "const_int_operand" ""))) - (clobber (match_scratch:HI 2 "=y"))] - "TARGET_M6811 /* See *lshrsi3 note. */" - "* -{ - CC_STATUS_INIT; - return \"ldy\\t%1\\n\\tbsr\\t___lshrsi3\"; -}") - -(define_insn "*lshrsi3" - [(set (match_operand:SI 0 "register_operand" "+D,D") - (lshiftrt:SI (match_dup 0) - (match_operand:HI 1 "general_operand" "y,mi"))) - (clobber (match_scratch:HI 2 "=1,X"))] - "" - "* -{ - CC_STATUS_INIT; - /* There is a reload problem if we don't accept 'm' for the shift value. - A RELOAD_OTHER reload can be generated for operand 0 (class A_REGS) - and this conflicts with all reloads. Since X, Y, Z are used there - is not enough register in class A_REGS. - - Assuming that 'operands[1]' does not refer to the stack (which - is true for 68hc11 only, we save temporary the value of Y. - - For 68HC12 we must also accept a constant because Z register is - disabled when compiling with -fomit-frame-pointer. We can come up - with a reload problem and the *lshrsi3_const pattern was disabled - for that reason. */ - if (!Y_REG_P (operands[2])) - { - rtx ops[1]; - int y_dead = dead_register_here (insn, iy_reg); - - ops[0] = operands[1]; - if (y_dead == 0) - { - output_asm_insn (\"pshy\", operands); - if (reg_mentioned_p (stack_pointer_rtx, operands[1])) - ops[0] = adjust_address (operands[1], GET_MODE (operands[1]), 2); - } - output_asm_insn (\"ldy\\t%0\", ops); - output_asm_insn (\"bsr\\t___lshrsi3\", operands); - return y_dead == 0 ? \"puly\" : \"\"; - } - return \"bsr\\t___lshrsi3\"; -}") - -(define_expand "lshrhi3" - [(set (match_operand:HI 0 "register_operand" "") - (lshiftrt:HI (match_operand:HI 1 "general_operand" "") - (match_operand:HI 2 "general_operand" "")))] - "" - " -{ - if (GET_CODE (operands[2]) != CONST_INT) - { - rtx scratch = gen_reg_rtx (HImode); - operand1 = force_reg (HImode, operand1); - - emit_move_insn (scratch, operands[2]); - emit_insn (gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, gen_rtx_SET (VOIDmode, - operand0, - gen_rtx_LSHIFTRT (HImode, - operand1, scratch)), - gen_rtx_CLOBBER (VOIDmode, scratch)))); - DONE; - } -}") - -(define_insn "lshrhi3_const1" - [(set (match_operand:HI 0 "non_push_operand" "=dm,!*u*A") - (lshiftrt:HI (match_operand:HI 1 "non_push_operand" "0,0") - (const_int 1)))] - "" - "* -{ - if (A_REG_P (operands[0])) - return \"#\"; - - if (D_REG_P (operands[0])) - return \"lsrd\"; - - CC_STATUS_INIT; - return \"lsr\\t%h0\\n\\tror\\t%b0\"; -}") - -(define_insn "lshrhi3_const" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,!*A,!*A") - (lshiftrt:HI (match_operand:HI 1 "general_operand" "dm*A,!u,dm,!u") - (match_operand:HI 2 "const_int_operand" "i,i,i,i")))] - "" - "* -{ - int val = INTVAL (operands[2]); - - if (A_REG_P (operands[0])) - return \"#\"; - - if (val >= 8) - { - if (val == 8) - CC_STATUS_INIT; - - if (!H_REG_P (operands[1])) - { - output_asm_insn (\"clra\", operands); - output_asm_insn (\"ldab\\t%h1\", operands); - } - else if (A_REG_P (operands[1])) - { - output_asm_insn (\"st%1\\t%t0\", operands); - output_asm_insn (\"ldab\\t%t0\", operands); - output_asm_insn (\"clra\", operands); - } - else - { - output_asm_insn (\"tab\", operands); - output_asm_insn (\"clra\", operands); - } - val -= 8; - switch (val) - { - case 7: - output_asm_insn (\"rolb\", operands); - output_asm_insn (\"tab\", operands); - output_asm_insn (\"rolb\", operands); - break; - - case 6: - output_asm_insn (\"rolb\", operands); - output_asm_insn (\"rolb\", operands); - output_asm_insn (\"rolb\", operands); - output_asm_insn (\"andb\\t#3\", operands); - break; - - default: - while (val > 0) - { - val --; - output_asm_insn (\"lsrb\", operands); - } - break; - } - return \"\"; - } - - if (!D_REG_P (operands[1])) - m68hc11_gen_movhi (insn, operands); - switch (val) - { - case 7: - output_asm_insn (\"rolb\", operands); - output_asm_insn (\"tab\", operands); - output_asm_insn (\"rolb\", operands); - output_asm_insn (\"rola\", operands); - output_asm_insn (\"rola\", operands); - output_asm_insn (\"anda\\t#1\", operands); - CC_STATUS_INIT; - break; - - default: - while (val > 0) - { - val --; - output_asm_insn (\"lsrd\", operands); - } - } - return \"\"; -}") - -(define_insn "*lshrhi3" - [(set (match_operand:HI 0 "register_operand" "=d,*x") - (lshiftrt:HI (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "register_operand" "+x,+d"))) - (clobber (match_dup 2))] - "" - "* -{ - if (A_REG_P (operands[0])) - return \"#\"; - - return \"bsr\\t___lshrhi3\"; -}") - -(define_expand "lshrqi3" - [(set (match_operand:QI 0 "register_operand" "") - (lshiftrt:QI (match_operand:QI 1 "register_operand" "") - (match_operand:QI 2 "general_operand" "")))] - "" - "") - -(define_insn "*lshrqi3_const1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=m,d,!u,!*q,!*A") - (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0,0,0,0") - (const_int 1)))] - "" - "@ - lsr\\t%b0 - lsrb - lsr\\t%b0 - lsr%0 - #") - -(define_insn "*lshrqi3_const" - [(set (match_operand:QI 0 "register_operand" "=d,!*q,!*A") - (lshiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0") - (match_operand:QI 2 "const_int_operand" "")))] - "" - "* -{ - int i; - const char* insn_code; - - if (D_REG_P (operands[0]) || DB_REG_P (operands[0])) - insn_code = \"lsrb\"; - else if (DA_REG_P (operands[0])) - insn_code = \"lsra\"; - else - return \"#\"; - - i = INTVAL (operands[2]); - if (i >= 8) - { - if (DA_REG_P (operands[0])) - return \"clra\"; - else - return \"clrb\"; - } - else if (i == 7) - { - if (DA_REG_P (operands[0])) - { - output_asm_insn (\"rola\", operands); - output_asm_insn (\"ldaa\\t#0\", operands); - return \"rola\"; - } - else - { - output_asm_insn (\"rolb\", operands); - output_asm_insn (\"ldab\\t#0\", operands); - return \"rolb\"; - } - } - else if (i == 6) - { - if (DA_REG_P (operands[0])) - { - output_asm_insn (\"rola\", operands); - output_asm_insn (\"rola\", operands); - output_asm_insn (\"rola\", operands); - return \"anda\\t#3\"; - } - else - { - output_asm_insn (\"rolb\", operands); - output_asm_insn (\"rolb\", operands); - output_asm_insn (\"rolb\", operands); - return \"andb\\t#3\"; - } - } - while (--i >= 0) - { - output_asm_insn (insn_code, operands); - } - return \"\"; -}") - -(define_insn "*lshrqi3" - [(set (match_operand:QI 0 "register_operand" "=d,!*q,!*A") - (lshiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0") - (match_operand:QI 2 "nonimmediate_operand" - "m*u*d*A,m*u*d*A,m*u")))] - "" - "* -{ - rtx ops[2]; - - if (!D_REG_P (operands[0]) && !Q_REG_P (operands[0])) - return \"#\"; - - CC_STATUS_INIT; - ops[0] = gen_rtx_REG (QImode, HARD_A_REGNUM); - ops[1] = operands[2]; - m68hc11_gen_movqi (insn, ops); - - if (!optimize || optimize_size) - { - return \"bsr\\t___lshrqi3\"; - } - - ops[0] = gen_label_rtx (); - ops[1] = gen_label_rtx (); - output_asm_insn (\"ble\\t%l1\", ops); - - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (ops[0])); - - output_asm_insn (\"lsrb\", operands); - output_asm_insn (\"deca\", operands); - output_asm_insn (\"bne\\t%l0\", ops); - - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (ops[1])); - return \"\"; -}") - -(define_insn "*rotlqi3_with_carry" - [(set (match_operand:QI 0 "register_operand" "=d,!q") - (rotate:QI (match_operand:QI 1 "register_operand" "0,0") - (reg:QI CC_REGNUM)))] - "" - "* -{ - if (DA_REG_P (operands[0])) - return \"rola\"; - else - return \"rolb\"; -}") - -(define_insn "*rotlhi3_with_carry" - [(set (match_operand:HI 0 "register_operand" "=d") - (rotate:HI (match_operand:HI 1 "register_operand" "0") - (const_int 1))) - (clobber (reg:HI CC_REGNUM))] - "" - "* -{ - CC_STATUS_INIT; - return \"rolb\\n\\trola\"; -}") - -(define_insn "*rotrhi3_with_carry" - [(set (match_operand:HI 0 "register_operand" "=d") - (rotatert:HI (match_operand:HI 1 "register_operand" "0") - (const_int 1))) - (clobber (reg:HI CC_REGNUM))] - "" - "* -{ - CC_STATUS_INIT; - return \"rora\\n\\trorb\"; -}") - -(define_insn "rotlqi3" - [(set (match_operand:QI 0 "register_operand" "=d,!q") - (rotate:QI (match_operand:QI 1 "register_operand" "0,0") - (match_operand:QI 2 "const_int_operand" "i,i")))] - "" - "* -{ - m68hc11_gen_rotate (ROTATE, insn, operands); - return \"\"; -}") - -(define_insn "rotrqi3" - [(set (match_operand:QI 0 "register_operand" "=d,!q") - (rotatert:QI (match_operand:QI 1 "register_operand" "0,0") - (match_operand:QI 2 "const_int_operand" "i,i")))] - "" - "* -{ - m68hc11_gen_rotate (ROTATERT, insn, operands); - return \"\"; -}") - -(define_expand "rotlhi3" - [(set (match_operand:HI 0 "register_operand" "") - (rotate:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" "")))] - "" - " -{ - if (GET_CODE (operands[2]) != CONST_INT) - { - rtx scratch = gen_reg_rtx (HImode); - operand1 = force_reg (HImode, operand1); - - emit_move_insn (scratch, operands[2]); - emit_insn (gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, gen_rtx_SET (VOIDmode, - operand0, - gen_rtx_ROTATE (HImode, - operand1, scratch)), - gen_rtx_CLOBBER (VOIDmode, scratch)))); - DONE; - } -}") - -(define_insn "rotlhi3_const" - [(set (match_operand:HI 0 "register_operand" "=d") - (rotate:HI (match_operand:HI 1 "register_operand" "0") - (match_operand:HI 2 "const_int_operand" "i")))] - "" - "* -{ - m68hc11_gen_rotate (ROTATE, insn, operands); - return \"\"; -}") - -(define_insn "*rotlhi3" - [(set (match_operand:HI 0 "register_operand" "=d,*x") - (rotate:HI (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "general_operand" "+x,+d"))) - (clobber (match_dup 2))] - "" - "* -{ - if (A_REG_P (operands[0])) - return \"#\"; - - return \"bsr\\t___rotlhi3\"; -}") - -(define_expand "rotrhi3" - [(set (match_operand:HI 0 "register_operand" "") - (rotatert:HI (match_operand:HI 1 "general_operand" "") - (match_operand:HI 2 "general_operand" "")))] - "" - " -{ - if (GET_CODE (operands[2]) != CONST_INT) - { - rtx scratch = gen_reg_rtx (HImode); - operand1 = force_reg (HImode, operand1); - - emit_move_insn (scratch, operands[2]); - emit_insn (gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, gen_rtx_SET (VOIDmode, - operand0, - gen_rtx_ROTATERT (HImode, - operand1, scratch)), - gen_rtx_CLOBBER (VOIDmode, scratch)))); - DONE; - } -}") - -(define_insn "rotrhi3_const" - [(set (match_operand:HI 0 "register_operand" "=d") - (rotatert:HI (match_operand:HI 1 "register_operand" "0") - (match_operand:HI 2 "const_int_operand" "i")))] - "" - "* -{ - m68hc11_gen_rotate (ROTATERT, insn, operands); - return \"\"; -}") - -(define_insn "*rotrhi3" - [(set (match_operand:HI 0 "register_operand" "=d,*x") - (rotatert:HI (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "general_operand" "+x,+d"))) - (clobber (match_dup 2))] - "" - "* -{ - if (A_REG_P (operands[0])) - return \"#\"; - - return \"bsr\\t___rotrhi3\"; -}") - -;; Split a shift operation on an address register in a shift -;; on D_REGNUM. -(define_split /* "*rotrhi3_addr" */ - [(set (match_operand:HI 0 "hard_addr_reg_operand" "") - (match_operator:HI 3 "m68hc11_shift_operator" - [(match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "register_operand" "")])) - (clobber (match_dup 2))] - "z_replacement_completed == 2" - [(parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))]) - (parallel [(set (reg:HI D_REGNUM) - (match_op_dup 3 [(reg:HI D_REGNUM) (match_dup 0)])) - (clobber (match_dup 0))]) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))])] - "") - -;;-------------------------------------------------------------------- -;;- 68HC12 Decrement/Increment and branch -;;-------------------------------------------------------------------- -;; These patterns are used by loop optimization as well as peephole2 -;; They must handle reloading themselves and the scratch register -;; is used for that. Even if we accept memory operand, we must not -;; accept them on the predicate because it might create too many reloads. -;; (specially on HC12 due to its auto-incdec addressing modes). -;; -(define_expand "decrement_and_branch_until_zero" - [(parallel [(set (pc) - (if_then_else - (ne (plus:HI (match_operand:HI 0 "register_operand" "") - (const_int 0)) - (const_int 1)) - (label_ref (match_operand 1 "" "")) - (pc))) - (set (match_dup 0) - (plus:HI (match_dup 0) - (const_int -1))) - (clobber (match_scratch:HI 2 ""))])] - "TARGET_M6812" - "") - -(define_expand "doloop_end" - [(use (match_operand 0 "" "")) ; loop pseudo - (use (match_operand 1 "" "")) ; iterations; zero if unknown - (use (match_operand 2 "" "")) ; max iterations - (use (match_operand 3 "" "")) ; loop level - (use (match_operand 4 "" ""))] ; label - "TARGET_M6812" - " -{ - /* Reject non-constant loops as it generates bigger code due to - the handling of the loop register. We can do better by using - the peephole2 dbcc/ibcc patterns. */ - if (INTVAL (operands[1]) == 0) - { - FAIL; - } - - /* Note that for xxx_dbcc_dec_yy the gen_rtx_NE is only used to pass - the operator and its operands are not relevant. */ - if (GET_MODE (operands[0]) == HImode) - { - emit_jump_insn (gen_m68hc12_dbcc_dec_hi (operands[0], - gen_rtx_NE (HImode, - operands[0], - const1_rtx), - operands[4])); - DONE; - } - if (GET_MODE (operands[0]) == QImode) - { - emit_jump_insn (gen_m68hc12_dbcc_dec_qi (operands[0], - gen_rtx_NE (QImode, - operands[0], - const1_rtx), - operands[4])); - DONE; - } - - FAIL; -}") - -;; Decrement-and-branch insns. -(define_insn "m68hc12_dbcc_dec_hi" - [(set (pc) - (if_then_else - (match_operator 1 "m68hc11_eq_compare_operator" - [(match_operand:HI 0 "register_operand" "+dxy,m*u*z") - (const_int 1)]) - (label_ref (match_operand 2 "" "")) - (pc))) - (set (match_dup 0) - (plus:HI (match_dup 0) (const_int -1))) - (clobber (match_scratch:HI 3 "=X,dxy"))] - "TARGET_M6812" - "* -{ - if (!H_REG_P (operands[0])) - return \"#\"; - - CC_STATUS_INIT; - if (GET_CODE (operands[1]) == EQ) - return \"dbeq\\t%0,%l2\"; - else - return \"dbne\\t%0,%l2\"; -}") - -;; Decrement-and-branch insns. -(define_insn "m68hc12_dbcc_inc_hi" - [(set (pc) - (if_then_else - (match_operator 1 "m68hc11_eq_compare_operator" - [(match_operand:HI 0 "register_operand" "+dxy,m*u*z") - (const_int -1)]) - (label_ref (match_operand 2 "" "")) - (pc))) - (set (match_dup 0) - (plus:HI (match_dup 0) (const_int 1))) - (clobber (match_scratch:HI 3 "=X,dxy"))] - "TARGET_M6812" - "* -{ - if (!H_REG_P (operands[0])) - return \"#\"; - - CC_STATUS_INIT; - if (GET_CODE (operands[1]) == EQ) - return \"ibeq\\t%0,%l2\"; - else - return \"ibeq\\t%0,%l2\"; -}") - -;; Decrement-and-branch (QImode). -(define_insn "m68hc12_dbcc_dec_qi" - [(set (pc) - (if_then_else - (match_operator 1 "m68hc11_eq_compare_operator" - [(match_operand:QI 0 "register_operand" "+d,m*u*A") - (const_int 1)]) - (label_ref (match_operand 2 "" "")) - (pc))) - (set (match_dup 0) - (plus:QI (match_dup 0) (const_int -1))) - (clobber (match_scratch:QI 3 "=X,d"))] - "TARGET_M6812" - "* -{ - if (!D_REG_P (operands[0])) - return \"#\"; - - CC_STATUS_INIT; - if (GET_CODE (operands[1]) == EQ) - return \"dbeq\\tb,%l2\"; - else - return \"dbne\\tb,%l2\"; -}") - -;; Increment-and-branch (QImode). -(define_insn "m68hc12_dbcc_inc_qi" - [(set (pc) - (if_then_else - (match_operator 1 "m68hc11_eq_compare_operator" - [(match_operand:QI 0 "register_operand" "+d,m*u*A") - (const_int -1)]) - (label_ref (match_operand 2 "" "")) - (pc))) - (set (match_dup 0) - (plus:QI (match_dup 0) (const_int 1))) - (clobber (match_scratch:QI 3 "=X,d"))] - "TARGET_M6812" - "* -{ - if (!D_REG_P (operands[0])) - return \"#\"; - - CC_STATUS_INIT; - if (GET_CODE (operands[1]) == EQ) - return \"ibeq\\tb,%l2\"; - else - return \"ibeq\\tb,%l2\"; -}") - -;; Split the above to handle the case where operand 0 is in memory -;; (a register that couldn't get a hard register) -(define_split - [(set (pc) - (if_then_else - (match_operator 3 "m68hc11_eq_compare_operator" - [(match_operand:HI 0 "general_operand" "") - (match_operand:HI 1 "const_int_operand" "")]) - (label_ref (match_operand 4 "" "")) - (pc))) - (set (match_dup 0) - (plus:HI (match_dup 0) (match_operand 2 "const_int_operand" ""))) - (clobber (match_operand:HI 5 "hard_reg_operand" ""))] - "TARGET_M6812 && reload_completed" - [(set (match_dup 5) (match_dup 0)) - (set (match_dup 5) (plus:HI (match_dup 5) (match_dup 2))) - (set (match_dup 0) (match_dup 5)) - (set (pc) - (if_then_else (match_op_dup 3 - [(match_dup 5) (const_int 0)]) - (label_ref (match_dup 4)) (pc)))] - "") - -;; Split the above to handle the case where operand 0 is in memory -;; (a register that couldn't get a hard register) -(define_split - [(set (pc) - (if_then_else - (match_operator 3 "m68hc11_eq_compare_operator" - [(match_operand:QI 0 "general_operand" "") - (match_operand:QI 1 "const_int_operand" "")]) - (label_ref (match_operand 4 "" "")) - (pc))) - (set (match_dup 0) - (plus:QI (match_dup 0) (match_operand 2 "const_int_operand" ""))) - (clobber (match_operand:QI 5 "hard_reg_operand" ""))] - "TARGET_M6812 && reload_completed" - [(set (match_dup 5) (match_dup 0)) - (set (match_dup 5) (plus:QI (match_dup 5) (match_dup 2))) - (set (match_dup 0) (match_dup 5)) - (set (pc) - (if_then_else (match_op_dup 3 - [(match_dup 5) (const_int 0)]) - (label_ref (match_dup 4)) (pc)))] - "") - -;;-------------------------------------------------------------------- -;;- Jumps and transfers -;;-------------------------------------------------------------------- -(define_insn "jump" - [(set (pc) - (label_ref (match_operand 0 "" "")))] - "" - "bra\\t%l0") - -(define_expand "cbranchsi4" - [(set (cc0) - (compare (match_operand:SI 1 "tst_operand" "") - (match_operand:SI 2 "cmp_operand" ""))) - (set (pc) - (if_then_else (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "" - " -{ - if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[2]) == MEM) - operands[1] = force_reg (SImode, operands[1]); - - m68hc11_expand_compare_and_branch (GET_CODE (operands[0]), operands[1], - operands[2], operands[3]); - DONE; -}") - -(define_expand "cbranchhi4" - [(set (cc0) - (compare (match_operand:HI 1 "tst_operand" "") - (match_operand:HI 2 "cmp_operand" ""))) - (set (pc) - (if_then_else (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "" - " -{ - if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[2]) == MEM) - operands[1] = force_reg (HImode, operands[1]); - - m68hc11_expand_compare_and_branch (GET_CODE (operands[0]), operands[1], - operands[2], operands[3]); - DONE; -}") - -(define_expand "cbranchqi4" - [(set (cc0) - (compare (match_operand:QI 1 "tst_operand" "") - (match_operand:QI 2 "cmp_operand" ""))) - (set (pc) - (if_then_else (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "" - " -{ - if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[2]) == MEM) - operands[1] = force_reg (QImode, operands[1]); - - m68hc11_expand_compare_and_branch (GET_CODE (operands[0]), operands[1], - operands[2], operands[3]); - DONE; -}") - - -;; -;; Test and branch instructions for 68HC12 for EQ and NE. -;; 'z' must not appear in the constraints because the z replacement -;; pass does not know how to restore the replacement register. -;; -(define_insn "*tbeq" - [(set (pc) - (if_then_else (eq (match_operand:HI 0 "register_operand" "dxy") - (const_int 0)) - (label_ref (match_operand 1 "" "")) - (pc)))] - "TARGET_M6812" - "* -{ - /* If the flags are already set correctly, use 'bne/beq' which are - smaller and a little bit faster. This happens quite often due - to reloading of operands[0]. In that case, flags are set correctly - due to the load instruction. */ - if ((cc_status.value1 && rtx_equal_p (cc_status.value1, operands[0])) - || (cc_status.value2 && rtx_equal_p (cc_status.value2, operands[0]))) - return \"beq\\t%l1\"; - else - return \"tbeq\\t%0,%l1\"; -}") - -(define_insn "*tbne" - [(set (pc) - (if_then_else (ne (match_operand:HI 0 "register_operand" "dxy") - (const_int 0)) - (label_ref (match_operand 1 "" "")) - (pc)))] - "TARGET_M6812" - "* -{ - if ((cc_status.value1 && rtx_equal_p (cc_status.value1, operands[0])) - || (cc_status.value2 && rtx_equal_p (cc_status.value2, operands[0]))) - return \"bne\\t%l1\"; - else - return \"tbne\\t%0,%l1\"; -}") - -;; -;; Test and branch with 8-bit register. Register must be B (or A). -;; -(define_insn "*tbeq8" - [(set (pc) - (if_then_else (eq (match_operand:QI 0 "register_operand" "d") - (const_int 0)) - (label_ref (match_operand 1 "" "")) - (pc)))] - "TARGET_M6812" - "* -{ - if ((cc_status.value1 && rtx_equal_p (cc_status.value1, operands[0])) - || (cc_status.value2 && rtx_equal_p (cc_status.value2, operands[0]))) - return \"beq\\t%l1\"; - else - return \"tbeq\\tb,%l1\"; -}") - -(define_insn "*tbne8" - [(set (pc) - (if_then_else (ne (match_operand:QI 0 "register_operand" "d") - (const_int 0)) - (label_ref (match_operand 1 "" "")) - (pc)))] - "TARGET_M6812" - "* -{ - if ((cc_status.value1 && rtx_equal_p (cc_status.value1, operands[0])) - || (cc_status.value2 && rtx_equal_p (cc_status.value2, operands[0]))) - return \"bne\\t%l1\"; - else - return \"tbne\\tb,%l1\"; -}") - -(define_insn "*beq" - [(set (pc) - (if_then_else (eq (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "beq\\t%l0") - -(define_insn "*bne" - [(set (pc) - (if_then_else (ne (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "bne\\t%l0") - -(define_insn "*bgt" - [(set (pc) - (if_then_else (gt (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "bgt\\t%l0") - -(define_insn "*bgtu" - [(set (pc) - (if_then_else (gtu (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "bhi\\t%l0") - -(define_insn "*blt" - [(set (pc) - (if_then_else (lt (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "* -{ - if (cc_prev_status.flags & CC_NO_OVERFLOW) - return \"bmi\\t%l0\"; - else - return \"blt\\t%l0\"; -}") - -(define_insn "*bltu" - [(set (pc) - (if_then_else (ltu (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "blo\\t%l0") - -(define_insn "*bge" - [(set (pc) - (if_then_else (ge (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "* -{ - if (cc_prev_status.flags & CC_NO_OVERFLOW) - return \"bpl\\t%l0\"; - else - return \"bge\\t%l0\"; -}") - -(define_insn "*bgeu" - [(set (pc) - (if_then_else (geu (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "bhs\\t%l0") - -(define_insn "*ble" - [(set (pc) - (if_then_else (le (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "* -{ - if (cc_prev_status.flags & CC_NO_OVERFLOW) - return \"bmi\\t%l0\\n\\tbeq\\t%l0\"; - else - return \"ble\\t%l0\"; -}") - -(define_insn "*bleu" - [(set (pc) - (if_then_else (leu (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "bls\\t%l0") - -;;-------------------------------------------------------------------- -;;- Negative test and branch -;;-------------------------------------------------------------------- -(define_insn "" - [(set (pc) - (if_then_else (eq (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "bne\\t%l0") - -(define_insn "" - [(set (pc) - (if_then_else (ne (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "beq\\t%l0") - -(define_insn "" - [(set (pc) - (if_then_else (gt (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "* -{ - if (cc_prev_status.flags & CC_NO_OVERFLOW) - return \"bmi\\t%l0\\n\\tbeq\\t%l0\"; - else - return \"ble\\t%l0\"; -}") - -(define_insn "" - [(set (pc) - (if_then_else (gtu (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "bls\\t%l0") - -(define_insn "" - [(set (pc) - (if_then_else (lt (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "* -{ - if (cc_prev_status.flags & CC_NO_OVERFLOW) - return \"bpl\\t%l0\"; - else - return \"bge\\t%l0\"; -}") - -(define_insn "" - [(set (pc) - (if_then_else (ltu (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "bhs\\t%l0") - -(define_insn "" - [(set (pc) - (if_then_else (ge (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "* -{ - if (cc_prev_status.flags & CC_NO_OVERFLOW) - return \"bmi\\t%l0\"; - else - return \"blt\\t%l0\"; -}") - -(define_insn "" - [(set (pc) - (if_then_else (geu (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "blo\\t%l0") - -(define_insn "" - [(set (pc) - (if_then_else (le (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "bgt\\t%l0") - -(define_insn "" - [(set (pc) - (if_then_else (leu (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "bhi\\t%l0") - -;;-------------------------------------------------------------------- -;;- Calls -;;-------------------------------------------------------------------- -;; -;;- Call a function that returns no value. -(define_insn "call" - [(call (match_operand:QI 0 "memory_operand" "m") - (match_operand:SI 1 "general_operand" "g"))] - ;; Operand 1 not really used on the m68hc11. - "" - "* -{ - if (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF) - { - if (m68hc11_is_far_symbol (operands[0])) - { - if (TARGET_M6812) - { - output_asm_insn (\"call\\t%0\", operands); - return \"\"; - } - else - { - output_asm_insn (\"pshb\", operands); - output_asm_insn (\"ldab\\t#%%page(%0)\", operands); - output_asm_insn (\"ldy\\t#%%addr(%0)\", operands); - return \"jsr\\t__call_a32\"; - } - } - if (m68hc11_is_trap_symbol (operands[0])) - return \"swi\"; - else - return \"bsr\\t%0\"; - } - else - { - return \"jsr\\t%0\"; - } -}") - -(define_insn "call_value" - [(set (match_operand 0 "" "=g") - (call (match_operand:QI 1 "memory_operand" "m") - (match_operand:SI 2 "general_operand" "g")))] - "" - "* -{ - if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF) - { - if (m68hc11_is_far_symbol (operands[1])) - { - if (TARGET_M6812) - { - output_asm_insn (\"call\\t%1\", operands); - return \"\"; - } - else - { - output_asm_insn (\"pshb\", operands); - output_asm_insn (\"ldab\\t#%%page(%1)\", operands); - output_asm_insn (\"ldy\\t#%%addr(%1)\", operands); - return \"jsr\\t__call_a32\"; - } - } - if (m68hc11_is_trap_symbol (operands[1])) - return \"swi\"; - else - return \"bsr\\t%1\"; - } - else - { - return \"jsr\\t%1\"; - } -}") - -;; Call subroutine returning any type. - -(define_expand "untyped_call" - [(parallel [(call (match_operand 0 "" "") - (const_int 0)) - (match_operand 1 "" "") - (match_operand 2 "" "")])] - "" - " -{ - int i; - - emit_call_insn (gen_call (operands[0], const0_rtx)); - - for (i = 0; i < XVECLEN (operands[2], 0); i++) - { - rtx set = XVECEXP (operands[2], 0, i); - emit_move_insn (SET_DEST (set), SET_SRC (set)); - } - - /* The optimizer does not know that the call sets the function value - registers we stored in the result block. We avoid problems by - claiming that all hard registers are used and clobbered at this - point. */ - emit_insn (gen_blockage ()); - - DONE; -}") - -;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and -;; all of memory. This blocks insns from being moved across this point. - -(define_insn "blockage" - [(unspec_volatile [(const_int 0)] 0)] - "" - "") - -(define_insn "nop" - [(const_int 0)] - "" - "nop") - -(define_expand "prologue" - [(const_int 0)] - "" - " -{ - expand_prologue (); - DONE; -}") - -(define_expand "epilogue" - [(return)] - "" - " -{ - expand_epilogue (); - DONE; -}") - -;; Used for frameless functions which save no regs and allocate no locals. -(define_expand "return" - [(return)] - "reload_completed && m68hc11_total_frame_size () == 0" - " -{ - int ret_size = 0; - - if (crtl->return_rtx) - ret_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx)); - - /* Emit use notes only when HAVE_return is true. */ - if (m68hc11_total_frame_size () != 0) - ret_size = 0; - - if (ret_size && ret_size <= 2) - { - emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, gen_rtx_RETURN (VOIDmode), - gen_rtx_USE (VOIDmode, - gen_rtx_REG (HImode, 1))))); - DONE; - } - if (ret_size) - { - emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, gen_rtx_RETURN (VOIDmode), - gen_rtx_USE (VOIDmode, - gen_rtx_REG (SImode, 0))))); - DONE; - } -}") - -(define_insn "*return_void" - [(return)] - "reload_completed" - "* -{ - rtx next = next_active_insn (insn); - - if (next - && GET_CODE (next) == JUMP_INSN - && GET_CODE (PATTERN (next)) == RETURN) - return \"\"; - if (current_function_interrupt || current_function_trap) - return \"rti\"; - else if (!current_function_far) - return \"rts\"; - else if (TARGET_M6812) - return \"rtc\"; - else - { - int ret_size = 0; - - if (crtl->return_rtx) - ret_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx)); - - if (ret_size == 0) - return \"jmp\\t__return_void\"; - if (ret_size <= 2) - return \"jmp\\t__return_16\"; - if (ret_size <= 4) - return \"jmp\\t__return_32\"; - return \"jmp\\t__return_16\"; - } -}") - -(define_insn "*return_16bit" - [(return) - (use (reg:HI D_REGNUM))] - "reload_completed && m68hc11_total_frame_size () == 0" - "* -{ - rtx next = next_active_insn (insn); - - if (next - && GET_CODE (next) == JUMP_INSN - && GET_CODE (PATTERN (next)) == RETURN) - return \"\"; - if (current_function_interrupt || current_function_trap) - return \"rti\"; - else if (!current_function_far) - return \"rts\"; - else if (TARGET_M6812) - return \"rtc\"; - else - return \"jmp\\t__return_16\"; -}") - -(define_insn "*return_32bit" - [(return) - (use (reg:SI 0))] - "reload_completed && m68hc11_total_frame_size () == 0" - "* -{ - rtx next = next_active_insn (insn); - - if (next - && GET_CODE (next) == JUMP_INSN - && GET_CODE (PATTERN (next)) == RETURN) - return \"\"; - if (current_function_interrupt || current_function_trap) - return \"rti\"; - else if (!current_function_far) - return \"rts\"; - else if (TARGET_M6812) - return \"rtc\"; - else - return \"jmp\\t__return_32\"; -}") - -(define_insn "indirect_jump" - [(set (pc) (match_operand:HI 0 "nonimmediate_operand" "xy"))] - "" - "jmp\\t0,%0") - -;;-------------------------------------------------------------------- -;;- Table jump -;;-------------------------------------------------------------------- -;; -;; Operand 0 is the address of the table element to use -;; operand 1 is the CODE_LABEL for the table -;;-------------------------------------------------------------------- -(define_expand "tablejump" - [(parallel [(set (pc) (match_operand 0 "" "")) - (use (label_ref (match_operand 1 "" "")))])] - "" - "") - -(define_insn "*jump_indirect" - [(parallel [ - (set (pc) (match_operand:HI 0 "register_operand" "xy")) - (use (label_ref (match_operand 1 "" "")))])] - "" - "jmp\\t0,%0") - -;;-------------------------------------------------------------------- -;;- Peepholes -;;-------------------------------------------------------------------- - -;;-------------------------------------------------------------------- -;;- 68HC12 dbcc/ibcc peepholes -;;-------------------------------------------------------------------- -;; -;; Replace: "addd #-1; bne L1" into "dbne d,L1" -;; "addd #-1; beq L1" into "dbeq d,L1" -;; "addd #1; bne L1" into "ibne d,L1" -;; "addd #1; beq L1" into "ibeq d,L1" -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (plus:HI (match_dup 0) - (match_operand:HI 1 "const_int_operand" ""))) - (set (pc) - (if_then_else (match_operator 2 "m68hc11_eq_compare_operator" - [(match_dup 0) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) (pc)))] - "TARGET_M6812 && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1)" - [(parallel [ - (set (pc) (if_then_else (match_op_dup 2 [(match_dup 0) (match_dup 5)]) - (label_ref (match_dup 3)) (pc))) - (set (match_dup 0) (plus:HI (match_dup 0) (match_dup 1))) - (clobber (match_dup 4))])] - "operands[4] = gen_rtx_SCRATCH(HImode); - operands[5] = GEN_INT (-INTVAL (operands[1]));") - - -;; -;; Replace: "addb #-1; bne L1" into "dbne b,L1" -;; "addb #-1; beq L1" into "dbeq b,L1" -;; -(define_peephole2 - [(set (match_operand:QI 0 "hard_reg_operand" "") - (plus:QI (match_dup 0) - (match_operand:QI 1 "const_int_operand" ""))) - (set (pc) - (if_then_else (match_operator 2 "m68hc11_eq_compare_operator" - [(match_dup 0) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) (pc)))] - "TARGET_M6812 && D_REG_P (operands[0]) - && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1)" - [(parallel [ - (set (pc) (if_then_else (match_op_dup 2 [(match_dup 0) (match_dup 5)]) - (label_ref (match_dup 3)) (pc))) - (set (match_dup 0) (plus:QI (match_dup 0) (match_dup 1))) - (clobber (match_dup 4))])] - "operands[4] = gen_rtx_SCRATCH(QImode); - operands[5] = GEN_INT (-INTVAL (operands[1]));") - - -;;-------------------------------------------------------------------- -;;- Move peephole2 -;;-------------------------------------------------------------------- - -;; -;; Replace "leas 2,sp" with a "pulx" or a "puly". -;; On 68HC12, this is one cycle slower but one byte smaller. -;; pr target/6899: This peephole was not valid because a register CSE -;; pass removes the pulx/puly. The 'use' clause ensure that the pulx is -;; not removed. -;; -(define_peephole2 - [(set (reg:HI SP_REGNUM) (plus:HI (reg:HI SP_REGNUM) (const_int 2))) - (match_scratch:HI 0 "xy")] - "TARGET_M6812 && optimize_size" - [(set (match_dup 0) (match_dup 1)) - (use (match_dup 0))] - "operands[1] = gen_rtx_MEM (HImode, - gen_rtx_POST_INC (HImode, - gen_rtx_REG (HImode, HARD_SP_REGNUM)));") - -;; Replace: "pshx; tfr d,x; stx 0,sp" into "pshd; tfr d,x" -;; -;; PR 14542: emit a use to pretend we need the value of initial register. -;; Otherwise verify_local_live_at_start will die due to a live change -;; of that register. -;; -(define_peephole2 - [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) - (match_operand:HI 0 "hard_reg_operand" "")) - (set (match_dup 0) - (match_operand:HI 1 "hard_reg_operand" "")) - (set (mem:HI (reg:HI SP_REGNUM)) - (match_dup 0))] - "TARGET_M6812" - [(use (match_dup 0)) - (set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) - (match_dup 1)) - (set (match_dup 0) (match_dup 1))] - "") - -;; -;; Change: "ldd 0,sp; pulx" into "puld" -;; This sequence usually appears at end a functions. -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (mem:HI (reg:HI SP_REGNUM))) - (use (match_dup 0)) - (set (match_operand:HI 1 "hard_reg_operand" "") - (mem:HI (post_inc:HI (reg:HI SP_REGNUM))))] - "peep2_reg_dead_p (2, operands[1])" - [(set (match_dup 0) (mem:HI (post_inc:HI (reg:HI SP_REGNUM)))) - (use (match_dup 0))] - "") - -;; Replace: "pshx; clr 0,sp; clr 1,sp" by "clr 1,-sp; clr 1,-sp" -;; Appears to allocate local variables. -(define_peephole2 - [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) - (match_operand:HI 0 "hard_reg_operand" "")) - (set (mem:QI (plus:HI (reg:HI SP_REGNUM) (const_int 1))) - (const_int 0)) - (set (mem:QI (reg:HI SP_REGNUM)) - (const_int 0))] - "TARGET_M6812" - [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) - (const_int 0))] - "") - -;; Likewise for HI mode -(define_peephole2 - [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) - (match_operand:HI 0 "hard_reg_operand" "")) - (set (mem:HI (reg:HI SP_REGNUM)) - (const_int 0))] - "TARGET_M6812" - [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) - (const_int 0))] - "") -;;-------------------------------------------------------------------- -;;- -;;-------------------------------------------------------------------- -;; -;; Optimize memory<->memory moves when the value is also loaded in -;; a register. -;; -(define_peephole2 - [(set (match_operand:QI 0 "memory_operand" "") - (match_operand:QI 1 "memory_operand" "")) - (set (reg:QI D_REGNUM) - (match_operand:QI 2 "memory_operand" ""))] - "(rtx_equal_p (operands[0], operands[2]) && !side_effects_p (operands[0])) - || (GET_CODE (XEXP (operands[0], 0)) == REG - && GET_CODE (XEXP (operands[2], 0)) == POST_INC - && rtx_equal_p (XEXP (operands[0], 0), XEXP (XEXP (operands[2], 0), 0)))" - [(set (reg:QI D_REGNUM) (match_dup 1)) - (set (match_dup 2) (reg:QI D_REGNUM))] - "") - -;; -;; Remove a possible move before a compare instruction when that -;; move will go in a dead register. Compare with the source then. -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "hard_reg_operand" "")) - (set (cc0) - (compare (match_dup 0) - (match_operand:HI 2 "cmp_operand" "")))] - "(X_REG_P (operands[1]) || Y_REG_P (operands[1])) - && peep2_reg_dead_p (2, operands[0]) - && !reg_mentioned_p (operands[0], operands[2])" - [(set (cc0) (compare (match_dup 1) (match_dup 2)))] - "") - -;; -;; Optimize loading a constant to memory when that same constant -;; is loaded to a hard register. Switch the two to use the register -;; for memory initialization. In most cases, the constant is 0. -;; -(define_peephole2 - [(set (match_operand:HI 0 "memory_operand" "") - (match_operand:HI 1 "immediate_operand" "")) - (set (match_operand:HI 2 "hard_reg_operand" "") - (match_dup 1))] - "(D_REG_P (operands[2]) || X_REG_P (operands[2]) || Y_REG_P (operands[2])) - && !reg_mentioned_p (operands[2], operands[0])" - [(set (match_dup 2) (match_dup 1)) - (set (match_dup 0) (match_dup 2))] - "") - -;; -;; Reorganize to optimize address computations. -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "const_int_operand" "")) - (set (match_dup 0) - (plus:HI (match_dup 0) - (match_operand:HI 2 "general_operand" "")))] - "(INTVAL (operands[1]) >= -2 && INTVAL (operands[1]) <= 2)" - [(set (match_dup 0) (match_dup 2)) - (set (match_dup 0) (plus:HI (match_dup 0) (match_dup 1)))] - "") - -;; -;; Replace: "ldx #N; xgdx; addd <var>; xgdx" by "ldab #N; ldx <var>; abx" -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "const_int_operand" "")) - (set (match_dup 0) - (plus:HI (match_dup 0) - (match_operand:HI 2 "general_operand" ""))) - (match_scratch:QI 3 "d")] - "TARGET_M6811 && (INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 0x0ff)" - [(set (match_dup 3) (match_dup 4)) - (set (match_dup 0) (match_dup 2)) - (set (match_dup 0) (plus:HI (zero_extend:HI (match_dup 3)) (match_dup 0)))] - "operands[4] = m68hc11_gen_lowpart (QImode, operands[1]);") - -;; -;; Replace: "ldx #N; xgdx; addd <var>; xgdx" by "ldab #N; ldx <var>; abx" -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "const_int_operand" "")) - (set (match_dup 0) - (plus:HI (match_dup 0) - (match_operand:HI 2 "general_operand" "")))] - "TARGET_M6812" - [(set (match_dup 0) (match_dup 2)) - (set (match_dup 0) (plus:HI (match_dup 0) (match_dup 1)))] - "") - -;; -;; Optimize an address register increment and a compare to use -;; a PRE_INC or PRE_DEC addressing mode (disabled on the tst insn -;; before reload, but can be enabled after). -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (plus:HI (match_dup 0) - (match_operand:HI 1 "const_int_operand" ""))) - (set (cc0) - (compare (match_operand:QI 2 "memory_operand" "") - (const_int 0)))] - "TARGET_AUTO_INC_DEC - && (INTVAL (operands[1]) == -1 || INTVAL (operands[1]) == 1) - && reg_mentioned_p (operands[0], operands[2])" - [(set (cc0) - (compare (match_dup 3) - (const_int 0)))] - "if (INTVAL (operands[1]) == 1) - operands[3] = gen_rtx_MEM (QImode, - gen_rtx_PRE_INC (HImode, operands[0])); - else - operands[3] = gen_rtx_MEM (QImode, - gen_rtx_PRE_DEC (HImode, operands[0])); - ") - -;; -;; Likewise for compare. -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (plus:HI (match_dup 0) - (match_operand:HI 1 "const_int_operand" ""))) - (set (cc0) - (compare (match_operand:QI 2 "hard_reg_operand" "") - (match_operand:QI 3 "memory_operand" "")))] - "TARGET_AUTO_INC_DEC - && (INTVAL (operands[1]) == -1 || INTVAL (operands[1]) == 1) - && reg_mentioned_p (operands[0], operands[3])" - [(set (cc0) (compare (match_dup 2) (match_dup 4)))] - "if (INTVAL (operands[1]) == 1) - operands[4] = gen_rtx_MEM (QImode, - gen_rtx_PRE_INC (HImode, operands[0])); - else - operands[4] = gen_rtx_MEM (QImode, - gen_rtx_PRE_DEC (HImode, operands[0])); - ") - -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (plus:HI (match_dup 0) - (match_operand:HI 1 "const_int_operand" ""))) - (set (cc0) - (compare (match_operand:QI 2 "memory_operand" "") - (match_operand:QI 3 "hard_reg_operand" "")))] - "TARGET_AUTO_INC_DEC - && (INTVAL (operands[1]) == -1 || INTVAL (operands[1]) == 1) - && reg_mentioned_p (operands[0], operands[2])" - [(set (cc0) (compare (match_dup 4) (match_dup 3)))] - "if (INTVAL (operands[1]) == 1) - operands[4] = gen_rtx_MEM (QImode, - gen_rtx_PRE_INC (HImode, operands[0])); - else - operands[4] = gen_rtx_MEM (QImode, - gen_rtx_PRE_DEC (HImode, operands[0])); - ") - -;; -;; Replace a "ldx #N; addx <sp>" with a "ldx <sp>; addx #n" -;; (avoids many temporary moves because we can't add sp to another reg easily) -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "const_int_operand" "")) - (set (match_dup 0) (plus:HI (match_dup 0) (reg:HI SP_REGNUM)))] - "" - [(set (match_dup 0) (reg:HI SP_REGNUM)) - (set (match_dup 0) (plus:HI (match_dup 0) (match_dup 1)))] - "") - -;; -;; Replace "ldd #N; addd <op>" with "ldd <op>; addd #N". -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "const_int_operand" "")) - (set (match_dup 0) - (plus:HI (match_dup 0) - (match_operand:HI 2 "general_operand" "")))] - "(INTVAL (operands[1]) >= -2 && INTVAL (operands[1]) <= 2)" - [(set (match_dup 0) (match_dup 2)) - (set (match_dup 0) (plus:HI (match_dup 0) (match_dup 1)))] - "") - -;; -;; -;; -(define_peephole2 - [(parallel - [(set (match_operand:SI 0 "hard_reg_operand" "") - (ashift:SI (match_operand:SI 1 "general_operand" "") - (const_int 1))) - (clobber (match_scratch:HI 2 ""))]) - (set (match_operand:HI 3 "nonimmediate_operand" "") (reg:HI D_REGNUM)) - (set (match_operand:HI 4 "nonimmediate_operand" "") (reg:HI X_REGNUM))] - "!X_REG_P (operands[1]) - && peep2_reg_dead_p (2, gen_rtx_REG (HImode, D_REGNUM)) - && peep2_reg_dead_p (3, gen_rtx_REG (HImode, X_REGNUM))" - [(set (reg:HI D_REGNUM) (match_dup 5)) - (set (reg:HI D_REGNUM) (ashift:HI (reg:HI D_REGNUM) (const_int 1))) - (set (match_dup 3) (reg:HI D_REGNUM)) - (set (reg:HI D_REGNUM) (match_dup 6)) - (parallel [(set (reg:HI D_REGNUM) - (rotate:HI (reg:HI D_REGNUM) (const_int 1))) - (clobber (reg:HI CC_REGNUM))]) - (set (match_dup 4) (reg:HI D_REGNUM))] - "operands[5] = m68hc11_gen_lowpart (HImode, operands[1]); - operands[6] = m68hc11_gen_highpart (HImode, operands[1]);") - -;; -;; Replace a "ldd <mem>; psha; pshb" with a "ldx <mem>; pshx". -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "memory_operand" "")) - (set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) - (match_dup 0)) - (match_scratch:HI 2 "x")] - "TARGET_M6811 && D_REG_P (operands[0]) && peep2_reg_dead_p (2, operands[0])" - [(set (match_dup 2) (match_dup 1)) - (set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 2))] - "") - -;; -;; Remove one load when copying a value to/from memory and also -;; to a register. Take care not clobbering a possible register used -;; by operand 2. -;; Replace: "ldd 0,y; std 2,y; ldx 0,y" into "ldx 0,y; stx 2,y" -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "general_operand" "")) - (set (match_operand:HI 2 "nonimmediate_operand" "") (match_dup 0)) - (set (match_operand:HI 3 "hard_reg_operand" "") (match_dup 1))] - "peep2_reg_dead_p (2, operands[0]) - && !side_effects_p (operands[1]) - && !side_effects_p (operands[2]) - && !reg_mentioned_p (operands[3], operands[2])" - [(set (match_dup 3) (match_dup 1)) - (set (match_dup 2) (match_dup 3))] - "") - -;; -;; Replace a "ldd <mem>; addd #N; std <mem>" into a -;; "ldx <mem>; leax; stx <mem>" if we have a free X/Y register -;; and the constant is small. -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "general_operand" "")) - (set (match_dup 0) (plus:HI (match_dup 0) - (match_operand:HI 2 "const_int_operand" ""))) - (set (match_operand:HI 3 "nonimmediate_operand" "") - (match_dup 0)) - (match_scratch:HI 4 "xy")] - "D_REG_P (operands[0]) - && (TARGET_M6812 - || (INTVAL (operands[2]) >= -2 && INTVAL (operands[2]) <= 2)) - && peep2_reg_dead_p (3, operands[0])" - [(set (match_dup 4) (match_dup 1)) - (set (match_dup 4) (plus:HI (match_dup 4) (match_dup 2))) - (set (match_dup 3) (match_dup 4))] - "if (reg_mentioned_p (operands[4], operands[1])) FAIL; - if (reg_mentioned_p (operands[4], operands[3])) FAIL;") - -;;-------------------------------------------------------------------- -;;- Bset peephole2 -;;-------------------------------------------------------------------- -;; These peepholes try to replace some logical sequences by 'bset' and 'bclr'. -;; -;; Replace 'ldab <mem>; orab #N; stab <mem>' by 'bset <mem> #N'. -;; Register D must be dead and there must be no register side effects for mem. -;; The <mem> *can* be volatile this is why we must not use 'side_effects_p'. -;; The good side effect is that it makes the sequence atomic. -;; -(define_peephole2 - [(set (match_operand:QI 0 "hard_reg_operand" "") - (match_operand:QI 1 "nonimmediate_operand" "")) - (set (match_dup 0) (ior:QI (match_dup 0) - (match_operand:QI 2 "const_int_operand" ""))) - (set (match_dup 1) (match_dup 0))] - "(TARGET_M6812 || m68hc11_indirect_p (operands[1], QImode)) - && (GET_CODE (operands[1]) != MEM || !auto_inc_p (XEXP (operands[1], 0))) - && peep2_reg_dead_p (3, operands[0])" - [(set (match_dup 1) (ior:QI (match_dup 1) (match_dup 2)))] - "") - -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "nonimmediate_operand" "")) - (set (match_dup 0) (ior:HI (match_dup 0) - (match_operand:HI 2 "const_int_operand" ""))) - (set (match_dup 1) (match_dup 0))] - "(TARGET_M6812 || m68hc11_indirect_p (operands[1], HImode)) - && (GET_CODE (operands[1]) != MEM || !auto_inc_p (XEXP (operands[1], 0))) - && peep2_reg_dead_p (3, operands[0])" - [(set (match_dup 1) (ior:HI (match_dup 1) (match_dup 2)))] - "") - -;;-------------------------------------------------------------------- -;;- Bclr peephole2 -;;-------------------------------------------------------------------- -;; Replace 'ldab <mem>; andab #N; stab <mem>' by 'bclr <mem> #N'. -;; See Bset peephole2. -;; -(define_peephole2 - [(set (match_operand:QI 0 "hard_reg_operand" "") - (match_operand:QI 1 "nonimmediate_operand" "")) - (set (match_dup 0) (and:QI (match_dup 0) - (match_operand:QI 2 "const_int_operand" ""))) - (set (match_dup 1) (match_dup 0))] - "(TARGET_M6812 || m68hc11_indirect_p (operands[1], QImode)) - && (GET_CODE (operands[1]) != MEM || !auto_inc_p (XEXP (operands[1], 0))) - && peep2_reg_dead_p (3, operands[0])" - [(set (match_dup 1) (and:QI (match_dup 1) (match_dup 2)))] - "") - -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "nonimmediate_operand" "")) - (set (match_dup 0) (and:HI (match_dup 0) - (match_operand:HI 2 "const_int_operand" ""))) - (set (match_dup 1) (match_dup 0))] - "(TARGET_M6812 || m68hc11_indirect_p (operands[1], HImode)) - && (GET_CODE (operands[1]) != MEM || !auto_inc_p (XEXP (operands[1], 0))) - && peep2_reg_dead_p (3, operands[0])" - [(set (match_dup 1) (and:HI (match_dup 1) (match_dup 2)))] - "") - - -;;-------------------------------------------------------------------- -;;- Compare peephole2 -;;-------------------------------------------------------------------- -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "hard_reg_operand" "")) - (set (match_dup 1) (plus:HI (match_dup 1) - (match_operand:HI 2 "const_int_operand" ""))) - (set (cc0) (compare (match_dup 0) - (const_int 0)))] - "peep2_reg_dead_p (3, operands[0]) && !Z_REG_P (operands[1])" - [(set (match_dup 1) (plus:HI (match_dup 1) (match_dup 2))) - (set (cc0) (compare (match_dup 1) (match_dup 2)))] - "") - -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "hard_reg_operand" "")) - (set (match_operand:HI 2 "hard_reg_operand" "") - (plus:HI (match_dup 2) - (match_operand:HI 3 "const_int_operand" ""))) - (set (match_operand:HI 4 "memory_operand" "") (match_dup 2)) - (set (cc0) (compare (match_operand:HI 5 "hard_reg_operand" "") - (const_int 0)))] - "peep2_reg_dead_p (4, operands[5]) && !Z_REG_P (operands[2]) - && !reg_mentioned_p (operands[2], operands[4]) - - && ((rtx_equal_p (operands[5], operands[0]) - && rtx_equal_p (operands[2], operands[1])) - - || (rtx_equal_p (operands[5], operands[1]) - && rtx_equal_p (operands[2], operands[0])))" - [(set (match_dup 2) (match_dup 1)) - (set (match_dup 2) (plus:HI (match_dup 2) (match_dup 3))) - (set (match_dup 4) (match_dup 2)) - (set (cc0) (compare (match_dup 2) (match_dup 3)))] - "") - - -;;-------------------------------------------------------------------- -;;- Load peephole2 -;;-------------------------------------------------------------------- -;; -;; Optimize initialization of 2 hard regs from the same memory location -;; Since we can't copy easily X, Y and D to each other, load the 2 registers -;; from the same memory location. -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "memory_operand" "")) - (set (match_operand:HI 2 "hard_reg_operand" "") (match_dup 0))] - "TARGET_M6811 - && !side_effects_p (operands[1]) - && !reg_mentioned_p (operands[0], operands[1])" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 2) (match_dup 1))] - "") - -;; Replace "ldd #N; addd <op>" with "ldd <op>; addd #N". -;; -(define_peephole2 - [(set (match_operand:HI 0 "nonimmediate_operand" "") (const_int 0)) - (set (match_operand:HI 1 "nonimmediate_operand" "") (const_int 0)) - (set (match_operand:HI 2 "nonimmediate_operand" "") (const_int 0)) - (set (match_operand:HI 3 "nonimmediate_operand" "") (const_int 0)) - (match_scratch:HI 4 "d")] - "" - [(set (match_dup 4) (const_int 0)) - (set (match_dup 0) (match_dup 4)) - (set (match_dup 1) (match_dup 4)) - (set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 4))] - "") - -;; -;; Replace "ldd #N; addd <op>" with "ldd <op>; addd #N". -;; -(define_peephole2 - [(set (match_operand:HI 0 "nonimmediate_operand" "") (const_int 0)) - (set (match_operand:HI 1 "nonimmediate_operand" "") (const_int 0)) - (set (match_operand:HI 2 "nonimmediate_operand" "") (const_int 0)) - (match_scratch:HI 3 "d")] - "" - [(set (match_dup 3) (const_int 0)) - (set (match_dup 0) (match_dup 3)) - (set (match_dup 1) (match_dup 3)) - (set (match_dup 2) (match_dup 3))] - "") - -;; -;; Replace "ldd #N; addd <op>" with "ldd <op>; addd #N". -;; -(define_peephole2 - [(set (match_operand:HI 0 "hard_reg_operand" "") (const_int 0)) - (set (match_operand:HI 1 "push_operand" "") (match_dup 0)) - (set (match_operand:HI 2 "push_operand" "") (match_dup 0)) - (set (match_operand:HI 3 "push_operand" "") (match_dup 0)) - (match_scratch:HI 4 "x")] - "TARGET_M6811 && D_REG_P (operands[0]) && peep2_reg_dead_p (4, operands[0])" - [(set (match_dup 4) (const_int 0)) - (set (match_dup 1) (match_dup 4)) - (set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 4))] - "") - -;; -;; This peephole catches the address computations generated by the reload -;; pass. -(define_peephole - [(set (match_operand:HI 0 "hard_reg_operand" "xy") - (match_operand:HI 1 "const_int_operand" "")) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))]) - (set (reg:HI D_REGNUM) - (plus (reg:HI D_REGNUM) - (match_operand:HI 2 "general_operand" ""))) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))])] - "(INTVAL (operands[1]) & 0x0FF) == 0" - "* -{ - int value_loaded = 1; - - if (X_REG_P (operands[0]) || SP_REG_P (operands[2])) - { - rtx ops[2]; - - ops[0] = operands[0]; - ops[1] = operands[2]; - m68hc11_gen_movhi (insn, ops); - output_asm_insn (\"xgd%0\", operands); - } - else if (Y_REG_P (operands[0])) - { - if (reg_mentioned_p (iy_reg, operands[2])) - output_asm_insn (\"ldy\\t%2\", operands); - else - value_loaded = 0; - output_asm_insn (\"xgdy\", operands); - } - else - { - output_asm_insn (\"ldd\\t%2\", operands); - } - - if (value_loaded == 0) - output_asm_insn (\"ldd\\t%2\", operands); - if ((INTVAL (operands[1]) & 0x0ff00) == 0x100) - output_asm_insn (\"inca\", operands); - else if ((INTVAL (operands[1]) & 0x0ff00) == 0xff00) - output_asm_insn (\"deca\", operands); - else if (INTVAL (operands[1]) != 0) - output_asm_insn (\"adda\\t%h1\", operands); - - if (X_REG_P (operands[0])) - return \"xgdx\"; - else if (Y_REG_P (operands[0])) - return \"xgdy\"; - else - return \"\"; -} -") - -(define_peephole - [(set (match_operand:HI 0 "hard_reg_operand" "h") - (match_operand:HI 1 "non_push_operand" "g")) - (set (match_operand:HI 2 "hard_reg_operand" "h") - (match_dup 0))] - "find_regno_note (insn, REG_DEAD, REGNO (operands[0])) - && !S_REG_P (operands[2])" - "* -{ - rtx ops[2]; - - ops[0] = operands[2]; - ops[1] = operands[1]; - m68hc11_gen_movhi (insn, ops); - return \"\"; -} -") - -(define_peephole - [(set (match_operand:HI 0 "hard_reg_operand" "h") - (match_operand:HI 1 "hard_reg_operand" "h")) - (set (match_operand:HI 2 "non_push_operand" "g") - (match_dup 0))] - "find_regno_note (insn, REG_DEAD, REGNO (operands[0])) - && !S_REG_P (operands[2])" - "* -{ - rtx ops[2]; - - ops[0] = operands[2]; - ops[1] = operands[1]; - m68hc11_gen_movhi (insn, ops); - return \"\"; -} -") - -;; -;; Catch a (set X/Y D) followed by a swap. In this form, D is dead after -;; the set, so we don't need to emit anything. 'ins1' refers to the -;; (set ...) insn. -;; -(define_peephole - [(set (match_operand:HI 0 "hard_reg_operand" "A") (reg:HI D_REGNUM)) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))])] - "find_regno_note (ins1, REG_DEAD, HARD_D_REGNUM)" - "* -{ - cc_status = cc_prev_status; - return \"\"; -} -") - -;; Same as above but due to some split, there may be a noop set -;; between the two. -(define_peephole - [(set (match_operand:HI 0 "hard_reg_operand" "A") (reg:HI D_REGNUM)) - (set (match_dup 0) (match_dup 0)) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))])] - "find_regno_note (ins1, REG_DEAD, HARD_D_REGNUM)" - "* -{ - cc_status = cc_prev_status; - return \"\"; -} -") - -;; -;; Catch a (set X/Y D) followed by an xgdx/xgdy. D is not dead -;; and we must, at least, setup X/Y with value of D. -;; -(define_peephole - [(set (match_operand:HI 0 "hard_reg_operand" "A") (reg:HI D_REGNUM)) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))])] - "" - "* -{ - rtx ops[2]; - - ops[0] = operands[0]; - ops[1] = gen_rtx_REG (HImode, HARD_D_REGNUM); - m68hc11_gen_movhi (insn, ops); - return \"\"; -} -") - -;;; -;;; Catch an xgdx/xgdy followed by a (set D X/Y). If X/Y is dead, we don't -;;; need to emit anything. Otherwise, we just need a copy of D to X/Y. -;;; -(define_peephole - [(parallel [(set (reg:HI D_REGNUM) (match_operand:HI 0 "hard_reg_operand" "A")) - (set (match_dup 0) (reg:HI D_REGNUM))]) - (set (reg:HI D_REGNUM) (match_dup 0))] - "find_regno_note (insn, REG_DEAD, REGNO (operands[0]))" - "* -{ - cc_status = cc_prev_status; - return \"\"; -} -") - -;;; -;;; Catch an xgdx/xgdy followed by a (set D X/Y). If X/Y is dead, we don't -;;; need to emit anything. Otherwise, we just need a copy of D to X/Y. -;;; -(define_peephole - [(parallel [(set (reg:HI D_REGNUM) (match_operand:HI 0 "hard_reg_operand" "A")) - (set (match_dup 0) (reg:HI D_REGNUM))]) - (set (reg:QI D_REGNUM) (match_operand:QI 1 "hard_reg_operand" "A"))] - "REGNO (operands[0]) == REGNO (operands[1]) - && find_regno_note (insn, REG_DEAD, REGNO (operands[0]))" - "* -{ - cc_status = cc_prev_status; - return \"\"; -} -") - -;;; -;;; Catch an xgdx/xgdy followed by a (set D X/Y). If X/Y is dead, we don't -;;; need to emit anything. Otherwise, we just need a copy of D to X/Y. -;;; -(define_peephole - [(parallel [(set (reg:HI D_REGNUM) (match_operand:HI 0 "hard_reg_operand" "A")) - (set (match_dup 0) (reg:HI D_REGNUM))]) - (set (reg:HI D_REGNUM) (match_dup 0))] - "" - "* -{ - rtx ops[2]; - - ops[0] = operands[0]; - ops[1] = gen_rtx_REG (HImode, HARD_D_REGNUM); - m68hc11_gen_movhi (insn, ops); - return \"\"; -} -") - -;;; -;;; Same peephole with a QI set. The copy is made as 16-bit to comply -;;; with the xgdx. -;;; -(define_peephole - [(parallel [(set (reg:HI D_REGNUM) (match_operand:HI 0 "hard_reg_operand" "A")) - (set (match_dup 0) (reg:HI D_REGNUM))]) - (set (reg:QI D_REGNUM) (match_operand:QI 1 "hard_reg_operand" "A"))] - "REGNO (operands[0]) == REGNO (operands[1])" - "* -{ - rtx ops[2]; - - ops[0] = operands[0]; - ops[1] = gen_rtx_REG (HImode, HARD_D_REGNUM); - m68hc11_gen_movhi (insn, ops); - return \"\"; -} -") - -;;; -;;; Catch two consecutive xgdx or xgdy, emit nothing. -;;; -(define_peephole - [(parallel [(set (reg:HI D_REGNUM) (match_operand:HI 0 "hard_reg_operand" "A")) - (set (match_dup 0) (reg:HI D_REGNUM))]) - (parallel [(set (reg:HI D_REGNUM) (match_dup 0)) - (set (match_dup 0) (reg:HI D_REGNUM))])] - "" - "* -{ - cc_status = cc_prev_status; - return \"\"; -} -") - -(define_peephole - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "stack_register_operand" "")) - (set (match_operand:HI 2 "hard_reg_operand" "") - (match_operand:HI 3 "memory_operand" "m")) - (set (match_dup 0) - (match_operand:HI 4 "memory_operand" "m"))] - "IS_STACK_POP (operands[4]) - && (GET_CODE (operands[3]) == MEM && - rtx_equal_p (operands[0], XEXP (operands[3], 0)))" - "* -{ - rtx ops[2]; - - ops[0] = operands[2]; - ops[1] = gen_rtx_MEM (HImode, - gen_rtx_POST_INC (HImode, stack_pointer_rtx)); - m68hc11_gen_movhi (insn, ops); - return \"\"; -} -") - -;; -;; Catch (d = -1) (d = d + sp) to avoid 2 adjust of SP. -;; -(define_peephole - [(set (match_operand:HI 0 "hard_reg_operand" "dA") (const_int -1)) - (set (match_dup 0) (plus:HI (match_dup 0) (reg:HI SP_REGNUM)))] - "TARGET_M6811" - "* -{ - return \"sts\\t%t0\\n\\tld%0\\t%t0\"; -} -") - -(define_peephole - [(set (match_operand:HI 0 "hard_reg_operand" "") - (match_operand:HI 1 "memory_operand" "")) - (set (match_operand:HI 2 "hard_reg_operand" "") (match_dup 0))] - "TARGET_M6811 - && !side_effects_p (operands[1]) - && !reg_mentioned_p (operands[0], operands[1])" - "* -{ - rtx ops[2]; - - ops[0] = operands[0]; - ops[1] = operands[1]; - m68hc11_gen_movhi (insn, ops); - ops[0] = operands[2]; - m68hc11_gen_movhi (insn, ops); - return \"\"; -}") - -;; Peephole for Z register replacement. -;; Avoid to use _.tmp register when comparing D and X if we can compare -;; with soft register -(define_peephole - [(set (match_operand:HI 0 "hard_reg_operand" "") (reg:HI SOFT_XY_REGNUM)) - (set (reg:HI SOFT_TMP_REGNUM) (match_dup 0)) - (set (cc0) (compare (match_operand:HI 2 "hard_reg_operand" "") - (reg:HI SOFT_TMP_REGNUM)))] - "X_REG_P (operands[0]) || Y_REG_P (operands[0])" - "* -{ - rtx ops[2]; - - ops[0] = operands[0]; - ops[1] = operands[1]; - m68hc11_gen_movhi (insn, ops); - return \"cp%2\\t%1\"; -}") diff --git a/gcc/config/m68hc11/m68hc11.opt b/gcc/config/m68hc11/m68hc11.opt deleted file mode 100644 index f0f29f2a7a1..00000000000 --- a/gcc/config/m68hc11/m68hc11.opt +++ /dev/null @@ -1,94 +0,0 @@ -; Options for the Motorola 68HC11 and 68HC12 port of the compiler. - -; Copyright (C) 2005, 2007 Free Software Foundation, Inc. -; -; This file is part of GCC. -; -; GCC 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 3, or (at your option) any later -; version. -; -; GCC 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 GCC; see the file COPYING3. If not see -; <http://www.gnu.org/licenses/>. - -m6811 -Target RejectNegative InverseMask(M6812, M6811) -Compile for a 68HC11 - -m6812 -Target RejectNegative Mask(M6812) -Compile for a 68HC12 - -m68hc11 -Target RejectNegative InverseMask(M6812) -Compile for a 68HC11 - -m68hc12 -Target RejectNegative Mask(M6812) MaskExists -Compile for a 68HC12 - -; At the moment, there is no difference between the code generated -; for -m68hc12 and -m68hcs12. -m68hcs12 -Target RejectNegative Mask(M6812) MaskExists -Compile for a 68HCS12 - -m68s12 -Target RejectNegative Mask(M6812) MaskExists -Compile for a 68HCS12 - -mauto-incdec -Target RejectNegative Report Mask(AUTO_INC_DEC) -Auto pre/post decrement increment allowed - -minmax -Target RejectNegative Report Mask(MIN_MAX) -Min/max instructions allowed - -mlong-calls -Target RejectNegative Report Mask(LONG_CALLS) -Use call and rtc for function calls and returns - -mnoauto-incdec -Target RejectNegative Report InverseMask(AUTO_INC_DEC) -Auto pre/post decrement increment not allowed - -mnolong-calls -Target RejectNegative Report InverseMask(LONG_CALLS) -Use jsr and rts for function calls and returns - -mnominmax -Target RejectNegative Report InverseMask(MIN_MAX) -Min/max instructions not allowed - -mnorelax -Target RejectNegative Report InverseMask(NO_DIRECT_MODE) -Use direct addressing mode for soft registers - -mnoshort -Target RejectNegative Report InverseMask(SHORT) -Compile with 32-bit integer mode - -; Currently ignored. -mreg-alloc= -Target RejectNegative Joined -Specify the register allocation order - -mrelax -Target RejectNegative Report Mask(NO_DIRECT_MODE) -Do not use direct addressing mode for soft registers - -mshort -Target RejectNegative Report Mask(SHORT) -Compile with 16-bit integer mode - -msoft-reg-count= -Target RejectNegative Joined UInteger Var(m68hc11_soft_reg_count) Init(-1) -Indicate the number of soft registers available diff --git a/gcc/config/m68hc11/m68hc12.h b/gcc/config/m68hc11/m68hc12.h deleted file mode 100644 index 22bdc008c57..00000000000 --- a/gcc/config/m68hc11/m68hc12.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Definitions of target machine for GNU compiler, for m68hc12. - Copyright (C) 1999, 2000, 2001, 2003, 2007 Free Software Foundation, Inc. - Contributed by Stephane Carrez (stcarrez@nerim.fr). - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -/* Compile and assemble for a 68hc12 unless there is a -m68hc11 option. */ -#define ASM_SPEC \ -"%{m68hc11:-m68hc11}" \ -"%{m68hcs12:-m68hcs12}" \ -"%{!m68hc11:%{!m68hcs12:-m68hc12}}" -#define LIB_SPEC "" -#define CC1_SPEC "" - -/* We need to tell the linker the target elf format. Just pass an - emulation option. This can be overridden by -Wl option of gcc. */ -#define LINK_SPEC \ -"%{m68hc11:-m m68hc11elf}" \ -"%{m68hcs12:-m m68hc12elf}" \ -"%{!m68hc11:%{!m68hcs12:-m m68hc11elf}} %{mrelax:-relax}" - -#define CPP_SPEC \ -"%{mshort:-D__HAVE_SHORT_INT__ -D__INT__=16}\ - %{!mshort:-D__INT__=32}\ - %{m68hc11:-Dmc6811 -DMC6811 -Dmc68hc11}\ - %{!m68hc11:%{!m68hc12:-Dmc6812 -DMC6812 -Dmc68hc12}}\ - %{m68hcs12:-Dmc6812 -DMC6812 -Dmc68hcs12}\ - %{fshort-double:-D__HAVE_SHORT_DOUBLE__}" - -/* Default target_flags if no switches specified. */ -#define TARGET_DEFAULT (MASK_M6812) diff --git a/gcc/config/m68hc11/predicates.md b/gcc/config/m68hc11/predicates.md deleted file mode 100644 index 77a524a0e1e..00000000000 --- a/gcc/config/m68hc11/predicates.md +++ /dev/null @@ -1,228 +0,0 @@ -;; Predicate definitions for Motorola 68HC11 and 68HC12. -;; Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc. -;; -;; This file is part of GCC. -;; -;; GCC 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 3, or (at your option) -;; any later version. -;; -;; GCC 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 GCC; see the file COPYING3. If not see -;; <http://www.gnu.org/licenses/>. - -;; TODO: Add a comment here. - -(define_predicate "stack_register_operand" - (match_code "subreg,reg") -{ - return SP_REG_P (op); -}) - -;; TODO: Add a comment here. - -(define_predicate "d_register_operand" - (match_code "subreg,reg") -{ - if (GET_MODE (op) != mode && mode != VOIDmode) - return 0; - - if (GET_CODE (op) == SUBREG) - op = XEXP (op, 0); - - return GET_CODE (op) == REG - && (REGNO (op) >= FIRST_PSEUDO_REGISTER - || REGNO (op) == HARD_D_REGNUM - || (mode == QImode && REGNO (op) == HARD_B_REGNUM)); -}) - -;; TODO: Add a comment here. - -(define_predicate "hard_addr_reg_operand" - (match_code "subreg,reg") -{ - if (GET_MODE (op) != mode && mode != VOIDmode) - return 0; - - if (GET_CODE (op) == SUBREG) - op = XEXP (op, 0); - - return GET_CODE (op) == REG - && (REGNO (op) == HARD_X_REGNUM - || REGNO (op) == HARD_Y_REGNUM - || REGNO (op) == HARD_Z_REGNUM); -}) - -;; TODO: Add a comment here. - -(define_predicate "hard_reg_operand" - (match_code "subreg,reg") -{ - if (GET_MODE (op) != mode && mode != VOIDmode) - return 0; - - if (GET_CODE (op) == SUBREG) - op = XEXP (op, 0); - - return GET_CODE (op) == REG - && (REGNO (op) >= FIRST_PSEUDO_REGISTER - || H_REGNO_P (REGNO (op))); -}) - -;; TODO: Add a comment here. - -(define_predicate "m68hc11_logical_operator" - (match_code "and,ior,xor") -{ - return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR; -}) - -;; TODO: Add a comment here. - -(define_predicate "m68hc11_arith_operator" - (match_code "and,ior,xor,plus,minus,ashift,ashiftrt,lshiftrt,rotate,rotatert") -{ - return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR - || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS - || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT - || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE - || GET_CODE (op) == ROTATERT; -}) - -;; TODO: Add a comment here. - -(define_predicate "m68hc11_non_shift_operator" - (match_code "and,ior,xor,plus,minus") -{ - return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR - || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS; -}) - -;; TODO: Add a comment here. - -(define_predicate "m68hc11_unary_operator" - (match_code "neg,not,sign_extend,zero_extend") -{ - return GET_CODE (op) == NEG || GET_CODE (op) == NOT - || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND; -}) - -;; Return true if op is a shift operator. - -(define_predicate "m68hc11_shift_operator" - (match_code "ashift,ashiftrt,lshiftrt,rotate,rotatert") -{ - return GET_CODE (op) == ROTATE || GET_CODE (op) == ROTATERT - || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFT - || GET_CODE (op) == ASHIFTRT; -}) - -;; TODO: Add a comment here. - -(define_predicate "m68hc11_eq_compare_operator" - (match_code "eq,ne") -{ - return GET_CODE (op) == EQ || GET_CODE (op) == NE; -}) - -;; TODO: Add a comment here. - -(define_predicate "non_push_operand" - (match_code "subreg,reg,mem") -{ - if (general_operand (op, mode) == 0) - return 0; - - if (push_operand (op, mode) == 1) - return 0; - return 1; -}) - -;; TODO: Add a comment here. - -(define_predicate "splitable_operand" - (match_code "subreg,reg,mem,symbol_ref,label_ref,const_int,const_double") -{ - if (general_operand (op, mode) == 0) - return 0; - - if (push_operand (op, mode) == 1) - return 0; - - /* Reject a (MEM (MEM X)) because the patterns that use non_push_operand - need to split such addresses to access the low and high part but it - is not possible to express a valid address for the low part. */ - if (mode != QImode && GET_CODE (op) == MEM - && GET_CODE (XEXP (op, 0)) == MEM) - return 0; - return 1; -}) - -;; TODO: Add a comment here. - -(define_predicate "reg_or_some_mem_operand" - (match_code "subreg,reg,mem") -{ - if (GET_CODE (op) == MEM) - { - rtx op0 = XEXP (op, 0); - int addr_mode; - - if (symbolic_memory_operand (op0, mode)) - return 1; - - if (IS_STACK_PUSH (op)) - return 1; - - if (GET_CODE (op) == REG && reload_in_progress - && REGNO (op) >= FIRST_PSEUDO_REGISTER - && reg_equiv_memory_loc[REGNO (op)]) - { - op = reg_equiv_memory_loc[REGNO (op)]; - op = eliminate_regs (op, VOIDmode, NULL_RTX); - } - if (GET_CODE (op) != MEM) - return 0; - - op0 = XEXP (op, 0); - addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0); - addr_mode &= ~ADDR_INDIRECT; - return m68hc11_valid_addressing_p (op0, mode, addr_mode); - } - - return register_operand (op, mode); -}) - -;; TODO: Add a comment here. - -(define_predicate "tst_operand" - (match_code "subreg,reg,mem") -{ - if (GET_CODE (op) == MEM && reload_completed == 0) - { - rtx addr = XEXP (op, 0); - if (m68hc11_auto_inc_p (addr)) - return 0; - } - return nonimmediate_operand (op, mode); -}) - -;; TODO: Add a comment here. - -(define_predicate "cmp_operand" - (match_code "subreg,reg,mem,symbol_ref,label_ref,const_int,const_double") -{ - if (GET_CODE (op) == MEM) - { - rtx addr = XEXP (op, 0); - if (m68hc11_auto_inc_p (addr)) - return 0; - } - return general_operand (op, mode); -}) diff --git a/gcc/config/m68hc11/t-m68hc11 b/gcc/config/m68hc11/t-m68hc11 deleted file mode 100644 index 5a8e6ade476..00000000000 --- a/gcc/config/m68hc11/t-m68hc11 +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright (C) 2000, 2001, 2002, 2003, 2005, -# 2008 Free Software Foundation, Inc. -# -# This file is part of GCC. -# -# GCC 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 3, or (at your option) -# any later version. -# -# GCC 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 GCC; see the file COPYING3. If not see -# <http://www.gnu.org/licenses/>. - -RANLIB_FOR_TARGET = ` \ - if [ -f $(objdir)/../binutils/ranlib ] ; then \ - echo $(objdir)/../binutils/ranlib ; \ - else \ - if [ "$(host)" = "$(target)" ] ; then \ - echo ranlib; \ - else \ - if [ -f $(bindir)/$(target_noncanonical)-ranlib ] ; then \ - echo $(bindir)/$(target_noncanonical)-ranlib ; \ - else \ - t='$(program_transform_cross_name)'; echo ranlib | sed -e $$t ; \ - fi; \ - fi; \ - fi` - -LIB1ASMSRC = m68hc11/larith.asm -LIB1ASMFUNCS = _mulsi3 \ - _mulqi3 _ashlsi3 _ashrsi3 _lshrsi3 \ - _divmodhi4 _mulhi3 _mulhi32 \ - _memcpy _memset _negsi2 _one_cmplsi2 \ - _regs_min _regs_frame _regs_d1_2 \ - _regs_d3_4 _regs_d5_6 _regs_d7_8 _regs_d9_16 _regs_d17_32 \ - _premain __exit _abort _cleanup \ - _adddi3 _subdi3 _notdi2 _rotlhi3 _rotrhi3 \ - _ashrhi3 _lshrhi3 _lshlhi3 _ashrqi3 _lshlqi3 _map_data _init_bss \ - _ctor _dtor _far_tramp _call_far _return_far - -TARGET_LIBGCC2_CFLAGS = -DUSE_GAS -DIN_GCC -Dinhibit_libc - -# C implementation of 32-bit div/mod. -LIB2FUNCS_EXTRA = $(srcdir)/config/udivmodsi4.c \ - $(srcdir)/config/divmod.c $(srcdir)/config/udivmod.c - -# Don't compile with -g1 this reduces the size of some sections (.eh_frame). -LIBGCC2_DEBUG_CFLAGS =-g -LIBGCC2_CFLAGS = -Os -mrelax $(LIBGCC2_INCLUDES) $(TARGET_LIBGCC2_CFLAGS) $(LIBGCC2_DEBUG_CFLAGS) $(GTHREAD_FLAGS) -DIN_LIBGCC2 - -MULTILIB_OPTIONS = m68hc11/m68hc12 mshort fshort-double -MULTILIB_DIRNAMES = -MULTILIB_MATCHES = m68hc11=m6811 m68hc12=m6812 m68hc12=m68hcs12 -MULTILIB_EXCEPTIONS = -mnoshort -mno68hc11 - -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 - -dp-bit.c: $(srcdir)/config/fp-bit.c - echo '#define SMALL_MACHINE' >> dp-bit.c - echo '#define CMPtype HItype' >> dp-bit.c - echo '#ifdef __LITTLE_ENDIAN__' >> dp-bit.c - echo '#define FLOAT_BIT_ORDER_MISMATCH' >>dp-bit.c - echo '#endif' >> dp-bit.c - cat $(srcdir)/config/fp-bit.c >> dp-bit.c - -fp-bit.c: $(srcdir)/config/fp-bit.c - echo '#define FLOAT' > fp-bit.c - echo '#define CMPtype HItype' >> fp-bit.c - echo '#define SMALL_MACHINE' >> fp-bit.c - echo '#ifdef __LITTLE_ENDIAN__' >> 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 - -CRT0_S = $(srcdir)/config/m68hc11/m68hc11-crt0.S -MCRT0_S= $(srcdir)/config/m68hc11/m68hc11-crt0.S - -CRT0STUFF_T_CFLAGS = - -# Assemble startup files. -$(T)crt1.o: $(CRT0_S) $(GCC_PASSES) - $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crt1.o -x assembler-with-cpp $(CRT0_S) - -EXTRA_MULTILIB_PARTS = crt1.o diff --git a/gcc/config/m68k/uclinux-oldabi.h b/gcc/config/m68k/uclinux-oldabi.h deleted file mode 100644 index 7ef202efbac..00000000000 --- a/gcc/config/m68k/uclinux-oldabi.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Definitions of target machine for GCC. m68k/ColdFire based uClinux system - using ELF objects with special linker post-processing to produce FLAT - executables. - - Copyright (C) 2003, 2007 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - - -/* The old uClinux ABI used 80-byte "long double"s for ColdFire too. */ -#undef LONG_DOUBLE_TYPE_SIZE -#define LONG_DOUBLE_TYPE_SIZE 80 -#undef LIBGCC2_LONG_DOUBLE_TYPE_SIZE -#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 80 - -/* Undo the definition of STARTFILE_SPEC from m68kelf.h so we'll - pick the default from gcc.c (just link crt0.o from multilib dir). */ -#undef STARTFILE_SPEC - -/* Override the default LIB_SPEC from gcc.c. We don't currently support - profiling, or libg.a. */ -#undef LIB_SPEC -#define LIB_SPEC "\ -%{mid-shared-library:-R libc.gdb%s -elf2flt -shared-lib-id 0} -lc \ -" - -/* we don't want a .eh_frame section. */ -#define EH_FRAME_IN_DATA_SECTION - -/* ??? Quick hack to get constructors working. Make this look more like a - COFF target, so the existing dejagnu/libgloss support works. A better - solution would be to make the necessary dejagnu and libgloss changes so - that we can use normal the ELF constructor mechanism. */ -#undef INIT_SECTION_ASM_OP -#undef FINI_SECTION_ASM_OP -#undef ENDFILE_SPEC -#define ENDFILE_SPEC "" - -/* Bring in standard linux defines */ -#undef TARGET_OS_CPP_BUILTINS -#define TARGET_OS_CPP_BUILTINS() \ - do \ - { \ - builtin_define_std ("mc68000"); \ - builtin_define ("__uClinux__"); \ - builtin_define_std ("linux"); \ - builtin_define_std ("unix"); \ - builtin_define ("__gnu_linux__"); \ - builtin_assert ("system=linux"); \ - builtin_assert ("system=unix"); \ - builtin_assert ("system=posix"); \ - if (TARGET_ID_SHARED_LIBRARY) \ - builtin_define ("__ID_SHARED_LIBRARY__"); \ - } \ - while (0) - diff --git a/gcc/config/mcore/mcore-pe.h b/gcc/config/mcore/mcore-pe.h deleted file mode 100644 index ccd34e9c70d..00000000000 --- a/gcc/config/mcore/mcore-pe.h +++ /dev/null @@ -1,102 +0,0 @@ -/* Definitions of target machine for GNU compiler, for MCore using COFF/PE. - Copyright (C) 1994, 1999, 2000, 2002, 2003, 2004, 2007 - Free Software Foundation, Inc. - Contributed by Michael Tiemann (tiemann@cygnus.com). - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -/* Run-time Target Specification. */ -#define TARGET_VERSION fputs (" (MCORE/pe)", stderr) - -#define TARGET_OS_CPP_BUILTINS() \ - do \ - { \ - builtin_define ("__pe__"); \ - } \ - while (0) - -/* The MCore ABI says that bitfields are unsigned by default. */ -/* The EPOC C++ environment does not support exceptions. */ -#undef CC1_SPEC -#define CC1_SPEC "-funsigned-bitfields %{!DIN_GCC:-fno-rtti} %{!DIN_GCC:-fno-exceptions}" - -#undef SDB_DEBUGGING_INFO -#define DBX_DEBUGGING_INFO 1 - -/* Computed in toplev.c. */ -#undef PREFERRED_DEBUGGING_TYPE - -#define READONLY_DATA_SECTION_ASM_OP "\t.section .rdata" - -#define MCORE_EXPORT_NAME(STREAM, NAME) \ - do \ - { \ - fprintf (STREAM, "\t.section .drectve\n"); \ - fprintf (STREAM, "\t.ascii \" -export:%s\"\n", \ - (* targetm.strip_name_encoding) (NAME)); \ - in_section = NULL; \ - } \ - while (0); - -/* Output the label for an initialized variable. */ -#undef ASM_DECLARE_OBJECT_NAME -#define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \ - do \ - { \ - if (mcore_dllexport_name_p (NAME)) \ - { \ - section *save_section = in_section; \ - MCORE_EXPORT_NAME (STREAM, NAME); \ - switch_to_section (save_section); \ - } \ - ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ - } \ - while (0) - -/* Output a function label definition. */ -#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \ - do \ - { \ - if (mcore_dllexport_name_p (NAME)) \ - { \ - MCORE_EXPORT_NAME (STREAM, NAME); \ - switch_to_section (function_section (DECL)); \ - } \ - ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ - } \ - while (0); - -#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true - -#define DBX_LINES_FUNCTION_RELATIVE 1 - -#define STARTFILE_SPEC "crt0.o%s" -#define ENDFILE_SPEC "%{!mno-lsim:-lsim}" - -/* __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 -#undef INIT_SECTION_ASM_OP -#undef DTORS_SECTION_ASM_OP - -#define SUPPORTS_ONE_ONLY 1 - -/* Switch into a generic section. */ -#undef TARGET_ASM_NAMED_SECTION -#define TARGET_ASM_NAMED_SECTION default_pe_asm_named_section diff --git a/gcc/config/mcore/t-mcore-pe b/gcc/config/mcore/t-mcore-pe deleted file mode 100644 index 37ad3b6f947..00000000000 --- a/gcc/config/mcore/t-mcore-pe +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (C) 2000, 2001, 2002, 2008 Free Software Foundation, Inc. -# -# This file is part of GCC. -# -# GCC 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 3, or (at your option) -# any later version. -# -# GCC 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 GCC; see the file COPYING3. If not see -# <http://www.gnu.org/licenses/>. - -LIB1ASMSRC = mcore/lib1.asm -LIB1ASMFUNCS = _divsi3 _udivsi3 _modsi3 _umodsi3 - -# 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 - -dp-bit.c: $(srcdir)/config/fp-bit.c $(srcdir)/config/mcore/t-mcore - rm -f dp-bit.c - echo '' > dp-bit.c - cat $(srcdir)/config/fp-bit.c >> dp-bit.c - -fp-bit.c: $(srcdir)/config/fp-bit.c $(srcdir)/config/mcore/t-mcore - rm -f fp-bit.c - echo '' > fp-bit.c - echo '#define FLOAT' > fp-bit.c - cat $(srcdir)/config/fp-bit.c >> fp-bit.c - -# could use -msifilter to be safe from interrupt/jmp interactions and others. -TARGET_LIBGCC2_CFLAGS=-O3 -DNO_FLOATLIB_FIXUNSDFSI #-msifilter - -# We have values for float.h. -CROSS_FLOAT_H = $(srcdir)/config/mcore/gfloat.h - -MULTILIB_OPTIONS = mbig-endian/mlittle-endian m210/m340 -MULTILIB_DIRNAMES = big little m210 m340 -MULTILIB_MATCHES = -MULTILIB_EXTRA_OPTS = -MULTILIB_EXCEPTIONS = - -# EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o -LIBGCC = stmp-multilib -INSTALL_LIBGCC = install-multilib - -# If EXTRA_MULTILIB_PARTS is not defined above then define EXTRA_PARTS here -# EXTRA_PARTS = crtbegin.o crtend.o - diff --git a/gcc/config/netbsd-aout.h b/gcc/config/netbsd-aout.h deleted file mode 100644 index 7306c156e68..00000000000 --- a/gcc/config/netbsd-aout.h +++ /dev/null @@ -1,196 +0,0 @@ -/* Common configuration file for NetBSD a.out targets. - Copyright (C) 2002, 2007, 2010 Free Software Foundation, Inc. - Contributed by Wasabi Systems, Inc. - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -/* TARGET_OS_CPP_BUILTINS() common to all NetBSD a.out targets. */ -#define NETBSD_OS_CPP_BUILTINS_AOUT() \ - do \ - { \ - NETBSD_OS_CPP_BUILTINS_COMMON(); \ - } \ - while (0) - - -/* Provide an ASM_SPEC appropriate for NetBSD. Currently we only deal - with the options for generating PIC code. */ - -#undef ASM_SPEC -#define ASM_SPEC "%{fpic|fpie:-k} %{fPIC|fPIE:-k -K}" - -#define AS_NEEDS_DASH_FOR_PIPED_INPUT - - -/* Provide a STARTFILE_SPEC appropriate for NetBSD a.out. Here we - provide support for the special GCC option -static. */ - -#undef STARTFILE_SPEC -#define STARTFILE_SPEC \ - "%{!shared: \ - %{pg:gcrt0%O%s} \ - %{!pg: \ - %{p:mcrt0%O%s} \ - %{!p: \ - %{!static:crt0%O%s} \ - %{static:scrt0%O%s}}}}" - -/* Provide a LINK_SPEC appropriate for NetBSD a.out. Here we provide - support for the special GCC options -static, -assert, and -nostdlib. */ - -#undef NETBSD_LINK_SPEC_AOUT -#define NETBSD_LINK_SPEC_AOUT \ - "%{nostdlib:-nostdlib} \ - %{!shared: \ - %{!nostdlib: \ - %{!r: \ - %{!e*:-e start}}} \ - -dc -dp \ - %{static:-Bstatic}} \ - %{shared:-Bshareable} \ - %{R*} \ - %{assert*}" - -/* Default LINK_SPEC. */ -#undef LINK_SPEC -#define LINK_SPEC NETBSD_LINK_SPEC_AOUT - -/* Define the strings used for the .type, .size, and .set directives. - These strings generally do not vary from one system running NetBSD - to another, but if a given system needs to use different pseudo-op - names for these, they may be overridden in the file included after - this one. */ - -#undef TYPE_ASM_OP -#undef SIZE_ASM_OP -#undef SET_ASM_OP -#define TYPE_ASM_OP "\t.type\t" -#define SIZE_ASM_OP "\t.size\t" -#define SET_ASM_OP "\t.set\t" - - -/* This is how we tell the assembler that a symbol is weak. */ - -#undef ASM_WEAKEN_LABEL -#define ASM_WEAKEN_LABEL(FILE,NAME) \ - do \ - { \ - fputs ("\t.globl\t", FILE); assemble_name (FILE, NAME); \ - fputc ('\n', FILE); \ - fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \ - fputc ('\n', FILE); \ - } \ - while (0) - - -/* The following macro defines the format used to output the second - operand of the .type assembler directive. Different svr4 assemblers - expect various different forms of this operand. The one given here - is just a default. You may need to override it in your machine- - specific tm.h file (depending on the particulars of your assembler). */ - -#undef TYPE_OPERAND_FMT -#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 - - -/* 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 (and a.out on NetBSD). - These macros also output the starting labels for the relevant - functions/objects. */ - -/* 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 \ - { \ - ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function"); \ - ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \ - ASM_OUTPUT_FUNCTION_LABEL (FILE, NAME, DECL); \ - } \ - while (0) - - -/* Write the extra assembler code needed to declare an object properly. */ - -#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ - do \ - { \ - HOST_WIDE_INT size; \ - \ - ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ - \ - size_directive_output = 0; \ - if (!flag_inhibit_size_directive \ - && (DECL) && DECL_SIZE (DECL)) \ - { \ - size_directive_output = 1; \ - size = int_size_in_bytes (TREE_TYPE (DECL)); \ - ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, size); \ - } \ - \ - 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. */ - -#undef ASM_FINISH_DECLARE_OBJECT -#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ - do \ - { \ - const char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ - HOST_WIDE_INT size; \ - 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; \ - size = int_size_in_bytes (TREE_TYPE (DECL)); \ - ASM_OUTPUT_SIZE_DIRECTIVE (FILE, name, size); \ - } \ - } \ - while (0) - - -/* This is how to declare the size of a function. */ - -#undef ASM_DECLARE_FUNCTION_SIZE -#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ - do \ - { \ - if (!flag_inhibit_size_directive) \ - ASM_OUTPUT_MEASURED_SIZE (FILE, FNAME); \ - } \ - while (0) diff --git a/gcc/config/rs6000/gnu.h b/gcc/config/rs6000/gnu.h deleted file mode 100644 index 0f329e53f10..00000000000 --- a/gcc/config/rs6000/gnu.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Definitions of target machine for GNU compiler, - for PowerPC machines running GNU. - Copyright (C) 2001, 2003, 2007 Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your - option) any later version. - - GCC 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 GCC; see the file COPYING3. If not see - <http://www.gnu.org/licenses/>. */ - -#undef CPP_OS_DEFAULT_SPEC -#define CPP_OS_DEFAULT_SPEC "%(cpp_os_gnu)" - -#undef STARTFILE_DEFAULT_SPEC -#define STARTFILE_DEFAULT_SPEC "%(startfile_gnu)" - -#undef ENDFILE_DEFAULT_SPEC -#define ENDFILE_DEFAULT_SPEC "%(endfile_gnu)" - -#undef LINK_START_DEFAULT_SPEC -#define LINK_START_DEFAULT_SPEC "%(link_start_gnu)" - -#undef LINK_OS_DEFAULT_SPEC -#define LINK_OS_DEFAULT_SPEC "%(link_os_gnu)" - -#undef TARGET_VERSION -#define TARGET_VERSION fprintf (stderr, " (PowerPC GNU)"); diff --git a/gcc/config/rs6000/linux64.h b/gcc/config/rs6000/linux64.h index e6840d63e80..04913f29df4 100644 --- a/gcc/config/rs6000/linux64.h +++ b/gcc/config/rs6000/linux64.h @@ -172,10 +172,6 @@ extern int dot_symbols; #undef ASM_SPEC #undef LINK_OS_LINUX_SPEC -/* FIXME: This will quite possibly choose the wrong dynamic linker. */ -#undef LINK_OS_GNU_SPEC -#define LINK_OS_GNU_SPEC LINK_OS_LINUX_SPEC - #ifndef RS6000_BI_ARCH #define ASM_DEFAULT_SPEC "-mppc64" #define ASM_SPEC "%(asm_spec64) %(asm_spec_common)" @@ -199,7 +195,6 @@ extern int dot_symbols; %{mcall-freebsd: -mbig} \ %{mcall-i960-old: -mlittle} \ %{mcall-linux: -mbig} \ - %{mcall-gnu: -mbig} \ %{mcall-netbsd: -mbig} \ }}}}" diff --git a/gcc/config/rs6000/sysv4.h b/gcc/config/rs6000/sysv4.h index aeb934f6ed5..5ba1253fd2c 100644 --- a/gcc/config/rs6000/sysv4.h +++ b/gcc/config/rs6000/sysv4.h @@ -98,8 +98,6 @@ do { \ else \ rs6000_current_abi = ABI_V4; \ } \ - else if (!strcmp (rs6000_abi_name, "gnu")) \ - rs6000_current_abi = ABI_V4; \ else if (!strcmp (rs6000_abi_name, "netbsd")) \ rs6000_current_abi = ABI_V4; \ else if (!strcmp (rs6000_abi_name, "openbsd")) \ @@ -556,8 +554,7 @@ extern int fixuplabelno; mcall-freebsd | \ mcall-netbsd | \ mcall-openbsd | \ - mcall-linux | \ - mcall-gnu :-mbig; \ + mcall-linux :-mbig; \ mcall-i960-old :-mlittle}" #define CC1_ENDIAN_BIG_SPEC "" @@ -583,8 +580,7 @@ extern int fixuplabelno; mcall-freebsd | \ mcall-netbsd | \ mcall-openbsd | \ - mcall-linux | \ - mcall-gnu : -mbig %(cc1_endian_big); \ + mcall-linux : -mbig %(cc1_endian_big); \ mcall-i960-old : -mlittle %(cc1_endian_little); \ : %(cc1_endian_default)} \ %{meabi: %{!mcall-*: -mcall-sysv }} \ @@ -593,7 +589,6 @@ extern int fixuplabelno; %{mcall-freebsd: -mno-eabi } \ %{mcall-i960-old: -meabi } \ %{mcall-linux: -mno-eabi } \ - %{mcall-gnu: -mno-eabi } \ %{mcall-netbsd: -mno-eabi } \ %{mcall-openbsd: -mno-eabi }}} \ %{msdata: -msdata=default} \ @@ -609,7 +604,6 @@ extern int fixuplabelno; msim : %(link_start_sim) ; \ mcall-freebsd: %(link_start_freebsd) ; \ mcall-linux : %(link_start_linux) ; \ - mcall-gnu : %(link_start_gnu) ; \ mcall-netbsd : %(link_start_netbsd) ; \ mcall-openbsd: %(link_start_openbsd) ; \ : %(link_start_default) }" @@ -647,7 +641,6 @@ extern int fixuplabelno; msim : %(link_os_sim) ; \ mcall-freebsd: %(link_os_freebsd) ; \ mcall-linux : %(link_os_linux) ; \ - mcall-gnu : %(link_os_gnu) ; \ mcall-netbsd : %(link_os_netbsd) ; \ mcall-openbsd: %(link_os_openbsd) ; \ : %(link_os_default) }" @@ -666,7 +659,6 @@ extern int fixuplabelno; msim : %(cpp_os_sim) ; \ mcall-freebsd: %(cpp_os_freebsd) ; \ mcall-linux : %(cpp_os_linux) ; \ - mcall-gnu : %(cpp_os_gnu) ; \ mcall-netbsd : %(cpp_os_netbsd) ; \ mcall-openbsd: %(cpp_os_openbsd) ; \ : %(cpp_os_default) }" @@ -681,7 +673,6 @@ extern int fixuplabelno; msim : %(startfile_sim) ; \ mcall-freebsd: %(startfile_freebsd) ; \ mcall-linux : %(startfile_linux) ; \ - mcall-gnu : %(startfile_gnu) ; \ mcall-netbsd : %(startfile_netbsd) ; \ mcall-openbsd: %(startfile_openbsd) ; \ : %(startfile_default) }" @@ -696,7 +687,6 @@ extern int fixuplabelno; msim : %(lib_sim) ; \ mcall-freebsd: %(lib_freebsd) ; \ mcall-linux : %(lib_linux) ; \ - mcall-gnu : %(lib_gnu) ; \ mcall-netbsd : %(lib_netbsd) ; \ mcall-openbsd: %(lib_openbsd) ; \ : %(lib_default) }" @@ -711,7 +701,6 @@ extern int fixuplabelno; msim : %(endfile_sim) ; \ mcall-freebsd: %(endfile_freebsd) ; \ mcall-linux : %(endfile_linux) ; \ - mcall-gnu : %(endfile_gnu) ; \ mcall-netbsd : %(endfile_netbsd) ; \ mcall-openbsd: %(endfile_openbsd) ; \ : %(crtsavres_default) %(endfile_default) }" @@ -845,31 +834,6 @@ extern int fixuplabelno; %{std=gnu*:-Dunix -D__unix -Dlinux -D__linux}}} \ -Asystem=linux -Asystem=unix -Asystem=posix %{pthread:-D_REENTRANT}" -/* GNU/Hurd support. */ -#define LIB_GNU_SPEC "%{mnewlib: --start-group -lgnu -lc --end-group } \ -%{!mnewlib: %{shared:-lc} %{!shared: %{pthread:-lpthread } \ -%{profile:-lc_p} %{!profile:-lc}}}" - -#define STARTFILE_GNU_SPEC "\ -%{!shared: %{!static: %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}}} \ -%{static: %{pg:gcrt0.o%s} %{!pg:%{p:gcrt0.o%s} %{!p:crt0.o%s}}} \ -%{mnewlib: ecrti.o%s} %{!mnewlib: crti.o%s} \ -%{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}" - -#define ENDFILE_GNU_SPEC "%{!shared:crtend.o%s} %{shared:crtendS.o%s} \ -%{mnewlib: ecrtn.o%s} %{!mnewlib: crtn.o%s}" - -#define LINK_START_GNU_SPEC "" - -#define LINK_OS_GNU_SPEC "-m elf32ppclinux %{!shared: %{!static: \ - %{rdynamic:-export-dynamic} \ - -dynamic-linker /lib/ld.so.1}}" - -#define CPP_OS_GNU_SPEC "-D__unix__ -D__gnu_hurd__ -D__GNU__ \ -%{!undef: \ - %{!ansi: -Dunix -D__unix}} \ --Asystem=gnu -Asystem=unix -Asystem=posix %{pthread:-D_REENTRANT}" - /* NetBSD support. */ #define LIB_NETBSD_SPEC "\ -lc" @@ -931,7 +895,6 @@ ncrtn.o%s" { "lib_mvme", LIB_MVME_SPEC }, \ { "lib_sim", LIB_SIM_SPEC }, \ { "lib_freebsd", LIB_FREEBSD_SPEC }, \ - { "lib_gnu", LIB_GNU_SPEC }, \ { "lib_linux", LIB_LINUX_SPEC }, \ { "lib_netbsd", LIB_NETBSD_SPEC }, \ { "lib_openbsd", LIB_OPENBSD_SPEC }, \ @@ -941,7 +904,6 @@ ncrtn.o%s" { "startfile_mvme", STARTFILE_MVME_SPEC }, \ { "startfile_sim", STARTFILE_SIM_SPEC }, \ { "startfile_freebsd", STARTFILE_FREEBSD_SPEC }, \ - { "startfile_gnu", STARTFILE_GNU_SPEC }, \ { "startfile_linux", STARTFILE_LINUX_SPEC }, \ { "startfile_netbsd", STARTFILE_NETBSD_SPEC }, \ { "startfile_openbsd", STARTFILE_OPENBSD_SPEC }, \ @@ -951,7 +913,6 @@ ncrtn.o%s" { "endfile_mvme", ENDFILE_MVME_SPEC }, \ { "endfile_sim", ENDFILE_SIM_SPEC }, \ { "endfile_freebsd", ENDFILE_FREEBSD_SPEC }, \ - { "endfile_gnu", ENDFILE_GNU_SPEC }, \ { "endfile_linux", ENDFILE_LINUX_SPEC }, \ { "endfile_netbsd", ENDFILE_NETBSD_SPEC }, \ { "endfile_openbsd", ENDFILE_OPENBSD_SPEC }, \ @@ -964,7 +925,6 @@ ncrtn.o%s" { "link_start_mvme", LINK_START_MVME_SPEC }, \ { "link_start_sim", LINK_START_SIM_SPEC }, \ { "link_start_freebsd", LINK_START_FREEBSD_SPEC }, \ - { "link_start_gnu", LINK_START_GNU_SPEC }, \ { "link_start_linux", LINK_START_LINUX_SPEC }, \ { "link_start_netbsd", LINK_START_NETBSD_SPEC }, \ { "link_start_openbsd", LINK_START_OPENBSD_SPEC }, \ @@ -976,7 +936,6 @@ ncrtn.o%s" { "link_os_sim", LINK_OS_SIM_SPEC }, \ { "link_os_freebsd", LINK_OS_FREEBSD_SPEC }, \ { "link_os_linux", LINK_OS_LINUX_SPEC }, \ - { "link_os_gnu", LINK_OS_GNU_SPEC }, \ { "link_os_netbsd", LINK_OS_NETBSD_SPEC }, \ { "link_os_openbsd", LINK_OS_OPENBSD_SPEC }, \ { "link_os_default", LINK_OS_DEFAULT_SPEC }, \ @@ -989,7 +948,6 @@ ncrtn.o%s" { "cpp_os_mvme", CPP_OS_MVME_SPEC }, \ { "cpp_os_sim", CPP_OS_SIM_SPEC }, \ { "cpp_os_freebsd", CPP_OS_FREEBSD_SPEC }, \ - { "cpp_os_gnu", CPP_OS_GNU_SPEC }, \ { "cpp_os_linux", CPP_OS_LINUX_SPEC }, \ { "cpp_os_netbsd", CPP_OS_NETBSD_SPEC }, \ { "cpp_os_openbsd", CPP_OS_OPENBSD_SPEC }, \ diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index d29147c9837..947ec04281f 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -1,6 +1,6 @@ /* Definitions of target machine for GNU compiler for Renesas / SuperH SH. Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2003, - 2004, 2005, 2006, 2007, 2008, 2009, 2010 + 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Steve Chamberlain (sac@cygnus.com). Improved by Jim Wilson (wilson@cygnus.com). @@ -170,17 +170,3 @@ extern int sh2a_is_function_vector_call (rtx); extern void sh_fix_range (const char *); extern bool sh_hard_regno_mode_ok (unsigned int, enum machine_mode); #endif /* ! GCC_SH_PROTOS_H */ - -#ifdef SYMBIAN -extern const char * sh_symbian_strip_name_encoding (const char *); -extern bool sh_symbian_is_dllexported_name (const char *); -#ifdef TREE_CODE -extern bool sh_symbian_is_dllexported (tree); -extern int sh_symbian_import_export_class (tree, int); -extern tree sh_symbian_handle_dll_attribute (tree *, tree, tree, int, bool *); -#ifdef RTX_CODE -extern void sh_symbian_encode_section_info (tree, rtx, int); -#endif -#endif -#endif /* SYMBIAN */ - diff --git a/gcc/config/sh/sh-symbian.h b/gcc/config/sh/sh-symbian.h deleted file mode 100644 index 2e37d2bbcac..00000000000 --- a/gcc/config/sh/sh-symbian.h +++ /dev/null @@ -1,42 +0,0 @@ -/* header file for GCC for a Symbian OS targeted SH backend. - Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. - Contributed by RedHat. - Most of this code is stolen from i386/winnt.c. - - This file is part of GCC. - - GCC 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 3, or (at your - option) any later version. - - GCC 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 GCC; see the file COPYING3. If not see - <http://www.gnu.org/licenses/>. */ - -/* A unique character to encode declspec encoded objects. */ -#define SH_SYMBIAN_FLAG_CHAR "$" - -/* Unique strings to prefix exported and imported objects. */ -#define DLL_IMPORT_PREFIX SH_SYMBIAN_FLAG_CHAR "i." -#define DLL_EXPORT_PREFIX SH_SYMBIAN_FLAG_CHAR "e." - -/* Select the level of debugging information to display. - 0 for no debugging. - 1 for informative messages about decisions to add attributes - 2 for verbose information about what is being done. */ -#define SYMBIAN_DEBUG 0 -/* #define SYMBIAN_DEBUG 1 */ -/* #define SYMBIAN_DEBUG 2 */ - -/* Functions exported from symbian-base.c. */ -extern tree sh_symbian_associated_type (tree); - -/* Functions exported from symbian-[c|c++].c. */ -extern bool sh_symbian_is_dllimported (tree); - diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index ee52c32a422..70bff999fc7 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -324,19 +324,6 @@ static const struct attribute_spec sh_attribute_table[] = sh_handle_resbank_handler_attribute, false }, { "function_vector", 1, 1, true, false, false, sh2a_handle_function_vector_handler_attribute, false }, -#ifdef SYMBIAN - /* Symbian support adds three new attributes: - dllexport - for exporting a function/variable that will live in a dll - dllimport - for importing a function/variable from a dll - - Microsoft allows multiple declspecs in one __declspec, separating - them with spaces. We do NOT support this. Instead, use __declspec - multiple times. */ - { "dllimport", 0, 0, true, false, false, - sh_symbian_handle_dll_attribute, false }, - { "dllexport", 0, 0, true, false, false, - sh_symbian_handle_dll_attribute, false }, -#endif { NULL, 0, 0, false, false, false, NULL, false } }; @@ -592,17 +579,6 @@ static const struct default_options sh_option_optimization_table[] = #undef TARGET_ENCODE_SECTION_INFO #define TARGET_ENCODE_SECTION_INFO sh_encode_section_info -#ifdef SYMBIAN - -#undef TARGET_ENCODE_SECTION_INFO -#define TARGET_ENCODE_SECTION_INFO sh_symbian_encode_section_info -#undef TARGET_STRIP_NAME_ENCODING -#define TARGET_STRIP_NAME_ENCODING sh_symbian_strip_name_encoding -#undef TARGET_CXX_IMPORT_EXPORT_CLASS -#define TARGET_CXX_IMPORT_EXPORT_CLASS sh_symbian_import_export_class - -#endif /* SYMBIAN */ - #undef TARGET_SECONDARY_RELOAD #define TARGET_SECONDARY_RELOAD sh_secondary_reload @@ -2823,12 +2799,6 @@ sh_file_start (void) { default_file_start (); -#ifdef SYMBIAN - /* Declare the .directive section before it is used. */ - fputs ("\t.section .directive, \"SM\", @progbits, 1\n", asm_out_file); - fputs ("\t.asciz \"#<SYMEDIT>#\\n\"\n", asm_out_file); -#endif - if (TARGET_ELF) /* We need to show the text section with the proper attributes as in TEXT_SECTION_ASM_OP, before dwarf2out diff --git a/gcc/config/sh/symbian-base.c b/gcc/config/sh/symbian-base.c deleted file mode 100644 index f8e678be3d2..00000000000 --- a/gcc/config/sh/symbian-base.c +++ /dev/null @@ -1,244 +0,0 @@ -/* Routines for GCC for a Symbian OS targeted SH backend, shared by - both the C and C++ compilers. - Copyright (C) 2004, 2005, 2007, 2009, 2010 Free Software Foundation, Inc. - Contributed by RedHat. - Most of this code is stolen from i386/winnt.c. - - This file is part of GCC. - - GCC 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 3, or (at your - option) any later version. - - GCC 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 GCC; see the file COPYING3. If not see - <http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "rtl.h" -#include "output.h" -#include "flags.h" -#include "tree.h" -#include "expr.h" -#include "tm_p.h" -#include "diagnostic-core.h" -#include "sh-symbian.h" - -/* Return nonzero if SYMBOL is marked as being dllexport'd. */ - -bool -sh_symbian_is_dllexported_name (const char *symbol) -{ - return strncmp (DLL_EXPORT_PREFIX, symbol, - strlen (DLL_EXPORT_PREFIX)) == 0; -} - -/* Return nonzero if SYMBOL is marked as being dllimport'd. */ - -static bool -sh_symbian_is_dllimported_name (const char *symbol) -{ - return strncmp (DLL_IMPORT_PREFIX, symbol, - strlen (DLL_IMPORT_PREFIX)) == 0; -} - -/* Return nonzero if DECL is a dllexport'd object. */ - -bool -sh_symbian_is_dllexported (tree decl) -{ - tree exp; - - if ( TREE_CODE (decl) != VAR_DECL - && TREE_CODE (decl) != FUNCTION_DECL) - return false; - - exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)); - - /* Class members get the dllexport status of their class. */ - if (exp == NULL) - { - tree class = sh_symbian_associated_type (decl); - - if (class) - exp = lookup_attribute ("dllexport", TYPE_ATTRIBUTES (class)); - } -#if SYMBIAN_DEBUG - if (exp) - { - print_node_brief (stderr, "dllexport:", decl, 0); - fprintf (stderr, "\n"); - } - else -#if SYMBIAN_DEBUG < 2 - if (TREE_CODE (decl) != FUNCTION_DECL) -#endif - { - print_node_brief (stderr, "no dllexport:", decl, 0); - fprintf (stderr, "\n"); - } -#endif - return exp ? true : false; -} - -/* Mark a DECL as being dllimport'd. */ - -static void -sh_symbian_mark_dllimport (tree decl) -{ - const char *oldname; - char *newname; - tree idp; - rtx rtlname; - rtx newrtl; - - rtlname = XEXP (DECL_RTL (decl), 0); - if (MEM_P (rtlname)) - rtlname = XEXP (rtlname, 0); - gcc_assert (GET_CODE (rtlname) == SYMBOL_REF); - oldname = XSTR (rtlname, 0); - - if (sh_symbian_is_dllexported_name (oldname)) - { - error ("%qE declared as both exported to and imported from a DLL", - DECL_NAME (decl)); - } - else if (sh_symbian_is_dllimported_name (oldname)) - { - /* Already done, but do a sanity check to prevent assembler errors. */ - if (!DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl)) - error ("failure in redeclaration of %q+D: dllimport%'d symbol lacks external linkage", - decl); - } - else - { - newname = (char *) alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1); - sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname); - - /* We pass newname through get_identifier to ensure it has a unique - address. RTL processing can sometimes peek inside the symbol ref - and compare the string's addresses to see if two symbols are - identical. */ - idp = get_identifier (newname); - newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); - XEXP (DECL_RTL (decl), 0) = newrtl; - } -} - -/* Mark a DECL as being dllexport'd. - Note that we override the previous setting (e.g.: dllimport). */ - -static void -sh_symbian_mark_dllexport (tree decl) -{ - const char *oldname; - char *newname; - rtx rtlname; - tree idp; - - rtlname = XEXP (DECL_RTL (decl), 0); - if (MEM_P (rtlname)) - rtlname = XEXP (rtlname, 0); - gcc_assert (GET_CODE (rtlname) == SYMBOL_REF); - oldname = XSTR (rtlname, 0); - - if (sh_symbian_is_dllimported_name (oldname)) - { - /* Remove DLL_IMPORT_PREFIX. - Note - we do not issue a warning here. In Symbian's environment it - is legitimate for a prototype to be marked as dllimport and the - corresponding definition to be marked as dllexport. The prototypes - are in headers used everywhere and the definition is in a translation - unit which has included the header in order to ensure argument - correctness. */ - oldname += strlen (DLL_IMPORT_PREFIX); - DECL_DLLIMPORT_P (decl) = 0; - } - else if (sh_symbian_is_dllexported_name (oldname)) - return; /* Already done. */ - - newname = (char *) alloca (strlen (DLL_EXPORT_PREFIX) + strlen (oldname) + 1); - sprintf (newname, "%s%s", DLL_EXPORT_PREFIX, oldname); - - /* We pass newname through get_identifier to ensure it has a unique - address. RTL processing can sometimes peek inside the symbol ref - and compare the string's addresses to see if two symbols are - identical. */ - idp = get_identifier (newname); - - XEXP (DECL_RTL (decl), 0) = - gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); -} - -void -sh_symbian_encode_section_info (tree decl, rtx rtl, int first) -{ - default_encode_section_info (decl, rtl, first); - - /* Mark the decl so we can tell from the rtl whether - the object is dllexport'd or dllimport'd. */ - if (sh_symbian_is_dllexported (decl)) - sh_symbian_mark_dllexport (decl); - else if (sh_symbian_is_dllimported (decl)) - sh_symbian_mark_dllimport (decl); - /* It might be that DECL has already been marked as dllimport, but a - subsequent definition nullified that. The attribute is gone but - DECL_RTL still has (DLL_IMPORT_PREFIX) prefixed. We need to remove - that. Ditto for the DECL_DLLIMPORT_P flag. */ - else if ( (TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == VAR_DECL) - && DECL_RTL (decl) != NULL_RTX - && MEM_P (DECL_RTL (decl)) - && MEM_P (XEXP (DECL_RTL (decl), 0)) - && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF - && sh_symbian_is_dllimported_name (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0))) - { - const char * oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0); - /* Remove DLL_IMPORT_PREFIX. */ - tree idp = get_identifier (oldname + strlen (DLL_IMPORT_PREFIX)); - rtx newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); - - warning (0, "%s %q+D %s after being referenced with dllimport linkage", - TREE_CODE (decl) == VAR_DECL ? "variable" : "function", - decl, (DECL_INITIAL (decl) || !DECL_EXTERNAL (decl)) - ? "defined locally" : "redeclared without dllimport attribute"); - - XEXP (DECL_RTL (decl), 0) = newrtl; - - DECL_DLLIMPORT_P (decl) = 0; - } -} - -/* Return the length of a function name prefix - that starts with the character 'c'. */ - -static int -sh_symbian_get_strip_length (int c) -{ - /* XXX Assumes strlen (DLL_EXPORT_PREFIX) == strlen (DLL_IMPORT_PREFIX). */ - return (c == SH_SYMBIAN_FLAG_CHAR[0]) ? strlen (DLL_EXPORT_PREFIX) : 0; -} - -/* Return a pointer to a function's name with any - and all prefix encodings stripped from it. */ - -const char * -sh_symbian_strip_name_encoding (const char *name) -{ - int skip; - - while ((skip = sh_symbian_get_strip_length (*name))) - name += skip; - - return name; -} - diff --git a/gcc/config/sh/symbian-c.c b/gcc/config/sh/symbian-c.c deleted file mode 100644 index c93922a3911..00000000000 --- a/gcc/config/sh/symbian-c.c +++ /dev/null @@ -1,181 +0,0 @@ -/* Routines for C compiler part of GCC for a Symbian OS targeted SH backend. - Copyright (C) 2004, 2005, 2007, 2009, 2010 Free Software Foundation, Inc. - Contributed by RedHat. - Most of this code is stolen from i386/winnt.c. - - This file is part of GCC. - - GCC 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 3, or (at your - option) any later version. - - GCC 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 GCC; see the file COPYING3. If not see - <http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "rtl.h" -#include "output.h" -#include "flags.h" -#include "tree.h" -#include "expr.h" -#include "tm_p.h" -#include "diagnostic-core.h" -#include "sh-symbian.h" - - -/* Return the type that we should use to determine if DECL is - imported or exported. */ - -tree -sh_symbian_associated_type (tree decl) -{ - tree t = NULL_TREE; - - /* We can just take the DECL_CONTEXT as normal. */ - if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))) - t = DECL_CONTEXT (decl); - - return t; -} - -/* Return nonzero if DECL is a dllimport'd object. */ - -bool -sh_symbian_is_dllimported (tree decl) -{ - tree imp; - - if ( TREE_CODE (decl) != VAR_DECL - && TREE_CODE (decl) != FUNCTION_DECL) - return false; - - imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)); - if (imp) - return true; - - /* Class members get the dllimport status of their class. */ - imp = sh_symbian_associated_type (decl); - if (! imp) - return false; - - imp = lookup_attribute ("dllimport", TYPE_ATTRIBUTES (imp)); - if (!imp) - return false; - - /* Don't mark defined functions as dllimport. If the definition itself - was marked with dllimport, then sh_symbian_handle_dll_attribute reports - an error. This handles the case when the definition overrides an - earlier declaration. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_INITIAL (decl) - && ! DECL_DECLARED_INLINE_P (decl)) - { - warning (OPT_Wattributes, "function %q+D is defined after prior " - "declaration as dllimport: attribute ignored", - decl); - return false; - } - - /* Don't allow definitions of static data members in dllimport - class. Just ignore the attribute for vtable data. */ - else if (TREE_CODE (decl) == VAR_DECL - && TREE_STATIC (decl) - && TREE_PUBLIC (decl) - && !DECL_EXTERNAL (decl)) - { - error ("definition of static data member %q+D of dllimport%'d class", - decl); - return false; - } - - return true; -} - -/* Handle a "dllimport" or "dllexport" attribute; - arguments as in struct attribute_spec.handler. */ - -tree -sh_symbian_handle_dll_attribute (tree *pnode, tree name, tree args, - int flags, bool *no_add_attrs) -{ - tree node = *pnode; - const char *attr = IDENTIFIER_POINTER (name); - - /* These attributes may apply to structure and union types being - created, but otherwise should pass to the declaration involved. */ - if (!DECL_P (node)) - { - if (flags & ((int) ATTR_FLAG_DECL_NEXT - | (int) ATTR_FLAG_FUNCTION_NEXT - | (int) ATTR_FLAG_ARRAY_NEXT)) - { - warning (OPT_Wattributes, "%qs attribute ignored", attr); - *no_add_attrs = true; - return tree_cons (name, args, NULL_TREE); - } - - if (TREE_CODE (node) != RECORD_TYPE && TREE_CODE (node) != UNION_TYPE) - { - warning (OPT_Wattributes, "%qs attribute ignored", attr); - *no_add_attrs = true; - } - - return NULL_TREE; - } - - /* Report error on dllimport ambiguities - seen now before they cause any damage. */ - else if (is_attribute_p ("dllimport", name)) - { - if (TREE_CODE (node) == VAR_DECL) - { - if (DECL_INITIAL (node)) - { - error ("variable %q+D definition is marked dllimport", - node); - *no_add_attrs = true; - } - - /* `extern' needn't be specified with dllimport. - Specify `extern' now and hope for the best. Sigh. */ - DECL_EXTERNAL (node) = 1; - /* Also, implicitly give dllimport'd variables declared within - a function global scope, unless declared static. */ - if (current_function_decl != NULL_TREE && ! TREE_STATIC (node)) - TREE_PUBLIC (node) = 1; - } - } - - /* Report error if symbol is not accessible at global scope. */ - if (!TREE_PUBLIC (node) - && ( TREE_CODE (node) == VAR_DECL - || TREE_CODE (node) == FUNCTION_DECL)) - { - error ("external linkage required for symbol %q+D because of %qE attribute", - node, name); - *no_add_attrs = true; - } - -#if SYMBIAN_DEBUG - print_node_brief (stderr, "mark node", node, 0); - fprintf (stderr, " as %s\n", attr); -#endif - - return NULL_TREE; -} - -int -sh_symbian_import_export_class (tree ctype ATTRIBUTE_UNUSED, int import_export) -{ - return import_export; -} diff --git a/gcc/config/sh/symbian-cxx.c b/gcc/config/sh/symbian-cxx.c deleted file mode 100644 index c0f8b71f626..00000000000 --- a/gcc/config/sh/symbian-cxx.c +++ /dev/null @@ -1,662 +0,0 @@ -/* Routines for C++ support for GCC for a Symbian OS targeted SH backend. - Copyright (C) 2004, 2005, 2007, 2009, 2010 Free Software Foundation, Inc. - Contributed by RedHat. - Most of this code is stolen from i386/winnt.c. - - This file is part of GCC. - - GCC 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 3, or (at your - option) any later version. - - GCC 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 GCC; see the file COPYING3. If not see - <http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "rtl.h" -#include "output.h" -#include "flags.h" -#include "tree.h" -#include "expr.h" -#include "tm_p.h" -#include "cp/cp-tree.h" /* We need access to the OVL_... macros. */ -#include "diagnostic-core.h" -#include "sh-symbian.h" - - -/* Return the type that we should use to determine if DECL is - imported or exported. */ - -tree -sh_symbian_associated_type (tree decl) -{ - tree t = NULL_TREE; - - if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) - /* Methods now inherit their dllimport/dllexport attributes correctly - so there is no need to check their class. In fact it is wrong to - check their class since a method can remain unexported from an - exported class. */ - return t; - - /* Otherwise we can just take the DECL_CONTEXT as normal. */ - if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))) - t = DECL_CONTEXT (decl); - - return t; -} - - -/* Return nonzero if DECL is a dllimport'd object. */ - -bool -sh_symbian_is_dllimported (tree decl) -{ - tree imp; - - if ( TREE_CODE (decl) != VAR_DECL - && TREE_CODE (decl) != FUNCTION_DECL) - return false; - - imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)); - if (imp) - return true; - - /* Class members get the dllimport status of their class. */ - imp = sh_symbian_associated_type (decl); - if (! imp) - return false; - - imp = lookup_attribute ("dllimport", TYPE_ATTRIBUTES (imp)); - if (!imp) - return false; - - /* Don't mark defined functions as dllimport. If the definition itself - was marked with dllimport, then sh_symbian_handle_dll_attribute reports - an error. This handles the case when the definition overrides an - earlier declaration. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_INITIAL (decl) - && ! DECL_DECLARED_INLINE_P (decl)) - { - /* Don't warn about artificial methods. */ - if (!DECL_ARTIFICIAL (decl)) - warning (OPT_Wattributes, "function %q+D is defined after prior " - "declaration as dllimport: attribute ignored", - decl); - return false; - } - - /* We ignore the dllimport attribute for inline member functions. - This differs from MSVC behavior which treats it like GNUC - 'extern inline' extension. */ - else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)) - { - if (extra_warnings) - warning (OPT_Wattributes, "inline function %q+D is declared as " - "dllimport: attribute ignored", - decl); - return false; - } - - /* Don't allow definitions of static data members in dllimport - class. Just ignore the attribute for vtable data. */ - else if (TREE_CODE (decl) == VAR_DECL - && TREE_STATIC (decl) - && TREE_PUBLIC (decl) - && !DECL_EXTERNAL (decl)) - { - if (!DECL_VIRTUAL_P (decl)) - error ("definition of static data member %q+D of dllimport%'d class", - decl); - return false; - } - - /* Since we can't treat a pointer to a dllimport'd symbol as a - constant address, we turn off the attribute on C++ virtual - methods to allow creation of vtables using thunks. Don't mark - artificial methods either (in sh_symbian_associated_type, only - COMDAT artificial method get import status from class context). */ - else if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE - && (DECL_VIRTUAL_P (decl) || DECL_ARTIFICIAL (decl))) - return false; - - return true; -} - - -/* This code implements a specification for exporting the vtable and rtti of - classes that have members with the dllexport or dllexport attributes. - This specification is defined here: - - http://www.armdevzone.com/EABI/exported_class.txt - - Basically it says that a class's vtable and rtti should be exported if - the following rules apply: - - - If it has any non-inline non-pure virtual functions, - at least one of these need to be declared dllimport - OR any of the constructors is declared dllimport. - - AND - - - The class has an inline constructor/destructor and - a key-function (placement of vtable uniquely defined) that - is defined in this translation unit. - - The specification also says that for classes which will have their - vtables and rtti exported that their base class(es) might also need a - similar exporting if: - - - Every base class needs to have its vtable & rtti exported - as well, if the following the conditions hold true: - + The base class has a non-inline declared non-pure virtual function - + The base class is polymorphic (has or inherits any virtual functions) - or the base class has any virtual base classes. */ - -/* Decide if a base class of a class should - also have its vtable and rtti exported. */ - -static void -sh_symbian_possibly_export_base_class (tree base_class) -{ - VEC(tree,gc) *method_vec; - int len; - - if (! (TYPE_CONTAINS_VPTR_P (base_class))) - return; - - method_vec = CLASSTYPE_METHOD_VEC (base_class); - len = method_vec ? VEC_length (tree, method_vec) : 0; - - for (;len --;) - { - tree member = VEC_index (tree, method_vec, len); - - if (! member) - continue; - - for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member)) - { - if (TREE_CODE (member) != FUNCTION_DECL) - continue; - - if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member)) - continue; - - if (! DECL_VIRTUAL_P (member)) - continue; - - if (DECL_PURE_VIRTUAL_P (member)) - continue; - - if (DECL_DECLARED_INLINE_P (member)) - continue; - - break; - } - - if (member) - break; - } - - if (len < 0) - return; - - /* FIXME: According to the spec this base class should be exported, but - a) how do we do this ? and - b) it does not appear to be necessary for compliance with the Symbian - OS which so far is the only consumer of this code. */ -#if SYMBIAN_DEBUG - print_node_brief (stderr, "", base_class, 0); - fprintf (stderr, " EXPORTed [base class of exported class]\n"); -#endif -} - -/* Add the named attribute to the given node. Copes with both DECLs and - TYPEs. Will only add the attribute if it is not already present. */ - -static void -sh_symbian_add_attribute (tree node, const char *attr_name) -{ - tree attrs; - tree attr; - - attrs = DECL_P (node) ? DECL_ATTRIBUTES (node) : TYPE_ATTRIBUTES (node); - - if (lookup_attribute (attr_name, attrs) != NULL_TREE) - return; - - attr = get_identifier (attr_name); - - if (DECL_P (node)) - DECL_ATTRIBUTES (node) = tree_cons (attr, NULL_TREE, attrs); - else - TYPE_ATTRIBUTES (node) = tree_cons (attr, NULL_TREE, attrs); - -#if SYMBIAN_DEBUG - fprintf (stderr, "propagate %s attribute", attr_name); - print_node_brief (stderr, " to", node, 0); - fprintf (stderr, "\n"); -#endif -} - -/* Add the named attribute to a class and its vtable and rtti. */ - -static void -sh_symbian_add_attribute_to_class_vtable_and_rtti (tree ctype, const char *attr_name) -{ - sh_symbian_add_attribute (ctype, attr_name); - - /* If the vtable exists then they need annotating as well. */ - if (CLASSTYPE_VTABLES (ctype)) - /* XXX - Do we need to annotate any vtables other than the primary ? */ - sh_symbian_add_attribute (CLASSTYPE_VTABLES (ctype), attr_name); - - /* If the rtti exists then it needs annotating as well. */ - if (TYPE_MAIN_VARIANT (ctype) - && CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype))) - sh_symbian_add_attribute (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)), - attr_name); -} - -/* Decide if a class needs to have an attribute because - one of its member functions has the attribute. */ - -static bool -sh_symbian_class_needs_attribute (tree ctype, const char *attribute_name) -{ - VEC(tree,gc) *method_vec; - - method_vec = CLASSTYPE_METHOD_VEC (ctype); - - /* If the key function has the attribute then the class needs it too. */ - if (TYPE_POLYMORPHIC_P (ctype) - && method_vec - && tree_contains_struct [TREE_CODE (ctype), TS_DECL_COMMON] == 1 - && lookup_attribute (attribute_name, - DECL_ATTRIBUTES (VEC_index (tree, method_vec, 0)))) - return true; - - /* Check the class's member functions. */ - if (TREE_CODE (ctype) == RECORD_TYPE) - { - unsigned int len; - - len = method_vec ? VEC_length (tree, method_vec) : 0; - - for (;len --;) - { - tree member = VEC_index (tree, method_vec, len); - - if (! member) - continue; - - for (member = OVL_CURRENT (member); - member; - member = OVL_NEXT (member)) - { - if (TREE_CODE (member) != FUNCTION_DECL) - continue; - - if (DECL_PURE_VIRTUAL_P (member)) - continue; - - if (! DECL_VIRTUAL_P (member)) - continue; - - if (lookup_attribute (attribute_name, DECL_ATTRIBUTES (member))) - { -#if SYMBIAN_DEBUG - print_node_brief (stderr, "", ctype, 0); - fprintf (stderr, " inherits %s because", attribute_name); - print_node_brief (stderr, "", member, 0); - fprintf (stderr, " has it.\n"); -#endif - return true; - } - } - } - } - -#if SYMBIAN_DEBUG - print_node_brief (stderr, "", ctype, 0); - fprintf (stderr, " does not inherit %s\n", attribute_name); -#endif - return false; -} - -/* Decide if a class needs its vtable and rtti exporting. */ - -static bool -symbian_export_vtable_and_rtti_p (tree ctype) -{ - bool inline_ctor_dtor; - bool dllimport_ctor_dtor; - bool dllimport_member; - tree binfo, base_binfo; - VEC(tree,gc) *method_vec; - tree key; - int i; - int len; - - /* Make sure that we are examining a class... */ - if (TREE_CODE (ctype) != RECORD_TYPE) - { -#if SYMBIAN_DEBUG - print_node_brief (stderr, "", ctype, 0); - fprintf (stderr, " does NOT need to be EXPORTed [not a class]\n"); -#endif - return false; - } - - /* If the class does not have a key function it - does not need to have its vtable exported. */ - if ((key = CLASSTYPE_KEY_METHOD (ctype)) == NULL_TREE) - { -#if SYMBIAN_DEBUG - print_node_brief (stderr, "", ctype, 0); - fprintf (stderr, " does NOT need to be EXPORTed [no key function]\n"); -#endif - return false; - } - - /* If the key fn has not been defined - then the class should not be exported. */ - if (! TREE_ASM_WRITTEN (key)) - { -#if SYMBIAN_DEBUG - print_node_brief (stderr, "", ctype, 0); - fprintf (stderr, " does NOT need to be EXPORTed [key function not defined]\n"); -#endif - return false; - } - - /* Check the class's member functions. */ - inline_ctor_dtor = false; - dllimport_ctor_dtor = false; - dllimport_member = false; - - method_vec = CLASSTYPE_METHOD_VEC (ctype); - len = method_vec ? VEC_length (tree, method_vec) : 0; - - for (;len --;) - { - tree member = VEC_index (tree, method_vec, len); - - if (! member) - continue; - - for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member)) - { - if (TREE_CODE (member) != FUNCTION_DECL) - continue; - - if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member)) - { - if (DECL_DECLARED_INLINE_P (member) - /* Ignore C++ backend created inline ctors/dtors. */ - && ( DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (member) - || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (member))) - inline_ctor_dtor = true; - - if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member))) - dllimport_ctor_dtor = true; - } - else - { - if (DECL_PURE_VIRTUAL_P (member)) - continue; - - if (! DECL_VIRTUAL_P (member)) - continue; - - if (DECL_DECLARED_INLINE_P (member)) - continue; - - if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member))) - dllimport_member = true; - } - } - } - - if (! dllimport_member && ! dllimport_ctor_dtor) - { -#if SYMBIAN_DEBUG - print_node_brief (stderr, "", ctype, 0); - fprintf (stderr, - " does NOT need to be EXPORTed [no non-pure virtuals or ctors/dtors with dllimport]\n"); -#endif - return false; - } - - if (! inline_ctor_dtor) - { -#if SYMBIAN_DEBUG - print_node_brief (stderr, "", ctype, 0); - fprintf (stderr, - " does NOT need to be EXPORTed [no inline ctor/dtor]\n"); -#endif - return false; - } - -#if SYMBIAN_DEBUG - print_node_brief (stderr, "", ctype, 0); - fprintf (stderr, " DOES need to be EXPORTed\n"); -#endif - - /* Now we must check and possibly export the base classes. */ - for (i = 0, binfo = TYPE_BINFO (ctype); - BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) - sh_symbian_possibly_export_base_class (BINFO_TYPE (base_binfo)); - - return true; -} - -/* Possibly override the decision to export class TYPE. Upon entry - IMPORT_EXPORT will contain 1 if the class is going to be exported, - -1 if it is going to be imported and 0 otherwise. This function - should return the modified value and perform any other actions - necessary to support the backend's targeted operating system. */ - -int -sh_symbian_import_export_class (tree ctype, int import_export) -{ - const char *attr_name = NULL; - - /* If we are exporting the class but it does not have the dllexport - attribute then we may need to add it. Similarly imported classes - may need the dllimport attribute. */ - switch (import_export) - { - case 1: attr_name = "dllexport"; break; - case -1: attr_name = "dllimport"; break; - default: break; - } - - if (attr_name - && ! lookup_attribute (attr_name, TYPE_ATTRIBUTES (ctype))) - { - if (sh_symbian_class_needs_attribute (ctype, attr_name)) - sh_symbian_add_attribute_to_class_vtable_and_rtti (ctype, attr_name); - - /* Classes can be forced to export their - vtable and rtti under certain conditions. */ - if (symbian_export_vtable_and_rtti_p (ctype)) - { - sh_symbian_add_attribute_to_class_vtable_and_rtti (ctype, "dllexport"); - - /* Make sure that the class and its vtable are exported. */ - import_export = 1; - - if (CLASSTYPE_VTABLES (ctype)) - DECL_EXTERNAL (CLASSTYPE_VTABLES (ctype)) = 1; - - /* Check to make sure that if the class has a key method that - it is now on the list of keyed classes. That way its vtable - will be emitted. */ - if (CLASSTYPE_KEY_METHOD (ctype)) - { - tree class; - - for (class = keyed_classes; class; class = TREE_CHAIN (class)) - if (class == ctype) - break; - - if (class == NULL_TREE) - { -#if SYMBIAN_DEBUG - print_node_brief (stderr, "Add node", ctype, 0); - fprintf (stderr, " to the keyed classes list\n"); -#endif - keyed_classes = tree_cons (NULL_TREE, ctype, keyed_classes); - } - } - - /* Make sure that the typeinfo will be emitted as well. */ - if (CLASS_TYPE_P (ctype)) - TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))) = 1; - } - } - - return import_export; -} - -/* Handle a "dllimport" or "dllexport" attribute; - arguments as in struct attribute_spec.handler. */ - -tree -sh_symbian_handle_dll_attribute (tree *pnode, tree name, tree args, - int flags, bool *no_add_attrs) -{ - tree thunk; - tree node = *pnode; - const char *attr = IDENTIFIER_POINTER (name); - - /* These attributes may apply to structure and union types being - created, but otherwise should pass to the declaration involved. */ - if (!DECL_P (node)) - { - if (flags & ((int) ATTR_FLAG_DECL_NEXT - | (int) ATTR_FLAG_FUNCTION_NEXT - | (int) ATTR_FLAG_ARRAY_NEXT)) - { - warning (OPT_Wattributes, "%qs attribute ignored", attr); - *no_add_attrs = true; - return tree_cons (name, args, NULL_TREE); - } - - if (TREE_CODE (node) != RECORD_TYPE && TREE_CODE (node) != UNION_TYPE) - { - warning (OPT_Wattributes, "%qs attribute ignored", attr); - *no_add_attrs = true; - } - - return NULL_TREE; - } - - /* Report error on dllimport ambiguities - seen now before they cause any damage. */ - else if (is_attribute_p ("dllimport", name)) - { - if (TREE_CODE (node) == VAR_DECL) - { - if (DECL_INITIAL (node)) - { - error ("variable %q+D definition is marked dllimport", - node); - *no_add_attrs = true; - } - - /* `extern' needn't be specified with dllimport. - Specify `extern' now and hope for the best. Sigh. */ - DECL_EXTERNAL (node) = 1; - /* Also, implicitly give dllimport'd variables declared within - a function global scope, unless declared static. */ - if (current_function_decl != NULL_TREE && ! TREE_STATIC (node)) - TREE_PUBLIC (node) = 1; - } - } - - /* If the node is an overloaded constructor or destructor, then we must - make sure that the attribute is propagated along the overload chain, - as it is these overloaded functions which will be emitted, rather than - the user declared constructor itself. */ - if (TREE_CODE (TREE_TYPE (node)) == METHOD_TYPE - && (DECL_CONSTRUCTOR_P (node) || DECL_DESTRUCTOR_P (node))) - { - tree overload; - - for (overload = OVL_CHAIN (node); overload; overload = OVL_CHAIN (overload)) - { - tree node_args; - tree func_args; - tree function = OVL_CURRENT (overload); - - if (! function - || ! DECL_P (function) - || (DECL_CONSTRUCTOR_P (node) && ! DECL_CONSTRUCTOR_P (function)) - || (DECL_DESTRUCTOR_P (node) && ! DECL_DESTRUCTOR_P (function))) - continue; - - /* The arguments must match as well. */ - for (node_args = DECL_ARGUMENTS (node), func_args = DECL_ARGUMENTS (function); - node_args && func_args; - node_args = TREE_CHAIN (node_args), func_args = TREE_CHAIN (func_args)) - if (TREE_TYPE (node_args) != TREE_TYPE (func_args)) - break; - - if (node_args || func_args) - { - /* We can ignore an extraneous __in_chrg arguments in the node. - GCC generated destructors, for example, will have this. */ - if ((node_args == NULL_TREE - || func_args != NULL_TREE) - && strcmp (IDENTIFIER_POINTER (DECL_NAME (node)), "__in_chrg") != 0) - continue; - } - - sh_symbian_add_attribute (function, attr); - - /* Propagate the attribute to any function thunks as well. */ - for (thunk = DECL_THUNKS (function); thunk; thunk = DECL_CHAIN (thunk)) - if (TREE_CODE (thunk) == FUNCTION_DECL) - sh_symbian_add_attribute (thunk, attr); - } - } - - if (TREE_CODE (node) == FUNCTION_DECL && DECL_VIRTUAL_P (node)) - { - /* Propagate the attribute to any thunks of this function. */ - for (thunk = DECL_THUNKS (node); thunk; thunk = DECL_CHAIN (thunk)) - if (TREE_CODE (thunk) == FUNCTION_DECL) - sh_symbian_add_attribute (thunk, attr); - } - - /* Report error if symbol is not accessible at global scope. */ - if (!TREE_PUBLIC (node) - && ( TREE_CODE (node) == VAR_DECL - || TREE_CODE (node) == FUNCTION_DECL)) - { - error ("external linkage required for symbol %q+D because of %qE attribute", - node, name); - *no_add_attrs = true; - } - -#if SYMBIAN_DEBUG - print_node_brief (stderr, "mark node", node, 0); - fprintf (stderr, " as %s\n", attr); -#endif - - return NULL_TREE; -} diff --git a/gcc/config/sh/symbian-post.h b/gcc/config/sh/symbian-post.h deleted file mode 100644 index a4497b96994..00000000000 --- a/gcc/config/sh/symbian-post.h +++ /dev/null @@ -1,88 +0,0 @@ -/* Definitions for the Symbian OS running on an SH part. - This file is included after all the other target specific headers. - - Copyright (C) 2004, 2007 Free Software Foundation, Inc. - Contributed by Red Hat. - - This file is part of GCC. - - GCC 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 3, or (at your - option) any later version. - - GCC 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 GCC; see the file COPYING3. If not see - <http://www.gnu.org/licenses/>. */ - -#undef TARGET_VERSION -#define TARGET_VERSION \ - fputs (" (Renesas SH for Symbian OS)", stderr); - -#undef LINK_EMUL_PREFIX -#define LINK_EMUL_PREFIX "shlsymbian" - - -#define SYMBIAN_EXPORT_NAME(NAME,FILE,DECL) \ - do \ - { \ - if ((DECL && sh_symbian_is_dllexported (DECL)) \ - || sh_symbian_is_dllexported_name (NAME)) \ - { \ - fprintf ((FILE), "\t.pushsection .directive\n"); \ - fprintf ((FILE), "\t.asciz \"EXPORT %s\\n\"\n", \ - sh_symbian_strip_name_encoding (NAME)); \ - fprintf ((FILE), "\t.popsection\n"); \ - } \ - } \ - while (0) - -/* Output a function definition label. */ -#undef ASM_DECLARE_FUNCTION_NAME -#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ - do \ - { \ - SYMBIAN_EXPORT_NAME ((NAME), (FILE), (DECL)); \ - ASM_OUTPUT_TYPE_DIRECTIVE ((FILE), (NAME), "function"); \ - ASM_DECLARE_RESULT ((FILE), DECL_RESULT (DECL)); \ - ASM_OUTPUT_LABEL ((FILE), (NAME)); \ - } \ - while (0) - -/* Output the label for an initialized variable. */ -#undef ASM_DECLARE_OBJECT_NAME -#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ - do \ - { \ - HOST_WIDE_INT size; \ - \ - SYMBIAN_EXPORT_NAME ((NAME), (FILE), (DECL)); \ - ASM_OUTPUT_TYPE_DIRECTIVE ((FILE), (NAME), "object"); \ - \ - size_directive_output = 0; \ - if (!flag_inhibit_size_directive \ - && (DECL) \ - && DECL_SIZE (DECL)) \ - { \ - size_directive_output = 1; \ - size = int_size_in_bytes (TREE_TYPE (DECL)); \ - ASM_OUTPUT_SIZE_DIRECTIVE ((FILE), (NAME), size); \ - } \ - \ - ASM_OUTPUT_LABEL ((FILE), (NAME)); \ - } \ - while (0) - -#undef ASM_OUTPUT_LABELREF -#define ASM_OUTPUT_LABELREF(FILE, NAME) \ - do \ - { \ - asm_fprintf ((FILE), "%U%s", \ - sh_symbian_strip_name_encoding (NAME)); \ - } \ - while (0) diff --git a/gcc/config/sh/symbian-pre.h b/gcc/config/sh/symbian-pre.h deleted file mode 100644 index d2229e071f2..00000000000 --- a/gcc/config/sh/symbian-pre.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Definitions for the Symbian OS running on an SH part. - This file is included before any other target specific headers. - - Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. - Contributed by Red Hat. - - This file is part of GCC. - - GCC 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 3, or (at your - option) any later version. - - GCC 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 GCC; see the file COPYING3. If not see - <http://www.gnu.org/licenses/>. */ - -/* Enable Symbian specific code. */ -#define SYMBIAN 1 - -/* Default to using the Renesas ABI. */ -#define TARGET_ABI_DEFAULT MASK_HITACHI - -#define SUBTARGET_CPP_SPEC "" - -/* Get tree.c to declare merge_dllimport_decl_attributes(). */ -#define TARGET_DLLIMPORT_DECL_ATTRIBUTES 1 - -/* The Symbian OS currently does not support exception handling. */ -#define SUBTARGET_CC1PLUS_SPEC "-fno-exceptions" - -/* Create constructor/destructor sections without the writable flag. - Symbian puts them into the text segment and munges them later on. */ -#define CTORS_SECTION_ASM_OP "\t.section\t.ctors,\"ax\",@progbits" -#define DTORS_SECTION_ASM_OP "\t.section\t.dtors,\"ax\",@progbits" diff --git a/gcc/config/sh/t-symbian b/gcc/config/sh/t-symbian deleted file mode 100644 index f0b7dabd4e5..00000000000 --- a/gcc/config/sh/t-symbian +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (C) 2004, 2006, 2008, 2009 Free Software Foundation, Inc. -# -# This file is part of GCC. -# -# GCC 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 3, or (at your option) -# any later version. -# -# GCC 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 GCC; see the file COPYING3. If not see -# <http://www.gnu.org/licenses/>. - -sh-c.o: $(srcdir)/config/sh/sh-c.c \ - $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TM_H) $(TM_P_H) coretypes.h - $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ - $(srcdir)/config/sh/sh-c.c - -symbian-cxx.o: \ - $(srcdir)/config/sh/symbian-cxx.c \ - $(srcdir)/config/sh/sh-symbian.h \ - $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(TREE_H) $(RTL_H) \ - toplev.h output.h coretypes.h flags.h expr.h - $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< - -symbian-c.o: \ - $(srcdir)/config/sh/symbian-c.c \ - $(srcdir)/config/sh/sh-symbian.h \ - $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(TREE_H) $(RTL_H) \ - toplev.h output.h coretypes.h flags.h expr.h - $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< - -symbian-base.o: \ - $(srcdir)/config/sh/symbian-base.c \ - $(srcdir)/config/sh/sh-symbian.h \ - $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(TREE_H) $(RTL_H) \ - toplev.h output.h coretypes.h flags.h expr.h - $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< - - -LIB1ASMSRC = sh/lib1funcs.asm -LIB1ASMFUNCS = _ashiftrt _ashiftrt_n _ashiftlt _lshiftrt _movstr \ - _movstr_i4 _mulsi3 _sdivsi3 _sdivsi3_i4 _udivsi3 _udivsi3_i4 _set_fpscr \ - $(LIB1ASMFUNCS_CACHE) - -# 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 - -dp-bit.c: $(srcdir)/config/fp-bit.c - cat $(srcdir)/config/fp-bit.c >> dp-bit.c - -fp-bit.c: $(srcdir)/config/fp-bit.c - echo '#define FLOAT' > fp-bit.c - cat $(srcdir)/config/fp-bit.c >> fp-bit.c - -$(T)crt1.o: $(srcdir)/config/sh/crt1.asm $(GCC_PASSES) - $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crt1.o -x assembler-with-cpp $(srcdir)/config/sh/crt1.asm -$(T)crti.o: $(srcdir)/config/sh/crti.asm $(GCC_PASSES) - $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/sh/crti.asm -$(T)crtn.o: $(srcdir)/config/sh/crtn.asm $(GCC_PASSES) - $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/sh/crtn.asm - -$(out_object_file): gt-sh.h -gt-sh.h : s-gtype ; @true - -symbian.o: $(srcdir)/config/sh/symbian.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) output.h flags.h $(TREE_H) expr.h toplev.h $(TM_P_H) - $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ - $(srcdir)/config/sh/symbian.c - - -# Local Variables: -# mode: Makefile -# End: diff --git a/gcc/config/svr3.h b/gcc/config/svr3.h deleted file mode 100644 index 243206245a6..00000000000 --- a/gcc/config/svr3.h +++ /dev/null @@ -1,146 +0,0 @@ -/* Operating system specific defines to be used when targeting GCC for - generic System V Release 3 system. - Copyright (C) 1991, 1996, 2000, 2002, 2004, 2007, 2010 - Free Software Foundation, Inc. - Contributed by Ron Guilmette (rfg@monkeys.com). - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -/* Define a symbol indicating that we are using svr3.h. */ -#define USING_SVR3_H - -/* Define a symbol so that libgcc* can know what sort of operating - environment and assembler syntax we are targeting for. */ -#define SVR3_target - -/* Assembler, linker, library, and startfile spec's. */ - -/* The .file command should always begin the output. */ -#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true - -/* This says how to output an assembler line - to define a global common symbol. */ -/* We don't use ROUNDED because the standard compiler doesn't, - and the linker gives error messages if a common symbol - has more than one length value. */ - -#undef ASM_OUTPUT_COMMON -#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ -( fputs (".comm ", (FILE)), \ - assemble_name ((FILE), (NAME)), \ - fprintf ((FILE), ",%lu\n", (unsigned long)(SIZE))) - -/* This says how to output an assembler line - to define a local common symbol. */ - -/* Note that using bss_section here caused errors - in building shared libraries on system V.3. */ -#undef ASM_OUTPUT_LOCAL -#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ - do { \ - int align = exact_log2 (ROUNDED); \ - if (align > 2) align = 2; \ - switch_to_section (data_section); \ - ASM_OUTPUT_ALIGN ((FILE), align == -1 ? 2 : align); \ - ASM_OUTPUT_LABEL ((FILE), (NAME)); \ - fprintf ((FILE), "\t.set .,.+%u\n", (int)(ROUNDED)); \ - } while (0) - -/* Output #ident as a .ident. */ - -#undef ASM_OUTPUT_IDENT -#define ASM_OUTPUT_IDENT(FILE, NAME) \ - fprintf (FILE, "\t.ident \"%s\"\n", NAME); - -/* Use periods rather than dollar signs in special g++ assembler names. */ - -#define NO_DOLLAR_IN_LABEL - -/* System V Release 3 uses COFF debugging info. */ - -#define SDB_DEBUGGING_INFO 1 - -/* We don't want to output DBX debugging information. */ - -#undef DBX_DEBUGGING_INFO - -/* The prefix to add to user-visible assembler symbols. - - For System V Release 3 the convention is to prepend a leading - underscore onto user-level symbol names. */ - -#undef USER_LABEL_PREFIX -#define USER_LABEL_PREFIX "_" - -/* This is how to store into the string LABEL - the symbol_ref name of an internal numbered label where - PREFIX is the class of label and NUM is the number within the class. - This is suitable for output with `assemble_name'. - - For most svr3 systems, the convention is that any symbol which begins - with a period is not put into the linker symbol table by the assembler. */ - -#undef ASM_GENERATE_INTERNAL_LABEL -#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ - sprintf (LABEL, "*%s%s%ld", LOCAL_LABEL_PREFIX, PREFIX, (long)(NUM)) - -/* We want local labels to start with period if made with asm_fprintf. */ -#undef LOCAL_LABEL_PREFIX -#define LOCAL_LABEL_PREFIX "." - -/* Support const sections and the ctors and dtors sections for g++. */ - -/* Define a few machine-specific details of the implementation of - constructors. - - The __CTORS_LIST__ goes in the .init section. Define CTOR_LIST_BEGIN - and CTOR_LIST_END to contribute to the .init section an instruction to - push a word containing 0 (or some equivalent of that). - - Define TARGET_ASM_CONSTRUCTOR to push the address of the constructor. */ - -#define INIT_SECTION_ASM_OP "\t.section\t.init" -#define FINI_SECTION_ASM_OP "\t.section .fini,\"x\"" -#define DTORS_SECTION_ASM_OP FINI_SECTION_ASM_OP - -/* CTOR_LIST_BEGIN and CTOR_LIST_END are machine-dependent - because they push on the stack. */ - -#ifndef STACK_GROWS_DOWNWARD - -/* Constructor list on stack is in reverse order. Go to the end of the - list and go backwards to call constructors in the right order. */ -#define DO_GLOBAL_CTORS_BODY \ -do { \ - func_ptr *p, *beg = alloca (0); \ - for (p = beg; *p; p++) \ - ; \ - while (p != beg) \ - (*--p) (); \ -} while (0) - -#else - -/* Constructor list on stack is in correct order. Just call them. */ -#define DO_GLOBAL_CTORS_BODY \ -do { \ - func_ptr *p, *beg = alloca (0); \ - for (p = beg; *p; ) \ - (*p++) (); \ -} while (0) - -#endif /* STACK_GROWS_DOWNWARD */ diff --git a/gcc/config/vax/netbsd.h b/gcc/config/vax/netbsd.h deleted file mode 100644 index 51c32f7346e..00000000000 --- a/gcc/config/vax/netbsd.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Definitions of target machine for GNU compiler. - NetBSD/vax a.out version. - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2007 - Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - - -#define TARGET_OS_CPP_BUILTINS() \ - do \ - { \ - NETBSD_OS_CPP_BUILTINS_AOUT(); \ - } \ - while (0) - -#undef CPP_SPEC -#define CPP_SPEC NETBSD_CPP_SPEC - -/* Make gcc agree with <machine/ansi.h> */ - -#undef SIZE_TYPE -#define SIZE_TYPE "unsigned int" - -#undef PTRDIFF_TYPE -#define PTRDIFF_TYPE "int" - -/* Until they use ELF or something that handles dwarf2 unwinds - and initialization stuff better. Use sjlj exceptions. */ -#undef DWARF2_UNWIND_INFO - -/* We use gas, not the UNIX assembler. */ -#undef TARGET_DEFAULT -#define TARGET_DEFAULT 0 |