Skip to content

Commit b61997e

Browse files
committed
Fix the IR gen for C++ method calls and refactor around CGFunctionInfo
In GenCall, fix the IR gen for C++ method calls as under MSVC as the calling conventions for free functions and C++ methods can be different. This also fixes the missing inreg (on sret arguments) issues on Windows ARM64. Also refactor to use CGFunctionInfo returnInfo isSretAfterThis to detect when to reorder the sret and the this arguments under MSVC. In ClagImporter, don't drop the return type for the compound assignment operators such as operator+= when the return value is a reference so that the CGFunctionInfo will be correctly indicate an indirect return for the compound assignment operators. Cherrypick commit fcc1f6b Cherrypick PR #76324
1 parent 0dc015c commit b61997e

File tree

6 files changed

+76
-24
lines changed

6 files changed

+76
-24
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2101,10 +2101,11 @@ ImportedType ClangImporter::Implementation::importFunctionReturnType(
21012101
// C++ operators +=, -=, *=, /= may return a reference to self. This is not
21022102
// idiomatic in Swift, let's drop these return values.
21032103
clang::OverloadedOperatorKind op = clangDecl->getOverloadedOperator();
2104-
if (op == clang::OverloadedOperatorKind::OO_PlusEqual ||
2105-
op == clang::OverloadedOperatorKind::OO_MinusEqual ||
2106-
op == clang::OverloadedOperatorKind::OO_StarEqual ||
2107-
op == clang::OverloadedOperatorKind::OO_SlashEqual)
2104+
if ((op == clang::OverloadedOperatorKind::OO_PlusEqual ||
2105+
op == clang::OverloadedOperatorKind::OO_MinusEqual ||
2106+
op == clang::OverloadedOperatorKind::OO_StarEqual ||
2107+
op == clang::OverloadedOperatorKind::OO_SlashEqual) &&
2108+
clangDecl->getReturnType()->isReferenceType())
21082109
return {SwiftContext.getVoidType(), false};
21092110

21102111
// Fix up optionality.

lib/IRGen/GenCall.cpp

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,9 +1433,15 @@ void SignatureExpansion::expandExternalSignatureTypes() {
14331433
// Generate function info for this signature.
14341434
auto extInfo = clang::FunctionType::ExtInfo();
14351435

1436-
auto &FI = clang::CodeGen::arrangeFreeFunctionCall(IGM.ClangCodeGen->CGM(),
1437-
clangResultTy, paramTys, extInfo,
1438-
clang::CodeGen::RequiredArgs::All);
1436+
bool isCXXMethod =
1437+
FnType->getRepresentation() == SILFunctionTypeRepresentation::CXXMethod;
1438+
auto &FI = isCXXMethod ?
1439+
clang::CodeGen::arrangeCXXMethodCall(IGM.ClangCodeGen->CGM(),
1440+
clangResultTy, paramTys, extInfo, {},
1441+
clang::CodeGen::RequiredArgs::All) :
1442+
clang::CodeGen::arrangeFreeFunctionCall(IGM.ClangCodeGen->CGM(),
1443+
clangResultTy, paramTys, extInfo, {},
1444+
clang::CodeGen::RequiredArgs::All);
14391445
ForeignInfo.ClangInfo = &FI;
14401446

14411447
assert(FI.arg_size() == paramTys.size() &&
@@ -1557,9 +1563,7 @@ void SignatureExpansion::expandExternalSignatureTypes() {
15571563
if (returnInfo.isIndirect()) {
15581564
auto resultType = getSILFuncConventions().getSingleSILResultType(
15591565
IGM.getMaximalTypeExpansionContext());
1560-
if (IGM.Triple.isWindowsMSVCEnvironment() &&
1561-
FnType->getRepresentation() ==
1562-
SILFunctionTypeRepresentation::CXXMethod) {
1566+
if (returnInfo.isSRetAfterThis()) {
15631567
// Windows ABI places `this` before the
15641568
// returned indirect values.
15651569
emitArg(0);
@@ -2406,11 +2410,12 @@ class SyncCallEmission final : public CallEmission {
24062410

24072411
// Windows ABI places `this` before the
24082412
// returned indirect values.
2409-
bool isThisFirst = IGF.IGM.Triple.isWindowsMSVCEnvironment();
2410-
if (!isThisFirst)
2413+
auto &returnInfo =
2414+
getCallee().getForeignInfo().ClangInfo->getReturnInfo();
2415+
if (returnInfo.isIndirect() && !returnInfo.isSRetAfterThis())
24112416
passIndirectResults();
24122417
adjusted.add(arg);
2413-
if (isThisFirst)
2418+
if (returnInfo.isIndirect() && returnInfo.isSRetAfterThis())
24142419
passIndirectResults();
24152420
}
24162421

@@ -2950,9 +2955,10 @@ void CallEmission::emitToUnmappedMemory(Address result) {
29502955
assert(LastArgWritten == 1 && "emitting unnaturally to indirect result");
29512956

29522957
Args[0] = result.getAddress();
2953-
if (IGF.IGM.Triple.isWindowsMSVCEnvironment() &&
2954-
getCallee().getRepresentation() ==
2955-
SILFunctionTypeRepresentation::CXXMethod &&
2958+
2959+
auto *FI = getCallee().getForeignInfo().ClangInfo;
2960+
if (FI && FI->getReturnInfo().isIndirect() &&
2961+
FI->getReturnInfo().isSRetAfterThis() &&
29562962
Args[1] == getCallee().getCXXMethodSelf()) {
29572963
// C++ methods in MSVC ABI pass `this` before the
29582964
// indirectly returned value.
@@ -3335,10 +3341,10 @@ void CallEmission::emitToExplosion(Explosion &out, bool isOutlined) {
33353341
emitToMemory(temp, substResultTI, isOutlined);
33363342
return;
33373343
}
3338-
if (IGF.IGM.Triple.isWindowsMSVCEnvironment() &&
3339-
getCallee().getRepresentation() ==
3340-
SILFunctionTypeRepresentation::CXXMethod &&
3341-
substResultType.isVoid()) {
3344+
3345+
auto *FI = getCallee().getForeignInfo().ClangInfo;
3346+
if (FI && FI->getReturnInfo().isIndirect() &&
3347+
FI->getReturnInfo().isSRetAfterThis() && substResultType.isVoid()) {
33423348
// Some C++ methods return a value but are imported as
33433349
// returning `Void` (e.g. `operator +=`). In this case
33443350
// we should allocate the correct temp indirect return
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#ifndef TEST_INTEROP_CXX_CLASS_METHOD_INREG_SRET_H
2+
#define TEST_INTEROP_CXX_CLASS_METHOD_INREG_SRET_H
3+
4+
struct OptionalBridgedBasicBlock {
5+
};
6+
7+
struct BridgedFunction {
8+
OptionalBridgedBasicBlock getFirstBlock() const { return {}; }
9+
};
10+
11+
#endif // TEST_INTEROP_CXX_CLASS_METHOD_INREG_SRET_H

test/Interop/Cxx/class/method/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,8 @@ module UnsafeProjections {
1414

1515
export *
1616
}
17+
18+
module InRegSRet {
19+
header "inreg-sret.h"
20+
requires cplusplus
21+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %target-swift-emit-irgen -I %S/Inputs -cxx-interoperability-mode=default %s | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-cpu
2+
3+
// REQUIRES: OS=windows-msvc
4+
5+
import InRegSRet
6+
7+
final public class BasicBlock {
8+
}
9+
10+
extension OptionalBridgedBasicBlock {
11+
public var block: BasicBlock? { nil }
12+
}
13+
14+
final public class Function {
15+
public var bridged: BridgedFunction {
16+
BridgedFunction()
17+
}
18+
19+
public var firstBlock : BasicBlock? { bridged.getFirstBlock().block }
20+
}
21+
22+
// Check that inreg on the sret isn't missing
23+
24+
// CHECK-x86_64: call void @"?getFirstBlock@BridgedFunction@@QEBA?AUOptionalBridgedBasicBlock@@XZ"(ptr {{.*}}, ptr noalias nocapture sret(%TSo25OptionalBridgedBasicBlockV) {{.*}})
25+
// CHECK-aarch64: call void @"?getFirstBlock@BridgedFunction@@QEBA?AUOptionalBridgedBasicBlock@@XZ"(ptr {{.*}}, ptr inreg noalias nocapture sret(%TSo25OptionalBridgedBasicBlockV) {{.*}})
26+
27+
// CHECK-x86_64: define {{.*}} void @"?getFirstBlock@BridgedFunction@@QEBA?AUOptionalBridgedBasicBlock@@XZ"(ptr {{.*}} %{{.*}}, ptr noalias sret(%struct.OptionalBridgedBasicBlock) {{.*}} %{{.*}})
28+
// CHECK-aarch64: define {{.*}} void @"?getFirstBlock@BridgedFunction@@QEBA?AUOptionalBridgedBasicBlock@@XZ"(ptr {{.*}} %{{.*}}, ptr inreg noalias sret(%struct.OptionalBridgedBasicBlock) {{.*}} %{{.*}})

test/Interop/Cxx/class/method/msvc-abi-return-indirect-trivial-record.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,15 @@ public func test(_ result: VecStr) -> CInt {
5757
}
5858

5959
// CHECK: swiftcc i32 @"$s4Test4testys5Int32VSo0014vecstr_yuJCataVF"({{.*}} %[[RESULT:.*]])
60-
// CHECK: call void @"?begin@?$vec@Vstr@@@@QEBA?AVIt@@XZ"(ptr %[[RESULT]], ptr sret{{.*}}
60+
// CHECK: call void @"?begin@?$vec@Vstr@@@@QEBA?AVIt@@XZ"(ptr %[[RESULT]], ptr {{.*}} sret{{.*}}
6161

6262
public func passTempForIndirectRetToVoidCall() {
6363
var lhs = LoadableIntWrapper(value: 2)
6464
let rhs = LoadableIntWrapper(value: 2)
6565
lhs += rhs
6666
}
6767

68-
// CHECK: void @"$sSo18LoadableIntWrapperV2peoiyyABz_ABtFZ"(ptr
69-
// CHECK: %[[OPRESULT:.*]] = alloca %struct.LoadableIntWrapper, align 16
70-
// CHECK: call void @"??YLoadableIntWrapper@@QEAA?AU0@U0@@Z"(ptr {{.*}}, ptr sret(%struct.LoadableIntWrapper) %[[OPRESULT]], i32
68+
// CHECK: i32 @"$sSo18LoadableIntWrapperV2peoiyA2Bz_ABtFZ"(ptr
69+
// CHECK: %[[OPRESULT:.*]] = alloca %TSo18LoadableIntWrapperV, align 4
70+
// CHECK-x86_64: call void @"??YLoadableIntWrapper@@QEAA?AU0@U0@@Z"(ptr {{.*}}, ptr {{.*}} sret(%TSo18LoadableIntWrapperV) %[[OPRESULT]], i32
71+
// CHECK-aarch64: call void @"??YLoadableIntWrapper@@QEAA?AU0@U0@@Z"(ptr {{.*}}, ptr {{.*}} sret(%TSo18LoadableIntWrapperV) %[[OPRESULT]], i64

0 commit comments

Comments
 (0)