/*===- 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): /// /// /// } /// ``` 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 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 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 class ExternalModel : public FallbackModel { public: using ConcreteEntity = ConcreteOp; ::llvm::LogicalResult verifyCommon(::mlir::Operation *tablegen_opaque_val) const; }; }; template struct AtomicReadOpInterfaceTrait; } // namespace detail class AtomicReadOpInterface : public ::mlir::OpInterface { public: using ::mlir::OpInterface::OpInterface; template struct Trait : public detail::AtomicReadOpInterfaceTrait {}; /// 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 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 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 class ExternalModel : public FallbackModel { public: using ConcreteEntity = ConcreteOp; ::llvm::LogicalResult verifyCommon(::mlir::Operation *tablegen_opaque_val) const; }; }; template struct AtomicWriteOpInterfaceTrait; } // namespace detail class AtomicWriteOpInterface : public ::mlir::OpInterface { public: using ::mlir::OpInterface::OpInterface; template struct Trait : public detail::AtomicWriteOpInterfaceTrait {}; /// 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 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 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 class ExternalModel : public FallbackModel { 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 struct AtomicUpdateOpInterfaceTrait; } // namespace detail class AtomicUpdateOpInterface : public ::mlir::OpInterface { public: using ::mlir::OpInterface::OpInterface; template struct Trait : public detail::AtomicUpdateOpInterfaceTrait {}; /// 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 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 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 class ExternalModel : public FallbackModel { 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 struct AtomicCaptureOpInterfaceTrait; } // namespace detail class AtomicCaptureOpInterface : public ::mlir::OpInterface { public: using ::mlir::OpInterface::OpInterface; template struct Trait : public detail::AtomicCaptureOpInterfaceTrait {}; /// 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): /// /// /// } /// ``` 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 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 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 class ExternalModel : public FallbackModel { 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 struct AtomicCompareOpInterfaceTrait; } // namespace detail class AtomicCompareOpInterface : public ::mlir::OpInterface { public: using ::mlir::OpInterface::OpInterface; template struct Trait : public detail::AtomicCompareOpInterfaceTrait {}; /// 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 struct AtomicReadOpInterfaceTrait : public ::mlir::OpInterface::Trait { /// Common verifier for operation that implements atomic read interface. ::llvm::LogicalResult verifyCommon() { if ((*static_cast(this)).getX() == (*static_cast(this)).getV()) { return (*static_cast(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 struct AtomicWriteOpInterfaceTrait : public ::mlir::OpInterface::Trait { /// Common verifier for operation that implements atomic write interface. ::llvm::LogicalResult verifyCommon() { mlir::Type elementType = (*static_cast(this)).getX().getType().getElementType(); if (elementType && elementType != (*static_cast(this)).getExpr().getType()) return (*static_cast(this)).emitError("address must dereference to value type"); return mlir::success(); } }; } // namespace mlir::accomp::detail namespace mlir::accomp::detail { template struct AtomicUpdateOpInterfaceTrait : public ::mlir::OpInterface::Trait { /// Returns the first operation in atomic update region. ::mlir::Operation *getFirstOp() { return &((*static_cast(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((*static_cast(this)).getFirstOp()); return terminator && terminator->getOperands().front() == (*static_cast(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((*static_cast(this)).getFirstOp()); if (terminator && terminator->getOperands().front() != (*static_cast(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(this)).getRegion().getNumArguments() != 1) return (*static_cast(this)).emitError("the region must accept exactly one argument"); Type elementType = (*static_cast(this)).getX().getType().getElementType(); if (elementType && elementType != (*static_cast(this)).getRegion().getArgument(0).getType()) { return (*static_cast(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(this)).getRegion().front().getTerminator(); if (terminator->getOperands().size() != 1) return (*static_cast(this)).emitError("only updated value must be returned"); if (terminator->getOperands().front().getType() != (*static_cast(this)).getRegion().getArgument(0).getType()) return (*static_cast(this)).emitError("input and yielded value must have the same type"); return mlir::success(); } }; } // namespace mlir::accomp::detail namespace mlir::accomp::detail { template struct AtomicCaptureOpInterfaceTrait : public ::mlir::OpInterface::Trait { /// Returns the first operation in atomic capture region. ::mlir::Operation *getFirstOp() { return &((*static_cast(this)).getRegion().front().getOperations().front()); } /// Returns the second operation in atomic capture region. ::mlir::Operation *getSecondOp() { auto &ops = (*static_cast(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(this)).getRegion().front().getOperations(); if (ops.size() != 3) return (*static_cast(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(firstOp); auto firstUpdateStmt = dyn_cast(firstOp); auto secondReadStmt = dyn_cast(secondOp); auto secondUpdateStmt = dyn_cast(secondOp); auto secondWriteStmt = dyn_cast(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 struct AtomicCompareOpInterfaceTrait : public ::mlir::OpInterface::Trait { /// Returns the first operation in the atomic compare region. ::mlir::Operation *getFirstOp() { return &((*static_cast(this)).getRegion().front().getOperations().front()); } /// Common verifier for operation that implements atomic compare interface. ::llvm::LogicalResult verifyCommon() { if ((*static_cast(this)).getRegion().getNumArguments() != 1) return (*static_cast(this)).emitError("the region must accept exactly one argument"); Type elementType = (*static_cast(this)).getX().getType().getElementType(); if (elementType && elementType != (*static_cast(this)).getRegion().getArgument(0).getType()) { return (*static_cast(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 ®ion = (*static_cast(this)).getRegion(); if (region.empty()) return (*static_cast(this)).emitError( "region for atomic compare must not be empty"); mlir::Block &block = region.front(); if (block.empty()) return (*static_cast(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(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 ®ion = (*static_cast(this)).getRegion(); if (region.empty()) return (*static_cast(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("predicate"); if (predAttr) { auto predName = mlir::arith::stringifyCmpIPredicate( static_cast(predAttr.getInt())); if (predName != "eq" && predName != "slt" && predName != "sgt") { return (*static_cast(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("predicate"); if (predAttr) { auto predName = mlir::arith::stringifyCmpFPredicate( static_cast(predAttr.getInt())); if (predName != "oeq" && predName != "ogt" && predName != "olt") { return (*static_cast(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("predicate"); if (predAttr) { auto predName = mlir::arith::stringifyCmpFPredicate( static_cast(predAttr.getInt())); if (predName != "oeq") { return (*static_cast(this)).emitError( "unsupported comparison operator '") << predName << "' in atomic compare region for complex type, " "only 'oeq' is supported"; } } break; } } if (!foundComparison) return (*static_cast(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 ::llvm::LogicalResult detail::AtomicReadOpInterfaceInterfaceTraits::Model::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).verifyCommon(); } template ::mlir::Value detail::AtomicReadOpInterfaceInterfaceTraits::Model::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).getX(); } template ::mlir::Value detail::AtomicReadOpInterfaceInterfaceTraits::Model::getV(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).getV(); } template ::llvm::LogicalResult detail::AtomicReadOpInterfaceInterfaceTraits::FallbackModel::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->verifyCommon(tablegen_opaque_val); } template ::mlir::Value detail::AtomicReadOpInterfaceInterfaceTraits::FallbackModel::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->getX(tablegen_opaque_val); } template ::mlir::Value detail::AtomicReadOpInterfaceInterfaceTraits::FallbackModel::getV(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->getV(tablegen_opaque_val); } template ::llvm::LogicalResult detail::AtomicReadOpInterfaceInterfaceTraits::ExternalModel::verifyCommon(::mlir::Operation *tablegen_opaque_val) const { if ((llvm::cast(tablegen_opaque_val)).getX() == (llvm::cast(tablegen_opaque_val)).getV()) { return (llvm::cast(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 ::llvm::LogicalResult detail::AtomicWriteOpInterfaceInterfaceTraits::Model::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).verifyCommon(); } template ::mlir::Value detail::AtomicWriteOpInterfaceInterfaceTraits::Model::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).getX(); } template ::mlir::Value detail::AtomicWriteOpInterfaceInterfaceTraits::Model::getExpr(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).getExpr(); } template ::llvm::LogicalResult detail::AtomicWriteOpInterfaceInterfaceTraits::FallbackModel::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->verifyCommon(tablegen_opaque_val); } template ::mlir::Value detail::AtomicWriteOpInterfaceInterfaceTraits::FallbackModel::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->getX(tablegen_opaque_val); } template ::mlir::Value detail::AtomicWriteOpInterfaceInterfaceTraits::FallbackModel::getExpr(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->getExpr(tablegen_opaque_val); } template ::llvm::LogicalResult detail::AtomicWriteOpInterfaceInterfaceTraits::ExternalModel::verifyCommon(::mlir::Operation *tablegen_opaque_val) const { mlir::Type elementType = (llvm::cast(tablegen_opaque_val)).getX().getType().getElementType(); if (elementType && elementType != (llvm::cast(tablegen_opaque_val)).getExpr().getType()) return (llvm::cast(tablegen_opaque_val)).emitError("address must dereference to value type"); return mlir::success(); } } // namespace mlir::accomp namespace mlir::accomp { template ::mlir::Value detail::AtomicUpdateOpInterfaceInterfaceTraits::Model::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).getX(); } template ::mlir::Operation *detail::AtomicUpdateOpInterfaceInterfaceTraits::Model::getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).getFirstOp(); } template bool detail::AtomicUpdateOpInterfaceInterfaceTraits::Model::isNoOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).isNoOp(); } template ::mlir::Value detail::AtomicUpdateOpInterfaceInterfaceTraits::Model::getWriteOpVal(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).getWriteOpVal(); } template ::llvm::LogicalResult detail::AtomicUpdateOpInterfaceInterfaceTraits::Model::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).verifyCommon(); } template ::llvm::LogicalResult detail::AtomicUpdateOpInterfaceInterfaceTraits::Model::verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).verifyRegionsCommon(); } template ::mlir::Value detail::AtomicUpdateOpInterfaceInterfaceTraits::FallbackModel::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->getX(tablegen_opaque_val); } template ::mlir::Operation *detail::AtomicUpdateOpInterfaceInterfaceTraits::FallbackModel::getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->getFirstOp(tablegen_opaque_val); } template bool detail::AtomicUpdateOpInterfaceInterfaceTraits::FallbackModel::isNoOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->isNoOp(tablegen_opaque_val); } template ::mlir::Value detail::AtomicUpdateOpInterfaceInterfaceTraits::FallbackModel::getWriteOpVal(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->getWriteOpVal(tablegen_opaque_val); } template ::llvm::LogicalResult detail::AtomicUpdateOpInterfaceInterfaceTraits::FallbackModel::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->verifyCommon(tablegen_opaque_val); } template ::llvm::LogicalResult detail::AtomicUpdateOpInterfaceInterfaceTraits::FallbackModel::verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->verifyRegionsCommon(tablegen_opaque_val); } template ::mlir::Operation *detail::AtomicUpdateOpInterfaceInterfaceTraits::ExternalModel::getFirstOp(::mlir::Operation *tablegen_opaque_val) const { return &((llvm::cast(tablegen_opaque_val)).getRegion().front().getOperations().front()); } template bool detail::AtomicUpdateOpInterfaceInterfaceTraits::ExternalModel::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((llvm::cast(tablegen_opaque_val)).getFirstOp()); return terminator && terminator->getOperands().front() == (llvm::cast(tablegen_opaque_val)).getRegion().front().getArgument(0); } template ::mlir::Value detail::AtomicUpdateOpInterfaceInterfaceTraits::ExternalModel::getWriteOpVal(::mlir::Operation *tablegen_opaque_val) const { mlir::Operation* terminator = llvm::dyn_cast((llvm::cast(tablegen_opaque_val)).getFirstOp()); if (terminator && terminator->getOperands().front() != (llvm::cast(tablegen_opaque_val)).getRegion().front().getArgument(0)) { return terminator->getOperands().front(); } return nullptr; } template ::llvm::LogicalResult detail::AtomicUpdateOpInterfaceInterfaceTraits::ExternalModel::verifyCommon(::mlir::Operation *tablegen_opaque_val) const { if ((llvm::cast(tablegen_opaque_val)).getRegion().getNumArguments() != 1) return (llvm::cast(tablegen_opaque_val)).emitError("the region must accept exactly one argument"); Type elementType = (llvm::cast(tablegen_opaque_val)).getX().getType().getElementType(); if (elementType && elementType != (llvm::cast(tablegen_opaque_val)).getRegion().getArgument(0).getType()) { return (llvm::cast(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 ::llvm::LogicalResult detail::AtomicUpdateOpInterfaceInterfaceTraits::ExternalModel::verifyRegionsCommon(::mlir::Operation *tablegen_opaque_val) const { mlir::Operation *terminator = (llvm::cast(tablegen_opaque_val)).getRegion().front().getTerminator(); if (terminator->getOperands().size() != 1) return (llvm::cast(tablegen_opaque_val)).emitError("only updated value must be returned"); if (terminator->getOperands().front().getType() != (llvm::cast(tablegen_opaque_val)).getRegion().getArgument(0).getType()) return (llvm::cast(tablegen_opaque_val)).emitError("input and yielded value must have the same type"); return mlir::success(); } } // namespace mlir::accomp namespace mlir::accomp { template ::mlir::Operation *detail::AtomicCaptureOpInterfaceInterfaceTraits::Model::getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).getFirstOp(); } template ::mlir::Operation *detail::AtomicCaptureOpInterfaceInterfaceTraits::Model::getSecondOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).getSecondOp(); } template ::llvm::LogicalResult detail::AtomicCaptureOpInterfaceInterfaceTraits::Model::verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).verifyRegionsCommon(); } template ::mlir::Operation *detail::AtomicCaptureOpInterfaceInterfaceTraits::FallbackModel::getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->getFirstOp(tablegen_opaque_val); } template ::mlir::Operation *detail::AtomicCaptureOpInterfaceInterfaceTraits::FallbackModel::getSecondOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->getSecondOp(tablegen_opaque_val); } template ::llvm::LogicalResult detail::AtomicCaptureOpInterfaceInterfaceTraits::FallbackModel::verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->verifyRegionsCommon(tablegen_opaque_val); } template ::mlir::Operation *detail::AtomicCaptureOpInterfaceInterfaceTraits::ExternalModel::getFirstOp(::mlir::Operation *tablegen_opaque_val) const { return &((llvm::cast(tablegen_opaque_val)).getRegion().front().getOperations().front()); } template ::mlir::Operation *detail::AtomicCaptureOpInterfaceInterfaceTraits::ExternalModel::getSecondOp(::mlir::Operation *tablegen_opaque_val) const { auto &ops = (llvm::cast(tablegen_opaque_val)).getRegion().front().getOperations(); return ops.getNextNode(ops.front()); } template ::llvm::LogicalResult detail::AtomicCaptureOpInterfaceInterfaceTraits::ExternalModel::verifyRegionsCommon(::mlir::Operation *tablegen_opaque_val) const { Block::OpListType &ops = (llvm::cast(tablegen_opaque_val)).getRegion().front().getOperations(); if (ops.size() != 3) return (llvm::cast(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(firstOp); auto firstUpdateStmt = dyn_cast(firstOp); auto secondReadStmt = dyn_cast(secondOp); auto secondUpdateStmt = dyn_cast(secondOp); auto secondWriteStmt = dyn_cast(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 ::mlir::Value detail::AtomicCompareOpInterfaceInterfaceTraits::Model::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).getX(); } template ::mlir::Operation *detail::AtomicCompareOpInterfaceInterfaceTraits::Model::getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).getFirstOp(); } template ::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::Model::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).verifyCommon(); } template ::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::Model::verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).verifyRegionsCommon(); } template ::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::Model::verifyOperator(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).verifyOperator(); } template ::mlir::Value detail::AtomicCompareOpInterfaceInterfaceTraits::FallbackModel::getX(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->getX(tablegen_opaque_val); } template ::mlir::Operation *detail::AtomicCompareOpInterfaceInterfaceTraits::FallbackModel::getFirstOp(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->getFirstOp(tablegen_opaque_val); } template ::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::FallbackModel::verifyCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->verifyCommon(tablegen_opaque_val); } template ::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::FallbackModel::verifyRegionsCommon(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->verifyRegionsCommon(tablegen_opaque_val); } template ::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::FallbackModel::verifyOperator(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->verifyOperator(tablegen_opaque_val); } template ::mlir::Operation *detail::AtomicCompareOpInterfaceInterfaceTraits::ExternalModel::getFirstOp(::mlir::Operation *tablegen_opaque_val) const { return &((llvm::cast(tablegen_opaque_val)).getRegion().front().getOperations().front()); } template ::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::ExternalModel::verifyCommon(::mlir::Operation *tablegen_opaque_val) const { if ((llvm::cast(tablegen_opaque_val)).getRegion().getNumArguments() != 1) return (llvm::cast(tablegen_opaque_val)).emitError("the region must accept exactly one argument"); Type elementType = (llvm::cast(tablegen_opaque_val)).getX().getType().getElementType(); if (elementType && elementType != (llvm::cast(tablegen_opaque_val)).getRegion().getArgument(0).getType()) { return (llvm::cast(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 ::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::ExternalModel::verifyRegionsCommon(::mlir::Operation *tablegen_opaque_val) const { mlir::Region ®ion = (llvm::cast(tablegen_opaque_val)).getRegion(); if (region.empty()) return (llvm::cast(tablegen_opaque_val)).emitError( "region for atomic compare must not be empty"); mlir::Block &block = region.front(); if (block.empty()) return (llvm::cast(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(tablegen_opaque_val)).emitError( "region must contain a comparison operation"); return mlir::success(); } template ::llvm::LogicalResult detail::AtomicCompareOpInterfaceInterfaceTraits::ExternalModel::verifyOperator(::mlir::Operation *tablegen_opaque_val) const { mlir::Region ®ion = (llvm::cast(tablegen_opaque_val)).getRegion(); if (region.empty()) return (llvm::cast(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("predicate"); if (predAttr) { auto predName = mlir::arith::stringifyCmpIPredicate( static_cast(predAttr.getInt())); if (predName != "eq" && predName != "slt" && predName != "sgt") { return (llvm::cast(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("predicate"); if (predAttr) { auto predName = mlir::arith::stringifyCmpFPredicate( static_cast(predAttr.getInt())); if (predName != "oeq" && predName != "ogt" && predName != "olt") { return (llvm::cast(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("predicate"); if (predAttr) { auto predName = mlir::arith::stringifyCmpFPredicate( static_cast(predAttr.getInt())); if (predName != "oeq") { return (llvm::cast(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(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