Skip to content

[flang] Align runtime info and lowering regarding passing ABIs #81166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions flang/include/flang/Evaluate/characteristics.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ struct DummyDataObject {
static std::optional<DummyDataObject> Characterize(
const semantics::Symbol &, FoldingContext &);
bool CanBePassedViaImplicitInterface(std::string *whyNot = nullptr) const;
bool IsPassedByDescriptor(bool isBindC) const;
llvm::raw_ostream &Dump(llvm::raw_ostream &) const;

TypeAndShape type;
Expand Down
24 changes: 24 additions & 0 deletions flang/lib/Evaluate/characteristics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,30 @@ bool DummyDataObject::CanBePassedViaImplicitInterface(
}
}

bool DummyDataObject::IsPassedByDescriptor(bool isBindC) const {
constexpr TypeAndShape::Attrs shapeRequiringBox = {
TypeAndShape::Attr::AssumedShape, TypeAndShape::Attr::DeferredShape,
TypeAndShape::Attr::AssumedRank, TypeAndShape::Attr::Coarray};
if ((attrs & Attrs{Attr::Allocatable, Attr::Pointer}).any()) {
return true;
} else if ((type.attrs() & shapeRequiringBox).any()) {
// Need to pass shape/coshape info in a descriptor.
return true;
} else if (type.type().IsPolymorphic() && !type.type().IsAssumedType()) {
// Need to pass dynamic type info in a descriptor.
return true;
} else if (const auto *derived{GetDerivedTypeSpec(type.type())}) {
if (const semantics::Scope *scope = derived->scope()) {
// Need to pass length type parameters in a descriptor if any.
return scope->IsDerivedTypeWithLengthParameter();
}
} else if (isBindC && type.type().IsAssumedLengthCharacter()) {
// Fortran 2018 18.3.6 point 2 (5)
return true;
}
return false;
}

llvm::raw_ostream &DummyDataObject::Dump(llvm::raw_ostream &o) const {
attrs.Dump(o, EnumToString);
if (intent != common::Intent::Default) {
Expand Down
27 changes: 1 addition & 26 deletions flang/lib/Lower/CallInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -915,31 +915,6 @@ class Fortran::lower::CallInterfaceImpl {
}
}

// Define when an explicit argument must be passed in a fir.box.
bool dummyRequiresBox(
const Fortran::evaluate::characteristics::DummyDataObject &obj,
bool isBindC) {
using ShapeAttr = Fortran::evaluate::characteristics::TypeAndShape::Attr;
using ShapeAttrs = Fortran::evaluate::characteristics::TypeAndShape::Attrs;
constexpr ShapeAttrs shapeRequiringBox = {
ShapeAttr::AssumedShape, ShapeAttr::DeferredShape,
ShapeAttr::AssumedRank, ShapeAttr::Coarray};
if ((obj.type.attrs() & shapeRequiringBox).any())
// Need to pass shape/coshape info in fir.box.
return true;
if (obj.type.type().IsPolymorphic() && !obj.type.type().IsAssumedType())
// Need to pass dynamic type info in fir.box.
return true;
if (const Fortran::semantics::DerivedTypeSpec *derived =
Fortran::evaluate::GetDerivedTypeSpec(obj.type.type()))
if (const Fortran::semantics::Scope *scope = derived->scope())
// Need to pass length type parameters in fir.box if any.
return scope->IsDerivedTypeWithLengthParameter();
if (isBindC && obj.type.type().IsAssumedLengthCharacter())
return true; // Fortran 2018 18.3.6 point 2 (5)
return false;
}

mlir::Type
translateDynamicType(const Fortran::evaluate::DynamicType &dynamicType) {
Fortran::common::TypeCategory cat = dynamicType.category();
Expand Down Expand Up @@ -1022,7 +997,7 @@ class Fortran::lower::CallInterfaceImpl {
addFirOperand(boxRefType, nextPassedArgPosition(), Property::MutableBox,
attrs);
addPassedArg(PassEntityBy::MutableBox, entity, characteristics);
} else if (dummyRequiresBox(obj, isBindC)) {
} else if (obj.IsPassedByDescriptor(isBindC)) {
// Pass as fir.box or fir.class
if (isValueAttr &&
!getConverter().getLoweringOptions().getLowerToHighLevelFIR())
Expand Down
14 changes: 9 additions & 5 deletions flang/lib/Semantics/runtime-type-info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1144,7 +1144,7 @@ void RuntimeTableBuilder::DescribeSpecialProc(
which = scalarFinalEnum_;
if (int rank{evaluate::GetRank(typeAndShape.shape())}; rank > 0) {
which = IntExpr<1>(ToInt64(which).value() + rank);
if (!proc->dummyArguments[0].CanBePassedViaImplicitInterface()) {
if (dummyData.IsPassedByDescriptor(proc->IsBindC())) {
argThatMightBeDescriptor = 1;
}
if (!typeAndShape.attrs().test(evaluate::characteristics::
Expand Down Expand Up @@ -1187,10 +1187,14 @@ void RuntimeTableBuilder::DescribeSpecialProc(
break;
}
}
if (argThatMightBeDescriptor != 0 &&
!proc->dummyArguments.at(argThatMightBeDescriptor - 1)
.CanBePassedViaImplicitInterface()) {
isArgDescriptorSet |= 1 << (argThatMightBeDescriptor - 1);
if (argThatMightBeDescriptor != 0) {
if (const auto *dummyData{
std::get_if<evaluate::characteristics::DummyDataObject>(
&proc->dummyArguments.at(argThatMightBeDescriptor - 1).u)}) {
if (dummyData->IsPassedByDescriptor(proc->IsBindC())) {
isArgDescriptorSet |= 1 << (argThatMightBeDescriptor - 1);
}
}
}
evaluate::StructureConstructorValues values;
auto index{evaluate::ToInt64(which)};
Expand Down
20 changes: 20 additions & 0 deletions flang/test/Semantics/typeinfo09.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
!RUN: bbc --dump-symbols %s | FileCheck %s
!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s
! test setting of isargdescriptorset in the runtime type info.

module m
type :: sometype
contains
procedure :: copy => copy_impl
generic :: assignment(=) => copy
end type
interface
subroutine copy_impl(this, x)
import
class(sometype), intent(out) :: this
type(sometype), target, intent(in) :: x
end subroutine
end interface
end module

!CHECK: .s.sometype, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=1_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=copy_impl)]