Commit 07127a0a by DJ Delorie Committed by DJ Delorie

addsub.md (addqi3): Disparage a0/a1.

* 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.

From-SVN: r111859
parent 8b3a0b71
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> 2006-03-08 Andreas Tobler <a.tobler@schweiz.ch>
* dwarf2out.c (expand_builtin_dwarf_sp_column): Make dwarf_regnum * dwarf2out.c (expand_builtin_dwarf_sp_column): Make dwarf_regnum
......
...@@ -24,22 +24,22 @@ ...@@ -24,22 +24,22 @@
(define_insn "addqi3" (define_insn "addqi3"
[(set (match_operand:QI 0 "mra_or_sp_operand" [(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" (plus:QI (match_operand:QI 1 "mra_operand"
"%0,0,0,0, 0,0,0,0") "%0,0,0,0, 0,0,0,0")
(match_operand:QI 2 "mrai_operand" (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" "add.b\t%2,%0"
[(set_attr "flags" "oszc")] [(set_attr "flags" "oszc")]
) )
(define_insn "addhi3" (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") "=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") "%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")))] "IU2sSdRhi,?Rmm,IU2sSdRhi,?Rmm, IM2,IM2, IS2IU2, I00, IS1, i")))]
"" ""
"@ "@
...@@ -57,45 +57,19 @@ ...@@ -57,45 +57,19 @@
) )
(define_insn "addpsi3" (define_insn "addpsi3"
[(set (match_operand:PSI 0 "nonimmediate_operand" "=SdRpi,SdRpi,Rsp*Rmm, Rpi,Rpi,Rhi,&Rhi") [(set (match_operand:PSI 0 "m32c_nonimmediate_operand" "=Rpi,Raa,SdRpi,SdRpi,Rsp*Rmm, Rpi,Rpi")
(plus:PSI (match_operand:PSI 1 "nonimmediate_operand" "0,0,0, Raa,Rad,!Rcl,Rhi") (plus:PSI (match_operand:PSI 1 "m32c_nonimmediate_operand" "0,0,0,0,0, Raa,Rad")
(match_operand:PSI 2 "general_operand" "iSdRpi,?Rmm,i, i,IS2,i,!Rcl")))] (match_operand:PSI 2 "m32c_any_operand" "Is3,IS1,iSdRpi,?Rmm,i, i,IS2")))]
"TARGET_A24" "TARGET_A24"
"@ "@
add.%&\t%2,%0 add.l:q\t%2,%0
add.%&\t%2,%0 addx\t%2,%0
add.%&\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
mova\t%D2[%1],%0 mova\t%D2[%1],%0"
# [(set_attr "flags" "oszc,oszc,oszc,oszc,oszc,*,*")]
#"
[(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)))]
""
) )
(define_insn "subqi3" (define_insn "subqi3"
......
...@@ -22,40 +22,247 @@ ...@@ -22,40 +22,247 @@
;; Bit-wise operations (and, ior, xor, shift) ;; Bit-wise operations (and, ior, xor, shift)
(define_insn "andqi3" ; On the R8C and M16C, "address" for bit instructions is usually (but
[(set (match_operand:QI 0 "mra_operand" "=RhlSd,RhlSd,??Rmm,??Rmm") ; not always!) the *bit* address, not the *byte* address. This
(and:QI (match_operand:QI 1 "mra_operand" "%0,0,0,0") ; confuses gcc, so we avoid cases where gcc would produce the wrong
(match_operand:QI 2 "mrai_operand" "iRhlSd,?Rmm,iRhlSd,?Rmm")))] ; 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" "if (TARGET_A16)
[(set_attr "flags" "sz,sz,sz,sz")] 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" (define_expand "andhi3"
[(set (match_operand:HI 0 "mra_operand" "=RhiSd,??Rmm,RhiSd,??Rmm") [(set (match_operand:HI 0 "mra_operand" "")
(and:HI (match_operand:HI 1 "mra_operand" "%0,0,0,0") (and:HI (match_operand:HI 1 "mra_operand" "")
(match_operand:HI 2 "mrai_operand" "iRhiSd,?Rmm,?Rmm,iRhiSd")))] (match_operand:HI 2 "mrai_operand" "")))]
"" ""
"and.w\t%X2,%0" "if (TARGET_A16)
[(set_attr "flags" "sz,sz,sz,sz")] 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" (define_expand "iorqi3"
[(set (match_operand:QI 0 "mra_operand" "=RqiSd,??Rmm,RqiSd,??Rmm") [(set (match_operand:QI 0 "mra_operand" "")
(ior:QI (match_operand:QI 1 "mra_operand" "%0,0,0,0") (ior:QI (match_operand:QI 1 "mra_operand" "")
(match_operand:QI 2 "mrai_operand" "iRhlSd,iRhlSd,?Rmm,?Rmm")))] (match_operand:QI 2 "mrai_operand" "")))]
"" ""
"or.b\t%x2,%0" "if (TARGET_A16)
[(set_attr "flags" "sz,sz,sz,sz")] 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" (define_expand "iorhi3"
[(set (match_operand:HI 0 "mra_operand" "=RhiSd,RhiSd,??Rmm,??Rmm") [(set (match_operand:HI 0 "mra_operand" "")
(ior:HI (match_operand:HI 1 "mra_operand" "%0,0,0,0") (ior:HI (match_operand:HI 1 "mra_operand" "")
(match_operand:HI 2 "mrai_operand" "iRhiSd,?Rmm,iRhiSd,?Rmm")))] (match_operand:HI 2 "mrai_operand" "")))]
"" ""
"or.w\t%X2,%0" "if (TARGET_A16)
[(set_attr "flags" "sz,sz,sz,sz")] 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" (define_insn "xorqi3"
...@@ -91,3 +298,38 @@ ...@@ -91,3 +298,38 @@
"not.w\t%0" "not.w\t%0"
[(set_attr "flags" "sz,sz")] [(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;"
)
;; 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" "*")]
)
...@@ -32,41 +32,152 @@ ...@@ -32,41 +32,152 @@
; right flags already. For example, a mov followed by a "cmp *,0" is ; right flags already. For example, a mov followed by a "cmp *,0" is
; redundant; the move already set the Z flag. ; redundant; the move already set the Z flag.
(define_insn "cbranchqi4" (define_insn_and_split "cbranch<mode>4"
[(set (pc) (if_then_else [(set (pc) (if_then_else
(match_operator 0 "m32c_cmp_operator" (match_operator 0 "m32c_cmp_operator"
[(match_operand:QI 1 "mrai_operand" "RqiSd,RqiSd,?Rmm,?Rmm") [(match_operand:QHPSI 1 "mra_operand" "RraSd")
(match_operand:QI 2 "mrai_operand" "iRqiSd,?Rmm,iRqiSd,?Rmm")]) (match_operand:QHPSI 2 "mrai_operand" "iRraSd")])
(label_ref (match_operand 3 "" "")) (label_ref (match_operand 3 "" ""))
(pc)))] (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" (define_insn "stzx_16"
[(set (pc) (if_then_else [(set (match_operand:QI 0 "mrai_operand" "=R0w,R0w,R0w")
(match_operator 0 "m32c_cmp_operator" (if_then_else:QI (eq (reg:CC FLG_REGNO) (const_int 0))
[(match_operand:HI 1 "mrai_operand" "Rhi,?Sd,Rhi,?Sd,?Rmm,?Rmm") (match_operand:QI 1 "const_int_operand" "i,i,0")
(match_operand:HI 2 "mrai_operand" "iRhiSd,iRhiSd,?Rmm,?Rmm,iRhiSd,?Rmm")]) (match_operand:QI 2 "const_int_operand" "i,0,i")))]
(label_ref (match_operand 3 "" "")) "TARGET_A16"
(pc)))] "@
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 (define_insn "cmp<mode>"
(match_operator 0 "m32c_cmp_operator" [(set (reg:CC FLG_REGNO)
[(match_operand:PSI 1 "mrai_operand" "RsiSd,RsiSd,?Rmm,?Rmm") (compare (match_operand:QHPSI 0 "mra_operand" "RraSd")
(match_operand:PSI 2 "mrai_operand" "iRsiSd,?Rmm,iRsiSd,?Rmm")]) (match_operand:QHPSI 1 "mrai_operand" "RraSdi")))]
(label_ref (match_operand 3 "" "")) ""
(pc)))] "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" "TARGET_A24"
"cmp.l\t%2,%1\n\tj%C0\t1f\n\tjmp.a\t%l3\n1:" "sc<code>\t%0")
; "cmp.l\t%2,%1\n\tj%c0\t%l3"
[(set_attr "flags" "oszc,oszc,oszc,oszc")] (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)]
"")
...@@ -58,8 +58,16 @@ rtx m32c_function_value (tree, tree); ...@@ -58,8 +58,16 @@ rtx m32c_function_value (tree, tree);
int m32c_cannot_change_mode_class (MM, MM, int); int m32c_cannot_change_mode_class (MM, MM, int);
int m32c_class_max_nregs (int, MM); int m32c_class_max_nregs (int, MM);
rtx m32c_cmp_flg_0 (rtx);
rtx m32c_eh_return_stackadj_rtx (void); rtx m32c_eh_return_stackadj_rtx (void);
void m32c_emit_eh_epilogue (rtx); 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_p (rtx, char, const char *);
int m32c_extra_constraint_p2 (rtx, char, const char *); int m32c_extra_constraint_p2 (rtx, char, const char *);
int m32c_hard_regno_nregs (int, MM); int m32c_hard_regno_nregs (int, MM);
...@@ -86,6 +94,7 @@ int m32c_reg_ok_for_base_p (rtx, int); ...@@ -86,6 +94,7 @@ int m32c_reg_ok_for_base_p (rtx, int);
int m32c_register_move_cost (MM, int, int); int m32c_register_move_cost (MM, int, int);
MM m32c_regno_reg_class (int); MM m32c_regno_reg_class (int);
rtx m32c_return_addr_rtx (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_secondary_reload_class (int, MM, rtx);
int m32c_split_move (rtx *, MM, int); int m32c_split_move (rtx *, MM, int);
int m32c_split_psi_p (rtx *); int m32c_split_psi_p (rtx *);
......
...@@ -412,7 +412,7 @@ m32c_override_options (void) ...@@ -412,7 +412,7 @@ m32c_override_options (void)
error ("invalid target memregs value '%d'", target_memregs); error ("invalid target memregs value '%d'", target_memregs);
} }
else else
target_memregs = "16"; target_memregs = 16;
} }
/* Defining data structures for per-function information */ /* Defining data structures for per-function information */
...@@ -490,7 +490,6 @@ static struct ...@@ -490,7 +490,6 @@ static struct
void void
m32c_conditional_register_usage (void) m32c_conditional_register_usage (void)
{ {
int memregs;
int i; int i;
if (0 <= target_memregs && target_memregs <= 16) if (0 <= target_memregs && target_memregs <= 16)
...@@ -564,8 +563,10 @@ m32c_modes_tieable_p (enum machine_mode m1, enum machine_mode m2) ...@@ -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)) if (GET_MODE_SIZE (m1) == GET_MODE_SIZE (m2))
return 1; return 1;
#if 0
if (m1 == QImode || m2 == QImode) if (m1 == QImode || m2 == QImode)
return 0; return 0;
#endif
return 1; return 1;
} }
...@@ -615,10 +616,10 @@ m32c_reg_class_from_constraint (char c ATTRIBUTE_UNUSED, const char *s) ...@@ -615,10 +616,10 @@ m32c_reg_class_from_constraint (char c ATTRIBUTE_UNUSED, const char *s)
return FB_REGS; return FB_REGS;
if (memcmp (s, "Rsb", 3) == 0) if (memcmp (s, "Rsb", 3) == 0)
return SB_REGS; return SB_REGS;
if (memcmp (s, "Rcr", 3) == 0 && TARGET_A16) if (memcmp (s, "Rcr", 3) == 0)
return CR_REGS; return TARGET_A16 ? CR_REGS : NO_REGS;
if (memcmp (s, "Rcl", 3) == 0 && TARGET_A24) if (memcmp (s, "Rcl", 3) == 0)
return CR_REGS; return TARGET_A24 ? CR_REGS : NO_REGS;
if (memcmp (s, "R0w", 3) == 0) if (memcmp (s, "R0w", 3) == 0)
return R0_REGS; return R0_REGS;
if (memcmp (s, "R1w", 3) == 0) if (memcmp (s, "R1w", 3) == 0)
...@@ -637,12 +638,16 @@ m32c_reg_class_from_constraint (char c ATTRIBUTE_UNUSED, const char *s) ...@@ -637,12 +638,16 @@ m32c_reg_class_from_constraint (char c ATTRIBUTE_UNUSED, const char *s)
return HL_REGS; return HL_REGS;
if (memcmp (s, "R23", 3) == 0) if (memcmp (s, "R23", 3) == 0)
return R23_REGS; 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) if (memcmp (s, "Raa", 3) == 0)
return A_REGS; return A_REGS;
if (memcmp (s, "Raw", 3) == 0 && TARGET_A16) if (memcmp (s, "Raw", 3) == 0)
return A_REGS; return TARGET_A16 ? A_REGS : NO_REGS;
if (memcmp (s, "Ral", 3) == 0 && TARGET_A24) if (memcmp (s, "Ral", 3) == 0)
return A_REGS; return TARGET_A24 ? A_REGS : NO_REGS;
if (memcmp (s, "Rqi", 3) == 0) if (memcmp (s, "Rqi", 3) == 0)
return QI_REGS; return QI_REGS;
if (memcmp (s, "Rad", 3) == 0) if (memcmp (s, "Rad", 3) == 0)
...@@ -677,6 +682,12 @@ m32c_reg_class_from_constraint (char c ATTRIBUTE_UNUSED, const char *s) ...@@ -677,6 +682,12 @@ m32c_reg_class_from_constraint (char c ATTRIBUTE_UNUSED, const char *s)
if (memcmp (s, "Rpa", 3) == 0) if (memcmp (s, "Rpa", 3) == 0)
return NO_REGS; return NO_REGS;
if (*s == 'R')
{
fprintf(stderr, "unrecognized R constraint: %.3s\n", s);
gcc_unreachable();
}
return NO_REGS; return NO_REGS;
} }
...@@ -914,11 +925,25 @@ m32c_const_ok_for_constraint_p (HOST_WIDE_INT value, ...@@ -914,11 +925,25 @@ m32c_const_ok_for_constraint_p (HOST_WIDE_INT value,
int b = exact_log2 (value); int b = exact_log2 (value);
return (b >= 1 && b <= 8); 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) if (memcmp (str, "Ilw", 3) == 0)
{ {
int b = exact_log2 (value); int b = exact_log2 (value);
return (b >= 1 && b <= 16); return (b >= 1 && b <= 16);
} }
if (memcmp (str, "Imw", 3) == 0)
{
int b = exact_log2 ((value ^ 0xffff) & 0xffff);
return (b >= 1 && b <= 16);
}
if (memcmp (str, "I00", 3) == 0)
{
return (value == 0);
}
return 0; return 0;
} }
...@@ -937,6 +962,12 @@ m32c_extra_constraint_p2 (rtx value, char c ATTRIBUTE_UNUSED, const char *str) ...@@ -937,6 +962,12 @@ m32c_extra_constraint_p2 (rtx value, char c ATTRIBUTE_UNUSED, const char *str)
return 1; return 1;
if (RTX_IS ("ms") || RTX_IS ("m+si")) if (RTX_IS ("ms") || RTX_IS ("m+si"))
return 1; return 1;
if (RTX_IS ("m++rii"))
{
if (REGNO (patternr[3]) == FB_REGNO
&& INTVAL (patternr[4]) == 0)
return 1;
}
if (RTX_IS ("mr")) if (RTX_IS ("mr"))
r = patternr[1]; r = patternr[1];
else if (RTX_IS ("m+ri") || RTX_IS ("m+rs") || RTX_IS ("m+r+si")) 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) ...@@ -980,6 +1011,12 @@ m32c_extra_constraint_p2 (rtx value, char c ATTRIBUTE_UNUSED, const char *str)
&& (IS_REG (patternr[1], SB_REGNO))) && (IS_REG (patternr[1], SB_REGNO)))
|| (RTX_IS ("m+ri") && (IS_REG (patternr[2], 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) else if (memcmp (str, "S1", 2) == 0)
{ {
return r1h_operand (value, QImode); return r1h_operand (value, QImode);
...@@ -1683,6 +1720,32 @@ m32c_initialize_trampoline (rtx tramp, rtx function, rtx chainval) ...@@ -1683,6 +1720,32 @@ m32c_initialize_trampoline (rtx tramp, rtx function, rtx chainval)
#undef A0 #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 */ /* Addressing Modes */
/* Used by GO_IF_LEGITIMATE_ADDRESS. The r8c/m32c family supports a /* 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, ...@@ -2030,6 +2093,107 @@ m32c_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
return COSTS_N_INSNS (10); 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 */ /* Defining the Output Assembler Language */
/* The Overall Framework of an Assembler File */ /* The Overall Framework of an Assembler File */
...@@ -2111,6 +2275,7 @@ const conversions[] = { ...@@ -2111,6 +2275,7 @@ const conversions[] = {
{ 'X', "i", "#0" }, { 'X', "i", "#0" },
{ 'm', "i", "#0" }, { 'm', "i", "#0" },
{ 'b', "i", "#0" }, { 'b', "i", "#0" },
{ 'B', "i", "0" },
{ 'p', "i", "0" }, { 'p', "i", "0" },
{ 0, 0, 0 } { 0, 0, 0 }
...@@ -2253,6 +2418,39 @@ m32c_print_operand (FILE * file, rtx x, int code) ...@@ -2253,6 +2418,39 @@ m32c_print_operand (FILE * file, rtx x, int code)
x = m32c_subreg (HImode, x, SImode, 2); x = m32c_subreg (HImode, x, SImode, 2);
code = 0; 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. */ /* 'x' and 'X' need to be ignored for non-immediates. */
if ((code == 'x' || code == 'X') && GET_CODE (x) != CONST_INT) if ((code == 'x' || code == 'X') && GET_CODE (x) != CONST_INT)
code = 0; code = 0;
...@@ -2284,8 +2482,17 @@ m32c_print_operand (FILE * file, rtx x, int code) ...@@ -2284,8 +2482,17 @@ m32c_print_operand (FILE * file, rtx x, int code)
switch (code) switch (code)
{ {
case 'b': case 'b':
/* Bit position. */ case 'B':
fprintf (file, "%d", (int) exact_log2 (INTVAL (r))); {
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; break;
case 'x': case 'x':
/* Unsigned byte. */ /* Unsigned byte. */
...@@ -2838,6 +3045,184 @@ m32c_split_move (rtx * operands, enum machine_mode mode, int split_all) ...@@ -2838,6 +3045,184 @@ m32c_split_move (rtx * operands, enum machine_mode mode, int split_all)
return rv; 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); typedef rtx (*shift_gen_func)(rtx, rtx, rtx);
static shift_gen_func static shift_gen_func
...@@ -2857,11 +3242,14 @@ shift_gen_func_for (int mode, int code) ...@@ -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, ASHIFTRT, TARGET_A16 ? gen_ashrsi3_16 : gen_ashrsi3_24);
GFF(SImode, LSHIFTRT, TARGET_A16 ? gen_lshrsi3_16 : gen_lshrsi3_24); GFF(SImode, LSHIFTRT, TARGET_A16 ? gen_lshrsi3_16 : gen_lshrsi3_24);
#undef GFF #undef GFF
gcc_unreachable ();
} }
/* The m32c only has one shift, but it takes a signed count. GCC /* 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 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 int
m32c_prepare_shift (rtx * operands, int scale, int shift_code) m32c_prepare_shift (rtx * operands, int scale, int shift_code)
{ {
...@@ -2971,23 +3359,154 @@ m32c_expand_neg_mulpsi3 (rtx * operands) ...@@ -2971,23 +3359,154 @@ m32c_expand_neg_mulpsi3 (rtx * operands)
{ {
/* operands: a = b * i */ /* operands: a = b * i */
rtx temp1; /* b as SI */ rtx temp1; /* b as SI */
rtx temp2; /* -b as SI */ rtx scale /* i as SI */;
rtx temp3; /* -b as PSI */ rtx temp2; /* a*b as SI */
rtx scale;
temp1 = gen_reg_rtx (SImode); temp1 = gen_reg_rtx (SImode);
temp2 = gen_reg_rtx (SImode); temp2 = gen_reg_rtx (SImode);
temp3 = gen_reg_rtx (PSImode); if (GET_CODE (operands[2]) != CONST_INT)
scale = GEN_INT (- INTVAL (operands[2])); {
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_zero_extendpsisi2 (temp1, operands[1]));
emit_insn (gen_negsi2 (temp2, temp1)); temp2 = expand_simple_binop (SImode, MULT, temp1, scale, temp2, 1, OPTAB_LIB);
emit_insn (gen_truncsipsi2 (temp3, temp2)); emit_insn (gen_truncsipsi2 (operands[0], temp2));
emit_insn (gen_mulpsi3 (operands[0], temp3, scale));
} }
/* Pattern Output Functions */ /* 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 /* Returns TRUE if the current function is a leaf, and thus we can
determine which registers an interrupt function really needs to determine which registers an interrupt function really needs to
save. The logic below is mostly about finding the insn sequence save. The logic below is mostly about finding the insn sequence
......
...@@ -261,10 +261,12 @@ machine_function; ...@@ -261,10 +261,12 @@ machine_function;
{ 0x0000000a }, /* R23 - r2 r3 */\ { 0x0000000a }, /* R23 - r2 r3 */\
{ 0x0000000f }, /* R03 - r0r2 r1r3 */\ { 0x0000000f }, /* R03 - r0r2 r1r3 */\
{ 0x0000000f }, /* DI - r0r2r1r3 + mems */\ { 0x0000000f }, /* DI - r0r2r1r3 + mems */\
{ 0x00000010 }, /* A0 - a0 */\
{ 0x00000020 }, /* A1 - a1 */\
{ 0x00000030 }, /* A - a0 a1 */\ { 0x00000030 }, /* A - a0 a1 */\
{ 0x000000f0 }, /* AD - a0 a1 sb fp */\ { 0x000000f0 }, /* AD - a0 a1 sb fp */\
{ 0x000001f0 }, /* PS - a0 a1 sb fp sp */\ { 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 }, /* HI - r0 r1 r2 r3 a0 a1 */\
{ 0x0000003f }, /* RA - r0..r3 a0 a1 */\ { 0x0000003f }, /* RA - r0..r3 a0 a1 */\
{ 0x0000007f }, /* GENERAL */\ { 0x0000007f }, /* GENERAL */\
...@@ -297,6 +299,8 @@ enum reg_class ...@@ -297,6 +299,8 @@ enum reg_class
R23_REGS, R23_REGS,
R03_REGS, R03_REGS,
DI_REGS, DI_REGS,
A0_REGS,
A1_REGS,
A_REGS, A_REGS,
AD_REGS, AD_REGS,
PS_REGS, PS_REGS,
...@@ -335,6 +339,8 @@ enum reg_class ...@@ -335,6 +339,8 @@ enum reg_class
"R23_REGS", \ "R23_REGS", \
"R03_REGS", \ "R03_REGS", \
"DI_REGS", \ "DI_REGS", \
"A0_REGS", \
"A1_REGS", \
"A_REGS", \ "A_REGS", \
"AD_REGS", \ "AD_REGS", \
"PS_REGS", \ "PS_REGS", \
...@@ -656,6 +662,8 @@ typedef struct m32c_cumulative_args ...@@ -656,6 +662,8 @@ typedef struct m32c_cumulative_args
#define MOVE_MAX 4 #define MOVE_MAX 4
#define TRULY_NOOP_TRUNCATION(op,ip) 1 #define TRULY_NOOP_TRUNCATION(op,ip) 1
#define STORE_FLAG_VALUE 1
/* 16 or 24 bit pointers */ /* 16 or 24 bit pointers */
#define Pmode (TARGET_A16 ? HImode : PSImode) #define Pmode (TARGET_A16 ? HImode : PSImode)
#define FUNCTION_MODE QImode #define FUNCTION_MODE QImode
......
...@@ -44,14 +44,35 @@ ...@@ -44,14 +44,35 @@
(UNS_EH_EPILOGUE 3) (UNS_EH_EPILOGUE 3)
(UNS_PUSHM 4) (UNS_PUSHM 4)
(UNS_POPM 5) (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" (define_insn "nop"
[(const_int 0)] [(const_int 0)]
"" ""
"nop") "nop")
;; n = no change, x = clobbered. The first 16 values are chosen such (define_insn "no_insn"
;; that the enum has one bit set for each flag. [(const_int 1)]
(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")]) "")
...@@ -32,9 +32,9 @@ ...@@ -32,9 +32,9 @@
;; Match push/pop before mov.b for passing char as arg, ;; Match push/pop before mov.b for passing char as arg,
;; e.g. stdlib/efgcvt.c. ;; e.g. stdlib/efgcvt.c.
(define_insn "movqi_op" (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") "=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"))] "iRqi*Rmm, iRqiSd*Rmm, >, Rqi*Rmm, SdSs, i"))]
"m32c_mov_ok (operands, QImode)" "m32c_mov_ok (operands, QImode)"
"@ "@
...@@ -48,17 +48,17 @@ ...@@ -48,17 +48,17 @@
) )
(define_expand "movqi" (define_expand "movqi"
[(set (match_operand:QI 0 "mra_qi_operand" "=RqiSd*Rmm") [(set (match_operand:QI 0 "nonimmediate_operand" "=RqiSd*Rmm")
(match_operand:QI 1 "mrai_qi_operand" "iRqiSd*Rmm"))] (match_operand:QI 1 "general_operand" "iRqiSd*Rmm"))]
"" ""
"if (m32c_prepare_move (operands, QImode)) DONE;" "if (m32c_prepare_move (operands, QImode)) DONE;"
) )
(define_insn "movhi_op" (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") "=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, >"))] "iRhi*RmmSdSs, i, Rhi*Rmm, RhiSd*Rmm, *Rcr, iRhiSd*Rmm, >, *Rcr, >"))]
"m32c_mov_ok (operands, HImode)" "m32c_mov_ok (operands, HImode)"
"@ "@
...@@ -75,18 +75,18 @@ ...@@ -75,18 +75,18 @@
) )
(define_expand "movhi" (define_expand "movhi"
[(set (match_operand:HI 0 "nonimmediate_operand" "=RhiSd*Rmm") [(set (match_operand:HI 0 "m32c_nonimmediate_operand" "=RhiSd*Rmm")
(match_operand:HI 1 "general_operand" "iRhiSd*Rmm"))] (match_operand:HI 1 "m32c_any_operand" "iRhiSd*Rmm"))]
"" ""
"if (m32c_prepare_move (operands, HImode)) DONE;" "if (m32c_prepare_move (operands, HImode)) DONE;"
) )
(define_insn "movpsi_op" (define_insn "movpsi_op"
[(set (match_operand:PSI 0 "nonimmediate_operand" [(set (match_operand:PSI 0 "m32c_nonimmediate_operand"
"=Raa, SdRmmRpi, Rcl, RpiSd*Rmm, <, <, Rcl, Rsi*Rmm") "=Raa, SdRmmRpi, Rcl, RpiSd*Rmm, <, <, Rcl, RpiRaa*Rmm")
(match_operand:PSI 1 "general_operand" (match_operand:PSI 1 "m32c_any_operand"
"sIU3, iSdRmmRpi, iRpiSd*Rmm, Rcl, Rsi*Rmm, Rcl, >, >"))] "sIU3, iSdRmmRpi, iRpiSd*Rmm, Rcl, Rpi*Rmm, Rcl, >, >"))]
"TARGET_A24 && m32c_mov_ok (operands, PSImode)" "TARGET_A24 && m32c_mov_ok (operands, PSImode)"
"@ "@
mov.l:s\t%1,%0 mov.l:s\t%1,%0
...@@ -104,9 +104,6 @@ ...@@ -104,9 +104,6 @@
;; The intention here is to combine the add with the move to create an ;; The intention here is to combine the add with the move to create an
;; indexed move. GCC doesn't always figure this out itself. ;; 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 (define_peephole2
[(set (match_operand:HPSI 0 "register_operand" "") [(set (match_operand:HPSI 0 "register_operand" "")
(plus:HPSI (match_operand:HPSI 1 "register_operand" "") (plus:HPSI (match_operand:HPSI 1 "register_operand" "")
...@@ -128,7 +125,7 @@ ...@@ -128,7 +125,7 @@
(plus:HPSI (match_operand:HPSI 1 "register_operand" "") (plus:HPSI (match_operand:HPSI 1 "register_operand" "")
(match_operand:HPSI 2 "immediate_operand" ""))) (match_operand:HPSI 2 "immediate_operand" "")))
(set (mem:QHSI (match_operand:HPSI 4 "register_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[1])
&& REGNO (operands[0]) == REGNO (operands[4]) && REGNO (operands[0]) == REGNO (operands[4])
&& dead_or_set_p (peep2_next_insn (1), operands[4]) && dead_or_set_p (peep2_next_insn (1), operands[4])
...@@ -141,8 +138,8 @@ ...@@ -141,8 +138,8 @@
; Some PSI moves must be split. ; Some PSI moves must be split.
(define_split (define_split
[(set (match_operand:PSI 0 "nonimmediate_operand" "") [(set (match_operand:PSI 0 "m32c_nonimmediate_operand" "")
(match_operand:PSI 1 "general_operand" ""))] (match_operand:PSI 1 "m32c_any_operand" ""))]
"reload_completed && m32c_split_psi_p (operands)" "reload_completed && m32c_split_psi_p (operands)"
[(set (match_dup 2) [(set (match_dup 2)
(match_dup 3)) (match_dup 3))
...@@ -152,8 +149,8 @@ ...@@ -152,8 +149,8 @@
) )
(define_expand "movpsi" (define_expand "movpsi"
[(set (match_operand:PSI 0 "mras_operand" "") [(set (match_operand:PSI 0 "m32c_nonimmediate_operand" "")
(match_operand:PSI 1 "mrasi_operand" ""))] (match_operand:PSI 1 "m32c_any_operand" ""))]
"" ""
"if (m32c_prepare_move (operands, PSImode)) DONE;" "if (m32c_prepare_move (operands, PSImode)) DONE;"
) )
...@@ -161,16 +158,16 @@ ...@@ -161,16 +158,16 @@
(define_expand "movsi" (define_expand "movsi"
[(set (match_operand:SI 0 "mras_operand" "=RsiSd*Rmm") [(set (match_operand:SI 0 "m32c_nonimmediate_operand" "=RsiSd*Rmm")
(match_operand:SI 1 "mrasi_operand" "iRsiSd*Rmm"))] (match_operand:SI 1 "m32c_any_operand" "iRsiSd*Rmm"))]
"" ""
"if (m32c_split_move (operands, SImode, 0)) DONE;" "if (m32c_split_move (operands, SImode, 0)) DONE;"
) )
; All SI moves are split if TARGET_A16 ; All SI moves are split if TARGET_A16
(define_insn_and_split "movsi_splittable" (define_insn_and_split "movsi_splittable"
[(set (match_operand:SI 0 "mras_operand" "=Rsi<*Rmm,RsiSd*Rmm,Ss") [(set (match_operand:SI 0 "m32c_nonimmediate_operand" "=Rsi<*Rmm,RsiSd*Rmm,Ss")
(match_operand:SI 1 "mrasi_operand" "iRsiSd*Rmm,iRsi>*Rmm,Rsi*Rmm"))] (match_operand:SI 1 "m32c_any_operand" "iRsiSd*Rmm,iRsi>*Rmm,Rsi*Rmm"))]
"TARGET_A16" "TARGET_A16"
"#" "#"
"TARGET_A16 && reload_completed" "TARGET_A16 && reload_completed"
...@@ -182,14 +179,14 @@ ...@@ -182,14 +179,14 @@
; don't match. ; don't match.
(define_insn "push_a01_l" (define_insn "push_a01_l"
[(set (mem:SI (pre_dec:PSI (reg:PSI SP_REGNO))) [(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" "push.l\t%0"
) )
(define_insn "movsi_24" (define_insn "movsi_24"
[(set (match_operand:SI 0 "mras_operand" "=Rsi*Rmm, Sd, RsiSd*Rmm, <") [(set (match_operand:SI 0 "m32c_nonimmediate_operand" "=Rsi*Rmm, Sd, RsiSd*Rmm, <")
(match_operand:SI 1 "mrasi_operand" "iRsiSd*Rmm, iRsi*Rmm, >, iRsiRaaSd*Rmm"))] (match_operand:SI 1 "m32c_any_operand" "iRsiSd*Rmm, iRsi*Rmm, >, iRsiRaaSd*Rmm"))]
"TARGET_A24" "TARGET_A24"
"@ "@
mov.l\t%1,%0 mov.l\t%1,%0
...@@ -199,15 +196,15 @@ ...@@ -199,15 +196,15 @@
) )
(define_expand "movdi" (define_expand "movdi"
[(set (match_operand:DI 0 "mras_operand" "=RdiSd*Rmm") [(set (match_operand:DI 0 "m32c_nonimmediate_operand" "=RdiSd*Rmm")
(match_operand:DI 1 "mrasi_operand" "iRdiSd*Rmm"))] (match_operand:DI 1 "m32c_any_operand" "iRdiSd*Rmm"))]
"" ""
"if (m32c_split_move (operands, DImode, 0)) DONE;" "if (m32c_split_move (operands, DImode, 0)) DONE;"
) )
(define_insn_and_split "movdi_splittable" (define_insn_and_split "movdi_splittable"
[(set (match_operand:DI 0 "mras_operand" "=Rdi<*Rmm,RdiSd*Rmm") [(set (match_operand:DI 0 "m32c_nonimmediate_operand" "=Rdi<*Rmm,RdiSd*Rmm")
(match_operand:DI 1 "mrasi_operand" "iRdiSd*Rmm,iRdi>*Rmm"))] (match_operand:DI 1 "m32c_any_operand" "iRdiSd*Rmm,iRdi>*Rmm"))]
"" ""
"#" "#"
"reload_completed" "reload_completed"
...@@ -305,7 +302,7 @@ ...@@ -305,7 +302,7 @@
;; Rhl used here as an HI-mode Rxl ;; Rhl used here as an HI-mode Rxl
(define_insn "extendqihi2" (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")))] (sign_extend:HI (match_operand:QI 1 "mra_operand" "0")))]
"" ""
"exts.b\t%1" "exts.b\t%1"
...@@ -313,7 +310,7 @@ ...@@ -313,7 +310,7 @@
) )
(define_insn "extendhisi2" (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")))] (sign_extend:SI (match_operand:HI 1 "r0123_operand" "0")))]
"" ""
"* "*
...@@ -337,28 +334,30 @@ ...@@ -337,28 +334,30 @@
) )
(define_insn "zero_extendhipsi2" (define_insn "zero_extendhipsi2"
[(set (match_operand:PSI 0 "nonimmediate_operand" "=Raa") [(set (match_operand:PSI 0 "register_operand" "=Raa")
(truncate:PSI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "Rhi"))))] (truncate:PSI (zero_extend:SI (match_operand:HI 1 "register_operand" "R03"))))]
"" ""
"mov.w\t%1,%0" "mov.w\t%1,%0"
) )
(define_insn "zero_extendhisi2" (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")))] (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")))]
"" ""
"mov.w\t#0,%H0" "mov.w\t#0,%H0"
) )
(define_insn "zero_extendqihi2" (define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "nonimmediate_operand" "=RsiRaaSd*Rmm") [(set (match_operand:HI 0 "m32c_nonimmediate_operand" "=Rhl,RhiSd*Rmm")
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0")))] (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" (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")))] (truncate:PSI (match_operand:SI 1 "nonimmediate_operand" "0,RsiSd*Rmm,RsiSd*Rmm,Rcr")))]
"TARGET_A16" "TARGET_A16"
"@ "@
...@@ -369,15 +368,15 @@ ...@@ -369,15 +368,15 @@
) )
(define_insn "trunchiqi2" (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")))] (truncate:QI (match_operand:HI 1 "mra_qi_operand" "0")))]
"" ""
"; no-op trunc hi %1 to qi %0" "; no-op trunc hi %1 to qi %0"
) )
(define_insn "truncsipsi2_24" (define_insn "truncsipsi2_24"
[(set (match_operand:PSI 0 "nonimmediate_operand" "=RsiSd*Rmm,Raa,!Rcl,RsiSd*Rmm") [(set (match_operand:PSI 0 "m32c_nonimmediate_operand" "=RsiSd*Rmm,Raa,!Rcl,RsiSd*Rmm")
(truncate:PSI (match_operand:SI 1 "nonimmediate_operand" "0,RsiSd*Rmm,RsiSd*Rmm,!Rcl")))] (truncate:PSI (match_operand:SI 1 "m32c_nonimmediate_operand" "0,RsiSd*Rmm,RsiSd*Rmm,!Rcl")))]
"TARGET_A24" "TARGET_A24"
"@ "@
; no-op trunc si %1 to psi %0 ; no-op trunc si %1 to psi %0
...@@ -387,8 +386,8 @@ ...@@ -387,8 +386,8 @@
) )
(define_expand "truncsipsi2" (define_expand "truncsipsi2"
[(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")))] (truncate:PSI (match_operand:SI 1 "m32c_nonimmediate_operand" "0,RsiSd*Rmm,RsiSd*Rmm,Rcr")))]
"" ""
"" ""
) )
......
...@@ -143,7 +143,8 @@ ...@@ -143,7 +143,8 @@
(mult:PSI (match_operand:PSI 1 "mra_operand" "%0") (mult:PSI (match_operand:PSI 1 "mra_operand" "%0")
(match_operand 2 "m32c_psi_scale" "Ilb")))] (match_operand 2 "m32c_psi_scale" "Ilb")))]
"TARGET_A24" "TARGET_A24"
"if (INTVAL(operands[2]) < 0) "if (GET_CODE (operands[2]) != CONST_INT
|| INTVAL(operands[2]) < 0)
{ {
m32c_expand_neg_mulpsi3 (operands); m32c_expand_neg_mulpsi3 (operands);
DONE; DONE;
......
...@@ -22,6 +22,19 @@ ...@@ -22,6 +22,19 @@
;; Predicates ;; 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. ; TRUE if the operand is a pseudo-register.
(define_predicate "m32c_pseudo" (define_predicate "m32c_pseudo"
(ior (and (match_code "reg") (ior (and (match_code "reg")
...@@ -63,12 +76,25 @@ ...@@ -63,12 +76,25 @@
(and (match_code "reg") (and (match_code "reg")
(match_test "REGNO(op) == R1_REGNO")))) (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 ; TRUE for r2
(define_predicate "m32c_r2_operand" (define_predicate "m32c_r2_operand"
(ior (match_operand 0 "m32c_pseudo" "") (ior (match_operand 0 "m32c_pseudo" "")
(and (match_code "reg") (and (match_code "reg")
(match_test "REGNO(op) == R2_REGNO")))) (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. ; TRUE for any general operand except r2.
(define_predicate "m32c_notr2_operand" (define_predicate "m32c_notr2_operand"
(and (match_operand 0 "general_operand") (and (match_operand 0 "general_operand")
...@@ -89,9 +115,14 @@ ...@@ -89,9 +115,14 @@
; TRUE for $a0 or $a1. ; TRUE for $a0 or $a1.
(define_predicate "a_operand" (define_predicate "a_operand"
(match_code "reg") (and (match_code "reg")
"return (REGNO (op) == A0_REGNO (match_test "REGNO (op) == A0_REGNO || REGNO (op) == A1_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. ; TRUE for r0 through r3, or a0 or a1.
(define_predicate "ra_operand" (define_predicate "ra_operand"
...@@ -112,7 +143,7 @@ ...@@ -112,7 +143,7 @@
; TRUE for memory, r0..r3, a0..a1, or immediates. ; TRUE for memory, r0..r3, a0..a1, or immediates.
(define_predicate "mrai_operand" (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 1 "cr_operand" "")))
(not (match_operand 2 "m32c_wide_subreg" "")))) (not (match_operand 2 "m32c_wide_subreg" ""))))
...@@ -126,7 +157,22 @@ ...@@ -126,7 +157,22 @@
(and (match_operand 0 "mra_operand" "") (and (match_operand 0 "mra_operand" "")
(not (match_operand 1 "a_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. ; normally knows about.
(define_predicate "r1h_operand" (define_predicate "r1h_operand"
(match_code "zero_extract") (match_code "zero_extract")
...@@ -175,19 +221,26 @@ ...@@ -175,19 +221,26 @@
; These two are only for movqi - no subreg limit ; These two are only for movqi - no subreg limit
(define_predicate "mra_qi_operand" (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 "cr_operand" "")))
(not (match_operand 1 "m32c_r2r3a_operand" "")))) (not (match_operand 1 "m32c_r2r3a_operand" ""))))
(define_predicate "mrai_qi_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 "cr_operand" "")))
(not (match_operand 1 "m32c_r2r3a_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. ; TRUE for comparisons we support.
(define_predicate "m32c_cmp_operator" (define_predicate "m32c_cmp_operator"
(match_code "eq,ne,gt,gtu,lt,ltu,ge,geu,le,leu")) (match_code "eq,ne,gt,gtu,lt,ltu,ge,geu,le,leu"))
(define_predicate "m32c_eqne_operator"
(match_code "eq,ne"))
; TRUE for mem0 ; TRUE for mem0
(define_predicate "m32c_mem0_operand" (define_predicate "m32c_mem0_operand"
(ior (match_operand 0 "m32c_pseudo" "") (ior (match_operand 0 "m32c_pseudo" "")
...@@ -204,3 +257,21 @@ ...@@ -204,3 +257,21 @@
(define_predicate "m32c_psi_scale" (define_predicate "m32c_psi_scale"
(and (match_operand 0 "const_int_operand") (and (match_operand 0 "const_int_operand")
(match_test "m32c_const_ok_for_constraint_p(INTVAL(op), 'I', \"Ilb\")"))) (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\")")))
...@@ -48,7 +48,7 @@ dp-bit.c: $(srcdir)/config/fp-bit.c ...@@ -48,7 +48,7 @@ dp-bit.c: $(srcdir)/config/fp-bit.c
md_file = md 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. # Doing it this way lets the gen* programs report the right line numbers.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment