[flang-commits] [flang] d0018c9 - [flang] Finish substring lowering
Jean Perier via flang-commits
flang-commits at lists.llvm.org
Mon Dec 19 23:48:25 PST 2022
Author: Jean Perier
Date: 2022-12-20T08:47:14+01:00
New Revision: d0018c959a30150aa923fb458c5d21cd284120d4
URL: https://github.com/llvm/llvm-project/commit/d0018c959a30150aa923fb458c5d21cd284120d4
DIFF: https://github.com/llvm/llvm-project/commit/d0018c959a30150aa923fb458c5d21cd284120d4.diff
LOG: [flang] Finish substring lowering
Hlfir.designate was made to support substrings but so far substrings
were not yet lowered to it. Implement support for them.
Differential Revision: https://reviews.llvm.org/D140310
Added:
flang/test/Lower/HLFIR/substrings.f90
Modified:
flang/include/flang/Optimizer/Builder/Character.h
flang/include/flang/Optimizer/Builder/HLFIRTools.h
flang/lib/Lower/ConvertExprToHLFIR.cpp
flang/lib/Optimizer/Builder/Character.cpp
flang/lib/Optimizer/Builder/HLFIRTools.cpp
flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp
Removed:
################################################################################
diff --git a/flang/include/flang/Optimizer/Builder/Character.h b/flang/include/flang/Optimizer/Builder/Character.h
index fca21363da84c..820c64f9357bb 100644
--- a/flang/include/flang/Optimizer/Builder/Character.h
+++ b/flang/include/flang/Optimizer/Builder/Character.h
@@ -47,6 +47,13 @@ class CharacterExprHelper {
fir::CharBoxValue createSubstring(const fir::CharBoxValue &str,
llvm::ArrayRef<mlir::Value> bounds);
+ /// Compute substring base address given the raw address (not fir.boxchar) of
+ /// a scalar string, a substring / lower bound, and the substring type.
+ mlir::Value genSubstringBase(mlir::Value stringRawAddr,
+ mlir::Value lowerBound,
+ mlir::Type substringAddrType,
+ mlir::Value one = {});
+
/// Return blank character of given \p type !fir.char<kind>
mlir::Value createBlankConstant(fir::CharacterType type);
diff --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h
index 0cdac83d8e1cc..d83766c9f0c7f 100644
--- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h
+++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h
@@ -174,10 +174,11 @@ translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
fir::FortranVariableOpInterface fortranVariable);
/// Generate declaration for a fir::ExtendedValue in memory.
-EntityWithAttributes genDeclare(mlir::Location loc, fir::FirOpBuilder &builder,
- const fir::ExtendedValue &exv,
- llvm::StringRef name,
- fir::FortranVariableFlagsAttr flags);
+fir::FortranVariableOpInterface genDeclare(mlir::Location loc,
+ fir::FirOpBuilder &builder,
+ const fir::ExtendedValue &exv,
+ llvm::StringRef name,
+ fir::FortranVariableFlagsAttr flags);
/// Generate an hlfir.associate to build a variable from an expression value.
/// The type of the variable must be provided so that scalar logicals are
@@ -238,6 +239,11 @@ void genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder,
Entity entity,
llvm::SmallVectorImpl<mlir::Value> &result);
+/// Get the length of a character entity. Crashes if the entity is not
+/// a character entity.
+mlir::Value genCharLength(mlir::Location loc, fir::FirOpBuilder &builder,
+ Entity entity);
+
/// Return the fir base, shape, and type parameters for a variable. Note that
/// type parameters are only added if the entity is not a box and the type
/// parameters is not a constant in the base type. This matches the arguments
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 7a772a1213a18..87c1ecab11d6e 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -24,6 +24,7 @@
#include "flang/Optimizer/Builder/Runtime/Character.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "llvm/ADT/TypeSwitch.h"
namespace {
@@ -65,6 +66,13 @@ class HlfirDesignatorBuilder {
designatorVariant);
}
+ hlfir::EntityWithAttributes
+ gen(const Fortran::evaluate::NamedEntity &namedEntity) {
+ if (namedEntity.IsSymbol())
+ return gen(Fortran::evaluate::SymbolRef{namedEntity.GetLastSymbol()});
+ return gen(namedEntity.GetComponent());
+ }
+
private:
/// Struct that is filled while visiting a part-ref (in the "visit" member
/// function) before the top level "gen" generates an hlfir.declare for the
@@ -75,6 +83,7 @@ class HlfirDesignatorBuilder {
hlfir::DesignateOp::Subscripts subscripts;
mlir::Value resultShape;
llvm::SmallVector<mlir::Value> typeParams;
+ llvm::SmallVector<mlir::Value, 2> substring;
};
/// Generate an hlfir.declare for a part-ref given a filled PartInfo and the
@@ -100,11 +109,11 @@ class HlfirDesignatorBuilder {
resultType = fir::ReferenceType::get(resultValueType);
std::optional<bool> complexPart;
- llvm::SmallVector<mlir::Value> substring;
auto designate = getBuilder().create<hlfir::DesignateOp>(
getLoc(), resultType, partInfo.base.getBase(), "",
- /*componentShape=*/mlir::Value{}, partInfo.subscripts, substring,
- complexPart, partInfo.resultShape, partInfo.typeParams);
+ /*componentShape=*/mlir::Value{}, partInfo.subscripts,
+ partInfo.substring, complexPart, partInfo.resultShape,
+ partInfo.typeParams);
return mlir::cast<fir::FortranVariableOpInterface>(
designate.getOperation());
}
@@ -132,6 +141,9 @@ class HlfirDesignatorBuilder {
gen(const Fortran::evaluate::CoarrayRef &coarrayRef) {
TODO(getLoc(), "lowering CoarrayRef to HLFIR");
}
+ mlir::Type visit(const Fortran::evaluate::CoarrayRef &, PartInfo &) {
+ TODO(getLoc(), "lowering CoarrayRef to HLFIR");
+ }
hlfir::EntityWithAttributes
gen(const Fortran::evaluate::ComplexPart &complexPart) {
@@ -140,7 +152,95 @@ class HlfirDesignatorBuilder {
hlfir::EntityWithAttributes
gen(const Fortran::evaluate::Substring &substring) {
- TODO(getLoc(), "lowering substrings to HLFIR");
+ PartInfo partInfo;
+ mlir::Type baseStringType = std::visit(
+ [&](const auto &x) { return visit(x, partInfo); }, substring.parent());
+ assert(partInfo.typeParams.size() == 1 && "expect base string length");
+ // Compute the substring lower and upper bound.
+ partInfo.substring.push_back(genSubscript(substring.lower()));
+ if (Fortran::evaluate::MaybeExtentExpr upperBound = substring.upper())
+ partInfo.substring.push_back(genSubscript(*upperBound));
+ else
+ partInfo.substring.push_back(partInfo.typeParams[0]);
+ fir::FirOpBuilder &builder = getBuilder();
+ mlir::Location loc = getLoc();
+ mlir::Type idxTy = builder.getIndexType();
+ partInfo.substring[0] =
+ builder.createConvert(loc, idxTy, partInfo.substring[0]);
+ partInfo.substring[1] =
+ builder.createConvert(loc, idxTy, partInfo.substring[1]);
+ // Try using constant length if available. mlir::arith folding would
+ // most likely be able to fold "max(ub-lb+1,0)" too, but getting
+ // the constant length in the FIR types would be harder.
+ std::optional<int64_t> cstLen =
+ Fortran::evaluate::ToInt64(Fortran::evaluate::Fold(
+ getConverter().getFoldingContext(), substring.LEN()));
+ if (cstLen) {
+ partInfo.typeParams[0] =
+ builder.createIntegerConstant(loc, idxTy, *cstLen);
+ } else {
+ // Compute "len = max(ub-lb+1,0)" (Fortran 2018 9.4.1).
+ mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
+ auto boundsDiff = builder.create<mlir::arith::SubIOp>(
+ loc, partInfo.substring[1], partInfo.substring[0]);
+ auto rawLen = builder.create<mlir::arith::AddIOp>(loc, boundsDiff, one);
+ partInfo.typeParams[0] =
+ fir::factory::genMaxWithZero(builder, loc, rawLen);
+ }
+ mlir::Type resultType = changeLengthInCharacterType(
+ loc, baseStringType,
+ cstLen ? *cstLen : fir::CharacterType::unknownLen());
+ return genDeclare(resultType, partInfo);
+ }
+
+ static mlir::Type changeLengthInCharacterType(mlir::Location loc,
+ mlir::Type type,
+ int64_t newLen) {
+ return llvm::TypeSwitch<mlir::Type, mlir::Type>(type)
+ .Case<fir::CharacterType>([&](fir::CharacterType charTy) -> mlir::Type {
+ return fir::CharacterType::get(charTy.getContext(), charTy.getFKind(),
+ newLen);
+ })
+ .Case<fir::SequenceType>([&](fir::SequenceType seqTy) -> mlir::Type {
+ return fir::SequenceType::get(
+ seqTy.getShape(),
+ changeLengthInCharacterType(loc, seqTy.getEleTy(), newLen));
+ })
+ .Case<fir::PointerType, fir::HeapType, fir::ReferenceType,
+ fir::BoxType>([&](auto t) -> mlir::Type {
+ using FIRT = decltype(t);
+ return FIRT::get(
+ changeLengthInCharacterType(loc, t.getEleTy(), newLen));
+ })
+ .Default([loc](mlir::Type t) -> mlir::Type {
+ fir::emitFatalError(loc, "expected character type");
+ });
+ }
+
+ mlir::Type visit(const Fortran::evaluate::DataRef &dataRef,
+ PartInfo &partInfo) {
+ return std::visit([&](const auto &x) { return visit(x, partInfo); },
+ dataRef.u);
+ }
+
+ mlir::Type
+ visit(const Fortran::evaluate::StaticDataObject::Pointer &staticObject,
+ PartInfo &partInfo) {
+ fir::FirOpBuilder &builder = getBuilder();
+ mlir::Location loc = getLoc();
+ std::optional<std::string> string = staticObject->AsString();
+ // TODO: see if StaticDataObject can be replaced by something based on
+ // Constant<T> to avoid dealing with endianness here for KIND>1.
+ // This will also avoid making string copies here.
+ if (!string)
+ TODO(loc, "StaticDataObject::Pointer substring with kind > 1");
+ fir::ExtendedValue exv =
+ fir::factory::createStringLiteral(builder, getLoc(), *string);
+ auto flags = fir::FortranVariableFlagsAttr::get(
+ builder.getContext(), fir::FortranVariableFlagsEnum::parameter);
+ partInfo.base = hlfir::genDeclare(loc, builder, exv, ".stringlit", flags);
+ partInfo.typeParams.push_back(fir::getLen(exv));
+ return partInfo.base.getElementOrSequenceType();
}
mlir::Type visit(const Fortran::evaluate::SymbolRef &symbolRef,
@@ -845,7 +945,33 @@ class HlfirBuilder {
hlfir::EntityWithAttributes
gen(const Fortran::evaluate::DescriptorInquiry &desc) {
- TODO(getLoc(), "lowering descriptor inquiry to HLFIR");
+ mlir::Location loc = getLoc();
+ auto &builder = getBuilder();
+ hlfir::EntityWithAttributes entity =
+ HlfirDesignatorBuilder(getLoc(), getConverter(), getSymMap(),
+ getStmtCtx())
+ .gen(desc.base());
+ using ResTy = Fortran::evaluate::DescriptorInquiry::Result;
+ mlir::Type resultType =
+ getConverter().genType(ResTy::category, ResTy::kind);
+ auto castResult = [&](mlir::Value v) {
+ return hlfir::EntityWithAttributes{
+ builder.createConvert(loc, resultType, v)};
+ };
+ switch (desc.field()) {
+ case Fortran::evaluate::DescriptorInquiry::Field::Len:
+ return castResult(hlfir::genCharLength(loc, builder, entity));
+ case Fortran::evaluate::DescriptorInquiry::Field::LowerBound:
+ TODO(loc, "lower bound inquiry in HLFIR");
+ case Fortran::evaluate::DescriptorInquiry::Field::Extent:
+ TODO(loc, "extent inquiry in HLFIR");
+ case Fortran::evaluate::DescriptorInquiry::Field::Rank:
+ TODO(loc, "rank inquiry on assumed rank");
+ case Fortran::evaluate::DescriptorInquiry::Field::Stride:
+ // So far the front end does not generate this inquiry.
+ TODO(loc, "stride inquiry");
+ }
+ llvm_unreachable("unknown descriptor inquiry");
}
hlfir::EntityWithAttributes
diff --git a/flang/lib/Optimizer/Builder/Character.cpp b/flang/lib/Optimizer/Builder/Character.cpp
index f3bb71efcbbb1..de4a5579620da 100644
--- a/flang/lib/Optimizer/Builder/Character.cpp
+++ b/flang/lib/Optimizer/Builder/Character.cpp
@@ -473,6 +473,17 @@ fir::CharBoxValue fir::factory::CharacterExprHelper::createConcatenate(
return temp;
}
+mlir::Value fir::factory::CharacterExprHelper::genSubstringBase(
+ mlir::Value stringRawAddr, mlir::Value lowerBound,
+ mlir::Type substringAddrType, mlir::Value one) {
+ if (!one)
+ one = builder.createIntegerConstant(loc, lowerBound.getType(), 1);
+ auto offset =
+ builder.create<mlir::arith::SubIOp>(loc, lowerBound, one).getResult();
+ auto addr = createElementAddr(stringRawAddr, offset);
+ return builder.createConvert(loc, substringAddrType, addr);
+}
+
fir::CharBoxValue fir::factory::CharacterExprHelper::createSubstring(
const fir::CharBoxValue &box, llvm::ArrayRef<mlir::Value> bounds) {
// Constant need to be materialize in memory to use fir.coordinate_of.
@@ -488,14 +499,12 @@ fir::CharBoxValue fir::factory::CharacterExprHelper::createSubstring(
builder.createConvert(loc, builder.getCharacterLengthType(), bound));
auto lowerBound = castBounds[0];
// FIR CoordinateOp is zero based but Fortran substring are one based.
- auto one = builder.createIntegerConstant(loc, lowerBound.getType(), 1);
- auto offset =
- builder.create<mlir::arith::SubIOp>(loc, lowerBound, one).getResult();
- auto addr = createElementAddr(box.getBuffer(), offset);
auto kind = getCharacterKind(box.getBuffer().getType());
auto charTy = fir::CharacterType::getUnknownLen(builder.getContext(), kind);
auto resultType = builder.getRefType(charTy);
- auto substringRef = builder.createConvert(loc, resultType, addr);
+ auto one = builder.createIntegerConstant(loc, lowerBound.getType(), 1);
+ auto substringRef =
+ genSubstringBase(box.getBuffer(), lowerBound, resultType, one);
// Compute the length.
mlir::Value substringLen;
diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
index b090da69135c1..ca645cf97cbb2 100644
--- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp
+++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
@@ -139,7 +139,7 @@ hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
return firBase;
}
-hlfir::EntityWithAttributes
+fir::FortranVariableOpInterface
hlfir::genDeclare(mlir::Location loc, fir::FirOpBuilder &builder,
const fir::ExtendedValue &exv, llvm::StringRef name,
fir::FortranVariableFlagsAttr flags) {
@@ -457,6 +457,14 @@ void hlfir::genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder,
TODO(loc, "inquire PDTs length parameters in HLFIR");
}
+mlir::Value hlfir::genCharLength(mlir::Location loc, fir::FirOpBuilder &builder,
+ hlfir::Entity entity) {
+ llvm::SmallVector<mlir::Value, 1> lenParams;
+ genLengthParameters(loc, builder, entity, lenParams);
+ assert(lenParams.size() == 1 && "characters must have one length parameters");
+ return lenParams[0];
+}
+
std::pair<mlir::Value, mlir::Value> hlfir::genVariableFirBaseShapeAndParams(
mlir::Location loc, fir::FirOpBuilder &builder, Entity entity,
llvm::SmallVectorImpl<mlir::Value> &typeParams) {
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
index 90951f8ed32c3..97b08ae595faa 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
@@ -220,7 +220,8 @@ struct ConcatOpConversion : public mlir::OpConversionPattern<hlfir::ConcatOp> {
mlir::Value cast = builder.createConvert(loc, addrType, fir::getBase(res));
res = fir::substBase(res, cast);
auto hlfirTempRes = hlfir::genDeclare(loc, builder, res, "tmp",
- fir::FortranVariableFlagsAttr{});
+ fir::FortranVariableFlagsAttr{})
+ .getBase();
mlir::Value bufferizedExpr =
packageBufferizedExpr(loc, builder, hlfirTempRes, false);
rewriter.replaceOp(concat, bufferizedExpr);
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index 9f64eb41e6528..a5c31b3e09395 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -8,6 +8,7 @@
// This file defines a pass to lower HLFIR to FIR
//===----------------------------------------------------------------------===//
+#include "flang/Optimizer/Builder/Character.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Builder/HLFIRTools.h"
#include "flang/Optimizer/Builder/MutableBox.h"
@@ -183,11 +184,8 @@ class DesignateOpConversion
auto module = designate->getParentOfType<mlir::ModuleOp>();
fir::FirOpBuilder builder(rewriter, fir::getKindMapping(module));
- if (designate.getComponent() || designate.getComplexPart() ||
- !designate.getSubstring().empty()) {
- // build path.
- TODO(loc, "hlfir::designate with complex part or substring or component");
- }
+ if (designate.getComponent() || designate.getComplexPart())
+ TODO(loc, "hlfir::designate with complex part or component");
hlfir::Entity baseEntity(designate.getMemref());
if (baseEntity.isMutableBox())
@@ -216,8 +214,20 @@ class DesignateOpConversion
triples.push_back(undef);
}
}
+ llvm::SmallVector<mlir::Value, 2> substring;
+ if (!designate.getSubstring().empty()) {
+ substring.push_back(designate.getSubstring()[0]);
+ mlir::Type idxTy = builder.getIndexType();
+ // fir.slice op substring expects the zero based lower bound.
+ mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
+ substring[0] = builder.createConvert(loc, idxTy, substring[0]);
+ substring[0] =
+ builder.create<mlir::arith::SubIOp>(loc, substring[0], one);
+ substring.push_back(designate.getTypeparams()[0]);
+ }
+
mlir::Value slice = builder.create<fir::SliceOp>(
- loc, triples, /*path=*/mlir::ValueRange{});
+ loc, triples, /*fields=*/mlir::ValueRange{}, substring);
llvm::SmallVector<mlir::Type> resultType{designateResultType};
mlir::Value resultBox;
if (base.getType().isa<fir::BoxType>())
@@ -230,29 +240,37 @@ class DesignateOpConversion
return mlir::success();
}
- // Indexing a single element (use fir.array_coor of fir.coordinate_of).
+ // Otherwise, the result is the address of a scalar. The base may be an
+ // array, or a scalar.
+ mlir::Type resultAddressType = designateResultType;
+ if (auto boxCharType = designateResultType.dyn_cast<fir::BoxCharType>())
+ resultAddressType = fir::ReferenceType::get(boxCharType.getEleTy());
- if (designate.getIndices().empty()) {
- // Scalar substring or complex part.
- // generate fir.coordinate_of.
- TODO(loc, "hlfir::designate to fir.coordinate_of");
+ // Array element indexing.
+ if (!designate.getIndices().empty()) {
+ auto eleTy = hlfir::getFortranElementType(base.getType());
+ auto arrayCoorType = fir::ReferenceType::get(eleTy);
+ base = builder.create<fir::ArrayCoorOp>(loc, arrayCoorType, base, shape,
+ /*slice=*/mlir::Value{},
+ designate.getIndices(),
+ firBaseTypeParameters);
}
- // Generate fir.array_coor
- mlir::Type resultType = designateResultType;
- if (auto boxCharType = designateResultType.dyn_cast<fir::BoxCharType>())
- resultType = fir::ReferenceType::get(boxCharType.getEleTy());
- auto arrayCoor = builder.create<fir::ArrayCoorOp>(
- loc, resultType, base, shape,
- /*slice=*/mlir::Value{}, designate.getIndices(), firBaseTypeParameters);
+ // Scalar substring (potentially on the previously built array element).
+ if (!designate.getSubstring().empty())
+ base = fir::factory::CharacterExprHelper{builder, loc}.genSubstringBase(
+ base, designate.getSubstring()[0], resultAddressType);
+
+ // Cast/embox the computed scalar address if needed.
if (designateResultType.isa<fir::BoxCharType>()) {
assert(designate.getTypeparams().size() == 1 &&
"must have character length");
auto emboxChar = builder.create<fir::EmboxCharOp>(
- loc, designateResultType, arrayCoor, designate.getTypeparams()[0]);
+ loc, designateResultType, base, designate.getTypeparams()[0]);
rewriter.replaceOp(designate, emboxChar.getResult());
} else {
- rewriter.replaceOp(designate, arrayCoor.getResult());
+ base = builder.createConvert(loc, designateResultType, base);
+ rewriter.replaceOp(designate, base);
}
return mlir::success();
}
diff --git a/flang/test/Lower/HLFIR/substrings.f90 b/flang/test/Lower/HLFIR/substrings.f90
new file mode 100644
index 0000000000000..d97f75eb51d65
--- /dev/null
+++ b/flang/test/Lower/HLFIR/substrings.f90
@@ -0,0 +1,114 @@
+! Test lowering of substrings to HLFIR
+! Note: cse is run to make the expected output more readable by sharing
+! the boilerplate between the
diff erent susbtring cases.
+! RUN: bbc -emit-fir -hlfir -o - %s | fir-opt -cse -o - | FileCheck %s
+
+! CHECK-LABEL: func.func @_QPcst_len(
+subroutine cst_len(array, scalar)
+ character(10) :: array(100), scalar
+! CHECK: %[[VAL_5:.*]] = arith.constant 100 : index
+! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %{{.*}}(%[[VAL_6:.*]]) typeparams %[[VAL_3:[^ ]*]] {{.*}}array"
+! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_3]] {{.*}}scalar"
+ print *, array(:)(2:5)
+! CHECK: %[[VAL_15:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_16:.*]] = arith.constant 2 : index
+! CHECK: %[[VAL_17:.*]] = arith.constant 5 : index
+! CHECK: %[[VAL_18:.*]] = arith.constant 4 : index
+! CHECK: %[[VAL_19:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_15]]:%[[VAL_5]]:%[[VAL_15]]) substr %[[VAL_16]], %[[VAL_17]] shape %[[VAL_6]] typeparams %[[VAL_18]] : (!fir.ref<!fir.array<100x!fir.char<1,10>>>, index, index, index, index, index, !fir.shape<1>, index) -> !fir.box<!fir.array<100x!fir.char<1,4>>>
+
+ print *, array(42)(2:5)
+! CHECK: %[[VAL_25:.*]] = arith.constant 42 : index
+! CHECK: %[[VAL_26:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_25]]) substr %[[VAL_16]], %[[VAL_17]] typeparams %[[VAL_18]] : (!fir.ref<!fir.array<100x!fir.char<1,10>>>, index, index, index, index) -> !fir.ref<!fir.char<1,4>>
+ print *, array(:)(2:)
+! CHECK: %[[VAL_33:.*]] = arith.constant 9 : index
+! CHECK: %[[VAL_34:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_15]]:%[[VAL_5]]:%[[VAL_15]]) substr %[[VAL_16]], %[[VAL_3]] shape %[[VAL_6]] typeparams %[[VAL_33]] : (!fir.ref<!fir.array<100x!fir.char<1,10>>>, index, index, index, index, index, !fir.shape<1>, index) -> !fir.box<!fir.array<100x!fir.char<1,9>>>
+
+ print *, scalar(2:5)
+! CHECK: %[[VAL_40:.*]] = hlfir.designate %[[VAL_9]]#0 substr %[[VAL_16]], %[[VAL_17]] typeparams %[[VAL_18]] : (!fir.boxchar<1>, index, index, index) -> !fir.ref<!fir.char<1,4>>
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdyn_len(
+subroutine dyn_len(array, scalar, l, n, m, k)
+ integer(8) :: n,m,k
+! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare {{.*}}k"
+! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare {{.*}}m"
+! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare {{.*}}n"
+ character(l) :: array(:), scalar
+! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_13:[^ ]*]] {{.*}}array"
+! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_18:[^ ]*]] {{.*}}scalar"
+
+ print *, array(:)(n:m)
+! CHECK: %[[VAL_25:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_26:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_27:.*]]:3 = fir.box_dims %[[VAL_14]]#1, %[[VAL_26]] : (!fir.box<!fir.array<?x!fir.char<1,?>>>, index) -> (index, index, index)
+! CHECK: %[[VAL_28:.*]] = arith.subi %[[VAL_27]]#1, %[[VAL_25]] : index
+! CHECK: %[[VAL_29:.*]] = arith.addi %[[VAL_28]], %[[VAL_25]] : index
+! CHECK: %[[VAL_30:.*]] = arith.divsi %[[VAL_29]], %[[VAL_25]] : index
+! CHECK: %[[VAL_31:.*]] = arith.cmpi sgt, %[[VAL_30]], %[[VAL_26]] : index
+! CHECK: %[[VAL_32:.*]] = arith.select %[[VAL_31]], %[[VAL_30]], %[[VAL_26]] : index
+! CHECK: %[[VAL_33:.*]] = fir.shape %[[VAL_32]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_34:.*]] = fir.load %[[VAL_9]]#0 : !fir.ref<i64>
+! CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref<i64>
+! CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_34]] : (i64) -> index
+! CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_35]] : (i64) -> index
+! CHECK: %[[VAL_38:.*]] = arith.subi %[[VAL_37]], %[[VAL_36]] : index
+! CHECK: %[[VAL_39:.*]] = arith.addi %[[VAL_38]], %[[VAL_25]] : index
+! CHECK: %[[VAL_40:.*]] = arith.cmpi sgt, %[[VAL_39]], %[[VAL_26]] : index
+! CHECK: %[[VAL_41:.*]] = arith.select %[[VAL_40]], %[[VAL_39]], %[[VAL_26]] : index
+! CHECK: %[[VAL_42:.*]] = hlfir.designate %[[VAL_14]]#0 (%[[VAL_25]]:%[[VAL_27]]#1:%[[VAL_25]]) substr %[[VAL_36]], %[[VAL_37]] shape %[[VAL_33]] typeparams %[[VAL_41]] : (!fir.box<!fir.array<?x!fir.char<1,?>>>, index, index, index, index, index, !fir.shape<1>, index) -> !fir.box<!fir.array<?x!fir.char<1,?>>>
+
+ print *, array(k)(n:m)
+! CHECK: %[[VAL_48:.*]] = fir.load %[[VAL_7]]#0 : !fir.ref<i64>
+! CHECK: %[[VAL_49:.*]] = fir.load %[[VAL_9]]#0 : !fir.ref<i64>
+! CHECK: %[[VAL_50:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref<i64>
+! CHECK: %[[VAL_51:.*]] = fir.convert %[[VAL_49]] : (i64) -> index
+! CHECK: %[[VAL_52:.*]] = fir.convert %[[VAL_50]] : (i64) -> index
+! CHECK: %[[VAL_53:.*]] = arith.subi %[[VAL_52]], %[[VAL_51]] : index
+! CHECK: %[[VAL_54:.*]] = arith.addi %[[VAL_53]], %[[VAL_25]] : index
+! CHECK: %[[VAL_55:.*]] = arith.cmpi sgt, %[[VAL_54]], %[[VAL_26]] : index
+! CHECK: %[[VAL_56:.*]] = arith.select %[[VAL_55]], %[[VAL_54]], %[[VAL_26]] : index
+! CHECK: %[[VAL_57:.*]] = hlfir.designate %[[VAL_14]]#0 (%[[VAL_48]]) substr %[[VAL_51]], %[[VAL_52]] typeparams %[[VAL_56]] : (!fir.box<!fir.array<?x!fir.char<1,?>>>, i64, index, index, index) -> !fir.boxchar<1>
+
+ print *, array(:)(n:)
+! CHECK: %[[VAL_65:.*]] = fir.load %[[VAL_9]]#0 : !fir.ref<i64>
+! CHECK: %[[VAL_66:.*]] = fir.convert %[[VAL_13]] : (i32) -> i64
+! CHECK: %[[VAL_67:.*]] = fir.convert %[[VAL_65]] : (i64) -> index
+! CHECK: %[[VAL_68:.*]] = fir.convert %[[VAL_66]] : (i64) -> index
+! CHECK: %[[VAL_69:.*]] = arith.subi %[[VAL_68]], %[[VAL_67]] : index
+! CHECK: %[[VAL_70:.*]] = arith.addi %[[VAL_69]], %[[VAL_25]] : index
+! CHECK: %[[VAL_71:.*]] = arith.cmpi sgt, %[[VAL_70]], %[[VAL_26]] : index
+! CHECK: %[[VAL_72:.*]] = arith.select %[[VAL_71]], %[[VAL_70]], %[[VAL_26]] : index
+! CHECK: %[[VAL_73:.*]] = hlfir.designate %[[VAL_14]]#0 (%[[VAL_25]]:%[[VAL_27]]#1:%[[VAL_25]]) substr %[[VAL_67]], %[[VAL_68]] shape %[[VAL_33]] typeparams %[[VAL_72]] : (!fir.box<!fir.array<?x!fir.char<1,?>>>, index, index, index, index, index, !fir.shape<1>, index) -> !fir.box<!fir.array<?x!fir.char<1,?>>>
+
+ print *, scalar(n:m)
+! CHECK: %[[VAL_79:.*]] = fir.load %[[VAL_9]]#0 : !fir.ref<i64>
+! CHECK: %[[VAL_80:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref<i64>
+! CHECK: %[[VAL_81:.*]] = fir.convert %[[VAL_79]] : (i64) -> index
+! CHECK: %[[VAL_82:.*]] = fir.convert %[[VAL_80]] : (i64) -> index
+! CHECK: %[[VAL_83:.*]] = arith.subi %[[VAL_82]], %[[VAL_81]] : index
+! CHECK: %[[VAL_84:.*]] = arith.addi %[[VAL_83]], %[[VAL_25]] : index
+! CHECK: %[[VAL_85:.*]] = arith.cmpi sgt, %[[VAL_84]], %[[VAL_26]] : index
+! CHECK: %[[VAL_86:.*]] = arith.select %[[VAL_85]], %[[VAL_84]], %[[VAL_26]] : index
+! CHECK: %[[VAL_87:.*]] = hlfir.designate %[[VAL_19]]#0 substr %[[VAL_81]], %[[VAL_82]] typeparams %[[VAL_86]] : (!fir.boxchar<1>, index, index, index) -> !fir.boxchar<1>
+end subroutine
+
+subroutine test_static_substring(i, j)
+ integer(8) :: i, j
+ print *, "hello"(i:j)
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_static_substring(
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %{{.*}}i"
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}}j"
+! CHECK: %[[VAL_10:.*]] = arith.constant 5 : index
+! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_10]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = ".stringlit"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
+! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<i64>
+! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i64>
+! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_12]] : (i64) -> index
+! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_13]] : (i64) -> index
+! CHECK: %[[VAL_16:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_17:.*]] = arith.subi %[[VAL_15]], %[[VAL_14]] : index
+! CHECK: %[[VAL_18:.*]] = arith.addi %[[VAL_17]], %[[VAL_16]] : index
+! CHECK: %[[VAL_19:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_20:.*]] = arith.cmpi sgt, %[[VAL_18]], %[[VAL_19]] : index
+! CHECK: %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_18]], %[[VAL_19]] : index
+! CHECK: %[[VAL_22:.*]] = hlfir.designate %[[VAL_11]]#0 substr %[[VAL_14]], %[[VAL_15]] typeparams %[[VAL_21]] : (!fir.ref<!fir.char<1,5>>, index, index, index) -> !fir.boxchar<1>
diff --git a/flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp b/flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp
index 429f75a1e1a19..75bd4b35ccbcf 100644
--- a/flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp
+++ b/flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp
@@ -37,7 +37,8 @@ struct HLFIRToolsTest : public testing::Test {
mlir::Value createDeclare(fir::ExtendedValue exv) {
return hlfir::genDeclare(getLoc(), *firBuilder, exv,
- "x" + std::to_string(varCounter++), fir::FortranVariableFlagsAttr{});
+ "x" + std::to_string(varCounter++), fir::FortranVariableFlagsAttr{})
+ .getBase();
}
mlir::Value createConstant(std::int64_t cst) {
More information about the flang-commits
mailing list