Skip to content

Commit ef1eb50

Browse files
authored
[flang][openacc] Support assumed shape arrays in reduction (#67610)
Assumed shape array are using descriptor and must be handled differently than known shape arrays. This patch adds support to generate the `init` and `combiner` region for the reduction recipe operation with assumed shape array by using the descriptor and the HLFIR lowering path. `createTempFromMold` function is moved from `flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp` to `flang/include/flang/Optimizer/Builder/HLFIRTools.h` to be reused to create the private copy.
1 parent 989173c commit ef1eb50

File tree

5 files changed

+186
-68
lines changed

5 files changed

+186
-68
lines changed

flang/include/flang/Optimizer/Builder/HLFIRTools.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,10 @@ hlfir::ElementalOp cloneToElementalOp(mlir::Location loc,
418418
/// would be incorrect.
419419
bool elementalOpMustProduceTemp(hlfir::ElementalOp elemental);
420420

421+
std::pair<hlfir::Entity, mlir::Value>
422+
createTempFromMold(mlir::Location loc, fir::FirOpBuilder &builder,
423+
hlfir::Entity mold);
424+
421425
} // namespace hlfir
422426

423427
#endif // FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H

flang/lib/Lower/OpenACC.cpp

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "flang/Optimizer/Builder/BoxValue.h"
2323
#include "flang/Optimizer/Builder/Complex.h"
2424
#include "flang/Optimizer/Builder/FIRBuilder.h"
25+
#include "flang/Optimizer/Builder/HLFIRTools.h"
2526
#include "flang/Optimizer/Builder/IntrinsicCall.h"
2627
#include "flang/Optimizer/Builder/Todo.h"
2728
#include "flang/Parser/parse-tree.h"
@@ -704,6 +705,9 @@ static mlir::Value getReductionInitValue(fir::FirOpBuilder &builder,
704705
if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty))
705706
return getReductionInitValue(builder, loc, seqTy.getEleTy(), op);
706707

708+
if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty))
709+
return getReductionInitValue(builder, loc, boxTy.getEleTy(), op);
710+
707711
llvm::report_fatal_error("Unsupported OpenACC reduction type");
708712
}
709713

