<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/128843>128843</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            GlobalISel inserts illegal COPY operation
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            backend:AArch64,
            llvm:globalisel
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          sdesmalen-arm
      </td>
    </tr>
</table>

<pre>
    ### Reproducer:
```
; compile with `llc -mattr=+fullfp16 -O0`

define i32 @reproducer() {
  %retval = call i32 @llvm.aarch64.neon.fcvtzs.i32.f16(half 0xH4566)
  ret i32 %retval
}
```

This runs into a llvm_unreachable:

```
H0 = COPY W0
unimplemented reg-to-reg copy

UNREACHABLE executed at llvm/lib/Target/AArch64/AArch64InstrInfo.cpp:5250
```

This issue may be related to #79822.

### My Analysis:

GlobalISel seems to assume that everything goes by default into a GPR, because after RegBankSelect the IR looks like this:
```
bb.1 (%ir-block.0):
  %1:fpr(s16) = G_FCONSTANT half 0xH4566
  %2:gpr(s16) = COPY %1:fpr(s16)
  %0:gpr(s32) = G_INTRINSIC intrinsic(@llvm.aarch64.neon.fcvtzs), %2:gpr(s16)
```

(1) During the 'instruction selection' step for `G_INTRINSIC` it inserts a COPY to move `%2` from a GPR -> FPR. This results in:
```
bb.1 (%ir-block.0):
  %1:fpr(s16) = G_FCONSTANT half 0xH4566
  %2:gpr(s16) = COPY %1:fpr(s16)      
 %3:fpr(s16) = COPY %2:gpr(s16)      // COPY inserted by lowering of G_INTRINSIC
  %0:gpr(s32) = FCVTZSUWHr %3
```

(2) During the 'instruction selection' step for `%2:gpr(s16) = COPY %1:fpr(s16)` it:
* Legalises the operation, e.g. if the size doesn't match, it either copies the sub-register or it inserts it into a larger register using SUBREG_TO_REG.
* Legalises the type (selects the appropriate register class for the result)

After this, the IR looks like:
```
  %6:fpr(s16) = G_FCONSTANT half 0xH4566
  %4:fpr32 = SUBREG_TO_REG 0, %6:fpr16, %subreg.hsub
 %2:gpr32all = COPY %4:fpr32         // type is promoted, and SUBREG_TO_REG is inserted
  %3:fpr16 = COPY %2:gpr32all
  %0:gpr32 = FCVTZSUWHr %3:fpr16
```

Because the GlobalISel instruction selector has explicit code not to revisit the `%3:fpr16 = COPY %2:gpr32all`, the COPY remains in place.
```
// Snippet from InstructionSelect::selectMachineFunction

for (auto End = MBB->rend(); MIIMaintainer.MII != End;) {
  MachineInstr &MI = *MIIMaintainer.MII;
  // Increment early to skip instructions inserted by select().
  ++MIIMaintainer.MII;
```

I think this COPY should instead have been turned into an FMOV by SelectionDAG, rather than leaving it a COPY and hoping the target will implement it. My understanding is that `copyPhysReg` should only implement copies where the sizes match.

I don't understand GlobalISel enough to make a judgement call on how to fix this though, @aemerson any ideas?
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzMV01z4zgO_TX0BRWVTFm2c_BBduK0qyZJl5Oeqd1LFyVBEicUqSIpJ55fv0VSsp2P3tqd07h86LYE4AF4eECYMbyWiCuSrkl6M2G9bZRemRJNywTKK6bbSa7K44rQJHxhj51WZV-gJklG4ozM4-EbZyRZQ6HajguEV24bIPNYiAKuWmatJskNoeuqF6LqpnO4ehyt4qzEiksEnlAgs1ifQ9AloddAFmsSZwCEphrtgQkgyQ0UTIjRRIhDGzGmi2Y-iyQqGVXFwf5lIp7QqJrOCV02TFQQv32bpfM5odfeoUYbPIyOHZzFzce04uy54QZ0Lw1waRUwcAF_9lIjKxqWCxyK8d7wW-yBbh6__wv-cD_0kredwBalxRI01ldWXWmsoVDdMdj_eNjfZptv2fq3W8A3LHr3JrM-IKFbwXNCt89M12gJ3WaZT_n8r500Vu9kpaKi60iSpTSNf5EON6ZHaNkRcgSNgrlIVgGhyeJ6SWk0JHRq_f0RMsnE0XBzSvdOqJyJ3RMKMIitcQ6YMX2LYBtmAQ-oj7bhsoZaoYH8CCVWrBd2rOTd9z2hG8ixYL1BYJVFDXus10y-PKHAwoJtEHZ7EEq9GBD8xfk-YbjILM-jKXjOpFxf5UIVL1Hseu3f9PyZkiSrOkcs41hx7Rt093O7eXx4es4enuEdTQYjSpKs_mjku_qFx9EoPhsl9Bxp9_C83z087TYuf82l4YVD_GsKO5d08xWMz30ldDl1oW567Sru6kbogjtO9IXlSoLxFeVKEroAY7GDSmk3pxfIyDwG7vpjUFsDLKRqFbTqgO5dj2UeQ6VVGzoIVyS5he33fQRhVND0wrpp-Yd2CfzHmRKaJl-FGy0_uQ2WdEvoNrwUCoWlI7dQr-hrr6rLZv9XUmw3vz__--nHH990APNVW-nfbOv_zV7f-6FpNIPfsGaCGzQ-qupQsxBmAxjVEfDKPzD8L4RSoXEALLTMFo17h1tAbhvUTuH44MX0uRM9btykK33JNX6SBeEkTsPpvd641J9-rPe3dz-fH3_ub--iLzHaY-fKswwlCb-xrtOq05xZPHssBDPG18m9Ehg7TFWcZV6GvMzQzWcB-sxq39753-HtLBi5NZTcvM8Q4mH0B8fOqf-_6XONddSYPh84PHQ5oW4rXnb47H78DNz1heIGOq1aZbF0rpksPyBwi2Lg9wg4GcF8NScewAe6D6l95PmY0ie-r4dd4Mp-sWA-E15paJgBfOsEL7iFQpUIUlknVhoP3PCwPMIg_A-45_HYbv9YY8u4X_rQCVZg9BFrqOST5F2HNujh7owyrC_HlSQLgO9Z0XCJ216GafXp-lGlS9ZbBbey9Oju12snqRplGY4gd1vd73b3jEvLuEQd3e92QOjUvX0rS5KsL0-lIZAHA4TO73feLaHZJyfOMvTLJ7OThfYXCiDT4uhKaV54d1l9807yQmYBZTR4WhO6_kWgD73euSGTL37UQtFNo3pR-njISmjYASFHlGB7LbEcBELC9v7xdxf_adS-m-zOdU8zLzi2YRIEsoPTDW7HNeYY3qhu1FHrLyl45e6WHG8z4DZy104vS9TGMll6HyacNGQeu3Pte3M0e6ydYA6IlRTHCyeD4r02qPEkkiZoYzQmX6qgmOdQl4xHqfq68auXvSAw-LMv68G7m3MloVGv7nnF30IJbeNMvEzMYoYtaqMkMHkEXiIzJNlOylVSXifXbIKr6WIWp-lyMU8mzSrGdDkt6aJgNMkrxOlyzqZpOaMlncbTIp3wFY1pGlM6j5cJnSXR9RLZbFGw6TKdpgmdkVnsJkZE_phRup74I3M1pcvlLJkIlqMw_q8NSnNWvDh2J9npiKWEbgil_tRNstrXgRsU7kl6M9Er9-Qq72vj7iVurDkHstwKXL1Xi7BShHD7IXT_tMAmvRarxtrOn5Ge-TW3TZ9HhfJ39nBuu4CdVn96hm99NobQ7ZDQYUX_EwAA__93wvx-">