Files
gps/tools/local/circt/include/mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.h.inc
T
2026-07-12 11:01:51 +03:00

1158 lines
57 KiB
C++

/*===- TableGen'erated file -------------------------------------*- C++ -*-===*\
|* *|
|* Interface Declarations *|
|* *|
|* Automatically generated file, do not edit! *|
|* *|
\*===----------------------------------------------------------------------===*/
namespace mlir::accomp {
/// This interface is used for OpenACC/OpenMP dialect operation that performs an
/// atomic read.
///
/// The interface terminology uses `x` and `v` like the directive
/// specifications:
/// `v = x;`
/// `x` is the address from where the value is atomically read.
/// `v` is the address where the value is stored after reading.
class AtomicReadOpInterface;
} // namespace mlir::accomp
namespace mlir::accomp {
/// This interface is used for OpenACC/OpenMP dialect operation that performs an
/// atomic write.
///
/// The interface terminology uses `x` and `expr` like the directive
/// specifications:
/// `x = expr;`
/// `x` is the address to where the `expr` is atomically written.
class AtomicWriteOpInterface;
} // namespace mlir::accomp
namespace mlir::accomp {
/// This interface is used for OpenACC/OpenMP dialect operation that performs an
/// atomic update.
///
/// The interface terminology uses `x` to specify the address where a value
/// is atomically written/read.
///
/// Since atomic update expression comes in many forms, this interface requires
/// that the operation uses a region with a single argument to capture the
/// expression.
///
/// The region describes how to update the value of `x`. It takes the value at
/// `x` as an input and must yield the updated value. Only the update to `x` is
/// atomic. Generally the region must have only one instruction, but can
/// potentially have more than one instructions too. The update is semantically
/// similar to a compare-exchange loop based atomic update.
class AtomicUpdateOpInterface;
} // namespace mlir::accomp
namespace mlir::accomp {
/// This interface is used for OpenACC/OpenMP dialect operation that performs an
/// atomic capture.
///
/// This interface requires a single region with two operations that each
/// implement one of the atomic interfaces. It can be found in one of these
/// forms:
/// `{ atomic.update, atomic.read }`
/// `{ atomic.read, atomic.update }`
/// `{ atomic.read, atomic.write }`
class AtomicCaptureOpInterface;
} // namespace mlir::accomp
namespace mlir::accomp {
/// This interface is used for OpenMP dialect operation that performs an
/// atomic compare.
///
/// The interface terminology uses `x`, `e`, and `d` like the directive
/// specifications:
/// `if (x == e) x = d`
/// `x` is the address of the variable that is being compared and updated.
/// The region describes the comparison and update logic. It takes
/// the current value of `x` as a single block argument.
///
/// The region has the following structure:
/// ```
/// atomic.compare {
/// ^bb0(%val_x):
/// <compare %val_x with e>
/// <conditionally yield d or %val_x>
/// }
/// ```
class AtomicCompareOpInterface;
} // namespace mlir::accomp
namespace mlir::accomp {
/// This interface is used for OpenACC/OpenMP dialect operation that performs an
/// atomic read.
///
/// The interface terminology uses `x` and `v` like the directive
/// specifications:
/// `v = x;`
/// `x` is the address from where the value is atomically read.
/// `v` is the address where the value is stored after reading.
namespace detail {
struct AtomicReadOpInterfaceInterfaceTraits {
struct Concept {
/// The methods defined by the interface.
::llvm::LogicalResult (*verifyCommon)(const Concept *impl, ::mlir::Operation *);
::mlir::Value (*getX)(const Concept *impl, ::mlir::Operation *);
::mlir::Value (*getV)(const Concept *impl, ::mlir::Operation *);
};
template<typename ConcreteOp>
class Model : public Concept {
public:
using Interface = ::mlir::accomp::AtomicReadOpInterface;
Model() : Concept{verifyCommon, getX, getV} {}
static inline ::llvm::LogicalResult verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Value getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Value getV(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
};
template<typename ConcreteOp>
class FallbackModel : public Concept {
public:
using Interface = ::mlir::accomp::AtomicReadOpInterface;
FallbackModel() : Concept{verifyCommon, getX, getV} {}
static inline ::llvm::LogicalResult verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Value getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Value getV(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
};
template<typename ConcreteModel, typename ConcreteOp>
class ExternalModel : public FallbackModel<ConcreteModel> {
public:
using ConcreteEntity = ConcreteOp;
::llvm::LogicalResult verifyCommon(::mlir::Operation *tablegen_opaque_val) const;
};
};
template <typename ConcreteOp>
struct AtomicReadOpInterfaceTrait;
} // namespace detail
class AtomicReadOpInterface : public ::mlir::OpInterface<AtomicReadOpInterface, detail::AtomicReadOpInterfaceInterfaceTraits> {
public:
using ::mlir::OpInterface<AtomicReadOpInterface, detail::AtomicReadOpInterfaceInterfaceTraits>::OpInterface;
template <typename ConcreteOp>
struct Trait : public detail::AtomicReadOpInterfaceTrait<ConcreteOp> {};
/// Common verifier for operation that implements atomic read interface.
::llvm::LogicalResult verifyCommon();
/// Obtains `x` which is the address from where the value is atomically
/// read.
::mlir::Value getX();
/// Obtains `v` which is the address where the value is stored after
/// reading.
::mlir::Value getV();
};
} // namespace mlir::accomp
namespace mlir::accomp {
/// This interface is used for OpenACC/OpenMP dialect operation that performs an
/// atomic write.
///
/// The interface terminology uses `x` and `expr` like the directive
/// specifications:
/// `x = expr;`
/// `x` is the address to where the `expr` is atomically written.
namespace detail {
struct AtomicWriteOpInterfaceInterfaceTraits {
struct Concept {
/// The methods defined by the interface.
::llvm::LogicalResult (*verifyCommon)(const Concept *impl, ::mlir::Operation *);
::mlir::Value (*getX)(const Concept *impl, ::mlir::Operation *);
::mlir::Value (*getExpr)(const Concept *impl, ::mlir::Operation *);
};
template<typename ConcreteOp>
class Model : public Concept {
public:
using Interface = ::mlir::accomp::AtomicWriteOpInterface;
Model() : Concept{verifyCommon, getX, getExpr} {}
static inline ::llvm::LogicalResult verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Value getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Value getExpr(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
};
template<typename ConcreteOp>
class FallbackModel : public Concept {
public:
using Interface = ::mlir::accomp::AtomicWriteOpInterface;
FallbackModel() : Concept{verifyCommon, getX, getExpr} {}
static inline ::llvm::LogicalResult verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Value getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Value getExpr(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
};
template<typename ConcreteModel, typename ConcreteOp>
class ExternalModel : public FallbackModel<ConcreteModel> {
public:
using ConcreteEntity = ConcreteOp;
::llvm::LogicalResult verifyCommon(::mlir::Operation *tablegen_opaque_val) const;
};
};
template <typename ConcreteOp>
struct AtomicWriteOpInterfaceTrait;
} // namespace detail
class AtomicWriteOpInterface : public ::mlir::OpInterface<AtomicWriteOpInterface, detail::AtomicWriteOpInterfaceInterfaceTraits> {
public:
using ::mlir::OpInterface<AtomicWriteOpInterface, detail::AtomicWriteOpInterfaceInterfaceTraits>::OpInterface;
template <typename ConcreteOp>
struct Trait : public detail::AtomicWriteOpInterfaceTrait<ConcreteOp> {};
/// Common verifier for operation that implements atomic write interface.
::llvm::LogicalResult verifyCommon();
/// Obtains `x` which is the address to which the value is atomically
/// written to.
::mlir::Value getX();
/// Obtains `expr` which corresponds to the expression whose value is
/// written to `x`.
::mlir::Value getExpr();
};
} // namespace mlir::accomp
namespace mlir::accomp {
/// This interface is used for OpenACC/OpenMP dialect operation that performs an
/// atomic update.
///
/// The interface terminology uses `x` to specify the address where a value
/// is atomically written/read.
///
/// Since atomic update expression comes in many forms, this interface requires
/// that the operation uses a region with a single argument to capture the
/// expression.
///
/// The region describes how to update the value of `x`. It takes the value at
/// `x` as an input and must yield the updated value. Only the update to `x` is
/// atomic. Generally the region must have only one instruction, but can
/// potentially have more than one instructions too. The update is semantically
/// similar to a compare-exchange loop based atomic update.
namespace detail {
struct AtomicUpdateOpInterfaceInterfaceTraits {
struct Concept {
/// The methods defined by the interface.
::mlir::Value (*getX)(const Concept *impl, ::mlir::Operation *);
::mlir::Operation *(*getFirstOp)(const Concept *impl, ::mlir::Operation *);
bool (*isNoOp)(const Concept *impl, ::mlir::Operation *);
::mlir::Value (*getWriteOpVal)(const Concept *impl, ::mlir::Operation *);
::llvm::LogicalResult (*verifyCommon)(const Concept *impl, ::mlir::Operation *);
::llvm::LogicalResult (*verifyRegionsCommon)(const Concept *impl, ::mlir::Operation *);
};
template<typename ConcreteOp>
class Model : public Concept {
public:
using Interface = ::mlir::accomp::AtomicUpdateOpInterface;
Model() : Concept{getX, getFirstOp, isNoOp, getWriteOpVal, verifyCommon, verifyRegionsCommon} {}
static inline ::mlir::Value getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Operation *getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline bool isNoOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Value getWriteOpVal(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::llvm::LogicalResult verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::llvm::LogicalResult verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
};
template<typename ConcreteOp>
class FallbackModel : public Concept {
public:
using Interface = ::mlir::accomp::AtomicUpdateOpInterface;
FallbackModel() : Concept{getX, getFirstOp, isNoOp, getWriteOpVal, verifyCommon, verifyRegionsCommon} {}
static inline ::mlir::Value getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Operation *getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline bool isNoOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Value getWriteOpVal(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::llvm::LogicalResult verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::llvm::LogicalResult verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
};
template<typename ConcreteModel, typename ConcreteOp>
class ExternalModel : public FallbackModel<ConcreteModel> {
public:
using ConcreteEntity = ConcreteOp;
::mlir::Operation *getFirstOp(::mlir::Operation *tablegen_opaque_val) const;
bool isNoOp(::mlir::Operation *tablegen_opaque_val) const;
::mlir::Value getWriteOpVal(::mlir::Operation *tablegen_opaque_val) const;
::llvm::LogicalResult verifyCommon(::mlir::Operation *tablegen_opaque_val) const;
::llvm::LogicalResult verifyRegionsCommon(::mlir::Operation *tablegen_opaque_val) const;
};
};
template <typename ConcreteOp>
struct AtomicUpdateOpInterfaceTrait;
} // namespace detail
class AtomicUpdateOpInterface : public ::mlir::OpInterface<AtomicUpdateOpInterface, detail::AtomicUpdateOpInterfaceInterfaceTraits> {
public:
using ::mlir::OpInterface<AtomicUpdateOpInterface, detail::AtomicUpdateOpInterfaceInterfaceTraits>::OpInterface;
template <typename ConcreteOp>
struct Trait : public detail::AtomicUpdateOpInterfaceTrait<ConcreteOp> {};
/// Obtains `x` which is the address to which the value is atomically
/// written to / read from.
::mlir::Value getX();
/// Returns the first operation in atomic update region.
::mlir::Operation *getFirstOp();
/// Returns true if the new value is same as old value and the operation is
/// a no-op, false otherwise.
bool isNoOp();
/// Returns the new value if the operation is equivalent to just a write
/// operation. Otherwise, returns nullptr.
::mlir::Value getWriteOpVal();
/// Common verifier for operation that implements atomic update interface.
::llvm::LogicalResult verifyCommon();
/// Common verifier of the required region for operation that implements
/// atomic update interface.
::llvm::LogicalResult verifyRegionsCommon();
};
} // namespace mlir::accomp
namespace mlir::accomp {
/// This interface is used for OpenACC/OpenMP dialect operation that performs an
/// atomic capture.
///
/// This interface requires a single region with two operations that each
/// implement one of the atomic interfaces. It can be found in one of these
/// forms:
/// `{ atomic.update, atomic.read }`
/// `{ atomic.read, atomic.update }`
/// `{ atomic.read, atomic.write }`
namespace detail {
struct AtomicCaptureOpInterfaceInterfaceTraits {
struct Concept {
/// The methods defined by the interface.
::mlir::Operation *(*getFirstOp)(const Concept *impl, ::mlir::Operation *);
::mlir::Operation *(*getSecondOp)(const Concept *impl, ::mlir::Operation *);
::llvm::LogicalResult (*verifyRegionsCommon)(const Concept *impl, ::mlir::Operation *);
};
template<typename ConcreteOp>
class Model : public Concept {
public:
using Interface = ::mlir::accomp::AtomicCaptureOpInterface;
Model() : Concept{getFirstOp, getSecondOp, verifyRegionsCommon} {}
static inline ::mlir::Operation *getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Operation *getSecondOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::llvm::LogicalResult verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
};
template<typename ConcreteOp>
class FallbackModel : public Concept {
public:
using Interface = ::mlir::accomp::AtomicCaptureOpInterface;
FallbackModel() : Concept{getFirstOp, getSecondOp, verifyRegionsCommon} {}
static inline ::mlir::Operation *getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Operation *getSecondOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::llvm::LogicalResult verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
};
template<typename ConcreteModel, typename ConcreteOp>
class ExternalModel : public FallbackModel<ConcreteModel> {
public:
using ConcreteEntity = ConcreteOp;
::mlir::Operation *getFirstOp(::mlir::Operation *tablegen_opaque_val) const;
::mlir::Operation *getSecondOp(::mlir::Operation *tablegen_opaque_val) const;
::llvm::LogicalResult verifyRegionsCommon(::mlir::Operation *tablegen_opaque_val) const;
};
};
template <typename ConcreteOp>
struct AtomicCaptureOpInterfaceTrait;
} // namespace detail
class AtomicCaptureOpInterface : public ::mlir::OpInterface<AtomicCaptureOpInterface, detail::AtomicCaptureOpInterfaceInterfaceTraits> {
public:
using ::mlir::OpInterface<AtomicCaptureOpInterface, detail::AtomicCaptureOpInterfaceInterfaceTraits>::OpInterface;
template <typename ConcreteOp>
struct Trait : public detail::AtomicCaptureOpInterfaceTrait<ConcreteOp> {};
/// Returns the first operation in atomic capture region.
::mlir::Operation *getFirstOp();
/// Returns the second operation in atomic capture region.
::mlir::Operation *getSecondOp();
/// Common verifier of the required region for operation that implements
/// atomic capture interface.
::llvm::LogicalResult verifyRegionsCommon();
};
} // namespace mlir::accomp
namespace mlir::accomp {
/// This interface is used for OpenMP dialect operation that performs an
/// atomic compare.
///
/// The interface terminology uses `x`, `e`, and `d` like the directive
/// specifications:
/// `if (x == e) x = d`
/// `x` is the address of the variable that is being compared and updated.
/// The region describes the comparison and update logic. It takes
/// the current value of `x` as a single block argument.
///
/// The region has the following structure:
/// ```
/// atomic.compare {
/// ^bb0(%val_x):
/// <compare %val_x with e>
/// <conditionally yield d or %val_x>
/// }
/// ```
namespace detail {
struct AtomicCompareOpInterfaceInterfaceTraits {
struct Concept {
/// The methods defined by the interface.
::mlir::Value (*getX)(const Concept *impl, ::mlir::Operation *);
::mlir::Operation *(*getFirstOp)(const Concept *impl, ::mlir::Operation *);
::llvm::LogicalResult (*verifyCommon)(const Concept *impl, ::mlir::Operation *);
::llvm::LogicalResult (*verifyRegionsCommon)(const Concept *impl, ::mlir::Operation *);
::llvm::LogicalResult (*verifyOperator)(const Concept *impl, ::mlir::Operation *);
};
template<typename ConcreteOp>
class Model : public Concept {
public:
using Interface = ::mlir::accomp::AtomicCompareOpInterface;
Model() : Concept{getX, getFirstOp, verifyCommon, verifyRegionsCommon, verifyOperator} {}
static inline ::mlir::Value getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Operation *getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::llvm::LogicalResult verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::llvm::LogicalResult verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::llvm::LogicalResult verifyOperator(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
};
template<typename ConcreteOp>
class FallbackModel : public Concept {
public:
using Interface = ::mlir::accomp::AtomicCompareOpInterface;
FallbackModel() : Concept{getX, getFirstOp, verifyCommon, verifyRegionsCommon, verifyOperator} {}
static inline ::mlir::Value getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::mlir::Operation *getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::llvm::LogicalResult verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::llvm::LogicalResult verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
static inline ::llvm::LogicalResult verifyOperator(const Concept *impl, ::mlir::Operation *tablegen_opaque_val);
};
template<typename ConcreteModel, typename ConcreteOp>
class ExternalModel : public FallbackModel<ConcreteModel> {
public:
using ConcreteEntity = ConcreteOp;
::mlir::Operation *getFirstOp(::mlir::Operation *tablegen_opaque_val) const;
::llvm::LogicalResult verifyCommon(::mlir::Operation *tablegen_opaque_val) const;
::llvm::LogicalResult verifyRegionsCommon(::mlir::Operation *tablegen_opaque_val) const;
::llvm::LogicalResult verifyOperator(::mlir::Operation *tablegen_opaque_val) const;
};
};
template <typename ConcreteOp>
struct AtomicCompareOpInterfaceTrait;
} // namespace detail
class AtomicCompareOpInterface : public ::mlir::OpInterface<AtomicCompareOpInterface, detail::AtomicCompareOpInterfaceInterfaceTraits> {
public:
using ::mlir::OpInterface<AtomicCompareOpInterface, detail::AtomicCompareOpInterfaceInterfaceTraits>::OpInterface;
template <typename ConcreteOp>
struct Trait : public detail::AtomicCompareOpInterfaceTrait<ConcreteOp> {};
/// Obtains `x` which is the address of the variable that is being
/// compared and potentially updated.
::mlir::Value getX();
/// Returns the first operation in the atomic compare region.
::mlir::Operation *getFirstOp();
/// Common verifier for operation that implements atomic compare interface.
::llvm::LogicalResult verifyCommon();
/// Common verifier of the required region for operation that implements
/// atomic compare interface.
::llvm::LogicalResult verifyRegionsCommon();
/// Common verifier for operator that implements atomic compare interface.
/// Checks that the comparison operation in the region uses:
/// 1) supported predicate for integer comparison : eq, slt, or sgt
/// 2) supported predicate for float comparison : oeq, oglt or lsgt
::llvm::LogicalResult verifyOperator();
};
} // namespace mlir::accomp
namespace mlir::accomp::detail {
template <typename ConcreteOp>
struct AtomicReadOpInterfaceTrait : public ::mlir::OpInterface<AtomicReadOpInterface, detail::AtomicReadOpInterfaceInterfaceTraits>::Trait<ConcreteOp> {
/// Common verifier for operation that implements atomic read interface.
::llvm::LogicalResult verifyCommon() {
if ((*static_cast<ConcreteOp *>(this)).getX() == (*static_cast<ConcreteOp *>(this)).getV()) {
return (*static_cast<ConcreteOp *>(this)).emitError(
"read and write must not be to the same location for atomic reads");
}
return mlir::success();
}
};
} // namespace mlir::accomp::detail
namespace mlir::accomp::detail {
template <typename ConcreteOp>
struct AtomicWriteOpInterfaceTrait : public ::mlir::OpInterface<AtomicWriteOpInterface, detail::AtomicWriteOpInterfaceInterfaceTraits>::Trait<ConcreteOp> {
/// Common verifier for operation that implements atomic write interface.
::llvm::LogicalResult verifyCommon() {
mlir::Type elementType = (*static_cast<ConcreteOp *>(this)).getX().getType().getElementType();
if (elementType && elementType != (*static_cast<ConcreteOp *>(this)).getExpr().getType())
return (*static_cast<ConcreteOp *>(this)).emitError("address must dereference to value type");
return mlir::success();
}
};
} // namespace mlir::accomp::detail
namespace mlir::accomp::detail {
template <typename ConcreteOp>
struct AtomicUpdateOpInterfaceTrait : public ::mlir::OpInterface<AtomicUpdateOpInterface, detail::AtomicUpdateOpInterfaceInterfaceTraits>::Trait<ConcreteOp> {
/// Returns the first operation in atomic update region.
::mlir::Operation *getFirstOp() {
return &((*static_cast<ConcreteOp *>(this)).getRegion().front().getOperations().front());
}
/// Returns true if the new value is same as old value and the operation is
/// a no-op, false otherwise.
bool isNoOp() {
// The atomic update is a no-op if the terminator is the first and only
// operation in its region.
mlir::Operation* terminator =
llvm::dyn_cast<mlir::RegionBranchTerminatorOpInterface>((*static_cast<ConcreteOp *>(this)).getFirstOp());
return terminator && terminator->getOperands().front() ==
(*static_cast<ConcreteOp *>(this)).getRegion().front().getArgument(0);
}
/// Returns the new value if the operation is equivalent to just a write
/// operation. Otherwise, returns nullptr.
::mlir::Value getWriteOpVal() {
mlir::Operation* terminator =
llvm::dyn_cast<mlir::RegionBranchTerminatorOpInterface>((*static_cast<ConcreteOp *>(this)).getFirstOp());
if (terminator && terminator->getOperands().front() !=
(*static_cast<ConcreteOp *>(this)).getRegion().front().getArgument(0)) {
return terminator->getOperands().front();
}
return nullptr;
}
/// Common verifier for operation that implements atomic update interface.
::llvm::LogicalResult verifyCommon() {
if ((*static_cast<ConcreteOp *>(this)).getRegion().getNumArguments() != 1)
return (*static_cast<ConcreteOp *>(this)).emitError("the region must accept exactly one argument");
Type elementType = (*static_cast<ConcreteOp *>(this)).getX().getType().getElementType();
if (elementType && elementType != (*static_cast<ConcreteOp *>(this)).getRegion().getArgument(0).getType()) {
return (*static_cast<ConcreteOp *>(this)).emitError("the type of the operand must be a pointer type whose "
"element type is the same as that of the region argument");
}
return mlir::success();
}
/// Common verifier of the required region for operation that implements
/// atomic update interface.
::llvm::LogicalResult verifyRegionsCommon() {
mlir::Operation *terminator = (*static_cast<ConcreteOp *>(this)).getRegion().front().getTerminator();
if (terminator->getOperands().size() != 1)
return (*static_cast<ConcreteOp *>(this)).emitError("only updated value must be returned");
if (terminator->getOperands().front().getType() !=
(*static_cast<ConcreteOp *>(this)).getRegion().getArgument(0).getType())
return (*static_cast<ConcreteOp *>(this)).emitError("input and yielded value must have the same type");
return mlir::success();
}
};
} // namespace mlir::accomp::detail
namespace mlir::accomp::detail {
template <typename ConcreteOp>
struct AtomicCaptureOpInterfaceTrait : public ::mlir::OpInterface<AtomicCaptureOpInterface, detail::AtomicCaptureOpInterfaceInterfaceTraits>::Trait<ConcreteOp> {
/// Returns the first operation in atomic capture region.
::mlir::Operation *getFirstOp() {
return &((*static_cast<ConcreteOp *>(this)).getRegion().front().getOperations().front());
}
/// Returns the second operation in atomic capture region.
::mlir::Operation *getSecondOp() {
auto &ops = (*static_cast<ConcreteOp *>(this)).getRegion().front().getOperations();
return ops.getNextNode(ops.front());
}
/// Common verifier of the required region for operation that implements
/// atomic capture interface.
::llvm::LogicalResult verifyRegionsCommon() {
Block::OpListType &ops = (*static_cast<ConcreteOp *>(this)).getRegion().front().getOperations();
if (ops.size() != 3)
return (*static_cast<ConcreteOp *>(this)).emitError()
<< "expected three operations in atomic.capture region (one "
"terminator, and two atomic ops)";
auto &firstOp = ops.front();
auto &secondOp = *ops.getNextNode(firstOp);
auto firstReadStmt = dyn_cast<AtomicReadOpInterface>(firstOp);
auto firstUpdateStmt = dyn_cast<AtomicUpdateOpInterface>(firstOp);
auto secondReadStmt = dyn_cast<AtomicReadOpInterface>(secondOp);
auto secondUpdateStmt = dyn_cast<AtomicUpdateOpInterface>(secondOp);
auto secondWriteStmt = dyn_cast<AtomicWriteOpInterface>(secondOp);
if (!((firstUpdateStmt && secondReadStmt) ||
(firstReadStmt && secondUpdateStmt) ||
(firstReadStmt && secondWriteStmt)))
return ops.front().emitError()
<< "invalid sequence of operations in the capture region";
if (firstUpdateStmt && secondReadStmt &&
firstUpdateStmt.getX() != secondReadStmt.getX())
return firstUpdateStmt.emitError()
<< "updated variable in atomic.update must be captured in "
"second operation";
if (firstReadStmt && secondUpdateStmt &&
firstReadStmt.getX() != secondUpdateStmt.getX())
return firstReadStmt.emitError()
<< "captured variable in atomic.read must be updated in second "
"operation";
if (firstReadStmt && secondWriteStmt &&
firstReadStmt.getX() != secondWriteStmt.getX())
return firstReadStmt.emitError()
<< "captured variable in atomic.read must be updated in "
"second operation";
return mlir::success();
}
};
} // namespace mlir::accomp::detail
namespace mlir::accomp::detail {
template <typename ConcreteOp>
struct AtomicCompareOpInterfaceTrait : public ::mlir::OpInterface<AtomicCompareOpInterface, detail::AtomicCompareOpInterfaceInterfaceTraits>::Trait<ConcreteOp> {
/// Returns the first operation in the atomic compare region.
::mlir::Operation *getFirstOp() {
return &((*static_cast<ConcreteOp *>(this)).getRegion().front().getOperations().front());
}
/// Common verifier for operation that implements atomic compare interface.
::llvm::LogicalResult verifyCommon() {
if ((*static_cast<ConcreteOp *>(this)).getRegion().getNumArguments() != 1)
return (*static_cast<ConcreteOp *>(this)).emitError("the region must accept exactly one argument");
Type elementType = (*static_cast<ConcreteOp *>(this)).getX().getType().getElementType();
if (elementType && elementType != (*static_cast<ConcreteOp *>(this)).getRegion().getArgument(0).getType()) {
return (*static_cast<ConcreteOp *>(this)).emitError("the type of the operand must be a pointer type whose "
"element type is the same as that of the region argument");
}
return mlir::success();
}
/// Common verifier of the required region for operation that implements
/// atomic compare interface.
::llvm::LogicalResult verifyRegionsCommon() {
mlir::Region &region = (*static_cast<ConcreteOp *>(this)).getRegion();
if (region.empty())
return (*static_cast<ConcreteOp *>(this)).emitError(
"region for atomic compare must not be empty");
mlir::Block &block = region.front();
if (block.empty())
return (*static_cast<ConcreteOp *>(this)).emitError(
"region body for atomic compare must not be empty");
// The region must contain at least a comparison operation and a
// terminator. A region with only a terminator is missing the
// required comparison logic.
if (block.getOperations().size() < 2)
return (*static_cast<ConcreteOp *>(this)).emitError(
"region must contain a comparison operation");
return mlir::success();
}
/// Common verifier for operator that implements atomic compare interface.
/// Checks that the comparison operation in the region uses:
/// 1) supported predicate for integer comparison : eq, slt, or sgt
/// 2) supported predicate for float comparison : oeq, oglt or lsgt
::llvm::LogicalResult verifyOperator() {
mlir::Region &region = (*static_cast<ConcreteOp *>(this)).getRegion();
if (region.empty())
return (*static_cast<ConcreteOp *>(this)).emitError(
"region for atomic compare must not be empty");
mlir::Block &block = region.front();
bool foundComparison = false;
for (mlir::Operation &op : block.getOperations()) {
llvm::StringRef opName = op.getName().getStringRef();
if (opName == "arith.cmpi" || opName == "llvm.icmp") {
foundComparison = true;
auto predAttr = op.getAttrOfType<mlir::IntegerAttr>("predicate");
if (predAttr) {
auto predName = mlir::arith::stringifyCmpIPredicate(
static_cast<mlir::arith::CmpIPredicate>(predAttr.getInt()));
if (predName != "eq" && predName != "slt" && predName != "sgt") {
return (*static_cast<ConcreteOp *>(this)).emitError(
"unsupported comparison operator '")
<< predName
<< "' in atomic compare region, "
"supported operators are: eq, slt, sgt";
}
}
break;
} else if (opName == "arith.cmpf" || opName == "llvm.fcmp") {
foundComparison = true;
auto predAttr = op.getAttrOfType<mlir::IntegerAttr>("predicate");
if (predAttr) {
auto predName = mlir::arith::stringifyCmpFPredicate(
static_cast<mlir::arith::CmpFPredicate>(predAttr.getInt()));
if (predName != "oeq" && predName != "ogt" && predName != "olt") {
return (*static_cast<ConcreteOp *>(this)).emitError(
"unsupported comparison operator '")
<< predName
<< "' in atomic compare region, "
"supported operators are: oeq, ogt, olt";
}
}
break;
} else if (opName == "fir.cmpc") {
foundComparison = true;
auto predAttr = op.getAttrOfType<mlir::IntegerAttr>("predicate");
if (predAttr) {
auto predName = mlir::arith::stringifyCmpFPredicate(
static_cast<mlir::arith::CmpFPredicate>(predAttr.getInt()));
if (predName != "oeq") {
return (*static_cast<ConcreteOp *>(this)).emitError(
"unsupported comparison operator '")
<< predName
<< "' in atomic compare region for complex type, "
"only 'oeq' is supported";
}
}
break;
}
}
if (!foundComparison)
return (*static_cast<ConcreteOp *>(this)).emitError(
"atomic compare region must contain a comparison operation "
"(arith.cmpi, arith.cmpf, llvm.icmp, llvm.fcmp, or fir.cmpc)");
return mlir::success();
}
};
} // namespace mlir::accomp::detail
namespace mlir::accomp {
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicReadOpInterfaceInterfaceTraits::Model<ConcreteOp>::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).verifyCommon();
}
template<typename ConcreteOp>
::mlir::Value detail::AtomicReadOpInterfaceInterfaceTraits::Model<ConcreteOp>::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getX();
}
template<typename ConcreteOp>
::mlir::Value detail::AtomicReadOpInterfaceInterfaceTraits::Model<ConcreteOp>::getV(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getV();
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicReadOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->verifyCommon(tablegen_opaque_val);
}
template<typename ConcreteOp>
::mlir::Value detail::AtomicReadOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->getX(tablegen_opaque_val);
}
template<typename ConcreteOp>
::mlir::Value detail::AtomicReadOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::getV(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->getV(tablegen_opaque_val);
}
template<typename ConcreteModel, typename ConcreteOp>
::llvm::LogicalResult detail::AtomicReadOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::verifyCommon(::mlir::Operation *tablegen_opaque_val) const {
if ((llvm::cast<ConcreteOp>(tablegen_opaque_val)).getX() == (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getV()) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError(
"read and write must not be to the same location for atomic reads");
}
return mlir::success();
}
} // namespace mlir::accomp
namespace mlir::accomp {
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicWriteOpInterfaceInterfaceTraits::Model<ConcreteOp>::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).verifyCommon();
}
template<typename ConcreteOp>
::mlir::Value detail::AtomicWriteOpInterfaceInterfaceTraits::Model<ConcreteOp>::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getX();
}
template<typename ConcreteOp>
::mlir::Value detail::AtomicWriteOpInterfaceInterfaceTraits::Model<ConcreteOp>::getExpr(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getExpr();
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicWriteOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->verifyCommon(tablegen_opaque_val);
}
template<typename ConcreteOp>
::mlir::Value detail::AtomicWriteOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->getX(tablegen_opaque_val);
}
template<typename ConcreteOp>
::mlir::Value detail::AtomicWriteOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::getExpr(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->getExpr(tablegen_opaque_val);
}
template<typename ConcreteModel, typename ConcreteOp>
::llvm::LogicalResult detail::AtomicWriteOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::verifyCommon(::mlir::Operation *tablegen_opaque_val) const {
mlir::Type elementType = (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getX().getType().getElementType();
if (elementType && elementType != (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getExpr().getType())
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError("address must dereference to value type");
return mlir::success();
}
} // namespace mlir::accomp
namespace mlir::accomp {
template<typename ConcreteOp>
::mlir::Value detail::AtomicUpdateOpInterfaceInterfaceTraits::Model<ConcreteOp>::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getX();
}
template<typename ConcreteOp>
::mlir::Operation *detail::AtomicUpdateOpInterfaceInterfaceTraits::Model<ConcreteOp>::getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getFirstOp();
}
template<typename ConcreteOp>
bool detail::AtomicUpdateOpInterfaceInterfaceTraits::Model<ConcreteOp>::isNoOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).isNoOp();
}
template<typename ConcreteOp>
::mlir::Value detail::AtomicUpdateOpInterfaceInterfaceTraits::Model<ConcreteOp>::getWriteOpVal(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getWriteOpVal();
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicUpdateOpInterfaceInterfaceTraits::Model<ConcreteOp>::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).verifyCommon();
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicUpdateOpInterfaceInterfaceTraits::Model<ConcreteOp>::verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).verifyRegionsCommon();
}
template<typename ConcreteOp>
::mlir::Value detail::AtomicUpdateOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->getX(tablegen_opaque_val);
}
template<typename ConcreteOp>
::mlir::Operation *detail::AtomicUpdateOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->getFirstOp(tablegen_opaque_val);
}
template<typename ConcreteOp>
bool detail::AtomicUpdateOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::isNoOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->isNoOp(tablegen_opaque_val);
}
template<typename ConcreteOp>
::mlir::Value detail::AtomicUpdateOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::getWriteOpVal(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->getWriteOpVal(tablegen_opaque_val);
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicUpdateOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->verifyCommon(tablegen_opaque_val);
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicUpdateOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->verifyRegionsCommon(tablegen_opaque_val);
}
template<typename ConcreteModel, typename ConcreteOp>
::mlir::Operation *detail::AtomicUpdateOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::getFirstOp(::mlir::Operation *tablegen_opaque_val) const {
return &((llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().front().getOperations().front());
}
template<typename ConcreteModel, typename ConcreteOp>
bool detail::AtomicUpdateOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::isNoOp(::mlir::Operation *tablegen_opaque_val) const {
// The atomic update is a no-op if the terminator is the first and only
// operation in its region.
mlir::Operation* terminator =
llvm::dyn_cast<mlir::RegionBranchTerminatorOpInterface>((llvm::cast<ConcreteOp>(tablegen_opaque_val)).getFirstOp());
return terminator && terminator->getOperands().front() ==
(llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().front().getArgument(0);
}
template<typename ConcreteModel, typename ConcreteOp>
::mlir::Value detail::AtomicUpdateOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::getWriteOpVal(::mlir::Operation *tablegen_opaque_val) const {
mlir::Operation* terminator =
llvm::dyn_cast<mlir::RegionBranchTerminatorOpInterface>((llvm::cast<ConcreteOp>(tablegen_opaque_val)).getFirstOp());
if (terminator && terminator->getOperands().front() !=
(llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().front().getArgument(0)) {
return terminator->getOperands().front();
}
return nullptr;
}
template<typename ConcreteModel, typename ConcreteOp>
::llvm::LogicalResult detail::AtomicUpdateOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::verifyCommon(::mlir::Operation *tablegen_opaque_val) const {
if ((llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().getNumArguments() != 1)
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError("the region must accept exactly one argument");
Type elementType = (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getX().getType().getElementType();
if (elementType && elementType != (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().getArgument(0).getType()) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError("the type of the operand must be a pointer type whose "
"element type is the same as that of the region argument");
}
return mlir::success();
}
template<typename ConcreteModel, typename ConcreteOp>
::llvm::LogicalResult detail::AtomicUpdateOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::verifyRegionsCommon(::mlir::Operation *tablegen_opaque_val) const {
mlir::Operation *terminator = (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().front().getTerminator();
if (terminator->getOperands().size() != 1)
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError("only updated value must be returned");
if (terminator->getOperands().front().getType() !=
(llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().getArgument(0).getType())
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError("input and yielded value must have the same type");
return mlir::success();
}
} // namespace mlir::accomp
namespace mlir::accomp {
template<typename ConcreteOp>
::mlir::Operation *detail::AtomicCaptureOpInterfaceInterfaceTraits::Model<ConcreteOp>::getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getFirstOp();
}
template<typename ConcreteOp>
::mlir::Operation *detail::AtomicCaptureOpInterfaceInterfaceTraits::Model<ConcreteOp>::getSecondOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getSecondOp();
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicCaptureOpInterfaceInterfaceTraits::Model<ConcreteOp>::verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).verifyRegionsCommon();
}
template<typename ConcreteOp>
::mlir::Operation *detail::AtomicCaptureOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->getFirstOp(tablegen_opaque_val);
}
template<typename ConcreteOp>
::mlir::Operation *detail::AtomicCaptureOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::getSecondOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->getSecondOp(tablegen_opaque_val);
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicCaptureOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->verifyRegionsCommon(tablegen_opaque_val);
}
template<typename ConcreteModel, typename ConcreteOp>
::mlir::Operation *detail::AtomicCaptureOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::getFirstOp(::mlir::Operation *tablegen_opaque_val) const {
return &((llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().front().getOperations().front());
}
template<typename ConcreteModel, typename ConcreteOp>
::mlir::Operation *detail::AtomicCaptureOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::getSecondOp(::mlir::Operation *tablegen_opaque_val) const {
auto &ops = (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().front().getOperations();
return ops.getNextNode(ops.front());
}
template<typename ConcreteModel, typename ConcreteOp>
::llvm::LogicalResult detail::AtomicCaptureOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::verifyRegionsCommon(::mlir::Operation *tablegen_opaque_val) const {
Block::OpListType &ops = (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().front().getOperations();
if (ops.size() != 3)
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError()
<< "expected three operations in atomic.capture region (one "
"terminator, and two atomic ops)";
auto &firstOp = ops.front();
auto &secondOp = *ops.getNextNode(firstOp);
auto firstReadStmt = dyn_cast<AtomicReadOpInterface>(firstOp);
auto firstUpdateStmt = dyn_cast<AtomicUpdateOpInterface>(firstOp);
auto secondReadStmt = dyn_cast<AtomicReadOpInterface>(secondOp);
auto secondUpdateStmt = dyn_cast<AtomicUpdateOpInterface>(secondOp);
auto secondWriteStmt = dyn_cast<AtomicWriteOpInterface>(secondOp);
if (!((firstUpdateStmt && secondReadStmt) ||
(firstReadStmt && secondUpdateStmt) ||
(firstReadStmt && secondWriteStmt)))
return ops.front().emitError()
<< "invalid sequence of operations in the capture region";
if (firstUpdateStmt && secondReadStmt &&
firstUpdateStmt.getX() != secondReadStmt.getX())
return firstUpdateStmt.emitError()
<< "updated variable in atomic.update must be captured in "
"second operation";
if (firstReadStmt && secondUpdateStmt &&
firstReadStmt.getX() != secondUpdateStmt.getX())
return firstReadStmt.emitError()
<< "captured variable in atomic.read must be updated in second "
"operation";
if (firstReadStmt && secondWriteStmt &&
firstReadStmt.getX() != secondWriteStmt.getX())
return firstReadStmt.emitError()
<< "captured variable in atomic.read must be updated in "
"second operation";
return mlir::success();
}
} // namespace mlir::accomp
namespace mlir::accomp {
template<typename ConcreteOp>
::mlir::Value detail::AtomicCompareOpInterfaceInterfaceTraits::Model<ConcreteOp>::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getX();
}
template<typename ConcreteOp>
::mlir::Operation *detail::AtomicCompareOpInterfaceInterfaceTraits::Model<ConcreteOp>::getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getFirstOp();
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::Model<ConcreteOp>::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).verifyCommon();
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::Model<ConcreteOp>::verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).verifyRegionsCommon();
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::Model<ConcreteOp>::verifyOperator(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).verifyOperator();
}
template<typename ConcreteOp>
::mlir::Value detail::AtomicCompareOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->getX(tablegen_opaque_val);
}
template<typename ConcreteOp>
::mlir::Operation *detail::AtomicCompareOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->getFirstOp(tablegen_opaque_val);
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->verifyCommon(tablegen_opaque_val);
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->verifyRegionsCommon(tablegen_opaque_val);
}
template<typename ConcreteOp>
::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::verifyOperator(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
return static_cast<const ConcreteOp *>(impl)->verifyOperator(tablegen_opaque_val);
}
template<typename ConcreteModel, typename ConcreteOp>
::mlir::Operation *detail::AtomicCompareOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::getFirstOp(::mlir::Operation *tablegen_opaque_val) const {
return &((llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().front().getOperations().front());
}
template<typename ConcreteModel, typename ConcreteOp>
::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::verifyCommon(::mlir::Operation *tablegen_opaque_val) const {
if ((llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().getNumArguments() != 1)
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError("the region must accept exactly one argument");
Type elementType = (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getX().getType().getElementType();
if (elementType && elementType != (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion().getArgument(0).getType()) {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError("the type of the operand must be a pointer type whose "
"element type is the same as that of the region argument");
}
return mlir::success();
}
template<typename ConcreteModel, typename ConcreteOp>
::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::verifyRegionsCommon(::mlir::Operation *tablegen_opaque_val) const {
mlir::Region &region = (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion();
if (region.empty())
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError(
"region for atomic compare must not be empty");
mlir::Block &block = region.front();
if (block.empty())
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError(
"region body for atomic compare must not be empty");
// The region must contain at least a comparison operation and a
// terminator. A region with only a terminator is missing the
// required comparison logic.
if (block.getOperations().size() < 2)
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError(
"region must contain a comparison operation");
return mlir::success();
}
template<typename ConcreteModel, typename ConcreteOp>
::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::ExternalModel<ConcreteModel, ConcreteOp>::verifyOperator(::mlir::Operation *tablegen_opaque_val) const {
mlir::Region &region = (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getRegion();
if (region.empty())
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError(
"region for atomic compare must not be empty");
mlir::Block &block = region.front();
bool foundComparison = false;
for (mlir::Operation &op : block.getOperations()) {
llvm::StringRef opName = op.getName().getStringRef();
if (opName == "arith.cmpi" || opName == "llvm.icmp") {
foundComparison = true;
auto predAttr = op.getAttrOfType<mlir::IntegerAttr>("predicate");
if (predAttr) {
auto predName = mlir::arith::stringifyCmpIPredicate(
static_cast<mlir::arith::CmpIPredicate>(predAttr.getInt()));
if (predName != "eq" && predName != "slt" && predName != "sgt") {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError(
"unsupported comparison operator '")
<< predName
<< "' in atomic compare region, "
"supported operators are: eq, slt, sgt";
}
}
break;
} else if (opName == "arith.cmpf" || opName == "llvm.fcmp") {
foundComparison = true;
auto predAttr = op.getAttrOfType<mlir::IntegerAttr>("predicate");
if (predAttr) {
auto predName = mlir::arith::stringifyCmpFPredicate(
static_cast<mlir::arith::CmpFPredicate>(predAttr.getInt()));
if (predName != "oeq" && predName != "ogt" && predName != "olt") {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError(
"unsupported comparison operator '")
<< predName
<< "' in atomic compare region, "
"supported operators are: oeq, ogt, olt";
}
}
break;
} else if (opName == "fir.cmpc") {
foundComparison = true;
auto predAttr = op.getAttrOfType<mlir::IntegerAttr>("predicate");
if (predAttr) {
auto predName = mlir::arith::stringifyCmpFPredicate(
static_cast<mlir::arith::CmpFPredicate>(predAttr.getInt()));
if (predName != "oeq") {
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError(
"unsupported comparison operator '")
<< predName
<< "' in atomic compare region for complex type, "
"only 'oeq' is supported";
}
}
break;
}
}
if (!foundComparison)
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).emitError(
"atomic compare region must contain a comparison operation "
"(arith.cmpi, arith.cmpf, llvm.icmp, llvm.fcmp, or fir.cmpc)");
return mlir::success();
}
} // namespace mlir::accomp