@@ -749,6 +753,14 @@ static mlir::Value genReductionInitRegion(fir::FirOpBuilder &builder,
749753
builder.setInsertionPointAfter(loops[0]);
750754
return declareOp.getBase();
751755
}
756+
} else if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(ty)) {
757+
if (!mlir::isa<fir::SequenceType>(boxTy.getEleTy()))
758+
TODO(loc, "Unsupported boxed type for reduction");
759+
// Create the private copy from the initial fir.box.
760+
hlfir::Entity source = hlfir::Entity{builder.getBlock()->getArgument(0)};
761+
auto [temp, cleanup] = hlfir::createTempFromMold(loc, builder, source);
762+
builder.create<hlfir::AssignOp>(loc, initValue, temp);
763+
return temp;
752764
}
753765
llvm::report_fatal_error("Unsupported OpenACC reduction type");
754766
}
@@ -850,8 +862,8 @@ static void genCombiner(fir::FirOpBuilder &builder, mlir::Location loc,
850862
ty = fir::unwrapRefType(ty);
851863

852864
if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty)) {
853-
if (seqTy.hasDynamicExtents())
854-
TODO(loc, "OpenACC reduction on array with dynamic extents");
865+
assert(!seqTy.hasDynamicExtents() &&
866+
"Assumed shaped array should be boxed for reduction");
855867
mlir::Type idxTy = builder.getIndexType();
856868
mlir::Type refTy = fir::ReferenceType::get(seqTy.getEleTy());
857869

@@ -875,6 +887,29 @@ static void genCombiner(fir::FirOpBuilder &builder, mlir::Location loc,
875887
genScalarCombiner(builder, loc, op, seqTy.getEleTy(), load1, load2);
876888
builder.create<fir::StoreOp>(loc, res, addr1);
877889
builder.setInsertionPointAfter(loops[0]);
890+
} else if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty)) {
891+
fir::SequenceType seqTy =
892+
mlir::dyn_cast_or_null<fir::SequenceType>(boxTy.getEleTy());
893+
if (!seqTy)
894+
TODO(loc, "Unsupported boxed type in OpenACC reduction");
895+
hlfir::Entity left = hlfir::Entity{value1};
896+
hlfir::Entity right = hlfir::Entity{value2};
897+
auto shape = hlfir::genShape(loc, builder, left);
898+
llvm::SmallVector<mlir::Value, 1> typeParams;
899+
auto genKernel = [&builder, &loc, op, seqTy, &left, &right](
900+
mlir::Location l, fir::FirOpBuilder &b,
901+
mlir::ValueRange oneBasedIndices) -> hlfir::Entity {
902+
auto leftElement = hlfir::getElementAt(l, b, left, oneBasedIndices);
903+
auto rightElement = hlfir::getElementAt(l, b, right, oneBasedIndices);
904+
auto leftVal = hlfir::loadTrivialScalar(l, b, leftElement);
905+
auto rightVal = hlfir::loadTrivialScalar(l, b, rightElement);
906+
return hlfir::Entity{genScalarCombiner(builder, loc, op, seqTy.getEleTy(),
907+
leftVal, rightVal)};
908+
};
909+
mlir::Value elemental = hlfir::genElementalOp(
910+
loc, builder, seqTy.getEleTy(), shape, typeParams, genKernel,
911+
/*isUnordered=*/true);
912+
builder.create<hlfir::AssignOp>(loc, elemental, value1);
878913
} else {
879914
mlir::Value res = genScalarCombiner(builder, loc, op, ty, value1, value2);
880915
builder.create<fir::StoreOp>(loc, res, value1);
@@ -932,9 +967,6 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList,
932967
mlir::acc::DataBoundsOp>(converter, builder, semanticsContext, stmtCtx,
933968
accObject, operandLocation, asFortran, bounds);
934969

935-
if (hasDynamicShape(bounds))
936-
TODO(operandLocation, "OpenACC reductions with dynamic shaped array");
937-
938970
mlir::Type reductionTy = fir::unwrapRefType(baseAddr.getType());
939971
if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(reductionTy))
940972
reductionTy = seqTy.getEleTy();
@@ -953,6 +985,8 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList,
953985
std::string recipeName = fir::getTypeAsString(
954986
ty, converter.getKindMap(),
955987
("reduction_" + stringifyReductionOperator(mlirOp)).str());
988+
if (hasDynamicShape(bounds))
989+
ty = baseAddr.getType();
956990
mlir::acc::ReductionRecipeOp recipe =
957991
Fortran::lower::createOrGetReductionRecipe(
958992
builder, recipeName, operandLocation, ty, mlirOp, bounds);

