diff --git gcc/config/cris/cris.md gcc/config/cris/cris.md
index 95eddab..308a2eb 100644
--- gcc/config/cris/cris.md
+++ gcc/config/cris/cris.md
@@ -3031,36 +3031,51 @@
 
 ;; A strict_low_part pattern.
 
+;; Note the use of (match_dup 0) for the first operand of the operation
+;; here.  Reload can't handle an operand pair where one is read-write
+;; and must match a read, like in:
+;; (insn 80 79 81 4
+;;  (set (strict_low_part
+;;        (subreg:QI (reg/v:SI 0 r0 [orig:36 data ] [36]) 0))
+;;       (and:QI
+;;        (subreg:QI (reg:SI 15 acr [orig:27 D.7531 ] [27]) 0)
+;;        (const_int -64 [0xf..fc0]))) x.c:126 147 {*andqi_lowpart_v32}
+;;  (nil))
+;; In theory, it could reload this as a movstrictqi of the register
+;; operand at the and:QI to the destination register and change the
+;; and:QI operand to the same as the read-write output operand and the
+;; result would be recognized, but it doesn't recognize that's a valid
+;; reload for a strict_low_part-destination; it just sees a "+" at the
+;; destination constraints.  Better than adding complexity to reload is
+;; to follow the lead of m68k (see comment that begins with "These insns
+;; must use MATCH_DUP") since prehistoric times and make it just a
+;; match_dup.  FIXME: a sanity-check in gen* to refuse an insn with
+;; input-constraints matching input-output-constraints, e.g. "+r" <- "0".
+
 (define_insn "*andhi_lowpart_non_v32"
   [(set (strict_low_part
-	 (match_operand:HI 0 "register_operand"	       "+r,r, r,r,r,r"))
-	(and:HI (match_operand:HI 1 "register_operand" "%0,0, 0,0,0,r")
-		(match_operand:HI 2 "general_operand"   "r,Q>,L,O,g,!To")))]
+	 (match_operand:HI 0 "register_operand"	       "+r,r,r"))
+	(and:HI (match_dup 0)
+		(match_operand:HI 1 "general_operand"   "r,Q>,g")))]
   "!TARGET_V32"
   "@
-   and.w %2,%0
-   and.w %2,%0
-   and.w %2,%0
-   anDq %b2,%0
-   and.w %2,%0
-   and.w %2,%1,%0"
-  [(set_attr "slottable" "yes,yes,no,yes,no,no")
-   (set_attr "cc" "normal,normal,normal,clobber,normal,normal")])
+   and.w %1,%0
+   and.w %1,%0
+   and.w %1,%0"
+  [(set_attr "slottable" "yes,yes,no")])
 
 (define_insn "*andhi_lowpart_v32"
   [(set (strict_low_part
-	 (match_operand:HI 0 "register_operand" "+r,r,r,r,r"))
-	(and:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0")
-		(match_operand:HI 2 "general_operand" "r,Q>,L,O,g")))]
+	 (match_operand:HI 0 "register_operand" "+r,r,r"))
+	(and:HI (match_dup 0)
+		(match_operand:HI 1 "general_operand" "r,Q>,g")))]
   "TARGET_V32"
   "@
-   and.w %2,%0
-   and.w %2,%0
-   and.w %2,%0
-   anDq %b2,%0
-   and.w %2,%0"
-  [(set_attr "slottable" "yes,yes,no,yes,no")
-   (set_attr "cc" "noov32,noov32,noov32,clobber,noov32")])
+   and.w %1,%0
+   and.w %1,%0
+   and.w %1,%0"
+  [(set_attr "slottable" "yes,yes,no")
+   (set_attr "cc" "noov32")])
 
 (define_expand "andqi3"
   [(set (match_operand:QI 0 "register_operand")
@@ -3100,32 +3115,28 @@
 
 (define_insn "*andqi_lowpart_non_v32"
   [(set (strict_low_part
-	 (match_operand:QI 0 "register_operand"	       "+r,r, r,r,r"))
-	(and:QI (match_operand:QI 1 "register_operand" "%0,0, 0,0,r")
-		(match_operand:QI 2 "general_operand"   "r,Q>,O,g,!To")))]
+	 (match_operand:QI 0 "register_operand"	       "+r,r,r"))
+	(and:QI (match_dup 0)
+		(match_operand:QI 1 "general_operand"   "r,Q>,g")))]
   "!TARGET_V32"
   "@
-   and.b %2,%0
-   and.b %2,%0
-   andQ %b2,%0
-   and.b %2,%0
-   and.b %2,%1,%0"
-  [(set_attr "slottable" "yes,yes,yes,no,no")
-   (set_attr "cc" "normal,normal,clobber,normal,normal")])
+   and.b %1,%0
+   and.b %1,%0
+   and.b %1,%0"
+  [(set_attr "slottable" "yes,yes,no")])
 
 (define_insn "*andqi_lowpart_v32"
   [(set (strict_low_part
-	 (match_operand:QI 0 "register_operand" "+r,r,r,r"))
-	(and:QI (match_operand:QI 1 "register_operand" "%0,0,0,0")
-		(match_operand:QI 2 "general_operand" "r,Q>,O,g")))]
+	 (match_operand:QI 0 "register_operand" "+r,r,r"))
+	(and:QI (match_dup 0)
+		(match_operand:QI 1 "general_operand" "r,Q>,g")))]
   "TARGET_V32"
   "@
