|
| 1 | +//===-- MemoryModel.h - ptr dialect memory model ---------------*- 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 defines the ptr's dialect memory model class and related |
| 10 | +// interfaces. |
| 11 | +// |
| 12 | +//===----------------------------------------------------------------------===// |
| 13 | + |
| 14 | +#ifndef MLIR_DIALECT_PTR_IR_MEMORYMODEL_H |
| 15 | +#define MLIR_DIALECT_PTR_IR_MEMORYMODEL_H |
| 16 | + |
| 17 | +#include "mlir/IR/Attributes.h" |
| 18 | +#include "mlir/IR/BuiltinAttributes.h" |
| 19 | +#include "mlir/IR/OpDefinition.h" |
| 20 | + |
| 21 | +namespace mlir { |
| 22 | +class Operation; |
| 23 | +namespace ptr { |
| 24 | +/// Memory operation validity. |
| 25 | +enum class MemOpValidity : uint8_t { |
| 26 | + Valid = 0, /// The operation is valid. |
| 27 | + InvalidType = |
| 28 | + 1, /// The type is not compatible with the operation and memory space. |
| 29 | + InvalidAtomicOrdering = 2, /// The atomic ordering is incompatible with the |
| 30 | + /// operation and memory space. |
| 31 | + InvalidAlignment = 4, /// The provided alignment is invalid. |
| 32 | +}; |
| 33 | + |
| 34 | +inline MemOpValidity operator&(MemOpValidity lhs, MemOpValidity rhs) { |
| 35 | + return static_cast<MemOpValidity>(static_cast<uint8_t>(lhs) & |
| 36 | + static_cast<uint8_t>(rhs)); |
| 37 | +} |
| 38 | +inline MemOpValidity operator|(MemOpValidity lhs, MemOpValidity rhs) { |
| 39 | + return static_cast<MemOpValidity>(static_cast<uint8_t>(lhs) | |
| 40 | + static_cast<uint8_t>(rhs)); |
| 41 | +} |
| 42 | + |
| 43 | +/// Checks if a specific cast validity flag is set. |
| 44 | +inline bool isMemValidityFlagSet(MemOpValidity value, MemOpValidity flag) { |
| 45 | + return (value & flag) == flag; |
| 46 | +} |
| 47 | + |
| 48 | +/// Ptr cast operations validity. |
| 49 | +enum class CastValidity : uint8_t { |
| 50 | + Valid = 0, /// Valid cast operation. |
| 51 | + InvalidSourceType = 1, /// Invalid source type. |
| 52 | + InvalidTargetType = 2, /// Invalid target type. |
| 53 | + InvalidVectorRank = 4, /// One of the operands has an invalid vector rank. |
| 54 | + InvalidScalableVector = 8, /// One of the operands is a scalable vector. |
| 55 | + IncompatibleShapes = 16, /// The types have incompatible shapes. |
| 56 | +}; |
| 57 | + |
| 58 | +inline CastValidity operator&(CastValidity lhs, CastValidity rhs) { |
| 59 | + return static_cast<CastValidity>(static_cast<uint8_t>(lhs) & |
| 60 | + static_cast<uint8_t>(rhs)); |
| 61 | +} |
| 62 | +inline CastValidity operator|(CastValidity lhs, CastValidity rhs) { |
| 63 | + return static_cast<CastValidity>(static_cast<uint8_t>(lhs) | |
| 64 | + static_cast<uint8_t>(rhs)); |
| 65 | +} |
| 66 | + |
| 67 | +/// Checks if a specific cast validity flag is set. |
| 68 | +inline bool isCastFlagSet(CastValidity value, CastValidity flag) { |
| 69 | + return (value & flag) == flag; |
| 70 | +} |
| 71 | + |
| 72 | +/// This method checks if it's valid to perform an `addrspacecast` op in the |
| 73 | +/// memory space. |
| 74 | +/// Compatible types are: |
| 75 | +/// Vectors of rank 1, or scalars of `ptr` type. |
| 76 | +CastValidity isValidAddrSpaceCastImpl(Type tgt, Type src); |
| 77 | + |
| 78 | +/// This method checks if it's valid to perform a `ptrtoint` or `inttoptr` op in |
| 79 | +/// the memory space. `CastValidity::InvalidSourceType` always refers to the |
| 80 | +/// 'ptr-like' type and `CastValidity::InvalidTargetType` always refers to the |
| 81 | +/// `int-like` type. |
| 82 | +/// Compatible types are: |
| 83 | +/// IntLikeTy: Vectors of rank 1, or scalars of integer types or `index` type. |
| 84 | +/// PtrLikeTy: Vectors of rank 1, or scalars of `ptr` type. |
| 85 | +CastValidity isValidPtrIntCastImpl(Type intLikeTy, Type ptrLikeTy); |
| 86 | + |
| 87 | +enum class AtomicBinOp : uint64_t; |
| 88 | +enum class AtomicOrdering : uint64_t; |
| 89 | +} // namespace ptr |
| 90 | +} // namespace mlir |
| 91 | + |
| 92 | +#include "mlir/Dialect/Ptr/IR/MemorySpaceAttrInterfaces.h.inc" |
| 93 | + |
| 94 | +namespace mlir { |
| 95 | +namespace ptr { |
| 96 | +/// This class wraps the `MemorySpaceAttrInterface` interface, providing a safe |
| 97 | +/// mechanism to specify the default behavior assumed by the ptr dialect. |
| 98 | +class MemoryModel { |
| 99 | +public: |
| 100 | + MemoryModel() = default; |
| 101 | + MemoryModel(std::nullptr_t) {} |
| 102 | + MemoryModel(MemorySpaceAttrInterface memorySpace) |
| 103 | + : memorySpaceAttr(memorySpace), memorySpace(memorySpace) {} |
| 104 | + MemoryModel(Attribute memorySpace) |
| 105 | + : memorySpaceAttr(memorySpace), |
| 106 | + memorySpace(dyn_cast_or_null<MemorySpaceAttrInterface>(memorySpace)) {} |
| 107 | + |
| 108 | + operator Attribute() const { return memorySpaceAttr; } |
| 109 | + operator MemorySpaceAttrInterface() const { return memorySpace; } |
| 110 | + bool operator==(const MemoryModel &memSpace) const { |
| 111 | + return memSpace.memorySpaceAttr == memorySpaceAttr; |
| 112 | + } |
| 113 | + |
| 114 | + /// Returns the underlying memory space. |
| 115 | + Attribute getUnderlyingSpace() const { return memorySpaceAttr; } |
| 116 | + |
| 117 | + /// Returns true if the underlying memory space is null. |
| 118 | + bool isDefaultModel() const { return memorySpace == nullptr; } |
| 119 | + |
| 120 | + /// Returns the memory space as an integer, or 0 if using the default model. |
| 121 | + unsigned getAddressSpace() const { |
| 122 | + if (memorySpace) |
| 123 | + return memorySpace.getAddressSpace(); |
| 124 | + if (auto intAttr = llvm::dyn_cast_or_null<IntegerAttr>(memorySpaceAttr)) |
| 125 | + return intAttr.getInt(); |
| 126 | + return 0; |
| 127 | + } |
| 128 | + |
| 129 | + /// Returns the default memory space as an attribute, or nullptr if using the |
| 130 | + /// default model. |
| 131 | + Attribute getDefaultMemorySpace() const { |
| 132 | + return memorySpace ? memorySpace.getDefaultMemorySpace() : nullptr; |
| 133 | + } |
| 134 | + |
| 135 | + /// This method checks if it's valid to load a value from the memory space |
| 136 | + /// with a specific type, alignment, and atomic ordering. The default model |
| 137 | + /// assumes all values are loadable. |
| 138 | + MemOpValidity isValidLoad(Type type, AtomicOrdering ordering, |
| 139 | + IntegerAttr alignment) const { |
| 140 | + return memorySpace ? memorySpace.isValidLoad(type, ordering, alignment) |
| 141 | + : MemOpValidity::Valid; |
| 142 | + } |
| 143 | + |
| 144 | + /// This method checks if it's valid to store a value in the memory space with |
| 145 | + /// a specific type, alignment, and atomic ordering. The default model assumes |
| 146 | + /// all values are loadable. |
| 147 | + MemOpValidity isValidStore(Type type, AtomicOrdering ordering, |
| 148 | + IntegerAttr alignment) const { |
| 149 | + return memorySpace ? memorySpace.isValidStore(type, ordering, alignment) |
| 150 | + : MemOpValidity::Valid; |
| 151 | + } |
| 152 | + |
| 153 | + /// This method checks if it's valid to perform an atomic operation in the |
| 154 | + /// memory space with a specific type, alignment, and atomic ordering. |
| 155 | + MemOpValidity isValidAtomicOp(AtomicBinOp op, Type type, |
| 156 | + AtomicOrdering ordering, |
| 157 | + IntegerAttr alignment) const { |
| 158 | + return memorySpace |
| 159 | + ? memorySpace.isValidAtomicOp(op, type, ordering, alignment) |
| 160 | + : MemOpValidity::Valid; |
| 161 | + } |
| 162 | + |
| 163 | + /// This method checks if it's valid to perform an atomic operation in the |
| 164 | + /// memory space with a specific type, alignment, and atomic ordering. |
| 165 | + MemOpValidity isValidAtomicXchg(Type type, AtomicOrdering successOrdering, |
| 166 | + AtomicOrdering failureOrdering, |
| 167 | + IntegerAttr alignment) const { |
| 168 | + return memorySpace ? memorySpace.isValidAtomicXchg( |
| 169 | + type, successOrdering, failureOrdering, alignment) |
| 170 | + : MemOpValidity::Valid; |
| 171 | + } |
| 172 | + |
| 173 | + /// This method checks if it's valid to perform an `addrspacecast` op in the |
| 174 | + /// memory space. |
| 175 | + CastValidity isValidAddrSpaceCast(Type tgt, Type src) const { |
| 176 | + return memorySpace ? memorySpace.isValidAddrSpaceCast(tgt, src) |
| 177 | + : isValidAddrSpaceCastImpl(tgt, src); |
| 178 | + } |
| 179 | + |
| 180 | + /// This method checks if it's valid to perform a `ptrtoint` or `inttoptr` op |
| 181 | + /// in the memory space. `CastValidity::InvalidSourceType` always refers to |
| 182 | + /// the 'ptr-like' type and `CastValidity::InvalidTargetType` always refers to |
| 183 | + /// the `int-like` type. |
| 184 | + CastValidity isValidPtrIntCast(Type intLikeTy, Type ptrLikeTy) const { |
| 185 | + return memorySpace ? memorySpace.isValidPtrIntCast(intLikeTy, ptrLikeTy) |
| 186 | + : isValidPtrIntCastImpl(intLikeTy, ptrLikeTy); |
| 187 | + } |
| 188 | + |
| 189 | +protected: |
| 190 | + /// Underlying memory space. |
| 191 | + Attribute memorySpaceAttr{}; |
| 192 | + /// Memory space. |
| 193 | + MemorySpaceAttrInterface memorySpace{}; |
| 194 | +}; |
| 195 | +} // namespace ptr |
| 196 | +} // namespace mlir |
| 197 | + |
| 198 | +#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h.inc" |
| 199 | + |
| 200 | +#endif // MLIR_DIALECT_PTR_IR_MEMORYMODEL_H |
0 commit comments