[flang-commits] [flang] [flang][CodeGen] Add initial SystemZ ABI support (PR #208618)

via flang-commits flang-commits at lists.llvm.org
Thu Jul 9 21:27:35 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics

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

Author: anoopkg6

<details>
<summary>Changes</summary>

Add initial implementation to enable target-specific code generation and rewriting support for SystemZ architecture in Flang.


@<!-- -->uweigand @<!-- -->dominik-steenken

---

Patch is 46.84 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/208618.diff


16 Files Affected:

- (modified) flang/lib/Frontend/CompilerInvocation.cpp (+6) 
- (modified) flang/lib/Optimizer/CodeGen/Target.cpp (+79) 
- (added) flang/test/Driver/code-gen-systemz.f90 (+9) 
- (added) flang/test/Driver/emit-asm-systemz.f90 (+11) 
- (added) flang/test/Driver/predefined-macros-systemz.f90 (+23) 
- (added) flang/test/Fir/struct-passing-systemz-byval.fir (+51) 
- (added) flang/test/Fir/struct-return-systemz.fir (+63) 
- (modified) flang/test/Fir/target-rewrite-boxchar.fir (+1) 
- (modified) flang/test/Fir/target-rewrite-char-proc.fir (+1) 
- (modified) flang/test/Fir/target-rewrite-complex.fir (+83) 
- (added) flang/test/Fir/target-rewrite-complex16-systemz.fir (+69) 
- (modified) flang/test/Fir/target-rewrite-indirect-calls.fir (+1) 
- (modified) flang/test/Fir/target-rewrite-integer.fir (+18) 
- (modified) flang/test/Fir/target-rewrite-selective.fir (+7) 
- (added) flang/test/Lower/OpenMP/simd_systemz.f90 (+16) 
- (added) flang/test/Semantics/realkinds-systemz-01.f90 (+12) 


``````````diff
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 79ad08353b64c..339b83f351152 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1899,6 +1899,12 @@ void CompilerInvocation::setDefaultPredefinitions() {
     fortranOptions.predefinitions.emplace_back("__aarch64__", "1");
     fortranOptions.predefinitions.emplace_back("__aarch64", "1");
     break;
+  case llvm::Triple::ArchType::systemz:
+    fortranOptions.predefinitions.emplace_back("__s390__", "1");
+    fortranOptions.predefinitions.emplace_back("__s390x__", "1");
+    fortranOptions.predefinitions.emplace_back("__s390x", "1");
+    fortranOptions.predefinitions.emplace_back("__zarch__", "1");
+    break;
   }
 }
 
diff --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp
index 48946d78d900c..37838e9e2e558 100644
--- a/flang/lib/Optimizer/CodeGen/Target.cpp
+++ b/flang/lib/Optimizer/CodeGen/Target.cpp
@@ -1893,6 +1893,81 @@ struct TargetLoongArch64 : public GenericTarget<TargetLoongArch64> {
 };
 } // namespace
 
