Skip to content

Commit fcc1f6b

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.
1 parent 11a0a7b commit fcc1f6b

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
@@ -2203,10 +2203,11 @@ ImportedType ClangImporter::Implementation::importFunctionReturnType(
22032203
// C++ operators +=, -=, *=, /= may return a reference to self. This is not
22042204
// idiomatic in Swift, let's drop these return values.
22052205
clang::OverloadedOperatorKind op = clangDecl->getOverloadedOperator();
2206-
if (op == clang::OverloadedOperatorKind::OO_PlusEqual ||
2207-
op == clang::OverloadedOperatorKind::OO_MinusEqual ||
2208-
op == clang::OverloadedOperatorKind::OO_StarEqual ||
2209-
op == clang::OverloadedOperatorKind::OO_SlashEqual)
2206+
if ((op == clang::OverloadedOperatorKind::OO_PlusEqual ||
2207+
op == clang::OverloadedOperatorKind::OO_MinusEqual ||
2208+
op == clang::OverloadedOperatorKind::OO_StarEqual ||
2209+
op == clang::OverloadedOperatorKind::OO_SlashEqual) &&
2210+
clangDecl->getReturnType()->isReferenceType())
22102211
return {SwiftContext.getVoidType(), false};
22112212

22122213
// Fix up optionality.

lib/IRGen/GenCall.cpp

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

1474-
auto &FI = clang::CodeGen::arrangeFreeFunctionCall(IGM.ClangCodeGen->CGM(),
1475-
clangResultTy, paramTys, extInfo,
1476-
clang::CodeGen::RequiredArgs::All);
1474+
bool isCXXMethod =
1475+
FnType->getRepresentation() == SILFunctionTypeRepresentation::CXXMethod;
1476+
auto &FI = isCXXMethod ?
1477+
clang::CodeGen::arrangeCXXMethodCall(IGM.ClangCodeGen->CGM(),
1478+
clangResultTy, paramTys, extInfo, {},
1479+
clang::CodeGen::RequiredArgs::All) :
1480+
clang::CodeGen::arrangeFreeFunctionCall(IGM.ClangCodeGen->CGM(),
1481+
clangResultTy, paramTys, extInfo, {},
1482+
clang::CodeGen::RequiredArgs::All);
14771483
ForeignInfo.ClangInfo = &FI;
14781484

14791485
assert(FI.arg_size() == paramTys.size() &&
@@ -1595,9 +1601,7 @@ void SignatureExpansion::expandExternalSignatureTypes() {
15951601
if (returnInfo.isIndirect()) {
15961602
auto resultType = getSILFuncConventions().getSingleSILResultType(
15971603
IGM.getMaximalTypeExpansionContext());
1598-
if (IGM.Triple.isWindowsMSVCEnvironment() &&
1599-
FnType->getRepresentation() ==
1600-
SILFunctionTypeRepresentation::CXXMethod) {
1604+
if (returnInfo.isSRetAfterThis()) {
16011605
// Windows ABI places `this` before the
16021606
// returned indirect values.
16031607
emitArg(0);
@@ -2577,11 +2581,12 @@ class SyncCallEmission final : public CallEmission {
25772581

25782582
// Windows ABI places `this` before the
25792583
// returned indirect values.
2580-
bool isThisFirst = IGF.IGM.Triple.isWindowsMSVCEnvironment();
2581-
if (!isThisFirst)
2584+
auto &returnInfo =
2585+
getCallee().getForeignInfo().ClangInfo->getReturnInfo();
2586+
if (returnInfo.isIndirect() && !returnInfo.isSRetAfterThis())
25822587
passIndirectResults();
25832588
adjusted.add(arg);
2584-
if (isThisFirst)
2589+
if (returnInfo.isIndirect() && returnInfo.isSRetAfterThis())
25852590
passIndirectResults();
25862591
}
25872592

@@ -3171,9 +3176,10 @@ void CallEmission::emitToUnmappedMemory(Address result) {
31713176
assert(LastArgWritten == 1 && "emitting unnaturally to indirect result");
31723177

31733178
Args[0] = result.getAddress();
3174-
if (IGF.IGM.Triple.isWindowsMSVCEnvironment() &&
3175-
getCallee().getRepresentation() ==
3176-
SILFunctionTypeRepresentation::CXXMethod &&
3179+
3180+
auto *FI = getCallee().getForeignInfo().ClangInfo;
3181+
if (FI && FI->getReturnInfo().isIndirect() &&
3182+
FI->getReturnInfo().isSRetAfterThis() &&
31773183
Args[1] == getCallee().getCXXMethodSelf()) {
31783184
// C++ methods in MSVC ABI pass `this` before the
31793185
// indirectly returned value.
@@ -3566,10 +3572,10 @@ void CallEmission::emitToExplosion(Explosion &out, bool isOutlined) {
35663572
emitToMemory(temp, substResultTI, isOutlined);
35673573
return;
35683574
}
3569-
if (IGF.IGM.Triple.isWindowsMSVCEnvironment() &&
3570-
getCallee().getRepresentation() ==
3571-
SILFunctionTypeRepresentation::CXXMethod &&
3572-
substResultType.isVoid()) {
3575+
3576+
auto *FI = getCallee().getForeignInfo().ClangInfo;
3577+
if (FI && FI->getReturnInfo().isIndirect() &&
3578+
FI->getReturnInfo().isSRetAfterThis() && substResultType.isVoid()) {
35733579
// Some C++ methods return a value but are imported as
35743580
// returning `Void` (e.g. `operator +=`). In this case
35753581
// 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
@@ -19,3 +19,8 @@ module SRetWinARM64 {
1919
header "sret-win-arm64.h"
2020
requires cplusplus
2121
}
22+
23+
module InRegSRet {
24+
header "inreg-sret.h"
25+
requires cplusplus
26+
}
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)