Skip to content
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

JIT: Add support for SwiftSelf<T> in Swift calling convention #103576

Merged
merged 1 commit into from
Jun 18, 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
42 changes: 39 additions & 3 deletions src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2027,6 +2027,7 @@ void Compiler::impPopArgsForSwiftCall(GenTreeCall* call, CORINFO_SIG_INFO* sig,
unsigned short swiftErrorIndex = sig->numArgs;
unsigned short swiftSelfIndex = sig->numArgs;

CORINFO_CLASS_HANDLE selfType = NO_CLASS_HANDLE;
// We are importing an unmanaged Swift call, which might require special parameter handling
bool checkEntireStack = false;

Expand Down Expand Up @@ -2090,6 +2091,34 @@ void Compiler::impPopArgsForSwiftCall(GenTreeCall* call, CORINFO_SIG_INFO* sig,
swiftSelfIndex = argIndex;
// Fall through to make sure the struct value becomes a local.
}
else if ((strcmp(className, "SwiftSelf`1") == 0) &&
(strcmp(namespaceName, "System.Runtime.InteropServices.Swift") == 0))
{
// We expect a SwiftSelf struct to be passed, not a pointer/reference
if (argIsByrefOrPtr)
{
BADCODE("Expected SwiftSelf<T> struct, got pointer/reference");
}

if (swiftSelfIndex != sig->numArgs)
{
BADCODE("Duplicate SwiftSelf parameter");
}

if (argIndex != 0)
{
BADCODE("SwiftSelf<T> must be the first argument in the signature");
}

selfType = info.compCompHnd->getTypeInstantiationArgument(argClass, 0);
CorInfoType selfCorType = info.compCompHnd->asCorInfoType(selfType);
if (selfCorType != CORINFO_TYPE_VALUECLASS)
{
BADCODE("SwiftSelf<T> expects T to be a value class");
}

swiftSelfIndex = argIndex;
}
// TODO: Handle SwiftAsync
}

