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