[flang-commits] [flang] 1906188 - [flang] Add FIR tests missing from fir-dev

Valentin Clement via flang-commits flang-commits at lists.llvm.org
Wed Jun 22 06:35:13 PDT 2022


Author: Valentin Clement
Date: 2022-06-22T15:35:04+02:00
New Revision: 1906188f0708eb1a517b5c093cbac43679293dda

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

LOG: [flang] Add FIR tests missing from fir-dev

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

Reviewed By: jeanPerier, PeteSteinfeld

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

Co-authored-by: Jean Perier <jperier at nvidia.com>
Co-authored-by: Eric Schweitz <eschweitz at nvidia.com>
Co-authored-by: Kiran Chandramohan <kiran.chandramohan at arm.com>

Added: 
    flang/test/Fir/fir-int-conversion.fir
    flang/test/Fir/loop10.fir
    flang/test/Fir/pdt.fir
    flang/test/Fir/real.fir
    flang/test/Fir/recursive-type-tco.fir
    flang/test/Fir/target-rewrite-complex16.fir
    flang/test/Fir/target.fir
    flang/test/Fir/type-descriptor.fir
    flang/test/Fir/undo-complex-pattern.fir

Modified: 
    flang/lib/Optimizer/CodeGen/Target.cpp
    flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
    flang/lib/Optimizer/Dialect/FIROps.cpp
    flang/test/Fir/target-rewrite-complex.fir

Removed: 
    


################################################################################
diff  --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp
index 47e6b0d57ab2..9ec2f04489ae 100644
--- a/flang/lib/Optimizer/CodeGen/Target.cpp
+++ b/flang/lib/Optimizer/CodeGen/Target.cpp
@@ -138,6 +138,13 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
       // two distinct double arguments
       marshal.emplace_back(eleTy, AT{});
       marshal.emplace_back(eleTy, AT{});
+    } else if (sem == &llvm::APFloat::IEEEquad()) {
+      // Use a type that will be translated into LLVM as:
+      // { fp128, fp128 }   struct of 2 fp128, byval, align 16
+      mlir::TypeRange range = {eleTy, eleTy};
+      marshal.emplace_back(fir::ReferenceType::get(
+                               mlir::TupleType::get(eleTy.getContext(), range)),
+                           AT{/*align=*/16, /*byval=*/true});
     } else {
       TODO(loc, "complex for this precision");
     }
@@ -157,6 +164,13 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
       mlir::TypeRange range = {eleTy, eleTy};
       marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range),
                            AT{});
+    } else if (sem == &llvm::APFloat::IEEEquad()) {
+      // Use a type that will be translated into LLVM as:
+      // { fp128, fp128 }   struct of 2 fp128, sret, align 16
+      mlir::TypeRange range = {eleTy, eleTy};
+      marshal.emplace_back(fir::ReferenceType::get(
+                               mlir::TupleType::get(eleTy.getContext(), range)),
+                           AT{/*align=*/16, /*byval=*/false, /*sret=*/true});
     } else {
       TODO(loc, "complex for this precision");
     }

diff  --git a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
index c88d4317d29a..f1e58d42779e 100644
--- a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
+++ b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
@@ -744,14 +744,33 @@ class TargetRewrite : public fir::TargetRewriteBase<TargetRewrite> {
     auto argTy = std::get<mlir::Type>(tup);
     if (attr.isSRet()) {
       unsigned argNo = newInTys.size();
-      fixups.emplace_back(
-          FixupTy::Codes::ReturnAsStore, argNo, [=](mlir::func::FuncOp func) {
-            func.setArgAttr(argNo, "llvm.sret", rewriter->getUnitAttr());
-          });
+      if (auto align = attr.getAlignment())
+        fixups.emplace_back(
+            FixupTy::Codes::ReturnAsStore, argNo, [=](mlir::func::FuncOp func) {
+              func.setArgAttr(argNo, "llvm.sret", rewriter->getUnitAttr());
+              func.setArgAttr(argNo, "llvm.align",
+                              rewriter->getIntegerAttr(
+                                  rewriter->getIntegerType(32), align));
+            });
+      else
+        fixups.emplace_back(
+            FixupTy::Codes::ReturnAsStore, argNo, [=](mlir::func::FuncOp func) {
+              func.setArgAttr(argNo, "llvm.sret", rewriter->getUnitAttr());
+            });
       newInTys.push_back(argTy);
       return;
+    } else {
+      if (auto align = attr.getAlignment())
+        fixups.emplace_back(FixupTy::Codes::ReturnType, newResTys.size(),
+                            [=](mlir::func::FuncOp func) {
+                              func.setArgAttr(
+                                  newResTys.size(), "llvm.align",
+                                  rewriter->getIntegerAttr(
+                                      rewriter->getIntegerType(32), align));
+                            });
+      else
+        fixups.emplace_back(FixupTy::Codes::ReturnType, newResTys.size());
     }
-    fixups.emplace_back(FixupTy::Codes::ReturnType, newResTys.size());
     newResTys.push_back(argTy);
   }
 

