aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/avr
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2023-06-10 23:21:13 +0200
committerGeorg-Johann Lay <avr@gjlay.de>2023-06-11 11:21:31 +0200
commit20643513b8dd34c07f2b0fccf119153a30735f66 (patch)
tree05254aa30aefbd2fcdd4af4c633feaad92648775 /gcc/config/avr
parent20c85207abd543c76818032632a5f1b3aea5495b (diff)
downloadgcc-20643513b8dd34c07f2b0fccf119153a30735f66.zip
gcc-20643513b8dd34c07f2b0fccf119153a30735f66.tar.gz
gcc-20643513b8dd34c07f2b0fccf119153a30735f66.tar.bz2
target/19907: Overhaul bit extractions.
o Logical right shift that shifts the MSB to position 0 can be performed in such a way that the input operand constraint can be relaxed from "0" to "r". This results in less register pressure. Moreover, no scratch register is required in that case. o The deprecated "extzv" pattern is replaced by "extzv<mode>" that allows inputs of scalar integer modes of different sizes (1 up to 4 bytes). o Existing patterns are adjusted to the more generic "extzv<mode>" pattern. Some patterns are added as the middle-end has been reworked to spot more bit-extraction opportunities. o A C function is used to print the asm for bit extractions, which is more convenient for complex output logic. The generated code is still not optimal because RTL optimizers might still prefer arithmetic like shift over bit-extractions. For test cases see also PR36884 and PR55181. gcc/ PR target/109907 * config/avr/avr.md (adjust_len) [extr, extr_not]: New elements. (MSB, SIZE): New mode attributes. (any_shift): New code iterator. (*lshr<mode>3_split, *lshr<mode>3, lshr<mode>3) (*lshr<mode>3_const_split): Add constraint alternative for the case of shift-offset = MSB. Ditch "length" attribute. (extzv<mode): New. replaces extzv. Adjust following patterns. Use avr_out_extr, avr_out_extr_not to print asm. (*extzv.subreg.<mode>, *extzv.<mode>.subreg, *extzv.xor) (*extzv<mode>.ge, *neg.ashiftrt<mode>.msb, *extzv.io.lsr7): New. * config/avr/constraints.md (C15, C23, C31, Yil): New * config/avr/predicates.md (reg_or_low_io_operand) (const7_operand, reg_or_low_io_operand) (const15_operand, const_0_to_15_operand) (const23_operand, const_0_to_23_operand) (const31_operand, const_0_to_31_operand): New. * config/avr/avr-protos.h (avr_out_extr, avr_out_extr_not): New. * config/avr/avr.cc (avr_out_extr, avr_out_extr_not): New funcs. (lshrqi3_out, lshrhi3_out, lshrpsi3_out, lshrsi3_out): Adjust MSB case to new insn constraint "r" for operands[1]. (avr_adjust_insn_length) [ADJUST_LEN_EXTR_NOT, ADJUST_LEN_EXTR]: Handle these cases. (avr_rtx_costs_1): Adjust cost for a new pattern. gcc/testsuite/ PR target/109907 * gcc.target/avr/pr109907.c: New test. * gcc.target/avr/torture/pr109907-1.c: New test. * gcc.target/avr/torture/pr109907-2.c: New test.
Diffstat (limited to 'gcc/config/avr')
-rw-r--r--gcc/config/avr/avr-protos.h2
-rw-r--r--gcc/config/avr/avr.cc183
-rw-r--r--gcc/config/avr/avr.md383
-rw-r--r--gcc/config/avr/constraints.md20
-rw-r--r--gcc/config/avr/predicates.md45
5 files changed, 519 insertions, 114 deletions
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index eba6f9f..a10d91d 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -58,6 +58,8 @@ extern const char *ret_cond_branch (rtx x, int len, int reverse);
extern const char *avr_out_movpsi (rtx_insn *, rtx*, int*);
extern const char *avr_out_sign_extend (rtx_insn *, rtx*, int*);
extern const char *avr_out_insert_notbit (rtx_insn *, rtx*, rtx, int*);
+extern const char *avr_out_extr (rtx_insn *, rtx*, int*);
+extern const char *avr_out_extr_not (rtx_insn *, rtx*, int*);
extern const char *avr_out_plus_set_ZN (rtx*, int*);
extern const char *avr_out_cmp_ext (rtx*, enum rtx_code, int*);
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index ff05510..b02fddd 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -7600,9 +7600,9 @@ lshrqi3_out (rtx_insn *insn, rtx operands[], int *len)
case 7:
*len = 3;
- return ("rol %0" CR_TAB
- "clr %0" CR_TAB
- "rol %0");
+ return ("bst %1,7" CR_TAB
+ "clr %0" CR_TAB
+ "bld %0,0");
}
}
else if (CONSTANT_P (operands[2]))
@@ -7859,10 +7859,10 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int *len)
case 15:
*len = 4;
- return ("clr %A0" CR_TAB
- "lsl %B0" CR_TAB
- "rol %A0" CR_TAB
- "clr %B0");
+ return ("bst %B1,7" CR_TAB
+ "clr %A0" CR_TAB
+ "clr %B0" CR_TAB
+ "bld %A0,0");
}
len = t;
}
@@ -7911,11 +7911,11 @@ avr_out_lshrpsi3 (rtx_insn *insn, rtx *op, int *plen)
/* fall through */
case 23:
- return avr_asm_len ("clr %A0" CR_TAB
- "sbrc %C0,7" CR_TAB
- "inc %A0" CR_TAB
- "clr %B0" CR_TAB
- "clr %C0", op, plen, 5);
+ return avr_asm_len ("bst %C1,7" CR_TAB
+ "clr %A0" CR_TAB
+ "clr %B0" CR_TAB
+ "clr %C0" CR_TAB
+ "bld %A0,0", op, plen, 5);
} /* switch */
}
@@ -7998,13 +7998,19 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *len)
"clr %D0");
case 31:
+ if (AVR_HAVE_MOVW)
+ return *len = 5, ("bst %D1,7" CR_TAB
+ "clr %A0" CR_TAB
+ "clr %B0" CR_TAB
+ "movw %C0,%A0" CR_TAB
+ "bld %A0,0");
*len = 6;
- return ("clr %A0" CR_TAB
- "sbrc %D0,7" CR_TAB
- "inc %A0" CR_TAB
- "clr %B0" CR_TAB
- "clr %C0" CR_TAB
- "clr %D0");
+ return ("bst %D1,7" CR_TAB
+ "clr %A0" CR_TAB
+ "clr %B0" CR_TAB
+ "clr %C0" CR_TAB
+ "clr %D0" CR_TAB
+ "bld %A0,0");
}
len = t;
}
@@ -9059,6 +9065,135 @@ avr_out_insert_notbit (rtx_insn *insn, rtx operands[], rtx xbitno, int *plen)
}
+/* Output instructions to extract a bit to 8-bit register XOP[0].
+ The input XOP[1] is a register or an 8-bit MEM in the lower I/O range.
+ XOP[2] is the const_int bit position. Return "".
+
+ PLEN != 0: Set *PLEN to the code length in words. Don't output anything.
+ PLEN == 0: Output instructions. */
+
+const char*
+avr_out_extr (rtx_insn *insn, rtx xop[], int *plen)
+{
+ rtx dest = xop[0];
+ rtx src = xop[1];
+ int bit = INTVAL (xop[2]);
+
+ if (GET_MODE (src) != QImode)
+ {
+ src = xop[1] = simplify_gen_subreg (QImode, src, GET_MODE (src), bit / 8);
+ bit %= 8;
+ xop[2] = GEN_INT (bit);
+ }
+
+ if (MEM_P (src))
+ {
+ xop[1] = XEXP (src, 0); // address
+ gcc_assert (low_io_address_operand (xop[1], Pmode));
+
+ return avr_asm_len ("clr %0" CR_TAB
+ "sbic %i1,%2" CR_TAB
+ "inc %0", xop, plen, -3);
+ }
+
+ gcc_assert (REG_P (src));
+
+ bool ld_dest_p = test_hard_reg_class (LD_REGS, dest);
+ bool ld_src_p = test_hard_reg_class (LD_REGS, src);
+
+ if (ld_dest_p
+ && REGNO (src) == REGNO (dest))
+ {
+ if (bit == 0)
+ return avr_asm_len ("andi %0,1", xop, plen, -1);
+ if (bit == 1)
+ return avr_asm_len ("lsr %0" CR_TAB
+ "andi %0,1", xop, plen, -2);
+ if (bit == 4)
+ return avr_asm_len ("swap %0" CR_TAB
+ "andi %0,1", xop, plen, -2);
+ }
+
+ if (bit == 0
+ && REGNO (src) != REGNO (dest))
+ {
+ if (ld_dest_p)
+ return avr_asm_len ("mov %0,%1" CR_TAB
+ "andi %0,1", xop, plen, -2);
+ if (ld_src_p
+ && reg_unused_after (insn, src))
+ return avr_asm_len ("andi %1,1" CR_TAB
+ "mov %0,%1", xop, plen, -2);
+ }
+
+ return avr_asm_len ("bst %1,%2" CR_TAB
+ "clr %0" CR_TAB
+ "bld %0,0", xop, plen, -3);
+}
+
+
+/* Output instructions to extract a negated bit to 8-bit register XOP[0].
+ The input XOP[1] is an 8-bit register or MEM in the lower I/O range.
+ XOP[2] is the const_int bit position. Return "".
+
+ PLEN != 0: Set *PLEN to the code length in words. Don't output anything.
+ PLEN == 0: Output instructions. */
+
+const char*
+avr_out_extr_not (rtx_insn* /* insn */, rtx xop[], int *plen)
+{
+ rtx dest = xop[0];
+ rtx src = xop[1];
+ int bit = INTVAL (xop[2]);
+
+ if (MEM_P (src))
+ {
+ xop[1] = XEXP (src, 0); // address
+ gcc_assert (low_io_address_operand (xop[1], Pmode));
+
+ return avr_asm_len ("clr %0" CR_TAB
+ "sbis %i1,%2" CR_TAB
+ "inc %0", xop, plen, -3);
+ }
+
+ gcc_assert (REG_P (src));
+
+ bool ld_src_p = test_hard_reg_class (LD_REGS, src);
+
+ if (ld_src_p
+ && REGNO (src) == REGNO (dest))
+ {
+ if (bit == 0)
+ return avr_asm_len ("inc %0" CR_TAB
+ "andi %0,1", xop, plen, -2);
+ if (bit == 1)
+ return avr_asm_len ("lsr %0" CR_TAB
+ "inc %0" CR_TAB
+ "andi %0,1", xop, plen, -3);
+ if (bit == 4)
+ return avr_asm_len ("swap %0" CR_TAB
+ "inc %0" CR_TAB
+ "andi %0,1", xop, plen, -3);
+ }
+
+ if (bit == 7
+ && ld_src_p)
+ return avr_asm_len ("cpi %1,0x80" CR_TAB
+ "sbc %0,%0" CR_TAB
+ "neg %0", xop, plen, -3);
+
+ if (REGNO (src) != REGNO (dest))
+ return avr_asm_len ("clr %0" CR_TAB
+ "sbrs %1,%2" CR_TAB
+ "inc %0", xop, plen, -3);
+
+ return avr_asm_len ("clr __tmp_reg__" CR_TAB
+ "sbrs %1,%2" CR_TAB
+ "inc __tmp_reg__" CR_TAB
+ "mov %0,__tmp_reg__", xop, plen, -4);
+}
+
+
/* Outputs instructions needed for fixed point type conversion.
This includes converting between any fixed point type, as well
as converting to any integer type. Conversion between integer
@@ -9856,6 +9991,8 @@ avr_adjust_insn_length (rtx_insn *insn, int len)
case ADJUST_LEN_RELOAD_IN32: output_reload_insisf (op, op[2], &len); break;
case ADJUST_LEN_OUT_BITOP: avr_out_bitop (insn, op, &len); break;
+ case ADJUST_LEN_EXTR_NOT: avr_out_extr_not (insn, op, &len); break;
+ case ADJUST_LEN_EXTR: avr_out_extr (insn, op, &len); break;
case ADJUST_LEN_PLUS: avr_out_plus (insn, op, &len); break;
case ADJUST_LEN_ADDTO_SP: avr_out_addto_sp (op, &len); break;
@@ -11494,6 +11631,16 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code,
*total = COSTS_N_INSNS (2);
return true;
}
+ if (AND == code
+ && single_one_operand (XEXP (x, 1), mode)
+ && (ASHIFT == GET_CODE (XEXP (x, 0))
+ || ASHIFTRT == GET_CODE (XEXP (x, 0))
+ || LSHIFTRT == GET_CODE (XEXP (x, 0))))
+ {
+ // "*insv.any_shift.<mode>
+ *total = COSTS_N_INSNS (1 + GET_MODE_SIZE (mode));
+ return true;
+ }
*total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
*total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, 0, speed);
if (!CONST_INT_P (XEXP (x, 1)))
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index fbae785..eadc482 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -154,7 +154,7 @@
;; Otherwise do special processing depending on the attribute.
(define_attr "adjust_len"
- "out_bitop, plus, addto_sp, sext,
+ "out_bitop, plus, addto_sp, sext, extr, extr_not,
tsthi, tstpsi, tstsi, compare, compare64, call,
mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32,
ufract, sfract, round,
@@ -284,12 +284,25 @@
(define_mode_iterator SPLIT34 [SI SF PSI
SQ USQ SA USA])
+;; Where the most significant bit is located.
+(define_mode_attr MSB [(QI "7") (QQ "7") (UQQ "7")
+ (HI "15") (HQ "15") (UHQ "15") (HA "15") (UHA "15")
+ (PSI "23")
+ (SI "31") (SQ "31") (USQ "31") (SA "31") (USA "31") (SF "31")])
+
+;; Size in bytes of the mode.
+(define_mode_attr SIZE [(QI "1") (QQ "1") (UQQ "1")
+ (HI "2") (HQ "2") (UHQ "2") (HA "2") (UHA "2")
+ (PSI "3")
+ (SI "4") (SQ "4") (USQ "4") (SA "4") (USA "4") (SF "4")])
+
;; Define code iterators
;; Define two incarnations so that we can build the cartesian product.
(define_code_iterator any_extend [sign_extend zero_extend])
(define_code_iterator any_extend2 [sign_extend zero_extend])
(define_code_iterator any_extract [sign_extract zero_extract])
(define_code_iterator any_shiftrt [lshiftrt ashiftrt])
+(define_code_iterator any_shift [lshiftrt ashiftrt ashift])
(define_code_iterator piaop [plus ior and])
(define_code_iterator bitop [xor ior and])
@@ -5715,9 +5728,9 @@
;; "*lshrqq3"
;; "*lshruqq3"
(define_insn_and_split "*lshr<mode>3_split"
- [(set (match_operand:ALL1 0 "register_operand" "=r,r,r,r,!d,r,r")
- (lshiftrt:ALL1 (match_operand:ALL1 1 "register_operand" "0,0,0,0,0 ,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,K,n ,n,Qm")))]
+ [(set (match_operand:ALL1 0 "register_operand" "=r,r,r,r,r ,!d,r,r")
+ (lshiftrt:ALL1 (match_operand:ALL1 1 "register_operand" "0,0,0,0,r ,0 ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,K,C07,n ,n,Qm")))]
""
"#"
"&& reload_completed"
@@ -5727,24 +5740,23 @@
(clobber (reg:CC REG_CC))])])
(define_insn "*lshr<mode>3"
- [(set (match_operand:ALL1 0 "register_operand" "=r,r,r,r,!d,r,r")
- (lshiftrt:ALL1 (match_operand:ALL1 1 "register_operand" "0,0,0,0,0 ,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,K,n ,n,Qm")))
+ [(set (match_operand:ALL1 0 "register_operand" "=r,r,r,r,r ,!d,r,r")
+ (lshiftrt:ALL1 (match_operand:ALL1 1 "register_operand" "0,0,0,0,r ,0 ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,K,C07,n ,n,Qm")))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return lshrqi3_out (insn, operands, NULL);
}
- [(set_attr "length" "5,0,1,2,4,6,9")
- (set_attr "adjust_len" "lshrqi")])
+ [(set_attr "adjust_len" "lshrqi")])
;; "lshrhi3"
;; "lshrhq3" "lshruhq3"
;; "lshrha3" "lshruha3"
(define_insn_and_split "lshr<mode>3"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r,r,r")
- (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r ,r,r,r")
+ (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r,r ,0,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,O,C15,K,n,Qm")))]
""
"#"
"&& reload_completed"
@@ -5754,22 +5766,21 @@
(clobber (reg:CC REG_CC))])])
(define_insn "*lshr<mode>3"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r,r,r")
- (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r ,r,r,r")
+ (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r,r ,0,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,O,C15,K,n,Qm")))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return lshrhi3_out (insn, operands, NULL);
}
- [(set_attr "length" "6,0,2,2,4,10,10")
- (set_attr "adjust_len" "lshrhi")])
+ [(set_attr "adjust_len" "lshrhi")])
(define_insn_and_split "lshrpsi3"
- [(set (match_operand:PSI 0 "register_operand" "=r,r,r,r,r")
- (lshiftrt:PSI (match_operand:PSI 1 "register_operand" "0,0,r,0,0")
- (match_operand:QI 2 "nonmemory_operand" "r,P,O,K,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))]
+ [(set (match_operand:PSI 0 "register_operand" "=r,r,r,r ,r,r")
+ (lshiftrt:PSI (match_operand:PSI 1 "register_operand" "0,0,r,r ,0,0")
+ (match_operand:QI 2 "nonmemory_operand" "r,P,O,C23,K,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X ,X,&d"))]
""
"#"
"&& reload_completed"
@@ -5780,10 +5791,10 @@
(clobber (reg:CC REG_CC))])])
(define_insn "*lshrpsi3"
- [(set (match_operand:PSI 0 "register_operand" "=r,r,r,r,r")
- (lshiftrt:PSI (match_operand:PSI 1 "register_operand" "0,0,r,0,0")
- (match_operand:QI 2 "nonmemory_operand" "r,P,O,K,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))
+ [(set (match_operand:PSI 0 "register_operand" "=r,r,r,r ,r,r")
+ (lshiftrt:PSI (match_operand:PSI 1 "register_operand" "0,0,r,r ,0,0")
+ (match_operand:QI 2 "nonmemory_operand" "r,P,O,C23,K,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X ,X,&d"))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
@@ -5795,9 +5806,9 @@
;; "lshrsq3" "lshrusq3"
;; "lshrsa3" "lshrusa3"
(define_insn_and_split "lshr<mode>3"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r,r,r,r")
- (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r,r,r ,r,r")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r,0,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,C31,n,Qm")))]
""
"#"
"&& reload_completed"
@@ -5807,16 +5818,15 @@
(clobber (reg:CC REG_CC))])])
(define_insn "*lshr<mode>3"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r,r,r,r")
- (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r,r,r ,r,r")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r,0,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,C31,n,Qm")))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return lshrsi3_out (insn, operands, NULL);
}
- [(set_attr "length" "8,0,4,4,8,10,12")
- (set_attr "adjust_len" "lshrsi")])
+ [(set_attr "adjust_len" "lshrsi")])
;; Optimize if a scratch register from LD_REGS happens to be available.
@@ -5875,7 +5885,7 @@
operands[2] = avr_to_int_mode (operands[0]);
})
-(define_peephole2
+(define_peephole2 ; "*lshrhi3_const"
[(match_scratch:QI 3 "d")
(parallel [(set (match_operand:ALL2 0 "register_operand" "")
(lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "")
@@ -5892,10 +5902,10 @@
;; "*lshrhq3_const" "*lshruhq3_const"
;; "*lshrha3_const" "*lshruha3_const"
(define_insn_and_split "*lshr<mode>3_const_split"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r")
- (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r,0,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,K,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))]
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r ,r,r")
+ (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r,r ,0,0")
+ (match_operand:QI 2 "const_int_operand" "L,P,O,C15,K,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X ,X,&d"))]
"reload_completed"
"#"
"&& reload_completed"
@@ -5906,19 +5916,18 @@
(clobber (reg:CC REG_CC))])])
(define_insn "*lshr<mode>3_const"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r")
- (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r,0,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,K,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r ,r,r")
+ (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r,r ,0,0")
+ (match_operand:QI 2 "const_int_operand" "L,P,O,C15,K,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X ,X,&d"))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return lshrhi3_out (insn, operands, NULL);
}
- [(set_attr "length" "0,2,2,4,10")
- (set_attr "adjust_len" "lshrhi")])
+ [(set_attr "adjust_len" "lshrhi")])
-(define_peephole2
+(define_peephole2 ; "*lshrsi3_const"
[(match_scratch:QI 3 "d")
(parallel [(set (match_operand:ALL4 0 "register_operand" "")
(lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "")
@@ -5935,10 +5944,10 @@
;; "*lshrsq3_const" "*lshrusq3_const"
;; "*lshrsa3_const" "*lshrusa3_const"
(define_insn_and_split "*lshr<mode>3_const_split"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r")
- (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,&d"))]
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r ,r")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,r ,0")
+ (match_operand:QI 2 "const_int_operand" "L,P,O,C31,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X ,&d"))]
"reload_completed"
"#"
"&& reload_completed"
@@ -5949,17 +5958,16 @@
(clobber (reg:CC REG_CC))])])
(define_insn "*lshr<mode>3_const"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r")
- (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,&d"))
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r ,r")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,r ,0")
+ (match_operand:QI 2 "const_int_operand" "L,P,O,C31,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X ,&d"))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return lshrsi3_out (insn, operands, NULL);
}
- [(set_attr "length" "0,4,4,10")
- (set_attr "adjust_len" "lshrsi")])
+ [(set_attr "adjust_len" "lshrsi")])
;; abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x)
;; abs
@@ -9672,17 +9680,17 @@
})
-(define_expand "extzv"
- [(set (match_operand:QI 0 "register_operand" "")
- (zero_extract:QI (match_operand:QI 1 "register_operand" "")
- (match_operand:QI 2 "const1_operand" "")
- (match_operand:QI 3 "const_0_to_7_operand" "")))])
+(define_expand "extzv<mode>"
+ [(set (match_operand:QI 0 "register_operand")
+ (zero_extract:QI (match_operand:QISI 1 "register_operand")
+ (match_operand:QI 2 "const1_operand")
+ (match_operand:QI 3 "const_0_to_<MSB>_operand")))])
-(define_insn_and_split "*extzv_split"
- [(set (match_operand:QI 0 "register_operand" "=*d,*d,*d,*d,r")
- (zero_extract:QI (match_operand:QI 1 "register_operand" "0,r,0,0,r")
+(define_insn_and_split "*extzv<mode>_split"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (zero_extract:QI (match_operand:QISI 1 "reg_or_low_io_operand" "r Yil")
(const_int 1)
- (match_operand:QI 2 "const_0_to_7_operand" "L,L,P,C04,n")))]
+ (match_operand:QI 2 "const_0_to_<MSB>_operand" "n")))]
""
"#"
"&& reload_completed"
@@ -9690,22 +9698,28 @@
(zero_extract:QI (match_dup 1)
(const_int 1)
(match_dup 2)))
- (clobber (reg:CC REG_CC))])])
+ (clobber (reg:CC REG_CC))])]
+ {
+ if (! MEM_P (operands[1]))
+ {
+ int bitno = INTVAL (operands[2]);
+ operands[1] = simplify_gen_subreg (QImode, operands[1], <MODE>mode, bitno / 8);
+ operands[2] = GEN_INT (bitno % 8);
+ }
+ })
-(define_insn "*extzv"
- [(set (match_operand:QI 0 "register_operand" "=*d,*d,*d,*d,r")
- (zero_extract:QI (match_operand:QI 1 "register_operand" "0,r,0,0,r")
+(define_insn "*extzv<mode>"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (zero_extract:QI (match_operand:QISI 1 "reg_or_low_io_operand" "r Yil")
(const_int 1)
- (match_operand:QI 2 "const_0_to_7_operand" "L,L,P,C04,n")))
+ (match_operand:QI 2 "const_0_to_<MSB>_operand" "n")))
(clobber (reg:CC REG_CC))]
"reload_completed"
- "@
- andi %0,1
- mov %0,%1\;andi %0,1
- lsr %0\;andi %0,1
- swap %0\;andi %0,1
- bst %1,%2\;clr %0\;bld %0,0"
- [(set_attr "length" "1,2,2,2,3")])
+ {
+ return avr_out_extr (insn, operands, nullptr);
+ }
+ [(set_attr "adjust_len" "extr")])
+
(define_insn_and_split "*extzv.qihi1"
[(set (match_operand:HI 0 "register_operand" "=r")
@@ -9726,16 +9740,197 @@
operands[4] = simplify_gen_subreg (QImode, operands[0], HImode, 1);
})
-(define_insn_and_split "*extzv.qihi2"
- [(set (match_operand:HI 0 "register_operand" "=r")
- (zero_extend:HI
- (zero_extract:QI (match_operand:QI 1 "register_operand" "r")
+(define_insn_and_split "*extzv.not_split"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (zero_extract:QI (not:QI (match_operand:QI 1 "reg_or_low_io_operand" "r Yil"))
+ (const_int 1)
+ (match_operand:QI 2 "const_0_to_7_operand" "n")))]
+ ""
+ "#"
+ "&& reload_completed"
+ [(parallel [(set (match_dup 0)
+ (zero_extract:QI (not:QI (match_dup 1))
+ (const_int 1)
+ (match_dup 2)))
+ (clobber (reg:CC REG_CC))])])
+
+(define_insn "*extzv.not"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (zero_extract:QI (not:QI (match_operand:QI 1 "reg_or_low_io_operand" "r Yil"))
+ (const_int 1)
+ (match_operand:QI 2 "const_0_to_7_operand" "n")))
+ (clobber (reg:CC REG_CC))]
+ "reload_completed"
+ {
+ return avr_out_extr_not (insn, operands, nullptr);
+ }
+ [(set_attr "adjust_len" "extr_not")])
+
+(define_insn_and_split "*extzv.subreg.<mode>"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (subreg:QI (zero_extract:HISI (match_operand:HISI 1 "register_operand" "r")
+ (const_int 1)
+ (match_operand:QI 2 "const_0_to_<MSB>_operand" "n"))
+ 0))]
+ "! reload_completed"
+ { gcc_unreachable(); }
+ "&& 1"
+ [; "*extzv<mode>_split"
+ (set (match_dup 0)
+ (zero_extract:QI (match_dup 1)
(const_int 1)
- (match_operand:QI 2 "const_0_to_7_operand" "n"))))]
+ (match_dup 2)))])
+
+;; Possible subreg bytes.
+(define_int_iterator SuReB [0 1 2 3])
+
+(define_insn_and_split "*extzv.<mode>.subreg<SuReB>"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (zero_extract:QI (subreg:QI
+ (and:HISI (match_operand:HISI 1 "register_operand" "r")
+ (match_operand:HISI 2 "single_one_operand" "n"))
+ SuReB)
+ (const_int 1)
+ (match_operand:QI 3 "const_0_to_7_operand" "n")))]
+ "! reload_completed
+ && IN_RANGE (UINTVAL(operands[2]) & GET_MODE_MASK(<MODE>mode),
+ 1U << (8 * <SuReB>), 0x80U << (8 * <SuReB>))
+ && exact_log2 (UINTVAL(operands[2]) & GET_MODE_MASK(<MODE>mode))
+ == 8 * <SuReB> + INTVAL (operands[3])"
+ { gcc_unreachable(); }
+ "&& 1"
+ [; "*extzv<mode>_split"
+ (set (match_dup 0)
+ (zero_extract:QI (match_dup 1)
+ (const_int 1)
+ (match_dup 4)))]
+ {
+ operands[4] = plus_constant (QImode, operands[3], 8 * <SuReB>);
+ })
+
+
+(define_insn_and_split "*extzv.xor"
+ [(set (match_operand:QI 0 "register_operand")
+ (zero_extract:QI (xor:QI (match_operand:QI 1 "reg_or_low_io_operand")
+ (match_operand:QI 2 "single_one_operand"))
+ (const_int 1)
+ (match_operand:QI 3 "const_0_to_7_operand")))]
+ "! reload_completed
+ && ((1 << INTVAL (operands[3])) & INTVAL (operands[2])) != 0"
+ { gcc_unreachable(); }
+ "&& 1"
+ [; "*extzv.not_split"
+ (set (match_dup 0)
+ (zero_extract:QI (not:QI (match_dup 1))
+ (const_int 1)
+ (match_dup 3)))])
+
+
+(define_insn_and_split "*extzv<mode>.ge"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (ge:QI (match_operand:QISI 1 "reg_or_low_io_operand" "r Yil")
+ (match_operand:QISI 2 "const0_operand" "Y00")))]
""
"#"
+ "reload_completed"
+ [; "*extzv.not"
+ (parallel [(set (match_dup 0)
+ (zero_extract:QI (not:QI (match_dup 1))
+ (const_int 1)
+ (const_int 7)))
+ (clobber (reg:CC REG_CC))])]
+ {
+ if (! MEM_P (operands[1]))
+ {
+ int msb = <SIZE> - 1;
+ operands[1] = simplify_gen_subreg (QImode, operands[1], <MODE>mode, msb);
+ }
+ })
+
+(define_insn_and_split "*neg.ashiftrt<mode>.msb"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (neg:QI (subreg:QI
+ (ashiftrt:QISI (match_operand:QISI 1 "register_operand" "r")
+ (match_operand:QI 2 "const<MSB>_operand" "n"))
+ 0)))]
+ "! reload_completed"
+ { gcc_unreachable(); }
+ "&& 1"
+ [; "*extzv<mode>_split"
+ (set (match_dup 0)
+ (zero_extract:QI (match_dup 1)
+ (const_int 1)
+ (match_dup 2)))])
+
+(define_insn_and_split "*extzv.io.lsr7"
+ [(set (match_operand:QI 0 "register_operand")
+ (lshiftrt:QI (match_operand:QI 1 "reg_or_low_io_operand")
+ (const_int 7)))]
+ "! reload_completed"
+ { gcc_unreachable(); }
+ "&& 1"
+ [; "*extzv_split"
+ (set (match_dup 0)
+ (zero_extract:QI (match_dup 1)
+ (const_int 1)
+ (const_int 7)))])
+
+(define_insn_and_split "*insv.any_shift.<mode>_split"
+ [(set (match_operand:QISI 0 "register_operand" "=r")
+ (and:QISI (any_shift:QISI (match_operand:QISI 1 "register_operand" "r")
+ (match_operand:QI 2 "const_0_to_<MSB>_operand" "n"))
+ (match_operand:QISI 3 "single_one_operand" "n")))]
""
- [(set (match_dup 3)
+ "#"
+ "&& reload_completed"
+ [(parallel [(set (match_dup 0)
+ (and:QISI (any_shift:QISI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))
+ (clobber (reg:CC REG_CC))])])
+
+(define_insn "*insv.any_shift.<mode>"
+ [(set (match_operand:QISI 0 "register_operand" "=r")
+ (and:QISI (any_shift:QISI (match_operand:QISI 1 "register_operand" "r")
+ (match_operand:QI 2 "const_0_to_<MSB>_operand" "n"))
+ (match_operand:QISI 3 "single_one_operand" "n")))
+ (clobber (reg:CC REG_CC))]
+ "reload_completed"
+ {
+ int shift = <CODE> == ASHIFT ? INTVAL (operands[2]) : -INTVAL (operands[2]);
+ int mask = GET_MODE_MASK (<MODE>mode) & INTVAL (operands[3]);
+ // Position of the output / input bit, respectively.
+ int obit = exact_log2 (mask);
+ int ibit = obit - shift;
+ gcc_assert (IN_RANGE (obit, 0, <MSB>));
+ gcc_assert (IN_RANGE (ibit, 0, <MSB>));
+ operands[3] = GEN_INT (obit);
+ operands[2] = GEN_INT (ibit);
+
+ if (<SIZE> == 1) return "bst %T1%T2\;clr %0\;" "bld %T0%T3";
+ if (<SIZE> == 2) return "bst %T1%T2\;clr %A0\;clr %B0\;" "bld %T0%T3";
+ if (<SIZE> == 3) return "bst %T1%T2\;clr %A0\;clr %B0\;clr %C0\;bld %T0%T3";
+ return AVR_HAVE_MOVW
+ ? "bst %T1%T2\;clr %A0\;clr %B0\;movw %C0,%A0\;" "bld %T0%T3"
+ : "bst %T1%T2\;clr %A0\;clr %B0\;clr %C0\;clr %D0\;bld %T0%T3";
+ }
+ [(set (attr "length")
+ (minus (symbol_ref "2 + <SIZE>")
+ ; One less if we can use a MOVW to clear.
+ (symbol_ref "<SIZE> == 4 && AVR_HAVE_MOVW")))])
+
+
+(define_insn_and_split "*extzv.<mode>hi2"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (zero_extend:HI
+ (zero_extract:QI (match_operand:QISI 1 "register_operand" "r")
+ (const_int 1)
+ (match_operand:QI 2 "const_0_to_<MSB>_operand" "n"))))]
+ "! reload_completed"
+ { gcc_unreachable(); }
+ "&& 1"
+ [; "*extzv<mode>_split"
+ (set (match_dup 3)
(zero_extract:QI (match_dup 1)
(const_int 1)
(match_dup 2)))
@@ -9749,24 +9944,20 @@
;; ??? do_store_flag emits a hard-coded right shift to extract a bit without
;; even considering rtx_costs, extzv, or a bit-test. See PR 55181 for an example.
(define_insn_and_split "*extract.subreg.bit"
- [(set (match_operand:QI 0 "register_operand" "=r")
- (and:QI (subreg:QI (any_shiftrt:HISI (match_operand:HISI 1 "register_operand" "r")
- (match_operand:QI 2 "const_int_operand" "n"))
- 0)
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (and:QI (subreg:QI
+ (any_shiftrt:HISI (match_operand:HISI 1 "register_operand" "r")
+ (match_operand:QI 2 "const_0_to_<MSB>_operand" "n"))
+ 0)
(const_int 1)))]
- "INTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode)"
+ "! reload_completed"
{ gcc_unreachable(); }
- "&& reload_completed"
- [;; "*extzv"
+ "&& 1"
+ [;; "*extzv<mode>_split"
(set (match_dup 0)
- (zero_extract:QI (match_dup 3)
+ (zero_extract:QI (match_dup 1)
(const_int 1)
- (match_dup 4)))]
- {
- int bitno = INTVAL (operands[2]);
- operands[3] = simplify_gen_subreg (QImode, operands[1], <MODE>mode, bitno / 8);
- operands[4] = GEN_INT (bitno % 8);
- })
+ (match_dup 2)))])
;; Fixed-point instructions
diff --git a/gcc/config/avr/constraints.md b/gcc/config/avr/constraints.md
index f840c01..8f97a48 100644
--- a/gcc/config/avr/constraints.md
+++ b/gcc/config/avr/constraints.md
@@ -133,6 +133,21 @@
(and (match_code "const_int")
(match_test "ival == 7")))
+(define_constraint "C15"
+ "Constant integer 15."
+ (and (match_code "const_int")
+ (match_test "ival == 15")))
+
+(define_constraint "C23"
+ "Constant integer 23."
+ (and (match_code "const_int")
+ (match_test "ival == 23")))
+
+(define_constraint "C31"
+ "Constant integer 31."
+ (and (match_code "const_int")
+ (match_test "ival == 31")))
+
(define_constraint "Ca1"
"Constant 1-byte integer that allows AND by means of CLT + BLD."
(and (match_code "const_int")
@@ -262,3 +277,8 @@
"Fixed-point constant from @minus{}0x003f to 0x003f."
(and (match_code "const_fixed")
(match_test "IN_RANGE (INTVAL (avr_to_int_mode (op)), -63, 63)")))
+
+(define_constraint "Yil"
+ "Memory in the lower half of the I/O space."
+ (and (match_code "mem")
+ (match_test "low_io_address_operand (XEXP (op, 0), Pmode)")))
diff --git a/gcc/config/avr/predicates.md b/gcc/config/avr/predicates.md
index f4ee42a..c279e17 100644
--- a/gcc/config/avr/predicates.md
+++ b/gcc/config/avr/predicates.md
@@ -55,6 +55,16 @@
(and (match_code "symbol_ref")
(match_test "SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_IO_LOW"))))
+;; Return true if OP is a register_operand or low_io_operand.
+(define_predicate "reg_or_low_io_operand"
+ (ior (match_operand 0 "register_operand")
+ (and (match_code "mem")
+ ; Deliberately only allow QImode no matter what the mode of
+ ; the operand is. This effectively disallows and I/O that
+ ; is not QImode for that operand.
+ (match_test "GET_MODE (op) == QImode")
+ (match_test "low_io_address_operand (XEXP (op, 0), Pmode)"))))
+
;; Return true if OP is a valid address for high half of I/O space.
(define_predicate "high_io_address_operand"
(and (match_code "const_int")
@@ -91,12 +101,47 @@
(and (match_code "const_int")
(match_test "op == CONST1_RTX (mode)")))
+;; Return 1 if OP is the constant integer 7 for MODE.
+(define_predicate "const7_operand"
+ (and (match_code "const_int")
+ (match_test "INTVAL(op) == 7")))
+
+;; Return 1 if OP is the constant integer 15 for MODE.
+(define_predicate "const15_operand"
+ (and (match_code "const_int")
+ (match_test "INTVAL(op) == 15")))
+
+;; Return 1 if OP is the constant integer 23 for MODE.
+(define_predicate "const23_operand"
+ (and (match_code "const_int")
+ (match_test "INTVAL(op) == 23")))
+
+;; Return 1 if OP is the constant integer 31 for MODE.
+(define_predicate "const31_operand"
+ (and (match_code "const_int")
+ (match_test "INTVAL(op) == 31")))
+
;; Return 1 if OP is constant integer 0..7 for MODE.
(define_predicate "const_0_to_7_operand"
(and (match_code "const_int")
(match_test "IN_RANGE (INTVAL (op), 0, 7)")))
+;; Return 1 if OP is constant integer 0..15 for MODE.
+(define_predicate "const_0_to_15_operand"
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (INTVAL (op), 0, 15)")))
+
+;; Return 1 if OP is constant integer 0..23 for MODE.
+(define_predicate "const_0_to_23_operand"
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (INTVAL (op), 0, 23)")))
+
+;; Return 1 if OP is constant integer 0..31 for MODE.
+(define_predicate "const_0_to_31_operand"
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (INTVAL (op), 0, 31)")))
+
;; Return 1 if OP is constant integer 2..7 for MODE.
(define_predicate "const_2_to_7_operand"
(and (match_code "const_int")