Skip to content
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

[flang][hlfir] address char_convert issues as mentioned in #64315 #67570

Merged
merged 1 commit into from
Oct 9, 2023

Conversation

cabreraam
Copy link
Contributor

@cabreraam cabreraam commented Sep 27, 2023

As shown in #64315, there were issues when trying to lower two flavors of Fortran code that implicitly perform CHARACTER conversion. Specifically, I address the following issues:

error: loc("repro.f90":9:3): 'fir.char_convert' op operand #0 must be any reference, but got '!fir.boxchar<4>'
error: loc("repro.f90":15:3): 'fir.char_convert' op operand #0 must be any reference, but got '!hlfir.expr<!fir.char<1>>'

@vzakhari @jeanPerier I borrowed a helper function from HLFIRTools.cpp. The function is static so I'm unable to link against it in flang/lib/Lower/ConvertExprToHLFIR.cpp. Is there a cleaner way that what I've done, which is just copy/paste code?

Thanks,
Anthony

@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir labels Sep 27, 2023
@llvmbot
Copy link
Member

llvmbot commented Sep 27, 2023

@llvm/pr-subscribers-flang-fir-hlfir

Changes

Draft PR message:
As shown in #64315, there were issues when trying to lower two flavors of Fortran code that implicitly perform CHARACTER conversion. Specifically, I address the following issues:

error: loc("repro.f90":9:3): 'fir.char_convert' op operand #<!-- -->0 must be any reference, but got '!fir.boxchar&lt;4&gt;'
error: loc("repro.f90":15:3): 'fir.char_convert' op operand #<!-- -->0 must be any reference, but got '!hlfir.expr&lt;!fir.char&lt;1&gt;&gt;'

@vzakhari @jeanPerier I borrowed a helper function from HLFIRTools.cpp. The function is static so I'm unable to link against it in flang/lib/Lower/ConvertExprToHLFIR.cpp. Is there a cleaner way that what I've done, which is just copy/paste code?

Thanks,
Anthony


Full diff: https://github.com/llvm/llvm-project/pull/67570.diff

2 Files Affected:

  • (modified) flang/lib/Lower/ConvertExprToHLFIR.cpp (+25-3)
  • (added) flang/test/Lower/HLFIR/charconvert.f90 (+60)
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index bc98fdd917d41d0..7fed9dc5c08868e 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1403,6 +1403,22 @@ struct UnaryOp<Fortran::evaluate::Parentheses<T>> {
   }
 };
 
+static fir::CharBoxValue genUnboxChar(mlir::Location loc,
+                                      fir::FirOpBuilder &builder,
+                                      mlir::Value boxChar) {
+  if (auto emboxChar = boxChar.getDefiningOp<fir::EmboxCharOp>())
+    return {emboxChar.getMemref(), emboxChar.getLen()};
+  mlir::Type refType = fir::ReferenceType::get(
+      boxChar.getType().cast<fir::BoxCharType>().getEleTy());
+  auto unboxed = builder.create<fir::UnboxCharOp>(
+      loc, refType, builder.getIndexType(), boxChar);
+  mlir::Value addr = unboxed.getResult(0);
+  mlir::Value len = unboxed.getResult(1);
+  if (auto varIface = boxChar.getDefiningOp<fir::FortranVariableOpInterface>())
+    if (mlir::Value explicitlen = varIface.getExplicitCharLen())
+      len = explicitlen;
+  return {addr, len};
+}
 template <Fortran::common::TypeCategory TC1, int KIND,
           Fortran::common::TypeCategory TC2>
 struct UnaryOp<
