liveBook · Manning

Compiler intrinsic

As explained in Rust in Action: Systems programming concepts and techniques

A compiler intrinsic is a compiler-recognized low-level operation exposed through a programming-language interface rather than an ordinary library implementation.

A compiler intrinsic is a function made available through the compiler rather than an ordinary language or library implementation. It gives a program access to functionality the compiler knows about, including features of the target CPU. Atomic operations and exception-handling facilities are examples. section 12.9.2

Intrinsics are useful when ordinary Rust cannot express the required behavior. A small operating-system kernel can call intrinsics::abort() from its panic handler. Another program can use setjmp() and longjmp() to jump out of deeply nested calls instead of returning through each call in turn. section 11.2.3 section 12.9

Using an LLVM intrinsic in Rust requires explicit setup:

  • Enable the relevant unstable feature at the crate level. This requires a nightly compiler toolchain. section 12.9.2 section 11.2.3
  • Declare an externally provided function with its type signature. For setjmp() and longjmp(), extern "C" selects C calling conventions, while link_name identifies the LLVM function. section 12.9.2
  • Call those declared functions inside an unsafe block: Rust knows their signatures, but not enough about their behavior to make their use safe automatically. section 12.9.2
Listing 12.15 Declaring the LLVM intrinsic functions within listing 12.17
extern "C" {
  #[link_name = "llvm.eh.sjlj.setjmp"]      #1
  pub fn setjmp(_: *mut i8) -> i32;         #2
 
  #[link_name = "llvm.eh.sjlj.longjmp"]     #1
  pub fn longjmp(_: *mut i8);
}

Compare each Rust declaration with its link_name. The Rust function name is what the program calls; the attribute names the LLVM intrinsic being linked. section 12.9.2

Listing 11.4 Creating an OS kernel that paints a block of color
 1 #![no_std]                              #1
 2 #![no_main]                             #1
 3 #![feature(core_intrinsics)]            #2
 4   
 5 use core::intrinsics;                   #2
 6 use core::panic::PanicInfo;             #3
 7  
 8 #[panic_handler]
 9 #[no_mangle]
10 pub fn panic(_info: &PanicInfo) -> ! {
11   intrinsics::abort();                  #4
12 }
13  
14 #[no_mangle]
15 pub extern "C" fn _start() -> ! {
16   let framebuffer = 0xb8000 as *mut u8;
17  
18   unsafe {
19     framebuffer
20       .offset(1)                        #5
21       .write_volatile(0x30);            #6
22   }
23  
24   loop {}
25 }

See a second use in a small kernel: a feature gate enables core intrinsics, and the panic handler calls intrinsics::abort(). section 11.2.3

This access comes with a trade-off. LLVM’s exposed internals are not covered by Rust’s stability guarantees and may change. Use an intrinsic when its extra capability is needed, not as a routine substitute for ordinary Rust. section 11.2.3 section 11.7

How Rust in Action: Systems programming concepts and techniques covers it

How deep it goes
Defines intrinsics and shows feature gates, external declarations, and unsafe use without detailing their compiler implementation.
Examples
Uses a kernel panic handler calling abort() and setjmp()/longjmp() declarations for escaping nested calls.
What it assumes
Introduces intrinsics from their definition and explains C calling conventions and pointer syntax used in the declarations.
What you can do after
Apply it via Rust feature gates and external declarations to access the demonstrated LLVM intrinsics.
How it connects
Connects intrinsics to LLVM, CPU instructions, atomic operations, exception handling, calling conventions, and unsafe Rust.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Rust in Action: Systems programming concepts and techniques. The section links point to the parts of the book it draws on.