diff  --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index 069fa4344c5d..6443d5c6eca4 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -1561,7 +1561,7 @@ struct UndoComplexPattern : public mlir::RewritePattern {
       return mlir::failure();
     auto insval2 = mlir::dyn_cast_or_null<fir::InsertValueOp>(
         insval.getAdt().getDefiningOp());
-    if (!insval2 || !mlir::isa<fir::UndefOp>(insval2.getAdt().getDefiningOp()))
+    if (!insval2)
       return mlir::failure();
     auto binf = mlir::dyn_cast_or_null<FltOp>(insval.getVal().getDefiningOp());
     auto binf2 =

diff  --git a/flang/test/Fir/fir-int-conversion.fir b/flang/test/Fir/fir-int-conversion.fir
new file mode 100644
index 000000000000..700272bf1322
--- /dev/null
+++ b/flang/test/Fir/fir-int-conversion.fir
@@ -0,0 +1,35 @@
+// RUN: fir-opt --split-input-file --fir-to-llvm-ir %s | FileCheck --check-prefixes=COMMON,DEFAULT %s
+// RUN: fir-opt --kind-mapping="i1:4,i2:8,i4:16,i8:32,i16:64" --split-input-file --fir-to-llvm-ir %s | FileCheck --check-prefixes=COMMON,ALL-CUSTOM %s
+// RUN: fir-opt --kind-mapping="i2:1,i4:8,i16:32" --split-input-file --fir-to-llvm-ir %s | FileCheck --check-prefixes=COMMON,SOME-CUSTOM %s
+
+// Test `!fir.integer<KIND>` conversion with and without kind-mapping string
+
+func.func private @foo0(%arg0: !fir.int<1>)
+// COMMON-LABEL: foo0
+// DEFAULT-SAME: i8
+// ALL-CUSTOM-SAME: i4
+// SOME-CUSTOM-SAME: i8
+
+func.func private @foo1(%arg0: !fir.int<2>)
+// COMMON-LABEL: foo1
+// DEFAULT-SAME: i16
+// ALL-CUSTOM-SAME: i8
+// SOME-CUSTOM-SAME: i1
+
+func.func private @foo2(%arg0: !fir.int<4>)
+// COMMON-LABEL: foo2
+// DEFAULT-SAME: i32
+// ALL-CUSTOM-SAME: i16
+// SOME-CUSTOM-SAME: i8
+
+func.func private @foo3(%arg0: !fir.int<8>)
+// COMMON-LABEL: foo3
+// DEFAULT-SAME: i64
+// ALL-CUSTOM-SAME: i32
+// SOME-CUSTOM-SAME: i64
+
+func.func private @foo4(%arg0: !fir.int<16>)
+// COMMON-LABEL: foo4
+// DEFAULT-SAME: i128
+// ALL-CUSTOM-SAME: i64
+// SOME-CUSTOM-SAME: i32

diff  --git a/flang/test/Fir/loop10.fir b/flang/test/Fir/loop10.fir
new file mode 100644
index 000000000000..e1c908bb1067
--- /dev/null
+++ b/flang/test/Fir/loop10.fir
@@ -0,0 +1,25 @@
+// RUN: tco %s | FileCheck %s
+
+// CHECK: @x({{.*}} %[[ADDR:.*]])
+func.func @x(%addr : !fir.ref<!fir.array<10x10xi32>>) -> index {
+  %c0 = arith.constant 0 : index
+  %c10 = arith.constant 10 : index
+  %c1 = arith.constant 1 : index
+  // CHECK-DAG: %[[R:.*]] = phi i64 {{.*}} [ 0,
+  // CHECK-DAG: %[[ROW:.*]] = phi i64 {{.*}} [ 11,
+  // CHECK: icmp sgt i64 %[[ROW]], 0
+  fir.do_loop %iv = %c0 to %c10 step %c1 {
+    // CHECK-DAG: %[[C:.*]] = phi i64 {{.*}} [ 0,
+    // CHECK-DAG: %[[COL:.*]] = phi i64 {{.*}} [ 11,
+    // CHECK: icmp sgt i64 %[[COL]], 0
+    fir.do_loop %jv = %c0 to %c10 step %c1 {
+      // CHECK: getelementptr {{.*}} %[[ADDR]], i64 0, i64 %[[R]], i64 %[[C]]
+      %ptr = fir.coordinate_of %addr, %jv, %iv : (!fir.ref<!fir.array<10x10xi32>>, index, index) -> !fir.ref<i32>
+      %c22 = arith.constant 22 : i32
+      // CHECK: store i32 22,
+      fir.store %c22 to %ptr : !fir.ref<i32>
+    }
+  }
+  // CHECK: ret i64 10
+  return %c10 : index
+}

diff  --git a/flang/test/Fir/pdt.fir b/flang/test/Fir/pdt.fir
new file mode 100644
index 000000000000..4464b897414a
--- /dev/null
+++ b/flang/test/Fir/pdt.fir
@@ -0,0 +1,110 @@
+// RUN: tco %s | FileCheck %s
+
+// CHECK-LINE: define i64 @_QTtP.mem.size(i32 %0, i16 %1)
+func.func @_QTtP.mem.size(%0 : i32, %1 : i16) -> index {
+  %2 = call @_QTtP.f1.size(%0, %1) : (i32, i16) -> index
+  %3 = call @_QTtP.f2.size(%0, %1) : (i32, i16) -> index
+  %4 = arith.addi %2, %3 : index
+  // CHECK: ret i64 8
+  return %4 : index
+}
+// CHECK-LINE: define i64 @_QTtP.f1.size(i32 %0, i16 %1)
+func.func @_QTtP.f1.size(%0 : i32, %1 : i16) -> index {
+  %2 = arith.constant 4 : index
+  // CHECK: ret i64 4
+  return %2 : index
+}
+// CHECK-LINE: define i64 @_QTtP.f2.size(i32 %0, i16 %1)
+func.func @_QTtP.f2.size(%0 : i32, %1 : i16) -> index {
+  %2 = arith.constant 4 : index
+  // CHECK: ret i64 4
+  return %2 : index
+}
+// CHECK-LINE: define i32 @_QTtP.f1.offset(i32 %0, i16 %1)
+func.func @_QTtP.f1.offset(%0 : i32, %1 : i16) -> i32 {
+  %2 = arith.constant 0 : i32
+  // CHECK: ret i32 0
+  return %2 : i32
+}
+// CHECK-LINE: define i32 @_QTtP.f2.offset(i32 %0, i16 %1)
+func.func @_QTtP.f2.offset(%0 : i32, %1 : i16) -> i32 {
+  %2 = arith.constant 4 : i32
+  // CHECK: ret i32 4
+  return %2 : i32
+}
+
+// program p
+//   type t(p1,p2)
+//      integer, len :: p1
+//      integer(kind=2), len :: p2
+//      integer f1
+//      real f2
+//   end type t
+//   type(t) var
+//   var%f1 = 4
+// end program p
+
+// CHECK-LINE: define void @_QQmain(i32 %0, i16 %1)
+func.func @_QQmain(%arg0 : i32, %arg1 : i16) {
+  // CHECK: %[[size:.*]] = call i64 @_QTtP.mem.size(i32 %0, i16 %1)
+  // CHECK: %[[alloc:.*]] = alloca i8, i64 %[[size]]
+  %0 = fir.alloca !fir.type<_QTt(p1:i32,p2:i16){f1:i32,f2:f32}>(%arg0, %arg1 : i32, i16) {name = "_QEvar"}
+  %1 = fir.field_index f1, !fir.type<_QTt(p1:i32,p2:i16){f1:i32,f2:f32}>(%arg0, %arg1 : i32, i16)
+  %2 = fir.coordinate_of %0, %1 : (!fir.ref<!fir.type<_QTt(p1:i32,p2:i16){f1:i32,f2:f32}>>, !fir.field) -> !fir.ref<i32>
+  %c4_i32 = arith.constant 4 : i32
+  fir.store %c4_i32 to %2 : !fir.ref<i32>
+  return
+}
+
+// CHECK-LINE: define i64 @_QTt1P.mem.size(i32 %0, i32 %1)
+func.func @_QTt1P.mem.size(%0 : i32, %1 : i32) -> index {
+  // CHECK: call i64 @_QTt1P.f1.size
+  %2 = call @_QTt1P.f1.size(%0, %1) : (i32, i32) -> index
+  // CHECK:  call i64 @_QTt1P.f2.size
+  %3 = call @_QTt1P.f2.size(%0, %1) : (i32, i32) -> index
+  %4 = arith.addi %2, %3 : index
+  return %4 : index
+}
+// CHECK-LINE: define i64 @_QTt1P.f1.size(i32 %0, i32 %1)
+func.func @_QTt1P.f1.size(%0 : i32, %1 : i32) -> index {
+  %2 = fir.convert %0 : (i32) -> index
+  return %2 : index
+}
+// CHECK-LINE: define i64 @_QTt1P.f2.size(i32 %0, i32 %1)
+func.func @_QTt1P.f2.size(%0 : i32, %1 : i32) -> index {
+  %2 = fir.convert %1 : (i32) -> index
+  return %2 : index
+}
+// CHECK-LINE: define i32 @_QTt1P.f1.offset(i32 %0, i32 %1)
+func.func @_QTt1P.f1.offset(%0 : i32, %1 : i32) -> i32 {
+  %2 = arith.constant 0 : i32
+  return %2 : i32
+}
+// CHECK-LINE: define i32 @_QTt1P.f2.offset(i32 %0, i32 %1)
+func.func @_QTt1P.f2.offset(%0 : i32, %1 : i32) -> i32 {
+  return %0 : i32
+}
+// subroutine foo(i,j)
+//   type t(p1,p2)
+//      integer, len :: p1
+//      integer, len :: p2
+//      character(LEN=p1) :: f1
+//      character(LEN=p2) :: f2
+//   end type t
+//   type(t(i,j)) var
+//   call bar(var%f2)
+// end program p
+
+func.func private @bar(!fir.ref<!fir.char<1,?>>)
+
+// CHECK-LINE: define i8* @_QPfoo(i32 %0, i32 %1)
+func.func @_QPfoo(%arg0 : i32, %arg1 : i32) {
+  // CHECK: %[[size:.*]] = call i64 @_QTt1P.mem.size(i32 %0, i32 %1)
+  // CHECK: %[[alloc:.*]] = alloca i8, i64 %[[size]]
+  %0 = fir.alloca !fir.type<_QTt1(p1:i32,p2:i32){f1:!fir.char<1,?>,f2:!fir.char<1,?>}>(%arg0, %arg1 : i32, i32)
+  %1 = fir.field_index f2, !fir.type<_QTt1>(%arg0, %arg1 : i32, i32)
+  //%2 = fir.coordinate_of %0, %1 : (!fir.ref<!fir.type<_QTt1>>, !fir.field) -> !fir.ref<!fir.char<1,?>>
+  %2 = fir.zero_bits !fir.ref<!fir.char<1,?>>
+  fir.call @bar(%2) : (!fir.ref<!fir.char<1,?>>) -> ()
+  return
+}

diff  --git a/flang/test/Fir/real.fir b/flang/test/Fir/real.fir
new file mode 100644
index 000000000000..3487d84f217e
--- /dev/null
+++ b/flang/test/Fir/real.fir
@@ -0,0 +1,51 @@
+// Test lowering of REAL operations from FIR to LLVM IR
+
+// RUN: tco %s | FileCheck %s
+
+// CHECK-LABEL: @bar
+func.func @bar(%a : f16, %b : f32, %c : f64, %d : f80, %e : f128) -> f80 {
+  // CHECK: fpext half %{{.*}} to x86_fp80
+  %1 = fir.convert %a : (f16) -> f80
+  // CHECK: fpext float %{{.*}} to x86_fp80
+  %2 = fir.convert %b : (f32) -> f80
+  // CHECK: fpext double %{{.*}} to x86_fp80
+  %3 = fir.convert %c : (f64) -> f80
+  // CHECK-NOT: fpext
+  // CHECK-NOT: fptrunc
+  %4 = fir.convert %d : (f80) -> f80
+  // CHECK: fptrunc fp128 %{{.*}} to x86_fp80
+  %5 = fir.convert %e : (f128) -> f80
+  // CHECK-NEXT: call x86_fp80
+  %6 = fir.call @foop(%1, %2, %3, %4, %5) : (f80, f80, f80, f80, f80) -> f80
+  return %6 : f80
+}
+
+// CHECK-LABEL: @foo
+func.func @foo(%a : f128, %b : f128, %c : f128, %d : f128, %e : f128) -> f128 {
+  // CHECK: fadd fp128
+  %1 = arith.addf %a, %b : f128
+  // CHECK: fmul fp128
+  %2 = arith.mulf %1, %c : f128
+  // CHECK: fsub fp128
+  %3 = arith.subf %2, %d : f128
+  // CHECK: fdiv fp128
+  %4 = arith.divf %3, %e : f128
+  // CHECK: frem fp128
+  %5 = arith.remf %4, %a : f128
+  return %5 : f128
+}
+
+// CHECK-LABEL: @foop
+func.func @foop(%a : f80, %b : f80, %c : f80, %d : f80, %e : f80) -> f80 {
+  // CHECK: fadd x86_fp80
+  %1 = arith.addf %a, %b : f80
+  // CHECK: fmul x86_fp80
+  %2 = arith.mulf %1, %c : f80
+  // CHECK: fsub x86_fp80
+  %3 = arith.subf %2, %d : f80
+  // CHECK: fdiv x86_fp80
+  %4 = arith.divf %3, %e : f80
+  // CHECK: frem x86_fp80
+  %5 = arith.remf %4, %a : f80
+  return %5 : f80
+}

diff  --git a/flang/test/Fir/recursive-type-tco.fir b/flang/test/Fir/recursive-type-tco.fir
new file mode 100644
index 000000000000..9933f727af12
--- /dev/null
+++ b/flang/test/Fir/recursive-type-tco.fir
@@ -0,0 +1,11 @@
+// Test lowering FIR to LLVM IR for a recursive type
+
+// RUN: tco %s | FileCheck %s
+
+// CHECK-LABEL: %t = type { ptr }
+!t = !fir.type<t {p : !fir.ptr<!fir.type<t>>}>
+
+// CHECK-LABEL: @a(%t %{{.*}})
+func.func @a(%a : !t) {
+  return
+}

diff  --git a/flang/test/Fir/target-rewrite-complex.fir b/flang/test/Fir/target-rewrite-complex.fir
index 515c18a10be8..b83d58217814 100644
--- a/flang/test/Fir/target-rewrite-complex.fir
+++ b/flang/test/Fir/target-rewrite-complex.fir
@@ -53,7 +53,7 @@ func.func @returncomplex4() -> !fir.complex<4> {
 // Test that we rewrite the signature and body of a function that returns a
 // complex<8>.
 // I32-LABEL:func @returncomplex8
-// I32-SAME: ([[ARG0:%[0-9A-Za-z]+]]: !fir.ref<tuple<!fir.real<8>, !fir.real<8>>>  {llvm.sret})
+// I32-SAME: ([[ARG0:%[0-9A-Za-z]+]]: !fir.ref<tuple<!fir.real<8>, !fir.real<8>>>  {llvm.align = 4 : i32, llvm.sret})
 // X64-LABEL: func @returncomplex8() -> tuple<!fir.real<8>, !fir.real<8>>
 // AARCH64-LABEL: func @returncomplex8() -> tuple<!fir.real<8>, !fir.real<8>>
 // PPC-LABEL: func @returncomplex8() -> tuple<!fir.real<8>, !fir.real<8>>

diff  --git a/flang/test/Fir/target-rewrite-complex16.fir b/flang/test/Fir/target-rewrite-complex16.fir
new file mode 100644
index 000000000000..9c4f0af7dd77
--- /dev/null
+++ b/flang/test/Fir/target-rewrite-complex16.fir
@@ -0,0 +1,125 @@
+// RUN: fir-opt --target-rewrite="target=x86_64-unknown-linux-gnu" %s | FileCheck %s
+// UNSUPPORTED: darwin
+
+// Test that we rewrite the signature and body of a func.function that returns a
+// complex<16>.
+func.func @returncomplex16() -> !fir.complex<16> {
+  %1 = fir.undefined !fir.complex<16>
+  %2 = arith.constant 2.0 : f128
+  %3 = fir.convert %2 : (f128) -> !fir.real<16>
+  %c0 = arith.constant 0 : i32
+  %4 = fir.insert_value %1, %3, [0 : i32] : (!fir.complex<16>, !fir.real<16>) -> !fir.complex<16>
+  %c1 = arith.constant 1 : i32
+  %5 = arith.constant -42.0 : f128
+  %6 = fir.insert_value %4, %5, [1 : i32] : (!fir.complex<16>, f128) -> !fir.complex<16>
+  return %6 : !fir.complex<16>
+}
+
+// Test that we rewrite the signature of a func.function that accepts a complex<16>.
+func.func private @paramcomplex16(!fir.complex<16>) -> ()
+
+// Test that we rewrite calls to func.functions that return or accept complex<16>.
+func.func @callcomplex16() {
+  %1 = fir.call @returncomplex16() : () -> !fir.complex<16>
+  fir.call @paramcomplex16(%1) : (!fir.complex<16>) -> ()
+  return
+}
+
+// Test multiple complex<16> parameters and arguments
+func.func private @calleemultipleparamscomplex16(!fir.complex<16>, !fir.complex<16>, !fir.complex<16>) -> ()
+
+func.func @multipleparamscomplex16(%z1 : !fir.complex<16>, %z2 : !fir.complex<16>, %z3 : !fir.complex<16>) {
+  fir.call @calleemultipleparamscomplex16(%z1, %z2, %z3) : (!fir.complex<16>, !fir.complex<16>, !fir.complex<16>) -> ()
+  return
+}
+
+// Test that we rewrite the signature of and calls to a func.function that accepts
+// and returns MLIR complex<f128>.
+func.func private @mlircomplexf128(%z1: complex<f128>, %z2: complex<f128>) -> complex<f128> {
+  %0 = fir.call @mlircomplexf128(%z1, %z2) : (complex<f128>, complex<f128>) -> complex<f128>
+  return %0 : complex<f128>
+}
+
+// Test that we rewrite the fir.address_of operator.
+func.func @addrof() {
+  %r = fir.address_of(@returncomplex16) : () -> !fir.complex<16>
+  %p = fir.address_of(@paramcomplex16) : (!fir.complex<16>) -> ()
+  return
+}
+
+// CHECK-LABEL:   func.func @returncomplex16(
+// CHECK-SAME:      %[[VAL_0:.*]]: !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.sret}) {
+// CHECK:           %[[VAL_1:.*]] = fir.undefined !fir.complex<16>
+// CHECK:           %[[VAL_2:.*]] = arith.constant 2.000000e+00 : f128
+// CHECK:           %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (f128) -> !fir.real<16>
+// CHECK:           %[[VAL_4:.*]] = arith.constant 0 : i32
+// CHECK:           %[[VAL_5:.*]] = fir.insert_value %[[VAL_1]], %[[VAL_3]], [0 : i32] : (!fir.complex<16>, !fir.real<16>) -> !fir.complex<16>
+// CHECK:           %[[VAL_6:.*]] = arith.constant 1 : i32
+// CHECK:           %[[VAL_7:.*]] = arith.constant -4.200000e+01 : f128
+// CHECK:           %[[VAL_8:.*]] = fir.insert_value %[[VAL_5]], %[[VAL_7]], [1 : i32] : (!fir.complex<16>, f128) -> !fir.complex<16>
+// CHECK:           %[[VAL_9:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> !fir.ref<!fir.complex<16>>
+// CHECK:           fir.store %[[VAL_8]] to %[[VAL_9]] : !fir.ref<!fir.complex<16>>
+// CHECK:           return
+// CHECK:         }
+// CHECK:         func.func private @paramcomplex16(!fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval})
+
+// CHECK-LABEL:   func.func @callcomplex16() {
+// CHECK:           %[[VAL_0:.*]] = fir.alloca tuple<!fir.real<16>, !fir.real<16>>
+// CHECK:           fir.call @returncomplex16(%[[VAL_0]]) : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> ()
+// CHECK:           %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> !fir.ref<!fir.complex<16>>
+// CHECK:           %[[VAL_2:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.complex<16>>
+// CHECK:           %[[VAL_3:.*]] = fir.alloca !fir.complex<16>
+// CHECK:           fir.store %[[VAL_2]] to %[[VAL_3]] : !fir.ref<!fir.complex<16>>
+// CHECK:           %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<!fir.complex<16>>) -> !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>
+// CHECK:           fir.call @paramcomplex16(%[[VAL_4]]) : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> ()
+// CHECK:           return
+// CHECK:         }
+// CHECK:         func.func private @calleemultipleparamscomplex16(!fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval}, !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval}, !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval})
+
+// CHECK-LABEL:   func.func @multipleparamscomplex16(
+// CHECK-SAME:       %[[VAL_0:.*]]: !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval}, %[[VAL_1:.*]]: !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval}, %[[VAL_2:.*]]: !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval}) {
+// CHECK:           %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> !fir.ref<!fir.complex<16>>
+// CHECK:           %[[VAL_4:.*]] = fir.load %[[VAL_3]] : !fir.ref<!fir.complex<16>>
+// CHECK:           %[[VAL_5:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> !fir.ref<!fir.complex<16>>
+// CHECK:           %[[VAL_6:.*]] = fir.load %[[VAL_5]] : !fir.ref<!fir.complex<16>>
+// CHECK:           %[[VAL_7:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> !fir.ref<!fir.complex<16>>
+// CHECK:           %[[VAL_8:.*]] = fir.load %[[VAL_7]] : !fir.ref<!fir.complex<16>>
+// CHECK:           %[[VAL_9:.*]] = fir.alloca !fir.complex<16>
+// CHECK:           fir.store %[[VAL_8]] to %[[VAL_9]] : !fir.ref<!fir.complex<16>>
+// CHECK:           %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (!fir.ref<!fir.complex<16>>) -> !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>
+// CHECK:           %[[VAL_11:.*]] = fir.alloca !fir.complex<16>
+// CHECK:           fir.store %[[VAL_6]] to %[[VAL_11]] : !fir.ref<!fir.complex<16>>
+// CHECK:           %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.ref<!fir.complex<16>>) -> !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>
+// CHECK:           %[[VAL_13:.*]] = fir.alloca !fir.complex<16>
+// CHECK:           fir.store %[[VAL_4]] to %[[VAL_13]] : !fir.ref<!fir.complex<16>>
+// CHECK:           %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (!fir.ref<!fir.complex<16>>) -> !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>
+// CHECK:           fir.call @calleemultipleparamscomplex16(%[[VAL_10]], %[[VAL_12]], %[[VAL_14]]) : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>, !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>, !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> ()
+// CHECK:           return
+// CHECK:         }
+
+// CHECK-LABEL:   func.func private @mlircomplexf128(
+// CHECK-SAME:      %[[VAL_0:.*]]: !fir.ref<tuple<f128, f128>> {llvm.align = 16 : i32, llvm.sret}, %[[VAL_1:.*]]: !fir.ref<tuple<f128, f128>> {llvm.align = 16 : i32, llvm.byval},  %[[VAL_2:.*]]: !fir.ref<tuple<f128, f128>> {llvm.align = 16 : i32, llvm.byval}) {
+// CHECK:           %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<tuple<f128, f128>>) -> !fir.ref<complex<f128>>
+// CHECK:           %[[VAL_4:.*]] = fir.load %[[VAL_3]] : !fir.ref<complex<f128>>
+// CHECK:           %[[VAL_5:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<tuple<f128, f128>>) -> !fir.ref<complex<f128>>
+// CHECK:           %[[VAL_6:.*]] = fir.load %[[VAL_5]] : !fir.ref<complex<f128>>
+// CHECK:           %[[VAL_7:.*]] = fir.alloca tuple<f128, f128>
+// CHECK:           %[[VAL_8:.*]] = fir.alloca complex<f128>
+// CHECK:           fir.store %[[VAL_6]] to %[[VAL_8]] : !fir.ref<complex<f128>>
+// CHECK:           %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.ref<complex<f128>>) -> !fir.ref<tuple<f128, f128>>
+// CHECK:           %[[VAL_10:.*]] = fir.alloca complex<f128>
+// CHECK:           fir.store %[[VAL_4]] to %[[VAL_10]] : !fir.ref<complex<f128>>
+// CHECK:           %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (!fir.ref<complex<f128>>) -> !fir.ref<tuple<f128, f128>>
+// CHECK:           fir.call @mlircomplexf128(%[[VAL_7]], %[[VAL_9]], %[[VAL_11]]) : (!fir.ref<tuple<f128, f128>>, !fir.ref<tuple<f128, f128>>, !fir.ref<tuple<f128, f128>>) -> ()
+// CHECK:           %[[VAL_12:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<tuple<f128, f128>>) -> !fir.ref<complex<f128>>
+// CHECK:           %[[VAL_13:.*]] = fir.load %[[VAL_12]] : !fir.ref<complex<f128>>
+// CHECK:           %[[VAL_14:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<f128, f128>>) -> !fir.ref<complex<f128>>
+// CHECK:           fir.store %[[VAL_13]] to %[[VAL_14]] : !fir.ref<complex<f128>>
+// CHECK:           return
+// CHECK:         }
+
+// CHECK-LABEL:   func.func @addrof() {
+// CHECK:           %[[VAL_0:.*]] = fir.address_of(@returncomplex16) : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> ()
+// CHECK:           %[[VAL_1:.*]] = fir.address_of(@paramcomplex16) : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> ()
+// CHECK:           return
+// CHECK:         }

diff  --git a/flang/test/Fir/target.fir b/flang/test/Fir/target.fir
new file mode 100644
index 000000000000..39798d0a2358
--- /dev/null
+++ b/flang/test/Fir/target.fir
@@ -0,0 +1,142 @@
+// RUN: tco --target=i386-unknown-linux-gnu %s | FileCheck %s --check-prefix=I32
+// RUN: tco --target=x86_64-unknown-linux-gnu %s | FileCheck %s --check-prefix=X64
+// RUN: tco --target=aarch64-unknown-linux-gnu %s | FileCheck %s --check-prefix=AARCH64
+// RUN: tco --target=powerpc64le-unknown-linux-gnu %s | FileCheck %s --check-prefix=PPC
+
+// I32-LABEL: define i64 @gen4()
+// X64-LABEL: define <2 x float> @gen4()
+// AARCH64-LABEL: define { float, float } @gen4()
+// PPC-LABEL: define { float, float } @gen4()
+func.func @gen4() -> !fir.complex<4> {
+  %1 = fir.undefined !fir.complex<4>
+  %2 = arith.constant 2.0 : f32
+  %3 = fir.convert %2 : (f32) -> !fir.real<4>
+  %c0 = arith.constant 0 : i32
+  %4 = fir.insert_value %1, %3, [0 : index] : (!fir.complex<4>, !fir.real<4>) -> !fir.complex<4>
+  %c1 = arith.constant 1 : i32
+  %5 = arith.constant -42.0 : f32
+  %6 = fir.insert_value %4, %5, [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+  // I32: store { float, float } { float 2.000000e+00, float -4.200000e+01 }
+  // I32: %[[load:.*]] = load i64, ptr
+  // I32: ret i64 %[[load]]
+  // X64: store { float, float } { float 2.000000e+00, float -4.200000e+01 }
+  // X64: %[[load:.*]] = load <2 x float>, ptr
+  // X64: ret <2 x float> %[[load]]
+  // AARCH64: ret { float, float }
+  // PPC: ret { float, float }
+  return %6 : !fir.complex<4>
+}
+
+// I32-LABEL: define void @gen8(ptr sret({ double, double }) align 4 %
+// X64-LABEL: define { double, double } @gen8()
+// AARCH64-LABEL: define { double, double } @gen8()
+// PPC-LABEL: define { double, double } @gen8()
+func.func @gen8() -> !fir.complex<8> {
+  %1 = fir.undefined !fir.complex<8>
+  %2 = arith.constant 1.0 : f64
+  %3 = arith.constant -4.0 : f64
+  %c0 = arith.constant 0 : i32
+  %4 = fir.insert_value %1, %3, [0 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  %c1 = arith.constant 1 : i32
+  %5 = fir.insert_value %4, %2, [1 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  // I32: store { double, double } { double -4.000000e+00, double 1.000000e+00 }
+  // I64: store { double, double } { double -4.000000e+00, double 1.000000e+00 }
+  // I64: %[[load:.*]] = load { double, double }
+  // I64: ret { double, double } %[[load]]
+  // AARCH64: ret { double, double }
+  // PPC: ret { double, double }
+  return %5 : !fir.complex<8>
+}
+
+// I32: declare void @sink4(ptr)
+// X64: declare void @sink4(<2 x float>)
+// AARCH64: declare void @sink4([2 x float])
+// PPC: declare void @sink4(float, float)
+func.func private @sink4(!fir.complex<4>) -> ()
+
+// I32: declare void @sink8(ptr)
+// X64: declare void @sink8(double, double)
+// AARCH64: declare void @sink8([2 x double])
+// PPC: declare void @sink8(double, double)
+func.func private @sink8(!fir.complex<8>) -> ()
+
+// I32-LABEL: define void @call4()
+// X64-LABEL: define void @call4()
+// AARCH64-LABEL: define void @call4()
+func.func @call4() {
+  // I32: = call i64 @gen4()
+  // X64: = call <2 x float> @gen4()
+  // AARCH64: = call { float, float } @gen4()
+  // PPC: = call { float, float } @gen4()
+  %1 = fir.call @gen4() : () -> !fir.complex<4>
+  // I32: call void @sink4(ptr %
+  // X64: call void @sink4(<2 x float> %
+  // AARCH64: call void @sink4([2 x float] %
+  // PPC: call void @sink4(float %{{.*}}, float %{{.*}})
+  fir.call @sink4(%1) : (!fir.complex<4>) -> ()
+  return
+}
+
+// I32-LABEL: define void @call8()
+// X64-LABEL: define void @call8()
+// AARCH64-LABEL: define void @call8()
+func.func @call8() {
+  // I32: call void @gen8(ptr %
+  // X64: = call { double, double } @gen8()
+  // AARCH64: = call { double, double } @gen8()
+  // PPC: = call { double, double } @gen8()
+  %1 = fir.call @gen8() : () -> !fir.complex<8>
+  // I32: call void @sink8(ptr %
+  // X64: call void @sink8(double %4, double %5)
+  // AARCH64: call void @sink8([2 x double] %
+  // PPC: call void @sink8(double %{{.*}}, double %{{.*}})
+  fir.call @sink8(%1) : (!fir.complex<8>) -> ()
+  return
+}
+
+// I32-LABEL: define i64 @char1lensum(ptr %0, ptr %1, i32 %2, i32 %3)
+// X64-LABEL: define i64 @char1lensum(ptr %0, ptr %1, i64 %2, i64 %3)
+// PPC-LABEL: define i64 @char1lensum(ptr %0, ptr %1, i64 %2, i64 %3)
+func.func @char1lensum(%arg0 : !fir.boxchar<1>, %arg1 : !fir.boxchar<1>) -> i64 {
+  // X64-DAG: %[[p0:.*]] = insertvalue { ptr, i64 } undef, ptr %1, 0
+  // X64-DAG: = insertvalue { ptr, i64 } %[[p0]], i64 %3, 1
+  // X64-DAG: %[[p1:.*]] = insertvalue { ptr, i64 } undef, ptr %0, 0
+  // X64-DAG: = insertvalue { ptr, i64 } %[[p1]], i64 %2, 1
+  %1:2 = fir.unboxchar %arg0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1>>, i64)
+  %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1>>, i64)
+  // I32: %[[add:.*]] = add i64 %
+  // X64: %[[add:.*]] = add i64 %
+  %3 = arith.addi %1#1, %2#1 : i64
+  // I32: ret i64 %[[add]]
+  // X64: ret i64 %[[add]]
+  return %3 : i64
+}
+
+// I32-LABEL: define void @char1copy(ptr sret(i8) %0, i32 %1, ptr %2, i32 %3)
+// I64-LABEL: define void @char1copy(ptr sret(i8) %0, i64 %1, ptr %2, i64 %3)
+// PPC-LABEL: define void @char1copy(ptr sret(i8) %0, i64 %1, ptr %2, i64 %3)
+func.func @char1copy(%arg0 : !fir.boxchar<1> {llvm.sret}, %arg1 : !fir.boxchar<1>) {
+  // I32-DAG: %[[p0:.*]] = insertvalue { ptr, i32 } undef, ptr %2, 0
+  // I32-DAG: = insertvalue { ptr, i32 } %[[p0]], i32 %3, 1
+  // I32-DAG: %[[p1:.*]] = insertvalue { ptr, i32 } undef, ptr %0, 0
+  // I32-DAG: = insertvalue { ptr, i32 } %[[p1]], i32 %1, 1
+  // X64-DAG: %[[p0:.*]] = insertvalue { ptr, i64 } undef, ptr %2, 0
+  // X64-DAG: = insertvalue { ptr, i64 } %[[p0]], i64 %3, 1
+  // X64-DAG: %[[p1:.*]] = insertvalue { ptr, i64 } undef, ptr %0, 0
+  // X64-DAG: = insertvalue { ptr, i64 } %[[p1]], i64 %1, 1
+  %1:2 = fir.unboxchar %arg0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.array<?x!fir.char<1>>>, i64)
+  %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref<!fir.array<?x!fir.char<1>>>, i64)
+  %c0 = arith.constant 0 : index
+  %c1 = arith.constant 1 : index
+  %3 = fir.convert %1#1 : (i64) -> index
+  %last = arith.subi %3, %c1 : index
+  fir.do_loop %i = %c0 to %last step %c1 {
+    %in_pos = fir.coordinate_of %2#0, %i : (!fir.ref<!fir.array<?x!fir.char<1>>>, index) -> !fir.ref<!fir.char<1>>
+    %out_pos = fir.coordinate_of %1#0, %i : (!fir.ref<!fir.array<?x!fir.char<1>>>, index) -> !fir.ref<!fir.char<1>>
+    %ch = fir.load %in_pos : !fir.ref<!fir.char<1>>
+    fir.store %ch to %out_pos : !fir.ref<!fir.char<1>>
+  }
+  // I32: ret void
+  // X64: ret void
+  return
+}

diff  --git a/flang/test/Fir/type-descriptor.fir b/flang/test/Fir/type-descriptor.fir
new file mode 100644
index 000000000000..c5362090e659
--- /dev/null
+++ b/flang/test/Fir/type-descriptor.fir
@@ -0,0 +1,29 @@
+// Test mapping between fir types and their runtime type descriptor objects.
+// RUN: tco -o - %s | FileCheck %s
+
+// Test mapping of derived type following the internal name ABI (i.e. that could come from an actual
+// compiled Fortran program).
+
+!sometype = !fir.type<_QFfooTsometype{num:i32,values:!fir.box<!fir.ptr<!fir.array<?x?xf32>>>}>
+fir.global internal @_QFfooE.dt.sometype constant : i8
+
+fir.global internal @_QFfooEx : !fir.box<!fir.heap<!sometype>> {
+  %0 = fir.zero_bits !fir.heap<!sometype>
+  %1 = fir.embox %0 : (!fir.heap<!sometype>) -> !fir.box<!fir.heap<!sometype>>
+  fir.has_value %1 : !fir.box<!fir.heap<!sometype>>
+}
+// CHECK: @_QFfooEx = internal global { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }
+// CHECK-SAME: { ptr null, i64 ptrtoint (ptr getelementptr (%_QFfooTsometype, ptr null, i32 1) to i64),
+// CHECK-SAME: i32 20180515, i8 0, i8 42, i8 2, i8 1, ptr @_QFfooE.dt.sometype, [1 x i64] undef }
+
+!some_pdt_type = !fir.type<_QFfooTsome_pdt_typeK42K43{num:i32,values:!fir.box<!fir.ptr<!fir.array<?x?xf32>>>}>
+fir.global internal @_QFfooE.dt.some_pdt_type.42.43 constant : i8
+
+fir.global internal @_QFfooEx2 : !fir.box<!fir.heap<!some_pdt_type>> {
+  %0 = fir.zero_bits !fir.heap<!some_pdt_type>
+  %1 = fir.embox %0 : (!fir.heap<!some_pdt_type>) -> !fir.box<!fir.heap<!some_pdt_type>>
+  fir.has_value %1 : !fir.box<!fir.heap<!some_pdt_type>>
+}
+// CHECK: @_QFfooEx2 = internal global { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }
+// CHECK-SAME: { ptr null, i64 ptrtoint (ptr getelementptr (%_QFfooTsome_pdt_typeK42K43, ptr null, i32 1) to i64),
+// CHECK-SAME: i32 20180515, i8 0, i8 42, i8 2, i8 1, ptr @_QFfooE.dt.some_pdt_type.42.43, [1 x i64] undef }

diff  --git a/flang/test/Fir/undo-complex-pattern.fir b/flang/test/Fir/undo-complex-pattern.fir
new file mode 100644
index 000000000000..853579b4bf5b
--- /dev/null
+++ b/flang/test/Fir/undo-complex-pattern.fir
@@ -0,0 +1,98 @@
+// Test regrouping of + and - operations on complex components into complex operations
+// RUN: fir-opt --canonicalize %s | FileCheck %s
+
+
+// CHECK-LABEL: @add
+func.func @add(%z: !fir.ref<!fir.complex<8>>, %z1 : !fir.complex<8>, %z2 : !fir.complex<8>) {
+  %c0 = arith.constant 0 : index
+  %c1 = arith.constant 1 : index
+  %real1 = fir.extract_value %z1, [0 : index] : (!fir.complex<8>) -> f64
+  %imag1 = fir.extract_value %z1, [1 : index] : (!fir.complex<8>) -> f64
+  %real2 = fir.extract_value %z2, [0 : index] : (!fir.complex<8>) -> f64
+  %imag2 = fir.extract_value %z2, [1 : index] : (!fir.complex<8>) -> f64
+
+  // CHECK-LABEL: fir.addc
+  %real = arith.addf %real1, %real2 : f64
+  %imag = arith.addf %imag1, %imag2 : f64
+  %undef = fir.undefined !fir.complex<8>
+  %insert_real = fir.insert_value %undef, %real, [0 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  %insert_imag = fir.insert_value %insert_real, %imag, [1 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  fir.store %insert_imag to %z : !fir.ref<!fir.complex<8>>
+  return
+}
+
+// CHECK-LABEL: @sub
+func.func @sub(%z: !fir.ref<!fir.complex<8>>, %z1 : !fir.complex<8>, %z2 : !fir.complex<8>) {
+  %c0 = arith.constant 0 : index
+  %c1 = arith.constant 1 : index
+  %real1 = fir.extract_value %z1, [0 : index] : (!fir.complex<8>) -> f64
+  %imag1 = fir.extract_value %z1, [1 : index] : (!fir.complex<8>) -> f64
+  %real2 = fir.extract_value %z2, [0 : index] : (!fir.complex<8>) -> f64
+  %imag2 = fir.extract_value %z2, [1 : index] : (!fir.complex<8>) -> f64
+
+  // CHECK-LABEL: fir.subc
+  %real = arith.subf %real1, %real2 : f64
+  %imag = arith.subf %imag1, %imag2 : f64
+  %undef = fir.undefined !fir.complex<8>
+  %insert_real = fir.insert_value %undef, %real, [0 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  %insert_imag = fir.insert_value %insert_real, %imag, [1 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  fir.store %insert_imag to %z : !fir.ref<!fir.complex<8>>
+  return
+}
+
+// CHECK-LABEL: @undefOpHiddenByBranch
+func.func @undefOpHiddenByBranch(%z: !fir.ref<!fir.complex<8>>, %b: i1) {
+  %c0 = arith.constant 0 : index
+  %c1 = arith.constant 1 : index
+  cf.cond_br %b, ^bb1, ^bb2
+^bb1:  // pred: ^bb0
+  %u1 = fir.undefined !fir.complex<8>
+  %z1l = fir.call @bar1() : () -> !fir.complex<8>
+  %z1r = fir.call @bar1() : () -> !fir.complex<8>
+  cf.br ^bb3(%u1, %z1l, %z1r : !fir.complex<8>, !fir.complex<8>, !fir.complex<8>)
+^bb2:  // pred: ^bb0
+  %u2 = fir.undefined !fir.complex<8>
+  %z2l = fir.call @bar2() : () -> !fir.complex<8>
+  %z2r = fir.call @bar2() : () -> !fir.complex<8>
+  cf.br ^bb3(%u2, %z2l, %z2r : !fir.complex<8>, !fir.complex<8>, !fir.complex<8>)
+
+// CHECK: ^bb3(%[[z1:.*]]: !fir.complex<8>, %[[z2:.*]]: !fir.complex<8>):  // 2 preds: ^bb1, ^bb2
+// CHECK:  fir.addc %[[z1]], %[[z2]] : !fir.complex<8>
+
+^bb3(%undef : !fir.complex<8>, %z1 : !fir.complex<8>, %z2 : !fir.complex<8>):  // 2 preds: ^bb1, ^bb2
+  %real1 = fir.extract_value %z1, [0 : index] : (!fir.complex<8>) -> f64
+  %imag1 = fir.extract_value %z1, [1 : index] : (!fir.complex<8>) -> f64
+  %real2 = fir.extract_value %z2, [0 : index] : (!fir.complex<8>) -> f64
+  %imag2 = fir.extract_value %z2, [1 : index] : (!fir.complex<8>) -> f64
+  %real = arith.addf %real1, %real2 : f64
+  %imag = arith.addf %imag1, %imag2 : f64
+  %insert_real = fir.insert_value %undef, %real, [0 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  %insert_imag = fir.insert_value %insert_real, %imag, [1 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  fir.store %insert_imag to %z : !fir.ref<!fir.complex<8>>
+  return
+}
+func.func private @bar1() -> !fir.complex<8>
+func.func private @bar2() -> !fir.complex<8>
+
+// CHECK-LABEL: @close_but_bad_pattern
+func.func @close_but_bad_pattern(%z: !fir.ref<!fir.complex<8>>, %z1 : !fir.complex<8>, %z2 : !fir.complex<8>) {
+  %c0 = arith.constant 0 : index
+  %c1 = arith.constant 1 : index
+  %real1 = fir.extract_value %z1, [0 : index] : (!fir.complex<8>) -> f64
+  // extracting %c0 instead of %c1 
+  %imag1 = fir.extract_value %z1, [0 : index] : (!fir.complex<8>) -> f64
+  %real2 = fir.extract_value %z2, [0 : index] : (!fir.complex<8>) -> f64
+  %imag2 = fir.extract_value %z2, [1 : index] : (!fir.complex<8>) -> f64
+  // CHECK: arith.subf
+  // CHECK: subf
+  %real = arith.subf %real1, %real2 : f64
+  %imag = arith.subf %imag1, %imag2 : f64
+  %undef = fir.undefined !fir.complex<8>
+  // CHECK: %[[insert1:.*]] = fir.insert_value %{{.*}}, %{{.*}}, [0
+  // CHECK: %[[insert2:.*]] = fir.insert_value %[[insert1]], %{{.*}}, [1
+  %insert_real = fir.insert_value %undef, %real, [0 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  %insert_imag = fir.insert_value %insert_real, %imag, [1 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  // CHECK: fir.store %[[insert2]] to {{.*}}
+  fir.store %insert_imag to %z : !fir.ref<!fir.complex<8>>
+  return
+}


        


More information about the flang-commits mailing list