Fixes #88935 Toggling reduction by-ref broke when multiple reduction clauses were used. Decisions made for the by-ref status for later clauses could then invalidate decisions for earlier clauses. For example, ``` reduction(+:scalar,scalar2) reduction(+:array) ``` The first clause would choose by value reduction and generate by-value reduction regions, but then after this the second clause would force by-ref to support the array argument. But by the time the second clause is processed, the first clause has already had the wrong kind of reduction regions generated. This is solved by toggling whether a variable should be reduced by reference per variable. In the above example, this allows only `array` to be reduced by ref.
165 lines
6.0 KiB
C++
165 lines
6.0 KiB
C++
//===-- 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
|