;; Machine description the Motorola MCore ;; Copyright (C) 1993-2015 Free Software Foundation, Inc. ;; Contributed by Motorola.
;; This file is part of GCC.
;; GCC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version.
;; GCC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License ;; along with GCC; see the file COPYING3. If not see ;; http://www.gnu.org/licenses/.
;;- See file “rtl.def” for documentation on define_insn, match_*, et. al.
;; ------------------------------------------------------------------------- ;; Attributes ;; -------------------------------------------------------------------------
; Target CPU.
(define_attr “type” “brcond,branch,jmp,load,store,move,alu,shift” (const_string “alu”))
;; If a branch destination is within -2048..2047 bytes away from the ;; instruction it can be 2 bytes long. All other conditional branches ;; are 10 bytes long, and all other unconditional branches are 8 bytes. ;; ;; the assembler handles the long-branch span case for us if we use ;; the “jb*” mnemonics for jumps/branches. This pushes the span ;; calculations and the literal table placement into the assembler, ;; where their interactions can be managed in a single place.
;; All MCORE instructions are two bytes long.
(define_attr “length” "" (const_int 2))
;; Scheduling. We only model a simple load latency. (define_insn_reservation “any_insn” 1 (eq_attr “type” “!load”) “nothing”) (define_insn_reservation “memory” 2 (eq_attr “type” “load”) “nothing”)
(include “predicates.md”) (include “constraints.md”)
;; ------------------------------------------------------------------------- ;; Test and bit test ;; -------------------------------------------------------------------------
(define_insn "" [(set (reg:SI 17) (sign_extract:SI (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (const_int 1) (match_operand:SI 1 “mcore_literal_K_operand” “K”)))] "" “btsti %0,%1” [(set_attr “type” “shift”)])
(define_insn "" [(set (reg:SI 17) (zero_extract:SI (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (const_int 1) (match_operand:SI 1 “mcore_literal_K_operand” “K”)))] "" “btsti %0,%1” [(set_attr “type” “shift”)])
;;; This is created by combine. (define_insn "" [(set (reg:CC 17) (ne:CC (zero_extract:SI (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (const_int 1) (match_operand:SI 1 “mcore_literal_K_operand” “K”)) (const_int 0)))] "" “btsti %0,%1” [(set_attr “type” “shift”)])
;; Created by combine from conditional patterns below (see sextb/btsti rx,31)
(define_insn "" [(set (reg:CC 17) (ne:CC (lshiftrt:SI (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (const_int 7)) (const_int 0)))] “GET_CODE(operands[0]) == SUBREG && GET_MODE(SUBREG_REG(operands[0])) == QImode” “btsti %0,7” [(set_attr “type” “shift”)])
(define_insn "" [(set (reg:CC 17) (ne:CC (lshiftrt:SI (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (const_int 15)) (const_int 0)))] “GET_CODE(operands[0]) == SUBREG && GET_MODE(SUBREG_REG(operands[0])) == HImode” “btsti %0,15” [(set_attr “type” “shift”)])
(define_split [(set (pc) (if_then_else (ne (eq:CC (zero_extract:SI (match_operand:SI 0 “mcore_arith_reg_operand” "") (const_int 1) (match_operand:SI 1 “mcore_literal_K_operand” "")) (const_int 0)) (const_int 0)) (label_ref (match_operand 2 "" "")) (pc)))] "" [(set (reg:CC 17) (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))) (set (pc) (if_then_else (eq (reg:CC 17) (const_int 0)) (label_ref (match_dup 2)) (pc)))] "")
(define_split [(set (pc) (if_then_else (eq (ne:CC (zero_extract:SI (match_operand:SI 0 “mcore_arith_reg_operand” "") (const_int 1) (match_operand:SI 1 “mcore_literal_K_operand” "")) (const_int 0)) (const_int 0)) (label_ref (match_operand 2 "" "")) (pc)))] "" [(set (reg:CC 17) (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))) (set (pc) (if_then_else (eq (reg:CC 17) (const_int 0)) (label_ref (match_dup 2)) (pc)))] "")
;; XXX - disabled by nickc because it fails on libiberty/fnmatch.c ;; ;; ; Experimental - relax immediates for and, andn, or, and tst to allow ;; ; any immediate value (or an immediate at all -- or, andn, & tst).
;; ; This is done to allow bit field masks to fold together in combine. ;; ; The reload phase will force the immediate into a register at the ;; ; very end. This helps in some cases, but hurts in others: we‘d ;; ; really like to cse these immediates. However, there is a phase ;; ; ordering problem here. cse picks up individual masks and cse’s ;; ; those, but not folded masks (cse happens before combine). It's ;; ; not clear what the best solution is because we really want cse ;; ; before combine (leaving the bit field masks alone). To pick up ;; ; relaxed immediates use -mrelax-immediates. It might take some ;; ; experimenting to see which does better (i.e. regular imms vs. ;; ; arbitrary imms) for a particular code. BRC ;; ;; (define_insn "" ;; [(set (reg:CC 17) ;; (ne:CC (and:SI (match_operand:SI 0 “mcore_arith_reg_operand” “r”) ;; (match_operand:SI 1 “mcore_arith_any_imm_operand” “rI”)) ;; (const_int 0)))] ;; “TARGET_RELAX_IMM” ;; “tst %0,%1”) ;; ;; (define_insn "" ;; [(set (reg:CC 17) ;; (ne:CC (and:SI (match_operand:SI 0 “mcore_arith_reg_operand” “r”) ;; (match_operand:SI 1 “mcore_arith_M_operand” “r”)) ;; (const_int 0)))] ;; “!TARGET_RELAX_IMM” ;; “tst %0,%1”)
(define_insn "" [(set (reg:CC 17) (ne:CC (and:SI (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (match_operand:SI 1 “mcore_arith_M_operand” “r”)) (const_int 0)))] "" “tst %0,%1”)
(define_split [(parallel[ (set (reg:CC 17) (ne:CC (ne:SI (leu:CC (match_operand:SI 0 “mcore_arith_reg_operand” "") (match_operand:SI 1 “mcore_arith_reg_operand” "")) (const_int 0)) (const_int 0))) (clobber (match_operand:CC 2 “mcore_arith_reg_operand” ""))])] "" [(set (reg:CC 17) (ne:SI (match_dup 0) (const_int 0))) (set (reg:CC 17) (leu:CC (match_dup 0) (match_dup 1)))])
;; ------------------------------------------------------------------------- ;; SImode signed integer comparisons ;; -------------------------------------------------------------------------
(define_insn “decne_t” [(set (reg:CC 17) (ne:CC (plus:SI (match_operand:SI 0 “mcore_arith_reg_operand” “+r”) (const_int -1))
(const_int 0))) (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1)))] "" “decne %0”)
;; The combiner seems to prefer the following to the former. ;; (define_insn "" [(set (reg:CC 17) (ne:CC (match_operand:SI 0 “mcore_arith_reg_operand” “+r”) (const_int 1))) (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1)))] "" “decne %0”)
(define_insn “cmpnesi_t” [(set (reg:CC 17) (ne:CC (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (match_operand:SI 1 “mcore_arith_reg_operand” “r”)))] "" “cmpne %0,%1”)
(define_insn “cmpneisi_t” [(set (reg:CC 17) (ne:CC (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (match_operand:SI 1 “mcore_arith_K_operand” “K”)))] "" “cmpnei %0,%1”)
(define_insn “cmpgtsi_t” [(set (reg:CC 17) (gt:CC (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (match_operand:SI 1 “mcore_arith_reg_operand” “r”)))] "" “cmplt %1,%0”)
(define_insn "" [(set (reg:CC 17) (gt:CC (plus:SI (match_operand:SI 0 “mcore_arith_reg_operand” “+r”) (const_int -1)) (const_int 0))) (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1)))] "" “decgt %0”)
(define_insn “cmpltsi_t” [(set (reg:CC 17) (lt:CC (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (match_operand:SI 1 “mcore_arith_reg_operand” “r”)))] "" “cmplt %0,%1”)
; cmplti is 1-32 (define_insn “cmpltisi_t” [(set (reg:CC 17) (lt:CC (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (match_operand:SI 1 “mcore_arith_J_operand” “J”)))] "" “cmplti %0,%1”)
; covers cmplti x,0 (define_insn "" [(set (reg:CC 17) (lt:CC (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (const_int 0)))] "" “btsti %0,31”)
(define_insn "" [(set (reg:CC 17) (lt:CC (plus:SI (match_operand:SI 0 “mcore_arith_reg_operand” “+r”) (const_int -1)) (const_int 0))) (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1)))] "" “declt %0”)
;; ------------------------------------------------------------------------- ;; SImode unsigned integer comparisons ;; -------------------------------------------------------------------------
(define_insn “cmpgeusi_t” [(set (reg:CC 17) (geu:CC (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (match_operand:SI 1 “mcore_arith_reg_operand” “r”)))] "" “cmphs %0,%1”)
(define_insn “cmpgeusi_0” [(set (reg:CC 17) (geu:CC (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (const_int 0)))] "" “cmpnei %0, 0”)
(define_insn “cmpleusi_t” [(set (reg:CC 17) (leu:CC (match_operand:SI 0 “mcore_arith_reg_operand” “r”) (match_operand:SI 1 “mcore_arith_reg_operand” “r”)))] "" “cmphs %1,%0”)
;; ------------------------------------------------------------------------- ;; Logical operations ;; -------------------------------------------------------------------------
;; Logical AND clearing a single bit. andsi3 knows that we have this ;; pattern and allows the constant literal pass through. ;;
;; RBE 2/97: don‘t need this pattern any longer... ;; RBE: I don’t think we need both “S” and exact_log2() clauses. ;;(define_insn "" ;; [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) ;; (and:SI (match_operand:SI 1 “mcore_arith_reg_operand” “%0”) ;; (match_operand:SI 2 “const_int_operand” “S”)))] ;; “mcore_arith_S_operand (operands[2])” ;; “bclri %0,%Q2”) ;;
(define_insn “andnsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (and:SI (not:SI (match_operand:SI 1 “mcore_arith_reg_operand” “r”)) (match_operand:SI 2 “mcore_arith_reg_operand” “0”)))] "" “andn %0,%1”)
(define_expand “andsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” "") (and:SI (match_operand:SI 1 “mcore_arith_reg_operand” "") (match_operand:SI 2 “nonmemory_operand” "")))] "" " { if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0 && ! mcore_arith_S_operand (operands[2])) { HOST_WIDE_INT not_value = ~ INTVAL (operands[2]);
if ( CONST_OK_FOR_I (not_value) || CONST_OK_FOR_M (not_value) || CONST_OK_FOR_N (not_value)) { operands[2] = copy_to_mode_reg (SImode, GEN_INT (not_value)); emit_insn (gen_andnsi3 (operands[0], operands[2], operands[1])); DONE; } }
if (! mcore_arith_K_S_operand (operands[2], SImode)) operands[2] = copy_to_mode_reg (SImode, operands[2]); }")
(define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,r,r,r”) (and:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0,0,r,0”) (match_operand:SI 2 “mcore_arith_any_imm_operand” “r,K,0,S”)))] “TARGET_RELAX_IMM” “* { switch (which_alternative) { case 0: return "and %0,%2"; case 1: return "andi %0,%2"; case 2: return "and %0,%1"; /* case -1: return "bclri %0,%Q2"; will not happen */ case 3: return mcore_output_bclri (operands[0], INTVAL (operands[2])); default: gcc_unreachable (); } }”)
;; This was the old “S” which was “!(2^n)” */ ;; case -1: return "bclri %0,%Q2"; will not happen */
(define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,r,r,r”) (and:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0,0,r,0”) (match_operand:SI 2 “mcore_arith_K_S_operand” “r,K,0,S”)))] “!TARGET_RELAX_IMM” “* { switch (which_alternative) { case 0: return "and %0,%2"; case 1: return "andi %0,%2"; case 2: return "and %0,%1"; case 3: return mcore_output_bclri (operands[0], INTVAL (operands[2])); default: gcc_unreachable (); } }”)
;(define_insn “iorsi3” ; [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) ; (ior:SI (match_operand:SI 1 “mcore_arith_reg_operand” “%0”) ; (match_operand:SI 2 “mcore_arith_reg_operand” “r”)))] ; "" ; “or %0,%2”)
; need an expand to resolve ambiguity betw. the two iors below. (define_expand “iorsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” "") (ior:SI (match_operand:SI 1 “mcore_arith_reg_operand” "") (match_operand:SI 2 “nonmemory_operand” "“)))] "" " { if (! mcore_arith_M_operand (operands[2], SImode)) operands[2] = copy_to_mode_reg (SImode, operands[2]); }”)
(define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,r,r”) (ior:SI (match_operand:SI 1 “mcore_arith_reg_operand” “%0,0,0”) (match_operand:SI 2 “mcore_arith_any_imm_operand” “r,M,T”)))] “TARGET_RELAX_IMM” “* { switch (which_alternative) { case 0: return "or %0,%2"; case 1: return "bseti %0,%P2"; case 2: return mcore_output_bseti (operands[0], INTVAL (operands[2])); default: gcc_unreachable (); } }”)
(define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,r,r”) (ior:SI (match_operand:SI 1 “mcore_arith_reg_operand” “%0,0,0”) (match_operand:SI 2 “mcore_arith_M_operand” “r,M,T”)))] “!TARGET_RELAX_IMM” “* { switch (which_alternative) { case 0: return "or %0,%2"; case 1: return "bseti %0,%P2"; case 2: return mcore_output_bseti (operands[0], INTVAL (operands[2])); default: gcc_unreachable (); } }”)
;(define_insn "" ; [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) ; (ior:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0”) ; (match_operand:SI 2 “const_int_operand” “M”)))] ; “exact_log2 (INTVAL (operands[2])) >= 0” ; “bseti %0,%P2”)
;(define_insn "" ; [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) ; (ior:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0”) ; (match_operand:SI 2 “const_int_operand” “i”)))] ; “mcore_num_ones (INTVAL (operands[2])) < 3” ; “* return mcore_output_bseti (operands[0], INTVAL (operands[2]));”)
(define_insn “xorsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (xor:SI (match_operand:SI 1 “mcore_arith_reg_operand” “%0”) (match_operand:SI 2 “mcore_arith_reg_operand” “r”)))] "" “xor %0,%2”)
;; ------------------------------------------------------------------------- ;; Shifts and rotates ;; -------------------------------------------------------------------------
;; Only allow these if the shift count is a convenient constant. (define_expand “rotlsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” "") (rotate:SI (match_operand:SI 1 “mcore_arith_reg_operand” "") (match_operand:SI 2 “nonmemory_operand” "")))] "" "if (! mcore_literal_K_operand (operands[2], SImode)) FAIL; ")
;; We can only do constant rotates, which is what this pattern provides. ;; The combiner will put it together for us when we do: ;; (x << N) | (x >> (32 - N)) (define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (rotate:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0”) (match_operand:SI 2 “mcore_literal_K_operand” “K”)))] "" “rotli %0,%2” [(set_attr “type” “shift”)])
(define_insn “ashlsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,r”) (ashift:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0,0”) (match_operand:SI 2 “mcore_arith_K_operand_not_0” “r,K”)))] "" “@ lsl %0,%2 lsli %0,%2” [(set_attr “type” “shift”)])
(define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (ashift:SI (const_int 1) (match_operand:SI 1 “mcore_arith_reg_operand” “r”)))] "" “bgenr %0,%1” [(set_attr “type” “shift”)])
(define_insn “ashrsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,r”) (ashiftrt:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0,0”) (match_operand:SI 2 “mcore_arith_K_operand_not_0” “r,K”)))] "" “@ asr %0,%2 asri %0,%2” [(set_attr “type” “shift”)])
(define_insn “lshrsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,r”) (lshiftrt:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0,0”) (match_operand:SI 2 “mcore_arith_K_operand_not_0” “r,K”)))] "" “@ lsr %0,%2 lsri %0,%2” [(set_attr “type” “shift”)])
;(define_expand “ashldi3” ; [(parallel[(set (match_operand:DI 0 “mcore_arith_reg_operand” "") ; (ashift:DI (match_operand:DI 1 “mcore_arith_reg_operand” "") ; (match_operand:DI 2 “immediate_operand” "“))) ; ; (clobber (reg:CC 17))])] ;
; ""
; "
;{
; if (GET_CODE (operands[2]) != CONST_INT ; || INTVAL (operands[2]) != 1) ; FAIL; ;}”) ; ;(define_insn "" ; [(set (match_operand:DI 0 “mcore_arith_reg_operand” “=r”) ; (ashift:DI (match_operand:DI 1 “mcore_arith_reg_operand” “0”) ; (const_int 1))) ; (clobber (reg:CC 17))] ; "" ; “lsli %R0,0;rotli %0,0” ; [(set_attr “length” “4”) (set_attr “type” “shift”)])
;; ------------------------------------------------------------------------- ;; Index instructions ;; ------------------------------------------------------------------------- ;; The second of each set of patterns is borrowed from the alpha.md file. ;; These variants of the above insns can occur if the second operand ;; is the frame pointer. This is a kludge, but there doesn't ;; seem to be a way around it. Only recognize them while reloading.
;; We must use reload_operand for some operands in case frame pointer ;; elimination put a MEM with invalid address there. Otherwise, ;; the result of the substitution will not match this pattern, and reload ;; will not be able to correctly fix the result.
;; indexing longlongs or doubles (8 bytes)
(define_insn “indexdi_t” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (plus:SI (mult:SI (match_operand:SI 1 “mcore_arith_reg_operand” “r”) (const_int 8)) (match_operand:SI 2 “mcore_arith_reg_operand” “0”)))] "" “* if (! mcore_is_same_reg (operands[1], operands[2])) { output_asm_insn ("ixw\t%0,%1", operands); output_asm_insn ("ixw\t%0,%1", operands); } else { output_asm_insn ("ixh\t%0,%1", operands); output_asm_insn ("ixh\t%0,%1", operands); } return ""; " ;; if operands[1] == operands[2], the first option above is wrong! -- dac ;; was this... -- dac ;; ixw %0,%1;ixw %0,%1”
[(set_attr “length” “4”)])
(define_insn "" [(set (match_operand:SI 0 “mcore_reload_operand” “=r,r,r”) (plus:SI (plus:SI (mult:SI (match_operand:SI 1 “mcore_reload_operand” “r,r,r”) (const_int 8)) (match_operand:SI 2 “mcore_arith_reg_operand” “0,0,0”)) (match_operand:SI 3 “mcore_addsub_operand” “r,J,L”)))] “reload_in_progress” “@ ixw %0,%1;ixw %0,%1;addu %0,%3 ixw %0,%1;ixw %0,%1;addi %0,%3 ixw %0,%1;ixw %0,%1;subi %0,%M3” [(set_attr “length” “6”)])
;; indexing longs (4 bytes)
(define_insn “indexsi_t” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (plus:SI (mult:SI (match_operand:SI 1 “mcore_arith_reg_operand” “r”) (const_int 4)) (match_operand:SI 2 “mcore_arith_reg_operand” “0”)))] "" “ixw %0,%1”)
(define_insn "" [(set (match_operand:SI 0 “mcore_reload_operand” “=r,r,r”) (plus:SI (plus:SI (mult:SI (match_operand:SI 1 “mcore_reload_operand” “r,r,r”) (const_int 4)) (match_operand:SI 2 “mcore_arith_reg_operand” “0,0,0”)) (match_operand:SI 3 “mcore_addsub_operand” “r,J,L”)))] “reload_in_progress” “@ ixw %0,%1;addu %0,%3 ixw %0,%1;addi %0,%3 ixw %0,%1;subi %0,%M3” [(set_attr “length” “4”)])
;; indexing shorts (2 bytes)
(define_insn “indexhi_t” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (plus:SI (mult:SI (match_operand:SI 1 “mcore_arith_reg_operand” “r”) (const_int 2)) (match_operand:SI 2 “mcore_arith_reg_operand” “0”)))] "" “ixh %0,%1”)
(define_insn "" [(set (match_operand:SI 0 “mcore_reload_operand” “=r,r,r”) (plus:SI (plus:SI (mult:SI (match_operand:SI 1 “mcore_reload_operand” “r,r,r”) (const_int 2)) (match_operand:SI 2 “mcore_arith_reg_operand” “0,0,0”)) (match_operand:SI 3 “mcore_addsub_operand” “r,J,L”)))] “reload_in_progress” “@ ixh %0,%1;addu %0,%3 ixh %0,%1;addi %0,%3 ixh %0,%1;subi %0,%M3” [(set_attr “length” “4”)])
;; ;; Other sizes may be handy for indexing. ;; the tradeoffs to consider when adding these are ;; code size, execution time [vs. mul it is easy to win], ;; and register pressure -- these patterns don't use an extra ;; register to build the offset from the base ;; and whether the compiler will not come up with some other idiom. ;;
;; ------------------------------------------------------------------------- ;; Addition, Subtraction instructions ;; -------------------------------------------------------------------------
(define_expand “addsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” "") (plus:SI (match_operand:SI 1 “mcore_arith_reg_operand” "") (match_operand:SI 2 “nonmemory_operand” "")))] "" " { /* If this is an add to the frame pointer, then accept it as is so that we can later fold in the fp/sp offset from frame pointer elimination. */ if (flag_omit_frame_pointer && GET_CODE (operands[1]) == REG && (REGNO (operands[1]) == VIRTUAL_STACK_VARS_REGNUM || REGNO (operands[1]) == FRAME_POINTER_REGNUM)) { emit_insn (gen_addsi3_fp (operands[0], operands[1], operands[2])); DONE; }
/* Convert adds to subtracts if this makes loading the constant cheaper. But only if we are allowed to generate new pseudos. */ if (! (reload_in_progress || reload_completed) && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < -32) { HOST_WIDE_INT neg_value = - INTVAL (operands[2]);
if ( CONST_OK_FOR_I (neg_value) || CONST_OK_FOR_M (neg_value) || CONST_OK_FOR_N (neg_value)) { operands[2] = copy_to_mode_reg (SImode, GEN_INT (neg_value)); emit_insn (gen_subsi3 (operands[0], operands[1], operands[2])); DONE; } }
if (! mcore_addsub_operand (operands[2], SImode)) operands[2] = copy_to_mode_reg (SImode, operands[2]); }")
;; RBE: for some constants which are not in the range which allows ;; us to do a single operation, we will try a paired addi/addi instead ;; of a movi/addi. This relieves some register pressure at the expense ;; of giving away some potential constant reuse. ;; ;; RBE 6/17/97: this didn't buy us anything, but I keep the pattern ;; for later reference ;; ;; (define_insn “addsi3_i2” ;; [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) ;; (plus:SI (match_operand:SI 1 “mcore_arith_reg_operand” “%0”) ;; (match_operand:SI 2 “const_int_operand” “g”)))] ;; “GET_CODE(operands[2]) == CONST_INT ;; && ((INTVAL (operands[2]) > 32 && INTVAL(operands[2]) <= 64) ;; || (INTVAL (operands[2]) < -32 && INTVAL(operands[2]) >= -64))” ;; “* ;; { ;; HOST_WIDE_INT n = INTVAL(operands[2]); ;; if (n > 0) ;; { ;; operands[2] = GEN_INT(n - 32); ;; return "addi\t%0,32;addi\t%0,%2"; ;; } ;; else ;; { ;; n = (-n); ;; operands[2] = GEN_INT(n - 32); ;; return "subi\t%0,32;subi\t%0,%2"; ;; } ;; }” ;; [(set_attr “length” “4”)])
(define_insn “addsi3_i” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,r,r”) (plus:SI (match_operand:SI 1 “mcore_arith_reg_operand” “%0,0,0”) (match_operand:SI 2 “mcore_addsub_operand” “r,J,L”)))] "" “@ addu %0,%2 addi %0,%2 subi %0,%M2”)
;; This exists so that address computations based on the frame pointer ;; can be folded in when frame pointer elimination occurs. Ordinarily ;; this would be bad because it allows insns which would require reloading, ;; but without it, we get multiple adds where one would do.
(define_insn “addsi3_fp” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,r,r”) (plus:SI (match_operand:SI 1 “mcore_arith_reg_operand” “%0,0,0”) (match_operand:SI 2 “immediate_operand” “r,J,L”)))] “flag_omit_frame_pointer && (reload_in_progress || reload_completed || REGNO (operands[1]) == FRAME_POINTER_REGNUM)” “@ addu %0,%2 addi %0,%2 subi %0,%M2”)
;; RBE: for some constants which are not in the range which allows ;; us to do a single operation, we will try a paired addi/addi instead ;; of a movi/addi. This relieves some register pressure at the expense ;; of giving away some potential constant reuse. ;; ;; RBE 6/17/97: this didn't buy us anything, but I keep the pattern ;; for later reference ;; ;; (define_insn “subsi3_i2” ;; [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) ;; (plus:SI (match_operand:SI 1 “mcore_arith_reg_operand” “%0”) ;; (match_operand:SI 2 “const_int_operand” “g”)))] ;; “TARGET_RBETEST && GET_CODE(operands[2]) == CONST_INT ;; && ((INTVAL (operands[2]) > 32 && INTVAL(operands[2]) <= 64) ;; || (INTVAL (operands[2]) < -32 && INTVAL(operands[2]) >= -64))” ;; “* ;; { ;; HOST_WIDE_INT n = INTVAL(operands[2]); ;; if ( n > 0) ;; { ;; operands[2] = GEN_INT( n - 32); ;; return "subi\t%0,32;subi\t%0,%2"; ;; } ;; else ;; { ;; n = (-n); ;; operands[2] = GEN_INT(n - 32); ;; return "addi\t%0,32;addi\t%0,%2"; ;; } ;; }” ;; [(set_attr “length” “4”)])
;(define_insn “subsi3” ; [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,r,r,r”) ; (minus:SI (match_operand:SI 1 “mcore_arith_K_operand” “0,0,r,K”) ; (match_operand:SI 2 “mcore_arith_J_operand” “r,J,0,0”)))] ; "" ; “@ ; sub %0,%2 ; subi %0,%2 ; rsub %0,%1 ; rsubi %0,%1”)
(define_insn “subsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,r,r”) (minus:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0,0,r”) (match_operand:SI 2 “mcore_arith_J_operand” “r,J,0”)))] "" “@ subu %0,%2 subi %0,%2 rsub %0,%1”)
(define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (minus:SI (match_operand:SI 1 “mcore_literal_K_operand” “K”) (match_operand:SI 2 “mcore_arith_reg_operand” “0”)))] "" “rsubi %0,%1”)
(define_insn “adddi3” [(set (match_operand:DI 0 “mcore_arith_reg_operand” “=&r”) (plus:DI (match_operand:DI 1 “mcore_arith_reg_operand” “%0”) (match_operand:DI 2 “mcore_arith_reg_operand” “r”))) (clobber (reg:CC 17))] "" “* { if (TARGET_LITTLE_END) return "cmplt %0,%0;addc %0,%2;addc %R0,%R2"; return "cmplt %R0,%R0;addc %R0,%R2;addc %0,%2"; }” [(set_attr “length” “6”)])
;; special case for “longlong += 1” (define_insn "" [(set (match_operand:DI 0 “mcore_arith_reg_operand” “=&r”) (plus:DI (match_operand:DI 1 “mcore_arith_reg_operand” “0”) (const_int 1))) (clobber (reg:CC 17))] "" “* { if (TARGET_LITTLE_END) return "addi %0,1;cmpnei %0,0;incf %R0"; return "addi %R0,1;cmpnei %R0,0;incf %0"; }” [(set_attr “length” “6”)])
;; special case for “longlong -= 1” (define_insn "" [(set (match_operand:DI 0 “mcore_arith_reg_operand” “=&r”) (plus:DI (match_operand:DI 1 “mcore_arith_reg_operand” “0”) (const_int -1))) (clobber (reg:CC 17))] "" “* { if (TARGET_LITTLE_END) return "cmpnei %0,0;decf %R0;subi %0,1"; return "cmpnei %R0,0;decf %0;subi %R0,1"; }” [(set_attr “length” “6”)])
;; special case for “longlong += const_int” ;; we have to use a register for the const_int because we don‘t ;; have an unsigned compare immediate... only +/- 1 get to ;; play the no-extra register game because they compare with 0. ;; This winds up working out for any literal that is synthesized ;; with a single instruction. The more complicated ones look ;; like the get broken into subreg’s to get initialized too soon ;; for us to catch here. -- RBE 4/25/96 ;; only allow for-sure positive values.
(define_insn "" [(set (match_operand:DI 0 “mcore_arith_reg_operand” “=&r”) (plus:DI (match_operand:DI 1 “mcore_arith_reg_operand” “0”) (match_operand:SI 2 “const_int_operand” “r”))) (clobber (reg:CC 17))] “GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 0 && ! (INTVAL (operands[2]) & 0x80000000)” “* { gcc_assert (GET_MODE (operands[2]) == SImode); if (TARGET_LITTLE_END) return "addu %0,%2;cmphs %0,%2;incf %R0"; return "addu %R0,%2;cmphs %R0,%2;incf %0"; }” [(set_attr “length” “6”)])
;; optimize “long long” + “unsigned long” ;; won't trigger because of how the extension is expanded upstream. ;; (define_insn "" ;; [(set (match_operand:DI 0 “mcore_arith_reg_operand” “=&r”) ;; (plus:DI (match_operand:DI 1 “mcore_arith_reg_operand” “%0”) ;; (zero_extend:DI (match_operand:SI 2 “mcore_arith_reg_operand” “r”)))) ;; (clobber (reg:CC 17))] ;; “0” ;; “cmplt %R0,%R0;addc %R0,%2;inct %0” ;; [(set_attr “length” “6”)])
;; optimize “long long” + “signed long” ;; won't trigger because of how the extension is expanded upstream. ;; (define_insn "" ;; [(set (match_operand:DI 0 “mcore_arith_reg_operand” “=&r”) ;; (plus:DI (match_operand:DI 1 “mcore_arith_reg_operand” “%0”) ;; (sign_extend:DI (match_operand:SI 2 “mcore_arith_reg_operand” “r”)))) ;; (clobber (reg:CC 17))] ;; “0” ;; “cmplt %R0,%R0;addc %R0,%2;inct %0;btsti %2,31;dect %0” ;; [(set_attr “length” “6”)])
(define_insn “subdi3” [(set (match_operand:DI 0 “mcore_arith_reg_operand” “=&r”) (minus:DI (match_operand:DI 1 “mcore_arith_reg_operand” “0”) (match_operand:DI 2 “mcore_arith_reg_operand” “r”))) (clobber (reg:CC 17))] "" “* { if (TARGET_LITTLE_END) return "cmphs %0,%0;subc %0,%2;subc %R0,%R2"; return "cmphs %R0,%R0;subc %R0,%R2;subc %0,%2"; }” [(set_attr “length” “6”)])
;; ------------------------------------------------------------------------- ;; Multiplication instructions ;; -------------------------------------------------------------------------
(define_insn “mulsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (mult:SI (match_operand:SI 1 “mcore_arith_reg_operand” “%0”) (match_operand:SI 2 “mcore_arith_reg_operand” “r”)))] "" “mult %0,%2”)
;; ;; 32/32 signed division -- added to the MCORE instruction set spring 1997 ;; ;; Different constraints based on the architecture revision... ;; (define_expand “divsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” "") (div:SI (match_operand:SI 1 “mcore_arith_reg_operand” "") (match_operand:SI 2 “mcore_arith_reg_operand” "")))] “TARGET_DIV” "")
;; MCORE Revision 1.50: restricts the divisor to be in r1. (6/97) ;; (define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (div:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0”) (match_operand:SI 2 “mcore_arith_reg_operand” “b”)))] “TARGET_DIV” “divs %0,%2”)
;; ;; 32/32 signed division -- added to the MCORE instruction set spring 1997 ;; ;; Different constraints based on the architecture revision... ;; (define_expand “udivsi3” [(set (match_operand:SI 0 “mcore_arith_reg_operand” "") (udiv:SI (match_operand:SI 1 “mcore_arith_reg_operand” "") (match_operand:SI 2 “mcore_arith_reg_operand” "")))] “TARGET_DIV” "")
;; MCORE Revision 1.50: restricts the divisor to be in r1. (6/97) (define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (udiv:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0”) (match_operand:SI 2 “mcore_arith_reg_operand” “b”)))] “TARGET_DIV” “divu %0,%2”)
;; ------------------------------------------------------------------------- ;; Unary arithmetic ;; -------------------------------------------------------------------------
(define_insn “negsi2” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (neg:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0”)))] "" “* { return "rsubi %0,0"; }”)
(define_insn “abssi2” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (abs:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0”)))] "" “abs %0”)
(define_insn “negdi2” [(set (match_operand:DI 0 “mcore_arith_reg_operand” “=&r”) (neg:DI (match_operand:DI 1 “mcore_arith_reg_operand” “0”))) (clobber (reg:CC 17))] "" “* { if (TARGET_LITTLE_END) return "cmpnei %0,0\n\trsubi %0,0\n\tnot %R0\n\tincf %R0"; return "cmpnei %R0,0\n\trsubi %R0,0\n\tnot %0\n\tincf %0"; }” [(set_attr “length” “8”)])
(define_insn “one_cmplsi2” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (not:SI (match_operand:SI 1 “mcore_arith_reg_operand” “0”)))] "" “not %0”)
;; ------------------------------------------------------------------------- ;; Zero extension instructions ;; -------------------------------------------------------------------------
(define_expand “zero_extendhisi2” [(set (match_operand:SI 0 “mcore_arith_reg_operand” "") (zero_extend:SI (match_operand:HI 1 “mcore_arith_reg_operand” "")))] "" "")
(define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,r”) (zero_extend:SI (match_operand:HI 1 “general_operand” “0,m”)))] "" “@ zexth %0 ld.h %0,%1” [(set_attr “type” “shift,load”)])
;; ldh gives us a free zero-extension. The combiner picks up on this. (define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (zero_extend:SI (mem:HI (match_operand:SI 1 “mcore_arith_reg_operand” “r”))))] "" “ld.h %0,(%1)” [(set_attr “type” “load”)])
(define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (zero_extend:SI (mem:HI (plus:SI (match_operand:SI 1 “mcore_arith_reg_operand” “r”) (match_operand:SI 2 “const_int_operand” "")))))] “(INTVAL (operands[2]) >= 0) && (INTVAL (operands[2]) < 32) && ((INTVAL (operands[2])&1) == 0)” “ld.h %0,(%1,%2)” [(set_attr “type” “load”)])
(define_expand “zero_extendqisi2” [(set (match_operand:SI 0 “mcore_arith_reg_operand” "") (zero_extend:SI (match_operand:QI 1 “general_operand” "")))] "" "")
;; RBE: XXX: we don't recognize that the xtrb3 kills the CC register. (define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r,b,r”) (zero_extend:SI (match_operand:QI 1 “general_operand” “0,r,m”)))] "" “@ zextb %0 xtrb3 %0,%1 ld.b %0,%1” [(set_attr “type” “shift,shift,load”)])
;; ldb gives us a free zero-extension. The combiner picks up on this. (define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (zero_extend:SI (mem:QI (match_operand:SI 1 “mcore_arith_reg_operand” “r”))))] "" “ld.b %0,(%1)” [(set_attr “type” “load”)])
(define_insn "" [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (zero_extend:SI (mem:QI (plus:SI (match_operand:SI 1 “mcore_arith_reg_operand” “r”) (match_operand:SI 2 “const_int_operand” "")))))] “(INTVAL (operands[2]) >= 0) && (INTVAL (operands[2]) < 16)” “ld.b %0,(%1,%2)” [(set_attr “type” “load”)])
(define_expand “zero_extendqihi2” [(set (match_operand:HI 0 “mcore_arith_reg_operand” "") (zero_extend:HI (match_operand:QI 1 “general_operand” "")))] "" "")
;; RBE: XXX: we don't recognize that the xtrb3 kills the CC register. (define_insn "" [(set (match_operand:HI 0 “mcore_arith_reg_operand” “=r,b,r”) (zero_extend:HI (match_operand:QI 1 “general_operand” “0,r,m”)))] "" “@ zextb %0 xtrb3 %0,%1 ld.b %0,%1” [(set_attr “type” “shift,shift,load”)])
;; ldb gives us a free zero-extension. The combiner picks up on this. ;; this doesn‘t catch references that are into a structure. ;; note that normally the compiler uses the above insn, unless it turns ;; out that we’re dealing with a volatile... (define_insn "" [(set (match_operand:HI 0 “mcore_arith_reg_operand” “=r”) (zero_extend:HI (mem:QI (match_operand:SI 1 “mcore_arith_reg_operand” “r”))))] "" “ld.b %0,(%1)” [(set_attr “type” “load”)])
(define_insn "" [(set (match_operand:HI 0 “mcore_arith_reg_operand” “=r”) (zero_extend:HI (mem:QI (plus:SI (match_operand:SI 1 “mcore_arith_reg_operand” “r”) (match_operand:SI 2 “const_int_operand” "")))))] “(INTVAL (operands[2]) >= 0) && (INTVAL (operands[2]) < 16)” “ld.b %0,(%1,%2)” [(set_attr “type” “load”)])
;; ------------------------------------------------------------------------- ;; Sign extension instructions ;; -------------------------------------------------------------------------
(define_expand “extendsidi2” [(set (match_operand:DI 0 “mcore_arith_reg_operand” “=r”) (match_operand:SI 1 “mcore_arith_reg_operand” “r”))] "" " { int low, high;
if (TARGET_LITTLE_END) low = 0, high = 4; else low = 4, high = 0; emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], low), operands[1])); emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], high), gen_rtx_ASHIFTRT (SImode, gen_rtx_SUBREG (SImode, operands[0], low), GEN_INT (31)))); DONE;
}" )
(define_insn “extendhisi2” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (sign_extend:SI (match_operand:HI 1 “mcore_arith_reg_operand” “0”)))] "" “sexth %0”)
(define_insn “extendqisi2” [(set (match_operand:SI 0 “mcore_arith_reg_operand” “=r”) (sign_extend:SI (match_operand:QI 1 “mcore_arith_reg_operand” “0”)))] "" “sextb %0”)
(define_insn “extendqihi2” [(set (match_operand:HI 0 “mcore_arith_reg_operand” “=r”) (sign_extend:HI (match_operand:QI 1 “mcore_arith_reg_operand” “0”)))] "" “sextb %0”)
;; ------------------------------------------------------------------------- ;; Move instructions ;; -------------------------------------------------------------------------
;; SImode
(define_expand “movsi” [(set (match_operand:SI 0 “general_operand” "") (match_operand:SI 1 “general_operand” "“))] "" " { if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (SImode, operands[1]); }”)
(define_insn "" [(set (match_operand:SI 0 “mcore_general_movdst_operand” “=r,r,a,r,a,r,m”) (match_operand:SI 1 “mcore_general_movsrc_operand” “r,P,i,c,R,m,r”))] “(register_operand (operands[0], SImode) || register_operand (operands[1], SImode))” “* return mcore_output_move (insn, operands, SImode);” [(set_attr “type” “move,move,move,move,load,load,store”)])
;; ;; HImode ;;
(define_expand “movhi” [(set (match_operand:HI 0 “general_operand” "") (match_operand:HI 1 “general_operand” "“))] "" " { if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (HImode, operands[1]); else if (CONSTANT_P (operands[1]) && (GET_CODE (operands[1]) != CONST_INT || (! CONST_OK_FOR_I (INTVAL (operands[1])) && ! CONST_OK_FOR_M (INTVAL (operands[1])) && ! CONST_OK_FOR_N (INTVAL (operands[1])))) && ! reload_completed && ! reload_in_progress) { rtx reg = gen_reg_rtx (SImode); emit_insn (gen_movsi (reg, operands[1])); operands[1] = gen_lowpart (HImode, reg); } }”)
(define_insn "" [(set (match_operand:HI 0 “mcore_general_movdst_operand” “=r,r,a,r,r,m”) (match_operand:HI 1 “mcore_general_movsrc_operand” “r,P,i,c,m,r”))] “(register_operand (operands[0], HImode) || register_operand (operands[1], HImode))” “* return mcore_output_move (insn, operands, HImode);” [(set_attr “type” “move,move,move,move,load,store”)])
;; ;; QImode ;;
(define_expand “movqi” [(set (match_operand:QI 0 “general_operand” "") (match_operand:QI 1 “general_operand” "“))] "" " { if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (QImode, operands[1]); else if (CONSTANT_P (operands[1]) && (GET_CODE (operands[1]) != CONST_INT || (! CONST_OK_FOR_I (INTVAL (operands[1])) && ! CONST_OK_FOR_M (INTVAL (operands[1])) && ! CONST_OK_FOR_N (INTVAL (operands[1])))) && ! reload_completed && ! reload_in_progress) { rtx reg = gen_reg_rtx (SImode); emit_insn (gen_movsi (reg, operands[1])); operands[1] = gen_lowpart (QImode, reg); } }”)
(define_insn "" [(set (match_operand:QI 0 “mcore_general_movdst_operand” “=r,r,a,r,r,m”) (match_operand:QI 1 “mcore_general_movsrc_operand” “r,P,i,c,m,r”))] “(register_operand (operands[0], QImode) || register_operand (operands[1], QImode))” “* return mcore_output_move (insn, operands, QImode);” [(set_attr “type” “move,move,move,move,load,store”)])
;; DImode
(define_expand “movdi” [(set (match_operand:DI 0 “general_operand” "") (match_operand:DI 1 “general_operand” "“))] "" " { if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (DImode, operands[1]); else if (GET_CODE (operands[1]) == CONST_INT && ! CONST_OK_FOR_I (INTVAL (operands[1])) && ! CONST_OK_FOR_M (INTVAL (operands[1])) && ! CONST_OK_FOR_N (INTVAL (operands[1]))) { int i; for (i = 0; i < UNITS_PER_WORD * 2; i += UNITS_PER_WORD) emit_move_insn (simplify_gen_subreg (SImode, operands[0], DImode, i), simplify_gen_subreg (SImode, operands[1], DImode, i)); DONE; } }”)
(define_insn “movdi_i” [(set (match_operand:DI 0 “nonimmediate_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 “nonimmediate_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 “nonimmediate_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 (Pmode, 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 (Pmode, 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 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; 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_code_label *out_label = 0; rtx_code_label *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 } }")