From fedc146b41c867a8a0a2f62d5826b51c1cd6ad3d Mon Sep 17 00:00:00 2001 From: dj Date: Thu, 9 Mar 2006 03:09:37 +0000 Subject: [PATCH] * 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. (cbranch4, stzx_16, stzx_24_, stzx_reversed, cmp, b, s, s_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 --- gcc/ChangeLog | 66 +++++ gcc/config/m32c/addsub.md | 56 ++--- gcc/config/m32c/bitops.md | 290 ++++++++++++++++++++-- gcc/config/m32c/blkmov.md | 243 ++++++++++++++++++ gcc/config/m32c/cond.md | 165 +++++++++++-- gcc/config/m32c/m32c-protos.h | 9 + gcc/config/m32c/m32c.c | 561 ++++++++++++++++++++++++++++++++++++++++-- gcc/config/m32c/m32c.h | 10 +- gcc/config/m32c/m32c.md | 29 ++- gcc/config/m32c/mov.md | 89 ++++--- gcc/config/m32c/muldiv.md | 3 +- gcc/config/m32c/predicates.md | 85 ++++++- gcc/config/m32c/t-m32c | 2 +- 13 files changed, 1436 insertions(+), 172 deletions(-) create mode 100644 gcc/config/m32c/blkmov.md diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0aeb088..047033c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,69 @@ +2006-03-08 DJ Delorie + + * 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. + (cbranch4, stzx_16, stzx_24_, stzx_reversed, + cmp, b, s, s_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 * dwarf2out.c (expand_builtin_dwarf_sp_column): Make dwarf_regnum diff --git a/gcc/config/m32c/addsub.md b/gcc/config/m32c/addsub.md index 104709c..6ac31dd 100644 --- a/gcc/config/m32c/addsub.md +++ b/gcc/config/m32c/addsub.md @@ -24,22 +24,22 @@ (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")))] "" "@ @@ -57,45 +57,19 @@ ) (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" diff --git a/gcc/config/m32c/bitops.md b/gcc/config/m32c/bitops.md index e6c269b..e7823b9 100644 --- a/gcc/config/m32c/bitops.md +++ b/gcc/config/m32c/bitops.md @@ -22,40 +22,247 @@ ;; 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" @@ -91,3 +298,38 @@ "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 index 0000000..44083e4 --- /dev/null +++ b/gcc/config/m32c/blkmov.md @@ -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_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_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" "*")] + ) + diff --git a/gcc/config/m32c/cond.md b/gcc/config/m32c/cond.md index c6b42c7..ad8a5d6 100644 --- a/gcc/config/m32c/cond.md +++ b/gcc/config/m32c/cond.md @@ -32,41 +32,152 @@ ; 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 "cbranch4" [(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_" + [(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.\t%1,%2,%0 + stz.\t%1,%0 + stnz.\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" + [(set (reg:CC FLG_REGNO) + (compare (match_operand:QHPSI 0 "mra_operand" "RraSd") + (match_operand:QHPSI 1 "mrai_operand" "RraSdi")))] + "" + "cmp.\t%1,%0") + +(define_insn "b" + [(set (pc) + (if_then_else (any_cond (reg:CC FLG_REGNO) + (const_int 0)) + (label_ref (match_operand 0 "")) + (pc)))] + "" + "j\t%l0" +) + +;; m32c_conditional_register_usage changes the setcc_gen_code array to +;; point to the _24 variants if needed. + +(define_insn "s" + [(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, );") + +(define_insn "s_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\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)] + "") diff --git a/gcc/config/m32c/m32c-protos.h b/gcc/config/m32c/m32c-protos.h index ebc4526..eb97796 100644 --- a/gcc/config/m32c/m32c-protos.h +++ b/gcc/config/m32c/m32c-protos.h @@ -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 *); diff --git a/gcc/config/m32c/m32c.c b/gcc/config/m32c/m32c.c index 73d75d6..75fc3bc 100644 --- a/gcc/config/m32c/m32c.c +++ b/gcc/config/m32c/m32c.c @@ -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 diff --git a/gcc/config/m32c/m32c.h b/gcc/config/m32c/m32c.h index b9eb223..3ac81a1 100644 --- a/gcc/config/m32c/m32c.h +++ b/gcc/config/m32c/m32c.h @@ -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 diff --git a/gcc/config/m32c/m32c.md b/gcc/config/m32c/m32c.md index aa6d3d7..f1930d4 100644 --- a/gcc/config/m32c/m32c.md +++ b/gcc/config/m32c/m32c.md @@ -44,14 +44,35 @@ (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)] + "" + "") diff --git a/gcc/config/m32c/mov.md b/gcc/config/m32c/mov.md index c3794a3..1a6878d 100644 --- a/gcc/config/m32c/mov.md +++ b/gcc/config/m32c/mov.md @@ -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)" "@ @@ -48,17 +48,17 @@ ) (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)" "@ @@ -75,18 +75,18 @@ ) (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 @@ -104,9 +104,6 @@ ;; 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" "") @@ -128,7 +125,7 @@ (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]) @@ -141,8 +138,8 @@ ; 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)) @@ -152,8 +149,8 @@ ) (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;" ) @@ -161,16 +158,16 @@ (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" @@ -182,14 +179,14 @@ ; 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 @@ -199,15 +196,15 @@ ) (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" @@ -305,7 +302,7 @@ ;; 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" @@ -313,7 +310,7 @@ ) (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")))] "" "* @@ -337,28 +334,30 @@ ) (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" "@ @@ -369,15 +368,15 @@ ) (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 @@ -387,8 +386,8 @@ ) (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")))] "" "" ) diff --git a/gcc/config/m32c/muldiv.md b/gcc/config/m32c/muldiv.md index bf6f357..038ca8a 100644 --- a/gcc/config/m32c/muldiv.md +++ b/gcc/config/m32c/muldiv.md @@ -143,7 +143,8 @@ (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; diff --git a/gcc/config/m32c/predicates.md b/gcc/config/m32c/predicates.md index c3b44b8..5b9549c 100644 --- a/gcc/config/m32c/predicates.md +++ b/gcc/config/m32c/predicates.md @@ -22,6 +22,19 @@ ;; 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") @@ -63,12 +76,25 @@ (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") @@ -89,9 +115,14 @@ ; 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" @@ -112,7 +143,7 @@ ; 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" "")))) @@ -126,7 +157,22 @@ (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") @@ -175,19 +221,26 @@ ; 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" "") @@ -204,3 +257,21 @@ (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\")"))) diff --git a/gcc/config/m32c/t-m32c b/gcc/config/m32c/t-m32c index a7b8ec7..eb5882d 100644 --- a/gcc/config/m32c/t-m32c +++ b/gcc/config/m32c/t-m32c @@ -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. -- 2.7.4