Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add native support for min/max #3130

Merged
merged 1 commit into from Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 13 additions & 24 deletions internal/compiler/builtin_macros.rs
Expand Up @@ -6,7 +6,7 @@

use crate::diagnostics::{BuildDiagnostics, Spanned};
use crate::expression_tree::{
BuiltinFunction, BuiltinMacroFunction, EasingCurve, Expression, Unit,
BuiltinFunction, BuiltinMacroFunction, EasingCurve, Expression, MinMaxOp, Unit,
};
use crate::langtype::{EnumerationValue, Type};
use crate::parser::NodeOrToken;
Expand All @@ -22,8 +22,8 @@ pub fn lower_macro(
diag: &mut BuildDiagnostics,
) -> Expression {
match mac {
BuiltinMacroFunction::Min => min_max_macro(n, '<', sub_expr.collect(), diag),
BuiltinMacroFunction::Max => min_max_macro(n, '>', sub_expr.collect(), diag),
BuiltinMacroFunction::Min => min_max_macro(n, MinMaxOp::Min, sub_expr.collect(), diag),
BuiltinMacroFunction::Max => min_max_macro(n, MinMaxOp::Max, sub_expr.collect(), diag),
BuiltinMacroFunction::Mod => mod_macro(n, sub_expr.collect(), diag),
BuiltinMacroFunction::Debug => debug_macro(n, sub_expr.collect(), diag),
BuiltinMacroFunction::CubicBezier => {
Expand Down Expand Up @@ -67,7 +67,7 @@ pub fn lower_macro(

fn min_max_macro(
node: Option<NodeOrToken>,
op: char,
op: MinMaxOp,
args: Vec<(Expression, Option<NodeOrToken>)>,
diag: &mut BuildDiagnostics,
) -> Expression {
Expand Down Expand Up @@ -345,24 +345,13 @@ fn to_debug_string(
/// Generate an expression which is like `min(lhs, rhs)` if op is '<' or `max(lhs, rhs)` if op is '>'.
/// counter is an unique id.
/// The rhs and lhs of the expression must have the same numerical type
pub fn min_max_expression(lhs: Expression, rhs: Expression, op: char) -> Expression {
let ty = lhs.ty();
let id = COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let n1 = format!("minmax_lhs{}", id);
let n2 = format!("minmax_rhs{}", id);
let a1 = Box::new(Expression::ReadLocalVariable { name: n1.clone(), ty: ty.clone() });
let a2 = Box::new(Expression::ReadLocalVariable { name: n2.clone(), ty });
Expression::CodeBlock(vec![
Expression::StoreLocalVariable { name: n1, value: Box::new(lhs) },
Expression::StoreLocalVariable { name: n2, value: Box::new(rhs) },
Expression::Condition {
condition: Box::new(Expression::BinaryExpression {
lhs: a1.clone(),
rhs: a2.clone(),
op,
}),
true_expr: a1,
false_expr: a2,
},
])
pub fn min_max_expression(lhs: Expression, rhs: Expression, op: MinMaxOp) -> Expression {
let lhs_ty = lhs.ty();
let rhs_ty = rhs.ty();
let ty = match (lhs_ty, rhs_ty) {
(a, b) if a == b => a,
(Type::Int32, Type::Float32) | (Type::Float32, Type::Int32) => Type::Float32,
_ => Type::Invalid,
};
Expression::MinMax { ty, op, lhs: Box::new(lhs), rhs: Box::new(rhs) }
}
33 changes: 33 additions & 0 deletions internal/compiler/expression_tree.rs
Expand Up @@ -429,6 +429,12 @@ impl Default for Unit {
}
}

#[derive(Debug, Clone, Copy)]
pub enum MinMaxOp {
Min,
Max,
}

/// The Expression is hold by properties, so it should not hold any strong references to node from the object_tree
#[derive(Debug, Clone, Default)]
pub enum Expression {
Expand Down Expand Up @@ -612,6 +618,13 @@ pub enum Expression {
/// The orientation is the orientation of the cache, not the orientation of the layout
ComputeLayoutInfo(crate::layout::Layout, crate::layout::Orientation),
SolveLayout(crate::layout::Layout, crate::layout::Orientation),

MinMax {
ty: Type,
op: MinMaxOp,
lhs: Box<Expression>,
rhs: Box<Expression>,
},
}

impl Expression {
Expand Down Expand Up @@ -738,6 +751,7 @@ impl Expression {
Expression::LayoutCacheAccess { .. } => Type::LogicalLength,
Expression::ComputeLayoutInfo(..) => crate::layout::layout_info_type(),
Expression::SolveLayout(..) => Type::LayoutCache,
Expression::MinMax { ty, .. } => ty.clone(),
}
}

Expand Down Expand Up @@ -836,6 +850,10 @@ impl Expression {
}
Expression::ComputeLayoutInfo(..) => {}
Expression::SolveLayout(..) => {}
Expression::MinMax { lhs, rhs, .. } => {
visitor(lhs);
visitor(rhs);
}
}
}

Expand Down Expand Up @@ -936,6 +954,10 @@ impl Expression {
}
Expression::ComputeLayoutInfo(..) => {}
Expression::SolveLayout(..) => {}
Expression::MinMax { lhs, rhs, .. } => {
visitor(lhs);
visitor(rhs);
}
}
}

Expand Down Expand Up @@ -1010,6 +1032,7 @@ impl Expression {
Expression::LayoutCacheAccess { .. } => false,
Expression::ComputeLayoutInfo(..) => false,
Expression::SolveLayout(..) => false,
Expression::MinMax { lhs, rhs, .. } => lhs.is_constant() && rhs.is_constant(),
}
}

Expand Down Expand Up @@ -1623,5 +1646,15 @@ pub fn pretty_print(f: &mut dyn std::fmt::Write, expression: &Expression) -> std
}
Expression::ComputeLayoutInfo(..) => write!(f, "layout_info(..)"),
Expression::SolveLayout(..) => write!(f, "solve_layout(..)"),
Expression::MinMax { ty: _, op, lhs, rhs } => {
match op {
MinMaxOp::Min => write!(f, "min(")?,
MinMaxOp::Max => write!(f, "max(")?,
}
pretty_print(f, lhs)?;
write!(f, ", ")?;
pretty_print(f, rhs)?;
write!(f, ")")
}
}
}
17 changes: 16 additions & 1 deletion internal/compiler/generator/cpp.rs
Expand Up @@ -309,7 +309,7 @@ mod cpp_ast {
}
}

use crate::expression_tree::{BuiltinFunction, EasingCurve};
use crate::expression_tree::{BuiltinFunction, EasingCurve, MinMaxOp};
use crate::langtype::{ElementType, Enumeration, EnumerationValue, NativeClass, Type};
use crate::layout::Orientation;
use crate::llr::{
Expand Down Expand Up @@ -2776,6 +2776,21 @@ fn compile_expression(expr: &llr::Expression, ctx: &EvaluationContext) -> String
)

}
Expression::MinMax { ty, op, lhs, rhs } => {
let ident = match op {
MinMaxOp::Min => "min",
MinMaxOp::Max => "max",
};
let lhs_code = compile_expression(lhs, ctx);
let rhs_code = compile_expression(rhs, ctx);
format!(
r#"std::{ident}<{ty}>({lhs_code}, {rhs_code})"#,
ty = ty.cpp_type().unwrap_or_default(),
ident = ident,
lhs_code = lhs_code,
rhs_code = rhs_code
)
}
}
}

Expand Down
19 changes: 18 additions & 1 deletion internal/compiler/generator/rust.rs
Expand Up @@ -12,7 +12,7 @@ Some convention used in the generated code:
this is usually a local variable to the init code that shouldn't rbe relied upon by the binding code.
*/

use crate::expression_tree::{BuiltinFunction, EasingCurve, OperatorClass};
use crate::expression_tree::{BuiltinFunction, EasingCurve, MinMaxOp, OperatorClass};
use crate::langtype::{ElementType, Enumeration, EnumerationValue, Type};
use crate::layout::Orientation;
use crate::llr::{
Expand Down Expand Up @@ -2189,6 +2189,23 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
let #cells_variable = sp::Slice::from_slice(&#cells_variable);
}
}
Expression::MinMax { ty, op, lhs, rhs } => {
let t = rust_primitive_type(ty);
let wrap = |expr| match &t {
Some(t) => quote!((#expr as #t)),
None => expr,
};
let lhs = wrap(compile_expression(lhs, ctx));
let rhs = wrap(compile_expression(rhs, ctx));
match op {
MinMaxOp::Min => {
quote!(#lhs.min(#rhs))
}
MinMaxOp::Max => {
quote!(#lhs.max(#rhs))
}
}
}
}
}

Expand Down
14 changes: 13 additions & 1 deletion internal/compiler/llr/expression.rs
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial

use super::PropertyReference;
use crate::expression_tree::{BuiltinFunction, OperatorClass};
use crate::expression_tree::{BuiltinFunction, MinMaxOp, OperatorClass};
use crate::langtype::Type;
use crate::layout::Orientation;
use itertools::Either;
Expand Down Expand Up @@ -180,6 +180,13 @@ pub enum Expression {
/// This is an Expression::Array
unsorted_cells: Box<Expression>,
},

MinMax {
ty: Type,
op: MinMaxOp,
lhs: Box<Expression>,
rhs: Box<Expression>,
},
}

impl Expression {
Expand Down Expand Up @@ -292,6 +299,7 @@ impl Expression {
Self::ComputeDialogLayoutCells { .. } => {
Type::Array(super::lower_expression::grid_layout_cell_data_ty().into())
}
Self::MinMax { ty, .. } => ty.clone(),
}
}
}
Expand Down Expand Up @@ -374,6 +382,10 @@ macro_rules! visit_impl {
$visitor(roles);
$visitor(unsorted_cells);
}
Expression::MinMax { ty: _, op: _, lhs, rhs } => {
$visitor(lhs);
$visitor(rhs);
}
}
};
}
Expand Down
6 changes: 6 additions & 0 deletions internal/compiler/llr/lower_expression.rs
Expand Up @@ -197,6 +197,12 @@ pub fn lower_expression(
}
tree_Expression::ComputeLayoutInfo(l, o) => compute_layout_info(l, *o, ctx),
tree_Expression::SolveLayout(l, o) => solve_layout(l, *o, ctx),
tree_Expression::MinMax { ty, op, lhs, rhs } => llr_Expression::MinMax {
ty: ty.clone(),
op: *op,
lhs: Box::new(lower_expression(lhs, ctx)),
rhs: Box::new(lower_expression(rhs, ctx)),
},
}
}

