--- gcc/config/m68k.md 2018/04/24 17:51:30 1.1 +++ gcc/config/m68k.md 2018/04/24 17:53:39 1.1.1.2 @@ -61,7 +61,7 @@ ;;- "%-" push operand "sp@-" move%.l d0,%- ;;- "%+" pop operand "sp@+" move%.l d0,%+ ;;- "%@" top of stack "sp@" move%.l d0,%@ -;;- "%!" ??? "cc" (not used) +;;- "%!" fpcr register ;;- "%$" single-precision fp specifier ("s" or "") f%$add.x fp0,fp1 ;;- "%&" double-precision fp specifier ("d" or "") f%&add.x fp0,fp1 @@ -221,7 +221,7 @@ ;;- "command register" mode means that no accessing of memory or the ;;- 68000 registers is being done. This can be expressed easily in ;;- constraints, so generally the mode of the instruction is -;;- determined by a branch off of which_alternative. In outputing +;;- determined by a branch off of which_alternative. In outputting ;;- instructions, a 'w' means to output an access to the constant ram ;;- (if the arg is CONST_DOUBLE and is one of the available ;;- constants), and 'x' means to output a register pair (if the arg is @@ -691,7 +691,7 @@ ;; ;; This is the main "hook" for PIC code. When generating ;; PIC, movsi is responsible for determining when the source address -;; needs PIC relocation and appropriatly calling legitimize_pic_address +;; needs PIC relocation and appropriately calling legitimize_pic_address ;; to perform the actual relocation. ;; ;; In both the PIC and non-PIC cases the patterns generated will @@ -1156,7 +1156,7 @@ { if (GET_CODE (operands[0]) == REG) { - /* Must clear condition codes, since the mov.l bases them on + /* Must clear condition codes, since the move.l bases them on the entire 32 bits, not just the desired 8 bits. */ CC_STATUS_INIT; return \"move%.l %1,%0\"; @@ -1177,14 +1177,14 @@ && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[1]) == CONST_INT)) { - /* Must clear condition codes, since the mov.w bases them on + /* Must clear condition codes, since the move.w bases them on the entire 16 bits, not just the desired 8 bits. */ CC_STATUS_INIT; return \"move%.w %1,%0\"; } if (GET_CODE (operands[0]) == REG) { - /* Must clear condition codes, since the mov.l bases them on + /* Must clear condition codes, since the move.l bases them on the entire 32 bits, not just the desired 8 bits. */ CC_STATUS_INIT; return \"move%.l %1,%0\"; @@ -1203,7 +1203,7 @@ { if (GET_CODE (operands[0]) == REG) { - /* Must clear condition codes, since the mov.l bases them on + /* Must clear condition codes, since the move.l bases them on the entire 32 bits, not just the desired 8 bits. */ CC_STATUS_INIT; return \"move%.l %1,%0\"; @@ -1577,7 +1577,7 @@ "* { CC_STATUS_INIT; - return \"fmovem%.l fpcr,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w #-33,%3\;fmovem%.l %3,fpcr\;fmove%.l %1,%0\;fmovem%.l %2,fpcr\"; + return \"fmovem%.l %!,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w #-33,%3\;fmovem%.l %3,%!\;fmove%.l %1,%0\;fmovem%.l %2,%!\"; }") (define_insn "fix_truncdfhi2" @@ -1589,7 +1589,7 @@ "* { CC_STATUS_INIT; - return \"fmovem%.l fpcr,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w #-33,%3\;fmovem%.l %3,fpcr\;fmove%.w %1,%0\;fmovem%.l %2,fpcr\"; + return \"fmovem%.l %!,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w #-33,%3\;fmovem%.l %3,%!\;fmove%.w %1,%0\;fmovem%.l %2,%!\"; }") (define_insn "fix_truncdfqi2" @@ -1601,7 +1601,7 @@ "* { CC_STATUS_INIT; - return \"fmovem%.l fpcr,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w #-33,%3\;fmovem%.l %3,fpcr\;fmove%.b %1,%0\;fmovem%.l %2,fpcr\"; + return \"fmovem%.l %!,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w #-33,%3\;fmovem%.l %3,%!\;fmove%.b %1,%0\;fmovem%.l %2,%!\"; }") ;; Convert a float to a float whose value is an integer. @@ -1747,7 +1747,7 @@ : \"subq%.l %2,%0\"); } /* On everything except the 68000 it is faster to use two - addqw instuctions to add a small integer (8 < N <= 16) + addqw instructions to add a small integer (8 < N <= 16) to an address register. Likewise for subqw.*/ if (INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16 @@ -1793,6 +1793,15 @@ #ifndef NO_ADDSUB_Q if (GET_CODE (operands[2]) == CONST_INT) { + /* If the constant would be a negative number when interpreted as + HImode, make it negative. This is usually, but not always, done + elsewhere in the compiler. First check for constants out of range, + which could confuse us. */ + + if (INTVAL (operands[2]) >= 32768) + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) - 65536); + if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) <= 8) return \"addq%.w %2,%0\"; @@ -1804,7 +1813,7 @@ return \"subq%.w %2,%0\"; } /* On everything except the 68000 it is faster to use two - addqw instuctions to add a small integer (8 < N <= 16) + addqw insttuctions to add a small integer (8 < N <= 16) to an address register. Likewise for subqw. */ if (INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16 @@ -1828,12 +1837,119 @@ return \"add%.w %2,%0\"; }") +;; These insns must use MATCH_DUP instead of the more expected +;; use of a matching constraint because the "output" here is also +;; an input, so you can't use the matching constraint. That also means +;; that you can't use the "%", so you need patterns with the matched +;; operand in both positions. + (define_insn "" [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) (plus:HI (match_dup 0) (match_operand:HI 1 "general_operand" "dn,rmn")))] "" - "add%.w %1,%0") + "* +{ +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[1]) == CONST_INT) + { + /* If the constant would be a negative number when interpreted as + HImode, make it negative. This is usually, but not always, done + elsewhere in the compiler. First check for constants out of range, + which could confuse us. */ + + if (INTVAL (operands[1]) >= 32768) + operands[1] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[1]) - 65536); + + if (INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= 8) + return \"addq%.w %1,%0\"; + if (INTVAL (operands[1]) < 0 + && INTVAL (operands[1]) >= -8) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + - INTVAL (operands[1])); + return \"subq%.w %1,%0\"; + } + /* On everything except the 68000 it is faster to use two + addqw instuctions to add a small integer (8 < N <= 16) + to an address register. Likewise for subqw. */ + if (INTVAL (operands[1]) > 8 + && INTVAL (operands[1]) <= 16 + && ADDRESS_REG_P (operands[0]) + && TARGET_68020) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) - 8); + return \"addq%.w %#8,%0; addq%.w %1,%0\"; + } + if (INTVAL (operands[1]) < -8 + && INTVAL (operands[1]) >= -16 + && ADDRESS_REG_P (operands[0]) + && TARGET_68020) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + - INTVAL (operands[1]) - 8); + return \"subq%.w %#8,%0; subq%.w %1,%0\"; + } + } +#endif + return \"add%.w %1,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (plus:HI (match_operand:HI 1 "general_operand" "dn,rmn") + (match_dup 0)))] + "" + "* +{ +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[1]) == CONST_INT) + { + /* If the constant would be a negative number when interpreted as + HImode, make it negative. This is usually, but not always, done + elsewhere in the compiler. First check for constants out of range, + which could confuse us. */ + + if (INTVAL (operands[1]) >= 32768) + operands[1] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[1]) - 65536); + + if (INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= 8) + return \"addq%.w %1,%0\"; + if (INTVAL (operands[1]) < 0 + && INTVAL (operands[1]) >= -8) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + - INTVAL (operands[1])); + return \"subq%.w %1,%0\"; + } + /* On everything except the 68000 it is faster to use two + addqw instuctions to add a small integer (8 < N <= 16) + to an address register. Likewise for subqw. */ + if (INTVAL (operands[1]) > 8 + && INTVAL (operands[1]) <= 16 + && ADDRESS_REG_P (operands[0]) + && TARGET_68020) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) - 8); + return \"addq%.w %#8,%0; addq%.w %1,%0\"; + } + if (INTVAL (operands[1]) < -8 + && INTVAL (operands[1]) >= -16 + && ADDRESS_REG_P (operands[0]) + && TARGET_68020) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + - INTVAL (operands[1]) - 8); + return \"subq%.w %#8,%0; subq%.w %1,%0\"; + } + } +#endif + return \"add%.w %1,%0\"; +}") (define_insn "addqi3" [(set (match_operand:QI 0 "general_operand" "=m,d") @@ -1845,12 +1961,13 @@ #ifndef NO_ADDSUB_Q if (GET_CODE (operands[2]) == CONST_INT) { + if (INTVAL (operands[2]) >= 128) + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) - 256); + if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) <= 8) return \"addq%.b %2,%0\"; - } - if (GET_CODE (operands[2]) == CONST_INT) - { if (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) >= -8) { operands[2] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2])); @@ -1866,7 +1983,54 @@ (plus:QI (match_dup 0) (match_operand:QI 1 "general_operand" "dn,dmn")))] "" - "add%.b %1,%0") + "* +{ +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[1]) == CONST_INT) + { + if (INTVAL (operands[1]) >= 128) + operands[1] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[1]) - 256); + + if (INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= 8) + return \"addq%.b %1,%0\"; + if (INTVAL (operands[1]) < 0 && INTVAL (operands[1]) >= -8) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[1])); + return \"subq%.b %1,%0\"; + } + } +#endif + return \"add%.b %1,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (plus:QI (match_operand:QI 1 "general_operand" "dn,dmn") + (match_dup 0)))] + "" + "* +{ +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[1]) == CONST_INT) + { + if (INTVAL (operands[1]) >= 128) + operands[1] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[1]) - 256); + + if (INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= 8) + return \"addq%.b %1,%0\"; + if (INTVAL (operands[1]) < 0 && INTVAL (operands[1]) >= -8) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[1])); + return \"subq%.b %1,%0\"; + } + } +#endif + return \"add%.b %1,%0\"; +}") (define_expand "adddf3" [(set (match_operand:DF 0 "general_operand" "") @@ -2522,11 +2686,7 @@ /* The swap insn produces cc's that don't correspond to the result. */ CC_STATUS_INIT; #ifdef MOTOROLA -#ifdef SGS_SWAP_W - return \"ext%.l %0\;divs%.w %2,%0\;swap%.w %0\"; -#else return \"ext%.l %0\;divs%.w %2,%0\;swap %0\"; -#endif #else return \"extl %0\;divs %2,%0\;swap %0\"; #endif @@ -2544,11 +2704,7 @@ /* The swap insn produces cc's that don't correspond to the result. */ CC_STATUS_INIT; #ifdef MOTOROLA -#ifdef SGS_SWAP_W - return \"divs%.w %2,%0\;swap%.w %0\"; -#else return \"divs%.w %2,%0\;swap %0\"; -#endif #else return \"divs %2,%0\;swap %0\"; #endif @@ -2564,11 +2720,7 @@ /* The swap insn produces cc's that don't correspond to the result. */ CC_STATUS_INIT; #ifdef MOTOROLA -#ifdef SGS_SWAP_W - return \"divs%.w %2,%0\;swap%.w %0\"; -#else return \"divs%.w %2,%0\;swap %0\"; -#endif #else return \"divs %2,%0\;swap %0\"; #endif @@ -2584,11 +2736,7 @@ /* The swap insn produces cc's that don't correspond to the result. */ CC_STATUS_INIT; #ifdef MOTOROLA -#ifdef SGS_SWAP_W - return \"and%.l %#0xFFFF,%0\;divu%.w %2,%0\;swap%.w %0\"; -#else return \"and%.l %#0xFFFF,%0\;divu%.w %2,%0\;swap %0\"; -#endif #else return \"andl %#0xFFFF,%0\;divu %2,%0\;swap %0\"; #endif @@ -2606,11 +2754,7 @@ /* The swap insn produces cc's that don't correspond to the result. */ CC_STATUS_INIT; #ifdef MOTOROLA -#ifdef SGS_SWAP_W - return \"divu%.w %2,%0\;swap%.w %0\"; -#else return \"divu%.w %2,%0\;swap %0\"; -#endif #else return \"divu %2,%0\;swap %0\"; #endif @@ -2626,11 +2770,7 @@ /* The swap insn produces cc's that don't correspond to the result. */ CC_STATUS_INIT; #ifdef MOTOROLA -#ifdef SGS_SWAP_W - return \"divu%.w %2,%0\;swap%.w %0\"; -#else return \"divu%.w %2,%0\;swap %0\"; -#endif #else return \"divu %2,%0\;swap %0\"; #endif @@ -2670,7 +2810,7 @@ ;; Prevent AND from being made with sp. This doesn't exist in the machine ;; and reload will cause inefficient code. Since sp is a FIXED_REG, we -;; can't allocate psuedos into it. +;; can't allocate pseudos into it. (define_insn "andsi3" [(set (match_operand:SI 0 "not_sp_operand" "=m,d") (and:SI (match_operand:SI 1 "general_operand" "%0,0") @@ -2721,6 +2861,20 @@ "" "and%.w %2,%0") +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (and:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,dmn")))] + "" + "and%.w %1,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (and:HI (match_operand:HI 1 "general_operand" "dn,dmn") + (match_dup 0)))] + "" + "and%.w %1,%0") + (define_insn "andqi3" [(set (match_operand:QI 0 "general_operand" "=m,d") (and:QI (match_operand:QI 1 "general_operand" "%0,0") @@ -2728,6 +2882,19 @@ "" "and%.b %2,%0") +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (and:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "" + "and%.b %1,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (and:QI (match_operand:QI 1 "general_operand" "dn,dmn") + (match_dup 0)))] + "" + "and%.b %1,%0") ;; inclusive-or instructions @@ -2776,12 +2943,40 @@ "" "or%.w %2,%0") +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (ior:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,dmn")))] + "" + "or%.w %1,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (ior:HI (match_operand:HI 1 "general_operand" "dn,dmn") + (match_dup 0)))] + "" + "or%.w %1,%0") + (define_insn "iorqi3" [(set (match_operand:QI 0 "general_operand" "=m,d") (ior:QI (match_operand:QI 1 "general_operand" "%0,0") (match_operand:QI 2 "general_operand" "dn,dmn")))] "" "or%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (ior:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "" + "or%.b %1,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (ior:QI (match_operand:QI 1 "general_operand" "dn,dmn") + (match_dup 0)))] + "" + "or%.b %1,%0") ;; xor instructions @@ -2812,12 +3007,41 @@ "" "eor%.w %2,%0") +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (xor:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn")))] + "" + "eor%.w %1,%0") + + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (xor:HI (match_operand:HI 1 "general_operand" "dn") + (match_dup 0)))] + "" + "eor%.w %1,%0") + (define_insn "xorqi3" [(set (match_operand:QI 0 "general_operand" "=dm") (xor:QI (match_operand:QI 1 "general_operand" "%0") (match_operand:QI 2 "general_operand" "dn")))] "" "eor%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (xor:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn")))] + "" + "eor%.b %1,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (xor:QI (match_operand:QI 1 "general_operand" "dn") + (match_dup 0)))] + "" + "eor%.b %1,%0") ;; negation instructions @@ -2833,12 +3057,24 @@ "" "neg%.w %0") +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (neg:HI (match_dup 0)))] + "" + "neg%.w %0") + (define_insn "negqi2" [(set (match_operand:QI 0 "general_operand" "=dm") (neg:QI (match_operand:QI 1 "general_operand" "0")))] "" "neg%.b %0") +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (neg:QI (match_dup 0)))] + "" + "neg%.b %0") + (define_expand "negsf2" [(set (match_operand:SF 0 "general_operand" "") (neg:SF (match_operand:SF 1 "general_operand" "")))] @@ -2957,15 +3193,40 @@ "" "not%.w %0") +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (not:HI (match_dup 0)))] + "" + "not%.w %0") + (define_insn "one_cmplqi2" [(set (match_operand:QI 0 "general_operand" "=dm") (not:QI (match_operand:QI 1 "general_operand" "0")))] "" "not%.b %0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (not:QI (match_dup 0)))] + "" + "not%.b %0") ;; arithmetic shift instructions ;; We don't need the shift memory by 1 bit instruction +;; On all 68k models, this makes faster code in a special case. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "(GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 16)" + "* +{ + CC_STATUS_INIT; + return \"swap %0\;clr%.w %0\"; +}") + ;; On the 68000, this makes faster code in a special case. (define_insn "" @@ -2973,16 +3234,13 @@ (ashift:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "(! TARGET_68020 && GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) >= 16 && INTVAL (operands[2]) <= 24)" + && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 24)" "* { CC_STATUS_INIT; - if (INTVAL (operands[2]) == 16) - return \"swap %0\;clrw %0\"; - operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) - 16); - return \"asl%.w %2,%0\;swap %0\;clrw %0\"; + return \"asl%.w %2,%0\;swap %0\;clr%.w %0\"; }") (define_insn "ashlsi3" @@ -3004,6 +3262,13 @@ "" "asl%.w %2,%0") +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) + (ashift:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dI")))] + "" + "asl%.w %1,%0") + (define_insn "ashlqi3" [(set (match_operand:QI 0 "register_operand" "=d") (ashift:QI (match_operand:QI 1 "register_operand" "0") @@ -3011,6 +3276,22 @@ "" "asl%.b %2,%0") +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) + (ashift:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dI")))] + "" + "asl%.b %1,%0") + +;; On all 68k models, this makes faster code in a special case. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "(GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 16)" + "swap %0\;ext%.l %0") + ;; On the 68000, this makes faster code in a special case. (define_insn "" @@ -3018,12 +3299,9 @@ (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "(! TARGET_68020 && GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) >= 16 && INTVAL (operands[2]) <= 24)" + && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 24)" "* { - if (INTVAL (operands[2]) == 16) - return \"swap %0\;ext%.l %0\"; - operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) - 16); return \"swap %0\;asr%.w %2,%0\;ext%.l %0\"; }") @@ -3045,15 +3323,42 @@ "" "asr%.w %2,%0") +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) + (ashiftrt:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dI")))] + "" + "asr%.w %1,%0") + (define_insn "ashrqi3" [(set (match_operand:QI 0 "register_operand" "=d") (ashiftrt:QI (match_operand:QI 1 "register_operand" "0") (match_operand:QI 2 "general_operand" "dI")))] "" "asr%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) + (ashiftrt:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dI")))] + "" + "asr%.b %1,%0") ;; logical shift instructions +;; On all 68k models, this makes faster code in a special case. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (lshift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "(GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 16)" + "* +{ + CC_STATUS_INIT; + return \"swap %0\;clr%.w %0\"; +}") + ;; On the 68000, this makes faster code in a special case. (define_insn "" @@ -3061,16 +3366,13 @@ (lshift:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "(! TARGET_68020 && GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) >= 16 && INTVAL (operands[2]) <= 24)" + && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 24)" "* { CC_STATUS_INIT; - if (INTVAL (operands[2]) == 16) - return \"swap %0\;clrw %0\"; - operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) - 16); - return \"lsl%.w %2,%0\;swap %0\;clrw %0\"; + return \"lsl%.w %2,%0\;swap %0\;clr%.w %0\"; }") (define_insn "lshlsi3" @@ -3092,6 +3394,13 @@ "" "lsl%.w %2,%0") +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) + (lshift:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dI")))] + "" + "lsl%.w %1,%0") + (define_insn "lshlqi3" [(set (match_operand:QI 0 "register_operand" "=d") (lshift:QI (match_operand:QI 1 "register_operand" "0") @@ -3099,6 +3408,26 @@ "" "lsl%.b %2,%0") +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) + (lshift:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dI")))] + "" + "lsl%.b %1,%0") + +;; On all 68k models, this makes faster code in a special case. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "(GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 16)" + "* +{ + CC_STATUS_INIT; + return \"clr%.w %0\;swap %0\"; +}") + ;; On the 68000, this makes faster code in a special case. (define_insn "" @@ -3106,18 +3435,12 @@ (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "immediate_operand" "i")))] "(! TARGET_68020 && GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) >= 16 && INTVAL (operands[2]) <= 24)" + && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 24)" "* { - if (INTVAL (operands[2]) == 16) - { - CC_STATUS_INIT; - return \"clrw %0\;swap %0\"; - } - /* I think lsr%.w sets the CC properly. */ operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) - 16); - return \"clrw %0\;swap %0\;lsr%.w %2,%0\"; + return \"clr%.w %0\;swap %0\;lsr%.w %2,%0\"; }") (define_insn "lshrsi3" @@ -3137,12 +3460,26 @@ "" "lsr%.w %2,%0") +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) + (lshiftrt:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dI")))] + "" + "lsr%.w %1,%0") + (define_insn "lshrqi3" [(set (match_operand:QI 0 "register_operand" "=d") (lshiftrt:QI (match_operand:QI 1 "register_operand" "0") (match_operand:QI 2 "general_operand" "dI")))] "" "lsr%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) + (lshiftrt:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dI")))] + "" + "lsr%.b %1,%0") ;; rotate instructions @@ -3160,6 +3497,14 @@ "" "rol%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) + (rotate:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dI")))] + "" + "rol%.w %1,%0") + (define_insn "rotlqi3" [(set (match_operand:QI 0 "register_operand" "=d") (rotate:QI (match_operand:QI 1 "register_operand" "0") @@ -3167,6 +3512,13 @@ "" "rol%.b %2,%0") +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) + (rotate:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dI")))] + "" + "rol%.b %1,%0") + (define_insn "rotrsi3" [(set (match_operand:SI 0 "register_operand" "=d") (rotatert:SI (match_operand:SI 1 "register_operand" "0") @@ -3181,12 +3533,26 @@ "" "ror%.w %2,%0") +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) + (rotatert:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dI")))] + "" + "ror%.w %1,%0") + (define_insn "rotrqi3" [(set (match_operand:QI 0 "register_operand" "=d") (rotatert:QI (match_operand:QI 1 "register_operand" "0") (match_operand:QI 2 "general_operand" "dI")))] "" "ror%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) + (rotatert:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dI")))] + "" + "ror%.b %1,%0") ;; Special cases of bit-field insns which we should ;; recognize in preference to the general case. @@ -4049,7 +4415,7 @@ } #ifdef MOTOROLA #ifdef SGS_CMP_ORDER -#ifndef NO_ADDSUB_Q +#ifdef NO_ADDSUB_Q return \"sub%.w %#1,%0\;cmp%.w %0,%#-1\;jbne %l1\"; #else return \"subq%.w %#1,%0\;cmp%.w %0,%#-1\;jbne %l1\"; @@ -4077,7 +4443,7 @@ { CC_STATUS_INIT; #ifdef MOTOROLA -#ifndef NO_ADDSUB_Q +#ifdef NO_ADDSUB_Q if (DATA_REG_P (operands[0])) return \"dbra %0,%l1\;clr%.w %0\;sub%.l %#1,%0\;jbcc %l1\"; if (GET_CODE (operands[0]) == MEM) @@ -4087,9 +4453,9 @@ return \"dbra %0,%l1\;clr%.w %0\;subq%.l %#1,%0\;jbcc %l1\"; if (GET_CODE (operands[0]) == MEM) return \"subq%.l %#1,%0\;jbcc %l1\"; -#endif /* not NO_ADDSUB_Q */ +#endif /* NO_ADDSUB_Q */ #ifdef SGS_CMP_ORDER -#ifndef NO_ADDSUB_Q +#ifdef NO_ADDSUB_Q return \"sub.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; #else return \"subq.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; @@ -4099,19 +4465,65 @@ #endif /* not SGS_CMP_ORDER */ #else /* not MOTOROLA */ if (DATA_REG_P (operands[0])) - return \"dbra %0,%l1\;clrw %0\;subql %#1,%0\;jcc %l1\"; + return \"dbra %0,%l1\;clr%.w %0\;subql %#1,%0\;jcc %l1\"; if (GET_CODE (operands[0]) == MEM) return \"subql %#1,%0\;jcc %l1\"; return \"subql %#1,%0\;cmpl %#-1,%0\;jne %l1\"; #endif /* not MOTOROLA */ }") -;; dbra patterns that use REG_NOTES info generated by strength_reduce. +;; Two dbra patterns that use REG_NOTES info generated by strength_reduce. + +(define_insn "" + [(set (pc) + (if_then_else + (ge (plus:HI (match_operand:HI 0 "general_operand" "+g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:HI (match_dup 0) + (const_int -1)))] + "find_reg_note (insn, REG_NONNEG, 0)" + "* +{ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifdef NO_ADDSUB_Q + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"sub%.w %#1,%0\;jbcc %l1\"; +#else + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subq%.w %#1,%0\;jbcc %l1\"; +#endif +#ifdef SGS_CMP_ORDER +#ifdef NO_ADDSUB_Q + return \"sub.w %#1,%0\;cmp.w %0,%#-1\;jbne %l1\"; +#else + return \"subq.w %#1,%0\;cmp.w %0,%#-1\;jbne %l1\"; +#endif +#else /* not SGS_CMP_ORDER */ + return \"subq.w %#1,%0\;cmp.w %#-1,%0\;jbne %l1\"; +#endif /* not SGS_CMP_ORDER */ +#else /* not MOTOROLA */ + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subqw %#1,%0\;jcc %l1\"; + return \"subqw %#1,%0\;cmpw %#-1,%0\;jne %l1\"; +#endif /* not MOTOROLA */ +}") (define_insn "decrement_and_branch_until_zero" [(set (pc) (if_then_else - (gt (match_operand:SI 0 "general_operand" "+g") + (ge (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) (const_int 0)) (label_ref (match_operand 1 "" "")) (pc))) @@ -4123,7 +4535,7 @@ { CC_STATUS_INIT; #ifdef MOTOROLA -#ifndef NO_ADDSUB_Q +#ifdef NO_ADDSUB_Q if (DATA_REG_P (operands[0])) return \"dbra %0,%l1\;clr%.w %0\;sub%.l %#1,%0\;jbcc %l1\"; if (GET_CODE (operands[0]) == MEM) @@ -4135,7 +4547,7 @@ return \"subq%.l %#1,%0\;jbcc %l1\"; #endif #ifdef SGS_CMP_ORDER -#ifndef NO_ADDSUB_Q +#ifdef NO_ADDSUB_Q return \"sub.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; #else return \"subq.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; @@ -4145,7 +4557,7 @@ #endif /* not SGS_CMP_ORDER */ #else /* not MOTOROLA */ if (DATA_REG_P (operands[0])) - return \"dbra %0,%l1\;clrw %0\;subql %#1,%0\;jcc %l1\"; + return \"dbra %0,%l1\;clr%.w %0\;subql %#1,%0\;jcc %l1\"; if (GET_CODE (operands[0]) == MEM) return \"subql %#1,%0\;jcc %l1\"; return \"subql %#1,%0\;cmpl %#-1,%0\;jne %l1\"; @@ -4263,7 +4675,7 @@ return \"tstl %0\"; }") -;; Used for framless functions which save no regs and allocate no locals. +;; Used for frameless functions which save no regs and allocate no locals. (define_insn "return" [(return)] "USE_RETURN_INSN" @@ -4413,6 +4825,71 @@ output_asm_insn (\"subq%.w %#4,%3\;move%.b %1,%2\", xoperands); return \"\"; }") + +;; dbCC peepholes +;; +;; Turns +;; loop: +;; [ ... ] +;; jCC label ; abnormal loop termination +;; dbra dN, loop ; normal loop termination +;; +;; Into +;; loop: +;; [ ... ] +;; dbCC dN, loop +;; jCC label +;; +;; Which moves the jCC condition outside the inner loop for free. +;; +(define_peephole + [(set (pc) (if_then_else (match_operator 3 "valid_dbcc_comparison_p" + [(cc0) (const_int 0)]) + (label_ref (match_operand 2 "" "")) + (pc))) + (parallel + [(set (pc) + (if_then_else + (ge (plus:HI (match_operand:HI 0 "register_operand" "+d") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:HI (match_dup 0) + (const_int -1)))])] + "DATA_REG_P (operands[0])" + "* +{ + CC_STATUS_INIT; + output_dbcc_and_branch (operands); + return \"\"; +}") + +(define_peephole + [(set (pc) (if_then_else (match_operator 3 "valid_dbcc_comparison_p" + [(cc0) (const_int 0)]) + (label_ref (match_operand 2 "" "")) + (pc))) + (parallel + [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "register_operand" "+d") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))])] + "DATA_REG_P (operands[0])" + "* +{ + CC_STATUS_INIT; + output_dbcc_and_branch (operands); + return \"\"; +}") + ;; FPA multiply and add. (define_insn ""