| ;;- Machine description for Intel 80960 chip for GNU C compiler |
| ;; Copyright (C) 1992, 1995 Free Software Foundation, Inc. |
| ;; Contributed by Steven McGeady, Intel Corp. |
| ;; Additional work by Glenn Colon-Bonet, Jonathan Shapiro, Andy Wilson |
| ;; Converted to GCC 2.0 by Jim Wilson and Michael Tiemann, Cygnus Support. |
| |
| ;; This file is part of GNU CC. |
| |
| ;; GNU CC is free software; you can redistribute it and/or modify |
| ;; it under the terms of the GNU General Public License as published by |
| ;; the Free Software Foundation; either version 2, or (at your option) |
| ;; any later version. |
| |
| ;; GNU CC is distributed in the hope that it will be useful, |
| ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ;; GNU General Public License for more details. |
| |
| ;; You should have received a copy of the GNU General Public License |
| ;; along with GNU CC; see the file COPYING. If not, write to |
| ;; the Free Software Foundation, 59 Temple Place - Suite 330, |
| ;; Boston, MA 02111-1307, USA. |
| |
| ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. |
| |
| ;; There are very few (4) 'f' registers, they can't be loaded/stored from/to |
| ;; memory, and some instructions explicitly require them, so we get better |
| ;; code by discouraging pseudo-registers from being allocated to them. |
| ;; However, we do want to allow all patterns which can store to them to |
| ;; include them in their constraints, so we always use '*f' in a destination |
| ;; constraint except when 'f' is the only alternative. |
| |
| ;; Insn attributes which describe the i960. |
| |
| ;; Modscan is not used, since the compiler never emits any of these insns. |
| (define_attr "type" |
| "move,arith,alu2,mult,div,modscan,load,store,branch,call,address,compare,fpload,fpstore,fpmove,fpcvt,fpcc,fpadd,fpmul,fpdiv,multi,misc" |
| (const_string "arith")) |
| |
| ;; Length (in # of insns). |
| (define_attr "length" "" |
| (cond [(eq_attr "type" "load,fpload") |
| (if_then_else (match_operand 1 "symbolic_memory_operand" "") |
| (const_int 2) |
| (const_int 1)) |
| (eq_attr "type" "store,fpstore") |
| (if_then_else (match_operand 0 "symbolic_memory_operand" "") |
| (const_int 2) |
| (const_int 1)) |
| (eq_attr "type" "address") |
| (const_int 2)] |
| (const_int 1))) |
| |
| (define_asm_attributes |
| [(set_attr "length" "1") |
| (set_attr "type" "multi")]) |
| |
| ;; (define_function_unit {name} {num-units} {n-users} {test} |
| ;; {ready-delay} {issue-delay} [{conflict-list}]) |
| |
| ;; The integer ALU |
| (define_function_unit "alu" 2 0 (eq_attr "type" "arith,compare,move,address") 1 0) |
| (define_function_unit "alu" 2 0 (eq_attr "type" "alu2") 2 0) |
| (define_function_unit "alu" 2 0 (eq_attr "type" "mult") 5 0) |
| (define_function_unit "alu" 2 0 (eq_attr "type" "div") 35 0) |
| (define_function_unit "alu" 2 0 (eq_attr "type" "modscan") 3 0) |
| |
| ;; Memory with load-delay of 1 (i.e., 2 cycle load). |
| (define_function_unit "memory" 1 0 (eq_attr "type" "load,fpload") 2 0) |
| |
| ;; Floating point operations. |
| (define_function_unit "fp" 1 2 (eq_attr "type" "fpmove") 5 0) |
| (define_function_unit "fp" 1 2 (eq_attr "type" "fpcvt") 35 0) |
| (define_function_unit "fp" 1 2 (eq_attr "type" "fpcc") 10 0) |
| (define_function_unit "fp" 1 2 (eq_attr "type" "fpadd") 10 0) |
| (define_function_unit "fp" 1 2 (eq_attr "type" "fpmul") 20 0) |
| (define_function_unit "fp" 1 2 (eq_attr "type" "fpdiv") 35 0) |
| |
| ;; Compare instructions. |
| ;; This controls RTL generation and register allocation. |
| |
| ;; We generate RTL for comparisons and branches by having the cmpxx |
| ;; patterns store away the operands. Then, the scc and bcc patterns |
| ;; emit RTL for both the compare and the branch. |
| ;; |
| ;; We start with the DEFINE_EXPANDs, then then DEFINE_INSNs to match |
| ;; the patterns. Finally, we have the DEFINE_SPLITs for some of the scc |
| ;; insns that actually require more than one machine instruction. |
| |
| ;; Put cmpsi first because it is expected to be the most common. |
| |
| (define_expand "cmpsi" |
| [(set (reg:CC 36) |
| (compare:CC (match_operand:SI 0 "nonimmediate_operand" "") |
| (match_operand:SI 1 "general_operand" "")))] |
| "" |
| " |
| { |
| i960_compare_op0 = operands[0]; |
| i960_compare_op1 = operands[1]; |
| DONE; |
| }") |
| |
| (define_expand "cmpdf" |
| [(set (reg:CC 36) |
| (compare:CC (match_operand:DF 0 "register_operand" "r") |
| (match_operand:DF 1 "nonmemory_operand" "rGH")))] |
| "TARGET_NUMERICS" |
| " |
| { |
| i960_compare_op0 = operands[0]; |
| i960_compare_op1 = operands[1]; |
| DONE; |
| }") |
| |
| (define_expand "cmpsf" |
| [(set (reg:CC 36) |
| (compare:CC (match_operand:SF 0 "register_operand" "r") |
| (match_operand:SF 1 "nonmemory_operand" "rGH")))] |
| "TARGET_NUMERICS" |
| " |
| { |
| i960_compare_op0 = operands[0]; |
| i960_compare_op1 = operands[1]; |
| DONE; |
| }") |
| |
| ;; Now the DEFINE_INSNs for the compare and scc cases. First the compares. |
| |
| (define_insn "" |
| [(set (reg:CC 36) |
| (compare:CC (match_operand:SI 0 "register_operand" "d") |
| (match_operand:SI 1 "arith_operand" "dI")))] |
| "" |
| "cmpi %0,%1" |
| [(set_attr "type" "compare")]) |
| |
| (define_insn "" |
| [(set (reg:CC_UNS 36) |
| (compare:CC_UNS (match_operand:SI 0 "register_operand" "d") |
| (match_operand:SI 1 "arith_operand" "dI")))] |
| "" |
| "cmpo %0,%1" |
| [(set_attr "type" "compare")]) |
| |
| (define_insn "" |
| [(set (reg:CC 36) |
| (compare:CC (match_operand:DF 0 "register_operand" "r") |
| (match_operand:DF 1 "nonmemory_operand" "rGH")))] |
| "TARGET_NUMERICS" |
| "cmprl %0,%1" |
| [(set_attr "type" "fpcc")]) |
| |
| (define_insn "" |
| [(set (reg:CC 36) |
| (compare:CC (match_operand:SF 0 "register_operand" "r") |
| (match_operand:SF 1 "nonmemory_operand" "rGH")))] |
| "TARGET_NUMERICS" |
| "cmpr %0,%1" |
| [(set_attr "type" "fpcc")]) |
| |
| ;; Instruction definitions for branch-on-bit-set and clear insns. |
| |
| (define_insn "" |
| [(set (pc) |
| (if_then_else |
| (ne (sign_extract:SI (match_operand:SI 1 "register_operand" "d") |
| (const_int 1) |
| (match_operand:SI 2 "arith_operand" "dI")) |
| (const_int 0)) |
| (label_ref (match_operand 3 "" "")) |
| (pc)))] |
| "" |
| "bbs %2,%1,%l3" |
| [(set_attr "type" "branch")]) |
| |
| (define_insn "" |
| [(set (pc) |
| (if_then_else |
| (eq (sign_extract:SI (match_operand:SI 1 "register_operand" "d") |
| (const_int 1) |
| (match_operand:SI 2 "arith_operand" "dI")) |
| (const_int 0)) |
| (label_ref (match_operand 3 "" "")) |
| (pc)))] |
| "" |
| "bbc %2,%1,%l3" |
| [(set_attr "type" "branch")]) |
| |
| (define_insn "" |
| [(set (pc) |
| (if_then_else |
| (ne (zero_extract:SI (match_operand:SI 1 "register_operand" "d") |
| (const_int 1) |
| (match_operand:SI 2 "arith_operand" "dI")) |
| (const_int 0)) |
| (label_ref (match_operand 3 "" "")) |
| (pc)))] |
| "" |
| "bbs %2,%1,%l3" |
| [(set_attr "type" "branch")]) |
| |
| (define_insn "" |
| [(set (pc) |
| (if_then_else |
| (eq (zero_extract:SI (match_operand:SI 1 "register_operand" "d") |
| (const_int 1) |
| (match_operand:SI 2 "arith_operand" "dI")) |
| (const_int 0)) |
| (label_ref (match_operand 3 "" "")) |
| (pc)))] |
| "" |
| "bbc %2,%1,%l3" |
| [(set_attr "type" "branch")]) |
| |
| ;; ??? These will never match. The LOG_LINKs necessary to make these match |
| ;; are not created by flow. These remain as a reminder to make this work |
| ;; some day. |
| |
| (define_insn "" |
| [(set (reg:CC 36) |
| (compare (match_operand:SI 0 "arith_operand" "d") |
| (match_operand:SI 1 "arith_operand" "d"))) |
| (set (match_dup 1) (plus:SI (match_dup 1) (const_int 1)))] |
| "0" |
| "cmpinci %0,%1" |
| [(set_attr "type" "compare")]) |
| |
| (define_insn "" |
| [(set (reg:CC_UNS 36) |
| (compare (match_operand:SI 0 "arith_operand" "d") |
| (match_operand:SI 1 "arith_operand" "d"))) |
| (set (match_dup 1) (plus:SI (match_dup 1) (const_int 1)))] |
| "0" |
| "cmpinco %0,%1" |
| [(set_attr "type" "compare")]) |
| |
| (define_insn "" |
| [(set (reg:CC 36) |
| (compare (match_operand:SI 0 "arith_operand" "d") |
| (match_operand:SI 1 "arith_operand" "d"))) |
| (set (match_dup 1) (minus:SI (match_dup 1) (const_int 1)))] |
| "0" |
| "cmpdeci %0,%1" |
| [(set_attr "type" "compare")]) |
| |
| (define_insn "" |
| [(set (reg:CC_UNS 36) |
| (compare (match_operand:SI 0 "arith_operand" "d") |
| (match_operand:SI 1 "arith_operand" "d"))) |
| (set (match_dup 1) (minus:SI (match_dup 1) (const_int 1)))] |
| "0" |
| "cmpdeco %0,%1" |
| [(set_attr "type" "compare")]) |
| |
| ;; Templates to store result of condition. |
| ;; '1' is stored if condition is true. |
| ;; '0' is stored if condition is false. |
| ;; These should use predicate "general_operand", since |
| ;; gcc seems to be creating mem references which use these |
| ;; templates. |
| |
| (define_expand "seq" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (eq:SI (match_dup 1) (const_int 0)))] |
| "" |
| " |
| { |
| operands[1] = gen_compare_reg (EQ, i960_compare_op0, i960_compare_op1); |
| }") |
| |
| (define_expand "sne" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (ne:SI (match_dup 1) (const_int 0)))] |
| "" |
| " |
| { |
| operands[1] = gen_compare_reg (NE, i960_compare_op0, i960_compare_op1); |
| }") |
| |
| (define_expand "sgt" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (gt:SI (match_dup 1) (const_int 0)))] |
| "" |
| " |
| { |
| operands[1] = gen_compare_reg (GT, i960_compare_op0, i960_compare_op1); |
| }") |
| |
| (define_expand "sgtu" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (gtu:SI (match_dup 1) (const_int 0)))] |
| "" |
| " |
| { |
| operands[1] = gen_compare_reg (GTU, i960_compare_op0, i960_compare_op1); |
| }") |
| |
| (define_expand "slt" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (lt:SI (match_dup 1) (const_int 0)))] |
| "" |
| " |
| { |
| operands[1] = gen_compare_reg (LT, i960_compare_op0, i960_compare_op1); |
| }") |
| |
| (define_expand "sltu" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (ltu:SI (match_dup 1) (const_int 0)))] |
| "" |
| " |
| { |
| operands[1] = gen_compare_reg (LTU, i960_compare_op0, i960_compare_op1); |
| }") |
| |
| (define_expand "sge" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (ge:SI (match_dup 1) (const_int 0)))] |
| "" |
| " |
| { |
| operands[1] = gen_compare_reg (GE, i960_compare_op0, i960_compare_op1); |
| }") |
| |
| (define_expand "sgeu" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (geu:SI (match_dup 1) (const_int 0)))] |
| "" |
| " |
| { |
| operands[1] = gen_compare_reg (GEU, i960_compare_op0, i960_compare_op1); |
| }") |
| |
| (define_expand "sle" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (le:SI (match_dup 1) (const_int 0)))] |
| "" |
| " |
| { |
| operands[1] = gen_compare_reg (LE, i960_compare_op0, i960_compare_op1); |
| }") |
| |
| (define_expand "sleu" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (leu:SI (match_dup 1) (const_int 0)))] |
| "" |
| " |
| { |
| operands[1] = gen_compare_reg (LEU, i960_compare_op0, i960_compare_op1); |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (eq:SI (match_operand:SI 1 "register_operand" "d") (const_int 0)))] |
| "" |
| "shro %1,1,%0" |
| [(set_attr "type" "alu2")]) |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (match_operator:SI 1 "comparison_operator" [(reg:CC 36) (const_int 0)]))] |
| "" |
| "test%C1 %0" |
| [(set_attr "type" "compare")]) |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "general_operand" "=d") |
| (match_operator:SI 1 "comparison_operator" [(reg:CC_UNS 36) (const_int 0)]))] |
| "" |
| "test%C1 %0" |
| [(set_attr "type" "compare")]) |
| |
| ;; These control RTL generation for conditional jump insns |
| ;; and match them for register allocation. |
| |
| (define_expand "beq" |
| [(set (pc) |
| (if_then_else (eq (match_dup 1) |
| (const_int 0)) |
| (label_ref (match_operand 0 "" "")) |
| (pc)))] |
| "" |
| " |
| { operands[1] = gen_compare_reg (EQ, i960_compare_op0, i960_compare_op1); }") |
| |
| (define_expand "bne" |
| [(set (pc) |
| (if_then_else (ne (match_dup 1) |
| (const_int 0)) |
| (label_ref (match_operand 0 "" "")) |
| (pc)))] |
| "" |
| " |
| { operands[1] = gen_compare_reg (NE, i960_compare_op0, i960_compare_op1); }") |
| |
| (define_expand "bgt" |
| [(set (pc) |
| (if_then_else (gt (match_dup 1) |
| (const_int 0)) |
| (label_ref (match_operand 0 "" "")) |
| (pc)))] |
| "" |
| " |
| { operands[1] = gen_compare_reg (GT, i960_compare_op0, i960_compare_op1); }") |
| |
| (define_expand "bgtu" |
| [(set (pc) |
| (if_then_else (gtu (match_dup 1) |
| (const_int 0)) |
| (label_ref (match_operand 0 "" "")) |
| (pc)))] |
| "" |
| " |
| { operands[1] = gen_compare_reg (GTU, i960_compare_op0, i960_compare_op1); }") |
| |
| (define_expand "blt" |
| [(set (pc) |
| (if_then_else (lt (match_dup 1) |
| (const_int 0)) |
| (label_ref (match_operand 0 "" "")) |
| (pc)))] |
| "" |
| " |
| { operands[1] = gen_compare_reg (LT, i960_compare_op0, i960_compare_op1); }") |
| |
| (define_expand "bltu" |
| [(set (pc) |
| (if_then_else (ltu (match_dup 1) |
| (const_int 0)) |
| (label_ref (match_operand 0 "" "")) |
| (pc)))] |
| "" |
| " |
| { operands[1] = gen_compare_reg (LTU, i960_compare_op0, i960_compare_op1); }") |
| |
| (define_expand "bge" |
| [(set (pc) |
| (if_then_else (ge (match_dup 1) |
| (const_int 0)) |
| (label_ref (match_operand 0 "" "")) |
| (pc)))] |
| "" |
| " |
| { operands[1] = gen_compare_reg (GE, i960_compare_op0, i960_compare_op1); }") |
| |
| (define_expand "bgeu" |
| [(set (pc) |
| (if_then_else (geu (match_dup 1) |
| (const_int 0)) |
| (label_ref (match_operand 0 "" "")) |
| (pc)))] |
| "" |
| " |
| { operands[1] = gen_compare_reg (GEU, i960_compare_op0, i960_compare_op1); }") |
| |
| (define_expand "ble" |
| [(set (pc) |
| (if_then_else (le (match_dup 1) |
| (const_int 0)) |
| (label_ref (match_operand 0 "" "")) |
| (pc)))] |
| "" |
| " |
| { operands[1] = gen_compare_reg (LE, i960_compare_op0, i960_compare_op1); }") |
| |
| (define_expand "bleu" |
| [(set (pc) |
| (if_then_else (leu (match_dup 1) |
| (const_int 0)) |
| (label_ref (match_operand 0 "" "")) |
| (pc)))] |
| "" |
| " |
| { operands[1] = gen_compare_reg (LEU, i960_compare_op0, i960_compare_op1); }") |
| |
| ;; Now the normal branch insns (forward and reverse). |
| |
| (define_insn "" |
| [(set (pc) |
| (if_then_else (match_operator 0 "comparison_operator" |
| [(reg:CC 36) (const_int 0)]) |
| (label_ref (match_operand 1 "" "")) |
| (pc)))] |
| "" |
| "b%C0 %l1" |
| [(set_attr "type" "branch")]) |
| |
| (define_insn "" |
| [(set (pc) |
| (if_then_else (match_operator 0 "comparison_operator" |
| [(reg:CC 36) (const_int 0)]) |
| (pc) |
| (label_ref (match_operand 1 "" ""))))] |
| "" |
| "b%I0 %l1" |
| [(set_attr "type" "branch")]) |
| |
| (define_insn "" |
| [(set (pc) |
| (if_then_else (match_operator 0 "comparison_operator" |
| [(reg:CC_UNS 36) (const_int 0)]) |
| (label_ref (match_operand 1 "" "")) |
| (pc)))] |
| "" |
| "b%C0 %l1" |
| [(set_attr "type" "branch")]) |
| |
| (define_insn "" |
| [(set (pc) |
| (if_then_else (match_operator 0 "comparison_operator" |
| [(reg:CC_UNS 36) (const_int 0)]) |
| (pc) |
| (label_ref (match_operand 1 "" ""))))] |
| "" |
| "b%I0 %l1" |
| [(set_attr "type" "branch")]) |
| |
| (define_insn "" |
| [(set (pc) |
| (if_then_else |
| (match_operator 0 "comparison_operator" |
| [(match_operand:SI 1 "arith_operand" "d") |
| (match_operand:SI 2 "arith_operand" "dI")]) |
| (label_ref (match_operand 3 "" "")) |
| (pc)))] |
| "" |
| "cmp%S0%B0%R0 %2,%1,%l3" |
| [(set_attr "type" "branch")]) |
| |
| (define_insn "" |
| [(set (pc) |
| (if_then_else |
| (match_operator 0 "comparison_operator" |
| [(match_operand:SI 1 "arith_operand" "d") |
| (match_operand:SI 2 "arith_operand" "dI")]) |
| (pc) |
| (label_ref (match_operand 3 "" ""))))] |
| "" |
| "cmp%S0%B0%X0 %2,%1,%l3" |
| [(set_attr "type" "branch")]) |
| |
| ;; Normal move instructions. |
| ;; This code is based on the sparc machine description. |
| |
| (define_expand "movsi" |
| [(set (match_operand:SI 0 "general_operand" "") |
| (match_operand:SI 1 "general_operand" ""))] |
| "" |
| " |
| { |
| if (emit_move_sequence (operands, SImode)) |
| DONE; |
| }") |
| |
| ;; The store case can not be separate, because reload may convert a register |
| ;; to register move insn to a store (or load) insn without rerecognizing |
| ;; the insn. |
| |
| ;; The i960 does not have any store constant to memory instruction. However, |
| ;; the calling convention is defined so that the arg pointer when it is not |
| ;; overwise being used is zero. Thus, we can handle store zero to memory |
| ;; by storing an unused arg pointer. The arg pointer will be unused if |
| ;; current_function_args_size is zero and this is not a stdarg/varargs |
| ;; function. This value of the former variable is not valid until after |
| ;; all rtl generation is complete, including function inlining (because a |
| ;; function that doesn't need an arg pointer may be inlined into a function |
| ;; that does need an arg pointer), so we must also check that |
| ;; rtx_equal_function_value_matters is zero. |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "general_operand" "=d,d,d,m") |
| (match_operand:SI 1 "general_operand" "dI,i,m,dJ"))] |
| "(current_function_args_size == 0 |
| && current_function_varargs == 0 |
| && current_function_stdarg == 0 |
| && rtx_equal_function_value_matters == 0) |
| && (register_operand (operands[0], SImode) |
| || register_operand (operands[1], SImode) |
| || operands[1] == const0_rtx)" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| if (i960_last_insn_type == I_TYPE_REG && TARGET_C_SERIES) |
| { |
| if (GET_CODE (operands[1]) == REG) |
| return \"lda (%1),%0\"; |
| else |
| return \"lda %1,%0\"; |
| } |
| return \"mov %1,%0\"; |
| case 1: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 2: |
| return \"ld %1,%0\"; |
| case 3: |
| if (operands[1] == const0_rtx) |
| return \"st g14,%0\"; |
| return \"st %1,%0\"; |
| } |
| }" |
| [(set_attr "type" "move,address,load,store") |
| (set_attr "length" "*,3,*,*")]) |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "general_operand" "=d,d,d,m") |
| (match_operand:SI 1 "general_operand" "dI,i,m,d"))] |
| "(current_function_args_size != 0 |
| || current_function_varargs != 0 |
| || current_function_stdarg != 0 |
| || rtx_equal_function_value_matters != 0) |
| && (register_operand (operands[0], SImode) |
| || register_operand (operands[1], SImode))" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| if (i960_last_insn_type == I_TYPE_REG && TARGET_C_SERIES) |
| { |
| if (GET_CODE (operands[1]) == REG) |
| return \"lda (%1),%0\"; |
| else |
| return \"lda %1,%0\"; |
| } |
| return \"mov %1,%0\"; |
| case 1: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 2: |
| return \"ld %1,%0\"; |
| case 3: |
| return \"st %1,%0\"; |
| } |
| }" |
| [(set_attr "type" "move,address,load,store") |
| (set_attr "length" "*,3,*,*")]) |
| |
| (define_expand "movhi" |
| [(set (match_operand:HI 0 "general_operand" "") |
| (match_operand:HI 1 "general_operand" ""))] |
| "" |
| " |
| { |
| if (emit_move_sequence (operands, HImode)) |
| DONE; |
| }") |
| |
| ;; Special pattern for zero stores to memory for functions which don't use |
| ;; the arg pointer. |
| |
| ;; The store case can not be separate. See above. |
| (define_insn "" |
| [(set (match_operand:HI 0 "general_operand" "=d,d,d,m") |
| (match_operand:HI 1 "general_operand" "dI,i,m,dJ"))] |
| "(current_function_args_size == 0 |
| && current_function_varargs == 0 |
| && current_function_stdarg == 0 |
| && rtx_equal_function_value_matters == 0) |
| && (register_operand (operands[0], HImode) |
| || register_operand (operands[1], HImode) |
| || operands[1] == const0_rtx)" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| if (i960_last_insn_type == I_TYPE_REG && TARGET_C_SERIES) |
| { |
| if (GET_CODE (operands[1]) == REG) |
| return \"lda (%1),%0\"; |
| else |
| return \"lda %1,%0\"; |
| } |
| return \"mov %1,%0\"; |
| case 1: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 2: |
| return \"ldos %1,%0\"; |
| case 3: |
| if (operands[1] == const0_rtx) |
| return \"stos g14,%0\"; |
| return \"stos %1,%0\"; |
| } |
| }" |
| [(set_attr "type" "move,misc,load,store") |
| (set_attr "length" "*,3,*,*")]) |
| |
| ;; The store case can not be separate. See above. |
| (define_insn "" |
| [(set (match_operand:HI 0 "general_operand" "=d,d,d,m") |
| (match_operand:HI 1 "general_operand" "dI,i,m,d"))] |
| "(current_function_args_size != 0 |
| || current_function_varargs != 0 |
| || current_function_stdarg != 0 |
| || rtx_equal_function_value_matters != 0) |
| && (register_operand (operands[0], HImode) |
| || register_operand (operands[1], HImode))" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| if (i960_last_insn_type == I_TYPE_REG && TARGET_C_SERIES) |
| { |
| if (GET_CODE (operands[1]) == REG) |
| return \"lda (%1),%0\"; |
| else |
| return \"lda %1,%0\"; |
| } |
| return \"mov %1,%0\"; |
| case 1: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 2: |
| return \"ldos %1,%0\"; |
| case 3: |
| return \"stos %1,%0\"; |
| } |
| }" |
| [(set_attr "type" "move,misc,load,store") |
| (set_attr "length" "*,3,*,*")]) |
| |
| (define_expand "movqi" |
| [(set (match_operand:QI 0 "general_operand" "") |
| (match_operand:QI 1 "general_operand" ""))] |
| "" |
| " |
| { |
| if (emit_move_sequence (operands, QImode)) |
| DONE; |
| }") |
| |
| ;; The store case can not be separate. See comment above. |
| (define_insn "" |
| [(set (match_operand:QI 0 "general_operand" "=d,d,d,m") |
| (match_operand:QI 1 "general_operand" "dI,i,m,dJ"))] |
| "(current_function_args_size == 0 |
| && current_function_varargs == 0 |
| && current_function_stdarg == 0 |
| && rtx_equal_function_value_matters == 0) |
| && (register_operand (operands[0], QImode) |
| || register_operand (operands[1], QImode) |
| || operands[1] == const0_rtx)" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| if (i960_last_insn_type == I_TYPE_REG && TARGET_C_SERIES) |
| { |
| if (GET_CODE (operands[1]) == REG) |
| return \"lda (%1),%0\"; |
| else |
| return \"lda %1,%0\"; |
| } |
| return \"mov %1,%0\"; |
| case 1: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 2: |
| return \"ldob %1,%0\"; |
| case 3: |
| if (operands[1] == const0_rtx) |
| return \"stob g14,%0\"; |
| return \"stob %1,%0\"; |
| } |
| }" |
| [(set_attr "type" "move,misc,load,store") |
| (set_attr "length" "*,3,*,*")]) |
| |
| ;; The store case can not be separate. See comment above. |
| (define_insn "" |
| [(set (match_operand:QI 0 "general_operand" "=d,d,d,m") |
| (match_operand:QI 1 "general_operand" "dI,i,m,d"))] |
| "(current_function_args_size != 0 |
| || current_function_varargs != 0 |
| || current_function_stdarg != 0 |
| || rtx_equal_function_value_matters != 0) |
| && (register_operand (operands[0], QImode) |
| || register_operand (operands[1], QImode))" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| if (i960_last_insn_type == I_TYPE_REG && TARGET_C_SERIES) |
| { |
| if (GET_CODE (operands[1]) == REG) |
| return \"lda (%1),%0\"; |
| else |
| return \"lda %1,%0\"; |
| } |
| return \"mov %1,%0\"; |
| case 1: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 2: |
| return \"ldob %1,%0\"; |
| case 3: |
| return \"stob %1,%0\"; |
| } |
| }" |
| [(set_attr "type" "move,misc,load,store") |
| (set_attr "length" "*,3,*,*")]) |
| |
| (define_expand "movdi" |
| [(set (match_operand:DI 0 "general_operand" "") |
| (match_operand:DI 1 "general_operand" ""))] |
| "" |
| " |
| { |
| if (emit_move_sequence (operands, DImode)) |
| DONE; |
| }") |
| |
| ;; The store case can not be separate. See comment above. |
| (define_insn "" |
| [(set (match_operand:DI 0 "general_operand" "=d,d,d,d,m,o") |
| (match_operand:DI 1 "general_operand" "d,I,i,m,d,J"))] |
| "(current_function_args_size == 0 |
| && current_function_varargs == 0 |
| && current_function_stdarg == 0 |
| && rtx_equal_function_value_matters == 0) |
| && (register_operand (operands[0], DImode) |
| || register_operand (operands[1], DImode) |
| || operands[1] == const0_rtx)" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| case 1: |
| case 3: |
| case 4: |
| return i960_output_move_double (operands[0], operands[1]); |
| case 2: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 5: |
| operands[1] = adj_offsettable_operand (operands[0], 4); |
| return \"st g14,%0\;st g14,%1\"; |
| } |
| }" |
| [(set_attr "type" "move,move,load,load,store,store")]) |
| |
| ;; The store case can not be separate. See comment above. |
| (define_insn "" |
| [(set (match_operand:DI 0 "general_operand" "=d,d,d,d,m") |
| (match_operand:DI 1 "general_operand" "d,I,i,m,d"))] |
| "(current_function_args_size != 0 |
| || current_function_varargs != 0 |
| || current_function_stdarg != 0 |
| || rtx_equal_function_value_matters != 0) |
| && (register_operand (operands[0], DImode) |
| || register_operand (operands[1], DImode))" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| case 1: |
| case 3: |
| case 4: |
| return i960_output_move_double (operands[0], operands[1]); |
| case 2: |
| return i960_output_ldconst (operands[0], operands[1]); |
| } |
| }" |
| [(set_attr "type" "move,move,load,load,store")]) |
| |
| (define_insn "*store_unaligned_di_reg" |
| [(set (match_operand:DI 0 "memory_operand" "=m") |
| (match_operand:DI 1 "register_operand" "d")) |
| (clobber (match_scratch:SI 2 "=&d"))] |
| "" |
| "* |
| { |
| operands[3] = gen_rtx (MEM, word_mode, operands[2]); |
| operands[4] = adj_offsettable_operand (operands[3], UNITS_PER_WORD); |
| return \"lda %0,%2\;st %1,%3\;st %D1,%4\"; |
| }" |
| [(set_attr "type" "store")]) |
| |
| (define_expand "movti" |
| [(set (match_operand:TI 0 "general_operand" "") |
| (match_operand:TI 1 "general_operand" ""))] |
| "" |
| " |
| { |
| if (emit_move_sequence (operands, TImode)) |
| DONE; |
| }") |
| |
| ;; The store case can not be separate. See comment above. |
| (define_insn "" |
| [(set (match_operand:TI 0 "general_operand" "=d,d,d,d,m,o") |
| (match_operand:TI 1 "general_operand" "d,I,i,m,d,J"))] |
| "(current_function_args_size == 0 |
| && current_function_varargs == 0 |
| && current_function_stdarg == 0 |
| && rtx_equal_function_value_matters == 0) |
| && (register_operand (operands[0], TImode) |
| || register_operand (operands[1], TImode) |
| || operands[1] == const0_rtx)" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| case 1: |
| case 3: |
| case 4: |
| return i960_output_move_quad (operands[0], operands[1]); |
| case 2: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 5: |
| operands[1] = adj_offsettable_operand (operands[0], 4); |
| operands[2] = adj_offsettable_operand (operands[0], 8); |
| operands[3] = adj_offsettable_operand (operands[0], 12); |
| return \"st g14,%0\;st g14,%1\;st g14,%2\;st g14,%3\"; |
| } |
| }" |
| [(set_attr "type" "move,move,load,load,store,store")]) |
| |
| ;; The store case can not be separate. See comment above. |
| (define_insn "" |
| [(set (match_operand:TI 0 "general_operand" "=d,d,d,d,m") |
| (match_operand:TI 1 "general_operand" "d,I,i,m,d"))] |
| "(current_function_args_size != 0 |
| || current_function_varargs != 0 |
| || current_function_stdarg != 0 |
| || rtx_equal_function_value_matters != 0) |
| && (register_operand (operands[0], TImode) |
| || register_operand (operands[1], TImode))" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| case 1: |
| case 3: |
| case 4: |
| return i960_output_move_quad (operands[0], operands[1]); |
| case 2: |
| return i960_output_ldconst (operands[0], operands[1]); |
| } |
| }" |
| [(set_attr "type" "move,move,load,load,store")]) |
| |
| (define_insn "*store_unaligned_ti_reg" |
| [(set (match_operand:TI 0 "memory_operand" "=m") |
| (match_operand:TI 1 "register_operand" "d")) |
| (clobber (match_scratch:SI 2 "=&d"))] |
| "" |
| "* |
| { |
| operands[3] = gen_rtx (MEM, word_mode, operands[2]); |
| operands[4] = adj_offsettable_operand (operands[3], UNITS_PER_WORD); |
| operands[5] = adj_offsettable_operand (operands[4], UNITS_PER_WORD); |
| operands[6] = adj_offsettable_operand (operands[5], UNITS_PER_WORD); |
| return \"lda %0,%2\;st %1,%3\;st %D1,%4\;st %E1,%5\;st %F1,%6\"; |
| }" |
| [(set_attr "type" "store")]) |
| |
| (define_expand "store_multiple" |
| [(set (match_operand:SI 0 "" "") ;;- dest |
| (match_operand:SI 1 "" "")) ;;- src |
| (use (match_operand:SI 2 "" ""))] ;;- nregs |
| "" |
| " |
| { |
| int regno; |
| int count; |
| rtx from; |
| int i; |
| |
| if (GET_CODE (operands[0]) != MEM |
| || GET_CODE (operands[1]) != REG |
| || GET_CODE (operands[2]) != CONST_INT) |
| FAIL; |
| |
| count = INTVAL (operands[2]); |
| if (count > 12) |
| FAIL; |
| |
| regno = REGNO (operands[1]); |
| from = memory_address (SImode, XEXP (operands[0], 0)); |
| while (count >= 4 && ((regno & 3) == 0)) |
| { |
| emit_insn (gen_rtx (SET, VOIDmode, |
| gen_rtx (MEM, TImode, from), |
| gen_rtx (REG, TImode, regno))); |
| count -= 4; |
| regno += 4; |
| from = memory_address (TImode, plus_constant (from, 16)); |
| } |
| while (count >= 2 && ((regno & 1) == 0)) |
| { |
| emit_insn (gen_rtx (SET, VOIDmode, |
| gen_rtx (MEM, DImode, from), |
| gen_rtx (REG, DImode, regno))); |
| count -= 2; |
| regno += 2; |
| from = memory_address (DImode, plus_constant (from, 8)); |
| } |
| while (count > 0) |
| { |
| emit_insn (gen_rtx (SET, VOIDmode, |
| gen_rtx (MEM, SImode, from), |
| gen_rtx (REG, SImode, regno))); |
| count -= 1; |
| regno += 1; |
| from = memory_address (SImode, plus_constant (from, 4)); |
| } |
| DONE; |
| }") |
| |
| ;; Floating point move insns |
| |
| (define_expand "movdf" |
| [(set (match_operand:DF 0 "general_operand" "") |
| (match_operand:DF 1 "fpmove_src_operand" ""))] |
| "" |
| " |
| { |
| if (emit_move_sequence (operands, DFmode)) |
| DONE; |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:DF 0 "general_operand" "=r,*f,d,d,m,o") |
| (match_operand:DF 1 "fpmove_src_operand" "r,GH,F,m,d,G"))] |
| "(current_function_args_size == 0 |
| && current_function_varargs == 0 |
| && current_function_stdarg == 0 |
| && rtx_equal_function_value_matters == 0) |
| && (register_operand (operands[0], DFmode) |
| || register_operand (operands[1], DFmode) |
| || operands[1] == CONST0_RTX (DFmode))" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) |
| return \"movrl %1,%0\"; |
| else |
| return \"movl %1,%0\"; |
| case 1: |
| return \"movrl %1,%0\"; |
| case 2: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 3: |
| return \"ldl %1,%0\"; |
| case 4: |
| return \"stl %1,%0\"; |
| case 5: |
| operands[1] = adj_offsettable_operand (operands[0], 4); |
| return \"st g14,%0\;st g14,%1\"; |
| } |
| }" |
| [(set_attr "type" "move,move,load,fpload,fpstore,fpstore")]) |
| |
| (define_insn "" |
| [(set (match_operand:DF 0 "general_operand" "=r,*f,d,d,m") |
| (match_operand:DF 1 "fpmove_src_operand" "r,GH,F,m,d"))] |
| "(current_function_args_size != 0 |
| || current_function_varargs != 0 |
| || current_function_stdarg != 0 |
| || rtx_equal_function_value_matters != 0) |
| && (register_operand (operands[0], DFmode) |
| || register_operand (operands[1], DFmode))" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) |
| return \"movrl %1,%0\"; |
| else |
| return \"movl %1,%0\"; |
| case 1: |
| return \"movrl %1,%0\"; |
| case 2: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 3: |
| return \"ldl %1,%0\"; |
| case 4: |
| return \"stl %1,%0\"; |
| } |
| }" |
| [(set_attr "type" "move,move,load,fpload,fpstore")]) |
| |
| (define_expand "movsf" |
| [(set (match_operand:SF 0 "general_operand" "") |
| (match_operand:SF 1 "fpmove_src_operand" ""))] |
| "" |
| " |
| { |
| if (emit_move_sequence (operands, SFmode)) |
| DONE; |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SF 0 "general_operand" "=r,*f,d,d,m") |
| (match_operand:SF 1 "fpmove_src_operand" "r,GH,F,m,dG"))] |
| "(current_function_args_size == 0 |
| && current_function_varargs == 0 |
| && current_function_stdarg == 0 |
| && rtx_equal_function_value_matters == 0) |
| && (register_operand (operands[0], SFmode) |
| || register_operand (operands[1], SFmode) |
| || operands[1] == CONST0_RTX (SFmode))" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) |
| return \"movr %1,%0\"; |
| else |
| return \"mov %1,%0\"; |
| case 1: |
| return \"movr %1,%0\"; |
| case 2: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 3: |
| return \"ld %1,%0\"; |
| case 4: |
| if (operands[1] == CONST0_RTX (SFmode)) |
| return \"st g14,%0\"; |
| return \"st %1,%0\"; |
| } |
| }" |
| [(set_attr "type" "move,move,load,fpload,fpstore")]) |
| |
| (define_insn "" |
| [(set (match_operand:SF 0 "general_operand" "=r,*f,d,d,m") |
| (match_operand:SF 1 "fpmove_src_operand" "r,GH,F,m,d"))] |
| "(current_function_args_size != 0 |
| || current_function_varargs != 0 |
| || current_function_stdarg != 0 |
| || rtx_equal_function_value_matters != 0) |
| && (register_operand (operands[0], SFmode) |
| || register_operand (operands[1], SFmode))" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) |
| return \"movr %1,%0\"; |
| else |
| return \"mov %1,%0\"; |
| case 1: |
| return \"movr %1,%0\"; |
| case 2: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 3: |
| return \"ld %1,%0\"; |
| case 4: |
| return \"st %1,%0\"; |
| } |
| }" |
| [(set_attr "type" "move,move,load,fpload,fpstore")]) |
| |
| ;; Mixed-mode moves with sign and zero-extension. |
| |
| ;; Note that the one starting from HImode comes before those for QImode |
| ;; so that a constant operand will match HImode, not QImode. |
| |
| (define_expand "extendhisi2" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (sign_extend:SI |
| (match_operand:HI 1 "nonimmediate_operand" "")))] |
| "" |
| " |
| { |
| if (GET_CODE (operand1) == REG |
| || (GET_CODE (operand1) == SUBREG |
| && GET_CODE (XEXP (operand1, 0)) == REG)) |
| { |
| rtx temp = gen_reg_rtx (SImode); |
| rtx shift_16 = gen_rtx (CONST_INT, VOIDmode, 16); |
| int op1_subreg_word = 0; |
| |
| if (GET_CODE (operand1) == SUBREG) |
| { |
| op1_subreg_word = SUBREG_WORD (operand1); |
| operand1 = SUBREG_REG (operand1); |
| } |
| operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_word); |
| |
| emit_insn (gen_ashlsi3 (temp, operand1, shift_16)); |
| emit_insn (gen_ashrsi3 (operand0, temp, shift_16)); |
| DONE; |
| } |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] |
| "" |
| "ldis %1,%0" |
| [(set_attr "type" "load")]) |
| |
| (define_expand "extendqisi2" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] |
| "" |
| " |
| { |
| if (GET_CODE (operand1) == REG |
| || (GET_CODE (operand1) == SUBREG |
| && GET_CODE (XEXP (operand1, 0)) == REG)) |
| { |
| rtx temp = gen_reg_rtx (SImode); |
| rtx shift_24 = gen_rtx (CONST_INT, VOIDmode, 24); |
| int op1_subreg_word = 0; |
| |
| if (GET_CODE (operand1) == SUBREG) |
| { |
| op1_subreg_word = SUBREG_WORD (operand1); |
| operand1 = SUBREG_REG (operand1); |
| } |
| operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_word), |
| |
| emit_insn (gen_ashlsi3 (temp, operand1, shift_24)); |
| emit_insn (gen_ashrsi3 (operand0, temp, shift_24)); |
| DONE; |
| } |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] |
| "" |
| "ldib %1,%0" |
| [(set_attr "type" "load")]) |
| |
| (define_expand "extendqihi2" |
| [(set (match_operand:HI 0 "register_operand" "") |
| (sign_extend:HI |
| (match_operand:QI 1 "nonimmediate_operand" "")))] |
| "" |
| " |
| { |
| if (GET_CODE (operand1) == REG |
| || (GET_CODE (operand1) == SUBREG |
| && GET_CODE (XEXP (operand1, 0)) == REG)) |
| { |
| rtx temp = gen_reg_rtx (SImode); |
| rtx shift_24 = gen_rtx (CONST_INT, VOIDmode, 24); |
| int op0_subreg_word = 0; |
| int op1_subreg_word = 0; |
| |
| if (GET_CODE (operand1) == SUBREG) |
| { |
| op1_subreg_word = SUBREG_WORD (operand1); |
| operand1 = SUBREG_REG (operand1); |
| } |
| operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_word); |
| |
| if (GET_CODE (operand0) == SUBREG) |
| { |
| op0_subreg_word = SUBREG_WORD (operand0); |
| operand0 = SUBREG_REG (operand0); |
| } |
| if (GET_MODE (operand0) != SImode) |
| operand0 = gen_rtx (SUBREG, SImode, operand0, op0_subreg_word); |
| |
| emit_insn (gen_ashlsi3 (temp, operand1, shift_24)); |
| emit_insn (gen_ashrsi3 (operand0, temp, shift_24)); |
| DONE; |
| } |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:HI 0 "register_operand" "=d") |
| (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] |
| "" |
| "ldib %1,%0" |
| [(set_attr "type" "load")]) |
| |
| (define_expand "zero_extendhisi2" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (zero_extend:SI |
| (match_operand:HI 1 "nonimmediate_operand" "")))] |
| "" |
| " |
| { |
| if (GET_CODE (operand1) == REG |
| || (GET_CODE (operand1) == SUBREG |
| && GET_CODE (XEXP (operand1, 0)) == REG)) |
| { |
| rtx temp = gen_reg_rtx (SImode); |
| rtx shift_16 = gen_rtx (CONST_INT, VOIDmode, 16); |
| int op1_subreg_word = 0; |
| |
| if (GET_CODE (operand1) == SUBREG) |
| { |
| op1_subreg_word = SUBREG_WORD (operand1); |
| operand1 = SUBREG_REG (operand1); |
| } |
| operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_word); |
| |
| emit_insn (gen_ashlsi3 (temp, operand1, shift_16)); |
| emit_insn (gen_lshrsi3 (operand0, temp, shift_16)); |
| DONE; |
| } |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] |
| "" |
| "ldos %1,%0" |
| [(set_attr "type" "load")]) |
| |
| ;; Using shifts here generates much better code than doing an `and 255'. |
| ;; This is mainly because the `and' requires loading the constant separately, |
| ;; the constant is likely to get optimized, and then the compiler can't |
| ;; optimize the `and' because it doesn't know that one operand is a constant. |
| |
| (define_expand "zero_extendqisi2" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] |
| "" |
| " |
| { |
| if (GET_CODE (operand1) == REG |
| || (GET_CODE (operand1) == SUBREG |
| && GET_CODE (XEXP (operand1, 0)) == REG)) |
| { |
| rtx temp = gen_reg_rtx (SImode); |
| rtx shift_24 = gen_rtx (CONST_INT, VOIDmode, 24); |
| int op1_subreg_word = 0; |
| |
| if (GET_CODE (operand1) == SUBREG) |
| { |
| op1_subreg_word = SUBREG_WORD (operand1); |
| operand1 = SUBREG_REG (operand1); |
| } |
| operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_word); |
| |
| emit_insn (gen_ashlsi3 (temp, operand1, shift_24)); |
| emit_insn (gen_lshrsi3 (operand0, temp, shift_24)); |
| DONE; |
| } |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] |
| "" |
| "ldob %1,%0" |
| [(set_attr "type" "load")]) |
| |
| (define_expand "zero_extendqihi2" |
| [(set (match_operand:HI 0 "register_operand" "") |
| (zero_extend:HI |
| (match_operand:QI 1 "nonimmediate_operand" "")))] |
| "" |
| " |
| { |
| if (GET_CODE (operand1) == REG |
| || (GET_CODE (operand1) == SUBREG |
| && GET_CODE (XEXP (operand1, 0)) == REG)) |
| { |
| rtx temp = gen_reg_rtx (SImode); |
| rtx shift_24 = gen_rtx (CONST_INT, VOIDmode, 24); |
| int op0_subreg_word = 0; |
| int op1_subreg_word = 0; |
| |
| if (GET_CODE (operand1) == SUBREG) |
| { |
| op1_subreg_word = SUBREG_WORD (operand1); |
| operand1 = SUBREG_REG (operand1); |
| } |
| operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_word); |
| |
| if (GET_CODE (operand0) == SUBREG) |
| { |
| op0_subreg_word = SUBREG_WORD (operand0); |
| operand0 = SUBREG_REG (operand0); |
| } |
| if (GET_MODE (operand0) != SImode) |
| operand0 = gen_rtx (SUBREG, SImode, operand0, op0_subreg_word); |
| |
| emit_insn (gen_ashlsi3 (temp, operand1, shift_24)); |
| emit_insn (gen_lshrsi3 (operand0, temp, shift_24)); |
| DONE; |
| } |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:HI 0 "register_operand" "=d") |
| (zero_extend:HI (match_operand:QI 1 "memory_operand" "m")))] |
| "" |
| "ldob %1,%0" |
| [(set_attr "type" "load")]) |
| |
| ;; Conversions between float and double. |
| |
| (define_insn "extendsfdf2" |
| [(set (match_operand:DF 0 "register_operand" "=*f,d") |
| (float_extend:DF (match_operand:SF 1 "fp_arith_operand" "dGH,fGH")))] |
| "TARGET_NUMERICS" |
| "@ |
| movr %1,%0 |
| movrl %1,%0" |
| [(set_attr "type" "fpmove")]) |
| |
| (define_insn "truncdfsf2" |
| [(set (match_operand:SF 0 "register_operand" "=d") |
| (float_truncate:SF |
| (match_operand:DF 1 "fp_arith_operand" "fGH")))] |
| "TARGET_NUMERICS" |
| "movr %1,%0" |
| [(set_attr "type" "fpmove")]) |
| |
| ;; Conversion between fixed point and floating point. |
| |
| (define_insn "floatsidf2" |
| [(set (match_operand:DF 0 "register_operand" "=f") |
| (float:DF (match_operand:SI 1 "register_operand" "d")))] |
| "TARGET_NUMERICS" |
| "cvtir %1,%0" |
| [(set_attr "type" "fpcvt")]) |
| |
| (define_insn "floatsisf2" |
| [(set (match_operand:SF 0 "register_operand" "=d*f") |
| (float:SF (match_operand:SI 1 "register_operand" "d")))] |
| "TARGET_NUMERICS" |
| "cvtir %1,%0" |
| [(set_attr "type" "fpcvt")]) |
| |
| ;; Convert a float to an actual integer. |
| ;; Truncation is performed as part of the conversion. |
| ;; The i960 requires conversion from DFmode to DImode to make |
| ;; unsigned conversions work properly. |
| |
| (define_insn "fixuns_truncdfdi2" |
| [(set (match_operand:DI 0 "register_operand" "=d") |
| (unsigned_fix:DI (fix:DF (match_operand:DF 1 "fp_arith_operand" "fGH"))))] |
| "TARGET_NUMERICS" |
| "cvtzril %1,%0" |
| [(set_attr "type" "fpcvt")]) |
| |
| (define_insn "fixuns_truncsfdi2" |
| [(set (match_operand:DI 0 "register_operand" "=d") |
| (unsigned_fix:DI (fix:SF (match_operand:SF 1 "fp_arith_operand" "fGH"))))] |
| "TARGET_NUMERICS" |
| "cvtzril %1,%0" |
| [(set_attr "type" "fpcvt")]) |
| |
| (define_insn "fix_truncdfsi2" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (fix:SI (fix:DF (match_operand:DF 1 "fp_arith_operand" "fGH"))))] |
| "TARGET_NUMERICS" |
| "cvtzri %1,%0" |
| [(set_attr "type" "fpcvt")]) |
| |
| (define_expand "fixuns_truncdfsi2" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (unsigned_fix:SI (fix:DF (match_operand:DF 1 "fp_arith_operand" ""))))] |
| "TARGET_NUMERICS" |
| " |
| { |
| rtx temp = gen_reg_rtx (DImode); |
| emit_insn (gen_rtx (SET, VOIDmode, temp, |
| gen_rtx (UNSIGNED_FIX, DImode, |
| gen_rtx (FIX, DFmode, operands[1])))); |
| emit_insn (gen_rtx (SET, VOIDmode, operands[0], |
| gen_rtx (SUBREG, SImode, temp, 0))); |
| DONE; |
| }") |
| |
| (define_insn "fix_truncsfsi2" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (fix:SI (fix:SF (match_operand:SF 1 "fp_arith_operand" "dfGH"))))] |
| "TARGET_NUMERICS" |
| "cvtzri %1,%0" |
| [(set_attr "type" "fpcvt")]) |
| |
| (define_expand "fixuns_truncsfsi2" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (unsigned_fix:SI (fix:SF (match_operand:SF 1 "fp_arith_operand" ""))))] |
| "TARGET_NUMERICS" |
| " |
| { |
| rtx temp = gen_reg_rtx (DImode); |
| emit_insn (gen_rtx (SET, VOIDmode, temp, |
| gen_rtx (UNSIGNED_FIX, DImode, |
| gen_rtx (FIX, SFmode, operands[1])))); |
| emit_insn (gen_rtx (SET, VOIDmode, operands[0], |
| gen_rtx (SUBREG, SImode, temp, 0))); |
| DONE; |
| }") |
| |
| ;; Arithmetic instructions. |
| |
| (define_insn "subsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (minus:SI (match_operand:SI 1 "arith_operand" "dI") |
| (match_operand:SI 2 "arith_operand" "dI")))] |
| "" |
| "subo %2,%1,%0") |
| |
| ;; Try to generate an lda instruction when it would be faster than an |
| ;; add instruction. |
| ;; Some assemblers apparently won't accept two addresses added together. |
| |
| ;; ??? The condition should be improved to reject the case of two |
| ;; symbolic constants. |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d,d,d") |
| (plus:SI (match_operand:SI 1 "arith32_operand" "%dn,i,dn") |
| (match_operand:SI 2 "arith32_operand" "dn,dn,i")))] |
| "(TARGET_C_SERIES) && (CONSTANT_P (operands[1]) || CONSTANT_P (operands[2]))" |
| "* |
| { |
| if (GET_CODE (operands[1]) == CONST_INT) |
| { |
| rtx tmp = operands[1]; |
| operands[1] = operands[2]; |
| operands[2] = tmp; |
| } |
| if (GET_CODE (operands[2]) == CONST_INT |
| && GET_CODE (operands[1]) == REG |
| && i960_last_insn_type != I_TYPE_REG) |
| { |
| if (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) > -32) |
| return \"subo %n2,%1,%0\"; |
| else if (INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32) |
| return \"addo %1,%2,%0\"; |
| } |
| /* Non-canonical results (op1 == const, op2 != const) have been seen |
| in reload output when both operands were symbols before reload, so |
| we deal with it here. This may be a fault of the constraints above. */ |
| if (CONSTANT_P (operands[1])) |
| { |
| if (CONSTANT_P (operands[2])) |
| return \"lda %1+%2,%0\"; |
| else |
| return \"lda %1(%2),%0\"; |
| } |
| return \"lda %2(%1),%0\"; |
| }") |
| |
| (define_insn "addsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (plus:SI (match_operand:SI 1 "signed_arith_operand" "%dI") |
| (match_operand:SI 2 "signed_arith_operand" "dIK")))] |
| "" |
| "* |
| { |
| if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) |
| return \"subo %n2,%1,%0\"; |
| if (i960_bypass (insn, operands[1], operands[2], 0)) |
| return \"addo %2,%1,%0\"; |
| return \"addo %1,%2,%0\"; |
| }") |
| |
| (define_insn "mulsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (mult:SI (match_operand:SI 1 "arith_operand" "%dI") |
| (match_operand:SI 2 "arith_operand" "dI")))] |
| "" |
| "* |
| { |
| if (i960_bypass (insn, operands[1], operands[2], 0)) |
| return \"mulo %2,%1,%0\"; |
| return \"mulo %1,%2,%0\"; |
| }" |
| [(set_attr "type" "mult")]) |
| |
| (define_insn "umulsidi3" |
| [(set (match_operand:DI 0 "register_operand" "=d") |
| (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d")) |
| (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))] |
| "" |
| "* |
| { |
| if (i960_bypass (insn, operands[1], operands[2], 0)) |
| return \"emul %2,%1,%0\"; |
| return \"emul %1,%2,%0\"; |
| }" |
| [(set_attr "type" "mult")]) |
| |
| (define_insn "" |
| [(set (match_operand:DI 0 "register_operand" "=d") |
| (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%d")) |
| (match_operand:SI 2 "literal" "I")))] |
| "" |
| "* |
| { |
| if (i960_bypass (insn, operands[1], operands[2], 0)) |
| return \"emul %2,%1,%0\"; |
| return \"emul %1,%2,%0\"; |
| }" |
| [(set_attr "type" "mult")]) |
| |
| ;; This goes after the move/add/sub/mul instructions |
| ;; because those instructions are better when they apply. |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (match_operand:SI 1 "address_operand" "p"))] |
| "" |
| "lda %a1,%0" |
| [(set_attr "type" "load")]) |
| |
| ;; This will never be selected because of an "optimization" that GCC does. |
| ;; It always converts divides by a power of 2 into a sequence of instructions |
| ;; that does a right shift, and then corrects the result if it was negative. |
| |
| ;; (define_insn "" |
| ;; [(set (match_operand:SI 0 "register_operand" "=d") |
| ;; (div:SI (match_operand:SI 1 "arith_operand" "dI") |
| ;; (match_operand:SI 2 "power2_operand" "nI")))] |
| ;; "" |
| ;; "*{ |
| ;; operands[2] = gen_rtx(CONST_INT, VOIDmode,bitpos (INTVAL (operands[2]))); |
| ;; return \"shrdi %2,%1,%0\"; |
| ;; }" |
| |
| (define_insn "divsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (div:SI (match_operand:SI 1 "arith_operand" "dI") |
| (match_operand:SI 2 "arith_operand" "dI")))] |
| "" |
| "divi %2,%1,%0" |
| [(set_attr "type" "div")]) |
| |
| (define_insn "udivsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (udiv:SI (match_operand:SI 1 "arith_operand" "dI") |
| (match_operand:SI 2 "arith_operand" "dI")))] |
| "" |
| "divo %2,%1,%0" |
| [(set_attr "type" "div")]) |
| |
| ;; We must use `remi' not `modi' here, to ensure that `%' has the effects |
| ;; specified by the ANSI C standard. |
| |
| (define_insn "modsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (mod:SI (match_operand:SI 1 "arith_operand" "dI") |
| (match_operand:SI 2 "arith_operand" "dI")))] |
| "" |
| "remi %2,%1,%0" |
| [(set_attr "type" "div")]) |
| |
| (define_insn "umodsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (umod:SI (match_operand:SI 1 "arith_operand" "dI") |
| (match_operand:SI 2 "arith_operand" "dI")))] |
| "" |
| "remo %2,%1,%0" |
| [(set_attr "type" "div")]) |
| |
| ;; And instructions (with complement also). |
| |
| (define_insn "andsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (and:SI (match_operand:SI 1 "register_operand" "%d") |
| (match_operand:SI 2 "logic_operand" "dIM")))] |
| "" |
| "* |
| { |
| if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) |
| return \"andnot %C2,%1,%0\"; |
| if (i960_bypass (insn, operands[1], operands[2], 0)) |
| return \"and %2,%1,%0\"; |
| return \"and %1,%2,%0\"; |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (and:SI (match_operand:SI 1 "arith_operand" "dI") |
| (match_operand:SI 2 "cmplpower2_operand" "n")))] |
| "" |
| "* |
| { |
| operands[2] = gen_rtx (CONST_INT, VOIDmode, |
| bitpos (~INTVAL (operands[2]))); |
| return \"clrbit %2,%1,%0\"; |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (and:SI (not:SI (match_operand:SI 1 "register_operand" "d")) |
| (match_operand:SI 2 "logic_operand" "dIM")))] |
| "" |
| "* |
| { |
| if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) |
| return \"nor %C2,%1,%0\"; |
| if (i960_bypass (insn, operands[1], operands[2], 0)) |
| return \"notand %2,%1,%0\"; |
| return \"andnot %1,%2,%0\"; |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (ior:SI (not:SI (match_operand:SI 1 "register_operand" "%d")) |
| (not:SI (match_operand:SI 2 "register_operand" "d"))))] |
| "" |
| "* |
| { |
| if (i960_bypass (insn, operands[1], operands[2], 0)) |
| return \"nand %2,%1,%0\"; |
| return \"nand %1,%2,%0\"; |
| }") |
| |
| (define_insn "iorsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (ior:SI (match_operand:SI 1 "register_operand" "%d") |
| (match_operand:SI 2 "logic_operand" "dIM")))] |
| "" |
| "* |
| { |
| if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) |
| return \"ornot %C2,%1,%0\"; |
| if (i960_bypass (insn, operands[1], operands[2], 0)) |
| return \"or %2,%1,%0\"; |
| return \"or %1,%2,%0\"; |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (ior:SI (match_operand:SI 1 "register_operand" "d") |
| (match_operand:SI 2 "power2_operand" "n")))] |
| "" |
| "* |
| { |
| operands[2] = gen_rtx (CONST_INT, VOIDmode, |
| bitpos (INTVAL (operands[2]))); |
| return \"setbit %2,%1,%0\"; |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (ior:SI (not:SI (match_operand:SI 1 "register_operand" "d")) |
| (match_operand:SI 2 "logic_operand" "dIM")))] |
| "" |
| "* |
| { |
| if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) |
| return \"nand %C2,%1,%0\"; |
| if (i960_bypass (insn, operands[1], operands[2], 0)) |
| return \"notor %2,%1,%0\"; |
| return \"ornot %1,%2,%0\"; |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (and:SI (not:SI (match_operand:SI 1 "register_operand" "%d")) |
| (not:SI (match_operand:SI 2 "register_operand" "d"))))] |
| "" |
| "* |
| { |
| if (i960_bypass (insn, operands[1], operands[2], 0)) |
| return \"nor %2,%1,%0\"; |
| return \"nor %1,%2,%0\"; |
| }") |
| |
| (define_insn "xorsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (xor:SI (match_operand:SI 1 "register_operand" "%d") |
| (match_operand:SI 2 "logic_operand" "dIM")))] |
| "" |
| "* |
| { |
| if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) |
| return \"xnor %C2,%1,%0\"; |
| if (i960_bypass (insn, operands[1], operands[2], 0)) |
| return \"xor %2,%1,%0\"; |
| return \"xor %1,%2,%0\"; |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (xor:SI (match_operand:SI 1 "arith_operand" "dI") |
| (match_operand:SI 2 "power2_operand" "n")))] |
| "" |
| "* |
| { |
| operands[2] = gen_rtx (CONST_INT, VOIDmode, |
| bitpos (INTVAL (operands[2]))); |
| return \"notbit %2,%1,%0\"; |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (not:SI (xor:SI (match_operand:SI 1 "register_operand" "%d") |
| (match_operand:SI 2 "register_operand" "d"))))] |
| "" |
| "* |
| { |
| if (i960_bypass (insn, operands[1], operands[2], 0)) |
| return \"xnor %2,%1,%0\"; |
| return \"xnor %2,%1,%0\"; |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (ior:SI (ashift:SI (const_int 1) |
| (match_operand:SI 1 "register_operand" "d")) |
| (match_operand:SI 2 "arith_operand" "dI")))] |
| "" |
| "setbit %1,%2,%0") |
| |
| ;; (not (ashift 1 reg)) canonicalizes to (rotate -2 reg) |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (and:SI (rotate:SI (const_int -2) |
| (match_operand:SI 1 "register_operand" "d")) |
| (match_operand:SI 2 "register_operand" "d")))] |
| "" |
| "clrbit %1,%2,%0") |
| |
| ;; The above pattern canonicalizes to this when both the input and output |
| ;; are the same pseudo-register. |
| (define_insn "" |
| [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "=d") |
| (const_int 1) |
| (match_operand:SI 1 "register_operand" "d")) |
| (const_int 0))] |
| "" |
| "clrbit %1,%0,%0") |
| |
| (define_insn "" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (xor:SI (ashift:SI (const_int 1) |
| (match_operand:SI 1 "register_operand" "d")) |
| (match_operand:SI 2 "arith_operand" "dI")))] |
| "" |
| "notbit %1,%2,%0") |
| |
| (define_insn "negsi2" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (neg:SI (match_operand:SI 1 "arith_operand" "dI")))] |
| "" |
| "subo %1,0,%0" |
| [(set_attr "length" "1")]) |
| |
| (define_insn "one_cmplsi2" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (not:SI (match_operand:SI 1 "arith_operand" "dI")))] |
| "" |
| "not %1,%0" |
| [(set_attr "length" "1")]) |
| |
| ;; Floating point arithmetic instructions. |
| |
| (define_insn "adddf3" |
| [(set (match_operand:DF 0 "register_operand" "=d*f") |
| (plus:DF (match_operand:DF 1 "fp_arith_operand" "%rGH") |
| (match_operand:DF 2 "fp_arith_operand" "rGH")))] |
| "TARGET_NUMERICS" |
| "addrl %1,%2,%0" |
| [(set_attr "type" "fpadd")]) |
| |
| (define_insn "addsf3" |
| [(set (match_operand:SF 0 "register_operand" "=d*f") |
| (plus:SF (match_operand:SF 1 "fp_arith_operand" "%rGH") |
| (match_operand:SF 2 "fp_arith_operand" "rGH")))] |
| "TARGET_NUMERICS" |
| "addr %1,%2,%0" |
| [(set_attr "type" "fpadd")]) |
| |
| |
| (define_insn "subdf3" |
| [(set (match_operand:DF 0 "register_operand" "=d*f") |
| (minus:DF (match_operand:DF 1 "fp_arith_operand" "rGH") |
| (match_operand:DF 2 "fp_arith_operand" "rGH")))] |
| "TARGET_NUMERICS" |
| "subrl %2,%1,%0" |
| [(set_attr "type" "fpadd")]) |
| |
| (define_insn "subsf3" |
| [(set (match_operand:SF 0 "register_operand" "=d*f") |
| (minus:SF (match_operand:SF 1 "fp_arith_operand" "rGH") |
| (match_operand:SF 2 "fp_arith_operand" "rGH")))] |
| "TARGET_NUMERICS" |
| "subr %2,%1,%0" |
| [(set_attr "type" "fpadd")]) |
| |
| |
| (define_insn "muldf3" |
| [(set (match_operand:DF 0 "register_operand" "=d*f") |
| (mult:DF (match_operand:DF 1 "fp_arith_operand" "%rGH") |
| (match_operand:DF 2 "fp_arith_operand" "rGH")))] |
| "TARGET_NUMERICS" |
| "mulrl %1,%2,%0" |
| [(set_attr "type" "fpmul")]) |
| |
| (define_insn "mulsf3" |
| [(set (match_operand:SF 0 "register_operand" "=d*f") |
| (mult:SF (match_operand:SF 1 "fp_arith_operand" "%rGH") |
| (match_operand:SF 2 "fp_arith_operand" "rGH")))] |
| "TARGET_NUMERICS" |
| "mulr %1,%2,%0" |
| [(set_attr "type" "fpmul")]) |
| |
| |
| (define_insn "divdf3" |
| [(set (match_operand:DF 0 "register_operand" "=d*f") |
| (div:DF (match_operand:DF 1 "fp_arith_operand" "rGH") |
| (match_operand:DF 2 "fp_arith_operand" "rGH")))] |
| "TARGET_NUMERICS" |
| "divrl %2,%1,%0" |
| [(set_attr "type" "fpdiv")]) |
| |
| (define_insn "divsf3" |
| [(set (match_operand:SF 0 "register_operand" "=d*f") |
| (div:SF (match_operand:SF 1 "fp_arith_operand" "rGH") |
| (match_operand:SF 2 "fp_arith_operand" "rGH")))] |
| "TARGET_NUMERICS" |
| "divr %2,%1,%0" |
| [(set_attr "type" "fpdiv")]) |
| |
| (define_insn "negdf2" |
| [(set (match_operand:DF 0 "register_operand" "=d,d*f") |
| (neg:DF (match_operand:DF 1 "register_operand" "d,r")))] |
| "" |
| "* |
| { |
| if (which_alternative == 0) |
| { |
| if (REGNO (operands[0]) == REGNO (operands[1])) |
| return \"notbit 31,%D1,%D0\"; |
| return \"mov %1,%0\;notbit 31,%D1,%D0\"; |
| } |
| return \"subrl %1,0f0.0,%0\"; |
| }" |
| [(set_attr "type" "fpadd")]) |
| |
| (define_insn "negsf2" |
| [(set (match_operand:SF 0 "register_operand" "=d,d*f") |
| (neg:SF (match_operand:SF 1 "register_operand" "d,r")))] |
| "" |
| "@ |
| notbit 31,%1,%0 |
| subr %1,0f0.0,%0" |
| [(set_attr "type" "fpadd")]) |
| |
| ;;; The abs patterns also work even if the target machine doesn't have |
| ;;; floating point, because in that case dstreg and srcreg will always be |
| ;;; less than 32. |
| |
| (define_insn "absdf2" |
| [(set (match_operand:DF 0 "register_operand" "=d*f") |
| (abs:DF (match_operand:DF 1 "register_operand" "df")))] |
| "" |
| "* |
| { |
| int dstreg = REGNO (operands[0]); |
| int srcreg = REGNO (operands[1]); |
| |
| if (dstreg < 32) |
| { |
| if (srcreg < 32) |
| { |
| if (dstreg != srcreg) |
| output_asm_insn (\"mov %1,%0\", operands); |
| return \"clrbit 31,%D1,%D0\"; |
| } |
| /* Src is an fp reg. */ |
| return \"movrl %1,%0\;clrbit 31,%D1,%D0\"; |
| } |
| if (srcreg >= 32) |
| return \"cpysre %1,0f0.0,%0\"; |
| return \"movrl %1,%0\;cpysre %0,0f0.0,%0\"; |
| }" |
| [(set_attr "type" "multi")]) |
| |
| (define_insn "abssf2" |
| [(set (match_operand:SF 0 "register_operand" "=d*f") |
| (abs:SF (match_operand:SF 1 "register_operand" "df")))] |
| "" |
| "* |
| { |
| int dstreg = REGNO (operands[0]); |
| int srcreg = REGNO (operands[1]); |
| |
| if (dstreg < 32 && srcreg < 32) |
| return \"clrbit 31,%1,%0\"; |
| |
| if (dstreg >= 32 && srcreg >= 32) |
| return \"cpysre %1,0f0.0,%0\"; |
| |
| if (dstreg < 32) |
| return \"movr %1,%0\;clrbit 31,%0,%0\"; |
| |
| return \"movr %1,%0\;cpysre %0,0f0.0,%0\"; |
| }" |
| [(set_attr "type" "multi")]) |
| |
| ;; Tetra (16 byte) float support. |
| |
| (define_expand "cmpxf" |
| [(set (reg:CC 36) |
| (compare:CC (match_operand:XF 0 "register_operand" "") |
| (match_operand:XF 1 "nonmemory_operand" "")))] |
| "TARGET_NUMERICS" |
| " |
| { |
| i960_compare_op0 = operands[0]; |
| i960_compare_op1 = operands[1]; |
| DONE; |
| }") |
| |
| (define_insn "" |
| [(set (reg:CC 36) |
| (compare:CC (match_operand:XF 0 "register_operand" "f") |
| (match_operand:XF 1 "nonmemory_operand" "fGH")))] |
| "TARGET_NUMERICS" |
| "cmpr %0,%1" |
| [(set_attr "type" "fpcc")]) |
| |
| (define_expand "movxf" |
| [(set (match_operand:XF 0 "general_operand" "") |
| (match_operand:XF 1 "fpmove_src_operand" ""))] |
| "" |
| " |
| { |
| if (emit_move_sequence (operands, XFmode)) |
| DONE; |
| }") |
| |
| (define_insn "" |
| [(set (match_operand:XF 0 "general_operand" "=r,f,d,d,m") |
| (match_operand:XF 1 "fpmove_src_operand" "r,GH,F,m,d"))] |
| "register_operand (operands[0], XFmode) |
| || register_operand (operands[1], XFmode)" |
| "* |
| { |
| switch (which_alternative) |
| { |
| case 0: |
| if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) |
| return \"movre %1,%0\"; |
| else |
| return \"movq %1,%0\"; |
| case 1: |
| return \"movre %1,%0\"; |
| case 2: |
| return i960_output_ldconst (operands[0], operands[1]); |
| case 3: |
| return \"ldt %1,%0\"; |
| case 4: |
| return \"stt %1,%0\"; |
| } |
| }" |
| [(set_attr "type" "move,move,load,fpload,fpstore")]) |
| |
| (define_insn "extendsfxf2" |
| [(set (match_operand:XF 0 "register_operand" "=f,d") |
| (float_extend:XF |
| (match_operand:SF 1 "register_operand" "d,f")))] |
| "TARGET_NUMERICS" |
| "@ |
| movr %1,%0 |
| movre %1,%0" |
| [(set_attr "type" "fpmove")]) |
| |
| (define_insn "extenddfxf2" |
| [(set (match_operand:XF 0 "register_operand" "=f,d") |
| (float_extend:XF |
| (match_operand:DF 1 "register_operand" "d,f")))] |
| "TARGET_NUMERICS" |
| "@ |
| movrl %1,%0 |
| movre %1,%0" |
| [(set_attr "type" "fpmove")]) |
| |
| (define_insn "truncxfdf2" |
| [(set (match_operand:DF 0 "register_operand" "=d") |
| (float_truncate:DF |
| (match_operand:XF 1 "register_operand" "f")))] |
| "TARGET_NUMERICS" |
| "movrl %1,%0" |
| [(set_attr "type" "fpmove")]) |
| |
| (define_insn "truncxfsf2" |
| [(set (match_operand:SF 0 "register_operand" "=d") |
| (float_truncate:SF |
| (match_operand:XF 1 "register_operand" "f")))] |
| "TARGET_NUMERICS" |
| "movr %1,%0" |
| [(set_attr "type" "fpmove")]) |
| |
| (define_insn "floatsixf2" |
| [(set (match_operand:XF 0 "register_operand" "=f") |
| (float:XF (match_operand:SI 1 "register_operand" "d")))] |
| "TARGET_NUMERICS" |
| "cvtir %1,%0" |
| [(set_attr "type" "fpcvt")]) |
| |
| (define_insn "fix_truncxfsi2" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (fix:SI (fix:XF (match_operand:XF 1 "register_operand" "f"))))] |
| "TARGET_NUMERICS" |
| "cvtzri %1,%0" |
| [(set_attr "type" "fpcvt")]) |
| |
| (define_insn "fixuns_truncxfsi2" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (unsigned_fix:SI (fix:XF (match_operand:XF 1 "register_operand" "f"))))] |
| "TARGET_NUMERICS" |
| "cvtzri %1,%0" |
| [(set_attr "type" "fpcvt")]) |
| |
| (define_insn "addxf3" |
| [(set (match_operand:XF 0 "register_operand" "=f") |
| (plus:XF (match_operand:XF 1 "nonmemory_operand" "%fGH") |
| (match_operand:XF 2 "nonmemory_operand" "fGH")))] |
| "TARGET_NUMERICS" |
| "addr %1,%2,%0" |
| [(set_attr "type" "fpadd")]) |
| |
| (define_insn "subxf3" |
| [(set (match_operand:XF 0 "register_operand" "=f") |
| (minus:XF (match_operand:XF 1 "nonmemory_operand" "fGH") |
| (match_operand:XF 2 "nonmemory_operand" "fGH")))] |
| "TARGET_NUMERICS" |
| "subr %2,%1,%0" |
| [(set_attr "type" "fpadd")]) |
| |
| (define_insn "mulxf3" |
| [(set (match_operand:XF 0 "register_operand" "=f") |
| (mult:XF (match_operand:XF 1 "nonmemory_operand" "%fGH") |
| (match_operand:XF 2 "nonmemory_operand" "fGH")))] |
| "TARGET_NUMERICS" |
| "mulr %1,%2,%0" |
| [(set_attr "type" "fpmul")]) |
| |
| (define_insn "divxf3" |
| [(set (match_operand:XF 0 "register_operand" "=f") |
| (div:XF (match_operand:XF 1 "nonmemory_operand" "fGH") |
| (match_operand:XF 2 "nonmemory_operand" "fGH")))] |
| "TARGET_NUMERICS" |
| "divr %2,%1,%0" |
| [(set_attr "type" "fpdiv")]) |
| |
| (define_insn "negxf2" |
| [(set (match_operand:XF 0 "register_operand" "=f") |
| (neg:XF (match_operand:XF 1 "register_operand" "f")))] |
| "TARGET_NUMERICS" |
| "subr %1,0f0.0,%0" |
| [(set_attr "type" "fpadd")]) |
| |
| (define_insn "absxf2" |
| [(set (match_operand:XF 0 "register_operand" "=f") |
| (abs:XF (match_operand:XF 1 "register_operand" "f")))] |
| "(TARGET_NUMERICS)" |
| "cpysre %1,0f0.0,%0" |
| [(set_attr "type" "fpmove")]) |
| |
| ;; Arithmetic shift instructions. |
| |
| ;; The shli instruction generates an overflow fault if the sign changes. |
| ;; In the case of overflow, it does not give the natural result, it instead |
| ;; gives the last shift value before the overflow. We can not use this |
| ;; instruction because gcc thinks that arithmetic left shift and logical |
| ;; left shift are identical, and sometimes canonicalizes the logical left |
| ;; shift to an arithmetic left shift. Therefore we must always use the |
| ;; logical left shift instruction. |
| |
| (define_insn "ashlsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (ashift:SI (match_operand:SI 1 "arith_operand" "dI") |
| (match_operand:SI 2 "arith_operand" "dI")))] |
| "" |
| "shlo %2,%1,%0" |
| [(set_attr "type" "alu2")]) |
| |
| (define_insn "ashrsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (ashiftrt:SI (match_operand:SI 1 "arith_operand" "dI") |
| (match_operand:SI 2 "arith_operand" "dI")))] |
| "" |
| "shri %2,%1,%0" |
| [(set_attr "type" "alu2")]) |
| |
| (define_insn "lshrsi3" |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (lshiftrt:SI (match_operand:SI 1 "arith_operand" "dI") |
| (match_operand:SI 2 "arith_operand" "dI")))] |
| "" |
| "shro %2,%1,%0" |
| [(set_attr "type" "alu2")]) |
| |
| ;; Unconditional and other jump instructions. |
| |
| (define_insn "jump" |
| [(set (pc) |
| (label_ref (match_operand 0 "" "")))] |
| "" |
| "b %l0" |
| [(set_attr "type" "branch")]) |
| |
| (define_insn "indirect_jump" |
| [(set (pc) (match_operand:SI 0 "address_operand" "p"))] |
| "" |
| "bx %a0" |
| [(set_attr "type" "branch")]) |
| |
| (define_insn "tablejump" |
| [(set (pc) (match_operand:SI 0 "register_operand" "d")) |
| (use (label_ref (match_operand 1 "" "")))] |
| "" |
| "bx (%0)" |
| [(set_attr "type" "branch")]) |
| |
| ;;- jump to subroutine |
| |
| (define_expand "call" |
| [(call (match_operand:SI 0 "memory_operand" "m") |
| (match_operand:SI 1 "immediate_operand" "i"))] |
| "" |
| " |
| { |
| emit_insn (gen_call_internal (operands[0], operands[1], |
| virtual_outgoing_args_rtx)); |
| DONE; |
| }") |
| |
| ;; We need a call saved register allocated for the match_scratch, so we use |
| ;; 'l' because all local registers are call saved. |
| |
| ;; ??? I would prefer to use a match_scratch here, but match_scratch allocated |
| ;; registers can't be used for spills. In a function with lots of calls, |
| ;; local-alloc may allocate all local registers to a match_scratch, leaving |
| ;; no local registers available for spills. |
| |
| (define_insn "call_internal" |
| [(call (match_operand:SI 0 "memory_operand" "m") |
| (match_operand:SI 1 "immediate_operand" "i")) |
| (use (match_operand:SI 2 "address_operand" "p")) |
| (clobber (reg:SI 19))] |
| "" |
| "* return i960_output_call_insn (operands[0], operands[1], operands[2], |
| insn);" |
| [(set_attr "type" "call")]) |
| |
| (define_expand "call_value" |
| [(set (match_operand 0 "register_operand" "=d") |
| (call (match_operand:SI 1 "memory_operand" "m") |
| (match_operand:SI 2 "immediate_operand" "i")))] |
| "" |
| " |
| { |
| emit_insn (gen_call_value_internal (operands[0], operands[1], operands[2], |
| virtual_outgoing_args_rtx)); |
| DONE; |
| }") |
| |
| ;; We need a call saved register allocated for the match_scratch, so we use |
| ;; 'l' because all local registers are call saved. |
| |
| (define_insn "call_value_internal" |
| [(set (match_operand 0 "register_operand" "=d") |
| (call (match_operand:SI 1 "memory_operand" "m") |
| (match_operand:SI 2 "immediate_operand" "i"))) |
| (use (match_operand:SI 3 "address_operand" "p")) |
| (clobber (reg:SI 19))] |
| "" |
| "* return i960_output_call_insn (operands[1], operands[2], operands[3], |
| insn);" |
| [(set_attr "type" "call")]) |
| |
| (define_insn "return" |
| [(return)] |
| "" |
| "* return i960_output_ret_insn (insn);" |
| [(set_attr "type" "branch")]) |
| |
| (define_insn "nop" |
| [(const_int 0)] |
| "" |
| "") |
| |
| ;; Various peephole optimizations for multiple-word moves, loads, and stores. |
| ;; Multiple register moves. |
| |
| ;; Matched 5/28/91 |
| (define_peephole |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (match_operand:SI 1 "register_operand" "r")) |
| (set (match_operand:SI 2 "register_operand" "=r") |
| (match_operand:SI 3 "register_operand" "r")) |
| (set (match_operand:SI 4 "register_operand" "=r") |
| (match_operand:SI 5 "register_operand" "r")) |
| (set (match_operand:SI 6 "register_operand" "=r") |
| (match_operand:SI 7 "register_operand" "r"))] |
| "((REGNO (operands[0]) & 3) == 0) |
| && ((REGNO (operands[1]) & 3) == 0) |
| && (REGNO (operands[0]) + 1 == REGNO (operands[2])) |
| && (REGNO (operands[1]) + 1 == REGNO (operands[3])) |
| && (REGNO (operands[0]) + 2 == REGNO (operands[4])) |
| && (REGNO (operands[1]) + 2 == REGNO (operands[5])) |
| && (REGNO (operands[0]) + 3 == REGNO (operands[6])) |
| && (REGNO (operands[1]) + 3 == REGNO (operands[7]))" |
| "movq %1,%0") |
| |
| ;; Matched 4/17/92 |
| (define_peephole |
| [(set (match_operand:DI 0 "register_operand" "=r") |
| (match_operand:DI 1 "register_operand" "r")) |
| (set (match_operand:DI 2 "register_operand" "=r") |
| (match_operand:DI 3 "register_operand" "r"))] |
| "((REGNO (operands[0]) & 3) == 0) |
| && ((REGNO (operands[1]) & 3) == 0) |
| && (REGNO (operands[0]) + 2 == REGNO (operands[2])) |
| && (REGNO (operands[1]) + 2 == REGNO (operands[3]))" |
| "movq %1,%0") |
| |
| ;; Matched 4/17/92 |
| (define_peephole |
| [(set (match_operand:DI 0 "register_operand" "=r") |
| (match_operand:DI 1 "register_operand" "r")) |
| (set (match_operand:SI 2 "register_operand" "=r") |
| (match_operand:SI 3 "register_operand" "r")) |
| (set (match_operand:SI 4 "register_operand" "=r") |
| (match_operand:SI 5 "register_operand" "r"))] |
| "((REGNO (operands[0]) & 3) == 0) |
| && ((REGNO (operands[1]) & 3) == 0) |
| && (REGNO (operands[0]) + 2 == REGNO (operands[2])) |
| && (REGNO (operands[1]) + 2 == REGNO (operands[3])) |
| && (REGNO (operands[0]) + 3 == REGNO (operands[4])) |
| && (REGNO (operands[1]) + 3 == REGNO (operands[5]))" |
| "movq %1,%0") |
| |
| ;; Matched 4/17/92 |
| (define_peephole |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (match_operand:SI 1 "register_operand" "r")) |
| (set (match_operand:SI 2 "register_operand" "=r") |
| (match_operand:SI 3 "register_operand" "r")) |
| (set (match_operand:DI 4 "register_operand" "=r") |
| (match_operand:DI 5 "register_operand" "r"))] |
| "((REGNO (operands[0]) & 3) == 0) |
| && ((REGNO (operands[1]) & 3) == 0) |
| && (REGNO (operands[0]) + 1 == REGNO (operands[2])) |
| && (REGNO (operands[1]) + 1 == REGNO (operands[3])) |
| && (REGNO (operands[0]) + 2 == REGNO (operands[4])) |
| && (REGNO (operands[1]) + 2 == REGNO (operands[5]))" |
| "movq %1,%0") |
| |
| ;; Matched 4/17/92 |
| (define_peephole |
| [(set (match_operand:DI 0 "register_operand" "=r") |
| (match_operand:DI 1 "register_operand" "r")) |
| (set (match_operand:SI 2 "register_operand" "=r") |
| (match_operand:SI 3 "register_operand" "r"))] |
| "((REGNO (operands[0]) & 3) == 0) |
| && ((REGNO (operands[1]) & 3) == 0) |
| && (REGNO (operands[0]) + 2 == REGNO (operands[2])) |
| && (REGNO (operands[1]) + 2 == REGNO (operands[3]))" |
| "movt %1,%0") |
| |
| ;; Matched 5/28/91 |
| (define_peephole |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (match_operand:SI 1 "register_operand" "r")) |
| (set (match_operand:SI 2 "register_operand" "=r") |
| (match_operand:SI 3 "register_operand" "r")) |
| (set (match_operand:SI 4 "register_operand" "=r") |
| (match_operand:SI 5 "register_operand" "r"))] |
| "((REGNO (operands[0]) & 3) == 0) |
| && ((REGNO (operands[1]) & 3) == 0) |
| && (REGNO (operands[0]) + 1 == REGNO (operands[2])) |
| && (REGNO (operands[1]) + 1 == REGNO (operands[3])) |
| && (REGNO (operands[0]) + 2 == REGNO (operands[4])) |
| && (REGNO (operands[1]) + 2 == REGNO (operands[5]))" |
| "movt %1,%0") |
| |
| ;; Matched 5/28/91 |
| (define_peephole |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (match_operand:SI 1 "register_operand" "r")) |
| (set (match_operand:SI 2 "register_operand" "=r") |
| (match_operand:SI 3 "register_operand" "r"))] |
| "((REGNO (operands[0]) & 1) == 0) |
| && ((REGNO (operands[1]) & 1) == 0) |
| && (REGNO (operands[0]) + 1 == REGNO (operands[2])) |
| && (REGNO (operands[1]) + 1 == REGNO (operands[3]))" |
| "movl %1,%0") |
| |
| ; Multiple register loads. |
| |
| ;; Matched 6/15/91 |
| (define_peephole |
| [(set (match_operand:SI 0 "register_operand" "=r") |
| (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r") |
| (match_operand:SI 2 "immediate_operand" "n")))) |
| (set (match_operand:SI 3 "register_operand" "=r") |
| (mem:SI (plus:SI (match_dup 1) |
| (match_operand:SI 4 "immediate_operand" "n")))) |
| (set (match_operand:SI 5 "register_operand" "=r") |
| (mem:SI (plus:SI (match_dup 1) |
| (match_operand:SI 6 "immediate_operand" "n")))) |
| (set (match_operand:SI 7 "register_operand" "=r") |
| (mem:SI (plus:SI (match_dup 1) |
| (match_operand:SI 8 "immediate_operand" "n"))))] |
| "(i960_si_ti (operands[1], operands[2]) && ((REGNO (operands[0]) & 3) == 0) |
| && (REGNO (operands[1]) != REGNO (operands[0])) |
| && (REGNO (operands[0]) + 1 == REGNO (operands[3])) |
| && (REGNO (operands[1]) != REGNO (operands[3])) |
| && (REGNO (operands[0]) + 2 == REGNO (operands[5])) |
| && (REGNO (operands[1]) != REGNO (operands[5])) |
| && (REGNO (operands[0]) + 3 == REGNO (operands[7])) |
| && (INTVAL (operands[2]) + 4 == INTVAL (operands[4])) |
| && (INTVAL (operands[2]) + 8 == INTVAL (operands[6])) |
| && (INTVAL (operands[2]) + 12 == INTVAL (operands[8])))" |
| "ldq %2(%1),%0") |
| |
| ;; Matched 5/28/91 |
| (define_peephole |
| [(set (match_operand:DF 0 "register_operand" "=d") |
| (mem:DF (plus:SI (match_operand:SI 1 "register_operand" "d") |
| (match_operand:SI 2 "immediate_operand" "n")))) |
| (set (match_operand:DF 3 "register_operand" "=d") |
| (mem:DF (plus:SI (match_dup 1) |
| (match_operand:SI 4 "immediate_operand" "n"))))] |
| "(i960_si_ti (operands[1], operands[2]) && ((REGNO (operands[0]) & 3) == 0) |
| && (REGNO (operands[1]) != REGNO (operands[0])) |
| && (REGNO (operands[0]) + 2 == REGNO (operands[3])) |
| && (REGNO (operands[1]) != REGNO (operands[3])) |
| && (INTVAL (operands[2]) + 8 == INTVAL (operands[4])))" |
| "ldq %2(%1),%0") |
| |
| ;; Matched 1/24/92 |
| (define_peephole |
| [(set (match_operand:DI 0 "register_operand" "=d") |
| (mem:DI (plus:SI (match_operand:SI 1 "register_operand" "d") |
| (match_operand:SI 2 "immediate_operand" "n")))) |
| (set (match_operand:DI 3 "register_operand" "=d") |
| (mem:DI (plus:SI (match_dup 1) |
| (match_operand:SI 4 "immediate_operand" "n"))))] |
| "(i960_si_ti (operands[1], operands[2]) && ((REGNO (operands[0]) & 3) == 0) |
| && (REGNO (operands[1]) != REGNO (operands[0])) |
| && (REGNO (operands[0]) + 2 == REGNO (operands[3])) |
| && (REGNO (operands[1]) != REGNO (operands[3])) |
| && (INTVAL (operands[2]) + 8 == INTVAL (operands[4])))" |
| "ldq %2(%1),%0") |
| |
| ;; Matched 4/17/92 |
| (define_peephole |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (mem:SI (match_operand:SI 1 "register_operand" "d"))) |
| (set (match_operand:SI 2 "register_operand" "=d") |
| (mem:SI (plus:SI (match_dup 1) |
| (match_operand:SI 3 "immediate_operand" "n")))) |
| (set (match_operand:SI 4 "register_operand" "=d") |
| (mem:SI (plus:SI (match_dup 1) |
| (match_operand:SI 5 "immediate_operand" "n")))) |
| (set (match_operand:SI 6 "register_operand" "=d") |
| (mem:SI (plus:SI (match_dup 1) |
| (match_operand:SI 7 "immediate_operand" "n"))))] |
| "(i960_si_ti (operands[1], 0) && ((REGNO (operands[0]) & 3) == 0) |
| && (REGNO (operands[1]) != REGNO (operands[0])) |
| && (REGNO (operands[0]) + 1 == REGNO (operands[2])) |
| && (REGNO (operands[1]) != REGNO (operands[2])) |
| && (REGNO (operands[0]) + 2 == REGNO (operands[4])) |
| && (REGNO (operands[1]) != REGNO (operands[4])) |
| && (REGNO (operands[0]) + 3 == REGNO (operands[6])) |
| && (INTVAL (operands[3]) == 4) |
| && (INTVAL (operands[5]) == 8) |
| && (INTVAL (operands[7]) == 12))" |
| "ldq (%1),%0") |
| |
| ;; Matched 5/28/91 |
| (define_peephole |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "d") |
| (match_operand:SI 2 "immediate_operand" "n")))) |
| (set (match_operand:SI 3 "register_operand" "=d") |
| (mem:SI (plus:SI (match_dup 1) |
| (match_operand:SI 4 "immediate_operand" "n")))) |
| (set (match_operand:SI 5 "register_operand" "=d") |
| (mem:SI (plus:SI (match_dup 1) |
| (match_operand:SI 6 "immediate_operand" "n"))))] |
| "(i960_si_ti (operands[1], operands[2]) && ((REGNO (operands[0]) & 3) == 0) |
| && (REGNO (operands[1]) != REGNO (operands[0])) |
| && (REGNO (operands[0]) + 1 == REGNO (operands[3])) |
| && (REGNO (operands[1]) != REGNO (operands[3])) |
| && (REGNO (operands[0]) + 2 == REGNO (operands[5])) |
| && (INTVAL (operands[2]) + 4 == INTVAL (operands[4])) |
| && (INTVAL (operands[2]) + 8 == INTVAL (operands[6])))" |
| "ldt %2(%1),%0") |
| |
| ;; Matched 6/15/91 |
| (define_peephole |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (mem:SI (match_operand:SI 1 "register_operand" "d"))) |
| (set (match_operand:SI 2 "register_operand" "=d") |
| (mem:SI (plus:SI (match_dup 1) |
| (match_operand:SI 3 "immediate_operand" "n")))) |
| (set (match_operand:SI 4 "register_operand" "=d") |
| (mem:SI (plus:SI (match_dup 1) |
| (match_operand:SI 5 "immediate_operand" "n"))))] |
| "(i960_si_ti (operands[1], 0) && ((REGNO (operands[0]) & 3) == 0) |
| && (REGNO (operands[1]) != REGNO (operands[0])) |
| && (REGNO (operands[0]) + 1 == REGNO (operands[2])) |
| && (REGNO (operands[1]) != REGNO (operands[2])) |
| && (REGNO (operands[0]) + 2 == REGNO (operands[4])) |
| && (INTVAL (operands[3]) == 4) |
| && (INTVAL (operands[5]) == 8))" |
| "ldt (%1),%0") |
| |
| ;; Matched 5/28/91 |
| (define_peephole |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "d") |
| (match_operand:SI 2 "immediate_operand" "n")))) |
| (set (match_operand:SI 3 "register_operand" "=d") |
| (mem:SI (plus:SI (match_dup 1) |
| (match_operand:SI 4 "immediate_operand" "n"))))] |
| "(i960_si_di (operands[1], operands[2]) && ((REGNO (operands[0]) & 1) == 0) |
| && (REGNO (operands[1]) != REGNO (operands[0])) |
| && (REGNO (operands[0]) + 1 == REGNO (operands[3])) |
| && (INTVAL (operands[2]) + 4 == INTVAL (operands[4])))" |
| "ldl %2(%1),%0") |
| |
| ;; Matched 5/28/91 |
| (define_peephole |
| [(set (match_operand:SI 0 "register_operand" "=d") |
| (mem:SI (match_operand:SI 1 "register_operand" "d"))) |
| (set (match_operand:SI 2 "register_operand" "=d") |
| (mem:SI (plus:SI (match_dup 1) |
| (match_operand:SI 3 "immediate_operand" "n"))))] |
| "(i960_si_di (operands[1], 0) && ((REGNO (operands[0]) & 1) == 0) |
| && (REGNO (operands[1]) != REGNO (operands[0])) |
| && (REGNO (operands[0]) + 1 == REGNO (operands[2])) |
| && (INTVAL (operands[3]) == 4))" |
| "ldl (%1),%0") |
| |
| ; Multiple register stores. |
| |
| ;; Matched 5/28/91 |
| (define_peephole |
| [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "d") |
| (match_operand:SI 1 "immediate_operand" "n"))) |
| (match_operand:SI 2 "register_operand" "d")) |
| (set (mem:SI (plus:SI (match_dup 0) |
| (match_operand:SI 3 "immediate_operand" "n"))) |
| (match_operand:SI 4 "register_operand" "d")) |
| (set (mem:SI (plus:SI (match_dup 0) |
| (match_operand:SI 5 "immediate_operand" "n"))) |
| (match_operand:SI 6 "register_operand" "d")) |
| (set (mem:SI (plus:SI (match_dup 0) |
| (match_operand:SI 7 "immediate_operand" "n"))) |
| (match_operand:SI 8 "register_operand" "d"))] |
| "(i960_si_ti (operands[0], operands[1]) && ((REGNO (operands[2]) & 3) == 0) |
| && (REGNO (operands[2]) + 1 == REGNO (operands[4])) |
| && (REGNO (operands[2]) + 2 == REGNO (operands[6])) |
| && (REGNO (operands[2]) + 3 == REGNO (operands[8])) |
| && (INTVAL (operands[1]) + 4 == INTVAL (operands[3])) |
| && (INTVAL (operands[1]) + 8 == INTVAL (operands[5])) |
| && (INTVAL (operands[1]) + 12 == INTVAL (operands[7])))" |
| "stq %2,%1(%0)") |
| |
| ;; Matched 6/16/91 |
| (define_peephole |
| [(set (mem:DF (plus:SI (match_operand:SI 0 "register_operand" "d") |
| (match_operand:SI 1 "immediate_operand" "n"))) |
| (match_operand:DF 2 "register_operand" "d")) |
| (set (mem:DF (plus:SI (match_dup 0) |
| (match_operand:SI 3 "immediate_operand" "n"))) |
| (match_operand:DF 4 "register_operand" "d"))] |
| "(i960_si_ti (operands[0], operands[1]) && ((REGNO (operands[2]) & 3) == 0) |
| && (REGNO (operands[2]) + 2 == REGNO (operands[4])) |
| && (INTVAL (operands[1]) + 8 == INTVAL (operands[3])))" |
| "stq %2,%1(%0)") |
| |
| ;; Matched 4/17/92 |
| (define_peephole |
| [(set (mem:DI (plus:SI (match_operand:SI 0 "register_operand" "d") |
| (match_operand:SI 1 "immediate_operand" "n"))) |
| (match_operand:DI 2 "register_operand" "d")) |
| (set (mem:DI (plus:SI (match_dup 0) |
| (match_operand:SI 3 "immediate_operand" "n"))) |
| (match_operand:DI 4 "register_operand" "d"))] |
| "(i960_si_ti (operands[0], operands[1]) && ((REGNO (operands[2]) & 3) == 0) |
| && (REGNO (operands[2]) + 2 == REGNO (operands[4])) |
| && (INTVAL (operands[1]) + 8 == INTVAL (operands[3])))" |
| "stq %2,%1(%0)") |
| |
| ;; Matched 1/23/92 |
| (define_peephole |
| [(set (mem:SI (match_operand:SI 0 "register_operand" "d")) |
| (match_operand:SI 1 "register_operand" "d")) |
| (set (mem:SI (plus:SI (match_dup 0) |
| (match_operand:SI 2 "immediate_operand" "n"))) |
| (match_operand:SI 3 "register_operand" "d")) |
| (set (mem:SI (plus:SI (match_dup 0) |
| (match_operand:SI 4 "immediate_operand" "n"))) |
| (match_operand:SI 5 "register_operand" "d")) |
| (set (mem:SI (plus:SI (match_dup 0) |
| (match_operand:SI 6 "immediate_operand" "n"))) |
| (match_operand:SI 7 "register_operand" "d"))] |
| "(i960_si_ti (operands[0], 0) && ((REGNO (operands[1]) & 3) == 0) |
| && (REGNO (operands[1]) + 1 == REGNO (operands[3])) |
| && (REGNO (operands[1]) + 2 == REGNO (operands[5])) |
| && (REGNO (operands[1]) + 3 == REGNO (operands[7])) |
| && (INTVAL (operands[2]) == 4) |
| && (INTVAL (operands[4]) == 8) |
| && (INTVAL (operands[6]) == 12))" |
| "stq %1,(%0)") |
| |
| ;; Matched 5/29/91 |
| (define_peephole |
| [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "d") |
| (match_operand:SI 1 "immediate_operand" "n"))) |
| (match_operand:SI 2 "register_operand" "d")) |
| (set (mem:SI (plus:SI (match_dup 0) |
| (match_operand:SI 3 "immediate_operand" "n"))) |
| (match_operand:SI 4 "register_operand" "d")) |
| (set (mem:SI (plus:SI (match_dup 0) |
| (match_operand:SI 5 "immediate_operand" "n"))) |
| (match_operand:SI 6 "register_operand" "d"))] |
| "(i960_si_ti (operands[0], operands[1]) && ((REGNO (operands[2]) & 3) == 0) |
| && (REGNO (operands[2]) + 1 == REGNO (operands[4])) |
| && (REGNO (operands[2]) + 2 == REGNO (operands[6])) |
| && (INTVAL (operands[1]) + 4 == INTVAL (operands[3])) |
| && (INTVAL (operands[1]) + 8 == INTVAL (operands[5])))" |
| "stt %2,%1(%0)") |
| |
| ;; Matched 5/29/91 |
| (define_peephole |
| [(set (mem:SI (match_operand:SI 0 "register_operand" "d")) |
| (match_operand:SI 1 "register_operand" "d")) |
| (set (mem:SI (plus:SI (match_dup 0) |
| (match_operand:SI 2 "immediate_operand" "n"))) |
| (match_operand:SI 3 "register_operand" "d")) |
| (set (mem:SI (plus:SI (match_dup 0) |
| (match_operand:SI 4 "immediate_operand" "n"))) |
| (match_operand:SI 5 "register_operand" "d"))] |
| "(i960_si_ti (operands[0], 0) && ((REGNO (operands[1]) & 3) == 0) |
| && (REGNO (operands[1]) + 1 == REGNO (operands[3])) |
| && (REGNO (operands[1]) + 2 == REGNO (operands[5])) |
| && (INTVAL (operands[2]) == 4) |
| && (INTVAL (operands[4]) == 8))" |
| "stt %1,(%0)") |
| |
| ;; Matched 5/28/91 |
| (define_peephole |
| [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "d") |
| (match_operand:SI 1 "immediate_operand" "n"))) |
| (match_operand:SI 2 "register_operand" "d")) |
| (set (mem:SI (plus:SI (match_dup 0) |
| (match_operand:SI 3 "immediate_operand" "n"))) |
| (match_operand:SI 4 "register_operand" "d"))] |
| "(i960_si_di (operands[0], operands[1]) && ((REGNO (operands[2]) & 1) == 0) |
| && (REGNO (operands[2]) + 1 == REGNO (operands[4])) |
| && (INTVAL (operands[1]) + 4 == INTVAL (operands[3])))" |
| "stl %2,%1(%0)") |
| |
| ;; Matched 5/28/91 |
| (define_peephole |
| [(set (mem:SI (match_operand:SI 0 "register_operand" "d")) |
| (match_operand:SI 1 "register_operand" "d")) |
| (set (mem:SI (plus:SI (match_dup 0) |
| (match_operand:SI 2 "immediate_operand" "n"))) |
| (match_operand:SI 3 "register_operand" "d"))] |
| "(i960_si_di (operands[0], 0) && ((REGNO (operands[1]) & 1) == 0) |
| && (REGNO (operands[1]) + 1 == REGNO (operands[3])) |
| && (INTVAL (operands[2]) == 4))" |
| "stl %1,(%0)") |