Skip to content

Bad codegen for reversing bits in bytes without swapping bytes #141863

Open
@tom-rein

Description

@tom-rein

The following code on RISC-V target with Zbkb extension (godbolt):

#include <cstdint>
uint8_t brev8(uint8_t x) {
    return __builtin_bitreverse8(x);
}

Results in:

brev8(unsigned char):
        rev8    a0, a0
        brev8   a0, a0
        srli    a0, a0, 56
        ret

The expected result would be just brev8 a0, a0 since it doesn't swap bytes.

On armv8 target (and similarly on armv7) bit reversing bytes in uint16_t uses rev16 which results in an extra shift:

uint16_t brev8(uint16_t x) {
    return __builtin_bswap16(__builtin_bitreverse16(x));
}
brev8(unsigned short):
        rbit    w8, w0
        lsr     w8, w8, #16
        rev16   w0, w8
        ret

This could instead be:

brev8(unsigned short):
        rbit    w0, w0
        rev     w0, w0
        ret

(Also the register allocation somehow uses w8 instead of reusing w0, which I find weird, since that is done on other targets, including armv7)

When doing bswap16 first and then bitreverse16, it doesn't even use rev16, but adds two shifts:

uint16_t brev8_2(uint16_t x) {
    return __builtin_bitreverse16(__builtin_bswap16(x));
}
brev8_2(unsigned short):
        rev     w8, w0
        lsr     w8, w8, #16
        rbit    w8, w8
        lsr     w0, w8, #16
        ret

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