diff --git a/src/Expr.cc b/src/Expr.cc index fb91b0b108..32445ccd69 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -4377,6 +4377,12 @@ bool ListExpr::IsPure() const { return true; } +bool ListExpr::HasConstantOps() const { + loop_over_list(exprs, i) if ( exprs[i]->Tag() != EXPR_CONST ) return false; + + return true; +} + ValPtr ListExpr::Eval(Frame* f) const { std::vector evs; diff --git a/src/Expr.h b/src/Expr.h index c83fbcd843..da1f2e13a3 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -1273,6 +1273,10 @@ public: // Optimization-related: ExprPtr Duplicate() override; + bool IsReduced(Reducer* c) const override; + bool WillTransform(Reducer* c) const override; + ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; + const std::vector& Map() const { return map; } protected: @@ -1362,7 +1366,9 @@ public: // Optimization-related: ExprPtr Duplicate() override; + bool IsReduced(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override; + ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; protected: ValPtr Fold(Val* v1, Val* v2) const override; @@ -1485,6 +1491,9 @@ public: // True if the entire list represents pure values. bool IsPure() const override; + // True if the entire list represents constant values. + bool HasConstantOps() const; + ValPtr Eval(Frame* f) const override; TypePtr InitType() const override; diff --git a/src/script_opt/Expr.cc b/src/script_opt/Expr.cc index e7e4070834..14f3717ea6 100644 --- a/src/script_opt/Expr.cc +++ b/src/script_opt/Expr.cc @@ -83,6 +83,11 @@ const RecordCoerceExpr* Expr::AsRecordCoerceExpr() const { return (const RecordCoerceExpr*)this; } +RecordConstructorExpr* Expr::AsRecordConstructorExpr() { + CHECK_TAG(tag, EXPR_RECORD_CONSTRUCTOR, "ExprVal::AsRecordConstructorExpr", expr_name) + return (RecordConstructorExpr*)this; +} + const RecordConstructorExpr* Expr::AsRecordConstructorExpr() const { CHECK_TAG(tag, EXPR_RECORD_CONSTRUCTOR, "ExprVal::AsRecordConstructorExpr", expr_name) return (const RecordConstructorExpr*)this; @@ -502,6 +507,11 @@ ExprPtr BinaryExpr::Reduce(Reducer* c, StmtPtr& red_stmt) { red_stmt = MergeStmts(red_stmt, std::move(red2_stmt)); auto op1_fold_val = op1->FoldVal(); + + if ( ! op1_fold_val && op1->Tag() == EXPR_LIST && op1->AsListExpr()->HasConstantOps() ) + // We can turn the list into a ListVal. + op1_fold_val = op1->Eval(nullptr); + auto op2_fold_val = op2->FoldVal(); if ( op1_fold_val && op2_fold_val ) { auto fold = Fold(op1_fold_val.get(), op2_fold_val.get()); @@ -1909,6 +1919,27 @@ ExprPtr RecordCoerceExpr::Duplicate() { return SetSucc(new RecordCoerceExpr(op_dup, GetType())); } +bool RecordCoerceExpr::IsReduced(Reducer* c) const { + if ( WillTransform(c) ) + return NonReduced(this); + + return UnaryExpr::IsReduced(c); +} + +bool RecordCoerceExpr::WillTransform(Reducer* c) const { return op->Tag() == EXPR_RECORD_CONSTRUCTOR; } + +ExprPtr RecordCoerceExpr::Reduce(Reducer* c, StmtPtr& red_stmt) { + if ( WillTransform(c) ) { + auto rt = cast_intrusive(type); + auto rc_op = op->AsRecordConstructorExpr(); + auto known_constr = make_intrusive(rt, rc_op->Op()); + auto red_e = known_constr->Reduce(c, red_stmt); + return TransformMe(std::move(red_e), c, red_stmt); + } + + return UnaryExpr::Reduce(c, red_stmt); +} + ExprPtr TableCoerceExpr::Duplicate() { auto op_dup = op->Duplicate(); return SetSucc(new TableCoerceExpr(op_dup, GetType())); @@ -1979,8 +2010,22 @@ ExprPtr InExpr::Duplicate() { return SetSucc(new InExpr(op1_d, op2_d)); } +bool InExpr::IsReduced(Reducer* c) const { + if ( op2->Tag() == EXPR_SET_CONSTRUCTOR && op2->GetOp1()->AsListExpr()->HasConstantOps() ) + return NonReduced(this); + + return BinaryExpr::IsReduced(c); +} + bool InExpr::HasReducedOps(Reducer* c) const { return op1->HasReducedOps(c) && op2->IsSingleton(c); } +ExprPtr InExpr::Reduce(Reducer* c, StmtPtr& red_stmt) { + if ( op2->Tag() == EXPR_SET_CONSTRUCTOR && op2->GetOp1()->AsListExpr()->HasConstantOps() ) + op2 = make_intrusive(op2->Eval(nullptr)); + + return BinaryExpr::Reduce(c, red_stmt); +} + ExprPtr CallExpr::Duplicate() { auto func_d = func->Duplicate(); auto args_d = args->Duplicate()->AsListExprPtr(); diff --git a/src/script_opt/ZAM/AM-Opt.cc b/src/script_opt/ZAM/AM-Opt.cc index 4cdd035e27..deb5fbbf69 100644 --- a/src/script_opt/ZAM/AM-Opt.cc +++ b/src/script_opt/ZAM/AM-Opt.cc @@ -228,6 +228,14 @@ bool ZAMCompiler::PruneUnused() { continue; } + if ( i == insts1.size() - 1 && inst->op == OP_RETURN_X ) { + // A non-value return at the very end of the body + // doesn't actually do anything. + did_prune = true; + KillInst(i); + continue; + } + if ( inst->IsLoad() && ! VarIsUsed(inst->v1) ) { did_prune = true; KillInst(i);