Remove superfluous `andi ..., 0xff` instruction from inline assembly when outputting an `i8`

Viewed 124

I have the following function using inline assembly, targeting mipsel-unknown-linux-gnu:

#![feature(asm)]

#[no_mangle]
pub unsafe extern "C" fn f(ptr: u32) {
    let value: i8;
    asm!(
        "lb $v0, ($a0)",
        in("$4") ptr,
        out("$2") value,
    );
    asm!(
        "sb $v0, ($a0)",
        in("$4") ptr,
        in("$2") value,
    );
}

I expected this to compile into the following:

lb $v0, ($a0)
sb $v0, ($a0)
jr $ra
nop

Note: In this example, it's possible the compiler reorders the store instruction to after the jump to use the delay slot, but in my actual use case, I return via an asm block, so this is not a worry. Given this I expected the assembly above exactly.

Instead, what I got was:

00000000 <f>:
   0:   80820000        lb      v0,0(a0)
   4:   304200ff        andi    v0,v0,0xff
   8:   a0820000        sb      v0,0(a0)
   c:   03e00008        jr      ra
  10:   00000000        nop

The compiler seems to not have trusted me that the output is an i8 and inserted an andi $v0, 0xff instruction there.

I need to produce the assembly I specified above exactly, so I'd like to get rid of the andi instruction, while keeping the type of value i8.

My use case for this is that I want to produce an exact assembly output from this function, while being able to later fork it and add rust code that interacts with the existing assembly code to extend the function. For this I'd like value's type to be properly described as an i8 in the rust side.

Edit

Looking at the llvm-ir generated by rust, the andi instruction seems to have been added by rustc, not llvm.

; Function Attrs: nonlazybind uwtable
define void @f(i32 %ptr) unnamed_addr #0 {
start:
  %0 = tail call i32 asm sideeffect alignstack "lbu $$v0, ($$a0)", "=&{$2},{$4},~{memory}"(i32 %ptr) #1, !srcloc !2
  %1 = and i32 %0, 255   # <--------- Over here
  tail call void asm sideeffect alignstack "sb $$v0, ($$a0)", "{$4},{$2},~{memory}"(i32 %ptr, i32 %1) #1, !srcloc !3
  ret void
}

There is also no mention of an i8, so I'm not quite sure what rustc is doing here.

0 Answers
Related