Expand Down
1 change: 1 addition & 0 deletions internal/compiler/llr/optim_passes/inline_expressions.rs
Expand Up @@ -54,6 +54,7 @@ fn expression_cost(exp: &Expression, ctx: &EvaluationContext) -> isize {
Expression::LayoutCacheAccess { .. } => PROPERTY_ACCESS_COST,
Expression::BoxLayoutFunction { .. } => return isize::MAX,
Expression::ComputeDialogLayoutCells { .. } => return isize::MAX,
Expression::MinMax { .. } => 10,
};

exp.visit(|e| cost = cost.saturating_add(expression_cost(e, ctx)));
Expand Down
6 changes: 6 additions & 0 deletions internal/compiler/llr/pretty_print.rs
Expand Up @@ -5,6 +5,8 @@ use std::fmt::{Display, Result, Write};

use itertools::Itertools;

use crate::expression_tree::MinMaxOp;

use super::{
EvaluationContext, Expression, ParentCtx, PropertyReference, PublicComponent, SubComponent,
};
Expand Down Expand Up @@ -250,6 +252,10 @@ impl<'a, T> Display for DisplayExpression<'a, T> {
Expression::ComputeDialogLayoutCells { .. } => {
write!(f, "ComputeDialogLayoutCells(TODO)",)
}
Expression::MinMax { ty: _, op, lhs, rhs } => match op {
MinMaxOp::Min => write!(f, "min({}, {})", e(lhs), e(rhs)),
MinMaxOp::Max => write!(f, "max({}, {})", e(lhs), e(rhs)),
},
}
}
}
4 changes: 2 additions & 2 deletions internal/compiler/passes/default_geometry.rs
Expand Up @@ -14,7 +14,7 @@ use std::rc::Rc;