-   and.b %2,%0
-   and.b %2,%0
-   andQ %b2,%0
-   and.b %2,%0"
-  [(set_attr "slottable" "yes,yes,yes,no")
-   (set_attr "cc" "noov32,noov32,clobber,noov32")])
+   and.b %1,%0
+   and.b %1,%0
+   and.b %1,%0"
+  [(set_attr "slottable" "yes,yes,no")
+   (set_attr "cc" "noov32")])
 
 ;; Bitwise or.
 
Index: gcc/testsuite/gcc.dg/torture/pr53120.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/pr53120.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/pr53120.c	(revision 0)
@@ -0,0 +1,110 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-tree-sra" } */
+typedef struct {
+  unsigned int en : 1;
+  unsigned int bit_order : 1;
+  unsigned int scl_io : 1;
+  unsigned int scl_inv : 1;
+  unsigned int sda0_io : 1;
+  unsigned int sda0_idle : 1;
+  unsigned int sda1_io : 1;
+  unsigned int sda1_idle : 1;
+  unsigned int sda2_io : 1;
+  unsigned int sda2_idle : 1;
+  unsigned int sda3_io : 1;
+  unsigned int sda3_idle : 1;
+  unsigned int sda_sel : 2;
+  unsigned int sen_idle : 1;
+  unsigned int sen_inv : 1;
+  unsigned int sen_sel : 2;
+  unsigned int dummy1 : 14;
+} reg_gio_rw_i2c1_cfg;
+
+typedef struct {
+  unsigned int data0 : 8;
+  unsigned int data1 : 8;
+  unsigned int data2 : 8;
+  unsigned int data3 : 8;
+} reg_gio_rw_i2c1_data;
+
+typedef struct {
+  unsigned int trf_bits : 6;
+  unsigned int switch_dir : 6;
+  unsigned int extra_start : 3;
+  unsigned int early_end : 1;
+  unsigned int start_stop : 1;
+  unsigned int ack_dir0 : 1;
+  unsigned int ack_dir1 : 1;
+  unsigned int ack_dir2 : 1;
+  unsigned int ack_dir3 : 1;
+  unsigned int ack_dir4 : 1;
+  unsigned int ack_dir5 : 1;
+  unsigned int ack_bit : 1;
+  unsigned int start_bit : 1;
+  unsigned int freq : 2;
+  unsigned int dummy1 : 5;
+} reg_gio_rw_i2c1_ctrl;
+
+extern reg_gio_rw_i2c1_cfg reg_gio;
+extern reg_gio_rw_i2c1_data reg_data;
+extern int reg_start;
+extern reg_gio_rw_i2c1_ctrl reg_ctrl;
+
+extern void foobar(void);
+extern void foo(int);
+extern void frob(unsigned int);
+extern void bar(int);
+extern void baz(void);
+
+unsigned int f(int *devspec, unsigned int addr)
+{
+ reg_gio_rw_i2c1_ctrl ctrl = {0};
+ reg_gio_rw_i2c1_data data = {0};
+
+ foobar();
+
+ static int first = 1;
+
+ if (first) {
+  reg_gio_rw_i2c1_cfg cfg = {0};
+  first = 0;
+
+  foo(1);
+  cfg.sda0_idle = 1;
+  cfg.sda0_io = 0;
+  cfg.scl_inv = 0;
+  cfg.scl_io = 0;
+  cfg.bit_order = 1;
+  cfg.sda_sel = 0;
+  cfg.sen_sel = 0;
+  cfg.en = 1;
+  reg_gio = cfg;
+ }
+
+ ctrl.freq = 1;
+ ctrl.start_bit = 0;
+ ctrl.ack_bit = 1;
+ ctrl.ack_dir0 = 0;
+ ctrl.ack_dir1 = 0;
+ ctrl.ack_dir2 = 0;
+ ctrl.ack_dir3 = 1;
+ ctrl.ack_dir4 = 0;
+ ctrl.ack_dir5 = 0;
+ ctrl.start_stop = 1;
+ ctrl.early_end = 0;
+ ctrl.extra_start = 2;
+ ctrl.switch_dir = 8*3;
+ ctrl.trf_bits = 8*4;
+ reg_ctrl = ctrl;
+ frob(0xac);
+ data.data0 = devspec[1] & 192;
+ data.data1 = addr;
+ data.data2 = devspec[1] | 0x01;
+ reg_data = data;
+ reg_start = 1;
+ bar(100);
+ data = reg_data;
+ baz();
+
+ return data.data3;
+}