+//===----------------------------------------------------------------------===//
+// SystemZ target specifics.
+//===----------------------------------------------------------------------===//
+
+namespace {
+struct TargetSystemZ : public GenericTarget<TargetSystemZ> {
+  using GenericTarget::GenericTarget;
+
+  static constexpr int defaultWidth = 64;
+
+  auto complexType(mlir::Type eleTy, bool isResult) const {
+    assert(fir::isa_real(eleTy));
+    CodeGenSpecifics::Marshalling marshal;
+    unsigned short align{std::max(
+        static_cast<unsigned short>(getDataLayout().getTypeABIAlignment(eleTy)),
+        static_cast<unsigned short>(8))};
+    marshal.emplace_back(
+        fir::ReferenceType::get(mlir::TupleType::get(
+            eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})),
+        AT{/*align=*/align, /*byval=*/!isResult, /*sret=*/isResult});
+    return marshal;
+  }
+
+  CodeGenSpecifics::Marshalling
+  complexArgumentType(mlir::Location /*loc*/, mlir::Type eleTy) const override {
+    return complexType(eleTy, false);
+  }
+
+  CodeGenSpecifics::Marshalling
+  complexReturnType(mlir::Location /*loc*/, mlir::Type eleTy) const override {
+    return complexType(eleTy, true);
+  }
+
+  CodeGenSpecifics::Marshalling
+  integerArgumentType(mlir::Location loc,
+                      mlir::IntegerType argTy) const override {
+    if (argTy.getWidth() == 32) {
+      AT::IntegerExtension intExt = argTy.isUnsigned()
+                                        ? AT::IntegerExtension::Zero
+                                        : AT::IntegerExtension::Sign;
+      CodeGenSpecifics::Marshalling marshal;
+      marshal.emplace_back(argTy, AT{/*alignment=*/0, /*byval=*/false,
+                                     /*sret=*/false, /*append=*/false,
+                                     /*intExt=*/intExt});
+      return marshal;
+    }
+    return GenericTarget::integerArgumentType(loc, argTy);
+  }
+
+  CodeGenSpecifics::Marshalling
+  structType(mlir::Location loc, fir::RecordType ty, bool isResult) const {
+    CodeGenSpecifics::Marshalling marshal;
+    auto sizeAndAlign{
+        fir::getTypeSizeAndAlignmentOrCrash(loc, ty, getDataLayout(), kindMap)};
+    unsigned short align{
+        std::max(sizeAndAlign.second, static_cast<unsigned short>(8))};
+    marshal.emplace_back(
+        fir::ReferenceType::get(ty),
+        AT{/*align=*/align, /*byval=*/!isResult, /*sret=*/isResult});
+    return marshal;
+  }
+
+  CodeGenSpecifics::Marshalling
+  structArgumentType(mlir::Location loc, fir::RecordType ty,
+                     const Marshalling &previousArguments) const override {
+    return structType(loc, ty, false);
+  }
+
+  CodeGenSpecifics::Marshalling
+  structReturnType(mlir::Location loc, fir::RecordType ty) const override {
+    return structType(loc, ty, true);
+  }
+};
+} // namespace
+
 // Instantiate the overloaded target instance based on the triple value.
 // TODO: Add other targets to this file as needed.
 std::unique_ptr<fir::CodeGenSpecifics> fir::CodeGenSpecifics::get(
@@ -1960,6 +2035,10 @@ std::unique_ptr<fir::CodeGenSpecifics> fir::CodeGenSpecifics::get(
     return std::make_unique<TargetLoongArch64>(ctx, std::move(trp),
                                                std::move(kindMap), targetCPU,
                                                targetFeatures, targetABI, dl);
+  case llvm::Triple::ArchType::systemz:
+    return std::make_unique<TargetSystemZ>(ctx, std::move(trp),
+                                           std::move(kindMap), targetCPU,
+                                           targetFeatures, targetABI, dl);
   }
   TODO(mlir::UnknownLoc::get(ctx), "target not implemented");
 }
