Skip to content

Commit b7dad2a

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 46eb3e1 commit b7dad2a

File tree

8 files changed

+78
-27
lines changed

8 files changed

+78
-27
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,10 +2204,11 @@ ImportedType ClangImporter::Implementation::importFunctionReturnType(
22042204
// C++ operators +=, -=, *=, /= may return a reference to self. This is not
22052205
// idiomatic in Swift, let's drop these return values.
22062206
clang::OverloadedOperatorKind op = clangDecl->getOverloadedOperator();
2207-
if (op == clang::OverloadedOperatorKind::OO_PlusEqual ||
2208-
op == clang::OverloadedOperatorKind::OO_MinusEqual ||
2209-
op == clang::OverloadedOperatorKind::OO_StarEqual ||
2210-
op == clang::OverloadedOperatorKind::OO_SlashEqual)
2207+
if ((op == clang::OverloadedOperatorKind::OO_PlusEqual ||
2208+
op == clang::OverloadedOperatorKind::OO_MinusEqual ||
2209+
op == clang::OverloadedOperatorKind::OO_StarEqual ||
2210+
op == clang::OverloadedOperatorKind::OO_SlashEqual) &&
2211+
clangDecl->getReturnType()->isReferenceType())
22112212
return {SwiftContext.getVoidType(), false};
22122213

22132214
// Fix up optionality.

lib/IRGen/GenCall.cpp

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

1456-
auto &FI = clang::CodeGen::arrangeFreeFunctionCall(IGM.ClangCodeGen->CGM(),
1457-
clangResultTy, paramTys, extInfo,
1458-
clang::CodeGen::RequiredArgs::All);
1456+
bool isCXXMethod =
1457+
FnType->getRepresentation() == SILFunctionTypeRepresentation::CXXMethod;
1458+
auto &FI = isCXXMethod ?
1459+
clang::CodeGen::arrangeCXXMethodCall(IGM.ClangCodeGen->CGM(),
1460+
clangResultTy, paramTys, extInfo, {},
1461+
clang::CodeGen::RequiredArgs::All) :
1462+
clang::CodeGen::arrangeFreeFunctionCall(IGM.ClangCodeGen->CGM(),
1463+
clangResultTy, paramTys, extInfo, {},
1464+
clang::CodeGen::RequiredArgs::All);
14591465
ForeignInfo.ClangInfo = &FI;
14601466

14611467
assert(FI.arg_size() == paramTys.size() &&
@@ -1577,9 +1583,7 @@ void SignatureExpansion::expandExternalSignatureTypes() {
15771583
if (returnInfo.isIndirect()) {
15781584
auto resultType = getSILFuncConventions().getSingleSILResultType(
15791585
IGM.getMaximalTypeExpansionContext());
1580-
if (IGM.Triple.isWindowsMSVCEnvironment() &&
1581-
FnType->getRepresentation() ==
1582-
SILFunctionTypeRepresentation::CXXMethod) {
1586+
if (returnInfo.isSRetAfterThis()) {
15831587
// Windows ABI places `this` before the
15841588
// returned indirect values.
15851589
emitArg(0);
@@ -2538,11 +2542,12 @@ class SyncCallEmission final : public CallEmission {
25382542

25392543
// Windows ABI places `this` before the
25402544
// returned indirect values.
2541-
bool isThisFirst = IGF.IGM.Triple.isWindowsMSVCEnvironment();
2542-
if (!isThisFirst)
2545+
auto &returnInfo =
2546+
getCallee().getForeignInfo().ClangInfo->getReturnInfo();
2547+
if (returnInfo.isIndirect() && !returnInfo.isSRetAfterThis())
25432548
passIndirectResults();
25442549
adjusted.add(arg);
2545-
if (isThisFirst)
2550+
if (returnInfo.isIndirect() && returnInfo.isSRetAfterThis())
25462551
passIndirectResults();
25472552
}
25482553

@@ -3119,9 +3124,10 @@ void CallEmission::emitToUnmappedMemory(Address result) {
31193124
assert(LastArgWritten == 1 && "emitting unnaturally to indirect result");
31203125

31213126
Args[0] = result.getAddress();
3122-
if (IGF.IGM.Triple.isWindowsMSVCEnvironment() &&
3123-
getCallee().getRepresentation() ==
3124-
SILFunctionTypeRepresentation::CXXMethod &&
3127+
3128+
auto *FI = getCallee().getForeignInfo().ClangInfo;
3129+
if (FI && FI->getReturnInfo().isIndirect() &&
3130+
FI->getReturnInfo().isSRetAfterThis() &&
31253131
Args[1] == getCallee().getCXXMethodSelf()) {
31263132
// C++ methods in MSVC ABI pass `this` before the
31273133
// indirectly returned value.
@@ -3486,10 +3492,10 @@ void CallEmission::emitToExplosion(Explosion &out, bool isOutlined) {
34863492
emitToMemory(temp, substResultTI, isOutlined);
34873493
return;
34883494
}
3489-
if (IGF.IGM.Triple.isWindowsMSVCEnvironment() &&
3490-
getCallee().getRepresentation() ==
3491-
SILFunctionTypeRepresentation::CXXMethod &&
3492-
substResultType.isVoid()) {
3495+
3496+
auto *FI = getCallee().getForeignInfo().ClangInfo;
3497+
if (FI && FI->getReturnInfo().isIndirect() &&
3498+
FI->getReturnInfo().isSRetAfterThis() && substResultType.isVoid()) {
34933499
// Some C++ methods return a value but are imported as
34943500
// returning `Void` (e.g. `operator +=`). In this case
34953501
// 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 & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +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-x86_64: call void @"??YLoadableIntWrapper@@QEAA?AU0@U0@@Z"(ptr {{.*}}, ptr sret(%struct.LoadableIntWrapper) %[[OPRESULT]], i32
71-
// CHECK-aarch64: call void @"??YLoadableIntWrapper@@QEAA?AU0@U0@@Z"(ptr {{.*}}, ptr sret(%struct.LoadableIntWrapper) %[[OPRESULT]], i64
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

test/Interop/Cxx/operators/member-inline-irgen.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import MemberInline
55
public func sub(_ lhs: inout LoadableIntWrapper, _ rhs: LoadableIntWrapper) -> LoadableIntWrapper { lhs - rhs }
66

77
// CHECK-SYSV: call [[RESA:i32|i64]] [[NAMEA:@_ZN18LoadableIntWrappermiES_]](ptr {{%[0-9]+}}, {{i32|\[1 x i32\]|i64|%struct.LoadableIntWrapper\* byval\(.*\) align 4}} {{%[0-9]+}})
8-
// CHECK-WIN: call [[RESA:void]] [[NAMEA:@"\?\?GLoadableIntWrapper@@QEAA\?AU0@U0@@Z"]](ptr {{%[0-9]+}}, ptr sret(%struct.LoadableIntWrapper) {{.*}}, i32 {{%[0-9]+}})
8+
// CHECK-WIN: call [[RESA:void]] [[NAMEA:@"\?\?GLoadableIntWrapper@@QEAA\?AU0@U0@@Z"]](ptr {{%[0-9]+}}, ptr {{.*}} sret(%TSo18LoadableIntWrapperV) {{.*}}, i32 {{%[0-9]+}})
99

1010
public func call(_ wrapper: inout LoadableIntWrapper, _ arg: Int32) -> Int32 { wrapper(arg) }
1111

test/Interop/Cxx/operators/member-out-of-line-irgen.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ public func add(_ lhs: inout LoadableIntWrapper, _ rhs: LoadableIntWrapper) -> L
77
// CHECK-SYSV: call {{i32|i64}} [[NAME:@_ZNK18LoadableIntWrapperplES_]](ptr %{{[0-9]+}}, {{i32|\[1 x i32\]|i64|%struct.LoadableIntWrapper\* byval\(.*\)}}{{.*}})
88
// CHECK-SYSV: declare {{.*}}{{i32|i64}} [[NAME]](ptr {{.*}}, {{i32|\[1 x i32\]|i64|%struct.LoadableIntWrapper\* .*byval\(%struct.LoadableIntWrapper\)}}{{.*}})
99

10-
// CHECK-WIN: call void [[NAME:@"\?\?HLoadableIntWrapper@@QEBA\?AU0@U0@@Z"]](ptr %{{[0-9]+}}, ptr sret(%struct.LoadableIntWrapper) {{.*}}, i32 %{{[0-9]+}})
10+
// CHECK-WIN: call void [[NAME:@"\?\?HLoadableIntWrapper@@QEBA\?AU0@U0@@Z"]](ptr %{{[0-9]+}}, ptr {{.*}} sret(%TSo18LoadableIntWrapperV) {{.*}}, i32 %{{[0-9]+}})
1111
// CHECK-WIN: declare dso_local void [[NAME]](ptr {{.*}}, ptr sret(%struct.LoadableIntWrapper) {{.*}}, i32)

0 commit comments

Comments
 (0)