diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h index ba0c4806c759e..dba946975e192 100644 --- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h +++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h @@ -202,6 +202,7 @@ struct IntrinsicLibrary { fir::ExtendedValue genCAssociatedCPtr(mlir::Type, llvm::ArrayRef); void genCFPointer(llvm::ArrayRef); + void genCFProcPointer(llvm::ArrayRef); fir::ExtendedValue genCFunLoc(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genCLoc(mlir::Type, llvm::ArrayRef); void genDateAndTime(llvm::ArrayRef); diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp index fd726c90c07bd..1ce4608a1c95a 100644 --- a/flang/lib/Lower/ConvertCall.cpp +++ b/flang/lib/Lower/ConvertCall.cpp @@ -1555,8 +1555,6 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals, } hlfir::Entity actual = arg.value()->getActual(loc, builder); - if (actual.isProcedurePointer()) - TODO(loc, "Procedure pointer as actual argument to intrinsics."); switch (argRules.lowerAs) { case fir::LowerIntrinsicArgAs::Value: operands.emplace_back( diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp index ff5dbff04360a..fbf2867ebe239 100644 --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -165,6 +165,10 @@ static constexpr IntrinsicHandler handlers[]{ {"fptr", asInquired}, {"shape", asAddr, handleDynamicOptional}}}, /*isElemental=*/false}, + {"c_f_procpointer", + &I::genCFProcPointer, + {{{"cptr", asValue}, {"fptr", asInquired}}}, + /*isElemental=*/false}, {"c_funloc", &I::genCFunLoc, {{{"x", asBox}}}, /*isElemental=*/false}, {"c_loc", &I::genCLoc, {{{"x", asBox}}}, /*isElemental=*/false}, {"ceiling", &I::genCeiling}, @@ -2498,6 +2502,22 @@ void IntrinsicLibrary::genCFPointer(llvm::ArrayRef args) { /*lbounds=*/mlir::ValueRange{}); } +// C_F_PROCPOINTER +void IntrinsicLibrary::genCFProcPointer( + llvm::ArrayRef args) { + assert(args.size() == 2); + mlir::Value cptr = + fir::factory::genCPtrOrCFunptrValue(builder, loc, fir::getBase(args[0])); + mlir::Value fptr = fir::getBase(args[1]); + auto boxProcType = + mlir::cast(fir::unwrapRefType(fptr.getType())); + mlir::Value cptrCast = + builder.createConvert(loc, boxProcType.getEleTy(), cptr); + mlir::Value cptrBox = + builder.create(loc, boxProcType, cptrCast); + builder.create(loc, cptrBox, fptr); +} + // C_FUNLOC fir::ExtendedValue IntrinsicLibrary::genCFunLoc(mlir::Type resultType, diff --git a/flang/test/Lower/Intrinsics/c_f_procpointer.f90 b/flang/test/Lower/Intrinsics/c_f_procpointer.f90 new file mode 100644 index 0000000000000..f70a56c91b916 --- /dev/null +++ b/flang/test/Lower/Intrinsics/c_f_procpointer.f90 @@ -0,0 +1,42 @@ +! Test C_F_PROCPOINTER() lowering. +! RUN: bbc -emit-hlfir -o - %s | FileCheck %s + +subroutine test_c_funloc(fptr, cptr) + use iso_c_binding, only : c_f_procpointer, c_funptr + real, pointer, external :: fptr + type(c_funptr), cptr + call c_f_procpointer(cptr, fptr) +end subroutine +! CHECK-LABEL: func.func @_QPtest_c_funloc( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref ()>>, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> {fir.bindc_name = "cptr"}) { +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest_c_funlocEcptr"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_c_funlocEfptr"} : (!fir.ref ()>>) -> (!fir.ref ()>>, !fir.ref ()>>) +! CHECK: %[[VAL_4:.*]] = fir.field_index __address, !fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}> +! CHECK: %[[VAL_5:.*]] = fir.coordinate_of %[[VAL_2]]#1, %[[VAL_4]] : (!fir.ref>, !fir.field) -> !fir.ref +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_5]] : !fir.ref +! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> (() -> ()) +! CHECK: %[[VAL_8:.*]] = fir.emboxproc %[[VAL_7]] : (() -> ()) -> !fir.boxproc<() -> ()> +! CHECK: fir.store %[[VAL_8]] to %[[VAL_3]]#1 : !fir.ref ()>> + +subroutine test_c_funloc_char(fptr, cptr) + use iso_c_binding, only : c_f_procpointer, c_funptr + interface + character(10) function char_func() + end function + end interface + procedure(char_func), pointer :: fptr + type(c_funptr), cptr + call c_f_procpointer(cptr, fptr) +end subroutine +! CHECK-LABEL: func.func @_QPtest_c_funloc_char( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref ()>>, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> {fir.bindc_name = "cptr"}) { +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest_c_funloc_charEcptr"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_c_funloc_charEfptr"} : (!fir.ref ()>>) -> (!fir.ref ()>>, !fir.ref ()>>) +! CHECK: %[[VAL_4:.*]] = fir.field_index __address, !fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}> +! CHECK: %[[VAL_5:.*]] = fir.coordinate_of %[[VAL_2]]#1, %[[VAL_4]] : (!fir.ref>, !fir.field) -> !fir.ref +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_5]] : !fir.ref +! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> (() -> ()) +! CHECK: %[[VAL_8:.*]] = fir.emboxproc %[[VAL_7]] : (() -> ()) -> !fir.boxproc<() -> ()> +! CHECK: fir.store %[[VAL_8]] to %[[VAL_3]]#1 : !fir.ref ()>>