-
Notifications
You must be signed in to change notification settings - Fork 640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Compiler optimizations #7680
Compiler optimizations #7680
Changes from 7 commits
aabbeb7
17b38d3
188de63
4ef27e3
cc6a700
9533dd1
68a1f3c
1b699e8
d494603
14c227e
57df760
47c0c70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,6 +105,19 @@ fn simplify_expression(expr: &mut Expression) -> bool { | |
} | ||
can_inline | ||
} | ||
Expression::UnaryOp { sub, op } => { | ||
ogoffart marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let can_inline = simplify_expression(sub); | ||
let new = match (*op, &mut **sub) { | ||
('!', Expression::BoolLiteral(b)) => Some(Expression::BoolLiteral(!*b)), | ||
('-', Expression::NumberLiteral(n, u)) => Some(Expression::NumberLiteral(-*n, *u)), | ||
('+', Expression::NumberLiteral(n, u)) => Some(Expression::NumberLiteral(*n, *u)), | ||
_ => None, | ||
}; | ||
if let Some(new) = new { | ||
*expr = new; | ||
} | ||
can_inline | ||
} | ||
Expression::StructFieldAccess { base, name } => { | ||
let r = simplify_expression(base); | ||
if let Expression::Struct { values, .. } = &mut **base { | ||
|
@@ -148,6 +161,38 @@ fn simplify_expression(expr: &mut Expression) -> bool { | |
} | ||
can_inline | ||
} | ||
Expression::Condition { condition, true_expr, false_expr } => { | ||
let mut can_inline = simplify_expression(condition); | ||
can_inline &= match &**condition { | ||
Expression::BoolLiteral(true) => { | ||
*expr = *true_expr.clone(); | ||
simplify_expression(expr) | ||
} | ||
Expression::BoolLiteral(false) => { | ||
*expr = *false_expr.clone(); | ||
simplify_expression(expr) | ||
} | ||
_ => simplify_expression(true_expr) && simplify_expression(false_expr), | ||
}; | ||
can_inline | ||
} | ||
Expression::CodeBlock(stmts) if stmts.len() == 1 => { | ||
*expr = stmts[0].clone(); | ||
simplify_expression(expr) | ||
} | ||
Expression::FunctionCall { function, arguments, .. } => { | ||
let mut args_can_inline = true; | ||
for arg in arguments.iter_mut() { | ||
args_can_inline &= simplify_expression(arg); | ||
} | ||
if args_can_inline { | ||
if let Some(inlined) = try_inline_function(function, arguments) { | ||
*expr = inlined; | ||
true; | ||
} | ||
} | ||
false | ||
ogoffart marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
Expression::ElementReference { .. } => false, | ||
Expression::LayoutCacheAccess { .. } => false, | ||
Expression::SolveLayout { .. } => false, | ||
|
@@ -199,6 +244,30 @@ fn extract_constant_property_reference(nr: &NamedReference) -> Option<Expression | |
Some(expression) | ||
} | ||
|
||
fn try_inline_function(function: &Callable, arguments: &[Expression]) -> Option<Expression> { | ||
let Callable::Function(function) = function else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note for future improvements: we could also try to inline some built-in functions. |
||
return None; | ||
}; | ||
if !function.is_constant() { | ||
return None; | ||
} | ||
let mut body = extract_constant_property_reference(function)?; | ||
|
||
body.visit_recursive_mut(&mut |e| { | ||
if let Expression::FunctionParameterReference { index, ty } = e { | ||
let Some(e_new) = arguments.get(*index).cloned() else { return }; | ||
ogoffart marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if e_new.ty() == *ty { | ||
*e = e_new; | ||
} | ||
} | ||
}); | ||
if simplify_expression(&mut body) { | ||
Some(body) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
#[test] | ||
fn test() { | ||
let mut compiler_config = | ||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -149,17 +149,33 @@ pub fn initialize(elem: &ElementRc, name: &str) -> Option<Expression> { | |||
}; | ||||
} | ||||
|
||||
let expr = match name { | ||||
"min-height" => layout_constraint_prop(elem, "min", Orientation::Vertical), | ||||
"min-width" => layout_constraint_prop(elem, "min", Orientation::Horizontal), | ||||
"max-height" => layout_constraint_prop(elem, "max", Orientation::Vertical), | ||||
"max-width" => layout_constraint_prop(elem, "max", Orientation::Horizontal), | ||||
"preferred-height" => layout_constraint_prop(elem, "preferred", Orientation::Vertical), | ||||
"preferred-width" => layout_constraint_prop(elem, "preferred", Orientation::Horizontal), | ||||
"horizontal-stretch" => layout_constraint_prop(elem, "stretch", Orientation::Horizontal), | ||||
"vertical-stretch" => layout_constraint_prop(elem, "stretch", Orientation::Vertical), | ||||
"opacity" => Expression::NumberLiteral(1., Unit::None), | ||||
"visible" => Expression::BoolLiteral(true), | ||||
let builtin_name = match elem.borrow().builtin_type() { | ||||
Some(b) => b.name.clone(), | ||||
None => SmolStr::default(), | ||||
}; | ||||
|
||||
let expr = match (name, builtin_name.as_str()) { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In implicit_layout_info_call called by this function, we we already have special case in other part for the rectangle and empty, slint/internal/compiler/layout.rs Line 513 in 705f810
My hope was that then this could be optimized. But this still create something like a Otherwise it would make more sense to handle the Image in Also this might not be working well if the Image contains elements such as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The struct declaration + struct field call gets transformed for sure in the const propagation phase. Putting it into implicit_layout_info_call would be non-trivial, because it'd need to asssemble a struct that has mostly fixed fields, except the preferred lengths. This would need to be done with either multiple implicit calls, or a non-trivial local variable thing, which is not simplified properly (yet). And where the full layoutinfo struct is needed, it is in fact better to just call the implicit layout info without trying to be smart. You were right with the Image with children case, I'm going to fix that. |
||||
("min-height", "Image") => Expression::NumberLiteral(0., Unit::Px), | ||||
("min-width", "Image") => Expression::NumberLiteral(0., Unit::Px), | ||||
("max-height", "Image") => Expression::NumberLiteral(f32::MAX as _, Unit::Px), | ||||
("max-width", "Image") => Expression::NumberLiteral(f32::MAX as _, Unit::Px), | ||||
("horizontal-stretch", "Image") => Expression::NumberLiteral(0., Unit::None), | ||||
("vertical-stretch", "Image") => Expression::NumberLiteral(0., Unit::None), | ||||
|
||||
("min-height", _) => layout_constraint_prop(elem, "min", Orientation::Vertical), | ||||
("min-width", _) => layout_constraint_prop(elem, "min", Orientation::Horizontal), | ||||
("max-height", _) => layout_constraint_prop(elem, "max", Orientation::Vertical), | ||||
("max-width", _) => layout_constraint_prop(elem, "max", Orientation::Horizontal), | ||||
("horizontal-stretch", _) => { | ||||
layout_constraint_prop(elem, "stretch", Orientation::Horizontal) | ||||
} | ||||
("vertical-stretch", _) => layout_constraint_prop(elem, "stretch", Orientation::Vertical), | ||||
("preferred-height", _) => layout_constraint_prop(elem, "preferred", Orientation::Vertical), | ||||
("preferred-width", _) => { | ||||
layout_constraint_prop(elem, "preferred", Orientation::Horizontal) | ||||
} | ||||
("opacity", _) => Expression::NumberLiteral(1., Unit::None), | ||||
("visible", _) => Expression::BoolLiteral(true), | ||||
_ => return None, | ||||
}; | ||||
Some(expr) | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this actually happen?
I guess it's good to be resilient in this debug code anyway. But it is a bit worrisome if that happens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something as simple as
cargo run --bin slint-compiler -- -f llr ./tests/cases/widgets/tableview.slint
crashes the printer on the most recent master.I guess there's an actual code generation issue here, but I didn't want to investigate. In fact I didn't want to push this commit at all, but it accidentally happened :D