rt_gccstream/gcc/config/mcore/mcore.md

3087 lines
99 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;; Machine description the Motorola MCore
;; Copyright (C) 1993, 1999, 2000, 2004, 2005, 2007
;; 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")
;; -------------------------------------------------------------------------
;; 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" "")))]
""
"
{
extern int flag_omit_frame_pointer;
/* 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
}
}")