diff --git a/flang/include/flang/Optimizer/CodeGen/TypeConverter.h b/flang/include/flang/Optimizer/CodeGen/TypeConverter.h index 7c317ddeea1fa..20270d41b1e9a 100644 --- a/flang/include/flang/Optimizer/CodeGen/TypeConverter.h +++ b/flang/include/flang/Optimizer/CodeGen/TypeConverter.h @@ -62,7 +62,7 @@ class LLVMTypeConverter : public mlir::LLVMTypeConverter { // fir.type --> llvm<"%name = { ty... }"> std::optional convertRecordType(fir::RecordType derived, - llvm::SmallVectorImpl &results); + llvm::SmallVectorImpl &results, bool isPacked); // Is an extended descriptor needed given the element type of a fir.box type ? // Extended descriptors are required for derived types. diff --git a/flang/include/flang/Optimizer/Dialect/FIRTypes.td b/flang/include/flang/Optimizer/Dialect/FIRTypes.td index 3919c9191c212..6ae74f16a72d3 100644 --- a/flang/include/flang/Optimizer/Dialect/FIRTypes.td +++ b/flang/include/flang/Optimizer/Dialect/FIRTypes.td @@ -346,6 +346,12 @@ def fir_RecordType : FIR_Type<"Record", "type"> { void finalize(llvm::ArrayRef lenPList, llvm::ArrayRef typeList); + // fir.type is unpacked by default. If the flag is set, the packed fir.type + // is generated and the alignment is enforced by explicit padding by i8 + // array fields. + bool isPacked() const; + void pack(bool); + detail::RecordTypeStorage const *uniqueKey() const; }]; } diff --git a/flang/lib/Lower/ConvertType.cpp b/flang/lib/Lower/ConvertType.cpp index 452ddda426fa1..31b85ef2b5476 100644 --- a/flang/lib/Lower/ConvertType.cpp +++ b/flang/lib/Lower/ConvertType.cpp @@ -20,6 +20,8 @@ #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinTypes.h" #include "llvm/Support/Debug.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/Triple.h" #define DEBUG_TYPE "flang-lower-type" @@ -385,9 +387,20 @@ struct TypeBuilderImpl { // with dozens of components/parents (modern Fortran). derivedTypeInConstruction.try_emplace(&derivedScope, rec); + auto targetTriple{llvm::Triple( + llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()))}; + // Always generate packed FIR struct type for bind(c) derived type for AIX + if (targetTriple.getOS() == llvm::Triple::OSType::AIX && + tySpec.typeSymbol().attrs().test(Fortran::semantics::Attr::BIND_C) && + !IsIsoCType(&tySpec)) { + rec.pack(true); + } + // Gather the record type fields. // (1) The data components. if (converter.getLoweringOptions().getLowerToHighLevelFIR()) { + size_t prev_offset{0}; + unsigned padCounter{0}; // In HLFIR the parent component is the first fir.type component. for (const auto &componentName : typeSymbol.get() @@ -397,7 +410,38 @@ struct TypeBuilderImpl { "failed to find derived type component symbol"); const Fortran::semantics::Symbol &component = scopeIter->second.get(); mlir::Type ty = genSymbolType(component); + if (rec.isPacked()) { + auto compSize{component.size()}; + auto compOffset{component.offset()}; + + if (prev_offset < compOffset) { + size_t pad{compOffset - prev_offset}; + mlir::Type i8Ty{mlir::IntegerType::get(context, 8)}; + fir::SequenceType::Shape shape{static_cast(pad)}; + mlir::Type padTy{fir::SequenceType::get(shape, i8Ty)}; + prev_offset += pad; + cs.emplace_back("__padding" + std::to_string(padCounter++), padTy); + } + prev_offset += compSize; + } cs.emplace_back(converter.getRecordTypeFieldName(component), ty); + if (rec.isPacked()) { + // For the last component, determine if any padding is needed. + if (componentName == + typeSymbol.get() + .componentNames() + .back()) { + auto compEnd{component.offset() + component.size()}; + if (compEnd < derivedScope.size()) { + size_t pad{derivedScope.size() - compEnd}; + mlir::Type i8Ty{mlir::IntegerType::get(context, 8)}; + fir::SequenceType::Shape shape{static_cast(pad)}; + mlir::Type padTy{fir::SequenceType::get(shape, i8Ty)}; + cs.emplace_back("__padding" + std::to_string(padCounter++), + padTy); + } + } + } } } else { for (const auto &component : diff --git a/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp b/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp index 1bb91d252529f..a601af1182c38 100644 --- a/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp +++ b/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp @@ -167,6 +167,7 @@ class BoxprocTypeRewriter : public mlir::TypeConverter { cs.emplace_back(t.first, t.second); } rec.finalize(ps, cs); + rec.pack(ty.isPacked()); return rec; }); addConversion([&](TypeDescType ty) { diff --git a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp index c23203efcd3df..0eace903720f0 100644 --- a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp +++ b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp @@ -82,7 +82,7 @@ LLVMTypeConverter::LLVMTypeConverter(mlir::ModuleOp module, bool applyTBAA, [&](fir::PointerType pointer) { return convertPointerLike(pointer); }); addConversion( [&](fir::RecordType derived, llvm::SmallVectorImpl &results) { - return convertRecordType(derived, results); + return convertRecordType(derived, results, derived.isPacked()); }); addConversion( [&](fir::ReferenceType ref) { return convertPointerLike(ref); }); @@ -133,8 +133,10 @@ mlir::Type LLVMTypeConverter::indexType() const { } // fir.type --> llvm<"%name = { ty... }"> -std::optional LLVMTypeConverter::convertRecordType( - fir::RecordType derived, llvm::SmallVectorImpl &results) { +std::optional +LLVMTypeConverter::convertRecordType(fir::RecordType derived, + llvm::SmallVectorImpl &results, + bool isPacked) { auto name = fir::NameUniquer::dropTypeConversionMarkers(derived.getName()); auto st = mlir::LLVM::LLVMStructType::getIdentified(&getContext(), name); @@ -156,7 +158,7 @@ std::optional LLVMTypeConverter::convertRecordType( else members.push_back(mlir::cast(convertType(mem.second))); } - if (mlir::failed(st.setBody(members, /*isPacked=*/false))) + if (mlir::failed(st.setBody(members, isPacked))) return mlir::failure(); results.push_back(st); return mlir::success(); diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp index cba7fa6412850..d25e5651f1142 100644 --- a/flang/lib/Optimizer/Dialect/FIRType.cpp +++ b/flang/lib/Optimizer/Dialect/FIRType.cpp @@ -165,16 +165,20 @@ struct RecordTypeStorage : public mlir::TypeStorage { setTypeList(typeList); } + bool isPacked() const { return packed; } + void pack(bool p) { packed = p; } + protected: std::string name; bool finalized; + bool packed; std::vector lens; std::vector types; private: RecordTypeStorage() = delete; explicit RecordTypeStorage(llvm::StringRef name) - : name{name}, finalized{false} {} + : name{name}, finalized{false}, packed{false} {} }; } // namespace detail @@ -872,9 +876,14 @@ llvm::LogicalResult fir::PointerType::verify( //===----------------------------------------------------------------------===// // Fortran derived type +// unpacked: // `type` `<` name // (`(` id `:` type (`,` id `:` type)* `)`)? // (`{` id `:` type (`,` id `:` type)* `}`)? '>' +// packed: +// `type` `<` name +// (`(` id `:` type (`,` id `:` type)* `)`)? +// (`<{` id `:` type (`,` id `:` type)* `}>`)? '>' mlir::Type fir::RecordType::parse(mlir::AsmParser &parser) { llvm::StringRef name; if (parser.parseLess() || parser.parseKeyword(&name)) @@ -900,6 +909,10 @@ mlir::Type fir::RecordType::parse(mlir::AsmParser &parser) { } RecordType::TypeList typeList; + if (!parser.parseOptionalLess()) { + result.pack(true); + } + if (!parser.parseOptionalLBrace()) { while (true) { llvm::StringRef field; @@ -913,8 +926,10 @@ mlir::Type fir::RecordType::parse(mlir::AsmParser &parser) { if (parser.parseOptionalComma()) break; } - if (parser.parseRBrace()) - return {}; + if (parser.parseOptionalGreater()) { + if (parser.parseRBrace()) + return {}; + } } if (parser.parseGreater()) @@ -941,6 +956,9 @@ void fir::RecordType::print(mlir::AsmPrinter &printer) const { printer << ')'; } if (getTypeList().size()) { + if (isPacked()) { + printer << '<'; + } char ch = '{'; for (auto p : getTypeList()) { printer << ch << p.first << ':'; @@ -948,6 +966,9 @@ void fir::RecordType::print(mlir::AsmPrinter &printer) const { ch = ','; } printer << '}'; + if (isPacked()) { + printer << '>'; + } } recordTypeVisited.erase(uniqueKey()); } @@ -973,6 +994,10 @@ RecordType::TypeList fir::RecordType::getLenParamList() const { bool fir::RecordType::isFinalized() const { return getImpl()->isFinalized(); } +void fir::RecordType::pack(bool p) { getImpl()->pack(p); } + +bool fir::RecordType::isPacked() const { return getImpl()->isPacked(); } + detail::RecordTypeStorage const *fir::RecordType::uniqueKey() const { return getImpl(); } diff --git a/flang/lib/Semantics/compute-offsets.cpp b/flang/lib/Semantics/compute-offsets.cpp index 94640fa30baa5..6d4fce2f00a6d 100644 --- a/flang/lib/Semantics/compute-offsets.cpp +++ b/flang/lib/Semantics/compute-offsets.cpp @@ -17,6 +17,8 @@ #include "flang/Semantics/symbol.h" #include "flang/Semantics/tools.h" #include "flang/Semantics/type.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/Triple.h" #include #include @@ -51,9 +53,12 @@ class ComputeOffsetsHelper { SymbolAndOffset Resolve(const SymbolAndOffset &); std::size_t ComputeOffset(const EquivalenceObject &); // Returns amount of padding that was needed for alignment - std::size_t DoSymbol(Symbol &); + std::size_t DoSymbol( + Symbol &, std::optional newAlign = std::nullopt); SizeAndAlignment GetSizeAndAlignment(const Symbol &, bool entire); std::size_t Align(std::size_t, std::size_t); + std::optional CompAlignment(const Symbol &); + std::optional HasSpecialAlign(const Symbol &, Scope &); SemanticsContext &context_; std::size_t offset_{0}; @@ -65,6 +70,69 @@ class ComputeOffsetsHelper { equivalenceBlock_; }; +// This function is only called if the target platform is AIX. +static bool isReal8OrLarger(const Fortran::semantics::DeclTypeSpec *type) { + return ((type->IsNumeric(common::TypeCategory::Real) || + type->IsNumeric(common::TypeCategory::Complex)) && + evaluate::ToInt64(type->numericTypeSpec().kind()) > 4); +} + +// This function is only called if the target platform is AIX. +// It determines the alignment of a component. If the component is a derived +// type, the alignment is computed accordingly. +std::optional ComputeOffsetsHelper::CompAlignment(const Symbol &sym) { + size_t max_align{0}; + constexpr size_t fourByteAlign{4}; + bool contain_double{false}; + auto derivedTypeSpec{sym.GetType()->AsDerived()}; + DirectComponentIterator directs{*derivedTypeSpec}; + for (auto it{directs.begin()}; it != directs.end(); ++it) { + auto type{it->GetType()}; + auto s{GetSizeAndAlignment(*it, true)}; + if (isReal8OrLarger(type)) { + max_align = std::max(max_align, fourByteAlign); + contain_double = true; + } else if (type->AsDerived()) { + if (const auto newAlgin{CompAlignment(*it)}) { + max_align = std::max(max_align, s.alignment); + } else { + return std::nullopt; + } + } else { + max_align = std::max(max_align, s.alignment); + } + } + + if (contain_double) { + return max_align; + } else { + return std::nullopt; + } +} + +// This function is only called if the target platform is AIX. +// Special alignment is needed only if it is a bind(c) derived type +// and contain real type components that have larger than 4 bytes. +std::optional ComputeOffsetsHelper::HasSpecialAlign( + const Symbol &sym, Scope &scope) { + // On AIX, if the component that is not the first component and is + // a float of 8 bytes or larger, it has the 4-byte alignment. + // Only set the special alignment for bind(c) derived type on that platform. + if (const auto type{sym.GetType()}) { + auto &symOwner{sym.owner()}; + if (symOwner.symbol() && symOwner.IsDerivedType() && + symOwner.symbol()->attrs().HasAny({semantics::Attr::BIND_C}) && + &sym != &(*scope.GetSymbols().front())) { + if (isReal8OrLarger(type)) { + return 4UL; + } else if (type->AsDerived()) { + return CompAlignment(sym); + } + } + } + return std::nullopt; +} + void ComputeOffsetsHelper::Compute(Scope &scope) { for (Scope &child : scope.children()) { ComputeOffsets(context_, child); @@ -113,7 +181,15 @@ void ComputeOffsetsHelper::Compute(Scope &scope) { if (!FindCommonBlockContaining(*symbol) && dependents_.find(symbol) == dependents_.end() && equivalenceBlock_.find(symbol) == equivalenceBlock_.end()) { - DoSymbol(*symbol); + + std::optional newAlign{std::nullopt}; + // Handle special alignment requirement for AIX + auto triple{llvm::Triple( + llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()))}; + if (triple.getOS() == llvm::Triple::OSType::AIX) { + newAlign = HasSpecialAlign(*symbol, scope); + } + DoSymbol(*symbol, newAlign); if (auto *generic{symbol->detailsIf()}) { if (Symbol * specific{generic->specific()}; specific && !FindCommonBlockContaining(*specific)) { @@ -313,7 +389,8 @@ std::size_t ComputeOffsetsHelper::ComputeOffset( return result; } -std::size_t ComputeOffsetsHelper::DoSymbol(Symbol &symbol) { +std::size_t ComputeOffsetsHelper::DoSymbol( + Symbol &symbol, std::optional newAlign) { if (!symbol.has() && !symbol.has()) { return 0; } @@ -322,12 +399,13 @@ std::size_t ComputeOffsetsHelper::DoSymbol(Symbol &symbol) { return 0; } std::size_t previousOffset{offset_}; - offset_ = Align(offset_, s.alignment); + size_t alignVal{newAlign.value_or(s.alignment)}; + offset_ = Align(offset_, alignVal); std::size_t padding{offset_ - previousOffset}; symbol.set_size(s.size); symbol.set_offset(offset_); offset_ += s.size; - alignment_ = std::max(alignment_, s.alignment); + alignment_ = std::max(alignment_, alignVal); return padding; } diff --git a/flang/test/Lower/CUDA/cuda-devptr.cuf b/flang/test/Lower/CUDA/cuda-devptr.cuf index 2eac890970d52..561d92ecd3e2e 100644 --- a/flang/test/Lower/CUDA/cuda-devptr.cuf +++ b/flang/test/Lower/CUDA/cuda-devptr.cuf @@ -38,8 +38,8 @@ end ! CHECK-LABEL: func.func @_QPsub2() ! CHECK: %[[X:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda, fortran_attrs = #fir.var_attrs, uniq_name = "_QFsub2Ex"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) -! CHECK: %[[CPTR:.*]] = fir.field_index cptr, !fir.type<_QM__fortran_builtinsT__builtin_c_devptr{cptr:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}> -! CHECK: %[[CPTR_COORD:.*]] = fir.coordinate_of %{{.*}}#1, %[[CPTR]] : (!fir.ref}>>, !fir.field) -> !fir.ref> +! CHECK: %[[CPTR:.*]] = fir.field_index cptr, !fir.type<_QM__fortran_builtinsT__builtin_c_devptr{{[<]?}}{cptr:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}{{[>]?}}> +! CHECK: %[[CPTR_COORD:.*]] = fir.coordinate_of %{{.*}}#1, %[[CPTR]] : (!fir.ref}{{[>]?}}>>, !fir.field) -> !fir.ref> ! CHECK: %[[ADDRESS:.*]] = fir.field_index __address, !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}> ! CHECK: %[[ADDRESS_COORD:.*]] = fir.coordinate_of %[[CPTR_COORD]], %[[ADDRESS]] : (!fir.ref>, !fir.field) -> !fir.ref ! CHECK: %[[ADDRESS_LOADED:.*]] = fir.load %[[ADDRESS_COORD]] : !fir.ref diff --git a/flang/test/Lower/HLFIR/bindc-value-derived.f90 b/flang/test/Lower/HLFIR/bindc-value-derived.f90 index 7a2196dfc8bf1..5af9f8edc804c 100644 --- a/flang/test/Lower/HLFIR/bindc-value-derived.f90 +++ b/flang/test/Lower/HLFIR/bindc-value-derived.f90 @@ -14,11 +14,11 @@ subroutine test(x) bind(c) call use_it(x%i) end subroutine ! CHECK-LABEL: func.func @test( -! CHECK-SAME: %[[VAL_0:.*]]: !fir.type<_QMbindc_byvalTt{i:i32}> -! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.type<_QMbindc_byvalTt{i:i32}> -! CHECK: fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref> -! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] dummy_scope %{{[0-9]+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QMbindc_byvalFtestEx"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) -! CHECK: %[[VAL_3:.*]] = hlfir.designate %[[VAL_2]]#0{"i"} : (!fir.ref>) -> !fir.ref +! CHECK-SAME: %[[VAL_0:.*]]: !fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}> +! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}> +! CHECK: fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref]?}}>> +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] dummy_scope %{{[0-9]}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QMbindc_byvalFtestEx"} : (!fir.ref]?}}>>, !fir.dscope) -> (!fir.ref]?}}>>, !fir.ref]?}}>>) +! CHECK: %[[VAL_3:.*]] = hlfir.designate %[[VAL_2]]#0{"i"} : (!fir.ref]?}}>>) -> !fir.ref ! CHECK: fir.call @_QPuse_it(%[[VAL_3]]) fastmath : (!fir.ref) -> () ! CHECK: return ! CHECK: } @@ -28,10 +28,10 @@ subroutine call_it(x) call test(x) end subroutine ! CHECK-LABEL: func.func @_QMbindc_byvalPcall_it( -! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> -! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %{{[0-9]+}} {uniq_name = "_QMbindc_byvalFcall_itEx"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) -! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#1 : !fir.ref> -! CHECK: fir.call @test(%[[VAL_2]]) proc_attrs fastmath : (!fir.type<_QMbindc_byvalTt{i:i32}>) -> () +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref]?}}>> +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %{{[0-9]}} {uniq_name = "_QMbindc_byvalFcall_itEx"} : (!fir.ref]?}}>>, !fir.dscope) -> (!fir.ref]?}}>>, !fir.ref]?}}>>) +! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#1 : !fir.ref]?}}>> +! CHECK: fir.call @test(%[[VAL_2]]) proc_attrs fastmath : (!fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}>) -> () ! CHECK: return ! CHECK: } end module diff --git a/flang/test/Lower/OpenMP/copyin.f90 b/flang/test/Lower/OpenMP/copyin.f90 index f3d147c10668f..9e9ccf8e3d914 100644 --- a/flang/test/Lower/OpenMP/copyin.f90 +++ b/flang/test/Lower/OpenMP/copyin.f90 @@ -86,7 +86,7 @@ subroutine copyin_char_chararray() end ! CHECK-LABEL: func.func @_QPcopyin_derived_type() { -! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QFcopyin_derived_typeE.b.my_type.t_arr) : !fir.ref,value:i64}>>> +! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QFcopyin_derived_typeE.b.my_type.t_arr) : !fir.ref,value:i64}{{[>]?}}>>> ! CHECK: %[[VAL_1:.*]] = arith.constant 0 : index ! CHECK: %[[VAL_2:.*]] = arith.constant 2 : index ! CHECK: %[[VAL_3:.*]] = arith.constant 0 : index diff --git a/flang/test/Lower/derived-types-bindc.f90 b/flang/test/Lower/derived-types-bindc.f90 new file mode 100644 index 0000000000000..309b2b7f5f492 --- /dev/null +++ b/flang/test/Lower/derived-types-bindc.f90 @@ -0,0 +1,44 @@ +! Test padding for BIND(C) derived types lowering for AIX target +! RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s + +! REQUIRES: target={{.+}}-aix{{.*}} + +subroutine s1() + use, intrinsic :: iso_c_binding + type, bind(c) :: t0 + character(c_char) :: x1 + real(c_double) :: x2 + end type + type(t0) :: xt0 +! CHECK-DAG: %_QFs1Tt0 = type <{ [1 x i8], [3 x i8], double }> + + type, bind(c) :: t1 + integer(c_short) :: x1 + real(c_double) :: x2 + end type + type(t1) :: xt1 +! CHECK-DAG: %_QFs1Tt1 = type <{ i16, [2 x i8], double }> + + type, bind(c) :: t2 + integer(c_short) :: x1 + real(c_double) :: x2 + character(c_char) :: x3 + end type + type(t2) :: xt2 +! CHECK-DAG: %_QFs1Tt2 = type <{ i16, [2 x i8], double, [1 x i8], [3 x i8] }> + + type, bind(c) :: t3 + character(c_char) :: x1 + complex(c_double_complex) :: x2 + end type + type(t3) :: xt3 +! CHECK-DAG: %_QFs1Tt3 = type <{ [1 x i8], [3 x i8], { double, double } }> + + type, bind(c) :: t4 + integer(c_short) :: x1 + complex(c_double_complex) :: x2 + character(c_char) :: x3 + end type + type(t4) :: xt4 +! CHECK-DAG: %_QFs1Tt4 = type <{ i16, [2 x i8], { double, double }, [1 x i8], [3 x i8] }> +end subroutine s1 diff --git a/flang/test/Lower/intentout-deallocate.f90 b/flang/test/Lower/intentout-deallocate.f90 index 8e7ccbcc9fdb9..931cf7d48885f 100644 --- a/flang/test/Lower/intentout-deallocate.f90 +++ b/flang/test/Lower/intentout-deallocate.f90 @@ -123,24 +123,24 @@ subroutine sub5(t) ! on the caller side. ! CHECK-LABEL: func.func @_QMmod1Psub4() -! FIR: %[[BOX:.*]] = fir.alloca !fir.box>> {bindc_name = "t", uniq_name = "_QMmod1Fsub4Et"} +! FIR: %[[BOX:.*]] = fir.alloca !fir.box]?}}>>> {bindc_name = "t", uniq_name = "_QMmod1Fsub4Et"} ! HLFIR: %[[BOX:.*]]:2 = hlfir.declare {{.*}}"_QMmod1Fsub4Et" ! CHECK-NOT: fir.call @_FortranAAllocatableDeallocate -! CHECK: fir.call @_QMmod1Psub5(%[[BOX]]{{[#0]*}}) {{.*}}: (!fir.ref>>>) -> () +! CHECK: fir.call @_QMmod1Psub5(%[[BOX]]{{[#0]*}}) {{.*}}: (!fir.ref]?}}>>>>) -> () ! Check deallocation of allocatble intent(out) on the callee side. Deallocation ! is done with a runtime call. ! CHECK-LABEL: func.func @_QMmod1Psub5( -! FIR-SAME: %[[ARG0:.*]]: !fir.ref>>> {fir.bindc_name = "t"}) +! FIR-SAME: %[[ARG0:.*]]: !fir.ref]?}}>>>> {fir.bindc_name = "t"}) ! HLFIR: %[[ARG0:.*]]:2 = hlfir.declare {{.*}}"_QMmod1Fsub5Et" -! CHECK: %[[BOX:.*]] = fir.load %[[ARG0]]{{[#1]*}} : !fir.ref>>> -! CHECK: %[[BOX_ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box>>) -> !fir.heap> -! CHECK: %[[BOX_ADDR_PTR:.*]] = fir.convert %[[BOX_ADDR]] : (!fir.heap>) -> i64 +! CHECK: %[[BOX:.*]] = fir.load %[[ARG0]]{{[#1]*}} : !fir.ref]?}}>>>> +! CHECK: %[[BOX_ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box]?}}>>>) -> !fir.heap]?}}>> +! CHECK: %[[BOX_ADDR_PTR:.*]] = fir.convert %[[BOX_ADDR]] : (!fir.heap]?}}>>) -> i64 ! CHECK: %[[C0:.*]] = arith.constant 0 : i64 ! CHECK: %[[IS_ALLOCATED:.*]] = arith.cmpi ne, %[[BOX_ADDR_PTR]], %[[C0]] : i64 ! CHECK: fir.if %[[IS_ALLOCATED]] { -! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]]{{[#1]*}} : (!fir.ref>>>) -> !fir.ref> +! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]]{{[#1]*}} : (!fir.ref]?}}>>>>) -> !fir.ref> ! CHECK: %{{.*}} = fir.call @_FortranAAllocatableDeallocate(%[[BOX_NONE]], %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 subroutine sub6() @@ -152,11 +152,11 @@ subroutine sub6() ! Deallocation is done with a runtime call. ! CHECK-LABEL: func.func @_QMmod1Psub6() -! FIR: %[[BOX:.*]] = fir.alloca !fir.box>> {bindc_name = "t", uniq_name = "_QMmod1Fsub6Et"} +! FIR: %[[BOX:.*]] = fir.alloca !fir.box]?}}>>> {bindc_name = "t", uniq_name = "_QMmod1Fsub6Et"} ! HLFIR: %[[BOX:.*]]:2 = hlfir.declare {{.*}}"_QMmod1Fsub6Et" -! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[BOX]]{{[#1]*}} : (!fir.ref>>>) -> !fir.ref> +! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[BOX]]{{[#1]*}} : (!fir.ref]?}}>>>>) -> !fir.ref> ! CHECK: %{{.*}} = fir.call @_FortranAAllocatableDeallocate(%[[BOX_NONE]], %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 -! CHECK: fir.call @sub7(%[[BOX]]{{[#0]*}}) {{.*}}: (!fir.ref>>>) -> () +! CHECK: fir.call @sub7(%[[BOX]]{{[#0]*}}) {{.*}}: (!fir.ref]?}}>>>>) -> () subroutine sub8() integer, allocatable :: a(:) diff --git a/flang/test/Semantics/offsets04.f90 b/flang/test/Semantics/offsets04.f90 new file mode 100644 index 0000000000000..d0d871a981c17 --- /dev/null +++ b/flang/test/Semantics/offsets04.f90 @@ -0,0 +1,105 @@ +!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s + +!REQUIRES: target={{.+}}-aix{{.*}} + +! Size and alignment of bind(c) derived types +subroutine s1() + use, intrinsic :: iso_c_binding + type, bind(c) :: dt1 + character(c_char) :: x1 !CHECK: x1 size=1 offset=0: + real(c_double) :: x2 !CHECK: x2 size=8 offset=4: + end type + type, bind(c) :: dt2 + character(c_char) :: x1(9) !CHECK: x1 size=9 offset=0: + real(c_double) :: x2 !CHECK: x2 size=8 offset=12: + end type + type, bind(c) :: dt3 + integer(c_short) :: x1 !CHECK: x1 size=2 offset=0: + real(c_double) :: x2 !CHECK: x2 size=8 offset=4: + end type + type, bind(c) :: dt4 + integer(c_int) :: x1 !CHECK: x1 size=4 offset=0: + real(c_double) :: x2 !CHECK: x2 size=8 offset=4: + end type + type, bind(c) :: dt5 + real(c_double) :: x1 !CHECK: x1 size=8 offset=0: + real(c_double) :: x2 !CHECK: x2 size=8 offset=8: + end type + type, bind(c) :: dt6 + integer(c_long) :: x1 !CHECK: x1 size=8 offset=0: + character(c_char) :: x2 !CHECK: x2 size=1 offset=8: + real(c_double) :: x3 !CHECK: x3 size=8 offset=12: + end type + type, bind(c) :: dt7 + integer(c_long) :: x1 !CHECK: x1 size=8 offset=0: + integer(c_long) :: x2 !CHECK: x2 size=8 offset=8: + character(c_char) :: x3 !CHECK: x3 size=1 offset=16: + real(c_double) :: x4 !CHECK: x4 size=8 offset=20: + end type + type, bind(c) :: dt8 + character(c_char) :: x1 !CHECK: x1 size=1 offset=0: + complex(c_double_complex) :: x2 !CHECK: x2 size=16 offset=4: + end type +end subroutine + +subroutine s2() + use, intrinsic :: iso_c_binding + type, bind(c) :: dt10 + character(c_char) :: x1 + real(c_double) :: x2 + end type + type, bind(c) :: dt11 + type(dt10) :: y1 !CHECK: y1 size=12 offset=0: + real(c_double) :: y2 !CHECK: y2 size=8 offset=12: + end type + type, bind(c) :: dt12 + character(c_char) :: y1 !CHECK: y1 size=1 offset=0: + type(dt10) :: y2 !CHECK: y2 size=12 offset=4: + character(c_char) :: y3 !CHECK: y3 size=1 offset=16: + end type + type, bind(c) :: dt13 + integer(c_short) :: y1 !CHECK: y1 size=2 offset=0: + type(dt10) :: y2 !CHECK: y2 size=12 offset=4: + character(c_char) :: y3 !CHECK: y3 size=1 offset=16: + end type + + type, bind(c) :: dt20 + character(c_char) :: x1 + integer(c_short) :: x2 + end type + type, bind(c) :: dt21 + real(c_double) :: y1 !CHECK: y1 size=8 offset=0: + type(dt20) :: y2 !CHECK: y2 size=4 offset=8: + real(c_double) :: y3 !CHECK: y3 size=8 offset=12: + end type + + type, bind(c) :: dt30 + character(c_char) :: x1 + character(c_char) :: x2 + end type + type, bind(c) :: dt31 + integer(c_long) :: y1 !CHECK: y1 size=8 offset=0: + type(dt30) :: y2 !CHECK: y2 size=2 offset=8: + real(c_double) :: y3 !CHECK: y3 size=8 offset=12: + end type + + type, bind(c) :: dt40 + integer(c_short) :: x1 + real(c_double) :: x2 + end type + type, bind(c) :: dt41 + real(c_double) :: y1 !CHECK: y1 size=8 offset=0: + type(dt40) :: y2 !CHECK: y2 size=12 offset=8: + real(c_double) :: y3 !CHECK: y3 size=8 offset=20: + end type + + type, bind(c) :: dt50 + integer(c_short) :: x1 + complex(c_double_complex) :: x2 + end type + type, bind(c) :: dt51 + real(c_double) :: y1 !CHECK: y1 size=8 offset=0: + type(dt50) :: y2 !CHECK: y2 size=20 offset=8: + complex(c_double_complex) :: y3 !CHECK: y3 size=16 offset=28: + end type +end subroutine