1 //===- SideEffectInterfaces.h - SideEffect in MLIR --------------*- C++ -*-===// 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 traits, interfaces, and utilities for defining and 10 // querying the side effects of an operation. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef MLIR_INTERFACES_SIDEEFFECTS_H 15 #define MLIR_INTERFACES_SIDEEFFECTS_H 16 17 #include "mlir/IR/OpDefinition.h" 18 19 namespace mlir { 20 namespace SideEffects { 21 //===----------------------------------------------------------------------===// 22 // Effects 23 //===----------------------------------------------------------------------===// 24 25 /// This class represents a base class for a specific effect type. 26 class Effect { 27 public: 28 /// This base class is used for derived effects that are non-parametric. 29 template <typename DerivedEffect, typename BaseEffect = Effect> 30 class Base : public BaseEffect { 31 public: 32 using BaseT = Base<DerivedEffect>; 33 34 /// Return the unique identifier for the base effects class. getEffectID()35 static TypeID getEffectID() { return TypeID::get<DerivedEffect>(); } 36 37 /// 'classof' used to support llvm style cast functionality. classof(const::mlir::SideEffects::Effect * effect)38 static bool classof(const ::mlir::SideEffects::Effect *effect) { 39 return effect->getEffectID() == BaseT::getEffectID(); 40 } 41 42 /// Returns a unique instance for the derived effect class. get()43 static DerivedEffect *get() { 44 return BaseEffect::template get<DerivedEffect>(); 45 } 46 using BaseEffect::get; 47 48 protected: Base()49 Base() : BaseEffect(BaseT::getEffectID()) {} 50 }; 51 52 /// Return the unique identifier for the base effects class. getEffectID()53 TypeID getEffectID() const { return id; } 54 55 /// Returns a unique instance for the given effect class. get()56 template <typename DerivedEffect> static DerivedEffect *get() { 57 static_assert(std::is_base_of<Effect, DerivedEffect>::value, 58 "expected DerivedEffect to inherit from Effect"); 59 60 static DerivedEffect instance; 61 return &instance; 62 } 63 64 protected: Effect(TypeID id)65 Effect(TypeID id) : id(id) {} 66 67 private: 68 /// The id of the derived effect class. 69 TypeID id; 70 }; 71 72 //===----------------------------------------------------------------------===// 73 // Resources 74 //===----------------------------------------------------------------------===// 75 76 /// This class represents a specific resource that an effect applies to. This 77 /// class represents an abstract interface for a given resource. 78 class Resource { 79 public: ~Resource()80 virtual ~Resource() {} 81 82 /// This base class is used for derived effects that are non-parametric. 83 template <typename DerivedResource, typename BaseResource = Resource> 84 class Base : public BaseResource { 85 public: 86 using BaseT = Base<DerivedResource>; 87 88 /// Returns a unique instance for the given effect class. get()89 static DerivedResource *get() { 90 static DerivedResource instance; 91 return &instance; 92 } 93 94 /// Return the unique identifier for the base resource class. getResourceID()95 static TypeID getResourceID() { return TypeID::get<DerivedResource>(); } 96 97 /// 'classof' used to support llvm style cast functionality. classof(const Resource * resource)98 static bool classof(const Resource *resource) { 99 return resource->getResourceID() == BaseT::getResourceID(); 100 } 101 102 protected: Base()103 Base() : BaseResource(BaseT::getResourceID()){}; 104 }; 105 106 /// Return the unique identifier for the base resource class. getResourceID()107 TypeID getResourceID() const { return id; } 108 109 /// Return a string name of the resource. 110 virtual StringRef getName() = 0; 111 112 protected: Resource(TypeID id)113 Resource(TypeID id) : id(id) {} 114 115 private: 116 /// The id of the derived resource class. 117 TypeID id; 118 }; 119 120 /// A conservative default resource kind. 121 struct DefaultResource : public Resource::Base<DefaultResource> { getNameDefaultResource122 StringRef getName() final { return "<Default>"; } 123 }; 124 125 /// An automatic allocation-scope resource that is valid in the context of a 126 /// parent AutomaticAllocationScope trait. 127 struct AutomaticAllocationScopeResource 128 : public Resource::Base<AutomaticAllocationScopeResource> { getNameAutomaticAllocationScopeResource129 StringRef getName() final { return "AutomaticAllocationScope"; } 130 }; 131 132 /// This class represents a specific instance of an effect. It contains the 133 /// effect being applied, a resource that corresponds to where the effect is 134 /// applied, and an optional symbol reference or value(either operand, result, 135 /// or region entry argument) that the effect is applied to, and an optional 136 /// parameters attribute further specifying the details of the effect. 137 template <typename EffectT> class EffectInstance { 138 public: 139 EffectInstance(EffectT *effect, Resource *resource = DefaultResource::get()) effect(effect)140 : effect(effect), resource(resource) {} 141 EffectInstance(EffectT *effect, Value value, 142 Resource *resource = DefaultResource::get()) effect(effect)143 : effect(effect), resource(resource), value(value) {} 144 EffectInstance(EffectT *effect, SymbolRefAttr symbol, 145 Resource *resource = DefaultResource::get()) effect(effect)146 : effect(effect), resource(resource), value(symbol) {} 147 EffectInstance(EffectT *effect, Attribute parameters, 148 Resource *resource = DefaultResource::get()) effect(effect)149 : effect(effect), resource(resource), parameters(parameters) {} 150 EffectInstance(EffectT *effect, Value value, Attribute parameters, 151 Resource *resource = DefaultResource::get()) effect(effect)152 : effect(effect), resource(resource), value(value), 153 parameters(parameters) {} 154 EffectInstance(EffectT *effect, SymbolRefAttr symbol, Attribute parameters, 155 Resource *resource = DefaultResource::get()) effect(effect)156 : effect(effect), resource(resource), value(symbol), 157 parameters(parameters) {} 158 159 /// Return the effect being applied. getEffect()160 EffectT *getEffect() const { return effect; } 161 162 /// Return the value the effect is applied on, or nullptr if there isn't a 163 /// known value being affected. getValue()164 Value getValue() const { return value ? value.dyn_cast<Value>() : Value(); } 165 166 /// Return the symbol reference the effect is applied on, or nullptr if there 167 /// isn't a known smbol being affected. getSymbolRef()168 SymbolRefAttr getSymbolRef() const { 169 return value ? value.dyn_cast<SymbolRefAttr>() : SymbolRefAttr(); 170 } 171 172 /// Return the resource that the effect applies to. getResource()173 Resource *getResource() const { return resource; } 174 175 /// Return the parameters of the effect, if any. getParameters()176 Attribute getParameters() const { return parameters; } 177 178 private: 179 /// The specific effect being applied. 180 EffectT *effect; 181 182 /// The resource that the given value resides in. 183 Resource *resource; 184 185 /// The Symbol or Value that the effect applies to. This is optionally null. 186 PointerUnion<SymbolRefAttr, Value> value; 187 188 /// Additional parameters of the effect instance. An attribute is used for 189 /// type-safe structured storage and context-based uniquing. Concrete effects 190 /// can use this at their convenience. This is optionally null. 191 Attribute parameters; 192 }; 193 } // namespace SideEffects 194 195 //===----------------------------------------------------------------------===// 196 // SideEffect Traits 197 //===----------------------------------------------------------------------===// 198 199 namespace OpTrait { 200 /// This trait indicates that the side effects of an operation includes the 201 /// effects of operations nested within its regions. If the operation has no 202 /// derived effects interfaces, the operation itself can be assumed to have no 203 /// side effects. 204 template <typename ConcreteType> 205 class HasRecursiveSideEffects 206 : public TraitBase<ConcreteType, HasRecursiveSideEffects> {}; 207 } // namespace OpTrait 208 209 //===----------------------------------------------------------------------===// 210 // Operation Memory-Effect Modeling 211 //===----------------------------------------------------------------------===// 212 213 namespace MemoryEffects { 214 /// This class represents the base class used for memory effects. 215 struct Effect : public SideEffects::Effect { 216 using SideEffects::Effect::Effect; 217 218 /// A base class for memory effects that provides helper utilities. 219 template <typename DerivedEffect> 220 using Base = SideEffects::Effect::Base<DerivedEffect, Effect>; 221 222 static bool classof(const SideEffects::Effect *effect); 223 }; 224 using EffectInstance = SideEffects::EffectInstance<Effect>; 225 226 /// The following effect indicates that the operation allocates from some 227 /// resource. An 'allocate' effect implies only allocation of the resource, and 228 /// not any visible mutation or dereference. 229 struct Allocate : public Effect::Base<Allocate> {}; 230 231 /// The following effect indicates that the operation frees some resource that 232 /// has been allocated. An 'allocate' effect implies only de-allocation of the 233 /// resource, and not any visible allocation, mutation or dereference. 234 struct Free : public Effect::Base<Free> {}; 235 236 /// The following effect indicates that the operation reads from some resource. 237 /// A 'read' effect implies only dereferencing of the resource, and not any 238 /// visible mutation. 239 struct Read : public Effect::Base<Read> {}; 240 241 /// The following effect indicates that the operation writes to some resource. A 242 /// 'write' effect implies only mutating a resource, and not any visible 243 /// dereference or read. 244 struct Write : public Effect::Base<Write> {}; 245 } // namespace MemoryEffects 246 247 //===----------------------------------------------------------------------===// 248 // SideEffect Utilities 249 //===----------------------------------------------------------------------===// 250 251 /// Return true if the given operation is unused, and has no side effects on 252 /// memory that prevent erasing. 253 bool isOpTriviallyDead(Operation *op); 254 255 /// Return true if the given operation would be dead if unused, and has no side 256 /// effects on memory that would prevent erasing. This is equivalent to checking 257 /// `isOpTriviallyDead` if `op` was unused. 258 bool wouldOpBeTriviallyDead(Operation *op); 259 260 } // end namespace mlir 261 262 //===----------------------------------------------------------------------===// 263 // SideEffect Interfaces 264 //===----------------------------------------------------------------------===// 265 266 /// Include the definitions of the side effect interfaces. 267 #include "mlir/Interfaces/SideEffectInterfaces.h.inc" 268 269 #endif // MLIR_INTERFACES_SIDEEFFECTS_H 270