[flang-commits] [flang] b09426f - [flang] Cleanup code and add test from fir-dev

Valentin Clement via flang-commits flang-commits at lists.llvm.org
Wed Jun 22 00:39:23 PDT 2022


Author: Valentin Clement
Date: 2022-06-22T09:39:11+02:00
New Revision: b09426ff266fefb2aee34a3d811562d802264937

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

LOG: [flang] Cleanup code and add test from fir-dev

This patch clean up some code for upstreaming and add couple of
missing tests that were left in fir-dev.

This patch is part of the upstreaming effort from fir-dev branch.

Reviewed By: jeanPerier, PeteSteinfeld

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

Co-authored-by: Jean Perier <jperier at nvidia.com>
Co-authored-by: Eric Schweitz <eschweitz at nvidia.com>

Added: 
    flang/test/Fir/array-coor.fir
    flang/test/Fir/box.fir
    flang/test/Fir/boxproc.fir
    flang/test/Fir/char01.fir
    flang/test/Fir/commute.fir
    flang/test/Fir/compare.fir
    flang/test/Fir/constant.fir
    flang/test/Fir/convert.fir
    flang/test/Fir/field-index.fir

Modified: 
    flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp
    flang/test/Fir/array-modify.fir
    flang/test/Fir/convert-to-llvm-invalid.fir
    flang/test/Fir/external-mangling.fir

Removed: 
    


################################################################################
diff  --git a/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp b/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp
index 989caab35a29..8c3a5fd35422 100644
--- a/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp
+++ b/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp
@@ -260,8 +260,8 @@ class ArrayCoorConversion : public mlir::OpRewritePattern<fir::ArrayCoorOp> {
 
 class CodeGenRewrite : public fir::CodeGenRewriteBase<CodeGenRewrite> {
 public:
-  void runOnOperation() override final {
-    auto op = getOperation();
+  void runOn(mlir::Operation *op, mlir::Region &region) {
+    // auto op = getOperation();
     auto &context = getContext();
     mlir::OpBuilder rewriter(&context);
     mlir::ConversionTarget target(context);
@@ -284,7 +284,60 @@ class CodeGenRewrite : public fir::CodeGenRewriteBase<CodeGenRewrite> {
                       "error in running the pre-codegen conversions");
       signalPassFailure();
     }
+    // Erase any residual.
+    simplifyRegion(region);
+  }
+
+  void runOnOperation() override final {
+    // Call runOn on all top level regions that may contain emboxOp/arrayCoorOp.
+    auto mod = getOperation();
+    for (auto func : mod.getOps<mlir::func::FuncOp>())
+      runOn(func, func.getBody());
+    for (auto global : mod.getOps<fir::GlobalOp>())
+      runOn(global, global.getRegion());
+  }
+
+  // Clean up the region.
+  void simplifyRegion(mlir::Region &region) {
+    for (auto &block : region.getBlocks())
+      for (auto &op : block.getOperations()) {
+        for (auto &reg : op.getRegions())
+          simplifyRegion(reg);
+        maybeEraseOp(&op);
+      }
+    doDCE();
+  }
+
+  /// Run a simple DCE cleanup to remove any dead code after the rewrites.
+  void doDCE() {
+    std::vector<mlir::Operation *> workList;
+    workList.swap(opsToErase);
+    while (!workList.empty()) {
+      for (auto *op : workList) {
+        std::vector<mlir::Value> opOperands(op->operand_begin(),
+                                            op->operand_end());
+        LLVM_DEBUG(llvm::dbgs() << "DCE on " << *op << '\n');
+        ++numDCE;
+        op->erase();
+        for (auto opnd : opOperands)
+          maybeEraseOp(opnd.getDefiningOp());
+      }
+      workList.clear();
+      workList.swap(opsToErase);
+    }
   }
+
+  void maybeEraseOp(mlir::Operation *op) {
+    if (!op)
+      return;
+    if (op->hasTrait<mlir::OpTrait::IsTerminator>())
+      return;
+    if (mlir::isOpTriviallyDead(op))
+      opsToErase.push_back(op);
+  }
+
+private:
+  std::vector<mlir::Operation *> opsToErase;
 };
 
 } // namespace

diff  --git a/flang/test/Fir/array-coor.fir b/flang/test/Fir/array-coor.fir
new file mode 100644
index 000000000000..8fa1fdaee17c
--- /dev/null
+++ b/flang/test/Fir/array-coor.fir
@@ -0,0 +1,22 @@
+// RUN: tco %s | FileCheck %s
+
+func.func @array_coor_box_value(%29 : !fir.box<!fir.array<2xf64>>,
+     			   %33 : index) -> f64 {
+  %34 = fir.array_coor %29 %33 : (!fir.box<!fir.array<2xf64>>, index) ->
+      		       	          !fir.ref<f64>
+  %35 = fir.load %34 : !fir.ref<f64>
+  return %35 : f64
+}
+
+// CHECK-LABEL: define double @array_coor_box_value
+// CHECK: %[[t3:.*]] = sub i64 %{{.*}}, 1
+// CHECK: %[[t4:.*]] = mul i64 %[[t3]], 1
+// CHECK: %[[t5:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %{{.*}}, i32 0, i32 7, i64 0, i32 2
+// CHECK: %[[t6:.*]] = load i64, ptr %[[t5]]
+// CHECK: %[[t7:.*]] = mul i64 %[[t4]], %[[t6]]
+// CHECK: %[[t8:.*]] = add i64 %[[t7]], 0
+// CHECK: %[[t9:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %{{.*}}, i32 0, i32 0
+// CHECK: %[[t10:.*]] = load ptr, ptr %[[t9]]
+// CHECK: %[[t11:.*]] = getelementptr i8, ptr %[[t10]], i64 %[[t8]]
+// CHECK: %[[t12:.*]] = load double, ptr %[[t11]]
+// CHECK: ret double %[[t12]]