diff --git a/flang/test/Driver/code-gen-systemz.f90 b/flang/test/Driver/code-gen-systemz.f90
new file mode 100644
index 0000000000000..8344fe9e7929b
--- /dev/null
+++ b/flang/test/Driver/code-gen-systemz.f90
@@ -0,0 +1,9 @@
+! Test -emit-obj for SystemZ (s390x)
+
+! REQUIRES: systemz-registered-target
+
+! RUN: %flang_fc1 -triple s390x-unknown-linux-gnu -emit-obj %s -o - | \
+! RUN: llvm-readobj -h - | FileCheck %s
+
+! CHECK: Arch: s390x
+end program
diff --git a/flang/test/Driver/emit-asm-systemz.f90 b/flang/test/Driver/emit-asm-systemz.f90
new file mode 100644
index 0000000000000..af0e250b54e85
--- /dev/null
+++ b/flang/test/Driver/emit-asm-systemz.f90
@@ -0,0 +1,11 @@
+! Test -S (SystemZ)
+
+! REQUIRES: systemz-registered-target
+
+! RUN: %flang_fc1 -S -triple s390x-unknown-linux-gnu %s -o - | FileCheck %s
+! RUN: %flang -S -target s390x-unknown-linux-gnu %s -o - | FileCheck %s
+
+! CHECK-LABEL: _QQmain:
+! CHECK: br %r14
+
+end program
diff --git a/flang/test/Driver/predefined-macros-systemz.f90 b/flang/test/Driver/predefined-macros-systemz.f90
new file mode 100644
index 0000000000000..4babe8bcba3d8
--- /dev/null
+++ b/flang/test/Driver/predefined-macros-systemz.f90
@@ -0,0 +1,23 @@
+! Test predefined macros for SystemZ architecture
+! REQUIRES: systemz-registered-target
+
+! RUN: %flang_fc1 -triple s390x-unknown-linux-gnu -cpp -E %s | FileCheck %s
+
+! CHECK: integer :: var1 = 1
+! CHECK: integer :: var2 = 1
+! CHECK: integer :: var3 = 1
+! CHECK: integer :: var4 = 1
+
+#if __s390__
+  integer :: var1 = __s390__
+#endif
+#if __s390x__
+  integer :: var2 = __s390x__
+#endif
+#if __s390x
+  integer :: var3 = __s390x
+#endif
+#if __zarch__
+  integer :: var4 = __zarch__
+#endif
+end program
diff --git a/flang/test/Fir/struct-passing-systemz-byval.fir b/flang/test/Fir/struct-passing-systemz-byval.fir
new file mode 100644
index 0000000000000..3fc35e4f16b60
--- /dev/null
+++ b/flang/test/Fir/struct-passing-systemz-byval.fir
@@ -0,0 +1,51 @@
+// Test SystemZ ABI rewrite of struct passed by value (BIND(C), VALUE derived types).
+// RUN: fir-opt --target-rewrite="target=s390x-unknown-linux-gnu" %s | FileCheck %s
+
+module attributes {
+  fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:128-v128:64-a:8:16-n32:64", llvm.target_triple = "s390x-unknown-linux-gnu" } {
+
+// CHECK-LABEL: func.func private @test_i32(!fir.ref<!fir.type<t1{i:i32}>>
+// CHECK-SAME:    {llvm.align = 8 : i32, llvm.byval = !fir.type<t1{i:i32}>})
+func.func private @test_i32(%arg0: !fir.type<t1{i:i32}>)
+
+// CHECK-LABEL: func.func @test_call_i32(
+// CHECK-SAME:    %[[ARG0:.*]]: !fir.ref<!fir.type<t1{i:i32}>>) {
+// CHECK: %[[IN:.*]] = fir.load %[[ARG0]] : !fir.ref<!fir.type<t1{i:i32}>>
+// CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr
+// CHECK: %[[TMP:.*]] = fir.alloca !fir.type<t1{i:i32}>
+// CHECK: fir.store %[[IN]] to %[[TMP]] : !fir.ref<!fir.type<t1{i:i32}>>
+// CHECK: fir.call @test_i32(%[[TMP]]) : (!fir.ref<!fir.type<t1{i:i32}>> {llvm.align = 8 : i32, llvm.byval = !fir.type<t1{i:i32}>}) -> ()
+// CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr
+// CHECK: return
+func.func @test_call_i32(%arg0: !fir.ref<!fir.type<t1{i:i32}>>) {
+  %in = fir.load %arg0 : !fir.ref<!fir.type<t1{i:i32}>>
+  fir.call @test_i32(%in) : (!fir.type<t1{i:i32}>) -> ()
+  return
+}
+
+// CHECK-LABEL: func.func private @test_i64(!fir.ref<!fir.type<t2{i:i64}>>
+// CHECK-SAME:    {llvm.align = 8 : i32, llvm.byval = !fir.type<t2{i:i64}>})
+func.func private @test_i64(%arg0: !fir.type<t2{i:i64}>)
+
+// CHECK-LABEL: func.func private @test_f32_f32(!fir.ref<!fir.type<t3{r:f32,i:f32}>>
+// CHECK-SAME:    {llvm.align = 8 : i32, llvm.byval = !fir.type<t3{r:f32,i:f32}>})
+func.func private @test_f32_f32(%arg0: !fir.type<t3{r:f32,i:f32}>)
+
+// CHECK-LABEL: func.func private @test_f64_f64(!fir.ref<!fir.type<t4{r:f64,i:f64}>>
+// CHECK-SAME:    {llvm.align = 8 : i32, llvm.byval = !fir.type<t4{r:f64,i:f64}>})
+func.func private @test_f64_f64(%arg0: !fir.type<t4{r:f64,i:f64}>)
+
+// CHECK-LABEL: func.func private @test_large(!fir.ref<!fir.type<t5{i:!fir.array<8xi32>}>>
+// CHECK-SAME:    {llvm.align = 8 : i32, llvm.byval = !fir.type<t5{i:!fir.array<8xi32>}>})
+func.func private @test_large(%arg0: !fir.type<t5{i:!fir.array<8xi32>}>)
+
+// CHECK-LABEL: func.func private @test_mixed(!fir.ref<!fir.type<t6{i:i32,r:f64}>>
+// CHECK-SAME:    {llvm.align = 8 : i32, llvm.byval = !fir.type<t6{i:i32,r:f64}>})
+func.func private @test_mixed(%arg0: !fir.type<t6{i:i32,r:f64}>)
+
+// Struct with f128 field — alignment is 16, not clamped down to 8.
+// CHECK-LABEL: func.func private @test_f128(!fir.ref<!fir.type<t7{r:f128}>>
+// CHECK-SAME:    {llvm.align = 16 : i32, llvm.byval = !fir.type<t7{r:f128}>})
+func.func private @test_f128(%arg0: !fir.type<t7{r:f128}>)
+
+} // end module
diff --git a/flang/test/Fir/struct-return-systemz.fir b/flang/test/Fir/struct-return-systemz.fir
new file mode 100644
index 0000000000000..d8caac40fbdb3
--- /dev/null
+++ b/flang/test/Fir/struct-return-systemz.fir
@@ -0,0 +1,63 @@
+// Test SystemZ ABI rewrite of struct returned by value (BIND(C), VALUE derived types).
+// RUN: fir-opt --target-rewrite="target=s390x-unknown-linux-gnu" %s | FileCheck %s
+
+module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:128-v128:64-a:8:16-n32:64", llvm.target_triple = "s390x-unknown-linux-gnu"} {
+
+// CHECK-LABEL: func.func private @test_i32(!fir.ref<!fir.type<t1{i:i32}>>
+// CHECK-SAME:    {llvm.align = 8 : i32, llvm.sret = !fir.type<t1{i:i32}>})
+func.func private @test_i32() -> !fir.type<t1{i:i32}>
+
+// CHECK-LABEL: func.func @test_call_i32(
+// CHECK-SAME:    %[[ARG0:.*]]: !fir.ref<!fir.type<t1{i:i32}>>)
+func.func @test_call_i32(%arg0 : !fir.ref<!fir.type<t1{i:i32}>>) {
+  // CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr
+  // CHECK: %[[ARG:.*]] = fir.alloca !fir.type<t1{i:i32}>
+  // CHECK: fir.call @test_i32(%[[ARG]]) : (!fir.ref<!fir.type<t1{i:i32}>> {llvm.align = 8 : i32, llvm.sret = !fir.type<t1{i:i32}>}) -> ()
+  // CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref<!fir.type<t1{i:i32}>>) -> !fir.ref<!fir.type<t1{i:i32}>>
+  // CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t1{i:i32}>>
+  // CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr
+  // CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t1{i:i32}>>
+  // CHECK: return
+  %out = fir.call @test_i32() : () -> !fir.type<t1{i:i32}>
+  fir.store %out to %arg0 : !fir.ref<!fir.type<t1{i:i32}>>
+  return
+}
+
+// CHECK-LABEL: func.func private @test_i64(!fir.ref<!fir.type<t2{i:i64}>>
+// CHECK-SAME:    {llvm.align = 8 : i32, llvm.sret = !fir.type<t2{i:i64}>})
+func.func private @test_i64() -> !fir.type<t2{i:i64}>
+
+// CHECK-LABEL: func.func @test_call_i64(
+// CHECK-SAME:    %[[ARG0:.*]]: !fir.ref<!fir.type<t2{i:i64}>>)
+func.func @test_call_i64(%arg0 : !fir.ref<!fir.type<t2{i:i64}>>) {
+  // CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr
+  // CHECK: %[[ARG:.*]] = fir.alloca !fir.type<t2{i:i64}>
+  // CHECK: fir.call @test_i64(%[[ARG]]) : (!fir.ref<!fir.type<t2{i:i64}>> {llvm.align = 8 : i32, llvm.sret = !fir.type<t2{i:i64}>}) -> ()
+  // CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref<!fir.type<t2{i:i64}>>) -> !fir.ref<!fir.type<t2{i:i64}>>
+  // CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t2{i:i64}>>
+  // CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr
+  // CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t2{i:i64}>>
+  // CHECK: return
+  %out = fir.call @test_i64() : () -> !fir.type<t2{i:i64}>
+  fir.store %out to %arg0 : !fir.ref<!fir.type<t2{i:i64}>>
+  return
+}
+
+// CHECK-LABEL: func.func private @test_f32_f32(!fir.ref<!fir.type<t3{r:f32,i:f32}>>
+// CHECK-SAME:    {llvm.align = 8 : i32, llvm.sret = !fir.type<t3{r:f32,i:f32}>})
+func.func private @test_f32_f32() -> !fir.type<t3{r:f32,i:f32}>
+
+// CHECK-LABEL: func.func private @test_f64_f64(!fir.ref<!fir.type<t4{r:f64,i:f64}>>
+// CHECK-SAME:    {llvm.align = 8 : i32, llvm.sret = !fir.type<t4{r:f64,i:f64}>})
+func.func private @test_f64_f64() -> !fir.type<t4{r:f64,i:f64}>
+
+// CHECK-LABEL: func.func private @test_large(!fir.ref<!fir.type<t5{i:!fir.array<8xi32>}>>
+// CHECK-SAME:    {llvm.align = 8 : i32, llvm.sret = !fir.type<t5{i:!fir.array<8xi32>}>})
+func.func private @test_large() -> !fir.type<t5{i:!fir.array<8xi32>}>
+
+// Struct with f128 field — alignment is 16, not clamped down to 8.
+// CHECK-LABEL: func.func private @test_f128(!fir.ref<!fir.type<t7{r:f128}>>
+// CHECK-SAME:    {llvm.align = 16 : i32, llvm.sret = !fir.type<t7{r:f128}>})
+func.func private @test_f128() -> !fir.type<t7{r:f128}>
+
+} // end module
diff --git a/flang/test/Fir/target-rewrite-boxchar.fir b/flang/test/Fir/target-rewrite-boxchar.fir
index 681536cde6a05..228ee7a367b71 100644
--- a/flang/test/Fir/target-rewrite-boxchar.fir
+++ b/flang/test/Fir/target-rewrite-boxchar.fir
@@ -5,6 +5,7 @@
 // RUN: fir-opt --target-rewrite="target=amdgcn-amd-amdhsa" %s | FileCheck %s --check-prefix=INT64
 // RUN: fir-opt --target-rewrite="target=nvptx64-nvidia-cuda" %s | FileCheck %s --check-prefix=INT64
 // RUN: fir-opt --target-rewrite="target=loongarch64-unknown-linux-gnu" %s | FileCheck %s --check-prefix=INT64
