[flang-commits] [flang] 8dea00f - [flang] Add hlfir.concat operation definition

Jean Perier via flang-commits flang-commits at lists.llvm.org
Fri Nov 25 00:35:26 PST 2022


Author: Jean Perier
Date: 2022-11-25T09:34:15+01:00
New Revision: 8dea00f4e79b7e19ab5d1adc728a0379c7f39d9e

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

LOG: [flang] Add hlfir.concat operation definition

This operation represents scalar character concatenation. This is
added as part of flang lowering update described in
https://github.com/llvm/llvm-project/blob/main/flang/docs/HighLevelFIR.md

A notable difference with Fortran concatenation is that hlfir.concat can
take two or more operands. This will be used to optimize concatenation
chains.

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

Added: 
    flang/test/HLFIR/concat.fir

Modified: 
    flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
    flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td
    flang/include/flang/Optimizer/HLFIR/HLFIROps.td
    flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp
    flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
    flang/test/HLFIR/invalid.fir

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
index 5d229dd445799..f9962df321303 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
@@ -20,6 +20,8 @@
 namespace hlfir {
 /// Is this a type that can be used for an HLFIR variable ?
 bool isFortranVariableType(mlir::Type);
+bool isFortranScalarCharacterType(mlir::Type);
+bool isFortranScalarCharacterExprType(mlir::Type);
 } // namespace hlfir
 
 #include "flang/Optimizer/HLFIR/HLFIRDialect.h.inc"