diff  --git a/flang/test/Fir/array-modify.fir b/flang/test/Fir/array-modify.fir
index 47f9352b07ce..4aff744c9ab7 100644
--- a/flang/test/Fir/array-modify.fir
+++ b/flang/test/Fir/array-modify.fir
@@ -123,7 +123,7 @@ func.func @overlap(%arg0: !fir.ref<!fir.array<100xf32>>) {
 // CHECK:             %[[VAL_42:.*]] = fir.load %[[VAL_41]] : !fir.ref<f32>
 // CHECK:             fir.store %[[VAL_42]] to %[[VAL_45]] : !fir.ref<f32>
 // CHECK:           }
-// CHECK:           fir.freemem %[[VAL_8]]
+// CHECK:           fir.freemem %[[VAL_8]] : !fir.heap<!fir.array<100xf32>>
 // CHECK:           return
 // CHECK:         }
 

diff  --git a/flang/test/Fir/box.fir b/flang/test/Fir/box.fir
new file mode 100644
index 000000000000..d8988102feab
--- /dev/null
+++ b/flang/test/Fir/box.fir
@@ -0,0 +1,166 @@
+// RUN: tco -o - %s | FileCheck %s
+
+// Global box initialization (test must come first because llvm globals are emitted first).
+// CHECK-LABEL: @globalx = internal global { ptr, i64, i32, i8, i8, i8, i8 } { ptr null, i64 4, i32 20180515, i8 0, i8 9, i8 2, i8 0 }
+fir.global internal @globalx : !fir.box<!fir.heap<i32>> {
+  %c0 = arith.constant 0 : index
+  %0 = fir.convert %c0 : (index) -> !fir.heap<i32>
+  %1 = fir.embox %0 : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
+  fir.has_value %1 : !fir.box<!fir.heap<i32>>
+}
+
+// CHECK-LABEL: @globaly = internal global { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } { ptr null, i64 4, i32 20180515, i8 1, i8 27, i8 2, i8 0,{{.*}}[3 x i64] [i64 1, i64 0, i64 4]
+fir.global internal @globaly : !fir.box<!fir.heap<!fir.array<?xf32>>> {
+  %c0 = arith.constant 0 : index
+  %0 = fir.convert %c0 : (index) -> !fir.heap<!fir.array<?xf32>>
+  %1 = fir.shape %c0 : (index) -> !fir.shape<1>
+  %2 = fir.embox %0(%1) : (!fir.heap<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.heap<!fir.array<?xf32>>>
+  fir.has_value %2 : !fir.box<!fir.heap<!fir.array<?xf32>>>
+}
+
+// CHECK-LABEL: declare void @g(ptr)
+func.func private @g(%b : !fir.box<f32>)
+// CHECK-LABEL: declare void @ga(ptr)
+func.func private @ga(%b : !fir.box<!fir.array<?xf32>>)
+
+// CHECK-LABEL: define void @f
+// CHECK: (ptr %[[ARG:.*]])
+func.func @f(%a : !fir.ref<f32>) {
+  // CHECK: %[[DESC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }
+  // CHECK: %[[INS0:.*]] = insertvalue {{.*}} { ptr undef, i64 4, i32 20180515, i8 0, i8 27, i8 0, i8 0 }, ptr %[[ARG]], 0
+  // CHECK: store {{.*}} %[[INS0]], {{.*}} %[[DESC]]
+  %b = fir.embox %a : (!fir.ref<f32>) -> !fir.box<f32>
+
+  // CHECK: call void @g({{.*}} %[[DESC]])
+  fir.call @g(%b) : (!fir.box<f32>) -> ()
+  // CHECK: ret void
+  return
+}
+
+// CHECK-LABEL: define void @fa
+// CHECK: (ptr %[[ARG:.*]])
+func.func @fa(%a : !fir.ref<!fir.array<100xf32>>) {
+  %c = fir.convert %a : (!fir.ref<!fir.array<100xf32>>) -> !fir.ref<!fir.array<?xf32>>
+  %c1 = arith.constant 1 : index
+  %c100 = arith.constant 100 : index
+  %d = fir.shape %c100 : (index) -> !fir.shape<1>
+  // CHECK: %[[INS70:.*]] = insertvalue {{.*}} { ptr undef, i64 4, i32 20180515, i8 1, i8 27, i8 0, i8 0, {{.*}} }, ptr %{{.*}}, 0
+  %b = fir.embox %c(%d) : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
+  // CHECK: call void @ga(
+  fir.call @ga(%b) : (!fir.box<!fir.array<?xf32>>) -> ()
+  // CHECK: ret void
+  return
+}
+
+// Boxing of a scalar character of dynamic length
+// CHECK-LABEL: define void @b1(
+// CHECK-SAME: ptr %[[res:.*]], ptr %[[arg0:.*]], i64 %[[arg1:.*]])
+func.func @b1(%arg0 : !fir.ref<!fir.char<1,?>>, %arg1 : index) -> !fir.box<!fir.char<1,?>> {
+  // CHECK: insertvalue {{.*}} undef, i64 %[[arg1]], 1
+  // CHECK: insertvalue {{.*}} i32 20180515, 2
+  // CHECK: insertvalue {{.*}} ptr %[[arg0]], 0
+  %x = fir.embox %arg0 typeparams %arg1 : (!fir.ref<!fir.char<1,?>>, index) -> !fir.box<!fir.char<1,?>>
+  // CHECK: store {{.*}}, ptr %[[res]]
+  return %x : !fir.box<!fir.char<1,?>>
+}
+
+// Boxing of a dynamic array of character with static length (5)
+// CHECK-LABEL: define void @b2(
+// CHECK-SAME: ptr %[[res]],
+// CHECK-SAME: ptr %[[arg0:.*]], i64 %[[arg1:.*]])
+func.func @b2(%arg0 : !fir.ref<!fir.array<?x!fir.char<1,5>>>, %arg1 : index) -> !fir.box<!fir.array<?x!fir.char<1,5>>> {
+  %1 = fir.shape %arg1 : (index) -> !fir.shape<1>
+  // CHECK: insertvalue {{.*}} { ptr undef, i64 5, i32 20180515, i8 1, i8 40, i8 0, i8 0, {{.*}} }, i64 %[[arg1]], 7, 0, 1
+  // CHECK: insertvalue {{.*}} %{{.*}}, i64 5, 7, 0, 2
+  // CHECK: insertvalue {{.*}} ptr %[[arg0]], 0
+  %2 = fir.embox %arg0(%1) : (!fir.ref<!fir.array<?x!fir.char<1,5>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.char<1,5>>>
+  // CHECK: store {{.*}}, ptr %[[res]]
+  return %2 : !fir.box<!fir.array<?x!fir.char<1,5>>>
+}
+
+// Boxing of a dynamic array of character of dynamic length
+// CHECK-LABEL: define void @b3(
+// CHECK-SAME: ptr %[[res:.*]], ptr %[[arg0:.*]], i64 %[[arg1:.*]], i64 %[[arg2:.*]])
+func.func @b3(%arg0 : !fir.ref<!fir.array<?x!fir.char<1,?>>>, %arg1 : index, %arg2 : index) -> !fir.box<!fir.array<?x!fir.char<1,?>>> {
+  %1 = fir.shape %arg2 : (index) -> !fir.shape<1>
+  // CHECK: insertvalue {{.*}} i64 %[[arg1]], 1
+  // CHECK: insertvalue {{.*}} i32 20180515, 2
+  // CHECK: insertvalue {{.*}} i64 %[[arg2]], 7, 0, 1
+  // CHECK: insertvalue {{.*}} i64 %[[arg1]], 7, 0, 2
+  // CHECK: insertvalue {{.*}} ptr %[[arg0]], 0
+  %2 = fir.embox %arg0(%1) typeparams %arg1 : (!fir.ref<!fir.array<?x!fir.char<1,?>>>, !fir.shape<1>, index) -> !fir.box<!fir.array<?x!fir.char<1,?>>>
+  // CHECK: store {{.*}}, ptr %[[res]]
+  return %2 : !fir.box<!fir.array<?x!fir.char<1,?>>>
+}
+
+// Boxing of a static array of character of dynamic length
+// CHECK-LABEL: define void @b4(
+// CHECK-SAME: ptr %[[res:.*]], ptr %[[arg0:.*]], i64 %[[arg1:.*]])
+func.func @b4(%arg0 : !fir.ref<!fir.array<7x!fir.char<1,?>>>, %arg1 : index) -> !fir.box<!fir.array<7x!fir.char<1,?>>> {
+  %c_7 = arith.constant 7 : index
+  %1 = fir.shape %c_7 : (index) -> !fir.shape<1>
+  // CHECK: insertvalue {{.*}} i64 %[[arg1]], 1
+  // CHECK: insertvalue {{.*}} i32 20180515, 2
+  // CHECK: insertvalue {{.*}} i64 7, 7, 0, 1
+  // CHECK: insertvalue {{.*}} i64 %[[arg1]], 7, 0, 2
+  // CHECK: insertvalue {{.*}} ptr %[[arg0]], 0
+  %x = fir.embox %arg0(%1) typeparams %arg1 : (!fir.ref<!fir.array<7x!fir.char<1,?>>>, !fir.shape<1>, index) -> !fir.box<!fir.array<7x!fir.char<1,?>>>
+  // CHECK: store {{.*}}, ptr %[[res]]
+  return %x : !fir.box<!fir.array<7x!fir.char<1,?>>>
+}
+
+// Storing a fir.box into a fir.ref<fir.box> (modifying descriptors).
+// CHECK-LABEL: define void @b5(
+// CHECK-SAME: ptr %[[arg0:.*]], ptr %[[arg1:.*]])
+func.func @b5(%arg0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xf32>>>>, %arg1 : !fir.box<!fir.heap<!fir.array<?x?xf32>>>) {
+  fir.store %arg1 to %arg0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xf32>>>>
+  // CHECK: %[[boxLoad:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] }, ptr %[[arg1]]
+  // CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] } %[[boxLoad]], ptr %[[arg0]]
+  return
+}
+
+func.func private @callee6(!fir.box<none>) -> i32
+
+// CHECK-LABEL: define i32 @box6(
+// CHECK-SAME: ptr %[[ARG0:.*]], i64 %[[ARG1:.*]], i64 %[[ARG2:.*]])
+func.func @box6(%0 : !fir.ref<!fir.array<?x?x?x?xf32>>, %1 : index, %2 : index) -> i32 {
+  %c100 = arith.constant 100 : index
+  %c50 = arith.constant 50 : index
+  %c30 = arith.constant 30 : index
+  %c6 = arith.constant 6 : index
+  %shape = fir.shape %c100, %c50, %c30, %c6 : (index, index, index, index) -> !fir.shape<4>
+  %3 = fir.undefined index
+  %c41 = arith.constant 41 : index
+  %c2 = arith.constant 2 : index
+  %c24 = arith.constant 24 : index
+  %c1 = arith.constant 1 : index
+  %c3 = arith.constant 3 : index
+
+  // CHECK: %[[i:.*]] = sub i64 %[[ARG1]], 1
+  // CHECK: %[[i100:.*]] = mul i64 %[[i]], 100
+  // CHECK: %[[i100p40:.*]] = add i64 %[[i100]], 40
+  // CHECK: %[[
diff :.*]] = sub i64 %[[ARG2]], %[[ARG1]]
+  // CHECK: %[[dp2:.*]] = add i64 %[[
diff ]], 2
+  // CHECK: %[[sdp2:.*]] = sdiv i64 %[[dp2]], 2
+  // CHECK: %[[cmp:.*]] = icmp sgt i64 %[[sdp2]], 0
+  // CHECK: %[[extent:.*]] = select i1 %[[cmp]], i64 %[[sdp2]], i64 0
+  // CHECK: insertvalue { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] } { ptr undef, i64 4, i32 20180515, i8 2, i8 27, i8 0, i8 0, [2 x [3 x i64]] [{{\[}}3 x i64] [i64 1, i64 undef, i64 undef], [3 x i64] undef] }, i64 %[[extent]], 7, 0, 1
+  // CHECK: insertvalue { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] } %{{.*}}, i64 800, 7, 0, 2
+  // CHECK: %[[op25:.*]] = add i64 25000, %[[i100p40]]
+  // CHECK: insertvalue { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] } %{{.*}}, i64 1, 7, 1, 0
+  // CHECK: insertvalue { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] } %{{.*}}, i64 4, 7, 1, 1
+  // CHECK: insertvalue { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] } %{{.*}}, i64 120000, 7, 1, 2
+  // CHECK: %[[op300:.*]] = add i64 300000, %[[op25]]
+  // CHECK: %[[ptr:.*]] = getelementptr float, ptr %[[ARG0]], i64 %[[op300]]
+  // CHECK: insertvalue { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] } %{{.*}}, ptr %[[ptr]], 0
+  // CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [2 x [3 x i64]] } %{{.*}}, ptr %[[mem:[0-9]+]]
+
+
+  %slice = fir.slice %c41, %3, %3, %1, %2, %c2, %c6, %c24, %c6, %c3, %3, %3 : (index, index, index, index, index, index, index, index, index, index, index, index) -> !fir.slice<4>
+  %box = fir.embox %0(%shape)[%slice] : (!fir.ref<!fir.array<?x?x?x?xf32>>, !fir.shape<4>, !fir.slice<4>) -> !fir.box<!fir.array<?x?x?x?xf32>>
+  %nonebox = fir.convert %box : (!fir.box<!fir.array<?x?x?x?xf32>>) -> !fir.box<none>
+  // CHECK: %[[call:.*]] = call i32 @callee6(ptr %[[mem]])
+  %rv = fir.call @callee6(%nonebox) : (!fir.box<none>) -> i32
+  // CHECK: ret i32 %[[call]]
+  return %rv : i32
+}

diff  --git a/flang/test/Fir/boxproc.fir b/flang/test/Fir/boxproc.fir
new file mode 100644
index 000000000000..128f6e0b252e
--- /dev/null
+++ b/flang/test/Fir/boxproc.fir
@@ -0,0 +1,319 @@
+// RUN: tco %s | FileCheck %s
+
+// CHECK-LABEL: define void @_QPtest_proc_dummy()
+// CHECK:         %[[VAL_0:.*]] = alloca i32, i64 1, align 4
+// CHECK:         %[[VAL_1:.*]] = alloca { ptr }, i64 1, align 8
+// CHECK:         %[[VAL_2:.*]] = getelementptr { ptr }, ptr %[[VAL_1]], i64 0, i32 0
+// CHECK:         store ptr %[[VAL_0]], ptr %[[VAL_2]], align 8
+// CHECK:         store i32 1, ptr %[[VAL_0]], align 4
+// CHECK:         %[[VAL_3:.*]] = alloca [32 x i8], i64 1, align 1
+// CHECK:         call void @llvm.init.trampoline(ptr %[[VAL_3]], ptr @_QFtest_proc_dummyPtest_proc_dummy_a, ptr %[[VAL_1]])
+// CHECK:         %[[VAL_6:.*]] = call ptr @llvm.adjust.trampoline(ptr %[[VAL_3]])
+// CHECK:         call void @_QPtest_proc_dummy_other(ptr %[[VAL_6]])
+
+// CHECK-LABEL: define void @_QFtest_proc_dummyPtest_proc_dummy_a(ptr
+// CHECK-SAME:              %[[VAL_0:.*]], ptr nest %[[VAL_1:.*]])
+
+// CHECK-LABEL: define void @_QPtest_proc_dummy_other(ptr
+// CHECK-SAME:              %[[VAL_0:.*]])
+// CHECK:         %[[VAL_1:.*]] = alloca i32, i64 1, align 4
+// CHECK:         store i32 4, ptr %[[VAL_1]], align 4
+// CHECK:         call void %[[VAL_0]](ptr %[[VAL_1]])
+
+func.func @_QPtest_proc_dummy() {
+  %c0_i32 = arith.constant 0 : i32
+  %c1_i32 = arith.constant 1 : i32
+  %c-1_i32 = arith.constant -1 : i32
+  %c5_i32 = arith.constant 5 : i32
+  %0 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFtest_proc_dummyEi"}
+  %1 = fir.alloca tuple<!fir.ref<i32>>
+  %2 = fir.coordinate_of %1, %c0_i32 : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
+  fir.store %0 to %2 : !fir.llvm_ptr<!fir.ref<i32>>
+  fir.store %c1_i32 to %0 : !fir.ref<i32>
+  %3 = fir.address_of(@_QFtest_proc_dummyPtest_proc_dummy_a) : (!fir.ref<i32>, !fir.ref<tuple<!fir.ref<i32>>>) -> ()
+  %4 = fir.emboxproc %3, %1 : ((!fir.ref<i32>, !fir.ref<tuple<!fir.ref<i32>>>) -> (), !fir.ref<tuple<!fir.ref<i32>>>) -> !fir.boxproc<() -> ()>
+  fir.call @_QPtest_proc_dummy_other(%4) : (!fir.boxproc<() -> ()>) -> ()
+  %5 = fir.address_of(@_QQcl.2E2F682E66393000) : !fir.ref<!fir.char<1,8>>
+  %6 = fir.convert %5 : (!fir.ref<!fir.char<1,8>>) -> !fir.ref<i8>
+  %7 = fir.call @_FortranAioBeginExternalListOutput(%c-1_i32, %6, %c5_i32) : (i32, !fir.ref<i8>, i32) -> !fir.ref<i8>
+  %8 = fir.load %0 : !fir.ref<i32>
+  %9 = fir.call @_FortranAioOutputInteger32(%7, %8) : (!fir.ref<i8>, i32) -> i1
+  %10 = fir.call @_FortranAioEndIoStatement(%7) : (!fir.ref<i8>) -> i32
+  return
+}
+func.func @_QFtest_proc_dummyPtest_proc_dummy_a(%arg0: !fir.ref<i32> {fir.bindc_name = "j"}, %arg1: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) {
+  %c0_i32 = arith.constant 0 : i32
+  %0 = fir.coordinate_of %arg1, %c0_i32 : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
+  %1 = fir.load %0 : !fir.llvm_ptr<!fir.ref<i32>>
+  %2 = fir.load %1 : !fir.ref<i32>
+  %3 = fir.load %arg0 : !fir.ref<i32>
+  %4 = arith.addi %2, %3 : i32
+  fir.store %4 to %1 : !fir.ref<i32>
+  return
+}
+func.func @_QPtest_proc_dummy_other(%arg0: !fir.boxproc<() -> ()>) {
+  %c4_i32 = arith.constant 4 : i32
+  %0 = fir.alloca i32 {adapt.valuebyref}
+  fir.store %c4_i32 to %0 : !fir.ref<i32>
+  %1 = fir.box_addr %arg0 : (!fir.boxproc<() -> ()>) -> ((!fir.ref<i32>) -> ())
+  fir.call %1(%0) : (!fir.ref<i32>) -> ()
+  return
+}
+
+// CHECK-LABEL: define void @_QPtest_proc_dummy_char()
+// CHECK:         %[[VAL_0:.*]] = alloca [40 x i8], i64 1, align 1
+// CHECK:         %[[VAL_1:.*]] = alloca [10 x i8], i64 1, align 1
+// CHECK:         %[[VAL_2:.*]] = alloca { { ptr, i64 } }, i64 1, align 8
+// CHECK:         %[[VAL_3:.*]] = getelementptr { { ptr, i64 } }, ptr %[[VAL_2]], i64 0, i32 0
+// CHECK:         %[[VAL_5:.*]] = insertvalue { ptr, i64 } undef, ptr %[[VAL_1]], 0
+// CHECK:         %[[VAL_6:.*]] = insertvalue { ptr, i64 } %[[VAL_5]], i64 10, 1
+// CHECK:         store { ptr, i64 } %[[VAL_6]], ptr %[[VAL_3]], align 8
+// CHECK:         call void @llvm.memmove.p0.p0.i64(ptr %[[VAL_1]], ptr
+// CHECK:         br label %[[VAL_8:.*]]
+// CHECK:         %[[VAL_11:.*]] = phi 
+// CHECK:         %[[VAL_13:.*]] = phi 
+// CHECK:         %[[VAL_15:.*]] = icmp sgt i64 %[[VAL_13]], 0
+// CHECK:         %[[VAL_18:.*]] = getelementptr [10 x [1 x i8]], ptr %[[VAL_1]], i64 0, i64 %[[VAL_11]]
+// CHECK:         store [1 x i8] c" ", ptr %[[VAL_18]], align 1
+// CHECK:         %[[VAL_20:.*]] = alloca [32 x i8], i64 1, align 1
+// CHECK:         call void @llvm.init.trampoline(ptr %[[VAL_20]], ptr @_QFtest_proc_dummy_charPgen_message, ptr %[[VAL_2]])
+// CHECK:         %[[VAL_23:.*]] = call ptr @llvm.adjust.trampoline(ptr %[[VAL_20]])
+// CHECK:         %[[VAL_25:.*]] = insertvalue { ptr, i64 } undef, ptr %[[VAL_23]], 0
+// CHECK:         %[[VAL_26:.*]] = insertvalue { ptr, i64 } %[[VAL_25]], i64 10, 1
+// CHECK:         %[[VAL_27:.*]] = call ptr @llvm.stacksave()
+// CHECK:         %[[VAL_28:.*]] = extractvalue { ptr, i64 } %[[VAL_26]], 0
+// CHECK:         %[[VAL_29:.*]] = extractvalue { ptr, i64 } %[[VAL_26]], 1
+// CHECK:         %[[VAL_30:.*]] = call { ptr, i64 } @_QPget_message(ptr %[[VAL_0]], i64 40, ptr %[[VAL_28]], i64 %[[VAL_29]])
+// CHECK:         %[[VAL_32:.*]] = call i1 @_FortranAioOutputAscii(ptr %{{.*}}, ptr %[[VAL_0]], i64 40)
+// CHECK:         call void @llvm.stackrestore(ptr %[[VAL_27]])
+
+// CHECK-LABEL: define { ptr, i64 } @_QFtest_proc_dummy_charPgen_message(ptr
+// CHECK-SAME:                %[[VAL_0:.*]], i64 %[[VAL_1:.*]], ptr nest %[[VAL_2:.*]])
+// CHECK:         %[[VAL_3:.*]] = getelementptr { { ptr, i64 } }, ptr %[[VAL_2]], i64 0, i32 0
+// CHECK:         %[[VAL_4:.*]] = load { ptr, i64 }, ptr %[[VAL_3]], align 8
+// CHECK:         %[[VAL_5:.*]] = extractvalue { ptr, i64 } %[[VAL_4]], 0
+// CHECK:         %[[VAL_6:.*]] = extractvalue { ptr, i64 } %[[VAL_4]], 1
+// CHECK:         %[[VAL_8:.*]] = icmp slt i64 10, %[[VAL_6]]
+// CHECK:         %[[VAL_9:.*]] = select i1 %[[VAL_8]], i64 10, i64 %[[VAL_6]]
+// CHECK:         call void @llvm.memmove.p0.p0.i64(ptr %[[VAL_0]], ptr %[[VAL_5]], i64 %[[VAL_9]], i1 false)
+// CHECK:         %[[VAL_10:.*]] = sub i64 10, %[[VAL_9]]
+// CHECK:         br label %[[VAL_11:.*]]
+// CHECK:         %[[VAL_14:.*]] = phi i64
+// CHECK:         %[[VAL_16:.*]] = phi i64
+// CHECK:         %[[VAL_18:.*]] = icmp sgt i64 %[[VAL_16]], 0
+// CHECK:         %[[VAL_21:.*]] = getelementptr [1 x i8], ptr %[[VAL_0]], i64 %[[VAL_14]]
+// CHECK:         store [1 x i8] c" ", ptr %[[VAL_21]], align 1
+// CHECK:         %[[VAL_22:.*]] = insertvalue { ptr, i64 } undef, ptr %[[VAL_0]], 0
+// CHECK:         %[[VAL_23:.*]] = insertvalue { ptr, i64 } %[[VAL_22]], i64 10, 1
+// CHECK:         ret { ptr, i64 } %[[VAL_23]]
+// CHECK:       }
+
+// CHECK-LABEL: define { ptr, i64 } @_QPget_message(ptr
+// CHECK-SAME:                  %[[VAL_0:.*]], i64 %[[VAL_1:.*]], ptr %[[VAL_2:.*]], i64
+// CHECK-SAME:                                                 %[[VAL_3:.*]])
+// CHECK:         %[[VAL_4:.*]] = insertvalue { ptr, i64 } undef, ptr %[[VAL_2]], 0
+// CHECK:         %[[VAL_5:.*]] = insertvalue { ptr, i64 } %[[VAL_4]], i64 %[[VAL_3]], 1
+// CHECK:         %[[VAL_7:.*]] = extractvalue { ptr, i64 } %[[VAL_5]], 0
+// CHECK:         %[[VAL_8:.*]] = extractvalue { ptr, i64 } %[[VAL_5]], 1
+// CHECK:         %[[VAL_9:.*]] = call ptr @llvm.stacksave()
+// CHECK:         %[[VAL_10:.*]] = alloca i8, i64 %[[VAL_8]], align 1
+// CHECK:         %[[VAL_12:.*]] = call { ptr, i64 } %[[VAL_7]](ptr %[[VAL_10]], i64 %[[VAL_8]])
+// CHECK:         %[[VAL_13:.*]] = add i64 %[[VAL_8]], 12
+// CHECK:         %[[VAL_14:.*]] = alloca i8, i64 %[[VAL_13]], align 1
+// CHECK:         call void @llvm.memmove.p0.p0.i64(ptr %[[VAL_14]], ptr {{.*}}, i64 12, i1 false)
+// CHECK:         %[[VAL_18:.*]] = phi i64
+// CHECK:         %[[VAL_20:.*]] = phi i64
+// CHECK:         %[[VAL_22:.*]] = icmp sgt i64 %[[VAL_20]], 0
+// CHECK:         %[[VAL_24:.*]] = sub i64 %[[VAL_18]], 12
+// CHECK:         %[[VAL_26:.*]] = getelementptr [1 x i8], ptr %[[VAL_10]], i64 %[[VAL_24]]
+// CHECK:         %[[VAL_27:.*]] = load [1 x i8], ptr %[[VAL_26]], align 1
+// CHECK:         %[[VAL_29:.*]] = getelementptr [1 x i8], ptr %[[VAL_14]], i64 %[[VAL_18]]
+// CHECK:         store [1 x i8] %[[VAL_27]], ptr %[[VAL_29]], align 1
+// CHECK:         %[[VAL_30:.*]] = icmp slt i64 40, %[[VAL_13]]
+// CHECK:         %[[VAL_31:.*]] =  select i1 %[[VAL_30]], i64 40, i64 %[[VAL_13]]
+// CHECK:         call void @llvm.memmove.p0.p0.i64(ptr %[[VAL_0]], ptr %[[VAL_14]], i64 %[[VAL_31]], i1 false)
+// CHECK:         %[[VAL_32:.*]] = sub i64 40, %[[VAL_31]]
+// CHECK:         %[[VAL_35:.*]] = phi i64
+// CHECK:         %[[VAL_37:.*]] = phi i64
+// CHECK:         %[[VAL_39:.*]] = icmp sgt i64 %[[VAL_37]], 0
+// CHECK:         %[[VAL_42:.*]] = getelementptr [1 x i8], ptr %[[VAL_0]], i64 %[[VAL_35]]
+// CHECK:         store [1 x i8] c" ", ptr %[[VAL_42]], align 1
+// CHECK:         call void @llvm.stackrestore(ptr %[[VAL_9]])
+// CHECK:         %[[VAL_43:.*]] = insertvalue { ptr, i64 } undef, ptr %[[VAL_0]], 0
+// CHECK:         %[[VAL_44:.*]] = insertvalue { ptr, i64 } %[[VAL_43]], i64 40, 1
+// CHECK:         ret { ptr, i64 } %[[VAL_44]]
+// CHECK:       }
+
+func.func @_QPtest_proc_dummy_char() {
+  %c10 = arith.constant 10 : index
+  %c0_i32 = arith.constant 0 : i32
+  %c9 = arith.constant 9 : index
+  %false = arith.constant false
+  %c1 = arith.constant 1 : index
+  %c32_i8 = arith.constant 32 : i8
+  %c-1_i32 = arith.constant -1 : i32
+  %c6_i32 = arith.constant 6 : i32
+  %c10_i64 = arith.constant 10 : i64
+  %c40 = arith.constant 40 : index
+  %c0 = arith.constant 0 : index
+  %0 = fir.alloca !fir.char<1,40> {bindc_name = ".result"}
+  %1 = fir.alloca !fir.char<1,10> {bindc_name = "message", uniq_name = "_QFtest_proc_dummy_charEmessage"}
+  %2 = fir.alloca tuple<!fir.boxchar<1>>
+  %3 = fir.coordinate_of %2, %c0_i32 : (!fir.ref<tuple<!fir.boxchar<1>>>, i32) -> !fir.ref<!fir.boxchar<1>>
+  %4 = fir.convert %1 : (!fir.ref<!fir.char<1,10>>) -> !fir.ref<!fir.char<1,?>>
+  %5 = fir.emboxchar %4, %c10 : (!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1>
+  fir.store %5 to %3 : !fir.ref<!fir.boxchar<1>>
+  %6 = fir.address_of(@_QQcl.486920746865726521) : !fir.ref<!fir.char<1,9>>
+  %7 = fir.convert %c9 : (index) -> i64
+  %8 = fir.convert %1 : (!fir.ref<!fir.char<1,10>>) -> !fir.ref<i8>
+  %9 = fir.convert %6 : (!fir.ref<!fir.char<1,9>>) -> !fir.ref<i8>
+  fir.call @llvm.memmove.p0.p0.i64(%8, %9, %7, %false) : (!fir.ref<i8>, !fir.ref<i8>, i64, i1) -> ()
+  %10 = fir.undefined !fir.char<1>
+  %11 = fir.insert_value %10, %c32_i8, [0 : index] : (!fir.char<1>, i8) -> !fir.char<1>
+  cf.br ^bb1(%c9, %c1 : index, index)
+^bb1(%12: index, %13: index):  // 2 preds: ^bb0, ^bb2
+  %14 = arith.cmpi sgt, %13, %c0 : index
+  cf.cond_br %14, ^bb2, ^bb3
+^bb2:  // pred: ^bb1
+  %15 = fir.convert %1 : (!fir.ref<!fir.char<1,10>>) -> !fir.ref<!fir.array<10x!fir.char<1>>>
+  %16 = fir.coordinate_of %15, %12 : (!fir.ref<!fir.array<10x!fir.char<1>>>, index) -> !fir.ref<!fir.char<1>>
+  fir.store %11 to %16 : !fir.ref<!fir.char<1>>
+  %17 = arith.addi %12, %c1 : index
+  %18 = arith.subi %13, %c1 : index
+  cf.br ^bb1(%17, %18 : index, index)
+^bb3:  // pred: ^bb1
+  %19 = fir.address_of(@_QQcl.2E2F682E66393000) : !fir.ref<!fir.char<1,8>>
+  %20 = fir.convert %19 : (!fir.ref<!fir.char<1,8>>) -> !fir.ref<i8>
+  %21 = fir.call @_FortranAioBeginExternalListOutput(%c-1_i32, %20, %c6_i32) : (i32, !fir.ref<i8>, i32) -> !fir.ref<i8>
+  %22 = fir.address_of(@_QFtest_proc_dummy_charPgen_message) : (!fir.ref<!fir.char<1,10>>, index, !fir.ref<tuple<!fir.boxchar<1>>>) -> !fir.boxchar<1>
+  %23 = fir.emboxproc %22, %2 : ((!fir.ref<!fir.char<1,10>>, index, !fir.ref<tuple<!fir.boxchar<1>>>) -> !fir.boxchar<1>, !fir.ref<tuple<!fir.boxchar<1>>>) -> !fir.boxproc<() -> ()>
+  %24 = fir.undefined tuple<!fir.boxproc<() -> ()>, i64>
+  %25 = fir.insert_value %24, %23, [0 : index] : (tuple<!fir.boxproc<() -> ()>, i64>, !fir.boxproc<() -> ()>) -> tuple<!fir.boxproc<() -> ()>, i64>
+  %26 = fir.insert_value %25, %c10_i64, [1 : index] : (tuple<!fir.boxproc<() -> ()>, i64>, i64) -> tuple<!fir.boxproc<() -> ()>, i64>
+  %27 = fir.call @llvm.stacksave() : () -> !fir.ref<i8>
+  %28 = fir.call @_QPget_message(%0, %c40, %26) : (!fir.ref<!fir.char<1,40>>, index, tuple<!fir.boxproc<() -> ()>, i64>) -> !fir.boxchar<1>
+  %29 = fir.convert %0 : (!fir.ref<!fir.char<1,40>>) -> !fir.ref<i8>
+  %30 = fir.convert %c40 : (index) -> i64
+  %31 = fir.call @_FortranAioOutputAscii(%21, %29, %30) : (!fir.ref<i8>, !fir.ref<i8>, i64) -> i1
+  fir.call @llvm.stackrestore(%27) : (!fir.ref<i8>) -> ()
+  %32 = fir.call @_FortranAioEndIoStatement(%21) : (!fir.ref<i8>) -> i32
+  return
+}
+func.func @_QFtest_proc_dummy_charPgen_message(%arg0: !fir.ref<!fir.char<1,10>>, %arg1: index, %arg2: !fir.ref<tuple<!fir.boxchar<1>>> {fir.host_assoc}) -> !fir.boxchar<1> {
+  %c0_i32 = arith.constant 0 : i32
+  %c10 = arith.constant 10 : index
+  %false = arith.constant false
+  %c1 = arith.constant 1 : index
+  %c32_i8 = arith.constant 32 : i8
+  %c0 = arith.constant 0 : index
+  %0 = fir.coordinate_of %arg2, %c0_i32 : (!fir.ref<tuple<!fir.boxchar<1>>>, i32) -> !fir.ref<!fir.boxchar<1>>
+  %1 = fir.load %0 : !fir.ref<!fir.boxchar<1>>
+  %2:2 = fir.unboxchar %1 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
+  %3 = fir.convert %arg0 : (!fir.ref<!fir.char<1,10>>) -> !fir.ref<!fir.char<1,?>>
+  %4 = arith.cmpi slt, %c10, %2#1 : index
+  %5 = arith.select %4, %c10, %2#1 : index
+  %6 = fir.convert %5 : (index) -> i64
+  %7 = fir.convert %3 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
+  %8 = fir.convert %2#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
+  fir.call @llvm.memmove.p0.p0.i64(%7, %8, %6, %false) : (!fir.ref<i8>, !fir.ref<i8>, i64, i1) -> ()
+  %9 = fir.undefined !fir.char<1>
+  %10 = fir.insert_value %9, %c32_i8, [0 : index] : (!fir.char<1>, i8) -> !fir.char<1>
+  %11 = arith.subi %c10, %5 : index
+  cf.br ^bb1(%5, %11 : index, index)
+^bb1(%12: index, %13: index):  // 2 preds: ^bb0, ^bb2
+  %14 = arith.cmpi sgt, %13, %c0 : index
+  cf.cond_br %14, ^bb2, ^bb3
+^bb2:  // pred: ^bb1
+  %15 = fir.convert %3 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.array<?x!fir.char<1>>>
+  %16 = fir.coordinate_of %15, %12 : (!fir.ref<!fir.array<?x!fir.char<1>>>, index) -> !fir.ref<!fir.char<1>>
+  fir.store %10 to %16 : !fir.ref<!fir.char<1>>
+  %17 = arith.addi %12, %c1 : index
+  %18 = arith.subi %13, %c1 : index
+  cf.br ^bb1(%17, %18 : index, index)
+^bb3:  // pred: ^bb1
+  %19 = fir.emboxchar %3, %c10 : (!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1>
+  return %19 : !fir.boxchar<1>
+}
+func.func @_QPget_message(%arg0: !fir.ref<!fir.char<1,40>>, %arg1: index, %arg2: tuple<!fir.boxproc<() -> ()>, i64> {fir.char_proc}) -> !fir.boxchar<1> {
+  %c40 = arith.constant 40 : index
+  %c12 = arith.constant 12 : index
+  %false = arith.constant false
+  %c1 = arith.constant 1 : index
+  %c32_i8 = arith.constant 32 : i8
+  %c0 = arith.constant 0 : index
+  %0 = fir.convert %arg0 : (!fir.ref<!fir.char<1,40>>) -> !fir.ref<!fir.char<1,?>>
+  %1 = fir.address_of(@_QQcl.6D6573736167652069733A20) : !fir.ref<!fir.char<1,12>>
+  %2 = fir.extract_value %arg2, [0 : index] : (tuple<!fir.boxproc<() -> ()>, i64>) -> !fir.boxproc<() -> ()>
+  %3 = fir.box_addr %2 : (!fir.boxproc<() -> ()>) -> (() -> ())
+  %4 = fir.extract_value %arg2, [1 : index] : (tuple<!fir.boxproc<() -> ()>, i64>) -> i64
+  %5 = fir.call @llvm.stacksave() : () -> !fir.ref<i8>
+  %6 = fir.alloca !fir.char<1,?>(%4 : i64) {bindc_name = ".result"}
+  %7 = fir.convert %3 : (() -> ()) -> ((!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1>)
+  %8 = fir.convert %4 : (i64) -> index
+  %9 = fir.call %7(%6, %8) : (!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1>
+  %10 = arith.addi %8, %c12 : index
+  %11 = fir.alloca !fir.char<1,?>(%10 : index) {bindc_name = ".chrtmp"}
+  %12 = fir.convert %c12 : (index) -> i64
+  %13 = fir.convert %11 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
+  %14 = fir.convert %1 : (!fir.ref<!fir.char<1,12>>) -> !fir.ref<i8>
+  fir.call @llvm.memmove.p0.p0.i64(%13, %14, %12, %false) : (!fir.ref<i8>, !fir.ref<i8>, i64, i1) -> ()
+  cf.br ^bb1(%c12, %8 : index, index)
+^bb1(%15: index, %16: index):  // 2 preds: ^bb0, ^bb2
+  %17 = arith.cmpi sgt, %16, %c0 : index
+  cf.cond_br %17, ^bb2, ^bb3
+^bb2:  // pred: ^bb1
+  %18 = arith.subi %15, %c12 : index
+  %19 = fir.convert %6 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.array<?x!fir.char<1>>>
+  %20 = fir.coordinate_of %19, %18 : (!fir.ref<!fir.array<?x!fir.char<1>>>, index) -> !fir.ref<!fir.char<1>>
+  %21 = fir.load %20 : !fir.ref<!fir.char<1>>
+  %22 = fir.convert %11 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.array<?x!fir.char<1>>>
+  %23 = fir.coordinate_of %22, %15 : (!fir.ref<!fir.array<?x!fir.char<1>>>, index) -> !fir.ref<!fir.char<1>>
+  fir.store %21 to %23 : !fir.ref<!fir.char<1>>
+  %24 = arith.addi %15, %c1 : index
+  %25 = arith.subi %16, %c1 : index
+  cf.br ^bb1(%24, %25 : index, index)
+^bb3:  // pred: ^bb1
+  %26 = arith.cmpi slt, %c40, %10 : index
+  %27 = arith.select %26, %c40, %10 : index
+  %28 = fir.convert %27 : (index) -> i64
+  %29 = fir.convert %0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
+  fir.call @llvm.memmove.p0.p0.i64(%29, %13, %28, %false) : (!fir.ref<i8>, !fir.ref<i8>, i64, i1) -> ()
+  %30 = fir.undefined !fir.char<1>
+  %31 = fir.insert_value %30, %c32_i8, [0 : index] : (!fir.char<1>, i8) -> !fir.char<1>
+  %32 = arith.subi %c40, %27 : index
+  cf.br ^bb4(%27, %32 : index, index)
+^bb4(%33: index, %34: index):  // 2 preds: ^bb3, ^bb5
+  %35 = arith.cmpi sgt, %34, %c0 : index
+  cf.cond_br %35, ^bb5, ^bb6
+^bb5:  // pred: ^bb4
+  %36 = fir.convert %0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.array<?x!fir.char<1>>>
+  %37 = fir.coordinate_of %36, %33 : (!fir.ref<!fir.array<?x!fir.char<1>>>, index) -> !fir.ref<!fir.char<1>>
+  fir.store %31 to %37 : !fir.ref<!fir.char<1>>
+  %38 = arith.addi %33, %c1 : index
+  %39 = arith.subi %34, %c1 : index
+  cf.br ^bb4(%38, %39 : index, index)
+^bb6:  // pred: ^bb4
+  fir.call @llvm.stackrestore(%5) : (!fir.ref<i8>) -> ()
+  %40 = fir.emboxchar %0, %c40 : (!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1>
+  return %40 : !fir.boxchar<1>
+}
+fir.global linkonce @_QQcl.486920746865726521 constant : !fir.char<1,9> {
+  %0 = fir.string_lit "Hi there!"(9) : !fir.char<1,9>
+  fir.has_value %0 : !fir.char<1,9>
+}
+func.func private @llvm.memmove.p0.p0.i64(!fir.ref<i8>, !fir.ref<i8>, i64, i1)
+fir.global linkonce @_QQcl.2E2F682E66393000 constant : !fir.char<1,8> {
+  %0 = fir.string_lit "./h.f90\00"(8) : !fir.char<1,8>
+  fir.has_value %0 : !fir.char<1,8>
+}
+func.func private @llvm.stacksave() -> !fir.ref<i8>
+func.func private @llvm.stackrestore(!fir.ref<i8>)
+fir.global linkonce @_QQcl.6D6573736167652069733A20 constant : !fir.char<1,12> {
+  %0 = fir.string_lit "message is: "(12) : !fir.char<1,12>
+  fir.has_value %0 : !fir.char<1,12>
+}
+
+func.func private @_FortranAioOutputAscii(!fir.ref<i8>, !fir.ref<i8>, i64) -> i1 attributes {fir.io, fir.runtime}
+func.func private @_FortranAioBeginExternalListOutput(i32, !fir.ref<i8>, i32) -> !fir.ref<i8> attributes {fir.io, fir.runtime}
+func.func private @_FortranAioOutputInteger32(!fir.ref<i8>, i32) -> i1 attributes {fir.io, fir.runtime}
+func.func private @_FortranAioEndIoStatement(!fir.ref<i8>) -> i32 attributes {fir.io, fir.runtime}

diff  --git a/flang/test/Fir/char01.fir b/flang/test/Fir/char01.fir
new file mode 100644
index 000000000000..ec8c63f540a2
--- /dev/null
+++ b/flang/test/Fir/char01.fir
@@ -0,0 +1,14 @@
+// RUN: fir-opt %s | tco | FileCheck %s
+
+// CHECK-LABEL: @test
+func.func @test(%arg0 : !fir.ref<!fir.char<1>>, %arg1 : !fir.ref<!fir.char<1,?>>, %arg2 : i32) {
+  %0 = fir.convert %arg1 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.array<?x!fir.char<1>>>
+  // CHECK: getelementptr [1 x i8], ptr
+  %1 = fir.coordinate_of %0, %arg2 : (!fir.ref<!fir.array<?x!fir.char<1>>>, i32) -> !fir.ref<!fir.char<1>>
+  // CHECK: load [1 x i8], ptr
+  %2 = fir.load %1 : !fir.ref<!fir.char<1>>
+  // CHECK: store [1 x i8]
+  fir.store %2 to %arg0 : !fir.ref<!fir.char<1>>
+  // CHECK: ret void
+  return
+}

diff  --git a/flang/test/Fir/commute.fir b/flang/test/Fir/commute.fir
new file mode 100644
index 000000000000..be25fd61953d
--- /dev/null
+++ b/flang/test/Fir/commute.fir
@@ -0,0 +1,34 @@
+// RUN: fir-opt %s | tco | FileCheck %s
+
+// CHECK-LABEL: define i32 @f1(i32 %0, i32 %1)
+func.func @f1(%a : i32, %b : i32) -> i32 {
+
+  // CHECK: %[[reg3:.*]] = add i32 %0, %1
+  %1 = arith.addi %a, %b : i32
+  %2 = arith.addi %b, %a : i32
+  // CHECK:  mul i32 %[[reg3]], %[[reg3]]
+  %3 = arith.muli %1, %2 : i32
+  return %3 : i32
+}
+
+// CHECK-LABEL: define i32 @f2(ptr %0)
+func.func @f2(%a : !fir.ref<i32>) -> i32 {
+  %1 = fir.load %a : !fir.ref<i32>
+  // CHECK: %[[r2:.*]] = load
+  %2 = fir.load %a : !fir.ref<i32>
+  // CHECK: %[[r3:.*]] = add i32 %[[r2]], %[[r2]]
+  %3 = arith.addi %1, %2 : i32
+  %4 = fir.load %a : !fir.ref<i32>
+  // CHECK: %[[r4:.*]] = add i32 %[[r3]], %[[r2]]
+  %5 = arith.addi %3, %4 : i32
+  %6 = fir.load %a : !fir.ref<i32>
+  // CHECK: %[[r5:.*]] = add i32 %[[r4]], %[[r2]]
+  %7 = arith.addi %5, %6 : i32
+  %8 = fir.load %a : !fir.ref<i32>
+  // CHECK: %[[r6:.*]] = add i32 %[[r5]], %[[r2]]
+  %9 = arith.addi %7, %8 : i32
+  %10 = fir.load %a : !fir.ref<i32>
+  // CHECK: %[[r7:.*]] = add i32 %[[r2]], %[[r6]]
+  %11 = arith.addi %10, %9 : i32
+  return %11 : i32
+}

diff  --git a/flang/test/Fir/compare.fir b/flang/test/Fir/compare.fir
new file mode 100644
index 000000000000..045a50d6bec7
--- /dev/null
+++ b/flang/test/Fir/compare.fir
@@ -0,0 +1,17 @@
+// RUN: fir-opt %s | tco --target=x86_64-unknown-linux-gnu | FileCheck %s
+
+// CHECK-LABEL: define i1 @cmp3(<2 x float> %0, <2 x float> %1)
+func.func @cmp3(%a : !fir.complex<4>, %b : !fir.complex<4>) -> i1 {
+  // CHECK: fcmp oeq float
+  %1 = fir.cmpc "oeq", %a, %b : !fir.complex<4>
+  return %1 : i1
+}
+
+// CHECK-LABEL: define { double, double } @neg3(double %0, double %1)
+func.func @neg3(%a : !fir.complex<8>) -> !fir.complex<8> {
+  // CHECK: %[[g2:.*]] = insertvalue { double, double } %
+  // CHECK: %[[r3:.*]] = fneg double
+  // CHECK: insertvalue { double, double } %[[g2]], double %[[r3]]
+  %1 = fir.negc %a : !fir.complex<8>
+  return %1 : !fir.complex<8>
+}

diff  --git a/flang/test/Fir/constant.fir b/flang/test/Fir/constant.fir
new file mode 100644
index 000000000000..380c6121acf9
--- /dev/null
+++ b/flang/test/Fir/constant.fir
@@ -0,0 +1,25 @@
+// RUN: fir-opt %s | tco | FileCheck %s
+
+// CHECK-LABEL: define [3 x i8] @x
+func.func @x() -> !fir.char<1,3> {
+  %1 = fir.string_lit "xyz"(3) : !fir.char<1,3>
+ // CHECK: ret [3 x i8] c"xyz"
+  return %1 : !fir.char<1,3>
+}
+
+// CHECK-LABEL: define x86_fp80 @y()
+func.func @y() -> !fir.real<10> {
+ %c1 = arith.constant 42.4 :f32
+ %0 = fir.convert %c1 : (f32) -> !fir.real<10>
+  // CHECK: ret x86_fp80 0xK4004A9999A0000000000
+  // TODO: What's that number?
+  return %0 : !fir.real<10>
+}
+
+// CHECK-LABEL: define i16 @z()
+func.func @z() -> !fir.logical<2> {
+  %1 = arith.constant true
+  %0 = fir.convert %1 : (i1) -> !fir.logical<2>
+ // CHECK-LABEL: ret i16 1
+  return %0 : !fir.logical<2>
+}

diff  --git a/flang/test/Fir/convert-to-llvm-invalid.fir b/flang/test/Fir/convert-to-llvm-invalid.fir
index 65a52f492486..7cba7fc55b8e 100644
--- a/flang/test/Fir/convert-to-llvm-invalid.fir
+++ b/flang/test/Fir/convert-to-llvm-invalid.fir
@@ -91,6 +91,13 @@ func.func @bar_select_type(%arg : !fir.box<!fir.ref<f32>>) -> i32 {
 
 // -----
 
+// Verify that `fir.dt_entry` requires a parent op
+
+// expected-error at +1{{'fir.dt_entry' op expects parent op 'fir.dispatch_table'}}
+fir.dt_entry "method", @method_impl
+
+// -----
+
 // `fir.coordinate_of` - dynamically sized arrays are not supported
 func.func @coordinate_of_dynamic_array(%arg0: !fir.ref<!fir.array<1x!fir.char<4,?>>>, %arg1: index) {
   // expected-error at +2{{fir.coordinate_of with a dynamic element size is unsupported}}

diff  --git a/flang/test/Fir/convert.fir b/flang/test/Fir/convert.fir
new file mode 100644
index 000000000000..ef9242ef1d8b
--- /dev/null
+++ b/flang/test/Fir/convert.fir
@@ -0,0 +1,13 @@
+// RUN: tco --target=x86_64-unknown-linux-gnu %s | FileCheck %s
+
+// CHECK-LABEL: define { double, double } @c(<2 x float> %
+func.func @c(%x : !fir.complex<4>) -> !fir.complex<8> {
+// CHECK: %[[R:.*]] = extractvalue { float, float } %{{.*}}, 0
+// CHECK: %[[I:.*]] = extractvalue { float, float } %{{.*}}, 1
+// CHECK: %[[CR:.*]] = fpext float %[[R]] to double
+// CHECK: %[[CI:.*]] = fpext float %[[I]] to double
+// CHECK: %[[X:.*]] = insertvalue { double, double } undef, double %[[CR]], 0
+// CHECK: insertvalue { double, double } %[[X]], double %[[CI]], 1
+  %1 = fir.convert %x : (!fir.complex<4>) -> !fir.complex<8>
+  return %1 : !fir.complex<8>
+}

diff  --git a/flang/test/Fir/external-mangling.fir b/flang/test/Fir/external-mangling.fir
index 013a27d8eb1f..9e26e96eac9d 100644
--- a/flang/test/Fir/external-mangling.fir
+++ b/flang/test/Fir/external-mangling.fir
@@ -1,4 +1,6 @@
 // RUN: fir-opt --external-name-interop %s | FileCheck %s
+// RUN: tco --external-name-interop %s | FileCheck %s
+// RUN: tco --external-name-interop %s | tco --fir-to-llvm-ir | FileCheck %s --check-prefix=LLVMIR
 
 func.func @_QPfoo() {  
   %c0 = arith.constant 0 : index
@@ -27,3 +29,13 @@ func.func private @_QPbar2(!fir.ref<f32>)
 // CHECK: fir.global common @a_(dense<0> : vector<4xi8>) : !fir.array<4xi8>
 // CHECK: fir.global common @__BLNK__(dense<0> : vector<4xi8>) : !fir.array<4xi8>
 // CHECK: func private @bar_(!fir.ref<i32>)
+
+// LLVMIR: %{{.*}} = llvm.mlir.addressof @a_ : !llvm.ptr<array<4 x i8>>
+// LLVMIR: %{{.*}} = llvm.mlir.addressof @__BLNK__ : !llvm.ptr<array<4 x i8>>
+// LLVMIR: llvm.call @bar_(%{{.*}}) : (!llvm.ptr<i32>) -> ()
+// LLVMIR: llvm.call @bar2_(%{{.*}}) : (!llvm.ptr<f32>) -> ()
+
+// LLVMIR: llvm.mlir.global common @a_(dense<0> : vector<4xi8>) : !llvm.array<4 x i8>
+// LLVMIR: llvm.mlir.global common @__BLNK__(dense<0> : vector<4xi8>) : !llvm.array<4 x i8>
+// LLVMIR: llvm.func @bar_(!llvm.ptr<i32>) attributes {sym_visibility = "private"}
+// LLVMIR: llvm.func @bar2_(!llvm.ptr<f32>) attributes {sym_visibility = "private"}

diff  --git a/flang/test/Fir/field-index.fir b/flang/test/Fir/field-index.fir
new file mode 100644
index 000000000000..cbbb5ff8f641
--- /dev/null
+++ b/flang/test/Fir/field-index.fir
@@ -0,0 +1,30 @@
+// Test fir.field_index llvm code generation
+// RUN: fir-opt %s | tco | FileCheck %s
+
+
+// CHECK-DAG: %[[a:.*]] = type { float, i32 }
+// CHECK-DAG: %[[b:.*]] = type { float, i32 }
+// CHECK-DAG: %[[c:.*]] = type { float, %[[b]] }
+
+// CHECK-LABEL: @simple_field
+// CHECK-SAME: (ptr %[[arg0:.*]])
+func.func @simple_field(%arg0: !fir.ref<!fir.type<a{x:f32,i:i32}>>) -> i32 {
+  %1 = fir.field_index i, !fir.type<a{x:f32,i:i32}>
+  // CHECK: %[[GEP:.*]] = getelementptr %a, ptr %[[arg0]], i64 0, i32 1
+  %2 = fir.coordinate_of %arg0, %1 : (!fir.ref<!fir.type<a{x:f32,i:i32}>>, !fir.field) -> !fir.ref<i32>
+  // CHECK: load i32, ptr %[[GEP]]
+  %3 = fir.load %2 : !fir.ref<i32>
+  return %3 : i32
+}
+
+// CHECK-LABEL: @derived_field
+// CHECK-SAME: (ptr %[[arg0:.*]])
+func.func @derived_field(%arg0: !fir.ref<!fir.type<c{x:f32,some_b:!fir.type<b{x:f32,i:i32}>}>>) -> i32 {
+  %1 = fir.field_index some_b, !fir.type<c{x:f32,some_b:!fir.type<b{x:f32,i:i32}>}>
+  %2 = fir.field_index i, !fir.type<b{x:f32,i:i32}>
+  // CHECK: %[[GEP:.*]] = getelementptr %c, ptr %[[arg0]], i64 0, i32 1, i32 1
+  %3 = fir.coordinate_of %arg0, %1, %2 : (!fir.ref<!fir.type<c{x:f32,some_b:!fir.type<b{x:f32,i:i32}>}>>, !fir.field, !fir.field) -> !fir.ref<i32>
+  // CHECK: load i32, ptr %[[GEP]]
+  %4 = fir.load %3 : !fir.ref<i32>
+  return %4 : i32
+}


        


More information about the flang-commits mailing list