Skip to content

Commit 060aade

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 #76324
1 parent dc4d927 commit 060aade

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
@@ -1408,9 +1408,15 @@ void SignatureExpansion::expandExternalSignatureTypes() {
14081408

14091409
// Generate function info for this signature.
14101410
auto extInfo = clang::FunctionType::ExtInfo();
1411-
auto &FI = clang::CodeGen::arrangeFreeFunctionCall(IGM.ClangCodeGen->CGM(),
1412-
clangResultTy, paramTys, extInfo,
1413-
clang::CodeGen::RequiredArgs::All);
1411+
bool isCXXMethod =
1412+
FnType->getRepresentation() == SILFunctionTypeRepresentation::CXXMethod;
1413+
auto &FI = isCXXMethod ?
1414+
clang::CodeGen::arrangeCXXMethodCall(IGM.ClangCodeGen->CGM(),
1415+
clangResultTy, paramTys, extInfo, {},
1416+
clang::CodeGen::RequiredArgs::All) :
1417+
clang::CodeGen::arrangeFreeFunctionCall(IGM.ClangCodeGen->CGM(),
1418+
clangResultTy, paramTys, extInfo, {},
1419+
clang::CodeGen::RequiredArgs::All);
14141420
ForeignInfo.ClangInfo = &FI;
14151421

14161422
assert(FI.arg_size() == paramTys.size() &&
@@ -1522,9 +1528,7 @@ void SignatureExpansion::expandExternalSignatureTypes() {
15221528

15231529
// If we return indirectly, that is the first parameter type.
15241530
if (returnInfo.isIndirect()) {
1525-
if (IGM.Triple.isWindowsMSVCEnvironment() &&
1526-
FnType->getRepresentation() ==
1527-
SILFunctionTypeRepresentation::CXXMethod) {
1531+
if (returnInfo.isSRetAfterThis()) {
15281532
// Windows ABI places `this` before the
15291533
// returned indirect values.
15301534
emitArg(0);
@@ -2365,11 +2369,12 @@ class SyncCallEmission final : public CallEmission {
23652369

23662370
// Windows ABI places `this` before the
23672371
// returned indirect values.
2368-
bool isThisFirst = IGF.IGM.Triple.isWindowsMSVCEnvironment();
2369-
if (!isThisFirst)
2372+
auto &returnInfo =
2373+
getCallee().getForeignInfo().ClangInfo->getReturnInfo();
2374+
if (returnInfo.isIndirect() && !returnInfo.isSRetAfterThis())
23702375
passIndirectResults();
23712376
adjusted.add(arg);
2372-
if (isThisFirst)
2377+
if (returnInfo.isIndirect() && returnInfo.isSRetAfterThis())
23732378
passIndirectResults();
23742379
}
23752380

@@ -2909,9 +2914,10 @@ void CallEmission::emitToUnmappedMemory(Address result) {
29092914
assert(LastArgWritten == 1 && "emitting unnaturally to indirect result");
29102915

29112916
Args[0] = result.getAddress();
2912-
if (IGF.IGM.Triple.isWindowsMSVCEnvironment() &&
2913-
getCallee().getRepresentation() ==
2914-
SILFunctionTypeRepresentation::CXXMethod &&
2917+
2918+
auto *FI = getCallee().getForeignInfo().ClangInfo;
2919+
if (FI && FI->getReturnInfo().isIndirect() &&
2920+
FI->getReturnInfo().isSRetAfterThis() &&
29152921
Args[1] == getCallee().getCXXMethodSelf()) {
29162922
// C++ methods in MSVC ABI pass `this` before the
29172923
// indirectly returned value.
@@ -3288,10 +3294,10 @@ void CallEmission::emitToExplosion(Explosion &out, bool isOutlined) {
32883294
emitToMemory(temp, substResultTI, isOutlined);
32893295
return;
32903296
}
3291-
if (IGF.IGM.Triple.isWindowsMSVCEnvironment() &&
3292-
getCallee().getRepresentation() ==
3293-
SILFunctionTypeRepresentation::CXXMethod &&
3294-
substResultType.isVoid()) {
3297+
3298+
auto *FI = getCallee().getForeignInfo().ClangInfo;
3299+
if (FI && FI->getReturnInfo().isIndirect() &&
3300+
FI->getReturnInfo().isSRetAfterThis() && substResultType.isVoid()) {
32953301
// Some C++ methods return a value but are imported as
32963302
// returning `Void` (e.g. `operator +=`). In this case
32973303
// 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(%struct.OptionalBridgedBasicBlock) {{.*}})
25+
// CHECK-aarch64: call void @"?getFirstBlock@BridgedFunction@@QEBA?AUOptionalBridgedBasicBlock@@XZ"(ptr {{.*}}, ptr inreg noalias nocapture sret(%struct.OptionalBridgedBasicBlock) {{.*}})
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)