diff --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp index 2a1eb0bc33f5c..e2f8fb9d239a1 100644 --- a/flang/lib/Optimizer/CodeGen/Target.cpp +++ b/flang/lib/Optimizer/CodeGen/Target.cpp @@ -1049,6 +1049,29 @@ struct TargetPPC64 : public GenericTarget { AT{}); return marshal; } + + 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(8))}; + marshal.emplace_back(fir::ReferenceType::get(ty), + AT{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 @@ -1060,7 +1083,7 @@ namespace { struct TargetPPC64le : public GenericTarget { using GenericTarget::GenericTarget; - static constexpr int defaultWidth = 64; + static constexpr int defaultWidth{64}; CodeGenSpecifics::Marshalling complexArgumentType(mlir::Location, mlir::Type eleTy) const override { @@ -1081,6 +1104,143 @@ struct TargetPPC64le : public GenericTarget { AT{}); return marshal; } + + unsigned getElemWidth(mlir::Type ty) const { + unsigned width{}; + llvm::TypeSwitch(ty) + .template Case([&](mlir::ComplexType cmplx) { + auto elemType{ + mlir::dyn_cast(cmplx.getElementType())}; + width = elemType.getWidth(); + }) + .template Case( + [&](mlir::FloatType real) { width = real.getWidth(); }); + return width; + } + + // Determine if all derived types components are of the same float type with + // the same width. Complex(4) is considered 2 floats and complex(8) 2 doubles. + bool hasSameFloatAndWidth( + fir::RecordType recTy, + std::pair &firstTypeAndWidth) const { + for (auto comp : recTy.getTypeList()) { + mlir::Type compType{comp.second}; + if (mlir::isa(compType)) { + auto rc{hasSameFloatAndWidth(mlir::cast(compType), + firstTypeAndWidth)}; + if (!rc) + return false; + } else { + mlir::Type ty; + bool isFloatType{false}; + if (mlir::isa(compType)) { + ty = compType; + isFloatType = true; + } else if (auto seqTy = mlir::dyn_cast(compType)) { + ty = seqTy.getEleTy(); + isFloatType = mlir::isa(ty); + } + + if (!isFloatType) { + return false; + } + auto width{getElemWidth(ty)}; + if (firstTypeAndWidth.first == nullptr) { + firstTypeAndWidth.first = ty; + firstTypeAndWidth.second = width; + } else if (width != firstTypeAndWidth.second) { + return false; + } + } + } + return true; + } + + CodeGenSpecifics::Marshalling + passOnTheStack(mlir::Location loc, mlir::Type ty, bool isResult) const { + CodeGenSpecifics::Marshalling marshal; + auto sizeAndAlign{ + fir::getTypeSizeAndAlignmentOrCrash(loc, ty, getDataLayout(), kindMap)}; + unsigned short align{ + std::max(sizeAndAlign.second, static_cast(8))}; + marshal.emplace_back(fir::ReferenceType::get(ty), + AT{align, /*byval=*/!isResult, /*sret=*/isResult}); + return marshal; + } + + CodeGenSpecifics::Marshalling + structType(mlir::Location loc, fir::RecordType recTy, bool isResult) const { + CodeGenSpecifics::Marshalling marshal; + auto sizeAndAlign{fir::getTypeSizeAndAlignmentOrCrash( + loc, recTy, getDataLayout(), kindMap)}; + auto recordTypeSize{sizeAndAlign.first}; + mlir::Type seqTy; + std::pair firstTyAndWidth{nullptr, 0}; + + // If there are less than or equal to 8 floats, the structure is flatten as + // an array of floats. + constexpr uint64_t maxNoOfFloats{8}; + + // i64 type + mlir::Type elemTy{mlir::IntegerType::get(recTy.getContext(), defaultWidth)}; + uint64_t nElem{static_cast( + std::ceil(static_cast(recordTypeSize * 8) / defaultWidth))}; + + // If the derived type components contains are all floats with the same + // width, the argument is passed as an array of floats. + if (hasSameFloatAndWidth(recTy, firstTyAndWidth)) { + uint64_t n{}; + auto firstType{firstTyAndWidth.first}; + + // Type is either float or complex + if (auto cmplx = mlir::dyn_cast(firstType)) { + auto fltType{mlir::dyn_cast(cmplx.getElementType())}; + n = static_cast(8 * recordTypeSize / fltType.getWidth()); + if (n <= maxNoOfFloats) { + nElem = n; + elemTy = fltType; + } + } else if (mlir::isa(firstType)) { + auto elemSizeAndAlign{fir::getTypeSizeAndAlignmentOrCrash( + loc, firstType, getDataLayout(), kindMap)}; + n = static_cast(recordTypeSize / elemSizeAndAlign.first); + if (n <= maxNoOfFloats) { + nElem = n; + elemTy = firstType; + } + } + // Neither float nor complex + assert(n > 0 && "unexpected type"); + } + + // For function returns, only flattened if there are less than 8 + // floats in total. + if (isResult && + ((mlir::isa(elemTy) && nElem > maxNoOfFloats) || + !mlir::isa(elemTy))) { + return passOnTheStack(loc, recTy, isResult); + } + + seqTy = fir::SequenceType::get(nElem, elemTy); + marshal.emplace_back(seqTy, AT{}); + return marshal; + } + + CodeGenSpecifics::Marshalling + structArgumentType(mlir::Location loc, fir::RecordType recType, + const Marshalling &previousArguments) const override { + auto sizeAndAlign{fir::getTypeSizeAndAlignmentOrCrash( + loc, recType, getDataLayout(), kindMap)}; + if (sizeAndAlign.first > 64) { + return passOnTheStack(loc, recType, false); + } + return structType(loc, recType, false); + } + + CodeGenSpecifics::Marshalling + structReturnType(mlir::Location loc, fir::RecordType recType) const override { + return structType(loc, recType, true); + } }; } // namespace diff --git a/flang/test/Fir/struct-passing-loongarch64-byreg.fir b/flang/test/Fir/struct-passing-loongarch64-byreg.fir index 585884504aacf..f2f54e12eac46 100644 --- a/flang/test/Fir/struct-passing-loongarch64-byreg.fir +++ b/flang/test/Fir/struct-passing-loongarch64-byreg.fir @@ -7,7 +7,6 @@ /// only the first example in each category checks the entire invocation process, /// while the other examples only check the signatures. -// REQUIRES: loongarch-registered-target // RUN: fir-opt --split-input-file --target-rewrite="target=loongarch64-unknown-linux-gnu" %s | FileCheck %s diff --git a/flang/test/Fir/struct-passing-powerpc64-aix-byval.fir b/flang/test/Fir/struct-passing-powerpc64-aix-byval.fir new file mode 100644 index 0000000000000..b6e9b2834b913 --- /dev/null +++ b/flang/test/Fir/struct-passing-powerpc64-aix-byval.fir @@ -0,0 +1,28 @@ +// Test powerpc64 rewrite of struct passed by value (BIND(C), VALUE derived types). +// +// RUN: fir-opt --target-rewrite="target=powerpc64-ibm-aix" %s | FileCheck %s + +module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "E-m:a-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512", llvm.target_triple = "powerpc64-ibm-aix7.2.0.0"} { + +// character type +func.func @csubch(%arg0: !fir.type<_QFcsubchTdt<{c:!fir.char<1>}>> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubch"} { return } +//CHECK-LABEL: func.func @csubch(%arg0: !fir.ref}>>> {fir.bindc_name = "arg", llvm.align = 8 : i32, llvm.byval = !fir.type<_QFcsubchTdt<{c:!fir.char<1>}>>}) attributes {fir.bindc_name = "csubch"} + +// integer type +func.func @csubi1(%arg0: !fir.type<_QFcsubi1Tdt<{i:i32}>> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubi1"} { return } +//CHECK-LABEL: func.func @csubi1(%arg0: !fir.ref>> {fir.bindc_name = "arg", llvm.align = 8 : i32, llvm.byval = !fir.type<_QFcsubi1Tdt<{i:i32}>>}) attributes {fir.bindc_name = "csubi1"} + +// real type (scalar) +func.func @csubr1(%arg0: !fir.type<_QFcsubr1Tdt<{r1:f32,r2:f32,r3:f32}>> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr1"} { return } +//CHECK-LABEL: func.func @csubr1(%arg0: !fir.ref>> {fir.bindc_name = "arg", llvm.align = 8 : i32, llvm.byval = !fir.type<_QFcsubr1Tdt<{r1:f32,r2:f32,r3:f32}>>}) attributes {fir.bindc_name = "csubr1"} + +// real type (array) +func.func @csubr5(%arg0: !fir.type<_QFcsubr5Tdt<{r:!fir.array<8xf32>}>> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr5"} { return } +//CHECK-LABEL: func.func @csubr5(%arg0: !fir.ref}>>> {fir.bindc_name = "arg", llvm.align = 8 : i32, llvm.byval = !fir.type<_QFcsubr5Tdt<{r:!fir.array<8xf32>}>>}) attributes {fir.bindc_name = "csubr5"} + +// mixed types +func.func @csub1(%arg0: !fir.type<_QFcsub1Tdt<{c:!fir.char<1>,r:f32,i:i64}>> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub1"} { return } +//CHECK-LABEL: func.func @csub1(%arg0: !fir.ref,r:f32,i:i64}>>> {fir.bindc_name = "arg", llvm.align = 8 : i32, llvm.byval = !fir.type<_QFcsub1Tdt<{c:!fir.char<1>,r:f32,i:i64}>>}) attributes {fir.bindc_name = "csub1"} + +} + diff --git a/flang/test/Fir/struct-passing-ppc64le-byval.fir b/flang/test/Fir/struct-passing-ppc64le-byval.fir new file mode 100644 index 0000000000000..b9be67fbe97bf --- /dev/null +++ b/flang/test/Fir/struct-passing-ppc64le-byval.fir @@ -0,0 +1,82 @@ +// Test ppc64le rewrite of struct passed by value (BIND(C), VALUE derived types). +// +// RUN: fir-opt --target-rewrite="target=ppc64le-ibm-linux" %s | FileCheck %s + +module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512", llvm.target_triple = "powerpc64le-unknown-linux-gnu"} { + +// character type +func.func @csubch(%arg0: !fir.type<_QFcsubchTdt{c:!fir.char<1>}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubch"} { return } +//CHECK-LABEL: func.func @csubch(%arg0: !fir.array<1xi64> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubch"} + +// integer type +func.func @csubi1(%arg0: !fir.type<_QFcsubi1Tdt{i:i32}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubi1"} { return } +//CHECK-LABEL: func.func @csubi1(%arg0: !fir.array<1xi64> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubi1"} + +// integer type with size > 64 bytes +func.func @csubi2(%arg0: !fir.type<_QFcsubi2Tdt{i:!fir.array<17xi32>}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubi2"} { return } +//CHECK-LABEL: func.func @csubi2(%arg0: !fir.ref}>> {fir.bindc_name = "arg", llvm.align = 8 : i32, llvm.byval = !fir.type<_QFcsubi2Tdt{i:!fir.array<17xi32>}>}) attributes {fir.bindc_name = "csubi2"} + +// real type (scalar) +func.func @csubr1(%arg0: !fir.type<_QFcsubr1Tdt{r1:f32,r2:f32,r3:f32}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr1"} { return } +//CHECK-LABEL: func.func @csubr1(%arg0: !fir.array<3xf32> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr1"} + +// real type (< 8 floats and <= 64 bytes) +func.func @csubr2(%arg0: !fir.type<_QFcsubr2Tdt{r1:f64,r2:f64,r3:f64,r4:f64,r5:f64,r6:f64,r7:f64,r8:f64}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr2"} { return } +//CHECK-LABEL: func.func @csubr2(%arg0: !fir.array<8xf64> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr2"} + +// real type (> 8 floats and <= 64 bytes) +func.func @csubr3(%arg0: !fir.type<_QFcsubr3Tdt{r1:f32,r2:f32,r3:f32,r4:f32,r5:f32,r6:f32,r7:f32,r8:f32,r9:f32}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr3"} { return } +//CHECK-LABEL: func.func @csubr3(%arg0: !fir.array<5xi64> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr3"} + +// real type (> 8 floats and > 64 bytes) +func.func @csubr4(%arg0: !fir.type<_QFcsubr4Tdt{r1:f32,r2:f32,r3:f32,r4:f32,r5:f32,r6:f32,r7:f32,r8:f32,r9:f32,r10:f32,r11:f32,r12:f32,r13:f32,r14:f32,r15:f32,r16:f32,r17:f32}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr4"} { return } +//CHECK-LABEL: func.func @csubr4(%arg0: !fir.ref> {fir.bindc_name = "arg", llvm.align = 8 : i32, llvm.byval = !fir.type<_QFcsubr4Tdt{r1:f32,r2:f32,r3:f32,r4:f32,r5:f32,r6:f32,r7:f32,r8:f32,r9:f32,r10:f32,r11:f32,r12:f32,r13:f32,r14:f32,r15:f32,r16:f32,r17:f32}>}) attributes {fir.bindc_name = "csubr4"} + +// real type (array) +func.func @csubr5(%arg0: !fir.type<_QFcsubr5Tdt{r:!fir.array<8xf32>}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr5"} { return } +//CHECK-LABEL: func.func @csubr5(%arg0: !fir.array<8xf32> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr5"} + +// real type (array componets and > 64 bytes) +func.func @csubr6(%arg0: !fir.type<_QFcsubr6Tdt{r:!fir.array<9xf64>}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr6"} { return } +//CHECK-LABEL: func.func @csubr6(%arg0: !fir.ref}>> {fir.bindc_name = "arg", llvm.align = 8 : i32, llvm.byval = !fir.type<_QFcsubr6Tdt{r:!fir.array<9xf64>}>}) attributes {fir.bindc_name = "csubr6"} + +// real type with different kinds +func.func @csubr7(%arg0: !fir.type<_QFcsubr7Tdt{r1:f32,r2:f64,r3:f64}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr7"} { return } +//CHECK-LABEL: func.func @csubr7(%arg0: !fir.array<3xi64> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubr7"} + +// complex type +func.func @csubc1(%arg0: !fir.type<_QFcsubc1Tdt{r1:complex,r2:complex}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubc1"} { return } +//CHECK-LABEL: func.func @csubc1(%arg0: !fir.array<4xf32> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubc1"} + +func.func @csubc2(%arg0: !fir.type<_QFcsubc2Tdt{r1:complex,r2:complex,r3:complex,r4:complex}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubc2"} { return } +//CHECK-LABEL: func.func @csubc2(%arg0: !fir.array<8xf64> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubc2"} + +// complex type (> 8 floats and size < 64 bytes) +func.func @csubc3(%arg0: !fir.type<_QFcsubc3Tdt{r:!fir.array<5xcomplex>}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubc3"} { return } +//CHECK-LABEL: func.func @csubc3(%arg0: !fir.array<5xi64> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubc3"} + +// complex type (size > 64 bytes) +func.func @csubc4(%arg0: !fir.type<_QFcsubc4Tdt{r:!fir.array<9xcomplex>}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csubc4"} { return } +//CHECK-LABEL: func.func @csubc4(%arg0: !fir.ref>}>> {fir.bindc_name = "arg", llvm.align = 8 : i32, llvm.byval = !fir.type<_QFcsubc4Tdt{r:!fir.array<9xcomplex>}>}) attributes {fir.bindc_name = "csubc4"} + +// mixed type +func.func @csub1(%arg0: !fir.type<_QFcsub1Tdt{c:!fir.char<1>,r:f32,i:i64}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub1"} { return } +//CHECK-LABEL: func.func @csub1(%arg0: !fir.array<2xi64> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub1"} + +// nested derived types +func.func @csub2(%arg0: !fir.type<_QFcsub2Tdt1{xdt0:!fir.type<_QFcsub2Tdt0{f1:f32,f2:f32,f3:f32}>,x1:f32,x2:f32,x3:f32,x4:f32,x5:f32}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub2"} { return } +//CHECK-LABEL: func.func @csub2(%arg0: !fir.array<8xf32> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub2"} + +func.func @csub3(%arg0: !fir.type<_QFcsub3Tdt1{xdt0:!fir.type<_QFcsub3Tdt0{f1:f32,f2:f32,f3:f32}>,x1:f32,x2:f32,i:i32}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub3"} { return } +//CHECK-LABEL: func.func @csub3(%arg0: !fir.array<3xi64> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub3"} + +func.func @csub4(%arg0: !fir.type<_QFcsub4Tdt1{xdt0:!fir.type<_QFcsub4Tdt0{f1:f32}>,x1:f64}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub4"} { return } +//CHECK-LABEL: func.func @csub4(%arg0: !fir.array<2xi64> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub4"} + +func.func @csub5(%arg0: !fir.type<_QFcsub5Tdt1{xdt0:!fir.type<_QFcsub5Tdt0{f1:complex}>,x1:f32}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub5"} { return } +//CHECK-LABEL: func.func @csub5(%arg0: !fir.array<3xf32> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub5"} + +func.func @csub6(%arg0: !fir.type<_QFcsub6Tdt1{xdt0:!fir.type<_QFcsub6Tdt0{f1:complex}>,x1:f64}> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub6"} { return } +//CHECK-LABEL: func.func @csub6(%arg0: !fir.array<2xi64> {fir.bindc_name = "arg"}) attributes {fir.bindc_name = "csub6"} + +} diff --git a/flang/test/Fir/struct-return-powerpc64-aix.fir b/flang/test/Fir/struct-return-powerpc64-aix.fir new file mode 100644 index 0000000000000..3058ef6b7e965 --- /dev/null +++ b/flang/test/Fir/struct-return-powerpc64-aix.fir @@ -0,0 +1,102 @@ +// Test powerpc64 ABI rewrite of struct returned by value (BIND(C), VALUE derived types). +// +// RUN: fir-opt --target-rewrite="target=powerpc64-ibm-aix" %s | FileCheck %s + +module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "E-m:a-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512", llvm.target_triple = "powerpc64-ibm-aix7.2.0.0"} { + +// character type +func.func private @test_t1() -> !fir.type}>> +//CHECK-LABEL: func.func private @test_t1(!fir.ref}>>> {llvm.align = 8 : i32, llvm.sret = !fir.type}>>}) +func.func @test_call_t1(%arg0 : !fir.ref}>>>) { +//CHECK-LABEL: func.func @test_call_t1( +//CHECK-SAME: %[[ARG0:.*]]: !fir.ref}>>>) + %out = fir.call @test_t1() : () -> !fir.type}>> + fir.store %out to %arg0 : !fir.ref}>>> + return + //CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr + //CHECK: %[[ARG:.*]] = fir.alloca !fir.type}>> + //CHECK: fir.call @test_t1(%[[ARG]]) : (!fir.ref}>>>) -> () + //CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref}>>>) -> !fir.ref}>>> + //CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref}>>> + //CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr + //CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref}>>> + //CHECK: return +} + +// integer type +func.func private @test_t2() -> !fir.type> +//CHECK-LABEL: func.func private @test_t2(!fir.ref>> {llvm.align = 8 : i32, llvm.sret = !fir.type>}) +func.func @test_call_t2(%arg0 : !fir.ref>>) { +//CHECK-LABEL: func.func @test_call_t2( +//CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>) + %out = fir.call @test_t2() : () -> !fir.type> + fir.store %out to %arg0 : !fir.ref>> + return + //CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr + //CHECK: %[[ARG:.*]] = fir.alloca !fir.type> + //CHECK: fir.call @test_t2(%[[ARG]]) : (!fir.ref>>) -> () + //CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref>>) -> !fir.ref>> + //CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref>> + //CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr + //CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref>> + //CHECK: return +} + +// real type (scalar) +func.func private @test_t3() -> !fir.type> +//CHECK-LABEL: func.func private @test_t3(!fir.ref>> {llvm.align = 8 : i32, llvm.sret = !fir.type>}) +func.func @test_call_t3(%arg0 : !fir.ref>>) { +//CHECK-LABEL: func.func @test_call_t3( +//CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>) + %out = fir.call @test_t3() : () -> !fir.type> + fir.store %out to %arg0 : !fir.ref>> + return + //CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr + //CHECK: %[[ARG:.*]] = fir.alloca !fir.type> + //CHECK: fir.call @test_t3(%[[ARG]]) : (!fir.ref>>) -> () + //CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref>>) -> !fir.ref>> + //CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref>> + //CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr + //CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref>> + //CHECK: return +} + +// real type (array) +func.func private @test_t4() -> !fir.type}>> +//CHECK-LABEL: func.func private @test_t4(!fir.ref}>>> {llvm.align = 8 : i32, llvm.sret = !fir.type}>>}) +func.func @test_call_t4(%arg0 : !fir.ref}>>>) { +//CHECK-LABEL: func.func @test_call_t4( +//CHECK-SAME: %[[ARG0:.*]]: !fir.ref}>>>) + %out = fir.call @test_t4() : () -> !fir.type}>> + fir.store %out to %arg0 : !fir.ref}>>> + return + //CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr + //CHECK: %[[ARG:.*]] = fir.alloca !fir.type}>> + //CHECK: fir.call @test_t4(%[[ARG]]) : (!fir.ref}>>>) -> () + //CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref}>>>) -> !fir.ref}>>> + //CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref}>>> + //CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr + //CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref}>>> + //CHECK: return +} + +// mixed types +func.func private @test_t5() -> !fir.type,r:f32,i:i64}>> +//CHECK-LABEL: func.func private @test_t5(!fir.ref,r:f32,i:i64}>>> {llvm.align = 8 : i32, llvm.sret = !fir.type,r:f32,i:i64}>>}) +func.func @test_call_t5(%arg0 : !fir.ref,r:f32,i:i64}>>>) { +//CHECK-LABEL: func.func @test_call_t5( +//CHECK-SAME: %[[ARG0:.*]]: !fir.ref,r:f32,i:i64}>>>) + %out = fir.call @test_t5() : () -> !fir.type,r:f32,i:i64}>> + fir.store %out to %arg0 : !fir.ref,r:f32,i:i64}>>> + return + //CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr + //CHECK: %[[ARG:.*]] = fir.alloca !fir.type,r:f32,i:i64}>> + //CHECK: fir.call @test_t5(%[[ARG]]) : (!fir.ref,r:f32,i:i64}>>>) -> () + //CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref,r:f32,i:i64}>>>) -> !fir.ref,r:f32,i:i64}>>> + //CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref,r:f32,i:i64}>>> + //CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr + //CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref,r:f32,i:i64}>>> + //CHECK: return +} + +} diff --git a/flang/test/Fir/struct-return-ppc64le.fir b/flang/test/Fir/struct-return-ppc64le.fir new file mode 100644 index 0000000000000..a5906280a0ef8 --- /dev/null +++ b/flang/test/Fir/struct-return-ppc64le.fir @@ -0,0 +1,103 @@ +// Test ppc64le ABI rewrite of struct returned by value (BIND(C), VALUE derived types). +// +// RUN: fir-opt --target-rewrite="target=ppc64le-ibm-linux" %s | FileCheck %s + +module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512", llvm.target_triple = "powerpc64le-unknown-linux-gnu"} { + +// character type +func.func private @test_t1() -> !fir.type}> +//CHECK-LABEL: func.func private @test_t1(!fir.ref}>> {llvm.align = 8 : i32, llvm.sret = !fir.type}>}) +func.func @test_call_t1(%arg0 : !fir.ref}>>) { +//CHECK-LABEL: func.func @test_call_t1( +//CHECK-SAME: %[[ARG0:.*]]: !fir.ref}>>) + %out = fir.call @test_t1() : () -> !fir.type}> + fir.store %out to %arg0 : !fir.ref}>> + return + //CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr + //CHECK: %[[ARG:.*]] = fir.alloca !fir.type}> + //CHECK: fir.call @test_t1(%[[ARG]]) : (!fir.ref}>>) -> () + //CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref}>>) -> !fir.ref}>> + //CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref}>> + //CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr + //CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref}>> + //CHECK: return +} + +// integer type +func.func private @test_t2() -> !fir.type +//CHECK-LABEL: func.func private @test_t2(!fir.ref> {llvm.align = 8 : i32, llvm.sret = !fir.type}) +func.func @test_call_t2(%arg0 : !fir.ref>) { +//CHECK-LABEL: func.func @test_call_t2( +//CHECK-SAME: %[[ARG0:.*]]: !fir.ref>) + %out = fir.call @test_t2() : () -> !fir.type + fir.store %out to %arg0 : !fir.ref> + return + //CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr + //CHECK: %[[ARG:.*]] = fir.alloca !fir.type + //CHECK: fir.call @test_t2(%[[ARG]]) : (!fir.ref>) -> () + //CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref>) -> !fir.ref> + //CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref> + //CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr + //CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref> + //CHECK: return +} + +// real type (scalar) +func.func private @test_t3() -> !fir.type +//CHECK-LABEL: func.func private @test_t3() -> !fir.array<3xf32> +func.func @test_call_t3(%arg0 : !fir.ref>) { +//CHECK-LABEL: func.func @test_call_t3( +//CHECK-SAME: %[[ARG0:.*]]: !fir.ref>) + %out = fir.call @test_t3() : () -> !fir.type + fir.store %out to %arg0 : !fir.ref> + return + //CHECK: %[[RET:.*]] = fir.call @test_t3() : () -> !fir.array<3xf32> + //CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr + //CHECK: %[[ARG:.*]] = fir.alloca !fir.array<3xf32> + //CHECK: fir.store %[[RET]] to %[[ARG]] : !fir.ref> + //CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref>) -> !fir.ref> + //CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref> + //CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr + //CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref> + //CHECK: return +} + +// real type (> 8 floats) +func.func private @test_t4() -> !fir.type}> +//CHECK-LABEL: func.func private @test_t4(!fir.ref}>> {llvm.align = 8 : i32, llvm.sret = !fir.type}>}) +func.func @test_call_t4(%arg0 : !fir.ref}>>) { +//CHECK-LABEL: func.func @test_call_t4( +//CHECK-SAME: %[[ARG0:.*]]: !fir.ref}>>) + %out = fir.call @test_t4() : () -> !fir.type}> + fir.store %out to %arg0 : !fir.ref}>> + return + //CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr + //CHECK: %[[ARG:.*]] = fir.alloca !fir.type}> + //CHECK: fir.call @test_t4(%[[ARG]]) : (!fir.ref}>>) -> () + //CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref}>>) -> !fir.ref}>> + //CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref}>> + //CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr + //CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref}>> + //CHECK: return +} + +// mixed types +func.func private @test_t5() -> !fir.type,r:f32,i:i64}> +//CHECK-LABEL: func.func private @test_t5(!fir.ref,r:f32,i:i64}>> {llvm.align = 8 : i32, llvm.sret = !fir.type,r:f32,i:i64}>}) +func.func @test_call_t5(%arg0 : !fir.ref,r:f32,i:i64}>>) { +//CHECK-LABEL: func.func @test_call_t5( +//CHECK-SAME: %[[ARG0:.*]]: !fir.ref,r:f32,i:i64}>>) + %out = fir.call @test_t5() : () -> !fir.type,r:f32,i:i64}> + fir.store %out to %arg0 : !fir.ref,r:f32,i:i64}>> + return + //CHECK: %[[STCK:.*]] = llvm.intr.stacksave : !llvm.ptr + //CHECK: %[[ARG:.*]] = fir.alloca !fir.type,r:f32,i:i64}> + //CHECK: fir.call @test_t5(%[[ARG]]) : (!fir.ref,r:f32,i:i64}>>) -> () + //CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref,r:f32,i:i64}>>) -> !fir.ref,r:f32,i:i64}>> + //CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref,r:f32,i:i64}>> + //CHECK: llvm.intr.stackrestore %[[STCK]] : !llvm.ptr + //CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref,r:f32,i:i64}>> + //CHECK: return +} + +}