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.