[flang] Update UBOUND runtime API and lowering (#95085)
LBOUND and SHAPE runtime were added with an API that avoids making a dynamic allocation for the small result storage. Update the UBOUND API that was already there and used in lowering outside of the assumed-rank case. Add tests for the assumed-rank case.
This commit is contained in:
parent
2b66d283bc
commit
65f746e76c
@ -35,7 +35,7 @@ std::int64_t RTDECL(Size)(
|
||||
std::int64_t RTDECL(SizeDim)(const Descriptor &array, int dim,
|
||||
const char *sourceFile = nullptr, int line = 0);
|
||||
|
||||
void RTDECL(Ubound)(Descriptor &result, const Descriptor &array, int kind,
|
||||
void RTDECL(Ubound)(void *result, const Descriptor &array, int kind,
|
||||
const char *sourceFile = nullptr, int line = 0);
|
||||
|
||||
} // extern "C"
|
||||
|
@ -6071,33 +6071,80 @@ mlir::Value IntrinsicLibrary::genSetExponent(mlir::Type resultType,
|
||||
fir::getBase(args[1])));
|
||||
}
|
||||
|
||||
/// Create a fir.box to be passed to the LBOUND/UBOUND runtime.
|
||||
/// This ensure that local lower bounds of assumed shape are propagated and that
|
||||
/// a fir.box with equivalent LBOUNDs.
|
||||
static mlir::Value
|
||||
createBoxForRuntimeBoundInquiry(mlir::Location loc, fir::FirOpBuilder &builder,
|
||||
const fir::ExtendedValue &array) {
|
||||
// Assumed-rank descriptor must always carry accurate lower bound information
|
||||
// in lowering since they cannot be tracked on the side in a vector at compile
|
||||
// time.
|
||||
if (array.hasAssumedRank())
|
||||
return builder.createBox(loc, array);
|
||||
|
||||
return array.match(
|
||||
[&](const fir::BoxValue &boxValue) -> mlir::Value {
|
||||
// This entity is mapped to a fir.box that may not contain the local
|
||||
// lower bound information if it is a dummy. Rebox it with the local
|
||||
// shape information.
|
||||
mlir::Value localShape = builder.createShape(loc, array);
|
||||
mlir::Value oldBox = boxValue.getAddr();
|
||||
return builder.create<fir::ReboxOp>(loc, oldBox.getType(), oldBox,
|
||||
localShape,
|
||||
/*slice=*/mlir::Value{});
|
||||
},
|
||||
[&](const auto &) -> mlir::Value {
|
||||
// This is a pointer/allocatable, or an entity not yet tracked with a
|
||||
// fir.box. For pointer/allocatable, createBox will forward the
|
||||
// descriptor that contains the correct lower bound information. For
|
||||
// other entities, a new fir.box will be made with the local lower
|
||||
// bounds.
|
||||
return builder.createBox(loc, array);
|
||||
});
|
||||
}
|
||||
|
||||
/// Generate runtime call to inquire about all the bounds/extents of an
|
||||
/// assumed-rank array.
|
||||
/// array (or an assumed-rank).
|
||||
template <typename Func>
|
||||
static fir::ExtendedValue genAssumedRankBoundInquiry(
|
||||
fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type resultType,
|
||||
llvm::ArrayRef<fir::ExtendedValue> args, int kindPos, Func genRtCall) {
|
||||
static fir::ExtendedValue
|
||||
genBoundInquiry(fir::FirOpBuilder &builder, mlir::Location loc,
|
||||
mlir::Type resultType, llvm::ArrayRef<fir::ExtendedValue> args,
|
||||
int kindPos, Func genRtCall, bool needAccurateLowerBound) {
|
||||
const fir::ExtendedValue &array = args[0];
|
||||
// Allocate an array with the maximum rank, that is big enough to hold the
|
||||
// result but still "small" (15 elements). Static size alloca make stack
|
||||
// analysis/manipulation easier.
|
||||
const bool hasAssumedRank = array.hasAssumedRank();
|
||||
mlir::Type resultElementType = fir::unwrapSequenceType(resultType);
|
||||
mlir::Type allocSeqType =
|
||||
fir::SequenceType::get({Fortran::common::maxRank}, resultElementType);
|
||||
// For assumed-rank arrays, allocate an array with the maximum rank, that is
|
||||
// big enough to hold the result but still "small" (15 elements). Static size
|
||||
// alloca make stack analysis/manipulation easier.
|
||||
int rank = hasAssumedRank ? Fortran::common::maxRank : array.rank();
|
||||
mlir::Type allocSeqType = fir::SequenceType::get(rank, resultElementType);
|
||||
mlir::Value resultStorage = builder.createTemporary(loc, allocSeqType);
|
||||
mlir::Value arrayBox = builder.createBox(loc, array);
|
||||
mlir::Value arrayBox =
|
||||
needAccurateLowerBound
|
||||
? createBoxForRuntimeBoundInquiry(loc, builder, array)
|
||||
: builder.createBox(loc, array);
|
||||
mlir::Value kind = isStaticallyAbsent(args, kindPos)
|
||||
? builder.createIntegerConstant(
|
||||
loc, builder.getI32Type(),
|
||||
builder.getKindMap().defaultIntegerKind())
|
||||
: fir::getBase(args[kindPos]);
|
||||
genRtCall(builder, loc, resultStorage, arrayBox, kind);
|
||||
mlir::Type baseType =
|
||||
fir::ReferenceType::get(builder.getVarLenSeqTy(resultElementType));
|
||||
mlir::Value resultBase = builder.createConvert(loc, baseType, resultStorage);
|
||||
mlir::Value rank =
|
||||
builder.create<fir::BoxRankOp>(loc, builder.getIndexType(), arrayBox);
|
||||
return fir::ArrayBoxValue{resultBase, {rank}};
|
||||
if (hasAssumedRank) {
|
||||
// Cast to fir.ref<array<?xik>> since the result extent is not a compile
|
||||
// time constant.
|
||||
mlir::Type baseType =
|
||||
fir::ReferenceType::get(builder.getVarLenSeqTy(resultElementType));
|
||||
mlir::Value resultBase =
|
||||
builder.createConvert(loc, baseType, resultStorage);
|
||||
mlir::Value rankValue =
|
||||
builder.create<fir::BoxRankOp>(loc, builder.getIndexType(), arrayBox);
|
||||
return fir::ArrayBoxValue{resultBase, {rankValue}};
|
||||
}
|
||||
// Result extent is a compile time constant in the other cases.
|
||||
mlir::Value rankValue =
|
||||
builder.createIntegerConstant(loc, builder.getIndexType(), rank);
|
||||
return fir::ArrayBoxValue{resultStorage, {rankValue}};
|
||||
}
|
||||
|
||||
// SHAPE
|
||||
@ -6107,8 +6154,9 @@ IntrinsicLibrary::genShape(mlir::Type resultType,
|
||||
assert(args.size() >= 1);
|
||||
const fir::ExtendedValue &array = args[0];
|
||||
if (array.hasAssumedRank())
|
||||
return genAssumedRankBoundInquiry(builder, loc, resultType, args,
|
||||
/*kindPos=*/1, fir::runtime::genShape);
|
||||
return genBoundInquiry(builder, loc, resultType, args,
|
||||
/*kindPos=*/1, fir::runtime::genShape,
|
||||
/*needAccurateLowerBound=*/false);
|
||||
int rank = array.rank();
|
||||
mlir::Type indexType = builder.getIndexType();
|
||||
mlir::Type extentType = fir::unwrapSequenceType(resultType);
|
||||
@ -6344,33 +6392,6 @@ static mlir::Value computeLBOUND(fir::FirOpBuilder &builder, mlir::Location loc,
|
||||
return builder.create<mlir::arith::SelectOp>(loc, dimIsEmpty, one, lb);
|
||||
}
|
||||
|
||||
/// Create a fir.box to be passed to the LBOUND/UBOUND runtime.
|
||||
/// This ensure that local lower bounds of assumed shape are propagated and that
|
||||
/// a fir.box with equivalent LBOUNDs.
|
||||
static mlir::Value
|
||||
createBoxForRuntimeBoundInquiry(mlir::Location loc, fir::FirOpBuilder &builder,
|
||||
const fir::ExtendedValue &array) {
|
||||
return array.match(
|
||||
[&](const fir::BoxValue &boxValue) -> mlir::Value {
|
||||
// This entity is mapped to a fir.box that may not contain the local
|
||||
// lower bound information if it is a dummy. Rebox it with the local
|
||||
// shape information.
|
||||
mlir::Value localShape = builder.createShape(loc, array);
|
||||
mlir::Value oldBox = boxValue.getAddr();
|
||||
return builder.create<fir::ReboxOp>(loc, oldBox.getType(), oldBox,
|
||||
localShape,
|
||||
/*slice=*/mlir::Value{});
|
||||
},
|
||||
[&](const auto &) -> mlir::Value {
|
||||
// This is a pointer/allocatable, or an entity not yet tracked with a
|
||||
// fir.box. For pointer/allocatable, createBox will forward the
|
||||
// descriptor that contains the correct lower bound information. For
|
||||
// other entities, a new fir.box will be made with the local lower
|
||||
// bounds.
|
||||
return builder.createBox(loc, array);
|
||||
});
|
||||
}
|
||||
|
||||
// LBOUND
|
||||
fir::ExtendedValue
|
||||
IntrinsicLibrary::genLbound(mlir::Type resultType,
|
||||
@ -6380,9 +6401,12 @@ IntrinsicLibrary::genLbound(mlir::Type resultType,
|
||||
// Semantics builds signatures for LBOUND calls as either
|
||||
// LBOUND(array, dim, [kind]) or LBOUND(array, [kind]).
|
||||
const bool dimIsAbsent = args.size() == 2 || isStaticallyAbsent(args, 1);
|
||||
if (array.hasAssumedRank() && dimIsAbsent)
|
||||
return genAssumedRankBoundInquiry(builder, loc, resultType, args,
|
||||
/*kindPos=*/1, fir::runtime::genLbound);
|
||||
if (array.hasAssumedRank() && dimIsAbsent) {
|
||||
int kindPos = args.size() == 2 ? 1 : 2;
|
||||
return genBoundInquiry(builder, loc, resultType, args, kindPos,
|
||||
fir::runtime::genLbound,
|
||||
/*needAccurateLowerBound=*/true);
|
||||
}
|
||||
|
||||
mlir::Type indexType = builder.getIndexType();
|
||||
|
||||
@ -6434,7 +6458,8 @@ fir::ExtendedValue
|
||||
IntrinsicLibrary::genUbound(mlir::Type resultType,
|
||||
llvm::ArrayRef<fir::ExtendedValue> args) {
|
||||
assert(args.size() == 3 || args.size() == 2);
|
||||
if (args.size() == 3) {
|
||||
const bool dimIsAbsent = args.size() == 2 || isStaticallyAbsent(args, 1);
|
||||
if (!dimIsAbsent) {
|
||||
// Handle calls to UBOUND with the DIM argument, which return a scalar
|
||||
mlir::Value extent = fir::getBase(genSize(resultType, args));
|
||||
mlir::Value lbound = fir::getBase(genLbound(resultType, args));
|
||||
@ -6442,28 +6467,12 @@ IntrinsicLibrary::genUbound(mlir::Type resultType,
|
||||
mlir::Value one = builder.createIntegerConstant(loc, resultType, 1);
|
||||
mlir::Value ubound = builder.create<mlir::arith::SubIOp>(loc, lbound, one);
|
||||
return builder.create<mlir::arith::AddIOp>(loc, ubound, extent);
|
||||
} else {
|
||||
// Handle calls to UBOUND without the DIM argument, which return an array
|
||||
mlir::Value kind = isStaticallyAbsent(args[1])
|
||||
? builder.createIntegerConstant(
|
||||
loc, builder.getIndexType(),
|
||||
builder.getKindMap().defaultIntegerKind())
|
||||
: fir::getBase(args[1]);
|
||||
|
||||
// Create mutable fir.box to be passed to the runtime for the result.
|
||||
mlir::Type type = builder.getVarLenSeqTy(resultType, /*rank=*/1);
|
||||
fir::MutableBoxValue resultMutableBox =
|
||||
fir::factory::createTempMutableBox(builder, loc, type);
|
||||
mlir::Value resultIrBox =
|
||||
fir::factory::getMutableIRBox(builder, loc, resultMutableBox);
|
||||
|
||||
fir::ExtendedValue box =
|
||||
createBoxForRuntimeBoundInquiry(loc, builder, args[0]);
|
||||
fir::runtime::genUbound(builder, loc, resultIrBox, fir::getBase(box), kind);
|
||||
|
||||
return readAndAddCleanUp(resultMutableBox, resultType, "UBOUND");
|
||||
}
|
||||
return mlir::Value();
|
||||
// Handle calls to UBOUND without the DIM argument, which return an array
|
||||
int kindPos = args.size() == 2 ? 1 : 2;
|
||||
return genBoundInquiry(builder, loc, resultType, args, kindPos,
|
||||
fir::runtime::genUbound,
|
||||
/*needAccurateLowerBound=*/true);
|
||||
}
|
||||
|
||||
// SPACING
|
||||
|
@ -39,28 +39,14 @@ std::int64_t RTDEF(LboundDim)(
|
||||
return static_cast<std::int64_t>(dimension.LowerBound());
|
||||
}
|
||||
|
||||
void RTDEF(Ubound)(Descriptor &result, const Descriptor &array, int kind,
|
||||
void RTDEF(Ubound)(void *result, const Descriptor &array, int kind,
|
||||
const char *sourceFile, int line) {
|
||||
SubscriptValue extent[1]{array.rank()};
|
||||
result.Establish(TypeCategory::Integer, kind, nullptr, 1, extent,
|
||||
CFI_attribute_allocatable);
|
||||
// The array returned by UBOUND has a lower bound of 1 and an extent equal to
|
||||
// the rank of its input array.
|
||||
result.GetDimension(0).SetBounds(1, array.rank());
|
||||
Terminator terminator{sourceFile, line};
|
||||
if (int stat{result.Allocate()}) {
|
||||
terminator.Crash(
|
||||
"UBOUND: could not allocate memory for result; STAT=%d", stat);
|
||||
}
|
||||
auto storeIntegerAt = [&](std::size_t atIndex, std::int64_t value) {
|
||||
Fortran::runtime::ApplyIntegerKind<StoreIntegerAt, void>(
|
||||
kind, terminator, result, atIndex, value);
|
||||
};
|
||||
|
||||
INTERNAL_CHECK(result.rank() == 1);
|
||||
INTERNAL_CHECK(array.rank() <= common::maxRank);
|
||||
for (SubscriptValue i{0}; i < array.rank(); ++i) {
|
||||
const Dimension &dimension{array.GetDimension(i)};
|
||||
storeIntegerAt(i, dimension.UpperBound());
|
||||
Fortran::runtime::ApplyIntegerKind<RawStoreIntegerAt, void>(
|
||||
kind, terminator, result, i, dimension.UpperBound());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,3 +109,86 @@ end subroutine
|
||||
! CHECK: %[[VAL_13:.*]] = fir.box_rank %[[VAL_4]] : (!fir.box<!fir.ptr<!fir.array<*:f32>>>) -> index
|
||||
! CHECK: %[[VAL_14:.*]] = fir.shape %[[VAL_13]] : (index) -> !fir.shape<1>
|
||||
! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_12]](%[[VAL_14]]) {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.ref<!fir.array<?xi32>>)
|
||||
|
||||
subroutine test_ubound(x)
|
||||
real :: x(..)
|
||||
call takes_integer_array(ubound(x))
|
||||
end subroutine
|
||||
! CHECK-LABEL: func.func @_QPtest_ubound(
|
||||
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<15xi32>
|
||||
! CHECK: %[[VAL_4:.*]] = arith.constant 4 : i32
|
||||
! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<15xi32>>) -> !fir.llvm_ptr<i8>
|
||||
! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_3:.*]] : (!fir.box<!fir.array<*:f32>>) -> !fir.box<none>
|
||||
! CHECK: %[[VAL_10:.*]] = fir.call @_FortranAUbound(%[[VAL_7]], %[[VAL_8]], %[[VAL_4]], %{{.*}}, %{{.*}})
|
||||
! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<15xi32>>) -> !fir.ref<!fir.array<?xi32>>
|
||||
! CHECK: %[[VAL_12:.*]] = fir.box_rank %[[VAL_3]] : (!fir.box<!fir.array<*:f32>>) -> index
|
||||
! CHECK: %[[VAL_13:.*]] = fir.shape %[[VAL_12]] : (index) -> !fir.shape<1>
|
||||
! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_11]](%[[VAL_13]]) {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.ref<!fir.array<?xi32>>)
|
||||
! CHECK: %[[VAL_15:.*]] = arith.constant false
|
||||
! CHECK: %[[VAL_16:.*]] = hlfir.as_expr %[[VAL_14]]#0 move %[[VAL_15]] : (!fir.box<!fir.array<?xi32>>, i1) -> !hlfir.expr<?xi32>
|
||||
! CHECK: %[[VAL_17:.*]]:3 = hlfir.associate %[[VAL_16]](%[[VAL_13]]) {adapt.valuebyref} : (!hlfir.expr<?xi32>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.ref<!fir.array<?xi32>>, i1)
|
||||
! CHECK: fir.call @_QPtakes_integer_array(%[[VAL_17]]#1) fastmath<contract> : (!fir.ref<!fir.array<?xi32>>) -> ()
|
||||
! CHECK: hlfir.end_associate %[[VAL_17]]#1, %[[VAL_17]]#2 : !fir.ref<!fir.array<?xi32>>, i1
|
||||
! CHECK: hlfir.destroy %[[VAL_16]] : !hlfir.expr<?xi32>
|
||||
! CHECK: return
|
||||
! CHECK: }
|
||||
|
||||
subroutine test_ubound_kind(x)
|
||||
real :: x(..)
|
||||
call takes_integer8_array(ubound(x, kind=8))
|
||||
end subroutine
|
||||
! CHECK-LABEL: func.func @_QPtest_ubound_kind(
|
||||
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<15xi64>
|
||||
! CHECK: %[[VAL_4:.*]] = arith.constant 8 : i32
|
||||
! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<15xi64>>) -> !fir.llvm_ptr<i8>
|
||||
! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_3:.*]] : (!fir.box<!fir.array<*:f32>>) -> !fir.box<none>
|
||||
! CHECK: %[[VAL_10:.*]] = fir.call @_FortranAUbound(%[[VAL_7]], %[[VAL_8]], %[[VAL_4]], %{{.*}}, %{{.*}})
|
||||
! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<15xi64>>) -> !fir.ref<!fir.array<?xi64>>
|
||||
! CHECK: %[[VAL_12:.*]] = fir.box_rank %[[VAL_3]] : (!fir.box<!fir.array<*:f32>>) -> index
|
||||
! CHECK: %[[VAL_13:.*]] = fir.shape %[[VAL_12]] : (index) -> !fir.shape<1>
|
||||
! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_11]](%[[VAL_13]]) {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref<!fir.array<?xi64>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi64>>, !fir.ref<!fir.array<?xi64>>)
|
||||
|
||||
subroutine test_ubound_2(x)
|
||||
real, pointer :: x(..)
|
||||
call takes_integer_array(ubound(x))
|
||||
end subroutine
|
||||
! CHECK-LABEL: func.func @_QPtest_ubound_2(
|
||||
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<15xi32>
|
||||
! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3:.*]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<*:f32>>>>
|
||||
! CHECK: %[[VAL_5:.*]] = arith.constant 4 : i32
|
||||
! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<15xi32>>) -> !fir.llvm_ptr<i8>
|
||||
! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_4]] : (!fir.box<!fir.ptr<!fir.array<*:f32>>>) -> !fir.box<none>
|
||||
! CHECK: %[[VAL_11:.*]] = fir.call @_FortranAUbound(%[[VAL_8]], %[[VAL_9]], %[[VAL_5]], %{{.*}}, %{{.*}})
|
||||
! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<15xi32>>) -> !fir.ref<!fir.array<?xi32>>
|
||||
! CHECK: %[[VAL_13:.*]] = fir.box_rank %[[VAL_4]] : (!fir.box<!fir.ptr<!fir.array<*:f32>>>) -> index
|
||||
! CHECK: %[[VAL_14:.*]] = fir.shape %[[VAL_13]] : (index) -> !fir.shape<1>
|
||||
! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_12]](%[[VAL_14]]) {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.ref<!fir.array<?xi32>>)
|
||||
|
||||
subroutine test_lbound_dim(x)
|
||||
real :: x(..)
|
||||
call takes_integer(lbound(x, dim=2))
|
||||
end subroutine
|
||||
! CHECK-LABEL: func.func @_QPtest_lbound_dim(
|
||||
! CHECK: %[[VAL_3:.*]] = arith.constant 2 : i32
|
||||
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_2:.*]]#0 : (!fir.box<!fir.array<*:f32>>) -> !fir.box<none>
|
||||
! CHECK: %[[VAL_8:.*]] = fir.call @_FortranALboundDim(%[[VAL_6]], %[[VAL_3]],
|
||||
! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i64) -> i32
|
||||
! CHECK: %[[VAL_10:.*]]:3 = hlfir.associate %[[VAL_9]]
|
||||
|
||||
|
||||
subroutine test_ubound_dim(x)
|
||||
real :: x(..)
|
||||
call takes_integer(ubound(x, dim=2))
|
||||
end subroutine
|
||||
! CHECK-LABEL: func.func @_QPtest_ubound_dim(
|
||||
! CHECK: %[[VAL_3:.*]] = arith.constant 2 : i32
|
||||
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_2:.*]]#0 : (!fir.box<!fir.array<*:f32>>) -> !fir.box<none>
|
||||
! CHECK: %[[VAL_8:.*]] = fir.call @_FortranASizeDim(%[[VAL_6]], %[[VAL_3]],
|
||||
! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i64) -> i32
|
||||
! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]]#0 : (!fir.box<!fir.array<*:f32>>) -> !fir.box<none>
|
||||
! CHECK: %[[VAL_14:.*]] = fir.call @_FortranALboundDim(%[[VAL_12]], %[[VAL_3]],
|
||||
! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (i64) -> i32
|
||||
! CHECK: %[[VAL_16:.*]] = arith.constant 1 : i32
|
||||
! CHECK: %[[VAL_17:.*]] = arith.subi %[[VAL_15]], %[[VAL_16]] : i32
|
||||
! CHECK: %[[VAL_18:.*]] = arith.addi %[[VAL_17]], %[[VAL_9]] : i32
|
||||
! CHECK: %[[VAL_19:.*]]:3 = hlfir.associate %[[VAL_18]]
|
||||
|
@ -20,4 +20,4 @@ end
|
||||
! CHECK-SAME: %[[ARG0:.*]]: !fir.box<!fir.array<?x?xf32>>
|
||||
! CHECK: %[[BOX:.*]] = fir.rebox %[[ARG0]](%{{.*}}) : (!fir.box<!fir.array<?x?xf32>>, !fir.shift<2>) -> !fir.box<!fir.array<?x?xf32>>
|
||||
! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[BOX]] : (!fir.box<!fir.array<?x?xf32>>) -> !fir.box<none>
|
||||
! CHECK: %{{.*}} = fir.call @_FortranAUbound(%{{.*}}, %[[BOX_NONE]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.ref<!fir.box<none>>, !fir.box<none>, i32, !fir.ref<i8>, i32) -> none
|
||||
! CHECK: %{{.*}} = fir.call @_FortranAUbound(%{{.*}}, %[[BOX_NONE]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.box<none>, i32, !fir.ref<i8>, i32) -> none
|
||||
|
@ -69,35 +69,33 @@ TEST(Inquiry, Ubound) {
|
||||
std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})};
|
||||
array->GetDimension(0).SetLowerBound(1000);
|
||||
array->GetDimension(1).SetLowerBound(1);
|
||||
StaticDescriptor<2, true> statDesc;
|
||||
|
||||
int intValue{1};
|
||||
SubscriptValue extent[]{2};
|
||||
Descriptor &result{statDesc.descriptor()};
|
||||
result.Establish(TypeCategory::Integer, /*KIND=*/4,
|
||||
static_cast<void *>(&intValue), 1, extent, CFI_attribute_pointer);
|
||||
RTNAME(Ubound)(result, *array, /*KIND=*/4, __FILE__, __LINE__);
|
||||
EXPECT_EQ(result.rank(), 1);
|
||||
EXPECT_EQ(result.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));
|
||||
// The lower bound of UBOUND's result array is always 1
|
||||
EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
|
||||
EXPECT_EQ(result.GetDimension(0).Extent(), 2);
|
||||
EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(0), 1001);
|
||||
EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(1), 3);
|
||||
result.Destroy();
|
||||
// UBOUND(ARRAY, KIND=1)
|
||||
auto int8Result{
|
||||
MakeArray<TypeCategory::Integer, 1>(std::vector<int>{array->rank()},
|
||||
std::vector<std::int8_t>(array->rank(), 0))};
|
||||
RTNAME(Ubound)
|
||||
(int8Result->raw().base_addr, *array, /*KIND=*/1, __FILE__, __LINE__);
|
||||
EXPECT_EQ(*int8Result->ZeroBasedIndexedElement<std::int8_t>(0), -23);
|
||||
EXPECT_EQ(*int8Result->ZeroBasedIndexedElement<std::int8_t>(1), 3);
|
||||
|
||||
result = statDesc.descriptor();
|
||||
result.Establish(TypeCategory::Integer, /*KIND=*/1,
|
||||
static_cast<void *>(&intValue), 1, extent, CFI_attribute_pointer);
|
||||
RTNAME(Ubound)(result, *array, /*KIND=*/1, __FILE__, __LINE__);
|
||||
EXPECT_EQ(result.rank(), 1);
|
||||
EXPECT_EQ(result.type().raw(), (TypeCode{TypeCategory::Integer, 1}.raw()));
|
||||
// The lower bound of UBOUND's result array is always 1
|
||||
EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
|
||||
EXPECT_EQ(result.GetDimension(0).Extent(), 2);
|
||||
EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int8_t>(0), -23);
|
||||
EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int8_t>(1), 3);
|
||||
result.Destroy();
|
||||
// UBOUND(ARRAY, KIND=4)
|
||||
auto int32Result{
|
||||
MakeArray<TypeCategory::Integer, 4>(std::vector<int>{array->rank()},
|
||||
std::vector<std::int32_t>(array->rank(), 0))};
|
||||
RTNAME(Ubound)
|
||||
(int32Result->raw().base_addr, *array, /*KIND=*/4, __FILE__, __LINE__);
|
||||
EXPECT_EQ(*int32Result->ZeroBasedIndexedElement<std::int32_t>(0), 1001);
|
||||
EXPECT_EQ(*int32Result->ZeroBasedIndexedElement<std::int32_t>(1), 3);
|
||||
|
||||
// UBOUND(ARRAY, KIND=8)
|
||||
auto int64Result{
|
||||
MakeArray<TypeCategory::Integer, 8>(std::vector<int>{array->rank()},
|
||||
std::vector<std::int64_t>(array->rank(), 0))};
|
||||
RTNAME(Ubound)
|
||||
(int64Result->raw().base_addr, *array, /*KIND=*/8, __FILE__, __LINE__);
|
||||
EXPECT_EQ(*int64Result->ZeroBasedIndexedElement<std::int64_t>(0), 1001);
|
||||
EXPECT_EQ(*int64Result->ZeroBasedIndexedElement<std::int64_t>(1), 3);
|
||||
}
|
||||
|
||||
TEST(Inquiry, Size) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user