diff options
Diffstat (limited to 'gcc/config/arc')
-rwxr-xr-x | gcc/config/arc/arc.c | 2203 | ||||
-rwxr-xr-x | gcc/config/arc/arc.h | 1642 | ||||
-rwxr-xr-x | gcc/config/arc/arc.md | 1630 | ||||
-rwxr-xr-x | gcc/config/arc/initfini.c | 157 | ||||
-rwxr-xr-x | gcc/config/arc/lib1funcs.asm | 273 | ||||
-rwxr-xr-x | gcc/config/arc/t-arc | 72 | ||||
-rwxr-xr-x | gcc/config/arc/xm-arc.h | 47 |
7 files changed, 0 insertions, 6024 deletions
diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c deleted file mode 100755 index 64aec44..0000000 --- a/gcc/config/arc/arc.c +++ /dev/null @@ -1,2203 +0,0 @@ -/* Subroutines used for code generation on the Argonaut ARC cpu. - Copyright (C) 1994, 1995, 1997 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* ??? This is an old port, and is undoubtedly suffering from bit rot. */ - -#include <stdio.h> -#include "config.h" -#include "tree.h" -#include "rtl.h" -#include "regs.h" -#include "hard-reg-set.h" -#include "real.h" -#include "insn-config.h" -#include "conditions.h" -#include "insn-flags.h" -#include "output.h" -#include "insn-attr.h" -#include "flags.h" -#include "expr.h" -#include "recog.h" - -/* Which cpu we're compiling for (NULL(=base), ???). */ -char *arc_cpu_string; -int arc_cpu_type; - -/* Name of mangle string to add to symbols to separate code compiled for each - cpu (or NULL). */ -char *arc_mangle_cpu; - -/* Save the operands last given to a compare for use when we - generate a scc or bcc insn. */ -rtx arc_compare_op0, arc_compare_op1; - -/* Name of text, data, and rodata sections, as specified on command line. - Selected by -m{text,data,rodata} flags. */ -char *arc_text_string = ARC_DEFAULT_TEXT_SECTION; -char *arc_data_string = ARC_DEFAULT_DATA_SECTION; -char *arc_rodata_string = ARC_DEFAULT_RODATA_SECTION; - -/* Name of text, data, and rodata sections used in varasm.c. */ -char *arc_text_section; -char *arc_data_section; -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 void record_cc_ref (); - -void arc_init_reg_tables (); - -/* Called by OVERRIDE_OPTIONS to initialize various things. */ - -void -arc_init (void) -{ - if (arc_cpu_string == 0 - || !strcmp (arc_cpu_string, "base")) - { - /* Ensure we have a printable value for the .cpu pseudo-op. */ - arc_cpu_string = "base"; - arc_cpu_type = 0; - arc_mangle_cpu = NULL; - } - else if (ARC_EXTENSION_CPU (arc_cpu_string)) - ; /* nothing to do */ - else - { - error ("bad value (%s) for -mcpu switch", arc_cpu_string); - arc_cpu_string = "base"; - arc_cpu_type = 0; - arc_mangle_cpu = NULL; - } - - /* Set the pseudo-ops for the various standard sections. */ - arc_text_section = xmalloc (strlen (arc_text_string) + sizeof (ARC_SECTION_FORMAT) + 1); - sprintf (arc_text_section, ARC_SECTION_FORMAT, arc_text_string); - arc_data_section = xmalloc (strlen (arc_data_string) + sizeof (ARC_SECTION_FORMAT) + 1); - sprintf (arc_data_section, ARC_SECTION_FORMAT, arc_data_string); - arc_rodata_section = xmalloc (strlen (arc_rodata_string) + sizeof (ARC_SECTION_FORMAT) + 1); - sprintf (arc_rodata_section, 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 char *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 (comparison) - 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 : abort (); - } - /*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 (op, x, y) - enum rtx_code op; - rtx x, y; -{ - 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; - } - } - 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. */ - -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]; - -void -arc_init_reg_tables () -{ - 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: - default: - /* mode_class hasn't been initialized yet for EXTRA_CC_MODES, so - we must explicitly check for them here. */ - if (i == (int) CCmode || i == (int) CCZNmode || i == (int) CCZNCmode) - arc_mode_class[i] = 1 << (int) C_MODE; - else - 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 -*/ - -/* Return nonzero if IDENTIFIER is a valid decl attribute. */ - -int -arc_valid_machine_decl_attribute (type, attributes, identifier, args) - tree type; - tree attributes; - tree identifier; - tree args; -{ - if (identifier == 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") - || !strcmp (TREE_STRING_POINTER (value), "ilink2")) - return 1; - } - return 0; -} - -/* Return zero if TYPE1 and TYPE are incompatible, one if they are compatible, - and two if they are nearly compatible (which causes a warning to be - generated). */ - -int -arc_comp_type_attributes (type1, type2) - tree type1, type2; -{ - return 1; -} - -/* Set the default attributes for TYPE. */ - -void -arc_set_default_type_attributes (type) - tree type; -{ -} - -/* Acceptable arguments to the call insn. */ - -int -call_address_operand (op, mode) - 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 (op, mode) - 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 (op, mode) - rtx op; - enum machine_mode mode; -{ - 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 (op, mode) - rtx op; - enum machine_mode mode; -{ - 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 (op, mode) - rtx op; - enum machine_mode mode; -{ - 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 (op, mode) - rtx op; - enum machine_mode mode; -{ - 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; - } - 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 (op, mode) - rtx op; - enum machine_mode mode; -{ - 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; - } - return 0; -} - -/* Return true if OP is an acceptable argument for a single word - move source. */ - -int -move_src_operand (op, mode) - 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 (op, mode) - 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 (op, mode) - 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 (op, mode) - 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 (op, mode) - 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 (op, mode) - 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 (op, mode) - rtx op; - enum machine_mode mode; -{ - /* 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 (op, mode) - rtx op; - enum machine_mode mode; -{ -#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 (op, mode) - rtx op; - enum machine_mode mode; -{ - enum rtx_code code = GET_CODE (op); - - if (GET_RTX_CLASS (code) != '<') - return 0; - - 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. Emit the compare insn and - return the rtx for the cc reg in the proper mode. */ - -rtx -gen_compare_reg (code, x, y) - enum rtx_code code; - rtx x, y; -{ - enum machine_mode mode = SELECT_CC_MODE (code, x, y); - rtx cc_reg; - - cc_reg = gen_rtx (REG, mode, 61); - - emit_insn (gen_rtx (SET, VOIDmode, cc_reg, - gen_rtx (COMPARE, mode, x, y))); - - return cc_reg; -} - -/* 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 (value) - rtx value; -{ - HOST_WIDE_INT low, high; - - if (GET_CODE (value) != CONST_DOUBLE) - abort (); - - 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-arc.h - to compensate. */ - -void -arc_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl) - CUMULATIVE_ARGS *cum; - enum machine_mode mode; - tree type; - int *pretend_size; - int no_rtl; -{ - int first_anon_arg; - - /* All BLKmode values are passed by reference. */ - if (mode == BLKmode) - abort (); - - /* We must treat `__builtin_va_alist' as an anonymous arg. */ - if (current_function_varargs) - first_anon_arg = *cum; - else - 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)); - move_block_from_reg (first_reg_offset, regblock, - MAX_ARC_PARM_REGS - first_reg_offset, - ((MAX_ARC_PARM_REGS - first_reg_offset) - * UNITS_PER_WORD)); - - *pretend_size = ((MAX_ARC_PARM_REGS - first_reg_offset + align_slop) - * UNITS_PER_WORD); - } -} - -/* Cost functions. */ - -/* Provide the costs of an addressing mode that contains ADDR. - If ADDR is not a valid address, its cost is irrelevant. */ - -int -arc_address_cost (addr) - rtx addr; -{ - switch (GET_CODE (addr)) - { - case REG : - /* This is handled in the macro that calls us. - It's here for documentation. */ - 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 (plus1) ? 1 : 2; - case CONST : - case SYMBOL_REF : - case LABEL_REF : - return 2; - default: - break; - } - 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 (decl) - 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_MACHINE_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 - abort (); - 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 \ - && (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_p))) - -#define MUST_SAVE_RETURN_ADDR (regs_ever_live[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 (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 = current_function_outgoing_args_size; - pretend_size = current_function_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) + current_function_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, base_reg, offset, gmask, op) - FILE *file; - char *base_reg; - unsigned int offset; - unsigned int gmask; - 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; - } - } -} - -/* Set up the stack and frame pointer (if desired) for the function. */ - -void -arc_output_function_prologue (file, size) - FILE *file; - int size; -{ - char *sp_str = reg_names[STACK_POINTER_REGNUM]; - 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. */ - if (size == 0 && gmask) - abort (); - - /* 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,%d\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. */ - -void -arc_output_function_epilogue (file, size) - FILE *file; - int size; -{ - rtx epilogue_delay = current_function_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 = !current_function_calls_alloca; - char *sp_str = reg_names[STACK_POINTER_REGNUM]; - 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) - { - if (!frame_pointer_needed) - abort (); - 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, -2, 1); - 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, -2, 1); - } - } - - /* Emit the return instruction. */ - { - static int regs[4] = { - 0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM - }; - 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) - { - if (frame_pointer_needed && !fp_restored_p) - abort (); - if (restored < size) - abort (); - final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1); - } - else if (frame_pointer_needed && !fp_restored_p) - { - if (!SMALL_INT (frame_size)) - abort (); - /* 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) - { - if (!SMALL_INT (size - restored)) - abort (); - fprintf (file, "\tadd %s,%s,%d\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 () -{ - 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 (trial, slot) - rtx trial; - int slot; -{ - if (slot != 0) - abort (); - - 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; -} - -/* PIC */ - -/* Emit special PIC prologues and epilogues. */ - -void -arc_finalize_pic () -{ - /* nothing to do */ -} - -/* Return true if OP is a shift operator. */ - -int -shift_operator (op, mode) - rtx op; - enum machine_mode mode; -{ - 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. */ - -char * -output_shift (operands) - rtx *operands; -{ - static int loopend_lab; - rtx shift = operands[3]; - enum machine_mode mode = GET_MODE (shift); - enum rtx_code code = GET_CODE (shift); - char *shift_one; - - if (mode != SImode) - abort (); - - 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: abort (); - } - - if (GET_CODE (operands[2]) != CONST_INT) - { - if (optimize) - output_asm_insn ("mov lp_count,%2", operands); - else - output_asm_insn ("mov %4,%2", operands); - goto shiftloop; - } - else - { - int n = INTVAL (operands[2]); - - /* If the count is negative, make it 0. */ - 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; - } - } - /* 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 ("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) - asm_fprintf (asm_out_file, "\t%s single insn loop\n", - ASM_COMMENT_START); - else - asm_fprintf (asm_out_file, "1:\t%s single insn loop\n", - ASM_COMMENT_START); - output_asm_insn (shift_one, operands); - } - else - { - asm_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); - asm_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 (tramp, fnaddr, cxt) - rtx tramp, fnaddr, cxt; -{ -} - -/* Set the cpu type and print out other fancy things, - at the top of the file. */ - -void -arc_asm_file_start (file) - FILE *file; -{ - fprintf (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, x, code) - 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_FLAG (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", - code == 'L' ? INTVAL (first) : INTVAL (second)); - } - else - output_operand_lossage ("invalid operand to %H/%L code"); - return; - case 'A' : - { - REAL_VALUE_TYPE d; - char str[30]; - - if (GET_CODE (x) != CONST_DOUBLE - || GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT) - abort (); - REAL_VALUE_FROM_CONST_DOUBLE (d, x); - REAL_VALUE_TO_DECIMAL (d, "%.20e", str); - 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, addr) - 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_FLAG (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); - if (GET_CODE (base) != REG) - abort (); - fputs (reg_names[REGNO (base)], file); - if (index == 0) - { - if (offset != 0) - fprintf (file, ",%d", offset); - } - else if (GET_CODE (index) == REG) - fprintf (file, ",%s", reg_names[REGNO (index)]); - else if (GET_CODE (index) == SYMBOL_REF) - fputc (',', file), output_addr_const (file, index); - else - abort (); - 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. */ - abort (); - break; - default : - output_addr_const (file, addr); - break; - } -} - -/* Update compare/branch separation marker. */ - -static void -record_cc_ref (insn) - 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 ASM_OUTPUT_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 (insn, opvec, noperands) - rtx insn; - rtx *opvec; - int noperands; -{ - /* BODY will hold the body of INSN. */ - register rtx body = PATTERN (insn); - - /* This will be 1 if trying to repeat the trick (ie: 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 - abort (); - - /* 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 if (seeking_return || arc_ccfsm_state == 2) - { - while (this_insn && GET_CODE (PATTERN (this_insn)) == USE) - { - this_insn = next_nonnote_insn (this_insn); - if (this_insn && (GET_CODE (this_insn) == BARRIER - || GET_CODE (this_insn) == CODE_LABEL)) - abort (); - } - if (!this_insn) - { - /* Oh dear! we ran off the end, give up. */ - insn_extract (insn); - arc_ccfsm_state = 0; - arc_ccfsm_target_insn = NULL; - return; - } - arc_ccfsm_target_insn = this_insn; - } - else - abort (); - - /* 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_operand. Getting the attributes of other insns can - destroy this array, but final.c assumes that it remains intact - across this call; since the insn has been recognized already we - call insn_extract direct. */ - insn_extract (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 ASM_OUTPUT_INTERNAL_LABEL. */ - -void -arc_ccfsm_at_label (prefix, num) - 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 () -{ - 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 () -{ - /* 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; -} diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h deleted file mode 100755 index 49d9fe2..0000000 --- a/gcc/config/arc/arc.h +++ /dev/null @@ -1,1642 +0,0 @@ -/* Definitions of target machine for GNU compiler, Argonaut ARC cpu. - Copyright (C) 1994, 1995, 1997, 1998 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* ??? This is an old port, and is undoubtedly suffering from bit rot. */ - -/* Things to do: - - - PREDICATE_CODES - - incscc, decscc? - - print active compiler options in assembler output -*/ - -/* ??? Create elf.h and have svr4.h include it. */ -#include "svr4.h" - -#undef ASM_SPEC -#undef LINK_SPEC -#undef STARTFILE_SPEC -#undef ENDFILE_SPEC -#undef SIZE_TYPE -#undef PTRDIFF_TYPE -#undef WCHAR_TYPE -#undef WCHAR_TYPE_SIZE - -/* 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 CPP_PREDEFINES "-Acpu(arc) -Amachine(arc) -D__arc__" - -/* Additional flags for the preprocessor. */ -#define CPP_SPEC "\ -%{!mcpu=*:-D__base__} %{mcpu=base:-D__base__} \ -%{EB:-D__big_endian__} \ -" - -/* 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 "%{v} %{EB} %{EL}" - -#define LINK_SPEC "%{v} %{EB} %{EL}" - -#define STARTFILE_SPEC "%{!shared:crt0.o%s} crtinit.o%s" - -#define ENDFILE_SPEC "crtfini.o%s" - -/* Run-time compilation parameters selecting different hardware subsets. */ - -extern int target_flags; - -/* Mangle all user symbols for the specified cpu. - ARC's can be shipped in which a collection of cpus are coupled together. - Each CPU may be different in some way, and thus we may need to distinguish - code compiled for one to ensure it isn't linked with code compiled for - another. */ -#define TARGET_MASK_MANGLE_CPU 1 -#define TARGET_MANGLE_CPU (target_flags & TARGET_MASK_MANGLE_CPU) - -#if 0 -/* Mangle libgcc symbols by adding a suffix for the specified cpu. */ -#define TARGET_MASK_MANGLE_CPU_LIBGCC 2 -#define TARGET_MANGLE_CPU_LIBGCC (target_flags & TARGET_MASK_MANGLE_CPU_LIBGCC) -#endif - -/* Align loops to 32 byte boundaries (cache line size). */ -#define TARGET_MASK_ALIGN_LOOPS 4 -#define TARGET_ALIGN_LOOPS (target_flags & TARGET_MASK_ALIGN_LOOPS) - -/* Big Endian. */ -#define TARGET_MASK_BIG_ENDIAN 8 -#define TARGET_BIG_ENDIAN (target_flags & TARGET_MASK_BIG_ENDIAN) - -/* Turn off conditional execution optimization, - so we can see how well it does, or in case it's buggy. */ -#define TARGET_MASK_NO_COND_EXEC 0x10 -#define TARGET_NO_COND_EXEC (target_flags & TARGET_MASK_NO_COND_EXEC) - -/* Macro to define tables used to set the flags. - This is a list in braces of pairs in braces, - each pair being { "NAME", VALUE } - where VALUE is the bits to set or minus the bits to clear. - An empty string NAME is used to identify the default VALUE. */ - -#define TARGET_SWITCHES \ -{ \ - { "mangle-cpu", TARGET_MASK_MANGLE_CPU }, \ - { "no-mangle-cpu", -TARGET_MASK_MANGLE_CPU }, \ -/* { "mangle-cpu-libgcc", TARGET_MASK_MANGLE_CPU_LIBGCC }, */ \ -/* { "no-mangle-cpu-libgcc", -TARGET_MASK_MANGLE_CPU_LIBGCC }, */ \ - { "align-loops", TARGET_MASK_ALIGN_LOOPS }, \ - { "no-align-loops", -TARGET_MASK_ALIGN_LOOPS }, \ - { "big-endian", TARGET_MASK_BIG_ENDIAN }, \ - { "little-endian", -TARGET_MASK_BIG_ENDIAN }, \ - { "no-cond-exec", TARGET_MASK_NO_COND_EXEC }, \ - SUBTARGET_SWITCHES \ - { "", TARGET_DEFAULT } \ -} - -#define TARGET_DEFAULT (0) - -#define SUBTARGET_SWITCHES - -/* Instruction set characteristics. - These are internal macros, set by the appropriate -mcpu= option. */ - -/* Non-zero means the cpu has a barrel shifter. */ -#define TARGET_SHIFTER 0 - -/* This macro is similar to `TARGET_SWITCHES' but defines names of - command options that have values. Its definition is an - initializer with a subgrouping for each command option. - - Each subgrouping contains a string constant, that defines the - fixed part of the option name, and the address of a variable. - The variable, type `char *', is set to the variable part of the - given option if the fixed part matches. The actual option name - is made by appending `-m' to the specified name. - - Here is an example which defines `-mshort-data-NUMBER'. If the - given option is `-mshort-data-512', the variable `m88k_short_data' - will be set to the string `"512"'. - - extern char *m88k_short_data; - #define TARGET_OPTIONS { { "short-data-", &m88k_short_data } } */ - -extern char *arc_cpu_string; -extern char *arc_text_string,*arc_data_string,*arc_rodata_string; - -#define TARGET_OPTIONS \ -{ \ - { "cpu=", &arc_cpu_string }, \ - { "text=", &arc_text_string }, \ - { "data=", &arc_data_string }, \ - { "rodata=", &arc_rodata_string }, \ -} - -/* 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 non-zero if the cpu is recognized, - otherwise zero. This is intended to be redefined in a cover file. - This is used by arc_init. */ -#define ARC_EXTENSION_CPU(cpu) 0 - -/* Sometimes certain combinations of command options do not make - sense on a particular target machine. You can define a macro - `OVERRIDE_OPTIONS' to take account of this. This macro, if - defined, is executed once just after all the command options have - been parsed. - - Don't use this macro to turn on various extra optimizations for - `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */ - -extern void arc_init (); - -#define OVERRIDE_OPTIONS \ -do { \ - /* These need to be done at start up. It's convenient to do them here. */ \ - arc_init (); \ -} while (0) - -/* Target machine storage layout. */ - -/* Define to use software floating point emulator for REAL_ARITHMETIC and - decimal <-> binary conversion. */ -#define REAL_ARITHMETIC - -/* 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) - -/* Define this to set the endianness to use in libgcc2.c, which can - not depend on target_flags. */ -#ifdef __big_endian__ -#define LIBGCC2_WORDS_BIG_ENDIAN 1 -#else -#define LIBGCC2_WORDS_BIG_ENDIAN 0 -#endif - -/* Number of bits in an addressable storage unit. */ -#define BITS_PER_UNIT 8 - -/* Width in bits of a "word", which is the contents of a machine register. - Note that this is not necessarily the width of data type `int'; - if using 16-bit ints on a 68000, this would still be 32. - But on a machine with 16-bit registers, this would be 16. */ -#define BITS_PER_WORD 32 - -/* 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; \ -} - -/* Define this macro if the promotion described by `PROMOTE_MODE' - should also be done for outgoing function arguments. */ -#define PROMOTE_FUNCTION_ARGS - -/* Likewise, if the function return value is promoted. */ -#define PROMOTE_FUNCTION_RETURN - -/* Width in bits of a pointer. - See also the macro `Pmode' defined below. */ -#define POINTER_SIZE 32 - -/* 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 bitfield 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 - -/* Define results of standard character escape sequences. */ -#define TARGET_BELL 007 -#define TARGET_BS 010 -#define TARGET_TAB 011 -#define TARGET_NEWLINE 012 -#define TARGET_VT 013 -#define TARGET_FF 014 -#define TARGET_CR 015 - -/* 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 GNU CC 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 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[]; -#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) < 29 || (unsigned) reg_renumber[REGNO] < 29) -#define REGNO_OK_FOR_INDEX_P(REGNO) \ -((REGNO) < 29 || (unsigned) reg_renumber[REGNO] < 29) - -/* Given an rtx X being reloaded into a reg required to be - in class CLASS, return the class of reg to actually use. - In general this is just CLASS; but on some machines - in some cases it is preferable to use a more restrictive class. */ -#define PREFERRED_RELOAD_CLASS(X,CLASS) \ -(CLASS) - -/* 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) \ - && (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_FLAG (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 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 - -/* 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 - -/* A C expression which is nonzero if a function must have and use a - frame pointer. This expression is evaluated in the reload pass. - If its value is nonzero the function will have a frame pointer. */ -#define FRAME_POINTER_REQUIRED \ -(current_function_calls_alloca) - -/* 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. */ - -/* When a prototype says `char' or `short', really pass an `int'. */ -#define PROMOTE_PROTOTYPES - -/* If defined, the maximum amount of space required for outgoing - arguments will be computed and placed into the variable - `current_function_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 - -/* Value is the number of bytes of arguments automatically - popped when returning from a subroutine call. - FUNDECL is the declaration node of the function (as a tree), - FUNTYPE is the data type of the function (as a tree), - or for a library call it is an identifier node for the subroutine name. - SIZE is the number of bytes of arguments passed on the stack. */ -#define RETURN_POPS_ARGS(DECL, FUNTYPE, SIZE) 0 - -/* 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) \ -((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) - -/* The ROUND_ADVANCE* macros are local to this file. */ -/* 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). - When passing arguments NAMED is always 1. When receiving arguments NAMED - is 1 for each argument except the last in a stdarg/varargs function. In - a stdarg function we want to treat the last named arg as named. In a - varargs function we want to treat the last named arg (which is - `__builtin_va_alist') as unnamed. - This macro is only used in this file. */ -extern int current_function_varargs; -#define PASS_IN_REG_P(CUM, MODE, TYPE, NAMED) \ -((!current_function_varargs || (NAMED)) \ - && (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. */ -#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ -(PASS_IN_REG_P ((CUM), (MODE), (TYPE), (NAMED)) \ - ? gen_rtx (REG, (MODE), ROUND_ADVANCE_CUM ((CUM), (MODE), (TYPE))) \ - : 0) - -/* A C expression for the number of words, at the beginning of an - argument, must be put in registers. The value must be zero for - arguments that are passed entirely in registers or that are entirely - pushed on the stack. - - On some machines, certain arguments must be passed partially in - registers and partially in memory. On these machines, typically the - first @var{n} words of arguments are passed in registers, and the rest - on the stack. If a multi-word argument (a @code{double} or a - structure) crosses that boundary, its first few words must be passed - in registers and the rest must be pushed. This macro tells the - compiler when this occurs, and how many of the words should go in - registers. */ -#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0 - -/* A C expression that indicates when an argument must be passed by - reference. If nonzero for an argument, a copy of that argument is - made in memory and a pointer to the argument is passed instead of - the argument itself. The pointer is passed in whatever way is - appropriate for passing a pointer to that type. */ -/* All aggregates and arguments greater than 8 bytes are passed this way. */ -#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \ -(TYPE \ - && (AGGREGATE_TYPE_P (TYPE) \ - || int_size_in_bytes (TYPE) > 8)) - -/* A C expression that indicates when it is the called function's - responsibility to make copies of arguments passed by reference. - If the callee can determine that the argument won't be modified, it can - avoid the copy. */ -/* ??? We'd love to be able to use NAMED here. Unfortunately, it doesn't - include the last named argument so we keep track of the args ourselves. */ - -#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) \ -FUNCTION_ARG_PASS_BY_REFERENCE ((CUM), (MODE), (TYPE), (NAMED)) - -/* 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.) */ -#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ -((CUM) = (ROUND_ADVANCE_CUM ((CUM), (MODE), (TYPE)) \ - + ROUND_ADVANCE_ARG ((MODE), (TYPE)))) - -/* If defined, a C expression that gives the alignment boundary, in bits, - of an argument with the specified mode and type. If it is not defined, - PARM_BOUNDARY is used for all arguments. */ -#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \ -(((TYPE) ? TYPE_ALIGN (TYPE) : GET_MODE_BITSIZE (MODE)) <= PARM_BOUNDARY \ - ? PARM_BOUNDARY \ - : 2 * PARM_BOUNDARY) - -/* This macro offers an alternative - to using `__builtin_saveregs' and defining the macro - `EXPAND_BUILTIN_SAVEREGS'. Use it to store the anonymous register - arguments into the stack so that all the arguments appear to have - been passed consecutively on the stack. Once this is done, you - can use the standard implementation of varargs that works for - machines that pass all their arguments on the stack. - - The argument ARGS_SO_FAR is the `CUMULATIVE_ARGS' data structure, - containing the values that obtain after processing of the named - arguments. The arguments MODE and TYPE describe the last named - argument--its machine mode and its data type as a tree node. - - The macro implementation should do two things: first, push onto the - stack all the argument registers *not* used for the named - arguments, and second, store the size of the data thus pushed into - the `int'-valued variable whose name is supplied as the argument - PRETEND_SIZE. The value that you store here will serve as - additional offset for setting up the stack frame. - - If the argument NO_RTL is nonzero, it means that the - arguments of the function are being analyzed for the second time. - This happens for an inline function, which is not actually - compiled until the end of the source file. The macro - `SETUP_INCOMING_VARARGS' should not generate any instructions in - this case. */ - -#define SETUP_INCOMING_VARARGS(ARGS_SO_FAR, MODE, TYPE, PRETEND_SIZE, NO_RTL) \ -arc_setup_incoming_varargs(&ARGS_SO_FAR, MODE, TYPE, &PRETEND_SIZE, NO_RTL) - -/* 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) - -/* A C expression which can inhibit the returning of certain function - values in registers, based on the type of value. A nonzero value says - to return the function value in memory, just as large structures are - always returned. Here TYPE will be a C expression of type `tree', - representing the data type of the value. */ -#define RETURN_IN_MEMORY(TYPE) \ -(AGGREGATE_TYPE_P (TYPE) \ - || int_size_in_bytes (TYPE) > 8 \ - || TREE_ADDRESSABLE (TYPE)) - -/* Tell GCC to use RETURN_IN_MEMORY. */ -#define DEFAULT_PCC_STRUCT_RETURN 0 - -/* Register in which address to store a structure value - is passed to a function, or 0 to use `invisible' first argument. */ -#define STRUCT_VALUE 0 - -/* Function entry and exit. */ - -/* This macro generates the assembly code for function entry. - FILE is a stdio stream to output the code to. - SIZE is an int: how many units of temporary storage to allocate. - Refer to the array `regs_ever_live' to determine which registers - to save; `regs_ever_live[I]' is nonzero if register number I - is ever used in the function. This macro is responsible for - knowing which registers should not be saved even if used. */ -#define FUNCTION_PROLOGUE(FILE, SIZE) \ -arc_output_function_prologue (FILE, SIZE) - -/* 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 - -/* This macro generates the assembly code for function exit, - on machines that need it. If FUNCTION_EPILOGUE is not defined - then individual return instructions are generated for each - return statement. Args are same as for FUNCTION_PROLOGUE. - - The function epilogue should not depend on the current stack pointer! - It should use the frame pointer only. This is mandatory because - of alloca; we also take advantage of it to omit stack adjustments - before returning. */ -#define FUNCTION_EPILOGUE(FILE, SIZE) \ -arc_output_function_epilogue (FILE, SIZE) - -/* 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) - -/* 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. :-( */ - -/* Output assembler code for a block containing the constant parts - of a trampoline, leaving space for the variable parts. */ -/* On the ARC, the trampoline is quite simple as we have 32 bit immediate - constants. - - mov r24,STATIC - j.nd FUNCTION -*/ -#define TRAMPOLINE_TEMPLATE(FILE) \ -do { \ - ASM_OUTPUT_INT (FILE, GEN_INT (0x631f7c00)); \ - ASM_OUTPUT_INT (FILE, const0_rtx); \ - ASM_OUTPUT_INT (FILE, GEN_INT (0x381f0000)); \ - ASM_OUTPUT_INT (FILE, const0_rtx); \ -} while (0) - -/* Length in units of the trampoline for entering a nested function. */ -#define TRAMPOLINE_SIZE 16 - -/* Emit RTL insns to initialize the variable parts of a trampoline. - FNADDR is an RTX for the address of the function's pure code. - CXT is an RTX for the static chain value for the function. */ -#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ -do { \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 4)), CXT); \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 12)), FNADDR); \ - emit_insn (gen_flush_icache (validize_mem (gen_rtx (MEM, SImode, TRAMP)))); \ -} while (0) - -/* Library calls. */ - -/* Generate calls to memcpy, memcmp and memset. */ -#define TARGET_MEM_FUNCTIONS - -/* 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) - 29 >= FIRST_PSEUDO_REGISTER - 29) -/* 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) - 29 >= FIRST_PSEUDO_REGISTER - 29) - -#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; \ -} - -/* Try machine-dependent ways of modifying an illegitimate address - to be legitimate. If we find one, return the new, valid address. - This macro is used in only one place: `memory_address' in explow.c. - - OLDX is the address as it was before break_out_memory_refs was called. - In some cases it is useful to look at this to decide what needs to be done. - - MODE and WIN are passed so that this macro can use - GO_IF_LEGITIMATE_ADDRESS. - - It is always safe for this macro to do nothing. It exists to recognize - opportunities to optimize the output. */ - -#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) - -/* Go to LABEL if ADDR (a legitimate address expression) - has an effect that depends on the machine mode it is used for. */ -#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ -{ if (GET_CODE (ADDR) == PRE_DEC) \ - goto LABEL; \ - if (GET_CODE (ADDR) == PRE_INC) \ - goto LABEL; \ -} - -/* Condition code usage. */ - -/* Some insns set all condition code flags, some only set the ZNC flags, and - some only set the ZN flags. */ - -#define EXTRA_CC_MODES CCZNCmode, CCZNmode - -#define EXTRA_CC_NAMES "CCZNC", "CCZN" - -/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, - return the mode to be used for the comparison. */ -extern enum machine_mode arc_select_cc_mode (); -#define SELECT_CC_MODE(OP, X, Y) \ -arc_select_cc_mode (OP, X, Y) - -/* Return non-zero if SELECT_CC_MODE will never return MODE for a - floating point inequality comparison. */ -#define REVERSIBLE_CC_MODE(MODE) 1 /*???*/ - -/* Costs. */ - -/* An insn is define to cost 4 "units", and we work from there. - COSTS_N_INSNS (N) is defined as (N) * 4 - 2 so that seems reasonable. - Some values are supposed to be defined relative to each other and thus - aren't necessarily related to COSTS_N_INSNS. */ - -/* Compute the cost of computing a constant rtl expression RTX - whose rtx-code is CODE. The body of this macro is a portion - of a switch statement. If the code is computed here, - return it with a return statement. Otherwise, break from the switch. */ -/* 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. */ -#define CONST_COSTS(X, CODE, OUTER_CODE) \ - case CONST_INT : \ - if (SMALL_INT (INTVAL (X))) \ - return 0; \ - /* fall through */ \ - case CONST : \ - case LABEL_REF : \ - case SYMBOL_REF : \ - return 4; \ - case CONST_DOUBLE : \ - { \ - rtx high, low; \ - split_double (X, &high, &low); \ - return 4 * (!SMALL_INT (INTVAL (high)) \ - + !SMALL_INT (INTVAL (low))); \ - } - -/* Compute the cost of an address. */ -#define ADDRESS_COST(ADDR) (REG_P (ADDR) ? 1 : arc_address_cost (ADDR)) - -/* Compute extra cost of moving data between one register class - and another. */ -#define REGISTER_MOVE_COST(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 2 - -/* Provide the costs of a rtl expression. This is in the body of a - switch on CODE. The purpose for the cost of MULT is to 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. */ -#define RTX_COSTS(X, CODE, OUTER_CODE) \ - case ASHIFT : \ - case ASHIFTRT : \ - case LSHIFTRT : \ - if (TARGET_SHIFTER) \ - return COSTS_N_INSNS (1); \ - if (GET_CODE (XEXP ((X), 1)) != CONST_INT) \ - return COSTS_N_INSNS (16); \ - return COSTS_N_INSNS (INTVAL (XEXP ((X), 1))); - -/* 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 - -/* Define this macro if it is as good or better for a function to call - itself with an explicit address than to call an address kept in a - register. */ -/* On the ARC, calling through registers is slow. */ -#define NO_RECURSIVE_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 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 /*"\t.section .text"*/ -#endif -#define DATA_SECTION_ASM_OP arc_data_section /*"\t.section .data"*/ - -#undef CONST_SECTION_ASM_OP -#define CONST_SECTION_ASM_OP arc_rodata_section /*"\t.section .rodata"*/ - -#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*/ - -/* Define this macro if references to a symbol must be treated - differently depending on something about the variable or - function named by the symbol (such as what section it is in). - - The macro definition, if any, is executed immediately after the - rtl for DECL or other node is created. - The value of the rtl will be a `mem' whose address is a - `symbol_ref'. - - The usual thing for this macro to do is to store a flag in the - `symbol_ref' (such as `SYMBOL_REF_FLAG') or to store a modified - name string in the `symbol_ref' (if one bit is not enough - information). */ - -/* On the ARC, function addresses are not the same as normal addresses. - Branch to absolute address insns take an address that is right-shifted - by 2. We encode the fact that we have a function here, and then emit a - special assembler op when outputting the address. */ -#define ENCODE_SECTION_INFO(DECL) \ -do { \ - if (TREE_CODE (DECL) == FUNCTION_DECL) \ - SYMBOL_REF_FLAG (XEXP (DECL_RTL (DECL), 0)) = 1; \ -} while (0) - -/* Decode SYM_NAME and store the real name part in VAR, sans - the characters that encode section info. Define this macro if - ENCODE_SECTION_INFO alters the symbol's name string. */ -/*#define STRIP_NAME_ENCODING(VAR, SYM_NAME)*/ - -/* For DWARF. Marginally different than default so output is "prettier" - (and consistent with above). */ -#define PUSHSECTION_FORMAT "\t%s %s\n" - -/* 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 26 - -/* 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*/ - -/* By generating position-independent code, when two different programs (A - and B) share a common library (libC.a), the text of the library can be - shared whether or not the library is linked at the same address for both - programs. In some of these environments, position-independent code - requires not only the use of different addressing modes, but also - special code to enable the use of these addressing modes. - - The FINALIZE_PIC macro serves as a hook to emit these special - codes once the function is being compiled into assembly code, but not - before. (It is not done before, because in the case of compiling an - inline function, it would lead to multiple PIC prologues being - included in functions which used inline functions and were compiled to - assembly language.) */ - -#define FINALIZE_PIC arc_finalize_pic () - -/* 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. */ - -/* Output at beginning of assembler file. */ -extern void arc_asm_file_start (); -#undef ASM_FILE_START -#define ASM_FILE_START(FILE) arc_asm_file_start (FILE) - -/* A C statement to output assembler commands which will identify the - object file as having been compiled with GNU CC (or another GNU - compiler). */ -#undef ASM_IDENTIFY_GCC -#define ASM_IDENTIFY_GCC(FILE) /* nothing */ - -/* Needed because we define ASM_IDENTIFY_GCC. */ -#define ASM_IDENTIFY_LANGUAGE(FILE) output_lang_identify (FILE) - -/* 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 "" - -/* This is how to output an assembler line defining a `char' constant. */ -#define ASM_OUTPUT_CHAR(FILE, VALUE) \ -( fprintf (FILE, "\t.byte\t"), \ - output_addr_const (FILE, (VALUE)), \ - fprintf (FILE, "\n")) - -/* This is how to output an assembler line defining a `short' constant. */ -#define ASM_OUTPUT_SHORT(FILE, VALUE) \ -( fprintf (FILE, "\t.hword\t"), \ - output_addr_const (FILE, (VALUE)), \ - fprintf (FILE, "\n")) - -/* This is how to output an assembler line defining an `int' constant. - We also handle symbol output here. Code addresses must be right shifted - by 2 because that's how the jump instruction wants them. */ -#define ASM_OUTPUT_INT(FILE, VALUE) \ -do { \ - fprintf (FILE, "\t.word\t"); \ - if ((GET_CODE (VALUE) == SYMBOL_REF && SYMBOL_REF_FLAG (VALUE)) \ - || GET_CODE (VALUE) == LABEL_REF) \ - { \ - fprintf (FILE, "%%st("); \ - output_addr_const (FILE, (VALUE)); \ - fprintf (FILE, ")"); \ - } \ - else \ - output_addr_const (FILE, (VALUE)); \ - fprintf (FILE, "\n"); \ -} while (0) - -/* This is how to output an assembler line defining a `float' constant. */ -#define ASM_OUTPUT_FLOAT(FILE, VALUE) \ -{ \ - long t; \ - char str[30]; \ - REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \ - REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", str); \ - fprintf (FILE, "\t.word\t0x%lx %s %s\n", \ - t, ASM_COMMENT_START, str); \ -} - -/* This is how to output an assembler line defining a `double' constant. */ -#define ASM_OUTPUT_DOUBLE(FILE, VALUE) \ -{ \ - long t[2]; \ - char str[30]; \ - REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t); \ - REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", str); \ - fprintf (FILE, "\t.word\t0x%lx %s %s\n\t.word\t0x%lx\n", \ - t[0], ASM_COMMENT_START, str, t[1]); \ -} - -/* This is how to output an assembler line for a numeric constant byte. */ -#define ASM_BYTE_OP ".byte" -#define ASM_OUTPUT_BYTE(FILE, VALUE) \ - fprintf (FILE, "\t%s\t0x%x\n", ASM_BYTE_OP, (VALUE)) - -/* The assembler's parentheses characters. */ -#define ASM_OPEN_PAREN "(" -#define ASM_CLOSE_PAREN ")" - -/* This is how to output the definition of a user-level label named NAME, - such as the label on a static function or variable NAME. */ -#define ASM_OUTPUT_LABEL(FILE, NAME) \ -do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) - -/* This is how to output a command to make the user-level label named NAME - defined for reference from other files. */ -#define ASM_GLOBALIZE_LABEL(FILE, NAME) \ -do { \ - fputs ("\t.global\t", FILE); \ - assemble_name (FILE, NAME); \ - fputs ("\n", FILE); \ -} while (0) - -/* A C statement (sans semicolon) to output on FILE an assembler pseudo-op to - declare a library function name external. The name of the library function - is given by SYMREF, which has type RTX and is a SYMBOL_REF. */ -#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. */ -extern char *arc_mangle_cpu; -#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, SYMREF) \ -do { \ - if (TARGET_MANGLE_CPU_LIBGCC) \ - { \ - fprintf (FILE, "\t.rename\t_%s, _%s%s\n", \ - XSTR (SYMREF, 0), XSTR (SYMREF, 0), \ - arc_mangle_suffix); \ - } \ -} while (0) -#endif - -/* 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 ASM_OUTPUT_INTERNAL_LABEL. */ -extern 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) - -/* 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. */ -#undef ASM_OUTPUT_INTERNAL_LABEL -#define ASM_OUTPUT_INTERNAL_LABEL(FILE, PREFIX, NUM) \ -do { \ - arc_ccfsm_at_label (PREFIX, NUM); \ - fprintf (FILE, ".%s%d:\n", PREFIX, NUM); \ -} while (0) - -/* Store in OUTPUT a string (made with alloca) containing - an assembler-name for a local static variable named NAME. - LABELNO is an integer which is different for each call. */ -#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ -( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ - sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) - -/* 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 ".set" - -/* A C statement (sans semicolon) to output an element in the table of - global constructors. */ -#undef ASM_OUTPUT_CONSTRUCTOR -#define ASM_OUTPUT_CONSTRUCTOR(FILE, NAME) \ -do { \ - ctors_section (); \ - fprintf (FILE, "\t.word\t%%st("); \ - assemble_name (FILE, NAME); \ - fprintf (FILE, ")\n"); \ -} while (0) - -/* A C statement (sans semicolon) to output an element in the table of - global destructors. */ -#undef ASM_OUTPUT_DESTRUCTOR -#define ASM_OUTPUT_DESTRUCTOR(FILE, NAME) \ -do { \ - dtors_section (); \ - fprintf (FILE, "\t.word\t%%st("); \ - assemble_name (FILE, NAME); \ - fprintf (FILE, ")\n"); \ -} while (0) - -/* 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[]; -#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. - - On some machines, the syntax for a symbolic address depends on - the section that the address refers to. On these machines, - define the macro `ENCODE_SECTION_INFO' to store the information - into the `symbol_ref', and then check for it here. */ -#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 -#define DWARF_DEBUGGING_INFO - -/* Prefer STABS (for now). */ -#undef PREFERRED_DEBUGGING_TYPE -#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG - -/* How to renumber registers for dbx and gdb. */ -#define DBX_REGISTER_NUMBER(REGNO) (REGNO) - -/* 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 as C expression which evaluates to nonzero if the tablejump - instruction expects the table to contain offsets from the address of the - table. - Do not define this if the table should contain absolute addresses. */ -/* It's not clear what PIC will look like or whether we want to use -fpic - for the embedded form currently being talked about. For now require -fpic - to get pc relative switch tables. */ -/*#define CASE_VECTOR_PC_RELATIVE 1 */ - -/* 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, NIL if none. */ -#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND - -/* Specify the tree operation to be used to convert reals to integers. */ -#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR - -/* This is the kind of divide that is easiest to do in the general case. */ -#define EASY_DIV_EXPR TRUNC_DIV_EXPR - -/* 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 - -/* We assume that the store-condition-codes instructions store 0 for false - and some other value for true. This is the value stored for true. */ -#define STORE_FLAG_VALUE 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 - -/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS - is a valid machine specific attribute for DECL. - The attributes in ATTRIBUTES have previously been assigned to TYPE. */ -extern int arc_valid_machine_attribute (); -#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ -arc_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) - -/* A C expression that returns zero if the attributes on TYPE1 and TYPE2 are - incompatible, one if they are compatible, and two if they are - nearly compatible (which causes a warning to be generated). */ -extern int arc_comp_type_attributes (); -#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \ -arc_comp_type_attributes (TYPE1, TYPE2) - -/* Give newly defined TYPE some default attributes. */ -extern void arc_set_default_type_attributes (); -#define SET_DEFAULT_TYPE_ATTRIBUTES(TYPE) \ -arc_set_default_type_attributes (TYPE) - -/* Define this if the target system supports the function - atexit from the ANSI C standard. If this is not defined, - and INIT_SECTION_ASM_OP is not defined, a default - exit function will be provided to support C++. */ -#define HAVE_ATEXIT - -/* alloca should avoid clobbering the old register save area. */ -/* ??? Not defined in tm.texi. */ -#define SETJMP_VIA_SAVE_AREA - -/* Define the information needed to generate branch and scc insns. This is - stored from the compare operation. Note that we can't use "rtx" here - since it hasn't been defined! */ -extern struct rtx_def *arc_compare_op0, *arc_compare_op1; - -/* Define the function that build the compare insn for scc and bcc. */ -extern struct rtx_def *gen_compare_reg (); - -/* Declarations for various fns used in the .md file. */ -extern char *output_shift (); - -/* 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. */ -enum arc_function_type arc_compute_function_type (); diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md deleted file mode 100755 index 328b1eb..0000000 --- a/gcc/config/arc/arc.md +++ /dev/null @@ -1,1630 +0,0 @@ -;; Machine description of the Argonaut ARC cpu for GNU C compiler -;; Copyright (C) 1994, 1997 Free Software Foundation, Inc. - -;; This file is part of GNU CC. - -;; GNU CC is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. - -;; GNU CC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU CC; see the file COPYING. If not, write to -;; the Free Software Foundation, 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;; 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 (eg: 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")]) - -;; Function units of the ARC - -;; (define_function_unit {name} {num-units} {n-users} {test} -;; {ready-delay} {issue-delay} [{conflict-list}]) - -;; 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_function_unit "compare" 1 0 (eq_attr "type" "compare") 2 2 [(eq_attr "type" "branch")]) - -;; 2) References to loaded registers should wait a cycle. - -;; Memory with load-delay of 1 (i.e., 2 cycle load). -(define_function_unit "memory" 1 1 (eq_attr "type" "load") 2 0) - -;; Units that take one cycle do not need to be specified. - -;; 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\"; - } -}" - [(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_insn (gen_rtx (CLOBBER, VOIDmode, 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 HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT - if (GET_CODE (operands[1]) == CONST_DOUBLE) - operands[1] = force_const_mem (SFmode, operands[1]); -#endif - - 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 HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT - if (GET_CODE (operands[1]) == CONST_DOUBLE) - operands[1] = force_const_mem (DFmode, operands[1]); -#endif - - 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\"; - } -}" - [(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_insn (gen_rtx (CLOBBER, VOIDmode, 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 (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 ccreg = gen_rtx (REG, - SELECT_CC_MODE (code, arc_compare_op0, arc_compare_op1), - 61); - - operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); -}") - -;(define_expand "movdicc" -; [(set (match_operand:DI 0 "register_operand" "") -; (if_then_else (match_operand 1 "comparison_operator" "") -; (match_operand:DI 2 "nonmemory_operand" "") -; (match_operand:DI 3 "register_operand" "")))] -; "0 /* ??? this would work better if we had cmpdi */" -; " -;{ -; enum rtx_code code = GET_CODE (operands[1]); -; rtx ccreg = gen_rtx (REG, -; SELECT_CC_MODE (code, arc_compare_op0, arc_compare_op1), -; 61); -; -; operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); -;}") - -(define_expand "movsfcc" - [(set (match_operand:SF 0 "register_operand" "") - (if_then_else (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 ccreg = gen_rtx (REG, - SELECT_CC_MODE (code, arc_compare_op0, arc_compare_op1), - 61); - - operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); -}") - -;(define_expand "movdfcc" -; [(set (match_operand:DF 0 "register_operand" "") -; (if_then_else (match_operand 1 "comparison_operator" "") -; (match_operand:DF 2 "nonmemory_operand" "") -; (match_operand:DF 3 "register_operand" "")))] -; "0 /* ??? can generate less efficient code if constants involved */" -; " -;{ -; enum rtx_code code = GET_CODE (operands[1]); -; rtx ccreg = gen_rtx (REG, -; SELECT_CC_MODE (code, arc_compare_op0, arc_compare_op1), -; 61); -; -; operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); -;}") - -(define_insn "*movsicc_insn" - [(set (match_operand:SI 0 "register_operand" "=r") - (if_then_else (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")]) - -; ??? This doesn't properly handle constants. -;(define_insn "*movdicc_insn" -; [(set (match_operand:DI 0 "register_operand" "=r,r") -; (if_then_else (match_operand 1 "comparison_operator" "") -; (match_operand:DI 2 "nonmemory_operand" "r,Ji") -; (match_operand:DI 3 "register_operand" "0,0")))] -; "0" -; "* -;{ -; 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[2]) + 1) -; return \"mov.%d1 %R0,%R2\;mov.%d1 %0,%2\"; -; else -; return \"mov.%d1 %0,%2\;mov.%d1 %R0,%R2\"; -; case 1 : -; return \"mov.%d1 %0,%2\;mov.%d1 %R0,%R2\"; -; } -;}" -; [(set_attr "type" "cmove,cmove") -; (set_attr "length" "2,4")]) - -(define_insn "*movsfcc_insn" - [(set (match_operand:SF 0 "register_operand" "=r,r") - (if_then_else (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")]) - -;(define_insn "*movdfcc_insn" -; [(set (match_operand:DF 0 "register_operand" "=r,r") -; (if_then_else (match_operand 1 "comparison_operator" "") -; (match_operand:DF 2 "nonmemory_operand" "r,E") -; (match_operand:DF 3 "register_operand" "0,0")))] -; "0" -; "* -;{ -; 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[2]) + 1) -; return \"mov.%d1 %R0,%R2\;mov.%d1 %0,%2\"; -; else -; return \"mov.%d1 %0,%2\;mov.%d1 %R0,%R2\"; -; case 1 : -; return \"mov.%d1 %0,%L2\;mov.%d1 %R0,%H2 ; %A2\"; -; } -;}" -; [(set_attr "type" "cmove,cmove") -; (set_attr "length" "2,4")]) - -;; 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:CC - (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, 0))))); - 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, 0))))); - 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, 0))))); - 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 generate RTL for comparisons and branches by having the cmpxx -;; patterns store away the operands. Then, the scc and bcc patterns -;; emit RTL for both the compare and the branch. - -(define_expand "cmpsi" - [(set (reg:CC 61) - (compare:CC (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "nonmemory_operand" "")))] - "" - " -{ - arc_compare_op0 = operands[0]; - arc_compare_op1 = operands[1]; - DONE; -}") - -;; ??? 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 insns. - -(define_expand "seq" - [(set (match_operand:SI 0 "register_operand" "=r") - (eq:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (EQ, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "sne" - [(set (match_operand:SI 0 "register_operand" "=r") - (ne:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (NE, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "sgt" - [(set (match_operand:SI 0 "register_operand" "=r") - (gt:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (GT, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "sle" - [(set (match_operand:SI 0 "register_operand" "=r") - (le:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (LE, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "sge" - [(set (match_operand:SI 0 "register_operand" "=r") - (ge:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (GE, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "slt" - [(set (match_operand:SI 0 "register_operand" "=r") - (lt:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (LT, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "sgtu" - [(set (match_operand:SI 0 "register_operand" "=r") - (gtu:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (GTU, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "sleu" - [(set (match_operand:SI 0 "register_operand" "=r") - (leu:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (LEU, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "sgeu" - [(set (match_operand:SI 0 "register_operand" "=r") - (geu:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (GEU, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "sltu" - [(set (match_operand:SI 0 "register_operand" "=r") - (ltu:SI (match_dup 1) (const_int 0)))] - "" - " -{ - operands[1] = gen_compare_reg (LTU, arc_compare_op0, arc_compare_op1); -}") - -(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 "beq" - [(set (pc) - (if_then_else (eq (match_dup 1) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (EQ, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "bne" - [(set (pc) - (if_then_else (ne (match_dup 1) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (NE, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "bgt" - [(set (pc) - (if_then_else (gt (match_dup 1) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (GT, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "ble" - [(set (pc) - (if_then_else (le (match_dup 1) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (LE, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "bge" - [(set (pc) - (if_then_else (ge (match_dup 1) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (GE, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "blt" - [(set (pc) - (if_then_else (lt (match_dup 1) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (LT, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "bgtu" - [(set (pc) - (if_then_else (gtu (match_dup 1) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (GTU, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "bleu" - [(set (pc) - (if_then_else (leu (match_dup 1) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (LEU, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "bgeu" - [(set (pc) - (if_then_else (geu (match_dup 1) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (GEU, arc_compare_op0, arc_compare_op1); -}") - -(define_expand "bltu" - [(set (pc) - (if_then_else (ltu (match_dup 1) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - " -{ - operands[1] = gen_compare_reg (LTU, arc_compare_op0, arc_compare_op1); -}") - -;; 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/initfini.c b/gcc/config/arc/initfini.c deleted file mode 100755 index 084e229..0000000 --- a/gcc/config/arc/initfini.c +++ /dev/null @@ -1,157 +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 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* As a special exception, if you link this file with files - compiled with GCC to produce an executable, this does not cause - the resulting executable to be covered by the GNU General Public License. - This exception does not however invalidate any other reasons why - the executable file might be covered by the GNU General Public License. */ - -/* 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 () -asm ("__do_global_dtors") __attribute__ ((section (".text"))); - -static void -__do_global_dtors () -{ - 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 (" - .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 (" - .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 -"); - -#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 () -asm ("__do_global_ctors") __attribute__ ((section (".text"))); - -static void -__do_global_ctors () -{ - 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 (" - .section .init\n - bl.nd __do_global_ctors - 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 (" - .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 100755 index a2d509a..0000000 --- a/gcc/config/arc/lib1funcs.asm +++ /dev/null @@ -1,273 +0,0 @@ -; libgcc1 routines for ARC cpu. - -/* Copyright (C) 1995, 1997 Free Software Foundation, Inc. - -This file is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -In addition to the permissions in the GNU General Public License, the -Free Software Foundation gives you unlimited permission to link the -compiled version of this file with other programs, and to distribute -those programs without any restriction coming from the use of this -file. (The General Public License restrictions do apply in other -respects; for example, they cover modification of the file, and -distribution when not linked into another program.) - -This file is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* As a special exception, if you link this library with other files, - some of which are compiled with GCC, to produce an executable, - this library does not by itself cause the resulting executable - to be covered by the GNU General Public License. - This exception does not however invalidate any other reasons why - the executable file might be covered by the GNU General Public License. */ - -#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) - add.nz r4,r4,r1 ; r += b - adc.nz r3,r3,r2 - 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 100755 index d922c27..0000000 --- a/gcc/config/arc/t-arc +++ /dev/null @@ -1,72 +0,0 @@ -CROSS_LIBGCC1 = libgcc1-asm.a -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 - -# These are really part of libgcc1, but this will cause them to be -# built correctly, so... - -LIB2FUNCS_EXTRA = fp-bit.c 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 - -x-crtinit.o: $(srcdir)/config/arc/initfini.c $(GCC_PASSES) $(CONFIG_H) - $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(CRTSTUFF_T_CFLAGS) \ - -DCRT_INIT -finhibit-size-directive -fno-inline-functions \ - -g0 -c $(srcdir)/config/arc/initfini.c -o $(dir)/crtinit.o - -x-crtfini.o: $(srcdir)/config/arc/initfini.c $(GCC_PASSES) $(CONFIG_H) - $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(CRTSTUFF_T_CFLAGS) \ - -DCRT_FINI -finhibit-size-directive -fno-inline-functions \ - -g0 -c $(srcdir)/config/arc/initfini.c -o $(dir)/crtfini.o - -MULTILIB_OPTIONS = EB -MULTILIB_DIRNAMES = be - -# We need our own versions to build multiple copies of crt*.o. -# ??? Use new support in Makefile. - -LIBGCC = stmp-multilib-arc -INSTALL_LIBGCC = install-multilib-arc - -stmp-multilib-arc: stmp-multilib - for i in `$(GCC_FOR_TARGET) --print-multi-lib`; do \ - dir=`echo $$i | sed -e 's/;.*$$//'`; \ - flags=`echo $$i | sed -e 's/^[^;]*;//' -e 's/@/ -/g'`; \ - $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \ - CC="$(CC)" CFLAGS="$(CFLAGS)" \ - HOST_PREFIX="$(HOST_PREFIX)" HOST_PREFIX_1="$(HOST_PREFIX_1)" \ - GCC_CFLAGS="$(GCC_CFLAGS) $${flags}" \ - INCLUDES="$(INCLUDES)" CRTSTUFF_T_CFLAGS=$(CRTSTUFF_T_CFLAGS) \ - dir="$${dir}" x-crtinit.o x-crtfini.o; \ - if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ - done - touch stmp-multilib-arc - -install-multilib-arc: install-multilib - for i in `$(GCC_FOR_TARGET) --print-multi-lib`; do \ - dir=`echo $$i | sed -e 's/;.*$$//'`; \ - rm -f $(libsubdir)/$${dir}/crtinit.o; \ - $(INSTALL_DATA) $${dir}/crtinit.o $(libsubdir)/$${dir}/crtinit.o; \ - chmod a-x $(libsubdir)/$${dir}/crtinit.o; \ - rm -f $(libsubdir)/$${dir}/crtfini.o; \ - $(INSTALL_DATA) $${dir}/crtfini.o $(libsubdir)/$${dir}/crtfini.o; \ - chmod a-x $(libsubdir)/$${dir}/crtfini.o; \ - done diff --git a/gcc/config/arc/xm-arc.h b/gcc/config/arc/xm-arc.h deleted file mode 100755 index ba011e9..0000000 --- a/gcc/config/arc/xm-arc.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Configuration for GNU C-compiler for the ARC processor. - Copyright (C) 1994, 1997 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* #defines that need visibility everywhere. */ -#define FALSE 0 -#define TRUE 1 - -/* This describes the machine the compiler is hosted on. */ -#define HOST_BITS_PER_CHAR 8 -#define HOST_BITS_PER_SHORT 16 -#define HOST_BITS_PER_INT 32 -#define HOST_BITS_PER_LONG 32 -#define HOST_BITS_PER_LONGLONG 64 - -/* Doubles are stored in memory with the high order word first. This - matters when cross-compiling. */ -#define HOST_WORDS_BIG_ENDIAN 1 - -/* target machine dependencies. - tm.h is a symbolic link to the actual target specific file. */ -#include "tm.h" - -/* Arguments to use with `exit'. */ -#define SUCCESS_EXIT_CODE 0 -#define FATAL_EXIT_CODE 33 - -/* If compiled with Sun CC, the use of alloca requires this #include. */ -#ifndef __GNUC__ -#include "alloca.h" -#endif |