;;- Machine description for Intel 860 chip for GNU C compiler ;; Copyright (C) 1989, 1990 Free Software Foundation, Inc. ;; This file is part of GNU CC. ;; GNU CC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; GNU CC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU CC; see the file COPYING. If not, write to ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ;;- 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; operands[2] = gen_rtx (CONST_INT, VOIDmode, ~((-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_rtx (CONST_INT, VOIDmode, - 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_rtx (CONST_INT, VOIDmode, - 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_rtx (CONST_INT, VOIDmode, - 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_rtx (CONST_INT, VOIDmode, - 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_rtx (CONST_INT, VOIDmode, - 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_rtx (CONST_INT, VOIDmode, - 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 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" [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" "")) (mem:BLK (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 0)) (clobber (match_dup 1))])] "" " { operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); operands[4] = gen_reg_rtx (SImode); operands[5] = gen_reg_rtx (SImode); operands[6] = gen_reg_rtx (SImode); }") (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 patters yeild 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; operands[2] = gen_rtx (CONST_INT, VOIDmode, (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_rtx (CONST_INT, VOIDmode, (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\"); 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\"; operands[2] = gen_rtx (CONST_INT, VOIDmode, - 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) 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) { operands[2] = gen_rtx (CONST_INT, VOIDmode, (unsigned) INTVAL (operands[2]) >> 16); return \"andh %2,%1,%0\"; } xop[0] = operands[0]; xop[1] = operands[1]; xop[2] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2]) & 0xffff); output_asm_insn (\"andnot %2,%1,%0\", xop); operands[2] = gen_rtx (CONST_INT, VOIDmode, ~(unsigned) 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_rtx (CONST_INT, VOIDmode, (unsigned) INTVAL (operands[1]) >> 16); return \"andnoth %1,%2,%0\"; } xop[0] = operands[0]; xop[1] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[1]) & 0xffff)); xop[2] = operands[2]; output_asm_insn (\"andnot %1,%2,%0\", xop); operands[1] = gen_rtx (CONST_INT, VOIDmode, (unsigned) 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_rtx (CONST_INT, VOIDmode, (unsigned) INTVAL (operands[2]) >> 16); return \"orh %2,%1,%0\"; } xop[0] = operands[0]; xop[1] = operands[1]; xop[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) & 0xffff)); output_asm_insn (\"or %2,%1,%0\", xop); operands[2] = gen_rtx (CONST_INT, VOIDmode, (unsigned) 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_rtx (CONST_INT, VOIDmode, (unsigned) INTVAL (operands[2]) >> 16); return \"xorh %2,%1,%0\"; } xop[0] = operands[0]; xop[1] = operands[1]; xop[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) & 0xffff)); output_asm_insn (\"xor %2,%1,%0\", xop); operands[2] = gen_rtx (CONST_INT, VOIDmode, (unsigned) 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. ;; 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 "" " { 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 "memory_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 "memory_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 "" " { 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 "memory_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 "memory_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 "memory_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); }") (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);") ;;- Local variables: ;;- mode:emacs-lisp ;;- comment-start: ";;- " ;;- eval: (set-syntax-table (copy-sequence (syntax-table))) ;;- eval: (modify-syntax-entry ?[ "(]") ;;- eval: (modify-syntax-entry ?] ")[") ;;- eval: (modify-syntax-entry ?{ "(}") ;;- eval: (modify-syntax-entry ?} "){") ;;- End: