[flang-commits] [flang] da78ae4 - [flang][hlfir] Lower some character elemental references

Jean Perier via flang-commits flang-commits at lists.llvm.org
Tue Jan 17 04:41:55 PST 2023


Author: Jean Perier
Date: 2023-01-17T13:41:07+01:00
New Revision: da78ae46f480b74d798ecb502d92436bb3b802de

URL: https://github.com/llvm/llvm-project/commit/da78ae46f480b74d798ecb502d92436bb3b802de
DIFF: https://github.com/llvm/llvm-project/commit/da78ae46f480b74d798ecb502d92436bb3b802de.diff

LOG: [flang][hlfir] Lower some character elemental references

Lower character elemental user procedures with constant length, and
bot dynamic and constant length ADJUSTL, ADJUSTR, and MERGE references
(which leaves out MIN/MAX).

Character elemental user procedures with dynamic length are a bit more
involving and since it is an edge-case that is not currently supported,
I will take this on later.

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

Added: 
    

Modified: 
    flang/lib/Lower/ConvertCall.cpp
    flang/lib/Lower/ConvertType.cpp
    flang/test/Lower/HLFIR/elemental-intrinsics.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index 7be735c8197f7..b6015ae83df21 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -724,12 +724,19 @@ static hlfir::EntityWithAttributes genIntrinsicRefCore(
       loc, builder, resultExv, ".tmp.intrinsic_result");
   // Move result into memory into an hlfir.expr since they are immutable from
   // that point, and the result storage is some temp.
-  if (!fir::isa_trivial(resultEntity.getType()))
-    resultEntity = hlfir::EntityWithAttributes{
-        builder
-            .create<hlfir::AsExprOp>(loc, resultEntity,
-                                     builder.createBool(loc, mustBeFreed))
-            .getResult()};
+  if (!fir::isa_trivial(resultEntity.getType())) {
+    hlfir::AsExprOp asExpr;
+    // Character/Derived MERGE lowering returns one of its argument address
+    // (this is the only intrinsic implemented in that way so far). The
+    // ownership of this address cannot be taken here since it may not be a
+    // temp.
+    if (intrinsic.name == "merge")
+      asExpr = builder.create<hlfir::AsExprOp>(loc, resultEntity);
+    else
+      asExpr = builder.create<hlfir::AsExprOp>(
+          loc, resultEntity, builder.createBool(loc, mustBeFreed));
+    resultEntity = hlfir::EntityWithAttributes{asExpr.getResult()};
+  }
   return resultEntity;
 }
 
@@ -800,8 +807,19 @@ class ElementalCallBuilder {
     // Get result length parameters.
     llvm::SmallVector<mlir::Value> typeParams;
     if (elementType.isa<fir::CharacterType>() ||
-        fir::isRecordWithTypeParameters(elementType))
-      TODO(loc, "compute elemental function result length parameters in HLFIR");
+        fir::isRecordWithTypeParameters(elementType)) {
+      auto charType = elementType.dyn_cast<fir::CharacterType>();
+      if (charType && charType.hasConstantLen())
+        typeParams.push_back(builder.createIntegerConstant(
+            loc, builder.getIndexType(), charType.getLen()));
+      else if (charType)
+        typeParams.push_back(impl().computeDynamicCharacterResultLength(
+            loweredActuals, callContext));
+      else
+        TODO(
+            loc,
+            "compute elemental PDT function result length parameters in HLFIR");
+    }
     auto genKernel = [&](mlir::Location l, fir::FirOpBuilder &b,
                          mlir::ValueRange oneBasedIndices) -> hlfir::Entity {
       callContext.stmtCtx.pushScope();
@@ -858,6 +876,13 @@ class ElementalUserCallBuilder
            arg.passBy == PassBy::BaseAddressValueAttribute;
   }
 
+  mlir::Value
+  computeDynamicCharacterResultLength(PreparedActualArguments &loweredActuals,
+                                      CallContext &callContext) {
+    TODO(callContext.loc,
+         "compute elemental function result length parameters in HLFIR");
+  }
+
 private:
   Fortran::lower::CallerInterface &caller;
   mlir::FunctionType callSiteType;
@@ -886,6 +911,19 @@ class ElementalIntrinsicCallBuilder
     return isFunction;
   }
 
