diff -Nur orig/gcc-20030127/gcc/config/vax/elf.h x/elf.h --- orig/gcc-20030127/gcc/config/vax/elf.h 2002-10-04 15:23:12.000000000 +1000 +++ x/elf.h 2003-06-15 11:36:40.000000000 +1000 @@ -71,10 +71,12 @@ #define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE, PREFIX, NUM, TABLE) /* Get the udiv/urem calls out of the user's namespace. */ +#if 0 #undef UDIVSI3_LIBCALL #define UDIVSI3_LIBCALL "*__udiv" #undef UMODSI3_LIBCALL #define UMODSI3_LIBCALL "*__urem" +#endif #undef OVERRIDE_OPTIONS #define OVERRIDE_OPTIONS \ diff -Nur orig/gcc-20030127/gcc/config/vax/linux.h x/linux.h --- orig/gcc-20030127/gcc/config/vax/linux.h 1970-01-01 10:00:00.000000000 +1000 +++ x/linux.h 2003-06-15 11:36:40.000000000 +1000 @@ -0,0 +1,78 @@ +/* Definitions of target machine for GNU compiler, + for NetBSD/vax ELF systems. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (VAX Linux/ELF)"); + +/* Names to predefine in the preprocessor for this target OS. */ +#undef TARGET_OS_CPP_BUILTINS +#define TARGET_OS_CPP_BUILTINS() \ + do \ + { \ + builtin_define_std ("linux"); \ + builtin_define_std ("unix"); \ + builtin_define ("__ELF__"); \ + builtin_define ("__gnu_linux__"); \ + builtin_assert ("system=posix"); \ + if (flag_pic) \ + { \ + builtin_define ("__PIC__"); \ + builtin_define ("__pic__"); \ + } \ + } \ + while (0) + +#undef CPP_SPEC +#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}" + +#undef CC1_SPEC +#define CC1_SPEC "%(cc1_cpu) %{profile:-p}" + + +#undef LINK_SPEC +#define LINK_SPEC "-m elf32vax %{shared:-shared} \ + %{!shared: \ + %{!ibcs: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2}} \ + %{static:-static}}}" + + +#if 0 +/* FIXME: We must link all executables statically until PIC support + is added to the compiler. */ +#define LINK_SPEC \ + "%{assert*} %{R*} %{rpath*} \ + %{shared:%eThe -shared option is not currently supported for VAX ELF.} \ + %{!shared: \ + -dc -dp \ + %{!nostdlib: \ + %{!r*: \ + %{!e*:-e %(netbsd_entry_point)}}} \ + %{!static:-static} \ + %{static:-static}}" +#endif + +/* We use gas, not the UNIX assembler. */ +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 0 + +#undef ASM_FINAL_SPEC diff -Nur orig/gcc-20030127/gcc/config/vax/vax.h x/vax.h --- orig/gcc-20030127/gcc/config/vax/vax.h 2002-10-23 09:05:24.000000000 +1000 +++ x/vax.h 2003-06-15 11:36:40.000000000 +1000 @@ -907,9 +907,10 @@ * We can use the BSD C library routines for the libgcc calls that are * still generated, since that's what they boil down to anyways. */ - +#if 0 #define UDIVSI3_LIBCALL "*udiv" #define UMODSI3_LIBCALL "*urem" +#endif /* Tell final.c how to eliminate redundant test instructions. */ diff -Nur orig/gcc-20030127/gcc/config/vax/vax.md x/vax.md --- orig/gcc-20030127/gcc/config/vax/vax.md 2002-10-02 06:16:04.000000000 +1000 +++ x/vax.md 2003-06-15 17:30:25.000000000 +1000 @@ -902,6 +902,312 @@ ; (match_operand:SI 2 "general_operand" "g")))] ; "" ; "ediv %2,%1,%0,%3") + +(define_insn "ediv_helper" + [(set (match_operand:SI 2 "general_operand" "=g") + (div:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:DI 1 "general_operand" "g"))) + (set (match_operand:SI 3 "general_operand" "=g") + (mod:SI (match_dup 0) + (match_dup 1)))] + "" + "ediv %0,%1,%2,%3") + + +(define_expand "udivsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (udiv:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + rtx remainder = gen_reg_rtx(SImode); + rtx dividend_di = gen_reg_rtx(DImode); + rtx dividend = gen_rtx(SUBREG, SImode, dividend_di, 0); + rtx dividend_hi = gen_rtx(SUBREG, SImode, dividend_di, 1); + + rtx label_easy = gen_label_rtx(); + rtx label_ediv = gen_label_rtx(); + rtx label_end = gen_label_rtx(); + rtx label_one = gen_label_rtx(); + + /* we have to deal with the case where one of the operands is + a constant, because otherwise invalid RTXs will be generated. + Both operands can never be constant, because constant + folding will already have eliminated then. */ + + if (GET_CODE (operands[2]) == CONST_INT) { + + /* Divisor is constant */ + + if (INTVAL (operands[2]) > 0) { + + /* Divisor <= 0x7fffffff. If dividend is also <= 0x7fffffff, + then signed division is OK, otherwise need to do extended + (64-bit) division */ + + emit_insn(gen_tstsi(operands[1])); + emit_jump_insn(gen_blt(label_ediv)); + + emit_insn(gen_divsi3(operands[0], operands[1], operands[2])); + emit_jump_insn(gen_jump(label_end)); + + } else { + + /* divisor is >= 0x80000000, so quotient can only be 1 or 0 + depending on which is bigger, dividend or divisor, + respectively */ + + emit_insn(gen_cmpsi(operands[1], operands[2])); + emit_jump_insn(gen_bgeu(label_one)); + emit_insn(gen_movsi(operands[0], const0_rtx)); + emit_jump_insn(gen_jump(label_end)); + emit_label(label_one); + emit_insn(gen_movsi(operands[0], const1_rtx)); + emit_jump_insn(gen_jump(label_end)); + } + } else if (GET_CODE (operands[1]) == CONST_INT) { + + /* Dividend is constant, divisor is variable */ + if (INTVAL (operands[1]) > 0) { + + /* Dividend <= 0x7fffffff. If divisor is also <= 0x7fffffff, + then signed division is OK, otherwise quotient must be 0 */ + + emit_move_insn(operands[0], const0_rtx); + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_blt(label_end)); + + emit_insn(gen_divsi3(operands[0], operands[1], operands[2])); + + } else { + + /* Is divisor <= 0x7fffffff ? (i.e. high bit clear, so looks positive) */ + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_bge(label_ediv)); + + /* divisor is >= 0x80000000, so quotient can only be 1 or 0 + depending on which is bigger, dividend or divisor, + respectively */ + emit_insn(gen_cmpsi(operands[2], operands[1])); + emit_jump_insn(gen_bleu(label_one)); + emit_insn(gen_movsi(operands[0], const0_rtx)); + emit_jump_insn(gen_jump(label_end)); + emit_label(label_one); + emit_insn(gen_movsi(operands[0], const1_rtx)); + emit_jump_insn(gen_jump(label_end)); + } + } else { + + /* Is divisor >= 0x80000000 ? (i.e. high bit set, so looks negative) */ + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_blt(label_easy)); + + emit_insn(gen_tstsi(operands[1])); + emit_jump_insn(gen_blt(label_ediv)); + + /* Both <= 0x7fffffff - signed division OK */ + emit_insn(gen_divsi3(operands[0], operands[1], operands[2])); + emit_jump_insn(gen_jump(label_end)); + + emit_label(label_easy); + + /* divisor is >= 0x80000000, so quotient can only be 1 or 0 + depending on which is bigger, dividend or divisor, + respectively */ + + emit_insn(gen_cmpsi(operands[1], operands[2])); + emit_jump_insn(gen_bgeu(label_one)); + emit_insn(gen_movsi(operands[0], const0_rtx)); + emit_jump_insn(gen_jump(label_end)); + emit_label(label_one); + emit_insn(gen_movsi(operands[0], const1_rtx)); + emit_jump_insn(gen_jump(label_end)); + } + + emit_jump_insn(gen_jump(label_end)); + + emit_label(label_ediv); + /* Dividend is >= 0x80000000 and divisor <= 0x7fffffff, + so we'll use the EDIV instruction instead (EDIV divides + a quadword by a longword, or a DImode by an SImode in + RTL-speak, and produces both quotient and remainder) */ + + emit_move_insn(dividend, operands[1]); + emit_move_insn(dividend_hi, const0_rtx); + + emit_insn(gen_ediv_helper(operands[2], dividend_di, operands[0], remainder)); + + emit_label(label_end); + + DONE; +} +") + +(define_expand "umodsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (umod:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + rtx quotient = gen_reg_rtx(SImode); + rtx dividend_di = gen_reg_rtx(DImode); + rtx dividend = gen_rtx(SUBREG, SImode, dividend_di, 0); + rtx dividend_hi = gen_rtx(SUBREG, SImode, dividend_di, 1); + + rtx label_signed_mod = gen_label_rtx(); + rtx label_compare = gen_label_rtx(); + rtx label_ediv = gen_label_rtx(); + rtx label_end = gen_label_rtx(); + + int emit_signed_mod_code = 0; + int emit_compare_code = 0; + int emit_ediv_code = 0; + + /* we have to deal with the case where one of the operands is + a constant, because otherwise invalid RTXs will be generated. + Both operands can never be constant, because constant + folding will already have eliminated then. */ + + if (GET_CODE (operands[2]) == CONST_INT) { + + /* Divisor is constant */ + + if (INTVAL (operands[2]) > 0) { + + /* Divisor <= 0x7fffffff. If dividend is also <= 0x7fffffff, + then signed division is OK, otherwise need to do extended + (64-bit) division */ + + emit_insn(gen_tstsi(operands[1])); + emit_jump_insn(gen_bge(label_signed_mod)); + emit_jump_insn(gen_jump(label_ediv)); + + emit_signed_mod_code = 1; + emit_ediv_code = 1; + + } else { + + /* divisor is >= 0x80000000, calculate by comparison */ + emit_jump_insn(gen_jump(label_compare)); + + emit_compare_code = 1; + } + + } else if (GET_CODE (operands[1]) == CONST_INT) { + + /* I don't know why, but GCC never seems to end up here */ + + /* Dividend is constant, divisor is variable */ + if (INTVAL (operands[1]) > 0) { + + /* Dividend <= 0x7fffffff. If divisor is also <= 0x7fffffff, + then signed modulus is OK, otherwise do 64-bit division */ + + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_bge(label_signed_mod)); + emit_jump_insn(gen_jump(label_ediv)); + + emit_signed_mod_code = 1; + emit_ediv_code = 1; + + } else { + + /* Dividend >= 0x80000000. If divisor is also >= 0x80000000, + then do mod-by-comparison, otherwise do 64-bit division */ + + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_blt(label_compare)); + emit_jump_insn(gen_jump(label_ediv)); + + emit_compare_code = 1; + emit_ediv_code = 1; + } + } else { + + /* Is divisor >= 0x80000000 ? (i.e. high bit set, so looks negative) */ + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_blt(label_compare)); + + /* Is dividend >= 0x80000000 ? (i.e. high bit set, so looks negative) */ + emit_insn(gen_tstsi(operands[1])); + emit_jump_insn(gen_blt(label_ediv)); + + /* Both <= 0x7fffffff - signed modulus OK */ + emit_jump_insn(gen_jump(label_signed_mod)); + + emit_ediv_code = 1; + emit_compare_code = 1; + emit_signed_mod_code = 1; + } + + if (emit_signed_mod_code) { + emit_label(label_signed_mod); + + /* Both <= 0x7fffffff - signed modulus OK */ + emit_insn(gen_divsi3(quotient, operands[1], operands[2])); + emit_insn(gen_mulsi3(quotient, quotient, operands[2])); + emit_insn(gen_subsi3(operands[0], operands[1], quotient)); + emit_jump_insn(gen_jump(label_end)); + + /* Emit code to use extended division instruction */ + } + + if (emit_ediv_code) { + emit_label(label_ediv); + + /* Dividend is >= 0x80000000 and divisor <= 0x7fffffff, + so we'll use the EDIV instruction instead (EDIV divides + a quadword by a longword, or a DImode by an SImode in + RTL-speak, and produces both quotient and remainder) */ + + emit_move_insn(dividend, operands[1]); + emit_move_insn(dividend_hi, const0_rtx); + + emit_insn(gen_ediv_helper(operands[2], dividend_di, quotient, operands[0])); + emit_jump_insn(gen_jump(label_end)); + } + + if (emit_compare_code) { + /* Emit code to to mod-by-comparison. */ + emit_label(label_compare); + emit_insn(gen_umodsi3_compare(operands[0], operands[1], operands[2])); + } + + emit_label(label_end); + + DONE; +} +") + +;; This is used by the umodsi3 define_expand above. It will never +;; be matched by GCC because it is more specific than the umodsi3 +;; definition, and GCC matches insns in the order they occur in +;; this file. This is essential, because the code generated here +;; is only valid for the case where the divisor is >= 0x80000000, +;; so dividend/divisor can only be 0 or 1 depending on which +;; is bigger, dividend or divisor. This means that the remainder +;; can be calculated without a division +;; +;; If divisor is bigger, then quotient is 0, so remainder is +;; +;; dividend - (divisor * quotient) +;; = dividend - (divisor * 0) +;; = dividend +;; +;; If dividend is bigger, then quotient is 1, so remainder is +;; +;; dividend - (divisor * quotient) +;; = dividend - (divisor * 1) +;; = dividend - divisor +(define_insn "umodsi3_compare" + [(set (match_operand:SI 0 "general_operand" "=ro") + (umod:SI (match_operand:SI 1 "general_operand" "ro") + (match_operand:SI 2 "general_operand" "g")))] + "" + "subl3 %2, %1, %0\;bcc .LB%=\;movl %1, %0\;.LB%=:") + ;; Bit-and on the VAX is done with a clear-bits insn. (define_expand "andsi3" diff -Nur orig/gcc-20030127/gcc/config/vax/vax.md~ x/vax.md~ --- orig/gcc-20030127/gcc/config/vax/vax.md~ 1970-01-01 10:00:00.000000000 +1000 +++ x/vax.md~ 2003-06-15 11:36:40.000000000 +1000 @@ -0,0 +1,2484 @@ +;; Machine description for GNU compiler, VAX Version +;; Copyright (C) 1987, 1988, 1991, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +;; 2002 Free Software Foundation, Inc. + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + + +;;- Instruction patterns. When multiple patterns apply, +;;- the first one in the file is chosen. +;;- +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;;- +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;; UNSPEC_VOLATILE usage: + +(define_constants + [(VUNSPEC_BLOCKAGE 0) ; `blockage' insn to prevent scheduling across an + ; insn in the code. + (VUNSPEC_SYNC_ISTREAM 1) ; sequence of insns to sync the I-stream + ] +) + +;; 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. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "nonimmediate_operand" "g"))] + "" + "tstl %0") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "nonimmediate_operand" "g"))] + "" + "tstw %0") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "nonimmediate_operand" "g"))] + "" + "tstb %0") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" "gF"))] + "" + "tst%# %0") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" "gF"))] + "" + "tstf %0") + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "nonimmediate_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "cmpl %0,%1") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "cmpw %0,%1") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "cmpb %0,%1") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "gF,gF") + (match_operand:DF 1 "general_operand" "G,gF")))] + "" + "@ + tst%# %0 + cmp%# %0,%1") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "gF,gF") + (match_operand:SF 1 "general_operand" "G,gF")))] + "" + "@ + tstf %0 + cmpf %0,%1") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "bitl %0,%1") + +(define_insn "" + [(set (cc0) + (and:HI (match_operand:HI 0 "general_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "bitw %0,%1") + +(define_insn "" + [(set (cc0) + (and:QI (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "bitb %0,%1") + +;; The VAX has no sCOND insns. It does have add/subtract with carry +;; which could be used to implement the sltu and sgeu patterns. However, +;; to do this properly requires a complete rewrite of the compare insns +;; to keep them together with the sltu/sgeu insns until after the +;; reload pass is complete. The previous implementation didn't do this +;; and has been deleted. +(define_insn "sltu" + [(set (match_operand:SI 0 "general_operand" "=ro,<>") + (ltu (cc0) (const_int 0)))] + "" + "@ + clrl %0\;adwc $0,%0 + blssu .LB%=1f\;clrl %0\;brb .LB%=2f\;.LB%=1f: movl $1, %0\;.LB%=2f:") + +(define_insn "sgeu" + [(set (match_operand:SI 0 "general_operand" "=ro,<>") + (geu (cc0) (const_int 0)))] + "" + "@ + movl $1,%0\;sbwc $0,%0 + bgequ .LB%=1f\;clrl %0\;brb .LB%=2f\;.LB%=1f: movl $1, %0\;.LB%=2f:") + + +(define_insn "sleu" + [(set (match_operand:SI 0 "general_operand" "=g") + (leu (cc0) (const_int 0)))] + "" + "blequ .LB%=1f\;clrl %0\;brb .LB%=2f\;.LB%=1f: movl $1, %0\;.LB%=2f:") + + + +(define_insn "movdf" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g") + (match_operand:DF 1 "general_operand" "G,gF"))] + "" + "@ + clr%# %0 + mov%# %1,%0") + +(define_insn "movsf" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g") + (match_operand:SF 1 "general_operand" "G,gF"))] + "" + "@ + clrf %0 + movf %1,%0") + +;; Some VAXen don't support this instruction. +;;(define_insn "movti" +;; [(set (match_operand:TI 0 "general_operand" "=g") +;; (match_operand:TI 1 "general_operand" "g"))] +;; "" +;; "movh %1,%0") + +(define_insn "movdi" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g,g") + (match_operand:DI 1 "general_operand" "I,g"))] + "" + "@ + clrq %0 + movq %D1,%0") + +;; The VAX move instructions have space-time tradeoffs. On a MicroVAX +;; register-register mov instructions take 3 bytes and 2 CPU cycles. clrl +;; takes 2 bytes and 3 cycles. mov from constant to register takes 2 cycles +;; if the constant is smaller than 4 bytes, 3 cycles for a longword +;; constant. movz, mneg, and mcom are as fast as mov, so movzwl is faster +;; than movl for positive constants that fit in 16 bits but not 6 bits. cvt +;; instructions take 4 cycles. inc takes 3 cycles. The machine description +;; is willing to trade 1 byte for 1 cycle (clrl instead of movl $0; cvtwl +;; instead of movl). + +;; Cycle counts for other models may vary (on a VAX 750 they are similar, +;; but on a VAX 9000 most move and add instructions with one constant +;; operand take 1 cycle). + +;; Loads of constants between 64 and 128 used to be done with +;; "addl3 $63,#,dst" but this is slower than movzbl and takes as much space. + +(define_insn "movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:SI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const1_rtx && reg_was_0_p (insn, operands[0])) + return \"incl %0\"; + + if (GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST) + { + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + return \"movab %a1,%0\"; + } + if (operands[1] == const0_rtx) + return \"clrl %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) >= 64) + { + int i = INTVAL (operands[1]); + if ((unsigned)(~i) < 64) + return \"mcoml %N1,%0\"; + if ((unsigned)i < 0x100) + return \"movzbl %1,%0\"; + if (i >= -0x80 && i < 0) + return \"cvtbl %1,%0\"; + if ((unsigned)i < 0x10000) + return \"movzwl %1,%0\"; + if (i >= -0x8000 && i < 0) + return \"cvtwl %1,%0\"; + } + if (push_operand (operands[0], SImode)) + return \"pushl %1\"; + return \"movl %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const1_rtx && reg_was_0_p (insn, operands[0])) + return \"incw %0\"; + + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i == 0) + return \"clrw %0\"; + else if ((unsigned int)i < 64) + return \"movw %1,%0\"; + else if ((unsigned int)~i < 64) + return \"mcomw %H1,%0\"; + else if ((unsigned int)i < 256) + return \"movzbw %1,%0\"; + } + return \"movw %1,%0\"; +}") + +(define_insn "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+g")) + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i == 0) + return \"clrw %0\"; + else if ((unsigned int)i < 64) + return \"movw %1,%0\"; + else if ((unsigned int)~i < 64) + return \"mcomw %H1,%0\"; + else if ((unsigned int)i < 256) + return \"movzbw %1,%0\"; + } + return \"movw %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const1_rtx && reg_was_0_p (insn, operands[0])) + return \"incb %0\"; + + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i == 0) + return \"clrb %0\"; + else if ((unsigned int)~i < 64) + return \"mcomb %B1,%0\"; + } + return \"movb %1,%0\"; +}") + +(define_insn "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+g")) + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i == 0) + return \"clrb %0\"; + else if ((unsigned int)~i < 64) + return \"mcomb %B1,%0\"; + } + return \"movb %1,%0\"; +}") + +;; This is here to accept 4 arguments and pass the first 3 along +;; to the movstrhi1 pattern that really does the work. +(define_expand "movstrhi" + [(set (match_operand:BLK 0 "general_operand" "=g") + (match_operand:BLK 1 "general_operand" "g")) + (use (match_operand:HI 2 "general_operand" "g")) + (match_operand 3 "" "")] + "" + " + emit_insn (gen_movstrhi1 (operands[0], operands[1], operands[2])); + DONE; +") + +;; 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 "movstrhi1" + [(set (match_operand:BLK 0 "memory_operand" "=m") + (match_operand:BLK 1 "memory_operand" "m")) + (use (match_operand:HI 2 "general_operand" "g")) + (clobber (reg:SI 0)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3)) + (clobber (reg:SI 4)) + (clobber (reg:SI 5))] + "" + "movc3 %2,%1,%0") + +;; Extension and truncation insns. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "g")))] + "" + "cvtlb %1,%0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "g")))] + "" + "cvtlw %1,%0") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (truncate:QI (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "cvtwb %1,%0") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "cvtwl %1,%0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "cvtbw %1,%0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "cvtbl %1,%0") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (float_extend:DF (match_operand:SF 1 "general_operand" "gF")))] + "" + "cvtf%# %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (float_truncate:SF (match_operand:DF 1 "general_operand" "gF")))] + "" + "cvt%#f %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "movzwl %1,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "movzbw %1,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "movzbl %1,%0") + +;; Fix-to-float conversion insns. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "g")))] + "" + "cvtlf %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (float:DF (match_operand:SI 1 "nonimmediate_operand" "g")))] + "" + "cvtl%# %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (float:SF (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "cvtwf %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (float:DF (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "cvtw%# %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (float:SF (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "cvtbf %1,%0") + +(define_insn "floatqidf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (float:DF (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "cvtb%# %1,%0") + +;; Float-to-fix conversion insns. + +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (fix:QI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfb %1,%0") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (fix:HI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfw %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfl %1,%0") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#b %1,%0") + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#w %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#l %1,%0") + +;;- All kinds of add instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g,g") + (plus:DF (match_operand:DF 1 "general_operand" "0,gF,gF") + (match_operand:DF 2 "general_operand" "gF,0,gF")))] + "" + "@ + add%#2 %2,%0 + add%#2 %1,%0 + add%#3 %1,%2,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g,g") + (plus:SF (match_operand:SF 1 "general_operand" "0,gF,gF") + (match_operand:SF 2 "general_operand" "gF,0,gF")))] + "" + "@ + addf2 %2,%0 + addf2 %1,%0 + addf3 %1,%2,%0") + +/* The space-time-opcode tradeoffs for addition vary by model of VAX. + + On a VAX 3 "movab (r1)[r2],r3" is faster than "addl3 r1,r2,r3", + but it not faster on other models. + + "movab #(r1),r2" is usually shorter than "addl3 #,r1,r2", and is + faster on a VAX 3, but some VAXen (e.g. VAX 9000) will stall if + a register is used in an address too soon after it is set. + Compromise by using movab only when it is shorter than the add + or the base register in the address is one of sp, ap, and fp, + which are not modified very often. */ + + +(define_insn "addsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (plus:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incl %0\"; + if (operands[2] == constm1_rtx) + return \"decl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl2 $%n2,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) INTVAL (operands[2]) >= 64 + && GET_CODE (operands[1]) == REG + && ((INTVAL (operands[2]) < 32767 && INTVAL (operands[2]) > -32768) + || REGNO (operands[1]) > 11)) + return \"movab %c2(%1),%0\"; + return \"addl2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addl2 %1,%0\"; + + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 32767 + && INTVAL (operands[2]) > -32768 + && GET_CODE (operands[1]) == REG + && push_operand (operands[0], SImode)) + return \"pushab %c2(%1)\"; + + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl3 $%n2,%1,%0\"; + + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) INTVAL (operands[2]) >= 64 + && GET_CODE (operands[1]) == REG + && ((INTVAL (operands[2]) < 32767 && INTVAL (operands[2]) > -32768) + || REGNO (operands[1]) > 11)) + return \"movab %c2(%1),%0\"; + + /* Add this if using gcc on a VAX 3xxx: + if (REG_P (operands[1]) && REG_P (operands[2])) + return \"movab (%1)[%2],%0\"; + */ + return \"addl3 %1,%2,%0\"; +}") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (plus:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incw %0\"; + if (operands[2] == constm1_rtx) + return \"decw %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw2 $%n2,%0\"; + return \"addw2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addw2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw3 $%n2,%1,%0\"; + return \"addw3 %1,%2,%0\"; +}") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (plus:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incb %0\"; + if (operands[2] == constm1_rtx) + return \"decb %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb2 $%n2,%0\"; + return \"addb2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addb2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb3 $%n2,%1,%0\"; + return \"addb3 %1,%2,%0\"; +}") + +;; The add-with-carry (adwc) instruction only accepts two operands. +(define_insn "adddi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=ro>,ro>") + (plus:DI (match_operand:DI 1 "general_operand" "%0,ro>") + (match_operand:DI 2 "general_operand" "Fro,F")))] + "" + "* +{ + rtx low[3]; + const char *pattern; + int carry = 1; + + split_quadword_operands (operands, low, 3); + /* Add low parts. */ + if (rtx_equal_p (operands[0], operands[1])) + { + if (low[2] == const0_rtx) + /* Should examine operand, punt if not POST_INC. */ + pattern = \"tstl %0\", carry = 0; + else if (low[2] == const1_rtx) + pattern = \"incl %0\"; + else + pattern = \"addl2 %2,%0\"; + } + else + { + if (low[2] == const0_rtx) + pattern = \"movl %1,%0\", carry = 0; + else + pattern = \"addl3 %2,%1,%0\"; + } + if (pattern) + output_asm_insn (pattern, low); + if (!carry) + /* If CARRY is 0, we don't have any carry value to worry about. */ + return get_insn_template (CODE_FOR_addsi3, insn); + /* %0 = C + %1 + %2 */ + if (!rtx_equal_p (operands[0], operands[1])) + output_asm_insn ((operands[1] == const0_rtx + ? \"clrl %0\" + : \"movl %1,%0\"), operands); + return \"adwc %2,%0\"; +}") + +;;- All kinds of subtract instructions. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g") + (minus:DF (match_operand:DF 1 "general_operand" "0,gF") + (match_operand:DF 2 "general_operand" "gF,gF")))] + "" + "@ + sub%#2 %2,%0 + sub%#3 %2,%1,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g") + (minus:SF (match_operand:SF 1 "general_operand" "0,gF") + (match_operand:SF 2 "general_operand" "gF,gF")))] + "" + "@ + subf2 %2,%0 + subf3 %2,%1,%0") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g") + (minus:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "general_operand" "g,g")))] + "" + "@ + subl2 %2,%0 + subl3 %2,%1,%0") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g") + (minus:HI (match_operand:HI 1 "general_operand" "0,g") + (match_operand:HI 2 "general_operand" "g,g")))] + "" + "@ + subw2 %2,%0 + subw3 %2,%1,%0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g") + (minus:QI (match_operand:QI 1 "general_operand" "0,g") + (match_operand:QI 2 "general_operand" "g,g")))] + "" + "@ + subb2 %2,%0 + subb3 %2,%1,%0") + +;; The subtract-with-carry (sbwc) instruction only takes two operands. +(define_insn "subdi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=or>,or>") + (minus:DI (match_operand:DI 1 "general_operand" "0,or>") + (match_operand:DI 2 "general_operand" "For,F")))] + "" + "* +{ + rtx low[3]; + const char *pattern; + int carry = 1; + + split_quadword_operands (operands, low, 3); + /* Subtract low parts. */ + if (rtx_equal_p (operands[0], operands[1])) + { + if (low[2] == const0_rtx) + pattern = 0, carry = 0; + else if (low[2] == constm1_rtx) + pattern = \"decl %0\"; + else + pattern = \"subl2 %2,%0\"; + } + else + { + if (low[2] == constm1_rtx) + pattern = \"decl %0\"; + else if (low[2] == const0_rtx) + pattern = get_insn_template (CODE_FOR_movsi, insn), carry = 0; + else + pattern = \"subl3 %2,%1,%0\"; + } + if (pattern) + output_asm_insn (pattern, low); + if (carry) + { + if (!rtx_equal_p (operands[0], operands[1])) + return \"movl %1,%0\;sbwc %2,%0\"; + return \"sbwc %2,%0\"; + /* %0 = %2 - %1 - C */ + } + return get_insn_template (CODE_FOR_subsi3, insn); +}") + +;;- Multiply instructions. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g,g") + (mult:DF (match_operand:DF 1 "general_operand" "0,gF,gF") + (match_operand:DF 2 "general_operand" "gF,0,gF")))] + "" + "@ + mul%#2 %2,%0 + mul%#2 %1,%0 + mul%#3 %1,%2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g,g") + (mult:SF (match_operand:SF 1 "general_operand" "0,gF,gF") + (match_operand:SF 2 "general_operand" "gF,0,gF")))] + "" + "@ + mulf2 %2,%0 + mulf2 %1,%0 + mulf3 %1,%2,%0") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g,g") + (mult:SI (match_operand:SI 1 "general_operand" "0,g,g") + (match_operand:SI 2 "general_operand" "g,0,g")))] + "" + "@ + mull2 %2,%0 + mull2 %1,%0 + mull3 %1,%2,%0") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g,") + (mult:HI (match_operand:HI 1 "general_operand" "0,g,g") + (match_operand:HI 2 "general_operand" "g,0,g")))] + "" + "@ + mulw2 %2,%0 + mulw2 %1,%0 + mulw3 %1,%2,%0") + +(define_insn "mulqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g,g") + (mult:QI (match_operand:QI 1 "general_operand" "0,g,g") + (match_operand:QI 2 "general_operand" "g,0,g")))] + "" + "@ + mulb2 %2,%0 + mulb2 %1,%0 + mulb3 %1,%2,%0") + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (mult:DI (sign_extend:DI + (match_operand:SI 1 "nonimmediate_operand" "g")) + (sign_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "g"))))] + "" + "emul %1,%2,$0,%0") + +(define_insn "" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (plus:DI + (mult:DI (sign_extend:DI + (match_operand:SI 1 "nonimmediate_operand" "g")) + (sign_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "g"))) + (sign_extend:DI (match_operand:SI 3 "nonimmediate_operand" "g"))))] + "" + "emul %1,%2,%3,%0") + +;; 'F' constraint means type CONST_DOUBLE +(define_insn "" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (plus:DI + (mult:DI (sign_extend:DI + (match_operand:SI 1 "nonimmediate_operand" "g")) + (sign_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "g"))) + (match_operand:DI 3 "immediate_operand" "F")))] + "GET_CODE (operands[3]) == CONST_DOUBLE + && CONST_DOUBLE_HIGH (operands[3]) == (CONST_DOUBLE_LOW (operands[3]) >> 31)" + "* +{ + if (CONST_DOUBLE_HIGH (operands[3])) + operands[3] = GEN_INT (CONST_DOUBLE_LOW (operands[3])); + return \"emul %1,%2,%3,%0\"; +}") + +;;- Divide instructions. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g") + (div:DF (match_operand:DF 1 "general_operand" "0,gF") + (match_operand:DF 2 "general_operand" "gF,gF")))] + "" + "@ + div%#2 %2,%0 + div%#3 %2,%1,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g") + (div:SF (match_operand:SF 1 "general_operand" "0,gF") + (match_operand:SF 2 "general_operand" "gF,gF")))] + "" + "@ + divf2 %2,%0 + divf3 %2,%1,%0") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g") + (div:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "general_operand" "g,g")))] + "" + "@ + divl2 %2,%0 + divl3 %2,%1,%0") + +(define_insn "divhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g") + (div:HI (match_operand:HI 1 "general_operand" "0,g") + (match_operand:HI 2 "general_operand" "g,g")))] + "" + "@ + divw2 %2,%0 + divw3 %2,%1,%0") + +(define_insn "divqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g") + (div:QI (match_operand:QI 1 "general_operand" "0,g") + (match_operand:QI 2 "general_operand" "g,g")))] + "" + "@ + divb2 %2,%0 + divb3 %2,%1,%0") + +;This is left out because it is very slow; +;we are better off programming around the "lack" of this insn. +;(define_insn "divmoddisi4" +; [(set (match_operand:SI 0 "general_operand" "=g") +; (div:SI (match_operand:DI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g"))) +; (set (match_operand:SI 3 "general_operand" "=g") +; (mod:SI (match_operand:DI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g")))] +; "" +; "ediv %2,%1,%0,%3") + +(define_insn "ediv_helper" + [(set (match_operand:SI 2 "general_operand" "=g") + (div:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:DI 1 "general_operand" "g"))) + (set (match_operand:SI 3 "general_operand" "=g") + (mod:SI (match_dup 0) + (match_dup 1)))] + "" + "ediv %0,%1,%2,%3") + + +(define_expand "udivsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (udiv:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + rtx remainder = gen_reg_rtx(SImode); + rtx dividend_di = gen_reg_rtx(DImode); + rtx dividend = gen_rtx(SUBREG, SImode, dividend_di, 0); + rtx dividend_hi = gen_rtx(SUBREG, SImode, dividend_di, 1); + + rtx label_easy = gen_label_rtx(); + rtx label_ediv = gen_label_rtx(); + rtx label_end = gen_label_rtx(); + + /* we have to deal with the case where one of the operands is + a constant, because otherwise invalid RTXs will be generated. + Both operands can never be constant, because constant + folding will already have eliminated then. */ + + if (GET_CODE (operands[2]) == CONST_INT) { + + /* Divisor is constant */ + + if (INTVAL (operands[2]) > 0) { + + /* Divisor <= 0x7fffffff. If dividend is also <= 0x7fffffff, + then signed division is OK, otherwise need to do extended + (64-bit) division */ + + emit_insn(gen_tstsi(operands[1])); + emit_jump_insn(gen_blt(label_ediv)); + + emit_insn(gen_divsi3(operands[0], operands[1], operands[2])); + emit_jump_insn(gen_jump(label_end)); + + } else { + + /* divisor is >= 0x80000000, so quotient can only be 1 or 0 + depending on which is bigger, dividend or divisor, + respectively */ + + emit_insn(gen_cmpsi(operands[1], operands[2])); + emit_insn(gen_sgeu(operands[0])); + + } + } else if (GET_CODE (operands[1]) == CONST_INT) { + + /* Dividend is constant, divisor is variable */ + if (INTVAL (operands[1]) > 0) { + + /* Dividend <= 0x7fffffff. If divisor is also <= 0x7fffffff, + then signed division is OK, otherwise quotient must be 0 */ + + emit_move_insn(operands[0], const0_rtx); + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_blt(label_end)); + + emit_insn(gen_divsi3(operands[0], operands[1], operands[2])); + + } else { + + /* Is divisor <= 0x7fffffff ? (i.e. high bit clear, so looks positive) */ + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_bge(label_ediv)); + + /* divisor is >= 0x80000000, so quotient can only be 1 or 0 + depending on which is bigger, dividend or divisor, + respectively */ + emit_insn(gen_cmpsi(operands[2], operands[1])); + emit_insn(gen_sleu(operands[0])); + } + } else { + + /* Is divisor >= 0x80000000 ? (i.e. high bit set, so looks negative) */ + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_blt(label_easy)); + + emit_insn(gen_tstsi(operands[1])); + emit_jump_insn(gen_blt(label_ediv)); + + /* Both <= 0x7fffffff - signed division OK */ + emit_insn(gen_divsi3(operands[0], operands[1], operands[2])); + emit_jump_insn(gen_jump(label_end)); + + emit_label(label_easy); + + /* divisor is >= 0x80000000, so quotient can only be 1 or 0 + depending on which is bigger, dividend or divisor, + respectively */ + + emit_insn(gen_cmpsi(operands[1], operands[2])); + emit_insn(gen_sgeu(operands[0])); + + } + + emit_jump_insn(gen_jump(label_end)); + + emit_label(label_ediv); + /* Dividend is >= 0x80000000 and divisor <= 0x7fffffff, + so we'll use the EDIV instruction instead (EDIV divides + a quadword by a longword, or a DImode by an SImode in + RTL-speak, and produces both quotient and remainder) */ + + emit_move_insn(dividend, operands[1]); + emit_move_insn(dividend_hi, const0_rtx); + + emit_insn(gen_ediv_helper(operands[2], dividend_di, operands[0], remainder)); + + emit_label(label_end); + + DONE; +} +") + +(define_expand "umodsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (umod:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + rtx quotient = gen_reg_rtx(SImode); + rtx dividend_di = gen_reg_rtx(DImode); + rtx dividend = gen_rtx(SUBREG, SImode, dividend_di, 0); + rtx dividend_hi = gen_rtx(SUBREG, SImode, dividend_di, 1); + + rtx label_signed_mod = gen_label_rtx(); + rtx label_compare = gen_label_rtx(); + rtx label_ediv = gen_label_rtx(); + rtx label_end = gen_label_rtx(); + + int emit_signed_mod_code = 0; + int emit_compare_code = 0; + int emit_ediv_code = 0; + + /* we have to deal with the case where one of the operands is + a constant, because otherwise invalid RTXs will be generated. + Both operands can never be constant, because constant + folding will already have eliminated then. */ + + if (GET_CODE (operands[2]) == CONST_INT) { + + /* Divisor is constant */ + + if (INTVAL (operands[2]) > 0) { + + /* Divisor <= 0x7fffffff. If dividend is also <= 0x7fffffff, + then signed division is OK, otherwise need to do extended + (64-bit) division */ + + emit_insn(gen_tstsi(operands[1])); + emit_jump_insn(gen_bge(label_signed_mod)); + emit_jump_insn(gen_jump(label_ediv)); + + emit_signed_mod_code = 1; + emit_ediv_code = 1; + + } else { + + /* divisor is >= 0x80000000, calculate by comparison */ + emit_jump_insn(gen_jump(label_compare)); + + emit_compare_code = 1; + } + + } else if (GET_CODE (operands[1]) == CONST_INT) { + + /* I don't know why, but GCC never seems to end up here */ + + /* Dividend is constant, divisor is variable */ + if (INTVAL (operands[1]) > 0) { + + /* Dividend <= 0x7fffffff. If divisor is also <= 0x7fffffff, + then signed modulus is OK, otherwise do 64-bit division */ + + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_bge(label_signed_mod)); + emit_jump_insn(gen_jump(label_ediv)); + + emit_signed_mod_code = 1; + emit_ediv_code = 1; + + } else { + + /* Dividend >= 0x80000000. If divisor is also >= 0x80000000, + then do mod-by-comparison, otherwise do 64-bit division */ + + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_blt(label_compare)); + emit_jump_insn(gen_jump(label_ediv)); + + emit_compare_code = 1; + emit_ediv_code = 1; + } + } else { + + /* Is divisor >= 0x80000000 ? (i.e. high bit set, so looks negative) */ + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_blt(label_compare)); + + /* Is dividend >= 0x80000000 ? (i.e. high bit set, so looks negative) */ + emit_insn(gen_tstsi(operands[1])); + emit_jump_insn(gen_blt(label_ediv)); + + /* Both <= 0x7fffffff - signed modulus OK */ + emit_jump_insn(gen_jump(label_signed_mod)); + + emit_ediv_code = 1; + emit_compare_code = 1; + emit_signed_mod_code = 1; + } + + if (emit_signed_mod_code) { + emit_label(label_signed_mod); + + /* Both <= 0x7fffffff - signed modulus OK */ + emit_insn(gen_divsi3(quotient, operands[1], operands[2])); + emit_insn(gen_mulsi3(quotient, quotient, operands[2])); + emit_insn(gen_subsi3(operands[0], operands[1], quotient)); + emit_jump_insn(gen_jump(label_end)); + + /* Emit code to use extended division instruction */ + } + + if (emit_ediv_code) { + emit_label(label_ediv); + + /* Dividend is >= 0x80000000 and divisor <= 0x7fffffff, + so we'll use the EDIV instruction instead (EDIV divides + a quadword by a longword, or a DImode by an SImode in + RTL-speak, and produces both quotient and remainder) */ + + emit_move_insn(dividend, operands[1]); + emit_move_insn(dividend_hi, const0_rtx); + + emit_insn(gen_ediv_helper(operands[2], dividend_di, quotient, operands[0])); + emit_jump_insn(gen_jump(label_end)); + } + + if (emit_compare_code) { + /* Emit code to to mod-by-comparison. */ + emit_label(label_compare); + emit_insn(gen_umodsi3_compare(operands[0], operands[1], operands[2])); + } + + emit_label(label_end); + + DONE; +} +") + +;; This is used by the umodsi3 define_expand above. It will never +;; be matched by GCC because it is more specific than the umodsi3 +;; definition, and GCC matches insns in the order they occur in +;; this file. This is essential, because the code generated here +;; is only valid for the case where the divisor is >= 0x80000000, +;; so dividend/divisor can only be 0 or 1 depending on which +;; is bigger, dividend or divisor. This means that the remainder +;; can be calculated without a division +;; +;; If divisor is bigger, then quotient is 0, so remainder is +;; +;; dividend - (divisor * quotient) +;; = dividend - (divisor * 0) +;; = dividend +;; +;; If dividend is bigger, then quotient is 1, so remainder is +;; +;; dividend - (divisor * quotient) +;; = dividend - (divisor * 1) +;; = dividend - divisor +(define_insn "umodsi3_compare" + [(set (match_operand:SI 0 "general_operand" "=ro") + (umod:SI (match_operand:SI 1 "general_operand" "ro") + (match_operand:SI 2 "general_operand" "g")))] + "" + "subl3 %2, %1, %0\;bcc .LB%=\;movl %1, %0\;.LB%=:") + + +;; Bit-and on the VAX is done with a clear-bits insn. +(define_expand "andsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (and:SI (not:SI (match_operand:SI 1 "general_operand" "")) + (match_operand:SI 2 "general_operand" "")))] + "" + " +{ + rtx op1 = operands[1]; + + /* If there is a constant argument, complement that one. */ + if (GET_CODE (operands[2]) == CONST_INT && GET_CODE (op1) != CONST_INT) + { + operands[1] = operands[2]; + operands[2] = op1; + op1 = operands[1]; + } + + if (GET_CODE (op1) == CONST_INT) + operands[1] = GEN_INT (~INTVAL (op1)); + else + operands[1] = expand_unop (SImode, one_cmpl_optab, op1, 0, 1); +}") + +(define_expand "andhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (and:HI (not:HI (match_operand:HI 1 "general_operand" "")) + (match_operand:HI 2 "general_operand" "")))] + "" + " +{ + rtx op1 = operands[1]; + + if (GET_CODE (operands[2]) == CONST_INT && GET_CODE (op1) != CONST_INT) + { + operands[1] = operands[2]; + operands[2] = op1; + op1 = operands[1]; + } + + if (GET_CODE (op1) == CONST_INT) + operands[1] = GEN_INT (~INTVAL (op1)); + else + operands[1] = expand_unop (HImode, one_cmpl_optab, op1, 0, 1); +}") + +(define_expand "andqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (and:QI (not:QI (match_operand:QI 1 "general_operand" "")) + (match_operand:QI 2 "general_operand" "")))] + "" + " +{ + rtx op1 = operands[1]; + + if (GET_CODE (operands[2]) == CONST_INT && GET_CODE (op1) != CONST_INT) + { + operands[1] = operands[2]; + operands[2] = op1; + op1 = operands[1]; + } + + if (GET_CODE (op1) == CONST_INT) + operands[1] = GEN_INT (~INTVAL (op1)); + else + operands[1] = expand_unop (QImode, one_cmpl_optab, op1, 0, 1); +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g") + (and:SI (not:SI (match_operand:SI 1 "general_operand" "g,g")) + (match_operand:SI 2 "general_operand" "0,g")))] + "" + "@ + bicl2 %1,%0 + bicl3 %1,%2,%0") + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g") + (and:HI (not:HI (match_operand:HI 1 "general_operand" "g,g")) + (match_operand:HI 2 "general_operand" "0,g")))] + "" + "@ + bicw2 %1,%0 + bicw3 %1,%2,%0") + +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g") + (and:QI (not:QI (match_operand:QI 1 "general_operand" "g,g")) + (match_operand:QI 2 "general_operand" "0,g")))] + "" + "@ + bicb2 %1,%0 + bicb3 %1,%2,%0") + +;; The following used to be needed because constant propagation can +;; create them starting from the bic insn patterns above. This is no +;; longer a problem. However, having these patterns allows optimization +;; opportunities in combine.c. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g") + (and:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "const_int_operand" "n,n")))] + "" + "@ + bicl2 %N2,%0 + bicl3 %N2,%1,%0") + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g") + (and:HI (match_operand:HI 1 "general_operand" "0,g") + (match_operand:HI 2 "const_int_operand" "n,n")))] + "" + "@ + bicw2 %H2,%0 + bicw3 %H2,%1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g") + (and:QI (match_operand:QI 1 "general_operand" "0,g") + (match_operand:QI 2 "const_int_operand" "n,n")))] + "" + "@ + bicb2 %B2,%0 + bicb3 %B2,%1,%0") + +;;- Bit set instructions. + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g,g") + (ior:SI (match_operand:SI 1 "general_operand" "0,g,g") + (match_operand:SI 2 "general_operand" "g,0,g")))] + "" + "@ + bisl2 %2,%0 + bisl2 %1,%0 + bisl3 %2,%1,%0") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g,g") + (ior:HI (match_operand:HI 1 "general_operand" "0,g,g") + (match_operand:HI 2 "general_operand" "g,0,g")))] + "" + "@ + bisw2 %2,%0 + bisw2 %1,%0 + bisw3 %2,%1,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g,g") + (ior:QI (match_operand:QI 1 "general_operand" "0,g,g") + (match_operand:QI 2 "general_operand" "g,0,g")))] + "" + "@ + bisb2 %2,%0 + bisb2 %1,%0 + bisb3 %2,%1,%0") + +;;- xor instructions. + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g,g") + (xor:SI (match_operand:SI 1 "general_operand" "0,g,g") + (match_operand:SI 2 "general_operand" "g,0,g")))] + "" + "@ + xorl2 %2,%0 + xorl2 %1,%0 + xorl3 %2,%1,%0") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g,g") + (xor:HI (match_operand:HI 1 "general_operand" "0,g,g") + (match_operand:HI 2 "general_operand" "g,0,g")))] + "" + "@ + xorw2 %2,%0 + xorw2 %1,%0 + xorw3 %2,%1,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g,g") + (xor:QI (match_operand:QI 1 "general_operand" "0,g,g") + (match_operand:QI 2 "general_operand" "g,0,g")))] + "" + "@ + xorb2 %2,%0 + xorb2 %1,%0 + xorb3 %2,%1,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (neg:DF (match_operand:DF 1 "general_operand" "gF")))] + "" + "mneg%# %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (neg:SF (match_operand:SF 1 "general_operand" "gF")))] + "" + "mnegf %1,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (neg:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mnegl %1,%0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (neg:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mnegw %1,%0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (neg:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mnegb %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (not:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mcoml %1,%0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (not:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mcomw %1,%0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (not:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mcomb %1,%0") + +;; Arithmetic right shift on the VAX works by negating the shift count, +;; then emitting a right shift with the shift count negated. This means +;; that all actual shift counts in the RTL will be positive. This +;; prevents converting shifts to ZERO_EXTRACTs with negative positions, +;; which isn't valid. +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2])); +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "const_int_operand" "n")))] + "" + "ashl $%n2,%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (neg:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "ashl %2,%1,%0") + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (operands[2] == const1_rtx && rtx_equal_p (operands[0], operands[1])) + return \"addl2 %0,%0\"; + if (GET_CODE (operands[1]) == REG + && GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if (i == 1) + return \"addl3 %1,%1,%0\"; + if (i == 2) + return \"moval 0[%1],%0\"; + if (i == 3) + return \"movad 0[%1],%0\"; + } + return \"ashl %2,%1,%0\"; +}") + +;; Arithmetic right shift on the VAX works by negating the shift count. +(define_expand "ashrdi3" + [(set (match_operand:DI 0 "general_operand" "=g") + (ashiftrt:DI (match_operand:DI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2])); +}") + +(define_insn "ashldi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (ashift:DI (match_operand:DI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "ashq %2,%1,%0") + +(define_insn "" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (ashiftrt:DI (match_operand:DI 1 "general_operand" "g") + (neg:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "ashq %2,%1,%0") + +;; We used to have expand_shift handle logical right shifts by using extzv, +;; but this make it very difficult to do lshrdi3. Since the VAX is the +;; only machine with this kludge, it's better to just do this with a +;; define_expand and remove that case from expand_shift. + +(define_expand "lshrsi3" + [(set (match_dup 3) + (minus:QI (const_int 32) + (match_dup 4))) + (set (match_operand:SI 0 "general_operand" "=g") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r") + (match_dup 3) + (match_operand:SI 2 "register_operand" "g")))] + "" + " +{ + operands[3] = gen_reg_rtx (QImode); + operands[4] = gen_lowpart (QImode, operands[2]); +}") + +;; Rotate right on the VAX works by negating the shift count. +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotatert:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2])); +}") + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (rotate:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "rotl %2,%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (rotatert:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "const_int_operand" "n")))] + "" + "rotl %R2,%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (rotatert:SI (match_operand:SI 1 "general_operand" "g") + (neg:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "rotl %2,%1,%0") + +;This insn is probably slower than a multiply and an add. +;(define_insn "" +; [(set (match_operand:SI 0 "general_operand" "=g") +; (mult:SI (plus:SI (match_operand:SI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g")) +; (match_operand:SI 3 "general_operand" "g")))] +; "" +; "index %1,$0x80000000,$0x7fffffff,%3,%2,%0") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+ro") + (match_operand:QI 1 "const_int_operand" "n") + (match_operand:SI 2 "const_int_operand" "n")) + (match_operand:SI 3 "general_operand" "g"))] + "(INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0 + && (GET_CODE (operands[0]) == REG + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + if (REG_P (operands[0])) + { + if (INTVAL (operands[2]) != 0) + return \"insv %3,%2,%1,%0\"; + } + else + operands[0] + = adjust_address (operands[0], + INTVAL (operands[1]) == 8 ? QImode : HImode, + INTVAL (operands[2]) / 8); + + CC_STATUS_INIT; + if (INTVAL (operands[1]) == 8) + return \"movb %3,%0\"; + return \"movw %3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=&g") + (zero_extract:SI (match_operand:SI 1 "register_operand" "ro") + (match_operand:QI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[3]) != 0) + return \"extzv %3,%2,%1,%0\"; + } + else + operands[1] + = adjust_address (operands[1], + INTVAL (operands[2]) == 8 ? QImode : HImode, + INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"movzbl %1,%0\"; + return \"movzwl %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extract:SI (match_operand:SI 1 "register_operand" "ro") + (match_operand:QI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[3]) != 0) + return \"extv %3,%2,%1,%0\"; + } + else + operands[1] + = adjust_address (operands[1], + INTVAL (operands[2]) == 8 ? QImode : HImode, + INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"cvtbl %1,%0\"; + return \"cvtwl %1,%0\"; +}") + +;; Register-only SImode cases of bit-field insns. + +(define_insn "" + [(set (cc0) + (compare + (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpv %2,%1,%0,%3") + +(define_insn "" + [(set (cc0) + (compare + (zero_extract:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpzv %2,%1,%0,%3") + +;; When the field position and size are constant and the destination +;; is a register, extv and extzv are much slower than a rotate followed +;; by a bicl or sign extension. Because we might end up choosing ext[z]v +;; anyway, we can't allow immediate values for the primary source operand. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extract:SI (match_operand:SI 1 "register_operand" "ro") + (match_operand:QI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[3]) != CONST_INT || GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[0]) != REG + || (INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16)) + return \"extv %3,%2,%1,%0\"; + if (INTVAL (operands[2]) == 8) + return \"rotl %R3,%1,%0\;cvtbl %0,%0\"; + return \"rotl %R3,%1,%0\;cvtwl %0,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (zero_extract:SI (match_operand:SI 1 "register_operand" "ro") + (match_operand:QI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[3]) != CONST_INT || GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[0]) != REG) + return \"extzv %3,%2,%1,%0\"; + if (INTVAL (operands[2]) == 8) + return \"rotl %R3,%1,%0\;movzbl %0,%0\"; + if (INTVAL (operands[2]) == 16) + return \"rotl %R3,%1,%0\;movzwl %0,%0\"; + if (INTVAL (operands[3]) & 31) + return \"rotl %R3,%1,%0\;bicl2 %M2,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"bicl2 %M2,%0\"; + return \"bicl3 %M2,%1,%0\"; +}") + +;; Non-register cases. +;; nonimmediate_operand is used to make sure that mode-ambiguous cases +;; don't match these (and therefore match the cases above instead). + +(define_insn "" + [(set (cc0) + (compare + (sign_extract:SI (match_operand:QI 0 "memory_operand" "m") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpv %2,%1,%0,%3") + +(define_insn "" + [(set (cc0) + (compare + (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "rm") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpzv %2,%1,%0,%3") + +(define_insn "extv" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extract:SI (match_operand:QI 1 "memory_operand" "m") + (match_operand:QI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[0]) != REG || GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[3]) != CONST_INT + || (INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16) + || INTVAL (operands[2]) + INTVAL (operands[3]) > 32 + || side_effects_p (operands[1]) + || (GET_CODE (operands[1]) == MEM + && mode_dependent_address_p (XEXP (operands[1], 0)))) + return \"extv %3,%2,%1,%0\"; + if (INTVAL (operands[2]) == 8) + return \"rotl %R3,%1,%0\;cvtbl %0,%0\"; + return \"rotl %R3,%1,%0\;cvtwl %0,%0\"; +}") + +(define_expand "extzv" + [(set (match_operand:SI 0 "general_operand" "") + (zero_extract:SI (match_operand:SI 1 "general_operand" "") + (match_operand:QI 2 "general_operand" "") + (match_operand:SI 3 "general_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (zero_extract:SI (match_operand:QI 1 "memory_operand" "m") + (match_operand:QI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[0]) != REG || GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[3]) != CONST_INT + || INTVAL (operands[2]) + INTVAL (operands[3]) > 32 + || side_effects_p (operands[1]) + || (GET_CODE (operands[1]) == MEM + && mode_dependent_address_p (XEXP (operands[1], 0)))) + return \"extzv %3,%2,%1,%0\"; + if (INTVAL (operands[2]) == 8) + return \"rotl %R3,%1,%0\;movzbl %0,%0\"; + if (INTVAL (operands[2]) == 16) + return \"rotl %R3,%1,%0\;movzwl %0,%0\"; + return \"rotl %R3,%1,%0\;bicl2 %M2,%0\"; +}") + +(define_expand "insv" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")) + (match_operand:SI 3 "general_operand" ""))] + "" + "") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+g") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g"))] + "" + "insv %3,%2,%1,%0") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g"))] + "" + "insv %3,%2,%1,%0") + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jbr %l0") + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jeql %l0") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jneq %l0") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtr %l0") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtru %l0") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlss %l0") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlssu %l0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgeq %l0") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgequ %l0") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jleq %l0") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlequ %l0") + +;; Recognize reversed jumps. +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(cc0) + (const_int 0)]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "j%C0 %l1") ; %C0 negates condition + +;; Recognize jbs, jlbs, jbc and jlbc instructions. Note that the operand +;; of jlbs and jlbc insns are SImode in the hardware. However, if it is +;; memory, we use QImode in the insn. So we can't use those instructions +;; for mode-dependent addresses. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q,g") + (const_int 1) + (match_operand:SI 1 "general_operand" "I,g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "@ + jlbs %0,%l2 + jbs %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q,g") + (const_int 1) + (match_operand:SI 1 "general_operand" "I,g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "@ + jlbc %0,%l2 + jbc %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r") + (const_int 1) + (match_operand:SI 1 "general_operand" "I,g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "@ + jlbs %0,%l2 + jbs %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r") + (const_int 1) + (match_operand:SI 1 "general_operand" "I,g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "@ + jlbc %0,%l2 + jbc %1,%0,%l2") + +;; Subtract-and-jump and Add-and-jump insns. +;; These are not used when output is for the Unix assembler +;; because it does not know how to modify them to reach far. + +;; Normal sob insns. + +(define_insn "" + [(set (pc) + (if_then_else + (gt (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgtr %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgeq %0,%l1") + +;; Normal aob insns. Define a version for when operands[1] is a constant. +(define_insn "" + [(set (pc) + (if_then_else + (lt (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaoblss %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (lt (match_operand:SI 0 "nonimmediate_operand" "+g") + (match_operand:SI 1 "general_operand" "g")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM && GET_CODE (operands[1]) == CONST_INT" + "jaoblss %P1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (le (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaobleq %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (le (match_operand:SI 0 "nonimmediate_operand" "+g") + (match_operand:SI 1 "general_operand" "g")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM && GET_CODE (operands[1]) == CONST_INT" + "jaobleq %P1,%0,%l2") + +;; Something like a sob insn, but compares against -1. +;; This finds `while (foo--)' which was changed to `while (--foo != -1)'. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "decl %0\;jgequ %l1") + +(define_expand "call_pop" + [(parallel [(call (match_operand:QI 0 "memory_operand" "") + (match_operand:SI 1 "const_int_operand" "")) + (set (reg:SI 14) + (plus:SI (reg:SI 14) + (match_operand:SI 3 "immediate_operand" "")))])] + "" +{ + if (INTVAL (operands[3]) > 255 * 4 || INTVAL (operands[3]) % 4) + abort (); + + /* Operand 1 is the number of bytes to be popped by DW_CFA_GNU_args_size + during EH unwinding. We must include the argument count pushed by + the calls instruction. */ + operands[1] = GEN_INT (INTVAL (operands[3]) + 4); +}) + +(define_insn "*call_pop" + [(call (match_operand:QI 0 "memory_operand" "m") + (match_operand:SI 1 "const_int_operand" "n")) + (set (reg:SI 14) (plus:SI (reg:SI 14) + (match_operand:SI 2 "immediate_operand" "i")))] + "" +{ + operands[1] = GEN_INT ((INTVAL (operands[1]) - 4) / 4); + return "calls %1,%0"; +}) + +(define_expand "call_value_pop" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "") + (match_operand:SI 2 "const_int_operand" ""))) + (set (reg:SI 14) + (plus:SI (reg:SI 14) + (match_operand:SI 4 "immediate_operand" "")))])] + "" +{ + if (INTVAL (operands[4]) > 255 * 4 || INTVAL (operands[4]) % 4) + abort (); + + /* Operand 2 is the number of bytes to be popped by DW_CFA_GNU_args_size + during EH unwinding. We must include the argument count pushed by + the calls instruction. */ + operands[2] = GEN_INT (INTVAL (operands[4]) + 4); +}) + +(define_insn "*call_value_pop" + [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "m") + (match_operand:SI 2 "const_int_operand" "n"))) + (set (reg:SI 14) (plus:SI (reg:SI 14) + (match_operand:SI 3 "immediate_operand" "i")))] + "" + "* +{ + operands[2] = GEN_INT ((INTVAL (operands[2]) - 4) / 4); + return \"calls %2,%1\"; +}") + +(define_expand "call" + [(call (match_operand:QI 0 "memory_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "" + " +{ + /* Operand 1 is the number of bytes to be popped by DW_CFA_GNU_args_size + during EH unwinding. We must include the argument count pushed by + the calls instruction. */ + operands[1] = GEN_INT (INTVAL (operands[1]) + 4); +}") + +(define_insn "*call" + [(call (match_operand:QI 0 "memory_operand" "m") + (match_operand:SI 1 "const_int_operand" ""))] + "" + "calls $0,%0") + +(define_expand "call_value" + [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "" + " +{ + /* Operand 2 is the number of bytes to be popped by DW_CFA_GNU_args_size + during EH unwinding. We must include the argument count pushed by + the calls instruction. */ + operands[2] = GEN_INT (INTVAL (operands[2]) + 4); +}") + +(define_insn "*call_value" + [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "m") + (match_operand:SI 2 "const_int_operand" "")))] + "" + "calls $0,%1") + +;; Call subroutine returning any type. + +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" + " +{ + int i; + + emit_call_insn (gen_call_pop (operands[0], const0_rtx, NULL, const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + + DONE; +}") + +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and +;; all of memory. This blocks insns from being moved across this point. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] VUNSPEC_BLOCKAGE)] + "" + "") + +(define_insn "return" + [(return)] + "" + "ret") + +(define_expand "epilogue" + [(return)] + "" + " +{ + emit_jump_insn (gen_return ()); + DONE; +}") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;; This had a wider constraint once, and it had trouble. +;; If you are tempted to try `g', please don't--it's not worth +;; the risk we will reopen the same bug. +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] + "" + "jmp (%0)") + +;; This is here to accept 5 arguments (as passed by expand_end_case) +;; and pass the first 4 along to the casesi1 pattern that really does the work. +(define_expand "casesi" + [(match_operand:SI 0 "general_operand" "") ; index + (match_operand:SI 1 "general_operand" "") ; lower + (match_operand:SI 2 "general_operand" "") ; upper-lower + (match_operand 3 "" "") ; table label + (match_operand 4 "" "")] ; default label + "" +{ + emit_jump_insn (gen_casesi1 (operands[0], operands[1], + operands[2], operands[3])); + DONE; +}) + +(define_insn "casesi1" + [(set (pc) + (if_then_else + (leu (minus:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (match_operand:SI 2 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (mult:SI (minus:SI (match_dup 0) + (match_dup 1)) + (const_int 2)) + (pc)))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,%1,%2") + +;; This can arise by simplification when operand 1 is a constant int. +(define_insn "" + [(set (pc) + (if_then_else + (leu (plus:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "const_int_operand" "n")) + (match_operand:SI 2 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (mult:SI (plus:SI (match_dup 0) + (match_dup 1)) + (const_int 2)) + (pc)))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "* +{ + operands[1] = GEN_INT (-INTVAL (operands[1])); + return \"casel %0,%1,%2\"; +}") + +;; This can arise by simplification when the base for the case insn is zero. +(define_insn "" + [(set (pc) + (if_then_else (leu (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (mult:SI (match_dup 0) + (const_int 2)) + (pc)))) + (label_ref:SI (match_operand 2 "" ""))) + (pc)))] + "" + "casel %0,$0,%1") + +;;- load or push effective address +;; These come after the move and add/sub patterns +;; because we don't want pushl $1 turned into pushad 1. +;; or addl3 r1,r2,r3 turned into movab 0(r1)[r2],r3. + +;; It does not work to use constraints to distinguish pushes from moves, +;; because < matches any autodecrement, not just a push. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + else + return \"movab %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:HI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaw %a1\"; + else + return \"movaw %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:SI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushal %a1\"; + else + return \"moval %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:DI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaq %a1\"; + else + return \"movaq %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:SF 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaf %a1\"; + else + return \"movaf %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:DF 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushad %a1\"; + else + return \"movad %a1,%0\"; +}") + +;; These used to be peepholes, but it is more straightforward to do them +;; as single insns. However, we must force the output to be a register +;; if it is not an offsettable address so that we know that we can assign +;; to it twice. + +;; If we had a good way of evaluating the relative costs, these could be +;; machine-independent. + +;; Optimize extzv ...,z; andl2 ...,z +;; or ashl ...,z; andl2 ...,z +;; with other operands constant. This is what the combiner converts the +;; above sequences to before attempting to recognize the new insn. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=ro") + (and:SI (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "const_int_operand" "n")) + (match_operand:SI 3 "const_int_operand" "n")))] + "(INTVAL (operands[3]) & ~((1 << (32 - INTVAL (operands[2]))) - 1)) == 0" + "* +{ + unsigned long mask1 = INTVAL (operands[3]); + unsigned long mask2 = (1 << (32 - INTVAL (operands[2]))) - 1; + + if ((mask1 & mask2) != mask1) + operands[3] = GEN_INT (mask1 & mask2); + + return \"rotl %R2,%1,%0\;bicl2 %N3,%0\"; +}") + +;; left-shift and mask +;; The only case where `ashl' is better is if the mask only turns off +;; bits that the ashl would anyways, in which case it should have been +;; optimized away. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=ro") + (and:SI (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "const_int_operand" "n")) + (match_operand:SI 3 "const_int_operand" "n")))] + "" + "* +{ + operands[3] + = GEN_INT (INTVAL (operands[3]) & ~((1 << INTVAL (operands[2])) - 1)); + return \"rotl %2,%1,%0\;bicl2 %N3,%0\"; +}") + +;; Instruction sequence to sync the VAX instruction stream. +(define_insn "sync_istream" + [(unspec_volatile [(const_int 0)] VUNSPEC_SYNC_ISTREAM)] + "" + "movpsl -(%|sp)\;pushal 1(%|pc)\;rei") diff -Nur orig/gcc-20030127/gcc/config/vax/vax.md.save x/vax.md.save --- orig/gcc-20030127/gcc/config/vax/vax.md.save 1970-01-01 10:00:00.000000000 +1000 +++ x/vax.md.save 2003-06-15 11:38:29.000000000 +1000 @@ -0,0 +1,2461 @@ +;; Machine description for GNU compiler, VAX Version +;; Copyright (C) 1987, 1988, 1991, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +;; 2002 Free Software Foundation, Inc. + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + + +;;- Instruction patterns. When multiple patterns apply, +;;- the first one in the file is chosen. +;;- +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;;- +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;; UNSPEC_VOLATILE usage: + +(define_constants + [(VUNSPEC_BLOCKAGE 0) ; `blockage' insn to prevent scheduling across an + ; insn in the code. + (VUNSPEC_SYNC_ISTREAM 1) ; sequence of insns to sync the I-stream + ] +) + +;; 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. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "nonimmediate_operand" "g"))] + "" + "tstl %0") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "nonimmediate_operand" "g"))] + "" + "tstw %0") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "nonimmediate_operand" "g"))] + "" + "tstb %0") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" "gF"))] + "" + "tst%# %0") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" "gF"))] + "" + "tstf %0") + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "nonimmediate_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "cmpl %0,%1") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "cmpw %0,%1") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "cmpb %0,%1") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "gF,gF") + (match_operand:DF 1 "general_operand" "G,gF")))] + "" + "@ + tst%# %0 + cmp%# %0,%1") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "gF,gF") + (match_operand:SF 1 "general_operand" "G,gF")))] + "" + "@ + tstf %0 + cmpf %0,%1") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "bitl %0,%1") + +(define_insn "" + [(set (cc0) + (and:HI (match_operand:HI 0 "general_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "bitw %0,%1") + +(define_insn "" + [(set (cc0) + (and:QI (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "bitb %0,%1") + +;; The VAX has no sCOND insns. It does have add/subtract with carry +;; which could be used to implement the sltu and sgeu patterns. However, +;; to do this properly requires a complete rewrite of the compare insns +;; to keep them together with the sltu/sgeu insns until after the +;; reload pass is complete. The previous implementation didn't do this +;; and has been deleted. + + +(define_insn "movdf" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g") + (match_operand:DF 1 "general_operand" "G,gF"))] + "" + "@ + clr%# %0 + mov%# %1,%0") + +(define_insn "movsf" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g") + (match_operand:SF 1 "general_operand" "G,gF"))] + "" + "@ + clrf %0 + movf %1,%0") + +;; Some VAXen don't support this instruction. +;;(define_insn "movti" +;; [(set (match_operand:TI 0 "general_operand" "=g") +;; (match_operand:TI 1 "general_operand" "g"))] +;; "" +;; "movh %1,%0") + +(define_insn "movdi" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g,g") + (match_operand:DI 1 "general_operand" "I,g"))] + "" + "@ + clrq %0 + movq %D1,%0") + +;; The VAX move instructions have space-time tradeoffs. On a MicroVAX +;; register-register mov instructions take 3 bytes and 2 CPU cycles. clrl +;; takes 2 bytes and 3 cycles. mov from constant to register takes 2 cycles +;; if the constant is smaller than 4 bytes, 3 cycles for a longword +;; constant. movz, mneg, and mcom are as fast as mov, so movzwl is faster +;; than movl for positive constants that fit in 16 bits but not 6 bits. cvt +;; instructions take 4 cycles. inc takes 3 cycles. The machine description +;; is willing to trade 1 byte for 1 cycle (clrl instead of movl $0; cvtwl +;; instead of movl). + +;; Cycle counts for other models may vary (on a VAX 750 they are similar, +;; but on a VAX 9000 most move and add instructions with one constant +;; operand take 1 cycle). + +;; Loads of constants between 64 and 128 used to be done with +;; "addl3 $63,#,dst" but this is slower than movzbl and takes as much space. + +(define_insn "movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:SI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const1_rtx && reg_was_0_p (insn, operands[0])) + return \"incl %0\"; + + if (GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST) + { + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + return \"movab %a1,%0\"; + } + if (operands[1] == const0_rtx) + return \"clrl %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) >= 64) + { + int i = INTVAL (operands[1]); + if ((unsigned)(~i) < 64) + return \"mcoml %N1,%0\"; + if ((unsigned)i < 0x100) + return \"movzbl %1,%0\"; + if (i >= -0x80 && i < 0) + return \"cvtbl %1,%0\"; + if ((unsigned)i < 0x10000) + return \"movzwl %1,%0\"; + if (i >= -0x8000 && i < 0) + return \"cvtwl %1,%0\"; + } + if (push_operand (operands[0], SImode)) + return \"pushl %1\"; + return \"movl %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const1_rtx && reg_was_0_p (insn, operands[0])) + return \"incw %0\"; + + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i == 0) + return \"clrw %0\"; + else if ((unsigned int)i < 64) + return \"movw %1,%0\"; + else if ((unsigned int)~i < 64) + return \"mcomw %H1,%0\"; + else if ((unsigned int)i < 256) + return \"movzbw %1,%0\"; + } + return \"movw %1,%0\"; +}") + +(define_insn "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+g")) + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i == 0) + return \"clrw %0\"; + else if ((unsigned int)i < 64) + return \"movw %1,%0\"; + else if ((unsigned int)~i < 64) + return \"mcomw %H1,%0\"; + else if ((unsigned int)i < 256) + return \"movzbw %1,%0\"; + } + return \"movw %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const1_rtx && reg_was_0_p (insn, operands[0])) + return \"incb %0\"; + + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i == 0) + return \"clrb %0\"; + else if ((unsigned int)~i < 64) + return \"mcomb %B1,%0\"; + } + return \"movb %1,%0\"; +}") + +(define_insn "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+g")) + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i == 0) + return \"clrb %0\"; + else if ((unsigned int)~i < 64) + return \"mcomb %B1,%0\"; + } + return \"movb %1,%0\"; +}") + +;; This is here to accept 4 arguments and pass the first 3 along +;; to the movstrhi1 pattern that really does the work. +(define_expand "movstrhi" + [(set (match_operand:BLK 0 "general_operand" "=g") + (match_operand:BLK 1 "general_operand" "g")) + (use (match_operand:HI 2 "general_operand" "g")) + (match_operand 3 "" "")] + "" + " + emit_insn (gen_movstrhi1 (operands[0], operands[1], operands[2])); + DONE; +") + +;; 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 "movstrhi1" + [(set (match_operand:BLK 0 "memory_operand" "=m") + (match_operand:BLK 1 "memory_operand" "m")) + (use (match_operand:HI 2 "general_operand" "g")) + (clobber (reg:SI 0)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3)) + (clobber (reg:SI 4)) + (clobber (reg:SI 5))] + "" + "movc3 %2,%1,%0") + +;; Extension and truncation insns. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "g")))] + "" + "cvtlb %1,%0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "g")))] + "" + "cvtlw %1,%0") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (truncate:QI (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "cvtwb %1,%0") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "cvtwl %1,%0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "cvtbw %1,%0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "cvtbl %1,%0") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (float_extend:DF (match_operand:SF 1 "general_operand" "gF")))] + "" + "cvtf%# %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (float_truncate:SF (match_operand:DF 1 "general_operand" "gF")))] + "" + "cvt%#f %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "movzwl %1,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "movzbw %1,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "movzbl %1,%0") + +;; Fix-to-float conversion insns. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "g")))] + "" + "cvtlf %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (float:DF (match_operand:SI 1 "nonimmediate_operand" "g")))] + "" + "cvtl%# %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (float:SF (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "cvtwf %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (float:DF (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "cvtw%# %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (float:SF (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "cvtbf %1,%0") + +(define_insn "floatqidf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (float:DF (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "cvtb%# %1,%0") + +;; Float-to-fix conversion insns. + +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (fix:QI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfb %1,%0") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (fix:HI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfw %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfl %1,%0") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#b %1,%0") + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#w %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#l %1,%0") + +;;- All kinds of add instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g,g") + (plus:DF (match_operand:DF 1 "general_operand" "0,gF,gF") + (match_operand:DF 2 "general_operand" "gF,0,gF")))] + "" + "@ + add%#2 %2,%0 + add%#2 %1,%0 + add%#3 %1,%2,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g,g") + (plus:SF (match_operand:SF 1 "general_operand" "0,gF,gF") + (match_operand:SF 2 "general_operand" "gF,0,gF")))] + "" + "@ + addf2 %2,%0 + addf2 %1,%0 + addf3 %1,%2,%0") + +/* The space-time-opcode tradeoffs for addition vary by model of VAX. + + On a VAX 3 "movab (r1)[r2],r3" is faster than "addl3 r1,r2,r3", + but it not faster on other models. + + "movab #(r1),r2" is usually shorter than "addl3 #,r1,r2", and is + faster on a VAX 3, but some VAXen (e.g. VAX 9000) will stall if + a register is used in an address too soon after it is set. + Compromise by using movab only when it is shorter than the add + or the base register in the address is one of sp, ap, and fp, + which are not modified very often. */ + + +(define_insn "addsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (plus:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incl %0\"; + if (operands[2] == constm1_rtx) + return \"decl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl2 $%n2,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) INTVAL (operands[2]) >= 64 + && GET_CODE (operands[1]) == REG + && ((INTVAL (operands[2]) < 32767 && INTVAL (operands[2]) > -32768) + || REGNO (operands[1]) > 11)) + return \"movab %c2(%1),%0\"; + return \"addl2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addl2 %1,%0\"; + + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 32767 + && INTVAL (operands[2]) > -32768 + && GET_CODE (operands[1]) == REG + && push_operand (operands[0], SImode)) + return \"pushab %c2(%1)\"; + + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl3 $%n2,%1,%0\"; + + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) INTVAL (operands[2]) >= 64 + && GET_CODE (operands[1]) == REG + && ((INTVAL (operands[2]) < 32767 && INTVAL (operands[2]) > -32768) + || REGNO (operands[1]) > 11)) + return \"movab %c2(%1),%0\"; + + /* Add this if using gcc on a VAX 3xxx: + if (REG_P (operands[1]) && REG_P (operands[2])) + return \"movab (%1)[%2],%0\"; + */ + return \"addl3 %1,%2,%0\"; +}") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (plus:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incw %0\"; + if (operands[2] == constm1_rtx) + return \"decw %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw2 $%n2,%0\"; + return \"addw2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addw2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw3 $%n2,%1,%0\"; + return \"addw3 %1,%2,%0\"; +}") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (plus:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incb %0\"; + if (operands[2] == constm1_rtx) + return \"decb %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb2 $%n2,%0\"; + return \"addb2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addb2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb3 $%n2,%1,%0\"; + return \"addb3 %1,%2,%0\"; +}") + +;; The add-with-carry (adwc) instruction only accepts two operands. +(define_insn "adddi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=ro>,ro>") + (plus:DI (match_operand:DI 1 "general_operand" "%0,ro>") + (match_operand:DI 2 "general_operand" "Fro,F")))] + "" + "* +{ + rtx low[3]; + const char *pattern; + int carry = 1; + + split_quadword_operands (operands, low, 3); + /* Add low parts. */ + if (rtx_equal_p (operands[0], operands[1])) + { + if (low[2] == const0_rtx) + /* Should examine operand, punt if not POST_INC. */ + pattern = \"tstl %0\", carry = 0; + else if (low[2] == const1_rtx) + pattern = \"incl %0\"; + else + pattern = \"addl2 %2,%0\"; + } + else + { + if (low[2] == const0_rtx) + pattern = \"movl %1,%0\", carry = 0; + else + pattern = \"addl3 %2,%1,%0\"; + } + if (pattern) + output_asm_insn (pattern, low); + if (!carry) + /* If CARRY is 0, we don't have any carry value to worry about. */ + return get_insn_template (CODE_FOR_addsi3, insn); + /* %0 = C + %1 + %2 */ + if (!rtx_equal_p (operands[0], operands[1])) + output_asm_insn ((operands[1] == const0_rtx + ? \"clrl %0\" + : \"movl %1,%0\"), operands); + return \"adwc %2,%0\"; +}") + +;;- All kinds of subtract instructions. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g") + (minus:DF (match_operand:DF 1 "general_operand" "0,gF") + (match_operand:DF 2 "general_operand" "gF,gF")))] + "" + "@ + sub%#2 %2,%0 + sub%#3 %2,%1,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g") + (minus:SF (match_operand:SF 1 "general_operand" "0,gF") + (match_operand:SF 2 "general_operand" "gF,gF")))] + "" + "@ + subf2 %2,%0 + subf3 %2,%1,%0") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g") + (minus:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "general_operand" "g,g")))] + "" + "@ + subl2 %2,%0 + subl3 %2,%1,%0") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g") + (minus:HI (match_operand:HI 1 "general_operand" "0,g") + (match_operand:HI 2 "general_operand" "g,g")))] + "" + "@ + subw2 %2,%0 + subw3 %2,%1,%0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g") + (minus:QI (match_operand:QI 1 "general_operand" "0,g") + (match_operand:QI 2 "general_operand" "g,g")))] + "" + "@ + subb2 %2,%0 + subb3 %2,%1,%0") + +;; The subtract-with-carry (sbwc) instruction only takes two operands. +(define_insn "subdi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=or>,or>") + (minus:DI (match_operand:DI 1 "general_operand" "0,or>") + (match_operand:DI 2 "general_operand" "For,F")))] + "" + "* +{ + rtx low[3]; + const char *pattern; + int carry = 1; + + split_quadword_operands (operands, low, 3); + /* Subtract low parts. */ + if (rtx_equal_p (operands[0], operands[1])) + { + if (low[2] == const0_rtx) + pattern = 0, carry = 0; + else if (low[2] == constm1_rtx) + pattern = \"decl %0\"; + else + pattern = \"subl2 %2,%0\"; + } + else + { + if (low[2] == constm1_rtx) + pattern = \"decl %0\"; + else if (low[2] == const0_rtx) + pattern = get_insn_template (CODE_FOR_movsi, insn), carry = 0; + else + pattern = \"subl3 %2,%1,%0\"; + } + if (pattern) + output_asm_insn (pattern, low); + if (carry) + { + if (!rtx_equal_p (operands[0], operands[1])) + return \"movl %1,%0\;sbwc %2,%0\"; + return \"sbwc %2,%0\"; + /* %0 = %2 - %1 - C */ + } + return get_insn_template (CODE_FOR_subsi3, insn); +}") + +;;- Multiply instructions. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g,g") + (mult:DF (match_operand:DF 1 "general_operand" "0,gF,gF") + (match_operand:DF 2 "general_operand" "gF,0,gF")))] + "" + "@ + mul%#2 %2,%0 + mul%#2 %1,%0 + mul%#3 %1,%2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g,g") + (mult:SF (match_operand:SF 1 "general_operand" "0,gF,gF") + (match_operand:SF 2 "general_operand" "gF,0,gF")))] + "" + "@ + mulf2 %2,%0 + mulf2 %1,%0 + mulf3 %1,%2,%0") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g,g") + (mult:SI (match_operand:SI 1 "general_operand" "0,g,g") + (match_operand:SI 2 "general_operand" "g,0,g")))] + "" + "@ + mull2 %2,%0 + mull2 %1,%0 + mull3 %1,%2,%0") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g,") + (mult:HI (match_operand:HI 1 "general_operand" "0,g,g") + (match_operand:HI 2 "general_operand" "g,0,g")))] + "" + "@ + mulw2 %2,%0 + mulw2 %1,%0 + mulw3 %1,%2,%0") + +(define_insn "mulqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g,g") + (mult:QI (match_operand:QI 1 "general_operand" "0,g,g") + (match_operand:QI 2 "general_operand" "g,0,g")))] + "" + "@ + mulb2 %2,%0 + mulb2 %1,%0 + mulb3 %1,%2,%0") + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (mult:DI (sign_extend:DI + (match_operand:SI 1 "nonimmediate_operand" "g")) + (sign_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "g"))))] + "" + "emul %1,%2,$0,%0") + +(define_insn "" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (plus:DI + (mult:DI (sign_extend:DI + (match_operand:SI 1 "nonimmediate_operand" "g")) + (sign_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "g"))) + (sign_extend:DI (match_operand:SI 3 "nonimmediate_operand" "g"))))] + "" + "emul %1,%2,%3,%0") + +;; 'F' constraint means type CONST_DOUBLE +(define_insn "" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (plus:DI + (mult:DI (sign_extend:DI + (match_operand:SI 1 "nonimmediate_operand" "g")) + (sign_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "g"))) + (match_operand:DI 3 "immediate_operand" "F")))] + "GET_CODE (operands[3]) == CONST_DOUBLE + && CONST_DOUBLE_HIGH (operands[3]) == (CONST_DOUBLE_LOW (operands[3]) >> 31)" + "* +{ + if (CONST_DOUBLE_HIGH (operands[3])) + operands[3] = GEN_INT (CONST_DOUBLE_LOW (operands[3])); + return \"emul %1,%2,%3,%0\"; +}") + +;;- Divide instructions. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g") + (div:DF (match_operand:DF 1 "general_operand" "0,gF") + (match_operand:DF 2 "general_operand" "gF,gF")))] + "" + "@ + div%#2 %2,%0 + div%#3 %2,%1,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g") + (div:SF (match_operand:SF 1 "general_operand" "0,gF") + (match_operand:SF 2 "general_operand" "gF,gF")))] + "" + "@ + divf2 %2,%0 + divf3 %2,%1,%0") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g") + (div:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "general_operand" "g,g")))] + "" + "@ + divl2 %2,%0 + divl3 %2,%1,%0") + +(define_insn "divhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g") + (div:HI (match_operand:HI 1 "general_operand" "0,g") + (match_operand:HI 2 "general_operand" "g,g")))] + "" + "@ + divw2 %2,%0 + divw3 %2,%1,%0") + +(define_insn "divqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g") + (div:QI (match_operand:QI 1 "general_operand" "0,g") + (match_operand:QI 2 "general_operand" "g,g")))] + "" + "@ + divb2 %2,%0 + divb3 %2,%1,%0") + +;This is left out because it is very slow; +;we are better off programming around the "lack" of this insn. +;(define_insn "divmoddisi4" +; [(set (match_operand:SI 0 "general_operand" "=g") +; (div:SI (match_operand:DI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g"))) +; (set (match_operand:SI 3 "general_operand" "=g") +; (mod:SI (match_operand:DI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g")))] +; "" +; "ediv %2,%1,%0,%3") + +(define_insn "ediv_helper" + [(set (match_operand:SI 2 "general_operand" "=g") + (div:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:DI 1 "general_operand" "g"))) + (set (match_operand:SI 3 "general_operand" "=g") + (mod:SI (match_dup 0) + (match_dup 1)))] + "" + "ediv %0,%1,%2,%3") + + +(define_expand "udivsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (udiv:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + rtx remainder = gen_reg_rtx(SImode); + rtx dividend_di = gen_reg_rtx(DImode); + rtx dividend = gen_rtx(SUBREG, SImode, dividend_di, 0); + rtx dividend_hi = gen_rtx(SUBREG, SImode, dividend_di, 1); + + rtx label_easy = gen_label_rtx(); + rtx label_ediv = gen_label_rtx(); + rtx label_end = gen_label_rtx(); + + /* we have to deal with the case where one of the operands is + a constant, because otherwise invalid RTXs will be generated. + Both operands can never be constant, because constant + folding will already have eliminated then. */ + + if (GET_CODE (operands[2]) == CONST_INT) { + + /* Divisor is constant */ + + if (INTVAL (operands[2]) > 0) { + + /* Divisor <= 0x7fffffff. If dividend is also <= 0x7fffffff, + then signed division is OK, otherwise need to do extended + (64-bit) division */ + + emit_insn(gen_tstsi(operands[1])); + emit_jump_insn(gen_blt(label_ediv)); + + emit_insn(gen_divsi3(operands[0], operands[1], operands[2])); + emit_jump_insn(gen_jump(label_end)); + + } else { + + /* divisor is >= 0x80000000, so quotient can only be 1 or 0 + depending on which is bigger, dividend or divisor, + respectively */ + + emit_insn(gen_cmpsi(operands[1], operands[2])); + emit_insn(gen_sgeu(operands[0])); + + } + } else if (GET_CODE (operands[1]) == CONST_INT) { + + /* Dividend is constant, divisor is variable */ + if (INTVAL (operands[1]) > 0) { + + /* Dividend <= 0x7fffffff. If divisor is also <= 0x7fffffff, + then signed division is OK, otherwise quotient must be 0 */ + + emit_move_insn(operands[0], const0_rtx); + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_blt(label_end)); + + emit_insn(gen_divsi3(operands[0], operands[1], operands[2])); + + } else { + + /* Is divisor <= 0x7fffffff ? (i.e. high bit clear, so looks positive) */ + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_bge(label_ediv)); + + /* divisor is >= 0x80000000, so quotient can only be 1 or 0 + depending on which is bigger, dividend or divisor, + respectively */ + emit_insn(gen_cmpsi(operands[2], operands[1])); + /* emit_insn(gen_sleu(operands[0])); */ + } + } else { + + /* Is divisor >= 0x80000000 ? (i.e. high bit set, so looks negative) */ + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_blt(label_easy)); + + emit_insn(gen_tstsi(operands[1])); + emit_jump_insn(gen_blt(label_ediv)); + + /* Both <= 0x7fffffff - signed division OK */ + emit_insn(gen_divsi3(operands[0], operands[1], operands[2])); + emit_jump_insn(gen_jump(label_end)); + + emit_label(label_easy); + + /* divisor is >= 0x80000000, so quotient can only be 1 or 0 + depending on which is bigger, dividend or divisor, + respectively */ + + emit_insn(gen_cmpsi(operands[1], operands[2])); + /* emit_insn(gen_sgeu(operands[0])); */ + + } + + emit_jump_insn(gen_jump(label_end)); + + emit_label(label_ediv); + /* Dividend is >= 0x80000000 and divisor <= 0x7fffffff, + so we'll use the EDIV instruction instead (EDIV divides + a quadword by a longword, or a DImode by an SImode in + RTL-speak, and produces both quotient and remainder) */ + + emit_move_insn(dividend, operands[1]); + emit_move_insn(dividend_hi, const0_rtx); + + emit_insn(gen_ediv_helper(operands[2], dividend_di, operands[0], remainder)); + + emit_label(label_end); + + DONE; +} +") + +(define_expand "umodsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (umod:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + rtx quotient = gen_reg_rtx(SImode); + rtx dividend_di = gen_reg_rtx(DImode); + rtx dividend = gen_rtx(SUBREG, SImode, dividend_di, 0); + rtx dividend_hi = gen_rtx(SUBREG, SImode, dividend_di, 1); + + rtx label_signed_mod = gen_label_rtx(); + rtx label_compare = gen_label_rtx(); + rtx label_ediv = gen_label_rtx(); + rtx label_end = gen_label_rtx(); + + int emit_signed_mod_code = 0; + int emit_compare_code = 0; + int emit_ediv_code = 0; + + /* we have to deal with the case where one of the operands is + a constant, because otherwise invalid RTXs will be generated. + Both operands can never be constant, because constant + folding will already have eliminated then. */ + + if (GET_CODE (operands[2]) == CONST_INT) { + + /* Divisor is constant */ + + if (INTVAL (operands[2]) > 0) { + + /* Divisor <= 0x7fffffff. If dividend is also <= 0x7fffffff, + then signed division is OK, otherwise need to do extended + (64-bit) division */ + + emit_insn(gen_tstsi(operands[1])); + emit_jump_insn(gen_bge(label_signed_mod)); + emit_jump_insn(gen_jump(label_ediv)); + + emit_signed_mod_code = 1; + emit_ediv_code = 1; + + } else { + + /* divisor is >= 0x80000000, calculate by comparison */ + emit_jump_insn(gen_jump(label_compare)); + + emit_compare_code = 1; + } + + } else if (GET_CODE (operands[1]) == CONST_INT) { + + /* I don't know why, but GCC never seems to end up here */ + + /* Dividend is constant, divisor is variable */ + if (INTVAL (operands[1]) > 0) { + + /* Dividend <= 0x7fffffff. If divisor is also <= 0x7fffffff, + then signed modulus is OK, otherwise do 64-bit division */ + + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_bge(label_signed_mod)); + emit_jump_insn(gen_jump(label_ediv)); + + emit_signed_mod_code = 1; + emit_ediv_code = 1; + + } else { + + /* Dividend >= 0x80000000. If divisor is also >= 0x80000000, + then do mod-by-comparison, otherwise do 64-bit division */ + + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_blt(label_compare)); + emit_jump_insn(gen_jump(label_ediv)); + + emit_compare_code = 1; + emit_ediv_code = 1; + } + } else { + + /* Is divisor >= 0x80000000 ? (i.e. high bit set, so looks negative) */ + emit_insn(gen_tstsi(operands[2])); + emit_jump_insn(gen_blt(label_compare)); + + /* Is dividend >= 0x80000000 ? (i.e. high bit set, so looks negative) */ + emit_insn(gen_tstsi(operands[1])); + emit_jump_insn(gen_blt(label_ediv)); + + /* Both <= 0x7fffffff - signed modulus OK */ + emit_jump_insn(gen_jump(label_signed_mod)); + + emit_ediv_code = 1; + emit_compare_code = 1; + emit_signed_mod_code = 1; + } + + if (emit_signed_mod_code) { + emit_label(label_signed_mod); + + /* Both <= 0x7fffffff - signed modulus OK */ + emit_insn(gen_divsi3(quotient, operands[1], operands[2])); + emit_insn(gen_mulsi3(quotient, quotient, operands[2])); + emit_insn(gen_subsi3(operands[0], operands[1], quotient)); + emit_jump_insn(gen_jump(label_end)); + + /* Emit code to use extended division instruction */ + } + + if (emit_ediv_code) { + emit_label(label_ediv); + + /* Dividend is >= 0x80000000 and divisor <= 0x7fffffff, + so we'll use the EDIV instruction instead (EDIV divides + a quadword by a longword, or a DImode by an SImode in + RTL-speak, and produces both quotient and remainder) */ + + emit_move_insn(dividend, operands[1]); + emit_move_insn(dividend_hi, const0_rtx); + + emit_insn(gen_ediv_helper(operands[2], dividend_di, quotient, operands[0])); + emit_jump_insn(gen_jump(label_end)); + } + + if (emit_compare_code) { + /* Emit code to to mod-by-comparison. */ + emit_label(label_compare); + emit_insn(gen_umodsi3_compare(operands[0], operands[1], operands[2])); + } + + emit_label(label_end); + + DONE; +} +") + +;; This is used by the umodsi3 define_expand above. It will never +;; be matched by GCC because it is more specific than the umodsi3 +;; definition, and GCC matches insns in the order they occur in +;; this file. This is essential, because the code generated here +;; is only valid for the case where the divisor is >= 0x80000000, +;; so dividend/divisor can only be 0 or 1 depending on which +;; is bigger, dividend or divisor. This means that the remainder +;; can be calculated without a division +;; +;; If divisor is bigger, then quotient is 0, so remainder is +;; +;; dividend - (divisor * quotient) +;; = dividend - (divisor * 0) +;; = dividend +;; +;; If dividend is bigger, then quotient is 1, so remainder is +;; +;; dividend - (divisor * quotient) +;; = dividend - (divisor * 1) +;; = dividend - divisor +(define_insn "umodsi3_compare" + [(set (match_operand:SI 0 "general_operand" "=ro") + (umod:SI (match_operand:SI 1 "general_operand" "ro") + (match_operand:SI 2 "general_operand" "g")))] + "" + "subl3 %2, %1, %0\;bcc .LB%=\;movl %1, %0\;.LB%=:") + + +;; Bit-and on the VAX is done with a clear-bits insn. +(define_expand "andsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (and:SI (not:SI (match_operand:SI 1 "general_operand" "")) + (match_operand:SI 2 "general_operand" "")))] + "" + " +{ + rtx op1 = operands[1]; + + /* If there is a constant argument, complement that one. */ + if (GET_CODE (operands[2]) == CONST_INT && GET_CODE (op1) != CONST_INT) + { + operands[1] = operands[2]; + operands[2] = op1; + op1 = operands[1]; + } + + if (GET_CODE (op1) == CONST_INT) + operands[1] = GEN_INT (~INTVAL (op1)); + else + operands[1] = expand_unop (SImode, one_cmpl_optab, op1, 0, 1); +}") + +(define_expand "andhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (and:HI (not:HI (match_operand:HI 1 "general_operand" "")) + (match_operand:HI 2 "general_operand" "")))] + "" + " +{ + rtx op1 = operands[1]; + + if (GET_CODE (operands[2]) == CONST_INT && GET_CODE (op1) != CONST_INT) + { + operands[1] = operands[2]; + operands[2] = op1; + op1 = operands[1]; + } + + if (GET_CODE (op1) == CONST_INT) + operands[1] = GEN_INT (~INTVAL (op1)); + else + operands[1] = expand_unop (HImode, one_cmpl_optab, op1, 0, 1); +}") + +(define_expand "andqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (and:QI (not:QI (match_operand:QI 1 "general_operand" "")) + (match_operand:QI 2 "general_operand" "")))] + "" + " +{ + rtx op1 = operands[1]; + + if (GET_CODE (operands[2]) == CONST_INT && GET_CODE (op1) != CONST_INT) + { + operands[1] = operands[2]; + operands[2] = op1; + op1 = operands[1]; + } + + if (GET_CODE (op1) == CONST_INT) + operands[1] = GEN_INT (~INTVAL (op1)); + else + operands[1] = expand_unop (QImode, one_cmpl_optab, op1, 0, 1); +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g") + (and:SI (not:SI (match_operand:SI 1 "general_operand" "g,g")) + (match_operand:SI 2 "general_operand" "0,g")))] + "" + "@ + bicl2 %1,%0 + bicl3 %1,%2,%0") + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g") + (and:HI (not:HI (match_operand:HI 1 "general_operand" "g,g")) + (match_operand:HI 2 "general_operand" "0,g")))] + "" + "@ + bicw2 %1,%0 + bicw3 %1,%2,%0") + +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g") + (and:QI (not:QI (match_operand:QI 1 "general_operand" "g,g")) + (match_operand:QI 2 "general_operand" "0,g")))] + "" + "@ + bicb2 %1,%0 + bicb3 %1,%2,%0") + +;; The following used to be needed because constant propagation can +;; create them starting from the bic insn patterns above. This is no +;; longer a problem. However, having these patterns allows optimization +;; opportunities in combine.c. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g") + (and:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "const_int_operand" "n,n")))] + "" + "@ + bicl2 %N2,%0 + bicl3 %N2,%1,%0") + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g") + (and:HI (match_operand:HI 1 "general_operand" "0,g") + (match_operand:HI 2 "const_int_operand" "n,n")))] + "" + "@ + bicw2 %H2,%0 + bicw3 %H2,%1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g") + (and:QI (match_operand:QI 1 "general_operand" "0,g") + (match_operand:QI 2 "const_int_operand" "n,n")))] + "" + "@ + bicb2 %B2,%0 + bicb3 %B2,%1,%0") + +;;- Bit set instructions. + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g,g") + (ior:SI (match_operand:SI 1 "general_operand" "0,g,g") + (match_operand:SI 2 "general_operand" "g,0,g")))] + "" + "@ + bisl2 %2,%0 + bisl2 %1,%0 + bisl3 %2,%1,%0") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g,g") + (ior:HI (match_operand:HI 1 "general_operand" "0,g,g") + (match_operand:HI 2 "general_operand" "g,0,g")))] + "" + "@ + bisw2 %2,%0 + bisw2 %1,%0 + bisw3 %2,%1,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g,g") + (ior:QI (match_operand:QI 1 "general_operand" "0,g,g") + (match_operand:QI 2 "general_operand" "g,0,g")))] + "" + "@ + bisb2 %2,%0 + bisb2 %1,%0 + bisb3 %2,%1,%0") + +;;- xor instructions. + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g,g") + (xor:SI (match_operand:SI 1 "general_operand" "0,g,g") + (match_operand:SI 2 "general_operand" "g,0,g")))] + "" + "@ + xorl2 %2,%0 + xorl2 %1,%0 + xorl3 %2,%1,%0") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g,g") + (xor:HI (match_operand:HI 1 "general_operand" "0,g,g") + (match_operand:HI 2 "general_operand" "g,0,g")))] + "" + "@ + xorw2 %2,%0 + xorw2 %1,%0 + xorw3 %2,%1,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g,g") + (xor:QI (match_operand:QI 1 "general_operand" "0,g,g") + (match_operand:QI 2 "general_operand" "g,0,g")))] + "" + "@ + xorb2 %2,%0 + xorb2 %1,%0 + xorb3 %2,%1,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (neg:DF (match_operand:DF 1 "general_operand" "gF")))] + "" + "mneg%# %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (neg:SF (match_operand:SF 1 "general_operand" "gF")))] + "" + "mnegf %1,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (neg:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mnegl %1,%0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (neg:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mnegw %1,%0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (neg:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mnegb %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (not:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mcoml %1,%0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (not:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mcomw %1,%0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (not:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mcomb %1,%0") + +;; Arithmetic right shift on the VAX works by negating the shift count, +;; then emitting a right shift with the shift count negated. This means +;; that all actual shift counts in the RTL will be positive. This +;; prevents converting shifts to ZERO_EXTRACTs with negative positions, +;; which isn't valid. +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2])); +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "const_int_operand" "n")))] + "" + "ashl $%n2,%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (neg:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "ashl %2,%1,%0") + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (operands[2] == const1_rtx && rtx_equal_p (operands[0], operands[1])) + return \"addl2 %0,%0\"; + if (GET_CODE (operands[1]) == REG + && GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if (i == 1) + return \"addl3 %1,%1,%0\"; + if (i == 2) + return \"moval 0[%1],%0\"; + if (i == 3) + return \"movad 0[%1],%0\"; + } + return \"ashl %2,%1,%0\"; +}") + +;; Arithmetic right shift on the VAX works by negating the shift count. +(define_expand "ashrdi3" + [(set (match_operand:DI 0 "general_operand" "=g") + (ashiftrt:DI (match_operand:DI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2])); +}") + +(define_insn "ashldi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (ashift:DI (match_operand:DI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "ashq %2,%1,%0") + +(define_insn "" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (ashiftrt:DI (match_operand:DI 1 "general_operand" "g") + (neg:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "ashq %2,%1,%0") + +;; We used to have expand_shift handle logical right shifts by using extzv, +;; but this make it very difficult to do lshrdi3. Since the VAX is the +;; only machine with this kludge, it's better to just do this with a +;; define_expand and remove that case from expand_shift. + +(define_expand "lshrsi3" + [(set (match_dup 3) + (minus:QI (const_int 32) + (match_dup 4))) + (set (match_operand:SI 0 "general_operand" "=g") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r") + (match_dup 3) + (match_operand:SI 2 "register_operand" "g")))] + "" + " +{ + operands[3] = gen_reg_rtx (QImode); + operands[4] = gen_lowpart (QImode, operands[2]); +}") + +;; Rotate right on the VAX works by negating the shift count. +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotatert:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2])); +}") + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (rotate:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "rotl %2,%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (rotatert:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "const_int_operand" "n")))] + "" + "rotl %R2,%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (rotatert:SI (match_operand:SI 1 "general_operand" "g") + (neg:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "rotl %2,%1,%0") + +;This insn is probably slower than a multiply and an add. +;(define_insn "" +; [(set (match_operand:SI 0 "general_operand" "=g") +; (mult:SI (plus:SI (match_operand:SI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g")) +; (match_operand:SI 3 "general_operand" "g")))] +; "" +; "index %1,$0x80000000,$0x7fffffff,%3,%2,%0") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+ro") + (match_operand:QI 1 "const_int_operand" "n") + (match_operand:SI 2 "const_int_operand" "n")) + (match_operand:SI 3 "general_operand" "g"))] + "(INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0 + && (GET_CODE (operands[0]) == REG + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + if (REG_P (operands[0])) + { + if (INTVAL (operands[2]) != 0) + return \"insv %3,%2,%1,%0\"; + } + else + operands[0] + = adjust_address (operands[0], + INTVAL (operands[1]) == 8 ? QImode : HImode, + INTVAL (operands[2]) / 8); + + CC_STATUS_INIT; + if (INTVAL (operands[1]) == 8) + return \"movb %3,%0\"; + return \"movw %3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=&g") + (zero_extract:SI (match_operand:SI 1 "register_operand" "ro") + (match_operand:QI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[3]) != 0) + return \"extzv %3,%2,%1,%0\"; + } + else + operands[1] + = adjust_address (operands[1], + INTVAL (operands[2]) == 8 ? QImode : HImode, + INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"movzbl %1,%0\"; + return \"movzwl %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extract:SI (match_operand:SI 1 "register_operand" "ro") + (match_operand:QI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[3]) != 0) + return \"extv %3,%2,%1,%0\"; + } + else + operands[1] + = adjust_address (operands[1], + INTVAL (operands[2]) == 8 ? QImode : HImode, + INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"cvtbl %1,%0\"; + return \"cvtwl %1,%0\"; +}") + +;; Register-only SImode cases of bit-field insns. + +(define_insn "" + [(set (cc0) + (compare + (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpv %2,%1,%0,%3") + +(define_insn "" + [(set (cc0) + (compare + (zero_extract:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpzv %2,%1,%0,%3") + +;; When the field position and size are constant and the destination +;; is a register, extv and extzv are much slower than a rotate followed +;; by a bicl or sign extension. Because we might end up choosing ext[z]v +;; anyway, we can't allow immediate values for the primary source operand. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extract:SI (match_operand:SI 1 "register_operand" "ro") + (match_operand:QI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[3]) != CONST_INT || GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[0]) != REG + || (INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16)) + return \"extv %3,%2,%1,%0\"; + if (INTVAL (operands[2]) == 8) + return \"rotl %R3,%1,%0\;cvtbl %0,%0\"; + return \"rotl %R3,%1,%0\;cvtwl %0,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (zero_extract:SI (match_operand:SI 1 "register_operand" "ro") + (match_operand:QI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[3]) != CONST_INT || GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[0]) != REG) + return \"extzv %3,%2,%1,%0\"; + if (INTVAL (operands[2]) == 8) + return \"rotl %R3,%1,%0\;movzbl %0,%0\"; + if (INTVAL (operands[2]) == 16) + return \"rotl %R3,%1,%0\;movzwl %0,%0\"; + if (INTVAL (operands[3]) & 31) + return \"rotl %R3,%1,%0\;bicl2 %M2,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"bicl2 %M2,%0\"; + return \"bicl3 %M2,%1,%0\"; +}") + +;; Non-register cases. +;; nonimmediate_operand is used to make sure that mode-ambiguous cases +;; don't match these (and therefore match the cases above instead). + +(define_insn "" + [(set (cc0) + (compare + (sign_extract:SI (match_operand:QI 0 "memory_operand" "m") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpv %2,%1,%0,%3") + +(define_insn "" + [(set (cc0) + (compare + (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "rm") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpzv %2,%1,%0,%3") + +(define_insn "extv" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extract:SI (match_operand:QI 1 "memory_operand" "m") + (match_operand:QI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[0]) != REG || GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[3]) != CONST_INT + || (INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16) + || INTVAL (operands[2]) + INTVAL (operands[3]) > 32 + || side_effects_p (operands[1]) + || (GET_CODE (operands[1]) == MEM + && mode_dependent_address_p (XEXP (operands[1], 0)))) + return \"extv %3,%2,%1,%0\"; + if (INTVAL (operands[2]) == 8) + return \"rotl %R3,%1,%0\;cvtbl %0,%0\"; + return \"rotl %R3,%1,%0\;cvtwl %0,%0\"; +}") + +(define_expand "extzv" + [(set (match_operand:SI 0 "general_operand" "") + (zero_extract:SI (match_operand:SI 1 "general_operand" "") + (match_operand:QI 2 "general_operand" "") + (match_operand:SI 3 "general_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (zero_extract:SI (match_operand:QI 1 "memory_operand" "m") + (match_operand:QI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[0]) != REG || GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[3]) != CONST_INT + || INTVAL (operands[2]) + INTVAL (operands[3]) > 32 + || side_effects_p (operands[1]) + || (GET_CODE (operands[1]) == MEM + && mode_dependent_address_p (XEXP (operands[1], 0)))) + return \"extzv %3,%2,%1,%0\"; + if (INTVAL (operands[2]) == 8) + return \"rotl %R3,%1,%0\;movzbl %0,%0\"; + if (INTVAL (operands[2]) == 16) + return \"rotl %R3,%1,%0\;movzwl %0,%0\"; + return \"rotl %R3,%1,%0\;bicl2 %M2,%0\"; +}") + +(define_expand "insv" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")) + (match_operand:SI 3 "general_operand" ""))] + "" + "") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+g") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g"))] + "" + "insv %3,%2,%1,%0") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g"))] + "" + "insv %3,%2,%1,%0") + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jbr %l0") + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jeql %l0") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jneq %l0") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtr %l0") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtru %l0") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlss %l0") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlssu %l0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgeq %l0") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgequ %l0") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jleq %l0") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlequ %l0") + +;; Recognize reversed jumps. +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(cc0) + (const_int 0)]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "j%C0 %l1") ; %C0 negates condition + +;; Recognize jbs, jlbs, jbc and jlbc instructions. Note that the operand +;; of jlbs and jlbc insns are SImode in the hardware. However, if it is +;; memory, we use QImode in the insn. So we can't use those instructions +;; for mode-dependent addresses. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q,g") + (const_int 1) + (match_operand:SI 1 "general_operand" "I,g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "@ + jlbs %0,%l2 + jbs %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q,g") + (const_int 1) + (match_operand:SI 1 "general_operand" "I,g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "@ + jlbc %0,%l2 + jbc %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r") + (const_int 1) + (match_operand:SI 1 "general_operand" "I,g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "@ + jlbs %0,%l2 + jbs %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r") + (const_int 1) + (match_operand:SI 1 "general_operand" "I,g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "@ + jlbc %0,%l2 + jbc %1,%0,%l2") + +;; Subtract-and-jump and Add-and-jump insns. +;; These are not used when output is for the Unix assembler +;; because it does not know how to modify them to reach far. + +;; Normal sob insns. + +(define_insn "" + [(set (pc) + (if_then_else + (gt (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgtr %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgeq %0,%l1") + +;; Normal aob insns. Define a version for when operands[1] is a constant. +(define_insn "" + [(set (pc) + (if_then_else + (lt (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaoblss %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (lt (match_operand:SI 0 "nonimmediate_operand" "+g") + (match_operand:SI 1 "general_operand" "g")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM && GET_CODE (operands[1]) == CONST_INT" + "jaoblss %P1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (le (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaobleq %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (le (match_operand:SI 0 "nonimmediate_operand" "+g") + (match_operand:SI 1 "general_operand" "g")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM && GET_CODE (operands[1]) == CONST_INT" + "jaobleq %P1,%0,%l2") + +;; Something like a sob insn, but compares against -1. +;; This finds `while (foo--)' which was changed to `while (--foo != -1)'. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "decl %0\;jgequ %l1") + +(define_expand "call_pop" + [(parallel [(call (match_operand:QI 0 "memory_operand" "") + (match_operand:SI 1 "const_int_operand" "")) + (set (reg:SI 14) + (plus:SI (reg:SI 14) + (match_operand:SI 3 "immediate_operand" "")))])] + "" +{ + if (INTVAL (operands[3]) > 255 * 4 || INTVAL (operands[3]) % 4) + abort (); + + /* Operand 1 is the number of bytes to be popped by DW_CFA_GNU_args_size + during EH unwinding. We must include the argument count pushed by + the calls instruction. */ + operands[1] = GEN_INT (INTVAL (operands[3]) + 4); +}) + +(define_insn "*call_pop" + [(call (match_operand:QI 0 "memory_operand" "m") + (match_operand:SI 1 "const_int_operand" "n")) + (set (reg:SI 14) (plus:SI (reg:SI 14) + (match_operand:SI 2 "immediate_operand" "i")))] + "" +{ + operands[1] = GEN_INT ((INTVAL (operands[1]) - 4) / 4); + return "calls %1,%0"; +}) + +(define_expand "call_value_pop" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "") + (match_operand:SI 2 "const_int_operand" ""))) + (set (reg:SI 14) + (plus:SI (reg:SI 14) + (match_operand:SI 4 "immediate_operand" "")))])] + "" +{ + if (INTVAL (operands[4]) > 255 * 4 || INTVAL (operands[4]) % 4) + abort (); + + /* Operand 2 is the number of bytes to be popped by DW_CFA_GNU_args_size + during EH unwinding. We must include the argument count pushed by + the calls instruction. */ + operands[2] = GEN_INT (INTVAL (operands[4]) + 4); +}) + +(define_insn "*call_value_pop" + [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "m") + (match_operand:SI 2 "const_int_operand" "n"))) + (set (reg:SI 14) (plus:SI (reg:SI 14) + (match_operand:SI 3 "immediate_operand" "i")))] + "" + "* +{ + operands[2] = GEN_INT ((INTVAL (operands[2]) - 4) / 4); + return \"calls %2,%1\"; +}") + +(define_expand "call" + [(call (match_operand:QI 0 "memory_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "" + " +{ + /* Operand 1 is the number of bytes to be popped by DW_CFA_GNU_args_size + during EH unwinding. We must include the argument count pushed by + the calls instruction. */ + operands[1] = GEN_INT (INTVAL (operands[1]) + 4); +}") + +(define_insn "*call" + [(call (match_operand:QI 0 "memory_operand" "m") + (match_operand:SI 1 "const_int_operand" ""))] + "" + "calls $0,%0") + +(define_expand "call_value" + [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "" + " +{ + /* Operand 2 is the number of bytes to be popped by DW_CFA_GNU_args_size + during EH unwinding. We must include the argument count pushed by + the calls instruction. */ + operands[2] = GEN_INT (INTVAL (operands[2]) + 4); +}") + +(define_insn "*call_value" + [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "m") + (match_operand:SI 2 "const_int_operand" "")))] + "" + "calls $0,%1") + +;; Call subroutine returning any type. + +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" + " +{ + int i; + + emit_call_insn (gen_call_pop (operands[0], const0_rtx, NULL, const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + + DONE; +}") + +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and +;; all of memory. This blocks insns from being moved across this point. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] VUNSPEC_BLOCKAGE)] + "" + "") + +(define_insn "return" + [(return)] + "" + "ret") + +(define_expand "epilogue" + [(return)] + "" + " +{ + emit_jump_insn (gen_return ()); + DONE; +}") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;; This had a wider constraint once, and it had trouble. +;; If you are tempted to try `g', please don't--it's not worth +;; the risk we will reopen the same bug. +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] + "" + "jmp (%0)") + +;; This is here to accept 5 arguments (as passed by expand_end_case) +;; and pass the first 4 along to the casesi1 pattern that really does the work. +(define_expand "casesi" + [(match_operand:SI 0 "general_operand" "") ; index + (match_operand:SI 1 "general_operand" "") ; lower + (match_operand:SI 2 "general_operand" "") ; upper-lower + (match_operand 3 "" "") ; table label + (match_operand 4 "" "")] ; default label + "" +{ + emit_jump_insn (gen_casesi1 (operands[0], operands[1], + operands[2], operands[3])); + DONE; +}) + +(define_insn "casesi1" + [(set (pc) + (if_then_else + (leu (minus:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (match_operand:SI 2 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (mult:SI (minus:SI (match_dup 0) + (match_dup 1)) + (const_int 2)) + (pc)))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,%1,%2") + +;; This can arise by simplification when operand 1 is a constant int. +(define_insn "" + [(set (pc) + (if_then_else + (leu (plus:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "const_int_operand" "n")) + (match_operand:SI 2 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (mult:SI (plus:SI (match_dup 0) + (match_dup 1)) + (const_int 2)) + (pc)))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "* +{ + operands[1] = GEN_INT (-INTVAL (operands[1])); + return \"casel %0,%1,%2\"; +}") + +;; This can arise by simplification when the base for the case insn is zero. +(define_insn "" + [(set (pc) + (if_then_else (leu (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (mult:SI (match_dup 0) + (const_int 2)) + (pc)))) + (label_ref:SI (match_operand 2 "" ""))) + (pc)))] + "" + "casel %0,$0,%1") + +;;- load or push effective address +;; These come after the move and add/sub patterns +;; because we don't want pushl $1 turned into pushad 1. +;; or addl3 r1,r2,r3 turned into movab 0(r1)[r2],r3. + +;; It does not work to use constraints to distinguish pushes from moves, +;; because < matches any autodecrement, not just a push. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + else + return \"movab %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:HI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaw %a1\"; + else + return \"movaw %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:SI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushal %a1\"; + else + return \"moval %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:DI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaq %a1\"; + else + return \"movaq %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:SF 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaf %a1\"; + else + return \"movaf %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:DF 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushad %a1\"; + else + return \"movad %a1,%0\"; +}") + +;; These used to be peepholes, but it is more straightforward to do them +;; as single insns. However, we must force the output to be a register +;; if it is not an offsettable address so that we know that we can assign +;; to it twice. + +;; If we had a good way of evaluating the relative costs, these could be +;; machine-independent. + +;; Optimize extzv ...,z; andl2 ...,z +;; or ashl ...,z; andl2 ...,z +;; with other operands constant. This is what the combiner converts the +;; above sequences to before attempting to recognize the new insn. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=ro") + (and:SI (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "const_int_operand" "n")) + (match_operand:SI 3 "const_int_operand" "n")))] + "(INTVAL (operands[3]) & ~((1 << (32 - INTVAL (operands[2]))) - 1)) == 0" + "* +{ + unsigned long mask1 = INTVAL (operands[3]); + unsigned long mask2 = (1 << (32 - INTVAL (operands[2]))) - 1; + + if ((mask1 & mask2) != mask1) + operands[3] = GEN_INT (mask1 & mask2); + + return \"rotl %R2,%1,%0\;bicl2 %N3,%0\"; +}") + +;; left-shift and mask +;; The only case where `ashl' is better is if the mask only turns off +;; bits that the ashl would anyways, in which case it should have been +;; optimized away. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=ro") + (and:SI (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "const_int_operand" "n")) + (match_operand:SI 3 "const_int_operand" "n")))] + "" + "* +{ + operands[3] + = GEN_INT (INTVAL (operands[3]) & ~((1 << INTVAL (operands[2])) - 1)); + return \"rotl %2,%1,%0\;bicl2 %N3,%0\"; +}") + +;; Instruction sequence to sync the VAX instruction stream. +(define_insn "sync_istream" + [(unspec_volatile [(const_int 0)] VUNSPEC_SYNC_ISTREAM)] + "" + "movpsl -(%|sp)\;pushal 1(%|pc)\;rei") diff -Nur orig/gcc-20030127/gcc/config/vax/vax.md.save~ x/vax.md.save~ --- orig/gcc-20030127/gcc/config/vax/vax.md.save~ 1970-01-01 10:00:00.000000000 +1000 +++ x/vax.md.save~ 2003-06-15 11:36:30.000000000 +1000 @@ -0,0 +1,2169 @@ +;; Machine description for GNU compiler, VAX Version +;; Copyright (C) 1987, 1988, 1991, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +;; 2002 Free Software Foundation, Inc. + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + + +;;- Instruction patterns. When multiple patterns apply, +;;- the first one in the file is chosen. +;;- +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;;- +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;; UNSPEC_VOLATILE usage: + +(define_constants + [(VUNSPEC_BLOCKAGE 0) ; `blockage' insn to prevent scheduling across an + ; insn in the code. + (VUNSPEC_SYNC_ISTREAM 1) ; sequence of insns to sync the I-stream + ] +) + +;; 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. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "nonimmediate_operand" "g"))] + "" + "tstl %0") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "nonimmediate_operand" "g"))] + "" + "tstw %0") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "nonimmediate_operand" "g"))] + "" + "tstb %0") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" "gF"))] + "" + "tst%# %0") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" "gF"))] + "" + "tstf %0") + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "nonimmediate_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "cmpl %0,%1") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "cmpw %0,%1") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "cmpb %0,%1") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "gF,gF") + (match_operand:DF 1 "general_operand" "G,gF")))] + "" + "@ + tst%# %0 + cmp%# %0,%1") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "gF,gF") + (match_operand:SF 1 "general_operand" "G,gF")))] + "" + "@ + tstf %0 + cmpf %0,%1") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "bitl %0,%1") + +(define_insn "" + [(set (cc0) + (and:HI (match_operand:HI 0 "general_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "bitw %0,%1") + +(define_insn "" + [(set (cc0) + (and:QI (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "bitb %0,%1") + +;; The VAX has no sCOND insns. It does have add/subtract with carry +;; which could be used to implement the sltu and sgeu patterns. However, +;; to do this properly requires a complete rewrite of the compare insns +;; to keep them together with the sltu/sgeu insns until after the +;; reload pass is complete. The previous implementation didn't do this +;; and has been deleted. + + +(define_insn "movdf" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g") + (match_operand:DF 1 "general_operand" "G,gF"))] + "" + "@ + clr%# %0 + mov%# %1,%0") + +(define_insn "movsf" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g") + (match_operand:SF 1 "general_operand" "G,gF"))] + "" + "@ + clrf %0 + movf %1,%0") + +;; Some VAXen don't support this instruction. +;;(define_insn "movti" +;; [(set (match_operand:TI 0 "general_operand" "=g") +;; (match_operand:TI 1 "general_operand" "g"))] +;; "" +;; "movh %1,%0") + +(define_insn "movdi" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g,g") + (match_operand:DI 1 "general_operand" "I,g"))] + "" + "@ + clrq %0 + movq %D1,%0") + +;; The VAX move instructions have space-time tradeoffs. On a MicroVAX +;; register-register mov instructions take 3 bytes and 2 CPU cycles. clrl +;; takes 2 bytes and 3 cycles. mov from constant to register takes 2 cycles +;; if the constant is smaller than 4 bytes, 3 cycles for a longword +;; constant. movz, mneg, and mcom are as fast as mov, so movzwl is faster +;; than movl for positive constants that fit in 16 bits but not 6 bits. cvt +;; instructions take 4 cycles. inc takes 3 cycles. The machine description +;; is willing to trade 1 byte for 1 cycle (clrl instead of movl $0; cvtwl +;; instead of movl). + +;; Cycle counts for other models may vary (on a VAX 750 they are similar, +;; but on a VAX 9000 most move and add instructions with one constant +;; operand take 1 cycle). + +;; Loads of constants between 64 and 128 used to be done with +;; "addl3 $63,#,dst" but this is slower than movzbl and takes as much space. + +(define_insn "movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:SI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const1_rtx && reg_was_0_p (insn, operands[0])) + return \"incl %0\"; + + if (GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST) + { + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + return \"movab %a1,%0\"; + } + if (operands[1] == const0_rtx) + return \"clrl %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) >= 64) + { + int i = INTVAL (operands[1]); + if ((unsigned)(~i) < 64) + return \"mcoml %N1,%0\"; + if ((unsigned)i < 0x100) + return \"movzbl %1,%0\"; + if (i >= -0x80 && i < 0) + return \"cvtbl %1,%0\"; + if ((unsigned)i < 0x10000) + return \"movzwl %1,%0\"; + if (i >= -0x8000 && i < 0) + return \"cvtwl %1,%0\"; + } + if (push_operand (operands[0], SImode)) + return \"pushl %1\"; + return \"movl %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const1_rtx && reg_was_0_p (insn, operands[0])) + return \"incw %0\"; + + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i == 0) + return \"clrw %0\"; + else if ((unsigned int)i < 64) + return \"movw %1,%0\"; + else if ((unsigned int)~i < 64) + return \"mcomw %H1,%0\"; + else if ((unsigned int)i < 256) + return \"movzbw %1,%0\"; + } + return \"movw %1,%0\"; +}") + +(define_insn "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+g")) + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i == 0) + return \"clrw %0\"; + else if ((unsigned int)i < 64) + return \"movw %1,%0\"; + else if ((unsigned int)~i < 64) + return \"mcomw %H1,%0\"; + else if ((unsigned int)i < 256) + return \"movzbw %1,%0\"; + } + return \"movw %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const1_rtx && reg_was_0_p (insn, operands[0])) + return \"incb %0\"; + + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i == 0) + return \"clrb %0\"; + else if ((unsigned int)~i < 64) + return \"mcomb %B1,%0\"; + } + return \"movb %1,%0\"; +}") + +(define_insn "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+g")) + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i == 0) + return \"clrb %0\"; + else if ((unsigned int)~i < 64) + return \"mcomb %B1,%0\"; + } + return \"movb %1,%0\"; +}") + +;; This is here to accept 4 arguments and pass the first 3 along +;; to the movstrhi1 pattern that really does the work. +(define_expand "movstrhi" + [(set (match_operand:BLK 0 "general_operand" "=g") + (match_operand:BLK 1 "general_operand" "g")) + (use (match_operand:HI 2 "general_operand" "g")) + (match_operand 3 "" "")] + "" + " + emit_insn (gen_movstrhi1 (operands[0], operands[1], operands[2])); + DONE; +") + +;; 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 "movstrhi1" + [(set (match_operand:BLK 0 "memory_operand" "=m") + (match_operand:BLK 1 "memory_operand" "m")) + (use (match_operand:HI 2 "general_operand" "g")) + (clobber (reg:SI 0)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3)) + (clobber (reg:SI 4)) + (clobber (reg:SI 5))] + "" + "movc3 %2,%1,%0") + +;; Extension and truncation insns. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "g")))] + "" + "cvtlb %1,%0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "g")))] + "" + "cvtlw %1,%0") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (truncate:QI (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "cvtwb %1,%0") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "cvtwl %1,%0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "cvtbw %1,%0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "cvtbl %1,%0") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (float_extend:DF (match_operand:SF 1 "general_operand" "gF")))] + "" + "cvtf%# %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (float_truncate:SF (match_operand:DF 1 "general_operand" "gF")))] + "" + "cvt%#f %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "movzwl %1,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "movzbw %1,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "movzbl %1,%0") + +;; Fix-to-float conversion insns. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "g")))] + "" + "cvtlf %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (float:DF (match_operand:SI 1 "nonimmediate_operand" "g")))] + "" + "cvtl%# %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (float:SF (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "cvtwf %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (float:DF (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "cvtw%# %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (float:SF (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "cvtbf %1,%0") + +(define_insn "floatqidf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (float:DF (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "cvtb%# %1,%0") + +;; Float-to-fix conversion insns. + +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (fix:QI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfb %1,%0") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (fix:HI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfw %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfl %1,%0") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#b %1,%0") + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#w %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#l %1,%0") + +;;- All kinds of add instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g,g") + (plus:DF (match_operand:DF 1 "general_operand" "0,gF,gF") + (match_operand:DF 2 "general_operand" "gF,0,gF")))] + "" + "@ + add%#2 %2,%0 + add%#2 %1,%0 + add%#3 %1,%2,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g,g") + (plus:SF (match_operand:SF 1 "general_operand" "0,gF,gF") + (match_operand:SF 2 "general_operand" "gF,0,gF")))] + "" + "@ + addf2 %2,%0 + addf2 %1,%0 + addf3 %1,%2,%0") + +/* The space-time-opcode tradeoffs for addition vary by model of VAX. + + On a VAX 3 "movab (r1)[r2],r3" is faster than "addl3 r1,r2,r3", + but it not faster on other models. + + "movab #(r1),r2" is usually shorter than "addl3 #,r1,r2", and is + faster on a VAX 3, but some VAXen (e.g. VAX 9000) will stall if + a register is used in an address too soon after it is set. + Compromise by using movab only when it is shorter than the add + or the base register in the address is one of sp, ap, and fp, + which are not modified very often. */ + + +(define_insn "addsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (plus:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incl %0\"; + if (operands[2] == constm1_rtx) + return \"decl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl2 $%n2,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) INTVAL (operands[2]) >= 64 + && GET_CODE (operands[1]) == REG + && ((INTVAL (operands[2]) < 32767 && INTVAL (operands[2]) > -32768) + || REGNO (operands[1]) > 11)) + return \"movab %c2(%1),%0\"; + return \"addl2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addl2 %1,%0\"; + + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 32767 + && INTVAL (operands[2]) > -32768 + && GET_CODE (operands[1]) == REG + && push_operand (operands[0], SImode)) + return \"pushab %c2(%1)\"; + + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl3 $%n2,%1,%0\"; + + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) INTVAL (operands[2]) >= 64 + && GET_CODE (operands[1]) == REG + && ((INTVAL (operands[2]) < 32767 && INTVAL (operands[2]) > -32768) + || REGNO (operands[1]) > 11)) + return \"movab %c2(%1),%0\"; + + /* Add this if using gcc on a VAX 3xxx: + if (REG_P (operands[1]) && REG_P (operands[2])) + return \"movab (%1)[%2],%0\"; + */ + return \"addl3 %1,%2,%0\"; +}") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (plus:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incw %0\"; + if (operands[2] == constm1_rtx) + return \"decw %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw2 $%n2,%0\"; + return \"addw2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addw2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw3 $%n2,%1,%0\"; + return \"addw3 %1,%2,%0\"; +}") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (plus:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incb %0\"; + if (operands[2] == constm1_rtx) + return \"decb %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb2 $%n2,%0\"; + return \"addb2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addb2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb3 $%n2,%1,%0\"; + return \"addb3 %1,%2,%0\"; +}") + +;; The add-with-carry (adwc) instruction only accepts two operands. +(define_insn "adddi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=ro>,ro>") + (plus:DI (match_operand:DI 1 "general_operand" "%0,ro>") + (match_operand:DI 2 "general_operand" "Fro,F")))] + "" + "* +{ + rtx low[3]; + const char *pattern; + int carry = 1; + + split_quadword_operands (operands, low, 3); + /* Add low parts. */ + if (rtx_equal_p (operands[0], operands[1])) + { + if (low[2] == const0_rtx) + /* Should examine operand, punt if not POST_INC. */ + pattern = \"tstl %0\", carry = 0; + else if (low[2] == const1_rtx) + pattern = \"incl %0\"; + else + pattern = \"addl2 %2,%0\"; + } + else + { + if (low[2] == const0_rtx) + pattern = \"movl %1,%0\", carry = 0; + else + pattern = \"addl3 %2,%1,%0\"; + } + if (pattern) + output_asm_insn (pattern, low); + if (!carry) + /* If CARRY is 0, we don't have any carry value to worry about. */ + return get_insn_template (CODE_FOR_addsi3, insn); + /* %0 = C + %1 + %2 */ + if (!rtx_equal_p (operands[0], operands[1])) + output_asm_insn ((operands[1] == const0_rtx + ? \"clrl %0\" + : \"movl %1,%0\"), operands); + return \"adwc %2,%0\"; +}") + +;;- All kinds of subtract instructions. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g") + (minus:DF (match_operand:DF 1 "general_operand" "0,gF") + (match_operand:DF 2 "general_operand" "gF,gF")))] + "" + "@ + sub%#2 %2,%0 + sub%#3 %2,%1,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g") + (minus:SF (match_operand:SF 1 "general_operand" "0,gF") + (match_operand:SF 2 "general_operand" "gF,gF")))] + "" + "@ + subf2 %2,%0 + subf3 %2,%1,%0") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g") + (minus:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "general_operand" "g,g")))] + "" + "@ + subl2 %2,%0 + subl3 %2,%1,%0") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g") + (minus:HI (match_operand:HI 1 "general_operand" "0,g") + (match_operand:HI 2 "general_operand" "g,g")))] + "" + "@ + subw2 %2,%0 + subw3 %2,%1,%0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g") + (minus:QI (match_operand:QI 1 "general_operand" "0,g") + (match_operand:QI 2 "general_operand" "g,g")))] + "" + "@ + subb2 %2,%0 + subb3 %2,%1,%0") + +;; The subtract-with-carry (sbwc) instruction only takes two operands. +(define_insn "subdi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=or>,or>") + (minus:DI (match_operand:DI 1 "general_operand" "0,or>") + (match_operand:DI 2 "general_operand" "For,F")))] + "" + "* +{ + rtx low[3]; + const char *pattern; + int carry = 1; + + split_quadword_operands (operands, low, 3); + /* Subtract low parts. */ + if (rtx_equal_p (operands[0], operands[1])) + { + if (low[2] == const0_rtx) + pattern = 0, carry = 0; + else if (low[2] == constm1_rtx) + pattern = \"decl %0\"; + else + pattern = \"subl2 %2,%0\"; + } + else + { + if (low[2] == constm1_rtx) + pattern = \"decl %0\"; + else if (low[2] == const0_rtx) + pattern = get_insn_template (CODE_FOR_movsi, insn), carry = 0; + else + pattern = \"subl3 %2,%1,%0\"; + } + if (pattern) + output_asm_insn (pattern, low); + if (carry) + { + if (!rtx_equal_p (operands[0], operands[1])) + return \"movl %1,%0\;sbwc %2,%0\"; + return \"sbwc %2,%0\"; + /* %0 = %2 - %1 - C */ + } + return get_insn_template (CODE_FOR_subsi3, insn); +}") + +;;- Multiply instructions. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g,g") + (mult:DF (match_operand:DF 1 "general_operand" "0,gF,gF") + (match_operand:DF 2 "general_operand" "gF,0,gF")))] + "" + "@ + mul%#2 %2,%0 + mul%#2 %1,%0 + mul%#3 %1,%2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g,g") + (mult:SF (match_operand:SF 1 "general_operand" "0,gF,gF") + (match_operand:SF 2 "general_operand" "gF,0,gF")))] + "" + "@ + mulf2 %2,%0 + mulf2 %1,%0 + mulf3 %1,%2,%0") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g,g") + (mult:SI (match_operand:SI 1 "general_operand" "0,g,g") + (match_operand:SI 2 "general_operand" "g,0,g")))] + "" + "@ + mull2 %2,%0 + mull2 %1,%0 + mull3 %1,%2,%0") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g,") + (mult:HI (match_operand:HI 1 "general_operand" "0,g,g") + (match_operand:HI 2 "general_operand" "g,0,g")))] + "" + "@ + mulw2 %2,%0 + mulw2 %1,%0 + mulw3 %1,%2,%0") + +(define_insn "mulqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g,g") + (mult:QI (match_operand:QI 1 "general_operand" "0,g,g") + (match_operand:QI 2 "general_operand" "g,0,g")))] + "" + "@ + mulb2 %2,%0 + mulb2 %1,%0 + mulb3 %1,%2,%0") + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (mult:DI (sign_extend:DI + (match_operand:SI 1 "nonimmediate_operand" "g")) + (sign_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "g"))))] + "" + "emul %1,%2,$0,%0") + +(define_insn "" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (plus:DI + (mult:DI (sign_extend:DI + (match_operand:SI 1 "nonimmediate_operand" "g")) + (sign_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "g"))) + (sign_extend:DI (match_operand:SI 3 "nonimmediate_operand" "g"))))] + "" + "emul %1,%2,%3,%0") + +;; 'F' constraint means type CONST_DOUBLE +(define_insn "" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (plus:DI + (mult:DI (sign_extend:DI + (match_operand:SI 1 "nonimmediate_operand" "g")) + (sign_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "g"))) + (match_operand:DI 3 "immediate_operand" "F")))] + "GET_CODE (operands[3]) == CONST_DOUBLE + && CONST_DOUBLE_HIGH (operands[3]) == (CONST_DOUBLE_LOW (operands[3]) >> 31)" + "* +{ + if (CONST_DOUBLE_HIGH (operands[3])) + operands[3] = GEN_INT (CONST_DOUBLE_LOW (operands[3])); + return \"emul %1,%2,%3,%0\"; +}") + +;;- Divide instructions. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g,g") + (div:DF (match_operand:DF 1 "general_operand" "0,gF") + (match_operand:DF 2 "general_operand" "gF,gF")))] + "" + "@ + div%#2 %2,%0 + div%#3 %2,%1,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g,g") + (div:SF (match_operand:SF 1 "general_operand" "0,gF") + (match_operand:SF 2 "general_operand" "gF,gF")))] + "" + "@ + divf2 %2,%0 + divf3 %2,%1,%0") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g") + (div:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "general_operand" "g,g")))] + "" + "@ + divl2 %2,%0 + divl3 %2,%1,%0") + +(define_insn "divhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g") + (div:HI (match_operand:HI 1 "general_operand" "0,g") + (match_operand:HI 2 "general_operand" "g,g")))] + "" + "@ + divw2 %2,%0 + divw3 %2,%1,%0") + +(define_insn "divqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g") + (div:QI (match_operand:QI 1 "general_operand" "0,g") + (match_operand:QI 2 "general_operand" "g,g")))] + "" + "@ + divb2 %2,%0 + divb3 %2,%1,%0") + +;This is left out because it is very slow; +;we are better off programming around the "lack" of this insn. +;(define_insn "divmoddisi4" +; [(set (match_operand:SI 0 "general_operand" "=g") +; (div:SI (match_operand:DI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g"))) +; (set (match_operand:SI 3 "general_operand" "=g") +; (mod:SI (match_operand:DI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g")))] +; "" +; "ediv %2,%1,%0,%3") + +;; Bit-and on the VAX is done with a clear-bits insn. +(define_expand "andsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (and:SI (not:SI (match_operand:SI 1 "general_operand" "")) + (match_operand:SI 2 "general_operand" "")))] + "" + " +{ + rtx op1 = operands[1]; + + /* If there is a constant argument, complement that one. */ + if (GET_CODE (operands[2]) == CONST_INT && GET_CODE (op1) != CONST_INT) + { + operands[1] = operands[2]; + operands[2] = op1; + op1 = operands[1]; + } + + if (GET_CODE (op1) == CONST_INT) + operands[1] = GEN_INT (~INTVAL (op1)); + else + operands[1] = expand_unop (SImode, one_cmpl_optab, op1, 0, 1); +}") + +(define_expand "andhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (and:HI (not:HI (match_operand:HI 1 "general_operand" "")) + (match_operand:HI 2 "general_operand" "")))] + "" + " +{ + rtx op1 = operands[1]; + + if (GET_CODE (operands[2]) == CONST_INT && GET_CODE (op1) != CONST_INT) + { + operands[1] = operands[2]; + operands[2] = op1; + op1 = operands[1]; + } + + if (GET_CODE (op1) == CONST_INT) + operands[1] = GEN_INT (~INTVAL (op1)); + else + operands[1] = expand_unop (HImode, one_cmpl_optab, op1, 0, 1); +}") + +(define_expand "andqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (and:QI (not:QI (match_operand:QI 1 "general_operand" "")) + (match_operand:QI 2 "general_operand" "")))] + "" + " +{ + rtx op1 = operands[1]; + + if (GET_CODE (operands[2]) == CONST_INT && GET_CODE (op1) != CONST_INT) + { + operands[1] = operands[2]; + operands[2] = op1; + op1 = operands[1]; + } + + if (GET_CODE (op1) == CONST_INT) + operands[1] = GEN_INT (~INTVAL (op1)); + else + operands[1] = expand_unop (QImode, one_cmpl_optab, op1, 0, 1); +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g") + (and:SI (not:SI (match_operand:SI 1 "general_operand" "g,g")) + (match_operand:SI 2 "general_operand" "0,g")))] + "" + "@ + bicl2 %1,%0 + bicl3 %1,%2,%0") + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g") + (and:HI (not:HI (match_operand:HI 1 "general_operand" "g,g")) + (match_operand:HI 2 "general_operand" "0,g")))] + "" + "@ + bicw2 %1,%0 + bicw3 %1,%2,%0") + +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g") + (and:QI (not:QI (match_operand:QI 1 "general_operand" "g,g")) + (match_operand:QI 2 "general_operand" "0,g")))] + "" + "@ + bicb2 %1,%0 + bicb3 %1,%2,%0") + +;; The following used to be needed because constant propagation can +;; create them starting from the bic insn patterns above. This is no +;; longer a problem. However, having these patterns allows optimization +;; opportunities in combine.c. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g") + (and:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "const_int_operand" "n,n")))] + "" + "@ + bicl2 %N2,%0 + bicl3 %N2,%1,%0") + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g") + (and:HI (match_operand:HI 1 "general_operand" "0,g") + (match_operand:HI 2 "const_int_operand" "n,n")))] + "" + "@ + bicw2 %H2,%0 + bicw3 %H2,%1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g") + (and:QI (match_operand:QI 1 "general_operand" "0,g") + (match_operand:QI 2 "const_int_operand" "n,n")))] + "" + "@ + bicb2 %B2,%0 + bicb3 %B2,%1,%0") + +;;- Bit set instructions. + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g,g") + (ior:SI (match_operand:SI 1 "general_operand" "0,g,g") + (match_operand:SI 2 "general_operand" "g,0,g")))] + "" + "@ + bisl2 %2,%0 + bisl2 %1,%0 + bisl3 %2,%1,%0") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g,g") + (ior:HI (match_operand:HI 1 "general_operand" "0,g,g") + (match_operand:HI 2 "general_operand" "g,0,g")))] + "" + "@ + bisw2 %2,%0 + bisw2 %1,%0 + bisw3 %2,%1,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g,g") + (ior:QI (match_operand:QI 1 "general_operand" "0,g,g") + (match_operand:QI 2 "general_operand" "g,0,g")))] + "" + "@ + bisb2 %2,%0 + bisb2 %1,%0 + bisb3 %2,%1,%0") + +;;- xor instructions. + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,g,g") + (xor:SI (match_operand:SI 1 "general_operand" "0,g,g") + (match_operand:SI 2 "general_operand" "g,0,g")))] + "" + "@ + xorl2 %2,%0 + xorl2 %1,%0 + xorl3 %2,%1,%0") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g,g,g") + (xor:HI (match_operand:HI 1 "general_operand" "0,g,g") + (match_operand:HI 2 "general_operand" "g,0,g")))] + "" + "@ + xorw2 %2,%0 + xorw2 %1,%0 + xorw3 %2,%1,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g,g,g") + (xor:QI (match_operand:QI 1 "general_operand" "0,g,g") + (match_operand:QI 2 "general_operand" "g,0,g")))] + "" + "@ + xorb2 %2,%0 + xorb2 %1,%0 + xorb3 %2,%1,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=g") + (neg:DF (match_operand:DF 1 "general_operand" "gF")))] + "" + "mneg%# %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=g") + (neg:SF (match_operand:SF 1 "general_operand" "gF")))] + "" + "mnegf %1,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (neg:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mnegl %1,%0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (neg:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mnegw %1,%0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (neg:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mnegb %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (not:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mcoml %1,%0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=g") + (not:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mcomw %1,%0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=g") + (not:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mcomb %1,%0") + +;; Arithmetic right shift on the VAX works by negating the shift count, +;; then emitting a right shift with the shift count negated. This means +;; that all actual shift counts in the RTL will be positive. This +;; prevents converting shifts to ZERO_EXTRACTs with negative positions, +;; which isn't valid. +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2])); +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "const_int_operand" "n")))] + "" + "ashl $%n2,%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (neg:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "ashl %2,%1,%0") + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (operands[2] == const1_rtx && rtx_equal_p (operands[0], operands[1])) + return \"addl2 %0,%0\"; + if (GET_CODE (operands[1]) == REG + && GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if (i == 1) + return \"addl3 %1,%1,%0\"; + if (i == 2) + return \"moval 0[%1],%0\"; + if (i == 3) + return \"movad 0[%1],%0\"; + } + return \"ashl %2,%1,%0\"; +}") + +;; Arithmetic right shift on the VAX works by negating the shift count. +(define_expand "ashrdi3" + [(set (match_operand:DI 0 "general_operand" "=g") + (ashiftrt:DI (match_operand:DI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2])); +}") + +(define_insn "ashldi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (ashift:DI (match_operand:DI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "ashq %2,%1,%0") + +(define_insn "" + [(set (match_operand:DI 0 "nonimmediate_operand" "=g") + (ashiftrt:DI (match_operand:DI 1 "general_operand" "g") + (neg:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "ashq %2,%1,%0") + +;; We used to have expand_shift handle logical right shifts by using extzv, +;; but this make it very difficult to do lshrdi3. Since the VAX is the +;; only machine with this kludge, it's better to just do this with a +;; define_expand and remove that case from expand_shift. + +(define_expand "lshrsi3" + [(set (match_dup 3) + (minus:QI (const_int 32) + (match_dup 4))) + (set (match_operand:SI 0 "general_operand" "=g") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r") + (match_dup 3) + (match_operand:SI 2 "register_operand" "g")))] + "" + " +{ + operands[3] = gen_reg_rtx (QImode); + operands[4] = gen_lowpart (QImode, operands[2]); +}") + +;; Rotate right on the VAX works by negating the shift count. +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotatert:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2])); +}") + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (rotate:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "rotl %2,%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (rotatert:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "const_int_operand" "n")))] + "" + "rotl %R2,%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (rotatert:SI (match_operand:SI 1 "general_operand" "g") + (neg:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "rotl %2,%1,%0") + +;This insn is probably slower than a multiply and an add. +;(define_insn "" +; [(set (match_operand:SI 0 "general_operand" "=g") +; (mult:SI (plus:SI (match_operand:SI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g")) +; (match_operand:SI 3 "general_operand" "g")))] +; "" +; "index %1,$0x80000000,$0x7fffffff,%3,%2,%0") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+ro") + (match_operand:QI 1 "const_int_operand" "n") + (match_operand:SI 2 "const_int_operand" "n")) + (match_operand:SI 3 "general_operand" "g"))] + "(INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0 + && (GET_CODE (operands[0]) == REG + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + if (REG_P (operands[0])) + { + if (INTVAL (operands[2]) != 0) + return \"insv %3,%2,%1,%0\"; + } + else + operands[0] + = adjust_address (operands[0], + INTVAL (operands[1]) == 8 ? QImode : HImode, + INTVAL (operands[2]) / 8); + + CC_STATUS_INIT; + if (INTVAL (operands[1]) == 8) + return \"movb %3,%0\"; + return \"movw %3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=&g") + (zero_extract:SI (match_operand:SI 1 "register_operand" "ro") + (match_operand:QI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[3]) != 0) + return \"extzv %3,%2,%1,%0\"; + } + else + operands[1] + = adjust_address (operands[1], + INTVAL (operands[2]) == 8 ? QImode : HImode, + INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"movzbl %1,%0\"; + return \"movzwl %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extract:SI (match_operand:SI 1 "register_operand" "ro") + (match_operand:QI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[3]) != 0) + return \"extv %3,%2,%1,%0\"; + } + else + operands[1] + = adjust_address (operands[1], + INTVAL (operands[2]) == 8 ? QImode : HImode, + INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"cvtbl %1,%0\"; + return \"cvtwl %1,%0\"; +}") + +;; Register-only SImode cases of bit-field insns. + +(define_insn "" + [(set (cc0) + (compare + (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpv %2,%1,%0,%3") + +(define_insn "" + [(set (cc0) + (compare + (zero_extract:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpzv %2,%1,%0,%3") + +;; When the field position and size are constant and the destination +;; is a register, extv and extzv are much slower than a rotate followed +;; by a bicl or sign extension. Because we might end up choosing ext[z]v +;; anyway, we can't allow immediate values for the primary source operand. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extract:SI (match_operand:SI 1 "register_operand" "ro") + (match_operand:QI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[3]) != CONST_INT || GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[0]) != REG + || (INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16)) + return \"extv %3,%2,%1,%0\"; + if (INTVAL (operands[2]) == 8) + return \"rotl %R3,%1,%0\;cvtbl %0,%0\"; + return \"rotl %R3,%1,%0\;cvtwl %0,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (zero_extract:SI (match_operand:SI 1 "register_operand" "ro") + (match_operand:QI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[3]) != CONST_INT || GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[0]) != REG) + return \"extzv %3,%2,%1,%0\"; + if (INTVAL (operands[2]) == 8) + return \"rotl %R3,%1,%0\;movzbl %0,%0\"; + if (INTVAL (operands[2]) == 16) + return \"rotl %R3,%1,%0\;movzwl %0,%0\"; + if (INTVAL (operands[3]) & 31) + return \"rotl %R3,%1,%0\;bicl2 %M2,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"bicl2 %M2,%0\"; + return \"bicl3 %M2,%1,%0\"; +}") + +;; Non-register cases. +;; nonimmediate_operand is used to make sure that mode-ambiguous cases +;; don't match these (and therefore match the cases above instead). + +(define_insn "" + [(set (cc0) + (compare + (sign_extract:SI (match_operand:QI 0 "memory_operand" "m") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpv %2,%1,%0,%3") + +(define_insn "" + [(set (cc0) + (compare + (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "rm") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpzv %2,%1,%0,%3") + +(define_insn "extv" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (sign_extract:SI (match_operand:QI 1 "memory_operand" "m") + (match_operand:QI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[0]) != REG || GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[3]) != CONST_INT + || (INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16) + || INTVAL (operands[2]) + INTVAL (operands[3]) > 32 + || side_effects_p (operands[1]) + || (GET_CODE (operands[1]) == MEM + && mode_dependent_address_p (XEXP (operands[1], 0)))) + return \"extv %3,%2,%1,%0\"; + if (INTVAL (operands[2]) == 8) + return \"rotl %R3,%1,%0\;cvtbl %0,%0\"; + return \"rotl %R3,%1,%0\;cvtwl %0,%0\"; +}") + +(define_expand "extzv" + [(set (match_operand:SI 0 "general_operand" "") + (zero_extract:SI (match_operand:SI 1 "general_operand" "") + (match_operand:QI 2 "general_operand" "") + (match_operand:SI 3 "general_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (zero_extract:SI (match_operand:QI 1 "memory_operand" "m") + (match_operand:QI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[0]) != REG || GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[3]) != CONST_INT + || INTVAL (operands[2]) + INTVAL (operands[3]) > 32 + || side_effects_p (operands[1]) + || (GET_CODE (operands[1]) == MEM + && mode_dependent_address_p (XEXP (operands[1], 0)))) + return \"extzv %3,%2,%1,%0\"; + if (INTVAL (operands[2]) == 8) + return \"rotl %R3,%1,%0\;movzbl %0,%0\"; + if (INTVAL (operands[2]) == 16) + return \"rotl %R3,%1,%0\;movzwl %0,%0\"; + return \"rotl %R3,%1,%0\;bicl2 %M2,%0\"; +}") + +(define_expand "insv" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")) + (match_operand:SI 3 "general_operand" ""))] + "" + "") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+g") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g"))] + "" + "insv %3,%2,%1,%0") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") + (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g"))] + "" + "insv %3,%2,%1,%0") + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jbr %l0") + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jeql %l0") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jneq %l0") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtr %l0") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtru %l0") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlss %l0") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlssu %l0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgeq %l0") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgequ %l0") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jleq %l0") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlequ %l0") + +;; Recognize reversed jumps. +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(cc0) + (const_int 0)]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "j%C0 %l1") ; %C0 negates condition + +;; Recognize jbs, jlbs, jbc and jlbc instructions. Note that the operand +;; of jlbs and jlbc insns are SImode in the hardware. However, if it is +;; memory, we use QImode in the insn. So we can't use those instructions +;; for mode-dependent addresses. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q,g") + (const_int 1) + (match_operand:SI 1 "general_operand" "I,g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "@ + jlbs %0,%l2 + jbs %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q,g") + (const_int 1) + (match_operand:SI 1 "general_operand" "I,g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "@ + jlbc %0,%l2 + jbc %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r") + (const_int 1) + (match_operand:SI 1 "general_operand" "I,g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "@ + jlbs %0,%l2 + jbs %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r") + (const_int 1) + (match_operand:SI 1 "general_operand" "I,g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "@ + jlbc %0,%l2 + jbc %1,%0,%l2") + +;; Subtract-and-jump and Add-and-jump insns. +;; These are not used when output is for the Unix assembler +;; because it does not know how to modify them to reach far. + +;; Normal sob insns. + +(define_insn "" + [(set (pc) + (if_then_else + (gt (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgtr %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgeq %0,%l1") + +;; Normal aob insns. Define a version for when operands[1] is a constant. +(define_insn "" + [(set (pc) + (if_then_else + (lt (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaoblss %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (lt (match_operand:SI 0 "nonimmediate_operand" "+g") + (match_operand:SI 1 "general_operand" "g")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM && GET_CODE (operands[1]) == CONST_INT" + "jaoblss %P1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (le (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaobleq %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (le (match_operand:SI 0 "nonimmediate_operand" "+g") + (match_operand:SI 1 "general_operand" "g")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM && GET_CODE (operands[1]) == CONST_INT" + "jaobleq %P1,%0,%l2") + +;; Something like a sob insn, but compares against -1. +;; This finds `while (foo--)' which was changed to `while (--foo != -1)'. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (match_operand:SI 0 "nonimmediate_operand" "+g") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "decl %0\;jgequ %l1") + +(define_expand "call_pop" + [(parallel [(call (match_operand:QI 0 "memory_operand" "") + (match_operand:SI 1 "const_int_operand" "")) + (set (reg:SI 14) + (plus:SI (reg:SI 14) + (match_operand:SI 3 "immediate_operand" "")))])] + "" +{ + if (INTVAL (operands[3]) > 255 * 4 || INTVAL (operands[3]) % 4) + abort (); + + /* Operand 1 is the number of bytes to be popped by DW_CFA_GNU_args_size + during EH unwinding. We must include the argument count pushed by + the calls instruction. */ + operands[1] = GEN_INT (INTVAL (operands[3]) + 4); +}) + +(define_insn "*call_pop" + [(call (match_operand:QI 0 "memory_operand" "m") + (match_operand:SI 1 "const_int_operand" "n")) + (set (reg:SI 14) (plus:SI (reg:SI 14) + (match_operand:SI 2 "immediate_operand" "i")))] + "" +{ + operands[1] = GEN_INT ((INTVAL (operands[1]) - 4) / 4); + return "calls %1,%0"; +}) + +(define_expand "call_value_pop" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "") + (match_operand:SI 2 "const_int_operand" ""))) + (set (reg:SI 14) + (plus:SI (reg:SI 14) + (match_operand:SI 4 "immediate_operand" "")))])] + "" +{ + if (INTVAL (operands[4]) > 255 * 4 || INTVAL (operands[4]) % 4) + abort (); + + /* Operand 2 is the number of bytes to be popped by DW_CFA_GNU_args_size + during EH unwinding. We must include the argument count pushed by + the calls instruction. */ + operands[2] = GEN_INT (INTVAL (operands[4]) + 4); +}) + +(define_insn "*call_value_pop" + [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "m") + (match_operand:SI 2 "const_int_operand" "n"))) + (set (reg:SI 14) (plus:SI (reg:SI 14) + (match_operand:SI 3 "immediate_operand" "i")))] + "" + "* +{ + operands[2] = GEN_INT ((INTVAL (operands[2]) - 4) / 4); + return \"calls %2,%1\"; +}") + +(define_expand "call" + [(call (match_operand:QI 0 "memory_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "" + " +{ + /* Operand 1 is the number of bytes to be popped by DW_CFA_GNU_args_size + during EH unwinding. We must include the argument count pushed by + the calls instruction. */ + operands[1] = GEN_INT (INTVAL (operands[1]) + 4); +}") + +(define_insn "*call" + [(call (match_operand:QI 0 "memory_operand" "m") + (match_operand:SI 1 "const_int_operand" ""))] + "" + "calls $0,%0") + +(define_expand "call_value" + [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "" + " +{ + /* Operand 2 is the number of bytes to be popped by DW_CFA_GNU_args_size + during EH unwinding. We must include the argument count pushed by + the calls instruction. */ + operands[2] = GEN_INT (INTVAL (operands[2]) + 4); +}") + +(define_insn "*call_value" + [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "m") + (match_operand:SI 2 "const_int_operand" "")))] + "" + "calls $0,%1") + +;; Call subroutine returning any type. + +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" + " +{ + int i; + + emit_call_insn (gen_call_pop (operands[0], const0_rtx, NULL, const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + + DONE; +}") + +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and +;; all of memory. This blocks insns from being moved across this point. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] VUNSPEC_BLOCKAGE)] + "" + "") + +(define_insn "return" + [(return)] + "" + "ret") + +(define_expand "epilogue" + [(return)] + "" + " +{ + emit_jump_insn (gen_return ()); + DONE; +}") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;; This had a wider constraint once, and it had trouble. +;; If you are tempted to try `g', please don't--it's not worth +;; the risk we will reopen the same bug. +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] + "" + "jmp (%0)") + +;; This is here to accept 5 arguments (as passed by expand_end_case) +;; and pass the first 4 along to the casesi1 pattern that really does the work. +(define_expand "casesi" + [(match_operand:SI 0 "general_operand" "") ; index + (match_operand:SI 1 "general_operand" "") ; lower + (match_operand:SI 2 "general_operand" "") ; upper-lower + (match_operand 3 "" "") ; table label + (match_operand 4 "" "")] ; default label + "" +{ + emit_jump_insn (gen_casesi1 (operands[0], operands[1], + operands[2], operands[3])); + DONE; +}) + +(define_insn "casesi1" + [(set (pc) + (if_then_else + (leu (minus:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (match_operand:SI 2 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (mult:SI (minus:SI (match_dup 0) + (match_dup 1)) + (const_int 2)) + (pc)))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,%1,%2") + +;; This can arise by simplification when operand 1 is a constant int. +(define_insn "" + [(set (pc) + (if_then_else + (leu (plus:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "const_int_operand" "n")) + (match_operand:SI 2 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (mult:SI (plus:SI (match_dup 0) + (match_dup 1)) + (const_int 2)) + (pc)))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "* +{ + operands[1] = GEN_INT (-INTVAL (operands[1])); + return \"casel %0,%1,%2\"; +}") + +;; This can arise by simplification when the base for the case insn is zero. +(define_insn "" + [(set (pc) + (if_then_else (leu (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (mult:SI (match_dup 0) + (const_int 2)) + (pc)))) + (label_ref:SI (match_operand 2 "" ""))) + (pc)))] + "" + "casel %0,$0,%1") + +;;- load or push effective address +;; These come after the move and add/sub patterns +;; because we don't want pushl $1 turned into pushad 1. +;; or addl3 r1,r2,r3 turned into movab 0(r1)[r2],r3. + +;; It does not work to use constraints to distinguish pushes from moves, +;; because < matches any autodecrement, not just a push. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + else + return \"movab %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:HI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaw %a1\"; + else + return \"movaw %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:SI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushal %a1\"; + else + return \"moval %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:DI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaq %a1\"; + else + return \"movaq %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:SF 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaf %a1\"; + else + return \"movaf %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=g") + (match_operand:DF 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushad %a1\"; + else + return \"movad %a1,%0\"; +}") + +;; These used to be peepholes, but it is more straightforward to do them +;; as single insns. However, we must force the output to be a register +;; if it is not an offsettable address so that we know that we can assign +;; to it twice. + +;; If we had a good way of evaluating the relative costs, these could be +;; machine-independent. + +;; Optimize extzv ...,z; andl2 ...,z +;; or ashl ...,z; andl2 ...,z +;; with other operands constant. This is what the combiner converts the +;; above sequences to before attempting to recognize the new insn. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=ro") + (and:SI (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "const_int_operand" "n")) + (match_operand:SI 3 "const_int_operand" "n")))] + "(INTVAL (operands[3]) & ~((1 << (32 - INTVAL (operands[2]))) - 1)) == 0" + "* +{ + unsigned long mask1 = INTVAL (operands[3]); + unsigned long mask2 = (1 << (32 - INTVAL (operands[2]))) - 1; + + if ((mask1 & mask2) != mask1) + operands[3] = GEN_INT (mask1 & mask2); + + return \"rotl %R2,%1,%0\;bicl2 %N3,%0\"; +}") + +;; left-shift and mask +;; The only case where `ashl' is better is if the mask only turns off +;; bits that the ashl would anyways, in which case it should have been +;; optimized away. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=ro") + (and:SI (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "const_int_operand" "n")) + (match_operand:SI 3 "const_int_operand" "n")))] + "" + "* +{ + operands[3] + = GEN_INT (INTVAL (operands[3]) & ~((1 << INTVAL (operands[2])) - 1)); + return \"rotl %2,%1,%0\;bicl2 %N3,%0\"; +}") + +;; Instruction sequence to sync the VAX instruction stream. +(define_insn "sync_istream" + [(unspec_volatile [(const_int 0)] VUNSPEC_SYNC_ISTREAM)] + "" + "movpsl -(%|sp)\;pushal 1(%|pc)\;rei")