@@ -1414,7 +1430,6 @@ struct UnaryOp<
                                          hlfir::Entity lhs) {
     if constexpr (TC1 == Fortran::common::TypeCategory::Character &&
                   TC2 == TC1) {
-      // TODO(loc, "character conversion in HLFIR");
       auto kindMap = builder.getKindMap();
       mlir::Type fromTy = lhs.getFortranElementType();
       mlir::Value origBufferSize = genCharLength(loc, builder, lhs);
@@ -1435,8 +1450,15 @@ struct UnaryOp<
       // allocate space on the stack for toBuffer
       auto dest = builder.create<fir::AllocaOp>(loc, toTy,
                                                 mlir::ValueRange{bufferSize});
-      builder.create<fir::CharConvertOp>(loc, lhs.getFirBase(), origBufferSize,
-                                         dest);
+      auto src = lhs.getFirBase();
+      if (lhs.getType().isa<hlfir::ExprType>()) {
+        if (auto asExpr = lhs.getDefiningOp<hlfir::AsExprOp>()) {
+          src = asExpr.getVar();
+        }
+      } else if (lhs.getType().isa<fir::BoxCharType>())
+        if (!lhs.getDefiningOp<hlfir::DeclareOp>())
+          src = genUnboxChar(loc, builder, lhs).getAddr();
+      builder.create<fir::CharConvertOp>(loc, src, origBufferSize, dest);
 
       return hlfir::EntityWithAttributes{builder.create<hlfir::DeclareOp>(
           loc, dest, "ctor.temp", /*shape=*/nullptr,
diff --git a/flang/test/Lower/HLFIR/charconvert.f90 b/flang/test/Lower/HLFIR/charconvert.f90
new file mode 100644
index 000000000000000..9779e79e4034d90
--- /dev/null
+++ b/flang/test/Lower/HLFIR/charconvert.f90
@@ -0,0 +1,60 @@
+! Test lowering of character concatenation to HLFIR
+! RUN: bbc -emit-hlfir -o - %s 2>&1 | FileCheck %s
+
+subroutine charconvert1(c,n)
+  character(*,4),intent(in) :: c(:)
+  integer,intent(in) :: n
+  interface
+     subroutine callee(c)
+       character(*),intent(in) :: c(:)
+     end subroutine callee
+  end interface
+  call show([character(n)::c])
+end subroutine charconvert1
+
+! CHECK-LABEL: func.func @_QPcharconvert1
+! CHECK:   %[[VAL_2:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFcharconvert1Ec"} : (!fir.box<!fir.array<?x!fir.char<4,?>>>) -> (!fir.box<!fir.array<?x!fir.char<4,?>>>, !fir.box<!fir.array<?x!fir.char<4,?>>>)
+! CHECK:   ^bb0(%[[ARG2:.*]]: index):
+! CHECK:     %[[VAL_37:.*]] = fir.box_elesize %[[VAL_2]]#1 : (!fir.box<!fir.array<?x!fir.char<4,?>>>) -> index
+! CHECK:     %[[C4_4:.*]] = arith.constant 4 : index
+! CHECK:     %[[VAL_38:.*]] = arith.divsi %[[VAL_37]], %[[C4_4]] : index
+! CHECK:     %[[VAL_39:.*]] = hlfir.designate %[[VAL_2]]#0 (%[[ARG2]])  typeparams %[[VAL_38]] : (!fir.box<!fir.array<?x!fir.char<4,?>>>, index, index) -> !fir.boxchar<4>
+! CHECK:     %[[C4_5:.*]] = arith.constant 4 : index
+! CHECK:     %[[VAL_40:.*]] = arith.muli %[[VAL_38]], %[[C4_5]] : index
+! CHECK:     %[[VAL_41:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_40]] : index)
+! CHECK:     %[[VAL_42:.*]]:2 = fir.unboxchar %[[VAL_39]] : (!fir.boxchar<4>) -> (!fir.ref<!fir.char<4,?>>, index)
+! CHECK:     fir.char_convert %[[VAL_42]]#0 for %[[VAL_38:.*]] to %[[VAL_41]] : !fir.ref<!fir.char<4,?>>, index, !fir.ref<!fir.char<1,?>>
+! CHECK:     %[[VAL_43:.*]]:2 = hlfir.declare %[[VAL_41]] typeparams %[[VAL_38]] {uniq_name = "ctor.temp"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK:     hlfir.yield_element %[[VAL_43]]#0 : !fir.boxchar<1>
+! CHECK:   }
+
+subroutine test2(x)
+  integer,intent(in) :: x
+  character(kind=4) :: cx
+  cx = achar(x)
+end subroutine test2
+! CHECK-LABEL: func.func @_QPtest2
+! CHECK-SAME: %[[ARG0:.*]]: !fir.ref<i32>
+! CHECK:   %[[VAL_0:.*]] = fir.alloca !fir.char<1>
+! CHECK:   %[[C1:.*]] = arith.constant 1 : index
+! CHECK:   %[[VAL_1:.*]] = fir.alloca !fir.char<4> {bindc_name = "cx", uniq_name = "_QFtest2Ecx"}
+! CHECK:   %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] typeparams %[[C1]] {uniq_name = "_QFtest2Ecx"} : (!fir.ref<!fir.char<4>>, index) -> (!fir.ref<!fir.char<4>>, !fir.ref<!fir.char<4>>)
+! CHECK:   %[[VAL_3:.*]]:2 = hlfir.declare %[[ARG0]] {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFtest2Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK:   %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i32>
+! CHECK:   %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i32) -> i64
+! CHECK:   %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i64) -> i8
+! CHECK:   %[[VAL_7:.*]] = fir.undefined !fir.char<1>
+! CHECK:   %[[VAL_8:.*]] = fir.insert_value %[[VAL_7]], %[[VAL_6]], [0 : index] : (!fir.char<1>, i8) -> !fir.char<1>
+! CHECK:   fir.store %[[VAL_8:.*]] to %[[VAL_0]] : !fir.ref<!fir.char<1>>
+! CHECK:   %[[FALSE:.*]] = arith.constant false
+! CHECK:   %[[VAL_9:.*]] = hlfir.as_expr %[[VAL_0]] move %[[FALSE]] : (!fir.ref<!fir.char<1>>, i1) -> !hlfir.expr<!fir.char<1>>
+! CHECK:   %[[C1_0:.*]] = arith.constant 1 : index
+! CHECK:   %[[VAL_10:.*]] = fir.alloca !fir.char<4,?>(%[[C1_0]] : index)
+! CHECK:   fir.char_convert %[[VAL_0:.*]] for %[[C1_0]] to %[[VAL_10]] : !fir.ref<!fir.char<1>>, index, !fir.ref<!fir.char<4,?>>
+! CHECK:   %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] typeparams %[[C1_0]] {uniq_name = "ctor.temp"} : (!fir.ref<!fir.char<4,?>>, index) -> (!fir.boxchar<4>, !fir.ref<!fir.char<4,?>>)
+! CHECK:   %[[C1_I64:.*]] = arith.constant 1 : i64
+! CHECK:   %[[VAL_12:.*]] = hlfir.set_length %[[VAL_11]]#0 len %[[C1_I64]] : (!fir.boxchar<4>, i64) -> !hlfir.expr<!fir.char<4>>
+! CHECK:   hlfir.assign %[[VAL_12:.*]] to %[[VAL_2]]#0 : !hlfir.expr<!fir.char<4>>, !fir.ref<!fir.char<4>>
+! CHECK:   hlfir.destroy %[[VAL_9:.*]] : !hlfir.expr<!fir.char<1>>
+! CHECK:   return
+! CHECK: }

Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on a fix!

flang/lib/Lower/ConvertExprToHLFIR.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing all the comments, LGTM

@cabreraam
Copy link
Contributor Author

Thanks for addressing all the comments, LGTM

I messed up a push to the feature branch so I need to fix some stuff. I will make sure to fix this before closing and merging!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:fir-hlfir flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants