<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/82030>82030</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[AMDGPU] LiveVariables incorrectly marks `$vcc_lo` dead
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
dmpots
</td>
</tr>
</table>
<pre>
I am running into a miscompile when compiling for wave32. The compiler is generating a S_CBRANCH_VCCZ instruction but deleting the def of `$vcc_lo` that controls the branch.
I was able to track down the problem to the LiveVariables pass. It marks the def of `$vcc_lo` dead and then the "Post-RA pseudo instruction expansion pass" converts that copy to a kill (which produces no output in the final codegen).
I am able to reproduce the issue with a simple example below.
## Repro
```
# llc %s -o - -mtriple=amdgcn -mcpu=gfx1010 -mattr="+wavefrontsize32,-wavefrontsize64" -verify-machineinstrs -run-pass=livevars
---
name: test
tracksRegLiveness: true
body: |
bb.0:
liveins: $sgpr1
%0:sreg_32 = S_AND_B32 $sgpr1, $sgpr1, implicit-def $scc
$vcc_lo = COPY %0:sreg_32
S_CBRANCH_VCCNZ %bb.1, implicit $vcc
bb.1:
S_ENDPGM 0
...
```
Running this MIR file through llc results in the COPY instruction being marked dead.
`dead $vcc_lo = COPY killed %0`
## Details
This looks to be a problem with how we mark `$VCC` and `$VCC_HI` as reserved registers when compiling for wave32. For wave32 the explicit `$vcc` uses are converted to `$vcc_lo`, but the implicit uses are left as `$vcc`. So we have an explicit def of `$vcc_lo` in a copy instruction, and an implicit use of `$vcc` on the `S_CBRANCH_VCCNZ` instruction.
The live variables pass skips reserved registers when processing an instruction uses (and defs)
```
// Process all uses.
for (unsigned MOReg : UseRegs) {
if (Register::isVirtualRegister(MOReg))
HandleVirtRegUse(MOReg, MBB, MI);
else if (!MRI->isReserved(MOReg))
HandlePhysRegUse(MOReg, MI);
}
```
https://github.com/llvm/llvm-project/blob/a4ce870859a2d8b5ce8b92732594089e2a81b4fb/llvm/lib/CodeGen/LiveVariables.cpp#L526
This means it thinks the `$vcc_lo` def has no uses and therefore can mark it as dead.
## Possible Fixes
I can think of a few different ways to solve this problem.
### Do not reserve VCC and VCC_HI in wave32
It looks like vcc_hi and vcc were only reserved to avoid possible bugs. I tried un-reserving them and inspecting codegen diffs. I did not see anything too troubling. It was allocating vcc_hi in the shaders now, but I think that should be ok.
```
// Disallow vcc_hi allocation in wave32. It may be allocated but most likely
// will result in bugs.
if (isWave32) {
Reserved.set(AMDGPU::VCC);
Reserved.set(AMDGPU::VCC_HI);
}
```
https://github.com/llvm/llvm-project/blob/2d9f3504491156282a3c785a562fcc0ba3c16161/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp#L614C1-L619C4
I was wary of this solution because of the unknown risk and the details about why it was reserved in the first place.
### Add VCC_LO and VCC_HI as implicit uses to branch instructions
We currently only add VCC as an implicit use to these branch instructions. We could add the VCC_LO and VCC_HI to the implicit uses as well. Or perhaps have different branch instructions for wave32 (similar to how we do for the `savexec` terminators).
```
let Uses = [VCC] in {
defm S_CBRANCH_VCCZ : SOPP_With_Relaxation <
"s_cbranch_vccz" , (ins SOPPBrTarget:$simm16),
"$simm16"
>;
defm S_CBRANCH_VCCNZ : SOPP_With_Relaxation <
"s_cbranch_vccnz" , (ins SOPPBrTarget:$simm16),
"$simm16"
>;
} // End Uses = [VCC]
```
https://github.com/llvm/llvm-project/blob/cc673867d97aeb1151da5f7f0dc59d47eb384b45/llvm/lib/Target/AMDGPU/SOPInstructions.td#L1509C1-L1518C22
Making this change caused a lot of test failures for invalid MIR, but seemed pretty mechanical to fix it up.
### Make LiveVariables handle reserved register with unreserved subregister
We could add code to process reserved registers by looking for unreserved subregisters.
```
+/// Process a use of a reserved physical register.
+void LiveVariables::HandleReservedPhysRegUse(unsigned Reg, MachineInstr &MI)
+{
+ assert(MRI->isReserved(Reg) && TRI->isPhysicalRegister(Reg));
+ for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/false);
+ SubRegs.isValid(); ++SubRegs) {
+ unsigned SubReg = *SubRegs;
+ if (!MRI->isReserved(SubReg))
+ HandlePhysRegUse(SubReg, MI);
+ }
+}
```
And then update live variables to explicitly do more work for reserved registers.
```
void LiveVariables::runOnInstr(MachineInstr &MI,
SmallVectorImpl<unsigned> &Defs) {
assert(!MI.isDebugInstr());
@@ -545,6 +603,8 @@ void LiveVariables::runOnInstr(MachineInstr &MI,
HandleVirtRegUse(MOReg, MBB, MI);
else if (!MRI->isReserved(MOReg))
HandlePhysRegUse(MOReg, MI);
+ else
+ HandleReservedPhysRegUse(MOReg, MI);
}
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy0WF9v4zgO_zTuC5HAlvP3oQ9tMt0NMJ0W6WwXty-FbNOxrrJkSHLS7Kc_ULLTJE2LvdvbwaBJLIqkKP5-JM2tFRuFeB2Nb6Px8oq3rtLmuqgb7exVpov99Qp4DaZVSqgNCOU0cKiFzXXdCImwq1BB-EECpTaw41tM2RB-VtitoAFhYYMKDXckxuHpZXG7vvmx-PXlebH4A4SyzrS5E1pB1jooUKKXdBVCgSXoEqJJHLHRNs9fpI4mMbiKO8i1ckZL6wUzw1VeDaN4GcU34e8KdtwCzySC0-AMz1-h0Dvl5RujM4m1X6kQvostPnMjSNpCw60dwspBzc2r_cqRAnkBXBUkExRHjD1q6wbrG2gstoU-OSC-NVxZ-kY2IsboFFs0zvZnavbgA_0qpISIzXaVyCtyt2hztKA06NY1rQMR7JVCcQm5LnCDKmLzsxDw-hABg50Wv09Y2yLshKuAgxV1IxHwjfvPDKXenSiKWBqxFNakonsyibv_vQBImUPExhYGGgYwqJ0RjcQoXfK62OQKBnXetFG63JRvSZzEMKi5cyZKlxFjEbul5CmNVs6KPzFlEVsMTh5NRhSvwRaNKPeDmueVUOiDa2FgWjXwIU2XUmxxy42F4NlgMAhfFK8xSm_AoXXhic8Ju8YNXb9C2n0DzrQYlgkE9CSaLsIDgCwbxlF60_8EIGNC-Y0RG9lNY5L3xYiNSdoa3LykDKJ0CU8vNz-WL7f0qxdni5PvdBUiF25AKUcLeX6ssUs-r2zx8PivMyOd6AnGfvxBQlk2PNHf6To6WXJysqeXbz-Wj7_cQ3fDw-FpRpzdv_-77sjCVcLC_WoNJRGFq4xuN5XPD4O2lc722etPcMIASPsJd1h4dJ0b9Yi7EAbCCxYhGqdOnWTwEh0X0h6v_CRnpdaEdA0ZAj-wg4dHpXewQ-9Th__nxYLAT7g_PHj5deWfWToimi0WYHAjrENjv6LKu8N3HxB862-nZxrS2lq0wA32bIEFuXpGRnS5RKAe3f0lH3ZKLB15d6x3CE-ajlbxLQJX78Y_YTuhgAeKOroyMkuR4OrE6sl-2qw7fpzEZ8kZNB_0DU_vBj3EYHtCzmBfRfN5pBujc7TWlxt1kl4-HBGbkcMFljZi8y-SmvB2F7E7eAwKgUvpVQz7dbrJiM1a5YtpAfcPa9wAscFvFte4IQMQTW_fYSUI1LN15zAhLr0R9lkY13J5eMxmXhO513sI_t-vXBUSSXyNm98svksu4P721n-saE96ZBOlxc5wxJL79WoQpd-EXXfhu2gtGHqs9vaCoVML0XR5MXyVcw0xYwjiRriqzYa5riN2J-W2_xg0Rv8bcxexu0zqLGJ3fJTjbBrPxnPOilk2znGWzdk0ZeP5KJ7NkfFZko3K7EiPoB8LXeAvVATvTsr5MG-aiKXfx2zyAfY1cmVBEGiE6kr9xxpfQsV96Q1oCuXeYKkJkVwFahAeXh8p65h9HrW1gsrxnXhDe1qpSZH3gpDDocQdFKIs0aBysON7z05Wyy0Geu046kKZ9jynQWnXIwSeFwGkgagIyIFzTlxwHQtK8YpA56-E37TNc9ihQdBK7t9BR23KVosCmv5UWbuhvgmcEVhAqwZBtmvmaq9MKNtg7hu8rmnxx_T7ClF4ry0SHe0pGhtwmpo33WZEnb4r822dlDoPHWXnaVdRbMULIgKldz0hrrq4-g7LVrqVBdG8fv2qoB2wvxSWjO0OEeksa_Uexq5Z3PvqEdax8LZrbZ0PqNyf6d1RgxfKISnysetFAlaF_T1c0jmH9MAdWnQRm93cL395_C1QCZWmY2x-LUpF668g-e_hmRXzMh3Ho9E8ScYTNmM8zaezMR9PWJnnccbTPJkkk-Qczz-52ZDXd53X7O5p1TPkSpW6B_YkGS2SwfdJMl-MPg4AO272BCkPGqtl2_UZOe-qFGVNq14VjQZG2Nce4FCEXgF4plsHu2pPGN8dV_hDD26sg0byHD-B400RsPf94RiG3J4Vauo__CBzXLROeOJ3hLw1xAlyH_DIg2pSdl6Cw3Bj8ZLSIZAqjwXSQMf46GA3HZ11ExZ2KOUQHgw0aCre2NBBvNPVBXtHTQ_lthW1kNyQha6_KrQX6RjY8i2-oW8cHJpaKO60sefzzVmaSnRUd63vCqPxLYFhvKRbOsCnwLI-n0CpXD89PD6-_C5c9bJGyd8CvqN08Q5aZl_ycK6XbZ7_SbNIaN1nQlm__9Z0GUsQGVlR18nE19RjLUcrPfum3w4I_Ojej__NP_UPORhNlz2BfVPFhWj_XzuBPJ9M09lkWsynHLMkGScFH5fTMi7y8bwYTTFLZ6NsNP4LzPHwuDrOflcQcyTjeE7UkYyT2YKdVMN7_nqYZPKKqw2V-tZiARykdp440DoouZCtwZDfQm25FAWNPn3xsYg1FtAYdG4PNZIukXNJmV-KN6KUtvmENe756_mricq3ZR873zCqtOqwYNusXzvnjwPoqQCTH12_fKmfzva-KeinlssG7JeTIbsN137SSPcjAn832lR76yPTqx0eFPg24yQQoYSFJrWvcSfN6qEl73vW8L7AJwFEbBJ62IOHPT9E7BaAW4uGyuWlVjk0yqQiYhP42Us8dt4ftfDvLXV6rL2bGe4XT222xs3KoSFyg_DT9hsXpDsA-C5iNyuVy7bAJ5Slf2NCWCq5pLOe6ff_OmVDYZ8pI33nT3Lgr-P2YOuos6DNh6gFgQBtdtOLn9n5cqQIe45nCtp1YazoBc_nCm_kvSOhS_qqO7np38K1TcHdh7HR6cN4K_dUbGrq3nfavPoL-Zj6w8tt4WepaFr1oHx20d1eSLaeY59qLuUz5k6bVd3IKF30QY_SbyS8DHPpUct3yEcK9Woo7BKzdtMbO8-xURyNYhiMiRYXE7rwSZxGbDGDbulvH-FvjKL_8CzaJSYZOc-5iyzx2UgLn7bCV8V1WszTOb_C62Qaz5IknqbpVXWd53GSJknOZvPRJGNZOcdpPmasHM9HCZ9Pr8Q1i9koZskkmScsSYezIkvKybScTmfxBBO6G6y5kEOqZUNtNlf-Je31jMVpfCV5htL61_WMKdyFN7hUpMfLK3PtCygNEdEolsI6-67FCSf9e_6uGo6XZ0VFqFwbgzkhI7zyvvSe-6o18vq_ruTeSxuxO3-K_wQAAP__DOh_OQ">