Skip to content

Commit 7c221a7

Browse files
committed
[mlir][Symbol] Change Symbol from a Trait into an OpInterface.
This provides a much cleaner interface into Symbols, and allows for users to start injecting op-specific information. For example, derived op can now inject when a symbol can be discarded if use_empty. This would let us drop unused external functions, which generally have public visibility. This revision also adds a new `extraTraitClassDeclaration` field to ODS OpInterface to allow for injecting declarations into the trait class that gets attached to the operations. Differential Revision: https://reviews.llvm.org/D78522
1 parent 21acc06 commit 7c221a7

File tree

20 files changed

+233
-140
lines changed

20 files changed

+233
-140
lines changed

flang/include/flang/Optimizer/Dialect/FIROps.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef FIR_DIALECT_FIR_OPS
1515
#define FIR_DIALECT_FIR_OPS
1616

17+
include "mlir/IR/SymbolInterfaces.td"
1718
include "mlir/Interfaces/ControlFlowInterfaces.td"
1819
include "mlir/Interfaces/SideEffects.td"
1920

mlir/include/mlir/Dialect/GPU/GPUOps.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
include "mlir/Dialect/GPU/GPUBase.td"
1717
include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
18+
include "mlir/IR/SymbolInterfaces.td"
1819
include "mlir/Interfaces/SideEffects.td"
1920

2021
// Type constraint accepting standard integers, indices and wrapped LLVM integer

mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define LLVMIR_OPS
1515

1616
include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
17+
include "mlir/IR/SymbolInterfaces.td"
1718
include "mlir/Interfaces/ControlFlowInterfaces.td"
1819
include "mlir/Interfaces/SideEffects.td"
1920

mlir/include/mlir/Dialect/SPIRV/SPIRVStructureOps.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define SPIRV_STRUCTURE_OPS
1717

1818
include "mlir/Dialect/SPIRV/SPIRVBase.td"
19+
include "mlir/IR/SymbolInterfaces.td"
1920
include "mlir/Interfaces/CallInterfaces.td"
2021
include "mlir/Interfaces/SideEffects.td"
2122

mlir/include/mlir/IR/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,8 @@ set(LLVM_TARGET_DEFINITIONS OpAsmInterface.td)
22
mlir_tablegen(OpAsmInterface.h.inc -gen-op-interface-decls)
33
mlir_tablegen(OpAsmInterface.cpp.inc -gen-op-interface-defs)
44
add_public_tablegen_target(MLIROpAsmInterfacesIncGen)
5+
6+
set(LLVM_TARGET_DEFINITIONS SymbolInterfaces.td)
7+
mlir_tablegen(SymbolInterfaces.h.inc -gen-op-interface-decls)
8+
mlir_tablegen(SymbolInterfaces.cpp.inc -gen-op-interface-defs)
9+
add_public_tablegen_target(MLIRSymbolInterfacesIncGen)

