From 14593a55e1d6743a384dc85e17d0a848cac17184 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 3 Jul 2024 21:10:05 +0200 Subject: [PATCH] llr: Don't generate unused globals Global for which none of the properties are used can be omitted in the generated code. --- internal/compiler/generator/cpp.rs | 8 +++-- internal/compiler/generator/rust.rs | 23 ++++++++---- internal/compiler/llr/item_tree.rs | 9 +++++ internal/compiler/llr/pretty_print.rs | 50 +++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 9 deletions(-) diff --git a/internal/compiler/generator/cpp.rs b/internal/compiler/generator/cpp.rs index 86a950bcd..df4a6d89b 100644 --- a/internal/compiler/generator/cpp.rs +++ b/internal/compiler/generator/cpp.rs @@ -831,7 +831,7 @@ pub fn generate( for glob in &llr.globals { let ty = if glob.is_builtin { format!("slint::cbindgen_private::{}", glob.name) - } else { + } else if glob.must_generate() { generate_global(&mut file, &conditional_includes, glob, &llr); file.definitions.extend(glob.aliases.iter().map(|name| { Declaration::TypeAlias(TypeAlias { @@ -840,6 +840,8 @@ pub fn generate( }) })); ident(&glob.name) + } else { + continue; }; globals_struct.members.push(( @@ -954,12 +956,12 @@ fn generate_public_component( }), )); - for glob in unit.globals.iter().filter(|glob| !glob.is_builtin) { + for glob in unit.globals.iter().filter(|glob| glob.must_generate()) { component_struct.friends.push(ident(&glob.name)); } let mut global_accessor_function_body = Vec::new(); - for glob in unit.globals.iter().filter(|glob| glob.exported && !glob.is_builtin) { + for glob in unit.globals.iter().filter(|glob| glob.exported && glob.must_generate()) { let accessor_statement = format!( "{0}if constexpr(std::is_same_v) {{ return *m_globals.global_{1}.get(); }}", if global_accessor_function_body.is_empty() { "" } else { "else " }, diff --git a/internal/compiler/generator/rust.rs b/internal/compiler/generator/rust.rs index c883c5688..de7b40f40 100644 --- a/internal/compiler/generator/rust.rs +++ b/internal/compiler/generator/rust.rs @@ -181,8 +181,11 @@ pub fn generate(doc: &Document, compiler_config: &CompilerConfiguration) -> Toke env!("CARGO_PKG_VERSION_PATCH"), ); - let globals = - llr.globals.iter().filter(|glob| !glob.is_builtin).map(|glob| generate_global(glob, &llr)); + let globals = llr + .globals + .iter() + .filter(|glob| glob.must_generate()) + .map(|glob| generate_global(glob, &llr)); let shared_globals = generate_shared_globals(&llr); let globals_ids = llr.globals.iter().filter(|glob| glob.exported).flat_map(|glob| { std::iter::once(ident(&glob.name)).chain(glob.aliases.iter().map(|x| ident(x))) @@ -310,12 +313,20 @@ fn generate_public_component( } fn generate_shared_globals(llr: &llr::CompilationUnit) -> TokenStream { - let global_names = - llr.globals.iter().map(|g| format_ident!("global_{}", ident(&g.name))).collect::>(); - let global_types = llr.globals.iter().map(global_inner_name).collect::>(); + let global_names = llr + .globals + .iter() + .filter(|g| g.is_builtin || g.must_generate()) + .map(|g| format_ident!("global_{}", ident(&g.name))) + .collect::>(); + let global_types = llr + .globals + .iter() + .filter(|g| g.is_builtin || g.must_generate()) + .map(global_inner_name) + .collect::>(); quote! { - #[allow(dead_code)] // FIXME: some global are unused because of optimization, we should then remove them completely struct SharedGlobals { #(#global_names : ::core::pin::Pin>,)* window_adapter : sp::OnceCell, diff --git a/internal/compiler/llr/item_tree.rs b/internal/compiler/llr/item_tree.rs index b5c51f6d7..b63ce09c0 100644 --- a/internal/compiler/llr/item_tree.rs +++ b/internal/compiler/llr/item_tree.rs @@ -73,6 +73,15 @@ pub struct GlobalComponent { pub prop_analysis: Vec, } +impl GlobalComponent { + pub fn must_generate(&self) -> bool { + !self.is_builtin + && (self.exported + || !self.functions.is_empty() + || self.properties.iter().any(|p| p.use_count.get() > 0)) + } +} + /// a Reference to a property, in the context of a SubComponent #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub enum PropertyReference { diff --git a/internal/compiler/llr/pretty_print.rs b/internal/compiler/llr/pretty_print.rs index fb5ce326d..a11fd76d6 100644 --- a/internal/compiler/llr/pretty_print.rs +++ b/internal/compiler/llr/pretty_print.rs @@ -30,6 +30,11 @@ struct PrettyPrinter<'a> { impl<'a> PrettyPrinter<'a> { fn print_root(&mut self, root: &CompilationUnit) -> Result { + for g in &root.globals { + if !g.is_builtin { + self.print_global(root, g)?; + } + } for c in &root.sub_components { self.print_component(root, c, None)? } @@ -111,6 +116,51 @@ impl<'a> PrettyPrinter<'a> { writeln!(self.writer, "}}") } + fn print_global(&mut self, root: &CompilationUnit, global: &super::GlobalComponent) -> Result { + let ctx = EvaluationContext::new_global(root, global, ()); + if global.exported { + write!(self.writer, "export ")?; + } + let aliases = global.aliases.join(","); + let aliases = if aliases.is_empty() { String::new() } else { format!(" /*{aliases}*/") }; + writeln!(self.writer, "global {} {{{aliases}", global.name)?; + self.indentation += 1; + for ((p, init), is_const) in + std::iter::zip(&global.properties, &global.init_values).zip(&global.const_properties) + { + self.indent()?; + let init = init.as_ref().map_or(String::new(), |init| { + format!( + ": {}{}", + DisplayExpression(&init.expression.borrow(), &ctx,), + if init.is_constant { "/*const*/" } else { "" } + ) + }); + writeln!( + self.writer, + "property <{}> {}{init}; //use={}{}", + p.ty, + p.name, + p.use_count.get(), + if *is_const { " const" } else { "" } + )?; + } + for f in &global.functions { + self.indent()?; + writeln!( + self.writer, + "function {} ({}) -> {} {{ {} }}; ", + f.name, + f.args.iter().map(ToString::to_string).join(", "), + f.ret_ty, + DisplayExpression(&f.code, &ctx) + )?; + } + self.indentation -= 1; + self.indent()?; + writeln!(self.writer, "}}") + } + fn indent(&mut self) -> Result { for _ in 0..self.indentation { self.writer.write_str(" ")?;