+2006-03-08 DJ Delorie <dj@redhat.com>
+
+ * config/m32c/addsub.md (addqi3): Disparage a0/a1.
+ (addpsi3): Expand to include memory operands. Remove
+ reload-specific splits.
+ * config/m32c/bitops.md (bset_qi, bset_hi, bclr_qi): New.
+ (andqi3_16, andhi3_16, iorqi3_16, iorhi3_16): New.
+ (andqi3_24, andhi3_24, iorqi3_24, iorhi3_24): New.
+ (andqi3, andhi3, iorqi3, iorhi3): Convert to expanders.
+ (shift1_qi, shift1_hi, insv): New.
+ * config/m32c/cond.md (cbranchqi4, cbranchhi4): Remove.
+ (cbranch<mode>4, stzx_16, stzx_24_<mode>, stzx_reversed,
+ cmp<mode>, b<code>, s<code>, s<code>_24, movqicc, movhicc,
+ cond_to_int): New.
+ * config/m32c/m32c-protos.h: Update as needed.
+ * config/m32c/m32c.c (m32c_reg_class_from_constraint): Don't
+ default the Rcr, Rcl, Raw, and Ral constraints. Add Ra0 and Ra1.
+ Fail for unrecognized R* constraints.
+ (m32c_cannot_change_mode_class): Be more picky about pseudos.
+ (m32c_const_ok_for_constraint_p): Add Imb, Imw, and I00.
+ (m32c_extra_constraint_p2): Allow (mem (plus (plus fb int) int)).
+ Add Sp constraint.
+ (m32c_init_libfuncs): New.
+ (m32c_legitimate_address_p): Add debug wrapper.
+ (m32c_rtx_costs): New.
+ (m32c_address_cost): New.
+ (conversions): Add 'B' prefix.
+ (m32c_print_operand): 'h' and 'H' pick lower and upper halves of
+ operands, or word regnames for QI operands. 'B' prints bit
+ position.
+ (m32c_expand_setmemhi): New.
+ (m32c_expand_movmemhi): New.
+ (m32c_expand_movstr): New.
+ (m32c_expand_cmpstr): New.
+ (m32c_prepare_shift): Shift counts are limited to 16 bits at a time.
+ (m32c_expand_neg_mulpsi3): Handle non-ints.
+ (m32c_cmp_flg_0): New.
+ (m32c_expand_movcc): New.
+ (m32c_expand_insv): New.
+ (m32c_scc_pattern): New.
+ * config/m32c/m32c.h (reg classes): Add AO_REGS and A1_REGS. Take
+ a0/a1 out of SIregs.
+ (STORE_FLAG_VALUE): New.
+ * config/m32c/m32c.md: Add unspecs for string moves. Define various mode and
+ code macros.
+ (no_insn): New.
+ * config/m32c/mov.md: Make constraints more liberal.
+ (zero_extendqihi2): Optimize r0/r1 case.
+ * config/m32c/muldiv.md (mulpsi3): Check for intvals.
+ * config/m32c/predicates.md (m32c_any_operand): New.
+ (m32c_nonimmediate_operand): New.
+ (m32c_hl_operand): New.
+ (m32c_r3_operand): New.
+ (ap_operand): New.
+ (ma_operand): New.
+ (memsym_operand): New.
+ (memimmed_operand): New.
+ (a_qi_operand): New.
+ (m32c_eqne_operator): New.
+ (m32c_1bit8_operand): New.
+ (m32c_1bit16_operand): New.
+ (m32c_1mask8_operand): New.
+ (m32c_1mask16_operand): New.
+ * config/m32c/blkmov.md: New file.
+ * config/m32c/t-m32c (MD_FILES): Add blkmov.
+
2006-03-08 Andreas Tobler <a.tobler@schweiz.ch>
* dwarf2out.c (expand_builtin_dwarf_sp_column): Make dwarf_regnum
(define_insn "addqi3"
[(set (match_operand:QI 0 "mra_or_sp_operand"
- "=SdRhl,SdRhl,??Rmm,??Rmm, Raa,Raa,SdRhl,??Rmm")
+ "=SdRhl,SdRhl,??Rmm,??Rmm, *Raa,*Raa,SdRhl,??Rmm")
(plus:QI (match_operand:QI 1 "mra_operand"
"%0,0,0,0, 0,0,0,0")
(match_operand:QI 2 "mrai_operand"
- "iSdRhl,?Rmm,iSdRhl,?Rmm, iSdRhl,?Rmm,Raa,Raa")))]
+ "iSdRhl,?Rmm,iSdRhl,?Rmm, iSdRhl,?Rmm,*Raa,*Raa")))]
""
"add.b\t%2,%0"
[(set_attr "flags" "oszc")]
)
(define_insn "addhi3"
- [(set (match_operand:HI 0 "nonimmediate_operand"
+ [(set (match_operand:HI 0 "m32c_nonimmediate_operand"
"=SdRhi,SdRhi,??Rmm,??Rmm, SdRhi,??Rmm, Rhi, Raw, Raw, !Rsp")
- (plus:HI (match_operand:HI 1 "general_operand"
+ (plus:HI (match_operand:HI 1 "m32c_any_operand"
"%0,0,0,0, 0,0, Raw, Rfb, Rfb, 0")
- (match_operand:HI 2 "general_operand"
+ (match_operand:HI 2 "m32c_any_operand"
"IU2sSdRhi,?Rmm,IU2sSdRhi,?Rmm, IM2,IM2, IS2IU2, I00, IS1, i")))]
""
"@
)
(define_insn "addpsi3"
- [(set (match_operand:PSI 0 "nonimmediate_operand" "=SdRpi,SdRpi,Rsp*Rmm, Rpi,Rpi,Rhi,&Rhi")
- (plus:PSI (match_operand:PSI 1 "nonimmediate_operand" "0,0,0, Raa,Rad,!Rcl,Rhi")
- (match_operand:PSI 2 "general_operand" "iSdRpi,?Rmm,i, i,IS2,i,!Rcl")))]
+ [(set (match_operand:PSI 0 "m32c_nonimmediate_operand" "=Rpi,Raa,SdRpi,SdRpi,Rsp*Rmm, Rpi,Rpi")
+ (plus:PSI (match_operand:PSI 1 "m32c_nonimmediate_operand" "0,0,0,0,0, Raa,Rad")
+ (match_operand:PSI 2 "m32c_any_operand" "Is3,IS1,iSdRpi,?Rmm,i, i,IS2")))]
"TARGET_A24"
"@
- add.%&\t%2,%0
- add.%&\t%2,%0
- add.%&\t%2,%0
+ add.l:q\t%2,%0
+ addx\t%2,%0
+ add.l\t%2,%0
+ add.l\t%2,%0
+ add.l\t%2,%0
mova\t%d2[%1],%0
- mova\t%D2[%1],%0
- #
- #"
- [(set_attr "flags" "oszc,oszc,oszc,*,*,oszc,oszc")]
- )
-
-; This is needed for reloading large frames.
-(define_split
- [(set (match_operand:PSI 0 "ra_operand" "")
- (plus:PSI (match_operand:PSI 1 "cr_operand" "")
- (match_operand:PSI 2 "immediate_operand" "")))]
- ""
- [(set (match_dup 0) (match_dup 1))
- (set (match_dup 0)
- (plus:PSI (match_dup 0)
- (match_dup 2)))]
- ""
- )
-
-; This is needed for reloading large frames.
-(define_split
- [(set (match_operand:PSI 0 "ra_operand" "")
- (plus:PSI (match_operand:PSI 1 "ra_operand" "")
- (match_operand:PSI 2 "cr_operand" "")))]
- ""
- [(set (match_dup 0) (match_dup 2))
- (set (match_dup 0)
- (plus:PSI (match_dup 0)
- (match_dup 1)))]
- ""
+ mova\t%D2[%1],%0"
+ [(set_attr "flags" "oszc,oszc,oszc,oszc,oszc,*,*")]
)
(define_insn "subqi3"
;; Bit-wise operations (and, ior, xor, shift)
-(define_insn "andqi3"
- [(set (match_operand:QI 0 "mra_operand" "=RhlSd,RhlSd,??Rmm,??Rmm")
- (and:QI (match_operand:QI 1 "mra_operand" "%0,0,0,0")
- (match_operand:QI 2 "mrai_operand" "iRhlSd,?Rmm,iRhlSd,?Rmm")))]
+; On the R8C and M16C, "address" for bit instructions is usually (but
+; not always!) the *bit* address, not the *byte* address. This
+; confuses gcc, so we avoid cases where gcc would produce the wrong
+; code. We're left with absolute addresses and registers, and the odd
+; case of shifting a bit by a variable.
+
+; On the M32C, "address" for bit instructions is a regular address,
+; and the bit number is stored in a separate field. Thus, we can let
+; gcc do more interesting things. However, the M32C cannot set all
+; the bits in a 16 bit register, which the R8C/M16C can do.
+
+; However, it all means that we end up with two sets of patterns, one
+; for each chip.
+
+;;----------------------------------------------------------------------
+
+;; First off, all the ways we can set one bit, other than plain IOR.
+
+(define_insn "bset_qi"
+ [(set (match_operand:QI 0 "memsym_operand" "+Si")
+ (ior:QI (subreg:QI (ashift:HI (const_int 1)
+ (subreg:QI (match_operand:HI 1 "a_qi_operand" "Raa") 0)) 0)
+ (match_operand:QI 2 "" "0")))]
+ "TARGET_A16"
+ "bset\t%0[%1]"
+ [(set_attr "flags" "sz")]
+ )
+
+(define_insn "bset_hi"
+ [(set (zero_extract:HI (match_operand:QI 0 "memsym_operand" "+Si")
+ (const_int 1)
+ (zero_extend:HI (subreg:QI (match_operand:HI 1 "a_qi_operand" "Raa") 0)))
+ (const_int 1))]
+ "TARGET_A16"
+ "bset\t%0[%1]"
+ [(set_attr "flags" "sz")]
+ )
+
+;;----------------------------------------------------------------------
+
+;; Now all the ways we can clear one bit, other than plain AND.
+
+; This is odd because the shift patterns use QI counts, but we can't
+; easily put QI in $aN without causing problems elsewhere.
+(define_insn "bclr_qi"
+ [(set (zero_extract:HI (match_operand:QI 0 "memsym_operand" "+Si")
+ (const_int 1)
+ (zero_extend:HI (subreg:QI (match_operand:HI 1 "a_qi_operand" "Raa") 0)))
+ (const_int 0))]
+ "TARGET_A16"
+ "bclr\t%0[%1]"
+ [(set_attr "flags" "sz")]
+ )
+
+
+;;----------------------------------------------------------------------
+
+;; Now the generic patterns.
+
+(define_insn "andqi3_16"
+ [(set (match_operand:QI 0 "mra_operand" "=Sp,Rqi,RhlSd,RhlSd,??Rmm,??Rmm")
+ (and:QI (match_operand:QI 1 "mra_operand" "%0,0,0,0,0,0")
+ (match_operand 2 "mrai_operand" "Imb,Imb,iRhlSd,?Rmm,iRhlSd,?Rmm")))]
+ "TARGET_A16"
+ "@
+ bclr\t%B2,%0
+ bclr\t%B2,%h0
+ and.b\t%x2,%0
+ and.b\t%x2,%0
+ and.b\t%x2,%0
+ and.b\t%x2,%0"
+ [(set_attr "flags" "n,n,sz,sz,sz,sz")]
+ )
+
+(define_insn "andhi3_16"
+ [(set (match_operand:HI 0 "mra_operand" "=Sp,Sp,Rhi,RhiSd,??Rmm,RhiSd,??Rmm")
+ (and:HI (match_operand:HI 1 "mra_operand" "%0,0,0,0,0,0,0")
+ (match_operand:HI 2 "mrai_operand" "Imb,Imw,Imw,iRhiSd,?Rmm,?Rmm,iRhiSd")))]
+ "TARGET_A16"
+ "@
+
+ bclr\t%B2,%0
+ bclr\t%B2-8,1+%0
+ bclr\t%B2,%0
+ and.w\t%X2,%0
+ and.w\t%X2,%0
+ and.w\t%X2,%0
+ and.w\t%X2,%0"
+ [(set_attr "flags" "n,n,n,sz,sz,sz,sz")]
+ )
+
+
+
+(define_insn "iorqi3_16"
+ [(set (match_operand:QI 0 "mra_operand" "=Sp,Rqi,RqiSd,??Rmm,RqiSd,??Rmm")
+ (ior:QI (match_operand:QI 1 "mra_operand" "%0,0,0,0,0,0")
+ (match_operand:QI 2 "mrai_operand" "Ilb,Ilb,iRhlSd,iRhlSd,?Rmm,?Rmm")))]
+ "TARGET_A16"
+ "@
+ bset\t%B2,%0
+ bset\t%B2,%h0
+ or.b\t%x2,%0
+ or.b\t%x2,%0
+ or.b\t%x2,%0
+ or.b\t%x2,%0"
+ [(set_attr "flags" "n,n,sz,sz,sz,sz")]
+ )
+
+(define_insn "iorhi3_16"
+ [(set (match_operand:HI 0 "mra_operand" "=Sp,Sp,Rhi,RhiSd,RhiSd,??Rmm,??Rmm")
+ (ior:HI (match_operand:HI 1 "mra_operand" "%0,0,0,0,0,0,0")
+ (match_operand:HI 2 "mrai_operand" "Imb,Imw,Ilw,iRhiSd,?Rmm,iRhiSd,?Rmm")))]
+ "TARGET_A16"
+ "@
+ bset %B2,%0
+ bset\t%B2-8,1+%0
+ bset\t%B2,%0
+ or.w\t%X2,%0
+ or.w\t%X2,%0
+ or.w\t%X2,%0
+ or.w\t%X2,%0"
+ [(set_attr "flags" "n,n,n,sz,sz,sz,sz")]
+ )
+
+; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+(define_insn "andqi3_24"
+ [(set (match_operand:QI 0 "mra_operand" "=Sd,Rqi,RhlSd,RhlSd,??Rmm,??Rmm")
+ (and:QI (match_operand:QI 1 "mra_operand" "%0,0,0,0,0,0")
+ (match_operand 2 "mrai_operand" "Imb,Imb,iRhlSd,?Rmm,iRhlSd,?Rmm")))]
+ "TARGET_A24"
+ "@
+ bclr\t%B2,%0
+ bclr\t%B2,%0
+ and.b\t%x2,%0
+ and.b\t%x2,%0
+ and.b\t%x2,%0
+ and.b\t%x2,%0"
+ [(set_attr "flags" "n,n,sz,sz,sz,sz")]
+ )
+
+(define_insn "andhi3_24"
+ [(set (match_operand:HI 0 "mra_operand" "=Sd,Sd,Rqi,Rqi,RhiSd,??Rmm,RhiSd,??Rmm")
+ (and:HI (match_operand:HI 1 "mra_operand" "%0,0,0,0,0,0,0,0")
+ (match_operand:HI 2 "mrai_operand" "Imb,Imw,Imb,Imw,iRhiSd,?Rmm,?Rmm,iRhiSd")))]
+ "TARGET_A24"
+ "@
+ bclr\t%B2,%0
+ bclr\t%B2-8,1+%0
+ bclr\t%B2,%h0
+ bclr\t%B2-8,%H0
+ and.w\t%X2,%0
+ and.w\t%X2,%0
+ and.w\t%X2,%0
+ and.w\t%X2,%0"
+ [(set_attr "flags" "n,n,n,n,sz,sz,sz,sz")]
+ )
+
+
+
+(define_insn "iorqi3_24"
+ [(set (match_operand:QI 0 "mra_operand" "=Sd,Rqi,RqiSd,??Rmm,RqiSd,??Rmm")
+ (ior:QI (match_operand:QI 1 "mra_operand" "%0,0,0,0,0,0")
+ (match_operand:QI 2 "mrai_operand" "Ilb,Ilb,iRhlSd,iRhlSd,?Rmm,?Rmm")))]
+ "TARGET_A24"
+ "@
+ bset\t%B2,%0
+ bset\t%B2,%0
+ or.b\t%x2,%0
+ or.b\t%x2,%0
+ or.b\t%x2,%0
+ or.b\t%x2,%0"
+ [(set_attr "flags" "n,n,sz,sz,sz,sz")]
+ )
+
+(define_insn "iorhi3_24"
+ [(set (match_operand:HI 0 "mra_operand" "=Sd,Sd,Rqi,Rqi,RhiSd,RhiSd,??Rmm,??Rmm")
+ (ior:HI (match_operand:HI 1 "mra_operand" "%0,0,0,0,0,0,0,0")
+ (match_operand:HI 2 "mrai_operand" "Ilb,Ilw,Ilb,Ilw,iRhiSd,?Rmm,iRhiSd,?Rmm")))]
+ "TARGET_A24"
+ "@
+ bset\t%B2,%0
+ bset\t%B2-8,1+%0
+ bset\t%B2,%h0
+ bset\t%B2-8,%H0
+ or.w\t%X2,%0
+ or.w\t%X2,%0
+ or.w\t%X2,%0
+ or.w\t%X2,%0"
+ [(set_attr "flags" "n,n,n,n,sz,sz,sz,sz")]
+ )
+
+
+; ----------------------------------------------------------------------
+
+(define_expand "andqi3"
+ [(set (match_operand:QI 0 "mra_operand" "")
+ (and:QI (match_operand:QI 1 "mra_operand" "")
+ (match_operand:QI 2 "mrai_operand" "")))]
""
- "and.b\t%x2,%0"
- [(set_attr "flags" "sz,sz,sz,sz")]
+ "if (TARGET_A16)
+ emit_insn (gen_andqi3_16 (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_andqi3_24 (operands[0], operands[1], operands[2]));
+ DONE;"
)
-(define_insn "andhi3"
- [(set (match_operand:HI 0 "mra_operand" "=RhiSd,??Rmm,RhiSd,??Rmm")
- (and:HI (match_operand:HI 1 "mra_operand" "%0,0,0,0")
- (match_operand:HI 2 "mrai_operand" "iRhiSd,?Rmm,?Rmm,iRhiSd")))]
+(define_expand "andhi3"
+ [(set (match_operand:HI 0 "mra_operand" "")
+ (and:HI (match_operand:HI 1 "mra_operand" "")
+ (match_operand:HI 2 "mrai_operand" "")))]
""
- "and.w\t%X2,%0"
- [(set_attr "flags" "sz,sz,sz,sz")]
+ "if (TARGET_A16)
+ emit_insn (gen_andhi3_16 (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_andhi3_24 (operands[0], operands[1], operands[2]));
+ DONE;"
)
-(define_insn "iorqi3"
- [(set (match_operand:QI 0 "mra_operand" "=RqiSd,??Rmm,RqiSd,??Rmm")
- (ior:QI (match_operand:QI 1 "mra_operand" "%0,0,0,0")
- (match_operand:QI 2 "mrai_operand" "iRhlSd,iRhlSd,?Rmm,?Rmm")))]
+(define_expand "iorqi3"
+ [(set (match_operand:QI 0 "mra_operand" "")
+ (ior:QI (match_operand:QI 1 "mra_operand" "")
+ (match_operand:QI 2 "mrai_operand" "")))]
""
- "or.b\t%x2,%0"
- [(set_attr "flags" "sz,sz,sz,sz")]
+ "if (TARGET_A16)
+ emit_insn (gen_iorqi3_16 (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_iorqi3_24 (operands[0], operands[1], operands[2]));
+ DONE;"
)
-(define_insn "iorhi3"
- [(set (match_operand:HI 0 "mra_operand" "=RhiSd,RhiSd,??Rmm,??Rmm")
- (ior:HI (match_operand:HI 1 "mra_operand" "%0,0,0,0")
- (match_operand:HI 2 "mrai_operand" "iRhiSd,?Rmm,iRhiSd,?Rmm")))]
+(define_expand "iorhi3"
+ [(set (match_operand:HI 0 "mra_operand" "")
+ (ior:HI (match_operand:HI 1 "mra_operand" "")
+ (match_operand:HI 2 "mrai_operand" "")))]
""
- "or.w\t%X2,%0"
- [(set_attr "flags" "sz,sz,sz,sz")]
+ "if (TARGET_A16)
+ emit_insn (gen_iorhi3_16 (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_iorhi3_24 (operands[0], operands[1], operands[2]));
+ DONE;"
)
(define_insn "xorqi3"
"not.w\t%0"
[(set_attr "flags" "sz,sz")]
)
+
+; Optimizations using bit opcodes
+
+; We need this because combine only looks at three insns at a time,
+; and the bclr_qi pattern uses four - mov, shift, not, and. GCC
+; should never expand this pattern, because it only shifts a constant
+; by a constant, so gcc should do that itself.
+(define_insn "shift1_qi"
+ [(set (match_operand:QI 0 "mra_operand" "=Rqi")
+ (ashift:QI (const_int 1)
+ (match_operand 1 "const_int_operand" "In4")))]
+ ""
+ "mov.b\t#1,%0\n\tshl.b\t%1,%0"
+ )
+(define_insn "shift1_hi"
+ [(set (match_operand:HI 0 "mra_operand" "=Rhi")
+ (ashift:HI (const_int 1)
+ (match_operand 1 "const_int_operand" "In4")))]
+ ""
+ "mov.w\t#1,%0\n\tshl.w\t%1,%0"
+ )
+
+; Generic insert-bit expander, needed so that we can use the bit
+; opcodes for volatile bitfields.
+
+(define_expand "insv"
+ [(set (zero_extract:HI (match_operand:HI 0 "mra_operand" "")
+ (match_operand 1 "const_int_operand" "")
+ (match_operand 2 "const_int_operand" ""))
+ (match_operand:HI 3 "const_int_operand" ""))]
+ ""
+ "if (m32c_expand_insv (operands))
+ FAIL;
+ DONE;"
+ )
--- /dev/null
+;; Machine Descriptions for R8C/M16C/M32C
+;; Copyright (C) 2006
+;; Free Software Foundation, Inc.
+;; Contributed by Red Hat.
+;;
+;; 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 2, 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 COPYING. If not, write to the Free
+;; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
+
+;; various block move instructions
+
+;; R8C:
+;; SMOVB - while (r3--) { *a1-- = *r1ha0--; } - memcpy
+;; SMOVF - while (r3--) { *a1++ = *r1ha0++; } - memcpy
+;; SSTR - while (r3--) { *a1++ = [r0l,r0]; } - memset
+
+;; M32CM:
+;; SCMPU - while (*a0 && *a0 != *a1) { a0++; a1++; } - strcmp
+;; SIN - while (r3--) { *a1++ = *a0; }
+;; SMOVB - while (r3--) { *a1-- = *a0--; } - memcpy
+;; SMOVF - while (r3--) { *a1++ = *a0++; } - memcpy
+;; SMOVU - while (*a1++ = *a0++) ; - strcpy
+;; SOUT - while (r3--) { *a1 = *a0++; }
+;; SSTR - while (r3--) { *a1++ = [r0l,r0]; } - memset
+
+
+
+;; 0 = destination (mem:BLK ...)
+;; 1 = source (mem:BLK ...)
+;; 2 = count
+;; 3 = alignment
+(define_expand "movmemhi"
+ [(match_operand 0 "ap_operand" "")
+ (match_operand 1 "ap_operand" "")
+ (match_operand 2 "m32c_r3_operand" "")
+ (match_operand 3 "" "")
+ ]
+ ""
+ "if (m32c_expand_movmemhi(operands)) DONE; FAIL;"
+ )
+
+;; We can't use mode macros for these because M16C uses r1h to extend
+;; the source address, for copying data from ROM to RAM. We don't yet
+;; support that, but we need to zero our r1h, so the patterns differ.
+
+;; 0 = dest (out)
+;; 1 = src (out)
+;; 2 = count (out)
+;; 3 = dest (in)
+;; 4 = src (in)
+;; 5 = count (in)
+(define_insn "movmemhi_bhi_op"
+ [(set (mem:QI (match_operand:HI 3 "ap_operand" "0"))
+ (mem:QI (match_operand:HI 4 "ap_operand" "1")))
+ (set (match_operand:HI 2 "m32c_r3_operand" "=R3w")
+ (const_int 0))
+ (set (match_operand:HI 0 "ap_operand" "=Ra1")
+ (plus:HI (match_dup 3)
+ (zero_extend:HI (match_operand:HI 5 "m32c_r3_operand" "2"))))
+ (set (match_operand:HI 1 "ap_operand" "=Ra0")
+ (plus:HI (match_dup 4)
+ (zero_extend:HI (match_dup 5))))
+ (use (reg:HI R1_REGNO))]
+ "TARGET_A16"
+ "mov.b:q\t#0,r1h\n\tsmovf.b\t; %0[0..%2-1]=r1h%1[]"
+ )
+(define_insn "movmemhi_bpsi_op"
+ [(set (mem:QI (match_operand:PSI 3 "ap_operand" "0"))
+ (mem:QI (match_operand:PSI 4 "ap_operand" "1")))
+ (set (match_operand:HI 2 "m32c_r3_operand" "=R3w")
+ (const_int 0))
+ (set (match_operand:PSI 0 "ap_operand" "=Ra1")
+ (plus:PSI (match_dup 3)
+ (zero_extend:PSI (match_operand:HI 5 "m32c_r3_operand" "2"))))
+ (set (match_operand:PSI 1 "ap_operand" "=Ra0")
+ (plus:PSI (match_dup 4)
+ (zero_extend:PSI (match_dup 5))))]
+ "TARGET_A24"
+ "smovf.b\t; %0[0..%2-1]=%1[]"
+ )
+(define_insn "movmemhi_whi_op"
+ [(set (mem:HI (match_operand:HI 3 "ap_operand" "0"))
+ (mem:HI (match_operand:HI 4 "ap_operand" "1")))
+ (set (match_operand:HI 2 "m32c_r3_operand" "=R3w")
+ (const_int 0))
+ (set (match_operand:HI 0 "ap_operand" "=Ra1")
+ (plus:HI (match_dup 3)
+ (zero_extend:HI (match_operand:HI 5 "m32c_r3_operand" "2"))))
+ (set (match_operand:HI 1 "ap_operand" "=Ra0")
+ (plus:HI (match_dup 4)
+ (zero_extend:HI (match_dup 5))))
+ (use (reg:HI R1_REGNO))]
+ "TARGET_A16"
+ "mov.b:q\t#0,r1h\n\tsmovf.w\t; %0[0..%2-1]=r1h%1[]"
+ )
+(define_insn "movmemhi_wpsi_op"
+ [(set (mem:HI (match_operand:PSI 3 "ap_operand" "0"))
+ (mem:HI (match_operand:PSI 4 "ap_operand" "1")))
+ (set (match_operand:HI 2 "m32c_r3_operand" "=R3w")
+ (const_int 0))
+ (set (match_operand:PSI 0 "ap_operand" "=Ra1")
+ (plus:PSI (match_dup 3)
+ (zero_extend:PSI (match_operand:HI 5 "m32c_r3_operand" "2"))))
+ (set (match_operand:PSI 1 "ap_operand" "=Ra0")
+ (plus:PSI (match_dup 4)
+ (zero_extend:PSI (match_dup 5))))]
+ "TARGET_A24"
+ "smovf.w\t; %0[0..%2-1]=%1[]"
+ )
+
+
+
+;; 0 = destination (mem:BLK ...)
+;; 1 = number of bytes
+;; 2 = value to store
+;; 3 = alignment
+(define_expand "setmemhi"
+ [(match_operand 0 "ap_operand" "")
+ (match_operand 1 "m32c_r3_operand" "")
+ (match_operand 2 "m32c_r0_operand" "")
+ (match_operand 3 "" "")
+ ]
+ "TARGET_A24"
+ "if (m32c_expand_setmemhi(operands)) DONE; FAIL;"
+ )
+
+;; 0 = address (out)
+;; 1 = count (out)
+;; 2 = value (in)
+;; 3 = address (in)
+;; 4 = count (in)
+(define_insn "setmemhi_b<mode>_op"
+ [(set (mem:QI (match_operand:HPSI 3 "ap_operand" "0"))
+ (match_operand:QI 2 "m32c_r0_operand" "R0w"))
+ (set (match_operand:HI 1 "m32c_r3_operand" "=R3w")
+ (const_int 0))
+ (set (match_operand:HPSI 0 "ap_operand" "=Ra1")
+ (plus:HPSI (match_dup 3)
+ (zero_extend:HPSI (match_operand:HI 4 "m32c_r3_operand" "1"))))]
+ "TARGET_A24"
+ "sstr.b\t; %0[0..%1-1]=%2"
+ )
+
+(define_insn "setmemhi_w<mode>_op"
+ [(set (mem:HI (match_operand:HPSI 3 "ap_operand" "0"))
+ (match_operand:HI 2 "m32c_r0_operand" "R0w"))
+ (set (match_operand:HI 1 "m32c_r3_operand" "=R3w")
+ (const_int 0))
+ (set (match_operand:HPSI 0 "ap_operand" "=Ra1")
+ (plus:HPSI (match_dup 3)
+ (zero_extend:HPSI (match_operand:HI 4 "m32c_r3_operand" "1"))))]
+ "TARGET_A24"
+ "sstr.w\t; %0[0..%1-1]=%2"
+ )
+
+
+;; SCMPU sets the flags according to the result of the string
+;; comparison. GCC wants the result to be a signed value reflecting
+;; the result, which it then compares to zero. Hopefully we can
+;; optimize that later (see peephole in cond.md). Meanwhile, the
+;; strcmp builtin is expanded to a SCMPU followed by a flags-to-int
+;; pattern in cond.md.
+
+;; 0 = result:HI
+;; 1 = destination (mem:BLK ...)
+;; 2 = source (mem:BLK ...)
+;; 3 = alignment
+
+(define_expand "cmpstrsi"
+ [(match_operand:HI 0 "" "")
+ (match_operand 1 "ap_operand" "")
+ (match_operand 2 "ap_operand" "")
+ (match_operand 3 "" "")
+ ]
+ "TARGET_A24"
+ "if (m32c_expand_cmpstr(operands)) DONE; FAIL;"
+ )
+
+;; 0 = string1
+;; 1 = string2
+
+(define_insn "cmpstrhi_op"
+ [(set (reg:CC FLG_REGNO)
+ (compare:CC (mem:BLK (match_operand:PSI 0 "ap_operand" "Ra0"))
+ (mem:BLK (match_operand:PSI 1 "ap_operand" "Ra1"))))
+ (clobber (match_operand:PSI 2 "ap_operand" "=0"))
+ (clobber (match_operand:PSI 3 "ap_operand" "=1"))]
+ "TARGET_A24"
+ "scmpu.b\t; flags := strcmp(*%0,*%1)"
+ [(set_attr "flags" "oszc")]
+ )
+
+
+
+;; Note that SMOVU leaves the address registers pointing *after*
+;; the NUL at the end of the string. This is not what gcc expects; it
+;; expects the address registers to point *at* the NUL. The expander
+;; must emit a suitable add insn.
+
+;; 0 = target: set to &NUL in dest
+;; 1 = destination (mem:BLK ...)
+;; 2 = source (mem:BLK ...)
+
+(define_expand "movstr"
+ [(match_operand 0 "" "")
+ (match_operand 1 "ap_operand" "")
+ (match_operand 2 "ap_operand" "")
+ ]
+ "TARGET_A24"
+ "if (m32c_expand_movstr(operands)) DONE; FAIL;"
+ )
+
+;; 0 = dest (out)
+;; 1 = src (out) (clobbered)
+;; 2 = dest (in)
+;; 3 = src (in)
+(define_insn "movstr_op"
+ [(set (mem:BLK (match_operand:PSI 2 "ap_operand" "0"))
+ (mem:BLK (match_operand:PSI 3 "ap_operand" "1")))
+ (set (match_operand:PSI 0 "ap_operand" "=Ra1")
+ (plus:PSI (match_dup 2)
+ (unspec:PSI [(const_int 0)] UNS_SMOVU)))
+ (set (match_operand:PSI 1 "ap_operand" "=Ra0")
+ (plus:PSI (match_dup 3)
+ (unspec:PSI [(const_int 0)] UNS_SMOVU)))]
+ "TARGET_A24"
+ "smovu.b\t; while (*%2++ := *%3++) != 0"
+ [(set_attr "flags" "*")]
+ )
+
; right flags already. For example, a mov followed by a "cmp *,0" is
; redundant; the move already set the Z flag.
-(define_insn "cbranchqi4"
+(define_insn_and_split "cbranch<mode>4"
[(set (pc) (if_then_else
(match_operator 0 "m32c_cmp_operator"
- [(match_operand:QI 1 "mrai_operand" "RqiSd,RqiSd,?Rmm,?Rmm")
- (match_operand:QI 2 "mrai_operand" "iRqiSd,?Rmm,iRqiSd,?Rmm")])
+ [(match_operand:QHPSI 1 "mra_operand" "RraSd")
+ (match_operand:QHPSI 2 "mrai_operand" "iRraSd")])
(label_ref (match_operand 3 "" ""))
(pc)))]
""
- "cmp.b\t%2,%1\n\tj%C0\t1f\n\tjmp.a\t%l3\n1:"
-; "cmp.b\t%2,%1\n\tj%c0\t%l3"
- [(set_attr "flags" "oszc,oszc,oszc,oszc")]
+ "#"
+ ""
+ [(set (reg:CC FLG_REGNO)
+ (compare (match_dup 1)
+ (match_dup 2)))
+ (set (pc) (if_then_else (match_dup 4)
+ (label_ref (match_dup 3))
+ (pc)))]
+ "operands[4] = m32c_cmp_flg_0 (operands[0]);"
)
-(define_insn "cbranchhi4"
- [(set (pc) (if_then_else
- (match_operator 0 "m32c_cmp_operator"
- [(match_operand:HI 1 "mrai_operand" "Rhi,?Sd,Rhi,?Sd,?Rmm,?Rmm")
- (match_operand:HI 2 "mrai_operand" "iRhiSd,iRhiSd,?Rmm,?Rmm,iRhiSd,?Rmm")])
- (label_ref (match_operand 3 "" ""))
- (pc)))]
+(define_insn "stzx_16"
+ [(set (match_operand:QI 0 "mrai_operand" "=R0w,R0w,R0w")
+ (if_then_else:QI (eq (reg:CC FLG_REGNO) (const_int 0))
+ (match_operand:QI 1 "const_int_operand" "i,i,0")
+ (match_operand:QI 2 "const_int_operand" "i,0,i")))]
+ "TARGET_A16"
+ "@
+ stzx\t%1,%2,%0
+ stz\t%1,%0
+ stnz\t%2,%0")
+
+(define_insn "stzx_24_<mode>"
+ [(set (match_operand:QHI 0 "mrai_operand" "=RraSd,RraSd,RraSd")
+ (if_then_else:QHI (eq (reg:CC FLG_REGNO) (const_int 0))
+ (match_operand:QHI 1 "const_int_operand" "i,i,0")
+ (match_operand:QHI 2 "const_int_operand" "i,0,i")))]
+ "TARGET_A24"
+ "@
+ stzx.<bwl>\t%1,%2,%0
+ stz.<bwl>\t%1,%0
+ stnz.<bwl>\t%2,%0")
+
+(define_insn_and_split "stzx_reversed"
+ [(set (match_operand 0 "m32c_r0_operand" "")
+ (if_then_else (ne (reg:CC FLG_REGNO) (const_int 0))
+ (match_operand 1 "const_int_operand" "")
+ (match_operand 2 "const_int_operand" "")))]
+ "TARGET_A24 || GET_MODE (operands[0]) == QImode"
+ "#"
+ ""
+ [(set (match_dup 0)
+ (if_then_else (eq (reg:CC FLG_REGNO) (const_int 0))
+ (match_dup 2)
+ (match_dup 1)))]
""
- "cmp.w\t%2,%1\n\tj%C0\t1f\n\tjmp.a\t%l3\n1:"
-; "cmp.w\t%2,%1\n\tj%c0\t%l3"
- [(set_attr "flags" "oszc,oszc,oszc,oszc,oszc,oszc")]
)
-(define_insn "cbranchpsi4"
- [(set (pc) (if_then_else
- (match_operator 0 "m32c_cmp_operator"
- [(match_operand:PSI 1 "mrai_operand" "RsiSd,RsiSd,?Rmm,?Rmm")
- (match_operand:PSI 2 "mrai_operand" "iRsiSd,?Rmm,iRsiSd,?Rmm")])
- (label_ref (match_operand 3 "" ""))
- (pc)))]
+
+(define_insn "cmp<mode>"
+ [(set (reg:CC FLG_REGNO)
+ (compare (match_operand:QHPSI 0 "mra_operand" "RraSd")
+ (match_operand:QHPSI 1 "mrai_operand" "RraSdi")))]
+ ""
+ "cmp.<bwl>\t%1,%0")
+
+(define_insn "b<code>"
+ [(set (pc)
+ (if_then_else (any_cond (reg:CC FLG_REGNO)
+ (const_int 0))
+ (label_ref (match_operand 0 ""))
+ (pc)))]
+ ""
+ "j<code>\t%l0"
+)
+
+;; m32c_conditional_register_usage changes the setcc_gen_code array to
+;; point to the _24 variants if needed.
+
+(define_insn "s<code>"
+ [(set (match_operand:QI 0 "register_operand" "=Rqi")
+ (any_cond:QI (reg:CC FLG_REGNO) (const_int 0)))]
+ "TARGET_A16"
+ "* return m32c_scc_pattern(operands, <CODE>);")
+
+(define_insn "s<code>_24"
+ [(set (match_operand:HI 0 "mra_operand" "=RhiSd")
+ (any_cond:HI (reg:CC FLG_REGNO) (const_int 0)))]
"TARGET_A24"
- "cmp.l\t%2,%1\n\tj%C0\t1f\n\tjmp.a\t%l3\n1:"
-; "cmp.l\t%2,%1\n\tj%c0\t%l3"
- [(set_attr "flags" "oszc,oszc,oszc,oszc")]
- )
+ "sc<code>\t%0")
+
+(define_expand "movqicc"
+ [(set (match_operand:QI 0 "register_operand" "")
+ (if_then_else:QI (match_operand 1 "m32c_eqne_operator" "")
+ (match_operand:QI 2 "const_int_operand" "")
+ (match_operand:QI 3 "const_int_operand" "")))]
+ ""
+ "if (m32c_expand_movcc(operands))
+ FAIL;
+ DONE;"
+)
+
+(define_expand "movhicc"
+ [(set (match_operand:HI 0 "mra_operand" "")
+ (if_then_else:HI (match_operand 1 "m32c_eqne_operator" "")
+ (match_operand:HI 2 "const_int_operand" "")
+ (match_operand:HI 3 "const_int_operand" "")))]
+ "TARGET_A24"
+ "if (m32c_expand_movcc(operands))
+ FAIL;
+ DONE;"
+)
+
+
+;; CMP opcodes subtract two values, set the flags, and discard the
+;; value. This pattern recovers the sign of the discarded value based
+;; on the flags. Operand 0 is set to -1, 0, or 1. This is used for
+;; the cmpstr pattern. For optimal code, this should be removed if
+;; followed by a suitable CMP insn, as SCMPU sets the flags correctly
+;; already (see the peephole following). This pattern is 7 bytes and
+;; 5 cycles. If you don't need specific values, a 5/4 pattern can be
+;; made with SCGT and BMLT to set the appropriate bits.
+
+(define_insn "cond_to_int"
+ [(set (match_operand:HI 0 "mra_qi_operand" "=Rqi")
+ (if_then_else:HI (lt (reg:CC FLG_REGNO) (const_int 0))
+ (const_int -1)
+ (if_then_else:HI (eq (reg:CC FLG_REGNO) (const_int 0))
+ (const_int 0)
+ (const_int -1))))]
+ "TARGET_A24"
+ "sceq\t%0\n\tbmgt\t1,%h0\n\tdec.w\t%0"
+ [(set_attr "flags" "sz")]
+ )
+
+;; A cond_to_int followed by a compare against zero is essentially a no-op.
+
+(define_peephole2
+ [(set (match_operand:HI 0 "mra_qi_operand" "")
+ (if_then_else:HI (lt (reg:CC FLG_REGNO) (const_int 0))
+ (const_int -1)
+ (if_then_else:HI (eq (reg:CC FLG_REGNO) (const_int 0))
+ (const_int 0)
+ (const_int -1))))
+ (set (reg:CC FLG_REGNO)
+ (compare (match_operand:HI 1 "mra_qi_operand" "")
+ (const_int 0)))
+ ]
+ "rtx_equal_p(operands[0], operands[1])"
+ [(const_int 1)]
+ "")
int m32c_cannot_change_mode_class (MM, MM, int);
int m32c_class_max_nregs (int, MM);
+rtx m32c_cmp_flg_0 (rtx);
rtx m32c_eh_return_stackadj_rtx (void);
void m32c_emit_eh_epilogue (rtx);
+int m32c_expand_cmpstr (rtx *);
+int m32c_expand_insv (rtx *);
+int m32c_expand_movcc (rtx *);
+int m32c_expand_movmemhi (rtx *);
+int m32c_expand_movstr (rtx *);
+void m32c_expand_neg_mulpsi3 (rtx *);
+int m32c_expand_setmemhi (rtx *);
int m32c_extra_constraint_p (rtx, char, const char *);
int m32c_extra_constraint_p2 (rtx, char, const char *);
int m32c_hard_regno_nregs (int, MM);
int m32c_register_move_cost (MM, int, int);
MM m32c_regno_reg_class (int);
rtx m32c_return_addr_rtx (int);
+const char *m32c_scc_pattern (rtx *, RTX_CODE);
int m32c_secondary_reload_class (int, MM, rtx);
int m32c_split_move (rtx *, MM, int);
int m32c_split_psi_p (rtx *);
error ("invalid target memregs value '%d'", target_memregs);
}
else
- target_memregs = "16";
+ target_memregs = 16;
}
/* Defining data structures for per-function information */
void
m32c_conditional_register_usage (void)
{
- int memregs;
int i;
if (0 <= target_memregs && target_memregs <= 16)
if (GET_MODE_SIZE (m1) == GET_MODE_SIZE (m2))
return 1;
+#if 0
if (m1 == QImode || m2 == QImode)
return 0;
+#endif
return 1;
}
return FB_REGS;
if (memcmp (s, "Rsb", 3) == 0)
return SB_REGS;
- if (memcmp (s, "Rcr", 3) == 0 && TARGET_A16)
- return CR_REGS;
- if (memcmp (s, "Rcl", 3) == 0 && TARGET_A24)
- return CR_REGS;
+ if (memcmp (s, "Rcr", 3) == 0)
+ return TARGET_A16 ? CR_REGS : NO_REGS;
+ if (memcmp (s, "Rcl", 3) == 0)
+ return TARGET_A24 ? CR_REGS : NO_REGS;
if (memcmp (s, "R0w", 3) == 0)
return R0_REGS;
if (memcmp (s, "R1w", 3) == 0)
return HL_REGS;
if (memcmp (s, "R23", 3) == 0)
return R23_REGS;
+ if (memcmp (s, "Ra0", 3) == 0)
+ return A0_REGS;
+ if (memcmp (s, "Ra1", 3) == 0)
+ return A1_REGS;
if (memcmp (s, "Raa", 3) == 0)
return A_REGS;
- if (memcmp (s, "Raw", 3) == 0 && TARGET_A16)
- return A_REGS;
- if (memcmp (s, "Ral", 3) == 0 && TARGET_A24)
- return A_REGS;
+ if (memcmp (s, "Raw", 3) == 0)
+ return TARGET_A16 ? A_REGS : NO_REGS;
+ if (memcmp (s, "Ral", 3) == 0)
+ return TARGET_A24 ? A_REGS : NO_REGS;
if (memcmp (s, "Rqi", 3) == 0)
return QI_REGS;
if (memcmp (s, "Rad", 3) == 0)
if (memcmp (s, "Rpa", 3) == 0)
return NO_REGS;
+ if (*s == 'R')
+ {
+ fprintf(stderr, "unrecognized R constraint: %.3s\n", s);
+ gcc_unreachable();
+ }
+
return NO_REGS;
}
int b = exact_log2 (value);
return (b >= 1 && b <= 8);
}
+ if (memcmp (str, "Imb", 3) == 0)
+ {
+ int b = exact_log2 ((value ^ 0xff) & 0xff);
+ return (b >= 1 && b <= 8);
+ }
if (memcmp (str, "Ilw", 3) == 0)
{
int b = exact_log2 (value);
return (b >= 1 && b <= 16);
}
+ if (memcmp (str, "Imw", 3) == 0)
+ {
+ int b = exact_log2 ((value ^ 0xffff) & 0xffff);
+ return (b >= 1 && b <= 16);
+ }
+ if (memcmp (str, "I00", 3) == 0)
+ {
+ return (value == 0);
+ }
return 0;
}
return 1;
if (RTX_IS ("ms") || RTX_IS ("m+si"))
return 1;
+ if (RTX_IS ("m++rii"))
+ {
+ if (REGNO (patternr[3]) == FB_REGNO
+ && INTVAL (patternr[4]) == 0)
+ return 1;
+ }
if (RTX_IS ("mr"))
r = patternr[1];
else if (RTX_IS ("m+ri") || RTX_IS ("m+rs") || RTX_IS ("m+r+si"))
&& (IS_REG (patternr[1], SB_REGNO)))
|| (RTX_IS ("m+ri") && (IS_REG (patternr[2], SB_REGNO))));
}
+ else if (memcmp (str, "Sp", 2) == 0)
+ {
+ /* Absolute addresses 0..0x1fff used for bit addressing (I/O ports) */
+ return (RTX_IS ("mi")
+ && !(INTVAL (patternr[1]) & ~0x1fff));
+ }
else if (memcmp (str, "S1", 2) == 0)
{
return r1h_operand (value, QImode);
#undef A0
}
+/* Implicit Calls to Library Routines */
+
+#undef TARGET_INIT_LIBFUNCS
+#define TARGET_INIT_LIBFUNCS m32c_init_libfuncs
+static void
+m32c_init_libfuncs (void)
+{
+ if (TARGET_A24)
+ {
+ /* We do this because the M32C has an HImode operand, but the
+ M16C has an 8 bit operand. Since gcc looks at the match data
+ and not the expanded rtl, we have to reset the array so that
+ the right modes are found. */
+ setcc_gen_code[EQ] = CODE_FOR_seq_24;
+ setcc_gen_code[NE] = CODE_FOR_sne_24;
+ setcc_gen_code[GT] = CODE_FOR_sgt_24;
+ setcc_gen_code[GE] = CODE_FOR_sge_24;
+ setcc_gen_code[LT] = CODE_FOR_slt_24;
+ setcc_gen_code[LE] = CODE_FOR_sle_24;
+ setcc_gen_code[GTU] = CODE_FOR_sgtu_24;
+ setcc_gen_code[GEU] = CODE_FOR_sgeu_24;
+ setcc_gen_code[LTU] = CODE_FOR_sltu_24;
+ setcc_gen_code[LEU] = CODE_FOR_sleu_24;
+ }
+}
+
/* Addressing Modes */
/* Used by GO_IF_LEGITIMATE_ADDRESS. The r8c/m32c family supports a
return COSTS_N_INSNS (10);
}
+/* Here we try to describe when we use multiple opcodes for one RTX so
+ that gcc knows when to use them. */
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS m32c_rtx_costs
+static bool
+m32c_rtx_costs (rtx x, int code, int outer_code, int *total)
+{
+ switch (code)
+ {
+ case REG:
+ if (REGNO (x) >= MEM0_REGNO && REGNO (x) <= MEM7_REGNO)
+ *total += COSTS_N_INSNS (500);
+ else
+ *total += COSTS_N_INSNS (1);
+ return true;
+
+ case ASHIFT:
+ case LSHIFTRT:
+ case ASHIFTRT:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ /* mov.b r1l, r1h */
+ *total += COSTS_N_INSNS (1);
+ return true;
+ }
+ if (INTVAL (XEXP (x, 1)) > 8
+ || INTVAL (XEXP (x, 1)) < -8)
+ {
+ /* mov.b #N, r1l */
+ /* mov.b r1l, r1h */
+ *total += COSTS_N_INSNS (2);
+ return true;
+ }
+ return true;
+
+ case LE:
+ case LEU:
+ case LT:
+ case LTU:
+ case GT:
+ case GTU:
+ case GE:
+ case GEU:
+ case NE:
+ case EQ:
+ if (outer_code == SET)
+ {
+ *total += COSTS_N_INSNS (2);
+ return true;
+ }
+ break;
+
+ case ZERO_EXTRACT:
+ {
+ rtx dest = XEXP (x, 0);
+ rtx addr = XEXP (dest, 0);
+ switch (GET_CODE (addr))
+ {
+ case CONST_INT:
+ *total += COSTS_N_INSNS (1);
+ break;
+ case SYMBOL_REF:
+ *total += COSTS_N_INSNS (3);
+ break;
+ default:
+ *total += COSTS_N_INSNS (2);
+ break;
+ }
+ return true;
+ }
+ break;
+
+ default:
+ /* Reasonable default. */
+ if (TARGET_A16 && GET_MODE(x) == SImode)
+ *total += COSTS_N_INSNS (2);
+ break;
+ }
+ return false;
+}
+
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST m32c_address_cost
+static int
+m32c_address_cost (rtx addr)
+{
+ /* fprintf(stderr, "\naddress_cost\n");
+ debug_rtx(addr);*/
+ switch (GET_CODE (addr))
+ {
+ case CONST_INT:
+ return COSTS_N_INSNS(1);
+ case SYMBOL_REF:
+ return COSTS_N_INSNS(3);
+ case REG:
+ return COSTS_N_INSNS(2);
+ default:
+ return 0;
+ }
+}
+
/* Defining the Output Assembler Language */
/* The Overall Framework of an Assembler File */
{ 'X', "i", "#0" },
{ 'm', "i", "#0" },
{ 'b', "i", "#0" },
+ { 'B', "i", "0" },
{ 'p', "i", "0" },
{ 0, 0, 0 }
x = m32c_subreg (HImode, x, SImode, 2);
code = 0;
}
+ if (code == 'h' && GET_MODE (x) == HImode)
+ {
+ x = m32c_subreg (QImode, x, HImode, 0);
+ code = 0;
+ }
+ if (code == 'H' && GET_MODE (x) == HImode)
+ {
+ /* We can't actually represent this as an rtx. Do it here. */
+ if (GET_CODE (x) == REG)
+ {
+ switch (REGNO (x))
+ {
+ case R0_REGNO:
+ fputs ("r0h", file);
+ return;
+ case R1_REGNO:
+ fputs ("r1h", file);
+ return;
+ default:
+ gcc_unreachable();
+ }
+ }
+ /* This should be a MEM. */
+ x = m32c_subreg (QImode, x, HImode, 1);
+ code = 0;
+ }
+ /* This is for BMcond, which always wants word register names. */
+ if (code == 'h' && GET_MODE (x) == QImode)
+ {
+ if (GET_CODE (x) == REG)
+ x = gen_rtx_REG (HImode, REGNO (x));
+ code = 0;
+ }
/* 'x' and 'X' need to be ignored for non-immediates. */
if ((code == 'x' || code == 'X') && GET_CODE (x) != CONST_INT)
code = 0;
switch (code)
{
case 'b':
- /* Bit position. */
- fprintf (file, "%d", (int) exact_log2 (INTVAL (r)));
+ case 'B':
+ {
+ int v = INTVAL (r);
+ int i = (int) exact_log2 (v);
+ if (i == -1)
+ i = (int) exact_log2 ((v ^ 0xffff) & 0xffff);
+ if (i == -1)
+ i = (int) exact_log2 ((v ^ 0xff) & 0xff);
+ /* Bit position. */
+ fprintf (file, "%d", i);
+ }
break;
case 'x':
/* Unsigned byte. */
return rv;
}
+/* The m32c has a number of opcodes that act like memcpy, strcmp, and
+ the like. For the R8C they expect one of the addresses to be in
+ R1L:An so we need to arrange for that. Otherwise, it's just a
+ matter of picking out the operands we want and emitting the right
+ pattern for them. All these expanders, which correspond to
+ patterns in blkmov.md, must return nonzero if they expand the insn,
+ or zero if they should FAIL. */
+
+/* This is a memset() opcode. All operands are implied, so we need to
+ arrange for them to be in the right registers. The opcode wants
+ addresses, not [mem] syntax. $0 is the destination (MEM:BLK), $1
+ the count (HI), and $2 the value (QI). */
+int
+m32c_expand_setmemhi(rtx *operands)
+{
+ rtx desta, count, val;
+ rtx desto, counto;
+
+ desta = XEXP (operands[0], 0);
+ count = operands[1];
+ val = operands[2];
+
+ desto = gen_reg_rtx (Pmode);
+ counto = gen_reg_rtx (HImode);
+
+ if (GET_CODE (desta) != REG
+ || REGNO (desta) < FIRST_PSEUDO_REGISTER)
+ desta = copy_to_mode_reg (Pmode, desta);
+
+ /* This looks like an arbitrary restriction, but this is by far the
+ most common case. For counts 8..14 this actually results in
+ smaller code with no speed penalty because the half-sized
+ constant can be loaded with a shorter opcode. */
+ if (GET_CODE (count) == CONST_INT
+ && GET_CODE (val) == CONST_INT
+ && ! (INTVAL (count) & 1)
+ && (INTVAL (count) > 1)
+ && (INTVAL (val) <= 7 && INTVAL (val) >= -8))
+ {
+ unsigned v = INTVAL (val) & 0xff;
+ v = v | (v << 8);
+ count = copy_to_mode_reg (HImode, GEN_INT (INTVAL (count) / 2));
+ val = copy_to_mode_reg (HImode, GEN_INT (v));
+ if (TARGET_A16)
+ emit_insn (gen_setmemhi_whi_op (desto, counto, val, desta, count));
+ else
+ emit_insn (gen_setmemhi_wpsi_op (desto, counto, val, desta, count));
+ return 1;
+ }
+
+ /* This is the generalized memset() case. */
+ if (GET_CODE (val) != REG
+ || REGNO (val) < FIRST_PSEUDO_REGISTER)
+ val = copy_to_mode_reg (QImode, val);
+
+ if (GET_CODE (count) != REG
+ || REGNO (count) < FIRST_PSEUDO_REGISTER)
+ count = copy_to_mode_reg (HImode, count);
+
+ if (TARGET_A16)
+ emit_insn (gen_setmemhi_bhi_op (desto, counto, val, desta, count));
+ else
+ emit_insn (gen_setmemhi_bpsi_op (desto, counto, val, desta, count));
+
+ return 1;
+}
+
+/* This is a memcpy() opcode. All operands are implied, so we need to
+ arrange for them to be in the right registers. The opcode wants
+ addresses, not [mem] syntax. $0 is the destination (MEM:BLK), $1
+ is the source (MEM:BLK), and $2 the count (HI). */
+int
+m32c_expand_movmemhi(rtx *operands)
+{
+ rtx desta, srca, count;
+ rtx desto, srco, counto;
+
+ desta = XEXP (operands[0], 0);
+ srca = XEXP (operands[1], 0);
+ count = operands[2];
+
+ desto = gen_reg_rtx (Pmode);
+ srco = gen_reg_rtx (Pmode);
+ counto = gen_reg_rtx (HImode);
+
+ if (GET_CODE (desta) != REG
+ || REGNO (desta) < FIRST_PSEUDO_REGISTER)
+ desta = copy_to_mode_reg (Pmode, desta);
+
+ if (GET_CODE (srca) != REG
+ || REGNO (srca) < FIRST_PSEUDO_REGISTER)
+ srca = copy_to_mode_reg (Pmode, srca);
+
+ /* Similar to setmem, but we don't need to check the value. */
+ if (GET_CODE (count) == CONST_INT
+ && ! (INTVAL (count) & 1)
+ && (INTVAL (count) > 1))
+ {
+ count = copy_to_mode_reg (HImode, GEN_INT (INTVAL (count) / 2));
+ if (TARGET_A16)
+ emit_insn (gen_movmemhi_whi_op (desto, srco, counto, desta, srca, count));
+ else
+ emit_insn (gen_movmemhi_wpsi_op (desto, srco, counto, desta, srca, count));
+ return 1;
+ }
+
+ /* This is the generalized memset() case. */
+ if (GET_CODE (count) != REG
+ || REGNO (count) < FIRST_PSEUDO_REGISTER)
+ count = copy_to_mode_reg (HImode, count);
+
+ if (TARGET_A16)
+ emit_insn (gen_movmemhi_bhi_op (desto, srco, counto, desta, srca, count));
+ else
+ emit_insn (gen_movmemhi_bpsi_op (desto, srco, counto, desta, srca, count));
+
+ return 1;
+}
+
+/* This is a stpcpy() opcode. $0 is the destination (MEM:BLK) after
+ the copy, which should point to the NUL at the end of the string,
+ $1 is the destination (MEM:BLK), and $2 is the source (MEM:BLK).
+ Since our opcode leaves the destination pointing *after* the NUL,
+ we must emit an adjustment. */
+int
+m32c_expand_movstr(rtx *operands)
+{
+ rtx desta, srca;
+ rtx desto, srco;
+
+ desta = XEXP (operands[1], 0);
+ srca = XEXP (operands[2], 0);
+
+ desto = gen_reg_rtx (Pmode);
+ srco = gen_reg_rtx (Pmode);
+
+ if (GET_CODE (desta) != REG
+ || REGNO (desta) < FIRST_PSEUDO_REGISTER)
+ desta = copy_to_mode_reg (Pmode, desta);
+
+ if (GET_CODE (srca) != REG
+ || REGNO (srca) < FIRST_PSEUDO_REGISTER)
+ srca = copy_to_mode_reg (Pmode, srca);
+
+ emit_insn (gen_movstr_op (desto, srco, desta, srca));
+ /* desto ends up being a1, which allows this type of add through MOVA. */
+ emit_insn (gen_addpsi3 (operands[0], desto, GEN_INT (-1)));
+
+ return 1;
+}
+
+/* This is a strcmp() opcode. $0 is the destination (HI) which holds
+ <=>0 depending on the comparison, $1 is one string (MEM:BLK), and
+ $2 is the other (MEM:BLK). We must do the comparison, and then
+ convert the flags to a signed integer result. */
+int
+m32c_expand_cmpstr(rtx *operands)
+{
+ rtx src1a, src2a;
+
+ src1a = XEXP (operands[1], 0);
+ src2a = XEXP (operands[2], 0);
+
+ if (GET_CODE (src1a) != REG
+ || REGNO (src1a) < FIRST_PSEUDO_REGISTER)
+ src1a = copy_to_mode_reg (Pmode, src1a);
+
+ if (GET_CODE (src2a) != REG
+ || REGNO (src2a) < FIRST_PSEUDO_REGISTER)
+ src2a = copy_to_mode_reg (Pmode, src2a);
+
+ emit_insn (gen_cmpstrhi_op (src1a, src2a, src1a, src2a));
+ emit_insn (gen_cond_to_int (operands[0]));
+
+ return 1;
+}
+
+
typedef rtx (*shift_gen_func)(rtx, rtx, rtx);
static shift_gen_func
GFF(SImode, ASHIFTRT, TARGET_A16 ? gen_ashrsi3_16 : gen_ashrsi3_24);
GFF(SImode, LSHIFTRT, TARGET_A16 ? gen_lshrsi3_16 : gen_lshrsi3_24);
#undef GFF
+ gcc_unreachable ();
}
/* The m32c only has one shift, but it takes a signed count. GCC
doesn't want this, so we fake it by negating any shift count when
- we're pretending to shift the other way. */
+ we're pretending to shift the other way. Also, the shift count is
+ limited to -8..8. It's slightly better to use two shifts for 9..15
+ than to load the count into r1h, so we do that too. */
int
m32c_prepare_shift (rtx * operands, int scale, int shift_code)
{
{
/* operands: a = b * i */
rtx temp1; /* b as SI */
- rtx temp2; /* -b as SI */
- rtx temp3; /* -b as PSI */
- rtx scale;
+ rtx scale /* i as SI */;
+ rtx temp2; /* a*b as SI */
temp1 = gen_reg_rtx (SImode);
temp2 = gen_reg_rtx (SImode);
- temp3 = gen_reg_rtx (PSImode);
- scale = GEN_INT (- INTVAL (operands[2]));
+ if (GET_CODE (operands[2]) != CONST_INT)
+ {
+ scale = gen_reg_rtx (SImode);
+ emit_insn (gen_zero_extendpsisi2 (scale, operands[2]));
+ }
+ else
+ scale = copy_to_mode_reg (SImode, operands[2]);
emit_insn (gen_zero_extendpsisi2 (temp1, operands[1]));
- emit_insn (gen_negsi2 (temp2, temp1));
- emit_insn (gen_truncsipsi2 (temp3, temp2));
- emit_insn (gen_mulpsi3 (operands[0], temp3, scale));
+ temp2 = expand_simple_binop (SImode, MULT, temp1, scale, temp2, 1, OPTAB_LIB);
+ emit_insn (gen_truncsipsi2 (operands[0], temp2));
}
/* Pattern Output Functions */
+/* Returns a (OP (reg:CC FLG_REGNO) (const_int 0)) from some other
+ match_operand rtx's OP. */
+rtx
+m32c_cmp_flg_0 (rtx cmp)
+{
+ return gen_rtx_fmt_ee (GET_CODE (cmp),
+ GET_MODE (cmp),
+ gen_rtx_REG (CCmode, FLG_REGNO),
+ GEN_INT (0));
+}
+
+int
+m32c_expand_movcc (rtx *operands)
+{
+ rtx rel = operands[1];
+ if (GET_CODE (rel) != EQ && GET_CODE (rel) != NE)
+ return 1;
+ if (GET_CODE (operands[2]) != CONST_INT
+ || GET_CODE (operands[3]) != CONST_INT)
+ return 1;
+ emit_insn (gen_cmpqi(XEXP (rel, 0), XEXP (rel, 1)));
+ if (GET_CODE (rel) == NE)
+ {
+ rtx tmp = operands[2];
+ operands[2] = operands[3];
+ operands[3] = tmp;
+ }
+ if (TARGET_A16)
+ emit_insn (gen_stzx_16 (operands[0], operands[2], operands[3]));
+ else if (GET_MODE (operands[0]) == QImode)
+ emit_insn (gen_stzx_24_qi (operands[0], operands[2], operands[3]));
+ else
+ emit_insn (gen_stzx_24_hi (operands[0], operands[2], operands[3]));
+ return 0;
+}
+
+/* Used for the "insv" pattern. Return nonzero to fail, else done. */
+int
+m32c_expand_insv (rtx *operands)
+{
+ rtx op0, src0, p;
+ int mask;
+
+ if (INTVAL (operands[1]) != 1)
+ return 1;
+
+ mask = 1 << INTVAL (operands[2]);
+
+ op0 = operands[0];
+ if (GET_CODE (op0) == SUBREG
+ && SUBREG_BYTE (op0) == 0)
+ {
+ rtx sub = SUBREG_REG (op0);
+ if (GET_MODE (sub) == HImode || GET_MODE (sub) == QImode)
+ op0 = sub;
+ }
+
+ if (no_new_pseudos
+ || (GET_CODE (op0) == MEM && MEM_VOLATILE_P (op0)))
+ src0 = op0;
+ else
+ {
+ src0 = gen_reg_rtx (GET_MODE (op0));
+ emit_move_insn (src0, op0);
+ }
+
+ if (GET_MODE (op0) == HImode
+ && INTVAL (operands[2]) >= 8
+ && GET_MODE (op0) == MEM)
+ {
+ /* We are little endian. */
+ rtx new_mem = gen_rtx_MEM (QImode, plus_constant (XEXP (op0, 0), 1));
+ MEM_COPY_ATTRIBUTES (new_mem, op0);
+ mask >>= 8;
+ }
+
+ if (INTVAL (operands[3]))
+ {
+ if (GET_MODE (op0) == HImode)
+ mask ^= 0xffff;
+ else
+ mask ^= 0xff;
+ }
+ if (GET_MODE (op0) == HImode)
+ {
+ if (mask & 0x8000)
+ mask -= 0x10000;
+ }
+ else
+ {
+ if (mask & 0x80)
+ mask -= 0x100;
+ }
+
+ switch ( (INTVAL (operands[3]) ? 4 : 0)
+ + ((GET_MODE (op0) == HImode) ? 2 : 0)
+ + (TARGET_A24 ? 1 : 0))
+ {
+ case 0: p = gen_andqi3_16 (op0, src0, GEN_INT (mask)); break;
+ case 1: p = gen_andqi3_24 (op0, src0, GEN_INT (mask)); break;
+ case 2: p = gen_andhi3_16 (op0, src0, GEN_INT (mask)); break;
+ case 3: p = gen_andhi3_24 (op0, src0, GEN_INT (mask)); break;
+ case 4: p = gen_iorqi3_16 (op0, src0, GEN_INT (mask)); break;
+ case 5: p = gen_iorqi3_24 (op0, src0, GEN_INT (mask)); break;
+ case 6: p = gen_iorhi3_16 (op0, src0, GEN_INT (mask)); break;
+ case 7: p = gen_iorhi3_24 (op0, src0, GEN_INT (mask)); break;
+ }
+
+ emit_insn (p);
+ return 0;
+}
+
+const char *
+m32c_scc_pattern(rtx *operands, RTX_CODE code)
+{
+ static char buf[30];
+ if (GET_CODE (operands[0]) == REG
+ && REGNO (operands[0]) == R0_REGNO)
+ {
+ if (code == EQ)
+ return "stzx\t#1,#0,r0l";
+ if (code == NE)
+ return "stzx\t#0,#1,r0l";
+ }
+ sprintf(buf, "bm%s\t0,%%h0\n\tand.b\t#1,%%0", GET_RTX_NAME (code));
+ return buf;
+}
+
/* Returns TRUE if the current function is a leaf, and thus we can
determine which registers an interrupt function really needs to
save. The logic below is mostly about finding the insn sequence
{ 0x0000000a }, /* R23 - r2 r3 */\
{ 0x0000000f }, /* R03 - r0r2 r1r3 */\
{ 0x0000000f }, /* DI - r0r2r1r3 + mems */\
+ { 0x00000010 }, /* A0 - a0 */\
+ { 0x00000020 }, /* A1 - a1 */\
{ 0x00000030 }, /* A - a0 a1 */\
{ 0x000000f0 }, /* AD - a0 a1 sb fp */\
{ 0x000001f0 }, /* PS - a0 a1 sb fp sp */\
- { 0x0000003f }, /* SI - r0r2 r1r3 a0a1 */\
+ { 0x0000000f }, /* SI - r0r2 r1r3 a0a1 */\
{ 0x0000003f }, /* HI - r0 r1 r2 r3 a0 a1 */\
{ 0x0000003f }, /* RA - r0..r3 a0 a1 */\
{ 0x0000007f }, /* GENERAL */\
R23_REGS,
R03_REGS,
DI_REGS,
+ A0_REGS,
+ A1_REGS,
A_REGS,
AD_REGS,
PS_REGS,
"R23_REGS", \
"R03_REGS", \
"DI_REGS", \
+"A0_REGS", \
+"A1_REGS", \
"A_REGS", \
"AD_REGS", \
"PS_REGS", \
#define MOVE_MAX 4
#define TRULY_NOOP_TRUNCATION(op,ip) 1
+#define STORE_FLAG_VALUE 1
+
/* 16 or 24 bit pointers */
#define Pmode (TARGET_A16 ? HImode : PSImode)
#define FUNCTION_MODE QImode
(UNS_EH_EPILOGUE 3)
(UNS_PUSHM 4)
(UNS_POPM 5)
+ (UNS_SMOVF 6)
+ (UNS_SSTR 7)
+ (UNS_SCMPU 8)
+ (UNS_SMOVU 9)
])
+;; n = no change, x = clobbered. The first 16 values are chosen such
+;; that the enum has one bit set for each flag.
+(define_attr "flags" "x,c,z,zc,s,sc,sz,szc,o,oc,oz,ozc,os,osc,osz,oszc,n" (const_string "n"))
+(define_asm_attributes [(set_attr "flags" "x")])
+
+(define_mode_macro QHI [QI HI])
+(define_mode_macro HPSI [(HI "TARGET_A16") (PSI "TARGET_A24")])
+(define_mode_macro QHPSI [QI HI (PSI "TARGET_A24")])
+(define_mode_macro QHSI [QI HI (SI "TARGET_A24")])
+(define_mode_attr bwl [(QI "b") (HI "w") (PSI "l") (SI "l")])
+
+(define_code_macro any_cond [eq ne gt ge lt le gtu geu ltu leu])
+(define_code_macro eqne_cond [eq ne])
+(define_code_macro gl_cond [gt ge lt le gtu geu ltu leu])
+
+
+
(define_insn "nop"
[(const_int 0)]
""
"nop")
-;; n = no change, x = clobbered. The first 16 values are chosen such
-;; that the enum has one bit set for each flag.
-(define_attr "flags" "x,c,z,zc,s,sc,sz,szc,o,oc,oz,ozc,os,osc,osz,oszc,n" (const_string "n"))
-(define_asm_attributes [(set_attr "flags" "x")])
+(define_insn "no_insn"
+ [(const_int 1)]
+ ""
+ "")
;; Match push/pop before mov.b for passing char as arg,
;; e.g. stdlib/efgcvt.c.
(define_insn "movqi_op"
- [(set (match_operand:QI 0 "mra_qi_operand"
+ [(set (match_operand:QI 0 "m32c_nonimmediate_operand"
"=Rqi*Rmm, <, RqiSd*Rmm, SdSs, Rqi*Rmm, Sd")
- (match_operand:QI 1 "mrai_qi_operand"
+ (match_operand:QI 1 "m32c_any_operand"
"iRqi*Rmm, iRqiSd*Rmm, >, Rqi*Rmm, SdSs, i"))]
"m32c_mov_ok (operands, QImode)"
"@
)
(define_expand "movqi"
- [(set (match_operand:QI 0 "mra_qi_operand" "=RqiSd*Rmm")
- (match_operand:QI 1 "mrai_qi_operand" "iRqiSd*Rmm"))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=RqiSd*Rmm")
+ (match_operand:QI 1 "general_operand" "iRqiSd*Rmm"))]
""
"if (m32c_prepare_move (operands, QImode)) DONE;"
)
(define_insn "movhi_op"
- [(set (match_operand:HI 0 "nonimmediate_operand"
+ [(set (match_operand:HI 0 "m32c_nonimmediate_operand"
"=Rhi*Rmm, Sd, SdSs, *Rcr, RhiSd*Rmm, <, RhiSd*Rmm, <, *Rcr")
- (match_operand:HI 1 "general_operand"
+ (match_operand:HI 1 "m32c_any_operand"
"iRhi*RmmSdSs, i, Rhi*Rmm, RhiSd*Rmm, *Rcr, iRhiSd*Rmm, >, *Rcr, >"))]
"m32c_mov_ok (operands, HImode)"
"@
)
(define_expand "movhi"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=RhiSd*Rmm")
- (match_operand:HI 1 "general_operand" "iRhiSd*Rmm"))]
+ [(set (match_operand:HI 0 "m32c_nonimmediate_operand" "=RhiSd*Rmm")
+ (match_operand:HI 1 "m32c_any_operand" "iRhiSd*Rmm"))]
""
"if (m32c_prepare_move (operands, HImode)) DONE;"
)
(define_insn "movpsi_op"
- [(set (match_operand:PSI 0 "nonimmediate_operand"
- "=Raa, SdRmmRpi, Rcl, RpiSd*Rmm, <, <, Rcl, Rsi*Rmm")
- (match_operand:PSI 1 "general_operand"
- "sIU3, iSdRmmRpi, iRpiSd*Rmm, Rcl, Rsi*Rmm, Rcl, >, >"))]
+ [(set (match_operand:PSI 0 "m32c_nonimmediate_operand"
+ "=Raa, SdRmmRpi, Rcl, RpiSd*Rmm, <, <, Rcl, RpiRaa*Rmm")
+ (match_operand:PSI 1 "m32c_any_operand"
+ "sIU3, iSdRmmRpi, iRpiSd*Rmm, Rcl, Rpi*Rmm, Rcl, >, >"))]
"TARGET_A24 && m32c_mov_ok (operands, PSImode)"
"@
mov.l:s\t%1,%0
;; The intention here is to combine the add with the move to create an
;; indexed move. GCC doesn't always figure this out itself.
-(define_mode_macro QHSI [QI HI SI])
-(define_mode_macro HPSI [(HI "TARGET_A16") (PSI "TARGET_A24")])
-
(define_peephole2
[(set (match_operand:HPSI 0 "register_operand" "")
(plus:HPSI (match_operand:HPSI 1 "register_operand" "")
(plus:HPSI (match_operand:HPSI 1 "register_operand" "")
(match_operand:HPSI 2 "immediate_operand" "")))
(set (mem:QHSI (match_operand:HPSI 4 "register_operand" ""))
- (match_operand:QHSI 3 "general_operand" ""))]
+ (match_operand:QHSI 3 "m32c_any_operand" ""))]
"REGNO (operands[0]) == REGNO (operands[1])
&& REGNO (operands[0]) == REGNO (operands[4])
&& dead_or_set_p (peep2_next_insn (1), operands[4])
; Some PSI moves must be split.
(define_split
- [(set (match_operand:PSI 0 "nonimmediate_operand" "")
- (match_operand:PSI 1 "general_operand" ""))]
+ [(set (match_operand:PSI 0 "m32c_nonimmediate_operand" "")
+ (match_operand:PSI 1 "m32c_any_operand" ""))]
"reload_completed && m32c_split_psi_p (operands)"
[(set (match_dup 2)
(match_dup 3))
)
(define_expand "movpsi"
- [(set (match_operand:PSI 0 "mras_operand" "")
- (match_operand:PSI 1 "mrasi_operand" ""))]
+ [(set (match_operand:PSI 0 "m32c_nonimmediate_operand" "")
+ (match_operand:PSI 1 "m32c_any_operand" ""))]
""
"if (m32c_prepare_move (operands, PSImode)) DONE;"
)
(define_expand "movsi"
- [(set (match_operand:SI 0 "mras_operand" "=RsiSd*Rmm")
- (match_operand:SI 1 "mrasi_operand" "iRsiSd*Rmm"))]
+ [(set (match_operand:SI 0 "m32c_nonimmediate_operand" "=RsiSd*Rmm")
+ (match_operand:SI 1 "m32c_any_operand" "iRsiSd*Rmm"))]
""
"if (m32c_split_move (operands, SImode, 0)) DONE;"
)
; All SI moves are split if TARGET_A16
(define_insn_and_split "movsi_splittable"
- [(set (match_operand:SI 0 "mras_operand" "=Rsi<*Rmm,RsiSd*Rmm,Ss")
- (match_operand:SI 1 "mrasi_operand" "iRsiSd*Rmm,iRsi>*Rmm,Rsi*Rmm"))]
+ [(set (match_operand:SI 0 "m32c_nonimmediate_operand" "=Rsi<*Rmm,RsiSd*Rmm,Ss")
+ (match_operand:SI 1 "m32c_any_operand" "iRsiSd*Rmm,iRsi>*Rmm,Rsi*Rmm"))]
"TARGET_A16"
"#"
"TARGET_A16 && reload_completed"
; don't match.
(define_insn "push_a01_l"
[(set (mem:SI (pre_dec:PSI (reg:PSI SP_REGNO)))
- (match_operand 0 "a_operand" ""))]
+ (match_operand 0 "a_operand" "Raa"))]
""
"push.l\t%0"
)
(define_insn "movsi_24"
- [(set (match_operand:SI 0 "mras_operand" "=Rsi*Rmm, Sd, RsiSd*Rmm, <")
- (match_operand:SI 1 "mrasi_operand" "iRsiSd*Rmm, iRsi*Rmm, >, iRsiRaaSd*Rmm"))]
+ [(set (match_operand:SI 0 "m32c_nonimmediate_operand" "=Rsi*Rmm, Sd, RsiSd*Rmm, <")
+ (match_operand:SI 1 "m32c_any_operand" "iRsiSd*Rmm, iRsi*Rmm, >, iRsiRaaSd*Rmm"))]
"TARGET_A24"
"@
mov.l\t%1,%0
)
(define_expand "movdi"
- [(set (match_operand:DI 0 "mras_operand" "=RdiSd*Rmm")
- (match_operand:DI 1 "mrasi_operand" "iRdiSd*Rmm"))]
+ [(set (match_operand:DI 0 "m32c_nonimmediate_operand" "=RdiSd*Rmm")
+ (match_operand:DI 1 "m32c_any_operand" "iRdiSd*Rmm"))]
""
"if (m32c_split_move (operands, DImode, 0)) DONE;"
)
(define_insn_and_split "movdi_splittable"
- [(set (match_operand:DI 0 "mras_operand" "=Rdi<*Rmm,RdiSd*Rmm")
- (match_operand:DI 1 "mrasi_operand" "iRdiSd*Rmm,iRdi>*Rmm"))]
+ [(set (match_operand:DI 0 "m32c_nonimmediate_operand" "=Rdi<*Rmm,RdiSd*Rmm")
+ (match_operand:DI 1 "m32c_any_operand" "iRdiSd*Rmm,iRdi>*Rmm"))]
""
"#"
"reload_completed"
;; Rhl used here as an HI-mode Rxl
(define_insn "extendqihi2"
-[(set (match_operand:HI 0 "mra_operand" "=RhlSd*Rmm")
+[(set (match_operand:HI 0 "m32c_nonimmediate_operand" "=RhlSd*Rmm")
(sign_extend:HI (match_operand:QI 1 "mra_operand" "0")))]
""
"exts.b\t%1"
)
(define_insn "extendhisi2"
- [(set (match_operand:SI 0 "r0123_operand" "=R03")
+ [(set (match_operand:SI 0 "register_operand" "=R03")
(sign_extend:SI (match_operand:HI 1 "r0123_operand" "0")))]
""
"*
)
(define_insn "zero_extendhipsi2"
- [(set (match_operand:PSI 0 "nonimmediate_operand" "=Raa")
- (truncate:PSI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "Rhi"))))]
+ [(set (match_operand:PSI 0 "register_operand" "=Raa")
+ (truncate:PSI (zero_extend:SI (match_operand:HI 1 "register_operand" "R03"))))]
""
"mov.w\t%1,%0"
)
(define_insn "zero_extendhisi2"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=RsiSd")
+ [(set (match_operand:SI 0 "m32c_nonimmediate_operand" "=RsiSd")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")))]
""
"mov.w\t#0,%H0"
)
(define_insn "zero_extendqihi2"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=RsiRaaSd*Rmm")
- (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0")))]
+ [(set (match_operand:HI 0 "m32c_nonimmediate_operand" "=Rhl,RhiSd*Rmm")
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,0")))]
""
- "and.w\t#255,%0"
+ "@
+ mov.b\t#0,%H0
+ and.w\t#255,%0"
)
(define_insn "truncsipsi2_16"
- [(set (match_operand:PSI 0 "nonimmediate_operand" "=RsiRadSd*Rmm,Raa,Rcr,RsiSd*Rmm")
+ [(set (match_operand:PSI 0 "m32c_nonimmediate_operand" "=RsiRadSd*Rmm,Raa,Rcr,RsiSd*Rmm")
(truncate:PSI (match_operand:SI 1 "nonimmediate_operand" "0,RsiSd*Rmm,RsiSd*Rmm,Rcr")))]
"TARGET_A16"
"@
)
(define_insn "trunchiqi2"
- [(set (match_operand:QI 0 "mra_qi_operand" "=RqiRmmSd")
+ [(set (match_operand:QI 0 "m32c_nonimmediate_operand" "=RqiRmmSd")
(truncate:QI (match_operand:HI 1 "mra_qi_operand" "0")))]
""
"; no-op trunc hi %1 to qi %0"
)
(define_insn "truncsipsi2_24"
- [(set (match_operand:PSI 0 "nonimmediate_operand" "=RsiSd*Rmm,Raa,!Rcl,RsiSd*Rmm")
- (truncate:PSI (match_operand:SI 1 "nonimmediate_operand" "0,RsiSd*Rmm,RsiSd*Rmm,!Rcl")))]
+ [(set (match_operand:PSI 0 "m32c_nonimmediate_operand" "=RsiSd*Rmm,Raa,!Rcl,RsiSd*Rmm")
+ (truncate:PSI (match_operand:SI 1 "m32c_nonimmediate_operand" "0,RsiSd*Rmm,RsiSd*Rmm,!Rcl")))]
"TARGET_A24"
"@
; no-op trunc si %1 to psi %0
)
(define_expand "truncsipsi2"
- [(set (match_operand:PSI 0 "nonimmediate_operand" "=RsiRadSd*Rmm,Raa,Rcr,RsiSd*Rmm")
- (truncate:PSI (match_operand:SI 1 "nonimmediate_operand" "0,RsiSd*Rmm,RsiSd*Rmm,Rcr")))]
+ [(set (match_operand:PSI 0 "m32c_nonimmediate_operand" "=RsiRadSd*Rmm,Raa,Rcr,RsiSd*Rmm")
+ (truncate:PSI (match_operand:SI 1 "m32c_nonimmediate_operand" "0,RsiSd*Rmm,RsiSd*Rmm,Rcr")))]
""
""
)
(mult:PSI (match_operand:PSI 1 "mra_operand" "%0")
(match_operand 2 "m32c_psi_scale" "Ilb")))]
"TARGET_A24"
- "if (INTVAL(operands[2]) < 0)
+ "if (GET_CODE (operands[2]) != CONST_INT
+ || INTVAL(operands[2]) < 0)
{
m32c_expand_neg_mulpsi3 (operands);
DONE;
;; Predicates
+; TRUE for any valid operand. We do this because general_operand
+; refuses to match volatile memory refs.
+
+(define_predicate "m32c_any_operand"
+ (ior (match_operand 0 "general_operand")
+ (match_operand 1 "memory_operand")))
+
+; Likewise for nonimmediate_operand.
+
+(define_predicate "m32c_nonimmediate_operand"
+ (ior (match_operand 0 "nonimmediate_operand")
+ (match_operand 1 "memory_operand")))
+
; TRUE if the operand is a pseudo-register.
(define_predicate "m32c_pseudo"
(ior (and (match_code "reg")
(and (match_code "reg")
(match_test "REGNO(op) == R1_REGNO"))))
+; TRUE for HL_CLASS (r0 or r1)
+(define_predicate "m32c_hl_operand"
+ (ior (match_operand 0 "m32c_pseudo" "")
+ (and (match_code "reg")
+ (match_test "REGNO(op) == R0_REGNO || REGNO(op) == R1_REGNO"))))
+
+
; TRUE for r2
(define_predicate "m32c_r2_operand"
(ior (match_operand 0 "m32c_pseudo" "")
(and (match_code "reg")
(match_test "REGNO(op) == R2_REGNO"))))
+; TRUE for r3
+(define_predicate "m32c_r3_operand"
+ (ior (match_operand 0 "m32c_pseudo" "")
+ (and (match_code "reg")
+ (match_test "REGNO(op) == R3_REGNO"))))
+
; TRUE for any general operand except r2.
(define_predicate "m32c_notr2_operand"
(and (match_operand 0 "general_operand")
; TRUE for $a0 or $a1.
(define_predicate "a_operand"
- (match_code "reg")
- "return (REGNO (op) == A0_REGNO
- || REGNO (op) == A1_REGNO);")
+ (and (match_code "reg")
+ (match_test "REGNO (op) == A0_REGNO || REGNO (op) == A1_REGNO")))
+
+; TRUE for $a0 or $a1 or a pseudo
+(define_predicate "ap_operand"
+ (ior (match_operand 0 "m32c_pseudo" "")
+ (and (match_code "reg")
+ (match_test "REGNO (op) == A0_REGNO || REGNO (op) == A1_REGNO"))))
; TRUE for r0 through r3, or a0 or a1.
(define_predicate "ra_operand"
; TRUE for memory, r0..r3, a0..a1, or immediates.
(define_predicate "mrai_operand"
- (and (and (match_operand 0 "general_operand" "")
+ (and (and (match_operand 0 "m32c_any_operand" "")
(not (match_operand 1 "cr_operand" "")))
(not (match_operand 2 "m32c_wide_subreg" ""))))
(and (match_operand 0 "mra_operand" "")
(not (match_operand 1 "a_operand" ""))))
-; TRUE for r1h. This complicated since r1h isn't a register GCC
+; TRUE for a0..a1 or memory.
+(define_predicate "ma_operand"
+ (ior (match_operand 0 "a_operand" "")
+ (match_operand 1 "memory_operand" "")))
+
+; TRUE for memory operands that are not indexed
+(define_predicate "memsym_operand"
+ (and (match_operand 0 "memory_operand" "")
+ (match_test "m32c_extra_constraint_p (op, 'S', \"Si\")")))
+
+; TRUE for memory operands with small integer addresses
+(define_predicate "memimmed_operand"
+ (and (match_operand 0 "memory_operand" "")
+ (match_test "m32c_extra_constraint_p (op, 'S', \"Sp\")")))
+
+; TRUE for r1h. This is complicated since r1h isn't a register GCC
; normally knows about.
(define_predicate "r1h_operand"
(match_code "zero_extract")
; These two are only for movqi - no subreg limit
(define_predicate "mra_qi_operand"
- (and (and (match_operand 0 "nonimmediate_operand" "")
+ (and (and (match_operand 0 "m32c_nonimmediate_operand" "")
(not (match_operand 1 "cr_operand" "")))
(not (match_operand 1 "m32c_r2r3a_operand" ""))))
(define_predicate "mrai_qi_operand"
- (and (and (match_operand 0 "general_operand" "")
+ (and (and (match_operand 0 "m32c_any_operand" "")
(not (match_operand 1 "cr_operand" "")))
(not (match_operand 1 "m32c_r2r3a_operand" ""))))
+(define_predicate "a_qi_operand"
+ (ior (match_operand 0 "m32c_pseudo" "")
+ (match_operand 1 "a_operand" "")))
+
; TRUE for comparisons we support.
(define_predicate "m32c_cmp_operator"
(match_code "eq,ne,gt,gtu,lt,ltu,ge,geu,le,leu"))
+(define_predicate "m32c_eqne_operator"
+ (match_code "eq,ne"))
+
; TRUE for mem0
(define_predicate "m32c_mem0_operand"
(ior (match_operand 0 "m32c_pseudo" "")
(define_predicate "m32c_psi_scale"
(and (match_operand 0 "const_int_operand")
(match_test "m32c_const_ok_for_constraint_p(INTVAL(op), 'I', \"Ilb\")")))
+
+; TRUE for one bit set (bit) or clear (mask) out of N bits.
+
+(define_predicate "m32c_1bit8_operand"
+ (and (match_operand 0 "const_int_operand")
+ (match_test "m32c_const_ok_for_constraint_p(INTVAL(op), 'I', \"Ilb\")")))
+
+(define_predicate "m32c_1bit16_operand"
+ (and (match_operand 0 "const_int_operand")
+ (match_test "m32c_const_ok_for_constraint_p(INTVAL(op), 'I', \"Ilw\")")))
+
+(define_predicate "m32c_1mask8_operand"
+ (and (match_operand 0 "const_int_operand")
+ (match_test "m32c_const_ok_for_constraint_p(INTVAL(op), 'I', \"Imb\")")))
+
+(define_predicate "m32c_1mask16_operand"
+ (and (match_operand 0 "const_int_operand")
+ (match_test "m32c_const_ok_for_constraint_p(INTVAL(op), 'I', \"Imw\")")))
md_file = md
-MD_FILES = m32c predicates addsub bitops cond jump minmax mov muldiv prologue shift
+MD_FILES = m32c predicates addsub bitops blkmov cond jump minmax mov muldiv prologue shift
# Doing it this way lets the gen* programs report the right line numbers.