diff options
author | Ian Dall <Ian.Dall@dsto.defence.gov.au> | 1998-11-25 23:34:42 +0000 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 1998-11-25 15:34:42 -0800 |
commit | 8357595779418585b4390bb66be518b32374965a (patch) | |
tree | 67aa038fe8d8b1eef82738fc896e6e5674ceb31b /gcc/config/ns32k | |
parent | 36696297f1a68d0789ec6cf07ac23cf640bd61ce (diff) | |
download | gcc-8357595779418585b4390bb66be518b32374965a.zip gcc-8357595779418585b4390bb66be518b32374965a.tar.gz gcc-8357595779418585b4390bb66be518b32374965a.tar.bz2 |
Bulk ns32k patch from Ian Dall. See ChangeLog for details.
Co-Authored-By: Matthias Pfaller <leo@dachau.marco.de>
From-SVN: r23887
Diffstat (limited to 'gcc/config/ns32k')
-rw-r--r-- | gcc/config/ns32k/netbsd.h | 7 | ||||
-rw-r--r-- | gcc/config/ns32k/ns32k.c | 500 | ||||
-rw-r--r-- | gcc/config/ns32k/ns32k.h | 488 | ||||
-rw-r--r-- | gcc/config/ns32k/ns32k.md | 700 |
4 files changed, 1212 insertions, 483 deletions
diff --git a/gcc/config/ns32k/netbsd.h b/gcc/config/ns32k/netbsd.h index cef68d8..bc86e31 100644 --- a/gcc/config/ns32k/netbsd.h +++ b/gcc/config/ns32k/netbsd.h @@ -24,9 +24,10 @@ Boston, MA 02111-1307, USA. /* Compile for the floating point unit & 32532 by default; Don't assume SB is zero; - Don't use bitfield instructions; */ + Don't use bitfield instructions; + FPU is 32381; */ -#define TARGET_DEFAULT (1 + 24 + 32 + 64) +#define TARGET_DEFAULT (1 + 24 + 32 + 64 + 256) /* 32-bit alignment for efficiency */ @@ -68,7 +69,7 @@ Boston, MA 02111-1307, USA. /* Names to predefine in the preprocessor for this target machine. */ #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dunix -Dns32k -Dns32000 -Dns32532 -D__NetBSD__ -Dpc532 -D__ns32k__ -Asystem(unix) -Asystem(NetBSD) -Acpu(ns32k) -Amachine(ns32k)" +#define CPP_PREDEFINES "-Dns32k -Dns32000 -Dns32532 -D__NetBSD__ -Dpc532 -D__ns32k__ -D__KPRINTF_ATTRIBUTE__ -Asystem(unix) -Asystem(NetBSD) -Acpu(ns32k) -Amachine(ns32k)" /* Make gcc agree with <machine/ansi.h> */ diff --git a/gcc/config/ns32k/ns32k.c b/gcc/config/ns32k/ns32k.c index 8c2fb1f..af89e59 100644 --- a/gcc/config/ns32k/ns32k.c +++ b/gcc/config/ns32k/ns32k.c @@ -20,7 +20,7 @@ Boston, MA 02111-1307, USA. */ /* Some output-actions in ns32k.md need these. */ #include "config.h" -#include <stdio.h> +#include "system.h" #include "rtl.h" #include "regs.h" #include "hard-reg-set.h" @@ -30,11 +30,33 @@ Boston, MA 02111-1307, USA. */ #include "insn-flags.h" #include "output.h" #include "insn-attr.h" +#include "tree.h" +#include "expr.h" +#include "flags.h" #ifdef OSF_OS int ns32k_num_files = 0; #endif +/* This duplicates reg_class_contens in reg_class.c, but maybe that isn't + initialized in time. Also this is more convenient as an array of ints. + We know that HARD_REG_SET fits in an unsigned int */ + +unsigned int ns32k_reg_class_contents[N_REG_CLASSES] = REG_CLASS_CONTENTS; + +enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] = +{ + GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, + GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, + FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS, FLOAT_REGS, + FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, + FP_REGS, FP_REGS, FP_REGS, FP_REGS, + FP_REGS, FP_REGS, FP_REGS, FP_REGS, + FRAME_POINTER_REG, STACK_POINTER_REG +}; + +char *ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES; + void trace (s, s1, s2) char *s, *s1, *s2; @@ -42,78 +64,67 @@ trace (s, s1, s2) fprintf (stderr, s, s1, s2); } -/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ int hard_regno_mode_ok (regno, mode) int regno; enum machine_mode mode; { - switch (mode) + int size = GET_MODE_UNIT_SIZE(mode); + + if (FLOAT_MODE_P(mode)) { - case QImode: - case HImode: - case PSImode: - case SImode: - case PDImode: - case VOIDmode: - case BLKmode: - if (regno < 8 || regno == 16 || regno == 17) + if (size == UNITS_PER_WORD && regno < L1_REGNUM) return 1; - else - return 0; - - case DImode: - if (regno < 8 && (regno & 1) == 0) + if (size == UNITS_PER_WORD * 2 + && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM))) return 1; - else - return 0; - - case SFmode: - case SCmode: - if (TARGET_32081) - { - if (regno < 16) - return 1; - else - return 0; - } - else - { - if (regno < 8) - return 1; - else - return 0; - } - - case DFmode: - case DCmode: - if ((regno & 1) == 0) - { - if (TARGET_32081) - { - if (regno < 16) - return 1; - else - return 0; - } - else - { - if (regno < 8) - return 1; - else - return 0; - } - } - else - return 0; + return 0; } - - /* Used to abort here, but simply saying "no" handles TImode - much better. */ + if (size == UNITS_PER_WORD * 2 + && (regno & 1) == 0 && regno < F0_REGNUM) + return 1; + if (size <= UNITS_PER_WORD + && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM + || regno == STACK_POINTER_REGNUM)) + return 1; return 0; } +int register_move_cost(CLASS1, CLASS2) + enum reg_class CLASS1; + enum reg_class CLASS2; +{ + if (CLASS1 == NO_REGS || CLASS2 == NO_REGS) + return 2; + if((SUBSET_P(CLASS1, FP_REGS) && !SUBSET_P(CLASS2, FP_REGS)) + || (!SUBSET_P(CLASS1, FP_REGS) && SUBSET_P(CLASS2, FP_REGS))) + return 8; + if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P(CLASS2,GENERAL_REGS)) + || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P(CLASS1,GENERAL_REGS))) + return 6; + if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P(CLASS2,GENERAL_REGS)) + || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P(CLASS1,GENERAL_REGS))) + return 6; + return 2; +} + +#if 0 +/* We made the insn definitions copy from floating point to general + registers via the stack. */ +int secondary_memory_needed(CLASS1, CLASS2, M) + enum reg_class CLASS1; + enum reg_class CLASS2; + enum machine_mode M; +{ + int ret = ((SUBSET_P(CLASS1, FP_REGS) && !SUBSET_P(CLASS2, FP_REGS)) + || (!SUBSET_P(CLASS1, FP_REGS) && SUBSET_P(CLASS2, FP_REGS))); + return ret; +} +#endif + + /* ADDRESS_COST calls this. This function is not optimal for the 32032 & 32332, but it probably is better than the default. */ @@ -146,8 +157,10 @@ calc_address_cost (operand) case POST_DEC: case PRE_DEC: break; - case MULT: case MEM: + cost += calc_address_cost (XEXP (operand, 0)); + break; + case MULT: case PLUS: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++) { @@ -174,30 +187,18 @@ secondary_reload_class (class, mode, in) if (regno >= FIRST_PSEUDO_REGISTER) regno = -1; - /* We can place anything into GENERAL_REGS and can put GENERAL_REGS - into anything. */ - if (class == GENERAL_REGS || (regno >= 0 && regno < 8)) - return NO_REGS; - - /* Constants, memory, and FP registers can go into FP registers. */ - if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS)) - return NO_REGS; - -#if 0 /* This isn't strictly true (can't move fp to sp or vice versa), - so it's cleaner to use PREFERRED_RELOAD_CLASS - to make the right things happen. */ - if (regno >= 16 && class == GEN_AND_MEM_REGS) + if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM) + || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM)) + return GENERAL_REGS; + else return NO_REGS; -#endif - - /* Otherwise, we need GENERAL_REGS. */ - return GENERAL_REGS; } + /* Generate the rtx that comes from an address expression in the md file */ /* The expression to be build is BASE[INDEX:SCALE]. To recognize this, scale must be converted from an exponent (from ASHIFT) to a multiplier (for MULT). */ -rtx +static rtx gen_indexed_expr (base, index, scale) rtx base, index, scale; { @@ -226,6 +227,7 @@ reg_or_mem_operand (op, mode) || GET_CODE (op) == SUBREG || GET_CODE (op) == MEM)); } + /* Split one or more DImode RTL references into pairs of SImode references. The RTL can be REG, offsettable MEM, integer constant, or @@ -404,27 +406,163 @@ output_move_double (operands) return singlemove_string (operands); } -int -check_reg (oper, reg) - rtx oper; - int reg; + +#define MAX_UNALIGNED_COPY (32) +/* Expand string/block move operations. + + operands[0] is the pointer to the destination. + operands[1] is the pointer to the source. + operands[2] is the number of bytes to move. + operands[3] is the alignment. */ + +static void +move_tail(operands, bytes, offset) + rtx operands[]; + int bytes; + int offset; { - register int i; + if (bytes & 2) + { + rtx src, dest; + dest = change_address(operands[0], HImode, + plus_constant(XEXP(operands[0], 0), offset)); + src = change_address(operands[1], HImode, + plus_constant(XEXP(operands[1], 0), offset)); + emit_move_insn(dest, src); + offset += 2; + } + if (bytes & 1) + { + rtx src, dest; + dest = change_address(operands[0], QImode, + plus_constant(XEXP(operands[0], 0), offset)); + src = change_address(operands[1], QImode, + plus_constant(XEXP(operands[1], 0), offset)); + emit_move_insn(dest, src); + } +} - if (oper == 0) - return 0; - switch (GET_CODE(oper)) +void +expand_block_move (operands) + rtx operands[]; +{ + rtx bytes_rtx = operands[2]; + rtx align_rtx = operands[3]; + int constp = (GET_CODE (bytes_rtx) == CONST_INT); + int bytes = (constp ? INTVAL (bytes_rtx) : 0); + int align = INTVAL (align_rtx); + rtx src_reg = gen_rtx(REG, Pmode, 1); + rtx dest_reg = gen_rtx(REG, Pmode, 2); + rtx count_reg = gen_rtx(REG, SImode, 0); + rtx insn; + + if (constp && bytes <= 0) + return; + + if (constp && bytes < 20) { - case REG: - return (REGNO(oper) == reg) ? 1 : 0; - case MEM: - return check_reg(XEXP(oper, 0), reg); - case PLUS: - case MULT: - return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg); + int words = bytes >> 2; + if (words) + if (words < 3 || flag_unroll_loops) + { + int offset = 0; + for (; words; words--, offset += 4) + { + rtx src, dest; + dest = change_address(operands[0], SImode, + plus_constant(XEXP(operands[0], 0), offset)); + src = change_address(operands[1], SImode, + plus_constant(XEXP(operands[1], 0), offset)); + emit_move_insn(dest, src); + } + } + else + { + /* Use movmd. It is slower than multiple movd's but more + compact. It is also slower than movsd for large copies + but causes less registers reloading so is better than movsd + for small copies. */ + rtx src, dest; + dest = copy_addr_to_reg (XEXP(operands[0], 0)); + src = copy_addr_to_reg (XEXP(operands[1], 0)); + + emit_insn(gen_movstrsi2(dest, src, GEN_INT(words))); + } + move_tail(operands, bytes & 3, bytes & ~3); + return; + } + + if (align > UNITS_PER_WORD) + align = UNITS_PER_WORD; + + /* Move the address into scratch registers. */ + emit_insn(gen_rtx(CLOBBER, VOIDmode, dest_reg)); + emit_move_insn(dest_reg, XEXP (operands[0], 0)); + emit_insn(gen_rtx(CLOBBER, VOIDmode, src_reg)); + emit_move_insn(src_reg, XEXP (operands[1], 0)); + emit_insn(gen_rtx(CLOBBER, VOIDmode, count_reg)); + + if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY)) + { + rtx bytes_reg; + + /* constant no of bytes and aligned or small enough copy to not bother + * aligning. Emit insns to copy by words. + */ + if (bytes >> 2) + { + emit_move_insn(count_reg, GEN_INT(bytes >> 2)); + emit_insn(gen_movstrsi1 (GEN_INT(4))); + } + /* insns to copy rest */ + move_tail(operands, bytes & 3, bytes & ~3); + } + else if (align == UNITS_PER_WORD) + { + /* insns to copy by words */ + emit_insn(gen_lshrsi3 (count_reg, bytes_rtx, GEN_INT(2))); + emit_insn(gen_movstrsi1 (GEN_INT(4))); + /* insns to copy rest */ + emit_insn(gen_andsi3 (count_reg, bytes_rtx, GEN_INT(3))); + emit_insn(gen_movstrsi1 (const1_rtx)); + } + else + { + /* Not aligned and we may have a lot to copy so it is worth + * aligning. + */ + rtx aligned_label = gen_label_rtx (); + rtx bytes_reg; + + bytes_reg = copy_to_mode_reg(SImode, bytes_rtx); + if (!constp) + { + /* Emit insns to test and skip over the alignment if it is + * not worth it. This doubles as a test to ensure that the alignment + * operation can't copy too many bytes + */ + emit_insn(gen_cmpsi (bytes_reg, GEN_INT(MAX_UNALIGNED_COPY))); + emit_jump_insn (gen_blt (aligned_label)); + } + + /* Emit insns to do alignment at run time */ + emit_insn(gen_negsi2 (count_reg, src_reg)); + emit_insn(gen_andsi3 (count_reg, count_reg, GEN_INT(3))); + emit_insn(gen_subsi3 (bytes_reg, bytes_reg, count_reg)); + emit_insn(gen_movstrsi1 (const1_rtx)); + if (!constp) + emit_label (aligned_label); + + /* insns to copy by words */ + emit_insn (gen_lshrsi3 (count_reg, bytes_reg, GEN_INT(2))); + emit_insn(gen_movstrsi1 (GEN_INT(4))); + + /* insns to copy rest */ + emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT(3))); + emit_insn(gen_movstrsi1 (const1_rtx)); } - return 0; } + /* Returns 1 if OP contains a global symbol reference */ @@ -466,10 +604,142 @@ global_symbolic_reference_mentioned_p (op, f) } +/* Returns 1 if OP contains a symbol reference */ + +int +symbolic_reference_mentioned_p (op) + rtx op; +{ + register char *fmt; + register int i; + + if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) + return 1; + + fmt = GET_RTX_FORMAT (GET_CODE (op)); + for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + + for (j = XVECLEN (op, i) - 1; j >= 0; j--) + if (symbolic_reference_mentioned_p (XVECEXP (op, i, j))) + return 1; + } + else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i))) + return 1; + } + + return 0; +} + +/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific + attribute for DECL. The attributes in ATTRIBUTES have previously been + assigned to DECL. */ + +int +ns32k_valid_decl_attribute_p (decl, attributes, identifier, args) + tree decl; + tree attributes; + tree identifier; + tree args; +{ + return 0; +} + +/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific + attribute for TYPE. The attributes in ATTRIBUTES have previously been + assigned to TYPE. */ + +int +ns32k_valid_type_attribute_p (type, attributes, identifier, args) + tree type; + tree attributes; + tree identifier; + tree args; +{ + if (TREE_CODE (type) != FUNCTION_TYPE + && TREE_CODE (type) != FIELD_DECL + && TREE_CODE (type) != TYPE_DECL) + return 0; + + /* Stdcall attribute says callee is responsible for popping arguments + if they are not variable. */ + if (is_attribute_p ("stdcall", identifier)) + return (args == NULL_TREE); + + /* Cdecl attribute says the callee is a normal C declaration */ + if (is_attribute_p ("cdecl", identifier)) + return (args == NULL_TREE); + + return 0; +} + +/* Return 0 if the attributes for two types are incompatible, 1 if they + are compatible, and 2 if they are nearly compatible (which causes a + warning to be generated). */ + +int +ns32k_comp_type_attributes (type1, type2) + tree type1; + tree type2; +{ + return 1; +} + + +/* 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. + + On the ns32k, the RET insn may be used to pop them if the number + of args is fixed, but if the number is variable then the caller + must pop them all. RET can't be used for library calls now + because the library is compiled with the Unix compiler. + Use of RET is a selectable option, since it is incompatible with + standard Unix calling sequences. If the option is not selected, + the caller must always pop the args. + + The attribute stdcall is equivalent to RET on a per module basis. */ + +int +ns32k_return_pops_args (fundecl, funtype, size) + tree fundecl; + tree funtype; + int size; +{ + int rtd = TARGET_RTD; + + if (TREE_CODE (funtype) == IDENTIFIER_NODE) + return rtd ? size : 0; + + /* Cdecl functions override -mrtd, and never pop the stack */ + if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) + return 0; + + /* Stdcall functions will pop the stack if not variable args */ + if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype))) + rtd = 1; + + if (rtd) + { + if (TYPE_ARG_TYPES (funtype) == NULL_TREE + || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node)) + return size; + } + + return 0; +} + /* PRINT_OPERAND is defined to call this function, which is easier to debug than putting all the code in a macro definition in ns32k.h. */ +/* XXX time 12% of cpu time is in fprintf for non optimizing */ void print_operand (file, x, code) FILE *file; @@ -481,7 +751,7 @@ print_operand (file, x, code) else if (code == '?') PUT_EXTERNAL_PREFIX (file); else if (GET_CODE (x) == REG) - fprintf (file, "%s", reg_names[REGNO (x)]); + fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]); else if (GET_CODE (x) == MEM) { rtx tmp = XEXP (x, 0); @@ -528,11 +798,30 @@ print_operand (file, x, code) } else { + if (flag_pic + && GET_CODE (x) == CONST + && symbolic_reference_mentioned_p (x)) + { + fprintf(stderr, "illegal constant for pic-mode: \n"); + print_rtl(stderr, x); + fprintf(stderr, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n", + GET_CODE (x), CONST, symbolic_reference_mentioned_p(x)); + abort (); + } + else if (flag_pic + && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)) + { + output_addr_const (file, x); + fprintf (file, "(sb)"); + } + else + { #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC - if (GET_CODE (x) == CONST_INT) + if (GET_CODE (x) == CONST_INT) #endif - PUT_IMMEDIATE_PREFIX (file); - output_addr_const (file, x); + PUT_IMMEDIATE_PREFIX (file); + output_addr_const (file, x); + } } } @@ -545,6 +834,7 @@ print_operand (file, x, code) figure out how it worked. 90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */ +void print_operand_address (file, addr) register FILE *file; register rtx addr; @@ -597,7 +887,7 @@ print_operand_address (file, addr) base = tmp; break; case REG: - if (REGNO (tmp) < 8) + if (REGNO (tmp) < F0_REGNUM) if (base) { indexexp = tmp; @@ -728,7 +1018,7 @@ print_operand_address (file, addr) (disp(sb)) (MEM ...) */ case REG: - fprintf (file, "(%s)", reg_names[REGNO (base)]); + fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]); break; case SYMBOL_REF: if (! flag_pic) @@ -785,7 +1075,7 @@ print_operand_address (file, addr) fprintf (file, "("); output_addr_const (file, offset); if (base) - fprintf (file, "(%s)", reg_names[REGNO (base)]); + fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]); else if (TARGET_SB) fprintf (file, "(sb)"); else @@ -816,16 +1106,16 @@ print_operand_address (file, addr) } else scale = 0; - if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8) + if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM) abort (); #ifdef UTEK_ASM fprintf (file, "[%c`%s]", scales[scale], - reg_names[REGNO (indexexp)]); + ns32k_out_reg_names[REGNO (indexexp)]); #else fprintf (file, "[%s:%c]", - reg_names[REGNO (indexexp)], + ns32k_out_reg_names[REGNO (indexexp)], scales[scale]); #endif } diff --git a/gcc/config/ns32k/ns32k.h b/gcc/config/ns32k/ns32k.h index d2e81d1..d409ac2 100644 --- a/gcc/config/ns32k/ns32k.h +++ b/gcc/config/ns32k/ns32k.h @@ -23,8 +23,6 @@ Boston, MA 02111-1307, USA. */ /* Note that some other tm.h files include this one and then override many of the definitions that relate to assembler syntax. */ -extern enum reg_class secondary_reload_class(); - /* Names to predefine in the preprocessor for this target machine. */ #define CPP_PREDEFINES "-Dns32000 -Dunix -Asystem(unix) -Acpu(ns32k) -Amachine(ns32k)" @@ -66,6 +64,18 @@ extern int target_flags; /* Compile 32081 insns for floating point (not library calls). */ #define TARGET_32081 (target_flags & 1) +#define TARGET_32381 (target_flags & 256) + +/* The use of multiply-add instructions is optional because it can + * cause an abort due to being unable to find a spill register. The + * main problem is that the multiply-add instructions require f0 and + * f0 is not available for spilling because it is "explicitly + * mentioned" in the rtl for function return values. This can be fixed + * by defining SMALL_REGISTER_CLASSES, but that causes worse code for + * the (more common) integer case. We really need better reload code. + */ + +#define TARGET_MULT_ADD (target_flags & 512) /* Compile using rtd insn calling sequence. This will not work unless you use prototypes at least @@ -93,9 +103,9 @@ extern int target_flags; 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 \ +#define TARGET_SWITCHES \ { { "32081", 1}, \ - { "soft-float", -1}, \ + { "soft-float", -257}, \ { "rtd", 2}, \ { "nortd", -2}, \ { "regparm", 4}, \ @@ -110,17 +120,66 @@ extern int target_flags; { "nobitfield", 64}, \ { "himem", 128}, \ { "nohimem", -128}, \ + { "32381", 256}, \ + { "mult-add", 512}, \ + { "nomult-add", -512}, \ { "", TARGET_DEFAULT}} + /* TARGET_DEFAULT is defined in encore.h, pc532.h, etc. */ /* When we are generating PIC, the sb is used as a pointer - to the GOT. */ + to the GOT. 32381 is a superset of 32081 */ -#define OVERRIDE_OPTIONS \ -{ \ +#define OVERRIDE_OPTIONS \ +{ \ if (flag_pic || TARGET_HIMEM) target_flags |= 32; \ + if (TARGET_32381) target_flags |= 1; \ + else target_flags &= ~512; \ } +/* Zero or more C statements that may conditionally modify two + variables `fixed_regs' and `call_used_regs' (both of type `char + []') after they have been initialized from the two preceding + macros. + + This is necessary in case the fixed or call-clobbered registers + depend on target flags. + + You need not define this macro if it has no work to do. + + If the usage of an entire class of registers depends on the target + flags, you may indicate this to GCC by using this macro to modify + `fixed_regs' and `call_used_regs' to 1 for each of the registers in + the classes which should not be used by GCC. Also define the macro + `REG_CLASS_FROM_LETTER' to return `NO_REGS' if it is called with a + letter for a class that shouldn't be used. + + (However, if this class is not included in `GENERAL_REGS' and all + of the insn patterns whose constraints permit this class are + controlled by target switches, then GCC will automatically avoid + using these registers when the target switches are opposed to + them.) */ + +#define CONDITIONAL_REGISTER_USAGE \ +do \ + { \ + if (!TARGET_32081) \ + { \ + int regno; \ + \ + for (regno = F0_REGNUM; regno <= F0_REGNUM + 8; regno++) \ + fixed_regs[regno] = call_used_regs[regno] = 1; \ + } \ + if (!TARGET_32381) \ + { \ + int regno; \ + \ + for (regno = L1_REGNUM; regno <= L1_REGNUM + 8; regno++) \ + fixed_regs[regno] = call_used_regs[regno] = 1; \ + } \ + } \ +while (0) + /* target machine storage layout */ @@ -190,13 +249,14 @@ extern int target_flags; from 0 to just below FIRST_PSEUDO_REGISTER. All registers that the compiler knows about must be given numbers, even those that are not normally considered general registers. */ -#define FIRST_PSEUDO_REGISTER 18 +#define FIRST_PSEUDO_REGISTER 26 /* 1 for registers that have pervasive standard uses and are not available for the register allocator. On the ns32k, these are the FP, SP, (SB and PC are not included here). */ #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, \ 1, 1} /* 1 for registers not available across function calls. @@ -207,13 +267,70 @@ extern int target_flags; Aside from that, you can include as many other registers as you like. */ #define CALL_USED_REGISTERS {1, 1, 1, 0, 0, 0, 0, 0, \ 1, 1, 1, 1, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 0, \ 1, 1} +/* 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", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "l1", "l1h","l3", "l3h","l5", "l5h","l7", "l7h", \ + "fp", "sp"} + + +#define ADDITIONAL_REGISTER_NAMES \ +{{"l0", 8}, {"l2", 10}, {"l4", 12}, {"l6", 14}} + +/* l0-7 are not recognized by the assembler. These are the names to use, + * but we don't want ambiguous names in REGISTER_NAMES + */ +#define OUTPUT_REGISTER_NAMES \ +{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "f1", "l1h","f3", "l3h","f5", "l5h","f7", "f7h", \ + "fp", "sp"} + +#define REG_ALLOC_ORDER \ +{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 10, 11, 18, 12, 13, 20, 14, 15, 22, 24, 25, 17, 19, 23} + +/* How to renumber registers for dbx and gdb. + NS32000 may need more change in the numeration. XXX */ + +#define DBX_REGISTER_NUMBER(REGNO) \ + ((REGNO) < L1_REGNUM? (REGNO) \ + : (REGNO) < FRAME_POINTER_REGNUM? (REGNO) - L1_REGNUM + 22 \ + : (REGNO) == FRAME_POINTER_REGNUM? 17 \ + : 16) + + + + +#define R0_REGNUM 0 +#define F0_REGNUM 8 +#define L1_REGNUM 16 + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* NS32000 pc is not overloaded on a register. */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 25 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 24 + + /* 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. - On the ns32k, all registers are 32 bits long. */ + On the ns32k, all registers are 32 bits long except for the 32381 "long" + registers but we treat those as pairs */ +#define LONG_FP_REGS_P(REGNO) ((REGNO) >= L1_REGNUM && (REGNO) < L1_REGNUM + 8) #define HARD_REGNO_NREGS(REGNO, MODE) \ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) @@ -223,22 +340,19 @@ extern int target_flags; /* Value is 1 if it is a good idea to tie two pseudo registers when one has mode MODE1 and one has mode MODE2. If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, - for any hard reg, then this must be 0 for correct output. */ -#define MODES_TIEABLE_P(MODE1, MODE2) \ - (((MODE1) == DFmode || (MODE1) == DCmode || (MODE1) == DImode) == \ - ((MODE2) == DFmode || (MODE2) == DCmode || (MODE2) == DImode)) + for any hard reg, then this must be 0 for correct output. -/* Specify the registers used for certain standard purposes. - The values of these macros are register numbers. */ - -/* NS32000 pc is not overloaded on a register. */ -/* #define PC_REGNUM */ + Early documentation says SI and DI are not tieable if some reg can + be OK for SI but not for DI. However other ports (mips, i860, mvs + and tahoe) don't meet the above criterion. Evidently the real + requirement is somewhat laxer. Documentation was changed for gcc + 2.8 but was not picked up by egcs (at least egcs 1.0). Having all + integer modes tieable definitely generates faster code. */ -/* Register to use for pushing function arguments. */ -#define STACK_POINTER_REGNUM 17 - -/* Base register for access to local variables of the function. */ -#define FRAME_POINTER_REGNUM 16 +#define MODES_TIEABLE_P(MODE1, MODE2) \ + ((FLOAT_MODE_P(MODE1) && FLOAT_MODE_P(MODE2) \ + && (GET_MODE_UNIT_SIZE(MODE1) == GET_MODE_UNIT_SIZE(MODE2))) \ + || (!FLOAT_MODE_P(MODE1) && !FLOAT_MODE_P(MODE2))) /* Value should be nonzero if functions must have frame pointers. Zero means the frame pointer need not be set up (and parms @@ -247,7 +361,7 @@ extern int target_flags; #define FRAME_POINTER_REQUIRED 0 /* Base register for access to arguments of the function. */ -#define ARG_POINTER_REGNUM 16 +#define ARG_POINTER_REGNUM 24 /* Register in which static-chain is passed to a function. */ #define STATIC_CHAIN_REGNUM 1 @@ -275,37 +389,39 @@ extern int target_flags; For any two classes, it is very desirable that there be another class that represents their union. */ - -enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS, - FRAME_POINTER_REG, STACK_POINTER_REG, - GEN_AND_MEM_REGS, ALL_REGS, LIM_REG_CLASSES }; + +enum reg_class +{ NO_REGS, GENERAL_REGS, FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS, + FP_REGS, GEN_AND_FP_REGS, FRAME_POINTER_REG, STACK_POINTER_REG, + GEN_AND_MEM_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", "GENERAL_REGS", "FLOAT_REGS", "GEN_AND_FP_REGS", \ - "FRAME_POINTER_REG", "STACK_POINTER_REG", "GEN_AND_MEM_REGS", "ALL_REGS" } + {"NO_REGS", "GENERAL_REGS", "FLOAT_REG0", "LONG_FLOAT_REG0", "FLOAT_REGS", \ + "FP_REGS", "GEN_AND_FP_REGS", "FRAME_POINTER_REG", "STACK_POINTER_REG", \ + "GEN_AND_MEM_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, 0x00ff, 0xff00, 0xffff, \ - 0x10000, 0x20000, 0x300ff, 0x3ffff } +#define REG_CLASS_CONTENTS {0, 0x00ff, 0x100, 0x300, 0xff00, \ + 0xffff00, 0xffffff, 0x1000000, 0x2000000, \ + 0x30000ff, 0x3ffffff } + +#define SUBSET_P(CLASS1, CLASS2) \ + ((ns32k_reg_class_contents[CLASS1] & ~ns32k_reg_class_contents[CLASS2]) \ + == 0) /* The same information, inverted: Return the class number of the smallest class containing reg number REGNO. This could be a conditional expression or could index an array. */ -#define REGNO_REG_CLASS(REGNO) \ - ((REGNO) < 8 ? GENERAL_REGS \ - : (REGNO) < 16 ? FLOAT_REGS \ - : (REGNO) == 16 ? FRAME_POINTER_REG \ - : (REGNO) == 17 ? STACK_POINTER_REG \ - : NO_REGS) +#define REGNO_REG_CLASS(REGNO) (regclass_map[REGNO]) /* The class value for index registers, and the one for base regs. */ @@ -314,10 +430,13 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS, /* Get reg_class from a letter such as appears in the machine description. */ -#define REG_CLASS_FROM_LETTER(C) \ - ((C) == 'f' ? FLOAT_REGS \ - : (C) == 'x' ? FRAME_POINTER_REG \ - : (C) == 'y' ? STACK_POINTER_REG \ +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'u' ? FLOAT_REG0 \ + : (C) == 'v' ? LONG_FLOAT_REG0 \ + : (C) == 'f' ? FLOAT_REGS \ + : (C) == 'l' ? FP_REGS \ + : (C) == 'x' ? FRAME_POINTER_REG \ + : (C) == 'y' ? STACK_POINTER_REG \ : NO_REGS) /* The letters I, J, K, L and M in a register constraint string @@ -353,13 +472,15 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS, /* We return GENERAL_REGS instead of GEN_AND_MEM_REGS. The latter offers no real additional possibilities - and can cause spurious secondary reloading. */ + and can cause spurious secondary reloading. */ + #define PREFERRED_RELOAD_CLASS(X,CLASS) \ ((CLASS) == GEN_AND_MEM_REGS ? GENERAL_REGS : (CLASS)) /* Return the maximum number of consecutive registers needed to represent mode MODE in a register of class CLASS. */ /* On the 32000, this is the size of MODE in words */ + #define CLASS_MAX_NREGS(CLASS, MODE) \ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) @@ -381,6 +502,46 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS, of the first local allocated. */ #define STARTING_FRAME_OFFSET 0 +/* A C expression whose value is RTL representing the location of the + incoming return address at the beginning of any function, before + the prologue. This RTL is either a `REG', indicating that the + return value is saved in `REG', or a `MEM' representing a location + in the stack. + + You only need to define this macro if you want to support call + frame debugging information like that provided by DWARF 2. + + Before the prologue, RA is at 0(sp). */ + +#define INCOMING_RETURN_ADDR_RTX \ + gen_rtx (MEM, VOIDmode, gen_rtx (REG, VOIDmode, STACK_POINTER_REGNUM)) + +/* A C expression whose value is RTL representing the value of the + return address for the frame COUNT steps up from the current frame, + after the prologue. 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. + + After the prologue, RA is at 4(fp) in the current frame. */ + +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + (gen_rtx (MEM, Pmode, gen_rtx (PLUS, Pmode, (FRAME), GEN_INT(4)))) + +/* A C expression whose value is an integer giving the offset, in + bytes, from the value of the stack pointer register to the top of + the stack frame at the beginning of any function, before the + prologue. The top of the frame is defined to be the value of the + stack pointer in the previous frame, just before the call + instruction. + + You only need to define this macro if you want to support call + frame debugging information like that provided by DWARF 2. */ + +#define INCOMING_FRAME_SP_OFFSET 4 + +/* Offset of the CFA from the argument pointer register value. */ +#define ARG_POINTER_CFA_OFFSET 8 + /* If we generate an insn to push BYTES bytes, this says how many the stack pointer really advances by. On the 32000, sp@- in a byte insn really pushes a BYTE. */ @@ -402,14 +563,12 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS, because the library is compiled with the Unix compiler. Use of RET is a selectable option, since it is incompatible with standard Unix calling sequences. If the option is not selected, - the caller must always pop the args. */ + the caller must always pop the args. + + The attribute stdcall is equivalent to RTD on a per module basis. */ -#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ - ((TARGET_RTD && (!(FUNDECL) || TREE_CODE (FUNDECL) != IDENTIFIER_NODE) \ - && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ - || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \ - == void_type_node))) \ - ? (SIZE) : 0) +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ + (ns32k_return_pops_args (FUNDECL, FUNTYPE, SIZE)) /* Define how to find the value returned by a function. VALTYPE is the data type of the value (as a tree). @@ -417,23 +576,19 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS, otherwise, FUNC is 0. */ /* On the 32000 the return value is in R0, - or perhaps in F0 is there is fp support. */ + or perhaps in F0 if there is fp support. */ -#define FUNCTION_VALUE(VALTYPE, FUNC) \ - (TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_32081 \ - ? gen_rtx (REG, TYPE_MODE (VALTYPE), 8) \ - : gen_rtx (REG, TYPE_MODE (VALTYPE), 0)) +#define FUNCTION_VALUE(VALTYPE, FUNC) LIBCALL_VALUE(TYPE_MODE (VALTYPE)) /* Define how to find the value returned by a library function assuming the value has mode MODE. */ /* On the 32000 the return value is in R0, - or perhaps F0 is there is fp support. */ + or perhaps F0 is there is fp support. */ #define LIBCALL_VALUE(MODE) \ - (((MODE) == DFmode || (MODE) == SFmode) && TARGET_32081 \ - ? gen_rtx (REG, MODE, 8) \ - : gen_rtx (REG, MODE, 0)) + gen_rtx (REG, MODE, \ + FLOAT_MODE_P(MODE) && TARGET_32081 ? F0_REGNUM: R0_REGNUM) /* Define this if PCC uses the nonreentrant convention for returning structure and union values. */ @@ -554,18 +709,18 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS, #define FUNCTION_PROLOGUE(FILE, SIZE) \ { register int regno, g_regs_used = 0; \ int used_regs_buf[8], *bufp = used_regs_buf; \ - int used_fregs_buf[8], *fbufp = used_fregs_buf; \ + int used_fregs_buf[17], *fbufp = used_fregs_buf; \ extern char call_used_regs[]; \ extern int current_function_uses_pic_offset_table, flag_pic; \ MAIN_FUNCTION_PROLOGUE; \ - for (regno = 0; regno < 8; regno++) \ + for (regno = R0_REGNUM; regno < F0_REGNUM; regno++) \ if (regs_ever_live[regno] \ && ! call_used_regs[regno]) \ { \ *bufp++ = regno; g_regs_used++; \ } \ *bufp = -1; \ - for (; regno < 16; regno++) \ + for (; regno < FRAME_POINTER_REGNUM; regno++) \ if (regs_ever_live[regno] && !call_used_regs[regno]) \ { \ *fbufp++ = regno; \ @@ -600,11 +755,12 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS, fbufp = used_fregs_buf; \ while (*fbufp >= 0) \ { \ - if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1)) \ - fprintf (FILE, "\tmovf f%d,tos\n", *fbufp++ - 8); \ + if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1)) \ + fprintf (FILE, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]); \ else \ { \ - fprintf (FILE, "\tmovl f%d,tos\n", fbufp[0] - 8); \ + fprintf (FILE, "\tmovl %s,tos\n", \ + ns32k_out_reg_names[fbufp[0]]); \ fbufp += 2; \ } \ } \ @@ -678,19 +834,19 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS, #define FUNCTION_EPILOGUE(FILE, SIZE) \ { register int regno, g_regs_used = 0, f_regs_used = 0; \ int used_regs_buf[8], *bufp = used_regs_buf; \ - int used_fregs_buf[8], *fbufp = used_fregs_buf; \ + int used_fregs_buf[17], *fbufp = used_fregs_buf; \ extern char call_used_regs[]; \ extern int current_function_uses_pic_offset_table, flag_pic; \ if (flag_pic && current_function_uses_pic_offset_table) \ fprintf (FILE, "\tlprd sb,tos\n"); \ *fbufp++ = -2; \ - for (regno = 8; regno < 16; regno++) \ + for (regno = F0_REGNUM; regno < FRAME_POINTER_REGNUM; regno++) \ if (regs_ever_live[regno] && !call_used_regs[regno]) \ { \ *fbufp++ = regno; f_regs_used++; \ } \ fbufp--; \ - for (regno = 0; regno < 8; regno++) \ + for (regno = 0; regno < F0_REGNUM; regno++) \ if (regs_ever_live[regno] \ && ! call_used_regs[regno]) \ { \ @@ -698,12 +854,13 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS, } \ while (fbufp > used_fregs_buf) \ { \ - if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1) \ + if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1) \ { \ - fprintf (FILE, "\tmovl tos,f%d\n", fbufp[-1] - 8); \ + fprintf (FILE, "\tmovl tos,%s\n", \ + ns32k_out_reg_names[fbufp[-1]]); \ fbufp -= 2; \ } \ - else fprintf (FILE, "\tmovf tos,f%d\n", *fbufp-- - 8); \ + else fprintf (FILE, "\tmovf tos,%s\n", ns32k_out_reg_names[*fbufp--]); \ } \ if (frame_pointer_needed) \ fprintf (FILE, "\texit ["); \ @@ -742,9 +899,12 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS, int regno; \ int offset = -4; \ extern int current_function_uses_pic_offset_table, flag_pic; \ - for (regno = 0; regno < 16; regno++) \ + for (regno = 0; regno < L1_REGNUM; regno++) \ if (regs_ever_live[regno] && ! call_used_regs[regno]) \ offset += 4; \ + for (; regno < FRAME_POINTER_REGNUM; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 8; \ if (flag_pic && current_function_uses_pic_offset_table) \ offset += 4; \ (DEPTH) = (offset + get_frame_size () \ @@ -824,12 +984,13 @@ __transfer_from_trampoline () \ /* note that FP and SP cannot be used as an index. What about PC? */ #define REGNO_OK_FOR_INDEX_P(REGNO) \ -((REGNO) < 8 || (unsigned)reg_renumber[REGNO] < 8) +((REGNO) < F0_REGNUM || (unsigned)reg_renumber[REGNO] < F0_REGNUM) #define REGNO_OK_FOR_BASE_P(REGNO) \ -((REGNO) < 8 || (unsigned)reg_renumber[REGNO] < 8 \ +((REGNO) < F0_REGNUM || (unsigned)reg_renumber[REGNO] < F0_REGNUM \ || (REGNO) == FRAME_POINTER_REGNUM || (REGNO) == STACK_POINTER_REGNUM) -#define FP_REG_P(X) (GET_CODE (X) == REG && REGNO (X) > 7 && REGNO (X) < 16) +#define FP_REG_P(X) \ + (GET_CODE (X) == REG && REGNO (X) >= F0_REGNUM && REGNO (X) < FRAME_POINTER_REGNUM) /* Maximum number of registers that can appear in a valid memory address. */ @@ -838,19 +999,18 @@ __transfer_from_trampoline () \ /* Recognize any constant value that is a valid address. This might not work on future ns32k processors as negative displacements are not officially allowed but a mode reserved - to National. This works on processors up to 32532, though. */ + to National. This works on processors up to 32532, though, + and we don't expect any new ones in the series ;-( */ #define CONSTANT_ADDRESS_P(X) \ (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \ || GET_CODE (X) == CONST \ || (GET_CODE (X) == CONST_INT \ - && ((unsigned)INTVAL (X) >= 0xe0000000 \ - || (unsigned)INTVAL (X) < 0x20000000))) + && NS32K_DISPLACEMENT_P (INTVAL (X)))) #define CONSTANT_ADDRESS_NO_LABEL_P(X) \ (GET_CODE (X) == CONST_INT \ - && ((unsigned)INTVAL (X) >= 0xe0000000 \ - || (unsigned)INTVAL (X) < 0x20000000)) + && NS32K_DISPLACEMENT_P (INTVAL (X))) /* Return the register class of a scratch register needed to copy IN into or out of a register in CLASS in MODE. If it can be done directly, @@ -859,6 +1019,42 @@ __transfer_from_trampoline () \ #define SECONDARY_RELOAD_CLASS(CLASS,MODE,IN) \ secondary_reload_class (CLASS, MODE, IN) +/* Certain machines have the property that some registers cannot be + copied to some other registers without using memory. Define this + macro on those machines to be a C expression that is non-zero if + objects of mode M in registers of CLASS1 can only be copied to + registers of class CLASS2 by storing a register of CLASS1 into + memory and loading that memory location into a register of CLASS2. + + On the ns32k, floating point regs can only be loaded through memory + + The movdf and movsf insns in ns32k.md copy between general and + floating registers using the stack. In principle, we could get + better code not allowing that case in the constraints and defining + SECONDARY_MEMORY_NEEDED in practice, though the stack slots used + are not available for optimization. */ + +#if 0 +#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, M) \ + secondary_memory_needed(CLASS1, CLASS2, M) +#endif + +/* SMALL_REGISTER_CLASSES is true only if we have said we are using the + * multiply-add instructions. + */ +#define SMALL_REGISTER_CLASSES (target_flags & 512) + +/* A C expression whose value is nonzero if pseudos that have been + assigned to registers of class CLASS would likely be spilled + because registers of CLASS are needed for spill registers. + + The default definition won't do because class LONG_FLOAT_REG0 has two + registers which are always acessed as a pair */ + +#define CLASS_LIKELY_SPILLED_P(CLASS) \ + (reg_class_size[(int) (CLASS)] == 1 || (CLASS) == LONG_FLOAT_REG0) + + /* Nonzero if the constant value X is a legitimate general operand. It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ @@ -882,10 +1078,10 @@ __transfer_from_trampoline () \ /* 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) \ - (REGNO (X) < 8 || REGNO (X) >= FIRST_PSEUDO_REGISTER) + (REGNO (X) < F0_REGNUM || REGNO (X) >= FIRST_PSEUDO_REGISTER) /* Nonzero if X is a hard reg that can be used as a base reg of if it is a pseudo reg. */ -#define REG_OK_FOR_BASE_P(X) (REGNO (X) < 8 || REGNO (X) >= FRAME_POINTER_REGNUM) +#define REG_OK_FOR_BASE_P(X) (REGNO (X) < F0_REGNUM || REGNO (X) >= FRAME_POINTER_REGNUM) /* Nonzero if X is a floating point reg or a pseudo reg. */ #else @@ -936,7 +1132,8 @@ __transfer_from_trampoline () \ /* Check for frame pointer or stack pointer. */ #define MEM_REG(X) \ - (GET_CODE (X) == REG && (REGNO (X) ^ 16) < 2) + (GET_CODE (X) == REG && (REGNO (X) == FRAME_POINTER_REGNUM \ + || REGNO(X) == STACK_POINTER_REGNUM)) /* A memory ref whose address is the FP or SP, with optional integer offset, or (on certain machines) a constant address. */ @@ -1040,15 +1237,21 @@ __transfer_from_trampoline () \ #define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {} /* Nonzero if the constant value X is a legitimate general operand - when generating PIC code. It is given that flag_pic is on and + when generating PIC code. It is given that flag_pic is on and that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ extern int current_function_uses_pic_offset_table, flag_pic; #define LEGITIMATE_PIC_OPERAND_P(X) \ (((! current_function_uses_pic_offset_table \ - && global_symbolic_reference_mentioned_p (X, 1))? \ + && symbolic_reference_mentioned_p (X))? \ (current_function_uses_pic_offset_table = 1):0 \ - ), 1) + ), (! SYMBOLIC_CONST (X) \ + || GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == LABEL_REF)) + +#define SYMBOLIC_CONST(X) \ +(GET_CODE (X) == SYMBOL_REF \ + || GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X))) /* Define this macro if references to a symbol must be treated differently depending on something about the variable or @@ -1082,6 +1285,33 @@ while (0) { if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) \ goto LABEL;} +/* If defined, a C expression whose value is nonzero if IDENTIFIER + with arguments ARGS is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ + +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, NAME, ARGS) \ + (ns32k_valid_decl_attribute_p (DECL, ATTRIBUTES, NAME, ARGS)) + +/* If defined, a C expression whose value is nonzero if IDENTIFIER + with arguments ARGS is a valid machine specific attribute for TYPE. + The attributes in ATTRIBUTES have previously been assigned to TYPE. */ + +#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, NAME, ARGS) \ + (ns32k_valid_type_attribute_p (TYPE, ATTRIBUTES, NAME, ARGS)) + +/* If defined, a C expression whose value is 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). */ + +#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \ + (ns32k_comp_type_attributes (TYPE1, TYPE2)) + +/* If defined, a C statement that assigns default attributes to newly + defined TYPE. */ + +/* #define SET_DEFAULT_TYPE_ATTRIBUTES (TYPE) */ + /* Specify the machine mode that this machine uses for the index in the tablejump instruction. HI mode is more efficient but the range is not wide enough for @@ -1107,6 +1337,12 @@ while (0) in one reasonably fast instruction. */ #define MOVE_MAX 4 +/* The number of scalar move insns which should be generated instead + of a string move insn or a library call. + + We have a smart movstrsi insn */ +#define MOVE_RATIO 0 + /* Define this if zero-extension is slow (more than one real instruction). */ /* #define SLOW_ZERO_EXTEND */ @@ -1226,16 +1462,13 @@ while (0) /* Describe the costs of the following register moves which are discouraged: 1.) Moves between the Floating point registers and the frame pointer and stack pointer 2.) Moves between the stack pointer and the frame pointer - 3.) Moves between the floating point and general registers */ + 3.) Moves between the floating point and general registers + + These all involve two memory references. This is worse than a memory + to memory move (default cost 4) + */ -#define REGISTER_MOVE_COST(CLASS1, CLASS2) \ - ((((CLASS1) == FLOAT_REGS && ((CLASS2) == STACK_POINTER_REG || (CLASS2) == FRAME_POINTER_REG)) \ - || ((CLASS2) == FLOAT_REGS && ((CLASS1) == STACK_POINTER_REG || (CLASS1) == FRAME_POINTER_REG)) \ - || ((CLASS1) == STACK_POINTER_REG && (CLASS2) == FRAME_POINTER_REG) \ - || ((CLASS2) == STACK_POINTER_REG && (CLASS1) == FRAME_POINTER_REG) \ - || ((CLASS1) == FLOAT_REGS && (CLASS2) == GENERAL_REGS) \ - || ((CLASS1) == GENERAL_REGS && (CLASS2) == FLOAT_REGS)) \ - ? 4 : 2) +#define REGISTER_MOVE_COST(CLASS1, CLASS2) register_move_cost(CLASS1, CLASS2) #define OUTPUT_JUMP(NORMAL, NO_OV) \ { if (cc_status.flags & CC_NO_OVERFLOW) \ @@ -1307,12 +1540,8 @@ while (0) /* This is how to output an assembler line defining an external/static address which is not in tree format (for collect.c). */ -#define ASM_OUTPUT_LABELREF_AS_INT(STREAM, NAME) \ -do { \ - fprintf (STREAM, "\t.long\t"); \ - ASM_OUTPUT_LABELREF (STREAM, NAME); \ - fprintf (STREAM, "\n"); \ -} while (0) +/* The prefix to add to user-visible assembler symbols. */ +#define USER_LABEL_PREFIX "_" /* This is how to output an insn to push a register on the stack. It need not be very fast code. */ @@ -1326,19 +1555,6 @@ do { \ #define ASM_OUTPUT_REG_POP(FILE,REGNO) \ fprintf (FILE, "\tmovd tos,%s\n", reg_names[REGNO]) -/* 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", \ - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ - "fp", "sp"} - -/* How to renumber registers for dbx and gdb. - NS32000 may need more change in the numeration. */ - -#define DBX_REGISTER_NUMBER(REGNO) ((REGNO < 8) ? (REGNO)+4 : (REGNO)) - /* 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. */ @@ -1365,9 +1581,11 @@ do { \ } while (0) #endif -/* The prefix to add to user-visible assembler symbols. */ +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ -#define USER_LABEL_PREFIX "_" +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) /* This is how to output an internal numbered label where PREFIX is the class of label and NUM is the number within the class. */ @@ -1463,11 +1681,39 @@ do { \ #define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address(FILE, ADDR) -/* Define functions in ns32k.c and used in insn-output.c. */ - -extern char *output_move_double (); -extern char *output_shift_insn (); -extern char *output_move_dconst (); +/* Prototypes for functions in ns32k.c */ + +/* Prototypes would be nice, but for now it causes too many problems. + This file gets included in places where the types (such as "rtx" + and enum machine_mode) are not defined. */ +#define NS32K_PROTO(ARGS) () + +int hard_regno_mode_ok NS32K_PROTO((int regno, enum machine_mode mode)); +int register_move_cost NS32K_PROTO((enum reg_class CLASS1, enum reg_class CLASS2)); +int calc_address_cost NS32K_PROTO((rtx operand)); +enum reg_class secondary_reload_class NS32K_PROTO((enum reg_class class, + enum machine_mode mode, rtx in)); +int reg_or_mem_operand NS32K_PROTO((register rtx op, enum machine_mode mode)); + +void split_di NS32K_PROTO((rtx operands[], int num, rtx lo_half[], hi_half[])); + +void expand_block_move NS32K_PROTO((rtx operands[])); +int global_symbolic_reference_mentioned_p NS32K_PROTO((rtx op, int f)); +int ns32k_comp_type_attributes NS32K_PROTO((tree type1, tree type2)); +int ns32k_return_pops_args NS32K_PROTO((tree fundecl, tree funtype, int size)); +int ns32k_valid_decl_attribute_p NS32K_PROTO((tree decl, tree attributes, + tree identifier, tree args)); +int ns32k_valid_type_attribute_p NS32K_PROTO((tree decl, tree attributes, + tree identifier, tree args)); +void print_operand NS32K_PROTO((FILE *file, rtx x, char code)); +void print_operand_address NS32K_PROTO((register FILE *file, register rtx addr)); +char *output_move_dconst NS32K_PROTO((int n, char *s)); +char *output_move_double NS32K_PROTO((rtx *operands)); +char *output_shift_insn NS32K_PROTO((rtx *operands)); + +extern unsigned int ns32k_reg_class_contents[N_REG_CLASSES]; +extern char *ns32k_out_reg_names[]; +extern enum reg_class regclass_map[]; /* smalled class containing REGNO */ /* Local variables: diff --git a/gcc/config/ns32k/ns32k.md b/gcc/config/ns32k/ns32k.md index e44cccc..161b74e 100644 --- a/gcc/config/ns32k/ns32k.md +++ b/gcc/config/ns32k/ns32k.md @@ -39,7 +39,20 @@ ;; We don't want to allow a constant operand for test insns because ;; (set (cc0) (const_int foo)) has no mode information. Such insns will ;; be folded while optimizing anyway. - +;; +;; In order for pic mode to work we cannot generate, for example +;; +;; addd _x+5,r1 +;; +;; instead we must force gcc to generate something like +;; +;; addr 5(_x(sb)),r0 +;; addd r0,r1 +;; +;; This was done through operand constraints (using "rmn" in place of "g"), +;; but with the proper definition of LEGITIMATE_PIC_OPERAND (ns32k.h) +;; this is unnecessary. +;; (define_insn "tstsi" [(set (cc0) (match_operand:SI 0 "nonimmediate_operand" "rm"))] @@ -69,7 +82,7 @@ (define_insn "tstdf" [(set (cc0) - (match_operand:DF 0 "general_operand" "fmF"))] + (match_operand:DF 0 "general_operand" "lmF"))] "TARGET_32081" "* { cc_status.flags |= CC_REVERSED; @@ -85,10 +98,11 @@ operands[1] = CONST0_RTX (SFmode); return \"cmpf %1,%0\"; }") +;; See note 1 (define_insn "cmpsi" [(set (cc0) - (compare (match_operand:SI 0 "nonimmediate_operand" "rmn") - (match_operand:SI 1 "general_operand" "rmn")))] + (compare (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] "" "* { @@ -113,7 +127,7 @@ (define_insn "cmphi" [(set (cc0) - (compare (match_operand:HI 0 "nonimmediate_operand" "g") + (compare (match_operand:HI 0 "general_operand" "g") (match_operand:HI 1 "general_operand" "g")))] "" "* @@ -145,7 +159,7 @@ (define_insn "cmpqi" [(set (cc0) - (compare (match_operand:QI 0 "nonimmediate_operand" "g") + (compare (match_operand:QI 0 "general_operand" "g") (match_operand:QI 1 "general_operand" "g")))] "" "* @@ -177,8 +191,8 @@ (define_insn "cmpdf" [(set (cc0) - (compare (match_operand:DF 0 "general_operand" "fmF") - (match_operand:DF 1 "general_operand" "fmF")))] + (compare (match_operand:DF 0 "general_operand" "lmF") + (match_operand:DF 1 "general_operand" "lmF")))] "TARGET_32081" "cmpl %0,%1") @@ -189,9 +203,14 @@ "TARGET_32081" "cmpf %0,%1") +;; movdf and movsf copy between general and floating registers using +;; the stack. In principle, we could get better code not allowing +;; that case in the constraints and defining SECONDARY_MEMORY_NEEDED +;; in practice, though the stack slots used are not available for +;; optimization. (define_insn "movdf" - [(set (match_operand:DF 0 "general_operand" "=fg<") - (match_operand:DF 1 "general_operand" "fFg"))] + [(set (match_operand:DF 0 "general_operand" "=lg<") + (match_operand:DF 1 "general_operand" "lFg"))] "" "* { @@ -231,7 +250,7 @@ { if (FP_REG_P (operands[0])) { - if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8) + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < F0_REGNUM) return \"movd %1,tos\;movf tos,%0\"; else return \"movf %1,%0\"; @@ -308,8 +327,8 @@ ;; This special case must precede movsi. (define_insn "" - [(set (reg:SI 17) - (match_operand:SI 0 "general_operand" "rmn"))] + [(set (reg:SI 25) + (match_operand:SI 0 "general_operand" "g"))] "" "lprd sp,%0") @@ -323,7 +342,7 @@ if (FP_REG_P (operands[0])) { - if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8) + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < F0_REGNUM) return \"movd %1,tos\;movf tos,%0\"; else return \"movf %1,%0\"; @@ -347,16 +366,16 @@ { if (i <= 7 && i >= -8) return \"movqd %1,%0\"; - if (i <= 0x1fffffff && i >= -0x20000000) + if (NS32K_DISPLACEMENT_P (i)) #if defined (GNX_V3) || defined (UTEK_ASM) return \"addr %c1,%0\"; #else return \"addr @%c1,%0\"; #endif - return \"movd %$%1,%0\"; + return \"movd %1,%0\"; } else - return output_move_dconst(i, \"%$%1,%0\"); + return output_move_dconst(i, \"%1,%0\"); } else if (GET_CODE (operands[1]) == CONST && ! flag_pic) { @@ -364,11 +383,11 @@ * that case addr might lead to overflow. For PIC symbolic * address loads always have to be done with addr. */ - return \"movd %$%1,%0\"; + return \"movd %1,%0\"; } else if (GET_CODE (operands[1]) == REG) { - if (REGNO (operands[1]) < 16) + if (REGNO (operands[1]) < F0_REGNUM) return \"movd %1,%0\"; else if (REGNO (operands[1]) == FRAME_POINTER_REGNUM) { @@ -426,7 +445,7 @@ } else if (FP_REG_P (operands[0])) { - if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8) + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < F0_REGNUM) return \"movwf %1,tos\;movf tos,%0\"; else return \"movwf %1,%0\"; @@ -472,7 +491,7 @@ } else if (FP_REG_P (operands[0])) { - if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8) + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < F0_REGNUM) return \"movbf %1,tos\;movf tos,%0\"; else return \"movbf %1,%0\"; @@ -499,75 +518,63 @@ return \"movb %1,%0\"; }") -;; This is here to accept 4 arguments and pass the first 3 along -;; to the movstrsi1 pattern that really does the work. +;; Block moves +;; Argument 0 is the destination +;; Argument 1 is the source +;; Argument 2 is the length +;; Argument 3 is the alignment +;; +;; Strategy: Use define_expand to +;; either emit insns directly if it can be done simply or +;; emit rtl to match movstrsi1 which has extra scratch registers +;; which can be used to generate more complex code. + (define_expand "movstrsi" - [(set (match_operand:BLK 0 "general_operand" "=g") - (match_operand:BLK 1 "general_operand" "g")) - (use (match_operand:SI 2 "general_operand" "rmn")) - (match_operand 3 "" "")] + [(parallel [(set (match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "")) + (use (match_operand:SI 2 "general_operand" "")) + (use (match_operand:SI 3 "const_int_operand" ""))])] "" " - emit_insn (gen_movstrsi1 (operands[0], operands[1], operands[2])); - DONE; -") +{ + if (operands[0]) /* avoid unused code messages */ + { + expand_block_move (operands); + DONE; + } +}") + +;; Special Registers: +;; r0 count +;; r1 from +;; r2 to +;; r3 match + -;; The definition of this insn does not really explain what it does, -;; but it should suffice -;; that anything generated as this insn will be recognized as one -;; and that it won't successfully combine with anything. (define_insn "movstrsi1" - [(set (match_operand:BLK 0 "general_operand" "=g") - (match_operand:BLK 1 "general_operand" "g")) - (use (match_operand:SI 2 "general_operand" "rmn")) - (clobber (reg:SI 0)) - (clobber (reg:SI 1)) - (clobber (reg:SI 2))] + [(set (mem:BLK (reg:SI 2)) + (mem:BLK (reg:SI 1))) + (use (reg:SI 0)) + (set (reg:SI 2) (plus:SI (reg:SI 2) (mult:SI (reg:SI 0) (match_operand:SI 0 "const_int_operand" "")))) + (set (reg:SI 1) (plus:SI (reg:SI 1) (mult:SI (reg:SI 0) (match_dup 0)))) + (set (reg:SI 0) (const_int 0))] "" "* -{ - if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) - abort (); - operands[0] = XEXP (operands[0], 0); - operands[1] = XEXP (operands[1], 0); - if (GET_CODE (operands[0]) == MEM) - if (GET_CODE (operands[1]) == MEM) - output_asm_insn (\"movd %0,r2\;movd %1,r1\", operands); - else - output_asm_insn (\"movd %0,r2\;addr %a1,r1\", operands); - else if (GET_CODE (operands[1]) == MEM) - output_asm_insn (\"addr %a0,r2\;movd %1,r1\", operands); - else - output_asm_insn (\"addr %a0,r2\;addr %a1,r1\", operands); + { + int align = INTVAL(operands[0]); + if (align == 4) + return \"movsd\"; + else + return \"movsb\"; + }") + +(define_insn "movstrsi2" + [(set (mem:BLK (match_operand:SI 0 "address_operand" "g")) + (mem:BLK (match_operand:SI 1 "address_operand" "g"))) + (use (match_operand 2 "immediate_operand" "i"))] + "" + "movmd %a1,%a0,%2") -#ifdef UTEK_ASM - if (GET_CODE (operands[2]) == CONST_INT && (INTVAL (operands[2]) & 0x3) == 0) - { - operands[2] = GEN_INT (INTVAL (operands[2]) >> 2); - if ((unsigned) INTVAL (operands[2]) <= 7) - return \"movqd %2,r0\;movsd $0\"; - else - return \"movd %2,r0\;movsd $0\"; - } - else - { - return \"movd %2,r0\;movsb $0\"; - } -#else - if (GET_CODE (operands[2]) == CONST_INT && (INTVAL (operands[2]) & 0x3) == 0) - { - operands[2] = GEN_INT (INTVAL (operands[2]) >> 2); - if ((unsigned) INTVAL (operands[2]) <= 7) - return \"movqd %2,r0\;movsd\"; - else - return \"movd %2,r0\;movsd\"; - } - else - { - return \"movd %2,r0\;movsb\"; - } -#endif -}") ;; Extension and truncation insns. ;; Those for integer source operand @@ -575,13 +582,13 @@ (define_insn "truncsiqi2" [(set (match_operand:QI 0 "general_operand" "=g<") - (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "rmn")))] + (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "g")))] "" "movb %1,%0") (define_insn "truncsihi2" [(set (match_operand:HI 0 "general_operand" "=g<") - (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "rmn")))] + (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "g")))] "" "movw %1,%0") @@ -610,14 +617,14 @@ "movxbd %1,%0") (define_insn "extendsfdf2" - [(set (match_operand:DF 0 "general_operand" "=fm<") + [(set (match_operand:DF 0 "general_operand" "=lm<") (float_extend:DF (match_operand:SF 1 "general_operand" "fmF")))] "TARGET_32081" "movfl %1,%0") (define_insn "truncdfsf2" [(set (match_operand:SF 0 "general_operand" "=fm<") - (float_truncate:SF (match_operand:DF 1 "general_operand" "fmF")))] + (float_truncate:SF (match_operand:DF 1 "general_operand" "lmF")))] "TARGET_32081" "movlf %1,%0") @@ -657,7 +664,7 @@ "movdf %1,%0") (define_insn "floatsidf2" - [(set (match_operand:DF 0 "general_operand" "=fm<") + [(set (match_operand:DF 0 "general_operand" "=lm<") (float:DF (match_operand:SI 1 "general_operand" "rm")))] "TARGET_32081" "movdl %1,%0") @@ -669,7 +676,7 @@ "movwf %1,%0") (define_insn "floathidf2" - [(set (match_operand:DF 0 "general_operand" "=fm<") + [(set (match_operand:DF 0 "general_operand" "=lm<") (float:DF (match_operand:HI 1 "general_operand" "rm")))] "TARGET_32081" "movwl %1,%0") @@ -683,7 +690,7 @@ ; Some assemblers warn that this insn doesn't work. ; Maybe they know something we don't. ;(define_insn "floatqidf2" -; [(set (match_operand:DF 0 "general_operand" "=fm<") +; [(set (match_operand:DF 0 "general_operand" "=lm<") ; (float:DF (match_operand:QI 1 "general_operand" "rm")))] ; "TARGET_32081" ; "movbl %1,%0") @@ -711,19 +718,19 @@ (define_insn "fixdfqi2" [(set (match_operand:QI 0 "general_operand" "=g<") - (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))] "TARGET_32081" "trunclb %1,%0") (define_insn "fixdfhi2" [(set (match_operand:HI 0 "general_operand" "=g<") - (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))] "TARGET_32081" "trunclw %1,%0") (define_insn "fixdfsi2" [(set (match_operand:SI 0 "general_operand" "=g<") - (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))] "TARGET_32081" "truncld %1,%0") @@ -749,19 +756,19 @@ (define_insn "fixunsdfqi2" [(set (match_operand:QI 0 "general_operand" "=g<") - (unsigned_fix:QI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + (unsigned_fix:QI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))] "TARGET_32081" "trunclb %1,%0") (define_insn "fixunsdfhi2" [(set (match_operand:HI 0 "general_operand" "=g<") - (unsigned_fix:HI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + (unsigned_fix:HI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))] "TARGET_32081" "trunclw %1,%0") (define_insn "fixunsdfsi2" [(set (match_operand:SI 0 "general_operand" "=g<") - (unsigned_fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + (unsigned_fix:SI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))] "TARGET_32081" "truncld %1,%0") @@ -786,28 +793,69 @@ (define_insn "fix_truncdfqi2" [(set (match_operand:QI 0 "general_operand" "=g<") - (fix:QI (match_operand:DF 1 "general_operand" "fm")))] + (fix:QI (match_operand:DF 1 "general_operand" "lm")))] "TARGET_32081" "trunclb %1,%0") (define_insn "fix_truncdfhi2" [(set (match_operand:HI 0 "general_operand" "=g<") - (fix:HI (match_operand:DF 1 "general_operand" "fm")))] + (fix:HI (match_operand:DF 1 "general_operand" "lm")))] "TARGET_32081" "trunclw %1,%0") (define_insn "fix_truncdfsi2" [(set (match_operand:SI 0 "general_operand" "=g<") - (fix:SI (match_operand:DF 1 "general_operand" "fm")))] + (fix:SI (match_operand:DF 1 "general_operand" "lm")))] "TARGET_32081" "truncld %1,%0") +;; Multiply-add instructions +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=v,v") + (plus:DF (mult:DF (match_operand:DF 1 "general_operand" "%lmF,0") + (match_operand:DF 2 "general_operand" "lmF,lmF")) + (match_operand:DF 3 "general_operand" "0,lmF")))] + "TARGET_MULT_ADD" + "@ + dotl %1,%2 + polyl %2,%3") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=u,u") + (plus:SF (mult:SF (match_operand:SF 1 "general_operand" "%fmF,0") + (match_operand:SF 2 "general_operand" "fmF,fmF")) + (match_operand:SF 3 "general_operand" "0,fmF")))] + "TARGET_MULT_ADD" + "@ + dotf %1,%2 + polyf %2,%3") + + +;; Multiply-sub instructions +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=v") + (minus:DF (mult:DF (match_operand:DF 1 "general_operand" "%lmF") + (match_operand:DF 2 "general_operand" "lmF")) + (match_operand:DF 3 "general_operand" "0")))] + "TARGET_MULT_ADD" + "@ + negl %0,%0\;dotl %1,%2") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=u") + (minus:SF (mult:SF (match_operand:SF 1 "general_operand" "%fmF") + (match_operand:SF 2 "general_operand" "fmF")) + (match_operand:SF 3 "general_operand" "0")))] + "TARGET_MULT_ADD" + "@ + negf %0,%0\;dotf %1,%2") + ;;- All kinds of add instructions. (define_insn "adddf3" - [(set (match_operand:DF 0 "general_operand" "=fm") + [(set (match_operand:DF 0 "general_operand" "=lm") (plus:DF (match_operand:DF 1 "general_operand" "%0") - (match_operand:DF 2 "general_operand" "fmF")))] + (match_operand:DF 2 "general_operand" "lmF")))] "TARGET_32081" "addl %2,%0") @@ -820,8 +868,8 @@ "addf %2,%0") (define_insn "" - [(set (reg:SI 17) - (plus:SI (reg:SI 17) + [(set (reg:SI 25) + (plus:SI (reg:SI 25) (match_operand:SI 0 "immediate_operand" "i")))] "GET_CODE (operands[0]) == CONST_INT" "* @@ -837,23 +885,23 @@ if (! TARGET_32532) { if (INTVAL (operands[0]) < 64 && INTVAL (operands[0]) > -64) - return \"adjspb %$%n0\"; + return \"adjspb %n0\"; else if (INTVAL (operands[0]) < 8192 && INTVAL (operands[0]) >= -8192) - return \"adjspw %$%n0\"; + return \"adjspw %n0\"; } - return \"adjspd %$%n0\"; + return \"adjspd %n0\"; }") (define_insn "" [(set (match_operand:SI 0 "general_operand" "=g<") - (plus:SI (reg:SI 16) + (plus:SI (reg:SI 24) (match_operand:SI 1 "immediate_operand" "i")))] "GET_CODE (operands[1]) == CONST_INT" "addr %c1(fp),%0") (define_insn "" [(set (match_operand:SI 0 "general_operand" "=g<") - (plus:SI (reg:SI 17) + (plus:SI (reg:SI 25) (match_operand:SI 1 "immediate_operand" "i")))] "GET_CODE (operands[1]) == CONST_INT" "addr %c1(sp),%0") @@ -882,14 +930,14 @@ { i = INTVAL (xops[3]); if (i <= 7 && i >= -8) - output_asm_insn (\"addqd %$%3,%1\", xops); + output_asm_insn (\"addqd %3,%1\", xops); else - output_asm_insn (\"addd %$%3,%1\", xops); + output_asm_insn (\"addd %3,%1\", xops); } else { - output_asm_insn (\"addqd %$%2,%0\", xops); - output_asm_insn (\"addcd %$%3,%1\", xops); + output_asm_insn (\"addqd %2,%0\", xops); + output_asm_insn (\"addcd %3,%1\", xops); } return \"\"; } @@ -899,29 +947,40 @@ return \"\"; }") +;; See Note 1 (define_insn "addsi3" [(set (match_operand:SI 0 "general_operand" "=g,=g&<") (plus:SI (match_operand:SI 1 "general_operand" "%0,r") - (match_operand:SI 2 "general_operand" "rmn,n")))] + (match_operand:SI 2 "general_operand" "g,i")))] "" "* { if (which_alternative == 1) { - int i = INTVAL (operands[2]); - if (NS32K_DISPLACEMENT_P (i)) - return \"addr %c2(%1),%0\"; + if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if (NS32K_DISPLACEMENT_P (i)) + return \"addr %c2(%1),%0\"; + else + return \"movd %1,%0\;addd %2,%0\"; + } else - return \"movd %1,%0\;addd %2,%0\"; + { + if (flag_pic) + return \"addr %a2[%1:b],%0\"; + else + return \"addr %c2(%1),%0\"; + } } - if (GET_CODE (operands[2]) == CONST_INT) + else if (GET_CODE (operands[2]) == CONST_INT) { int i = INTVAL (operands[2]); if (i <= 7 && i >= -8) return \"addqd %2,%0\"; else if (! TARGET_32532 && GET_CODE (operands[0]) == REG - && i <= 0x1fffffff && i >= -0x20000000) + && NS32K_DISPLACEMENT_P (i)) return \"addr %c2(%0),%0\"; } return \"addd %2,%0\"; @@ -986,9 +1045,9 @@ ;;- All kinds of subtract instructions. (define_insn "subdf3" - [(set (match_operand:DF 0 "general_operand" "=fm") + [(set (match_operand:DF 0 "general_operand" "=lm") (minus:DF (match_operand:DF 1 "general_operand" "0") - (match_operand:DF 2 "general_operand" "fmF")))] + (match_operand:DF 2 "general_operand" "lmF")))] "TARGET_32081" "subl %2,%0") @@ -1000,16 +1059,16 @@ "subf %2,%0") (define_insn "" - [(set (reg:SI 17) - (minus:SI (reg:SI 17) + [(set (reg:SI 25) + (minus:SI (reg:SI 25) (match_operand:SI 0 "immediate_operand" "i")))] "GET_CODE (operands[0]) == CONST_INT" "* { if (! TARGET_32532 && GET_CODE(operands[0]) == CONST_INT && INTVAL(operands[0]) < 64 && INTVAL(operands[0]) > -64) - return \"adjspb %$%0\"; - return \"adjspd %$%0\"; + return \"adjspb %0\"; + return \"adjspd %0\"; }") (define_insn "subdi3" @@ -1036,14 +1095,14 @@ { i = INTVAL (xops[3]); if (i <= 8 && i >= -7) - output_asm_insn (\"addqd %$%n3,%1\", xops); + output_asm_insn (\"addqd %n3,%1\", xops); else - output_asm_insn (\"subd %$%3,%1\", xops); + output_asm_insn (\"subd %3,%1\", xops); } else { - output_asm_insn (\"addqd %$%n2,%0\", xops); - output_asm_insn (\"subcd %$%3,%1\", xops); + output_asm_insn (\"addqd %n2,%0\", xops); + output_asm_insn (\"subcd %3,%1\", xops); } return \"\"; } @@ -1056,7 +1115,7 @@ (define_insn "subsi3" [(set (match_operand:SI 0 "general_operand" "=g") (minus:SI (match_operand:SI 1 "general_operand" "0") - (match_operand:SI 2 "general_operand" "rmn")))] + (match_operand:SI 2 "general_operand" "g")))] "" "* { if (GET_CODE (operands[2]) == CONST_INT) @@ -1064,7 +1123,7 @@ int i = INTVAL (operands[2]); if (i <= 8 && i >= -7) - return \"addqd %$%n2,%0\"; + return \"addqd %n2,%0\"; } return \"subd %2,%0\"; }") @@ -1080,7 +1139,7 @@ int i = INTVAL (operands[2]); if (i <= 8 && i >= -7) - return \"addqw %$%n2,%0\"; + return \"addqw %n2,%0\"; } return \"subw %2,%0\"; }") @@ -1094,7 +1153,7 @@ { if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) >-8 && INTVAL(operands[1]) < 9) - return \"addqw %$%n2,%0\"; + return \"addqw %n2,%0\"; return \"subw %2,%0\"; }") @@ -1109,7 +1168,7 @@ int i = INTVAL (operands[2]); if (i <= 8 && i >= -7) - return \"addqb %$%n2,%0\"; + return \"addqb %n2,%0\"; } return \"subb %2,%0\"; }") @@ -1123,16 +1182,16 @@ { if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) >-8 && INTVAL(operands[1]) < 9) - return \"addqb %$%n2,%0\"; + return \"addqb %n2,%0\"; return \"subb %2,%0\"; }") ;;- Multiply instructions. (define_insn "muldf3" - [(set (match_operand:DF 0 "general_operand" "=fm") + [(set (match_operand:DF 0 "general_operand" "=lm") (mult:DF (match_operand:DF 1 "general_operand" "%0") - (match_operand:DF 2 "general_operand" "fmF")))] + (match_operand:DF 2 "general_operand" "lmF")))] "TARGET_32081" "mull %2,%0") @@ -1143,10 +1202,11 @@ "TARGET_32081" "mulf %2,%0") +;; See note 1 (define_insn "mulsi3" [(set (match_operand:SI 0 "general_operand" "=g") (mult:SI (match_operand:SI 1 "general_operand" "%0") - (match_operand:SI 2 "general_operand" "rmn")))] + (match_operand:SI 2 "general_operand" "g")))] "" "muld %2,%0") @@ -1169,16 +1229,195 @@ (mult:DI (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "0")) (zero_extend:DI - (match_operand:SI 2 "nonimmediate_operand" "rmn"))))] + (match_operand:SI 2 "nonimmediate_operand" "g"))))] "" "meid %2,%0") +;; divmod insns: We can only do the unsigned case. +(define_expand "udivmodsi4" + [(parallel + [(set (match_operand:SI 0 "reg_or_mem_operand" "") + (udiv:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" ""))) + (set (match_operand:SI 3 "reg_or_mem_operand" "") + (umod:SI (match_dup 1) (match_dup 2)))])] + "" + " +{ + rtx temp = gen_reg_rtx(DImode); + rtx insn, first, last; + first = emit_move_insn(gen_lowpart(SImode, temp), operands[1]); + emit_move_insn(gen_highpart(SImode, temp), const0_rtx); + emit_insn(gen_udivmoddisi4_internal(temp, temp, operands[2])); + last = emit_move_insn(temp, temp); + { + rtx divdi, moddi, divsi, modsi; + divsi = gen_rtx (UDIV, SImode, operands[1], operands[2]); + modsi = gen_rtx (UMOD, SImode, operands[1], operands[2]); + divdi = gen_rtx (ZERO_EXTEND, DImode, divsi); + moddi = gen_rtx (ZERO_EXTEND, DImode, modsi); + REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last, + REG_NOTES (first)); + REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first, + gen_rtx (EXPR_LIST, REG_EQUAL, + gen_rtx (IOR, DImode, moddi, + gen_rtx (ASHIFT, DImode, divdi, GEN_INT(32))), + REG_NOTES (last))); + } + + insn = emit_move_insn(operands[0], gen_highpart(SImode, temp)); + insn = emit_move_insn(operands[3], gen_lowpart(SImode, temp)); + DONE; +}") + +;; If we try and describe what this does, we have to zero-expand an +;; operand, which prevents it being a constant (VOIDmode) (see udivmoddisi4 +;; below. This udivmoddisi4_internal never matches anything and is only +;; ever used when explicitly emitted by a define_expand. +(define_insn "udivmoddisi4_internal" + [(set (match_operand:DI 0 "reg_or_mem_operand" "=rm") + (unspec:SI [(match_operand:DI 1 "reg_or_mem_operand" "0") + (match_operand:SI 2 "general_operand" "g")] 0))] + "" + "deid %2,%0") + +;; Retain this insn which *does* have a pattern indicating what it does, +;; just in case the compiler is smart enough to recognize a substitution. +(define_insn "udivmoddisi4" + [(set (subreg:SI (match_operand:DI 0 "register_operand" "=rm") 1) + (truncate:SI (udiv:DI (match_operand:DI 1 "reg_or_mem_operand" "0") + (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "g"))))) + (set (subreg:SI (match_operand:DI 3 "register_operand" "=0") 0) + (truncate:SI (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))] + "" + "deid %2,%0") + +;; Part word variants. These seem to never be used at the moment (gcc +;; 2.7.2.2). The code generation prefers to zero extend hi's and qi's +;; and use signed div and mod. Keep these insns incase that changes. +;; divmod should have an advantage when both div and mod are needed. However, +;; divmod uses two registers, so maybe the compiler knows best. + +(define_expand "udivmodhi4" + [(parallel + [(set (match_operand:HI 0 "reg_or_mem_operand" "") + (udiv:HI (match_operand:HI 1 "general_operand" "") + (match_operand:HI 2 "general_operand" ""))) + (set (match_operand:HI 3 "reg_or_mem_operand" "") + (umod:HI (match_dup 1) (match_dup 2)))])] + "" + " +{ + rtx temp = gen_reg_rtx(DImode); + rtx insn, first, last; + first = emit_move_insn(gen_lowpart(HImode, temp), operands[1]); + emit_move_insn(gen_highpart (HImode, temp), const0_rtx); + operands[2] = force_reg(HImode, operands[2]); + emit_insn(gen_udivmoddihi4_internal(temp, temp, operands[2])); + last = emit_move_insn(temp, temp); + { + rtx divdi, moddi, divhi, modhi; + divhi = gen_rtx (UDIV, HImode, operands[1], operands[2]); + modhi = gen_rtx (UMOD, HImode, operands[1], operands[2]); + divdi = gen_rtx (ZERO_EXTEND, DImode, divhi); + moddi = gen_rtx (ZERO_EXTEND, DImode, modhi); + REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last, + REG_NOTES (first)); + REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first, + gen_rtx (EXPR_LIST, REG_EQUAL, + gen_rtx(IOR, DImode, moddi, + gen_rtx(ASHIFT, DImode, divdi, GEN_INT(32))), + REG_NOTES (last))); + } + + insn = emit_move_insn(operands[0], gen_highpart(HImode, temp)); + insn = emit_move_insn(operands[3], gen_lowpart(HImode, temp)); + DONE; +}") + +;; deiw wants two hi's in seperate registers or else they can be adjacent +;; in memory. DI mode will ensure two registers are available, but if we +;; want to allow memory as an operand we would need SI mode. There is no +;; way to do this, so just restrict operand 0 and 1 to be in registers. +(define_insn "udivmoddihi4_internal" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:HI [(match_operand:DI 1 "register_operand" "0") + (match_operand:HI 2 "general_operand" "g")] 0))] + "" + "deiw %2,%0") + +(define_insn "udivmoddihi4" + [(set (subreg:HI (match_operand:DI 0 "register_operand" "=r") 1) + (truncate:HI (udiv:DI (match_operand:DI 1 "reg_or_mem_operand" "0") + (zero_extend:DI (match_operand:HI 2 "nonimmediate_operand" "g"))))) + (set (subreg:HI (match_operand:DI 3 "register_operand" "=0") 0) + (truncate:HI (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))] + "" + "deiw %2,%0") + +(define_expand "udivmodqi4" + [(parallel + [(set (match_operand:QI 0 "reg_or_mem_operand" "") + (udiv:QI (match_operand:QI 1 "general_operand" "") + (match_operand:QI 2 "general_operand" ""))) + (set (match_operand:QI 3 "reg_or_mem_operand" "") + (umod:QI (match_dup 1) (match_dup 2)))])] + "" + " +{ + rtx temp = gen_reg_rtx(DImode); + rtx insn, first, last; + first = emit_move_insn(gen_lowpart(QImode, temp), operands[1]); + emit_move_insn(gen_highpart(QImode, temp), const0_rtx); + operands[2] = force_reg(QImode, operands[2]); + emit_insn(gen_udivmoddiqi4_internal(temp, temp, operands[2])); + last = emit_move_insn(temp, temp); + { + rtx divdi, moddi, divqi, modqi; + divqi = gen_rtx (UDIV, QImode, operands[1], operands[2]); + modqi = gen_rtx (UMOD, QImode, operands[1], operands[2]); + divdi = gen_rtx (ZERO_EXTEND, DImode, divqi); + moddi = gen_rtx (ZERO_EXTEND, DImode, modqi); + REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last, + REG_NOTES (first)); + REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first, + gen_rtx (EXPR_LIST, REG_EQUAL, + gen_rtx(IOR, DImode, moddi, + gen_rtx(ASHIFT, DImode, divdi, GEN_INT(32))), + REG_NOTES (last))); + } + + insn = emit_move_insn(operands[0], gen_highpart(QImode, temp)); + insn = emit_move_insn(operands[3], gen_lowpart(QImode, temp)); + DONE; +}") + +;; deib wants two qi's in seperate registers or else they can be adjacent +;; in memory. DI mode will ensure two registers are available, but if we +;; want to allow memory as an operand we would need HI mode. There is no +;; way to do this, so just restrict operand 0 and 1 to be in registers. +(define_insn "udivmoddiqi4_internal" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:QI [(match_operand:DI 1 "reg_or_mem_operand" "0") + (match_operand:QI 2 "general_operand" "g")] 0))] + "" + "deib %2,%0") + +(define_insn "udivmoddiqi4" + [(set (subreg:QI (match_operand:DI 0 "register_operand" "=r") 1) + (truncate:QI (udiv:DI (match_operand:DI 1 "reg_or_mem_operand" "0") + (zero_extend:DI (match_operand:QI 2 "nonimmediate_operand" "g"))))) + (set (subreg:QI (match_operand:DI 3 "register_operand" "=0") 0) + (truncate:QI (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))] + "" + "deib %2,%0") + ;;- Divide instructions. (define_insn "divdf3" - [(set (match_operand:DF 0 "general_operand" "=fm") + [(set (match_operand:DF 0 "general_operand" "=lm") (div:DF (match_operand:DF 1 "general_operand" "0") - (match_operand:DF 2 "general_operand" "fmF")))] + (match_operand:DF 2 "general_operand" "lmF")))] "TARGET_32081" "divl %2,%0") @@ -1189,10 +1428,11 @@ "TARGET_32081" "divf %2,%0") +;; See note 1 (define_insn "divsi3" [(set (match_operand:SI 0 "general_operand" "=g") (div:SI (match_operand:SI 1 "general_operand" "0") - (match_operand:SI 2 "general_operand" "rmn")))] + (match_operand:SI 2 "general_operand" "g")))] "" "quod %2,%0") @@ -1209,46 +1449,14 @@ (match_operand:QI 2 "general_operand" "g")))] "" "quob %2,%0") - -(define_insn "udivsi3" - [(set (match_operand:SI 0 "register_operand" "=r") - (udiv:SI (subreg:SI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) - (match_operand:SI 2 "general_operand" "rmn")))] - "" - "* -{ - operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); - return \"deid %2,%0\;movd %1,%0\"; -}") - -(define_insn "udivhi3" - [(set (match_operand:HI 0 "register_operand" "=r") - (udiv:HI (subreg:HI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) - (match_operand:HI 2 "general_operand" "g")))] - "" - "* -{ - operands[1] = gen_rtx (REG, HImode, REGNO (operands[0]) + 1); - return \"deiw %2,%0\;movw %1,%0\"; -}") - -(define_insn "udivqi3" - [(set (match_operand:QI 0 "register_operand" "=r") - (udiv:QI (subreg:QI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) - (match_operand:QI 2 "general_operand" "g")))] - "" - "* -{ - operands[1] = gen_rtx (REG, QImode, REGNO (operands[0]) + 1); - return \"deib %2,%0\;movb %1,%0\"; -}") - + ;; Remainder instructions. +;; See note 1 (define_insn "modsi3" [(set (match_operand:SI 0 "general_operand" "=g") (mod:SI (match_operand:SI 1 "general_operand" "0") - (match_operand:SI 2 "general_operand" "rmn")))] + (match_operand:SI 2 "general_operand" "g")))] "" "remd %2,%0") @@ -1266,43 +1474,14 @@ "" "remb %2,%0") -(define_insn "umodsi3" - [(set (match_operand:SI 0 "register_operand" "=r") - (umod:SI (subreg:SI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) - (match_operand:SI 2 "general_operand" "rmn")))] - "" - "deid %2,%0") - -(define_insn "umodhi3" - [(set (match_operand:HI 0 "register_operand" "=r") - (umod:HI (subreg:HI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) - (match_operand:HI 2 "general_operand" "g")))] - "" - "deiw %2,%0") - -(define_insn "umodqi3" - [(set (match_operand:QI 0 "register_operand" "=r") - (umod:QI (subreg:QI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) - (match_operand:QI 2 "general_operand" "g")))] - "" - "deib %2,%0") - -; This isn't be usable in its current form. -;(define_insn "udivmoddisi4" -; [(set (subreg:SI (match_operand:DI 0 "general_operand" "=r") 1) -; (udiv:SI (match_operand:DI 1 "general_operand" "0") -; (match_operand:SI 2 "general_operand" "rmn"))) -; (set (subreg:SI (match_dup 0) 0) -; (umod:SI (match_dup 1) (match_dup 2)))] -; "" -; "deid %2,%0") ;;- Logical Instructions: AND +;; See note 1 (define_insn "andsi3" [(set (match_operand:SI 0 "general_operand" "=g") (and:SI (match_operand:SI 1 "general_operand" "%0") - (match_operand:SI 2 "general_operand" "rmn")))] + (match_operand:SI 2 "general_operand" "g")))] "" "* { @@ -1360,9 +1539,10 @@ "" "andb %2,%0") +;; See note 1 (define_insn "" [(set (match_operand:SI 0 "general_operand" "=g") - (and:SI (not:SI (match_operand:SI 1 "general_operand" "rmn")) + (and:SI (not:SI (match_operand:SI 1 "general_operand" "g")) (match_operand:SI 2 "general_operand" "0")))] "" "bicd %1,%0") @@ -1383,10 +1563,11 @@ ;;- Bit set instructions. +;; See note 1 (define_insn "iorsi3" [(set (match_operand:SI 0 "general_operand" "=g") (ior:SI (match_operand:SI 1 "general_operand" "%0") - (match_operand:SI 2 "general_operand" "rmn")))] + (match_operand:SI 2 "general_operand" "g")))] "" "* { @@ -1421,10 +1602,11 @@ ;;- xor instructions. +;; See note 1 (define_insn "xorsi3" [(set (match_operand:SI 0 "general_operand" "=g") (xor:SI (match_operand:SI 1 "general_operand" "%0") - (match_operand:SI 2 "general_operand" "rmn")))] + (match_operand:SI 2 "general_operand" "g")))] "" "* { @@ -1458,8 +1640,8 @@ "xorb %2,%0") (define_insn "negdf2" - [(set (match_operand:DF 0 "general_operand" "=fm<") - (neg:DF (match_operand:DF 1 "general_operand" "fmF")))] + [(set (match_operand:DF 0 "general_operand" "=lm<") + (neg:DF (match_operand:DF 1 "general_operand" "lmF")))] "TARGET_32081" "negl %1,%0") @@ -1497,9 +1679,10 @@ return \"\"; }") +;; See note 1 (define_insn "negsi2" [(set (match_operand:SI 0 "general_operand" "=g<") - (neg:SI (match_operand:SI 1 "general_operand" "rmn")))] + (neg:SI (match_operand:SI 1 "general_operand" "g")))] "" "negd %1,%0") @@ -1515,9 +1698,10 @@ "" "negb %1,%0") +;; See note 1 (define_insn "one_cmplsi2" [(set (match_operand:SI 0 "general_operand" "=g<") - (not:SI (match_operand:SI 1 "general_operand" "rmn")))] + (not:SI (match_operand:SI 1 "general_operand" "g")))] "" "comd %1,%0") @@ -1540,10 +1724,11 @@ ;; than elsewhere. ;; alternative 0 never matches on the 32532 +;; See note 1 (define_insn "ashlsi3" [(set (match_operand:SI 0 "general_operand" "=g,g") (ashift:SI (match_operand:SI 1 "general_operand" "r,0") - (match_operand:SI 2 "general_operand" "I,rmn")))] + (match_operand:SI 2 "general_operand" "I,g")))] "" "* { if (TARGET_32532) @@ -1555,7 +1740,7 @@ (define_insn "ashlhi3" [(set (match_operand:HI 0 "general_operand" "=g") (ashift:HI (match_operand:HI 1 "general_operand" "0") - (match_operand:SI 2 "general_operand" "rmn")))] + (match_operand:SI 2 "general_operand" "g")))] "" "* { if (GET_CODE (operands[2]) == CONST_INT) @@ -1574,7 +1759,7 @@ (define_insn "ashlqi3" [(set (match_operand:QI 0 "general_operand" "=g") (ashift:QI (match_operand:QI 1 "general_operand" "0") - (match_operand:SI 2 "general_operand" "rmn")))] + (match_operand:SI 2 "general_operand" "g")))] "" "* { if (GET_CODE (operands[2]) == CONST_INT) @@ -1607,7 +1792,7 @@ (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "" - "ashd %$%n2,%0") + "ashd %n2,%0") (define_insn "" [(set (match_operand:SI 0 "general_operand" "=g") @@ -1632,7 +1817,7 @@ (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "" - "ashw %$%n2,%0") + "ashw %n2,%0") (define_insn "" [(set (match_operand:HI 0 "general_operand" "=g") @@ -1657,7 +1842,7 @@ (ashiftrt:QI (match_operand:QI 1 "general_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "" - "ashb %$%n2,%0") + "ashb %n2,%0") (define_insn "" [(set (match_operand:QI 0 "general_operand" "=g") @@ -1685,7 +1870,7 @@ (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "" - "lshd %$%n2,%0") + "lshd %n2,%0") (define_insn "" [(set (match_operand:SI 0 "general_operand" "=g") @@ -1710,7 +1895,7 @@ (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "" - "lshw %$%n2,%0") + "lshw %n2,%0") (define_insn "" [(set (match_operand:HI 0 "general_operand" "=g") @@ -1735,7 +1920,7 @@ (lshiftrt:QI (match_operand:QI 1 "general_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "" - "lshb %$%n2,%0") + "lshb %n2,%0") (define_insn "" [(set (match_operand:QI 0 "general_operand" "=g") @@ -1746,24 +1931,25 @@ ;; Rotate instructions +;; See note 1 (define_insn "rotlsi3" [(set (match_operand:SI 0 "general_operand" "=g") (rotate:SI (match_operand:SI 1 "general_operand" "0") - (match_operand:SI 2 "general_operand" "rmn")))] + (match_operand:SI 2 "general_operand" "g")))] "" "rotd %2,%0") (define_insn "rotlhi3" [(set (match_operand:HI 0 "general_operand" "=g") (rotate:HI (match_operand:HI 1 "general_operand" "0") - (match_operand:SI 2 "general_operand" "rmn")))] + (match_operand:SI 2 "general_operand" "g")))] "" "rotw %2,%0") (define_insn "rotlqi3" [(set (match_operand:QI 0 "general_operand" "=g") (rotate:QI (match_operand:QI 1 "general_operand" "0") - (match_operand:SI 2 "general_operand" "rmn")))] + (match_operand:SI 2 "general_operand" "g")))] "" "rotb %2,%0") @@ -1784,7 +1970,7 @@ (rotatert:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "" - "rotd %$%n2,%0") + "rotd %n2,%0") (define_insn "" [(set (match_operand:SI 0 "general_operand" "=g") @@ -1809,7 +1995,7 @@ (rotatert:HI (match_operand:HI 1 "general_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "" - "rotw %$%n2,%0") + "rotw %n2,%0") (define_insn "" [(set (match_operand:HI 0 "general_operand" "=g") @@ -1834,7 +2020,7 @@ (rotatert:QI (match_operand:QI 1 "general_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "" - "rotb %$%n2,%0") + "rotb %n2,%0") (define_insn "" [(set (match_operand:QI 0 "general_operand" "=g") @@ -1871,53 +2057,58 @@ ;;; Index insns. These are about the same speed as multiply-add counterparts. ;;; but slower then using power-of-2 shifts if we can use them ; +;;; See note 1 ;(define_insn "" ; [(set (match_operand:SI 0 "register_operand" "=r") -; (plus:SI (match_operand:SI 1 "general_operand" "rmn") +; (plus:SI (match_operand:SI 1 "general_operand" "g") ; (mult:SI (match_operand:SI 2 "register_operand" "0") -; (plus:SI (match_operand:SI 3 "general_operand" "rmn") (const_int 1)))))] +; (plus:SI (match_operand:SI 3 "general_operand" "g") (const_int 1)))))] ; "GET_CODE (operands[3]) != CONST_INT || INTVAL (operands[3]) > 8" ; "indexd %0,%3,%1") ; ;(define_insn "" ; [(set (match_operand:SI 0 "register_operand" "=r") ; (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "0") -; (plus:SI (match_operand:SI 2 "general_operand" "rmn") (const_int 1))) -; (match_operand:SI 3 "general_operand" "rmn")))] +; (plus:SI (match_operand:SI 2 "general_operand" "g") (const_int 1))) +; (match_operand:SI 3 "general_operand" "g")))] ; "GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) > 8" ; "indexd %0,%2,%3") ;; Set, Clear, and Invert bit +;; See note 1 (define_insn "" [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+g") (const_int 1) - (match_operand:SI 1 "general_operand" "rmn")) + (match_operand:SI 1 "general_operand" "g")) (const_int 1))] "" "sbitd %1,%0") +;; See note 1 (define_insn "" [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+g") (const_int 1) - (match_operand:SI 1 "general_operand" "rmn")) + (match_operand:SI 1 "general_operand" "g")) (const_int 0))] "" "cbitd %1,%0") +;; See note 1 (define_insn "" [(set (match_operand:SI 0 "general_operand" "+g") (xor:SI (ashift:SI (const_int 1) - (match_operand:SI 1 "general_operand" "rmn")) + (match_operand:SI 1 "general_operand" "g")) (match_dup 0)))] "" "ibitd %1,%0") +;; See note 1 (define_insn "" [(set (match_operand:QI 0 "general_operand" "=g") (xor:QI (subreg:QI (ashift:SI (const_int 1) - (match_operand:QI 1 "general_operand" "rmn")) 0) + (match_operand:QI 1 "general_operand" "g")) 0) (match_dup 0)))] "" "ibitb %1,%0") @@ -2308,7 +2499,7 @@ (minus:SI (match_dup 0) (match_dup 1)))] "INTVAL (operands[1]) > -8 && INTVAL (operands[1]) <= 8" - "acbd %$%n1,%0,%l2") + "acbd %n1,%0,%l2") (define_insn "" [(set (pc) @@ -2450,14 +2641,15 @@ "absf %1,%0") (define_insn "absdf2" - [(set (match_operand:DF 0 "general_operand" "=fm<") - (abs:DF (match_operand:DF 1 "general_operand" "fmF")))] + [(set (match_operand:DF 0 "general_operand" "=lm<") + (abs:DF (match_operand:DF 1 "general_operand" "lmF")))] "TARGET_32081" "absl %1,%0") +;; See note 1 (define_insn "abssi2" [(set (match_operand:SI 0 "general_operand" "=g<") - (abs:SI (match_operand:SI 1 "general_operand" "rmn")))] + (abs:SI (match_operand:SI 1 "general_operand" "g")))] "" "absd %1,%0") @@ -2745,14 +2937,14 @@ ;; Speed up stack adjust followed by a HI fixedpoint push. (define_peephole - [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int -2))) + [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int -2))) (set (match_operand:HI 0 "push_operand" "=m") (match_operand:HI 1 "general_operand" "g"))] "! reg_mentioned_p (stack_pointer_rtx, operands[1])" "* { if (GET_CODE (operands[1]) == CONST_INT) - output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,tos\"), + output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,tos\"), operands); else output_asm_insn (\"movzwd %1,tos\", operands); @@ -2762,14 +2954,14 @@ ;; Speed up stack adjust followed by a zero_extend:HI(QI) fixedpoint push. (define_peephole - [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int -2))) + [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int -2))) (set (match_operand:HI 0 "push_operand" "=m") (zero_extend:HI (match_operand:QI 1 "general_operand" "g")))] "! reg_mentioned_p (stack_pointer_rtx, operands[1])" "* { if (GET_CODE (operands[1]) == CONST_INT) - output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,tos\"), + output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,tos\"), operands); else output_asm_insn (\"movzbd %1,tos\", operands); @@ -2779,14 +2971,14 @@ ;; Speed up stack adjust followed by a sign_extend:HI(QI) fixedpoint push. (define_peephole - [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int -2))) + [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int -2))) (set (match_operand:HI 0 "push_operand" "=m") (sign_extend:HI (match_operand:QI 1 "general_operand" "g")))] "! reg_mentioned_p (stack_pointer_rtx, operands[1])" "* { if (GET_CODE (operands[1]) == CONST_INT) - output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,tos\"), + output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,tos\"), operands); else output_asm_insn (\"movxbd %1,tos\", operands); @@ -2796,14 +2988,14 @@ ;; Speed up stack adjust followed by a QI fixedpoint push. (define_peephole - [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int -3))) + [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int -3))) (set (match_operand:QI 0 "push_operand" "=m") (match_operand:QI 1 "general_operand" "g"))] "! reg_mentioned_p (stack_pointer_rtx, operands[1])" "* { if (GET_CODE (operands[1]) == CONST_INT) - output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,tos\"), + output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,tos\"), operands); else output_asm_insn (\"movzbd %1,tos\", operands); @@ -2813,14 +3005,14 @@ ;; Speed up stack adjust followed by a SI fixedpoint push. (define_peephole - [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int 4))) + [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int 4))) (set (match_operand:SI 0 "push_operand" "=m") (match_operand:SI 1 "general_operand" "g"))] "! reg_mentioned_p (stack_pointer_rtx, operands[1])" "* { if (GET_CODE (operands[1]) == CONST_INT) - output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,0(sp)\"), + output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,0(sp)\"), operands); else if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != MEM @@ -2834,7 +3026,7 @@ ;; Speed up stack adjust followed by two fullword fixedpoint pushes. (define_peephole - [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int 8))) + [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int 8))) (set (match_operand:SI 0 "push_operand" "=m") (match_operand:SI 1 "general_operand" "g")) (set (match_operand:SI 2 "push_operand" "=m") @@ -2844,7 +3036,7 @@ "* { if (GET_CODE (operands[1]) == CONST_INT) - output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,4(sp)\"), + output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,4(sp)\"), operands); else if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != MEM @@ -2854,7 +3046,7 @@ output_asm_insn (\"movd %1,4(sp)\", operands); if (GET_CODE (operands[3]) == CONST_INT) - output_asm_insn (output_move_dconst (INTVAL (operands[3]), \"%$%3,0(sp)\"), + output_asm_insn (output_move_dconst (INTVAL (operands[3]), \"%3,0(sp)\"), operands); else if (GET_CODE (operands[3]) != REG && GET_CODE (operands[3]) != MEM |