diff --git a/mlir/include/mlir/Interfaces/SideEffectInterfaces.td b/mlir/include/mlir/Interfaces/SideEffectInterfaceBase.td copy from mlir/include/mlir/Interfaces/SideEffectInterfaces.td copy to mlir/include/mlir/Interfaces/SideEffectInterfaceBase.td --- a/mlir/include/mlir/Interfaces/SideEffectInterfaces.td +++ b/mlir/include/mlir/Interfaces/SideEffectInterfaceBase.td @@ -1,4 +1,4 @@ -//===-- SideEffectInterfaces.td - Side Effect Interfaces ------------*- tablegen -*-===// +//===-- SideEffectInterfaceBase.td - Side Effect Base ------*- tablegen -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,13 +6,14 @@ // //===----------------------------------------------------------------------===// // -// This file contains a set of interfaces that can be used to define information -// about what effects are applied by an operation. +// This file contains base class definitions for side effect interfaces, i.e. +// the customizable interfaces that provide information about which effects are +// applied by an operation. // //===----------------------------------------------------------------------===// -#ifndef MLIR_INTERFACES_SIDEEFFECTS -#define MLIR_INTERFACES_SIDEEFFECTS +#ifndef MLIR_INTERFACES_SIDEEFFECTS_BASE +#define MLIR_INTERFACES_SIDEEFFECTS_BASE include "mlir/IR/OpBase.td" @@ -162,70 +163,4 @@ list effects = staticEffects; } -//===----------------------------------------------------------------------===// -// MemoryEffects -//===----------------------------------------------------------------------===// - -// This def represents the definition for the memory effects interface. Users -// should generally not use this directly, and should instead use -// `MemoryEffects`. -def MemoryEffectsOpInterface - : EffectOpInterfaceBase<"MemoryEffectOpInterface", - "::mlir::MemoryEffects::Effect"> { - let description = [{ - An interface used to query information about the memory effects applied by - an operation. - }]; - let cppNamespace = "::mlir"; -} - -// The base class for defining specific memory effects. -class MemoryEffect - : SideEffect; - -// This class represents the trait for memory effects that may be placed on -// operations. -class MemoryEffects effects = []> - : SideEffectsTraitBase; - -//===----------------------------------------------------------------------===// -// Effects - -// The following effect indicates that the operation allocates from some -// resource. An 'allocate' effect implies only allocation of the resource, and -// not any visible mutation or dereference. -class MemAlloc - : MemoryEffect<"MemoryEffects::Allocate", resource>; -def MemAlloc : MemAlloc; - -// The following effect indicates that the operation frees some resource that -// has been allocated. A 'free' effect implies only de-allocation of the -// resource, and not any visible allocation, mutation or dereference. -class MemFree - : MemoryEffect<"MemoryEffects::Free", resource>; -def MemFree : MemFree; - -// The following effect indicates that the operation reads from some -// resource. A 'read' effect implies only dereferencing of the resource, and -// not any visible mutation. -class MemRead - : MemoryEffect<"MemoryEffects::Read", resource>; -def MemRead : MemRead; - -// The following effect indicates that the operation writes to some -// resource. A 'write' effect implies only mutating a resource, and not any -// visible dereference or read. -class MemWrite - : MemoryEffect<"MemoryEffects::Write", resource>; -def MemWrite : MemWrite; - -//===----------------------------------------------------------------------===// -// Effect Traits -//===----------------------------------------------------------------------===// - -// Op has no side effect. -def NoSideEffect : MemoryEffects<[]>; -// Op has recursively computed side effects. -def RecursiveSideEffects : NativeOpTrait<"HasRecursiveSideEffects">; - -#endif // MLIR_INTERFACES_SIDEEFFECTS +#endif // MLIR_INTERFACES_SIDEEFFECTS_BASE diff --git a/mlir/include/mlir/Interfaces/SideEffectInterfaces.h b/mlir/include/mlir/Interfaces/SideEffectInterfaces.h --- a/mlir/include/mlir/Interfaces/SideEffectInterfaces.h +++ b/mlir/include/mlir/Interfaces/SideEffectInterfaces.h @@ -131,8 +131,9 @@ /// This class represents a specific instance of an effect. It contains the /// effect being applied, a resource that corresponds to where the effect is -/// applied, and an optional value(either operand, result, or region entry -/// argument) that the effect is applied to. +/// applied, an optional value (either operand, result, or region entry +/// argument) that the effect is applied to, and an optional parameters +/// attribute further specifying the details of the effect. template class EffectInstance { public: EffectInstance(EffectT *effect, Resource *resource = DefaultResource::get()) @@ -140,6 +141,13 @@ EffectInstance(EffectT *effect, Value value, Resource *resource = DefaultResource::get()) : effect(effect), resource(resource), value(value) {} + EffectInstance(EffectT *effect, Attribute parameters, + Resource *resource = DefaultResource::get()) + : effect(effect), resource(resource), parameters(parameters) {} + EffectInstance(EffectT *effect, Value value, Attribute parameters, + Resource *resource = DefaultResource::get()) + : effect(effect), resource(resource), value(value), + parameters(parameters) {} /// Return the effect being applied. EffectT *getEffect() const { return effect; } @@ -151,6 +159,9 @@ /// Return the resource that the effect applies to. Resource *getResource() const { return resource; } + /// Return the parameters of the effect, if any. + Attribute getParameters() const { return parameters; } + private: /// The specific effect being applied. EffectT *effect; @@ -160,6 +171,11 @@ /// The value that the effect applies to. This is optionally null. Value value; + + /// Additional parameters of the effect instance. An attribute is used for + /// type-safe structured storage and context-based uniquing. Concrete effects + /// can use this at their convenience. This is optionally null. + Attribute parameters; }; } // namespace SideEffects diff --git a/mlir/include/mlir/Interfaces/SideEffectInterfaces.td b/mlir/include/mlir/Interfaces/SideEffectInterfaces.td --- a/mlir/include/mlir/Interfaces/SideEffectInterfaces.td +++ b/mlir/include/mlir/Interfaces/SideEffectInterfaces.td @@ -1,4 +1,4 @@ -//===-- SideEffectInterfaces.td - Side Effect Interfaces ------------*- tablegen -*-===// +//===-- SideEffectInterfaces.td - Side Effect Interfaces ---*- tablegen -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -14,153 +14,7 @@ #ifndef MLIR_INTERFACES_SIDEEFFECTS #define MLIR_INTERFACES_SIDEEFFECTS -include "mlir/IR/OpBase.td" - -//===----------------------------------------------------------------------===// -// Resource Bindings -//===----------------------------------------------------------------------===// - -// A generic resource that can be attached to a general base side effect. -class Resource { - /// The resource that the associated effect is being applied to. - string name = resourceName; -} - -// An intrinsic resource that lives in the ::mlir::SideEffects namespace. -class IntrinsicResource : - Resource { -} - -// A link to the DefaultResource class. -def DefaultResource : IntrinsicResource<"DefaultResource">; -// A link to the AutomaticAllocationScopeResource class. -def AutomaticAllocationScopeResource : - IntrinsicResource<"AutomaticAllocationScopeResource">; - -//===----------------------------------------------------------------------===// -// EffectOpInterface -//===----------------------------------------------------------------------===// - -// A base interface used to query information about the side effects applied to -// an operation. This template class takes the name of the derived interface -// class, as well as the name of the base effect class. -class EffectOpInterfaceBase - : OpInterface { - let methods = [ - InterfaceMethod<[{ - Collects all of the operation's effects into `effects`. - }], - "void", "getEffects", - (ins "SmallVectorImpl<::mlir::SideEffects::EffectInstance<" - # baseEffect # ">> &":$effects) - >, - ]; - - let extraClassDeclaration = [{ - /// Collect all of the effect instances that correspond to the given - /// `Effect` and place them in 'effects'. - template void getEffects( - SmallVectorImpl<::mlir::SideEffects::EffectInstance< - }] # baseEffect # [{>> &effects) { - getEffects(effects); - llvm::erase_if(effects, [&](auto &it) { - return !llvm::isa(it.getEffect()); - }); - } - - /// Returns true if this operation exhibits the given effect. - template bool hasEffect() { - SmallVector, 4> effects; - getEffects(effects); - return llvm::any_of(effects, [](const auto &it) { - return llvm::isa(it.getEffect()); - }); - } - - /// Returns true if this operation only has the given effect. - template bool onlyHasEffect() { - SmallVector, 4> effects; - getEffects(effects); - return !effects.empty() && llvm::all_of(effects, [](const auto &it) { - return isa(it.getEffect()); - }); - } - - /// Returns true if this operation has no effects. - bool hasNoEffect() { - SmallVector<::mlir::SideEffects::EffectInstance<}] # baseEffect # [{>, 4> effects; - getEffects(effects); - return effects.empty(); - } - - /// Returns true if the given operation has no effects for this interface. - static bool hasNoEffect(Operation *op) { - if (auto interface = dyn_cast<}] # name # [{>(op)) - return interface.hasNoEffect(); - return op->hasTrait<::mlir::OpTrait::HasRecursiveSideEffects>(); - } - - /// Collect all of the effect instances that operate on the provided value - /// and place them in 'effects'. - void getEffectsOnValue(::mlir::Value value, - llvm::SmallVectorImpl<::mlir::SideEffects::EffectInstance< - }] # baseEffect # [{>> & effects) { - getEffects(effects); - llvm::erase_if(effects, [&](auto &it) { return it.getValue() != value; }); - } - - /// Collect all of the effect instances that operate on the provided - /// resource and place them in 'effects'. - void getEffectsOnValue(::mlir::SideEffects::Resource *resource, - llvm::SmallVectorImpl<::mlir::SideEffects::EffectInstance< - }] # baseEffect # [{>> & effects) { - getEffects(effects); - llvm::erase_if(effects, [&](auto &it) { - return it.getResource() != resource; - }); - } - }]; - - // The base effect name of this interface. - string baseEffectName = baseEffect; -} - -// This class is the general base side effect class. This is used by derived -// effect interfaces to define their effects. -class SideEffect : OpVariableDecorator { - /// The name of the base effects class. - string baseEffectName = interface.baseEffectName; - - /// The parent interface that the effect belongs to. - string interfaceTrait = interface.trait; - - /// The cpp namespace of the interface trait. - string cppNamespace = interface.cppNamespace; - - /// The derived effect that is being applied. - string effect = effectName; - - /// The resource that the effect is being applied to. - string resource = resourceReference.name; -} - -// This class is the base used for specifying effects applied to an operation. -class SideEffectsTraitBase staticEffects> - : OpInterfaceTrait<""> { - /// The name of the interface trait to use. - let trait = parentInterface.trait; - - /// The cpp namespace of the interface trait. - string cppNamespace = parentInterface.cppNamespace; - - /// The name of the base effects class. - string baseEffectName = parentInterface.baseEffectName; - - /// The derived effects being applied. - list effects = staticEffects; -} +include "mlir/Interfaces/SideEffectInterfaceBase.td" //===----------------------------------------------------------------------===// // MemoryEffects diff --git a/mlir/test/IR/test-side-effects.mlir b/mlir/test/IR/test-side-effects.mlir --- a/mlir/test/IR/test-side-effects.mlir +++ b/mlir/test/IR/test-side-effects.mlir @@ -18,3 +18,10 @@ %3 = "test.side_effect_op"() {effects = [ {effect="allocate", on_result, test_resource} ]} : () -> i32 + +// No _memory_ effects, but a parametric test effect. +// expected-remark@+2 {{operation has no memory effects}} +// expected-remark@+1 {{found a parametric effect with affine_map<(d0, d1) -> (d1, d0)>}} +%4 = "test.side_effect_op"() { + effect_parameter = affine_map<(i, j) -> (j, i)> +} : () -> i32 diff --git a/mlir/test/lib/Dialect/Test/CMakeLists.txt b/mlir/test/lib/Dialect/Test/CMakeLists.txt --- a/mlir/test/lib/Dialect/Test/CMakeLists.txt +++ b/mlir/test/lib/Dialect/Test/CMakeLists.txt @@ -7,6 +7,8 @@ set(LLVM_TARGET_DEFINITIONS TestInterfaces.td) mlir_tablegen(TestTypeInterfaces.h.inc -gen-type-interface-decls) mlir_tablegen(TestTypeInterfaces.cpp.inc -gen-type-interface-defs) +mlir_tablegen(TestOpInterfaces.h.inc -gen-op-interface-decls) +mlir_tablegen(TestOpInterfaces.cpp.inc -gen-op-interface-defs) add_public_tablegen_target(MLIRTestInterfaceIncGen) set(LLVM_TARGET_DEFINITIONS TestTypeDefs.td) @@ -29,6 +31,7 @@ # Exclude tests from libMLIR.so add_mlir_library(MLIRTestDialect TestDialect.cpp + TestInterfaces.cpp TestPatterns.cpp TestTraits.cpp TestTypes.cpp diff --git a/mlir/test/lib/Dialect/Test/TestDialect.h b/mlir/test/lib/Dialect/Test/TestDialect.h --- a/mlir/test/lib/Dialect/Test/TestDialect.h +++ b/mlir/test/lib/Dialect/Test/TestDialect.h @@ -14,6 +14,7 @@ #ifndef MLIR_TESTDIALECT_H #define MLIR_TESTDIALECT_H +#include "TestInterfaces.h" #include "mlir/Dialect/Traits.h" #include "mlir/IR/BuiltinDialect.h" #include "mlir/IR/Dialect.h" @@ -30,7 +31,7 @@ #include "mlir/Interfaces/SideEffectInterfaces.h" #include "TestOpEnums.h.inc" - +#include "TestOpInterfaces.h.inc" #include "TestOpStructs.h.inc" #include "TestOpsDialect.h.inc" diff --git a/mlir/test/lib/Dialect/Test/TestDialect.cpp b/mlir/test/lib/Dialect/Test/TestDialect.cpp --- a/mlir/test/lib/Dialect/Test/TestDialect.cpp +++ b/mlir/test/lib/Dialect/Test/TestDialect.cpp @@ -758,6 +758,15 @@ } } +void SideEffectOp::getEffects( + SmallVectorImpl &effects) { + auto effectsAttr = getAttrOfType("effect_parameter"); + if (!effectsAttr) + return; + + effects.emplace_back(TestEffects::Concrete::get(), effectsAttr); +} + //===----------------------------------------------------------------------===// // StringAttrPrettyNameOp //===----------------------------------------------------------------------===// @@ -911,6 +920,7 @@ } #include "TestOpEnums.cpp.inc" +#include "TestOpInterfaces.cpp.inc" #include "TestOpStructs.cpp.inc" #include "TestTypeInterfaces.cpp.inc" diff --git a/mlir/test/lib/Dialect/Test/TestInterfaces.h b/mlir/test/lib/Dialect/Test/TestInterfaces.h new file mode 100644 --- /dev/null +++ b/mlir/test/lib/Dialect/Test/TestInterfaces.h @@ -0,0 +1,37 @@ +//===- TestInterfaces.h - MLIR interfaces for testing -----------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares interfaces for the 'test' dialect that can be used for +// testing the interface infrastructure. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_TEST_LIB_DIALECT_TEST_TESTINTERFACES_H +#define MLIR_TEST_LIB_DIALECT_TEST_TESTINTERFACES_H + +#include "mlir/Interfaces/SideEffectInterfaces.h" + +namespace mlir { +namespace TestEffects { +struct Effect : public SideEffects::Effect { + using SideEffects::Effect::Effect; + + template + using Base = SideEffects::Effect::Base; + + static bool classof(const SideEffects::Effect *effect); +}; + +using EffectInstance = SideEffects::EffectInstance; + +struct Concrete : public Effect::Base {}; + +} // namespace TestEffects +} // namespace mlir + +#endif // MLIR_TEST_LIB_DIALECT_TEST_TESTINTERFACES_H diff --git a/mlir/test/lib/Dialect/Test/TestInterfaces.cpp b/mlir/test/lib/Dialect/Test/TestInterfaces.cpp new file mode 100644 --- /dev/null +++ b/mlir/test/lib/Dialect/Test/TestInterfaces.cpp @@ -0,0 +1,8 @@ +#include "TestInterfaces.h" + +using namespace mlir; + +bool mlir::TestEffects::Effect::classof( + const mlir::SideEffects::Effect *effect) { + return isa(effect); +} diff --git a/mlir/test/lib/Dialect/Test/TestInterfaces.td b/mlir/test/lib/Dialect/Test/TestInterfaces.td --- a/mlir/test/lib/Dialect/Test/TestInterfaces.td +++ b/mlir/test/lib/Dialect/Test/TestInterfaces.td @@ -6,10 +6,11 @@ // //===----------------------------------------------------------------------===// -#ifndef TEST_INTERFACES -#define TEST_INTERFACES +#ifndef MLIR_TEST_DIALECT_TEST_INTERFACES +#define MLIR_TEST_DIALECT_TEST_INTERFACES include "mlir/IR/OpBase.td" +include "mlir/Interfaces/SideEffectInterfaceBase.td" // A type interface used to test the ODS generation of type interfaces. def TestTypeInterface : TypeInterface<"TestTypeInterface"> { @@ -52,4 +53,18 @@ }]; } -#endif // TEST_INTERFACES +def TestEffectOpInterface + : EffectOpInterfaceBase<"TestEffectOpInterface", + "::mlir::TestEffects::Effect"> { + let cppNamespace = "::mlir"; +} + +class TestEffect + : SideEffect; + +class TestEffects effects = []> + : SideEffectsTraitBase; + +def TestConcreteEffect : TestEffect<"TestEffects::Concrete">; + +#endif // MLIR_TEST_DIALECT_TEST_INTERFACES diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td --- a/mlir/test/lib/Dialect/Test/TestOps.td +++ b/mlir/test/lib/Dialect/Test/TestOps.td @@ -18,6 +18,7 @@ include "mlir/Interfaces/CopyOpInterface.td" include "mlir/Interfaces/InferTypeOpInterface.td" include "mlir/Interfaces/SideEffectInterfaces.td" +include "TestInterfaces.td" def Test_Dialect : Dialect { let name = "test"; @@ -1721,7 +1722,8 @@ //===----------------------------------------------------------------------===// def SideEffectOp : TEST_Op<"side_effect_op", - [DeclareOpInterfaceMethods]> { + [DeclareOpInterfaceMethods, + DeclareOpInterfaceMethods]> { let results = (outs AnyType:$result); } diff --git a/mlir/test/lib/IR/TestSideEffects.cpp b/mlir/test/lib/IR/TestSideEffects.cpp --- a/mlir/test/lib/IR/TestSideEffects.cpp +++ b/mlir/test/lib/IR/TestSideEffects.cpp @@ -47,6 +47,20 @@ diag << " on resource '" << instance.getResource()->getName() << "'"; } }); + + SmallVector testEffects; + module.walk([&](TestEffectOpInterface op) { + testEffects.clear(); + op.getEffects(testEffects); + + if (testEffects.empty()) + return; + + for (const TestEffects::EffectInstance &instance : testEffects) { + op.emitRemark() << "found a parametric effect with " + << instance.getParameters(); + } + }); } }; } // end anonymous namespace