+// RUN: fir-opt --target-rewrite="target=s390x-unknown-linux-gnu" %s | FileCheck %s --check-prefix=INT64
 
 // Test that we rewrite the signatures and bodies of functions that take boxchar
 // parameters.
diff --git a/flang/test/Fir/target-rewrite-char-proc.fir b/flang/test/Fir/target-rewrite-char-proc.fir
index ccb1fc06f6f0d..62655cd081c53 100644
--- a/flang/test/Fir/target-rewrite-char-proc.fir
+++ b/flang/test/Fir/target-rewrite-char-proc.fir
@@ -2,6 +2,7 @@
 // arguments: one for the function address, and one for the length. The length
 // argument is added after other characters.
 // RUN: fir-opt --target-rewrite="target=x86_64-unknown-linux-gnu" %s | FileCheck %s
+// RUN: fir-opt --target-rewrite="target=s390x-unknown-linux-gnu" %s | FileCheck %s
 
 // CHECK:  func private @takes_char_proc(() -> () {fir.char_proc}, i64)
 func.func private @takes_char_proc(tuple<() -> (), i64> {fir.char_proc})
diff --git a/flang/test/Fir/target-rewrite-complex.fir b/flang/test/Fir/target-rewrite-complex.fir
index c8cf867713632..9b0d0464d88d6 100644
--- a/flang/test/Fir/target-rewrite-complex.fir
+++ b/flang/test/Fir/target-rewrite-complex.fir
@@ -10,6 +10,7 @@
 // RUN: fir-opt --target-rewrite="target=powerpc64-ibm-aix7.2.0.0" %s | FileCheck %s --check-prefix=PPC64
 // RUN: fir-opt --target-rewrite="target=powerpc-ibm-aix7.2.0.0" %s | FileCheck %s --check-prefix=PPC
 // RUN: fir-opt --target-rewrite="target=loongarch64-unknown-linux-gnu" %s | FileCheck %s --check-prefix=LOONGARCH64
