[flang-commits] [flang] c67a874 - [flang] Add more diagnostics to fir.coordinate_of

Valentin Clement via flang-commits flang-commits at lists.llvm.org
Tue Jun 21 11:43:33 PDT 2022


Author: Valentin Clement
Date: 2022-06-21T20:43:22+02:00
New Revision: c67a87444f5585aafa659c52544ac912f283e7e3

URL: https://github.com/llvm/llvm-project/commit/c67a87444f5585aafa659c52544ac912f283e7e3
DIFF: https://github.com/llvm/llvm-project/commit/c67a87444f5585aafa659c52544ac912f283e7e3.diff

LOG: [flang] Add more diagnostics to fir.coordinate_of

Add more diagnostics to fir.coordinate_of to provide better checking
that the IR is sane.

This patch is part of the upstreaming effort from fir-dev branch.

Reviewed By: PeteSteinfeld

Differential Revision: https://reviews.llvm.org/D128255

Co-authored-by: Eric Schweitz <eschweitz at nvidia.com>

Added: 
    flang/test/Fir/coordinate_of_1.fir
    flang/test/Fir/coordinateof.fir

Modified: 
    flang/include/flang/Optimizer/Dialect/FIROps.td
    flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp
    flang/lib/Optimizer/Dialect/FIROps.cpp
    flang/test/Fir/convert-to-llvm.fir
    flang/test/Fir/invalid.fir

Removed: 
    flang/test/Fir/Todo/coordinate_of_1.fir
    flang/test/Fir/Todo/coordinate_of_5.fir
    flang/test/Fir/Todo/coordinate_of_6.fir


################################################################################
diff  --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index b9ba0a7a2cd24..6dc6bae6afde9 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -1716,8 +1716,8 @@ def fir_FieldIndexOp : fir_OneResultOp<"field_index", [NoSideEffect]> {
       "mlir::Type":$recTy, CArg<"mlir::ValueRange","{}">:$operands)>];
 
   let extraClassDeclaration = [{
-    static constexpr llvm::StringRef fieldAttrName() { return "field_id"; }
-    static constexpr llvm::StringRef typeAttrName() { return "on_type"; }
+    static constexpr llvm::StringRef getFieldAttrName() { return "field_id"; }
+    static constexpr llvm::StringRef getTypeAttrName() { return "on_type"; }
     llvm::StringRef getFieldName() { return getFieldId(); }
     llvm::SmallVector<mlir::Attribute> getAttributes();
   }];
