Skip to content

RISC-V missed optimisation: branch on equal to small constant #105539

@Wren6991

Description

@Wren6991

In this code:

void __attribute__((naked)) f() {asm ("ret");}
void __attribute__((naked)) g() {asm ("ret");}

void h(int a) {
    if (a == 15) {
        f();
    } else {
        g();
    }
}

clang trunk on godbolt produces the following at -Oz:

h(int):
        li      a1, 15
        bne     a0, a1, .LBB2_2
        tail    f()
.LBB2_2:
        tail    g()

(Godbolt link: https://godbolt.org/z/srT6MhG5Y)

However the following is two bytes smaller (because bnez compresses) and avoids a register clobber:

h(int):
        addi    a0, a0, -15
        bnez    a0, .LBB2_2
        tail    f()
.LBB2_2:
        tail    g()

This transform applies when the branch is the final use of the value, and the comparison constant is not -2048 or -32 (due to the sign change). It is useful when the branch is in compressible range, or when avoiding the clobber is profitable.

The same pattern applies to some sparse switch statements, like here in the RP2350 bootrom. That source file has several instances where this pattern saved static code size in handwritten code.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions