xref: /llvm-project/flang/lib/Lower/OpenMP/ReductionProcessor.cpp (revision 8557a57c4b1a228ce63f2409dd5cc4c70a25e6fc)
14d4af15cSKareem Ergawy //===-- ReductionProcessor.cpp ----------------------------------*- C++ -*-===//
24d4af15cSKareem Ergawy //
34d4af15cSKareem Ergawy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44d4af15cSKareem Ergawy // See https://llvm.org/LICENSE.txt for license information.
54d4af15cSKareem Ergawy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64d4af15cSKareem Ergawy //
74d4af15cSKareem Ergawy //===----------------------------------------------------------------------===//
84d4af15cSKareem Ergawy //
94d4af15cSKareem Ergawy // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
104d4af15cSKareem Ergawy //
114d4af15cSKareem Ergawy //===----------------------------------------------------------------------===//
124d4af15cSKareem Ergawy 
134d4af15cSKareem Ergawy #include "ReductionProcessor.h"
144d4af15cSKareem Ergawy 
15*8557a57cSTom Eccles #include "PrivateReductionUtils.h"
164d4af15cSKareem Ergawy #include "flang/Lower/AbstractConverter.h"
17221f438aSMats Petersson #include "flang/Lower/ConvertType.h"
18698bf3daSSourabh Singh Tomar #include "flang/Lower/SymbolMap.h"
19221f438aSMats Petersson #include "flang/Optimizer/Builder/Complex.h"
20197f3ecfSTom Eccles #include "flang/Optimizer/Builder/HLFIRTools.h"
214d4af15cSKareem Ergawy #include "flang/Optimizer/Builder/Todo.h"
22f46f5a01STom Eccles #include "flang/Optimizer/Dialect/FIRType.h"
234d4af15cSKareem Ergawy #include "flang/Optimizer/HLFIR/HLFIROps.h"
246f068b9cSTom Eccles #include "flang/Optimizer/Support/FatalError.h"
254d4af15cSKareem Ergawy #include "flang/Parser/tools.h"
264d4af15cSKareem Ergawy #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
27f46f5a01STom Eccles #include "llvm/Support/CommandLine.h"
28f46f5a01STom Eccles 
29f46f5a01STom Eccles static llvm::cl::opt<bool> forceByrefReduction(
30f46f5a01STom Eccles     "force-byref-reduction",
31f46f5a01STom Eccles     llvm::cl::desc("Pass all reduction arguments by reference"),
32f46f5a01STom Eccles     llvm::cl::Hidden);
334d4af15cSKareem Ergawy 
344d4af15cSKareem Ergawy namespace Fortran {
354d4af15cSKareem Ergawy namespace lower {
364d4af15cSKareem Ergawy namespace omp {
374d4af15cSKareem Ergawy 
384d4af15cSKareem Ergawy ReductionProcessor::ReductionIdentifier ReductionProcessor::getReductionType(
3963e70c05SKrzysztof Parzyszek     const omp::clause::ProcedureDesignator &pd) {
404d4af15cSKareem Ergawy   auto redType = llvm::StringSwitch<std::optional<ReductionIdentifier>>(
418b18f2feSKrzysztof Parzyszek                      getRealName(pd.v.sym()).ToString())
424d4af15cSKareem Ergawy                      .Case("max", ReductionIdentifier::MAX)
434d4af15cSKareem Ergawy                      .Case("min", ReductionIdentifier::MIN)
444d4af15cSKareem Ergawy                      .Case("iand", ReductionIdentifier::IAND)
454d4af15cSKareem Ergawy                      .Case("ior", ReductionIdentifier::IOR)
464d4af15cSKareem Ergawy                      .Case("ieor", ReductionIdentifier::IEOR)
474d4af15cSKareem Ergawy                      .Default(std::nullopt);
484d4af15cSKareem Ergawy   assert(redType && "Invalid Reduction");
494d4af15cSKareem Ergawy   return *redType;
504d4af15cSKareem Ergawy }
514d4af15cSKareem Ergawy 
524d4af15cSKareem Ergawy ReductionProcessor::ReductionIdentifier ReductionProcessor::getReductionType(
5363e70c05SKrzysztof Parzyszek     omp::clause::DefinedOperator::IntrinsicOperator intrinsicOp) {
544d4af15cSKareem Ergawy   switch (intrinsicOp) {
5563e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::Add:
564d4af15cSKareem Ergawy     return ReductionIdentifier::ADD;
5763e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::Subtract:
584d4af15cSKareem Ergawy     return ReductionIdentifier::SUBTRACT;
5963e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::Multiply:
604d4af15cSKareem Ergawy     return ReductionIdentifier::MULTIPLY;
6163e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::AND:
624d4af15cSKareem Ergawy     return ReductionIdentifier::AND;
6363e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::EQV:
644d4af15cSKareem Ergawy     return ReductionIdentifier::EQV;
6563e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::OR:
664d4af15cSKareem Ergawy     return ReductionIdentifier::OR;
6763e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::NEQV:
684d4af15cSKareem Ergawy     return ReductionIdentifier::NEQV;
694d4af15cSKareem Ergawy   default:
704d4af15cSKareem Ergawy     llvm_unreachable("unexpected intrinsic operator in reduction");
714d4af15cSKareem Ergawy   }
724d4af15cSKareem Ergawy }
734d4af15cSKareem Ergawy 
744d4af15cSKareem Ergawy bool ReductionProcessor::supportedIntrinsicProcReduction(
7563e70c05SKrzysztof Parzyszek     const omp::clause::ProcedureDesignator &pd) {
768b18f2feSKrzysztof Parzyszek   semantics::Symbol *sym = pd.v.sym();
777a66e420SKrzysztof Parzyszek   if (!sym->GetUltimate().attrs().test(semantics::Attr::INTRINSIC))
784d4af15cSKareem Ergawy     return false;
7963e70c05SKrzysztof Parzyszek   auto redType = llvm::StringSwitch<bool>(getRealName(sym).ToString())
804d4af15cSKareem Ergawy                      .Case("max", true)
814d4af15cSKareem Ergawy                      .Case("min", true)
824d4af15cSKareem Ergawy                      .Case("iand", true)
834d4af15cSKareem Ergawy                      .Case("ior", true)
844d4af15cSKareem Ergawy                      .Case("ieor", true)
854d4af15cSKareem Ergawy                      .Default(false);
864d4af15cSKareem Ergawy   return redType;
874d4af15cSKareem Ergawy }
884d4af15cSKareem Ergawy 
893deaa77fSTom Eccles std::string
903deaa77fSTom Eccles ReductionProcessor::getReductionName(llvm::StringRef name,
913deaa77fSTom Eccles                                      const fir::KindMapping &kindMap,
92f46f5a01STom Eccles                                      mlir::Type ty, bool isByRef) {
93f46f5a01STom Eccles   ty = fir::unwrapRefType(ty);
94f46f5a01STom Eccles 
95f46f5a01STom Eccles   // extra string to distinguish reduction functions for variables passed by
96f46f5a01STom Eccles   // reference
97f46f5a01STom Eccles   llvm::StringRef byrefAddition{""};
98f46f5a01STom Eccles   if (isByRef)
99f46f5a01STom Eccles     byrefAddition = "_byref";
100f46f5a01STom Eccles 
1013deaa77fSTom Eccles   return fir::getTypeAsString(ty, kindMap, (name + byrefAddition).str());
1024d4af15cSKareem Ergawy }
1034d4af15cSKareem Ergawy 
1044d4af15cSKareem Ergawy std::string ReductionProcessor::getReductionName(
1053deaa77fSTom Eccles     omp::clause::DefinedOperator::IntrinsicOperator intrinsicOp,
1063deaa77fSTom Eccles     const fir::KindMapping &kindMap, mlir::Type ty, bool isByRef) {
1074d4af15cSKareem Ergawy   std::string reductionName;
1084d4af15cSKareem Ergawy 
1094d4af15cSKareem Ergawy   switch (intrinsicOp) {
11063e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::Add:
1114d4af15cSKareem Ergawy     reductionName = "add_reduction";
1124d4af15cSKareem Ergawy     break;
11363e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::Multiply:
1144d4af15cSKareem Ergawy     reductionName = "multiply_reduction";
1154d4af15cSKareem Ergawy     break;
11663e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::AND:
1174d4af15cSKareem Ergawy     return "and_reduction";
11863e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::EQV:
1194d4af15cSKareem Ergawy     return "eqv_reduction";
12063e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::OR:
1214d4af15cSKareem Ergawy     return "or_reduction";
12263e70c05SKrzysztof Parzyszek   case omp::clause::DefinedOperator::IntrinsicOperator::NEQV:
1234d4af15cSKareem Ergawy     return "neqv_reduction";
1244d4af15cSKareem Ergawy   default:
1254d4af15cSKareem Ergawy     reductionName = "other_reduction";
1264d4af15cSKareem Ergawy     break;
1274d4af15cSKareem Ergawy   }
1284d4af15cSKareem Ergawy 
1293deaa77fSTom Eccles   return getReductionName(reductionName, kindMap, ty, isByRef);
1304d4af15cSKareem Ergawy }
1314d4af15cSKareem Ergawy 
1324d4af15cSKareem Ergawy mlir::Value
1334d4af15cSKareem Ergawy ReductionProcessor::getReductionInitValue(mlir::Location loc, mlir::Type type,
1344d4af15cSKareem Ergawy                                           ReductionIdentifier redId,
1354d4af15cSKareem Ergawy                                           fir::FirOpBuilder &builder) {
136f46f5a01STom Eccles   type = fir::unwrapRefType(type);
1373deaa77fSTom Eccles   if (!fir::isa_integer(type) && !fir::isa_real(type) &&
138221f438aSMats Petersson       !fir::isa_complex(type) && !mlir::isa<fir::LogicalType>(type))
1393deaa77fSTom Eccles     TODO(loc, "Reduction of some types is not supported");
1404d4af15cSKareem Ergawy   switch (redId) {
1414d4af15cSKareem Ergawy   case ReductionIdentifier::MAX: {
142fac349a1SChristian Sigg     if (auto ty = mlir::dyn_cast<mlir::FloatType>(type)) {
1434d4af15cSKareem Ergawy       const llvm::fltSemantics &sem = ty.getFloatSemantics();
1444d4af15cSKareem Ergawy       return builder.createRealConstant(
1454d4af15cSKareem Ergawy           loc, type, llvm::APFloat::getLargest(sem, /*Negative=*/true));
1464d4af15cSKareem Ergawy     }
1474d4af15cSKareem Ergawy     unsigned bits = type.getIntOrFloatBitWidth();
1484d4af15cSKareem Ergawy     int64_t minInt = llvm::APInt::getSignedMinValue(bits).getSExtValue();
1494d4af15cSKareem Ergawy     return builder.createIntegerConstant(loc, type, minInt);
1504d4af15cSKareem Ergawy   }
1514d4af15cSKareem Ergawy   case ReductionIdentifier::MIN: {
152fac349a1SChristian Sigg     if (auto ty = mlir::dyn_cast<mlir::FloatType>(type)) {
1534d4af15cSKareem Ergawy       const llvm::fltSemantics &sem = ty.getFloatSemantics();
1544d4af15cSKareem Ergawy       return builder.createRealConstant(
1554d4af15cSKareem Ergawy           loc, type, llvm::APFloat::getLargest(sem, /*Negative=*/false));
1564d4af15cSKareem Ergawy     }
1574d4af15cSKareem Ergawy     unsigned bits = type.getIntOrFloatBitWidth();
1584d4af15cSKareem Ergawy     int64_t maxInt = llvm::APInt::getSignedMaxValue(bits).getSExtValue();
1594d4af15cSKareem Ergawy     return builder.createIntegerConstant(loc, type, maxInt);
1604d4af15cSKareem Ergawy   }
1614d4af15cSKareem Ergawy   case ReductionIdentifier::IOR: {
1624d4af15cSKareem Ergawy     unsigned bits = type.getIntOrFloatBitWidth();
1634d4af15cSKareem Ergawy     int64_t zeroInt = llvm::APInt::getZero(bits).getSExtValue();
1644d4af15cSKareem Ergawy     return builder.createIntegerConstant(loc, type, zeroInt);
1654d4af15cSKareem Ergawy   }
1664d4af15cSKareem Ergawy   case ReductionIdentifier::IEOR: {
1674d4af15cSKareem Ergawy     unsigned bits = type.getIntOrFloatBitWidth();
1684d4af15cSKareem Ergawy     int64_t zeroInt = llvm::APInt::getZero(bits).getSExtValue();
1694d4af15cSKareem Ergawy     return builder.createIntegerConstant(loc, type, zeroInt);
1704d4af15cSKareem Ergawy   }
1714d4af15cSKareem Ergawy   case ReductionIdentifier::IAND: {
1724d4af15cSKareem Ergawy     unsigned bits = type.getIntOrFloatBitWidth();
1734d4af15cSKareem Ergawy     int64_t allOnInt = llvm::APInt::getAllOnes(bits).getSExtValue();
1744d4af15cSKareem Ergawy     return builder.createIntegerConstant(loc, type, allOnInt);
1754d4af15cSKareem Ergawy   }
1764d4af15cSKareem Ergawy   case ReductionIdentifier::ADD:
1774d4af15cSKareem Ergawy   case ReductionIdentifier::MULTIPLY:
1784d4af15cSKareem Ergawy   case ReductionIdentifier::AND:
1794d4af15cSKareem Ergawy   case ReductionIdentifier::OR:
1804d4af15cSKareem Ergawy   case ReductionIdentifier::EQV:
1814d4af15cSKareem Ergawy   case ReductionIdentifier::NEQV:
182c4204c0bSjeanPerier     if (auto cplxTy = mlir::dyn_cast<mlir::ComplexType>(type)) {
183c4204c0bSjeanPerier       mlir::Type realTy = cplxTy.getElementType();
184221f438aSMats Petersson       mlir::Value initRe = builder.createRealConstant(
185221f438aSMats Petersson           loc, realTy, getOperationIdentity(redId, loc));
186221f438aSMats Petersson       mlir::Value initIm = builder.createRealConstant(loc, realTy, 0);
187221f438aSMats Petersson 
188221f438aSMats Petersson       return fir::factory::Complex{builder, loc}.createComplex(type, initRe,
189221f438aSMats Petersson                                                                initIm);
190221f438aSMats Petersson     }
191fac349a1SChristian Sigg     if (mlir::isa<mlir::FloatType>(type))
1924d4af15cSKareem Ergawy       return builder.create<mlir::arith::ConstantOp>(
1934d4af15cSKareem Ergawy           loc, type,
1944d4af15cSKareem Ergawy           builder.getFloatAttr(type, (double)getOperationIdentity(redId, loc)));
1954d4af15cSKareem Ergawy 
196fac349a1SChristian Sigg     if (mlir::isa<fir::LogicalType>(type)) {
1974d4af15cSKareem Ergawy       mlir::Value intConst = builder.create<mlir::arith::ConstantOp>(
1984d4af15cSKareem Ergawy           loc, builder.getI1Type(),
1994d4af15cSKareem Ergawy           builder.getIntegerAttr(builder.getI1Type(),
2004d4af15cSKareem Ergawy                                  getOperationIdentity(redId, loc)));
2014d4af15cSKareem Ergawy       return builder.createConvert(loc, type, intConst);
2024d4af15cSKareem Ergawy     }
2034d4af15cSKareem Ergawy 
2044d4af15cSKareem Ergawy     return builder.create<mlir::arith::ConstantOp>(
2054d4af15cSKareem Ergawy         loc, type,
2064d4af15cSKareem Ergawy         builder.getIntegerAttr(type, getOperationIdentity(redId, loc)));
2074d4af15cSKareem Ergawy   case ReductionIdentifier::ID:
2084d4af15cSKareem Ergawy   case ReductionIdentifier::USER_DEF_OP:
2094d4af15cSKareem Ergawy   case ReductionIdentifier::SUBTRACT:
2104d4af15cSKareem Ergawy     TODO(loc, "Reduction of some identifier types is not supported");
2114d4af15cSKareem Ergawy   }
2124d4af15cSKareem Ergawy   llvm_unreachable("Unhandled Reduction identifier : getReductionInitValue");
2134d4af15cSKareem Ergawy }
2144d4af15cSKareem Ergawy 
2154d4af15cSKareem Ergawy mlir::Value ReductionProcessor::createScalarCombiner(
2164d4af15cSKareem Ergawy     fir::FirOpBuilder &builder, mlir::Location loc, ReductionIdentifier redId,
2174d4af15cSKareem Ergawy     mlir::Type type, mlir::Value op1, mlir::Value op2) {
2184d4af15cSKareem Ergawy   mlir::Value reductionOp;
219f46f5a01STom Eccles   type = fir::unwrapRefType(type);
2204d4af15cSKareem Ergawy   switch (redId) {
2214d4af15cSKareem Ergawy   case ReductionIdentifier::MAX:
2224d4af15cSKareem Ergawy     reductionOp =
2230c455ee3SJan Leyonberg         getReductionOperation<mlir::arith::MaxNumFOp, mlir::arith::MaxSIOp>(
2244d4af15cSKareem Ergawy             builder, type, loc, op1, op2);
2254d4af15cSKareem Ergawy     break;
2264d4af15cSKareem Ergawy   case ReductionIdentifier::MIN:
2274d4af15cSKareem Ergawy     reductionOp =
2280c455ee3SJan Leyonberg         getReductionOperation<mlir::arith::MinNumFOp, mlir::arith::MinSIOp>(
2294d4af15cSKareem Ergawy             builder, type, loc, op1, op2);
2304d4af15cSKareem Ergawy     break;
2314d4af15cSKareem Ergawy   case ReductionIdentifier::IOR:
2324d4af15cSKareem Ergawy     assert((type.isIntOrIndex()) && "only integer is expected");
2334d4af15cSKareem Ergawy     reductionOp = builder.create<mlir::arith::OrIOp>(loc, op1, op2);
2344d4af15cSKareem Ergawy     break;
2354d4af15cSKareem Ergawy   case ReductionIdentifier::IEOR:
2364d4af15cSKareem Ergawy     assert((type.isIntOrIndex()) && "only integer is expected");
2374d4af15cSKareem Ergawy     reductionOp = builder.create<mlir::arith::XOrIOp>(loc, op1, op2);
2384d4af15cSKareem Ergawy     break;
2394d4af15cSKareem Ergawy   case ReductionIdentifier::IAND:
2404d4af15cSKareem Ergawy     assert((type.isIntOrIndex()) && "only integer is expected");
2414d4af15cSKareem Ergawy     reductionOp = builder.create<mlir::arith::AndIOp>(loc, op1, op2);
2424d4af15cSKareem Ergawy     break;
2434d4af15cSKareem Ergawy   case ReductionIdentifier::ADD:
2444d4af15cSKareem Ergawy     reductionOp =
245221f438aSMats Petersson         getReductionOperation<mlir::arith::AddFOp, mlir::arith::AddIOp,
246221f438aSMats Petersson                               fir::AddcOp>(builder, type, loc, op1, op2);
2474d4af15cSKareem Ergawy     break;
2484d4af15cSKareem Ergawy   case ReductionIdentifier::MULTIPLY:
2494d4af15cSKareem Ergawy     reductionOp =
250221f438aSMats Petersson         getReductionOperation<mlir::arith::MulFOp, mlir::arith::MulIOp,
251221f438aSMats Petersson                               fir::MulcOp>(builder, type, loc, op1, op2);
2524d4af15cSKareem Ergawy     break;
2534d4af15cSKareem Ergawy   case ReductionIdentifier::AND: {
2544d4af15cSKareem Ergawy     mlir::Value op1I1 = builder.createConvert(loc, builder.getI1Type(), op1);
2554d4af15cSKareem Ergawy     mlir::Value op2I1 = builder.createConvert(loc, builder.getI1Type(), op2);
2564d4af15cSKareem Ergawy 
2574d4af15cSKareem Ergawy     mlir::Value andiOp = builder.create<mlir::arith::AndIOp>(loc, op1I1, op2I1);
2584d4af15cSKareem Ergawy 
2594d4af15cSKareem Ergawy     reductionOp = builder.createConvert(loc, type, andiOp);
2604d4af15cSKareem Ergawy     break;
2614d4af15cSKareem Ergawy   }
2624d4af15cSKareem Ergawy   case ReductionIdentifier::OR: {
2634d4af15cSKareem Ergawy     mlir::Value op1I1 = builder.createConvert(loc, builder.getI1Type(), op1);
2644d4af15cSKareem Ergawy     mlir::Value op2I1 = builder.createConvert(loc, builder.getI1Type(), op2);
2654d4af15cSKareem Ergawy 
2664d4af15cSKareem Ergawy     mlir::Value oriOp = builder.create<mlir::arith::OrIOp>(loc, op1I1, op2I1);
2674d4af15cSKareem Ergawy 
2684d4af15cSKareem Ergawy     reductionOp = builder.createConvert(loc, type, oriOp);
2694d4af15cSKareem Ergawy     break;
2704d4af15cSKareem Ergawy   }
2714d4af15cSKareem Ergawy   case ReductionIdentifier::EQV: {
2724d4af15cSKareem Ergawy     mlir::Value op1I1 = builder.createConvert(loc, builder.getI1Type(), op1);
2734d4af15cSKareem Ergawy     mlir::Value op2I1 = builder.createConvert(loc, builder.getI1Type(), op2);
2744d4af15cSKareem Ergawy 
2754d4af15cSKareem Ergawy     mlir::Value cmpiOp = builder.create<mlir::arith::CmpIOp>(
2764d4af15cSKareem Ergawy         loc, mlir::arith::CmpIPredicate::eq, op1I1, op2I1);
2774d4af15cSKareem Ergawy 
2784d4af15cSKareem Ergawy     reductionOp = builder.createConvert(loc, type, cmpiOp);
2794d4af15cSKareem Ergawy     break;
2804d4af15cSKareem Ergawy   }
2814d4af15cSKareem Ergawy   case ReductionIdentifier::NEQV: {
2824d4af15cSKareem Ergawy     mlir::Value op1I1 = builder.createConvert(loc, builder.getI1Type(), op1);
2834d4af15cSKareem Ergawy     mlir::Value op2I1 = builder.createConvert(loc, builder.getI1Type(), op2);
2844d4af15cSKareem Ergawy 
2854d4af15cSKareem Ergawy     mlir::Value cmpiOp = builder.create<mlir::arith::CmpIOp>(
2864d4af15cSKareem Ergawy         loc, mlir::arith::CmpIPredicate::ne, op1I1, op2I1);
2874d4af15cSKareem Ergawy 
2884d4af15cSKareem Ergawy     reductionOp = builder.createConvert(loc, type, cmpiOp);
2894d4af15cSKareem Ergawy     break;
2904d4af15cSKareem Ergawy   }
2914d4af15cSKareem Ergawy   default:
2924d4af15cSKareem Ergawy     TODO(loc, "Reduction of some intrinsic operators is not supported");
2934d4af15cSKareem Ergawy   }
2944d4af15cSKareem Ergawy 
2954d4af15cSKareem Ergawy   return reductionOp;
2964d4af15cSKareem Ergawy }
2974d4af15cSKareem Ergawy 
298197f3ecfSTom Eccles /// Create reduction combiner region for reduction variables which are boxed
299197f3ecfSTom Eccles /// arrays
300197f3ecfSTom Eccles static void genBoxCombiner(fir::FirOpBuilder &builder, mlir::Location loc,
301197f3ecfSTom Eccles                            ReductionProcessor::ReductionIdentifier redId,
302197f3ecfSTom Eccles                            fir::BaseBoxType boxTy, mlir::Value lhs,
303197f3ecfSTom Eccles                            mlir::Value rhs) {
3048cc34fadSTom Eccles   fir::SequenceType seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(
3058cc34fadSTom Eccles       fir::unwrapRefType(boxTy.getEleTy()));
3068cc34fadSTom Eccles   fir::HeapType heapTy =
3078cc34fadSTom Eccles       mlir::dyn_cast_or_null<fir::HeapType>(boxTy.getEleTy());
308b6b0f975STom Eccles   fir::PointerType ptrTy =
309b6b0f975STom Eccles       mlir::dyn_cast_or_null<fir::PointerType>(boxTy.getEleTy());
310b6b0f975STom Eccles   if ((!seqTy || seqTy.hasUnknownShape()) && !heapTy && !ptrTy)
311197f3ecfSTom Eccles     TODO(loc, "Unsupported boxed type in OpenMP reduction");
312197f3ecfSTom Eccles 
313197f3ecfSTom Eccles   // load fir.ref<fir.box<...>>
314197f3ecfSTom Eccles   mlir::Value lhsAddr = lhs;
315197f3ecfSTom Eccles   lhs = builder.create<fir::LoadOp>(loc, lhs);
316197f3ecfSTom Eccles   rhs = builder.create<fir::LoadOp>(loc, rhs);
317197f3ecfSTom Eccles 
318b6b0f975STom Eccles   if ((heapTy || ptrTy) && !seqTy) {
3198cc34fadSTom Eccles     // get box contents (heap pointers)
3208cc34fadSTom Eccles     lhs = builder.create<fir::BoxAddrOp>(loc, lhs);
3218cc34fadSTom Eccles     rhs = builder.create<fir::BoxAddrOp>(loc, rhs);
3228cc34fadSTom Eccles     mlir::Value lhsValAddr = lhs;
3238cc34fadSTom Eccles 
3248cc34fadSTom Eccles     // load heap pointers
3258cc34fadSTom Eccles     lhs = builder.create<fir::LoadOp>(loc, lhs);
3268cc34fadSTom Eccles     rhs = builder.create<fir::LoadOp>(loc, rhs);
3278cc34fadSTom Eccles 
328b6b0f975STom Eccles     mlir::Type eleTy = heapTy ? heapTy.getEleTy() : ptrTy.getEleTy();
329b6b0f975STom Eccles 
3308cc34fadSTom Eccles     mlir::Value result = ReductionProcessor::createScalarCombiner(
331b6b0f975STom Eccles         builder, loc, redId, eleTy, lhs, rhs);
3328cc34fadSTom Eccles     builder.create<fir::StoreOp>(loc, result, lhsValAddr);
3338cc34fadSTom Eccles     builder.create<mlir::omp::YieldOp>(loc, lhsAddr);
3348cc34fadSTom Eccles     return;
3358cc34fadSTom Eccles   }
3368cc34fadSTom Eccles 
33718bf0c3cSTom Eccles   fir::ShapeShiftOp shapeShift = getShapeShift(builder, loc, lhs);
338197f3ecfSTom Eccles 
339197f3ecfSTom Eccles   // Iterate over array elements, applying the equivalent scalar reduction:
340197f3ecfSTom Eccles 
3418cc34fadSTom Eccles   // F2018 5.4.10.2: Unallocated allocatable variables may not be referenced
3428cc34fadSTom Eccles   // and so no null check is needed here before indexing into the (possibly
3438cc34fadSTom Eccles   // allocatable) arrays.
3448cc34fadSTom Eccles 
345197f3ecfSTom Eccles   // A hlfir::elemental here gets inlined with a temporary so create the
346197f3ecfSTom Eccles   // loop nest directly.
347197f3ecfSTom Eccles   // This function already controls all of the code in this region so we
348197f3ecfSTom Eccles   // know this won't miss any opportuinties for clever elemental inlining
34918bf0c3cSTom Eccles   hlfir::LoopNest nest = hlfir::genLoopNest(
35018bf0c3cSTom Eccles       loc, builder, shapeShift.getExtents(), /*isUnordered=*/true);
3518bb21ae6SIvan R. Ivanov   builder.setInsertionPointToStart(nest.body);
352197f3ecfSTom Eccles   mlir::Type refTy = fir::ReferenceType::get(seqTy.getEleTy());
353197f3ecfSTom Eccles   auto lhsEleAddr = builder.create<fir::ArrayCoorOp>(
354197f3ecfSTom Eccles       loc, refTy, lhs, shapeShift, /*slice=*/mlir::Value{},
355197f3ecfSTom Eccles       nest.oneBasedIndices, /*typeparms=*/mlir::ValueRange{});
356197f3ecfSTom Eccles   auto rhsEleAddr = builder.create<fir::ArrayCoorOp>(
357197f3ecfSTom Eccles       loc, refTy, rhs, shapeShift, /*slice=*/mlir::Value{},
358197f3ecfSTom Eccles       nest.oneBasedIndices, /*typeparms=*/mlir::ValueRange{});
359197f3ecfSTom Eccles   auto lhsEle = builder.create<fir::LoadOp>(loc, lhsEleAddr);
360197f3ecfSTom Eccles   auto rhsEle = builder.create<fir::LoadOp>(loc, rhsEleAddr);
361197f3ecfSTom Eccles   mlir::Value scalarReduction = ReductionProcessor::createScalarCombiner(
362197f3ecfSTom Eccles       builder, loc, redId, refTy, lhsEle, rhsEle);
363197f3ecfSTom Eccles   builder.create<fir::StoreOp>(loc, scalarReduction, lhsEleAddr);
364197f3ecfSTom Eccles 
3658bb21ae6SIvan R. Ivanov   builder.setInsertionPointAfter(nest.outerOp);
366197f3ecfSTom Eccles   builder.create<mlir::omp::YieldOp>(loc, lhsAddr);
367197f3ecfSTom Eccles }
368197f3ecfSTom Eccles 
369197f3ecfSTom Eccles // generate combiner region for reduction operations
370197f3ecfSTom Eccles static void genCombiner(fir::FirOpBuilder &builder, mlir::Location loc,
371197f3ecfSTom Eccles                         ReductionProcessor::ReductionIdentifier redId,
372197f3ecfSTom Eccles                         mlir::Type ty, mlir::Value lhs, mlir::Value rhs,
373197f3ecfSTom Eccles                         bool isByRef) {
374197f3ecfSTom Eccles   ty = fir::unwrapRefType(ty);
375197f3ecfSTom Eccles 
376197f3ecfSTom Eccles   if (fir::isa_trivial(ty)) {
377197f3ecfSTom Eccles     mlir::Value lhsLoaded = builder.loadIfRef(loc, lhs);
378197f3ecfSTom Eccles     mlir::Value rhsLoaded = builder.loadIfRef(loc, rhs);
379197f3ecfSTom Eccles 
380197f3ecfSTom Eccles     mlir::Value result = ReductionProcessor::createScalarCombiner(
381197f3ecfSTom Eccles         builder, loc, redId, ty, lhsLoaded, rhsLoaded);
382197f3ecfSTom Eccles     if (isByRef) {
383197f3ecfSTom Eccles       builder.create<fir::StoreOp>(loc, result, lhs);
384197f3ecfSTom Eccles       builder.create<mlir::omp::YieldOp>(loc, lhs);
385197f3ecfSTom Eccles     } else {
386197f3ecfSTom Eccles       builder.create<mlir::omp::YieldOp>(loc, result);
387197f3ecfSTom Eccles     }
388197f3ecfSTom Eccles     return;
389197f3ecfSTom Eccles   }
390197f3ecfSTom Eccles   // all arrays should have been boxed
391197f3ecfSTom Eccles   if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty)) {
392197f3ecfSTom Eccles     genBoxCombiner(builder, loc, redId, boxTy, lhs, rhs);
393197f3ecfSTom Eccles     return;
394197f3ecfSTom Eccles   }
395197f3ecfSTom Eccles 
396197f3ecfSTom Eccles   TODO(loc, "OpenMP genCombiner for unsupported reduction variable type");
397197f3ecfSTom Eccles }
398197f3ecfSTom Eccles 
3998cc34fadSTom Eccles // like fir::unwrapSeqOrBoxedSeqType except it also works for non-sequence boxes
4008cc34fadSTom Eccles static mlir::Type unwrapSeqOrBoxedType(mlir::Type ty) {
401fac349a1SChristian Sigg   if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty))
4028cc34fadSTom Eccles     return seqTy.getEleTy();
403fac349a1SChristian Sigg   if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty)) {
4048cc34fadSTom Eccles     auto eleTy = fir::unwrapRefType(boxTy.getEleTy());
405fac349a1SChristian Sigg     if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(eleTy))
4068cc34fadSTom Eccles       return seqTy.getEleTy();
4078cc34fadSTom Eccles     return eleTy;
4088cc34fadSTom Eccles   }
4098cc34fadSTom Eccles   return ty;
4108cc34fadSTom Eccles }
4118cc34fadSTom Eccles 
412f2027a93STom Eccles static void createReductionAllocAndInitRegions(
413f2027a93STom Eccles     fir::FirOpBuilder &builder, mlir::Location loc,
4146f068b9cSTom Eccles     mlir::omp::DeclareReductionOp &reductionDecl,
415f2027a93STom Eccles     const ReductionProcessor::ReductionIdentifier redId, mlir::Type type,
416f2027a93STom Eccles     bool isByRef) {
417f2027a93STom Eccles   auto yield = [&](mlir::Value ret) {
418f2027a93STom Eccles     builder.create<mlir::omp::YieldOp>(loc, ret);
419f2027a93STom Eccles   };
420f2027a93STom Eccles 
421f2027a93STom Eccles   mlir::Block *allocBlock = nullptr;
422f2027a93STom Eccles   mlir::Block *initBlock = nullptr;
423f2027a93STom Eccles   if (isByRef) {
424f2027a93STom Eccles     allocBlock =
425f2027a93STom Eccles         builder.createBlock(&reductionDecl.getAllocRegion(),
426f2027a93STom Eccles                             reductionDecl.getAllocRegion().end(), {}, {});
427f2027a93STom Eccles     initBlock = builder.createBlock(&reductionDecl.getInitializerRegion(),
428f2027a93STom Eccles                                     reductionDecl.getInitializerRegion().end(),
429f2027a93STom Eccles                                     {type, type}, {loc, loc});
430f2027a93STom Eccles   } else {
431f2027a93STom Eccles     initBlock = builder.createBlock(&reductionDecl.getInitializerRegion(),
432f2027a93STom Eccles                                     reductionDecl.getInitializerRegion().end(),
433f2027a93STom Eccles                                     {type}, {loc});
434f2027a93STom Eccles   }
435f2027a93STom Eccles 
436197f3ecfSTom Eccles   mlir::Type ty = fir::unwrapRefType(type);
437f2027a93STom Eccles   builder.setInsertionPointToEnd(initBlock);
438197f3ecfSTom Eccles   mlir::Value initValue = ReductionProcessor::getReductionInitValue(
4398cc34fadSTom Eccles       loc, unwrapSeqOrBoxedType(ty), redId, builder);
440197f3ecfSTom Eccles 
441*8557a57cSTom Eccles   if (isByRef) {
442*8557a57cSTom Eccles     populateByRefInitAndCleanupRegions(builder, loc, type, initValue, initBlock,
443*8557a57cSTom Eccles                                        reductionDecl.getInitializerAllocArg(),
444*8557a57cSTom Eccles                                        reductionDecl.getInitializerMoldArg(),
445*8557a57cSTom Eccles                                        reductionDecl.getCleanupRegion());
446*8557a57cSTom Eccles   }
447*8557a57cSTom Eccles 
448197f3ecfSTom Eccles   if (fir::isa_trivial(ty)) {
449197f3ecfSTom Eccles     if (isByRef) {
450f2027a93STom Eccles       // alloc region
451f2027a93STom Eccles       builder.setInsertionPointToEnd(allocBlock);
452197f3ecfSTom Eccles       mlir::Value alloca = builder.create<fir::AllocaOp>(loc, ty);
453f2027a93STom Eccles       yield(alloca);
454f2027a93STom Eccles       return;
455197f3ecfSTom Eccles     }
456197f3ecfSTom Eccles     // by val
457f2027a93STom Eccles     yield(initValue);
458f2027a93STom Eccles     return;
459197f3ecfSTom Eccles   }
460*8557a57cSTom Eccles   assert(isByRef && "passing non-trivial types by val is unsupported");
461f2027a93STom Eccles 
462f2027a93STom Eccles   // alloc region
463f2027a93STom Eccles   builder.setInsertionPointToEnd(allocBlock);
4648cc34fadSTom Eccles   mlir::Value boxAlloca = builder.create<fir::AllocaOp>(loc, ty);
465f2027a93STom Eccles   yield(boxAlloca);
466f2027a93STom Eccles }
467f2027a93STom Eccles 
468d84252e0SSergio Afonso mlir::omp::DeclareReductionOp ReductionProcessor::createDeclareReduction(
4694d4af15cSKareem Ergawy     fir::FirOpBuilder &builder, llvm::StringRef reductionOpName,
470f46f5a01STom Eccles     const ReductionIdentifier redId, mlir::Type type, mlir::Location loc,
471f46f5a01STom Eccles     bool isByRef) {
4724d4af15cSKareem Ergawy   mlir::OpBuilder::InsertionGuard guard(builder);
4734d4af15cSKareem Ergawy   mlir::ModuleOp module = builder.getModule();
4744d4af15cSKareem Ergawy 
4753deaa77fSTom Eccles   assert(!reductionOpName.empty());
476197f3ecfSTom Eccles 
4774d4af15cSKareem Ergawy   auto decl =
478d84252e0SSergio Afonso       module.lookupSymbol<mlir::omp::DeclareReductionOp>(reductionOpName);
4794d4af15cSKareem Ergawy   if (decl)
4804d4af15cSKareem Ergawy     return decl;
4814d4af15cSKareem Ergawy 
4824d4af15cSKareem Ergawy   mlir::OpBuilder modBuilder(module.getBodyRegion());
483f46f5a01STom Eccles   mlir::Type valTy = fir::unwrapRefType(type);
484f46f5a01STom Eccles   if (!isByRef)
485f46f5a01STom Eccles     type = valTy;
4864d4af15cSKareem Ergawy 
487d84252e0SSergio Afonso   decl = modBuilder.create<mlir::omp::DeclareReductionOp>(loc, reductionOpName,
4884d4af15cSKareem Ergawy                                                           type);
489f2027a93STom Eccles   createReductionAllocAndInitRegions(builder, loc, decl, redId, type, isByRef);
4904d4af15cSKareem Ergawy 
4914d4af15cSKareem Ergawy   builder.createBlock(&decl.getReductionRegion(),
4924d4af15cSKareem Ergawy                       decl.getReductionRegion().end(), {type, type},
4934d4af15cSKareem Ergawy                       {loc, loc});
4944d4af15cSKareem Ergawy 
4954d4af15cSKareem Ergawy   builder.setInsertionPointToEnd(&decl.getReductionRegion().back());
4964d4af15cSKareem Ergawy   mlir::Value op1 = decl.getReductionRegion().front().getArgument(0);
4974d4af15cSKareem Ergawy   mlir::Value op2 = decl.getReductionRegion().front().getArgument(1);
498197f3ecfSTom Eccles   genCombiner(builder, loc, redId, type, op1, op2, isByRef);
4994d4af15cSKareem Ergawy 
5004d4af15cSKareem Ergawy   return decl;
5014d4af15cSKareem Ergawy }
5024d4af15cSKareem Ergawy 
50374a87548STom Eccles static bool doReductionByRef(mlir::Value reductionVar) {
504f46f5a01STom Eccles   if (forceByrefReduction)
505f46f5a01STom Eccles     return true;
506f46f5a01STom Eccles 
507f46f5a01STom Eccles   if (auto declare =
508f46f5a01STom Eccles           mlir::dyn_cast<hlfir::DeclareOp>(reductionVar.getDefiningOp()))
509f46f5a01STom Eccles     reductionVar = declare.getMemref();
510f46f5a01STom Eccles 
511f46f5a01STom Eccles   if (!fir::isa_trivial(fir::unwrapRefType(reductionVar.getType())))
512f46f5a01STom Eccles     return true;
51374a87548STom Eccles 
514f46f5a01STom Eccles   return false;
515f46f5a01STom Eccles }
516f46f5a01STom Eccles 
517d84252e0SSergio Afonso void ReductionProcessor::addDeclareReduction(
5187a66e420SKrzysztof Parzyszek     mlir::Location currentLocation, lower::AbstractConverter &converter,
51963e70c05SKrzysztof Parzyszek     const omp::clause::Reduction &reduction,
5204d4af15cSKareem Ergawy     llvm::SmallVectorImpl<mlir::Value> &reductionVars,
52174a87548STom Eccles     llvm::SmallVectorImpl<bool> &reduceVarByRef,
5224d4af15cSKareem Ergawy     llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
52388478a89SSergio Afonso     llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols) {
5244d4af15cSKareem Ergawy   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
52517cb8a53SKiran Chandramohan 
52617cb8a53SKiran Chandramohan   if (std::get<std::optional<omp::clause::Reduction::ReductionModifier>>(
52717cb8a53SKiran Chandramohan           reduction.t))
52817cb8a53SKiran Chandramohan     TODO(currentLocation, "Reduction modifiers are not supported");
52917cb8a53SKiran Chandramohan 
530d84252e0SSergio Afonso   mlir::omp::DeclareReductionOp decl;
531148a5579SKrzysztof Parzyszek   const auto &redOperatorList{
532148a5579SKrzysztof Parzyszek       std::get<omp::clause::Reduction::ReductionIdentifiers>(reduction.t)};
533148a5579SKrzysztof Parzyszek   assert(redOperatorList.size() == 1 && "Expecting single operator");
534148a5579SKrzysztof Parzyszek   const auto &redOperator = redOperatorList.front();
53563e70c05SKrzysztof Parzyszek   const auto &objectList{std::get<omp::ObjectList>(reduction.t)};
536f46f5a01STom Eccles 
53763e70c05SKrzysztof Parzyszek   if (!std::holds_alternative<omp::clause::DefinedOperator>(redOperator.u)) {
538f46f5a01STom Eccles     if (const auto *reductionIntrinsic =
53963e70c05SKrzysztof Parzyszek             std::get_if<omp::clause::ProcedureDesignator>(&redOperator.u)) {
540f46f5a01STom Eccles       if (!ReductionProcessor::supportedIntrinsicProcReduction(
541f46f5a01STom Eccles               *reductionIntrinsic)) {
542f46f5a01STom Eccles         return;
543f46f5a01STom Eccles       }
544f46f5a01STom Eccles     } else {
545f46f5a01STom Eccles       return;
546f46f5a01STom Eccles     }
547f46f5a01STom Eccles   }
548f46f5a01STom Eccles 
5491002c08cSTom Eccles   // Reduction variable processing common to both intrinsic operators and
5501002c08cSTom Eccles   // procedure designators
551197f3ecfSTom Eccles   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
55263e70c05SKrzysztof Parzyszek   for (const Object &object : objectList) {
5538b18f2feSKrzysztof Parzyszek     const semantics::Symbol *symbol = object.sym();
55488478a89SSergio Afonso     reductionSymbols.push_back(symbol);
555f46f5a01STom Eccles     mlir::Value symVal = converter.getSymbolAddress(*symbol);
556dbd6eb67STom Eccles     mlir::Type eleType;
557dbd6eb67STom Eccles     auto refType = mlir::dyn_cast_or_null<fir::ReferenceType>(symVal.getType());
558dbd6eb67STom Eccles     if (refType)
559dbd6eb67STom Eccles       eleType = refType.getEleTy();
560dbd6eb67STom Eccles     else
561dbd6eb67STom Eccles       eleType = symVal.getType();
562197f3ecfSTom Eccles 
563197f3ecfSTom Eccles     // all arrays must be boxed so that we have convenient access to all the
564197f3ecfSTom Eccles     // information needed to iterate over the array
565dbd6eb67STom Eccles     if (mlir::isa<fir::SequenceType>(eleType)) {
566698bf3daSSourabh Singh Tomar       // For Host associated symbols, use `SymbolBox` instead
5677a66e420SKrzysztof Parzyszek       lower::SymbolBox symBox = converter.lookupOneLevelUpSymbol(*symbol);
568698bf3daSSourabh Singh Tomar       hlfir::Entity entity{symBox.getAddr()};
569197f3ecfSTom Eccles       entity = genVariableBox(currentLocation, builder, entity);
570197f3ecfSTom Eccles       mlir::Value box = entity.getBase();
571197f3ecfSTom Eccles 
572197f3ecfSTom Eccles       // Always pass the box by reference so that the OpenMP dialect
573197f3ecfSTom Eccles       // verifiers don't need to know anything about fir.box
574197f3ecfSTom Eccles       auto alloca =
575197f3ecfSTom Eccles           builder.create<fir::AllocaOp>(currentLocation, box.getType());
576197f3ecfSTom Eccles       builder.create<fir::StoreOp>(currentLocation, box, alloca);
577197f3ecfSTom Eccles 
578197f3ecfSTom Eccles       symVal = alloca;
579dbd6eb67STom Eccles     } else if (mlir::isa<fir::BaseBoxType>(symVal.getType())) {
580dbd6eb67STom Eccles       // boxed arrays are passed as values not by reference. Unfortunately,
581dbd6eb67STom Eccles       // we can't pass a box by value to omp.redution_declare, so turn it
582dbd6eb67STom Eccles       // into a reference
583dbd6eb67STom Eccles 
584dbd6eb67STom Eccles       auto alloca =
585dbd6eb67STom Eccles           builder.create<fir::AllocaOp>(currentLocation, symVal.getType());
586dbd6eb67STom Eccles       builder.create<fir::StoreOp>(currentLocation, symVal, alloca);
587dbd6eb67STom Eccles       symVal = alloca;
588197f3ecfSTom Eccles     } else if (auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>()) {
589f46f5a01STom Eccles       symVal = declOp.getBase();
590197f3ecfSTom Eccles     }
591197f3ecfSTom Eccles 
592dbd6eb67STom Eccles     // this isn't the same as the by-val and by-ref passing later in the
593dbd6eb67STom Eccles     // pipeline. Both styles assume that the variable is a reference at
594dbd6eb67STom Eccles     // this point
595dbd6eb67STom Eccles     assert(mlir::isa<fir::ReferenceType>(symVal.getType()) &&
596dbd6eb67STom Eccles            "reduction input var is a reference");
597dbd6eb67STom Eccles 
598f46f5a01STom Eccles     reductionVars.push_back(symVal);
59974a87548STom Eccles     reduceVarByRef.push_back(doReductionByRef(symVal));
600f46f5a01STom Eccles   }
601f46f5a01STom Eccles 
6021002c08cSTom Eccles   for (auto [symVal, isByRef] : llvm::zip(reductionVars, reduceVarByRef)) {
6031002c08cSTom Eccles     auto redType = mlir::cast<fir::ReferenceType>(symVal.getType());
6041002c08cSTom Eccles     const auto &kindMap = firOpBuilder.getKindMap();
6051002c08cSTom Eccles     std::string reductionName;
6061002c08cSTom Eccles     ReductionIdentifier redId;
6071002c08cSTom Eccles     mlir::Type redNameTy = redType;
6081002c08cSTom Eccles     if (mlir::isa<fir::LogicalType>(redType.getEleTy()))
6091002c08cSTom Eccles       redNameTy = builder.getI1Type();
6101002c08cSTom Eccles 
6114d4af15cSKareem Ergawy     if (const auto &redDefinedOp =
61263e70c05SKrzysztof Parzyszek             std::get_if<omp::clause::DefinedOperator>(&redOperator.u)) {
6134d4af15cSKareem Ergawy       const auto &intrinsicOp{
61463e70c05SKrzysztof Parzyszek           std::get<omp::clause::DefinedOperator::IntrinsicOperator>(
6154d4af15cSKareem Ergawy               redDefinedOp->u)};
6161002c08cSTom Eccles       redId = getReductionType(intrinsicOp);
6174d4af15cSKareem Ergawy       switch (redId) {
6184d4af15cSKareem Ergawy       case ReductionIdentifier::ADD:
6194d4af15cSKareem Ergawy       case ReductionIdentifier::MULTIPLY:
6204d4af15cSKareem Ergawy       case ReductionIdentifier::AND:
6214d4af15cSKareem Ergawy       case ReductionIdentifier::EQV:
6224d4af15cSKareem Ergawy       case ReductionIdentifier::OR:
6234d4af15cSKareem Ergawy       case ReductionIdentifier::NEQV:
6244d4af15cSKareem Ergawy         break;
6254d4af15cSKareem Ergawy       default:
6264d4af15cSKareem Ergawy         TODO(currentLocation,
6274d4af15cSKareem Ergawy              "Reduction of some intrinsic operators is not supported");
6284d4af15cSKareem Ergawy         break;
6294d4af15cSKareem Ergawy       }
63063e70c05SKrzysztof Parzyszek 
6311002c08cSTom Eccles       reductionName =
6321002c08cSTom Eccles           getReductionName(intrinsicOp, kindMap, redNameTy, isByRef);
6334d4af15cSKareem Ergawy     } else if (const auto *reductionIntrinsic =
63463e70c05SKrzysztof Parzyszek                    std::get_if<omp::clause::ProcedureDesignator>(
6354d4af15cSKareem Ergawy                        &redOperator.u)) {
6361002c08cSTom Eccles       if (!ReductionProcessor::supportedIntrinsicProcReduction(
6374d4af15cSKareem Ergawy               *reductionIntrinsic)) {
6381002c08cSTom Eccles         TODO(currentLocation, "Unsupported intrinsic proc reduction");
6394d4af15cSKareem Ergawy       }
6401002c08cSTom Eccles       redId = getReductionType(*reductionIntrinsic);
6411002c08cSTom Eccles       reductionName =
6421002c08cSTom Eccles           getReductionName(getRealName(*reductionIntrinsic).ToString(), kindMap,
6431002c08cSTom Eccles                            redNameTy, isByRef);
6441002c08cSTom Eccles     } else {
6451002c08cSTom Eccles       TODO(currentLocation, "Unexpected reduction type");
6464d4af15cSKareem Ergawy     }
6471002c08cSTom Eccles 
6481002c08cSTom Eccles     decl = createDeclareReduction(firOpBuilder, reductionName, redId, redType,
6491002c08cSTom Eccles                                   currentLocation, isByRef);
6501002c08cSTom Eccles     reductionDeclSymbols.push_back(
6511002c08cSTom Eccles         mlir::SymbolRefAttr::get(firOpBuilder.getContext(), decl.getSymName()));
6524d4af15cSKareem Ergawy   }
6534d4af15cSKareem Ergawy }
65463e70c05SKrzysztof Parzyszek 
6557a66e420SKrzysztof Parzyszek const semantics::SourceName
6567a66e420SKrzysztof Parzyszek ReductionProcessor::getRealName(const semantics::Symbol *symbol) {
65763e70c05SKrzysztof Parzyszek   return symbol->GetUltimate().name();
6584d4af15cSKareem Ergawy }
6594d4af15cSKareem Ergawy 
6607a66e420SKrzysztof Parzyszek const semantics::SourceName
66163e70c05SKrzysztof Parzyszek ReductionProcessor::getRealName(const omp::clause::ProcedureDesignator &pd) {
6628b18f2feSKrzysztof Parzyszek   return getRealName(pd.v.sym());
6634d4af15cSKareem Ergawy }
6644d4af15cSKareem Ergawy 
6654d4af15cSKareem Ergawy int ReductionProcessor::getOperationIdentity(ReductionIdentifier redId,
6664d4af15cSKareem Ergawy                                              mlir::Location loc) {
6674d4af15cSKareem Ergawy   switch (redId) {
6684d4af15cSKareem Ergawy   case ReductionIdentifier::ADD:
6694d4af15cSKareem Ergawy   case ReductionIdentifier::OR:
6704d4af15cSKareem Ergawy   case ReductionIdentifier::NEQV:
6714d4af15cSKareem Ergawy     return 0;
6724d4af15cSKareem Ergawy   case ReductionIdentifier::MULTIPLY:
6734d4af15cSKareem Ergawy   case ReductionIdentifier::AND:
6744d4af15cSKareem Ergawy   case ReductionIdentifier::EQV:
6754d4af15cSKareem Ergawy     return 1;
6764d4af15cSKareem Ergawy   default:
6774d4af15cSKareem Ergawy     TODO(loc, "Reduction of some intrinsic operators is not supported");
6784d4af15cSKareem Ergawy   }
6794d4af15cSKareem Ergawy }
6804d4af15cSKareem Ergawy 
6814d4af15cSKareem Ergawy } // namespace omp
6824d4af15cSKareem Ergawy } // namespace lower
6834d4af15cSKareem Ergawy } // namespace Fortran
684