diff  --git a/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td
index 244cf79cd0ce2..7c06349481c60 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td
@@ -63,7 +63,8 @@ def hlfir_ExprType : TypeDef<hlfir_Dialect, "Expr"> {
   let extraClassDeclaration = [{
     using Shape = llvm::SmallVector<int64_t>;
     mlir::Type getEleTy() const {return getElementType();}
-    bool isArray() const { return !getShape().empty(); }
+    bool isScalar() const { return getShape().empty(); }
+    bool isArray() const { return !isScalar(); }
     bool isPolymorphic() const { return getPolymorphic(); }
   }];
 
@@ -85,5 +86,14 @@ def AnyFortranValue : TypeConstraint<Or<[AnyLogicalLike.predicate,
 def AnyFortranEntity : TypeConstraint<Or<[AnyFortranVariable.predicate,
     AnyFortranValue.predicate]>, "any Fortran value or variable type">;
 
+def IsFortranScalarCharacterPred
+        : CPred<"::hlfir::isFortranScalarCharacterType($_self)">;
+def AnyScalarCharacterEntity : Type<IsFortranScalarCharacterPred,
+    "any character scalar type">;
+
+def IsFortranScalarCharacterExprPred
+        : CPred<"::hlfir::isFortranScalarCharacterExprType($_self)">;
+def AnyScalarCharacterExpr : Type<IsFortranScalarCharacterExprPred,
+    "any character scalar expression type">;
 
 #endif // FORTRAN_DIALECT_HLFIR_OP_BASE

diff  --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index 46775b198fdc6..3c65f798542f9 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -208,4 +208,23 @@ def hlfir_DesignateOp : hlfir_Op<"designate", [AttrSizedOperandSegments,
   let hasVerifier = 1;
 }
 
+def hlfir_ConcatOp : hlfir_Op<"concat", []> {
+  let summary = "concatenate characters";
+  let description = [{
+    Concatenate two or more character strings of a same character kind.
+  }];
+
+  let arguments = (ins Variadic<AnyScalarCharacterEntity>:$strings,
+                   AnyIntegerType:$length);
+
+  let results = (outs AnyScalarCharacterExpr);
+
+  let assemblyFormat = [{
+    $strings `len` $length
+     attr-dict `:` functional-type(operands, results)
+  }];
+
+  let hasVerifier = 1;
+}
+
 #endif // FORTRAN_DIALECT_HLFIR_OPS

diff  --git a/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp
index 79f2d527d00fc..fbb7d77e25ca4 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp
@@ -85,3 +85,17 @@ bool hlfir::isFortranVariableType(mlir::Type type) {
       .Case<fir::BaseBoxType, fir::BoxCharType>([](auto) { return true; })
       .Default([](mlir::Type) { return false; });
 }
+
+bool hlfir::isFortranScalarCharacterType(mlir::Type type) {
+  return isFortranScalarCharacterExprType(type) ||
+         type.isa<fir::BoxCharType>() ||
+         fir::unwrapPassByRefType(fir::unwrapRefType(type))
+             .isa<fir::CharacterType>();
+}
+
+bool hlfir::isFortranScalarCharacterExprType(mlir::Type type) {
+  if (auto exprType = type.dyn_cast<hlfir::ExprType>())
+    return exprType.isScalar() &&
+           exprType.getElementType().isa<fir::CharacterType>();
+  return false;
+}

diff  --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index 986553a35451e..cb987f1516be5 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -337,5 +337,22 @@ mlir::LogicalResult hlfir::DesignateOp::verify() {
   return mlir::success();
 }
 
+//===----------------------------------------------------------------------===//
+// ConcatOp
+//===----------------------------------------------------------------------===//
+
+mlir::LogicalResult hlfir::ConcatOp::verify() {
+  if (getStrings().size() < 2)
+    return emitOpError("must be provided at least two string operands");
+  auto exprTy = getResult().getType().cast<hlfir::ExprType>();
+  unsigned kind = exprTy.getElementType().cast<fir::CharacterType>().getFKind();
+  for (auto string : getStrings())
+    if (kind != getFortranElementType(string.getType())
+                    .cast<fir::CharacterType>()
+                    .getFKind())
+      return emitOpError("strings must have the same KIND as the result type");
+  return mlir::success();
+}
+
 #define GET_OP_CLASSES
 #include "flang/Optimizer/HLFIR/HLFIROps.cpp.inc"

diff  --git a/flang/test/HLFIR/concat.fir b/flang/test/HLFIR/concat.fir
new file mode 100644
index 0000000000000..b4ecd2e43acfc
--- /dev/null
+++ b/flang/test/HLFIR/concat.fir
@@ -0,0 +1,62 @@
+// Test hlfir.concat operation parse, verify (no errors), and unparse.
+
+// RUN: fir-opt %s | fir-opt | FileCheck %s
+
+func.func @concat_var(%arg0: !fir.ref<!fir.char<1,10>>, %arg1: !fir.ref<!fir.char<1,20>>) {
+  %c30 = arith.constant 30 : index
+  %0 = hlfir.concat %arg0, %arg1 len %c30 : (!fir.ref<!fir.char<1,10>>, !fir.ref<!fir.char<1,20>>, index) -> (!hlfir.expr<!fir.char<1,30>>)
+  return
+}
+// CHECK-LABEL:   func.func @concat_var(
+// CHECK-SAME:    %[[VAL_0:.*]]: !fir.ref<!fir.char<1,10>>,
+// CHECK-SAME:    %[[VAL_1:.*]]: !fir.ref<!fir.char<1,20>>) {
+// CHECK:  %[[VAL_2:.*]] = arith.constant 30 : index
+// CHECK:  %[[VAL_3:.*]] = hlfir.concat %[[VAL_0]], %[[VAL_1]] len %[[VAL_2]] : (!fir.ref<!fir.char<1,10>>, !fir.ref<!fir.char<1,20>>, index) -> !hlfir.expr<!fir.char<1,30>>
+
+
+func.func @concat_boxchar(%arg0: !fir.boxchar<1>, %arg1: !fir.boxchar<1>) {
+  %c30 = arith.constant 30 : index
+  %0 = hlfir.concat %arg0, %arg1 len %c30 : (!fir.boxchar<1>, !fir.boxchar<1>, index) -> (!hlfir.expr<!fir.char<1,?>>)
+  return
+}
+// CHECK-LABEL:   func.func @concat_boxchar(
+// CHECK-SAME:    %[[VAL_0:.*]]: !fir.boxchar<1>,
+// CHECK-SAME:    %[[VAL_1:.*]]: !fir.boxchar<1>) {
+// CHECK:  %[[VAL_2:.*]] = arith.constant 30 : index
+// CHECK:  %[[VAL_3:.*]] = hlfir.concat %[[VAL_0]], %[[VAL_1]] len %[[VAL_2]] : (!fir.boxchar<1>, !fir.boxchar<1>, index) -> !hlfir.expr<!fir.char<1,?>>
+
+
+func.func @concat_boxchar_kind2(%arg0: !fir.boxchar<2>, %arg1: !fir.boxchar<2>) {
+  %c30 = arith.constant 30 : index
+  %0 = hlfir.concat %arg0, %arg1 len %c30 : (!fir.boxchar<2>, !fir.boxchar<2>, index) -> (!hlfir.expr<!fir.char<2,?>>)
+  return
+}
+// CHECK-LABEL:   func.func @concat_boxchar_kind2(
+// CHECK-SAME:    %[[VAL_0:.*]]: !fir.boxchar<2>,
+// CHECK-SAME:    %[[VAL_1:.*]]: !fir.boxchar<2>) {
+// CHECK:  %[[VAL_2:.*]] = arith.constant 30 : index
+// CHECK:  %[[VAL_3:.*]] = hlfir.concat %[[VAL_0]], %[[VAL_1]] len %[[VAL_2]] : (!fir.boxchar<2>, !fir.boxchar<2>, index) -> !hlfir.expr<!fir.char<2,?>>
+
+
+func.func @concat_expr(%arg0: !hlfir.expr<!fir.char<1,10>>, %arg1: !hlfir.expr<!fir.char<1,20>>) {
+  %c30 = arith.constant 30 : index
+  %0 = hlfir.concat %arg0, %arg1 len %c30 : (!hlfir.expr<!fir.char<1,10>>, !hlfir.expr<!fir.char<1,20>>, index) -> (!hlfir.expr<!fir.char<1,30>>)
+  return
+}
+// CHECK-LABEL:   func.func @concat_expr(
+// CHECK-SAME:    %[[VAL_0:.*]]: !hlfir.expr<!fir.char<1,10>>,
+// CHECK-SAME:    %[[VAL_1:.*]]: !hlfir.expr<!fir.char<1,20>>) {
+// CHECK:  %[[VAL_2:.*]] = arith.constant 30 : index
+// CHECK:  %[[VAL_3:.*]] = hlfir.concat %[[VAL_0]], %[[VAL_1]] len %[[VAL_2]] : (!hlfir.expr<!fir.char<1,10>>, !hlfir.expr<!fir.char<1,20>>, index) -> !hlfir.expr<!fir.char<1,30>>
+
+
+func.func @concat_several_args(%arg0: !fir.boxchar<1>, %arg1: !fir.boxchar<1>) {
+  %c30 = arith.constant 30 : index
+  %0 = hlfir.concat %arg0, %arg1, %arg1 len %c30 : (!fir.boxchar<1>, !fir.boxchar<1>, !fir.boxchar<1>, index) -> (!hlfir.expr<!fir.char<1,?>>)
+  return
+}
+// CHECK-LABEL:   func.func @concat_several_args(
+// CHECK-SAME:    %[[VAL_0:.*]]: !fir.boxchar<1>,
+// CHECK-SAME:    %[[VAL_1:.*]]: !fir.boxchar<1>) {
+// CHECK:  %[[VAL_2:.*]] = arith.constant 30 : index
+// CHECK:  %[[VAL_3:.*]] = hlfir.concat %[[VAL_0]], %[[VAL_1]], %[[VAL_1]] len %[[VAL_2]] : (!fir.boxchar<1>, !fir.boxchar<1>, !fir.boxchar<1>, index) -> !hlfir.expr<!fir.char<1,?>>

diff  --git a/flang/test/HLFIR/invalid.fir b/flang/test/HLFIR/invalid.fir
index a4b901fc0d95a..a7a3150a1534f 100644
--- a/flang/test/HLFIR/invalid.fir
+++ b/flang/test/HLFIR/invalid.fir
@@ -255,3 +255,43 @@ func.func @bad_designate_len_params_3(%arg0 : !fir.box<!fir.array<?xi32>>) {
   %0 = hlfir.designate %arg0(%c1) typeparams %c1 :  (!fir.box<!fir.array<?xi32>>, index, index) -> !fir.ref<i32>
   return
 }
+
+// -----
+func.func @bad_concat(%arg0: !fir.ref<!fir.char<1,10>>, %arg1: !fir.ref<!fir.char<1,20>>) {
+  %c30 = arith.constant 30 : index
+  // expected-error at +1 {{'hlfir.concat' op result #0 must be any character scalar expression type, but got '!fir.ref<!fir.char<1,30>>'}}
+  %0 = hlfir.concat %arg0, %arg1 len %c30 : (!fir.ref<!fir.char<1,10>>, !fir.ref<!fir.char<1,20>>, index) -> (!fir.ref<!fir.char<1,30>>)
+  return
+}
+
+// -----
+func.func @bad_concat_2(%arg0: !fir.ref<!fir.array<100x!fir.char<1,10>>>, %arg1: !fir.ref<!fir.array<100x!fir.char<1,20>>>) {
+  %c30 = arith.constant 30 : index
+  // expected-error at +1 {{'hlfir.concat' op operand #0 must be any character scalar type, but got '!fir.ref<!fir.array<100x!fir.char<1,10>>>'}}
+  %0 = hlfir.concat %arg0, %arg1 len %c30 : (!fir.ref<!fir.array<100x!fir.char<1,10>>>, !fir.ref<!fir.array<100x!fir.char<1,20>>>, index) -> (!hlfir.expr<100x!fir.char<1,30>>)
+  return
+}
+
+// -----
+func.func @bad_concat_3(%arg0: !fir.ref<!fir.char<1,10>>, %arg1: !fir.ref<i32>) {
+  %c30 = arith.constant 30 : index
+  // expected-error at +1 {{'hlfir.concat' op operand #1 must be any character scalar type, but got '!fir.ref<i32>'}}
+  %0 = hlfir.concat %arg0, %arg1 len %c30 : (!fir.ref<!fir.char<1,10>>, !fir.ref<i32>, index) -> (!hlfir.expr<!fir.char<1,30>>)
+  return
+}
+
+// -----
+func.func @bad_concat_4(%arg0: !fir.ref<!fir.char<1,10>>, %arg1: !fir.ref<!fir.char<2,20>>) {
+  %c30 = arith.constant 30 : index
+  // expected-error at +1 {{'hlfir.concat' op strings must have the same KIND as the result type}}
+  %0 = hlfir.concat %arg0, %arg1 len %c30 : (!fir.ref<!fir.char<1,10>>, !fir.ref<!fir.char<2,20>>, index) -> (!hlfir.expr<!fir.char<1,30>>)
+  return
+}
+
+// -----
+func.func @bad_concat_4(%arg0: !fir.ref<!fir.char<1,30>>) {
+  %c30 = arith.constant 30 : index
+  // expected-error at +1 {{'hlfir.concat' op must be provided at least two string operands}}
+  %0 = hlfir.concat %arg0 len %c30 : (!fir.ref<!fir.char<1,30>>, index) -> (!hlfir.expr<!fir.char<1,30>>)
+  return
+}


        


More information about the flang-commits mailing list