| ;; GCC Machine description for the Intel i860 microprocessor |
| ;; Copyright (C) 1989, 1990, 1997, 1998, 1999, 2000, 2003 |
| ;; Free Software Foundation, Inc. |
| |
| ;; This file is part of GCC. |
| |
| ;; GCC 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. |
| |
| ;; GCC 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 GCC; 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. |
| |
| ;; |
| ;; UNSPEC_VOLATILE usage |
| ;; |
| |
| (define_constants |
| [; Blockage |
| (UNSPECV_BLOCKAGE 0) |
| ]) |
| |
| ;;- 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; |
| operands[2] = GEN_INT (~((-1) << width) << pos); |
| 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; |
| operands[1] = GEN_INT (- INTVAL (operands[1])); |
| 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; |
| operands[0] = GEN_INT (- INTVAL (operands[0])); |
| 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; |
| operands[0] = GEN_INT (- INTVAL (operands[0])); |
| 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; |
| operands[1] = GEN_INT (- INTVAL (operands[1])); |
| 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; |
| operands[1] = GEN_INT (- INTVAL (operands[1])); |
| 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; |
| operands[0] = GEN_INT (- INTVAL (operands[0])); |
| 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 *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 *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" |
| [(parallel [(set (match_operand:BLK 0 "general_operand" "") |
| (match_operand:BLK 1 "general_operand" "")) |
| (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)) |
| (clobber (match_dup 7)) |
| (clobber (match_dup 8))])] |
| "" |
| " |
| { |
| operands[4] = gen_reg_rtx (SImode); |
| operands[5] = gen_reg_rtx (SImode); |
| operands[6] = gen_reg_rtx (SImode); |
| operands[7] = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); |
| operands[8] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); |
| |
| operands[0] = replace_equiv_address (operands[0], operands[7]); |
| operands[1] = replace_equiv_address (operands[1], operands[8]); |
| }") |
| |
| (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\"; |
| }") |
| |
| ;; The 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; |
| operands[2] = GEN_INT (INTVAL (operands[2]) << INTVAL (operands[1])); |
| 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; |
| operands[2] = GEN_INT (INTVAL (operands[2]) << INTVAL (operands[1])); |
| 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 don't 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 don't 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\"; |
| operands[2] = GEN_INT (- INTVAL (operands[2])); |
| 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) 4) (match_operand:SI 1 "general_operand" "")) |
| (set (subreg:SI (match_dup 5) 4) (match_operand:SI 2 "general_operand" "")) |
| (clobber (match_dup 3)) |
| (set (subreg:SI (match_dup 3) 4) |
| (mult:SI (subreg:SI (match_dup 4) 4) (subreg:SI (match_dup 5) 4))) |
| (set (match_operand:SI 0 "register_operand" "") (subreg:SI (match_dup 3) 4))] |
| "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") 4) |
| (mult:SI (subreg:SI (match_operand:DI 1 "register_operand" "f") 4) |
| (subreg:SI (match_operand:DI 2 "register_operand" "f") 4)))] |
| "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) |
| { |
| operands[2] |
| = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (operands[2]) >> 16); |
| return \"andh %2,%1,%0\"; |
| } |
| xop[0] = operands[0]; |
| xop[1] = operands[1]; |
| xop[2] = GEN_INT (~INTVAL (operands[2]) & 0xffff); |
| output_asm_insn (\"andnot %2,%1,%0\", xop); |
| operands[2] = GEN_INT (~(unsigned HOST_WIDE_INT) INTVAL (operands[2]) >> 16); |
| 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) |
| { |
| operands[1] |
| = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (operands[1]) >> 16); |
| return \"andnoth %1,%2,%0\"; |
| } |
| xop[0] = operands[0]; |
| xop[1] = GEN_INT (INTVAL (operands[1]) & 0xffff); |
| xop[2] = operands[2]; |
| output_asm_insn (\"andnot %1,%2,%0\", xop); |
| operands[1] = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (operands[1]) >> 16); |
| 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) |
| { |
| operands[2] |
| = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (operands[2]) >> 16); |
| return \"orh %2,%1,%0\"; |
| } |
| xop[0] = operands[0]; |
| xop[1] = operands[1]; |
| xop[2] = GEN_INT (INTVAL (operands[2]) & 0xffff); |
| output_asm_insn (\"or %2,%1,%0\", xop); |
| operands[2] = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (operands[2]) >> 16); |
| 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) |
| { |
| operands[2] |
| = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (operands[2]) >> 16); |
| return \"xorh %2,%1,%0\"; |
| } |
| xop[0] = operands[0]; |
| xop[1] = operands[1]; |
| xop[2] = GEN_INT (INTVAL (operands[2]) & 0xffff); |
| output_asm_insn (\"xor %2,%1,%0\", xop); |
| operands[2] = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (operands[2]) >> 16); |
| 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, which 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\"; |
| }") |
| |
| (define_insn "tablejump" |
| [(set (pc) (match_operand:SI 0 "register_operand" "r")) |
| (use (label_ref (match_operand 1 "" "")))] |
| "" |
| "bri %0\;nop") |
| |
| ;;- 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] |
| = replace_equiv_address (operands[0], |
| 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_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] |
| = replace_equiv_address (operands[1], |
| 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\"; |
| }") |
| |
| ;; 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)] UNSPECV_BLOCKAGE)] |
| "" |
| "") |
| |
| (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\"; |
| }") |
| |