mlir/include/mlir/IR/Function.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,10 @@ namespace mlir {
3030
/// implicitly capture global values, and all external references must use
3131
/// Function arguments or attributes that establish a symbolic connection(e.g.
3232
/// symbols referenced by name via a string attribute).
33-
class FuncOp
34-
: public Op<FuncOp, OpTrait::ZeroOperands, OpTrait::ZeroResult,
35-
OpTrait::IsIsolatedFromAbove, OpTrait::Symbol,
36-
OpTrait::FunctionLike, OpTrait::AutomaticAllocationScope,
37-
CallableOpInterface::Trait> {
33+
class FuncOp : public Op<FuncOp, OpTrait::ZeroOperands, OpTrait::ZeroResult,
34+
OpTrait::IsIsolatedFromAbove, OpTrait::FunctionLike,
35+
OpTrait::AutomaticAllocationScope,
36+
CallableOpInterface::Trait, SymbolOpInterface::Trait> {
3837
public:
3938
using Op::Op;
4039
using Op::print;

mlir/include/mlir/IR/Module.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ class ModuleOp
3131
: public Op<
3232
ModuleOp, OpTrait::ZeroOperands, OpTrait::ZeroResult,
3333
OpTrait::IsIsolatedFromAbove, OpTrait::SymbolTable,
34-
OpTrait::SingleBlockImplicitTerminator<ModuleTerminatorOp>::Impl> {
34+
OpTrait::SingleBlockImplicitTerminator<ModuleTerminatorOp>::Impl,
35+
SymbolOpInterface::Trait> {
3536
public:
3637
using Op::Op;
3738
using Op::print;
@@ -95,6 +96,13 @@ class ModuleOp
9596
insertPt = Block::iterator(body->getTerminator());
9697
body->getOperations().insert(insertPt, op);
9798
}
99+
100+
//===--------------------------------------------------------------------===//
101+
// SymbolOpInterface Methods
102+
//===--------------------------------------------------------------------===//
103+
104+
/// A ModuleOp may optionally define a symbol.
105+
bool isOptionalSymbol() { return true; }
98106
};
99107

100108
/// The ModuleTerminatorOp is a special terminator operation for the body of a

mlir/include/mlir/IR/OpBase.td

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,10 +1658,6 @@ def SameOperandsElementType : NativeOpTrait<"SameOperandsElementType">;
16581658
// Op has the same operand and result element type (or type itself, if scalar).
16591659
def SameOperandsAndResultElementType :
16601660
NativeOpTrait<"SameOperandsAndResultElementType">;
1661-
// Op is a symbol.
1662-
def Symbol : NativeOpTrait<"Symbol">;
1663-
// Op defines a symbol table.
1664-
def SymbolTable : NativeOpTrait<"SymbolTable">;
16651661
// Op is a terminator.
16661662
def Terminator : NativeOpTrait<"IsTerminator">;
16671663

@@ -1721,6 +1717,10 @@ class OpInterfaceTrait<string name, code verifyBody = [{}]> : NativeOpTrait<"">
17211717
// Specify the body of the verification function. `$_op` will be replaced with
17221718
// the operation being verified.
17231719
code verify = verifyBody;
1720+
1721+
// An optional code block containing extra declarations to place in the
1722+
// interface trait declaration.
1723+
code extraTraitClassDeclaration = "";
17241724
}
17251725

17261726
// This class represents a single, optionally static, interface method.

mlir/include/mlir/IR/OpDefinition.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,7 @@ class OpInterface : public Op<ConcreteType> {
13591359
public:
13601360
using Concept = typename Traits::Concept;
13611361
template <typename T> using Model = typename Traits::template Model<T>;
1362+
using Base = OpInterface<ConcreteType, Traits>;
13621363

13631364
OpInterface(Operation *op = nullptr)
13641365
: Op<ConcreteType>(op), impl(op ? getInterfaceFor(op) : nullptr) {
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
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+
17+
include "mlir/IR/OpBase.td"
18+
19+
//===----------------------------------------------------------------------===//
20+
// SymbolOpInterface
21+
//===----------------------------------------------------------------------===//
22+
23+
def 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+
31+
let methods = [
32+
InterfaceMethod<"Returns the name of this symbol.",
33+
"StringRef", "getName", (ins), [{
34+
// Don't rely on the trait implementation as optional symbol operations
35+
// may override this.
36+
return mlir::SymbolTable::getSymbolName(op);
37+
}], /*defaultImplementation=*/[{
38+
return mlir::SymbolTable::getSymbolName(this->getOperation());
39+
}]
40+
>,
41+
InterfaceMethod<"Sets the name of this symbol.",
42+
"void", "setName", (ins "StringRef":$name), [{}],
43+
/*defaultImplementation=*/[{
44+
this->getOperation()->setAttr(
45+
mlir::SymbolTable::getSymbolAttrName(),
46+
StringAttr::get(name, this->getOperation()->getContext()));
47+
}]
48+
>,
49+
InterfaceMethod<"Gets the visibility of this symbol.",
50+
"mlir::SymbolTable::Visibility", "getVisibility", (ins), [{}],
51+
/*defaultImplementation=*/[{
52+
return mlir::SymbolTable::getSymbolVisibility(this->getOperation());
53+
}]
54+
>,
55+
InterfaceMethod<"Sets the visibility of this symbol.",
56+
"void", "setVisibility", (ins "mlir::SymbolTable::Visibility":$vis), [{}],
57+
/*defaultImplementation=*/[{
58+
mlir::SymbolTable::setSymbolVisibility(this->getOperation(), vis);
59+
}]
60+
>,
61+
InterfaceMethod<[{
62+
Get all of the uses of the current symbol that are nested within the
63+
given operation 'from'.
64+
Note: See mlir::SymbolTable::getSymbolUses for more details.
65+
}],
66+
"Optional<::mlir::SymbolTable::UseRange>", "getSymbolUses",
67+
(ins "Operation *":$from), [{}],
68+
/*defaultImplementation=*/[{
69+
return ::mlir::SymbolTable::getSymbolUses(this->getOperation(), from);
70+
}]
71+
>,
72+
InterfaceMethod<[{
73+
Return if the current symbol is known to have no uses that are nested
74+
within the given operation 'from'.
75+
Note: See mlir::SymbolTable::symbolKnownUseEmpty for more details.
76+
}],
77+
"bool", "symbolKnownUseEmpty", (ins "Operation *":$from), [{}],
78+
/*defaultImplementation=*/[{
79+
return ::mlir::SymbolTable::symbolKnownUseEmpty(this->getOperation(),
80+
from);
81+
}]
82+
>,
83+
InterfaceMethod<[{
84+
Attempt to replace all uses of the current symbol with the provided
85+
symbol 'newSymbol' that are nested within the given operation 'from'.
86+
Note: See mlir::SymbolTable::replaceAllSymbolUses for more details.
87+
}],
88+
"LogicalResult", "replaceAllSymbolUses", (ins "StringRef":$newSymbol,
89+
"Operation *":$from), [{}],
90+
/*defaultImplementation=*/[{
91+
return ::mlir::SymbolTable::replaceAllSymbolUses(this->getOperation(),
92+
newSymbol, from);
93+
}]
94+
>,
95+
InterfaceMethod<[{
96+
Returns true if this operation optionally defines a symbol based on the
97+
presence of the symbol name.
98+
}],
99+
"bool", "isOptionalSymbol", (ins), [{}],
100+
/*defaultImplementation=*/[{ return false; }]
101+
>,
102+
InterfaceMethod<[{
103+
Returns true if this operation can be discarded if it has no remaining
104+
symbol uses.
105+
}],
106+
"bool", "canDiscardOnUseEmpty", (ins), [{}],
107+
/*defaultImplementation=*/[{
108+
// By default, base this on the visibility alone. A symbol can be
109+
// discarded as long as it is not public. Only public symbols may be
110+
// visible from outside of the IR.
111+
return getVisibility() != ::mlir::SymbolTable::Visibility::Public;
112+
}]
113+
>,
114+
];
115+
116+
let verify = [{
117+
// If this is an optional symbol, bail out early if possible.
118+
auto concreteOp = cast<ConcreteOp>($_op);
119+
if (concreteOp.isOptionalSymbol()) {
120+
if(!concreteOp.getAttr(::mlir::SymbolTable::getSymbolAttrName()))
121+
return success();
122+
}
123+
return ::mlir::detail::verifySymbol($_op);
124+
}];
125+
126+
let extraClassDeclaration = [{
127+
using Visibility = mlir::SymbolTable::Visibility;
128+
129+
/// Custom classof that handles the case where the symbol is optional.
130+
static bool classof(Operation *op) {
131+
return Base::classof(op)
132+
&& op->getAttr(::mlir::SymbolTable::getSymbolAttrName());
133+
}
134+
135+
/// Returns true if this symbol has nested visibility.
136+
bool isNested() { return getVisibility() == Visibility::Nested; }
137+
/// Returns true if this symbol has private visibility.
138+
bool isPrivate() { return getVisibility() == Visibility::Private; }
139+
/// Returns true if this symbol has public visibility.
140+
bool isPublic() { return getVisibility() == Visibility::Public; }
141+
}];
142+
143+
let extraTraitClassDeclaration = [{
144+
using Visibility = mlir::SymbolTable::Visibility;
145+
}];
146+
}
147+
148+
//===----------------------------------------------------------------------===//
149+
// Symbol Traits
150+
//===----------------------------------------------------------------------===//
151+
152+
// Op defines a symbol table.
153+
def SymbolTable : NativeOpTrait<"SymbolTable">;
154+
155+
#endif // MLIR_IR_SYMBOLINTERFACES

0 commit comments

Comments
 (0)