* config/m32c/addsub.md (addqi3): Disparage a0/a1.
authordj <dj@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 9 Mar 2006 03:09:37 +0000 (03:09 +0000)
committerdj <dj@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 9 Mar 2006 03:09:37 +0000 (03:09 +0000)
(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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@111859 138bc75d-0d04-0410-961f-82ee72b054a4

13 files changed:
gcc/ChangeLog
gcc/config/m32c/addsub.md
gcc/config/m32c/bitops.md
gcc/config/m32c/blkmov.md [new file with mode: 0644]
gcc/config/m32c/cond.md
gcc/config/m32c/m32c-protos.h
gcc/config/m32c/m32c.c
gcc/config/m32c/m32c.h
gcc/config/m32c/m32c.md
gcc/config/m32c/mov.md
gcc/config/m32c/muldiv.md
gcc/config/m32c/predicates.md
gcc/config/m32c/t-m32c

index 0aeb088..047033c 100644 (file)
@@ -1,3 +1,69 @@
+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
index 104709c..6ac31dd 100644 (file)
 
 (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"
index e6c269b..e7823b9 100644 (file)
 
 ;; 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;"
+  )
diff --git a/gcc/config/m32c/blkmov.md b/gcc/config/m32c/blkmov.md
new file mode 100644 (file)
index 0000000..44083e4
--- /dev/null
@@ -0,0 +1,243 @@
+;; 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" "*")]
+  )
+  
index c6b42c7..ad8a5d6 100644 (file)
 ; 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)]
+  "")
index ebc4526..eb97796 100644 (file)
@@ -58,8 +58,16 @@ rtx  m32c_function_value (tree, tree);
 
 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);
@@ -86,6 +94,7 @@ int  m32c_reg_ok_for_base_p (rtx, int);
 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 *);
index 73d75d6..75fc3bc 100644 (file)
@@ -412,7 +412,7 @@ m32c_override_options (void)
        error ("invalid target memregs value '%d'", target_memregs);
     }
   else
-    target_memregs = "16";
+    target_memregs = 16;
 }
 
 /* Defining data structures for per-function information */
@@ -490,7 +490,6 @@ static struct
 void
 m32c_conditional_register_usage (void)
 {
-  int memregs;
   int i;
 
   if (0 <= target_memregs && target_memregs <= 16)
@@ -564,8 +563,10 @@ m32c_modes_tieable_p (enum machine_mode m1, enum machine_mode m2)
   if (GET_MODE_SIZE (m1) == GET_MODE_SIZE (m2))
     return 1;
 
+#if 0
   if (m1 == QImode || m2 == QImode)
     return 0;
+#endif
 
   return 1;
 }
@@ -615,10 +616,10 @@ m32c_reg_class_from_constraint (char c ATTRIBUTE_UNUSED, const char *s)
     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)
@@ -637,12 +638,16 @@ m32c_reg_class_from_constraint (char c ATTRIBUTE_UNUSED, const char *s)
     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)
@@ -677,6 +682,12 @@ m32c_reg_class_from_constraint (char c ATTRIBUTE_UNUSED, const char *s)
   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;
 }
 
@@ -914,11 +925,25 @@ m32c_const_ok_for_constraint_p (HOST_WIDE_INT value,
       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;
 }
 
@@ -937,6 +962,12 @@ m32c_extra_constraint_p2 (rtx value, char c ATTRIBUTE_UNUSED, const char *str)
        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"))
@@ -980,6 +1011,12 @@ m32c_extra_constraint_p2 (rtx value, char c ATTRIBUTE_UNUSED, const char *str)
               && (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);
@@ -1683,6 +1720,32 @@ m32c_initialize_trampoline (rtx tramp, rtx function, rtx chainval)
 #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
@@ -2030,6 +2093,107 @@ m32c_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
   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 */
@@ -2111,6 +2275,7 @@ const conversions[] = {
   { 'X', "i", "#0" },
   { 'm', "i", "#0" },
   { 'b', "i", "#0" },
+  { 'B', "i", "0" },
   { 'p', "i", "0" },
 
   { 0, 0, 0 }
@@ -2253,6 +2418,39 @@ m32c_print_operand (FILE * file, rtx x, int code)
       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;
@@ -2284,8 +2482,17 @@ m32c_print_operand (FILE * file, rtx x, int code)
                  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.  */
@@ -2838,6 +3045,184 @@ m32c_split_move (rtx * operands, enum machine_mode mode, int split_all)
   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
@@ -2857,11 +3242,14 @@ shift_gen_func_for (int mode, int code)
   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)
 {
@@ -2971,23 +3359,154 @@ m32c_expand_neg_mulpsi3 (rtx * operands)
 {
   /* 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
index b9eb223..3ac81a1 100644 (file)
@@ -261,10 +261,12 @@ machine_function;
   { 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 */\
@@ -297,6 +299,8 @@ enum reg_class
   R23_REGS,
   R03_REGS,
   DI_REGS,
+  A0_REGS,
+  A1_REGS,
   A_REGS,
   AD_REGS,
   PS_REGS,
@@ -335,6 +339,8 @@ enum reg_class
 "R23_REGS", \
 "R03_REGS", \
 "DI_REGS", \
+"A0_REGS", \
+"A1_REGS", \
 "A_REGS", \
 "AD_REGS", \
 "PS_REGS", \
@@ -656,6 +662,8 @@ typedef struct m32c_cumulative_args
 #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
index aa6d3d7..f1930d4 100644 (file)
    (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)]
+  ""
+  "")
index c3794a3..1a6878d 100644 (file)
@@ -32,9 +32,9 @@
 ;; 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")))]
   ""
   ""
   )
index bf6f357..038ca8a 100644 (file)
        (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;
index c3b44b8..5b9549c 100644 (file)
 
 ;; 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\")")))
index a7b8ec7..eb5882d 100644 (file)
@@ -48,7 +48,7 @@ dp-bit.c: $(srcdir)/config/fp-bit.c
 
 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.