From af2e5975222c4df3567d7cafcd5e1bd8fe7b86bd Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Fri, 16 Dec 2022 09:20:47 +0100 Subject: [PATCH] [flang] enable as_expr codegen from array without FortranVariabeInterface The defining op of HLFIR variables is expected to be visible in most cases, but HLFIR codegen won't rely on it from a correctness point of view. This patch allows building a fir.shape from an hlfir::Entity does not have a visible FortranVariabeInterface defining op. Differential Revision: https://reviews.llvm.org/D140099 --- flang/include/flang/Optimizer/Dialect/FIROps.td | 3 ++ flang/lib/Optimizer/Builder/HLFIRTools.cpp | 32 ++++++++++++++--- .../Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp | 27 ++++++++++----- flang/test/HLFIR/as_expr-codegen.fir | 40 ++++++++++++++++++++-- 4 files changed, 86 insertions(+), 16 deletions(-) diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index 088294c..cbe5940 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -1029,6 +1029,9 @@ def fir_BoxDimsOp : fir_Op<"box_dims", [NoMemoryEffect]> { let extraClassDeclaration = [{ mlir::Type getTupleType(); + mlir::Value getLowerBound() {return getResult(0);}; + mlir::Value getExtent() {return getResult(1);}; + mlir::Value getByteStride() {return getResult(2);}; }]; } diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp index faba6e1..cdb78bd 100644 --- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp +++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp @@ -358,6 +358,12 @@ mlir::Value hlfir::genShape(mlir::Location loc, fir::FirOpBuilder &builder, else entity = followEntitySource(entity); + if (entity.getType().isa()) { + if (auto elemental = entity.getDefiningOp()) + return elemental.getShape(); + TODO(loc, "get shape from HLFIR expr without producer holding the shape"); + } + // Entity is an array variable. if (auto varIface = entity.getIfVariableInterface()) { if (auto shape = varIface.getShape()) { if (shape.getType().isa()) @@ -366,12 +372,28 @@ mlir::Value hlfir::genShape(mlir::Location loc, fir::FirOpBuilder &builder, if (auto s = shape.getDefiningOp()) return builder.create(loc, s.getExtents()); } - } else if (entity.getType().isa()) { - if (auto elemental = entity.getDefiningOp()) - return elemental.getShape(); - TODO(loc, "get shape from HLFIR expr without producer holding the shape"); } - TODO(loc, "get shape from HLFIR variable without interface"); + // There is no shape lying around for this entity: build one using + // the type shape information, and/or the fir.box/fir.class shape + // information if any extents are not static. + fir::SequenceType seqTy = + hlfir::getFortranElementOrSequenceType(entity.getType()) + .cast(); + llvm::SmallVector extents; + mlir::Type idxTy = builder.getIndexType(); + for (auto typeExtent : seqTy.getShape()) + if (typeExtent != fir::SequenceType::getUnknownExtent()) { + extents.push_back(builder.createIntegerConstant(loc, idxTy, typeExtent)); + } else { + assert(entity.getType().isa() && + "array variable with dynamic extent must be boxes"); + mlir::Value dim = + builder.createIntegerConstant(loc, idxTy, extents.size()); + auto dimInfo = + builder.create(loc, idxTy, idxTy, idxTy, entity, dim); + extents.push_back(dimInfo.getExtent()); + } + return builder.create(loc, extents); } void hlfir::genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder, diff --git a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp index 728c1dd..4a35b73 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp @@ -118,19 +118,28 @@ getIndexExtents(mlir::Location loc, fir::FirOpBuilder &builder, static std::pair createTempFromMold(mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity mold) { - if (mold.isArray()) - TODO(loc, "create temps from array mold"); llvm::SmallVector lenParams; hlfir::genLengthParameters(loc, builder, mold, lenParams); llvm::StringRef tmpName{".tmp"}; - mlir::Value alloca = - builder.createTemporary(loc, mold.getFortranElementType(), tmpName, - /*shape*/ std::nullopt, lenParams); + mlir::Value alloc; + mlir::Value isHeapAlloc; + mlir::Value shape{}; + if (mold.isArray()) { + mlir::Type sequenceType = + hlfir::getFortranElementOrSequenceType(mold.getType()); + shape = hlfir::genShape(loc, builder, mold); + auto extents = getIndexExtents(loc, builder, shape); + alloc = builder.createHeapTemporary(loc, sequenceType, tmpName, extents, + lenParams); + isHeapAlloc = builder.createBool(loc, true); + } else { + alloc = builder.createTemporary(loc, mold.getFortranElementType(), tmpName, + /*shape*/ std::nullopt, lenParams); + isHeapAlloc = builder.createBool(loc, false); + } auto declareOp = builder.create( - loc, alloca, tmpName, /*shapeOrShift*/ mlir::Value{}, lenParams, - fir::FortranVariableFlagsAttr{}); - mlir::Value falseVal = builder.createBool(loc, false); - return {hlfir::Entity{declareOp.getBase()}, falseVal}; + loc, alloc, tmpName, shape, lenParams, fir::FortranVariableFlagsAttr{}); + return {hlfir::Entity{declareOp.getBase()}, isHeapAlloc}; } static std::pair diff --git a/flang/test/HLFIR/as_expr-codegen.fir b/flang/test/HLFIR/as_expr-codegen.fir index 077b5da..7f7c310 100644 --- a/flang/test/HLFIR/as_expr-codegen.fir +++ b/flang/test/HLFIR/as_expr-codegen.fir @@ -12,8 +12,8 @@ func.func @char_expr(%addr: !fir.ref>, %len: index) { // CHECK-SAME: %[[VAL_1:.*]]: index) { // CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] typeparams %[[VAL_1]] {uniq_name = "c"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) // CHECK: %[[VAL_3:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_1]] : index) {bindc_name = ".tmp"} -// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3]] typeparams %[[VAL_1]] {uniq_name = ".tmp"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) // CHECK: %[[VAL_5:.*]] = arith.constant false +// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3]] typeparams %[[VAL_1]] {uniq_name = ".tmp"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) // CHECK: hlfir.assign %[[VAL_2]]#0 to %[[VAL_4]]#0 : !fir.boxchar<1>, !fir.boxchar<1> // CHECK: %[[VAL_6:.*]] = fir.undefined tuple, i1> // CHECK: %[[VAL_7:.*]] = fir.insert_value %[[VAL_6]], %[[VAL_5]], [1 : index] : (tuple, i1>, i1) -> tuple, i1> @@ -29,9 +29,45 @@ func.func @char_expr_2(%addr: !fir.ref>, %len: index) { // CHECK-SAME: %[[VAL_1:.*]]: index) { // CHECK: %[[VAL_2:.*]] = fir.alloca !fir.char<1,10> {bindc_name = ".tmp"} // CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] typeparams %[[VAL_1]] {uniq_name = "c"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) -// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_2]] typeparams %[[VAL_1]] {uniq_name = ".tmp"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) // CHECK: %[[VAL_5:.*]] = arith.constant false +// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_2]] typeparams %[[VAL_1]] {uniq_name = ".tmp"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) // CHECK: hlfir.assign %[[VAL_3]]#0 to %[[VAL_4]]#0 : !fir.ref>, !fir.ref> // CHECK: %[[VAL_6:.*]] = fir.undefined tuple>, i1> // CHECK: %[[VAL_7:.*]] = fir.insert_value %[[VAL_6]], %[[VAL_5]], [1 : index] : (tuple>, i1>, i1) -> tuple>, i1> // CHECK: %[[VAL_8:.*]] = fir.insert_value %[[VAL_7]], %[[VAL_4]]#0, [0 : index] : (tuple>, i1>, !fir.ref>) -> tuple>, i1> + +func.func @shape_from_type(%arg0 : !fir.ref>) { + %expr = hlfir.as_expr %arg0 : (!fir.ref>) -> !hlfir.expr<10x20xi32> + return +} +// CHECK-LABEL: func.func @shape_from_type( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>) { +// CHECK: %[[VAL_1:.*]] = arith.constant 10 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 20 : index +// CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_1]], %[[VAL_2]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_4:.*]] = fir.allocmem !fir.array<10x20xi32> {bindc_name = ".tmp", uniq_name = ""} +// CHECK: %[[VAL_5:.*]] = arith.constant true +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_4]](%[[VAL_3]]) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<2>) -> (!fir.heap>, !fir.heap>) +// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_6]]#0 : !fir.ref>, !fir.heap> +// CHECK: %[[VAL_7:.*]] = fir.undefined tuple>, i1> +// CHECK: %[[VAL_8:.*]] = fir.insert_value %[[VAL_7]], %[[VAL_5]], [1 : index] : (tuple>, i1>, i1) -> tuple>, i1> +// CHECK: %[[VAL_9:.*]] = fir.insert_value %[[VAL_8]], %[[VAL_6]]#0, [0 : index] : (tuple>, i1>, !fir.heap>) -> tuple>, i1> + + +func.func @shape_from_box(%arg0 : !fir.class>) { + %expr = hlfir.as_expr %arg0 : (!fir.class>) -> !hlfir.expr<10x?xi32> + return +} +// CHECK-LABEL: func.func @shape_from_box( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.class>) { +// CHECK: %[[VAL_1:.*]] = arith.constant 10 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_3:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_2]] : (!fir.class>, index) -> (index, index, index) +// CHECK: %[[VAL_4:.*]] = fir.shape %[[VAL_1]], %[[VAL_3]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_5:.*]] = fir.allocmem !fir.array<10x?xi32>, %[[VAL_3]]#1 {bindc_name = ".tmp", uniq_name = ""} +// CHECK: %[[VAL_6:.*]] = arith.constant true +// CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_5]](%[[VAL_4]]) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<2>) -> (!fir.box>, !fir.heap>) +// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_7]]#0 : !fir.class>, !fir.box> +// CHECK: %[[VAL_8:.*]] = fir.undefined tuple>, i1> +// CHECK: %[[VAL_9:.*]] = fir.insert_value %[[VAL_8]], %[[VAL_6]], [1 : index] : (tuple>, i1>, i1) -> tuple>, i1> +// CHECK: %[[VAL_10:.*]] = fir.insert_value %[[VAL_9]], %[[VAL_7]]#0, [0 : index] : (tuple>, i1>, !fir.box>) -> tuple>, i1> -- 2.7.4