1998-03-29 12:14:27 +04:00
|
|
|
|
;;- Machine description for Intel 860 chip for GNU C compiler
|
1998-08-16 21:35:45 +04:00
|
|
|
|
;; Copyright (C) 1989, 1990, 1997 Free Software Foundation, Inc.
|
1998-03-29 12:14:27 +04:00
|
|
|
|
|
|
|
|
|
;; This file is part of GNU CC.
|
|
|
|
|
|
|
|
|
|
;; GNU CC is free software; you can redistribute it and/or modify
|
|
|
|
|
;; it under the terms of the GNU General Public License as published by
|
|
|
|
|
;; the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
|
;; any later version.
|
|
|
|
|
|
|
|
|
|
;; GNU CC is distributed in the hope that it will be useful,
|
|
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
;; GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
|
|
|
;; along with GNU CC; see the file COPYING. If not, write to
|
|
|
|
|
;; the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
|
|
;; Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
|
|
|
|
|
|
|
|
|
|
;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code
|
|
|
|
|
;;- updates for most instructions.
|
|
|
|
|
|
|
|
|
|
;;- Operand classes for the register allocator:
|
|
|
|
|
|
|
|
|
|
/* Bit-test instructions. */
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0) (eq (and:SI (match_operand:SI 0 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 1 "logic_operand" "rL"))
|
|
|
|
|
(const_int 0)))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"and %1,%0,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0) (ne (and:SI (match_operand:SI 0 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 1 "logic_operand" "rL"))
|
|
|
|
|
(const_int 0)))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
cc_status.flags |= CC_NEGATED;
|
|
|
|
|
return \"and %1,%0,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0) (eq (and:SI (match_operand:SI 0 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 1 "immediate_operand" "i"))
|
|
|
|
|
(const_int 0)))]
|
|
|
|
|
"GET_CODE (operands[1]) == CONST_INT && (INTVAL (operands[1]) & 0xffff) == 0"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"andh %H1,%0,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0) (ne (and:SI (match_operand:SI 0 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 1 "immediate_operand" "i"))
|
|
|
|
|
(const_int 0)))]
|
|
|
|
|
"GET_CODE (operands[1]) == CONST_INT && (INTVAL (operands[1]) & 0xffff) == 0"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
cc_status.flags |= CC_NEGATED;
|
|
|
|
|
return \"andh %H1,%0,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0) (eq (ashiftrt:SI
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(ashift:QI (match_operand:QI 0 "register_operand" "r")
|
|
|
|
|
(match_operand:QI 1 "logic_int" "n")))
|
|
|
|
|
(match_operand:SI 2 "logic_int" "n"))
|
|
|
|
|
(const_int 0)))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
int width = 8 - INTVAL (operands[2]);
|
|
|
|
|
int pos = 8 - width - INTVAL (operands[1]);
|
|
|
|
|
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[2] = GEN_INT (~((-1) << width) << pos);
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"and %2,%0,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; -------------------------------------------------------------------------
|
|
|
|
|
;; SImode signed integer comparisons
|
|
|
|
|
;; -------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpeqsi"
|
|
|
|
|
[(set (cc0) (eq (match_operand:SI 0 "logic_operand" "r,rL")
|
|
|
|
|
(match_operand:SI 1 "logic_operand" "L,r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (REG_P (operands[0]))
|
|
|
|
|
return \"xor %1,%0,%?r0\";
|
|
|
|
|
else
|
|
|
|
|
return \"xor %0,%1,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpnesi"
|
|
|
|
|
[(set (cc0) (ne (match_operand:SI 0 "logic_operand" "r,rL")
|
|
|
|
|
(match_operand:SI 1 "logic_operand" "L,r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
cc_status.flags |= CC_NEGATED;
|
|
|
|
|
if (REG_P (operands[0]))
|
|
|
|
|
return \"xor %1,%0,%?r0\";
|
|
|
|
|
else
|
|
|
|
|
return \"xor %0,%1,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpltsi"
|
|
|
|
|
[(set (cc0) (lt (match_operand:SI 0 "arith_operand" "r,rI")
|
|
|
|
|
(match_operand:SI 1 "arith_operand" "I,r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (REG_P (operands[1]))
|
|
|
|
|
return \"subs %0,%1,%?r0\";
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cc_status.flags |= CC_REVERSED;
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[1] = GEN_INT (- INTVAL (operands[1]));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"adds %1,%0,%?r0\";
|
|
|
|
|
}
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpgtsi"
|
|
|
|
|
[(set (cc0) (gt (match_operand:SI 0 "arith_operand" "r,rI")
|
|
|
|
|
(match_operand:SI 1 "arith_operand" "I,r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (REG_P (operands[0]))
|
|
|
|
|
return \"subs %1,%0,%?r0\";
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cc_status.flags |= CC_REVERSED;
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[0] = GEN_INT (- INTVAL (operands[0]));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"adds %0,%1,%?r0\";
|
|
|
|
|
}
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "cmplesi"
|
|
|
|
|
[(set (cc0) (le (match_operand:SI 0 "arith_operand" "r,rI")
|
|
|
|
|
(match_operand:SI 1 "arith_operand" "I,r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
cc_status.flags |= CC_NEGATED;
|
|
|
|
|
if (REG_P (operands[0]))
|
|
|
|
|
return \"subs %1,%0,%?r0\";
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cc_status.flags |= CC_REVERSED;
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[0] = GEN_INT (- INTVAL (operands[0]));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"adds %0,%1,%?r0\";
|
|
|
|
|
}
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpgesi"
|
|
|
|
|
[(set (cc0) (ge (match_operand:SI 0 "arith_operand" "r,rI")
|
|
|
|
|
(match_operand:SI 1 "arith_operand" "I,r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
cc_status.flags |= CC_NEGATED;
|
|
|
|
|
if (REG_P (operands[1]))
|
|
|
|
|
return \"subs %0,%1,%?r0\";
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cc_status.flags |= CC_REVERSED;
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[1] = GEN_INT (- INTVAL (operands[1]));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"adds %1,%0,%?r0\";
|
|
|
|
|
}
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; -------------------------------------------------------------------------
|
|
|
|
|
;; SImode unsigned integer comparisons
|
|
|
|
|
;; -------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
;; WARNING! There is a small i860 hardware limitation (bug?) which we
|
|
|
|
|
;; may run up against (if we are not careful) when we are trying to do
|
|
|
|
|
;; unsigned comparisons like (x >= 0), (x < 0), (0 <= x), and (0 > x).
|
|
|
|
|
;; Specifically, we must avoid using an `addu' instruction to perform
|
|
|
|
|
;; such comparisons because the result (in the CC bit register) will
|
|
|
|
|
;; come out wrong. (This fact is documented in a footnote on page 7-10
|
|
|
|
|
;; of the 1991 version of the i860 Microprocessor Family Programmer's
|
|
|
|
|
;; Reference Manual). Note that unsigned comparisons of this sort are
|
|
|
|
|
;; always redundant anyway, because an unsigned quantity can never be
|
|
|
|
|
;; less than zero. When we see cases like this, we generate an
|
|
|
|
|
;; `or K,%r0,%r0' instruction instead (where K is a constant 0 or -1)
|
|
|
|
|
;; so as to get the CC bit register set properly for any subsequent
|
|
|
|
|
;; conditional jump instruction.
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpgeusi"
|
|
|
|
|
[(set (cc0) (geu (match_operand:SI 0 "arith_operand" "r,rI")
|
|
|
|
|
(match_operand:SI 1 "arith_operand" "I,r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (REG_P (operands[1]))
|
|
|
|
|
return \"subu %0,%1,%?r0\";
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (INTVAL (operands[1]) == 0)
|
|
|
|
|
return \"or 0,%?r0,%?r0\";
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cc_status.flags |= CC_REVERSED;
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[1] = GEN_INT (- INTVAL (operands[1]));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"addu %1,%0,%?r0\";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpleusi"
|
|
|
|
|
[(set (cc0) (leu (match_operand:SI 0 "arith_operand" "r,rI")
|
|
|
|
|
(match_operand:SI 1 "arith_operand" "I,r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (REG_P (operands[0]))
|
|
|
|
|
return \"subu %1,%0,%?r0\";
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (INTVAL (operands[0]) == 0)
|
|
|
|
|
return \"or 0,%?r0,%?r0\";
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cc_status.flags |= CC_REVERSED;
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[0] = GEN_INT (- INTVAL (operands[0]));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"addu %0,%1,%?r0\";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; -------------------------------------------------------------------------
|
|
|
|
|
;; SFmode floating-point comparisons
|
|
|
|
|
;; -------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpeqsf"
|
|
|
|
|
[(set (cc0) (eq (match_operand:SF 0 "reg_or_0_operand" "fG")
|
|
|
|
|
(match_operand:SF 1 "reg_or_0_operand" "fG")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"pfeq.ss %r0,%r1,%?f0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpnesf"
|
|
|
|
|
[(set (cc0) (ne (match_operand:SF 0 "reg_or_0_operand" "fG")
|
|
|
|
|
(match_operand:SF 1 "reg_or_0_operand" "fG")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
cc_status.flags |= CC_NEGATED;
|
|
|
|
|
return \"pfeq.ss %r1,%r0,%?f0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; NOTE: The i860 Programmer's Reference Manual says that when we are
|
|
|
|
|
;; doing (A < B) or (A > B) comparisons, we have to use pfgt for these
|
|
|
|
|
;; in order to be IEEE compliant (in case a trap occurs during these
|
|
|
|
|
;; operations). Conversely, for (A <= B) or (A >= B) comparisons, we
|
|
|
|
|
;; must use pfle to be IEEE compliant.
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpltsf"
|
|
|
|
|
[(set (cc0) (lt (match_operand:SF 0 "reg_or_0_operand" "fG")
|
|
|
|
|
(match_operand:SF 1 "reg_or_0_operand" "fG")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"pfgt.ss %r1,%r0,%?f0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpgtsf"
|
|
|
|
|
[(set (cc0) (gt (match_operand:SF 0 "reg_or_0_operand" "fG")
|
|
|
|
|
(match_operand:SF 1 "reg_or_0_operand" "fG")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"pfgt.ss %r0,%r1,%?f0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; NOTE: The pfle opcode doesn't do what you think it does. It is
|
|
|
|
|
;; bass-ackwards. It *clears* the CC flag if the first operand is
|
|
|
|
|
;; less than or equal to the second. Thus, we have to set CC_NEGATED
|
|
|
|
|
;; for the following two patterns.
|
|
|
|
|
|
|
|
|
|
(define_insn "cmplesf"
|
|
|
|
|
[(set (cc0) (le (match_operand:SF 0 "reg_or_0_operand" "fG")
|
|
|
|
|
(match_operand:SF 1 "reg_or_0_operand" "fG")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
cc_status.flags |= CC_NEGATED;
|
|
|
|
|
return \"pfle.ss %r0,%r1,%?f0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpgesf"
|
|
|
|
|
[(set (cc0) (ge (match_operand:SF 0 "reg_or_0_operand" "fG")
|
|
|
|
|
(match_operand:SF 1 "reg_or_0_operand" "fG")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
cc_status.flags |= CC_NEGATED;
|
|
|
|
|
return \"pfle.ss %r1,%r0,%?f0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; -------------------------------------------------------------------------
|
|
|
|
|
;; DFmode floating-point comparisons
|
|
|
|
|
;; -------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpeqdf"
|
|
|
|
|
[(set (cc0) (eq (match_operand:DF 0 "reg_or_0_operand" "fG")
|
|
|
|
|
(match_operand:DF 1 "reg_or_0_operand" "fG")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"pfeq.dd %r0,%r1,%?f0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpnedf"
|
|
|
|
|
[(set (cc0) (ne (match_operand:DF 0 "reg_or_0_operand" "fG")
|
|
|
|
|
(match_operand:DF 1 "reg_or_0_operand" "fG")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
cc_status.flags |= CC_NEGATED;
|
|
|
|
|
return \"pfeq.dd %r1,%r0,%?f0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; NOTE: The i860 Programmer's Reference Manual says that when we are
|
|
|
|
|
;; doing (A < B) or (A > B) comparisons, we have to use pfgt for these
|
|
|
|
|
;; in order to be IEEE compliant (in case a trap occurs during these
|
|
|
|
|
;; operations). Conversely, for (A <= B) or (A >= B) comparisons, we
|
|
|
|
|
;; must use pfle to be IEEE compliant.
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpltdf"
|
|
|
|
|
[(set (cc0) (lt (match_operand:DF 0 "reg_or_0_operand" "fG")
|
|
|
|
|
(match_operand:DF 1 "reg_or_0_operand" "fG")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"pfgt.dd %r1,%r0,%?f0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpgtdf"
|
|
|
|
|
[(set (cc0) (gt (match_operand:DF 0 "reg_or_0_operand" "fG")
|
|
|
|
|
(match_operand:DF 1 "reg_or_0_operand" "fG")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"pfgt.dd %r0,%r1,%?f0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; NOTE: The pfle opcode doesn't do what you think it does. It is
|
|
|
|
|
;; bass-ackwards. It *clears* the CC flag if the first operand is
|
|
|
|
|
;; less than or equal to the second. Thus, we have to set CC_NEGATED
|
|
|
|
|
;; for the following two patterns.
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpledf"
|
|
|
|
|
[(set (cc0) (le (match_operand:DF 0 "reg_or_0_operand" "fG")
|
|
|
|
|
(match_operand:DF 1 "reg_or_0_operand" "fG")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
cc_status.flags |= CC_NEGATED;
|
|
|
|
|
return \"pfle.dd %r0,%r1,%?f0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "cmpgedf"
|
|
|
|
|
[(set (cc0) (ge (match_operand:DF 0 "reg_or_0_operand" "fG")
|
|
|
|
|
(match_operand:DF 1 "reg_or_0_operand" "fG")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
cc_status.flags |= CC_NEGATED;
|
|
|
|
|
return \"pfle.dd %r1,%r0,%?f0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; ------------------------------------------------------------------------
|
|
|
|
|
;; Integer EQ/NE comparisons against constant values which will fit in the
|
|
|
|
|
;; 16-bit immediate field of an instruction. These are made by combining.
|
|
|
|
|
;; ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0) (eq (zero_extend:SI (match_operand:HI 0 "load_operand" "m"))
|
|
|
|
|
(match_operand:SI 1 "small_int" "I")))]
|
|
|
|
|
"INTVAL (operands[1]) >= 0"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"ld.s %0,%?r31\;xor %1,%?r31,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0) (eq (match_operand:SI 0 "small_int" "I")
|
|
|
|
|
(zero_extend:SI (match_operand:HI 1 "load_operand" "m"))))]
|
|
|
|
|
"INTVAL (operands[0]) >= 0"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"ld.s %1,%?r31\;xor %0,%?r31,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; ------------------------------------------------------------------------
|
|
|
|
|
;; Define the real conditional branch instructions.
|
|
|
|
|
;; ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
(define_insn "cbranch"
|
|
|
|
|
[(set (pc) (if_then_else (eq (cc0) (const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if ((cc_prev_status.flags & CC_NEGATED) == 0)
|
|
|
|
|
return \"bnc %l0\";
|
|
|
|
|
else
|
|
|
|
|
return \"bc %l0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "flipped_cbranch"
|
|
|
|
|
[(set (pc) (if_then_else (ne (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(pc)
|
|
|
|
|
(label_ref (match_operand 0 "" ""))))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if ((cc_prev_status.flags & CC_NEGATED) == 0)
|
|
|
|
|
return \"bnc %l0\";
|
|
|
|
|
else
|
|
|
|
|
return \"bc %l0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "inverse_cbranch"
|
|
|
|
|
[(set (pc) (if_then_else (eq (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(pc)
|
|
|
|
|
(label_ref (match_operand 0 "" ""))))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if ((cc_prev_status.flags & CC_NEGATED) == 0)
|
|
|
|
|
return \"bc %l0\";
|
|
|
|
|
else
|
|
|
|
|
return \"bnc %l0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define_insn "flipped_inverse_cbranch"
|
|
|
|
|
[(set (pc) (if_then_else (ne (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if ((cc_prev_status.flags & CC_NEGATED) == 0)
|
|
|
|
|
return \"bc %l0\";
|
|
|
|
|
else
|
|
|
|
|
return \"bnc %l0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Simple BTE/BTNE compare-and-branch insns made by combining.
|
|
|
|
|
;; Note that it is wrong to add similar patterns for QI or HImode
|
|
|
|
|
;; because bte/btne always compare the whole register.
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (eq (match_operand:SI 0 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 1 "bte_operand" "rK"))
|
|
|
|
|
(label_ref (match_operand 2 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"bte %1,%0,%2")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (ne (match_operand:SI 0 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 1 "bte_operand" "rK"))
|
|
|
|
|
(label_ref (match_operand 2 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"btne %1,%0,%2")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (eq (match_operand:SI 0 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 1 "bte_operand" "rK"))
|
|
|
|
|
(pc)
|
|
|
|
|
(label_ref (match_operand 2 "" ""))))]
|
|
|
|
|
""
|
|
|
|
|
"btne %1,%0,%2")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (ne (match_operand:SI 0 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 1 "bte_operand" "rK"))
|
|
|
|
|
(pc)
|
|
|
|
|
(label_ref (match_operand 2 "" ""))))]
|
|
|
|
|
""
|
|
|
|
|
"bte %1,%0,%2")
|
|
|
|
|
|
|
|
|
|
;; Load byte/halfword, zero-extend, & compare-and-branch insns.
|
|
|
|
|
;; These are made by combining.
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (eq (zero_extend:SI (match_operand:QI 0 "memory_operand" "m"))
|
|
|
|
|
(match_operand:SI 1 "bte_operand" "K"))
|
|
|
|
|
(label_ref (match_operand 2 "" ""))
|
|
|
|
|
(pc)))
|
|
|
|
|
(match_scratch:SI 3 "=r")]
|
|
|
|
|
""
|
|
|
|
|
"ld.b %0,%3;bte %1,%3,%2")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (ne (zero_extend:SI (match_operand:QI 0 "memory_operand" "m"))
|
|
|
|
|
(match_operand:SI 1 "bte_operand" "K"))
|
|
|
|
|
(label_ref (match_operand 2 "" ""))
|
|
|
|
|
(pc)))
|
|
|
|
|
(match_scratch:SI 3 "=r")]
|
|
|
|
|
""
|
|
|
|
|
"ld.b %0,%3;btne %1,%3,%2")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (eq (zero_extend:SI (match_operand:QI 0 "memory_operand" "m"))
|
|
|
|
|
(match_operand:SI 1 "bte_operand" "K"))
|
|
|
|
|
(pc)
|
|
|
|
|
(label_ref (match_operand 2 "" ""))))
|
|
|
|
|
(match_scratch:SI 3 "=r")]
|
|
|
|
|
""
|
|
|
|
|
"ld.b %0,%3;btne %1,%3,%2")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (ne (zero_extend:SI (match_operand:QI 0 "memory_operand" "m"))
|
|
|
|
|
(match_operand:SI 1 "bte_operand" "K"))
|
|
|
|
|
(pc)
|
|
|
|
|
(label_ref (match_operand 2 "" ""))))
|
|
|
|
|
(match_scratch:SI 3 "=r")]
|
|
|
|
|
""
|
|
|
|
|
"ld.b %0,%3;bte %1,%3,%2")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (eq (zero_extend:SI (match_operand:HI 0 "memory_operand" "m"))
|
|
|
|
|
(match_operand:SI 1 "bte_operand" "K"))
|
|
|
|
|
(label_ref (match_operand 2 "" ""))
|
|
|
|
|
(pc)))
|
|
|
|
|
(match_scratch:SI 3 "=r")]
|
|
|
|
|
""
|
|
|
|
|
"ld.s %0,%3;bte %1,%3,%2")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (ne (zero_extend:SI (match_operand:HI 0 "memory_operand" "m"))
|
|
|
|
|
(match_operand:SI 1 "bte_operand" "K"))
|
|
|
|
|
(label_ref (match_operand 2 "" ""))
|
|
|
|
|
(pc)))
|
|
|
|
|
(match_scratch:SI 3 "=r")]
|
|
|
|
|
""
|
|
|
|
|
"ld.s %0,%3;btne %1,%3,%2")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (eq (zero_extend:SI (match_operand:HI 0 "memory_operand" "m"))
|
|
|
|
|
(match_operand:SI 1 "bte_operand" "K"))
|
|
|
|
|
(pc)
|
|
|
|
|
(label_ref (match_operand 2 "" ""))))
|
|
|
|
|
(match_scratch:SI 3 "=r")]
|
|
|
|
|
""
|
|
|
|
|
"ld.s %0,%3;btne %1,%3,%2")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (ne (zero_extend:SI (match_operand:HI 0 "memory_operand" "m"))
|
|
|
|
|
(match_operand:SI 1 "bte_operand" "K"))
|
|
|
|
|
(pc)
|
|
|
|
|
(label_ref (match_operand 2 "" ""))))
|
|
|
|
|
(match_scratch:SI 3 "=r")]
|
|
|
|
|
""
|
|
|
|
|
"ld.s %0,%3;bte %1,%3,%2")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; Generation of conditionals.
|
|
|
|
|
|
|
|
|
|
;; We save the compare operands in the cmpxx patterns and use then when
|
|
|
|
|
;; we generate the branch.
|
|
|
|
|
|
|
|
|
|
(define_expand "cmpsi"
|
|
|
|
|
[(set (cc0) (compare (match_operand:SI 0 "register_operand" "")
|
|
|
|
|
(match_operand:SI 1 "compare_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{ i860_compare_op0 = operands[0];
|
|
|
|
|
i860_compare_op1 = operands[1];
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "cmpsf"
|
|
|
|
|
[(set (cc0) (compare (match_operand:SF 0 "register_operand" "")
|
|
|
|
|
(match_operand:SF 1 "register_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{ i860_compare_op0 = operands[0];
|
|
|
|
|
i860_compare_op1 = operands[1];
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "cmpdf"
|
|
|
|
|
[(set (cc0) (compare (match_operand:DF 0 "register_operand" "")
|
|
|
|
|
(match_operand:DF 1 "register_operand" "")))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{ i860_compare_op0 = operands[0];
|
|
|
|
|
i860_compare_op1 = operands[1];
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; These are the standard-named conditional branch patterns.
|
|
|
|
|
;; Detailed comments are found in the first one only.
|
|
|
|
|
|
|
|
|
|
(define_expand "beq"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (eq (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* Emit a single-condition compare insn according to
|
|
|
|
|
the type of operands and the condition to be tested. */
|
|
|
|
|
|
|
|
|
|
if (GET_MODE_CLASS (GET_MODE (i860_compare_op0)) == MODE_INT)
|
|
|
|
|
emit_insn (gen_cmpeqsi (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else if (GET_MODE (i860_compare_op0) == SFmode)
|
|
|
|
|
emit_insn (gen_cmpeqsf (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else if (GET_MODE (i860_compare_op0) == DFmode)
|
|
|
|
|
emit_insn (gen_cmpeqdf (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
/* Emit branch-if-true. */
|
|
|
|
|
|
|
|
|
|
emit_jump_insn (gen_flipped_inverse_cbranch (operands[0]));
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "bne"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (ne (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (GET_MODE_CLASS (GET_MODE (i860_compare_op0)) == MODE_INT)
|
|
|
|
|
emit_insn (gen_cmpeqsi (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else if (GET_MODE (i860_compare_op0) == SFmode)
|
|
|
|
|
emit_insn (gen_cmpeqsf (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else if (GET_MODE (i860_compare_op0) == DFmode)
|
|
|
|
|
emit_insn (gen_cmpeqdf (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
emit_jump_insn (gen_flipped_cbranch (operands[0]));
|
|
|
|
|
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "bgt"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (gt (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (GET_MODE_CLASS (GET_MODE (i860_compare_op0)) == MODE_INT)
|
|
|
|
|
emit_insn (gen_cmpgtsi (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else if (GET_MODE (i860_compare_op0) == SFmode)
|
|
|
|
|
emit_insn (gen_cmpgtsf (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else if (GET_MODE (i860_compare_op0) == DFmode)
|
|
|
|
|
emit_insn (gen_cmpgtdf (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
emit_jump_insn (gen_flipped_inverse_cbranch (operands[0]));
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "blt"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (lt (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (GET_MODE_CLASS (GET_MODE (i860_compare_op0)) == MODE_INT)
|
|
|
|
|
emit_insn (gen_cmpltsi (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else if (GET_MODE (i860_compare_op0) == SFmode)
|
|
|
|
|
emit_insn (gen_cmpltsf (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else if (GET_MODE (i860_compare_op0) == DFmode)
|
|
|
|
|
emit_insn (gen_cmpltdf (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
emit_jump_insn (gen_flipped_inverse_cbranch (operands[0]));
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "ble"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (le (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (GET_MODE_CLASS (GET_MODE (i860_compare_op0)) == MODE_INT)
|
|
|
|
|
{
|
|
|
|
|
emit_insn (gen_cmpgtsi (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
emit_jump_insn (gen_flipped_cbranch (operands[0]));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (GET_MODE (i860_compare_op0) == SFmode)
|
|
|
|
|
emit_insn (gen_cmplesf (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else if (GET_MODE (i860_compare_op0) == DFmode)
|
|
|
|
|
emit_insn (gen_cmpledf (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else
|
|
|
|
|
abort ();
|
|
|
|
|
emit_jump_insn (gen_flipped_inverse_cbranch (operands[0]));
|
|
|
|
|
}
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "bge"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (ge (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (GET_MODE_CLASS (GET_MODE (i860_compare_op0)) == MODE_INT)
|
|
|
|
|
{
|
|
|
|
|
emit_insn (gen_cmpltsi (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
emit_jump_insn (gen_flipped_cbranch (operands[0]));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (GET_MODE (i860_compare_op0) == SFmode)
|
|
|
|
|
emit_insn (gen_cmpgesf (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else if (GET_MODE (i860_compare_op0) == DFmode)
|
|
|
|
|
emit_insn (gen_cmpgedf (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
else
|
|
|
|
|
abort ();
|
|
|
|
|
emit_jump_insn (gen_flipped_inverse_cbranch (operands[0]));
|
|
|
|
|
}
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "bgtu"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (gtu (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (GET_MODE_CLASS (GET_MODE (i860_compare_op0)) != MODE_INT)
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
emit_insn (gen_cmpleusi (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
emit_jump_insn (gen_flipped_cbranch (operands[0]));
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "bltu"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (ltu (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (GET_MODE_CLASS (GET_MODE (i860_compare_op0)) != MODE_INT)
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
emit_insn (gen_cmpgeusi (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
emit_jump_insn (gen_flipped_cbranch (operands[0]));
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "bgeu"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (geu (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (GET_MODE_CLASS (GET_MODE (i860_compare_op0)) != MODE_INT)
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
emit_insn (gen_cmpgeusi (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
emit_jump_insn (gen_flipped_inverse_cbranch (operands[0]));
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "bleu"
|
|
|
|
|
[(set (pc)
|
|
|
|
|
(if_then_else (leu (cc0)
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(label_ref (match_operand 0 "" ""))
|
|
|
|
|
(pc)))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (GET_MODE_CLASS (GET_MODE (i860_compare_op0)) != MODE_INT)
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
emit_insn (gen_cmpleusi (i860_compare_op0, i860_compare_op1));
|
|
|
|
|
emit_jump_insn (gen_flipped_inverse_cbranch (operands[0]));
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Move instructions
|
|
|
|
|
|
|
|
|
|
;; Note that source operands for `mov' pseudo-instructions are no longer
|
|
|
|
|
;; allowed (by the svr4 assembler) to be "big" things, i.e. constants that
|
|
|
|
|
;; won't fit in 16-bits. (This includes any sort of a relocatable address
|
|
|
|
|
;; also.) Thus, we must use an explicit orh/or pair of instructions if
|
|
|
|
|
;; the source operand is something "big".
|
|
|
|
|
|
|
|
|
|
(define_insn "movsi"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=r,m,f")
|
|
|
|
|
(match_operand:SI 1 "general_operand" "rmif,rfJ,rmfJ"))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (operands[0]) == MEM)
|
|
|
|
|
{
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
|
|
|
|
|
return output_store (operands);
|
|
|
|
|
if (FP_REG_P (operands[1]))
|
|
|
|
|
return \"fst.l %1,%0\";
|
|
|
|
|
return \"st.l %r1,%0\";
|
|
|
|
|
}
|
|
|
|
|
if (GET_CODE (operands[1]) == MEM)
|
|
|
|
|
{
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
|
|
|
|
return output_load (operands);
|
|
|
|
|
if (FP_REG_P (operands[0]))
|
|
|
|
|
return \"fld.l %1,%0\";
|
|
|
|
|
return \"ld.l %1,%0\";
|
|
|
|
|
}
|
|
|
|
|
if (FP_REG_P (operands[1]) && FP_REG_P (operands[0]))
|
|
|
|
|
return \"fmov.ss %1,%0\";
|
|
|
|
|
if (FP_REG_P (operands[1]))
|
|
|
|
|
return \"fxfr %1,%0\";
|
|
|
|
|
if (FP_REG_P (operands[0]) && operands[1] == const0_rtx)
|
|
|
|
|
return \"fmov.ss %?f0,%0\";
|
|
|
|
|
if (FP_REG_P (operands[0]))
|
|
|
|
|
return \"ixfr %1,%0\";
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (operands[1]) == REG)
|
|
|
|
|
return \"shl %?r0,%1,%0\";
|
|
|
|
|
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (operands[1]) == CONST_INT)
|
|
|
|
|
{
|
|
|
|
|
if((INTVAL (operands[1]) & 0xffff0000) == 0)
|
|
|
|
|
return \"or %L1,%?r0,%0\";
|
|
|
|
|
if((INTVAL (operands[1]) & 0x0000ffff) == 0)
|
|
|
|
|
return \"orh %H1,%?r0,%0\";
|
|
|
|
|
}
|
|
|
|
|
return \"orh %H1,%?r0,%0\;or %L1,%0,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "movhi"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=r,m,!*f,!r")
|
|
|
|
|
(match_operand:HI 1 "general_operand" "rmi,rJ,rJ*f,*f"))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (operands[0]) == MEM)
|
|
|
|
|
{
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
|
|
|
|
|
return output_store (operands);
|
|
|
|
|
return \"st.s %r1,%0\";
|
|
|
|
|
}
|
|
|
|
|
if (GET_CODE (operands[1]) == MEM)
|
|
|
|
|
{
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
|
|
|
|
return output_load (operands);
|
|
|
|
|
return \"ld.s %1,%0\";
|
|
|
|
|
}
|
|
|
|
|
if (FP_REG_P (operands[1]) && FP_REG_P (operands[0]))
|
|
|
|
|
return \"fmov.ss %1,%0\";
|
|
|
|
|
if (FP_REG_P (operands[1]))
|
|
|
|
|
return \"fxfr %1,%0\";
|
|
|
|
|
if (FP_REG_P (operands[0]) && operands[1] == const0_rtx)
|
|
|
|
|
return \"fmov.ss %?f0,%0\";
|
|
|
|
|
if (FP_REG_P (operands[0]))
|
|
|
|
|
return \"ixfr %1,%0\";
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (operands[1]) == REG)
|
|
|
|
|
return \"shl %?r0,%1,%0\";
|
|
|
|
|
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
|
|
|
|
|
return \"or %L1,%?r0,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "movqi"
|
|
|
|
|
[(set (match_operand:QI 0 "general_operand" "=r,m,!*f,!r")
|
|
|
|
|
(match_operand:QI 1 "general_operand" "rmi,rJ,rJ*f,*f"))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (operands[0]) == MEM)
|
|
|
|
|
{
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
|
|
|
|
|
return output_store (operands);
|
|
|
|
|
return \"st.b %r1,%0\";
|
|
|
|
|
}
|
|
|
|
|
if (GET_CODE (operands[1]) == MEM)
|
|
|
|
|
{
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
|
|
|
|
return output_load (operands);
|
|
|
|
|
return \"ld.b %1,%0\";
|
|
|
|
|
}
|
|
|
|
|
if (FP_REG_P (operands[1]) && FP_REG_P (operands[0]))
|
|
|
|
|
return \"fmov.ss %1,%0\";
|
|
|
|
|
if (FP_REG_P (operands[1]))
|
|
|
|
|
return \"fxfr %1,%0\";
|
|
|
|
|
if (FP_REG_P (operands[0]) && operands[1] == const0_rtx)
|
|
|
|
|
return \"fmov.ss %?f0,%0\";
|
|
|
|
|
if (FP_REG_P (operands[0]))
|
|
|
|
|
return \"ixfr %1,%0\";
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (operands[1]) == REG)
|
|
|
|
|
return \"shl %?r0,%1,%0\";
|
|
|
|
|
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
|
|
|
|
|
return \"or %L1,%?r0,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; 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_expand "movstrsi"
|
1998-08-16 21:35:45 +04:00
|
|
|
|
[(parallel [(set (match_operand:BLK 0 "general_operand" "")
|
|
|
|
|
(match_operand:BLK 1 "general_operand" ""))
|
1998-03-29 12:14:27 +04:00
|
|
|
|
(use (match_operand:SI 2 "nonmemory_operand" ""))
|
|
|
|
|
(use (match_operand:SI 3 "immediate_operand" ""))
|
|
|
|
|
(clobber (match_dup 4))
|
|
|
|
|
(clobber (match_dup 5))
|
|
|
|
|
(clobber (match_dup 6))
|
1998-08-16 21:35:45 +04:00
|
|
|
|
(clobber (match_dup 7))
|
|
|
|
|
(clobber (match_dup 8))])]
|
1998-03-29 12:14:27 +04:00
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
operands[4] = gen_reg_rtx (SImode);
|
|
|
|
|
operands[5] = gen_reg_rtx (SImode);
|
|
|
|
|
operands[6] = gen_reg_rtx (SImode);
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[7] = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
|
|
|
|
|
operands[8] = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
|
|
|
|
|
|
|
|
|
|
operands[0] = change_address (operands[0], VOIDmode, operands[7]);
|
|
|
|
|
operands[1] = change_address (operands[1], VOIDmode, operands[8]);
|
1998-03-29 12:14:27 +04:00
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (mem:BLK (match_operand:SI 0 "register_operand" "r"))
|
|
|
|
|
(mem:BLK (match_operand:SI 1 "register_operand" "r")))
|
|
|
|
|
(use (match_operand:SI 2 "general_operand" "rn"))
|
|
|
|
|
(use (match_operand:SI 3 "immediate_operand" "i"))
|
|
|
|
|
(clobber (match_operand:SI 4 "register_operand" "=r"))
|
|
|
|
|
(clobber (match_operand:SI 5 "register_operand" "=r"))
|
|
|
|
|
(clobber (match_operand:SI 6 "register_operand" "=r"))
|
|
|
|
|
(clobber (match_dup 0))
|
|
|
|
|
(clobber (match_dup 1))]
|
|
|
|
|
""
|
|
|
|
|
"* return output_block_move (operands);")
|
|
|
|
|
|
|
|
|
|
;; Floating point move insns
|
|
|
|
|
|
|
|
|
|
;; This pattern forces (set (reg:DF ...) (const_double ...))
|
|
|
|
|
;; to be reloaded by putting the constant into memory.
|
|
|
|
|
;; It must come before the more general movdf pattern.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:DF 0 "general_operand" "=r,f,o")
|
|
|
|
|
(match_operand:DF 1 "" "mG,m,G"))]
|
|
|
|
|
"GET_CODE (operands[1]) == CONST_DOUBLE"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (FP_REG_P (operands[0]) || operands[1] == CONST0_RTX (DFmode))
|
|
|
|
|
return output_fp_move_double (operands);
|
|
|
|
|
return output_move_double (operands);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "movdf"
|
|
|
|
|
[(set (match_operand:DF 0 "general_operand" "=*rm,*r,?f,?*rm")
|
|
|
|
|
(match_operand:DF 1 "general_operand" "*r,m,*rfmG,f"))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (operands[0]) == MEM
|
|
|
|
|
&& CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
|
|
|
|
|
return output_store (operands);
|
|
|
|
|
if (GET_CODE (operands[1]) == MEM
|
|
|
|
|
&& CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
|
|
|
|
return output_load (operands);
|
|
|
|
|
|
|
|
|
|
if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]))
|
|
|
|
|
return output_fp_move_double (operands);
|
|
|
|
|
return output_move_double (operands);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "movdi"
|
|
|
|
|
[(set (match_operand:DI 0 "general_operand" "=rm,r,?f,?rm")
|
|
|
|
|
(match_operand:DI 1 "general_operand" "r,miF,rfmG,f"))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (operands[0]) == MEM
|
|
|
|
|
&& CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
|
|
|
|
|
return output_store (operands);
|
|
|
|
|
if (GET_CODE (operands[1]) == MEM
|
|
|
|
|
&& CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
|
|
|
|
return output_load (operands);
|
|
|
|
|
|
|
|
|
|
/* ??? How can we have a DFmode arg here with DImode above? */
|
|
|
|
|
if (FP_REG_P (operands[0]) && operands[1] == CONST0_RTX (DFmode))
|
|
|
|
|
return \"fmov.dd %?f0,%0\";
|
|
|
|
|
|
|
|
|
|
if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]))
|
|
|
|
|
return output_fp_move_double (operands);
|
|
|
|
|
return output_move_double (operands);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; The alternative m/r is separate from m/f
|
|
|
|
|
;; The first alternative is separate from the second for the same reason.
|
|
|
|
|
(define_insn "movsf"
|
|
|
|
|
[(set (match_operand:SF 0 "general_operand" "=*rf,*rf,*r,m,m")
|
|
|
|
|
(match_operand:SF 1 "general_operand" "*r,fmG,F,*r,f"))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (operands[0]) == MEM
|
|
|
|
|
&& CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
|
|
|
|
|
return output_store (operands);
|
|
|
|
|
if (GET_CODE (operands[1]) == MEM
|
|
|
|
|
&& CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
|
|
|
|
return output_load (operands);
|
|
|
|
|
if (FP_REG_P (operands[0]))
|
|
|
|
|
{
|
|
|
|
|
if (FP_REG_P (operands[1]))
|
|
|
|
|
return \"fmov.ss %1,%0\";
|
|
|
|
|
if (GET_CODE (operands[1]) == REG)
|
|
|
|
|
return \"ixfr %1,%0\";
|
|
|
|
|
if (operands[1] == CONST0_RTX (SFmode))
|
|
|
|
|
return \"fmov.ss %?f0,%0\";
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
|
|
|
|
{
|
|
|
|
|
if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
|
|
|
|
|
&& (cc_prev_status.flags & CC_HI_R31_ADJ)
|
|
|
|
|
&& cc_prev_status.mdep == XEXP(operands[1],0)))
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_INIT;
|
|
|
|
|
cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
|
|
|
|
|
cc_status.mdep = XEXP (operands[1], 0);
|
|
|
|
|
return \"orh %h1,%?r0,%?r31\;fld.l %L1(%?r31),%0\";
|
|
|
|
|
}
|
|
|
|
|
return \"fld.l %L1(%?r31),%0\";
|
|
|
|
|
}
|
|
|
|
|
return \"fld.l %1,%0\";
|
|
|
|
|
}
|
|
|
|
|
if (FP_REG_P (operands[1]) || GET_CODE (operands[1]) == CONST_DOUBLE)
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (operands[0]) == REG && FP_REG_P (operands[1]))
|
|
|
|
|
return \"fxfr %1,%0\";
|
|
|
|
|
if (GET_CODE (operands[0]) == REG)
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (GET_CODE (operands[1]) == CONST_DOUBLE)
|
|
|
|
|
{
|
|
|
|
|
register unsigned long ul;
|
|
|
|
|
|
|
|
|
|
ul = sfmode_constant_to_ulong (operands[1]);
|
|
|
|
|
if ((ul & 0x0000ffff) == 0)
|
|
|
|
|
return \"orh %H1,%?r0,%0\";
|
|
|
|
|
if ((ul & 0xffff0000) == 0)
|
|
|
|
|
return \"or %L1,%?r0,%0\";
|
|
|
|
|
}
|
|
|
|
|
return \"orh %H1,%?r0,%0\;or %L1,%0,%0\";
|
|
|
|
|
}
|
|
|
|
|
/* Now operand 0 must be memory.
|
|
|
|
|
If operand 1 is CONST_DOUBLE, its value must be 0. */
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
|
|
|
|
|
{
|
|
|
|
|
if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
|
|
|
|
|
&& (cc_prev_status.flags & CC_HI_R31_ADJ)
|
|
|
|
|
&& XEXP (operands[0], 0) == cc_prev_status.mdep))
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_INIT;
|
|
|
|
|
cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
|
|
|
|
|
cc_status.mdep = XEXP (operands[0], 0);
|
|
|
|
|
output_asm_insn (\"orh %h0,%?r0,%?r31\", operands);
|
|
|
|
|
}
|
|
|
|
|
return \"fst.l %r1,%L0(%?r31)\";
|
|
|
|
|
}
|
|
|
|
|
return \"fst.l %r1,%0\";
|
|
|
|
|
}
|
|
|
|
|
if (GET_CODE (operands[0]) == MEM)
|
|
|
|
|
return \"st.l %r1,%0\";
|
|
|
|
|
if (GET_CODE (operands[1]) == MEM)
|
|
|
|
|
return \"ld.l %1,%0\";
|
|
|
|
|
if (operands[1] == CONST0_RTX (SFmode))
|
|
|
|
|
return \"shl %?r0,%?r0,%0\";
|
|
|
|
|
return \"mov %1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Special load insns for REG+REG addresses.
|
|
|
|
|
;; Such addresses are not "legitimate" because st rejects them.
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:DF 0 "register_operand" "=rf")
|
|
|
|
|
(match_operand:DF 1 "indexed_operand" "m"))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (FP_REG_P (operands[0]))
|
|
|
|
|
return output_fp_move_double (operands);
|
|
|
|
|
return output_move_double (operands);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SF 0 "register_operand" "=rf")
|
|
|
|
|
(match_operand:SF 1 "indexed_operand" "m"))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (FP_REG_P (operands[0]))
|
|
|
|
|
return \"fld.l %1,%0\";
|
|
|
|
|
return \"ld.l %1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=rf")
|
|
|
|
|
(match_operand:SI 1 "indexed_operand" "m"))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (FP_REG_P (operands[0]))
|
|
|
|
|
return \"fld.l %1,%0\";
|
|
|
|
|
return \"ld.l %1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:HI 0 "register_operand" "=r")
|
|
|
|
|
(match_operand:HI 1 "indexed_operand" "m"))]
|
|
|
|
|
""
|
|
|
|
|
"ld.s %1,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:QI 0 "register_operand" "=r")
|
|
|
|
|
(match_operand:QI 1 "indexed_operand" "m"))]
|
|
|
|
|
""
|
|
|
|
|
"ld.b %1,%0")
|
|
|
|
|
|
|
|
|
|
;; Likewise for floating-point store insns.
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:DF 0 "indexed_operand" "=m")
|
|
|
|
|
(match_operand:DF 1 "register_operand" "f"))]
|
|
|
|
|
""
|
|
|
|
|
"fst.d %1,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SF 0 "indexed_operand" "=m")
|
|
|
|
|
(match_operand:SF 1 "register_operand" "f"))]
|
|
|
|
|
""
|
|
|
|
|
"fst.l %1,%0")
|
|
|
|
|
|
|
|
|
|
;;- truncation instructions
|
|
|
|
|
(define_insn "truncsiqi2"
|
|
|
|
|
[(set (match_operand:QI 0 "general_operand" "=g")
|
|
|
|
|
(truncate:QI
|
|
|
|
|
(match_operand:SI 1 "register_operand" "r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (operands[0]) == MEM)
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
|
|
|
|
|
{
|
|
|
|
|
if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
|
|
|
|
|
&& (cc_prev_status.flags & CC_HI_R31_ADJ)
|
|
|
|
|
&& XEXP (operands[0], 0) == cc_prev_status.mdep))
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_INIT;
|
|
|
|
|
cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
|
|
|
|
|
cc_status.mdep = XEXP (operands[0], 0);
|
|
|
|
|
output_asm_insn (\"orh %h0,%?r0,%?r31\", operands);
|
|
|
|
|
}
|
|
|
|
|
return \"st.b %1,%L0(%?r31)\";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return \"st.b %1,%0\";
|
|
|
|
|
return \"shl %?r0,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "trunchiqi2"
|
|
|
|
|
[(set (match_operand:QI 0 "general_operand" "=g")
|
|
|
|
|
(truncate:QI
|
|
|
|
|
(match_operand:HI 1 "register_operand" "r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (operands[0]) == MEM)
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
|
|
|
|
|
{
|
|
|
|
|
if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
|
|
|
|
|
&& (cc_prev_status.flags & CC_HI_R31_ADJ)
|
|
|
|
|
&& XEXP (operands[0], 0) == cc_prev_status.mdep))
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_INIT;
|
|
|
|
|
cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
|
|
|
|
|
cc_status.mdep = XEXP (operands[0], 0);
|
|
|
|
|
output_asm_insn (\"orh %h0,%?r0,%?r31\", operands);
|
|
|
|
|
}
|
|
|
|
|
return \"st.b %1,%L0(%?r31)\";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return \"st.b %1,%0\";
|
|
|
|
|
return \"shl %?r0,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "truncsihi2"
|
|
|
|
|
[(set (match_operand:HI 0 "general_operand" "=g")
|
|
|
|
|
(truncate:HI
|
|
|
|
|
(match_operand:SI 1 "register_operand" "r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (operands[0]) == MEM)
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
|
|
|
|
|
{
|
|
|
|
|
if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
|
|
|
|
|
&& (cc_prev_status.flags & CC_HI_R31_ADJ)
|
|
|
|
|
&& XEXP (operands[0], 0) == cc_prev_status.mdep))
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_INIT;
|
|
|
|
|
cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
|
|
|
|
|
cc_status.mdep = XEXP (operands[0], 0);
|
|
|
|
|
output_asm_insn (\"orh %h0,%?r0,%?r31\", operands);
|
|
|
|
|
}
|
|
|
|
|
return \"st.s %1,%L0(%?r31)\";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return \"st.s %1,%0\";
|
|
|
|
|
return \"shl %?r0,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;;- zero extension instructions
|
|
|
|
|
|
|
|
|
|
(define_insn "zero_extendhisi2"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(zero_extend:SI
|
|
|
|
|
(match_operand:HI 1 "register_operand" "r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"and 0xffff,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "zero_extendqihi2"
|
|
|
|
|
[(set (match_operand:HI 0 "register_operand" "=r")
|
|
|
|
|
(zero_extend:HI
|
|
|
|
|
(match_operand:QI 1 "register_operand" "r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"and 0xff,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "zero_extendqisi2"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(zero_extend:SI
|
|
|
|
|
(match_operand:QI 1 "register_operand" "r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"and 0xff,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Sign extension instructions.
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(match_operand:HI 1 "indexed_operand" "m")))]
|
|
|
|
|
""
|
|
|
|
|
"ld.s %1,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:HI 0 "register_operand" "=r")
|
|
|
|
|
(sign_extend:HI
|
|
|
|
|
(match_operand:QI 1 "indexed_operand" "m")))]
|
|
|
|
|
""
|
|
|
|
|
"ld.b %1,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(match_operand:QI 1 "indexed_operand" "m")))]
|
|
|
|
|
""
|
|
|
|
|
"ld.b %1,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn "extendhisi2"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(match_operand:HI 1 "nonimmediate_operand" "mr")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (REG_P (operands[1]))
|
|
|
|
|
return \"shl 16,%1,%0\;shra 16,%0,%0\";
|
|
|
|
|
if (GET_CODE (operands[1]) == CONST_INT)
|
|
|
|
|
abort ();
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_INIT;
|
|
|
|
|
cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
|
|
|
|
|
cc_status.mdep = XEXP (operands[1], 0);
|
|
|
|
|
return \"orh %h1,%?r0,%?r31\;ld.s %L1(%?r31),%0\";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return \"ld.s %1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "extendqihi2"
|
|
|
|
|
[(set (match_operand:HI 0 "register_operand" "=r")
|
|
|
|
|
(sign_extend:HI
|
|
|
|
|
(match_operand:QI 1 "nonimmediate_operand" "mr")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (REG_P (operands[1]))
|
|
|
|
|
return \"shl 24,%1,%0\;shra 24,%0,%0\";
|
|
|
|
|
if (GET_CODE (operands[1]) == CONST_INT)
|
|
|
|
|
abort ();
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_INIT;
|
|
|
|
|
cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
|
|
|
|
|
cc_status.mdep = XEXP (operands[1], 0);
|
|
|
|
|
return \"orh %h1,%?r0,%?r31\;ld.b %L1(%?r31),%0\";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return \"ld.b %1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "extendqisi2"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(match_operand:QI 1 "nonimmediate_operand" "mr")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (REG_P (operands[1]))
|
|
|
|
|
return \"shl 24,%1,%0\;shra 24,%0,%0\";
|
|
|
|
|
if (GET_CODE (operands[1]) == CONST_INT)
|
|
|
|
|
abort ();
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_INIT;
|
|
|
|
|
cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
|
|
|
|
|
cc_status.mdep = XEXP (operands[1], 0);
|
|
|
|
|
return \"orh %h1,%?r0,%?r31\;ld.b %L1(%?r31),%0\";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return \"ld.b %1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Signed bitfield extractions come out looking like
|
|
|
|
|
;; (shiftrt (sign_extend (shift <Y> <C1>)) <C2>)
|
|
|
|
|
;; which we expand poorly as four shift insns.
|
|
|
|
|
;; These patterns yield two shifts:
|
|
|
|
|
;; (shiftrt (shift <Y> <C3>) <C4>)
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(ashiftrt:SI
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(match_operand:QI 1 "register_operand" "r"))
|
|
|
|
|
(match_operand:SI 2 "logic_int" "n")))]
|
|
|
|
|
"INTVAL (operands[2]) < 8"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
return \"shl 24,%1,%0\;shra 24+%2,%0,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(ashiftrt:SI
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(subreg:QI (ashift:SI (match_operand:SI 1 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 2 "logic_int" "n")) 0))
|
|
|
|
|
(match_operand:SI 3 "logic_int" "n")))]
|
|
|
|
|
"INTVAL (operands[3]) < 8"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
return \"shl 0x18+%2,%1,%0\;shra 0x18+%3,%0,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(ashiftrt:SI
|
|
|
|
|
(sign_extend:SI
|
|
|
|
|
(ashift:QI (match_operand:QI 1 "register_operand" "r")
|
|
|
|
|
(match_operand:QI 2 "logic_int" "n")))
|
|
|
|
|
(match_operand:SI 3 "logic_int" "n")))]
|
|
|
|
|
"INTVAL (operands[3]) < 8"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
return \"shl 0x18+%2,%1,%0\;shra 0x18+%3,%0,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Special patterns for optimizing bit-field instructions.
|
|
|
|
|
|
|
|
|
|
;; First two patterns are for bitfields that came from memory
|
|
|
|
|
;; testing only the high bit. They work with old combiner.
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0)
|
|
|
|
|
(eq (zero_extend:SI (subreg:QI (lshiftrt:SI (match_operand:SI 0 "register_operand" "r")
|
|
|
|
|
(const_int 7)) 0))
|
|
|
|
|
(const_int 0)))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"and 128,%0,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0)
|
|
|
|
|
(eq (sign_extend:SI (subreg:QI (ashiftrt:SI (match_operand:SI 0 "register_operand" "r")
|
|
|
|
|
(const_int 7)) 0))
|
|
|
|
|
(const_int 0)))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"and 128,%0,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; next two patterns are good for bitfields coming from memory
|
|
|
|
|
;; (via pseudo-register) or from a register, though this optimization
|
|
|
|
|
;; is only good for values contained wholly within the bottom 13 bits
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0)
|
|
|
|
|
(eq
|
|
|
|
|
(and:SI (lshiftrt:SI (match_operand:SI 0 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 1 "logic_int" "n"))
|
|
|
|
|
(match_operand:SI 2 "logic_int" "n"))
|
|
|
|
|
(const_int 0)))]
|
|
|
|
|
"LOGIC_INTVAL (INTVAL (operands[2]) << INTVAL (operands[1]))"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[2] = GEN_INT ((INTVAL (operands[2]) << INTVAL (operands[1])));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"and %2,%0,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (cc0)
|
|
|
|
|
(eq
|
|
|
|
|
(and:SI (ashiftrt:SI (match_operand:SI 0 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 1 "logic_int" "n"))
|
|
|
|
|
(match_operand:SI 2 "logic_int" "n"))
|
|
|
|
|
(const_int 0)))]
|
|
|
|
|
"LOGIC_INTVAL (INTVAL (operands[2]) << INTVAL (operands[1]))"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[2] = GEN_INT ((INTVAL (operands[2]) << INTVAL (operands[1])));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"and %2,%0,%?r0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Conversions between float and double.
|
|
|
|
|
|
|
|
|
|
(define_insn "extendsfdf2"
|
|
|
|
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|
|
|
|
(float_extend:DF
|
|
|
|
|
(match_operand:SF 1 "register_operand" "f")))]
|
|
|
|
|
""
|
|
|
|
|
"fmov.sd %1,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn "truncdfsf2"
|
|
|
|
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|
|
|
|
(float_truncate:SF
|
|
|
|
|
(match_operand:DF 1 "register_operand" "f")))]
|
|
|
|
|
""
|
|
|
|
|
"fmov.ds %1,%0")
|
|
|
|
|
|
|
|
|
|
;; 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.
|
|
|
|
|
|
|
|
|
|
;; This pattern forces (set (reg:SF ...) (float:SF (const_int ...)))
|
|
|
|
|
;; to be reloaded by putting the constant into memory.
|
|
|
|
|
;; It must come before the more general floatsisf2 pattern.
|
|
|
|
|
(define_expand "floatsidf2"
|
|
|
|
|
[(set (match_dup 2) (match_dup 3))
|
|
|
|
|
(set (match_dup 4) (xor:SI (match_operand:SI 1 "register_operand" "")
|
|
|
|
|
(const_int -2147483648)))
|
|
|
|
|
(set (match_dup 5) (match_dup 3))
|
|
|
|
|
(set (subreg:SI (match_dup 5) 0) (match_dup 4))
|
|
|
|
|
(set (match_operand:DF 0 "register_operand" "")
|
|
|
|
|
(minus:DF (match_dup 5) (match_dup 2)))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
REAL_VALUE_TYPE d;
|
|
|
|
|
/* 4503601774854144 is (1 << 30) * ((1 << 22) + (1 << 1)). */
|
|
|
|
|
d = REAL_VALUE_ATOF (\"4503601774854144\", DFmode);
|
|
|
|
|
operands[2] = gen_reg_rtx (DFmode);
|
|
|
|
|
operands[3] = CONST_DOUBLE_FROM_REAL_VALUE (d, DFmode);
|
|
|
|
|
operands[4] = gen_reg_rtx (SImode);
|
|
|
|
|
operands[5] = gen_reg_rtx (DFmode);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Floating to fixed conversion.
|
|
|
|
|
|
|
|
|
|
(define_expand "fix_truncdfsi2"
|
|
|
|
|
;; This first insn produces a double-word value
|
|
|
|
|
;; in which only the low word is valid.
|
|
|
|
|
[(set (match_dup 2)
|
|
|
|
|
(fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f"))))
|
|
|
|
|
(set (match_operand:SI 0 "register_operand" "=f")
|
|
|
|
|
(subreg:SI (match_dup 2) 0))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
operands[2] = gen_reg_rtx (DImode);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Recognize the first insn generated above.
|
|
|
|
|
;; This RTL looks like a fix_truncdfdi2 insn,
|
|
|
|
|
;; but we dont call it that, because only 32 bits
|
|
|
|
|
;; of the result are valid.
|
|
|
|
|
;; This pattern will work for the intended purposes
|
|
|
|
|
;; as long as we do not have any fixdfdi2 or fix_truncdfdi2.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:DI 0 "register_operand" "=f")
|
|
|
|
|
(fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f"))))]
|
|
|
|
|
""
|
|
|
|
|
"ftrunc.dd %1,%0")
|
|
|
|
|
|
|
|
|
|
(define_expand "fix_truncsfsi2"
|
|
|
|
|
;; This first insn produces a double-word value
|
|
|
|
|
;; in which only the low word is valid.
|
|
|
|
|
[(set (match_dup 2)
|
|
|
|
|
(fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f"))))
|
|
|
|
|
(set (match_operand:SI 0 "register_operand" "=f")
|
|
|
|
|
(subreg:SI (match_dup 2) 0))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
operands[2] = gen_reg_rtx (DImode);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Recognize the first insn generated above.
|
|
|
|
|
;; This RTL looks like a fix_truncsfdi2 insn,
|
|
|
|
|
;; but we dont call it that, because only 32 bits
|
|
|
|
|
;; of the result are valid.
|
|
|
|
|
;; This pattern will work for the intended purposes
|
|
|
|
|
;; as long as we do not have any fixsfdi2 or fix_truncsfdi2.
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:DI 0 "register_operand" "=f")
|
|
|
|
|
(fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f"))))]
|
|
|
|
|
""
|
|
|
|
|
"ftrunc.sd %1,%0")
|
|
|
|
|
|
|
|
|
|
;;- arithmetic instructions
|
|
|
|
|
|
|
|
|
|
(define_insn "addsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r,*f")
|
|
|
|
|
(plus:SI (match_operand:SI 1 "nonmemory_operand" "%r,*f")
|
|
|
|
|
(match_operand:SI 2 "arith_operand" "rI,*f")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (which_alternative == 1)
|
|
|
|
|
return \"fiadd.ss %2,%1,%0\";
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"addu %2,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "adddi3"
|
|
|
|
|
[(set (match_operand:DI 0 "register_operand" "=f")
|
|
|
|
|
(plus:DI (match_operand:DI 1 "register_operand" "%f")
|
|
|
|
|
(match_operand:DI 2 "register_operand" "f")))]
|
|
|
|
|
""
|
|
|
|
|
"fiadd.dd %1,%2,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn "subsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r,r,*f")
|
|
|
|
|
(minus:SI (match_operand:SI 1 "register_operand" "r,I,*f")
|
|
|
|
|
(match_operand:SI 2 "arith_operand" "rI,r,*f")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (which_alternative == 2)
|
|
|
|
|
return \"fisub.ss %1,%2,%0\";
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (REG_P (operands[2]))
|
|
|
|
|
return \"subu %1,%2,%0\";
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[2] = GEN_INT (- INTVAL (operands[2]));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"addu %2,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "subdi3"
|
|
|
|
|
[(set (match_operand:DI 0 "register_operand" "=f")
|
|
|
|
|
(minus:DI (match_operand:DI 1 "register_operand" "f")
|
|
|
|
|
(match_operand:DI 2 "register_operand" "f")))]
|
|
|
|
|
""
|
|
|
|
|
"fisub.dd %1,%2,%0")
|
|
|
|
|
|
|
|
|
|
(define_expand "mulsi3"
|
|
|
|
|
[(set (subreg:SI (match_dup 4) 0) (match_operand:SI 1 "general_operand" ""))
|
|
|
|
|
(set (subreg:SI (match_dup 5) 0) (match_operand:SI 2 "general_operand" ""))
|
|
|
|
|
(clobber (match_dup 3))
|
|
|
|
|
(set (subreg:SI (match_dup 3) 0)
|
|
|
|
|
(mult:SI (subreg:SI (match_dup 4) 0) (subreg:SI (match_dup 5) 0)))
|
|
|
|
|
(set (match_operand:SI 0 "register_operand" "") (subreg:SI (match_dup 3) 0))]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
if (WORDS_BIG_ENDIAN)
|
|
|
|
|
emit_insn (gen_mulsi3_big (operands[0], operands[1], operands[2]));
|
|
|
|
|
else
|
|
|
|
|
emit_insn (gen_mulsi3_little (operands[0], operands[1], operands[2]));
|
|
|
|
|
DONE;
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "mulsi3_little"
|
|
|
|
|
[(set (subreg:SI (match_dup 4) 0) (match_operand:SI 1 "general_operand" ""))
|
|
|
|
|
(set (subreg:SI (match_dup 5) 0) (match_operand:SI 2 "general_operand" ""))
|
|
|
|
|
(clobber (match_dup 3))
|
|
|
|
|
(set (subreg:SI (match_dup 3) 0)
|
|
|
|
|
(mult:SI (subreg:SI (match_dup 4) 0) (subreg:SI (match_dup 5) 0)))
|
|
|
|
|
(set (match_operand:SI 0 "register_operand" "") (subreg:SI (match_dup 3) 0))]
|
|
|
|
|
"! WORDS_BIG_ENDIAN"
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
operands[3] = gen_reg_rtx (DImode);
|
|
|
|
|
operands[4] = gen_reg_rtx (DImode);
|
|
|
|
|
operands[5] = gen_reg_rtx (DImode);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "mulsi3_big"
|
|
|
|
|
[(set (subreg:SI (match_dup 4) 1) (match_operand:SI 1 "general_operand" ""))
|
|
|
|
|
(set (subreg:SI (match_dup 5) 1) (match_operand:SI 2 "general_operand" ""))
|
|
|
|
|
(clobber (match_dup 3))
|
|
|
|
|
(set (subreg:SI (match_dup 3) 1)
|
|
|
|
|
(mult:SI (subreg:SI (match_dup 4) 1) (subreg:SI (match_dup 5) 1)))
|
|
|
|
|
(set (match_operand:SI 0 "register_operand" "") (subreg:SI (match_dup 3) 1))]
|
|
|
|
|
"WORDS_BIG_ENDIAN"
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
operands[3] = gen_reg_rtx (DImode);
|
|
|
|
|
operands[4] = gen_reg_rtx (DImode);
|
|
|
|
|
operands[5] = gen_reg_rtx (DImode);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (subreg:SI (match_operand:DI 0 "register_operand" "=f") 0)
|
|
|
|
|
(mult:SI (subreg:SI (match_operand:DI 1 "register_operand" "f") 0)
|
|
|
|
|
(subreg:SI (match_operand:DI 2 "register_operand" "f") 0)))]
|
|
|
|
|
"! WORDS_BIG_ENDIAN"
|
|
|
|
|
"fmlow.dd %2,%1,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (subreg:SI (match_operand:DI 0 "register_operand" "=f") 1)
|
|
|
|
|
(mult:SI (subreg:SI (match_operand:DI 1 "register_operand" "f") 1)
|
|
|
|
|
(subreg:SI (match_operand:DI 2 "register_operand" "f") 1)))]
|
|
|
|
|
"WORDS_BIG_ENDIAN"
|
|
|
|
|
"fmlow.dd %2,%1,%0")
|
|
|
|
|
|
|
|
|
|
;;- and instructions (with compliment also)
|
|
|
|
|
(define_insn "andsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(and:SI (match_operand:SI 1 "nonmemory_operand" "%r")
|
|
|
|
|
(match_operand:SI 2 "nonmemory_operand" "rL")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
rtx xop[3];
|
|
|
|
|
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (REG_P (operands[2]) || LOGIC_INT (operands[2]))
|
|
|
|
|
return \"and %2,%1,%0\";
|
|
|
|
|
if ((INTVAL (operands[2]) & 0xffff) == 0)
|
|
|
|
|
{
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[2] = GEN_INT ((unsigned) INTVAL (operands[2]) >> 16);
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"andh %2,%1,%0\";
|
|
|
|
|
}
|
|
|
|
|
xop[0] = operands[0];
|
|
|
|
|
xop[1] = operands[1];
|
1998-08-16 21:35:45 +04:00
|
|
|
|
xop[2] = GEN_INT (~INTVAL (operands[2]) & 0xffff);
|
1998-03-29 12:14:27 +04:00
|
|
|
|
output_asm_insn (\"andnot %2,%1,%0\", xop);
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[2] = GEN_INT (~(unsigned) INTVAL (operands[2]) >> 16);
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"andnoth %2,%0,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(and:SI (not:SI (match_operand:SI 1 "register_operand" "rn"))
|
|
|
|
|
(match_operand:SI 2 "register_operand" "r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
rtx xop[3];
|
|
|
|
|
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (REG_P (operands[1]) || LOGIC_INT (operands[1]))
|
|
|
|
|
return \"andnot %1,%2,%0\";
|
|
|
|
|
if ((INTVAL (operands[1]) & 0xffff) == 0)
|
|
|
|
|
{
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[1] = GEN_INT ((unsigned) INTVAL (operands[1]) >> 16);
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"andnoth %1,%2,%0\";
|
|
|
|
|
}
|
|
|
|
|
xop[0] = operands[0];
|
1998-08-16 21:35:45 +04:00
|
|
|
|
xop[1] = GEN_INT ((INTVAL (operands[1]) & 0xffff));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
xop[2] = operands[2];
|
|
|
|
|
output_asm_insn (\"andnot %1,%2,%0\", xop);
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[1] = GEN_INT ((unsigned) INTVAL (operands[1]) >> 16);
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"andnoth %1,%0,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "iorsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(ior:SI (match_operand:SI 1 "nonmemory_operand" "%r")
|
|
|
|
|
(match_operand:SI 2 "nonmemory_operand" "rL")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
rtx xop[3];
|
|
|
|
|
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (REG_P (operands[2]) || LOGIC_INT (operands[2]))
|
|
|
|
|
return \"or %2,%1,%0\";
|
|
|
|
|
if ((INTVAL (operands[2]) & 0xffff) == 0)
|
|
|
|
|
{
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[2] = GEN_INT ((unsigned) INTVAL (operands[2]) >> 16);
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"orh %2,%1,%0\";
|
|
|
|
|
}
|
|
|
|
|
xop[0] = operands[0];
|
|
|
|
|
xop[1] = operands[1];
|
1998-08-16 21:35:45 +04:00
|
|
|
|
xop[2] = GEN_INT ((INTVAL (operands[2]) & 0xffff));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
output_asm_insn (\"or %2,%1,%0\", xop);
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[2] = GEN_INT ((unsigned) INTVAL (operands[2]) >> 16);
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"orh %2,%0,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "xorsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(xor:SI (match_operand:SI 1 "nonmemory_operand" "%r")
|
|
|
|
|
(match_operand:SI 2 "nonmemory_operand" "rL")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
rtx xop[3];
|
|
|
|
|
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (REG_P (operands[2]) || LOGIC_INT (operands[2]))
|
|
|
|
|
return \"xor %2,%1,%0\";
|
|
|
|
|
if ((INTVAL (operands[2]) & 0xffff) == 0)
|
|
|
|
|
{
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[2] = GEN_INT ((unsigned) INTVAL (operands[2]) >> 16);
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"xorh %2,%1,%0\";
|
|
|
|
|
}
|
|
|
|
|
xop[0] = operands[0];
|
|
|
|
|
xop[1] = operands[1];
|
1998-08-16 21:35:45 +04:00
|
|
|
|
xop[2] = GEN_INT ((INTVAL (operands[2]) & 0xffff));
|
1998-03-29 12:14:27 +04:00
|
|
|
|
output_asm_insn (\"xor %2,%1,%0\", xop);
|
1998-08-16 21:35:45 +04:00
|
|
|
|
operands[2] = GEN_INT ((unsigned) INTVAL (operands[2]) >> 16);
|
1998-03-29 12:14:27 +04:00
|
|
|
|
return \"xorh %2,%0,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;(The i860 instruction set doesn't allow an immediate second operand in
|
|
|
|
|
; a subtraction.)
|
|
|
|
|
(define_insn "negsi2"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=r")
|
|
|
|
|
(neg:SI (match_operand:SI 1 "arith_operand" "r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"subu %?r0,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "one_cmplsi2"
|
|
|
|
|
[(set (match_operand:SI 0 "general_operand" "=r")
|
|
|
|
|
(not:SI (match_operand:SI 1 "arith_operand" "r")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
return \"subu -1,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Floating point arithmetic instructions.
|
|
|
|
|
|
|
|
|
|
(define_insn "adddf3"
|
|
|
|
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|
|
|
|
(plus:DF (match_operand:DF 1 "register_operand" "f")
|
|
|
|
|
(match_operand:DF 2 "register_operand" "f")))]
|
|
|
|
|
""
|
|
|
|
|
"fadd.dd %1,%2,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn "addsf3"
|
|
|
|
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|
|
|
|
(plus:SF (match_operand:SF 1 "register_operand" "f")
|
|
|
|
|
(match_operand:SF 2 "register_operand" "f")))]
|
|
|
|
|
""
|
|
|
|
|
"fadd.ss %1,%2,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn "subdf3"
|
|
|
|
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|
|
|
|
(minus:DF (match_operand:DF 1 "register_operand" "f")
|
|
|
|
|
(match_operand:DF 2 "register_operand" "f")))]
|
|
|
|
|
""
|
|
|
|
|
"fsub.dd %1,%2,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn "subsf3"
|
|
|
|
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|
|
|
|
(minus:SF (match_operand:SF 1 "register_operand" "f")
|
|
|
|
|
(match_operand:SF 2 "register_operand" "f")))]
|
|
|
|
|
""
|
|
|
|
|
"fsub.ss %1,%2,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn "muldf3"
|
|
|
|
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|
|
|
|
(mult:DF (match_operand:DF 1 "register_operand" "f")
|
|
|
|
|
(match_operand:DF 2 "register_operand" "f")))]
|
|
|
|
|
""
|
|
|
|
|
"fmul.dd %1,%2,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn "mulsf3"
|
|
|
|
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|
|
|
|
(mult:SF (match_operand:SF 1 "register_operand" "f")
|
|
|
|
|
(match_operand:SF 2 "register_operand" "f")))]
|
|
|
|
|
""
|
|
|
|
|
"fmul.ss %1,%2,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn "negdf2"
|
|
|
|
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|
|
|
|
(neg:DF (match_operand:DF 1 "register_operand" "f")))]
|
|
|
|
|
""
|
|
|
|
|
"fsub.dd %?f0,%1,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn "negsf2"
|
|
|
|
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|
|
|
|
(neg:SF (match_operand:SF 1 "register_operand" "f")))]
|
|
|
|
|
""
|
|
|
|
|
"fsub.ss %?f0,%1,%0")
|
|
|
|
|
|
|
|
|
|
(define_insn "divdf3"
|
|
|
|
|
[(set (match_operand:DF 0 "register_operand" "=&f")
|
|
|
|
|
(div:DF (match_operand:DF 1 "register_operand" "f")
|
|
|
|
|
(match_operand:DF 2 "register_operand" "f")))
|
|
|
|
|
(clobber (match_scratch:DF 3 "=&f"))
|
|
|
|
|
(clobber (match_scratch:DF 4 "=&f"))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (((cc_prev_status.flags & CC_KNOW_HI_R31) == 0)
|
|
|
|
|
|| (cc_prev_status.flags & CC_HI_R31_ADJ)
|
|
|
|
|
|| (cc_prev_status.mdep != CONST2_RTX (SFmode)))
|
|
|
|
|
{
|
|
|
|
|
cc_status.flags |= CC_KNOW_HI_R31;
|
|
|
|
|
cc_status.flags &= ~CC_HI_R31_ADJ;
|
|
|
|
|
cc_status.mdep = CONST2_RTX (SFmode);
|
|
|
|
|
return \"frcp.dd %2,%3\;fmul.dd %2,%3,%0\;fmov.dd %?f0,%4\;\\\
|
|
|
|
|
orh 0x4000,%?r0,%?r31\;ixfr %?r31,%R4\;fsub.dd %4,%0,%0\;\\\
|
|
|
|
|
fmul.dd %3,%0,%3\;fmul.dd %2,%3,%0\;fsub.dd %4,%0,%0\;\\\
|
|
|
|
|
fmul.dd %3,%0,%3\;fmul.dd %2,%3,%0\;fsub.dd %4,%0,%0\;\\\
|
|
|
|
|
fmul.dd %3,%1,%3\;fmul.dd %0,%3,%0\";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return \"frcp.dd %2,%3\;fmul.dd %2,%3,%0\;fmov.dd %?f0,%4\;\\\
|
|
|
|
|
ixfr %?r31,%R4\;fsub.dd %4,%0,%0\;\\\
|
|
|
|
|
fmul.dd %3,%0,%3\;fmul.dd %2,%3,%0\;fsub.dd %4,%0,%0\;\\\
|
|
|
|
|
fmul.dd %3,%0,%3\;fmul.dd %2,%3,%0\;fsub.dd %4,%0,%0\;\\\
|
|
|
|
|
fmul.dd %3,%1,%3\;fmul.dd %0,%3,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "divsf3"
|
|
|
|
|
[(set (match_operand:SF 0 "register_operand" "=&f")
|
|
|
|
|
(div:SF (match_operand:SF 1 "register_operand" "f")
|
|
|
|
|
(match_operand:SF 2 "register_operand" "f")))
|
|
|
|
|
(clobber (match_scratch:SF 3 "=&f"))
|
|
|
|
|
(clobber (match_scratch:SF 4 "=&f"))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_PARTIAL_INIT;
|
|
|
|
|
if (((cc_prev_status.flags & CC_KNOW_HI_R31) == 0)
|
|
|
|
|
|| (cc_prev_status.flags & CC_HI_R31_ADJ)
|
|
|
|
|
|| (cc_prev_status.mdep != CONST2_RTX (SFmode)))
|
|
|
|
|
{
|
|
|
|
|
cc_status.flags |= CC_KNOW_HI_R31;
|
|
|
|
|
cc_status.flags &= ~CC_HI_R31_ADJ;
|
|
|
|
|
cc_status.mdep = CONST2_RTX (SFmode);
|
|
|
|
|
output_asm_insn (\"orh 0x4000,%?r0,%?r31\", operands);
|
|
|
|
|
}
|
|
|
|
|
return \"ixfr %?r31,%4\;frcp.ss %2,%0\;\\\
|
|
|
|
|
fmul.ss %2,%0,%3\;fsub.ss %4,%3,%3\;fmul.ss %0,%3,%0\;\\\
|
|
|
|
|
fmul.ss %2,%0,%3\;fsub.ss %4,%3,%3\;\\\
|
|
|
|
|
fmul.ss %1,%0,%4\;fmul.ss %3,%4,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Shift instructions
|
|
|
|
|
|
|
|
|
|
;; Optimized special case of shifting.
|
|
|
|
|
;; Must precede the general case.
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(ashiftrt:SI (match_operand:SI 1 "memory_operand" "m")
|
|
|
|
|
(const_int 24)))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_INIT;
|
|
|
|
|
cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
|
|
|
|
|
cc_status.mdep = XEXP (operands[1], 0);
|
|
|
|
|
return \"orh %h1,%?r0,%?r31\;ld.b %L1(%?r31),%0\";
|
|
|
|
|
}
|
|
|
|
|
return \"ld.b %1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;- arithmetic shift instructions
|
|
|
|
|
(define_insn "ashlsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(ashift:SI (match_operand:SI 1 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 2 "shift_operand" "rn")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
return \"shl %2,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "ashlhi3"
|
|
|
|
|
[(set (match_operand:HI 0 "register_operand" "=r")
|
|
|
|
|
(ashift:HI (match_operand:HI 1 "register_operand" "r")
|
|
|
|
|
(match_operand:HI 2 "shift_operand" "rn")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
return \"shl %2,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "ashlqi3"
|
|
|
|
|
[(set (match_operand:QI 0 "register_operand" "=r")
|
|
|
|
|
(ashift:QI (match_operand:QI 1 "register_operand" "r")
|
|
|
|
|
(match_operand:QI 2 "shift_operand" "rn")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
return \"shl %2,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "ashrsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(ashiftrt:SI (match_operand:SI 1 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 2 "shift_operand" "rn")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
return \"shra %2,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn "lshrsi3"
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
|
|
|
|
|
(match_operand:SI 2 "shift_operand" "rn")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
return \"shr %2,%1,%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Unconditional and other jump instructions
|
|
|
|
|
|
|
|
|
|
(define_insn "jump"
|
|
|
|
|
[(set (pc) (label_ref (match_operand 0 "" "")))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
return \"br %l0\;nop\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Here are two simple peepholes which fill the delay slot of
|
|
|
|
|
;; an unconditional branch.
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=rf")
|
|
|
|
|
(match_operand:SI 1 "single_insn_src_p" "gfG"))
|
|
|
|
|
(set (pc) (label_ref (match_operand 2 "" "")))]
|
|
|
|
|
""
|
|
|
|
|
"* return output_delayed_branch (\"br %l2\", operands, insn);")
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (match_operand:SI 0 "memory_operand" "=m")
|
|
|
|
|
(match_operand:SI 1 "reg_or_0_operand" "rfJ"))
|
|
|
|
|
(set (pc) (label_ref (match_operand 2 "" "")))]
|
|
|
|
|
""
|
|
|
|
|
"* return output_delayed_branch (\"br %l2\", operands, insn);")
|
|
|
|
|
|
|
|
|
|
(define_insn "tablejump"
|
|
|
|
|
[(set (pc) (match_operand:SI 0 "register_operand" "r"))
|
|
|
|
|
(use (label_ref (match_operand 1 "" "")))]
|
|
|
|
|
""
|
|
|
|
|
"bri %0\;nop")
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (match_operand:SI 0 "memory_operand" "=m")
|
|
|
|
|
(match_operand:SI 1 "reg_or_0_operand" "rfJ"))
|
|
|
|
|
(set (pc) (match_operand:SI 2 "register_operand" "r"))
|
|
|
|
|
(use (label_ref (match_operand 3 "" "")))]
|
|
|
|
|
""
|
|
|
|
|
"* return output_delayed_branch (\"bri %2\", operands, insn);")
|
|
|
|
|
|
|
|
|
|
;;- jump to subroutine
|
|
|
|
|
(define_expand "call"
|
|
|
|
|
[(call (match_operand:SI 0 "memory_operand" "m")
|
|
|
|
|
(match_operand 1 "" "i"))]
|
|
|
|
|
;; operand[2] is next_arg_register
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* Make sure the address is just one reg and will stay that way. */
|
|
|
|
|
if (! call_insn_operand (operands[0], QImode))
|
|
|
|
|
operands[0]
|
|
|
|
|
= change_address (operands[0], VOIDmode,
|
|
|
|
|
copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
|
|
|
|
|
if (INTVAL (operands[1]) > 0)
|
|
|
|
|
{
|
|
|
|
|
emit_move_insn (arg_pointer_rtx, stack_pointer_rtx);
|
|
|
|
|
emit_insn (gen_rtx (USE, VOIDmode, arg_pointer_rtx));
|
|
|
|
|
}
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;;- jump to subroutine
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(call (match_operand:SI 0 "call_insn_operand" "m")
|
|
|
|
|
(match_operand 1 "" "i"))]
|
|
|
|
|
;; operand[2] is next_arg_register
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
/* strip the MEM. */
|
|
|
|
|
operands[0] = XEXP (operands[0], 0);
|
|
|
|
|
CC_STATUS_INIT;
|
|
|
|
|
if (GET_CODE (operands[0]) == REG)
|
|
|
|
|
return \"calli %0\;nop\";
|
|
|
|
|
return \"call %0\;nop\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=rf")
|
|
|
|
|
(match_operand:SI 1 "single_insn_src_p" "gfG"))
|
|
|
|
|
(call (match_operand:SI 2 "memory_operand" "m")
|
|
|
|
|
(match_operand 3 "" "i"))]
|
|
|
|
|
;;- Don't use operand 1 for most machines.
|
|
|
|
|
"! reg_mentioned_p (operands[0], operands[2])"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
/* strip the MEM. */
|
|
|
|
|
operands[2] = XEXP (operands[2], 0);
|
|
|
|
|
if (GET_CODE (operands[2]) == REG)
|
|
|
|
|
return output_delayed_branch (\"calli %2\", operands, insn);
|
|
|
|
|
return output_delayed_branch (\"call %2\", operands, insn);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (match_operand:SI 0 "memory_operand" "=m")
|
|
|
|
|
(match_operand:SI 1 "reg_or_0_operand" "rfJ"))
|
|
|
|
|
(call (match_operand:SI 2 "call_insn_operand" "m")
|
|
|
|
|
(match_operand 3 "" "i"))]
|
|
|
|
|
;;- Don't use operand 1 for most machines.
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
/* strip the MEM. */
|
|
|
|
|
operands[2] = XEXP (operands[2], 0);
|
|
|
|
|
if (GET_CODE (operands[2]) == REG)
|
|
|
|
|
return output_delayed_branch (\"calli %2\", operands, insn);
|
|
|
|
|
return output_delayed_branch (\"call %2\", operands, insn);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_expand "call_value"
|
|
|
|
|
[(set (match_operand 0 "register_operand" "=rf")
|
|
|
|
|
(call (match_operand:SI 1 "memory_operand" "m")
|
|
|
|
|
(match_operand 2 "" "i")))]
|
|
|
|
|
;; operand 3 is next_arg_register
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
/* Make sure the address is just one reg and will stay that way. */
|
|
|
|
|
if (! call_insn_operand (operands[1], QImode))
|
|
|
|
|
operands[1]
|
|
|
|
|
= change_address (operands[1], VOIDmode,
|
|
|
|
|
copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
|
|
|
|
|
if (INTVAL (operands[2]) > 0)
|
|
|
|
|
{
|
|
|
|
|
emit_move_insn (arg_pointer_rtx, stack_pointer_rtx);
|
|
|
|
|
emit_insn (gen_rtx (USE, VOIDmode, arg_pointer_rtx));
|
|
|
|
|
}
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand 0 "register_operand" "=rf")
|
|
|
|
|
(call (match_operand:SI 1 "call_insn_operand" "m")
|
|
|
|
|
(match_operand 2 "" "i")))]
|
|
|
|
|
;; operand 3 is next_arg_register
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
/* strip the MEM. */
|
|
|
|
|
operands[1] = XEXP (operands[1], 0);
|
|
|
|
|
CC_STATUS_INIT;
|
|
|
|
|
if (GET_CODE (operands[1]) == REG)
|
|
|
|
|
return \"calli %1\;nop\";
|
|
|
|
|
return \"call %1\;nop\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=rf")
|
|
|
|
|
(match_operand:SI 1 "single_insn_src_p" "gfG"))
|
|
|
|
|
(set (match_operand 2 "" "=rf")
|
|
|
|
|
(call (match_operand:SI 3 "call_insn_operand" "m")
|
|
|
|
|
(match_operand 4 "" "i")))]
|
|
|
|
|
;;- Don't use operand 4 for most machines.
|
|
|
|
|
"! reg_mentioned_p (operands[0], operands[3])"
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
/* strip the MEM. */
|
|
|
|
|
operands[3] = XEXP (operands[3], 0);
|
|
|
|
|
if (GET_CODE (operands[3]) == REG)
|
|
|
|
|
return output_delayed_branch (\"calli %3\", operands, insn);
|
|
|
|
|
return output_delayed_branch (\"call %3\", operands, insn);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (match_operand:SI 0 "memory_operand" "=m")
|
|
|
|
|
(match_operand:SI 1 "reg_or_0_operand" "rJf"))
|
|
|
|
|
(set (match_operand 2 "" "=rf")
|
|
|
|
|
(call (match_operand:SI 3 "call_insn_operand" "m")
|
|
|
|
|
(match_operand 4 "" "i")))]
|
|
|
|
|
;;- Don't use operand 4 for most machines.
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
/* strip the MEM. */
|
|
|
|
|
operands[3] = XEXP (operands[3], 0);
|
|
|
|
|
if (GET_CODE (operands[3]) == REG)
|
|
|
|
|
return output_delayed_branch (\"calli %3\", operands, insn);
|
|
|
|
|
return output_delayed_branch (\"call %3\", operands, insn);
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
;; Call subroutine returning any type.
|
|
|
|
|
|
|
|
|
|
(define_expand "untyped_call"
|
|
|
|
|
[(parallel [(call (match_operand 0 "" "")
|
|
|
|
|
(const_int 0))
|
|
|
|
|
(match_operand 1 "" "")
|
|
|
|
|
(match_operand 2 "" "")])]
|
|
|
|
|
""
|
|
|
|
|
"
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
emit_call_insn (gen_call (operands[0], const0_rtx, 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)] 0)]
|
|
|
|
|
""
|
|
|
|
|
"")
|
|
|
|
|
|
|
|
|
|
(define_insn "nop"
|
|
|
|
|
[(const_int 0)]
|
|
|
|
|
""
|
|
|
|
|
"nop")
|
|
|
|
|
|
|
|
|
|
(define_insn "indirect_jump"
|
|
|
|
|
[(set (pc) (match_operand:SI 0 "register_operand" "r"))]
|
|
|
|
|
""
|
|
|
|
|
"bri %0")
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
;; A special insn that does the work to get setup just
|
|
|
|
|
;; before a table jump.
|
|
|
|
|
;;
|
|
|
|
|
(define_insn ""
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
|
|
(mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r")
|
|
|
|
|
(label_ref (match_operand 2 "" "")))))]
|
|
|
|
|
""
|
|
|
|
|
"*
|
|
|
|
|
{
|
|
|
|
|
CC_STATUS_INIT;
|
|
|
|
|
return \"orh %H2,%?r0,%?r31\;or %L2,%?r31,%?r31\;ld.l %?r31(%1),%0\";
|
|
|
|
|
}")
|
|
|
|
|
|
|
|
|
|
(define_peephole
|
|
|
|
|
[(set (match_operand:SI 0 "register_operand" "=rf")
|
|
|
|
|
(match_operand:SI 1 "single_insn_src_p" "gfG"))
|
|
|
|
|
(set (pc) (match_operand:SI 2 "register_operand" "r"))
|
|
|
|
|
(use (label_ref (match_operand 3 "" "")))]
|
|
|
|
|
"REGNO (operands[0]) != REGNO (operands[2])"
|
|
|
|
|
"* return output_delayed_branch (\"bri %2\", operands, insn);")
|