// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include #include #include #include #include #include #include #include "glog/logging.h" #include "paddle/common/enforce.h" #include "paddle/common/overloaded.h" #include "paddle/pir/include/core/dll_decl.h" #include "paddle/pir/include/core/utils.h" namespace symbol { #define SYMBOL_NOT_IMPLEMENTED \ PADDLE_THROW(common::errors::Unimplemented("Not Implemented")) template struct UnaryDimExpr { explicit UnaryDimExpr(const T& d) : data(std::make_shared(d)) {} struct Data { explicit Data(const T& d) : data(d) {} T data; }; const Data& operator*() const { return *data; } Data& operator*() { return *data; } const Data* operator->() const { return data.get(); } Data* operator->() { return data.get(); } std::shared_ptr data; }; template struct BinaryDimExpr { explicit BinaryDimExpr(const T& l, const T& r) : data(std::make_shared(l, r)) {} struct Data { explicit Data(const T& l, const T& r) : lhs(l), rhs(r) {} T lhs; T rhs; }; const Data& operator*() const { return *data; } Data& operator*() { return *data; } const Data* operator->() const { return data.get(); } Data* operator->() { return data.get(); } std::shared_ptr data; }; template class List final { public: List(const List&) = default; List(List&&) = default; List& operator=(const List&) = default; List& operator=(List&&) = default; using value_type = T; explicit List() : vector_(std::make_shared>()) {} template < typename Arg, std::enable_if_t, List>, bool> = true> explicit List(Arg&& arg) : vector_(std::make_shared>( std::vector{std::forward(arg)})) {} template List(Arg0&& arg0, Arg1&& arg1, Args&&... args) : vector_(std::make_shared>( std::vector{std::forward(arg0), std::forward(arg1), std::forward(args)...})) {} bool operator==(const List& other) const { if (&vector() == &other.vector()) { return true; } return vector() == other.vector(); } bool operator!=(const List& other) const { return !(*this == other); } std::vector& operator*() const { return *vector_; } std::vector* operator->() const { return vector_.get(); } const std::vector& vector() const { return *vector_; } const auto& Get(std::size_t idx) const { return vector_->at(idx); } private: std::shared_ptr> vector_; }; template struct Negative final : public UnaryDimExpr { using UnaryDimExpr::UnaryDimExpr; }; template struct Add final { List operands; }; template struct Mul final { List operands; }; template struct Div final : public BinaryDimExpr { using BinaryDimExpr::BinaryDimExpr; }; template struct Max final { List operands; }; template struct Min final { List operands; }; template struct Broadcast final { List operands; }; template struct Equal final : public BinaryDimExpr { using BinaryDimExpr::BinaryDimExpr; }; template struct Broadcastable final : public BinaryDimExpr { using BinaryDimExpr::BinaryDimExpr; bool operator==(const Broadcastable& other) const { return (this->data->lhs == other.data->lhs && this->data->rhs == other.data->rhs) || (this->data->lhs == other.data->rhs && this->data->rhs == other.data->lhs); } }; class DimExpr; // DimExpr = std::int64_t // | std::string // | Negative DimExpr // | Add DimExpr // | Mul DimExpr // | Div DimExpr // | Max DimExpr // | Min DimExpr // | Broadcast DimExpr using DimExprBase = std::variant, Add, Mul, Div, Max, Min, Broadcast>; class IR_API DimExpr : public DimExprBase { public: using DimExprBase::DimExprBase; template bool isa() const { return std::holds_alternative(*this); } template const T& dyn_cast() const { return std::get(*this); } template bool Has() const { return std::holds_alternative(*this); } template const T& Get() const { return std::get(*this); } const DimExprBase& variant() const { return static_cast(*this); } DEFINE_MATCH_METHOD(); DimExpr operator+(const DimExpr& other) const; DimExpr operator-(const DimExpr& other) const; DimExpr operator*(const DimExpr& other) const; DimExpr operator/(const DimExpr& other) const; bool operator==(const DimExpr& other) const; bool operator!=(const DimExpr& other) const; }; // DimExprConstraint = Equal DimExpr // | Broadcastable DimExpr using DimExprConstraint = std::variant, Broadcastable>; IR_API std::string ToString(const DimExpr& dim_expr); IR_API std::ostream& operator<<(std::ostream&, const DimExpr& dim_expr); IR_API std::ostream& operator<<(std::ostream&, const std::vector& dim_exprs); IR_API std::size_t GetHashValue(const DimExpr& dim_expr); } // namespace symbol namespace std { template <> struct hash { std::size_t operator()(const symbol::DimExpr& dim_expr) const { return symbol::GetHashValue(dim_expr); } }; template <> struct hash> { std::size_t operator()(const std::vector& dim_exprs) const { std::size_t hash_value = 0; const auto hash_func = std::hash(); for (const auto& dim_expr : dim_exprs) { hash_value = pir::detail::hash_combine(hash_value, hash_func(dim_expr)); } return hash_value; } }; template <> struct hash> { std::size_t operator()( const symbol::Broadcastable& broadcastable) const { return pir::detail::hash_combine(GetHashValue(broadcastable.data->lhs), GetHashValue(broadcastable.data->rhs)); } }; } // namespace std