//===-- Lower/OpenMP/ReductionProcessor.h -----------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
//
//===----------------------------------------------------------------------===//
#ifndef FORTRAN_LOWER_REDUCTIONPROCESSOR_H
#define FORTRAN_LOWER_REDUCTIONPROCESSOR_H
#include "Clauses.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Semantics/symbol.h"
#include "flang/Semantics/type.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/Types.h"
namespace mlir {
namespace omp {
class DeclareReductionOp;
} // namespace omp
} // namespace mlir
namespace Fortran {
namespace lower {
class AbstractConverter;
} // namespace lower
} // namespace Fortran
namespace Fortran {
namespace lower {
namespace omp {
class ReductionProcessor {
public:
// TODO: Move this enumeration to the OpenMP dialect
enum ReductionIdentifier {
ID,
USER_DEF_OP,
ADD,
SUBTRACT,
MULTIPLY,
AND,
OR,
EQV,
NEQV,
MAX,
MIN,
IAND,
IOR,
IEOR
};
static ReductionIdentifier
getReductionType(const omp::clause::ProcedureDesignator &pd);
static ReductionIdentifier
getReductionType(omp::clause::DefinedOperator::IntrinsicOperator intrinsicOp);
static bool
supportedIntrinsicProcReduction(const omp::clause::ProcedureDesignator &pd);
static const semantics::SourceName
getRealName(const semantics::Symbol *symbol);
static const semantics::SourceName
getRealName(const omp::clause::ProcedureDesignator &pd);
static std::string getReductionName(llvm::StringRef name,
const fir::KindMapping &kindMap,
mlir::Type ty, bool isByRef);
static std::string
getReductionName(omp::clause::DefinedOperator::IntrinsicOperator intrinsicOp,
const fir::KindMapping &kindMap, mlir::Type ty,
bool isByRef);
/// This function returns the identity value of the operator \p
/// reductionOpName. For example:
/// 0 + x = x,
/// 1 * x = x
static int getOperationIdentity(ReductionIdentifier redId,
mlir::Location loc);
static mlir::Value getReductionInitValue(mlir::Location loc, mlir::Type type,
ReductionIdentifier redId,
fir::FirOpBuilder &builder);
template <typename FloatOp, typename IntegerOp>
static mlir::Value getReductionOperation(fir::FirOpBuilder &builder,
mlir::Type type, mlir::Location loc,
mlir::Value op1, mlir::Value op2);
template <typename FloatOp, typename IntegerOp, typename ComplexOp>
static mlir::Value getReductionOperation(fir::FirOpBuilder &builder,
mlir::Type type, mlir::Location loc,
mlir::Value op1, mlir::Value op2);
static mlir::Value createScalarCombiner(fir::FirOpBuilder &builder,
mlir::Location loc,
ReductionIdentifier redId,
mlir::Type type, mlir::Value op1,
mlir::Value op2);
/// Creates an OpenMP reduction declaration and inserts it into the provided
/// symbol table. The declaration has a constant initializer with the neutral
/// value `initValue`, and the reduction combiner carried over from `reduce`.
/// TODO: add atomic region.
static mlir::omp::DeclareReductionOp
createDeclareReduction(fir::FirOpBuilder &builder,
llvm::StringRef reductionOpName,
const ReductionIdentifier redId, mlir::Type type,
mlir::Location loc, bool isByRef);
/// Creates a reduction declaration and associates it with an OpenMP block
/// directive.
static void addDeclareReduction(
mlir::Location currentLocation, lower::AbstractConverter &converter,
const omp::clause::Reduction &reduction,
llvm::SmallVectorImpl<mlir::Value> &reductionVars,
llvm::SmallVectorImpl<bool> &reduceVarByRef,
llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
llvm::SmallVectorImpl<const semantics::Symbol *> *reductionSymbols =
nullptr);
};
template <typename FloatOp, typename IntegerOp>
mlir::Value
ReductionProcessor::getReductionOperation(fir::FirOpBuilder &builder,
mlir::Type type, mlir::Location loc,
mlir::Value op1, mlir::Value op2) {
type = fir::unwrapRefType(type);
assert(type.isIntOrIndexOrFloat() &&
"only integer, float and complex types are currently supported");
if (type.isIntOrIndex())
return builder.create<IntegerOp>(loc, op1, op2);
return builder.create<FloatOp>(loc, op1, op2);
}
template <typename FloatOp, typename IntegerOp, typename ComplexOp>
mlir::Value
ReductionProcessor::getReductionOperation(fir::FirOpBuilder &builder,
mlir::Type type, mlir::Location loc,
mlir::Value op1, mlir::Value op2) {
assert((type.isIntOrIndexOrFloat() || fir::isa_complex(type)) &&
"only integer, float and complex types are currently supported");
if (type.isIntOrIndex())
return builder.create<IntegerOp>(loc, op1, op2);
if (fir::isa_real(type))
return builder.create<FloatOp>(loc, op1, op2);
return builder.create<ComplexOp>(loc, op1, op2);
}
} // namespace omp
} // namespace lower
} // namespace Fortran
#endif // FORTRAN_LOWER_REDUCTIONPROCESSOR_H