amdgcn: fix ICE on subreg of BI reg.
authorAndrew Stubbs <ams@codesourcery.com>
Wed, 26 Feb 2020 16:45:29 +0000 (16:45 +0000)
committerAndrew Stubbs <ams@codesourcery.com>
Thu, 27 Feb 2020 12:03:10 +0000 (12:03 +0000)
BImode usually only requires one bit, but instructions that write to VCC also
clobber the reset of the DImode register pair, so gcn_class_max_nregs reports
that two registers are needed for BImode.  Paradoxically, accessing VCC via
SImode is therefore uses fewer registers than accessing via BImode.

The LRA checking code takes this into account, but the DF liveness data also
looks at the subreg, so it says (subreg:SI (reg:BI VCC) 0) only makes the low
part live.  Both are "correct", but they disagree, which causes an ICE.

This doesn't happen when writing conditions to VCC; it happens when accessing
VCC_LO via a regular move to a regular SImode register.

If we transform the subregs so that BImode is always the outer mode then it
basically means the same thing, except that now both LRA and DF calculate nregs
the same, and ICE goes away.

As soon as LRA is done the subregs all evaporate anyway.

2020-02-27  Andrew Stubbs  <ams@codesourcery.com>

gcc/
* config/gcn/gcn.md (mov<mode>): Add transformations for BI subregs.

gcc/ChangeLog
gcc/config/gcn/gcn.md

index beb56bc0130d3aa17d6c5704d055695e03b78aea..b17d255ac8a1389f0906c87b5c6af46a6f42fa32 100644 (file)
@@ -1,3 +1,7 @@
+2020-02-27  Andrew Stubbs  <ams@codesourcery.com>
+
+       * config/gcn/gcn.md (mov<mode>): Add transformations for BI subregs.
+
 2020-02-27  Mark Williams  <mwilliams@fb.com>
 
        * dwarf2out.c (file_name_acquire): Call remap_debug_filename.
index b527d9a7a8bd626da6178eefb435e357c5e814dc..d8b49dfd640e66d67d2956fe7dab9040492397ec 100644 (file)
        (match_operand:MOV_MODE 1 "general_operand"))]
   ""
   {
+    if (SUBREG_P (operands[1])
+       && GET_MODE (operands[1]) == SImode
+       && GET_MODE (SUBREG_REG (operands[1])) == BImode)
+    {
+      /* (reg:BI VCC) has nregs==2 to ensure it gets clobbered as a whole,
+        but (subreg:SI (reg:BI VCC)) doesn't, which causes the LRA liveness
+        checks to assert.  Transform this:
+          (set (reg:SI) (subreg:SI (reg:BI)))
+        to this:
+          (set (subreg:BI (reg:SI)) (reg:BI))  */
+      operands[0] = gen_rtx_SUBREG (BImode, operands[0], 0);
+      operands[1] = SUBREG_REG (operands[1]);
+    }
+    if (SUBREG_P (operands[0])
+       && GET_MODE (operands[0]) == SImode
+       && GET_MODE (SUBREG_REG (operands[0])) == BImode)
+      {
+       /* Likewise, transform this:
+            (set (subreg:SI (reg:BI)) (reg:SI))
+          to this:
+            (set (reg:BI) (subreg:BI (reg:SI))) */
+       operands[0] = SUBREG_REG (operands[0]);
+       operands[1] = gen_rtx_SUBREG (BImode, operands[1], 0);
+      }
+
     if (MEM_P (operands[0]))
       operands[1] = force_reg (<MODE>mode, operands[1]);