[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:02 PDT 2026
https://github.com/anoopkg6 created https://github.com/llvm/llvm-project/pull/208618
Add initial implementation to enable target-specific code generation and rewriting support for SystemZ architecture in Flang.
@uweigand @dominik-steenken
>From 26e5075029b4bdf663b4d63f77e4a0481bf2e08c Mon Sep 17 00:00:00 2001
From: "anoop.kumar6 at ibm.com" <anoopk at b35lp63.lnxne.boe>
Date: Fri, 10 Jul 2026 03:24:18 +0200
Subject: [PATCH] [flang][CodeGen] Add initial SystemZ ABI support
---
flang/lib/Frontend/CompilerInvocation.cpp | 6 ++
flang/lib/Optimizer/CodeGen/Target.cpp | 79 ++++++++++++++++++
flang/test/Driver/code-gen-systemz.f90 | 9 ++
flang/test/Driver/emit-asm-systemz.f90 | 11 +++
.../test/Driver/predefined-macros-systemz.f90 | 23 +++++
.../test/Fir/struct-passing-systemz-byval.fir | 51 ++++++++++++
flang/test/Fir/struct-return-systemz.fir | 63 ++++++++++++++
flang/test/Fir/target-rewrite-boxchar.fir | 1 +
flang/test/Fir/target-rewrite-char-proc.fir | 1 +
flang/test/Fir/target-rewrite-complex.fir | 83 +++++++++++++++++++
.../Fir/target-rewrite-complex16-systemz.fir | 69 +++++++++++++++
.../Fir/target-rewrite-indirect-calls.fir | 1 +
flang/test/Fir/target-rewrite-integer.fir | 18 ++++
flang/test/Fir/target-rewrite-selective.fir | 7 ++
flang/test/Lower/OpenMP/simd_systemz.f90 | 16 ++++
flang/test/Semantics/realkinds-systemz-01.f90 | 12 +++
16 files changed, 450 insertions(+)
create mode 100644 flang/test/Driver/code-gen-systemz.f90
create mode 100644 flang/test/Driver/emit-asm-systemz.f90
create mode 100644 flang/test/Driver/predefined-macros-systemz.f90
create mode 100644 flang/test/Fir/struct-passing-systemz-byval.fir
create mode 100644 flang/test/Fir/struct-return-systemz.fir
create mode 100644 flang/test/Fir/target-rewrite-complex16-systemz.fir
create mode 100644 flang/test/Lower/OpenMP/simd_systemz.f90
create mode 100644 flang/test/Semantics/realkinds-systemz-01.f90
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 @callcomplex4(%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i3
// LOONGARCH64: [[A:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [0 : i32] : (complex<f32>) -> f32
// LOONGARCH64: [[B:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [1 : i32] : (complex<f32>) -> f32
// LOONGARCH64: fir.call @paramcomplex4([[A]], [[B]]) : (f32, f32) -> ()
+ // SYSTEMZ: [[RESC:%[0-9A-Za-z]+]] = fir.convert [[RES]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
+ // SYSTEMZ: [[C:%[0-9A-Za-z]+]] = fir.load [[RESC]] : !fir.ref<complex<f32>>
+ // SYSTEMZ: llvm.intr.stackrestore [[STCK]] : !llvm.ptr
+ // SYSTEMZ: [[TMP:%[0-9A-Za-z]+]] = fir.alloca complex<f32>
+ // SYSTEMZ: fir.store [[C]] to [[TMP]] : !fir.ref<complex<f32>>
+ // SYSTEMZ: [[T:%[0-9A-Za-z]+]] = fir.convert [[TMP]] : (!fir.ref<complex<f32>>) -> !fir.ref<tuple<f32, f32>>
+ // SYSTEMZ: fir.call @paramcomplex4([[T]]) : (!fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>}) -> ()
fir.call @paramcomplex4(%1) : (complex<f32>) -> ()
// I32: [[RES:%[0-9A-Za-z]+]] = fir.dispatch "ret_complex"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) -> i64 {pass_arg_pos = 0 : i32}
@@ -354,6 +381,12 @@ func.func @callcomplex4(%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i3
// SPARCV9: [[RES:%[0-9A-Za-z]+]] = fir.dispatch "ret_complex"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) -> tuple<f32, f32> {pass_arg_pos = 0 : i32}
// PPC64: [[RES:%[0-9A-Za-z]+]] = fir.dispatch "ret_complex"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) -> tuple<f32, f32> {pass_arg_pos = 0 : i32}
// PPC: [[RES:%[0-9A-Za-z]+]] = fir.dispatch "ret_complex"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) -> tuple<f32, f32> {pass_arg_pos = 0 : i32}
+ // SYSTEMZ: [[STCK2:%[0-9A-Za-z]+]] = llvm.intr.stacksave : !llvm.ptr
+ // SYSTEMZ: [[RES2:%[0-9A-Za-z]+]] = fir.alloca tuple<f32, f32>
+ // SYSTEMZ: fir.dispatch "ret_complex"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) ([[RES2]], %{{.*}} : !fir.ref<tuple<f32, f32>>, !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) {pass_arg_pos = 1 : i32}
+ // SYSTEMZ: [[RESC2:%[0-9A-Za-z]+]] = fir.convert [[RES2]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
+ // SYSTEMZ: [[C2:%[0-9A-Za-z]+]] = fir.load [[RESC2]] : !fir.ref<complex<f32>>
+ // SYSTEMZ: llvm.intr.stackrestore [[STCK2]] : !llvm.ptr
%2 = fir.dispatch "ret_complex"(%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) -> complex<f32> {pass_arg_pos = 0 : i32}
// I32: [[ADDRI64:%[0-9A-Za-z]+]] = fir.alloca i64
@@ -427,6 +460,12 @@ func.func @callcomplex4(%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i3
// PPC64: [[A:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [0 : i32] : (complex<f32>) -> f32
// PPC64: [[B:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [1 : i32] : (complex<f32>) -> f32
// PPC64: fir.dispatch "with_complex"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%{{.*}}, [[A]], [[B]] : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>, f32, f32) {pass_arg_pos = 0 : i32}
+ // SYSTEMZ: [[STCK3:%[0-9A-Za-z]+]] = llvm.intr.stacksave : !llvm.ptr
+ // SYSTEMZ: [[TMP3:%[0-9A-Za-z]+]] = fir.alloca complex<f32>
+ // SYSTEMZ: fir.store [[C2]] to [[TMP3]] : !fir.ref<complex<f32>>
+ // SYSTEMZ: [[T3:%[0-9A-Za-z]+]] = fir.convert [[TMP3]] : (!fir.ref<complex<f32>>) -> !fir.ref<tuple<f32, f32>>
+ // SYSTEMZ: fir.dispatch "with_complex"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%{{.*}}, [[T3]] : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>, !fir.ref<tuple<f32, f32>>) {pass_arg_pos = 0 : i32}
+ // SYSTEMZ: llvm.intr.stackrestore [[STCK3]] : !llvm.ptr
fir.dispatch "with_complex"(%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%arg0, %2 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>, complex<f32>) {pass_arg_pos = 0 : i32}
// PPC: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<f32, f32>
@@ -436,6 +475,13 @@ func.func @callcomplex4(%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i3
// PPC: [[A:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [0 : i32] : (complex<f32>) -> f32
// PPC: [[B:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [1 : i32] : (complex<f32>) -> f32
// PPC: fir.dispatch "with_complex"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%{{.*}}, [[A]], [[B]] : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>, f32, f32) {pass_arg_pos = 0 : i32}
+ // SYSTEMZ: [[STCK4:%[0-9A-Za-z]+]] = llvm.intr.stacksave : !llvm.ptr
+ // SYSTEMZ: [[TMP4:%[0-9A-Za-z]+]] = fir.alloca complex<f32>
+ // SYSTEMZ: fir.store [[C2]] to [[TMP4]] : !fir.ref<complex<f32>>
+ // SYSTEMZ: [[T4:%[0-9A-Za-z]+]] = fir.convert [[TMP4]] : (!fir.ref<complex<f32>>) -> !fir.ref<tuple<f32, f32>>
+ // SYSTEMZ: fir.dispatch "with_complex"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%{{.*}}, [[T4]] : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>, !fir.ref<tuple<f32, f32>>) {pass_arg_pos = 0 : i32}
+ // SYSTEMZ: llvm.intr.stackrestore [[STCK4]] : !llvm.ptr
+
fir.dispatch "with_complex"(%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%arg0, %2 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>, complex<f32>) {pass_arg_pos = 0 : i32}
// I32: fir.dispatch "with_complex2"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%{{.*}}, %{{.*}} : !fir.ref<tuple<f32, f32>>, !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) {pass_arg_pos = 1 : i32}
@@ -449,6 +495,12 @@ func.func @callcomplex4(%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i3
// PPC64: fir.dispatch "with_complex2"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%{{.*}}, %{{.*}}, %{{.*}} : f32, f32, !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) {pass_arg_pos = 2 : i32}
// PPC: fir.dispatch "with_complex2"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%{{.*}}, %{{.*}}, %{{.*}} : f32, f32, !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) {pass_arg_pos = 2 : i32}
// LOONGARCH64: fir.dispatch "with_complex2"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%{{.*}}, %{{.*}}, %{{.*}} : f32, f32, !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) {pass_arg_pos = 2 : i32}
+ // SYSTEMZ: [[STCK5:%[0-9A-Za-z]+]] = llvm.intr.stacksave : !llvm.ptr
+ // SYSTEMZ: [[TMP5:%[0-9A-Za-z]+]] = fir.alloca complex<f32>
+ // SYSTEMZ: fir.store [[C2]] to [[TMP5]] : !fir.ref<complex<f32>>
+ // SYSTEMZ: [[T5:%[0-9A-Za-z]+]] = fir.convert [[TMP5]] : (!fir.ref<complex<f32>>) -> !fir.ref<tuple<f32, f32>>
+ // SYSTEMZ: fir.dispatch "with_complex2"(%{{.*}} : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) ([[T5]], %{{.*}} : !fir.ref<tuple<f32, f32>>, !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) {pass_arg_pos = 1 : i32}
+ // SYSTEMZ: llvm.intr.stackrestore [[STCK5]] : !llvm.ptr
fir.dispatch "with_complex2"(%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) (%2, %arg0 : complex<f32>, !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) {pass_arg_pos = 1 : i32}
return
@@ -466,6 +518,7 @@ func.func @callcomplex4(%arg0 : !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i3
// PPC64-LABEL: func private @paramcomplex8(f64, f64)
// PPC-LABEL: func private @paramcomplex8(f64, f64)
// LOONGARCH64-LABEL: func private @paramcomplex8(f64, f64)
+// SYSTEMZ-LABEL: func private @paramcomplex8(!fir.ref<tuple<f64, f64>> {llvm.align = 8 : i32, llvm.byval = tuple<f64, f64>})
func.func private @paramcomplex8(complex<f64>) -> ()
// Test that we rewrite calls to functions that return or accept complex<8>.
@@ -480,6 +533,7 @@ func.func private @paramcomplex8(complex<f64>) -> ()
// PPC64-LABEL: func @callcomplex8()
// PPC-LABEL: func @callcomplex8()
// LOONGARCH64-LABEL: func @callcomplex8()
+// SYSTEMZ-LABEL: func @callcomplex8()
func.func @callcomplex8() {
// I32: [[RES:%[0-9A-Za-z]+]] = fir.alloca tuple<f64, f64>
// I32: fir.call @returncomplex8([[RES]]) : (!fir.ref<tuple<f64, f64>> {llvm.align = 4 : i32, llvm.sret = tuple<f64, f64>}) -> ()
@@ -495,6 +549,9 @@ func.func @callcomplex8() {
// PPC64: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex8() : () -> tuple<f64, f64>
// PPC: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex8() : () -> tuple<f64, f64>
// LOONGARCH64: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex8() : () -> tuple<f64, f64>
+ // SYSTEMZ: [[STCK:%[0-9A-Za-z]+]] = llvm.intr.stacksave : !llvm.ptr
+ // SYSTEMZ: [[RES:%[0-9A-Za-z]+]] = fir.alloca tuple<f64, f64>
+ // SYSTEMZ: fir.call @returncomplex8([[RES]]) : (!fir.ref<tuple<f64, f64>> {llvm.align = 8 : i32, llvm.sret = tuple<f64, f64>}) -> ()
%1 = fir.call @returncomplex8() : () -> complex<f64>
// I32: [[RESC:%[0-9A-Za-z]+]] = fir.convert [[RES]] : (!fir.ref<tuple<f64, f64>>) -> !fir.ref<complex<f64>>
@@ -583,6 +640,13 @@ func.func @callcomplex8() {
// LOONGARCH64: [[A:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [0 : i32] : (complex<f64>) -> f64
// LOONGARCH64: [[B:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [1 : i32] : (complex<f64>) -> f64
// LOONGARCH64: fir.call @paramcomplex8([[A]], [[B]]) : (f64, f64) -> ()
+ // SYSTEMZ: [[RESC:%[0-9A-Za-z]+]] = fir.convert [[RES]] : (!fir.ref<tuple<f64, f64>>) -> !fir.ref<complex<f64>>
+ // SYSTEMZ: [[C:%[0-9A-Za-z]+]] = fir.load [[RESC]] : !fir.ref<complex<f64>>
+ // SYSTEMZ: llvm.intr.stackrestore [[STCK]] : !llvm.ptr
+ // SYSTEMZ: [[TMP:%[0-9A-Za-z]+]] = fir.alloca complex<f64>
+ // SYSTEMZ: fir.store [[C]] to [[TMP]] : !fir.ref<complex<f64>>
+ // SYSTEMZ: [[T:%[0-9A-Za-z]+]] = fir.convert [[TMP]] : (!fir.ref<complex<f64>>) -> !fir.ref<tuple<f64, f64>>
+ // SYSTEMZ: fir.call @paramcomplex8([[T]]) : (!fir.ref<tuple<f64, f64>> {llvm.align = 8 : i32, llvm.byval = tuple<f64, f64>}) -> ()
fir.call @paramcomplex8(%1) : (complex<f64>) -> ()
return
@@ -600,6 +664,7 @@ func.func @callcomplex8() {
// PPC64-LABEL: func private @calleemultipleparamscomplex4(f32, f32, f32, f32, f32, f32)
// PPC-LABEL: func private @calleemultipleparamscomplex4(f32, f32, f32, f32, f32, f32)
// LOONGARCH64-LABEL: func private @calleemultipleparamscomplex4(f32, f32, f32, f32, f32, f32)
+// SYSTEMZ-LABEL: func private @calleemultipleparamscomplex4(!fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>}, !fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>}, !fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>})
func.func private @calleemultipleparamscomplex4(complex<f32>, complex<f32>, complex<f32>) -> ()
// I32-LABEL: func @multipleparamscomplex4
@@ -624,6 +689,8 @@ func.func private @calleemultipleparamscomplex4(complex<f32>, complex<f32>, comp
// PPC-SAME: ([[A1:%[0-9A-Za-z]+]]: f32, [[B1:%[0-9A-Za-z]+]]: f32, [[A2:%[0-9A-Za-z]+]]: f32, [[B2:%[0-9A-Za-z]+]]: f32, [[A3:%[0-9A-Za-z]+]]: f32, [[B3:%[0-9A-Za-z]+]]: f32)
// LOONGARCH64-LABEL: func @multipleparamscomplex4
// LOONGARCH64-SAME: ([[A1:%[0-9A-Za-z]+]]: f32, [[B1:%[0-9A-Za-z]+]]: f32, [[A2:%[0-9A-Za-z]+]]: f32, [[B2:%[0-9A-Za-z]+]]: f32, [[A3:%[0-9A-Za-z]+]]: f32, [[B3:%[0-9A-Za-z]+]]: f32)
+// SYSTEMZ-LABEL: func @multipleparamscomplex4
+// SYSTEMZ-SAME: ([[Z1:%[0-9A-Za-z]+]]: !fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>}, [[Z2:%[0-9A-Za-z]+]]: !fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>}, [[Z3:%[0-9A-Za-z]+]]: !fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>})
func.func @multipleparamscomplex4(%z1 : complex<f32>, %z2 : complex<f32>, %z3 : complex<f32>) {
// I32-DAG: [[Z1_ADDR:%[0-9A-Za-z]+]] = fir.convert [[Z1]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
// I32-DAG: [[Z1_VAL:%[0-9A-Za-z]+]] = fir.load [[Z1_ADDR]] : !fir.ref<complex<f32>>
@@ -860,6 +927,22 @@ func.func @multipleparamscomplex4(%z1 : complex<f32>, %z2 : complex<f32>, %z3 :
// LOONGARCH64-DAG: [[B3_EXTR:%[0-9A-Za-z]+]] = fir.extract_value [[Z3]], [1 : i32] : (complex<f32>) -> f32
// LOONGARCH64: fir.call @calleemultipleparamscomplex4([[A1_EXTR]], [[B1_EXTR]], [[A2_EXTR]], [[B2_EXTR]], [[A3_EXTR]], [[B3_EXTR]]) : (f32, f32, f32, f32, f32, f32) -> ()
+ // SYSTEMZ-DAG: [[Z1_ADDR:%[0-9A-Za-z]+]] = fir.convert [[Z1]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
+ // SYSTEMZ-DAG: [[Z1_VAL:%[0-9A-Za-z]+]] = fir.load [[Z1_ADDR]] : !fir.ref<complex<f32>>
+ // SYSTEMZ-DAG: [[Z2_ADDR:%[0-9A-Za-z]+]] = fir.convert [[Z2]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
+ // SYSTEMZ-DAG: [[Z2_VAL:%[0-9A-Za-z]+]] = fir.load [[Z2_ADDR]] : !fir.ref<complex<f32>>
+ // SYSTEMZ-DAG: [[Z3_ADDR:%[0-9A-Za-z]+]] = fir.convert [[Z3]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
+ // SYSTEMZ-DAG: [[Z3_VAL:%[0-9A-Za-z]+]] = fir.load [[Z3_ADDR]] : !fir.ref<complex<f32>>
+ // SYSTEMZ-DAG: [[Z1_ADDRC:%[0-9A-Za-z]+]] = fir.alloca complex<f32>
+ // SYSTEMZ-DAG: fir.store [[Z1_VAL]] to [[Z1_ADDRC]] : !fir.ref<complex<f32>>
+ // SYSTEMZ-DAG: [[Z1_ADDRT:%[0-9A-Za-z]+]] = fir.convert [[Z1_ADDRC]] : (!fir.ref<complex<f32>>) -> !fir.ref<tuple<f32, f32>>
+ // SYSTEMZ-DAG: [[Z2_ADDRC:%[0-9A-Za-z]+]] = fir.alloca complex<f32>
+ // SYSTEMZ-DAG: fir.store [[Z2_VAL]] to [[Z2_ADDRC]] : !fir.ref<complex<f32>>
+ // SYSTEMZ-DAG: [[Z2_ADDRT:%[0-9A-Za-z]+]] = fir.convert [[Z2_ADDRC]] : (!fir.ref<complex<f32>>) -> !fir.ref<tuple<f32, f32>>
+ // SYSTEMZ-DAG: [[Z3_ADDRC:%[0-9A-Za-z]+]] = fir.alloca complex<f32>
+ // SYSTEMZ-DAG: fir.store [[Z3_VAL]] to [[Z3_ADDRC]] : !fir.ref<complex<f32>>
+ // SYSTEMZ-DAG: [[Z3_ADDRT:%[0-9A-Za-z]+]] = fir.convert [[Z3_ADDRC]] : (!fir.ref<complex<f32>>) -> !fir.ref<tuple<f32, f32>>
+ // SYSTEMZ: fir.call @calleemultipleparamscomplex4([[Z1_ADDRT]], [[Z2_ADDRT]], [[Z3_ADDRT]]) : (!fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>}, !fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>}, !fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>}) -> ()
fir.call @calleemultipleparamscomplex4(%z1, %z2, %z3) : (complex<f32>, complex<f32>, complex<f32>) -> ()
return
}
diff --git a/flang/test/Fir/target-rewrite-complex16-systemz.fir b/flang/test/Fir/target-rewrite-complex16-systemz.fir
new file mode 100644
index 0000000000000..71703e543c610
--- /dev/null
+++ b/flang/test/Fir/target-rewrite-complex16-systemz.fir
@@ -0,0 +1,69 @@
+// RUN: fir-opt --target-rewrite="target=s390x-unknown-linux-gnu" %s | FileCheck %s
+// This test checks SystemZ target rewriting for complex(16) / complex<f128>.
+// An explicit `llvm.data_layout` is required to override the generic
+// MLIR fallback data layout (which defaults f128 to 16-byte alignment).
+// The SystemZ ABI requires an 8-byte alignment for complex(16) aggregates.
+module attributes {
+ llvm.data_layout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64",
+ llvm.target_triple = "s390x-unknown-linux-gnu" } {
+
+func.func @returncomplex16() -> complex<f128> {
+ %1 = fir.undefined complex<f128>
+ %2 = arith.constant 2.0 : f128
+ %3 = fir.convert %2 : (f128) -> f128
+ %c0 = arith.constant 0 : i32
+ %4 = fir.insert_value %1, %3, [0 : i32] : (complex<f128>, f128) -> complex<f128>
+ %c1 = arith.constant 1 : i32
+ %5 = arith.constant -42.0 : f128
+ %6 = fir.insert_value %4, %5, [1 : i32] : (complex<f128>, f128) -> complex<f128>
+ return %6 : complex<f128>
+}
+
+func.func private @paramcomplex16(complex<f128>) -> ()
+
+func.func @callcomplex16() {
+ %1 = fir.call @returncomplex16() : () -> complex<f128>
+ fir.call @paramcomplex16(%1) : (complex<f128>) -> ()
+ return
+}
+
+func.func private @calleemultipleparamscomplex16(complex<f128>, complex<f128>, complex<f128>) -> ()
+
+func.func @multipleparamscomplex16(%z1 : complex<f128>, %z2 : complex<f128>, %z3 : complex<f128>) {
+ fir.call @calleemultipleparamscomplex16(%z1, %z2, %z3) : (complex<f128>, complex<f128>, complex<f128>) -> ()
+ return
+}
+
+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>
+}
+
+func.func @addrof() {
+ %r = fir.address_of(@returncomplex16) : () -> complex<f128>
+ %p = fir.address_of(@paramcomplex16) : (complex<f128>) -> ()
+ return
+}
+
+} // module
+
+// CHECK-LABEL: func.func @returncomplex16(
+// CHECK-SAME: %{{.*}}: !fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.sret = tuple<f128, f128>}) {
+
+// CHECK: func.func private @paramcomplex16(!fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.byval = tuple<f128, f128>})
+
+// CHECK-LABEL: func.func @callcomplex16() {
+// CHECK: fir.call @returncomplex16(%{{.*}}) : (!fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.sret = tuple<f128, f128>}) -> ()
+// CHECK: fir.call @paramcomplex16(%{{.*}}) : (!fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.byval = tuple<f128, f128>}) -> ()
+
+// CHECK: func.func private @calleemultipleparamscomplex16(!fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.byval = tuple<f128, f128>}, !fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.byval = tuple<f128, f128>}, !fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.byval = tuple<f128, f128>})
+
+// CHECK-LABEL: func.func @multipleparamscomplex16(
+// CHECK-SAME: %{{.*}}: !fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.byval = tuple<f128, f128>}, %{{.*}}: !fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.byval = tuple<f128, f128>}, %{{.*}}: !fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.byval = tuple<f128, f128>}) {
+
+// CHECK-LABEL: func.func private @mlircomplexf128(
+// CHECK-SAME: %{{.*}}: !fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.sret = tuple<f128, f128>}, %{{.*}}: !fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.byval = tuple<f128, f128>}, %{{.*}}: !fir.ref<tuple<f128, f128>> {llvm.align = 8 : i32, llvm.byval = tuple<f128, f128>}) {
+
+// CHECK-LABEL: func.func @addrof() {
+// CHECK: fir.address_of(@returncomplex16) : (!fir.ref<tuple<f128, f128>>) -> ()
+// CHECK: fir.address_of(@paramcomplex16) : (!fir.ref<tuple<f128, f128>>) -> ()
diff --git a/flang/test/Fir/target-rewrite-indirect-calls.fir b/flang/test/Fir/target-rewrite-indirect-calls.fir
index 58a9a260b9a98..ccf9bf0e0be59 100644
--- a/flang/test/Fir/target-rewrite-indirect-calls.fir
+++ b/flang/test/Fir/target-rewrite-indirect-calls.fir
@@ -1,5 +1,6 @@
// Test that ABI attributes are set in indirect calls to BIND(C) functions.
// 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
func.func @test(%arg0: () -> (), %arg1: !fir.ref<!fir.type<t{a:!fir.array<5xf64>}>>, %arg2: f64) {
%0 = fir.load %arg1 : !fir.ref<!fir.type<t{a:!fir.array<5xf64>}>>
diff --git a/flang/test/Fir/target-rewrite-integer.fir b/flang/test/Fir/target-rewrite-integer.fir
index 4cb2026cf9ee0..66a3cce49a470 100644
--- a/flang/test/Fir/target-rewrite-integer.fir
+++ b/flang/test/Fir/target-rewrite-integer.fir
@@ -7,6 +7,7 @@
// RUN: fir-opt --split-input-file --target-rewrite="target=sparc64-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=SPARCV9,ALL
// RUN: fir-opt --split-input-file --target-rewrite="target=sparcv9-sun-solaris2.11" %s | FileCheck %s --check-prefixes=SPARCV9,ALL
// RUN: fir-opt --split-input-file --target-rewrite="target=loongarch64-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=LOONGARCH64,ALL
+// RUN: fir-opt --split-input-file --target-rewrite="target=s390x-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=SYSTEMZ,ALL
// -----
@@ -23,6 +24,7 @@
// PPC: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
// SPARCV9: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
// LOONGARCH64: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
+// SYSTEMZ: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
func.func @_QPtest_i1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "x"}) {
%c3_i32 = arith.constant 3 : i32
%c-1_i32 = arith.constant -1 : i32
@@ -56,6 +58,7 @@ func.func private @_FortranAioEndIoStatement(!fir.ref<i8>) -> i32 attributes {fi
// PPC: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
// SPARCV9: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
// LOONGARCH64: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
+// SYSTEMZ: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
func.func @_QPtest_si1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "x"}) {
%0 = fir.load %arg0 : !fir.ref<!fir.logical<4>>
%1 = fir.convert %0 : (!fir.logical<4>) -> si1
@@ -77,6 +80,7 @@ func.func private @_SomeFunc_si1(si1) -> si1 attributes {fir.runtime}
// PPC: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
// SPARCV9: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
// LOONGARCH64: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
+// SYSTEMZ: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
func.func @_QPtest_ui1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "x"}) {
%0 = fir.load %arg0 : !fir.ref<!fir.logical<4>>
%1 = fir.convert %0 : (!fir.logical<4>) -> ui1
@@ -118,6 +122,8 @@ func.func private @_SomeFunc_ui1(ui1) -> ui1 attributes {fir.runtime}
// SPARCV9: func.func private @cfun16(i16 {llvm.signext}) -> (i16 {llvm.signext}) attributes {fir.bindc_name = "cfun16"}
// LOONGARCH64: func.func private @cfun8(i8 {llvm.signext}) -> (i8 {llvm.signext}) attributes {fir.bindc_name = "cfun8"}
// LOONGARCH64: func.func private @cfun16(i16 {llvm.signext}) -> (i16 {llvm.signext}) attributes {fir.bindc_name = "cfun16"}
+// SYSTEMZ: func.func private @cfun8(i8 {llvm.signext}) -> (i8 {llvm.signext}) attributes {fir.bindc_name = "cfun8"}
+// SYSTEMZ: func.func private @cfun16(i16 {llvm.signext}) -> (i16 {llvm.signext}) attributes {fir.bindc_name = "cfun16"}
func.func @_QPtest_bindc(%arg0: !fir.ref<i8> {fir.bindc_name = "x"}, %arg1: !fir.ref<i16> {fir.bindc_name = "y"}) {
%0 = fir.load %arg0 : !fir.ref<i8>
%1 = fir.call @cfun8(%0) fastmath<contract> : (i8) -> i8
@@ -129,3 +135,15 @@ func.func @_QPtest_bindc(%arg0: !fir.ref<i8> {fir.bindc_name = "x"}, %arg1: !fir
}
func.func private @cfun8(i8) -> i8 attributes {fir.bindc_name = "cfun8"}
func.func private @cfun16(i16) -> i16 attributes {fir.bindc_name = "cfun16"}
+
+// -----
+
+// SYSTEMZ-LABEL: @_QPtest_bindc32
+// SYSTEMZ: func.func private @cfun32(i32 {llvm.signext}) -> (i32 {llvm.signext}) attributes {fir.bindc_name = "cfun32"}
+func.func @_QPtest_bindc32(%arg0: !fir.ref<i32> {fir.bindc_name = "x"}) {
+ %0 = fir.load %arg0 : !fir.ref<i32>
+ %1 = fir.call @cfun32(%0) fastmath<contract> : (i32) -> i32
+ fir.store %1 to %arg0 : !fir.ref<i32>
+ return
+}
+func.func private @cfun32(i32) -> i32 attributes {fir.bindc_name = "cfun32"}
diff --git a/flang/test/Fir/target-rewrite-selective.fir b/flang/test/Fir/target-rewrite-selective.fir
index eac1d35f8d24a..51f52de8c833b 100644
--- a/flang/test/Fir/target-rewrite-selective.fir
+++ b/flang/test/Fir/target-rewrite-selective.fir
@@ -1,5 +1,7 @@
// RUN: fir-opt --target-rewrite="target=x86_64-unknown-linux-gnu no-complex-conversion" %s | FileCheck --check-prefix=CMPLXOFF %s
// RUN: fir-opt --target-rewrite="target=x86_64-unknown-linux-gnu no-character-conversion" %s | FileCheck --check-prefix=CHAROFF %s
+// RUN: fir-opt --target-rewrite="target=s390x-unknown-linux-gnu no-complex-conversion" %s | FileCheck --check-prefix=CMPLXOFF %s
+// RUN: fir-opt --target-rewrite="target=s390x-unknown-linux-gnu no-character-conversion" %s | FileCheck --check-prefix=SYSTEMZ_CHAROFF %s
// Verify that selective TargetRewrite with no-complex-conversion and
// no-character-conversion options works as expected.
@@ -31,6 +33,11 @@
// CHAROFF-DAG: func.func private @_QPtest1(!fir.boxchar<1>, !fir.vector<2:f32>) -> !fir.vector<2:f32>
// CHAROFF-DAG: func.func private @_QPtest2(!fir.ref<!fir.char<1,10>>, index, !fir.vector<2:f32>) -> !fir.boxchar<1>
+// SYSTEMZ_CHAROFF-DAG: fir.call @_QPtest1({{.*}}, {{.*}}, {{.*}}) fastmath<contract> : (!fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.sret = tuple<f32, f32>}, !fir.boxchar<1>, !fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>}) -> ()
+// SYSTEMZ_CHAROFF-DAG: fir.call @_QPtest2({{.*}}, {{.*}}, {{.*}}) fastmath<contract> : (!fir.ref<!fir.char<1,10>>, index, !fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>}) -> !fir.boxchar<1>
+// SYSTEMZ_CHAROFF-DAG: func.func private @_QPtest1(!fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.sret = tuple<f32, f32>}, !fir.boxchar<1>, !fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>})
+// SYSTEMZ_CHAROFF-DAG: func.func private @_QPtest2(!fir.ref<!fir.char<1,10>>, index, !fir.ref<tuple<f32, f32>> {llvm.align = 8 : i32, llvm.byval = tuple<f32, f32>}) -> !fir.boxchar<1>
+
module {
func.func @_QPtest(%arg0: complex<f32> {fir.bindc_name = "value"}) -> complex<f32> {
%c10 = arith.constant 10 : index
diff --git a/flang/test/Lower/OpenMP/simd_systemz.f90 b/flang/test/Lower/OpenMP/simd_systemz.f90
new file mode 100644
index 0000000000000..a0c1e6f22f08f
--- /dev/null
+++ b/flang/test/Lower/OpenMP/simd_systemz.f90
@@ -0,0 +1,16 @@
+! Tests for 2.9.3.1 Simd and target dependent default alignment for SystemZ
+! The default alignment for SystemZ is 0 so we do not emit aligned clause
+! REQUIRES: systemz-registered-target
+! RUN: %flang_fc1 -triple s390x-unknown-linux-gnu -emit-hlfir -fopenmp %s -o - | FileCheck %s
+subroutine simdloop_aligned_cptr(A)
+ use iso_c_binding
+ integer :: i
+ type (c_ptr) :: A
+ !CHECK: omp.simd
+ !CHECK-NOT: aligned(
+ !$OMP SIMD ALIGNED(A)
+ do i = 1, 10
+ call c_test_call(A)
+ end do
+ !$OMP END SIMD
+end subroutine
diff --git a/flang/test/Semantics/realkinds-systemz-01.f90 b/flang/test/Semantics/realkinds-systemz-01.f90
new file mode 100644
index 0000000000000..20d7ee707349c
--- /dev/null
+++ b/flang/test/Semantics/realkinds-systemz-01.f90
@@ -0,0 +1,12 @@
+! REQUIRES: systemz-registered-target
+! REQUIRES: flang-supports-f128-math
+! RUN: %python %S/test_modfile.py %s %flang_fc1 -triple s390x-unknown-linux-gnu
+
+module m1
+ logical, parameter :: realpcheck = 16 == selected_real_kind(16)
+end module m1
+!Expect: m1.mod
+!module m1
+!logical(4),parameter::realpcheck=.true._4
+!intrinsic::selected_real_kind
+!end
More information about the flang-commits
mailing list