Skip to content

Instantly share code, notes, and snippets.

@japaric
Created March 29, 2018 08:18
Show Gist options
  • Save japaric/ec53ba0f81785c2cc0c948ba7d415587 to your computer and use it in GitHub Desktop.
Save japaric/ec53ba0f81785c2cc0c948ba7d415587 to your computer and use it in GitHub Desktop.

Currently panic! is implemented as such:

// for std
static ARGS: _ = (format_args!("format string", args...), file!(), line!(), column!())
std::rt::begin_panic_fmt(&ARGS)
// for core
static ARGS: _ = (format_args!("format string", args...), file!(), line!(), column!())
core::panicking::panic(&ARGS)

This implementation is tuned very heavily to make sure that at the panic location as little code is generated as possible, and as much of it, as possible, is generated at compile time.

In LLVM this desugars to code as trivial as (somewhat abridged):

@str.6 = internal constant [6 x i8] c"peach.rs"
@ref.7 = private unnamed_addr constant { { [0 x i8]*, i64 }, i32, i32 } { { [0 x i8]*, i64 } { [0 x i8]* bitcast ([6 x i8]* @str.6 to [0 x i8]*), i64 6 }, i32 9, i32 5 }, align 8

define void @banana() unnamed_addr #1 personality i32 (...)* @rust_eh_personality {
  ; constructs ArgumentsV1 with some more global constants
  invoke void @"core::panicking::panic_fmt"(%"core::fmt::Arguments"* noalias nocapture nonnull dereferenceable(48) %_1, { { [0 x i8]*, i64 }, i32, i32 }* noalias readonly dereferenceable(24) bitcast ({ { [0 x i8]*, i64 }, i32, i32 }* @ref.7 to { { [0 x i8]*, i64 }, i32, i32 }*))
          to label %unreachable unwind label %cleanup
}

; later on

declare void @"core::panicking::panic_fmt"(%"core::fmt::Arguments"* noalias nocapture dereferenceable(48), { { [0 x i8]*, i64 }, i32, i32 }* noalias readonly dereferenceable(24)) unnamed_addr #3

This means that LLVM has no insight whatsoever into what is within the panic_fmt, and therefore must be conservative wrt the optimisations involving the globals.

Consider for example, a fairly common scenario in embedded/wasm, where the implementation of panic_fmt language item does not use any of this information from ARGS (or uses only some of it). LLVM is unable to remove any of these constants from the binary unless very aggressive optimisation options are employed. Due to panic_fmt wrapper, LLVM wouldn’t be able to remove the information even in the scenario where "all" the code, including the implementation of the panic_fmt language item, is within the same crate.

In other words, this panic_fmt wrapper is preventing optimisations even in areas where such optimisation would be otherwise possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment