From: Torbjorn Granlund Date: Sat, 14 Mar 1992 05:15:35 +0000 (+0000) Subject: Initial revision X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d12a2c91cad623b3d6a4154a95edbe40efd57f83;p=gcc.git Initial revision From-SVN: r474 --- diff --git a/gcc/config/gmicro/gmicro.md b/gcc/config/gmicro/gmicro.md new file mode 100644 index 00000000000..deb929ae9da --- /dev/null +++ b/gcc/config/gmicro/gmicro.md @@ -0,0 +1,2660 @@ +;;- Machine description for GNU compiler +;;- Fujitsu Gmicro Version +;;- Ported by M.Yuhara, Fujitsu Laboratories LTD. +;; +;; Copyright (C) 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. +;; Among other things, the copyright +;; notice and this notice must be preserved on all copies. + + +;; 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 definitions + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- When naming insn's (operand 0 of define_insn) be careful about using +;;- names from other targets machine descriptions. + +;;- cpp macro #define NOTICE_UPDATE_CC is essentially a no-op for the +;;- gmicro; no compares are eliminated. + +;;- The original structure of this file is m68k.md. + +;; ??? Work to be done: +;; Add patterns for ACB and SCB instructions. +;; Add define_insn patterns to recognize the insns that extend a byte +;; to a word and add it into a word, etc. + +;;- Some of these insn's are composites of several Gmicro op codes. +;;- The assembler (or final @@??) insures that the appropriate one is +;;- selected. + +(define_insn "" + [(set (match_operand:DF 0 "push_operand" "=m") + (match_operand:DF 1 "general_operand" "rmfF"))] + "" + "* +{ + if (FPU_REG_P (operands[1])) + return \"fmov.d %f1,%0\"; + return output_move_double (operands); +}") + +(define_insn "" + [(set (match_operand:DI 0 "push_operand" "=m") + (match_operand:DF 1 "general_operand" "rmF"))] + "" + "* +{ + return output_move_double (operands); +}") + +;; We don't want to allow a constant operand for test insns because +;; (set (cc0) (const_int foo)) has no mode information. Such insns will +;; be folded while optimizing anyway. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "nonimmediate_operand" "rm"))] + "" + "cmp:z.w #0,%0") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "nonimmediate_operand" "rm"))] + "" + "cmp:z.h #0,%0") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "nonimmediate_operand" "rm"))] + "" + "cmp:z.b #0,%0") + + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" "fmF"))] + "TARGET_FPU" + "* +{ + cc_status.flags = CC_IN_FPU; + return \"ftst.s %0\"; +}") + + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" "fmF"))] + "TARGET_FPU" + "* +{ + cc_status.flags = CC_IN_FPU; + return \"ftst.d %0\"; +}") + +;; compare instructions. + +;; (operand0 - operand1) +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "nonimmediate_operand" "ri,rm") + (match_operand:SI 1 "general_operand" "rm,rmi")))] + "" + "* +{ + int signed_flag = my_signed_comp (insn); + + if (which_alternative == 0) + { + cc_status.flags |= CC_REVERSED; + if (signed_flag && GET_CODE (operands[0]) == CONST_INT) + { + register rtx xfoo; + xfoo = operands[1]; + operands[0] = operands[1]; + operands[1] = xfoo; + return cmp_imm_word (INTVAL (operands[1]), operands[0]); + } + if (signed_flag) + return \"cmp.w %0,%1\"; + return \"cmpu.w %0,%1\"; + } + if (signed_flag) + { + if (GET_CODE (operands[1]) == CONST_INT) + return cmp_imm_word (INTVAL (operands[1]), operands[0]); + return \"cmp.w %1,%0\"; + } + else + return \"cmpu.w %1,%0\"; +}") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "ri,rm") + (match_operand:HI 1 "general_operand" "rm,rmi")))] + "" + "* +{ + int signed_flag = my_signed_comp (insn); + + if (which_alternative == 0) + { + cc_status.flags |= CC_REVERSED; + if (signed_flag) + return \"cmp.h %0,%1\"; + return \"cmpu.h %0,%1\"; + } + if (signed_flag) + return \"cmp.h %1,%0\"; + return \"cmpu.h %1,%0\"; +}") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "ri,rm") + (match_operand:QI 1 "general_operand" "rm,rmi")))] + "" + "* +{ + int signed_flag = my_signed_comp (insn); + + if (which_alternative == 0) + { + cc_status.flags |= CC_REVERSED; + if (signed_flag) + return \"cmp.b %0,%1\"; + return \"cmpu.b %0,%1\"; + } + if (signed_flag) + return \"cmp.b %1,%0\"; + return \"cmpu.b %1,%0\"; +}") + + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "f,mG") + (match_operand:DF 1 "general_operand" "fmG,f")))] + "TARGET_FPU" + "* +{ + cc_status.flags = CC_IN_FPU; + + if (FPU_REG_P (operands[0])) + return \"fcmp.d %f1,%f0\"; + cc_status.flags |= CC_REVERSED; + return \"fcmp.d %f0,%f1\"; +}") + + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "f,mG") + (match_operand:SF 1 "general_operand" "fmG,f")))] + "TARGET_FPU" + "* +{ + cc_status.flags = CC_IN_FPU; + if (FPU_REG_P (operands[0])) + return \"fcmp.s %f1,%0\"; + cc_status.flags |= CC_REVERSED; + return \"fcmp.s %f0,%1\"; +}") + +;; Recognizers for btst instructions. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "rm") + (const_int 1) + (match_operand:SI 1 "general_operand" "rmi")))] + "" + "btst %1.w,%0.b") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:HI 0 "nonimmediate_operand" "rm") + (const_int 1) + (match_operand:SI 1 "general_operand" "rmi")))] + "" + "btst %1.w,%0.h") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "rm") + (const_int 1) + (match_operand:SI 1 "general_operand" "rmi")))] + "" + "btst %1.w,%0.w") + +;; The following two patterns are like the previous two +;; except that they use the fact that bit-number operands (offset) +;; are automatically masked to 3 or 5 bits when the base is a register. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "r") + (const_int 1) + (and:SI + (match_operand:SI 1 "general_operand" "rmi") + (const_int 7))))] + "" + "btst %1.w,%0.b") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "r") + (const_int 1) + (and:SI + (match_operand:SI 1 "general_operand" "rmi") + (const_int 31))))] + "" + "btst %1.w,%0.w") + +; More various size-patterns are allowed for btst, but not +; included yet. M.Yuhara + + +(define_insn "" + [(set (cc0) (and:SI (sign_extend:SI (sign_extend:HI (match_operand:QI 0 "nonimmediate_operand" "rm"))) + (match_operand:SI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) < 0x100 + && exact_log2 (INTVAL (operands[1])) >= 0)" + "* +{ + register int log = exact_log2 (INTVAL (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, log); + return \"btst %1,%0.b\"; +}") + +; I can add more patterns like above. But not yet. M.Yuhara + + +; mtst is supported only by G/300. + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "%rmi") + (match_operand:SI 1 "general_operand" "rm")))] + "TARGET_G300" + "* +{ + if (GET_CODE (operands[0]) == CONST_INT) + return \"mtst.w %0,%1\"; + return \"mtst.w %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (and:HI (match_operand:HI 0 "general_operand" "%rmi") + (match_operand:HI 1 "general_operand" "rm")))] + "TARGET_G300" + "* +{ + if (GET_CODE (operands[0]) == CONST_INT) + return \"mtst.h %0,%1\"; + return \"mtst.h %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (and:QI (match_operand:QI 0 "general_operand" "%rmi") + (match_operand:QI 1 "general_operand" "rm")))] + "TARGET_G300" + "* +{ + if (GET_CODE (operands[0]) == CONST_INT) + return \"mtst.b %0,%1\"; + return \"mtst.b %1,%0\"; +}") + + + +;; move instructions + +/* added by M.Yuhara */ +;; 1.35.04 89.08.28 modification start +;; register_operand -> general_operand +;; ashift -> mult + +(define_insn "" + [(set (mem:SI (plus:SI + (match_operand:SI 0 "general_operand" "r") + (ashift:SI + (match_operand:SI 1 "general_operand" "r") + (const_int 2)))) + (match_operand:SI 2 "general_operand" "rmi"))] + "" + "* +{ + return \"mov.w %2,@(%0:b,%1*4)\"; +}") + +(define_insn "" + [(set (mem:SI (plus:SI + (ashift:SI + (match_operand:SI 0 "general_operand" "r") + (const_int 2)) + (match_operand:SI 1 "general_operand" "r"))) + (match_operand:SI 2 "general_operand" "rmi"))] + "" + "* +{ + return \"mov.w %2,@(%1:b,%0*4)\"; +}") + + +(define_insn "" + [(set (mem:SI (plus:SI + (match_operand:SI 0 "register_operand" "r") + (mult:SI + (match_operand:SI 1 "register_operand" "r") + (const_int 4)))) + (match_operand:SI 2 "general_operand" "rmi"))] + "" + "* +{ + return \"mov.w %2,@(%0:b,%1*4)\"; +}") + +(define_insn "" + [(set (mem:SI (plus:SI + (mult:SI + (match_operand:SI 0 "register_operand" "r") + (const_int 4)) + (match_operand:SI 1 "register_operand" "r"))) + (match_operand:SI 2 "general_operand" "rmi"))] + "" + "* +{ + return \"mov.w %2,@(%1:b,%0*4)\"; +}") + + +(define_insn "" + [(set (mem:SI (plus:SI + (match_operand:SI 0 "general_operand" "r") + (plus:SI + (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "i")))) + (match_operand:SI 3 "general_operand" "rmi"))] + "" + "* +{ + return \"mov.w %3,@(%c2,%0,%1)\"; +}") + +(define_insn "" + [(set (mem:SI (plus:SI + (plus:SI + (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "general_operand" "i"))) + (match_operand:SI 3 "general_operand" "rmi"))] + "" + "* +{ + return \"mov.w %3,@(%c2,%0,%1)\"; +}") + + +(define_insn "" + [(set (mem:SI (plus:SI + (match_operand:SI 0 "general_operand" "i") + (plus:SI + (match_operand:SI 1 "register_operand" "r") + (mult:SI + (match_operand:SI 2 "register_operand" "r") + (const_int 4))))) + (match_operand:SI 3 "general_operand" "rmi"))] + "" + "* +{ + return \"mov.w %3,@(%1:b,%0,%2*4)\"; +}") + +;; 89.08.28 1.35.04 modification end + +;; Should add "!" to op2 ?? + +;; General move-address-to-operand should handle these. +;; If that does not work, please figure out why. + +;(define_insn "" +; [(set (match_operand:SI 0 "push_operand" "=m") +; (plus:SI +; (match_operand:SI 1 "immediate_operand" "i") +; (match_operand:SI 2 "general_operand" "r")))] +; "" +; "mova.w @(%c1,%2),%-") + +;(define_insn "" +; [(set (match_operand:SI 0 "push_operand" "=m") +; (plus:SI +; (match_operand:SI 1 "general_operand" "r") +; (match_operand:SI 2 "immediate_operand" "i")))] +; "" +; "mova.w @(%c2,%1),%-") + + +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=m") + (minus:SI + (match_operand:SI 1 "general_operand" "r") + (match_operand:SI 2 "immediate_operand" "i")))] + "" + "mova.w @(%n2,%1),%-") + + + +;; General case of fullword move. + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=rm") + (match_operand:SI 1 "general_operand" "rmi"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + return mov_imm_word (INTVAL (operands[1]), operands[0]); + /* if (address_operand (operands[1], SImode)) + return \"mova.w %1,%0\"; */ + if (push_operand (operands[0], SImode)) + return \"mov.w %1,%-\"; + return \"mov.w %1,%0\"; +}") + +/* pushsi 89.08.10 for test M.Yuhara */ +/* +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=m") + (match_operand:SI 1 "general_operand" "rmi"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + return mov_imm_word (INTVAL (operands[1]), operands[0]); + if (push_operand (operands[0], SImode)) + return \"mov.w %1,%-\"; + return \"mov.w %1,%0\"; +}") +*/ + + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=rm") + (match_operand:HI 1 "general_operand" "rmi"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"mov.h %1,%-\"; + return \"mov.h %1,%0\"; +}") + +;; Is the operand constraint "+" necessary ???? +;; Should I check push_operand ???? + +(define_insn "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+rm")) + (match_operand:HI 1 "general_operand" "rmi"))] + "" + "mov.h %1,%0"); + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=rm") + (match_operand:QI 1 "general_operand" "rmi"))] + "" + "* +{ + if (GREG_P (operands[0])) + { + if (CONSTANT_P (operands[1])) + return \"mov:l %1,%0.w\"; + else + return \"mov:l %1.b,%0.w\"; + } + if (GREG_P (operands[1])) + return \"mov:s %1.w,%0.b\"; + return \"mov.b %1,%0\"; +}") + +(define_insn "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+rm")) + (match_operand:QI 1 "general_operand" "rmi"))] + "" + "mov.b %1,%0") + + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=f,mf,rm,fr") + (match_operand:SF 1 "general_operand" "mfF,f,rmF,fr"))] + "" + "* +{ + switch (which_alternative) + { + case 0: + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + return \"fmov.s %1,%0\"; + case 1: + return \"fmov.s %1,%0\"; + case 2: + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + return \"mov.w %1,%0\"; + case 3: + if (FPU_REG_P (operands[0])) + return \"mov.w %1,%-\\n\\tfmov.s %+,%0\"; + return \"fmov.s %1,%-\\n\\tmov.w %+,%0\"; + } +}") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=f,mf,rm,fr") + (match_operand:DF 1 "general_operand" "mfF,f,rmF,fr"))] + "" + "* +{ + switch (which_alternative) + { + case 0: + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + return \"fmov.d %1,%0\"; + case 1: + return \"fmov.d %1,%0\"; + case 2: + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + return output_move_double (operands); + case 3: + if (FPU_REG_P (operands[0])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"mov.w %1,%-\", xoperands); + output_asm_insn (\"mov.w %1,%-\", operands); + return \"fmov.d %+,%0\"; + } + else + { + output_asm_insn (\"fmov.d %f1,%-\", operands); + output_asm_insn (\"mov.w %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"mov.w %+,%0\"; + } + } +}") + + +;; movdi can apply to fp regs in some cases +;; Must check again. you can use fsti/fldi, etc. +;; FPU reg should be included ?? +;; 89.12.13 for test + +(define_insn "movdi" + ;; Let's see if it really still needs to handle fp regs, and, if so, why. + [(set (match_operand:DI 0 "general_operand" "=rm,&r,&ro") + (match_operand:DI 1 "general_operand" "rF,m,roiF"))] + "" + "* +{ + if (FPU_REG_P (operands[0])) + { + if (FPU_REG_P (operands[1])) + return \"fmov.d %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"mov.w %1,%-\", xoperands); + output_asm_insn (\"mov.w %1,%-\", operands); + return \"fmov.d %+,%0\"; + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + return \"fmov.d %f1,%0\"; + } + else if (FPU_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmov.d %f1,%-\;mov.w %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"mov.w %+,%0\"; + } + else + return \"fmov.d %f1,%0\"; + } + return output_move_double (operands); +} +") + + +;; The definition of this insn does not really explain what it does, +;; but it should suffice +;; that anything generated as this insn will be recognized as one +;; and that it won't successfully combine with anything. + +;; This is dangerous when %0 and %1 overlapped !!!!! +;; Ugly code... + +(define_insn "movstrhi" + [(set (match_operand:BLK 0 "general_operand" "=m") + (match_operand:BLK 1 "general_operand" "m")) + (use (match_operand:HI 2 "general_operand" "rmi")) + (clobber (reg:SI 0)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2))] + "" + "* +{ + int op2const; + rtx tmpx; + + if (CONSTANT_P (operands[1])) + { + fprintf (stderr, \"smov 1 const err \"); + abort (); + } + else if (GET_CODE (operands[1]) == REG) + { + fprintf (stderr, \"smov 1 reg err \"); + abort (); + } + else if (GET_CODE (operands[1]) == MEM) + { + tmpx = XEXP (operands[1], 0); + if (CONSTANT_ADDRESS_P (tmpx) || GREG_P (tmpx)) + { + operands[1] = tmpx; + output_asm_insn (\"mov.w %1,r0\", operands); + } + else + { + output_asm_insn (\"mova %1,r0\", operands); + } + } + else + { + fprintf (stderr, \"smov 1 else err \"); + abort (); + output_asm_insn (\"mova.w %p1,r0\", operands); + } + + if (CONSTANT_P (operands[0])) + { + fprintf (stderr, \"smov 0 const err \"); + abort (); + } + else if (GET_CODE (operands[0]) == REG) + { + fprintf (stderr, \"smov 0 reg err \"); + abort (); + } + else if (GET_CODE (operands[0]) == MEM) + { + tmpx = XEXP (operands[0], 0); + if (CONSTANT_ADDRESS_P (tmpx) || GREG_P (tmpx)) + { + operands[0] = tmpx; + output_asm_insn (\"mov.w %0,r1\", operands); + } + else + { + output_asm_insn (\"mova %0,r1\", operands); + } + } + else + { + fprintf (stderr, \"smov 0 else err \"); + abort (); + } + + if (GET_CODE (operands[2]) == CONST_INT) + { + op2const = INTVAL (operands[2]); + if (op2const % 4 != 0) + { + output_asm_insn (\"mov.w %2,r2\", operands); + return \"smov/n/f.b\"; + } + op2const = op2const / 4; + if (op2const <= 4) + { + if (op2const == 0) + abort (0); + if (op2const == 1) + return \"mov.w @r0,@r1\"; + output_asm_insn (\"mov.w @r0,@r1\", operands); + if (op2const == 2) + return \"mov.w @(4,r0),@(4,r1)\"; + output_asm_insn (\"mov.w @(4,r0),@(4,r1)\", operands); + if (op2const == 3) + return \"mov.w @(8,r0),@(8,r1)\"; + output_asm_insn (\"mov.w @(8,r0),@(8,r1)\", operands); + return \"mov.w @(12,r0),@(12,r1)\"; + } + + operands[2] = + gen_rtx (CONST_INT, VOIDmode, op2const); + output_asm_insn (\"mov.w %2,r2\", operands); + return \"smov/n/f.w\"; + } + else + { + fprintf (stderr, \"smov 0 else err \"); + abort (); + output_asm_insn (\"mov %2.h,r2.w\", operands); + return \"smov/n/f.b\"; + } + +}") + +;; M.Yuhara 89.08.24 +;; experiment on the built-in strcpy (__builtin_smov) +;; +;; len = 0 means unknown string length. +;; +;; mem:SI is dummy. Necessary so as not to be deleted by optimization. +;; Use of BLKmode would be better... +;; +;; +(define_insn "smovsi" + [(set (mem:SI (match_operand:SI 0 "general_operand" "=rm")) + (mem:SI (match_operand:SI 1 "general_operand" "rm"))) + (use (match_operand:SI 2 "general_operand" "i")) + (clobber (reg:SI 0)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3))] + "" + "* +{ + int len, wlen, blen, offset; + char tmpstr[128]; + rtx xoperands[1]; + + len = INTVAL (operands[2]); + output_asm_insn (\"mov.w %1,r0\\t; begin built-in strcpy\", operands); + output_asm_insn (\"mov.w %0,r1\", operands); + + if (len == 0) + { + output_asm_insn (\"mov:z.w #0,r2\", operands); + output_asm_insn (\"mov:z.w #0,r3\", operands); + return \"smov/eq/f.b\\t; end built-in strcpy\"; + } + + wlen = len / 4; + blen = len - wlen * 4; + + if (wlen > 0) + { + if (len <= 40 && !TARGET_FORCE_SMOV) + { + output_asm_insn (\"mov.w @r0,@r1\", operands); + offset = 4; + while ( (blen = len - offset) > 0) + { + if (blen >= 4) + { + sprintf (tmpstr, \"mov.w @(%d,r0),@(%d,r1)\", + offset, offset); + output_asm_insn (tmpstr, operands); + offset += 4; + } + else if (blen >= 2) + { + sprintf (tmpstr, \"mov.h @(%d,r0),@(%d,r1)\", + offset, offset); + output_asm_insn (tmpstr, operands); + offset += 2; + } + else + { + sprintf (tmpstr, \"mov.b @(%d,r0),@(%d,r1)\", + offset, offset); + output_asm_insn (tmpstr, operands); + offset++; + } + } + return \"\\t\\t; end built-in strcpy\"; + } + else + { + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, wlen); + output_asm_insn (\"mov.w %0,r2\", xoperands); + output_asm_insn (\"smov/n/f.w\", operands); + } + } + + if (blen >= 2) + { + output_asm_insn (\"mov.h @r0,@r1\", operands); + if (blen == 3) + output_asm_insn (\"mov.b @(2,r0),@(2,r1)\", operands); + } + else if (blen == 1) + { + output_asm_insn (\"mov.b @r0,@r1\", operands); + } + + return \"\\t\\t; end built-in strcpy\"; +}") + +;; truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=rm") + (truncate:QI + (match_operand:SI 1 "general_operand" "rmi")))] + "" + "mov %1.w,%0.b") +; "* +;{ +; if (GET_CODE (operands[0]) == REG) +; return \"mov.w %1,%0\"; +; if (GET_CODE (operands[1]) == MEM) +; operands[1] = adj_offsettable_operand (operands[1], 3); +; return \"mov.b %1,%0\"; +;}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=rm") + (truncate:QI + (match_operand:HI 1 "general_operand" "rmi")))] + "" + "mov %1.h,%0.b") +; "* +;{ +; if (GET_CODE (operands[0]) == REG) +; return \"mov.h %1,%0\"; +; if (GET_CODE (operands[1]) == MEM) +; operands[1] = adj_offsettable_operand (operands[1], 1); +; return \"mov.b %1,%0\"; +;}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=rm") + (truncate:HI + (match_operand:SI 1 "general_operand" "rmi")))] + "" + "mov %1.w,%0.h") +; "* +;{ +; if (GET_CODE (operands[0]) == REG) +; return \"mov.w %1,%0\"; +; if (GET_CODE (operands[1]) == MEM) +; operands[1] = adj_offsettable_operand (operands[1], 2); +; return \"mov.h %1,%0\"; +;}") + +;; zero extension instructions +;; define_expand (68k) -> define_insn (Gmicro) + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))] + "" + "movu %1.h,%0.w") + + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=rm") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "movu %1.b,%0.h") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "movu %1.b,%0.w") + + +;; sign extension instructions + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))] + "" + "mov %1.h,%0.w") + + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=rm") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "mov %1.b,%0.h") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "mov %1.b,%0.w") + + + +;; Conversions between float and double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=*frm,f") + (float_extend:DF + (match_operand:SF 1 "general_operand" "f,rmF")))] + "TARGET_FPU" + "* +{ + if (FPU_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + if (GREG_P (operands[1])) + { + output_asm_insn (\"mov.w %1,%-\", operands); + return \"fmov %+.s,%0.d\"; + } + return \"fmov %1.s,%0.d\"; + } + else + { + if (GREG_P (operands[0])) + { + output_asm_insn (\"fmov %1.s,%-.d\", operands); + output_asm_insn (\"mov.w %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"mov.w %+,%0\"; + } + return \"fmov %1.s,%0.d\"; + } +}") + + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=rfm") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "f")))] + "TARGET_FPU" + "* +{ + if (GREG_P (operands[0])) + { + output_asm_insn (\"fmov %1.d,%-.s\", operands); + return \"mov.w %+,%0\"; + } + return \"fmov %1.d,%0.s\"; +}") + +;; Conversion between fixed point and floating point. +;; Note that among the fix-to-float insns +;; the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:SI 1 "general_operand" "rmi")))] + "TARGET_FPU" + "fldi %1.w,%0.s") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:SI 1 "general_operand" "rmi")))] + "TARGET_FPU" + "fldi %1.w,%0.d") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:HI 1 "general_operand" "rmi")))] + "TARGET_FPU" + "fldi %1.h,%0.s") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:HI 1 "general_operand" "rmi")))] + "TARGET_FPU" + "fldi %1.h,%0.d") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:QI 1 "general_operand" "rmi")))] + "TARGET_FPU" + "fldi %1.b,%0.s") + +(define_insn "floatqidf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:QI 1 "general_operand" "rmi")))] + "TARGET_FPU" + "fldi %1.b,%0.d") + +;;; Convert a float to a float whose value is an integer. +;;; This is the first stage of converting it to an integer type. +; +;(define_insn "ftruncdf2" +; [(set (match_operand:DF 0 "general_operand" "=f") +; (fix:DF (match_operand:DF 1 "general_operand" "fFm")))] +; "TARGET_FPU" +; "* +;{ +; return \"fintrz.d %f1,%0\"; +;}") +; +;(define_insn "ftruncsf2" +; [(set (match_operand:SF 0 "general_operand" "=f") +; (fix:SF (match_operand:SF 1 "general_operand" "fFm")))] +; "TARGET_FPU" +; "* +;{ +; return \"fintrz.s %f1,%0\"; +;}") + +;; Convert a float to an integer. + +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "general_operand" "=rm") + (fix:QI (fix:SF (match_operand:SF 1 "general_operand" "f"))))] + "TARGET_FPU" + "fsti %1.s,%0.b") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "general_operand" "=rm") + (fix:HI (fix:SF (match_operand:SF 1 "general_operand" "f"))))] + "TARGET_FPU" + "fsti %1.s,%0.h") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "f"))))] + "TARGET_FPU" + "fsti %1.s,%0.w") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "general_operand" "=rm") + (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "f"))))] + "TARGET_FPU" + "fsti %1.d,%0.b") + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "general_operand" "=rm") + (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "f"))))] + "TARGET_FPU" + "fsti %1.d,%0.h") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "f"))))] + "TARGET_FPU" + "fsti %1.d,%0.w") + + +;;; Special add patterns +;;; 89.09.28 + +;; This should be redundant; please find out why regular addsi3 +;; fails to match this case. + +;(define_insn "" +; [(set (mem:SI (plus:SI +; (plus:SI (match_operand 0 "general_operand" "r") +; (match_operand 1 "general_operand" "r")) +; (match_operand 2 "general_operand" "i"))) +; (plus:SI +; (mem:SI (plus:SI +; (plus:SI (match_dup 0) +; (match_dup 1)) +; (match_dup 2))) +; (match_operand 3 "general_operand" "rmi")))] +; "" +; "add.w %3,@(%c2,%0,%1)") + + +;; add instructions + +;; Note that the last two alternatives are near-duplicates +;; in order to handle insns generated by reload. +;; This is needed since they are not themselves reloaded, +;; so commutativity won't apply to them. + +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=rm,!r,!r") + (plus:SI (match_operand:SI 1 "general_operand" "%0,r,ri") + (match_operand:SI 2 "general_operand" "rmi,ri,r")))] + "" + "* +{ + if (which_alternative == 0) + { + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[1] = operands[2]; + return add_imm_word (INTVAL (operands[1]), operands[0], &operands[1]); + } + else + return \"add.w %2,%0\"; + } + else + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"add.w %2,%0\"; + if (GET_CODE (operands[2]) == REG + && REGNO (operands[0]) == REGNO (operands[2])) + return \"add.w %1,%0\"; + + if (GET_CODE (operands[1]) == REG) + { + if (GET_CODE (operands[2]) == REG) + return \"mova.w @(%1,%2),%0\"; + else + return \"mova.w @(%c2,%1),%0\"; + } + else + return \"mova.w @(%c1,%2),%0\"; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=rm") + (plus:SI (match_operand:SI 1 "general_operand" "0") + (sign_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rmi"))))] + "" + "* +{ + if (CONSTANT_P (operands[2])) + { + operands[1] = operands[2]; + return add_imm_word (INTVAL (operands[1]), operands[0], &operands[1]); + } + else + return \"add %2.h,%0.w\"; +}") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (plus:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) + return \"sub.h #%n2,%0\"; + if (GREG_P (operands[0])) + { + if (CONSTANT_P (operands[2])) + return \"add:l %2,%0.w\"; + else + return \"add:l %2.h,%0.w\"; + } + return \"add.h %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+rm")) + (plus:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "rmi")))] + "" + "add.h %1,%0") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (plus:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) + return \"sub.b #%n2,%0\"; + if (GREG_P (operands[0])) + { + if (CONSTANT_P (operands[2])) + return \"add:l %2,%0.w\"; + else + return \"add:l %2.b,%0.w\"; + } + return \"add.b %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+rm")) + (plus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "rmi")))] + "" + "add.b %1,%0") + +(define_insn "adddf3" + [(set (match_operand:DF 0 "general_operand" "=f") + (plus:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_FPU" + "fadd.d %f2,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "general_operand" "=f") + (plus:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fmG")))] + "TARGET_FPU" + "fadd.s %f2,%0") + +;; subtract instructions + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=rm,!r") + (minus:SI (match_operand:SI 1 "general_operand" "0,r") + (match_operand:SI 2 "general_operand" "rmi,i")))] + "" + "* +{ + if (which_alternative == 0 + || (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1]))) + { + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[1] = operands[2]; + return sub_imm_word (INTVAL (operands[1]), + operands[0], &operands[1]); + } + else + return \"sub.w %2,%0\"; + } + else + return \"mova.w @(%n2,%1),%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=rm") + (minus:SI (match_operand:SI 1 "general_operand" "0") + (sign_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rmi"))))] + "" + "sub %2.h,%0.w") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (minus:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != 0x8000) + return \"add.h #%n2,%0\"; + return \"sub.h %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+rm")) + (minus:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "rmi")))] + "" + "sub.h %1,%0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (minus:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != 0x80) + return \"add.b #%n2,%0\"; + return \"sub.b %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+rm")) + (minus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "rmi")))] + "" + "sub.b %1,%0") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "general_operand" "=f") + (minus:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_FPU" + "fsub.d %f2,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "general_operand" "=f") + (minus:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fmG")))] + "TARGET_FPU" + "fsub.s %f2,%0") + + +;; multiply instructions + +(define_insn "mulqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (mult:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "mul.b %2,%0") + + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (mult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "mul.h %2,%0") + +;; define_insn "mulhisi3" + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (mult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmi")))] + "" + "mul.w %2,%0") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "general_operand" "=f") + (mult:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_FPU" + "fmul.d %f2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "general_operand" "=f") + (mult:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fmG")))] + "TARGET_FPU" + "fmul.s %f2,%0") + + +;; divide instructions + +(define_insn "divqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (div:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "div.b %2,%0") + +(define_insn "divhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (div:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "div.h %2,%0") + +(define_insn "divhisi3" + [(set (match_operand:HI 0 "general_operand" "=r") + (div:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "div %2.h,%0.w") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmi")))] + "" + "div.w %2,%0") + +(define_insn "udivqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (udiv:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "divu.b %2,%0") + +(define_insn "udivhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (udiv:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "divu.h %2,%0") + +(define_insn "udivhisi3" + [(set (match_operand:HI 0 "general_operand" "=r") + (udiv:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "divu %2.h,%0.w") + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmi")))] + "" + "divu.w %2,%0") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "general_operand" "=f") + (div:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_FPU" + "fdiv.d %f2,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "general_operand" "=f") + (div:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fmG")))] + "TARGET_FPU" + "fdiv.s %f2,%0") + +;; Remainder instructions. + +(define_insn "modqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (mod:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "rem.b %2,%0") + +(define_insn "modhisi3" + [(set (match_operand:HI 0 "general_operand" "=r") + (mod:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "rem.h %2,%0") + +(define_insn "umodqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (umod:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "remu.b %2,%0") + +(define_insn "umodhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (umod:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "remu.h %2,%0") + +(define_insn "umodhisi3" + [(set (match_operand:HI 0 "general_operand" "=r") + (umod:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "remu %2.h,%0.w") + +;; define_insn "divmodsi4" + +(define_insn "udivmodsi4" + [(set (match_operand:SI 0 "general_operand" "=rm") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmi"))) + (set (match_operand:SI 3 "general_operand" "=r") + (umod:SI (match_dup 1) (match_dup 2)))] + "" + "mov.w #0,%3;divx.w %2,%0,%3") + +;; logical-and instructions + +(define_insn "andsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (and:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmi")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) | 0xffff) == 0xffffffff + && (GREG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + + { + if (GET_CODE (operands[0]) != REG) + operands[0] = adj_offsettable_operand (operands[0], 2); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xffff); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + return \"and.h %2,%0\"; + } + return \"and.w %2,%0\"; +}") + +(define_insn "andhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (and:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "and.h %2,%0") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (and:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "and.b %2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (and:SI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")) + (match_operand:SI 2 "general_operand" "0")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + return \"and %1,%0.w\"; + return \"and %1.h,%0.w\"; +}") + + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (and:SI (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")) + (match_operand:SI 2 "general_operand" "0")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + return \"and %1,%0.w\"; + return \"and %1.b,%0.w\"; +}") + +;; inclusive-or instructions + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (ior:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmi")))] + "" + "* +{ + register int logval; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >> 16 == 0 + && (GREG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (GET_CODE (operands[0]) != REG) + operands[0] = adj_offsettable_operand (operands[0], 2); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + return \"or.h %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT + && (logval = exact_log2 (INTVAL (operands[2]))) >= 0 + && (GREG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (GREG_P (operands[0])) + { + if (logval < 7) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, 7 - logval); + return \"bset.b %1,%0\"; + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, 31 - logval); + return \"bset.w %1,%0\"; + } + else + { + operands[0] = adj_offsettable_operand (operands[0], 3 - (logval / 8)); + operands[1] = gen_rtx (CONST_INT, VOIDmode, 7 - (logval % 8)); + } + return \"bset.b %1,%0\"; + } + return \"or.w %2,%0\"; +}") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (ior:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "or.h %2,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (ior:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "or.b %2,%0") + +;; xor instructions + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (xor:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmi")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >> 16 == 0 + && (offsettable_memref_p (operands[0]) || GREG_P (operands[0]))) + { + if (! GREG_P (operands[0])) + operands[0] = adj_offsettable_operand (operands[0], 2); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + return \"xor.h %2,%0\"; + } + return \"xor.w %2,%0\"; +}") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (xor:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "xor.h %2,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (xor:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "xor.b %2,%0") + +;; negation instructions + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (neg:SI (match_operand:SI 1 "general_operand" "0")))] + "" + "neg.w %0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=rm") + (neg:HI (match_operand:HI 1 "general_operand" "0")))] + "" + "neg.h %0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=rm") + (neg:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "neg.b %0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "general_operand" "f") + (neg:SF (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_FPU" + "fneg.s %f1,%0") + + +(define_insn "negdf2" + [(set (match_operand:DF 0 "general_operand" "f") + (neg:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_FPU" + "fneg.d %f1,%0") + + +;; Absolute value instructions + +(define_insn "abssf2" + [(set (match_operand:SF 0 "general_operand" "f") + (abs:SF (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_FPU" + "fabs.s %f1,%0") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "general_operand" "f") + (abs:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_FPU" + "fabs.d %f1,%0") + + +;; one complement instructions + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (not:SI (match_operand:SI 1 "general_operand" "0")))] + "" + "not.w %0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=rm") + (not:HI (match_operand:HI 1 "general_operand" "0")))] + "" + "not.h %0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=rm") + (not:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "not.b %0") + +;; Optimized special case of shifting. +;; Must precede the general case. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "GET_CODE (XEXP (operands[1], 0)) != POST_INC + && GET_CODE (XEXP (operands[1], 0)) != PRE_DEC" + "mov:l %1.b,%0.w") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "GET_CODE (XEXP (operands[1], 0)) != POST_INC + && GET_CODE (XEXP (operands[1], 0)) != PRE_DEC" + "movu %1.b,%0.w") + +(define_insn "" + [(set (cc0) (compare (match_operand:QI 0 "general_operand" "i") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24))))] + "(GET_CODE (operands[0]) == CONST_INT + && (INTVAL (operands[0]) & ~0xff) == 0)" + "* +{ + cc_status.flags |= CC_REVERSED; + if (my_signed_comp (insn)) + return \"cmp.b %0,%1\"; + return \"cmpu.b %0,%1\"; +}") + +(define_insn "" + [(set (cc0) (compare (lshiftrt:SI (match_operand:SI 0 "memory_operand" "m") + (const_int 24)) + (match_operand:QI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & ~0xff) == 0)" + "* + if (my_signed_comp (insn)) + return \"cmp.b %1,%0\"; + return \"cmpu.b %1,%0\"; +") + +(define_insn "" + [(set (cc0) (compare (match_operand:QI 0 "general_operand" "i") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24))))] + "(GET_CODE (operands[0]) == CONST_INT + && ((INTVAL (operands[0]) + 0x80) & ~0xff) == 0)" + "* + cc_status.flags |= CC_REVERSED; + if (my_signed_comp (insn)) + return \"cmp.b %0,%1\"; + return \"cmpu.b %0,%1\"; +") + +(define_insn "" + [(set (cc0) (compare (ashiftrt:SI (match_operand:SI 0 "memory_operand" "m") + (const_int 24)) + (match_operand:QI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && ((INTVAL (operands[1]) + 0x80) & ~0xff) == 0)" + "* + if (my_signed_comp (insn)) + return \"cmp.b %1,%0\"; + return \"cmpu.b %1,%0\"; +") + +;; arithmetic shift instructions +;; We don't need the shift memory by 1 bit instruction + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (ashift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmi")))] + "" + "sha.w %2,%0") + +(define_insn "ashlhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (ashift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "sha.h %2,%0") + +(define_insn "ashlqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (ashift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "sha.b %2,%0") + +;; Arithmetic right shift on the Gmicro works by negating the shift count + +;; ashiftrt -> ashift +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (ashift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmi")))] + "" + "{ operands[2] = negate_rtx (SImode, operands[2]); }") + +;; ashiftrt -> ashift +(define_expand "ashrhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (ashift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + " { operands[2] = negate_rtx (HImode, operands[2]); }") + +;; ashiftrt -> ashift +(define_expand "ashrqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (ashift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + " { operands[2] = negate_rtx (QImode, operands[2]); }") + +;; logical shift instructions + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (lshift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmi")))] + "" + "shl.w %2,%0") + +(define_insn "lshlhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (lshift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "shl.h %2,%0") + +(define_insn "lshlqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (lshift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "shl.b %2,%0") + +;; lshiftrt -> lshift +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (lshift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmi")))] + "" + " { operands[2] = negate_rtx (SImode, operands[2]); }") + +;; lshiftrt -> lshift +(define_expand "lshrhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (lshift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + " { operands[2] = negate_rtx (HImode, operands[2]); }") + +;; lshiftrt -> lshift +(define_expand "lshrqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (lshift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + " { operands[2] = negate_rtx (QImode, operands[2]); }") + +;; rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (rotate:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmi")))] + "" + "rol.w %2,%0") + +(define_insn "rotlhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (rotate:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + "rol.h %2,%0") + +(define_insn "rotlqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (rotate:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + "rol.b %2,%0") + +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (rotatert:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmi")))] + "" + " { operands[2] = negate_rtx (SImode, operands[2]); }") + +(define_expand "rotrhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (rotatert:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "rmi")))] + "" + " { operands[2] = negate_rtx (HImode, operands[2]); }") + +(define_expand "rotrqi3" + [(set (match_operand:QI 0 "general_operand" "=rm") + (rotatert:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "rmi")))] + "" + " { operands[2] = negate_rtx (QImode, operands[2]); }") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +;; Should I add mode_dependent_address_p ???? + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+rm") + (match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "immediate_operand" "i")) + (match_operand:SI 3 "general_operand" "rm"))] + "TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0 + && (GET_CODE (operands[0]) != REG + || ( INTVAL (operands[1]) + INTVAL (operands[2]) == 32))" + "* +{ + if (GET_CODE (operands[3]) == MEM) + operands[3] = adj_offsettable_operand (operands[3], + (32 - INTVAL (operands[1])) / 8); + + if (GET_CODE (operands[0]) == REG) + { + if (INTVAL (operands[1]) == 8) + return \"movu %3.b,%0.w\"; + return \"movu %3.h,%0.w\"; + } + else + { + operands[0] + = adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8); + if (INTVAL (operands[1]) == 8) + return \"mov.b %3,%0\"; + return \"mov.h %3,%0\"; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=&r") + (zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "rm") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_BITFIELD + && GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0" + "* +{ + if (!REG_P (operands[1])) + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (REG_P (operands[0])) + { + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) == 8) + { /* width == 8 */ + switch (INTVAL (operands[3])) + { + case 0: + return \"mov.w %1,%0;shl.w #-24,%0\"; + break; + case 8: + return \"mov.w %1,%0;shl.w #8,%0;shl.w #-24,%0\"; + break; + case 16: + return \"mov.w %1,%0;shl.w #16,%0;shl.w #-24,%0\"; + break; + case 24: + return \"movu %1.b,%0.w\"; + break; + default: + myabort (2); + } + } + else + { + switch (INTVAL (operands[3])) + { + case 0: + return \"mov.w %1,%0;shl.w #-16,%0\"; + break; + case 16: + return \"movu %1.h,%0.w\"; + break; + default: + myabort (3); + } + } + } + else + { + if (INTVAL (operands[2]) == 8) + return \"movu %1.h,%0.w\"; + else + return \"movu %1.b,%0.w\"; + } + } + else + { /* op[0] == MEM */ + if (INTVAL (operands[2]) == 8) + return \"movu %1.b,%0.w\"; + return \"movu %1.h,%0.w\"; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "ro") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_BITFIELD + && GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0" + "* +{ + if (!REG_P (operands[1])) + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (REG_P (operands[0])) + { + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) == 8) + { /* width == 8 */ + switch (INTVAL (operands[3])) + { + case 0: + return \"mov.w %1,%0;sha.w #-24,%0\"; + break; + case 8: + return \"mov.w %1,%0;shl.w #8,%0;sha.w #-24,%0\"; + break; + case 16: + return \"mov.w %1,%0;shl.w #16,%0;sha.w #-24,%0\"; + break; + case 24: + return \"mov %1.b,%0.w\"; + break; + default: + myabort (4); + } + } + else + { + switch (INTVAL (operands[3])) + { + case 0: + return \"mov.w %1,%0;sha.w #-16,%0\"; + break; + case 16: + return \"mov %1.h,%0.w\"; + break; + default: + myabort (5); + } + } + } + else + { + if (INTVAL (operands[2]) == 8) + return \"mov %1.h,%0.w\"; + else + return \"mov %1.b,%0.w\"; + } + } + else + { /* op[0] == MEM */ + if (INTVAL (operands[2]) == 8) + return \"mov %1.b,%0.w\"; + return \"mov %1.h,%0.w\"; + } +}") + +;; Bit field instructions, general cases. +;; "o,d" constraint causes a nonoffsettable memref to match the "o" +;; so that its address is reloaded. + +;; extv dest:SI src(:QI/:SI) width:SI pos:SI +;; r.w m r.w/# rmi +;; %0 %1 %2 %3 + +(define_insn "extv" + [(set (match_operand:SI 0 "general_operand" "=r") + (sign_extract:SI (match_operand:QI 1 "nonimmediate_operand" "m") + (match_operand:SI 2 "general_operand" "ri") + (match_operand:SI 3 "general_operand" "rmi")))] + "TARGET_BITFIELD" + "bfext %3,%2,%1,%0") + + +(define_insn "extzv" + [(set (match_operand:SI 0 "general_operand" "=r") + (zero_extract:SI (match_operand:QI 1 "nonimmediate_operand" "m") + (match_operand:SI 2 "general_operand" "ri") + (match_operand:SI 3 "general_operand" "rmi")))] + "TARGET_BITFIELD" + "bfextu %3,%2,%1,%0") + +;; There is no insn on the Gmicro to NOT/SET/CLR bitfield. + + +;; insv dest(BF):QI/SI width:SI pos:SI src:SI +;; m r.w rmi r.w/i +;; 0 1 2 3 + + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+m,m") + (match_operand:SI 1 "general_operand" "r,i") + (match_operand:SI 2 "general_operand" "rmi,i")) + (match_operand:SI 3 "general_operand" "ri,ri"))] + "TARGET_BITFIELD" + "bfinsu %3,%2,%1,%0") +;;; bfins/bfinsu ???????? + +;; == == == == == == == == == == == == == + +;; Now recognize bit field insns that operate on registers +;; (or at least were intended to do so). + +;; On the Gmicro/300, +;; bitfield instructions are not applicable to registers ;-< +;; But I write the register cases, because without them the gcc +;; seems to use "and" instruction with some other instructions +;; instead of using a shift instruction. +;; It is because on many processors shift instructions are slower. +;; On the Gmicro/300 which has a barrel shifter, +;; it is faster to use a shift instruction. +;; +;; Restricts width and offset to be immediates. +;; +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "r") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_BITFIELD" + "* +{ + if (REGNO (operands[0]) != REGNO (operands[1])) + output_asm_insn (\"mov.w %1,%0\", operands); + if (INTVAL (operands[3]) != 0) + output_asm_insn (\"shl.w %3,%0\", operands); + operands[2] = gen_rtx (CONST_INT, VOIDmode, -(32 - INTVAL (operands[2]))); + return \"sha.w %3,%0\"; +}") + + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "r") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_BITFIELD" + "* +{ + if (REGNO (operands[0]) != REGNO (operands[1])) + output_asm_insn (\"mov.w %1,%0\", operands); + if (INTVAL (operands[3]) != 0) + output_asm_insn (\"shl.w %3,%0\", operands); + operands[2] = gen_rtx (CONST_INT, VOIDmode, -(32 - INTVAL (operands[2]))); + return \"shl.w %3,%0\"; +}") + + +;; There are more descriptions for m68k, but not yet for the Gmicro. +;; + +;; Basic conditional jump instructions. + + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"beq %b0\", \"fbeq %b0\", \"beq %b0\"); +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"bne %b0\", \"fbne %b0\", \"bne %b0\"); +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + OUTPUT_JUMP (\"bgt %b0\", \"fbgt %b0\", 0); +") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bgt %b0") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + OUTPUT_JUMP (\"blt %b0\", \"fblt %b0\", \"bms %b0\"); +") + +;; bms ????? +;; + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "blt %b0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + OUTPUT_JUMP (\"bge %b0\", \"fbge %b0\", \"bmc %b0\"); +") + +;; bmc ?? + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bge %b0") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "ble %b0") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "ble %b0") + +;; Negated conditional jump instructions. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + OUTPUT_JUMP (\"bne %b0\", \"fbne %b0\", \"bne %b0\"); +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + OUTPUT_JUMP (\"beq %b0\", \"fbeq %b0\", \"beq %b0\"); +}") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + OUTPUT_JUMP (\"ble %b0\", \"fbngt %b0\", 0); +") +;; fbngt ??? + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "ble %b0") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + OUTPUT_JUMP (\"bge %b0\", \"fbnlt %b0\", \"jbmc %b0\"); +") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "blt %b0") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + OUTPUT_JUMP (\"blt %b0\", \"fbnge %b0\", \"jbms %b0\"); +") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "blt %b0") +;; ???? + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + OUTPUT_JUMP (\"bgt %b0\", \"fbnle %b0\", 0); +") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bgt %b0") + +;; Unconditional and other jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "bra %b0") + +(define_insn "tablejump" + [(set (pc) + (plus:SI (pc) (match_operand:SI 0 "general_operand" "r"))) + (use (label_ref (match_operand 1 "" "")))] + "" + "jmp @(pc:b,4:4,%0)") + +;; +;; Should Add code for "ACB", "SCB". !!! ???? +;; See m68k.h (dbra) +;; + +;; Call subroutine with no return value. +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "m") + (match_operand:SI 1 "general_operand" "rmi"))] + ;; Operand 1 not really used on the Gmicro. + + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0],0)) == SYMBOL_REF) + return \"bsr %b0\"; + return \"jsr %0\"; +}") + +;; Call subroutine, returning value in operand 0 +;; (which must be a hard register). +(define_insn "call_value" + [(set (match_operand 0 "" "=rf") + (call (match_operand:QI 1 "general_operand" "m") + (match_operand:SI 2 "general_operand" "rmi")))] + ;; Operand 2 not really used on the Gmicro. + "" + "* +{ + if (GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1],0)) == SYMBOL_REF) + return \"bsr %b1\"; + return \"jsr %1\"; +}") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;; Turned off because the general move-an-address pattern handles it. +;; +;; Thus goes after the move instructions +;; because the move instructions are better (require no spilling) +;; when they can apply. +;; After add/sub now !! + +;(define_insn "pushasi" +; [(set (match_operand:SI 0 "push_operand" "=m") +; (match_operand:SI 1 "address_operand" "p"))] +; "" +; "* +;{ +; if (GET_CODE (operands[1]) == CONST_INT) +; return push_imm_word (INTVAL (operands[1]), operands[0]); +; if (CONSTANT_P (operands[1])) +; return \"mov.w %1,%-\"; +; if (GET_CODE (operands[1]) == REG) +; return \"mov.w %1,%-\"; +; else if (GET_CODE (operands[1]) == MEM) +; { +; return \"mov.w %1,%-\"; +; } +; else +; return \"mova.w %p1,%-\"; +;}") + +;; This should not be used unless the add/sub insns can't be. + +/* mova.[whq] 89.08.11 for test M.Yuhara */ +;(define_insn "" +; [(set (match_operand:SI 0 "general_operand" "=rm") +; (address (match_operand:SI 1 "address_operand" "p")))] +; "" +; "* +;{ +; if (GET_CODE (operands[1]) == CONST_INT) +; return mov_imm_word (INTVAL (operands[1]), operands[0]); +; if (CONSTANT_P (operands[1])) +; return \"mov.w %1,%0\"; +; if (GET_CODE (operands[1]) == REG) +; return \"mov.w %1,%0\"; +; else if (GET_CODE (operands[1]) == MEM) { +; operands[1] = XEXP (operands[1],0); +; return \"mov.w %1,%0\"; +; } +; else +; return \"mova.w %p1,%0\"; +;}") + + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=rm") + (address (match_operand:HI 1 "address_operand" "")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + return mov_imm_word (INTVAL (operands[1]), operands[0]); + if (CONSTANT_P (operands[1])) + return \"mov.w %1,%0\"; + if (GET_CODE (operands[1]) == REG) + return \"mov.w %1,%0\"; + else if (GET_CODE (operands[1]) == MEM) + { + operands[1] = XEXP (operands[1],0); + return \"mov.w %1,%0\"; /* OK ? */ + } + else + return \"mova.w %p1,%0\"; +}") + +;(define_insn "" +; [(set (match_operand:SI 0 "general_operand" "=rm") +; (match_operand:QI 1 "address_operand" "p"))] +; "" +; "* +;{ +; if (push_operand (operands[0], SImode)) +; return \"mova %1,%-\"; +; return \"mova %1,%0\"; +;}") + +;(define_insn "" +; [(set (match_operand:SI 0 "general_operand" "=rm") +; (match_operand:QI 1 "address_operand" "p"))] +; "" +; "* +;{ +; if (CONSTANT_P (operands[1])) +; return \"mov.w %1,%0\"; +; else if (GET_CODE (operands[1]) == REG) +; return \"mov.w %1,%0\"; +; else if (GET_CODE (operands[1]) == MEM) +; { +; operands[1] = XEXP (operands[1],0); +; return \"mov.w %1,%0 ; OK?\"; +; } +; else if (GET_CODE (operands[0]) == REG +; && GET_CODE (operands[1]) == PLUS) +; { +; rtx xreg, xdisp; +; +; if (GET_CODE (XEXP (operands[1], 0)) == REG +; && REGNO (XEXP (operands[1], 0)) == REGNO (operands[0])) +; { +; xreg = XEXP (operands[1], 0); +; xdisp = XEXP (operands[1],1); +; } +; else +; { +; xreg = XEXP (operands[1], 1); +; xdisp = XEXP (operands[1],0); +; } +; +; if (GET_CODE (xreg) == REG +; && REGNO (xreg) == REGNO (operands[0]) +; && (CONSTANT_P (xdisp) || GET_CODE (xdisp) == REG)) +; { +; operands[1] = xdisp; +; if (CONSTANT_P (xdisp)) +; return add_imm_word (INTVAL (xdisp), xreg, &operands[1]); +; else +; return \"add.w %1,%0\"; +; } +; } +; return \"mova.w %p1,%0\"; +;}") + +;; This is the first machine-dependent peephole optimization. +;; It is useful when a floating value is returned from a function call +;; and then is moved into an FP register. +;; But it is mainly intended to test the support for these optimizations. + +(define_peephole + [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4))) + (set (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "register_operand" "r"))] + "FPU_REG_P (operands[0]) && ! FPU_REG_P (operands[1])" + "* +{ + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"mov.w %1,@sp\", xoperands); + output_asm_insn (\"mov.w %1,%-\", operands); + return \"fmov.d %+,%0\"; +} +") + + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- comment-start-skip: ";+- *" +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: