support for conditional expressions transforming into interal has-elements expr

This commit is contained in:
Vern Paxson 2024-04-08 18:21:18 -04:00 committed by Tim Wojtulewicz
parent 86d3c932b7
commit 52f506b7ae
2 changed files with 66 additions and 1 deletions

View file

@ -329,6 +329,11 @@ public:
// Reduces the expression to one that can appear as a conditional. // Reduces the expression to one that can appear as a conditional.
ExprPtr ReduceToConditional(Reducer* c, StmtPtr& red_stmt); ExprPtr ReduceToConditional(Reducer* c, StmtPtr& red_stmt);
// Transforms the expression into its form suitable for use in
// a conditional. Only meaningful for expressions that return true
// for WillTransformInConditional().
virtual ExprPtr TransformToConditional(Reducer* c, StmtPtr& red_stmt);
// Reduces the expression to one that can appear as a field // Reduces the expression to one that can appear as a field
// assignment. // assignment.
ExprPtr ReduceToFieldAssignment(Reducer* c, StmtPtr& red_stmt); ExprPtr ReduceToFieldAssignment(Reducer* c, StmtPtr& red_stmt);
@ -806,6 +811,7 @@ public:
bool WillTransform(Reducer* c) const override; bool WillTransform(Reducer* c) const override;
bool WillTransformInConditional(Reducer* c) const override; bool WillTransformInConditional(Reducer* c) const override;
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
ExprPtr TransformToConditional(Reducer* c, StmtPtr& red_stmt) override;
protected: protected:
bool IsTrue(const ExprPtr& e) const; bool IsTrue(const ExprPtr& e) const;

View file

@ -274,6 +274,18 @@ StmtPtr Expr::ReduceToSingletons(Reducer* c) {
} }
ExprPtr Expr::ReduceToConditional(Reducer* c, StmtPtr& red_stmt) { ExprPtr Expr::ReduceToConditional(Reducer* c, StmtPtr& red_stmt) {
if ( WillTransformInConditional(c) ) {
auto new_me = TransformToConditional(c, red_stmt);
// Now that we've transformed, reduce the result for use in a
// conditional.
StmtPtr red_stmt2;
new_me = new_me->ReduceToConditional(c, red_stmt2);
red_stmt = MergeStmts(red_stmt, red_stmt2);
return new_me;
}
switch ( tag ) { switch ( tag ) {
case EXPR_CONST: return ThisPtr(); case EXPR_CONST: return ThisPtr();
@ -355,6 +367,13 @@ ExprPtr Expr::ReduceToConditional(Reducer* c, StmtPtr& red_stmt) {
} }
} }
ExprPtr Expr::TransformToConditional(Reducer* c, StmtPtr& red_stmt) {
// This shouldn't happen since every expression that can return
// true for WillTransformInConditional() should implement this
// method.
reporter->InternalError("Expr::TransformToConditional called");
}
ExprPtr Expr::ReduceToFieldAssignment(Reducer* c, StmtPtr& red_stmt) { ExprPtr Expr::ReduceToFieldAssignment(Reducer* c, StmtPtr& red_stmt) {
if ( ! IsFieldAssignable(this) || tag == EXPR_NAME ) if ( ! IsFieldAssignable(this) || tag == EXPR_NAME )
return ReduceToSingleton(c, red_stmt); return ReduceToSingleton(c, red_stmt);
@ -1291,7 +1310,7 @@ bool CondExpr::IsReduced(Reducer* c) const {
} }
bool CondExpr::HasReducedOps(Reducer* c) const { bool CondExpr::HasReducedOps(Reducer* c) const {
return op1->IsSingleton(c) && op2->IsSingleton(c) && op3->IsSingleton(c) && ! op1->IsConst(); return ! IsMinOrMax(c) && op1->IsSingleton(c) && op2->IsSingleton(c) && op3->IsSingleton(c) && ! op1->IsConst();
} }
bool CondExpr::WillTransform(Reducer* c) const { return ! HasReducedOps(c); } bool CondExpr::WillTransform(Reducer* c) const { return ! HasReducedOps(c); }
@ -1303,6 +1322,16 @@ ExprPtr CondExpr::Reduce(Reducer* c, StmtPtr& red_stmt) {
op3 = c->UpdateExpr(op3); op3 = c->UpdateExpr(op3);
} }
while ( op1->Tag() == EXPR_NOT ) {
op1 = op1->GetOp1();
std::swap(op2, op3);
}
if ( IsMinOrMax(c) ) {
auto res = TransformToMinOrMax();
return res->Reduce(c, red_stmt);
}
StmtPtr op1_red_stmt; StmtPtr op1_red_stmt;
op1 = op1->ReduceToSingleton(c, op1_red_stmt); op1 = op1->ReduceToSingleton(c, op1_red_stmt);
@ -1391,6 +1420,36 @@ StmtPtr CondExpr::ReduceToSingletons(Reducer* c) {
return MergeStmts(red1_stmt, if_else); return MergeStmts(red1_stmt, if_else);
} }
bool CondExpr::IsMinOrMax(Reducer* c) const {
switch ( op1->Tag() ) {
case EXPR_LT:
case EXPR_LE:
case EXPR_GE:
case EXPR_GT: break;
default: return false;
}
auto relop1 = op1->GetOp1();
auto relop2 = op1->GetOp2();
return (same_expr(relop1, op2) && same_expr(relop2, op3)) || (same_expr(relop1, op3) && same_expr(relop2, op2));
}
ExprPtr CondExpr::TransformToMinOrMax() const {
auto relop1 = op1->GetOp1();
auto relop2 = op1->GetOp2();
auto is_min = (op1->Tag() == EXPR_LT || op1->Tag() == EXPR_LE);
if ( same_expr(relop1, op3) )
is_min = ! is_min;
auto built_in = is_min ? ScriptOptBuiltinExpr::MINIMUM : ScriptOptBuiltinExpr::MAXIMUM;
return with_location_of(make_intrusive<ScriptOptBuiltinExpr>(built_in, relop1, relop2), this);
}
ExprPtr RefExpr::Duplicate() { return SetSucc(new RefExpr(op->Duplicate())); } ExprPtr RefExpr::Duplicate() { return SetSucc(new RefExpr(op->Duplicate())); }
bool RefExpr::IsReduced(Reducer* c) const { bool RefExpr::IsReduced(Reducer* c) const {