[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.
This commit is contained in:
jeanPerier
2024-05-30 11:02:09 +02:00
committed by GitHub
parent 32b91ec395
commit fd8b2d2046
7 changed files with 50 additions and 4 deletions

View File

@@ -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

View File

@@ -62,6 +62,12 @@ class fir_SimpleOneResultOp<string mnemonic, list<Trait> 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<IsBoxAddressOrValueTypePred,
"fir.box or fir.class type or reference">;
//===----------------------------------------------------------------------===//
// 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<MemoryEffectsOpInterface>]> {
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);
}

View File

@@ -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");

View File

@@ -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<fir::BoxRankOp>(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,

View File

@@ -428,7 +428,8 @@ struct BoxRankOpConversion : public fir::FIROpConversion<fir::BoxRankOp> {
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);

View File

@@ -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<mlir::MemoryEffects::Effect>>
&effects) {
mlir::Value inputBox = getBox();
if (fir::isBoxAddress(inputBox.getType()))
effects.emplace_back(mlir::MemoryEffects::Read::get(), inputBox,
mlir::SideEffects::DefaultResource::get());
}
//===----------------------------------------------------------------------===//
// CallOp
//===----------------------------------------------------------------------===//

View File

@@ -970,6 +970,18 @@ func.func @extract_rank(%arg0: !fir.box<!fir.array<*:f64>>) -> i32 {
// CHECK: %[[RANK:.*]] = llvm.sext %[[RAW_RANK]] : i8 to i32
// CHECK: llvm.return %[[RANK]] : i32
func.func @extract_rank2(%arg0: !fir.ref<!fir.box<!fir.array<*:f64>>>) -> i32 {
%0 = fir.box_rank %arg0 : (!fir.ref<!fir.box<!fir.array<*:f64>>>) -> 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.