diff --git a/gcc/config/pyr/pyr.md b/gcc/config/pyr/pyr.md new file mode 100644 index 00000000000..1edb7b87470 --- /dev/null +++ b/gcc/config/pyr/pyr.md @@ -0,0 +1,1372 @@ +;; GNU C machine description for Pyramid 90x, 9000, MIServer Series +;; 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. + +;; Instruction patterns. When multiple patterns apply, +;; the first one in the file is chosen. +;; +;; 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. + +;; * Try using define_insn instead of some peepholes in more places. +;; * Set REG_NOTES:REG_EQUIV for cvt[bh]w loads. This would make the +;; backward scan in sign_extend needless. +;; * Match (pc) (label_ref) case in peephole patterns. +;; * Should optimize +;; "cmpX op1,op2; b{eq,ne} LY; ucmpX op1.op2; b{lt,le,gt,ge} LZ" +;; to +;; "ucmpX op1,op2; b{eq,ne} LY; b{lt,le,gt,ge} LZ" +;; by pre-scanning insn and running notice_update_cc for them. +;; * Is it necessary to do copy_rtx in the test and compare patterns? +;; * Fix true frame pointer omission. +;; * Make the jump tables contain branches, not addresses! This would +;; save us one instruction. +;; * Could the compilcated scheme for compares be simplyfied, if we had +;; no named cmpqi or cmphi patterns, and instead anonymous patterns for +;; the less-than-word compare cases pyr can handle??? +;; * The jump insn seems to accept more than just IR addressing. Would +;; we win by telling GCC? Or can we use movw into the global reg which +;; is a synonym for pc? +;; * More DImode patterns. +;; * Scan backwards in "zero_extendhisi2", "zero_extendqisi2" to find out +;; if the extension can be omitted. +;; * "divmodsi" with Pyramid "ediv" insn. Is it possible in rtl?? +;; * Would "rcsp tmpreg; u?cmp[bh] op1_regdispl(tmpreg),op2" win in +;; comparison with the two extensions and single test generated now? +;; The rcsp insn could be expanded, and moved out of loops by the +;; optimizer, making 1 (64 bit) insn of 3 (32 bit) insns in loops. +;; The rcsp insn could be followed by an add insn, making non-displacement +;; IR addressing sufficient. + +;______________________________________________________________________ +; +; Test and Compare Patterns. +;______________________________________________________________________ + +; The argument for the rather complicated test and compare expansion +; scheme, is the irregular pyramid instructions for these operations. +; 1) Pyramid has different signed and unsigned compares. 2) HImode +; and QImode integers are memory-memory and immediate-memory only. 3) +; Unsigned HImode compares doesn't exist. 4) Only certain +; combinations of addresses are allowed for memory-memory compares. +; Whenever necessary, in order to fulfill these addressing +; constraints, the compare operands are swapped. + +(define_expand "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" ""))] + "" "operands[0] = force_reg (SImode, operands[0]);") + +(define_insn "" + [(set (cc0) + (compare (match_operand:SI 0 "memory_operand" "m") + (match_operand:SI 1 "memory_operand" "m")))] + "weird_memory_memory (operands[0], operands[1])" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + weird_memory_memory (operands[0], operands[1]); + + if (swap_operands) + { + cc_status.flags = CC_REVERSED; + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw %0,%1\"; + } + return \"cmpw %0,%1\"; + } + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw %1,%0\"; + } + return \"cmpw %1,%0\"; +}") + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "nonimmediate_operand" "r,g") + (match_operand:SI 1 "general_operand" "g,r")))] + "" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + if (which_alternative != 0) + { + cc_status.flags = CC_REVERSED; + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw %0,%1\"; + } + return \"cmpw %0,%1\"; + } + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw %1,%0\"; + } + return \"cmpw %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (match_operand:SI 0 "general_operand" "r"))] + "" + "* +{ +#if 0 + cc_status.flags |= CC_NO_OVERFLOW; + return \"cmpw $0,%0\"; +#endif + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw $0,%0\"; + } + return \"mtstw %0,%0\"; +}") + +(define_expand "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "") + (match_operand:HI 1 "general_operand" "")))] + "" + " +{ + extern rtx test_op0, test_op1; extern enum machine_mode test_mode; + test_op0 = copy_rtx (operands[0]); + test_op1 = copy_rtx (operands[1]); + test_mode = HImode; + DONE; +}") + +(define_expand "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" ""))] + "" + " +{ + extern rtx test_op0; extern enum machine_mode test_mode; + test_op0 = copy_rtx (operands[0]); + test_mode = HImode; + DONE; +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:HI 0 "memory_operand" "m") + (match_operand:HI 1 "memory_operand" "m")))] + "weird_memory_memory (operands[0], operands[1])" + "* +{ + rtx br_insn = NEXT_INSN (insn); + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + + weird_memory_memory (operands[0], operands[1]); + + if (swap_operands) + { + cc_status.flags = CC_REVERSED; + return \"cmph %0,%1\"; + } + + return \"cmph %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "r,m") + (match_operand:HI 1 "nonimmediate_operand" "m,r")))] + "(GET_CODE (operands[0]) != GET_CODE (operands[1]))" + "* +{ + rtx br_insn = NEXT_INSN (insn); + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + + if (which_alternative != 0) + { + cc_status.flags = CC_REVERSED; + return \"cmph %0,%1\"; + } + + return \"cmph %1,%0\"; +}") + +(define_expand "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" "")))] + "" + " +{ + extern rtx test_op0, test_op1; extern enum machine_mode test_mode; + test_op0 = copy_rtx (operands[0]); + test_op1 = copy_rtx (operands[1]); + test_mode = QImode; + DONE; +}") + +(define_expand "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" ""))] + "" + " +{ + extern rtx test_op0; extern enum machine_mode test_mode; + test_op0 = copy_rtx (operands[0]); + test_mode = QImode; + DONE; +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:QI 0 "memory_operand" "m") + (match_operand:QI 1 "memory_operand" "m")))] + "weird_memory_memory (operands[0], operands[1])" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + weird_memory_memory (operands[0], operands[1]); + + if (swap_operands) + { + cc_status.flags = CC_REVERSED; + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpb %0,%1\"; + } + return \"cmpb %0,%1\"; + } + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpb %1,%0\"; + } + return \"cmpb %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "r,m") + (match_operand:QI 1 "nonimmediate_operand" "m,r")))] + "(GET_CODE (operands[0]) != GET_CODE (operands[1]))" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + if (which_alternative != 0) + { + cc_status.flags = CC_REVERSED; + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpb %0,%1\"; + } + return \"cmpb %0,%1\"; + } + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpb %1,%0\"; + } + return \"cmpb %1,%0\"; +}") + +(define_expand "bgt" + [(set (pc) (if_then_else (gt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "blt" + [(set (pc) (if_then_else (lt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "bge" + [(set (pc) (if_then_else (ge (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "ble" + [(set (pc) (if_then_else (le (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "beq" + [(set (pc) (if_then_else (eq (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "bne" + [(set (pc) (if_then_else (ne (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "bgtu" + [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (ZERO_EXTEND);") + +(define_expand "bltu" + [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (ZERO_EXTEND);") + +(define_expand "bgeu" + [(set (pc) (if_then_else (geu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (ZERO_EXTEND);") + +(define_expand "bleu" + [(set (pc) (if_then_else (leu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (ZERO_EXTEND);") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "r") + (match_operand:DF 1 "register_operand" "r")))] + "" + "cmpd %1,%0") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "register_operand" "r") + (match_operand:SF 1 "register_operand" "r")))] + "" + "cmpf %1,%0") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "register_operand" "r"))] + "" + "mtstd %0,%0") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "register_operand" "r"))] + "" + "mtstf %0,%0") + +;______________________________________________________________________ +; +; Fixed-point Arithmetic. +;______________________________________________________________________ + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r,!r") + (plus:SI (match_operand:SI 1 "general_operand" "%0,r") + (match_operand:SI 2 "general_operand" "g,rJ")))] + "" + "* +{ + if (which_alternative == 0) + return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 32 + ? \"subw %n2,%0\" : \"addw %2,%0\"); + else + { + forget_cc_if_dependent (operands[0]); + return \"mova %a2[%1*1],%0\"; + } +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "general_operand" "g,0")))] + "" + "* return (which_alternative == 0) ? \"subw %2,%0\" : \"rsubw %1,%0\";") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "mulw %2,%0") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (div:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "general_operand" "g,0")))] + "" + "* return (which_alternative == 0) ? \"divw %2,%0\" : \"rdivw %1,%0\";") + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "udivw %2,%0") + +(define_insn "modsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mod:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "modw %2,%0") + +(define_insn "umodsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umod:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "umodw %2,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "mnegw %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "mcomw %1,%0") + +(define_insn "abssi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (abs:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "mabsw %1,%0") + +;______________________________________________________________________ +; +; Floating-point Arithmetic. +;______________________________________________________________________ + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (plus:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "register_operand" "r")))] + "" + "addd %2,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (plus:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "register_operand" "r")))] + "" + "addf %2,%0") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (minus:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "register_operand" "r")))] + "" + "subd %2,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (minus:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "register_operand" "r")))] + "" + "subf %2,%0") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (mult:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "register_operand" "r")))] + "" + "muld %2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (mult:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "register_operand" "r")))] + "" + "mulf %2,%0") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (div:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "register_operand" "r")))] + "" + "divd %2,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (div:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "register_operand" "r")))] + "" + "divf %2,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (neg:DF (match_operand:DF 1 "register_operand" "r")))] + "" + "mnegd %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (neg:SF (match_operand:SF 1 "register_operand" "r")))] + "" + "mnegf %1,%0") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (abs:DF (match_operand:DF 1 "register_operand" "r")))] + "" + "mabsd %1,%0") + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (abs:SF (match_operand:SF 1 "register_operand" "r")))] + "" + "mabsf %1,%0") + +;______________________________________________________________________ +; +; Logical and Shift Instructions. +;______________________________________________________________________ + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "%r") + (match_operand:SI 1 "general_operand" "g")))] + "" + "* +{ + cc_status.flags |= CC_NO_OVERFLOW; + return \"bitw %1,%0\"; +}") + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (and:SI (match_operand:SI 1 "general_operand" "%0,r") + (match_operand:SI 2 "general_operand" "g,K")))] + "" + "* +{ + if (which_alternative == 0) + return \"andw %2,%0\"; + + cc_status.flags = CC_NOT_NEGATIVE; + return (INTVAL (operands[2]) == 255 + ? \"movzbw %1,%0\" : \"movzhw %1,%0\"); +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (not:SI (match_operand:SI 1 "general_operand" "g")) + (match_operand:SI 2 "register_operand" "0")))] + "" + "bicw %1,%0") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "orw %2,%0") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "xorw %2,%0") + +; The arithmetic left shift instructions work strangely on pyramids. +; They fail to modify the sign bit. Therefore, use logic shifts. + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"lshlw %2,%0\", operands[2], 32); ") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"ashrw %2,%0\", operands[2], 32); ") + +(define_insn "ashrdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"ashrl %2,%0\", operands[2], 64); ") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"lshrw %2,%0\", operands[2], 32); ") + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotate:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"rotlw %2,%0\", operands[2], 32); ") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotatert:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"rotrw %2,%0\", operands[2], 32); ") + +;______________________________________________________________________ +; +; Fixed and Floating Moves. +;______________________________________________________________________ + +;; If the destination is a memory operand, indexed source operands are +;; disallowed. Big DImode constants are always loaded into a reg pair, +;; although offsetable memory addresses really could be dealt with. + +(define_insn "" + [(set (match_operand:DI 0 "memory_operand" "=m") + (match_operand:DI 1 "nonindexed_operand" "gF"))] + "(GET_CODE (operands[1]) == CONST_DOUBLE + ? ((CONST_DOUBLE_HIGH (operands[1]) == 0 + && CONST_DOUBLE_LOW (operands[1]) >= 0) + || (CONST_DOUBLE_HIGH (operands[1]) == -1 + && CONST_DOUBLE_LOW (operands[1]) < 0)) + : 1)" + "* +{ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + return \"movl %1,%0\"; +}") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=r") + (match_operand:DI 1 "general_operand" "gF"))] + "" + "* return output_move_double (operands); ") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "nonindexed_operand" "g"))] + "" + "movw %1,%0") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=r") + (match_operand:SI 1 "general_operand" "g"))] + "" + "movw %1,%0") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:HI 0 "memory_operand" "=m") + (match_operand:HI 1 "nonindexed_operand" "g"))] + "" + "* +{ + if (REG_P (operands[1])) + return \"cvtwh %1,%0\"; /* reg -> mem */ + else + return \"movh %1,%0\"; /* mem imm -> mem */ +}") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=r") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) != MEM) + return \"movw %1,%0\"; /* reg imm -> reg */ + return \"cvthw %1,%0\"; /* mem -> reg */ +}") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:QI 0 "memory_operand" "=m") + (match_operand:QI 1 "nonindexed_operand" "g"))] + "" + "* +{ + if (REG_P (operands[1])) + return \"cvtwb %1,%0\"; /* reg -> mem */ + else + return \"movb %1,%0\"; /* mem imm -> mem */ +}") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=r") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) != MEM) + return \"movw %1,%0\"; /* reg imm -> reg */ + return \"cvtbw %1,%0\"; /* mem -> reg */ +}") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:DF 0 "memory_operand" "=m") + (match_operand:DF 1 "nonindexed_operand" "g"))] + "GET_CODE (operands[1]) != CONST_DOUBLE" + "movl %1,%0") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=r") + (match_operand:DF 1 "general_operand" "gF"))] + "" + "* return output_move_double (operands); ") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:SF 0 "memory_operand" "=m") + (match_operand:SF 1 "nonindexed_operand" "g"))] + "" + "movw %1,%0") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=r") + (match_operand:SF 1 "general_operand" "g"))] + "" + "movw %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + forget_cc_if_dependent (operands[0]); + return \"mova %a1,%0\"; +}") + +;______________________________________________________________________ +; +; Conversion patterns. +;______________________________________________________________________ + +;; The trunc patterns are used only when non compile-time constants are used. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + if (REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1])) + { + cc_status = cc_prev_status; + return \"\"; + } + forget_cc_if_dependent (operands[0]); + return \"movw %1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + if (REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1])) + { + cc_status = cc_prev_status; + return \"\"; + } + forget_cc_if_dependent (operands[0]); + return \"movw %1,%0\"; +}") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=r,m") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm,r")))] + "" + "* +{ + extern int optimize; + if (optimize && REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1]) + && already_sign_extended (insn, HImode, operands[0])) + { + cc_status = cc_prev_status; + return \"\"; + } + return \"cvthw %1,%0\"; +}") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=r,m") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm,r")))] + "" + "* +{ + extern int optimize; + if (optimize && REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1]) + && already_sign_extended (insn, QImode, operands[0])) + { + cc_status = cc_prev_status; + return \"\"; + } + return \"cvtbw %1,%0\"; +}") + +; Pyramid doesn't have insns *called* "cvtbh" or "movzbh". +; But we can cvtbw/movzbw into a register, where there is no distinction +; between words and halfwords. + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "cvtbw %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + cc_status.flags = CC_NOT_NEGATIVE; + return \"movzhw %1,%0\"; +}") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + cc_status.flags = CC_NOT_NEGATIVE; + return \"movzbw %1,%0\"; +}") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + cc_status.flags = CC_NOT_NEGATIVE; + return \"movzbw %1,%0\"; +}") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=&r,m") + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "rm,r")))] + "" + "cvtfd %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=&r,m") + (float_truncate:SF (match_operand:DF 1 "nonimmediate_operand" "rm,r")))] + "" + "cvtdf %1,%0") + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=&r,m") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "rm,r")))] + "" + "cvtwf %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=&r,m") + (float:DF (match_operand:SI 1 "nonimmediate_operand" "rm,r")))] + "" + "cvtwd %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=&r,m") + (fix:SI (fix:SF (match_operand:SF 1 "nonimmediate_operand" "rm,r"))))] + "" + "cvtfw %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=&r,m") + (fix:SI (fix:DF (match_operand:DF 1 "nonimmediate_operand" "rm,r"))))] + "" + "cvtdw %1,%0") + +;______________________________________________________________________ +; +; Flow Control Patterns. +;______________________________________________________________________ + +;; Prefer "br" to "jump" for unconditional jumps, since it's faster. +;; (The assembler can manage with out-of-range branches.) + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "br %l0") + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* +{ + extern int optimize; + if (optimize) + switch (GET_CODE (operands[0])) + { + case EQ: case NE: + break; + case LT: case LE: case GE: case GT: + if (cc_prev_status.mdep == CC_VALID_FOR_UNSIGNED) + return 0; + break; + case LTU: case LEU: case GEU: case GTU: + if (cc_prev_status.mdep != CC_VALID_FOR_UNSIGNED) + return 0; + break; + } + + return \"b%N0 %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* +{ + extern int optimize; + if (optimize) + switch (GET_CODE (operands[0])) + { + case EQ: case NE: + break; + case LT: case LE: case GE: case GT: + if (cc_prev_status.mdep == CC_VALID_FOR_UNSIGNED) + return 0; + break; + case LTU: case LEU: case GEU: case GTU: + if (cc_prev_status.mdep != CC_VALID_FOR_UNSIGNED) + return 0; + break; + } + + return \"b%C0 %l1\"; +}") + +(define_insn "call" + [(call (match_operand:QI 0 "memory_operand" "m") + (match_operand:SI 1 "immediate_operand" "n"))] + "" + "call %0") + +(define_insn "call_value" + [(set (match_operand 0 "" "=r") + (call (match_operand:QI 1 "memory_operand" "m") + (match_operand:SI 2 "immediate_operand" "n")))] + ;; Operand 2 not really used on Pyramid architecture. + "" + "call %1") + +(define_insn "return" + [(return)] + "" + "* +{ + if (get_frame_size () + current_function_pretend_args_size + + current_function_args_size != 0 + || current_function_calls_alloca) + { + int dealloc_size = current_function_pretend_args_size; + if (current_function_pops_args) + dealloc_size += current_function_args_size; + operands[0] = gen_rtx (CONST_INT, VOIDmode, dealloc_size); + return \"retd %0\"; + } + else + return \"ret\"; +}") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jump (%0)") + +(define_insn "nop" + [(const_int 0)] + "" + "movw gr0,gr0 # nop") + +;______________________________________________________________________ +; +; Peep-hole Optimization Patterns. +;______________________________________________________________________ + +;; Optimize fullword move followed by a test of the moved value. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "nonimmediate_operand" "rm")) + (set (cc0) (match_operand:SI 2 "nonimmediate_operand" "rm"))] + "rtx_equal_p (operands[2], operands[0]) + || rtx_equal_p (operands[2], operands[1])" + "* + cc_status.flags |= CC_NO_OVERFLOW; + return \"mtstw %1,%0\"; +") + +;; Same for HI and QI mode move-test as well. + +(define_peephole + [(set (match_operand:HI 0 "register_operand" "=r") + (match_operand:HI 1 "nonimmediate_operand" "rm")) + (set (match_operand:SI 2 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 3 "nonimmediate_operand" "rm"))) + (set (cc0) (match_dup 2))] + "dead_or_set_p (insn, operands[2]) + && (rtx_equal_p (operands[3], operands[0]) + || rtx_equal_p (operands[3], operands[1]))" + "* + cc_status.flags |= CC_NO_OVERFLOW; + return \"cvthw %1,%0\"; +") + +(define_peephole + [(set (match_operand:QI 0 "register_operand" "=r") + (match_operand:QI 1 "nonimmediate_operand" "rm")) + (set (match_operand:SI 2 "register_operand" "=r") + (sign_extend:SI (match_operand:QI 3 "nonimmediate_operand" "rm"))) + (set (cc0) (match_dup 2))] + "dead_or_set_p (insn, operands[2]) + && (rtx_equal_p (operands[3], operands[0]) + || rtx_equal_p (operands[3], operands[1]))" + "* + cc_status.flags |= CC_NO_OVERFLOW; + return \"cvtbw %1,%0\"; +") + +;; Optimize loops with an incremented/decremented variable. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_dup 0) + (const_int -1))) + (set (cc0) + (compare (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "nonmemory_operand" "ri"))) + (set (pc) + (if_then_else (match_operator:SI 3 "signed_comparison" + [(cc0) (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc)))] + "(GET_CODE (operands[2]) == CONST_INT + ? (unsigned)INTVAL (operands[2]) + 32 >= 64 + : 1) && (rtx_equal_p (operands[0], operands[1]) + || rtx_equal_p (operands[0], operands[2]))" + "* + if (rtx_equal_p (operands[0], operands[1])) + { + output_asm_insn (\"dcmpw %2,%0\", operands); + return \"b%N3 %l4\"; + } + else + { + output_asm_insn (\"dcmpw %1,%0\", operands); + return \"b%R3 %l4\"; + } +") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_dup 0) + (const_int 1))) + (set (cc0) + (compare (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "nonmemory_operand" "ri"))) + (set (pc) + (if_then_else (match_operator:SI 3 "signed_comparison" + [(cc0) (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc)))] + "(GET_CODE (operands[2]) == CONST_INT + ? (unsigned)INTVAL (operands[2]) + 32 >= 64 + : 1) && (rtx_equal_p (operands[0], operands[1]) + || rtx_equal_p (operands[0], operands[2]))" + "* + if (rtx_equal_p (operands[0], operands[1])) + { + output_asm_insn (\"icmpw %2,%0\", operands); + return \"b%N3 %l4\"; + } + else + { + output_asm_insn (\"icmpw %1,%0\", operands); + return \"b%R3 %l4\"; + } +") + +;; Combine two word moves with consecutive operands into one long move. +;; Also combines immediate moves, if the high-order destination operand +;; is loaded with 0 or -1 and the low-order destination operand is loaded +;; with a constant with the same sign. + +(define_peephole + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "general_operand" "g")) + (set (match_operand:SI 2 "general_operand" "=g") + (match_operand:SI 3 "general_operand" "g"))] + "movdi_possible (operands)" + "* + output_asm_insn (\"# COMBINE movw %1,%0\", operands); + output_asm_insn (\"# COMBINE movw %3,%2\", operands); + movdi_possible (operands); + if (CONSTANT_P (operands[1])) + return (swap_operands) ? \"movl %3,%0\" : \"movl %1,%2\"; + + return (swap_operands) ? \"movl %1,%0\" : \"movl %3,%2\"; +") + +;; Optimize certain tests after memory stores. + +(define_peephole + [(set (match_operand 0 "memory_operand" "=m") + (match_operand 1 "register_operand" "r")) + (set (match_operand:SI 2 "register_operand" "=r") + (sign_extend:SI (match_dup 1))) + (set (cc0) + (match_dup 2))] + "dead_or_set_p (insn, operands[2])" + "* + cc_status.flags |= CC_NO_OVERFLOW; + if (GET_MODE (operands[0]) == QImode) + return \"cvtwb %1,%0\"; + else + return \"cvtwh %1,%0\"; +") + +;______________________________________________________________________ +; +; DImode Patterns. +;______________________________________________________________________ + +(define_expand "extendsidi2" + [(set (subreg:SI (match_operand:DI 0 "register_operand" "=r") 1) + (match_operand:SI 1 "general_operand" "g")) + (set (subreg:SI (match_dup 0) 0) + (subreg:SI (match_dup 0) 1)) + (set (subreg:SI (match_dup 0) 0) + (ashiftrt:SI (subreg:SI (match_dup 0) 0) + (const_int 31)))] + "" + "") + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (match_operand:DI 1 "nonmemory_operand" "%0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"addw %1,%0\", xoperands); + return \"addwc %2,%0\"; +}") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (minus:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"subw %1,%0\", xoperands); + return \"subwb %2,%0\"; +}") + +(define_insn "iordi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (ior:DI (match_operand:DI 1 "nonmemory_operand" "%0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"orw %1,%0\", xoperands); + return \"orw %2,%0\"; +}") + +(define_insn "anddi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (match_operand:DI 1 "nonmemory_operand" "%0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"andw %1,%0\", xoperands); + return \"andw %2,%0\"; +}") + +(define_insn "xordi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (xor:DI (match_operand:DI 1 "nonmemory_operand" "%0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"xorw %1,%0\", xoperands); + return \"xorw %2,%0\"; +}") + +;;- 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 ?} "){") +;;- End: +