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

    <tr>
        <th>Summary</th>
        <td>
            [RISC-V] suboptimal loop transformation with some for loops
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

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

    <tr>
      <th>Reporter</th>
      <td>
          tom-rein
      </td>
    </tr>
</table>

<pre>
    The following code illustrates the problem ([godbolt](https://godbolt.org/z/bW4d1bG8n)):
```C++
void add1(int *x, int *end) {
    for (; x != end; ++x) {
        ++*x;
    }
}

void add1_i(int *x, size_t n) {
    for (size_t i = 0; i != n; ++i) {
 ++x[i];
    }
}

void add1_n(int *x, size_t n) {
    add1(x, x + n);
}

void add1_2(int *x, int *end) {
    size_t n = end - x;
    for (size_t i = 0; i != n; ++i) {
        ++x[i];
    }
}

void add1_3(int *x, int *end) {
    add1_i(x, end - x);
}

void add1_s(std::span<int> r) {
    for (int &x : r) {
        ++x;
    }
}
```
`add1` and `add1_i` generate optimal code with a single induction variable and `bne`.
```
add1(int*, int*):
        beq     a0, a1, .LBB0_2
.LBB0_1:
 lw      a2, 0(a0)
        addi    a2, a2, 1
        sw      a2, 0(a0)
        addi    a0, a0, 4
        bne     a0, a1, .LBB0_1
.LBB0_2:
 ret

add1_i(int*, unsigned long):
        beqz    a1, .LBB1_3
 slli    a1, a1, 2
        add     a1, a1, a0
.LBB1_2:
        lw a2, 0(a0)
        addi    a2, a2, 1
        sw      a2, 0(a0)
        addi a0, a0, 4
        bne     a0, a1, .LBB1_2
.LBB1_3:
        ret
```
I would expect `add1_n` to be identical to `add1_i`, but instead this is generated:
```
add1_n(int*, unsigned long):
        beqz    a1, .LBB2_3
 slli    a1, a1, 2
.LBB2_2:
        lw      a2, 0(a0)
        addi a1, a1, -4
        addi    a2, a2, 1
        sw      a2, 0(a0)
 addi    a0, a0, 4
        bnez    a1, .LBB2_2
.LBB2_3:
 ret
```
One extra add per iteration and a totally useless left shift (useless because `a1` is only used as a loop counter).
`add1_2` is similar to `add1_n` with a subtract (and useless right shift) to get the length, but should be the same as `add1`.
`add1_3` is almost correct. It has the correct loop body, but adds and subtracts `a0` which should have been removed:
```
add1_3(int*, int*):
        beq     a1, a0, .LBB4_3
 sub     a1, a1, a0
        srai    a1, a1, 2
        slli    a1, a1, 2
 add     a1, a1, a0
.LBB4_2:
        lw      a2, 0(a0)
        addi a2, a2, 1
        sw      a2, 0(a0)
        addi    a0, a0, 4
        bne a0, a1, .LBB4_2
.LBB4_3:
        ret
```
`add1_s` results in the same as `add1_n`, even though the code does almost exactly what the generated `add1_i` does.
The redundant add and subtract seems to only happen for RISC-V.
The variation in the loop body also happens on aarch64 (when I disable vectorization), but I don't know if there is a performance difference.
On aarch64 there are also the same useless shifts, where the loop counter is not used for indexing.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJy0V2-P4rYT_jTmzWhR4gQWXvACdn_8tFKlSm3Vvlw58YS4NTa1HeD201fj_CFw3N7etYdCSOKx55mZZx4c4b3aGcQVm23Y7HkimlBbtwp2_-BQmUlh5afVbzVCZbW2J2V2UFqJoLRufHAioIdQIxycLTTugfEFm212VhZWBzZ7ZnxRh3DwLFszvmV82w1Nrdsxvn1jfFv8kcu0-P_CML6kI1uzZM3mSXs8Mb6hI1kfrZIgpEwZXygTgPH1mfEn6K7RSMaXwB7JFgCgsi7CyTZwBsZTlj0DGWUbaNc8X9vTp3NGK2f9c_b4TIDa8wjGq7oB4tUbvgYwd2F0gwoIRkIgVA_KXCCp0dwe5GyjKJFfx2M-hKfLYLSgvGyiQbv8nUX5B7PdO4MuzfAAoxx-dxKu6vINucg-CHsoZLTqcb-TD09hBEkszdb-IAzLnpQJLPsfuLuFbz3Pz8Cy9a3JOLT7MfVt0F7H2s0TEEZCd_uq6MEODVIzgj0EtRe6bdKTCjUI8MrsNIIysimDsgaOwilRaOzXKQyyeTK98XdpNcbXXQ7jVdeifQAF_h1_RUJGIqXz9KfNJnnlLFm3V2k3RZ_aOYKTVcL4gmYtR6sJKdXFoj2no3H_8RVaPPGcj_Ea_ALedMDLO7wOQ0uAccN36WhMlE4J2prdvay8RS_D-kTKZA1ea3UZaM_8Gj7cjoukQ5YOyLqPPv34XH5rItOh8BTyFdwunyOWvcDJNloCng9YhoHVhlgdLBQISqIJqhSa7sesJ39FE0AZH1BICLXyoPzQDPLmr6Qvo_lXZeTvl7E1-bxKH0r0aK2H_L8p5Ae64bMAL3Fk130wyuTPBgHPwYlI2AM6UIGyTvpCsiIg2CC0_gSNR43eg8YqgK9VRXq46J8WWIrGYyxs1DblwZp2mgThQYC29gClbUxA0s_pRQtfeTfDq73Swo0ZEhnUK2BTBCfK6JjA9c6d2tUdJhLmYGGHIe5nNJpdqHuG-TpytMA45sUeCdlFkMeQsg6S0HvrA5TWOSzDFF4C1KLdLHXP2sBoh9X7EVL6mL0ecOskiaHUqqx7JLU4IhSIBhzu7fGLVM--ScDTC0Wo_HnH9Ka4L0gD-5x4V9G-qHjvSl3-vU30Q_84brUuH5ol_7rW9RTxVE-HvtHBgzL3SBXpG7ckRyQD2-zqjjsSQVocCIZnUQb9CU61aKk7yN_1FoHmEE9pM-9QNkYKExl3RTjwiHtPnRCbsBaHA5q4lfnl5denh9_7FeIWIjZ7h3_gMgjtbTeRWhmEcGU9z6n3TjUaeAGpfNx-HLEM1qm3uFDc_bdt8AKS7h8D_GXsCVRFHhzGriKpqazbC1MiSFVV6NCUOI2SNPhq7QV9Cc2Q4L7xY8t78neKlkMEncyQK2NDK0IUvTISz8rsphO5yuQyW4oJrtLHWZrmeb7IJ_VqWVXpfD4vF4VcVtV8hlgtHpcZl2lW5Y-8nKgVT_gsmfMFT5OU59NlPscFX4hHUc5FkaUsT3AvlJ5qfdzTC9JEed_gKs3nPE8nWhSofXxR49zgCeIo45ze29yKJj0Uzc6zPNHKB39ZJqig4xteW0M2e6Z691vFGHdwwviY11jUqJve7jEGTxZ-0ji9unmXU6Fuimlp94xvyVv383Bw9k8sA-PbiNEzvu2COK74PwEAAP__o0j5UQ">