From fd8b2d2046508c027ccf0fffb50d665c8355997a Mon Sep 17 00:00:00 2001 From: jeanPerier Date: Thu, 30 May 2024 11:02:09 +0200 Subject: [PATCH] [flang] lower RANK intrinsic (#93694) First commit is reviewed in https://github.com/llvm/llvm-project/pull/93682. Lower RANK using fir.box_rank. This patches updates fir.box_rank to accept box reference, this avoids the need of generating an assumed-rank fir.load just for the sake of reading ALLOCATABLE/POINTER rank. The fir.load would generate a "dynamic" memcpy that is hard to optimize without further knowledge. A read effect is conditionally given to the operation. --- flang/include/flang/Optimizer/Builder/HLFIRTools.h | 3 +++ flang/include/flang/Optimizer/Dialect/FIROps.td | 11 +++++++++-- flang/lib/Lower/ConvertExprToHLFIR.cpp | 2 +- flang/lib/Optimizer/Builder/HLFIRTools.cpp | 9 +++++++++ flang/lib/Optimizer/CodeGen/CodeGen.cpp | 3 ++- flang/lib/Optimizer/Dialect/FIROps.cpp | 14 ++++++++++++++ flang/test/Fir/convert-to-llvm.fir | 12 ++++++++++++ 7 files changed, 50 insertions(+), 4 deletions(-) diff --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h index 43aa1661550e..6dce89d2ecab 100644 --- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h +++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h @@ -334,6 +334,9 @@ void genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value genCharLength(mlir::Location loc, fir::FirOpBuilder &builder, Entity entity); +mlir::Value genRank(mlir::Location loc, fir::FirOpBuilder &builder, + Entity entity, mlir::Type resultType); + /// 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/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index 584b7e82bf27..3afc97475db1 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -62,6 +62,12 @@ class fir_SimpleOneResultOp traits = []> : let builders = [fir_OneResultOpBuilder]; } +// Whether a type is a BaseBoxType or a reference to a BaseBoxType. +def IsBoxAddressOrValueTypePred + : CPred<"::fir::isBoxAddressOrValue($_self)">; +def fir_BoxAddressOrValueType : Type; + //===----------------------------------------------------------------------===// // Memory SSA operations //===----------------------------------------------------------------------===// @@ -1205,7 +1211,8 @@ def fir_BoxProcHostOp : fir_SimpleOp<"boxproc_host", [NoMemoryEffect]> { let results = (outs fir_ReferenceType); } -def fir_BoxRankOp : fir_SimpleOneResultOp<"box_rank", [NoMemoryEffect]> { +def fir_BoxRankOp : fir_SimpleOneResultOp<"box_rank", + [DeclareOpInterfaceMethods]> { let summary = "return the number of dimensions for the boxed value"; let description = [{ @@ -1222,7 +1229,7 @@ def fir_BoxRankOp : fir_SimpleOneResultOp<"box_rank", [NoMemoryEffect]> { descriptor may be either an array or a scalar, so the value is nonnegative. }]; - let arguments = (ins fir_BoxType:$val); + let arguments = (ins fir_BoxAddressOrValueType:$box); let results = (outs AnyIntegerType); } diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp index 3c305955520e..a4352ee3359e 100644 --- a/flang/lib/Lower/ConvertExprToHLFIR.cpp +++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp @@ -1626,7 +1626,7 @@ private: return castResult( hlfir::genExtent(loc, builder, entity, desc.dimension())); case Fortran::evaluate::DescriptorInquiry::Field::Rank: - TODO(loc, "rank inquiry on assumed rank"); + return castResult(hlfir::genRank(loc, builder, entity, resultType)); case Fortran::evaluate::DescriptorInquiry::Field::Stride: // So far the front end does not generate this inquiry. TODO(loc, "stride inquiry"); diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp index 511585dc7689..e14e635a7f46 100644 --- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp +++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp @@ -642,6 +642,15 @@ mlir::Value hlfir::genCharLength(mlir::Location loc, fir::FirOpBuilder &builder, return lenParams[0]; } +mlir::Value hlfir::genRank(mlir::Location loc, fir::FirOpBuilder &builder, + hlfir::Entity entity, mlir::Type resultType) { + if (!entity.isAssumedRank()) + return builder.createIntegerConstant(loc, resultType, entity.getRank()); + assert(entity.isBoxAddressOrValue() && + "assumed-ranks are box addresses or values"); + return builder.create(loc, resultType, entity); +} + // Return a "shape" that can be used in fir.embox/fir.rebox with \p exv base. static mlir::Value asEmboxShape(mlir::Location loc, fir::FirOpBuilder &builder, const fir::ExtendedValue &exv, diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index 59aa9216b707..5d3adc3dfbf4 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -428,7 +428,8 @@ struct BoxRankOpConversion : public fir::FIROpConversion { mlir::Value a = adaptor.getOperands()[0]; auto loc = boxrank.getLoc(); mlir::Type ty = convertType(boxrank.getType()); - TypePair boxTyPair = getBoxTypePair(boxrank.getVal().getType()); + TypePair boxTyPair = + getBoxTypePair(fir::unwrapRefType(boxrank.getBox().getType())); mlir::Value rank = getRankFromBox(loc, boxTyPair, a, rewriter); mlir::Value result = integerCast(loc, rewriter, ty, rank); rewriter.replaceOp(boxrank, result); diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index 998e9535582c..b541b7cdc7a5 100644 --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -675,6 +675,20 @@ mlir::Type fir::BoxDimsOp::getTupleType() { return mlir::TupleType::get(getContext(), triple); } +//===----------------------------------------------------------------------===// +// BoxRankOp +//===----------------------------------------------------------------------===// + +void fir::BoxRankOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &effects) { + mlir::Value inputBox = getBox(); + if (fir::isBoxAddress(inputBox.getType())) + effects.emplace_back(mlir::MemoryEffects::Read::get(), inputBox, + mlir::SideEffects::DefaultResource::get()); +} + //===----------------------------------------------------------------------===// // CallOp //===----------------------------------------------------------------------===// diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir index 81810aa4bfc7..ee116e998c22 100644 --- a/flang/test/Fir/convert-to-llvm.fir +++ b/flang/test/Fir/convert-to-llvm.fir @@ -970,6 +970,18 @@ func.func @extract_rank(%arg0: !fir.box>) -> i32 { // CHECK: %[[RANK:.*]] = llvm.sext %[[RAW_RANK]] : i8 to i32 // CHECK: llvm.return %[[RANK]] : i32 +func.func @extract_rank2(%arg0: !fir.ref>>) -> i32 { + %0 = fir.box_rank %arg0 : (!fir.ref>>) -> i32 + return %0 : i32 +} + +// CHECK-LABEL: llvm.func @extract_rank2( +// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr) -> i32 +// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})> +// CHECK: %[[RAW_RANK:.*]] = llvm.load %[[GEP]] : !llvm.ptr -> i8 +// CHECK: %[[RANK:.*]] = llvm.sext %[[RAW_RANK]] : i8 to i32 +// CHECK: llvm.return %[[RANK]] : i32 + // ----- // Test `fir.box_addr` conversion.