+  mlir::Value
+  computeDynamicCharacterResultLength(PreparedActualArguments &loweredActuals,
+                                      CallContext &callContext) {
+    if (intrinsic.name == "adjustr" || intrinsic.name == "adjustl" ||
+        intrinsic.name == "merge")
+      return hlfir::genCharLength(callContext.loc, callContext.getBuilder(),
+                                  loweredActuals[0].value().actual);
+    // Character MIN/MAX is the min/max of the arguments length that are
+    // present.
+    TODO(callContext.loc,
+         "compute elemental character min/max function result length in HLFIR");
+  }
+
 private:
   const Fortran::evaluate::SpecificIntrinsic &intrinsic;
   const Fortran::lower::IntrinsicArgumentLoweringRules *argLowering;

diff  --git a/flang/lib/Lower/ConvertType.cpp b/flang/lib/Lower/ConvertType.cpp
index 8c362a3fee184..db18553ab9a7f 100644
--- a/flang/lib/Lower/ConvertType.cpp
+++ b/flang/lib/Lower/ConvertType.cpp
@@ -409,6 +409,15 @@ struct TypeBuilderImpl {
   Fortran::lower::LenParameterTy getCharacterLength(const A &expr) {
     return fir::SequenceType::getUnknownExtent();
   }
+
+  template <typename T>
+  Fortran::lower::LenParameterTy
+  getCharacterLength(const Fortran::evaluate::FunctionRef<T> &funcRef) {
+    if (auto constantLen = toInt64(funcRef.LEN()))
+      return *constantLen;
+    return fir::SequenceType::getUnknownExtent();
+  }
+
   Fortran::lower::LenParameterTy
   getCharacterLength(const Fortran::lower::SomeExpr &expr) {
     // Do not use dynamic type length here. We would miss constant

diff  --git a/flang/test/Lower/HLFIR/elemental-intrinsics.f90 b/flang/test/Lower/HLFIR/elemental-intrinsics.f90
index a22a43b7b2c6a..20c5f5730dc01 100644
--- a/flang/test/Lower/HLFIR/elemental-intrinsics.f90
+++ b/flang/test/Lower/HLFIR/elemental-intrinsics.f90
@@ -88,3 +88,65 @@ subroutine elemental_with_char_args(x,y)
 ! CHECK:  }
 ! CHECK: fir.call
 ! CHECK: hlfir.destroy %[[VAL_13]]
+
+
+! -----------------------------------------------------------------------------
+!  Test elemental character intrinsics with non compile time constant result
+!  length.
+! -----------------------------------------------------------------------------
+
+subroutine test_adjustl(x)
+  character(*) :: x(100)
+  call bar(adjustl(x))
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_adjustl(
+! CHECK:  %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_3:.*]](%[[VAL_5:[a-z0-9]*]]) typeparams %[[VAL_2:[a-z0-9]*]]#1  {{.*}}Ex
+! CHECK:  %[[VAL_7:.*]] = hlfir.elemental %[[VAL_5]] typeparams %[[VAL_2]]#1 : (!fir.shape<1>, index) -> !hlfir.expr<100x!fir.char<1,?>> {
+! CHECK:  ^bb0(%[[VAL_8:.*]]: index):
+! CHECK:    %[[VAL_9:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_8]])  typeparams %[[VAL_2]]#1 : (!fir.box<!fir.array<100x!fir.char<1,?>>>, index, index) -> !fir.boxchar<1>
+! CHECK:    fir.call @_FortranAAdjustl
+! CHECK:    %[[VAL_24:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_22:.*]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.heap<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.heap<!fir.char<1,?>>)
+! CHECK:    %[[VAL_25:.*]] = arith.constant true
+! CHECK:    %[[VAL_26:.*]] = hlfir.as_expr %[[VAL_24]]#0 move %[[VAL_25]] : (!fir.boxchar<1>, i1) -> !hlfir.expr<!fir.char<1,?>>
+! CHECK:    hlfir.yield_element %[[VAL_26]] : !hlfir.expr<!fir.char<1,?>>
+! CHECK:  }
+
+subroutine test_adjustr(x)
+  character(*) :: x(100)
+  call bar(adjustr(x))
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_adjustr(
+! CHECK:  %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_3:.*]](%[[VAL_5:[a-z0-9]*]]) typeparams %[[VAL_2:[a-z0-9]*]]#1  {{.*}}Ex
+! CHECK:  %[[VAL_7:.*]] = hlfir.elemental %[[VAL_5]] typeparams %[[VAL_2]]#1 : (!fir.shape<1>, index) -> !hlfir.expr<100x!fir.char<1,?>> {
+! CHECK:  ^bb0(%[[VAL_8:.*]]: index):
+! CHECK:    %[[VAL_9:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_8]])  typeparams %[[VAL_2]]#1 : (!fir.box<!fir.array<100x!fir.char<1,?>>>, index, index) -> !fir.boxchar<1>
+! CHECK:    fir.call @_FortranAAdjustr
+! CHECK:    %[[VAL_24:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_22:.*]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.heap<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.heap<!fir.char<1,?>>)
+! CHECK:    %[[VAL_25:.*]] = arith.constant true
+! CHECK:    %[[VAL_26:.*]] = hlfir.as_expr %[[VAL_24]]#0 move %[[VAL_25]] : (!fir.boxchar<1>, i1) -> !hlfir.expr<!fir.char<1,?>>
+! CHECK:    hlfir.yield_element %[[VAL_26]] : !hlfir.expr<!fir.char<1,?>>
+! CHECK:  }
+
+subroutine test_merge(x, y, mask)
+  character(*) :: x(100), y(100)
+  logical :: mask(100)
+  call bar(merge(x, y, mask))
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_merge(
+! CHECK:  %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_2:[a-z0-9]*]](%[[VAL_4:[a-z0-9]*]])  {{.*}}Emask
+! CHECK:  %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_7:[a-z0-9]*]](%[[VAL_9:[a-z0-9]*]]) typeparams %[[VAL_6:[a-z0-9]*]]#1  {{.*}}Ex
+! CHECK:  %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_12:[a-z0-9]*]](%[[VAL_14:[a-z0-9]*]]) typeparams %[[VAL_11:[a-z0-9]*]]#1  {{.*}}Ey
+! CHECK:  %[[VAL_16:.*]] = hlfir.elemental %[[VAL_9]] typeparams %[[VAL_6]]#1 : (!fir.shape<1>, index) -> !hlfir.expr<100x!fir.char<1,?>> {
+! CHECK:  ^bb0(%[[VAL_17:.*]]: index):
+! CHECK:    %[[VAL_18:.*]] = hlfir.designate %[[VAL_10]]#0 (%[[VAL_17]])  typeparams %[[VAL_6]]#1 : (!fir.box<!fir.array<100x!fir.char<1,?>>>, index, index) -> !fir.boxchar<1>
+! CHECK:    %[[VAL_19:.*]] = hlfir.designate %[[VAL_15]]#0 (%[[VAL_17]])  typeparams %[[VAL_11]]#1 : (!fir.box<!fir.array<100x!fir.char<1,?>>>, index, index) -> !fir.boxchar<1>
+! CHECK:    %[[VAL_20:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_17]])  : (!fir.ref<!fir.array<100x!fir.logical<4>>>, index) -> !fir.ref<!fir.logical<4>>
+! CHECK:    %[[VAL_21:.*]]:2 = fir.unboxchar %[[VAL_18]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
+! CHECK:    %[[VAL_22:.*]]:2 = fir.unboxchar %[[VAL_19]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
+! CHECK:    %[[VAL_23:.*]] = fir.load %[[VAL_20]] : !fir.ref<!fir.logical<4>>
+! CHECK:    %[[VAL_24:.*]] = fir.convert %[[VAL_23]] : (!fir.logical<4>) -> i1
+! CHECK:    %[[VAL_25:.*]] = arith.select %[[VAL_24]], %[[VAL_21]]#0, %[[VAL_22]]#0 : !fir.ref<!fir.char<1,?>>
+! CHECK:    %[[VAL_26:.*]]:2 = hlfir.declare %[[VAL_25]] typeparams %[[VAL_6]]#1 {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK:    %[[VAL_27:.*]] = hlfir.as_expr %[[VAL_26]]#0 : (!fir.boxchar<1>) -> !hlfir.expr<!fir.char<1,?>>
+! CHECK:    hlfir.yield_element %[[VAL_27]] : !hlfir.expr<!fir.char<1,?>>
+! CHECK:  }


        


More information about the flang-commits mailing list