//===- Nodes.h --------------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef MLIR_TOOLS_PDLL_AST_NODES_H_ #define MLIR_TOOLS_PDLL_AST_NODES_H_ #include "mlir/Support/LLVM.h" #include "mlir/Tools/PDLL/AST/Types.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TrailingObjects.h" #include namespace mlir { namespace pdll { namespace ast { class Context; class Decl; class Expr; class NamedAttributeDecl; class OpNameDecl; class VariableDecl; //===----------------------------------------------------------------------===// // Name //===----------------------------------------------------------------------===// /// This class provides a convenient API for interacting with source names. It /// contains a string name as well as the source location for that name. struct Name { static const Name &create(Context &ctx, StringRef name, SMRange location); /// Return the raw string name. StringRef getName() const { return name; } /// Get the location of this name. SMRange getLoc() const { return location; } private: Name() = delete; Name(const Name &) = delete; Name &operator=(const Name &) = delete; Name(StringRef name, SMRange location) : name(name), location(location) {} /// The string name of the decl. StringRef name; /// The location of the decl name. SMRange location; }; //===----------------------------------------------------------------------===// // DeclScope //===----------------------------------------------------------------------===// /// This class represents a scope for named AST decls. A scope determines the /// visibility and lifetime of a named declaration. class DeclScope { public: /// Create a new scope with an optional parent scope. DeclScope(DeclScope *parent = nullptr) : parent(parent) {} /// Return the parent scope of this scope, or nullptr if there is no parent. DeclScope *getParentScope() { return parent; } const DeclScope *getParentScope() const { return parent; } /// Return all of the decls within this scope. auto getDecls() const { return llvm::make_second_range(decls); } /// Add a new decl to the scope. void add(Decl *decl); /// Lookup a decl with the given name starting from this scope. Returns /// nullptr if no decl could be found. Decl *lookup(StringRef name); template T *lookup(StringRef name) { return dyn_cast_or_null(lookup(name)); } const Decl *lookup(StringRef name) const { return const_cast(this)->lookup(name); } template const T *lookup(StringRef name) const { return dyn_cast_or_null(lookup(name)); } private: /// The parent scope, or null if this is a top-level scope. DeclScope *parent; /// The decls defined within this scope. llvm::StringMap decls; }; //===----------------------------------------------------------------------===// // Node //===----------------------------------------------------------------------===// /// This class represents a base AST node. All AST nodes are derived from this /// class, and it contains many of the base functionality for interacting with /// nodes. class Node { public: /// This CRTP class provides several utilies when defining new AST nodes. template class NodeBase : public BaseT { public: using Base = NodeBase; /// Provide type casting support. static bool classof(const Node *node) { return node->getTypeID() == TypeID::get(); } protected: template explicit NodeBase(SMRange loc, Args &&...args) : BaseT(TypeID::get(), loc, std::forward(args)...) {} }; /// Return the type identifier of this node. TypeID getTypeID() const { return typeID; } /// Return the location of this node. SMRange getLoc() const { return loc; } /// Print this node to the given stream. void print(raw_ostream &os) const; /// Walk all of the nodes including, and nested under, this node in pre-order. void walk(function_ref walkFn) const; template ::template arg_t<0>> std::enable_if_t::value> walk(WalkFnT &&walkFn) const { walk([&](const Node *node) { if (const ArgT *derivedNode = dyn_cast(node)) walkFn(derivedNode); }); } protected: Node(TypeID typeID, SMRange loc) : typeID(typeID), loc(loc) {} private: /// A unique type identifier for this node. TypeID typeID; /// The location of this node. SMRange loc; }; //===----------------------------------------------------------------------===// // Stmt //===----------------------------------------------------------------------===// /// This class represents a base AST Statement node. class Stmt : public Node { public: using Node::Node; /// Provide type casting support. static bool classof(const Node *node); }; //===----------------------------------------------------------------------===// // CompoundStmt //===----------------------------------------------------------------------===// /// This statement represents a compound statement, which contains a collection /// of other statements. class CompoundStmt final : public Node::NodeBase, private llvm::TrailingObjects { public: static CompoundStmt *create(Context &ctx, SMRange location, ArrayRef children); /// Return the children of this compound statement. MutableArrayRef getChildren() { return getTrailingObjects(numChildren); } ArrayRef getChildren() const { return getTrailingObjects(numChildren); } ArrayRef::iterator begin() const { return getChildren().begin(); } ArrayRef::iterator end() const { return getChildren().end(); } private: CompoundStmt(SMRange location, unsigned numChildren) : Base(location), numChildren(numChildren) {} /// The number of held children statements. unsigned numChildren; // Allow access to various privates. friend class llvm::TrailingObjects; }; //===----------------------------------------------------------------------===// // LetStmt //===----------------------------------------------------------------------===// /// This statement represents a `let` statement in PDLL. This statement is used /// to define variables. class LetStmt final : public Node::NodeBase { public: static LetStmt *create(Context &ctx, SMRange loc, VariableDecl *varDecl); /// Return the variable defined by this statement. VariableDecl *getVarDecl() const { return varDecl; } private: LetStmt(SMRange loc, VariableDecl *varDecl) : Base(loc), varDecl(varDecl) {} /// The variable defined by this statement. VariableDecl *varDecl; }; //===----------------------------------------------------------------------===// // OpRewriteStmt //===----------------------------------------------------------------------===// /// This class represents a base operation rewrite statement. Operation rewrite /// statements perform a set of transformations on a given root operation. class OpRewriteStmt : public Stmt { public: /// Provide type casting support. static bool classof(const Node *node); /// Return the root operation of this rewrite. Expr *getRootOpExpr() const { return rootOp; } protected: OpRewriteStmt(TypeID typeID, SMRange loc, Expr *rootOp) : Stmt(typeID, loc), rootOp(rootOp) {} protected: /// The root operation being rewritten. Expr *rootOp; }; //===----------------------------------------------------------------------===// // EraseStmt //===----------------------------------------------------------------------===// /// This statement represents the `erase` statement in PDLL. This statement /// erases the given root operation, corresponding roughly to the /// PatternRewriter::eraseOp API. class EraseStmt final : public Node::NodeBase { public: static EraseStmt *create(Context &ctx, SMRange loc, Expr *rootOp); private: EraseStmt(SMRange loc, Expr *rootOp) : Base(loc, rootOp) {} }; //===----------------------------------------------------------------------===// // ReplaceStmt //===----------------------------------------------------------------------===// /// This statement represents the `replace` statement in PDLL. This statement /// replace the given root operation with a set of values, corresponding roughly /// to the PatternRewriter::replaceOp API. class ReplaceStmt final : public Node::NodeBase, private llvm::TrailingObjects { public: static ReplaceStmt *create(Context &ctx, SMRange loc, Expr *rootOp, ArrayRef replExprs); /// Return the replacement values of this statement. MutableArrayRef getReplExprs() { return getTrailingObjects(numReplExprs); } ArrayRef getReplExprs() const { return getTrailingObjects(numReplExprs); } private: ReplaceStmt(SMRange loc, Expr *rootOp, unsigned numReplExprs) : Base(loc, rootOp), numReplExprs(numReplExprs) {} /// The number of replacement values within this statement. unsigned numReplExprs; /// TrailingObject utilities. friend class llvm::TrailingObjects; }; //===----------------------------------------------------------------------===// // RewriteStmt //===----------------------------------------------------------------------===// /// This statement represents an operation rewrite that contains a block of /// nested rewrite commands. This allows for building more complex operation /// rewrites that span across multiple statements, which may be unconnected. class RewriteStmt final : public Node::NodeBase { public: static RewriteStmt *create(Context &ctx, SMRange loc, Expr *rootOp, CompoundStmt *rewriteBody); /// Return the compound rewrite body. CompoundStmt *getRewriteBody() const { return rewriteBody; } private: RewriteStmt(SMRange loc, Expr *rootOp, CompoundStmt *rewriteBody) : Base(loc, rootOp), rewriteBody(rewriteBody) {} /// The body of nested rewriters within this statement. CompoundStmt *rewriteBody; }; //===----------------------------------------------------------------------===// // ReturnStmt //===----------------------------------------------------------------------===// /// This statement represents a return from a "callable" like decl, e.g. a /// Constraint or a Rewrite. class ReturnStmt final : public Node::NodeBase { public: static ReturnStmt *create(Context &ctx, SMRange loc, Expr *resultExpr); /// Return the result expression of this statement. Expr *getResultExpr() { return resultExpr; } const Expr *getResultExpr() const { return resultExpr; } /// Set the result expression of this statement. void setResultExpr(Expr *expr) { resultExpr = expr; } private: ReturnStmt(SMRange loc, Expr *resultExpr) : Base(loc), resultExpr(resultExpr) {} // The result expression of this statement. Expr *resultExpr; }; //===----------------------------------------------------------------------===// // Expr //===----------------------------------------------------------------------===// /// This class represents a base AST Expression node. class Expr : public Stmt { public: /// Return the type of this expression. Type getType() const { return type; } /// Provide type casting support. static bool classof(const Node *node); protected: Expr(TypeID typeID, SMRange loc, Type type) : Stmt(typeID, loc), type(type) {} private: /// The type of this expression. Type type; }; //===----------------------------------------------------------------------===// // AttributeExpr //===----------------------------------------------------------------------===// /// This expression represents a literal MLIR Attribute, and contains the /// textual assembly format of that attribute. class AttributeExpr : public Node::NodeBase { public: static AttributeExpr *create(Context &ctx, SMRange loc, StringRef value); /// Get the raw value of this expression. This is the textual assembly format /// of the MLIR Attribute. StringRef getValue() const { return value; } private: AttributeExpr(Context &ctx, SMRange loc, StringRef value) : Base(loc, AttributeType::get(ctx)), value(value) {} /// The value referenced by this expression. StringRef value; }; //===----------------------------------------------------------------------===// // CallExpr //===----------------------------------------------------------------------===// /// This expression represents a call to a decl, such as a /// UserConstraintDecl/UserRewriteDecl. class CallExpr final : public Node::NodeBase, private llvm::TrailingObjects { public: static CallExpr *create(Context &ctx, SMRange loc, Expr *callable, ArrayRef arguments, Type resultType, bool isNegated = false); /// Return the callable of this call. Expr *getCallableExpr() const { return callable; } /// Return the arguments of this call. MutableArrayRef getArguments() { return getTrailingObjects(numArgs); } ArrayRef getArguments() const { return getTrailingObjects(numArgs); } /// Returns whether the result of this call is to be negated. bool getIsNegated() const { return isNegated; } private: CallExpr(SMRange loc, Type type, Expr *callable, unsigned numArgs, bool isNegated) : Base(loc, type), callable(callable), numArgs(numArgs), isNegated(isNegated) {} /// The callable of this call. Expr *callable; /// The number of arguments of the call. unsigned numArgs; /// TrailingObject utilities. friend llvm::TrailingObjects; // Is the result of this call to be negated. bool isNegated; }; //===----------------------------------------------------------------------===// // DeclRefExpr //===----------------------------------------------------------------------===// /// This expression represents a reference to a Decl node. class DeclRefExpr : public Node::NodeBase { public: static DeclRefExpr *create(Context &ctx, SMRange loc, Decl *decl, Type type); /// Get the decl referenced by this expression. Decl *getDecl() const { return decl; } private: DeclRefExpr(SMRange loc, Decl *decl, Type type) : Base(loc, type), decl(decl) {} /// The decl referenced by this expression. Decl *decl; }; //===----------------------------------------------------------------------===// // MemberAccessExpr //===----------------------------------------------------------------------===// /// This expression represents a named member or field access of a given parent /// expression. class MemberAccessExpr : public Node::NodeBase { public: static MemberAccessExpr *create(Context &ctx, SMRange loc, const Expr *parentExpr, StringRef memberName, Type type); /// Get the parent expression of this access. const Expr *getParentExpr() const { return parentExpr; } /// Return the name of the member being accessed. StringRef getMemberName() const { return memberName; } private: MemberAccessExpr(SMRange loc, const Expr *parentExpr, StringRef memberName, Type type) : Base(loc, type), parentExpr(parentExpr), memberName(memberName) {} /// The parent expression of this access. const Expr *parentExpr; /// The name of the member being accessed from the parent. StringRef memberName; }; //===----------------------------------------------------------------------===// // AllResultsMemberAccessExpr //===----------------------------------------------------------------------===// /// This class represents an instance of MemberAccessExpr that references all /// results of an operation. class AllResultsMemberAccessExpr : public MemberAccessExpr { public: /// Return the member name used for the "all-results" access. static StringRef getMemberName() { return "$results"; } static AllResultsMemberAccessExpr *create(Context &ctx, SMRange loc, const Expr *parentExpr, Type type) { return cast( MemberAccessExpr::create(ctx, loc, parentExpr, getMemberName(), type)); } /// Provide type casting support. static bool classof(const Node *node) { const MemberAccessExpr *memAccess = dyn_cast(node); return memAccess && memAccess->getMemberName() == getMemberName(); } }; //===----------------------------------------------------------------------===// // OperationExpr //===----------------------------------------------------------------------===// /// This expression represents the structural form of an MLIR Operation. It /// represents either an input operation to match, or an operation to create /// within a rewrite. class OperationExpr final : public Node::NodeBase, private llvm::TrailingObjects { public: static OperationExpr *create(Context &ctx, SMRange loc, const ods::Operation *odsOp, const OpNameDecl *nameDecl, ArrayRef operands, ArrayRef resultTypes, ArrayRef attributes); /// Return the name of the operation, or std::nullopt if there isn't one. std::optional getName() const; /// Return the declaration of the operation name. const OpNameDecl *getNameDecl() const { return nameDecl; } /// Return the location of the name of the operation expression, or an invalid /// location if there isn't a name. SMRange getNameLoc() const { return nameLoc; } /// Return the operands of this operation. MutableArrayRef getOperands() { return getTrailingObjects(numOperands); } ArrayRef getOperands() const { return getTrailingObjects(numOperands); } /// Return the result types of this operation. MutableArrayRef getResultTypes() { return {getTrailingObjects() + numOperands, numResultTypes}; } MutableArrayRef getResultTypes() const { return const_cast(this)->getResultTypes(); } /// Return the attributes of this operation. MutableArrayRef getAttributes() { return getTrailingObjects(numAttributes); } ArrayRef getAttributes() const { return getTrailingObjects(numAttributes); } private: OperationExpr(SMRange loc, Type type, const OpNameDecl *nameDecl, unsigned numOperands, unsigned numResultTypes, unsigned numAttributes, SMRange nameLoc) : Base(loc, type), nameDecl(nameDecl), numOperands(numOperands), numResultTypes(numResultTypes), numAttributes(numAttributes), nameLoc(nameLoc) {} /// The name decl of this expression. const OpNameDecl *nameDecl; /// The number of operands, result types, and attributes of the operation. unsigned numOperands, numResultTypes, numAttributes; /// The location of the operation name in the expression if it has a name. SMRange nameLoc; /// TrailingObject utilities. friend llvm::TrailingObjects; size_t numTrailingObjects(OverloadToken) const { return numOperands + numResultTypes; } }; //===----------------------------------------------------------------------===// // RangeExpr //===----------------------------------------------------------------------===// /// This expression builds a range from a set of element values (which may be /// ranges themselves). class RangeExpr final : public Node::NodeBase, private llvm::TrailingObjects { public: static RangeExpr *create(Context &ctx, SMRange loc, ArrayRef elements, RangeType type); /// Return the element expressions of this range. MutableArrayRef getElements() { return getTrailingObjects(numElements); } ArrayRef getElements() const { return getTrailingObjects(numElements); } /// Return the range result type of this expression. RangeType getType() const { return mlir::cast(Base::getType()); } private: RangeExpr(SMRange loc, RangeType type, unsigned numElements) : Base(loc, type), numElements(numElements) {} /// The number of element values for this range. unsigned numElements; /// TrailingObject utilities. friend class llvm::TrailingObjects; }; //===----------------------------------------------------------------------===// // TupleExpr //===----------------------------------------------------------------------===// /// This expression builds a tuple from a set of element values. class TupleExpr final : public Node::NodeBase, private llvm::TrailingObjects { public: static TupleExpr *create(Context &ctx, SMRange loc, ArrayRef elements, ArrayRef elementNames); /// Return the element expressions of this tuple. MutableArrayRef getElements() { return getTrailingObjects(getType().size()); } ArrayRef getElements() const { return getTrailingObjects(getType().size()); } /// Return the tuple result type of this expression. TupleType getType() const { return mlir::cast(Base::getType()); } private: TupleExpr(SMRange loc, TupleType type) : Base(loc, type) {} /// TrailingObject utilities. friend class llvm::TrailingObjects; }; //===----------------------------------------------------------------------===// // TypeExpr //===----------------------------------------------------------------------===// /// This expression represents a literal MLIR Type, and contains the textual /// assembly format of that type. class TypeExpr : public Node::NodeBase { public: static TypeExpr *create(Context &ctx, SMRange loc, StringRef value); /// Get the raw value of this expression. This is the textual assembly format /// of the MLIR Type. StringRef getValue() const { return value; } private: TypeExpr(Context &ctx, SMRange loc, StringRef value) : Base(loc, TypeType::get(ctx)), value(value) {} /// The value referenced by this expression. StringRef value; }; //===----------------------------------------------------------------------===// // Decl //===----------------------------------------------------------------------===// /// This class represents the base Decl node. class Decl : public Node { public: /// Return the name of the decl, or nullptr if it doesn't have one. const Name *getName() const { return name; } /// Provide type casting support. static bool classof(const Node *node); /// Set the documentation comment for this decl. void setDocComment(Context &ctx, StringRef comment); /// Return the documentation comment attached to this decl if it has been set. /// Otherwise, returns std::nullopt. std::optional getDocComment() const { return docComment; } protected: Decl(TypeID typeID, SMRange loc, const Name *name = nullptr) : Node(typeID, loc), name(name) {} private: /// The name of the decl. This is optional for some decls, such as /// PatternDecl. const Name *name; /// The documentation comment attached to this decl. Defaults to std::nullopt /// if the comment is unset/unknown. std::optional docComment; }; //===----------------------------------------------------------------------===// // ConstraintDecl //===----------------------------------------------------------------------===// /// This class represents the base of all AST Constraint decls. Constraints /// apply matcher conditions to, and define the type of PDLL variables. class ConstraintDecl : public Decl { public: /// Provide type casting support. static bool classof(const Node *node); protected: ConstraintDecl(TypeID typeID, SMRange loc, const Name *name = nullptr) : Decl(typeID, loc, name) {} }; /// This class represents a reference to a constraint, and contains a constraint /// and the location of the reference. struct ConstraintRef { ConstraintRef(const ConstraintDecl *constraint, SMRange refLoc) : constraint(constraint), referenceLoc(refLoc) {} explicit ConstraintRef(const ConstraintDecl *constraint) : ConstraintRef(constraint, constraint->getLoc()) {} const ConstraintDecl *constraint; SMRange referenceLoc; }; //===----------------------------------------------------------------------===// // CoreConstraintDecl //===----------------------------------------------------------------------===// /// This class represents the base of all "core" constraints. Core constraints /// are those that generally represent a concrete IR construct, such as /// `Type`s or `Value`s. class CoreConstraintDecl : public ConstraintDecl { public: /// Provide type casting support. static bool classof(const Node *node); protected: CoreConstraintDecl(TypeID typeID, SMRange loc, const Name *name = nullptr) : ConstraintDecl(typeID, loc, name) {} }; //===----------------------------------------------------------------------===// // AttrConstraintDecl //===----------------------------------------------------------------------===// /// The class represents an Attribute constraint, and constrains a variable to /// be an Attribute. class AttrConstraintDecl : public Node::NodeBase { public: static AttrConstraintDecl *create(Context &ctx, SMRange loc, Expr *typeExpr = nullptr); /// Return the optional type the attribute is constrained to. Expr *getTypeExpr() { return typeExpr; } const Expr *getTypeExpr() const { return typeExpr; } protected: AttrConstraintDecl(SMRange loc, Expr *typeExpr) : Base(loc), typeExpr(typeExpr) {} /// An optional type that the attribute is constrained to. Expr *typeExpr; }; //===----------------------------------------------------------------------===// // OpConstraintDecl //===----------------------------------------------------------------------===// /// The class represents an Operation constraint, and constrains a variable to /// be an Operation. class OpConstraintDecl : public Node::NodeBase { public: static OpConstraintDecl *create(Context &ctx, SMRange loc, const OpNameDecl *nameDecl = nullptr); /// Return the name of the operation, or std::nullopt if there isn't one. std::optional getName() const; /// Return the declaration of the operation name. const OpNameDecl *getNameDecl() const { return nameDecl; } protected: explicit OpConstraintDecl(SMRange loc, const OpNameDecl *nameDecl) : Base(loc), nameDecl(nameDecl) {} /// The operation name of this constraint. const OpNameDecl *nameDecl; }; //===----------------------------------------------------------------------===// // TypeConstraintDecl //===----------------------------------------------------------------------===// /// The class represents a Type constraint, and constrains a variable to be a /// Type. class TypeConstraintDecl : public Node::NodeBase { public: static TypeConstraintDecl *create(Context &ctx, SMRange loc); protected: using Base::Base; }; //===----------------------------------------------------------------------===// // TypeRangeConstraintDecl //===----------------------------------------------------------------------===// /// The class represents a TypeRange constraint, and constrains a variable to be /// a TypeRange. class TypeRangeConstraintDecl : public Node::NodeBase { public: static TypeRangeConstraintDecl *create(Context &ctx, SMRange loc); protected: using Base::Base; }; //===----------------------------------------------------------------------===// // ValueConstraintDecl //===----------------------------------------------------------------------===// /// The class represents a Value constraint, and constrains a variable to be a /// Value. class ValueConstraintDecl : public Node::NodeBase { public: static ValueConstraintDecl *create(Context &ctx, SMRange loc, Expr *typeExpr); /// Return the optional type the value is constrained to. Expr *getTypeExpr() { return typeExpr; } const Expr *getTypeExpr() const { return typeExpr; } protected: ValueConstraintDecl(SMRange loc, Expr *typeExpr) : Base(loc), typeExpr(typeExpr) {} /// An optional type that the value is constrained to. Expr *typeExpr; }; //===----------------------------------------------------------------------===// // ValueRangeConstraintDecl //===----------------------------------------------------------------------===// /// The class represents a ValueRange constraint, and constrains a variable to /// be a ValueRange. class ValueRangeConstraintDecl : public Node::NodeBase { public: static ValueRangeConstraintDecl *create(Context &ctx, SMRange loc, Expr *typeExpr = nullptr); /// Return the optional type the value range is constrained to. Expr *getTypeExpr() { return typeExpr; } const Expr *getTypeExpr() const { return typeExpr; } protected: ValueRangeConstraintDecl(SMRange loc, Expr *typeExpr) : Base(loc), typeExpr(typeExpr) {} /// An optional type that the value range is constrained to. Expr *typeExpr; }; //===----------------------------------------------------------------------===// // UserConstraintDecl //===----------------------------------------------------------------------===// /// This decl represents a user defined constraint. This is either: /// * an imported native constraint /// - Similar to an external function declaration. This is a native /// constraint defined externally, and imported into PDLL via a /// declaration. /// * a native constraint defined in PDLL /// - This is a native constraint, i.e. a constraint whose implementation is /// defined in C++(or potentially some other non-PDLL language). The /// implementation of this constraint is specified as a string code block /// in PDLL. /// * a PDLL constraint /// - This is a constraint which is defined using only PDLL constructs. class UserConstraintDecl final : public Node::NodeBase, llvm::TrailingObjects { public: /// Create a native constraint with the given optional code block. static UserConstraintDecl * createNative(Context &ctx, const Name &name, ArrayRef inputs, ArrayRef results, std::optional codeBlock, Type resultType, ArrayRef nativeInputTypes = {}) { return createImpl(ctx, name, inputs, nativeInputTypes, results, codeBlock, /*body=*/nullptr, resultType); } /// Create a PDLL constraint with the given body. static UserConstraintDecl *createPDLL(Context &ctx, const Name &name, ArrayRef inputs, ArrayRef results, const CompoundStmt *body, Type resultType) { return createImpl(ctx, name, inputs, /*nativeInputTypes=*/{}, results, /*codeBlock=*/std::nullopt, body, resultType); } /// Return the name of the constraint. const Name &getName() const { return *Decl::getName(); } /// Return the input arguments of this constraint. MutableArrayRef getInputs() { return getTrailingObjects(numInputs); } ArrayRef getInputs() const { return getTrailingObjects(numInputs); } /// Return the explicit native type to use for the given input. Returns /// std::nullopt if no explicit type was set. std::optional getNativeInputType(unsigned index) const; /// Return the explicit results of the constraint declaration. May be empty, /// even if the constraint has results (e.g. in the case of inferred results). MutableArrayRef getResults() { return {getTrailingObjects() + numInputs, numResults}; } ArrayRef getResults() const { return const_cast(this)->getResults(); } /// Return the optional code block of this constraint, if this is a native /// constraint with a provided implementation. std::optional getCodeBlock() const { return codeBlock; } /// Return the body of this constraint if this constraint is a PDLL /// constraint, otherwise returns nullptr. const CompoundStmt *getBody() const { return constraintBody; } /// Return the result type of this constraint. Type getResultType() const { return resultType; } /// Returns true if this constraint is external. bool isExternal() const { return !constraintBody && !codeBlock; } private: /// Create either a PDLL constraint or a native constraint with the given /// components. static UserConstraintDecl *createImpl(Context &ctx, const Name &name, ArrayRef inputs, ArrayRef nativeInputTypes, ArrayRef results, std::optional codeBlock, const CompoundStmt *body, Type resultType); UserConstraintDecl(const Name &name, unsigned numInputs, bool hasNativeInputTypes, unsigned numResults, std::optional codeBlock, const CompoundStmt *body, Type resultType) : Base(name.getLoc(), &name), numInputs(numInputs), numResults(numResults), codeBlock(codeBlock), constraintBody(body), resultType(resultType), hasNativeInputTypes(hasNativeInputTypes) {} /// The number of inputs to this constraint. unsigned numInputs; /// The number of explicit results to this constraint. unsigned numResults; /// The optional code block of this constraint. std::optional codeBlock; /// The optional body of this constraint. const CompoundStmt *constraintBody; /// The result type of the constraint. Type resultType; /// Flag indicating if this constraint has explicit native input types. bool hasNativeInputTypes; /// Allow access to various internals. friend llvm::TrailingObjects; size_t numTrailingObjects(OverloadToken) const { return numInputs + numResults; } }; //===----------------------------------------------------------------------===// // NamedAttributeDecl //===----------------------------------------------------------------------===// /// This Decl represents a NamedAttribute, and contains a string name and /// attribute value. class NamedAttributeDecl : public Node::NodeBase { public: static NamedAttributeDecl *create(Context &ctx, const Name &name, Expr *value); /// Return the name of the attribute. const Name &getName() const { return *Decl::getName(); } /// Return value of the attribute. Expr *getValue() const { return value; } private: NamedAttributeDecl(const Name &name, Expr *value) : Base(name.getLoc(), &name), value(value) {} /// The value of the attribute. Expr *value; }; //===----------------------------------------------------------------------===// // OpNameDecl //===----------------------------------------------------------------------===// /// This Decl represents an OperationName. class OpNameDecl : public Node::NodeBase { public: static OpNameDecl *create(Context &ctx, const Name &name); static OpNameDecl *create(Context &ctx, SMRange loc); /// Return the name of this operation, or std::nullopt if the name is unknown. std::optional getName() const { const Name *name = Decl::getName(); return name ? std::optional(name->getName()) : std::nullopt; } private: explicit OpNameDecl(const Name &name) : Base(name.getLoc(), &name) {} explicit OpNameDecl(SMRange loc) : Base(loc) {} }; //===----------------------------------------------------------------------===// // PatternDecl //===----------------------------------------------------------------------===// /// This Decl represents a single Pattern. class PatternDecl : public Node::NodeBase { public: static PatternDecl *create(Context &ctx, SMRange location, const Name *name, std::optional benefit, bool hasBoundedRecursion, const CompoundStmt *body); /// Return the benefit of this pattern if specified, or std::nullopt. std::optional getBenefit() const { return benefit; } /// Return if this pattern has bounded rewrite recursion. bool hasBoundedRewriteRecursion() const { return hasBoundedRecursion; } /// Return the body of this pattern. const CompoundStmt *getBody() const { return patternBody; } /// Return the root rewrite statement of this pattern. const OpRewriteStmt *getRootRewriteStmt() const { return cast(patternBody->getChildren().back()); } private: PatternDecl(SMRange loc, const Name *name, std::optional benefit, bool hasBoundedRecursion, const CompoundStmt *body) : Base(loc, name), benefit(benefit), hasBoundedRecursion(hasBoundedRecursion), patternBody(body) {} /// The benefit of the pattern if it was explicitly specified, std::nullopt /// otherwise. std::optional benefit; /// If the pattern has properly bounded rewrite recursion or not. bool hasBoundedRecursion; /// The compound statement representing the body of the pattern. const CompoundStmt *patternBody; }; //===----------------------------------------------------------------------===// // UserRewriteDecl //===----------------------------------------------------------------------===// /// This decl represents a user defined rewrite. This is either: /// * an imported native rewrite /// - Similar to an external function declaration. This is a native /// rewrite defined externally, and imported into PDLL via a declaration. /// * a native rewrite defined in PDLL /// - This is a native rewrite, i.e. a rewrite whose implementation is /// defined in C++(or potentially some other non-PDLL language). The /// implementation of this rewrite is specified as a string code block /// in PDLL. /// * a PDLL rewrite /// - This is a rewrite which is defined using only PDLL constructs. class UserRewriteDecl final : public Node::NodeBase, llvm::TrailingObjects { public: /// Create a native rewrite with the given optional code block. static UserRewriteDecl *createNative(Context &ctx, const Name &name, ArrayRef inputs, ArrayRef results, std::optional codeBlock, Type resultType) { return createImpl(ctx, name, inputs, results, codeBlock, /*body=*/nullptr, resultType); } /// Create a PDLL rewrite with the given body. static UserRewriteDecl *createPDLL(Context &ctx, const Name &name, ArrayRef inputs, ArrayRef results, const CompoundStmt *body, Type resultType) { return createImpl(ctx, name, inputs, results, /*codeBlock=*/std::nullopt, body, resultType); } /// Return the name of the rewrite. const Name &getName() const { return *Decl::getName(); } /// Return the input arguments of this rewrite. MutableArrayRef getInputs() { return getTrailingObjects(numInputs); } ArrayRef getInputs() const { return getTrailingObjects(numInputs); } /// Return the explicit results of the rewrite declaration. May be empty, /// even if the rewrite has results (e.g. in the case of inferred results). MutableArrayRef getResults() { return {getTrailingObjects() + numInputs, numResults}; } ArrayRef getResults() const { return const_cast(this)->getResults(); } /// Return the optional code block of this rewrite, if this is a native /// rewrite with a provided implementation. std::optional getCodeBlock() const { return codeBlock; } /// Return the body of this rewrite if this rewrite is a PDLL rewrite, /// otherwise returns nullptr. const CompoundStmt *getBody() const { return rewriteBody; } /// Return the result type of this rewrite. Type getResultType() const { return resultType; } /// Returns true if this rewrite is external. bool isExternal() const { return !rewriteBody && !codeBlock; } private: /// Create either a PDLL rewrite or a native rewrite with the given /// components. static UserRewriteDecl *createImpl(Context &ctx, const Name &name, ArrayRef inputs, ArrayRef results, std::optional codeBlock, const CompoundStmt *body, Type resultType); UserRewriteDecl(const Name &name, unsigned numInputs, unsigned numResults, std::optional codeBlock, const CompoundStmt *body, Type resultType) : Base(name.getLoc(), &name), numInputs(numInputs), numResults(numResults), codeBlock(codeBlock), rewriteBody(body), resultType(resultType) {} /// The number of inputs to this rewrite. unsigned numInputs; /// The number of explicit results to this rewrite. unsigned numResults; /// The optional code block of this rewrite. std::optional codeBlock; /// The optional body of this rewrite. const CompoundStmt *rewriteBody; /// The result type of the rewrite. Type resultType; /// Allow access to various internals. friend llvm::TrailingObjects; }; //===----------------------------------------------------------------------===// // CallableDecl //===----------------------------------------------------------------------===// /// This decl represents a shared interface for all callable decls. class CallableDecl : public Decl { public: /// Return the callable type of this decl. StringRef getCallableType() const { if (isa(this)) return "constraint"; assert(isa(this) && "unknown callable type"); return "rewrite"; } /// Return the inputs of this decl. ArrayRef getInputs() const { if (const auto *cst = dyn_cast(this)) return cst->getInputs(); return cast(this)->getInputs(); } /// Return the result type of this decl. Type getResultType() const { if (const auto *cst = dyn_cast(this)) return cst->getResultType(); return cast(this)->getResultType(); } /// Return the explicit results of the declaration. Note that these may be /// empty, even if the callable has results (e.g. in the case of inferred /// results). ArrayRef getResults() const { if (const auto *cst = dyn_cast(this)) return cst->getResults(); return cast(this)->getResults(); } /// Return the optional code block of this callable, if this is a native /// callable with a provided implementation. std::optional getCodeBlock() const { if (const auto *cst = dyn_cast(this)) return cst->getCodeBlock(); return cast(this)->getCodeBlock(); } /// Support LLVM type casting facilities. static bool classof(const Node *decl) { return isa(decl); } }; //===----------------------------------------------------------------------===// // VariableDecl //===----------------------------------------------------------------------===// /// This Decl represents the definition of a PDLL variable. class VariableDecl final : public Node::NodeBase, private llvm::TrailingObjects { public: static VariableDecl *create(Context &ctx, const Name &name, Type type, Expr *initExpr, ArrayRef constraints); /// Return the constraints of this variable. MutableArrayRef getConstraints() { return getTrailingObjects(numConstraints); } ArrayRef getConstraints() const { return getTrailingObjects(numConstraints); } /// Return the initializer expression of this statement, or nullptr if there /// was no initializer. Expr *getInitExpr() const { return initExpr; } /// Return the name of the decl. const Name &getName() const { return *Decl::getName(); } /// Return the type of the decl. Type getType() const { return type; } private: VariableDecl(const Name &name, Type type, Expr *initExpr, unsigned numConstraints) : Base(name.getLoc(), &name), type(type), initExpr(initExpr), numConstraints(numConstraints) {} /// The type of the variable. Type type; /// The optional initializer expression of this statement. Expr *initExpr; /// The number of constraints attached to this variable. unsigned numConstraints; /// Allow access to various internals. friend llvm::TrailingObjects; }; //===----------------------------------------------------------------------===// // Module //===----------------------------------------------------------------------===// /// This class represents a top-level AST module. class Module final : public Node::NodeBase, private llvm::TrailingObjects { public: static Module *create(Context &ctx, SMLoc loc, ArrayRef children); /// Return the children of this module. MutableArrayRef getChildren() { return getTrailingObjects(numChildren); } ArrayRef getChildren() const { return getTrailingObjects(numChildren); } private: Module(SMLoc loc, unsigned numChildren) : Base(SMRange{loc, loc}), numChildren(numChildren) {} /// The number of decls held by this module. unsigned numChildren; /// Allow access to various internals. friend llvm::TrailingObjects; }; //===----------------------------------------------------------------------===// // Defered Method Definitions //===----------------------------------------------------------------------===// inline bool Decl::classof(const Node *node) { return isa(node); } inline bool ConstraintDecl::classof(const Node *node) { return isa(node); } inline bool CoreConstraintDecl::classof(const Node *node) { return isa(node); } inline bool Expr::classof(const Node *node) { return isa(node); } inline bool OpRewriteStmt::classof(const Node *node) { return isa(node); } inline bool Stmt::classof(const Node *node) { return isa(node); } } // namespace ast } // namespace pdll } // namespace mlir #endif // MLIR_TOOLS_PDLL_AST_NODES_H_