diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /gcc/config/mcore/mcore.md | |
download | cbb-gcc-4.6.4-upstream.tar.bz2 cbb-gcc-4.6.4-upstream.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'gcc/config/mcore/mcore.md')
-rw-r--r-- | gcc/config/mcore/mcore.md | 3085 |
1 files changed, 3085 insertions, 0 deletions
diff --git a/gcc/config/mcore/mcore.md b/gcc/config/mcore/mcore.md new file mode 100644 index 000000000..c56a0c6ae --- /dev/null +++ b/gcc/config/mcore/mcore.md @@ -0,0 +1,3085 @@ +;; Machine description the Motorola MCore +;; Copyright (C) 1993, 1999, 2000, 2004, 2005, 2007, 2009, 2010 +;; Free Software Foundation, Inc. +;; Contributed by Motorola. + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; <http://www.gnu.org/licenses/>. + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + + + +;; ------------------------------------------------------------------------- +;; Attributes +;; ------------------------------------------------------------------------- + +; Target CPU. + +(define_attr "type" "brcond,branch,jmp,load,store,move,alu,shift" + (const_string "alu")) + +;; If a branch destination is within -2048..2047 bytes away from the +;; instruction it can be 2 bytes long. All other conditional branches +;; are 10 bytes long, and all other unconditional branches are 8 bytes. +;; +;; the assembler handles the long-branch span case for us if we use +;; the "jb*" mnemonics for jumps/branches. This pushes the span +;; calculations and the literal table placement into the assembler, +;; where their interactions can be managed in a single place. + +;; All MCORE instructions are two bytes long. + +(define_attr "length" "" (const_int 2)) + +;; Scheduling. We only model a simple load latency. +(define_insn_reservation "any_insn" 1 + (eq_attr "type" "!load") + "nothing") +(define_insn_reservation "memory" 2 + (eq_attr "type" "load") + "nothing") + +(include "predicates.md") +(include "constraints.md") + +;; ------------------------------------------------------------------------- +;; Test and bit test +;; ------------------------------------------------------------------------- + +(define_insn "" + [(set (reg:SI 17) + (sign_extract:SI (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (const_int 1) + (match_operand:SI 1 "mcore_literal_K_operand" "K")))] + "" + "btsti %0,%1" + [(set_attr "type" "shift")]) + +(define_insn "" + [(set (reg:SI 17) + (zero_extract:SI (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (const_int 1) + (match_operand:SI 1 "mcore_literal_K_operand" "K")))] + "" + "btsti %0,%1" + [(set_attr "type" "shift")]) + +;;; This is created by combine. +(define_insn "" + [(set (reg:CC 17) + (ne:CC (zero_extract:SI (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (const_int 1) + (match_operand:SI 1 "mcore_literal_K_operand" "K")) + (const_int 0)))] + "" + "btsti %0,%1" + [(set_attr "type" "shift")]) + + +;; Created by combine from conditional patterns below (see sextb/btsti rx,31) + +(define_insn "" + [(set (reg:CC 17) + (ne:CC (lshiftrt:SI (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (const_int 7)) + (const_int 0)))] + "GET_CODE(operands[0]) == SUBREG && + GET_MODE(SUBREG_REG(operands[0])) == QImode" + "btsti %0,7" + [(set_attr "type" "shift")]) + +(define_insn "" + [(set (reg:CC 17) + (ne:CC (lshiftrt:SI (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (const_int 15)) + (const_int 0)))] + "GET_CODE(operands[0]) == SUBREG && + GET_MODE(SUBREG_REG(operands[0])) == HImode" + "btsti %0,15" + [(set_attr "type" "shift")]) + +(define_split + [(set (pc) + (if_then_else (ne (eq:CC (zero_extract:SI + (match_operand:SI 0 "mcore_arith_reg_operand" "") + (const_int 1) + (match_operand:SI 1 "mcore_literal_K_operand" "")) + (const_int 0)) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + [(set (reg:CC 17) + (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))) + (set (pc) (if_then_else (eq (reg:CC 17) (const_int 0)) + (label_ref (match_dup 2)) + (pc)))] + "") + +(define_split + [(set (pc) + (if_then_else (eq (ne:CC (zero_extract:SI + (match_operand:SI 0 "mcore_arith_reg_operand" "") + (const_int 1) + (match_operand:SI 1 "mcore_literal_K_operand" "")) + (const_int 0)) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + [(set (reg:CC 17) + (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))) + (set (pc) (if_then_else (eq (reg:CC 17) (const_int 0)) + (label_ref (match_dup 2)) + (pc)))] + "") + +;; XXX - disabled by nickc because it fails on libiberty/fnmatch.c +;; +;; ; Experimental - relax immediates for and, andn, or, and tst to allow +;; ; any immediate value (or an immediate at all -- or, andn, & tst). +;; ; This is done to allow bit field masks to fold together in combine. +;; ; The reload phase will force the immediate into a register at the +;; ; very end. This helps in some cases, but hurts in others: we'd +;; ; really like to cse these immediates. However, there is a phase +;; ; ordering problem here. cse picks up individual masks and cse's +;; ; those, but not folded masks (cse happens before combine). It's +;; ; not clear what the best solution is because we really want cse +;; ; before combine (leaving the bit field masks alone). To pick up +;; ; relaxed immediates use -mrelax-immediates. It might take some +;; ; experimenting to see which does better (i.e. regular imms vs. +;; ; arbitrary imms) for a particular code. BRC +;; +;; (define_insn "" +;; [(set (reg:CC 17) +;; (ne:CC (and:SI (match_operand:SI 0 "mcore_arith_reg_operand" "r") +;; (match_operand:SI 1 "mcore_arith_any_imm_operand" "rI")) +;; (const_int 0)))] +;; "TARGET_RELAX_IMM" +;; "tst %0,%1") +;; +;; (define_insn "" +;; [(set (reg:CC 17) +;; (ne:CC (and:SI (match_operand:SI 0 "mcore_arith_reg_operand" "r") +;; (match_operand:SI 1 "mcore_arith_M_operand" "r")) +;; (const_int 0)))] +;; "!TARGET_RELAX_IMM" +;; "tst %0,%1") + +(define_insn "" + [(set (reg:CC 17) + (ne:CC (and:SI (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (match_operand:SI 1 "mcore_arith_M_operand" "r")) + (const_int 0)))] + "" + "tst %0,%1") + + +(define_split + [(parallel[ + (set (reg:CC 17) + (ne:CC (ne:SI (leu:CC (match_operand:SI 0 "mcore_arith_reg_operand" "") + (match_operand:SI 1 "mcore_arith_reg_operand" "")) + (const_int 0)) + (const_int 0))) + (clobber (match_operand:CC 2 "mcore_arith_reg_operand" ""))])] + "" + [(set (reg:CC 17) (ne:SI (match_dup 0) (const_int 0))) + (set (reg:CC 17) (leu:CC (match_dup 0) (match_dup 1)))]) + +;; ------------------------------------------------------------------------- +;; SImode signed integer comparisons +;; ------------------------------------------------------------------------- + +(define_insn "decne_t" + [(set (reg:CC 17) (ne:CC (plus:SI (match_operand:SI 0 "mcore_arith_reg_operand" "+r") + (const_int -1)) + (const_int 0))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "decne %0") + +;; The combiner seems to prefer the following to the former. +;; +(define_insn "" + [(set (reg:CC 17) (ne:CC (match_operand:SI 0 "mcore_arith_reg_operand" "+r") + (const_int 1))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "decne %0") + +(define_insn "cmpnesi_t" + [(set (reg:CC 17) (ne:CC (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (match_operand:SI 1 "mcore_arith_reg_operand" "r")))] + "" + "cmpne %0,%1") + +(define_insn "cmpneisi_t" + [(set (reg:CC 17) (ne:CC (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (match_operand:SI 1 "mcore_arith_K_operand" "K")))] + "" + "cmpnei %0,%1") + +(define_insn "cmpgtsi_t" + [(set (reg:CC 17) (gt:CC (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (match_operand:SI 1 "mcore_arith_reg_operand" "r")))] + "" + "cmplt %1,%0") + +(define_insn "" + [(set (reg:CC 17) (gt:CC (plus:SI + (match_operand:SI 0 "mcore_arith_reg_operand" "+r") + (const_int -1)) + (const_int 0))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1)))] + "" + "decgt %0") + +(define_insn "cmpltsi_t" + [(set (reg:CC 17) (lt:CC (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (match_operand:SI 1 "mcore_arith_reg_operand" "r")))] + "" + "cmplt %0,%1") + +; cmplti is 1-32 +(define_insn "cmpltisi_t" + [(set (reg:CC 17) (lt:CC (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (match_operand:SI 1 "mcore_arith_J_operand" "J")))] + "" + "cmplti %0,%1") + +; covers cmplti x,0 +(define_insn "" + [(set (reg:CC 17) (lt:CC (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (const_int 0)))] + "" + "btsti %0,31") + +(define_insn "" + [(set (reg:CC 17) (lt:CC (plus:SI + (match_operand:SI 0 "mcore_arith_reg_operand" "+r") + (const_int -1)) + (const_int 0))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1)))] + "" + "declt %0") + +;; ------------------------------------------------------------------------- +;; SImode unsigned integer comparisons +;; ------------------------------------------------------------------------- + +(define_insn "cmpgeusi_t" + [(set (reg:CC 17) (geu:CC (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (match_operand:SI 1 "mcore_arith_reg_operand" "r")))] + "" + "cmphs %0,%1") + +(define_insn "cmpgeusi_0" + [(set (reg:CC 17) (geu:CC (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (const_int 0)))] + "" + "cmpnei %0, 0") + +(define_insn "cmpleusi_t" + [(set (reg:CC 17) (leu:CC (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (match_operand:SI 1 "mcore_arith_reg_operand" "r")))] + "" + "cmphs %1,%0") + +;; ------------------------------------------------------------------------- +;; Logical operations +;; ------------------------------------------------------------------------- + +;; Logical AND clearing a single bit. andsi3 knows that we have this +;; pattern and allows the constant literal pass through. +;; + +;; RBE 2/97: don't need this pattern any longer... +;; RBE: I don't think we need both "S" and exact_log2() clauses. +;;(define_insn "" +;; [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") +;; (and:SI (match_operand:SI 1 "mcore_arith_reg_operand" "%0") +;; (match_operand:SI 2 "const_int_operand" "S")))] +;; "mcore_arith_S_operand (operands[2])" +;; "bclri %0,%Q2") +;; + +(define_insn "andnsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (and:SI (not:SI (match_operand:SI 1 "mcore_arith_reg_operand" "r")) + (match_operand:SI 2 "mcore_arith_reg_operand" "0")))] + "" + "andn %0,%1") + +(define_expand "andsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (and:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0 + && ! mcore_arith_S_operand (operands[2])) + { + HOST_WIDE_INT not_value = ~ INTVAL (operands[2]); + + if ( CONST_OK_FOR_I (not_value) + || CONST_OK_FOR_M (not_value) + || CONST_OK_FOR_N (not_value)) + { + operands[2] = copy_to_mode_reg (SImode, GEN_INT (not_value)); + emit_insn (gen_andnsi3 (operands[0], operands[2], operands[1])); + DONE; + } + } + + if (! mcore_arith_K_S_operand (operands[2], SImode)) + operands[2] = copy_to_mode_reg (SImode, operands[2]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (and:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0,0,r,0") + (match_operand:SI 2 "mcore_arith_any_imm_operand" "r,K,0,S")))] + "TARGET_RELAX_IMM" + "* +{ + switch (which_alternative) + { + case 0: return \"and %0,%2\"; + case 1: return \"andi %0,%2\"; + case 2: return \"and %0,%1\"; + /* case -1: return \"bclri %0,%Q2\"; will not happen */ + case 3: return mcore_output_bclri (operands[0], INTVAL (operands[2])); + default: gcc_unreachable (); + } +}") + +;; This was the old "S" which was "!(2^n)" */ +;; case -1: return \"bclri %0,%Q2\"; will not happen */ + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (and:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0,0,r,0") + (match_operand:SI 2 "mcore_arith_K_S_operand" "r,K,0,S")))] + "!TARGET_RELAX_IMM" + "* +{ + switch (which_alternative) + { + case 0: return \"and %0,%2\"; + case 1: return \"andi %0,%2\"; + case 2: return \"and %0,%1\"; + case 3: return mcore_output_bclri (operands[0], INTVAL (operands[2])); + default: gcc_unreachable (); + } +}") + +;(define_insn "iorsi3" +; [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") +; (ior:SI (match_operand:SI 1 "mcore_arith_reg_operand" "%0") +; (match_operand:SI 2 "mcore_arith_reg_operand" "r")))] +; "" +; "or %0,%2") + +; need an expand to resolve ambiguity betw. the two iors below. +(define_expand "iorsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (ior:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " +{ + if (! mcore_arith_M_operand (operands[2], SImode)) + operands[2] = copy_to_mode_reg (SImode, operands[2]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r") + (ior:SI (match_operand:SI 1 "mcore_arith_reg_operand" "%0,0,0") + (match_operand:SI 2 "mcore_arith_any_imm_operand" "r,M,T")))] + "TARGET_RELAX_IMM" + "* +{ + switch (which_alternative) + { + case 0: return \"or %0,%2\"; + case 1: return \"bseti %0,%P2\"; + case 2: return mcore_output_bseti (operands[0], INTVAL (operands[2])); + default: gcc_unreachable (); + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r") + (ior:SI (match_operand:SI 1 "mcore_arith_reg_operand" "%0,0,0") + (match_operand:SI 2 "mcore_arith_M_operand" "r,M,T")))] + "!TARGET_RELAX_IMM" + "* +{ + switch (which_alternative) + { + case 0: return \"or %0,%2\"; + case 1: return \"bseti %0,%P2\"; + case 2: return mcore_output_bseti (operands[0], INTVAL (operands[2])); + default: gcc_unreachable (); + } +}") + +;(define_insn "" +; [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") +; (ior:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0") +; (match_operand:SI 2 "const_int_operand" "M")))] +; "exact_log2 (INTVAL (operands[2])) >= 0" +; "bseti %0,%P2") + +;(define_insn "" +; [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") +; (ior:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0") +; (match_operand:SI 2 "const_int_operand" "i")))] +; "mcore_num_ones (INTVAL (operands[2])) < 3" +; "* return mcore_output_bseti (operands[0], INTVAL (operands[2]));") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (xor:SI (match_operand:SI 1 "mcore_arith_reg_operand" "%0") + (match_operand:SI 2 "mcore_arith_reg_operand" "r")))] + "" + "xor %0,%2") + +; these patterns give better code then gcc invents if +; left to its own devices + +(define_insn "anddi3" + [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=r") + (and:DI (match_operand:DI 1 "mcore_arith_reg_operand" "%0") + (match_operand:DI 2 "mcore_arith_reg_operand" "r")))] + "" + "and %0,%2\;and %R0,%R2" + [(set_attr "length" "4")]) + +(define_insn "iordi3" + [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=r") + (ior:DI (match_operand:DI 1 "mcore_arith_reg_operand" "%0") + (match_operand:DI 2 "mcore_arith_reg_operand" "r")))] + "" + "or %0,%2\;or %R0,%R2" + [(set_attr "length" "4")]) + +(define_insn "xordi3" + [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=r") + (xor:DI (match_operand:DI 1 "mcore_arith_reg_operand" "%0") + (match_operand:DI 2 "mcore_arith_reg_operand" "r")))] + "" + "xor %0,%2\;xor %R0,%R2" + [(set_attr "length" "4")]) + +;; ------------------------------------------------------------------------- +;; Shifts and rotates +;; ------------------------------------------------------------------------- + +;; Only allow these if the shift count is a convenient constant. +(define_expand "rotlsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (rotate:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + "if (! mcore_literal_K_operand (operands[2], SImode)) + FAIL; + ") + +;; We can only do constant rotates, which is what this pattern provides. +;; The combiner will put it together for us when we do: +;; (x << N) | (x >> (32 - N)) +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (rotate:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0") + (match_operand:SI 2 "mcore_literal_K_operand" "K")))] + "" + "rotli %0,%2" + [(set_attr "type" "shift")]) + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r") + (ashift:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0,0") + (match_operand:SI 2 "mcore_arith_K_operand_not_0" "r,K")))] + "" + "@ + lsl %0,%2 + lsli %0,%2" + [(set_attr "type" "shift")]) + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (ashift:SI (const_int 1) + (match_operand:SI 1 "mcore_arith_reg_operand" "r")))] + "" + "bgenr %0,%1" + [(set_attr "type" "shift")]) + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r") + (ashiftrt:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0,0") + (match_operand:SI 2 "mcore_arith_K_operand_not_0" "r,K")))] + "" + "@ + asr %0,%2 + asri %0,%2" + [(set_attr "type" "shift")]) + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r") + (lshiftrt:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0,0") + (match_operand:SI 2 "mcore_arith_K_operand_not_0" "r,K")))] + "" + "@ + lsr %0,%2 + lsri %0,%2" + [(set_attr "type" "shift")]) + +;(define_expand "ashldi3" +; [(parallel[(set (match_operand:DI 0 "mcore_arith_reg_operand" "") +; (ashift:DI (match_operand:DI 1 "mcore_arith_reg_operand" "") +; (match_operand:DI 2 "immediate_operand" ""))) +; +; (clobber (reg:CC 17))])] +; +; "" +; " +;{ +; if (GET_CODE (operands[2]) != CONST_INT +; || INTVAL (operands[2]) != 1) +; FAIL; +;}") +; +;(define_insn "" +; [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=r") +; (ashift:DI (match_operand:DI 1 "mcore_arith_reg_operand" "0") +; (const_int 1))) +; (clobber (reg:CC 17))] +; "" +; "lsli %R0,0\;rotli %0,0" +; [(set_attr "length" "4") (set_attr "type" "shift")]) + +;; ------------------------------------------------------------------------- +;; Index instructions +;; ------------------------------------------------------------------------- +;; The second of each set of patterns is borrowed from the alpha.md file. +;; These variants of the above insns can occur if the second operand +;; is the frame pointer. This is a kludge, but there doesn't +;; seem to be a way around it. Only recognize them while reloading. + +;; We must use reload_operand for some operands in case frame pointer +;; elimination put a MEM with invalid address there. Otherwise, +;; the result of the substitution will not match this pattern, and reload +;; will not be able to correctly fix the result. + +;; indexing longlongs or doubles (8 bytes) + +(define_insn "indexdi_t" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (plus:SI (mult:SI (match_operand:SI 1 "mcore_arith_reg_operand" "r") + (const_int 8)) + (match_operand:SI 2 "mcore_arith_reg_operand" "0")))] + "" + "* + if (! mcore_is_same_reg (operands[1], operands[2])) + { + output_asm_insn (\"ixw\\t%0,%1\", operands); + output_asm_insn (\"ixw\\t%0,%1\", operands); + } + else + { + output_asm_insn (\"ixh\\t%0,%1\", operands); + output_asm_insn (\"ixh\\t%0,%1\", operands); + } + return \"\"; + " +;; if operands[1] == operands[2], the first option above is wrong! -- dac +;; was this... -- dac +;; ixw %0,%1\;ixw %0,%1" + + [(set_attr "length" "4")]) + +(define_insn "" + [(set (match_operand:SI 0 "mcore_reload_operand" "=r,r,r") + (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "mcore_reload_operand" "r,r,r") + (const_int 8)) + (match_operand:SI 2 "mcore_arith_reg_operand" "0,0,0")) + (match_operand:SI 3 "mcore_addsub_operand" "r,J,L")))] + "reload_in_progress" + "@ + ixw %0,%1\;ixw %0,%1\;addu %0,%3 + ixw %0,%1\;ixw %0,%1\;addi %0,%3 + ixw %0,%1\;ixw %0,%1\;subi %0,%M3" + [(set_attr "length" "6")]) + +;; indexing longs (4 bytes) + +(define_insn "indexsi_t" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (plus:SI (mult:SI (match_operand:SI 1 "mcore_arith_reg_operand" "r") + (const_int 4)) + (match_operand:SI 2 "mcore_arith_reg_operand" "0")))] + "" + "ixw %0,%1") + +(define_insn "" + [(set (match_operand:SI 0 "mcore_reload_operand" "=r,r,r") + (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "mcore_reload_operand" "r,r,r") + (const_int 4)) + (match_operand:SI 2 "mcore_arith_reg_operand" "0,0,0")) + (match_operand:SI 3 "mcore_addsub_operand" "r,J,L")))] + "reload_in_progress" + "@ + ixw %0,%1\;addu %0,%3 + ixw %0,%1\;addi %0,%3 + ixw %0,%1\;subi %0,%M3" + [(set_attr "length" "4")]) + +;; indexing shorts (2 bytes) + +(define_insn "indexhi_t" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (plus:SI (mult:SI (match_operand:SI 1 "mcore_arith_reg_operand" "r") + (const_int 2)) + (match_operand:SI 2 "mcore_arith_reg_operand" "0")))] + "" + "ixh %0,%1") + +(define_insn "" + [(set (match_operand:SI 0 "mcore_reload_operand" "=r,r,r") + (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "mcore_reload_operand" "r,r,r") + (const_int 2)) + (match_operand:SI 2 "mcore_arith_reg_operand" "0,0,0")) + (match_operand:SI 3 "mcore_addsub_operand" "r,J,L")))] + "reload_in_progress" + "@ + ixh %0,%1\;addu %0,%3 + ixh %0,%1\;addi %0,%3 + ixh %0,%1\;subi %0,%M3" + [(set_attr "length" "4")]) + +;; +;; Other sizes may be handy for indexing. +;; the tradeoffs to consider when adding these are +;; code size, execution time [vs. mul it is easy to win], +;; and register pressure -- these patterns don't use an extra +;; register to build the offset from the base +;; and whether the compiler will not come up with some other idiom. +;; + +;; ------------------------------------------------------------------------- +;; Addition, Subtraction instructions +;; ------------------------------------------------------------------------- + +(define_expand "addsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (plus:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " +{ + /* If this is an add to the frame pointer, then accept it as is so + that we can later fold in the fp/sp offset from frame pointer + elimination. */ + if (flag_omit_frame_pointer + && GET_CODE (operands[1]) == REG + && (REGNO (operands[1]) == VIRTUAL_STACK_VARS_REGNUM + || REGNO (operands[1]) == FRAME_POINTER_REGNUM)) + { + emit_insn (gen_addsi3_fp (operands[0], operands[1], operands[2])); + DONE; + } + + /* Convert adds to subtracts if this makes loading the constant cheaper. + But only if we are allowed to generate new pseudos. */ + if (! (reload_in_progress || reload_completed) + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < -32) + { + HOST_WIDE_INT neg_value = - INTVAL (operands[2]); + + if ( CONST_OK_FOR_I (neg_value) + || CONST_OK_FOR_M (neg_value) + || CONST_OK_FOR_N (neg_value)) + { + operands[2] = copy_to_mode_reg (SImode, GEN_INT (neg_value)); + emit_insn (gen_subsi3 (operands[0], operands[1], operands[2])); + DONE; + } + } + + if (! mcore_addsub_operand (operands[2], SImode)) + operands[2] = copy_to_mode_reg (SImode, operands[2]); +}") + +;; RBE: for some constants which are not in the range which allows +;; us to do a single operation, we will try a paired addi/addi instead +;; of a movi/addi. This relieves some register pressure at the expense +;; of giving away some potential constant reuse. +;; +;; RBE 6/17/97: this didn't buy us anything, but I keep the pattern +;; for later reference +;; +;; (define_insn "addsi3_i2" +;; [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") +;; (plus:SI (match_operand:SI 1 "mcore_arith_reg_operand" "%0") +;; (match_operand:SI 2 "const_int_operand" "g")))] +;; "GET_CODE(operands[2]) == CONST_INT +;; && ((INTVAL (operands[2]) > 32 && INTVAL(operands[2]) <= 64) +;; || (INTVAL (operands[2]) < -32 && INTVAL(operands[2]) >= -64))" +;; "* +;; { +;; HOST_WIDE_INT n = INTVAL(operands[2]); +;; if (n > 0) +;; { +;; operands[2] = GEN_INT(n - 32); +;; return \"addi\\t%0,32\;addi\\t%0,%2\"; +;; } +;; else +;; { +;; n = (-n); +;; operands[2] = GEN_INT(n - 32); +;; return \"subi\\t%0,32\;subi\\t%0,%2\"; +;; } +;; }" +;; [(set_attr "length" "4")]) + +(define_insn "addsi3_i" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r") + (plus:SI (match_operand:SI 1 "mcore_arith_reg_operand" "%0,0,0") + (match_operand:SI 2 "mcore_addsub_operand" "r,J,L")))] + "" + "@ + addu %0,%2 + addi %0,%2 + subi %0,%M2") + +;; This exists so that address computations based on the frame pointer +;; can be folded in when frame pointer elimination occurs. Ordinarily +;; this would be bad because it allows insns which would require reloading, +;; but without it, we get multiple adds where one would do. + +(define_insn "addsi3_fp" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r") + (plus:SI (match_operand:SI 1 "mcore_arith_reg_operand" "%0,0,0") + (match_operand:SI 2 "immediate_operand" "r,J,L")))] + "flag_omit_frame_pointer + && (reload_in_progress || reload_completed || REGNO (operands[1]) == FRAME_POINTER_REGNUM)" + "@ + addu %0,%2 + addi %0,%2 + subi %0,%M2") + +;; RBE: for some constants which are not in the range which allows +;; us to do a single operation, we will try a paired addi/addi instead +;; of a movi/addi. This relieves some register pressure at the expense +;; of giving away some potential constant reuse. +;; +;; RBE 6/17/97: this didn't buy us anything, but I keep the pattern +;; for later reference +;; +;; (define_insn "subsi3_i2" +;; [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") +;; (plus:SI (match_operand:SI 1 "mcore_arith_reg_operand" "%0") +;; (match_operand:SI 2 "const_int_operand" "g")))] +;; "TARGET_RBETEST && GET_CODE(operands[2]) == CONST_INT +;; && ((INTVAL (operands[2]) > 32 && INTVAL(operands[2]) <= 64) +;; || (INTVAL (operands[2]) < -32 && INTVAL(operands[2]) >= -64))" +;; "* +;; { +;; HOST_WIDE_INT n = INTVAL(operands[2]); +;; if ( n > 0) +;; { +;; operands[2] = GEN_INT( n - 32); +;; return \"subi\\t%0,32\;subi\\t%0,%2\"; +;; } +;; else +;; { +;; n = (-n); +;; operands[2] = GEN_INT(n - 32); +;; return \"addi\\t%0,32\;addi\\t%0,%2\"; +;; } +;; }" +;; [(set_attr "length" "4")]) + +;(define_insn "subsi3" +; [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") +; (minus:SI (match_operand:SI 1 "mcore_arith_K_operand" "0,0,r,K") +; (match_operand:SI 2 "mcore_arith_J_operand" "r,J,0,0")))] +; "" +; "@ +; sub %0,%2 +; subi %0,%2 +; rsub %0,%1 +; rsubi %0,%1") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r") + (minus:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0,0,r") + (match_operand:SI 2 "mcore_arith_J_operand" "r,J,0")))] + "" + "@ + subu %0,%2 + subi %0,%2 + rsub %0,%1") + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (minus:SI (match_operand:SI 1 "mcore_literal_K_operand" "K") + (match_operand:SI 2 "mcore_arith_reg_operand" "0")))] + "" + "rsubi %0,%1") + +(define_insn "adddi3" + [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=&r") + (plus:DI (match_operand:DI 1 "mcore_arith_reg_operand" "%0") + (match_operand:DI 2 "mcore_arith_reg_operand" "r"))) + (clobber (reg:CC 17))] + "" + "* + { + if (TARGET_LITTLE_END) + return \"cmplt %0,%0\;addc %0,%2\;addc %R0,%R2\"; + return \"cmplt %R0,%R0\;addc %R0,%R2\;addc %0,%2\"; + }" + [(set_attr "length" "6")]) + +;; special case for "longlong += 1" +(define_insn "" + [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=&r") + (plus:DI (match_operand:DI 1 "mcore_arith_reg_operand" "0") + (const_int 1))) + (clobber (reg:CC 17))] + "" + "* + { + if (TARGET_LITTLE_END) + return \"addi %0,1\;cmpnei %0,0\;incf %R0\"; + return \"addi %R0,1\;cmpnei %R0,0\;incf %0\"; + }" + [(set_attr "length" "6")]) + +;; special case for "longlong -= 1" +(define_insn "" + [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=&r") + (plus:DI (match_operand:DI 1 "mcore_arith_reg_operand" "0") + (const_int -1))) + (clobber (reg:CC 17))] + "" + "* + { + if (TARGET_LITTLE_END) + return \"cmpnei %0,0\;decf %R0\;subi %0,1\"; + return \"cmpnei %R0,0\;decf %0\;subi %R0,1\"; + }" + [(set_attr "length" "6")]) + +;; special case for "longlong += const_int" +;; we have to use a register for the const_int because we don't +;; have an unsigned compare immediate... only +/- 1 get to +;; play the no-extra register game because they compare with 0. +;; This winds up working out for any literal that is synthesized +;; with a single instruction. The more complicated ones look +;; like the get broken into subreg's to get initialized too soon +;; for us to catch here. -- RBE 4/25/96 +;; only allow for-sure positive values. + +(define_insn "" + [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=&r") + (plus:DI (match_operand:DI 1 "mcore_arith_reg_operand" "0") + (match_operand:SI 2 "const_int_operand" "r"))) + (clobber (reg:CC 17))] + "GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) > 0 && ! (INTVAL (operands[2]) & 0x80000000)" + "* +{ + gcc_assert (GET_MODE (operands[2]) == SImode); + if (TARGET_LITTLE_END) + return \"addu %0,%2\;cmphs %0,%2\;incf %R0\"; + return \"addu %R0,%2\;cmphs %R0,%2\;incf %0\"; +}" + [(set_attr "length" "6")]) + +;; optimize "long long" + "unsigned long" +;; won't trigger because of how the extension is expanded upstream. +;; (define_insn "" +;; [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=&r") +;; (plus:DI (match_operand:DI 1 "mcore_arith_reg_operand" "%0") +;; (zero_extend:DI (match_operand:SI 2 "mcore_arith_reg_operand" "r")))) +;; (clobber (reg:CC 17))] +;; "0" +;; "cmplt %R0,%R0\;addc %R0,%2\;inct %0" +;; [(set_attr "length" "6")]) + +;; optimize "long long" + "signed long" +;; won't trigger because of how the extension is expanded upstream. +;; (define_insn "" +;; [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=&r") +;; (plus:DI (match_operand:DI 1 "mcore_arith_reg_operand" "%0") +;; (sign_extend:DI (match_operand:SI 2 "mcore_arith_reg_operand" "r")))) +;; (clobber (reg:CC 17))] +;; "0" +;; "cmplt %R0,%R0\;addc %R0,%2\;inct %0\;btsti %2,31\;dect %0" +;; [(set_attr "length" "6")]) + +(define_insn "subdi3" + [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=&r") + (minus:DI (match_operand:DI 1 "mcore_arith_reg_operand" "0") + (match_operand:DI 2 "mcore_arith_reg_operand" "r"))) + (clobber (reg:CC 17))] + "" + "* + { + if (TARGET_LITTLE_END) + return \"cmphs %0,%0\;subc %0,%2\;subc %R0,%R2\"; + return \"cmphs %R0,%R0\;subc %R0,%R2\;subc %0,%2\"; + }" + [(set_attr "length" "6")]) + +;; ------------------------------------------------------------------------- +;; Multiplication instructions +;; ------------------------------------------------------------------------- + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (mult:SI (match_operand:SI 1 "mcore_arith_reg_operand" "%0") + (match_operand:SI 2 "mcore_arith_reg_operand" "r")))] + "" + "mult %0,%2") + +;; +;; 32/32 signed division -- added to the MCORE instruction set spring 1997 +;; +;; Different constraints based on the architecture revision... +;; +(define_expand "divsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (div:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "mcore_arith_reg_operand" "")))] + "TARGET_DIV" + "") + +;; MCORE Revision 1.50: restricts the divisor to be in r1. (6/97) +;; +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (div:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0") + (match_operand:SI 2 "mcore_arith_reg_operand" "b")))] + "TARGET_DIV" + "divs %0,%2") + +;; +;; 32/32 signed division -- added to the MCORE instruction set spring 1997 +;; +;; Different constraints based on the architecture revision... +;; +(define_expand "udivsi3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (udiv:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "mcore_arith_reg_operand" "")))] + "TARGET_DIV" + "") + +;; MCORE Revision 1.50: restricts the divisor to be in r1. (6/97) +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (udiv:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0") + (match_operand:SI 2 "mcore_arith_reg_operand" "b")))] + "TARGET_DIV" + "divu %0,%2") + +;; ------------------------------------------------------------------------- +;; Unary arithmetic +;; ------------------------------------------------------------------------- + +(define_insn "negsi2" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (neg:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0")))] + "" + "* +{ + return \"rsubi %0,0\"; +}") + + +(define_insn "abssi2" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (abs:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0")))] + "" + "abs %0") + +(define_insn "negdi2" + [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=&r") + (neg:DI (match_operand:DI 1 "mcore_arith_reg_operand" "0"))) + (clobber (reg:CC 17))] + "" + "* +{ + if (TARGET_LITTLE_END) + return \"cmpnei %0,0\\n\\trsubi %0,0\\n\\tnot %R0\\n\\tincf %R0\"; + return \"cmpnei %R0,0\\n\\trsubi %R0,0\\n\\tnot %0\\n\\tincf %0\"; +}" + [(set_attr "length" "8")]) + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (not:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0")))] + "" + "not %0") + +;; ------------------------------------------------------------------------- +;; Zero extension instructions +;; ------------------------------------------------------------------------- + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (zero_extend:SI (match_operand:HI 1 "mcore_arith_reg_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r") + (zero_extend:SI (match_operand:HI 1 "general_operand" "0,m")))] + "" + "@ + zexth %0 + ld.h %0,%1" + [(set_attr "type" "shift,load")]) + +;; ldh gives us a free zero-extension. The combiner picks up on this. +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (zero_extend:SI (mem:HI (match_operand:SI 1 "mcore_arith_reg_operand" "r"))))] + "" + "ld.h %0,(%1)" + [(set_attr "type" "load")]) + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (zero_extend:SI (mem:HI (plus:SI (match_operand:SI 1 "mcore_arith_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "")))))] + "(INTVAL (operands[2]) >= 0) && + (INTVAL (operands[2]) < 32) && + ((INTVAL (operands[2])&1) == 0)" + "ld.h %0,(%1,%2)" + [(set_attr "type" "load")]) + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (zero_extend:SI (match_operand:QI 1 "general_operand" "")))] + "" + "") + +;; RBE: XXX: we don't recognize that the xtrb3 kills the CC register. +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,b,r") + (zero_extend:SI (match_operand:QI 1 "general_operand" "0,r,m")))] + "" + "@ + zextb %0 + xtrb3 %0,%1 + ld.b %0,%1" + [(set_attr "type" "shift,shift,load")]) + +;; ldb gives us a free zero-extension. The combiner picks up on this. +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (zero_extend:SI (mem:QI (match_operand:SI 1 "mcore_arith_reg_operand" "r"))))] + "" + "ld.b %0,(%1)" + [(set_attr "type" "load")]) + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (zero_extend:SI (mem:QI (plus:SI (match_operand:SI 1 "mcore_arith_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "")))))] + "(INTVAL (operands[2]) >= 0) && + (INTVAL (operands[2]) < 16)" + "ld.b %0,(%1,%2)" + [(set_attr "type" "load")]) + +(define_expand "zero_extendqihi2" + [(set (match_operand:HI 0 "mcore_arith_reg_operand" "") + (zero_extend:HI (match_operand:QI 1 "general_operand" "")))] + "" + "") + +;; RBE: XXX: we don't recognize that the xtrb3 kills the CC register. +(define_insn "" + [(set (match_operand:HI 0 "mcore_arith_reg_operand" "=r,b,r") + (zero_extend:HI (match_operand:QI 1 "general_operand" "0,r,m")))] + "" + "@ + zextb %0 + xtrb3 %0,%1 + ld.b %0,%1" + [(set_attr "type" "shift,shift,load")]) + +;; ldb gives us a free zero-extension. The combiner picks up on this. +;; this doesn't catch references that are into a structure. +;; note that normally the compiler uses the above insn, unless it turns +;; out that we're dealing with a volatile... +(define_insn "" + [(set (match_operand:HI 0 "mcore_arith_reg_operand" "=r") + (zero_extend:HI (mem:QI (match_operand:SI 1 "mcore_arith_reg_operand" "r"))))] + "" + "ld.b %0,(%1)" + [(set_attr "type" "load")]) + +(define_insn "" + [(set (match_operand:HI 0 "mcore_arith_reg_operand" "=r") + (zero_extend:HI (mem:QI (plus:SI (match_operand:SI 1 "mcore_arith_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "")))))] + "(INTVAL (operands[2]) >= 0) && + (INTVAL (operands[2]) < 16)" + "ld.b %0,(%1,%2)" + [(set_attr "type" "load")]) + + +;; ------------------------------------------------------------------------- +;; Sign extension instructions +;; ------------------------------------------------------------------------- + +(define_expand "extendsidi2" + [(set (match_operand:DI 0 "mcore_arith_reg_operand" "=r") + (match_operand:SI 1 "mcore_arith_reg_operand" "r"))] + "" + " + { + int low, high; + + if (TARGET_LITTLE_END) + low = 0, high = 4; + else + low = 4, high = 0; + + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], low), + operands[1])); + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], high), + gen_rtx_ASHIFTRT (SImode, + gen_rtx_SUBREG (SImode, operands[0], low), + GEN_INT (31)))); + DONE; + }" +) + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "mcore_arith_reg_operand" "0")))] + "" + "sexth %0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "mcore_arith_reg_operand" "0")))] + "" + "sextb %0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "mcore_arith_reg_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "mcore_arith_reg_operand" "0")))] + "" + "sextb %0") + +;; ------------------------------------------------------------------------- +;; Move instructions +;; ------------------------------------------------------------------------- + +;; SImode + +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (SImode, operands[1]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "mcore_general_movdst_operand" "=r,r,a,r,a,r,m") + (match_operand:SI 1 "mcore_general_movsrc_operand" "r,P,i,c,R,m,r"))] + "(register_operand (operands[0], SImode) + || register_operand (operands[1], SImode))" + "* return mcore_output_move (insn, operands, SImode);" + [(set_attr "type" "move,move,move,move,load,load,store")]) + +;; +;; HImode +;; + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (HImode, operands[1]); + else if (CONSTANT_P (operands[1]) + && (GET_CODE (operands[1]) != CONST_INT + || (! CONST_OK_FOR_I (INTVAL (operands[1])) + && ! CONST_OK_FOR_M (INTVAL (operands[1])) + && ! CONST_OK_FOR_N (INTVAL (operands[1])))) + && ! reload_completed && ! reload_in_progress) + { + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_movsi (reg, operands[1])); + operands[1] = gen_lowpart (HImode, reg); + } +}") + +(define_insn "" + [(set (match_operand:HI 0 "mcore_general_movdst_operand" "=r,r,a,r,r,m") + (match_operand:HI 1 "mcore_general_movsrc_operand" "r,P,i,c,m,r"))] + "(register_operand (operands[0], HImode) + || register_operand (operands[1], HImode))" + "* return mcore_output_move (insn, operands, HImode);" + [(set_attr "type" "move,move,move,move,load,store")]) + +;; +;; QImode +;; + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (QImode, operands[1]); + else if (CONSTANT_P (operands[1]) + && (GET_CODE (operands[1]) != CONST_INT + || (! CONST_OK_FOR_I (INTVAL (operands[1])) + && ! CONST_OK_FOR_M (INTVAL (operands[1])) + && ! CONST_OK_FOR_N (INTVAL (operands[1])))) + && ! reload_completed && ! reload_in_progress) + { + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_movsi (reg, operands[1])); + operands[1] = gen_lowpart (QImode, reg); + } +}") + +(define_insn "" + [(set (match_operand:QI 0 "mcore_general_movdst_operand" "=r,r,a,r,r,m") + (match_operand:QI 1 "mcore_general_movsrc_operand" "r,P,i,c,m,r"))] + "(register_operand (operands[0], QImode) + || register_operand (operands[1], QImode))" + "* return mcore_output_move (insn, operands, QImode);" + [(set_attr "type" "move,move,move,move,load,store")]) + + +;; DImode + +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (DImode, operands[1]); + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_I (INTVAL (operands[1])) + && ! CONST_OK_FOR_M (INTVAL (operands[1])) + && ! CONST_OK_FOR_N (INTVAL (operands[1]))) + { + int i; + for (i = 0; i < UNITS_PER_WORD * 2; i += UNITS_PER_WORD) + emit_move_insn (simplify_gen_subreg (SImode, operands[0], DImode, i), + simplify_gen_subreg (SImode, operands[1], DImode, i)); + DONE; + } +}") + +(define_insn "movdi_i" + [(set (match_operand:DI 0 "general_operand" "=r,r,r,r,a,r,m") + (match_operand:DI 1 "mcore_general_movsrc_operand" "I,M,N,r,R,m,r"))] + "" + "* return mcore_output_movedouble (operands, DImode);" + [(set_attr "length" "4") (set_attr "type" "move,move,move,move,load,load,store")]) + +;; SFmode + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (SFmode, operands[1]); +}") + +(define_insn "movsf_i" + [(set (match_operand:SF 0 "general_operand" "=r,r,m") + (match_operand:SF 1 "general_operand" "r,m,r"))] + "" + "@ + mov %0,%1 + ld.w %0,%1 + st.w %1,%0" + [(set_attr "type" "move,load,store")]) + +;; DFmode + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (DFmode, operands[1]); +}") + +(define_insn "movdf_k" + [(set (match_operand:DF 0 "general_operand" "=r,r,m") + (match_operand:DF 1 "general_operand" "r,m,r"))] + "" + "* return mcore_output_movedouble (operands, DFmode);" + [(set_attr "length" "4") (set_attr "type" "move,load,store")]) + + +;; Load/store multiple + +;; ??? This is not currently used. +(define_insn "ldm" + [(set (match_operand:TI 0 "mcore_arith_reg_operand" "=r") + (mem:TI (match_operand:SI 1 "mcore_arith_reg_operand" "r")))] + "" + "ldq %U0,(%1)") + +;; ??? This is not currently used. +(define_insn "stm" + [(set (mem:TI (match_operand:SI 0 "mcore_arith_reg_operand" "r")) + (match_operand:TI 1 "mcore_arith_reg_operand" "r"))] + "" + "stq %U1,(%0)") + +(define_expand "load_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" + " +{ + int regno, count, i; + + /* Support only loading a constant number of registers from memory and + only if at least two registers. The last register must be r15. */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[1]) != MEM + || XEXP (operands[1], 0) != stack_pointer_rtx + || GET_CODE (operands[0]) != REG + || REGNO (operands[0]) + INTVAL (operands[2]) != 16) + FAIL; + + count = INTVAL (operands[2]); + regno = REGNO (operands[0]); + + operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + for (i = 0; i < count; i++) + XVECEXP (operands[3], 0, i) + = gen_rtx_SET (VOIDmode, + gen_rtx_REG (SImode, regno + i), + gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, + i * 4))); +}") + +(define_insn "" + [(match_parallel 0 "mcore_load_multiple_operation" + [(set (match_operand:SI 1 "mcore_arith_reg_operand" "=r") + (mem:SI (match_operand:SI 2 "register_operand" "r")))])] + "GET_CODE (operands[2]) == REG && REGNO (operands[2]) == STACK_POINTER_REGNUM" + "ldm %1-r15,(%2)") + +(define_expand "store_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" + " +{ + int regno, count, i; + + /* Support only storing a constant number of registers to memory and + only if at least two registers. The last register must be r15. */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[0]) != MEM + || XEXP (operands[0], 0) != stack_pointer_rtx + || GET_CODE (operands[1]) != REG + || REGNO (operands[1]) + INTVAL (operands[2]) != 16) + FAIL; + + count = INTVAL (operands[2]); + regno = REGNO (operands[1]); + + operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + for (i = 0; i < count; i++) + XVECEXP (operands[3], 0, i) + = gen_rtx_SET (VOIDmode, + gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, + i * 4)), + gen_rtx_REG (SImode, regno + i)); +}") + +(define_insn "" + [(match_parallel 0 "mcore_store_multiple_operation" + [(set (mem:SI (match_operand:SI 2 "register_operand" "r")) + (match_operand:SI 1 "mcore_arith_reg_operand" "r"))])] + "GET_CODE (operands[2]) == REG && REGNO (operands[2]) == STACK_POINTER_REGNUM" + "stm %1-r15,(%2)") + +;; ------------------------------------------------------------------------ +;; Define the real conditional branch instructions. +;; ------------------------------------------------------------------------ + +;; At top-level, condition test are eq/ne, because we +;; are comparing against the condition register (which +;; has the result of the true relational test + +(define_insn "branch_true" + [(set (pc) (if_then_else (ne (reg:CC 17) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jbt %l0" + [(set_attr "type" "brcond")]) + +(define_insn "branch_false" + [(set (pc) (if_then_else (eq (reg:CC 17) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jbf %l0" + [(set_attr "type" "brcond")]) + +(define_insn "inverse_branch_true" + [(set (pc) (if_then_else (ne (reg:CC 17) (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jbf %l0" + [(set_attr "type" "brcond")]) + +(define_insn "inverse_branch_false" + [(set (pc) (if_then_else (eq (reg:CC 17) (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jbt %l0" + [(set_attr "type" "brcond")]) + +;; Conditional branch insns + +(define_expand "cbranchsi4" + [(set (pc) + (if_then_else (match_operator:SI 0 "ordered_comparison_operator" + [(match_operand:SI 1 "mcore_compare_operand") + (match_operand:SI 2 "nonmemory_operand")]) + (label_ref (match_operand 3 "")) + (pc)))] + "" + " +{ + bool invert; + invert = mcore_gen_compare (GET_CODE (operands[0]), + operands[1], operands[2]); + + if (invert) + emit_jump_insn (gen_branch_false (operands[3])); + else + emit_jump_insn (gen_branch_true (operands[3])); + DONE; +}") + + + +;; ------------------------------------------------------------------------ +;; Jump and linkage insns +;; ------------------------------------------------------------------------ + +(define_insn "jump_real" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jbr %l0" + [(set_attr "type" "branch")]) + +(define_expand "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + " +{ + emit_jump_insn (gen_jump_real (operand0)); + DONE; +} +") + +(define_insn "indirect_jump" + [(set (pc) + (match_operand:SI 0 "mcore_arith_reg_operand" "r"))] + "" + "jmp %0" + [(set_attr "type" "jmp")]) + +(define_expand "call" + [(parallel[(call (match_operand:SI 0 "" "") + (match_operand 1 "" "")) + (clobber (reg:SI 15))])] + "" + " +{ + if (GET_CODE (operands[0]) == MEM + && ! register_operand (XEXP (operands[0], 0), SImode) + && ! mcore_symbolic_address_p (XEXP (operands[0], 0))) + operands[0] = gen_rtx_MEM (GET_MODE (operands[0]), + force_reg (Pmode, XEXP (operands[0], 0))); +}") + +(define_insn "call_internal" + [(call (mem:SI (match_operand:SI 0 "mcore_call_address_operand" "riR")) + (match_operand 1 "" "")) + (clobber (reg:SI 15))] + "" + "* return mcore_output_call (operands, 0);") + +(define_expand "call_value" + [(parallel[(set (match_operand 0 "register_operand" "") + (call (match_operand:SI 1 "" "") + (match_operand 2 "" ""))) + (clobber (reg:SI 15))])] + "" + " +{ + if (GET_CODE (operands[0]) == MEM + && ! register_operand (XEXP (operands[0], 0), SImode) + && ! mcore_symbolic_address_p (XEXP (operands[0], 0))) + operands[1] = gen_rtx_MEM (GET_MODE (operands[1]), + force_reg (Pmode, XEXP (operands[1], 0))); +}") + +(define_insn "call_value_internal" + [(set (match_operand 0 "register_operand" "=r") + (call (mem:SI (match_operand:SI 1 "mcore_call_address_operand" "riR")) + (match_operand 2 "" ""))) + (clobber (reg:SI 15))] + "" + "* return mcore_output_call (operands, 1);") + +(define_insn "call_value_struct" + [(parallel [(set (match_parallel 0 "" + [(expr_list (match_operand 3 "register_operand" "") (match_operand 4 "immediate_operand" "")) + (expr_list (match_operand 5 "register_operand" "") (match_operand 6 "immediate_operand" ""))]) + (call (match_operand:SI 1 "" "") + (match_operand 2 "" ""))) + (clobber (reg:SI 15))])] + "" + "* return mcore_output_call (operands, 1);" +) + + +;; ------------------------------------------------------------------------ +;; Misc insns +;; ------------------------------------------------------------------------ + +(define_insn "nop" + [(const_int 0)] + "" + "or r0,r0") + +(define_insn "tablejump" + [(set (pc) + (match_operand:SI 0 "mcore_arith_reg_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jmp %0" + [(set_attr "type" "jmp")]) + +(define_insn "*return" + [(return)] + "reload_completed && ! mcore_naked_function_p ()" + "jmp r15" + [(set_attr "type" "jmp")]) + +(define_insn "*no_return" + [(return)] + "reload_completed && mcore_naked_function_p ()" + "" + [(set_attr "length" "0")] +) + +(define_expand "prologue" + [(const_int 0)] + "" + "mcore_expand_prolog (); DONE;") + +(define_expand "epilogue" + [(return)] + "" + "mcore_expand_epilog ();") + +;; ------------------------------------------------------------------------ +;; Scc instructions +;; ------------------------------------------------------------------------ + +(define_insn "mvc" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (ne:SI (reg:CC 17) (const_int 0)))] + "" + "mvc %0" + [(set_attr "type" "move")]) + +(define_insn "mvcv" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (eq:SI (reg:CC 17) (const_int 0)))] + "" + "mvcv %0" + [(set_attr "type" "move")]) + +; in 0.97 use (LE 0) with (LT 1) and complement c. BRC +(define_split + [(parallel[ + (set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (ne:SI (gt:CC (match_operand:SI 1 "mcore_arith_reg_operand" "") + (const_int 0)) + (const_int 0))) + (clobber (reg:SI 17))])] + "" + [(set (reg:CC 17) + (lt:CC (match_dup 1) (const_int 1))) + (set (match_dup 0) (eq:SI (reg:CC 17) (const_int 0)))]) + + +(define_expand "cstoresi4" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (match_operator:SI 1 "ordered_comparison_operator" + [(match_operand:SI 2 "mcore_compare_operand" "") + (match_operand:SI 3 "nonmemory_operand" "")]))] + "" + " +{ + bool invert; + invert = mcore_gen_compare (GET_CODE (operands[1]), + operands[2], operands[3]); + + if (invert) + emit_insn (gen_mvcv (operands[0])); + else + emit_insn (gen_mvc (operands[0])); + DONE; +}") + +(define_insn "incscc" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (plus:SI (ne (reg:CC 17) (const_int 0)) + (match_operand:SI 1 "mcore_arith_reg_operand" "0")))] + "" + "inct %0") + +(define_insn "incscc_false" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (plus:SI (eq (reg:CC 17) (const_int 0)) + (match_operand:SI 1 "mcore_arith_reg_operand" "0")))] + "" + "incf %0") + +(define_insn "decscc" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (minus:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0") + (ne (reg:CC 17) (const_int 0))))] + "" + "dect %0") + +(define_insn "decscc_false" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (minus:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0") + (eq (reg:CC 17) (const_int 0))))] + "" + "decf %0") + +;; ------------------------------------------------------------------------ +;; Conditional move patterns. +;; ------------------------------------------------------------------------ + +(define_expand "smaxsi3" + [(set (reg:CC 17) + (lt:CC (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "mcore_arith_reg_operand" ""))) + (set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (if_then_else:SI (eq (reg:CC 17) (const_int 0)) + (match_dup 1) (match_dup 2)))] + "" + "") + +(define_split + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (smax:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "mcore_arith_reg_operand" "")))] + "" + [(set (reg:CC 17) + (lt:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (if_then_else:SI (eq (reg:CC 17) (const_int 0)) + (match_dup 1) (match_dup 2)))] + "") + +; no tstgt in 0.97, so just use cmplti (btsti x,31) and reverse move +; condition BRC +(define_split + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (smax:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (const_int 0)))] + "" + [(set (reg:CC 17) + (lt:CC (match_dup 1) (const_int 0))) + (set (match_dup 0) + (if_then_else:SI (eq (reg:CC 17) (const_int 0)) + (match_dup 1) (const_int 0)))] + "") + +(define_expand "sminsi3" + [(set (reg:CC 17) + (lt:CC (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "mcore_arith_reg_operand" ""))) + (set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (if_then_else:SI (ne (reg:CC 17) (const_int 0)) + (match_dup 1) (match_dup 2)))] + "" + "") + +(define_split + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (smin:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "mcore_arith_reg_operand" "")))] + "" + [(set (reg:CC 17) + (lt:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (if_then_else:SI (ne (reg:CC 17) (const_int 0)) + (match_dup 1) (match_dup 2)))] + "") + +;(define_split +; [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") +; (smin:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") +; (const_int 0)))] +; "" +; [(set (reg:CC 17) +; (gt:CC (match_dup 1) (const_int 0))) +; (set (match_dup 0) +; (if_then_else:SI (eq (reg:CC 17) (const_int 0)) +; (match_dup 1) (const_int 0)))] +; "") + +; changed these unsigned patterns to use geu instead of ltu. it appears +; that the c-torture & ssrl test suites didn't catch these! only showed +; up in friedman's clib work. BRC 7/7/95 + +(define_expand "umaxsi3" + [(set (reg:CC 17) + (geu:CC (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "mcore_arith_reg_operand" ""))) + (set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (if_then_else:SI (eq (reg:CC 17) (const_int 0)) + (match_dup 2) (match_dup 1)))] + "" + "") + +(define_split + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (umax:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "mcore_arith_reg_operand" "")))] + "" + [(set (reg:CC 17) + (geu:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (if_then_else:SI (eq (reg:CC 17) (const_int 0)) + (match_dup 2) (match_dup 1)))] + "") + +(define_expand "uminsi3" + [(set (reg:CC 17) + (geu:CC (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "mcore_arith_reg_operand" ""))) + (set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (if_then_else:SI (ne (reg:CC 17) (const_int 0)) + (match_dup 2) (match_dup 1)))] + "" + "") + +(define_split + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (umin:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "mcore_arith_reg_operand" "")))] + "" + [(set (reg:CC 17) + (geu:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (if_then_else:SI (ne (reg:CC 17) (const_int 0)) + (match_dup 2) (match_dup 1)))] + "") + +;; ------------------------------------------------------------------------ +;; conditional move patterns really start here +;; ------------------------------------------------------------------------ + +;; the "movtK" patterns are experimental. they are intended to account for +;; gcc's mucking on code such as: +;; +;; free_ent = ((block_compress) ? 257 : 256 ); +;; +;; these patterns help to get a tstne/bgeni/inct (or equivalent) sequence +;; when both arms have constants that are +/- 1 of each other. +;; +;; note in the following patterns that the "movtK" ones should be the first +;; one defined in each sequence. this is because the general pattern also +;; matches, so use ordering to determine priority (it's easier this way than +;; adding conditions to the general patterns). BRC +;; +;; the U and Q constraints are necessary to ensure that reload does the +;; 'right thing'. U constrains the operand to 0 and Q to 1 for use in the +;; clrt & clrf and clrt/inct & clrf/incf patterns. BRC 6/26 +;; +;; ??? there appears to be some problems with these movtK patterns for ops +;; other than eq & ne. need to fix. 6/30 BRC + +;; ------------------------------------------------------------------------ +;; ne +;; ------------------------------------------------------------------------ + +; experimental conditional move with two constants +/- 1 BRC + +(define_insn "movtK_1" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (if_then_else:SI + (ne (reg:CC 17) (const_int 0)) + (match_operand:SI 1 "mcore_arith_O_operand" "O") + (match_operand:SI 2 "mcore_arith_O_operand" "O")))] + " GET_CODE (operands[1]) == CONST_INT + && GET_CODE (operands[2]) == CONST_INT + && ( (INTVAL (operands[1]) - INTVAL (operands[2]) == 1) + || (INTVAL (operands[2]) - INTVAL (operands[1]) == 1))" + "* return mcore_output_cmov (operands, 1, NULL);" + [(set_attr "length" "4")]) + +(define_insn "movt0" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI + (ne (reg:CC 17) (const_int 0)) + (match_operand:SI 1 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 2 "mcore_arith_imm_operand" "0,r,0,U")))] + "" + "@ + movt %0,%1 + movf %0,%2 + clrt %0 + clrf %0") + +;; ------------------------------------------------------------------------ +;; eq +;; ------------------------------------------------------------------------ + +; experimental conditional move with two constants +/- 1 BRC +(define_insn "movtK_2" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (if_then_else:SI + (eq (reg:CC 17) (const_int 0)) + (match_operand:SI 1 "mcore_arith_O_operand" "O") + (match_operand:SI 2 "mcore_arith_O_operand" "O")))] + " GET_CODE (operands[1]) == CONST_INT + && GET_CODE (operands[2]) == CONST_INT + && ( (INTVAL (operands[1]) - INTVAL (operands[2]) == 1) + || (INTVAL (operands[2]) - INTVAL (operands[1]) == 1))" + "* return mcore_output_cmov (operands, 0, NULL);" + [(set_attr "length" "4")]) + +(define_insn "movf0" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI + (eq (reg:CC 17) (const_int 0)) + (match_operand:SI 1 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 2 "mcore_arith_imm_operand" "0,r,0,U")))] + "" + "@ + movf %0,%1 + movt %0,%2 + clrf %0 + clrt %0") + +; turns lsli rx,imm/btsti rx,31 into btsti rx,imm. not done by a peephole +; because the instructions are not adjacent (peepholes are related by posn - +; not by dataflow). BRC + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI (eq (zero_extract:SI + (match_operand:SI 1 "mcore_arith_reg_operand" "r,r,r,r") + (const_int 1) + (match_operand:SI 2 "mcore_literal_K_operand" "K,K,K,K")) + (const_int 0)) + (match_operand:SI 3 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 4 "mcore_arith_imm_operand" "0,r,0,U")))] + "" + "@ + btsti %1,%2\;movf %0,%3 + btsti %1,%2\;movt %0,%4 + btsti %1,%2\;clrf %0 + btsti %1,%2\;clrt %0" + [(set_attr "length" "4")]) + +; turns sextb rx/btsti rx,31 into btsti rx,7. must be QImode to be safe. BRC + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI (eq (lshiftrt:SI + (match_operand:SI 1 "mcore_arith_reg_operand" "r,r,r,r") + (const_int 7)) + (const_int 0)) + (match_operand:SI 2 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 3 "mcore_arith_imm_operand" "0,r,0,U")))] + "GET_CODE (operands[1]) == SUBREG && + GET_MODE (SUBREG_REG (operands[1])) == QImode" + "@ + btsti %1,7\;movf %0,%2 + btsti %1,7\;movt %0,%3 + btsti %1,7\;clrf %0 + btsti %1,7\;clrt %0" + [(set_attr "length" "4")]) + + +;; ------------------------------------------------------------------------ +;; ne +;; ------------------------------------------------------------------------ + +;; Combine creates this from an andn instruction in a scc sequence. +;; We must recognize it to get conditional moves generated. + +; experimental conditional move with two constants +/- 1 BRC +(define_insn "movtK_3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (if_then_else:SI + (ne (match_operand:SI 1 "mcore_arith_reg_operand" "r") + (const_int 0)) + (match_operand:SI 2 "mcore_arith_O_operand" "O") + (match_operand:SI 3 "mcore_arith_O_operand" "O")))] + " GET_CODE (operands[2]) == CONST_INT + && GET_CODE (operands[3]) == CONST_INT + && ( (INTVAL (operands[2]) - INTVAL (operands[3]) == 1) + || (INTVAL (operands[3]) - INTVAL (operands[2]) == 1))" + "* +{ + rtx out_operands[4]; + out_operands[0] = operands[0]; + out_operands[1] = operands[2]; + out_operands[2] = operands[3]; + out_operands[3] = operands[1]; + + return mcore_output_cmov (out_operands, 1, \"cmpnei %3,0\"); + +}" + [(set_attr "length" "6")]) + +(define_insn "movt2" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI (ne (match_operand:SI 1 "mcore_arith_reg_operand" "r,r,r,r") + (const_int 0)) + (match_operand:SI 2 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 3 "mcore_arith_imm_operand" "0,r,0,U")))] + "" + "@ + cmpnei %1,0\;movt %0,%2 + cmpnei %1,0\;movf %0,%3 + cmpnei %1,0\;clrt %0 + cmpnei %1,0\;clrf %0" + [(set_attr "length" "4")]) + +; turns lsli rx,imm/btsti rx,31 into btsti rx,imm. not done by a peephole +; because the instructions are not adjacent (peepholes are related by posn - +; not by dataflow). BRC + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI (ne (zero_extract:SI + (match_operand:SI 1 "mcore_arith_reg_operand" "r,r,r,r") + (const_int 1) + (match_operand:SI 2 "mcore_literal_K_operand" "K,K,K,K")) + (const_int 0)) + (match_operand:SI 3 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 4 "mcore_arith_imm_operand" "0,r,0,U")))] + "" + "@ + btsti %1,%2\;movt %0,%3 + btsti %1,%2\;movf %0,%4 + btsti %1,%2\;clrt %0 + btsti %1,%2\;clrf %0" + [(set_attr "length" "4")]) + +; turns sextb rx/btsti rx,31 into btsti rx,7. must be QImode to be safe. BRC + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI (ne (lshiftrt:SI + (match_operand:SI 1 "mcore_arith_reg_operand" "r,r,r,r") + (const_int 7)) + (const_int 0)) + (match_operand:SI 2 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 3 "mcore_arith_imm_operand" "0,r,0,U")))] + "GET_CODE (operands[1]) == SUBREG && + GET_MODE (SUBREG_REG (operands[1])) == QImode" + "@ + btsti %1,7\;movt %0,%2 + btsti %1,7\;movf %0,%3 + btsti %1,7\;clrt %0 + btsti %1,7\;clrf %0" + [(set_attr "length" "4")]) + +;; ------------------------------------------------------------------------ +;; eq/eq +;; ------------------------------------------------------------------------ + +; experimental conditional move with two constants +/- 1 BRC +(define_insn "movtK_4" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (if_then_else:SI + (eq (eq:SI (reg:CC 17) (const_int 0)) (const_int 0)) + (match_operand:SI 1 "mcore_arith_O_operand" "O") + (match_operand:SI 2 "mcore_arith_O_operand" "O")))] + "GET_CODE (operands[1]) == CONST_INT && + GET_CODE (operands[2]) == CONST_INT && + ((INTVAL (operands[1]) - INTVAL (operands[2]) == 1) || + (INTVAL (operands[2]) - INTVAL (operands[1]) == 1))" + "* return mcore_output_cmov(operands, 1, NULL);" + [(set_attr "length" "4")]) + +(define_insn "movt3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI + (eq (eq:SI (reg:CC 17) (const_int 0)) (const_int 0)) + (match_operand:SI 1 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 2 "mcore_arith_imm_operand" "0,r,0,U")))] + "" + "@ + movt %0,%1 + movf %0,%2 + clrt %0 + clrf %0") + +;; ------------------------------------------------------------------------ +;; eq/ne +;; ------------------------------------------------------------------------ + +; experimental conditional move with two constants +/- 1 BRC +(define_insn "movtK_5" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (if_then_else:SI + (eq (ne:SI (reg:CC 17) (const_int 0)) (const_int 0)) + (match_operand:SI 1 "mcore_arith_O_operand" "O") + (match_operand:SI 2 "mcore_arith_O_operand" "O")))] + "GET_CODE (operands[1]) == CONST_INT && + GET_CODE (operands[2]) == CONST_INT && + ((INTVAL (operands[1]) - INTVAL (operands[2]) == 1) || + (INTVAL (operands[2]) - INTVAL (operands[1]) == 1))" + "* return mcore_output_cmov (operands, 0, NULL);" + [(set_attr "length" "4")]) + +(define_insn "movf1" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI + (eq (ne:SI (reg:CC 17) (const_int 0)) (const_int 0)) + (match_operand:SI 1 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 2 "mcore_arith_imm_operand" "0,r,0,U")))] + "" + "@ + movf %0,%1 + movt %0,%2 + clrf %0 + clrt %0") + +;; ------------------------------------------------------------------------ +;; eq +;; ------------------------------------------------------------------------ + +;; Combine creates this from an andn instruction in a scc sequence. +;; We must recognize it to get conditional moves generated. + +; experimental conditional move with two constants +/- 1 BRC + +(define_insn "movtK_6" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (if_then_else:SI + (eq (match_operand:SI 1 "mcore_arith_reg_operand" "r") + (const_int 0)) + (match_operand:SI 2 "mcore_arith_O_operand" "O") + (match_operand:SI 3 "mcore_arith_O_operand" "O")))] + "GET_CODE (operands[1]) == CONST_INT && + GET_CODE (operands[2]) == CONST_INT && + ((INTVAL (operands[2]) - INTVAL (operands[3]) == 1) || + (INTVAL (operands[3]) - INTVAL (operands[2]) == 1))" + "* +{ + rtx out_operands[4]; + out_operands[0] = operands[0]; + out_operands[1] = operands[2]; + out_operands[2] = operands[3]; + out_operands[3] = operands[1]; + + return mcore_output_cmov (out_operands, 0, \"cmpnei %3,0\"); +}" + [(set_attr "length" "6")]) + +(define_insn "movf3" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI (eq (match_operand:SI 1 "mcore_arith_reg_operand" "r,r,r,r") + (const_int 0)) + (match_operand:SI 2 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 3 "mcore_arith_imm_operand" "0,r,0,U")))] + "" + "@ + cmpnei %1,0\;movf %0,%2 + cmpnei %1,0\;movt %0,%3 + cmpnei %1,0\;clrf %0 + cmpnei %1,0\;clrt %0" + [(set_attr "length" "4")]) + +;; ------------------------------------------------------------------------ +;; ne/eq +;; ------------------------------------------------------------------------ + +; experimental conditional move with two constants +/- 1 BRC +(define_insn "movtK_7" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (if_then_else:SI + (ne (eq:SI (reg:CC 17) (const_int 0)) (const_int 0)) + (match_operand:SI 1 "mcore_arith_O_operand" "O") + (match_operand:SI 2 "mcore_arith_O_operand" "O")))] + "GET_CODE (operands[1]) == CONST_INT && + GET_CODE (operands[2]) == CONST_INT && + ((INTVAL (operands[1]) - INTVAL (operands[2]) == 1) || + (INTVAL (operands[2]) - INTVAL (operands[1]) == 1))" + "* return mcore_output_cmov (operands, 0, NULL);" + [(set_attr "length" "4")]) + +(define_insn "movf4" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI + (ne (eq:SI (reg:CC 17) (const_int 0)) (const_int 0)) + (match_operand:SI 1 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 2 "mcore_arith_imm_operand" "0,r,0,U")))] + "" + "@ + movf %0,%1 + movt %0,%2 + clrf %0 + clrt %0") + +;; ------------------------------------------------------------------------ +;; ne/ne +;; ------------------------------------------------------------------------ + +; experimental conditional move with two constants +/- 1 BRC +(define_insn "movtK_8" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (if_then_else:SI + (ne (ne:SI (reg:CC 17) (const_int 0)) (const_int 0)) + (match_operand:SI 1 "mcore_arith_O_operand" "O") + (match_operand:SI 2 "mcore_arith_O_operand" "O")))] + "GET_CODE (operands[1]) == CONST_INT && + GET_CODE (operands[2]) == CONST_INT && + ((INTVAL (operands[1]) - INTVAL (operands[2]) == 1) || + (INTVAL (operands[2]) - INTVAL (operands[1]) == 1))" + "* return mcore_output_cmov (operands, 1, NULL);" + [(set_attr "length" "4")]) + +(define_insn "movt4" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI + (ne (ne:SI (reg:CC 17) (const_int 0)) (const_int 0)) + (match_operand:SI 1 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 2 "mcore_arith_imm_operand" "0,r,0,U")))] + "" + "@ + movt %0,%1 + movf %0,%2 + clrt %0 + clrf %0") + +;; Also need patterns to recognize lt/ge, since otherwise the compiler will +;; try to output not/asri/tstne/movf. + +;; ------------------------------------------------------------------------ +;; lt +;; ------------------------------------------------------------------------ + +; experimental conditional move with two constants +/- 1 BRC +(define_insn "movtK_9" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (if_then_else:SI + (lt (match_operand:SI 1 "mcore_arith_reg_operand" "r") + (const_int 0)) + (match_operand:SI 2 "mcore_arith_O_operand" "O") + (match_operand:SI 3 "mcore_arith_O_operand" "O")))] + "GET_CODE (operands[2]) == CONST_INT && + GET_CODE (operands[3]) == CONST_INT && + ((INTVAL (operands[2]) - INTVAL (operands[3]) == 1) || + (INTVAL (operands[3]) - INTVAL (operands[2]) == 1))" + "* +{ + rtx out_operands[4]; + out_operands[0] = operands[0]; + out_operands[1] = operands[2]; + out_operands[2] = operands[3]; + out_operands[3] = operands[1]; + + return mcore_output_cmov (out_operands, 1, \"btsti %3,31\"); +}" + [(set_attr "length" "6")]) + +(define_insn "movt5" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI (lt (match_operand:SI 1 "mcore_arith_reg_operand" "r,r,r,r") + (const_int 0)) + (match_operand:SI 2 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 3 "mcore_arith_imm_operand" "0,r,0,U")))] + "" + "@ + btsti %1,31\;movt %0,%2 + btsti %1,31\;movf %0,%3 + btsti %1,31\;clrt %0 + btsti %1,31\;clrf %0" + [(set_attr "length" "4")]) + + +;; ------------------------------------------------------------------------ +;; ge +;; ------------------------------------------------------------------------ + +; experimental conditional move with two constants +/- 1 BRC +(define_insn "movtK_10" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (if_then_else:SI + (ge (match_operand:SI 1 "mcore_arith_reg_operand" "r") + (const_int 0)) + (match_operand:SI 2 "mcore_arith_O_operand" "O") + (match_operand:SI 3 "mcore_arith_O_operand" "O")))] + "GET_CODE (operands[2]) == CONST_INT && + GET_CODE (operands[3]) == CONST_INT && + ((INTVAL (operands[2]) - INTVAL (operands[3]) == 1) || + (INTVAL (operands[3]) - INTVAL (operands[2]) == 1))" + "* +{ + rtx out_operands[4]; + out_operands[0] = operands[0]; + out_operands[1] = operands[2]; + out_operands[2] = operands[3]; + out_operands[3] = operands[1]; + + return mcore_output_cmov (out_operands, 0, \"btsti %3,31\"); +}" + [(set_attr "length" "6")]) + +(define_insn "movf5" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,r,r,r") + (if_then_else:SI (ge (match_operand:SI 1 "mcore_arith_reg_operand" "r,r,r,r") + (const_int 0)) + (match_operand:SI 2 "mcore_arith_imm_operand" "r,0,U,0") + (match_operand:SI 3 "mcore_arith_imm_operand" "0,r,0,U")))] + "" + "@ + btsti %1,31\;movf %0,%2 + btsti %1,31\;movt %0,%3 + btsti %1,31\;clrf %0 + btsti %1,31\;clrt %0" + [(set_attr "length" "4")]) + +;; ------------------------------------------------------------------------ +;; Bitfield extract (xtrbN) +;; ------------------------------------------------------------------------ + +; sometimes we're better off using QI/HI mode and letting the machine indep. +; part expand insv and extv. +; +; e.g., sequences like:a [an insertion] +; +; ldw r8,(r6) +; movi r7,0x00ffffff +; and r8,r7 r7 dead +; stw r8,(r6) r8 dead +; +; become: +; +; movi r8,0 +; stb r8,(r6) r8 dead +; +; it looks like always using SI mode is a win except in this type of code +; (when adjacent bit fields collapse on a byte or halfword boundary). when +; expanding with SI mode, non-adjacent bit field masks fold, but with QI/HI +; mode, they do not. one thought is to add some peepholes to cover cases +; like the above, but this is not a general solution. +; +; -mword-bitfields expands/inserts using SI mode. otherwise, do it with +; the smallest mode possible (using the machine indep. expansions). BRC + +;(define_expand "extv" +; [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") +; (sign_extract:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") +; (match_operand:SI 2 "const_int_operand" "") +; (match_operand:SI 3 "const_int_operand" ""))) +; (clobber (reg:CC 17))] +; "" +; " +;{ +; if (INTVAL (operands[1]) != 8 || INTVAL (operands[2]) % 8 != 0) +; { +; if (TARGET_W_FIELD) +; { +; rtx lshft = GEN_INT (32 - (INTVAL (operands[2]) + INTVAL (operands[3]))); +; rtx rshft = GEN_INT (32 - INTVAL (operands[2])); +; +; emit_insn (gen_rtx_SET (SImode, operands[0], operands[1])); +; emit_insn (gen_rtx_SET (SImode, operands[0], +; gen_rtx_ASHIFT (SImode, operands[0], lshft))); +; emit_insn (gen_rtx_SET (SImode, operands[0], +; gen_rtx_ASHIFTRT (SImode, operands[0], rshft))); +; DONE; +; } +; else +; FAIL; +; } +;}") + +(define_expand "extv" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (sign_extract:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" ""))) + (clobber (reg:CC 17))] + "" + " +{ + if (INTVAL (operands[2]) == 8 && INTVAL (operands[3]) % 8 == 0) + { + /* 8-bit field, aligned properly, use the xtrb[0123]+sext sequence. */ + /* not DONE, not FAIL, but let the RTL get generated.... */ + } + else if (TARGET_W_FIELD) + { + /* Arbitrary placement; note that the tree->rtl generator will make + something close to this if we return FAIL */ + rtx lshft = GEN_INT (32 - (INTVAL (operands[2]) + INTVAL (operands[3]))); + rtx rshft = GEN_INT (32 - INTVAL (operands[2])); + rtx tmp1 = gen_reg_rtx (SImode); + rtx tmp2 = gen_reg_rtx (SImode); + + emit_insn (gen_rtx_SET (SImode, tmp1, operands[1])); + emit_insn (gen_rtx_SET (SImode, tmp2, + gen_rtx_ASHIFT (SImode, tmp1, lshft))); + emit_insn (gen_rtx_SET (SImode, operands[0], + gen_rtx_ASHIFTRT (SImode, tmp2, rshft))); + DONE; + } + else + { + /* Let the caller choose an alternate sequence. */ + FAIL; + } +}") + +(define_expand "extzv" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (zero_extract:SI (match_operand:SI 1 "mcore_arith_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" ""))) + (clobber (reg:CC 17))] + "" + " +{ + if (INTVAL (operands[2]) == 8 && INTVAL (operands[3]) % 8 == 0) + { + /* 8-bit field, aligned properly, use the xtrb[0123] sequence. */ + /* Let the template generate some RTL.... */ + } + else if (CONST_OK_FOR_K ((1 << INTVAL (operands[2])) - 1)) + { + /* A narrow bit-field (<=5 bits) means we can do a shift to put + it in place and then use an andi to extract it. + This is as good as a shiftleft/shiftright. */ + + rtx shifted; + rtx mask = GEN_INT ((1 << INTVAL (operands[2])) - 1); + + if (INTVAL (operands[3]) == 0) + { + shifted = operands[1]; + } + else + { + rtx rshft = GEN_INT (INTVAL (operands[3])); + shifted = gen_reg_rtx (SImode); + emit_insn (gen_rtx_SET (SImode, shifted, + gen_rtx_LSHIFTRT (SImode, operands[1], rshft))); + } + emit_insn (gen_rtx_SET (SImode, operands[0], + gen_rtx_AND (SImode, shifted, mask))); + DONE; + } + else if (TARGET_W_FIELD) + { + /* Arbitrary pattern; play shift/shift games to get it. + * this is pretty much what the caller will do if we say FAIL */ + rtx lshft = GEN_INT (32 - (INTVAL (operands[2]) + INTVAL (operands[3]))); + rtx rshft = GEN_INT (32 - INTVAL (operands[2])); + rtx tmp1 = gen_reg_rtx (SImode); + rtx tmp2 = gen_reg_rtx (SImode); + + emit_insn (gen_rtx_SET (SImode, tmp1, operands[1])); + emit_insn (gen_rtx_SET (SImode, tmp2, + gen_rtx_ASHIFT (SImode, tmp1, lshft))); + emit_insn (gen_rtx_SET (SImode, operands[0], + gen_rtx_LSHIFTRT (SImode, tmp2, rshft))); + DONE; + } + else + { + /* Make the compiler figure out some alternative mechanism. */ + FAIL; + } + + /* Emit the RTL pattern; something will match it later. */ +}") + +(define_expand "insv" + [(set (zero_extract:SI (match_operand:SI 0 "mcore_arith_reg_operand" "") + (match_operand:SI 1 "const_int_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (match_operand:SI 3 "general_operand" "")) + (clobber (reg:CC 17))] + "" + " +{ + if (mcore_expand_insv (operands)) + { + DONE; + } + else + { + FAIL; + } +}") + +;; +;; the xtrb[0123] instructions handily get at 8-bit fields on nice boundaries. +;; but then, they do force you through r1. +;; +;; the combiner will build such patterns for us, so we'll make them available +;; for its use. +;; +;; Note that we have both SIGNED and UNSIGNED versions of these... +;; + +;; +;; These no longer worry about the clobbering of CC bit; not sure this is +;; good... +;; +;; the SIGNED versions of these +;; +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,b") + (sign_extract:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0,r") (const_int 8) (const_int 24)))] + "" + "@ + asri %0,24 + xtrb0 %0,%1\;sextb %0" + [(set_attr "type" "shift")]) + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=b") + (sign_extract:SI (match_operand:SI 1 "mcore_arith_reg_operand" "r") (const_int 8) (const_int 16)))] + "" + "xtrb1 %0,%1\;sextb %0" + [(set_attr "type" "shift")]) + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=b") + (sign_extract:SI (match_operand:SI 1 "mcore_arith_reg_operand" "r") (const_int 8) (const_int 8)))] + "" + "xtrb2 %0,%1\;sextb %0" + [(set_attr "type" "shift")]) + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0") (const_int 8) (const_int 0)))] + "" + "sextb %0" + [(set_attr "type" "shift")]) + +;; the UNSIGNED uses of xtrb[0123] +;; +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,b") + (zero_extract:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0,r") (const_int 8) (const_int 24)))] + "" + "@ + lsri %0,24 + xtrb0 %0,%1" + [(set_attr "type" "shift")]) + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=b") + (zero_extract:SI (match_operand:SI 1 "mcore_arith_reg_operand" "r") (const_int 8) (const_int 16)))] + "" + "xtrb1 %0,%1" + [(set_attr "type" "shift")]) + +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=b") + (zero_extract:SI (match_operand:SI 1 "mcore_arith_reg_operand" "r") (const_int 8) (const_int 8)))] + "" + "xtrb2 %0,%1" + [(set_attr "type" "shift")]) + +;; This can be peepholed if it follows a ldb ... +(define_insn "" + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r,b") + (zero_extract:SI (match_operand:SI 1 "mcore_arith_reg_operand" "0,r") (const_int 8) (const_int 0)))] + "" + "@ + zextb %0 + xtrb3 %0,%1\;zextb %0" + [(set_attr "type" "shift")]) + + +;; ------------------------------------------------------------------------ +;; Block move - adapted from m88k.md +;; ------------------------------------------------------------------------ + +(define_expand "movmemsi" + [(parallel [(set (mem:BLK (match_operand:BLK 0 "" "")) + (mem:BLK (match_operand:BLK 1 "" ""))) + (use (match_operand:SI 2 "general_operand" "")) + (use (match_operand:SI 3 "immediate_operand" ""))])] + "" + " +{ + if (mcore_expand_block_move (operands)) + DONE; + else + FAIL; +}") + +;; ;;; ??? These patterns are meant to be generated from expand_block_move, +;; ;;; but they currently are not. +;; +;; (define_insn "" +;; [(set (match_operand:QI 0 "mcore_arith_reg_operand" "=r") +;; (match_operand:BLK 1 "mcore_general_movsrc_operand" "m"))] +;; "" +;; "ld.b %0,%1" +;; [(set_attr "type" "load")]) +;; +;; (define_insn "" +;; [(set (match_operand:HI 0 "mcore_arith_reg_operand" "=r") +;; (match_operand:BLK 1 "mcore_general_movsrc_operand" "m"))] +;; "" +;; "ld.h %0,%1" +;; [(set_attr "type" "load")]) +;; +;; (define_insn "" +;; [(set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") +;; (match_operand:BLK 1 "mcore_general_movsrc_operand" "m"))] +;; "" +;; "ld.w %0,%1" +;; [(set_attr "type" "load")]) +;; +;; (define_insn "" +;; [(set (match_operand:BLK 0 "mcore_general_movdst_operand" "=m") +;; (match_operand:QI 1 "mcore_arith_reg_operand" "r"))] +;; "" +;; "st.b %1,%0" +;; [(set_attr "type" "store")]) +;; +;; (define_insn "" +;; [(set (match_operand:BLK 0 "mcore_general_movdst_operand" "=m") +;; (match_operand:HI 1 "mcore_arith_reg_operand" "r"))] +;; "" +;; "st.h %1,%0" +;; [(set_attr "type" "store")]) +;; +;; (define_insn "" +;; [(set (match_operand:BLK 0 "mcore_general_movdst_operand" "=m") +;; (match_operand:SI 1 "mcore_arith_reg_operand" "r"))] +;; "" +;; "st.w %1,%0" +;; [(set_attr "type" "store")]) + +;; ------------------------------------------------------------------------ +;; Misc Optimizing quirks +;; ------------------------------------------------------------------------ + +;; pair to catch constructs like: (int *)((p+=4)-4) which happen +;; in stdarg/varargs traversal. This changes a 3 insn sequence to a 2 +;; insn sequence. -- RBE 11/30/95 +(define_insn "" + [(parallel[ + (set (match_operand:SI 0 "mcore_arith_reg_operand" "=r") + (match_operand:SI 1 "mcore_arith_reg_operand" "+r")) + (set (match_dup 1) (plus:SI (match_dup 1) (match_operand 2 "mcore_arith_any_imm_operand" "")))])] + "GET_CODE(operands[2]) == CONST_INT" + "#" + [(set_attr "length" "4")]) + +(define_split + [(parallel[ + (set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (match_operand:SI 1 "mcore_arith_reg_operand" "")) + (set (match_dup 1) (plus:SI (match_dup 1) (match_operand 2 "mcore_arith_any_imm_operand" "")))])] + "GET_CODE(operands[2]) == CONST_INT && + operands[0] != operands[1]" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 1) (plus:SI (match_dup 1) (match_dup 2)))]) + + +;;; Peepholes + +; note: in the following patterns, use mcore_is_dead() to ensure that the +; reg we may be trashing really is dead. reload doesn't always mark +; deaths, so mcore_is_dead() (see mcore.c) scans forward to find its death. BRC + +;;; A peephole to convert the 3 instruction sequence generated by reload +;;; to load a FP-offset address into a 2 instruction sequence. +;;; ??? This probably never matches anymore. +(define_peephole + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (match_operand:SI 1 "const_int_operand" "J")) + (set (match_dup 0) (neg:SI (match_dup 0))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "mcore_arith_reg_operand" "r")))] + "CONST_OK_FOR_J (INTVAL (operands[1]))" + "error\;mov %0,%2\;subi %0,%1") + +;; Moves of inlinable constants are done late, so when a 'not' is generated +;; it is never combined with the following 'and' to generate an 'andn' b/c +;; the combiner never sees it. use a peephole to pick up this case (happens +;; mostly with bitfields) BRC + +(define_peephole + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (match_operand:SI 1 "const_int_operand" "i")) + (set (match_operand:SI 2 "mcore_arith_reg_operand" "r") + (and:SI (match_dup 2) (match_dup 0)))] + "mcore_const_trick_uses_not (INTVAL (operands[1])) && + operands[0] != operands[2] && + mcore_is_dead (insn, operands[0])" + "* return mcore_output_andn (insn, operands);") + +; when setting or clearing just two bits, it's cheapest to use two bseti's +; or bclri's. only happens when relaxing immediates. BRC + +(define_peephole + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (match_operand:SI 1 "const_int_operand" "")) + (set (match_operand:SI 2 "mcore_arith_reg_operand" "") + (ior:SI (match_dup 2) (match_dup 0)))] + "TARGET_HARDLIT + && mcore_num_ones (INTVAL (operands[1])) == 2 + && mcore_is_dead (insn, operands[0])" + "* return mcore_output_bseti (operands[2], INTVAL (operands[1]));") + +(define_peephole + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (match_operand:SI 1 "const_int_operand" "")) + (set (match_operand:SI 2 "mcore_arith_reg_operand" "") + (and:SI (match_dup 2) (match_dup 0)))] + "TARGET_HARDLIT && mcore_num_zeros (INTVAL (operands[1])) == 2 && + mcore_is_dead (insn, operands[0])" + "* return mcore_output_bclri (operands[2], INTVAL (operands[1]));") + +; change an and with a mask that has a single cleared bit into a bclri. this +; handles QI and HI mode values using the knowledge that the most significant +; bits don't matter. + +(define_peephole + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (match_operand:SI 1 "const_int_operand" "")) + (set (match_operand:SI 2 "mcore_arith_reg_operand" "") + (and:SI (match_operand:SI 3 "mcore_arith_reg_operand" "") + (match_dup 0)))] + "GET_CODE (operands[3]) == SUBREG && + GET_MODE (SUBREG_REG (operands[3])) == QImode && + mcore_num_zeros (INTVAL (operands[1]) | 0xffffff00) == 1 && + mcore_is_dead (insn, operands[0])" +"* + if (! mcore_is_same_reg (operands[2], operands[3])) + output_asm_insn (\"mov\\t%2,%3\", operands); + return mcore_output_bclri (operands[2], INTVAL (operands[1]) | 0xffffff00);") + +/* Do not fold these together -- mode is lost at final output phase. */ + +(define_peephole + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (match_operand:SI 1 "const_int_operand" "")) + (set (match_operand:SI 2 "mcore_arith_reg_operand" "") + (and:SI (match_operand:SI 3 "mcore_arith_reg_operand" "") + (match_dup 0)))] + "GET_CODE (operands[3]) == SUBREG && + GET_MODE (SUBREG_REG (operands[3])) == HImode && + mcore_num_zeros (INTVAL (operands[1]) | 0xffff0000) == 1 && + operands[2] == operands[3] && + mcore_is_dead (insn, operands[0])" +"* + if (! mcore_is_same_reg (operands[2], operands[3])) + output_asm_insn (\"mov\\t%2,%3\", operands); + return mcore_output_bclri (operands[2], INTVAL (operands[1]) | 0xffff0000);") + +; This peephole helps when using -mwide-bitfields to widen fields so they +; collapse. This, however, has the effect that a narrower mode is not used +; when desirable. +; +; e.g., sequences like: +; +; ldw r8,(r6) +; movi r7,0x00ffffff +; and r8,r7 r7 dead +; stw r8,(r6) r8 dead +; +; get peepholed to become: +; +; movi r8,0 +; stb r8,(r6) r8 dead +; +; Do only easy addresses that have no offset. This peephole is also applied +; to halfwords. We need to check that the load is non-volatile before we get +; rid of it. + +(define_peephole + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (match_operand:SI 1 "memory_operand" "")) + (set (match_operand:SI 2 "mcore_arith_reg_operand" "") + (match_operand:SI 3 "const_int_operand" "")) + (set (match_dup 0) (and:SI (match_dup 0) (match_dup 2))) + (set (match_operand:SI 4 "memory_operand" "") (match_dup 0))] + "mcore_is_dead (insn, operands[0]) && + ! MEM_VOLATILE_P (operands[1]) && + mcore_is_dead (insn, operands[2]) && + (mcore_byte_offset (INTVAL (operands[3])) > -1 || + mcore_halfword_offset (INTVAL (operands[3])) > -1) && + ! MEM_VOLATILE_P (operands[4]) && + GET_CODE (XEXP (operands[4], 0)) == REG" +"* +{ + int ofs; + enum machine_mode mode; + rtx base_reg = XEXP (operands[4], 0); + + if ((ofs = mcore_byte_offset (INTVAL (operands[3]))) > -1) + mode = QImode; + else if ((ofs = mcore_halfword_offset (INTVAL (operands[3]))) > -1) + mode = HImode; + else + gcc_unreachable (); + + if (ofs > 0) + operands[4] = gen_rtx_MEM (mode, + gen_rtx_PLUS (SImode, base_reg, GEN_INT(ofs))); + else + operands[4] = gen_rtx_MEM (mode, base_reg); + + if (mode == QImode) + return \"movi %0,0\\n\\tst.b %0,%4\"; + + return \"movi %0,0\\n\\tst.h %0,%4\"; +}") + +; from sop11. get btsti's for (LT A 0) where A is a QI or HI value + +(define_peephole + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (sign_extend:SI (match_operand:QI 1 "mcore_arith_reg_operand" "0"))) + (set (reg:CC 17) + (lt:CC (match_dup 0) + (const_int 0)))] + "mcore_is_dead (insn, operands[0])" + "btsti %0,7") + +(define_peephole + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "r") + (sign_extend:SI (match_operand:HI 1 "mcore_arith_reg_operand" "0"))) + (set (reg:CC 17) + (lt:CC (match_dup 0) + (const_int 0)))] + "mcore_is_dead (insn, operands[0])" + "btsti %0,15") + +; Pick up a tst. This combination happens because the immediate is not +; allowed to fold into one of the operands of the tst. Does not happen +; when relaxing immediates. BRC + +(define_peephole + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (match_operand:SI 1 "mcore_arith_reg_operand" "")) + (set (match_dup 0) + (and:SI (match_dup 0) + (match_operand:SI 2 "mcore_literal_K_operand" ""))) + (set (reg:CC 17) (ne:CC (match_dup 0) (const_int 0)))] + "mcore_is_dead (insn, operands[0])" + "movi %0,%2\;tst %1,%0") + +(define_peephole + [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") + (if_then_else:SI (ne (zero_extract:SI + (match_operand:SI 1 "mcore_arith_reg_operand" "") + (const_int 1) + (match_operand:SI 2 "mcore_literal_K_operand" "")) + (const_int 0)) + (match_operand:SI 3 "mcore_arith_imm_operand" "") + (match_operand:SI 4 "mcore_arith_imm_operand" ""))) + (set (reg:CC 17) (ne:CC (match_dup 0) (const_int 0)))] + "" +"* +{ + unsigned int op0 = REGNO (operands[0]); + + if (GET_CODE (operands[3]) == REG) + { + if (REGNO (operands[3]) == op0 && GET_CODE (operands[4]) == CONST_INT + && INTVAL (operands[4]) == 0) + return \"btsti %1,%2\\n\\tclrf %0\"; + else if (GET_CODE (operands[4]) == REG) + { + if (REGNO (operands[4]) == op0) + return \"btsti %1,%2\\n\\tmovf %0,%3\"; + else if (REGNO (operands[3]) == op0) + return \"btsti %1,%2\\n\\tmovt %0,%4\"; + } + + gcc_unreachable (); + } + else if (GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) == 0 + && GET_CODE (operands[4]) == REG) + return \"btsti %1,%2\\n\\tclrt %0\"; + + gcc_unreachable (); +}") + +; experimental - do the constant folding ourselves. note that this isn't +; re-applied like we'd really want. i.e., four ands collapse into two +; instead of one. this is because peepholes are applied as a sliding +; window. the peephole does not generate new rtl's, but instead slides +; across the rtl's generating machine instructions. it would be nice +; if the peephole optimizer is changed to re-apply patterns and to gen +; new rtl's. this is more flexible. the pattern below helps when we're +; not using relaxed immediates. BRC + +;(define_peephole +; [(set (match_operand:SI 0 "mcore_arith_reg_operand" "") +; (match_operand:SI 1 "const_int_operand" "")) +; (set (match_operand:SI 2 "mcore_arith_reg_operand" "") +; (and:SI (match_dup 2) (match_dup 0))) +; (set (match_dup 0) +; (match_operand:SI 3 "const_int_operand" "")) +; (set (match_dup 2) +; (and:SI (match_dup 2) (match_dup 0)))] +; "!TARGET_RELAX_IMM && mcore_is_dead (insn, operands[0]) && +; mcore_const_ok_for_inline (INTVAL (operands[1]) & INTVAL (operands[3]))" +; "* +;{ +; rtx out_operands[2]; +; out_operands[0] = operands[0]; +; out_operands[1] = GEN_INT (INTVAL (operands[1]) & INTVAL (operands[3])); +; +; output_inline_const (SImode, out_operands); +; +; output_asm_insn (\"and %2,%0\", operands); +; +; return \"\"; +;}") + +; BRC: for inlining get rid of extra test - experimental +;(define_peephole +; [(set (match_operand:SI 0 "mcore_arith_reg_operand" "r") +; (ne:SI (reg:CC 17) (const_int 0))) +; (set (reg:CC 17) (ne:CC (match_dup 0) (const_int 0))) +; (set (pc) +; (if_then_else (eq (reg:CC 17) (const_int 0)) +; (label_ref (match_operand 1 "" "")) +; (pc)))] +; "" +; "* +;{ +; if (get_attr_length (insn) == 10) +; { +; output_asm_insn (\"bt 2f\\n\\tjmpi [1f]\", operands); +; output_asm_insn (\".align 2\\n1:\", operands); +; output_asm_insn (\".long %1\\n2:\", operands); +; return \"\"; +; } +; return \"bf %l1\"; +;}") + + +;;; Special patterns for dealing with the constant pool. + +;;; 4 byte integer in line. + +(define_insn "consttable_4" + [(unspec_volatile [(match_operand:SI 0 "general_operand" "=g")] 0)] + "" + "* +{ + assemble_integer (operands[0], 4, BITS_PER_WORD, 1); + return \"\"; +}" + [(set_attr "length" "4")]) + +;;; align to a four byte boundary. + +(define_insn "align_4" + [(unspec_volatile [(const_int 0)] 1)] + "" + ".align 2") + +;;; Handle extra constant pool entries created during final pass. + +(define_insn "consttable_end" + [(unspec_volatile [(const_int 0)] 2)] + "" + "* return mcore_output_jump_label_table ();") + +;; +;; Stack allocation -- in particular, for alloca(). +;; this is *not* what we use for entry into functions. +;; +;; This is how we allocate stack space. If we are allocating a +;; constant amount of space and we know it is less than 4096 +;; bytes, we need do nothing. +;; +;; If it is more than 4096 bytes, we need to probe the stack +;; periodically. +;; +;; operands[1], the distance is a POSITIVE number indicating that we +;; are allocating stack space +;; +(define_expand "allocate_stack" + [(set (reg:SI 0) + (plus:SI (reg:SI 0) + (match_operand:SI 1 "general_operand" ""))) + (set (match_operand:SI 0 "register_operand" "=r") + (match_dup 2))] + "" + " +{ + /* If he wants no probing, just do it for him. */ + if (mcore_stack_increment == 0) + { + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,operands[1])); +;; emit_move_insn (operands[0], virtual_stack_dynamic_rtx); + DONE; + } + + /* For small constant growth, we unroll the code. */ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < 8 * STACK_UNITS_MAXSTEP) + { + HOST_WIDE_INT left = INTVAL(operands[1]); + + /* If it's a long way, get close enough for a last shot. */ + if (left >= STACK_UNITS_MAXSTEP) + { + rtx tmp = gen_reg_rtx (Pmode); + emit_insn (gen_movsi (tmp, GEN_INT (STACK_UNITS_MAXSTEP))); + do + { + rtx memref = gen_rtx_MEM (SImode, stack_pointer_rtx); + + MEM_VOLATILE_P (memref) = 1; + emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp)); + emit_insn (gen_movsi (memref, stack_pointer_rtx)); + left -= STACK_UNITS_MAXSTEP; + } + while (left > STACK_UNITS_MAXSTEP); + } + /* Perform the final adjustment. */ + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-left))); +;; emit_move_insn (operands[0], virtual_stack_dynamic_rtx); + DONE; + } + else + { + rtx out_label = 0; + rtx loop_label = gen_label_rtx (); + rtx step = gen_reg_rtx (Pmode); + rtx tmp = gen_reg_rtx (Pmode); + rtx test, memref; + +#if 1 + emit_insn (gen_movsi (tmp, operands[1])); + emit_insn (gen_movsi (step, GEN_INT (STACK_UNITS_MAXSTEP))); + + if (GET_CODE (operands[1]) != CONST_INT) + { + out_label = gen_label_rtx (); + test = gen_rtx_GEU (VOIDmode, step, tmp); /* quick out */ + emit_jump_insn (gen_cbranchsi4 (test, step, tmp, out_label)); + } + + /* Run a loop that steps it incrementally. */ + emit_label (loop_label); + + /* Extend a step, probe, and adjust remaining count. */ + emit_insn(gen_subsi3(stack_pointer_rtx, stack_pointer_rtx, step)); + memref = gen_rtx_MEM (SImode, stack_pointer_rtx); + MEM_VOLATILE_P (memref) = 1; + emit_insn(gen_movsi(memref, stack_pointer_rtx)); + emit_insn(gen_subsi3(tmp, tmp, step)); + + /* Loop condition -- going back up. */ + test = gen_rtx_LTU (VOIDmode, step, tmp); + emit_jump_insn (gen_cbranchsi4 (test, step, tmp, loop_label)); + + if (out_label) + emit_label (out_label); + + /* Bump the residual. */ + emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp)); +;; emit_move_insn (operands[0], virtual_stack_dynamic_rtx); + DONE; +#else + /* simple one-shot -- ensure register and do a subtract. + * This does NOT comply with the ABI. */ + emit_insn (gen_movsi (tmp, operands[1])); + emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp)); +;; emit_move_insn (operands[0], virtual_stack_dynamic_rtx); + DONE; +#endif + } +}") |