Skip to content

Mixed language link time optimization

Daniel Micay edited this page Oct 6, 2013 · 11 revisions

main.c

#include <stdint.h>

uint32_t *foo();

int main() {
    free(foo());
}

foo.rs

#[no_std];
#[allow(ctypes, cstack)];

extern {
    fn malloc(size: uint) -> *mut u8;
    fn free(ptr: *mut u8);
    fn abort() -> !;
}

#[lang = "exchange_malloc"]
#[inline(always)]
unsafe fn exchange_malloc(size: uint) -> *mut u8 {
  let ptr = malloc(size);
  if ptr == 0 as *mut u8 {
    abort()
  }

  ptr
}

#[lang = "exchange_free"]
#[inline(always)]
unsafe fn exchange_free(ptr: *mut u8) {
    free(ptr)
}

#[no_mangle]
extern "C" fn foo() -> ~u32 {
    ~5
}

Build LLVM bytecode from the Rust code:

$ rustc foo.rs --emit-llvm --lib -O

The --lib flag is necessary even if Rust defines main, to avoid treating the Rust part as the entire application.

Compile together the C and Rust code with clang:

$ clang foo.bc main.c -flto -O3 -o main

Verify that LLVM eliminated the call to foo via inlining and removed the allocation as a dead store:

$ gdb main
(gdb) disassemble main
Dump of assembler code for function main:
   0x00000000004005b0 <+0>:	xor    %eax,%eax
   0x00000000004005b2 <+2>:	retq   
End of assembler dump.

All Categories:

Clone this wiki locally