use crate::diagnostics::{BuildDiagnostics, Spanned};
use crate::expression_tree::{
BindingExpression, BuiltinFunction, Expression, NamedReference, Unit,
BindingExpression, BuiltinFunction, Expression, MinMaxOp, NamedReference, Unit,
};
use crate::langtype::{BuiltinElement, DefaultSizeBinding, PropertyLookupResult, Type};
use crate::layout::{implicit_layout_info_call, LayoutConstraints, Orientation};
Expand Down Expand Up @@ -297,7 +297,7 @@ fn make_default_implicit(elem: &ElementRc, property: &str) {
&format!("preferred-{}", property),
)),
Expression::PropertyReference(NamedReference::new(elem, &format!("min-{}", property))),
'>',
MinMaxOp::Max,
);
elem.borrow_mut().set_binding_if_not_set(property.into(), || e);
}
Expand Down
16 changes: 8 additions & 8 deletions internal/compiler/passes/flickable.rs
Expand Up @@ -13,7 +13,7 @@
use std::cell::RefCell;
use std::rc::Rc;

use crate::expression_tree::{BindingExpression, Expression, NamedReference};
use crate::expression_tree::{BindingExpression, Expression, MinMaxOp, NamedReference};
use crate::langtype::{ElementType, NativeClass};
use crate::object_tree::{Component, Element, ElementRc};
use crate::typeregister::TypeRegister;
Expand Down Expand Up @@ -85,7 +85,7 @@ fn create_viewport_element(flickable: &ElementRc, native_empty: &Rc<NativeClass>
}

fn fixup_geometry(flickable_elem: &ElementRc) {
let forward_minmax_of = |prop: &str, op: char| {
let forward_minmax_of = |prop: &str, op: MinMaxOp| {
set_binding_if_not_explicit(flickable_elem, prop, || {
flickable_elem
.borrow()
Expand All @@ -100,12 +100,12 @@ fn fixup_geometry(flickable_elem: &ElementRc) {
};

if !flickable_elem.borrow().bindings.contains_key("height") {
forward_minmax_of("max-height", '<');
forward_minmax_of("preferred-height", '<');
forward_minmax_of("max-height", MinMaxOp::Min);
forward_minmax_of("preferred-height", MinMaxOp::Min);
}
if !flickable_elem.borrow().bindings.contains_key("width") {
forward_minmax_of("max-width", '<');
forward_minmax_of("preferred-width", '<');
forward_minmax_of("max-width", MinMaxOp::Min);
forward_minmax_of("preferred-width", MinMaxOp::Min);
}
set_binding_if_not_explicit(flickable_elem, "viewport-width", || {
Some(
Expand All @@ -119,7 +119,7 @@ fn fixup_geometry(flickable_elem: &ElementRc) {
.map(|x| Expression::PropertyReference(NamedReference::new(x, "min-width")))
.fold(
Expression::PropertyReference(NamedReference::new(flickable_elem, "width")),
|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'),
|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, MinMaxOp::Max),
),
)
});
Expand All @@ -135,7 +135,7 @@ fn fixup_geometry(flickable_elem: &ElementRc) {
.map(|x| Expression::PropertyReference(NamedReference::new(x, "min-height")))
.fold(
Expression::PropertyReference(NamedReference::new(flickable_elem, "height")),
|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'),
|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, MinMaxOp::Max),
),
)
});
Expand Down
6 changes: 3 additions & 3 deletions internal/compiler/passes/lower_tabwidget.rs
Expand Up @@ -9,7 +9,7 @@
//! be further inlined as it may expends to native widget that needs inlining

use crate::diagnostics::BuildDiagnostics;
use crate::expression_tree::{BindingExpression, Expression, NamedReference, Unit};
use crate::expression_tree::{BindingExpression, Expression, MinMaxOp, NamedReference, Unit};
use crate::langtype::{ElementType, Type};
use crate::object_tree::*;
use std::cell::RefCell;
Expand Down Expand Up @@ -167,14 +167,14 @@ fn process_tabwidget(
if let Some(expr) = children
.iter()
.map(|x| Expression::PropertyReference(NamedReference::new(x, "min-width")))
.reduce(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'))
.reduce(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, MinMaxOp::Max))
{
elem.borrow_mut().bindings.insert("content-min-width".into(), RefCell::new(expr.into()));
};
if let Some(expr) = children
.iter()
.map(|x| Expression::PropertyReference(NamedReference::new(x, "min-height")))
.reduce(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'))
.reduce(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, MinMaxOp::Max))
{
elem.borrow_mut().bindings.insert("content-min-height".into(), RefCell::new(expr.into()));
};
Expand Down