diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index bbaccecca0d66..9c56e4a64ba5b 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -2917,8 +2917,19 @@ llvm::CallInst *IRBuilder::CreateCall(const FunctionPointer &fn, llvm::CallInst *call = IRBuilderBase::CreateCall(fnTy, fn.getRawPointer(), args, bundles); - call->setAttributes( - fixUpTypesInByValAndStructRetAttributes(fnTy, fn.getAttributes())); + llvm::AttributeList attrs = fn.getAttributes(); + // If a parameter of a function is SRet, the corresponding argument should be + // wrapped in SRet(...). + if (auto func = dyn_cast(fn.getRawPointer())) { + for (unsigned argIndex = 0; argIndex < func->arg_size(); ++argIndex) { + if (func->hasParamAttribute(argIndex, llvm::Attribute::StructRet)) { + llvm::AttrBuilder builder; + builder.addStructRetAttr(nullptr); + attrs = attrs.addParamAttributes(func->getContext(), argIndex, builder); + } + } + } + call->setAttributes(fixUpTypesInByValAndStructRetAttributes(fnTy, attrs)); call->setCallingConv(fn.getCallingConv()); return call; } diff --git a/test/Interop/Cxx/class/Inputs/module.modulemap b/test/Interop/Cxx/class/Inputs/module.modulemap index daffb192badbb..b1d08b3dc5429 100644 --- a/test/Interop/Cxx/class/Inputs/module.modulemap +++ b/test/Interop/Cxx/class/Inputs/module.modulemap @@ -102,3 +102,8 @@ module ForwardDeclaredCxxRecord { header "forward-declared-cxx-record.h" requires cplusplus } + +module ReturnsLargeClass { + header "returns-large-class.h" + requires cplusplus +} diff --git a/test/Interop/Cxx/class/Inputs/returns-large-class.h b/test/Interop/Cxx/class/Inputs/returns-large-class.h new file mode 100644 index 0000000000000..15f1a05af4bb3 --- /dev/null +++ b/test/Interop/Cxx/class/Inputs/returns-large-class.h @@ -0,0 +1,22 @@ +#ifndef TEST_INTEROP_CXX_CLASS_INPUTS_RETURNS_LARGE_CLASS_H +#define TEST_INTEROP_CXX_CLASS_INPUTS_RETURNS_LARGE_CLASS_H + +struct LargeClass { + long long a1 = 0; + long long a2 = 0; + long long a3 = 0; + long long a4 = 0; + long long a5 = 0; + long long a6 = 0; + long long a7 = 0; + long long a8 = 0; +}; + +LargeClass funcReturnsLargeClass() { + LargeClass l; + l.a2 = 2; + l.a6 = 6; + return l; +} + +#endif // TEST_INTEROP_CXX_CLASS_INPUTS_RETURNS_LARGE_CLASS_H diff --git a/test/Interop/Cxx/class/returns-large-class-irgen.swift b/test/Interop/Cxx/class/returns-large-class-irgen.swift new file mode 100644 index 0000000000000..aaef2398d762e --- /dev/null +++ b/test/Interop/Cxx/class/returns-large-class-irgen.swift @@ -0,0 +1,20 @@ +// RUN: %target-swift-emit-ir -I %S/Inputs -enable-experimental-cxx-interop %s -validate-tbd-against-ir=none | %FileCheck %s + +// This test verifies that Swift correctly emits IR calls to C++ functions that +// had Named Return Value Optimization applied to them. The first argument of +// such functions has `sret` attribute. When calling them, the first +// parameter should be wrapped in `sret(...)`. + +import ReturnsLargeClass + +func foo() -> LargeClass { + let x = funcReturnsLargeClass() + return x +} + +foo() + +// CHECK: call swiftcc void @"$s4main3fooSo10LargeClassVyF"(%TSo10LargeClassV* noalias nocapture sret(%TSo10LargeClassV) %{{.*}}) + +// The C++ function: +// CHECK: define{{( dso_local)?}} void @{{_Z21funcReturnsLargeClassv|"\?funcReturnsLargeClass@@YA\?AULargeClass@@XZ"}}({{%struct.LargeClass\*|ptr}} noalias sret(%struct.LargeClass){{( align .*)?}} %{{.*}}) diff --git a/test/Interop/Cxx/class/returns-large-class.swift b/test/Interop/Cxx/class/returns-large-class.swift new file mode 100644 index 0000000000000..86683ed0977b0 --- /dev/null +++ b/test/Interop/Cxx/class/returns-large-class.swift @@ -0,0 +1,22 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -enable-experimental-cxx-interop -Xfrontend -validate-tbd-against-ir=none) + +// REQUIRES: executable_test + +// This test verifies that Swift correctly handles calls to C++ functions that +// had Named Return Value Optimization applied to them. + +import StdlibUnittest +import ReturnsLargeClass + +var LargeTypes = TestSuite("Large C++ Return Types") + +LargeTypes.test("NRVO") { + let x = funcReturnsLargeClass() + + expectEqual(0, x.a1) + expectEqual(2, x.a2) + expectEqual(6, x.a6) + expectEqual(0, x.a7) +} + +runAllTests() diff --git a/test/Interop/Cxx/operators/member-inline.swift b/test/Interop/Cxx/operators/member-inline.swift index d72228a04a2be..46ab663eb2501 100644 --- a/test/Interop/Cxx/operators/member-inline.swift +++ b/test/Interop/Cxx/operators/member-inline.swift @@ -52,12 +52,14 @@ OperatorsTestSuite.test("LoadableIntWrapper.successor() (inline)") { expectEqual(42, wrapper.value) } +#if !os(Windows) // SR-13129 OperatorsTestSuite.test("LoadableBoolWrapper.exclaim (inline)") { var wrapper = LoadableBoolWrapper(value: true) let resultExclaim = !wrapper expectEqual(false, resultExclaim.value) } +#endif OperatorsTestSuite.test("AddressOnlyIntWrapper.call (inline)") { var wrapper = AddressOnlyIntWrapper(42) diff --git a/test/SILOptimizer/addr_escape_info.sil b/test/SILOptimizer/addr_escape_info.sil index 96a80084e9322..d3478834af8fe 100644 --- a/test/SILOptimizer/addr_escape_info.sil +++ b/test/SILOptimizer/addr_escape_info.sil @@ -2,9 +2,6 @@ // REQUIRES: swift_in_compiler -// Currently failing on arm: rdar://92963081 -// REQUIRES: CPU=x86_64 - sil_stage canonical import Builtin diff --git a/test/SILOptimizer/escape_info.sil b/test/SILOptimizer/escape_info.sil index bbd8f0074693e..e2d9d19e94d03 100644 --- a/test/SILOptimizer/escape_info.sil +++ b/test/SILOptimizer/escape_info.sil @@ -2,9 +2,6 @@ // REQUIRES: swift_in_compiler -// Currently failing on arm: rdar://92963081 -// REQUIRES: CPU=x86_64 - sil_stage canonical import Builtin diff --git a/test/SILOptimizer/ranges.sil b/test/SILOptimizer/ranges.sil index 95a34811810cb..6b97c3bed5ec7 100644 --- a/test/SILOptimizer/ranges.sil +++ b/test/SILOptimizer/ranges.sil @@ -2,9 +2,6 @@ // REQUIRES: swift_in_compiler -// Currently failing on arm: rdar://92963081 -// REQUIRES: CPU=x86_64 - sil_stage canonical // CHECK-LABEL: Instruction range in basic_test: