[flang] Delegate pointer association to class(*) pointer to the runtime
authorValentin Clement <clementval@gmail.com>
Wed, 30 Nov 2022 17:57:28 +0000 (18:57 +0100)
committerValentin Clement <clementval@gmail.com>
Wed, 30 Nov 2022 17:57:57 +0000 (18:57 +0100)
Pointer association with an unlimited polymorphic pointer on the lhs
requires more than just updating the base_addr. Delegate the association to
the runtime function `PointerAssociation`.

Reviewed By: PeteSteinfeld

Differential Revision: https://reviews.llvm.org/D139019

flang/include/flang/Lower/Runtime.h
flang/include/flang/Optimizer/Dialect/FIRType.h
flang/lib/Lower/Bridge.cpp
flang/lib/Lower/Runtime.cpp
flang/lib/Optimizer/Dialect/FIROps.cpp
flang/lib/Optimizer/Dialect/FIRType.cpp
flang/test/Lower/polymorphic.f90

index 11eedf8..87d5b5b 100644 (file)
@@ -69,6 +69,9 @@ void genPauseStatement(AbstractConverter &, const parser::PauseStmt &);
 mlir::Value genAssociated(fir::FirOpBuilder &, mlir::Location,
                           mlir::Value pointer, mlir::Value target);
 
+void genPointerAssociate(fir::FirOpBuilder &, mlir::Location,
+                         mlir::Value pointer, mlir::Value target);
+
 mlir::Value genCpuTime(fir::FirOpBuilder &, mlir::Location);
 void genDateAndTime(fir::FirOpBuilder &, mlir::Location,
                     llvm::Optional<fir::CharBoxValue> date,
index 0928e85..ae50d08 100644 (file)
@@ -280,6 +280,12 @@ bool isAllocatableType(mlir::Type ty);
 /// e.g. !fir.box<!fir.type<derived>>
 bool isBoxedRecordType(mlir::Type ty);
 
+/// Return true iff `ty` is a !fir.ref<!fir.box<T>> type.
+bool isRefBoxType(mlir::Type ty);
+
+/// Return true iff `ty` is !fir.box<none> type.
+bool isOpaqueDescType(mlir::Type ty);
+
 /// Return true iff `ty` is the type of an polymorphic entity or
 /// value.
 bool isPolymorphicType(mlir::Type ty);
index 93255c6..c98d838 100644 (file)
@@ -2710,6 +2710,19 @@ private:
             [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
               if (Fortran::evaluate::IsProcedure(assign.rhs))
                 TODO(loc, "procedure pointer assignment");
+
+              std::optional<Fortran::evaluate::DynamicType> lhsType =
+                  assign.lhs.GetType();
+              // Delegate pointer association to unlimited polymorphic pointer
+              // to the runtime. element size, type code, attribute and of
+              // course base_addr might need to be updated.
+              if (lhsType && lhsType->IsUnlimitedPolymorphic()) {
+                mlir::Value lhs = genExprMutableBox(loc, assign.lhs).getAddr();
+                mlir::Value rhs = genExprMutableBox(loc, assign.rhs).getAddr();
+                Fortran::lower::genPointerAssociate(*builder, loc, lhs, rhs);
+                return;
+              }
+
               llvm::SmallVector<mlir::Value> lbounds;
               for (const Fortran::evaluate::ExtentExpr &lbExpr : lbExprs)
                 lbounds.push_back(
index 6322e54..ef93d4d 100644 (file)
@@ -188,6 +188,17 @@ mlir::Value Fortran::lower::genAssociated(fir::FirOpBuilder &builder,
   return builder.create<fir::CallOp>(loc, func, args).getResult(0);
 }
 
+void Fortran::lower::genPointerAssociate(fir::FirOpBuilder &builder,
+                                         mlir::Location loc,
+                                         mlir::Value pointer,
+                                         mlir::Value target) {
+  mlir::func::FuncOp func =
+      fir::runtime::getRuntimeFunc<mkRTKey(PointerAssociate)>(loc, builder);
+  llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
+      builder, loc, func.getFunctionType(), pointer, target);
+  builder.create<fir::CallOp>(loc, func, args).getResult(0);
+}
+
 mlir::Value Fortran::lower::genCpuTime(fir::FirOpBuilder &builder,
                                        mlir::Location loc) {
   mlir::func::FuncOp func =
index 409b64b..0adeb6b 100644 (file)
@@ -938,8 +938,10 @@ mlir::LogicalResult fir::ConvertOp::verify() {
       (inType.isa<fir::BoxProcType>() && outType.isa<fir::BoxProcType>()) ||
       (fir::isa_complex(inType) && fir::isa_complex(outType)) ||
       (fir::isBoxedRecordType(inType) && fir::isPolymorphicType(outType)) ||
-      (fir::isPolymorphicType(inType) && fir::isPolymorphicType(outType)))
+      (fir::isPolymorphicType(inType) && fir::isPolymorphicType(outType)) ||
+      (fir::isRefBoxType(inType) && fir::isOpaqueDescType(outType)))
     return mlir::success();
+  llvm::errs() << inType << " / " << outType << "\n";
   return emitOpError("invalid type conversion");
 }
 
index 89a806c..a2906e8 100644 (file)
@@ -274,6 +274,19 @@ bool isBoxedRecordType(mlir::Type ty) {
   return false;
 }
 
+bool isRefBoxType(mlir::Type ty) {
+  if (auto refTy = ty.dyn_cast<fir::ReferenceType>())
+    return refTy.getEleTy().isa<fir::BaseBoxType>();
+  return false;
+}
+
+bool isOpaqueDescType(mlir::Type ty) {
+  if (auto boxTy = ty.dyn_cast<fir::BoxType>())
+    if (boxTy.getEleTy().isa<mlir::NoneType>())
+      return true;
+  return false;
+}
+
 static bool isAssumedType(mlir::Type ty) {
   if (auto boxTy = ty.dyn_cast<fir::BoxType>()) {
     if (boxTy.getEleTy().isa<mlir::NoneType>())
index b97cc46..662aca9 100644 (file)
@@ -130,24 +130,20 @@ module polymorphic_test
 ! CHECK-LABEL: func.func @_QMpolymorphic_testPcall_up_ret() {
 ! CHECK:         %{{.*}} = fir.call @_QMpolymorphic_testPup_ret() {{.*}} : () -> !fir.class<!fir.ptr<!fir.array<?xnone>>>
 
-  subroutine rebox_f32_to_none(r)
+  subroutine associate_up_pointer(r)
     class(r1) :: r
     class(*), pointer :: p(:)
     p => r%rp
   end subroutine
 
-! CHECK-LABEL: func.func @_QMpolymorphic_testPrebox_f32_to_none(
+! CHECK-LABEL: func.func @_QMpolymorphic_testPassociate_up_pointer(
 ! CHECK-SAME: %[[ARG0:.*]]: !fir.class<!fir.type<_QMpolymorphic_testTr1{rp:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>> {fir.bindc_name = "r"}) {
-! CHECK: %[[P:.*]] = fir.alloca !fir.class<!fir.ptr<!fir.array<?xnone>>> {bindc_name = "p", uniq_name = "_QMpolymorphic_testFrebox_f32_to_noneEp"}
+! CHECK: %[[P:.*]] = fir.alloca !fir.class<!fir.ptr<!fir.array<?xnone>>> {bindc_name = "p", uniq_name = "_QMpolymorphic_testFassociate_up_pointerEp"}
 ! CHECK: %[[FIELD_RP:.*]] = fir.field_index rp, !fir.type<_QMpolymorphic_testTr1{rp:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>
 ! CHECK: %[[COORD_RP:.*]] = fir.coordinate_of %[[ARG0]], %[[FIELD_RP]] : (!fir.class<!fir.type<_QMpolymorphic_testTr1{rp:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
-! CHECK: %[[LOADED_RP:.*]] = fir.load %[[COORD_RP]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
-! CHECK: %[[C0:.*]] = arith.constant 0 : index
-! CHECK: %[[RP_DIMS:.*]]:3 = fir.box_dims %[[LOADED_RP]], %[[C0]] : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, index) -> (index, index, index)
-! CHECK: %[[SHIFT:.*]] = fir.shift %[[RP_DIMS]]#0 : (index) -> !fir.shift<1>
-! CHECK: %[[REBOX_TO_BOX:.*]] = fir.rebox %[[LOADED_RP]](%[[SHIFT]]) : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, !fir.shift<1>) -> !fir.box<!fir.array<?xf32>>
-! CHECK: %[[REBOX_TO_UP:.*]] = fir.rebox %[[REBOX_TO_BOX]] : (!fir.box<!fir.array<?xf32>>) -> !fir.class<!fir.ptr<!fir.array<?xnone>>>
-! CHECK: fir.store %[[REBOX_TO_UP]] to %[[P]] : !fir.ref<!fir.class<!fir.ptr<!fir.array<?xnone>>>>
+! CHECK: %[[CONV_P:.*]] = fir.convert %[[P]] : (!fir.ref<!fir.class<!fir.ptr<!fir.array<?xnone>>>>) -> !fir.ref<!fir.box<none>>
+! CHECK: %[[CONV_RP:.*]] = fir.convert %[[COORD_RP]] : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> !fir.box<none>
+! CHECK: %{{.*}} = fir.call @_FortranAPointerAssociate(%[[CONV_P]], %[[CONV_RP]]) {{.*}} : (!fir.ref<!fir.box<none>>, !fir.box<none>) -> none
 ! CHECK: return
 
 ! Test that the fir.dispatch operation is created with the correct pass object