Index: flang/include/flang/Optimizer/Builder/Runtime/Reduction.h =================================================================== --- flang/include/flang/Optimizer/Builder/Runtime/Reduction.h +++ flang/include/flang/Optimizer/Builder/Runtime/Reduction.h @@ -165,6 +165,42 @@ mlir::Value resultBox, mlir::Value arrayBox, mlir::Value dim, mlir::Value maskBox); +/// Generate call to `IAll` intrinsic runtime routine. This is the version +/// that does not take a dim argument. +mlir::Value genIAll(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value arrayBox, mlir::Value maskBox, + mlir::Value resultBox); + +/// Generate call to `IAllDim` intrinsic runtime routine. This is the version +/// that takes arrays of any rank with a dim argument specified. +void genIAllDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, mlir::Value dim, + mlir::Value maskBox); + +/// Generate call to `IAny` intrinsic runtime routine. This is the version +/// that does not take a dim argument. +mlir::Value genIAny(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value arrayBox, mlir::Value maskBox, + mlir::Value resultBox); + +/// Generate call to `IAnyDim` intrinsic runtime routine. This is the version +/// that takes arrays of any rank with a dim argument specified. +void genIAnyDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, mlir::Value dim, + mlir::Value maskBox); + +/// Generate call to `IParity` intrinsic runtime routine. This is the version +/// that does not take a dim argument. +mlir::Value genIParity(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value arrayBox, mlir::Value maskBox, + mlir::Value resultBox); + +/// Generate call to `IParityDim` intrinsic runtime routine. This is the version +/// that takes arrays of any rank with a dim argument specified. +void genIParityDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, mlir::Value dim, + mlir::Value maskBox); + } // namespace fir::runtime #endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_REDUCTION_H Index: flang/lib/Lower/IntrinsicCall.cpp =================================================================== --- flang/lib/Lower/IntrinsicCall.cpp +++ flang/lib/Lower/IntrinsicCall.cpp @@ -175,10 +175,10 @@ }); } -/// Process calls to Product, Sum intrinsic functions +/// Process calls to Product, Sum, IAll, IAny, IParity intrinsic functions template static fir::ExtendedValue -genProdOrSum(FN func, FD funcDim, mlir::Type resultType, +genReduction(FN func, FD funcDim, mlir::Type resultType, fir::FirOpBuilder &builder, mlir::Location loc, Fortran::lower::StatementContext *stmtCtx, llvm::StringRef errMsg, llvm::ArrayRef args) { @@ -500,9 +500,11 @@ mlir::ArrayRef args); void genGetCommandArgument(mlir::ArrayRef args); void genGetEnvironmentVariable(llvm::ArrayRef); + fir::ExtendedValue genIall(mlir::Type, llvm::ArrayRef); /// Lowering for the IAND intrinsic. The IAND intrinsic expects two arguments /// in the llvm::ArrayRef. mlir::Value genIand(mlir::Type, llvm::ArrayRef); + fir::ExtendedValue genIany(mlir::Type, llvm::ArrayRef); mlir::Value genIbclr(mlir::Type, llvm::ArrayRef); mlir::Value genIbits(mlir::Type, llvm::ArrayRef); mlir::Value genIbset(mlir::Type, llvm::ArrayRef); @@ -514,6 +516,7 @@ mlir::Value genIeor(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genIndex(mlir::Type, llvm::ArrayRef); mlir::Value genIor(mlir::Type, llvm::ArrayRef); + fir::ExtendedValue genIparity(mlir::Type, llvm::ArrayRef); mlir::Value genIshft(mlir::Type, llvm::ArrayRef); mlir::Value genIshftc(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genLbound(mlir::Type, llvm::ArrayRef); @@ -802,7 +805,19 @@ {"errmsg", asBox, handleDynamicOptional}}}, /*isElemental=*/false}, {"iachar", &I::genIchar}, + {"iall", + &I::genIall, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, {"iand", &I::genIand}, + {"iany", + &I::genIany, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, {"ibclr", &I::genIbclr}, {"ibits", &I::genIbits}, {"ibset", &I::genIbset}, @@ -820,6 +835,12 @@ {"back", asValue, handleDynamicOptional}, {"kind", asValue}}}}, {"ior", &I::genIor}, + {"iparity", + &I::genIparity, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, {"ishft", &I::genIshft}, {"ishftc", &I::genIshftc}, {"lbound", @@ -3069,6 +3090,15 @@ } } +// IALL +fir::ExtendedValue +IntrinsicLibrary::genIall(mlir::Type resultType, + llvm::ArrayRef args) { + return genReduction(fir::runtime::genIAll, fir::runtime::genIAllDim, + resultType, builder, loc, stmtCtx, + "unexpected result for IALL", args); +} + // IAND mlir::Value IntrinsicLibrary::genIand(mlir::Type resultType, llvm::ArrayRef args) { @@ -3078,6 +3108,15 @@ return builder.create(loc, arg0, arg1); } +// IANY +fir::ExtendedValue +IntrinsicLibrary::genIany(mlir::Type resultType, + llvm::ArrayRef args) { + return genReduction(fir::runtime::genIAny, fir::runtime::genIAnyDim, + resultType, builder, loc, stmtCtx, + "unexpected result for IANY", args); +} + // IBCLR mlir::Value IntrinsicLibrary::genIbclr(mlir::Type resultType, llvm::ArrayRef args) { @@ -3302,6 +3341,15 @@ return builder.create(loc, args[0], args[1]); } +// IPARITY +fir::ExtendedValue +IntrinsicLibrary::genIparity(mlir::Type resultType, + llvm::ArrayRef args) { + return genReduction(fir::runtime::genIParity, fir::runtime::genIParityDim, + resultType, builder, loc, stmtCtx, + "unexpected result for IPARITY", args); +} + // ISHFT mlir::Value IntrinsicLibrary::genIshft(mlir::Type resultType, llvm::ArrayRef args) { @@ -3809,7 +3857,7 @@ fir::ExtendedValue IntrinsicLibrary::genProduct(mlir::Type resultType, llvm::ArrayRef args) { - return genProdOrSum(fir::runtime::genProduct, fir::runtime::genProductDim, + return genReduction(fir::runtime::genProduct, fir::runtime::genProductDim, resultType, builder, loc, stmtCtx, "unexpected result for Product", args); } @@ -4409,7 +4457,7 @@ fir::ExtendedValue IntrinsicLibrary::genSum(mlir::Type resultType, llvm::ArrayRef args) { - return genProdOrSum(fir::runtime::genSum, fir::runtime::genSumDim, resultType, + return genReduction(fir::runtime::genSum, fir::runtime::genSumDim, resultType, builder, loc, stmtCtx, "unexpected result for Sum", args); } Index: flang/lib/Optimizer/Builder/Runtime/Reduction.cpp =================================================================== --- flang/lib/Optimizer/Builder/Runtime/Reduction.cpp +++ flang/lib/Optimizer/Builder/Runtime/Reduction.cpp @@ -17,6 +17,11 @@ using namespace Fortran::runtime; +#define STRINGIFY(S) #S +#define JOIN2(A, B) A##B +#define JOIN3(A, B, C) A##B##C +#define EXPAND_AND_QUOTE(S) ExpandAndQuoteKey(RTNAME(S)) + /// Placeholder for real*10 version of Maxval Intrinsic struct ForcedMaxvalReal10 { static constexpr const char *name = ExpandAndQuoteKey(RTNAME(MaxvalReal10)); @@ -368,6 +373,54 @@ } }; +/// Placeholder for integer(16) version of IAll Intrinsic +struct ForcedIAll16 { + static constexpr const char *name = EXPAND_AND_QUOTE(IAll16); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::IntegerType::get(ctx, 128); + auto boxTy = + fir::runtime::getModel()(ctx); + auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); + auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); + return mlir::FunctionType::get(ctx, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for integer(16) version of IAny Intrinsic +struct ForcedIAny16 { + static constexpr const char *name = EXPAND_AND_QUOTE(IAny16); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::IntegerType::get(ctx, 128); + auto boxTy = + fir::runtime::getModel()(ctx); + auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); + auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); + return mlir::FunctionType::get(ctx, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for integer(16) version of IParity Intrinsic +struct ForcedIParity16 { + static constexpr const char *name = EXPAND_AND_QUOTE(IParity16); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::IntegerType::get(ctx, 128); + auto boxTy = + fir::runtime::getModel()(ctx); + auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); + auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); + return mlir::FunctionType::get(ctx, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + /// Generate call to specialized runtime function that takes a mask and /// dim argument. The All, Any, and Count intrinsics use this pattern. template @@ -942,3 +995,78 @@ return builder.create(loc, func, args).getResult(0); } + +// The IAll, IAny and IParity intrinsics have essentially the same +// implementation. This macro will generate the function body given the +// instrinsic name. +#define GEN_IALL_IANY_IPARITY(F) \ + mlir::Value fir::runtime::JOIN2(gen, F)( \ + fir::FirOpBuilder & builder, mlir::Location loc, mlir::Value arrayBox, \ + mlir::Value maskBox, mlir::Value resultBox) { \ + mlir::func::FuncOp func; \ + auto ty = arrayBox.getType(); \ + auto arrTy = fir::dyn_cast_ptrOrBoxEleTy(ty); \ + auto eleTy = arrTy.cast().getEleTy(); \ + auto dim = builder.createIntegerConstant(loc, builder.getIndexType(), 0); \ + \ + if (eleTy.isInteger(builder.getKindMap().getIntegerBitsize(1))) \ + func = fir::runtime::getRuntimeFunc(loc, builder); \ + else if (eleTy.isInteger(builder.getKindMap().getIntegerBitsize(2))) \ + func = fir::runtime::getRuntimeFunc(loc, builder); \ + else if (eleTy.isInteger(builder.getKindMap().getIntegerBitsize(4))) \ + func = fir::runtime::getRuntimeFunc(loc, builder); \ + else if (eleTy.isInteger(builder.getKindMap().getIntegerBitsize(8))) \ + func = fir::runtime::getRuntimeFunc(loc, builder); \ + else if (eleTy.isInteger(builder.getKindMap().getIntegerBitsize(16))) \ + func = fir::runtime::getRuntimeFunc(loc, builder); \ + else \ + fir::emitFatalError(loc, "invalid type in " STRINGIFY(F)); \ + \ + auto fTy = func.getFunctionType(); \ + auto sourceFile = fir::factory::locationToFilename(builder, loc); \ + auto sourceLine = \ + fir::factory::locationToLineNo(builder, loc, fTy.getInput(2)); \ + auto args = fir::runtime::createArguments( \ + builder, loc, fTy, arrayBox, sourceFile, sourceLine, dim, maskBox); \ + \ + return builder.create(loc, func, args).getResult(0); \ + } + +/// Generate call to `IAllDim` intrinsic runtime routine. This is the version +/// that handles any rank array with the dim argument specified. +void fir::runtime::genIAllDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value dim, mlir::Value maskBox) { + auto func = fir::runtime::getRuntimeFunc(loc, builder); + genReduction3Args(func, builder, loc, resultBox, arrayBox, dim, maskBox); +} + +/// Generate call to `IAll` intrinsic runtime routine. This is the version +/// that does not take a dim argument. +GEN_IALL_IANY_IPARITY(IAll) + +/// Generate call to `IAnyDim` intrinsic runtime routine. This is the version +/// that handles any rank array with the dim argument specified. +void fir::runtime::genIAnyDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value dim, mlir::Value maskBox) { + auto func = fir::runtime::getRuntimeFunc(loc, builder); + genReduction3Args(func, builder, loc, resultBox, arrayBox, dim, maskBox); +} + +/// Generate call to `IAny` intrinsic runtime routine. This is the version +/// that does not take a dim argument. +GEN_IALL_IANY_IPARITY(IAny) + +/// Generate call to `IParityDim` intrinsic runtime routine. This is the version +/// that handles any rank array with the dim argument specified. +void fir::runtime::genIParityDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value dim, mlir::Value maskBox) { + auto func = fir::runtime::getRuntimeFunc(loc, builder); + genReduction3Args(func, builder, loc, resultBox, arrayBox, dim, maskBox); +} + +/// Generate call to `IParity` intrinsic runtime routine. This is the version +/// that does not take a dim argument. +GEN_IALL_IANY_IPARITY(IParity)