mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 19:56:38 +00:00
[flang][AIX] BIND(C) derived type alignment for AIX (#121505)
This patch is to handle the alignment requirement for the `bind(c)` derived type component that is real type and larger than 4 bytes. The alignment of such component is 4-byte.
This commit is contained in:
parent
e2c49a45da
commit
79e788d02e
@ -62,7 +62,7 @@ public:
|
||||
// fir.type<name(p : TY'...){f : TY...}> --> llvm<"%name = { ty... }">
|
||||
std::optional<llvm::LogicalResult>
|
||||
convertRecordType(fir::RecordType derived,
|
||||
llvm::SmallVectorImpl<mlir::Type> &results);
|
||||
llvm::SmallVectorImpl<mlir::Type> &results, bool isPacked);
|
||||
|
||||
// Is an extended descriptor needed given the element type of a fir.box type ?
|
||||
// Extended descriptors are required for derived types.
|
||||
|
@ -346,6 +346,12 @@ def fir_RecordType : FIR_Type<"Record", "type"> {
|
||||
void finalize(llvm::ArrayRef<TypePair> lenPList,
|
||||
llvm::ArrayRef<TypePair> 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;
|
||||
}];
|
||||
}
|
||||
|
@ -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<Fortran::semantics::DerivedTypeDetails>()
|
||||
@ -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<int64_t>(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<Fortran::semantics::DerivedTypeDetails>()
|
||||
.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<int64_t>(pad)};
|
||||
mlir::Type padTy{fir::SequenceType::get(shape, i8Ty)};
|
||||
cs.emplace_back("__padding" + std::to_string(padCounter++),
|
||||
padTy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const auto &component :
|
||||
|
@ -167,6 +167,7 @@ public:
|
||||
cs.emplace_back(t.first, t.second);
|
||||
}
|
||||
rec.finalize(ps, cs);
|
||||
rec.pack(ty.isPacked());
|
||||
return rec;
|
||||
});
|
||||
addConversion([&](TypeDescType ty) {
|
||||
|
@ -82,7 +82,7 @@ LLVMTypeConverter::LLVMTypeConverter(mlir::ModuleOp module, bool applyTBAA,
|
||||
[&](fir::PointerType pointer) { return convertPointerLike(pointer); });
|
||||
addConversion(
|
||||
[&](fir::RecordType derived, llvm::SmallVectorImpl<mlir::Type> &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<name(p : TY'...){f : TY...}> --> llvm<"%name = { ty... }">
|
||||
std::optional<llvm::LogicalResult> LLVMTypeConverter::convertRecordType(
|
||||
fir::RecordType derived, llvm::SmallVectorImpl<mlir::Type> &results) {
|
||||
std::optional<llvm::LogicalResult>
|
||||
LLVMTypeConverter::convertRecordType(fir::RecordType derived,
|
||||
llvm::SmallVectorImpl<mlir::Type> &results,
|
||||
bool isPacked) {
|
||||
auto name = fir::NameUniquer::dropTypeConversionMarkers(derived.getName());
|
||||
auto st = mlir::LLVM::LLVMStructType::getIdentified(&getContext(), name);
|
||||
|
||||
@ -156,7 +158,7 @@ std::optional<llvm::LogicalResult> LLVMTypeConverter::convertRecordType(
|
||||
else
|
||||
members.push_back(mlir::cast<mlir::Type>(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();
|
||||
|
@ -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<RecordType::TypePair> lens;
|
||||
std::vector<RecordType::TypePair> 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();
|
||||
}
|
||||
|
@ -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 <algorithm>
|
||||
#include <vector>
|
||||
|
||||
@ -51,9 +53,12 @@ private:
|
||||
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<const size_t> newAlign = std::nullopt);
|
||||
SizeAndAlignment GetSizeAndAlignment(const Symbol &, bool entire);
|
||||
std::size_t Align(std::size_t, std::size_t);
|
||||
std::optional<size_t> CompAlignment(const Symbol &);
|
||||
std::optional<size_t> HasSpecialAlign(const Symbol &, Scope &);
|
||||
|
||||
SemanticsContext &context_;
|
||||
std::size_t offset_{0};
|
||||
@ -65,6 +70,69 @@ private:
|
||||
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<size_t> 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<size_t> 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<size_t> 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<GenericDetails>()}) {
|
||||
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<const size_t> newAlign) {
|
||||
if (!symbol.has<ObjectEntityDetails>() && !symbol.has<ProcEntityDetails>()) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -38,8 +38,8 @@ end
|
||||
|
||||
! CHECK-LABEL: func.func @_QPsub2()
|
||||
! CHECK: %[[X:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFsub2Ex"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>)
|
||||
! 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.type<_QM__fortran_builtinsT__builtin_c_devptr{cptr:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>, !fir.field) -> !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>
|
||||
! 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.type<_QM__fortran_builtinsT__builtin_c_devptr{{[<]?}}{cptr:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}{{[>]?}}>>, !fir.field) -> !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>
|
||||
! 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.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.field) -> !fir.ref<i64>
|
||||
! CHECK: %[[ADDRESS_LOADED:.*]] = fir.load %[[ADDRESS_COORD]] : !fir.ref<i64>
|
||||
|
@ -14,11 +14,11 @@ contains
|
||||
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<!fir.type<_QMbindc_byvalTt{i:i32}>>
|
||||
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] dummy_scope %{{[0-9]+}} {fortran_attrs = #fir.var_attrs<value>, uniq_name = "_QMbindc_byvalFtestEx"} : (!fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>, !fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>)
|
||||
! CHECK: %[[VAL_3:.*]] = hlfir.designate %[[VAL_2]]#0{"i"} : (!fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>) -> !fir.ref<i32>
|
||||
! 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<!fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}>>
|
||||
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] dummy_scope %{{[0-9]}} {fortran_attrs = #fir.var_attrs<value>, uniq_name = "_QMbindc_byvalFtestEx"} : (!fir.ref<!fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}>>, !fir.ref<!fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}>>)
|
||||
! CHECK: %[[VAL_3:.*]] = hlfir.designate %[[VAL_2]]#0{"i"} : (!fir.ref<!fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}>>) -> !fir.ref<i32>
|
||||
! CHECK: fir.call @_QPuse_it(%[[VAL_3]]) fastmath<contract> : (!fir.ref<i32>) -> ()
|
||||
! CHECK: return
|
||||
! CHECK: }
|
||||
@ -28,10 +28,10 @@ contains
|
||||
call test(x)
|
||||
end subroutine
|
||||
! CHECK-LABEL: func.func @_QMbindc_byvalPcall_it(
|
||||
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>
|
||||
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %{{[0-9]+}} {uniq_name = "_QMbindc_byvalFcall_itEx"} : (!fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>, !fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>)
|
||||
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#1 : !fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>
|
||||
! CHECK: fir.call @test(%[[VAL_2]]) proc_attrs<bind_c> fastmath<contract> : (!fir.type<_QMbindc_byvalTt{i:i32}>) -> ()
|
||||
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}>>
|
||||
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %{{[0-9]}} {uniq_name = "_QMbindc_byvalFcall_itEx"} : (!fir.ref<!fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}>>, !fir.ref<!fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}>>)
|
||||
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#1 : !fir.ref<!fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}>>
|
||||
! CHECK: fir.call @test(%[[VAL_2]]) proc_attrs<bind_c> fastmath<contract> : (!fir.type<_QMbindc_byvalTt{{[<]?}}{i:i32}{{[>]?}}>) -> ()
|
||||
! CHECK: return
|
||||
! CHECK: }
|
||||
end module
|
||||
|
@ -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<!fir.array<2x1x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>
|
||||
! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QFcopyin_derived_typeE.b.my_type.t_arr) : !fir.ref<!fir.array<2x1x!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>>>
|
||||
! CHECK: %[[VAL_1:.*]] = arith.constant 0 : index
|
||||
! CHECK: %[[VAL_2:.*]] = arith.constant 2 : index
|
||||
! CHECK: %[[VAL_3:.*]] = arith.constant 0 : index
|
||||
|
44
flang/test/Lower/derived-types-bindc.f90
Normal file
44
flang/test/Lower/derived-types-bindc.f90
Normal file
@ -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
|
@ -123,24 +123,24 @@ contains
|
||||
! on the caller side.
|
||||
|
||||
! CHECK-LABEL: func.func @_QMmod1Psub4()
|
||||
! FIR: %[[BOX:.*]] = fir.alloca !fir.box<!fir.heap<!fir.type<_QMmod1Tt1{i:i32}>>> {bindc_name = "t", uniq_name = "_QMmod1Fsub4Et"}
|
||||
! FIR: %[[BOX:.*]] = fir.alloca !fir.box<!fir.heap<!fir.type<_QMmod1Tt1{{[<]?}}{i:i32}{{[>]?}}>>> {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<!fir.box<!fir.heap<!fir.type<_QMmod1Tt1{i:i32}>>>>) -> ()
|
||||
! CHECK: fir.call @_QMmod1Psub5(%[[BOX]]{{[#0]*}}) {{.*}}: (!fir.ref<!fir.box<!fir.heap<!fir.type<_QMmod1Tt1{{[<]?}}{i:i32}{{[>]?}}>>>>) -> ()
|
||||
|
||||
! 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.box<!fir.heap<!fir.type<_QMmod1Tt1{i:i32}>>>> {fir.bindc_name = "t"})
|
||||
! FIR-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.type<_QMmod1Tt1{{[<]?}}{i:i32}{{[>]?}}>>>> {fir.bindc_name = "t"})
|
||||
! HLFIR: %[[ARG0:.*]]:2 = hlfir.declare {{.*}}"_QMmod1Fsub5Et"
|
||||
! CHECK: %[[BOX:.*]] = fir.load %[[ARG0]]{{[#1]*}} : !fir.ref<!fir.box<!fir.heap<!fir.type<_QMmod1Tt1{i:i32}>>>>
|
||||
! CHECK: %[[BOX_ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box<!fir.heap<!fir.type<_QMmod1Tt1{i:i32}>>>) -> !fir.heap<!fir.type<_QMmod1Tt1{i:i32}>>
|
||||
! CHECK: %[[BOX_ADDR_PTR:.*]] = fir.convert %[[BOX_ADDR]] : (!fir.heap<!fir.type<_QMmod1Tt1{i:i32}>>) -> i64
|
||||
! CHECK: %[[BOX:.*]] = fir.load %[[ARG0]]{{[#1]*}} : !fir.ref<!fir.box<!fir.heap<!fir.type<_QMmod1Tt1{{[<]?}}{i:i32}{{[>]?}}>>>>
|
||||
! CHECK: %[[BOX_ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box<!fir.heap<!fir.type<_QMmod1Tt1{{[<]?}}{i:i32}{{[>]?}}>>>) -> !fir.heap<!fir.type<_QMmod1Tt1{{[<]?}}{i:i32}{{[>]?}}>>
|
||||
! CHECK: %[[BOX_ADDR_PTR:.*]] = fir.convert %[[BOX_ADDR]] : (!fir.heap<!fir.type<_QMmod1Tt1{{[<]?}}{i:i32}{{[>]?}}>>) -> 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.box<!fir.heap<!fir.type<_QMmod1Tt1{i:i32}>>>>) -> !fir.ref<!fir.box<none>>
|
||||
! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]]{{[#1]*}} : (!fir.ref<!fir.box<!fir.heap<!fir.type<_QMmod1Tt1{{[<]?}}{i:i32}{{[>]?}}>>>>) -> !fir.ref<!fir.box<none>>
|
||||
! CHECK: %{{.*}} = fir.call @_FortranAAllocatableDeallocate(%[[BOX_NONE]], %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.ref<!fir.box<none>>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
|
||||
|
||||
subroutine sub6()
|
||||
@ -152,11 +152,11 @@ contains
|
||||
! Deallocation is done with a runtime call.
|
||||
|
||||
! CHECK-LABEL: func.func @_QMmod1Psub6()
|
||||
! FIR: %[[BOX:.*]] = fir.alloca !fir.box<!fir.heap<!fir.type<_QMmod1Tt1{i:i32}>>> {bindc_name = "t", uniq_name = "_QMmod1Fsub6Et"}
|
||||
! FIR: %[[BOX:.*]] = fir.alloca !fir.box<!fir.heap<!fir.type<_QMmod1Tt1{{[<]?}}{i:i32}{{[>]?}}>>> {bindc_name = "t", uniq_name = "_QMmod1Fsub6Et"}
|
||||
! HLFIR: %[[BOX:.*]]:2 = hlfir.declare {{.*}}"_QMmod1Fsub6Et"
|
||||
! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[BOX]]{{[#1]*}} : (!fir.ref<!fir.box<!fir.heap<!fir.type<_QMmod1Tt1{i:i32}>>>>) -> !fir.ref<!fir.box<none>>
|
||||
! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[BOX]]{{[#1]*}} : (!fir.ref<!fir.box<!fir.heap<!fir.type<_QMmod1Tt1{{[<]?}}{i:i32}{{[>]?}}>>>>) -> !fir.ref<!fir.box<none>>
|
||||
! CHECK: %{{.*}} = fir.call @_FortranAAllocatableDeallocate(%[[BOX_NONE]], %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.ref<!fir.box<none>>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
|
||||
! CHECK: fir.call @sub7(%[[BOX]]{{[#0]*}}) {{.*}}: (!fir.ref<!fir.box<!fir.heap<!fir.type<_QMmod1Tt1{i:i32}>>>>) -> ()
|
||||
! CHECK: fir.call @sub7(%[[BOX]]{{[#0]*}}) {{.*}}: (!fir.ref<!fir.box<!fir.heap<!fir.type<_QMmod1Tt1{{[<]?}}{i:i32}{{[>]?}}>>>>) -> ()
|
||||
|
||||
subroutine sub8()
|
||||
integer, allocatable :: a(:)
|
||||
|
105
flang/test/Semantics/offsets04.f90
Normal file
105
flang/test/Semantics/offsets04.f90
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user