Skip to content

Commit ebae4cc

Browse files
committed
[flang][hlfir] Fixed array constructor lowering.
First issue is that the clean-ups were generated after the yield_element operation that must be the terminator. Second issue is that codegen for elemenal operation was not working properly with nested elemental ops. Differential Revision: https://reviews.llvm.org/D149921
1 parent 913b95f commit ebae4cc

File tree

5 files changed

+244
-23
lines changed

5 files changed

+244
-23
lines changed

flang/lib/Lower/ConvertArrayConstructor.cpp

Lines changed: 83 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,55 @@
5656
// strategy.pushValue(ac-value);
5757
// } else if (ac-value is implied-do) {
5858
// strategy.startImpliedDo(lower, upper, stride);
59+
// strategy.startImpliedDoScope();
5960
// // lower nested values
61+
// ...
62+
// strategy.endImpliedDoScope();
6063
// }
6164
// result = strategy.finishArrayCtorLowering();
6265
// ```
6366

6467
//===----------------------------------------------------------------------===//
6568
// Definition of the lowering strategies. Each lowering strategy is defined
66-
// as a class that implements "pushValue", "startImpliedDo", and
67-
// "finishArrayCtorLowering".
69+
// as a class that implements "pushValue", "startImpliedDo" and
70+
// "finishArrayCtorLowering". A strategy may optionally override
71+
// "startImpliedDoScope" and "endImpliedDoScope" virtual methods
72+
// of its base class StrategyBase.
6873
//===----------------------------------------------------------------------===//
6974

7075
namespace {
76+
/// Class provides common implementation of scope push/pop methods
77+
/// that update StatementContext scopes and SymMap bindings.
78+
/// They might be overridden by the lowering strategies, e.g.
79+
/// see AsElementalStrategy.
80+
class StrategyBase {
81+
public:
82+
StrategyBase(Fortran::lower::StatementContext &stmtCtx,
83+
Fortran::lower::SymMap &symMap)
84+
: stmtCtx{stmtCtx}, symMap{symMap} {};
85+
virtual ~StrategyBase() = default;
86+
87+
virtual void startImpliedDoScope(llvm::StringRef doName,
88+
mlir::Value indexValue) {
89+
symMap.pushImpliedDoBinding(doName, indexValue);
90+
stmtCtx.pushScope();
91+
}
92+
93+
virtual void endImpliedDoScope() {
94+
stmtCtx.finalizeAndPop();
95+
symMap.popImpliedDoBinding();
96+
}
97+
98+
protected:
99+
Fortran::lower::StatementContext &stmtCtx;
100+
Fortran::lower::SymMap &symMap;
101+
};
102+
71103
/// Class that implements the "inlined temp strategy" to lower array
72104
/// constructors. It must be further provided a CounterType class to specify how
73105
/// the current ac-value insertion position is tracked.
74106
template <typename CounterType>
75-
class InlinedTempStrategyImpl {
107+
class InlinedTempStrategyImpl : public StrategyBase {
76108
/// Name that will be given to the temporary allocation and hlfir.declare in
77109
/// the IR.
78110
static constexpr char tempName[] = ".tmp.arrayctor";
@@ -81,9 +113,12 @@ class InlinedTempStrategyImpl {
81113
/// Start lowering an array constructor according to the inline strategy.
82114
/// The temporary is created right away.
83115
InlinedTempStrategyImpl(mlir::Location loc, fir::FirOpBuilder &builder,
116+
Fortran::lower::StatementContext &stmtCtx,
117+
Fortran::lower::SymMap &symMap,
84118
fir::SequenceType declaredType, mlir::Value extent,
85119
llvm::ArrayRef<mlir::Value> lengths)
86-
: one{builder.createIntegerConstant(loc, builder.getIndexType(), 1)},
120+
: StrategyBase{stmtCtx, symMap},
121+
one{builder.createIntegerConstant(loc, builder.getIndexType(), 1)},
87122
counter{loc, builder, one} {
88123
// Allocate the temporary storage.
89124
llvm::SmallVector<mlir::Value, 1> extents{extent};
@@ -224,15 +259,17 @@ using InlinedTempStrategy = InlinedTempStrategyImpl<InMemoryCounter>;
224259
/// implied-do nest and wrapped in an hlfir.reshape to a rank 1 array. But this
225260
/// op does not exist yet, so this is left for the future if it appears
226261
/// profitable.
227-
class AsElementalStrategy {
262+
class AsElementalStrategy : public StrategyBase {
228263
public:
229264
/// The constructor only gathers the operands to create the hlfir.elemental.
230265
AsElementalStrategy(mlir::Location loc, fir::FirOpBuilder &builder,
266+
Fortran::lower::StatementContext &stmtCtx,
267+
Fortran::lower::SymMap &symMap,
231268
fir::SequenceType declaredType, mlir::Value extent,
232269
llvm::ArrayRef<mlir::Value> lengths)
233-
: shape{builder.genShape(loc, {extent})},
234-
lengthParams{lengths.begin(), lengths.end()}, exprType{getExprType(
235-
declaredType)} {}
270+
: StrategyBase{stmtCtx, symMap}, shape{builder.genShape(loc, {extent})},
271+
lengthParams{lengths.begin(), lengths.end()},
272+
exprType{getExprType(declaredType)} {}
236273

237274
static hlfir::ExprType getExprType(fir::SequenceType declaredType) {
238275
// Note: 7.8 point 4: the dynamic type of an array constructor is its static
@@ -271,9 +308,19 @@ class AsElementalStrategy {
271308
if (fir::isa_trivial(elementResult.getType()))
272309
elementResult =
273310
builder.createConvert(loc, exprType.getElementType(), elementResult);
311+
312+
// The clean-ups associated with the implied-do body operations
313+
// must be initiated before the YieldElementOp, so we have to pop the scope
314+
// right now.
315+
stmtCtx.finalizeAndPop();
316+
274317
builder.create<hlfir::YieldElementOp>(loc, elementResult);
275318
}
276319

320+
// Override the default, because the context scope must be popped in
321+
// pushValue().
322+
virtual void endImpliedDoScope() override { symMap.popImpliedDoBinding(); }
323+
277324
/// Return the created hlfir.elemental.
278325
hlfir::Entity finishArrayCtorLowering(mlir::Location loc,
279326
fir::FirOpBuilder &builder) {
@@ -289,7 +336,7 @@ class AsElementalStrategy {
289336

290337
/// Class that implements the "runtime temp strategy" to lower array
291338
/// constructors.
292-
class RuntimeTempStrategy {
339+
class RuntimeTempStrategy : public StrategyBase {
293340
/// Name that will be given to the temporary allocation and hlfir.declare in
294341
/// the IR.
295342
static constexpr char tempName[] = ".tmp.arrayctor";
@@ -305,11 +352,14 @@ class RuntimeTempStrategy {
305352
/// constructor, if they could be precomputed. \p missingLengthParameters is
306353
/// set to true if the length parameters could not be precomputed.
307354
RuntimeTempStrategy(mlir::Location loc, fir::FirOpBuilder &builder,
355+
Fortran::lower::StatementContext &stmtCtx,
356+
Fortran::lower::SymMap &symMap,
308357
fir::SequenceType declaredType,
309358
std::optional<mlir::Value> extent,
310359
llvm::ArrayRef<mlir::Value> lengths,
311360
bool missingLengthParameters)
312-
: arrayConstructorElementType{declaredType.getEleTy()} {
361+
: StrategyBase{stmtCtx, symMap},
362+
arrayConstructorElementType{declaredType.getEleTy()} {
313363
mlir::Type heapType = fir::HeapType::get(declaredType);
314364
mlir::Type boxType = fir::BoxType::get(heapType);
315365
allocatableTemp = builder.createTemporary(loc, boxType, tempName);
@@ -463,6 +513,19 @@ class ArrayCtorLoweringStrategy {
463513
implVariant);
464514
}
465515

516+
void startImpliedDoScope(llvm::StringRef doName, mlir::Value indexValue) {
517+
std::visit(
518+
[&](auto &impl) {
519+
return impl.startImpliedDoScope(doName, indexValue);
520+
},
521+
implVariant);
522+
}
523+
524+
void endImpliedDoScope() {
525+
std::visit([&](auto &impl) { return impl.endImpliedDoScope(); },
526+
implVariant);
527+
}
528+
466529
private:
467530
std::variant<InlinedTempStrategy, LooplessInlinedTempStrategy,
468531
AsElementalStrategy, RuntimeTempStrategy>
@@ -694,20 +757,22 @@ static ArrayCtorLoweringStrategy selectArrayCtorLoweringStrategy(
694757
if (!extent || needToEvaluateOneExprToGetLengthParameters ||
695758
analysis.anyArrayExpr || declaredType.getEleTy().isa<fir::RecordType>())
696759
return RuntimeTempStrategy(
697-
loc, builder, declaredType,
760+
loc, builder, stmtCtx, symMap, declaredType,
698761
extent ? std::optional<mlir::Value>(extent) : std::nullopt, lengths,
699762
needToEvaluateOneExprToGetLengthParameters);
700763
// Note: array constructors containing impure ac-value expr are currently not
701764
// rewritten to hlfir.elemental because impure expressions should be evaluated
702765
// in order, and hlfir.elemental currently misses a way to indicate that.
703766
if (analysis.isSingleImpliedDoWithOneScalarPureExpr())
704-
return AsElementalStrategy(loc, builder, declaredType, extent, lengths);
767+
return AsElementalStrategy(loc, builder, stmtCtx, symMap, declaredType,
768+
extent, lengths);
705769

706770
if (analysis.anyImpliedDo)
707-
return InlinedTempStrategy(loc, builder, declaredType, extent, lengths);
771+
return InlinedTempStrategy(loc, builder, stmtCtx, symMap, declaredType,
772+
extent, lengths);
708773

709-
return LooplessInlinedTempStrategy(loc, builder, declaredType, extent,
710-
lengths);
774+
return LooplessInlinedTempStrategy(loc, builder, stmtCtx, symMap,
775+
declaredType, extent, lengths);
711776
}
712777

713778
/// Lower an ac-value expression \p expr and forward it to the selected
@@ -747,9 +812,8 @@ static void genAcValue(mlir::Location loc,
747812
mlir::OpBuilder::InsertPoint insertPt = builder.saveInsertionPoint();
748813
mlir::Value impliedDoIndexValue =
749814
arrayBuilder.startImpliedDo(loc, builder, lower, upper, stride);
750-
symMap.pushImpliedDoBinding(toStringRef(impledDo.name()),
751-
impliedDoIndexValue);
752-
stmtCtx.pushScope();
815+
arrayBuilder.startImpliedDoScope(toStringRef(impledDo.name()),
816+
impliedDoIndexValue);
753817

754818
for (const auto &acValue : impledDo.values())
755819
std::visit(
@@ -758,8 +822,7 @@ static void genAcValue(mlir::Location loc,
758822
},
759823
acValue.u);
760824

761-
stmtCtx.finalizeAndPop();
762-
symMap.popImpliedDoBinding();
825+
arrayBuilder.endImpliedDoScope();
763826
builder.restoreInsertionPoint(insertPt);
764827
}
765828

flang/lib/Optimizer/Builder/HLFIRTools.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,9 @@ hlfir::genElementalOp(mlir::Location loc, fir::FirOpBuilder &builder,
744744
return elementalOp;
745745
}
746746

747+
// TODO: we do not actually need to clone the YieldElementOp,
748+
// because returning its getElementValue() operand should be enough
749+
// for all callers of this function.
747750
hlfir::YieldElementOp
748751
hlfir::inlineElementalOp(mlir::Location loc, fir::FirOpBuilder &builder,
749752
hlfir::ElementalOp elemental,

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,13 @@ struct ElementalOpConversion
489489
: public mlir::OpConversionPattern<hlfir::ElementalOp> {
490490
using mlir::OpConversionPattern<hlfir::ElementalOp>::OpConversionPattern;
491491
explicit ElementalOpConversion(mlir::MLIRContext *ctx)
492-
: mlir::OpConversionPattern<hlfir::ElementalOp>{ctx} {}
492+
: mlir::OpConversionPattern<hlfir::ElementalOp>{ctx} {
493+
// This pattern recursively converts nested ElementalOp's
494+
// by cloning and then converting them, so we have to allow
495+
// for recursive pattern application. The recursion is bounded
496+
// by the nesting level of ElementalOp's.
497+
setHasBoundedRewriteRecursion();
498+
}
493499
mlir::LogicalResult
494500
matchAndRewrite(hlfir::ElementalOp elemental, OpAdaptor adaptor,
495501
mlir::ConversionPatternRewriter &rewriter) const override {
@@ -568,9 +574,14 @@ class BufferizeHLFIR : public hlfir::impl::BufferizeHLFIRBase<BufferizeHLFIR> {
568574
EndAssociateOpConversion, NoReassocOpConversion,
569575
SetLengthOpConversion, ShapeOfOpConversion>(context);
570576
mlir::ConversionTarget target(*context);
577+
// Note that YieldElementOp is not marked as an illegal operation.
578+
// It must be erased by its parent converter and there is no explicit
579+
// conversion pattern to YieldElementOp itself. If any YieldElementOp
580+
// survives this pass, the verifier will detect it because it has to be
581+
// a child of ElementalOp and ElementalOp's are explicitly illegal.
571582
target.addIllegalOp<hlfir::ApplyOp, hlfir::AssociateOp, hlfir::ElementalOp,
572-
hlfir::EndAssociateOp, hlfir::SetLengthOp,
573-
hlfir::YieldElementOp>();
583+
hlfir::EndAssociateOp, hlfir::SetLengthOp>();
584+
574585
target.markUnknownOpDynamicallyLegal([](mlir::Operation *op) {
575586
return llvm::all_of(
576587
op->getResultTypes(),
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Test nested hlfir.elemental code generation
2+
// RUN: fir-opt %s --bufferize-hlfir | FileCheck %s
3+
4+
// CHECK-LABEL: func.func @_QPtest(
5+
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32> {fir.bindc_name = "pi"},
6+
// CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<!fir.array<2xf32>> {fir.bindc_name = "h1"}) {
7+
// CHECK: %[[VAL_2:.*]] = arith.constant 2 : index
8+
// CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
9+
// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_3]]) {uniq_name = "_QFtestEh1"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<2xf32>>, !fir.ref<!fir.array<2xf32>>)
10+
// CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "k", uniq_name = "_QFtestEk"}
11+
// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFtestEk"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
12+
// CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "l", uniq_name = "_QFtestEl"}
13+
// CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFtestEl"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
14+
// CHECK: %[[VAL_9:.*]] = fir.address_of(@_QFtestECn) : !fir.ref<i32>
15+
// CHECK: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QFtestECn"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
16+
// CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtestEpi"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
17+
// CHECK: %[[VAL_12:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
18+
// CHECK: %[[VAL_13:.*]] = fir.allocmem !fir.array<2xf32> {bindc_name = ".tmp.array", uniq_name = ""}
19+
// CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_13]](%[[VAL_12]]) {uniq_name = ".tmp.array"} : (!fir.heap<!fir.array<2xf32>>, !fir.shape<1>) -> (!fir.heap<!fir.array<2xf32>>, !fir.heap<!fir.array<2xf32>>)
20+
// CHECK: %[[VAL_15:.*]] = arith.constant true
21+
// CHECK: %[[VAL_16:.*]] = arith.constant 1 : index
22+
// CHECK: fir.do_loop %[[VAL_17:.*]] = %[[VAL_16]] to %[[VAL_2]] step %[[VAL_16]] {
23+
// CHECK: %[[VAL_18:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
24+
// CHECK: %[[VAL_19:.*]] = fir.allocmem !fir.array<2xf32> {bindc_name = ".tmp.array", uniq_name = ""}
25+
// CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_19]](%[[VAL_18]]) {uniq_name = ".tmp.array"} : (!fir.heap<!fir.array<2xf32>>, !fir.shape<1>) -> (!fir.heap<!fir.array<2xf32>>, !fir.heap<!fir.array<2xf32>>)
26+
// CHECK: %[[VAL_21:.*]] = arith.constant true
27+
// CHECK: %[[VAL_22:.*]] = arith.constant 1 : index
28+
// CHECK: fir.do_loop %[[VAL_23:.*]] = %[[VAL_22]] to %[[VAL_2]] step %[[VAL_22]] {
29+
// CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref<f32>
30+
// CHECK: %[[VAL_25:.*]] = hlfir.designate %[[VAL_20]]#0 (%[[VAL_23]]) : (!fir.heap<!fir.array<2xf32>>, index) -> !fir.ref<f32>
31+
// CHECK: hlfir.assign %[[VAL_24]] to %[[VAL_25]] : f32, !fir.ref<f32>
32+
// CHECK: }
33+
// CHECK: %[[VAL_26:.*]] = fir.undefined tuple<!fir.heap<!fir.array<2xf32>>, i1>
34+
// CHECK: %[[VAL_27:.*]] = fir.insert_value %[[VAL_26]], %[[VAL_21]], [1 : index] : (tuple<!fir.heap<!fir.array<2xf32>>, i1>, i1) -> tuple<!fir.heap<!fir.array<2xf32>>, i1>
35+
// CHECK: %[[VAL_28:.*]] = fir.insert_value %[[VAL_27]], %[[VAL_20]]#0, [0 : index] : (tuple<!fir.heap<!fir.array<2xf32>>, i1>, !fir.heap<!fir.array<2xf32>>) -> tuple<!fir.heap<!fir.array<2xf32>>, i1>
36+
// CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_20]]#0 : (!fir.heap<!fir.array<2xf32>>) -> !fir.ref<!fir.array<2xf32>>
37+
// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_20]]#1 : (!fir.heap<!fir.array<2xf32>>) -> !fir.ref<!fir.array<2xf32>>
38+
// CHECK: %[[VAL_31:.*]] = fir.embox %[[VAL_29]](%[[VAL_18]]) : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xf32>>
39+
// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (!fir.box<!fir.array<2xf32>>) -> !fir.box<!fir.array<?xf32>>
40+
// CHECK: %[[VAL_33:.*]] = fir.call @_QPfoo(%[[VAL_32]]) fastmath<contract> : (!fir.box<!fir.array<?xf32>>) -> f32
41+
// CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_30]] : (!fir.ref<!fir.array<2xf32>>) -> !fir.heap<!fir.array<2xf32>>
42+
// CHECK: fir.freemem %[[VAL_34]] : !fir.heap<!fir.array<2xf32>>
43+
// CHECK: %[[VAL_35:.*]] = hlfir.designate %[[VAL_14]]#0 (%[[VAL_17]]) : (!fir.heap<!fir.array<2xf32>>, index) -> !fir.ref<f32>
44+
// CHECK: hlfir.assign %[[VAL_33]] to %[[VAL_35]] : f32, !fir.ref<f32>
45+
// CHECK: }
46+
// CHECK: %[[VAL_36:.*]] = fir.undefined tuple<!fir.heap<!fir.array<2xf32>>, i1>
47+
// CHECK: %[[VAL_37:.*]] = fir.insert_value %[[VAL_36]], %[[VAL_15]], [1 : index] : (tuple<!fir.heap<!fir.array<2xf32>>, i1>, i1) -> tuple<!fir.heap<!fir.array<2xf32>>, i1>
48+
// CHECK: %[[VAL_38:.*]] = fir.insert_value %[[VAL_37]], %[[VAL_14]]#0, [0 : index] : (tuple<!fir.heap<!fir.array<2xf32>>, i1>, !fir.heap<!fir.array<2xf32>>) -> tuple<!fir.heap<!fir.array<2xf32>>, i1>
49+
// CHECK: hlfir.assign %[[VAL_14]]#0 to %[[VAL_4]]#0 : !fir.heap<!fir.array<2xf32>>, !fir.ref<!fir.array<2xf32>>
50+
// CHECK: fir.freemem %[[VAL_14]]#1 : !fir.heap<!fir.array<2xf32>>
51+
// CHECK: return
52+
// CHECK: }
53+
func.func @_QPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "pi"}, %arg1: !fir.ref<!fir.array<2xf32>> {fir.bindc_name = "h1"}) {
54+
%c2 = arith.constant 2 : index
55+
%0 = fir.shape %c2 : (index) -> !fir.shape<1>
56+
%1:2 = hlfir.declare %arg1(%0) {uniq_name = "_QFtestEh1"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<2xf32>>, !fir.ref<!fir.array<2xf32>>)
57+
%2 = fir.alloca i32 {bindc_name = "k", uniq_name = "_QFtestEk"}
58+
%3:2 = hlfir.declare %2 {uniq_name = "_QFtestEk"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
59+
%4 = fir.alloca i32 {bindc_name = "l", uniq_name = "_QFtestEl"}
60+
%5:2 = hlfir.declare %4 {uniq_name = "_QFtestEl"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
61+
%6 = fir.address_of(@_QFtestECn) : !fir.ref<i32>
62+
%7:2 = hlfir.declare %6 {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QFtestECn"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
63+
%8:2 = hlfir.declare %arg0 {uniq_name = "_QFtestEpi"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
64+
%9 = fir.shape %c2 : (index) -> !fir.shape<1>
65+
%10 = hlfir.elemental %9 : (!fir.shape<1>) -> !hlfir.expr<2xf32> {
66+
^bb0(%arg2: index):
67+
%11 = fir.shape %c2 : (index) -> !fir.shape<1>
68+
%12 = hlfir.elemental %11 : (!fir.shape<1>) -> !hlfir.expr<2xf32> {
69+
^bb0(%arg3: index):
70+
%17 = fir.load %8#0 : !fir.ref<f32>
71+
hlfir.yield_element %17 : f32
72+
}
73+
%13:3 = hlfir.associate %12(%11) {uniq_name = "adapt.valuebyref"} : (!hlfir.expr<2xf32>, !fir.shape<1>) -> (!fir.ref<!fir.array<2xf32>>, !fir.ref<!fir.array<2xf32>>, i1)
74+
%14 = fir.embox %13#0(%11) : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xf32>>
75+
%15 = fir.convert %14 : (!fir.box<!fir.array<2xf32>>) -> !fir.box<!fir.array<?xf32>>
76+
%16 = fir.call @_QPfoo(%15) fastmath<contract> : (!fir.box<!fir.array<?xf32>>) -> f32
77+
hlfir.end_associate %13#1, %13#2 : !fir.ref<!fir.array<2xf32>>, i1
78+
hlfir.destroy %12 : !hlfir.expr<2xf32>
79+
hlfir.yield_element %16 : f32
80+
}
81+
hlfir.assign %10 to %1#0 : !hlfir.expr<2xf32>, !fir.ref<!fir.array<2xf32>>
82+
hlfir.destroy %10 : !hlfir.expr<2xf32>
83+
return
84+
}
85+
fir.global internal @_QFtestECn constant : i32 {
86+
%c2_i32 = arith.constant 2 : i32
87+
fir.has_value %c2_i32 : i32
88+
}
89+
func.func private @_QPfoo(!fir.box<!fir.array<?xf32>>) -> f32

0 commit comments

Comments
 (0)