diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h --- a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h +++ b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h @@ -22,6 +22,7 @@ bool isFortranVariableType(mlir::Type); bool isFortranScalarCharacterType(mlir::Type); bool isFortranScalarCharacterExprType(mlir::Type); +bool isFortranArrayCharacterExprType(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 --- a/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td @@ -109,6 +109,16 @@ def AnyScalarCharacterExpr : Type; +def isFortranArrayCharacterExprTypePred + : CPred<"::hlfir::isFortranArrayCharacterExprType($_self)">; +def AnyArrayCharacterExpr : Type; + +def AnyScalarOrArrayCharacterExpr : + Type, + "any character scalar or array expression type">; + def IsFortranNumericalArrayObjectPred : CPred<"::hlfir::isFortranNumericalArrayObject($_self)">; def AnyFortranNumericalArrayObject : Type]; } +def hlfir_GetLengthOp : hlfir_Op<"get_length", [Pure]> { + let summary = "get the length of a character entity"; + let description = [{ + Get the length of character entity represented as hlfir.expr. + }]; + + let arguments = (ins AnyScalarOrArrayCharacterExpr:$expr); + let results = (outs Index); + + let assemblyFormat = [{ + $expr attr-dict `:` functional-type(operands, results) + }]; + + // If character length is know via the type, then the operation + // may be immediately canonicalized into arith::ConstantOp. + let hasCanonicalizeMethod = 1; +} + def hlfir_SumOp : hlfir_Op<"sum", [AttrSizedOperandSegments, DeclareOpInterfaceMethods]> { let summary = "SUM transformational intrinsic"; diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp --- a/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp +++ b/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp @@ -104,6 +104,14 @@ return false; } +bool hlfir::isFortranArrayCharacterExprType(mlir::Type type) { + if (auto exprType = mlir::dyn_cast(type)) + return exprType.isArray() && + mlir::isa(exprType.getElementType()); + + return false; +} + bool hlfir::isFortranScalarNumericalType(mlir::Type type) { return fir::isa_integer(type) || fir::isa_real(type) || fir::isa_complex(type); diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp --- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp +++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp @@ -1501,6 +1501,26 @@ build(builder, result, resultType, predicate, strings); } +//===----------------------------------------------------------------------===// +// GetLength +//===----------------------------------------------------------------------===// + +mlir::LogicalResult +hlfir::GetLengthOp::canonicalize(GetLengthOp getLength, + mlir::PatternRewriter &rewriter) { + mlir::Location loc = getLength.getLoc(); + auto exprTy = mlir::cast(getLength.getExpr().getType()); + auto charTy = mlir::cast(exprTy.getElementType()); + if (!charTy.hasConstantLen()) + return mlir::failure(); + + mlir::Type indexTy = rewriter.getIndexType(); + auto cstLen = rewriter.create( + loc, indexTy, mlir::IntegerAttr::get(indexTy, charTy.getLen())); + rewriter.replaceOp(getLength, cstLen); + return mlir::success(); +} + #include "flang/Optimizer/HLFIR/HLFIROpInterfaces.cpp.inc" #define GET_OP_CLASSES #include "flang/Optimizer/HLFIR/HLFIREnums.cpp.inc" diff --git a/flang/test/HLFIR/get_length.fir b/flang/test/HLFIR/get_length.fir new file mode 100644 --- /dev/null +++ b/flang/test/HLFIR/get_length.fir @@ -0,0 +1,48 @@ +// Test hlfir.get_length operation parse, verify (no errors), and unparse. + +// RUN: fir-opt %s | fir-opt | FileCheck %s --check-prefix CHECK --check-prefix CHECK-ALL + +// Test canonicalization. +// RUN: fir-opt %s --canonicalize | FileCheck %s --check-prefix CHECK-CANON --check-prefix CHECK-ALL + +func.func @fixed_len_scalar(%arg0: !hlfir.expr>) -> index { + %1 = hlfir.get_length %arg0 : (!hlfir.expr>) -> index + return %1 : index +} +// CHECK-ALL-LABEL: func.func @fixed_len_scalar( +// CHECK-ALL-SAME: %[[VAL_0:.*]]: !hlfir.expr>) -> index { +// CHECK: %[[VAL_1:.*]] = hlfir.get_length %[[VAL_0]] : (!hlfir.expr>) -> index +// CHECK-CANON: %[[VAL_1:.*]] = arith.constant 10 : index +// CHECK-ALL: return %[[VAL_1]] : index +// CHECK-ALL: } + +func.func @assumed_len_scalar(%arg0: !hlfir.expr>) -> index { + %1 = hlfir.get_length %arg0 : (!hlfir.expr>) -> index + return %1 : index +} +// CHECK-ALL-LABEL: func.func @assumed_len_scalar( +// CHECK-ALL-SAME: %[[VAL_0:.*]]: !hlfir.expr>) -> index { +// CHECK-ALL: %[[VAL_1:.*]] = hlfir.get_length %[[VAL_0]] : (!hlfir.expr>) -> index +// CHECK-ALL: return %[[VAL_1]] : index +// CHECK-ALL: } + +func.func @fixed_len_array(%arg0: !hlfir.expr>) -> index { + %1 = hlfir.get_length %arg0 : (!hlfir.expr>) -> index + return %1 : index +} +// CHECK-ALL-LABEL: func.func @fixed_len_array( +// CHECK-ALL-SAME: %[[VAL_0:.*]]: !hlfir.expr>) -> index { +// CHECK: %[[VAL_1:.*]] = hlfir.get_length %[[VAL_0]] : (!hlfir.expr>) -> index +// CHECK-CANON: %[[VAL_1:.*]] = arith.constant 10 : index +// CHECK-ALL: return %[[VAL_1]] : index +// CHECK-ALL: } + +func.func @assumed_len_array(%arg0: !hlfir.expr>) -> index { + %1 = hlfir.get_length %arg0 : (!hlfir.expr>) -> index + return %1 : index +} +// CHECK-ALL-LABEL: func.func @assumed_len_array( +// CHECK-ALL-SAME: %[[VAL_0:.*]]: !hlfir.expr>) -> index { +// CHECK-ALL: %[[VAL_1:.*]] = hlfir.get_length %[[VAL_0]] : (!hlfir.expr>) -> index +// CHECK-ALL: return %[[VAL_1]] : index +// CHECK-ALL: } diff --git a/flang/test/HLFIR/invalid.fir b/flang/test/HLFIR/invalid.fir --- a/flang/test/HLFIR/invalid.fir +++ b/flang/test/HLFIR/invalid.fir @@ -947,3 +947,24 @@ } return } + +// ----- +func.func @bad_get_length_1(%arg0: !hlfir.expr) { + // expected-error@+1 {{'hlfir.get_length' op operand #0 must be any character scalar or array expression type, but got '!hlfir.expr'}} + %1 = hlfir.get_length %arg0 : (!hlfir.expr) -> index + return +} + +// ----- +func.func @bad_get_length_2(%arg0: !hlfir.expr) { + // expected-error@+1 {{'hlfir.get_length' op operand #0 must be any character scalar or array expression type, but got '!hlfir.expr'}} + %1 = hlfir.get_length %arg0 : (!hlfir.expr) -> index + return +} + +// ----- +func.func @bad_get_length_3(%arg0: !hlfir.expr>) { + // expected-error@+1 {{'hlfir.get_length' op operand #0 must be any character scalar or array expression type, but got '!hlfir.expr>'}} + %1 = hlfir.get_length %arg0 : (!hlfir.expr>) -> index + return +}