+// RUN: fir-opt --target-rewrite="target=s390x-unknown-linux-gnu" %s | FileCheck %s --check-prefix=SYSTEMZ
 
 // Test that we rewrite the signature and body of a function that returns a
 // complex<4>.
@@ -24,6 +25,8 @@
 // PPC64-LABEL: func @returncomplex4() -> tuple<f32, f32>
 // PPC-LABEL: func @returncomplex4() -> tuple<f32, f32>
 // LOONGARCH64-LABEL: func @returncomplex4() -> tuple<f32, f32>
+// SYSTEMZ-LABEL: func @returncomplex4
+// SYSTEMZ-SAME: ([[ARG0:%[0-9A-Za-z]+]]: !fir.ref<tuple<f32, f32>>  {llvm.align = 8 : i32, llvm.sret = tuple<f32, f32>})
 func.func @returncomplex4() -> complex<f32> {
   // I32: fir.insert_value
   // I32: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value
@@ -47,6 +50,8 @@ func.func @returncomplex4() -> complex<f32> {
   // PPC: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value
   // LOONGARCH64: fir.insert_value
   // LOONGARCH64: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value
+  // SYSTEMZ: fir.insert_value
+  // SYSTEMZ: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value
   %1 = fir.undefined complex<f32>
   %2 = arith.constant 2.0 : f32
   %3 = fir.convert %2 : (f32) -> f32
@@ -105,6 +110,9 @@ func.func @returncomplex4() -> complex<f32> {
   // PPC: return [[RES]] : tuple<f32, f32>
   // LOONGARCH64: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<f32, f32>
   // LOONGARCH64: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
+  // SYSTEMZ: [[ADDR:%[0-9A-Za-z]+]] = fir.convert [[ARG0]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
+  // SYSTEMZ: fir.store [[VAL]] to [[ADDR]] : !fir.ref<complex<f32>>
+  // SYSTEMZ: return
   return %6 : complex<f32>
 }
 
@@ -124,6 +132,8 @@ func.func @returncomplex4() -> complex<f32> {
 // PPC64-LABEL: func @returncomplex8() -> tuple<f64, f64>
 // PPC-LABEL: func @returncomplex8() -> tuple<f64, f64>
 // LOONGARCH64-LABEL: func @returncomplex8() -> tuple<f64, f64>
+// SYSTEMZ-LABEL: func @returncomplex8
+// SYSTEMZ-SAME: ([[ARG0:%[0-9A-Za-z]+]]: !fir.ref<tuple<f64, f64>>  {llvm.align = 8 : i32, llvm.sret = tuple<f64, f64>})
 func.func @returncomplex8() -> complex<f64> {
   // I32: fir.insert_value
   // I32: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value {{.*}}
@@ -147,6 +157,8 @@ func.func @returncomplex8() -> complex<f64> {
   // PPC: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value {{.*}}
   // LOONGARCH64: fir.insert_value
   // LOONGARCH64: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value {{.*}}
+  // SYSTEMZ: fir.insert_value
+  // SYSTEMZ: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value {{.*}}
   %1 = fir.undefined complex<f64>
   %2 = arith.constant 1.0 : f64
   %3 = arith.constant -4.0 : f64
@@ -204,6 +216,9 @@ func.func @returncomplex8() -> complex<f64> {
   // LOONGARCH64: fir.store [[VAL]] to [[ADDRC]] : !fir.ref<complex<f64>>
   // LOONGARCH64: [[RES:%[0-9A-Za-z]+]] = fir.load [[ADDRT]] : !fir.ref<tuple<f64, f64>>
   // LOONGARCH64: return [[RES]] : tuple<f64, f64>
+  // SYSTEMZ: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ARG0]] : (!fir.ref<tuple<f64, f64>>) -> !fir.ref<complex<f64>>
+  // SYSTEMZ: fir.store [[VAL]] to [[ADDRC]] : !fir.ref<complex<f64>>
+  // SYSTEMZ: return
   return %5 : complex<f64>
 }
 
@@ -219,6 +234,7 @@ func.func @returncomplex8() -> complex<f64> {
 // PPC64-LABEL: func private @paramcomplex4(f32, f32)
 // PPC-LABEL: func private @paramcomplex4(f32, f32)
 // LOONGARCH64-LABEL: func private @paramcomplex4(f32, f32)
+// SYSTEMZ-LABEL: func private @paramcomplex4(!fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>})
 func.func private @paramcomplex4(complex<f32>) -> ()
 
 // Test that we rewrite calls to functions that return or accept complex<4>.
@@ -233,6 +249,7 @@ func.func private @paramcomplex4(complex<f32>) -> ()
 // PPC64-LABEL: func @callcomplex4
 // PPC-LABEL: func @callcomplex4
 // LOONGARCH64-LABEL: func @callcomplex4
+// SYSTEMZ-LABEL: func @callcomplex4
 func.func @callcomplex4(%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) {
 
   // I32: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex4() : () -> i64
@@ -246,6 +263,9 @@ func.func @callcomplex4(%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i3
   // PPC64: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex4() : () -> tuple<f32, f32>
   // PPC: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex4() : () -> tuple<f32, f32>
   // LOONGARCH64: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex4() : () -> tuple<f32, f32>
+  // SYSTEMZ: [[STCK:%[0-9A-Za-z]+]] = llvm.intr.stacksave : !llvm.ptr
+  // SYSTEMZ: [[RES:%[0-9A-Za-z]+]] = fir.alloca tuple<f32, f32>
+  // SYSTEMZ: fir.call @returncomplex4([[RES]]) : (!fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.sret = tuple<f32, f32>}) -> ()
   %1 = fir.call @returncomplex4() : () -> complex<f32>
 
   // I32: [[ADDRI64:%[0-9A-Za-z]+]] = fir.alloca i64
@@ -343,6 +363,13 @@ func.func @callcomplex...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/208618


More information about the flang-commits mailing list