// 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 "paddle/common/enforce.h" #include "paddle/pir/include/core/interface_support.h" #include "paddle/pir/include/core/operation.h" #include "paddle/pir/include/core/utils.h" #include "paddle/pir/include/core/value.h" namespace pir { class Builder; class IrPrinter; class Block; class OpBase { public: explicit OpBase(const Operation *operation = nullptr) : operation_(const_cast(operation)) {} Operation *operation() const { PADDLE_ENFORCE_NOT_NULL( operation_, common::errors::InvalidArgument("Can't use operation() in a null op.")); return operation_; } explicit operator bool() const { return operation_ != nullptr; } operator Operation *() const { return operation(); } Operation *operator->() const { return operation(); } IrContext *ir_context() const { return operation()->ir_context(); } uint32_t num_results() const { return operation()->num_results(); } uint32_t num_operands() const { return operation()->num_operands(); } Block *parent() const { return operation()->GetParent(); } // Attribute related interfaces const AttributeMap &attributes() const { return operation()->attributes(); } Attribute attribute(const std::string &key) const { return operation()->attribute(key); } template T attribute(const std::string &key) const { return operation()->attribute(key); } Value operand_source(uint32_t index) const { return operation()->operand_source(index); } Type operand_type(uint32_t index) const { return operation()->operand_type(index); } Value result(uint32_t index) const { return operation()->result(index); } template T result_type(uint32_t index) const { return operation()->result_type(index); } void VerifySig() {} void VerifyRegion() {} protected: Operation *operation_; // Not owned }; /// /// \brief OpTrait /// template class OpTraitBase : public OpBase { public: using Base = OpTraitBase; explicit OpTraitBase(const Operation *op) : OpBase(op) {} static TypeId GetTraitId() { return TypeId::get(); } static ConcreteTrait dyn_cast(const Operation *op) { if (op && op->HasTrait()) { return ConcreteTrait(op); } return ConcreteTrait(nullptr); } }; /// /// \brief OpInterface /// template class OpInterfaceBase : public OpBase { public: explicit OpInterfaceBase(const Operation *op) : OpBase(op) {} /// /// \brief Accessor for the ID of this interface. /// static TypeId GetInterfaceId() { return TypeId::get(); } /// /// \brief Checking if the given object defines the concrete interface. /// static bool classof(Operation *op) { return op->HasInterface(); } static ConcreteInterface dyn_cast(const Operation *op) { if (op && op->HasInterface()) { return ConcreteInterface( op, op->info().GetInterfaceImpl()); } return ConcreteInterface(nullptr, nullptr); } }; template struct VerifyTraitOrInterface { static void call(Operation *) {} }; template struct VerifyTraitOrInterface()))> { static void call(Operation *op) { T::Verify(op); } }; template class Op : public OpBase { public: using OpBase::OpBase; using TraitList = typename detail::Filter>::Type; using InterfaceList = typename detail::Filter>::Type; // TODO(zhangbopd): Use classof static ConcreteOp dyn_cast(const Operation *op) { if (op && op->info().id() == TypeId::get()) { return ConcreteOp(op); } return ConcreteOp(nullptr); } static bool classof(const Operation *op) { return op && op->info().id() == TypeId::get(); } static std::set interface_set() { return detail::GetInterfaceSet(); } static std::vector GetTraitSet() { return detail::GetTraitSet(); } // Checking that the derived class does not define any member by comparing // its size to an ad-hoc EmptyOp. static constexpr bool HasNoDataMembers() { class EmptyOp : public Op {}; return sizeof(ConcreteOp) == sizeof(EmptyOp); } // Implementation of `VerifySigInvariantsFn` OperationName hook. static void VerifySigInvariants(Operation *op) { static_assert(HasNoDataMembers(), "Op class shouldn't define new data members"); op->dyn_cast().VerifySig(); (void)std::initializer_list{ 0, (VerifyTraitOrInterface::call(op), 0)...}; } static void VerifyRegionInvariants(Operation *op) { static_assert(HasNoDataMembers(), "Op class shouldn't define new data members"); op->dyn_cast().VerifyRegion(); } }; } // namespace pir