1//===- SymbolInterfaces.td - Interfaces for symbol ops -----*- tablegen -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains a set of interfaces and traits that can be used to define
10// properties of symbol and symbol table operations.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef MLIR_IR_SYMBOLINTERFACES
15#define MLIR_IR_SYMBOLINTERFACES
16
17include "mlir/IR/OpBase.td"
18
19//===----------------------------------------------------------------------===//
20// SymbolOpInterface
21//===----------------------------------------------------------------------===//
22
23def Symbol : OpInterface<"SymbolOpInterface"> {
24  let description = [{
25    This interface describes an operation that may define a `Symbol`. A `Symbol`
26    operation resides immediately within a region that defines a `SymbolTable`.
27    See [Symbols and SymbolTables](SymbolsAndSymbolTables.md) for more details
28    and constraints on `Symbol` operations.
29  }];
30  let cppNamespace = "::mlir";
31
32  let methods = [
33    InterfaceMethod<"Returns the name of this symbol.",
34      "StringRef", "getName", (ins), [{
35        // Don't rely on the trait implementation as optional symbol operations
36        // may override this.
37        return mlir::SymbolTable::getSymbolName($_op);
38      }], /*defaultImplementation=*/[{
39        return mlir::SymbolTable::getSymbolName(this->getOperation());
40      }]
41    >,
42    InterfaceMethod<"Sets the name of this symbol.",
43      "void", "setName", (ins "StringRef":$name), [{}],
44      /*defaultImplementation=*/[{
45        this->getOperation()->setAttr(
46            mlir::SymbolTable::getSymbolAttrName(),
47            StringAttr::get(name, this->getOperation()->getContext()));
48      }]
49    >,
50    InterfaceMethod<"Gets the visibility of this symbol.",
51      "mlir::SymbolTable::Visibility", "getVisibility", (ins), [{}],
52      /*defaultImplementation=*/[{
53        return mlir::SymbolTable::getSymbolVisibility(this->getOperation());
54      }]
55    >,
56    InterfaceMethod<"Returns true if this symbol has nested visibility.",
57      "bool", "isNested", (ins),  [{}],
58      /*defaultImplementation=*/[{
59        return getVisibility() == mlir::SymbolTable::Visibility::Nested;
60      }]
61    >,
62    InterfaceMethod<"Returns true if this symbol has private visibility.",
63      "bool", "isPrivate", (ins),  [{}],
64      /*defaultImplementation=*/[{
65        return getVisibility() == mlir::SymbolTable::Visibility::Private;
66      }]
67    >,
68    InterfaceMethod<"Returns true if this symbol has public visibility.",
69      "bool", "isPublic", (ins),  [{}],
70      /*defaultImplementation=*/[{
71        return getVisibility() == mlir::SymbolTable::Visibility::Public;
72      }]
73    >,
74    InterfaceMethod<"Sets the visibility of this symbol.",
75      "void", "setVisibility", (ins "mlir::SymbolTable::Visibility":$vis), [{}],
76      /*defaultImplementation=*/[{
77        mlir::SymbolTable::setSymbolVisibility(this->getOperation(), vis);
78      }]
79    >,
80    InterfaceMethod<"Sets the visibility of this symbol to be nested.",
81      "void", "setNested", (ins),  [{}],
82      /*defaultImplementation=*/[{
83        setVisibility(mlir::SymbolTable::Visibility::Nested);
84      }]
85    >,
86    InterfaceMethod<"Sets the visibility of this symbol to be private.",
87      "void", "setPrivate", (ins),  [{}],
88      /*defaultImplementation=*/[{
89        setVisibility(mlir::SymbolTable::Visibility::Private);
90      }]
91    >,
92    InterfaceMethod<"Sets the visibility of this symbol to be public.",
93      "void", "setPublic", (ins),  [{}],
94      /*defaultImplementation=*/[{
95        setVisibility(mlir::SymbolTable::Visibility::Public);
96      }]
97    >,
98    InterfaceMethod<[{
99        Get all of the uses of the current symbol that are nested within the
100        given operation 'from'.
101        Note: See mlir::SymbolTable::getSymbolUses for more details.
102      }],
103      "Optional<::mlir::SymbolTable::UseRange>", "getSymbolUses",
104      (ins "Operation *":$from), [{}],
105      /*defaultImplementation=*/[{
106        return ::mlir::SymbolTable::getSymbolUses(this->getOperation(), from);
107      }]
108    >,
109    InterfaceMethod<[{
110        Return if the current symbol is known to have no uses that are nested
111        within the given operation 'from'.
112        Note: See mlir::SymbolTable::symbolKnownUseEmpty for more details.
113      }],
114      "bool", "symbolKnownUseEmpty", (ins "Operation *":$from), [{}],
115      /*defaultImplementation=*/[{
116        return ::mlir::SymbolTable::symbolKnownUseEmpty(this->getOperation(),
117                                                        from);
118      }]
119    >,
120    InterfaceMethod<[{
121        Attempt to replace all uses of the current symbol with the provided
122        symbol 'newSymbol' that are nested within the given operation 'from'.
123        Note: See mlir::SymbolTable::replaceAllSymbolUses for more details.
124      }],
125      "LogicalResult", "replaceAllSymbolUses", (ins "StringRef":$newSymbol,
126                                                    "Operation *":$from), [{}],
127      /*defaultImplementation=*/[{
128        return ::mlir::SymbolTable::replaceAllSymbolUses(this->getOperation(),
129                                                         newSymbol, from);
130      }]
131    >,
132    InterfaceMethod<[{
133        Returns true if this operation optionally defines a symbol based on the
134        presence of the symbol name.
135      }],
136      "bool", "isOptionalSymbol", (ins), [{}],
137      /*defaultImplementation=*/[{ return false; }]
138    >,
139    InterfaceMethod<[{
140        Returns true if this operation can be discarded if it has no remaining
141        symbol uses.
142      }],
143      "bool", "canDiscardOnUseEmpty", (ins), [{}],
144      /*defaultImplementation=*/[{
145        // By default, base this on the visibility alone. A symbol can be
146        // discarded as long as it is not public. Only public symbols may be
147        // visible from outside of the IR.
148        return getVisibility() != ::mlir::SymbolTable::Visibility::Public;
149      }]
150    >,
151    InterfaceMethod<[{
152        Returns true if this operation is a declaration of a symbol (as opposed
153        to a definition).
154      }],
155      "bool", "isDeclaration", (ins), [{}],
156      /*defaultImplementation=*/[{
157        // By default, assume that the operation defines a symbol.
158        return false;
159      }]
160    >,
161  ];
162
163  let verify = [{
164    // If this is an optional symbol, bail out early if possible.
165    auto concreteOp = cast<ConcreteOp>($_op);
166    if (concreteOp.isOptionalSymbol()) {
167      if(!concreteOp.getAttr(::mlir::SymbolTable::getSymbolAttrName()))
168        return success();
169    }
170    if (::mlir::failed(::mlir::detail::verifySymbol($_op)))
171      return ::mlir::failure();
172    if (concreteOp.isDeclaration() && concreteOp.isPublic())
173      return concreteOp.emitOpError("symbol declaration cannot have public "
174             "visibility");
175    return success();
176  }];
177
178  let extraClassDeclaration = [{
179    /// Custom classof that handles the case where the symbol is optional.
180    static bool classof(Operation *op) {
181      auto *concept = getInterfaceFor(op);
182      if (!concept)
183        return false;
184      return !concept->isOptionalSymbol(op) ||
185             op->getAttr(::mlir::SymbolTable::getSymbolAttrName());
186    }
187  }];
188
189  let extraTraitClassDeclaration = [{
190    using Visibility = mlir::SymbolTable::Visibility;
191  }];
192}
193
194//===----------------------------------------------------------------------===//
195// SymbolUserOpInterface
196//===----------------------------------------------------------------------===//
197
198def SymbolUserOpInterface : OpInterface<"SymbolUserOpInterface"> {
199  let description = [{
200    This interface describes an operation that may use a `Symbol`. This
201    interface allows for users of symbols to hook into verification and other
202    symbol related utilities that are either costly or otherwise disallowed
203    within a traditional operation.
204  }];
205  let cppNamespace = "::mlir";
206
207  let methods = [
208    InterfaceMethod<"Verify the symbol uses held by this operation.",
209      "LogicalResult", "verifySymbolUses",
210      (ins "::mlir::SymbolTableCollection &":$symbolTable)
211    >,
212  ];
213}
214
215//===----------------------------------------------------------------------===//
216// Symbol Traits
217//===----------------------------------------------------------------------===//
218
219// Op defines a symbol table.
220def SymbolTable : NativeOpTrait<"SymbolTable">;
221
222#endif // MLIR_IR_SYMBOLINTERFACES
223