Skip to content

Incorrect code generated from inline assembly with inout register on riscv32im-unknown-none-elf #128212

@shkoo

Description

@shkoo

I tried compiling this code with a target of riscv32im-unknown-none-elf:

#![no_std]

static mut MY_BUFFER: [u32; 4] = [0u32; 4];

#[no_mangle]
unsafe fn using_inout() {
    let mut start = MY_BUFFER.as_mut_ptr();
    ::core::arch::asm!(
            "ecall",
            inout("a0") start);
    _ = start;
}

The assembly generated is incorrect, since it doesn't add in the lower 16 bits of the address of MY_BUFFER before calling the ecall:

using_inout:
        lui     a0, %hi(example::MY_BUFFER::he36bd30b506a9b69)
        ecall
        ret

As a workaround, changing the inout to inlateout seems to fix the problem:

using_inlateout:
        lui     a0, %hi(example::MY_BUFFER::he36bd30b506a9b69)
        addi    a0, a0, %lo(example::MY_BUFFER::he36bd30b506a9b69)
        ecall
        ret

Here is a compiler explorer link for rust nightly that demonstrates the problem:

https://godbolt.org/z/xMjoTo5oY

(For reference in case it gets fixed in nightly, it's also present in rust 1.80.0)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-inline-assemblyArea: Inline assembly (`asm!(…)`)C-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessO-riscvTarget: RISC-V architectureP-highHigh priorityllvm-fixed-upstreamIssue expected to be fixed by the next major LLVM upgrade, or backported fixes

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions