// Copyright Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT #include #include namespace rocRoller { namespace Expression { template concept CIntegral = std::integral && !std::same_as; template concept CConstant = CIntegral || std::floating_point; template struct AssociativeBinary { template ExpressionPtr operator()(RHS rhs) { if(std::holds_alternative(*m_lhs)) { auto lhs_op = std::get(*m_lhs); bool eval_lhs = evaluationTimes(lhs_op.lhs)[EvaluationTime::Translate]; bool eval_rhs = evaluationTimes(lhs_op.rhs)[EvaluationTime::Translate]; OP operation; if(CCommutativeBinary && eval_lhs) { operation.lhs = simplify(std::make_shared(OP{lhs_op.lhs, literal(rhs)})); operation.rhs = lhs_op.rhs; } else { operation.lhs = lhs_op.lhs; operation.rhs = simplify(std::make_shared(OP{lhs_op.rhs, literal(rhs)})); } return std::make_shared(operation); } return nullptr; } ExpressionPtr call(ExpressionPtr lhs, CommandArgumentValue rhs) { m_lhs = lhs; return visit(*this, rhs); } private: ExpressionPtr m_lhs; }; template struct CollectedShift { template ExpressionPtr operator()(RHS rhs) { if(std::holds_alternative(*m_lhs)) { auto lhs_op = std::get(*m_lhs); bool eval_rhs = evaluationTimes(lhs_op.rhs)[EvaluationTime::Translate]; if(eval_rhs) { OP operation; operation.lhs = lhs_op.lhs; operation.rhs = simplify(std::make_shared(Add{lhs_op.rhs, literal(rhs)})); return std::make_shared(operation); } } return nullptr; } ExpressionPtr call(ExpressionPtr lhs, CommandArgumentValue rhs) { m_lhs = lhs; return visit(*this, rhs); } private: ExpressionPtr m_lhs; }; struct AssociativeExpressionVisitor { template ExpressionPtr operator()(Expr const& expr) const { auto lhs = call(expr.lhs); auto rhs = call(expr.rhs); bool eval_lhs = evaluationTimes(lhs)[EvaluationTime::Translate]; bool eval_rhs = evaluationTimes(rhs)[EvaluationTime::Translate]; auto associativeBinary = AssociativeBinary(); ExpressionPtr rv; if(eval_lhs && eval_rhs) { rv = literal(evaluate(std::make_shared(Expr{lhs, rhs}))); } else if(CCommutativeBinary && eval_lhs) { rv = associativeBinary.call(rhs, evaluate(lhs)); } else if(eval_rhs) { rv = associativeBinary.call(lhs, evaluate(rhs)); } if(rv != nullptr) { copyComment(rv, expr); return rv; } return std::make_shared(Expr({lhs, rhs, expr.comment})); } template ExpressionPtr operator()(Expr const& expr) const { Expr cpy = expr; cpy.arg = call(expr.arg); return std::make_shared(cpy); } template requires(!CAssociativeBinary && !CShift) ExpressionPtr operator()(Expr const& expr) const { Expr cpy = expr; cpy.lhs = call(expr.lhs); cpy.rhs = call(expr.rhs); return std::make_shared(cpy); } ExpressionPtr operator()(ScaledMatrixMultiply const& expr) const { ScaledMatrixMultiply cpy = expr; cpy.matA = call(expr.matA); cpy.matB = call(expr.matB); cpy.matC = call(expr.matC); cpy.scaleA = call(expr.scaleA); cpy.scaleB = call(expr.scaleB); return std::make_shared(cpy); } template ExpressionPtr operator()(Expr const& expr) const { Expr cpy = expr; cpy.lhs = call(expr.lhs); cpy.r1hs = call(expr.r1hs); cpy.r2hs = call(expr.r2hs); return std::make_shared(cpy); } template ExpressionPtr operator()(Expr const& expr) const { auto cpy = expr; std::ranges::for_each(cpy.operands, [this](auto& op) { op = call(op); }); return std::make_shared(std::move(cpy)); } template ExpressionPtr operator()(Expr const& expr) const { auto lhs = call(expr.lhs); auto rhs = call(expr.rhs); bool eval_lhs = evaluationTimes(lhs)[EvaluationTime::Translate]; bool eval_rhs = evaluationTimes(rhs)[EvaluationTime::Translate]; auto collectedShift = CollectedShift(); ExpressionPtr rv; if(eval_lhs && eval_rhs) { rv = literal(evaluate(std::make_shared(Expr{lhs, rhs}))); } else if(eval_rhs) { rv = collectedShift.call(lhs, evaluate(rhs)); } if(rv != nullptr) { copyComment(rv, expr); return rv; } return std::make_shared(Expr({lhs, rhs, expr.comment})); } template ExpressionPtr operator()(Value const& expr) const { return std::make_shared(expr); } ExpressionPtr call(ExpressionPtr expr) const { if(!expr) return expr; auto rv = std::visit(*this, *expr); return rv; } }; ExpressionPtr fuseAssociative(ExpressionPtr expr) { auto visitor = AssociativeExpressionVisitor(); return visitor.call(expr); } } }