Skip to content

Commit 00cc335

Browse files
WIP: constant evaluation for select
1 parent a9e93f9 commit 00cc335

1 file changed

Lines changed: 130 additions & 3 deletions

File tree

naga/src/proc/constant_evaluator.rs

Lines changed: 130 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,24 @@ pub enum ConstantEvaluatorError {
563563
RuntimeExpr,
564564
#[error("Unexpected override-expression")]
565565
OverrideExpr,
566+
#[error("Expected scalars of the same type for reject and accept args., got something else")]
567+
SelectScalarRejectAcceptTypeMismatch,
568+
#[error("Expected boolean expression for condition argument of `select`, got something else")]
569+
SelectScalarConditionNotABool,
570+
#[error(
571+
"Expected vectors of the same component type for reject and accept args., got something else",
572+
)]
573+
SelectVecRejectAcceptTypeMismatch,
574+
#[error("Expected boolean vector for condition arg., got something else")]
575+
SelectConditionNotAVecBool,
576+
#[error(
577+
"Expected same number of vector components between condition, accept, and reject args., got something else",
578+
)]
579+
SelectConditionVecSizeMismatch,
580+
#[error(
581+
"Expected reject and accept args. to be scalars of vectors of the same type, got something else",
582+
)]
583+
SelectAcceptRejectTypeMismatch,
566584
}
567585

568586
impl<'a> ConstantEvaluator<'a> {
@@ -904,9 +922,118 @@ impl<'a> ConstantEvaluator<'a> {
904922
)),
905923
}
906924
}
907-
Expression::Select { .. } => Err(ConstantEvaluatorError::NotImplemented(
908-
"select built-in function".into(),
909-
)),
925+
Expression::Select {
926+
reject,
927+
accept,
928+
condition,
929+
} => {
930+
let arg = |this: &mut Self, expr| {
931+
let expr: &Expression = &this.expressions[expr];
932+
this.try_eval_and_append(expr.clone(), span)
933+
};
934+
935+
let reject = arg(self, reject)?;
936+
let accept = arg(self, accept)?;
937+
let condition = arg(self, condition)?;
938+
939+
let select_single_component =
940+
|this: &mut Self, reject_scalar, reject, accept, condition| {
941+
let accept = this.cast(accept, reject_scalar, span)?;
942+
if condition {
943+
Ok(accept)
944+
} else {
945+
Ok(reject)
946+
}
947+
};
948+
949+
// NOTE: Frontends are on the hook for any conversions between arguments, if the
950+
// language supports it. If types don't match, the buck stops here.
951+
match (&self.expressions[reject], &self.expressions[accept]) {
952+
(&Expression::Literal(reject_lit), &Expression::Literal(accept_lit)) => {
953+
let reject_scalar = reject_lit.scalar();
954+
// if reject_scalar != accept_lit.scalar() {
955+
// return Err(
956+
// ConstantEvaluatorError::SelectScalarRejectAcceptTypeMismatch,
957+
// );
958+
// }
959+
let &Expression::Literal(Literal::Bool(condition)) =
960+
&self.expressions[condition]
961+
else {
962+
return Err(ConstantEvaluatorError::SelectScalarConditionNotABool);
963+
};
964+
select_single_component(self, reject_scalar, reject, accept, condition)
965+
}
966+
(
967+
&Expression::Compose {
968+
ty: reject_ty,
969+
components: ref reject_components,
970+
},
971+
&Expression::Compose {
972+
ty: accept_ty,
973+
components: ref accept_components,
974+
},
975+
) => {
976+
if reject_ty != accept_ty {
977+
return Err(ConstantEvaluatorError::SelectVecRejectAcceptTypeMismatch);
978+
}
979+
let ty = reject_ty;
980+
981+
let ty_deets = |ty| {
982+
let (size, scalar) =
983+
self.types[ty].inner.vector_size_and_scalar().unwrap();
984+
(size.unwrap(), scalar)
985+
};
986+
let (expected_vec_size, _scalar) = ty_deets(ty);
987+
988+
let &Expression::Compose {
989+
ty: condition_ty,
990+
components: ref condition_components,
991+
} = &self.expressions[condition]
992+
else {
993+
return Err(ConstantEvaluatorError::SelectConditionNotAVecBool);
994+
};
995+
996+
{
997+
let (condition_vec_size, condition_scalar) = ty_deets(condition_ty);
998+
if condition_scalar.kind != ScalarKind::Bool {
999+
return Err(ConstantEvaluatorError::SelectConditionNotAVecBool);
1000+
}
1001+
if condition_vec_size != expected_vec_size {
1002+
return Err(ConstantEvaluatorError::SelectConditionVecSizeMismatch);
1003+
}
1004+
}
1005+
1006+
let evaluated = Expression::Compose {
1007+
ty,
1008+
components: reject_components
1009+
.clone()
1010+
.into_iter()
1011+
.zip(accept_components.clone().into_iter())
1012+
.zip(condition_components.clone().into_iter())
1013+
.map(|((reject, accept), condition)| {
1014+
let reject_scalar = match &self.expressions[reject] {
1015+
&Expression::Literal(lit) => lit.scalar(),
1016+
_ => unreachable!(),
1017+
};
1018+
let condition = match &self.expressions[condition] {
1019+
&Expression::Literal(Literal::Bool(condition)) => condition,
1020+
_ => unreachable!(),
1021+
};
1022+
select_single_component(
1023+
self,
1024+
reject_scalar,
1025+
reject,
1026+
accept,
1027+
condition,
1028+
)
1029+
})
1030+
.collect::<Result<_, _>>()?,
1031+
};
1032+
self.register_evaluated_expr(evaluated, span)
1033+
}
1034+
_ => Err(ConstantEvaluatorError::SelectAcceptRejectTypeMismatch),
1035+
}
1036+
}
9101037
Expression::Relational { fun, argument } => {
9111038
let argument = self.check_and_get(argument)?;
9121039
self.relational(fun, argument, span)

0 commit comments

Comments
 (0)