flang/lib/Optimizer/Builder/HLFIRTools.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "flang/Optimizer/Builder/Character.h"
1515
#include "flang/Optimizer/Builder/FIRBuilder.h"
1616
#include "flang/Optimizer/Builder/MutableBox.h"
17+
#include "flang/Optimizer/Builder/Runtime/Allocatable.h"
1718
#include "flang/Optimizer/Builder/Todo.h"
1819
#include "flang/Optimizer/HLFIR/HLFIROps.h"
1920
#include "mlir/IR/IRMapping.h"
@@ -1030,3 +1031,64 @@ bool hlfir::elementalOpMustProduceTemp(hlfir::ElementalOp elemental) {
10301031

10311032
return false;
10321033
}
1034+
1035+
std::pair<hlfir::Entity, mlir::Value>
1036+
hlfir::createTempFromMold(mlir::Location loc, fir::FirOpBuilder &builder,
1037+
hlfir::Entity mold) {
1038+
llvm::SmallVector<mlir::Value> lenParams;
1039+
hlfir::genLengthParameters(loc, builder, mold, lenParams);
1040+
llvm::StringRef tmpName{".tmp"};
1041+
mlir::Value alloc;
1042+
mlir::Value isHeapAlloc;
1043+
mlir::Value shape{};
1044+
fir::FortranVariableFlagsAttr declAttrs;
1045+
1046+
if (mold.isPolymorphic()) {
1047+
// Create unallocated polymorphic temporary using the dynamic type
1048+
// of the mold. The static type of the temporary matches
1049+
// the static type of the mold, but then the dynamic type
1050+
// of the mold is applied to the temporary's descriptor.
1051+
1052+
if (mold.isArray())
1053+
hlfir::genShape(loc, builder, mold);
1054+
1055+
// Create polymorphic allocatable box on the stack.
1056+
mlir::Type boxHeapType = fir::HeapType::get(fir::unwrapRefType(
1057+
mlir::cast<fir::BaseBoxType>(mold.getType()).getEleTy()));
1058+
// The box must be initialized, because AllocatableApplyMold
1059+
// may read its contents (e.g. for checking whether it is allocated).
1060+
alloc = fir::factory::genNullBoxStorage(builder, loc,
1061+
fir::ClassType::get(boxHeapType));
1062+
// The temporary is unallocated even after AllocatableApplyMold below.
1063+
// If the temporary is used as assignment LHS it will be automatically
1064+
// allocated on the heap, as long as we use Assign family
1065+
// runtime functions. So set MustFree to true.
1066+
isHeapAlloc = builder.createBool(loc, true);
1067+
declAttrs = fir::FortranVariableFlagsAttr::get(
1068+
builder.getContext(), fir::FortranVariableFlagsEnum::allocatable);
1069+
} else if (mold.isArray()) {
1070+
mlir::Type sequenceType =
1071+
hlfir::getFortranElementOrSequenceType(mold.getType());
1072+
shape = hlfir::genShape(loc, builder, mold);
1073+
auto extents = hlfir::getIndexExtents(loc, builder, shape);
1074+
alloc = builder.createHeapTemporary(loc, sequenceType, tmpName, extents,
1075+
lenParams);
1076+
isHeapAlloc = builder.createBool(loc, true);
1077+
} else {
1078+
alloc = builder.createTemporary(loc, mold.getFortranElementType(), tmpName,
1079+
/*shape=*/std::nullopt, lenParams);
1080+
isHeapAlloc = builder.createBool(loc, false);
1081+
}
1082+
auto declareOp = builder.create<hlfir::DeclareOp>(loc, alloc, tmpName, shape,
1083+
lenParams, declAttrs);
1084+
if (mold.isPolymorphic()) {
1085+
int rank = mold.getRank();
1086+
// TODO: should probably read rank from the mold.
1087+
if (rank < 0)
1088+
TODO(loc, "create temporary for assumed rank polymorphic");
1089+
fir::runtime::genAllocatableApplyMold(builder, loc, alloc,
1090+
mold.getFirBase(), rank);
1091+
}
1092+
1093+
return {hlfir::Entity{declareOp.getBase()}, isHeapAlloc};
1094+
}

flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp

Lines changed: 2 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -101,67 +101,6 @@ static mlir::Value getBufferizedExprMustFreeFlag(mlir::Value bufferizedExpr) {
101101
TODO(bufferizedExpr.getLoc(), "general extract storage case");
102102
}
103103

