/// value.
bool isUnlimitedPolymorphicType(mlir::Type ty);
+/// Return the inner type of the given type.
+mlir::Type unwrapInnerType(mlir::Type ty);
+
/// Return true iff `ty` is a RecordType with members that are allocatable.
bool isRecordWithAllocatableMember(mlir::Type ty);
// Lower TRANSPOSE as a runtime call under -O0.
loweringOpts.setOptimizeTranspose(codegenOpts.OptimizationLevel > 0);
+ loweringOpts.setPolymorphicTypeImpl(true);
const LangOptions &langOptions = getLangOpts();
Fortran::common::MathOptionsBase &mathOpts = loweringOpts.getMathOptions();
Fortran::common::TypeCategory category = dynamicType->category();
mlir::Type baseType;
- if (category == Fortran::common::TypeCategory::Derived) {
+ if (dynamicType->IsUnlimitedPolymorphic()) {
+ baseType = mlir::NoneType::get(context);
+ } else if (category == Fortran::common::TypeCategory::Derived) {
baseType = genDerivedType(dynamicType->GetDerivedTypeSpec());
} else {
// LOGICAL, INTEGER, REAL, COMPLEX, CHARACTER
/// Get the address of the type descriptor global variable that was created by
/// lowering for derived type \p recType.
- template <typename BOX>
- mlir::Value
- getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter,
- mlir::Location loc, fir::RecordType recType) const {
+ mlir::Value getTypeDescriptor(mlir::ModuleOp mod,
+ mlir::ConversionPatternRewriter &rewriter,
+ mlir::Location loc,
+ fir::RecordType recType) const {
std::string name =
fir::NameUniquer::getTypeDescriptorName(recType.getName());
- auto module = box->template getParentOfType<mlir::ModuleOp>();
- if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) {
+ if (auto global = mod.template lookupSymbol<fir::GlobalOp>(name)) {
auto ty = mlir::LLVM::LLVMPointerType::get(
this->lowerTy().convertType(global.getType()));
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
global.getSymName());
}
- if (auto global =
- module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
+ if (auto global = mod.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
// The global may have already been translated to LLVM.
auto ty = mlir::LLVM::LLVMPointerType::get(global.getType());
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
fir::emitFatalError(
loc, "runtime derived type info descriptor was not generated");
return rewriter.create<mlir::LLVM::NullOp>(
- loc, ::getVoidPtrType(box.getContext()));
+ loc, ::getVoidPtrType(mod.getContext()));
}
- template <typename BOX>
- std::tuple<fir::BaseBoxType, mlir::Value, mlir::Value>
- consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter,
- unsigned rank, mlir::ValueRange lenParams,
- mlir::Value typeDesc = {}) const {
- auto loc = box.getLoc();
- auto boxTy = box.getType().template dyn_cast<fir::BaseBoxType>();
+ mlir::Value populateDescriptor(mlir::Location loc, mlir::ModuleOp mod,
+ fir::BaseBoxType boxTy, mlir::Type inputType,
+ mlir::ConversionPatternRewriter &rewriter,
+ unsigned rank, mlir::Value eleSize,
+ mlir::Value cfiTy,
+ mlir::Value typeDesc) const {
auto convTy = this->lowerTy().convertBoxType(boxTy, rank);
auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>();
auto llvmBoxTy = llvmBoxPtrTy.getElementType();
+ bool isUnlimitedPolymorphic = fir::isUnlimitedPolymorphicType(boxTy);
mlir::Value descriptor =
rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
-
- llvm::SmallVector<mlir::Value> typeparams = lenParams;
- if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
- if (!box.getSubstr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
- typeparams.push_back(box.getSubstr()[1]);
- }
-
- // Write each of the fields with the appropriate values
- auto [eleSize, cfiTy] =
- getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
descriptor =
insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
descriptor =
insertField(rewriter, loc, descriptor, {kAttributePosInBox},
this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
- const bool hasAddendum = isDerivedType(boxTy);
+ const bool hasAddendum = isDerivedType(boxTy) || isUnlimitedPolymorphic;
descriptor =
insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox},
this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0));
if (hasAddendum) {
unsigned typeDescFieldId = getTypeDescFieldId(boxTy);
- if (!typeDesc)
- typeDesc =
- getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy));
- descriptor =
- insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
- /*bitCast=*/true);
+ if (!typeDesc) {
+ if (isUnlimitedPolymorphic) {
+ mlir::Type innerType = fir::unwrapInnerType(inputType);
+ if (innerType && innerType.template isa<fir::RecordType>()) {
+ auto recTy = innerType.template dyn_cast<fir::RecordType>();
+ typeDesc = getTypeDescriptor(mod, rewriter, loc, recTy);
+ } else {
+ // Unlimited polymorphic type descriptor with no record type. Set
+ // type descriptor address to a clean state.
+ typeDesc = rewriter.create<mlir::LLVM::NullOp>(
+ loc, ::getVoidPtrType(mod.getContext()));
+ }
+ } else {
+ typeDesc =
+ getTypeDescriptor(mod, rewriter, loc, unwrapIfDerived(boxTy));
+ }
+ }
+ if (typeDesc)
+ descriptor =
+ insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
+ /*bitCast=*/true);
}
+ return descriptor;
+ }
+
+ // Template used for fir::EmboxOp and fir::cg::XEmboxOp
+ template <typename BOX>
+ std::tuple<fir::BaseBoxType, mlir::Value, mlir::Value>
+ consDescriptorPrefix(BOX box, mlir::Type inputType,
+ mlir::ConversionPatternRewriter &rewriter, unsigned rank,
+ mlir::ValueRange lenParams,
+ mlir::Value typeDesc = {}) const {
+ auto loc = box.getLoc();
+ auto boxTy = box.getType().template dyn_cast<fir::BaseBoxType>();
+ bool isUnlimitedPolymorphic = fir::isUnlimitedPolymorphicType(boxTy);
+ bool useInputType =
+ isUnlimitedPolymorphic && !fir::isUnlimitedPolymorphicType(inputType);
+ llvm::SmallVector<mlir::Value> typeparams = lenParams;
+ if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
+ if (!box.getSubstr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
+ typeparams.push_back(box.getSubstr()[1]);
+ }
+
+ // Write each of the fields with the appropriate values.
+ // When emboxing an element to a unlimited polymorphic descriptor, use the
+ // input type since the destination descriptor type as no type information.
+ auto [eleSize, cfiTy] = getSizeAndTypeCode(
+ loc, rewriter, useInputType ? inputType : boxTy.getEleTy(), typeparams);
+ auto mod = box->template getParentOfType<mlir::ModuleOp>();
+ mlir::Value descriptor = populateDescriptor(
+ loc, mod, boxTy, inputType, rewriter, rank, eleSize, cfiTy, typeDesc);
+
+ return {boxTy, descriptor, eleSize};
+ }
+
+ std::tuple<fir::BaseBoxType, mlir::Value, mlir::Value>
+ consDescriptorPrefix(fir::cg::XReboxOp box, mlir::Value loweredBox,
+ mlir::ConversionPatternRewriter &rewriter, unsigned rank,
+ mlir::ValueRange lenParams,
+ mlir::Value typeDesc = {}) const {
+ auto loc = box.getLoc();
+ auto boxTy = box.getType().dyn_cast<fir::BaseBoxType>();
+ llvm::SmallVector<mlir::Value> typeparams = lenParams;
+ if (!box.getSubstr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
+ typeparams.push_back(box.getSubstr()[1]);
+
+ auto [eleSize, cfiTy] =
+ getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
+
+ // Reboxing an unlimited polymorphic entities. eleSize and type code need to
+ // be retrived from the initial box.
+ if (fir::isUnlimitedPolymorphicType(boxTy) &&
+ fir::isUnlimitedPolymorphicType(box.getBox().getType())) {
+ mlir::Type idxTy = this->lowerTy().indexType();
+ eleSize = this->loadElementSizeFromBox(loc, idxTy, loweredBox, rewriter);
+ cfiTy = this->getValueFromBox(loc, loweredBox, cfiTy.getType(), rewriter,
+ kTypePosInBox);
+ typeDesc = this->loadTypeDescAddress(loc, box.getBox().getType(),
+ loweredBox, rewriter);
+ }
+
+ auto mod = box->template getParentOfType<mlir::ModuleOp>();
+ mlir::Value descriptor =
+ populateDescriptor(loc, mod, boxTy, box.getBox().getType(), rewriter,
+ rank, eleSize, cfiTy, typeDesc);
return {boxTy, descriptor, eleSize};
}
tdesc = operands[embox.getTdescOffset()];
assert(!embox.getShape() && "There should be no dims on this embox op");
auto [boxTy, dest, eleSize] = consDescriptorPrefix(
- embox, rewriter,
+ embox, fir::unwrapRefType(embox.getMemref().getType()), rewriter,
/*rank=*/0, /*lenParams=*/operands.drop_front(1), tdesc);
dest = insertBaseAddress(rewriter, embox.getLoc(), dest, operands[0]);
if (isDerivedTypeWithLenParams(boxTy)) {
mlir::Value tdesc;
if (xbox.getTdesc())
tdesc = operands[xbox.getTdescOffset()];
- auto [boxTy, dest, eleSize] =
- consDescriptorPrefix(xbox, rewriter, xbox.getOutRank(),
- operands.drop_front(xbox.lenParamOffset()), tdesc);
+ auto [boxTy, dest, eleSize] = consDescriptorPrefix(
+ xbox, fir::unwrapRefType(xbox.getMemref().getType()), rewriter,
+ xbox.getOutRank(), operands.drop_front(xbox.lenParamOffset()), tdesc);
// Generate the triples in the dims field of the descriptor
auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64);
mlir::Value base = operands[0];
typeDescAddr = loadTypeDescAddress(loc, rebox.getBox().getType(),
loweredBox, rewriter);
- auto [boxTy, dest, eleSize] = consDescriptorPrefix(
- rebox, rewriter, rebox.getOutRank(), lenParams, typeDescAddr);
+ auto [boxTy, dest, eleSize] =
+ consDescriptorPrefix(rebox, loweredBox, rewriter, rebox.getOutRank(),
+ lenParams, typeDescAddr);
// Read input extents, strides, and base address
llvm::SmallVector<mlir::Value> inputExtents;
dataDescFields.push_back(mlir::LLVM::LLVMArrayType::get(rowTy, rank));
}
// opt-type-ptr: i8* (see fir.tdesc)
- if (requiresExtendedDesc(ele)) {
+ if (requiresExtendedDesc(ele) || fir::isUnlimitedPolymorphicType(box)) {
dataDescFields.push_back(
getExtendedDescFieldTypeModel<kOptTypePtrPosInBox>()(&getContext()));
auto rowTy =
return isAssumedType(ty);
}
+mlir::Type unwrapInnerType(mlir::Type ty) {
+ return llvm::TypeSwitch<mlir::Type, mlir::Type>(ty)
+ .Case<fir::PointerType, fir::HeapType, fir::SequenceType>([](auto t) {
+ mlir::Type eleTy = t.getEleTy();
+ if (auto seqTy = eleTy.dyn_cast<fir::SequenceType>())
+ return seqTy.getEleTy();
+ return eleTy;
+ })
+ .Default([](mlir::Type) { return mlir::Type{}; });
+}
+
bool isRecordWithAllocatableMember(mlir::Type ty) {
if (auto recTy = ty.dyn_cast<fir::RecordType>())
for (auto [field, memTy] : recTy.getTypeList()) {
}
mlir::Type BaseBoxType::unwrapInnerType() const {
- return llvm::TypeSwitch<mlir::Type, mlir::Type>(getEleTy())
- .Case<fir::PointerType, fir::HeapType, fir::SequenceType>([](auto ty) {
- mlir::Type eleTy = ty.getEleTy();
- if (auto seqTy = eleTy.dyn_cast<fir::SequenceType>())
- return seqTy.getEleTy();
- return eleTy;
- })
- .Default([](mlir::Type) { return mlir::Type{}; });
+ return fir::unwrapInnerType(getEleTy());
}
//===----------------------------------------------------------------------===//
// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr<array<100 x i32>>
// CHECK: %[[C1:.*]] = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[C1]] x !llvm.struct<(ptr<array<100 x i32>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})> {alignment = 8 : i64} : (i32) -> !llvm.ptr<struct<(ptr<array<100 x i32>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>
-// CHECK: %[[DESC:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<array<100 x i32>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
// CHECK: %[[NULL:.*]] = llvm.mlir.null : !llvm.ptr<i32>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
// CHECK: %[[I64_ELEM_SIZE:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr<i32> to i64
// CHECK: %[[TYPE_CODE:.*]] = llvm.mlir.constant(9 : i32) : i32
+// CHECK: %[[DESC:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<array<100 x i32>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
// CHECK: %[[DESC0:.*]] = llvm.insertvalue %[[I64_ELEM_SIZE]], %[[DESC]][1] : !llvm.struct<(ptr<array<100 x i32>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
// CHECK: %[[CFI_VERSION:.*]] = llvm.mlir.constant(20180515 : i32) : i32
// CHECK: %[[DESC1:.*]] = llvm.insertvalue %[[CFI_VERSION]], %[[DESC0]][2] : !llvm.struct<(ptr<array<100 x i32>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
// CHECK: %[[ALLOCA_SIZE:.*]] = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[ALLOCA_SIZE]] x !llvm.struct<(ptr<i32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr<struct<(ptr<i32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>>
// CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : i64) : i64
-// CHECK: %[[BOX0:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<i32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
// CHECK: %[[NULL:.*]] = llvm.mlir.null : !llvm.ptr<i32>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
// CHECK: %[[ELEM_LEN_I64:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr<i32> to i64
// CHECK: %[[TYPE:.*]] = llvm.mlir.constant(9 : i32) : i32
+// CHECK: %[[BOX0:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<i32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
// CHECK: %[[BOX1:.*]] = llvm.insertvalue %[[ELEM_LEN_I64]], %[[BOX0]][1] : !llvm.struct<(ptr<i32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
// CHECK: %[[VERSION:.*]] = llvm.mlir.constant(20180515 : i32) : i32
// CHECK: %[[BOX2:.*]] = llvm.insertvalue %[[VERSION]], %[[BOX1]][2] : !llvm.struct<(ptr<i32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
// CHECK: %[[ARR_SIZE_TMP1:.*]] = llvm.mul %[[C1_0]], %[[N1]] : i64
// CHECK: %[[ARR_SIZE:.*]] = llvm.mul %[[ARR_SIZE_TMP1]], %[[N2]] : i64
// CHECK: %[[ARR:.*]] = llvm.alloca %[[ARR_SIZE]] x f64 {bindc_name = "arr", in_type = !fir.array<?x?xf64>, operand_segment_sizes = array<i32: 0, 2>, uniq_name = "_QFsbEarr"} : (i64) -> !llvm.ptr<f64>
-// CHECK: %[[BOX0:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>
// CHECK: %[[NULL:.*]] = llvm.mlir.null : !llvm.ptr<f64>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
// CHECK: %[[ELEM_LEN_I64:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr<f64> to i64
// CHECK: %[[TYPE_CODE:.*]] = llvm.mlir.constant(28 : i32) : i32
+// CHECK: %[[BOX0:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>
// CHECK: %[[BOX1:.*]] = llvm.insertvalue %[[ELEM_LEN_I64]], %[[BOX0]][1] : !llvm.struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>
// CHECK: %[[VERSION:.*]] = llvm.mlir.constant(20180515 : i32) : i32
// CHECK: %[[BOX2:.*]] = llvm.insertvalue %[[VERSION]], %[[BOX1]][2] : !llvm.struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>
// CHECK: %[[V:.*]] = llvm.alloca %[[ALLOCA_SIZE_V]] x i32 {bindc_name = "v", in_type = i32, operand_segment_sizes = array<i32: 0, 0>, uniq_name = "_QFtest_dt_sliceEv"} : (i64) -> !llvm.ptr<i32>
// CHECK: %[[ALLOCA_SIZE_X:.*]] = llvm.mlir.constant(1 : i64) : i64
// CHECK: %[[X:.*]] = llvm.alloca %[[ALLOCA_SIZE_X]] x !llvm.array<20 x struct<"_QFtest_dt_sliceTt", (i32, i32)>> {bindc_name = "x", in_type = !fir.array<20x!fir.type<_QFtest_dt_sliceTt{i:i32,j:i32}>>, operand_segment_sizes = array<i32: 0, 0>, uniq_name = "_QFtest_dt_sliceEx"} : (i64) -> !llvm.ptr<array<20 x struct<"_QFtest_dt_sliceTt", (i32, i32)>>>
-// CHECK: %[[BOX0:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<i32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
// CHECK: %[[NULL:.*]] = llvm.mlir.null : !llvm.ptr<i32>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
// CHECK: %[[ELEM_LEN_I64:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr<i32> to i64
// CHECK: %[[TYPE_CODE:.*]] = llvm.mlir.constant(9 : i32) : i32
+// CHECK: %[[BOX0:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<i32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
// CHECK: %[[BOX1:.*]] = llvm.insertvalue %[[ELEM_LEN_I64]], %[[BOX0]][1] : !llvm.struct<(ptr<i32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
// CHECK: %[[VERSION:.*]] = llvm.mlir.constant(20180515 : i32) : i32
// CHECK: %[[BOX2:.*]] = llvm.insertvalue %[[VERSION]], %[[BOX1]][2] : !llvm.struct<(ptr<i32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
//CHECK: %[[FIVE:.*]] = llvm.mlir.constant(5 : index) : i64
//CHECK: %[[SIX:.*]] = llvm.mlir.constant(6 : index) : i64
//CHECK: %[[EIGHTY:.*]] = llvm.mlir.constant(80 : index) : i64
-//CHECK: %[[RBOX:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<f32>, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
//CHECK: %[[NULL:.*]] = llvm.mlir.null : !llvm.ptr<f32>
//CHECK: %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
//CHECK: %[[ELEM_SIZE_I64:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr<f32> to i64
//CHECK: %[[FLOAT_TYPE:.*]] = llvm.mlir.constant(27 : i32) : i32
+//CHECK: %[[RBOX:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<f32>, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
//CHECK: %[[RBOX_TMP1:.*]] = llvm.insertvalue %[[ELEM_SIZE_I64]], %[[RBOX]][1] : !llvm.struct<(ptr<f32>, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
//CHECK: %[[CFI_VERSION:.*]] = llvm.mlir.constant(20180515 : i32) : i32
//CHECK: %[[RBOX_TMP2:.*]] = llvm.insertvalue %[[CFI_VERSION]], %[[RBOX_TMP1]][2] : !llvm.struct<(ptr<f32>, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
}
// CHECK-LABEL: define void @_QMpolymorphic_testPtest_allocate_unlimited_polymorphic_non_derived() {
-// CHECK: %[[MEM:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }
-// CHECK: %[[DESC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }, i64 1
-// CHECK: store { ptr, i64, i32, i8, i8, i8, i8 } { ptr null, i64 0, i32 20180515, i8 0, i8 -1, i8 1, i8 0 }, ptr %[[MEM]]
-// CHECK: %[[LOADED:.*]] = load { ptr, i64, i32, i8, i8, i8, i8 }, ptr %[[MEM]], align 8
-// CHECK: store { ptr, i64, i32, i8, i8, i8, i8 } %[[LOADED]], ptr %[[DESC]]
+// CHECK: %[[MEM:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }
+// CHECK: %[[DESC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, i64 1
+// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } { ptr null, i64 0, i32 20180515, i8 0, i8 -1, i8 1, i8 1, ptr null, [1 x i64] undef }, ptr %[[MEM]]
+// CHECK: %[[LOADED:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[MEM]], align 8
+// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOADED]], ptr %[[DESC]]
// CHECK: ret void
// CHECK: }
+
+
+// Test rebox of unlimited polymoprhic descriptor
+
+func.func @_QMpolymorphic_testPtest_rebox() {
+ %0 = fir.address_of(@_QFEx) : !fir.ref<!fir.class<!fir.ptr<!fir.array<?xnone>>>>
+ %c-1_i32 = arith.constant -1 : i32
+ %9 = fir.address_of(@_QQcl.2E2F64756D6D792E66393000) : !fir.ref<!fir.char<1,12>>
+ %10 = fir.convert %9 : (!fir.ref<!fir.char<1,12>>) -> !fir.ref<i8>
+ %c8_i32 = arith.constant 8 : i32
+ %11 = fir.call @_FortranAioBeginExternalListOutput(%c-1_i32, %10, %c8_i32) fastmath<contract> : (i32, !fir.ref<i8>, i32) -> !fir.ref<i8>
+ %12 = fir.load %0 : !fir.ref<!fir.class<!fir.ptr<!fir.array<?xnone>>>>
+ %c0_1 = arith.constant 0 : index
+ %13:3 = fir.box_dims %12, %c0_1 : (!fir.class<!fir.ptr<!fir.array<?xnone>>>, index) -> (index, index, index)
+ %14 = fir.shift %13#0 : (index) -> !fir.shift<1>
+ %15 = fir.rebox %12(%14) : (!fir.class<!fir.ptr<!fir.array<?xnone>>>, !fir.shift<1>) -> !fir.class<!fir.array<?xnone>>
+ %16 = fir.convert %15 : (!fir.class<!fir.array<?xnone>>) -> !fir.box<none>
+ %17 = fir.call @_FortranAioOutputDescriptor(%11, %16) fastmath<contract> : (!fir.ref<i8>, !fir.box<none>) -> i1
+ %18 = fir.call @_FortranAioEndIoStatement(%11) fastmath<contract> : (!fir.ref<i8>) -> i32
+ return
+}
+
+// CHECK-LABEL: @_QMpolymorphic_testPtest_rebox
+// CHECK: %[[ELE_SIZE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %{{.*}}, i32 0, i32 1
+// CHECK: %[[ELE_SIZE:.*]] = load i64, ptr %[[ELE_SIZE_GEP]]
+// CHECK: %[[TYPE_CODE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %{{.*}}, i32 0, i32 4
+// CHECK: %[[TYPE_CODE:.*]] = load i32, ptr %[[TYPE_CODE_GEP]]
+// CHECK: %{{.*}} = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } undef, i64 %[[ELE_SIZE]], 1
+// CHECK: %[[TYPE_CODE_I8:.*]] = trunc i32 %[[TYPE_CODE]] to i8
+// CHECK: %{{.*}} = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %{{.*}}, i8 %[[TYPE_CODE_I8]], 4
+
+// Test emboxing to a unlimited polymorphic descriptor
+
+func.func @_QMpolymorphic_testPtest_embox() {
+ %0 = fir.address_of(@_QFEx) : !fir.ref<!fir.class<!fir.ptr<!fir.array<?xnone>>>>
+ %1 = fir.address_of(@_QFEy) : !fir.ref<!fir.array<1xi32>>
+ %c1 = arith.constant 1 : index
+ %2 = fir.alloca i32 {bindc_name = "z", uniq_name = "_QFEz"}
+ %3 = fir.shape %c1 : (index) -> !fir.shape<1>
+ %4 = fir.embox %1(%3) : (!fir.ref<!fir.array<1xi32>>, !fir.shape<1>) -> !fir.class<!fir.ptr<!fir.array<?xnone>>>
+ fir.store %4 to %0 : !fir.ref<!fir.class<!fir.ptr<!fir.array<?xnone>>>>
+ return
+}
+
+// CHECK-LABEL: @_QMpolymorphic_testPtest_embox()
+// CHECK: %[[ALLOCA_DESC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }
+// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } { ptr @_QFEy, i64 ptrtoint (ptr getelementptr (i32, ptr null, i32 1) to i64), i32 20180515, i8 1, i8 9, {{.*}}, ptr %[[ALLOCA_DESC]]
+// CHECK: %[[LOADED_DESC:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[ALLOCA_DESC]], align 8
+// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %[[LOADED_DESC]], ptr @_QFEx, align 8
+
+
+fir.global internal @_QFEx : !fir.class<!fir.ptr<!fir.array<?xnone>>> {
+ %0 = fir.zero_bits !fir.ptr<!fir.array<?xnone>>
+ %c0 = arith.constant 0 : index
+ %1 = fir.shape %c0 : (index) -> !fir.shape<1>
+ %2 = fir.embox %0(%1) : (!fir.ptr<!fir.array<?xnone>>, !fir.shape<1>) -> !fir.class<!fir.ptr<!fir.array<?xnone>>>
+ fir.has_value %2 : !fir.class<!fir.ptr<!fir.array<?xnone>>>
+}
+
+fir.global internal @_QFEy target : !fir.array<1xi32> {
+ %0 = fir.undefined !fir.array<1xi32>
+ fir.has_value %0 : !fir.array<1xi32>
+}
+
+func.func private @_FortranAioBeginExternalListOutput(i32, !fir.ref<i8>, i32) -> !fir.ref<i8> attributes {fir.io, fir.runtime}
+func.func private @_FortranAioOutputDescriptor(!fir.ref<i8>, !fir.box<none>) -> i1 attributes {fir.io, fir.runtime}
+func.func private @_FortranAioEndIoStatement(!fir.ref<i8>) -> i32 attributes {fir.io, fir.runtime}
+fir.global linkonce @_QQcl.2E2F64756D6D792E66393000 constant : !fir.char<1,12> {
+ %0 = fir.string_lit "./dummy.f90\00"(12) : !fir.char<1,12>
+ fir.has_value %0 : !fir.char<1,12>
+}