[flang-commits] [flang] 783222e - [flang] Fix codegen of subcomponents' indexing
Leandro Lupori via flang-commits
flang-commits at lists.llvm.org
Mon Jul 3 05:01:30 PDT 2023
Author: Leandro Lupori
Date: 2023-07-03T08:59:53-03:00
New Revision: 783222efded0ac5f7d76ea41ec03eb2bf83ff918
URL: https://github.com/llvm/llvm-project/commit/783222efded0ac5f7d76ea41ec03eb2bf83ff918
DIFF: https://github.com/llvm/llvm-project/commit/783222efded0ac5f7d76ea41ec03eb2bf83ff918.diff
LOG: [flang] Fix codegen of subcomponents' indexing
Identify multidimensional array indices in subcomponents and
convert them from column-major to row-major ordering.
This fixes codegen for fircg.ext_array_coor, fircg.ext_embox and,
possibly, fircg.ext_rebox.
Fixes https://github.com/llvm/llvm-project/issues/62038
Reviewed By: jeanPerier
Differential Revision: https://reviews.llvm.org/D154214
Added:
Modified:
flang/lib/Optimizer/CodeGen/CodeGen.cpp
flang/test/Fir/convert-to-llvm.fir
Removed:
################################################################################
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index b03c5bb9c4218b..0df2e494234daa 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -1252,6 +1252,45 @@ struct FreeMemOpConversion : public FIROpConversion<fir::FreeMemOp> {
};
} // namespace
+// Convert subcomponent array indices from column-major to row-major ordering.
+static llvm::SmallVector<mlir::Value>
+convertSubcomponentIndices(mlir::Location loc, mlir::Type eleTy,
+ mlir::ValueRange indices,
+ mlir::Type *retTy = nullptr) {
+ llvm::SmallVector<mlir::Value> result;
+ llvm::SmallVector<mlir::Value> arrayIndices;
+
+ auto appendArrayIndices = [&] {
+ if (arrayIndices.empty())
+ return;
+ std::reverse(arrayIndices.begin(), arrayIndices.end());
+ result.append(arrayIndices.begin(), arrayIndices.end());
+ arrayIndices.clear();
+ };
+
+ for (mlir::Value index : indices) {
+ // Component indices can be field index to select a component, or array
+ // index, to select an element in an array component.
+ if (auto structTy = mlir::dyn_cast<mlir::LLVM::LLVMStructType>(eleTy)) {
+ std::int64_t cstIndex = getConstantIntValue(index);
+ assert(cstIndex < (int64_t)structTy.getBody().size() &&
+ "out-of-bounds struct field index");
+ eleTy = structTy.getBody()[cstIndex];
+ appendArrayIndices();
+ result.push_back(index);
+ } else if (auto arrayTy =
+ mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(eleTy)) {
+ eleTy = arrayTy.getElementType();
+ arrayIndices.push_back(index);
+ } else
+ fir::emitFatalError(loc, "Unexpected subcomponent type");
+ }
+ appendArrayIndices();
+ if (retTy)
+ *retTy = eleTy;
+ return result;
+}
+
/// Common base class for embox to descriptor conversion.
template <typename OP>
struct EmboxCommonConversion : public FIROpConversion<OP> {
@@ -1556,21 +1595,9 @@ struct EmboxCommonConversion : public FIROpConversion<OP> {
resultTy = arrayTy.getElementType();
gepArgs.push_back(interiorIndex);
}
- for (mlir::Value componentIndex : componentIndices) {
- // Component indices can be field index to select a component, or array
- // index, to select an element in an array component.
- if (auto structTy = resultTy.dyn_cast<mlir::LLVM::LLVMStructType>()) {
- std::int64_t cstIndex = getConstantIntValue(componentIndex);
- resultTy = structTy.getBody()[cstIndex];
- } else if (auto arrayTy =
- resultTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
- resultTy = arrayTy.getElementType();
- } else {
- fir::emitFatalError(loc, "corrupted component GEP generated being "
- "generated in fir.embox/fir.rebox");
- }
- gepArgs.push_back(componentIndex);
- }
+ llvm::SmallVector<mlir::Value> gepIndices =
+ convertSubcomponentIndices(loc, resultTy, componentIndices, &resultTy);
+ gepArgs.append(gepIndices.begin(), gepIndices.end());
if (substringOffset) {
if (auto arrayTy = resultTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
gepArgs.push_back(*substringOffset);
@@ -2407,10 +2434,11 @@ struct XArrayCoorOpConversion
// as below, as the LLVM struct type cannot be statically defined.
TODO(loc, "derived type with type parameters");
}
- // TODO: array offset subcomponents must be converted to LLVM's
- // row-major layout here.
- for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
- args.push_back(operands[i]);
+ llvm::SmallVector<mlir::Value> indices = convertSubcomponentIndices(
+ loc, elementType,
+ operands.slice(coor.subcomponentOffset(),
+ coor.getSubcomponent().size()));
+ args.append(indices.begin(), indices.end());
rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, casted, args);
return mlir::success();
}
@@ -2437,7 +2465,10 @@ struct XArrayCoorOpConversion
}
// Cast the base address to a pointer to T.
base = rewriter.create<mlir::LLVM::BitcastOp>(loc, ty, operands[0]);
- } else {
+ }
+
+ llvm::SmallVector<mlir::LLVM::GEPArg> args = {offset};
+ if (!coor.getSubcomponent().empty()) {
// Operand #0 must have a pointer type. For subcomponent slicing, we
// want to cast away the array type and have a plain struct type.
mlir::Type ty0 = operands[0].getType();
@@ -2448,10 +2479,12 @@ struct XArrayCoorOpConversion
eleTy = arrTy.getElementType();
auto newTy = mlir::LLVM::LLVMPointerType::get(eleTy);
base = rewriter.create<mlir::LLVM::BitcastOp>(loc, newTy, operands[0]);
+ llvm::SmallVector<mlir::Value> indices = convertSubcomponentIndices(
+ loc, eleTy,
+ operands.slice(coor.subcomponentOffset(),
+ coor.getSubcomponent().size()));
+ args.append(indices.begin(), indices.end());
}
- llvm::SmallVector<mlir::LLVM::GEPArg> args = {offset};
- for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
- args.push_back(operands[i]);
rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, base, args);
return mlir::success();
}
diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir
index 14cd58a6148b19..d0c154fb0376e3 100644
--- a/flang/test/Fir/convert-to-llvm.fir
+++ b/flang/test/Fir/convert-to-llvm.fir
@@ -1988,6 +1988,27 @@ func.func private @_QPtest_dt_callee(%arg0: !fir.box<!fir.array<?xi32>>)
// CHECK: llvm.store %[[BOX10]], %[[ALLOCA]] : !llvm.ptr<struct<(ptr<i32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>>
// CHECK: llvm.call @_QPtest_dt_callee(%1) : (!llvm.ptr<struct<(ptr<i32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>>) -> ()
+// Conversion with a subcomponent that indexes a 2d array field in a derived type.
+
+func.func @_QPtest_dt_slice2(%arg0: !fir.ref<!fir.array<2x!fir.type<_QPtest_dt_slice2Tt{a:!fir.array<2x3xi32>}>>>) {
+ %c0 = arith.constant 0 : index
+ %c1 = arith.constant 1 : index
+ %c2 = arith.constant 2 : index
+ %1 = fir.field_index a, !fir.type<_QPtest_dt_slice2Tt{a:!fir.array<2x3xi32>}>
+ %2 = fircg.ext_embox %arg0(%c2)[%c1, %c2, %c1] path %1, %c0, %c1 : (!fir.ref<!fir.array<2x!fir.type<_QPtest_dt_slice2Tt{a:!fir.array<2x3xi32>}>>>, index, index, index, index, !fir.field, index, index) -> !fir.box<!fir.array<2xi32>>
+ return
+}
+
+// CHECK-LABEL: llvm.func @_QPtest_dt_slice2(
+// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr<array<2 x struct<"_QPtest_dt_slice2Tt", (array<3 x array<2 x i32>>)>>>) {
+// CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : index) : i64
+// CHECK: %[[C1:.*]] = llvm.mlir.constant(1 : index) : i64
+// CHECK: %[[C2:.*]] = llvm.mlir.constant(2 : index) : i64
+// CHECK: %[[C0_2:.*]] = llvm.mlir.constant(0 : i64) : i64
+// CHECK: %{{.*}} = llvm.getelementptr %[[ARG0]][%[[C0_2]], {{.*}}, 0, %[[C1]], %[[C0]]] : (!llvm.ptr<array<2 x struct<"_QPtest_dt_slice2Tt", (array<3 x array<2 x i32>>)>>>, i64, i64, i64, i64) -> !llvm.ptr<i32>
+// CHECK: return
+// CHECK: }
+
// -----
// Test `fircg.ext_array_coor` conversion.
@@ -2191,6 +2212,21 @@ func.func @ext_array_coor_dt_slice(%arg0: !fir.ref<!fir.array<20x!fir.type<_QFte
// CHECK: llvm.return
// CHECK: }
+// Conversion for derived type with an array field
+
+func.func @ext_array_coor_dt_slice2(%arg0: !fir.ref<!fir.array<2x!fir.type<_QFtest_dt_slice2Tt{a:!fir.array<2x3xi32>}>>>, %idx1 : index, %idx2 : index, %idx3 : index, %idx4 : index, %idx5 : index, %idx6 : index, %idx7 : index) {
+ %1 = fir.field_index a, !fir.type<_QFtest_dt_sliceT2t{a:!fir.array<2x3xi32>}>
+ %2 = fircg.ext_array_coor %arg0(%idx1)[%idx2, %idx3, %idx4] path %1, %idx5, %idx6 <%idx7> : (!fir.ref<!fir.array<2x!fir.type<_QFtest_dt_slice2Tt{a:!fir.array<2x3xi32>}>>>, index, index, index, index, !fir.field, index, index, index) -> !fir.ref<i32>
+ return
+}
+
+// CHECK-LABEL: llvm.func @ext_array_coor_dt_slice2(
+// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr<array<2 x struct<"_QFtest_dt_slice2Tt", (array<3 x array<2 x i32>>)>>>, %[[IDX1:.*]]: i64, %[[IDX2:.*]]: i64, %[[IDX3:.*]]: i64, %[[IDX4:.*]]: i64, %[[IDX5:.*]]: i64, %[[IDX6:.*]]: i64, %[[IDX7:.*]]: i64) {
+// CHECK: %[[PTR:.*]] = llvm.bitcast %[[ARG0]] : !llvm.ptr<array<2 x struct<"_QFtest_dt_slice2Tt", (array<3 x array<2 x i32>>)>>> to !llvm.ptr<struct<"_QFtest_dt_slice2Tt", (array<3 x array<2 x i32>>)>>
+// CHECK: %{{.*}} = llvm.getelementptr %[[PTR]][%{{.*}}, 0, %[[IDX6]], %[[IDX5]]] : (!llvm.ptr<struct<"_QFtest_dt_slice2Tt", (array<3 x array<2 x i32>>)>>, i64, i64, i64) -> !llvm.ptr<i32>
+// CHECK: llvm.return
+// CHECK: }
+
// -----
// Check `fircg.ext_rebox` conversion to LLVM IR dialect
More information about the flang-commits
mailing list