Skip to content

Fix the IR gen for C++ method calls and refactor around CGFunctionInfo #76324

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions lib/ClangImporter/ImportType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2203,10 +2203,11 @@ ImportedType ClangImporter::Implementation::importFunctionReturnType(
// C++ operators +=, -=, *=, /= may return a reference to self. This is not
// idiomatic in Swift, let's drop these return values.
clang::OverloadedOperatorKind op = clangDecl->getOverloadedOperator();
if (op == clang::OverloadedOperatorKind::OO_PlusEqual ||
op == clang::OverloadedOperatorKind::OO_MinusEqual ||
op == clang::OverloadedOperatorKind::OO_StarEqual ||
op == clang::OverloadedOperatorKind::OO_SlashEqual)
if ((op == clang::OverloadedOperatorKind::OO_PlusEqual ||
op == clang::OverloadedOperatorKind::OO_MinusEqual ||
op == clang::OverloadedOperatorKind::OO_StarEqual ||
op == clang::OverloadedOperatorKind::OO_SlashEqual) &&
clangDecl->getReturnType()->isReferenceType())
return {SwiftContext.getVoidType(), false};

// Fix up optionality.
Expand Down
38 changes: 22 additions & 16 deletions lib/IRGen/GenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1471,9 +1471,15 @@ void SignatureExpansion::expandExternalSignatureTypes() {
// Generate function info for this signature.
auto extInfo = clang::FunctionType::ExtInfo();

auto &FI = clang::CodeGen::arrangeFreeFunctionCall(IGM.ClangCodeGen->CGM(),
clangResultTy, paramTys, extInfo,
clang::CodeGen::RequiredArgs::All);
bool isCXXMethod =
FnType->getRepresentation() == SILFunctionTypeRepresentation::CXXMethod;
auto &FI = isCXXMethod ?
clang::CodeGen::arrangeCXXMethodCall(IGM.ClangCodeGen->CGM(),
clangResultTy, paramTys, extInfo, {},
clang::CodeGen::RequiredArgs::All) :
clang::CodeGen::arrangeFreeFunctionCall(IGM.ClangCodeGen->CGM(),
clangResultTy, paramTys, extInfo, {},
clang::CodeGen::RequiredArgs::All);
ForeignInfo.ClangInfo = &FI;

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

// Windows ABI places `this` before the
// returned indirect values.
bool isThisFirst = IGF.IGM.Triple.isWindowsMSVCEnvironment();
if (!isThisFirst)
auto &returnInfo =
getCallee().getForeignInfo().ClangInfo->getReturnInfo();
if (returnInfo.isIndirect() && !returnInfo.isSRetAfterThis())
passIndirectResults();
adjusted.add(arg);
if (isThisFirst)
if (returnInfo.isIndirect() && returnInfo.isSRetAfterThis())
passIndirectResults();
}

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

Args[0] = result.getAddress();
if (IGF.IGM.Triple.isWindowsMSVCEnvironment() &&
getCallee().getRepresentation() ==
SILFunctionTypeRepresentation::CXXMethod &&

auto *FI = getCallee().getForeignInfo().ClangInfo;
if (FI && FI->getReturnInfo().isIndirect() &&
FI->getReturnInfo().isSRetAfterThis() &&
Args[1] == getCallee().getCXXMethodSelf()) {
// C++ methods in MSVC ABI pass `this` before the
// indirectly returned value.
Expand Down Expand Up @@ -3566,10 +3572,10 @@ void CallEmission::emitToExplosion(Explosion &out, bool isOutlined) {
emitToMemory(temp, substResultTI, isOutlined);
return;
}
if (IGF.IGM.Triple.isWindowsMSVCEnvironment() &&
getCallee().getRepresentation() ==
SILFunctionTypeRepresentation::CXXMethod &&
substResultType.isVoid()) {

auto *FI = getCallee().getForeignInfo().ClangInfo;
if (FI && FI->getReturnInfo().isIndirect() &&
FI->getReturnInfo().isSRetAfterThis() && substResultType.isVoid()) {
// Some C++ methods return a value but are imported as
// returning `Void` (e.g. `operator +=`). In this case
// we should allocate the correct temp indirect return
Expand Down
11 changes: 11 additions & 0 deletions test/Interop/Cxx/class/method/Inputs/inreg-sret.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef TEST_INTEROP_CXX_CLASS_METHOD_INREG_SRET_H
#define TEST_INTEROP_CXX_CLASS_METHOD_INREG_SRET_H

struct OptionalBridgedBasicBlock {
};

struct BridgedFunction {
OptionalBridgedBasicBlock getFirstBlock() const { return {}; }
};

#endif // TEST_INTEROP_CXX_CLASS_METHOD_INREG_SRET_H
5 changes: 5 additions & 0 deletions test/Interop/Cxx/class/method/Inputs/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ module SRetWinARM64 {
header "sret-win-arm64.h"
requires cplusplus
}

module InRegSRet {
header "inreg-sret.h"
requires cplusplus
}
28 changes: 28 additions & 0 deletions test/Interop/Cxx/class/method/inreg-sret.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// RUN: %target-swift-emit-irgen -I %S/Inputs -cxx-interoperability-mode=default %s | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-cpu

// REQUIRES: OS=windows-msvc

import InRegSRet

final public class BasicBlock {
}

extension OptionalBridgedBasicBlock {
public var block: BasicBlock? { nil }
}

final public class Function {
public var bridged: BridgedFunction {
BridgedFunction()
}

public var firstBlock : BasicBlock? { bridged.getFirstBlock().block }
}

// Check that inreg on the sret isn't missing

// CHECK-x86_64: call void @"?getFirstBlock@BridgedFunction@@QEBA?AUOptionalBridgedBasicBlock@@XZ"(ptr {{.*}}, ptr noalias nocapture sret(%TSo25OptionalBridgedBasicBlockV) {{.*}})
// CHECK-aarch64: call void @"?getFirstBlock@BridgedFunction@@QEBA?AUOptionalBridgedBasicBlock@@XZ"(ptr {{.*}}, ptr inreg noalias nocapture sret(%TSo25OptionalBridgedBasicBlockV) {{.*}})

// CHECK-x86_64: define {{.*}} void @"?getFirstBlock@BridgedFunction@@QEBA?AUOptionalBridgedBasicBlock@@XZ"(ptr {{.*}} %{{.*}}, ptr noalias sret(%struct.OptionalBridgedBasicBlock) {{.*}} %{{.*}})
// CHECK-aarch64: define {{.*}} void @"?getFirstBlock@BridgedFunction@@QEBA?AUOptionalBridgedBasicBlock@@XZ"(ptr {{.*}} %{{.*}}, ptr inreg noalias sret(%struct.OptionalBridgedBasicBlock) {{.*}} %{{.*}})
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ public func test(_ result: VecStr) -> CInt {
}

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

public func passTempForIndirectRetToVoidCall() {
var lhs = LoadableIntWrapper(value: 2)
let rhs = LoadableIntWrapper(value: 2)
lhs += rhs
}

// CHECK: void @"$sSo18LoadableIntWrapperV2peoiyyABz_ABtFZ"(ptr
// CHECK: %[[OPRESULT:.*]] = alloca %struct.LoadableIntWrapper, align 16
// CHECK-x86_64: call void @"??YLoadableIntWrapper@@QEAA?AU0@U0@@Z"(ptr {{.*}}, ptr sret(%struct.LoadableIntWrapper) %[[OPRESULT]], i32
// CHECK-aarch64: call void @"??YLoadableIntWrapper@@QEAA?AU0@U0@@Z"(ptr {{.*}}, ptr sret(%struct.LoadableIntWrapper) %[[OPRESULT]], i64
// CHECK: i32 @"$sSo18LoadableIntWrapperV2peoiyA2Bz_ABtFZ"(ptr
// CHECK: %[[OPRESULT:.*]] = alloca %TSo18LoadableIntWrapperV, align 4
// CHECK-x86_64: call void @"??YLoadableIntWrapper@@QEAA?AU0@U0@@Z"(ptr {{.*}}, ptr {{.*}} sret(%TSo18LoadableIntWrapperV) %[[OPRESULT]], i32
// CHECK-aarch64: call void @"??YLoadableIntWrapper@@QEAA?AU0@U0@@Z"(ptr {{.*}}, ptr {{.*}} sret(%TSo18LoadableIntWrapperV) %[[OPRESULT]], i64
2 changes: 1 addition & 1 deletion test/Interop/Cxx/operators/member-inline-irgen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import MemberInline
public func sub(_ lhs: inout LoadableIntWrapper, _ rhs: LoadableIntWrapper) -> LoadableIntWrapper { lhs - rhs }

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ public func add(_ lhs: inout LoadableIntWrapper, _ rhs: LoadableIntWrapper) -> L
// CHECK-SYSV: call {{i32|i64}} [[NAME:@_ZNK18LoadableIntWrapperplES_]](ptr %{{[0-9]+}}, {{i32|\[1 x i32\]|i64|%struct.LoadableIntWrapper\* byval\(.*\)}}{{.*}})
// CHECK-SYSV: declare {{.*}}{{i32|i64}} [[NAME]](ptr {{.*}}, {{i32|\[1 x i32\]|i64|%struct.LoadableIntWrapper\* .*byval\(%struct.LoadableIntWrapper\)}}{{.*}})

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