[flang-commits] [flang] [llvm] [flang] To fix LIT test that AIX does not emit comdat. (PR #214950)
Daniel Chen via flang-commits
flang-commits at lists.llvm.org
Sat Aug 8 16:17:46 PDT 2026
https://github.com/DanielCChen updated https://github.com/llvm/llvm-project/pull/214950
>From 12faecad00a218d650b4a534817368ebbb6e779f Mon Sep 17 00:00:00 2001
From: Daniel Chen <cdchen at ca.ibm.com>
Date: Wed, 5 Aug 2026 08:28:11 -0400
Subject: [PATCH 1/3] [flang] Fix ICE when lowering IBM vector() array through
fir.box
---
flang/lib/Optimizer/CodeGen/CodeGen.cpp | 2 +-
flang/lib/Optimizer/Dialect/FIRType.cpp | 5 ++-
flang/test/Fir/embox-ppc-vector.fir | 40 +++++++++++++++++++
.../test/Lower/PowerPC/ppc-vec-array-box.f90 | 39 ++++++++++++++++++
4 files changed, 84 insertions(+), 2 deletions(-)
create mode 100644 flang/test/Fir/embox-ppc-vector.fir
create mode 100644 flang/test/Lower/PowerPC/ppc-vec-array-box.f90
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 4b7891bd46df1..8a9b511a35420 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -1820,7 +1820,7 @@ struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
return {genTypeStrideInBytes(loc, i64Ty, rewriter, ptrTy, dataLayout),
typeCodeVal};
}
- if (mlir::isa<fir::RecordType>(boxEleTy))
+ if (mlir::isa<fir::RecordType, fir::VectorType>(boxEleTy))
return {genTypeStrideInBytes(loc, i64Ty, rewriter,
this->convertType(boxEleTy), dataLayout),
typeCodeVal};
diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index 178860239e17d..8b80f1d60146a 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -584,7 +584,10 @@ int getTypeCode(mlir::Type ty, const fir::KindMapping &kindMap) {
}
if (fir::isa_ref_type(ty))
return CFI_type_cptr;
- if (mlir::isa<fir::RecordType>(ty))
+ // fir::VectorType is the IBM Fortran vector() extension type used as a
+ // fir.box element type. Use CFI_type_struct as the accepted fallback
+ // for opaque aggregate types in internal descriptors
+ if (mlir::isa<fir::RecordType, fir::VectorType>(ty))
return CFI_type_struct;
llvm_unreachable("unsupported type");
}
diff --git a/flang/test/Fir/embox-ppc-vector.fir b/flang/test/Fir/embox-ppc-vector.fir
new file mode 100644
index 0000000000000..14f163e8b970e
--- /dev/null
+++ b/flang/test/Fir/embox-ppc-vector.fir
@@ -0,0 +1,40 @@
+// Test emboxing PPC vector type to a descriptor
+//RUN: fir-opt -cg-rewrite --fir-to-llvm-ir %s | FileCheck %s
+
+func.func @test1() {
+ %0 = fir.alloca !fir.box<!fir.heap<!fir.vector<4:i32>>>
+ %1 = fir.zero_bits !fir.heap<!fir.vector<4:i32>>
+ %2 = fir.embox %1 : (!fir.heap<!fir.vector<4:i32>>) -> !fir.box<!fir.heap<!fir.vector<4:i32>>>
+ fir.store %2 to %0 : !fir.ref<!fir.box<!fir.heap<!fir.vector<4:i32>>>>
+ return
+}
+
+//CHECK-LABEL: llvm.func @test1()
+//CHECK: %[[TYPE_VAL:.*]] = llvm.mlir.constant(42 : i32) : i32
+//CHECK: %[[ELEM_LEN_VAL:.*]] = llvm.mlir.constant(16 : i64) : i64
+//CHECK: %[[DSC_1:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+//CHECK: %[[DSC_2:.*]] = llvm.insertvalue %[[ELEM_LEN_VAL]], %[[DSC_1]][1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+//CHECK: %[[RANK_VAL:.*]] = llvm.mlir.constant(0 : i32) : i32
+//CHECK: %[[DSC_3:.*]] = llvm.trunc %[[RANK_VAL]] : i32 to i8
+//CHECK: %[[DSC_4:.*]] = llvm.insertvalue %[[DSC_3]], %11[3] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+//CHECK: %[[DSC_5:.*]] = llvm.trunc %[[TYPE_VAL]] : i32 to i8
+//CHECK: %[[DSC_6:.*]] = llvm.insertvalue %[[DSC_5]], %[[DSC_4]][4] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+
+func.func @test2() {
+ %0 = fir.alloca !fir.box<!fir.heap<!fir.vector<2:f64>>>
+ %1 = fir.zero_bits !fir.heap<!fir.vector<2:f64>>
+ %2 = fir.embox %1 : (!fir.heap<!fir.vector<2:f64>>) -> !fir.box<!fir.heap<!fir.vector<2:f64>>>
+ fir.store %2 to %0 : !fir.ref<!fir.box<!fir.heap<!fir.vector<2:f64>>>>
+ return
+}
+
+//CHECK-LABEL: llvm.func @test2()
+//CHECK: %[[TYPE_VAL:.*]] = llvm.mlir.constant(42 : i32) : i32
+//CHECK: %[[ELEM_LEN_VAL:.*]] = llvm.mlir.constant(16 : i64) : i64
+//CHECK: %[[DSC_1:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+//CHECK: %[[DSC_2:.*]] = llvm.insertvalue %[[ELEM_LEN_VAL]], %[[DSC_1]][1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+//CHECK: %[[RANK_VAL:.*]] = llvm.mlir.constant(0 : i32) : i32
+//CHECK: %[[DSC_3:.*]] = llvm.trunc %[[RANK_VAL]] : i32 to i8
+//CHECK: %[[DSC_4:.*]] = llvm.insertvalue %[[DSC_3]], %11[3] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+//CHECK: %[[DSC_5:.*]] = llvm.trunc %[[TYPE_VAL]] : i32 to i8
+//CHECK: %[[DSC_6:.*]] = llvm.insertvalue %[[DSC_5]], %[[DSC_4]][4] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
diff --git a/flang/test/Lower/PowerPC/ppc-vec-array-box.f90 b/flang/test/Lower/PowerPC/ppc-vec-array-box.f90
new file mode 100644
index 0000000000000..fcd824704e501
--- /dev/null
+++ b/flang/test/Lower/PowerPC/ppc-vec-array-box.f90
@@ -0,0 +1,39 @@
+! RUN: %flang_fc1 -triple powerpc64-ibm-aix7.2.0.0 -emit-fir -o - %s | FileCheck %s --check-prefix=FIR
+! RUN: %flang_fc1 -triple powerpc64-ibm-aix7.2.0.0 -emit-llvm -O0 -o - %s | FileCheck %s --check-prefix=LLVMIR
+! REQUIRES: target=powerpc{{.*}}
+
+! Test that merge() on an array of IBM vector() type lowers correctly through
+! a fir.box descriptor at -O0.
+!
+! At -O0, HLFIR bufferization creates a temporary array and wraps it in a
+! fir.box<!fir.array<Nx!fir.vector<...>>>. Before the fix, both:
+! - getTypeCode() in FIRType.cpp hit llvm_unreachable("unsupported type")
+! - getSizeAndTypeCode() in CodeGen.cpp hit fir::emitFatalError(...)
+! because neither handled fir::VectorType as a fir.box element type.
+!
+! Additionally, getTypeCode() must return CFI_type_struct (not CFI_type_other)
+! for fir::VectorType. CFI_type_other is rejected at runtime by
+! VerifyEstablishParameters for internal (compiler-generated) descriptors,
+! causing a fatal error: "CFI_establish returned 15 for CFI_type_t(-1)".
+!
+! At -O3, hlfir::createInlineHLFIRCopy inlines the copy element-by-element,
+! avoiding the fir.box entirely, which is why -O3 always passed.
+
+subroutine vec_merge_array(va, vb, mask, res)
+ vector(integer(4)), intent(in) :: va(2), vb(2)
+ logical, intent(in) :: mask(2)
+ vector(integer(4)), intent(out) :: res(2)
+ res = merge(va, vb, mask)
+end subroutine
+
+! FIR-LABEL: func.func @_QPvec_merge_array
+
+! Verify the temporary array and its fir.embox are generated with
+! fir.vector<4:i32> as the element type — this is the type that previously
+! triggered the ICE in getTypeCode() and getSizeAndTypeCode().
+! FIR: fir.allocmem !fir.array<2x!fir.vector<4:i32>>
+! FIR: fir.embox {{.*}} : ({{.*}}!fir.array<2x!fir.vector<4:i32>>{{.*}}) -> !fir.box<!fir.array<2x!fir.vector<4:i32>>>
+
+! LLVMIR-LABEL: define void @vec_merge_array_
+! Verify CodeGen completes and produces correct vector stores.
+! LLVMIR: store <4 x i32>
>From a5dc9547ea151f8a0f714bd5fa59ad435bbadded Mon Sep 17 00:00:00 2001
From: Daniel Chen <cdchen at ca.ibm.com>
Date: Fri, 7 Aug 2026 22:37:55 -0400
Subject: [PATCH 2/3] [flang] Fix same_type_as for IBM vector() types in
class(*) descriptors
When a class(*) allocatable holds an IBM vector extension type (e.g.
vector(integer(4)) or vector(real(4))), same_type_as produced wrong
results:
- same_type_as(x, x) after allocate(x, source=vi) returned .false.
(derivedType_ was null in the descriptor addendum)
- same_type_as(xi, xr) where xi/xr hold different vector KINDs
returned .true. (uninstantiatedType() compared equal for all
vector() variants)
Root cause and fixes (7 files):
1. flang/lib/Lower/ConvertType.cpp
genDerivedType() returned early for IsVectorType() before calling
registerTypeInfo(), so no fir.type_info stub was ever queued.
Fix: call registerTypeInfo with an empty fir.RecordType before
the early return.
2. flang/lib/Lower/Bridge.cpp
createTypeInfoOp() would crash on vector types because the normal
path iterates DerivedTypeDetails::componentNames(), which is invalid
for vector types.
Fix: early return for IsVectorType() that emits a minimal
fir.type_info stub with no-init/no-destroy/no-final attributes.
3. flang/lib/Lower/Allocatable.cpp
The mold value for allocate(source=vi) was a plain fir.box with no
addendum, so AllocatableApplyMold copied a null derivedType_ into
the LHS descriptor.
Fix: new genVectorMoldBox() helper that re-boxes vector molds as
fir.class<fir.type<K0K4>> so the derivedType_ addendum is set;
called in genRuntimeAllocateApplyMold().
4. flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
The polymorphic assignment RHS for a vector type was a plain fir.box
with no addendum, leaving derivedType_ null after assignment.
Fix: when LHS is polymorphic and RHS element type is VectorType,
re-box as fir.class<fir.type<K0K4>> before passing to the runtime.
5. flang/lib/Optimizer/CodeGen/CodeGen.cpp (populateDescriptor)
When useInputType=true and the input element type is VectorType
(not RecordType), the RecordType branch was skipped and the code fell
through to the zero-pointer branch, leaving the type descriptor null.
Fix: add an else-if that uses fir::unwrapIfDerived(boxTy) to obtain
the RecordType from the box's declared type instead.
6. flang/lib/Optimizer/Dialect/FIRType.cpp
Remove a stale comment; no functional change (VectorType and
RecordType remain combined in the CFI_type_struct branch, which is
required to avoid a CFI_establish runtime error).
7. flang-rt/lib/runtime/derived-api.cpp (SameTypeAs)
After uninstantiatedType() pointer equality, all vector() KINDs were
considered the same type because they share a single PDT template.
Fix: after confirming the uninstantiated template pointers match,
check whether the type name starts with __builtin_ppc_intrinsic_vector
and return false if so -- each vector KIND is a distinct user type.
Test: flang/test/Lower/PowerPC/ppc-vec-same-type-as.f90
- allocate(class(*), source=vector(integer(4))): same_type_as .true.
- allocate(class(*), source=vector(real(4))): same_type_as .true.
- assign vector(real(4)) to class(*): same_type_as .true.
- cross-kind: same_type_as(xi, xr) .false., same-kind still .true.
---
flang-rt/lib/runtime/derived-api.cpp | 20 ++++-
flang/lib/Lower/Allocatable.cpp | 76 ++++++++++++++++++-
flang/lib/Lower/Bridge.cpp | 23 +++++-
flang/lib/Lower/ConvertType.cpp | 14 ++++
flang/lib/Optimizer/CodeGen/CodeGen.cpp | 5 ++
flang/lib/Optimizer/Dialect/FIRType.cpp | 3 -
.../HLFIR/Transforms/ConvertToFIR.cpp | 42 ++++++++++
.../Lower/PowerPC/ppc-vec-same-type-as.f90 | 63 +++++++++++++++
8 files changed, 235 insertions(+), 11 deletions(-)
create mode 100644 flang/test/Lower/PowerPC/ppc-vec-same-type-as.f90
diff --git a/flang-rt/lib/runtime/derived-api.cpp b/flang-rt/lib/runtime/derived-api.cpp
index fe6868292f019..4655022953cf8 100644
--- a/flang-rt/lib/runtime/derived-api.cpp
+++ b/flang-rt/lib/runtime/derived-api.cpp
@@ -106,11 +106,25 @@ bool RTDEF(SameTypeAs)(const Descriptor &a, const Descriptor &b) {
return true;
} else if (const typeInfo::DerivedType *
uninstDerivedTypeA{derivedTypeA->uninstantiatedType()}) {
- // There are KIND type parameters, are these the same type if those
- // are ignored?
+ // IBM vector types share an uninstantiated PDT template but are
+ // distinct to the user. Guard against them below.
const typeInfo::DerivedType *uninstDerivedTypeB{
derivedTypeB->uninstantiatedType()};
- return uninstDerivedTypeA == uninstDerivedTypeB;
+ if (uninstDerivedTypeA != uninstDerivedTypeB)
+ return false;
+ // Same uninstantiated template -- reject if it is an IBM vector type.
+ static constexpr char vecPrefix[] =
+ "__builtin_ppc_intrinsic_vector";
+ static constexpr std::size_t vecPrefixLen{sizeof(vecPrefix) - 1};
+ const Descriptor &nameDesc{uninstDerivedTypeA->name()};
+ const char *typeName{nameDesc.OffsetElement<const char>()};
+ std::size_t nameLen{nameDesc.ElementBytes()};
+ if (nameLen >= vecPrefixLen &&
+ Fortran::runtime::memcmp(
+ typeName, vecPrefix, vecPrefixLen) == 0)
+ // IBM vector types: same template but different KIND -- distinct.
+ return false;
+ return true;
}
}
}
diff --git a/flang/lib/Lower/Allocatable.cpp b/flang/lib/Lower/Allocatable.cpp
index f51342b27a19d..ecc965720c468 100644
--- a/flang/lib/Lower/Allocatable.cpp
+++ b/flang/lib/Lower/Allocatable.cpp
@@ -207,7 +207,74 @@ static mlir::Value genRuntimeAllocateSource(fir::FirOpBuilder &builder,
return fir::CallOp::create(builder, loc, callee, args).getResult(0);
}
-/// Generate runtime call to apply mold to the descriptor.
+/// Re-box \p mold as fir.class<fir.type<K0K4>> when it holds an IBM vector
+/// type so AllocatableApplyMold copies a valid derivedType_ into the LHS.
+/// Returns {} if \p mold is not a vector type.
+static mlir::Value genVectorMoldBox(fir::FirOpBuilder &builder,
+ mlir::Location loc,
+ const fir::ExtendedValue &mold) {
+ // The mold is always a BoxValue; getBase returns a fir.box.
+ // unwrapSeqOrBoxedSeqType (not getFortranElementType) is needed to unwrap
+ // through the box to reach the vector element type.
+ mlir::Value baseVal = fir::getBase(mold);
+ mlir::Type elemTy = fir::unwrapSeqOrBoxedSeqType(baseVal.getType());
+ if (!mlir::isa<fir::VectorType>(elemTy))
+ return {};
+ // K-suffix: K0K<bytes> for integer/unsigned, K2K<bytes> for real.
+ mlir::Type eleTy = mlir::cast<fir::VectorType>(elemTy).getEleTy();
+ std::string kSuffix;
+ if (auto intTy = mlir::dyn_cast<mlir::IntegerType>(eleTy))
+ kSuffix = "K0K" + std::to_string(intTy.getWidth() / 8);
+ else if (auto floatTy = mlir::dyn_cast<mlir::FloatType>(eleTy))
+ kSuffix = "K2K" + std::to_string(floatTy.getWidth() / 8);
+ if (kSuffix.empty())
+ return {};
+ // Look up by MLIR-uniqued name; do not walk the module -- fir.type_info ops
+ // are emitted after the function body and not yet present.
+ std::string recName =
+ "_QM__ppc_typesT__builtin_ppc_intrinsic_vector" + kSuffix;
+ fir::RecordType recTy =
+ fir::RecordType::get(builder.getContext(), recName);
+ if (!recTy)
+ return {};
+ // fir.embox requires a data pointer, not a descriptor value.
+ mlir::Value dataAddr = fir::BoxAddrOp::create(builder, loc, baseVal);
+ // Build seqTy from the unwrapped address (known or unknown extents).
+ mlir::Type seqTy;
+ if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(
+ fir::unwrapPassByRefType(dataAddr.getType())))
+ seqTy = fir::SequenceType::get(arrTy.getShape(), recTy);
+ else
+ seqTy = fir::SequenceType::get({fir::SequenceType::getUnknownExtent()},
+ recTy);
+ // createShape returns {} for a BoxValue with no explicit lower bounds;
+ // fall back to reading extents from the box (constants or fir.box_dims).
+ mlir::Value shape = builder.createShape(loc, mold);
+ if (!shape) {
+ mlir::Type innerTy = fir::dyn_cast_ptrOrBoxEleTy(baseVal.getType());
+ if (auto seqArrTy = mlir::dyn_cast<fir::SequenceType>(innerTy)) {
+ mlir::Type idxTy = builder.getIndexType();
+ llvm::SmallVector<mlir::Value> extents;
+ for (auto [d, ext] : llvm::enumerate(seqArrTy.getShape())) {
+ if (ext != fir::SequenceType::getUnknownExtent())
+ extents.push_back(builder.createIntegerConstant(loc, idxTy, ext));
+ else {
+ mlir::Value dimIdx = builder.createIntegerConstant(loc, idxTy, d);
+ auto dimInfo = fir::BoxDimsOp::create(builder, loc, idxTy, idxTy,
+ idxTy, baseVal, dimIdx);
+ extents.push_back(dimInfo.getResult(1));
+ }
+ }
+ if (!extents.empty())
+ shape = builder.genShape(loc, extents);
+ }
+ }
+ mlir::Value empty;
+ mlir::ValueRange emptyRange;
+ return fir::EmboxOp::create(builder, loc, fir::ClassType::get(seqTy),
+ dataAddr, shape, empty, emptyRange);
+}
+
static void genRuntimeAllocateApplyMold(fir::FirOpBuilder &builder,
mlir::Location loc,
const fir::MutableBoxValue &box,
@@ -218,9 +285,14 @@ static void genRuntimeAllocateApplyMold(fir::FirOpBuilder &builder,
builder)
: fir::runtime::getRuntimeFunc<mkRTKey(AllocatableApplyMold)>(
loc, builder);
+ // For IBM vector molds, re-box as fir.class so the descriptor addendum
+ // carries derivedType_, which AllocatableApplyMold copies to the LHS.
+ mlir::Value moldBase = genVectorMoldBox(builder, loc, mold);
+ if (!moldBase)
+ moldBase = fir::getBase(mold);
const auto args = fir::runtime::createArguments(
builder, loc, callee.getFunctionType(),
- fir::factory::getMutableIRBox(builder, loc, box), fir::getBase(mold),
+ fir::factory::getMutableIRBox(builder, loc, box), moldBase,
builder.createIntegerConstant(
loc, callee.getFunctionType().getInputs()[2], rank));
fir::CallOp::create(builder, loc, callee, args);
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index a8e3e4a0aea1a..38eabf6085d4a 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -402,14 +402,31 @@ class TypeInfoConverter {
void createTypeInfoOp(Fortran::lower::AbstractConverter &converter,
const TypeInfo &info) {
+ fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+ fir::TypeInfoOp dt;
+ mlir::OpBuilder::InsertPoint insertPointIfCreated;
+
+ // IBM vector types have no components or bindings; emit a minimal
+ // fir.type_info stub so CodeGen can find the .dt. global when lowering
+ // a fir.class<fir.type<K0K4>> descriptor for same_type_as support.
+ if (info.typeSpec.IsVectorType()) {
+ std::tie(dt, insertPointIfCreated) =
+ builder.createTypeInfoOp(info.loc, info.type,
+ /*parentType=*/fir::RecordType{});
+ if (!insertPointIfCreated.isSet())
+ return;
+ dt->setAttr(dt.getNoInitAttrName(), builder.getUnitAttr());
+ dt->setAttr(dt.getNoDestroyAttrName(), builder.getUnitAttr());
+ dt->setAttr(dt.getNoFinalAttrName(), builder.getUnitAttr());
+ builder.restoreInsertionPoint(insertPointIfCreated);
+ return;
+ }
+
fir::RecordType parentType{};
if (const Fortran::semantics::DerivedTypeSpec *parent =
Fortran::evaluate::GetParentTypeSpec(info.typeSpec))
parentType = mlir::cast<fir::RecordType>(converter.genType(*parent));
- fir::FirOpBuilder &builder = converter.getFirOpBuilder();
- fir::TypeInfoOp dt;
- mlir::OpBuilder::InsertPoint insertPointIfCreated;
std::tie(dt, insertPointIfCreated) =
builder.createTypeInfoOp(info.loc, info.type, parentType);
if (!insertPointIfCreated.isSet())
diff --git a/flang/lib/Lower/ConvertType.cpp b/flang/lib/Lower/ConvertType.cpp
index 0fdbdfcc74424..dd4e8485d48e4 100644
--- a/flang/lib/Lower/ConvertType.cpp
+++ b/flang/lib/Lower/ConvertType.cpp
@@ -383,6 +383,20 @@ struct TypeBuilderImpl {
std::vector<std::pair<std::string, mlir::Type>> ps;
std::vector<std::pair<std::string, mlir::Type>> cs;
if (tySpec.IsVectorType()) {
+ // Register an empty fir.type<> so TypeInfoConverter emits a fir.type_info
+ // stub (see Bridge.cpp). This lets CodeGen resolve the .dt. global when
+ // a vector type appears in a fir.class<> descriptor.
+ if (const Fortran::semantics::Scope *scope = tySpec.GetScope()) {
+ if (const Fortran::semantics::Symbol *typeInfoSym =
+ scope->runtimeDerivedTypeDescription()) {
+ mlir::Location loc =
+ converter.genLocation(tySpec.typeSymbol().name());
+ auto rec = fir::RecordType::get(context, converter.mangleName(tySpec));
+ if (!rec.isFinalized())
+ rec.finalize({}, {}); // empty: no Fortran components, no len params
+ converter.registerTypeInfo(loc, *typeInfoSym, tySpec, rec);
+ }
+ }
return genVectorType(tySpec);
}
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 8a9b511a35420..c3d1e3ad4db55 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -1936,6 +1936,11 @@ struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
auto recTy = mlir::dyn_cast<fir::RecordType>(innerType);
typeDesc =
getTypeDescriptor(mod, rewriter, loc, recTy, this->options);
+ } else if (auto recTy = fir::unwrapIfDerived(boxTy)) {
+ // inputType is not a RecordType (e.g. IBM vector re-boxed as
+ // fir.class<fir.type<K0K4>>); use the record type from boxTy.
+ typeDesc =
+ getTypeDescriptor(mod, rewriter, loc, recTy, this->options);
} else {
// Unlimited polymorphic type descriptor with no record type. Set
// type descriptor address to a clean state.
diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index 8b80f1d60146a..a1426d1fff666 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -584,9 +584,6 @@ int getTypeCode(mlir::Type ty, const fir::KindMapping &kindMap) {
}
if (fir::isa_ref_type(ty))
return CFI_type_cptr;
- // fir::VectorType is the IBM Fortran vector() extension type used as a
- // fir.box element type. Use CFI_type_struct as the accepted fallback
- // for opaque aggregate types in internal descriptors
if (mlir::isa<fir::RecordType, fir::VectorType>(ty))
return CFI_type_struct;
llvm_unreachable("unsupported type");
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index 29c209f4c338e..7ad22838e2d89 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -87,6 +87,48 @@ class AssignOpConversion : public mlir::OpRewritePattern<hlfir::AssignOp> {
fir::StoreOp::create(builder, loc, rhsVal, temp);
rhsExv = temp;
}
+ // For polymorphic LHS with an IBM vector RHS, re-box as
+ // fir.class<fir.type<K0K4>> so CodeGen stores the .dt. global address
+ // into the descriptor addendum (derivedType_). RecordType is looked up
+ // by MLIR-uniqued name (K0K<bytes> for integer, K2K<bytes> for real);
+ // a module walk is not possible as fir.type_info ops are emitted after
+ // the function body.
+ if (lhs.isPolymorphic()) {
+ mlir::Type rhsElemTy = rhs.getFortranElementType();
+ if (auto vecTy = mlir::dyn_cast<fir::VectorType>(rhsElemTy)) {
+ // K-suffix: K0K<bytes> for integer/unsigned, K2K<bytes> for real.
+ mlir::Type eleTy = vecTy.getEleTy();
+ std::string kSuffix;
+ if (auto intTy = mlir::dyn_cast<mlir::IntegerType>(eleTy))
+ kSuffix = "K0K" + std::to_string(intTy.getWidth() / 8);
+ else if (auto floatTy = mlir::dyn_cast<mlir::FloatType>(eleTy))
+ kSuffix = "K2K" + std::to_string(floatTy.getWidth() / 8);
+ if (!kSuffix.empty()) {
+ // RecordType looked up by MLIR-uniqued name.
+ std::string recName =
+ "_QM__ppc_typesT__builtin_ppc_intrinsic_vector" + kSuffix;
+ fir::RecordType recTy =
+ fir::RecordType::get(builder.getContext(), recName);
+ if (recTy) {
+ mlir::Value baseAddr = fir::getBase(rhsExv);
+ mlir::Type rhsSeqTy =
+ fir::unwrapPassByRefType(baseAddr.getType());
+ mlir::Type recSeqTy;
+ if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(rhsSeqTy))
+ recSeqTy = fir::SequenceType::get(seqTy.getShape(), recTy);
+ else
+ recSeqTy = recTy;
+ mlir::Type classTy = fir::ClassType::get(recSeqTy);
+ mlir::Value shape = builder.createShape(loc, rhsExv);
+ mlir::Value empty;
+ mlir::ValueRange emptyRange;
+ return fir::EmboxOp::create(builder, loc, classTy, baseAddr,
+ shape, /*slice=*/empty,
+ /*typeParams=*/emptyRange);
+ }
+ }
+ }
+ }
return fir::getBase(builder.createBox(loc, rhsExv));
};
diff --git a/flang/test/Lower/PowerPC/ppc-vec-same-type-as.f90 b/flang/test/Lower/PowerPC/ppc-vec-same-type-as.f90
new file mode 100644
index 0000000000000..bd47f4d9d7824
--- /dev/null
+++ b/flang/test/Lower/PowerPC/ppc-vec-same-type-as.f90
@@ -0,0 +1,63 @@
+! RUN: %flang -o %t %s && %t
+! REQUIRES: target=powerpc{{.*}}-{{.*}}-aix{{.*}}
+!
+! Test that same_type_as works correctly when a class(*) allocatable holds an
+! IBM vector extension type:
+! - same_type_as(x, x) must be .true. when x is vector(integer(4)) or
+! vector(real(4)) (derivedType_ must be non-null in the descriptor)
+! - same_type_as(x, y) must be .false. when x is vector(integer(4)) and y is
+! vector(real(4)) (distinct types must not compare equal via
+! uninstantiatedType())
+
+subroutine test_allocate_source()
+ vector(integer(4)) :: vi(2)
+ vector(real(4)) :: vr(2)
+ class(*), allocatable :: x(:)
+
+ ! allocate from vector(integer(4))
+ allocate(x(2), source=vi)
+ if (.not. same_type_as(x, x)) error stop "FAIL: allocate vector(integer(4))"
+ deallocate(x)
+
+ ! allocate from vector(real(4))
+ allocate(x(2), source=vr)
+ if (.not. same_type_as(x, x)) error stop "FAIL: allocate vector(real(4))"
+ deallocate(x)
+end subroutine
+
+subroutine test_assign()
+ vector(integer(4)) :: vi(2)
+ vector(real(4)) :: vr(2)
+ class(*), allocatable :: x(:)
+
+ ! allocate first, then assign a different vector type
+ allocate(x(2), source=vi)
+ x = vr
+ if (.not. same_type_as(x, x)) error stop "FAIL: assign vector(real(4))"
+end subroutine
+
+subroutine test_cross_type()
+ vector(integer(4)) :: vi(2)
+ vector(real(4)) :: vr(2)
+ class(*), allocatable :: xi(:), xr(:)
+
+ ! xi holds vector(integer(4)), xr holds vector(real(4)) -- must be .false.
+ allocate(xi(2), source=vi)
+ allocate(xr(2), source=vr)
+ if (same_type_as(xi, xr)) &
+ error stop "FAIL: vector(integer(4)) same_type_as vector(real(4))"
+ if (same_type_as(xr, xi)) &
+ error stop "FAIL: vector(real(4)) same_type_as vector(integer(4))"
+
+ ! Same-type checks must still pass
+ if (.not. same_type_as(xi, xi)) &
+ error stop "FAIL: xi same_type_as xi"
+ if (.not. same_type_as(xr, xr)) &
+ error stop "FAIL: xr same_type_as xr"
+end subroutine
+
+call test_allocate_source()
+call test_assign()
+call test_cross_type()
+print *, "PASS"
+end
>From cbbe3e2fd0fce125958f02fbaaff3253e48a0eda Mon Sep 17 00:00:00 2001
From: Daniel Chen <cdchen at ca.ibm.com>
Date: Sat, 8 Aug 2026 06:27:23 -0400
Subject: [PATCH 3/3] To fix LIT test that AIX does not emit comdat.
---
flang/test/Lower/MIF/coarray_dealloc_not_alloc.f90 | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/flang/test/Lower/MIF/coarray_dealloc_not_alloc.f90 b/flang/test/Lower/MIF/coarray_dealloc_not_alloc.f90
index 5575a411dae14..44e31704c0055 100644
--- a/flang/test/Lower/MIF/coarray_dealloc_not_alloc.f90
+++ b/flang/test/Lower/MIF/coarray_dealloc_not_alloc.f90
@@ -1,6 +1,6 @@
! RUN: %flang_fc1 -emit-llvm -fcoarray %s -o - 2>&1 | FileCheck %s --check-prefix=LLVM
-! LLVM: @_QFB1Ekk_coarray_handle = linkonce global %_QM__fortran_builtinsT__builtin_prif_coarray_handle_type zeroinitializer, comdat
+! LLVM: @_QFB1Ekk_coarray_handle = linkonce global %_QM__fortran_builtinsT__builtin_prif_coarray_handle_type zeroinitializer{{.*}}
! LLVM-LABEL: @_QQmain()
! LLVM: call void @_QMprifPprif_deallocate_coarray(ptr @_QFB1Ekk_coarray_handle, ptr null, ptr null, ptr null)
@@ -11,4 +11,3 @@
allocatable :: kk(:)[:]
endblock
end
-
More information about the flang-commits
mailing list