@@ -1970,21 +1970,22 @@ def fir_LenParamIndexOp : fir_OneResultOp<"len_param_index", [NoSideEffect]> {
     ```
   }];
 
-  let arguments = (ins StrAttr:$field_id, TypeAttr:$on_type);
+  let arguments = (ins
+    StrAttr:$field_id,
+    TypeAttr:$on_type,
+    Variadic<AnyIntegerType>:$typeparams
+  );
 
   let hasCustomAssemblyFormat = 1;
 
   let builders = [OpBuilder<(ins "llvm::StringRef":$fieldName,
-      "mlir::Type":$recTy),
-    [{
-      $_state.addAttribute(fieldAttrName(), $_builder.getStringAttr(fieldName));
-      $_state.addAttribute(typeAttrName(), mlir::TypeAttr::get(recTy));
-    }]
-  >];
+      "mlir::Type":$recTy, CArg<"mlir::ValueRange","{}">:$operands)>];
 
   let extraClassDeclaration = [{
-    static constexpr llvm::StringRef fieldAttrName() { return "field_id"; }
-    static constexpr llvm::StringRef typeAttrName() { return "on_type"; }
+    static constexpr llvm::StringRef getFieldAttrName() { return "field_id"; }
+    static constexpr llvm::StringRef getTypeAttrName() { return "on_type"; }
+    llvm::StringRef getParamName() { return getFieldId(); }
+    llvm::SmallVector<mlir::Attribute> getAttributes();
   }];
 }
 

diff  --git a/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp b/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp
index 1bc490aade3af..e652ca75f207f 100644
--- a/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp
+++ b/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp
@@ -307,7 +307,7 @@ class BoxedProcedurePass : public BoxedProcedurePassBase<BoxedProcedurePass> {
             auto toTy = typeConverter.convertType(ty);
             auto toOnTy = typeConverter.convertType(onTy);
             rewriter.replaceOpWithNewOp<LenParamIndexOp>(
-                mem, toTy, index.getFieldId(), toOnTy);
+                mem, toTy, index.getFieldId(), toOnTy, index.getTypeparams());
           }
         } else if (op->getDialect() == firDialect) {
           rewriter.startRootUpdate(op);

diff  --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index 05478ac5dd9a2..069fa4344c5d1 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -924,7 +924,7 @@ mlir::ParseResult fir::CoordinateOp::parse(mlir::OpAsmParser &parser,
 }
 
 mlir::LogicalResult fir::CoordinateOp::verify() {
-  auto refTy = getRef().getType();
+  const mlir::Type refTy = getRef().getType();
   if (fir::isa_ref_type(refTy)) {
     auto eleTy = fir::dyn_cast_ptrEleTy(refTy);
     if (auto arrTy = eleTy.dyn_cast<fir::SequenceType>()) {
@@ -935,18 +935,70 @@ mlir::LogicalResult fir::CoordinateOp::verify() {
     }
     if (!(fir::isa_aggregate(eleTy) || fir::isa_complex(eleTy) ||
           fir::isa_char_string(eleTy)))
-      return emitOpError("cannot apply coordinate_of to this type");
-  }
-  // Recovering a LEN type parameter only makes sense from a boxed value. For a
-  // bare reference, the LEN type parameters must be passed as additional
-  // arguments to `op`.
-  for (auto co : getCoor())
-    if (mlir::dyn_cast_or_null<fir::LenParamIndexOp>(co.getDefiningOp())) {
-      if (getNumOperands() != 2)
-        return emitOpError("len_param_index must be last argument");
-      if (!getRef().getType().isa<BoxType>())
-        return emitOpError("len_param_index must be used on box type");
+      return emitOpError("cannot apply to this element type");
+  }
+  auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(refTy);
+  unsigned dimension = 0;
+  const unsigned numCoors = getCoor().size();
+  for (auto coorOperand : llvm::enumerate(getCoor())) {
+    auto co = coorOperand.value();
+    if (dimension == 0 && eleTy.isa<fir::SequenceType>()) {
+      dimension = eleTy.cast<fir::SequenceType>().getDimension();
+      if (dimension == 0)
+        return emitOpError("cannot apply to array of unknown rank");
     }
+    if (auto *defOp = co.getDefiningOp()) {
+      if (auto index = mlir::dyn_cast<fir::LenParamIndexOp>(defOp)) {
+        // Recovering a LEN type parameter only makes sense from a boxed
+        // value. For a bare reference, the LEN type parameters must be
+        // passed as additional arguments to `index`.
+        if (refTy.isa<fir::BoxType>()) {
+          if (coorOperand.index() != numCoors - 1)
+            return emitOpError("len_param_index must be last argument");
+          if (getNumOperands() != 2)
+            return emitOpError("too many operands for len_param_index case");
+        }
+        if (eleTy != index.getOnType())
+          emitOpError(
+              "len_param_index type not compatible with reference type");
+        return mlir::success();
+      } else if (auto index = mlir::dyn_cast<fir::FieldIndexOp>(defOp)) {
+        if (eleTy != index.getOnType())
+          emitOpError("field_index type not compatible with reference type");
+        if (auto recTy = eleTy.dyn_cast<fir::RecordType>()) {
+          eleTy = recTy.getType(index.getFieldName());
+          continue;
+        }
+        return emitOpError("field_index not applied to !fir.type");
+      }
+    }
+    if (dimension) {
+      if (--dimension == 0)
+        eleTy = eleTy.cast<fir::SequenceType>().getEleTy();
+    } else {
+      if (auto t = eleTy.dyn_cast<mlir::TupleType>()) {
+        // FIXME: Generally, we don't know which field of the tuple is being
+        // referred to unless the operand is a constant. Just assume everything
+        // is good in the tuple case for now.
+        return mlir::success();
+      } else if (auto t = eleTy.dyn_cast<fir::RecordType>()) {
+        // FIXME: This is the same as the tuple case.
+        return mlir::success();
+      } else if (auto t = eleTy.dyn_cast<fir::ComplexType>()) {
+        eleTy = t.getElementType();
+      } else if (auto t = eleTy.dyn_cast<mlir::ComplexType>()) {
+        eleTy = t.getElementType();
+      } else if (auto t = eleTy.dyn_cast<fir::CharacterType>()) {
+        if (t.getLen() == fir::CharacterType::singleton())
+          return emitOpError("cannot apply to character singleton");
+        eleTy = fir::CharacterType::getSingleton(t.getContext(), t.getFKind());
+        if (fir::unwrapRefType(getType()) != eleTy)
+          return emitOpError("character type mismatch");
+      } else {
+        return emitOpError("invalid parameters (too many)");
+      }
+    }
+  }
   return mlir::success();
 }
 
@@ -1331,19 +1383,20 @@ void fir::GlobalLenOp::print(mlir::OpAsmPrinter &p) {
 // FieldIndexOp
 //===----------------------------------------------------------------------===//
 
-mlir::ParseResult fir::FieldIndexOp::parse(mlir::OpAsmParser &parser,
-                                           mlir::OperationState &result) {
+template <typename TY>
+mlir::ParseResult parseFieldLikeOp(mlir::OpAsmParser &parser,
+                                   mlir::OperationState &result) {
   llvm::StringRef fieldName;
   auto &builder = parser.getBuilder();
   mlir::Type recty;
   if (parser.parseOptionalKeyword(&fieldName) || parser.parseComma() ||
       parser.parseType(recty))
     return mlir::failure();
-  result.addAttribute(fir::FieldIndexOp::fieldAttrName(),
+  result.addAttribute(fir::FieldIndexOp::getFieldAttrName(),
                       builder.getStringAttr(fieldName));
   if (!recty.dyn_cast<fir::RecordType>())
     return mlir::failure();
-  result.addAttribute(fir::FieldIndexOp::typeAttrName(),
+  result.addAttribute(fir::FieldIndexOp::getTypeAttrName(),
                       mlir::TypeAttr::get(recty));
   if (!parser.parseOptionalLParen()) {
     llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;
@@ -1354,23 +1407,30 @@ mlir::ParseResult fir::FieldIndexOp::parse(mlir::OpAsmParser &parser,
         parser.resolveOperands(operands, types, loc, result.operands))
       return mlir::failure();
   }
-  mlir::Type fieldType = fir::FieldType::get(builder.getContext());
+  mlir::Type fieldType = TY::get(builder.getContext());
   if (parser.addTypeToList(fieldType, result.types))
     return mlir::failure();
   return mlir::success();
 }
 
-void fir::FieldIndexOp::print(mlir::OpAsmPrinter &p) {
+mlir::ParseResult fir::FieldIndexOp::parse(mlir::OpAsmParser &parser,
+                                           mlir::OperationState &result) {
+  return parseFieldLikeOp<fir::FieldType>(parser, result);
+}
+
+template <typename OP>
+void printFieldLikeOp(mlir::OpAsmPrinter &p, OP &op) {
   p << ' '
-    << getOperation()
-           ->getAttrOfType<mlir::StringAttr>(fir::FieldIndexOp::fieldAttrName())
+    << op.getOperation()
+           ->template getAttrOfType<mlir::StringAttr>(
+               fir::FieldIndexOp::getFieldAttrName())
            .getValue()
-    << ", " << getOperation()->getAttr(fir::FieldIndexOp::typeAttrName());
-  if (getNumOperands()) {
+    << ", " << op.getOperation()->getAttr(fir::FieldIndexOp::getTypeAttrName());
+  if (op.getNumOperands()) {
     p << '(';
-    p.printOperands(getTypeparams());
-    const auto *sep = ") : ";
-    for (auto op : getTypeparams()) {
+    p.printOperands(op.getTypeparams());
+    auto sep = ") : ";
+    for (auto op : op.getTypeparams()) {
       p << sep;
       if (op)
         p.printType(op.getType());
@@ -1381,12 +1441,16 @@ void fir::FieldIndexOp::print(mlir::OpAsmPrinter &p) {
   }
 }
 
+void fir::FieldIndexOp::print(mlir::OpAsmPrinter &p) {
+  printFieldLikeOp(p, *this);
+}
+
 void fir::FieldIndexOp::build(mlir::OpBuilder &builder,
                               mlir::OperationState &result,
                               llvm::StringRef fieldName, mlir::Type recTy,
                               mlir::ValueRange operands) {
-  result.addAttribute(fieldAttrName(), builder.getStringAttr(fieldName));
-  result.addAttribute(typeAttrName(), mlir::TypeAttr::get(recTy));
+  result.addAttribute(getFieldAttrName(), builder.getStringAttr(fieldName));
+  result.addAttribute(getTypeAttrName(), mlir::TypeAttr::get(recTy));
   result.addOperands(operands);
 }
 
@@ -1767,31 +1831,27 @@ mlir::Value fir::IterWhileOp::blockArgToSourceOp(unsigned blockArgNum) {
 
 mlir::ParseResult fir::LenParamIndexOp::parse(mlir::OpAsmParser &parser,
                                               mlir::OperationState &result) {
-  llvm::StringRef fieldName;
-  auto &builder = parser.getBuilder();
-  mlir::Type recty;
-  if (parser.parseOptionalKeyword(&fieldName) || parser.parseComma() ||
-      parser.parseType(recty))
-    return mlir::failure();
-  result.addAttribute(fir::LenParamIndexOp::fieldAttrName(),
-                      builder.getStringAttr(fieldName));
-  if (!recty.dyn_cast<fir::RecordType>())
-    return mlir::failure();
-  result.addAttribute(fir::LenParamIndexOp::typeAttrName(),
-                      mlir::TypeAttr::get(recty));
-  mlir::Type lenType = fir::LenType::get(builder.getContext());
-  if (parser.addTypeToList(lenType, result.types))
-    return mlir::failure();
-  return mlir::success();
+  return parseFieldLikeOp<fir::LenType>(parser, result);
 }
 
 void fir::LenParamIndexOp::print(mlir::OpAsmPrinter &p) {
-  p << ' '
-    << getOperation()
-           ->getAttrOfType<mlir::StringAttr>(
-               fir::LenParamIndexOp::fieldAttrName())
-           .getValue()
-    << ", " << getOperation()->getAttr(fir::LenParamIndexOp::typeAttrName());
+  printFieldLikeOp(p, *this);
+}
+
+void fir::LenParamIndexOp::build(mlir::OpBuilder &builder,
+                                 mlir::OperationState &result,
+                                 llvm::StringRef fieldName, mlir::Type recTy,
+                                 mlir::ValueRange operands) {
+  result.addAttribute(getFieldAttrName(), builder.getStringAttr(fieldName));
+  result.addAttribute(getTypeAttrName(), mlir::TypeAttr::get(recTy));
+  result.addOperands(operands);
+}
+
+llvm::SmallVector<mlir::Attribute> fir::LenParamIndexOp::getAttributes() {
+  llvm::SmallVector<mlir::Attribute> attrs;
+  attrs.push_back(getFieldIdAttr());
+  attrs.push_back(getOnTypeAttr());
+  return attrs;
 }
 
 //===----------------------------------------------------------------------===//

diff  --git a/flang/test/Fir/Todo/coordinate_of_1.fir b/flang/test/Fir/Todo/coordinate_of_1.fir
deleted file mode 100644
index 6dc90b8cca7ec..0000000000000
--- a/flang/test/Fir/Todo/coordinate_of_1.fir
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: %not_todo_cmd fir-opt --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" %s 2>&1 | FileCheck %s
-
-// `fir.coordinate_of` - derived type with `fir.len_param_index`. As
-// `fir.len_param_index` is not implemented yet, that's the error that's
-// currently being generated (this error is generated before trying to convert
-// `fir.coordinate_of`)
-func.func @coordinate_box_derived_with_fir_len(%arg0: !fir.box<!fir.type<derived_2{len1:i32}>>) {
-// CHECK: not yet implemented: fir.len_param_index codegen
-  %e = fir.len_param_index len1, !fir.type<derived_2{len1:i32}>
-  %q = fir.coordinate_of %arg0, %e : (!fir.box<!fir.type<derived_2{len1:i32}>>, !fir.len) -> !fir.ref<i32>
-  return
-}

diff  --git a/flang/test/Fir/Todo/coordinate_of_5.fir b/flang/test/Fir/Todo/coordinate_of_5.fir
deleted file mode 100644
index 47737096ffd8d..0000000000000
--- a/flang/test/Fir/Todo/coordinate_of_5.fir
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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.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/coordinate_of_6.fir b/flang/test/Fir/Todo/coordinate_of_6.fir
deleted file mode 100644
index 647fe2fae0bdf..0000000000000
--- a/flang/test/Fir/Todo/coordinate_of_6.fir
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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.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.fir b/flang/test/Fir/convert-to-llvm.fir
index 2ee507a00164d..ae46b3653115d 100644
--- a/flang/test/Fir/convert-to-llvm.fir
+++ b/flang/test/Fir/convert-to-llvm.fir
@@ -2642,13 +2642,13 @@ func.func @coordinate_ref_derived_nested(%arg0: !fir.ref<!fir.type<derived_5{fie
 // 5.3 `fir.char`
 func.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>
+  %2 = fir.coordinate_of %arr, %1 : (!fir.ref<!fir.char<10, 2>>, i32) -> !fir.ref<!fir.char<10>>
   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:           %[[VAL_2:.*]] = llvm.getelementptr %[[VAL_0]]{{\[}}%[[VAL_1]]] : (!llvm.ptr<array<2 x i80>>, i32) -> !llvm.ptr<array<1 x i80>>
 // CHECK:           llvm.return
 // CHECK:         }
 

diff  --git a/flang/test/Fir/coordinate_of_1.fir b/flang/test/Fir/coordinate_of_1.fir
new file mode 100644
index 0000000000000..ebde8c5a0d465
--- /dev/null
+++ b/flang/test/Fir/coordinate_of_1.fir
@@ -0,0 +1,49 @@
+// RUN: fir-opt --split-input-file --verify-diagnostics %s
+
+func.func @_QPcoordinate_box_derived_with_fir_len(%arg0: !fir.box<!fir.type<derived_2{len1:i32}>>) -> i32 {
+  %lp = arith.constant 22 : i32
+  %e = fir.len_param_index len1, !fir.type<derived_1{len1:i32}>(%lp : i32)
+  // expected-error at +1 {{'fir.coordinate_of' op len_param_index type not compatible with reference type}}
+  %q = fir.coordinate_of %arg0, %e : (!fir.box<!fir.type<derived_2{len1:i32}>>, !fir.len) -> !fir.ref<i32>
+  %val = fir.load %q : !fir.ref<i32>
+  return %val : i32
+}
+
+// -----
+
+func.func @_QPcoordinate_box_derived_with_fir_len2(%arg0: !fir.box<!fir.array<?x!fir.type<derived_2{len1:i32}>>>) -> i32 {
+  %lp = arith.constant 22 : i32
+  %e = fir.len_param_index len1, !fir.type<derived_1{len1:i32}>(%lp : i32)
+  // expected-error at +1 {{'fir.coordinate_of' op too many operands for len_param_index case}}
+  %q = fir.coordinate_of %arg0, %lp, %e : (!fir.box<!fir.array<?x!fir.type<derived_2{len1:i32}>>>, i32, !fir.len) -> !fir.ref<i32>
+  %val = fir.load %q : !fir.ref<i32>
+  return %val : i32
+}
+
+// -----
+
+func.func @_QPcoordinate_box_derived_with_fir_len3(%arg0: !fir.box<!fir.type<derived_2{len1:i32}>>) -> i32 {
+  %lp = arith.constant 22 : i32
+  %e = fir.len_param_index len1, !fir.type<derived_1{len1:i32}>(%lp : i32)
+  // expected-error at +1 {{'fir.coordinate_of' op len_param_index must be last argument}}
+  %q = fir.coordinate_of %arg0, %e, %e : (!fir.box<!fir.type<derived_2{len1:i32}>>, !fir.len, !fir.len) -> !fir.ref<i32>
+  %val = fir.load %q : !fir.ref<i32>
+  return %val : i32
+}
+
+// -----
+
+func.func @_QPtest_coordinate_of(%arr : !fir.ref<!fir.array<2 x !fir.char<10, 2>>>, %arg1: index) {
+  %1 = arith.constant 10 : i32
+  // expected-error at +1 {{'fir.coordinate_of' op character type mismatch}}
+  %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
+}
+
+// -----
+
+func.func @_QPtest_coordinate_of(%arr : !fir.ref<!fir.array<2 x i32>>, %arg1: index) {
+  // expected-error at +1 {{'fir.coordinate_of' op invalid parameters (too many)}}
+  %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/coordinateof.fir b/flang/test/Fir/coordinateof.fir
new file mode 100644
index 0000000000000..6603996fef60e
--- /dev/null
+++ b/flang/test/Fir/coordinateof.fir
@@ -0,0 +1,80 @@
+// RUN: fir-opt %s | tco | FileCheck %s
+
+// tests on coordinate_of op
+
+// CHECK-LABEL: @foo1
+func.func @foo1(%i : i32, %j : i32, %k : i32) -> !fir.ref<f32> {
+  %1 = fir.alloca !fir.array<10 x 20 x 30 x f32>
+  // CHECK: %[[alloca:.*]] = alloca [30 x [20 x [10 x float]]]
+  %2 = fir.convert %1 : (!fir.ref<!fir.array<10 x 20 x 30 x f32>>) -> !fir.ref<!fir.array<10 x 20 x ? x f32>>
+  // CHECK: getelementptr [20 x [10 x float]], ptr %[[alloca]]
+  %3 = fir.coordinate_of %2, %i, %j, %k : (!fir.ref<!fir.array<10 x 20 x ? x f32>>, i32, i32, i32) -> !fir.ref<f32>
+  return %3 : !fir.ref<f32>
+}
+
+// CHECK-LABEL: @foo2
+func.func @foo2(%i : i32, %j : i32, %k : i32) -> !fir.ref<f32> {
+  %1 = fir.alloca !fir.array<10 x 20 x 30 x f32>
+  // CHECK: %[[alloca:.*]] = alloca [30 x [20 x [10 x float]]]
+  %2 = fir.convert %1 : (!fir.ref<!fir.array<10 x 20 x 30 x f32>>) -> !fir.ref<!fir.array<?xf32>>
+  // CHECK: getelementptr float, ptr %[[alloca]]
+  %3 = fir.coordinate_of %2, %i : (!fir.ref<!fir.array<?xf32>>, i32) -> !fir.ref<f32>
+  return %3 : !fir.ref<f32>
+}
+
+// CHECK-LABEL: @foo3
+func.func @foo3(%box : !fir.box<!fir.array<?xi32>>, %i : i32) -> i32 {
+  // CHECK: %[[cvt:.*]] = sext i32 %
+  %ii = fir.convert %i : (i32) -> index
+  // CHECK: %[[gep0:.*]] = getelementptr { ptr
+  // CHECK: %[[boxptr:.*]] = load ptr, ptr %[[gep0]]
+  // CHECK: %[[gep1:.*]] = getelementptr { ptr, i64, {{.*}} i32 7
+  // CHECK: %[[stride:.*]] = load i64, ptr %[[gep1]]
+  // CHECK: %[[dimoffset:.*]] = mul i64 %[[cvt]], %[[stride]]
+  // CHECK: %[[offset:.*]] = add i64 %[[dimoffset]], 0
+  // CHECK: %[[gep2:.*]] = getelementptr i8, ptr %[[boxptr]], i64 %[[offset]]
+  %1 = fir.coordinate_of %box, %ii : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
+  // CHECK: load i32, ptr %[[gep2]]
+  %rv = fir.load %1 : !fir.ref<i32>
+  return %rv : i32
+}
+
+// CHECK-LABEL: @foo4
+func.func @foo4(%a : !fir.ptr<!fir.array<5x15x25xi32>>, %i : i32, %j : i64, %k : index) -> i32 {
+  // CHECK: getelementptr [25 x [15 x [5 x
+  %1 = fir.coordinate_of %a, %k : (!fir.ptr<!fir.array<5x15x25xi32>>, index) -> !fir.ref<!fir.array<5x15xi32>>
+  // CHECK: getelementptr [15 x [5 x
+  %2 = fir.coordinate_of %1, %j : (!fir.ref<!fir.array<5x15xi32>>, i64) -> !fir.ref<!fir.array<5xi32>>
+  // CHECK: %[[ref:.*]] = getelementptr [5 x
+  %3 = fir.coordinate_of %2, %i : (!fir.ref<!fir.array<5xi32>>, i32) -> !fir.ref<i32>
+  // CHECK: load i32, ptr %[[ref]]
+  %4 = fir.load %3 : !fir.ref<i32>
+  return %4 : i32
+}
+
+// CHECK-LABEL: @foo5
+func.func @foo5(%box : !fir.box<!fir.ptr<!fir.array<?xi32>>>, %i : index) -> i32 {
+  // similar to foo3 test. Just check that the ptr type is not disturbing codegen.
+  %1 = fir.coordinate_of %box, %i : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
+  // CHECK: load i32, ptr %{{.*}}
+  %rv = fir.load %1 : !fir.ref<i32>
+  return %rv : i32
+}
+
+// CHECK-LABEL: @foo6
+// CHECK-SAME: (ptr %[[box:.*]], i64 %{{.*}}, ptr %{{.*}}) 
+func.func @foo6(%box : !fir.box<!fir.ptr<!fir.array<?x!fir.char<1>>>>, %i : i64 , %res : !fir.ref<!fir.char<1>>) {
+  // CHECK: %[[addr_gep:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[box]], i32 0, i32 0
+  // CHECK: %[[addr:.*]] = load ptr, ptr %[[addr_gep]]
+  // CHECK: %[[stride_gep:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[box]], i32 0, i32 7, i64 0, i32 2
+  // CHECK: %[[stride:.*]] = load i64, ptr %[[stride_gep]]
+  // CHECK: %[[mul:.*]] = mul i64 %{{.*}}, %[[stride]]
+  // CHECK: %[[offset:.*]] = add i64 %[[mul]], 0
+  // CHECK: %[[gep:.*]] = getelementptr i8, ptr %[[addr]], i64 %[[offset]]
+  %coor = fir.coordinate_of %box, %i : (!fir.box<!fir.ptr<!fir.array<?x!fir.char<1>>>>, i64) -> !fir.ref<!fir.char<1>>
+
+  // CHECK: load [1 x i8], ptr %[[gep]]
+  %load = fir.load %coor : !fir.ref<!fir.char<1>>
+  fir.store %load to %res : !fir.ref<!fir.char<1>>
+  return
+}

diff  --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir
index 43cef63362d5b..8d2a68fad87a6 100644
--- a/flang/test/Fir/invalid.fir
+++ b/flang/test/Fir/invalid.fir
@@ -287,17 +287,17 @@ func.func @test_coordinate_of(%arr : !fir.ref<!fir.array<*:f32>>) {
 
 func.func @test_coordinate_of(%arr : !fir.ref<!fir.char<10>>) {
   %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>>, i32) -> !fir.ref<f32>
+  // expected-error at +1 {{'fir.coordinate_of' op cannot apply to this element type}}
+  %2 = fir.coordinate_of %arr, %1 : (!fir.ref<!fir.char<10>>, i32) -> !fir.ref<!fir.char<10>>
   return
 }
 
 // -----
 
-func.func @test_coordinate_of(%arr : !fir.ref<!fir.char<10, 1>>) {
+func.func @test_coordinate_of(%arr : !fir.ref<!fir.char<10, 2>>) {
   %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>
+  // expected-error at +1 {{'fir.coordinate_of' op cannot apply to character singleton}}
+  %2 = fir.coordinate_of %arr, %1, %1 : (!fir.ref<!fir.char<10, 2>>, i32, i32) -> !fir.ref<!fir.char<10>>
   return
 }
 


        


More information about the flang-commits mailing list