How to disable inlining for function

I like to play with cargo asm (cargo-asm package). The problem is that every function I call from main() is inlined by rustc. Are there a way to say rust not to inline specific function (in release mode)? I found 'inline' hint, but not the opposite.

Similar to #[inline(always)] you can use never:

#[inline(never)]
fn no_inline() {
    println!("no_inline");
}

It almost worked. It does work for functions with side effects, but does not prevent rust to be 'too smart' and throwing away my function.

This code does not produce assembly for foo42:

#[inline(never)]
pub fn foo42() -> i32 {
    let a = 0;
    a
}

fn main() {
    println!("Hello, world!");
    while foo42()==0 {}
}

The only way for that to work would be to ensure that LLVM can't see the definition of foo42. You could try putting foo42 in a different module. This will often cause rustc to place it in a different codegen unit that unless you are using LTO is optimized independently by LLVM.

It does not work :frowning:

mod view {#[inline(never)]
    pub fn foo42() -> i32 {
        let a = 0;
        a
    }
}

fn main() {
    println!("Hello, world!");
    while view::foo42()==0 {}
}

I still can't see the assembly. Too smart!

Try to make it an extern function?

mod view{
    #[inline(never)]
    pub extern "C" fn foo42() -> i32 {
        let a = 0;
        a
    }
}

fn main() {
    println!("Hello, world!");
    while view::foo42()==0 {}
}

Nope, it's not in the function list:

cargo asm --rust 
__rustc_debug_gdb_scripts_section__
core::ops::function::FnOnce::call_once{{vtable.shim}}
core::ptr::drop_in_place
foo::main
std::rt::lang_start
std::rt::lang_start::{{closure}}
std::sys_common::backtrace::__rust_begin_short_backtrace

Here is an example of what @newpavlov meant (I think): Playground

FWIW, it does not seem to be a true blackbox for the caller (I guess thanks to LTO), but it does seem to prevent the function from being elided in the generated assembly :slightly_smiling_face:

If you just want to see what foo42 compiles to, it's fairly easy to just make it a library entry point by using #[no_mangle]:

#![crate_type = "staticlib"]

#[no_mangle]
fn foo42() -> i32 {
    let a = 0;
    a
}
foo42:
	xor	eax, eax
	ret
1 Like

I've tried, but it's not in the list of the functions (it appears if I add some side effect into function, like println!, so 'asm' crate does work).

It's exactly like your code, but with fn main(){} at the end (without it cargo does not compile it).

It needs to be a staticlib, not a binary. Binaries only have the main entry point.

Forgot that --emit asm forces a single codegen unit and as such this workaround doesn't work.