Auto merge of #88832 - pcwalton:debug-unit-variant-fast-path, r=oli-obk
Introduce a fast path that avoids the `debug_tuple` abstraction when deriving Debug for unit-like enum variants. The intent here is to allow LLVM to remove the switch entirely in favor of an indexed load from a table of constant strings, which is likely what the programmer would write in C. Unfortunately, LLVM currently doesn't perform this optimization due to a bug, but there is [a patch](https://reviews.llvm.org/D109565) that fixes this issue. I've verified that, with that patch applied on top of this commit, Debug for unit-like tuple variants becomes a load, reducing the O(n) code bloat to O(1). Note that inlining `DebugTuple::finish()` wasn't enough to allow LLVM to optimize the code properly; I had to avoid the abstraction entirely. Not using the abstraction is likely better for compile time anyway. Part of #88793. r? `@oli-obk`
This commit is contained in:
commit
78a46efff0
@ -65,15 +65,29 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
|
|||||||
// We want to make sure we have the ctxt set so that we can use unstable methods
|
// We want to make sure we have the ctxt set so that we can use unstable methods
|
||||||
let span = cx.with_def_site_ctxt(span);
|
let span = cx.with_def_site_ctxt(span);
|
||||||
let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
|
let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
|
||||||
|
let fmt = substr.nonself_args[0].clone();
|
||||||
|
|
||||||
|
// Special fast path for unit variants. In the common case of an enum that is entirely unit
|
||||||
|
// variants (i.e. a C-like enum), this fast path allows LLVM to eliminate the entire switch in
|
||||||
|
// favor of a lookup table.
|
||||||
|
if let ast::VariantData::Unit(..) = vdata {
|
||||||
|
let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
|
||||||
|
let expr = cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]);
|
||||||
|
let stmts = vec![cx.stmt_expr(expr)];
|
||||||
|
let block = cx.block(span, stmts);
|
||||||
|
return cx.expr_block(block);
|
||||||
|
}
|
||||||
|
|
||||||
let builder = Ident::new(sym::debug_trait_builder, span);
|
let builder = Ident::new(sym::debug_trait_builder, span);
|
||||||
let builder_expr = cx.expr_ident(span, builder);
|
let builder_expr = cx.expr_ident(span, builder);
|
||||||
|
|
||||||
let fmt = substr.nonself_args[0].clone();
|
|
||||||
|
|
||||||
let mut stmts = Vec::with_capacity(fields.len() + 2);
|
let mut stmts = Vec::with_capacity(fields.len() + 2);
|
||||||
let fn_path_finish;
|
let fn_path_finish;
|
||||||
match vdata {
|
match vdata {
|
||||||
ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
|
ast::VariantData::Unit(..) => {
|
||||||
|
cx.span_bug(span, "unit variants should have been handled above");
|
||||||
|
}
|
||||||
|
ast::VariantData::Tuple(..) => {
|
||||||
// tuple struct/"normal" variant
|
// tuple struct/"normal" variant
|
||||||
let fn_path_debug_tuple = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_tuple]);
|
let fn_path_debug_tuple = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_tuple]);
|
||||||
let expr = cx.expr_call_global(span, fn_path_debug_tuple, vec![fmt, name]);
|
let expr = cx.expr_call_global(span, fn_path_debug_tuple, vec![fmt, name]);
|
||||||
|
@ -1417,6 +1417,7 @@ symbols! {
|
|||||||
wrapping_sub,
|
wrapping_sub,
|
||||||
wreg,
|
wreg,
|
||||||
write_bytes,
|
write_bytes,
|
||||||
|
write_str,
|
||||||
x87_reg,
|
x87_reg,
|
||||||
xer,
|
xer,
|
||||||
xmm_reg,
|
xmm_reg,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user