+;;
+;; This code is derived from software copyrighted by the Free Software
+;; Foundation.
+;;
+;; Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+;;
+;; @(#)i386.md 6.2 (Berkeley) 5/8/91
+;;
+
+;; GCC machine description for Intel 80386.
+;; Copyright (C) 1988 Free Software Foundation, Inc.
+;; Mostly by William Schelter.
+
+;; 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 1, 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.
+
+
+;;- instruction definitions
+
+;;- @@The original PO technology requires these to be ordered by speed,
+;;- @@ so that assigner will pick the fastest.
+
+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+;;- When naming insn's (operand 0 of define_insn) be careful about using
+;;- names from other targets machine descriptions.
+
+;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code
+;;- updates for most instructions.
+
+;;- Operand classes for the register allocator:
+;;- 'a' for eax
+;;- 'd' for edx
+;;- 'c' for ecx
+;;- 'b' for ebx
+;;- 'f' for anything in FLOAT_REGS
+;;- 'r' any (non-floating-point) register
+;;- 'q' regs that allow byte operations (A, B, C and D)
+;;- 'A' A and D registers
+
+;; the special asm out single letter directives following a '%' are:
+;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of operands[1]
+;; 's' output a '*'
+;; 'w' If the operand is a REG, it uses the mode size to determine the
+;; printing of the reg
+
+\f
+;; Put tstsi first among test insns so it matches a CONST_INT operand.
+
+(define_insn "tstsi"
+ [(set (cc0)
+ (match_operand:SI 0 "general_operand" "rm"))]
+ ""
+ "*
+{
+ operands[1] = const0_rtx;
+ if (REG_P (operands[0]))
+ return AS2 (test%L0,%0,%0);
+ return AS2 (cmp%L0,%1,%0);
+}")
+
+(define_insn "tsthi"
+ [(set (cc0)
+ (match_operand:HI 0 "general_operand" "rm"))]
+ ""
+ "*
+{
+ operands[1] = const0_rtx;
+ if (REG_P (operands[0]))
+ return AS2 (test%W0,%0,%0);
+ return AS2 (cmp%W0,%1,%0);
+}")
+
+(define_insn "tstqi"
+ [(set (cc0)
+ (match_operand:QI 0 "general_operand" "qm"))]
+ ""
+ "*
+{
+ operands[1] = const0_rtx;
+ if (REG_P (operands[0]))
+ return AS2 (test%B0,%0,%0);
+ return AS2 (cmp%B0,%1,%0);
+}")
+
+(define_insn "tstsf"
+ [(set (cc0)
+ (match_operand:SF 0 "general_operand" "rm,f"))
+ (clobber (reg:SI 0))]
+ "TARGET_80387"
+ "*
+{
+ rtx xops[1];
+ if (!FP_REG_P (operands[0]))
+ fp_push_sf (operands[0]);
+/* fp_pop_level--; */
+ xops[0] = FP_TOP;
+ cc_status.flags |= CC_IN_80387;
+ if (FP_REG_P (operands[0]) && ! top_dead_p (insn))
+ output_asm_insn (\"ftst\;fnstsw %R0ax\;sahf\", xops);
+ else
+ output_asm_insn (\"ftst\;fstp %0(0)\;fnstsw %R0ax\;sahf\", xops);
+ RETCOM (testsf);
+}")
+
+(define_insn "tstdf"
+ [(set (cc0)
+ (match_operand:DF 0 "general_operand" "rm,f"))
+ (clobber (reg:SI 0))
+ ]
+ "TARGET_80387"
+ "*
+{
+ rtx xops[1];
+ if (!FP_REG_P (operands[0]))
+ fp_push_df (operands[0]);
+/* fp_pop_level--; */
+ xops[0] = FP_TOP;
+ cc_status.flags |= CC_IN_80387;
+ if (FP_REG_P (operands[0]) && ! top_dead_p (insn))
+ output_asm_insn (\"ftst\;fnstsw %R0ax\;sahf\", xops);
+ else
+ output_asm_insn (\"ftst\;fstp %0(0)\;fnstsw %R0ax\;sahf\", xops);
+ RETCOM (testdf);
+}")
+\f
+;;- compare instructions
+
+;; Put cmpsi first among compare insns so it matches two CONST_INT operands.
+
+(define_insn "cmpsi"
+ [(set (cc0)
+ (compare (match_operand:SI 0 "general_operand" "mr,ri")
+ (match_operand:SI 1 "general_operand" "ri,mr")))]
+ ""
+ "*
+{
+ if (REG_P (operands[1])
+ || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM))
+ {
+ cc_status.flags |= CC_REVERSED;
+ return AS2 (cmp%L0,%0,%1);
+ }
+ return AS2 (cmp%L0,%1,%0);
+}")
+
+(define_insn "cmphi"
+ [(set (cc0)
+ (compare (match_operand:HI 0 "general_operand" "mr,ri")
+ (match_operand:HI 1 "general_operand" "ri,mr")))]
+ ""
+ "*
+{
+ if (REG_P (operands[1])
+ || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM))
+ {
+ cc_status.flags |= CC_REVERSED;
+ return AS2 (cmp%W0,%0,%1);
+ }
+ return AS2 (cmp%W0,%1,%0);
+}")
+
+(define_insn "cmpqi"
+ [(set (cc0)
+ (compare (match_operand:QI 0 "general_operand" "qn,mq")
+ (match_operand:QI 1 "general_operand" "qm,nq")))]
+ ""
+ "*
+{
+ if (REG_P (operands[1])
+ || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM))
+ {
+ cc_status.flags |= CC_REVERSED;
+ return AS2 (cmp%B0,%0,%1);
+ }
+ return AS2 (cmp%B0,%1,%0);
+}")
+
+(define_insn "cmpdf"
+ [(set (cc0)
+ (compare (match_operand:DF 0 "general_operand" "m,f*r,m,f,r,!*r")
+ (match_operand:DF 1 "general_operand" "m,m,f*r,r,f,*r")))
+ (clobber (reg:SI 0))]
+ "TARGET_80387"
+ "*
+{
+ if (FP_REG_P (operands[0]))
+ {
+ rtx tem = operands[1];
+ operands[1] = operands[0];
+ operands[0] = tem;
+ cc_status.flags |= CC_REVERSED;
+ }
+ if (! FP_REG_P (operands[1]))
+ output_movdf (FP_TOP, operands[1]);
+ output_movdf (FP_TOP, operands[0]);
+/* fp_pop_level--;
+ fp_pop_level--; */
+ cc_status.flags |= CC_IN_80387;
+ return \"fcompp\;fnstsw %R0ax\;sahf\";
+}")
+
+(define_insn "cmpsf"
+ [(set (cc0)
+ (compare (match_operand:SF 0 "general_operand" "m,f*r,m,f,r,!*r")
+ (match_operand:SF 1 "general_operand" "m,m,f*r,r,f,*r")))
+ (clobber (reg:SI 0))]
+ "TARGET_80387"
+ "*
+{
+ if (FP_REG_P (operands[0]))
+ {
+ rtx tem = operands[1];
+ operands[1] = operands[0];
+ operands[0] = tem;
+ cc_status.flags |= CC_REVERSED;
+ }
+ if (! FP_REG_P (operands[1]))
+ output_movsf (FP_TOP, operands[1]);
+ output_movsf (FP_TOP, operands[0]);
+/* fp_pop_level--;
+ fp_pop_level--; */
+ cc_status.flags |= CC_IN_80387;
+ return \"fcompp\;fnstsw %R0ax\;sahf\";
+}")
+
+;; logical compare
+(define_insn ""
+ [(set (cc0)
+ (and:SI (match_operand:SI 0 "general_operand" "rm,ri")
+ (match_operand:SI 1 "general_operand" "ri,rm")))]
+ ""
+ "*
+{
+ if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
+ return AS2 (test%L0,%1,%0);
+ return AS2 (test%L0,%0,%1);
+}")
+
+(define_insn ""
+ [(set (cc0)
+ (and:HI (match_operand:HI 0 "general_operand" "rm,ri")
+ (match_operand:HI 1 "general_operand" "ri,rm")))]
+ ""
+ "*
+{
+ if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
+ return AS2 (test%W0,%1,%0);
+ return AS2 (test%W0,%0,%1);
+}")
+
+(define_insn ""
+ [(set (cc0)
+ (and:QI (match_operand:QI 0 "general_operand" "qm,qi")
+ (match_operand:QI 1 "general_operand" "qi,qm")))]
+ ""
+ "*
+{
+ if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
+ return AS2 (test%B0,%1,%0);
+ return AS2 (test%B0,%0,%1);
+}")
+\f
+;; move instructions.
+;; There is one for each machine mode,
+;; and each is preceded by a corresponding push-insn pattern
+;; (since pushes are not general_operands on the 386).
+
+(define_insn ""
+ [(set (match_operand:SI 0 "push_operand" "=<")
+ (match_operand:SI 1 "general_operand" "g"))]
+ ""
+ "push%L0 %1")
+
+;; General case of fullword move.
+(define_insn "movsi"
+ [(set (match_operand:SI 0 "general_operand" "=g,r")
+ (match_operand:SI 1 "general_operand" "ri,m"))]
+ ""
+ "*
+{
+ rtx link;
+ if (operands[1] == const0_rtx && REG_P (operands[0]))
+ return \"xor%L0 %0,%0\";
+ if (operands[1] == const1_rtx
+ && (link = find_reg_note (insn, REG_WAS_0, 0))
+ /* Make sure the insn that stored the 0 is still present. */
+ && ! XEXP (link, 0)->volatil
+ && GET_CODE (XEXP (link, 0)) != NOTE
+ /* Make sure cross jumping didn't happen here. */
+ && no_labels_between_p (XEXP (link, 0), insn))
+ /* Fastest way to change a 0 to a 1. */
+ return \"inc%L0 %0\";
+ return \"mov%L0 %1,%0\";
+}")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "push_operand" "=<")
+ (match_operand:HI 1 "general_operand" "g"))]
+ ""
+ "push%W0 %1")
+
+(define_insn "movhi"
+ [(set (match_operand:HI 0 "general_operand" "=g,r")
+ (match_operand:HI 1 "general_operand" "ri,m"))]
+ ""
+ "*
+{
+ rtx link;
+ if (operands[1] == const0_rtx && REG_P (operands[0]))
+ return \"xor%W0 %0,%0\";
+ if (operands[1] == const1_rtx
+ && (link = find_reg_note (insn, REG_WAS_0, 0))
+ /* Make sure the insn that stored the 0 is still present. */
+ && ! XEXP (link, 0)->volatil
+ && GET_CODE (XEXP (link, 0)) != NOTE
+ /* Make sure cross jumping didn't happen here. */
+ && no_labels_between_p (XEXP (link, 0), insn))
+ /* Fastest way to change a 0 to a 1. */
+ return \"inc%W0 %0\";
+ return \"mov%W0 %1,%0\";
+}")
+
+;; emit_push_insn when it calls move_by_pieces
+;; requires an insn to "push a byte".
+;; But actually we use pushw, which has the effect of rounding
+;; the amount pushed up to a halfword.
+(define_insn ""
+ [(set (match_operand:QI 0 "push_operand" "=<")
+ (match_operand:QI 1 "general_operand" "q"))]
+ ""
+ "*
+{
+ operands[1] = gen_rtx (REG, HImode, REGNO (operands[1]));
+ return \"push%W0 %1\";
+}")
+
+(define_insn "movqi"
+ [(set (match_operand:QI 0 "general_operand" "=q,*r,m")
+ (match_operand:QI 1 "general_operand" "*g,q,qi"))]
+ ""
+ "*
+{
+ rtx link;
+ if (operands[1] == const0_rtx && REG_P (operands[0]))
+ return \"xor%B0 %0,%0\";
+ if (operands[1] == const1_rtx
+ && (link = find_reg_note (insn, REG_WAS_0, 0))
+ /* Make sure the insn that stored the 0 is still present. */
+ && ! XEXP (link, 0)->volatil
+ && GET_CODE (XEXP (link, 0)) != NOTE
+ /* Make sure cross jumping didn't happen here. */
+ && no_labels_between_p (XEXP (link, 0), insn))
+ /* Fastest way to change a 0 to a 1. */
+ return \"inc%B0 %0\";
+ /* If mov%B0 isn't allowed for one of these regs, use mov%W0. */
+ if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1]))
+ return (AS2 (mov%W0,%w1,%w0));
+ return (AS2 (mov%B0,%1,%0));
+}")
+
+; I suspect nothing can ever match this ???
+;(define_insn ""
+; [(set (match_operand:SF 0 "general_operand" "rm")
+; (match_operand:SF 1 "general_operand" "f"))
+; (clobber (reg:SF 8))]
+; ""
+; "*
+;{
+; output_asm_insn ("???", operands);
+; fpop_sf (operands[0]);
+; RETCOM (movsf_clobber);
+;}")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "push_operand" "=<,<")
+ (match_operand:SF 1 "general_operand" "gF,f"))]
+ ""
+ "*
+{
+ if (FP_REG_P (operands[1]))
+ {
+ rtx xops[3];
+ xops[0] = AT_SP (SFmode);
+ xops[1] = gen_rtx (CONST_INT, VOIDmode, 4);
+ xops[2] = stack_pointer_rtx;
+/* fp_pop_level--; */
+ output_asm_insn (AS2 (sub%L0,%1,%2), xops);
+ if (top_dead_p (insn))
+ output_asm_insn (\"fstp%S0 %0\", xops);
+ else
+ output_asm_insn (\"fst%S0 %0\", xops);
+ RET;
+ }
+ return \"push%L0 %1\";
+}")
+
+(define_insn "movsf"
+ ;; `rf' is duplicated in the second alternative
+ ;; to make sure an optional reload is generated
+ ;; for the memref in operand 0. Otherwise
+ ;; we could use too many hard regs.
+ [(set (match_operand:SF 0 "general_operand" "=rf,mrf,!rm")
+ (match_operand:SF 1 "general_operand" "mrf,rf,F"))]
+ ""
+ "*
+{
+ if (FP_REG_P (operands[1])
+ && !FP_REG_P (operands[0])
+ && !top_dead_p (insn))
+ fp_store_sf (operands[0]);
+ else
+ output_movsf (operands[0], operands[1]);
+ RETCOM (movsf);
+}")
+
+;;should change to handle the memory operands[1] without doing df push..
+(define_insn ""
+ [(set (match_operand:DF 0 "push_operand" "=<,<")
+ (match_operand:DF 1 "general_operand" "gF,f"))]
+ ""
+ "*
+{
+ if (FP_REG_P (operands[1]))
+ {
+ rtx xops[3];
+ xops[0] = AT_SP (DFmode);
+ xops[1] = gen_rtx (CONST_INT, VOIDmode, 8);
+ xops[2] = stack_pointer_rtx;
+/* fp_pop_level--; */
+ output_asm_insn (AS2 (sub%L0,%1,%2), xops);
+ if (top_dead_p(insn))
+ output_asm_insn (\"fstp%Q0 %0\", xops);
+ else
+ output_asm_insn (\"fst%Q0 %0\", xops);
+ RETCOM (pushdf);
+ }
+ else
+ return output_move_double (operands);
+}")
+
+(define_insn "movdf"
+ [(set (match_operand:DF 0 "general_operand" "=rmf,&fr,!rm")
+ ;; `rf' is duplicated in the second alternative
+ ;; to make sure that optional reloads are generated
+ ;; for the memory reference in operand 1.
+ (match_operand:DF 1 "general_operand" "fr,mrf,F"))]
+ ""
+ "*
+{
+ if (FP_REG_P (operands[1])
+ && ! FP_REG_P (operands[0])
+ && ! top_dead_p (insn))
+ fp_store_df (operands[0]);
+ else
+ output_movdf (operands[0], operands[1]);
+ RETCOM (movdf);
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "push_operand" "=<")
+ (match_operand:DI 1 "general_operand" "roiF"))]
+ ""
+ "*
+{
+ return output_move_double (operands);
+}")
+
+(define_insn "movdi"
+ [(set (match_operand:DI 0 "general_operand" "=&r,rm")
+ (match_operand:DI 1 "general_operand" "m,riF"))]
+ ""
+ "*
+{
+ return output_move_double (operands);
+}")
+\f
+;; These go after the move instructions
+;; because the move instructions are better (require no spilling)
+;; when they can apply. But these go before the add and subtract insns
+;; because it is often shorter to use these when both apply.
+
+;Lennart Augustsson <augustss@cs.chalmers.se>
+;says this pattern just makes slower code:
+; pushl %ebp
+; addl $-80,(%esp)
+;instead of
+; leal -80(%ebp),%eax
+; pushl %eax
+;
+;(define_insn ""
+; [(set (match_operand:SI 0 "push_operand" "=<")
+; (plus:SI (match_operand:SI 1 "general_operand" "%r")
+; (match_operand:SI 2 "general_operand" "ri")))]
+; ""
+; "*
+;{
+; rtx xops[4];
+; xops[0] = operands[0];
+; xops[1] = operands[1];
+; xops[2] = operands[2];
+; xops[3] = gen_rtx (MEM, SImode, stack_pointer_rtx);
+; output_asm_insn (\"push%z1 %1\", xops);
+; output_asm_insn (AS2 (add%z3,%2,%3), xops);
+; RET;
+;}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (plus:SI (match_operand:SI 1 "general_operand" "0")
+ (const_int 1)))]
+ ""
+ "inc%L0 %0")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (plus:SI (match_operand:SI 1 "general_operand" "0")
+ (const_int -1)))]
+ ""
+ "dec%L0 %0")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (minus:SI (match_operand:SI 1 "general_operand" "0")
+ (const_int 1)))]
+ ""
+ "dec%L0 %0")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operand:QI 1 "address_operand" "p"))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ /* Adding a constant to a register is faster with an add. */
+ if (GET_CODE (operands[1]) == PLUS
+ && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
+ && rtx_equal_p (operands[0], XEXP (operands[1], 0)))
+ {
+ operands[1] = XEXP (operands[1], 1);
+ return AS2 (add%L0,%1,%0);
+ }
+ return \"lea%L0 %a1,%0\";
+}")
+\f
+;;- conversion instructions
+;;- NONE
+
+;;- truncation instructions
+(define_insn "truncsiqi2"
+ [(set (match_operand:QI 0 "general_operand" "=q,m")
+ (truncate:QI
+ (match_operand:SI 1 "general_operand" "qim,qn")))]
+ ""
+ "*
+{
+ if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT)
+ return \"mov%L0 %1,%k0\";
+ return \"mov%B0 %b1,%0\";
+}")
+
+(define_insn "trunchiqi2"
+ [(set (match_operand:QI 0 "general_operand" "=q,m")
+ (truncate:QI
+ (match_operand:HI 1 "general_operand" "qim,qn")))]
+ ""
+ "*
+{
+ if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT)
+ return \"mov%W0 %1,%w0\";
+ return \"mov%B0 %b1,%0\";
+}")
+
+(define_insn "truncsihi2"
+ [(set (match_operand:HI 0 "general_operand" "=r,m")
+ (truncate:HI
+ (match_operand:SI 1 "general_operand" "rim,rn")))]
+ ""
+ "*
+{
+ if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT)
+ return \"mov%L0 %1,%k0\";
+ return \"mov%W0 %w1,%0\";
+}")
+\f
+;;- zero extension instructions
+;; Note that the one starting from HImode comes before those for QImode
+;; so that a constant operand will match HImode, not QImode.
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "general_operand" "=r")
+ (zero_extend:SI
+ (match_operand:HI 1 "general_operand" "rm")))]
+ ""
+ "movz%W0%L0 %1,%0")
+
+(define_insn "zero_extendqihi2"
+ [(set (match_operand:HI 0 "general_operand" "=r")
+ (zero_extend:HI
+ (match_operand:QI 1 "general_operand" "qm")))]
+ ""
+ "movz%B0%W0 %1,%0")
+
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "general_operand" "=r")
+ (zero_extend:SI
+ (match_operand:QI 1 "general_operand" "qm")))]
+ ""
+ "movz%B0%L0 %1,%0")
+\f
+;;- sign extension instructions
+;; Note that the one starting from HImode comes before those for QImode
+;; so that a constant operand will match HImode, not QImode.
+
+/*
+(define_insn "extendsidi2"
+ [(set (match_operand:DI 0 "general_operand" "=a")
+ (sign_extend:DI
+ (match_operand:SI 1 "general_operand" "a")))]
+ ""
+ "clq")
+*/
+
+;; Note that the i386 programmers' manual says that the opcodes
+;; are named movsx..., but the assembler on Unix does not accept that.
+;; We use what the Unix assembler expects.
+
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "general_operand" "=r")
+ (sign_extend:SI
+ (match_operand:HI 1 "general_operand" "rm")))]
+ ""
+ "movs%W0%L0 %1,%0")
+
+(define_insn "extendqihi2"
+ [(set (match_operand:HI 0 "general_operand" "=r")
+ (sign_extend:HI
+ (match_operand:QI 1 "general_operand" "qm")))]
+ ""
+ "movs%B0%W0 %1,%0")
+
+(define_insn "extendqisi2"
+ [(set (match_operand:SI 0 "general_operand" "=r")
+ (sign_extend:SI
+ (match_operand:QI 1 "general_operand" "qm")))]
+ ""
+ "movs%B0%L0 %1,%0"
+ )
+\f
+;; Conversions between float and double.
+
+(define_insn "extendsfdf2"
+ [(set (match_operand:DF 0 "general_operand" "=fm,f,fm,fm")
+ (float_extend:DF
+ (match_operand:SF 1 "general_operand" "m,0,f,!*r")))]
+ "TARGET_80387"
+ "*
+{
+ if (FP_REG_P (operands[0]))
+ {
+ output_movsf (operands[0], operands[1]);
+ RET;
+ }
+ if (FP_REG_P (operands[1]))
+ {
+ if (top_dead_p (insn))
+ fp_pop_df (operands[0]);
+ else
+ fp_store_df (operands[0]);
+ RET;
+ }
+ output_movsf (FP_TOP, operands[1]);
+ fp_pop_df (operands[0]);
+ RETCOM (extendsfdf2);
+}")
+
+;; This cannot output into an f-reg because there is no way to be
+;; sure of truncating in that case.
+(define_insn "truncdfsf2"
+ [(set (match_operand:SF 0 "general_operand" "=m,!*r")
+ (float_truncate:SF
+ (match_operand:DF 1 "general_operand" "f,f")))]
+ "TARGET_80387"
+ "*
+{
+ if (top_dead_p (insn))
+ fp_pop_sf (operands[0]);
+ else
+ fp_store_sf (operands[0]);
+ RETCOM (truncdfsf2);
+}")
+\f
+;; Conversion between fixed point and floating point.
+;; Note that among the fix-to-float insns
+;; the ones that start with SImode come first.
+;; That is so that an operand that is a CONST_INT
+;; (and therefore lacks a specific machine mode).
+;; will be recognized as SImode (which is always valid)
+;; rather than as QImode or HImode. The 80387 would not know
+;; what to do with the smaller sizes anyway. (I think).
+
+(define_insn "floatsisf2"
+ [(set (match_operand:SF 0 "general_operand" "=fm,fm")
+ (float:SF (match_operand:SI 1 "general_operand" "m,!*r")))]
+ "TARGET_80387"
+ "*
+{
+/* fp_pop_level++; */
+
+ if (GET_CODE (operands[1]) != MEM)
+ {
+ rtx xops[2];
+ output_asm_insn (\"push%L0 %1\", operands);
+ operands[1] = AT_SP (SImode);
+ output_asm_insn (\"fild%L0 %1\", operands);
+ xops[0] = stack_pointer_rtx;
+ xops[1] = gen_rtx (CONST_INT, VOIDmode, 4);
+ output_asm_insn (AS2 (add%L0,%1,%0), xops);
+ }
+ else
+ output_asm_insn (\"fild%L0 %1\", operands);
+
+ if (! FP_REG_P (operands[0]))
+ {
+/* fp_pop_level--; */
+ return \"fstp%S0 %0\";
+ }
+ RET;
+}")
+
+(define_insn "floatsidf2"
+ [(set (match_operand:DF 0 "general_operand" "=fm,fm")
+ (float:DF (match_operand:SI 1 "general_operand" "m,!*r")))]
+ "TARGET_80387"
+ "*
+{
+/* fp_pop_level++; */
+ if (GET_CODE (operands[1]) != MEM)
+ {
+ rtx xops[2];
+ output_asm_insn (\"push%L0 %1\", operands);
+ operands[1] = AT_SP (SImode);
+ output_asm_insn (\"fild%L0 %1\", operands);
+ xops[0] = stack_pointer_rtx;
+ xops[1] = gen_rtx (CONST_INT, VOIDmode, 4);
+ output_asm_insn (AS2 (add%L0,%1,%0), xops);
+ }
+ else
+ output_asm_insn (\"fild%L0 %1\", operands);
+ if (! FP_REG_P (operands[0]))
+ {
+/* fp_pop_level--; */
+ return \"fstp%Q0 %0\";
+ }
+ RET;
+}")
+\f
+;; Convert a float to a float whose value is an integer.
+;; This is the first stage of converting it to an integer type.
+
+;; On the 387 truncating doub to an short integer shor can be performed:
+
+; fstcw -4(%esp) ;save cw
+; movw -4(%esp),%ax
+; orw $0x0c00,%ax ;set rounding to chop towards zero
+; movw %ax,-2(%esp) ;
+; fldcw -2(%esp) ;
+; fldl doubl
+; fistpl -12(%esp) ;store the round value
+; fldcw -4(%esp) ;restore cw
+; movl -12(%esp),%eax
+; movw %ax,shor ; move the result into shor.
+
+;; but it is probably better to have a call, rather than waste this
+;; space. The last instruction would have been a movl if were
+;; going to an int instead of a short.
+;; For the moment we will go with the soft float for these.
+
+/* These are incorrect since they don't set the rounding bits of CW flag.
+ The proper way to do that is to make the function prologue save the CW
+ and also construct the alternate CW value needed for these insns.
+ Then these insns can output two fldcw's, referring to fixed places in
+ the stack frame.
+
+;; Convert a float whose value is an integer
+;; to an actual integer. Second stage of converting float to integer type.
+
+(define_insn "fix_truncsfqi2"
+ [(set (match_operand:QI 0 "general_operand" "=m,?*q")
+ (fix:QI (fix:SF (match_operand:SF 1 "general_operand" "f,f"))))]
+ "TARGET_80387"
+ "*
+{
+ fp_pop_int (operands[0]);
+ RET;
+}")
+
+(define_insn "fix_truncsfhi2"
+ [(set (match_operand:HI 0 "general_operand" "=m,?*r")
+ (fix:HI (fix:SF (match_operand:SF 1 "general_operand" "f,f"))))]
+ "TARGET_80387"
+ "*
+{
+ fp_pop_int (operands[0]);
+ RET;
+}")
+
+(define_insn "fix_truncsfsi2"
+ [(set (match_operand:SI 0 "general_operand" "=m,?*r")
+ (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "f,f"))))]
+ "TARGET_80387"
+ "*
+{
+ fp_pop_int (operands[0]);
+ RET;
+}")
+
+(define_insn "fix_truncdfqi2"
+ [(set (match_operand:QI 0 "general_operand" "=m,?*q")
+ (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "f,f"))))]
+
+ "TARGET_80387"
+ "*
+{
+ fp_pop_int (operands[0]);
+ RET;
+}")
+
+
+(define_insn "fix_truncdfhi2"
+ [(set (match_operand:HI 0 "general_operand" "=m,?*r")
+ (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "f,f"))))]
+ "TARGET_80387"
+ "*
+{
+ fp_pop_int (operands[0]);
+ RET;
+}")
+
+
+(define_insn "fix_truncdfsi2"
+ [(set (match_operand:SI 0 "general_operand" "=m,?*r")
+ (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "f,f"))))]
+ "TARGET_80387"
+ "*
+{
+ fp_pop_int (operands[0]);
+ RET;
+}")
+*/
+
+\f
+;;- add instructions
+;;moved incl to above leal
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "general_operand" "=rm,r")
+ (plus:SI (match_operand:SI 1 "general_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "ri,rm")))]
+ ""
+ "add%L0 %2,%0")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "general_operand" "=g")
+ (plus:HI (match_operand:HI 1 "general_operand" "0")
+ (const_int 1)))]
+ ""
+ "inc%W0 %0")
+
+(define_insn "addhi3"
+ [(set (match_operand:HI 0 "general_operand" "=rm,r")
+ (plus:HI (match_operand:HI 1 "general_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "ri,rm")))]
+ ""
+ "add%W0 %2,%0")
+
+(define_insn ""
+ [(set (match_operand:QI 0 "general_operand" "=qm")
+ (plus:QI (match_operand:QI 1 "general_operand" "0")
+ (const_int 1)))]
+ ""
+ "inc%B0 %0")
+
+(define_insn "addqi3"
+ [(set (match_operand:QI 0 "general_operand" "=m,q")
+ (plus:QI (match_operand:QI 1 "general_operand" "%0,0")
+ (match_operand:QI 2 "general_operand" "qn,qmn")))]
+ ""
+ "add%B0 %2,%0")
+
+;;had "fmF,m"
+
+(define_insn "adddf3"
+ [(set (match_operand:DF 0 "general_operand" "=f,m,f")
+ (plus:DF (match_operand:DF 1 "general_operand" "%0,0,0")
+ (match_operand:DF 2 "general_operand" "m,!f,!*r")))]
+ "TARGET_80387"
+ "*FP_CALL (\"fadd%z0 %0\", \"fadd%z0 %0\", 2)")
+
+(define_insn "addsf3"
+ [(set (match_operand:SF 0 "general_operand" "=f,m,f")
+ (plus:SF (match_operand:SF 1 "general_operand" "%0,0,0")
+ (match_operand:SF 2 "general_operand" "m,!f,!*r")))]
+ "TARGET_80387"
+ "*FP_CALL (\"fadd%z0 %0\", \"fadd%z0 %0\", 2)")
+\f
+;;- subtract instructions
+
+;;moved decl above leal
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "general_operand" "=rm,r")
+ (minus:SI (match_operand:SI 1 "general_operand" "0,0")
+ (match_operand:SI 2 "general_operand" "ri,rm")))]
+ ""
+ "sub%L0 %2,%0")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "general_operand" "=g")
+ (minus:HI (match_operand:HI 1 "general_operand" "0")
+ (const_int 1)))]
+ ""
+ "dec%W0 %0")
+
+(define_insn "subhi3"
+ [(set (match_operand:HI 0 "general_operand" "=rm,r")
+ (minus:HI (match_operand:HI 1 "general_operand" "0,0")
+ (match_operand:HI 2 "general_operand" "ri,rm")))]
+ ""
+ "sub%W0 %2,%0")
+
+(define_insn ""
+ [(set (match_operand:QI 0 "general_operand" "=qm")
+ (minus:QI (match_operand:QI 1 "general_operand" "0")
+ (const_int 1)))]
+ ""
+ "dec%B0 %0")
+
+(define_insn "subqi3"
+ [(set (match_operand:QI 0 "general_operand" "=m,q")
+ (minus:QI (match_operand:QI 1 "general_operand" "0,0")
+ (match_operand:QI 2 "general_operand" "qn,qmn")))]
+ ""
+ "sub%B0 %2,%0")
+
+(define_insn "subdf3"
+ [(set (match_operand:DF 0 "general_operand" "=f,m,f,f")
+ (minus:DF (match_operand:DF 1 "general_operand" "0,0,0,m")
+ (match_operand:DF 2 "general_operand" "m,!f,!*r,*0")))]
+ "TARGET_80387"
+ "*FP_CALL (\"fsub%z0 %0\", \"fsubr%z0 %0\", 2)")
+
+
+(define_insn "subsf3"
+ [(set (match_operand:SF 0 "general_operand" "=f,m,f,f")
+ (minus:SF (match_operand:SF 1 "general_operand" "0,0,0,m")
+ (match_operand:SF 2 "general_operand" "m,!f,!*r,*0")))]
+ "TARGET_80387"
+ "*FP_CALL (\"fsub%z0 %0\", \"fsubr%z0 %0\", 2)")
+\f
+;;- multiply instructions
+
+;(define_insn "mulqi3"
+; [(set (match_operand:QI 0 "general_operand" "=a")
+; (mult:QI (match_operand:QI 1 "general_operand" "%0")
+; (match_operand:QI 2 "general_operand" "qm")))]
+; ""
+; "mul%B0 %2,%0")
+
+(define_insn "mulhi3"
+ [(set (match_operand:HI 0 "general_operand" "=r,r")
+ (mult:SI (match_operand:HI 1 "general_operand" "%0,rm")
+ (match_operand:HI 2 "general_operand" "g,i")))]
+ ""
+ "*
+{
+ if (GET_CODE (operands[1]) == REG
+ && REGNO (operands[1]) == REGNO (operands[0])
+ && (GET_CODE (operands[2]) == MEM
+ || GET_CODE (operands[2]) == REG))
+ /* Assembler has weird restrictions. */
+ return AS2 (imul%W0,%2,%0);
+ return AS3 (imul%W0,%2,%1,%0);
+}")
+
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "general_operand" "=r,r")
+ (mult:SI (match_operand:SI 1 "general_operand" "%0,rm")
+ (match_operand:SI 2 "general_operand" "g,i")))]
+ ""
+ "*
+{
+ if (GET_CODE (operands[1]) == REG
+ && REGNO (operands[1]) == REGNO (operands[0])
+ && (GET_CODE (operands[2]) == MEM
+ || GET_CODE (operands[2]) == REG))
+ /* Assembler has weird restrictions. */
+ return AS2 (imul%L0,%2,%0);
+ return AS3 (imul%L0,%2,%1,%0);
+}")
+
+;; Turned off due to possible assembler bug.
+;(define_insn "umulqi3"
+; [(set (match_operand:QI 0 "general_operand" "=a")
+; (umult:QI (match_operand:QI 1 "general_operand" "%0")
+; (match_operand:QI 2 "general_operand" "qm")))]
+; ""
+; "mul%B0 %2,%0")
+
+;(define_insn "umulqihi3"
+; [(set (match_operand:HI 0 "general_operand" "=a")
+; (umult:HI (match_operand:QI 1 "general_operand" "%0")
+; (match_operand:QI 2 "general_operand" "qm")))]
+; ""
+; "mul%B0 %2,%0")
+
+(define_insn "umulhi3"
+ [(set (match_operand:HI 0 "general_operand" "=a")
+ (umult:SI (match_operand:HI 1 "general_operand" "%0")
+ (match_operand:HI 2 "general_operand" "rm")))
+ (clobber (reg:HI 1))]
+ ""
+ "mul%W0 %2,%0")
+
+(define_insn "umulsi3"
+ [(set (match_operand:SI 0 "general_operand" "=a")
+ (umult:SI (match_operand:SI 1 "general_operand" "%0")
+ (match_operand:SI 2 "general_operand" "rm")))
+ (clobber (reg:SI 1))]
+ ""
+ "mul%L0 %2,%0")
+
+(define_insn "muldf3"
+ [(set (match_operand:DF 0 "general_operand" "=f,m,f")
+ (mult:DF (match_operand:DF 1 "general_operand" "%0,0,0")
+ (match_operand:DF 2 "general_operand" "m,!f,!*r")))]
+ "TARGET_80387"
+ "*FP_CALL (\"fmul%z0 %0\", \"fmul%z0 %0\", 2)
+")
+
+(define_insn "mulsf3"
+ [(set (match_operand:SF 0 "general_operand" "=f,m,f")
+ (mult:SF (match_operand:SF 1 "general_operand" "%0,0,0")
+ (match_operand:SF 2 "general_operand" "m,!f,!*r")))]
+ "TARGET_80387"
+ "*FP_CALL (\"fmul%z0 %0\", \"fmul%z0 %0\", 2)
+")
+\f
+;;- divide instructions
+(define_insn "divdf3"
+ [(set (match_operand:DF 0 "general_operand" "=f,m,f,f")
+ (div:DF (match_operand:DF 1 "general_operand" "0,0,0,m")
+ (match_operand:DF 2 "general_operand" "m,!f,!*r,*0")))]
+ "TARGET_80387"
+ "*FP_CALL (\"fdiv%z0 %0\", \"fdivr%z0 %0\", 2)
+")
+
+(define_insn "divsf3"
+ [(set (match_operand:SF 0 "general_operand" "=f,m,f,f")
+ (div:SF (match_operand:SF 1 "general_operand" "0,0,0,m")
+ (match_operand:SF 2 "general_operand" "m,!f,!*r,*0")))]
+ "TARGET_80387"
+ "*FP_CALL (\"fdiv%z0 %0\", \"fdivr%z0 %0\", 2)
+")
+\f
+;; Remainder instructions.
+
+(define_insn "divmodsi4"
+ [(set (match_operand:SI 0 "general_operand" "=a")
+ (div:SI (match_operand:SI 1 "general_operand" "0")
+ (match_operand:SI 2 "general_operand" "rm")))
+ (set (match_operand:SI 3 "general_operand" "=&d")
+ (mod:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "cltd\;idiv%L0 %2")
+
+(define_insn "udivmodsi4"
+ [(set (match_operand:SI 0 "general_operand" "=a")
+ (udiv:SI (match_operand:SI 1 "general_operand" "0")
+ (match_operand:SI 2 "general_operand" "rm")))
+ (set (match_operand:SI 3 "general_operand" "=&d")
+ (umod:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "xor%L0 %3,%3\;div%L0 %2")
+
+/*
+;;this should be a valid double division which we may want to add
+
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=a")
+ (udiv:DI (match_operand:DI 1 "general_operand" "a")
+ (match_operand:SI 2 "general_operand" "rm")))
+ (set (match_operand:SI 3 "general_operand" "=d")
+ (umod:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "div%L0 %2,%0")
+*/
+\f
+;;- and instructions
+
+;; The `r' in `rm' for operand 3 looks redundant, but it causes
+;; optional reloads to be generated if op 3 is a pseudo in a stack slot.
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "general_operand" "=rm,r")
+ (and:SI (match_operand:SI 1 "general_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "ri,rm")))]
+ ""
+ "and%L0 %2,%0")
+
+(define_insn "andhi3"
+ [(set (match_operand:HI 0 "general_operand" "=rm,r")
+ (and:HI (match_operand:HI 1 "general_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "ri,rm")))]
+ ""
+ "and%W0 %2,%0")
+
+(define_insn "andqi3"
+ [(set (match_operand:QI 0 "general_operand" "=m,q")
+ (and:QI (match_operand:QI 1 "general_operand" "%0,0")
+ (match_operand:QI 2 "general_operand" "qn,qmn")))]
+ ""
+ "and%B0 %2,%0")
+
+/* I am nervous about these two.. add them later..
+;I presume this means that we have something in say op0= eax which is small
+;and we want to and it with memory so we can do this by just an
+;andb m,%al and have success.
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=r")
+ (and:SI (zero_extend:SI (match_operand:HI 1 "general_operand" "rm"))
+ (match_operand:SI 2 "general_operand" "0")))]
+ "GET_CODE (operands[2]) == CONST_INT
+ && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (HImode))"
+ "and%W0 %1,%0")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=q")
+ (and:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "qm"))
+ (match_operand:SI 2 "general_operand" "0")))]
+ "GET_CODE (operands[2]) == CONST_INT
+ && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))"
+ "and%L0 %1,%0")
+
+*/
+
+
+\f
+;;- Bit set (inclusive or) instructions
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "general_operand" "=rm,r")
+ (ior:SI (match_operand:SI 1 "general_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "ri,rm")))]
+ ""
+ "or%L0 %2,%0")
+
+(define_insn "iorhi3"
+ [(set (match_operand:HI 0 "general_operand" "=rm,r")
+ (ior:HI (match_operand:HI 1 "general_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "ri,rm")))]
+ ""
+ "or%W0 %2,%0")
+
+(define_insn "iorqi3"
+ [(set (match_operand:QI 0 "general_operand" "=m,q")
+ (ior:QI (match_operand:QI 1 "general_operand" "%0,0")
+ (match_operand:QI 2 "general_operand" "qn,qmn")))]
+ ""
+ "or%B0 %2,%0")
+\f
+;;- xor instructions
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "general_operand" "=rm,r")
+ (xor:SI (match_operand:SI 1 "general_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "ri,rm")))]
+ ""
+ "xor%L0 %2,%0")
+
+(define_insn "xorhi3"
+ [(set (match_operand:HI 0 "general_operand" "=rm,r")
+ (xor:HI (match_operand:HI 1 "general_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "ri,rm")))]
+ ""
+ "xor%W0 %2,%0")
+
+(define_insn "xorqi3"
+ [(set (match_operand:QI 0 "general_operand" "=qm")
+ (xor:QI (match_operand:QI 1 "general_operand" "%0")
+ (match_operand:QI 2 "general_operand" "qn")))]
+ ""
+ "xor%B0 %2,%0")
+\f
+;;- negation instructions
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "general_operand" "=rm")
+ (neg:SI (match_operand:SI 1 "general_operand" "0")))]
+ ""
+ "neg%L0 %0")
+
+(define_insn "neghi2"
+ [(set (match_operand:HI 0 "general_operand" "=rm")
+ (neg:HI (match_operand:HI 1 "general_operand" "0")))]
+ ""
+ "neg%W0 %0")
+
+(define_insn "negqi2"
+ [(set (match_operand:QI 0 "general_operand" "=qm")
+ (neg:QI (match_operand:QI 1 "general_operand" "0")))]
+ ""
+ "neg%B0 %0")
+
+(define_insn "negsf2"
+ [(set (match_operand:SF 0 "general_operand" "=f,!m")
+ (neg:SF (match_operand:SF 1 "general_operand" "0,0")))]
+ "TARGET_80387"
+ "*FP_CALL1 (\"fchs\")")
+
+(define_insn "negdf2"
+ [(set (match_operand:DF 0 "general_operand" "=f,!m")
+ (neg:DF (match_operand:DF 1 "general_operand" "0,0")))]
+ "TARGET_80387"
+ "*FP_CALL1 (\"fchs\")")
+\f
+;; Absolute value instructions
+
+(define_insn "abssf2"
+ [(set (match_operand:SF 0 "general_operand" "=f,!m")
+ (abs:SF (match_operand:SF 1 "general_operand" "0,0")))]
+ "TARGET_80387"
+ "*FP_CALL1 (\"fabs\")")
+
+(define_insn "absdf2"
+ [(set (match_operand:DF 0 "general_operand" "=f,!m")
+ (abs:DF (match_operand:DF 1 "general_operand" "0,0")))]
+ "TARGET_80387"
+ "*FP_CALL1 (\"fabs\")")
+\f
+;;- one complement instructions
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "general_operand" "=rm")
+ (not:SI (match_operand:SI 1 "general_operand" "0")))]
+ ""
+ "not%L0 %0")
+
+(define_insn "one_cmplhi2"
+ [(set (match_operand:HI 0 "general_operand" "=rm")
+ (not:HI (match_operand:HI 1 "general_operand" "0")))]
+ ""
+ "not%W0 %0")
+
+(define_insn "one_cmplqi2"
+ [(set (match_operand:QI 0 "general_operand" "=qm")
+ (not:QI (match_operand:QI 1 "general_operand" "0")))]
+ ""
+ "not%B0 %0")
+\f
+;;- arithmetic shift instructions
+
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "general_operand" "=rm")
+ (ashift:SI (match_operand:SI 1 "general_operand" "0")
+ (match_operand:SI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (sal%L0,%R0cl,%0);
+ else if (REG_P (operands[1]) && GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == 1)
+ return AS2 (add%L0,%1,%1);
+ return AS2 (sal%L0,%2,%1);
+}")
+
+(define_insn "ashlhi3"
+ [(set (match_operand:HI 0 "general_operand" "=rm")
+ (ashift:HI (match_operand:HI 1 "general_operand" "0")
+ (match_operand:HI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (sal%W0,%R0cl,%0);
+ else
+ return AS2 (sal%W0,%2,%1);
+}")
+
+(define_insn "ashlqi3"
+ [(set (match_operand:QI 0 "general_operand" "=qm")
+ (ashift:QI (match_operand:QI 1 "general_operand" "0")
+ (match_operand:QI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (sal%B0,%R0cl,%0);
+ else
+ return AS2 (sal%B0,%2,%1);
+}")
+
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "general_operand" "=rm")
+ (ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
+ (match_operand:SI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (sar%L0,%R0cl,%0);
+ else
+ return AS2 (sar%L0,%2,%0);
+}")
+
+(define_insn "ashrhi3"
+ [(set (match_operand:HI 0 "general_operand" "=rm")
+ (ashiftrt:HI (match_operand:HI 1 "general_operand" "0")
+ (match_operand:HI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (sar%W0,%R0cl,%0);
+ else
+ return AS2 (sar%W0,%2,%0);
+}")
+
+(define_insn "ashrqi3"
+ [(set (match_operand:QI 0 "general_operand" "=qm")
+ (ashiftrt:QI (match_operand:QI 1 "general_operand" "0")
+ (match_operand:QI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (sar%B0,%R0cl,%0);
+ return
+ AS2 (sar%B0,%2,%1);
+}")
+\f
+;;- logical shift instructions
+
+(define_insn "lshlsi3"
+ [(set (match_operand:SI 0 "general_operand" "=rm")
+ (lshift:SI (match_operand:SI 1 "general_operand" "0")
+ (match_operand:SI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (shl%L0,%R0cl,%0);
+ else
+ return AS2 (shl%L0,%2,%1);
+}")
+
+(define_insn "lshlhi3"
+ [(set (match_operand:HI 0 "general_operand" "=rm")
+ (lshift:HI (match_operand:HI 1 "general_operand" "0")
+ (match_operand:HI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (shl%W0,%R0cl,%0);
+ else
+ return AS2 (shl%W0,%2,%1);
+}")
+
+(define_insn "lshlqi3"
+ [(set (match_operand:QI 0 "general_operand" "=qm")
+ (lshift:QI (match_operand:QI 1 "general_operand" "0")
+ (match_operand:QI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (shl%B0,%R0cl,%0);
+ else
+ return AS2 (shl%B0,%2,%1);
+}")
+
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "general_operand" "=rm")
+ (lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
+ (match_operand:SI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (shr%L0,%R0cl,%0);
+ else
+ return AS2 (shr%L0,%2,%1);
+}")
+
+(define_insn "lshrhi3"
+ [(set (match_operand:HI 0 "general_operand" "=rm")
+ (lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
+ (match_operand:HI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (shr%W0,%%cl,%0);
+ else
+ return AS2 (shr%W0,%2,%1);
+}")
+
+(define_insn "lshrqi3"
+ [(set (match_operand:QI 0 "general_operand" "=qm")
+ (lshiftrt:QI (match_operand:QI 1 "general_operand" "0")
+ (match_operand:QI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (shr%B0,%%cl,%0);
+ else
+ return AS2 (shr%B0,%2,%1);
+}")
+\f
+;;- rotate instructions
+
+(define_insn "rotlsi3"
+ [(set (match_operand:SI 0 "general_operand" "=rm")
+ (rotate:SI (match_operand:SI 1 "general_operand" "0")
+ (match_operand:SI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (rol%L0,%%cl,%0);
+ else
+ return AS2 (rol%L0,%2,%1);
+}")
+
+(define_insn "rotlhi3"
+ [(set (match_operand:HI 0 "general_operand" "=rm")
+ (rotate:HI (match_operand:HI 1 "general_operand" "0")
+ (match_operand:HI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (rol%W0,%%cl,%0);
+ else
+ return AS2 (rol%W0,%2,%1);
+}")
+
+(define_insn "rotlqi3"
+ [(set (match_operand:QI 0 "general_operand" "=qm")
+ (rotate:QI (match_operand:QI 1 "general_operand" "0")
+ (match_operand:QI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (rol%B0,%%cl,%0);
+ else
+ return AS2 (rol%B0,%2,%1);
+}")
+
+(define_insn "rotrsi3"
+ [(set (match_operand:SI 0 "general_operand" "=rm")
+ (rotatert:SI (match_operand:SI 1 "general_operand" "0")
+ (match_operand:SI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (ror%L0,%%cl,%0);
+ else
+ return AS2 (ror%L0,%2,%1);
+}")
+
+(define_insn "rotrhi3"
+ [(set (match_operand:HI 0 "general_operand" "=rm")
+ (rotatert:HI (match_operand:HI 1 "general_operand" "0")
+ (match_operand:HI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (ror%W0,%%cl,%0);
+ else
+ return AS2 (ror%W0,%2,%1);
+}")
+
+(define_insn "rotrqi3"
+ [(set (match_operand:QI 0 "general_operand" "=qm")
+ (rotatert:QI (match_operand:QI 1 "general_operand" "0")
+ (match_operand:QI 2 "general_operand" "cI")))]
+ ""
+ "*
+{
+ if (REG_P (operands[2]))
+ return AS2 (ror%B0,%%cl,%0);
+ else
+ return AS2 (ror%B0,%2,%1);
+}")
+\f
+;; Store-flag instructions.
+
+(define_insn "seq"
+ [(set (match_operand:QI 0 "general_operand" "=q")
+ (eq (cc0) (const_int 0)))]
+ ""
+ "*
+ cc_status = cc_prev_status;
+ return \"sete %0\";
+")
+
+(define_insn "sne"
+ [(set (match_operand:QI 0 "general_operand" "=q")
+ (ne (cc0) (const_int 0)))]
+ ""
+ "*
+ cc_status = cc_prev_status;
+ return \"setne %0\";
+")
+
+(define_insn "sgt"
+ [(set (match_operand:QI 0 "general_operand" "=q")
+ (gt (cc0) (const_int 0)))]
+ ""
+ "*
+ cc_status = cc_prev_status;
+ OUTPUT_JUMP (\"setg %0\", \"seta %0\", 0);
+")
+
+(define_insn "sgtu"
+ [(set (match_operand:QI 0 "general_operand" "=q")
+ (gtu (cc0) (const_int 0)))]
+ ""
+ "* cc_status = cc_prev_status;
+ return \"seta %0\"; ")
+
+(define_insn "slt"
+ [(set (match_operand:QI 0 "general_operand" "=q")
+ (lt (cc0) (const_int 0)))]
+ ""
+ "* cc_status = cc_prev_status;
+ OUTPUT_JUMP (\"setl %0\", \"setb %0\", \"sets %0\"); ")
+
+(define_insn "sltu"
+ [(set (match_operand:QI 0 "general_operand" "=q")
+ (ltu (cc0) (const_int 0)))]
+ ""
+ "* cc_status = cc_prev_status;
+ return \"setb %0\"; ")
+
+(define_insn "sge"
+ [(set (match_operand:QI 0 "general_operand" "=q")
+ (ge (cc0) (const_int 0)))]
+ ""
+ "* cc_status = cc_prev_status;
+ OUTPUT_JUMP (\"setge %0\", \"setae %0\", \"setns %0\"); ")
+
+(define_insn "sgeu"
+ [(set (match_operand:QI 0 "general_operand" "=q")
+ (geu (cc0) (const_int 0)))]
+ ""
+ "* cc_status = cc_prev_status;
+ return \"setae %0\"; ")
+
+(define_insn "sle"
+ [(set (match_operand:QI 0 "general_operand" "=q")
+ (le (cc0) (const_int 0)))]
+ ""
+ "*
+ cc_status = cc_prev_status;
+ OUTPUT_JUMP (\"setle %0\", \"setbe %0\", 0);
+")
+
+(define_insn "sleu"
+ [(set (match_operand:QI 0 "general_operand" "=q")
+ (leu (cc0) (const_int 0)))]
+ ""
+ "* cc_status = cc_prev_status;
+ return \"setbe %0\"; ")
+\f
+;; Basic conditional jump instructions.
+;; We ignore the overflow flag for signed branch instructions.
+
+(define_insn "beq"
+ [(set (pc)
+ (if_then_else (eq (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "je %l0")
+
+(define_insn "bne"
+ [(set (pc)
+ (if_then_else (ne (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jne %l0")
+
+(define_insn "bgt"
+ [(set (pc)
+ (if_then_else (gt (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "*OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0)")
+
+(define_insn "bgtu"
+ [(set (pc)
+ (if_then_else (gtu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "ja %l0")
+
+;; There is no jump insn to check for `<' on IEEE floats.
+;; Page 17-80 in the 80387 manual says jb, but that's wrong;
+;; jb checks for `not >='. So swap the operands and do `>'.
+(define_expand "blt"
+ [(set (pc)
+ (if_then_else (lt (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ extern rtx sequence_stack;
+ rtx prev = XEXP (XEXP (sequence_stack, 1), 0);
+ rtx body = PATTERN (prev);
+ rtx comp;
+ if (GET_CODE (body) == SET)
+ comp = SET_SRC (body);
+ else
+ comp = SET_SRC (XVECEXP (body, 0, 0));
+
+ if (GET_CODE (comp) == COMPARE
+ ? GET_MODE_CLASS (GET_MODE (XEXP (comp, 0))) == MODE_FLOAT
+ : GET_MODE_CLASS (GET_MODE (comp)) == MODE_FLOAT)
+ {
+ if (GET_CODE (comp) == COMPARE)
+ {
+ rtx op0 = XEXP (comp, 0);
+ rtx op1 = XEXP (comp, 1);
+ XEXP (comp, 0) = op1;
+ XEXP (comp, 1) = op0;
+ }
+ else
+ {
+ rtx new = gen_rtx (COMPARE, VOIDmode,
+ CONST0_RTX (GET_MODE (comp)), comp);
+ if (GET_CODE (body) == SET)
+ SET_SRC (body) = new;
+ else
+ SET_SRC (XVECEXP (body, 0, 0)) = new;
+ }
+ emit_insn (gen_bgt (operands[0]));
+ DONE;
+ }
+}")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (lt (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "*OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\")")
+
+(define_insn "bltu"
+ [(set (pc)
+ (if_then_else (ltu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jb %l0")
+
+(define_insn "bge"
+ [(set (pc)
+ (if_then_else (ge (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "*OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\")")
+
+(define_insn "bgeu"
+ [(set (pc)
+ (if_then_else (geu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jae %l0")
+
+;; See comment on `blt', above.
+(define_expand "ble"
+ [(set (pc)
+ (if_then_else (le (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ extern rtx sequence_stack;
+ rtx prev = XEXP (XEXP (sequence_stack, 1), 0);
+ rtx body = PATTERN (prev);
+ rtx comp;
+ if (GET_CODE (body) == SET)
+ comp = SET_SRC (body);
+ else
+ comp = SET_SRC (XVECEXP (body, 0, 0));
+
+ if (GET_CODE (comp) == COMPARE
+ ? GET_MODE_CLASS (GET_MODE (XEXP (comp, 0))) == MODE_FLOAT
+ : GET_MODE_CLASS (GET_MODE (comp)) == MODE_FLOAT)
+ {
+ if (GET_CODE (comp) == COMPARE)
+ {
+ rtx op0 = XEXP (comp, 0);
+ rtx op1 = XEXP (comp, 1);
+ XEXP (comp, 0) = op1;
+ XEXP (comp, 1) = op0;
+ }
+ else
+ {
+ rtx new = gen_rtx (COMPARE, VOIDmode,
+ CONST0_RTX (GET_MODE (comp)), comp);
+ if (GET_CODE (body) == SET)
+ SET_SRC (body) = new;
+ else
+ SET_SRC (XVECEXP (body, 0, 0)) = new;
+ }
+ emit_insn (gen_bge (operands[0]));
+ DONE;
+ }
+}")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (le (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "*OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0) ")
+
+(define_insn "bleu"
+ [(set (pc)
+ (if_then_else (leu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jbe %l0")
+\f
+;; Negated conditional jump instructions.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (eq (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jne %l0")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ne (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "je %l0")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (gt (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "*OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0) ")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (gtu (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jbe %l0")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (lt (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "*OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\")
+")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ltu (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jae %l0")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ge (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "*OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\")")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (geu (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jb %l0")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (le (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "*OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0)")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (leu (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "ja %l0")
+\f
+;; Unconditional and other jump instructions
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+ "jmp %l0")
+
+(define_insn "tablejump"
+ [(set (pc) (match_operand:SI 0 "general_operand" "rm"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+
+ return \"jmp %*%0\";
+}")
+
+/*
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (compare (minus:HI (match_operand:HI 0 "general_operand" "c")
+ (const_int 1))
+ (const_int -1))
+ (const_int 0))
+ (label_ref (match_operand 1 "" "g"))
+ (pc)))
+ (set (match_dup 0)
+ (minus:HI (match_dup 0)
+ (const_int 1)))]
+ ""
+ "loop %l1")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (compare (const_int -1)
+ (minus:SI (match_operand:SI 0 "general_operand" "c")
+ (const_int 1)))
+ (const_int 0))
+ (label_ref (match_operand 1 "" "g"))
+ (pc)))
+ (set (match_dup 0)
+ (minus:SI (match_dup 0)
+ (const_int 1)))]
+ ""
+ "loop %l1")
+*/
+
+;; Call subroutine returning no value.
+(define_insn "call"
+ [(call (match_operand:QI 0 "indirect_operand" "m")
+ (match_operand:SI 1 "general_operand" "g"))]
+ ;; Operand 1 not really used on the m68000.
+ ""
+ "*
+{
+ if (GET_CODE (operands[0]) == MEM
+ && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
+ {
+ operands[0] = XEXP (operands[0], 0);
+ return \"call %*%0\";
+ }
+ else
+ return \"call %0\";
+}")
+
+;; Call subroutine, returning value in operand 0
+;; (which must be a hard register).
+(define_insn "call_value"
+ [(set (match_operand 0 "" "=rf")
+ (call (match_operand:QI 1 "indirect_operand" "m")
+ (match_operand:SI 2 "general_operand" "g")))]
+ ;; Operand 2 not really used on the m68000.
+ ""
+ "*
+{
+ if (GET_CODE (operands[1]) == MEM
+ && ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
+ {
+ operands[1] = XEXP (operands[1], 0);
+ output_asm_insn (\"call %*%1\", operands);
+ }
+ else
+ output_asm_insn (\"call %1\", operands);
+
+ if (GET_MODE (operands[0]) == DFmode
+ || GET_MODE (operands[0]) == SFmode)
+ {
+/* fp_pop_level++; */
+ /* pop if reg dead */
+ if (!FP_REG_P (operands[0]))
+ abort ();
+ if (top_dead_p (insn))
+ {
+ POP_ONE_FP;
+ }
+ }
+ RET;
+}")
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop")
+\f
+;;- Local variables:
+;;- mode:emacs-lisp
+;;- comment-start: ";;- "
+;;- eval: (set-syntax-table (copy-sequence (syntax-table)))
+;;- eval: (modify-syntax-entry ?[ "(]")
+;;- eval: (modify-syntax-entry ?] ")[")
+;;- eval: (modify-syntax-entry ?{ "(}")
+;;- eval: (modify-syntax-entry ?} "){")
+;;- End: