[flang-commits] [flang] 6d655ad - [flang][codegen] Add a conversion for `fir.coordinate_of` - part 2
Andrzej Warzynski via flang-commits
flang-commits at lists.llvm.org
Fri Dec 17 02:35:45 PST 2021
Author: Andrzej Warzynski
Date: 2021-12-17T10:34:57Z
New Revision: 6d655ad0111e4fcdcbfba924c89da9053d484095
URL: https://github.com/llvm/llvm-project/commit/6d655ad0111e4fcdcbfba924c89da9053d484095
DIFF: https://github.com/llvm/llvm-project/commit/6d655ad0111e4fcdcbfba924c89da9053d484095.diff
LOG: [flang][codegen] Add a conversion for `fir.coordinate_of` - part 2
This patch extends the `FIRToLLVMLowering` pass in Flang by extending
the hook to transform `fir.coordinate_of` into a sequence of LLVM MLIR
instructions (i.e. `CoordinateOpConversion::doRewrite`). The following
case is added:
3.1 the input object is inside `!fir.ref` (e.g. `!fir.ref<!fir.array>` or
`!fir.ref<!fir.type>`).
3.2 the input object is inside `!fir.ptr` (e.g. `!fir.ptr<!fir.array>` or
`!fir.ptr<!fir.type>`).
>From the point of view of the conversion, 3.1 and 3.2 are currently identical.
This is part of the upstreaming effort from the `fir-dev` branch in [1].
[1] https://github.com/flang-compiler/f18-llvm-project
Originally written by:
Co-authored-by: Jean Perier <jperier at nvidia.com>
Co-authored-by: Eric Schweitz <eschweitz at nvidia.com>
Co-authored-by: V Donaldson <vdonaldson at nvidia.com>
Depends on: D114159
Differential Revision: https://reviews.llvm.org/D115333
Added:
flang/test/Fir/Todo/cordinate_of_5.fir
flang/test/Fir/Todo/cordinate_of_6.fir
Modified:
flang/lib/Optimizer/CodeGen/CodeGen.cpp
flang/test/Fir/convert-to-llvm-invalid.fir
flang/test/Fir/convert-to-llvm.fir
flang/test/Fir/invalid.fir
Removed:
################################################################################
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 970cfa6397847..6018de1799510 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -2940,17 +2940,13 @@ struct CoordinateOpConversion
return success();
}
- // Box type - get the base pointer from the box
- if (auto boxTy = baseObjectTy.dyn_cast<fir::BoxType>()) {
- doRewriteBox(coor, ty, operands, loc, rewriter);
- return success();
- }
+ // Boxed type - get the base pointer from the box
+ if (baseObjectTy.dyn_cast<fir::BoxType>())
+ return doRewriteBox(coor, ty, operands, loc, rewriter);
- // Sequence type (e.g. fir.array)
- if (auto arrTy = objectTy.dyn_cast<fir::SequenceType>()) {
- doRewriteSequence(loc);
- return success();
- }
+ // Reference or pointer type
+ if (baseObjectTy.isa<fir::ReferenceType, fir::PointerType>())
+ return doRewriteRefOrPtr(coor, ty, operands, loc, rewriter);
return rewriter.notifyMatchFailure(
coor, "fir.coordinate_of base operand has unsupported type");
@@ -2976,10 +2972,70 @@ struct CoordinateOpConversion
fir::emitFatalError(val.getLoc(), "must be a constant");
}
+ bool hasSubDimensions(mlir::Type type) const {
+ return type.isa<fir::SequenceType, fir::RecordType, mlir::TupleType>();
+ }
+
+ /// Check whether this form of `!fir.coordinate_of` is supported. These
+ /// additional checks are required, because we are not yet able to convert
+ /// all valid forms of `!fir.coordinate_of`.
+ /// TODO: Either implement the unsupported cases or extend the verifier
+ /// in FIROps.cpp instead.
+ bool supportedCoordinate(mlir::Type type, mlir::ValueRange coors) const {
+ const std::size_t numOfCoors = coors.size();
+ std::size_t i = 0;
+ bool subEle = false;
+ bool ptrEle = false;
+ for (; i < numOfCoors; ++i) {
+ mlir::Value nxtOpnd = coors[i];
+ if (auto arrTy = type.dyn_cast<fir::SequenceType>()) {
+ subEle = true;
+ i += arrTy.getDimension() - 1;
+ type = arrTy.getEleTy();
+ } else if (auto recTy = type.dyn_cast<fir::RecordType>()) {
+ subEle = true;
+ type = recTy.getType(getFieldNumber(recTy, nxtOpnd));
+ } else if (auto tupTy = type.dyn_cast<mlir::TupleType>()) {
+ subEle = true;
+ type = tupTy.getType(getIntValue(nxtOpnd));
+ } else {
+ ptrEle = true;
+ }
+ }
+ if (ptrEle)
+ return (!subEle) && (numOfCoors == 1);
+ return subEle && (i >= numOfCoors);
+ }
+
+ /// Walk the abstract memory layout and determine if the path traverses any
+ /// array types with unknown shape. Return true iff all the array types have a
+ /// constant shape along the path.
+ bool arraysHaveKnownShape(mlir::Type type, mlir::ValueRange coors) const {
+ const std::size_t sz = coors.size();
+ std::size_t i = 0;
+ for (; i < sz; ++i) {
+ mlir::Value nxtOpnd = coors[i];
+ if (auto arrTy = type.dyn_cast<fir::SequenceType>()) {
+ if (fir::sequenceWithNonConstantShape(arrTy))
+ return false;
+ i += arrTy.getDimension() - 1;
+ type = arrTy.getEleTy();
+ } else if (auto strTy = type.dyn_cast<fir::RecordType>()) {
+ type = strTy.getType(getFieldNumber(strTy, nxtOpnd));
+ } else if (auto strTy = type.dyn_cast<mlir::TupleType>()) {
+ type = strTy.getType(getIntValue(nxtOpnd));
+ } else {
+ return true;
+ }
+ }
+ return true;
+ }
+
private:
- void doRewriteBox(fir::CoordinateOp coor, mlir::Type ty,
- mlir::ValueRange operands, mlir::Location loc,
- mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::LogicalResult
+ doRewriteBox(fir::CoordinateOp coor, mlir::Type ty, mlir::ValueRange operands,
+ mlir::Location loc,
+ mlir::ConversionPatternRewriter &rewriter) const {
mlir::Type boxObjTy = coor.getBaseType();
assert(boxObjTy.dyn_cast<fir::BoxType>() && "This is not a `fir.box`");
@@ -3064,11 +3120,118 @@ struct CoordinateOpConversion
}
rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, ty, resultAddr);
- return;
+ return success();
}
- void doRewriteSequence(mlir::Location loc) const {
- TODO(loc, "fir.coordinate_of codegen for sequence types");
+ mlir::LogicalResult
+ doRewriteRefOrPtr(fir::CoordinateOp coor, mlir::Type ty,
+ mlir::ValueRange operands, mlir::Location loc,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Type baseObjectTy = coor.getBaseType();
+
+ mlir::Type currentObjTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
+ bool hasSubdimension = hasSubDimensions(currentObjTy);
+ bool columnIsDeferred = !hasSubdimension;
+
+ if (!supportedCoordinate(currentObjTy, operands.drop_front(1))) {
+ TODO(loc, "unsupported combination of coordinate operands");
+ }
+
+ const bool hasKnownShape =
+ arraysHaveKnownShape(currentObjTy, operands.drop_front(1));
+
+ // If only the column is `?`, then we can simply place the column value in
+ // the 0-th GEP position.
+ if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) {
+ if (!hasKnownShape) {
+ const unsigned sz = arrTy.getDimension();
+ if (arraysHaveKnownShape(arrTy.getEleTy(),
+ operands.drop_front(1 + sz))) {
+ llvm::ArrayRef<int64_t> shape = arrTy.getShape();
+ bool allConst = true;
+ for (unsigned i = 0; i < sz - 1; ++i) {
+ if (shape[i] < 0) {
+ allConst = false;
+ break;
+ }
+ }
+ if (allConst)
+ columnIsDeferred = true;
+ }
+ }
+ }
+
+ if (fir::hasDynamicSize(fir::unwrapSequenceType(currentObjTy))) {
+ mlir::emitError(
+ loc, "fir.coordinate_of with a dynamic element size is unsupported");
+ return failure();
+ }
+
+ if (hasKnownShape || columnIsDeferred) {
+ SmallVector<mlir::Value> offs;
+ if (hasKnownShape && hasSubdimension) {
+ mlir::LLVM::ConstantOp c0 =
+ genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
+ offs.push_back(c0);
+ }
+ const std::size_t sz = operands.size();
+ Optional<int> dims;
+ SmallVector<mlir::Value> arrIdx;
+ for (std::size_t i = 1; i < sz; ++i) {
+ mlir::Value nxtOpnd = operands[i];
+
+ if (!currentObjTy) {
+ mlir::emitError(loc, "invalid coordinate/check failed");
+ return failure();
+ }
+
+ // check if the i-th coordinate relates to an array
+ if (dims.hasValue()) {
+ arrIdx.push_back(nxtOpnd);
+ int dimsLeft = *dims;
+ if (dimsLeft > 1) {
+ dims = dimsLeft - 1;
+ continue;
+ }
+ currentObjTy = currentObjTy.cast<fir::SequenceType>().getEleTy();
+ // append array range in reverse (FIR arrays are column-major)
+ offs.append(arrIdx.rbegin(), arrIdx.rend());
+ arrIdx.clear();
+ dims.reset();
+ continue;
+ }
+ if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) {
+ int d = arrTy.getDimension() - 1;
+ if (d > 0) {
+ dims = d;
+ arrIdx.push_back(nxtOpnd);
+ continue;
+ }
+ currentObjTy = currentObjTy.cast<fir::SequenceType>().getEleTy();
+ offs.push_back(nxtOpnd);
+ continue;
+ }
+
+ // check if the i-th coordinate relates to a field
+ if (auto recTy = currentObjTy.dyn_cast<fir::RecordType>())
+ currentObjTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
+ else if (auto tupTy = currentObjTy.dyn_cast<mlir::TupleType>())
+ currentObjTy = tupTy.getType(getIntValue(nxtOpnd));
+ else
+ currentObjTy = nullptr;
+
+ offs.push_back(nxtOpnd);
+ }
+ if (dims.hasValue())
+ offs.append(arrIdx.rbegin(), arrIdx.rend());
+ mlir::Value base = operands[0];
+ mlir::Value retval = genGEP(loc, ty, rewriter, base, offs);
+ rewriter.replaceOp(coor, retval);
+ return success();
+ }
+
+ mlir::emitError(loc, "fir.coordinate_of base operand has unsupported type");
+ return failure();
}
};
diff --git a/flang/test/Fir/Todo/cordinate_of_5.fir b/flang/test/Fir/Todo/cordinate_of_5.fir
new file mode 100644
index 0000000000000..33dfce224d6c1
--- /dev/null
+++ b/flang/test/Fir/Todo/cordinate_of_5.fir
@@ -0,0 +1,8 @@
+// RUN: %not_todo_cmd fir-opt --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" %s 2>&1 | FileCheck %s
+
+// CHECK: unsupported combination of coordinate operands
+func @test_coordinate_of(%arr : !fir.ref<!fir.array<2 x !fir.char<10, 2>>>, %arg1: index) {
+ %1 = arith.constant 10 : i32
+ %2 = fir.coordinate_of %arr, %arg1, %1 : (!fir.ref<!fir.array<2 x !fir.char<10, 2>>>, index, i32) -> !fir.ref<!fir.char<1,10>>
+ return
+}
diff --git a/flang/test/Fir/Todo/cordinate_of_6.fir b/flang/test/Fir/Todo/cordinate_of_6.fir
new file mode 100644
index 0000000000000..2ccb8c02ea6e3
--- /dev/null
+++ b/flang/test/Fir/Todo/cordinate_of_6.fir
@@ -0,0 +1,8 @@
+// RUN: %not_todo_cmd fir-opt --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" %s 2>&1 | FileCheck %s
+
+// CHECK: unsupported combination of coordinate operands
+
+func @test_coordinate_of(%arr : !fir.ref<!fir.array<2 x i32>>, %arg1: index) {
+ %2 = fir.coordinate_of %arr, %arg1, %arg1 : (!fir.ref<!fir.array<2 x i32>>, index, index) -> !fir.ref<i32>
+ return
+}
diff --git a/flang/test/Fir/convert-to-llvm-invalid.fir b/flang/test/Fir/convert-to-llvm-invalid.fir
index 41ffe7e5e6ddd..43ea7e58f7ab2 100644
--- a/flang/test/Fir/convert-to-llvm-invalid.fir
+++ b/flang/test/Fir/convert-to-llvm-invalid.fir
@@ -88,3 +88,13 @@ func @bar_select_type(%arg : !fir.box<!fir.ref<f32>>) -> i32 {
%zero = arith.constant 0 : i32
return %zero : i32
}
+
+// -----
+
+// `fir.coordinate_of` - dynamically sized arrays are not supported
+func @coordinate_of_dynamic_array(%arg0: !fir.ref<!fir.array<1x!fir.char<4,?>>>, %arg1: index) {
+ // expected-error at +2{{fir.coordinate_of with a dynamic element size is unsupported}}
+ // expected-error at +1{{failed to legalize operation 'fir.coordinate_of'}}
+ %p = fir.coordinate_of %arg0, %arg1 : (!fir.ref<!fir.array<1x!fir.char<4,?>>>, index) -> !fir.ref<f32>
+ return
+}
diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir
index f7e3c465fcb8e..669e9a30b6375 100644
--- a/flang/test/Fir/convert-to-llvm.fir
+++ b/flang/test/Fir/convert-to-llvm.fir
@@ -2196,7 +2196,7 @@ func @foo(%arg0: !fir.box<!fir.array<?x!fir.type<t{i:i32,c:!fir.char<1,10>}>>>)
// -----
-// Test `fir.coordinate_of` conversion
+// Test `fir.coordinate_of` conversion (items inside `!fir.box`)
// 1. COMPLEX TYPE (`fir.complex` is a special case)
// Complex type wrapped in `fir.ref`
@@ -2225,7 +2225,7 @@ func @coordinate_box_complex(%arg0: !fir.box<!fir.complex<16>>, %arg1: index) {
// -----
-// Test `fir.coordinate_of` conversion
+// Test `fir.coordinate_of` conversion (items inside `!fir.box`)
// 2. BOX TYPE (objects wrapped in `fir.box`)
// Derived type - basic case (1 index)
@@ -2278,7 +2278,7 @@ func @coordinate_box_derived_2(%arg0: !fir.box<!fir.type<derived_2{field_1:!fir.
// -----
-// Test `fir.coordinate_of` conversion
+// Test `fir.coordinate_of` conversion (items inside `!fir.box`)
// 3. BOX TYPE - `fir.array` wrapped in `fir.box`
// `fir.array` inside a `fir.box` (1d)
@@ -2391,7 +2391,7 @@ func @coordinate_box_array_2d(%arg0: !fir.box<!fir.array<10 x 10 x f32>>, %arg1:
// -----
-// Test `fir.coordinate_of` conversion
+// Test `fir.coordinate_of` conversion (items inside `!fir.box`)
// 4. BOX TYPE - `fir.derived` inside `fir.array`
func @coordinate_box_derived_inside_array(%arg0: !fir.box<!fir.array<10 x !fir.type<derived_3{field_1:f32, field_2:f32}>>>, %arg1 : index) {
@@ -2424,3 +2424,118 @@ func @coordinate_box_derived_inside_array(%arg0: !fir.box<!fir.array<10 x !fir.t
// CHECK: %[[VAL_21:.*]] = llvm.bitcast %[[VAL_20]] : !llvm.ptr<f32> to !llvm.ptr<i8>
// CHECK: %[[VAL_22:.*]] = llvm.bitcast %[[VAL_21]] : !llvm.ptr<i8> to !llvm.ptr<f32>
// CHECK: llvm.return
+
+// -----
+
+// Test `fir.coordinate_of` conversion (items inside `!fir.ref`)
+
+// 5.1. `fir.array`
+func @coordinate_array_unknown_size_1d(%arg0: !fir.ref<!fir.array<? x i32>>, %arg1 : index) {
+ %q = fir.coordinate_of %arg0, %arg1 : (!fir.ref<!fir.array<? x i32>>, index) -> !fir.ref<i32>
+ return
+}
+// CHECK-LABEL: llvm.func @coordinate_array_unknown_size_1d(
+// CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr<i32>,
+// CHECK-SAME: %[[VAL_1:.*]]: i64) {
+// CHECK: %[[VAL_2:.*]] = llvm.getelementptr %[[VAL_0]]{{\[}}%[[VAL_1]]] : (!llvm.ptr<i32>, i64) -> !llvm.ptr<i32>
+// CHECK: llvm.return
+// CHECK: }
+
+func @coordinate_array_known_size_1d(%arg0: !fir.ref<!fir.array<10 x i32>>, %arg1 : index) {
+ %q = fir.coordinate_of %arg0, %arg1 : (!fir.ref<!fir.array<10 x i32>>, index) -> !fir.ref<i32>
+ return
+}
+// CHECK-LABEL: llvm.func @coordinate_array_known_size_1d(
+// CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr<array<10 x i32>>,
+// CHECK-SAME: %[[VAL_1:.*]]: i64) {
+// CHECK: %[[VAL_2:.*]] = llvm.mlir.constant(0 : i64) : i64
+// CHECK: %[[VAL_3:.*]] = llvm.getelementptr %[[VAL_0]]{{\[}}%[[VAL_2]], %[[VAL_1]]] : (!llvm.ptr<array<10 x i32>>, i64, i64) -> !llvm.ptr<i32>
+// CHECK: llvm.return
+// CHECK: }
+
+func @coordinate_array_known_size_2d(%arg0: !fir.ref<!fir.array<10 x 10 x i32>>, %arg1 : index, %arg2 : index) {
+ %q = fir.coordinate_of %arg0, %arg1, %arg2 : (!fir.ref<!fir.array<10 x 10 x i32>>, index, index) -> !fir.ref<i32>
+ return
+}
+// CHECK-LABEL: llvm.func @coordinate_array_known_size_2d(
+// CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr<array<10 x array<10 x i32>>>,
+// CHECK-SAME: %[[VAL_1:.*]]: i64,
+// CHECK-SAME: %[[VAL_2:.*]]: i64) {
+// CHECK: %[[VAL_3:.*]] = llvm.mlir.constant(0 : i64) : i64
+// CHECK: %[[VAL_4:.*]] = llvm.getelementptr %[[VAL_0]]{{\[}}%[[VAL_3]], %[[VAL_2]], %[[VAL_1]]] : (!llvm.ptr<array<10 x array<10 x i32>>>, i64, i64, i64) -> !llvm.ptr<i32>
+// CHECK: llvm.return
+// CHECK: }
+
+// 5.2. `fir.derived`
+func @coordinate_ref_derived(%arg0: !fir.ref<!fir.type<dervied_4{field_1:i32, field_2:i32}>>) {
+ %idx = fir.field_index field_2, !fir.type<dervied_4{field_1:i32, field_2:i32}>
+ %q = fir.coordinate_of %arg0, %idx : (!fir.ref<!fir.type<dervied_4{field_1:i32, field_2:i32}>>, !fir.field) -> !fir.ref<i32>
+ return
+}
+// CHECK-LABEL: llvm.func @coordinate_ref_derived(
+// CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr<struct<"dervied_4", (i32, i32)>>) {
+// CHECK: %[[VAL_1:.*]] = llvm.mlir.constant(1 : i32) : i32
+// CHECK: %[[VAL_2:.*]] = llvm.mlir.constant(0 : i64) : i64
+// CHECK: %[[VAL_3:.*]] = llvm.getelementptr %[[VAL_0]]{{\[}}%[[VAL_2]], %[[VAL_1]]] : (!llvm.ptr<struct<"dervied_4", (i32, i32)>>, i64, i32) -> !llvm.ptr<i32>
+// CHECK: llvm.return
+// CHECK: }
+
+func @coordinate_ref_derived_nested(%arg0: !fir.ref<!fir.type<derived_5{field_1:!fir.type<nested_derived{inner1:i32, inner2:f32}>, field_2:i32}>>) {
+ %idx0 = fir.field_index field_1, !fir.type<derived_5{field_1:!fir.type<nested_derived{inner1:i32, inner2:f32}>, field_2:i32}>
+ %idx1 = fir.field_index inner2, !fir.type<nested_derived{inner1:i32, inner2:f32}>
+ %q = fir.coordinate_of %arg0, %idx0, %idx1 : (!fir.ref<!fir.type<derived_5{field_1:!fir.type<nested_derived{inner1:i32, inner2:f32}>, field_2:i32}>>, !fir.field, !fir.field) -> !fir.ref<i32>
+ return
+}
+// CHECK-LABEL: llvm.func @coordinate_ref_derived_nested(
+// CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr<struct<"derived_5", (struct<"nested_derived", (i32, f32)>, i32)>>) {
+// CHECK: %[[VAL_1:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK: %[[VAL_2:.*]] = llvm.mlir.constant(1 : i32) : i32
+// CHECK: %[[VAL_3:.*]] = llvm.mlir.constant(0 : i64) : i64
+// CHECK: %[[VAL_4:.*]] = llvm.getelementptr %[[VAL_0]]{{\[}}%[[VAL_3]], %[[VAL_1]], %[[VAL_2]]] : (!llvm.ptr<struct<"derived_5", (struct<"nested_derived", (i32, f32)>, i32)>>, i64, i32, i32) -> !llvm.ptr<i32>
+// CHECK: llvm.return
+// CHECK: }
+
+// 5.3 `fir.char`
+func @test_coordinate_of_char(%arr : !fir.ref<!fir.char<10, 2>>) {
+ %1 = arith.constant 10 : i32
+ %2 = fir.coordinate_of %arr, %1 : (!fir.ref<!fir.char<10, 2>>, i32) -> !fir.ref<i80>
+ return
+}
+// CHECK-LABEL: llvm.func @test_coordinate_of_char(
+// CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr<array<2 x i80>>) {
+// CHECK: %[[VAL_1:.*]] = llvm.mlir.constant(10 : i32) : i32
+// CHECK: %[[VAL_2:.*]] = llvm.getelementptr %[[VAL_0]]{{\[}}%[[VAL_1]]] : (!llvm.ptr<array<2 x i80>>, i32) -> !llvm.ptr<i80>
+// CHECK: llvm.return
+// CHECK: }
+
+// 5.4 `mlir.tuple`
+func @test_coordinate_of_tuple(%tup : !fir.ref<tuple<!fir.ref<i32>>>) {
+ %1 = arith.constant 0 : i64
+ %2 = fir.coordinate_of %tup, %1 : (!fir.ref<tuple<!fir.ref<i32>>>, i64) -> !fir.ref<i32>
+ return
+}
+// CHECK-LABEL: llvm.func @test_coordinate_of_tuple(
+// CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr<struct<(ptr<i32>)>>) {
+// CHECK: %[[VAL_1:.*]] = llvm.mlir.constant(0 : i64) : i64
+// CHECK: %[[VAL_2:.*]] = llvm.mlir.constant(0 : i64) : i64
+// CHECK: %[[VAL_3:.*]] = llvm.getelementptr %[[VAL_0]]{{\[}}%[[VAL_2]], %[[VAL_1]]] : (!llvm.ptr<struct<(ptr<i32>)>>, i64, i64) -> !llvm.ptr<i32>
+// CHECK: llvm.return
+// CHECK: }
+
+// -----
+
+// Test `fir.coordinate_of` conversion - items inside `!fir.ptr`. This should
+// be almost identical to `!fir.ref` (i.e. it's the same code path in the code
+// gen). Instead of duplicating the tests, only one for sanity-checking is added.
+
+// 6.1. `fir.array`
+func @coordinate_array_unknown_size_1d(%arg0: !fir.ptr<!fir.array<? x i32>>, %arg1 : index) {
+ %q = fir.coordinate_of %arg0, %arg1 : (!fir.ptr<!fir.array<? x i32>>, index) -> !fir.ref<i32>
+ return
+}
+// CHECK-LABEL: llvm.func @coordinate_array_unknown_size_1d(
+// CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr<i32>,
+// CHECK-SAME: %[[VAL_1:.*]]: i64) {
+// CHECK: %[[VAL_2:.*]] = llvm.getelementptr %[[VAL_0]]{{\[}}%[[VAL_1]]] : (!llvm.ptr<i32>, i64) -> !llvm.ptr<i32>
+// CHECK: llvm.return
+// CHECK: }
diff --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir
index b7c99f1b690ac..b9933389908cc 100644
--- a/flang/test/Fir/invalid.fir
+++ b/flang/test/Fir/invalid.fir
@@ -284,6 +284,15 @@ func @test_coordinate_of(%arr : !fir.ref<!fir.char<10>>) {
// -----
+func @test_coordinate_of(%arr : !fir.ref<!fir.char<10, 1>>) {
+ %1 = arith.constant 10 : i32
+ // expected-error at +1 {{'fir.coordinate_of' op cannot apply coordinate_of to this type}}
+ %2 = fir.coordinate_of %arr, %1 : (!fir.ref<!fir.char<10, 1>>, i32) -> !fir.ref<f32>
+ return
+}
+
+// -----
+
%0 = arith.constant 22 : i32
// expected-error at +1 {{'fir.embox' op operand #0 must be any reference, but got 'i32'}}
%1 = fir.embox %0 : (i32) -> !fir.box<i32>
More information about the flang-commits
mailing list