104-
static std::pair<hlfir::Entity, mlir::Value>
105-
createTempFromMold(mlir::Location loc, fir::FirOpBuilder &builder,
106-
hlfir::Entity mold) {
107-
llvm::SmallVector<mlir::Value> lenParams;
108-
hlfir::genLengthParameters(loc, builder, mold, lenParams);
109-
llvm::StringRef tmpName{".tmp"};
110-
mlir::Value alloc;
111-
mlir::Value isHeapAlloc;
112-
mlir::Value shape{};
113-
fir::FortranVariableFlagsAttr declAttrs;
114-
115-
if (mold.isPolymorphic()) {
116-
// Create unallocated polymorphic temporary using the dynamic type
117-
// of the mold. The static type of the temporary matches
118-
// the static type of the mold, but then the dynamic type
119-
// of the mold is applied to the temporary's descriptor.
120-
121-
if (mold.isArray())
122-
hlfir::genShape(loc, builder, mold);
123-
124-
// Create polymorphic allocatable box on the stack.
125-
mlir::Type boxHeapType = fir::HeapType::get(fir::unwrapRefType(
126-
mlir::cast<fir::BaseBoxType>(mold.getType()).getEleTy()));
127-
// The box must be initialized, because AllocatableApplyMold
128-
// may read its contents (e.g. for checking whether it is allocated).
129-
alloc = fir::factory::genNullBoxStorage(builder, loc,
130-
fir::ClassType::get(boxHeapType));
131-
// The temporary is unallocated even after AllocatableApplyMold below.
132-
// If the temporary is used as assignment LHS it will be automatically
133-
// allocated on the heap, as long as we use Assign family
134-
// runtime functions. So set MustFree to true.
135-
isHeapAlloc = builder.createBool(loc, true);
136-
declAttrs = fir::FortranVariableFlagsAttr::get(
137-
builder.getContext(), fir::FortranVariableFlagsEnum::allocatable);
138-
} else if (mold.isArray()) {
139-
mlir::Type sequenceType =
140-
hlfir::getFortranElementOrSequenceType(mold.getType());
141-
shape = hlfir::genShape(loc, builder, mold);
142-
auto extents = hlfir::getIndexExtents(loc, builder, shape);
143-
alloc = builder.createHeapTemporary(loc, sequenceType, tmpName, extents,
144-
lenParams);
145-
isHeapAlloc = builder.createBool(loc, true);
146-
} else {
147-
alloc = builder.createTemporary(loc, mold.getFortranElementType(), tmpName,
148-
/*shape=*/std::nullopt, lenParams);
149-
isHeapAlloc = builder.createBool(loc, false);
150-
}
151-
auto declareOp = builder.create<hlfir::DeclareOp>(loc, alloc, tmpName, shape,
152-
lenParams, declAttrs);
153-
if (mold.isPolymorphic()) {
154-
int rank = mold.getRank();
155-
// TODO: should probably read rank from the mold.
156-
if (rank < 0)
157-
TODO(loc, "create temporary for assumed rank polymorphic");
158-
fir::runtime::genAllocatableApplyMold(builder, loc, alloc,
159-
mold.getFirBase(), rank);
160-
}
161-
162-
return {hlfir::Entity{declareOp.getBase()}, isHeapAlloc};
163-
}
164-
165104
static std::pair<hlfir::Entity, mlir::Value>
166105
createArrayTemp(mlir::Location loc, fir::FirOpBuilder &builder,
167106
mlir::Type exprType, mlir::Value shape,
@@ -239,7 +178,7 @@ struct AsExprOpConversion : public mlir::OpConversionPattern<hlfir::AsExprOp> {
239178
}
240179
// Otherwise, create a copy in a new buffer.
241180
hlfir::Entity source = hlfir::Entity{adaptor.getVar()};
242-
auto [temp, cleanup] = createTempFromMold(loc, builder, source);
181+
auto [temp, cleanup] = hlfir::createTempFromMold(loc, builder, source);
243182
builder.create<hlfir::AssignOp>(loc, source, temp, temp.isAllocatable(),
244183
/*keep_lhs_length_if_realloc=*/false,
245184
/*temporary_lhs=*/true);
@@ -596,7 +535,7 @@ struct AssociateOpConversion
596535
// non-trivial value with more than one use. We will have to make a copy and
597536
// use that
598537
hlfir::Entity source = hlfir::Entity{bufferizedExpr};
599-
auto [temp, cleanup] = createTempFromMold(loc, builder, source);
538+
auto [temp, cleanup] = hlfir::createTempFromMold(loc, builder, source);
600539
builder.create<hlfir::AssignOp>(loc, source, temp, temp.isAllocatable(),
601540
/*keep_lhs_length_if_realloc=*/false,
602541
/*temporary_lhs=*/true);

flang/test/Lower/OpenACC/acc-reduction.f90

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,61 @@
33
! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s --check-prefixes=CHECK,FIR
44
! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,HLFIR
55

6+
! CHECK-LABEL: acc.reduction.recipe @"reduction_max_ref_?xf32" : !fir.box<!fir.array<?xf32>> reduction_operator <max> init {
7+
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xf32>>):
8+
! CHECK: %[[INIT_VALUE:.*]] = arith.constant -1.401300e-45 : f32
9+
! HLFIR: %[[C0:.*]] = arith.constant 0 : index
10+
! HLFIR: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[ARG0]], %[[C0]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
11+
! HLFIR: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1 : (index) -> !fir.shape<1>
12+
! HLFIR: %[[TEMP:.*]] = fir.allocmem !fir.array<?xf32>, %0#1 {bindc_name = ".tmp", uniq_name = ""}
13+
! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?xf32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xf32>>, !fir.heap<!fir.array<?xf32>>)
14+
! HLFIR: hlfir.assign %[[INIT_VALUE]] to %[[DECLARE]]#0 : f32, !fir.box<!fir.array<?xf32>>
15+
! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.box<!fir.array<?xf32>>
16+
! CHECK: } combiner {
17+
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xf32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?xf32>>):
18+
! HLFIR: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[ARG0]], %{{.*}} : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
19+
! HLFIR: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1 : (index) -> !fir.shape<1>
20+
! HLFIR: %[[ELEMENTAL:.*]] = hlfir.elemental %[[SHAPE]] unordered : (!fir.shape<1>) -> !hlfir.expr<?xf32> {
21+
! HLFIR: ^bb0(%arg2: index):
22+
! HLFIR: %[[DES_V1:.*]] = hlfir.designate %[[ARG0]] (%{{.*}}) : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
23+
! HLFIR: %[[DES_V2:.*]] = hlfir.designate %[[ARG1]] (%{{.*}}) : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
24+
! HLFIR: %[[LOAD_V1:.*]] = fir.load %[[DES_V1]] : !fir.ref<f32>
25+
! HLFIR: %[[LOAD_V2:.*]] = fir.load %[[DES_V2]] : !fir.ref<f32>
26+
! HLFIR: %[[CMPF:.*]] = arith.cmpf ogt, %[[LOAD_V1]], %[[LOAD_V2]] : f32
27+
! HLFIR: %[[SELECT:.*]] = arith.select %[[CMPF]], %[[LOAD_V1]], %[[LOAD_V2]] : f32
28+
! HLFIR: hlfir.yield_element %[[SELECT]] : f32
29+
! HLFIR: }
30+
! HLFIR: hlfir.assign %[[ELEMENTAL]] to %[[ARG0]] : !hlfir.expr<?xf32>, !fir.box<!fir.array<?xf32>>
31+
! CHECK: acc.yield %[[ARG0]] : !fir.box<!fir.array<?xf32>>
32+
! CHECK: }
33+
34+
! CHECK-LABEL: acc.reduction.recipe @"reduction_add_ref_?xi32" : !fir.box<!fir.array<?xi32>> reduction_operator <add> init {
35+
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xi32>>):
36+
! HLFIR: %[[INIT_VALUE:.*]] = arith.constant 0 : i32
37+
! HLFIR: %[[C0:.*]] = arith.constant 0 : index
38+
! HLFIR: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[ARG0]], %[[C0]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
39+
! HLFIR: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1 : (index) -> !fir.shape<1>
40+
! HLFIR: %[[TEMP:.*]] = fir.allocmem !fir.array<?xi32>, %[[BOX_DIMS]]#1 {bindc_name = ".tmp", uniq_name = ""}
41+
! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.heap<!fir.array<?xi32>>)
42+
! HLFIR: hlfir.assign %[[INIT_VALUE]] to %[[DECLARE]]#0 : i32, !fir.box<!fir.array<?xi32>>
43+
! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.box<!fir.array<?xi32>>
44+
! CHECK: } combiner {
45+
! CHECK: ^bb0(%[[V1:.*]]: !fir.box<!fir.array<?xi32>>, %[[V2:.*]]: !fir.box<!fir.array<?xi32>>):
46+
! HLFIR: %[[BOX_DIMS]]:3 = fir.box_dims %[[V1]], %{{.*}} : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
47+
! HLFIR: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1 : (index) -> !fir.shape<1>
48+
! HLFIR: %[[ELEMENTAL:.*]] = hlfir.elemental %[[SHAPE]] unordered : (!fir.shape<1>) -> !hlfir.expr<?xi32> {
49+
! HLFIR: ^bb0(%{{.*}}: index):
50+
! HLFIR: %[[DES_V1:.*]] = hlfir.designate %[[V1]] (%{{.*}}) : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
51+
! HLFIR: %[[DES_V2:.*]] = hlfir.designate %[[V2]] (%{{.*}}) : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
52+
! HLFIR: %[[LOAD_V1:.*]] = fir.load %[[DES_V1]] : !fir.ref<i32>
53+
! HLFIR: %[[LOAD_V2:.*]] = fir.load %[[DES_V2]] : !fir.ref<i32>
54+
! HLFIR: %[[COMBINED:.*]] = arith.addi %[[LOAD_V1]], %[[LOAD_V2]] : i32
55+
! HLFIR: hlfir.yield_element %[[COMBINED]] : i32
56+
! HLFIR: }
57+
! HLFIR: hlfir.assign %[[ELEMENTAL]] to %[[V1]] : !hlfir.expr<?xi32>, !fir.box<!fir.array<?xi32>>
58+
! CHECK: acc.yield %arg0 : !fir.box<!fir.array<?xi32>>
59+
! CHECK: }
60+
661
! CHECK-LABEL: acc.reduction.recipe @reduction_mul_ref_z32 : !fir.ref<!fir.complex<4>> reduction_operator <mul> init {
762
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.complex<4>>):
863
! CHECK: %[[REAL:.*]] = arith.constant 1.000000e+00 : f32
@@ -1005,3 +1060,27 @@ subroutine acc_reduction_add_static_slice(a)
10051060
! FIR: %[[RED:.*]] = acc.reduction varPtr(%[[ARG0]] : !fir.ref<!fir.array<100xi32>>) bounds(%[[BOUND]]) -> !fir.ref<!fir.array<100xi32>> {name = "a(11:20)"}
10061061
! HLFIR: %[[RED:.*]] = acc.reduction varPtr(%[[DECLARG0]]#1 : !fir.ref<!fir.array<100xi32>>) bounds(%[[BOUND]]) -> !fir.ref<!fir.array<100xi32>> {name = "a(11:20)"}
10071062
! CHECK: acc.parallel reduction(@reduction_add_ref_100xi32 -> %[[RED]] : !fir.ref<!fir.array<100xi32>>)
1063+
1064+
subroutine acc_reduction_add_dynamic_extent_add(a)
1065+
integer :: a(:)
1066+
!$acc parallel reduction(+:a)
1067+
!$acc end parallel
1068+
end subroutine
1069+
1070+
! CHECK-LABEL: func.func @_QPacc_reduction_add_dynamic_extent_add(
1071+
! CHECK-SAME: %[[ARG0:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a"})
1072+
! HLFIR: %[[DECLARG0:.*]]:2 = hlfir.declare %[[ARG0]]
1073+
! HLFIR: %[[RED:.*]] = acc.reduction varPtr(%{{.*}} : !fir.ref<!fir.array<?xi32>>) bounds(%{{.*}}) -> !fir.ref<!fir.array<?xi32>> {name = "a"}
1074+
! HLFIR: acc.parallel reduction(@"reduction_add_ref_?xi32" -> %[[RED:.*]] : !fir.ref<!fir.array<?xi32>>)
1075+
1076+
subroutine acc_reduction_add_dynamic_extent_max(a)
1077+
real :: a(:)
1078+
!$acc parallel reduction(max:a)
1079+
!$acc end parallel
1080+
end subroutine
1081+
1082+
! CHECK-LABEL: func.func @_QPacc_reduction_add_dynamic_extent_max(
1083+
! CHECK-SAME: %[[ARG0:.*]]: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "a"})
1084+
! HLFIR: %[[DECLARG0:.*]]:2 = hlfir.declare %[[ARG0]]
1085+
! HLFIR: %[[RED:.*]] = acc.reduction varPtr(%{{.*}} : !fir.ref<!fir.array<?xf32>>) bounds(%{{.*}}) -> !fir.ref<!fir.array<?xf32>> {name = "a"}
1086+
! HLFIR: acc.parallel reduction(@"reduction_max_ref_?xf32" -> %[[RED]] : !fir.ref<!fir.array<?xf32>>) {

0 commit comments

Comments
 (0)