Expand Down Expand Up @@ -2157,7 +2186,7 @@ void Compiler::impPopArgsForSwiftCall(GenTreeCall* call, CORINFO_SIG_INFO* sig,
// For the self arg, change it from the SwiftSelf struct to a
// TYP_I_IMPL primitive directly. It must also be marked as a well
// known arg because it has a non-standard calling convention.
if (argIndex == swiftSelfIndex)
if ((argIndex == swiftSelfIndex) && (selfType == NO_CLASS_HANDLE))
{
assert(arg->GetNode()->OperIsLocalRead());
GenTree* primitiveSelf = gtNewLclFldNode(structVal->GetLclNum(), TYP_I_IMPL, structVal->GetLclOffs());
Expand All @@ -2166,7 +2195,8 @@ void Compiler::impPopArgsForSwiftCall(GenTreeCall* call, CORINFO_SIG_INFO* sig,
}
else
{
const CORINFO_SWIFT_LOWERING* lowering = GetSwiftLowering(arg->GetSignatureClassHandle());
CORINFO_CLASS_HANDLE argClass = argIndex == swiftSelfIndex ? selfType : arg->GetSignatureClassHandle();
const CORINFO_SWIFT_LOWERING* lowering = GetSwiftLowering(argClass);
if (lowering->byReference)
{
JITDUMP(" Argument %d of type %s must be passed by reference\n", argIndex,
Expand All @@ -2188,7 +2218,13 @@ void Compiler::impPopArgsForSwiftCall(GenTreeCall* call, CORINFO_SIG_INFO* sig,
GenTree* addrNode = gtNewLclAddrNode(structVal->GetLclNum(), structVal->GetLclOffs());
JITDUMP(" Passing by reference\n");

insertAfter = call->gtArgs.InsertAfter(this, insertAfter, NewCallArg::Primitive(addrNode, TYP_I_IMPL));
NewCallArg newArg = NewCallArg::Primitive(addrNode, TYP_I_IMPL);
if (argIndex == swiftSelfIndex)
{
newArg = newArg.WellKnown(WellKnownArg::SwiftSelf);
}

insertAfter = call->gtArgs.InsertAfter(this, insertAfter, newArg);
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion src/tests/Interop/Swift/SwiftSelfContext/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ if (NOT SWIFT_COMPILER_TARGET AND CLR_CMAKE_TARGET_OSX)
endif()

add_custom_target(${SOURCE} ALL
COMMAND xcrun swiftc -target ${SWIFT_COMPILER_TARGET} -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib
COMMAND xcrun swiftc -target ${SWIFT_COMPILER_TARGET} -enable-library-evolution -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift
COMMENT "Generating ${SOURCE} library"
)
Expand Down
43 changes: 41 additions & 2 deletions src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ public class SelfContextTests
public unsafe static extern void* getInstance();

[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport(SwiftLib, EntryPoint = "$s16SwiftSelfContext0B7LibraryC14getMagicNumberSiyF")]
[DllImport(SwiftLib, EntryPoint = "$s16SwiftSelfContext0B7LibraryC14getMagicNumberSiyFTj")]
public static extern nint getMagicNumber(SwiftSelf self);

[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport(SwiftLib, EntryPoint = "$s16SwiftSelfContext0B7LibraryC14getMagicNumberSiyF")]
[DllImport(SwiftLib, EntryPoint = "$s16SwiftSelfContext0B7LibraryC14getMagicNumberSiyFTj")]
public static extern nint getMagicNumberOnStack(int dummy0, int dummy1, int dummy2, int dummy3, int dummy4, int dummy5, int dummy6, int dummy7, int dummy8, int dummy9, SwiftSelf self);

[Fact]
Expand All @@ -44,4 +44,43 @@ public unsafe static void TestSwiftSelfContextOnStack()
int result = (int)getMagicNumberOnStack(i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, self);
Assert.True(result == 42, "The result from Swift does not match the expected value.");
}

public struct FrozenEnregisteredStruct
{
public long A;
public long B;
}

public struct FrozenNonEnregisteredStruct
{
public long A;
public long B;
public long C;
public long D;
public long E;
}

[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport(SwiftLib, EntryPoint = "$s16SwiftSelfContext24FrozenEnregisteredStructV3Sums5Int64VyF")]
public static extern long SumFrozenEnregisteredStruct(SwiftSelf<FrozenEnregisteredStruct> self);

[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport(SwiftLib, EntryPoint = "$s16SwiftSelfContext27FrozenNonEnregisteredStructV3Sums5Int64VyF")]
public static extern long SumFrozenNonEnregisteredStruct(SwiftSelf<FrozenNonEnregisteredStruct> self);

[Fact]
[SkipOnMono("SwiftSelf<T> is not supported on Mono")]
public unsafe static void TestSelfIsFrozenEnregisteredStruct()
{
long sum = SumFrozenEnregisteredStruct(new SwiftSelf<FrozenEnregisteredStruct>(new FrozenEnregisteredStruct { A = 10, B = 20 }));
Assert.Equal(30, sum);
}

[Fact]
[SkipOnMono("SwiftSelf<T> is not supported on Mono")]
public unsafe static void TestSelfIsFrozenNonEnregisteredStruct()
{
long sum = SumFrozenNonEnregisteredStruct(new SwiftSelf<FrozenNonEnregisteredStruct>(new FrozenNonEnregisteredStruct { A = 10, B = 20, C = 30, D = 40, E = 50 }));
Assert.Equal(150, sum);
}
}
24 changes: 24 additions & 0 deletions src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,27 @@ public class SelfLibrary {
return pointer
}
}

@frozen
public struct FrozenEnregisteredStruct
{
let a : Int64;
let b : Int64;

public func Sum() -> Int64 {
return a + b
}
}

@frozen
public struct FrozenNonEnregisteredStruct {
let a : Int64;
let b : Int64;
let c : Int64;
let d : Int64;
let e : Int64;

public func Sum() -> Int64 {
return a + b + c + d + e
}
}
Loading